xref: /titanic_53/usr/src/cmd/dladm/dladm.c (revision 0ba2cbe97e0678a691742f98d2532caed0a2c4aa)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5219a2a31Shl157128  * Common Development and Distribution License (the "License").
6219a2a31Shl157128  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22219a2a31Shl157128  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate #include <stdio.h>
29*0ba2cbe9Sxc151355 #include <ctype.h>
307c478bd9Sstevel@tonic-gate #include <locale.h>
31*0ba2cbe9Sxc151355 #include <signal.h>
327c478bd9Sstevel@tonic-gate #include <stdarg.h>
337c478bd9Sstevel@tonic-gate #include <stdlib.h>
347c478bd9Sstevel@tonic-gate #include <fcntl.h>
357c478bd9Sstevel@tonic-gate #include <string.h>
367c478bd9Sstevel@tonic-gate #include <stropts.h>
377c478bd9Sstevel@tonic-gate #include <errno.h>
387c478bd9Sstevel@tonic-gate #include <kstat.h>
397c478bd9Sstevel@tonic-gate #include <strings.h>
407c478bd9Sstevel@tonic-gate #include <getopt.h>
417c478bd9Sstevel@tonic-gate #include <unistd.h>
42cd93090eSericheng #include <priv.h>
43*0ba2cbe9Sxc151355 #include <termios.h>
44*0ba2cbe9Sxc151355 #include <pwd.h>
45*0ba2cbe9Sxc151355 #include <auth_attr.h>
46*0ba2cbe9Sxc151355 #include <auth_list.h>
477c478bd9Sstevel@tonic-gate #include <libintl.h>
487c478bd9Sstevel@tonic-gate #include <libdlpi.h>
497c478bd9Sstevel@tonic-gate #include <libdladm.h>
507c478bd9Sstevel@tonic-gate #include <liblaadm.h>
517c478bd9Sstevel@tonic-gate #include <libmacadm.h>
52*0ba2cbe9Sxc151355 #include <libwladm.h>
53*0ba2cbe9Sxc151355 #include <libinetutil.h>
54*0ba2cbe9Sxc151355 #include <bsm/adt.h>
55*0ba2cbe9Sxc151355 #include <bsm/adt_event.h>
567c478bd9Sstevel@tonic-gate 
57ba2e4443Sseb #define	AGGR_DRV	"aggr"
587c478bd9Sstevel@tonic-gate #define	MAXPORT		256
597c478bd9Sstevel@tonic-gate #define	DUMP_LACP_FORMAT	"    %-9s %-8s %-7s %-12s "	\
607c478bd9Sstevel@tonic-gate 	"%-5s %-4s %-4s %-9s %-7s\n"
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate typedef struct pktsum_s {
637c478bd9Sstevel@tonic-gate 	uint64_t	ipackets;
647c478bd9Sstevel@tonic-gate 	uint64_t	opackets;
657c478bd9Sstevel@tonic-gate 	uint64_t	rbytes;
667c478bd9Sstevel@tonic-gate 	uint64_t	obytes;
677c478bd9Sstevel@tonic-gate 	uint32_t	ierrors;
687c478bd9Sstevel@tonic-gate 	uint32_t	oerrors;
697c478bd9Sstevel@tonic-gate } pktsum_t;
707c478bd9Sstevel@tonic-gate 
717c478bd9Sstevel@tonic-gate typedef struct show_link_state {
727c478bd9Sstevel@tonic-gate 	boolean_t	ls_firstonly;
737c478bd9Sstevel@tonic-gate 	boolean_t	ls_donefirst;
747c478bd9Sstevel@tonic-gate 	boolean_t	ls_stats;
757c478bd9Sstevel@tonic-gate 	pktsum_t	ls_prevstats;
767c478bd9Sstevel@tonic-gate 	boolean_t	ls_parseable;
777c478bd9Sstevel@tonic-gate } show_link_state_t;
787c478bd9Sstevel@tonic-gate 
797c478bd9Sstevel@tonic-gate typedef struct show_grp_state {
807c478bd9Sstevel@tonic-gate 	uint32_t	gs_key;
817c478bd9Sstevel@tonic-gate 	boolean_t	gs_lacp;
827c478bd9Sstevel@tonic-gate 	boolean_t	gs_found;
837c478bd9Sstevel@tonic-gate 	boolean_t	gs_stats;
847c478bd9Sstevel@tonic-gate 	boolean_t	gs_firstonly;
857c478bd9Sstevel@tonic-gate 	pktsum_t	gs_prevstats[MAXPORT];
867c478bd9Sstevel@tonic-gate 	boolean_t	gs_parseable;
877c478bd9Sstevel@tonic-gate } show_grp_state_t;
887c478bd9Sstevel@tonic-gate 
897c478bd9Sstevel@tonic-gate typedef struct show_mac_state {
907c478bd9Sstevel@tonic-gate 	boolean_t	ms_firstonly;
917c478bd9Sstevel@tonic-gate 	boolean_t	ms_donefirst;
927c478bd9Sstevel@tonic-gate 	pktsum_t	ms_prevstats;
937c478bd9Sstevel@tonic-gate 	boolean_t	ms_parseable;
947c478bd9Sstevel@tonic-gate } show_mac_state_t;
957c478bd9Sstevel@tonic-gate 
967c478bd9Sstevel@tonic-gate typedef struct port_state {
977c478bd9Sstevel@tonic-gate 	char			*state_name;
987c478bd9Sstevel@tonic-gate 	aggr_port_state_t	state_num;
997c478bd9Sstevel@tonic-gate } port_state_t;
1007c478bd9Sstevel@tonic-gate 
1017c478bd9Sstevel@tonic-gate static port_state_t port_states[] = {
1027c478bd9Sstevel@tonic-gate 	{"standby", AGGR_PORT_STATE_STANDBY },
1037c478bd9Sstevel@tonic-gate 	{"attached", AGGR_PORT_STATE_ATTACHED }
1047c478bd9Sstevel@tonic-gate };
1057c478bd9Sstevel@tonic-gate 
1067c478bd9Sstevel@tonic-gate #define	NPORTSTATES	(sizeof (port_states) / sizeof (port_state_t))
1077c478bd9Sstevel@tonic-gate 
108*0ba2cbe9Sxc151355 typedef	void cmdfunc_t(int, char **);
109*0ba2cbe9Sxc151355 
110*0ba2cbe9Sxc151355 static cmdfunc_t do_show_link, do_show_dev, do_show_wifi;
111*0ba2cbe9Sxc151355 static cmdfunc_t do_create_aggr, do_delete_aggr, do_add_aggr, do_remove_aggr;
112*0ba2cbe9Sxc151355 static cmdfunc_t do_modify_aggr, do_show_aggr, do_up_aggr, do_down_aggr;
113*0ba2cbe9Sxc151355 static cmdfunc_t do_scan_wifi, do_connect_wifi, do_disconnect_wifi;
114*0ba2cbe9Sxc151355 static cmdfunc_t do_show_linkprop, do_set_linkprop, do_reset_linkprop;
115*0ba2cbe9Sxc151355 static cmdfunc_t do_create_secobj, do_delete_secobj, do_show_secobj;
116*0ba2cbe9Sxc151355 static cmdfunc_t do_init_linkprop, do_init_secobj;
1177c478bd9Sstevel@tonic-gate 
1187c478bd9Sstevel@tonic-gate static void	link_stats(const char *, uint32_t);
1197c478bd9Sstevel@tonic-gate static void	aggr_stats(uint16_t, uint32_t);
1207c478bd9Sstevel@tonic-gate static void	dev_stats(const char *dev, uint32_t);
1217c478bd9Sstevel@tonic-gate 
122ba2e4443Sseb static void	get_mac_stats(const char *, pktsum_t *);
1237c478bd9Sstevel@tonic-gate static void	get_link_stats(const char *, pktsum_t *);
124ba2e4443Sseb static uint64_t	mac_ifspeed(const char *);
125ba2e4443Sseb static char	*mac_link_state(const char *);
126ba2e4443Sseb static char	*mac_link_duplex(const char *);
1277c478bd9Sstevel@tonic-gate static void	stats_total(pktsum_t *, pktsum_t *, pktsum_t *);
1287c478bd9Sstevel@tonic-gate static void	stats_diff(pktsum_t *, pktsum_t *, pktsum_t *);
1297c478bd9Sstevel@tonic-gate 
1307c478bd9Sstevel@tonic-gate typedef struct	cmd {
1317c478bd9Sstevel@tonic-gate 	char		*c_name;
132*0ba2cbe9Sxc151355 	cmdfunc_t	*c_fn;
1337c478bd9Sstevel@tonic-gate } cmd_t;
1347c478bd9Sstevel@tonic-gate 
1357c478bd9Sstevel@tonic-gate static cmd_t	cmds[] = {
1367c478bd9Sstevel@tonic-gate 	{ "show-link",		do_show_link 		},
137210db224Sericheng 	{ "show-dev",		do_show_dev 		},
1387c478bd9Sstevel@tonic-gate 	{ "create-aggr",	do_create_aggr		},
1397c478bd9Sstevel@tonic-gate 	{ "delete-aggr",	do_delete_aggr 		},
1407c478bd9Sstevel@tonic-gate 	{ "add-aggr",		do_add_aggr 		},
1417c478bd9Sstevel@tonic-gate 	{ "remove-aggr",	do_remove_aggr		},
1427c478bd9Sstevel@tonic-gate 	{ "modify-aggr",	do_modify_aggr		},
1437c478bd9Sstevel@tonic-gate 	{ "show-aggr",		do_show_aggr		},
1447c478bd9Sstevel@tonic-gate 	{ "up-aggr",		do_up_aggr		},
145*0ba2cbe9Sxc151355 	{ "down-aggr",		do_down_aggr		},
146*0ba2cbe9Sxc151355 	{ "scan-wifi",		do_scan_wifi 		},
147*0ba2cbe9Sxc151355 	{ "connect-wifi",	do_connect_wifi 	},
148*0ba2cbe9Sxc151355 	{ "disconnect-wifi",	do_disconnect_wifi 	},
149*0ba2cbe9Sxc151355 	{ "show-wifi",		do_show_wifi		},
150*0ba2cbe9Sxc151355 	{ "show-linkprop",	do_show_linkprop 	},
151*0ba2cbe9Sxc151355 	{ "set-linkprop", 	do_set_linkprop 	},
152*0ba2cbe9Sxc151355 	{ "reset-linkprop",	do_reset_linkprop 	},
153*0ba2cbe9Sxc151355 	{ "create-secobj",	do_create_secobj 	},
154*0ba2cbe9Sxc151355 	{ "delete-secobj",	do_delete_secobj 	},
155*0ba2cbe9Sxc151355 	{ "show-secobj",	do_show_secobj 		},
156*0ba2cbe9Sxc151355 	{ "init-linkprop",	do_init_linkprop	},
157*0ba2cbe9Sxc151355 	{ "init-secobj",	do_init_secobj 		}
1587c478bd9Sstevel@tonic-gate };
1597c478bd9Sstevel@tonic-gate 
1607c478bd9Sstevel@tonic-gate static const struct option longopts[] = {
1617c478bd9Sstevel@tonic-gate 	{"vlan-id",	required_argument,	0, 'v'	},
1627c478bd9Sstevel@tonic-gate 	{"dev",		required_argument,	0, 'd'	},
1637c478bd9Sstevel@tonic-gate 	{"policy",	required_argument,	0, 'P'	},
1647c478bd9Sstevel@tonic-gate 	{"lacp-mode",	required_argument,	0, 'l'	},
1657c478bd9Sstevel@tonic-gate 	{"lacp-timer",	required_argument,	0, 'T'	},
1667c478bd9Sstevel@tonic-gate 	{"unicast",	required_argument,	0, 'u'	},
1677c478bd9Sstevel@tonic-gate 	{"statistics",	no_argument,		0, 's'	},
1687c478bd9Sstevel@tonic-gate 	{"interval",	required_argument,	0, 'i'	},
1697c478bd9Sstevel@tonic-gate 	{"lacp",	no_argument,		0, 'L'	},
1707c478bd9Sstevel@tonic-gate 	{"temporary",	no_argument,		0, 't'	},
1717c478bd9Sstevel@tonic-gate 	{"root-dir",	required_argument,	0, 'r'	},
1727c478bd9Sstevel@tonic-gate 	{"parseable",	no_argument,		0, 'p'	},
1737c478bd9Sstevel@tonic-gate 	{ 0, 0, 0, 0 }
1747c478bd9Sstevel@tonic-gate };
1757c478bd9Sstevel@tonic-gate 
176*0ba2cbe9Sxc151355 static const struct option prop_longopts[] = {
177*0ba2cbe9Sxc151355 	{"temporary",	no_argument,		0, 't'	},
178*0ba2cbe9Sxc151355 	{"root-dir",	required_argument,	0, 'R'	},
179*0ba2cbe9Sxc151355 	{"prop",	required_argument,	0, 'p'	},
180*0ba2cbe9Sxc151355 	{"parseable",	no_argument,		0, 'c'	},
181*0ba2cbe9Sxc151355 	{"persistent",	no_argument,		0, 'P'	},
182*0ba2cbe9Sxc151355 	{ 0, 0, 0, 0 }
183*0ba2cbe9Sxc151355 };
184*0ba2cbe9Sxc151355 
185*0ba2cbe9Sxc151355 static const struct option wifi_longopts[] = {
186*0ba2cbe9Sxc151355 	{"parseable",	no_argument,		0, 'p'	},
187*0ba2cbe9Sxc151355 	{"output",	required_argument,	0, 'o'	},
188*0ba2cbe9Sxc151355 	{"essid",	required_argument,	0, 'e'	},
189*0ba2cbe9Sxc151355 	{"bsstype",	required_argument,	0, 'b'	},
190*0ba2cbe9Sxc151355 	{"mode",	required_argument,	0, 'm'	},
191*0ba2cbe9Sxc151355 	{"key",		required_argument,	0, 'k'	},
192*0ba2cbe9Sxc151355 	{"sec",		required_argument,	0, 's'	},
193*0ba2cbe9Sxc151355 	{"auth",	required_argument,	0, 'a'	},
194*0ba2cbe9Sxc151355 	{"create-ibss",	required_argument,	0, 'c'	},
195*0ba2cbe9Sxc151355 	{"timeout",	required_argument,	0, 'T'	},
196*0ba2cbe9Sxc151355 	{"all-links",	no_argument,		0, 'a'	},
197*0ba2cbe9Sxc151355 	{"temporary",	no_argument,		0, 't'	},
198*0ba2cbe9Sxc151355 	{"root-dir",	required_argument,	0, 'R'	},
199*0ba2cbe9Sxc151355 	{"persistent",	no_argument,		0, 'P'	},
200*0ba2cbe9Sxc151355 	{"file",	required_argument,	0, 'f'	},
201*0ba2cbe9Sxc151355 	{ 0, 0, 0, 0 }
202*0ba2cbe9Sxc151355 };
203*0ba2cbe9Sxc151355 
2047c478bd9Sstevel@tonic-gate static char *progname;
205*0ba2cbe9Sxc151355 static sig_atomic_t signalled;
2067c478bd9Sstevel@tonic-gate 
2077c478bd9Sstevel@tonic-gate #define	PRINT_ERR_DIAG(s, diag, func) {					\
2087c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext(s), progname, strerror(errno));	\
2097c478bd9Sstevel@tonic-gate 	if (diag != 0)							\
2107c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, " (%s)", func(diag));		\
2117c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "\n");					\
2127c478bd9Sstevel@tonic-gate }
2137c478bd9Sstevel@tonic-gate 
2147c478bd9Sstevel@tonic-gate static void
2157c478bd9Sstevel@tonic-gate usage(void)
2167c478bd9Sstevel@tonic-gate {
217*0ba2cbe9Sxc151355 	(void) fprintf(stderr, gettext("usage:  dladm <subcommand> <args> ...\n"
218*0ba2cbe9Sxc151355 	    "\tshow-link       [-p] [-s [-i <interval>]] [<name>]\n"
219*0ba2cbe9Sxc151355 	    "\tshow-dev        [-p] [-s [-i <interval>]] [<dev>]\n"
220*0ba2cbe9Sxc151355 	    "\n"
221*0ba2cbe9Sxc151355 	    "\tcreate-aggr     [-t] [-R <root-dir>] [-P <policy>] [-l <mode>]\n"
222*0ba2cbe9Sxc151355 	    "\t                [-T <time>] [-u <address>] -d <dev> ... <key>\n"
223*0ba2cbe9Sxc151355 	    "\tmodify-aggr     [-t] [-R <root-dir>] [-P <policy>] [-l <mode>]\n"
224*0ba2cbe9Sxc151355 	    "\t                [-T <time>] [-u <address>] <key>\n"
225*0ba2cbe9Sxc151355 	    "\tdelete-aggr     [-t] [-R <root-dir>] <key>\n"
226*0ba2cbe9Sxc151355 	    "\tadd-aggr        [-t] [-R <root-dir>] -d <dev> ... <key>\n"
227*0ba2cbe9Sxc151355 	    "\tremove-aggr     [-t] [-R <root-dir>] -d <dev> ... <key>\n"
228*0ba2cbe9Sxc151355 	    "\tshow-aggr       [-pL][-s [-i <interval>]] [<key>]\n"
229*0ba2cbe9Sxc151355 	    "\n"
230*0ba2cbe9Sxc151355 	    "\tscan-wifi       [-p] [-o <field>,...] [<name>]\n"
231*0ba2cbe9Sxc151355 	    "\tconnect-wifi    [-e <essid>] [-i <bssid>] [-k <key>,...]"
232*0ba2cbe9Sxc151355 	    " [-s wep]\n"
233*0ba2cbe9Sxc151355 	    "\t                [-a open|shared] [-b bss|ibss] [-c] [-m a|b|g]\n"
234*0ba2cbe9Sxc151355 	    "\t                [-T <time>] [<name>]\n"
235*0ba2cbe9Sxc151355 	    "\tdisconnect-wifi [-a] [<name>]\n"
236*0ba2cbe9Sxc151355 	    "\tshow-wifi       [-p] [-o <field>,...] [<name>]\n"
237*0ba2cbe9Sxc151355 	    "\n"
238*0ba2cbe9Sxc151355 	    "\tset-linkprop    [-t] [-R <root-dir>]  -p <prop>=<value>[,...]"
239*0ba2cbe9Sxc151355 	    " <name>\n"
240*0ba2cbe9Sxc151355 	    "\treset-linkprop  [-t] [-R <root-dir>] [-p <prop>,...] <name>\n"
241*0ba2cbe9Sxc151355 	    "\tshow-linkprop   [-cP][-p <prop>,...] <name>\n"
242*0ba2cbe9Sxc151355 	    "\n"
243*0ba2cbe9Sxc151355 	    "\tcreate-secobj   [-t] [-R <root-dir>] [-f <file>] -c <class>"
244*0ba2cbe9Sxc151355 	    " <secobj>\n"
245*0ba2cbe9Sxc151355 	    "\tdelete-secobj   [-t] [-R <root-dir>] <secobj>[,...]\n"
246*0ba2cbe9Sxc151355 	    "\tshow-secobj     [-pP][<secobj>,...]\n"));
2477c478bd9Sstevel@tonic-gate 	exit(1);
2487c478bd9Sstevel@tonic-gate }
2497c478bd9Sstevel@tonic-gate 
2507c478bd9Sstevel@tonic-gate int
2517c478bd9Sstevel@tonic-gate main(int argc, char *argv[])
2527c478bd9Sstevel@tonic-gate {
2537c478bd9Sstevel@tonic-gate 	int	i;
2547c478bd9Sstevel@tonic-gate 	cmd_t	*cmdp;
2557c478bd9Sstevel@tonic-gate 
2567c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
2577c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)
2587c478bd9Sstevel@tonic-gate #define	TEXT_DOMAIN "SYS_TEST"
2597c478bd9Sstevel@tonic-gate #endif
2607c478bd9Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
2617c478bd9Sstevel@tonic-gate 
2627c478bd9Sstevel@tonic-gate 	progname = argv[0];
2637c478bd9Sstevel@tonic-gate 
2647c478bd9Sstevel@tonic-gate 	if (argc < 2)
2657c478bd9Sstevel@tonic-gate 		usage();
2667c478bd9Sstevel@tonic-gate 
267cd93090eSericheng 	if (!priv_ineffect(PRIV_SYS_NET_CONFIG) ||
268cd93090eSericheng 	    !priv_ineffect(PRIV_NET_RAWACCESS)) {
269cd93090eSericheng 		(void) fprintf(stderr,
270cd93090eSericheng 		    gettext("%s: insufficient privileges\n"), progname);
271cd93090eSericheng 		exit(1);
272cd93090eSericheng 	}
273cd93090eSericheng 
2747c478bd9Sstevel@tonic-gate 	for (i = 0; i < sizeof (cmds) / sizeof (cmds[0]); i++) {
2757c478bd9Sstevel@tonic-gate 		cmdp = &cmds[i];
2767c478bd9Sstevel@tonic-gate 		if (strcmp(argv[1], cmdp->c_name) == 0) {
2777c478bd9Sstevel@tonic-gate 			cmdp->c_fn(argc - 1, &argv[1]);
2787c478bd9Sstevel@tonic-gate 			exit(0);
2797c478bd9Sstevel@tonic-gate 		}
2807c478bd9Sstevel@tonic-gate 	}
2817c478bd9Sstevel@tonic-gate 
2827c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("%s: unknown subcommand '%s'\n"),
2837c478bd9Sstevel@tonic-gate 	    progname, argv[1]);
2847c478bd9Sstevel@tonic-gate 	usage();
2857c478bd9Sstevel@tonic-gate 
2867c478bd9Sstevel@tonic-gate 	return (0);
2877c478bd9Sstevel@tonic-gate }
2887c478bd9Sstevel@tonic-gate 
2897c478bd9Sstevel@tonic-gate 
2907c478bd9Sstevel@tonic-gate static void
2917c478bd9Sstevel@tonic-gate do_create_aggr(int argc, char *argv[])
2927c478bd9Sstevel@tonic-gate {
2937c478bd9Sstevel@tonic-gate 	char			option;
2947c478bd9Sstevel@tonic-gate 	uint16_t		key;
2957c478bd9Sstevel@tonic-gate 	uint32_t		policy = AGGR_POLICY_L4;
2967c478bd9Sstevel@tonic-gate 	aggr_lacp_mode_t	lacp_mode = AGGR_LACP_OFF;
2977c478bd9Sstevel@tonic-gate 	aggr_lacp_timer_t	lacp_timer = AGGR_LACP_TIMER_SHORT;
2987c478bd9Sstevel@tonic-gate 	laadm_port_attr_db_t	port[MAXPORT];
2997c478bd9Sstevel@tonic-gate 	uint_t			nport = 0;
3007c478bd9Sstevel@tonic-gate 	uint8_t			mac_addr[ETHERADDRL];
3017c478bd9Sstevel@tonic-gate 	boolean_t		mac_addr_fixed = B_FALSE;
3027c478bd9Sstevel@tonic-gate 	boolean_t		P_arg = B_FALSE;
3037c478bd9Sstevel@tonic-gate 	boolean_t		l_arg = B_FALSE;
3047c478bd9Sstevel@tonic-gate 	boolean_t		t_arg = B_FALSE;
3057c478bd9Sstevel@tonic-gate 	boolean_t		u_arg = B_FALSE;
3067c478bd9Sstevel@tonic-gate 	boolean_t		T_arg = B_FALSE;
3077c478bd9Sstevel@tonic-gate 	char			*altroot = NULL;
3087c478bd9Sstevel@tonic-gate 	char			*endp = NULL;
3097c478bd9Sstevel@tonic-gate 	laadm_diag_t		diag = 0;
3107c478bd9Sstevel@tonic-gate 
3117c478bd9Sstevel@tonic-gate 	opterr = 0;
3127c478bd9Sstevel@tonic-gate 	while ((option = getopt_long(argc, argv, ":d:l:P:R:tu:T:",
3137c478bd9Sstevel@tonic-gate 	    longopts, NULL)) != -1) {
3147c478bd9Sstevel@tonic-gate 		switch (option) {
3157c478bd9Sstevel@tonic-gate 		case 'd':
3167c478bd9Sstevel@tonic-gate 			if (nport >= MAXPORT) {
3177c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
3187c478bd9Sstevel@tonic-gate 				    gettext("%s: too many <dev> arguments\n"),
3197c478bd9Sstevel@tonic-gate 				    progname);
3207c478bd9Sstevel@tonic-gate 				exit(1);
3217c478bd9Sstevel@tonic-gate 			}
3227c478bd9Sstevel@tonic-gate 
3237c478bd9Sstevel@tonic-gate 			if (strlcpy(port[nport].lp_devname, optarg,
3247c478bd9Sstevel@tonic-gate 			    MAXNAMELEN) >= MAXNAMELEN) {
3257c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
3267c478bd9Sstevel@tonic-gate 				    gettext("%s: device name too long\n"),
3277c478bd9Sstevel@tonic-gate 				    progname);
3287c478bd9Sstevel@tonic-gate 				exit(1);
3297c478bd9Sstevel@tonic-gate 			}
3307c478bd9Sstevel@tonic-gate 
3317c478bd9Sstevel@tonic-gate 			nport++;
3327c478bd9Sstevel@tonic-gate 			break;
3337c478bd9Sstevel@tonic-gate 		case 'P':
3347c478bd9Sstevel@tonic-gate 			if (P_arg) {
3357c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
3367c478bd9Sstevel@tonic-gate 				    "%s: the option -P cannot be specified "
3377c478bd9Sstevel@tonic-gate 				    "more than once\n"), progname);
3387c478bd9Sstevel@tonic-gate 				usage();
3397c478bd9Sstevel@tonic-gate 			}
3407c478bd9Sstevel@tonic-gate 
3417c478bd9Sstevel@tonic-gate 			P_arg = B_TRUE;
3427c478bd9Sstevel@tonic-gate 
3437c478bd9Sstevel@tonic-gate 			if (!laadm_str_to_policy(optarg, &policy)) {
3447c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
3457c478bd9Sstevel@tonic-gate 				    gettext("%s: invalid policy '%s'\n"),
3467c478bd9Sstevel@tonic-gate 				    progname, optarg);
3477c478bd9Sstevel@tonic-gate 				exit(1);
3487c478bd9Sstevel@tonic-gate 			}
3497c478bd9Sstevel@tonic-gate 			break;
3507c478bd9Sstevel@tonic-gate 		case 'u':
3517c478bd9Sstevel@tonic-gate 			if (u_arg) {
3527c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
3537c478bd9Sstevel@tonic-gate 				    "%s: the option -u cannot be specified "
3547c478bd9Sstevel@tonic-gate 				    "more than once\n"), progname);
3557c478bd9Sstevel@tonic-gate 				usage();
3567c478bd9Sstevel@tonic-gate 			}
3577c478bd9Sstevel@tonic-gate 
3587c478bd9Sstevel@tonic-gate 			u_arg = B_TRUE;
3597c478bd9Sstevel@tonic-gate 
3607c478bd9Sstevel@tonic-gate 			if (!laadm_str_to_mac_addr(optarg, &mac_addr_fixed,
3617c478bd9Sstevel@tonic-gate 			    mac_addr)) {
3627c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
3637c478bd9Sstevel@tonic-gate 				    gettext("%s: invalid MAC address '%s'\n"),
3647c478bd9Sstevel@tonic-gate 				    progname, optarg);
3657c478bd9Sstevel@tonic-gate 				exit(1);
3667c478bd9Sstevel@tonic-gate 			}
3677c478bd9Sstevel@tonic-gate 
3687c478bd9Sstevel@tonic-gate 			break;
3697c478bd9Sstevel@tonic-gate 		case 'l':
3707c478bd9Sstevel@tonic-gate 			if (l_arg) {
3717c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
3727c478bd9Sstevel@tonic-gate 				    "%s: the option -l cannot be specified "
3737c478bd9Sstevel@tonic-gate 				    "more than once\n"), progname);
3747c478bd9Sstevel@tonic-gate 				usage();
3757c478bd9Sstevel@tonic-gate 			}
3767c478bd9Sstevel@tonic-gate 
3777c478bd9Sstevel@tonic-gate 			l_arg = B_TRUE;
3787c478bd9Sstevel@tonic-gate 
3797c478bd9Sstevel@tonic-gate 			if (!laadm_str_to_lacp_mode(optarg, &lacp_mode)) {
3807c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
3817c478bd9Sstevel@tonic-gate 				    gettext("%s: invalid LACP mode '%s'\n"),
3827c478bd9Sstevel@tonic-gate 				    progname, optarg);
3837c478bd9Sstevel@tonic-gate 				exit(1);
3847c478bd9Sstevel@tonic-gate 			}
3857c478bd9Sstevel@tonic-gate 
3867c478bd9Sstevel@tonic-gate 			break;
3877c478bd9Sstevel@tonic-gate 		case 'T':
3887c478bd9Sstevel@tonic-gate 			if (T_arg) {
3897c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
3907c478bd9Sstevel@tonic-gate 				    "%s: the option -T cannot be specified "
3917c478bd9Sstevel@tonic-gate 				    "more than once\n"), progname);
3927c478bd9Sstevel@tonic-gate 				usage();
3937c478bd9Sstevel@tonic-gate 			}
3947c478bd9Sstevel@tonic-gate 
3957c478bd9Sstevel@tonic-gate 			T_arg = B_TRUE;
3967c478bd9Sstevel@tonic-gate 
3977c478bd9Sstevel@tonic-gate 			if (!laadm_str_to_lacp_timer(optarg, &lacp_timer)) {
3987c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
3997c478bd9Sstevel@tonic-gate 				    gettext("%s: invalid LACP timer value"
4007c478bd9Sstevel@tonic-gate 				    " '%s'\n"),
4017c478bd9Sstevel@tonic-gate 				    progname, optarg);
4027c478bd9Sstevel@tonic-gate 				exit(1);
4037c478bd9Sstevel@tonic-gate 			}
4047c478bd9Sstevel@tonic-gate 
4057c478bd9Sstevel@tonic-gate 			break;
4067c478bd9Sstevel@tonic-gate 		case 't':
4077c478bd9Sstevel@tonic-gate 			t_arg = B_TRUE;
4087c478bd9Sstevel@tonic-gate 			break;
4097c478bd9Sstevel@tonic-gate 		case 'R':
4107c478bd9Sstevel@tonic-gate 			altroot = optarg;
4117c478bd9Sstevel@tonic-gate 			break;
4127c478bd9Sstevel@tonic-gate 		case ':':
4137c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
4147c478bd9Sstevel@tonic-gate 			    gettext("%s: option requires a value '-%c'\n"),
4157c478bd9Sstevel@tonic-gate 			    progname, optopt);
4167c478bd9Sstevel@tonic-gate 			exit(1);
4177c478bd9Sstevel@tonic-gate 			/*NOTREACHED*/
4187c478bd9Sstevel@tonic-gate 		case '?':
4197c478bd9Sstevel@tonic-gate 		default:
4207c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
4217c478bd9Sstevel@tonic-gate 			    gettext("%s: unrecognized option '-%c'\n"),
4227c478bd9Sstevel@tonic-gate 			    progname, optopt);
4237c478bd9Sstevel@tonic-gate 			exit(1);
4247c478bd9Sstevel@tonic-gate 		}
4257c478bd9Sstevel@tonic-gate 	}
4267c478bd9Sstevel@tonic-gate 
4277c478bd9Sstevel@tonic-gate 	if (nport == 0)
4287c478bd9Sstevel@tonic-gate 		usage();
4297c478bd9Sstevel@tonic-gate 
4307c478bd9Sstevel@tonic-gate 	/* get key value (required last argument) */
4317c478bd9Sstevel@tonic-gate 	if (optind != (argc-1))
4327c478bd9Sstevel@tonic-gate 		usage();
4337c478bd9Sstevel@tonic-gate 
4347c478bd9Sstevel@tonic-gate 	errno = 0;
4357c478bd9Sstevel@tonic-gate 	key = (int)strtol(argv[optind], &endp, 10);
4367c478bd9Sstevel@tonic-gate 	if (errno != 0 || key < 1 || *endp != '\0') {
4377c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
4387c478bd9Sstevel@tonic-gate 		    gettext("%s: illegal key value '%d'\n"),
4397c478bd9Sstevel@tonic-gate 		    progname, key);
4407c478bd9Sstevel@tonic-gate 		exit(1);
4417c478bd9Sstevel@tonic-gate 	}
4427c478bd9Sstevel@tonic-gate 
4437c478bd9Sstevel@tonic-gate 	if (laadm_create(key, nport, port, policy, mac_addr_fixed,
4447c478bd9Sstevel@tonic-gate 	    mac_addr, lacp_mode, lacp_timer, t_arg, altroot, &diag) < 0) {
4457c478bd9Sstevel@tonic-gate 		PRINT_ERR_DIAG("%s: create operation failed: %s", diag,
4467c478bd9Sstevel@tonic-gate 		    laadm_diag);
4477c478bd9Sstevel@tonic-gate 		exit(1);
4487c478bd9Sstevel@tonic-gate 	}
4497c478bd9Sstevel@tonic-gate }
4507c478bd9Sstevel@tonic-gate 
4517c478bd9Sstevel@tonic-gate static void
4527c478bd9Sstevel@tonic-gate do_delete_aggr(int argc, char *argv[])
4537c478bd9Sstevel@tonic-gate {
4547c478bd9Sstevel@tonic-gate 	uint16_t		key;
4557c478bd9Sstevel@tonic-gate 	char			option;
4567c478bd9Sstevel@tonic-gate 	boolean_t		t_arg = B_FALSE;
4577c478bd9Sstevel@tonic-gate 	char			*altroot = NULL;
4587c478bd9Sstevel@tonic-gate 	char			*endp = NULL;
4597c478bd9Sstevel@tonic-gate 	laadm_diag_t		diag = 0;
4607c478bd9Sstevel@tonic-gate 
4617c478bd9Sstevel@tonic-gate 	opterr = 0;
4627c478bd9Sstevel@tonic-gate 	while ((option = getopt_long(argc, argv, ":R:t", longopts,
4637c478bd9Sstevel@tonic-gate 	    NULL)) != -1) {
4647c478bd9Sstevel@tonic-gate 		switch (option) {
4657c478bd9Sstevel@tonic-gate 
4667c478bd9Sstevel@tonic-gate 		case 't':
4677c478bd9Sstevel@tonic-gate 			t_arg = B_TRUE;
4687c478bd9Sstevel@tonic-gate 			break;
4697c478bd9Sstevel@tonic-gate 		case 'R':
4707c478bd9Sstevel@tonic-gate 			altroot = optarg;
4717c478bd9Sstevel@tonic-gate 			break;
4727c478bd9Sstevel@tonic-gate 		case ':':
4737c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
4747c478bd9Sstevel@tonic-gate 			    gettext("%s: option requires a value '-%c'\n"),
4757c478bd9Sstevel@tonic-gate 			    progname, optopt);
4767c478bd9Sstevel@tonic-gate 			exit(1);
4777c478bd9Sstevel@tonic-gate 			break;
4787c478bd9Sstevel@tonic-gate 		case '?':
4797c478bd9Sstevel@tonic-gate 		default:
4807c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
4817c478bd9Sstevel@tonic-gate 			    gettext("%s: unrecognized option '-%c'\n"),
4827c478bd9Sstevel@tonic-gate 			    progname, optopt);
4837c478bd9Sstevel@tonic-gate 			exit(1);
4847c478bd9Sstevel@tonic-gate 			break;
4857c478bd9Sstevel@tonic-gate 		}
4867c478bd9Sstevel@tonic-gate 	}
4877c478bd9Sstevel@tonic-gate 
4887c478bd9Sstevel@tonic-gate 	/* get key value (required last argument) */
4897c478bd9Sstevel@tonic-gate 	if (optind != (argc-1))
4907c478bd9Sstevel@tonic-gate 		usage();
4917c478bd9Sstevel@tonic-gate 
4927c478bd9Sstevel@tonic-gate 	errno = 0;
4937c478bd9Sstevel@tonic-gate 	key = (int)strtol(argv[optind], &endp, 10);
4947c478bd9Sstevel@tonic-gate 	if (errno != 0 || key < 1 || *endp != '\0') {
4957c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
4967c478bd9Sstevel@tonic-gate 		    gettext("%s: illegal key value '%d'\n"),
4977c478bd9Sstevel@tonic-gate 		    progname, key);
4987c478bd9Sstevel@tonic-gate 		exit(1);
4997c478bd9Sstevel@tonic-gate 	}
5007c478bd9Sstevel@tonic-gate 
5017c478bd9Sstevel@tonic-gate 	if (laadm_delete(key, t_arg, altroot, &diag) < 0) {
5027c478bd9Sstevel@tonic-gate 		PRINT_ERR_DIAG("%s: delete operation failed: %s", diag,
5037c478bd9Sstevel@tonic-gate 		    laadm_diag);
5047c478bd9Sstevel@tonic-gate 		exit(1);
5057c478bd9Sstevel@tonic-gate 	}
5067c478bd9Sstevel@tonic-gate }
5077c478bd9Sstevel@tonic-gate 
5087c478bd9Sstevel@tonic-gate static void
5097c478bd9Sstevel@tonic-gate do_add_aggr(int argc, char *argv[])
5107c478bd9Sstevel@tonic-gate {
5117c478bd9Sstevel@tonic-gate 	char			option;
5127c478bd9Sstevel@tonic-gate 	uint16_t		key;
5137c478bd9Sstevel@tonic-gate 	laadm_port_attr_db_t	port[MAXPORT];
5147c478bd9Sstevel@tonic-gate 	uint_t			nport = 0;
5157c478bd9Sstevel@tonic-gate 	boolean_t		t_arg = B_FALSE;
5167c478bd9Sstevel@tonic-gate 	char			*altroot = NULL;
5177c478bd9Sstevel@tonic-gate 	char			*endp = NULL;
5187c478bd9Sstevel@tonic-gate 	laadm_diag_t		diag = 0;
5197c478bd9Sstevel@tonic-gate 
5207c478bd9Sstevel@tonic-gate 	opterr = 0;
5217c478bd9Sstevel@tonic-gate 	while ((option = getopt_long(argc, argv, ":d:R:t", longopts,
5227c478bd9Sstevel@tonic-gate 	    NULL)) != -1) {
5237c478bd9Sstevel@tonic-gate 		switch (option) {
5247c478bd9Sstevel@tonic-gate 		case 'd':
5257c478bd9Sstevel@tonic-gate 			if (nport >= MAXPORT) {
5267c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
5277c478bd9Sstevel@tonic-gate 				    gettext("%s: too many <dev> arguments\n"),
5287c478bd9Sstevel@tonic-gate 				    progname);
5297c478bd9Sstevel@tonic-gate 				exit(1);
5307c478bd9Sstevel@tonic-gate 			}
5317c478bd9Sstevel@tonic-gate 
5327c478bd9Sstevel@tonic-gate 			if (strlcpy(port[nport].lp_devname, optarg,
5337c478bd9Sstevel@tonic-gate 			    MAXNAMELEN) >= MAXNAMELEN) {
5347c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
5357c478bd9Sstevel@tonic-gate 				    gettext("%s: device name too long\n"),
5367c478bd9Sstevel@tonic-gate 				    progname);
5377c478bd9Sstevel@tonic-gate 				exit(1);
5387c478bd9Sstevel@tonic-gate 			}
5397c478bd9Sstevel@tonic-gate 			nport++;
5407c478bd9Sstevel@tonic-gate 			break;
5417c478bd9Sstevel@tonic-gate 		case 't':
5427c478bd9Sstevel@tonic-gate 			t_arg = B_TRUE;
5437c478bd9Sstevel@tonic-gate 			break;
5447c478bd9Sstevel@tonic-gate 		case 'R':
5457c478bd9Sstevel@tonic-gate 			altroot = optarg;
5467c478bd9Sstevel@tonic-gate 			break;
5477c478bd9Sstevel@tonic-gate 		case ':':
5487c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
5497c478bd9Sstevel@tonic-gate 			    gettext("%s: option requires a value '-%c'\n"),
5507c478bd9Sstevel@tonic-gate 			    progname, optopt);
5517c478bd9Sstevel@tonic-gate 			exit(1);
5527c478bd9Sstevel@tonic-gate 			/*NOTREACHED*/
5537c478bd9Sstevel@tonic-gate 		case '?':
5547c478bd9Sstevel@tonic-gate 		default:
5557c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
5567c478bd9Sstevel@tonic-gate 			    gettext("%s: unrecognized option '-%c'\n"),
5577c478bd9Sstevel@tonic-gate 			    progname, optopt);
5587c478bd9Sstevel@tonic-gate 			exit(1);
5597c478bd9Sstevel@tonic-gate 		}
5607c478bd9Sstevel@tonic-gate 	}
5617c478bd9Sstevel@tonic-gate 
5627c478bd9Sstevel@tonic-gate 	if (nport == 0)
5637c478bd9Sstevel@tonic-gate 		usage();
5647c478bd9Sstevel@tonic-gate 
5657c478bd9Sstevel@tonic-gate 	/* get key value (required last argument) */
5667c478bd9Sstevel@tonic-gate 	if (optind != (argc-1))
5677c478bd9Sstevel@tonic-gate 		usage();
5687c478bd9Sstevel@tonic-gate 
5697c478bd9Sstevel@tonic-gate 	errno = 0;
5707c478bd9Sstevel@tonic-gate 	key = (int)strtol(argv[optind], &endp, 10);
5717c478bd9Sstevel@tonic-gate 	if (errno != 0 || key < 1 || *endp != '\0') {
5727c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
5737c478bd9Sstevel@tonic-gate 		    gettext("%s: illegal key value '%d'\n"),
5747c478bd9Sstevel@tonic-gate 		    progname, key);
5757c478bd9Sstevel@tonic-gate 		exit(1);
5767c478bd9Sstevel@tonic-gate 	}
5777c478bd9Sstevel@tonic-gate 
5787c478bd9Sstevel@tonic-gate 	if (laadm_add(key, nport, port, t_arg, altroot, &diag) < 0) {
579219a2a31Shl157128 		/*
580219a2a31Shl157128 		 * checking ENOTSUP is a temporary workaround
581219a2a31Shl157128 		 * and should be removed once 6399681 is fixed.
582219a2a31Shl157128 		 */
583219a2a31Shl157128 		if (errno == ENOTSUP) {
584219a2a31Shl157128 			(void) fprintf(stderr,
585219a2a31Shl157128 			    gettext("%s: add operation failed: %s\n"),
586219a2a31Shl157128 			    progname,
587219a2a31Shl157128 			    gettext("device capabilities don't match"));
588219a2a31Shl157128 			exit(ENOTSUP);
589219a2a31Shl157128 		}
5907c478bd9Sstevel@tonic-gate 		PRINT_ERR_DIAG("%s: add operation failed: %s", diag,
5917c478bd9Sstevel@tonic-gate 		    laadm_diag);
5927c478bd9Sstevel@tonic-gate 		exit(1);
5937c478bd9Sstevel@tonic-gate 	}
5947c478bd9Sstevel@tonic-gate }
5957c478bd9Sstevel@tonic-gate 
5967c478bd9Sstevel@tonic-gate static void
5977c478bd9Sstevel@tonic-gate do_remove_aggr(int argc, char *argv[])
5987c478bd9Sstevel@tonic-gate {
5997c478bd9Sstevel@tonic-gate 	char			option;
6007c478bd9Sstevel@tonic-gate 	uint16_t		key;
6017c478bd9Sstevel@tonic-gate 	laadm_port_attr_db_t	port[MAXPORT];
6027c478bd9Sstevel@tonic-gate 	uint_t			nport = 0;
6037c478bd9Sstevel@tonic-gate 	boolean_t		t_arg = B_FALSE;
6047c478bd9Sstevel@tonic-gate 	char			*altroot = NULL;
6057c478bd9Sstevel@tonic-gate 	char			*endp = NULL;
6067c478bd9Sstevel@tonic-gate 	laadm_diag_t		diag = 0;
6077c478bd9Sstevel@tonic-gate 
6087c478bd9Sstevel@tonic-gate 	opterr = 0;
6097c478bd9Sstevel@tonic-gate 	while ((option = getopt_long(argc, argv, ":d:R:t",
6107c478bd9Sstevel@tonic-gate 	    longopts, NULL)) != -1) {
6117c478bd9Sstevel@tonic-gate 		switch (option) {
6127c478bd9Sstevel@tonic-gate 		case 'd':
6137c478bd9Sstevel@tonic-gate 			if (nport >= MAXPORT) {
6147c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
6157c478bd9Sstevel@tonic-gate 				    gettext("%s: too many <dev> arguments\n"),
6167c478bd9Sstevel@tonic-gate 				    progname);
6177c478bd9Sstevel@tonic-gate 				exit(1);
6187c478bd9Sstevel@tonic-gate 			}
6197c478bd9Sstevel@tonic-gate 
6207c478bd9Sstevel@tonic-gate 			if (strlcpy(port[nport].lp_devname, optarg,
6217c478bd9Sstevel@tonic-gate 			    MAXNAMELEN) >= MAXNAMELEN) {
6227c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
6237c478bd9Sstevel@tonic-gate 				    gettext("%s: device name too long\n"),
6247c478bd9Sstevel@tonic-gate 				    progname);
6257c478bd9Sstevel@tonic-gate 				exit(1);
6267c478bd9Sstevel@tonic-gate 			}
6277c478bd9Sstevel@tonic-gate 			nport++;
6287c478bd9Sstevel@tonic-gate 			break;
6297c478bd9Sstevel@tonic-gate 		case 't':
6307c478bd9Sstevel@tonic-gate 			t_arg = B_TRUE;
6317c478bd9Sstevel@tonic-gate 			break;
6327c478bd9Sstevel@tonic-gate 		case 'R':
6337c478bd9Sstevel@tonic-gate 			altroot = optarg;
6347c478bd9Sstevel@tonic-gate 			break;
6357c478bd9Sstevel@tonic-gate 		case ':':
6367c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
6377c478bd9Sstevel@tonic-gate 			    gettext("%s: option requires a value '-%c'\n"),
6387c478bd9Sstevel@tonic-gate 			    progname, optopt);
6397c478bd9Sstevel@tonic-gate 			exit(1);
6407c478bd9Sstevel@tonic-gate 			/*NOTREACHED*/
6417c478bd9Sstevel@tonic-gate 		case '?':
6427c478bd9Sstevel@tonic-gate 		default:
6437c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
6447c478bd9Sstevel@tonic-gate 			    gettext("%s: unrecognized option '-%c'\n"),
6457c478bd9Sstevel@tonic-gate 			    progname, optopt);
6467c478bd9Sstevel@tonic-gate 			exit(1);
6477c478bd9Sstevel@tonic-gate 		}
6487c478bd9Sstevel@tonic-gate 	}
6497c478bd9Sstevel@tonic-gate 
6507c478bd9Sstevel@tonic-gate 	if (nport == 0)
6517c478bd9Sstevel@tonic-gate 		usage();
6527c478bd9Sstevel@tonic-gate 
6537c478bd9Sstevel@tonic-gate 	/* get key value (required last argument) */
6547c478bd9Sstevel@tonic-gate 	if (optind != (argc-1))
6557c478bd9Sstevel@tonic-gate 		usage();
6567c478bd9Sstevel@tonic-gate 
6577c478bd9Sstevel@tonic-gate 	errno = 0;
6587c478bd9Sstevel@tonic-gate 	key = (int)strtol(argv[optind], &endp, 10);
6597c478bd9Sstevel@tonic-gate 	if (errno != 0 || key < 1 || *endp != '\0') {
6607c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
6617c478bd9Sstevel@tonic-gate 		    gettext("%s: illegal key value '%d'\n"),
6627c478bd9Sstevel@tonic-gate 		    progname, key);
6637c478bd9Sstevel@tonic-gate 		exit(1);
6647c478bd9Sstevel@tonic-gate 	}
6657c478bd9Sstevel@tonic-gate 
6667c478bd9Sstevel@tonic-gate 	if (laadm_remove(key, nport, port, t_arg, altroot, &diag) < 0) {
6677c478bd9Sstevel@tonic-gate 		PRINT_ERR_DIAG("%s: remove operation failed: %s", diag,
6687c478bd9Sstevel@tonic-gate 		    laadm_diag);
6697c478bd9Sstevel@tonic-gate 		exit(1);
6707c478bd9Sstevel@tonic-gate 	}
6717c478bd9Sstevel@tonic-gate }
6727c478bd9Sstevel@tonic-gate 
6737c478bd9Sstevel@tonic-gate static void
6747c478bd9Sstevel@tonic-gate do_modify_aggr(int argc, char *argv[])
6757c478bd9Sstevel@tonic-gate {
6767c478bd9Sstevel@tonic-gate 	char			option;
6777c478bd9Sstevel@tonic-gate 	uint16_t		key;
6787c478bd9Sstevel@tonic-gate 	uint32_t		policy = AGGR_POLICY_L4;
6797c478bd9Sstevel@tonic-gate 	aggr_lacp_mode_t	lacp_mode = AGGR_LACP_OFF;
6807c478bd9Sstevel@tonic-gate 	aggr_lacp_timer_t	lacp_timer = AGGR_LACP_TIMER_SHORT;
6817c478bd9Sstevel@tonic-gate 	uint8_t			mac_addr[ETHERADDRL];
6827c478bd9Sstevel@tonic-gate 	boolean_t		mac_addr_fixed = B_FALSE;
6837c478bd9Sstevel@tonic-gate 	uint8_t			modify_mask = 0;
6847c478bd9Sstevel@tonic-gate 	boolean_t		t_arg = B_FALSE;
6857c478bd9Sstevel@tonic-gate 	char			*altroot = NULL;
6867c478bd9Sstevel@tonic-gate 	char			*endp = NULL;
6877c478bd9Sstevel@tonic-gate 	laadm_diag_t		diag = 0;
6887c478bd9Sstevel@tonic-gate 
6897c478bd9Sstevel@tonic-gate 	opterr = 0;
6907c478bd9Sstevel@tonic-gate 	while ((option = getopt_long(argc, argv, ":l:P:R:tu:T:", longopts,
6917c478bd9Sstevel@tonic-gate 	    NULL)) != -1) {
6927c478bd9Sstevel@tonic-gate 		switch (option) {
6937c478bd9Sstevel@tonic-gate 		case 'P':
6947c478bd9Sstevel@tonic-gate 			if (modify_mask & LAADM_MODIFY_POLICY) {
6957c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
6967c478bd9Sstevel@tonic-gate 				    "%s: the option -P cannot be specified "
6977c478bd9Sstevel@tonic-gate 				    "more than once\n"), progname);
6987c478bd9Sstevel@tonic-gate 				usage();
6997c478bd9Sstevel@tonic-gate 			}
7007c478bd9Sstevel@tonic-gate 
7017c478bd9Sstevel@tonic-gate 			modify_mask |= LAADM_MODIFY_POLICY;
7027c478bd9Sstevel@tonic-gate 
7037c478bd9Sstevel@tonic-gate 			if (!laadm_str_to_policy(optarg, &policy)) {
7047c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
7057c478bd9Sstevel@tonic-gate 				    gettext("%s: invalid policy '%s'\n"),
7067c478bd9Sstevel@tonic-gate 				    progname, optarg);
7077c478bd9Sstevel@tonic-gate 				exit(1);
7087c478bd9Sstevel@tonic-gate 			}
7097c478bd9Sstevel@tonic-gate 			break;
7107c478bd9Sstevel@tonic-gate 		case 'u':
7117c478bd9Sstevel@tonic-gate 			if (modify_mask & LAADM_MODIFY_MAC) {
7127c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
7137c478bd9Sstevel@tonic-gate 				    "%s: the option -u cannot be specified "
7147c478bd9Sstevel@tonic-gate 				    "more than once\n"), progname);
7157c478bd9Sstevel@tonic-gate 				usage();
7167c478bd9Sstevel@tonic-gate 			}
7177c478bd9Sstevel@tonic-gate 
7187c478bd9Sstevel@tonic-gate 			modify_mask |= LAADM_MODIFY_MAC;
7197c478bd9Sstevel@tonic-gate 
7207c478bd9Sstevel@tonic-gate 			if (!laadm_str_to_mac_addr(optarg, &mac_addr_fixed,
7217c478bd9Sstevel@tonic-gate 			    mac_addr)) {
7227c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
7237c478bd9Sstevel@tonic-gate 				    gettext("%s: invalid MAC address '%s'\n"),
7247c478bd9Sstevel@tonic-gate 				    progname, optarg);
7257c478bd9Sstevel@tonic-gate 				exit(1);
7267c478bd9Sstevel@tonic-gate 			}
7277c478bd9Sstevel@tonic-gate 
7287c478bd9Sstevel@tonic-gate 			break;
7297c478bd9Sstevel@tonic-gate 		case 'l':
7307c478bd9Sstevel@tonic-gate 			if (modify_mask & LAADM_MODIFY_LACP_MODE) {
7317c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
7327c478bd9Sstevel@tonic-gate 				    "%s: the option -l cannot be specified "
7337c478bd9Sstevel@tonic-gate 				    "more than once\n"), progname);
7347c478bd9Sstevel@tonic-gate 				usage();
7357c478bd9Sstevel@tonic-gate 			}
7367c478bd9Sstevel@tonic-gate 
7377c478bd9Sstevel@tonic-gate 			modify_mask |= LAADM_MODIFY_LACP_MODE;
7387c478bd9Sstevel@tonic-gate 
7397c478bd9Sstevel@tonic-gate 			if (!laadm_str_to_lacp_mode(optarg, &lacp_mode)) {
7407c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
7417c478bd9Sstevel@tonic-gate 				    gettext("%s: invalid LACP mode '%s'\n"),
7427c478bd9Sstevel@tonic-gate 				    progname, optarg);
7437c478bd9Sstevel@tonic-gate 				exit(1);
7447c478bd9Sstevel@tonic-gate 			}
7457c478bd9Sstevel@tonic-gate 
7467c478bd9Sstevel@tonic-gate 			break;
7477c478bd9Sstevel@tonic-gate 		case 'T':
7487c478bd9Sstevel@tonic-gate 			if (modify_mask & LAADM_MODIFY_LACP_TIMER) {
7497c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
7507c478bd9Sstevel@tonic-gate 				    "%s: the option -T cannot be specified "
7517c478bd9Sstevel@tonic-gate 				    "more than once\n"), progname);
7527c478bd9Sstevel@tonic-gate 				usage();
7537c478bd9Sstevel@tonic-gate 			}
7547c478bd9Sstevel@tonic-gate 
7557c478bd9Sstevel@tonic-gate 			modify_mask |= LAADM_MODIFY_LACP_TIMER;
7567c478bd9Sstevel@tonic-gate 
7577c478bd9Sstevel@tonic-gate 			if (!laadm_str_to_lacp_timer(optarg, &lacp_timer)) {
7587c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
7597c478bd9Sstevel@tonic-gate 				    gettext("%s: invalid LACP timer value"
7607c478bd9Sstevel@tonic-gate 				    " '%s'\n"),
7617c478bd9Sstevel@tonic-gate 				    progname, optarg);
7627c478bd9Sstevel@tonic-gate 				exit(1);
7637c478bd9Sstevel@tonic-gate 			}
7647c478bd9Sstevel@tonic-gate 
7657c478bd9Sstevel@tonic-gate 			break;
7667c478bd9Sstevel@tonic-gate 		case 't':
7677c478bd9Sstevel@tonic-gate 			t_arg = B_TRUE;
7687c478bd9Sstevel@tonic-gate 			break;
7697c478bd9Sstevel@tonic-gate 		case 'R':
7707c478bd9Sstevel@tonic-gate 			altroot = optarg;
7717c478bd9Sstevel@tonic-gate 			break;
7727c478bd9Sstevel@tonic-gate 		case ':':
7737c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
7747c478bd9Sstevel@tonic-gate 			    gettext("%s: option requires a value '-%c'\n"),
7757c478bd9Sstevel@tonic-gate 			    progname, optopt);
7767c478bd9Sstevel@tonic-gate 			exit(1);
7777c478bd9Sstevel@tonic-gate 			/*NOTREACHED*/
7787c478bd9Sstevel@tonic-gate 		case '?':
7797c478bd9Sstevel@tonic-gate 		default:
7807c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
7817c478bd9Sstevel@tonic-gate 			    gettext("%s: unrecognized option '-%c'\n"),
7827c478bd9Sstevel@tonic-gate 			    progname, optopt);
7837c478bd9Sstevel@tonic-gate 			exit(1);
7847c478bd9Sstevel@tonic-gate 		}
7857c478bd9Sstevel@tonic-gate 	}
7867c478bd9Sstevel@tonic-gate 
7877c478bd9Sstevel@tonic-gate 	if (modify_mask == 0) {
7887c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s: at least one of the "
7897c478bd9Sstevel@tonic-gate 		    "-PulT options must be specified\n"), progname);
7907c478bd9Sstevel@tonic-gate 		usage();
7917c478bd9Sstevel@tonic-gate 	}
7927c478bd9Sstevel@tonic-gate 
7937c478bd9Sstevel@tonic-gate 	/* get key value (required last argument) */
7947c478bd9Sstevel@tonic-gate 	if (optind != (argc-1))
7957c478bd9Sstevel@tonic-gate 		usage();
7967c478bd9Sstevel@tonic-gate 
7977c478bd9Sstevel@tonic-gate 	errno = 0;
7987c478bd9Sstevel@tonic-gate 	key = (int)strtol(argv[optind], &endp, 10);
7997c478bd9Sstevel@tonic-gate 	if (errno != 0 || key < 1 || *endp != '\0') {
8007c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
8017c478bd9Sstevel@tonic-gate 		    gettext("%s: illegal key value '%d'\n"),
8027c478bd9Sstevel@tonic-gate 		    progname, key);
8037c478bd9Sstevel@tonic-gate 		exit(1);
8047c478bd9Sstevel@tonic-gate 	}
8057c478bd9Sstevel@tonic-gate 
8067c478bd9Sstevel@tonic-gate 
8077c478bd9Sstevel@tonic-gate 	if (laadm_modify(key, modify_mask, policy, mac_addr_fixed, mac_addr,
8087c478bd9Sstevel@tonic-gate 	    lacp_mode, lacp_timer, t_arg, altroot, &diag) < 0) {
8097c478bd9Sstevel@tonic-gate 		PRINT_ERR_DIAG("%s: modify operation failed: %s", diag,
8107c478bd9Sstevel@tonic-gate 		    laadm_diag);
8117c478bd9Sstevel@tonic-gate 		exit(1);
8127c478bd9Sstevel@tonic-gate 	}
8137c478bd9Sstevel@tonic-gate }
8147c478bd9Sstevel@tonic-gate 
8157c478bd9Sstevel@tonic-gate static void
8167c478bd9Sstevel@tonic-gate do_up_aggr(int argc, char *argv[])
8177c478bd9Sstevel@tonic-gate {
8187c478bd9Sstevel@tonic-gate 	uint16_t	key = 0;
8197c478bd9Sstevel@tonic-gate 	char		*endp = NULL;
8207c478bd9Sstevel@tonic-gate 	laadm_diag_t	diag = 0;
8217c478bd9Sstevel@tonic-gate 
8227c478bd9Sstevel@tonic-gate 	/* get aggregation key (optional last argument) */
8237c478bd9Sstevel@tonic-gate 	if (argc == 2) {
8247c478bd9Sstevel@tonic-gate 		errno = 0;
8257c478bd9Sstevel@tonic-gate 		key = (int)strtol(argv[1], &endp, 10);
8267c478bd9Sstevel@tonic-gate 		if (errno != 0 || key < 1 || *endp != '\0') {
8277c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
8287c478bd9Sstevel@tonic-gate 			    gettext("%s: illegal key value '%d'\n"),
8297c478bd9Sstevel@tonic-gate 			    progname, key);
8307c478bd9Sstevel@tonic-gate 			exit(1);
8317c478bd9Sstevel@tonic-gate 		}
8327c478bd9Sstevel@tonic-gate 	} else if (argc > 2) {
8337c478bd9Sstevel@tonic-gate 		usage();
8347c478bd9Sstevel@tonic-gate 	}
8357c478bd9Sstevel@tonic-gate 
8367c478bd9Sstevel@tonic-gate 	if (laadm_up(key, NULL, &diag) < 0) {
8377c478bd9Sstevel@tonic-gate 		if (key != 0) {
8387c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
8397c478bd9Sstevel@tonic-gate 			    gettext("%s: could not bring up aggregation"
8407c478bd9Sstevel@tonic-gate 			    " '%u' : %s"), progname, key, strerror(errno));
8417c478bd9Sstevel@tonic-gate 			if (diag != 0)
8427c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, " (%s)",
8437c478bd9Sstevel@tonic-gate 				    laadm_diag(diag));
8447c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "\n");
8457c478bd9Sstevel@tonic-gate 		} else {
8467c478bd9Sstevel@tonic-gate 			PRINT_ERR_DIAG(
8477c478bd9Sstevel@tonic-gate 			    "%s: could not bring aggregations up: %s",
8487c478bd9Sstevel@tonic-gate 			    diag, laadm_diag);
8497c478bd9Sstevel@tonic-gate 		}
8507c478bd9Sstevel@tonic-gate 		exit(1);
8517c478bd9Sstevel@tonic-gate 	}
8527c478bd9Sstevel@tonic-gate }
8537c478bd9Sstevel@tonic-gate 
8547c478bd9Sstevel@tonic-gate static void
8557c478bd9Sstevel@tonic-gate do_down_aggr(int argc, char *argv[])
8567c478bd9Sstevel@tonic-gate {
8577c478bd9Sstevel@tonic-gate 	uint16_t	key = 0;
8587c478bd9Sstevel@tonic-gate 	char		*endp = NULL;
8597c478bd9Sstevel@tonic-gate 
8607c478bd9Sstevel@tonic-gate 	/* get aggregation key (optional last argument) */
8617c478bd9Sstevel@tonic-gate 	if (argc == 2) {
8627c478bd9Sstevel@tonic-gate 		errno = 0;
8637c478bd9Sstevel@tonic-gate 		key = (int)strtol(argv[1], &endp, 10);
8647c478bd9Sstevel@tonic-gate 		if (errno != 0 || key < 1 || *endp != '\0') {
8657c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
8667c478bd9Sstevel@tonic-gate 			    gettext("%s: illegal key value '%d'\n"),
8677c478bd9Sstevel@tonic-gate 			    progname, key);
8687c478bd9Sstevel@tonic-gate 			exit(1);
8697c478bd9Sstevel@tonic-gate 		}
8707c478bd9Sstevel@tonic-gate 	} else if (argc > 2) {
8717c478bd9Sstevel@tonic-gate 		usage();
8727c478bd9Sstevel@tonic-gate 	}
8737c478bd9Sstevel@tonic-gate 
8747c478bd9Sstevel@tonic-gate 	if (laadm_down(key) < 0) {
8757c478bd9Sstevel@tonic-gate 		if (key != 0) {
8767c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
8777c478bd9Sstevel@tonic-gate 			    gettext("%s: could not bring aggregation"
8787c478bd9Sstevel@tonic-gate 			    " down '%u' : %s"),
8797c478bd9Sstevel@tonic-gate 			    progname, key, strerror(errno));
8807c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "\n");
8817c478bd9Sstevel@tonic-gate 		} else {
8827c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
8837c478bd9Sstevel@tonic-gate 			    gettext("%s: could not bring aggregations"
8847c478bd9Sstevel@tonic-gate 			    " down: %s"), progname, strerror(errno));
8857c478bd9Sstevel@tonic-gate 		}
8867c478bd9Sstevel@tonic-gate 		exit(1);
8877c478bd9Sstevel@tonic-gate 	}
8887c478bd9Sstevel@tonic-gate }
8897c478bd9Sstevel@tonic-gate 
8907c478bd9Sstevel@tonic-gate #define	TYPE_WIDTH	10
891210db224Sericheng 
892210db224Sericheng static void
893210db224Sericheng print_link_parseable(const char *name, dladm_attr_t *dap, boolean_t legacy)
894210db224Sericheng {
895210db224Sericheng 	char		type[TYPE_WIDTH];
896210db224Sericheng 
897210db224Sericheng 	if (!legacy) {
898ba2e4443Sseb 		char	drv[LIFNAMSIZ];
899ba2e4443Sseb 		int	instance;
900ba2e4443Sseb 
901210db224Sericheng 		if (dap->da_vid != 0) {
902210db224Sericheng 			(void) snprintf(type, TYPE_WIDTH, "vlan %u",
903210db224Sericheng 			    dap->da_vid);
904210db224Sericheng 		} else {
905210db224Sericheng 			(void) snprintf(type, TYPE_WIDTH, "non-vlan");
906210db224Sericheng 		}
907ba2e4443Sseb 		if (dlpi_if_parse(dap->da_dev, drv, &instance) != 0)
908ba2e4443Sseb 			return;
909ba2e4443Sseb 		if (strncmp(drv, AGGR_DRV, sizeof (AGGR_DRV)) == 0) {
910210db224Sericheng 			(void) printf("%s type=%s mtu=%d key=%u\n",
911ba2e4443Sseb 			    name, type, dap->da_max_sdu, instance);
912210db224Sericheng 		} else {
913210db224Sericheng 			(void) printf("%s type=%s mtu=%d device=%s\n",
914210db224Sericheng 			    name, type, dap->da_max_sdu, dap->da_dev);
915210db224Sericheng 		}
916210db224Sericheng 	} else {
917210db224Sericheng 		(void) printf("%s type=legacy mtu=%d device=%s\n",
918210db224Sericheng 		    name, dap->da_max_sdu, name);
919210db224Sericheng 	}
920210db224Sericheng }
921210db224Sericheng 
922210db224Sericheng static void
923210db224Sericheng print_link(const char *name, dladm_attr_t *dap, boolean_t legacy)
924210db224Sericheng {
925210db224Sericheng 	char		type[TYPE_WIDTH];
926210db224Sericheng 
927210db224Sericheng 	if (!legacy) {
928ba2e4443Sseb 		char drv[LIFNAMSIZ];
929ba2e4443Sseb 		int instance;
930ba2e4443Sseb 
931210db224Sericheng 		if (dap->da_vid != 0) {
932210db224Sericheng 			(void) snprintf(type, TYPE_WIDTH, gettext("vlan %u"),
933210db224Sericheng 			    dap->da_vid);
934210db224Sericheng 		} else {
935210db224Sericheng 			(void) snprintf(type, TYPE_WIDTH, gettext("non-vlan"));
936210db224Sericheng 		}
937ba2e4443Sseb 		if (dlpi_if_parse(dap->da_dev, drv, &instance) != 0)
938ba2e4443Sseb 			return;
939ba2e4443Sseb 		if (strncmp(drv, AGGR_DRV, sizeof (AGGR_DRV)) == 0) {
940210db224Sericheng 			(void) printf(gettext("%-9s\ttype: %s\tmtu: %d"
941210db224Sericheng 			    "\taggregation: key %u\n"), name, type,
942ba2e4443Sseb 			    dap->da_max_sdu, instance);
943210db224Sericheng 		} else {
944210db224Sericheng 			(void) printf(gettext("%-9s\ttype: %s\tmtu: "
945210db224Sericheng 			    "%d\tdevice: %s\n"), name, type, dap->da_max_sdu,
946210db224Sericheng 			    dap->da_dev);
947210db224Sericheng 		}
948210db224Sericheng 	} else {
949210db224Sericheng 		(void) printf(gettext("%-9s\ttype: legacy\tmtu: "
950210db224Sericheng 		    "%d\tdevice: %s\n"), name, dap->da_max_sdu, name);
951210db224Sericheng 	}
952210db224Sericheng }
953210db224Sericheng 
954210db224Sericheng static int
955210db224Sericheng get_if_info(const char *name, dladm_attr_t *dlattrp, boolean_t *legacy)
956210db224Sericheng {
957210db224Sericheng 	int	err;
958210db224Sericheng 
959210db224Sericheng 	if ((err = dladm_info(name, dlattrp)) == 0) {
960210db224Sericheng 		*legacy = B_FALSE;
961210db224Sericheng 	} else if (err < 0 && errno == ENODEV) {
962210db224Sericheng 		int		fd;
963210db224Sericheng 		dlpi_if_attr_t	dia;
964210db224Sericheng 		dl_info_ack_t	dlia;
965210db224Sericheng 
966210db224Sericheng 		/*
967210db224Sericheng 		 * A return value of ENODEV means that the specified
968210db224Sericheng 		 * device is not gldv3.
969210db224Sericheng 		 */
970210db224Sericheng 		if ((fd = dlpi_if_open(name, &dia, B_FALSE)) != -1 &&
971210db224Sericheng 		    dlpi_info(fd, -1, &dlia, NULL, NULL, NULL, NULL,
972210db224Sericheng 		    NULL, NULL) != -1) {
973210db224Sericheng 			(void) dlpi_close(fd);
974210db224Sericheng 
975210db224Sericheng 			*legacy = B_TRUE;
976210db224Sericheng 			bzero(dlattrp, sizeof (*dlattrp));
977210db224Sericheng 			dlattrp->da_max_sdu = (uint_t)dlia.dl_max_sdu;
978210db224Sericheng 		} else {
979210db224Sericheng 			errno = ENOENT;
980210db224Sericheng 			return (-1);
981210db224Sericheng 		}
982210db224Sericheng 	} else {
983210db224Sericheng 		/*
984210db224Sericheng 		 * If the return value is not ENODEV, this means that
985210db224Sericheng 		 * user is either passing in a bogus interface name
986210db224Sericheng 		 * or a vlan interface name that doesn't exist yet.
987210db224Sericheng 		 */
988210db224Sericheng 		errno = ENOENT;
989210db224Sericheng 		return (-1);
990210db224Sericheng 	}
991210db224Sericheng 	return (0);
992210db224Sericheng }
9937c478bd9Sstevel@tonic-gate 
9947c478bd9Sstevel@tonic-gate /* ARGSUSED */
9957c478bd9Sstevel@tonic-gate static void
9967c478bd9Sstevel@tonic-gate show_link(void *arg, const char *name)
9977c478bd9Sstevel@tonic-gate {
9987c478bd9Sstevel@tonic-gate 	dladm_attr_t	dlattr;
999210db224Sericheng 	boolean_t	legacy = B_TRUE;
10007c478bd9Sstevel@tonic-gate 	show_link_state_t *state = (show_link_state_t *)arg;
10017c478bd9Sstevel@tonic-gate 
1002210db224Sericheng 	if (get_if_info(name, &dlattr, &legacy) < 0) {
1003210db224Sericheng 		(void) fprintf(stderr, gettext("%s: invalid device '%s'\n"),
10047c478bd9Sstevel@tonic-gate 		    progname, name);
10057c478bd9Sstevel@tonic-gate 		exit(1);
10067c478bd9Sstevel@tonic-gate 	}
10077c478bd9Sstevel@tonic-gate 
1008210db224Sericheng 	if (state->ls_parseable) {
1009210db224Sericheng 		print_link_parseable(name, &dlattr, legacy);
10107c478bd9Sstevel@tonic-gate 	} else {
1011210db224Sericheng 		print_link(name, &dlattr, legacy);
10127c478bd9Sstevel@tonic-gate 	}
10137c478bd9Sstevel@tonic-gate }
10147c478bd9Sstevel@tonic-gate 
10157c478bd9Sstevel@tonic-gate static void
10167c478bd9Sstevel@tonic-gate show_link_stats(void *arg, const char *name)
10177c478bd9Sstevel@tonic-gate {
10187c478bd9Sstevel@tonic-gate 	show_link_state_t *state = (show_link_state_t *)arg;
10197c478bd9Sstevel@tonic-gate 	pktsum_t stats, diff_stats;
10207c478bd9Sstevel@tonic-gate 
10217c478bd9Sstevel@tonic-gate 	if (state->ls_firstonly) {
10227c478bd9Sstevel@tonic-gate 		if (state->ls_donefirst)
10237c478bd9Sstevel@tonic-gate 			return;
10247c478bd9Sstevel@tonic-gate 		state->ls_donefirst = B_TRUE;
10257c478bd9Sstevel@tonic-gate 	} else {
10267c478bd9Sstevel@tonic-gate 		bzero(&state->ls_prevstats, sizeof (state->ls_prevstats));
10277c478bd9Sstevel@tonic-gate 	}
10287c478bd9Sstevel@tonic-gate 
10297c478bd9Sstevel@tonic-gate 	get_link_stats(name, &stats);
10307c478bd9Sstevel@tonic-gate 	stats_diff(&diff_stats, &stats, &state->ls_prevstats);
10317c478bd9Sstevel@tonic-gate 
10327c478bd9Sstevel@tonic-gate 	(void) printf("%s", name);
10337c478bd9Sstevel@tonic-gate 	(void) printf("\t\t%-10llu", diff_stats.ipackets);
10347c478bd9Sstevel@tonic-gate 	(void) printf("%-12llu", diff_stats.rbytes);
10357c478bd9Sstevel@tonic-gate 	(void) printf("%-8u", diff_stats.ierrors);
10367c478bd9Sstevel@tonic-gate 	(void) printf("%-10llu", diff_stats.opackets);
10377c478bd9Sstevel@tonic-gate 	(void) printf("%-12llu", diff_stats.obytes);
10387c478bd9Sstevel@tonic-gate 	(void) printf("%-8u\n", diff_stats.oerrors);
10397c478bd9Sstevel@tonic-gate 
10407c478bd9Sstevel@tonic-gate 	state->ls_prevstats = stats;
10417c478bd9Sstevel@tonic-gate }
10427c478bd9Sstevel@tonic-gate 
10437c478bd9Sstevel@tonic-gate static void
10447c478bd9Sstevel@tonic-gate dump_grp(laadm_grp_attr_sys_t	*grp, boolean_t parseable)
10457c478bd9Sstevel@tonic-gate {
10467c478bd9Sstevel@tonic-gate 	char policy_str[LAADM_POLICY_STR_LEN];
10477c478bd9Sstevel@tonic-gate 	char addr_str[ETHERADDRL * 3];
10487c478bd9Sstevel@tonic-gate 
10497c478bd9Sstevel@tonic-gate 	if (!parseable) {
10507c478bd9Sstevel@tonic-gate 		(void) printf(gettext("key: %d (0x%04x)"),
10517c478bd9Sstevel@tonic-gate 		    grp->lg_key, grp->lg_key);
10527c478bd9Sstevel@tonic-gate 
10537c478bd9Sstevel@tonic-gate 		(void) printf(gettext("\tpolicy: %s"),
10547c478bd9Sstevel@tonic-gate 		    laadm_policy_to_str(grp->lg_policy, policy_str));
10557c478bd9Sstevel@tonic-gate 
10567c478bd9Sstevel@tonic-gate 		(void) printf(gettext("\taddress: %s (%s)\n"),
10577c478bd9Sstevel@tonic-gate 		    laadm_mac_addr_to_str(grp->lg_mac, addr_str),
10587c478bd9Sstevel@tonic-gate 		    (grp->lg_mac_fixed) ? gettext("fixed") : gettext("auto"));
10597c478bd9Sstevel@tonic-gate 	} else {
10607c478bd9Sstevel@tonic-gate 		(void) printf("aggr key=%d", grp->lg_key);
10617c478bd9Sstevel@tonic-gate 
10627c478bd9Sstevel@tonic-gate 		(void) printf(" policy=%s",
10637c478bd9Sstevel@tonic-gate 		    laadm_policy_to_str(grp->lg_policy, policy_str));
10647c478bd9Sstevel@tonic-gate 
10657c478bd9Sstevel@tonic-gate 		(void) printf(" address=%s",
10667c478bd9Sstevel@tonic-gate 		    laadm_mac_addr_to_str(grp->lg_mac, addr_str));
10677c478bd9Sstevel@tonic-gate 
10687c478bd9Sstevel@tonic-gate 		(void) printf(" address-type=%s\n",
10697c478bd9Sstevel@tonic-gate 		    (grp->lg_mac_fixed) ? "fixed" : "auto");
10707c478bd9Sstevel@tonic-gate 	}
10717c478bd9Sstevel@tonic-gate }
10727c478bd9Sstevel@tonic-gate 
10737c478bd9Sstevel@tonic-gate static void
10747c478bd9Sstevel@tonic-gate dump_grp_lacp(laadm_grp_attr_sys_t *grp, boolean_t parseable)
10757c478bd9Sstevel@tonic-gate {
10767c478bd9Sstevel@tonic-gate 	const char *lacp_mode_str = laadm_lacp_mode_to_str(grp->lg_lacp_mode);
10777c478bd9Sstevel@tonic-gate 	const char *lacp_timer_str =
10787c478bd9Sstevel@tonic-gate 	    laadm_lacp_timer_to_str(grp->lg_lacp_timer);
10797c478bd9Sstevel@tonic-gate 
10807c478bd9Sstevel@tonic-gate 	if (!parseable) {
10817c478bd9Sstevel@tonic-gate 		(void) printf(gettext("\t\tLACP mode: %s"), lacp_mode_str);
10827c478bd9Sstevel@tonic-gate 		(void) printf(gettext("\tLACP timer: %s\n"), lacp_timer_str);
10837c478bd9Sstevel@tonic-gate 	} else {
10847c478bd9Sstevel@tonic-gate 		(void) printf(" lacp-mode=%s", lacp_mode_str);
10857c478bd9Sstevel@tonic-gate 		(void) printf(" lacp-timer=%s\n", lacp_timer_str);
10867c478bd9Sstevel@tonic-gate 	}
10877c478bd9Sstevel@tonic-gate }
10887c478bd9Sstevel@tonic-gate 
10897c478bd9Sstevel@tonic-gate static void
10907c478bd9Sstevel@tonic-gate dump_grp_stats(laadm_grp_attr_sys_t *grp)
10917c478bd9Sstevel@tonic-gate {
10927c478bd9Sstevel@tonic-gate 	(void) printf("key: %d", grp->lg_key);
10937c478bd9Sstevel@tonic-gate 	(void) printf("\tipackets  rbytes      opackets	 obytes		 ");
10947c478bd9Sstevel@tonic-gate 	(void) printf("%%ipkts	%%opkts\n");
10957c478bd9Sstevel@tonic-gate }
10967c478bd9Sstevel@tonic-gate 
10977c478bd9Sstevel@tonic-gate static void
10987c478bd9Sstevel@tonic-gate dump_ports_lacp_head(void)
10997c478bd9Sstevel@tonic-gate {
11007c478bd9Sstevel@tonic-gate 	(void) printf(DUMP_LACP_FORMAT, gettext("device"), gettext("activity"),
11017c478bd9Sstevel@tonic-gate 	    gettext("timeout"), gettext("aggregatable"), gettext("sync"),
11027c478bd9Sstevel@tonic-gate 	    gettext("coll"), gettext("dist"), gettext("defaulted"),
11037c478bd9Sstevel@tonic-gate 	    gettext("expired"));
11047c478bd9Sstevel@tonic-gate }
11057c478bd9Sstevel@tonic-gate 
11067c478bd9Sstevel@tonic-gate static void
11077c478bd9Sstevel@tonic-gate dump_ports_head(void)
11087c478bd9Sstevel@tonic-gate {
11097c478bd9Sstevel@tonic-gate 	(void) printf(gettext("	   device\taddress\t\t	speed\t\tduplex\tlink\t"
11107c478bd9Sstevel@tonic-gate 	    "state\n"));
11117c478bd9Sstevel@tonic-gate }
11127c478bd9Sstevel@tonic-gate 
11137c478bd9Sstevel@tonic-gate static char *
11147c478bd9Sstevel@tonic-gate port_state_to_str(aggr_port_state_t state_num)
11157c478bd9Sstevel@tonic-gate {
11167c478bd9Sstevel@tonic-gate 	int			i;
11177c478bd9Sstevel@tonic-gate 	port_state_t		*state;
11187c478bd9Sstevel@tonic-gate 
11197c478bd9Sstevel@tonic-gate 	for (i = 0; i < NPORTSTATES; i++) {
11207c478bd9Sstevel@tonic-gate 		state = &port_states[i];
11217c478bd9Sstevel@tonic-gate 		if (state->state_num == state_num)
11227c478bd9Sstevel@tonic-gate 			return (state->state_name);
11237c478bd9Sstevel@tonic-gate 	}
11247c478bd9Sstevel@tonic-gate 
11257c478bd9Sstevel@tonic-gate 	return ("unknown");
11267c478bd9Sstevel@tonic-gate }
11277c478bd9Sstevel@tonic-gate 
11287c478bd9Sstevel@tonic-gate static void
11297c478bd9Sstevel@tonic-gate dump_port(laadm_port_attr_sys_t *port, boolean_t parseable)
11307c478bd9Sstevel@tonic-gate {
11317c478bd9Sstevel@tonic-gate 	char *dev = port->lp_devname;
11327c478bd9Sstevel@tonic-gate 	char buf[ETHERADDRL * 3];
11337c478bd9Sstevel@tonic-gate 
11347c478bd9Sstevel@tonic-gate 	if (!parseable) {
11357c478bd9Sstevel@tonic-gate 		(void) printf("	   %-9s\t%s", dev, laadm_mac_addr_to_str(
11367c478bd9Sstevel@tonic-gate 		    port->lp_mac, buf));
1137ba2e4443Sseb 		(void) printf("\t  %-5u Mbps", (int)(mac_ifspeed(dev) /
11387c478bd9Sstevel@tonic-gate 		    1000000ull));
1139ba2e4443Sseb 		(void) printf("\t%s", mac_link_duplex(dev));
1140ba2e4443Sseb 		(void) printf("\t%s", mac_link_state(dev));
11417c478bd9Sstevel@tonic-gate 		(void) printf("\t%s\n", port_state_to_str(port->lp_state));
11427c478bd9Sstevel@tonic-gate 
11437c478bd9Sstevel@tonic-gate 	} else {
11447c478bd9Sstevel@tonic-gate 		(void) printf(" device=%s address=%s", dev,
11457c478bd9Sstevel@tonic-gate 		    laadm_mac_addr_to_str(port->lp_mac, buf));
1146ba2e4443Sseb 		(void) printf(" speed=%u", (int)(mac_ifspeed(dev) /
11477c478bd9Sstevel@tonic-gate 		    1000000ull));
1148ba2e4443Sseb 		(void) printf(" duplex=%s", mac_link_duplex(dev));
1149ba2e4443Sseb 		(void) printf(" link=%s", mac_link_state(dev));
11507c478bd9Sstevel@tonic-gate 		(void) printf(" port=%s", port_state_to_str(port->lp_state));
11517c478bd9Sstevel@tonic-gate 	}
11527c478bd9Sstevel@tonic-gate }
11537c478bd9Sstevel@tonic-gate 
11547c478bd9Sstevel@tonic-gate static void
11557c478bd9Sstevel@tonic-gate dump_port_lacp(laadm_port_attr_sys_t *port)
11567c478bd9Sstevel@tonic-gate {
11577c478bd9Sstevel@tonic-gate 	aggr_lacp_state_t *state = &port->lp_lacp_state;
11587c478bd9Sstevel@tonic-gate 
11597c478bd9Sstevel@tonic-gate 	(void) printf(DUMP_LACP_FORMAT,
11607c478bd9Sstevel@tonic-gate 	    port->lp_devname, state->bit.activity ? "active" : "passive",
11617c478bd9Sstevel@tonic-gate 	    state->bit.timeout ? "short" : "long",
11627c478bd9Sstevel@tonic-gate 	    state->bit.aggregation ? "yes" : "no",
11637c478bd9Sstevel@tonic-gate 	    state->bit.sync ? "yes" : "no",
11647c478bd9Sstevel@tonic-gate 	    state->bit.collecting ? "yes" : "no",
11657c478bd9Sstevel@tonic-gate 	    state->bit.distributing ? "yes" : "no",
11667c478bd9Sstevel@tonic-gate 	    state->bit.defaulted ? "yes" : "no",
11677c478bd9Sstevel@tonic-gate 	    state->bit.expired ? "yes" : "no");
11687c478bd9Sstevel@tonic-gate }
11697c478bd9Sstevel@tonic-gate 
11707c478bd9Sstevel@tonic-gate static void
11717c478bd9Sstevel@tonic-gate dump_port_stat(int index, show_grp_state_t *state, pktsum_t *port_stats,
11727c478bd9Sstevel@tonic-gate     pktsum_t *tot_stats)
11737c478bd9Sstevel@tonic-gate {
11747c478bd9Sstevel@tonic-gate 	pktsum_t	diff_stats;
11757c478bd9Sstevel@tonic-gate 	pktsum_t	*old_stats = &state->gs_prevstats[index];
11767c478bd9Sstevel@tonic-gate 
11777c478bd9Sstevel@tonic-gate 	stats_diff(&diff_stats, port_stats, old_stats);
11787c478bd9Sstevel@tonic-gate 
11797c478bd9Sstevel@tonic-gate 	(void) printf("\t%-10llu", diff_stats.ipackets);
11807c478bd9Sstevel@tonic-gate 	(void) printf("%-12llu", diff_stats.rbytes);
11817c478bd9Sstevel@tonic-gate 	(void) printf("%-10llu", diff_stats.opackets);
11827c478bd9Sstevel@tonic-gate 	(void) printf("%-12llu", diff_stats.obytes);
11837c478bd9Sstevel@tonic-gate 
11847c478bd9Sstevel@tonic-gate 	if (tot_stats->ipackets == 0)
11857c478bd9Sstevel@tonic-gate 		(void) printf("\t-");
11867c478bd9Sstevel@tonic-gate 	else
11877c478bd9Sstevel@tonic-gate 		(void) printf("\t%-6.1f", (double)diff_stats.ipackets/
11887c478bd9Sstevel@tonic-gate 		    (double)tot_stats->ipackets * 100);
11897c478bd9Sstevel@tonic-gate 
11907c478bd9Sstevel@tonic-gate 	if (tot_stats->opackets == 0)
11917c478bd9Sstevel@tonic-gate 		(void) printf("\t-");
11927c478bd9Sstevel@tonic-gate 	else
11937c478bd9Sstevel@tonic-gate 		(void) printf("\t%-6.1f", (double)diff_stats.opackets/
11947c478bd9Sstevel@tonic-gate 		    (double)tot_stats->opackets * 100);
11957c478bd9Sstevel@tonic-gate 
11967c478bd9Sstevel@tonic-gate 	(void) printf("\n");
11977c478bd9Sstevel@tonic-gate 
11987c478bd9Sstevel@tonic-gate 	*old_stats = *port_stats;
11997c478bd9Sstevel@tonic-gate }
12007c478bd9Sstevel@tonic-gate 
12017c478bd9Sstevel@tonic-gate static int
12027c478bd9Sstevel@tonic-gate show_key(void *arg, laadm_grp_attr_sys_t *grp)
12037c478bd9Sstevel@tonic-gate {
12047c478bd9Sstevel@tonic-gate 	show_grp_state_t	*state = (show_grp_state_t *)arg;
12057c478bd9Sstevel@tonic-gate 	int			i;
12067c478bd9Sstevel@tonic-gate 	pktsum_t		pktsumtot, port_stat;
12077c478bd9Sstevel@tonic-gate 
12087c478bd9Sstevel@tonic-gate 	if (state->gs_key != 0 && state->gs_key != grp->lg_key)
12097c478bd9Sstevel@tonic-gate 		return (0);
12107c478bd9Sstevel@tonic-gate 	if (state->gs_firstonly) {
12117c478bd9Sstevel@tonic-gate 		if (state->gs_found)
12127c478bd9Sstevel@tonic-gate 			return (0);
12137c478bd9Sstevel@tonic-gate 	} else {
12147c478bd9Sstevel@tonic-gate 		bzero(&state->gs_prevstats, sizeof (state->gs_prevstats));
12157c478bd9Sstevel@tonic-gate 	}
12167c478bd9Sstevel@tonic-gate 
12177c478bd9Sstevel@tonic-gate 	state->gs_found = B_TRUE;
12187c478bd9Sstevel@tonic-gate 
12197c478bd9Sstevel@tonic-gate 	if (state->gs_stats) {
12207c478bd9Sstevel@tonic-gate 		/* show statistics */
12217c478bd9Sstevel@tonic-gate 		dump_grp_stats(grp);
12227c478bd9Sstevel@tonic-gate 
12237c478bd9Sstevel@tonic-gate 		/* sum the ports statistics */
12247c478bd9Sstevel@tonic-gate 		bzero(&pktsumtot, sizeof (pktsumtot));
12257c478bd9Sstevel@tonic-gate 		for (i = 0; i < grp->lg_nports; i++) {
1226ba2e4443Sseb 			get_mac_stats(grp->lg_ports[i].lp_devname, &port_stat);
12277c478bd9Sstevel@tonic-gate 			stats_total(&pktsumtot, &port_stat,
12287c478bd9Sstevel@tonic-gate 			    &state->gs_prevstats[i]);
12297c478bd9Sstevel@tonic-gate 		}
12307c478bd9Sstevel@tonic-gate 
12317c478bd9Sstevel@tonic-gate 		(void) printf("	   Total");
12327c478bd9Sstevel@tonic-gate 		(void) printf("\t%-10llu", pktsumtot.ipackets);
12337c478bd9Sstevel@tonic-gate 		(void) printf("%-12llu", pktsumtot.rbytes);
12347c478bd9Sstevel@tonic-gate 		(void) printf("%-10llu", pktsumtot.opackets);
12357c478bd9Sstevel@tonic-gate 		(void) printf("%-12llu\n", pktsumtot.obytes);
12367c478bd9Sstevel@tonic-gate 
12377c478bd9Sstevel@tonic-gate 		for (i = 0; i < grp->lg_nports; i++) {
1238ba2e4443Sseb 			get_mac_stats(grp->lg_ports[i].lp_devname, &port_stat);
12397c478bd9Sstevel@tonic-gate 			(void) printf("	   %s", grp->lg_ports[i].lp_devname);
12407c478bd9Sstevel@tonic-gate 			dump_port_stat(i, state, &port_stat, &pktsumtot);
12417c478bd9Sstevel@tonic-gate 		}
12427c478bd9Sstevel@tonic-gate 	} else if (state->gs_lacp) {
12437c478bd9Sstevel@tonic-gate 		/* show LACP info */
12447c478bd9Sstevel@tonic-gate 		dump_grp(grp, state->gs_parseable);
12457c478bd9Sstevel@tonic-gate 		dump_grp_lacp(grp, state->gs_parseable);
12467c478bd9Sstevel@tonic-gate 		dump_ports_lacp_head();
12477c478bd9Sstevel@tonic-gate 		for (i = 0; i < grp->lg_nports; i++)
12487c478bd9Sstevel@tonic-gate 			dump_port_lacp(&grp->lg_ports[i]);
12497c478bd9Sstevel@tonic-gate 	} else {
12507c478bd9Sstevel@tonic-gate 		dump_grp(grp, state->gs_parseable);
12517c478bd9Sstevel@tonic-gate 		if (!state->gs_parseable)
12527c478bd9Sstevel@tonic-gate 			dump_ports_head();
12537c478bd9Sstevel@tonic-gate 		for (i = 0; i < grp->lg_nports; i++) {
12547c478bd9Sstevel@tonic-gate 			if (state->gs_parseable)
12557c478bd9Sstevel@tonic-gate 				(void) printf("dev key=%d", grp->lg_key);
12567c478bd9Sstevel@tonic-gate 			dump_port(&grp->lg_ports[i], state->gs_parseable);
12577c478bd9Sstevel@tonic-gate 			if (state->gs_parseable)
12587c478bd9Sstevel@tonic-gate 				(void) printf("\n");
12597c478bd9Sstevel@tonic-gate 		}
12607c478bd9Sstevel@tonic-gate 	}
12617c478bd9Sstevel@tonic-gate 
12627c478bd9Sstevel@tonic-gate 	return (0);
12637c478bd9Sstevel@tonic-gate }
12647c478bd9Sstevel@tonic-gate 
12657c478bd9Sstevel@tonic-gate static int
12667c478bd9Sstevel@tonic-gate kstat_value(kstat_t *ksp, const char *name, uint8_t type, void *buf)
12677c478bd9Sstevel@tonic-gate {
12687c478bd9Sstevel@tonic-gate 	kstat_named_t	*knp;
12697c478bd9Sstevel@tonic-gate 
12707c478bd9Sstevel@tonic-gate 	if ((knp = kstat_data_lookup(ksp, (char *)name)) == NULL)
12717c478bd9Sstevel@tonic-gate 		return (-1);
12727c478bd9Sstevel@tonic-gate 
12737c478bd9Sstevel@tonic-gate 	if (knp->data_type != type)
12747c478bd9Sstevel@tonic-gate 		return (-1);
12757c478bd9Sstevel@tonic-gate 
12767c478bd9Sstevel@tonic-gate 	switch (type) {
12777c478bd9Sstevel@tonic-gate 	case KSTAT_DATA_UINT64:
12787c478bd9Sstevel@tonic-gate 		*(uint64_t *)buf = knp->value.ui64;
12797c478bd9Sstevel@tonic-gate 		break;
12807c478bd9Sstevel@tonic-gate 	case KSTAT_DATA_UINT32:
12817c478bd9Sstevel@tonic-gate 		*(uint32_t *)buf = knp->value.ui32;
12827c478bd9Sstevel@tonic-gate 		break;
12837c478bd9Sstevel@tonic-gate 	default:
12847c478bd9Sstevel@tonic-gate 		return (-1);
12857c478bd9Sstevel@tonic-gate 	}
12867c478bd9Sstevel@tonic-gate 
12877c478bd9Sstevel@tonic-gate 	return (0);
12887c478bd9Sstevel@tonic-gate }
12897c478bd9Sstevel@tonic-gate 
12907c478bd9Sstevel@tonic-gate static void
1291210db224Sericheng show_dev(void *arg, const char *dev)
12927c478bd9Sstevel@tonic-gate {
12937c478bd9Sstevel@tonic-gate 	show_mac_state_t *state = (show_mac_state_t *)arg;
12947c478bd9Sstevel@tonic-gate 
12957c478bd9Sstevel@tonic-gate 	(void) printf("%s", dev);
12967c478bd9Sstevel@tonic-gate 
12977c478bd9Sstevel@tonic-gate 	if (!state->ms_parseable) {
12987c478bd9Sstevel@tonic-gate 		(void) printf(gettext("\t\tlink: %s"),
1299ba2e4443Sseb 		    mac_link_state(dev));
13007c478bd9Sstevel@tonic-gate 		(void) printf(gettext("\tspeed: %-5u Mbps"),
1301ba2e4443Sseb 		    (unsigned int)(mac_ifspeed(dev) / 1000000ull));
13027c478bd9Sstevel@tonic-gate 		(void) printf(gettext("\tduplex: %s\n"),
1303ba2e4443Sseb 		    mac_link_duplex(dev));
13047c478bd9Sstevel@tonic-gate 	} else {
1305ba2e4443Sseb 		(void) printf(" link=%s", mac_link_state(dev));
13067c478bd9Sstevel@tonic-gate 		(void) printf(" speed=%u",
1307ba2e4443Sseb 		    (unsigned int)(mac_ifspeed(dev) / 1000000ull));
1308ba2e4443Sseb 		(void) printf(" duplex=%s\n", mac_link_duplex(dev));
13097c478bd9Sstevel@tonic-gate 	}
13107c478bd9Sstevel@tonic-gate }
13117c478bd9Sstevel@tonic-gate 
13127c478bd9Sstevel@tonic-gate /*ARGSUSED*/
13137c478bd9Sstevel@tonic-gate static void
1314210db224Sericheng show_dev_stats(void *arg, const char *dev)
13157c478bd9Sstevel@tonic-gate {
13167c478bd9Sstevel@tonic-gate 	show_mac_state_t *state = (show_mac_state_t *)arg;
13177c478bd9Sstevel@tonic-gate 	pktsum_t stats, diff_stats;
13187c478bd9Sstevel@tonic-gate 
13197c478bd9Sstevel@tonic-gate 	if (state->ms_firstonly) {
13207c478bd9Sstevel@tonic-gate 		if (state->ms_donefirst)
13217c478bd9Sstevel@tonic-gate 			return;
13227c478bd9Sstevel@tonic-gate 		state->ms_donefirst = B_TRUE;
13237c478bd9Sstevel@tonic-gate 	} else {
13247c478bd9Sstevel@tonic-gate 		bzero(&state->ms_prevstats, sizeof (state->ms_prevstats));
13257c478bd9Sstevel@tonic-gate 	}
13267c478bd9Sstevel@tonic-gate 
1327ba2e4443Sseb 	get_mac_stats(dev, &stats);
13287c478bd9Sstevel@tonic-gate 	stats_diff(&diff_stats, &stats, &state->ms_prevstats);
13297c478bd9Sstevel@tonic-gate 
13307c478bd9Sstevel@tonic-gate 	(void) printf("%s", dev);
13317c478bd9Sstevel@tonic-gate 	(void) printf("\t\t%-10llu", diff_stats.ipackets);
13327c478bd9Sstevel@tonic-gate 	(void) printf("%-12llu", diff_stats.rbytes);
13337c478bd9Sstevel@tonic-gate 	(void) printf("%-8u", diff_stats.ierrors);
13347c478bd9Sstevel@tonic-gate 	(void) printf("%-10llu", diff_stats.opackets);
13357c478bd9Sstevel@tonic-gate 	(void) printf("%-12llu", diff_stats.obytes);
13367c478bd9Sstevel@tonic-gate 	(void) printf("%-8u\n", diff_stats.oerrors);
13377c478bd9Sstevel@tonic-gate 
13387c478bd9Sstevel@tonic-gate 	state->ms_prevstats = stats;
13397c478bd9Sstevel@tonic-gate }
13407c478bd9Sstevel@tonic-gate 
13417c478bd9Sstevel@tonic-gate static void
13427c478bd9Sstevel@tonic-gate do_show_link(int argc, char *argv[])
13437c478bd9Sstevel@tonic-gate {
13447c478bd9Sstevel@tonic-gate 	char		*name = NULL;
13457c478bd9Sstevel@tonic-gate 	int		option;
13467c478bd9Sstevel@tonic-gate 	boolean_t	s_arg = B_FALSE;
13477c478bd9Sstevel@tonic-gate 	boolean_t	i_arg = B_FALSE;
13487c478bd9Sstevel@tonic-gate 	uint32_t	interval = 0;
13497c478bd9Sstevel@tonic-gate 	show_link_state_t state;
13507c478bd9Sstevel@tonic-gate 	char		*endp = NULL;
13517c478bd9Sstevel@tonic-gate 
13527c478bd9Sstevel@tonic-gate 	state.ls_stats = B_FALSE;
13537c478bd9Sstevel@tonic-gate 	state.ls_parseable = B_FALSE;
13547c478bd9Sstevel@tonic-gate 
13557c478bd9Sstevel@tonic-gate 	opterr = 0;
13567c478bd9Sstevel@tonic-gate 	while ((option = getopt_long(argc, argv, ":psi:",
13577c478bd9Sstevel@tonic-gate 	    longopts, NULL)) != -1) {
13587c478bd9Sstevel@tonic-gate 		switch (option) {
13597c478bd9Sstevel@tonic-gate 		case 'p':
13607c478bd9Sstevel@tonic-gate 			state.ls_parseable = B_TRUE;
13617c478bd9Sstevel@tonic-gate 			break;
13627c478bd9Sstevel@tonic-gate 		case 's':
13637c478bd9Sstevel@tonic-gate 			if (s_arg) {
13647c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
13657c478bd9Sstevel@tonic-gate 				    "%s: the option -s cannot be specified "
13667c478bd9Sstevel@tonic-gate 				    "more than once\n"), progname);
13677c478bd9Sstevel@tonic-gate 				usage();
13687c478bd9Sstevel@tonic-gate 			}
13697c478bd9Sstevel@tonic-gate 
13707c478bd9Sstevel@tonic-gate 			s_arg = B_TRUE;
13717c478bd9Sstevel@tonic-gate 			break;
13727c478bd9Sstevel@tonic-gate 		case 'i':
13737c478bd9Sstevel@tonic-gate 			if (i_arg) {
13747c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
13757c478bd9Sstevel@tonic-gate 				    "%s: the option -i cannot be specified "
13767c478bd9Sstevel@tonic-gate 				    "more than once\n"), progname);
13777c478bd9Sstevel@tonic-gate 				usage();
13787c478bd9Sstevel@tonic-gate 			}
13797c478bd9Sstevel@tonic-gate 
13807c478bd9Sstevel@tonic-gate 			i_arg = B_TRUE;
13817c478bd9Sstevel@tonic-gate 
13827c478bd9Sstevel@tonic-gate 			errno = 0;
13837c478bd9Sstevel@tonic-gate 			interval = (int)strtol(optarg, &endp, 10);
13847c478bd9Sstevel@tonic-gate 			if (errno != 0 || interval == 0 || *endp != '\0') {
13857c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
13867c478bd9Sstevel@tonic-gate 				    gettext("%s: invalid interval value"
13877c478bd9Sstevel@tonic-gate 				    " '%d'\n"),
13887c478bd9Sstevel@tonic-gate 				    progname, interval);
13897c478bd9Sstevel@tonic-gate 				exit(1);
13907c478bd9Sstevel@tonic-gate 			}
13917c478bd9Sstevel@tonic-gate 			break;
13927c478bd9Sstevel@tonic-gate 		case ':':
13937c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
13947c478bd9Sstevel@tonic-gate 			    gettext("%s: option requires a value '-%c'\n"),
13957c478bd9Sstevel@tonic-gate 			    progname, optopt);
13967c478bd9Sstevel@tonic-gate 			exit(1);
13977c478bd9Sstevel@tonic-gate 			/*NOTREACHED*/
13987c478bd9Sstevel@tonic-gate 		case '?':
13997c478bd9Sstevel@tonic-gate 		default:
14007c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
14017c478bd9Sstevel@tonic-gate 			    gettext("%s: unrecognized option '-%c'\n"),
14027c478bd9Sstevel@tonic-gate 			    progname, optopt);
14037c478bd9Sstevel@tonic-gate 			exit(1);
14047c478bd9Sstevel@tonic-gate 		}
14057c478bd9Sstevel@tonic-gate 	}
14067c478bd9Sstevel@tonic-gate 
14077c478bd9Sstevel@tonic-gate 	if (i_arg && !s_arg) {
14087c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s: the option -i "
14097c478bd9Sstevel@tonic-gate 		    "can be used only with -s\n"), progname);
14107c478bd9Sstevel@tonic-gate 		usage();
14117c478bd9Sstevel@tonic-gate 	}
14127c478bd9Sstevel@tonic-gate 
14137c478bd9Sstevel@tonic-gate 
14147c478bd9Sstevel@tonic-gate 	/* get link name (optional last argument) */
14157c478bd9Sstevel@tonic-gate 	if (optind == (argc-1))
14167c478bd9Sstevel@tonic-gate 		name = argv[optind];
14177c478bd9Sstevel@tonic-gate 	else if (optind != argc)
14187c478bd9Sstevel@tonic-gate 		usage();
14197c478bd9Sstevel@tonic-gate 
14207c478bd9Sstevel@tonic-gate 	if (s_arg) {
14217c478bd9Sstevel@tonic-gate 		link_stats(name, interval);
14227c478bd9Sstevel@tonic-gate 		return;
14237c478bd9Sstevel@tonic-gate 	}
14247c478bd9Sstevel@tonic-gate 
1425210db224Sericheng 	if (name == NULL) {
14267c478bd9Sstevel@tonic-gate 		(void) dladm_walk(show_link, &state);
1427210db224Sericheng 	} else {
14287c478bd9Sstevel@tonic-gate 		show_link(&state, name);
14297c478bd9Sstevel@tonic-gate 	}
1430210db224Sericheng }
14317c478bd9Sstevel@tonic-gate 
14327c478bd9Sstevel@tonic-gate static void
14337c478bd9Sstevel@tonic-gate do_show_aggr(int argc, char *argv[])
14347c478bd9Sstevel@tonic-gate {
14357c478bd9Sstevel@tonic-gate 	int			option;
14367c478bd9Sstevel@tonic-gate 	uint16_t		key = 0;
14377c478bd9Sstevel@tonic-gate 	boolean_t		L_arg = B_FALSE;
14387c478bd9Sstevel@tonic-gate 	boolean_t		s_arg = B_FALSE;
14397c478bd9Sstevel@tonic-gate 	boolean_t		i_arg = B_FALSE;
14407c478bd9Sstevel@tonic-gate 	show_grp_state_t	state;
14417c478bd9Sstevel@tonic-gate 	uint32_t		interval = 0;
14427c478bd9Sstevel@tonic-gate 	char			*endp = NULL;
14437c478bd9Sstevel@tonic-gate 
14447c478bd9Sstevel@tonic-gate 	state.gs_stats = B_FALSE;
14457c478bd9Sstevel@tonic-gate 	state.gs_lacp = B_FALSE;
14467c478bd9Sstevel@tonic-gate 	state.gs_parseable = B_FALSE;
14477c478bd9Sstevel@tonic-gate 
14487c478bd9Sstevel@tonic-gate 	opterr = 0;
14497c478bd9Sstevel@tonic-gate 	while ((option = getopt_long(argc, argv, ":Lpsi:",
14507c478bd9Sstevel@tonic-gate 	    longopts, NULL)) != -1) {
14517c478bd9Sstevel@tonic-gate 		switch (option) {
14527c478bd9Sstevel@tonic-gate 		case 'L':
14537c478bd9Sstevel@tonic-gate 			if (L_arg) {
14547c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
14557c478bd9Sstevel@tonic-gate 				    "%s: the option -L cannot be specified "
14567c478bd9Sstevel@tonic-gate 				    "more than once\n"), progname);
14577c478bd9Sstevel@tonic-gate 				usage();
14587c478bd9Sstevel@tonic-gate 			}
14597c478bd9Sstevel@tonic-gate 
14607c478bd9Sstevel@tonic-gate 			if (s_arg || i_arg) {
14617c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
14627c478bd9Sstevel@tonic-gate 				    "%s: the option -L cannot be used with "
14637c478bd9Sstevel@tonic-gate 				    "any of -is\n"), progname);
14647c478bd9Sstevel@tonic-gate 				usage();
14657c478bd9Sstevel@tonic-gate 			}
14667c478bd9Sstevel@tonic-gate 
14677c478bd9Sstevel@tonic-gate 			L_arg = B_TRUE;
14687c478bd9Sstevel@tonic-gate 
14697c478bd9Sstevel@tonic-gate 			state.gs_lacp = B_TRUE;
14707c478bd9Sstevel@tonic-gate 			break;
14717c478bd9Sstevel@tonic-gate 		case 'p':
14727c478bd9Sstevel@tonic-gate 			state.gs_parseable = B_TRUE;
14737c478bd9Sstevel@tonic-gate 			break;
14747c478bd9Sstevel@tonic-gate 		case 's':
14757c478bd9Sstevel@tonic-gate 			if (s_arg) {
14767c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
14777c478bd9Sstevel@tonic-gate 				    "%s: the option -s cannot be specified "
14787c478bd9Sstevel@tonic-gate 				    "more than once\n"), progname);
14797c478bd9Sstevel@tonic-gate 				usage();
14807c478bd9Sstevel@tonic-gate 			}
14817c478bd9Sstevel@tonic-gate 
14827c478bd9Sstevel@tonic-gate 			if (L_arg) {
14837c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
14847c478bd9Sstevel@tonic-gate 				    "%s: the option -L cannot be used "
14857c478bd9Sstevel@tonic-gate 				    "with -k\n"), progname);
14867c478bd9Sstevel@tonic-gate 				usage();
14877c478bd9Sstevel@tonic-gate 			}
14887c478bd9Sstevel@tonic-gate 
14897c478bd9Sstevel@tonic-gate 			s_arg = B_TRUE;
14907c478bd9Sstevel@tonic-gate 			break;
14917c478bd9Sstevel@tonic-gate 		case 'i':
14927c478bd9Sstevel@tonic-gate 			if (i_arg) {
14937c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
14947c478bd9Sstevel@tonic-gate 				    "%s: the option -i cannot be specified "
14957c478bd9Sstevel@tonic-gate 				    "more than once\n"), progname);
14967c478bd9Sstevel@tonic-gate 				usage();
14977c478bd9Sstevel@tonic-gate 			}
14987c478bd9Sstevel@tonic-gate 
14997c478bd9Sstevel@tonic-gate 			if (L_arg) {
15007c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
15017c478bd9Sstevel@tonic-gate 				    "%s: the option -i cannot be used "
15027c478bd9Sstevel@tonic-gate 				    "with -L\n"), progname);
15037c478bd9Sstevel@tonic-gate 				usage();
15047c478bd9Sstevel@tonic-gate 			}
15057c478bd9Sstevel@tonic-gate 
15067c478bd9Sstevel@tonic-gate 			i_arg = B_TRUE;
15077c478bd9Sstevel@tonic-gate 
15087c478bd9Sstevel@tonic-gate 			errno = 0;
15097c478bd9Sstevel@tonic-gate 			interval = (int)strtol(optarg, &endp, 10);
15107c478bd9Sstevel@tonic-gate 			if (errno != 0 || interval == 0 || *endp != '\0') {
15117c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
15127c478bd9Sstevel@tonic-gate 				    gettext("%s: invalid interval value"
15137c478bd9Sstevel@tonic-gate 				    " '%d'\n"),
15147c478bd9Sstevel@tonic-gate 				    progname, interval);
15157c478bd9Sstevel@tonic-gate 				exit(1);
15167c478bd9Sstevel@tonic-gate 			}
15177c478bd9Sstevel@tonic-gate 			break;
15187c478bd9Sstevel@tonic-gate 		case ':':
15197c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
15207c478bd9Sstevel@tonic-gate 			    gettext("%s: option requires a value '-%c'\n"),
15217c478bd9Sstevel@tonic-gate 			    progname, optopt);
15227c478bd9Sstevel@tonic-gate 			exit(1);
15237c478bd9Sstevel@tonic-gate 			/*NOTREACHED*/
15247c478bd9Sstevel@tonic-gate 		case '?':
15257c478bd9Sstevel@tonic-gate 		default:
15267c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
15277c478bd9Sstevel@tonic-gate 			    gettext("%s: unrecognized option '-%c'\n"),
15287c478bd9Sstevel@tonic-gate 			    progname, optopt);
15297c478bd9Sstevel@tonic-gate 			exit(1);
15307c478bd9Sstevel@tonic-gate 		}
15317c478bd9Sstevel@tonic-gate 	}
15327c478bd9Sstevel@tonic-gate 
15337c478bd9Sstevel@tonic-gate 	if (i_arg && !s_arg) {
15347c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s: the option -i "
15357c478bd9Sstevel@tonic-gate 		    "can be used only with -s\n"), progname);
15367c478bd9Sstevel@tonic-gate 		usage();
15377c478bd9Sstevel@tonic-gate 	}
15387c478bd9Sstevel@tonic-gate 
15397c478bd9Sstevel@tonic-gate 	/* get aggregation key (optional last argument) */
15407c478bd9Sstevel@tonic-gate 	if (optind == (argc-1)) {
15417c478bd9Sstevel@tonic-gate 		errno = 0;
15427c478bd9Sstevel@tonic-gate 		key = (int)strtol(argv[optind], &endp, 10);
15437c478bd9Sstevel@tonic-gate 		if (errno != 0 || key < 1 || *endp != '\0') {
15447c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
15457c478bd9Sstevel@tonic-gate 			    gettext("%s: illegal key value '%d'\n"),
15467c478bd9Sstevel@tonic-gate 			    progname, key);
15477c478bd9Sstevel@tonic-gate 			exit(1);
15487c478bd9Sstevel@tonic-gate 		}
15497c478bd9Sstevel@tonic-gate 	} else if (optind != argc) {
15507c478bd9Sstevel@tonic-gate 		usage();
15517c478bd9Sstevel@tonic-gate 	}
15527c478bd9Sstevel@tonic-gate 
15537c478bd9Sstevel@tonic-gate 	if (s_arg) {
15547c478bd9Sstevel@tonic-gate 		aggr_stats(key, interval);
15557c478bd9Sstevel@tonic-gate 		return;
15567c478bd9Sstevel@tonic-gate 	}
15577c478bd9Sstevel@tonic-gate 
15587c478bd9Sstevel@tonic-gate 	state.gs_key = key;
15597c478bd9Sstevel@tonic-gate 	state.gs_found = B_FALSE;
15607c478bd9Sstevel@tonic-gate 
15617c478bd9Sstevel@tonic-gate 	(void) laadm_walk_sys(show_key, &state);
15627c478bd9Sstevel@tonic-gate 
15637c478bd9Sstevel@tonic-gate 	if (key != 0 && !state.gs_found) {
15647c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
15657c478bd9Sstevel@tonic-gate 		    gettext("%s: non-existent aggregation key '%u'\n"),
15667c478bd9Sstevel@tonic-gate 		    progname, key);
15677c478bd9Sstevel@tonic-gate 		exit(1);
15687c478bd9Sstevel@tonic-gate 	}
15697c478bd9Sstevel@tonic-gate }
15707c478bd9Sstevel@tonic-gate 
15717c478bd9Sstevel@tonic-gate static void
15727c478bd9Sstevel@tonic-gate do_show_dev(int argc, char *argv[])
15737c478bd9Sstevel@tonic-gate {
15747c478bd9Sstevel@tonic-gate 	int		option;
15757c478bd9Sstevel@tonic-gate 	char		*dev = NULL;
15767c478bd9Sstevel@tonic-gate 	boolean_t	s_arg = B_FALSE;
15777c478bd9Sstevel@tonic-gate 	boolean_t	i_arg = B_FALSE;
15787c478bd9Sstevel@tonic-gate 	uint32_t	interval = 0;
15797c478bd9Sstevel@tonic-gate 	show_mac_state_t state;
15807c478bd9Sstevel@tonic-gate 	char		*endp = NULL;
15817c478bd9Sstevel@tonic-gate 
15827c478bd9Sstevel@tonic-gate 	state.ms_parseable = B_FALSE;
15837c478bd9Sstevel@tonic-gate 
15847c478bd9Sstevel@tonic-gate 	opterr = 0;
15857c478bd9Sstevel@tonic-gate 	while ((option = getopt_long(argc, argv, ":psi:",
15867c478bd9Sstevel@tonic-gate 	    longopts, NULL)) != -1) {
15877c478bd9Sstevel@tonic-gate 		switch (option) {
15887c478bd9Sstevel@tonic-gate 		case 'p':
15897c478bd9Sstevel@tonic-gate 			state.ms_parseable = B_TRUE;
15907c478bd9Sstevel@tonic-gate 			break;
15917c478bd9Sstevel@tonic-gate 		case 's':
15927c478bd9Sstevel@tonic-gate 			if (s_arg) {
15937c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
15947c478bd9Sstevel@tonic-gate 				    "%s: the option -s cannot be specified "
15957c478bd9Sstevel@tonic-gate 				    "more than once\n"), progname);
15967c478bd9Sstevel@tonic-gate 				usage();
15977c478bd9Sstevel@tonic-gate 			}
15987c478bd9Sstevel@tonic-gate 
15997c478bd9Sstevel@tonic-gate 			s_arg = B_TRUE;
16007c478bd9Sstevel@tonic-gate 			break;
16017c478bd9Sstevel@tonic-gate 		case 'i':
16027c478bd9Sstevel@tonic-gate 			if (i_arg) {
16037c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
16047c478bd9Sstevel@tonic-gate 				    "%s: the option -i cannot be specified "
16057c478bd9Sstevel@tonic-gate 				    "more than once\n"), progname);
16067c478bd9Sstevel@tonic-gate 				usage();
16077c478bd9Sstevel@tonic-gate 			}
16087c478bd9Sstevel@tonic-gate 
16097c478bd9Sstevel@tonic-gate 			i_arg = B_TRUE;
16107c478bd9Sstevel@tonic-gate 
16117c478bd9Sstevel@tonic-gate 			errno = 0;
16127c478bd9Sstevel@tonic-gate 			interval = (int)strtol(optarg, &endp, 10);
16137c478bd9Sstevel@tonic-gate 			if (errno != 0 || interval == 0 || *endp != '\0') {
16147c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
16157c478bd9Sstevel@tonic-gate 				    gettext("%s: invalid interval value"
16167c478bd9Sstevel@tonic-gate 				    " '%d'\n"),
16177c478bd9Sstevel@tonic-gate 				    progname, interval);
16187c478bd9Sstevel@tonic-gate 				exit(1);
16197c478bd9Sstevel@tonic-gate 			}
16207c478bd9Sstevel@tonic-gate 			break;
16217c478bd9Sstevel@tonic-gate 		case ':':
16227c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
16237c478bd9Sstevel@tonic-gate 			    gettext("%s: option requires a value '-%c'\n"),
16247c478bd9Sstevel@tonic-gate 			    progname, optopt);
16257c478bd9Sstevel@tonic-gate 			exit(1);
16267c478bd9Sstevel@tonic-gate 			/*NOTREACHED*/
16277c478bd9Sstevel@tonic-gate 		case '?':
16287c478bd9Sstevel@tonic-gate 		default:
16297c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
16307c478bd9Sstevel@tonic-gate 			    gettext("%s: unrecognized option '-%c'\n"),
16317c478bd9Sstevel@tonic-gate 			    progname, optopt);
16327c478bd9Sstevel@tonic-gate 			exit(1);
16337c478bd9Sstevel@tonic-gate 		}
16347c478bd9Sstevel@tonic-gate 	}
16357c478bd9Sstevel@tonic-gate 
16367c478bd9Sstevel@tonic-gate 	if (i_arg && !s_arg) {
16377c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s: the option -i "
16387c478bd9Sstevel@tonic-gate 		    "can be used only with -s\n"), progname);
16397c478bd9Sstevel@tonic-gate 		usage();
16407c478bd9Sstevel@tonic-gate 	}
16417c478bd9Sstevel@tonic-gate 
16427c478bd9Sstevel@tonic-gate 	/* get dev name (optional last argument) */
16437c478bd9Sstevel@tonic-gate 	if (optind == (argc-1))
16447c478bd9Sstevel@tonic-gate 		dev = argv[optind];
16457c478bd9Sstevel@tonic-gate 	else if (optind != argc)
16467c478bd9Sstevel@tonic-gate 		usage();
16477c478bd9Sstevel@tonic-gate 
1648cd93090eSericheng 	if (dev != NULL) {
1649cd93090eSericheng 		int		index;
1650cd93090eSericheng 		char		drv[LIFNAMSIZ];
1651cd93090eSericheng 		dladm_attr_t	dlattr;
1652cd93090eSericheng 		boolean_t	legacy;
1653cd93090eSericheng 
1654cd93090eSericheng 		/*
1655cd93090eSericheng 		 * Check for invalid devices.
1656cd93090eSericheng 		 * aggregations and vlans are not considered devices.
1657cd93090eSericheng 		 */
1658cd93090eSericheng 		if (strncmp(dev, "aggr", 4) == 0 ||
1659cd93090eSericheng 		    dlpi_if_parse(dev, drv, &index) < 0 ||
1660cd93090eSericheng 		    index >= 1000 ||
1661cd93090eSericheng 		    get_if_info(dev, &dlattr, &legacy) < 0) {
16627c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
1663cd93090eSericheng 			    gettext("%s: invalid device '%s'\n"),
16647c478bd9Sstevel@tonic-gate 			    progname, dev);
16657c478bd9Sstevel@tonic-gate 			exit(1);
16667c478bd9Sstevel@tonic-gate 		}
1667cd93090eSericheng 	}
16687c478bd9Sstevel@tonic-gate 
16697c478bd9Sstevel@tonic-gate 	if (s_arg) {
16707c478bd9Sstevel@tonic-gate 		dev_stats(dev, interval);
16717c478bd9Sstevel@tonic-gate 		return;
16727c478bd9Sstevel@tonic-gate 	}
16737c478bd9Sstevel@tonic-gate 
16747c478bd9Sstevel@tonic-gate 	if (dev == NULL)
16757c478bd9Sstevel@tonic-gate 		(void) macadm_walk(show_dev, &state, B_TRUE);
16767c478bd9Sstevel@tonic-gate 	else
1677210db224Sericheng 		show_dev(&state, dev);
16787c478bd9Sstevel@tonic-gate }
16797c478bd9Sstevel@tonic-gate 
16807c478bd9Sstevel@tonic-gate /* ARGSUSED */
16817c478bd9Sstevel@tonic-gate static void
16827c478bd9Sstevel@tonic-gate link_stats(const char *link, uint32_t interval)
16837c478bd9Sstevel@tonic-gate {
1684210db224Sericheng 	dladm_attr_t		dlattr;
1685210db224Sericheng 	boolean_t		legacy;
16867c478bd9Sstevel@tonic-gate 	show_link_state_t	state;
16877c478bd9Sstevel@tonic-gate 
1688210db224Sericheng 	if (link != NULL && get_if_info(link, &dlattr, &legacy) < 0) {
1689210db224Sericheng 		(void) fprintf(stderr, gettext("%s: invalid device '%s'\n"),
16907c478bd9Sstevel@tonic-gate 		    progname, link);
16917c478bd9Sstevel@tonic-gate 		exit(1);
16927c478bd9Sstevel@tonic-gate 	}
16937c478bd9Sstevel@tonic-gate 	bzero(&state, sizeof (state));
16947c478bd9Sstevel@tonic-gate 
16957c478bd9Sstevel@tonic-gate 	/*
16967c478bd9Sstevel@tonic-gate 	 * If an interval is specified, continuously show the stats
16977c478bd9Sstevel@tonic-gate 	 * only for the first MAC port.
16987c478bd9Sstevel@tonic-gate 	 */
16997c478bd9Sstevel@tonic-gate 	state.ls_firstonly = (interval != 0);
17007c478bd9Sstevel@tonic-gate 
17017c478bd9Sstevel@tonic-gate 	for (;;) {
17027c478bd9Sstevel@tonic-gate 		(void) printf("\t\tipackets  rbytes	 ierrors ");
17037c478bd9Sstevel@tonic-gate 		(void) printf("opackets	 obytes	     oerrors\n");
17047c478bd9Sstevel@tonic-gate 
17057c478bd9Sstevel@tonic-gate 		state.ls_donefirst = B_FALSE;
17067c478bd9Sstevel@tonic-gate 		if (link == NULL)
17077c478bd9Sstevel@tonic-gate 			(void) dladm_walk(show_link_stats, &state);
17087c478bd9Sstevel@tonic-gate 		else
17097c478bd9Sstevel@tonic-gate 			show_link_stats(&state, link);
17107c478bd9Sstevel@tonic-gate 
17117c478bd9Sstevel@tonic-gate 		if (interval == 0)
17127c478bd9Sstevel@tonic-gate 			break;
17137c478bd9Sstevel@tonic-gate 
17147c478bd9Sstevel@tonic-gate 		(void) sleep(interval);
17157c478bd9Sstevel@tonic-gate 	}
17167c478bd9Sstevel@tonic-gate }
17177c478bd9Sstevel@tonic-gate 
17187c478bd9Sstevel@tonic-gate /* ARGSUSED */
17197c478bd9Sstevel@tonic-gate static void
17207c478bd9Sstevel@tonic-gate aggr_stats(uint16_t key, uint32_t interval)
17217c478bd9Sstevel@tonic-gate {
17227c478bd9Sstevel@tonic-gate 	show_grp_state_t state;
17237c478bd9Sstevel@tonic-gate 
17247c478bd9Sstevel@tonic-gate 	bzero(&state, sizeof (state));
17257c478bd9Sstevel@tonic-gate 	state.gs_stats = B_TRUE;
17267c478bd9Sstevel@tonic-gate 	state.gs_key = key;
17277c478bd9Sstevel@tonic-gate 
17287c478bd9Sstevel@tonic-gate 	/*
17297c478bd9Sstevel@tonic-gate 	 * If an interval is specified, continuously show the stats
17307c478bd9Sstevel@tonic-gate 	 * only for the first group.
17317c478bd9Sstevel@tonic-gate 	 */
17327c478bd9Sstevel@tonic-gate 	state.gs_firstonly = (interval != 0);
17337c478bd9Sstevel@tonic-gate 
17347c478bd9Sstevel@tonic-gate 	for (;;) {
17357c478bd9Sstevel@tonic-gate 		state.gs_found = B_FALSE;
17367c478bd9Sstevel@tonic-gate 		(void) laadm_walk_sys(show_key, &state);
17377c478bd9Sstevel@tonic-gate 		if (state.gs_key != 0 && !state.gs_found) {
17387c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
17397c478bd9Sstevel@tonic-gate 			    gettext("%s: non-existent aggregation key '%u'\n"),
17407c478bd9Sstevel@tonic-gate 			    progname, key);
17417c478bd9Sstevel@tonic-gate 			exit(1);
17427c478bd9Sstevel@tonic-gate 		}
17437c478bd9Sstevel@tonic-gate 
17447c478bd9Sstevel@tonic-gate 		if (interval == 0)
17457c478bd9Sstevel@tonic-gate 			break;
17467c478bd9Sstevel@tonic-gate 
17477c478bd9Sstevel@tonic-gate 		(void) sleep(interval);
17487c478bd9Sstevel@tonic-gate 	}
17497c478bd9Sstevel@tonic-gate }
17507c478bd9Sstevel@tonic-gate 
17517c478bd9Sstevel@tonic-gate /* ARGSUSED */
17527c478bd9Sstevel@tonic-gate static void
17537c478bd9Sstevel@tonic-gate dev_stats(const char *dev, uint32_t interval)
17547c478bd9Sstevel@tonic-gate {
17557c478bd9Sstevel@tonic-gate 	show_mac_state_t state;
17567c478bd9Sstevel@tonic-gate 
17577c478bd9Sstevel@tonic-gate 	bzero(&state, sizeof (state));
17587c478bd9Sstevel@tonic-gate 
17597c478bd9Sstevel@tonic-gate 	/*
17607c478bd9Sstevel@tonic-gate 	 * If an interval is specified, continuously show the stats
17617c478bd9Sstevel@tonic-gate 	 * only for the first MAC port.
17627c478bd9Sstevel@tonic-gate 	 */
17637c478bd9Sstevel@tonic-gate 	state.ms_firstonly = (interval != 0);
17647c478bd9Sstevel@tonic-gate 
17657c478bd9Sstevel@tonic-gate 	for (;;) {
17667c478bd9Sstevel@tonic-gate 
17677c478bd9Sstevel@tonic-gate 		(void) printf("\t\tipackets  rbytes	 ierrors ");
17687c478bd9Sstevel@tonic-gate 		(void) printf("opackets	 obytes	     oerrors\n");
17697c478bd9Sstevel@tonic-gate 
17707c478bd9Sstevel@tonic-gate 		state.ms_donefirst = B_FALSE;
1771210db224Sericheng 		if (dev == NULL)
17727c478bd9Sstevel@tonic-gate 			(void) macadm_walk(show_dev_stats, &state, B_TRUE);
1773210db224Sericheng 		else
1774210db224Sericheng 			show_dev_stats(&state, dev);
17757c478bd9Sstevel@tonic-gate 
17767c478bd9Sstevel@tonic-gate 		if (interval == 0)
17777c478bd9Sstevel@tonic-gate 			break;
17787c478bd9Sstevel@tonic-gate 
17797c478bd9Sstevel@tonic-gate 		(void) sleep(interval);
17807c478bd9Sstevel@tonic-gate 	}
17817c478bd9Sstevel@tonic-gate }
17827c478bd9Sstevel@tonic-gate 
17837c478bd9Sstevel@tonic-gate /* accumulate stats (s1 += (s2 - s3)) */
17847c478bd9Sstevel@tonic-gate static void
17857c478bd9Sstevel@tonic-gate stats_total(pktsum_t *s1, pktsum_t *s2, pktsum_t *s3)
17867c478bd9Sstevel@tonic-gate {
17877c478bd9Sstevel@tonic-gate 	s1->ipackets += (s2->ipackets - s3->ipackets);
17887c478bd9Sstevel@tonic-gate 	s1->opackets += (s2->opackets - s3->opackets);
17897c478bd9Sstevel@tonic-gate 	s1->rbytes += (s2->rbytes - s3->rbytes);
17907c478bd9Sstevel@tonic-gate 	s1->obytes += (s2->obytes - s3->obytes);
17917c478bd9Sstevel@tonic-gate 	s1->ierrors += (s2->ierrors - s3->ierrors);
17927c478bd9Sstevel@tonic-gate 	s1->oerrors += (s2->oerrors - s3->oerrors);
17937c478bd9Sstevel@tonic-gate }
17947c478bd9Sstevel@tonic-gate 
17957c478bd9Sstevel@tonic-gate /* compute stats differences (s1 = s2 - s3) */
17967c478bd9Sstevel@tonic-gate static void
17977c478bd9Sstevel@tonic-gate stats_diff(pktsum_t *s1, pktsum_t *s2, pktsum_t *s3)
17987c478bd9Sstevel@tonic-gate {
17997c478bd9Sstevel@tonic-gate 	s1->ipackets = s2->ipackets - s3->ipackets;
18007c478bd9Sstevel@tonic-gate 	s1->opackets = s2->opackets - s3->opackets;
18017c478bd9Sstevel@tonic-gate 	s1->rbytes = s2->rbytes - s3->rbytes;
18027c478bd9Sstevel@tonic-gate 	s1->obytes = s2->obytes - s3->obytes;
18037c478bd9Sstevel@tonic-gate 	s1->ierrors = s2->ierrors - s3->ierrors;
18047c478bd9Sstevel@tonic-gate 	s1->oerrors = s2->oerrors - s3->oerrors;
18057c478bd9Sstevel@tonic-gate }
18067c478bd9Sstevel@tonic-gate 
1807cd93090eSericheng /*
1808ba2e4443Sseb  * In the following routines, we do the first kstat_lookup() assuming that
1809ba2e4443Sseb  * the device is gldv3-based and that the kstat name is the one passed in
1810ba2e4443Sseb  * as the "name" argument. If the lookup fails, we redo the kstat_lookup()
1811ba2e4443Sseb  * omitting the kstat name. This second lookup is needed for getting kstats
1812ba2e4443Sseb  * from legacy devices. This can fail too if the device is not attached or
1813ba2e4443Sseb  * the device is legacy and doesn't export the kstats we need.
1814cd93090eSericheng  */
18157c478bd9Sstevel@tonic-gate static void
18167c478bd9Sstevel@tonic-gate get_stats(char *module, int instance, char *name, pktsum_t *stats)
18177c478bd9Sstevel@tonic-gate {
18187c478bd9Sstevel@tonic-gate 	kstat_ctl_t	*kcp;
18197c478bd9Sstevel@tonic-gate 	kstat_t		*ksp;
18207c478bd9Sstevel@tonic-gate 
18217c478bd9Sstevel@tonic-gate 	if ((kcp = kstat_open()) == NULL) {
18227c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
18237c478bd9Sstevel@tonic-gate 		    gettext("%s: kstat open operation failed\n"),
18247c478bd9Sstevel@tonic-gate 		    progname);
18257c478bd9Sstevel@tonic-gate 		return;
18267c478bd9Sstevel@tonic-gate 	}
18277c478bd9Sstevel@tonic-gate 
1828cd93090eSericheng 	if ((ksp = kstat_lookup(kcp, module, instance, name)) == NULL &&
1829ba2e4443Sseb 	    (ksp = kstat_lookup(kcp, module, instance, NULL)) == NULL) {
18307c478bd9Sstevel@tonic-gate 		/*
18317c478bd9Sstevel@tonic-gate 		 * The kstat query could fail if the underlying MAC
18327c478bd9Sstevel@tonic-gate 		 * driver was already detached.
18337c478bd9Sstevel@tonic-gate 		 */
18347c478bd9Sstevel@tonic-gate 		(void) kstat_close(kcp);
18357c478bd9Sstevel@tonic-gate 		return;
18367c478bd9Sstevel@tonic-gate 	}
18377c478bd9Sstevel@tonic-gate 
18387c478bd9Sstevel@tonic-gate 	if (kstat_read(kcp, ksp, NULL) == -1)
18397c478bd9Sstevel@tonic-gate 		goto bail;
18407c478bd9Sstevel@tonic-gate 
18417c478bd9Sstevel@tonic-gate 	if (kstat_value(ksp, "ipackets64", KSTAT_DATA_UINT64,
18427c478bd9Sstevel@tonic-gate 	    &stats->ipackets) < 0)
18437c478bd9Sstevel@tonic-gate 		goto bail;
18447c478bd9Sstevel@tonic-gate 
18457c478bd9Sstevel@tonic-gate 	if (kstat_value(ksp, "opackets64", KSTAT_DATA_UINT64,
18467c478bd9Sstevel@tonic-gate 	    &stats->opackets) < 0)
18477c478bd9Sstevel@tonic-gate 		goto bail;
18487c478bd9Sstevel@tonic-gate 
18497c478bd9Sstevel@tonic-gate 	if (kstat_value(ksp, "rbytes64", KSTAT_DATA_UINT64,
18507c478bd9Sstevel@tonic-gate 	    &stats->rbytes) < 0)
18517c478bd9Sstevel@tonic-gate 		goto bail;
18527c478bd9Sstevel@tonic-gate 
18537c478bd9Sstevel@tonic-gate 	if (kstat_value(ksp, "obytes64", KSTAT_DATA_UINT64,
18547c478bd9Sstevel@tonic-gate 	    &stats->obytes) < 0)
18557c478bd9Sstevel@tonic-gate 		goto bail;
18567c478bd9Sstevel@tonic-gate 
18577c478bd9Sstevel@tonic-gate 	if (kstat_value(ksp, "ierrors", KSTAT_DATA_UINT32,
18587c478bd9Sstevel@tonic-gate 	    &stats->ierrors) < 0)
18597c478bd9Sstevel@tonic-gate 		goto bail;
18607c478bd9Sstevel@tonic-gate 
18617c478bd9Sstevel@tonic-gate 	if (kstat_value(ksp, "oerrors", KSTAT_DATA_UINT32,
18627c478bd9Sstevel@tonic-gate 	    &stats->oerrors) < 0)
18637c478bd9Sstevel@tonic-gate 		goto bail;
18647c478bd9Sstevel@tonic-gate 
18657c478bd9Sstevel@tonic-gate 	(void) kstat_close(kcp);
18667c478bd9Sstevel@tonic-gate 	return;
18677c478bd9Sstevel@tonic-gate 
18687c478bd9Sstevel@tonic-gate bail:
18697c478bd9Sstevel@tonic-gate 	(void) kstat_close(kcp);
18707c478bd9Sstevel@tonic-gate }
18717c478bd9Sstevel@tonic-gate 
18727c478bd9Sstevel@tonic-gate static void
1873ba2e4443Sseb get_mac_stats(const char *dev, pktsum_t *stats)
18747c478bd9Sstevel@tonic-gate {
1875ba2e4443Sseb 	char	module[LIFNAMSIZ];
1876ba2e4443Sseb 	int	instance;
18777c478bd9Sstevel@tonic-gate 
1878ba2e4443Sseb 	if (dlpi_if_parse(dev, module, &instance) != 0)
1879ba2e4443Sseb 		return;
18807c478bd9Sstevel@tonic-gate 	bzero(stats, sizeof (*stats));
1881ba2e4443Sseb 	get_stats(module, instance, "mac", stats);
18827c478bd9Sstevel@tonic-gate }
18837c478bd9Sstevel@tonic-gate 
18847c478bd9Sstevel@tonic-gate static void
18857c478bd9Sstevel@tonic-gate get_link_stats(const char *link, pktsum_t *stats)
18867c478bd9Sstevel@tonic-gate {
1887ba2e4443Sseb 	char	module[LIFNAMSIZ];
1888ba2e4443Sseb 	int	instance;
1889ba2e4443Sseb 
1890ba2e4443Sseb 	if (dlpi_if_parse(link, module, &instance) != 0)
1891ba2e4443Sseb 		return;
18927c478bd9Sstevel@tonic-gate 	bzero(stats, sizeof (*stats));
1893ba2e4443Sseb 	get_stats(module, instance, (char *)link, stats);
18947c478bd9Sstevel@tonic-gate }
18957c478bd9Sstevel@tonic-gate 
1896ba2e4443Sseb static int
1897ba2e4443Sseb get_single_mac_stat(const char *dev, const char *name, uint8_t type,
1898ba2e4443Sseb     void *val)
18997c478bd9Sstevel@tonic-gate {
1900ba2e4443Sseb 	char		module[LIFNAMSIZ];
1901ba2e4443Sseb 	int		instance;
19027c478bd9Sstevel@tonic-gate 	kstat_ctl_t	*kcp;
19037c478bd9Sstevel@tonic-gate 	kstat_t		*ksp;
19047c478bd9Sstevel@tonic-gate 
19057c478bd9Sstevel@tonic-gate 	if ((kcp = kstat_open()) == NULL) {
19067c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
19077c478bd9Sstevel@tonic-gate 		    gettext("%s: kstat open operation failed\n"),
19087c478bd9Sstevel@tonic-gate 		    progname);
1909ba2e4443Sseb 		return (-1);
19107c478bd9Sstevel@tonic-gate 	}
19117c478bd9Sstevel@tonic-gate 
1912ba2e4443Sseb 	if (dlpi_if_parse(dev, module, &instance) != 0)
1913ba2e4443Sseb 		return (-1);
1914ba2e4443Sseb 	if ((ksp = kstat_lookup(kcp, module, instance, "mac")) == NULL &&
1915ba2e4443Sseb 	    (ksp = kstat_lookup(kcp, module, instance, NULL)) == NULL) {
19167c478bd9Sstevel@tonic-gate 		/*
19177c478bd9Sstevel@tonic-gate 		 * The kstat query could fail if the underlying MAC
19187c478bd9Sstevel@tonic-gate 		 * driver was already detached.
19197c478bd9Sstevel@tonic-gate 		 */
19207c478bd9Sstevel@tonic-gate 		goto bail;
19217c478bd9Sstevel@tonic-gate 	}
19227c478bd9Sstevel@tonic-gate 
19237c478bd9Sstevel@tonic-gate 	if (kstat_read(kcp, ksp, NULL) == -1) {
19247c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
19257c478bd9Sstevel@tonic-gate 		    gettext("%s: kstat read failed\n"),
19267c478bd9Sstevel@tonic-gate 		    progname);
19277c478bd9Sstevel@tonic-gate 		goto bail;
19287c478bd9Sstevel@tonic-gate 	}
19297c478bd9Sstevel@tonic-gate 
1930ba2e4443Sseb 	if (kstat_value(ksp, name, type, val) < 0)
19317c478bd9Sstevel@tonic-gate 		goto bail;
1932ba2e4443Sseb 
1933ba2e4443Sseb 	(void) kstat_close(kcp);
1934ba2e4443Sseb 	return (0);
19357c478bd9Sstevel@tonic-gate 
19367c478bd9Sstevel@tonic-gate bail:
19377c478bd9Sstevel@tonic-gate 	(void) kstat_close(kcp);
1938ba2e4443Sseb 	return (-1);
1939ba2e4443Sseb }
1940ba2e4443Sseb 
1941ba2e4443Sseb static uint64_t
1942ba2e4443Sseb mac_ifspeed(const char *dev)
1943ba2e4443Sseb {
1944ba2e4443Sseb 	uint64_t ifspeed = 0;
1945ba2e4443Sseb 
1946ba2e4443Sseb 	(void) get_single_mac_stat(dev, "ifspeed", KSTAT_DATA_UINT64, &ifspeed);
19477c478bd9Sstevel@tonic-gate 	return (ifspeed);
19487c478bd9Sstevel@tonic-gate }
19497c478bd9Sstevel@tonic-gate 
19507c478bd9Sstevel@tonic-gate static char *
1951ba2e4443Sseb mac_link_state(const char *dev)
19527c478bd9Sstevel@tonic-gate {
19537c478bd9Sstevel@tonic-gate 	link_state_t	link_state;
19547c478bd9Sstevel@tonic-gate 	char		*state_str = "unknown";
19557c478bd9Sstevel@tonic-gate 
1956ba2e4443Sseb 	if (get_single_mac_stat(dev, "link_state", KSTAT_DATA_UINT32,
1957ba2e4443Sseb 	    &link_state) != 0) {
19587c478bd9Sstevel@tonic-gate 		return (state_str);
19597c478bd9Sstevel@tonic-gate 	}
19607c478bd9Sstevel@tonic-gate 
19617c478bd9Sstevel@tonic-gate 	switch (link_state) {
19627c478bd9Sstevel@tonic-gate 	case LINK_STATE_UP:
19637c478bd9Sstevel@tonic-gate 		state_str = "up";
19647c478bd9Sstevel@tonic-gate 		break;
19657c478bd9Sstevel@tonic-gate 	case LINK_STATE_DOWN:
19667c478bd9Sstevel@tonic-gate 		state_str = "down";
19677c478bd9Sstevel@tonic-gate 		break;
19687c478bd9Sstevel@tonic-gate 	default:
19697c478bd9Sstevel@tonic-gate 		break;
19707c478bd9Sstevel@tonic-gate 	}
19717c478bd9Sstevel@tonic-gate 
19727c478bd9Sstevel@tonic-gate 	return (state_str);
19737c478bd9Sstevel@tonic-gate }
19747c478bd9Sstevel@tonic-gate 
19757c478bd9Sstevel@tonic-gate 
19767c478bd9Sstevel@tonic-gate static char *
1977ba2e4443Sseb mac_link_duplex(const char *dev)
19787c478bd9Sstevel@tonic-gate {
19797c478bd9Sstevel@tonic-gate 	link_duplex_t	link_duplex;
19807c478bd9Sstevel@tonic-gate 	char		*duplex_str = "unknown";
19817c478bd9Sstevel@tonic-gate 
1982ba2e4443Sseb 	if (get_single_mac_stat(dev, "link_duplex", KSTAT_DATA_UINT32,
1983ba2e4443Sseb 	    &link_duplex) != 0) {
19847c478bd9Sstevel@tonic-gate 		return (duplex_str);
19857c478bd9Sstevel@tonic-gate 	}
19867c478bd9Sstevel@tonic-gate 
19877c478bd9Sstevel@tonic-gate 	switch (link_duplex) {
19887c478bd9Sstevel@tonic-gate 	case LINK_DUPLEX_FULL:
19897c478bd9Sstevel@tonic-gate 		duplex_str = "full";
19907c478bd9Sstevel@tonic-gate 		break;
19917c478bd9Sstevel@tonic-gate 	case LINK_DUPLEX_HALF:
19927c478bd9Sstevel@tonic-gate 		duplex_str = "half";
19937c478bd9Sstevel@tonic-gate 		break;
19947c478bd9Sstevel@tonic-gate 	default:
19957c478bd9Sstevel@tonic-gate 		break;
19967c478bd9Sstevel@tonic-gate 	}
19977c478bd9Sstevel@tonic-gate 
19987c478bd9Sstevel@tonic-gate 	return (duplex_str);
19997c478bd9Sstevel@tonic-gate }
2000*0ba2cbe9Sxc151355 
2001*0ba2cbe9Sxc151355 #define	WIFI_CMD_SCAN	0x00000001
2002*0ba2cbe9Sxc151355 #define	WIFI_CMD_SHOW	0x00000002
2003*0ba2cbe9Sxc151355 #define	WIFI_CMD_ALL	(WIFI_CMD_SCAN | WIFI_CMD_SHOW)
2004*0ba2cbe9Sxc151355 typedef struct wifi_field {
2005*0ba2cbe9Sxc151355 	const char	*wf_name;
2006*0ba2cbe9Sxc151355 	const char	*wf_header;
2007*0ba2cbe9Sxc151355 	uint_t		wf_width;
2008*0ba2cbe9Sxc151355 	uint_t		wf_mask;
2009*0ba2cbe9Sxc151355 	uint_t		wf_cmdtype;
2010*0ba2cbe9Sxc151355 } wifi_field_t;
2011*0ba2cbe9Sxc151355 
2012*0ba2cbe9Sxc151355 static wifi_field_t wifi_fields[] = {
2013*0ba2cbe9Sxc151355 { "link",	"LINK",		10,	0, 			WIFI_CMD_ALL},
2014*0ba2cbe9Sxc151355 { "essid",	"ESSID",	19,	WLADM_WLAN_ATTR_ESSID,	WIFI_CMD_ALL},
2015*0ba2cbe9Sxc151355 { "bssid",	"BSSID/IBSSID", 17,	WLADM_WLAN_ATTR_BSSID, 	WIFI_CMD_ALL},
2016*0ba2cbe9Sxc151355 { "ibssid",	"BSSID/IBSSID", 17,	WLADM_WLAN_ATTR_BSSID,	WIFI_CMD_ALL},
2017*0ba2cbe9Sxc151355 { "mode",	"MODE",		6,	WLADM_WLAN_ATTR_MODE,	WIFI_CMD_ALL},
2018*0ba2cbe9Sxc151355 { "speed",	"SPEED",	6,	WLADM_WLAN_ATTR_SPEED,	WIFI_CMD_ALL},
2019*0ba2cbe9Sxc151355 { "auth",	"AUTH",		8,	WLADM_WLAN_ATTR_AUTH,	WIFI_CMD_ALL},
2020*0ba2cbe9Sxc151355 { "bsstype",	"BSSTYPE",	8,	WLADM_WLAN_ATTR_BSSTYPE, WIFI_CMD_ALL},
2021*0ba2cbe9Sxc151355 { "sec", 	"SEC",		6,	WLADM_WLAN_ATTR_SECMODE, WIFI_CMD_ALL},
2022*0ba2cbe9Sxc151355 { "status",	"STATUS",	17,	WLADM_LINK_ATTR_STATUS, WIFI_CMD_SHOW},
2023*0ba2cbe9Sxc151355 { "strength",	"STRENGTH",	10,	WLADM_WLAN_ATTR_STRENGTH, WIFI_CMD_ALL}}
2024*0ba2cbe9Sxc151355 ;
2025*0ba2cbe9Sxc151355 
2026*0ba2cbe9Sxc151355 static char *all_scan_wifi_fields =
2027*0ba2cbe9Sxc151355 	"link,essid,bssid,sec,strength,mode,speed,auth,bsstype";
2028*0ba2cbe9Sxc151355 static char *all_show_wifi_fields =
2029*0ba2cbe9Sxc151355 	"link,status,essid,sec,strength,mode,speed,auth,bssid,bsstype";
2030*0ba2cbe9Sxc151355 static char *def_scan_wifi_fields =
2031*0ba2cbe9Sxc151355 	"link,essid,bssid,sec,strength,mode,speed";
2032*0ba2cbe9Sxc151355 static char *def_show_wifi_fields =
2033*0ba2cbe9Sxc151355 	"link,status,essid,sec,strength,mode,speed";
2034*0ba2cbe9Sxc151355 
2035*0ba2cbe9Sxc151355 #define	WIFI_MAX_FIELDS 	(sizeof (wifi_fields) / sizeof (wifi_field_t))
2036*0ba2cbe9Sxc151355 #define	WIFI_MAX_FIELD_LEN	32
2037*0ba2cbe9Sxc151355 
2038*0ba2cbe9Sxc151355 typedef struct {
2039*0ba2cbe9Sxc151355 	char	*s_buf;
2040*0ba2cbe9Sxc151355 	char	**s_fields;	/* array of pointer to the fields in s_buf */
2041*0ba2cbe9Sxc151355 	uint_t	s_nfields;	/* the number of fields in s_buf */
2042*0ba2cbe9Sxc151355 } split_t;
2043*0ba2cbe9Sxc151355 
2044*0ba2cbe9Sxc151355 /*
2045*0ba2cbe9Sxc151355  * Free the split_t structure pointed to by `sp'.
2046*0ba2cbe9Sxc151355  */
2047*0ba2cbe9Sxc151355 static void
2048*0ba2cbe9Sxc151355 splitfree(split_t *sp)
2049*0ba2cbe9Sxc151355 {
2050*0ba2cbe9Sxc151355 	free(sp->s_buf);
2051*0ba2cbe9Sxc151355 	free(sp->s_fields);
2052*0ba2cbe9Sxc151355 	free(sp);
2053*0ba2cbe9Sxc151355 }
2054*0ba2cbe9Sxc151355 
2055*0ba2cbe9Sxc151355 /*
2056*0ba2cbe9Sxc151355  * Split `str' into at most `maxfields' fields, each field at most `maxlen' in
2057*0ba2cbe9Sxc151355  * length.  Return a pointer to a split_t containing the split fields, or NULL
2058*0ba2cbe9Sxc151355  * on failure.
2059*0ba2cbe9Sxc151355  */
2060*0ba2cbe9Sxc151355 static split_t *
2061*0ba2cbe9Sxc151355 split(const char *str, uint_t maxfields, uint_t maxlen)
2062*0ba2cbe9Sxc151355 {
2063*0ba2cbe9Sxc151355 	char	*field, *token, *lasts = NULL;
2064*0ba2cbe9Sxc151355 	split_t	*sp;
2065*0ba2cbe9Sxc151355 
2066*0ba2cbe9Sxc151355 	if (*str == '\0' || maxfields == 0 || maxlen == 0)
2067*0ba2cbe9Sxc151355 		return (NULL);
2068*0ba2cbe9Sxc151355 
2069*0ba2cbe9Sxc151355 	sp = calloc(sizeof (split_t), 1);
2070*0ba2cbe9Sxc151355 	if (sp == NULL)
2071*0ba2cbe9Sxc151355 		return (NULL);
2072*0ba2cbe9Sxc151355 
2073*0ba2cbe9Sxc151355 	sp->s_buf = strdup(str);
2074*0ba2cbe9Sxc151355 	sp->s_fields = malloc(sizeof (char *) * maxfields);
2075*0ba2cbe9Sxc151355 	if (sp->s_buf == NULL || sp->s_fields == NULL)
2076*0ba2cbe9Sxc151355 		goto fail;
2077*0ba2cbe9Sxc151355 
2078*0ba2cbe9Sxc151355 	token = sp->s_buf;
2079*0ba2cbe9Sxc151355 	while ((field = strtok_r(token, ",", &lasts)) != NULL) {
2080*0ba2cbe9Sxc151355 		if (sp->s_nfields == maxfields || strlen(field) > maxlen)
2081*0ba2cbe9Sxc151355 			goto fail;
2082*0ba2cbe9Sxc151355 		token = NULL;
2083*0ba2cbe9Sxc151355 		sp->s_fields[sp->s_nfields++] = field;
2084*0ba2cbe9Sxc151355 	}
2085*0ba2cbe9Sxc151355 	return (sp);
2086*0ba2cbe9Sxc151355 fail:
2087*0ba2cbe9Sxc151355 	splitfree(sp);
2088*0ba2cbe9Sxc151355 	return (NULL);
2089*0ba2cbe9Sxc151355 }
2090*0ba2cbe9Sxc151355 
2091*0ba2cbe9Sxc151355 static int
2092*0ba2cbe9Sxc151355 parse_wifi_fields(char *str, wifi_field_t ***fields, uint_t *countp,
2093*0ba2cbe9Sxc151355     uint_t cmdtype)
2094*0ba2cbe9Sxc151355 {
2095*0ba2cbe9Sxc151355 	uint_t		i, j;
2096*0ba2cbe9Sxc151355 	wifi_field_t	**wf = NULL;
2097*0ba2cbe9Sxc151355 	split_t		*sp;
2098*0ba2cbe9Sxc151355 	boolean_t	good_match = B_FALSE;
2099*0ba2cbe9Sxc151355 
2100*0ba2cbe9Sxc151355 	if (cmdtype == WIFI_CMD_SCAN) {
2101*0ba2cbe9Sxc151355 		if (str == NULL)
2102*0ba2cbe9Sxc151355 			str = def_scan_wifi_fields;
2103*0ba2cbe9Sxc151355 		if (strcasecmp(str, "all") == 0)
2104*0ba2cbe9Sxc151355 			str = all_scan_wifi_fields;
2105*0ba2cbe9Sxc151355 	} else if (cmdtype == WIFI_CMD_SHOW) {
2106*0ba2cbe9Sxc151355 		if (str == NULL)
2107*0ba2cbe9Sxc151355 			str = def_show_wifi_fields;
2108*0ba2cbe9Sxc151355 		if (strcasecmp(str, "all") == 0)
2109*0ba2cbe9Sxc151355 			str = all_show_wifi_fields;
2110*0ba2cbe9Sxc151355 	} else {
2111*0ba2cbe9Sxc151355 		return (-1);
2112*0ba2cbe9Sxc151355 	}
2113*0ba2cbe9Sxc151355 
2114*0ba2cbe9Sxc151355 	sp = split(str, WIFI_MAX_FIELDS, WIFI_MAX_FIELD_LEN);
2115*0ba2cbe9Sxc151355 	if (sp == NULL)
2116*0ba2cbe9Sxc151355 		return (-1);
2117*0ba2cbe9Sxc151355 
2118*0ba2cbe9Sxc151355 	wf = malloc(sp->s_nfields * sizeof (wifi_field_t *));
2119*0ba2cbe9Sxc151355 	if (wf == NULL)
2120*0ba2cbe9Sxc151355 		goto fail;
2121*0ba2cbe9Sxc151355 
2122*0ba2cbe9Sxc151355 	for (i = 0; i < sp->s_nfields; i++) {
2123*0ba2cbe9Sxc151355 		for (j = 0; j < WIFI_MAX_FIELDS; j++) {
2124*0ba2cbe9Sxc151355 			if (strcasecmp(sp->s_fields[i],
2125*0ba2cbe9Sxc151355 			    wifi_fields[j].wf_name) == 0) {
2126*0ba2cbe9Sxc151355 				good_match = wifi_fields[i].
2127*0ba2cbe9Sxc151355 				    wf_cmdtype & cmdtype;
2128*0ba2cbe9Sxc151355 				break;
2129*0ba2cbe9Sxc151355 			}
2130*0ba2cbe9Sxc151355 		}
2131*0ba2cbe9Sxc151355 		if (!good_match)
2132*0ba2cbe9Sxc151355 			goto fail;
2133*0ba2cbe9Sxc151355 
2134*0ba2cbe9Sxc151355 		good_match = B_FALSE;
2135*0ba2cbe9Sxc151355 		wf[i] = &wifi_fields[j];
2136*0ba2cbe9Sxc151355 	}
2137*0ba2cbe9Sxc151355 	*countp = i;
2138*0ba2cbe9Sxc151355 	*fields = wf;
2139*0ba2cbe9Sxc151355 	splitfree(sp);
2140*0ba2cbe9Sxc151355 	return (0);
2141*0ba2cbe9Sxc151355 fail:
2142*0ba2cbe9Sxc151355 	free(wf);
2143*0ba2cbe9Sxc151355 	splitfree(sp);
2144*0ba2cbe9Sxc151355 	return (-1);
2145*0ba2cbe9Sxc151355 }
2146*0ba2cbe9Sxc151355 
2147*0ba2cbe9Sxc151355 typedef struct print_wifi_state {
2148*0ba2cbe9Sxc151355 	const char	*ws_link;
2149*0ba2cbe9Sxc151355 	boolean_t	ws_parseable;
2150*0ba2cbe9Sxc151355 	boolean_t	ws_header;
2151*0ba2cbe9Sxc151355 	wifi_field_t	**ws_fields;
2152*0ba2cbe9Sxc151355 	uint_t		ws_nfields;
2153*0ba2cbe9Sxc151355 	boolean_t	ws_lastfield;
2154*0ba2cbe9Sxc151355 	uint_t		ws_overflow;
2155*0ba2cbe9Sxc151355 } print_wifi_state_t;
2156*0ba2cbe9Sxc151355 
2157*0ba2cbe9Sxc151355 static void
2158*0ba2cbe9Sxc151355 print_wifi_head(print_wifi_state_t *statep)
2159*0ba2cbe9Sxc151355 {
2160*0ba2cbe9Sxc151355 	int		i;
2161*0ba2cbe9Sxc151355 	wifi_field_t	*wfp;
2162*0ba2cbe9Sxc151355 
2163*0ba2cbe9Sxc151355 	for (i = 0; i < statep->ws_nfields; i++) {
2164*0ba2cbe9Sxc151355 		wfp = statep->ws_fields[i];
2165*0ba2cbe9Sxc151355 		if (i + 1 < statep->ws_nfields)
2166*0ba2cbe9Sxc151355 			(void) printf("%-*s ", wfp->wf_width, wfp->wf_header);
2167*0ba2cbe9Sxc151355 		else
2168*0ba2cbe9Sxc151355 			(void) printf("%s", wfp->wf_header);
2169*0ba2cbe9Sxc151355 	}
2170*0ba2cbe9Sxc151355 	(void) printf("\n");
2171*0ba2cbe9Sxc151355 }
2172*0ba2cbe9Sxc151355 
2173*0ba2cbe9Sxc151355 static void
2174*0ba2cbe9Sxc151355 print_wifi_field(print_wifi_state_t *statep, wifi_field_t *wfp,
2175*0ba2cbe9Sxc151355     const char *value)
2176*0ba2cbe9Sxc151355 {
2177*0ba2cbe9Sxc151355 	uint_t	width = wfp->wf_width;
2178*0ba2cbe9Sxc151355 	uint_t	valwidth = strlen(value);
2179*0ba2cbe9Sxc151355 	uint_t	compress;
2180*0ba2cbe9Sxc151355 
2181*0ba2cbe9Sxc151355 	if (statep->ws_parseable) {
2182*0ba2cbe9Sxc151355 		(void) printf("%s=\"%s\"", wfp->wf_header, value);
2183*0ba2cbe9Sxc151355 	} else {
2184*0ba2cbe9Sxc151355 		if (value[0] == '\0')
2185*0ba2cbe9Sxc151355 			value = "--";
2186*0ba2cbe9Sxc151355 		if (statep->ws_lastfield) {
2187*0ba2cbe9Sxc151355 			(void) printf("%s", value);
2188*0ba2cbe9Sxc151355 			return;
2189*0ba2cbe9Sxc151355 		}
2190*0ba2cbe9Sxc151355 
2191*0ba2cbe9Sxc151355 		if (valwidth > width) {
2192*0ba2cbe9Sxc151355 			statep->ws_overflow += valwidth - width;
2193*0ba2cbe9Sxc151355 		} else if (valwidth < width && statep->ws_overflow > 0) {
2194*0ba2cbe9Sxc151355 			compress = min(statep->ws_overflow, width - valwidth);
2195*0ba2cbe9Sxc151355 			statep->ws_overflow -= compress;
2196*0ba2cbe9Sxc151355 			width -= compress;
2197*0ba2cbe9Sxc151355 		}
2198*0ba2cbe9Sxc151355 		(void) printf("%-*s", width, value);
2199*0ba2cbe9Sxc151355 	}
2200*0ba2cbe9Sxc151355 
2201*0ba2cbe9Sxc151355 	if (!statep->ws_lastfield)
2202*0ba2cbe9Sxc151355 		(void) putchar(' ');
2203*0ba2cbe9Sxc151355 }
2204*0ba2cbe9Sxc151355 
2205*0ba2cbe9Sxc151355 static void
2206*0ba2cbe9Sxc151355 print_wlan_attr(print_wifi_state_t *statep, wifi_field_t *wfp,
2207*0ba2cbe9Sxc151355     wladm_wlan_attr_t *attrp)
2208*0ba2cbe9Sxc151355 {
2209*0ba2cbe9Sxc151355 	char		buf[WLADM_STRSIZE];
2210*0ba2cbe9Sxc151355 	const char	*str = "";
2211*0ba2cbe9Sxc151355 
2212*0ba2cbe9Sxc151355 	if (wfp->wf_mask == 0) {
2213*0ba2cbe9Sxc151355 		print_wifi_field(statep, wfp, statep->ws_link);
2214*0ba2cbe9Sxc151355 		return;
2215*0ba2cbe9Sxc151355 	}
2216*0ba2cbe9Sxc151355 
2217*0ba2cbe9Sxc151355 	if ((wfp->wf_mask & attrp->wa_valid) == 0) {
2218*0ba2cbe9Sxc151355 		print_wifi_field(statep, wfp, "");
2219*0ba2cbe9Sxc151355 		return;
2220*0ba2cbe9Sxc151355 	}
2221*0ba2cbe9Sxc151355 
2222*0ba2cbe9Sxc151355 	switch (wfp->wf_mask) {
2223*0ba2cbe9Sxc151355 	case WLADM_WLAN_ATTR_ESSID:
2224*0ba2cbe9Sxc151355 		str = wladm_essid2str(&attrp->wa_essid, buf);
2225*0ba2cbe9Sxc151355 		break;
2226*0ba2cbe9Sxc151355 	case WLADM_WLAN_ATTR_BSSID:
2227*0ba2cbe9Sxc151355 		str = wladm_bssid2str(&attrp->wa_bssid, buf);
2228*0ba2cbe9Sxc151355 		break;
2229*0ba2cbe9Sxc151355 	case WLADM_WLAN_ATTR_SECMODE:
2230*0ba2cbe9Sxc151355 		str = wladm_secmode2str(&attrp->wa_secmode, buf);
2231*0ba2cbe9Sxc151355 		break;
2232*0ba2cbe9Sxc151355 	case WLADM_WLAN_ATTR_STRENGTH:
2233*0ba2cbe9Sxc151355 		str = wladm_strength2str(&attrp->wa_strength, buf);
2234*0ba2cbe9Sxc151355 		break;
2235*0ba2cbe9Sxc151355 	case WLADM_WLAN_ATTR_MODE:
2236*0ba2cbe9Sxc151355 		str = wladm_mode2str(&attrp->wa_mode, buf);
2237*0ba2cbe9Sxc151355 		break;
2238*0ba2cbe9Sxc151355 	case WLADM_WLAN_ATTR_SPEED:
2239*0ba2cbe9Sxc151355 		str = wladm_speed2str(&attrp->wa_speed, buf);
2240*0ba2cbe9Sxc151355 		(void) strlcat(buf, "Mb", sizeof (buf));
2241*0ba2cbe9Sxc151355 		break;
2242*0ba2cbe9Sxc151355 	case WLADM_WLAN_ATTR_AUTH:
2243*0ba2cbe9Sxc151355 		str = wladm_auth2str(&attrp->wa_auth, buf);
2244*0ba2cbe9Sxc151355 		break;
2245*0ba2cbe9Sxc151355 	case WLADM_WLAN_ATTR_BSSTYPE:
2246*0ba2cbe9Sxc151355 		str = wladm_bsstype2str(&attrp->wa_bsstype, buf);
2247*0ba2cbe9Sxc151355 		break;
2248*0ba2cbe9Sxc151355 	}
2249*0ba2cbe9Sxc151355 
2250*0ba2cbe9Sxc151355 	print_wifi_field(statep, wfp, str);
2251*0ba2cbe9Sxc151355 }
2252*0ba2cbe9Sxc151355 
2253*0ba2cbe9Sxc151355 static boolean_t
2254*0ba2cbe9Sxc151355 print_scan_results(void *arg, wladm_wlan_attr_t *attrp)
2255*0ba2cbe9Sxc151355 {
2256*0ba2cbe9Sxc151355 	print_wifi_state_t	*statep = arg;
2257*0ba2cbe9Sxc151355 	int			i;
2258*0ba2cbe9Sxc151355 
2259*0ba2cbe9Sxc151355 	if (statep->ws_header) {
2260*0ba2cbe9Sxc151355 		statep->ws_header = B_FALSE;
2261*0ba2cbe9Sxc151355 		if (!statep->ws_parseable)
2262*0ba2cbe9Sxc151355 			print_wifi_head(statep);
2263*0ba2cbe9Sxc151355 	}
2264*0ba2cbe9Sxc151355 
2265*0ba2cbe9Sxc151355 	statep->ws_overflow = 0;
2266*0ba2cbe9Sxc151355 	for (i = 0; i < statep->ws_nfields; i++) {
2267*0ba2cbe9Sxc151355 		statep->ws_lastfield = (i + 1 == statep->ws_nfields);
2268*0ba2cbe9Sxc151355 		print_wlan_attr(statep, statep->ws_fields[i], attrp);
2269*0ba2cbe9Sxc151355 	}
2270*0ba2cbe9Sxc151355 	(void) putchar('\n');
2271*0ba2cbe9Sxc151355 	return (B_TRUE);
2272*0ba2cbe9Sxc151355 }
2273*0ba2cbe9Sxc151355 
2274*0ba2cbe9Sxc151355 static boolean_t
2275*0ba2cbe9Sxc151355 scan_wifi(void *arg, const char *link)
2276*0ba2cbe9Sxc151355 {
2277*0ba2cbe9Sxc151355 	char			errmsg[WLADM_STRSIZE];
2278*0ba2cbe9Sxc151355 	print_wifi_state_t	*statep = arg;
2279*0ba2cbe9Sxc151355 	wladm_status_t		status;
2280*0ba2cbe9Sxc151355 
2281*0ba2cbe9Sxc151355 	statep->ws_link = link;
2282*0ba2cbe9Sxc151355 	status = wladm_scan(link, statep, print_scan_results);
2283*0ba2cbe9Sxc151355 	if (status != WLADM_STATUS_OK) {
2284*0ba2cbe9Sxc151355 		(void) fprintf(stderr, gettext(
2285*0ba2cbe9Sxc151355 		    "%s: cannot scan link '%s': %s\n"),
2286*0ba2cbe9Sxc151355 		    progname, link, wladm_status2str(status, errmsg));
2287*0ba2cbe9Sxc151355 		exit(1);
2288*0ba2cbe9Sxc151355 	}
2289*0ba2cbe9Sxc151355 	return (B_TRUE);
2290*0ba2cbe9Sxc151355 }
2291*0ba2cbe9Sxc151355 
2292*0ba2cbe9Sxc151355 static void
2293*0ba2cbe9Sxc151355 print_link_attr(print_wifi_state_t *statep, wifi_field_t *wfp,
2294*0ba2cbe9Sxc151355     wladm_link_attr_t *attrp)
2295*0ba2cbe9Sxc151355 {
2296*0ba2cbe9Sxc151355 	char		buf[WLADM_STRSIZE];
2297*0ba2cbe9Sxc151355 	const char	*str = "";
2298*0ba2cbe9Sxc151355 
2299*0ba2cbe9Sxc151355 	if (strcmp(wfp->wf_name, "status") == 0) {
2300*0ba2cbe9Sxc151355 		if ((wfp->wf_mask & attrp->la_valid) != 0)
2301*0ba2cbe9Sxc151355 			str = wladm_linkstatus2str(&attrp->la_status, buf);
2302*0ba2cbe9Sxc151355 		print_wifi_field(statep, wfp, str);
2303*0ba2cbe9Sxc151355 		return;
2304*0ba2cbe9Sxc151355 	}
2305*0ba2cbe9Sxc151355 	print_wlan_attr(statep, wfp, &attrp->la_wlan_attr);
2306*0ba2cbe9Sxc151355 }
2307*0ba2cbe9Sxc151355 
2308*0ba2cbe9Sxc151355 static boolean_t
2309*0ba2cbe9Sxc151355 show_wifi(void *arg, const char *link)
2310*0ba2cbe9Sxc151355 {
2311*0ba2cbe9Sxc151355 	int			i;
2312*0ba2cbe9Sxc151355 	char 			buf[WLADM_STRSIZE];
2313*0ba2cbe9Sxc151355 	print_wifi_state_t	*statep = arg;
2314*0ba2cbe9Sxc151355 	wladm_link_attr_t	attr;
2315*0ba2cbe9Sxc151355 	wladm_status_t		status;
2316*0ba2cbe9Sxc151355 
2317*0ba2cbe9Sxc151355 	status = wladm_get_link_attr(link, &attr);
2318*0ba2cbe9Sxc151355 	if (status != WLADM_STATUS_OK) {
2319*0ba2cbe9Sxc151355 		(void) fprintf(stderr, gettext("%s: cannot get link "
2320*0ba2cbe9Sxc151355 		    "attributes for '%s': %s\n"), progname, link,
2321*0ba2cbe9Sxc151355 		    wladm_status2str(status, buf));
2322*0ba2cbe9Sxc151355 		exit(1);
2323*0ba2cbe9Sxc151355 	}
2324*0ba2cbe9Sxc151355 
2325*0ba2cbe9Sxc151355 	if (statep->ws_header) {
2326*0ba2cbe9Sxc151355 		statep->ws_header = B_FALSE;
2327*0ba2cbe9Sxc151355 		if (!statep->ws_parseable)
2328*0ba2cbe9Sxc151355 			print_wifi_head(statep);
2329*0ba2cbe9Sxc151355 	}
2330*0ba2cbe9Sxc151355 
2331*0ba2cbe9Sxc151355 	statep->ws_link = link;
2332*0ba2cbe9Sxc151355 	statep->ws_overflow = 0;
2333*0ba2cbe9Sxc151355 	for (i = 0; i < statep->ws_nfields; i++) {
2334*0ba2cbe9Sxc151355 		statep->ws_lastfield = (i + 1 == statep->ws_nfields);
2335*0ba2cbe9Sxc151355 		print_link_attr(statep, statep->ws_fields[i], &attr);
2336*0ba2cbe9Sxc151355 	}
2337*0ba2cbe9Sxc151355 	(void) putchar('\n');
2338*0ba2cbe9Sxc151355 	return (B_TRUE);
2339*0ba2cbe9Sxc151355 }
2340*0ba2cbe9Sxc151355 
2341*0ba2cbe9Sxc151355 static void
2342*0ba2cbe9Sxc151355 do_display_wifi(int argc, char **argv, int cmd)
2343*0ba2cbe9Sxc151355 {
2344*0ba2cbe9Sxc151355 	int			option;
2345*0ba2cbe9Sxc151355 	char 			errmsg[WLADM_STRSIZE];
2346*0ba2cbe9Sxc151355 	char			*fields_str = NULL;
2347*0ba2cbe9Sxc151355 	wifi_field_t		**fields;
2348*0ba2cbe9Sxc151355 	boolean_t		(*callback)(void *, const char *);
2349*0ba2cbe9Sxc151355 	uint_t			nfields;
2350*0ba2cbe9Sxc151355 	print_wifi_state_t	state;
2351*0ba2cbe9Sxc151355 	wladm_status_t		status;
2352*0ba2cbe9Sxc151355 
2353*0ba2cbe9Sxc151355 	if (cmd == WIFI_CMD_SCAN)
2354*0ba2cbe9Sxc151355 		callback = scan_wifi;
2355*0ba2cbe9Sxc151355 	else if (cmd == WIFI_CMD_SHOW)
2356*0ba2cbe9Sxc151355 		callback = show_wifi;
2357*0ba2cbe9Sxc151355 	else
2358*0ba2cbe9Sxc151355 		return;
2359*0ba2cbe9Sxc151355 
2360*0ba2cbe9Sxc151355 	state.ws_link = NULL;
2361*0ba2cbe9Sxc151355 	state.ws_parseable = B_FALSE;
2362*0ba2cbe9Sxc151355 	state.ws_header = B_TRUE;
2363*0ba2cbe9Sxc151355 	opterr = 0;
2364*0ba2cbe9Sxc151355 	while ((option = getopt_long(argc, argv, ":o:p",
2365*0ba2cbe9Sxc151355 	    wifi_longopts, NULL)) != -1) {
2366*0ba2cbe9Sxc151355 		switch (option) {
2367*0ba2cbe9Sxc151355 		case 'o':
2368*0ba2cbe9Sxc151355 			fields_str = optarg;
2369*0ba2cbe9Sxc151355 			break;
2370*0ba2cbe9Sxc151355 		case 'p':
2371*0ba2cbe9Sxc151355 			state.ws_parseable = B_TRUE;
2372*0ba2cbe9Sxc151355 			if (fields_str == NULL)
2373*0ba2cbe9Sxc151355 				fields_str = "all";
2374*0ba2cbe9Sxc151355 			break;
2375*0ba2cbe9Sxc151355 		case ':':
2376*0ba2cbe9Sxc151355 			(void) fprintf(stderr,
2377*0ba2cbe9Sxc151355 			    gettext("%s: option requires a value '-%c'\n"),
2378*0ba2cbe9Sxc151355 			    progname, optopt);
2379*0ba2cbe9Sxc151355 			exit(1);
2380*0ba2cbe9Sxc151355 			break;
2381*0ba2cbe9Sxc151355 		case '?':
2382*0ba2cbe9Sxc151355 		default:
2383*0ba2cbe9Sxc151355 			(void) fprintf(stderr,
2384*0ba2cbe9Sxc151355 			    gettext("%s: unrecognized option '-%c'\n"),
2385*0ba2cbe9Sxc151355 			    progname, optopt);
2386*0ba2cbe9Sxc151355 			exit(1);
2387*0ba2cbe9Sxc151355 			break;
2388*0ba2cbe9Sxc151355 		}
2389*0ba2cbe9Sxc151355 	}
2390*0ba2cbe9Sxc151355 
2391*0ba2cbe9Sxc151355 	if (optind == (argc - 1))
2392*0ba2cbe9Sxc151355 		state.ws_link = argv[optind];
2393*0ba2cbe9Sxc151355 	else if (optind != argc)
2394*0ba2cbe9Sxc151355 		usage();
2395*0ba2cbe9Sxc151355 
2396*0ba2cbe9Sxc151355 	if (parse_wifi_fields(fields_str, &fields, &nfields, cmd) < 0) {
2397*0ba2cbe9Sxc151355 		(void) fprintf(stderr,
2398*0ba2cbe9Sxc151355 		    gettext("%s: invalid field(s) specified\n"),
2399*0ba2cbe9Sxc151355 		    progname);
2400*0ba2cbe9Sxc151355 		exit(1);
2401*0ba2cbe9Sxc151355 	}
2402*0ba2cbe9Sxc151355 	state.ws_fields = fields;
2403*0ba2cbe9Sxc151355 	state.ws_nfields = nfields;
2404*0ba2cbe9Sxc151355 
2405*0ba2cbe9Sxc151355 	if (state.ws_link == NULL) {
2406*0ba2cbe9Sxc151355 		status = wladm_walk(&state, callback);
2407*0ba2cbe9Sxc151355 		if (status != WLADM_STATUS_OK) {
2408*0ba2cbe9Sxc151355 			(void) fprintf(stderr, gettext("%s: %s\n"),
2409*0ba2cbe9Sxc151355 			    progname, wladm_status2str(status, errmsg));
2410*0ba2cbe9Sxc151355 			exit(1);
2411*0ba2cbe9Sxc151355 		}
2412*0ba2cbe9Sxc151355 	} else {
2413*0ba2cbe9Sxc151355 		(void) (*callback)(&state, state.ws_link);
2414*0ba2cbe9Sxc151355 	}
2415*0ba2cbe9Sxc151355 	free(fields);
2416*0ba2cbe9Sxc151355 }
2417*0ba2cbe9Sxc151355 
2418*0ba2cbe9Sxc151355 static void
2419*0ba2cbe9Sxc151355 do_scan_wifi(int argc, char **argv)
2420*0ba2cbe9Sxc151355 {
2421*0ba2cbe9Sxc151355 	do_display_wifi(argc, argv, WIFI_CMD_SCAN);
2422*0ba2cbe9Sxc151355 }
2423*0ba2cbe9Sxc151355 
2424*0ba2cbe9Sxc151355 static void
2425*0ba2cbe9Sxc151355 do_show_wifi(int argc, char **argv)
2426*0ba2cbe9Sxc151355 {
2427*0ba2cbe9Sxc151355 	do_display_wifi(argc, argv, WIFI_CMD_SHOW);
2428*0ba2cbe9Sxc151355 }
2429*0ba2cbe9Sxc151355 
2430*0ba2cbe9Sxc151355 typedef struct wlan_count_attr {
2431*0ba2cbe9Sxc151355 	uint_t		wc_count;
2432*0ba2cbe9Sxc151355 	const char	*wc_link;
2433*0ba2cbe9Sxc151355 } wlan_count_attr_t;
2434*0ba2cbe9Sxc151355 
2435*0ba2cbe9Sxc151355 static boolean_t
2436*0ba2cbe9Sxc151355 do_count_wlan(void *arg, const char *link)
2437*0ba2cbe9Sxc151355 {
2438*0ba2cbe9Sxc151355 	wlan_count_attr_t	*cp = (wlan_count_attr_t *)arg;
2439*0ba2cbe9Sxc151355 
2440*0ba2cbe9Sxc151355 	if (cp->wc_count == 0)
2441*0ba2cbe9Sxc151355 		cp->wc_link = strdup(link);
2442*0ba2cbe9Sxc151355 	cp->wc_count++;
2443*0ba2cbe9Sxc151355 	return (B_TRUE);
2444*0ba2cbe9Sxc151355 }
2445*0ba2cbe9Sxc151355 
2446*0ba2cbe9Sxc151355 static int
2447*0ba2cbe9Sxc151355 parse_wep_keys(char *str, wladm_wep_key_t **keys, uint_t *key_countp)
2448*0ba2cbe9Sxc151355 {
2449*0ba2cbe9Sxc151355 	uint_t		i;
2450*0ba2cbe9Sxc151355 	split_t		*sp;
2451*0ba2cbe9Sxc151355 	wladm_wep_key_t	*wk;
2452*0ba2cbe9Sxc151355 
2453*0ba2cbe9Sxc151355 	sp = split(str, WLADM_MAX_WEPKEYS, WLADM_MAX_WEPKEYNAME_LEN);
2454*0ba2cbe9Sxc151355 	if (sp == NULL)
2455*0ba2cbe9Sxc151355 		return (-1);
2456*0ba2cbe9Sxc151355 
2457*0ba2cbe9Sxc151355 	wk = malloc(sp->s_nfields * sizeof (wladm_wep_key_t));
2458*0ba2cbe9Sxc151355 	if (wk == NULL)
2459*0ba2cbe9Sxc151355 		goto fail;
2460*0ba2cbe9Sxc151355 
2461*0ba2cbe9Sxc151355 	for (i = 0; i < sp->s_nfields; i++) {
2462*0ba2cbe9Sxc151355 		char			*s;
2463*0ba2cbe9Sxc151355 		dladm_secobj_class_t	class;
2464*0ba2cbe9Sxc151355 		dladm_status_t		status;
2465*0ba2cbe9Sxc151355 
2466*0ba2cbe9Sxc151355 		(void) strlcpy(wk[i].wk_name, sp->s_fields[i],
2467*0ba2cbe9Sxc151355 		    WLADM_MAX_WEPKEYNAME_LEN);
2468*0ba2cbe9Sxc151355 
2469*0ba2cbe9Sxc151355 		wk[i].wk_idx = 1;
2470*0ba2cbe9Sxc151355 		if ((s = strrchr(wk[i].wk_name, ':')) != NULL) {
2471*0ba2cbe9Sxc151355 			if (s[1] == '\0' || s[2] != '\0' || !isdigit(s[1]))
2472*0ba2cbe9Sxc151355 				goto fail;
2473*0ba2cbe9Sxc151355 
2474*0ba2cbe9Sxc151355 			wk[i].wk_idx = (uint_t)(s[1] - '0');
2475*0ba2cbe9Sxc151355 			*s = '\0';
2476*0ba2cbe9Sxc151355 		}
2477*0ba2cbe9Sxc151355 		wk[i].wk_len = WLADM_MAX_WEPKEY_LEN;
2478*0ba2cbe9Sxc151355 
2479*0ba2cbe9Sxc151355 		status = dladm_get_secobj(wk[i].wk_name, &class,
2480*0ba2cbe9Sxc151355 		    wk[i].wk_val, &wk[i].wk_len, 0);
2481*0ba2cbe9Sxc151355 		if (status != DLADM_STATUS_OK) {
2482*0ba2cbe9Sxc151355 			if (status == DLADM_STATUS_NOTFOUND) {
2483*0ba2cbe9Sxc151355 				status = dladm_get_secobj(wk[i].wk_name,
2484*0ba2cbe9Sxc151355 				    &class, wk[i].wk_val, &wk[i].wk_len,
2485*0ba2cbe9Sxc151355 				    DLADM_OPT_PERSIST);
2486*0ba2cbe9Sxc151355 			}
2487*0ba2cbe9Sxc151355 			if (status != DLADM_STATUS_OK)
2488*0ba2cbe9Sxc151355 				goto fail;
2489*0ba2cbe9Sxc151355 		}
2490*0ba2cbe9Sxc151355 	}
2491*0ba2cbe9Sxc151355 	*keys = wk;
2492*0ba2cbe9Sxc151355 	*key_countp = i;
2493*0ba2cbe9Sxc151355 	splitfree(sp);
2494*0ba2cbe9Sxc151355 	return (0);
2495*0ba2cbe9Sxc151355 fail:
2496*0ba2cbe9Sxc151355 	free(wk);
2497*0ba2cbe9Sxc151355 	splitfree(sp);
2498*0ba2cbe9Sxc151355 	return (-1);
2499*0ba2cbe9Sxc151355 }
2500*0ba2cbe9Sxc151355 
2501*0ba2cbe9Sxc151355 static void
2502*0ba2cbe9Sxc151355 do_connect_wifi(int argc, char **argv)
2503*0ba2cbe9Sxc151355 {
2504*0ba2cbe9Sxc151355 	int			option;
2505*0ba2cbe9Sxc151355 	wladm_wlan_attr_t	attr, *attrp;
2506*0ba2cbe9Sxc151355 	wladm_status_t		status = WLADM_STATUS_OK;
2507*0ba2cbe9Sxc151355 	int			timeout = WLADM_CONNECT_TIMEOUT_DEFAULT;
2508*0ba2cbe9Sxc151355 	char			errmsg[WLADM_STRSIZE];
2509*0ba2cbe9Sxc151355 	const char		*link = NULL;
2510*0ba2cbe9Sxc151355 	char			*endp = NULL;
2511*0ba2cbe9Sxc151355 	wladm_wep_key_t		*keys = NULL;
2512*0ba2cbe9Sxc151355 	uint_t			key_count = 0;
2513*0ba2cbe9Sxc151355 	uint_t			flags = 0;
2514*0ba2cbe9Sxc151355 	wladm_secmode_t		keysecmode = WLADM_SECMODE_NONE;
2515*0ba2cbe9Sxc151355 
2516*0ba2cbe9Sxc151355 	opterr = 0;
2517*0ba2cbe9Sxc151355 	(void) memset(&attr, 0, sizeof (attr));
2518*0ba2cbe9Sxc151355 	while ((option = getopt_long(argc, argv, ":e:i:a:m:b:s:k:T:c",
2519*0ba2cbe9Sxc151355 	    wifi_longopts, NULL)) != -1) {
2520*0ba2cbe9Sxc151355 		switch (option) {
2521*0ba2cbe9Sxc151355 		case 'e':
2522*0ba2cbe9Sxc151355 			status = wladm_str2essid(optarg, &attr.wa_essid);
2523*0ba2cbe9Sxc151355 			if (status != WLADM_STATUS_OK) {
2524*0ba2cbe9Sxc151355 				(void) fprintf(stderr,
2525*0ba2cbe9Sxc151355 				    gettext("%s: invalid ESSID '%s'\n"),
2526*0ba2cbe9Sxc151355 				    progname, optarg);
2527*0ba2cbe9Sxc151355 				exit(1);
2528*0ba2cbe9Sxc151355 			}
2529*0ba2cbe9Sxc151355 			attr.wa_valid |= WLADM_WLAN_ATTR_ESSID;
2530*0ba2cbe9Sxc151355 			/*
2531*0ba2cbe9Sxc151355 			 * Try to connect without doing a scan.
2532*0ba2cbe9Sxc151355 			 */
2533*0ba2cbe9Sxc151355 			flags |= WLADM_OPT_NOSCAN;
2534*0ba2cbe9Sxc151355 			break;
2535*0ba2cbe9Sxc151355 		case 'i':
2536*0ba2cbe9Sxc151355 			status = wladm_str2bssid(optarg, &attr.wa_bssid);
2537*0ba2cbe9Sxc151355 			if (status != WLADM_STATUS_OK) {
2538*0ba2cbe9Sxc151355 				(void) fprintf(stderr,
2539*0ba2cbe9Sxc151355 				    gettext("%s: invalid BSSID %s\n"),
2540*0ba2cbe9Sxc151355 				    progname, optarg);
2541*0ba2cbe9Sxc151355 				exit(1);
2542*0ba2cbe9Sxc151355 			}
2543*0ba2cbe9Sxc151355 			attr.wa_valid |= WLADM_WLAN_ATTR_BSSID;
2544*0ba2cbe9Sxc151355 			break;
2545*0ba2cbe9Sxc151355 		case 'a':
2546*0ba2cbe9Sxc151355 			status = wladm_str2auth(optarg, &attr.wa_auth);
2547*0ba2cbe9Sxc151355 			if (status != WLADM_STATUS_OK) {
2548*0ba2cbe9Sxc151355 				(void) fprintf(stderr,
2549*0ba2cbe9Sxc151355 				    gettext("%s: invalid authentication "
2550*0ba2cbe9Sxc151355 					"mode '%s'\n"), progname, optarg);
2551*0ba2cbe9Sxc151355 				exit(1);
2552*0ba2cbe9Sxc151355 			}
2553*0ba2cbe9Sxc151355 			attr.wa_valid |= WLADM_WLAN_ATTR_AUTH;
2554*0ba2cbe9Sxc151355 			break;
2555*0ba2cbe9Sxc151355 		case 'm':
2556*0ba2cbe9Sxc151355 			status = wladm_str2mode(optarg, &attr.wa_mode);
2557*0ba2cbe9Sxc151355 			if (status != WLADM_STATUS_OK) {
2558*0ba2cbe9Sxc151355 				(void) fprintf(stderr,
2559*0ba2cbe9Sxc151355 				    gettext("%s: invalid mode '%s'\n"),
2560*0ba2cbe9Sxc151355 				    progname, optarg);
2561*0ba2cbe9Sxc151355 				exit(1);
2562*0ba2cbe9Sxc151355 			}
2563*0ba2cbe9Sxc151355 			attr.wa_valid |= WLADM_WLAN_ATTR_MODE;
2564*0ba2cbe9Sxc151355 			break;
2565*0ba2cbe9Sxc151355 		case 'b':
2566*0ba2cbe9Sxc151355 			status = wladm_str2bsstype(optarg, &attr.wa_bsstype);
2567*0ba2cbe9Sxc151355 			if (status != WLADM_STATUS_OK) {
2568*0ba2cbe9Sxc151355 				(void) fprintf(stderr,
2569*0ba2cbe9Sxc151355 				    gettext("%s: invalid bsstype '%s'\n"),
2570*0ba2cbe9Sxc151355 				    progname, optarg);
2571*0ba2cbe9Sxc151355 				exit(1);
2572*0ba2cbe9Sxc151355 			}
2573*0ba2cbe9Sxc151355 			attr.wa_valid |= WLADM_WLAN_ATTR_BSSTYPE;
2574*0ba2cbe9Sxc151355 			break;
2575*0ba2cbe9Sxc151355 		case 's':
2576*0ba2cbe9Sxc151355 			status = wladm_str2secmode(optarg, &attr.wa_secmode);
2577*0ba2cbe9Sxc151355 			if (status != WLADM_STATUS_OK) {
2578*0ba2cbe9Sxc151355 				(void) fprintf(stderr,
2579*0ba2cbe9Sxc151355 				    gettext("%s: invalid security mode '%s'\n"),
2580*0ba2cbe9Sxc151355 				    progname, optarg);
2581*0ba2cbe9Sxc151355 				exit(1);
2582*0ba2cbe9Sxc151355 			}
2583*0ba2cbe9Sxc151355 			attr.wa_valid |= WLADM_WLAN_ATTR_SECMODE;
2584*0ba2cbe9Sxc151355 			break;
2585*0ba2cbe9Sxc151355 		case 'k':
2586*0ba2cbe9Sxc151355 			if (parse_wep_keys(optarg, &keys, &key_count) < 0) {
2587*0ba2cbe9Sxc151355 				(void) fprintf(stderr,
2588*0ba2cbe9Sxc151355 				    gettext("%s: invalid key(s) '%s'\n"),
2589*0ba2cbe9Sxc151355 				    progname, optarg);
2590*0ba2cbe9Sxc151355 				exit(1);
2591*0ba2cbe9Sxc151355 			}
2592*0ba2cbe9Sxc151355 			keysecmode = WLADM_SECMODE_WEP;
2593*0ba2cbe9Sxc151355 			break;
2594*0ba2cbe9Sxc151355 		case 'T':
2595*0ba2cbe9Sxc151355 			if (strcasecmp(optarg, "forever") == 0) {
2596*0ba2cbe9Sxc151355 				timeout = -1;
2597*0ba2cbe9Sxc151355 				break;
2598*0ba2cbe9Sxc151355 			}
2599*0ba2cbe9Sxc151355 			errno = 0;
2600*0ba2cbe9Sxc151355 			timeout = (int)strtol(optarg, &endp, 10);
2601*0ba2cbe9Sxc151355 			if (timeout < 0 || errno != 0 || *endp != '\0') {
2602*0ba2cbe9Sxc151355 				(void) fprintf(stderr,
2603*0ba2cbe9Sxc151355 				    gettext("%s: invalid timeout value '%s'\n"),
2604*0ba2cbe9Sxc151355 				    progname, optarg);
2605*0ba2cbe9Sxc151355 				exit(1);
2606*0ba2cbe9Sxc151355 			}
2607*0ba2cbe9Sxc151355 			break;
2608*0ba2cbe9Sxc151355 		case 'c':
2609*0ba2cbe9Sxc151355 			flags |= WLADM_OPT_CREATEIBSS;
2610*0ba2cbe9Sxc151355 			break;
2611*0ba2cbe9Sxc151355 		case ':':
2612*0ba2cbe9Sxc151355 			(void) fprintf(stderr,
2613*0ba2cbe9Sxc151355 			    gettext("%s: option requires a value '-%c'\n"),
2614*0ba2cbe9Sxc151355 			    progname, optopt);
2615*0ba2cbe9Sxc151355 			exit(1);
2616*0ba2cbe9Sxc151355 			break;
2617*0ba2cbe9Sxc151355 		case '?':
2618*0ba2cbe9Sxc151355 		default:
2619*0ba2cbe9Sxc151355 			(void) fprintf(stderr,
2620*0ba2cbe9Sxc151355 			    gettext("%s: unrecognized option '-%c'\n"),
2621*0ba2cbe9Sxc151355 			    progname, optopt);
2622*0ba2cbe9Sxc151355 			exit(1);
2623*0ba2cbe9Sxc151355 			break;
2624*0ba2cbe9Sxc151355 		}
2625*0ba2cbe9Sxc151355 	}
2626*0ba2cbe9Sxc151355 
2627*0ba2cbe9Sxc151355 	if (keysecmode == WLADM_SECMODE_NONE) {
2628*0ba2cbe9Sxc151355 		if ((attr.wa_valid & WLADM_WLAN_ATTR_SECMODE) != 0 &&
2629*0ba2cbe9Sxc151355 		    attr.wa_secmode == WLADM_SECMODE_WEP) {
2630*0ba2cbe9Sxc151355 			(void) fprintf(stderr,
2631*0ba2cbe9Sxc151355 			    gettext("%s: key required for security mode "
2632*0ba2cbe9Sxc151355 				"'wep'\n"), progname);
2633*0ba2cbe9Sxc151355 			exit(1);
2634*0ba2cbe9Sxc151355 		}
2635*0ba2cbe9Sxc151355 	} else {
2636*0ba2cbe9Sxc151355 		if ((attr.wa_valid & WLADM_WLAN_ATTR_SECMODE) != 0 &&
2637*0ba2cbe9Sxc151355 		    attr.wa_secmode != keysecmode) {
2638*0ba2cbe9Sxc151355 			(void) fprintf(stderr,
2639*0ba2cbe9Sxc151355 			    gettext("%s: incompatible -s and -k options\n"),
2640*0ba2cbe9Sxc151355 			    progname);
2641*0ba2cbe9Sxc151355 			exit(1);
2642*0ba2cbe9Sxc151355 		}
2643*0ba2cbe9Sxc151355 	}
2644*0ba2cbe9Sxc151355 	attr.wa_secmode = keysecmode;
2645*0ba2cbe9Sxc151355 	attr.wa_valid |= WLADM_WLAN_ATTR_SECMODE;
2646*0ba2cbe9Sxc151355 
2647*0ba2cbe9Sxc151355 	if (optind == (argc - 1))
2648*0ba2cbe9Sxc151355 		link = argv[optind];
2649*0ba2cbe9Sxc151355 	else if (optind != argc)
2650*0ba2cbe9Sxc151355 		usage();
2651*0ba2cbe9Sxc151355 
2652*0ba2cbe9Sxc151355 	if (link == NULL) {
2653*0ba2cbe9Sxc151355 		wlan_count_attr_t wcattr;
2654*0ba2cbe9Sxc151355 
2655*0ba2cbe9Sxc151355 		wcattr.wc_link = NULL;
2656*0ba2cbe9Sxc151355 		wcattr.wc_count = 0;
2657*0ba2cbe9Sxc151355 		(void) wladm_walk(&wcattr, do_count_wlan);
2658*0ba2cbe9Sxc151355 		if (wcattr.wc_count == 0) {
2659*0ba2cbe9Sxc151355 			(void) fprintf(stderr, gettext(
2660*0ba2cbe9Sxc151355 			    "%s: no wifi links are available\n"), progname);
2661*0ba2cbe9Sxc151355 			exit(1);
2662*0ba2cbe9Sxc151355 		} else if (wcattr.wc_count > 1) {
2663*0ba2cbe9Sxc151355 			(void) fprintf(stderr, gettext(
2664*0ba2cbe9Sxc151355 			    "%s: link name is required when more than "
2665*0ba2cbe9Sxc151355 			    "one link is available\n"), progname);
2666*0ba2cbe9Sxc151355 			exit(1);
2667*0ba2cbe9Sxc151355 		}
2668*0ba2cbe9Sxc151355 		link = wcattr.wc_link;
2669*0ba2cbe9Sxc151355 	}
2670*0ba2cbe9Sxc151355 	attrp = (attr.wa_valid == 0) ? NULL : &attr;
2671*0ba2cbe9Sxc151355 
2672*0ba2cbe9Sxc151355 	status = wladm_connect(link, attrp, timeout, keys, key_count, flags);
2673*0ba2cbe9Sxc151355 	if (status != WLADM_STATUS_OK) {
2674*0ba2cbe9Sxc151355 		if ((flags & WLADM_OPT_NOSCAN) != 0) {
2675*0ba2cbe9Sxc151355 			/*
2676*0ba2cbe9Sxc151355 			 * Redo the connect. This time with scanning
2677*0ba2cbe9Sxc151355 			 * and filtering.
2678*0ba2cbe9Sxc151355 			 */
2679*0ba2cbe9Sxc151355 			flags &= ~WLADM_OPT_NOSCAN;
2680*0ba2cbe9Sxc151355 			status = wladm_connect(link, attrp, timeout, keys,
2681*0ba2cbe9Sxc151355 			    key_count, flags);
2682*0ba2cbe9Sxc151355 			if (status == WLADM_STATUS_OK) {
2683*0ba2cbe9Sxc151355 				free(keys);
2684*0ba2cbe9Sxc151355 				return;
2685*0ba2cbe9Sxc151355 			}
2686*0ba2cbe9Sxc151355 		}
2687*0ba2cbe9Sxc151355 		if (status == WLADM_STATUS_NOTFOUND) {
2688*0ba2cbe9Sxc151355 			if (attr.wa_valid == 0) {
2689*0ba2cbe9Sxc151355 				(void) fprintf(stderr, gettext(
2690*0ba2cbe9Sxc151355 				    "%s: no wifi networks are available\n"),
2691*0ba2cbe9Sxc151355 				    progname);
2692*0ba2cbe9Sxc151355 			} else {
2693*0ba2cbe9Sxc151355 				(void) fprintf(stderr, gettext("%s: no wifi "
2694*0ba2cbe9Sxc151355 				    "networks with the specified criteria "
2695*0ba2cbe9Sxc151355 				    "are available\n"), progname);
2696*0ba2cbe9Sxc151355 			}
2697*0ba2cbe9Sxc151355 		} else {
2698*0ba2cbe9Sxc151355 			(void) fprintf(stderr, gettext("%s: cannot connect: %s"
2699*0ba2cbe9Sxc151355 			    "\n"), progname, wladm_status2str(status, errmsg));
2700*0ba2cbe9Sxc151355 		}
2701*0ba2cbe9Sxc151355 		exit(1);
2702*0ba2cbe9Sxc151355 	}
2703*0ba2cbe9Sxc151355 	free(keys);
2704*0ba2cbe9Sxc151355 }
2705*0ba2cbe9Sxc151355 
2706*0ba2cbe9Sxc151355 /* ARGSUSED */
2707*0ba2cbe9Sxc151355 static boolean_t
2708*0ba2cbe9Sxc151355 do_all_disconnect_wifi(void *arg, const char *link)
2709*0ba2cbe9Sxc151355 {
2710*0ba2cbe9Sxc151355 	wladm_status_t	status;
2711*0ba2cbe9Sxc151355 	char		errmsg[WLADM_STRSIZE];
2712*0ba2cbe9Sxc151355 
2713*0ba2cbe9Sxc151355 	status = wladm_disconnect(link);
2714*0ba2cbe9Sxc151355 	if (status != WLADM_STATUS_OK) {
2715*0ba2cbe9Sxc151355 		(void) fprintf(stderr,
2716*0ba2cbe9Sxc151355 		    gettext("%s: cannot disconnect link '%s': %s\n"),
2717*0ba2cbe9Sxc151355 		    progname, link, wladm_status2str(status, errmsg));
2718*0ba2cbe9Sxc151355 	}
2719*0ba2cbe9Sxc151355 	return (B_TRUE);
2720*0ba2cbe9Sxc151355 }
2721*0ba2cbe9Sxc151355 
2722*0ba2cbe9Sxc151355 static void
2723*0ba2cbe9Sxc151355 do_disconnect_wifi(int argc, char **argv)
2724*0ba2cbe9Sxc151355 {
2725*0ba2cbe9Sxc151355 	int			option;
2726*0ba2cbe9Sxc151355 	const char		*link = NULL;
2727*0ba2cbe9Sxc151355 	char 			errmsg[WLADM_STRSIZE];
2728*0ba2cbe9Sxc151355 	boolean_t		all_links = B_FALSE;
2729*0ba2cbe9Sxc151355 	wladm_status_t		status;
2730*0ba2cbe9Sxc151355 	wlan_count_attr_t	wcattr;
2731*0ba2cbe9Sxc151355 
2732*0ba2cbe9Sxc151355 	opterr = 0;
2733*0ba2cbe9Sxc151355 	while ((option = getopt_long(argc, argv, ":a",
2734*0ba2cbe9Sxc151355 	    wifi_longopts, NULL)) != -1) {
2735*0ba2cbe9Sxc151355 		switch (option) {
2736*0ba2cbe9Sxc151355 		case 'a':
2737*0ba2cbe9Sxc151355 			all_links = B_TRUE;
2738*0ba2cbe9Sxc151355 			break;
2739*0ba2cbe9Sxc151355 		case ':':
2740*0ba2cbe9Sxc151355 			(void) fprintf(stderr,
2741*0ba2cbe9Sxc151355 			    gettext("%s: option requires a value '-%c'\n"),
2742*0ba2cbe9Sxc151355 			    progname, optopt);
2743*0ba2cbe9Sxc151355 			exit(1);
2744*0ba2cbe9Sxc151355 			break;
2745*0ba2cbe9Sxc151355 		case '?':
2746*0ba2cbe9Sxc151355 		default:
2747*0ba2cbe9Sxc151355 			(void) fprintf(stderr,
2748*0ba2cbe9Sxc151355 			    gettext("%s: unrecognized option '-%c'\n"),
2749*0ba2cbe9Sxc151355 			    progname, optopt);
2750*0ba2cbe9Sxc151355 			exit(1);
2751*0ba2cbe9Sxc151355 			break;
2752*0ba2cbe9Sxc151355 		}
2753*0ba2cbe9Sxc151355 	}
2754*0ba2cbe9Sxc151355 
2755*0ba2cbe9Sxc151355 	if (optind == (argc - 1))
2756*0ba2cbe9Sxc151355 		link = argv[optind];
2757*0ba2cbe9Sxc151355 	else if (optind != argc)
2758*0ba2cbe9Sxc151355 		usage();
2759*0ba2cbe9Sxc151355 
2760*0ba2cbe9Sxc151355 	if (link == NULL) {
2761*0ba2cbe9Sxc151355 		if (!all_links) {
2762*0ba2cbe9Sxc151355 			wcattr.wc_link = NULL;
2763*0ba2cbe9Sxc151355 			wcattr.wc_count = 0;
2764*0ba2cbe9Sxc151355 			(void) wladm_walk(&wcattr, do_count_wlan);
2765*0ba2cbe9Sxc151355 			if (wcattr.wc_count == 0) {
2766*0ba2cbe9Sxc151355 				(void) fprintf(stderr, gettext(
2767*0ba2cbe9Sxc151355 				    "%s: no wifi links are available\n"),
2768*0ba2cbe9Sxc151355 				    progname);
2769*0ba2cbe9Sxc151355 				exit(1);
2770*0ba2cbe9Sxc151355 			} else if (wcattr.wc_count > 1) {
2771*0ba2cbe9Sxc151355 				(void) fprintf(stderr, gettext(
2772*0ba2cbe9Sxc151355 				    "%s: link name is required when more than "
2773*0ba2cbe9Sxc151355 				    "one link is available\n"), progname);
2774*0ba2cbe9Sxc151355 				exit(1);
2775*0ba2cbe9Sxc151355 			}
2776*0ba2cbe9Sxc151355 			link = wcattr.wc_link;
2777*0ba2cbe9Sxc151355 		} else {
2778*0ba2cbe9Sxc151355 			(void) wladm_walk(&all_links, do_all_disconnect_wifi);
2779*0ba2cbe9Sxc151355 			return;
2780*0ba2cbe9Sxc151355 		}
2781*0ba2cbe9Sxc151355 	}
2782*0ba2cbe9Sxc151355 	status = wladm_disconnect(link);
2783*0ba2cbe9Sxc151355 	if (status != WLADM_STATUS_OK) {
2784*0ba2cbe9Sxc151355 		(void) fprintf(stderr, gettext("%s: cannot disconnect: %s\n"),
2785*0ba2cbe9Sxc151355 		    progname, wladm_status2str(status, errmsg));
2786*0ba2cbe9Sxc151355 		exit(1);
2787*0ba2cbe9Sxc151355 	}
2788*0ba2cbe9Sxc151355 }
2789*0ba2cbe9Sxc151355 
2790*0ba2cbe9Sxc151355 #define	MAX_PROPS		32
2791*0ba2cbe9Sxc151355 #define	MAX_PROP_VALS		32
2792*0ba2cbe9Sxc151355 #define	MAX_PROP_LINE		512
2793*0ba2cbe9Sxc151355 
2794*0ba2cbe9Sxc151355 typedef struct prop_info {
2795*0ba2cbe9Sxc151355 	char		*pi_name;
2796*0ba2cbe9Sxc151355 	char		*pi_val[MAX_PROP_VALS];
2797*0ba2cbe9Sxc151355 	uint_t		pi_count;
2798*0ba2cbe9Sxc151355 } prop_info_t;
2799*0ba2cbe9Sxc151355 
2800*0ba2cbe9Sxc151355 typedef struct prop_list {
2801*0ba2cbe9Sxc151355 	prop_info_t	pl_info[MAX_PROPS];
2802*0ba2cbe9Sxc151355 	uint_t		pl_count;
2803*0ba2cbe9Sxc151355 	char		*pl_buf;
2804*0ba2cbe9Sxc151355 } prop_list_t;
2805*0ba2cbe9Sxc151355 
2806*0ba2cbe9Sxc151355 typedef struct show_linkprop_state {
2807*0ba2cbe9Sxc151355 	const char	*ls_link;
2808*0ba2cbe9Sxc151355 	char		*ls_line;
2809*0ba2cbe9Sxc151355 	char		**ls_propvals;
2810*0ba2cbe9Sxc151355 	boolean_t	ls_parseable;
2811*0ba2cbe9Sxc151355 	boolean_t	ls_persist;
2812*0ba2cbe9Sxc151355 	boolean_t	ls_header;
2813*0ba2cbe9Sxc151355 } show_linkprop_state_t;
2814*0ba2cbe9Sxc151355 
2815*0ba2cbe9Sxc151355 static void
2816*0ba2cbe9Sxc151355 free_props(prop_list_t *list)
2817*0ba2cbe9Sxc151355 {
2818*0ba2cbe9Sxc151355 	if (list != NULL) {
2819*0ba2cbe9Sxc151355 		free(list->pl_buf);
2820*0ba2cbe9Sxc151355 		free(list);
2821*0ba2cbe9Sxc151355 	}
2822*0ba2cbe9Sxc151355 }
2823*0ba2cbe9Sxc151355 
2824*0ba2cbe9Sxc151355 static int
2825*0ba2cbe9Sxc151355 parse_props(char *str, prop_list_t **listp, boolean_t novalues)
2826*0ba2cbe9Sxc151355 {
2827*0ba2cbe9Sxc151355 	prop_list_t	*list;
2828*0ba2cbe9Sxc151355 	prop_info_t	*pip;
2829*0ba2cbe9Sxc151355 	char		*buf, *curr;
2830*0ba2cbe9Sxc151355 	int		len, i;
2831*0ba2cbe9Sxc151355 
2832*0ba2cbe9Sxc151355 	list = malloc(sizeof (prop_list_t));
2833*0ba2cbe9Sxc151355 	if (list == NULL)
2834*0ba2cbe9Sxc151355 		return (-1);
2835*0ba2cbe9Sxc151355 
2836*0ba2cbe9Sxc151355 	list->pl_count = 0;
2837*0ba2cbe9Sxc151355 	list->pl_buf = buf = strdup(str);
2838*0ba2cbe9Sxc151355 	if (buf == NULL)
2839*0ba2cbe9Sxc151355 		goto fail;
2840*0ba2cbe9Sxc151355 
2841*0ba2cbe9Sxc151355 	curr = buf;
2842*0ba2cbe9Sxc151355 	len = strlen(buf);
2843*0ba2cbe9Sxc151355 	pip = NULL;
2844*0ba2cbe9Sxc151355 	for (i = 0; i < len; i++) {
2845*0ba2cbe9Sxc151355 		char		c = buf[i];
2846*0ba2cbe9Sxc151355 		boolean_t	match = (c == '=' || c == ',');
2847*0ba2cbe9Sxc151355 
2848*0ba2cbe9Sxc151355 		if (!match && i != len - 1)
2849*0ba2cbe9Sxc151355 			continue;
2850*0ba2cbe9Sxc151355 
2851*0ba2cbe9Sxc151355 		if (match) {
2852*0ba2cbe9Sxc151355 			buf[i] = '\0';
2853*0ba2cbe9Sxc151355 			if (*curr == '\0')
2854*0ba2cbe9Sxc151355 				goto fail;
2855*0ba2cbe9Sxc151355 		}
2856*0ba2cbe9Sxc151355 
2857*0ba2cbe9Sxc151355 		if (pip != NULL && c != '=') {
2858*0ba2cbe9Sxc151355 			if (pip->pi_count > MAX_PROP_VALS)
2859*0ba2cbe9Sxc151355 				goto fail;
2860*0ba2cbe9Sxc151355 
2861*0ba2cbe9Sxc151355 			if (novalues)
2862*0ba2cbe9Sxc151355 				goto fail;
2863*0ba2cbe9Sxc151355 
2864*0ba2cbe9Sxc151355 			pip->pi_val[pip->pi_count] = curr;
2865*0ba2cbe9Sxc151355 			pip->pi_count++;
2866*0ba2cbe9Sxc151355 		} else {
2867*0ba2cbe9Sxc151355 			if (list->pl_count > MAX_PROPS)
2868*0ba2cbe9Sxc151355 				goto fail;
2869*0ba2cbe9Sxc151355 
2870*0ba2cbe9Sxc151355 			pip = &list->pl_info[list->pl_count];
2871*0ba2cbe9Sxc151355 			pip->pi_name = curr;
2872*0ba2cbe9Sxc151355 			pip->pi_count = 0;
2873*0ba2cbe9Sxc151355 			list->pl_count++;
2874*0ba2cbe9Sxc151355 			if (c == ',')
2875*0ba2cbe9Sxc151355 				pip = NULL;
2876*0ba2cbe9Sxc151355 		}
2877*0ba2cbe9Sxc151355 		curr = buf + i + 1;
2878*0ba2cbe9Sxc151355 	}
2879*0ba2cbe9Sxc151355 	*listp = list;
2880*0ba2cbe9Sxc151355 	return (0);
2881*0ba2cbe9Sxc151355 
2882*0ba2cbe9Sxc151355 fail:
2883*0ba2cbe9Sxc151355 	free_props(list);
2884*0ba2cbe9Sxc151355 	return (-1);
2885*0ba2cbe9Sxc151355 }
2886*0ba2cbe9Sxc151355 
2887*0ba2cbe9Sxc151355 static void
2888*0ba2cbe9Sxc151355 print_linkprop_head(void)
2889*0ba2cbe9Sxc151355 {
2890*0ba2cbe9Sxc151355 	(void) printf("%-15s %-14s %-14s %-30s \n",
2891*0ba2cbe9Sxc151355 	    "PROPERTY", "VALUE", "DEFAULT", "POSSIBLE");
2892*0ba2cbe9Sxc151355 }
2893*0ba2cbe9Sxc151355 
2894*0ba2cbe9Sxc151355 static void
2895*0ba2cbe9Sxc151355 print_linkprop(show_linkprop_state_t *statep, const char *propname,
2896*0ba2cbe9Sxc151355     dladm_prop_type_t type, const char *typename, const char *format,
2897*0ba2cbe9Sxc151355     char **pptr)
2898*0ba2cbe9Sxc151355 {
2899*0ba2cbe9Sxc151355 	int		i;
2900*0ba2cbe9Sxc151355 	char		*ptr, *lim;
2901*0ba2cbe9Sxc151355 	char		buf[DLADM_STRSIZE];
2902*0ba2cbe9Sxc151355 	char		*unknown = "?", *notsup = "";
2903*0ba2cbe9Sxc151355 	char		**propvals = statep->ls_propvals;
2904*0ba2cbe9Sxc151355 	uint_t		valcnt = MAX_PROP_VALS;
2905*0ba2cbe9Sxc151355 	dladm_status_t	status;
2906*0ba2cbe9Sxc151355 
2907*0ba2cbe9Sxc151355 	status = dladm_get_prop(statep->ls_link, type, propname,
2908*0ba2cbe9Sxc151355 	    propvals, &valcnt);
2909*0ba2cbe9Sxc151355 	if (status != DLADM_STATUS_OK) {
2910*0ba2cbe9Sxc151355 		if (status == DLADM_STATUS_NOTSUP || statep->ls_persist) {
2911*0ba2cbe9Sxc151355 			valcnt = 1;
2912*0ba2cbe9Sxc151355 			if (type == DLADM_PROP_VAL_CURRENT)
2913*0ba2cbe9Sxc151355 				propvals = &unknown;
2914*0ba2cbe9Sxc151355 			else
2915*0ba2cbe9Sxc151355 				propvals = &notsup;
2916*0ba2cbe9Sxc151355 		} else {
2917*0ba2cbe9Sxc151355 			(void) fprintf(stderr, gettext(
2918*0ba2cbe9Sxc151355 			    "%s: cannot get link property '%s': %s\n"),
2919*0ba2cbe9Sxc151355 			    progname, propname, dladm_status2str(status, buf));
2920*0ba2cbe9Sxc151355 			exit(1);
2921*0ba2cbe9Sxc151355 		}
2922*0ba2cbe9Sxc151355 	}
2923*0ba2cbe9Sxc151355 
2924*0ba2cbe9Sxc151355 	ptr = buf;
2925*0ba2cbe9Sxc151355 	lim = buf + DLADM_STRSIZE;
2926*0ba2cbe9Sxc151355 	for (i = 0; i < valcnt; i++) {
2927*0ba2cbe9Sxc151355 		if (propvals[i][0] == '\0' && !statep->ls_parseable)
2928*0ba2cbe9Sxc151355 			ptr += snprintf(ptr, lim - ptr, "--,");
2929*0ba2cbe9Sxc151355 		else
2930*0ba2cbe9Sxc151355 			ptr += snprintf(ptr, lim - ptr, "%s,", propvals[i]);
2931*0ba2cbe9Sxc151355 		if (ptr >= lim)
2932*0ba2cbe9Sxc151355 			break;
2933*0ba2cbe9Sxc151355 	}
2934*0ba2cbe9Sxc151355 	if (valcnt > 0)
2935*0ba2cbe9Sxc151355 		buf[strlen(buf) - 1] = '\0';
2936*0ba2cbe9Sxc151355 
2937*0ba2cbe9Sxc151355 	lim = statep->ls_line + MAX_PROP_LINE;
2938*0ba2cbe9Sxc151355 	if (statep->ls_parseable) {
2939*0ba2cbe9Sxc151355 		*pptr += snprintf(*pptr, lim - *pptr,
2940*0ba2cbe9Sxc151355 		    "%s=\"%s\" ", typename, buf);
2941*0ba2cbe9Sxc151355 	} else {
2942*0ba2cbe9Sxc151355 		*pptr += snprintf(*pptr, lim - *pptr, format, buf);
2943*0ba2cbe9Sxc151355 	}
2944*0ba2cbe9Sxc151355 }
2945*0ba2cbe9Sxc151355 
2946*0ba2cbe9Sxc151355 static boolean_t
2947*0ba2cbe9Sxc151355 show_linkprop(void *arg, const char *propname)
2948*0ba2cbe9Sxc151355 {
2949*0ba2cbe9Sxc151355 	show_linkprop_state_t	*statep = arg;
2950*0ba2cbe9Sxc151355 	char			*ptr = statep->ls_line;
2951*0ba2cbe9Sxc151355 	char			*lim = ptr + MAX_PROP_LINE;
2952*0ba2cbe9Sxc151355 
2953*0ba2cbe9Sxc151355 	if (statep->ls_parseable)
2954*0ba2cbe9Sxc151355 		ptr += snprintf(ptr, lim - ptr, "PROPERTY=\"%s\" ", propname);
2955*0ba2cbe9Sxc151355 	else
2956*0ba2cbe9Sxc151355 		ptr += snprintf(ptr, lim - ptr, "%-15s ", propname);
2957*0ba2cbe9Sxc151355 
2958*0ba2cbe9Sxc151355 	print_linkprop(statep, propname,
2959*0ba2cbe9Sxc151355 	    statep->ls_persist ? DLADM_PROP_VAL_PERSISTENT :
2960*0ba2cbe9Sxc151355 	    DLADM_PROP_VAL_CURRENT, "VALUE", "%-14s ", &ptr);
2961*0ba2cbe9Sxc151355 	print_linkprop(statep, propname, DLADM_PROP_VAL_DEFAULT,
2962*0ba2cbe9Sxc151355 	    "DEFAULT", "%-14s ", &ptr);
2963*0ba2cbe9Sxc151355 	print_linkprop(statep, propname, DLADM_PROP_VAL_MODIFIABLE,
2964*0ba2cbe9Sxc151355 	    "POSSIBLE", "%-30s ", &ptr);
2965*0ba2cbe9Sxc151355 
2966*0ba2cbe9Sxc151355 	if (statep->ls_header) {
2967*0ba2cbe9Sxc151355 		statep->ls_header = B_FALSE;
2968*0ba2cbe9Sxc151355 		if (!statep->ls_parseable)
2969*0ba2cbe9Sxc151355 			print_linkprop_head();
2970*0ba2cbe9Sxc151355 	}
2971*0ba2cbe9Sxc151355 	(void) printf("%s\n", statep->ls_line);
2972*0ba2cbe9Sxc151355 	return (B_TRUE);
2973*0ba2cbe9Sxc151355 }
2974*0ba2cbe9Sxc151355 
2975*0ba2cbe9Sxc151355 static void
2976*0ba2cbe9Sxc151355 do_show_linkprop(int argc, char **argv)
2977*0ba2cbe9Sxc151355 {
2978*0ba2cbe9Sxc151355 	int			i, option, fd;
2979*0ba2cbe9Sxc151355 	char			errmsg[DLADM_STRSIZE];
2980*0ba2cbe9Sxc151355 	char			linkname[MAXPATHLEN];
2981*0ba2cbe9Sxc151355 	prop_list_t		*proplist = NULL;
2982*0ba2cbe9Sxc151355 	char			*buf;
2983*0ba2cbe9Sxc151355 	dladm_status_t		status;
2984*0ba2cbe9Sxc151355 	show_linkprop_state_t	state;
2985*0ba2cbe9Sxc151355 
2986*0ba2cbe9Sxc151355 	opterr = 0;
2987*0ba2cbe9Sxc151355 	state.ls_link = NULL;
2988*0ba2cbe9Sxc151355 	state.ls_propvals = NULL;
2989*0ba2cbe9Sxc151355 	state.ls_line = NULL;
2990*0ba2cbe9Sxc151355 	state.ls_parseable = B_FALSE;
2991*0ba2cbe9Sxc151355 	state.ls_persist = B_FALSE;
2992*0ba2cbe9Sxc151355 	state.ls_header = B_TRUE;
2993*0ba2cbe9Sxc151355 	while ((option = getopt_long(argc, argv, ":p:cP",
2994*0ba2cbe9Sxc151355 	    prop_longopts, NULL)) != -1) {
2995*0ba2cbe9Sxc151355 		switch (option) {
2996*0ba2cbe9Sxc151355 		case 'p':
2997*0ba2cbe9Sxc151355 			if (parse_props(optarg, &proplist, B_TRUE) < 0) {
2998*0ba2cbe9Sxc151355 				(void) fprintf(stderr,
2999*0ba2cbe9Sxc151355 				    gettext("%s: invalid field(s) specified\n"),
3000*0ba2cbe9Sxc151355 				    progname);
3001*0ba2cbe9Sxc151355 				exit(1);
3002*0ba2cbe9Sxc151355 			}
3003*0ba2cbe9Sxc151355 			break;
3004*0ba2cbe9Sxc151355 		case 'c':
3005*0ba2cbe9Sxc151355 			state.ls_parseable = B_TRUE;
3006*0ba2cbe9Sxc151355 			break;
3007*0ba2cbe9Sxc151355 		case 'P':
3008*0ba2cbe9Sxc151355 			state.ls_persist = B_TRUE;
3009*0ba2cbe9Sxc151355 			break;
3010*0ba2cbe9Sxc151355 		case ':':
3011*0ba2cbe9Sxc151355 			(void) fprintf(stderr,
3012*0ba2cbe9Sxc151355 			    gettext("%s: option requires a value '-%c'\n"),
3013*0ba2cbe9Sxc151355 			    progname, optopt);
3014*0ba2cbe9Sxc151355 			exit(1);
3015*0ba2cbe9Sxc151355 			break;
3016*0ba2cbe9Sxc151355 		case '?':
3017*0ba2cbe9Sxc151355 		default:
3018*0ba2cbe9Sxc151355 			(void) fprintf(stderr,
3019*0ba2cbe9Sxc151355 			    gettext("%s: unrecognized option '-%c'\n"),
3020*0ba2cbe9Sxc151355 			    progname, optopt);
3021*0ba2cbe9Sxc151355 			exit(1);
3022*0ba2cbe9Sxc151355 			break;
3023*0ba2cbe9Sxc151355 		}
3024*0ba2cbe9Sxc151355 	}
3025*0ba2cbe9Sxc151355 
3026*0ba2cbe9Sxc151355 	if (optind == (argc - 1))
3027*0ba2cbe9Sxc151355 		state.ls_link = argv[optind];
3028*0ba2cbe9Sxc151355 	else if (optind != argc)
3029*0ba2cbe9Sxc151355 		usage();
3030*0ba2cbe9Sxc151355 
3031*0ba2cbe9Sxc151355 	if (state.ls_link == NULL) {
3032*0ba2cbe9Sxc151355 		(void) fprintf(stderr,
3033*0ba2cbe9Sxc151355 		    gettext("%s: link name must be specified\n"), progname);
3034*0ba2cbe9Sxc151355 		exit(1);
3035*0ba2cbe9Sxc151355 	}
3036*0ba2cbe9Sxc151355 
3037*0ba2cbe9Sxc151355 	/*
3038*0ba2cbe9Sxc151355 	 * When some WiFi links are opened for the first time, their hardware
3039*0ba2cbe9Sxc151355 	 * automatically scans for APs and does other slow operations.  Thus,
3040*0ba2cbe9Sxc151355 	 * if there are no open links, the retrieval of link properties
3041*0ba2cbe9Sxc151355 	 * (below) will proceed slowly unless we hold the link open.
3042*0ba2cbe9Sxc151355 	 */
3043*0ba2cbe9Sxc151355 	(void) snprintf(linkname, MAXPATHLEN, "/dev/%s", state.ls_link);
3044*0ba2cbe9Sxc151355 	if ((fd = open(linkname, O_RDWR)) < 0) {
3045*0ba2cbe9Sxc151355 		(void) fprintf(stderr,
3046*0ba2cbe9Sxc151355 		    gettext("%s: cannot open %s\n"), progname, state.ls_link);
3047*0ba2cbe9Sxc151355 		exit(1);
3048*0ba2cbe9Sxc151355 	}
3049*0ba2cbe9Sxc151355 
3050*0ba2cbe9Sxc151355 	buf = malloc((sizeof (char *) + DLADM_PROP_VAL_MAX) * MAX_PROP_VALS +
3051*0ba2cbe9Sxc151355 	    MAX_PROP_LINE);
3052*0ba2cbe9Sxc151355 	if (buf == NULL) {
3053*0ba2cbe9Sxc151355 		(void) fprintf(stderr,
3054*0ba2cbe9Sxc151355 		    gettext("%s: insufficient memory\n"), progname);
3055*0ba2cbe9Sxc151355 		exit(1);
3056*0ba2cbe9Sxc151355 	}
3057*0ba2cbe9Sxc151355 	state.ls_propvals = (char **)(void *)buf;
3058*0ba2cbe9Sxc151355 	for (i = 0; i < MAX_PROP_VALS; i++) {
3059*0ba2cbe9Sxc151355 		state.ls_propvals[i] = buf + sizeof (char *) * MAX_PROP_VALS +
3060*0ba2cbe9Sxc151355 		    i * DLADM_PROP_VAL_MAX;
3061*0ba2cbe9Sxc151355 	}
3062*0ba2cbe9Sxc151355 	state.ls_line = buf +
3063*0ba2cbe9Sxc151355 	    (sizeof (char *) + DLADM_PROP_VAL_MAX) * MAX_PROP_VALS;
3064*0ba2cbe9Sxc151355 
3065*0ba2cbe9Sxc151355 	if (proplist != NULL) {
3066*0ba2cbe9Sxc151355 		for (i = 0; i < proplist->pl_count; i++) {
3067*0ba2cbe9Sxc151355 			if (!show_linkprop(&state,
3068*0ba2cbe9Sxc151355 			    proplist->pl_info[i].pi_name))
3069*0ba2cbe9Sxc151355 				break;
3070*0ba2cbe9Sxc151355 		}
3071*0ba2cbe9Sxc151355 	} else {
3072*0ba2cbe9Sxc151355 		status = dladm_walk_prop(state.ls_link, &state, show_linkprop);
3073*0ba2cbe9Sxc151355 		if (status != DLADM_STATUS_OK) {
3074*0ba2cbe9Sxc151355 			(void) fprintf(stderr,
3075*0ba2cbe9Sxc151355 			    gettext("%s: show-linkprop: %s\n"), progname,
3076*0ba2cbe9Sxc151355 			    dladm_status2str(status, errmsg));
3077*0ba2cbe9Sxc151355 			exit(1);
3078*0ba2cbe9Sxc151355 		}
3079*0ba2cbe9Sxc151355 	}
3080*0ba2cbe9Sxc151355 	(void) close(fd);
3081*0ba2cbe9Sxc151355 	free(buf);
3082*0ba2cbe9Sxc151355 	free_props(proplist);
3083*0ba2cbe9Sxc151355 }
3084*0ba2cbe9Sxc151355 
3085*0ba2cbe9Sxc151355 static dladm_status_t
3086*0ba2cbe9Sxc151355 set_linkprop_persist(const char *link, const char *prop_name, char **prop_val,
3087*0ba2cbe9Sxc151355     uint_t val_cnt, boolean_t reset)
3088*0ba2cbe9Sxc151355 {
3089*0ba2cbe9Sxc151355 	dladm_status_t	status;
3090*0ba2cbe9Sxc151355 	char		errmsg[DLADM_STRSIZE];
3091*0ba2cbe9Sxc151355 
3092*0ba2cbe9Sxc151355 	status = dladm_set_prop(link, prop_name, prop_val, val_cnt,
3093*0ba2cbe9Sxc151355 	    DLADM_OPT_PERSIST);
3094*0ba2cbe9Sxc151355 
3095*0ba2cbe9Sxc151355 	if (status != DLADM_STATUS_OK) {
3096*0ba2cbe9Sxc151355 		if (reset) {
3097*0ba2cbe9Sxc151355 			(void) fprintf(stderr, gettext("%s: warning: cannot "
3098*0ba2cbe9Sxc151355 			    "persistently reset link property '%s' on '%s': "
3099*0ba2cbe9Sxc151355 			    "%s\n"), progname, prop_name, link,
3100*0ba2cbe9Sxc151355 			    dladm_status2str(status, errmsg));
3101*0ba2cbe9Sxc151355 		} else {
3102*0ba2cbe9Sxc151355 			(void) fprintf(stderr, gettext("%s: warning: cannot "
3103*0ba2cbe9Sxc151355 			    "persistently set link property '%s' on '%s': "
3104*0ba2cbe9Sxc151355 			    "%s\n"), progname, prop_name, link,
3105*0ba2cbe9Sxc151355 			    dladm_status2str(status, errmsg));
3106*0ba2cbe9Sxc151355 		}
3107*0ba2cbe9Sxc151355 	}
3108*0ba2cbe9Sxc151355 	return (status);
3109*0ba2cbe9Sxc151355 }
3110*0ba2cbe9Sxc151355 
3111*0ba2cbe9Sxc151355 static void
3112*0ba2cbe9Sxc151355 set_linkprop(int argc, char **argv, boolean_t reset)
3113*0ba2cbe9Sxc151355 {
3114*0ba2cbe9Sxc151355 	int		i, option;
3115*0ba2cbe9Sxc151355 	char		errmsg[DLADM_STRSIZE];
3116*0ba2cbe9Sxc151355 	const char	*link = NULL;
3117*0ba2cbe9Sxc151355 	prop_list_t	*proplist = NULL;
3118*0ba2cbe9Sxc151355 	boolean_t	temp = B_FALSE;
3119*0ba2cbe9Sxc151355 	dladm_status_t	status = DLADM_STATUS_OK;
3120*0ba2cbe9Sxc151355 
3121*0ba2cbe9Sxc151355 	opterr = 0;
3122*0ba2cbe9Sxc151355 	while ((option = getopt_long(argc, argv, ":p:R:t",
3123*0ba2cbe9Sxc151355 	    prop_longopts, NULL)) != -1) {
3124*0ba2cbe9Sxc151355 		switch (option) {
3125*0ba2cbe9Sxc151355 		case 'p':
3126*0ba2cbe9Sxc151355 			if (parse_props(optarg, &proplist, reset) < 0) {
3127*0ba2cbe9Sxc151355 				(void) fprintf(stderr, gettext(
3128*0ba2cbe9Sxc151355 				    "%s: invalid link properties specified\n"),
3129*0ba2cbe9Sxc151355 				    progname);
3130*0ba2cbe9Sxc151355 				exit(1);
3131*0ba2cbe9Sxc151355 			}
3132*0ba2cbe9Sxc151355 			break;
3133*0ba2cbe9Sxc151355 		case 't':
3134*0ba2cbe9Sxc151355 			temp = B_TRUE;
3135*0ba2cbe9Sxc151355 			break;
3136*0ba2cbe9Sxc151355 		case 'R':
3137*0ba2cbe9Sxc151355 			status = dladm_set_rootdir(optarg);
3138*0ba2cbe9Sxc151355 			if (status != DLADM_STATUS_OK) {
3139*0ba2cbe9Sxc151355 				(void) fprintf(stderr, gettext(
3140*0ba2cbe9Sxc151355 				    "%s: invalid directory specified: %s\n"),
3141*0ba2cbe9Sxc151355 				    progname, dladm_status2str(status, errmsg));
3142*0ba2cbe9Sxc151355 				exit(1);
3143*0ba2cbe9Sxc151355 			}
3144*0ba2cbe9Sxc151355 			break;
3145*0ba2cbe9Sxc151355 		case ':':
3146*0ba2cbe9Sxc151355 			(void) fprintf(stderr,
3147*0ba2cbe9Sxc151355 			    gettext("%s: option requires a value '-%c'\n"),
3148*0ba2cbe9Sxc151355 			    progname, optopt);
3149*0ba2cbe9Sxc151355 			exit(1);
3150*0ba2cbe9Sxc151355 			break;
3151*0ba2cbe9Sxc151355 		case '?':
3152*0ba2cbe9Sxc151355 		default:
3153*0ba2cbe9Sxc151355 			(void) fprintf(stderr,
3154*0ba2cbe9Sxc151355 			    gettext("%s: unrecognized option '-%c'\n"),
3155*0ba2cbe9Sxc151355 			    progname, optopt);
3156*0ba2cbe9Sxc151355 			exit(1);
3157*0ba2cbe9Sxc151355 			break;
3158*0ba2cbe9Sxc151355 		}
3159*0ba2cbe9Sxc151355 	}
3160*0ba2cbe9Sxc151355 
3161*0ba2cbe9Sxc151355 	if (optind == (argc - 1))
3162*0ba2cbe9Sxc151355 		link = argv[optind];
3163*0ba2cbe9Sxc151355 	else if (optind != argc)
3164*0ba2cbe9Sxc151355 		usage();
3165*0ba2cbe9Sxc151355 
3166*0ba2cbe9Sxc151355 	if (link == NULL) {
3167*0ba2cbe9Sxc151355 		(void) fprintf(stderr,
3168*0ba2cbe9Sxc151355 		    gettext("%s: link name must be specified\n"),
3169*0ba2cbe9Sxc151355 		    progname);
3170*0ba2cbe9Sxc151355 		exit(1);
3171*0ba2cbe9Sxc151355 	}
3172*0ba2cbe9Sxc151355 
3173*0ba2cbe9Sxc151355 	if (proplist == NULL) {
3174*0ba2cbe9Sxc151355 		if (!reset) {
3175*0ba2cbe9Sxc151355 			(void) fprintf(stderr,
3176*0ba2cbe9Sxc151355 			    gettext("%s: link property must be specified\n"),
3177*0ba2cbe9Sxc151355 			    progname);
3178*0ba2cbe9Sxc151355 			exit(1);
3179*0ba2cbe9Sxc151355 		}
3180*0ba2cbe9Sxc151355 		status = dladm_set_prop(link, NULL, NULL, 0, DLADM_OPT_TEMP);
3181*0ba2cbe9Sxc151355 		if (status != DLADM_STATUS_OK) {
3182*0ba2cbe9Sxc151355 			(void) fprintf(stderr, gettext(
3183*0ba2cbe9Sxc151355 			    "%s: warning: cannot reset link "
3184*0ba2cbe9Sxc151355 			    "properties on '%s': %s\n"),
3185*0ba2cbe9Sxc151355 			    progname, link, dladm_status2str(status, errmsg));
3186*0ba2cbe9Sxc151355 		}
3187*0ba2cbe9Sxc151355 		if (!temp) {
3188*0ba2cbe9Sxc151355 			status = set_linkprop_persist(link, NULL, NULL, 0,
3189*0ba2cbe9Sxc151355 			    reset);
3190*0ba2cbe9Sxc151355 		}
3191*0ba2cbe9Sxc151355 		goto done;
3192*0ba2cbe9Sxc151355 	}
3193*0ba2cbe9Sxc151355 
3194*0ba2cbe9Sxc151355 	for (i = 0; i < proplist->pl_count; i++) {
3195*0ba2cbe9Sxc151355 		prop_info_t	*pip = &proplist->pl_info[i];
3196*0ba2cbe9Sxc151355 		char		**val;
3197*0ba2cbe9Sxc151355 		uint_t		count;
3198*0ba2cbe9Sxc151355 		dladm_status_t	s;
3199*0ba2cbe9Sxc151355 
3200*0ba2cbe9Sxc151355 		if (reset) {
3201*0ba2cbe9Sxc151355 			val = NULL;
3202*0ba2cbe9Sxc151355 			count = 0;
3203*0ba2cbe9Sxc151355 		} else {
3204*0ba2cbe9Sxc151355 			val = pip->pi_val;
3205*0ba2cbe9Sxc151355 			count = pip->pi_count;
3206*0ba2cbe9Sxc151355 			if (count == 0) {
3207*0ba2cbe9Sxc151355 				(void) fprintf(stderr, gettext(
3208*0ba2cbe9Sxc151355 				    "%s: value(s) for '%s' not specified\n"),
3209*0ba2cbe9Sxc151355 				    progname, pip->pi_name);
3210*0ba2cbe9Sxc151355 				status = DLADM_STATUS_BADARG;
3211*0ba2cbe9Sxc151355 				continue;
3212*0ba2cbe9Sxc151355 			}
3213*0ba2cbe9Sxc151355 		}
3214*0ba2cbe9Sxc151355 		s = dladm_set_prop(link, pip->pi_name, val, count,
3215*0ba2cbe9Sxc151355 		    DLADM_OPT_TEMP);
3216*0ba2cbe9Sxc151355 		if (s == DLADM_STATUS_OK) {
3217*0ba2cbe9Sxc151355 			if (!temp) {
3218*0ba2cbe9Sxc151355 				s = set_linkprop_persist(link,
3219*0ba2cbe9Sxc151355 				    pip->pi_name, val, count, reset);
3220*0ba2cbe9Sxc151355 				if (s != DLADM_STATUS_OK)
3221*0ba2cbe9Sxc151355 					status = s;
3222*0ba2cbe9Sxc151355 			}
3223*0ba2cbe9Sxc151355 			continue;
3224*0ba2cbe9Sxc151355 		}
3225*0ba2cbe9Sxc151355 		status = s;
3226*0ba2cbe9Sxc151355 		switch (s) {
3227*0ba2cbe9Sxc151355 		case DLADM_STATUS_NOTFOUND:
3228*0ba2cbe9Sxc151355 			(void) fprintf(stderr,
3229*0ba2cbe9Sxc151355 			    gettext("%s: invalid link property '%s'\n"),
3230*0ba2cbe9Sxc151355 			    progname, pip->pi_name);
3231*0ba2cbe9Sxc151355 			break;
3232*0ba2cbe9Sxc151355 		case DLADM_STATUS_BADVAL: {
3233*0ba2cbe9Sxc151355 			int		j;
3234*0ba2cbe9Sxc151355 			char		*ptr, *lim;
3235*0ba2cbe9Sxc151355 			char		**propvals = NULL;
3236*0ba2cbe9Sxc151355 			uint_t		valcnt = MAX_PROP_VALS;
3237*0ba2cbe9Sxc151355 
3238*0ba2cbe9Sxc151355 			ptr = malloc((sizeof (char *) +
3239*0ba2cbe9Sxc151355 			    DLADM_PROP_VAL_MAX) * MAX_PROP_VALS +
3240*0ba2cbe9Sxc151355 			    MAX_PROP_LINE);
3241*0ba2cbe9Sxc151355 
3242*0ba2cbe9Sxc151355 			propvals = (char **)(void *)ptr;
3243*0ba2cbe9Sxc151355 			if (propvals == NULL) {
3244*0ba2cbe9Sxc151355 				(void) fprintf(stderr, gettext(
3245*0ba2cbe9Sxc151355 				    "%s: insufficient memory\n"), progname);
3246*0ba2cbe9Sxc151355 				exit(1);
3247*0ba2cbe9Sxc151355 			}
3248*0ba2cbe9Sxc151355 			for (j = 0; j < MAX_PROP_VALS; j++) {
3249*0ba2cbe9Sxc151355 				propvals[j] = ptr + sizeof (char *) *
3250*0ba2cbe9Sxc151355 				    MAX_PROP_VALS +
3251*0ba2cbe9Sxc151355 				    j * DLADM_PROP_VAL_MAX;
3252*0ba2cbe9Sxc151355 			}
3253*0ba2cbe9Sxc151355 			s = dladm_get_prop(link, DLADM_PROP_VAL_MODIFIABLE,
3254*0ba2cbe9Sxc151355 			    pip->pi_name, propvals, &valcnt);
3255*0ba2cbe9Sxc151355 
3256*0ba2cbe9Sxc151355 			ptr = errmsg;
3257*0ba2cbe9Sxc151355 			lim = ptr + DLADM_STRSIZE;
3258*0ba2cbe9Sxc151355 			*ptr = '\0';
3259*0ba2cbe9Sxc151355 			for (j = 0; j < valcnt && s == DLADM_STATUS_OK; j++) {
3260*0ba2cbe9Sxc151355 				ptr += snprintf(ptr, lim - ptr, "%s,",
3261*0ba2cbe9Sxc151355 				    propvals[j]);
3262*0ba2cbe9Sxc151355 				if (ptr >= lim)
3263*0ba2cbe9Sxc151355 					break;
3264*0ba2cbe9Sxc151355 			}
3265*0ba2cbe9Sxc151355 			if (ptr > errmsg)
3266*0ba2cbe9Sxc151355 				*(ptr - 1) = '\0';
3267*0ba2cbe9Sxc151355 			(void) fprintf(stderr, gettext(
3268*0ba2cbe9Sxc151355 			    "%s: link property '%s' must be one of: %s\n"),
3269*0ba2cbe9Sxc151355 			    progname, pip->pi_name, errmsg);
3270*0ba2cbe9Sxc151355 			free(propvals);
3271*0ba2cbe9Sxc151355 			break;
3272*0ba2cbe9Sxc151355 		}
3273*0ba2cbe9Sxc151355 		default:
3274*0ba2cbe9Sxc151355 			if (reset) {
3275*0ba2cbe9Sxc151355 				(void) fprintf(stderr, gettext(
3276*0ba2cbe9Sxc151355 				    "%s: cannot reset link property '%s' on "
3277*0ba2cbe9Sxc151355 				    "'%s': %s\n"), progname, pip->pi_name, link,
3278*0ba2cbe9Sxc151355 				    dladm_status2str(s, errmsg));
3279*0ba2cbe9Sxc151355 			} else {
3280*0ba2cbe9Sxc151355 				(void) fprintf(stderr, gettext(
3281*0ba2cbe9Sxc151355 				    "%s: cannot set link property '%s' on "
3282*0ba2cbe9Sxc151355 				    "'%s': %s\n"), progname, pip->pi_name, link,
3283*0ba2cbe9Sxc151355 				    dladm_status2str(s, errmsg));
3284*0ba2cbe9Sxc151355 			}
3285*0ba2cbe9Sxc151355 			break;
3286*0ba2cbe9Sxc151355 		}
3287*0ba2cbe9Sxc151355 	}
3288*0ba2cbe9Sxc151355 done:
3289*0ba2cbe9Sxc151355 	free_props(proplist);
3290*0ba2cbe9Sxc151355 	if (status != DLADM_STATUS_OK)
3291*0ba2cbe9Sxc151355 		exit(1);
3292*0ba2cbe9Sxc151355 }
3293*0ba2cbe9Sxc151355 
3294*0ba2cbe9Sxc151355 static void
3295*0ba2cbe9Sxc151355 do_set_linkprop(int argc, char **argv)
3296*0ba2cbe9Sxc151355 {
3297*0ba2cbe9Sxc151355 	set_linkprop(argc, argv, B_FALSE);
3298*0ba2cbe9Sxc151355 }
3299*0ba2cbe9Sxc151355 
3300*0ba2cbe9Sxc151355 static void
3301*0ba2cbe9Sxc151355 do_reset_linkprop(int argc, char **argv)
3302*0ba2cbe9Sxc151355 {
3303*0ba2cbe9Sxc151355 	set_linkprop(argc, argv, B_TRUE);
3304*0ba2cbe9Sxc151355 }
3305*0ba2cbe9Sxc151355 
3306*0ba2cbe9Sxc151355 static int
3307*0ba2cbe9Sxc151355 convert_secobj(char *buf, uint_t len, uint8_t *obj_val, uint_t *obj_lenp,
3308*0ba2cbe9Sxc151355     dladm_secobj_class_t class)
3309*0ba2cbe9Sxc151355 {
3310*0ba2cbe9Sxc151355 	int error = 0;
3311*0ba2cbe9Sxc151355 
3312*0ba2cbe9Sxc151355 	if (class != DLADM_SECOBJ_CLASS_WEP)
3313*0ba2cbe9Sxc151355 		return (ENOENT);
3314*0ba2cbe9Sxc151355 
3315*0ba2cbe9Sxc151355 	switch (len) {
3316*0ba2cbe9Sxc151355 	case 5:			/* ASCII key sizes */
3317*0ba2cbe9Sxc151355 	case 13:
3318*0ba2cbe9Sxc151355 		(void) memcpy(obj_val, buf, len);
3319*0ba2cbe9Sxc151355 		*obj_lenp = len;
3320*0ba2cbe9Sxc151355 		break;
3321*0ba2cbe9Sxc151355 	case 10:		/* Hex key sizes, not preceded by 0x */
3322*0ba2cbe9Sxc151355 	case 26:
3323*0ba2cbe9Sxc151355 		error = hexascii_to_octet(buf, len, obj_val, obj_lenp);
3324*0ba2cbe9Sxc151355 		break;
3325*0ba2cbe9Sxc151355 	case 12:		/* Hex key sizes, preceded by 0x */
3326*0ba2cbe9Sxc151355 	case 28:
3327*0ba2cbe9Sxc151355 		if (strncmp(buf, "0x", 2) != 0)
3328*0ba2cbe9Sxc151355 			return (EINVAL);
3329*0ba2cbe9Sxc151355 		error = hexascii_to_octet(buf + 2, len - 2, obj_val, obj_lenp);
3330*0ba2cbe9Sxc151355 		break;
3331*0ba2cbe9Sxc151355 	default:
3332*0ba2cbe9Sxc151355 		return (EINVAL);
3333*0ba2cbe9Sxc151355 	}
3334*0ba2cbe9Sxc151355 	return (error);
3335*0ba2cbe9Sxc151355 }
3336*0ba2cbe9Sxc151355 
3337*0ba2cbe9Sxc151355 /* ARGSUSED */
3338*0ba2cbe9Sxc151355 static void
3339*0ba2cbe9Sxc151355 defersig(int sig)
3340*0ba2cbe9Sxc151355 {
3341*0ba2cbe9Sxc151355 	signalled = sig;
3342*0ba2cbe9Sxc151355 }
3343*0ba2cbe9Sxc151355 
3344*0ba2cbe9Sxc151355 static int
3345*0ba2cbe9Sxc151355 get_secobj_from_tty(uint_t try, const char *objname, char *buf)
3346*0ba2cbe9Sxc151355 {
3347*0ba2cbe9Sxc151355 	uint_t		len = 0;
3348*0ba2cbe9Sxc151355 	int		c;
3349*0ba2cbe9Sxc151355 	struct termios	stored, current;
3350*0ba2cbe9Sxc151355 	void    	(*sigfunc)(int);
3351*0ba2cbe9Sxc151355 
3352*0ba2cbe9Sxc151355 	/*
3353*0ba2cbe9Sxc151355 	 * Turn off echo -- but before we do so, defer SIGINT handling
3354*0ba2cbe9Sxc151355 	 * so that a ^C doesn't leave the terminal corrupted.
3355*0ba2cbe9Sxc151355 	 */
3356*0ba2cbe9Sxc151355 	sigfunc = signal(SIGINT, defersig);
3357*0ba2cbe9Sxc151355 	(void) fflush(stdin);
3358*0ba2cbe9Sxc151355 	(void) tcgetattr(0, &stored);
3359*0ba2cbe9Sxc151355 	current = stored;
3360*0ba2cbe9Sxc151355 	current.c_lflag &= ~(ICANON|ECHO);
3361*0ba2cbe9Sxc151355 	current.c_cc[VTIME] = 0;
3362*0ba2cbe9Sxc151355 	current.c_cc[VMIN] = 1;
3363*0ba2cbe9Sxc151355 	(void) tcsetattr(0, TCSANOW, &current);
3364*0ba2cbe9Sxc151355 again:
3365*0ba2cbe9Sxc151355 	if (try == 1)
3366*0ba2cbe9Sxc151355 		(void) printf(gettext("provide value for '%s': "), objname);
3367*0ba2cbe9Sxc151355 	else
3368*0ba2cbe9Sxc151355 		(void) printf(gettext("confirm value for '%s': "), objname);
3369*0ba2cbe9Sxc151355 
3370*0ba2cbe9Sxc151355 	(void) fflush(stdout);
3371*0ba2cbe9Sxc151355 	while (signalled == 0) {
3372*0ba2cbe9Sxc151355 		c = getchar();
3373*0ba2cbe9Sxc151355 		if (c == '\n' || c == '\r') {
3374*0ba2cbe9Sxc151355 			if (len != 0)
3375*0ba2cbe9Sxc151355 				break;
3376*0ba2cbe9Sxc151355 			(void) putchar('\n');
3377*0ba2cbe9Sxc151355 			goto again;
3378*0ba2cbe9Sxc151355 		}
3379*0ba2cbe9Sxc151355 
3380*0ba2cbe9Sxc151355 		buf[len++] = c;
3381*0ba2cbe9Sxc151355 		if (len >= DLADM_SECOBJ_VAL_MAX - 1)
3382*0ba2cbe9Sxc151355 			break;
3383*0ba2cbe9Sxc151355 		(void) putchar('*');
3384*0ba2cbe9Sxc151355 	}
3385*0ba2cbe9Sxc151355 
3386*0ba2cbe9Sxc151355 	(void) putchar('\n');
3387*0ba2cbe9Sxc151355 	(void) fflush(stdin);
3388*0ba2cbe9Sxc151355 
3389*0ba2cbe9Sxc151355 	/*
3390*0ba2cbe9Sxc151355 	 * Restore terminal setting and handle deferred signals.
3391*0ba2cbe9Sxc151355 	 */
3392*0ba2cbe9Sxc151355 	(void) tcsetattr(0, TCSANOW, &stored);
3393*0ba2cbe9Sxc151355 
3394*0ba2cbe9Sxc151355 	(void) signal(SIGINT, sigfunc);
3395*0ba2cbe9Sxc151355 	if (signalled != 0)
3396*0ba2cbe9Sxc151355 		(void) kill(getpid(), signalled);
3397*0ba2cbe9Sxc151355 
3398*0ba2cbe9Sxc151355 	return (len);
3399*0ba2cbe9Sxc151355 }
3400*0ba2cbe9Sxc151355 
3401*0ba2cbe9Sxc151355 static int
3402*0ba2cbe9Sxc151355 get_secobj_val(char *obj_name, uint8_t *obj_val, uint_t *obj_lenp,
3403*0ba2cbe9Sxc151355     dladm_secobj_class_t class, FILE *filep)
3404*0ba2cbe9Sxc151355 {
3405*0ba2cbe9Sxc151355 	int		rval;
3406*0ba2cbe9Sxc151355 	uint_t		len, len2;
3407*0ba2cbe9Sxc151355 	char		buf[DLADM_SECOBJ_VAL_MAX], buf2[DLADM_SECOBJ_VAL_MAX];
3408*0ba2cbe9Sxc151355 
3409*0ba2cbe9Sxc151355 	if (filep == NULL) {
3410*0ba2cbe9Sxc151355 		len = get_secobj_from_tty(1, obj_name, buf);
3411*0ba2cbe9Sxc151355 		rval = convert_secobj(buf, len, obj_val, obj_lenp, class);
3412*0ba2cbe9Sxc151355 		if (rval == 0) {
3413*0ba2cbe9Sxc151355 			len2 = get_secobj_from_tty(2, obj_name, buf2);
3414*0ba2cbe9Sxc151355 			if (len != len2 || memcmp(buf, buf2, len) != 0)
3415*0ba2cbe9Sxc151355 				rval = ENOTSUP;
3416*0ba2cbe9Sxc151355 		}
3417*0ba2cbe9Sxc151355 		return (rval);
3418*0ba2cbe9Sxc151355 	} else {
3419*0ba2cbe9Sxc151355 		for (;;) {
3420*0ba2cbe9Sxc151355 			if (fgets(buf, sizeof (buf), filep) == NULL)
3421*0ba2cbe9Sxc151355 				break;
3422*0ba2cbe9Sxc151355 			if (isspace(buf[0]))
3423*0ba2cbe9Sxc151355 				continue;
3424*0ba2cbe9Sxc151355 
3425*0ba2cbe9Sxc151355 			len = strlen(buf);
3426*0ba2cbe9Sxc151355 			if (buf[len - 1] == '\n') {
3427*0ba2cbe9Sxc151355 				buf[len - 1] = '\0';
3428*0ba2cbe9Sxc151355 				len--;
3429*0ba2cbe9Sxc151355 			}
3430*0ba2cbe9Sxc151355 			break;
3431*0ba2cbe9Sxc151355 		}
3432*0ba2cbe9Sxc151355 		(void) fclose(filep);
3433*0ba2cbe9Sxc151355 	}
3434*0ba2cbe9Sxc151355 	return (convert_secobj(buf, len, obj_val, obj_lenp, class));
3435*0ba2cbe9Sxc151355 }
3436*0ba2cbe9Sxc151355 
3437*0ba2cbe9Sxc151355 static boolean_t
3438*0ba2cbe9Sxc151355 check_auth(const char *auth)
3439*0ba2cbe9Sxc151355 {
3440*0ba2cbe9Sxc151355 	struct passwd	*pw;
3441*0ba2cbe9Sxc151355 
3442*0ba2cbe9Sxc151355 	if ((pw = getpwuid(getuid())) == NULL)
3443*0ba2cbe9Sxc151355 		return (B_FALSE);
3444*0ba2cbe9Sxc151355 
3445*0ba2cbe9Sxc151355 	return (chkauthattr(auth, pw->pw_name) != 0);
3446*0ba2cbe9Sxc151355 }
3447*0ba2cbe9Sxc151355 
3448*0ba2cbe9Sxc151355 static void
3449*0ba2cbe9Sxc151355 audit_secobj(char *auth, char *class, char *obj,
3450*0ba2cbe9Sxc151355     boolean_t success, boolean_t create)
3451*0ba2cbe9Sxc151355 {
3452*0ba2cbe9Sxc151355 	adt_session_data_t	*ah;
3453*0ba2cbe9Sxc151355 	adt_event_data_t	*event;
3454*0ba2cbe9Sxc151355 	au_event_t		flag;
3455*0ba2cbe9Sxc151355 	char			*errstr;
3456*0ba2cbe9Sxc151355 
3457*0ba2cbe9Sxc151355 	if (create) {
3458*0ba2cbe9Sxc151355 		flag = ADT_dladm_create_secobj;
3459*0ba2cbe9Sxc151355 		errstr = "ADT_dladm_create_secobj";
3460*0ba2cbe9Sxc151355 	} else {
3461*0ba2cbe9Sxc151355 		flag = ADT_dladm_delete_secobj;
3462*0ba2cbe9Sxc151355 		errstr = "ADT_dladm_delete_secobj";
3463*0ba2cbe9Sxc151355 	}
3464*0ba2cbe9Sxc151355 
3465*0ba2cbe9Sxc151355 	if (adt_start_session(&ah, NULL, ADT_USE_PROC_DATA) != 0) {
3466*0ba2cbe9Sxc151355 		(void) fprintf(stderr, "%s: adt_start_session: %s\n",
3467*0ba2cbe9Sxc151355 		    progname, strerror(errno));
3468*0ba2cbe9Sxc151355 		exit(1);
3469*0ba2cbe9Sxc151355 	}
3470*0ba2cbe9Sxc151355 
3471*0ba2cbe9Sxc151355 	if ((event = adt_alloc_event(ah, flag)) == NULL) {
3472*0ba2cbe9Sxc151355 		(void) fprintf(stderr, "%s: adt_alloc_event"
3473*0ba2cbe9Sxc151355 		    "(%s): %s\n", progname, errstr,
3474*0ba2cbe9Sxc151355 		    strerror(errno));
3475*0ba2cbe9Sxc151355 		exit(1);
3476*0ba2cbe9Sxc151355 	}
3477*0ba2cbe9Sxc151355 
3478*0ba2cbe9Sxc151355 	/* fill in audit info */
3479*0ba2cbe9Sxc151355 	if (create) {
3480*0ba2cbe9Sxc151355 		event->adt_dladm_create_secobj.auth_used = auth;
3481*0ba2cbe9Sxc151355 		event->adt_dladm_create_secobj.obj_class = class;
3482*0ba2cbe9Sxc151355 		event->adt_dladm_create_secobj.obj_name = obj;
3483*0ba2cbe9Sxc151355 	} else {
3484*0ba2cbe9Sxc151355 		event->adt_dladm_delete_secobj.auth_used = auth;
3485*0ba2cbe9Sxc151355 		event->adt_dladm_delete_secobj.obj_class = class;
3486*0ba2cbe9Sxc151355 		event->adt_dladm_delete_secobj.obj_name = obj;
3487*0ba2cbe9Sxc151355 	}
3488*0ba2cbe9Sxc151355 
3489*0ba2cbe9Sxc151355 	if (success) {
3490*0ba2cbe9Sxc151355 		if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS) != 0) {
3491*0ba2cbe9Sxc151355 			(void) fprintf(stderr, "%s: adt_put_event"
3492*0ba2cbe9Sxc151355 			    "(%s, success): %s\n",
3493*0ba2cbe9Sxc151355 			    progname, errstr, strerror(errno));
3494*0ba2cbe9Sxc151355 			exit(1);
3495*0ba2cbe9Sxc151355 		}
3496*0ba2cbe9Sxc151355 	} else {
3497*0ba2cbe9Sxc151355 		if (adt_put_event(event, ADT_FAILURE,
3498*0ba2cbe9Sxc151355 		    ADT_FAIL_VALUE_AUTH) != 0) {
3499*0ba2cbe9Sxc151355 			(void) fprintf(stderr, "%s: adt_put_event"
3500*0ba2cbe9Sxc151355 			    "(%s, failure): %s\n",
3501*0ba2cbe9Sxc151355 			    progname, errstr, strerror(errno));
3502*0ba2cbe9Sxc151355 			exit(1);
3503*0ba2cbe9Sxc151355 		}
3504*0ba2cbe9Sxc151355 	}
3505*0ba2cbe9Sxc151355 
3506*0ba2cbe9Sxc151355 	adt_free_event(event);
3507*0ba2cbe9Sxc151355 	(void) adt_end_session(ah);
3508*0ba2cbe9Sxc151355 }
3509*0ba2cbe9Sxc151355 
3510*0ba2cbe9Sxc151355 #define	MAX_SECOBJS		32
3511*0ba2cbe9Sxc151355 #define	MAX_SECOBJ_NAMELEN	32
3512*0ba2cbe9Sxc151355 static void
3513*0ba2cbe9Sxc151355 do_create_secobj(int argc, char **argv)
3514*0ba2cbe9Sxc151355 {
3515*0ba2cbe9Sxc151355 	int			option, rval;
3516*0ba2cbe9Sxc151355 	char			errmsg[DLADM_STRSIZE];
3517*0ba2cbe9Sxc151355 	FILE			*filep = NULL;
3518*0ba2cbe9Sxc151355 	char			*obj_name = NULL;
3519*0ba2cbe9Sxc151355 	char			*class_name = NULL;
3520*0ba2cbe9Sxc151355 	uint8_t			obj_val[DLADM_SECOBJ_VAL_MAX];
3521*0ba2cbe9Sxc151355 	uint_t			obj_len;
3522*0ba2cbe9Sxc151355 	boolean_t		success, temp = B_FALSE;
3523*0ba2cbe9Sxc151355 	dladm_status_t		status;
3524*0ba2cbe9Sxc151355 	dladm_secobj_class_t	class = -1;
3525*0ba2cbe9Sxc151355 	uid_t			euid;
3526*0ba2cbe9Sxc151355 
3527*0ba2cbe9Sxc151355 	opterr = 0;
3528*0ba2cbe9Sxc151355 	(void) memset(obj_val, 0, DLADM_SECOBJ_VAL_MAX);
3529*0ba2cbe9Sxc151355 	while ((option = getopt_long(argc, argv, ":f:c:R:t",
3530*0ba2cbe9Sxc151355 	    wifi_longopts, NULL)) != -1) {
3531*0ba2cbe9Sxc151355 		switch (option) {
3532*0ba2cbe9Sxc151355 		case 'f':
3533*0ba2cbe9Sxc151355 			euid = geteuid();
3534*0ba2cbe9Sxc151355 			(void) seteuid(getuid());
3535*0ba2cbe9Sxc151355 			filep = fopen(optarg, "r");
3536*0ba2cbe9Sxc151355 			if (filep == NULL) {
3537*0ba2cbe9Sxc151355 				(void) fprintf(stderr,
3538*0ba2cbe9Sxc151355 				    gettext("%s: cannot open %s: %s\n"),
3539*0ba2cbe9Sxc151355 				    progname, optarg, strerror(errno));
3540*0ba2cbe9Sxc151355 				exit(1);
3541*0ba2cbe9Sxc151355 			}
3542*0ba2cbe9Sxc151355 			(void) seteuid(euid);
3543*0ba2cbe9Sxc151355 			break;
3544*0ba2cbe9Sxc151355 		case 'c':
3545*0ba2cbe9Sxc151355 			class_name = optarg;
3546*0ba2cbe9Sxc151355 			status = dladm_str2secobjclass(optarg, &class);
3547*0ba2cbe9Sxc151355 			if (status != DLADM_STATUS_OK) {
3548*0ba2cbe9Sxc151355 				(void) fprintf(stderr, gettext(
3549*0ba2cbe9Sxc151355 				    "%s: invalid secure object class '%s', "
3550*0ba2cbe9Sxc151355 				    "valid values are: wep\n"),
3551*0ba2cbe9Sxc151355 				    progname, optarg);
3552*0ba2cbe9Sxc151355 				exit(1);
3553*0ba2cbe9Sxc151355 			}
3554*0ba2cbe9Sxc151355 			break;
3555*0ba2cbe9Sxc151355 		case 't':
3556*0ba2cbe9Sxc151355 			temp = B_TRUE;
3557*0ba2cbe9Sxc151355 			break;
3558*0ba2cbe9Sxc151355 		case 'R':
3559*0ba2cbe9Sxc151355 			status = dladm_set_rootdir(optarg);
3560*0ba2cbe9Sxc151355 			if (status != DLADM_STATUS_OK) {
3561*0ba2cbe9Sxc151355 				(void) fprintf(stderr, gettext(
3562*0ba2cbe9Sxc151355 				    "%s: invalid directory specified: %s\n"),
3563*0ba2cbe9Sxc151355 				    progname, dladm_status2str(status, errmsg));
3564*0ba2cbe9Sxc151355 				exit(1);
3565*0ba2cbe9Sxc151355 			}
3566*0ba2cbe9Sxc151355 			break;
3567*0ba2cbe9Sxc151355 		case ':':
3568*0ba2cbe9Sxc151355 			(void) fprintf(stderr,
3569*0ba2cbe9Sxc151355 			    gettext("%s: option requires a value '-%c'\n"),
3570*0ba2cbe9Sxc151355 			    progname, optopt);
3571*0ba2cbe9Sxc151355 			exit(1);
3572*0ba2cbe9Sxc151355 			break;
3573*0ba2cbe9Sxc151355 		case '?':
3574*0ba2cbe9Sxc151355 		default:
3575*0ba2cbe9Sxc151355 			(void) fprintf(stderr,
3576*0ba2cbe9Sxc151355 			    gettext("%s: unrecognized option '-%c'\n"),
3577*0ba2cbe9Sxc151355 			    progname, optopt);
3578*0ba2cbe9Sxc151355 			exit(1);
3579*0ba2cbe9Sxc151355 			break;
3580*0ba2cbe9Sxc151355 		}
3581*0ba2cbe9Sxc151355 	}
3582*0ba2cbe9Sxc151355 
3583*0ba2cbe9Sxc151355 	if (optind == (argc - 1))
3584*0ba2cbe9Sxc151355 		obj_name = argv[optind];
3585*0ba2cbe9Sxc151355 	else if (optind != argc)
3586*0ba2cbe9Sxc151355 		usage();
3587*0ba2cbe9Sxc151355 
3588*0ba2cbe9Sxc151355 	if (class == -1) {
3589*0ba2cbe9Sxc151355 		(void) fprintf(stderr,
3590*0ba2cbe9Sxc151355 		    gettext("%s: secure object class required\n"),
3591*0ba2cbe9Sxc151355 		    progname);
3592*0ba2cbe9Sxc151355 		exit(1);
3593*0ba2cbe9Sxc151355 	}
3594*0ba2cbe9Sxc151355 
3595*0ba2cbe9Sxc151355 	if (obj_name == NULL) {
3596*0ba2cbe9Sxc151355 		(void) fprintf(stderr,
3597*0ba2cbe9Sxc151355 		    gettext("%s: secure object name required\n"),
3598*0ba2cbe9Sxc151355 		    progname);
3599*0ba2cbe9Sxc151355 		exit(1);
3600*0ba2cbe9Sxc151355 	}
3601*0ba2cbe9Sxc151355 
3602*0ba2cbe9Sxc151355 	success = check_auth(LINK_SEC_AUTH);
3603*0ba2cbe9Sxc151355 	audit_secobj(LINK_SEC_AUTH, class_name, obj_name, success, B_TRUE);
3604*0ba2cbe9Sxc151355 	if (!success) {
3605*0ba2cbe9Sxc151355 		(void) fprintf(stderr,
3606*0ba2cbe9Sxc151355 		    gettext("%s: authorization '%s' is required\n"),
3607*0ba2cbe9Sxc151355 		    progname, LINK_SEC_AUTH);
3608*0ba2cbe9Sxc151355 		exit(1);
3609*0ba2cbe9Sxc151355 	}
3610*0ba2cbe9Sxc151355 
3611*0ba2cbe9Sxc151355 	if ((rval = get_secobj_val(obj_name, obj_val, &obj_len,
3612*0ba2cbe9Sxc151355 	    class, filep)) != 0) {
3613*0ba2cbe9Sxc151355 		switch (rval) {
3614*0ba2cbe9Sxc151355 		case ENOENT:
3615*0ba2cbe9Sxc151355 			(void) fprintf(stderr,
3616*0ba2cbe9Sxc151355 			    gettext("%s: invalid secure object class\n"),
3617*0ba2cbe9Sxc151355 			    progname);
3618*0ba2cbe9Sxc151355 			break;
3619*0ba2cbe9Sxc151355 		case EINVAL:
3620*0ba2cbe9Sxc151355 			(void) fprintf(stderr,
3621*0ba2cbe9Sxc151355 			    gettext("%s: invalid secure object value\n"),
3622*0ba2cbe9Sxc151355 			    progname);
3623*0ba2cbe9Sxc151355 			break;
3624*0ba2cbe9Sxc151355 		case ENOTSUP:
3625*0ba2cbe9Sxc151355 			(void) fprintf(stderr, gettext(
3626*0ba2cbe9Sxc151355 			    "%s: verification failed\n"), progname);
3627*0ba2cbe9Sxc151355 			break;
3628*0ba2cbe9Sxc151355 		default:
3629*0ba2cbe9Sxc151355 			(void) fprintf(stderr, gettext(
3630*0ba2cbe9Sxc151355 			    "%s: invalid secure object: %s\n"),
3631*0ba2cbe9Sxc151355 			    progname, strerror(rval));
3632*0ba2cbe9Sxc151355 			break;
3633*0ba2cbe9Sxc151355 		}
3634*0ba2cbe9Sxc151355 		exit(1);
3635*0ba2cbe9Sxc151355 	}
3636*0ba2cbe9Sxc151355 
3637*0ba2cbe9Sxc151355 	status = dladm_set_secobj(obj_name, class, obj_val, obj_len,
3638*0ba2cbe9Sxc151355 	    DLADM_OPT_CREATE | DLADM_OPT_TEMP);
3639*0ba2cbe9Sxc151355 	if (status != DLADM_STATUS_OK) {
3640*0ba2cbe9Sxc151355 		(void) fprintf(stderr,
3641*0ba2cbe9Sxc151355 		    gettext("%s: could not create secure object '%s': %s\n"),
3642*0ba2cbe9Sxc151355 		    progname, obj_name, dladm_status2str(status, errmsg));
3643*0ba2cbe9Sxc151355 		exit(1);
3644*0ba2cbe9Sxc151355 	}
3645*0ba2cbe9Sxc151355 	if (temp)
3646*0ba2cbe9Sxc151355 		return;
3647*0ba2cbe9Sxc151355 
3648*0ba2cbe9Sxc151355 	status = dladm_set_secobj(obj_name, class, obj_val, obj_len,
3649*0ba2cbe9Sxc151355 	    DLADM_OPT_PERSIST);
3650*0ba2cbe9Sxc151355 	if (status != DLADM_STATUS_OK) {
3651*0ba2cbe9Sxc151355 		(void) fprintf(stderr,
3652*0ba2cbe9Sxc151355 		    gettext("%s: warning: could not persistently create "
3653*0ba2cbe9Sxc151355 		    "secure object '%s': %s\n"), progname, obj_name,
3654*0ba2cbe9Sxc151355 		    dladm_status2str(status, errmsg));
3655*0ba2cbe9Sxc151355 		exit(1);
3656*0ba2cbe9Sxc151355 	}
3657*0ba2cbe9Sxc151355 }
3658*0ba2cbe9Sxc151355 
3659*0ba2cbe9Sxc151355 static void
3660*0ba2cbe9Sxc151355 do_delete_secobj(int argc, char **argv)
3661*0ba2cbe9Sxc151355 {
3662*0ba2cbe9Sxc151355 	int		i, option;
3663*0ba2cbe9Sxc151355 	char		errmsg[DLADM_STRSIZE];
3664*0ba2cbe9Sxc151355 	boolean_t	temp = B_FALSE;
3665*0ba2cbe9Sxc151355 	split_t		*sp = NULL;
3666*0ba2cbe9Sxc151355 	boolean_t	success;
3667*0ba2cbe9Sxc151355 	dladm_status_t	status, pstatus;
3668*0ba2cbe9Sxc151355 
3669*0ba2cbe9Sxc151355 	opterr = 0;
3670*0ba2cbe9Sxc151355 	status = pstatus = DLADM_STATUS_OK;
3671*0ba2cbe9Sxc151355 	while ((option = getopt_long(argc, argv, "R:t",
3672*0ba2cbe9Sxc151355 	    wifi_longopts, NULL)) != -1) {
3673*0ba2cbe9Sxc151355 		switch (option) {
3674*0ba2cbe9Sxc151355 		case 't':
3675*0ba2cbe9Sxc151355 			temp = B_TRUE;
3676*0ba2cbe9Sxc151355 			break;
3677*0ba2cbe9Sxc151355 		case 'R':
3678*0ba2cbe9Sxc151355 			status = dladm_set_rootdir(optarg);
3679*0ba2cbe9Sxc151355 			if (status != DLADM_STATUS_OK) {
3680*0ba2cbe9Sxc151355 				(void) fprintf(stderr, gettext(
3681*0ba2cbe9Sxc151355 				    "%s: invalid directory specified: %s\n"),
3682*0ba2cbe9Sxc151355 				    progname, dladm_status2str(status, errmsg));
3683*0ba2cbe9Sxc151355 				exit(1);
3684*0ba2cbe9Sxc151355 			}
3685*0ba2cbe9Sxc151355 			break;
3686*0ba2cbe9Sxc151355 		case ':':
3687*0ba2cbe9Sxc151355 			(void) fprintf(stderr,
3688*0ba2cbe9Sxc151355 			    gettext("%s: option requires a value '-%c'\n"),
3689*0ba2cbe9Sxc151355 			    progname, optopt);
3690*0ba2cbe9Sxc151355 			exit(1);
3691*0ba2cbe9Sxc151355 			break;
3692*0ba2cbe9Sxc151355 		case '?':
3693*0ba2cbe9Sxc151355 		default:
3694*0ba2cbe9Sxc151355 			(void) fprintf(stderr,
3695*0ba2cbe9Sxc151355 			    gettext("%s: unrecognized option '-%c'\n"),
3696*0ba2cbe9Sxc151355 			    progname, optopt);
3697*0ba2cbe9Sxc151355 			exit(1);
3698*0ba2cbe9Sxc151355 			break;
3699*0ba2cbe9Sxc151355 		}
3700*0ba2cbe9Sxc151355 	}
3701*0ba2cbe9Sxc151355 
3702*0ba2cbe9Sxc151355 	if (optind == (argc - 1)) {
3703*0ba2cbe9Sxc151355 		sp = split(argv[optind], MAX_SECOBJS, MAX_SECOBJ_NAMELEN);
3704*0ba2cbe9Sxc151355 		if (sp == NULL) {
3705*0ba2cbe9Sxc151355 			(void) fprintf(stderr, gettext(
3706*0ba2cbe9Sxc151355 			    "%s: invalid secure object name(s): '%s'\n"),
3707*0ba2cbe9Sxc151355 			    progname, argv[optind]);
3708*0ba2cbe9Sxc151355 			exit(1);
3709*0ba2cbe9Sxc151355 		}
3710*0ba2cbe9Sxc151355 	} else if (optind != argc)
3711*0ba2cbe9Sxc151355 		usage();
3712*0ba2cbe9Sxc151355 
3713*0ba2cbe9Sxc151355 	if (sp == NULL || sp->s_nfields < 1) {
3714*0ba2cbe9Sxc151355 		(void) fprintf(stderr,
3715*0ba2cbe9Sxc151355 		    gettext("%s: secure object name required\n"),
3716*0ba2cbe9Sxc151355 		    progname);
3717*0ba2cbe9Sxc151355 		exit(1);
3718*0ba2cbe9Sxc151355 	}
3719*0ba2cbe9Sxc151355 
3720*0ba2cbe9Sxc151355 	success = check_auth(LINK_SEC_AUTH);
3721*0ba2cbe9Sxc151355 	audit_secobj(LINK_SEC_AUTH, "wep", argv[optind], success, B_FALSE);
3722*0ba2cbe9Sxc151355 	if (!success) {
3723*0ba2cbe9Sxc151355 		(void) fprintf(stderr,
3724*0ba2cbe9Sxc151355 		    gettext("%s: authorization '%s' is required\n"),
3725*0ba2cbe9Sxc151355 		    progname, LINK_SEC_AUTH);
3726*0ba2cbe9Sxc151355 		exit(1);
3727*0ba2cbe9Sxc151355 	}
3728*0ba2cbe9Sxc151355 
3729*0ba2cbe9Sxc151355 	for (i = 0; i < sp->s_nfields; i++) {
3730*0ba2cbe9Sxc151355 		status = dladm_unset_secobj(sp->s_fields[i], DLADM_OPT_TEMP);
3731*0ba2cbe9Sxc151355 		if (!temp) {
3732*0ba2cbe9Sxc151355 			pstatus = dladm_unset_secobj(sp->s_fields[i],
3733*0ba2cbe9Sxc151355 			    DLADM_OPT_PERSIST);
3734*0ba2cbe9Sxc151355 		} else {
3735*0ba2cbe9Sxc151355 			pstatus = DLADM_STATUS_OK;
3736*0ba2cbe9Sxc151355 		}
3737*0ba2cbe9Sxc151355 
3738*0ba2cbe9Sxc151355 		if (status != DLADM_STATUS_OK) {
3739*0ba2cbe9Sxc151355 			(void) fprintf(stderr, gettext(
3740*0ba2cbe9Sxc151355 			    "%s: could not delete secure object '%s': %s\n"),
3741*0ba2cbe9Sxc151355 			    progname, sp->s_fields[i],
3742*0ba2cbe9Sxc151355 			    dladm_status2str(status, errmsg));
3743*0ba2cbe9Sxc151355 		}
3744*0ba2cbe9Sxc151355 		if (pstatus != DLADM_STATUS_OK) {
3745*0ba2cbe9Sxc151355 			(void) fprintf(stderr, gettext("%s: warning: could not "
3746*0ba2cbe9Sxc151355 			    "persistently delete secure object '%s': %s\n"),
3747*0ba2cbe9Sxc151355 			    progname, sp->s_fields[i],
3748*0ba2cbe9Sxc151355 			    dladm_status2str(pstatus, errmsg));
3749*0ba2cbe9Sxc151355 		}
3750*0ba2cbe9Sxc151355 	}
3751*0ba2cbe9Sxc151355 	if (status != DLADM_STATUS_OK || pstatus != DLADM_STATUS_OK)
3752*0ba2cbe9Sxc151355 		exit(1);
3753*0ba2cbe9Sxc151355 }
3754*0ba2cbe9Sxc151355 
3755*0ba2cbe9Sxc151355 typedef struct show_secobj_state {
3756*0ba2cbe9Sxc151355 	boolean_t	ss_persist;
3757*0ba2cbe9Sxc151355 	boolean_t	ss_parseable;
3758*0ba2cbe9Sxc151355 	boolean_t	ss_debug;
3759*0ba2cbe9Sxc151355 	boolean_t	ss_header;
3760*0ba2cbe9Sxc151355 } show_secobj_state_t;
3761*0ba2cbe9Sxc151355 
3762*0ba2cbe9Sxc151355 static void
3763*0ba2cbe9Sxc151355 print_secobj_head(show_secobj_state_t *statep)
3764*0ba2cbe9Sxc151355 {
3765*0ba2cbe9Sxc151355 	(void) printf("%-20s %-20s ", "OBJECT", "CLASS");
3766*0ba2cbe9Sxc151355 	if (statep->ss_debug)
3767*0ba2cbe9Sxc151355 		(void) printf("%-30s", "VALUE");
3768*0ba2cbe9Sxc151355 	(void) putchar('\n');
3769*0ba2cbe9Sxc151355 }
3770*0ba2cbe9Sxc151355 
3771*0ba2cbe9Sxc151355 static boolean_t
3772*0ba2cbe9Sxc151355 show_secobj(void *arg, const char *obj_name)
3773*0ba2cbe9Sxc151355 {
3774*0ba2cbe9Sxc151355 	uint_t			obj_len = DLADM_SECOBJ_VAL_MAX;
3775*0ba2cbe9Sxc151355 	uint8_t			obj_val[DLADM_SECOBJ_VAL_MAX];
3776*0ba2cbe9Sxc151355 	char			buf[DLADM_STRSIZE];
3777*0ba2cbe9Sxc151355 	uint_t			flags = 0;
3778*0ba2cbe9Sxc151355 	dladm_secobj_class_t	class;
3779*0ba2cbe9Sxc151355 	show_secobj_state_t	*statep = arg;
3780*0ba2cbe9Sxc151355 	dladm_status_t		status;
3781*0ba2cbe9Sxc151355 
3782*0ba2cbe9Sxc151355 	if (statep->ss_persist)
3783*0ba2cbe9Sxc151355 		flags |= DLADM_OPT_PERSIST;
3784*0ba2cbe9Sxc151355 
3785*0ba2cbe9Sxc151355 	status = dladm_get_secobj(obj_name, &class, obj_val, &obj_len, flags);
3786*0ba2cbe9Sxc151355 	if (status != DLADM_STATUS_OK) {
3787*0ba2cbe9Sxc151355 		(void) fprintf(stderr, gettext(
3788*0ba2cbe9Sxc151355 		    "%s: cannot get secure object '%s': %s\n"), progname,
3789*0ba2cbe9Sxc151355 		    obj_name, dladm_status2str(status, buf));
3790*0ba2cbe9Sxc151355 		exit(1);
3791*0ba2cbe9Sxc151355 	}
3792*0ba2cbe9Sxc151355 
3793*0ba2cbe9Sxc151355 	if (statep->ss_header) {
3794*0ba2cbe9Sxc151355 		statep->ss_header = B_FALSE;
3795*0ba2cbe9Sxc151355 		if (!statep->ss_parseable)
3796*0ba2cbe9Sxc151355 			print_secobj_head(statep);
3797*0ba2cbe9Sxc151355 	}
3798*0ba2cbe9Sxc151355 
3799*0ba2cbe9Sxc151355 	if (statep->ss_parseable) {
3800*0ba2cbe9Sxc151355 		(void) printf("OBJECT=\"%s\" CLASS=\"%s\" ", obj_name,
3801*0ba2cbe9Sxc151355 		    dladm_secobjclass2str(class, buf));
3802*0ba2cbe9Sxc151355 	} else {
3803*0ba2cbe9Sxc151355 		(void) printf("%-20s %-20s ", obj_name,
3804*0ba2cbe9Sxc151355 		    dladm_secobjclass2str(class, buf));
3805*0ba2cbe9Sxc151355 	}
3806*0ba2cbe9Sxc151355 
3807*0ba2cbe9Sxc151355 	if (statep->ss_debug) {
3808*0ba2cbe9Sxc151355 		char 	val[DLADM_SECOBJ_VAL_MAX * 2];
3809*0ba2cbe9Sxc151355 		uint_t	len = sizeof (val);
3810*0ba2cbe9Sxc151355 
3811*0ba2cbe9Sxc151355 		if (octet_to_hexascii(obj_val, obj_len, val, &len) == 0) {
3812*0ba2cbe9Sxc151355 			if (statep->ss_parseable)
3813*0ba2cbe9Sxc151355 				(void) printf("VALUE=\"0x%s\"", val);
3814*0ba2cbe9Sxc151355 			else
3815*0ba2cbe9Sxc151355 				(void) printf("0x%-30s", val);
3816*0ba2cbe9Sxc151355 		}
3817*0ba2cbe9Sxc151355 	}
3818*0ba2cbe9Sxc151355 	(void) putchar('\n');
3819*0ba2cbe9Sxc151355 	return (B_TRUE);
3820*0ba2cbe9Sxc151355 }
3821*0ba2cbe9Sxc151355 
3822*0ba2cbe9Sxc151355 static void
3823*0ba2cbe9Sxc151355 do_show_secobj(int argc, char **argv)
3824*0ba2cbe9Sxc151355 {
3825*0ba2cbe9Sxc151355 	int			option;
3826*0ba2cbe9Sxc151355 	show_secobj_state_t	state;
3827*0ba2cbe9Sxc151355 	dladm_status_t		status;
3828*0ba2cbe9Sxc151355 	uint_t			i;
3829*0ba2cbe9Sxc151355 	char			errmsg[DLADM_STRSIZE];
3830*0ba2cbe9Sxc151355 	split_t			*sp;
3831*0ba2cbe9Sxc151355 	uint_t			flags;
3832*0ba2cbe9Sxc151355 
3833*0ba2cbe9Sxc151355 	opterr = 0;
3834*0ba2cbe9Sxc151355 	state.ss_persist = B_FALSE;
3835*0ba2cbe9Sxc151355 	state.ss_parseable = B_FALSE;
3836*0ba2cbe9Sxc151355 	state.ss_debug = B_FALSE;
3837*0ba2cbe9Sxc151355 	state.ss_header = B_TRUE;
3838*0ba2cbe9Sxc151355 	while ((option = getopt_long(argc, argv, ":pPd",
3839*0ba2cbe9Sxc151355 	    wifi_longopts, NULL)) != -1) {
3840*0ba2cbe9Sxc151355 		switch (option) {
3841*0ba2cbe9Sxc151355 		case 'p':
3842*0ba2cbe9Sxc151355 			state.ss_parseable = B_TRUE;
3843*0ba2cbe9Sxc151355 			break;
3844*0ba2cbe9Sxc151355 		case 'P':
3845*0ba2cbe9Sxc151355 			state.ss_persist = B_TRUE;
3846*0ba2cbe9Sxc151355 			break;
3847*0ba2cbe9Sxc151355 		case 'd':
3848*0ba2cbe9Sxc151355 			if (getuid() != 0) {
3849*0ba2cbe9Sxc151355 				(void) fprintf(stderr,
3850*0ba2cbe9Sxc151355 				    gettext("%s: insufficient privileges\n"),
3851*0ba2cbe9Sxc151355 				    progname);
3852*0ba2cbe9Sxc151355 				exit(1);
3853*0ba2cbe9Sxc151355 			}
3854*0ba2cbe9Sxc151355 			state.ss_debug = B_TRUE;
3855*0ba2cbe9Sxc151355 			break;
3856*0ba2cbe9Sxc151355 		case ':':
3857*0ba2cbe9Sxc151355 			(void) fprintf(stderr,
3858*0ba2cbe9Sxc151355 			    gettext("%s: option requires a value '-%c'\n"),
3859*0ba2cbe9Sxc151355 			    progname, optopt);
3860*0ba2cbe9Sxc151355 			exit(1);
3861*0ba2cbe9Sxc151355 			break;
3862*0ba2cbe9Sxc151355 		case '?':
3863*0ba2cbe9Sxc151355 		default:
3864*0ba2cbe9Sxc151355 			(void) fprintf(stderr,
3865*0ba2cbe9Sxc151355 			    gettext("%s: unrecognized option '-%c'\n"),
3866*0ba2cbe9Sxc151355 			    progname, optopt);
3867*0ba2cbe9Sxc151355 			exit(1);
3868*0ba2cbe9Sxc151355 			break;
3869*0ba2cbe9Sxc151355 		}
3870*0ba2cbe9Sxc151355 	}
3871*0ba2cbe9Sxc151355 
3872*0ba2cbe9Sxc151355 	if (optind == (argc - 1)) {
3873*0ba2cbe9Sxc151355 		sp = split(argv[optind], MAX_SECOBJS, MAX_SECOBJ_NAMELEN);
3874*0ba2cbe9Sxc151355 		if (sp == NULL) {
3875*0ba2cbe9Sxc151355 			(void) fprintf(stderr, gettext(
3876*0ba2cbe9Sxc151355 			    "%s: invalid secure object name(s): '%s'\n"),
3877*0ba2cbe9Sxc151355 			    progname, argv[optind]);
3878*0ba2cbe9Sxc151355 			exit(1);
3879*0ba2cbe9Sxc151355 		}
3880*0ba2cbe9Sxc151355 		for (i = 0; i < sp->s_nfields; i++) {
3881*0ba2cbe9Sxc151355 			if (!show_secobj(&state, sp->s_fields[i]))
3882*0ba2cbe9Sxc151355 				break;
3883*0ba2cbe9Sxc151355 		}
3884*0ba2cbe9Sxc151355 		splitfree(sp);
3885*0ba2cbe9Sxc151355 		return;
3886*0ba2cbe9Sxc151355 	} else if (optind != argc)
3887*0ba2cbe9Sxc151355 		usage();
3888*0ba2cbe9Sxc151355 
3889*0ba2cbe9Sxc151355 	flags = state.ss_persist ? DLADM_OPT_PERSIST : 0;
3890*0ba2cbe9Sxc151355 	status = dladm_walk_secobj(&state, show_secobj, flags);
3891*0ba2cbe9Sxc151355 	if (status != DLADM_STATUS_OK) {
3892*0ba2cbe9Sxc151355 		(void) fprintf(stderr, gettext("%s: show-secobj: %s\n"),
3893*0ba2cbe9Sxc151355 		    progname, dladm_status2str(status, errmsg));
3894*0ba2cbe9Sxc151355 		exit(1);
3895*0ba2cbe9Sxc151355 	}
3896*0ba2cbe9Sxc151355 }
3897*0ba2cbe9Sxc151355 
3898*0ba2cbe9Sxc151355 /* ARGSUSED */
3899*0ba2cbe9Sxc151355 static void
3900*0ba2cbe9Sxc151355 do_init_linkprop(int argc, char **argv)
3901*0ba2cbe9Sxc151355 {
3902*0ba2cbe9Sxc151355 	char		errmsg[DLADM_STRSIZE];
3903*0ba2cbe9Sxc151355 	dladm_status_t	status;
3904*0ba2cbe9Sxc151355 
3905*0ba2cbe9Sxc151355 	status = dladm_init_linkprop();
3906*0ba2cbe9Sxc151355 	if (status != DLADM_STATUS_OK) {
3907*0ba2cbe9Sxc151355 		(void) fprintf(stderr,
3908*0ba2cbe9Sxc151355 		    gettext("%s: link property initialization failed: %s\n"),
3909*0ba2cbe9Sxc151355 		    progname, dladm_status2str(status, errmsg));
3910*0ba2cbe9Sxc151355 		exit(1);
3911*0ba2cbe9Sxc151355 	}
3912*0ba2cbe9Sxc151355 }
3913*0ba2cbe9Sxc151355 
3914*0ba2cbe9Sxc151355 /* ARGSUSED */
3915*0ba2cbe9Sxc151355 static void
3916*0ba2cbe9Sxc151355 do_init_secobj(int argc, char **argv)
3917*0ba2cbe9Sxc151355 {
3918*0ba2cbe9Sxc151355 	char		errmsg[DLADM_STRSIZE];
3919*0ba2cbe9Sxc151355 	dladm_status_t	status;
3920*0ba2cbe9Sxc151355 
3921*0ba2cbe9Sxc151355 	status = dladm_init_secobj();
3922*0ba2cbe9Sxc151355 	if (status != DLADM_STATUS_OK) {
3923*0ba2cbe9Sxc151355 		(void) fprintf(stderr,
3924*0ba2cbe9Sxc151355 		    gettext("%s: secure object initialization failed: %s\n"),
3925*0ba2cbe9Sxc151355 		    progname, dladm_status2str(status, errmsg));
3926*0ba2cbe9Sxc151355 		exit(1);
3927*0ba2cbe9Sxc151355 	}
3928*0ba2cbe9Sxc151355 }
3929