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 /* 22*f4b3ec61Sdh155122 * 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> 3533343a97Smeem #include <stdarg.h> 367c478bd9Sstevel@tonic-gate #include <string.h> 377c478bd9Sstevel@tonic-gate #include <stropts.h> 387c478bd9Sstevel@tonic-gate #include <errno.h> 397c478bd9Sstevel@tonic-gate #include <kstat.h> 407c478bd9Sstevel@tonic-gate #include <strings.h> 417c478bd9Sstevel@tonic-gate #include <getopt.h> 427c478bd9Sstevel@tonic-gate #include <unistd.h> 43cd93090eSericheng #include <priv.h> 440ba2cbe9Sxc151355 #include <termios.h> 450ba2cbe9Sxc151355 #include <pwd.h> 460ba2cbe9Sxc151355 #include <auth_attr.h> 470ba2cbe9Sxc151355 #include <auth_list.h> 487c478bd9Sstevel@tonic-gate #include <libintl.h> 497c478bd9Sstevel@tonic-gate #include <libdlpi.h> 507c478bd9Sstevel@tonic-gate #include <libdladm.h> 517c478bd9Sstevel@tonic-gate #include <liblaadm.h> 527c478bd9Sstevel@tonic-gate #include <libmacadm.h> 530ba2cbe9Sxc151355 #include <libwladm.h> 540ba2cbe9Sxc151355 #include <libinetutil.h> 550ba2cbe9Sxc151355 #include <bsm/adt.h> 560ba2cbe9Sxc151355 #include <bsm/adt_event.h> 577c478bd9Sstevel@tonic-gate 58ba2e4443Sseb #define AGGR_DRV "aggr" 597c478bd9Sstevel@tonic-gate #define MAXPORT 256 607c478bd9Sstevel@tonic-gate #define DUMP_LACP_FORMAT " %-9s %-8s %-7s %-12s " \ 617c478bd9Sstevel@tonic-gate "%-5s %-4s %-4s %-9s %-7s\n" 627c478bd9Sstevel@tonic-gate 637c478bd9Sstevel@tonic-gate typedef struct pktsum_s { 647c478bd9Sstevel@tonic-gate uint64_t ipackets; 657c478bd9Sstevel@tonic-gate uint64_t opackets; 667c478bd9Sstevel@tonic-gate uint64_t rbytes; 677c478bd9Sstevel@tonic-gate uint64_t obytes; 687c478bd9Sstevel@tonic-gate uint32_t ierrors; 697c478bd9Sstevel@tonic-gate uint32_t oerrors; 707c478bd9Sstevel@tonic-gate } pktsum_t; 717c478bd9Sstevel@tonic-gate 727c478bd9Sstevel@tonic-gate typedef struct show_link_state { 737c478bd9Sstevel@tonic-gate boolean_t ls_firstonly; 747c478bd9Sstevel@tonic-gate boolean_t ls_donefirst; 757c478bd9Sstevel@tonic-gate boolean_t ls_stats; 767c478bd9Sstevel@tonic-gate pktsum_t ls_prevstats; 777c478bd9Sstevel@tonic-gate boolean_t ls_parseable; 787c478bd9Sstevel@tonic-gate } show_link_state_t; 797c478bd9Sstevel@tonic-gate 807c478bd9Sstevel@tonic-gate typedef struct show_grp_state { 817c478bd9Sstevel@tonic-gate uint32_t gs_key; 827c478bd9Sstevel@tonic-gate boolean_t gs_lacp; 837c478bd9Sstevel@tonic-gate boolean_t gs_found; 847c478bd9Sstevel@tonic-gate boolean_t gs_stats; 857c478bd9Sstevel@tonic-gate boolean_t gs_firstonly; 867c478bd9Sstevel@tonic-gate pktsum_t gs_prevstats[MAXPORT]; 877c478bd9Sstevel@tonic-gate boolean_t gs_parseable; 887c478bd9Sstevel@tonic-gate } show_grp_state_t; 897c478bd9Sstevel@tonic-gate 907c478bd9Sstevel@tonic-gate typedef struct show_mac_state { 917c478bd9Sstevel@tonic-gate boolean_t ms_firstonly; 927c478bd9Sstevel@tonic-gate boolean_t ms_donefirst; 937c478bd9Sstevel@tonic-gate pktsum_t ms_prevstats; 947c478bd9Sstevel@tonic-gate boolean_t ms_parseable; 957c478bd9Sstevel@tonic-gate } show_mac_state_t; 967c478bd9Sstevel@tonic-gate 977c478bd9Sstevel@tonic-gate typedef struct port_state { 987c478bd9Sstevel@tonic-gate char *state_name; 997c478bd9Sstevel@tonic-gate aggr_port_state_t state_num; 1007c478bd9Sstevel@tonic-gate } port_state_t; 1017c478bd9Sstevel@tonic-gate 1027c478bd9Sstevel@tonic-gate static port_state_t port_states[] = { 1037c478bd9Sstevel@tonic-gate {"standby", AGGR_PORT_STATE_STANDBY }, 1047c478bd9Sstevel@tonic-gate {"attached", AGGR_PORT_STATE_ATTACHED } 1057c478bd9Sstevel@tonic-gate }; 1067c478bd9Sstevel@tonic-gate 1077c478bd9Sstevel@tonic-gate #define NPORTSTATES (sizeof (port_states) / sizeof (port_state_t)) 1087c478bd9Sstevel@tonic-gate 1090ba2cbe9Sxc151355 typedef void cmdfunc_t(int, char **); 1100ba2cbe9Sxc151355 1110ba2cbe9Sxc151355 static cmdfunc_t do_show_link, do_show_dev, do_show_wifi; 1120ba2cbe9Sxc151355 static cmdfunc_t do_create_aggr, do_delete_aggr, do_add_aggr, do_remove_aggr; 1130ba2cbe9Sxc151355 static cmdfunc_t do_modify_aggr, do_show_aggr, do_up_aggr, do_down_aggr; 1140ba2cbe9Sxc151355 static cmdfunc_t do_scan_wifi, do_connect_wifi, do_disconnect_wifi; 1150ba2cbe9Sxc151355 static cmdfunc_t do_show_linkprop, do_set_linkprop, do_reset_linkprop; 1160ba2cbe9Sxc151355 static cmdfunc_t do_create_secobj, do_delete_secobj, do_show_secobj; 1170ba2cbe9Sxc151355 static cmdfunc_t do_init_linkprop, do_init_secobj; 1187c478bd9Sstevel@tonic-gate 119*f4b3ec61Sdh155122 static void show_linkprop_onelink(void *, const char *); 120*f4b3ec61Sdh155122 12133343a97Smeem static void link_stats(const char *, uint_t); 12233343a97Smeem static void aggr_stats(uint32_t, uint_t); 1237c478bd9Sstevel@tonic-gate static void dev_stats(const char *dev, uint32_t); 1247c478bd9Sstevel@tonic-gate 125ba2e4443Sseb static void get_mac_stats(const char *, pktsum_t *); 1267c478bd9Sstevel@tonic-gate static void get_link_stats(const char *, pktsum_t *); 127ba2e4443Sseb static uint64_t mac_ifspeed(const char *); 128ba2e4443Sseb static char *mac_link_state(const char *); 129ba2e4443Sseb static char *mac_link_duplex(const char *); 1307c478bd9Sstevel@tonic-gate static void stats_total(pktsum_t *, pktsum_t *, pktsum_t *); 1317c478bd9Sstevel@tonic-gate static void stats_diff(pktsum_t *, pktsum_t *, pktsum_t *); 1327c478bd9Sstevel@tonic-gate 13333343a97Smeem static boolean_t str2int(const char *, int *); 13433343a97Smeem static void die(const char *, ...); 13533343a97Smeem static void die_optdup(int); 13633343a97Smeem static void die_opterr(int, int); 13733343a97Smeem static void die_laerr(laadm_diag_t, const char *, ...); 13833343a97Smeem static void die_wlerr(wladm_status_t, const char *, ...); 13933343a97Smeem static void die_dlerr(dladm_status_t, const char *, ...); 14033343a97Smeem static void warn(const char *, ...); 14133343a97Smeem static void warn_wlerr(wladm_status_t, const char *, ...); 14233343a97Smeem static void warn_dlerr(dladm_status_t, const char *, ...); 14333343a97Smeem 1447c478bd9Sstevel@tonic-gate typedef struct cmd { 1457c478bd9Sstevel@tonic-gate char *c_name; 1460ba2cbe9Sxc151355 cmdfunc_t *c_fn; 1477c478bd9Sstevel@tonic-gate } cmd_t; 1487c478bd9Sstevel@tonic-gate 1497c478bd9Sstevel@tonic-gate static cmd_t cmds[] = { 1507c478bd9Sstevel@tonic-gate { "show-link", do_show_link }, 151210db224Sericheng { "show-dev", do_show_dev }, 1527c478bd9Sstevel@tonic-gate { "create-aggr", do_create_aggr }, 1537c478bd9Sstevel@tonic-gate { "delete-aggr", do_delete_aggr }, 1547c478bd9Sstevel@tonic-gate { "add-aggr", do_add_aggr }, 1557c478bd9Sstevel@tonic-gate { "remove-aggr", do_remove_aggr }, 1567c478bd9Sstevel@tonic-gate { "modify-aggr", do_modify_aggr }, 1577c478bd9Sstevel@tonic-gate { "show-aggr", do_show_aggr }, 1587c478bd9Sstevel@tonic-gate { "up-aggr", do_up_aggr }, 1590ba2cbe9Sxc151355 { "down-aggr", do_down_aggr }, 1600ba2cbe9Sxc151355 { "scan-wifi", do_scan_wifi }, 1610ba2cbe9Sxc151355 { "connect-wifi", do_connect_wifi }, 1620ba2cbe9Sxc151355 { "disconnect-wifi", do_disconnect_wifi }, 1630ba2cbe9Sxc151355 { "show-wifi", do_show_wifi }, 1640ba2cbe9Sxc151355 { "show-linkprop", do_show_linkprop }, 1650ba2cbe9Sxc151355 { "set-linkprop", do_set_linkprop }, 1660ba2cbe9Sxc151355 { "reset-linkprop", do_reset_linkprop }, 1670ba2cbe9Sxc151355 { "create-secobj", do_create_secobj }, 1680ba2cbe9Sxc151355 { "delete-secobj", do_delete_secobj }, 1690ba2cbe9Sxc151355 { "show-secobj", do_show_secobj }, 1700ba2cbe9Sxc151355 { "init-linkprop", do_init_linkprop }, 1710ba2cbe9Sxc151355 { "init-secobj", do_init_secobj } 1727c478bd9Sstevel@tonic-gate }; 1737c478bd9Sstevel@tonic-gate 1747c478bd9Sstevel@tonic-gate static const struct option longopts[] = { 1757c478bd9Sstevel@tonic-gate {"vlan-id", required_argument, 0, 'v' }, 1767c478bd9Sstevel@tonic-gate {"dev", required_argument, 0, 'd' }, 1777c478bd9Sstevel@tonic-gate {"policy", required_argument, 0, 'P' }, 1787c478bd9Sstevel@tonic-gate {"lacp-mode", required_argument, 0, 'l' }, 1797c478bd9Sstevel@tonic-gate {"lacp-timer", required_argument, 0, 'T' }, 1807c478bd9Sstevel@tonic-gate {"unicast", required_argument, 0, 'u' }, 1817c478bd9Sstevel@tonic-gate {"statistics", no_argument, 0, 's' }, 1827c478bd9Sstevel@tonic-gate {"interval", required_argument, 0, 'i' }, 1837c478bd9Sstevel@tonic-gate {"lacp", no_argument, 0, 'L' }, 1847c478bd9Sstevel@tonic-gate {"temporary", no_argument, 0, 't' }, 1857c478bd9Sstevel@tonic-gate {"root-dir", required_argument, 0, 'r' }, 1867c478bd9Sstevel@tonic-gate {"parseable", no_argument, 0, 'p' }, 1877c478bd9Sstevel@tonic-gate { 0, 0, 0, 0 } 1887c478bd9Sstevel@tonic-gate }; 1897c478bd9Sstevel@tonic-gate 1900ba2cbe9Sxc151355 static const struct option prop_longopts[] = { 1910ba2cbe9Sxc151355 {"temporary", no_argument, 0, 't' }, 1920ba2cbe9Sxc151355 {"root-dir", required_argument, 0, 'R' }, 1930ba2cbe9Sxc151355 {"prop", required_argument, 0, 'p' }, 1940ba2cbe9Sxc151355 {"parseable", no_argument, 0, 'c' }, 1950ba2cbe9Sxc151355 {"persistent", no_argument, 0, 'P' }, 1960ba2cbe9Sxc151355 { 0, 0, 0, 0 } 1970ba2cbe9Sxc151355 }; 1980ba2cbe9Sxc151355 1990ba2cbe9Sxc151355 static const struct option wifi_longopts[] = { 2000ba2cbe9Sxc151355 {"parseable", no_argument, 0, 'p' }, 2010ba2cbe9Sxc151355 {"output", required_argument, 0, 'o' }, 2020ba2cbe9Sxc151355 {"essid", required_argument, 0, 'e' }, 2030ba2cbe9Sxc151355 {"bsstype", required_argument, 0, 'b' }, 2040ba2cbe9Sxc151355 {"mode", required_argument, 0, 'm' }, 2050ba2cbe9Sxc151355 {"key", required_argument, 0, 'k' }, 2060ba2cbe9Sxc151355 {"sec", required_argument, 0, 's' }, 2070ba2cbe9Sxc151355 {"auth", required_argument, 0, 'a' }, 2080ba2cbe9Sxc151355 {"create-ibss", required_argument, 0, 'c' }, 2090ba2cbe9Sxc151355 {"timeout", required_argument, 0, 'T' }, 2100ba2cbe9Sxc151355 {"all-links", no_argument, 0, 'a' }, 2110ba2cbe9Sxc151355 {"temporary", no_argument, 0, 't' }, 2120ba2cbe9Sxc151355 {"root-dir", required_argument, 0, 'R' }, 2130ba2cbe9Sxc151355 {"persistent", no_argument, 0, 'P' }, 2140ba2cbe9Sxc151355 {"file", required_argument, 0, 'f' }, 2150ba2cbe9Sxc151355 { 0, 0, 0, 0 } 2160ba2cbe9Sxc151355 }; 2170ba2cbe9Sxc151355 2187c478bd9Sstevel@tonic-gate static char *progname; 2190ba2cbe9Sxc151355 static sig_atomic_t signalled; 2207c478bd9Sstevel@tonic-gate 2217c478bd9Sstevel@tonic-gate static void 2227c478bd9Sstevel@tonic-gate usage(void) 2237c478bd9Sstevel@tonic-gate { 2240ba2cbe9Sxc151355 (void) fprintf(stderr, gettext("usage: dladm <subcommand> <args> ...\n" 2250ba2cbe9Sxc151355 "\tshow-link [-p] [-s [-i <interval>]] [<name>]\n" 2260ba2cbe9Sxc151355 "\tshow-dev [-p] [-s [-i <interval>]] [<dev>]\n" 2270ba2cbe9Sxc151355 "\n" 2280ba2cbe9Sxc151355 "\tcreate-aggr [-t] [-R <root-dir>] [-P <policy>] [-l <mode>]\n" 2290ba2cbe9Sxc151355 "\t [-T <time>] [-u <address>] -d <dev> ... <key>\n" 2300ba2cbe9Sxc151355 "\tmodify-aggr [-t] [-R <root-dir>] [-P <policy>] [-l <mode>]\n" 2310ba2cbe9Sxc151355 "\t [-T <time>] [-u <address>] <key>\n" 2320ba2cbe9Sxc151355 "\tdelete-aggr [-t] [-R <root-dir>] <key>\n" 2330ba2cbe9Sxc151355 "\tadd-aggr [-t] [-R <root-dir>] -d <dev> ... <key>\n" 2340ba2cbe9Sxc151355 "\tremove-aggr [-t] [-R <root-dir>] -d <dev> ... <key>\n" 2350ba2cbe9Sxc151355 "\tshow-aggr [-pL][-s [-i <interval>]] [<key>]\n" 2360ba2cbe9Sxc151355 "\n" 2370ba2cbe9Sxc151355 "\tscan-wifi [-p] [-o <field>,...] [<name>]\n" 2380ba2cbe9Sxc151355 "\tconnect-wifi [-e <essid>] [-i <bssid>] [-k <key>,...]" 2390ba2cbe9Sxc151355 " [-s wep]\n" 2400ba2cbe9Sxc151355 "\t [-a open|shared] [-b bss|ibss] [-c] [-m a|b|g]\n" 2410ba2cbe9Sxc151355 "\t [-T <time>] [<name>]\n" 2420ba2cbe9Sxc151355 "\tdisconnect-wifi [-a] [<name>]\n" 2430ba2cbe9Sxc151355 "\tshow-wifi [-p] [-o <field>,...] [<name>]\n" 2440ba2cbe9Sxc151355 "\n" 2450ba2cbe9Sxc151355 "\tset-linkprop [-t] [-R <root-dir>] -p <prop>=<value>[,...]" 2460ba2cbe9Sxc151355 " <name>\n" 2470ba2cbe9Sxc151355 "\treset-linkprop [-t] [-R <root-dir>] [-p <prop>,...] <name>\n" 2480ba2cbe9Sxc151355 "\tshow-linkprop [-cP][-p <prop>,...] <name>\n" 2490ba2cbe9Sxc151355 "\n" 2500ba2cbe9Sxc151355 "\tcreate-secobj [-t] [-R <root-dir>] [-f <file>] -c <class>" 2510ba2cbe9Sxc151355 " <secobj>\n" 2520ba2cbe9Sxc151355 "\tdelete-secobj [-t] [-R <root-dir>] <secobj>[,...]\n" 2530ba2cbe9Sxc151355 "\tshow-secobj [-pP][<secobj>,...]\n")); 2547c478bd9Sstevel@tonic-gate exit(1); 2557c478bd9Sstevel@tonic-gate } 2567c478bd9Sstevel@tonic-gate 2577c478bd9Sstevel@tonic-gate int 2587c478bd9Sstevel@tonic-gate main(int argc, char *argv[]) 2597c478bd9Sstevel@tonic-gate { 2607c478bd9Sstevel@tonic-gate int i; 2617c478bd9Sstevel@tonic-gate cmd_t *cmdp; 2627c478bd9Sstevel@tonic-gate 2637c478bd9Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 2647c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) 2657c478bd9Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST" 2667c478bd9Sstevel@tonic-gate #endif 2677c478bd9Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 2687c478bd9Sstevel@tonic-gate 2697c478bd9Sstevel@tonic-gate progname = argv[0]; 2707c478bd9Sstevel@tonic-gate 2717c478bd9Sstevel@tonic-gate if (argc < 2) 2727c478bd9Sstevel@tonic-gate usage(); 2737c478bd9Sstevel@tonic-gate 274cd93090eSericheng if (!priv_ineffect(PRIV_SYS_NET_CONFIG) || 27533343a97Smeem !priv_ineffect(PRIV_NET_RAWACCESS)) 27633343a97Smeem die("insufficient privileges"); 277cd93090eSericheng 2787c478bd9Sstevel@tonic-gate for (i = 0; i < sizeof (cmds) / sizeof (cmds[0]); i++) { 2797c478bd9Sstevel@tonic-gate cmdp = &cmds[i]; 2807c478bd9Sstevel@tonic-gate if (strcmp(argv[1], cmdp->c_name) == 0) { 2817c478bd9Sstevel@tonic-gate cmdp->c_fn(argc - 1, &argv[1]); 2827c478bd9Sstevel@tonic-gate exit(0); 2837c478bd9Sstevel@tonic-gate } 2847c478bd9Sstevel@tonic-gate } 2857c478bd9Sstevel@tonic-gate 2867c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: unknown subcommand '%s'\n"), 2877c478bd9Sstevel@tonic-gate progname, argv[1]); 2887c478bd9Sstevel@tonic-gate usage(); 2897c478bd9Sstevel@tonic-gate 2907c478bd9Sstevel@tonic-gate return (0); 2917c478bd9Sstevel@tonic-gate } 2927c478bd9Sstevel@tonic-gate 2937c478bd9Sstevel@tonic-gate static void 2947c478bd9Sstevel@tonic-gate do_create_aggr(int argc, char *argv[]) 2957c478bd9Sstevel@tonic-gate { 2967c478bd9Sstevel@tonic-gate char option; 29733343a97Smeem int key; 2987c478bd9Sstevel@tonic-gate uint32_t policy = AGGR_POLICY_L4; 2997c478bd9Sstevel@tonic-gate aggr_lacp_mode_t lacp_mode = AGGR_LACP_OFF; 3007c478bd9Sstevel@tonic-gate aggr_lacp_timer_t lacp_timer = AGGR_LACP_TIMER_SHORT; 3017c478bd9Sstevel@tonic-gate laadm_port_attr_db_t port[MAXPORT]; 3027c478bd9Sstevel@tonic-gate uint_t nport = 0; 3037c478bd9Sstevel@tonic-gate uint8_t mac_addr[ETHERADDRL]; 3047c478bd9Sstevel@tonic-gate boolean_t mac_addr_fixed = B_FALSE; 3057c478bd9Sstevel@tonic-gate boolean_t P_arg = B_FALSE; 3067c478bd9Sstevel@tonic-gate boolean_t l_arg = B_FALSE; 3077c478bd9Sstevel@tonic-gate boolean_t t_arg = B_FALSE; 3087c478bd9Sstevel@tonic-gate boolean_t u_arg = B_FALSE; 3097c478bd9Sstevel@tonic-gate boolean_t T_arg = B_FALSE; 3107c478bd9Sstevel@tonic-gate char *altroot = NULL; 3117c478bd9Sstevel@tonic-gate laadm_diag_t diag = 0; 3127c478bd9Sstevel@tonic-gate 3137c478bd9Sstevel@tonic-gate opterr = 0; 3147c478bd9Sstevel@tonic-gate while ((option = getopt_long(argc, argv, ":d:l:P:R:tu:T:", 3157c478bd9Sstevel@tonic-gate longopts, NULL)) != -1) { 3167c478bd9Sstevel@tonic-gate switch (option) { 3177c478bd9Sstevel@tonic-gate case 'd': 31833343a97Smeem if (nport >= MAXPORT) 31933343a97Smeem die("too many <dev> arguments"); 3207c478bd9Sstevel@tonic-gate 3217c478bd9Sstevel@tonic-gate if (strlcpy(port[nport].lp_devname, optarg, 32233343a97Smeem MAXNAMELEN) >= MAXNAMELEN) 32333343a97Smeem die("device name too long"); 3247c478bd9Sstevel@tonic-gate 3257c478bd9Sstevel@tonic-gate nport++; 3267c478bd9Sstevel@tonic-gate break; 3277c478bd9Sstevel@tonic-gate case 'P': 32833343a97Smeem if (P_arg) 32933343a97Smeem die_optdup(option); 3307c478bd9Sstevel@tonic-gate 3317c478bd9Sstevel@tonic-gate P_arg = B_TRUE; 33233343a97Smeem if (!laadm_str_to_policy(optarg, &policy)) 33333343a97Smeem die("invalid policy '%s'", optarg); 3347c478bd9Sstevel@tonic-gate break; 3357c478bd9Sstevel@tonic-gate case 'u': 33633343a97Smeem if (u_arg) 33733343a97Smeem die_optdup(option); 3387c478bd9Sstevel@tonic-gate 3397c478bd9Sstevel@tonic-gate u_arg = B_TRUE; 3407c478bd9Sstevel@tonic-gate if (!laadm_str_to_mac_addr(optarg, &mac_addr_fixed, 34133343a97Smeem mac_addr)) 34233343a97Smeem die("invalid MAC address '%s'", optarg); 3437c478bd9Sstevel@tonic-gate break; 3447c478bd9Sstevel@tonic-gate case 'l': 34533343a97Smeem if (l_arg) 34633343a97Smeem die_optdup(option); 3477c478bd9Sstevel@tonic-gate 3487c478bd9Sstevel@tonic-gate l_arg = B_TRUE; 34933343a97Smeem if (!laadm_str_to_lacp_mode(optarg, &lacp_mode)) 35033343a97Smeem die("invalid LACP mode '%s'", optarg); 3517c478bd9Sstevel@tonic-gate break; 3527c478bd9Sstevel@tonic-gate case 'T': 35333343a97Smeem if (T_arg) 35433343a97Smeem die_optdup(option); 3557c478bd9Sstevel@tonic-gate 3567c478bd9Sstevel@tonic-gate T_arg = B_TRUE; 35733343a97Smeem if (!laadm_str_to_lacp_timer(optarg, &lacp_timer)) 35833343a97Smeem die("invalid LACP timer value '%s'", optarg); 3597c478bd9Sstevel@tonic-gate break; 3607c478bd9Sstevel@tonic-gate case 't': 3617c478bd9Sstevel@tonic-gate t_arg = B_TRUE; 3627c478bd9Sstevel@tonic-gate break; 3637c478bd9Sstevel@tonic-gate case 'R': 3647c478bd9Sstevel@tonic-gate altroot = optarg; 3657c478bd9Sstevel@tonic-gate break; 3667c478bd9Sstevel@tonic-gate default: 36733343a97Smeem die_opterr(optopt, option); 36833343a97Smeem break; 3697c478bd9Sstevel@tonic-gate } 3707c478bd9Sstevel@tonic-gate } 3717c478bd9Sstevel@tonic-gate 3727c478bd9Sstevel@tonic-gate if (nport == 0) 3737c478bd9Sstevel@tonic-gate usage(); 3747c478bd9Sstevel@tonic-gate 3757c478bd9Sstevel@tonic-gate /* get key value (required last argument) */ 3767c478bd9Sstevel@tonic-gate if (optind != (argc-1)) 3777c478bd9Sstevel@tonic-gate usage(); 3787c478bd9Sstevel@tonic-gate 37933343a97Smeem if (!str2int(argv[optind], &key) || key < 1) 38033343a97Smeem die("invalid key value '%s'", argv[optind]); 3817c478bd9Sstevel@tonic-gate 3827c478bd9Sstevel@tonic-gate if (laadm_create(key, nport, port, policy, mac_addr_fixed, 38333343a97Smeem mac_addr, lacp_mode, lacp_timer, t_arg, altroot, &diag) < 0) 38433343a97Smeem die_laerr(diag, "create operation failed"); 3857c478bd9Sstevel@tonic-gate } 3867c478bd9Sstevel@tonic-gate 3877c478bd9Sstevel@tonic-gate static void 3887c478bd9Sstevel@tonic-gate do_delete_aggr(int argc, char *argv[]) 3897c478bd9Sstevel@tonic-gate { 39033343a97Smeem int key; 3917c478bd9Sstevel@tonic-gate char option; 3927c478bd9Sstevel@tonic-gate boolean_t t_arg = B_FALSE; 3937c478bd9Sstevel@tonic-gate char *altroot = NULL; 3947c478bd9Sstevel@tonic-gate laadm_diag_t diag = 0; 3957c478bd9Sstevel@tonic-gate 3967c478bd9Sstevel@tonic-gate opterr = 0; 3977c478bd9Sstevel@tonic-gate while ((option = getopt_long(argc, argv, ":R:t", longopts, 3987c478bd9Sstevel@tonic-gate NULL)) != -1) { 3997c478bd9Sstevel@tonic-gate switch (option) { 4007c478bd9Sstevel@tonic-gate case 't': 4017c478bd9Sstevel@tonic-gate t_arg = B_TRUE; 4027c478bd9Sstevel@tonic-gate break; 4037c478bd9Sstevel@tonic-gate case 'R': 4047c478bd9Sstevel@tonic-gate altroot = optarg; 4057c478bd9Sstevel@tonic-gate break; 4067c478bd9Sstevel@tonic-gate default: 40733343a97Smeem die_opterr(optopt, option); 4087c478bd9Sstevel@tonic-gate break; 4097c478bd9Sstevel@tonic-gate } 4107c478bd9Sstevel@tonic-gate } 4117c478bd9Sstevel@tonic-gate 4127c478bd9Sstevel@tonic-gate /* get key value (required last argument) */ 4137c478bd9Sstevel@tonic-gate if (optind != (argc-1)) 4147c478bd9Sstevel@tonic-gate usage(); 4157c478bd9Sstevel@tonic-gate 41633343a97Smeem if (!str2int(argv[optind], &key) || key < 1) 41733343a97Smeem die("invalid key value '%s'", argv[optind]); 4187c478bd9Sstevel@tonic-gate 41933343a97Smeem if (laadm_delete(key, t_arg, altroot, &diag) < 0) 42033343a97Smeem die_laerr(diag, "delete operation failed"); 4217c478bd9Sstevel@tonic-gate } 4227c478bd9Sstevel@tonic-gate 4237c478bd9Sstevel@tonic-gate static void 4247c478bd9Sstevel@tonic-gate do_add_aggr(int argc, char *argv[]) 4257c478bd9Sstevel@tonic-gate { 4267c478bd9Sstevel@tonic-gate char option; 42733343a97Smeem int key; 4287c478bd9Sstevel@tonic-gate laadm_port_attr_db_t port[MAXPORT]; 4297c478bd9Sstevel@tonic-gate uint_t nport = 0; 4307c478bd9Sstevel@tonic-gate boolean_t t_arg = B_FALSE; 4317c478bd9Sstevel@tonic-gate char *altroot = NULL; 4327c478bd9Sstevel@tonic-gate laadm_diag_t diag = 0; 4337c478bd9Sstevel@tonic-gate 4347c478bd9Sstevel@tonic-gate opterr = 0; 4357c478bd9Sstevel@tonic-gate while ((option = getopt_long(argc, argv, ":d:R:t", longopts, 4367c478bd9Sstevel@tonic-gate NULL)) != -1) { 4377c478bd9Sstevel@tonic-gate switch (option) { 4387c478bd9Sstevel@tonic-gate case 'd': 43933343a97Smeem if (nport >= MAXPORT) 44033343a97Smeem die("too many <dev> arguments"); 4417c478bd9Sstevel@tonic-gate 4427c478bd9Sstevel@tonic-gate if (strlcpy(port[nport].lp_devname, optarg, 44333343a97Smeem MAXNAMELEN) >= MAXNAMELEN) 44433343a97Smeem die("device name too long"); 44533343a97Smeem 4467c478bd9Sstevel@tonic-gate nport++; 4477c478bd9Sstevel@tonic-gate break; 4487c478bd9Sstevel@tonic-gate case 't': 4497c478bd9Sstevel@tonic-gate t_arg = B_TRUE; 4507c478bd9Sstevel@tonic-gate break; 4517c478bd9Sstevel@tonic-gate case 'R': 4527c478bd9Sstevel@tonic-gate altroot = optarg; 4537c478bd9Sstevel@tonic-gate break; 4547c478bd9Sstevel@tonic-gate default: 45533343a97Smeem die_opterr(optopt, option); 45633343a97Smeem break; 4577c478bd9Sstevel@tonic-gate } 4587c478bd9Sstevel@tonic-gate } 4597c478bd9Sstevel@tonic-gate 4607c478bd9Sstevel@tonic-gate if (nport == 0) 4617c478bd9Sstevel@tonic-gate usage(); 4627c478bd9Sstevel@tonic-gate 4637c478bd9Sstevel@tonic-gate /* get key value (required last argument) */ 4647c478bd9Sstevel@tonic-gate if (optind != (argc-1)) 4657c478bd9Sstevel@tonic-gate usage(); 4667c478bd9Sstevel@tonic-gate 46733343a97Smeem if (!str2int(argv[optind], &key) || key < 1) 46833343a97Smeem die("invalid key value '%s'", argv[optind]); 4697c478bd9Sstevel@tonic-gate 4707c478bd9Sstevel@tonic-gate if (laadm_add(key, nport, port, t_arg, altroot, &diag) < 0) { 471219a2a31Shl157128 /* 472219a2a31Shl157128 * checking ENOTSUP is a temporary workaround 473219a2a31Shl157128 * and should be removed once 6399681 is fixed. 474219a2a31Shl157128 */ 475219a2a31Shl157128 if (errno == ENOTSUP) { 476219a2a31Shl157128 (void) fprintf(stderr, 477219a2a31Shl157128 gettext("%s: add operation failed: %s\n"), 478219a2a31Shl157128 progname, 479219a2a31Shl157128 gettext("device capabilities don't match")); 480219a2a31Shl157128 exit(ENOTSUP); 481219a2a31Shl157128 } 48233343a97Smeem die_laerr(diag, "add operation failed"); 4837c478bd9Sstevel@tonic-gate } 4847c478bd9Sstevel@tonic-gate } 4857c478bd9Sstevel@tonic-gate 4867c478bd9Sstevel@tonic-gate static void 4877c478bd9Sstevel@tonic-gate do_remove_aggr(int argc, char *argv[]) 4887c478bd9Sstevel@tonic-gate { 4897c478bd9Sstevel@tonic-gate char option; 49033343a97Smeem int key; 4917c478bd9Sstevel@tonic-gate laadm_port_attr_db_t port[MAXPORT]; 4927c478bd9Sstevel@tonic-gate uint_t nport = 0; 4937c478bd9Sstevel@tonic-gate boolean_t t_arg = B_FALSE; 4947c478bd9Sstevel@tonic-gate char *altroot = NULL; 4957c478bd9Sstevel@tonic-gate laadm_diag_t diag = 0; 4967c478bd9Sstevel@tonic-gate 4977c478bd9Sstevel@tonic-gate opterr = 0; 4987c478bd9Sstevel@tonic-gate while ((option = getopt_long(argc, argv, ":d:R:t", 4997c478bd9Sstevel@tonic-gate longopts, NULL)) != -1) { 5007c478bd9Sstevel@tonic-gate switch (option) { 5017c478bd9Sstevel@tonic-gate case 'd': 50233343a97Smeem if (nport >= MAXPORT) 50333343a97Smeem die("too many <dev> arguments"); 5047c478bd9Sstevel@tonic-gate 5057c478bd9Sstevel@tonic-gate if (strlcpy(port[nport].lp_devname, optarg, 50633343a97Smeem MAXNAMELEN) >= MAXNAMELEN) 50733343a97Smeem die("device name too long"); 50833343a97Smeem 5097c478bd9Sstevel@tonic-gate nport++; 5107c478bd9Sstevel@tonic-gate break; 5117c478bd9Sstevel@tonic-gate case 't': 5127c478bd9Sstevel@tonic-gate t_arg = B_TRUE; 5137c478bd9Sstevel@tonic-gate break; 5147c478bd9Sstevel@tonic-gate case 'R': 5157c478bd9Sstevel@tonic-gate altroot = optarg; 5167c478bd9Sstevel@tonic-gate break; 5177c478bd9Sstevel@tonic-gate default: 51833343a97Smeem die_opterr(optopt, option); 51933343a97Smeem break; 5207c478bd9Sstevel@tonic-gate } 5217c478bd9Sstevel@tonic-gate } 5227c478bd9Sstevel@tonic-gate 5237c478bd9Sstevel@tonic-gate if (nport == 0) 5247c478bd9Sstevel@tonic-gate usage(); 5257c478bd9Sstevel@tonic-gate 5267c478bd9Sstevel@tonic-gate /* get key value (required last argument) */ 5277c478bd9Sstevel@tonic-gate if (optind != (argc-1)) 5287c478bd9Sstevel@tonic-gate usage(); 5297c478bd9Sstevel@tonic-gate 53033343a97Smeem if (!str2int(argv[optind], &key) || key < 1) 53133343a97Smeem die("invalid key value '%s'", argv[optind]); 5327c478bd9Sstevel@tonic-gate 53333343a97Smeem if (laadm_remove(key, nport, port, t_arg, altroot, &diag) < 0) 53433343a97Smeem die_laerr(diag, "remove operation failed"); 5357c478bd9Sstevel@tonic-gate } 5367c478bd9Sstevel@tonic-gate 5377c478bd9Sstevel@tonic-gate static void 5387c478bd9Sstevel@tonic-gate do_modify_aggr(int argc, char *argv[]) 5397c478bd9Sstevel@tonic-gate { 5407c478bd9Sstevel@tonic-gate char option; 54133343a97Smeem int key; 5427c478bd9Sstevel@tonic-gate uint32_t policy = AGGR_POLICY_L4; 5437c478bd9Sstevel@tonic-gate aggr_lacp_mode_t lacp_mode = AGGR_LACP_OFF; 5447c478bd9Sstevel@tonic-gate aggr_lacp_timer_t lacp_timer = AGGR_LACP_TIMER_SHORT; 5457c478bd9Sstevel@tonic-gate uint8_t mac_addr[ETHERADDRL]; 5467c478bd9Sstevel@tonic-gate boolean_t mac_addr_fixed = B_FALSE; 5477c478bd9Sstevel@tonic-gate uint8_t modify_mask = 0; 5487c478bd9Sstevel@tonic-gate boolean_t t_arg = B_FALSE; 5497c478bd9Sstevel@tonic-gate char *altroot = NULL; 5507c478bd9Sstevel@tonic-gate laadm_diag_t diag = 0; 5517c478bd9Sstevel@tonic-gate 5527c478bd9Sstevel@tonic-gate opterr = 0; 5537c478bd9Sstevel@tonic-gate while ((option = getopt_long(argc, argv, ":l:P:R:tu:T:", longopts, 5547c478bd9Sstevel@tonic-gate NULL)) != -1) { 5557c478bd9Sstevel@tonic-gate switch (option) { 5567c478bd9Sstevel@tonic-gate case 'P': 55733343a97Smeem if (modify_mask & LAADM_MODIFY_POLICY) 55833343a97Smeem die_optdup(option); 5597c478bd9Sstevel@tonic-gate 5607c478bd9Sstevel@tonic-gate modify_mask |= LAADM_MODIFY_POLICY; 5617c478bd9Sstevel@tonic-gate 56233343a97Smeem if (!laadm_str_to_policy(optarg, &policy)) 56333343a97Smeem die("invalid policy '%s'", optarg); 5647c478bd9Sstevel@tonic-gate break; 5657c478bd9Sstevel@tonic-gate case 'u': 56633343a97Smeem if (modify_mask & LAADM_MODIFY_MAC) 56733343a97Smeem die_optdup(option); 5687c478bd9Sstevel@tonic-gate 5697c478bd9Sstevel@tonic-gate modify_mask |= LAADM_MODIFY_MAC; 5707c478bd9Sstevel@tonic-gate 5717c478bd9Sstevel@tonic-gate if (!laadm_str_to_mac_addr(optarg, &mac_addr_fixed, 57233343a97Smeem mac_addr)) 57333343a97Smeem die("invalid MAC address '%s'", optarg); 5747c478bd9Sstevel@tonic-gate break; 5757c478bd9Sstevel@tonic-gate case 'l': 57633343a97Smeem if (modify_mask & LAADM_MODIFY_LACP_MODE) 57733343a97Smeem die_optdup(option); 5787c478bd9Sstevel@tonic-gate 5797c478bd9Sstevel@tonic-gate modify_mask |= LAADM_MODIFY_LACP_MODE; 5807c478bd9Sstevel@tonic-gate 58133343a97Smeem if (!laadm_str_to_lacp_mode(optarg, &lacp_mode)) 58233343a97Smeem die("invalid LACP mode '%s'", optarg); 5837c478bd9Sstevel@tonic-gate break; 5847c478bd9Sstevel@tonic-gate case 'T': 58533343a97Smeem if (modify_mask & LAADM_MODIFY_LACP_TIMER) 58633343a97Smeem die_optdup(option); 5877c478bd9Sstevel@tonic-gate 5887c478bd9Sstevel@tonic-gate modify_mask |= LAADM_MODIFY_LACP_TIMER; 5897c478bd9Sstevel@tonic-gate 59033343a97Smeem if (!laadm_str_to_lacp_timer(optarg, &lacp_timer)) 59133343a97Smeem die("invalid LACP timer value '%s'", optarg); 5927c478bd9Sstevel@tonic-gate break; 5937c478bd9Sstevel@tonic-gate case 't': 5947c478bd9Sstevel@tonic-gate t_arg = B_TRUE; 5957c478bd9Sstevel@tonic-gate break; 5967c478bd9Sstevel@tonic-gate case 'R': 5977c478bd9Sstevel@tonic-gate altroot = optarg; 5987c478bd9Sstevel@tonic-gate break; 5997c478bd9Sstevel@tonic-gate default: 60033343a97Smeem die_opterr(optopt, option); 60133343a97Smeem break; 6027c478bd9Sstevel@tonic-gate } 6037c478bd9Sstevel@tonic-gate } 6047c478bd9Sstevel@tonic-gate 60533343a97Smeem if (modify_mask == 0) 60633343a97Smeem die("at least one of the -PulT options must be specified"); 6077c478bd9Sstevel@tonic-gate 6087c478bd9Sstevel@tonic-gate /* get key value (required last argument) */ 6097c478bd9Sstevel@tonic-gate if (optind != (argc-1)) 6107c478bd9Sstevel@tonic-gate usage(); 6117c478bd9Sstevel@tonic-gate 61233343a97Smeem if (!str2int(argv[optind], &key) || key < 1) 61333343a97Smeem die("invalid key value '%s'", argv[optind]); 6147c478bd9Sstevel@tonic-gate 6157c478bd9Sstevel@tonic-gate if (laadm_modify(key, modify_mask, policy, mac_addr_fixed, mac_addr, 61633343a97Smeem lacp_mode, lacp_timer, t_arg, altroot, &diag) < 0) 61733343a97Smeem die_laerr(diag, "modify operation failed"); 6187c478bd9Sstevel@tonic-gate } 6197c478bd9Sstevel@tonic-gate 6207c478bd9Sstevel@tonic-gate static void 6217c478bd9Sstevel@tonic-gate do_up_aggr(int argc, char *argv[]) 6227c478bd9Sstevel@tonic-gate { 62333343a97Smeem int key = 0; 6247c478bd9Sstevel@tonic-gate laadm_diag_t diag = 0; 6257c478bd9Sstevel@tonic-gate 6267c478bd9Sstevel@tonic-gate /* get aggregation key (optional last argument) */ 6277c478bd9Sstevel@tonic-gate if (argc == 2) { 62833343a97Smeem if (!str2int(argv[1], &key) || key < 1) 62933343a97Smeem die("invalid key value '%s'", argv[1]); 6307c478bd9Sstevel@tonic-gate } else if (argc > 2) { 6317c478bd9Sstevel@tonic-gate usage(); 6327c478bd9Sstevel@tonic-gate } 6337c478bd9Sstevel@tonic-gate 6347c478bd9Sstevel@tonic-gate if (laadm_up(key, NULL, &diag) < 0) { 6357c478bd9Sstevel@tonic-gate if (key != 0) { 63633343a97Smeem die_laerr(diag, "could not bring up aggregation '%u'", 63733343a97Smeem key); 6387c478bd9Sstevel@tonic-gate } else { 63933343a97Smeem die_laerr(diag, "could not bring aggregations up"); 6407c478bd9Sstevel@tonic-gate } 6417c478bd9Sstevel@tonic-gate } 6427c478bd9Sstevel@tonic-gate } 6437c478bd9Sstevel@tonic-gate 6447c478bd9Sstevel@tonic-gate static void 6457c478bd9Sstevel@tonic-gate do_down_aggr(int argc, char *argv[]) 6467c478bd9Sstevel@tonic-gate { 64733343a97Smeem int key = 0; 6487c478bd9Sstevel@tonic-gate 6497c478bd9Sstevel@tonic-gate /* get aggregation key (optional last argument) */ 6507c478bd9Sstevel@tonic-gate if (argc == 2) { 65133343a97Smeem if (!str2int(argv[1], &key) || key < 1) 65233343a97Smeem die("invalid key value '%s'", argv[1]); 6537c478bd9Sstevel@tonic-gate } else if (argc > 2) { 6547c478bd9Sstevel@tonic-gate usage(); 6557c478bd9Sstevel@tonic-gate } 6567c478bd9Sstevel@tonic-gate 6577c478bd9Sstevel@tonic-gate if (laadm_down(key) < 0) { 6587c478bd9Sstevel@tonic-gate if (key != 0) { 65933343a97Smeem die("could not bring down aggregation '%u': %s", 66033343a97Smeem key, strerror(errno)); 6617c478bd9Sstevel@tonic-gate } else { 66233343a97Smeem die("could not bring down aggregations: %s", 66333343a97Smeem strerror(errno)); 6647c478bd9Sstevel@tonic-gate } 6657c478bd9Sstevel@tonic-gate } 6667c478bd9Sstevel@tonic-gate } 6677c478bd9Sstevel@tonic-gate 6687c478bd9Sstevel@tonic-gate #define TYPE_WIDTH 10 669210db224Sericheng 670210db224Sericheng static void 671210db224Sericheng print_link_parseable(const char *name, dladm_attr_t *dap, boolean_t legacy) 672210db224Sericheng { 673210db224Sericheng char type[TYPE_WIDTH]; 674210db224Sericheng 675210db224Sericheng if (!legacy) { 676ba2e4443Sseb char drv[LIFNAMSIZ]; 677ba2e4443Sseb int instance; 678ba2e4443Sseb 679210db224Sericheng if (dap->da_vid != 0) { 680210db224Sericheng (void) snprintf(type, TYPE_WIDTH, "vlan %u", 681210db224Sericheng dap->da_vid); 682210db224Sericheng } else { 683210db224Sericheng (void) snprintf(type, TYPE_WIDTH, "non-vlan"); 684210db224Sericheng } 685ba2e4443Sseb if (dlpi_if_parse(dap->da_dev, drv, &instance) != 0) 686ba2e4443Sseb return; 687ba2e4443Sseb if (strncmp(drv, AGGR_DRV, sizeof (AGGR_DRV)) == 0) { 688210db224Sericheng (void) printf("%s type=%s mtu=%d key=%u\n", 689ba2e4443Sseb name, type, dap->da_max_sdu, instance); 690210db224Sericheng } else { 691210db224Sericheng (void) printf("%s type=%s mtu=%d device=%s\n", 692210db224Sericheng name, type, dap->da_max_sdu, dap->da_dev); 693210db224Sericheng } 694210db224Sericheng } else { 695210db224Sericheng (void) printf("%s type=legacy mtu=%d device=%s\n", 696210db224Sericheng name, dap->da_max_sdu, name); 697210db224Sericheng } 698210db224Sericheng } 699210db224Sericheng 700210db224Sericheng static void 701210db224Sericheng print_link(const char *name, dladm_attr_t *dap, boolean_t legacy) 702210db224Sericheng { 703210db224Sericheng char type[TYPE_WIDTH]; 704210db224Sericheng 705210db224Sericheng if (!legacy) { 706ba2e4443Sseb char drv[LIFNAMSIZ]; 707ba2e4443Sseb int instance; 708ba2e4443Sseb 709210db224Sericheng if (dap->da_vid != 0) { 710210db224Sericheng (void) snprintf(type, TYPE_WIDTH, gettext("vlan %u"), 711210db224Sericheng dap->da_vid); 712210db224Sericheng } else { 713210db224Sericheng (void) snprintf(type, TYPE_WIDTH, gettext("non-vlan")); 714210db224Sericheng } 715ba2e4443Sseb if (dlpi_if_parse(dap->da_dev, drv, &instance) != 0) 716ba2e4443Sseb return; 717ba2e4443Sseb if (strncmp(drv, AGGR_DRV, sizeof (AGGR_DRV)) == 0) { 718210db224Sericheng (void) printf(gettext("%-9s\ttype: %s\tmtu: %d" 719210db224Sericheng "\taggregation: key %u\n"), name, type, 720ba2e4443Sseb dap->da_max_sdu, instance); 721210db224Sericheng } else { 722210db224Sericheng (void) printf(gettext("%-9s\ttype: %s\tmtu: " 723210db224Sericheng "%d\tdevice: %s\n"), name, type, dap->da_max_sdu, 724210db224Sericheng dap->da_dev); 725210db224Sericheng } 726210db224Sericheng } else { 727210db224Sericheng (void) printf(gettext("%-9s\ttype: legacy\tmtu: " 728210db224Sericheng "%d\tdevice: %s\n"), name, dap->da_max_sdu, name); 729210db224Sericheng } 730210db224Sericheng } 731210db224Sericheng 732210db224Sericheng static int 733210db224Sericheng get_if_info(const char *name, dladm_attr_t *dlattrp, boolean_t *legacy) 734210db224Sericheng { 735210db224Sericheng int err; 736210db224Sericheng 737210db224Sericheng if ((err = dladm_info(name, dlattrp)) == 0) { 738210db224Sericheng *legacy = B_FALSE; 739210db224Sericheng } else if (err < 0 && errno == ENODEV) { 740210db224Sericheng int fd; 741210db224Sericheng dlpi_if_attr_t dia; 742210db224Sericheng dl_info_ack_t dlia; 743210db224Sericheng 744210db224Sericheng /* 745210db224Sericheng * A return value of ENODEV means that the specified 746210db224Sericheng * device is not gldv3. 747210db224Sericheng */ 748210db224Sericheng if ((fd = dlpi_if_open(name, &dia, B_FALSE)) != -1 && 749210db224Sericheng dlpi_info(fd, -1, &dlia, NULL, NULL, NULL, NULL, 750210db224Sericheng NULL, NULL) != -1) { 751210db224Sericheng (void) dlpi_close(fd); 752210db224Sericheng 753210db224Sericheng *legacy = B_TRUE; 754210db224Sericheng bzero(dlattrp, sizeof (*dlattrp)); 755210db224Sericheng dlattrp->da_max_sdu = (uint_t)dlia.dl_max_sdu; 756210db224Sericheng } else { 757210db224Sericheng errno = ENOENT; 758210db224Sericheng return (-1); 759210db224Sericheng } 760210db224Sericheng } else { 761210db224Sericheng /* 762210db224Sericheng * If the return value is not ENODEV, this means that 763210db224Sericheng * user is either passing in a bogus interface name 764210db224Sericheng * or a vlan interface name that doesn't exist yet. 765210db224Sericheng */ 766210db224Sericheng errno = ENOENT; 767210db224Sericheng return (-1); 768210db224Sericheng } 769210db224Sericheng return (0); 770210db224Sericheng } 7717c478bd9Sstevel@tonic-gate 7727c478bd9Sstevel@tonic-gate /* ARGSUSED */ 7737c478bd9Sstevel@tonic-gate static void 7747c478bd9Sstevel@tonic-gate show_link(void *arg, const char *name) 7757c478bd9Sstevel@tonic-gate { 7767c478bd9Sstevel@tonic-gate dladm_attr_t dlattr; 777210db224Sericheng boolean_t legacy = B_TRUE; 7787c478bd9Sstevel@tonic-gate show_link_state_t *state = (show_link_state_t *)arg; 7797c478bd9Sstevel@tonic-gate 78033343a97Smeem if (get_if_info(name, &dlattr, &legacy) < 0) 78133343a97Smeem die("invalid link '%s'", name); 7827c478bd9Sstevel@tonic-gate 783210db224Sericheng if (state->ls_parseable) { 784210db224Sericheng print_link_parseable(name, &dlattr, legacy); 7857c478bd9Sstevel@tonic-gate } else { 786210db224Sericheng print_link(name, &dlattr, legacy); 7877c478bd9Sstevel@tonic-gate } 7887c478bd9Sstevel@tonic-gate } 7897c478bd9Sstevel@tonic-gate 7907c478bd9Sstevel@tonic-gate static void 7917c478bd9Sstevel@tonic-gate show_link_stats(void *arg, const char *name) 7927c478bd9Sstevel@tonic-gate { 7937c478bd9Sstevel@tonic-gate show_link_state_t *state = (show_link_state_t *)arg; 7947c478bd9Sstevel@tonic-gate pktsum_t stats, diff_stats; 7957c478bd9Sstevel@tonic-gate 7967c478bd9Sstevel@tonic-gate if (state->ls_firstonly) { 7977c478bd9Sstevel@tonic-gate if (state->ls_donefirst) 7987c478bd9Sstevel@tonic-gate return; 7997c478bd9Sstevel@tonic-gate state->ls_donefirst = B_TRUE; 8007c478bd9Sstevel@tonic-gate } else { 8017c478bd9Sstevel@tonic-gate bzero(&state->ls_prevstats, sizeof (state->ls_prevstats)); 8027c478bd9Sstevel@tonic-gate } 8037c478bd9Sstevel@tonic-gate 8047c478bd9Sstevel@tonic-gate get_link_stats(name, &stats); 8057c478bd9Sstevel@tonic-gate stats_diff(&diff_stats, &stats, &state->ls_prevstats); 8067c478bd9Sstevel@tonic-gate 8077c478bd9Sstevel@tonic-gate (void) printf("%s", name); 8087c478bd9Sstevel@tonic-gate (void) printf("\t\t%-10llu", diff_stats.ipackets); 8097c478bd9Sstevel@tonic-gate (void) printf("%-12llu", diff_stats.rbytes); 8107c478bd9Sstevel@tonic-gate (void) printf("%-8u", diff_stats.ierrors); 8117c478bd9Sstevel@tonic-gate (void) printf("%-10llu", diff_stats.opackets); 8127c478bd9Sstevel@tonic-gate (void) printf("%-12llu", diff_stats.obytes); 8137c478bd9Sstevel@tonic-gate (void) printf("%-8u\n", diff_stats.oerrors); 8147c478bd9Sstevel@tonic-gate 8157c478bd9Sstevel@tonic-gate state->ls_prevstats = stats; 8167c478bd9Sstevel@tonic-gate } 8177c478bd9Sstevel@tonic-gate 8187c478bd9Sstevel@tonic-gate static void 8197c478bd9Sstevel@tonic-gate dump_grp(laadm_grp_attr_sys_t *grp, boolean_t parseable) 8207c478bd9Sstevel@tonic-gate { 8217c478bd9Sstevel@tonic-gate char policy_str[LAADM_POLICY_STR_LEN]; 8227c478bd9Sstevel@tonic-gate char addr_str[ETHERADDRL * 3]; 8237c478bd9Sstevel@tonic-gate 8247c478bd9Sstevel@tonic-gate if (!parseable) { 8257c478bd9Sstevel@tonic-gate (void) printf(gettext("key: %d (0x%04x)"), 8267c478bd9Sstevel@tonic-gate grp->lg_key, grp->lg_key); 8277c478bd9Sstevel@tonic-gate 8287c478bd9Sstevel@tonic-gate (void) printf(gettext("\tpolicy: %s"), 8297c478bd9Sstevel@tonic-gate laadm_policy_to_str(grp->lg_policy, policy_str)); 8307c478bd9Sstevel@tonic-gate 8317c478bd9Sstevel@tonic-gate (void) printf(gettext("\taddress: %s (%s)\n"), 8327c478bd9Sstevel@tonic-gate laadm_mac_addr_to_str(grp->lg_mac, addr_str), 8337c478bd9Sstevel@tonic-gate (grp->lg_mac_fixed) ? gettext("fixed") : gettext("auto")); 8347c478bd9Sstevel@tonic-gate } else { 8357c478bd9Sstevel@tonic-gate (void) printf("aggr key=%d", grp->lg_key); 8367c478bd9Sstevel@tonic-gate 8377c478bd9Sstevel@tonic-gate (void) printf(" policy=%s", 8387c478bd9Sstevel@tonic-gate laadm_policy_to_str(grp->lg_policy, policy_str)); 8397c478bd9Sstevel@tonic-gate 8407c478bd9Sstevel@tonic-gate (void) printf(" address=%s", 8417c478bd9Sstevel@tonic-gate laadm_mac_addr_to_str(grp->lg_mac, addr_str)); 8427c478bd9Sstevel@tonic-gate 8437c478bd9Sstevel@tonic-gate (void) printf(" address-type=%s\n", 8447c478bd9Sstevel@tonic-gate (grp->lg_mac_fixed) ? "fixed" : "auto"); 8457c478bd9Sstevel@tonic-gate } 8467c478bd9Sstevel@tonic-gate } 8477c478bd9Sstevel@tonic-gate 8487c478bd9Sstevel@tonic-gate static void 8497c478bd9Sstevel@tonic-gate dump_grp_lacp(laadm_grp_attr_sys_t *grp, boolean_t parseable) 8507c478bd9Sstevel@tonic-gate { 8517c478bd9Sstevel@tonic-gate const char *lacp_mode_str = laadm_lacp_mode_to_str(grp->lg_lacp_mode); 8527c478bd9Sstevel@tonic-gate const char *lacp_timer_str = 8537c478bd9Sstevel@tonic-gate laadm_lacp_timer_to_str(grp->lg_lacp_timer); 8547c478bd9Sstevel@tonic-gate 8557c478bd9Sstevel@tonic-gate if (!parseable) { 8567c478bd9Sstevel@tonic-gate (void) printf(gettext("\t\tLACP mode: %s"), lacp_mode_str); 8577c478bd9Sstevel@tonic-gate (void) printf(gettext("\tLACP timer: %s\n"), lacp_timer_str); 8587c478bd9Sstevel@tonic-gate } else { 8597c478bd9Sstevel@tonic-gate (void) printf(" lacp-mode=%s", lacp_mode_str); 8607c478bd9Sstevel@tonic-gate (void) printf(" lacp-timer=%s\n", lacp_timer_str); 8617c478bd9Sstevel@tonic-gate } 8627c478bd9Sstevel@tonic-gate } 8637c478bd9Sstevel@tonic-gate 8647c478bd9Sstevel@tonic-gate static void 8657c478bd9Sstevel@tonic-gate dump_grp_stats(laadm_grp_attr_sys_t *grp) 8667c478bd9Sstevel@tonic-gate { 8677c478bd9Sstevel@tonic-gate (void) printf("key: %d", grp->lg_key); 8687c478bd9Sstevel@tonic-gate (void) printf("\tipackets rbytes opackets obytes "); 8697c478bd9Sstevel@tonic-gate (void) printf("%%ipkts %%opkts\n"); 8707c478bd9Sstevel@tonic-gate } 8717c478bd9Sstevel@tonic-gate 8727c478bd9Sstevel@tonic-gate static void 8737c478bd9Sstevel@tonic-gate dump_ports_lacp_head(void) 8747c478bd9Sstevel@tonic-gate { 8757c478bd9Sstevel@tonic-gate (void) printf(DUMP_LACP_FORMAT, gettext("device"), gettext("activity"), 8767c478bd9Sstevel@tonic-gate gettext("timeout"), gettext("aggregatable"), gettext("sync"), 8777c478bd9Sstevel@tonic-gate gettext("coll"), gettext("dist"), gettext("defaulted"), 8787c478bd9Sstevel@tonic-gate gettext("expired")); 8797c478bd9Sstevel@tonic-gate } 8807c478bd9Sstevel@tonic-gate 8817c478bd9Sstevel@tonic-gate static void 8827c478bd9Sstevel@tonic-gate dump_ports_head(void) 8837c478bd9Sstevel@tonic-gate { 8847c478bd9Sstevel@tonic-gate (void) printf(gettext(" device\taddress\t\t speed\t\tduplex\tlink\t" 8857c478bd9Sstevel@tonic-gate "state\n")); 8867c478bd9Sstevel@tonic-gate } 8877c478bd9Sstevel@tonic-gate 8887c478bd9Sstevel@tonic-gate static char * 8897c478bd9Sstevel@tonic-gate port_state_to_str(aggr_port_state_t state_num) 8907c478bd9Sstevel@tonic-gate { 8917c478bd9Sstevel@tonic-gate int i; 8927c478bd9Sstevel@tonic-gate port_state_t *state; 8937c478bd9Sstevel@tonic-gate 8947c478bd9Sstevel@tonic-gate for (i = 0; i < NPORTSTATES; i++) { 8957c478bd9Sstevel@tonic-gate state = &port_states[i]; 8967c478bd9Sstevel@tonic-gate if (state->state_num == state_num) 8977c478bd9Sstevel@tonic-gate return (state->state_name); 8987c478bd9Sstevel@tonic-gate } 8997c478bd9Sstevel@tonic-gate 9007c478bd9Sstevel@tonic-gate return ("unknown"); 9017c478bd9Sstevel@tonic-gate } 9027c478bd9Sstevel@tonic-gate 9037c478bd9Sstevel@tonic-gate static void 9047c478bd9Sstevel@tonic-gate dump_port(laadm_port_attr_sys_t *port, boolean_t parseable) 9057c478bd9Sstevel@tonic-gate { 9067c478bd9Sstevel@tonic-gate char *dev = port->lp_devname; 9077c478bd9Sstevel@tonic-gate char buf[ETHERADDRL * 3]; 9087c478bd9Sstevel@tonic-gate 9097c478bd9Sstevel@tonic-gate if (!parseable) { 9107c478bd9Sstevel@tonic-gate (void) printf(" %-9s\t%s", dev, laadm_mac_addr_to_str( 9117c478bd9Sstevel@tonic-gate port->lp_mac, buf)); 91233343a97Smeem (void) printf("\t %5uMb", (int)(mac_ifspeed(dev) / 9137c478bd9Sstevel@tonic-gate 1000000ull)); 914ba2e4443Sseb (void) printf("\t%s", mac_link_duplex(dev)); 915ba2e4443Sseb (void) printf("\t%s", mac_link_state(dev)); 9167c478bd9Sstevel@tonic-gate (void) printf("\t%s\n", port_state_to_str(port->lp_state)); 9177c478bd9Sstevel@tonic-gate 9187c478bd9Sstevel@tonic-gate } else { 9197c478bd9Sstevel@tonic-gate (void) printf(" device=%s address=%s", dev, 9207c478bd9Sstevel@tonic-gate laadm_mac_addr_to_str(port->lp_mac, buf)); 921ba2e4443Sseb (void) printf(" speed=%u", (int)(mac_ifspeed(dev) / 9227c478bd9Sstevel@tonic-gate 1000000ull)); 923ba2e4443Sseb (void) printf(" duplex=%s", mac_link_duplex(dev)); 924ba2e4443Sseb (void) printf(" link=%s", mac_link_state(dev)); 9257c478bd9Sstevel@tonic-gate (void) printf(" port=%s", port_state_to_str(port->lp_state)); 9267c478bd9Sstevel@tonic-gate } 9277c478bd9Sstevel@tonic-gate } 9287c478bd9Sstevel@tonic-gate 9297c478bd9Sstevel@tonic-gate static void 9307c478bd9Sstevel@tonic-gate dump_port_lacp(laadm_port_attr_sys_t *port) 9317c478bd9Sstevel@tonic-gate { 9327c478bd9Sstevel@tonic-gate aggr_lacp_state_t *state = &port->lp_lacp_state; 9337c478bd9Sstevel@tonic-gate 9347c478bd9Sstevel@tonic-gate (void) printf(DUMP_LACP_FORMAT, 9357c478bd9Sstevel@tonic-gate port->lp_devname, state->bit.activity ? "active" : "passive", 9367c478bd9Sstevel@tonic-gate state->bit.timeout ? "short" : "long", 9377c478bd9Sstevel@tonic-gate state->bit.aggregation ? "yes" : "no", 9387c478bd9Sstevel@tonic-gate state->bit.sync ? "yes" : "no", 9397c478bd9Sstevel@tonic-gate state->bit.collecting ? "yes" : "no", 9407c478bd9Sstevel@tonic-gate state->bit.distributing ? "yes" : "no", 9417c478bd9Sstevel@tonic-gate state->bit.defaulted ? "yes" : "no", 9427c478bd9Sstevel@tonic-gate state->bit.expired ? "yes" : "no"); 9437c478bd9Sstevel@tonic-gate } 9447c478bd9Sstevel@tonic-gate 9457c478bd9Sstevel@tonic-gate static void 9467c478bd9Sstevel@tonic-gate dump_port_stat(int index, show_grp_state_t *state, pktsum_t *port_stats, 9477c478bd9Sstevel@tonic-gate pktsum_t *tot_stats) 9487c478bd9Sstevel@tonic-gate { 9497c478bd9Sstevel@tonic-gate pktsum_t diff_stats; 9507c478bd9Sstevel@tonic-gate pktsum_t *old_stats = &state->gs_prevstats[index]; 9517c478bd9Sstevel@tonic-gate 9527c478bd9Sstevel@tonic-gate stats_diff(&diff_stats, port_stats, old_stats); 9537c478bd9Sstevel@tonic-gate 9547c478bd9Sstevel@tonic-gate (void) printf("\t%-10llu", diff_stats.ipackets); 9557c478bd9Sstevel@tonic-gate (void) printf("%-12llu", diff_stats.rbytes); 9567c478bd9Sstevel@tonic-gate (void) printf("%-10llu", diff_stats.opackets); 9577c478bd9Sstevel@tonic-gate (void) printf("%-12llu", diff_stats.obytes); 9587c478bd9Sstevel@tonic-gate 9597c478bd9Sstevel@tonic-gate if (tot_stats->ipackets == 0) 9607c478bd9Sstevel@tonic-gate (void) printf("\t-"); 9617c478bd9Sstevel@tonic-gate else 9627c478bd9Sstevel@tonic-gate (void) printf("\t%-6.1f", (double)diff_stats.ipackets/ 9637c478bd9Sstevel@tonic-gate (double)tot_stats->ipackets * 100); 9647c478bd9Sstevel@tonic-gate 9657c478bd9Sstevel@tonic-gate if (tot_stats->opackets == 0) 9667c478bd9Sstevel@tonic-gate (void) printf("\t-"); 9677c478bd9Sstevel@tonic-gate else 9687c478bd9Sstevel@tonic-gate (void) printf("\t%-6.1f", (double)diff_stats.opackets/ 9697c478bd9Sstevel@tonic-gate (double)tot_stats->opackets * 100); 9707c478bd9Sstevel@tonic-gate 9717c478bd9Sstevel@tonic-gate (void) printf("\n"); 9727c478bd9Sstevel@tonic-gate 9737c478bd9Sstevel@tonic-gate *old_stats = *port_stats; 9747c478bd9Sstevel@tonic-gate } 9757c478bd9Sstevel@tonic-gate 9767c478bd9Sstevel@tonic-gate static int 9777c478bd9Sstevel@tonic-gate show_key(void *arg, laadm_grp_attr_sys_t *grp) 9787c478bd9Sstevel@tonic-gate { 9797c478bd9Sstevel@tonic-gate show_grp_state_t *state = (show_grp_state_t *)arg; 9807c478bd9Sstevel@tonic-gate int i; 9817c478bd9Sstevel@tonic-gate pktsum_t pktsumtot, port_stat; 9827c478bd9Sstevel@tonic-gate 9837c478bd9Sstevel@tonic-gate if (state->gs_key != 0 && state->gs_key != grp->lg_key) 9847c478bd9Sstevel@tonic-gate return (0); 9857c478bd9Sstevel@tonic-gate if (state->gs_firstonly) { 9867c478bd9Sstevel@tonic-gate if (state->gs_found) 9877c478bd9Sstevel@tonic-gate return (0); 9887c478bd9Sstevel@tonic-gate } else { 9897c478bd9Sstevel@tonic-gate bzero(&state->gs_prevstats, sizeof (state->gs_prevstats)); 9907c478bd9Sstevel@tonic-gate } 9917c478bd9Sstevel@tonic-gate 9927c478bd9Sstevel@tonic-gate state->gs_found = B_TRUE; 9937c478bd9Sstevel@tonic-gate 9947c478bd9Sstevel@tonic-gate if (state->gs_stats) { 9957c478bd9Sstevel@tonic-gate /* show statistics */ 9967c478bd9Sstevel@tonic-gate dump_grp_stats(grp); 9977c478bd9Sstevel@tonic-gate 9987c478bd9Sstevel@tonic-gate /* sum the ports statistics */ 9997c478bd9Sstevel@tonic-gate bzero(&pktsumtot, sizeof (pktsumtot)); 10007c478bd9Sstevel@tonic-gate for (i = 0; i < grp->lg_nports; i++) { 1001ba2e4443Sseb get_mac_stats(grp->lg_ports[i].lp_devname, &port_stat); 10027c478bd9Sstevel@tonic-gate stats_total(&pktsumtot, &port_stat, 10037c478bd9Sstevel@tonic-gate &state->gs_prevstats[i]); 10047c478bd9Sstevel@tonic-gate } 10057c478bd9Sstevel@tonic-gate 10067c478bd9Sstevel@tonic-gate (void) printf(" Total"); 10077c478bd9Sstevel@tonic-gate (void) printf("\t%-10llu", pktsumtot.ipackets); 10087c478bd9Sstevel@tonic-gate (void) printf("%-12llu", pktsumtot.rbytes); 10097c478bd9Sstevel@tonic-gate (void) printf("%-10llu", pktsumtot.opackets); 10107c478bd9Sstevel@tonic-gate (void) printf("%-12llu\n", pktsumtot.obytes); 10117c478bd9Sstevel@tonic-gate 10127c478bd9Sstevel@tonic-gate for (i = 0; i < grp->lg_nports; i++) { 1013ba2e4443Sseb get_mac_stats(grp->lg_ports[i].lp_devname, &port_stat); 10147c478bd9Sstevel@tonic-gate (void) printf(" %s", grp->lg_ports[i].lp_devname); 10157c478bd9Sstevel@tonic-gate dump_port_stat(i, state, &port_stat, &pktsumtot); 10167c478bd9Sstevel@tonic-gate } 10177c478bd9Sstevel@tonic-gate } else if (state->gs_lacp) { 10187c478bd9Sstevel@tonic-gate /* show LACP info */ 10197c478bd9Sstevel@tonic-gate dump_grp(grp, state->gs_parseable); 10207c478bd9Sstevel@tonic-gate dump_grp_lacp(grp, state->gs_parseable); 10217c478bd9Sstevel@tonic-gate dump_ports_lacp_head(); 10227c478bd9Sstevel@tonic-gate for (i = 0; i < grp->lg_nports; i++) 10237c478bd9Sstevel@tonic-gate dump_port_lacp(&grp->lg_ports[i]); 10247c478bd9Sstevel@tonic-gate } else { 10257c478bd9Sstevel@tonic-gate dump_grp(grp, state->gs_parseable); 10267c478bd9Sstevel@tonic-gate if (!state->gs_parseable) 10277c478bd9Sstevel@tonic-gate dump_ports_head(); 10287c478bd9Sstevel@tonic-gate for (i = 0; i < grp->lg_nports; i++) { 10297c478bd9Sstevel@tonic-gate if (state->gs_parseable) 10307c478bd9Sstevel@tonic-gate (void) printf("dev key=%d", grp->lg_key); 10317c478bd9Sstevel@tonic-gate dump_port(&grp->lg_ports[i], state->gs_parseable); 10327c478bd9Sstevel@tonic-gate if (state->gs_parseable) 10337c478bd9Sstevel@tonic-gate (void) printf("\n"); 10347c478bd9Sstevel@tonic-gate } 10357c478bd9Sstevel@tonic-gate } 10367c478bd9Sstevel@tonic-gate 10377c478bd9Sstevel@tonic-gate return (0); 10387c478bd9Sstevel@tonic-gate } 10397c478bd9Sstevel@tonic-gate 10407c478bd9Sstevel@tonic-gate static int 10417c478bd9Sstevel@tonic-gate kstat_value(kstat_t *ksp, const char *name, uint8_t type, void *buf) 10427c478bd9Sstevel@tonic-gate { 10437c478bd9Sstevel@tonic-gate kstat_named_t *knp; 10447c478bd9Sstevel@tonic-gate 10457c478bd9Sstevel@tonic-gate if ((knp = kstat_data_lookup(ksp, (char *)name)) == NULL) 10467c478bd9Sstevel@tonic-gate return (-1); 10477c478bd9Sstevel@tonic-gate 10487c478bd9Sstevel@tonic-gate if (knp->data_type != type) 10497c478bd9Sstevel@tonic-gate return (-1); 10507c478bd9Sstevel@tonic-gate 10517c478bd9Sstevel@tonic-gate switch (type) { 10527c478bd9Sstevel@tonic-gate case KSTAT_DATA_UINT64: 10537c478bd9Sstevel@tonic-gate *(uint64_t *)buf = knp->value.ui64; 10547c478bd9Sstevel@tonic-gate break; 10557c478bd9Sstevel@tonic-gate case KSTAT_DATA_UINT32: 10567c478bd9Sstevel@tonic-gate *(uint32_t *)buf = knp->value.ui32; 10577c478bd9Sstevel@tonic-gate break; 10587c478bd9Sstevel@tonic-gate default: 10597c478bd9Sstevel@tonic-gate return (-1); 10607c478bd9Sstevel@tonic-gate } 10617c478bd9Sstevel@tonic-gate 10627c478bd9Sstevel@tonic-gate return (0); 10637c478bd9Sstevel@tonic-gate } 10647c478bd9Sstevel@tonic-gate 10657c478bd9Sstevel@tonic-gate static void 1066210db224Sericheng show_dev(void *arg, const char *dev) 10677c478bd9Sstevel@tonic-gate { 10687c478bd9Sstevel@tonic-gate show_mac_state_t *state = (show_mac_state_t *)arg; 10697c478bd9Sstevel@tonic-gate 10707c478bd9Sstevel@tonic-gate (void) printf("%s", dev); 10717c478bd9Sstevel@tonic-gate 10727c478bd9Sstevel@tonic-gate if (!state->ms_parseable) { 10737c478bd9Sstevel@tonic-gate (void) printf(gettext("\t\tlink: %s"), 1074ba2e4443Sseb mac_link_state(dev)); 107533343a97Smeem (void) printf(gettext("\tspeed: %5uMb"), 1076ba2e4443Sseb (unsigned int)(mac_ifspeed(dev) / 1000000ull)); 10777c478bd9Sstevel@tonic-gate (void) printf(gettext("\tduplex: %s\n"), 1078ba2e4443Sseb mac_link_duplex(dev)); 10797c478bd9Sstevel@tonic-gate } else { 1080ba2e4443Sseb (void) printf(" link=%s", mac_link_state(dev)); 10817c478bd9Sstevel@tonic-gate (void) printf(" speed=%u", 1082ba2e4443Sseb (unsigned int)(mac_ifspeed(dev) / 1000000ull)); 1083ba2e4443Sseb (void) printf(" duplex=%s\n", mac_link_duplex(dev)); 10847c478bd9Sstevel@tonic-gate } 10857c478bd9Sstevel@tonic-gate } 10867c478bd9Sstevel@tonic-gate 10877c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 10887c478bd9Sstevel@tonic-gate static void 1089210db224Sericheng show_dev_stats(void *arg, const char *dev) 10907c478bd9Sstevel@tonic-gate { 10917c478bd9Sstevel@tonic-gate show_mac_state_t *state = (show_mac_state_t *)arg; 10927c478bd9Sstevel@tonic-gate pktsum_t stats, diff_stats; 10937c478bd9Sstevel@tonic-gate 10947c478bd9Sstevel@tonic-gate if (state->ms_firstonly) { 10957c478bd9Sstevel@tonic-gate if (state->ms_donefirst) 10967c478bd9Sstevel@tonic-gate return; 10977c478bd9Sstevel@tonic-gate state->ms_donefirst = B_TRUE; 10987c478bd9Sstevel@tonic-gate } else { 10997c478bd9Sstevel@tonic-gate bzero(&state->ms_prevstats, sizeof (state->ms_prevstats)); 11007c478bd9Sstevel@tonic-gate } 11017c478bd9Sstevel@tonic-gate 1102ba2e4443Sseb get_mac_stats(dev, &stats); 11037c478bd9Sstevel@tonic-gate stats_diff(&diff_stats, &stats, &state->ms_prevstats); 11047c478bd9Sstevel@tonic-gate 11057c478bd9Sstevel@tonic-gate (void) printf("%s", dev); 11067c478bd9Sstevel@tonic-gate (void) printf("\t\t%-10llu", diff_stats.ipackets); 11077c478bd9Sstevel@tonic-gate (void) printf("%-12llu", diff_stats.rbytes); 11087c478bd9Sstevel@tonic-gate (void) printf("%-8u", diff_stats.ierrors); 11097c478bd9Sstevel@tonic-gate (void) printf("%-10llu", diff_stats.opackets); 11107c478bd9Sstevel@tonic-gate (void) printf("%-12llu", diff_stats.obytes); 11117c478bd9Sstevel@tonic-gate (void) printf("%-8u\n", diff_stats.oerrors); 11127c478bd9Sstevel@tonic-gate 11137c478bd9Sstevel@tonic-gate state->ms_prevstats = stats; 11147c478bd9Sstevel@tonic-gate } 11157c478bd9Sstevel@tonic-gate 11167c478bd9Sstevel@tonic-gate static void 11177c478bd9Sstevel@tonic-gate do_show_link(int argc, char *argv[]) 11187c478bd9Sstevel@tonic-gate { 11197c478bd9Sstevel@tonic-gate char *name = NULL; 11207c478bd9Sstevel@tonic-gate int option; 11217c478bd9Sstevel@tonic-gate boolean_t s_arg = B_FALSE; 11227c478bd9Sstevel@tonic-gate boolean_t i_arg = B_FALSE; 112333343a97Smeem int interval = 0; 11247c478bd9Sstevel@tonic-gate show_link_state_t state; 11257c478bd9Sstevel@tonic-gate 11267c478bd9Sstevel@tonic-gate state.ls_stats = B_FALSE; 11277c478bd9Sstevel@tonic-gate state.ls_parseable = B_FALSE; 11287c478bd9Sstevel@tonic-gate 11297c478bd9Sstevel@tonic-gate opterr = 0; 11307c478bd9Sstevel@tonic-gate while ((option = getopt_long(argc, argv, ":psi:", 11317c478bd9Sstevel@tonic-gate longopts, NULL)) != -1) { 11327c478bd9Sstevel@tonic-gate switch (option) { 11337c478bd9Sstevel@tonic-gate case 'p': 11347c478bd9Sstevel@tonic-gate state.ls_parseable = B_TRUE; 11357c478bd9Sstevel@tonic-gate break; 11367c478bd9Sstevel@tonic-gate case 's': 113733343a97Smeem if (s_arg) 113833343a97Smeem die_optdup(option); 11397c478bd9Sstevel@tonic-gate 11407c478bd9Sstevel@tonic-gate s_arg = B_TRUE; 11417c478bd9Sstevel@tonic-gate break; 11427c478bd9Sstevel@tonic-gate case 'i': 114333343a97Smeem if (i_arg) 114433343a97Smeem die_optdup(option); 11457c478bd9Sstevel@tonic-gate 11467c478bd9Sstevel@tonic-gate i_arg = B_TRUE; 114733343a97Smeem if (!str2int(optarg, &interval) || interval == 0) 114833343a97Smeem die("invalid interval value '%s'", optarg); 11497c478bd9Sstevel@tonic-gate break; 11507c478bd9Sstevel@tonic-gate default: 115133343a97Smeem die_opterr(optopt, option); 115233343a97Smeem break; 11537c478bd9Sstevel@tonic-gate } 11547c478bd9Sstevel@tonic-gate } 11557c478bd9Sstevel@tonic-gate 115633343a97Smeem if (i_arg && !s_arg) 115733343a97Smeem die("the option -i can be used only with -s"); 11587c478bd9Sstevel@tonic-gate 11597c478bd9Sstevel@tonic-gate /* get link name (optional last argument) */ 11607c478bd9Sstevel@tonic-gate if (optind == (argc-1)) 11617c478bd9Sstevel@tonic-gate name = argv[optind]; 11627c478bd9Sstevel@tonic-gate else if (optind != argc) 11637c478bd9Sstevel@tonic-gate usage(); 11647c478bd9Sstevel@tonic-gate 11657c478bd9Sstevel@tonic-gate if (s_arg) { 11667c478bd9Sstevel@tonic-gate link_stats(name, interval); 11677c478bd9Sstevel@tonic-gate return; 11687c478bd9Sstevel@tonic-gate } 11697c478bd9Sstevel@tonic-gate 1170210db224Sericheng if (name == NULL) { 11717c478bd9Sstevel@tonic-gate (void) dladm_walk(show_link, &state); 1172210db224Sericheng } else { 11737c478bd9Sstevel@tonic-gate show_link(&state, name); 11747c478bd9Sstevel@tonic-gate } 1175210db224Sericheng } 11767c478bd9Sstevel@tonic-gate 11777c478bd9Sstevel@tonic-gate static void 11787c478bd9Sstevel@tonic-gate do_show_aggr(int argc, char *argv[]) 11797c478bd9Sstevel@tonic-gate { 11807c478bd9Sstevel@tonic-gate int option; 118133343a97Smeem int key = 0; 11827c478bd9Sstevel@tonic-gate boolean_t L_arg = B_FALSE; 11837c478bd9Sstevel@tonic-gate boolean_t s_arg = B_FALSE; 11847c478bd9Sstevel@tonic-gate boolean_t i_arg = B_FALSE; 11857c478bd9Sstevel@tonic-gate show_grp_state_t state; 118633343a97Smeem int interval = 0; 11877c478bd9Sstevel@tonic-gate 11887c478bd9Sstevel@tonic-gate state.gs_stats = B_FALSE; 11897c478bd9Sstevel@tonic-gate state.gs_lacp = B_FALSE; 11907c478bd9Sstevel@tonic-gate state.gs_parseable = B_FALSE; 11917c478bd9Sstevel@tonic-gate 11927c478bd9Sstevel@tonic-gate opterr = 0; 11937c478bd9Sstevel@tonic-gate while ((option = getopt_long(argc, argv, ":Lpsi:", 11947c478bd9Sstevel@tonic-gate longopts, NULL)) != -1) { 11957c478bd9Sstevel@tonic-gate switch (option) { 11967c478bd9Sstevel@tonic-gate case 'L': 119733343a97Smeem if (L_arg) 119833343a97Smeem die_optdup(option); 11997c478bd9Sstevel@tonic-gate 12007c478bd9Sstevel@tonic-gate if (s_arg || i_arg) { 120133343a97Smeem die("the option -L cannot be used with -i " 120233343a97Smeem "or -s"); 12037c478bd9Sstevel@tonic-gate } 12047c478bd9Sstevel@tonic-gate 12057c478bd9Sstevel@tonic-gate L_arg = B_TRUE; 12067c478bd9Sstevel@tonic-gate state.gs_lacp = B_TRUE; 12077c478bd9Sstevel@tonic-gate break; 12087c478bd9Sstevel@tonic-gate case 'p': 12097c478bd9Sstevel@tonic-gate state.gs_parseable = B_TRUE; 12107c478bd9Sstevel@tonic-gate break; 12117c478bd9Sstevel@tonic-gate case 's': 121233343a97Smeem if (s_arg) 121333343a97Smeem die_optdup(option); 12147c478bd9Sstevel@tonic-gate 121533343a97Smeem if (L_arg) 121613994ee8Sxz162242 die("the option -s cannot be used with -L"); 12177c478bd9Sstevel@tonic-gate 12187c478bd9Sstevel@tonic-gate s_arg = B_TRUE; 12197c478bd9Sstevel@tonic-gate break; 12207c478bd9Sstevel@tonic-gate case 'i': 122133343a97Smeem if (i_arg) 122233343a97Smeem die_optdup(option); 12237c478bd9Sstevel@tonic-gate 122433343a97Smeem if (L_arg) 122533343a97Smeem die("the option -i cannot be used with -L"); 12267c478bd9Sstevel@tonic-gate 12277c478bd9Sstevel@tonic-gate i_arg = B_TRUE; 122833343a97Smeem if (!str2int(optarg, &interval) || interval == 0) 122933343a97Smeem die("invalid interval value '%s'", optarg); 12307c478bd9Sstevel@tonic-gate break; 12317c478bd9Sstevel@tonic-gate default: 123233343a97Smeem die_opterr(optopt, option); 123333343a97Smeem break; 12347c478bd9Sstevel@tonic-gate } 12357c478bd9Sstevel@tonic-gate } 12367c478bd9Sstevel@tonic-gate 123733343a97Smeem if (i_arg && !s_arg) 123833343a97Smeem die("the option -i can be used only with -s"); 12397c478bd9Sstevel@tonic-gate 12407c478bd9Sstevel@tonic-gate /* get aggregation key (optional last argument) */ 12417c478bd9Sstevel@tonic-gate if (optind == (argc-1)) { 124233343a97Smeem if (!str2int(argv[optind], &key) || key < 1) 124333343a97Smeem die("invalid key value '%s'", argv[optind]); 12447c478bd9Sstevel@tonic-gate } else if (optind != argc) { 12457c478bd9Sstevel@tonic-gate usage(); 12467c478bd9Sstevel@tonic-gate } 12477c478bd9Sstevel@tonic-gate 12487c478bd9Sstevel@tonic-gate if (s_arg) { 12497c478bd9Sstevel@tonic-gate aggr_stats(key, interval); 12507c478bd9Sstevel@tonic-gate return; 12517c478bd9Sstevel@tonic-gate } 12527c478bd9Sstevel@tonic-gate 12537c478bd9Sstevel@tonic-gate state.gs_key = key; 12547c478bd9Sstevel@tonic-gate state.gs_found = B_FALSE; 12557c478bd9Sstevel@tonic-gate 12567c478bd9Sstevel@tonic-gate (void) laadm_walk_sys(show_key, &state); 12577c478bd9Sstevel@tonic-gate 125833343a97Smeem if (key != 0 && !state.gs_found) 125933343a97Smeem die("non-existent aggregation key '%u'", key); 12607c478bd9Sstevel@tonic-gate } 12617c478bd9Sstevel@tonic-gate 12627c478bd9Sstevel@tonic-gate static void 12637c478bd9Sstevel@tonic-gate do_show_dev(int argc, char *argv[]) 12647c478bd9Sstevel@tonic-gate { 12657c478bd9Sstevel@tonic-gate int option; 12667c478bd9Sstevel@tonic-gate char *dev = NULL; 12677c478bd9Sstevel@tonic-gate boolean_t s_arg = B_FALSE; 12687c478bd9Sstevel@tonic-gate boolean_t i_arg = B_FALSE; 126933343a97Smeem int interval = 0; 12707c478bd9Sstevel@tonic-gate show_mac_state_t state; 12717c478bd9Sstevel@tonic-gate 12727c478bd9Sstevel@tonic-gate state.ms_parseable = B_FALSE; 12737c478bd9Sstevel@tonic-gate 12747c478bd9Sstevel@tonic-gate opterr = 0; 12757c478bd9Sstevel@tonic-gate while ((option = getopt_long(argc, argv, ":psi:", 12767c478bd9Sstevel@tonic-gate longopts, NULL)) != -1) { 12777c478bd9Sstevel@tonic-gate switch (option) { 12787c478bd9Sstevel@tonic-gate case 'p': 12797c478bd9Sstevel@tonic-gate state.ms_parseable = B_TRUE; 12807c478bd9Sstevel@tonic-gate break; 12817c478bd9Sstevel@tonic-gate case 's': 128233343a97Smeem if (s_arg) 128333343a97Smeem die_optdup(option); 12847c478bd9Sstevel@tonic-gate 12857c478bd9Sstevel@tonic-gate s_arg = B_TRUE; 12867c478bd9Sstevel@tonic-gate break; 12877c478bd9Sstevel@tonic-gate case 'i': 128833343a97Smeem if (i_arg) 128933343a97Smeem die_optdup(option); 12907c478bd9Sstevel@tonic-gate 12917c478bd9Sstevel@tonic-gate i_arg = B_TRUE; 129233343a97Smeem if (!str2int(optarg, &interval) || interval == 0) 129333343a97Smeem die("invalid interval value '%s'", optarg); 12947c478bd9Sstevel@tonic-gate break; 12957c478bd9Sstevel@tonic-gate default: 129633343a97Smeem die_opterr(optopt, option); 129733343a97Smeem break; 12987c478bd9Sstevel@tonic-gate } 12997c478bd9Sstevel@tonic-gate } 13007c478bd9Sstevel@tonic-gate 130133343a97Smeem if (i_arg && !s_arg) 130233343a97Smeem die("the option -i can be used only with -s"); 13037c478bd9Sstevel@tonic-gate 13047c478bd9Sstevel@tonic-gate /* get dev name (optional last argument) */ 13057c478bd9Sstevel@tonic-gate if (optind == (argc-1)) 13067c478bd9Sstevel@tonic-gate dev = argv[optind]; 13077c478bd9Sstevel@tonic-gate else if (optind != argc) 13087c478bd9Sstevel@tonic-gate usage(); 13097c478bd9Sstevel@tonic-gate 1310cd93090eSericheng if (dev != NULL) { 1311cd93090eSericheng int index; 1312cd93090eSericheng char drv[LIFNAMSIZ]; 1313cd93090eSericheng dladm_attr_t dlattr; 1314cd93090eSericheng boolean_t legacy; 1315cd93090eSericheng 1316cd93090eSericheng /* 1317cd93090eSericheng * Check for invalid devices. 1318cd93090eSericheng * aggregations and vlans are not considered devices. 1319cd93090eSericheng */ 1320cd93090eSericheng if (strncmp(dev, "aggr", 4) == 0 || 1321cd93090eSericheng dlpi_if_parse(dev, drv, &index) < 0 || 132233343a97Smeem index >= 1000 || get_if_info(dev, &dlattr, &legacy) < 0) 132333343a97Smeem die("invalid device '%s'", dev); 1324cd93090eSericheng } 13257c478bd9Sstevel@tonic-gate 13267c478bd9Sstevel@tonic-gate if (s_arg) { 13277c478bd9Sstevel@tonic-gate dev_stats(dev, interval); 13287c478bd9Sstevel@tonic-gate return; 13297c478bd9Sstevel@tonic-gate } 13307c478bd9Sstevel@tonic-gate 13317c478bd9Sstevel@tonic-gate if (dev == NULL) 13327c478bd9Sstevel@tonic-gate (void) macadm_walk(show_dev, &state, B_TRUE); 13337c478bd9Sstevel@tonic-gate else 1334210db224Sericheng show_dev(&state, dev); 13357c478bd9Sstevel@tonic-gate } 13367c478bd9Sstevel@tonic-gate 13377c478bd9Sstevel@tonic-gate /* ARGSUSED */ 13387c478bd9Sstevel@tonic-gate static void 133933343a97Smeem link_stats(const char *link, uint_t interval) 13407c478bd9Sstevel@tonic-gate { 1341210db224Sericheng dladm_attr_t dlattr; 1342210db224Sericheng boolean_t legacy; 13437c478bd9Sstevel@tonic-gate show_link_state_t state; 13447c478bd9Sstevel@tonic-gate 134533343a97Smeem if (link != NULL && get_if_info(link, &dlattr, &legacy) < 0) 134633343a97Smeem die("invalid link '%s'", link); 134733343a97Smeem 13487c478bd9Sstevel@tonic-gate bzero(&state, sizeof (state)); 13497c478bd9Sstevel@tonic-gate 13507c478bd9Sstevel@tonic-gate /* 13517c478bd9Sstevel@tonic-gate * If an interval is specified, continuously show the stats 13527c478bd9Sstevel@tonic-gate * only for the first MAC port. 13537c478bd9Sstevel@tonic-gate */ 13547c478bd9Sstevel@tonic-gate state.ls_firstonly = (interval != 0); 13557c478bd9Sstevel@tonic-gate 13567c478bd9Sstevel@tonic-gate for (;;) { 13577c478bd9Sstevel@tonic-gate (void) printf("\t\tipackets rbytes ierrors "); 13587c478bd9Sstevel@tonic-gate (void) printf("opackets obytes oerrors\n"); 13597c478bd9Sstevel@tonic-gate 13607c478bd9Sstevel@tonic-gate state.ls_donefirst = B_FALSE; 13617c478bd9Sstevel@tonic-gate if (link == NULL) 13627c478bd9Sstevel@tonic-gate (void) dladm_walk(show_link_stats, &state); 13637c478bd9Sstevel@tonic-gate else 13647c478bd9Sstevel@tonic-gate show_link_stats(&state, link); 13657c478bd9Sstevel@tonic-gate 13667c478bd9Sstevel@tonic-gate if (interval == 0) 13677c478bd9Sstevel@tonic-gate break; 13687c478bd9Sstevel@tonic-gate 13697c478bd9Sstevel@tonic-gate (void) sleep(interval); 13707c478bd9Sstevel@tonic-gate } 13717c478bd9Sstevel@tonic-gate } 13727c478bd9Sstevel@tonic-gate 13737c478bd9Sstevel@tonic-gate /* ARGSUSED */ 13747c478bd9Sstevel@tonic-gate static void 137533343a97Smeem aggr_stats(uint32_t key, uint_t interval) 13767c478bd9Sstevel@tonic-gate { 13777c478bd9Sstevel@tonic-gate show_grp_state_t state; 13787c478bd9Sstevel@tonic-gate 13797c478bd9Sstevel@tonic-gate bzero(&state, sizeof (state)); 13807c478bd9Sstevel@tonic-gate state.gs_stats = B_TRUE; 13817c478bd9Sstevel@tonic-gate state.gs_key = key; 13827c478bd9Sstevel@tonic-gate 13837c478bd9Sstevel@tonic-gate /* 13847c478bd9Sstevel@tonic-gate * If an interval is specified, continuously show the stats 13857c478bd9Sstevel@tonic-gate * only for the first group. 13867c478bd9Sstevel@tonic-gate */ 13877c478bd9Sstevel@tonic-gate state.gs_firstonly = (interval != 0); 13887c478bd9Sstevel@tonic-gate 13897c478bd9Sstevel@tonic-gate for (;;) { 13907c478bd9Sstevel@tonic-gate state.gs_found = B_FALSE; 13917c478bd9Sstevel@tonic-gate (void) laadm_walk_sys(show_key, &state); 139233343a97Smeem if (state.gs_key != 0 && !state.gs_found) 139333343a97Smeem die("non-existent aggregation key '%u'", key); 13947c478bd9Sstevel@tonic-gate 13957c478bd9Sstevel@tonic-gate if (interval == 0) 13967c478bd9Sstevel@tonic-gate break; 13977c478bd9Sstevel@tonic-gate 13987c478bd9Sstevel@tonic-gate (void) sleep(interval); 13997c478bd9Sstevel@tonic-gate } 14007c478bd9Sstevel@tonic-gate } 14017c478bd9Sstevel@tonic-gate 14027c478bd9Sstevel@tonic-gate /* ARGSUSED */ 14037c478bd9Sstevel@tonic-gate static void 14047c478bd9Sstevel@tonic-gate dev_stats(const char *dev, uint32_t interval) 14057c478bd9Sstevel@tonic-gate { 14067c478bd9Sstevel@tonic-gate show_mac_state_t state; 14077c478bd9Sstevel@tonic-gate 14087c478bd9Sstevel@tonic-gate bzero(&state, sizeof (state)); 14097c478bd9Sstevel@tonic-gate 14107c478bd9Sstevel@tonic-gate /* 14117c478bd9Sstevel@tonic-gate * If an interval is specified, continuously show the stats 14127c478bd9Sstevel@tonic-gate * only for the first MAC port. 14137c478bd9Sstevel@tonic-gate */ 14147c478bd9Sstevel@tonic-gate state.ms_firstonly = (interval != 0); 14157c478bd9Sstevel@tonic-gate 14167c478bd9Sstevel@tonic-gate for (;;) { 14177c478bd9Sstevel@tonic-gate 14187c478bd9Sstevel@tonic-gate (void) printf("\t\tipackets rbytes ierrors "); 14197c478bd9Sstevel@tonic-gate (void) printf("opackets obytes oerrors\n"); 14207c478bd9Sstevel@tonic-gate 14217c478bd9Sstevel@tonic-gate state.ms_donefirst = B_FALSE; 1422210db224Sericheng if (dev == NULL) 14237c478bd9Sstevel@tonic-gate (void) macadm_walk(show_dev_stats, &state, B_TRUE); 1424210db224Sericheng else 1425210db224Sericheng show_dev_stats(&state, dev); 14267c478bd9Sstevel@tonic-gate 14277c478bd9Sstevel@tonic-gate if (interval == 0) 14287c478bd9Sstevel@tonic-gate break; 14297c478bd9Sstevel@tonic-gate 14307c478bd9Sstevel@tonic-gate (void) sleep(interval); 14317c478bd9Sstevel@tonic-gate } 14327c478bd9Sstevel@tonic-gate } 14337c478bd9Sstevel@tonic-gate 14347c478bd9Sstevel@tonic-gate /* accumulate stats (s1 += (s2 - s3)) */ 14357c478bd9Sstevel@tonic-gate static void 14367c478bd9Sstevel@tonic-gate stats_total(pktsum_t *s1, pktsum_t *s2, pktsum_t *s3) 14377c478bd9Sstevel@tonic-gate { 14387c478bd9Sstevel@tonic-gate s1->ipackets += (s2->ipackets - s3->ipackets); 14397c478bd9Sstevel@tonic-gate s1->opackets += (s2->opackets - s3->opackets); 14407c478bd9Sstevel@tonic-gate s1->rbytes += (s2->rbytes - s3->rbytes); 14417c478bd9Sstevel@tonic-gate s1->obytes += (s2->obytes - s3->obytes); 14427c478bd9Sstevel@tonic-gate s1->ierrors += (s2->ierrors - s3->ierrors); 14437c478bd9Sstevel@tonic-gate s1->oerrors += (s2->oerrors - s3->oerrors); 14447c478bd9Sstevel@tonic-gate } 14457c478bd9Sstevel@tonic-gate 14467c478bd9Sstevel@tonic-gate /* compute stats differences (s1 = s2 - s3) */ 14477c478bd9Sstevel@tonic-gate static void 14487c478bd9Sstevel@tonic-gate stats_diff(pktsum_t *s1, pktsum_t *s2, pktsum_t *s3) 14497c478bd9Sstevel@tonic-gate { 14507c478bd9Sstevel@tonic-gate s1->ipackets = s2->ipackets - s3->ipackets; 14517c478bd9Sstevel@tonic-gate s1->opackets = s2->opackets - s3->opackets; 14527c478bd9Sstevel@tonic-gate s1->rbytes = s2->rbytes - s3->rbytes; 14537c478bd9Sstevel@tonic-gate s1->obytes = s2->obytes - s3->obytes; 14547c478bd9Sstevel@tonic-gate s1->ierrors = s2->ierrors - s3->ierrors; 14557c478bd9Sstevel@tonic-gate s1->oerrors = s2->oerrors - s3->oerrors; 14567c478bd9Sstevel@tonic-gate } 14577c478bd9Sstevel@tonic-gate 1458cd93090eSericheng /* 1459ba2e4443Sseb * In the following routines, we do the first kstat_lookup() assuming that 1460ba2e4443Sseb * the device is gldv3-based and that the kstat name is the one passed in 1461ba2e4443Sseb * as the "name" argument. If the lookup fails, we redo the kstat_lookup() 1462ba2e4443Sseb * omitting the kstat name. This second lookup is needed for getting kstats 1463ba2e4443Sseb * from legacy devices. This can fail too if the device is not attached or 1464ba2e4443Sseb * the device is legacy and doesn't export the kstats we need. 1465cd93090eSericheng */ 14667c478bd9Sstevel@tonic-gate static void 14677c478bd9Sstevel@tonic-gate get_stats(char *module, int instance, char *name, pktsum_t *stats) 14687c478bd9Sstevel@tonic-gate { 14697c478bd9Sstevel@tonic-gate kstat_ctl_t *kcp; 14707c478bd9Sstevel@tonic-gate kstat_t *ksp; 14717c478bd9Sstevel@tonic-gate 14727c478bd9Sstevel@tonic-gate if ((kcp = kstat_open()) == NULL) { 147333343a97Smeem warn("kstat open operation failed"); 14747c478bd9Sstevel@tonic-gate return; 14757c478bd9Sstevel@tonic-gate } 14767c478bd9Sstevel@tonic-gate 1477cd93090eSericheng if ((ksp = kstat_lookup(kcp, module, instance, name)) == NULL && 1478ba2e4443Sseb (ksp = kstat_lookup(kcp, module, instance, NULL)) == NULL) { 14797c478bd9Sstevel@tonic-gate /* 14807c478bd9Sstevel@tonic-gate * The kstat query could fail if the underlying MAC 14817c478bd9Sstevel@tonic-gate * driver was already detached. 14827c478bd9Sstevel@tonic-gate */ 14837c478bd9Sstevel@tonic-gate (void) kstat_close(kcp); 14847c478bd9Sstevel@tonic-gate return; 14857c478bd9Sstevel@tonic-gate } 14867c478bd9Sstevel@tonic-gate 14877c478bd9Sstevel@tonic-gate if (kstat_read(kcp, ksp, NULL) == -1) 14887c478bd9Sstevel@tonic-gate goto bail; 14897c478bd9Sstevel@tonic-gate 14907c478bd9Sstevel@tonic-gate if (kstat_value(ksp, "ipackets64", KSTAT_DATA_UINT64, 14917c478bd9Sstevel@tonic-gate &stats->ipackets) < 0) 14927c478bd9Sstevel@tonic-gate goto bail; 14937c478bd9Sstevel@tonic-gate 14947c478bd9Sstevel@tonic-gate if (kstat_value(ksp, "opackets64", KSTAT_DATA_UINT64, 14957c478bd9Sstevel@tonic-gate &stats->opackets) < 0) 14967c478bd9Sstevel@tonic-gate goto bail; 14977c478bd9Sstevel@tonic-gate 14987c478bd9Sstevel@tonic-gate if (kstat_value(ksp, "rbytes64", KSTAT_DATA_UINT64, 14997c478bd9Sstevel@tonic-gate &stats->rbytes) < 0) 15007c478bd9Sstevel@tonic-gate goto bail; 15017c478bd9Sstevel@tonic-gate 15027c478bd9Sstevel@tonic-gate if (kstat_value(ksp, "obytes64", KSTAT_DATA_UINT64, 15037c478bd9Sstevel@tonic-gate &stats->obytes) < 0) 15047c478bd9Sstevel@tonic-gate goto bail; 15057c478bd9Sstevel@tonic-gate 15067c478bd9Sstevel@tonic-gate if (kstat_value(ksp, "ierrors", KSTAT_DATA_UINT32, 15077c478bd9Sstevel@tonic-gate &stats->ierrors) < 0) 15087c478bd9Sstevel@tonic-gate goto bail; 15097c478bd9Sstevel@tonic-gate 15107c478bd9Sstevel@tonic-gate if (kstat_value(ksp, "oerrors", KSTAT_DATA_UINT32, 15117c478bd9Sstevel@tonic-gate &stats->oerrors) < 0) 15127c478bd9Sstevel@tonic-gate goto bail; 15137c478bd9Sstevel@tonic-gate 15147c478bd9Sstevel@tonic-gate (void) kstat_close(kcp); 15157c478bd9Sstevel@tonic-gate return; 15167c478bd9Sstevel@tonic-gate 15177c478bd9Sstevel@tonic-gate bail: 15187c478bd9Sstevel@tonic-gate (void) kstat_close(kcp); 15197c478bd9Sstevel@tonic-gate } 15207c478bd9Sstevel@tonic-gate 15217c478bd9Sstevel@tonic-gate static void 1522ba2e4443Sseb get_mac_stats(const char *dev, pktsum_t *stats) 15237c478bd9Sstevel@tonic-gate { 1524ba2e4443Sseb char module[LIFNAMSIZ]; 1525ba2e4443Sseb int instance; 15267c478bd9Sstevel@tonic-gate 1527ba2e4443Sseb if (dlpi_if_parse(dev, module, &instance) != 0) 1528ba2e4443Sseb return; 15297c478bd9Sstevel@tonic-gate bzero(stats, sizeof (*stats)); 1530ba2e4443Sseb get_stats(module, instance, "mac", stats); 15317c478bd9Sstevel@tonic-gate } 15327c478bd9Sstevel@tonic-gate 15337c478bd9Sstevel@tonic-gate static void 15347c478bd9Sstevel@tonic-gate get_link_stats(const char *link, pktsum_t *stats) 15357c478bd9Sstevel@tonic-gate { 1536ba2e4443Sseb char module[LIFNAMSIZ]; 1537ba2e4443Sseb int instance; 1538ba2e4443Sseb 1539ba2e4443Sseb if (dlpi_if_parse(link, module, &instance) != 0) 1540ba2e4443Sseb return; 15417c478bd9Sstevel@tonic-gate bzero(stats, sizeof (*stats)); 1542ba2e4443Sseb get_stats(module, instance, (char *)link, stats); 15437c478bd9Sstevel@tonic-gate } 15447c478bd9Sstevel@tonic-gate 1545ba2e4443Sseb static int 1546ba2e4443Sseb get_single_mac_stat(const char *dev, const char *name, uint8_t type, 1547ba2e4443Sseb void *val) 15487c478bd9Sstevel@tonic-gate { 1549ba2e4443Sseb char module[LIFNAMSIZ]; 1550ba2e4443Sseb int instance; 15517c478bd9Sstevel@tonic-gate kstat_ctl_t *kcp; 15527c478bd9Sstevel@tonic-gate kstat_t *ksp; 15537c478bd9Sstevel@tonic-gate 15547c478bd9Sstevel@tonic-gate if ((kcp = kstat_open()) == NULL) { 155533343a97Smeem warn("kstat open operation failed"); 1556ba2e4443Sseb return (-1); 15577c478bd9Sstevel@tonic-gate } 15587c478bd9Sstevel@tonic-gate 1559ba2e4443Sseb if (dlpi_if_parse(dev, module, &instance) != 0) 1560ba2e4443Sseb return (-1); 1561ba2e4443Sseb if ((ksp = kstat_lookup(kcp, module, instance, "mac")) == NULL && 1562ba2e4443Sseb (ksp = kstat_lookup(kcp, module, instance, NULL)) == NULL) { 15637c478bd9Sstevel@tonic-gate /* 15647c478bd9Sstevel@tonic-gate * The kstat query could fail if the underlying MAC 15657c478bd9Sstevel@tonic-gate * driver was already detached. 15667c478bd9Sstevel@tonic-gate */ 15677c478bd9Sstevel@tonic-gate goto bail; 15687c478bd9Sstevel@tonic-gate } 15697c478bd9Sstevel@tonic-gate 15707c478bd9Sstevel@tonic-gate if (kstat_read(kcp, ksp, NULL) == -1) { 157133343a97Smeem warn("kstat read failed"); 15727c478bd9Sstevel@tonic-gate goto bail; 15737c478bd9Sstevel@tonic-gate } 15747c478bd9Sstevel@tonic-gate 1575ba2e4443Sseb if (kstat_value(ksp, name, type, val) < 0) 15767c478bd9Sstevel@tonic-gate goto bail; 1577ba2e4443Sseb 1578ba2e4443Sseb (void) kstat_close(kcp); 1579ba2e4443Sseb return (0); 15807c478bd9Sstevel@tonic-gate 15817c478bd9Sstevel@tonic-gate bail: 15827c478bd9Sstevel@tonic-gate (void) kstat_close(kcp); 1583ba2e4443Sseb return (-1); 1584ba2e4443Sseb } 1585ba2e4443Sseb 1586ba2e4443Sseb static uint64_t 1587ba2e4443Sseb mac_ifspeed(const char *dev) 1588ba2e4443Sseb { 1589ba2e4443Sseb uint64_t ifspeed = 0; 1590ba2e4443Sseb 1591ba2e4443Sseb (void) get_single_mac_stat(dev, "ifspeed", KSTAT_DATA_UINT64, &ifspeed); 15927c478bd9Sstevel@tonic-gate return (ifspeed); 15937c478bd9Sstevel@tonic-gate } 15947c478bd9Sstevel@tonic-gate 15957c478bd9Sstevel@tonic-gate static char * 1596ba2e4443Sseb mac_link_state(const char *dev) 15977c478bd9Sstevel@tonic-gate { 15987c478bd9Sstevel@tonic-gate link_state_t link_state; 15997c478bd9Sstevel@tonic-gate char *state_str = "unknown"; 16007c478bd9Sstevel@tonic-gate 1601ba2e4443Sseb if (get_single_mac_stat(dev, "link_state", KSTAT_DATA_UINT32, 1602ba2e4443Sseb &link_state) != 0) { 16037c478bd9Sstevel@tonic-gate return (state_str); 16047c478bd9Sstevel@tonic-gate } 16057c478bd9Sstevel@tonic-gate 16067c478bd9Sstevel@tonic-gate switch (link_state) { 16077c478bd9Sstevel@tonic-gate case LINK_STATE_UP: 16087c478bd9Sstevel@tonic-gate state_str = "up"; 16097c478bd9Sstevel@tonic-gate break; 16107c478bd9Sstevel@tonic-gate case LINK_STATE_DOWN: 16117c478bd9Sstevel@tonic-gate state_str = "down"; 16127c478bd9Sstevel@tonic-gate break; 16137c478bd9Sstevel@tonic-gate default: 16147c478bd9Sstevel@tonic-gate break; 16157c478bd9Sstevel@tonic-gate } 16167c478bd9Sstevel@tonic-gate 16177c478bd9Sstevel@tonic-gate return (state_str); 16187c478bd9Sstevel@tonic-gate } 16197c478bd9Sstevel@tonic-gate 16207c478bd9Sstevel@tonic-gate 16217c478bd9Sstevel@tonic-gate static char * 1622ba2e4443Sseb mac_link_duplex(const char *dev) 16237c478bd9Sstevel@tonic-gate { 16247c478bd9Sstevel@tonic-gate link_duplex_t link_duplex; 16257c478bd9Sstevel@tonic-gate char *duplex_str = "unknown"; 16267c478bd9Sstevel@tonic-gate 1627ba2e4443Sseb if (get_single_mac_stat(dev, "link_duplex", KSTAT_DATA_UINT32, 1628ba2e4443Sseb &link_duplex) != 0) { 16297c478bd9Sstevel@tonic-gate return (duplex_str); 16307c478bd9Sstevel@tonic-gate } 16317c478bd9Sstevel@tonic-gate 16327c478bd9Sstevel@tonic-gate switch (link_duplex) { 16337c478bd9Sstevel@tonic-gate case LINK_DUPLEX_FULL: 16347c478bd9Sstevel@tonic-gate duplex_str = "full"; 16357c478bd9Sstevel@tonic-gate break; 16367c478bd9Sstevel@tonic-gate case LINK_DUPLEX_HALF: 16377c478bd9Sstevel@tonic-gate duplex_str = "half"; 16387c478bd9Sstevel@tonic-gate break; 16397c478bd9Sstevel@tonic-gate default: 16407c478bd9Sstevel@tonic-gate break; 16417c478bd9Sstevel@tonic-gate } 16427c478bd9Sstevel@tonic-gate 16437c478bd9Sstevel@tonic-gate return (duplex_str); 16447c478bd9Sstevel@tonic-gate } 16450ba2cbe9Sxc151355 16460ba2cbe9Sxc151355 #define WIFI_CMD_SCAN 0x00000001 16470ba2cbe9Sxc151355 #define WIFI_CMD_SHOW 0x00000002 16480ba2cbe9Sxc151355 #define WIFI_CMD_ALL (WIFI_CMD_SCAN | WIFI_CMD_SHOW) 16490ba2cbe9Sxc151355 typedef struct wifi_field { 16500ba2cbe9Sxc151355 const char *wf_name; 16510ba2cbe9Sxc151355 const char *wf_header; 16520ba2cbe9Sxc151355 uint_t wf_width; 16530ba2cbe9Sxc151355 uint_t wf_mask; 16540ba2cbe9Sxc151355 uint_t wf_cmdtype; 16550ba2cbe9Sxc151355 } wifi_field_t; 16560ba2cbe9Sxc151355 16570ba2cbe9Sxc151355 static wifi_field_t wifi_fields[] = { 16580ba2cbe9Sxc151355 { "link", "LINK", 10, 0, WIFI_CMD_ALL}, 16590ba2cbe9Sxc151355 { "essid", "ESSID", 19, WLADM_WLAN_ATTR_ESSID, WIFI_CMD_ALL}, 16600ba2cbe9Sxc151355 { "bssid", "BSSID/IBSSID", 17, WLADM_WLAN_ATTR_BSSID, WIFI_CMD_ALL}, 16610ba2cbe9Sxc151355 { "ibssid", "BSSID/IBSSID", 17, WLADM_WLAN_ATTR_BSSID, WIFI_CMD_ALL}, 16620ba2cbe9Sxc151355 { "mode", "MODE", 6, WLADM_WLAN_ATTR_MODE, WIFI_CMD_ALL}, 16630ba2cbe9Sxc151355 { "speed", "SPEED", 6, WLADM_WLAN_ATTR_SPEED, WIFI_CMD_ALL}, 166413994ee8Sxz162242 { "auth", "AUTH", 8, WLADM_WLAN_ATTR_AUTH, WIFI_CMD_SHOW}, 16650ba2cbe9Sxc151355 { "bsstype", "BSSTYPE", 8, WLADM_WLAN_ATTR_BSSTYPE, WIFI_CMD_ALL}, 16660ba2cbe9Sxc151355 { "sec", "SEC", 6, WLADM_WLAN_ATTR_SECMODE, WIFI_CMD_ALL}, 16670ba2cbe9Sxc151355 { "status", "STATUS", 17, WLADM_LINK_ATTR_STATUS, WIFI_CMD_SHOW}, 16680ba2cbe9Sxc151355 { "strength", "STRENGTH", 10, WLADM_WLAN_ATTR_STRENGTH, WIFI_CMD_ALL}} 16690ba2cbe9Sxc151355 ; 16700ba2cbe9Sxc151355 16710ba2cbe9Sxc151355 static char *all_scan_wifi_fields = 167213994ee8Sxz162242 "link,essid,bssid,sec,strength,mode,speed,bsstype"; 16730ba2cbe9Sxc151355 static char *all_show_wifi_fields = 16740ba2cbe9Sxc151355 "link,status,essid,sec,strength,mode,speed,auth,bssid,bsstype"; 16750ba2cbe9Sxc151355 static char *def_scan_wifi_fields = 16760ba2cbe9Sxc151355 "link,essid,bssid,sec,strength,mode,speed"; 16770ba2cbe9Sxc151355 static char *def_show_wifi_fields = 16780ba2cbe9Sxc151355 "link,status,essid,sec,strength,mode,speed"; 16790ba2cbe9Sxc151355 16800ba2cbe9Sxc151355 #define WIFI_MAX_FIELDS (sizeof (wifi_fields) / sizeof (wifi_field_t)) 16810ba2cbe9Sxc151355 #define WIFI_MAX_FIELD_LEN 32 16820ba2cbe9Sxc151355 16830ba2cbe9Sxc151355 typedef struct { 16840ba2cbe9Sxc151355 char *s_buf; 16850ba2cbe9Sxc151355 char **s_fields; /* array of pointer to the fields in s_buf */ 16860ba2cbe9Sxc151355 uint_t s_nfields; /* the number of fields in s_buf */ 16870ba2cbe9Sxc151355 } split_t; 16880ba2cbe9Sxc151355 16890ba2cbe9Sxc151355 /* 16900ba2cbe9Sxc151355 * Free the split_t structure pointed to by `sp'. 16910ba2cbe9Sxc151355 */ 16920ba2cbe9Sxc151355 static void 16930ba2cbe9Sxc151355 splitfree(split_t *sp) 16940ba2cbe9Sxc151355 { 16950ba2cbe9Sxc151355 free(sp->s_buf); 16960ba2cbe9Sxc151355 free(sp->s_fields); 16970ba2cbe9Sxc151355 free(sp); 16980ba2cbe9Sxc151355 } 16990ba2cbe9Sxc151355 17000ba2cbe9Sxc151355 /* 17010ba2cbe9Sxc151355 * Split `str' into at most `maxfields' fields, each field at most `maxlen' in 17020ba2cbe9Sxc151355 * length. Return a pointer to a split_t containing the split fields, or NULL 17030ba2cbe9Sxc151355 * on failure. 17040ba2cbe9Sxc151355 */ 17050ba2cbe9Sxc151355 static split_t * 17060ba2cbe9Sxc151355 split(const char *str, uint_t maxfields, uint_t maxlen) 17070ba2cbe9Sxc151355 { 17080ba2cbe9Sxc151355 char *field, *token, *lasts = NULL; 17090ba2cbe9Sxc151355 split_t *sp; 17100ba2cbe9Sxc151355 17110ba2cbe9Sxc151355 if (*str == '\0' || maxfields == 0 || maxlen == 0) 17120ba2cbe9Sxc151355 return (NULL); 17130ba2cbe9Sxc151355 17140ba2cbe9Sxc151355 sp = calloc(sizeof (split_t), 1); 17150ba2cbe9Sxc151355 if (sp == NULL) 17160ba2cbe9Sxc151355 return (NULL); 17170ba2cbe9Sxc151355 17180ba2cbe9Sxc151355 sp->s_buf = strdup(str); 17190ba2cbe9Sxc151355 sp->s_fields = malloc(sizeof (char *) * maxfields); 17200ba2cbe9Sxc151355 if (sp->s_buf == NULL || sp->s_fields == NULL) 17210ba2cbe9Sxc151355 goto fail; 17220ba2cbe9Sxc151355 17230ba2cbe9Sxc151355 token = sp->s_buf; 17240ba2cbe9Sxc151355 while ((field = strtok_r(token, ",", &lasts)) != NULL) { 17250ba2cbe9Sxc151355 if (sp->s_nfields == maxfields || strlen(field) > maxlen) 17260ba2cbe9Sxc151355 goto fail; 17270ba2cbe9Sxc151355 token = NULL; 17280ba2cbe9Sxc151355 sp->s_fields[sp->s_nfields++] = field; 17290ba2cbe9Sxc151355 } 17300ba2cbe9Sxc151355 return (sp); 17310ba2cbe9Sxc151355 fail: 17320ba2cbe9Sxc151355 splitfree(sp); 17330ba2cbe9Sxc151355 return (NULL); 17340ba2cbe9Sxc151355 } 17350ba2cbe9Sxc151355 17360ba2cbe9Sxc151355 static int 17370ba2cbe9Sxc151355 parse_wifi_fields(char *str, wifi_field_t ***fields, uint_t *countp, 17380ba2cbe9Sxc151355 uint_t cmdtype) 17390ba2cbe9Sxc151355 { 17400ba2cbe9Sxc151355 uint_t i, j; 17410ba2cbe9Sxc151355 wifi_field_t **wf = NULL; 17420ba2cbe9Sxc151355 split_t *sp; 17430ba2cbe9Sxc151355 boolean_t good_match = B_FALSE; 17440ba2cbe9Sxc151355 17450ba2cbe9Sxc151355 if (cmdtype == WIFI_CMD_SCAN) { 17460ba2cbe9Sxc151355 if (str == NULL) 17470ba2cbe9Sxc151355 str = def_scan_wifi_fields; 17480ba2cbe9Sxc151355 if (strcasecmp(str, "all") == 0) 17490ba2cbe9Sxc151355 str = all_scan_wifi_fields; 17500ba2cbe9Sxc151355 } else if (cmdtype == WIFI_CMD_SHOW) { 17510ba2cbe9Sxc151355 if (str == NULL) 17520ba2cbe9Sxc151355 str = def_show_wifi_fields; 17530ba2cbe9Sxc151355 if (strcasecmp(str, "all") == 0) 17540ba2cbe9Sxc151355 str = all_show_wifi_fields; 17550ba2cbe9Sxc151355 } else { 17560ba2cbe9Sxc151355 return (-1); 17570ba2cbe9Sxc151355 } 17580ba2cbe9Sxc151355 17590ba2cbe9Sxc151355 sp = split(str, WIFI_MAX_FIELDS, WIFI_MAX_FIELD_LEN); 17600ba2cbe9Sxc151355 if (sp == NULL) 17610ba2cbe9Sxc151355 return (-1); 17620ba2cbe9Sxc151355 17630ba2cbe9Sxc151355 wf = malloc(sp->s_nfields * sizeof (wifi_field_t *)); 17640ba2cbe9Sxc151355 if (wf == NULL) 17650ba2cbe9Sxc151355 goto fail; 17660ba2cbe9Sxc151355 17670ba2cbe9Sxc151355 for (i = 0; i < sp->s_nfields; i++) { 17680ba2cbe9Sxc151355 for (j = 0; j < WIFI_MAX_FIELDS; j++) { 17690ba2cbe9Sxc151355 if (strcasecmp(sp->s_fields[i], 17700ba2cbe9Sxc151355 wifi_fields[j].wf_name) == 0) { 177113994ee8Sxz162242 good_match = wifi_fields[j]. 17720ba2cbe9Sxc151355 wf_cmdtype & cmdtype; 17730ba2cbe9Sxc151355 break; 17740ba2cbe9Sxc151355 } 17750ba2cbe9Sxc151355 } 17760ba2cbe9Sxc151355 if (!good_match) 17770ba2cbe9Sxc151355 goto fail; 17780ba2cbe9Sxc151355 17790ba2cbe9Sxc151355 good_match = B_FALSE; 17800ba2cbe9Sxc151355 wf[i] = &wifi_fields[j]; 17810ba2cbe9Sxc151355 } 17820ba2cbe9Sxc151355 *countp = i; 17830ba2cbe9Sxc151355 *fields = wf; 17840ba2cbe9Sxc151355 splitfree(sp); 17850ba2cbe9Sxc151355 return (0); 17860ba2cbe9Sxc151355 fail: 17870ba2cbe9Sxc151355 free(wf); 17880ba2cbe9Sxc151355 splitfree(sp); 17890ba2cbe9Sxc151355 return (-1); 17900ba2cbe9Sxc151355 } 17910ba2cbe9Sxc151355 17920ba2cbe9Sxc151355 typedef struct print_wifi_state { 17930ba2cbe9Sxc151355 const char *ws_link; 17940ba2cbe9Sxc151355 boolean_t ws_parseable; 17950ba2cbe9Sxc151355 boolean_t ws_header; 17960ba2cbe9Sxc151355 wifi_field_t **ws_fields; 17970ba2cbe9Sxc151355 uint_t ws_nfields; 17980ba2cbe9Sxc151355 boolean_t ws_lastfield; 17990ba2cbe9Sxc151355 uint_t ws_overflow; 18000ba2cbe9Sxc151355 } print_wifi_state_t; 18010ba2cbe9Sxc151355 18020ba2cbe9Sxc151355 static void 18030ba2cbe9Sxc151355 print_wifi_head(print_wifi_state_t *statep) 18040ba2cbe9Sxc151355 { 18050ba2cbe9Sxc151355 int i; 18060ba2cbe9Sxc151355 wifi_field_t *wfp; 18070ba2cbe9Sxc151355 18080ba2cbe9Sxc151355 for (i = 0; i < statep->ws_nfields; i++) { 18090ba2cbe9Sxc151355 wfp = statep->ws_fields[i]; 18100ba2cbe9Sxc151355 if (i + 1 < statep->ws_nfields) 18110ba2cbe9Sxc151355 (void) printf("%-*s ", wfp->wf_width, wfp->wf_header); 18120ba2cbe9Sxc151355 else 18130ba2cbe9Sxc151355 (void) printf("%s", wfp->wf_header); 18140ba2cbe9Sxc151355 } 18150ba2cbe9Sxc151355 (void) printf("\n"); 18160ba2cbe9Sxc151355 } 18170ba2cbe9Sxc151355 18180ba2cbe9Sxc151355 static void 18190ba2cbe9Sxc151355 print_wifi_field(print_wifi_state_t *statep, wifi_field_t *wfp, 18200ba2cbe9Sxc151355 const char *value) 18210ba2cbe9Sxc151355 { 18220ba2cbe9Sxc151355 uint_t width = wfp->wf_width; 18230ba2cbe9Sxc151355 uint_t valwidth = strlen(value); 18240ba2cbe9Sxc151355 uint_t compress; 18250ba2cbe9Sxc151355 18260ba2cbe9Sxc151355 if (statep->ws_parseable) { 18270ba2cbe9Sxc151355 (void) printf("%s=\"%s\"", wfp->wf_header, value); 18280ba2cbe9Sxc151355 } else { 18290ba2cbe9Sxc151355 if (value[0] == '\0') 18300ba2cbe9Sxc151355 value = "--"; 18310ba2cbe9Sxc151355 if (statep->ws_lastfield) { 18320ba2cbe9Sxc151355 (void) printf("%s", value); 18330ba2cbe9Sxc151355 return; 18340ba2cbe9Sxc151355 } 18350ba2cbe9Sxc151355 18360ba2cbe9Sxc151355 if (valwidth > width) { 18370ba2cbe9Sxc151355 statep->ws_overflow += valwidth - width; 18380ba2cbe9Sxc151355 } else if (valwidth < width && statep->ws_overflow > 0) { 18390ba2cbe9Sxc151355 compress = min(statep->ws_overflow, width - valwidth); 18400ba2cbe9Sxc151355 statep->ws_overflow -= compress; 18410ba2cbe9Sxc151355 width -= compress; 18420ba2cbe9Sxc151355 } 18430ba2cbe9Sxc151355 (void) printf("%-*s", width, value); 18440ba2cbe9Sxc151355 } 18450ba2cbe9Sxc151355 18460ba2cbe9Sxc151355 if (!statep->ws_lastfield) 18470ba2cbe9Sxc151355 (void) putchar(' '); 18480ba2cbe9Sxc151355 } 18490ba2cbe9Sxc151355 18500ba2cbe9Sxc151355 static void 18510ba2cbe9Sxc151355 print_wlan_attr(print_wifi_state_t *statep, wifi_field_t *wfp, 18520ba2cbe9Sxc151355 wladm_wlan_attr_t *attrp) 18530ba2cbe9Sxc151355 { 18540ba2cbe9Sxc151355 char buf[WLADM_STRSIZE]; 18550ba2cbe9Sxc151355 const char *str = ""; 18560ba2cbe9Sxc151355 18570ba2cbe9Sxc151355 if (wfp->wf_mask == 0) { 18580ba2cbe9Sxc151355 print_wifi_field(statep, wfp, statep->ws_link); 18590ba2cbe9Sxc151355 return; 18600ba2cbe9Sxc151355 } 18610ba2cbe9Sxc151355 18620ba2cbe9Sxc151355 if ((wfp->wf_mask & attrp->wa_valid) == 0) { 18630ba2cbe9Sxc151355 print_wifi_field(statep, wfp, ""); 18640ba2cbe9Sxc151355 return; 18650ba2cbe9Sxc151355 } 18660ba2cbe9Sxc151355 18670ba2cbe9Sxc151355 switch (wfp->wf_mask) { 18680ba2cbe9Sxc151355 case WLADM_WLAN_ATTR_ESSID: 18690ba2cbe9Sxc151355 str = wladm_essid2str(&attrp->wa_essid, buf); 18700ba2cbe9Sxc151355 break; 18710ba2cbe9Sxc151355 case WLADM_WLAN_ATTR_BSSID: 18720ba2cbe9Sxc151355 str = wladm_bssid2str(&attrp->wa_bssid, buf); 18730ba2cbe9Sxc151355 break; 18740ba2cbe9Sxc151355 case WLADM_WLAN_ATTR_SECMODE: 18750ba2cbe9Sxc151355 str = wladm_secmode2str(&attrp->wa_secmode, buf); 18760ba2cbe9Sxc151355 break; 18770ba2cbe9Sxc151355 case WLADM_WLAN_ATTR_STRENGTH: 18780ba2cbe9Sxc151355 str = wladm_strength2str(&attrp->wa_strength, buf); 18790ba2cbe9Sxc151355 break; 18800ba2cbe9Sxc151355 case WLADM_WLAN_ATTR_MODE: 18810ba2cbe9Sxc151355 str = wladm_mode2str(&attrp->wa_mode, buf); 18820ba2cbe9Sxc151355 break; 18830ba2cbe9Sxc151355 case WLADM_WLAN_ATTR_SPEED: 18840ba2cbe9Sxc151355 str = wladm_speed2str(&attrp->wa_speed, buf); 18850ba2cbe9Sxc151355 (void) strlcat(buf, "Mb", sizeof (buf)); 18860ba2cbe9Sxc151355 break; 18870ba2cbe9Sxc151355 case WLADM_WLAN_ATTR_AUTH: 18880ba2cbe9Sxc151355 str = wladm_auth2str(&attrp->wa_auth, buf); 18890ba2cbe9Sxc151355 break; 18900ba2cbe9Sxc151355 case WLADM_WLAN_ATTR_BSSTYPE: 18910ba2cbe9Sxc151355 str = wladm_bsstype2str(&attrp->wa_bsstype, buf); 18920ba2cbe9Sxc151355 break; 18930ba2cbe9Sxc151355 } 18940ba2cbe9Sxc151355 18950ba2cbe9Sxc151355 print_wifi_field(statep, wfp, str); 18960ba2cbe9Sxc151355 } 18970ba2cbe9Sxc151355 18980ba2cbe9Sxc151355 static boolean_t 18990ba2cbe9Sxc151355 print_scan_results(void *arg, wladm_wlan_attr_t *attrp) 19000ba2cbe9Sxc151355 { 19010ba2cbe9Sxc151355 print_wifi_state_t *statep = arg; 19020ba2cbe9Sxc151355 int i; 19030ba2cbe9Sxc151355 19040ba2cbe9Sxc151355 if (statep->ws_header) { 19050ba2cbe9Sxc151355 statep->ws_header = B_FALSE; 19060ba2cbe9Sxc151355 if (!statep->ws_parseable) 19070ba2cbe9Sxc151355 print_wifi_head(statep); 19080ba2cbe9Sxc151355 } 19090ba2cbe9Sxc151355 19100ba2cbe9Sxc151355 statep->ws_overflow = 0; 19110ba2cbe9Sxc151355 for (i = 0; i < statep->ws_nfields; i++) { 19120ba2cbe9Sxc151355 statep->ws_lastfield = (i + 1 == statep->ws_nfields); 19130ba2cbe9Sxc151355 print_wlan_attr(statep, statep->ws_fields[i], attrp); 19140ba2cbe9Sxc151355 } 19150ba2cbe9Sxc151355 (void) putchar('\n'); 19160ba2cbe9Sxc151355 return (B_TRUE); 19170ba2cbe9Sxc151355 } 19180ba2cbe9Sxc151355 19190ba2cbe9Sxc151355 static boolean_t 19200ba2cbe9Sxc151355 scan_wifi(void *arg, const char *link) 19210ba2cbe9Sxc151355 { 19220ba2cbe9Sxc151355 print_wifi_state_t *statep = arg; 19230ba2cbe9Sxc151355 wladm_status_t status; 19240ba2cbe9Sxc151355 19250ba2cbe9Sxc151355 statep->ws_link = link; 19260ba2cbe9Sxc151355 status = wladm_scan(link, statep, print_scan_results); 192733343a97Smeem if (status != WLADM_STATUS_OK) 192833343a97Smeem die_wlerr(status, "cannot scan link '%s'", link); 192933343a97Smeem 19300ba2cbe9Sxc151355 return (B_TRUE); 19310ba2cbe9Sxc151355 } 19320ba2cbe9Sxc151355 19330ba2cbe9Sxc151355 static void 19340ba2cbe9Sxc151355 print_link_attr(print_wifi_state_t *statep, wifi_field_t *wfp, 19350ba2cbe9Sxc151355 wladm_link_attr_t *attrp) 19360ba2cbe9Sxc151355 { 19370ba2cbe9Sxc151355 char buf[WLADM_STRSIZE]; 19380ba2cbe9Sxc151355 const char *str = ""; 19390ba2cbe9Sxc151355 19400ba2cbe9Sxc151355 if (strcmp(wfp->wf_name, "status") == 0) { 19410ba2cbe9Sxc151355 if ((wfp->wf_mask & attrp->la_valid) != 0) 19420ba2cbe9Sxc151355 str = wladm_linkstatus2str(&attrp->la_status, buf); 19430ba2cbe9Sxc151355 print_wifi_field(statep, wfp, str); 19440ba2cbe9Sxc151355 return; 19450ba2cbe9Sxc151355 } 19460ba2cbe9Sxc151355 print_wlan_attr(statep, wfp, &attrp->la_wlan_attr); 19470ba2cbe9Sxc151355 } 19480ba2cbe9Sxc151355 19490ba2cbe9Sxc151355 static boolean_t 19500ba2cbe9Sxc151355 show_wifi(void *arg, const char *link) 19510ba2cbe9Sxc151355 { 19520ba2cbe9Sxc151355 int i; 19530ba2cbe9Sxc151355 print_wifi_state_t *statep = arg; 19540ba2cbe9Sxc151355 wladm_link_attr_t attr; 19550ba2cbe9Sxc151355 wladm_status_t status; 19560ba2cbe9Sxc151355 19570ba2cbe9Sxc151355 status = wladm_get_link_attr(link, &attr); 195833343a97Smeem if (status != WLADM_STATUS_OK) 195933343a97Smeem die_wlerr(status, "cannot get link attributes for '%s'", link); 19600ba2cbe9Sxc151355 19610ba2cbe9Sxc151355 if (statep->ws_header) { 19620ba2cbe9Sxc151355 statep->ws_header = B_FALSE; 19630ba2cbe9Sxc151355 if (!statep->ws_parseable) 19640ba2cbe9Sxc151355 print_wifi_head(statep); 19650ba2cbe9Sxc151355 } 19660ba2cbe9Sxc151355 19670ba2cbe9Sxc151355 statep->ws_link = link; 19680ba2cbe9Sxc151355 statep->ws_overflow = 0; 19690ba2cbe9Sxc151355 for (i = 0; i < statep->ws_nfields; i++) { 19700ba2cbe9Sxc151355 statep->ws_lastfield = (i + 1 == statep->ws_nfields); 19710ba2cbe9Sxc151355 print_link_attr(statep, statep->ws_fields[i], &attr); 19720ba2cbe9Sxc151355 } 19730ba2cbe9Sxc151355 (void) putchar('\n'); 19740ba2cbe9Sxc151355 return (B_TRUE); 19750ba2cbe9Sxc151355 } 19760ba2cbe9Sxc151355 19770ba2cbe9Sxc151355 static void 19780ba2cbe9Sxc151355 do_display_wifi(int argc, char **argv, int cmd) 19790ba2cbe9Sxc151355 { 19800ba2cbe9Sxc151355 int option; 19810ba2cbe9Sxc151355 char *fields_str = NULL; 19820ba2cbe9Sxc151355 wifi_field_t **fields; 19830ba2cbe9Sxc151355 boolean_t (*callback)(void *, const char *); 19840ba2cbe9Sxc151355 uint_t nfields; 19850ba2cbe9Sxc151355 print_wifi_state_t state; 19860ba2cbe9Sxc151355 wladm_status_t status; 19870ba2cbe9Sxc151355 19880ba2cbe9Sxc151355 if (cmd == WIFI_CMD_SCAN) 19890ba2cbe9Sxc151355 callback = scan_wifi; 19900ba2cbe9Sxc151355 else if (cmd == WIFI_CMD_SHOW) 19910ba2cbe9Sxc151355 callback = show_wifi; 19920ba2cbe9Sxc151355 else 19930ba2cbe9Sxc151355 return; 19940ba2cbe9Sxc151355 19950ba2cbe9Sxc151355 state.ws_link = NULL; 19960ba2cbe9Sxc151355 state.ws_parseable = B_FALSE; 19970ba2cbe9Sxc151355 state.ws_header = B_TRUE; 19980ba2cbe9Sxc151355 opterr = 0; 19990ba2cbe9Sxc151355 while ((option = getopt_long(argc, argv, ":o:p", 20000ba2cbe9Sxc151355 wifi_longopts, NULL)) != -1) { 20010ba2cbe9Sxc151355 switch (option) { 20020ba2cbe9Sxc151355 case 'o': 20030ba2cbe9Sxc151355 fields_str = optarg; 20040ba2cbe9Sxc151355 break; 20050ba2cbe9Sxc151355 case 'p': 20060ba2cbe9Sxc151355 state.ws_parseable = B_TRUE; 20070ba2cbe9Sxc151355 if (fields_str == NULL) 20080ba2cbe9Sxc151355 fields_str = "all"; 20090ba2cbe9Sxc151355 break; 20100ba2cbe9Sxc151355 default: 201133343a97Smeem die_opterr(optopt, option); 20120ba2cbe9Sxc151355 break; 20130ba2cbe9Sxc151355 } 20140ba2cbe9Sxc151355 } 20150ba2cbe9Sxc151355 20160ba2cbe9Sxc151355 if (optind == (argc - 1)) 20170ba2cbe9Sxc151355 state.ws_link = argv[optind]; 20180ba2cbe9Sxc151355 else if (optind != argc) 20190ba2cbe9Sxc151355 usage(); 20200ba2cbe9Sxc151355 202133343a97Smeem if (parse_wifi_fields(fields_str, &fields, &nfields, cmd) < 0) 202233343a97Smeem die("invalid field(s) specified"); 202333343a97Smeem 20240ba2cbe9Sxc151355 state.ws_fields = fields; 20250ba2cbe9Sxc151355 state.ws_nfields = nfields; 20260ba2cbe9Sxc151355 20270ba2cbe9Sxc151355 if (state.ws_link == NULL) { 20280ba2cbe9Sxc151355 status = wladm_walk(&state, callback); 202933343a97Smeem if (status != WLADM_STATUS_OK) 203033343a97Smeem die_wlerr(status, "cannot walk wifi links"); 20310ba2cbe9Sxc151355 } else { 20320ba2cbe9Sxc151355 (void) (*callback)(&state, state.ws_link); 20330ba2cbe9Sxc151355 } 20340ba2cbe9Sxc151355 free(fields); 20350ba2cbe9Sxc151355 } 20360ba2cbe9Sxc151355 20370ba2cbe9Sxc151355 static void 20380ba2cbe9Sxc151355 do_scan_wifi(int argc, char **argv) 20390ba2cbe9Sxc151355 { 20400ba2cbe9Sxc151355 do_display_wifi(argc, argv, WIFI_CMD_SCAN); 20410ba2cbe9Sxc151355 } 20420ba2cbe9Sxc151355 20430ba2cbe9Sxc151355 static void 20440ba2cbe9Sxc151355 do_show_wifi(int argc, char **argv) 20450ba2cbe9Sxc151355 { 20460ba2cbe9Sxc151355 do_display_wifi(argc, argv, WIFI_CMD_SHOW); 20470ba2cbe9Sxc151355 } 20480ba2cbe9Sxc151355 20490ba2cbe9Sxc151355 typedef struct wlan_count_attr { 20500ba2cbe9Sxc151355 uint_t wc_count; 20510ba2cbe9Sxc151355 const char *wc_link; 20520ba2cbe9Sxc151355 } wlan_count_attr_t; 20530ba2cbe9Sxc151355 20540ba2cbe9Sxc151355 static boolean_t 20550ba2cbe9Sxc151355 do_count_wlan(void *arg, const char *link) 20560ba2cbe9Sxc151355 { 205733343a97Smeem wlan_count_attr_t *cp = arg; 20580ba2cbe9Sxc151355 20590ba2cbe9Sxc151355 if (cp->wc_count == 0) 20600ba2cbe9Sxc151355 cp->wc_link = strdup(link); 20610ba2cbe9Sxc151355 cp->wc_count++; 20620ba2cbe9Sxc151355 return (B_TRUE); 20630ba2cbe9Sxc151355 } 20640ba2cbe9Sxc151355 20650ba2cbe9Sxc151355 static int 20660ba2cbe9Sxc151355 parse_wep_keys(char *str, wladm_wep_key_t **keys, uint_t *key_countp) 20670ba2cbe9Sxc151355 { 20680ba2cbe9Sxc151355 uint_t i; 20690ba2cbe9Sxc151355 split_t *sp; 20700ba2cbe9Sxc151355 wladm_wep_key_t *wk; 20710ba2cbe9Sxc151355 20720ba2cbe9Sxc151355 sp = split(str, WLADM_MAX_WEPKEYS, WLADM_MAX_WEPKEYNAME_LEN); 20730ba2cbe9Sxc151355 if (sp == NULL) 20740ba2cbe9Sxc151355 return (-1); 20750ba2cbe9Sxc151355 20760ba2cbe9Sxc151355 wk = malloc(sp->s_nfields * sizeof (wladm_wep_key_t)); 20770ba2cbe9Sxc151355 if (wk == NULL) 20780ba2cbe9Sxc151355 goto fail; 20790ba2cbe9Sxc151355 20800ba2cbe9Sxc151355 for (i = 0; i < sp->s_nfields; i++) { 20810ba2cbe9Sxc151355 char *s; 20820ba2cbe9Sxc151355 dladm_secobj_class_t class; 20830ba2cbe9Sxc151355 dladm_status_t status; 20840ba2cbe9Sxc151355 20850ba2cbe9Sxc151355 (void) strlcpy(wk[i].wk_name, sp->s_fields[i], 20860ba2cbe9Sxc151355 WLADM_MAX_WEPKEYNAME_LEN); 20870ba2cbe9Sxc151355 20880ba2cbe9Sxc151355 wk[i].wk_idx = 1; 20890ba2cbe9Sxc151355 if ((s = strrchr(wk[i].wk_name, ':')) != NULL) { 20900ba2cbe9Sxc151355 if (s[1] == '\0' || s[2] != '\0' || !isdigit(s[1])) 20910ba2cbe9Sxc151355 goto fail; 20920ba2cbe9Sxc151355 20930ba2cbe9Sxc151355 wk[i].wk_idx = (uint_t)(s[1] - '0'); 20940ba2cbe9Sxc151355 *s = '\0'; 20950ba2cbe9Sxc151355 } 20960ba2cbe9Sxc151355 wk[i].wk_len = WLADM_MAX_WEPKEY_LEN; 20970ba2cbe9Sxc151355 20980ba2cbe9Sxc151355 status = dladm_get_secobj(wk[i].wk_name, &class, 20990ba2cbe9Sxc151355 wk[i].wk_val, &wk[i].wk_len, 0); 21000ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK) { 21010ba2cbe9Sxc151355 if (status == DLADM_STATUS_NOTFOUND) { 21020ba2cbe9Sxc151355 status = dladm_get_secobj(wk[i].wk_name, 21030ba2cbe9Sxc151355 &class, wk[i].wk_val, &wk[i].wk_len, 21040ba2cbe9Sxc151355 DLADM_OPT_PERSIST); 21050ba2cbe9Sxc151355 } 21060ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK) 21070ba2cbe9Sxc151355 goto fail; 21080ba2cbe9Sxc151355 } 21090ba2cbe9Sxc151355 } 21100ba2cbe9Sxc151355 *keys = wk; 21110ba2cbe9Sxc151355 *key_countp = i; 21120ba2cbe9Sxc151355 splitfree(sp); 21130ba2cbe9Sxc151355 return (0); 21140ba2cbe9Sxc151355 fail: 21150ba2cbe9Sxc151355 free(wk); 21160ba2cbe9Sxc151355 splitfree(sp); 21170ba2cbe9Sxc151355 return (-1); 21180ba2cbe9Sxc151355 } 21190ba2cbe9Sxc151355 21200ba2cbe9Sxc151355 static void 21210ba2cbe9Sxc151355 do_connect_wifi(int argc, char **argv) 21220ba2cbe9Sxc151355 { 21230ba2cbe9Sxc151355 int option; 21240ba2cbe9Sxc151355 wladm_wlan_attr_t attr, *attrp; 21250ba2cbe9Sxc151355 wladm_status_t status = WLADM_STATUS_OK; 21260ba2cbe9Sxc151355 int timeout = WLADM_CONNECT_TIMEOUT_DEFAULT; 21270ba2cbe9Sxc151355 const char *link = NULL; 21280ba2cbe9Sxc151355 wladm_wep_key_t *keys = NULL; 21290ba2cbe9Sxc151355 uint_t key_count = 0; 21300ba2cbe9Sxc151355 uint_t flags = 0; 21310ba2cbe9Sxc151355 wladm_secmode_t keysecmode = WLADM_SECMODE_NONE; 21320ba2cbe9Sxc151355 21330ba2cbe9Sxc151355 opterr = 0; 21340ba2cbe9Sxc151355 (void) memset(&attr, 0, sizeof (attr)); 21350ba2cbe9Sxc151355 while ((option = getopt_long(argc, argv, ":e:i:a:m:b:s:k:T:c", 21360ba2cbe9Sxc151355 wifi_longopts, NULL)) != -1) { 21370ba2cbe9Sxc151355 switch (option) { 21380ba2cbe9Sxc151355 case 'e': 21390ba2cbe9Sxc151355 status = wladm_str2essid(optarg, &attr.wa_essid); 214033343a97Smeem if (status != WLADM_STATUS_OK) 214133343a97Smeem die("invalid ESSID '%s'", optarg); 214233343a97Smeem 21430ba2cbe9Sxc151355 attr.wa_valid |= WLADM_WLAN_ATTR_ESSID; 21440ba2cbe9Sxc151355 /* 21450ba2cbe9Sxc151355 * Try to connect without doing a scan. 21460ba2cbe9Sxc151355 */ 21470ba2cbe9Sxc151355 flags |= WLADM_OPT_NOSCAN; 21480ba2cbe9Sxc151355 break; 21490ba2cbe9Sxc151355 case 'i': 21500ba2cbe9Sxc151355 status = wladm_str2bssid(optarg, &attr.wa_bssid); 215133343a97Smeem if (status != WLADM_STATUS_OK) 215233343a97Smeem die("invalid BSSID %s", optarg); 215333343a97Smeem 21540ba2cbe9Sxc151355 attr.wa_valid |= WLADM_WLAN_ATTR_BSSID; 21550ba2cbe9Sxc151355 break; 21560ba2cbe9Sxc151355 case 'a': 21570ba2cbe9Sxc151355 status = wladm_str2auth(optarg, &attr.wa_auth); 215833343a97Smeem if (status != WLADM_STATUS_OK) 215933343a97Smeem die("invalid authentication mode '%s'", optarg); 216033343a97Smeem 21610ba2cbe9Sxc151355 attr.wa_valid |= WLADM_WLAN_ATTR_AUTH; 21620ba2cbe9Sxc151355 break; 21630ba2cbe9Sxc151355 case 'm': 21640ba2cbe9Sxc151355 status = wladm_str2mode(optarg, &attr.wa_mode); 216533343a97Smeem if (status != WLADM_STATUS_OK) 216633343a97Smeem die("invalid mode '%s'", optarg); 216733343a97Smeem 21680ba2cbe9Sxc151355 attr.wa_valid |= WLADM_WLAN_ATTR_MODE; 21690ba2cbe9Sxc151355 break; 21700ba2cbe9Sxc151355 case 'b': 21710ba2cbe9Sxc151355 status = wladm_str2bsstype(optarg, &attr.wa_bsstype); 217233343a97Smeem if (status != WLADM_STATUS_OK) 217333343a97Smeem die("invalid bsstype '%s'", optarg); 217433343a97Smeem 21750ba2cbe9Sxc151355 attr.wa_valid |= WLADM_WLAN_ATTR_BSSTYPE; 21760ba2cbe9Sxc151355 break; 21770ba2cbe9Sxc151355 case 's': 21780ba2cbe9Sxc151355 status = wladm_str2secmode(optarg, &attr.wa_secmode); 217933343a97Smeem if (status != WLADM_STATUS_OK) 218033343a97Smeem die("invalid security mode '%s'", optarg); 218133343a97Smeem 21820ba2cbe9Sxc151355 attr.wa_valid |= WLADM_WLAN_ATTR_SECMODE; 21830ba2cbe9Sxc151355 break; 21840ba2cbe9Sxc151355 case 'k': 218533343a97Smeem if (parse_wep_keys(optarg, &keys, &key_count) < 0) 218633343a97Smeem die("invalid key(s) '%s'", optarg); 218733343a97Smeem 21880ba2cbe9Sxc151355 keysecmode = WLADM_SECMODE_WEP; 21890ba2cbe9Sxc151355 break; 21900ba2cbe9Sxc151355 case 'T': 21910ba2cbe9Sxc151355 if (strcasecmp(optarg, "forever") == 0) { 21920ba2cbe9Sxc151355 timeout = -1; 21930ba2cbe9Sxc151355 break; 21940ba2cbe9Sxc151355 } 219533343a97Smeem if (!str2int(optarg, &timeout) || timeout < 0) 219633343a97Smeem die("invalid timeout value '%s'", optarg); 21970ba2cbe9Sxc151355 break; 21980ba2cbe9Sxc151355 case 'c': 21990ba2cbe9Sxc151355 flags |= WLADM_OPT_CREATEIBSS; 22000ba2cbe9Sxc151355 break; 22010ba2cbe9Sxc151355 default: 220233343a97Smeem die_opterr(optopt, option); 22030ba2cbe9Sxc151355 break; 22040ba2cbe9Sxc151355 } 22050ba2cbe9Sxc151355 } 22060ba2cbe9Sxc151355 22070ba2cbe9Sxc151355 if (keysecmode == WLADM_SECMODE_NONE) { 22080ba2cbe9Sxc151355 if ((attr.wa_valid & WLADM_WLAN_ATTR_SECMODE) != 0 && 220933343a97Smeem attr.wa_secmode == WLADM_SECMODE_WEP) 221033343a97Smeem die("key required for security mode 'wep'"); 22110ba2cbe9Sxc151355 } else { 22120ba2cbe9Sxc151355 if ((attr.wa_valid & WLADM_WLAN_ATTR_SECMODE) != 0 && 221333343a97Smeem attr.wa_secmode != keysecmode) 221433343a97Smeem die("incompatible -s and -k options"); 22150ba2cbe9Sxc151355 } 22160ba2cbe9Sxc151355 attr.wa_secmode = keysecmode; 22170ba2cbe9Sxc151355 attr.wa_valid |= WLADM_WLAN_ATTR_SECMODE; 22180ba2cbe9Sxc151355 22190ba2cbe9Sxc151355 if (optind == (argc - 1)) 22200ba2cbe9Sxc151355 link = argv[optind]; 22210ba2cbe9Sxc151355 else if (optind != argc) 22220ba2cbe9Sxc151355 usage(); 22230ba2cbe9Sxc151355 22240ba2cbe9Sxc151355 if (link == NULL) { 22250ba2cbe9Sxc151355 wlan_count_attr_t wcattr; 22260ba2cbe9Sxc151355 22270ba2cbe9Sxc151355 wcattr.wc_link = NULL; 22280ba2cbe9Sxc151355 wcattr.wc_count = 0; 22290ba2cbe9Sxc151355 (void) wladm_walk(&wcattr, do_count_wlan); 22300ba2cbe9Sxc151355 if (wcattr.wc_count == 0) { 223133343a97Smeem die("no wifi links are available"); 22320ba2cbe9Sxc151355 } else if (wcattr.wc_count > 1) { 223333343a97Smeem die("link name is required when more than one wifi " 223433343a97Smeem "link is available"); 22350ba2cbe9Sxc151355 } 22360ba2cbe9Sxc151355 link = wcattr.wc_link; 22370ba2cbe9Sxc151355 } 22380ba2cbe9Sxc151355 attrp = (attr.wa_valid == 0) ? NULL : &attr; 223933343a97Smeem again: 22400ba2cbe9Sxc151355 status = wladm_connect(link, attrp, timeout, keys, key_count, flags); 22410ba2cbe9Sxc151355 if (status != WLADM_STATUS_OK) { 22420ba2cbe9Sxc151355 if ((flags & WLADM_OPT_NOSCAN) != 0) { 22430ba2cbe9Sxc151355 /* 224433343a97Smeem * Try again with scanning and filtering. 22450ba2cbe9Sxc151355 */ 22460ba2cbe9Sxc151355 flags &= ~WLADM_OPT_NOSCAN; 224733343a97Smeem goto again; 22480ba2cbe9Sxc151355 } 224933343a97Smeem 22500ba2cbe9Sxc151355 if (status == WLADM_STATUS_NOTFOUND) { 22510ba2cbe9Sxc151355 if (attr.wa_valid == 0) { 225233343a97Smeem die("no wifi networks are available"); 22530ba2cbe9Sxc151355 } else { 225433343a97Smeem die("no wifi networks with the specified " 225533343a97Smeem "criteria are available"); 22560ba2cbe9Sxc151355 } 22570ba2cbe9Sxc151355 } 225813994ee8Sxz162242 die_wlerr(status, "cannot connect link '%s'", link); 22590ba2cbe9Sxc151355 } 22600ba2cbe9Sxc151355 free(keys); 22610ba2cbe9Sxc151355 } 22620ba2cbe9Sxc151355 22630ba2cbe9Sxc151355 /* ARGSUSED */ 22640ba2cbe9Sxc151355 static boolean_t 22650ba2cbe9Sxc151355 do_all_disconnect_wifi(void *arg, const char *link) 22660ba2cbe9Sxc151355 { 22670ba2cbe9Sxc151355 wladm_status_t status; 22680ba2cbe9Sxc151355 22690ba2cbe9Sxc151355 status = wladm_disconnect(link); 227033343a97Smeem if (status != WLADM_STATUS_OK) 227133343a97Smeem warn_wlerr(status, "cannot disconnect link '%s'", link); 227233343a97Smeem 22730ba2cbe9Sxc151355 return (B_TRUE); 22740ba2cbe9Sxc151355 } 22750ba2cbe9Sxc151355 22760ba2cbe9Sxc151355 static void 22770ba2cbe9Sxc151355 do_disconnect_wifi(int argc, char **argv) 22780ba2cbe9Sxc151355 { 22790ba2cbe9Sxc151355 int option; 22800ba2cbe9Sxc151355 const char *link = NULL; 22810ba2cbe9Sxc151355 boolean_t all_links = B_FALSE; 22820ba2cbe9Sxc151355 wladm_status_t status; 22830ba2cbe9Sxc151355 wlan_count_attr_t wcattr; 22840ba2cbe9Sxc151355 22850ba2cbe9Sxc151355 opterr = 0; 22860ba2cbe9Sxc151355 while ((option = getopt_long(argc, argv, ":a", 22870ba2cbe9Sxc151355 wifi_longopts, NULL)) != -1) { 22880ba2cbe9Sxc151355 switch (option) { 22890ba2cbe9Sxc151355 case 'a': 22900ba2cbe9Sxc151355 all_links = B_TRUE; 22910ba2cbe9Sxc151355 break; 22920ba2cbe9Sxc151355 default: 229333343a97Smeem die_opterr(optopt, option); 22940ba2cbe9Sxc151355 break; 22950ba2cbe9Sxc151355 } 22960ba2cbe9Sxc151355 } 22970ba2cbe9Sxc151355 22980ba2cbe9Sxc151355 if (optind == (argc - 1)) 22990ba2cbe9Sxc151355 link = argv[optind]; 23000ba2cbe9Sxc151355 else if (optind != argc) 23010ba2cbe9Sxc151355 usage(); 23020ba2cbe9Sxc151355 23030ba2cbe9Sxc151355 if (link == NULL) { 23040ba2cbe9Sxc151355 if (!all_links) { 23050ba2cbe9Sxc151355 wcattr.wc_link = NULL; 23060ba2cbe9Sxc151355 wcattr.wc_count = 0; 23070ba2cbe9Sxc151355 (void) wladm_walk(&wcattr, do_count_wlan); 23080ba2cbe9Sxc151355 if (wcattr.wc_count == 0) { 230933343a97Smeem die("no wifi links are available"); 23100ba2cbe9Sxc151355 } else if (wcattr.wc_count > 1) { 231133343a97Smeem die("link name is required when more than " 231233343a97Smeem "one wifi link is available"); 23130ba2cbe9Sxc151355 } 23140ba2cbe9Sxc151355 link = wcattr.wc_link; 23150ba2cbe9Sxc151355 } else { 23160ba2cbe9Sxc151355 (void) wladm_walk(&all_links, do_all_disconnect_wifi); 23170ba2cbe9Sxc151355 return; 23180ba2cbe9Sxc151355 } 23190ba2cbe9Sxc151355 } 23200ba2cbe9Sxc151355 status = wladm_disconnect(link); 232133343a97Smeem if (status != WLADM_STATUS_OK) 232233343a97Smeem die_wlerr(status, "cannot disconnect link '%s'", link); 23230ba2cbe9Sxc151355 } 23240ba2cbe9Sxc151355 23250ba2cbe9Sxc151355 #define MAX_PROPS 32 23260ba2cbe9Sxc151355 #define MAX_PROP_VALS 32 23270ba2cbe9Sxc151355 #define MAX_PROP_LINE 512 23280ba2cbe9Sxc151355 23290ba2cbe9Sxc151355 typedef struct prop_info { 23300ba2cbe9Sxc151355 char *pi_name; 23310ba2cbe9Sxc151355 char *pi_val[MAX_PROP_VALS]; 23320ba2cbe9Sxc151355 uint_t pi_count; 23330ba2cbe9Sxc151355 } prop_info_t; 23340ba2cbe9Sxc151355 23350ba2cbe9Sxc151355 typedef struct prop_list { 23360ba2cbe9Sxc151355 prop_info_t pl_info[MAX_PROPS]; 23370ba2cbe9Sxc151355 uint_t pl_count; 23380ba2cbe9Sxc151355 char *pl_buf; 23390ba2cbe9Sxc151355 } prop_list_t; 23400ba2cbe9Sxc151355 23410ba2cbe9Sxc151355 typedef struct show_linkprop_state { 23420ba2cbe9Sxc151355 const char *ls_link; 23430ba2cbe9Sxc151355 char *ls_line; 23440ba2cbe9Sxc151355 char **ls_propvals; 2345*f4b3ec61Sdh155122 prop_list_t *ls_proplist; 23460ba2cbe9Sxc151355 boolean_t ls_parseable; 23470ba2cbe9Sxc151355 boolean_t ls_persist; 23480ba2cbe9Sxc151355 boolean_t ls_header; 23490ba2cbe9Sxc151355 } show_linkprop_state_t; 23500ba2cbe9Sxc151355 23510ba2cbe9Sxc151355 static void 23520ba2cbe9Sxc151355 free_props(prop_list_t *list) 23530ba2cbe9Sxc151355 { 23540ba2cbe9Sxc151355 if (list != NULL) { 23550ba2cbe9Sxc151355 free(list->pl_buf); 23560ba2cbe9Sxc151355 free(list); 23570ba2cbe9Sxc151355 } 23580ba2cbe9Sxc151355 } 23590ba2cbe9Sxc151355 23600ba2cbe9Sxc151355 static int 23610ba2cbe9Sxc151355 parse_props(char *str, prop_list_t **listp, boolean_t novalues) 23620ba2cbe9Sxc151355 { 23630ba2cbe9Sxc151355 prop_list_t *list; 23640ba2cbe9Sxc151355 prop_info_t *pip; 23650ba2cbe9Sxc151355 char *buf, *curr; 23660ba2cbe9Sxc151355 int len, i; 23670ba2cbe9Sxc151355 23680ba2cbe9Sxc151355 list = malloc(sizeof (prop_list_t)); 23690ba2cbe9Sxc151355 if (list == NULL) 23700ba2cbe9Sxc151355 return (-1); 23710ba2cbe9Sxc151355 23720ba2cbe9Sxc151355 list->pl_count = 0; 23730ba2cbe9Sxc151355 list->pl_buf = buf = strdup(str); 23740ba2cbe9Sxc151355 if (buf == NULL) 23750ba2cbe9Sxc151355 goto fail; 23760ba2cbe9Sxc151355 23770ba2cbe9Sxc151355 curr = buf; 23780ba2cbe9Sxc151355 len = strlen(buf); 23790ba2cbe9Sxc151355 pip = NULL; 23800ba2cbe9Sxc151355 for (i = 0; i < len; i++) { 23810ba2cbe9Sxc151355 char c = buf[i]; 23820ba2cbe9Sxc151355 boolean_t match = (c == '=' || c == ','); 23830ba2cbe9Sxc151355 23840ba2cbe9Sxc151355 if (!match && i != len - 1) 23850ba2cbe9Sxc151355 continue; 23860ba2cbe9Sxc151355 23870ba2cbe9Sxc151355 if (match) { 23880ba2cbe9Sxc151355 buf[i] = '\0'; 23890ba2cbe9Sxc151355 if (*curr == '\0') 23900ba2cbe9Sxc151355 goto fail; 23910ba2cbe9Sxc151355 } 23920ba2cbe9Sxc151355 23930ba2cbe9Sxc151355 if (pip != NULL && c != '=') { 23940ba2cbe9Sxc151355 if (pip->pi_count > MAX_PROP_VALS) 23950ba2cbe9Sxc151355 goto fail; 23960ba2cbe9Sxc151355 23970ba2cbe9Sxc151355 if (novalues) 23980ba2cbe9Sxc151355 goto fail; 23990ba2cbe9Sxc151355 24000ba2cbe9Sxc151355 pip->pi_val[pip->pi_count] = curr; 24010ba2cbe9Sxc151355 pip->pi_count++; 24020ba2cbe9Sxc151355 } else { 24030ba2cbe9Sxc151355 if (list->pl_count > MAX_PROPS) 24040ba2cbe9Sxc151355 goto fail; 24050ba2cbe9Sxc151355 24060ba2cbe9Sxc151355 pip = &list->pl_info[list->pl_count]; 24070ba2cbe9Sxc151355 pip->pi_name = curr; 24080ba2cbe9Sxc151355 pip->pi_count = 0; 24090ba2cbe9Sxc151355 list->pl_count++; 24100ba2cbe9Sxc151355 if (c == ',') 24110ba2cbe9Sxc151355 pip = NULL; 24120ba2cbe9Sxc151355 } 24130ba2cbe9Sxc151355 curr = buf + i + 1; 24140ba2cbe9Sxc151355 } 24150ba2cbe9Sxc151355 *listp = list; 24160ba2cbe9Sxc151355 return (0); 24170ba2cbe9Sxc151355 24180ba2cbe9Sxc151355 fail: 24190ba2cbe9Sxc151355 free_props(list); 24200ba2cbe9Sxc151355 return (-1); 24210ba2cbe9Sxc151355 } 24220ba2cbe9Sxc151355 24230ba2cbe9Sxc151355 static void 24240ba2cbe9Sxc151355 print_linkprop_head(void) 24250ba2cbe9Sxc151355 { 2426*f4b3ec61Sdh155122 (void) printf("%-12s %-15s %-14s %-14s %-20s \n", 2427*f4b3ec61Sdh155122 "LINK", "PROPERTY", "VALUE", "DEFAULT", "POSSIBLE"); 24280ba2cbe9Sxc151355 } 24290ba2cbe9Sxc151355 24300ba2cbe9Sxc151355 static void 24310ba2cbe9Sxc151355 print_linkprop(show_linkprop_state_t *statep, const char *propname, 24320ba2cbe9Sxc151355 dladm_prop_type_t type, const char *typename, const char *format, 24330ba2cbe9Sxc151355 char **pptr) 24340ba2cbe9Sxc151355 { 24350ba2cbe9Sxc151355 int i; 24360ba2cbe9Sxc151355 char *ptr, *lim; 24370ba2cbe9Sxc151355 char buf[DLADM_STRSIZE]; 24380ba2cbe9Sxc151355 char *unknown = "?", *notsup = ""; 24390ba2cbe9Sxc151355 char **propvals = statep->ls_propvals; 24400ba2cbe9Sxc151355 uint_t valcnt = MAX_PROP_VALS; 24410ba2cbe9Sxc151355 dladm_status_t status; 24420ba2cbe9Sxc151355 24430ba2cbe9Sxc151355 status = dladm_get_prop(statep->ls_link, type, propname, 24440ba2cbe9Sxc151355 propvals, &valcnt); 24450ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK) { 24460ba2cbe9Sxc151355 if (status == DLADM_STATUS_NOTSUP || statep->ls_persist) { 24470ba2cbe9Sxc151355 valcnt = 1; 24480ba2cbe9Sxc151355 if (type == DLADM_PROP_VAL_CURRENT) 24490ba2cbe9Sxc151355 propvals = &unknown; 24500ba2cbe9Sxc151355 else 24510ba2cbe9Sxc151355 propvals = ¬sup; 24520ba2cbe9Sxc151355 } else { 245333343a97Smeem die_dlerr(status, "cannot get link property '%s'", 245433343a97Smeem propname); 24550ba2cbe9Sxc151355 } 24560ba2cbe9Sxc151355 } 24570ba2cbe9Sxc151355 24580ba2cbe9Sxc151355 ptr = buf; 24590ba2cbe9Sxc151355 lim = buf + DLADM_STRSIZE; 24600ba2cbe9Sxc151355 for (i = 0; i < valcnt; i++) { 24610ba2cbe9Sxc151355 if (propvals[i][0] == '\0' && !statep->ls_parseable) 24620ba2cbe9Sxc151355 ptr += snprintf(ptr, lim - ptr, "--,"); 24630ba2cbe9Sxc151355 else 24640ba2cbe9Sxc151355 ptr += snprintf(ptr, lim - ptr, "%s,", propvals[i]); 24650ba2cbe9Sxc151355 if (ptr >= lim) 24660ba2cbe9Sxc151355 break; 24670ba2cbe9Sxc151355 } 24680ba2cbe9Sxc151355 if (valcnt > 0) 24690ba2cbe9Sxc151355 buf[strlen(buf) - 1] = '\0'; 24700ba2cbe9Sxc151355 24710ba2cbe9Sxc151355 lim = statep->ls_line + MAX_PROP_LINE; 24720ba2cbe9Sxc151355 if (statep->ls_parseable) { 24730ba2cbe9Sxc151355 *pptr += snprintf(*pptr, lim - *pptr, 24740ba2cbe9Sxc151355 "%s=\"%s\" ", typename, buf); 24750ba2cbe9Sxc151355 } else { 24760ba2cbe9Sxc151355 *pptr += snprintf(*pptr, lim - *pptr, format, buf); 24770ba2cbe9Sxc151355 } 24780ba2cbe9Sxc151355 } 24790ba2cbe9Sxc151355 24800ba2cbe9Sxc151355 static boolean_t 24810ba2cbe9Sxc151355 show_linkprop(void *arg, const char *propname) 24820ba2cbe9Sxc151355 { 24830ba2cbe9Sxc151355 show_linkprop_state_t *statep = arg; 24840ba2cbe9Sxc151355 char *ptr = statep->ls_line; 24850ba2cbe9Sxc151355 char *lim = ptr + MAX_PROP_LINE; 24860ba2cbe9Sxc151355 2487*f4b3ec61Sdh155122 if (statep->ls_persist && dladm_is_prop_temponly(propname, NULL)) 2488*f4b3ec61Sdh155122 return (B_TRUE); 2489*f4b3ec61Sdh155122 2490*f4b3ec61Sdh155122 if (statep->ls_parseable) 2491*f4b3ec61Sdh155122 ptr += snprintf(ptr, lim - ptr, "LINK=\"%s\" ", 2492*f4b3ec61Sdh155122 statep->ls_link); 2493*f4b3ec61Sdh155122 else 2494*f4b3ec61Sdh155122 ptr += snprintf(ptr, lim - ptr, "%-12s ", statep->ls_link); 2495*f4b3ec61Sdh155122 24960ba2cbe9Sxc151355 if (statep->ls_parseable) 24970ba2cbe9Sxc151355 ptr += snprintf(ptr, lim - ptr, "PROPERTY=\"%s\" ", propname); 24980ba2cbe9Sxc151355 else 24990ba2cbe9Sxc151355 ptr += snprintf(ptr, lim - ptr, "%-15s ", propname); 25000ba2cbe9Sxc151355 25010ba2cbe9Sxc151355 print_linkprop(statep, propname, 25020ba2cbe9Sxc151355 statep->ls_persist ? DLADM_PROP_VAL_PERSISTENT : 25030ba2cbe9Sxc151355 DLADM_PROP_VAL_CURRENT, "VALUE", "%-14s ", &ptr); 25040ba2cbe9Sxc151355 print_linkprop(statep, propname, DLADM_PROP_VAL_DEFAULT, 25050ba2cbe9Sxc151355 "DEFAULT", "%-14s ", &ptr); 25060ba2cbe9Sxc151355 print_linkprop(statep, propname, DLADM_PROP_VAL_MODIFIABLE, 2507*f4b3ec61Sdh155122 "POSSIBLE", "%-20s ", &ptr); 25080ba2cbe9Sxc151355 25090ba2cbe9Sxc151355 if (statep->ls_header) { 25100ba2cbe9Sxc151355 statep->ls_header = B_FALSE; 25110ba2cbe9Sxc151355 if (!statep->ls_parseable) 25120ba2cbe9Sxc151355 print_linkprop_head(); 25130ba2cbe9Sxc151355 } 25140ba2cbe9Sxc151355 (void) printf("%s\n", statep->ls_line); 25150ba2cbe9Sxc151355 return (B_TRUE); 25160ba2cbe9Sxc151355 } 25170ba2cbe9Sxc151355 25180ba2cbe9Sxc151355 static void 25190ba2cbe9Sxc151355 do_show_linkprop(int argc, char **argv) 25200ba2cbe9Sxc151355 { 2521*f4b3ec61Sdh155122 int option; 25220ba2cbe9Sxc151355 prop_list_t *proplist = NULL; 25230ba2cbe9Sxc151355 show_linkprop_state_t state; 25240ba2cbe9Sxc151355 25250ba2cbe9Sxc151355 opterr = 0; 25260ba2cbe9Sxc151355 state.ls_link = NULL; 25270ba2cbe9Sxc151355 state.ls_propvals = NULL; 25280ba2cbe9Sxc151355 state.ls_line = NULL; 25290ba2cbe9Sxc151355 state.ls_parseable = B_FALSE; 25300ba2cbe9Sxc151355 state.ls_persist = B_FALSE; 25310ba2cbe9Sxc151355 state.ls_header = B_TRUE; 25320ba2cbe9Sxc151355 while ((option = getopt_long(argc, argv, ":p:cP", 25330ba2cbe9Sxc151355 prop_longopts, NULL)) != -1) { 25340ba2cbe9Sxc151355 switch (option) { 25350ba2cbe9Sxc151355 case 'p': 253633343a97Smeem if (parse_props(optarg, &proplist, B_TRUE) < 0) 253713994ee8Sxz162242 die("invalid link properties specified"); 25380ba2cbe9Sxc151355 break; 25390ba2cbe9Sxc151355 case 'c': 25400ba2cbe9Sxc151355 state.ls_parseable = B_TRUE; 25410ba2cbe9Sxc151355 break; 25420ba2cbe9Sxc151355 case 'P': 25430ba2cbe9Sxc151355 state.ls_persist = B_TRUE; 25440ba2cbe9Sxc151355 break; 25450ba2cbe9Sxc151355 default: 254633343a97Smeem die_opterr(optopt, option); 25470ba2cbe9Sxc151355 break; 25480ba2cbe9Sxc151355 } 25490ba2cbe9Sxc151355 } 25500ba2cbe9Sxc151355 25510ba2cbe9Sxc151355 if (optind == (argc - 1)) 25520ba2cbe9Sxc151355 state.ls_link = argv[optind]; 25530ba2cbe9Sxc151355 else if (optind != argc) 25540ba2cbe9Sxc151355 usage(); 25550ba2cbe9Sxc151355 2556*f4b3ec61Sdh155122 state.ls_proplist = proplist; 2557*f4b3ec61Sdh155122 2558*f4b3ec61Sdh155122 if (state.ls_link == NULL) { 2559*f4b3ec61Sdh155122 (void) dladm_walk(show_linkprop_onelink, &state); 2560*f4b3ec61Sdh155122 } else { 2561*f4b3ec61Sdh155122 show_linkprop_onelink(&state, state.ls_link); 2562*f4b3ec61Sdh155122 } 2563*f4b3ec61Sdh155122 free_props(proplist); 2564*f4b3ec61Sdh155122 } 2565*f4b3ec61Sdh155122 2566*f4b3ec61Sdh155122 static void 2567*f4b3ec61Sdh155122 show_linkprop_onelink(void *arg, const char *link) 2568*f4b3ec61Sdh155122 { 2569*f4b3ec61Sdh155122 int i, fd; 2570*f4b3ec61Sdh155122 char linkname[MAXPATHLEN]; 2571*f4b3ec61Sdh155122 char *buf; 2572*f4b3ec61Sdh155122 dladm_status_t status; 2573*f4b3ec61Sdh155122 prop_list_t *proplist = NULL; 2574*f4b3ec61Sdh155122 show_linkprop_state_t *statep; 2575*f4b3ec61Sdh155122 const char *savep; 2576*f4b3ec61Sdh155122 2577*f4b3ec61Sdh155122 statep = (show_linkprop_state_t *)arg; 2578*f4b3ec61Sdh155122 savep = statep->ls_link; 2579*f4b3ec61Sdh155122 statep->ls_link = link; 2580*f4b3ec61Sdh155122 proplist = statep->ls_proplist; 25810ba2cbe9Sxc151355 25820ba2cbe9Sxc151355 /* 25830ba2cbe9Sxc151355 * When some WiFi links are opened for the first time, their hardware 25840ba2cbe9Sxc151355 * automatically scans for APs and does other slow operations. Thus, 25850ba2cbe9Sxc151355 * if there are no open links, the retrieval of link properties 25860ba2cbe9Sxc151355 * (below) will proceed slowly unless we hold the link open. 25870ba2cbe9Sxc151355 */ 2588*f4b3ec61Sdh155122 (void) snprintf(linkname, MAXPATHLEN, "/dev/%s", link); 258933343a97Smeem if ((fd = open(linkname, O_RDWR)) < 0) 2590*f4b3ec61Sdh155122 die("cannot open %s: %s", link, strerror(errno)); 25910ba2cbe9Sxc151355 25920ba2cbe9Sxc151355 buf = malloc((sizeof (char *) + DLADM_PROP_VAL_MAX) * MAX_PROP_VALS + 25930ba2cbe9Sxc151355 MAX_PROP_LINE); 259433343a97Smeem if (buf == NULL) 259533343a97Smeem die("insufficient memory"); 259633343a97Smeem 2597*f4b3ec61Sdh155122 statep->ls_propvals = (char **)(void *)buf; 25980ba2cbe9Sxc151355 for (i = 0; i < MAX_PROP_VALS; i++) { 2599*f4b3ec61Sdh155122 statep->ls_propvals[i] = buf + sizeof (char *) * MAX_PROP_VALS + 26000ba2cbe9Sxc151355 i * DLADM_PROP_VAL_MAX; 26010ba2cbe9Sxc151355 } 2602*f4b3ec61Sdh155122 statep->ls_line = buf + 26030ba2cbe9Sxc151355 (sizeof (char *) + DLADM_PROP_VAL_MAX) * MAX_PROP_VALS; 26040ba2cbe9Sxc151355 26050ba2cbe9Sxc151355 if (proplist != NULL) { 26060ba2cbe9Sxc151355 for (i = 0; i < proplist->pl_count; i++) { 2607*f4b3ec61Sdh155122 if (!show_linkprop(statep, 26080ba2cbe9Sxc151355 proplist->pl_info[i].pi_name)) 26090ba2cbe9Sxc151355 break; 26100ba2cbe9Sxc151355 } 26110ba2cbe9Sxc151355 } else { 2612*f4b3ec61Sdh155122 status = dladm_walk_prop(link, statep, show_linkprop); 261333343a97Smeem if (status != DLADM_STATUS_OK) 261433343a97Smeem die_dlerr(status, "show-linkprop"); 26150ba2cbe9Sxc151355 } 26160ba2cbe9Sxc151355 (void) close(fd); 26170ba2cbe9Sxc151355 free(buf); 2618*f4b3ec61Sdh155122 statep->ls_link = savep; 26190ba2cbe9Sxc151355 } 26200ba2cbe9Sxc151355 26210ba2cbe9Sxc151355 static dladm_status_t 26220ba2cbe9Sxc151355 set_linkprop_persist(const char *link, const char *prop_name, char **prop_val, 26230ba2cbe9Sxc151355 uint_t val_cnt, boolean_t reset) 26240ba2cbe9Sxc151355 { 26250ba2cbe9Sxc151355 dladm_status_t status; 2626*f4b3ec61Sdh155122 char *errprop; 26270ba2cbe9Sxc151355 26280ba2cbe9Sxc151355 status = dladm_set_prop(link, prop_name, prop_val, val_cnt, 2629*f4b3ec61Sdh155122 DLADM_OPT_PERSIST, &errprop); 26300ba2cbe9Sxc151355 26310ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK) { 26320ba2cbe9Sxc151355 if (reset) { 263333343a97Smeem warn_dlerr(status, "cannot persistently reset link " 2634*f4b3ec61Sdh155122 "property '%s' on '%s'", errprop, link); 26350ba2cbe9Sxc151355 } else { 263633343a97Smeem warn_dlerr(status, "cannot persistently set link " 2637*f4b3ec61Sdh155122 "property '%s' on '%s'", errprop, link); 26380ba2cbe9Sxc151355 } 26390ba2cbe9Sxc151355 } 26400ba2cbe9Sxc151355 return (status); 26410ba2cbe9Sxc151355 } 26420ba2cbe9Sxc151355 26430ba2cbe9Sxc151355 static void 26440ba2cbe9Sxc151355 set_linkprop(int argc, char **argv, boolean_t reset) 26450ba2cbe9Sxc151355 { 26460ba2cbe9Sxc151355 int i, option; 26470ba2cbe9Sxc151355 char errmsg[DLADM_STRSIZE]; 26480ba2cbe9Sxc151355 const char *link = NULL; 26490ba2cbe9Sxc151355 prop_list_t *proplist = NULL; 26500ba2cbe9Sxc151355 boolean_t temp = B_FALSE; 26510ba2cbe9Sxc151355 dladm_status_t status = DLADM_STATUS_OK; 26520ba2cbe9Sxc151355 26530ba2cbe9Sxc151355 opterr = 0; 26540ba2cbe9Sxc151355 while ((option = getopt_long(argc, argv, ":p:R:t", 26550ba2cbe9Sxc151355 prop_longopts, NULL)) != -1) { 26560ba2cbe9Sxc151355 switch (option) { 26570ba2cbe9Sxc151355 case 'p': 265833343a97Smeem if (parse_props(optarg, &proplist, reset) < 0) 265933343a97Smeem die("invalid link properties specified"); 26600ba2cbe9Sxc151355 break; 26610ba2cbe9Sxc151355 case 't': 26620ba2cbe9Sxc151355 temp = B_TRUE; 26630ba2cbe9Sxc151355 break; 26640ba2cbe9Sxc151355 case 'R': 26650ba2cbe9Sxc151355 status = dladm_set_rootdir(optarg); 26660ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK) { 266733343a97Smeem die_dlerr(status, "invalid directory " 266833343a97Smeem "specified"); 26690ba2cbe9Sxc151355 } 26700ba2cbe9Sxc151355 break; 26710ba2cbe9Sxc151355 default: 267233343a97Smeem die_opterr(optopt, option); 26730ba2cbe9Sxc151355 break; 26740ba2cbe9Sxc151355 } 26750ba2cbe9Sxc151355 } 26760ba2cbe9Sxc151355 26770ba2cbe9Sxc151355 if (optind == (argc - 1)) 26780ba2cbe9Sxc151355 link = argv[optind]; 26790ba2cbe9Sxc151355 else if (optind != argc) 26800ba2cbe9Sxc151355 usage(); 26810ba2cbe9Sxc151355 268233343a97Smeem if (link == NULL) 268333343a97Smeem die("link name must be specified"); 26840ba2cbe9Sxc151355 2685dbc95d79Sxz162242 if (proplist == NULL) { 2686*f4b3ec61Sdh155122 char *errprop; 2687*f4b3ec61Sdh155122 2688dbc95d79Sxz162242 if (!reset) 268933343a97Smeem die("link property must be specified"); 269033343a97Smeem 2691*f4b3ec61Sdh155122 status = dladm_set_prop(link, NULL, NULL, 0, DLADM_OPT_TEMP, 2692*f4b3ec61Sdh155122 &errprop); 26930ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK) { 2694*f4b3ec61Sdh155122 warn_dlerr(status, "cannot reset link property '%s' " 2695*f4b3ec61Sdh155122 "on '%s'", errprop, link); 26960ba2cbe9Sxc151355 } 26970ba2cbe9Sxc151355 if (!temp) { 269813994ee8Sxz162242 dladm_status_t s; 269913994ee8Sxz162242 270013994ee8Sxz162242 s = set_linkprop_persist(link, NULL, NULL, 0, reset); 270113994ee8Sxz162242 if (s != DLADM_STATUS_OK) 270213994ee8Sxz162242 status = s; 27030ba2cbe9Sxc151355 } 27040ba2cbe9Sxc151355 goto done; 27050ba2cbe9Sxc151355 } 27060ba2cbe9Sxc151355 27070ba2cbe9Sxc151355 for (i = 0; i < proplist->pl_count; i++) { 27080ba2cbe9Sxc151355 prop_info_t *pip = &proplist->pl_info[i]; 27090ba2cbe9Sxc151355 char **val; 27100ba2cbe9Sxc151355 uint_t count; 27110ba2cbe9Sxc151355 dladm_status_t s; 27120ba2cbe9Sxc151355 27130ba2cbe9Sxc151355 if (reset) { 27140ba2cbe9Sxc151355 val = NULL; 27150ba2cbe9Sxc151355 count = 0; 27160ba2cbe9Sxc151355 } else { 27170ba2cbe9Sxc151355 val = pip->pi_val; 27180ba2cbe9Sxc151355 count = pip->pi_count; 27190ba2cbe9Sxc151355 if (count == 0) { 272033343a97Smeem warn("no value specified for '%s'", 272133343a97Smeem pip->pi_name); 27220ba2cbe9Sxc151355 status = DLADM_STATUS_BADARG; 27230ba2cbe9Sxc151355 continue; 27240ba2cbe9Sxc151355 } 27250ba2cbe9Sxc151355 } 27260ba2cbe9Sxc151355 s = dladm_set_prop(link, pip->pi_name, val, count, 2727*f4b3ec61Sdh155122 DLADM_OPT_TEMP, NULL); 27280ba2cbe9Sxc151355 if (s == DLADM_STATUS_OK) { 27290ba2cbe9Sxc151355 if (!temp) { 27300ba2cbe9Sxc151355 s = set_linkprop_persist(link, 27310ba2cbe9Sxc151355 pip->pi_name, val, count, reset); 27320ba2cbe9Sxc151355 if (s != DLADM_STATUS_OK) 27330ba2cbe9Sxc151355 status = s; 27340ba2cbe9Sxc151355 } 27350ba2cbe9Sxc151355 continue; 27360ba2cbe9Sxc151355 } 27370ba2cbe9Sxc151355 status = s; 27380ba2cbe9Sxc151355 switch (s) { 27390ba2cbe9Sxc151355 case DLADM_STATUS_NOTFOUND: 274033343a97Smeem warn("invalid link property '%s'", pip->pi_name); 27410ba2cbe9Sxc151355 break; 27420ba2cbe9Sxc151355 case DLADM_STATUS_BADVAL: { 27430ba2cbe9Sxc151355 int j; 27440ba2cbe9Sxc151355 char *ptr, *lim; 27450ba2cbe9Sxc151355 char **propvals = NULL; 27460ba2cbe9Sxc151355 uint_t valcnt = MAX_PROP_VALS; 27470ba2cbe9Sxc151355 27480ba2cbe9Sxc151355 ptr = malloc((sizeof (char *) + 27490ba2cbe9Sxc151355 DLADM_PROP_VAL_MAX) * MAX_PROP_VALS + 27500ba2cbe9Sxc151355 MAX_PROP_LINE); 27510ba2cbe9Sxc151355 27520ba2cbe9Sxc151355 propvals = (char **)(void *)ptr; 275333343a97Smeem if (propvals == NULL) 275433343a97Smeem die("insufficient memory"); 275533343a97Smeem 27560ba2cbe9Sxc151355 for (j = 0; j < MAX_PROP_VALS; j++) { 27570ba2cbe9Sxc151355 propvals[j] = ptr + sizeof (char *) * 27580ba2cbe9Sxc151355 MAX_PROP_VALS + 27590ba2cbe9Sxc151355 j * DLADM_PROP_VAL_MAX; 27600ba2cbe9Sxc151355 } 27610ba2cbe9Sxc151355 s = dladm_get_prop(link, DLADM_PROP_VAL_MODIFIABLE, 27620ba2cbe9Sxc151355 pip->pi_name, propvals, &valcnt); 27630ba2cbe9Sxc151355 27640ba2cbe9Sxc151355 ptr = errmsg; 27650ba2cbe9Sxc151355 lim = ptr + DLADM_STRSIZE; 27660ba2cbe9Sxc151355 *ptr = '\0'; 27670ba2cbe9Sxc151355 for (j = 0; j < valcnt && s == DLADM_STATUS_OK; j++) { 27680ba2cbe9Sxc151355 ptr += snprintf(ptr, lim - ptr, "%s,", 27690ba2cbe9Sxc151355 propvals[j]); 27700ba2cbe9Sxc151355 if (ptr >= lim) 27710ba2cbe9Sxc151355 break; 27720ba2cbe9Sxc151355 } 2773*f4b3ec61Sdh155122 if (ptr > errmsg) { 27740ba2cbe9Sxc151355 *(ptr - 1) = '\0'; 277533343a97Smeem warn("link property '%s' must be one of: %s", 277633343a97Smeem pip->pi_name, errmsg); 2777*f4b3ec61Sdh155122 } else 2778*f4b3ec61Sdh155122 warn("invalid link property '%s'", *val); 27790ba2cbe9Sxc151355 free(propvals); 27800ba2cbe9Sxc151355 break; 27810ba2cbe9Sxc151355 } 27820ba2cbe9Sxc151355 default: 27830ba2cbe9Sxc151355 if (reset) { 278433343a97Smeem warn_dlerr(status, "cannot reset link property " 278533343a97Smeem "'%s' on '%s'", pip->pi_name, link); 27860ba2cbe9Sxc151355 } else { 278733343a97Smeem warn_dlerr(status, "cannot set link property " 278833343a97Smeem "'%s' on '%s'", pip->pi_name, link); 27890ba2cbe9Sxc151355 } 27900ba2cbe9Sxc151355 break; 27910ba2cbe9Sxc151355 } 27920ba2cbe9Sxc151355 } 27930ba2cbe9Sxc151355 done: 27940ba2cbe9Sxc151355 free_props(proplist); 27950ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK) 27960ba2cbe9Sxc151355 exit(1); 27970ba2cbe9Sxc151355 } 27980ba2cbe9Sxc151355 27990ba2cbe9Sxc151355 static void 28000ba2cbe9Sxc151355 do_set_linkprop(int argc, char **argv) 28010ba2cbe9Sxc151355 { 28020ba2cbe9Sxc151355 set_linkprop(argc, argv, B_FALSE); 28030ba2cbe9Sxc151355 } 28040ba2cbe9Sxc151355 28050ba2cbe9Sxc151355 static void 28060ba2cbe9Sxc151355 do_reset_linkprop(int argc, char **argv) 28070ba2cbe9Sxc151355 { 28080ba2cbe9Sxc151355 set_linkprop(argc, argv, B_TRUE); 28090ba2cbe9Sxc151355 } 28100ba2cbe9Sxc151355 28110ba2cbe9Sxc151355 static int 28120ba2cbe9Sxc151355 convert_secobj(char *buf, uint_t len, uint8_t *obj_val, uint_t *obj_lenp, 28130ba2cbe9Sxc151355 dladm_secobj_class_t class) 28140ba2cbe9Sxc151355 { 28150ba2cbe9Sxc151355 int error = 0; 28160ba2cbe9Sxc151355 28170ba2cbe9Sxc151355 if (class != DLADM_SECOBJ_CLASS_WEP) 28180ba2cbe9Sxc151355 return (ENOENT); 28190ba2cbe9Sxc151355 28200ba2cbe9Sxc151355 switch (len) { 28210ba2cbe9Sxc151355 case 5: /* ASCII key sizes */ 28220ba2cbe9Sxc151355 case 13: 28230ba2cbe9Sxc151355 (void) memcpy(obj_val, buf, len); 28240ba2cbe9Sxc151355 *obj_lenp = len; 28250ba2cbe9Sxc151355 break; 28260ba2cbe9Sxc151355 case 10: /* Hex key sizes, not preceded by 0x */ 28270ba2cbe9Sxc151355 case 26: 28280ba2cbe9Sxc151355 error = hexascii_to_octet(buf, len, obj_val, obj_lenp); 28290ba2cbe9Sxc151355 break; 28300ba2cbe9Sxc151355 case 12: /* Hex key sizes, preceded by 0x */ 28310ba2cbe9Sxc151355 case 28: 28320ba2cbe9Sxc151355 if (strncmp(buf, "0x", 2) != 0) 28330ba2cbe9Sxc151355 return (EINVAL); 28340ba2cbe9Sxc151355 error = hexascii_to_octet(buf + 2, len - 2, obj_val, obj_lenp); 28350ba2cbe9Sxc151355 break; 28360ba2cbe9Sxc151355 default: 28370ba2cbe9Sxc151355 return (EINVAL); 28380ba2cbe9Sxc151355 } 28390ba2cbe9Sxc151355 return (error); 28400ba2cbe9Sxc151355 } 28410ba2cbe9Sxc151355 28420ba2cbe9Sxc151355 /* ARGSUSED */ 28430ba2cbe9Sxc151355 static void 28440ba2cbe9Sxc151355 defersig(int sig) 28450ba2cbe9Sxc151355 { 28460ba2cbe9Sxc151355 signalled = sig; 28470ba2cbe9Sxc151355 } 28480ba2cbe9Sxc151355 28490ba2cbe9Sxc151355 static int 28500ba2cbe9Sxc151355 get_secobj_from_tty(uint_t try, const char *objname, char *buf) 28510ba2cbe9Sxc151355 { 28520ba2cbe9Sxc151355 uint_t len = 0; 28530ba2cbe9Sxc151355 int c; 28540ba2cbe9Sxc151355 struct termios stored, current; 28550ba2cbe9Sxc151355 void (*sigfunc)(int); 28560ba2cbe9Sxc151355 28570ba2cbe9Sxc151355 /* 28580ba2cbe9Sxc151355 * Turn off echo -- but before we do so, defer SIGINT handling 28590ba2cbe9Sxc151355 * so that a ^C doesn't leave the terminal corrupted. 28600ba2cbe9Sxc151355 */ 28610ba2cbe9Sxc151355 sigfunc = signal(SIGINT, defersig); 28620ba2cbe9Sxc151355 (void) fflush(stdin); 28630ba2cbe9Sxc151355 (void) tcgetattr(0, &stored); 28640ba2cbe9Sxc151355 current = stored; 28650ba2cbe9Sxc151355 current.c_lflag &= ~(ICANON|ECHO); 28660ba2cbe9Sxc151355 current.c_cc[VTIME] = 0; 28670ba2cbe9Sxc151355 current.c_cc[VMIN] = 1; 28680ba2cbe9Sxc151355 (void) tcsetattr(0, TCSANOW, ¤t); 28690ba2cbe9Sxc151355 again: 28700ba2cbe9Sxc151355 if (try == 1) 28710ba2cbe9Sxc151355 (void) printf(gettext("provide value for '%s': "), objname); 28720ba2cbe9Sxc151355 else 28730ba2cbe9Sxc151355 (void) printf(gettext("confirm value for '%s': "), objname); 28740ba2cbe9Sxc151355 28750ba2cbe9Sxc151355 (void) fflush(stdout); 28760ba2cbe9Sxc151355 while (signalled == 0) { 28770ba2cbe9Sxc151355 c = getchar(); 28780ba2cbe9Sxc151355 if (c == '\n' || c == '\r') { 28790ba2cbe9Sxc151355 if (len != 0) 28800ba2cbe9Sxc151355 break; 28810ba2cbe9Sxc151355 (void) putchar('\n'); 28820ba2cbe9Sxc151355 goto again; 28830ba2cbe9Sxc151355 } 28840ba2cbe9Sxc151355 28850ba2cbe9Sxc151355 buf[len++] = c; 28860ba2cbe9Sxc151355 if (len >= DLADM_SECOBJ_VAL_MAX - 1) 28870ba2cbe9Sxc151355 break; 28880ba2cbe9Sxc151355 (void) putchar('*'); 28890ba2cbe9Sxc151355 } 28900ba2cbe9Sxc151355 28910ba2cbe9Sxc151355 (void) putchar('\n'); 28920ba2cbe9Sxc151355 (void) fflush(stdin); 28930ba2cbe9Sxc151355 28940ba2cbe9Sxc151355 /* 28950ba2cbe9Sxc151355 * Restore terminal setting and handle deferred signals. 28960ba2cbe9Sxc151355 */ 28970ba2cbe9Sxc151355 (void) tcsetattr(0, TCSANOW, &stored); 28980ba2cbe9Sxc151355 28990ba2cbe9Sxc151355 (void) signal(SIGINT, sigfunc); 29000ba2cbe9Sxc151355 if (signalled != 0) 29010ba2cbe9Sxc151355 (void) kill(getpid(), signalled); 29020ba2cbe9Sxc151355 29030ba2cbe9Sxc151355 return (len); 29040ba2cbe9Sxc151355 } 29050ba2cbe9Sxc151355 29060ba2cbe9Sxc151355 static int 29070ba2cbe9Sxc151355 get_secobj_val(char *obj_name, uint8_t *obj_val, uint_t *obj_lenp, 29080ba2cbe9Sxc151355 dladm_secobj_class_t class, FILE *filep) 29090ba2cbe9Sxc151355 { 29100ba2cbe9Sxc151355 int rval; 29110ba2cbe9Sxc151355 uint_t len, len2; 29120ba2cbe9Sxc151355 char buf[DLADM_SECOBJ_VAL_MAX], buf2[DLADM_SECOBJ_VAL_MAX]; 29130ba2cbe9Sxc151355 29140ba2cbe9Sxc151355 if (filep == NULL) { 29150ba2cbe9Sxc151355 len = get_secobj_from_tty(1, obj_name, buf); 29160ba2cbe9Sxc151355 rval = convert_secobj(buf, len, obj_val, obj_lenp, class); 29170ba2cbe9Sxc151355 if (rval == 0) { 29180ba2cbe9Sxc151355 len2 = get_secobj_from_tty(2, obj_name, buf2); 29190ba2cbe9Sxc151355 if (len != len2 || memcmp(buf, buf2, len) != 0) 29200ba2cbe9Sxc151355 rval = ENOTSUP; 29210ba2cbe9Sxc151355 } 29220ba2cbe9Sxc151355 return (rval); 29230ba2cbe9Sxc151355 } else { 29240ba2cbe9Sxc151355 for (;;) { 29250ba2cbe9Sxc151355 if (fgets(buf, sizeof (buf), filep) == NULL) 29260ba2cbe9Sxc151355 break; 29270ba2cbe9Sxc151355 if (isspace(buf[0])) 29280ba2cbe9Sxc151355 continue; 29290ba2cbe9Sxc151355 29300ba2cbe9Sxc151355 len = strlen(buf); 29310ba2cbe9Sxc151355 if (buf[len - 1] == '\n') { 29320ba2cbe9Sxc151355 buf[len - 1] = '\0'; 29330ba2cbe9Sxc151355 len--; 29340ba2cbe9Sxc151355 } 29350ba2cbe9Sxc151355 break; 29360ba2cbe9Sxc151355 } 29370ba2cbe9Sxc151355 (void) fclose(filep); 29380ba2cbe9Sxc151355 } 29390ba2cbe9Sxc151355 return (convert_secobj(buf, len, obj_val, obj_lenp, class)); 29400ba2cbe9Sxc151355 } 29410ba2cbe9Sxc151355 29420ba2cbe9Sxc151355 static boolean_t 29430ba2cbe9Sxc151355 check_auth(const char *auth) 29440ba2cbe9Sxc151355 { 29450ba2cbe9Sxc151355 struct passwd *pw; 29460ba2cbe9Sxc151355 29470ba2cbe9Sxc151355 if ((pw = getpwuid(getuid())) == NULL) 29480ba2cbe9Sxc151355 return (B_FALSE); 29490ba2cbe9Sxc151355 29500ba2cbe9Sxc151355 return (chkauthattr(auth, pw->pw_name) != 0); 29510ba2cbe9Sxc151355 } 29520ba2cbe9Sxc151355 29530ba2cbe9Sxc151355 static void 29540ba2cbe9Sxc151355 audit_secobj(char *auth, char *class, char *obj, 29550ba2cbe9Sxc151355 boolean_t success, boolean_t create) 29560ba2cbe9Sxc151355 { 29570ba2cbe9Sxc151355 adt_session_data_t *ah; 29580ba2cbe9Sxc151355 adt_event_data_t *event; 29590ba2cbe9Sxc151355 au_event_t flag; 29600ba2cbe9Sxc151355 char *errstr; 29610ba2cbe9Sxc151355 29620ba2cbe9Sxc151355 if (create) { 29630ba2cbe9Sxc151355 flag = ADT_dladm_create_secobj; 29640ba2cbe9Sxc151355 errstr = "ADT_dladm_create_secobj"; 29650ba2cbe9Sxc151355 } else { 29660ba2cbe9Sxc151355 flag = ADT_dladm_delete_secobj; 29670ba2cbe9Sxc151355 errstr = "ADT_dladm_delete_secobj"; 29680ba2cbe9Sxc151355 } 29690ba2cbe9Sxc151355 297033343a97Smeem if (adt_start_session(&ah, NULL, ADT_USE_PROC_DATA) != 0) 297133343a97Smeem die("adt_start_session: %s", strerror(errno)); 29720ba2cbe9Sxc151355 297333343a97Smeem if ((event = adt_alloc_event(ah, flag)) == NULL) 297433343a97Smeem die("adt_alloc_event (%s): %s", errstr, strerror(errno)); 29750ba2cbe9Sxc151355 29760ba2cbe9Sxc151355 /* fill in audit info */ 29770ba2cbe9Sxc151355 if (create) { 29780ba2cbe9Sxc151355 event->adt_dladm_create_secobj.auth_used = auth; 29790ba2cbe9Sxc151355 event->adt_dladm_create_secobj.obj_class = class; 29800ba2cbe9Sxc151355 event->adt_dladm_create_secobj.obj_name = obj; 29810ba2cbe9Sxc151355 } else { 29820ba2cbe9Sxc151355 event->adt_dladm_delete_secobj.auth_used = auth; 29830ba2cbe9Sxc151355 event->adt_dladm_delete_secobj.obj_class = class; 29840ba2cbe9Sxc151355 event->adt_dladm_delete_secobj.obj_name = obj; 29850ba2cbe9Sxc151355 } 29860ba2cbe9Sxc151355 29870ba2cbe9Sxc151355 if (success) { 29880ba2cbe9Sxc151355 if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS) != 0) { 298933343a97Smeem die("adt_put_event (%s, success): %s", errstr, 299033343a97Smeem strerror(errno)); 29910ba2cbe9Sxc151355 } 29920ba2cbe9Sxc151355 } else { 29930ba2cbe9Sxc151355 if (adt_put_event(event, ADT_FAILURE, 29940ba2cbe9Sxc151355 ADT_FAIL_VALUE_AUTH) != 0) { 299533343a97Smeem die("adt_put_event: (%s, failure): %s", errstr, 299633343a97Smeem strerror(errno)); 29970ba2cbe9Sxc151355 } 29980ba2cbe9Sxc151355 } 29990ba2cbe9Sxc151355 30000ba2cbe9Sxc151355 adt_free_event(event); 30010ba2cbe9Sxc151355 (void) adt_end_session(ah); 30020ba2cbe9Sxc151355 } 30030ba2cbe9Sxc151355 30040ba2cbe9Sxc151355 #define MAX_SECOBJS 32 30050ba2cbe9Sxc151355 #define MAX_SECOBJ_NAMELEN 32 30060ba2cbe9Sxc151355 static void 30070ba2cbe9Sxc151355 do_create_secobj(int argc, char **argv) 30080ba2cbe9Sxc151355 { 30090ba2cbe9Sxc151355 int option, rval; 30100ba2cbe9Sxc151355 FILE *filep = NULL; 30110ba2cbe9Sxc151355 char *obj_name = NULL; 30120ba2cbe9Sxc151355 char *class_name = NULL; 30130ba2cbe9Sxc151355 uint8_t obj_val[DLADM_SECOBJ_VAL_MAX]; 30140ba2cbe9Sxc151355 uint_t obj_len; 30150ba2cbe9Sxc151355 boolean_t success, temp = B_FALSE; 30160ba2cbe9Sxc151355 dladm_status_t status; 30170ba2cbe9Sxc151355 dladm_secobj_class_t class = -1; 30180ba2cbe9Sxc151355 uid_t euid; 30190ba2cbe9Sxc151355 30200ba2cbe9Sxc151355 opterr = 0; 30210ba2cbe9Sxc151355 (void) memset(obj_val, 0, DLADM_SECOBJ_VAL_MAX); 30220ba2cbe9Sxc151355 while ((option = getopt_long(argc, argv, ":f:c:R:t", 30230ba2cbe9Sxc151355 wifi_longopts, NULL)) != -1) { 30240ba2cbe9Sxc151355 switch (option) { 30250ba2cbe9Sxc151355 case 'f': 30260ba2cbe9Sxc151355 euid = geteuid(); 30270ba2cbe9Sxc151355 (void) seteuid(getuid()); 30280ba2cbe9Sxc151355 filep = fopen(optarg, "r"); 30290ba2cbe9Sxc151355 if (filep == NULL) { 303033343a97Smeem die("cannot open %s: %s", optarg, 303133343a97Smeem strerror(errno)); 30320ba2cbe9Sxc151355 } 30330ba2cbe9Sxc151355 (void) seteuid(euid); 30340ba2cbe9Sxc151355 break; 30350ba2cbe9Sxc151355 case 'c': 30360ba2cbe9Sxc151355 class_name = optarg; 30370ba2cbe9Sxc151355 status = dladm_str2secobjclass(optarg, &class); 30380ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK) { 303933343a97Smeem die("invalid secure object class '%s', " 304033343a97Smeem "valid values are: wep", optarg); 30410ba2cbe9Sxc151355 } 30420ba2cbe9Sxc151355 break; 30430ba2cbe9Sxc151355 case 't': 30440ba2cbe9Sxc151355 temp = B_TRUE; 30450ba2cbe9Sxc151355 break; 30460ba2cbe9Sxc151355 case 'R': 30470ba2cbe9Sxc151355 status = dladm_set_rootdir(optarg); 30480ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK) { 304933343a97Smeem die_dlerr(status, "invalid directory " 305033343a97Smeem "specified"); 30510ba2cbe9Sxc151355 } 30520ba2cbe9Sxc151355 break; 30530ba2cbe9Sxc151355 default: 305433343a97Smeem die_opterr(optopt, option); 30550ba2cbe9Sxc151355 break; 30560ba2cbe9Sxc151355 } 30570ba2cbe9Sxc151355 } 30580ba2cbe9Sxc151355 30590ba2cbe9Sxc151355 if (optind == (argc - 1)) 30600ba2cbe9Sxc151355 obj_name = argv[optind]; 30610ba2cbe9Sxc151355 else if (optind != argc) 30620ba2cbe9Sxc151355 usage(); 30630ba2cbe9Sxc151355 306433343a97Smeem if (class == -1) 306533343a97Smeem die("secure object class required"); 30660ba2cbe9Sxc151355 306733343a97Smeem if (obj_name == NULL) 306833343a97Smeem die("secure object name required"); 30690ba2cbe9Sxc151355 30700ba2cbe9Sxc151355 success = check_auth(LINK_SEC_AUTH); 30710ba2cbe9Sxc151355 audit_secobj(LINK_SEC_AUTH, class_name, obj_name, success, B_TRUE); 307233343a97Smeem if (!success) 307333343a97Smeem die("authorization '%s' is required", LINK_SEC_AUTH); 30740ba2cbe9Sxc151355 307533343a97Smeem rval = get_secobj_val(obj_name, obj_val, &obj_len, class, filep); 307633343a97Smeem if (rval != 0) { 30770ba2cbe9Sxc151355 switch (rval) { 30780ba2cbe9Sxc151355 case ENOENT: 307933343a97Smeem die("invalid secure object class"); 30800ba2cbe9Sxc151355 break; 30810ba2cbe9Sxc151355 case EINVAL: 308233343a97Smeem die("invalid secure object value"); 30830ba2cbe9Sxc151355 break; 30840ba2cbe9Sxc151355 case ENOTSUP: 308533343a97Smeem die("verification failed"); 30860ba2cbe9Sxc151355 break; 30870ba2cbe9Sxc151355 default: 308833343a97Smeem die("invalid secure object: %s", strerror(rval)); 30890ba2cbe9Sxc151355 break; 30900ba2cbe9Sxc151355 } 30910ba2cbe9Sxc151355 } 30920ba2cbe9Sxc151355 30930ba2cbe9Sxc151355 status = dladm_set_secobj(obj_name, class, obj_val, obj_len, 30940ba2cbe9Sxc151355 DLADM_OPT_CREATE | DLADM_OPT_TEMP); 30950ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK) { 309633343a97Smeem die_dlerr(status, "could not create secure object '%s'", 309733343a97Smeem obj_name); 30980ba2cbe9Sxc151355 } 30990ba2cbe9Sxc151355 if (temp) 31000ba2cbe9Sxc151355 return; 31010ba2cbe9Sxc151355 31020ba2cbe9Sxc151355 status = dladm_set_secobj(obj_name, class, obj_val, obj_len, 31030ba2cbe9Sxc151355 DLADM_OPT_PERSIST); 31040ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK) { 310533343a97Smeem warn_dlerr(status, "could not persistently create secure " 310633343a97Smeem "object '%s'", obj_name); 31070ba2cbe9Sxc151355 } 31080ba2cbe9Sxc151355 } 31090ba2cbe9Sxc151355 31100ba2cbe9Sxc151355 static void 31110ba2cbe9Sxc151355 do_delete_secobj(int argc, char **argv) 31120ba2cbe9Sxc151355 { 31130ba2cbe9Sxc151355 int i, option; 31140ba2cbe9Sxc151355 boolean_t temp = B_FALSE; 31150ba2cbe9Sxc151355 split_t *sp = NULL; 31160ba2cbe9Sxc151355 boolean_t success; 31170ba2cbe9Sxc151355 dladm_status_t status, pstatus; 31180ba2cbe9Sxc151355 31190ba2cbe9Sxc151355 opterr = 0; 31200ba2cbe9Sxc151355 status = pstatus = DLADM_STATUS_OK; 312133343a97Smeem while ((option = getopt_long(argc, argv, ":R:t", 31220ba2cbe9Sxc151355 wifi_longopts, NULL)) != -1) { 31230ba2cbe9Sxc151355 switch (option) { 31240ba2cbe9Sxc151355 case 't': 31250ba2cbe9Sxc151355 temp = B_TRUE; 31260ba2cbe9Sxc151355 break; 31270ba2cbe9Sxc151355 case 'R': 31280ba2cbe9Sxc151355 status = dladm_set_rootdir(optarg); 31290ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK) { 313033343a97Smeem die_dlerr(status, "invalid directory " 313133343a97Smeem "specified"); 31320ba2cbe9Sxc151355 } 31330ba2cbe9Sxc151355 break; 31340ba2cbe9Sxc151355 default: 313533343a97Smeem die_opterr(optopt, option); 31360ba2cbe9Sxc151355 break; 31370ba2cbe9Sxc151355 } 31380ba2cbe9Sxc151355 } 31390ba2cbe9Sxc151355 31400ba2cbe9Sxc151355 if (optind == (argc - 1)) { 31410ba2cbe9Sxc151355 sp = split(argv[optind], MAX_SECOBJS, MAX_SECOBJ_NAMELEN); 31420ba2cbe9Sxc151355 if (sp == NULL) { 314333343a97Smeem die("invalid secure object name(s): '%s'", 314433343a97Smeem argv[optind]); 31450ba2cbe9Sxc151355 } 31460ba2cbe9Sxc151355 } else if (optind != argc) 31470ba2cbe9Sxc151355 usage(); 31480ba2cbe9Sxc151355 314933343a97Smeem if (sp == NULL || sp->s_nfields < 1) 315033343a97Smeem die("secure object name required"); 31510ba2cbe9Sxc151355 31520ba2cbe9Sxc151355 success = check_auth(LINK_SEC_AUTH); 31530ba2cbe9Sxc151355 audit_secobj(LINK_SEC_AUTH, "wep", argv[optind], success, B_FALSE); 315433343a97Smeem if (!success) 315533343a97Smeem die("authorization '%s' is required", LINK_SEC_AUTH); 31560ba2cbe9Sxc151355 31570ba2cbe9Sxc151355 for (i = 0; i < sp->s_nfields; i++) { 31580ba2cbe9Sxc151355 status = dladm_unset_secobj(sp->s_fields[i], DLADM_OPT_TEMP); 31590ba2cbe9Sxc151355 if (!temp) { 31600ba2cbe9Sxc151355 pstatus = dladm_unset_secobj(sp->s_fields[i], 31610ba2cbe9Sxc151355 DLADM_OPT_PERSIST); 31620ba2cbe9Sxc151355 } else { 31630ba2cbe9Sxc151355 pstatus = DLADM_STATUS_OK; 31640ba2cbe9Sxc151355 } 31650ba2cbe9Sxc151355 31660ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK) { 316733343a97Smeem warn_dlerr(status, "could not delete secure object " 316833343a97Smeem "'%s'", sp->s_fields[i]); 31690ba2cbe9Sxc151355 } 31700ba2cbe9Sxc151355 if (pstatus != DLADM_STATUS_OK) { 317133343a97Smeem warn_dlerr(pstatus, "could not persistently delete " 317233343a97Smeem "secure object '%s'", sp->s_fields[i]); 31730ba2cbe9Sxc151355 } 31740ba2cbe9Sxc151355 } 31750ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK || pstatus != DLADM_STATUS_OK) 31760ba2cbe9Sxc151355 exit(1); 31770ba2cbe9Sxc151355 } 31780ba2cbe9Sxc151355 31790ba2cbe9Sxc151355 typedef struct show_secobj_state { 31800ba2cbe9Sxc151355 boolean_t ss_persist; 31810ba2cbe9Sxc151355 boolean_t ss_parseable; 31820ba2cbe9Sxc151355 boolean_t ss_debug; 31830ba2cbe9Sxc151355 boolean_t ss_header; 31840ba2cbe9Sxc151355 } show_secobj_state_t; 31850ba2cbe9Sxc151355 31860ba2cbe9Sxc151355 static void 31870ba2cbe9Sxc151355 print_secobj_head(show_secobj_state_t *statep) 31880ba2cbe9Sxc151355 { 31890ba2cbe9Sxc151355 (void) printf("%-20s %-20s ", "OBJECT", "CLASS"); 31900ba2cbe9Sxc151355 if (statep->ss_debug) 31910ba2cbe9Sxc151355 (void) printf("%-30s", "VALUE"); 31920ba2cbe9Sxc151355 (void) putchar('\n'); 31930ba2cbe9Sxc151355 } 31940ba2cbe9Sxc151355 31950ba2cbe9Sxc151355 static boolean_t 31960ba2cbe9Sxc151355 show_secobj(void *arg, const char *obj_name) 31970ba2cbe9Sxc151355 { 31980ba2cbe9Sxc151355 uint_t obj_len = DLADM_SECOBJ_VAL_MAX; 31990ba2cbe9Sxc151355 uint8_t obj_val[DLADM_SECOBJ_VAL_MAX]; 32000ba2cbe9Sxc151355 char buf[DLADM_STRSIZE]; 32010ba2cbe9Sxc151355 uint_t flags = 0; 32020ba2cbe9Sxc151355 dladm_secobj_class_t class; 32030ba2cbe9Sxc151355 show_secobj_state_t *statep = arg; 32040ba2cbe9Sxc151355 dladm_status_t status; 32050ba2cbe9Sxc151355 32060ba2cbe9Sxc151355 if (statep->ss_persist) 32070ba2cbe9Sxc151355 flags |= DLADM_OPT_PERSIST; 32080ba2cbe9Sxc151355 32090ba2cbe9Sxc151355 status = dladm_get_secobj(obj_name, &class, obj_val, &obj_len, flags); 321033343a97Smeem if (status != DLADM_STATUS_OK) 321133343a97Smeem die_dlerr(status, "cannot get secure object '%s'", obj_name); 32120ba2cbe9Sxc151355 32130ba2cbe9Sxc151355 if (statep->ss_header) { 32140ba2cbe9Sxc151355 statep->ss_header = B_FALSE; 32150ba2cbe9Sxc151355 if (!statep->ss_parseable) 32160ba2cbe9Sxc151355 print_secobj_head(statep); 32170ba2cbe9Sxc151355 } 32180ba2cbe9Sxc151355 32190ba2cbe9Sxc151355 if (statep->ss_parseable) { 32200ba2cbe9Sxc151355 (void) printf("OBJECT=\"%s\" CLASS=\"%s\" ", obj_name, 32210ba2cbe9Sxc151355 dladm_secobjclass2str(class, buf)); 32220ba2cbe9Sxc151355 } else { 32230ba2cbe9Sxc151355 (void) printf("%-20s %-20s ", obj_name, 32240ba2cbe9Sxc151355 dladm_secobjclass2str(class, buf)); 32250ba2cbe9Sxc151355 } 32260ba2cbe9Sxc151355 32270ba2cbe9Sxc151355 if (statep->ss_debug) { 32280ba2cbe9Sxc151355 char val[DLADM_SECOBJ_VAL_MAX * 2]; 32290ba2cbe9Sxc151355 uint_t len = sizeof (val); 32300ba2cbe9Sxc151355 32310ba2cbe9Sxc151355 if (octet_to_hexascii(obj_val, obj_len, val, &len) == 0) { 32320ba2cbe9Sxc151355 if (statep->ss_parseable) 32330ba2cbe9Sxc151355 (void) printf("VALUE=\"0x%s\"", val); 32340ba2cbe9Sxc151355 else 32350ba2cbe9Sxc151355 (void) printf("0x%-30s", val); 32360ba2cbe9Sxc151355 } 32370ba2cbe9Sxc151355 } 32380ba2cbe9Sxc151355 (void) putchar('\n'); 32390ba2cbe9Sxc151355 return (B_TRUE); 32400ba2cbe9Sxc151355 } 32410ba2cbe9Sxc151355 32420ba2cbe9Sxc151355 static void 32430ba2cbe9Sxc151355 do_show_secobj(int argc, char **argv) 32440ba2cbe9Sxc151355 { 32450ba2cbe9Sxc151355 int option; 32460ba2cbe9Sxc151355 show_secobj_state_t state; 32470ba2cbe9Sxc151355 dladm_status_t status; 32480ba2cbe9Sxc151355 uint_t i; 32490ba2cbe9Sxc151355 split_t *sp; 32500ba2cbe9Sxc151355 uint_t flags; 32510ba2cbe9Sxc151355 32520ba2cbe9Sxc151355 opterr = 0; 32530ba2cbe9Sxc151355 state.ss_persist = B_FALSE; 32540ba2cbe9Sxc151355 state.ss_parseable = B_FALSE; 32550ba2cbe9Sxc151355 state.ss_debug = B_FALSE; 32560ba2cbe9Sxc151355 state.ss_header = B_TRUE; 32570ba2cbe9Sxc151355 while ((option = getopt_long(argc, argv, ":pPd", 32580ba2cbe9Sxc151355 wifi_longopts, NULL)) != -1) { 32590ba2cbe9Sxc151355 switch (option) { 32600ba2cbe9Sxc151355 case 'p': 32610ba2cbe9Sxc151355 state.ss_parseable = B_TRUE; 32620ba2cbe9Sxc151355 break; 32630ba2cbe9Sxc151355 case 'P': 32640ba2cbe9Sxc151355 state.ss_persist = B_TRUE; 32650ba2cbe9Sxc151355 break; 32660ba2cbe9Sxc151355 case 'd': 326733343a97Smeem if (getuid() != 0) 326833343a97Smeem die("insufficient privileges"); 32690ba2cbe9Sxc151355 state.ss_debug = B_TRUE; 32700ba2cbe9Sxc151355 break; 32710ba2cbe9Sxc151355 default: 327233343a97Smeem die_opterr(optopt, option); 32730ba2cbe9Sxc151355 break; 32740ba2cbe9Sxc151355 } 32750ba2cbe9Sxc151355 } 32760ba2cbe9Sxc151355 32770ba2cbe9Sxc151355 if (optind == (argc - 1)) { 32780ba2cbe9Sxc151355 sp = split(argv[optind], MAX_SECOBJS, MAX_SECOBJ_NAMELEN); 32790ba2cbe9Sxc151355 if (sp == NULL) { 328033343a97Smeem die("invalid secure object name(s): '%s'", 328133343a97Smeem argv[optind]); 32820ba2cbe9Sxc151355 } 32830ba2cbe9Sxc151355 for (i = 0; i < sp->s_nfields; i++) { 32840ba2cbe9Sxc151355 if (!show_secobj(&state, sp->s_fields[i])) 32850ba2cbe9Sxc151355 break; 32860ba2cbe9Sxc151355 } 32870ba2cbe9Sxc151355 splitfree(sp); 32880ba2cbe9Sxc151355 return; 32890ba2cbe9Sxc151355 } else if (optind != argc) 32900ba2cbe9Sxc151355 usage(); 32910ba2cbe9Sxc151355 32920ba2cbe9Sxc151355 flags = state.ss_persist ? DLADM_OPT_PERSIST : 0; 32930ba2cbe9Sxc151355 status = dladm_walk_secobj(&state, show_secobj, flags); 329433343a97Smeem if (status != DLADM_STATUS_OK) 329533343a97Smeem die_dlerr(status, "show-secobj"); 32960ba2cbe9Sxc151355 } 32970ba2cbe9Sxc151355 32980ba2cbe9Sxc151355 /* ARGSUSED */ 32990ba2cbe9Sxc151355 static void 33000ba2cbe9Sxc151355 do_init_linkprop(int argc, char **argv) 33010ba2cbe9Sxc151355 { 33020ba2cbe9Sxc151355 dladm_status_t status; 33030ba2cbe9Sxc151355 33040ba2cbe9Sxc151355 status = dladm_init_linkprop(); 330533343a97Smeem if (status != DLADM_STATUS_OK) 330633343a97Smeem die_dlerr(status, "link property initialization failed"); 33070ba2cbe9Sxc151355 } 33080ba2cbe9Sxc151355 33090ba2cbe9Sxc151355 /* ARGSUSED */ 33100ba2cbe9Sxc151355 static void 33110ba2cbe9Sxc151355 do_init_secobj(int argc, char **argv) 33120ba2cbe9Sxc151355 { 33130ba2cbe9Sxc151355 dladm_status_t status; 33140ba2cbe9Sxc151355 33150ba2cbe9Sxc151355 status = dladm_init_secobj(); 331633343a97Smeem if (status != DLADM_STATUS_OK) 331733343a97Smeem die_dlerr(status, "secure object initialization failed"); 331833343a97Smeem } 331933343a97Smeem 332033343a97Smeem static boolean_t 332133343a97Smeem str2int(const char *str, int *valp) 332233343a97Smeem { 332333343a97Smeem int val; 332433343a97Smeem char *endp = NULL; 332533343a97Smeem 332633343a97Smeem errno = 0; 332733343a97Smeem val = strtol(str, &endp, 10); 332833343a97Smeem if (errno != 0 || *endp != '\0') 332933343a97Smeem return (B_FALSE); 333033343a97Smeem 333133343a97Smeem *valp = val; 333233343a97Smeem return (B_TRUE); 333333343a97Smeem } 333433343a97Smeem 333533343a97Smeem /* PRINTFLIKE1 */ 333633343a97Smeem static void 333733343a97Smeem warn(const char *format, ...) 333833343a97Smeem { 333933343a97Smeem va_list alist; 334033343a97Smeem 334133343a97Smeem format = gettext(format); 334233343a97Smeem (void) fprintf(stderr, "%s: warning: ", progname); 334333343a97Smeem 334433343a97Smeem va_start(alist, format); 334533343a97Smeem (void) vfprintf(stderr, format, alist); 334633343a97Smeem va_end(alist); 334733343a97Smeem 334833343a97Smeem (void) putchar('\n'); 334933343a97Smeem } 335033343a97Smeem 335133343a97Smeem /* PRINTFLIKE2 */ 335233343a97Smeem static void 335333343a97Smeem warn_wlerr(wladm_status_t err, const char *format, ...) 335433343a97Smeem { 335533343a97Smeem va_list alist; 335633343a97Smeem char errmsg[WLADM_STRSIZE]; 335733343a97Smeem 335833343a97Smeem format = gettext(format); 335933343a97Smeem (void) fprintf(stderr, gettext("%s: warning: "), progname); 336033343a97Smeem 336133343a97Smeem va_start(alist, format); 336233343a97Smeem (void) vfprintf(stderr, format, alist); 336333343a97Smeem va_end(alist); 336433343a97Smeem (void) fprintf(stderr, ": %s\n", wladm_status2str(err, errmsg)); 336533343a97Smeem } 336633343a97Smeem 336733343a97Smeem /* PRINTFLIKE2 */ 336833343a97Smeem static void 336933343a97Smeem warn_dlerr(dladm_status_t err, const char *format, ...) 337033343a97Smeem { 337133343a97Smeem va_list alist; 337233343a97Smeem char errmsg[DLADM_STRSIZE]; 337333343a97Smeem 337433343a97Smeem format = gettext(format); 337533343a97Smeem (void) fprintf(stderr, gettext("%s: warning: "), progname); 337633343a97Smeem 337733343a97Smeem va_start(alist, format); 337833343a97Smeem (void) vfprintf(stderr, format, alist); 337933343a97Smeem va_end(alist); 338033343a97Smeem (void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg)); 338133343a97Smeem } 338233343a97Smeem 338333343a97Smeem /* PRINTFLIKE2 */ 338433343a97Smeem static void 338533343a97Smeem die_laerr(laadm_diag_t diag, const char *format, ...) 338633343a97Smeem { 338733343a97Smeem va_list alist; 338833343a97Smeem char *errstr = strerror(errno); 338933343a97Smeem 339033343a97Smeem format = gettext(format); 339133343a97Smeem (void) fprintf(stderr, "%s: ", progname); 339233343a97Smeem 339333343a97Smeem va_start(alist, format); 339433343a97Smeem (void) vfprintf(stderr, format, alist); 339533343a97Smeem va_end(alist); 339633343a97Smeem 339733343a97Smeem if (diag == 0) 339833343a97Smeem (void) fprintf(stderr, ": %s\n", errstr); 339933343a97Smeem else 340033343a97Smeem (void) fprintf(stderr, ": %s (%s)\n", errstr, laadm_diag(diag)); 340133343a97Smeem 340233343a97Smeem exit(EXIT_FAILURE); 340333343a97Smeem } 340433343a97Smeem 340533343a97Smeem /* PRINTFLIKE2 */ 340633343a97Smeem static void 340733343a97Smeem die_wlerr(wladm_status_t err, const char *format, ...) 340833343a97Smeem { 340933343a97Smeem va_list alist; 341033343a97Smeem char errmsg[WLADM_STRSIZE]; 341133343a97Smeem 341233343a97Smeem format = gettext(format); 341333343a97Smeem (void) fprintf(stderr, "%s: ", progname); 341433343a97Smeem 341533343a97Smeem va_start(alist, format); 341633343a97Smeem (void) vfprintf(stderr, format, alist); 341733343a97Smeem va_end(alist); 341833343a97Smeem (void) fprintf(stderr, ": %s\n", wladm_status2str(err, errmsg)); 341933343a97Smeem 342033343a97Smeem exit(EXIT_FAILURE); 342133343a97Smeem } 342233343a97Smeem 342333343a97Smeem /* PRINTFLIKE2 */ 342433343a97Smeem static void 342533343a97Smeem die_dlerr(dladm_status_t err, const char *format, ...) 342633343a97Smeem { 342733343a97Smeem va_list alist; 342833343a97Smeem char errmsg[DLADM_STRSIZE]; 342933343a97Smeem 343033343a97Smeem format = gettext(format); 343133343a97Smeem (void) fprintf(stderr, "%s: ", progname); 343233343a97Smeem 343333343a97Smeem va_start(alist, format); 343433343a97Smeem (void) vfprintf(stderr, format, alist); 343533343a97Smeem va_end(alist); 343633343a97Smeem (void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg)); 343733343a97Smeem 343833343a97Smeem exit(EXIT_FAILURE); 343933343a97Smeem } 344033343a97Smeem 344133343a97Smeem /* PRINTFLIKE1 */ 344233343a97Smeem static void 344333343a97Smeem die(const char *format, ...) 344433343a97Smeem { 344533343a97Smeem va_list alist; 344633343a97Smeem 344733343a97Smeem format = gettext(format); 344833343a97Smeem (void) fprintf(stderr, "%s: ", progname); 344933343a97Smeem 345033343a97Smeem va_start(alist, format); 345133343a97Smeem (void) vfprintf(stderr, format, alist); 345233343a97Smeem va_end(alist); 345333343a97Smeem 345433343a97Smeem (void) putchar('\n'); 345533343a97Smeem exit(EXIT_FAILURE); 345633343a97Smeem } 345733343a97Smeem 345833343a97Smeem static void 345933343a97Smeem die_optdup(int opt) 346033343a97Smeem { 346133343a97Smeem die("the option -%c cannot be specified more than once", opt); 346233343a97Smeem } 346333343a97Smeem 346433343a97Smeem static void 346533343a97Smeem die_opterr(int opt, int opterr) 346633343a97Smeem { 346733343a97Smeem switch (opterr) { 346833343a97Smeem case ':': 346933343a97Smeem die("option '-%c' requires a value", opt); 347033343a97Smeem break; 347133343a97Smeem case '?': 347233343a97Smeem default: 347333343a97Smeem die("unrecognized option '-%c'", opt); 347433343a97Smeem break; 34750ba2cbe9Sxc151355 } 34760ba2cbe9Sxc151355 } 3477