xref: /titanic_53/usr/src/cmd/dladm/dladm.c (revision e7801d59e8ceda0cde8ebdfdddd7582ee2ea96ef)
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 /*
22d62bc4baSyz147064  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate #include <stdio.h>
290ba2cbe9Sxc151355 #include <ctype.h>
307c478bd9Sstevel@tonic-gate #include <locale.h>
310ba2cbe9Sxc151355 #include <signal.h>
327c478bd9Sstevel@tonic-gate #include <stdarg.h>
337c478bd9Sstevel@tonic-gate #include <stdlib.h>
347c478bd9Sstevel@tonic-gate #include <fcntl.h>
357c478bd9Sstevel@tonic-gate #include <string.h>
367c478bd9Sstevel@tonic-gate #include <stropts.h>
37d62bc4baSyz147064 #include <sys/stat.h>
387c478bd9Sstevel@tonic-gate #include <errno.h>
397c478bd9Sstevel@tonic-gate #include <kstat.h>
407c478bd9Sstevel@tonic-gate #include <strings.h>
417c478bd9Sstevel@tonic-gate #include <getopt.h>
427c478bd9Sstevel@tonic-gate #include <unistd.h>
43cd93090eSericheng #include <priv.h>
440ba2cbe9Sxc151355 #include <termios.h>
450ba2cbe9Sxc151355 #include <pwd.h>
460ba2cbe9Sxc151355 #include <auth_attr.h>
470ba2cbe9Sxc151355 #include <auth_list.h>
487c478bd9Sstevel@tonic-gate #include <libintl.h>
49d62bc4baSyz147064 #include <libdevinfo.h>
507c478bd9Sstevel@tonic-gate #include <libdlpi.h>
51f595a68aSyz147064 #include <libdllink.h>
52f595a68aSyz147064 #include <libdlaggr.h>
53f595a68aSyz147064 #include <libdlwlan.h>
54d62bc4baSyz147064 #include <libdlvlan.h>
55d62bc4baSyz147064 #include <libdlvnic.h>
560ba2cbe9Sxc151355 #include <libinetutil.h>
570ba2cbe9Sxc151355 #include <bsm/adt.h>
580ba2cbe9Sxc151355 #include <bsm/adt_event.h>
59*e7801d59Ssowmini #include <stddef.h>
607c478bd9Sstevel@tonic-gate 
61ba2e4443Sseb #define	AGGR_DRV		"aggr"
62*e7801d59Ssowmini #define	STR_UNDEF_VAL		"--"
637c478bd9Sstevel@tonic-gate #define	MAXPORT			256
64d62bc4baSyz147064 #define	BUFLEN(lim, ptr)	(((lim) > (ptr)) ? ((lim) - (ptr)) : 0)
65d62bc4baSyz147064 #define	MAXLINELEN		1024
66d62bc4baSyz147064 #define	SMF_UPGRADE_FILE		"/var/svc/profile/upgrade"
67d62bc4baSyz147064 #define	SMF_UPGRADEDATALINK_FILE	"/var/svc/profile/upgrade_datalink"
68d62bc4baSyz147064 #define	SMF_DLADM_UPGRADE_MSG		" # added by dladm(1M)"
697c478bd9Sstevel@tonic-gate 
70*e7801d59Ssowmini #define	CMD_TYPE_ANY		0xffffffff
71*e7801d59Ssowmini #define	WIFI_CMD_SCAN		0x00000001
72*e7801d59Ssowmini #define	WIFI_CMD_SHOW		0x00000002
73*e7801d59Ssowmini #define	WIFI_CMD_ALL		(WIFI_CMD_SCAN | WIFI_CMD_SHOW)
74*e7801d59Ssowmini 
75*e7801d59Ssowmini /*
76*e7801d59Ssowmini  * data structures and routines for printing output.
77*e7801d59Ssowmini  * All non-parseable output is assumed to be in a columnar format.
78*e7801d59Ssowmini  * Parseable output will be printed as <pf_header>="<value>"
79*e7801d59Ssowmini  *
80*e7801d59Ssowmini  * Each sub-command is associated with a global array of pointers,
81*e7801d59Ssowmini  * print_field_t *fields[], where the print_field_t contains information
82*e7801d59Ssowmini  * about the format in which the output is  to be printed.
83*e7801d59Ssowmini  *
84*e7801d59Ssowmini  * Sub-commands may be implemented in one of two ways:
85*e7801d59Ssowmini  * (i)  the implementation could get all field values into a character
86*e7801d59Ssowmini  *      buffer, with pf_offset containing the offset (for pf_name) within
87*e7801d59Ssowmini  *      the buffer. The sub-command would make the needed system calls
88*e7801d59Ssowmini  *      to obtain all possible column values and then invoke the
89*e7801d59Ssowmini  *      dladm_print_field() function to print the specific fields
90*e7801d59Ssowmini  *      requested in the command line. See the comments for dladm_print_field
91*e7801d59Ssowmini  *      for further details.
92*e7801d59Ssowmini  * (ii) Alternatively, each fields[i] entry could store a pf_index value
93*e7801d59Ssowmini  *      that uniquely identifies the column to be printed. The implementation
94*e7801d59Ssowmini  *      of the sub-command would then invoke dladm_print_output() with a
95*e7801d59Ssowmini  *      callback function whose semantics are described below (see comments
96*e7801d59Ssowmini  *      for dladm_print_output())
97*e7801d59Ssowmini  *
98*e7801d59Ssowmini  * Thus, an implementation of a sub-command must provide the following:
99*e7801d59Ssowmini  *
100*e7801d59Ssowmini  * static print_field_t sub_command_fields[] = {
101*e7801d59Ssowmini  *	{<name>, <header>,<field width>,  <offset_or_index>, cmdtype},
102*e7801d59Ssowmini  *	:
103*e7801d59Ssowmini  *	{<name>, <header>,<field width>,  <offset_or_index>, cmdtype}
104*e7801d59Ssowmini  * };
105*e7801d59Ssowmini  *
106*e7801d59Ssowmini  * #define	SUB_COMMAND_MAX_FIELDS sizeof \
107*e7801d59Ssowmini  *		(sub_comand_fields) / sizeof (print_field_t))
108*e7801d59Ssowmini  *
109*e7801d59Ssowmini  * print_state_t sub_command_print_state;
110*e7801d59Ssowmini  *
111*e7801d59Ssowmini  * The function that parses command line arguments (typically
112*e7801d59Ssowmini  * do_sub_command()) should then contain an invocation like:
113*e7801d59Ssowmini  *
114*e7801d59Ssowmini  *	fields = parse_output_fields(fields_str, sub_command_fields,
115*e7801d59Ssowmini  *	    SUB_COMMAND_MAX_FIELDS, CMD_TYPE_ANY, &nfields);
116*e7801d59Ssowmini  *
117*e7801d59Ssowmini  * and store the resulting fields and nfields value in a print_state_t
118*e7801d59Ssowmini  * structure tracked for the command.
119*e7801d59Ssowmini  *
120*e7801d59Ssowmini  *	sub_command_print_state.ps_fields = fields;
121*e7801d59Ssowmini  *	sub_command_print_state.ps_nfields = nfields;
122*e7801d59Ssowmini  *
123*e7801d59Ssowmini  * To print the column header for the output, the print_header()
124*e7801d59Ssowmini  * function must then be invoked by do_sub_command().
125*e7801d59Ssowmini  *
126*e7801d59Ssowmini  * Then if method (i) is used for the sub_command, the do_sub_command()
127*e7801d59Ssowmini  * function should make the necessary system calls to fill up the buffer
128*e7801d59Ssowmini  * and then invoke dladm_print_field(). An example of this method is
129*e7801d59Ssowmini  * the implementation of do_show_link() and show_link();
130*e7801d59Ssowmini  *
131*e7801d59Ssowmini  * If method (ii) is used, do_sub_command should invoke dladm_print_output()
132*e7801d59Ssowmini  * with a callback function that will be called for each field to be printed.
133*e7801d59Ssowmini  * The callback function will be passed a pointer to the print_field_t
134*e7801d59Ssowmini  * for the field, and the pf_index may then be used to identify the
135*e7801d59Ssowmini  * system call required to find the value to be printed. An example of
136*e7801d59Ssowmini  * this implementation may be found in the do_show_dev() and print_dev()
137*e7801d59Ssowmini  * invocation.
138*e7801d59Ssowmini  */
139*e7801d59Ssowmini 
140*e7801d59Ssowmini typedef struct print_field_s {
141*e7801d59Ssowmini 	const char	*pf_name;	/* name of column to be printed */
142*e7801d59Ssowmini 	const char	*pf_header;	/* header for this column */
143*e7801d59Ssowmini 	uint_t		pf_width;
144*e7801d59Ssowmini 	union {
145*e7801d59Ssowmini 		uint_t	_pf_index;	/* private index for sub-command */
146*e7801d59Ssowmini 		size_t	_pf_offset;
147*e7801d59Ssowmini 	}_pf_un;
148*e7801d59Ssowmini #define	pf_index	_pf_un._pf_index
149*e7801d59Ssowmini #define	pf_offset	_pf_un._pf_offset;
150*e7801d59Ssowmini 	uint_t		pf_cmdtype;
151*e7801d59Ssowmini } print_field_t;
152*e7801d59Ssowmini 
153*e7801d59Ssowmini /*
154*e7801d59Ssowmini  * The state of the output is tracked in a print_state_t structure.
155*e7801d59Ssowmini  * Each ps_fields[i] entry points at the global print_field_t array for
156*e7801d59Ssowmini  * the sub-command, where ps_nfields is the number of requested fields.
157*e7801d59Ssowmini  */
158*e7801d59Ssowmini typedef struct print_state_s {
159*e7801d59Ssowmini 	print_field_t	**ps_fields;
160*e7801d59Ssowmini 	uint_t		ps_nfields;
161*e7801d59Ssowmini 	boolean_t	ps_lastfield;
162*e7801d59Ssowmini 	uint_t		ps_overflow;
163*e7801d59Ssowmini } print_state_t;
164*e7801d59Ssowmini 
165*e7801d59Ssowmini typedef char *(*print_callback_t)(print_field_t *, void *);
166*e7801d59Ssowmini static print_field_t **parse_output_fields(char *, print_field_t *, int,
167*e7801d59Ssowmini     uint_t, uint_t *);
168*e7801d59Ssowmini /*
169*e7801d59Ssowmini  * print the header for the output
170*e7801d59Ssowmini  */
171*e7801d59Ssowmini static void print_header(print_state_t *);
172*e7801d59Ssowmini static void print_field(print_state_t *, print_field_t *, const char *,
173*e7801d59Ssowmini     boolean_t);
174*e7801d59Ssowmini 
175*e7801d59Ssowmini /*
176*e7801d59Ssowmini  * to print output values, call dladm_print_output with a callback
177*e7801d59Ssowmini  * function (*func)() that should parse the args and return an
178*e7801d59Ssowmini  * unformatted character buffer with the value to be printed.
179*e7801d59Ssowmini  *
180*e7801d59Ssowmini  * dladm_print_output() prints the character buffer using the formatting
181*e7801d59Ssowmini  * information provided in the print_field_t for that column.
182*e7801d59Ssowmini  */
183*e7801d59Ssowmini static void dladm_print_output(print_state_t *, boolean_t,
184*e7801d59Ssowmini     print_callback_t, void *);
185*e7801d59Ssowmini 
186*e7801d59Ssowmini /*
187*e7801d59Ssowmini  * helper function that, when invoked as dladm_print_field(pf, buf)
188*e7801d59Ssowmini  * prints string which is offset by pf->pf_offset  within buf
189*e7801d59Ssowmini  */
190*e7801d59Ssowmini static char *dladm_print_field(print_field_t *, void *);
191*e7801d59Ssowmini 
192*e7801d59Ssowmini 
193*e7801d59Ssowmini #define	MAX_FIELD_LEN	32
194*e7801d59Ssowmini 
195*e7801d59Ssowmini 
1967c478bd9Sstevel@tonic-gate typedef struct pktsum_s {
1977c478bd9Sstevel@tonic-gate 	uint64_t	ipackets;
1987c478bd9Sstevel@tonic-gate 	uint64_t	opackets;
1997c478bd9Sstevel@tonic-gate 	uint64_t	rbytes;
2007c478bd9Sstevel@tonic-gate 	uint64_t	obytes;
2017c478bd9Sstevel@tonic-gate 	uint32_t	ierrors;
2027c478bd9Sstevel@tonic-gate 	uint32_t	oerrors;
2037c478bd9Sstevel@tonic-gate } pktsum_t;
2047c478bd9Sstevel@tonic-gate 
205d62bc4baSyz147064 typedef struct show_state {
2067c478bd9Sstevel@tonic-gate 	boolean_t	ls_firstonly;
2077c478bd9Sstevel@tonic-gate 	boolean_t	ls_donefirst;
2087c478bd9Sstevel@tonic-gate 	pktsum_t	ls_prevstats;
209d62bc4baSyz147064 	uint32_t	ls_flags;
210d62bc4baSyz147064 	dladm_status_t	ls_status;
211*e7801d59Ssowmini 	print_state_t	ls_print;
212*e7801d59Ssowmini 	boolean_t	ls_parseable;
213*e7801d59Ssowmini 	boolean_t	ls_printheader;
214d62bc4baSyz147064 } show_state_t;
2157c478bd9Sstevel@tonic-gate 
2167c478bd9Sstevel@tonic-gate typedef struct show_grp_state {
217*e7801d59Ssowmini 	pktsum_t	gs_prevstats[MAXPORT];
218*e7801d59Ssowmini 	uint32_t	gs_flags;
219*e7801d59Ssowmini 	dladm_status_t	gs_status;
220*e7801d59Ssowmini 	boolean_t	gs_parseable;
2217c478bd9Sstevel@tonic-gate 	boolean_t	gs_lacp;
222d62bc4baSyz147064 	boolean_t	gs_extended;
2237c478bd9Sstevel@tonic-gate 	boolean_t	gs_stats;
2247c478bd9Sstevel@tonic-gate 	boolean_t	gs_firstonly;
225d62bc4baSyz147064 	boolean_t	gs_donefirst;
226*e7801d59Ssowmini 	boolean_t	gs_printheader;
227*e7801d59Ssowmini 	print_state_t	gs_print;
2287c478bd9Sstevel@tonic-gate } show_grp_state_t;
2297c478bd9Sstevel@tonic-gate 
2300ba2cbe9Sxc151355 typedef void cmdfunc_t(int, char **);
2310ba2cbe9Sxc151355 
232d62bc4baSyz147064 static cmdfunc_t do_show_link, do_show_dev, do_show_wifi, do_show_phys;
2330ba2cbe9Sxc151355 static cmdfunc_t do_create_aggr, do_delete_aggr, do_add_aggr, do_remove_aggr;
234d62bc4baSyz147064 static cmdfunc_t do_modify_aggr, do_show_aggr, do_up_aggr;
2350ba2cbe9Sxc151355 static cmdfunc_t do_scan_wifi, do_connect_wifi, do_disconnect_wifi;
2360ba2cbe9Sxc151355 static cmdfunc_t do_show_linkprop, do_set_linkprop, do_reset_linkprop;
2370ba2cbe9Sxc151355 static cmdfunc_t do_create_secobj, do_delete_secobj, do_show_secobj;
2380ba2cbe9Sxc151355 static cmdfunc_t do_init_linkprop, do_init_secobj;
239d62bc4baSyz147064 static cmdfunc_t do_create_vlan, do_delete_vlan, do_up_vlan, do_show_vlan;
240d62bc4baSyz147064 static cmdfunc_t do_rename_link, do_delete_phys, do_init_phys;
241d62bc4baSyz147064 static cmdfunc_t do_show_linkmap;
242*e7801d59Ssowmini static cmdfunc_t do_show_ether;
2437c478bd9Sstevel@tonic-gate 
244d62bc4baSyz147064 static void	altroot_cmd(char *, int, char **);
245d62bc4baSyz147064 static int	show_linkprop_onelink(datalink_id_t, void *);
246f4b3ec61Sdh155122 
247d62bc4baSyz147064 static void	link_stats(datalink_id_t, uint_t);
248d62bc4baSyz147064 static void	aggr_stats(datalink_id_t, show_grp_state_t *, uint_t);
249*e7801d59Ssowmini static void	dev_stats(const char *dev, uint32_t, char *, show_state_t *);
2507c478bd9Sstevel@tonic-gate 
251d62bc4baSyz147064 static int	get_one_kstat(const char *, const char *, uint8_t,
252d62bc4baSyz147064 		    void *, boolean_t);
253ba2e4443Sseb static void	get_mac_stats(const char *, pktsum_t *);
2547c478bd9Sstevel@tonic-gate static void	get_link_stats(const char *, pktsum_t *);
255d62bc4baSyz147064 static uint64_t	get_ifspeed(const char *, boolean_t);
2567c478bd9Sstevel@tonic-gate static void	stats_total(pktsum_t *, pktsum_t *, pktsum_t *);
2577c478bd9Sstevel@tonic-gate static void	stats_diff(pktsum_t *, pktsum_t *, pktsum_t *);
258d62bc4baSyz147064 static const char	*get_linkstate(const char *, boolean_t, char *);
259d62bc4baSyz147064 static const char	*get_linkduplex(const char *, boolean_t, char *);
2607c478bd9Sstevel@tonic-gate 
261*e7801d59Ssowmini static int	show_etherprop(datalink_id_t, void *);
262*e7801d59Ssowmini static void	show_ether_xprop(datalink_id_t, void *);
263*e7801d59Ssowmini static boolean_t get_speed_duplex(datalink_id_t, const char *, char *,
264*e7801d59Ssowmini     char *, boolean_t);
265*e7801d59Ssowmini static char 	*pause_str(int, int);
266*e7801d59Ssowmini static boolean_t	link_is_ether(const char *, datalink_id_t *);
267*e7801d59Ssowmini 
268*e7801d59Ssowmini #define	IS_FDX	0x10
269*e7801d59Ssowmini #define	IS_HDX	0x01
270*e7801d59Ssowmini 
27133343a97Smeem static boolean_t str2int(const char *, int *);
27233343a97Smeem static void	die(const char *, ...);
27333343a97Smeem static void	die_optdup(int);
27433343a97Smeem static void	die_opterr(int, int);
27533343a97Smeem static void	die_dlerr(dladm_status_t, const char *, ...);
27633343a97Smeem static void	warn(const char *, ...);
27733343a97Smeem static void	warn_dlerr(dladm_status_t, const char *, ...);
27833343a97Smeem 
2797c478bd9Sstevel@tonic-gate typedef struct	cmd {
2807c478bd9Sstevel@tonic-gate 	char		*c_name;
2810ba2cbe9Sxc151355 	cmdfunc_t	*c_fn;
2827c478bd9Sstevel@tonic-gate } cmd_t;
2837c478bd9Sstevel@tonic-gate 
2847c478bd9Sstevel@tonic-gate static cmd_t	cmds[] = {
2857c478bd9Sstevel@tonic-gate 	{ "show-link",		do_show_link		},
286210db224Sericheng 	{ "show-dev",		do_show_dev		},
2877c478bd9Sstevel@tonic-gate 	{ "create-aggr",	do_create_aggr		},
2887c478bd9Sstevel@tonic-gate 	{ "delete-aggr",	do_delete_aggr		},
2897c478bd9Sstevel@tonic-gate 	{ "add-aggr",		do_add_aggr		},
2907c478bd9Sstevel@tonic-gate 	{ "remove-aggr",	do_remove_aggr		},
2917c478bd9Sstevel@tonic-gate 	{ "modify-aggr",	do_modify_aggr		},
2927c478bd9Sstevel@tonic-gate 	{ "show-aggr",		do_show_aggr		},
2937c478bd9Sstevel@tonic-gate 	{ "up-aggr",		do_up_aggr		},
2940ba2cbe9Sxc151355 	{ "scan-wifi",		do_scan_wifi		},
2950ba2cbe9Sxc151355 	{ "connect-wifi",	do_connect_wifi		},
2960ba2cbe9Sxc151355 	{ "disconnect-wifi",	do_disconnect_wifi	},
2970ba2cbe9Sxc151355 	{ "show-wifi",		do_show_wifi		},
2980ba2cbe9Sxc151355 	{ "show-linkprop",	do_show_linkprop	},
2990ba2cbe9Sxc151355 	{ "set-linkprop",	do_set_linkprop		},
3000ba2cbe9Sxc151355 	{ "reset-linkprop",	do_reset_linkprop	},
301*e7801d59Ssowmini 	{ "show-ether",		do_show_ether		},
3020ba2cbe9Sxc151355 	{ "create-secobj",	do_create_secobj	},
3030ba2cbe9Sxc151355 	{ "delete-secobj",	do_delete_secobj	},
3040ba2cbe9Sxc151355 	{ "show-secobj",	do_show_secobj		},
3050ba2cbe9Sxc151355 	{ "init-linkprop",	do_init_linkprop	},
306d62bc4baSyz147064 	{ "init-secobj",	do_init_secobj		},
307d62bc4baSyz147064 	{ "create-vlan", 	do_create_vlan 		},
308d62bc4baSyz147064 	{ "delete-vlan", 	do_delete_vlan 		},
309d62bc4baSyz147064 	{ "show-vlan",		do_show_vlan		},
310d62bc4baSyz147064 	{ "up-vlan",		do_up_vlan		},
311d62bc4baSyz147064 	{ "rename-link",	do_rename_link 		},
312d62bc4baSyz147064 	{ "delete-phys",	do_delete_phys 		},
313d62bc4baSyz147064 	{ "show-phys",		do_show_phys		},
314d62bc4baSyz147064 	{ "init-phys",		do_init_phys		},
315d62bc4baSyz147064 	{ "show-linkmap",	do_show_linkmap		}
3167c478bd9Sstevel@tonic-gate };
3177c478bd9Sstevel@tonic-gate 
318d62bc4baSyz147064 static const struct option lopts[] = {
3197c478bd9Sstevel@tonic-gate 	{"vlan-id",	required_argument,	0, 'v'},
320*e7801d59Ssowmini 	{"output",	required_argument,	0, 'o'},
3217c478bd9Sstevel@tonic-gate 	{"dev",		required_argument,	0, 'd'},
3227c478bd9Sstevel@tonic-gate 	{"policy",	required_argument,	0, 'P'},
323d62bc4baSyz147064 	{"lacp-mode",	required_argument,	0, 'L'},
3247c478bd9Sstevel@tonic-gate 	{"lacp-timer",	required_argument,	0, 'T'},
3257c478bd9Sstevel@tonic-gate 	{"unicast",	required_argument,	0, 'u'},
326d62bc4baSyz147064 	{"temporary",	no_argument,		0, 't'},
327d62bc4baSyz147064 	{"root-dir",	required_argument,	0, 'R'},
328d62bc4baSyz147064 	{"link",	required_argument,	0, 'l'},
329d62bc4baSyz147064 	{"forcible",	no_argument,		0, 'f'},
330d62bc4baSyz147064 	{ 0, 0, 0, 0 }
331d62bc4baSyz147064 };
332d62bc4baSyz147064 
333d62bc4baSyz147064 static const struct option show_lopts[] = {
3347c478bd9Sstevel@tonic-gate 	{"statistics",	no_argument,		0, 's'},
3357c478bd9Sstevel@tonic-gate 	{"interval",	required_argument,	0, 'i'},
3367c478bd9Sstevel@tonic-gate 	{"parseable",	no_argument,		0, 'p'},
337d62bc4baSyz147064 	{"extended",	no_argument,		0, 'x'},
338*e7801d59Ssowmini 	{"output",	required_argument,	0, 'o'},
339d62bc4baSyz147064 	{"persistent",	no_argument,		0, 'P'},
340d62bc4baSyz147064 	{"lacp",	no_argument,		0, 'L'},
3417c478bd9Sstevel@tonic-gate 	{ 0, 0, 0, 0 }
3427c478bd9Sstevel@tonic-gate };
3437c478bd9Sstevel@tonic-gate 
3440ba2cbe9Sxc151355 static const struct option prop_longopts[] = {
3450ba2cbe9Sxc151355 	{"temporary",	no_argument,		0, 't'  },
346*e7801d59Ssowmini 	{"output",	required_argument,	0, 'o'  },
3470ba2cbe9Sxc151355 	{"root-dir",	required_argument,	0, 'R'  },
3480ba2cbe9Sxc151355 	{"prop",	required_argument,	0, 'p'  },
3490ba2cbe9Sxc151355 	{"parseable",	no_argument,		0, 'c'  },
3500ba2cbe9Sxc151355 	{"persistent",	no_argument,		0, 'P'  },
3510ba2cbe9Sxc151355 	{ 0, 0, 0, 0 }
3520ba2cbe9Sxc151355 };
3530ba2cbe9Sxc151355 
3540ba2cbe9Sxc151355 static const struct option wifi_longopts[] = {
3550ba2cbe9Sxc151355 	{"parseable",	no_argument,		0, 'p'  },
3560ba2cbe9Sxc151355 	{"output",	required_argument,	0, 'o'  },
3570ba2cbe9Sxc151355 	{"essid",	required_argument,	0, 'e'  },
3580ba2cbe9Sxc151355 	{"bsstype",	required_argument,	0, 'b'  },
3590ba2cbe9Sxc151355 	{"mode",	required_argument,	0, 'm'  },
3600ba2cbe9Sxc151355 	{"key",		required_argument,	0, 'k'  },
3610ba2cbe9Sxc151355 	{"sec",		required_argument,	0, 's'  },
3620ba2cbe9Sxc151355 	{"auth",	required_argument,	0, 'a'  },
3630ba2cbe9Sxc151355 	{"create-ibss",	required_argument,	0, 'c'  },
3640ba2cbe9Sxc151355 	{"timeout",	required_argument,	0, 'T'  },
3650ba2cbe9Sxc151355 	{"all-links",	no_argument,		0, 'a'  },
3660ba2cbe9Sxc151355 	{"temporary",	no_argument,		0, 't'  },
3670ba2cbe9Sxc151355 	{"root-dir",	required_argument,	0, 'R'  },
3680ba2cbe9Sxc151355 	{"persistent",	no_argument,		0, 'P'  },
3690ba2cbe9Sxc151355 	{"file",	required_argument,	0, 'f'  },
3700ba2cbe9Sxc151355 	{ 0, 0, 0, 0 }
3710ba2cbe9Sxc151355 };
372*e7801d59Ssowmini static const struct option showeth_lopts[] = {
373*e7801d59Ssowmini 	{"parseable",	no_argument,		0, 'p'	},
374*e7801d59Ssowmini 	{"extended",	no_argument,		0, 'x'	},
375*e7801d59Ssowmini 	{"output",	required_argument,	0, 'o'	},
376*e7801d59Ssowmini 	{ 0, 0, 0, 0 }
377*e7801d59Ssowmini };
378*e7801d59Ssowmini 
379*e7801d59Ssowmini /*
380*e7801d59Ssowmini  * structures for 'dladm show-ether'
381*e7801d59Ssowmini  */
382*e7801d59Ssowmini typedef struct ether_fields_buf_s
383*e7801d59Ssowmini {
384*e7801d59Ssowmini 	char	eth_link[15];
385*e7801d59Ssowmini 	char	eth_ptype[8];
386*e7801d59Ssowmini 	char	eth_state[8];
387*e7801d59Ssowmini 	char	eth_autoneg[5];
388*e7801d59Ssowmini 	char	eth_spdx[31];
389*e7801d59Ssowmini 	char	eth_pause[6];
390*e7801d59Ssowmini 	char	eth_rem_fault[16];
391*e7801d59Ssowmini } ether_fields_buf_t;
392*e7801d59Ssowmini 
393*e7801d59Ssowmini static print_field_t ether_fields[] = {
394*e7801d59Ssowmini /* name,	header,			field width,  offset,	cmdtype */
395*e7801d59Ssowmini { "link",	"LINK",			15,
396*e7801d59Ssowmini     offsetof(ether_fields_buf_t, eth_link),	CMD_TYPE_ANY},
397*e7801d59Ssowmini { "ptype",	"PTYPE",		8,
398*e7801d59Ssowmini     offsetof(ether_fields_buf_t, eth_ptype),	CMD_TYPE_ANY},
399*e7801d59Ssowmini { "state",	"STATE",		8,
400*e7801d59Ssowmini     offsetof(ether_fields_buf_t, eth_state),	CMD_TYPE_ANY},
401*e7801d59Ssowmini { "auto",	"AUTO",			5,
402*e7801d59Ssowmini     offsetof(ether_fields_buf_t, eth_autoneg),	CMD_TYPE_ANY},
403*e7801d59Ssowmini { "speed-duplex", "SPEED-DUPLEX",	31,
404*e7801d59Ssowmini     offsetof(ether_fields_buf_t, eth_spdx),	CMD_TYPE_ANY},
405*e7801d59Ssowmini { "pause",	"PAUSE",		6,
406*e7801d59Ssowmini     offsetof(ether_fields_buf_t, eth_pause),	CMD_TYPE_ANY},
407*e7801d59Ssowmini { "rem_fault",	"REM_FAULT",		16,
408*e7801d59Ssowmini     offsetof(ether_fields_buf_t, eth_rem_fault),	CMD_TYPE_ANY}}
409*e7801d59Ssowmini ;
410*e7801d59Ssowmini #define	ETHER_MAX_FIELDS	(sizeof (ether_fields) / sizeof (print_field_t))
411*e7801d59Ssowmini 
412*e7801d59Ssowmini typedef struct print_ether_state {
413*e7801d59Ssowmini 	const char	*es_link;
414*e7801d59Ssowmini 	boolean_t	es_parseable;
415*e7801d59Ssowmini 	boolean_t	es_header;
416*e7801d59Ssowmini 	boolean_t	es_extended;
417*e7801d59Ssowmini 	print_state_t	es_print;
418*e7801d59Ssowmini } print_ether_state_t;
419*e7801d59Ssowmini 
420*e7801d59Ssowmini /*
421*e7801d59Ssowmini  * structures for 'dladm show-dev'.
422*e7801d59Ssowmini  */
423*e7801d59Ssowmini typedef enum {
424*e7801d59Ssowmini 	DEV_LINK,
425*e7801d59Ssowmini 	DEV_STATE,
426*e7801d59Ssowmini 	DEV_SPEED,
427*e7801d59Ssowmini 	DEV_DUPLEX
428*e7801d59Ssowmini } dev_field_index_t;
429*e7801d59Ssowmini 
430*e7801d59Ssowmini static print_field_t dev_fields[] = {
431*e7801d59Ssowmini /* name,	header,		field width,	index,		cmdtype */
432*e7801d59Ssowmini { "link",	"LINK",			15,	DEV_LINK,	CMD_TYPE_ANY},
433*e7801d59Ssowmini { "state",	"STATE",		6,	DEV_STATE,	CMD_TYPE_ANY},
434*e7801d59Ssowmini { "speed",	"SPEED",		8,	DEV_SPEED,	CMD_TYPE_ANY},
435*e7801d59Ssowmini { "duplex",	"DUPLEX",		8,	DEV_DUPLEX,	CMD_TYPE_ANY}}
436*e7801d59Ssowmini ;
437*e7801d59Ssowmini #define	DEV_MAX_FIELDS	(sizeof (dev_fields) / sizeof (print_field_t))
438*e7801d59Ssowmini 
439*e7801d59Ssowmini /*
440*e7801d59Ssowmini  * structures for 'dladm show-dev -s' (print statistics)
441*e7801d59Ssowmini  */
442*e7801d59Ssowmini typedef enum {
443*e7801d59Ssowmini 	DEVS_LINK,
444*e7801d59Ssowmini 	DEVS_IPKTS,
445*e7801d59Ssowmini 	DEVS_RBYTES,
446*e7801d59Ssowmini 	DEVS_IERRORS,
447*e7801d59Ssowmini 	DEVS_OPKTS,
448*e7801d59Ssowmini 	DEVS_OBYTES,
449*e7801d59Ssowmini 	DEVS_OERRORS
450*e7801d59Ssowmini } devs_field_index_t;
451*e7801d59Ssowmini 
452*e7801d59Ssowmini static print_field_t devs_fields[] = {
453*e7801d59Ssowmini /* name,	header,		field width,	index,		cmdtype	*/
454*e7801d59Ssowmini { "link",	"LINK",			15,	DEVS_LINK,	CMD_TYPE_ANY},
455*e7801d59Ssowmini { "ipackets",	"IPACKETS",		10,	DEVS_IPKTS,	CMD_TYPE_ANY},
456*e7801d59Ssowmini { "rbytes",	"RBYTES",		8,	DEVS_RBYTES,	CMD_TYPE_ANY},
457*e7801d59Ssowmini { "ierrors",	"IERRORS",		10,	DEVS_IERRORS,	CMD_TYPE_ANY},
458*e7801d59Ssowmini { "opackets",	"OPACKETS",		12,	DEVS_OPKTS,	CMD_TYPE_ANY},
459*e7801d59Ssowmini { "obytes",	"OBYTES",		12,	DEVS_OBYTES,	CMD_TYPE_ANY},
460*e7801d59Ssowmini { "oerrors",	"OERRORS",		8,	DEVS_OERRORS,	CMD_TYPE_ANY}}
461*e7801d59Ssowmini ;
462*e7801d59Ssowmini #define	DEVS_MAX_FIELDS	(sizeof (devs_fields) / sizeof (print_field_t))
463*e7801d59Ssowmini typedef struct dev_args_s {
464*e7801d59Ssowmini 	char		*devs_link;
465*e7801d59Ssowmini 	pktsum_t 	*devs_psum;
466*e7801d59Ssowmini } dev_args_t;
467*e7801d59Ssowmini static char *print_dev_stats(print_field_t *, void *);
468*e7801d59Ssowmini static char *print_dev(print_field_t *, void *);
469*e7801d59Ssowmini 
470*e7801d59Ssowmini /*
471*e7801d59Ssowmini  * buffer used by print functions for show-{link,phys,vlan} commands.
472*e7801d59Ssowmini  */
473*e7801d59Ssowmini typedef struct link_fields_buf_s {
474*e7801d59Ssowmini 	char link_name[MAXLINKNAMELEN];
475*e7801d59Ssowmini 	char link_class[DLADM_STRSIZE];
476*e7801d59Ssowmini 	char link_mtu[6];
477*e7801d59Ssowmini 	char link_state[DLADM_STRSIZE];
478*e7801d59Ssowmini 	char link_over[MAXLINKNAMELEN];
479*e7801d59Ssowmini 	char link_phys_state[6];
480*e7801d59Ssowmini 	char link_phys_media[DLADM_STRSIZE];
481*e7801d59Ssowmini 	char link_phys_speed[DLADM_STRSIZE];
482*e7801d59Ssowmini 	char link_phys_duplex[DLPI_LINKNAME_MAX];
483*e7801d59Ssowmini 	char link_phys_device[DLPI_LINKNAME_MAX];
484*e7801d59Ssowmini 	char link_flags[6];
485*e7801d59Ssowmini 	char link_vlan_vid[6];
486*e7801d59Ssowmini } link_fields_buf_t;
487*e7801d59Ssowmini 
488*e7801d59Ssowmini /*
489*e7801d59Ssowmini  * structures for 'dladm show-link'
490*e7801d59Ssowmini  */
491*e7801d59Ssowmini static print_field_t link_fields[] = {
492*e7801d59Ssowmini /* name,	header,		field width,	offset,	cmdtype		*/
493*e7801d59Ssowmini { "link",	"LINK",		11,
494*e7801d59Ssowmini     offsetof(link_fields_buf_t, link_name),	CMD_TYPE_ANY},
495*e7801d59Ssowmini { "class",	"CLASS",	 8,
496*e7801d59Ssowmini     offsetof(link_fields_buf_t, link_class),	CMD_TYPE_ANY},
497*e7801d59Ssowmini { "mtu",	"MTU",		 6,
498*e7801d59Ssowmini     offsetof(link_fields_buf_t, link_mtu),	CMD_TYPE_ANY},
499*e7801d59Ssowmini { "state",	"STATE",	 8,
500*e7801d59Ssowmini     offsetof(link_fields_buf_t, link_state),	CMD_TYPE_ANY},
501*e7801d59Ssowmini { "over",	"OVER",		DLPI_LINKNAME_MAX,
502*e7801d59Ssowmini     offsetof(link_fields_buf_t, link_over),	CMD_TYPE_ANY}}
503*e7801d59Ssowmini ;
504*e7801d59Ssowmini #define	DEV_LINK_FIELDS	(sizeof (link_fields) / sizeof (print_field_t))
505*e7801d59Ssowmini 
506*e7801d59Ssowmini /*
507*e7801d59Ssowmini  * structures for 'dladm show-aggr'
508*e7801d59Ssowmini  */
509*e7801d59Ssowmini typedef struct laggr_fields_buf_s {
510*e7801d59Ssowmini 	char laggr_name[DLPI_LINKNAME_MAX];
511*e7801d59Ssowmini 	char laggr_policy[9];
512*e7801d59Ssowmini 	char laggr_addrpolicy[ETHERADDRL * 3 + 3];
513*e7801d59Ssowmini 	char laggr_lacpactivity[14];
514*e7801d59Ssowmini 	char laggr_lacptimer[DLADM_STRSIZE];
515*e7801d59Ssowmini 	char laggr_flags[7];
516*e7801d59Ssowmini } laggr_fields_buf_t;
517*e7801d59Ssowmini 
518*e7801d59Ssowmini typedef struct laggr_args_s {
519*e7801d59Ssowmini 	int			laggr_lport; /* -1 indicates the aggr itself */
520*e7801d59Ssowmini 	const char 		*laggr_link;
521*e7801d59Ssowmini 	dladm_aggr_grp_attr_t	*laggr_ginfop;
522*e7801d59Ssowmini 	dladm_status_t		*laggr_status;
523*e7801d59Ssowmini 	pktsum_t		*laggr_pktsumtot; /* -s only */
524*e7801d59Ssowmini 	pktsum_t		*laggr_prevstats; /* -s only */
525*e7801d59Ssowmini 	boolean_t		laggr_parseable;
526*e7801d59Ssowmini } laggr_args_t;
527*e7801d59Ssowmini 
528*e7801d59Ssowmini static print_field_t laggr_fields[] = {
529*e7801d59Ssowmini /* name,		header,		field width,	offset,	cmdtype	*/
530*e7801d59Ssowmini { "link",		"LINK",		15,
531*e7801d59Ssowmini     offsetof(laggr_fields_buf_t, laggr_name),		CMD_TYPE_ANY},
532*e7801d59Ssowmini { "policy",		"POLICY",	 8,
533*e7801d59Ssowmini     offsetof(laggr_fields_buf_t, laggr_policy),	CMD_TYPE_ANY},
534*e7801d59Ssowmini { "addrpolicy",		"ADDRPOLICY",	 ETHERADDRL * 3 + 2,
535*e7801d59Ssowmini     offsetof(laggr_fields_buf_t, laggr_addrpolicy),	CMD_TYPE_ANY},
536*e7801d59Ssowmini { "lacpactivity",	"LACPACTIVITY",	 13,
537*e7801d59Ssowmini     offsetof(laggr_fields_buf_t, laggr_lacpactivity),	CMD_TYPE_ANY},
538*e7801d59Ssowmini { "lacptimer",		"LACPTIMER",	 11,
539*e7801d59Ssowmini     offsetof(laggr_fields_buf_t, laggr_lacptimer),	CMD_TYPE_ANY},
540*e7801d59Ssowmini { "flags",		"FLAGS",	 7,
541*e7801d59Ssowmini     offsetof(laggr_fields_buf_t, laggr_flags),	CMD_TYPE_ANY}}
542*e7801d59Ssowmini ;
543*e7801d59Ssowmini #define	LAGGR_MAX_FIELDS	(sizeof (laggr_fields) / sizeof (print_field_t))
544*e7801d59Ssowmini 
545*e7801d59Ssowmini /*
546*e7801d59Ssowmini  * structures for 'dladm show-aggr -x'.
547*e7801d59Ssowmini  */
548*e7801d59Ssowmini typedef enum {
549*e7801d59Ssowmini 	AGGR_X_LINK,
550*e7801d59Ssowmini 	AGGR_X_PORT,
551*e7801d59Ssowmini 	AGGR_X_SPEED,
552*e7801d59Ssowmini 	AGGR_X_DUPLEX,
553*e7801d59Ssowmini 	AGGR_X_STATE,
554*e7801d59Ssowmini 	AGGR_X_ADDRESS,
555*e7801d59Ssowmini 	AGGR_X_PORTSTATE
556*e7801d59Ssowmini } aggr_x_field_index_t;
557*e7801d59Ssowmini 
558*e7801d59Ssowmini static print_field_t aggr_x_fields[] = {
559*e7801d59Ssowmini /* name,	header,		field width,	index,		cmdtype	*/
560*e7801d59Ssowmini { "link",	"LINK",			11,	AGGR_X_LINK,	CMD_TYPE_ANY},
561*e7801d59Ssowmini { "port",	"PORT",			14,	AGGR_X_PORT,	CMD_TYPE_ANY},
562*e7801d59Ssowmini { "speed",	"SPEED",		4,	AGGR_X_SPEED,	CMD_TYPE_ANY},
563*e7801d59Ssowmini { "duplex",	"DUPLEX",		9,	AGGR_X_DUPLEX,	CMD_TYPE_ANY},
564*e7801d59Ssowmini { "state",	"STATE",		9,	AGGR_X_STATE,	CMD_TYPE_ANY},
565*e7801d59Ssowmini { "address",	"ADDRESS",		18,	AGGR_X_ADDRESS,	CMD_TYPE_ANY},
566*e7801d59Ssowmini { "portstate",	"PORTSTATE",		15,	AGGR_X_PORTSTATE, CMD_TYPE_ANY}}
567*e7801d59Ssowmini ;
568*e7801d59Ssowmini #define	AGGR_X_MAX_FIELDS \
569*e7801d59Ssowmini 	(sizeof (aggr_x_fields) / sizeof (print_field_t))
570*e7801d59Ssowmini 
571*e7801d59Ssowmini /*
572*e7801d59Ssowmini  * structures for 'dladm show-aggr -s'.
573*e7801d59Ssowmini  */
574*e7801d59Ssowmini typedef enum {
575*e7801d59Ssowmini 	AGGR_S_LINK,
576*e7801d59Ssowmini 	AGGR_S_PORT,
577*e7801d59Ssowmini 	AGGR_S_IPKTS,
578*e7801d59Ssowmini 	AGGR_S_RBYTES,
579*e7801d59Ssowmini 	AGGR_S_OPKTS,
580*e7801d59Ssowmini 	AGGR_S_OBYTES,
581*e7801d59Ssowmini 	AGGR_S_IPKTDIST,
582*e7801d59Ssowmini 	AGGR_S_OPKTDIST
583*e7801d59Ssowmini } aggr_s_field_index_t;
584*e7801d59Ssowmini 
585*e7801d59Ssowmini static print_field_t aggr_s_fields[] = {
586*e7801d59Ssowmini /* name,		header,		field width,	index,	cmdtype	*/
587*e7801d59Ssowmini { "link",		"LINK",		11,	AGGR_S_LINK,
588*e7801d59Ssowmini     CMD_TYPE_ANY},
589*e7801d59Ssowmini { "port",		"PORT",		9,	AGGR_S_PORT,
590*e7801d59Ssowmini     CMD_TYPE_ANY},
591*e7801d59Ssowmini { "ipackets",		"IPACKETS",	7,	AGGR_S_IPKTS,
592*e7801d59Ssowmini     CMD_TYPE_ANY},
593*e7801d59Ssowmini { "rbytes",		"RBYTES",	7,	AGGR_S_RBYTES,
594*e7801d59Ssowmini     CMD_TYPE_ANY},
595*e7801d59Ssowmini { "opackets",		"OPACKETS",	7,	AGGR_S_OPKTS,
596*e7801d59Ssowmini     CMD_TYPE_ANY},
597*e7801d59Ssowmini { "obytes",		"OBYTES",	7,	AGGR_S_OBYTES,
598*e7801d59Ssowmini     CMD_TYPE_ANY},
599*e7801d59Ssowmini { "ipktdist",		"IPKTDIST",	8,	AGGR_S_IPKTDIST,
600*e7801d59Ssowmini     CMD_TYPE_ANY},
601*e7801d59Ssowmini { "opktdist",		"OPKTDIST",	14,	AGGR_S_OPKTDIST,
602*e7801d59Ssowmini     CMD_TYPE_ANY}}
603*e7801d59Ssowmini ;
604*e7801d59Ssowmini #define	AGGR_S_MAX_FIELDS \
605*e7801d59Ssowmini 	(sizeof (aggr_l_fields) / sizeof (print_field_t))
606*e7801d59Ssowmini 
607*e7801d59Ssowmini /*
608*e7801d59Ssowmini  * structures for 'dladm show-dev -L'.
609*e7801d59Ssowmini  */
610*e7801d59Ssowmini typedef enum {
611*e7801d59Ssowmini 	AGGR_L_LINK,
612*e7801d59Ssowmini 	AGGR_L_PORT,
613*e7801d59Ssowmini 	AGGR_L_AGGREGATABLE,
614*e7801d59Ssowmini 	AGGR_L_SYNC,
615*e7801d59Ssowmini 	AGGR_L_COLL,
616*e7801d59Ssowmini 	AGGR_L_DIST,
617*e7801d59Ssowmini 	AGGR_L_DEFAULTED,
618*e7801d59Ssowmini 	AGGR_L_EXPIRED
619*e7801d59Ssowmini } aggr_l_field_index_t;
620*e7801d59Ssowmini 
621*e7801d59Ssowmini static print_field_t aggr_l_fields[] = {
622*e7801d59Ssowmini /* name,		header,		field width,	index,	cmdtype	*/
623*e7801d59Ssowmini { "link",		"LINK",		11,	AGGR_L_LINK,
624*e7801d59Ssowmini     CMD_TYPE_ANY},
625*e7801d59Ssowmini { "port",		"PORT",		12,	AGGR_L_PORT,
626*e7801d59Ssowmini     CMD_TYPE_ANY},
627*e7801d59Ssowmini { "aggregatable",	"AGGREGATABLE",	12,	AGGR_L_AGGREGATABLE,
628*e7801d59Ssowmini     CMD_TYPE_ANY},
629*e7801d59Ssowmini { "sync",		"SYNC",		4,	AGGR_L_SYNC,
630*e7801d59Ssowmini     CMD_TYPE_ANY},
631*e7801d59Ssowmini { "coll",		"COLL",		4,	AGGR_L_COLL,
632*e7801d59Ssowmini     CMD_TYPE_ANY},
633*e7801d59Ssowmini { "dist",		"DIST",		4,	AGGR_L_DIST,
634*e7801d59Ssowmini     CMD_TYPE_ANY},
635*e7801d59Ssowmini { "defaulted",		"DEFAULTED",	9,	AGGR_L_DEFAULTED,
636*e7801d59Ssowmini     CMD_TYPE_ANY},
637*e7801d59Ssowmini { "expired",		"EXPIRED",	14,	AGGR_L_EXPIRED,
638*e7801d59Ssowmini     CMD_TYPE_ANY}}
639*e7801d59Ssowmini ;
640*e7801d59Ssowmini #define	AGGR_L_MAX_FIELDS \
641*e7801d59Ssowmini 	(sizeof (aggr_l_fields) / sizeof (print_field_t))
642*e7801d59Ssowmini 
643*e7801d59Ssowmini /*
644*e7801d59Ssowmini  * structures for 'dladm show-phys'
645*e7801d59Ssowmini  */
646*e7801d59Ssowmini 
647*e7801d59Ssowmini static print_field_t phys_fields[] = {
648*e7801d59Ssowmini /* name,	header,		field width,	offset,	cmdtype		*/
649*e7801d59Ssowmini { "link",	"LINK",			12,
650*e7801d59Ssowmini     offsetof(link_fields_buf_t, link_name),		CMD_TYPE_ANY},
651*e7801d59Ssowmini { "media",	"MEDIA",		20,
652*e7801d59Ssowmini     offsetof(link_fields_buf_t, link_phys_media),	CMD_TYPE_ANY},
653*e7801d59Ssowmini { "state",	"STATE",		10,
654*e7801d59Ssowmini     offsetof(link_fields_buf_t, link_phys_state),	CMD_TYPE_ANY},
655*e7801d59Ssowmini { "speed",	"SPEED",		4,
656*e7801d59Ssowmini     offsetof(link_fields_buf_t, link_phys_speed),	CMD_TYPE_ANY},
657*e7801d59Ssowmini { "duplex",	"DUPLEX",		9,
658*e7801d59Ssowmini     offsetof(link_fields_buf_t, link_phys_duplex),	CMD_TYPE_ANY},
659*e7801d59Ssowmini { "device",	"DEVICE",		12,
660*e7801d59Ssowmini     offsetof(link_fields_buf_t, link_phys_device),	CMD_TYPE_ANY},
661*e7801d59Ssowmini { "flags",	"FLAGS",		6,
662*e7801d59Ssowmini     offsetof(link_fields_buf_t, link_flags),		CMD_TYPE_ANY}}
663*e7801d59Ssowmini ;
664*e7801d59Ssowmini #define	PHYS_MAX_FIELDS	(sizeof (phys_fields) / sizeof (print_field_t))
665*e7801d59Ssowmini 
666*e7801d59Ssowmini /*
667*e7801d59Ssowmini  * structures for 'dladm show-vlan'
668*e7801d59Ssowmini  */
669*e7801d59Ssowmini static print_field_t vlan_fields[] = {
670*e7801d59Ssowmini /* name,	header,		field width,	offset,	cmdtype		*/
671*e7801d59Ssowmini { "link",	"LINK",			15,
672*e7801d59Ssowmini     offsetof(link_fields_buf_t, link_name),		CMD_TYPE_ANY},
673*e7801d59Ssowmini { "vid",	"VID",			8,
674*e7801d59Ssowmini     offsetof(link_fields_buf_t, link_vlan_vid),	CMD_TYPE_ANY},
675*e7801d59Ssowmini { "over",	"OVER",			12,
676*e7801d59Ssowmini     offsetof(link_fields_buf_t, link_over),		CMD_TYPE_ANY},
677*e7801d59Ssowmini { "flags",	"FLAGS",		6,
678*e7801d59Ssowmini     offsetof(link_fields_buf_t, link_flags),		CMD_TYPE_ANY}}
679*e7801d59Ssowmini ;
680*e7801d59Ssowmini #define	VLAN_MAX_FIELDS	(sizeof (vlan_fields) / sizeof (print_field_t))
681*e7801d59Ssowmini 
682*e7801d59Ssowmini /*
683*e7801d59Ssowmini  * structures for 'dladm show-wifi'
684*e7801d59Ssowmini  */
685*e7801d59Ssowmini static print_field_t wifi_fields[] = {
686*e7801d59Ssowmini { "link",	"LINK",		10, 0,			WIFI_CMD_ALL},
687*e7801d59Ssowmini { "essid",	"ESSID",	19, DLADM_WLAN_ATTR_ESSID,	WIFI_CMD_ALL},
688*e7801d59Ssowmini { "bssid",	"BSSID/IBSSID", 17, DLADM_WLAN_ATTR_BSSID,	WIFI_CMD_ALL},
689*e7801d59Ssowmini { "ibssid",	"BSSID/IBSSID", 17, DLADM_WLAN_ATTR_BSSID,	WIFI_CMD_ALL},
690*e7801d59Ssowmini { "mode",	"MODE",		6,  DLADM_WLAN_ATTR_MODE,	WIFI_CMD_ALL},
691*e7801d59Ssowmini { "speed",	"SPEED",	6,  DLADM_WLAN_ATTR_SPEED,	WIFI_CMD_ALL},
692*e7801d59Ssowmini { "auth",	"AUTH",		8,  DLADM_WLAN_ATTR_AUTH,	WIFI_CMD_SHOW},
693*e7801d59Ssowmini { "bsstype",	"BSSTYPE",	8,  DLADM_WLAN_ATTR_BSSTYPE, WIFI_CMD_ALL},
694*e7801d59Ssowmini { "sec",	"SEC",		6,  DLADM_WLAN_ATTR_SECMODE, WIFI_CMD_ALL},
695*e7801d59Ssowmini { "status",	"STATUS",	17, DLADM_WLAN_LINKATTR_STATUS, WIFI_CMD_SHOW},
696*e7801d59Ssowmini { "strength",	"STRENGTH",	10, DLADM_WLAN_ATTR_STRENGTH, WIFI_CMD_ALL}}
697*e7801d59Ssowmini ;
698*e7801d59Ssowmini 
699*e7801d59Ssowmini static char *all_scan_wifi_fields =
700*e7801d59Ssowmini 	"link,essid,bssid,sec,strength,mode,speed,bsstype";
701*e7801d59Ssowmini static char *all_show_wifi_fields =
702*e7801d59Ssowmini 	"link,status,essid,sec,strength,mode,speed,auth,bssid,bsstype";
703*e7801d59Ssowmini static char *def_scan_wifi_fields =
704*e7801d59Ssowmini 	"link,essid,bssid,sec,strength,mode,speed";
705*e7801d59Ssowmini static char *def_show_wifi_fields =
706*e7801d59Ssowmini 	"link,status,essid,sec,strength,mode,speed";
707*e7801d59Ssowmini 
708*e7801d59Ssowmini #define	WIFI_MAX_FIELDS		(sizeof (wifi_fields) / sizeof (print_field_t))
709*e7801d59Ssowmini 
710*e7801d59Ssowmini /*
711*e7801d59Ssowmini  * structures for 'dladm show-linkprop'
712*e7801d59Ssowmini  */
713*e7801d59Ssowmini typedef enum {
714*e7801d59Ssowmini 	LINKPROP_LINK,
715*e7801d59Ssowmini 	LINKPROP_PROPERTY,
716*e7801d59Ssowmini 	LINKPROP_VALUE,
717*e7801d59Ssowmini 	LINKPROP_DEFAULT,
718*e7801d59Ssowmini 	LINKPROP_POSSIBLE
719*e7801d59Ssowmini } linkprop_field_index_t;
720*e7801d59Ssowmini 
721*e7801d59Ssowmini static print_field_t linkprop_fields[] = {
722*e7801d59Ssowmini /* name,	header,		field width,  index,		cmdtype */
723*e7801d59Ssowmini { "link",	"LINK",		12,	LINKPROP_LINK,		CMD_TYPE_ANY},
724*e7801d59Ssowmini { "property",	"PROPERTY",	15,	LINKPROP_PROPERTY,	CMD_TYPE_ANY},
725*e7801d59Ssowmini { "value",	"VALUE",	14,	LINKPROP_VALUE,		CMD_TYPE_ANY},
726*e7801d59Ssowmini { "default",	"DEFAULT",	14,	LINKPROP_DEFAULT, 	CMD_TYPE_ANY},
727*e7801d59Ssowmini { "possible",	"POSSIBLE",	20,	LINKPROP_POSSIBLE,	CMD_TYPE_ANY}}
728*e7801d59Ssowmini ;
729*e7801d59Ssowmini #define	LINKPROP_MAX_FIELDS					\
730*e7801d59Ssowmini 	(sizeof (linkprop_fields) / sizeof (print_field_t))
731*e7801d59Ssowmini 
732*e7801d59Ssowmini #define	MAX_PROPS		32
733*e7801d59Ssowmini #define	MAX_PROP_LINE		512
734*e7801d59Ssowmini 
735*e7801d59Ssowmini typedef struct prop_info {
736*e7801d59Ssowmini 	char		*pi_name;
737*e7801d59Ssowmini 	char		*pi_val[DLADM_MAX_PROP_VALCNT];
738*e7801d59Ssowmini 	uint_t		pi_count;
739*e7801d59Ssowmini } prop_info_t;
740*e7801d59Ssowmini 
741*e7801d59Ssowmini typedef struct prop_list {
742*e7801d59Ssowmini 	prop_info_t	pl_info[MAX_PROPS];
743*e7801d59Ssowmini 	uint_t		pl_count;
744*e7801d59Ssowmini 	char		*pl_buf;
745*e7801d59Ssowmini } prop_list_t;
746*e7801d59Ssowmini 
747*e7801d59Ssowmini typedef struct show_linkprop_state {
748*e7801d59Ssowmini 	char		ls_link[MAXLINKNAMELEN];
749*e7801d59Ssowmini 	char		*ls_line;
750*e7801d59Ssowmini 	char		**ls_propvals;
751*e7801d59Ssowmini 	prop_list_t	*ls_proplist;
752*e7801d59Ssowmini 	boolean_t	ls_parseable;
753*e7801d59Ssowmini 	boolean_t	ls_persist;
754*e7801d59Ssowmini 	boolean_t	ls_header;
755*e7801d59Ssowmini 	dladm_status_t	ls_status;
756*e7801d59Ssowmini 	dladm_status_t	ls_retstatus;
757*e7801d59Ssowmini 	print_state_t	ls_print;
758*e7801d59Ssowmini } show_linkprop_state_t;
759*e7801d59Ssowmini 
760*e7801d59Ssowmini typedef struct linkprop_args_s {
761*e7801d59Ssowmini 	show_linkprop_state_t	*ls_state;
762*e7801d59Ssowmini 	char			*ls_propname;
763*e7801d59Ssowmini 	datalink_id_t		ls_linkid;
764*e7801d59Ssowmini } linkprop_args_t;
765*e7801d59Ssowmini 
766*e7801d59Ssowmini /*
767*e7801d59Ssowmini  * structures for 'dladm show-secobj'
768*e7801d59Ssowmini  */
769*e7801d59Ssowmini typedef struct secobj_fields_buf_s {
770*e7801d59Ssowmini 	char			ss_obj_name[DLADM_SECOBJ_VAL_MAX];
771*e7801d59Ssowmini 	char			ss_class[20];
772*e7801d59Ssowmini 	char			ss_val[30];
773*e7801d59Ssowmini } secobj_fields_buf_t;
774*e7801d59Ssowmini static print_field_t secobj_fields[] = {
775*e7801d59Ssowmini /* name,	header,		field width,	offset,	cmdtype		*/
776*e7801d59Ssowmini { "object",	"OBJECT",		20,
777*e7801d59Ssowmini     offsetof(secobj_fields_buf_t, ss_obj_name),	CMD_TYPE_ANY},
778*e7801d59Ssowmini { "class",	"CLASS",		20,
779*e7801d59Ssowmini     offsetof(secobj_fields_buf_t, ss_class),	CMD_TYPE_ANY},
780*e7801d59Ssowmini { "value",	"VALUE",		30,
781*e7801d59Ssowmini     offsetof(secobj_fields_buf_t, ss_val),	CMD_TYPE_ANY}}
782*e7801d59Ssowmini ;
783*e7801d59Ssowmini #define	DEV_SOBJ_FIELDS	(sizeof (secobj_fields) / sizeof (print_field_t))
7840ba2cbe9Sxc151355 
7857c478bd9Sstevel@tonic-gate static char *progname;
7860ba2cbe9Sxc151355 static sig_atomic_t signalled;
7877c478bd9Sstevel@tonic-gate 
7887c478bd9Sstevel@tonic-gate static void
7897c478bd9Sstevel@tonic-gate usage(void)
7907c478bd9Sstevel@tonic-gate {
7910ba2cbe9Sxc151355 	(void) fprintf(stderr, gettext("usage:	dladm <subcommand> <args> ...\n"
792*e7801d59Ssowmini 	    "\tshow-link       [-pP] [-o <field>,..] [-s [-i <interval>]] "
793*e7801d59Ssowmini 	    "[<link>]\n"
794d62bc4baSyz147064 	    "\trename-link     [-R <root-dir>] <oldlink> <newlink>\n"
795d62bc4baSyz147064 	    "\n"
796d62bc4baSyz147064 	    "\tdelete-phys     <link>\n"
797*e7801d59Ssowmini 	    "\tshow-phys       [-pP] [-o <field>,..] [<link>]\n"
798*e7801d59Ssowmini 	    "\tshow-dev        [-p] [-o <field>,..] [-s [-i <interval>]] "
799*e7801d59Ssowmini 	    "[<dev>]\n"
8000ba2cbe9Sxc151355 	    "\n"
801d62bc4baSyz147064 	    "\tcreate-aggr     [-t] [-R <root-dir>] [-P <policy>] [-L <mode>]\n"
802d62bc4baSyz147064 	    "\t		[-T <time>] [-u <address>] [-l <link>] ... <link>\n"
803d62bc4baSyz147064 	    "\tmodify-aggr     [-t] [-R <root-dir>] [-P <policy>] [-L <mode>]\n"
804d62bc4baSyz147064 	    "\t		[-T <time>] [-u <address>] <link>\n"
805d62bc4baSyz147064 	    "\tdelete-aggr     [-t] [-R <root-dir>] <link>\n"
806d62bc4baSyz147064 	    "\tadd-aggr        [-t] [-R <root-dir>] [-l <link>] ... <link>\n"
807d62bc4baSyz147064 	    "\tremove-aggr     [-t] [-R <root-dir>] [-l <link>] ... <link>"
808*e7801d59Ssowmini 	    "\n\tshow-aggr       [-pPLx] [-o <field>,..] [-s [-i <interval>]] "
809*e7801d59Ssowmini 	    "[<link>]\n"
8100ba2cbe9Sxc151355 	    "\n"
811d62bc4baSyz147064 	    "\tcreate-vlan     [-ft] [-R <root-dir>] -l <link> -v <vid> [link]"
812d62bc4baSyz147064 	    "\n\tdelete-vlan     [-t]  [-R <root-dir>] <link>\n"
813*e7801d59Ssowmini 	    "\tshow-vlan       [-pP] [-o <field>,..] [<link>]\n"
814d62bc4baSyz147064 	    "\n"
815d62bc4baSyz147064 	    "\tscan-wifi       [-p] [-o <field>,...] [<link>]\n"
8160ba2cbe9Sxc151355 	    "\tconnect-wifi    [-e <essid>] [-i <bssid>] [-k <key>,...]"
817a399b765Szf162725 	    " [-s wep|wpa]\n"
8180ba2cbe9Sxc151355 	    "\t                [-a open|shared] [-b bss|ibss] [-c] [-m a|b|g]\n"
819d62bc4baSyz147064 	    "\t                [-T <time>] [<link>]\n"
820d62bc4baSyz147064 	    "\tdisconnect-wifi [-a] [<link>]\n"
821d62bc4baSyz147064 	    "\tshow-wifi       [-p] [-o <field>,...] [<link>]\n"
8220ba2cbe9Sxc151355 	    "\n"
8230ba2cbe9Sxc151355 	    "\tset-linkprop    [-t] [-R <root-dir>]  -p <prop>=<value>[,...]"
8240ba2cbe9Sxc151355 	    " <name>\n"
8250ba2cbe9Sxc151355 	    "\treset-linkprop  [-t] [-R <root-dir>] [-p <prop>,...] <name>\n"
826*e7801d59Ssowmini 	    "\tshow-linkprop   [-cP][-o <field>,...][-p <prop>,...] <name>\n"
8270ba2cbe9Sxc151355 	    "\n"
8280ba2cbe9Sxc151355 	    "\tcreate-secobj   [-t] [-R <root-dir>] [-f <file>] -c <class>"
8290ba2cbe9Sxc151355 	    " <secobj>\n"
8300ba2cbe9Sxc151355 	    "\tdelete-secobj   [-t] [-R <root-dir>] <secobj>[,...]\n"
831*e7801d59Ssowmini 	    "\tshow-secobj     [-pP][-o <field>,...][<secobj>,...]\n"
832*e7801d59Ssowmini 	    "\n"
833*e7801d59Ssowmini 	    "\tshow-ether      [-px][-o <field>,...] <link>\n"));
834*e7801d59Ssowmini 
8357c478bd9Sstevel@tonic-gate 	exit(1);
8367c478bd9Sstevel@tonic-gate }
8377c478bd9Sstevel@tonic-gate 
8387c478bd9Sstevel@tonic-gate int
8397c478bd9Sstevel@tonic-gate main(int argc, char *argv[])
8407c478bd9Sstevel@tonic-gate {
8417c478bd9Sstevel@tonic-gate 	int	i;
8427c478bd9Sstevel@tonic-gate 	cmd_t	*cmdp;
8437c478bd9Sstevel@tonic-gate 
8447c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
8457c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)
8467c478bd9Sstevel@tonic-gate #define	TEXT_DOMAIN "SYS_TEST"
8477c478bd9Sstevel@tonic-gate #endif
8487c478bd9Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
8497c478bd9Sstevel@tonic-gate 
8507c478bd9Sstevel@tonic-gate 	progname = argv[0];
8517c478bd9Sstevel@tonic-gate 
8527c478bd9Sstevel@tonic-gate 	if (argc < 2)
8537c478bd9Sstevel@tonic-gate 		usage();
8547c478bd9Sstevel@tonic-gate 
855cd93090eSericheng 	if (!priv_ineffect(PRIV_SYS_NET_CONFIG) ||
85633343a97Smeem 	    !priv_ineffect(PRIV_NET_RAWACCESS))
85733343a97Smeem 		die("insufficient privileges");
858cd93090eSericheng 
8597c478bd9Sstevel@tonic-gate 	for (i = 0; i < sizeof (cmds) / sizeof (cmds[0]); i++) {
8607c478bd9Sstevel@tonic-gate 		cmdp = &cmds[i];
8617c478bd9Sstevel@tonic-gate 		if (strcmp(argv[1], cmdp->c_name) == 0) {
8627c478bd9Sstevel@tonic-gate 			cmdp->c_fn(argc - 1, &argv[1]);
8637c478bd9Sstevel@tonic-gate 			exit(0);
8647c478bd9Sstevel@tonic-gate 		}
8657c478bd9Sstevel@tonic-gate 	}
8667c478bd9Sstevel@tonic-gate 
8677c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("%s: unknown subcommand '%s'\n"),
8687c478bd9Sstevel@tonic-gate 	    progname, argv[1]);
8697c478bd9Sstevel@tonic-gate 	usage();
8707c478bd9Sstevel@tonic-gate 
8717c478bd9Sstevel@tonic-gate 	return (0);
8727c478bd9Sstevel@tonic-gate }
8737c478bd9Sstevel@tonic-gate 
8747c478bd9Sstevel@tonic-gate static void
8757c478bd9Sstevel@tonic-gate do_create_aggr(int argc, char *argv[])
8767c478bd9Sstevel@tonic-gate {
8777c478bd9Sstevel@tonic-gate 	char			option;
878d62bc4baSyz147064 	int			key = 0;
8797c478bd9Sstevel@tonic-gate 	uint32_t		policy = AGGR_POLICY_L4;
8807c478bd9Sstevel@tonic-gate 	aggr_lacp_mode_t	lacp_mode = AGGR_LACP_OFF;
8817c478bd9Sstevel@tonic-gate 	aggr_lacp_timer_t	lacp_timer = AGGR_LACP_TIMER_SHORT;
882f595a68aSyz147064 	dladm_aggr_port_attr_db_t	port[MAXPORT];
883d62bc4baSyz147064 	uint_t			n, ndev, nlink;
8847c478bd9Sstevel@tonic-gate 	uint8_t			mac_addr[ETHERADDRL];
8857c478bd9Sstevel@tonic-gate 	boolean_t		mac_addr_fixed = B_FALSE;
8867c478bd9Sstevel@tonic-gate 	boolean_t		P_arg = B_FALSE;
8877c478bd9Sstevel@tonic-gate 	boolean_t		l_arg = B_FALSE;
8887c478bd9Sstevel@tonic-gate 	boolean_t		u_arg = B_FALSE;
8897c478bd9Sstevel@tonic-gate 	boolean_t		T_arg = B_FALSE;
890d62bc4baSyz147064 	uint32_t		flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
8917c478bd9Sstevel@tonic-gate 	char			*altroot = NULL;
892d62bc4baSyz147064 	char			name[MAXLINKNAMELEN];
893d62bc4baSyz147064 	char			*devs[MAXPORT];
894d62bc4baSyz147064 	char			*links[MAXPORT];
895f595a68aSyz147064 	dladm_status_t		status;
8967c478bd9Sstevel@tonic-gate 
897d62bc4baSyz147064 	ndev = nlink = opterr = 0;
898d62bc4baSyz147064 	while ((option = getopt_long(argc, argv, ":d:l:L:P:R:tfu:T:",
899d62bc4baSyz147064 	    lopts, NULL)) != -1) {
9007c478bd9Sstevel@tonic-gate 		switch (option) {
9017c478bd9Sstevel@tonic-gate 		case 'd':
902d62bc4baSyz147064 			if (ndev + nlink >= MAXPORT)
903d62bc4baSyz147064 				die("too many ports specified");
9047c478bd9Sstevel@tonic-gate 
905d62bc4baSyz147064 			devs[ndev++] = optarg;
9067c478bd9Sstevel@tonic-gate 			break;
9077c478bd9Sstevel@tonic-gate 		case 'P':
90833343a97Smeem 			if (P_arg)
90933343a97Smeem 				die_optdup(option);
9107c478bd9Sstevel@tonic-gate 
9117c478bd9Sstevel@tonic-gate 			P_arg = B_TRUE;
912f595a68aSyz147064 			if (!dladm_aggr_str2policy(optarg, &policy))
91333343a97Smeem 				die("invalid policy '%s'", optarg);
9147c478bd9Sstevel@tonic-gate 			break;
9157c478bd9Sstevel@tonic-gate 		case 'u':
91633343a97Smeem 			if (u_arg)
91733343a97Smeem 				die_optdup(option);
9187c478bd9Sstevel@tonic-gate 
9197c478bd9Sstevel@tonic-gate 			u_arg = B_TRUE;
920f595a68aSyz147064 			if (!dladm_aggr_str2macaddr(optarg, &mac_addr_fixed,
92133343a97Smeem 			    mac_addr))
92233343a97Smeem 				die("invalid MAC address '%s'", optarg);
9237c478bd9Sstevel@tonic-gate 			break;
9247c478bd9Sstevel@tonic-gate 		case 'l':
925d62bc4baSyz147064 			if (isdigit(optarg[strlen(optarg) - 1])) {
926d62bc4baSyz147064 
927d62bc4baSyz147064 				/*
928d62bc4baSyz147064 				 * Ended with digit, possibly a link name.
929d62bc4baSyz147064 				 */
930d62bc4baSyz147064 				if (ndev + nlink >= MAXPORT)
931d62bc4baSyz147064 					die("too many ports specified");
932d62bc4baSyz147064 
933d62bc4baSyz147064 				links[nlink++] = optarg;
934d62bc4baSyz147064 				break;
935d62bc4baSyz147064 			}
936d62bc4baSyz147064 			/* FALLTHROUGH */
937d62bc4baSyz147064 		case 'L':
93833343a97Smeem 			if (l_arg)
93933343a97Smeem 				die_optdup(option);
9407c478bd9Sstevel@tonic-gate 
9417c478bd9Sstevel@tonic-gate 			l_arg = B_TRUE;
942f595a68aSyz147064 			if (!dladm_aggr_str2lacpmode(optarg, &lacp_mode))
94333343a97Smeem 				die("invalid LACP mode '%s'", optarg);
9447c478bd9Sstevel@tonic-gate 			break;
9457c478bd9Sstevel@tonic-gate 		case 'T':
94633343a97Smeem 			if (T_arg)
94733343a97Smeem 				die_optdup(option);
9487c478bd9Sstevel@tonic-gate 
9497c478bd9Sstevel@tonic-gate 			T_arg = B_TRUE;
950f595a68aSyz147064 			if (!dladm_aggr_str2lacptimer(optarg, &lacp_timer))
95133343a97Smeem 				die("invalid LACP timer value '%s'", optarg);
9527c478bd9Sstevel@tonic-gate 			break;
9537c478bd9Sstevel@tonic-gate 		case 't':
954d62bc4baSyz147064 			flags &= ~DLADM_OPT_PERSIST;
955d62bc4baSyz147064 			break;
956d62bc4baSyz147064 		case 'f':
957d62bc4baSyz147064 			flags |= DLADM_OPT_FORCE;
9587c478bd9Sstevel@tonic-gate 			break;
9597c478bd9Sstevel@tonic-gate 		case 'R':
9607c478bd9Sstevel@tonic-gate 			altroot = optarg;
9617c478bd9Sstevel@tonic-gate 			break;
9627c478bd9Sstevel@tonic-gate 		default:
96333343a97Smeem 			die_opterr(optopt, option);
96433343a97Smeem 			break;
9657c478bd9Sstevel@tonic-gate 		}
9667c478bd9Sstevel@tonic-gate 	}
9677c478bd9Sstevel@tonic-gate 
968d62bc4baSyz147064 	if (ndev + nlink == 0)
9697c478bd9Sstevel@tonic-gate 		usage();
9707c478bd9Sstevel@tonic-gate 
971d62bc4baSyz147064 	/* get key value or the aggregation name (required last argument) */
9727c478bd9Sstevel@tonic-gate 	if (optind != (argc-1))
9737c478bd9Sstevel@tonic-gate 		usage();
9747c478bd9Sstevel@tonic-gate 
975d62bc4baSyz147064 	if (!str2int(argv[optind], &key)) {
976d62bc4baSyz147064 		if (strlcpy(name, argv[optind], MAXLINKNAMELEN) >=
977d62bc4baSyz147064 		    MAXLINKNAMELEN) {
978d62bc4baSyz147064 			die("link name too long '%s'", argv[optind]);
979d62bc4baSyz147064 		}
9807c478bd9Sstevel@tonic-gate 
981d62bc4baSyz147064 		if (!dladm_valid_linkname(name))
982d62bc4baSyz147064 			die("invalid link name '%s'", argv[optind]);
983d62bc4baSyz147064 	} else {
984d62bc4baSyz147064 		(void) snprintf(name, MAXLINKNAMELEN, "aggr%d", key);
985d62bc4baSyz147064 	}
986d62bc4baSyz147064 
987d62bc4baSyz147064 	if (altroot != NULL)
988d62bc4baSyz147064 		altroot_cmd(altroot, argc, argv);
989d62bc4baSyz147064 
990d62bc4baSyz147064 	for (n = 0; n < ndev; n++) {
991d62bc4baSyz147064 		if (dladm_dev2linkid(devs[n], &port[n].lp_linkid) !=
992d62bc4baSyz147064 		    DLADM_STATUS_OK) {
993d62bc4baSyz147064 			die("invalid dev name '%s'", devs[n]);
994d62bc4baSyz147064 		}
995d62bc4baSyz147064 	}
996d62bc4baSyz147064 
997d62bc4baSyz147064 	for (n = 0; n < nlink; n++) {
998d62bc4baSyz147064 		if (dladm_name2info(links[n], &port[ndev + n].lp_linkid,
999d62bc4baSyz147064 		    NULL, NULL, NULL) != DLADM_STATUS_OK) {
1000d62bc4baSyz147064 			die("invalid link name '%s'", links[n]);
1001d62bc4baSyz147064 		}
1002d62bc4baSyz147064 	}
1003d62bc4baSyz147064 
1004d62bc4baSyz147064 	status = dladm_aggr_create(name, key, ndev + nlink, port, policy,
1005d62bc4baSyz147064 	    mac_addr_fixed, (const uchar_t *)mac_addr, lacp_mode,
1006d62bc4baSyz147064 	    lacp_timer, flags);
1007d62bc4baSyz147064 done:
1008d62bc4baSyz147064 	if (status != DLADM_STATUS_OK) {
1009d62bc4baSyz147064 		if (status == DLADM_STATUS_NONOTIF) {
1010d62bc4baSyz147064 			die_dlerr(status, "not all links have link up/down "
1011d62bc4baSyz147064 			    "detection; must use -f (see dladm(1M))\n");
1012d62bc4baSyz147064 		} else {
1013f595a68aSyz147064 			die_dlerr(status, "create operation failed");
10147c478bd9Sstevel@tonic-gate 		}
1015d62bc4baSyz147064 	}
1016d62bc4baSyz147064 }
1017d62bc4baSyz147064 
1018d62bc4baSyz147064 /*
1019d62bc4baSyz147064  * arg is either the key or the aggr name. Validate it and convert it to
1020d62bc4baSyz147064  * the linkid if altroot is NULL.
1021d62bc4baSyz147064  */
1022d62bc4baSyz147064 static dladm_status_t
1023d62bc4baSyz147064 i_dladm_aggr_get_linkid(const char *altroot, const char *arg,
1024d62bc4baSyz147064     datalink_id_t *linkidp, uint32_t flags)
1025d62bc4baSyz147064 {
1026d62bc4baSyz147064 	int		key = 0;
1027d62bc4baSyz147064 	char		*aggr = NULL;
1028d62bc4baSyz147064 	dladm_status_t	status;
1029d62bc4baSyz147064 
1030d62bc4baSyz147064 	if (!str2int(arg, &key))
1031d62bc4baSyz147064 		aggr = (char *)arg;
1032d62bc4baSyz147064 
1033d62bc4baSyz147064 	if (aggr == NULL && key == 0)
1034d62bc4baSyz147064 		return (DLADM_STATUS_LINKINVAL);
1035d62bc4baSyz147064 
1036d62bc4baSyz147064 	if (altroot != NULL)
1037d62bc4baSyz147064 		return (DLADM_STATUS_OK);
1038d62bc4baSyz147064 
1039d62bc4baSyz147064 	if (aggr != NULL) {
1040d62bc4baSyz147064 		status = dladm_name2info(aggr, linkidp, NULL, NULL, NULL);
1041d62bc4baSyz147064 	} else {
1042d62bc4baSyz147064 		status = dladm_key2linkid(key, linkidp, flags);
1043d62bc4baSyz147064 	}
1044d62bc4baSyz147064 
1045d62bc4baSyz147064 	return (status);
1046d62bc4baSyz147064 }
10477c478bd9Sstevel@tonic-gate 
10487c478bd9Sstevel@tonic-gate static void
10497c478bd9Sstevel@tonic-gate do_delete_aggr(int argc, char *argv[])
10507c478bd9Sstevel@tonic-gate {
10517c478bd9Sstevel@tonic-gate 	char			option;
10527c478bd9Sstevel@tonic-gate 	char			*altroot = NULL;
1053d62bc4baSyz147064 	uint32_t		flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
1054f595a68aSyz147064 	dladm_status_t		status;
1055d62bc4baSyz147064 	datalink_id_t		linkid;
10567c478bd9Sstevel@tonic-gate 
10577c478bd9Sstevel@tonic-gate 	opterr = 0;
1058d62bc4baSyz147064 	while ((option = getopt_long(argc, argv, ":R:t", lopts, NULL)) != -1) {
10597c478bd9Sstevel@tonic-gate 		switch (option) {
10607c478bd9Sstevel@tonic-gate 		case 't':
1061d62bc4baSyz147064 			flags &= ~DLADM_OPT_PERSIST;
10627c478bd9Sstevel@tonic-gate 			break;
10637c478bd9Sstevel@tonic-gate 		case 'R':
10647c478bd9Sstevel@tonic-gate 			altroot = optarg;
10657c478bd9Sstevel@tonic-gate 			break;
10667c478bd9Sstevel@tonic-gate 		default:
106733343a97Smeem 			die_opterr(optopt, option);
10687c478bd9Sstevel@tonic-gate 			break;
10697c478bd9Sstevel@tonic-gate 		}
10707c478bd9Sstevel@tonic-gate 	}
10717c478bd9Sstevel@tonic-gate 
1072d62bc4baSyz147064 	/* get key value or the aggregation name (required last argument) */
10737c478bd9Sstevel@tonic-gate 	if (optind != (argc-1))
10747c478bd9Sstevel@tonic-gate 		usage();
10757c478bd9Sstevel@tonic-gate 
1076d62bc4baSyz147064 	status = i_dladm_aggr_get_linkid(altroot, argv[optind], &linkid, flags);
1077d62bc4baSyz147064 	if (status != DLADM_STATUS_OK)
1078d62bc4baSyz147064 		goto done;
10797c478bd9Sstevel@tonic-gate 
1080d62bc4baSyz147064 	if (altroot != NULL)
1081d62bc4baSyz147064 		altroot_cmd(altroot, argc, argv);
1082d62bc4baSyz147064 
1083d62bc4baSyz147064 	status = dladm_aggr_delete(linkid, flags);
1084d62bc4baSyz147064 done:
1085f595a68aSyz147064 	if (status != DLADM_STATUS_OK)
1086f595a68aSyz147064 		die_dlerr(status, "delete operation failed");
10877c478bd9Sstevel@tonic-gate }
10887c478bd9Sstevel@tonic-gate 
10897c478bd9Sstevel@tonic-gate static void
10907c478bd9Sstevel@tonic-gate do_add_aggr(int argc, char *argv[])
10917c478bd9Sstevel@tonic-gate {
10927c478bd9Sstevel@tonic-gate 	char			option;
1093d62bc4baSyz147064 	uint_t			n, ndev, nlink;
10947c478bd9Sstevel@tonic-gate 	char			*altroot = NULL;
1095d62bc4baSyz147064 	uint32_t		flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
1096d62bc4baSyz147064 	datalink_id_t		linkid;
1097f595a68aSyz147064 	dladm_status_t		status;
1098d62bc4baSyz147064 	dladm_aggr_port_attr_db_t	port[MAXPORT];
1099d62bc4baSyz147064 	char			*devs[MAXPORT];
1100d62bc4baSyz147064 	char			*links[MAXPORT];
11017c478bd9Sstevel@tonic-gate 
1102d62bc4baSyz147064 	ndev = nlink = opterr = 0;
1103d62bc4baSyz147064 	while ((option = getopt_long(argc, argv, ":d:l:R:tf", lopts,
11047c478bd9Sstevel@tonic-gate 	    NULL)) != -1) {
11057c478bd9Sstevel@tonic-gate 		switch (option) {
11067c478bd9Sstevel@tonic-gate 		case 'd':
1107d62bc4baSyz147064 			if (ndev + nlink >= MAXPORT)
1108d62bc4baSyz147064 				die("too many ports specified");
11097c478bd9Sstevel@tonic-gate 
1110d62bc4baSyz147064 			devs[ndev++] = optarg;
1111d62bc4baSyz147064 			break;
1112d62bc4baSyz147064 		case 'l':
1113d62bc4baSyz147064 			if (ndev + nlink >= MAXPORT)
1114d62bc4baSyz147064 				die("too many ports specified");
111533343a97Smeem 
1116d62bc4baSyz147064 			links[nlink++] = optarg;
11177c478bd9Sstevel@tonic-gate 			break;
11187c478bd9Sstevel@tonic-gate 		case 't':
1119d62bc4baSyz147064 			flags &= ~DLADM_OPT_PERSIST;
1120d62bc4baSyz147064 			break;
1121d62bc4baSyz147064 		case 'f':
1122d62bc4baSyz147064 			flags |= DLADM_OPT_FORCE;
11237c478bd9Sstevel@tonic-gate 			break;
11247c478bd9Sstevel@tonic-gate 		case 'R':
11257c478bd9Sstevel@tonic-gate 			altroot = optarg;
11267c478bd9Sstevel@tonic-gate 			break;
11277c478bd9Sstevel@tonic-gate 		default:
112833343a97Smeem 			die_opterr(optopt, option);
112933343a97Smeem 			break;
11307c478bd9Sstevel@tonic-gate 		}
11317c478bd9Sstevel@tonic-gate 	}
11327c478bd9Sstevel@tonic-gate 
1133d62bc4baSyz147064 	if (ndev + nlink == 0)
11347c478bd9Sstevel@tonic-gate 		usage();
11357c478bd9Sstevel@tonic-gate 
1136d62bc4baSyz147064 	/* get key value or the aggregation name (required last argument) */
11377c478bd9Sstevel@tonic-gate 	if (optind != (argc-1))
11387c478bd9Sstevel@tonic-gate 		usage();
11397c478bd9Sstevel@tonic-gate 
1140d62bc4baSyz147064 	if ((status = i_dladm_aggr_get_linkid(altroot, argv[optind], &linkid,
1141d62bc4baSyz147064 	    flags & (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST))) !=
1142d62bc4baSyz147064 	    DLADM_STATUS_OK) {
1143d62bc4baSyz147064 		goto done;
1144d62bc4baSyz147064 	}
11457c478bd9Sstevel@tonic-gate 
1146d62bc4baSyz147064 	if (altroot != NULL)
1147d62bc4baSyz147064 		altroot_cmd(altroot, argc, argv);
1148d62bc4baSyz147064 
1149d62bc4baSyz147064 	for (n = 0; n < ndev; n++) {
1150d62bc4baSyz147064 		if (dladm_dev2linkid(devs[n], &(port[n].lp_linkid)) !=
1151d62bc4baSyz147064 		    DLADM_STATUS_OK) {
1152d62bc4baSyz147064 			die("invalid <dev> '%s'", devs[n]);
1153d62bc4baSyz147064 		}
1154d62bc4baSyz147064 	}
1155d62bc4baSyz147064 
1156d62bc4baSyz147064 	for (n = 0; n < nlink; n++) {
1157d62bc4baSyz147064 		if (dladm_name2info(links[n], &port[n + ndev].lp_linkid,
1158d62bc4baSyz147064 		    NULL, NULL, NULL) != DLADM_STATUS_OK) {
1159d62bc4baSyz147064 			die("invalid <link> '%s'", links[n]);
1160d62bc4baSyz147064 		}
1161d62bc4baSyz147064 	}
1162d62bc4baSyz147064 
1163d62bc4baSyz147064 	status = dladm_aggr_add(linkid, ndev + nlink, port, flags);
1164d62bc4baSyz147064 done:
1165f595a68aSyz147064 	if (status != DLADM_STATUS_OK) {
1166219a2a31Shl157128 		/*
1167f595a68aSyz147064 		 * checking DLADM_STATUS_NOTSUP is a temporary workaround
1168219a2a31Shl157128 		 * and should be removed once 6399681 is fixed.
1169219a2a31Shl157128 		 */
1170f595a68aSyz147064 		if (status == DLADM_STATUS_NOTSUP) {
1171219a2a31Shl157128 			(void) fprintf(stderr,
1172219a2a31Shl157128 			    gettext("%s: add operation failed: %s\n"),
1173219a2a31Shl157128 			    progname,
1174d62bc4baSyz147064 			    gettext("link capabilities don't match"));
1175219a2a31Shl157128 			exit(ENOTSUP);
1176d62bc4baSyz147064 		} else if (status == DLADM_STATUS_NONOTIF) {
1177d62bc4baSyz147064 			die_dlerr(status, "not all links have link up/down "
1178d62bc4baSyz147064 			    "detection; must use -f (see dladm(1M))\n");
1179d62bc4baSyz147064 		} else {
1180f595a68aSyz147064 			die_dlerr(status, "add operation failed");
11817c478bd9Sstevel@tonic-gate 		}
11827c478bd9Sstevel@tonic-gate 	}
1183d62bc4baSyz147064 }
11847c478bd9Sstevel@tonic-gate 
11857c478bd9Sstevel@tonic-gate static void
11867c478bd9Sstevel@tonic-gate do_remove_aggr(int argc, char *argv[])
11877c478bd9Sstevel@tonic-gate {
11887c478bd9Sstevel@tonic-gate 	char				option;
1189f595a68aSyz147064 	dladm_aggr_port_attr_db_t	port[MAXPORT];
1190d62bc4baSyz147064 	uint_t				n, ndev, nlink;
1191d62bc4baSyz147064 	char				*devs[MAXPORT];
1192d62bc4baSyz147064 	char				*links[MAXPORT];
11937c478bd9Sstevel@tonic-gate 	char				*altroot = NULL;
1194d62bc4baSyz147064 	uint32_t			flags;
1195d62bc4baSyz147064 	datalink_id_t			linkid;
1196f595a68aSyz147064 	dladm_status_t			status;
11977c478bd9Sstevel@tonic-gate 
1198d62bc4baSyz147064 	flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
1199d62bc4baSyz147064 	ndev = nlink = opterr = 0;
1200d62bc4baSyz147064 	while ((option = getopt_long(argc, argv, ":d:l:R:t",
1201d62bc4baSyz147064 	    lopts, NULL)) != -1) {
12027c478bd9Sstevel@tonic-gate 		switch (option) {
12037c478bd9Sstevel@tonic-gate 		case 'd':
1204d62bc4baSyz147064 			if (ndev + nlink >= MAXPORT)
1205d62bc4baSyz147064 				die("too many ports specified");
12067c478bd9Sstevel@tonic-gate 
1207d62bc4baSyz147064 			devs[ndev++] = optarg;
1208d62bc4baSyz147064 			break;
1209d62bc4baSyz147064 		case 'l':
1210d62bc4baSyz147064 			if (ndev + nlink >= MAXPORT)
1211d62bc4baSyz147064 				die("too many ports specified");
121233343a97Smeem 
1213d62bc4baSyz147064 			links[nlink++] = optarg;
12147c478bd9Sstevel@tonic-gate 			break;
12157c478bd9Sstevel@tonic-gate 		case 't':
1216d62bc4baSyz147064 			flags &= ~DLADM_OPT_PERSIST;
12177c478bd9Sstevel@tonic-gate 			break;
12187c478bd9Sstevel@tonic-gate 		case 'R':
12197c478bd9Sstevel@tonic-gate 			altroot = optarg;
12207c478bd9Sstevel@tonic-gate 			break;
12217c478bd9Sstevel@tonic-gate 		default:
122233343a97Smeem 			die_opterr(optopt, option);
122333343a97Smeem 			break;
12247c478bd9Sstevel@tonic-gate 		}
12257c478bd9Sstevel@tonic-gate 	}
12267c478bd9Sstevel@tonic-gate 
1227d62bc4baSyz147064 	if (ndev + nlink == 0)
12287c478bd9Sstevel@tonic-gate 		usage();
12297c478bd9Sstevel@tonic-gate 
1230d62bc4baSyz147064 	/* get key value or the aggregation name (required last argument) */
12317c478bd9Sstevel@tonic-gate 	if (optind != (argc-1))
12327c478bd9Sstevel@tonic-gate 		usage();
12337c478bd9Sstevel@tonic-gate 
1234d62bc4baSyz147064 	status = i_dladm_aggr_get_linkid(altroot, argv[optind], &linkid, flags);
1235d62bc4baSyz147064 	if (status != DLADM_STATUS_OK)
1236d62bc4baSyz147064 		goto done;
12377c478bd9Sstevel@tonic-gate 
1238d62bc4baSyz147064 	if (altroot != NULL)
1239d62bc4baSyz147064 		altroot_cmd(altroot, argc, argv);
1240d62bc4baSyz147064 
1241d62bc4baSyz147064 	for (n = 0; n < ndev; n++) {
1242d62bc4baSyz147064 		if (dladm_dev2linkid(devs[n], &(port[n].lp_linkid)) !=
1243d62bc4baSyz147064 		    DLADM_STATUS_OK) {
1244d62bc4baSyz147064 			die("invalid <dev> '%s'", devs[n]);
1245d62bc4baSyz147064 		}
1246d62bc4baSyz147064 	}
1247d62bc4baSyz147064 
1248d62bc4baSyz147064 	for (n = 0; n < nlink; n++) {
1249d62bc4baSyz147064 		if (dladm_name2info(links[n], &port[n + ndev].lp_linkid,
1250d62bc4baSyz147064 		    NULL, NULL, NULL) != DLADM_STATUS_OK) {
1251d62bc4baSyz147064 			die("invalid <link> '%s'", links[n]);
1252d62bc4baSyz147064 		}
1253d62bc4baSyz147064 	}
1254d62bc4baSyz147064 
1255d62bc4baSyz147064 	status = dladm_aggr_remove(linkid, ndev + nlink, port, flags);
1256d62bc4baSyz147064 done:
1257f595a68aSyz147064 	if (status != DLADM_STATUS_OK)
1258f595a68aSyz147064 		die_dlerr(status, "remove operation failed");
12597c478bd9Sstevel@tonic-gate }
12607c478bd9Sstevel@tonic-gate 
12617c478bd9Sstevel@tonic-gate static void
12627c478bd9Sstevel@tonic-gate do_modify_aggr(int argc, char *argv[])
12637c478bd9Sstevel@tonic-gate {
12647c478bd9Sstevel@tonic-gate 	char			option;
12657c478bd9Sstevel@tonic-gate 	uint32_t		policy = AGGR_POLICY_L4;
12667c478bd9Sstevel@tonic-gate 	aggr_lacp_mode_t	lacp_mode = AGGR_LACP_OFF;
12677c478bd9Sstevel@tonic-gate 	aggr_lacp_timer_t	lacp_timer = AGGR_LACP_TIMER_SHORT;
12687c478bd9Sstevel@tonic-gate 	uint8_t			mac_addr[ETHERADDRL];
12697c478bd9Sstevel@tonic-gate 	boolean_t		mac_addr_fixed = B_FALSE;
12707c478bd9Sstevel@tonic-gate 	uint8_t			modify_mask = 0;
12717c478bd9Sstevel@tonic-gate 	char			*altroot = NULL;
1272d62bc4baSyz147064 	uint32_t		flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
1273d62bc4baSyz147064 	datalink_id_t		linkid;
1274f595a68aSyz147064 	dladm_status_t		status;
12757c478bd9Sstevel@tonic-gate 
12767c478bd9Sstevel@tonic-gate 	opterr = 0;
1277d62bc4baSyz147064 	while ((option = getopt_long(argc, argv, ":L:l:P:R:tu:T:", lopts,
12787c478bd9Sstevel@tonic-gate 	    NULL)) != -1) {
12797c478bd9Sstevel@tonic-gate 		switch (option) {
12807c478bd9Sstevel@tonic-gate 		case 'P':
1281f595a68aSyz147064 			if (modify_mask & DLADM_AGGR_MODIFY_POLICY)
128233343a97Smeem 				die_optdup(option);
12837c478bd9Sstevel@tonic-gate 
1284f595a68aSyz147064 			modify_mask |= DLADM_AGGR_MODIFY_POLICY;
12857c478bd9Sstevel@tonic-gate 
1286f595a68aSyz147064 			if (!dladm_aggr_str2policy(optarg, &policy))
128733343a97Smeem 				die("invalid policy '%s'", optarg);
12887c478bd9Sstevel@tonic-gate 			break;
12897c478bd9Sstevel@tonic-gate 		case 'u':
1290f595a68aSyz147064 			if (modify_mask & DLADM_AGGR_MODIFY_MAC)
129133343a97Smeem 				die_optdup(option);
12927c478bd9Sstevel@tonic-gate 
1293f595a68aSyz147064 			modify_mask |= DLADM_AGGR_MODIFY_MAC;
12947c478bd9Sstevel@tonic-gate 
1295f595a68aSyz147064 			if (!dladm_aggr_str2macaddr(optarg, &mac_addr_fixed,
129633343a97Smeem 			    mac_addr))
129733343a97Smeem 				die("invalid MAC address '%s'", optarg);
12987c478bd9Sstevel@tonic-gate 			break;
12997c478bd9Sstevel@tonic-gate 		case 'l':
1300d62bc4baSyz147064 		case 'L':
1301f595a68aSyz147064 			if (modify_mask & DLADM_AGGR_MODIFY_LACP_MODE)
130233343a97Smeem 				die_optdup(option);
13037c478bd9Sstevel@tonic-gate 
1304f595a68aSyz147064 			modify_mask |= DLADM_AGGR_MODIFY_LACP_MODE;
13057c478bd9Sstevel@tonic-gate 
1306f595a68aSyz147064 			if (!dladm_aggr_str2lacpmode(optarg, &lacp_mode))
130733343a97Smeem 				die("invalid LACP mode '%s'", optarg);
13087c478bd9Sstevel@tonic-gate 			break;
13097c478bd9Sstevel@tonic-gate 		case 'T':
1310f595a68aSyz147064 			if (modify_mask & DLADM_AGGR_MODIFY_LACP_TIMER)
131133343a97Smeem 				die_optdup(option);
13127c478bd9Sstevel@tonic-gate 
1313f595a68aSyz147064 			modify_mask |= DLADM_AGGR_MODIFY_LACP_TIMER;
13147c478bd9Sstevel@tonic-gate 
1315f595a68aSyz147064 			if (!dladm_aggr_str2lacptimer(optarg, &lacp_timer))
131633343a97Smeem 				die("invalid LACP timer value '%s'", optarg);
13177c478bd9Sstevel@tonic-gate 			break;
13187c478bd9Sstevel@tonic-gate 		case 't':
1319d62bc4baSyz147064 			flags &= ~DLADM_OPT_PERSIST;
13207c478bd9Sstevel@tonic-gate 			break;
13217c478bd9Sstevel@tonic-gate 		case 'R':
13227c478bd9Sstevel@tonic-gate 			altroot = optarg;
13237c478bd9Sstevel@tonic-gate 			break;
13247c478bd9Sstevel@tonic-gate 		default:
132533343a97Smeem 			die_opterr(optopt, option);
132633343a97Smeem 			break;
13277c478bd9Sstevel@tonic-gate 		}
13287c478bd9Sstevel@tonic-gate 	}
13297c478bd9Sstevel@tonic-gate 
133033343a97Smeem 	if (modify_mask == 0)
133133343a97Smeem 		die("at least one of the -PulT options must be specified");
13327c478bd9Sstevel@tonic-gate 
1333d62bc4baSyz147064 	/* get key value or the aggregation name (required last argument) */
13347c478bd9Sstevel@tonic-gate 	if (optind != (argc-1))
13357c478bd9Sstevel@tonic-gate 		usage();
13367c478bd9Sstevel@tonic-gate 
1337d62bc4baSyz147064 	status = i_dladm_aggr_get_linkid(altroot, argv[optind], &linkid, flags);
1338d62bc4baSyz147064 	if (status != DLADM_STATUS_OK)
1339d62bc4baSyz147064 		goto done;
13407c478bd9Sstevel@tonic-gate 
1341d62bc4baSyz147064 	if (altroot != NULL)
1342d62bc4baSyz147064 		altroot_cmd(altroot, argc, argv);
1343d62bc4baSyz147064 
1344d62bc4baSyz147064 	status = dladm_aggr_modify(linkid, modify_mask, policy, mac_addr_fixed,
1345d62bc4baSyz147064 	    (const uchar_t *)mac_addr, lacp_mode, lacp_timer, flags);
1346d62bc4baSyz147064 
1347d62bc4baSyz147064 done:
1348f595a68aSyz147064 	if (status != DLADM_STATUS_OK)
1349f595a68aSyz147064 		die_dlerr(status, "modify operation failed");
13507c478bd9Sstevel@tonic-gate }
13517c478bd9Sstevel@tonic-gate 
13527c478bd9Sstevel@tonic-gate static void
13537c478bd9Sstevel@tonic-gate do_up_aggr(int argc, char *argv[])
13547c478bd9Sstevel@tonic-gate {
1355d62bc4baSyz147064 	datalink_id_t	linkid = DATALINK_ALL_LINKID;
1356f595a68aSyz147064 	dladm_status_t	status;
13577c478bd9Sstevel@tonic-gate 
1358d62bc4baSyz147064 	/*
1359d62bc4baSyz147064 	 * get the key or the name of the aggregation (optional last argument)
1360d62bc4baSyz147064 	 */
13617c478bd9Sstevel@tonic-gate 	if (argc == 2) {
1362d62bc4baSyz147064 		if ((status = i_dladm_aggr_get_linkid(NULL, argv[1], &linkid,
1363d62bc4baSyz147064 		    DLADM_OPT_PERSIST)) != DLADM_STATUS_OK) {
1364d62bc4baSyz147064 			goto done;
1365d62bc4baSyz147064 		}
13667c478bd9Sstevel@tonic-gate 	} else if (argc > 2) {
13677c478bd9Sstevel@tonic-gate 		usage();
13687c478bd9Sstevel@tonic-gate 	}
13697c478bd9Sstevel@tonic-gate 
1370d62bc4baSyz147064 	status = dladm_aggr_up(linkid);
1371d62bc4baSyz147064 done:
1372d62bc4baSyz147064 	if (status != DLADM_STATUS_OK) {
1373d62bc4baSyz147064 		if (argc == 2) {
1374d62bc4baSyz147064 			die_dlerr(status,
1375d62bc4baSyz147064 			    "could not bring up aggregation '%s'", argv[1]);
13767c478bd9Sstevel@tonic-gate 		} else {
1377f595a68aSyz147064 			die_dlerr(status, "could not bring aggregations up");
13787c478bd9Sstevel@tonic-gate 		}
13797c478bd9Sstevel@tonic-gate 	}
13807c478bd9Sstevel@tonic-gate }
13817c478bd9Sstevel@tonic-gate 
13827c478bd9Sstevel@tonic-gate static void
1383d62bc4baSyz147064 do_create_vlan(int argc, char *argv[])
13847c478bd9Sstevel@tonic-gate {
1385d62bc4baSyz147064 	char		*link = NULL;
1386d62bc4baSyz147064 	char		drv[DLPI_LINKNAME_MAX];
1387d62bc4baSyz147064 	uint_t		ppa;
1388d62bc4baSyz147064 	datalink_id_t	linkid;
1389d62bc4baSyz147064 	int		vid = 0;
1390d62bc4baSyz147064 	char		option;
1391d62bc4baSyz147064 	uint32_t	flags = (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST);
1392d62bc4baSyz147064 	char		*altroot = NULL;
1393d62bc4baSyz147064 	char		vlan[MAXLINKNAMELEN];
1394f595a68aSyz147064 	dladm_status_t	status;
13957c478bd9Sstevel@tonic-gate 
1396d62bc4baSyz147064 	opterr = 0;
1397d62bc4baSyz147064 	while ((option = getopt_long(argc, argv, ":tfl:v:",
1398d62bc4baSyz147064 	    lopts, NULL)) != -1) {
1399d62bc4baSyz147064 		switch (option) {
1400d62bc4baSyz147064 		case 'v':
1401d62bc4baSyz147064 			if (vid != 0)
1402d62bc4baSyz147064 				die_optdup(option);
1403d62bc4baSyz147064 
1404d62bc4baSyz147064 			if (!str2int(optarg, &vid) || vid < 1 || vid > 4094)
1405d62bc4baSyz147064 				die("invalid VLAN identifier '%s'", optarg);
1406d62bc4baSyz147064 
1407d62bc4baSyz147064 			break;
1408d62bc4baSyz147064 		case 'l':
1409d62bc4baSyz147064 			if (link != NULL)
1410d62bc4baSyz147064 				die_optdup(option);
1411d62bc4baSyz147064 
1412d62bc4baSyz147064 			link = optarg;
1413d62bc4baSyz147064 			break;
1414d62bc4baSyz147064 		case 'f':
1415d62bc4baSyz147064 			flags |= DLADM_OPT_FORCE;
1416d62bc4baSyz147064 			break;
1417d62bc4baSyz147064 		case 't':
1418d62bc4baSyz147064 			flags &= ~DLADM_OPT_PERSIST;
1419d62bc4baSyz147064 			break;
1420d62bc4baSyz147064 		case 'R':
1421d62bc4baSyz147064 			altroot = optarg;
1422d62bc4baSyz147064 			break;
1423d62bc4baSyz147064 		default:
1424d62bc4baSyz147064 			die_opterr(optopt, option);
1425d62bc4baSyz147064 			break;
1426d62bc4baSyz147064 		}
1427d62bc4baSyz147064 	}
1428d62bc4baSyz147064 
1429d62bc4baSyz147064 	/* get vlan name if there is any */
1430d62bc4baSyz147064 	if ((vid == 0) || (link == NULL) || (argc - optind > 1))
14317c478bd9Sstevel@tonic-gate 		usage();
1432d62bc4baSyz147064 
1433d62bc4baSyz147064 	if (optind == (argc - 1)) {
1434d62bc4baSyz147064 		if (strlcpy(vlan, argv[optind], MAXLINKNAMELEN) >=
1435d62bc4baSyz147064 		    MAXLINKNAMELEN) {
1436d62bc4baSyz147064 			die("vlan name too long '%s'", argv[optind]);
1437d62bc4baSyz147064 		}
1438d62bc4baSyz147064 	} else {
1439d62bc4baSyz147064 		if ((dlpi_parselink(link, drv, &ppa) != DLPI_SUCCESS) ||
1440d62bc4baSyz147064 		    (ppa >= 1000) ||
1441d62bc4baSyz147064 		    (dlpi_makelink(vlan, drv, vid * 1000 + ppa) !=
1442d62bc4baSyz147064 		    DLPI_SUCCESS)) {
1443d62bc4baSyz147064 			die("invalid link name '%s'", link);
1444d62bc4baSyz147064 		}
14457c478bd9Sstevel@tonic-gate 	}
14467c478bd9Sstevel@tonic-gate 
1447d62bc4baSyz147064 	if (altroot != NULL)
1448d62bc4baSyz147064 		altroot_cmd(altroot, argc, argv);
1449d62bc4baSyz147064 
1450d62bc4baSyz147064 	if (dladm_name2info(link, &linkid, NULL, NULL, NULL) !=
1451d62bc4baSyz147064 	    DLADM_STATUS_OK) {
1452d62bc4baSyz147064 		die("invalid link name '%s'", link);
1453d62bc4baSyz147064 	}
1454d62bc4baSyz147064 
1455d62bc4baSyz147064 	if ((status = dladm_vlan_create(vlan, linkid, vid, flags)) !=
1456d62bc4baSyz147064 	    DLADM_STATUS_OK) {
1457d62bc4baSyz147064 		if (status == DLADM_STATUS_NOTSUP) {
1458*e7801d59Ssowmini 			die_dlerr(status, "not all links have link up/down "
1459*e7801d59Ssowmini 			    "detection; must use -f (see dladm(1M))\n");
1460d62bc4baSyz147064 		} else {
1461d62bc4baSyz147064 			die_dlerr(status, "create operation failed");
1462d62bc4baSyz147064 		}
1463d62bc4baSyz147064 	}
1464d62bc4baSyz147064 }
1465d62bc4baSyz147064 
1466d62bc4baSyz147064 static void
1467d62bc4baSyz147064 do_delete_vlan(int argc, char *argv[])
1468d62bc4baSyz147064 {
1469d62bc4baSyz147064 	char		option;
1470d62bc4baSyz147064 	uint32_t	flags = (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST);
1471d62bc4baSyz147064 	char		*altroot = NULL;
1472d62bc4baSyz147064 	datalink_id_t	linkid;
1473d62bc4baSyz147064 	dladm_status_t	status;
1474d62bc4baSyz147064 
1475d62bc4baSyz147064 	opterr = 0;
1476d62bc4baSyz147064 	while ((option = getopt_long(argc, argv, ":R:t", lopts, NULL)) != -1) {
1477d62bc4baSyz147064 		switch (option) {
1478d62bc4baSyz147064 		case 't':
1479d62bc4baSyz147064 			flags &= ~DLADM_OPT_PERSIST;
1480d62bc4baSyz147064 			break;
1481d62bc4baSyz147064 		case 'R':
1482d62bc4baSyz147064 			altroot = optarg;
1483d62bc4baSyz147064 			break;
1484d62bc4baSyz147064 		default:
1485d62bc4baSyz147064 			die_opterr(optopt, option);
1486d62bc4baSyz147064 			break;
1487d62bc4baSyz147064 		}
1488d62bc4baSyz147064 	}
1489d62bc4baSyz147064 
1490d62bc4baSyz147064 	/* get VLAN link name (required last argument) */
1491d62bc4baSyz147064 	if (optind != (argc - 1))
1492d62bc4baSyz147064 		usage();
1493d62bc4baSyz147064 
1494d62bc4baSyz147064 	if (altroot != NULL)
1495d62bc4baSyz147064 		altroot_cmd(altroot, argc, argv);
1496d62bc4baSyz147064 
1497d62bc4baSyz147064 	status = dladm_name2info(argv[optind], &linkid, NULL, NULL, NULL);
1498d62bc4baSyz147064 	if (status != DLADM_STATUS_OK)
1499d62bc4baSyz147064 		goto done;
1500d62bc4baSyz147064 
1501d62bc4baSyz147064 	status = dladm_vlan_delete(linkid, flags);
1502d62bc4baSyz147064 done:
1503d62bc4baSyz147064 	if (status != DLADM_STATUS_OK)
1504d62bc4baSyz147064 		die_dlerr(status, "delete operation failed");
1505d62bc4baSyz147064 }
1506d62bc4baSyz147064 
1507d62bc4baSyz147064 static void
1508d62bc4baSyz147064 do_up_vlan(int argc, char *argv[])
1509d62bc4baSyz147064 {
1510d62bc4baSyz147064 	datalink_id_t	linkid = DATALINK_ALL_LINKID;
1511d62bc4baSyz147064 	dladm_status_t	status;
1512d62bc4baSyz147064 
1513d62bc4baSyz147064 	/*
1514d62bc4baSyz147064 	 * get the name of the VLAN (optional last argument)
1515d62bc4baSyz147064 	 */
1516d62bc4baSyz147064 	if (argc > 2)
1517d62bc4baSyz147064 		usage();
1518d62bc4baSyz147064 
1519d62bc4baSyz147064 	if (argc == 2) {
1520d62bc4baSyz147064 		status = dladm_name2info(argv[1], &linkid, NULL, NULL, NULL);
1521d62bc4baSyz147064 		if (status != DLADM_STATUS_OK)
1522d62bc4baSyz147064 			goto done;
1523d62bc4baSyz147064 	}
1524d62bc4baSyz147064 
1525d62bc4baSyz147064 	status = dladm_vlan_up(linkid);
1526d62bc4baSyz147064 done:
1527d62bc4baSyz147064 	if (status != DLADM_STATUS_OK) {
1528d62bc4baSyz147064 		if (argc == 2) {
1529f595a68aSyz147064 			die_dlerr(status,
1530d62bc4baSyz147064 			    "could not bring up VLAN '%s'", argv[1]);
15317c478bd9Sstevel@tonic-gate 		} else {
1532d62bc4baSyz147064 			die_dlerr(status, "could not bring VLANs up");
15337c478bd9Sstevel@tonic-gate 		}
15347c478bd9Sstevel@tonic-gate 	}
15357c478bd9Sstevel@tonic-gate }
15367c478bd9Sstevel@tonic-gate 
1537210db224Sericheng static void
1538d62bc4baSyz147064 do_rename_link(int argc, char *argv[])
1539210db224Sericheng {
1540d62bc4baSyz147064 	char		option;
1541d62bc4baSyz147064 	char		*link1, *link2;
1542d62bc4baSyz147064 	char		*altroot = NULL;
1543d62bc4baSyz147064 	dladm_status_t	status;
1544210db224Sericheng 
1545d62bc4baSyz147064 	opterr = 0;
1546d62bc4baSyz147064 	while ((option = getopt_long(argc, argv, ":R:", lopts, NULL)) != -1) {
1547d62bc4baSyz147064 		switch (option) {
1548d62bc4baSyz147064 		case 'R':
1549d62bc4baSyz147064 			altroot = optarg;
1550d62bc4baSyz147064 			break;
1551d62bc4baSyz147064 		default:
1552d62bc4baSyz147064 			die_opterr(optopt, option);
1553d62bc4baSyz147064 			break;
1554210db224Sericheng 		}
1555210db224Sericheng 	}
1556210db224Sericheng 
1557d62bc4baSyz147064 	/* get link1 and link2 name (required the last 2 arguments) */
1558d62bc4baSyz147064 	if (optind != (argc - 2))
1559d62bc4baSyz147064 		usage();
1560d62bc4baSyz147064 
1561d62bc4baSyz147064 	if (altroot != NULL)
1562d62bc4baSyz147064 		altroot_cmd(altroot, argc, argv);
1563d62bc4baSyz147064 
1564d62bc4baSyz147064 	link1 = argv[optind++];
1565d62bc4baSyz147064 	link2 = argv[optind];
1566d62bc4baSyz147064 	if ((status = dladm_rename_link(link1, link2)) != DLADM_STATUS_OK)
1567d62bc4baSyz147064 		die_dlerr(status, "rename operation failed");
1568d62bc4baSyz147064 }
1569d62bc4baSyz147064 
1570d62bc4baSyz147064 static void
1571d62bc4baSyz147064 do_delete_phys(int argc, char *argv[])
1572d62bc4baSyz147064 {
1573d62bc4baSyz147064 	datalink_id_t	linkid = DATALINK_ALL_LINKID;
1574d62bc4baSyz147064 	dladm_status_t	status;
1575d62bc4baSyz147064 
1576d62bc4baSyz147064 	/* get link name (required the last argument) */
1577d62bc4baSyz147064 	if (argc > 2)
1578d62bc4baSyz147064 		usage();
1579d62bc4baSyz147064 
1580d62bc4baSyz147064 	if (argc == 2) {
1581d62bc4baSyz147064 		status = dladm_name2info(argv[1], &linkid, NULL, NULL, NULL);
1582d62bc4baSyz147064 		if (status != DLADM_STATUS_OK)
1583d62bc4baSyz147064 			die_dlerr(status, "cannot delete '%s'", argv[1]);
1584d62bc4baSyz147064 	}
1585d62bc4baSyz147064 
1586d62bc4baSyz147064 	if ((status = dladm_phys_delete(linkid)) != DLADM_STATUS_OK) {
1587d62bc4baSyz147064 		if (argc == 2)
1588d62bc4baSyz147064 			die_dlerr(status, "cannot delete '%s'", argv[1]);
1589d62bc4baSyz147064 		else
1590d62bc4baSyz147064 			die_dlerr(status, "delete operation failed");
1591d62bc4baSyz147064 	}
1592d62bc4baSyz147064 }
1593d62bc4baSyz147064 
1594d62bc4baSyz147064 /*ARGSUSED*/
1595210db224Sericheng static int
1596d62bc4baSyz147064 i_dladm_walk_linkmap(datalink_id_t linkid, void *arg)
1597210db224Sericheng {
1598d62bc4baSyz147064 	char			name[MAXLINKNAMELEN];
1599d62bc4baSyz147064 	char			mediabuf[DLADM_STRSIZE];
1600d62bc4baSyz147064 	char			classbuf[DLADM_STRSIZE];
1601d62bc4baSyz147064 	datalink_class_t	class;
1602d62bc4baSyz147064 	uint32_t		media;
1603d62bc4baSyz147064 	uint32_t		flags;
1604210db224Sericheng 
1605d62bc4baSyz147064 	if (dladm_datalink_id2info(linkid, &flags, &class, &media, name,
1606d62bc4baSyz147064 	    MAXLINKNAMELEN) == DLADM_STATUS_OK) {
1607d62bc4baSyz147064 		(void) dladm_class2str(class, classbuf);
1608d62bc4baSyz147064 		(void) dladm_media2str(media, mediabuf);
1609d62bc4baSyz147064 		(void) printf("%-12s%8d  %-12s%-20s %6d\n", name,
1610d62bc4baSyz147064 		    linkid, classbuf, mediabuf, flags);
1611210db224Sericheng 	}
1612d62bc4baSyz147064 	return (DLADM_WALK_CONTINUE);
1613210db224Sericheng }
16147c478bd9Sstevel@tonic-gate 
16157c478bd9Sstevel@tonic-gate /*ARGSUSED*/
16167c478bd9Sstevel@tonic-gate static void
1617d62bc4baSyz147064 do_show_linkmap(int argc, char *argv[])
16187c478bd9Sstevel@tonic-gate {
1619d62bc4baSyz147064 	if (argc != 1)
1620d62bc4baSyz147064 		die("invalid arguments");
16217c478bd9Sstevel@tonic-gate 
1622d62bc4baSyz147064 	(void) printf("%-12s%8s  %-12s%-20s %6s\n", "NAME", "LINKID",
1623d62bc4baSyz147064 	    "CLASS", "MEDIA", "FLAGS");
1624d62bc4baSyz147064 	(void) dladm_walk_datalink_id(i_dladm_walk_linkmap, NULL,
1625d62bc4baSyz147064 	    DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE,
1626d62bc4baSyz147064 	    DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST);
16277c478bd9Sstevel@tonic-gate }
1628d62bc4baSyz147064 
1629d62bc4baSyz147064 /*
1630d62bc4baSyz147064  * Delete inactive physical links.
1631d62bc4baSyz147064  */
1632d62bc4baSyz147064 /*ARGSUSED*/
1633d62bc4baSyz147064 static int
1634d62bc4baSyz147064 purge_phys(datalink_id_t linkid, void *arg)
1635d62bc4baSyz147064 {
1636d62bc4baSyz147064 	datalink_class_t	class;
1637d62bc4baSyz147064 	uint32_t		flags;
1638d62bc4baSyz147064 
1639d62bc4baSyz147064 	if (dladm_datalink_id2info(linkid, &flags, &class, NULL,
1640d62bc4baSyz147064 	    NULL, 0) != DLADM_STATUS_OK) {
1641d62bc4baSyz147064 		return (DLADM_WALK_CONTINUE);
1642d62bc4baSyz147064 	}
1643d62bc4baSyz147064 
1644d62bc4baSyz147064 	if (class == DATALINK_CLASS_PHYS && !(flags & DLADM_OPT_ACTIVE))
1645d62bc4baSyz147064 		(void) dladm_phys_delete(linkid);
1646d62bc4baSyz147064 
1647d62bc4baSyz147064 	return (DLADM_WALK_CONTINUE);
1648d62bc4baSyz147064 }
1649d62bc4baSyz147064 
1650d62bc4baSyz147064 /*ARGSUSED*/
1651d62bc4baSyz147064 static void
1652d62bc4baSyz147064 do_init_phys(int argc, char *argv[])
1653d62bc4baSyz147064 {
1654d62bc4baSyz147064 	di_node_t devtree;
1655d62bc4baSyz147064 
1656d62bc4baSyz147064 	if (argc > 1)
1657d62bc4baSyz147064 		usage();
1658d62bc4baSyz147064 
1659d62bc4baSyz147064 	/*
1660d62bc4baSyz147064 	 * Force all the devices to attach, therefore all the network physical
1661d62bc4baSyz147064 	 * devices can be known to the dlmgmtd daemon.
1662d62bc4baSyz147064 	 */
1663d62bc4baSyz147064 	if ((devtree = di_init("/", DINFOFORCE | DINFOSUBTREE)) != DI_NODE_NIL)
1664d62bc4baSyz147064 		di_fini(devtree);
1665d62bc4baSyz147064 
1666d62bc4baSyz147064 	(void) dladm_walk_datalink_id(purge_phys, NULL,
1667d62bc4baSyz147064 	    DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST);
16687c478bd9Sstevel@tonic-gate }
16697c478bd9Sstevel@tonic-gate 
1670d62bc4baSyz147064 
1671d62bc4baSyz147064 /*
1672d62bc4baSyz147064  * Print the active topology information.
1673d62bc4baSyz147064  */
1674d62bc4baSyz147064 static dladm_status_t
1675d62bc4baSyz147064 print_link_topology(show_state_t *state, datalink_id_t linkid,
1676*e7801d59Ssowmini     datalink_class_t class, link_fields_buf_t *lbuf)
1677d62bc4baSyz147064 {
1678d62bc4baSyz147064 	uint32_t	flags = state->ls_flags;
1679d62bc4baSyz147064 	dladm_status_t	status = DLADM_STATUS_OK;
1680d62bc4baSyz147064 
1681*e7801d59Ssowmini 	if (!state->ls_parseable)
1682*e7801d59Ssowmini 		(void) sprintf(lbuf->link_over, STR_UNDEF_VAL);
1683d62bc4baSyz147064 	else
1684*e7801d59Ssowmini 		(void) sprintf(lbuf->link_over, "");
1685d62bc4baSyz147064 
1686d62bc4baSyz147064 	if (class == DATALINK_CLASS_VLAN) {
1687d62bc4baSyz147064 		dladm_vlan_attr_t	vinfo;
1688d62bc4baSyz147064 
1689d62bc4baSyz147064 		status = dladm_vlan_info(linkid, &vinfo, flags);
1690d62bc4baSyz147064 		if (status != DLADM_STATUS_OK)
1691d62bc4baSyz147064 			goto done;
1692d62bc4baSyz147064 		status = dladm_datalink_id2info(vinfo.dv_linkid, NULL, NULL,
1693*e7801d59Ssowmini 		    NULL, lbuf->link_over, sizeof (lbuf->link_over));
1694d62bc4baSyz147064 		if (status != DLADM_STATUS_OK)
1695d62bc4baSyz147064 			goto done;
1696d62bc4baSyz147064 	} else if (class == DATALINK_CLASS_AGGR) {
1697d62bc4baSyz147064 		dladm_aggr_grp_attr_t	ginfo;
1698d62bc4baSyz147064 		int			i;
1699d62bc4baSyz147064 
1700d62bc4baSyz147064 		status = dladm_aggr_info(linkid, &ginfo, flags);
1701d62bc4baSyz147064 		if (status != DLADM_STATUS_OK)
1702d62bc4baSyz147064 			goto done;
1703d62bc4baSyz147064 
1704d62bc4baSyz147064 		if (ginfo.lg_nports == 0) {
1705d62bc4baSyz147064 			status = DLADM_STATUS_BADVAL;
1706d62bc4baSyz147064 			goto done;
1707d62bc4baSyz147064 		}
1708d62bc4baSyz147064 		for (i = 0; i < ginfo.lg_nports; i++) {
1709d62bc4baSyz147064 			status = dladm_datalink_id2info(
1710*e7801d59Ssowmini 			    ginfo.lg_ports[i].lp_linkid, NULL, NULL, NULL,
1711*e7801d59Ssowmini 			    lbuf->link_over, sizeof (lbuf->link_over));
1712d62bc4baSyz147064 			if (status != DLADM_STATUS_OK) {
1713d62bc4baSyz147064 				free(ginfo.lg_ports);
1714d62bc4baSyz147064 				goto done;
1715d62bc4baSyz147064 			}
1716d62bc4baSyz147064 		}
1717d62bc4baSyz147064 		free(ginfo.lg_ports);
1718d62bc4baSyz147064 	} else if (class == DATALINK_CLASS_VNIC) {
1719d62bc4baSyz147064 		dladm_vnic_attr_sys_t	vinfo;
1720d62bc4baSyz147064 
1721d62bc4baSyz147064 		if ((status = dladm_vnic_info(linkid, &vinfo, flags)) !=
1722d62bc4baSyz147064 		    DLADM_STATUS_OK || (status = dladm_datalink_id2info(
1723*e7801d59Ssowmini 		    vinfo.va_link_id, NULL, NULL, NULL, lbuf->link_over,
1724*e7801d59Ssowmini 		    sizeof (lbuf->link_over)) != DLADM_STATUS_OK)) {
1725d62bc4baSyz147064 			goto done;
1726d62bc4baSyz147064 		}
1727d62bc4baSyz147064 	}
1728d62bc4baSyz147064 done:
1729d62bc4baSyz147064 	return (status);
1730d62bc4baSyz147064 }
1731d62bc4baSyz147064 
1732d62bc4baSyz147064 static dladm_status_t
1733*e7801d59Ssowmini print_link(show_state_t *state, datalink_id_t linkid, link_fields_buf_t *lbuf)
1734d62bc4baSyz147064 {
1735d62bc4baSyz147064 	char			link[MAXLINKNAMELEN];
1736d62bc4baSyz147064 	datalink_class_t	class;
1737d62bc4baSyz147064 	uint_t			mtu;
1738d62bc4baSyz147064 	uint32_t		flags;
1739d62bc4baSyz147064 	dladm_status_t		status;
1740d62bc4baSyz147064 
1741d62bc4baSyz147064 	if ((status = dladm_datalink_id2info(linkid, &flags, &class, NULL,
1742d62bc4baSyz147064 	    link, sizeof (link))) != DLADM_STATUS_OK) {
1743d62bc4baSyz147064 		goto done;
1744d62bc4baSyz147064 	}
1745d62bc4baSyz147064 
1746d62bc4baSyz147064 	if (!(state->ls_flags & flags)) {
1747d62bc4baSyz147064 		status = DLADM_STATUS_NOTFOUND;
1748d62bc4baSyz147064 		goto done;
1749d62bc4baSyz147064 	}
1750d62bc4baSyz147064 
1751d62bc4baSyz147064 	if (state->ls_flags == DLADM_OPT_ACTIVE) {
1752d62bc4baSyz147064 		dladm_attr_t	dlattr;
1753d62bc4baSyz147064 
1754d62bc4baSyz147064 		if (class == DATALINK_CLASS_PHYS) {
1755d62bc4baSyz147064 			dladm_phys_attr_t	dpa;
1756d62bc4baSyz147064 			dlpi_handle_t		dh;
1757d62bc4baSyz147064 			dlpi_info_t		dlinfo;
1758d62bc4baSyz147064 
1759d62bc4baSyz147064 			if ((status = dladm_phys_info(linkid, &dpa,
1760d62bc4baSyz147064 			    DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) {
1761d62bc4baSyz147064 				goto done;
1762d62bc4baSyz147064 			}
1763d62bc4baSyz147064 
1764d62bc4baSyz147064 			if (!dpa.dp_novanity)
1765d62bc4baSyz147064 				goto link_mtu;
1766d62bc4baSyz147064 
1767d62bc4baSyz147064 			/*
1768d62bc4baSyz147064 			 * This is a physical link that does not have
1769d62bc4baSyz147064 			 * vanity naming support.
1770d62bc4baSyz147064 			 */
1771d62bc4baSyz147064 			if (dlpi_open(dpa.dp_dev, &dh, DLPI_DEVONLY) !=
1772d62bc4baSyz147064 			    DLPI_SUCCESS) {
1773d62bc4baSyz147064 				status = DLADM_STATUS_NOTFOUND;
1774d62bc4baSyz147064 				goto done;
1775d62bc4baSyz147064 			}
1776d62bc4baSyz147064 
1777d62bc4baSyz147064 			if (dlpi_info(dh, &dlinfo, 0) != DLPI_SUCCESS) {
1778d62bc4baSyz147064 				dlpi_close(dh);
1779d62bc4baSyz147064 				status = DLADM_STATUS_BADARG;
1780d62bc4baSyz147064 				goto done;
1781d62bc4baSyz147064 			}
1782d62bc4baSyz147064 
1783d62bc4baSyz147064 			dlpi_close(dh);
1784d62bc4baSyz147064 			mtu = dlinfo.di_max_sdu;
1785d62bc4baSyz147064 		} else {
1786d62bc4baSyz147064 link_mtu:
1787d62bc4baSyz147064 			status = dladm_info(linkid, &dlattr);
1788d62bc4baSyz147064 			if (status != DLADM_STATUS_OK)
1789d62bc4baSyz147064 				goto done;
1790d62bc4baSyz147064 			mtu = dlattr.da_max_sdu;
1791d62bc4baSyz147064 		}
1792d62bc4baSyz147064 	}
1793d62bc4baSyz147064 
1794*e7801d59Ssowmini 	(void) snprintf(lbuf->link_name, sizeof (lbuf->link_name),
1795*e7801d59Ssowmini 	    "%s", link);
1796*e7801d59Ssowmini 	(void) dladm_class2str(class, lbuf->link_class);
1797d62bc4baSyz147064 	if (state->ls_flags == DLADM_OPT_ACTIVE) {
1798*e7801d59Ssowmini 		(void) snprintf(lbuf->link_mtu, sizeof (lbuf->link_mtu),
1799*e7801d59Ssowmini 		    "%d", mtu);
1800*e7801d59Ssowmini 		(void) get_linkstate(link, B_TRUE, lbuf->link_state);
1801d62bc4baSyz147064 	}
1802d62bc4baSyz147064 
1803*e7801d59Ssowmini 	status = print_link_topology(state, linkid, class, lbuf);
1804d62bc4baSyz147064 	if (status != DLADM_STATUS_OK)
1805d62bc4baSyz147064 		goto done;
1806d62bc4baSyz147064 
1807d62bc4baSyz147064 done:
1808d62bc4baSyz147064 	return (status);
1809d62bc4baSyz147064 }
1810d62bc4baSyz147064 
1811*e7801d59Ssowmini 
1812d62bc4baSyz147064 static int
1813d62bc4baSyz147064 show_link(datalink_id_t linkid, void *arg)
1814d62bc4baSyz147064 {
1815*e7801d59Ssowmini 	show_state_t		*state = (show_state_t *)arg;
1816d62bc4baSyz147064 	dladm_status_t		status;
1817*e7801d59Ssowmini 	link_fields_buf_t	lbuf;
1818d62bc4baSyz147064 
1819*e7801d59Ssowmini 	/*
1820*e7801d59Ssowmini 	 * first get all the link attributes into lbuf;
1821*e7801d59Ssowmini 	 */
1822*e7801d59Ssowmini 	status = print_link(state, linkid, &lbuf);
1823*e7801d59Ssowmini 
1824d62bc4baSyz147064 	if (status != DLADM_STATUS_OK)
1825d62bc4baSyz147064 		goto done;
1826*e7801d59Ssowmini 
1827*e7801d59Ssowmini 	if (!state->ls_parseable && !state->ls_printheader) {
1828*e7801d59Ssowmini 		print_header(&state->ls_print);
1829*e7801d59Ssowmini 		state->ls_printheader = B_TRUE;
1830*e7801d59Ssowmini 	}
1831*e7801d59Ssowmini 
1832*e7801d59Ssowmini 	dladm_print_output(&state->ls_print, state->ls_parseable,
1833*e7801d59Ssowmini 	    dladm_print_field, (void *)&lbuf);
1834d62bc4baSyz147064 
1835d62bc4baSyz147064 done:
1836d62bc4baSyz147064 	state->ls_status = status;
1837d62bc4baSyz147064 	return (DLADM_WALK_CONTINUE);
1838d62bc4baSyz147064 }
1839d62bc4baSyz147064 
1840d62bc4baSyz147064 static int
1841d62bc4baSyz147064 show_link_stats(datalink_id_t linkid, void *arg)
1842d62bc4baSyz147064 {
1843*e7801d59Ssowmini 	char link[DLPI_LINKNAME_MAX];
1844d62bc4baSyz147064 	datalink_class_t class;
1845*e7801d59Ssowmini 	show_state_t *state = (show_state_t *)arg;
18467c478bd9Sstevel@tonic-gate 	pktsum_t stats, diff_stats;
1847d62bc4baSyz147064 	dladm_phys_attr_t dpa;
18487c478bd9Sstevel@tonic-gate 
18497c478bd9Sstevel@tonic-gate 	if (state->ls_firstonly) {
18507c478bd9Sstevel@tonic-gate 		if (state->ls_donefirst)
1851d62bc4baSyz147064 			return (DLADM_WALK_CONTINUE);
18527c478bd9Sstevel@tonic-gate 		state->ls_donefirst = B_TRUE;
18537c478bd9Sstevel@tonic-gate 	} else {
18547c478bd9Sstevel@tonic-gate 		bzero(&state->ls_prevstats, sizeof (state->ls_prevstats));
18557c478bd9Sstevel@tonic-gate 	}
18567c478bd9Sstevel@tonic-gate 
1857d62bc4baSyz147064 	if (dladm_datalink_id2info(linkid, NULL, &class, NULL, link,
1858*e7801d59Ssowmini 	    DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) {
1859d62bc4baSyz147064 		return (DLADM_WALK_CONTINUE);
1860d62bc4baSyz147064 	}
1861d62bc4baSyz147064 
1862d62bc4baSyz147064 	if (class == DATALINK_CLASS_PHYS) {
1863d62bc4baSyz147064 		if (dladm_phys_info(linkid, &dpa, DLADM_OPT_ACTIVE) !=
1864d62bc4baSyz147064 		    DLADM_STATUS_OK) {
1865d62bc4baSyz147064 			return (DLADM_WALK_CONTINUE);
1866d62bc4baSyz147064 		}
1867d62bc4baSyz147064 		if (dpa.dp_novanity)
1868d62bc4baSyz147064 			get_mac_stats(dpa.dp_dev, &stats);
1869d62bc4baSyz147064 		else
1870d62bc4baSyz147064 			get_link_stats(link, &stats);
1871d62bc4baSyz147064 	} else {
1872d62bc4baSyz147064 		get_link_stats(link, &stats);
1873d62bc4baSyz147064 	}
18747c478bd9Sstevel@tonic-gate 	stats_diff(&diff_stats, &stats, &state->ls_prevstats);
18757c478bd9Sstevel@tonic-gate 
1876d62bc4baSyz147064 	(void) printf("%-12s", link);
1877d62bc4baSyz147064 	(void) printf("%-10llu", diff_stats.ipackets);
18787c478bd9Sstevel@tonic-gate 	(void) printf("%-12llu", diff_stats.rbytes);
18797c478bd9Sstevel@tonic-gate 	(void) printf("%-8u", diff_stats.ierrors);
18807c478bd9Sstevel@tonic-gate 	(void) printf("%-10llu", diff_stats.opackets);
18817c478bd9Sstevel@tonic-gate 	(void) printf("%-12llu", diff_stats.obytes);
18827c478bd9Sstevel@tonic-gate 	(void) printf("%-8u\n", diff_stats.oerrors);
18837c478bd9Sstevel@tonic-gate 
18847c478bd9Sstevel@tonic-gate 	state->ls_prevstats = stats;
1885d62bc4baSyz147064 	return (DLADM_WALK_CONTINUE);
18867c478bd9Sstevel@tonic-gate }
18877c478bd9Sstevel@tonic-gate 
1888d62bc4baSyz147064 
1889d62bc4baSyz147064 static dladm_status_t
1890d62bc4baSyz147064 print_aggr_info(show_grp_state_t *state, const char *link,
1891*e7801d59Ssowmini     dladm_aggr_grp_attr_t *ginfop)
1892d62bc4baSyz147064 {
1893d62bc4baSyz147064 	char			addr_str[ETHERADDRL * 3];
1894*e7801d59Ssowmini 	laggr_fields_buf_t	lbuf;
1895d62bc4baSyz147064 
1896*e7801d59Ssowmini 	(void) snprintf(lbuf.laggr_name, sizeof (lbuf.laggr_name),
1897*e7801d59Ssowmini 	    "%s", link);
1898*e7801d59Ssowmini 
1899*e7801d59Ssowmini 	(void) dladm_aggr_policy2str(ginfop->lg_policy,
1900*e7801d59Ssowmini 	    lbuf.laggr_policy);
1901d62bc4baSyz147064 
1902d62bc4baSyz147064 	if (ginfop->lg_mac_fixed) {
1903d62bc4baSyz147064 		(void) dladm_aggr_macaddr2str(ginfop->lg_mac, addr_str);
1904*e7801d59Ssowmini 		(void) snprintf(lbuf.laggr_addrpolicy,
1905*e7801d59Ssowmini 		    sizeof (lbuf.laggr_addrpolicy), "fixed (%s)", addr_str);
1906d62bc4baSyz147064 	} else {
1907*e7801d59Ssowmini 		(void) snprintf(lbuf.laggr_addrpolicy,
1908*e7801d59Ssowmini 		    sizeof (lbuf.laggr_addrpolicy), "auto");
1909d62bc4baSyz147064 	}
1910d62bc4baSyz147064 
1911d62bc4baSyz147064 
1912*e7801d59Ssowmini 	(void) dladm_aggr_lacpmode2str(ginfop->lg_lacp_mode,
1913*e7801d59Ssowmini 	    lbuf.laggr_lacpactivity);
1914*e7801d59Ssowmini 	(void) dladm_aggr_lacptimer2str(ginfop->lg_lacp_timer,
1915*e7801d59Ssowmini 	    lbuf.laggr_lacptimer);
1916*e7801d59Ssowmini 	(void) snprintf(lbuf.laggr_flags, sizeof (lbuf.laggr_flags), "%c----",
1917d62bc4baSyz147064 	    ginfop->lg_force ? 'f' : '-');
1918*e7801d59Ssowmini 
1919*e7801d59Ssowmini 	if (!state->gs_parseable && !state->gs_printheader) {
1920*e7801d59Ssowmini 		print_header(&state->gs_print);
1921*e7801d59Ssowmini 		state->gs_printheader = B_TRUE;
1922d62bc4baSyz147064 	}
1923d62bc4baSyz147064 
1924*e7801d59Ssowmini 	dladm_print_output(&state->gs_print, state->gs_parseable,
1925*e7801d59Ssowmini 	    dladm_print_field, (void *)&lbuf);
1926*e7801d59Ssowmini 
1927d62bc4baSyz147064 	return (DLADM_STATUS_OK);
1928d62bc4baSyz147064 }
1929d62bc4baSyz147064 
1930*e7801d59Ssowmini static char *
1931*e7801d59Ssowmini print_xaggr_callback(print_field_t *pf, void *arg)
1932d62bc4baSyz147064 {
1933*e7801d59Ssowmini 	const laggr_args_t 	*l = arg;
1934*e7801d59Ssowmini 	int 			portnum;
1935*e7801d59Ssowmini 	static char 		buf[DLADM_STRSIZE];
1936*e7801d59Ssowmini 	boolean_t		is_port = (l->laggr_lport >= 0);
1937*e7801d59Ssowmini 	dladm_aggr_port_attr_t *portp;
1938d62bc4baSyz147064 	dladm_phys_attr_t	dpa;
1939*e7801d59Ssowmini 	dladm_status_t		*stat, status;
1940d62bc4baSyz147064 
1941*e7801d59Ssowmini 	stat = l->laggr_status;
1942*e7801d59Ssowmini 	*stat = DLADM_STATUS_OK;
1943d62bc4baSyz147064 
1944*e7801d59Ssowmini 	if (is_port) {
1945*e7801d59Ssowmini 		portnum = l->laggr_lport;
1946*e7801d59Ssowmini 		portp = &(l->laggr_ginfop->lg_ports[portnum]);
1947*e7801d59Ssowmini 		if ((status = dladm_datalink_id2info(portp->lp_linkid,
1948*e7801d59Ssowmini 		    NULL, NULL, NULL, buf, sizeof (buf))) !=
1949*e7801d59Ssowmini 		    DLADM_STATUS_OK) {
1950*e7801d59Ssowmini 			goto err;
1951d62bc4baSyz147064 		}
1952d62bc4baSyz147064 		if ((status = dladm_phys_info(portp->lp_linkid, &dpa,
1953d62bc4baSyz147064 		    DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) {
1954*e7801d59Ssowmini 			goto err;
1955*e7801d59Ssowmini 		}
1956d62bc4baSyz147064 	}
1957d62bc4baSyz147064 
1958*e7801d59Ssowmini 	switch (pf->pf_index) {
1959*e7801d59Ssowmini 	case AGGR_X_LINK:
1960*e7801d59Ssowmini 		(void) snprintf(buf, sizeof (buf), "%s",
1961*e7801d59Ssowmini 		    (is_port && !l->laggr_parseable ? " " : l->laggr_link));
1962*e7801d59Ssowmini 		break;
1963*e7801d59Ssowmini 	case AGGR_X_PORT:
1964*e7801d59Ssowmini 		if (is_port)
1965*e7801d59Ssowmini 			break;
1966*e7801d59Ssowmini 		return ("");
1967*e7801d59Ssowmini 		break;
1968d62bc4baSyz147064 
1969*e7801d59Ssowmini 	case AGGR_X_SPEED:
1970*e7801d59Ssowmini 		if (is_port) {
1971*e7801d59Ssowmini 			(void) snprintf(buf, sizeof (buf), "%uMb",
1972*e7801d59Ssowmini 			    (uint_t)((get_ifspeed(dpa.dp_dev,
1973*e7801d59Ssowmini 			    B_FALSE)) / 1000000ull));
1974*e7801d59Ssowmini 		} else {
1975*e7801d59Ssowmini 			(void) snprintf(buf, sizeof (buf), "%uMb",
1976*e7801d59Ssowmini 			    (uint_t)((get_ifspeed(l->laggr_link,
1977*e7801d59Ssowmini 			    B_TRUE)) / 1000000ull));
1978*e7801d59Ssowmini 		}
1979*e7801d59Ssowmini 		break;
1980*e7801d59Ssowmini 
1981*e7801d59Ssowmini 	case AGGR_X_DUPLEX:
1982*e7801d59Ssowmini 		if (is_port)
1983*e7801d59Ssowmini 			(void) get_linkduplex(dpa.dp_dev, B_FALSE, buf);
1984d62bc4baSyz147064 		else
1985*e7801d59Ssowmini 			(void) get_linkduplex(l->laggr_link, B_TRUE, buf);
1986*e7801d59Ssowmini 		break;
1987d62bc4baSyz147064 
1988*e7801d59Ssowmini 	case AGGR_X_STATE:
1989*e7801d59Ssowmini 		if (is_port) {
1990d62bc4baSyz147064 			(void) dladm_aggr_portstate2str(
1991*e7801d59Ssowmini 			    portp->lp_state, buf);
1992d62bc4baSyz147064 		} else {
1993*e7801d59Ssowmini 			return (STR_UNDEF_VAL);
1994d62bc4baSyz147064 		}
1995*e7801d59Ssowmini 		break;
1996*e7801d59Ssowmini 	case AGGR_X_ADDRESS:
1997*e7801d59Ssowmini 		(void) dladm_aggr_macaddr2str(
1998*e7801d59Ssowmini 		    (is_port ? portp->lp_mac : l->laggr_ginfop->lg_mac),
1999*e7801d59Ssowmini 		    buf);
2000*e7801d59Ssowmini 		break;
2001*e7801d59Ssowmini 
2002*e7801d59Ssowmini 	case AGGR_X_PORTSTATE:
2003*e7801d59Ssowmini 		(void) snprintf(buf, sizeof (buf), "%s",
2004*e7801d59Ssowmini 		    (is_port ? dladm_aggr_portstate2str(portp->lp_state, buf):
2005*e7801d59Ssowmini 		    (l->laggr_parseable ? "" : STR_UNDEF_VAL)));
2006*e7801d59Ssowmini 		break;
2007*e7801d59Ssowmini 	}
2008*e7801d59Ssowmini 	return (buf);
2009*e7801d59Ssowmini 
2010*e7801d59Ssowmini err:
2011*e7801d59Ssowmini 	*stat = status;
2012*e7801d59Ssowmini 	buf[0] = '\0';
2013*e7801d59Ssowmini 	return (buf);
2014*e7801d59Ssowmini }
2015*e7801d59Ssowmini 
2016*e7801d59Ssowmini static dladm_status_t
2017*e7801d59Ssowmini print_aggr_extended(show_grp_state_t *state, const char *link,
2018*e7801d59Ssowmini     dladm_aggr_grp_attr_t *ginfop)
2019*e7801d59Ssowmini {
2020*e7801d59Ssowmini 	int			i;
2021*e7801d59Ssowmini 	dladm_status_t		status;
2022*e7801d59Ssowmini 	laggr_args_t		largs;
2023*e7801d59Ssowmini 
2024*e7801d59Ssowmini 	if (!state->gs_parseable && !state->gs_printheader) {
2025*e7801d59Ssowmini 		print_header(&state->gs_print);
2026*e7801d59Ssowmini 		state->gs_printheader = B_TRUE;
2027*e7801d59Ssowmini 	}
2028*e7801d59Ssowmini 
2029*e7801d59Ssowmini 	largs.laggr_lport = -1;
2030*e7801d59Ssowmini 	largs.laggr_link = link;
2031*e7801d59Ssowmini 	largs.laggr_ginfop = ginfop;
2032*e7801d59Ssowmini 	largs.laggr_status = &status;
2033*e7801d59Ssowmini 	largs.laggr_parseable = state->gs_parseable;
2034*e7801d59Ssowmini 
2035*e7801d59Ssowmini 	dladm_print_output(&state->gs_print, state->gs_parseable,
2036*e7801d59Ssowmini 	    print_xaggr_callback, &largs);
2037*e7801d59Ssowmini 
2038*e7801d59Ssowmini 	if (status != DLADM_STATUS_OK)
2039*e7801d59Ssowmini 		goto done;
2040*e7801d59Ssowmini 
2041*e7801d59Ssowmini 	for (i = 0; i < ginfop->lg_nports; i++) {
2042*e7801d59Ssowmini 		largs.laggr_lport = i;
2043*e7801d59Ssowmini 		dladm_print_output(&state->gs_print, state->gs_parseable,
2044*e7801d59Ssowmini 		    print_xaggr_callback, &largs);
2045*e7801d59Ssowmini 		if (status != DLADM_STATUS_OK)
2046*e7801d59Ssowmini 			goto done;
2047d62bc4baSyz147064 	}
2048d62bc4baSyz147064 
2049d62bc4baSyz147064 	status = DLADM_STATUS_OK;
2050d62bc4baSyz147064 done:
2051d62bc4baSyz147064 	return (status);
2052d62bc4baSyz147064 }
2053d62bc4baSyz147064 
2054*e7801d59Ssowmini 
2055*e7801d59Ssowmini static char *
2056*e7801d59Ssowmini print_lacp_callback(print_field_t *pf, void *arg)
2057*e7801d59Ssowmini {
2058*e7801d59Ssowmini 	const laggr_args_t	*l = arg;
2059*e7801d59Ssowmini 	int			portnum;
2060*e7801d59Ssowmini 	static char		buf[DLADM_STRSIZE];
2061*e7801d59Ssowmini 	boolean_t		is_port = (l->laggr_lport >= 0);
2062*e7801d59Ssowmini 	dladm_aggr_port_attr_t	*portp;
2063*e7801d59Ssowmini 	dladm_status_t		*stat, status;
2064*e7801d59Ssowmini 	aggr_lacp_state_t	*lstate;
2065*e7801d59Ssowmini 
2066*e7801d59Ssowmini 	if (!is_port) {
2067*e7801d59Ssowmini 		return (NULL); /* cannot happen! */
2068*e7801d59Ssowmini 	}
2069*e7801d59Ssowmini 
2070*e7801d59Ssowmini 	stat = l->laggr_status;
2071*e7801d59Ssowmini 
2072*e7801d59Ssowmini 	portnum = l->laggr_lport;
2073*e7801d59Ssowmini 	portp = &(l->laggr_ginfop->lg_ports[portnum]);
2074*e7801d59Ssowmini 	if ((status = dladm_datalink_id2info(portp->lp_linkid,
2075*e7801d59Ssowmini 	    NULL, NULL, NULL, buf, sizeof (buf))) != DLADM_STATUS_OK) {
2076*e7801d59Ssowmini 			goto err;
2077*e7801d59Ssowmini 	}
2078*e7801d59Ssowmini 	lstate = &(portp->lp_lacp_state);
2079*e7801d59Ssowmini 
2080*e7801d59Ssowmini 	switch (pf->pf_index) {
2081*e7801d59Ssowmini 	case AGGR_L_LINK:
2082*e7801d59Ssowmini 		(void) snprintf(buf, sizeof (buf), "%s",
2083*e7801d59Ssowmini 		    (portnum > 0 ? "" : l->laggr_link));
2084*e7801d59Ssowmini 		break;
2085*e7801d59Ssowmini 
2086*e7801d59Ssowmini 	case AGGR_L_PORT:
2087*e7801d59Ssowmini 		break;
2088*e7801d59Ssowmini 
2089*e7801d59Ssowmini 	case AGGR_L_AGGREGATABLE:
2090*e7801d59Ssowmini 		(void) snprintf(buf, sizeof (buf), "%s",
2091*e7801d59Ssowmini 		    (lstate->bit.aggregation ? "yes" : "no"));
2092*e7801d59Ssowmini 		break;
2093*e7801d59Ssowmini 
2094*e7801d59Ssowmini 	case AGGR_L_SYNC:
2095*e7801d59Ssowmini 		(void) snprintf(buf, sizeof (buf), "%s",
2096*e7801d59Ssowmini 		    (lstate->bit.sync ? "yes" : "no"));
2097*e7801d59Ssowmini 		break;
2098*e7801d59Ssowmini 
2099*e7801d59Ssowmini 	case AGGR_L_COLL:
2100*e7801d59Ssowmini 		(void) snprintf(buf, sizeof (buf), "%s",
2101*e7801d59Ssowmini 		    (lstate->bit.collecting ? "yes" : "no"));
2102*e7801d59Ssowmini 		break;
2103*e7801d59Ssowmini 
2104*e7801d59Ssowmini 	case AGGR_L_DIST:
2105*e7801d59Ssowmini 		(void) snprintf(buf, sizeof (buf), "%s",
2106*e7801d59Ssowmini 		    (lstate->bit.distributing ? "yes" : "no"));
2107*e7801d59Ssowmini 		break;
2108*e7801d59Ssowmini 
2109*e7801d59Ssowmini 	case AGGR_L_DEFAULTED:
2110*e7801d59Ssowmini 		(void) snprintf(buf, sizeof (buf), "%s",
2111*e7801d59Ssowmini 		    (lstate->bit.defaulted ? "yes" : "no"));
2112*e7801d59Ssowmini 		break;
2113*e7801d59Ssowmini 
2114*e7801d59Ssowmini 	case AGGR_L_EXPIRED:
2115*e7801d59Ssowmini 		(void) snprintf(buf, sizeof (buf), "%s",
2116*e7801d59Ssowmini 		    (lstate->bit.expired ? "yes" : "no"));
2117*e7801d59Ssowmini 		break;
2118*e7801d59Ssowmini 	}
2119*e7801d59Ssowmini 
2120*e7801d59Ssowmini 	*stat = DLADM_STATUS_OK;
2121*e7801d59Ssowmini 	return (buf);
2122*e7801d59Ssowmini 
2123*e7801d59Ssowmini err:
2124*e7801d59Ssowmini 	*stat = status;
2125*e7801d59Ssowmini 	buf[0] = '\0';
2126*e7801d59Ssowmini 	return (buf);
2127*e7801d59Ssowmini }
2128*e7801d59Ssowmini 
2129d62bc4baSyz147064 static dladm_status_t
2130d62bc4baSyz147064 print_aggr_lacp(show_grp_state_t *state, const char *link,
2131*e7801d59Ssowmini     dladm_aggr_grp_attr_t *ginfop)
2132d62bc4baSyz147064 {
2133d62bc4baSyz147064 	int		i;
2134d62bc4baSyz147064 	dladm_status_t	status;
2135*e7801d59Ssowmini 	laggr_args_t	largs;
2136d62bc4baSyz147064 
2137*e7801d59Ssowmini 	if (!state->gs_parseable && !state->gs_printheader) {
2138*e7801d59Ssowmini 		print_header(&state->gs_print);
2139*e7801d59Ssowmini 		state->gs_printheader = B_TRUE;
2140d62bc4baSyz147064 	}
2141d62bc4baSyz147064 
2142*e7801d59Ssowmini 	largs.laggr_link = link;
2143*e7801d59Ssowmini 	largs.laggr_ginfop = ginfop;
2144*e7801d59Ssowmini 	largs.laggr_status = &status;
2145d62bc4baSyz147064 
2146*e7801d59Ssowmini 	for (i = 0; i < ginfop->lg_nports; i++) {
2147*e7801d59Ssowmini 		largs.laggr_lport = i;
2148*e7801d59Ssowmini 		dladm_print_output(&state->gs_print, state->gs_parseable,
2149*e7801d59Ssowmini 		    print_lacp_callback, &largs);
2150d62bc4baSyz147064 		if (status != DLADM_STATUS_OK)
2151d62bc4baSyz147064 			goto done;
2152d62bc4baSyz147064 	}
2153d62bc4baSyz147064 
2154d62bc4baSyz147064 	status = DLADM_STATUS_OK;
2155d62bc4baSyz147064 done:
2156d62bc4baSyz147064 	return (status);
2157d62bc4baSyz147064 }
2158d62bc4baSyz147064 
2159*e7801d59Ssowmini static char *
2160*e7801d59Ssowmini print_aggr_stats_callback(print_field_t *pf, void *arg)
2161*e7801d59Ssowmini {
2162*e7801d59Ssowmini 	const laggr_args_t	*l = arg;
2163*e7801d59Ssowmini 	int 			portnum;
2164*e7801d59Ssowmini 	static char		buf[DLADM_STRSIZE];
2165*e7801d59Ssowmini 	boolean_t		is_port = (l->laggr_lport >= 0);
2166*e7801d59Ssowmini 	dladm_aggr_port_attr_t	*portp;
2167*e7801d59Ssowmini 	dladm_phys_attr_t	dpa;
2168*e7801d59Ssowmini 	dladm_status_t		*stat, status;
2169*e7801d59Ssowmini 	pktsum_t		port_stat, diff_stats;
2170*e7801d59Ssowmini 
2171*e7801d59Ssowmini 	stat = l->laggr_status;
2172*e7801d59Ssowmini 	*stat = DLADM_STATUS_OK;
2173*e7801d59Ssowmini 
2174*e7801d59Ssowmini 	if (is_port) {
2175*e7801d59Ssowmini 		portnum = l->laggr_lport;
2176*e7801d59Ssowmini 		portp = &(l->laggr_ginfop->lg_ports[portnum]);
2177*e7801d59Ssowmini 		if ((status = dladm_phys_info(portp->lp_linkid, &dpa,
2178*e7801d59Ssowmini 		    DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) {
2179*e7801d59Ssowmini 			goto err;
2180*e7801d59Ssowmini 		}
2181*e7801d59Ssowmini 
2182*e7801d59Ssowmini 		get_mac_stats(dpa.dp_dev, &port_stat);
2183*e7801d59Ssowmini 
2184*e7801d59Ssowmini 		if ((status = dladm_datalink_id2info(portp->lp_linkid, NULL,
2185*e7801d59Ssowmini 		    NULL, NULL, buf, sizeof (buf))) != DLADM_STATUS_OK) {
2186*e7801d59Ssowmini 			goto err;
2187*e7801d59Ssowmini 		}
2188*e7801d59Ssowmini 
2189*e7801d59Ssowmini 		stats_diff(&diff_stats, &port_stat, l->laggr_prevstats);
2190*e7801d59Ssowmini 	}
2191*e7801d59Ssowmini 
2192*e7801d59Ssowmini 	switch (pf->pf_index) {
2193*e7801d59Ssowmini 	case AGGR_S_LINK:
2194*e7801d59Ssowmini 		(void) snprintf(buf, sizeof (buf), "%s",
2195*e7801d59Ssowmini 		    (is_port ? "" : l->laggr_link));
2196*e7801d59Ssowmini 		break;
2197*e7801d59Ssowmini 	case AGGR_S_PORT:
2198*e7801d59Ssowmini 		if (is_port)
2199*e7801d59Ssowmini 			break;
2200*e7801d59Ssowmini 		return (STR_UNDEF_VAL);
2201*e7801d59Ssowmini 		break;
2202*e7801d59Ssowmini 
2203*e7801d59Ssowmini 	case AGGR_S_IPKTS:
2204*e7801d59Ssowmini 		if (is_port) {
2205*e7801d59Ssowmini 			(void) snprintf(buf, sizeof (buf), "%llu",
2206*e7801d59Ssowmini 			    diff_stats.ipackets);
2207*e7801d59Ssowmini 		} else {
2208*e7801d59Ssowmini 			(void) snprintf(buf, sizeof (buf), "%llu",
2209*e7801d59Ssowmini 			    l->laggr_pktsumtot->ipackets);
2210*e7801d59Ssowmini 		}
2211*e7801d59Ssowmini 		break;
2212*e7801d59Ssowmini 
2213*e7801d59Ssowmini 	case AGGR_S_RBYTES:
2214*e7801d59Ssowmini 		if (is_port) {
2215*e7801d59Ssowmini 			(void) snprintf(buf, sizeof (buf), "%llu",
2216*e7801d59Ssowmini 			    diff_stats.rbytes);
2217*e7801d59Ssowmini 		} else {
2218*e7801d59Ssowmini 			(void) snprintf(buf, sizeof (buf), "%llu",
2219*e7801d59Ssowmini 			    l->laggr_pktsumtot->rbytes);
2220*e7801d59Ssowmini 		}
2221*e7801d59Ssowmini 		break;
2222*e7801d59Ssowmini 
2223*e7801d59Ssowmini 	case AGGR_S_OPKTS:
2224*e7801d59Ssowmini 		if (is_port) {
2225*e7801d59Ssowmini 			(void) snprintf(buf, sizeof (buf), "%llu",
2226*e7801d59Ssowmini 			    diff_stats.opackets);
2227*e7801d59Ssowmini 		} else {
2228*e7801d59Ssowmini 			(void) snprintf(buf, sizeof (buf), "%llu",
2229*e7801d59Ssowmini 			    l->laggr_pktsumtot->opackets);
2230*e7801d59Ssowmini 		}
2231*e7801d59Ssowmini 		break;
2232*e7801d59Ssowmini 	case AGGR_S_OBYTES:
2233*e7801d59Ssowmini 		if (is_port) {
2234*e7801d59Ssowmini 			(void) snprintf(buf, sizeof (buf), "%llu",
2235*e7801d59Ssowmini 			    diff_stats.obytes);
2236*e7801d59Ssowmini 		} else {
2237*e7801d59Ssowmini 			(void) snprintf(buf, sizeof (buf), "%llu",
2238*e7801d59Ssowmini 			    l->laggr_pktsumtot->obytes);
2239*e7801d59Ssowmini 
2240*e7801d59Ssowmini 		}
2241*e7801d59Ssowmini 		break;
2242*e7801d59Ssowmini 
2243*e7801d59Ssowmini 	case AGGR_S_IPKTDIST:
2244*e7801d59Ssowmini 		if (is_port) {
2245*e7801d59Ssowmini 			(void) snprintf(buf, sizeof (buf), "%-6.1f",
2246*e7801d59Ssowmini 			    (double)diff_stats.opackets/
2247*e7801d59Ssowmini 			    (double)l->laggr_pktsumtot->ipackets * 100);
2248*e7801d59Ssowmini 		} else {
2249*e7801d59Ssowmini 			return (STR_UNDEF_VAL);
2250*e7801d59Ssowmini 		}
2251*e7801d59Ssowmini 		break;
2252*e7801d59Ssowmini 	case AGGR_S_OPKTDIST:
2253*e7801d59Ssowmini 		if (is_port) {
2254*e7801d59Ssowmini 			(void) snprintf(buf, sizeof (buf), "%-6.1f",
2255*e7801d59Ssowmini 			    (double)diff_stats.opackets/
2256*e7801d59Ssowmini 			    (double)l->laggr_pktsumtot->opackets * 100);
2257*e7801d59Ssowmini 		} else {
2258*e7801d59Ssowmini 			(void) sprintf(buf, STR_UNDEF_VAL);
2259*e7801d59Ssowmini 		}
2260*e7801d59Ssowmini 		break;
2261*e7801d59Ssowmini 	}
2262*e7801d59Ssowmini 	return (buf);
2263*e7801d59Ssowmini 
2264*e7801d59Ssowmini err:
2265*e7801d59Ssowmini 	*stat = status;
2266*e7801d59Ssowmini 	buf[0] = '\0';
2267*e7801d59Ssowmini 	return (buf);
2268*e7801d59Ssowmini }
2269*e7801d59Ssowmini 
2270d62bc4baSyz147064 static dladm_status_t
2271d62bc4baSyz147064 print_aggr_stats(show_grp_state_t *state, const char *link,
2272*e7801d59Ssowmini     dladm_aggr_grp_attr_t *ginfop)
2273d62bc4baSyz147064 {
2274d62bc4baSyz147064 	dladm_phys_attr_t	dpa;
2275d62bc4baSyz147064 	dladm_aggr_port_attr_t	*portp;
2276d62bc4baSyz147064 	pktsum_t		pktsumtot, port_stat;
2277d62bc4baSyz147064 	dladm_status_t		status;
2278d62bc4baSyz147064 	int			i;
2279*e7801d59Ssowmini 	laggr_args_t		largs;
22807c478bd9Sstevel@tonic-gate 
22817c478bd9Sstevel@tonic-gate 	/* sum the ports statistics */
22827c478bd9Sstevel@tonic-gate 	bzero(&pktsumtot, sizeof (pktsumtot));
2283d62bc4baSyz147064 
2284d62bc4baSyz147064 	for (i = 0; i < ginfop->lg_nports; i++) {
2285d62bc4baSyz147064 
2286d62bc4baSyz147064 		portp = &(ginfop->lg_ports[i]);
2287d62bc4baSyz147064 		if ((status = dladm_phys_info(portp->lp_linkid, &dpa,
2288d62bc4baSyz147064 		    DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) {
2289d62bc4baSyz147064 			goto done;
22907c478bd9Sstevel@tonic-gate 		}
22917c478bd9Sstevel@tonic-gate 
2292d62bc4baSyz147064 		get_mac_stats(dpa.dp_dev, &port_stat);
2293d62bc4baSyz147064 		stats_total(&pktsumtot, &port_stat, &state->gs_prevstats[i]);
22947c478bd9Sstevel@tonic-gate 	}
22957c478bd9Sstevel@tonic-gate 
2296*e7801d59Ssowmini 	if (!state->gs_parseable && !state->gs_printheader) {
2297*e7801d59Ssowmini 		print_header(&state->gs_print);
2298*e7801d59Ssowmini 		state->gs_printheader = B_TRUE;
2299*e7801d59Ssowmini 	}
2300*e7801d59Ssowmini 
2301*e7801d59Ssowmini 	largs.laggr_lport = -1;
2302*e7801d59Ssowmini 	largs.laggr_link = link;
2303*e7801d59Ssowmini 	largs.laggr_ginfop = ginfop;
2304*e7801d59Ssowmini 	largs.laggr_status = &status;
2305*e7801d59Ssowmini 	largs.laggr_pktsumtot = &pktsumtot;
2306*e7801d59Ssowmini 
2307*e7801d59Ssowmini 	dladm_print_output(&state->gs_print, state->gs_parseable,
2308*e7801d59Ssowmini 	    print_aggr_stats_callback, &largs);
2309*e7801d59Ssowmini 
2310*e7801d59Ssowmini 	if (status != DLADM_STATUS_OK)
2311*e7801d59Ssowmini 		goto done;
2312d62bc4baSyz147064 
2313d62bc4baSyz147064 	for (i = 0; i < ginfop->lg_nports; i++) {
2314*e7801d59Ssowmini 		largs.laggr_lport = i;
2315*e7801d59Ssowmini 		largs.laggr_prevstats = &state->gs_prevstats[i];
2316*e7801d59Ssowmini 		dladm_print_output(&state->gs_print, state->gs_parseable,
2317*e7801d59Ssowmini 		    print_aggr_stats_callback, &largs);
2318*e7801d59Ssowmini 		if (status != DLADM_STATUS_OK)
2319d62bc4baSyz147064 			goto done;
2320d62bc4baSyz147064 	}
2321d62bc4baSyz147064 
2322d62bc4baSyz147064 	status = DLADM_STATUS_OK;
2323d62bc4baSyz147064 done:
2324d62bc4baSyz147064 	return (status);
2325d62bc4baSyz147064 }
2326d62bc4baSyz147064 
2327d62bc4baSyz147064 static dladm_status_t
2328*e7801d59Ssowmini print_aggr(show_grp_state_t *state, datalink_id_t linkid)
2329d62bc4baSyz147064 {
2330d62bc4baSyz147064 	char			link[MAXLINKNAMELEN];
2331d62bc4baSyz147064 	dladm_aggr_grp_attr_t	ginfo;
2332d62bc4baSyz147064 	uint32_t		flags;
2333d62bc4baSyz147064 	dladm_status_t		status;
2334d62bc4baSyz147064 
2335d62bc4baSyz147064 	if ((status = dladm_datalink_id2info(linkid, &flags, NULL, NULL, link,
2336*e7801d59Ssowmini 	    MAXLINKNAMELEN)) != DLADM_STATUS_OK) {
2337d62bc4baSyz147064 		return (status);
2338d62bc4baSyz147064 	}
2339d62bc4baSyz147064 
2340d62bc4baSyz147064 	if (!(state->gs_flags & flags))
2341d62bc4baSyz147064 		return (DLADM_STATUS_NOTFOUND);
2342d62bc4baSyz147064 
2343d62bc4baSyz147064 	status = dladm_aggr_info(linkid, &ginfo, state->gs_flags);
2344d62bc4baSyz147064 	if (status != DLADM_STATUS_OK)
2345d62bc4baSyz147064 		return (status);
2346d62bc4baSyz147064 
2347d62bc4baSyz147064 	if (state->gs_lacp)
2348*e7801d59Ssowmini 		status = print_aggr_lacp(state, link, &ginfo);
2349d62bc4baSyz147064 	else if (state->gs_extended)
2350*e7801d59Ssowmini 		status = print_aggr_extended(state, link, &ginfo);
2351d62bc4baSyz147064 	else if (state->gs_stats)
2352*e7801d59Ssowmini 		status = print_aggr_stats(state, link, &ginfo);
2353*e7801d59Ssowmini 	else {
2354*e7801d59Ssowmini 		status = print_aggr_info(state, link, &ginfo);
2355*e7801d59Ssowmini 	}
2356d62bc4baSyz147064 
2357d62bc4baSyz147064 done:
2358d62bc4baSyz147064 	free(ginfo.lg_ports);
2359d62bc4baSyz147064 	return (status);
2360d62bc4baSyz147064 }
2361d62bc4baSyz147064 
2362d62bc4baSyz147064 static int
2363d62bc4baSyz147064 show_aggr(datalink_id_t linkid, void *arg)
2364d62bc4baSyz147064 {
2365d62bc4baSyz147064 	show_grp_state_t	*state = arg;
2366d62bc4baSyz147064 	dladm_status_t		status;
2367d62bc4baSyz147064 
2368*e7801d59Ssowmini 	status = print_aggr(state, linkid);
2369d62bc4baSyz147064 	if (status != DLADM_STATUS_OK)
2370d62bc4baSyz147064 		goto done;
2371d62bc4baSyz147064 
2372d62bc4baSyz147064 done:
2373d62bc4baSyz147064 	state->gs_status = status;
2374d62bc4baSyz147064 	return (DLADM_WALK_CONTINUE);
23757c478bd9Sstevel@tonic-gate }
23767c478bd9Sstevel@tonic-gate 
2377*e7801d59Ssowmini static char *
2378*e7801d59Ssowmini print_dev(print_field_t *pf, void *arg)
23797c478bd9Sstevel@tonic-gate {
2380*e7801d59Ssowmini 	const char *dev = arg;
2381*e7801d59Ssowmini 	static char buf[DLADM_STRSIZE];
23827c478bd9Sstevel@tonic-gate 
2383*e7801d59Ssowmini 	switch (pf->pf_index) {
2384*e7801d59Ssowmini 	case DEV_LINK:
2385*e7801d59Ssowmini 		(void) snprintf(buf, sizeof (buf), "%s", dev);
23867c478bd9Sstevel@tonic-gate 		break;
2387*e7801d59Ssowmini 	case DEV_STATE:
2388*e7801d59Ssowmini 		(void) get_linkstate(dev, B_FALSE, buf);
2389*e7801d59Ssowmini 		break;
2390*e7801d59Ssowmini 	case DEV_SPEED:
2391*e7801d59Ssowmini 		(void) snprintf(buf, sizeof (buf), "%uMb",
2392*e7801d59Ssowmini 		    (unsigned int)(get_ifspeed(dev, B_FALSE) / 1000000ull));
2393*e7801d59Ssowmini 		break;
2394*e7801d59Ssowmini 	case DEV_DUPLEX:
2395*e7801d59Ssowmini 		(void) get_linkduplex(dev, B_FALSE, buf);
23967c478bd9Sstevel@tonic-gate 		break;
23977c478bd9Sstevel@tonic-gate 	default:
2398*e7801d59Ssowmini 		die("invalid index '%d'", pf->pf_index);
2399*e7801d59Ssowmini 		break;
24007c478bd9Sstevel@tonic-gate 	}
2401*e7801d59Ssowmini 	return (buf);
24027c478bd9Sstevel@tonic-gate }
24037c478bd9Sstevel@tonic-gate 
2404d62bc4baSyz147064 static int
2405d62bc4baSyz147064 show_dev(const char *dev, void *arg)
24067c478bd9Sstevel@tonic-gate {
2407d62bc4baSyz147064 	show_state_t	*state = arg;
24087c478bd9Sstevel@tonic-gate 
2409*e7801d59Ssowmini 	if (!state->ls_parseable && !state->ls_printheader) {
2410*e7801d59Ssowmini 		print_header(&state->ls_print);
2411*e7801d59Ssowmini 		state->ls_printheader = B_TRUE;
24127c478bd9Sstevel@tonic-gate 	}
24137c478bd9Sstevel@tonic-gate 
2414*e7801d59Ssowmini 	dladm_print_output(&state->ls_print, state->ls_parseable,
2415*e7801d59Ssowmini 	    print_dev, (void *)dev);
2416d62bc4baSyz147064 
2417d62bc4baSyz147064 	return (DLADM_WALK_CONTINUE);
2418d62bc4baSyz147064 }
2419d62bc4baSyz147064 
2420*e7801d59Ssowmini static char *
2421*e7801d59Ssowmini print_dev_stats(print_field_t *pf, void *arg)
2422*e7801d59Ssowmini {
2423*e7801d59Ssowmini 	dev_args_t *dargs = arg;
2424*e7801d59Ssowmini 	pktsum_t *diff_stats = dargs->devs_psum;
2425*e7801d59Ssowmini 	static char buf[DLADM_STRSIZE];
2426*e7801d59Ssowmini 
2427*e7801d59Ssowmini 	switch (pf->pf_index) {
2428*e7801d59Ssowmini 	case DEVS_LINK:
2429*e7801d59Ssowmini 		(void) snprintf(buf, sizeof (buf), "%s", dargs->devs_link);
2430*e7801d59Ssowmini 		break;
2431*e7801d59Ssowmini 	case DEVS_IPKTS:
2432*e7801d59Ssowmini 		(void) snprintf(buf, sizeof (buf), "%llu",
2433*e7801d59Ssowmini 		    diff_stats->ipackets);
2434*e7801d59Ssowmini 		break;
2435*e7801d59Ssowmini 	case DEVS_RBYTES:
2436*e7801d59Ssowmini 		(void) snprintf(buf, sizeof (buf), "%llu",
2437*e7801d59Ssowmini 		    diff_stats->rbytes);
2438*e7801d59Ssowmini 		break;
2439*e7801d59Ssowmini 	case DEVS_IERRORS:
2440*e7801d59Ssowmini 		(void) snprintf(buf, sizeof (buf), "%u",
2441*e7801d59Ssowmini 		    diff_stats->ierrors);
2442*e7801d59Ssowmini 		break;
2443*e7801d59Ssowmini 	case DEVS_OPKTS:
2444*e7801d59Ssowmini 		(void) snprintf(buf, sizeof (buf), "%llu",
2445*e7801d59Ssowmini 		    diff_stats->opackets);
2446*e7801d59Ssowmini 		break;
2447*e7801d59Ssowmini 	case DEVS_OBYTES:
2448*e7801d59Ssowmini 		(void) snprintf(buf, sizeof (buf), "%llu",
2449*e7801d59Ssowmini 		    diff_stats->obytes);
2450*e7801d59Ssowmini 		break;
2451*e7801d59Ssowmini 	case DEVS_OERRORS:
2452*e7801d59Ssowmini 		(void) snprintf(buf, sizeof (buf), "%u",
2453*e7801d59Ssowmini 		    diff_stats->oerrors);
2454*e7801d59Ssowmini 		break;
2455*e7801d59Ssowmini 	default:
2456*e7801d59Ssowmini 		die("invalid input");
2457*e7801d59Ssowmini 		break;
2458*e7801d59Ssowmini 	}
2459*e7801d59Ssowmini 	return (buf);
2460*e7801d59Ssowmini }
2461*e7801d59Ssowmini 
2462d62bc4baSyz147064 static int
2463d62bc4baSyz147064 show_dev_stats(const char *dev, void *arg)
24647c478bd9Sstevel@tonic-gate {
2465d62bc4baSyz147064 	show_state_t *state = arg;
24667c478bd9Sstevel@tonic-gate 	pktsum_t stats, diff_stats;
2467*e7801d59Ssowmini 	dev_args_t dargs;
24687c478bd9Sstevel@tonic-gate 
2469d62bc4baSyz147064 	if (state->ls_firstonly) {
2470d62bc4baSyz147064 		if (state->ls_donefirst)
2471d62bc4baSyz147064 			return (DLADM_WALK_CONTINUE);
2472d62bc4baSyz147064 		state->ls_donefirst = B_TRUE;
24737c478bd9Sstevel@tonic-gate 	} else {
2474d62bc4baSyz147064 		bzero(&state->ls_prevstats, sizeof (state->ls_prevstats));
24757c478bd9Sstevel@tonic-gate 	}
24767c478bd9Sstevel@tonic-gate 
2477ba2e4443Sseb 	get_mac_stats(dev, &stats);
2478d62bc4baSyz147064 	stats_diff(&diff_stats, &stats, &state->ls_prevstats);
24797c478bd9Sstevel@tonic-gate 
2480*e7801d59Ssowmini 	dargs.devs_link = (char *)dev;
2481*e7801d59Ssowmini 	dargs.devs_psum = &diff_stats;
2482*e7801d59Ssowmini 	dladm_print_output(&state->ls_print, state->ls_parseable,
2483*e7801d59Ssowmini 	    print_dev_stats, &dargs);
24847c478bd9Sstevel@tonic-gate 
2485d62bc4baSyz147064 	state->ls_prevstats = stats;
2486d62bc4baSyz147064 	return (DLADM_WALK_CONTINUE);
24877c478bd9Sstevel@tonic-gate }
24887c478bd9Sstevel@tonic-gate 
24897c478bd9Sstevel@tonic-gate static void
24907c478bd9Sstevel@tonic-gate do_show_link(int argc, char *argv[])
24917c478bd9Sstevel@tonic-gate {
24927c478bd9Sstevel@tonic-gate 	int		option;
24937c478bd9Sstevel@tonic-gate 	boolean_t	s_arg = B_FALSE;
24947c478bd9Sstevel@tonic-gate 	boolean_t	i_arg = B_FALSE;
2495d62bc4baSyz147064 	uint32_t	flags = DLADM_OPT_ACTIVE;
2496d62bc4baSyz147064 	boolean_t	p_arg = B_FALSE;
2497d62bc4baSyz147064 	datalink_id_t	linkid = DATALINK_ALL_LINKID;
249833343a97Smeem 	int		interval = 0;
2499d62bc4baSyz147064 	show_state_t	state;
2500d62bc4baSyz147064 	dladm_status_t	status;
2501*e7801d59Ssowmini 	boolean_t	o_arg = B_FALSE;
2502*e7801d59Ssowmini 	char		*fields_str = NULL;
2503*e7801d59Ssowmini 	print_field_t	**fields;
2504*e7801d59Ssowmini 	uint_t		nfields;
2505*e7801d59Ssowmini 	char		*all_active_fields = "link,class,mtu,state,over";
2506*e7801d59Ssowmini 	char		*all_inactive_fields = "link,class,over";
2507*e7801d59Ssowmini 
2508*e7801d59Ssowmini 	bzero(&state, sizeof (state));
25097c478bd9Sstevel@tonic-gate 
25107c478bd9Sstevel@tonic-gate 	opterr = 0;
2511*e7801d59Ssowmini 	while ((option = getopt_long(argc, argv, ":pPsi:o:",
2512d62bc4baSyz147064 	    show_lopts, NULL)) != -1) {
25137c478bd9Sstevel@tonic-gate 		switch (option) {
25147c478bd9Sstevel@tonic-gate 		case 'p':
2515d62bc4baSyz147064 			if (p_arg)
2516d62bc4baSyz147064 				die_optdup(option);
2517d62bc4baSyz147064 
2518d62bc4baSyz147064 			p_arg = B_TRUE;
25197c478bd9Sstevel@tonic-gate 			break;
25207c478bd9Sstevel@tonic-gate 		case 's':
252133343a97Smeem 			if (s_arg)
252233343a97Smeem 				die_optdup(option);
25237c478bd9Sstevel@tonic-gate 
25247c478bd9Sstevel@tonic-gate 			s_arg = B_TRUE;
25257c478bd9Sstevel@tonic-gate 			break;
2526d62bc4baSyz147064 		case 'P':
2527d62bc4baSyz147064 			if (flags != DLADM_OPT_ACTIVE)
2528d62bc4baSyz147064 				die_optdup(option);
2529d62bc4baSyz147064 
2530d62bc4baSyz147064 			flags = DLADM_OPT_PERSIST;
2531d62bc4baSyz147064 			break;
2532*e7801d59Ssowmini 		case 'o':
2533*e7801d59Ssowmini 			o_arg = B_TRUE;
2534*e7801d59Ssowmini 			fields_str = optarg;
2535*e7801d59Ssowmini 			break;
25367c478bd9Sstevel@tonic-gate 		case 'i':
253733343a97Smeem 			if (i_arg)
253833343a97Smeem 				die_optdup(option);
25397c478bd9Sstevel@tonic-gate 
25407c478bd9Sstevel@tonic-gate 			i_arg = B_TRUE;
254133343a97Smeem 			if (!str2int(optarg, &interval) || interval == 0)
254233343a97Smeem 				die("invalid interval value '%s'", optarg);
25437c478bd9Sstevel@tonic-gate 			break;
25447c478bd9Sstevel@tonic-gate 		default:
254533343a97Smeem 			die_opterr(optopt, option);
254633343a97Smeem 			break;
25477c478bd9Sstevel@tonic-gate 		}
25487c478bd9Sstevel@tonic-gate 	}
25497c478bd9Sstevel@tonic-gate 
255033343a97Smeem 	if (i_arg && !s_arg)
255133343a97Smeem 		die("the option -i can be used only with -s");
25527c478bd9Sstevel@tonic-gate 
2553d62bc4baSyz147064 	if (s_arg && (p_arg || flags != DLADM_OPT_ACTIVE))
2554d62bc4baSyz147064 		die("the option -%c cannot be used with -s", p_arg ? 'p' : 'P');
2555d62bc4baSyz147064 
25567c478bd9Sstevel@tonic-gate 	/* get link name (optional last argument) */
2557d62bc4baSyz147064 	if (optind == (argc-1)) {
2558d62bc4baSyz147064 		uint32_t	f;
2559d62bc4baSyz147064 
2560d62bc4baSyz147064 		if ((status = dladm_name2info(argv[optind], &linkid, &f,
2561d62bc4baSyz147064 		    NULL, NULL)) != DLADM_STATUS_OK) {
2562d62bc4baSyz147064 			die_dlerr(status, "link %s is not valid", argv[optind]);
2563d62bc4baSyz147064 		}
2564d62bc4baSyz147064 
2565d62bc4baSyz147064 		if (!(f & flags)) {
2566d62bc4baSyz147064 			die_dlerr(DLADM_STATUS_BADARG, "link %s is %s",
2567d62bc4baSyz147064 			    argv[optind], flags == DLADM_OPT_PERSIST ?
2568d62bc4baSyz147064 			    "a temporary link" : "temporarily removed");
2569d62bc4baSyz147064 		}
2570d62bc4baSyz147064 	} else if (optind != argc) {
25717c478bd9Sstevel@tonic-gate 		usage();
2572d62bc4baSyz147064 	}
25737c478bd9Sstevel@tonic-gate 
25747c478bd9Sstevel@tonic-gate 	if (s_arg) {
2575d62bc4baSyz147064 		link_stats(linkid, interval);
25767c478bd9Sstevel@tonic-gate 		return;
25777c478bd9Sstevel@tonic-gate 	}
25787c478bd9Sstevel@tonic-gate 
2579d62bc4baSyz147064 	state.ls_parseable = p_arg;
2580d62bc4baSyz147064 	state.ls_flags = flags;
2581d62bc4baSyz147064 	state.ls_donefirst = B_FALSE;
2582*e7801d59Ssowmini 
2583*e7801d59Ssowmini 	if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) {
2584*e7801d59Ssowmini 		if (state.ls_flags & DLADM_OPT_ACTIVE)
2585*e7801d59Ssowmini 			fields_str = all_active_fields;
2586*e7801d59Ssowmini 		else
2587*e7801d59Ssowmini 			fields_str = all_inactive_fields;
2588*e7801d59Ssowmini 	}
2589*e7801d59Ssowmini 
2590*e7801d59Ssowmini 
2591*e7801d59Ssowmini 	fields = parse_output_fields(fields_str, link_fields, DEV_LINK_FIELDS,
2592*e7801d59Ssowmini 	    CMD_TYPE_ANY, &nfields);
2593*e7801d59Ssowmini 
2594*e7801d59Ssowmini 	if (fields == NULL) {
2595*e7801d59Ssowmini 		die("invalid field(s) specified");
2596*e7801d59Ssowmini 		return;
2597*e7801d59Ssowmini 	}
2598*e7801d59Ssowmini 
2599*e7801d59Ssowmini 	state.ls_print.ps_fields = fields;
2600*e7801d59Ssowmini 	state.ls_print.ps_nfields = nfields;
2601*e7801d59Ssowmini 
2602d62bc4baSyz147064 	if (linkid == DATALINK_ALL_LINKID) {
2603d62bc4baSyz147064 		(void) dladm_walk_datalink_id(show_link, &state,
2604d62bc4baSyz147064 		    DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE, flags);
2605210db224Sericheng 	} else {
2606d62bc4baSyz147064 		(void) show_link(linkid, &state);
2607d62bc4baSyz147064 		if (state.ls_status != DLADM_STATUS_OK) {
2608d62bc4baSyz147064 			die_dlerr(state.ls_status, "failed to show link %s",
2609d62bc4baSyz147064 			    argv[optind]);
2610d62bc4baSyz147064 		}
26117c478bd9Sstevel@tonic-gate 	}
2612210db224Sericheng }
26137c478bd9Sstevel@tonic-gate 
26147c478bd9Sstevel@tonic-gate static void
26157c478bd9Sstevel@tonic-gate do_show_aggr(int argc, char *argv[])
26167c478bd9Sstevel@tonic-gate {
26177c478bd9Sstevel@tonic-gate 	boolean_t		L_arg = B_FALSE;
26187c478bd9Sstevel@tonic-gate 	boolean_t		s_arg = B_FALSE;
26197c478bd9Sstevel@tonic-gate 	boolean_t		i_arg = B_FALSE;
2620d62bc4baSyz147064 	boolean_t		p_arg = B_FALSE;
2621d62bc4baSyz147064 	boolean_t		x_arg = B_FALSE;
26227c478bd9Sstevel@tonic-gate 	show_grp_state_t	state;
2623d62bc4baSyz147064 	uint32_t		flags = DLADM_OPT_ACTIVE;
2624d62bc4baSyz147064 	datalink_id_t		linkid = DATALINK_ALL_LINKID;
2625d62bc4baSyz147064 	int			option;
262633343a97Smeem 	int			interval = 0;
2627d62bc4baSyz147064 	int			key;
2628d62bc4baSyz147064 	dladm_status_t		status;
2629*e7801d59Ssowmini 	boolean_t	o_arg = B_FALSE;
2630*e7801d59Ssowmini 	char		*fields_str = NULL;
2631*e7801d59Ssowmini 	print_field_t   **fields;
2632*e7801d59Ssowmini 	uint_t		nfields;
2633*e7801d59Ssowmini 	char		*all_fields =
2634*e7801d59Ssowmini 	    "link,policy,addrpolicy,lacpactivity,lacptimer,flags";
2635*e7801d59Ssowmini 	char		*all_lacp_fields =
2636*e7801d59Ssowmini 	    "link,port,aggregatable,sync,coll,dist,defaulted,expired";
2637*e7801d59Ssowmini 	char		*all_stats_fields =
2638*e7801d59Ssowmini 	    "link,port,ipackets,rbytes,opackets,obytes,ipktdist,opktdist";
2639*e7801d59Ssowmini 	char		*all_extended_fields =
2640*e7801d59Ssowmini 	    "link,port,speed,duplex,state,address,portstate";
2641*e7801d59Ssowmini 	print_field_t		*pf;
2642*e7801d59Ssowmini 	int			pfmax;
2643*e7801d59Ssowmini 
2644*e7801d59Ssowmini 	bzero(&state, sizeof (state));
26457c478bd9Sstevel@tonic-gate 
26467c478bd9Sstevel@tonic-gate 	opterr = 0;
2647*e7801d59Ssowmini 	while ((option = getopt_long(argc, argv, ":LpPxsi:o:",
2648d62bc4baSyz147064 	    show_lopts, NULL)) != -1) {
26497c478bd9Sstevel@tonic-gate 		switch (option) {
26507c478bd9Sstevel@tonic-gate 		case 'L':
265133343a97Smeem 			if (L_arg)
265233343a97Smeem 				die_optdup(option);
26537c478bd9Sstevel@tonic-gate 
26547c478bd9Sstevel@tonic-gate 			L_arg = B_TRUE;
26557c478bd9Sstevel@tonic-gate 			break;
26567c478bd9Sstevel@tonic-gate 		case 'p':
2657d62bc4baSyz147064 			if (p_arg)
2658d62bc4baSyz147064 				die_optdup(option);
2659d62bc4baSyz147064 
2660d62bc4baSyz147064 			p_arg = B_TRUE;
2661d62bc4baSyz147064 			break;
2662d62bc4baSyz147064 		case 'x':
2663d62bc4baSyz147064 			if (x_arg)
2664d62bc4baSyz147064 				die_optdup(option);
2665d62bc4baSyz147064 
2666d62bc4baSyz147064 			x_arg = B_TRUE;
2667d62bc4baSyz147064 			break;
2668d62bc4baSyz147064 		case 'P':
2669d62bc4baSyz147064 			if (flags != DLADM_OPT_ACTIVE)
2670d62bc4baSyz147064 				die_optdup(option);
2671d62bc4baSyz147064 
2672d62bc4baSyz147064 			flags = DLADM_OPT_PERSIST;
26737c478bd9Sstevel@tonic-gate 			break;
26747c478bd9Sstevel@tonic-gate 		case 's':
267533343a97Smeem 			if (s_arg)
267633343a97Smeem 				die_optdup(option);
26777c478bd9Sstevel@tonic-gate 
26787c478bd9Sstevel@tonic-gate 			s_arg = B_TRUE;
26797c478bd9Sstevel@tonic-gate 			break;
2680*e7801d59Ssowmini 		case 'o':
2681*e7801d59Ssowmini 			o_arg = B_TRUE;
2682*e7801d59Ssowmini 			fields_str = optarg;
2683*e7801d59Ssowmini 			break;
26847c478bd9Sstevel@tonic-gate 		case 'i':
268533343a97Smeem 			if (i_arg)
268633343a97Smeem 				die_optdup(option);
26877c478bd9Sstevel@tonic-gate 
26887c478bd9Sstevel@tonic-gate 			i_arg = B_TRUE;
268933343a97Smeem 			if (!str2int(optarg, &interval) || interval == 0)
269033343a97Smeem 				die("invalid interval value '%s'", optarg);
26917c478bd9Sstevel@tonic-gate 			break;
26927c478bd9Sstevel@tonic-gate 		default:
269333343a97Smeem 			die_opterr(optopt, option);
269433343a97Smeem 			break;
26957c478bd9Sstevel@tonic-gate 		}
26967c478bd9Sstevel@tonic-gate 	}
26977c478bd9Sstevel@tonic-gate 
269833343a97Smeem 	if (i_arg && !s_arg)
269933343a97Smeem 		die("the option -i can be used only with -s");
27007c478bd9Sstevel@tonic-gate 
2701d62bc4baSyz147064 	if (s_arg && (L_arg || p_arg || x_arg || flags != DLADM_OPT_ACTIVE)) {
2702d62bc4baSyz147064 		die("the option -%c cannot be used with -s",
2703d62bc4baSyz147064 		    L_arg ? 'L' : (p_arg ? 'p' : (x_arg ? 'x' : 'P')));
2704d62bc4baSyz147064 	}
2705d62bc4baSyz147064 
2706d62bc4baSyz147064 	if (L_arg && flags != DLADM_OPT_ACTIVE)
2707d62bc4baSyz147064 		die("the option -P cannot be used with -L");
2708d62bc4baSyz147064 
2709d62bc4baSyz147064 	if (x_arg && (L_arg || flags != DLADM_OPT_ACTIVE))
2710d62bc4baSyz147064 		die("the option -%c cannot be used with -x", L_arg ? 'L' : 'P');
2711d62bc4baSyz147064 
2712d62bc4baSyz147064 	/* get aggregation key or aggrname (optional last argument) */
27137c478bd9Sstevel@tonic-gate 	if (optind == (argc-1)) {
2714d62bc4baSyz147064 		if (!str2int(argv[optind], &key)) {
2715d62bc4baSyz147064 			status = dladm_name2info(argv[optind], &linkid, NULL,
2716d62bc4baSyz147064 			    NULL, NULL);
2717d62bc4baSyz147064 		} else {
2718d62bc4baSyz147064 			status = dladm_key2linkid((uint16_t)key,
2719d62bc4baSyz147064 			    &linkid, DLADM_OPT_ACTIVE);
2720d62bc4baSyz147064 		}
2721d62bc4baSyz147064 
2722d62bc4baSyz147064 		if (status != DLADM_STATUS_OK)
2723d62bc4baSyz147064 			die("non-existent aggregation '%s'", argv[optind]);
2724d62bc4baSyz147064 
27257c478bd9Sstevel@tonic-gate 	} else if (optind != argc) {
27267c478bd9Sstevel@tonic-gate 		usage();
27277c478bd9Sstevel@tonic-gate 	}
27287c478bd9Sstevel@tonic-gate 
2729d62bc4baSyz147064 	bzero(&state, sizeof (state));
2730d62bc4baSyz147064 	state.gs_lacp = L_arg;
2731d62bc4baSyz147064 	state.gs_stats = s_arg;
2732d62bc4baSyz147064 	state.gs_flags = flags;
2733d62bc4baSyz147064 	state.gs_parseable = p_arg;
2734d62bc4baSyz147064 	state.gs_extended = x_arg;
2735d62bc4baSyz147064 
2736*e7801d59Ssowmini 	if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) {
2737*e7801d59Ssowmini 		if (state.gs_lacp)
2738*e7801d59Ssowmini 			fields_str = all_lacp_fields;
2739*e7801d59Ssowmini 		else if (state.gs_stats)
2740*e7801d59Ssowmini 			fields_str = all_stats_fields;
2741*e7801d59Ssowmini 		else if (state.gs_extended)
2742*e7801d59Ssowmini 			fields_str = all_extended_fields;
2743*e7801d59Ssowmini 		else
2744*e7801d59Ssowmini 			fields_str = all_fields;
2745*e7801d59Ssowmini 	}
2746*e7801d59Ssowmini 
2747*e7801d59Ssowmini 	if (state.gs_lacp) {
2748*e7801d59Ssowmini 		pf = aggr_l_fields;
2749*e7801d59Ssowmini 		pfmax = AGGR_L_MAX_FIELDS;
2750*e7801d59Ssowmini 	} else if (state.gs_stats) {
2751*e7801d59Ssowmini 		pf = aggr_s_fields;
2752*e7801d59Ssowmini 		pfmax = AGGR_S_MAX_FIELDS;
2753*e7801d59Ssowmini 	} else if (state.gs_extended) {
2754*e7801d59Ssowmini 		pf = aggr_x_fields;
2755*e7801d59Ssowmini 		pfmax = AGGR_X_MAX_FIELDS;
2756*e7801d59Ssowmini 	} else {
2757*e7801d59Ssowmini 		pf = laggr_fields;
2758*e7801d59Ssowmini 		pfmax = LAGGR_MAX_FIELDS;
2759*e7801d59Ssowmini 	}
2760*e7801d59Ssowmini 	fields = parse_output_fields(fields_str, pf, pfmax, CMD_TYPE_ANY,
2761*e7801d59Ssowmini 	    &nfields);
2762*e7801d59Ssowmini 
2763*e7801d59Ssowmini 	if (fields == NULL) {
2764*e7801d59Ssowmini 		die("invalid field(s) specified");
2765*e7801d59Ssowmini 		return;
2766*e7801d59Ssowmini 	}
2767*e7801d59Ssowmini 
2768*e7801d59Ssowmini 	state.gs_print.ps_fields = fields;
2769*e7801d59Ssowmini 	state.gs_print.ps_nfields = nfields;
2770*e7801d59Ssowmini 
27717c478bd9Sstevel@tonic-gate 	if (s_arg) {
2772d62bc4baSyz147064 		aggr_stats(linkid, &state, interval);
27737c478bd9Sstevel@tonic-gate 		return;
27747c478bd9Sstevel@tonic-gate 	}
27757c478bd9Sstevel@tonic-gate 
2776d62bc4baSyz147064 	if (linkid == DATALINK_ALL_LINKID) {
2777d62bc4baSyz147064 		(void) dladm_walk_datalink_id(show_aggr, &state,
2778d62bc4baSyz147064 		    DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE, flags);
2779d62bc4baSyz147064 	} else {
2780d62bc4baSyz147064 		(void) show_aggr(linkid, &state);
2781d62bc4baSyz147064 		if (state.gs_status != DLADM_STATUS_OK) {
2782d62bc4baSyz147064 			die_dlerr(state.gs_status, "failed to show aggr %s",
2783d62bc4baSyz147064 			    argv[optind]);
2784d62bc4baSyz147064 		}
2785d62bc4baSyz147064 	}
27867c478bd9Sstevel@tonic-gate }
27877c478bd9Sstevel@tonic-gate 
27887c478bd9Sstevel@tonic-gate static void
27897c478bd9Sstevel@tonic-gate do_show_dev(int argc, char *argv[])
27907c478bd9Sstevel@tonic-gate {
27917c478bd9Sstevel@tonic-gate 	int		option;
27927c478bd9Sstevel@tonic-gate 	char		*dev = NULL;
27937c478bd9Sstevel@tonic-gate 	boolean_t	s_arg = B_FALSE;
27947c478bd9Sstevel@tonic-gate 	boolean_t	i_arg = B_FALSE;
2795*e7801d59Ssowmini 	boolean_t	o_arg = B_FALSE;
2796d62bc4baSyz147064 	boolean_t	p_arg = B_FALSE;
2797d62bc4baSyz147064 	datalink_id_t	linkid;
279833343a97Smeem 	int		interval = 0;
2799d62bc4baSyz147064 	show_state_t	state;
2800*e7801d59Ssowmini 	char		*fields_str = NULL;
2801*e7801d59Ssowmini 	print_field_t	**fields;
2802*e7801d59Ssowmini 	uint_t		nfields;
2803*e7801d59Ssowmini 	char		*all_fields = "link,state,speed,duplex";
2804*e7801d59Ssowmini 	static char	*allstat_fields =
2805*e7801d59Ssowmini 	    "link,ipackets,rbytes,ierrors,opackets,obytes,oerrors";
2806*e7801d59Ssowmini 
2807*e7801d59Ssowmini 	bzero(&state, sizeof (state));
2808*e7801d59Ssowmini 	fields_str = all_fields;
28097c478bd9Sstevel@tonic-gate 
28107c478bd9Sstevel@tonic-gate 	opterr = 0;
2811*e7801d59Ssowmini 	while ((option = getopt_long(argc, argv, ":psi:o:",
2812d62bc4baSyz147064 	    show_lopts, NULL)) != -1) {
28137c478bd9Sstevel@tonic-gate 		switch (option) {
28147c478bd9Sstevel@tonic-gate 		case 'p':
2815d62bc4baSyz147064 			if (p_arg)
2816d62bc4baSyz147064 				die_optdup(option);
2817d62bc4baSyz147064 
2818d62bc4baSyz147064 			p_arg = B_TRUE;
28197c478bd9Sstevel@tonic-gate 			break;
28207c478bd9Sstevel@tonic-gate 		case 's':
282133343a97Smeem 			if (s_arg)
282233343a97Smeem 				die_optdup(option);
28237c478bd9Sstevel@tonic-gate 
28247c478bd9Sstevel@tonic-gate 			s_arg = B_TRUE;
28257c478bd9Sstevel@tonic-gate 			break;
2826*e7801d59Ssowmini 		case 'o':
2827*e7801d59Ssowmini 			o_arg = B_TRUE;
2828*e7801d59Ssowmini 			fields_str = optarg;
2829*e7801d59Ssowmini 			break;
28307c478bd9Sstevel@tonic-gate 		case 'i':
283133343a97Smeem 			if (i_arg)
283233343a97Smeem 				die_optdup(option);
28337c478bd9Sstevel@tonic-gate 
28347c478bd9Sstevel@tonic-gate 			i_arg = B_TRUE;
283533343a97Smeem 			if (!str2int(optarg, &interval) || interval == 0)
283633343a97Smeem 				die("invalid interval value '%s'", optarg);
28377c478bd9Sstevel@tonic-gate 			break;
28387c478bd9Sstevel@tonic-gate 		default:
283933343a97Smeem 			die_opterr(optopt, option);
284033343a97Smeem 			break;
28417c478bd9Sstevel@tonic-gate 		}
28427c478bd9Sstevel@tonic-gate 	}
28437c478bd9Sstevel@tonic-gate 
284433343a97Smeem 	if (i_arg && !s_arg)
284533343a97Smeem 		die("the option -i can be used only with -s");
28467c478bd9Sstevel@tonic-gate 
2847*e7801d59Ssowmini 	if (o_arg && strcasecmp(fields_str, "all") == 0) {
2848*e7801d59Ssowmini 		if (!s_arg)
2849*e7801d59Ssowmini 			fields_str = all_fields;
2850*e7801d59Ssowmini 		else
2851*e7801d59Ssowmini 			fields_str = allstat_fields;
2852*e7801d59Ssowmini 	}
2853*e7801d59Ssowmini 
2854*e7801d59Ssowmini 	if (!o_arg && s_arg)
2855*e7801d59Ssowmini 		fields_str = allstat_fields;
2856*e7801d59Ssowmini 
2857d62bc4baSyz147064 	if (s_arg && p_arg)
2858d62bc4baSyz147064 		die("the option -s cannot be used with -p");
2859d62bc4baSyz147064 
28607c478bd9Sstevel@tonic-gate 	/* get dev name (optional last argument) */
2861d62bc4baSyz147064 	if (optind == (argc-1)) {
2862d62bc4baSyz147064 		uint32_t flags;
2863d62bc4baSyz147064 
28647c478bd9Sstevel@tonic-gate 		dev = argv[optind];
2865d62bc4baSyz147064 
2866d62bc4baSyz147064 		if (dladm_dev2linkid(dev, &linkid) != DLADM_STATUS_OK)
2867d62bc4baSyz147064 			die("invalid device %s", dev);
2868d62bc4baSyz147064 
2869d62bc4baSyz147064 		if ((dladm_datalink_id2info(linkid, &flags, NULL, NULL,
2870d62bc4baSyz147064 		    NULL, 0) != DLADM_STATUS_OK) ||
2871d62bc4baSyz147064 		    !(flags & DLADM_OPT_ACTIVE)) {
2872d62bc4baSyz147064 			die("device %s has been removed", dev);
2873d62bc4baSyz147064 		}
2874d62bc4baSyz147064 	} else if (optind != argc) {
28757c478bd9Sstevel@tonic-gate 		usage();
2876cd93090eSericheng 	}
28777c478bd9Sstevel@tonic-gate 
2878*e7801d59Ssowmini 	state.ls_parseable = p_arg;
2879*e7801d59Ssowmini 	state.ls_donefirst = B_FALSE;
2880*e7801d59Ssowmini 
28817c478bd9Sstevel@tonic-gate 	if (s_arg) {
2882*e7801d59Ssowmini 		dev_stats(dev, interval, fields_str, &state);
28837c478bd9Sstevel@tonic-gate 		return;
28847c478bd9Sstevel@tonic-gate 	}
28857c478bd9Sstevel@tonic-gate 
2886*e7801d59Ssowmini 	fields = parse_output_fields(fields_str, dev_fields, DEV_MAX_FIELDS,
2887*e7801d59Ssowmini 	    CMD_TYPE_ANY, &nfields);
2888*e7801d59Ssowmini 
2889*e7801d59Ssowmini 	if (fields == NULL) {
2890*e7801d59Ssowmini 		die("invalid field(s) specified");
2891*e7801d59Ssowmini 		return;
2892*e7801d59Ssowmini 	}
2893*e7801d59Ssowmini 
2894*e7801d59Ssowmini 	state.ls_print.ps_fields = fields;
2895*e7801d59Ssowmini 	state.ls_print.ps_nfields = nfields;
2896*e7801d59Ssowmini 
2897d62bc4baSyz147064 	if (dev == NULL) {
2898f595a68aSyz147064 		(void) dladm_mac_walk(show_dev, &state);
2899d62bc4baSyz147064 	} else {
2900d62bc4baSyz147064 		(void) show_dev(dev, &state);
2901d62bc4baSyz147064 	}
29027c478bd9Sstevel@tonic-gate }
29037c478bd9Sstevel@tonic-gate 
2904d62bc4baSyz147064 
2905d62bc4baSyz147064 static dladm_status_t
2906*e7801d59Ssowmini print_phys(show_state_t *state, datalink_id_t linkid, link_fields_buf_t *pattr)
2907d62bc4baSyz147064 {
2908d62bc4baSyz147064 	char			link[MAXLINKNAMELEN];
2909d62bc4baSyz147064 	dladm_phys_attr_t	dpa;
2910d62bc4baSyz147064 	uint32_t		flags;
2911d62bc4baSyz147064 	datalink_class_t	class;
2912d62bc4baSyz147064 	uint32_t		media;
2913d62bc4baSyz147064 	dladm_status_t		status;
2914d62bc4baSyz147064 
2915d62bc4baSyz147064 	if ((status = dladm_datalink_id2info(linkid, &flags, &class, &media,
2916*e7801d59Ssowmini 	    link, MAXLINKNAMELEN)) != DLADM_STATUS_OK) {
2917d62bc4baSyz147064 		goto done;
2918d62bc4baSyz147064 	}
2919d62bc4baSyz147064 
2920d62bc4baSyz147064 	if (class != DATALINK_CLASS_PHYS) {
2921d62bc4baSyz147064 		status = DLADM_STATUS_BADARG;
2922d62bc4baSyz147064 		goto done;
2923d62bc4baSyz147064 	}
2924d62bc4baSyz147064 
2925d62bc4baSyz147064 	if (!(state->ls_flags & flags)) {
2926d62bc4baSyz147064 		status = DLADM_STATUS_NOTFOUND;
2927d62bc4baSyz147064 		goto done;
2928d62bc4baSyz147064 	}
2929d62bc4baSyz147064 
2930d62bc4baSyz147064 	status = dladm_phys_info(linkid, &dpa, state->ls_flags);
2931d62bc4baSyz147064 	if (status != DLADM_STATUS_OK)
2932d62bc4baSyz147064 		goto done;
2933d62bc4baSyz147064 
2934*e7801d59Ssowmini 	(void) snprintf(pattr->link_phys_device,
2935*e7801d59Ssowmini 	    sizeof (pattr->link_phys_device), "%s", dpa.dp_dev);
2936*e7801d59Ssowmini 	(void) dladm_media2str(media, pattr->link_phys_media);
2937d62bc4baSyz147064 	if (state->ls_flags == DLADM_OPT_ACTIVE) {
2938d62bc4baSyz147064 		boolean_t	islink;
2939d62bc4baSyz147064 
2940d62bc4baSyz147064 		if (!dpa.dp_novanity) {
2941*e7801d59Ssowmini 			(void) strlcpy(pattr->link_name, link,
2942*e7801d59Ssowmini 			    sizeof (pattr->link_name));
2943d62bc4baSyz147064 			islink = B_TRUE;
2944d62bc4baSyz147064 		} else {
2945d62bc4baSyz147064 			/*
2946d62bc4baSyz147064 			 * This is a physical link that does not have
2947d62bc4baSyz147064 			 * vanity naming support.
2948d62bc4baSyz147064 			 */
2949*e7801d59Ssowmini 			(void) strlcpy(pattr->link_name, dpa.dp_dev,
2950*e7801d59Ssowmini 			    sizeof (pattr->link_name));
2951d62bc4baSyz147064 			islink = B_FALSE;
2952d62bc4baSyz147064 		}
2953d62bc4baSyz147064 
2954*e7801d59Ssowmini 		(void) get_linkstate(pattr->link_name, islink,
2955*e7801d59Ssowmini 		    pattr->link_phys_state);
2956*e7801d59Ssowmini 		(void) snprintf(pattr->link_phys_speed,
2957*e7801d59Ssowmini 		    sizeof (pattr->link_phys_speed), "%u",
2958*e7801d59Ssowmini 		    (uint_t)((get_ifspeed(pattr->link_name,
2959*e7801d59Ssowmini 		    islink)) / 1000000ull));
2960*e7801d59Ssowmini 		(void) get_linkduplex(pattr->link_name, islink,
2961*e7801d59Ssowmini 		    pattr->link_phys_duplex);
2962d62bc4baSyz147064 	} else {
2963*e7801d59Ssowmini 		(void) snprintf(pattr->link_name, sizeof (pattr->link_name),
2964*e7801d59Ssowmini 		    "%s", link);
2965*e7801d59Ssowmini 		(void) snprintf(pattr->link_flags, sizeof (pattr->link_flags),
2966*e7801d59Ssowmini 		    "%c----", flags & DLADM_OPT_ACTIVE ? '-' : 'r');
2967d62bc4baSyz147064 	}
2968d62bc4baSyz147064 
2969d62bc4baSyz147064 done:
2970d62bc4baSyz147064 	return (status);
2971d62bc4baSyz147064 }
2972d62bc4baSyz147064 
2973d62bc4baSyz147064 static int
2974d62bc4baSyz147064 show_phys(datalink_id_t linkid, void *arg)
2975d62bc4baSyz147064 {
2976d62bc4baSyz147064 	show_state_t	*state = arg;
2977d62bc4baSyz147064 	dladm_status_t	status;
2978*e7801d59Ssowmini 	link_fields_buf_t	pattr;
2979d62bc4baSyz147064 
2980*e7801d59Ssowmini 	status = print_phys(state, linkid, &pattr);
2981d62bc4baSyz147064 	if (status != DLADM_STATUS_OK)
2982d62bc4baSyz147064 		goto done;
2983*e7801d59Ssowmini 
2984*e7801d59Ssowmini 	if (!state->ls_parseable && !state->ls_printheader) {
2985*e7801d59Ssowmini 		print_header(&state->ls_print);
2986*e7801d59Ssowmini 		state->ls_printheader = B_TRUE;
2987*e7801d59Ssowmini 	}
2988*e7801d59Ssowmini 
2989*e7801d59Ssowmini 	dladm_print_output(&state->ls_print, state->ls_parseable,
2990*e7801d59Ssowmini 	    dladm_print_field, (void *)&pattr);
2991d62bc4baSyz147064 
2992d62bc4baSyz147064 done:
2993d62bc4baSyz147064 	state->ls_status = status;
2994d62bc4baSyz147064 	return (DLADM_WALK_CONTINUE);
2995d62bc4baSyz147064 }
2996d62bc4baSyz147064 
2997d62bc4baSyz147064 
2998d62bc4baSyz147064 /*
2999d62bc4baSyz147064  * Print the active topology information.
3000d62bc4baSyz147064  */
3001d62bc4baSyz147064 static dladm_status_t
3002*e7801d59Ssowmini print_vlan(show_state_t *state, datalink_id_t linkid, link_fields_buf_t *l)
3003d62bc4baSyz147064 {
3004d62bc4baSyz147064 	dladm_vlan_attr_t	vinfo;
3005d62bc4baSyz147064 	uint32_t		flags;
3006d62bc4baSyz147064 	dladm_status_t		status;
3007d62bc4baSyz147064 
3008*e7801d59Ssowmini 	if ((status = dladm_datalink_id2info(linkid, &flags, NULL, NULL,
3009*e7801d59Ssowmini 	    l->link_name, sizeof (l->link_name))) != DLADM_STATUS_OK) {
3010d62bc4baSyz147064 		goto done;
3011d62bc4baSyz147064 	}
3012d62bc4baSyz147064 
3013d62bc4baSyz147064 	if (!(state->ls_flags & flags)) {
3014d62bc4baSyz147064 		status = DLADM_STATUS_NOTFOUND;
3015d62bc4baSyz147064 		goto done;
3016d62bc4baSyz147064 	}
3017d62bc4baSyz147064 
3018d62bc4baSyz147064 	if ((status = dladm_vlan_info(linkid, &vinfo, state->ls_flags)) !=
3019d62bc4baSyz147064 	    DLADM_STATUS_OK || (status = dladm_datalink_id2info(
3020*e7801d59Ssowmini 	    vinfo.dv_linkid, NULL, NULL, NULL, l->link_over,
3021*e7801d59Ssowmini 	    sizeof (l->link_over))) != DLADM_STATUS_OK) {
3022d62bc4baSyz147064 		goto done;
3023d62bc4baSyz147064 	}
3024d62bc4baSyz147064 
3025*e7801d59Ssowmini 	(void) snprintf(l->link_vlan_vid, sizeof (l->link_vlan_vid), "%d",
3026*e7801d59Ssowmini 	    vinfo.dv_vid);
3027*e7801d59Ssowmini 	(void) snprintf(l->link_flags, sizeof (l->link_flags), "%c%c---",
3028*e7801d59Ssowmini 	    vinfo.dv_force ? 'f' : '-', vinfo.dv_implicit ? 'i' : '-');
3029d62bc4baSyz147064 
3030d62bc4baSyz147064 done:
3031d62bc4baSyz147064 	return (status);
3032d62bc4baSyz147064 }
3033d62bc4baSyz147064 
3034d62bc4baSyz147064 static int
3035d62bc4baSyz147064 show_vlan(datalink_id_t linkid, void *arg)
3036d62bc4baSyz147064 {
3037d62bc4baSyz147064 	show_state_t	*state = arg;
3038d62bc4baSyz147064 	dladm_status_t	status;
3039*e7801d59Ssowmini 	link_fields_buf_t	lbuf;
3040d62bc4baSyz147064 
3041*e7801d59Ssowmini 	status = print_vlan(state, linkid, &lbuf);
3042d62bc4baSyz147064 	if (status != DLADM_STATUS_OK)
3043d62bc4baSyz147064 		goto done;
3044*e7801d59Ssowmini 
3045*e7801d59Ssowmini 	if (!state->ls_parseable && !state->ls_printheader) {
3046*e7801d59Ssowmini 		print_header(&state->ls_print);
3047*e7801d59Ssowmini 		state->ls_printheader = B_TRUE;
3048*e7801d59Ssowmini 	}
3049*e7801d59Ssowmini 
3050*e7801d59Ssowmini 	dladm_print_output(&state->ls_print, state->ls_parseable,
3051*e7801d59Ssowmini 	    dladm_print_field, (void *)&lbuf);
3052d62bc4baSyz147064 
3053d62bc4baSyz147064 done:
3054d62bc4baSyz147064 	state->ls_status = status;
3055d62bc4baSyz147064 	return (DLADM_WALK_CONTINUE);
3056d62bc4baSyz147064 }
3057d62bc4baSyz147064 
3058d62bc4baSyz147064 static void
3059d62bc4baSyz147064 do_show_phys(int argc, char *argv[])
3060d62bc4baSyz147064 {
3061d62bc4baSyz147064 	int		option;
3062d62bc4baSyz147064 	uint32_t	flags = DLADM_OPT_ACTIVE;
3063d62bc4baSyz147064 	boolean_t	p_arg = B_FALSE;
3064*e7801d59Ssowmini 	boolean_t	o_arg = B_FALSE;
3065d62bc4baSyz147064 	datalink_id_t	linkid = DATALINK_ALL_LINKID;
3066d62bc4baSyz147064 	show_state_t	state;
3067d62bc4baSyz147064 	dladm_status_t	status;
3068*e7801d59Ssowmini 	char			*fields_str = NULL;
3069*e7801d59Ssowmini 	print_field_t		**fields;
3070*e7801d59Ssowmini 	uint_t			nfields;
3071*e7801d59Ssowmini 	char			*all_active_fields =
3072*e7801d59Ssowmini 	    "link,media,state,speed,duplex,device";
3073*e7801d59Ssowmini 	char			*all_inactive_fields =
3074*e7801d59Ssowmini 	    "link,device,media,flags";
3075d62bc4baSyz147064 
3076*e7801d59Ssowmini 	bzero(&state, sizeof (state));
3077d62bc4baSyz147064 	opterr = 0;
3078*e7801d59Ssowmini 	while ((option = getopt_long(argc, argv, ":pPo:",
3079d62bc4baSyz147064 	    show_lopts, NULL)) != -1) {
3080d62bc4baSyz147064 		switch (option) {
3081d62bc4baSyz147064 		case 'p':
3082d62bc4baSyz147064 			if (p_arg)
3083d62bc4baSyz147064 				die_optdup(option);
3084d62bc4baSyz147064 
3085d62bc4baSyz147064 			p_arg = B_TRUE;
3086d62bc4baSyz147064 			break;
3087d62bc4baSyz147064 		case 'P':
3088d62bc4baSyz147064 			if (flags != DLADM_OPT_ACTIVE)
3089d62bc4baSyz147064 				die_optdup(option);
3090d62bc4baSyz147064 
3091d62bc4baSyz147064 			flags = DLADM_OPT_PERSIST;
3092d62bc4baSyz147064 			break;
3093*e7801d59Ssowmini 		case 'o':
3094*e7801d59Ssowmini 			o_arg = B_TRUE;
3095*e7801d59Ssowmini 			fields_str = optarg;
3096*e7801d59Ssowmini 			break;
3097d62bc4baSyz147064 		default:
3098d62bc4baSyz147064 			die_opterr(optopt, option);
3099d62bc4baSyz147064 			break;
3100d62bc4baSyz147064 		}
3101d62bc4baSyz147064 	}
3102d62bc4baSyz147064 
3103d62bc4baSyz147064 	/* get link name (optional last argument) */
3104d62bc4baSyz147064 	if (optind == (argc-1)) {
3105d62bc4baSyz147064 		if ((status = dladm_name2info(argv[optind], &linkid, NULL,
3106d62bc4baSyz147064 		    NULL, NULL)) != DLADM_STATUS_OK) {
3107d62bc4baSyz147064 			die_dlerr(status, "link %s is not valid", argv[optind]);
3108d62bc4baSyz147064 		}
3109d62bc4baSyz147064 	} else if (optind != argc) {
3110d62bc4baSyz147064 		usage();
3111d62bc4baSyz147064 	}
3112d62bc4baSyz147064 
3113d62bc4baSyz147064 	state.ls_parseable = p_arg;
3114d62bc4baSyz147064 	state.ls_flags = flags;
3115d62bc4baSyz147064 	state.ls_donefirst = B_FALSE;
3116d62bc4baSyz147064 
3117*e7801d59Ssowmini 	if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) {
3118*e7801d59Ssowmini 		if (state.ls_flags & DLADM_OPT_ACTIVE)
3119*e7801d59Ssowmini 			fields_str = all_active_fields;
3120*e7801d59Ssowmini 		else
3121*e7801d59Ssowmini 			fields_str = all_inactive_fields;
3122*e7801d59Ssowmini 	}
3123*e7801d59Ssowmini 
3124*e7801d59Ssowmini 	fields = parse_output_fields(fields_str, phys_fields,
3125*e7801d59Ssowmini 	    PHYS_MAX_FIELDS, CMD_TYPE_ANY, &nfields);
3126*e7801d59Ssowmini 
3127*e7801d59Ssowmini 	if (fields == NULL) {
3128*e7801d59Ssowmini 		die("invalid field(s) specified");
3129*e7801d59Ssowmini 		return;
3130*e7801d59Ssowmini 	}
3131*e7801d59Ssowmini 
3132*e7801d59Ssowmini 	state.ls_print.ps_fields = fields;
3133*e7801d59Ssowmini 	state.ls_print.ps_nfields = nfields;
3134*e7801d59Ssowmini 
3135d62bc4baSyz147064 	if (linkid == DATALINK_ALL_LINKID) {
3136d62bc4baSyz147064 		(void) dladm_walk_datalink_id(show_phys, &state,
3137d62bc4baSyz147064 		    DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE, flags);
3138d62bc4baSyz147064 	} else {
3139d62bc4baSyz147064 		(void) show_phys(linkid, &state);
3140d62bc4baSyz147064 		if (state.ls_status != DLADM_STATUS_OK) {
3141d62bc4baSyz147064 			die_dlerr(state.ls_status,
3142d62bc4baSyz147064 			    "failed to show physical link %s", argv[optind]);
3143d62bc4baSyz147064 		}
3144d62bc4baSyz147064 	}
3145d62bc4baSyz147064 }
3146d62bc4baSyz147064 
3147d62bc4baSyz147064 static void
3148d62bc4baSyz147064 do_show_vlan(int argc, char *argv[])
3149d62bc4baSyz147064 {
3150d62bc4baSyz147064 	int		option;
3151d62bc4baSyz147064 	uint32_t	flags = DLADM_OPT_ACTIVE;
3152d62bc4baSyz147064 	boolean_t	p_arg = B_FALSE;
3153d62bc4baSyz147064 	datalink_id_t	linkid = DATALINK_ALL_LINKID;
3154d62bc4baSyz147064 	show_state_t	state;
3155d62bc4baSyz147064 	dladm_status_t	status;
3156*e7801d59Ssowmini 	boolean_t	o_arg = B_FALSE;
3157*e7801d59Ssowmini 	char		*fields_str = NULL;
3158*e7801d59Ssowmini 	print_field_t	**fields;
3159*e7801d59Ssowmini 	uint_t		nfields;
3160*e7801d59Ssowmini 	char		*all_fields = "link,vid,over,flags";
3161*e7801d59Ssowmini 
3162*e7801d59Ssowmini 	bzero(&state, sizeof (state));
3163d62bc4baSyz147064 
3164d62bc4baSyz147064 	opterr = 0;
3165*e7801d59Ssowmini 	while ((option = getopt_long(argc, argv, ":pPo:",
3166d62bc4baSyz147064 	    show_lopts, NULL)) != -1) {
3167d62bc4baSyz147064 		switch (option) {
3168d62bc4baSyz147064 		case 'p':
3169d62bc4baSyz147064 			if (p_arg)
3170d62bc4baSyz147064 				die_optdup(option);
3171d62bc4baSyz147064 
3172d62bc4baSyz147064 			p_arg = B_TRUE;
3173d62bc4baSyz147064 			break;
3174d62bc4baSyz147064 		case 'P':
3175d62bc4baSyz147064 			if (flags != DLADM_OPT_ACTIVE)
3176d62bc4baSyz147064 				die_optdup(option);
3177d62bc4baSyz147064 
3178d62bc4baSyz147064 			flags = DLADM_OPT_PERSIST;
3179d62bc4baSyz147064 			break;
3180*e7801d59Ssowmini 		case 'o':
3181*e7801d59Ssowmini 			o_arg = B_TRUE;
3182*e7801d59Ssowmini 			fields_str = optarg;
3183*e7801d59Ssowmini 			break;
3184d62bc4baSyz147064 		default:
3185d62bc4baSyz147064 			die_opterr(optopt, option);
3186d62bc4baSyz147064 			break;
3187d62bc4baSyz147064 		}
3188d62bc4baSyz147064 	}
3189d62bc4baSyz147064 
3190d62bc4baSyz147064 	/* get link name (optional last argument) */
3191d62bc4baSyz147064 	if (optind == (argc-1)) {
3192d62bc4baSyz147064 		if ((status = dladm_name2info(argv[optind], &linkid, NULL,
3193d62bc4baSyz147064 		    NULL, NULL)) != DLADM_STATUS_OK) {
3194d62bc4baSyz147064 			die_dlerr(status, "link %s is not valid", argv[optind]);
3195d62bc4baSyz147064 		}
3196d62bc4baSyz147064 	} else if (optind != argc) {
3197d62bc4baSyz147064 		usage();
3198d62bc4baSyz147064 	}
3199d62bc4baSyz147064 
3200d62bc4baSyz147064 	state.ls_parseable = p_arg;
3201d62bc4baSyz147064 	state.ls_flags = flags;
3202d62bc4baSyz147064 	state.ls_donefirst = B_FALSE;
3203d62bc4baSyz147064 
3204*e7801d59Ssowmini 	if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0))
3205*e7801d59Ssowmini 		fields_str = all_fields;
3206*e7801d59Ssowmini 
3207*e7801d59Ssowmini 	fields = parse_output_fields(fields_str, vlan_fields, VLAN_MAX_FIELDS,
3208*e7801d59Ssowmini 	    CMD_TYPE_ANY, &nfields);
3209*e7801d59Ssowmini 
3210*e7801d59Ssowmini 	if (fields == NULL) {
3211*e7801d59Ssowmini 		die("invalid field(s) specified");
3212*e7801d59Ssowmini 		return;
3213*e7801d59Ssowmini 	}
3214*e7801d59Ssowmini 	state.ls_print.ps_fields = fields;
3215*e7801d59Ssowmini 	state.ls_print.ps_nfields = nfields;
3216*e7801d59Ssowmini 
3217d62bc4baSyz147064 	if (linkid == DATALINK_ALL_LINKID) {
3218d62bc4baSyz147064 		(void) dladm_walk_datalink_id(show_vlan, &state,
3219d62bc4baSyz147064 		    DATALINK_CLASS_VLAN, DATALINK_ANY_MEDIATYPE, flags);
3220d62bc4baSyz147064 	} else {
3221d62bc4baSyz147064 		(void) show_vlan(linkid, &state);
3222d62bc4baSyz147064 		if (state.ls_status != DLADM_STATUS_OK) {
3223d62bc4baSyz147064 			die_dlerr(state.ls_status, "failed to show vlan %s",
3224d62bc4baSyz147064 			    argv[optind]);
3225d62bc4baSyz147064 		}
3226d62bc4baSyz147064 	}
3227d62bc4baSyz147064 }
3228d62bc4baSyz147064 
3229d62bc4baSyz147064 static void
3230d62bc4baSyz147064 link_stats(datalink_id_t linkid, uint_t interval)
3231d62bc4baSyz147064 {
3232d62bc4baSyz147064 	show_state_t	state;
323333343a97Smeem 
32347c478bd9Sstevel@tonic-gate 	bzero(&state, sizeof (state));
32357c478bd9Sstevel@tonic-gate 
32367c478bd9Sstevel@tonic-gate 	/*
32377c478bd9Sstevel@tonic-gate 	 * If an interval is specified, continuously show the stats
32387c478bd9Sstevel@tonic-gate 	 * only for the first MAC port.
32397c478bd9Sstevel@tonic-gate 	 */
32407c478bd9Sstevel@tonic-gate 	state.ls_firstonly = (interval != 0);
32417c478bd9Sstevel@tonic-gate 
32427c478bd9Sstevel@tonic-gate 	for (;;) {
3243d62bc4baSyz147064 		(void) printf("%-12s%-10s%-12s%-8s%-10s%-12s%-8s\n",
3244d62bc4baSyz147064 		    "LINK", "IPACKETS", "RBYTES", "IERRORS", "OPACKETS",
3245d62bc4baSyz147064 		    "OBYTES", "OERRORS");
32467c478bd9Sstevel@tonic-gate 
32477c478bd9Sstevel@tonic-gate 		state.ls_donefirst = B_FALSE;
3248d62bc4baSyz147064 		if (linkid == DATALINK_ALL_LINKID) {
3249d62bc4baSyz147064 			(void) dladm_walk_datalink_id(show_link_stats, &state,
3250d62bc4baSyz147064 			    DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE,
3251d62bc4baSyz147064 			    DLADM_OPT_ACTIVE);
3252d62bc4baSyz147064 		} else {
3253d62bc4baSyz147064 			(void) show_link_stats(linkid, &state);
3254d62bc4baSyz147064 		}
32557c478bd9Sstevel@tonic-gate 
32567c478bd9Sstevel@tonic-gate 		if (interval == 0)
32577c478bd9Sstevel@tonic-gate 			break;
32587c478bd9Sstevel@tonic-gate 
32597c478bd9Sstevel@tonic-gate 		(void) sleep(interval);
32607c478bd9Sstevel@tonic-gate 	}
32617c478bd9Sstevel@tonic-gate }
32627c478bd9Sstevel@tonic-gate 
32637c478bd9Sstevel@tonic-gate static void
3264d62bc4baSyz147064 aggr_stats(datalink_id_t linkid, show_grp_state_t *state, uint_t interval)
32657c478bd9Sstevel@tonic-gate {
32667c478bd9Sstevel@tonic-gate 	/*
32677c478bd9Sstevel@tonic-gate 	 * If an interval is specified, continuously show the stats
32687c478bd9Sstevel@tonic-gate 	 * only for the first group.
32697c478bd9Sstevel@tonic-gate 	 */
3270d62bc4baSyz147064 	state->gs_firstonly = (interval != 0);
32717c478bd9Sstevel@tonic-gate 
32727c478bd9Sstevel@tonic-gate 	for (;;) {
3273d62bc4baSyz147064 		state->gs_donefirst = B_FALSE;
3274d62bc4baSyz147064 		if (linkid == DATALINK_ALL_LINKID)
3275d62bc4baSyz147064 			(void) dladm_walk_datalink_id(show_aggr, state,
3276d62bc4baSyz147064 			    DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE,
3277d62bc4baSyz147064 			    DLADM_OPT_ACTIVE);
3278d62bc4baSyz147064 		else
3279d62bc4baSyz147064 			(void) show_aggr(linkid, state);
32807c478bd9Sstevel@tonic-gate 
32817c478bd9Sstevel@tonic-gate 		if (interval == 0)
32827c478bd9Sstevel@tonic-gate 			break;
32837c478bd9Sstevel@tonic-gate 
32847c478bd9Sstevel@tonic-gate 		(void) sleep(interval);
32857c478bd9Sstevel@tonic-gate 	}
32867c478bd9Sstevel@tonic-gate }
32877c478bd9Sstevel@tonic-gate 
32887c478bd9Sstevel@tonic-gate static void
3289*e7801d59Ssowmini dev_stats(const char *dev, uint32_t interval, char *fields_str,
3290*e7801d59Ssowmini     show_state_t *state)
32917c478bd9Sstevel@tonic-gate {
3292*e7801d59Ssowmini 	print_field_t	**fields;
3293*e7801d59Ssowmini 	uint_t		nfields;
32947c478bd9Sstevel@tonic-gate 
3295*e7801d59Ssowmini 	fields = parse_output_fields(fields_str, devs_fields, DEVS_MAX_FIELDS,
3296*e7801d59Ssowmini 	    CMD_TYPE_ANY, &nfields);
3297*e7801d59Ssowmini 
3298*e7801d59Ssowmini 	if (fields == NULL) {
3299*e7801d59Ssowmini 		die("invalid field(s) specified");
3300*e7801d59Ssowmini 		return;
3301*e7801d59Ssowmini 	}
3302*e7801d59Ssowmini 
3303*e7801d59Ssowmini 	state->ls_print.ps_fields = fields;
3304*e7801d59Ssowmini 	state->ls_print.ps_nfields = nfields;
3305*e7801d59Ssowmini 
33067c478bd9Sstevel@tonic-gate 
33077c478bd9Sstevel@tonic-gate 	/*
33087c478bd9Sstevel@tonic-gate 	 * If an interval is specified, continuously show the stats
33097c478bd9Sstevel@tonic-gate 	 * only for the first MAC port.
33107c478bd9Sstevel@tonic-gate 	 */
3311*e7801d59Ssowmini 	state->ls_firstonly = (interval != 0);
33127c478bd9Sstevel@tonic-gate 
33137c478bd9Sstevel@tonic-gate 	for (;;) {
33147c478bd9Sstevel@tonic-gate 
3315*e7801d59Ssowmini 		if (!state->ls_parseable)
3316*e7801d59Ssowmini 			print_header(&state->ls_print);
3317*e7801d59Ssowmini 		state->ls_donefirst = B_FALSE;
33187c478bd9Sstevel@tonic-gate 
3319210db224Sericheng 		if (dev == NULL)
3320*e7801d59Ssowmini 			(void) dladm_mac_walk(show_dev_stats, state);
3321210db224Sericheng 		else
3322*e7801d59Ssowmini 			(void) show_dev_stats(dev, state);
33237c478bd9Sstevel@tonic-gate 
33247c478bd9Sstevel@tonic-gate 		if (interval == 0)
33257c478bd9Sstevel@tonic-gate 			break;
33267c478bd9Sstevel@tonic-gate 
33277c478bd9Sstevel@tonic-gate 		(void) sleep(interval);
33287c478bd9Sstevel@tonic-gate 	}
3329d62bc4baSyz147064 
3330*e7801d59Ssowmini 	if (dev != NULL && state->ls_status != DLADM_STATUS_OK)
3331*e7801d59Ssowmini 		die_dlerr(state->ls_status, "cannot show device '%s'", dev);
33327c478bd9Sstevel@tonic-gate }
33337c478bd9Sstevel@tonic-gate 
33347c478bd9Sstevel@tonic-gate /* accumulate stats (s1 += (s2 - s3)) */
33357c478bd9Sstevel@tonic-gate static void
33367c478bd9Sstevel@tonic-gate stats_total(pktsum_t *s1, pktsum_t *s2, pktsum_t *s3)
33377c478bd9Sstevel@tonic-gate {
33387c478bd9Sstevel@tonic-gate 	s1->ipackets += (s2->ipackets - s3->ipackets);
33397c478bd9Sstevel@tonic-gate 	s1->opackets += (s2->opackets - s3->opackets);
33407c478bd9Sstevel@tonic-gate 	s1->rbytes += (s2->rbytes - s3->rbytes);
33417c478bd9Sstevel@tonic-gate 	s1->obytes += (s2->obytes - s3->obytes);
33427c478bd9Sstevel@tonic-gate 	s1->ierrors += (s2->ierrors - s3->ierrors);
33437c478bd9Sstevel@tonic-gate 	s1->oerrors += (s2->oerrors - s3->oerrors);
33447c478bd9Sstevel@tonic-gate }
33457c478bd9Sstevel@tonic-gate 
33467c478bd9Sstevel@tonic-gate /* compute stats differences (s1 = s2 - s3) */
33477c478bd9Sstevel@tonic-gate static void
33487c478bd9Sstevel@tonic-gate stats_diff(pktsum_t *s1, pktsum_t *s2, pktsum_t *s3)
33497c478bd9Sstevel@tonic-gate {
33507c478bd9Sstevel@tonic-gate 	s1->ipackets = s2->ipackets - s3->ipackets;
33517c478bd9Sstevel@tonic-gate 	s1->opackets = s2->opackets - s3->opackets;
33527c478bd9Sstevel@tonic-gate 	s1->rbytes = s2->rbytes - s3->rbytes;
33537c478bd9Sstevel@tonic-gate 	s1->obytes = s2->obytes - s3->obytes;
33547c478bd9Sstevel@tonic-gate 	s1->ierrors = s2->ierrors - s3->ierrors;
33557c478bd9Sstevel@tonic-gate 	s1->oerrors = s2->oerrors - s3->oerrors;
33567c478bd9Sstevel@tonic-gate }
33577c478bd9Sstevel@tonic-gate 
33587c478bd9Sstevel@tonic-gate static void
3359d62bc4baSyz147064 get_stats(char *module, int instance, const char *name, pktsum_t *stats)
33607c478bd9Sstevel@tonic-gate {
33617c478bd9Sstevel@tonic-gate 	kstat_ctl_t	*kcp;
33627c478bd9Sstevel@tonic-gate 	kstat_t		*ksp;
33637c478bd9Sstevel@tonic-gate 
33647c478bd9Sstevel@tonic-gate 	if ((kcp = kstat_open()) == NULL) {
336533343a97Smeem 		warn("kstat open operation failed");
33667c478bd9Sstevel@tonic-gate 		return;
33677c478bd9Sstevel@tonic-gate 	}
33687c478bd9Sstevel@tonic-gate 
3369d62bc4baSyz147064 	if ((ksp = kstat_lookup(kcp, module, instance, (char *)name)) == NULL) {
33707c478bd9Sstevel@tonic-gate 		/*
33717c478bd9Sstevel@tonic-gate 		 * The kstat query could fail if the underlying MAC
33727c478bd9Sstevel@tonic-gate 		 * driver was already detached.
33737c478bd9Sstevel@tonic-gate 		 */
33747c478bd9Sstevel@tonic-gate 		(void) kstat_close(kcp);
33757c478bd9Sstevel@tonic-gate 		return;
33767c478bd9Sstevel@tonic-gate 	}
33777c478bd9Sstevel@tonic-gate 
33787c478bd9Sstevel@tonic-gate 	if (kstat_read(kcp, ksp, NULL) == -1)
33797c478bd9Sstevel@tonic-gate 		goto bail;
33807c478bd9Sstevel@tonic-gate 
3381*e7801d59Ssowmini 	if (dladm_kstat_value(ksp, "ipackets64", KSTAT_DATA_UINT64,
33827c478bd9Sstevel@tonic-gate 	    &stats->ipackets) < 0)
33837c478bd9Sstevel@tonic-gate 		goto bail;
33847c478bd9Sstevel@tonic-gate 
3385*e7801d59Ssowmini 	if (dladm_kstat_value(ksp, "opackets64", KSTAT_DATA_UINT64,
33867c478bd9Sstevel@tonic-gate 	    &stats->opackets) < 0)
33877c478bd9Sstevel@tonic-gate 		goto bail;
33887c478bd9Sstevel@tonic-gate 
3389*e7801d59Ssowmini 	if (dladm_kstat_value(ksp, "rbytes64", KSTAT_DATA_UINT64,
33907c478bd9Sstevel@tonic-gate 	    &stats->rbytes) < 0)
33917c478bd9Sstevel@tonic-gate 		goto bail;
33927c478bd9Sstevel@tonic-gate 
3393*e7801d59Ssowmini 	if (dladm_kstat_value(ksp, "obytes64", KSTAT_DATA_UINT64,
33947c478bd9Sstevel@tonic-gate 	    &stats->obytes) < 0)
33957c478bd9Sstevel@tonic-gate 		goto bail;
33967c478bd9Sstevel@tonic-gate 
3397*e7801d59Ssowmini 	if (dladm_kstat_value(ksp, "ierrors", KSTAT_DATA_UINT32,
33987c478bd9Sstevel@tonic-gate 	    &stats->ierrors) < 0)
33997c478bd9Sstevel@tonic-gate 		goto bail;
34007c478bd9Sstevel@tonic-gate 
3401*e7801d59Ssowmini 	if (dladm_kstat_value(ksp, "oerrors", KSTAT_DATA_UINT32,
34027c478bd9Sstevel@tonic-gate 	    &stats->oerrors) < 0)
34037c478bd9Sstevel@tonic-gate 		goto bail;
34047c478bd9Sstevel@tonic-gate 
3405d62bc4baSyz147064 bail:
34067c478bd9Sstevel@tonic-gate 	(void) kstat_close(kcp);
34077c478bd9Sstevel@tonic-gate 	return;
34087c478bd9Sstevel@tonic-gate 
34097c478bd9Sstevel@tonic-gate }
34107c478bd9Sstevel@tonic-gate 
34117c478bd9Sstevel@tonic-gate static void
3412ba2e4443Sseb get_mac_stats(const char *dev, pktsum_t *stats)
34137c478bd9Sstevel@tonic-gate {
3414c7e4935fSss150715 	char module[DLPI_LINKNAME_MAX];
3415c7e4935fSss150715 	uint_t instance;
34167c478bd9Sstevel@tonic-gate 
3417d62bc4baSyz147064 	bzero(stats, sizeof (*stats));
3418c7e4935fSss150715 	if (dlpi_parselink(dev, module, &instance) != DLPI_SUCCESS)
3419ba2e4443Sseb 		return;
3420d62bc4baSyz147064 
3421ba2e4443Sseb 	get_stats(module, instance, "mac", stats);
34227c478bd9Sstevel@tonic-gate }
34237c478bd9Sstevel@tonic-gate 
34247c478bd9Sstevel@tonic-gate static void
34257c478bd9Sstevel@tonic-gate get_link_stats(const char *link, pktsum_t *stats)
34267c478bd9Sstevel@tonic-gate {
34277c478bd9Sstevel@tonic-gate 	bzero(stats, sizeof (*stats));
3428d62bc4baSyz147064 	get_stats("link", 0, link, stats);
34297c478bd9Sstevel@tonic-gate }
34307c478bd9Sstevel@tonic-gate 
3431ba2e4443Sseb static int
3432d62bc4baSyz147064 query_kstat(char *module, int instance, const char *name, const char *stat,
3433d62bc4baSyz147064     uint8_t type, void *val)
34347c478bd9Sstevel@tonic-gate {
34357c478bd9Sstevel@tonic-gate 	kstat_ctl_t	*kcp;
34367c478bd9Sstevel@tonic-gate 	kstat_t		*ksp;
34377c478bd9Sstevel@tonic-gate 
34387c478bd9Sstevel@tonic-gate 	if ((kcp = kstat_open()) == NULL) {
343933343a97Smeem 		warn("kstat open operation failed");
3440ba2e4443Sseb 		return (-1);
34417c478bd9Sstevel@tonic-gate 	}
34427c478bd9Sstevel@tonic-gate 
3443d62bc4baSyz147064 	if ((ksp = kstat_lookup(kcp, module, instance, (char *)name)) == NULL) {
34447c478bd9Sstevel@tonic-gate 		/*
34457c478bd9Sstevel@tonic-gate 		 * The kstat query could fail if the underlying MAC
34467c478bd9Sstevel@tonic-gate 		 * driver was already detached.
34477c478bd9Sstevel@tonic-gate 		 */
34487c478bd9Sstevel@tonic-gate 		goto bail;
34497c478bd9Sstevel@tonic-gate 	}
34507c478bd9Sstevel@tonic-gate 
34517c478bd9Sstevel@tonic-gate 	if (kstat_read(kcp, ksp, NULL) == -1) {
345233343a97Smeem 		warn("kstat read failed");
34537c478bd9Sstevel@tonic-gate 		goto bail;
34547c478bd9Sstevel@tonic-gate 	}
34557c478bd9Sstevel@tonic-gate 
3456*e7801d59Ssowmini 	if (dladm_kstat_value(ksp, stat, type, val) < 0)
34577c478bd9Sstevel@tonic-gate 		goto bail;
3458ba2e4443Sseb 
3459ba2e4443Sseb 	(void) kstat_close(kcp);
3460ba2e4443Sseb 	return (0);
34617c478bd9Sstevel@tonic-gate 
34627c478bd9Sstevel@tonic-gate bail:
34637c478bd9Sstevel@tonic-gate 	(void) kstat_close(kcp);
3464ba2e4443Sseb 	return (-1);
3465ba2e4443Sseb }
3466ba2e4443Sseb 
3467d62bc4baSyz147064 static int
3468d62bc4baSyz147064 get_one_kstat(const char *name, const char *stat, uint8_t type,
3469d62bc4baSyz147064     void *val, boolean_t islink)
3470d62bc4baSyz147064 {
3471d62bc4baSyz147064 	char		module[DLPI_LINKNAME_MAX];
3472d62bc4baSyz147064 	uint_t		instance;
3473d62bc4baSyz147064 
3474d62bc4baSyz147064 	if (islink) {
3475d62bc4baSyz147064 		return (query_kstat("link", 0, name, stat, type, val));
3476d62bc4baSyz147064 	} else {
3477d62bc4baSyz147064 		if (dlpi_parselink(name, module, &instance) != DLPI_SUCCESS)
3478d62bc4baSyz147064 			return (-1);
3479d62bc4baSyz147064 
3480d62bc4baSyz147064 		return (query_kstat(module, instance, "mac", stat, type, val));
3481d62bc4baSyz147064 	}
3482d62bc4baSyz147064 }
3483d62bc4baSyz147064 
3484ba2e4443Sseb static uint64_t
3485d62bc4baSyz147064 get_ifspeed(const char *name, boolean_t islink)
3486ba2e4443Sseb {
3487ba2e4443Sseb 	uint64_t ifspeed = 0;
3488ba2e4443Sseb 
3489d62bc4baSyz147064 	(void) get_one_kstat(name, "ifspeed", KSTAT_DATA_UINT64,
3490d62bc4baSyz147064 	    &ifspeed, islink);
3491d62bc4baSyz147064 
34927c478bd9Sstevel@tonic-gate 	return (ifspeed);
34937c478bd9Sstevel@tonic-gate }
34947c478bd9Sstevel@tonic-gate 
3495f595a68aSyz147064 static const char *
3496d62bc4baSyz147064 get_linkstate(const char *name, boolean_t islink, char *buf)
34977c478bd9Sstevel@tonic-gate {
3498d62bc4baSyz147064 	link_state_t	linkstate;
34997c478bd9Sstevel@tonic-gate 
3500d62bc4baSyz147064 	if (get_one_kstat(name, "link_state", KSTAT_DATA_UINT32,
3501d62bc4baSyz147064 	    &linkstate, islink) != 0) {
35023a62633bSyz147064 		(void) strlcpy(buf, "unknown", DLADM_STRSIZE);
35033a62633bSyz147064 		return (buf);
35047c478bd9Sstevel@tonic-gate 	}
3505d62bc4baSyz147064 	return (dladm_linkstate2str(linkstate, buf));
35067c478bd9Sstevel@tonic-gate }
35077c478bd9Sstevel@tonic-gate 
3508f595a68aSyz147064 static const char *
3509d62bc4baSyz147064 get_linkduplex(const char *name, boolean_t islink, char *buf)
35107c478bd9Sstevel@tonic-gate {
3511d62bc4baSyz147064 	link_duplex_t	linkduplex;
35127c478bd9Sstevel@tonic-gate 
3513d62bc4baSyz147064 	if (get_one_kstat(name, "link_duplex", KSTAT_DATA_UINT32,
3514d62bc4baSyz147064 	    &linkduplex, islink) != 0) {
35153a62633bSyz147064 		(void) strlcpy(buf, "unknown", DLADM_STRSIZE);
35163a62633bSyz147064 		return (buf);
35177c478bd9Sstevel@tonic-gate 	}
35187c478bd9Sstevel@tonic-gate 
3519d62bc4baSyz147064 	return (dladm_linkduplex2str(linkduplex, buf));
35207c478bd9Sstevel@tonic-gate }
35210ba2cbe9Sxc151355 
35220ba2cbe9Sxc151355 typedef struct {
35230ba2cbe9Sxc151355 	char	*s_buf;
35240ba2cbe9Sxc151355 	char	**s_fields;	/* array of pointer to the fields in s_buf */
35250ba2cbe9Sxc151355 	uint_t	s_nfields;	/* the number of fields in s_buf */
35260ba2cbe9Sxc151355 } split_t;
35270ba2cbe9Sxc151355 
35280ba2cbe9Sxc151355 /*
35290ba2cbe9Sxc151355  * Free the split_t structure pointed to by `sp'.
35300ba2cbe9Sxc151355  */
35310ba2cbe9Sxc151355 static void
35320ba2cbe9Sxc151355 splitfree(split_t *sp)
35330ba2cbe9Sxc151355 {
35340ba2cbe9Sxc151355 	free(sp->s_buf);
35350ba2cbe9Sxc151355 	free(sp->s_fields);
35360ba2cbe9Sxc151355 	free(sp);
35370ba2cbe9Sxc151355 }
35380ba2cbe9Sxc151355 
35390ba2cbe9Sxc151355 /*
35400ba2cbe9Sxc151355  * Split `str' into at most `maxfields' fields, each field at most `maxlen' in
35410ba2cbe9Sxc151355  * length.  Return a pointer to a split_t containing the split fields, or NULL
35420ba2cbe9Sxc151355  * on failure.
35430ba2cbe9Sxc151355  */
35440ba2cbe9Sxc151355 static split_t *
35450ba2cbe9Sxc151355 split(const char *str, uint_t maxfields, uint_t maxlen)
35460ba2cbe9Sxc151355 {
35470ba2cbe9Sxc151355 	char	*field, *token, *lasts = NULL;
35480ba2cbe9Sxc151355 	split_t	*sp;
35490ba2cbe9Sxc151355 
35500ba2cbe9Sxc151355 	if (*str == '\0' || maxfields == 0 || maxlen == 0)
35510ba2cbe9Sxc151355 		return (NULL);
35520ba2cbe9Sxc151355 
35530ba2cbe9Sxc151355 	sp = calloc(sizeof (split_t), 1);
35540ba2cbe9Sxc151355 	if (sp == NULL)
35550ba2cbe9Sxc151355 		return (NULL);
35560ba2cbe9Sxc151355 
35570ba2cbe9Sxc151355 	sp->s_buf = strdup(str);
35580ba2cbe9Sxc151355 	sp->s_fields = malloc(sizeof (char *) * maxfields);
35590ba2cbe9Sxc151355 	if (sp->s_buf == NULL || sp->s_fields == NULL)
35600ba2cbe9Sxc151355 		goto fail;
35610ba2cbe9Sxc151355 
35620ba2cbe9Sxc151355 	token = sp->s_buf;
35630ba2cbe9Sxc151355 	while ((field = strtok_r(token, ",", &lasts)) != NULL) {
35640ba2cbe9Sxc151355 		if (sp->s_nfields == maxfields || strlen(field) > maxlen)
35650ba2cbe9Sxc151355 			goto fail;
35660ba2cbe9Sxc151355 		token = NULL;
35670ba2cbe9Sxc151355 		sp->s_fields[sp->s_nfields++] = field;
35680ba2cbe9Sxc151355 	}
35690ba2cbe9Sxc151355 	return (sp);
35700ba2cbe9Sxc151355 fail:
35710ba2cbe9Sxc151355 	splitfree(sp);
35720ba2cbe9Sxc151355 	return (NULL);
35730ba2cbe9Sxc151355 }
35740ba2cbe9Sxc151355 
35750ba2cbe9Sxc151355 static int
3576*e7801d59Ssowmini parse_wifi_fields(char *str, print_field_t ***fields, uint_t *countp,
35770ba2cbe9Sxc151355     uint_t cmdtype)
35780ba2cbe9Sxc151355 {
35790ba2cbe9Sxc151355 
35800ba2cbe9Sxc151355 	if (cmdtype == WIFI_CMD_SCAN) {
35810ba2cbe9Sxc151355 		if (str == NULL)
35820ba2cbe9Sxc151355 			str = def_scan_wifi_fields;
35830ba2cbe9Sxc151355 		if (strcasecmp(str, "all") == 0)
35840ba2cbe9Sxc151355 			str = all_scan_wifi_fields;
35850ba2cbe9Sxc151355 	} else if (cmdtype == WIFI_CMD_SHOW) {
35860ba2cbe9Sxc151355 		if (str == NULL)
35870ba2cbe9Sxc151355 			str = def_show_wifi_fields;
35880ba2cbe9Sxc151355 		if (strcasecmp(str, "all") == 0)
35890ba2cbe9Sxc151355 			str = all_show_wifi_fields;
35900ba2cbe9Sxc151355 	} else {
35910ba2cbe9Sxc151355 		return (-1);
35920ba2cbe9Sxc151355 	}
3593*e7801d59Ssowmini 	*fields = parse_output_fields(str, wifi_fields, WIFI_MAX_FIELDS,
3594*e7801d59Ssowmini 	    cmdtype, countp);
3595*e7801d59Ssowmini 	if (*fields != NULL)
3596*e7801d59Ssowmini 		return (0);
35970ba2cbe9Sxc151355 	return (-1);
3598*e7801d59Ssowmini }
3599*e7801d59Ssowmini static print_field_t **
3600*e7801d59Ssowmini parse_output_fields(char *str, print_field_t *template, int max_fields,
3601*e7801d59Ssowmini     uint_t cmdtype, uint_t *countp)
3602*e7801d59Ssowmini {
3603*e7801d59Ssowmini 	split_t		*sp;
3604*e7801d59Ssowmini 	boolean_t	good_match = B_FALSE;
3605*e7801d59Ssowmini 	uint_t		i, j;
3606*e7801d59Ssowmini 	print_field_t	**pf = NULL;
36070ba2cbe9Sxc151355 
3608*e7801d59Ssowmini 	sp = split(str, max_fields, MAX_FIELD_LEN);
3609*e7801d59Ssowmini 
3610*e7801d59Ssowmini 	if (sp == NULL)
3611*e7801d59Ssowmini 		return (NULL);
3612*e7801d59Ssowmini 
3613*e7801d59Ssowmini 	pf = malloc(sp->s_nfields * sizeof (print_field_t *));
3614*e7801d59Ssowmini 	if (pf == NULL)
36150ba2cbe9Sxc151355 		goto fail;
36160ba2cbe9Sxc151355 
36170ba2cbe9Sxc151355 	for (i = 0; i < sp->s_nfields; i++) {
3618*e7801d59Ssowmini 		for (j = 0; j < max_fields; j++) {
36190ba2cbe9Sxc151355 			if (strcasecmp(sp->s_fields[i],
3620*e7801d59Ssowmini 			    template[j].pf_name) == 0) {
3621*e7801d59Ssowmini 				good_match = template[j]. pf_cmdtype & cmdtype;
36220ba2cbe9Sxc151355 				break;
36230ba2cbe9Sxc151355 			}
36240ba2cbe9Sxc151355 		}
36250ba2cbe9Sxc151355 		if (!good_match)
36260ba2cbe9Sxc151355 			goto fail;
36270ba2cbe9Sxc151355 
36280ba2cbe9Sxc151355 		good_match = B_FALSE;
3629*e7801d59Ssowmini 		pf[i] = &template[j];
36300ba2cbe9Sxc151355 	}
36310ba2cbe9Sxc151355 	*countp = i;
36320ba2cbe9Sxc151355 	splitfree(sp);
3633*e7801d59Ssowmini 	return (pf);
36340ba2cbe9Sxc151355 fail:
3635*e7801d59Ssowmini 	free(pf);
36360ba2cbe9Sxc151355 	splitfree(sp);
3637*e7801d59Ssowmini 	return (NULL);
36380ba2cbe9Sxc151355 }
36390ba2cbe9Sxc151355 
36400ba2cbe9Sxc151355 typedef struct print_wifi_state {
3641d62bc4baSyz147064 	char		*ws_link;
36420ba2cbe9Sxc151355 	boolean_t	ws_parseable;
36430ba2cbe9Sxc151355 	boolean_t	ws_header;
3644*e7801d59Ssowmini 	print_state_t	ws_print_state;
36450ba2cbe9Sxc151355 } print_wifi_state_t;
36460ba2cbe9Sxc151355 
3647*e7801d59Ssowmini typedef struct  wlan_scan_args_s {
3648*e7801d59Ssowmini 	print_wifi_state_t	*ws_state;
3649*e7801d59Ssowmini 	void			*ws_attr;
3650*e7801d59Ssowmini } wlan_scan_args_t;
36510ba2cbe9Sxc151355 
36520ba2cbe9Sxc151355 
36530ba2cbe9Sxc151355 static void
3654*e7801d59Ssowmini print_field(print_state_t *statep, print_field_t *pfp, const char *value,
3655*e7801d59Ssowmini     boolean_t parseable)
36560ba2cbe9Sxc151355 {
3657*e7801d59Ssowmini 	uint_t	width = pfp->pf_width;
36580ba2cbe9Sxc151355 	uint_t	valwidth = strlen(value);
36590ba2cbe9Sxc151355 	uint_t	compress;
36600ba2cbe9Sxc151355 
3661*e7801d59Ssowmini 	if (parseable) {
3662*e7801d59Ssowmini 		(void) printf("%s=\"%s\"", pfp->pf_header, value);
36630ba2cbe9Sxc151355 	} else {
36640ba2cbe9Sxc151355 		if (value[0] == '\0')
3665*e7801d59Ssowmini 			value = STR_UNDEF_VAL;
3666*e7801d59Ssowmini 		if (statep->ps_lastfield) {
36670ba2cbe9Sxc151355 			(void) printf("%s", value);
36680ba2cbe9Sxc151355 			return;
36690ba2cbe9Sxc151355 		}
36700ba2cbe9Sxc151355 
36710ba2cbe9Sxc151355 		if (valwidth > width) {
3672*e7801d59Ssowmini 			statep->ps_overflow += valwidth - width;
3673*e7801d59Ssowmini 		} else if (valwidth < width && statep->ps_overflow > 0) {
3674*e7801d59Ssowmini 			compress = min(statep->ps_overflow, width - valwidth);
3675*e7801d59Ssowmini 			statep->ps_overflow -= compress;
36760ba2cbe9Sxc151355 			width -= compress;
36770ba2cbe9Sxc151355 		}
36780ba2cbe9Sxc151355 		(void) printf("%-*s", width, value);
36790ba2cbe9Sxc151355 	}
36800ba2cbe9Sxc151355 
3681*e7801d59Ssowmini 	if (!statep->ps_lastfield)
36820ba2cbe9Sxc151355 		(void) putchar(' ');
36830ba2cbe9Sxc151355 }
36840ba2cbe9Sxc151355 
3685*e7801d59Ssowmini static char *
3686*e7801d59Ssowmini print_wlan_attr(print_field_t *wfp, void *warg)
36870ba2cbe9Sxc151355 {
3688*e7801d59Ssowmini 	static char		buf[DLADM_STRSIZE];
3689*e7801d59Ssowmini 	wlan_scan_args_t	*w = warg;
3690*e7801d59Ssowmini 	print_wifi_state_t	*statep = w->ws_state;
3691*e7801d59Ssowmini 	dladm_wlan_attr_t	*attrp = w->ws_attr;
36920ba2cbe9Sxc151355 
3693*e7801d59Ssowmini 	if (wfp->pf_index == 0) {
3694*e7801d59Ssowmini 		return ((char *)statep->ws_link);
36950ba2cbe9Sxc151355 	}
36960ba2cbe9Sxc151355 
3697*e7801d59Ssowmini 	if ((wfp->pf_index & attrp->wa_valid) == 0) {
3698*e7801d59Ssowmini 		return ("");
36990ba2cbe9Sxc151355 	}
37000ba2cbe9Sxc151355 
3701*e7801d59Ssowmini 	switch (wfp->pf_index) {
3702f595a68aSyz147064 	case DLADM_WLAN_ATTR_ESSID:
3703*e7801d59Ssowmini 		(void) dladm_wlan_essid2str(&attrp->wa_essid, buf);
37040ba2cbe9Sxc151355 		break;
3705f595a68aSyz147064 	case DLADM_WLAN_ATTR_BSSID:
3706*e7801d59Ssowmini 		(void) dladm_wlan_bssid2str(&attrp->wa_bssid, buf);
37070ba2cbe9Sxc151355 		break;
3708f595a68aSyz147064 	case DLADM_WLAN_ATTR_SECMODE:
3709*e7801d59Ssowmini 		(void) dladm_wlan_secmode2str(&attrp->wa_secmode, buf);
37100ba2cbe9Sxc151355 		break;
3711f595a68aSyz147064 	case DLADM_WLAN_ATTR_STRENGTH:
3712*e7801d59Ssowmini 		(void) dladm_wlan_strength2str(&attrp->wa_strength, buf);
37130ba2cbe9Sxc151355 		break;
3714f595a68aSyz147064 	case DLADM_WLAN_ATTR_MODE:
3715*e7801d59Ssowmini 		(void) dladm_wlan_mode2str(&attrp->wa_mode, buf);
37160ba2cbe9Sxc151355 		break;
3717f595a68aSyz147064 	case DLADM_WLAN_ATTR_SPEED:
3718*e7801d59Ssowmini 		(void) dladm_wlan_speed2str(&attrp->wa_speed, buf);
37190ba2cbe9Sxc151355 		(void) strlcat(buf, "Mb", sizeof (buf));
37200ba2cbe9Sxc151355 		break;
3721f595a68aSyz147064 	case DLADM_WLAN_ATTR_AUTH:
3722*e7801d59Ssowmini 		(void) dladm_wlan_auth2str(&attrp->wa_auth, buf);
37230ba2cbe9Sxc151355 		break;
3724f595a68aSyz147064 	case DLADM_WLAN_ATTR_BSSTYPE:
3725*e7801d59Ssowmini 		(void) dladm_wlan_bsstype2str(&attrp->wa_bsstype, buf);
37260ba2cbe9Sxc151355 		break;
37270ba2cbe9Sxc151355 	}
37280ba2cbe9Sxc151355 
3729*e7801d59Ssowmini 	return (buf);
37300ba2cbe9Sxc151355 }
37310ba2cbe9Sxc151355 
37320ba2cbe9Sxc151355 static boolean_t
3733f595a68aSyz147064 print_scan_results(void *arg, dladm_wlan_attr_t *attrp)
37340ba2cbe9Sxc151355 {
37350ba2cbe9Sxc151355 	print_wifi_state_t	*statep = arg;
3736*e7801d59Ssowmini 	wlan_scan_args_t	warg;
37370ba2cbe9Sxc151355 
37380ba2cbe9Sxc151355 	if (statep->ws_header) {
37390ba2cbe9Sxc151355 		statep->ws_header = B_FALSE;
37400ba2cbe9Sxc151355 		if (!statep->ws_parseable)
3741*e7801d59Ssowmini 			print_header(&statep->ws_print_state);
37420ba2cbe9Sxc151355 	}
37430ba2cbe9Sxc151355 
3744*e7801d59Ssowmini 	statep->ws_print_state.ps_overflow = 0;
3745*e7801d59Ssowmini 	bzero(&warg, sizeof (warg));
3746*e7801d59Ssowmini 	warg.ws_state = statep;
3747*e7801d59Ssowmini 	warg.ws_attr = attrp;
3748*e7801d59Ssowmini 	dladm_print_output(&statep->ws_print_state, statep->ws_parseable,
3749*e7801d59Ssowmini 	    print_wlan_attr, &warg);
37500ba2cbe9Sxc151355 	return (B_TRUE);
37510ba2cbe9Sxc151355 }
37520ba2cbe9Sxc151355 
3753d62bc4baSyz147064 static int
3754d62bc4baSyz147064 scan_wifi(datalink_id_t linkid, void *arg)
37550ba2cbe9Sxc151355 {
37560ba2cbe9Sxc151355 	print_wifi_state_t	*statep = arg;
3757f595a68aSyz147064 	dladm_status_t		status;
3758d62bc4baSyz147064 	char			link[MAXLINKNAMELEN];
3759d62bc4baSyz147064 
3760*e7801d59Ssowmini 	if ((status = dladm_datalink_id2info(linkid, NULL, NULL, NULL, link,
3761*e7801d59Ssowmini 	    sizeof (link))) != DLADM_STATUS_OK) {
3762d62bc4baSyz147064 		return (DLADM_WALK_CONTINUE);
3763d62bc4baSyz147064 	}
37640ba2cbe9Sxc151355 
37650ba2cbe9Sxc151355 	statep->ws_link = link;
3766d62bc4baSyz147064 	status = dladm_wlan_scan(linkid, statep, print_scan_results);
3767f595a68aSyz147064 	if (status != DLADM_STATUS_OK)
3768d62bc4baSyz147064 		die_dlerr(status, "cannot scan link '%s'", statep->ws_link);
376933343a97Smeem 
3770d62bc4baSyz147064 	return (DLADM_WALK_CONTINUE);
37710ba2cbe9Sxc151355 }
37720ba2cbe9Sxc151355 
3773*e7801d59Ssowmini static char *
3774*e7801d59Ssowmini print_link_attr(print_field_t *wfp, void *warg)
37750ba2cbe9Sxc151355 {
3776*e7801d59Ssowmini 	static char		buf[DLADM_STRSIZE];
3777*e7801d59Ssowmini 	char			*ptr;
3778*e7801d59Ssowmini 	wlan_scan_args_t	*w = warg, w1;
3779*e7801d59Ssowmini 	print_wifi_state_t	*statep = w->ws_state;
3780*e7801d59Ssowmini 	dladm_wlan_linkattr_t	*attrp = w->ws_attr;
37810ba2cbe9Sxc151355 
3782*e7801d59Ssowmini 	if (strcmp(wfp->pf_name, "status") == 0) {
3783*e7801d59Ssowmini 		if ((wfp->pf_index & attrp->la_valid) != 0)
3784*e7801d59Ssowmini 			(void) dladm_wlan_linkstatus2str(
3785*e7801d59Ssowmini 			    &attrp->la_status, buf);
3786*e7801d59Ssowmini 		return (buf);
37870ba2cbe9Sxc151355 	}
3788*e7801d59Ssowmini 	statep->ws_print_state.ps_overflow = 0;
3789*e7801d59Ssowmini 	bzero(&w1, sizeof (w1));
3790*e7801d59Ssowmini 	w1.ws_state = statep;
3791*e7801d59Ssowmini 	w1.ws_attr = &attrp->la_wlan_attr;
3792*e7801d59Ssowmini 	ptr = print_wlan_attr(wfp, &w1);
3793*e7801d59Ssowmini 	return (ptr);
37940ba2cbe9Sxc151355 }
37950ba2cbe9Sxc151355 
3796d62bc4baSyz147064 static int
3797d62bc4baSyz147064 show_wifi(datalink_id_t linkid, void *arg)
37980ba2cbe9Sxc151355 {
37990ba2cbe9Sxc151355 	print_wifi_state_t	*statep = arg;
3800f595a68aSyz147064 	dladm_wlan_linkattr_t	attr;
3801f595a68aSyz147064 	dladm_status_t		status;
3802d62bc4baSyz147064 	char			link[MAXLINKNAMELEN];
3803*e7801d59Ssowmini 	wlan_scan_args_t	warg;
38040ba2cbe9Sxc151355 
3805*e7801d59Ssowmini 	if ((status = dladm_datalink_id2info(linkid, NULL, NULL, NULL, link,
3806*e7801d59Ssowmini 	    sizeof (link))) != DLADM_STATUS_OK) {
3807d62bc4baSyz147064 		return (DLADM_WALK_CONTINUE);
3808d62bc4baSyz147064 	}
3809d62bc4baSyz147064 
3810d62bc4baSyz147064 	status = dladm_wlan_get_linkattr(linkid, &attr);
3811f595a68aSyz147064 	if (status != DLADM_STATUS_OK)
3812d62bc4baSyz147064 		die_dlerr(status, "cannot get link attributes for %s", link);
3813d62bc4baSyz147064 
3814d62bc4baSyz147064 	statep->ws_link = link;
38150ba2cbe9Sxc151355 
38160ba2cbe9Sxc151355 	if (statep->ws_header) {
38170ba2cbe9Sxc151355 		statep->ws_header = B_FALSE;
38180ba2cbe9Sxc151355 		if (!statep->ws_parseable)
3819*e7801d59Ssowmini 			print_header(&statep->ws_print_state);
38200ba2cbe9Sxc151355 	}
38210ba2cbe9Sxc151355 
3822*e7801d59Ssowmini 	statep->ws_print_state.ps_overflow = 0;
3823*e7801d59Ssowmini 	bzero(&warg, sizeof (warg));
3824*e7801d59Ssowmini 	warg.ws_state = statep;
3825*e7801d59Ssowmini 	warg.ws_attr = &attr;
3826*e7801d59Ssowmini 	dladm_print_output(&statep->ws_print_state, statep->ws_parseable,
3827*e7801d59Ssowmini 	    print_link_attr, &warg);
3828d62bc4baSyz147064 	return (DLADM_WALK_CONTINUE);
38290ba2cbe9Sxc151355 }
38300ba2cbe9Sxc151355 
38310ba2cbe9Sxc151355 static void
38320ba2cbe9Sxc151355 do_display_wifi(int argc, char **argv, int cmd)
38330ba2cbe9Sxc151355 {
38340ba2cbe9Sxc151355 	int			option;
38350ba2cbe9Sxc151355 	char			*fields_str = NULL;
3836*e7801d59Ssowmini 	print_field_t		**fields;
3837d62bc4baSyz147064 	int			(*callback)(datalink_id_t, void *);
38380ba2cbe9Sxc151355 	uint_t			nfields;
38390ba2cbe9Sxc151355 	print_wifi_state_t	state;
3840d62bc4baSyz147064 	datalink_id_t		linkid = DATALINK_ALL_LINKID;
3841f595a68aSyz147064 	dladm_status_t		status;
38420ba2cbe9Sxc151355 
38430ba2cbe9Sxc151355 	if (cmd == WIFI_CMD_SCAN)
38440ba2cbe9Sxc151355 		callback = scan_wifi;
38450ba2cbe9Sxc151355 	else if (cmd == WIFI_CMD_SHOW)
38460ba2cbe9Sxc151355 		callback = show_wifi;
38470ba2cbe9Sxc151355 	else
38480ba2cbe9Sxc151355 		return;
38490ba2cbe9Sxc151355 
38500ba2cbe9Sxc151355 	state.ws_parseable = B_FALSE;
38510ba2cbe9Sxc151355 	state.ws_header = B_TRUE;
38520ba2cbe9Sxc151355 	opterr = 0;
38530ba2cbe9Sxc151355 	while ((option = getopt_long(argc, argv, ":o:p",
38540ba2cbe9Sxc151355 	    wifi_longopts, NULL)) != -1) {
38550ba2cbe9Sxc151355 		switch (option) {
38560ba2cbe9Sxc151355 		case 'o':
38570ba2cbe9Sxc151355 			fields_str = optarg;
38580ba2cbe9Sxc151355 			break;
38590ba2cbe9Sxc151355 		case 'p':
38600ba2cbe9Sxc151355 			state.ws_parseable = B_TRUE;
38610ba2cbe9Sxc151355 			if (fields_str == NULL)
38620ba2cbe9Sxc151355 				fields_str = "all";
38630ba2cbe9Sxc151355 			break;
38640ba2cbe9Sxc151355 		default:
386533343a97Smeem 			die_opterr(optopt, option);
38660ba2cbe9Sxc151355 			break;
38670ba2cbe9Sxc151355 		}
38680ba2cbe9Sxc151355 	}
38690ba2cbe9Sxc151355 
3870d62bc4baSyz147064 	if (optind == (argc - 1)) {
3871d62bc4baSyz147064 		if ((status = dladm_name2info(argv[optind], &linkid, NULL,
3872d62bc4baSyz147064 		    NULL, NULL)) != DLADM_STATUS_OK) {
3873d62bc4baSyz147064 			die_dlerr(status, "link %s is not valid", argv[optind]);
3874d62bc4baSyz147064 		}
3875d62bc4baSyz147064 	} else if (optind != argc) {
38760ba2cbe9Sxc151355 		usage();
3877d62bc4baSyz147064 	}
38780ba2cbe9Sxc151355 
387933343a97Smeem 	if (parse_wifi_fields(fields_str, &fields, &nfields, cmd) < 0)
388033343a97Smeem 		die("invalid field(s) specified");
388133343a97Smeem 
3882*e7801d59Ssowmini 	bzero(&state.ws_print_state, sizeof (state.ws_print_state));
3883*e7801d59Ssowmini 	state.ws_print_state.ps_fields = fields;
3884*e7801d59Ssowmini 	state.ws_print_state.ps_nfields = nfields;
38850ba2cbe9Sxc151355 
3886d62bc4baSyz147064 	if (linkid == DATALINK_ALL_LINKID) {
3887d62bc4baSyz147064 		(void) dladm_walk_datalink_id(callback, &state,
3888d62bc4baSyz147064 		    DATALINK_CLASS_PHYS, DL_WIFI, DLADM_OPT_ACTIVE);
38890ba2cbe9Sxc151355 	} else {
3890d62bc4baSyz147064 		(void) (*callback)(linkid, &state);
38910ba2cbe9Sxc151355 	}
38920ba2cbe9Sxc151355 	free(fields);
38930ba2cbe9Sxc151355 }
38940ba2cbe9Sxc151355 
38950ba2cbe9Sxc151355 static void
38960ba2cbe9Sxc151355 do_scan_wifi(int argc, char **argv)
38970ba2cbe9Sxc151355 {
38980ba2cbe9Sxc151355 	do_display_wifi(argc, argv, WIFI_CMD_SCAN);
38990ba2cbe9Sxc151355 }
39000ba2cbe9Sxc151355 
39010ba2cbe9Sxc151355 static void
39020ba2cbe9Sxc151355 do_show_wifi(int argc, char **argv)
39030ba2cbe9Sxc151355 {
39040ba2cbe9Sxc151355 	do_display_wifi(argc, argv, WIFI_CMD_SHOW);
39050ba2cbe9Sxc151355 }
39060ba2cbe9Sxc151355 
39070ba2cbe9Sxc151355 typedef struct wlan_count_attr {
39080ba2cbe9Sxc151355 	uint_t		wc_count;
3909d62bc4baSyz147064 	datalink_id_t	wc_linkid;
39100ba2cbe9Sxc151355 } wlan_count_attr_t;
39110ba2cbe9Sxc151355 
3912d62bc4baSyz147064 static int
3913d62bc4baSyz147064 do_count_wlan(datalink_id_t linkid, void *arg)
39140ba2cbe9Sxc151355 {
391533343a97Smeem 	wlan_count_attr_t *cp = arg;
39160ba2cbe9Sxc151355 
39170ba2cbe9Sxc151355 	if (cp->wc_count == 0)
3918d62bc4baSyz147064 		cp->wc_linkid = linkid;
39190ba2cbe9Sxc151355 	cp->wc_count++;
3920d62bc4baSyz147064 	return (DLADM_WALK_CONTINUE);
39210ba2cbe9Sxc151355 }
39220ba2cbe9Sxc151355 
39230ba2cbe9Sxc151355 static int
3924a399b765Szf162725 parse_wlan_keys(char *str, dladm_wlan_key_t **keys, uint_t *key_countp)
39250ba2cbe9Sxc151355 {
39260ba2cbe9Sxc151355 	uint_t			i;
39270ba2cbe9Sxc151355 	split_t			*sp;
3928a399b765Szf162725 	dladm_wlan_key_t	*wk;
39290ba2cbe9Sxc151355 
3930a399b765Szf162725 	sp = split(str, DLADM_WLAN_MAX_WEPKEYS, DLADM_WLAN_MAX_KEYNAME_LEN);
39310ba2cbe9Sxc151355 	if (sp == NULL)
39320ba2cbe9Sxc151355 		return (-1);
39330ba2cbe9Sxc151355 
3934a399b765Szf162725 	wk = malloc(sp->s_nfields * sizeof (dladm_wlan_key_t));
39350ba2cbe9Sxc151355 	if (wk == NULL)
39360ba2cbe9Sxc151355 		goto fail;
39370ba2cbe9Sxc151355 
39380ba2cbe9Sxc151355 	for (i = 0; i < sp->s_nfields; i++) {
39390ba2cbe9Sxc151355 		char			*s;
39400ba2cbe9Sxc151355 		dladm_secobj_class_t	class;
39410ba2cbe9Sxc151355 		dladm_status_t		status;
39420ba2cbe9Sxc151355 
39430ba2cbe9Sxc151355 		(void) strlcpy(wk[i].wk_name, sp->s_fields[i],
3944a399b765Szf162725 		    DLADM_WLAN_MAX_KEYNAME_LEN);
39450ba2cbe9Sxc151355 
39460ba2cbe9Sxc151355 		wk[i].wk_idx = 1;
39470ba2cbe9Sxc151355 		if ((s = strrchr(wk[i].wk_name, ':')) != NULL) {
39480ba2cbe9Sxc151355 			if (s[1] == '\0' || s[2] != '\0' || !isdigit(s[1]))
39490ba2cbe9Sxc151355 				goto fail;
39500ba2cbe9Sxc151355 
39510ba2cbe9Sxc151355 			wk[i].wk_idx = (uint_t)(s[1] - '0');
39520ba2cbe9Sxc151355 			*s = '\0';
39530ba2cbe9Sxc151355 		}
3954a399b765Szf162725 		wk[i].wk_len = DLADM_WLAN_MAX_KEY_LEN;
39550ba2cbe9Sxc151355 
39560ba2cbe9Sxc151355 		status = dladm_get_secobj(wk[i].wk_name, &class,
39570ba2cbe9Sxc151355 		    wk[i].wk_val, &wk[i].wk_len, 0);
39580ba2cbe9Sxc151355 		if (status != DLADM_STATUS_OK) {
39590ba2cbe9Sxc151355 			if (status == DLADM_STATUS_NOTFOUND) {
39600ba2cbe9Sxc151355 				status = dladm_get_secobj(wk[i].wk_name,
39610ba2cbe9Sxc151355 				    &class, wk[i].wk_val, &wk[i].wk_len,
39620ba2cbe9Sxc151355 				    DLADM_OPT_PERSIST);
39630ba2cbe9Sxc151355 			}
39640ba2cbe9Sxc151355 			if (status != DLADM_STATUS_OK)
39650ba2cbe9Sxc151355 				goto fail;
39660ba2cbe9Sxc151355 		}
3967a399b765Szf162725 		wk[i].wk_class = class;
39680ba2cbe9Sxc151355 	}
39690ba2cbe9Sxc151355 	*keys = wk;
39700ba2cbe9Sxc151355 	*key_countp = i;
39710ba2cbe9Sxc151355 	splitfree(sp);
39720ba2cbe9Sxc151355 	return (0);
39730ba2cbe9Sxc151355 fail:
39740ba2cbe9Sxc151355 	free(wk);
39750ba2cbe9Sxc151355 	splitfree(sp);
39760ba2cbe9Sxc151355 	return (-1);
39770ba2cbe9Sxc151355 }
39780ba2cbe9Sxc151355 
39790ba2cbe9Sxc151355 static void
39800ba2cbe9Sxc151355 do_connect_wifi(int argc, char **argv)
39810ba2cbe9Sxc151355 {
39820ba2cbe9Sxc151355 	int			option;
3983f595a68aSyz147064 	dladm_wlan_attr_t	attr, *attrp;
3984f595a68aSyz147064 	dladm_status_t		status = DLADM_STATUS_OK;
3985f595a68aSyz147064 	int			timeout = DLADM_WLAN_CONNECT_TIMEOUT_DEFAULT;
3986d62bc4baSyz147064 	datalink_id_t		linkid = DATALINK_ALL_LINKID;
3987a399b765Szf162725 	dladm_wlan_key_t	*keys = NULL;
39880ba2cbe9Sxc151355 	uint_t			key_count = 0;
39890ba2cbe9Sxc151355 	uint_t			flags = 0;
3990f595a68aSyz147064 	dladm_wlan_secmode_t	keysecmode = DLADM_WLAN_SECMODE_NONE;
3991a399b765Szf162725 	char			buf[DLADM_STRSIZE];
39920ba2cbe9Sxc151355 
39930ba2cbe9Sxc151355 	opterr = 0;
39940ba2cbe9Sxc151355 	(void) memset(&attr, 0, sizeof (attr));
39950ba2cbe9Sxc151355 	while ((option = getopt_long(argc, argv, ":e:i:a:m:b:s:k:T:c",
39960ba2cbe9Sxc151355 	    wifi_longopts, NULL)) != -1) {
39970ba2cbe9Sxc151355 		switch (option) {
39980ba2cbe9Sxc151355 		case 'e':
3999f595a68aSyz147064 			status = dladm_wlan_str2essid(optarg, &attr.wa_essid);
4000f595a68aSyz147064 			if (status != DLADM_STATUS_OK)
400133343a97Smeem 				die("invalid ESSID '%s'", optarg);
400233343a97Smeem 
4003f595a68aSyz147064 			attr.wa_valid |= DLADM_WLAN_ATTR_ESSID;
40040ba2cbe9Sxc151355 			/*
40050ba2cbe9Sxc151355 			 * Try to connect without doing a scan.
40060ba2cbe9Sxc151355 			 */
4007f595a68aSyz147064 			flags |= DLADM_WLAN_CONNECT_NOSCAN;
40080ba2cbe9Sxc151355 			break;
40090ba2cbe9Sxc151355 		case 'i':
4010f595a68aSyz147064 			status = dladm_wlan_str2bssid(optarg, &attr.wa_bssid);
4011f595a68aSyz147064 			if (status != DLADM_STATUS_OK)
401233343a97Smeem 				die("invalid BSSID %s", optarg);
401333343a97Smeem 
4014f595a68aSyz147064 			attr.wa_valid |= DLADM_WLAN_ATTR_BSSID;
40150ba2cbe9Sxc151355 			break;
40160ba2cbe9Sxc151355 		case 'a':
4017f595a68aSyz147064 			status = dladm_wlan_str2auth(optarg, &attr.wa_auth);
4018f595a68aSyz147064 			if (status != DLADM_STATUS_OK)
401933343a97Smeem 				die("invalid authentication mode '%s'", optarg);
402033343a97Smeem 
4021f595a68aSyz147064 			attr.wa_valid |= DLADM_WLAN_ATTR_AUTH;
40220ba2cbe9Sxc151355 			break;
40230ba2cbe9Sxc151355 		case 'm':
4024f595a68aSyz147064 			status = dladm_wlan_str2mode(optarg, &attr.wa_mode);
4025f595a68aSyz147064 			if (status != DLADM_STATUS_OK)
402633343a97Smeem 				die("invalid mode '%s'", optarg);
402733343a97Smeem 
4028f595a68aSyz147064 			attr.wa_valid |= DLADM_WLAN_ATTR_MODE;
40290ba2cbe9Sxc151355 			break;
40300ba2cbe9Sxc151355 		case 'b':
4031f595a68aSyz147064 			if ((status = dladm_wlan_str2bsstype(optarg,
4032f595a68aSyz147064 			    &attr.wa_bsstype)) != DLADM_STATUS_OK) {
403333343a97Smeem 				die("invalid bsstype '%s'", optarg);
4034f595a68aSyz147064 			}
403533343a97Smeem 
4036f595a68aSyz147064 			attr.wa_valid |= DLADM_WLAN_ATTR_BSSTYPE;
40370ba2cbe9Sxc151355 			break;
40380ba2cbe9Sxc151355 		case 's':
4039f595a68aSyz147064 			if ((status = dladm_wlan_str2secmode(optarg,
4040f595a68aSyz147064 			    &attr.wa_secmode)) != DLADM_STATUS_OK) {
404133343a97Smeem 				die("invalid security mode '%s'", optarg);
4042f595a68aSyz147064 			}
404333343a97Smeem 
4044f595a68aSyz147064 			attr.wa_valid |= DLADM_WLAN_ATTR_SECMODE;
40450ba2cbe9Sxc151355 			break;
40460ba2cbe9Sxc151355 		case 'k':
4047a399b765Szf162725 			if (parse_wlan_keys(optarg, &keys, &key_count) < 0)
404833343a97Smeem 				die("invalid key(s) '%s'", optarg);
404933343a97Smeem 
4050a399b765Szf162725 			if (keys[0].wk_class == DLADM_SECOBJ_CLASS_WEP)
4051f595a68aSyz147064 				keysecmode = DLADM_WLAN_SECMODE_WEP;
4052a399b765Szf162725 			else
4053a399b765Szf162725 				keysecmode = DLADM_WLAN_SECMODE_WPA;
40540ba2cbe9Sxc151355 			break;
40550ba2cbe9Sxc151355 		case 'T':
40560ba2cbe9Sxc151355 			if (strcasecmp(optarg, "forever") == 0) {
40570ba2cbe9Sxc151355 				timeout = -1;
40580ba2cbe9Sxc151355 				break;
40590ba2cbe9Sxc151355 			}
406033343a97Smeem 			if (!str2int(optarg, &timeout) || timeout < 0)
406133343a97Smeem 				die("invalid timeout value '%s'", optarg);
40620ba2cbe9Sxc151355 			break;
40630ba2cbe9Sxc151355 		case 'c':
4064f595a68aSyz147064 			flags |= DLADM_WLAN_CONNECT_CREATEIBSS;
4065a399b765Szf162725 			flags |= DLADM_WLAN_CONNECT_CREATEIBSS;
40660ba2cbe9Sxc151355 			break;
40670ba2cbe9Sxc151355 		default:
406833343a97Smeem 			die_opterr(optopt, option);
40690ba2cbe9Sxc151355 			break;
40700ba2cbe9Sxc151355 		}
40710ba2cbe9Sxc151355 	}
40720ba2cbe9Sxc151355 
4073f595a68aSyz147064 	if (keysecmode == DLADM_WLAN_SECMODE_NONE) {
4074a399b765Szf162725 		if ((attr.wa_valid & DLADM_WLAN_ATTR_SECMODE) != 0) {
4075a399b765Szf162725 			die("key required for security mode '%s'",
4076a399b765Szf162725 			    dladm_wlan_secmode2str(&attr.wa_secmode, buf));
4077a399b765Szf162725 		}
40780ba2cbe9Sxc151355 	} else {
4079f595a68aSyz147064 		if ((attr.wa_valid & DLADM_WLAN_ATTR_SECMODE) != 0 &&
408033343a97Smeem 		    attr.wa_secmode != keysecmode)
408133343a97Smeem 			die("incompatible -s and -k options");
4082f595a68aSyz147064 		attr.wa_valid |= DLADM_WLAN_ATTR_SECMODE;
4083a399b765Szf162725 		attr.wa_secmode = keysecmode;
4084a399b765Szf162725 	}
40850ba2cbe9Sxc151355 
4086d62bc4baSyz147064 	if (optind == (argc - 1)) {
4087d62bc4baSyz147064 		if ((status = dladm_name2info(argv[optind], &linkid, NULL,
4088d62bc4baSyz147064 		    NULL, NULL)) != DLADM_STATUS_OK) {
4089d62bc4baSyz147064 			die_dlerr(status, "link %s is not valid", argv[optind]);
4090d62bc4baSyz147064 		}
4091d62bc4baSyz147064 	} else if (optind != argc) {
40920ba2cbe9Sxc151355 		usage();
4093d62bc4baSyz147064 	}
40940ba2cbe9Sxc151355 
4095d62bc4baSyz147064 	if (linkid == DATALINK_ALL_LINKID) {
40960ba2cbe9Sxc151355 		wlan_count_attr_t wcattr;
40970ba2cbe9Sxc151355 
4098d62bc4baSyz147064 		wcattr.wc_linkid = DATALINK_INVALID_LINKID;
40990ba2cbe9Sxc151355 		wcattr.wc_count = 0;
4100d62bc4baSyz147064 		(void) dladm_walk_datalink_id(do_count_wlan, &wcattr,
4101d62bc4baSyz147064 		    DATALINK_CLASS_PHYS, DL_WIFI, DLADM_OPT_ACTIVE);
41020ba2cbe9Sxc151355 		if (wcattr.wc_count == 0) {
410333343a97Smeem 			die("no wifi links are available");
41040ba2cbe9Sxc151355 		} else if (wcattr.wc_count > 1) {
410533343a97Smeem 			die("link name is required when more than one wifi "
410633343a97Smeem 			    "link is available");
41070ba2cbe9Sxc151355 		}
4108d62bc4baSyz147064 		linkid = wcattr.wc_linkid;
41090ba2cbe9Sxc151355 	}
41100ba2cbe9Sxc151355 	attrp = (attr.wa_valid == 0) ? NULL : &attr;
411133343a97Smeem again:
4112d62bc4baSyz147064 	if ((status = dladm_wlan_connect(linkid, attrp, timeout, keys,
4113f595a68aSyz147064 	    key_count, flags)) != DLADM_STATUS_OK) {
4114f595a68aSyz147064 		if ((flags & DLADM_WLAN_CONNECT_NOSCAN) != 0) {
41150ba2cbe9Sxc151355 			/*
411633343a97Smeem 			 * Try again with scanning and filtering.
41170ba2cbe9Sxc151355 			 */
4118f595a68aSyz147064 			flags &= ~DLADM_WLAN_CONNECT_NOSCAN;
411933343a97Smeem 			goto again;
41200ba2cbe9Sxc151355 		}
412133343a97Smeem 
4122f595a68aSyz147064 		if (status == DLADM_STATUS_NOTFOUND) {
41230ba2cbe9Sxc151355 			if (attr.wa_valid == 0) {
412433343a97Smeem 				die("no wifi networks are available");
41250ba2cbe9Sxc151355 			} else {
412633343a97Smeem 				die("no wifi networks with the specified "
412733343a97Smeem 				    "criteria are available");
41280ba2cbe9Sxc151355 			}
41290ba2cbe9Sxc151355 		}
4130d62bc4baSyz147064 		die_dlerr(status, "cannot connect");
41310ba2cbe9Sxc151355 	}
41320ba2cbe9Sxc151355 	free(keys);
41330ba2cbe9Sxc151355 }
41340ba2cbe9Sxc151355 
41350ba2cbe9Sxc151355 /* ARGSUSED */
4136d62bc4baSyz147064 static int
4137d62bc4baSyz147064 do_all_disconnect_wifi(datalink_id_t linkid, void *arg)
41380ba2cbe9Sxc151355 {
4139f595a68aSyz147064 	dladm_status_t	status;
41400ba2cbe9Sxc151355 
4141d62bc4baSyz147064 	status = dladm_wlan_disconnect(linkid);
4142f595a68aSyz147064 	if (status != DLADM_STATUS_OK)
4143d62bc4baSyz147064 		warn_dlerr(status, "cannot disconnect link");
414433343a97Smeem 
4145d62bc4baSyz147064 	return (DLADM_WALK_CONTINUE);
41460ba2cbe9Sxc151355 }
41470ba2cbe9Sxc151355 
41480ba2cbe9Sxc151355 static void
41490ba2cbe9Sxc151355 do_disconnect_wifi(int argc, char **argv)
41500ba2cbe9Sxc151355 {
41510ba2cbe9Sxc151355 	int			option;
4152d62bc4baSyz147064 	datalink_id_t		linkid = DATALINK_ALL_LINKID;
41530ba2cbe9Sxc151355 	boolean_t		all_links = B_FALSE;
4154f595a68aSyz147064 	dladm_status_t		status;
41550ba2cbe9Sxc151355 	wlan_count_attr_t	wcattr;
41560ba2cbe9Sxc151355 
41570ba2cbe9Sxc151355 	opterr = 0;
41580ba2cbe9Sxc151355 	while ((option = getopt_long(argc, argv, ":a",
41590ba2cbe9Sxc151355 	    wifi_longopts, NULL)) != -1) {
41600ba2cbe9Sxc151355 		switch (option) {
41610ba2cbe9Sxc151355 		case 'a':
41620ba2cbe9Sxc151355 			all_links = B_TRUE;
41630ba2cbe9Sxc151355 			break;
41640ba2cbe9Sxc151355 		default:
416533343a97Smeem 			die_opterr(optopt, option);
41660ba2cbe9Sxc151355 			break;
41670ba2cbe9Sxc151355 		}
41680ba2cbe9Sxc151355 	}
41690ba2cbe9Sxc151355 
4170d62bc4baSyz147064 	if (optind == (argc - 1)) {
4171d62bc4baSyz147064 		if ((status = dladm_name2info(argv[optind], &linkid, NULL,
4172d62bc4baSyz147064 		    NULL, NULL)) != DLADM_STATUS_OK) {
4173d62bc4baSyz147064 			die_dlerr(status, "link %s is not valid", argv[optind]);
4174d62bc4baSyz147064 		}
4175d62bc4baSyz147064 	} else if (optind != argc) {
41760ba2cbe9Sxc151355 		usage();
4177d62bc4baSyz147064 	}
41780ba2cbe9Sxc151355 
4179d62bc4baSyz147064 	if (linkid == DATALINK_ALL_LINKID) {
41800ba2cbe9Sxc151355 		if (!all_links) {
4181d62bc4baSyz147064 			wcattr.wc_linkid = linkid;
41820ba2cbe9Sxc151355 			wcattr.wc_count = 0;
4183d62bc4baSyz147064 			(void) dladm_walk_datalink_id(do_count_wlan, &wcattr,
4184d62bc4baSyz147064 			    DATALINK_CLASS_PHYS, DL_WIFI, DLADM_OPT_ACTIVE);
41850ba2cbe9Sxc151355 			if (wcattr.wc_count == 0) {
418633343a97Smeem 				die("no wifi links are available");
41870ba2cbe9Sxc151355 			} else if (wcattr.wc_count > 1) {
418833343a97Smeem 				die("link name is required when more than "
418933343a97Smeem 				    "one wifi link is available");
41900ba2cbe9Sxc151355 			}
4191d62bc4baSyz147064 			linkid = wcattr.wc_linkid;
41920ba2cbe9Sxc151355 		} else {
4193d62bc4baSyz147064 			(void) dladm_walk_datalink_id(do_all_disconnect_wifi,
4194d62bc4baSyz147064 			    NULL, DATALINK_CLASS_PHYS, DL_WIFI,
4195d62bc4baSyz147064 			    DLADM_OPT_ACTIVE);
41960ba2cbe9Sxc151355 			return;
41970ba2cbe9Sxc151355 		}
41980ba2cbe9Sxc151355 	}
4199d62bc4baSyz147064 	status = dladm_wlan_disconnect(linkid);
4200f595a68aSyz147064 	if (status != DLADM_STATUS_OK)
4201d62bc4baSyz147064 		die_dlerr(status, "cannot disconnect");
42020ba2cbe9Sxc151355 }
42030ba2cbe9Sxc151355 
42040ba2cbe9Sxc151355 
42050ba2cbe9Sxc151355 static void
42060ba2cbe9Sxc151355 free_props(prop_list_t *list)
42070ba2cbe9Sxc151355 {
42080ba2cbe9Sxc151355 	if (list != NULL) {
42090ba2cbe9Sxc151355 		free(list->pl_buf);
42100ba2cbe9Sxc151355 		free(list);
42110ba2cbe9Sxc151355 	}
42120ba2cbe9Sxc151355 }
42130ba2cbe9Sxc151355 
42140ba2cbe9Sxc151355 static int
42150ba2cbe9Sxc151355 parse_props(char *str, prop_list_t **listp, boolean_t novalues)
42160ba2cbe9Sxc151355 {
42170ba2cbe9Sxc151355 	prop_list_t	*list;
42180ba2cbe9Sxc151355 	prop_info_t	*pip;
42190ba2cbe9Sxc151355 	char		*buf, *curr;
42200ba2cbe9Sxc151355 	int		len, i;
42210ba2cbe9Sxc151355 
42220ba2cbe9Sxc151355 	list = malloc(sizeof (prop_list_t));
42230ba2cbe9Sxc151355 	if (list == NULL)
42240ba2cbe9Sxc151355 		return (-1);
42250ba2cbe9Sxc151355 
42260ba2cbe9Sxc151355 	list->pl_count = 0;
42270ba2cbe9Sxc151355 	list->pl_buf = buf = strdup(str);
42280ba2cbe9Sxc151355 	if (buf == NULL)
42290ba2cbe9Sxc151355 		goto fail;
42300ba2cbe9Sxc151355 
4231*e7801d59Ssowmini 	/*
4232*e7801d59Ssowmini 	 * buf is a string of form [<propname>=<value>][,<propname>=<value>]+
4233*e7801d59Ssowmini 	 * where each <value> string itself could be a comma-separated array.
4234*e7801d59Ssowmini 	 * The loop below will count the number of propname assignments
4235*e7801d59Ssowmini 	 * in pl_count; for each property, there is a pip entry with
4236*e7801d59Ssowmini 	 * pi_name == <propname>, pi_count == # of elements in <value> array.
4237*e7801d59Ssowmini 	 * pi_val[] contains the actual values.
4238*e7801d59Ssowmini 	 *
4239*e7801d59Ssowmini 	 * This could really be a combination of  calls to
4240*e7801d59Ssowmini 	 * strtok (token delimiter is ",") and strchr (chr '=')
4241*e7801d59Ssowmini 	 * with appropriate null/string-bound-checks.
4242*e7801d59Ssowmini 	 */
4243*e7801d59Ssowmini 
42440ba2cbe9Sxc151355 	curr = buf;
42450ba2cbe9Sxc151355 	len = strlen(buf);
42460ba2cbe9Sxc151355 	pip = NULL;
42470ba2cbe9Sxc151355 	for (i = 0; i < len; i++) {
42480ba2cbe9Sxc151355 		char		c = buf[i];
42490ba2cbe9Sxc151355 		boolean_t	match = (c == '=' || c == ',');
42500ba2cbe9Sxc151355 
42510ba2cbe9Sxc151355 		if (!match && i != len - 1)
42520ba2cbe9Sxc151355 			continue;
42530ba2cbe9Sxc151355 
42540ba2cbe9Sxc151355 		if (match) {
42550ba2cbe9Sxc151355 			buf[i] = '\0';
42560ba2cbe9Sxc151355 			if (*curr == '\0')
42570ba2cbe9Sxc151355 				goto fail;
42580ba2cbe9Sxc151355 		}
42590ba2cbe9Sxc151355 
42600ba2cbe9Sxc151355 		if (pip != NULL && c != '=') {
4261d62bc4baSyz147064 			if (pip->pi_count > DLADM_MAX_PROP_VALCNT)
42620ba2cbe9Sxc151355 				goto fail;
42630ba2cbe9Sxc151355 
42640ba2cbe9Sxc151355 			if (novalues)
42650ba2cbe9Sxc151355 				goto fail;
42660ba2cbe9Sxc151355 
42670ba2cbe9Sxc151355 			pip->pi_val[pip->pi_count] = curr;
42680ba2cbe9Sxc151355 			pip->pi_count++;
42690ba2cbe9Sxc151355 		} else {
42700ba2cbe9Sxc151355 			if (list->pl_count > MAX_PROPS)
42710ba2cbe9Sxc151355 				goto fail;
42720ba2cbe9Sxc151355 
42730ba2cbe9Sxc151355 			pip = &list->pl_info[list->pl_count];
42740ba2cbe9Sxc151355 			pip->pi_name = curr;
42750ba2cbe9Sxc151355 			pip->pi_count = 0;
42760ba2cbe9Sxc151355 			list->pl_count++;
42770ba2cbe9Sxc151355 			if (c == ',')
42780ba2cbe9Sxc151355 				pip = NULL;
42790ba2cbe9Sxc151355 		}
42800ba2cbe9Sxc151355 		curr = buf + i + 1;
42810ba2cbe9Sxc151355 	}
42820ba2cbe9Sxc151355 	*listp = list;
42830ba2cbe9Sxc151355 	return (0);
42840ba2cbe9Sxc151355 
42850ba2cbe9Sxc151355 fail:
42860ba2cbe9Sxc151355 	free_props(list);
42870ba2cbe9Sxc151355 	return (-1);
42880ba2cbe9Sxc151355 }
42890ba2cbe9Sxc151355 
42900ba2cbe9Sxc151355 static void
4291d62bc4baSyz147064 print_linkprop(datalink_id_t linkid, show_linkprop_state_t *statep,
4292*e7801d59Ssowmini     const char *propname, dladm_prop_type_t type,
4293d62bc4baSyz147064     const char *format, char **pptr)
42940ba2cbe9Sxc151355 {
42950ba2cbe9Sxc151355 	int		i;
42960ba2cbe9Sxc151355 	char		*ptr, *lim;
42970ba2cbe9Sxc151355 	char		buf[DLADM_STRSIZE];
42980ba2cbe9Sxc151355 	char		*unknown = "?", *notsup = "";
42990ba2cbe9Sxc151355 	char		**propvals = statep->ls_propvals;
4300d62bc4baSyz147064 	uint_t		valcnt = DLADM_MAX_PROP_VALCNT;
43010ba2cbe9Sxc151355 	dladm_status_t	status;
43020ba2cbe9Sxc151355 
4303d62bc4baSyz147064 	status = dladm_get_linkprop(linkid, type, propname, propvals, &valcnt);
43040ba2cbe9Sxc151355 	if (status != DLADM_STATUS_OK) {
4305f595a68aSyz147064 		if (status == DLADM_STATUS_TEMPONLY) {
4306d62bc4baSyz147064 			if (type == DLADM_PROP_VAL_MODIFIABLE &&
4307d62bc4baSyz147064 			    statep->ls_persist) {
4308d62bc4baSyz147064 				valcnt = 1;
4309d62bc4baSyz147064 				propvals = &unknown;
4310d62bc4baSyz147064 			} else {
4311f595a68aSyz147064 				statep->ls_status = status;
4312*e7801d59Ssowmini 				statep->ls_retstatus = status;
4313f595a68aSyz147064 				return;
4314d62bc4baSyz147064 			}
4315f595a68aSyz147064 		} else if (status == DLADM_STATUS_NOTSUP ||
4316f595a68aSyz147064 		    statep->ls_persist) {
43170ba2cbe9Sxc151355 			valcnt = 1;
43180ba2cbe9Sxc151355 			if (type == DLADM_PROP_VAL_CURRENT)
43190ba2cbe9Sxc151355 				propvals = &unknown;
43200ba2cbe9Sxc151355 			else
43210ba2cbe9Sxc151355 				propvals = &notsup;
43220ba2cbe9Sxc151355 		} else {
4323*e7801d59Ssowmini 			if (statep->ls_proplist &&
4324*e7801d59Ssowmini 			    statep->ls_status == DLADM_STATUS_OK) {
4325f595a68aSyz147064 				warn_dlerr(status,
4326f595a68aSyz147064 				    "cannot get link property '%s' for %s",
4327f595a68aSyz147064 				    propname, statep->ls_link);
4328d62bc4baSyz147064 			}
4329*e7801d59Ssowmini 			statep->ls_status = status;
4330*e7801d59Ssowmini 			statep->ls_retstatus = status;
4331f595a68aSyz147064 			return;
43320ba2cbe9Sxc151355 		}
43330ba2cbe9Sxc151355 	}
43340ba2cbe9Sxc151355 
4335*e7801d59Ssowmini 	statep->ls_status = DLADM_STATUS_OK;
4336*e7801d59Ssowmini 
43370ba2cbe9Sxc151355 	ptr = buf;
43380ba2cbe9Sxc151355 	lim = buf + DLADM_STRSIZE;
43390ba2cbe9Sxc151355 	for (i = 0; i < valcnt; i++) {
43400ba2cbe9Sxc151355 		if (propvals[i][0] == '\0' && !statep->ls_parseable)
4341*e7801d59Ssowmini 			ptr += snprintf(ptr, lim - ptr, STR_UNDEF_VAL",");
43420ba2cbe9Sxc151355 		else
43430ba2cbe9Sxc151355 			ptr += snprintf(ptr, lim - ptr, "%s,", propvals[i]);
43440ba2cbe9Sxc151355 		if (ptr >= lim)
43450ba2cbe9Sxc151355 			break;
43460ba2cbe9Sxc151355 	}
43470ba2cbe9Sxc151355 	if (valcnt > 0)
43480ba2cbe9Sxc151355 		buf[strlen(buf) - 1] = '\0';
43490ba2cbe9Sxc151355 
43500ba2cbe9Sxc151355 	lim = statep->ls_line + MAX_PROP_LINE;
43510ba2cbe9Sxc151355 	if (statep->ls_parseable) {
43520ba2cbe9Sxc151355 		*pptr += snprintf(*pptr, lim - *pptr,
4353*e7801d59Ssowmini 		    "%s", buf);
43540ba2cbe9Sxc151355 	} else {
43550ba2cbe9Sxc151355 		*pptr += snprintf(*pptr, lim - *pptr, format, buf);
43560ba2cbe9Sxc151355 	}
43570ba2cbe9Sxc151355 }
43580ba2cbe9Sxc151355 
4359*e7801d59Ssowmini static char *
4360*e7801d59Ssowmini linkprop_callback(print_field_t *pf, void *ls_arg)
4361*e7801d59Ssowmini {
4362*e7801d59Ssowmini 	linkprop_args_t		*arg = ls_arg;
4363*e7801d59Ssowmini 	char 			*propname = arg->ls_propname;
4364*e7801d59Ssowmini 	show_linkprop_state_t	*statep = arg->ls_state;
4365*e7801d59Ssowmini 	char			*ptr = statep->ls_line;
4366*e7801d59Ssowmini 	char			*lim = ptr + MAX_PROP_LINE;
4367*e7801d59Ssowmini 	datalink_id_t		linkid = arg->ls_linkid;
4368*e7801d59Ssowmini 
4369*e7801d59Ssowmini 	switch (pf->pf_index) {
4370*e7801d59Ssowmini 	case LINKPROP_LINK:
4371*e7801d59Ssowmini 		(void) snprintf(ptr, lim - ptr, "%s", statep->ls_link);
4372*e7801d59Ssowmini 		break;
4373*e7801d59Ssowmini 	case LINKPROP_PROPERTY:
4374*e7801d59Ssowmini 		(void) snprintf(ptr, lim - ptr, "%s", propname);
4375*e7801d59Ssowmini 		break;
4376*e7801d59Ssowmini 	case LINKPROP_VALUE:
4377*e7801d59Ssowmini 		print_linkprop(linkid, statep, propname,
4378*e7801d59Ssowmini 		    statep->ls_persist ? DLADM_PROP_VAL_PERSISTENT :
4379*e7801d59Ssowmini 		    DLADM_PROP_VAL_CURRENT, "%s", &ptr);
4380*e7801d59Ssowmini 		/*
4381*e7801d59Ssowmini 		 * If we failed to query the link property, for example, query
4382*e7801d59Ssowmini 		 * the persistent value of a non-persistable link property,
4383*e7801d59Ssowmini 		 * simply skip the output.
4384*e7801d59Ssowmini 		 */
4385*e7801d59Ssowmini 		if (statep->ls_status != DLADM_STATUS_OK)
4386*e7801d59Ssowmini 			goto skip;
4387*e7801d59Ssowmini 		ptr = statep->ls_line;
4388*e7801d59Ssowmini 		break;
4389*e7801d59Ssowmini 	case LINKPROP_DEFAULT:
4390*e7801d59Ssowmini 		print_linkprop(linkid, statep, propname,
4391*e7801d59Ssowmini 		    DLADM_PROP_VAL_DEFAULT, "%s", &ptr);
4392*e7801d59Ssowmini 		if (statep->ls_status != DLADM_STATUS_OK)
4393*e7801d59Ssowmini 			goto skip;
4394*e7801d59Ssowmini 		ptr = statep->ls_line;
4395*e7801d59Ssowmini 		break;
4396*e7801d59Ssowmini 	case LINKPROP_POSSIBLE:
4397*e7801d59Ssowmini 		print_linkprop(linkid, statep, propname,
4398*e7801d59Ssowmini 		    DLADM_PROP_VAL_MODIFIABLE, "%s ", &ptr);
4399*e7801d59Ssowmini 		if (statep->ls_status != DLADM_STATUS_OK)
4400*e7801d59Ssowmini 			goto skip;
4401*e7801d59Ssowmini 		ptr = statep->ls_line;
4402*e7801d59Ssowmini 		break;
4403*e7801d59Ssowmini 	default:
4404*e7801d59Ssowmini 		die("invalid input");
4405*e7801d59Ssowmini 		break;
4406*e7801d59Ssowmini 	}
4407*e7801d59Ssowmini 	return (ptr);
4408*e7801d59Ssowmini skip:
4409*e7801d59Ssowmini 	if (statep->ls_status != DLADM_STATUS_OK)
4410*e7801d59Ssowmini 		return (NULL);
4411*e7801d59Ssowmini 	else
4412*e7801d59Ssowmini 		return ("");
4413*e7801d59Ssowmini }
4414*e7801d59Ssowmini 
4415d62bc4baSyz147064 static int
4416d62bc4baSyz147064 show_linkprop(datalink_id_t linkid, const char *propname, void *arg)
44170ba2cbe9Sxc151355 {
44180ba2cbe9Sxc151355 	show_linkprop_state_t	*statep = arg;
4419*e7801d59Ssowmini 	linkprop_args_t		ls_arg;
44200ba2cbe9Sxc151355 
4421*e7801d59Ssowmini 	bzero(&ls_arg, sizeof (ls_arg));
4422*e7801d59Ssowmini 	ls_arg.ls_state = statep;
4423*e7801d59Ssowmini 	ls_arg.ls_propname = (char *)propname;
4424*e7801d59Ssowmini 	ls_arg.ls_linkid = linkid;
44250ba2cbe9Sxc151355 
44260ba2cbe9Sxc151355 	if (statep->ls_header) {
44270ba2cbe9Sxc151355 		statep->ls_header = B_FALSE;
44280ba2cbe9Sxc151355 		if (!statep->ls_parseable)
4429*e7801d59Ssowmini 			print_header(&statep->ls_print);
44300ba2cbe9Sxc151355 	}
4431*e7801d59Ssowmini 	dladm_print_output(&statep->ls_print, statep->ls_parseable,
4432*e7801d59Ssowmini 	    linkprop_callback, (void *)&ls_arg);
4433*e7801d59Ssowmini 
4434d62bc4baSyz147064 	return (DLADM_WALK_CONTINUE);
44350ba2cbe9Sxc151355 }
44360ba2cbe9Sxc151355 
44370ba2cbe9Sxc151355 static void
44380ba2cbe9Sxc151355 do_show_linkprop(int argc, char **argv)
44390ba2cbe9Sxc151355 {
4440f4b3ec61Sdh155122 	int			option;
44410ba2cbe9Sxc151355 	prop_list_t		*proplist = NULL;
4442d62bc4baSyz147064 	datalink_id_t		linkid = DATALINK_ALL_LINKID;
44430ba2cbe9Sxc151355 	show_linkprop_state_t	state;
4444d62bc4baSyz147064 	uint32_t		flags = DLADM_OPT_ACTIVE;
4445d62bc4baSyz147064 	dladm_status_t		status;
4446*e7801d59Ssowmini 	char			*fields_str = NULL;
4447*e7801d59Ssowmini 	print_field_t		**fields;
4448*e7801d59Ssowmini 	uint_t			nfields;
4449*e7801d59Ssowmini 	char			*all_fields =
4450*e7801d59Ssowmini 	    "link,property,value,default,possible";
4451*e7801d59Ssowmini 
4452*e7801d59Ssowmini 	fields_str = all_fields;
44530ba2cbe9Sxc151355 
44540ba2cbe9Sxc151355 	opterr = 0;
44550ba2cbe9Sxc151355 	state.ls_propvals = NULL;
44560ba2cbe9Sxc151355 	state.ls_line = NULL;
44570ba2cbe9Sxc151355 	state.ls_parseable = B_FALSE;
44580ba2cbe9Sxc151355 	state.ls_persist = B_FALSE;
44590ba2cbe9Sxc151355 	state.ls_header = B_TRUE;
4460*e7801d59Ssowmini 	state.ls_retstatus = DLADM_STATUS_OK;
4461*e7801d59Ssowmini 	while ((option = getopt_long(argc, argv, ":p:cPo:",
44620ba2cbe9Sxc151355 	    prop_longopts, NULL)) != -1) {
44630ba2cbe9Sxc151355 		switch (option) {
44640ba2cbe9Sxc151355 		case 'p':
446533343a97Smeem 			if (parse_props(optarg, &proplist, B_TRUE) < 0)
446613994ee8Sxz162242 				die("invalid link properties specified");
44670ba2cbe9Sxc151355 			break;
44680ba2cbe9Sxc151355 		case 'c':
44690ba2cbe9Sxc151355 			state.ls_parseable = B_TRUE;
44700ba2cbe9Sxc151355 			break;
44710ba2cbe9Sxc151355 		case 'P':
44720ba2cbe9Sxc151355 			state.ls_persist = B_TRUE;
4473d62bc4baSyz147064 			flags = DLADM_OPT_PERSIST;
44740ba2cbe9Sxc151355 			break;
4475*e7801d59Ssowmini 		case 'o':
4476*e7801d59Ssowmini 			if (strcasecmp(optarg, "all") == 0)
4477*e7801d59Ssowmini 				fields_str = all_fields;
4478*e7801d59Ssowmini 			else
4479*e7801d59Ssowmini 				fields_str = optarg;
4480*e7801d59Ssowmini 			break;
44810ba2cbe9Sxc151355 		default:
448233343a97Smeem 			die_opterr(optopt, option);
44830ba2cbe9Sxc151355 			break;
44840ba2cbe9Sxc151355 		}
44850ba2cbe9Sxc151355 	}
44860ba2cbe9Sxc151355 
4487d62bc4baSyz147064 	if (optind == (argc - 1)) {
4488d62bc4baSyz147064 		if ((status = dladm_name2info(argv[optind], &linkid, NULL,
4489d62bc4baSyz147064 		    NULL, NULL)) != DLADM_STATUS_OK) {
4490d62bc4baSyz147064 			die_dlerr(status, "link %s is not valid", argv[optind]);
4491d62bc4baSyz147064 		}
4492d62bc4baSyz147064 	} else if (optind != argc) {
44930ba2cbe9Sxc151355 		usage();
4494d62bc4baSyz147064 	}
44950ba2cbe9Sxc151355 
4496*e7801d59Ssowmini 	bzero(&state.ls_print, sizeof (print_state_t));
4497f4b3ec61Sdh155122 	state.ls_proplist = proplist;
4498f595a68aSyz147064 	state.ls_status = DLADM_STATUS_OK;
4499f4b3ec61Sdh155122 
4500*e7801d59Ssowmini 	fields = parse_output_fields(fields_str, linkprop_fields,
4501*e7801d59Ssowmini 	    LINKPROP_MAX_FIELDS, CMD_TYPE_ANY, &nfields);
4502*e7801d59Ssowmini 
4503*e7801d59Ssowmini 	if (fields == NULL) {
4504*e7801d59Ssowmini 		die("invalid field(s) specified");
4505*e7801d59Ssowmini 		return;
4506*e7801d59Ssowmini 	}
4507*e7801d59Ssowmini 
4508*e7801d59Ssowmini 	state.ls_print.ps_fields = fields;
4509*e7801d59Ssowmini 	state.ls_print.ps_nfields = nfields;
4510d62bc4baSyz147064 	if (linkid == DATALINK_ALL_LINKID) {
4511d62bc4baSyz147064 		(void) dladm_walk_datalink_id(show_linkprop_onelink, &state,
4512d62bc4baSyz147064 		    DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE, flags);
4513f4b3ec61Sdh155122 	} else {
4514d62bc4baSyz147064 		(void) show_linkprop_onelink(linkid, &state);
4515f4b3ec61Sdh155122 	}
4516f4b3ec61Sdh155122 	free_props(proplist);
4517f595a68aSyz147064 
4518*e7801d59Ssowmini 	if (state.ls_retstatus != DLADM_STATUS_OK)
4519f595a68aSyz147064 		exit(EXIT_FAILURE);
4520f4b3ec61Sdh155122 }
4521f4b3ec61Sdh155122 
4522d62bc4baSyz147064 static int
4523d62bc4baSyz147064 show_linkprop_onelink(datalink_id_t linkid, void *arg)
4524f4b3ec61Sdh155122 {
4525948f2876Sss150715 	int			i;
4526f4b3ec61Sdh155122 	char			*buf;
4527d62bc4baSyz147064 	uint32_t		flags;
4528f4b3ec61Sdh155122 	prop_list_t		*proplist = NULL;
4529d62bc4baSyz147064 	show_linkprop_state_t	*statep = arg;
4530d62bc4baSyz147064 	dlpi_handle_t		dh = NULL;
4531f4b3ec61Sdh155122 
4532d62bc4baSyz147064 	statep->ls_status = DLADM_STATUS_OK;
4533d62bc4baSyz147064 
4534d62bc4baSyz147064 	if (dladm_datalink_id2info(linkid, &flags, NULL, NULL, statep->ls_link,
4535d62bc4baSyz147064 	    MAXLINKNAMELEN) != DLADM_STATUS_OK) {
4536d62bc4baSyz147064 		statep->ls_status = DLADM_STATUS_NOTFOUND;
4537d62bc4baSyz147064 		return (DLADM_WALK_CONTINUE);
4538d62bc4baSyz147064 	}
4539d62bc4baSyz147064 
4540d62bc4baSyz147064 	if ((statep->ls_persist && !(flags & DLADM_OPT_PERSIST)) ||
4541d62bc4baSyz147064 	    (!statep->ls_persist && !(flags & DLADM_OPT_ACTIVE))) {
4542d62bc4baSyz147064 		statep->ls_status = DLADM_STATUS_BADARG;
4543d62bc4baSyz147064 		return (DLADM_WALK_CONTINUE);
4544d62bc4baSyz147064 	}
4545d62bc4baSyz147064 
4546f4b3ec61Sdh155122 	proplist = statep->ls_proplist;
45470ba2cbe9Sxc151355 
45480ba2cbe9Sxc151355 	/*
45490ba2cbe9Sxc151355 	 * When some WiFi links are opened for the first time, their hardware
45500ba2cbe9Sxc151355 	 * automatically scans for APs and does other slow operations.	Thus,
45510ba2cbe9Sxc151355 	 * if there are no open links, the retrieval of link properties
45520ba2cbe9Sxc151355 	 * (below) will proceed slowly unless we hold the link open.
4553d62bc4baSyz147064 	 *
4554d62bc4baSyz147064 	 * Note that failure of dlpi_open() does not necessarily mean invalid
4555d62bc4baSyz147064 	 * link properties, because dlpi_open() may fail because of incorrect
4556d62bc4baSyz147064 	 * autopush configuration. Therefore, we ingore the return value of
4557d62bc4baSyz147064 	 * dlpi_open().
45580ba2cbe9Sxc151355 	 */
4559d62bc4baSyz147064 	if (!statep->ls_persist)
4560d62bc4baSyz147064 		(void) dlpi_open(statep->ls_link, &dh, 0);
45610ba2cbe9Sxc151355 
4562d62bc4baSyz147064 	buf = malloc((sizeof (char *) + DLADM_PROP_VAL_MAX) *
4563d62bc4baSyz147064 	    DLADM_MAX_PROP_VALCNT + MAX_PROP_LINE);
456433343a97Smeem 	if (buf == NULL)
456533343a97Smeem 		die("insufficient memory");
456633343a97Smeem 
4567f4b3ec61Sdh155122 	statep->ls_propvals = (char **)(void *)buf;
4568d62bc4baSyz147064 	for (i = 0; i < DLADM_MAX_PROP_VALCNT; i++) {
4569d62bc4baSyz147064 		statep->ls_propvals[i] = buf +
4570d62bc4baSyz147064 		    sizeof (char *) * DLADM_MAX_PROP_VALCNT +
45710ba2cbe9Sxc151355 		    i * DLADM_PROP_VAL_MAX;
45720ba2cbe9Sxc151355 	}
4573f4b3ec61Sdh155122 	statep->ls_line = buf +
4574d62bc4baSyz147064 	    (sizeof (char *) + DLADM_PROP_VAL_MAX) * DLADM_MAX_PROP_VALCNT;
45750ba2cbe9Sxc151355 
45760ba2cbe9Sxc151355 	if (proplist != NULL) {
4577d62bc4baSyz147064 		for (i = 0; i < proplist->pl_count; i++) {
4578d62bc4baSyz147064 			(void) show_linkprop(linkid,
4579d62bc4baSyz147064 			    proplist->pl_info[i].pi_name, statep);
45800ba2cbe9Sxc151355 		}
4581d62bc4baSyz147064 	} else {
4582d62bc4baSyz147064 		(void) dladm_walk_linkprop(linkid, statep, show_linkprop);
4583d62bc4baSyz147064 	}
4584d62bc4baSyz147064 	if (dh != NULL)
4585948f2876Sss150715 		dlpi_close(dh);
45860ba2cbe9Sxc151355 	free(buf);
4587d62bc4baSyz147064 	return (DLADM_WALK_CONTINUE);
45880ba2cbe9Sxc151355 }
45890ba2cbe9Sxc151355 
45900ba2cbe9Sxc151355 static dladm_status_t
4591d62bc4baSyz147064 set_linkprop_persist(datalink_id_t linkid, const char *prop_name,
4592d62bc4baSyz147064     char **prop_val, uint_t val_cnt, boolean_t reset)
45930ba2cbe9Sxc151355 {
45940ba2cbe9Sxc151355 	dladm_status_t	status;
45950ba2cbe9Sxc151355 
4596d62bc4baSyz147064 	status = dladm_set_linkprop(linkid, prop_name, prop_val, val_cnt,
4597d62bc4baSyz147064 	    DLADM_OPT_PERSIST);
45980ba2cbe9Sxc151355 
45990ba2cbe9Sxc151355 	if (status != DLADM_STATUS_OK) {
4600d62bc4baSyz147064 		warn_dlerr(status, "cannot persistently %s link property",
4601d62bc4baSyz147064 		    reset ? "reset" : "set");
46020ba2cbe9Sxc151355 	}
46030ba2cbe9Sxc151355 	return (status);
46040ba2cbe9Sxc151355 }
46050ba2cbe9Sxc151355 
46060ba2cbe9Sxc151355 static void
46070ba2cbe9Sxc151355 set_linkprop(int argc, char **argv, boolean_t reset)
46080ba2cbe9Sxc151355 {
46090ba2cbe9Sxc151355 	int		i, option;
46100ba2cbe9Sxc151355 	char		errmsg[DLADM_STRSIZE];
4611d62bc4baSyz147064 	char		*altroot = NULL;
4612d62bc4baSyz147064 	datalink_id_t	linkid;
46130ba2cbe9Sxc151355 	prop_list_t	*proplist = NULL;
46140ba2cbe9Sxc151355 	boolean_t	temp = B_FALSE;
46150ba2cbe9Sxc151355 	dladm_status_t	status = DLADM_STATUS_OK;
46160ba2cbe9Sxc151355 
46170ba2cbe9Sxc151355 	opterr = 0;
46180ba2cbe9Sxc151355 	while ((option = getopt_long(argc, argv, ":p:R:t",
46190ba2cbe9Sxc151355 	    prop_longopts, NULL)) != -1) {
46200ba2cbe9Sxc151355 		switch (option) {
46210ba2cbe9Sxc151355 		case 'p':
462233343a97Smeem 			if (parse_props(optarg, &proplist, reset) < 0)
462333343a97Smeem 				die("invalid link properties specified");
46240ba2cbe9Sxc151355 			break;
46250ba2cbe9Sxc151355 		case 't':
46260ba2cbe9Sxc151355 			temp = B_TRUE;
46270ba2cbe9Sxc151355 			break;
46280ba2cbe9Sxc151355 		case 'R':
4629d62bc4baSyz147064 			altroot = optarg;
46300ba2cbe9Sxc151355 			break;
46310ba2cbe9Sxc151355 		default:
463233343a97Smeem 			die_opterr(optopt, option);
46330ba2cbe9Sxc151355 			break;
46340ba2cbe9Sxc151355 		}
46350ba2cbe9Sxc151355 	}
46360ba2cbe9Sxc151355 
4637d62bc4baSyz147064 	/* get link name (required last argument) */
4638d62bc4baSyz147064 	if (optind != (argc - 1))
46390ba2cbe9Sxc151355 		usage();
46400ba2cbe9Sxc151355 
4641d62bc4baSyz147064 	if (proplist == NULL && !reset)
464233343a97Smeem 		die("link property must be specified");
464333343a97Smeem 
4644d62bc4baSyz147064 	if (altroot != NULL) {
4645d62bc4baSyz147064 		free_props(proplist);
4646d62bc4baSyz147064 		altroot_cmd(altroot, argc, argv);
4647d62bc4baSyz147064 	}
4648d62bc4baSyz147064 
4649d62bc4baSyz147064 	status = dladm_name2info(argv[optind], &linkid, NULL, NULL, NULL);
4650d62bc4baSyz147064 	if (status != DLADM_STATUS_OK)
4651d62bc4baSyz147064 		die_dlerr(status, "link %s is not valid", argv[optind]);
4652d62bc4baSyz147064 
4653d62bc4baSyz147064 	if (proplist == NULL) {
4654*e7801d59Ssowmini 		status = dladm_set_linkprop(linkid, NULL, NULL, 0,
4655*e7801d59Ssowmini 		    DLADM_OPT_ACTIVE);
4656*e7801d59Ssowmini 		if (status != DLADM_STATUS_OK) {
4657d62bc4baSyz147064 			warn_dlerr(status, "cannot reset link property "
4658d62bc4baSyz147064 			    "on '%s'", argv[optind]);
46590ba2cbe9Sxc151355 		}
46600ba2cbe9Sxc151355 		if (!temp) {
466113994ee8Sxz162242 			dladm_status_t	s;
466213994ee8Sxz162242 
4663d62bc4baSyz147064 			s = set_linkprop_persist(linkid, NULL, NULL, 0, reset);
466413994ee8Sxz162242 			if (s != DLADM_STATUS_OK)
466513994ee8Sxz162242 				status = s;
46660ba2cbe9Sxc151355 		}
46670ba2cbe9Sxc151355 		goto done;
46680ba2cbe9Sxc151355 	}
46690ba2cbe9Sxc151355 
46700ba2cbe9Sxc151355 	for (i = 0; i < proplist->pl_count; i++) {
46710ba2cbe9Sxc151355 		prop_info_t	*pip = &proplist->pl_info[i];
46720ba2cbe9Sxc151355 		char		**val;
46730ba2cbe9Sxc151355 		uint_t		count;
46740ba2cbe9Sxc151355 		dladm_status_t	s;
46750ba2cbe9Sxc151355 
46760ba2cbe9Sxc151355 		if (reset) {
46770ba2cbe9Sxc151355 			val = NULL;
46780ba2cbe9Sxc151355 			count = 0;
46790ba2cbe9Sxc151355 		} else {
46800ba2cbe9Sxc151355 			val = pip->pi_val;
46810ba2cbe9Sxc151355 			count = pip->pi_count;
46820ba2cbe9Sxc151355 			if (count == 0) {
468333343a97Smeem 				warn("no value specified for '%s'",
468433343a97Smeem 				    pip->pi_name);
46850ba2cbe9Sxc151355 				status = DLADM_STATUS_BADARG;
46860ba2cbe9Sxc151355 				continue;
46870ba2cbe9Sxc151355 			}
46880ba2cbe9Sxc151355 		}
4689d62bc4baSyz147064 		s = dladm_set_linkprop(linkid, pip->pi_name, val, count,
4690d62bc4baSyz147064 		    DLADM_OPT_ACTIVE);
46910ba2cbe9Sxc151355 		if (s == DLADM_STATUS_OK) {
46920ba2cbe9Sxc151355 			if (!temp) {
4693d62bc4baSyz147064 				s = set_linkprop_persist(linkid,
46940ba2cbe9Sxc151355 				    pip->pi_name, val, count, reset);
46950ba2cbe9Sxc151355 				if (s != DLADM_STATUS_OK)
46960ba2cbe9Sxc151355 					status = s;
46970ba2cbe9Sxc151355 			}
46980ba2cbe9Sxc151355 			continue;
46990ba2cbe9Sxc151355 		}
47000ba2cbe9Sxc151355 		status = s;
47010ba2cbe9Sxc151355 		switch (s) {
47020ba2cbe9Sxc151355 		case DLADM_STATUS_NOTFOUND:
470333343a97Smeem 			warn("invalid link property '%s'", pip->pi_name);
47040ba2cbe9Sxc151355 			break;
47050ba2cbe9Sxc151355 		case DLADM_STATUS_BADVAL: {
47060ba2cbe9Sxc151355 			int		j;
47070ba2cbe9Sxc151355 			char		*ptr, *lim;
47080ba2cbe9Sxc151355 			char		**propvals = NULL;
4709d62bc4baSyz147064 			uint_t		valcnt = DLADM_MAX_PROP_VALCNT;
47100ba2cbe9Sxc151355 
47110ba2cbe9Sxc151355 			ptr = malloc((sizeof (char *) +
4712d62bc4baSyz147064 			    DLADM_PROP_VAL_MAX) * DLADM_MAX_PROP_VALCNT +
47130ba2cbe9Sxc151355 			    MAX_PROP_LINE);
47140ba2cbe9Sxc151355 
47150ba2cbe9Sxc151355 			propvals = (char **)(void *)ptr;
471633343a97Smeem 			if (propvals == NULL)
471733343a97Smeem 				die("insufficient memory");
471833343a97Smeem 
4719d62bc4baSyz147064 			for (j = 0; j < DLADM_MAX_PROP_VALCNT; j++) {
47200ba2cbe9Sxc151355 				propvals[j] = ptr + sizeof (char *) *
4721d62bc4baSyz147064 				    DLADM_MAX_PROP_VALCNT +
47220ba2cbe9Sxc151355 				    j * DLADM_PROP_VAL_MAX;
47230ba2cbe9Sxc151355 			}
4724d62bc4baSyz147064 			s = dladm_get_linkprop(linkid,
4725d62bc4baSyz147064 			    DLADM_PROP_VAL_MODIFIABLE, pip->pi_name, propvals,
4726d62bc4baSyz147064 			    &valcnt);
4727d62bc4baSyz147064 
4728d62bc4baSyz147064 			if (s != DLADM_STATUS_OK) {
4729d62bc4baSyz147064 				warn_dlerr(status, "cannot set link property "
4730d62bc4baSyz147064 				    "'%s' on '%s'", pip->pi_name, argv[optind]);
4731d62bc4baSyz147064 				free(propvals);
4732d62bc4baSyz147064 				break;
4733d62bc4baSyz147064 			}
47340ba2cbe9Sxc151355 
47350ba2cbe9Sxc151355 			ptr = errmsg;
47360ba2cbe9Sxc151355 			lim = ptr + DLADM_STRSIZE;
47370ba2cbe9Sxc151355 			*ptr = '\0';
4738d62bc4baSyz147064 			for (j = 0; j < valcnt; j++) {
47390ba2cbe9Sxc151355 				ptr += snprintf(ptr, lim - ptr, "%s,",
47400ba2cbe9Sxc151355 				    propvals[j]);
47410ba2cbe9Sxc151355 				if (ptr >= lim)
47420ba2cbe9Sxc151355 					break;
47430ba2cbe9Sxc151355 			}
4744f4b3ec61Sdh155122 			if (ptr > errmsg) {
47450ba2cbe9Sxc151355 				*(ptr - 1) = '\0';
474633343a97Smeem 				warn("link property '%s' must be one of: %s",
474733343a97Smeem 				    pip->pi_name, errmsg);
4748f4b3ec61Sdh155122 			} else
4749f4b3ec61Sdh155122 				warn("invalid link property '%s'", *val);
47500ba2cbe9Sxc151355 			free(propvals);
47510ba2cbe9Sxc151355 			break;
47520ba2cbe9Sxc151355 		}
47530ba2cbe9Sxc151355 		default:
47540ba2cbe9Sxc151355 			if (reset) {
475533343a97Smeem 				warn_dlerr(status, "cannot reset link property "
4756d62bc4baSyz147064 				    "'%s' on '%s'", pip->pi_name, argv[optind]);
47570ba2cbe9Sxc151355 			} else {
475833343a97Smeem 				warn_dlerr(status, "cannot set link property "
4759d62bc4baSyz147064 				    "'%s' on '%s'", pip->pi_name, argv[optind]);
47600ba2cbe9Sxc151355 			}
47610ba2cbe9Sxc151355 			break;
47620ba2cbe9Sxc151355 		}
47630ba2cbe9Sxc151355 	}
47640ba2cbe9Sxc151355 done:
47650ba2cbe9Sxc151355 	free_props(proplist);
47660ba2cbe9Sxc151355 	if (status != DLADM_STATUS_OK)
47670ba2cbe9Sxc151355 		exit(1);
47680ba2cbe9Sxc151355 }
47690ba2cbe9Sxc151355 
47700ba2cbe9Sxc151355 static void
47710ba2cbe9Sxc151355 do_set_linkprop(int argc, char **argv)
47720ba2cbe9Sxc151355 {
47730ba2cbe9Sxc151355 	set_linkprop(argc, argv, B_FALSE);
47740ba2cbe9Sxc151355 }
47750ba2cbe9Sxc151355 
47760ba2cbe9Sxc151355 static void
47770ba2cbe9Sxc151355 do_reset_linkprop(int argc, char **argv)
47780ba2cbe9Sxc151355 {
47790ba2cbe9Sxc151355 	set_linkprop(argc, argv, B_TRUE);
47800ba2cbe9Sxc151355 }
47810ba2cbe9Sxc151355 
47820ba2cbe9Sxc151355 static int
47830ba2cbe9Sxc151355 convert_secobj(char *buf, uint_t len, uint8_t *obj_val, uint_t *obj_lenp,
47840ba2cbe9Sxc151355     dladm_secobj_class_t class)
47850ba2cbe9Sxc151355 {
47860ba2cbe9Sxc151355 	int error = 0;
47870ba2cbe9Sxc151355 
4788a399b765Szf162725 	if (class == DLADM_SECOBJ_CLASS_WPA) {
4789a399b765Szf162725 		if (len < 8 || len > 63)
4790a399b765Szf162725 			return (EINVAL);
4791a399b765Szf162725 		(void) memcpy(obj_val, buf, len);
4792a399b765Szf162725 		*obj_lenp = len;
4793a399b765Szf162725 		return (error);
4794a399b765Szf162725 	}
47950ba2cbe9Sxc151355 
4796a399b765Szf162725 	if (class == DLADM_SECOBJ_CLASS_WEP) {
47970ba2cbe9Sxc151355 		switch (len) {
47980ba2cbe9Sxc151355 		case 5:			/* ASCII key sizes */
47990ba2cbe9Sxc151355 		case 13:
48000ba2cbe9Sxc151355 			(void) memcpy(obj_val, buf, len);
48010ba2cbe9Sxc151355 			*obj_lenp = len;
48020ba2cbe9Sxc151355 			break;
48030ba2cbe9Sxc151355 		case 10:		/* Hex key sizes, not preceded by 0x */
48040ba2cbe9Sxc151355 		case 26:
48050ba2cbe9Sxc151355 			error = hexascii_to_octet(buf, len, obj_val, obj_lenp);
48060ba2cbe9Sxc151355 			break;
48070ba2cbe9Sxc151355 		case 12:		/* Hex key sizes, preceded by 0x */
48080ba2cbe9Sxc151355 		case 28:
48090ba2cbe9Sxc151355 			if (strncmp(buf, "0x", 2) != 0)
48100ba2cbe9Sxc151355 				return (EINVAL);
4811a399b765Szf162725 			error = hexascii_to_octet(buf + 2, len - 2,
4812a399b765Szf162725 			    obj_val, obj_lenp);
48130ba2cbe9Sxc151355 			break;
48140ba2cbe9Sxc151355 		default:
48150ba2cbe9Sxc151355 			return (EINVAL);
48160ba2cbe9Sxc151355 		}
48170ba2cbe9Sxc151355 		return (error);
48180ba2cbe9Sxc151355 	}
48190ba2cbe9Sxc151355 
4820a399b765Szf162725 	return (ENOENT);
4821a399b765Szf162725 }
4822a399b765Szf162725 
48230ba2cbe9Sxc151355 /* ARGSUSED */
48240ba2cbe9Sxc151355 static void
48250ba2cbe9Sxc151355 defersig(int sig)
48260ba2cbe9Sxc151355 {
48270ba2cbe9Sxc151355 	signalled = sig;
48280ba2cbe9Sxc151355 }
48290ba2cbe9Sxc151355 
48300ba2cbe9Sxc151355 static int
48310ba2cbe9Sxc151355 get_secobj_from_tty(uint_t try, const char *objname, char *buf)
48320ba2cbe9Sxc151355 {
48330ba2cbe9Sxc151355 	uint_t		len = 0;
48340ba2cbe9Sxc151355 	int		c;
48350ba2cbe9Sxc151355 	struct termios	stored, current;
48360ba2cbe9Sxc151355 	void		(*sigfunc)(int);
48370ba2cbe9Sxc151355 
48380ba2cbe9Sxc151355 	/*
48390ba2cbe9Sxc151355 	 * Turn off echo -- but before we do so, defer SIGINT handling
48400ba2cbe9Sxc151355 	 * so that a ^C doesn't leave the terminal corrupted.
48410ba2cbe9Sxc151355 	 */
48420ba2cbe9Sxc151355 	sigfunc = signal(SIGINT, defersig);
48430ba2cbe9Sxc151355 	(void) fflush(stdin);
48440ba2cbe9Sxc151355 	(void) tcgetattr(0, &stored);
48450ba2cbe9Sxc151355 	current = stored;
48460ba2cbe9Sxc151355 	current.c_lflag &= ~(ICANON|ECHO);
48470ba2cbe9Sxc151355 	current.c_cc[VTIME] = 0;
48480ba2cbe9Sxc151355 	current.c_cc[VMIN] = 1;
48490ba2cbe9Sxc151355 	(void) tcsetattr(0, TCSANOW, &current);
48500ba2cbe9Sxc151355 again:
48510ba2cbe9Sxc151355 	if (try == 1)
48520ba2cbe9Sxc151355 		(void) printf(gettext("provide value for '%s': "), objname);
48530ba2cbe9Sxc151355 	else
48540ba2cbe9Sxc151355 		(void) printf(gettext("confirm value for '%s': "), objname);
48550ba2cbe9Sxc151355 
48560ba2cbe9Sxc151355 	(void) fflush(stdout);
48570ba2cbe9Sxc151355 	while (signalled == 0) {
48580ba2cbe9Sxc151355 		c = getchar();
48590ba2cbe9Sxc151355 		if (c == '\n' || c == '\r') {
48600ba2cbe9Sxc151355 			if (len != 0)
48610ba2cbe9Sxc151355 				break;
48620ba2cbe9Sxc151355 			(void) putchar('\n');
48630ba2cbe9Sxc151355 			goto again;
48640ba2cbe9Sxc151355 		}
48650ba2cbe9Sxc151355 
48660ba2cbe9Sxc151355 		buf[len++] = c;
48670ba2cbe9Sxc151355 		if (len >= DLADM_SECOBJ_VAL_MAX - 1)
48680ba2cbe9Sxc151355 			break;
48690ba2cbe9Sxc151355 		(void) putchar('*');
48700ba2cbe9Sxc151355 	}
48710ba2cbe9Sxc151355 
48720ba2cbe9Sxc151355 	(void) putchar('\n');
48730ba2cbe9Sxc151355 	(void) fflush(stdin);
48740ba2cbe9Sxc151355 
48750ba2cbe9Sxc151355 	/*
48760ba2cbe9Sxc151355 	 * Restore terminal setting and handle deferred signals.
48770ba2cbe9Sxc151355 	 */
48780ba2cbe9Sxc151355 	(void) tcsetattr(0, TCSANOW, &stored);
48790ba2cbe9Sxc151355 
48800ba2cbe9Sxc151355 	(void) signal(SIGINT, sigfunc);
48810ba2cbe9Sxc151355 	if (signalled != 0)
48820ba2cbe9Sxc151355 		(void) kill(getpid(), signalled);
48830ba2cbe9Sxc151355 
48840ba2cbe9Sxc151355 	return (len);
48850ba2cbe9Sxc151355 }
48860ba2cbe9Sxc151355 
48870ba2cbe9Sxc151355 static int
48880ba2cbe9Sxc151355 get_secobj_val(char *obj_name, uint8_t *obj_val, uint_t *obj_lenp,
48890ba2cbe9Sxc151355     dladm_secobj_class_t class, FILE *filep)
48900ba2cbe9Sxc151355 {
48910ba2cbe9Sxc151355 	int		rval;
48920ba2cbe9Sxc151355 	uint_t		len, len2;
48930ba2cbe9Sxc151355 	char		buf[DLADM_SECOBJ_VAL_MAX], buf2[DLADM_SECOBJ_VAL_MAX];
48940ba2cbe9Sxc151355 
48950ba2cbe9Sxc151355 	if (filep == NULL) {
48960ba2cbe9Sxc151355 		len = get_secobj_from_tty(1, obj_name, buf);
48970ba2cbe9Sxc151355 		rval = convert_secobj(buf, len, obj_val, obj_lenp, class);
48980ba2cbe9Sxc151355 		if (rval == 0) {
48990ba2cbe9Sxc151355 			len2 = get_secobj_from_tty(2, obj_name, buf2);
49000ba2cbe9Sxc151355 			if (len != len2 || memcmp(buf, buf2, len) != 0)
49010ba2cbe9Sxc151355 				rval = ENOTSUP;
49020ba2cbe9Sxc151355 		}
49030ba2cbe9Sxc151355 		return (rval);
49040ba2cbe9Sxc151355 	} else {
49050ba2cbe9Sxc151355 		for (;;) {
49060ba2cbe9Sxc151355 			if (fgets(buf, sizeof (buf), filep) == NULL)
49070ba2cbe9Sxc151355 				break;
49080ba2cbe9Sxc151355 			if (isspace(buf[0]))
49090ba2cbe9Sxc151355 				continue;
49100ba2cbe9Sxc151355 
49110ba2cbe9Sxc151355 			len = strlen(buf);
49120ba2cbe9Sxc151355 			if (buf[len - 1] == '\n') {
49130ba2cbe9Sxc151355 				buf[len - 1] = '\0';
49140ba2cbe9Sxc151355 				len--;
49150ba2cbe9Sxc151355 			}
49160ba2cbe9Sxc151355 			break;
49170ba2cbe9Sxc151355 		}
49180ba2cbe9Sxc151355 		(void) fclose(filep);
49190ba2cbe9Sxc151355 	}
49200ba2cbe9Sxc151355 	return (convert_secobj(buf, len, obj_val, obj_lenp, class));
49210ba2cbe9Sxc151355 }
49220ba2cbe9Sxc151355 
49230ba2cbe9Sxc151355 static boolean_t
49240ba2cbe9Sxc151355 check_auth(const char *auth)
49250ba2cbe9Sxc151355 {
49260ba2cbe9Sxc151355 	struct passwd	*pw;
49270ba2cbe9Sxc151355 
49280ba2cbe9Sxc151355 	if ((pw = getpwuid(getuid())) == NULL)
49290ba2cbe9Sxc151355 		return (B_FALSE);
49300ba2cbe9Sxc151355 
49310ba2cbe9Sxc151355 	return (chkauthattr(auth, pw->pw_name) != 0);
49320ba2cbe9Sxc151355 }
49330ba2cbe9Sxc151355 
49340ba2cbe9Sxc151355 static void
49350ba2cbe9Sxc151355 audit_secobj(char *auth, char *class, char *obj,
49360ba2cbe9Sxc151355     boolean_t success, boolean_t create)
49370ba2cbe9Sxc151355 {
49380ba2cbe9Sxc151355 	adt_session_data_t	*ah;
49390ba2cbe9Sxc151355 	adt_event_data_t	*event;
49400ba2cbe9Sxc151355 	au_event_t		flag;
49410ba2cbe9Sxc151355 	char			*errstr;
49420ba2cbe9Sxc151355 
49430ba2cbe9Sxc151355 	if (create) {
49440ba2cbe9Sxc151355 		flag = ADT_dladm_create_secobj;
49450ba2cbe9Sxc151355 		errstr = "ADT_dladm_create_secobj";
49460ba2cbe9Sxc151355 	} else {
49470ba2cbe9Sxc151355 		flag = ADT_dladm_delete_secobj;
49480ba2cbe9Sxc151355 		errstr = "ADT_dladm_delete_secobj";
49490ba2cbe9Sxc151355 	}
49500ba2cbe9Sxc151355 
495133343a97Smeem 	if (adt_start_session(&ah, NULL, ADT_USE_PROC_DATA) != 0)
495233343a97Smeem 		die("adt_start_session: %s", strerror(errno));
49530ba2cbe9Sxc151355 
495433343a97Smeem 	if ((event = adt_alloc_event(ah, flag)) == NULL)
495533343a97Smeem 		die("adt_alloc_event (%s): %s", errstr, strerror(errno));
49560ba2cbe9Sxc151355 
49570ba2cbe9Sxc151355 	/* fill in audit info */
49580ba2cbe9Sxc151355 	if (create) {
49590ba2cbe9Sxc151355 		event->adt_dladm_create_secobj.auth_used = auth;
49600ba2cbe9Sxc151355 		event->adt_dladm_create_secobj.obj_class = class;
49610ba2cbe9Sxc151355 		event->adt_dladm_create_secobj.obj_name = obj;
49620ba2cbe9Sxc151355 	} else {
49630ba2cbe9Sxc151355 		event->adt_dladm_delete_secobj.auth_used = auth;
49640ba2cbe9Sxc151355 		event->adt_dladm_delete_secobj.obj_class = class;
49650ba2cbe9Sxc151355 		event->adt_dladm_delete_secobj.obj_name = obj;
49660ba2cbe9Sxc151355 	}
49670ba2cbe9Sxc151355 
49680ba2cbe9Sxc151355 	if (success) {
49690ba2cbe9Sxc151355 		if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS) != 0) {
497033343a97Smeem 			die("adt_put_event (%s, success): %s", errstr,
497133343a97Smeem 			    strerror(errno));
49720ba2cbe9Sxc151355 		}
49730ba2cbe9Sxc151355 	} else {
49740ba2cbe9Sxc151355 		if (adt_put_event(event, ADT_FAILURE,
49750ba2cbe9Sxc151355 		    ADT_FAIL_VALUE_AUTH) != 0) {
497633343a97Smeem 			die("adt_put_event: (%s, failure): %s", errstr,
497733343a97Smeem 			    strerror(errno));
49780ba2cbe9Sxc151355 		}
49790ba2cbe9Sxc151355 	}
49800ba2cbe9Sxc151355 
49810ba2cbe9Sxc151355 	adt_free_event(event);
49820ba2cbe9Sxc151355 	(void) adt_end_session(ah);
49830ba2cbe9Sxc151355 }
49840ba2cbe9Sxc151355 
49850ba2cbe9Sxc151355 #define	MAX_SECOBJS		32
49860ba2cbe9Sxc151355 #define	MAX_SECOBJ_NAMELEN	32
49870ba2cbe9Sxc151355 static void
49880ba2cbe9Sxc151355 do_create_secobj(int argc, char **argv)
49890ba2cbe9Sxc151355 {
49900ba2cbe9Sxc151355 	int			option, rval;
49910ba2cbe9Sxc151355 	FILE			*filep = NULL;
49920ba2cbe9Sxc151355 	char			*obj_name = NULL;
49930ba2cbe9Sxc151355 	char			*class_name = NULL;
49940ba2cbe9Sxc151355 	uint8_t			obj_val[DLADM_SECOBJ_VAL_MAX];
49950ba2cbe9Sxc151355 	uint_t			obj_len;
49960ba2cbe9Sxc151355 	boolean_t		success, temp = B_FALSE;
49970ba2cbe9Sxc151355 	dladm_status_t		status;
49980ba2cbe9Sxc151355 	dladm_secobj_class_t	class = -1;
49990ba2cbe9Sxc151355 	uid_t			euid;
50000ba2cbe9Sxc151355 
50010ba2cbe9Sxc151355 	opterr = 0;
50020ba2cbe9Sxc151355 	(void) memset(obj_val, 0, DLADM_SECOBJ_VAL_MAX);
50030ba2cbe9Sxc151355 	while ((option = getopt_long(argc, argv, ":f:c:R:t",
50040ba2cbe9Sxc151355 	    wifi_longopts, NULL)) != -1) {
50050ba2cbe9Sxc151355 		switch (option) {
50060ba2cbe9Sxc151355 		case 'f':
50070ba2cbe9Sxc151355 			euid = geteuid();
50080ba2cbe9Sxc151355 			(void) seteuid(getuid());
50090ba2cbe9Sxc151355 			filep = fopen(optarg, "r");
50100ba2cbe9Sxc151355 			if (filep == NULL) {
501133343a97Smeem 				die("cannot open %s: %s", optarg,
501233343a97Smeem 				    strerror(errno));
50130ba2cbe9Sxc151355 			}
50140ba2cbe9Sxc151355 			(void) seteuid(euid);
50150ba2cbe9Sxc151355 			break;
50160ba2cbe9Sxc151355 		case 'c':
50170ba2cbe9Sxc151355 			class_name = optarg;
50180ba2cbe9Sxc151355 			status = dladm_str2secobjclass(optarg, &class);
50190ba2cbe9Sxc151355 			if (status != DLADM_STATUS_OK) {
502033343a97Smeem 				die("invalid secure object class '%s', "
5021a399b765Szf162725 				    "valid values are: wep, wpa", optarg);
50220ba2cbe9Sxc151355 			}
50230ba2cbe9Sxc151355 			break;
50240ba2cbe9Sxc151355 		case 't':
50250ba2cbe9Sxc151355 			temp = B_TRUE;
50260ba2cbe9Sxc151355 			break;
50270ba2cbe9Sxc151355 		case 'R':
50280ba2cbe9Sxc151355 			status = dladm_set_rootdir(optarg);
50290ba2cbe9Sxc151355 			if (status != DLADM_STATUS_OK) {
503033343a97Smeem 				die_dlerr(status, "invalid directory "
503133343a97Smeem 				    "specified");
50320ba2cbe9Sxc151355 			}
50330ba2cbe9Sxc151355 			break;
50340ba2cbe9Sxc151355 		default:
503533343a97Smeem 			die_opterr(optopt, option);
50360ba2cbe9Sxc151355 			break;
50370ba2cbe9Sxc151355 		}
50380ba2cbe9Sxc151355 	}
50390ba2cbe9Sxc151355 
50400ba2cbe9Sxc151355 	if (optind == (argc - 1))
50410ba2cbe9Sxc151355 		obj_name = argv[optind];
50420ba2cbe9Sxc151355 	else if (optind != argc)
50430ba2cbe9Sxc151355 		usage();
50440ba2cbe9Sxc151355 
504533343a97Smeem 	if (class == -1)
504633343a97Smeem 		die("secure object class required");
50470ba2cbe9Sxc151355 
504833343a97Smeem 	if (obj_name == NULL)
504933343a97Smeem 		die("secure object name required");
50500ba2cbe9Sxc151355 
50510ba2cbe9Sxc151355 	success = check_auth(LINK_SEC_AUTH);
50520ba2cbe9Sxc151355 	audit_secobj(LINK_SEC_AUTH, class_name, obj_name, success, B_TRUE);
505333343a97Smeem 	if (!success)
505433343a97Smeem 		die("authorization '%s' is required", LINK_SEC_AUTH);
50550ba2cbe9Sxc151355 
505633343a97Smeem 	rval = get_secobj_val(obj_name, obj_val, &obj_len, class, filep);
505733343a97Smeem 	if (rval != 0) {
50580ba2cbe9Sxc151355 		switch (rval) {
50590ba2cbe9Sxc151355 		case ENOENT:
506033343a97Smeem 			die("invalid secure object class");
50610ba2cbe9Sxc151355 			break;
50620ba2cbe9Sxc151355 		case EINVAL:
506333343a97Smeem 			die("invalid secure object value");
50640ba2cbe9Sxc151355 			break;
50650ba2cbe9Sxc151355 		case ENOTSUP:
506633343a97Smeem 			die("verification failed");
50670ba2cbe9Sxc151355 			break;
50680ba2cbe9Sxc151355 		default:
506933343a97Smeem 			die("invalid secure object: %s", strerror(rval));
50700ba2cbe9Sxc151355 			break;
50710ba2cbe9Sxc151355 		}
50720ba2cbe9Sxc151355 	}
50730ba2cbe9Sxc151355 
50740ba2cbe9Sxc151355 	status = dladm_set_secobj(obj_name, class, obj_val, obj_len,
5075d62bc4baSyz147064 	    DLADM_OPT_CREATE | DLADM_OPT_ACTIVE);
50760ba2cbe9Sxc151355 	if (status != DLADM_STATUS_OK) {
507733343a97Smeem 		die_dlerr(status, "could not create secure object '%s'",
507833343a97Smeem 		    obj_name);
50790ba2cbe9Sxc151355 	}
50800ba2cbe9Sxc151355 	if (temp)
50810ba2cbe9Sxc151355 		return;
50820ba2cbe9Sxc151355 
50830ba2cbe9Sxc151355 	status = dladm_set_secobj(obj_name, class, obj_val, obj_len,
50840ba2cbe9Sxc151355 	    DLADM_OPT_PERSIST);
50850ba2cbe9Sxc151355 	if (status != DLADM_STATUS_OK) {
508633343a97Smeem 		warn_dlerr(status, "could not persistently create secure "
508733343a97Smeem 		    "object '%s'", obj_name);
50880ba2cbe9Sxc151355 	}
50890ba2cbe9Sxc151355 }
50900ba2cbe9Sxc151355 
50910ba2cbe9Sxc151355 static void
50920ba2cbe9Sxc151355 do_delete_secobj(int argc, char **argv)
50930ba2cbe9Sxc151355 {
50940ba2cbe9Sxc151355 	int		i, option;
50950ba2cbe9Sxc151355 	boolean_t	temp = B_FALSE;
50960ba2cbe9Sxc151355 	split_t		*sp = NULL;
50970ba2cbe9Sxc151355 	boolean_t	success;
50980ba2cbe9Sxc151355 	dladm_status_t	status, pstatus;
50990ba2cbe9Sxc151355 
51000ba2cbe9Sxc151355 	opterr = 0;
51010ba2cbe9Sxc151355 	status = pstatus = DLADM_STATUS_OK;
510233343a97Smeem 	while ((option = getopt_long(argc, argv, ":R:t",
51030ba2cbe9Sxc151355 	    wifi_longopts, NULL)) != -1) {
51040ba2cbe9Sxc151355 		switch (option) {
51050ba2cbe9Sxc151355 		case 't':
51060ba2cbe9Sxc151355 			temp = B_TRUE;
51070ba2cbe9Sxc151355 			break;
51080ba2cbe9Sxc151355 		case 'R':
51090ba2cbe9Sxc151355 			status = dladm_set_rootdir(optarg);
51100ba2cbe9Sxc151355 			if (status != DLADM_STATUS_OK) {
511133343a97Smeem 				die_dlerr(status, "invalid directory "
511233343a97Smeem 				    "specified");
51130ba2cbe9Sxc151355 			}
51140ba2cbe9Sxc151355 			break;
51150ba2cbe9Sxc151355 		default:
511633343a97Smeem 			die_opterr(optopt, option);
51170ba2cbe9Sxc151355 			break;
51180ba2cbe9Sxc151355 		}
51190ba2cbe9Sxc151355 	}
51200ba2cbe9Sxc151355 
51210ba2cbe9Sxc151355 	if (optind == (argc - 1)) {
51220ba2cbe9Sxc151355 		sp = split(argv[optind], MAX_SECOBJS, MAX_SECOBJ_NAMELEN);
51230ba2cbe9Sxc151355 		if (sp == NULL) {
512433343a97Smeem 			die("invalid secure object name(s): '%s'",
512533343a97Smeem 			    argv[optind]);
51260ba2cbe9Sxc151355 		}
51270ba2cbe9Sxc151355 	} else if (optind != argc)
51280ba2cbe9Sxc151355 		usage();
51290ba2cbe9Sxc151355 
513033343a97Smeem 	if (sp == NULL || sp->s_nfields < 1)
513133343a97Smeem 		die("secure object name required");
51320ba2cbe9Sxc151355 
51330ba2cbe9Sxc151355 	success = check_auth(LINK_SEC_AUTH);
5134a399b765Szf162725 	audit_secobj(LINK_SEC_AUTH, "unknown", argv[optind], success, B_FALSE);
513533343a97Smeem 	if (!success)
513633343a97Smeem 		die("authorization '%s' is required", LINK_SEC_AUTH);
51370ba2cbe9Sxc151355 
51380ba2cbe9Sxc151355 	for (i = 0; i < sp->s_nfields; i++) {
5139d62bc4baSyz147064 		status = dladm_unset_secobj(sp->s_fields[i], DLADM_OPT_ACTIVE);
51400ba2cbe9Sxc151355 		if (!temp) {
51410ba2cbe9Sxc151355 			pstatus = dladm_unset_secobj(sp->s_fields[i],
51420ba2cbe9Sxc151355 			    DLADM_OPT_PERSIST);
51430ba2cbe9Sxc151355 		} else {
51440ba2cbe9Sxc151355 			pstatus = DLADM_STATUS_OK;
51450ba2cbe9Sxc151355 		}
51460ba2cbe9Sxc151355 
51470ba2cbe9Sxc151355 		if (status != DLADM_STATUS_OK) {
514833343a97Smeem 			warn_dlerr(status, "could not delete secure object "
514933343a97Smeem 			    "'%s'", sp->s_fields[i]);
51500ba2cbe9Sxc151355 		}
51510ba2cbe9Sxc151355 		if (pstatus != DLADM_STATUS_OK) {
515233343a97Smeem 			warn_dlerr(pstatus, "could not persistently delete "
515333343a97Smeem 			    "secure object '%s'", sp->s_fields[i]);
51540ba2cbe9Sxc151355 		}
51550ba2cbe9Sxc151355 	}
51560ba2cbe9Sxc151355 	if (status != DLADM_STATUS_OK || pstatus != DLADM_STATUS_OK)
51570ba2cbe9Sxc151355 		exit(1);
51580ba2cbe9Sxc151355 }
51590ba2cbe9Sxc151355 
51600ba2cbe9Sxc151355 typedef struct show_secobj_state {
51610ba2cbe9Sxc151355 	boolean_t	ss_persist;
51620ba2cbe9Sxc151355 	boolean_t	ss_parseable;
51630ba2cbe9Sxc151355 	boolean_t	ss_header;
5164*e7801d59Ssowmini 	print_state_t	ss_print;
51650ba2cbe9Sxc151355 } show_secobj_state_t;
51660ba2cbe9Sxc151355 
51670ba2cbe9Sxc151355 
51680ba2cbe9Sxc151355 static boolean_t
51690ba2cbe9Sxc151355 show_secobj(void *arg, const char *obj_name)
51700ba2cbe9Sxc151355 {
51710ba2cbe9Sxc151355 	uint_t			obj_len = DLADM_SECOBJ_VAL_MAX;
51720ba2cbe9Sxc151355 	uint8_t			obj_val[DLADM_SECOBJ_VAL_MAX];
51730ba2cbe9Sxc151355 	char			buf[DLADM_STRSIZE];
51740ba2cbe9Sxc151355 	uint_t			flags = 0;
51750ba2cbe9Sxc151355 	dladm_secobj_class_t	class;
51760ba2cbe9Sxc151355 	show_secobj_state_t	*statep = arg;
51770ba2cbe9Sxc151355 	dladm_status_t		status;
5178*e7801d59Ssowmini 	secobj_fields_buf_t	sbuf;
51790ba2cbe9Sxc151355 
51800ba2cbe9Sxc151355 	if (statep->ss_persist)
51810ba2cbe9Sxc151355 		flags |= DLADM_OPT_PERSIST;
51820ba2cbe9Sxc151355 
51830ba2cbe9Sxc151355 	status = dladm_get_secobj(obj_name, &class, obj_val, &obj_len, flags);
518433343a97Smeem 	if (status != DLADM_STATUS_OK)
518533343a97Smeem 		die_dlerr(status, "cannot get secure object '%s'", obj_name);
51860ba2cbe9Sxc151355 
51870ba2cbe9Sxc151355 	if (statep->ss_header) {
51880ba2cbe9Sxc151355 		statep->ss_header = B_FALSE;
51890ba2cbe9Sxc151355 		if (!statep->ss_parseable)
5190*e7801d59Ssowmini 			print_header(&statep->ss_print);
51910ba2cbe9Sxc151355 	}
51920ba2cbe9Sxc151355 
5193*e7801d59Ssowmini 	(void) snprintf(sbuf.ss_obj_name, sizeof (sbuf.ss_obj_name),
5194*e7801d59Ssowmini 	    obj_name);
5195*e7801d59Ssowmini 	(void) dladm_secobjclass2str(class, buf);
5196*e7801d59Ssowmini 	(void) snprintf(sbuf.ss_class, sizeof (sbuf.ss_class), "%s", buf);
5197*e7801d59Ssowmini 	if (getuid() == 0) {
51980ba2cbe9Sxc151355 		char	val[DLADM_SECOBJ_VAL_MAX * 2];
51990ba2cbe9Sxc151355 		uint_t	len = sizeof (val);
52000ba2cbe9Sxc151355 
5201*e7801d59Ssowmini 		if (octet_to_hexascii(obj_val, obj_len, val, &len) == 0)
5202*e7801d59Ssowmini 			(void) snprintf(sbuf.ss_val,
5203*e7801d59Ssowmini 			    sizeof (sbuf.ss_val), "%s", val);
52040ba2cbe9Sxc151355 	}
5205*e7801d59Ssowmini 	dladm_print_output(&statep->ss_print, statep->ss_parseable,
5206*e7801d59Ssowmini 	    dladm_print_field, (void *)&sbuf);
52070ba2cbe9Sxc151355 	return (B_TRUE);
52080ba2cbe9Sxc151355 }
52090ba2cbe9Sxc151355 
52100ba2cbe9Sxc151355 static void
52110ba2cbe9Sxc151355 do_show_secobj(int argc, char **argv)
52120ba2cbe9Sxc151355 {
52130ba2cbe9Sxc151355 	int			option;
52140ba2cbe9Sxc151355 	show_secobj_state_t	state;
52150ba2cbe9Sxc151355 	dladm_status_t		status;
52160ba2cbe9Sxc151355 	uint_t			i;
52170ba2cbe9Sxc151355 	split_t			*sp;
52180ba2cbe9Sxc151355 	uint_t			flags;
5219*e7801d59Ssowmini 	char			*fields_str = NULL;
5220*e7801d59Ssowmini 	print_field_t		**fields;
5221*e7801d59Ssowmini 	uint_t			nfields;
5222*e7801d59Ssowmini 	char			*def_fields = "object,class";
5223*e7801d59Ssowmini 	char			*all_fields = "object,class,value";
52240ba2cbe9Sxc151355 
52250ba2cbe9Sxc151355 	opterr = 0;
5226*e7801d59Ssowmini 	bzero(&state, sizeof (state));
5227*e7801d59Ssowmini 	state.ss_parseable = B_FALSE;
5228*e7801d59Ssowmini 	fields_str = def_fields;
52290ba2cbe9Sxc151355 	state.ss_persist = B_FALSE;
52300ba2cbe9Sxc151355 	state.ss_parseable = B_FALSE;
52310ba2cbe9Sxc151355 	state.ss_header = B_TRUE;
5232*e7801d59Ssowmini 	while ((option = getopt_long(argc, argv, ":pPo:",
52330ba2cbe9Sxc151355 	    wifi_longopts, NULL)) != -1) {
52340ba2cbe9Sxc151355 		switch (option) {
52350ba2cbe9Sxc151355 		case 'p':
52360ba2cbe9Sxc151355 			state.ss_parseable = B_TRUE;
52370ba2cbe9Sxc151355 			break;
52380ba2cbe9Sxc151355 		case 'P':
52390ba2cbe9Sxc151355 			state.ss_persist = B_TRUE;
52400ba2cbe9Sxc151355 			break;
5241*e7801d59Ssowmini 		case 'o':
5242*e7801d59Ssowmini 			if (strcasecmp(optarg, "all") == 0)
5243*e7801d59Ssowmini 				fields_str = all_fields;
5244*e7801d59Ssowmini 			else
5245*e7801d59Ssowmini 				fields_str = optarg;
52460ba2cbe9Sxc151355 			break;
52470ba2cbe9Sxc151355 		default:
524833343a97Smeem 			die_opterr(optopt, option);
52490ba2cbe9Sxc151355 			break;
52500ba2cbe9Sxc151355 		}
52510ba2cbe9Sxc151355 	}
52520ba2cbe9Sxc151355 
5253*e7801d59Ssowmini 	fields = parse_output_fields(fields_str, secobj_fields,
5254*e7801d59Ssowmini 	    DEV_SOBJ_FIELDS, CMD_TYPE_ANY, &nfields);
5255*e7801d59Ssowmini 
5256*e7801d59Ssowmini 	if (fields == NULL) {
5257*e7801d59Ssowmini 		die("invalid field(s) specified");
5258*e7801d59Ssowmini 		return;
5259*e7801d59Ssowmini 	}
5260*e7801d59Ssowmini 	state.ss_print.ps_fields = fields;
5261*e7801d59Ssowmini 	state.ss_print.ps_nfields = nfields;
5262*e7801d59Ssowmini 
5263*e7801d59Ssowmini 	flags = state.ss_persist ? DLADM_OPT_PERSIST : 0;
52640ba2cbe9Sxc151355 	if (optind == (argc - 1)) {
52650ba2cbe9Sxc151355 		sp = split(argv[optind], MAX_SECOBJS, MAX_SECOBJ_NAMELEN);
52660ba2cbe9Sxc151355 		if (sp == NULL) {
526733343a97Smeem 			die("invalid secure object name(s): '%s'",
526833343a97Smeem 			    argv[optind]);
52690ba2cbe9Sxc151355 		}
52700ba2cbe9Sxc151355 		for (i = 0; i < sp->s_nfields; i++) {
52710ba2cbe9Sxc151355 			if (!show_secobj(&state, sp->s_fields[i]))
52720ba2cbe9Sxc151355 				break;
52730ba2cbe9Sxc151355 		}
52740ba2cbe9Sxc151355 		splitfree(sp);
52750ba2cbe9Sxc151355 		return;
52760ba2cbe9Sxc151355 	} else if (optind != argc)
52770ba2cbe9Sxc151355 		usage();
52780ba2cbe9Sxc151355 
52790ba2cbe9Sxc151355 	status = dladm_walk_secobj(&state, show_secobj, flags);
528033343a97Smeem 	if (status != DLADM_STATUS_OK)
528133343a97Smeem 		die_dlerr(status, "show-secobj");
52820ba2cbe9Sxc151355 }
52830ba2cbe9Sxc151355 
52840ba2cbe9Sxc151355 /*ARGSUSED*/
5285d62bc4baSyz147064 static int
5286d62bc4baSyz147064 i_dladm_init_linkprop(datalink_id_t linkid, void *arg)
5287d62bc4baSyz147064 {
5288d62bc4baSyz147064 	(void) dladm_init_linkprop(linkid);
5289d62bc4baSyz147064 	return (DLADM_WALK_CONTINUE);
5290d62bc4baSyz147064 }
5291d62bc4baSyz147064 
5292d62bc4baSyz147064 /* ARGSUSED */
52930ba2cbe9Sxc151355 static void
52940ba2cbe9Sxc151355 do_init_linkprop(int argc, char **argv)
52950ba2cbe9Sxc151355 {
5296d62bc4baSyz147064 	/*
5297d62bc4baSyz147064 	 * linkprops of links of other classes have been initialized as a
5298d62bc4baSyz147064 	 * part of the dladm up-xxx operation.
5299d62bc4baSyz147064 	 */
5300d62bc4baSyz147064 	(void) dladm_walk_datalink_id(i_dladm_init_linkprop, NULL,
5301d62bc4baSyz147064 	    DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST);
53020ba2cbe9Sxc151355 }
53030ba2cbe9Sxc151355 
53040ba2cbe9Sxc151355 /* ARGSUSED */
53050ba2cbe9Sxc151355 static void
5306*e7801d59Ssowmini do_show_ether(int argc, char **argv)
5307*e7801d59Ssowmini {
5308*e7801d59Ssowmini 	int 			option;
5309*e7801d59Ssowmini 	datalink_id_t		linkid;
5310*e7801d59Ssowmini 	print_ether_state_t 	state;
5311*e7801d59Ssowmini 	print_field_t 		**fields;
5312*e7801d59Ssowmini 	char			*fields_str;
5313*e7801d59Ssowmini 	uint_t			nfields;
5314*e7801d59Ssowmini 	char *all_fields =
5315*e7801d59Ssowmini 	    "link,ptype,state,auto,speed-duplex,pause,rem_fault";
5316*e7801d59Ssowmini 	char *default_fields =
5317*e7801d59Ssowmini 	    "link,ptype,state,auto,speed-duplex,pause";
5318*e7801d59Ssowmini 
5319*e7801d59Ssowmini 	fields_str = default_fields;
5320*e7801d59Ssowmini 	bzero(&state, sizeof (state));
5321*e7801d59Ssowmini 	state.es_link = NULL;
5322*e7801d59Ssowmini 	state.es_parseable = B_FALSE;
5323*e7801d59Ssowmini 
5324*e7801d59Ssowmini 	while ((option = getopt_long(argc, argv, "o:px",
5325*e7801d59Ssowmini 	    showeth_lopts, NULL)) != -1) {
5326*e7801d59Ssowmini 		switch (option) {
5327*e7801d59Ssowmini 			case 'x':
5328*e7801d59Ssowmini 				state.es_extended = B_TRUE;
5329*e7801d59Ssowmini 				break;
5330*e7801d59Ssowmini 			case 'p':
5331*e7801d59Ssowmini 				state.es_parseable = B_TRUE;
5332*e7801d59Ssowmini 				break;
5333*e7801d59Ssowmini 			case 'o':
5334*e7801d59Ssowmini 				if (strcasecmp(optarg, "all") == 0)
5335*e7801d59Ssowmini 					fields_str = all_fields;
5336*e7801d59Ssowmini 				else
5337*e7801d59Ssowmini 					fields_str = optarg;
5338*e7801d59Ssowmini 				break;
5339*e7801d59Ssowmini 			default:
5340*e7801d59Ssowmini 				die_opterr(optopt, option);
5341*e7801d59Ssowmini 				break;
5342*e7801d59Ssowmini 		}
5343*e7801d59Ssowmini 	}
5344*e7801d59Ssowmini 
5345*e7801d59Ssowmini 	if (optind == (argc - 1))
5346*e7801d59Ssowmini 		state.es_link = argv[optind];
5347*e7801d59Ssowmini 
5348*e7801d59Ssowmini 	fields = parse_output_fields(fields_str, ether_fields,
5349*e7801d59Ssowmini 	    ETHER_MAX_FIELDS, CMD_TYPE_ANY, &nfields);
5350*e7801d59Ssowmini 
5351*e7801d59Ssowmini 	if (fields == NULL) {
5352*e7801d59Ssowmini 		die("invalid field(s) specified");
5353*e7801d59Ssowmini 		exit(EXIT_FAILURE);
5354*e7801d59Ssowmini 	}
5355*e7801d59Ssowmini 	state.es_print.ps_fields = fields;
5356*e7801d59Ssowmini 	state.es_print.ps_nfields = nfields;
5357*e7801d59Ssowmini 
5358*e7801d59Ssowmini 	if (state.es_link == NULL) {
5359*e7801d59Ssowmini 		(void) dladm_walk_datalink_id(show_etherprop, &state,
5360*e7801d59Ssowmini 		    DATALINK_CLASS_PHYS, DL_ETHER,
5361*e7801d59Ssowmini 		    DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST);
5362*e7801d59Ssowmini 	} else {
5363*e7801d59Ssowmini 		if (!link_is_ether(state.es_link, &linkid)) {
5364*e7801d59Ssowmini 			die("invalid link specified");
5365*e7801d59Ssowmini 		}
5366*e7801d59Ssowmini 		(void) show_etherprop(linkid, &state);
5367*e7801d59Ssowmini 	}
5368*e7801d59Ssowmini 
5369*e7801d59Ssowmini 	exit(DLADM_STATUS_OK);
5370*e7801d59Ssowmini 
5371*e7801d59Ssowmini }
5372*e7801d59Ssowmini 
5373*e7801d59Ssowmini static char *
5374*e7801d59Ssowmini dladm_print_field(print_field_t *pf, void *arg)
5375*e7801d59Ssowmini {
5376*e7801d59Ssowmini 	char *value;
5377*e7801d59Ssowmini 
5378*e7801d59Ssowmini 	value = (char *)arg + pf->pf_offset;
5379*e7801d59Ssowmini 	return (value);
5380*e7801d59Ssowmini }
5381*e7801d59Ssowmini 
5382*e7801d59Ssowmini static int
5383*e7801d59Ssowmini show_etherprop(datalink_id_t linkid, void *arg)
5384*e7801d59Ssowmini {
5385*e7801d59Ssowmini 	print_ether_state_t *statep = arg;
5386*e7801d59Ssowmini 	char buf[DLADM_STRSIZE];
5387*e7801d59Ssowmini 	int speed;
5388*e7801d59Ssowmini 	uint64_t s;
5389*e7801d59Ssowmini 	uint32_t autoneg, pause, asmpause, adv_rf, cap_rf, lp_rf;
5390*e7801d59Ssowmini 	ether_fields_buf_t ebuf;
5391*e7801d59Ssowmini 	char speed_unit = 'M';
5392*e7801d59Ssowmini 
5393*e7801d59Ssowmini 	if (dladm_datalink_id2info(linkid, NULL, NULL, NULL,
5394*e7801d59Ssowmini 	    ebuf.eth_link, sizeof (ebuf.eth_link)) != DLADM_STATUS_OK) {
5395*e7801d59Ssowmini 		return (DLADM_WALK_CONTINUE);
5396*e7801d59Ssowmini 	}
5397*e7801d59Ssowmini 
5398*e7801d59Ssowmini 	if (!statep->es_header && !statep->es_parseable) {
5399*e7801d59Ssowmini 		print_header(&statep->es_print);
5400*e7801d59Ssowmini 		statep->es_header = B_TRUE;
5401*e7801d59Ssowmini 	}
5402*e7801d59Ssowmini 	(void) snprintf(ebuf.eth_ptype, sizeof (ebuf.eth_ptype),
5403*e7801d59Ssowmini 	    "%s", "current");
5404*e7801d59Ssowmini 
5405*e7801d59Ssowmini 	(void) dladm_get_single_mac_stat(linkid, "link_autoneg",
5406*e7801d59Ssowmini 	    KSTAT_DATA_UINT32, &autoneg);
5407*e7801d59Ssowmini 	(void) snprintf(ebuf.eth_autoneg, sizeof (ebuf.eth_autoneg),
5408*e7801d59Ssowmini 	    "%s", (autoneg ? "yes" : "no"));
5409*e7801d59Ssowmini 
5410*e7801d59Ssowmini 	(void) dladm_get_single_mac_stat(linkid, "link_pause",
5411*e7801d59Ssowmini 	    KSTAT_DATA_UINT32, &pause);
5412*e7801d59Ssowmini 	(void) dladm_get_single_mac_stat(linkid, "link_asmpause",
5413*e7801d59Ssowmini 	    KSTAT_DATA_UINT32, &asmpause);
5414*e7801d59Ssowmini 	(void) snprintf(ebuf.eth_pause, sizeof (ebuf.eth_pause),
5415*e7801d59Ssowmini 	    "%s", pause_str(pause, asmpause));
5416*e7801d59Ssowmini 
5417*e7801d59Ssowmini 	(void) dladm_get_single_mac_stat(linkid, "ifspeed",
5418*e7801d59Ssowmini 	    KSTAT_DATA_UINT64, &s);
5419*e7801d59Ssowmini 	speed = (int)(s/1000000ull);
5420*e7801d59Ssowmini 
5421*e7801d59Ssowmini 	if (speed >= 1000) {
5422*e7801d59Ssowmini 		speed = speed/1000;
5423*e7801d59Ssowmini 		speed_unit = 'G';
5424*e7801d59Ssowmini 	}
5425*e7801d59Ssowmini 	(void) get_linkduplex(ebuf.eth_link, B_FALSE, buf);
5426*e7801d59Ssowmini 	(void) snprintf(ebuf.eth_spdx, sizeof (ebuf.eth_spdx), "%d%c-%c",
5427*e7801d59Ssowmini 	    speed, speed_unit, buf[0]);
5428*e7801d59Ssowmini 
5429*e7801d59Ssowmini 	(void) get_linkstate(ebuf.eth_link, B_FALSE, buf);
5430*e7801d59Ssowmini 	(void) snprintf(ebuf.eth_state, sizeof (ebuf.eth_state),
5431*e7801d59Ssowmini 	    "%s", buf);
5432*e7801d59Ssowmini 
5433*e7801d59Ssowmini 	(void) dladm_get_single_mac_stat(linkid, "adv_rem_fault",
5434*e7801d59Ssowmini 	    KSTAT_DATA_UINT32, &adv_rf);
5435*e7801d59Ssowmini 	(void) dladm_get_single_mac_stat(linkid, "cap_rem_fault",
5436*e7801d59Ssowmini 	    KSTAT_DATA_UINT32, &cap_rf);
5437*e7801d59Ssowmini 	(void) dladm_get_single_mac_stat(linkid, "lp_rem_fault",
5438*e7801d59Ssowmini 	    KSTAT_DATA_UINT32, &lp_rf);
5439*e7801d59Ssowmini 	(void) snprintf(ebuf.eth_rem_fault, sizeof (ebuf.eth_rem_fault),
5440*e7801d59Ssowmini 	    "%s", (adv_rf == 0 && lp_rf == 0 ? "none" : "fault"));
5441*e7801d59Ssowmini 
5442*e7801d59Ssowmini 	dladm_print_output(&statep->es_print, statep->es_parseable,
5443*e7801d59Ssowmini 	    dladm_print_field, &ebuf);
5444*e7801d59Ssowmini 
5445*e7801d59Ssowmini 	if (statep->es_extended)
5446*e7801d59Ssowmini 		show_ether_xprop(linkid, arg);
5447*e7801d59Ssowmini 
5448*e7801d59Ssowmini 	return (DLADM_WALK_CONTINUE);
5449*e7801d59Ssowmini }
5450*e7801d59Ssowmini 
5451*e7801d59Ssowmini /* ARGSUSED */
5452*e7801d59Ssowmini static void
54530ba2cbe9Sxc151355 do_init_secobj(int argc, char **argv)
54540ba2cbe9Sxc151355 {
54550ba2cbe9Sxc151355 	dladm_status_t status;
54560ba2cbe9Sxc151355 
54570ba2cbe9Sxc151355 	status = dladm_init_secobj();
545833343a97Smeem 	if (status != DLADM_STATUS_OK)
545933343a97Smeem 		die_dlerr(status, "secure object initialization failed");
546033343a97Smeem }
546133343a97Smeem 
5462d62bc4baSyz147064 /*
5463d62bc4baSyz147064  * "-R" option support. It is used for live upgrading. Append dladm commands
5464d62bc4baSyz147064  * to a upgrade script which will be run when the alternative root boots up:
5465d62bc4baSyz147064  *
5466d62bc4baSyz147064  * - If the dlmgmtd door file exists on the alternative root, append dladm
5467d62bc4baSyz147064  * commands to the <altroot>/var/svc/profile/upgrade_datalink script. This
5468d62bc4baSyz147064  * script will be run as part of the network/physical service. We cannot defer
5469d62bc4baSyz147064  * this to /var/svc/profile/upgrade because then the configuration will not
5470d62bc4baSyz147064  * be able to take effect before network/physical plumbs various interfaces.
5471d62bc4baSyz147064  *
5472d62bc4baSyz147064  * - If the dlmgmtd door file does not exist on the alternative root, append
5473d62bc4baSyz147064  * dladm commands to the <altroot>/var/svc/profile/upgrade script, which will
5474d62bc4baSyz147064  * be run in the manifest-import service.
5475d62bc4baSyz147064  *
5476d62bc4baSyz147064  * Note that the SMF team is considering to move the manifest-import service
5477d62bc4baSyz147064  * to be run at the very begining of boot. Once that is done, the need for
5478d62bc4baSyz147064  * the /var/svc/profile/upgrade_datalink script will not exist any more.
5479d62bc4baSyz147064  */
5480d62bc4baSyz147064 static void
5481d62bc4baSyz147064 altroot_cmd(char *altroot, int argc, char *argv[])
5482d62bc4baSyz147064 {
5483d62bc4baSyz147064 	char		path[MAXPATHLEN];
5484d62bc4baSyz147064 	struct stat	stbuf;
5485d62bc4baSyz147064 	FILE		*fp;
5486d62bc4baSyz147064 	int		i;
5487d62bc4baSyz147064 
5488d62bc4baSyz147064 	/*
5489d62bc4baSyz147064 	 * Check for the existence of the dlmgmtd door file, and determine
5490d62bc4baSyz147064 	 * the name of script file.
5491d62bc4baSyz147064 	 */
5492d62bc4baSyz147064 	(void) snprintf(path, MAXPATHLEN, "/%s/%s", altroot, DLMGMT_DOOR);
5493d62bc4baSyz147064 	if (stat(path, &stbuf) < 0) {
5494d62bc4baSyz147064 		(void) snprintf(path, MAXPATHLEN, "/%s/%s", altroot,
5495d62bc4baSyz147064 		    SMF_UPGRADE_FILE);
5496d62bc4baSyz147064 	} else {
5497d62bc4baSyz147064 		(void) snprintf(path, MAXPATHLEN, "/%s/%s", altroot,
5498d62bc4baSyz147064 		    SMF_UPGRADEDATALINK_FILE);
5499d62bc4baSyz147064 	}
5500d62bc4baSyz147064 
5501d62bc4baSyz147064 	if ((fp = fopen(path, "a+")) == NULL)
5502d62bc4baSyz147064 		die("operation not supported on %s", altroot);
5503d62bc4baSyz147064 
5504d62bc4baSyz147064 	(void) fprintf(fp, "/sbin/dladm ");
5505d62bc4baSyz147064 	for (i = 0; i < argc; i++) {
5506d62bc4baSyz147064 		/*
5507d62bc4baSyz147064 		 * Directly write to the file if it is not the "-R <altroot>"
5508d62bc4baSyz147064 		 * option. In which case, skip it.
5509d62bc4baSyz147064 		 */
5510d62bc4baSyz147064 		if (strcmp(argv[i], "-R") != 0)
5511d62bc4baSyz147064 			(void) fprintf(fp, "%s ", argv[i]);
5512d62bc4baSyz147064 		else
5513d62bc4baSyz147064 			i ++;
5514d62bc4baSyz147064 	}
5515d62bc4baSyz147064 	(void) fprintf(fp, "%s\n", SMF_DLADM_UPGRADE_MSG);
5516d62bc4baSyz147064 	(void) fclose(fp);
5517d62bc4baSyz147064 	exit(0);
5518d62bc4baSyz147064 }
5519d62bc4baSyz147064 
5520d62bc4baSyz147064 /*
5521d62bc4baSyz147064  * Convert the string to an integer. Note that the string must not have any
5522d62bc4baSyz147064  * trailing non-integer characters.
5523d62bc4baSyz147064  */
552433343a97Smeem static boolean_t
552533343a97Smeem str2int(const char *str, int *valp)
552633343a97Smeem {
552733343a97Smeem 	int	val;
552833343a97Smeem 	char	*endp = NULL;
552933343a97Smeem 
553033343a97Smeem 	errno = 0;
553133343a97Smeem 	val = strtol(str, &endp, 10);
553233343a97Smeem 	if (errno != 0 || *endp != '\0')
553333343a97Smeem 		return (B_FALSE);
553433343a97Smeem 
553533343a97Smeem 	*valp = val;
553633343a97Smeem 	return (B_TRUE);
553733343a97Smeem }
553833343a97Smeem 
553933343a97Smeem /* PRINTFLIKE1 */
554033343a97Smeem static void
554133343a97Smeem warn(const char *format, ...)
554233343a97Smeem {
554333343a97Smeem 	va_list alist;
554433343a97Smeem 
554533343a97Smeem 	format = gettext(format);
554633343a97Smeem 	(void) fprintf(stderr, "%s: warning: ", progname);
554733343a97Smeem 
554833343a97Smeem 	va_start(alist, format);
554933343a97Smeem 	(void) vfprintf(stderr, format, alist);
555033343a97Smeem 	va_end(alist);
555133343a97Smeem 
555233343a97Smeem 	(void) putchar('\n');
555333343a97Smeem }
555433343a97Smeem 
555533343a97Smeem /* PRINTFLIKE2 */
555633343a97Smeem static void
555733343a97Smeem warn_dlerr(dladm_status_t err, const char *format, ...)
555833343a97Smeem {
555933343a97Smeem 	va_list alist;
556033343a97Smeem 	char	errmsg[DLADM_STRSIZE];
556133343a97Smeem 
556233343a97Smeem 	format = gettext(format);
556333343a97Smeem 	(void) fprintf(stderr, gettext("%s: warning: "), progname);
556433343a97Smeem 
556533343a97Smeem 	va_start(alist, format);
556633343a97Smeem 	(void) vfprintf(stderr, format, alist);
556733343a97Smeem 	va_end(alist);
556833343a97Smeem 	(void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg));
556933343a97Smeem }
557033343a97Smeem 
557133343a97Smeem /* PRINTFLIKE2 */
557233343a97Smeem static void
557333343a97Smeem die_dlerr(dladm_status_t err, const char *format, ...)
557433343a97Smeem {
557533343a97Smeem 	va_list alist;
557633343a97Smeem 	char	errmsg[DLADM_STRSIZE];
557733343a97Smeem 
557833343a97Smeem 	format = gettext(format);
557933343a97Smeem 	(void) fprintf(stderr, "%s: ", progname);
558033343a97Smeem 
558133343a97Smeem 	va_start(alist, format);
558233343a97Smeem 	(void) vfprintf(stderr, format, alist);
558333343a97Smeem 	va_end(alist);
558433343a97Smeem 	(void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg));
558533343a97Smeem 
558633343a97Smeem 	exit(EXIT_FAILURE);
558733343a97Smeem }
558833343a97Smeem 
558933343a97Smeem /* PRINTFLIKE1 */
559033343a97Smeem static void
559133343a97Smeem die(const char *format, ...)
559233343a97Smeem {
559333343a97Smeem 	va_list alist;
559433343a97Smeem 
559533343a97Smeem 	format = gettext(format);
559633343a97Smeem 	(void) fprintf(stderr, "%s: ", progname);
559733343a97Smeem 
559833343a97Smeem 	va_start(alist, format);
559933343a97Smeem 	(void) vfprintf(stderr, format, alist);
560033343a97Smeem 	va_end(alist);
560133343a97Smeem 
560233343a97Smeem 	(void) putchar('\n');
560333343a97Smeem 	exit(EXIT_FAILURE);
560433343a97Smeem }
560533343a97Smeem 
560633343a97Smeem static void
560733343a97Smeem die_optdup(int opt)
560833343a97Smeem {
560933343a97Smeem 	die("the option -%c cannot be specified more than once", opt);
561033343a97Smeem }
561133343a97Smeem 
561233343a97Smeem static void
561333343a97Smeem die_opterr(int opt, int opterr)
561433343a97Smeem {
561533343a97Smeem 	switch (opterr) {
561633343a97Smeem 	case ':':
561733343a97Smeem 		die("option '-%c' requires a value", opt);
561833343a97Smeem 		break;
561933343a97Smeem 	case '?':
562033343a97Smeem 	default:
562133343a97Smeem 		die("unrecognized option '-%c'", opt);
562233343a97Smeem 		break;
56230ba2cbe9Sxc151355 	}
56240ba2cbe9Sxc151355 }
5625*e7801d59Ssowmini 
5626*e7801d59Ssowmini static void
5627*e7801d59Ssowmini show_ether_xprop(datalink_id_t linkid, void *arg)
5628*e7801d59Ssowmini {
5629*e7801d59Ssowmini 	print_ether_state_t *statep = arg;
5630*e7801d59Ssowmini 	char buf[DLADM_STRSIZE];
5631*e7801d59Ssowmini 	uint32_t autoneg, pause, asmpause, adv_rf, cap_rf, lp_rf;
5632*e7801d59Ssowmini 	boolean_t add_comma, r1;
5633*e7801d59Ssowmini 	ether_fields_buf_t ebuf;
5634*e7801d59Ssowmini 
5635*e7801d59Ssowmini 	/* capable */
5636*e7801d59Ssowmini 	bzero(&ebuf, sizeof (ebuf));
5637*e7801d59Ssowmini 	(void) snprintf(ebuf.eth_link, sizeof (ebuf.eth_link), "");
5638*e7801d59Ssowmini 
5639*e7801d59Ssowmini 	(void) snprintf(ebuf.eth_ptype, sizeof (ebuf.eth_ptype),
5640*e7801d59Ssowmini 	    "%s", "capable");
5641*e7801d59Ssowmini 	(void) snprintf(ebuf.eth_state, sizeof (ebuf.eth_state),
5642*e7801d59Ssowmini 	    STR_UNDEF_VAL);
5643*e7801d59Ssowmini 
5644*e7801d59Ssowmini 	(void) dladm_get_single_mac_stat(linkid, "cap_autoneg",
5645*e7801d59Ssowmini 	    KSTAT_DATA_UINT32, &autoneg);
5646*e7801d59Ssowmini 	(void) snprintf(ebuf.eth_autoneg, sizeof (ebuf.eth_autoneg),
5647*e7801d59Ssowmini 	    "%s", (autoneg ? "yes" : "no"));
5648*e7801d59Ssowmini 
5649*e7801d59Ssowmini 	add_comma = B_FALSE;
5650*e7801d59Ssowmini 	bzero(buf, sizeof (buf));
5651*e7801d59Ssowmini 	r1 = get_speed_duplex(linkid, "cap_1000", buf, "1G", B_FALSE);
5652*e7801d59Ssowmini 	if (r1)
5653*e7801d59Ssowmini 		add_comma = B_TRUE;
5654*e7801d59Ssowmini 	r1 = get_speed_duplex(linkid, "cap_100", buf, "100M", add_comma);
5655*e7801d59Ssowmini 	if (r1)
5656*e7801d59Ssowmini 		add_comma = B_TRUE;
5657*e7801d59Ssowmini 	r1 = get_speed_duplex(linkid, "cap_10", buf, "10M", add_comma);
5658*e7801d59Ssowmini 	add_comma = B_FALSE;
5659*e7801d59Ssowmini 	(void) snprintf(ebuf.eth_spdx, sizeof (ebuf.eth_spdx), "%s", buf);
5660*e7801d59Ssowmini 
5661*e7801d59Ssowmini 	(void) dladm_get_single_mac_stat(linkid, "cap_pause",
5662*e7801d59Ssowmini 	    KSTAT_DATA_UINT32, &pause);
5663*e7801d59Ssowmini 	(void) dladm_get_single_mac_stat(linkid, "cap_asmpause",
5664*e7801d59Ssowmini 	    KSTAT_DATA_UINT32, &asmpause);
5665*e7801d59Ssowmini 	(void) snprintf(ebuf.eth_pause, sizeof (ebuf.eth_pause),
5666*e7801d59Ssowmini 	    "%s", pause_str(pause, asmpause));
5667*e7801d59Ssowmini 
5668*e7801d59Ssowmini 	(void) dladm_get_single_mac_stat(linkid, "adv_rem_fault",
5669*e7801d59Ssowmini 	    KSTAT_DATA_UINT32, &adv_rf);
5670*e7801d59Ssowmini 	(void) dladm_get_single_mac_stat(linkid, "cap_rem_fault",
5671*e7801d59Ssowmini 	    KSTAT_DATA_UINT32, &cap_rf);
5672*e7801d59Ssowmini 	(void) dladm_get_single_mac_stat(linkid, "lp_rem_fault",
5673*e7801d59Ssowmini 	    KSTAT_DATA_UINT32, &lp_rf);
5674*e7801d59Ssowmini 
5675*e7801d59Ssowmini 	(void) snprintf(ebuf.eth_rem_fault, sizeof (ebuf.eth_rem_fault),
5676*e7801d59Ssowmini 	    "%s", (cap_rf ? "yes" : "no"));
5677*e7801d59Ssowmini 
5678*e7801d59Ssowmini 	dladm_print_output(&statep->es_print, statep->es_parseable,
5679*e7801d59Ssowmini 	    dladm_print_field, &ebuf);
5680*e7801d59Ssowmini 
5681*e7801d59Ssowmini 	/* advertised */
5682*e7801d59Ssowmini 	bzero(&ebuf, sizeof (ebuf));
5683*e7801d59Ssowmini 	(void) snprintf(ebuf.eth_ptype, sizeof (ebuf.eth_ptype),
5684*e7801d59Ssowmini 	    "%s", "adv");
5685*e7801d59Ssowmini 	(void) snprintf(ebuf.eth_state, sizeof (ebuf.eth_state),
5686*e7801d59Ssowmini 	    STR_UNDEF_VAL);
5687*e7801d59Ssowmini 
5688*e7801d59Ssowmini 	(void) dladm_get_single_mac_stat(linkid, "adv_cap_autoneg",
5689*e7801d59Ssowmini 	    KSTAT_DATA_UINT32, &autoneg);
5690*e7801d59Ssowmini 	(void) snprintf(ebuf.eth_autoneg, sizeof (ebuf.eth_autoneg),
5691*e7801d59Ssowmini 	    "%s", (autoneg ? "yes" : "no"));
5692*e7801d59Ssowmini 
5693*e7801d59Ssowmini 	add_comma = B_FALSE;
5694*e7801d59Ssowmini 	bzero(buf, sizeof (buf));
5695*e7801d59Ssowmini 	r1 = get_speed_duplex(linkid, "adv_cap_1000", buf, "1G", add_comma);
5696*e7801d59Ssowmini 	if (r1)
5697*e7801d59Ssowmini 		add_comma = B_TRUE;
5698*e7801d59Ssowmini 	r1 = get_speed_duplex(linkid, "adv_cap_100", buf, "100M", add_comma);
5699*e7801d59Ssowmini 	if (r1)
5700*e7801d59Ssowmini 		add_comma = B_TRUE;
5701*e7801d59Ssowmini 	r1 = get_speed_duplex(linkid, "adv_cap_10", buf, "10M", add_comma);
5702*e7801d59Ssowmini 	add_comma = B_FALSE;
5703*e7801d59Ssowmini 	(void) snprintf(ebuf.eth_spdx, sizeof (ebuf.eth_spdx), "%s", buf);
5704*e7801d59Ssowmini 
5705*e7801d59Ssowmini 	(void) dladm_get_single_mac_stat(linkid, "adv_cap_pause",
5706*e7801d59Ssowmini 	    KSTAT_DATA_UINT32, &pause);
5707*e7801d59Ssowmini 	(void) dladm_get_single_mac_stat(linkid, "adv_cap_asmpause",
5708*e7801d59Ssowmini 	    KSTAT_DATA_UINT32, &asmpause);
5709*e7801d59Ssowmini 	(void) snprintf(ebuf.eth_pause, sizeof (ebuf.eth_pause),
5710*e7801d59Ssowmini 	    "%s", pause_str(pause, asmpause));
5711*e7801d59Ssowmini 
5712*e7801d59Ssowmini 	(void) snprintf(ebuf.eth_rem_fault, sizeof (ebuf.eth_rem_fault),
5713*e7801d59Ssowmini 	    "%s", (adv_rf ? "fault" : "none"));
5714*e7801d59Ssowmini 
5715*e7801d59Ssowmini 	dladm_print_output(&statep->es_print, statep->es_parseable,
5716*e7801d59Ssowmini 	    dladm_print_field, &ebuf);
5717*e7801d59Ssowmini 
5718*e7801d59Ssowmini 	/* peeradv */
5719*e7801d59Ssowmini 	bzero(&ebuf, sizeof (ebuf));
5720*e7801d59Ssowmini 	(void) snprintf(ebuf.eth_ptype, sizeof (ebuf.eth_ptype),
5721*e7801d59Ssowmini 	    "%s", "peeradv");
5722*e7801d59Ssowmini 	(void) snprintf(ebuf.eth_state, sizeof (ebuf.eth_state),
5723*e7801d59Ssowmini 	    STR_UNDEF_VAL);
5724*e7801d59Ssowmini 
5725*e7801d59Ssowmini 	(void) dladm_get_single_mac_stat(linkid, "lp_cap_autoneg",
5726*e7801d59Ssowmini 	    KSTAT_DATA_UINT32, &autoneg);
5727*e7801d59Ssowmini 	(void) snprintf(ebuf.eth_autoneg, sizeof (ebuf.eth_autoneg),
5728*e7801d59Ssowmini 	    "%s", (autoneg ? "yes" : "no"));
5729*e7801d59Ssowmini 
5730*e7801d59Ssowmini 	add_comma = B_FALSE;
5731*e7801d59Ssowmini 	bzero(buf, sizeof (buf));
5732*e7801d59Ssowmini 	r1 = get_speed_duplex(linkid, "lp_cap_1000", buf, "1G", add_comma);
5733*e7801d59Ssowmini 	if (r1)
5734*e7801d59Ssowmini 		add_comma = B_TRUE;
5735*e7801d59Ssowmini 	r1 = get_speed_duplex(linkid, "lp_cap_100", buf, "100M", add_comma);
5736*e7801d59Ssowmini 	if (r1)
5737*e7801d59Ssowmini 		add_comma = B_TRUE;
5738*e7801d59Ssowmini 	r1 = get_speed_duplex(linkid, "lp_cap_10", buf, "10M", add_comma);
5739*e7801d59Ssowmini 	(void) snprintf(ebuf.eth_spdx, sizeof (ebuf.eth_spdx), "%s", buf);
5740*e7801d59Ssowmini 
5741*e7801d59Ssowmini 	(void) dladm_get_single_mac_stat(linkid, "lp_cap_pause",
5742*e7801d59Ssowmini 	    KSTAT_DATA_UINT32, &pause);
5743*e7801d59Ssowmini 	(void) dladm_get_single_mac_stat(linkid, "lp_cap_asmpause",
5744*e7801d59Ssowmini 	    KSTAT_DATA_UINT32, &asmpause);
5745*e7801d59Ssowmini 	(void) snprintf(ebuf.eth_pause, sizeof (ebuf.eth_pause),
5746*e7801d59Ssowmini 	    "%s", pause_str(pause, asmpause));
5747*e7801d59Ssowmini 
5748*e7801d59Ssowmini 	(void) snprintf(ebuf.eth_rem_fault, sizeof (ebuf.eth_rem_fault),
5749*e7801d59Ssowmini 	    "%s", (lp_rf ? "fault" : "none"));
5750*e7801d59Ssowmini 
5751*e7801d59Ssowmini 	dladm_print_output(&statep->es_print, statep->es_parseable,
5752*e7801d59Ssowmini 	    dladm_print_field, &ebuf);
5753*e7801d59Ssowmini }
5754*e7801d59Ssowmini 
5755*e7801d59Ssowmini static boolean_t
5756*e7801d59Ssowmini get_speed_duplex(datalink_id_t linkid, const char *mii_prop_prefix,
5757*e7801d59Ssowmini     char *spbuf, char *sp, boolean_t add_comma)
5758*e7801d59Ssowmini {
5759*e7801d59Ssowmini 	int speed, duplex = 0;
5760*e7801d59Ssowmini 	boolean_t ret = B_FALSE;
5761*e7801d59Ssowmini 	char mii_prop[DLADM_STRSIZE];
5762*e7801d59Ssowmini 
5763*e7801d59Ssowmini 	(void) snprintf(mii_prop, DLADM_STRSIZE, "%sfdx", mii_prop_prefix);
5764*e7801d59Ssowmini 	(void) dladm_get_single_mac_stat(linkid, mii_prop, KSTAT_DATA_UINT32,
5765*e7801d59Ssowmini 	    &speed);
5766*e7801d59Ssowmini 	if (speed) {
5767*e7801d59Ssowmini 		ret = B_TRUE;
5768*e7801d59Ssowmini 		duplex  |= IS_FDX;
5769*e7801d59Ssowmini 	}
5770*e7801d59Ssowmini 	(void) snprintf(mii_prop, DLADM_STRSIZE, "%shdx", mii_prop_prefix);
5771*e7801d59Ssowmini 	(void) dladm_get_single_mac_stat(linkid, mii_prop,
5772*e7801d59Ssowmini 	    KSTAT_DATA_UINT32, &speed);
5773*e7801d59Ssowmini 	if (speed) {
5774*e7801d59Ssowmini 		ret = B_TRUE;
5775*e7801d59Ssowmini 		duplex |= IS_HDX;
5776*e7801d59Ssowmini 	}
5777*e7801d59Ssowmini 	if (ret) {
5778*e7801d59Ssowmini 		if (add_comma)
5779*e7801d59Ssowmini 			(void) strncat(spbuf, ",", DLADM_STRSIZE);
5780*e7801d59Ssowmini 		(void) strncat(spbuf, sp, DLADM_STRSIZE);
5781*e7801d59Ssowmini 		if ((duplex & (IS_FDX|IS_HDX)) == (IS_FDX|IS_HDX))
5782*e7801d59Ssowmini 			(void) strncat(spbuf, "-fh", DLADM_STRSIZE);
5783*e7801d59Ssowmini 		else if (duplex & IS_FDX)
5784*e7801d59Ssowmini 			(void) strncat(spbuf, "-f", DLADM_STRSIZE);
5785*e7801d59Ssowmini 		else if (duplex & IS_HDX)
5786*e7801d59Ssowmini 			(void) strncat(spbuf, "-h", DLADM_STRSIZE);
5787*e7801d59Ssowmini 	}
5788*e7801d59Ssowmini 	return (ret);
5789*e7801d59Ssowmini }
5790*e7801d59Ssowmini 
5791*e7801d59Ssowmini static void
5792*e7801d59Ssowmini dladm_print_output(print_state_t *statep, boolean_t parseable,
5793*e7801d59Ssowmini     print_callback_t fn, void *arg)
5794*e7801d59Ssowmini {
5795*e7801d59Ssowmini 	int i;
5796*e7801d59Ssowmini 	char *value;
5797*e7801d59Ssowmini 	print_field_t **pf;
5798*e7801d59Ssowmini 
5799*e7801d59Ssowmini 	pf = statep->ps_fields;
5800*e7801d59Ssowmini 	for (i = 0; i < statep->ps_nfields; i++) {
5801*e7801d59Ssowmini 		statep->ps_lastfield = (i + 1 == statep->ps_nfields);
5802*e7801d59Ssowmini 		value = (*fn)(pf[i], arg);
5803*e7801d59Ssowmini 		if (value != NULL)
5804*e7801d59Ssowmini 			print_field(statep, pf[i], value, parseable);
5805*e7801d59Ssowmini 	}
5806*e7801d59Ssowmini 	(void) putchar('\n');
5807*e7801d59Ssowmini }
5808*e7801d59Ssowmini 
5809*e7801d59Ssowmini static void
5810*e7801d59Ssowmini print_header(print_state_t *ps)
5811*e7801d59Ssowmini {
5812*e7801d59Ssowmini 	int i;
5813*e7801d59Ssowmini 	print_field_t **pf;
5814*e7801d59Ssowmini 
5815*e7801d59Ssowmini 	pf = ps->ps_fields;
5816*e7801d59Ssowmini 	for (i = 0; i < ps->ps_nfields; i++) {
5817*e7801d59Ssowmini 		ps->ps_lastfield = (i + 1 == ps->ps_nfields);
5818*e7801d59Ssowmini 		print_field(ps, pf[i], pf[i]->pf_header, B_FALSE);
5819*e7801d59Ssowmini 	}
5820*e7801d59Ssowmini 	(void) putchar('\n');
5821*e7801d59Ssowmini }
5822*e7801d59Ssowmini 
5823*e7801d59Ssowmini static char *
5824*e7801d59Ssowmini pause_str(int pause, int asmpause)
5825*e7801d59Ssowmini {
5826*e7801d59Ssowmini 	if (pause == 1)
5827*e7801d59Ssowmini 		return ("bi");
5828*e7801d59Ssowmini 	if (asmpause == 1)
5829*e7801d59Ssowmini 		return ("tx");
5830*e7801d59Ssowmini 	return ("none");
5831*e7801d59Ssowmini }
5832*e7801d59Ssowmini 
5833*e7801d59Ssowmini static boolean_t
5834*e7801d59Ssowmini link_is_ether(const char *link, datalink_id_t *linkid)
5835*e7801d59Ssowmini {
5836*e7801d59Ssowmini 	uint32_t media;
5837*e7801d59Ssowmini 	datalink_class_t class;
5838*e7801d59Ssowmini 
5839*e7801d59Ssowmini 	if (dladm_name2info(link, linkid, NULL, &class, &media) ==
5840*e7801d59Ssowmini 	    DLADM_STATUS_OK) {
5841*e7801d59Ssowmini 		if (class == DATALINK_CLASS_PHYS && media == DL_ETHER)
5842*e7801d59Ssowmini 			return (B_TRUE);
5843*e7801d59Ssowmini 	}
5844*e7801d59Ssowmini 	return (B_FALSE);
5845*e7801d59Ssowmini }
5846