xref: /titanic_53/usr/src/cmd/dladm/dladm.c (revision 149b7eb2919570a01d698963b7ab14d45b4edda8)
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 #include <stdio.h>
270ba2cbe9Sxc151355 #include <ctype.h>
287c478bd9Sstevel@tonic-gate #include <locale.h>
290ba2cbe9Sxc151355 #include <signal.h>
307c478bd9Sstevel@tonic-gate #include <stdarg.h>
317c478bd9Sstevel@tonic-gate #include <stdlib.h>
327c478bd9Sstevel@tonic-gate #include <fcntl.h>
337c478bd9Sstevel@tonic-gate #include <string.h>
347c478bd9Sstevel@tonic-gate #include <stropts.h>
35d62bc4baSyz147064 #include <sys/stat.h>
367c478bd9Sstevel@tonic-gate #include <errno.h>
377c478bd9Sstevel@tonic-gate #include <kstat.h>
387c478bd9Sstevel@tonic-gate #include <strings.h>
397c478bd9Sstevel@tonic-gate #include <getopt.h>
407c478bd9Sstevel@tonic-gate #include <unistd.h>
41cd93090eSericheng #include <priv.h>
420ba2cbe9Sxc151355 #include <termios.h>
430ba2cbe9Sxc151355 #include <pwd.h>
440ba2cbe9Sxc151355 #include <auth_attr.h>
450ba2cbe9Sxc151355 #include <auth_list.h>
467c478bd9Sstevel@tonic-gate #include <libintl.h>
47d62bc4baSyz147064 #include <libdevinfo.h>
487c478bd9Sstevel@tonic-gate #include <libdlpi.h>
49f595a68aSyz147064 #include <libdllink.h>
50f595a68aSyz147064 #include <libdlaggr.h>
51f595a68aSyz147064 #include <libdlwlan.h>
52d62bc4baSyz147064 #include <libdlvlan.h>
53d62bc4baSyz147064 #include <libdlvnic.h>
540ba2cbe9Sxc151355 #include <libinetutil.h>
550ba2cbe9Sxc151355 #include <bsm/adt.h>
560ba2cbe9Sxc151355 #include <bsm/adt_event.h>
57e7801d59Ssowmini #include <stddef.h>
587c478bd9Sstevel@tonic-gate 
59ba2e4443Sseb #define	AGGR_DRV		"aggr"
60e7801d59Ssowmini #define	STR_UNDEF_VAL		"--"
617c478bd9Sstevel@tonic-gate #define	MAXPORT			256
62d62bc4baSyz147064 #define	BUFLEN(lim, ptr)	(((lim) > (ptr)) ? ((lim) - (ptr)) : 0)
63d62bc4baSyz147064 #define	MAXLINELEN		1024
64d62bc4baSyz147064 #define	SMF_UPGRADE_FILE		"/var/svc/profile/upgrade"
65d62bc4baSyz147064 #define	SMF_UPGRADEDATALINK_FILE	"/var/svc/profile/upgrade_datalink"
66d62bc4baSyz147064 #define	SMF_DLADM_UPGRADE_MSG		" # added by dladm(1M)"
677c478bd9Sstevel@tonic-gate 
68e7801d59Ssowmini #define	CMD_TYPE_ANY		0xffffffff
69e7801d59Ssowmini #define	WIFI_CMD_SCAN		0x00000001
70e7801d59Ssowmini #define	WIFI_CMD_SHOW		0x00000002
71e7801d59Ssowmini #define	WIFI_CMD_ALL		(WIFI_CMD_SCAN | WIFI_CMD_SHOW)
72e7801d59Ssowmini 
73e7801d59Ssowmini /*
740d365605Sschuster  * Data structures and routines for printing output.
75e7801d59Ssowmini  * All non-parseable output is assumed to be in a columnar format.
760d365605Sschuster  * Multiple fields in parsable output are separated by ':'; single
770d365605Sschuster  * field output is printed as-is.
78e7801d59Ssowmini  *
79e7801d59Ssowmini  * Each sub-command is associated with a global array of pointers,
80e7801d59Ssowmini  * print_field_t *fields[], where the print_field_t contains information
81e7801d59Ssowmini  * about the format in which the output is to be printed.
82e7801d59Ssowmini  *
83e7801d59Ssowmini  * Sub-commands may be implemented in one of two ways:
84e7801d59Ssowmini  * (i)  the implementation could get all field values into a character
85e7801d59Ssowmini  *      buffer, with pf_offset containing the offset (for pf_name) within
86e7801d59Ssowmini  *      the buffer. The sub-command would make the needed system calls
87e7801d59Ssowmini  *      to obtain all possible column values and then invoke the
88e7801d59Ssowmini  *      dladm_print_field() function to print the specific fields
89e7801d59Ssowmini  *      requested in the command line. See the comments for dladm_print_field
90e7801d59Ssowmini  *      for further details.
91e7801d59Ssowmini  * (ii) Alternatively, each fields[i] entry could store a pf_index value
92e7801d59Ssowmini  *      that uniquely identifies the column to be printed. The implementation
93e7801d59Ssowmini  *      of the sub-command would then invoke dladm_print_output() with a
94e7801d59Ssowmini  *      callback function whose semantics are described below (see comments
95e7801d59Ssowmini  *      for dladm_print_output())
96e7801d59Ssowmini  *
97e7801d59Ssowmini  * Thus, an implementation of a sub-command must provide the following:
98e7801d59Ssowmini  *
99e7801d59Ssowmini  * static print_field_t sub_command_fields[] = {
100e7801d59Ssowmini  *	{<name>, <header>,<field width>,  <offset_or_index>, cmdtype},
101e7801d59Ssowmini  *	:
102e7801d59Ssowmini  *	{<name>, <header>,<field width>,  <offset_or_index>, cmdtype}
103e7801d59Ssowmini  * };
104e7801d59Ssowmini  *
105e7801d59Ssowmini  * #define	SUB_COMMAND_MAX_FIELDS sizeof \
106e7801d59Ssowmini  *		(sub_comand_fields) / sizeof (print_field_t))
107e7801d59Ssowmini  *
108e7801d59Ssowmini  * print_state_t sub_command_print_state;
109e7801d59Ssowmini  *
110e7801d59Ssowmini  * The function that parses command line arguments (typically
111e7801d59Ssowmini  * do_sub_command()) should then contain an invocation like:
112e7801d59Ssowmini  *
113e7801d59Ssowmini  *	fields = parse_output_fields(fields_str, sub_command_fields,
114e7801d59Ssowmini  *	    SUB_COMMAND_MAX_FIELDS, CMD_TYPE_ANY, &nfields);
115e7801d59Ssowmini  *
116e7801d59Ssowmini  * and store the resulting fields and nfields value in a print_state_t
117e7801d59Ssowmini  * structure tracked for the command.
118e7801d59Ssowmini  *
119e7801d59Ssowmini  *	sub_command_print_state.ps_fields = fields;
120e7801d59Ssowmini  *	sub_command_print_state.ps_nfields = nfields;
121e7801d59Ssowmini  *
122e7801d59Ssowmini  * To print the column header for the output, the print_header()
123e7801d59Ssowmini  * function must then be invoked by do_sub_command().
124e7801d59Ssowmini  *
125e7801d59Ssowmini  * Then if method (i) is used for the sub_command, the do_sub_command()
126e7801d59Ssowmini  * function should make the necessary system calls to fill up the buffer
127e7801d59Ssowmini  * and then invoke dladm_print_field(). An example of this method is
128e7801d59Ssowmini  * the implementation of do_show_link() and show_link();
129e7801d59Ssowmini  *
130e7801d59Ssowmini  * If method (ii) is used, do_sub_command should invoke dladm_print_output()
131e7801d59Ssowmini  * with a callback function that will be called for each field to be printed.
132e7801d59Ssowmini  * The callback function will be passed a pointer to the print_field_t
133e7801d59Ssowmini  * for the field, and the pf_index may then be used to identify the
134e7801d59Ssowmini  * system call required to find the value to be printed. An example of
135e7801d59Ssowmini  * this implementation may be found in the do_show_dev() and print_dev()
136e7801d59Ssowmini  * invocation.
137e7801d59Ssowmini  */
138e7801d59Ssowmini 
139e7801d59Ssowmini typedef struct print_field_s {
140e7801d59Ssowmini 	const char	*pf_name;	/* name of column to be printed */
141e7801d59Ssowmini 	const char	*pf_header;	/* header for this column */
142e7801d59Ssowmini 	uint_t		pf_width;
143e7801d59Ssowmini 	union {
144e7801d59Ssowmini 		uint_t	_pf_index;	/* private index for sub-command */
145e7801d59Ssowmini 		size_t	_pf_offset;
146e7801d59Ssowmini 	}_pf_un;
147e7801d59Ssowmini #define	pf_index	_pf_un._pf_index
148e7801d59Ssowmini #define	pf_offset	_pf_un._pf_offset;
149e7801d59Ssowmini 	uint_t		pf_cmdtype;
150e7801d59Ssowmini } print_field_t;
151e7801d59Ssowmini 
152e7801d59Ssowmini /*
153e7801d59Ssowmini  * The state of the output is tracked in a print_state_t structure.
154e7801d59Ssowmini  * Each ps_fields[i] entry points at the global print_field_t array for
155e7801d59Ssowmini  * the sub-command, where ps_nfields is the number of requested fields.
156e7801d59Ssowmini  */
157e7801d59Ssowmini typedef struct print_state_s {
158e7801d59Ssowmini 	print_field_t	**ps_fields;
159e7801d59Ssowmini 	uint_t		ps_nfields;
160e7801d59Ssowmini 	boolean_t	ps_lastfield;
161e7801d59Ssowmini 	uint_t		ps_overflow;
162e7801d59Ssowmini } print_state_t;
163e7801d59Ssowmini 
164e7801d59Ssowmini typedef char *(*print_callback_t)(print_field_t *, void *);
165e7801d59Ssowmini static print_field_t **parse_output_fields(char *, print_field_t *, int,
166e7801d59Ssowmini     uint_t, uint_t *);
167e7801d59Ssowmini /*
168e7801d59Ssowmini  * print the header for the output
169e7801d59Ssowmini  */
170e7801d59Ssowmini static void print_header(print_state_t *);
171e7801d59Ssowmini static void print_field(print_state_t *, print_field_t *, const char *,
172e7801d59Ssowmini     boolean_t);
173e7801d59Ssowmini 
174e7801d59Ssowmini /*
175e7801d59Ssowmini  * to print output values, call dladm_print_output with a callback
176e7801d59Ssowmini  * function (*func)() that should parse the args and return an
177e7801d59Ssowmini  * unformatted character buffer with the value to be printed.
178e7801d59Ssowmini  *
179e7801d59Ssowmini  * dladm_print_output() prints the character buffer using the formatting
180e7801d59Ssowmini  * information provided in the print_field_t for that column.
181e7801d59Ssowmini  */
182e7801d59Ssowmini static void dladm_print_output(print_state_t *, boolean_t,
183e7801d59Ssowmini     print_callback_t, void *);
184e7801d59Ssowmini 
185e7801d59Ssowmini /*
186e7801d59Ssowmini  * helper function that, when invoked as dladm_print_field(pf, buf)
187e7801d59Ssowmini  * prints string which is offset by pf->pf_offset  within buf
188e7801d59Ssowmini  */
189e7801d59Ssowmini static char *dladm_print_field(print_field_t *, void *);
190e7801d59Ssowmini 
191e7801d59Ssowmini 
192e7801d59Ssowmini #define	MAX_FIELD_LEN	32
193e7801d59Ssowmini 
194e7801d59Ssowmini 
1957c478bd9Sstevel@tonic-gate typedef struct pktsum_s {
1967c478bd9Sstevel@tonic-gate 	uint64_t	ipackets;
1977c478bd9Sstevel@tonic-gate 	uint64_t	opackets;
1987c478bd9Sstevel@tonic-gate 	uint64_t	rbytes;
1997c478bd9Sstevel@tonic-gate 	uint64_t	obytes;
2007c478bd9Sstevel@tonic-gate 	uint32_t	ierrors;
2017c478bd9Sstevel@tonic-gate 	uint32_t	oerrors;
2027c478bd9Sstevel@tonic-gate } pktsum_t;
2037c478bd9Sstevel@tonic-gate 
204d62bc4baSyz147064 typedef struct show_state {
2057c478bd9Sstevel@tonic-gate 	boolean_t	ls_firstonly;
2067c478bd9Sstevel@tonic-gate 	boolean_t	ls_donefirst;
2077c478bd9Sstevel@tonic-gate 	pktsum_t	ls_prevstats;
208d62bc4baSyz147064 	uint32_t	ls_flags;
209d62bc4baSyz147064 	dladm_status_t	ls_status;
210e7801d59Ssowmini 	print_state_t	ls_print;
211e7801d59Ssowmini 	boolean_t	ls_parseable;
212e7801d59Ssowmini 	boolean_t	ls_printheader;
213d62bc4baSyz147064 } show_state_t;
2147c478bd9Sstevel@tonic-gate 
2157c478bd9Sstevel@tonic-gate typedef struct show_grp_state {
216e7801d59Ssowmini 	pktsum_t	gs_prevstats[MAXPORT];
217e7801d59Ssowmini 	uint32_t	gs_flags;
218e7801d59Ssowmini 	dladm_status_t	gs_status;
219e7801d59Ssowmini 	boolean_t	gs_parseable;
2207c478bd9Sstevel@tonic-gate 	boolean_t	gs_lacp;
221d62bc4baSyz147064 	boolean_t	gs_extended;
2227c478bd9Sstevel@tonic-gate 	boolean_t	gs_stats;
2237c478bd9Sstevel@tonic-gate 	boolean_t	gs_firstonly;
224d62bc4baSyz147064 	boolean_t	gs_donefirst;
225e7801d59Ssowmini 	boolean_t	gs_printheader;
226e7801d59Ssowmini 	print_state_t	gs_print;
2277c478bd9Sstevel@tonic-gate } show_grp_state_t;
2287c478bd9Sstevel@tonic-gate 
2298d5c46e6Sam223141 typedef void cmdfunc_t(int, char **, const char *);
2300ba2cbe9Sxc151355 
231d62bc4baSyz147064 static cmdfunc_t do_show_link, do_show_dev, do_show_wifi, do_show_phys;
2320ba2cbe9Sxc151355 static cmdfunc_t do_create_aggr, do_delete_aggr, do_add_aggr, do_remove_aggr;
233d62bc4baSyz147064 static cmdfunc_t do_modify_aggr, do_show_aggr, do_up_aggr;
2340ba2cbe9Sxc151355 static cmdfunc_t do_scan_wifi, do_connect_wifi, do_disconnect_wifi;
2350ba2cbe9Sxc151355 static cmdfunc_t do_show_linkprop, do_set_linkprop, do_reset_linkprop;
2360ba2cbe9Sxc151355 static cmdfunc_t do_create_secobj, do_delete_secobj, do_show_secobj;
2370ba2cbe9Sxc151355 static cmdfunc_t do_init_linkprop, do_init_secobj;
238d62bc4baSyz147064 static cmdfunc_t do_create_vlan, do_delete_vlan, do_up_vlan, do_show_vlan;
239d62bc4baSyz147064 static cmdfunc_t do_rename_link, do_delete_phys, do_init_phys;
240d62bc4baSyz147064 static cmdfunc_t do_show_linkmap;
241e7801d59Ssowmini static cmdfunc_t do_show_ether;
2427c478bd9Sstevel@tonic-gate 
243d62bc4baSyz147064 static void	altroot_cmd(char *, int, char **);
244d62bc4baSyz147064 static int	show_linkprop_onelink(datalink_id_t, void *);
245f4b3ec61Sdh155122 
2466be03d0bSVasumathi Sundaram - Sun Microsystems static void	link_stats(datalink_id_t, uint_t, char *, show_state_t *);
247d62bc4baSyz147064 static void	aggr_stats(datalink_id_t, show_grp_state_t *, uint_t);
248e7801d59Ssowmini static void	dev_stats(const char *dev, uint32_t, char *, show_state_t *);
2497c478bd9Sstevel@tonic-gate 
250d62bc4baSyz147064 static int	get_one_kstat(const char *, const char *, uint8_t,
251d62bc4baSyz147064 		    void *, boolean_t);
252ba2e4443Sseb static void	get_mac_stats(const char *, pktsum_t *);
2537c478bd9Sstevel@tonic-gate static void	get_link_stats(const char *, pktsum_t *);
254d62bc4baSyz147064 static uint64_t	get_ifspeed(const char *, boolean_t);
2557c478bd9Sstevel@tonic-gate static void	stats_total(pktsum_t *, pktsum_t *, pktsum_t *);
2567c478bd9Sstevel@tonic-gate static void	stats_diff(pktsum_t *, pktsum_t *, pktsum_t *);
257d62bc4baSyz147064 static const char	*get_linkstate(const char *, boolean_t, char *);
258d62bc4baSyz147064 static const char	*get_linkduplex(const char *, boolean_t, char *);
2597c478bd9Sstevel@tonic-gate 
260e7801d59Ssowmini static int	show_etherprop(datalink_id_t, void *);
261e7801d59Ssowmini static void	show_ether_xprop(datalink_id_t, void *);
262e7801d59Ssowmini static boolean_t get_speed_duplex(datalink_id_t, const char *, char *,
263e7801d59Ssowmini     char *, boolean_t);
264e7801d59Ssowmini static char 	*pause_str(int, int);
265e7801d59Ssowmini static boolean_t	link_is_ether(const char *, datalink_id_t *);
266e7801d59Ssowmini 
267e7801d59Ssowmini #define	IS_FDX	0x10
268e7801d59Ssowmini #define	IS_HDX	0x01
269e7801d59Ssowmini 
27033343a97Smeem static boolean_t str2int(const char *, int *);
27133343a97Smeem static void	die(const char *, ...);
27233343a97Smeem static void	die_optdup(int);
2738d5c46e6Sam223141 static void	die_opterr(int, int, const char *);
27433343a97Smeem static void	die_dlerr(dladm_status_t, const char *, ...);
27533343a97Smeem static void	warn(const char *, ...);
27633343a97Smeem static void	warn_dlerr(dladm_status_t, const char *, ...);
27733343a97Smeem 
2787c478bd9Sstevel@tonic-gate typedef struct	cmd {
2797c478bd9Sstevel@tonic-gate 	char		*c_name;
2800ba2cbe9Sxc151355 	cmdfunc_t	*c_fn;
2818d5c46e6Sam223141 	const char	*c_usage;
2827c478bd9Sstevel@tonic-gate } cmd_t;
2837c478bd9Sstevel@tonic-gate 
2847c478bd9Sstevel@tonic-gate static cmd_t	cmds[] = {
2858d5c46e6Sam223141 	{ "show-link",		do_show_link,
2868d5c46e6Sam223141 	    "\tshow-link\t[-pP] [-o <field>,..] [-s [-i <interval>]] [<link>]"},
2878d5c46e6Sam223141 	{ "rename-link",	do_rename_link,
2888d5c46e6Sam223141 	    "\trename-link\t[-R <root-dir>] <oldlink> <newlink>\n"	},
2898d5c46e6Sam223141 	{ "show-dev",		do_show_dev,
2908d5c46e6Sam223141 	    "\tshow-dev\t[-p] [-o <field>,..] [-s [-i <interval>]] [<dev>]\n" },
2918d5c46e6Sam223141 	{ "create-aggr",	do_create_aggr,
2928d5c46e6Sam223141 	    "\tcreate-aggr\t[-t] [-R <root-dir>] [-P <policy>] [-L <mode>]\n"
2938d5c46e6Sam223141 	    "\t\t\t[-T <time>] [-u <address>] [-l <link>] ... <link>"	},
2948d5c46e6Sam223141 	{ "delete-aggr",	do_delete_aggr,
2958d5c46e6Sam223141 	    "\tdelete-aggr\t[-t] [-R <root-dir>] <link>"		},
2968d5c46e6Sam223141 	{ "add-aggr",		do_add_aggr,
2978d5c46e6Sam223141 	    "\tadd-aggr\t[-t] [-R <root-dir>] [-l <link>] ... <link>"	},
2988d5c46e6Sam223141 	{ "remove-aggr",	do_remove_aggr,
2998d5c46e6Sam223141 	    "\tremove-aggr\t[-t] [-R <root-dir>] [-l <link>] ... <link>"},
3008d5c46e6Sam223141 	{ "modify-aggr",	do_modify_aggr,
3018d5c46e6Sam223141 	    "\tmodify-aggr\t[-t] [-R <root-dir>] [-P <policy>] [-L <mode>]\n"
3028d5c46e6Sam223141 	    "\t\t\t[-T <time>] [-u <address>] <link>"			},
3038d5c46e6Sam223141 	{ "show-aggr",		do_show_aggr,
3048d5c46e6Sam223141 	    "\tshow-aggr\t[-pPLx] [-o <field>,..] [-s [-i <interval>]] "
3058d5c46e6Sam223141 	    "[<link>]\n"						},
3068d5c46e6Sam223141 	{ "up-aggr",		do_up_aggr,		NULL		},
3078d5c46e6Sam223141 	{ "scan-wifi",		do_scan_wifi,
3088d5c46e6Sam223141 	    "\tscan-wifi\t[-p] [-o <field>,...] [<link>]"		},
3098d5c46e6Sam223141 	{ "connect-wifi",	do_connect_wifi,
3108d5c46e6Sam223141 	    "\tconnect-wifi\t[-e <essid>] [-i <bssid>] [-k <key>,...] "
3118d5c46e6Sam223141 	    "[-s wep|wpa]\n"
3128d5c46e6Sam223141 	    "\t\t\t[-a open|shared] [-b bss|ibss] [-c] [-m a|b|g]\n"
3138d5c46e6Sam223141 	    "\t\t\t[-T <time>] [<link>]"				},
3148d5c46e6Sam223141 	{ "disconnect-wifi",	do_disconnect_wifi,
3158d5c46e6Sam223141 	    "\tdisconnect-wifi\t[-a] [<link>]"				},
3168d5c46e6Sam223141 	{ "show-wifi",		do_show_wifi,
3178d5c46e6Sam223141 	    "\tshow-wifi\t[-p] [-o <field>,...] [<link>]\n"		},
3188d5c46e6Sam223141 	{ "show-linkprop",	do_show_linkprop,
3198d5c46e6Sam223141 	    "\tshow-linkprop\t[-cP] [-o <field>,...] [-p <prop>,...] <name>"},
3208d5c46e6Sam223141 	{ "set-linkprop",	do_set_linkprop,
3218d5c46e6Sam223141 	    "\tset-linkprop\t[-t] [-R <root-dir>] -p <prop>=<value>[,...] "
3228d5c46e6Sam223141 	    "<name>"							},
3238d5c46e6Sam223141 	{ "reset-linkprop",	do_reset_linkprop,
3248d5c46e6Sam223141 	    "\treset-linkprop\t[-t] [-R <root-dir>] [-p <prop>,...] <name>\n" },
3258d5c46e6Sam223141 	{ "show-ether",		do_show_ether,
3268d5c46e6Sam223141 	    "\tshow-ether\t[-px][-o <field>,...] <link>\n"		},
3278d5c46e6Sam223141 	{ "create-secobj",	do_create_secobj,
3288d5c46e6Sam223141 	    "\tcreate-secobj\t[-t] [-R <root-dir>] [-f <file>] -c <class> "
3298d5c46e6Sam223141 	    "<secobj>"							},
3308d5c46e6Sam223141 	{ "delete-secobj",	do_delete_secobj,
3318d5c46e6Sam223141 	    "\tdelete-secobj\t[-t] [-R <root-dir>] <secobj>[,...]"	},
3328d5c46e6Sam223141 	{ "show-secobj",	do_show_secobj,
3338d5c46e6Sam223141 	    "\tshow-secobj\t[-pP] [-o <field>,...] [<secobj>,...]\n"	},
3348d5c46e6Sam223141 	{ "init-linkprop",	do_init_linkprop,	NULL		},
3358d5c46e6Sam223141 	{ "init-secobj",	do_init_secobj,		NULL		},
3368d5c46e6Sam223141 	{ "create-vlan", 	do_create_vlan,
3378d5c46e6Sam223141 	    "\tcreate-vlan\t[-ft] [-R <root-dir>] -l <link> -v <vid> [link]" },
3388d5c46e6Sam223141 	{ "delete-vlan", 	do_delete_vlan,
3398d5c46e6Sam223141 	    "\tdelete-vlan\t[-t] [-R <root-dir>] <link>"		},
3408d5c46e6Sam223141 	{ "show-vlan",		do_show_vlan,
3418d5c46e6Sam223141 	    "\tshow-vlan\t[-pP] [-o <field>,..] [<link>]\n"		},
3428d5c46e6Sam223141 	{ "up-vlan",		do_up_vlan,		NULL		},
3438d5c46e6Sam223141 	{ "delete-phys",	do_delete_phys,
3448d5c46e6Sam223141 	    "\tdelete-phys\t<link>"					},
3458d5c46e6Sam223141 	{ "show-phys",		do_show_phys,
3468d5c46e6Sam223141 	    "\tshow-phys\t[-pP] [-o <field>,..] [<link>]"		},
3478d5c46e6Sam223141 	{ "init-phys",		do_init_phys,		NULL		},
3488d5c46e6Sam223141 	{ "show-linkmap",	do_show_linkmap,	NULL		}
3497c478bd9Sstevel@tonic-gate };
3507c478bd9Sstevel@tonic-gate 
351d62bc4baSyz147064 static const struct option lopts[] = {
3527c478bd9Sstevel@tonic-gate 	{"vlan-id",	required_argument,	0, 'v'},
353e7801d59Ssowmini 	{"output",	required_argument,	0, 'o'},
3547c478bd9Sstevel@tonic-gate 	{"dev",		required_argument,	0, 'd'},
3557c478bd9Sstevel@tonic-gate 	{"policy",	required_argument,	0, 'P'},
356d62bc4baSyz147064 	{"lacp-mode",	required_argument,	0, 'L'},
3577c478bd9Sstevel@tonic-gate 	{"lacp-timer",	required_argument,	0, 'T'},
3587c478bd9Sstevel@tonic-gate 	{"unicast",	required_argument,	0, 'u'},
359d62bc4baSyz147064 	{"temporary",	no_argument,		0, 't'},
360d62bc4baSyz147064 	{"root-dir",	required_argument,	0, 'R'},
361d62bc4baSyz147064 	{"link",	required_argument,	0, 'l'},
362d62bc4baSyz147064 	{"forcible",	no_argument,		0, 'f'},
363d62bc4baSyz147064 	{ 0, 0, 0, 0 }
364d62bc4baSyz147064 };
365d62bc4baSyz147064 
366d62bc4baSyz147064 static const struct option show_lopts[] = {
3677c478bd9Sstevel@tonic-gate 	{"statistics",	no_argument,		0, 's'},
3687c478bd9Sstevel@tonic-gate 	{"interval",	required_argument,	0, 'i'},
3697c478bd9Sstevel@tonic-gate 	{"parseable",	no_argument,		0, 'p'},
370d62bc4baSyz147064 	{"extended",	no_argument,		0, 'x'},
371e7801d59Ssowmini 	{"output",	required_argument,	0, 'o'},
372d62bc4baSyz147064 	{"persistent",	no_argument,		0, 'P'},
373d62bc4baSyz147064 	{"lacp",	no_argument,		0, 'L'},
3747c478bd9Sstevel@tonic-gate 	{ 0, 0, 0, 0 }
3757c478bd9Sstevel@tonic-gate };
3767c478bd9Sstevel@tonic-gate 
3770ba2cbe9Sxc151355 static const struct option prop_longopts[] = {
3780ba2cbe9Sxc151355 	{"temporary",	no_argument,		0, 't'  },
379e7801d59Ssowmini 	{"output",	required_argument,	0, 'o'  },
3800ba2cbe9Sxc151355 	{"root-dir",	required_argument,	0, 'R'  },
3810ba2cbe9Sxc151355 	{"prop",	required_argument,	0, 'p'  },
3820ba2cbe9Sxc151355 	{"parseable",	no_argument,		0, 'c'  },
3830ba2cbe9Sxc151355 	{"persistent",	no_argument,		0, 'P'  },
3840ba2cbe9Sxc151355 	{ 0, 0, 0, 0 }
3850ba2cbe9Sxc151355 };
3860ba2cbe9Sxc151355 
3870ba2cbe9Sxc151355 static const struct option wifi_longopts[] = {
3880ba2cbe9Sxc151355 	{"parseable",	no_argument,		0, 'p'  },
3890ba2cbe9Sxc151355 	{"output",	required_argument,	0, 'o'  },
3900ba2cbe9Sxc151355 	{"essid",	required_argument,	0, 'e'  },
3910ba2cbe9Sxc151355 	{"bsstype",	required_argument,	0, 'b'  },
3920ba2cbe9Sxc151355 	{"mode",	required_argument,	0, 'm'  },
3930ba2cbe9Sxc151355 	{"key",		required_argument,	0, 'k'  },
3940ba2cbe9Sxc151355 	{"sec",		required_argument,	0, 's'  },
3950ba2cbe9Sxc151355 	{"auth",	required_argument,	0, 'a'  },
3960ba2cbe9Sxc151355 	{"create-ibss",	required_argument,	0, 'c'  },
3970ba2cbe9Sxc151355 	{"timeout",	required_argument,	0, 'T'  },
3980ba2cbe9Sxc151355 	{"all-links",	no_argument,		0, 'a'  },
3990ba2cbe9Sxc151355 	{"temporary",	no_argument,		0, 't'  },
4000ba2cbe9Sxc151355 	{"root-dir",	required_argument,	0, 'R'  },
4010ba2cbe9Sxc151355 	{"persistent",	no_argument,		0, 'P'  },
4020ba2cbe9Sxc151355 	{"file",	required_argument,	0, 'f'  },
4030ba2cbe9Sxc151355 	{ 0, 0, 0, 0 }
4040ba2cbe9Sxc151355 };
405e7801d59Ssowmini static const struct option showeth_lopts[] = {
406e7801d59Ssowmini 	{"parseable",	no_argument,		0, 'p'	},
407e7801d59Ssowmini 	{"extended",	no_argument,		0, 'x'	},
408e7801d59Ssowmini 	{"output",	required_argument,	0, 'o'	},
409e7801d59Ssowmini 	{ 0, 0, 0, 0 }
410e7801d59Ssowmini };
411e7801d59Ssowmini 
412e7801d59Ssowmini /*
413e7801d59Ssowmini  * structures for 'dladm show-ether'
414e7801d59Ssowmini  */
415e7801d59Ssowmini typedef struct ether_fields_buf_s
416e7801d59Ssowmini {
417e7801d59Ssowmini 	char	eth_link[15];
418e7801d59Ssowmini 	char	eth_ptype[8];
419e7801d59Ssowmini 	char	eth_state[8];
420e7801d59Ssowmini 	char	eth_autoneg[5];
421e7801d59Ssowmini 	char	eth_spdx[31];
422e7801d59Ssowmini 	char	eth_pause[6];
423e7801d59Ssowmini 	char	eth_rem_fault[16];
424e7801d59Ssowmini } ether_fields_buf_t;
425e7801d59Ssowmini 
426e7801d59Ssowmini static print_field_t ether_fields[] = {
427e7801d59Ssowmini /* name,	header,			field width,  offset,	cmdtype */
428e7801d59Ssowmini { "link",	"LINK",			15,
429e7801d59Ssowmini     offsetof(ether_fields_buf_t, eth_link),	CMD_TYPE_ANY},
430e7801d59Ssowmini { "ptype",	"PTYPE",		8,
431e7801d59Ssowmini     offsetof(ether_fields_buf_t, eth_ptype),	CMD_TYPE_ANY},
432e7801d59Ssowmini { "state",	"STATE",		8,
433e7801d59Ssowmini     offsetof(ether_fields_buf_t, eth_state),	CMD_TYPE_ANY},
434e7801d59Ssowmini { "auto",	"AUTO",			5,
435e7801d59Ssowmini     offsetof(ether_fields_buf_t, eth_autoneg),	CMD_TYPE_ANY},
436e7801d59Ssowmini { "speed-duplex", "SPEED-DUPLEX",	31,
437e7801d59Ssowmini     offsetof(ether_fields_buf_t, eth_spdx),	CMD_TYPE_ANY},
438e7801d59Ssowmini { "pause",	"PAUSE",		6,
439e7801d59Ssowmini     offsetof(ether_fields_buf_t, eth_pause),	CMD_TYPE_ANY},
440e7801d59Ssowmini { "rem_fault",	"REM_FAULT",		16,
441e7801d59Ssowmini     offsetof(ether_fields_buf_t, eth_rem_fault),	CMD_TYPE_ANY}}
442e7801d59Ssowmini ;
443e7801d59Ssowmini #define	ETHER_MAX_FIELDS	(sizeof (ether_fields) / sizeof (print_field_t))
444e7801d59Ssowmini 
445e7801d59Ssowmini typedef struct print_ether_state {
446e7801d59Ssowmini 	const char	*es_link;
447e7801d59Ssowmini 	boolean_t	es_parseable;
448e7801d59Ssowmini 	boolean_t	es_header;
449e7801d59Ssowmini 	boolean_t	es_extended;
450e7801d59Ssowmini 	print_state_t	es_print;
451e7801d59Ssowmini } print_ether_state_t;
452e7801d59Ssowmini 
453e7801d59Ssowmini /*
454e7801d59Ssowmini  * structures for 'dladm show-dev'.
455e7801d59Ssowmini  */
456e7801d59Ssowmini typedef enum {
457e7801d59Ssowmini 	DEV_LINK,
458e7801d59Ssowmini 	DEV_STATE,
459e7801d59Ssowmini 	DEV_SPEED,
460e7801d59Ssowmini 	DEV_DUPLEX
461e7801d59Ssowmini } dev_field_index_t;
462e7801d59Ssowmini 
463e7801d59Ssowmini static print_field_t dev_fields[] = {
464e7801d59Ssowmini /* name,	header,		field width,	index,		cmdtype */
465e7801d59Ssowmini { "link",	"LINK",			15,	DEV_LINK,	CMD_TYPE_ANY},
466e7801d59Ssowmini { "state",	"STATE",		6,	DEV_STATE,	CMD_TYPE_ANY},
467e7801d59Ssowmini { "speed",	"SPEED",		8,	DEV_SPEED,	CMD_TYPE_ANY},
468e7801d59Ssowmini { "duplex",	"DUPLEX",		8,	DEV_DUPLEX,	CMD_TYPE_ANY}}
469e7801d59Ssowmini ;
470e7801d59Ssowmini #define	DEV_MAX_FIELDS	(sizeof (dev_fields) / sizeof (print_field_t))
471e7801d59Ssowmini 
472e7801d59Ssowmini /*
473e7801d59Ssowmini  * structures for 'dladm show-dev -s' (print statistics)
474e7801d59Ssowmini  */
475e7801d59Ssowmini typedef enum {
476e7801d59Ssowmini 	DEVS_LINK,
477e7801d59Ssowmini 	DEVS_IPKTS,
478e7801d59Ssowmini 	DEVS_RBYTES,
479e7801d59Ssowmini 	DEVS_IERRORS,
480e7801d59Ssowmini 	DEVS_OPKTS,
481e7801d59Ssowmini 	DEVS_OBYTES,
482e7801d59Ssowmini 	DEVS_OERRORS
483e7801d59Ssowmini } devs_field_index_t;
484e7801d59Ssowmini 
485e7801d59Ssowmini static print_field_t devs_fields[] = {
486e7801d59Ssowmini /* name,	header,		field width,	index,		cmdtype	*/
487e7801d59Ssowmini { "link",	"LINK",			15,	DEVS_LINK,	CMD_TYPE_ANY},
488e7801d59Ssowmini { "ipackets",	"IPACKETS",		10,	DEVS_IPKTS,	CMD_TYPE_ANY},
489e7801d59Ssowmini { "rbytes",	"RBYTES",		8,	DEVS_RBYTES,	CMD_TYPE_ANY},
490e7801d59Ssowmini { "ierrors",	"IERRORS",		10,	DEVS_IERRORS,	CMD_TYPE_ANY},
491e7801d59Ssowmini { "opackets",	"OPACKETS",		12,	DEVS_OPKTS,	CMD_TYPE_ANY},
492e7801d59Ssowmini { "obytes",	"OBYTES",		12,	DEVS_OBYTES,	CMD_TYPE_ANY},
493e7801d59Ssowmini { "oerrors",	"OERRORS",		8,	DEVS_OERRORS,	CMD_TYPE_ANY}}
494e7801d59Ssowmini ;
495e7801d59Ssowmini #define	DEVS_MAX_FIELDS	(sizeof (devs_fields) / sizeof (print_field_t))
496e7801d59Ssowmini typedef struct dev_args_s {
497e7801d59Ssowmini 	char		*devs_link;
498e7801d59Ssowmini 	pktsum_t 	*devs_psum;
499e7801d59Ssowmini } dev_args_t;
500e7801d59Ssowmini static char *print_dev_stats(print_field_t *, void *);
501e7801d59Ssowmini static char *print_dev(print_field_t *, void *);
502e7801d59Ssowmini 
503e7801d59Ssowmini /*
504e7801d59Ssowmini  * buffer used by print functions for show-{link,phys,vlan} commands.
505e7801d59Ssowmini  */
506e7801d59Ssowmini typedef struct link_fields_buf_s {
507e7801d59Ssowmini 	char link_name[MAXLINKNAMELEN];
508e7801d59Ssowmini 	char link_class[DLADM_STRSIZE];
509c08e5e1aSdr146992 	char link_mtu[11];
510e7801d59Ssowmini 	char link_state[DLADM_STRSIZE];
511e7801d59Ssowmini 	char link_over[MAXLINKNAMELEN];
5124045d941Ssowmini 	char link_phys_state[DLADM_STRSIZE];
513e7801d59Ssowmini 	char link_phys_media[DLADM_STRSIZE];
514e7801d59Ssowmini 	char link_phys_speed[DLADM_STRSIZE];
515e7801d59Ssowmini 	char link_phys_duplex[DLPI_LINKNAME_MAX];
516e7801d59Ssowmini 	char link_phys_device[DLPI_LINKNAME_MAX];
517e7801d59Ssowmini 	char link_flags[6];
518e7801d59Ssowmini 	char link_vlan_vid[6];
519e7801d59Ssowmini } link_fields_buf_t;
520e7801d59Ssowmini 
521e7801d59Ssowmini /*
522e7801d59Ssowmini  * structures for 'dladm show-link'
523e7801d59Ssowmini  */
524e7801d59Ssowmini static print_field_t link_fields[] = {
525e7801d59Ssowmini /* name,	header,		field width,	offset,	cmdtype		*/
526e7801d59Ssowmini { "link",	"LINK",		11,
527e7801d59Ssowmini     offsetof(link_fields_buf_t, link_name),	CMD_TYPE_ANY},
528e7801d59Ssowmini { "class",	"CLASS",	 8,
529e7801d59Ssowmini     offsetof(link_fields_buf_t, link_class),	CMD_TYPE_ANY},
530e7801d59Ssowmini { "mtu",	"MTU",		 6,
531e7801d59Ssowmini     offsetof(link_fields_buf_t, link_mtu),	CMD_TYPE_ANY},
532e7801d59Ssowmini { "state",	"STATE",	 8,
533e7801d59Ssowmini     offsetof(link_fields_buf_t, link_state),	CMD_TYPE_ANY},
534e7801d59Ssowmini { "over",	"OVER",		DLPI_LINKNAME_MAX,
535e7801d59Ssowmini     offsetof(link_fields_buf_t, link_over),	CMD_TYPE_ANY}}
536e7801d59Ssowmini ;
537e7801d59Ssowmini #define	DEV_LINK_FIELDS	(sizeof (link_fields) / sizeof (print_field_t))
538e7801d59Ssowmini 
539e7801d59Ssowmini /*
540e7801d59Ssowmini  * structures for 'dladm show-aggr'
541e7801d59Ssowmini  */
542e7801d59Ssowmini typedef struct laggr_fields_buf_s {
543e7801d59Ssowmini 	char laggr_name[DLPI_LINKNAME_MAX];
544e7801d59Ssowmini 	char laggr_policy[9];
545e7801d59Ssowmini 	char laggr_addrpolicy[ETHERADDRL * 3 + 3];
546e7801d59Ssowmini 	char laggr_lacpactivity[14];
547e7801d59Ssowmini 	char laggr_lacptimer[DLADM_STRSIZE];
548e7801d59Ssowmini 	char laggr_flags[7];
549e7801d59Ssowmini } laggr_fields_buf_t;
550e7801d59Ssowmini 
551e7801d59Ssowmini typedef struct laggr_args_s {
552e7801d59Ssowmini 	int			laggr_lport; /* -1 indicates the aggr itself */
553e7801d59Ssowmini 	const char 		*laggr_link;
554e7801d59Ssowmini 	dladm_aggr_grp_attr_t	*laggr_ginfop;
555e7801d59Ssowmini 	dladm_status_t		*laggr_status;
556e7801d59Ssowmini 	pktsum_t		*laggr_pktsumtot; /* -s only */
557e7801d59Ssowmini 	pktsum_t		*laggr_prevstats; /* -s only */
558e7801d59Ssowmini 	boolean_t		laggr_parseable;
559e7801d59Ssowmini } laggr_args_t;
560e7801d59Ssowmini 
561e7801d59Ssowmini static print_field_t laggr_fields[] = {
562e7801d59Ssowmini /* name,		header,		field width,	offset,	cmdtype	*/
563e7801d59Ssowmini { "link",		"LINK",		15,
564e7801d59Ssowmini     offsetof(laggr_fields_buf_t, laggr_name),		CMD_TYPE_ANY},
565e7801d59Ssowmini { "policy",		"POLICY",	 8,
566e7801d59Ssowmini     offsetof(laggr_fields_buf_t, laggr_policy),	CMD_TYPE_ANY},
567e7801d59Ssowmini { "addrpolicy",		"ADDRPOLICY",	 ETHERADDRL * 3 + 2,
568e7801d59Ssowmini     offsetof(laggr_fields_buf_t, laggr_addrpolicy),	CMD_TYPE_ANY},
569e7801d59Ssowmini { "lacpactivity",	"LACPACTIVITY",	 13,
570e7801d59Ssowmini     offsetof(laggr_fields_buf_t, laggr_lacpactivity),	CMD_TYPE_ANY},
571e7801d59Ssowmini { "lacptimer",		"LACPTIMER",	 11,
572e7801d59Ssowmini     offsetof(laggr_fields_buf_t, laggr_lacptimer),	CMD_TYPE_ANY},
573e7801d59Ssowmini { "flags",		"FLAGS",	 7,
574e7801d59Ssowmini     offsetof(laggr_fields_buf_t, laggr_flags),	CMD_TYPE_ANY}}
575e7801d59Ssowmini ;
576e7801d59Ssowmini #define	LAGGR_MAX_FIELDS	(sizeof (laggr_fields) / sizeof (print_field_t))
577e7801d59Ssowmini 
578e7801d59Ssowmini /*
579e7801d59Ssowmini  * structures for 'dladm show-aggr -x'.
580e7801d59Ssowmini  */
581e7801d59Ssowmini typedef enum {
582e7801d59Ssowmini 	AGGR_X_LINK,
583e7801d59Ssowmini 	AGGR_X_PORT,
584e7801d59Ssowmini 	AGGR_X_SPEED,
585e7801d59Ssowmini 	AGGR_X_DUPLEX,
586e7801d59Ssowmini 	AGGR_X_STATE,
587e7801d59Ssowmini 	AGGR_X_ADDRESS,
588e7801d59Ssowmini 	AGGR_X_PORTSTATE
589e7801d59Ssowmini } aggr_x_field_index_t;
590e7801d59Ssowmini 
591e7801d59Ssowmini static print_field_t aggr_x_fields[] = {
592e7801d59Ssowmini /* name,	header,		field width,	index,		cmdtype	*/
593e7801d59Ssowmini { "link",	"LINK",			11,	AGGR_X_LINK,	CMD_TYPE_ANY},
594e7801d59Ssowmini { "port",	"PORT",			14,	AGGR_X_PORT,	CMD_TYPE_ANY},
595e7801d59Ssowmini { "speed",	"SPEED",		4,	AGGR_X_SPEED,	CMD_TYPE_ANY},
596e7801d59Ssowmini { "duplex",	"DUPLEX",		9,	AGGR_X_DUPLEX,	CMD_TYPE_ANY},
597e7801d59Ssowmini { "state",	"STATE",		9,	AGGR_X_STATE,	CMD_TYPE_ANY},
598e7801d59Ssowmini { "address",	"ADDRESS",		18,	AGGR_X_ADDRESS,	CMD_TYPE_ANY},
599e7801d59Ssowmini { "portstate",	"PORTSTATE",		15,	AGGR_X_PORTSTATE, CMD_TYPE_ANY}}
600e7801d59Ssowmini ;
601e7801d59Ssowmini #define	AGGR_X_MAX_FIELDS \
602e7801d59Ssowmini 	(sizeof (aggr_x_fields) / sizeof (print_field_t))
603e7801d59Ssowmini 
604e7801d59Ssowmini /*
605e7801d59Ssowmini  * structures for 'dladm show-aggr -s'.
606e7801d59Ssowmini  */
607e7801d59Ssowmini typedef enum {
608e7801d59Ssowmini 	AGGR_S_LINK,
609e7801d59Ssowmini 	AGGR_S_PORT,
610e7801d59Ssowmini 	AGGR_S_IPKTS,
611e7801d59Ssowmini 	AGGR_S_RBYTES,
612e7801d59Ssowmini 	AGGR_S_OPKTS,
613e7801d59Ssowmini 	AGGR_S_OBYTES,
614e7801d59Ssowmini 	AGGR_S_IPKTDIST,
615e7801d59Ssowmini 	AGGR_S_OPKTDIST
616e7801d59Ssowmini } aggr_s_field_index_t;
617e7801d59Ssowmini 
618e7801d59Ssowmini static print_field_t aggr_s_fields[] = {
619e7801d59Ssowmini /* name,		header,		field width,	index,	cmdtype	*/
620e7801d59Ssowmini { "link",		"LINK",		11,	AGGR_S_LINK,
621e7801d59Ssowmini     CMD_TYPE_ANY},
622e7801d59Ssowmini { "port",		"PORT",		9,	AGGR_S_PORT,
623e7801d59Ssowmini     CMD_TYPE_ANY},
624e7801d59Ssowmini { "ipackets",		"IPACKETS",	7,	AGGR_S_IPKTS,
625e7801d59Ssowmini     CMD_TYPE_ANY},
626e7801d59Ssowmini { "rbytes",		"RBYTES",	7,	AGGR_S_RBYTES,
627e7801d59Ssowmini     CMD_TYPE_ANY},
628e7801d59Ssowmini { "opackets",		"OPACKETS",	7,	AGGR_S_OPKTS,
629e7801d59Ssowmini     CMD_TYPE_ANY},
630e7801d59Ssowmini { "obytes",		"OBYTES",	7,	AGGR_S_OBYTES,
631e7801d59Ssowmini     CMD_TYPE_ANY},
632e7801d59Ssowmini { "ipktdist",		"IPKTDIST",	8,	AGGR_S_IPKTDIST,
633e7801d59Ssowmini     CMD_TYPE_ANY},
634e7801d59Ssowmini { "opktdist",		"OPKTDIST",	14,	AGGR_S_OPKTDIST,
635e7801d59Ssowmini     CMD_TYPE_ANY}}
636e7801d59Ssowmini ;
637e7801d59Ssowmini #define	AGGR_S_MAX_FIELDS \
638e7801d59Ssowmini 	(sizeof (aggr_l_fields) / sizeof (print_field_t))
639e7801d59Ssowmini 
640e7801d59Ssowmini /*
641e7801d59Ssowmini  * structures for 'dladm show-dev -L'.
642e7801d59Ssowmini  */
643e7801d59Ssowmini typedef enum {
644e7801d59Ssowmini 	AGGR_L_LINK,
645e7801d59Ssowmini 	AGGR_L_PORT,
646e7801d59Ssowmini 	AGGR_L_AGGREGATABLE,
647e7801d59Ssowmini 	AGGR_L_SYNC,
648e7801d59Ssowmini 	AGGR_L_COLL,
649e7801d59Ssowmini 	AGGR_L_DIST,
650e7801d59Ssowmini 	AGGR_L_DEFAULTED,
651e7801d59Ssowmini 	AGGR_L_EXPIRED
652e7801d59Ssowmini } aggr_l_field_index_t;
653e7801d59Ssowmini 
654e7801d59Ssowmini static print_field_t aggr_l_fields[] = {
655e7801d59Ssowmini /* name,		header,		field width,	index,	cmdtype	*/
656e7801d59Ssowmini { "link",		"LINK",		11,	AGGR_L_LINK,
657e7801d59Ssowmini     CMD_TYPE_ANY},
658e7801d59Ssowmini { "port",		"PORT",		12,	AGGR_L_PORT,
659e7801d59Ssowmini     CMD_TYPE_ANY},
660e7801d59Ssowmini { "aggregatable",	"AGGREGATABLE",	12,	AGGR_L_AGGREGATABLE,
661e7801d59Ssowmini     CMD_TYPE_ANY},
662e7801d59Ssowmini { "sync",		"SYNC",		4,	AGGR_L_SYNC,
663e7801d59Ssowmini     CMD_TYPE_ANY},
664e7801d59Ssowmini { "coll",		"COLL",		4,	AGGR_L_COLL,
665e7801d59Ssowmini     CMD_TYPE_ANY},
666e7801d59Ssowmini { "dist",		"DIST",		4,	AGGR_L_DIST,
667e7801d59Ssowmini     CMD_TYPE_ANY},
668e7801d59Ssowmini { "defaulted",		"DEFAULTED",	9,	AGGR_L_DEFAULTED,
669e7801d59Ssowmini     CMD_TYPE_ANY},
670e7801d59Ssowmini { "expired",		"EXPIRED",	14,	AGGR_L_EXPIRED,
671e7801d59Ssowmini     CMD_TYPE_ANY}}
672e7801d59Ssowmini ;
673e7801d59Ssowmini #define	AGGR_L_MAX_FIELDS \
674e7801d59Ssowmini 	(sizeof (aggr_l_fields) / sizeof (print_field_t))
675e7801d59Ssowmini 
676e7801d59Ssowmini /*
677e7801d59Ssowmini  * structures for 'dladm show-phys'
678e7801d59Ssowmini  */
679e7801d59Ssowmini 
680e7801d59Ssowmini static print_field_t phys_fields[] = {
681e7801d59Ssowmini /* name,	header,		field width,	offset,	cmdtype		*/
682e7801d59Ssowmini { "link",	"LINK",			12,
683e7801d59Ssowmini     offsetof(link_fields_buf_t, link_name),		CMD_TYPE_ANY},
684e7801d59Ssowmini { "media",	"MEDIA",		20,
685e7801d59Ssowmini     offsetof(link_fields_buf_t, link_phys_media),	CMD_TYPE_ANY},
686e7801d59Ssowmini { "state",	"STATE",		10,
687e7801d59Ssowmini     offsetof(link_fields_buf_t, link_phys_state),	CMD_TYPE_ANY},
6886be03d0bSVasumathi Sundaram - Sun Microsystems { "speed",	"SPEED",		6,
689e7801d59Ssowmini     offsetof(link_fields_buf_t, link_phys_speed),	CMD_TYPE_ANY},
690e7801d59Ssowmini { "duplex",	"DUPLEX",		9,
691e7801d59Ssowmini     offsetof(link_fields_buf_t, link_phys_duplex),	CMD_TYPE_ANY},
692e7801d59Ssowmini { "device",	"DEVICE",		12,
693e7801d59Ssowmini     offsetof(link_fields_buf_t, link_phys_device),	CMD_TYPE_ANY},
694e7801d59Ssowmini { "flags",	"FLAGS",		6,
695e7801d59Ssowmini     offsetof(link_fields_buf_t, link_flags),		CMD_TYPE_ANY}}
696e7801d59Ssowmini ;
697e7801d59Ssowmini #define	PHYS_MAX_FIELDS	(sizeof (phys_fields) / sizeof (print_field_t))
698e7801d59Ssowmini 
699e7801d59Ssowmini /*
700e7801d59Ssowmini  * structures for 'dladm show-vlan'
701e7801d59Ssowmini  */
702e7801d59Ssowmini static print_field_t vlan_fields[] = {
703e7801d59Ssowmini /* name,	header,		field width,	offset,	cmdtype		*/
704e7801d59Ssowmini { "link",	"LINK",			15,
705e7801d59Ssowmini     offsetof(link_fields_buf_t, link_name),		CMD_TYPE_ANY},
706e7801d59Ssowmini { "vid",	"VID",			8,
707e7801d59Ssowmini     offsetof(link_fields_buf_t, link_vlan_vid),	CMD_TYPE_ANY},
708e7801d59Ssowmini { "over",	"OVER",			12,
709e7801d59Ssowmini     offsetof(link_fields_buf_t, link_over),		CMD_TYPE_ANY},
710e7801d59Ssowmini { "flags",	"FLAGS",		6,
711e7801d59Ssowmini     offsetof(link_fields_buf_t, link_flags),		CMD_TYPE_ANY}}
712e7801d59Ssowmini ;
713e7801d59Ssowmini #define	VLAN_MAX_FIELDS	(sizeof (vlan_fields) / sizeof (print_field_t))
714e7801d59Ssowmini 
715e7801d59Ssowmini /*
716e7801d59Ssowmini  * structures for 'dladm show-wifi'
717e7801d59Ssowmini  */
718e7801d59Ssowmini static print_field_t wifi_fields[] = {
719e7801d59Ssowmini { "link",	"LINK",		10, 0,			WIFI_CMD_ALL},
720e7801d59Ssowmini { "essid",	"ESSID",	19, DLADM_WLAN_ATTR_ESSID,	WIFI_CMD_ALL},
721e7801d59Ssowmini { "bssid",	"BSSID/IBSSID", 17, DLADM_WLAN_ATTR_BSSID,	WIFI_CMD_ALL},
722e7801d59Ssowmini { "ibssid",	"BSSID/IBSSID", 17, DLADM_WLAN_ATTR_BSSID,	WIFI_CMD_ALL},
723e7801d59Ssowmini { "mode",	"MODE",		6,  DLADM_WLAN_ATTR_MODE,	WIFI_CMD_ALL},
724e7801d59Ssowmini { "speed",	"SPEED",	6,  DLADM_WLAN_ATTR_SPEED,	WIFI_CMD_ALL},
725e7801d59Ssowmini { "auth",	"AUTH",		8,  DLADM_WLAN_ATTR_AUTH,	WIFI_CMD_SHOW},
726e7801d59Ssowmini { "bsstype",	"BSSTYPE",	8,  DLADM_WLAN_ATTR_BSSTYPE, WIFI_CMD_ALL},
727e7801d59Ssowmini { "sec",	"SEC",		6,  DLADM_WLAN_ATTR_SECMODE, WIFI_CMD_ALL},
728e7801d59Ssowmini { "status",	"STATUS",	17, DLADM_WLAN_LINKATTR_STATUS, WIFI_CMD_SHOW},
729e7801d59Ssowmini { "strength",	"STRENGTH",	10, DLADM_WLAN_ATTR_STRENGTH, WIFI_CMD_ALL}}
730e7801d59Ssowmini ;
731e7801d59Ssowmini 
732e7801d59Ssowmini static char *all_scan_wifi_fields =
733e7801d59Ssowmini 	"link,essid,bssid,sec,strength,mode,speed,bsstype";
734e7801d59Ssowmini static char *all_show_wifi_fields =
735e7801d59Ssowmini 	"link,status,essid,sec,strength,mode,speed,auth,bssid,bsstype";
736e7801d59Ssowmini static char *def_scan_wifi_fields =
737e7801d59Ssowmini 	"link,essid,bssid,sec,strength,mode,speed";
738e7801d59Ssowmini static char *def_show_wifi_fields =
739e7801d59Ssowmini 	"link,status,essid,sec,strength,mode,speed";
740e7801d59Ssowmini 
741e7801d59Ssowmini #define	WIFI_MAX_FIELDS		(sizeof (wifi_fields) / sizeof (print_field_t))
742e7801d59Ssowmini 
743e7801d59Ssowmini /*
744e7801d59Ssowmini  * structures for 'dladm show-linkprop'
745e7801d59Ssowmini  */
746e7801d59Ssowmini typedef enum {
747e7801d59Ssowmini 	LINKPROP_LINK,
748e7801d59Ssowmini 	LINKPROP_PROPERTY,
749e7801d59Ssowmini 	LINKPROP_VALUE,
750e7801d59Ssowmini 	LINKPROP_DEFAULT,
751e7801d59Ssowmini 	LINKPROP_POSSIBLE
752e7801d59Ssowmini } linkprop_field_index_t;
753e7801d59Ssowmini 
754e7801d59Ssowmini static print_field_t linkprop_fields[] = {
755e7801d59Ssowmini /* name,	header,		field width,  index,		cmdtype */
756e7801d59Ssowmini { "link",	"LINK",		12,	LINKPROP_LINK,		CMD_TYPE_ANY},
757e7801d59Ssowmini { "property",	"PROPERTY",	15,	LINKPROP_PROPERTY,	CMD_TYPE_ANY},
758e7801d59Ssowmini { "value",	"VALUE",	14,	LINKPROP_VALUE,		CMD_TYPE_ANY},
759e7801d59Ssowmini { "default",	"DEFAULT",	14,	LINKPROP_DEFAULT, 	CMD_TYPE_ANY},
760e7801d59Ssowmini { "possible",	"POSSIBLE",	20,	LINKPROP_POSSIBLE,	CMD_TYPE_ANY}}
761e7801d59Ssowmini ;
762e7801d59Ssowmini #define	LINKPROP_MAX_FIELDS					\
763e7801d59Ssowmini 	(sizeof (linkprop_fields) / sizeof (print_field_t))
764e7801d59Ssowmini 
765e7801d59Ssowmini #define	MAX_PROPS		32
766e7801d59Ssowmini #define	MAX_PROP_LINE		512
767e7801d59Ssowmini 
768e7801d59Ssowmini typedef struct prop_info {
769e7801d59Ssowmini 	char		*pi_name;
770e7801d59Ssowmini 	char		*pi_val[DLADM_MAX_PROP_VALCNT];
771e7801d59Ssowmini 	uint_t		pi_count;
772e7801d59Ssowmini } prop_info_t;
773e7801d59Ssowmini 
774e7801d59Ssowmini typedef struct prop_list {
775e7801d59Ssowmini 	prop_info_t	pl_info[MAX_PROPS];
776e7801d59Ssowmini 	uint_t		pl_count;
777e7801d59Ssowmini 	char		*pl_buf;
778e7801d59Ssowmini } prop_list_t;
779e7801d59Ssowmini 
780e7801d59Ssowmini typedef struct show_linkprop_state {
781e7801d59Ssowmini 	char		ls_link[MAXLINKNAMELEN];
782e7801d59Ssowmini 	char		*ls_line;
783e7801d59Ssowmini 	char		**ls_propvals;
784e7801d59Ssowmini 	prop_list_t	*ls_proplist;
785e7801d59Ssowmini 	boolean_t	ls_parseable;
786e7801d59Ssowmini 	boolean_t	ls_persist;
787e7801d59Ssowmini 	boolean_t	ls_header;
788e7801d59Ssowmini 	dladm_status_t	ls_status;
789e7801d59Ssowmini 	dladm_status_t	ls_retstatus;
790e7801d59Ssowmini 	print_state_t	ls_print;
791e7801d59Ssowmini } show_linkprop_state_t;
792e7801d59Ssowmini 
793e7801d59Ssowmini typedef struct linkprop_args_s {
794e7801d59Ssowmini 	show_linkprop_state_t	*ls_state;
795e7801d59Ssowmini 	char			*ls_propname;
796e7801d59Ssowmini 	datalink_id_t		ls_linkid;
797e7801d59Ssowmini } linkprop_args_t;
798e7801d59Ssowmini 
799e7801d59Ssowmini /*
800e7801d59Ssowmini  * structures for 'dladm show-secobj'
801e7801d59Ssowmini  */
802e7801d59Ssowmini typedef struct secobj_fields_buf_s {
803e7801d59Ssowmini 	char			ss_obj_name[DLADM_SECOBJ_VAL_MAX];
804e7801d59Ssowmini 	char			ss_class[20];
805e7801d59Ssowmini 	char			ss_val[30];
806e7801d59Ssowmini } secobj_fields_buf_t;
807e7801d59Ssowmini static print_field_t secobj_fields[] = {
808e7801d59Ssowmini /* name,	header,		field width,	offset,	cmdtype		*/
809e7801d59Ssowmini { "object",	"OBJECT",		20,
810e7801d59Ssowmini     offsetof(secobj_fields_buf_t, ss_obj_name),	CMD_TYPE_ANY},
811e7801d59Ssowmini { "class",	"CLASS",		20,
812e7801d59Ssowmini     offsetof(secobj_fields_buf_t, ss_class),	CMD_TYPE_ANY},
813e7801d59Ssowmini { "value",	"VALUE",		30,
814e7801d59Ssowmini     offsetof(secobj_fields_buf_t, ss_val),	CMD_TYPE_ANY}}
815e7801d59Ssowmini ;
816e7801d59Ssowmini #define	DEV_SOBJ_FIELDS	(sizeof (secobj_fields) / sizeof (print_field_t))
8170ba2cbe9Sxc151355 
8187c478bd9Sstevel@tonic-gate static char *progname;
8190ba2cbe9Sxc151355 static sig_atomic_t signalled;
8207c478bd9Sstevel@tonic-gate 
8217c478bd9Sstevel@tonic-gate static void
8227c478bd9Sstevel@tonic-gate usage(void)
8237c478bd9Sstevel@tonic-gate {
8248d5c46e6Sam223141 	int	i;
8258d5c46e6Sam223141 	cmd_t	*cmdp;
8268d5c46e6Sam223141 	(void) fprintf(stderr, gettext("usage:  dladm <subcommand> <args> ..."
8278d5c46e6Sam223141 	    "\n"));
8288d5c46e6Sam223141 	for (i = 0; i < sizeof (cmds) / sizeof (cmds[0]); i++) {
8298d5c46e6Sam223141 		cmdp = &cmds[i];
8308d5c46e6Sam223141 		if (cmdp->c_usage != NULL)
8318d5c46e6Sam223141 			(void) fprintf(stderr, "%s\n", gettext(cmdp->c_usage));
8328d5c46e6Sam223141 	}
8337c478bd9Sstevel@tonic-gate 	exit(1);
8347c478bd9Sstevel@tonic-gate }
8357c478bd9Sstevel@tonic-gate 
8367c478bd9Sstevel@tonic-gate int
8377c478bd9Sstevel@tonic-gate main(int argc, char *argv[])
8387c478bd9Sstevel@tonic-gate {
8397c478bd9Sstevel@tonic-gate 	int	i;
8407c478bd9Sstevel@tonic-gate 	cmd_t	*cmdp;
8417c478bd9Sstevel@tonic-gate 
8427c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
8437c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)
8447c478bd9Sstevel@tonic-gate #define	TEXT_DOMAIN "SYS_TEST"
8457c478bd9Sstevel@tonic-gate #endif
8467c478bd9Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
8477c478bd9Sstevel@tonic-gate 
8487c478bd9Sstevel@tonic-gate 	progname = argv[0];
8497c478bd9Sstevel@tonic-gate 
8507c478bd9Sstevel@tonic-gate 	if (argc < 2)
8517c478bd9Sstevel@tonic-gate 		usage();
8527c478bd9Sstevel@tonic-gate 
8537c478bd9Sstevel@tonic-gate 	for (i = 0; i < sizeof (cmds) / sizeof (cmds[0]); i++) {
8547c478bd9Sstevel@tonic-gate 		cmdp = &cmds[i];
8557c478bd9Sstevel@tonic-gate 		if (strcmp(argv[1], cmdp->c_name) == 0) {
8568d5c46e6Sam223141 			cmdp->c_fn(argc - 1, &argv[1], cmdp->c_usage);
8577c478bd9Sstevel@tonic-gate 			exit(0);
8587c478bd9Sstevel@tonic-gate 		}
8597c478bd9Sstevel@tonic-gate 	}
8607c478bd9Sstevel@tonic-gate 
8617c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("%s: unknown subcommand '%s'\n"),
8627c478bd9Sstevel@tonic-gate 	    progname, argv[1]);
8637c478bd9Sstevel@tonic-gate 	usage();
8647c478bd9Sstevel@tonic-gate 
8657c478bd9Sstevel@tonic-gate 	return (0);
8667c478bd9Sstevel@tonic-gate }
8677c478bd9Sstevel@tonic-gate 
8687c478bd9Sstevel@tonic-gate static void
8698d5c46e6Sam223141 do_create_aggr(int argc, char *argv[], const char *use)
8707c478bd9Sstevel@tonic-gate {
8717c478bd9Sstevel@tonic-gate 	char			option;
872d62bc4baSyz147064 	int			key = 0;
8737c478bd9Sstevel@tonic-gate 	uint32_t		policy = AGGR_POLICY_L4;
8747c478bd9Sstevel@tonic-gate 	aggr_lacp_mode_t	lacp_mode = AGGR_LACP_OFF;
8757c478bd9Sstevel@tonic-gate 	aggr_lacp_timer_t	lacp_timer = AGGR_LACP_TIMER_SHORT;
876f595a68aSyz147064 	dladm_aggr_port_attr_db_t	port[MAXPORT];
877d62bc4baSyz147064 	uint_t			n, ndev, nlink;
8787c478bd9Sstevel@tonic-gate 	uint8_t			mac_addr[ETHERADDRL];
8797c478bd9Sstevel@tonic-gate 	boolean_t		mac_addr_fixed = B_FALSE;
8807c478bd9Sstevel@tonic-gate 	boolean_t		P_arg = B_FALSE;
8817c478bd9Sstevel@tonic-gate 	boolean_t		l_arg = B_FALSE;
8827c478bd9Sstevel@tonic-gate 	boolean_t		u_arg = B_FALSE;
8837c478bd9Sstevel@tonic-gate 	boolean_t		T_arg = B_FALSE;
884d62bc4baSyz147064 	uint32_t		flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
8857c478bd9Sstevel@tonic-gate 	char			*altroot = NULL;
886d62bc4baSyz147064 	char			name[MAXLINKNAMELEN];
887d62bc4baSyz147064 	char			*devs[MAXPORT];
888d62bc4baSyz147064 	char			*links[MAXPORT];
889f595a68aSyz147064 	dladm_status_t		status;
8907c478bd9Sstevel@tonic-gate 
891d62bc4baSyz147064 	ndev = nlink = opterr = 0;
892d62bc4baSyz147064 	while ((option = getopt_long(argc, argv, ":d:l:L:P:R:tfu:T:",
893d62bc4baSyz147064 	    lopts, NULL)) != -1) {
8947c478bd9Sstevel@tonic-gate 		switch (option) {
8957c478bd9Sstevel@tonic-gate 		case 'd':
896d62bc4baSyz147064 			if (ndev + nlink >= MAXPORT)
897d62bc4baSyz147064 				die("too many ports specified");
8987c478bd9Sstevel@tonic-gate 
899d62bc4baSyz147064 			devs[ndev++] = optarg;
9007c478bd9Sstevel@tonic-gate 			break;
9017c478bd9Sstevel@tonic-gate 		case 'P':
90233343a97Smeem 			if (P_arg)
90333343a97Smeem 				die_optdup(option);
9047c478bd9Sstevel@tonic-gate 
9057c478bd9Sstevel@tonic-gate 			P_arg = B_TRUE;
906f595a68aSyz147064 			if (!dladm_aggr_str2policy(optarg, &policy))
90733343a97Smeem 				die("invalid policy '%s'", optarg);
9087c478bd9Sstevel@tonic-gate 			break;
9097c478bd9Sstevel@tonic-gate 		case 'u':
91033343a97Smeem 			if (u_arg)
91133343a97Smeem 				die_optdup(option);
9127c478bd9Sstevel@tonic-gate 
9137c478bd9Sstevel@tonic-gate 			u_arg = B_TRUE;
914f595a68aSyz147064 			if (!dladm_aggr_str2macaddr(optarg, &mac_addr_fixed,
91533343a97Smeem 			    mac_addr))
91633343a97Smeem 				die("invalid MAC address '%s'", optarg);
9177c478bd9Sstevel@tonic-gate 			break;
9187c478bd9Sstevel@tonic-gate 		case 'l':
919d62bc4baSyz147064 			if (isdigit(optarg[strlen(optarg) - 1])) {
920d62bc4baSyz147064 
921d62bc4baSyz147064 				/*
922d62bc4baSyz147064 				 * Ended with digit, possibly a link name.
923d62bc4baSyz147064 				 */
924d62bc4baSyz147064 				if (ndev + nlink >= MAXPORT)
925d62bc4baSyz147064 					die("too many ports specified");
926d62bc4baSyz147064 
927d62bc4baSyz147064 				links[nlink++] = optarg;
928d62bc4baSyz147064 				break;
929d62bc4baSyz147064 			}
930d62bc4baSyz147064 			/* FALLTHROUGH */
931d62bc4baSyz147064 		case 'L':
93233343a97Smeem 			if (l_arg)
93333343a97Smeem 				die_optdup(option);
9347c478bd9Sstevel@tonic-gate 
9357c478bd9Sstevel@tonic-gate 			l_arg = B_TRUE;
936f595a68aSyz147064 			if (!dladm_aggr_str2lacpmode(optarg, &lacp_mode))
93733343a97Smeem 				die("invalid LACP mode '%s'", optarg);
9387c478bd9Sstevel@tonic-gate 			break;
9397c478bd9Sstevel@tonic-gate 		case 'T':
94033343a97Smeem 			if (T_arg)
94133343a97Smeem 				die_optdup(option);
9427c478bd9Sstevel@tonic-gate 
9437c478bd9Sstevel@tonic-gate 			T_arg = B_TRUE;
944f595a68aSyz147064 			if (!dladm_aggr_str2lacptimer(optarg, &lacp_timer))
94533343a97Smeem 				die("invalid LACP timer value '%s'", optarg);
9467c478bd9Sstevel@tonic-gate 			break;
9477c478bd9Sstevel@tonic-gate 		case 't':
948d62bc4baSyz147064 			flags &= ~DLADM_OPT_PERSIST;
949d62bc4baSyz147064 			break;
950d62bc4baSyz147064 		case 'f':
951d62bc4baSyz147064 			flags |= DLADM_OPT_FORCE;
9527c478bd9Sstevel@tonic-gate 			break;
9537c478bd9Sstevel@tonic-gate 		case 'R':
9547c478bd9Sstevel@tonic-gate 			altroot = optarg;
9557c478bd9Sstevel@tonic-gate 			break;
9567c478bd9Sstevel@tonic-gate 		default:
9578d5c46e6Sam223141 			die_opterr(optopt, option, use);
95833343a97Smeem 			break;
9597c478bd9Sstevel@tonic-gate 		}
9607c478bd9Sstevel@tonic-gate 	}
9617c478bd9Sstevel@tonic-gate 
962d62bc4baSyz147064 	if (ndev + nlink == 0)
9637c478bd9Sstevel@tonic-gate 		usage();
9647c478bd9Sstevel@tonic-gate 
965d62bc4baSyz147064 	/* get key value or the aggregation name (required last argument) */
9667c478bd9Sstevel@tonic-gate 	if (optind != (argc-1))
9677c478bd9Sstevel@tonic-gate 		usage();
9687c478bd9Sstevel@tonic-gate 
969d62bc4baSyz147064 	if (!str2int(argv[optind], &key)) {
970d62bc4baSyz147064 		if (strlcpy(name, argv[optind], MAXLINKNAMELEN) >=
971d62bc4baSyz147064 		    MAXLINKNAMELEN) {
972d62bc4baSyz147064 			die("link name too long '%s'", argv[optind]);
973d62bc4baSyz147064 		}
9747c478bd9Sstevel@tonic-gate 
975d62bc4baSyz147064 		if (!dladm_valid_linkname(name))
976d62bc4baSyz147064 			die("invalid link name '%s'", argv[optind]);
977d62bc4baSyz147064 	} else {
978d62bc4baSyz147064 		(void) snprintf(name, MAXLINKNAMELEN, "aggr%d", key);
979d62bc4baSyz147064 	}
980d62bc4baSyz147064 
981d62bc4baSyz147064 	if (altroot != NULL)
982d62bc4baSyz147064 		altroot_cmd(altroot, argc, argv);
983d62bc4baSyz147064 
984d62bc4baSyz147064 	for (n = 0; n < ndev; n++) {
985d62bc4baSyz147064 		if (dladm_dev2linkid(devs[n], &port[n].lp_linkid) !=
986d62bc4baSyz147064 		    DLADM_STATUS_OK) {
987d62bc4baSyz147064 			die("invalid dev name '%s'", devs[n]);
988d62bc4baSyz147064 		}
989d62bc4baSyz147064 	}
990d62bc4baSyz147064 
991d62bc4baSyz147064 	for (n = 0; n < nlink; n++) {
992d62bc4baSyz147064 		if (dladm_name2info(links[n], &port[ndev + n].lp_linkid,
993d62bc4baSyz147064 		    NULL, NULL, NULL) != DLADM_STATUS_OK) {
994d62bc4baSyz147064 			die("invalid link name '%s'", links[n]);
995d62bc4baSyz147064 		}
996d62bc4baSyz147064 	}
997d62bc4baSyz147064 
998d62bc4baSyz147064 	status = dladm_aggr_create(name, key, ndev + nlink, port, policy,
999d62bc4baSyz147064 	    mac_addr_fixed, (const uchar_t *)mac_addr, lacp_mode,
1000d62bc4baSyz147064 	    lacp_timer, flags);
1001d62bc4baSyz147064 done:
1002d62bc4baSyz147064 	if (status != DLADM_STATUS_OK) {
1003d62bc4baSyz147064 		if (status == DLADM_STATUS_NONOTIF) {
1004d62bc4baSyz147064 			die_dlerr(status, "not all links have link up/down "
1005d62bc4baSyz147064 			    "detection; must use -f (see dladm(1M))\n");
1006d62bc4baSyz147064 		} else {
1007f595a68aSyz147064 			die_dlerr(status, "create operation failed");
10087c478bd9Sstevel@tonic-gate 		}
1009d62bc4baSyz147064 	}
1010d62bc4baSyz147064 }
1011d62bc4baSyz147064 
1012d62bc4baSyz147064 /*
1013d62bc4baSyz147064  * arg is either the key or the aggr name. Validate it and convert it to
1014d62bc4baSyz147064  * the linkid if altroot is NULL.
1015d62bc4baSyz147064  */
1016d62bc4baSyz147064 static dladm_status_t
1017d62bc4baSyz147064 i_dladm_aggr_get_linkid(const char *altroot, const char *arg,
1018d62bc4baSyz147064     datalink_id_t *linkidp, uint32_t flags)
1019d62bc4baSyz147064 {
1020d62bc4baSyz147064 	int		key = 0;
1021d62bc4baSyz147064 	char		*aggr = NULL;
1022d62bc4baSyz147064 	dladm_status_t	status;
1023d62bc4baSyz147064 
1024d62bc4baSyz147064 	if (!str2int(arg, &key))
1025d62bc4baSyz147064 		aggr = (char *)arg;
1026d62bc4baSyz147064 
1027d62bc4baSyz147064 	if (aggr == NULL && key == 0)
1028d62bc4baSyz147064 		return (DLADM_STATUS_LINKINVAL);
1029d62bc4baSyz147064 
1030d62bc4baSyz147064 	if (altroot != NULL)
1031d62bc4baSyz147064 		return (DLADM_STATUS_OK);
1032d62bc4baSyz147064 
1033d62bc4baSyz147064 	if (aggr != NULL) {
1034d62bc4baSyz147064 		status = dladm_name2info(aggr, linkidp, NULL, NULL, NULL);
1035d62bc4baSyz147064 	} else {
1036d62bc4baSyz147064 		status = dladm_key2linkid(key, linkidp, flags);
1037d62bc4baSyz147064 	}
1038d62bc4baSyz147064 
1039d62bc4baSyz147064 	return (status);
1040d62bc4baSyz147064 }
10417c478bd9Sstevel@tonic-gate 
10427c478bd9Sstevel@tonic-gate static void
10438d5c46e6Sam223141 do_delete_aggr(int argc, char *argv[], const char *use)
10447c478bd9Sstevel@tonic-gate {
10457c478bd9Sstevel@tonic-gate 	char			option;
10467c478bd9Sstevel@tonic-gate 	char			*altroot = NULL;
1047d62bc4baSyz147064 	uint32_t		flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
1048f595a68aSyz147064 	dladm_status_t		status;
1049d62bc4baSyz147064 	datalink_id_t		linkid;
10507c478bd9Sstevel@tonic-gate 
10517c478bd9Sstevel@tonic-gate 	opterr = 0;
1052d62bc4baSyz147064 	while ((option = getopt_long(argc, argv, ":R:t", lopts, NULL)) != -1) {
10537c478bd9Sstevel@tonic-gate 		switch (option) {
10547c478bd9Sstevel@tonic-gate 		case 't':
1055d62bc4baSyz147064 			flags &= ~DLADM_OPT_PERSIST;
10567c478bd9Sstevel@tonic-gate 			break;
10577c478bd9Sstevel@tonic-gate 		case 'R':
10587c478bd9Sstevel@tonic-gate 			altroot = optarg;
10597c478bd9Sstevel@tonic-gate 			break;
10607c478bd9Sstevel@tonic-gate 		default:
10618d5c46e6Sam223141 			die_opterr(optopt, option, use);
10627c478bd9Sstevel@tonic-gate 			break;
10637c478bd9Sstevel@tonic-gate 		}
10647c478bd9Sstevel@tonic-gate 	}
10657c478bd9Sstevel@tonic-gate 
1066d62bc4baSyz147064 	/* get key value or the aggregation name (required last argument) */
10677c478bd9Sstevel@tonic-gate 	if (optind != (argc-1))
10687c478bd9Sstevel@tonic-gate 		usage();
10697c478bd9Sstevel@tonic-gate 
1070d62bc4baSyz147064 	status = i_dladm_aggr_get_linkid(altroot, argv[optind], &linkid, flags);
1071d62bc4baSyz147064 	if (status != DLADM_STATUS_OK)
1072d62bc4baSyz147064 		goto done;
10737c478bd9Sstevel@tonic-gate 
1074d62bc4baSyz147064 	if (altroot != NULL)
1075d62bc4baSyz147064 		altroot_cmd(altroot, argc, argv);
1076d62bc4baSyz147064 
1077d62bc4baSyz147064 	status = dladm_aggr_delete(linkid, flags);
1078d62bc4baSyz147064 done:
1079f595a68aSyz147064 	if (status != DLADM_STATUS_OK)
1080f595a68aSyz147064 		die_dlerr(status, "delete operation failed");
10817c478bd9Sstevel@tonic-gate }
10827c478bd9Sstevel@tonic-gate 
10837c478bd9Sstevel@tonic-gate static void
10848d5c46e6Sam223141 do_add_aggr(int argc, char *argv[], const char *use)
10857c478bd9Sstevel@tonic-gate {
10867c478bd9Sstevel@tonic-gate 	char			option;
1087d62bc4baSyz147064 	uint_t			n, ndev, nlink;
10887c478bd9Sstevel@tonic-gate 	char			*altroot = NULL;
1089d62bc4baSyz147064 	uint32_t		flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
1090d62bc4baSyz147064 	datalink_id_t		linkid;
1091f595a68aSyz147064 	dladm_status_t		status;
1092d62bc4baSyz147064 	dladm_aggr_port_attr_db_t	port[MAXPORT];
1093d62bc4baSyz147064 	char			*devs[MAXPORT];
1094d62bc4baSyz147064 	char			*links[MAXPORT];
10957c478bd9Sstevel@tonic-gate 
1096d62bc4baSyz147064 	ndev = nlink = opterr = 0;
1097d62bc4baSyz147064 	while ((option = getopt_long(argc, argv, ":d:l:R:tf", lopts,
10987c478bd9Sstevel@tonic-gate 	    NULL)) != -1) {
10997c478bd9Sstevel@tonic-gate 		switch (option) {
11007c478bd9Sstevel@tonic-gate 		case 'd':
1101d62bc4baSyz147064 			if (ndev + nlink >= MAXPORT)
1102d62bc4baSyz147064 				die("too many ports specified");
11037c478bd9Sstevel@tonic-gate 
1104d62bc4baSyz147064 			devs[ndev++] = optarg;
1105d62bc4baSyz147064 			break;
1106d62bc4baSyz147064 		case 'l':
1107d62bc4baSyz147064 			if (ndev + nlink >= MAXPORT)
1108d62bc4baSyz147064 				die("too many ports specified");
110933343a97Smeem 
1110d62bc4baSyz147064 			links[nlink++] = optarg;
11117c478bd9Sstevel@tonic-gate 			break;
11127c478bd9Sstevel@tonic-gate 		case 't':
1113d62bc4baSyz147064 			flags &= ~DLADM_OPT_PERSIST;
1114d62bc4baSyz147064 			break;
1115d62bc4baSyz147064 		case 'f':
1116d62bc4baSyz147064 			flags |= DLADM_OPT_FORCE;
11177c478bd9Sstevel@tonic-gate 			break;
11187c478bd9Sstevel@tonic-gate 		case 'R':
11197c478bd9Sstevel@tonic-gate 			altroot = optarg;
11207c478bd9Sstevel@tonic-gate 			break;
11217c478bd9Sstevel@tonic-gate 		default:
11228d5c46e6Sam223141 			die_opterr(optopt, option, use);
112333343a97Smeem 			break;
11247c478bd9Sstevel@tonic-gate 		}
11257c478bd9Sstevel@tonic-gate 	}
11267c478bd9Sstevel@tonic-gate 
1127d62bc4baSyz147064 	if (ndev + nlink == 0)
11287c478bd9Sstevel@tonic-gate 		usage();
11297c478bd9Sstevel@tonic-gate 
1130d62bc4baSyz147064 	/* get key value or the aggregation name (required last argument) */
11317c478bd9Sstevel@tonic-gate 	if (optind != (argc-1))
11327c478bd9Sstevel@tonic-gate 		usage();
11337c478bd9Sstevel@tonic-gate 
1134d62bc4baSyz147064 	if ((status = i_dladm_aggr_get_linkid(altroot, argv[optind], &linkid,
1135d62bc4baSyz147064 	    flags & (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST))) !=
1136d62bc4baSyz147064 	    DLADM_STATUS_OK) {
1137d62bc4baSyz147064 		goto done;
1138d62bc4baSyz147064 	}
11397c478bd9Sstevel@tonic-gate 
1140d62bc4baSyz147064 	if (altroot != NULL)
1141d62bc4baSyz147064 		altroot_cmd(altroot, argc, argv);
1142d62bc4baSyz147064 
1143d62bc4baSyz147064 	for (n = 0; n < ndev; n++) {
1144d62bc4baSyz147064 		if (dladm_dev2linkid(devs[n], &(port[n].lp_linkid)) !=
1145d62bc4baSyz147064 		    DLADM_STATUS_OK) {
1146d62bc4baSyz147064 			die("invalid <dev> '%s'", devs[n]);
1147d62bc4baSyz147064 		}
1148d62bc4baSyz147064 	}
1149d62bc4baSyz147064 
1150d62bc4baSyz147064 	for (n = 0; n < nlink; n++) {
1151d62bc4baSyz147064 		if (dladm_name2info(links[n], &port[n + ndev].lp_linkid,
1152d62bc4baSyz147064 		    NULL, NULL, NULL) != DLADM_STATUS_OK) {
1153d62bc4baSyz147064 			die("invalid <link> '%s'", links[n]);
1154d62bc4baSyz147064 		}
1155d62bc4baSyz147064 	}
1156d62bc4baSyz147064 
1157d62bc4baSyz147064 	status = dladm_aggr_add(linkid, ndev + nlink, port, flags);
1158d62bc4baSyz147064 done:
1159f595a68aSyz147064 	if (status != DLADM_STATUS_OK) {
1160219a2a31Shl157128 		/*
1161f595a68aSyz147064 		 * checking DLADM_STATUS_NOTSUP is a temporary workaround
1162219a2a31Shl157128 		 * and should be removed once 6399681 is fixed.
1163219a2a31Shl157128 		 */
1164f595a68aSyz147064 		if (status == DLADM_STATUS_NOTSUP) {
1165219a2a31Shl157128 			(void) fprintf(stderr,
1166219a2a31Shl157128 			    gettext("%s: add operation failed: %s\n"),
1167219a2a31Shl157128 			    progname,
1168d62bc4baSyz147064 			    gettext("link capabilities don't match"));
1169219a2a31Shl157128 			exit(ENOTSUP);
1170d62bc4baSyz147064 		} else if (status == DLADM_STATUS_NONOTIF) {
1171d62bc4baSyz147064 			die_dlerr(status, "not all links have link up/down "
1172d62bc4baSyz147064 			    "detection; must use -f (see dladm(1M))\n");
1173d62bc4baSyz147064 		} else {
1174f595a68aSyz147064 			die_dlerr(status, "add operation failed");
11757c478bd9Sstevel@tonic-gate 		}
11767c478bd9Sstevel@tonic-gate 	}
1177d62bc4baSyz147064 }
11787c478bd9Sstevel@tonic-gate 
11797c478bd9Sstevel@tonic-gate static void
11808d5c46e6Sam223141 do_remove_aggr(int argc, char *argv[], const char *use)
11817c478bd9Sstevel@tonic-gate {
11827c478bd9Sstevel@tonic-gate 	char				option;
1183f595a68aSyz147064 	dladm_aggr_port_attr_db_t	port[MAXPORT];
1184d62bc4baSyz147064 	uint_t				n, ndev, nlink;
1185d62bc4baSyz147064 	char				*devs[MAXPORT];
1186d62bc4baSyz147064 	char				*links[MAXPORT];
11877c478bd9Sstevel@tonic-gate 	char				*altroot = NULL;
1188d62bc4baSyz147064 	uint32_t			flags;
1189d62bc4baSyz147064 	datalink_id_t			linkid;
1190f595a68aSyz147064 	dladm_status_t			status;
11917c478bd9Sstevel@tonic-gate 
1192d62bc4baSyz147064 	flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
1193d62bc4baSyz147064 	ndev = nlink = opterr = 0;
1194d62bc4baSyz147064 	while ((option = getopt_long(argc, argv, ":d:l:R:t",
1195d62bc4baSyz147064 	    lopts, NULL)) != -1) {
11967c478bd9Sstevel@tonic-gate 		switch (option) {
11977c478bd9Sstevel@tonic-gate 		case 'd':
1198d62bc4baSyz147064 			if (ndev + nlink >= MAXPORT)
1199d62bc4baSyz147064 				die("too many ports specified");
12007c478bd9Sstevel@tonic-gate 
1201d62bc4baSyz147064 			devs[ndev++] = optarg;
1202d62bc4baSyz147064 			break;
1203d62bc4baSyz147064 		case 'l':
1204d62bc4baSyz147064 			if (ndev + nlink >= MAXPORT)
1205d62bc4baSyz147064 				die("too many ports specified");
120633343a97Smeem 
1207d62bc4baSyz147064 			links[nlink++] = optarg;
12087c478bd9Sstevel@tonic-gate 			break;
12097c478bd9Sstevel@tonic-gate 		case 't':
1210d62bc4baSyz147064 			flags &= ~DLADM_OPT_PERSIST;
12117c478bd9Sstevel@tonic-gate 			break;
12127c478bd9Sstevel@tonic-gate 		case 'R':
12137c478bd9Sstevel@tonic-gate 			altroot = optarg;
12147c478bd9Sstevel@tonic-gate 			break;
12157c478bd9Sstevel@tonic-gate 		default:
12168d5c46e6Sam223141 			die_opterr(optopt, option, use);
121733343a97Smeem 			break;
12187c478bd9Sstevel@tonic-gate 		}
12197c478bd9Sstevel@tonic-gate 	}
12207c478bd9Sstevel@tonic-gate 
1221d62bc4baSyz147064 	if (ndev + nlink == 0)
12227c478bd9Sstevel@tonic-gate 		usage();
12237c478bd9Sstevel@tonic-gate 
1224d62bc4baSyz147064 	/* get key value or the aggregation name (required last argument) */
12257c478bd9Sstevel@tonic-gate 	if (optind != (argc-1))
12267c478bd9Sstevel@tonic-gate 		usage();
12277c478bd9Sstevel@tonic-gate 
1228d62bc4baSyz147064 	status = i_dladm_aggr_get_linkid(altroot, argv[optind], &linkid, flags);
1229d62bc4baSyz147064 	if (status != DLADM_STATUS_OK)
1230d62bc4baSyz147064 		goto done;
12317c478bd9Sstevel@tonic-gate 
1232d62bc4baSyz147064 	if (altroot != NULL)
1233d62bc4baSyz147064 		altroot_cmd(altroot, argc, argv);
1234d62bc4baSyz147064 
1235d62bc4baSyz147064 	for (n = 0; n < ndev; n++) {
1236d62bc4baSyz147064 		if (dladm_dev2linkid(devs[n], &(port[n].lp_linkid)) !=
1237d62bc4baSyz147064 		    DLADM_STATUS_OK) {
1238d62bc4baSyz147064 			die("invalid <dev> '%s'", devs[n]);
1239d62bc4baSyz147064 		}
1240d62bc4baSyz147064 	}
1241d62bc4baSyz147064 
1242d62bc4baSyz147064 	for (n = 0; n < nlink; n++) {
1243d62bc4baSyz147064 		if (dladm_name2info(links[n], &port[n + ndev].lp_linkid,
1244d62bc4baSyz147064 		    NULL, NULL, NULL) != DLADM_STATUS_OK) {
1245d62bc4baSyz147064 			die("invalid <link> '%s'", links[n]);
1246d62bc4baSyz147064 		}
1247d62bc4baSyz147064 	}
1248d62bc4baSyz147064 
1249d62bc4baSyz147064 	status = dladm_aggr_remove(linkid, ndev + nlink, port, flags);
1250d62bc4baSyz147064 done:
1251f595a68aSyz147064 	if (status != DLADM_STATUS_OK)
1252f595a68aSyz147064 		die_dlerr(status, "remove operation failed");
12537c478bd9Sstevel@tonic-gate }
12547c478bd9Sstevel@tonic-gate 
12557c478bd9Sstevel@tonic-gate static void
12568d5c46e6Sam223141 do_modify_aggr(int argc, char *argv[], const char *use)
12577c478bd9Sstevel@tonic-gate {
12587c478bd9Sstevel@tonic-gate 	char			option;
12597c478bd9Sstevel@tonic-gate 	uint32_t		policy = AGGR_POLICY_L4;
12607c478bd9Sstevel@tonic-gate 	aggr_lacp_mode_t	lacp_mode = AGGR_LACP_OFF;
12617c478bd9Sstevel@tonic-gate 	aggr_lacp_timer_t	lacp_timer = AGGR_LACP_TIMER_SHORT;
12627c478bd9Sstevel@tonic-gate 	uint8_t			mac_addr[ETHERADDRL];
12637c478bd9Sstevel@tonic-gate 	boolean_t		mac_addr_fixed = B_FALSE;
12647c478bd9Sstevel@tonic-gate 	uint8_t			modify_mask = 0;
12657c478bd9Sstevel@tonic-gate 	char			*altroot = NULL;
1266d62bc4baSyz147064 	uint32_t		flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
1267d62bc4baSyz147064 	datalink_id_t		linkid;
1268f595a68aSyz147064 	dladm_status_t		status;
12697c478bd9Sstevel@tonic-gate 
12707c478bd9Sstevel@tonic-gate 	opterr = 0;
1271d62bc4baSyz147064 	while ((option = getopt_long(argc, argv, ":L:l:P:R:tu:T:", lopts,
12727c478bd9Sstevel@tonic-gate 	    NULL)) != -1) {
12737c478bd9Sstevel@tonic-gate 		switch (option) {
12747c478bd9Sstevel@tonic-gate 		case 'P':
1275f595a68aSyz147064 			if (modify_mask & DLADM_AGGR_MODIFY_POLICY)
127633343a97Smeem 				die_optdup(option);
12777c478bd9Sstevel@tonic-gate 
1278f595a68aSyz147064 			modify_mask |= DLADM_AGGR_MODIFY_POLICY;
12797c478bd9Sstevel@tonic-gate 
1280f595a68aSyz147064 			if (!dladm_aggr_str2policy(optarg, &policy))
128133343a97Smeem 				die("invalid policy '%s'", optarg);
12827c478bd9Sstevel@tonic-gate 			break;
12837c478bd9Sstevel@tonic-gate 		case 'u':
1284f595a68aSyz147064 			if (modify_mask & DLADM_AGGR_MODIFY_MAC)
128533343a97Smeem 				die_optdup(option);
12867c478bd9Sstevel@tonic-gate 
1287f595a68aSyz147064 			modify_mask |= DLADM_AGGR_MODIFY_MAC;
12887c478bd9Sstevel@tonic-gate 
1289f595a68aSyz147064 			if (!dladm_aggr_str2macaddr(optarg, &mac_addr_fixed,
129033343a97Smeem 			    mac_addr))
129133343a97Smeem 				die("invalid MAC address '%s'", optarg);
12927c478bd9Sstevel@tonic-gate 			break;
12937c478bd9Sstevel@tonic-gate 		case 'l':
1294d62bc4baSyz147064 		case 'L':
1295f595a68aSyz147064 			if (modify_mask & DLADM_AGGR_MODIFY_LACP_MODE)
129633343a97Smeem 				die_optdup(option);
12977c478bd9Sstevel@tonic-gate 
1298f595a68aSyz147064 			modify_mask |= DLADM_AGGR_MODIFY_LACP_MODE;
12997c478bd9Sstevel@tonic-gate 
1300f595a68aSyz147064 			if (!dladm_aggr_str2lacpmode(optarg, &lacp_mode))
130133343a97Smeem 				die("invalid LACP mode '%s'", optarg);
13027c478bd9Sstevel@tonic-gate 			break;
13037c478bd9Sstevel@tonic-gate 		case 'T':
1304f595a68aSyz147064 			if (modify_mask & DLADM_AGGR_MODIFY_LACP_TIMER)
130533343a97Smeem 				die_optdup(option);
13067c478bd9Sstevel@tonic-gate 
1307f595a68aSyz147064 			modify_mask |= DLADM_AGGR_MODIFY_LACP_TIMER;
13087c478bd9Sstevel@tonic-gate 
1309f595a68aSyz147064 			if (!dladm_aggr_str2lacptimer(optarg, &lacp_timer))
131033343a97Smeem 				die("invalid LACP timer value '%s'", optarg);
13117c478bd9Sstevel@tonic-gate 			break;
13127c478bd9Sstevel@tonic-gate 		case 't':
1313d62bc4baSyz147064 			flags &= ~DLADM_OPT_PERSIST;
13147c478bd9Sstevel@tonic-gate 			break;
13157c478bd9Sstevel@tonic-gate 		case 'R':
13167c478bd9Sstevel@tonic-gate 			altroot = optarg;
13177c478bd9Sstevel@tonic-gate 			break;
13187c478bd9Sstevel@tonic-gate 		default:
13198d5c46e6Sam223141 			die_opterr(optopt, option, use);
132033343a97Smeem 			break;
13217c478bd9Sstevel@tonic-gate 		}
13227c478bd9Sstevel@tonic-gate 	}
13237c478bd9Sstevel@tonic-gate 
132433343a97Smeem 	if (modify_mask == 0)
132533343a97Smeem 		die("at least one of the -PulT options must be specified");
13267c478bd9Sstevel@tonic-gate 
1327d62bc4baSyz147064 	/* get key value or the aggregation name (required last argument) */
13287c478bd9Sstevel@tonic-gate 	if (optind != (argc-1))
13297c478bd9Sstevel@tonic-gate 		usage();
13307c478bd9Sstevel@tonic-gate 
1331d62bc4baSyz147064 	status = i_dladm_aggr_get_linkid(altroot, argv[optind], &linkid, flags);
1332d62bc4baSyz147064 	if (status != DLADM_STATUS_OK)
1333d62bc4baSyz147064 		goto done;
13347c478bd9Sstevel@tonic-gate 
1335d62bc4baSyz147064 	if (altroot != NULL)
1336d62bc4baSyz147064 		altroot_cmd(altroot, argc, argv);
1337d62bc4baSyz147064 
1338d62bc4baSyz147064 	status = dladm_aggr_modify(linkid, modify_mask, policy, mac_addr_fixed,
1339d62bc4baSyz147064 	    (const uchar_t *)mac_addr, lacp_mode, lacp_timer, flags);
1340d62bc4baSyz147064 
1341d62bc4baSyz147064 done:
1342f595a68aSyz147064 	if (status != DLADM_STATUS_OK)
1343f595a68aSyz147064 		die_dlerr(status, "modify operation failed");
13447c478bd9Sstevel@tonic-gate }
13457c478bd9Sstevel@tonic-gate 
13468d5c46e6Sam223141 /*ARGSUSED*/
13477c478bd9Sstevel@tonic-gate static void
13488d5c46e6Sam223141 do_up_aggr(int argc, char *argv[], const char *use)
13497c478bd9Sstevel@tonic-gate {
1350d62bc4baSyz147064 	datalink_id_t	linkid = DATALINK_ALL_LINKID;
1351f595a68aSyz147064 	dladm_status_t	status;
13527c478bd9Sstevel@tonic-gate 
1353d62bc4baSyz147064 	/*
1354d62bc4baSyz147064 	 * get the key or the name of the aggregation (optional last argument)
1355d62bc4baSyz147064 	 */
13567c478bd9Sstevel@tonic-gate 	if (argc == 2) {
1357d62bc4baSyz147064 		if ((status = i_dladm_aggr_get_linkid(NULL, argv[1], &linkid,
1358d62bc4baSyz147064 		    DLADM_OPT_PERSIST)) != DLADM_STATUS_OK) {
1359d62bc4baSyz147064 			goto done;
1360d62bc4baSyz147064 		}
13617c478bd9Sstevel@tonic-gate 	} else if (argc > 2) {
13627c478bd9Sstevel@tonic-gate 		usage();
13637c478bd9Sstevel@tonic-gate 	}
13647c478bd9Sstevel@tonic-gate 
1365d62bc4baSyz147064 	status = dladm_aggr_up(linkid);
1366d62bc4baSyz147064 done:
1367d62bc4baSyz147064 	if (status != DLADM_STATUS_OK) {
1368d62bc4baSyz147064 		if (argc == 2) {
1369d62bc4baSyz147064 			die_dlerr(status,
1370d62bc4baSyz147064 			    "could not bring up aggregation '%s'", argv[1]);
13717c478bd9Sstevel@tonic-gate 		} else {
1372f595a68aSyz147064 			die_dlerr(status, "could not bring aggregations up");
13737c478bd9Sstevel@tonic-gate 		}
13747c478bd9Sstevel@tonic-gate 	}
13757c478bd9Sstevel@tonic-gate }
13767c478bd9Sstevel@tonic-gate 
13777c478bd9Sstevel@tonic-gate static void
13788d5c46e6Sam223141 do_create_vlan(int argc, char *argv[], const char *use)
13797c478bd9Sstevel@tonic-gate {
1380d62bc4baSyz147064 	char		*link = NULL;
1381d62bc4baSyz147064 	char		drv[DLPI_LINKNAME_MAX];
1382d62bc4baSyz147064 	uint_t		ppa;
1383d62bc4baSyz147064 	datalink_id_t	linkid;
1384d62bc4baSyz147064 	int		vid = 0;
1385d62bc4baSyz147064 	char		option;
1386d62bc4baSyz147064 	uint32_t	flags = (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST);
1387d62bc4baSyz147064 	char		*altroot = NULL;
1388d62bc4baSyz147064 	char		vlan[MAXLINKNAMELEN];
1389f595a68aSyz147064 	dladm_status_t	status;
13907c478bd9Sstevel@tonic-gate 
1391d62bc4baSyz147064 	opterr = 0;
1392d62bc4baSyz147064 	while ((option = getopt_long(argc, argv, ":tfl:v:",
1393d62bc4baSyz147064 	    lopts, NULL)) != -1) {
1394d62bc4baSyz147064 		switch (option) {
1395d62bc4baSyz147064 		case 'v':
1396d62bc4baSyz147064 			if (vid != 0)
1397d62bc4baSyz147064 				die_optdup(option);
1398d62bc4baSyz147064 
1399d62bc4baSyz147064 			if (!str2int(optarg, &vid) || vid < 1 || vid > 4094)
1400d62bc4baSyz147064 				die("invalid VLAN identifier '%s'", optarg);
1401d62bc4baSyz147064 
1402d62bc4baSyz147064 			break;
1403d62bc4baSyz147064 		case 'l':
1404d62bc4baSyz147064 			if (link != NULL)
1405d62bc4baSyz147064 				die_optdup(option);
1406d62bc4baSyz147064 
1407d62bc4baSyz147064 			link = optarg;
1408d62bc4baSyz147064 			break;
1409d62bc4baSyz147064 		case 'f':
1410d62bc4baSyz147064 			flags |= DLADM_OPT_FORCE;
1411d62bc4baSyz147064 			break;
1412d62bc4baSyz147064 		case 't':
1413d62bc4baSyz147064 			flags &= ~DLADM_OPT_PERSIST;
1414d62bc4baSyz147064 			break;
1415d62bc4baSyz147064 		case 'R':
1416d62bc4baSyz147064 			altroot = optarg;
1417d62bc4baSyz147064 			break;
1418d62bc4baSyz147064 		default:
14198d5c46e6Sam223141 			die_opterr(optopt, option, use);
1420d62bc4baSyz147064 			break;
1421d62bc4baSyz147064 		}
1422d62bc4baSyz147064 	}
1423d62bc4baSyz147064 
1424d62bc4baSyz147064 	/* get vlan name if there is any */
1425d62bc4baSyz147064 	if ((vid == 0) || (link == NULL) || (argc - optind > 1))
14267c478bd9Sstevel@tonic-gate 		usage();
1427d62bc4baSyz147064 
1428d62bc4baSyz147064 	if (optind == (argc - 1)) {
1429d62bc4baSyz147064 		if (strlcpy(vlan, argv[optind], MAXLINKNAMELEN) >=
1430d62bc4baSyz147064 		    MAXLINKNAMELEN) {
1431d62bc4baSyz147064 			die("vlan name too long '%s'", argv[optind]);
1432d62bc4baSyz147064 		}
1433d62bc4baSyz147064 	} else {
1434d62bc4baSyz147064 		if ((dlpi_parselink(link, drv, &ppa) != DLPI_SUCCESS) ||
1435d62bc4baSyz147064 		    (ppa >= 1000) ||
1436d62bc4baSyz147064 		    (dlpi_makelink(vlan, drv, vid * 1000 + ppa) !=
1437d62bc4baSyz147064 		    DLPI_SUCCESS)) {
1438d62bc4baSyz147064 			die("invalid link name '%s'", link);
1439d62bc4baSyz147064 		}
14407c478bd9Sstevel@tonic-gate 	}
14417c478bd9Sstevel@tonic-gate 
1442d62bc4baSyz147064 	if (altroot != NULL)
1443d62bc4baSyz147064 		altroot_cmd(altroot, argc, argv);
1444d62bc4baSyz147064 
1445d62bc4baSyz147064 	if (dladm_name2info(link, &linkid, NULL, NULL, NULL) !=
1446d62bc4baSyz147064 	    DLADM_STATUS_OK) {
1447d62bc4baSyz147064 		die("invalid link name '%s'", link);
1448d62bc4baSyz147064 	}
1449d62bc4baSyz147064 
1450d62bc4baSyz147064 	if ((status = dladm_vlan_create(vlan, linkid, vid, flags)) !=
1451d62bc4baSyz147064 	    DLADM_STATUS_OK) {
1452d62bc4baSyz147064 		if (status == DLADM_STATUS_NOTSUP) {
14536b9e797cSsowmini 			die_dlerr(status, "VLAN over '%s' may require lowered "
14546b9e797cSsowmini 			    "MTU; must use -f (see dladm(1M))\n", link);
1455d62bc4baSyz147064 		} else {
1456d62bc4baSyz147064 			die_dlerr(status, "create operation failed");
1457d62bc4baSyz147064 		}
1458d62bc4baSyz147064 	}
1459d62bc4baSyz147064 }
1460d62bc4baSyz147064 
1461d62bc4baSyz147064 static void
14628d5c46e6Sam223141 do_delete_vlan(int argc, char *argv[], const char *use)
1463d62bc4baSyz147064 {
1464d62bc4baSyz147064 	char		option;
1465d62bc4baSyz147064 	uint32_t	flags = (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST);
1466d62bc4baSyz147064 	char		*altroot = NULL;
1467d62bc4baSyz147064 	datalink_id_t	linkid;
1468d62bc4baSyz147064 	dladm_status_t	status;
1469d62bc4baSyz147064 
1470d62bc4baSyz147064 	opterr = 0;
1471d62bc4baSyz147064 	while ((option = getopt_long(argc, argv, ":R:t", lopts, NULL)) != -1) {
1472d62bc4baSyz147064 		switch (option) {
1473d62bc4baSyz147064 		case 't':
1474d62bc4baSyz147064 			flags &= ~DLADM_OPT_PERSIST;
1475d62bc4baSyz147064 			break;
1476d62bc4baSyz147064 		case 'R':
1477d62bc4baSyz147064 			altroot = optarg;
1478d62bc4baSyz147064 			break;
1479d62bc4baSyz147064 		default:
14808d5c46e6Sam223141 			die_opterr(optopt, option, use);
1481d62bc4baSyz147064 			break;
1482d62bc4baSyz147064 		}
1483d62bc4baSyz147064 	}
1484d62bc4baSyz147064 
1485d62bc4baSyz147064 	/* get VLAN link name (required last argument) */
1486d62bc4baSyz147064 	if (optind != (argc - 1))
1487d62bc4baSyz147064 		usage();
1488d62bc4baSyz147064 
1489d62bc4baSyz147064 	if (altroot != NULL)
1490d62bc4baSyz147064 		altroot_cmd(altroot, argc, argv);
1491d62bc4baSyz147064 
1492d62bc4baSyz147064 	status = dladm_name2info(argv[optind], &linkid, NULL, NULL, NULL);
1493d62bc4baSyz147064 	if (status != DLADM_STATUS_OK)
1494d62bc4baSyz147064 		goto done;
1495d62bc4baSyz147064 
1496d62bc4baSyz147064 	status = dladm_vlan_delete(linkid, flags);
1497d62bc4baSyz147064 done:
1498d62bc4baSyz147064 	if (status != DLADM_STATUS_OK)
1499d62bc4baSyz147064 		die_dlerr(status, "delete operation failed");
1500d62bc4baSyz147064 }
1501d62bc4baSyz147064 
15028d5c46e6Sam223141 /*ARGSUSED*/
1503d62bc4baSyz147064 static void
15048d5c46e6Sam223141 do_up_vlan(int argc, char *argv[], const char *use)
1505d62bc4baSyz147064 {
1506d62bc4baSyz147064 	datalink_id_t	linkid = DATALINK_ALL_LINKID;
1507d62bc4baSyz147064 	dladm_status_t	status;
1508d62bc4baSyz147064 
1509d62bc4baSyz147064 	/*
1510d62bc4baSyz147064 	 * get the name of the VLAN (optional last argument)
1511d62bc4baSyz147064 	 */
1512d62bc4baSyz147064 	if (argc > 2)
1513d62bc4baSyz147064 		usage();
1514d62bc4baSyz147064 
1515d62bc4baSyz147064 	if (argc == 2) {
1516d62bc4baSyz147064 		status = dladm_name2info(argv[1], &linkid, NULL, NULL, NULL);
1517d62bc4baSyz147064 		if (status != DLADM_STATUS_OK)
1518d62bc4baSyz147064 			goto done;
1519d62bc4baSyz147064 	}
1520d62bc4baSyz147064 
1521d62bc4baSyz147064 	status = dladm_vlan_up(linkid);
1522d62bc4baSyz147064 done:
1523d62bc4baSyz147064 	if (status != DLADM_STATUS_OK) {
1524d62bc4baSyz147064 		if (argc == 2) {
1525f595a68aSyz147064 			die_dlerr(status,
1526d62bc4baSyz147064 			    "could not bring up VLAN '%s'", argv[1]);
15277c478bd9Sstevel@tonic-gate 		} else {
1528d62bc4baSyz147064 			die_dlerr(status, "could not bring VLANs up");
15297c478bd9Sstevel@tonic-gate 		}
15307c478bd9Sstevel@tonic-gate 	}
15317c478bd9Sstevel@tonic-gate }
15327c478bd9Sstevel@tonic-gate 
1533210db224Sericheng static void
15348d5c46e6Sam223141 do_rename_link(int argc, char *argv[], const char *use)
1535210db224Sericheng {
1536d62bc4baSyz147064 	char		option;
1537d62bc4baSyz147064 	char		*link1, *link2;
1538d62bc4baSyz147064 	char		*altroot = NULL;
1539d62bc4baSyz147064 	dladm_status_t	status;
1540210db224Sericheng 
1541d62bc4baSyz147064 	opterr = 0;
1542d62bc4baSyz147064 	while ((option = getopt_long(argc, argv, ":R:", lopts, NULL)) != -1) {
1543d62bc4baSyz147064 		switch (option) {
1544d62bc4baSyz147064 		case 'R':
1545d62bc4baSyz147064 			altroot = optarg;
1546d62bc4baSyz147064 			break;
1547d62bc4baSyz147064 		default:
15488d5c46e6Sam223141 			die_opterr(optopt, option, use);
1549d62bc4baSyz147064 			break;
1550210db224Sericheng 		}
1551210db224Sericheng 	}
1552210db224Sericheng 
1553d62bc4baSyz147064 	/* get link1 and link2 name (required the last 2 arguments) */
1554d62bc4baSyz147064 	if (optind != (argc - 2))
1555d62bc4baSyz147064 		usage();
1556d62bc4baSyz147064 
1557d62bc4baSyz147064 	if (altroot != NULL)
1558d62bc4baSyz147064 		altroot_cmd(altroot, argc, argv);
1559d62bc4baSyz147064 
1560d62bc4baSyz147064 	link1 = argv[optind++];
1561d62bc4baSyz147064 	link2 = argv[optind];
1562d62bc4baSyz147064 	if ((status = dladm_rename_link(link1, link2)) != DLADM_STATUS_OK)
1563d62bc4baSyz147064 		die_dlerr(status, "rename operation failed");
1564d62bc4baSyz147064 }
1565d62bc4baSyz147064 
15668d5c46e6Sam223141 /*ARGSUSED*/
1567d62bc4baSyz147064 static void
15688d5c46e6Sam223141 do_delete_phys(int argc, char *argv[], const char *use)
1569d62bc4baSyz147064 {
1570d62bc4baSyz147064 	datalink_id_t	linkid = DATALINK_ALL_LINKID;
1571d62bc4baSyz147064 	dladm_status_t	status;
1572d62bc4baSyz147064 
1573d62bc4baSyz147064 	/* get link name (required the last argument) */
1574d62bc4baSyz147064 	if (argc > 2)
1575d62bc4baSyz147064 		usage();
1576d62bc4baSyz147064 
1577d62bc4baSyz147064 	if (argc == 2) {
1578d62bc4baSyz147064 		status = dladm_name2info(argv[1], &linkid, NULL, NULL, NULL);
1579d62bc4baSyz147064 		if (status != DLADM_STATUS_OK)
1580d62bc4baSyz147064 			die_dlerr(status, "cannot delete '%s'", argv[1]);
1581d62bc4baSyz147064 	}
1582d62bc4baSyz147064 
1583d62bc4baSyz147064 	if ((status = dladm_phys_delete(linkid)) != DLADM_STATUS_OK) {
1584d62bc4baSyz147064 		if (argc == 2)
1585d62bc4baSyz147064 			die_dlerr(status, "cannot delete '%s'", argv[1]);
1586d62bc4baSyz147064 		else
1587d62bc4baSyz147064 			die_dlerr(status, "delete operation failed");
1588d62bc4baSyz147064 	}
1589d62bc4baSyz147064 }
1590d62bc4baSyz147064 
1591d62bc4baSyz147064 /*ARGSUSED*/
1592210db224Sericheng static int
1593d62bc4baSyz147064 i_dladm_walk_linkmap(datalink_id_t linkid, void *arg)
1594210db224Sericheng {
1595d62bc4baSyz147064 	char			name[MAXLINKNAMELEN];
1596d62bc4baSyz147064 	char			mediabuf[DLADM_STRSIZE];
1597d62bc4baSyz147064 	char			classbuf[DLADM_STRSIZE];
1598d62bc4baSyz147064 	datalink_class_t	class;
1599d62bc4baSyz147064 	uint32_t		media;
1600d62bc4baSyz147064 	uint32_t		flags;
1601210db224Sericheng 
1602d62bc4baSyz147064 	if (dladm_datalink_id2info(linkid, &flags, &class, &media, name,
1603d62bc4baSyz147064 	    MAXLINKNAMELEN) == DLADM_STATUS_OK) {
1604d62bc4baSyz147064 		(void) dladm_class2str(class, classbuf);
1605d62bc4baSyz147064 		(void) dladm_media2str(media, mediabuf);
1606d62bc4baSyz147064 		(void) printf("%-12s%8d  %-12s%-20s %6d\n", name,
1607d62bc4baSyz147064 		    linkid, classbuf, mediabuf, flags);
1608210db224Sericheng 	}
1609d62bc4baSyz147064 	return (DLADM_WALK_CONTINUE);
1610210db224Sericheng }
16117c478bd9Sstevel@tonic-gate 
16127c478bd9Sstevel@tonic-gate /*ARGSUSED*/
16137c478bd9Sstevel@tonic-gate static void
16148d5c46e6Sam223141 do_show_linkmap(int argc, char *argv[], const char *use)
16157c478bd9Sstevel@tonic-gate {
1616d62bc4baSyz147064 	if (argc != 1)
1617d62bc4baSyz147064 		die("invalid arguments");
16187c478bd9Sstevel@tonic-gate 
1619d62bc4baSyz147064 	(void) printf("%-12s%8s  %-12s%-20s %6s\n", "NAME", "LINKID",
1620d62bc4baSyz147064 	    "CLASS", "MEDIA", "FLAGS");
1621d62bc4baSyz147064 	(void) dladm_walk_datalink_id(i_dladm_walk_linkmap, NULL,
1622d62bc4baSyz147064 	    DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE,
1623d62bc4baSyz147064 	    DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST);
16247c478bd9Sstevel@tonic-gate }
1625d62bc4baSyz147064 
1626d62bc4baSyz147064 /*
1627d62bc4baSyz147064  * Delete inactive physical links.
1628d62bc4baSyz147064  */
1629d62bc4baSyz147064 /*ARGSUSED*/
1630d62bc4baSyz147064 static int
1631d62bc4baSyz147064 purge_phys(datalink_id_t linkid, void *arg)
1632d62bc4baSyz147064 {
1633d62bc4baSyz147064 	datalink_class_t	class;
1634d62bc4baSyz147064 	uint32_t		flags;
1635d62bc4baSyz147064 
1636d62bc4baSyz147064 	if (dladm_datalink_id2info(linkid, &flags, &class, NULL,
1637d62bc4baSyz147064 	    NULL, 0) != DLADM_STATUS_OK) {
1638d62bc4baSyz147064 		return (DLADM_WALK_CONTINUE);
1639d62bc4baSyz147064 	}
1640d62bc4baSyz147064 
1641d62bc4baSyz147064 	if (class == DATALINK_CLASS_PHYS && !(flags & DLADM_OPT_ACTIVE))
1642d62bc4baSyz147064 		(void) dladm_phys_delete(linkid);
1643d62bc4baSyz147064 
1644d62bc4baSyz147064 	return (DLADM_WALK_CONTINUE);
1645d62bc4baSyz147064 }
1646d62bc4baSyz147064 
1647d62bc4baSyz147064 /*ARGSUSED*/
1648d62bc4baSyz147064 static void
16498d5c46e6Sam223141 do_init_phys(int argc, char *argv[], const char *use)
1650d62bc4baSyz147064 {
1651d62bc4baSyz147064 	di_node_t devtree;
1652d62bc4baSyz147064 
1653d62bc4baSyz147064 	if (argc > 1)
1654d62bc4baSyz147064 		usage();
1655d62bc4baSyz147064 
1656d62bc4baSyz147064 	/*
1657d62bc4baSyz147064 	 * Force all the devices to attach, therefore all the network physical
1658d62bc4baSyz147064 	 * devices can be known to the dlmgmtd daemon.
1659d62bc4baSyz147064 	 */
1660d62bc4baSyz147064 	if ((devtree = di_init("/", DINFOFORCE | DINFOSUBTREE)) != DI_NODE_NIL)
1661d62bc4baSyz147064 		di_fini(devtree);
1662d62bc4baSyz147064 
1663d62bc4baSyz147064 	(void) dladm_walk_datalink_id(purge_phys, NULL,
1664d62bc4baSyz147064 	    DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST);
16657c478bd9Sstevel@tonic-gate }
16667c478bd9Sstevel@tonic-gate 
1667d62bc4baSyz147064 
1668d62bc4baSyz147064 /*
1669d62bc4baSyz147064  * Print the active topology information.
1670d62bc4baSyz147064  */
1671d62bc4baSyz147064 static dladm_status_t
1672d62bc4baSyz147064 print_link_topology(show_state_t *state, datalink_id_t linkid,
1673e7801d59Ssowmini     datalink_class_t class, link_fields_buf_t *lbuf)
1674d62bc4baSyz147064 {
1675d62bc4baSyz147064 	uint32_t	flags = state->ls_flags;
1676d62bc4baSyz147064 	dladm_status_t	status = DLADM_STATUS_OK;
16776b9e797cSsowmini 	char		tmpbuf[MAXLINKNAMELEN];
1678d62bc4baSyz147064 
1679e7801d59Ssowmini 	if (!state->ls_parseable)
1680e7801d59Ssowmini 		(void) sprintf(lbuf->link_over, STR_UNDEF_VAL);
1681d62bc4baSyz147064 	else
1682e7801d59Ssowmini 		(void) sprintf(lbuf->link_over, "");
1683d62bc4baSyz147064 
1684d62bc4baSyz147064 	if (class == DATALINK_CLASS_VLAN) {
1685d62bc4baSyz147064 		dladm_vlan_attr_t	vinfo;
1686d62bc4baSyz147064 
1687d62bc4baSyz147064 		status = dladm_vlan_info(linkid, &vinfo, flags);
1688d62bc4baSyz147064 		if (status != DLADM_STATUS_OK)
1689d62bc4baSyz147064 			goto done;
1690d62bc4baSyz147064 		status = dladm_datalink_id2info(vinfo.dv_linkid, NULL, NULL,
1691e7801d59Ssowmini 		    NULL, lbuf->link_over, sizeof (lbuf->link_over));
1692d62bc4baSyz147064 		if (status != DLADM_STATUS_OK)
1693d62bc4baSyz147064 			goto done;
1694d62bc4baSyz147064 	} else if (class == DATALINK_CLASS_AGGR) {
1695d62bc4baSyz147064 		dladm_aggr_grp_attr_t	ginfo;
1696d62bc4baSyz147064 		int			i;
1697d62bc4baSyz147064 
16986b9e797cSsowmini 		(void) sprintf(lbuf->link_over, "");
16996b9e797cSsowmini 
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(
1710e7801d59Ssowmini 			    ginfo.lg_ports[i].lp_linkid, NULL, NULL, NULL,
17116b9e797cSsowmini 			    tmpbuf, sizeof (tmpbuf));
1712d62bc4baSyz147064 			if (status != DLADM_STATUS_OK) {
1713d62bc4baSyz147064 				free(ginfo.lg_ports);
1714d62bc4baSyz147064 				goto done;
1715d62bc4baSyz147064 			}
17166b9e797cSsowmini 			(void) strlcat(lbuf->link_over, tmpbuf,
17176b9e797cSsowmini 			    sizeof (lbuf->link_over));
17186b9e797cSsowmini 			if (i != (ginfo.lg_nports - 1)) {
17196b9e797cSsowmini 				(void) strlcat(lbuf->link_over, " ",
17206b9e797cSsowmini 				    sizeof (lbuf->link_over));
17216b9e797cSsowmini 			}
1722d62bc4baSyz147064 		}
1723d62bc4baSyz147064 		free(ginfo.lg_ports);
1724d62bc4baSyz147064 	} else if (class == DATALINK_CLASS_VNIC) {
1725d62bc4baSyz147064 		dladm_vnic_attr_sys_t	vinfo;
1726d62bc4baSyz147064 
1727d62bc4baSyz147064 		if ((status = dladm_vnic_info(linkid, &vinfo, flags)) !=
1728d62bc4baSyz147064 		    DLADM_STATUS_OK || (status = dladm_datalink_id2info(
1729e7801d59Ssowmini 		    vinfo.va_link_id, NULL, NULL, NULL, lbuf->link_over,
1730e7801d59Ssowmini 		    sizeof (lbuf->link_over)) != DLADM_STATUS_OK)) {
1731d62bc4baSyz147064 			goto done;
1732d62bc4baSyz147064 		}
1733d62bc4baSyz147064 	}
1734d62bc4baSyz147064 done:
1735d62bc4baSyz147064 	return (status);
1736d62bc4baSyz147064 }
1737d62bc4baSyz147064 
1738d62bc4baSyz147064 static dladm_status_t
1739e7801d59Ssowmini print_link(show_state_t *state, datalink_id_t linkid, link_fields_buf_t *lbuf)
1740d62bc4baSyz147064 {
1741d62bc4baSyz147064 	char			link[MAXLINKNAMELEN];
1742d62bc4baSyz147064 	datalink_class_t	class;
1743d62bc4baSyz147064 	uint_t			mtu;
1744d62bc4baSyz147064 	uint32_t		flags;
1745d62bc4baSyz147064 	dladm_status_t		status;
1746d62bc4baSyz147064 
1747d62bc4baSyz147064 	if ((status = dladm_datalink_id2info(linkid, &flags, &class, NULL,
1748d62bc4baSyz147064 	    link, sizeof (link))) != DLADM_STATUS_OK) {
1749d62bc4baSyz147064 		goto done;
1750d62bc4baSyz147064 	}
1751d62bc4baSyz147064 
1752d62bc4baSyz147064 	if (!(state->ls_flags & flags)) {
1753d62bc4baSyz147064 		status = DLADM_STATUS_NOTFOUND;
1754d62bc4baSyz147064 		goto done;
1755d62bc4baSyz147064 	}
1756d62bc4baSyz147064 
1757d62bc4baSyz147064 	if (state->ls_flags == DLADM_OPT_ACTIVE) {
1758d62bc4baSyz147064 		dladm_attr_t	dlattr;
1759d62bc4baSyz147064 
1760d62bc4baSyz147064 		if (class == DATALINK_CLASS_PHYS) {
1761d62bc4baSyz147064 			dladm_phys_attr_t	dpa;
1762d62bc4baSyz147064 			dlpi_handle_t		dh;
1763d62bc4baSyz147064 			dlpi_info_t		dlinfo;
1764d62bc4baSyz147064 
1765d62bc4baSyz147064 			if ((status = dladm_phys_info(linkid, &dpa,
1766d62bc4baSyz147064 			    DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) {
1767d62bc4baSyz147064 				goto done;
1768d62bc4baSyz147064 			}
1769d62bc4baSyz147064 
1770d62bc4baSyz147064 			if (!dpa.dp_novanity)
1771d62bc4baSyz147064 				goto link_mtu;
1772d62bc4baSyz147064 
1773d62bc4baSyz147064 			/*
1774d62bc4baSyz147064 			 * This is a physical link that does not have
1775d62bc4baSyz147064 			 * vanity naming support.
1776d62bc4baSyz147064 			 */
1777d62bc4baSyz147064 			if (dlpi_open(dpa.dp_dev, &dh, DLPI_DEVONLY) !=
1778d62bc4baSyz147064 			    DLPI_SUCCESS) {
1779d62bc4baSyz147064 				status = DLADM_STATUS_NOTFOUND;
1780d62bc4baSyz147064 				goto done;
1781d62bc4baSyz147064 			}
1782d62bc4baSyz147064 
1783d62bc4baSyz147064 			if (dlpi_info(dh, &dlinfo, 0) != DLPI_SUCCESS) {
1784d62bc4baSyz147064 				dlpi_close(dh);
1785d62bc4baSyz147064 				status = DLADM_STATUS_BADARG;
1786d62bc4baSyz147064 				goto done;
1787d62bc4baSyz147064 			}
1788d62bc4baSyz147064 
1789d62bc4baSyz147064 			dlpi_close(dh);
1790d62bc4baSyz147064 			mtu = dlinfo.di_max_sdu;
1791d62bc4baSyz147064 		} else {
1792d62bc4baSyz147064 link_mtu:
1793d62bc4baSyz147064 			status = dladm_info(linkid, &dlattr);
1794d62bc4baSyz147064 			if (status != DLADM_STATUS_OK)
1795d62bc4baSyz147064 				goto done;
1796d62bc4baSyz147064 			mtu = dlattr.da_max_sdu;
1797d62bc4baSyz147064 		}
1798d62bc4baSyz147064 	}
1799d62bc4baSyz147064 
1800e7801d59Ssowmini 	(void) snprintf(lbuf->link_name, sizeof (lbuf->link_name),
1801e7801d59Ssowmini 	    "%s", link);
1802e7801d59Ssowmini 	(void) dladm_class2str(class, lbuf->link_class);
1803d62bc4baSyz147064 	if (state->ls_flags == DLADM_OPT_ACTIVE) {
1804e7801d59Ssowmini 		(void) snprintf(lbuf->link_mtu, sizeof (lbuf->link_mtu),
1805c08e5e1aSdr146992 		    "%u", mtu);
1806e7801d59Ssowmini 		(void) get_linkstate(link, B_TRUE, lbuf->link_state);
1807d62bc4baSyz147064 	}
1808d62bc4baSyz147064 
1809e7801d59Ssowmini 	status = print_link_topology(state, linkid, class, lbuf);
1810d62bc4baSyz147064 	if (status != DLADM_STATUS_OK)
1811d62bc4baSyz147064 		goto done;
1812d62bc4baSyz147064 
1813d62bc4baSyz147064 done:
1814d62bc4baSyz147064 	return (status);
1815d62bc4baSyz147064 }
1816d62bc4baSyz147064 
1817e7801d59Ssowmini 
1818d62bc4baSyz147064 static int
1819d62bc4baSyz147064 show_link(datalink_id_t linkid, void *arg)
1820d62bc4baSyz147064 {
1821e7801d59Ssowmini 	show_state_t		*state = (show_state_t *)arg;
1822d62bc4baSyz147064 	dladm_status_t		status;
1823e7801d59Ssowmini 	link_fields_buf_t	lbuf;
1824d62bc4baSyz147064 
1825e7801d59Ssowmini 	/*
1826e7801d59Ssowmini 	 * first get all the link attributes into lbuf;
1827e7801d59Ssowmini 	 */
18285f5c9f54SAnurag S. Maskey 	bzero(&lbuf, sizeof (link_fields_buf_t));
1829e7801d59Ssowmini 	status = print_link(state, linkid, &lbuf);
1830e7801d59Ssowmini 
1831d62bc4baSyz147064 	if (status != DLADM_STATUS_OK)
1832d62bc4baSyz147064 		goto done;
1833e7801d59Ssowmini 
1834e7801d59Ssowmini 	if (!state->ls_parseable && !state->ls_printheader) {
1835e7801d59Ssowmini 		print_header(&state->ls_print);
1836e7801d59Ssowmini 		state->ls_printheader = B_TRUE;
1837e7801d59Ssowmini 	}
1838e7801d59Ssowmini 
1839e7801d59Ssowmini 	dladm_print_output(&state->ls_print, state->ls_parseable,
1840e7801d59Ssowmini 	    dladm_print_field, (void *)&lbuf);
1841d62bc4baSyz147064 
1842d62bc4baSyz147064 done:
1843d62bc4baSyz147064 	state->ls_status = status;
1844d62bc4baSyz147064 	return (DLADM_WALK_CONTINUE);
1845d62bc4baSyz147064 }
1846d62bc4baSyz147064 
1847d62bc4baSyz147064 static int
1848d62bc4baSyz147064 show_link_stats(datalink_id_t linkid, void *arg)
1849d62bc4baSyz147064 {
1850e7801d59Ssowmini 	char			link[DLPI_LINKNAME_MAX];
1851d62bc4baSyz147064 	datalink_class_t	class;
1852e7801d59Ssowmini 	show_state_t		*state = (show_state_t *)arg;
18537c478bd9Sstevel@tonic-gate 	pktsum_t		stats, diff_stats;
1854d62bc4baSyz147064 	dladm_phys_attr_t	dpa;
18556be03d0bSVasumathi Sundaram - Sun Microsystems 	dev_args_t largs;
18567c478bd9Sstevel@tonic-gate 
18577c478bd9Sstevel@tonic-gate 	if (state->ls_firstonly) {
18587c478bd9Sstevel@tonic-gate 		if (state->ls_donefirst)
1859d62bc4baSyz147064 			return (DLADM_WALK_CONTINUE);
18607c478bd9Sstevel@tonic-gate 		state->ls_donefirst = B_TRUE;
18617c478bd9Sstevel@tonic-gate 	} else {
18627c478bd9Sstevel@tonic-gate 		bzero(&state->ls_prevstats, sizeof (state->ls_prevstats));
18637c478bd9Sstevel@tonic-gate 	}
18647c478bd9Sstevel@tonic-gate 
1865d62bc4baSyz147064 	if (dladm_datalink_id2info(linkid, NULL, &class, NULL, link,
1866e7801d59Ssowmini 	    DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) {
1867d62bc4baSyz147064 		return (DLADM_WALK_CONTINUE);
1868d62bc4baSyz147064 	}
1869d62bc4baSyz147064 
1870d62bc4baSyz147064 	if (class == DATALINK_CLASS_PHYS) {
1871d62bc4baSyz147064 		if (dladm_phys_info(linkid, &dpa, DLADM_OPT_ACTIVE) !=
1872d62bc4baSyz147064 		    DLADM_STATUS_OK) {
1873d62bc4baSyz147064 			return (DLADM_WALK_CONTINUE);
1874d62bc4baSyz147064 		}
1875d62bc4baSyz147064 		if (dpa.dp_novanity)
1876d62bc4baSyz147064 			get_mac_stats(dpa.dp_dev, &stats);
1877d62bc4baSyz147064 		else
1878d62bc4baSyz147064 			get_link_stats(link, &stats);
1879d62bc4baSyz147064 	} else {
1880d62bc4baSyz147064 		get_link_stats(link, &stats);
1881d62bc4baSyz147064 	}
18827c478bd9Sstevel@tonic-gate 	stats_diff(&diff_stats, &stats, &state->ls_prevstats);
18837c478bd9Sstevel@tonic-gate 
18846be03d0bSVasumathi Sundaram - Sun Microsystems 	largs.devs_link = link;
18856be03d0bSVasumathi Sundaram - Sun Microsystems 	largs.devs_psum = &diff_stats;
18866be03d0bSVasumathi Sundaram - Sun Microsystems 	dladm_print_output(&state->ls_print, state->ls_parseable,
18876be03d0bSVasumathi Sundaram - Sun Microsystems 	    print_dev_stats, &largs);
18887c478bd9Sstevel@tonic-gate 
18897c478bd9Sstevel@tonic-gate 	state->ls_prevstats = stats;
1890d62bc4baSyz147064 	return (DLADM_WALK_CONTINUE);
18917c478bd9Sstevel@tonic-gate }
18927c478bd9Sstevel@tonic-gate 
1893d62bc4baSyz147064 
1894d62bc4baSyz147064 static dladm_status_t
1895d62bc4baSyz147064 print_aggr_info(show_grp_state_t *state, const char *link,
1896e7801d59Ssowmini     dladm_aggr_grp_attr_t *ginfop)
1897d62bc4baSyz147064 {
1898d62bc4baSyz147064 	char			addr_str[ETHERADDRL * 3];
1899e7801d59Ssowmini 	laggr_fields_buf_t	lbuf;
1900d62bc4baSyz147064 
1901e7801d59Ssowmini 	(void) snprintf(lbuf.laggr_name, sizeof (lbuf.laggr_name),
1902e7801d59Ssowmini 	    "%s", link);
1903e7801d59Ssowmini 
1904e7801d59Ssowmini 	(void) dladm_aggr_policy2str(ginfop->lg_policy,
1905e7801d59Ssowmini 	    lbuf.laggr_policy);
1906d62bc4baSyz147064 
1907d62bc4baSyz147064 	if (ginfop->lg_mac_fixed) {
1908d62bc4baSyz147064 		(void) dladm_aggr_macaddr2str(ginfop->lg_mac, addr_str);
1909e7801d59Ssowmini 		(void) snprintf(lbuf.laggr_addrpolicy,
1910e7801d59Ssowmini 		    sizeof (lbuf.laggr_addrpolicy), "fixed (%s)", addr_str);
1911d62bc4baSyz147064 	} else {
1912e7801d59Ssowmini 		(void) snprintf(lbuf.laggr_addrpolicy,
1913e7801d59Ssowmini 		    sizeof (lbuf.laggr_addrpolicy), "auto");
1914d62bc4baSyz147064 	}
1915d62bc4baSyz147064 
1916d62bc4baSyz147064 
1917e7801d59Ssowmini 	(void) dladm_aggr_lacpmode2str(ginfop->lg_lacp_mode,
1918e7801d59Ssowmini 	    lbuf.laggr_lacpactivity);
1919e7801d59Ssowmini 	(void) dladm_aggr_lacptimer2str(ginfop->lg_lacp_timer,
1920e7801d59Ssowmini 	    lbuf.laggr_lacptimer);
1921e7801d59Ssowmini 	(void) snprintf(lbuf.laggr_flags, sizeof (lbuf.laggr_flags), "%c----",
1922d62bc4baSyz147064 	    ginfop->lg_force ? 'f' : '-');
1923e7801d59Ssowmini 
1924e7801d59Ssowmini 	if (!state->gs_parseable && !state->gs_printheader) {
1925e7801d59Ssowmini 		print_header(&state->gs_print);
1926e7801d59Ssowmini 		state->gs_printheader = B_TRUE;
1927d62bc4baSyz147064 	}
1928d62bc4baSyz147064 
1929e7801d59Ssowmini 	dladm_print_output(&state->gs_print, state->gs_parseable,
1930e7801d59Ssowmini 	    dladm_print_field, (void *)&lbuf);
1931e7801d59Ssowmini 
1932d62bc4baSyz147064 	return (DLADM_STATUS_OK);
1933d62bc4baSyz147064 }
1934d62bc4baSyz147064 
1935e7801d59Ssowmini static char *
1936e7801d59Ssowmini print_xaggr_callback(print_field_t *pf, void *arg)
1937d62bc4baSyz147064 {
1938e7801d59Ssowmini 	const laggr_args_t 	*l = arg;
1939e7801d59Ssowmini 	int 			portnum;
1940e7801d59Ssowmini 	static char 		buf[DLADM_STRSIZE];
1941e7801d59Ssowmini 	boolean_t		is_port = (l->laggr_lport >= 0);
1942e7801d59Ssowmini 	dladm_aggr_port_attr_t *portp;
1943d62bc4baSyz147064 	dladm_phys_attr_t	dpa;
1944e7801d59Ssowmini 	dladm_status_t		*stat, status;
1945d62bc4baSyz147064 
1946e7801d59Ssowmini 	stat = l->laggr_status;
1947e7801d59Ssowmini 	*stat = DLADM_STATUS_OK;
1948d62bc4baSyz147064 
1949e7801d59Ssowmini 	if (is_port) {
1950e7801d59Ssowmini 		portnum = l->laggr_lport;
1951e7801d59Ssowmini 		portp = &(l->laggr_ginfop->lg_ports[portnum]);
1952e7801d59Ssowmini 		if ((status = dladm_datalink_id2info(portp->lp_linkid,
1953e7801d59Ssowmini 		    NULL, NULL, NULL, buf, sizeof (buf))) !=
1954e7801d59Ssowmini 		    DLADM_STATUS_OK) {
1955e7801d59Ssowmini 			goto err;
1956d62bc4baSyz147064 		}
1957d62bc4baSyz147064 		if ((status = dladm_phys_info(portp->lp_linkid, &dpa,
1958d62bc4baSyz147064 		    DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) {
1959e7801d59Ssowmini 			goto err;
1960e7801d59Ssowmini 		}
1961d62bc4baSyz147064 	}
1962d62bc4baSyz147064 
1963e7801d59Ssowmini 	switch (pf->pf_index) {
1964e7801d59Ssowmini 	case AGGR_X_LINK:
1965e7801d59Ssowmini 		(void) snprintf(buf, sizeof (buf), "%s",
1966e7801d59Ssowmini 		    (is_port && !l->laggr_parseable ? " " : l->laggr_link));
1967e7801d59Ssowmini 		break;
1968e7801d59Ssowmini 	case AGGR_X_PORT:
1969e7801d59Ssowmini 		if (is_port)
1970e7801d59Ssowmini 			break;
1971e7801d59Ssowmini 		return ("");
1972e7801d59Ssowmini 		break;
1973d62bc4baSyz147064 
1974e7801d59Ssowmini 	case AGGR_X_SPEED:
1975e7801d59Ssowmini 		if (is_port) {
1976e7801d59Ssowmini 			(void) snprintf(buf, sizeof (buf), "%uMb",
1977e7801d59Ssowmini 			    (uint_t)((get_ifspeed(dpa.dp_dev,
1978e7801d59Ssowmini 			    B_FALSE)) / 1000000ull));
1979e7801d59Ssowmini 		} else {
1980e7801d59Ssowmini 			(void) snprintf(buf, sizeof (buf), "%uMb",
1981e7801d59Ssowmini 			    (uint_t)((get_ifspeed(l->laggr_link,
1982e7801d59Ssowmini 			    B_TRUE)) / 1000000ull));
1983e7801d59Ssowmini 		}
1984e7801d59Ssowmini 		break;
1985e7801d59Ssowmini 
1986e7801d59Ssowmini 	case AGGR_X_DUPLEX:
1987e7801d59Ssowmini 		if (is_port)
1988e7801d59Ssowmini 			(void) get_linkduplex(dpa.dp_dev, B_FALSE, buf);
1989d62bc4baSyz147064 		else
1990e7801d59Ssowmini 			(void) get_linkduplex(l->laggr_link, B_TRUE, buf);
1991e7801d59Ssowmini 		break;
1992d62bc4baSyz147064 
1993e7801d59Ssowmini 	case AGGR_X_STATE:
19941a1811a0Svs226613 		if (is_port)
19951a1811a0Svs226613 			(void) get_linkstate(dpa.dp_dev,  B_FALSE, buf);
19961a1811a0Svs226613 		else
19971a1811a0Svs226613 			(void) get_linkstate(l->laggr_link, B_TRUE, buf);
1998e7801d59Ssowmini 		break;
1999e7801d59Ssowmini 	case AGGR_X_ADDRESS:
2000e7801d59Ssowmini 		(void) dladm_aggr_macaddr2str(
2001e7801d59Ssowmini 		    (is_port ? portp->lp_mac : l->laggr_ginfop->lg_mac),
2002e7801d59Ssowmini 		    buf);
2003e7801d59Ssowmini 		break;
2004e7801d59Ssowmini 	case AGGR_X_PORTSTATE:
20050d365605Sschuster 		if (is_port)
20060d365605Sschuster 			(void) dladm_aggr_portstate2str(
20070d365605Sschuster 			    portp->lp_state, buf);
20080d365605Sschuster 		else
20090d365605Sschuster 			return ("");
2010e7801d59Ssowmini 		break;
2011e7801d59Ssowmini 	}
2012e7801d59Ssowmini 	return (buf);
2013e7801d59Ssowmini 
2014e7801d59Ssowmini err:
2015e7801d59Ssowmini 	*stat = status;
2016e7801d59Ssowmini 	buf[0] = '\0';
2017e7801d59Ssowmini 	return (buf);
2018e7801d59Ssowmini }
2019e7801d59Ssowmini 
2020e7801d59Ssowmini static dladm_status_t
2021e7801d59Ssowmini print_aggr_extended(show_grp_state_t *state, const char *link,
2022e7801d59Ssowmini     dladm_aggr_grp_attr_t *ginfop)
2023e7801d59Ssowmini {
2024e7801d59Ssowmini 	int			i;
2025e7801d59Ssowmini 	dladm_status_t		status;
2026e7801d59Ssowmini 	laggr_args_t		largs;
2027e7801d59Ssowmini 
2028e7801d59Ssowmini 	if (!state->gs_parseable && !state->gs_printheader) {
2029e7801d59Ssowmini 		print_header(&state->gs_print);
2030e7801d59Ssowmini 		state->gs_printheader = B_TRUE;
2031e7801d59Ssowmini 	}
2032e7801d59Ssowmini 
2033e7801d59Ssowmini 	largs.laggr_lport = -1;
2034e7801d59Ssowmini 	largs.laggr_link = link;
2035e7801d59Ssowmini 	largs.laggr_ginfop = ginfop;
2036e7801d59Ssowmini 	largs.laggr_status = &status;
2037e7801d59Ssowmini 	largs.laggr_parseable = state->gs_parseable;
2038e7801d59Ssowmini 
2039e7801d59Ssowmini 	dladm_print_output(&state->gs_print, state->gs_parseable,
2040e7801d59Ssowmini 	    print_xaggr_callback, &largs);
2041e7801d59Ssowmini 
2042e7801d59Ssowmini 	if (status != DLADM_STATUS_OK)
2043e7801d59Ssowmini 		goto done;
2044e7801d59Ssowmini 
2045e7801d59Ssowmini 	for (i = 0; i < ginfop->lg_nports; i++) {
2046e7801d59Ssowmini 		largs.laggr_lport = i;
2047e7801d59Ssowmini 		dladm_print_output(&state->gs_print, state->gs_parseable,
2048e7801d59Ssowmini 		    print_xaggr_callback, &largs);
2049e7801d59Ssowmini 		if (status != DLADM_STATUS_OK)
2050e7801d59Ssowmini 			goto done;
2051d62bc4baSyz147064 	}
2052d62bc4baSyz147064 
2053d62bc4baSyz147064 	status = DLADM_STATUS_OK;
2054d62bc4baSyz147064 done:
2055d62bc4baSyz147064 	return (status);
2056d62bc4baSyz147064 }
2057d62bc4baSyz147064 
2058e7801d59Ssowmini 
2059e7801d59Ssowmini static char *
2060e7801d59Ssowmini print_lacp_callback(print_field_t *pf, void *arg)
2061e7801d59Ssowmini {
2062e7801d59Ssowmini 	const laggr_args_t	*l = arg;
2063e7801d59Ssowmini 	int			portnum;
2064e7801d59Ssowmini 	static char		buf[DLADM_STRSIZE];
2065e7801d59Ssowmini 	boolean_t		is_port = (l->laggr_lport >= 0);
2066e7801d59Ssowmini 	dladm_aggr_port_attr_t	*portp;
2067e7801d59Ssowmini 	dladm_status_t		*stat, status;
2068e7801d59Ssowmini 	aggr_lacp_state_t	*lstate;
2069e7801d59Ssowmini 
2070e7801d59Ssowmini 	if (!is_port) {
2071e7801d59Ssowmini 		return (NULL); /* cannot happen! */
2072e7801d59Ssowmini 	}
2073e7801d59Ssowmini 
2074e7801d59Ssowmini 	stat = l->laggr_status;
2075e7801d59Ssowmini 
2076e7801d59Ssowmini 	portnum = l->laggr_lport;
2077e7801d59Ssowmini 	portp = &(l->laggr_ginfop->lg_ports[portnum]);
2078e7801d59Ssowmini 	if ((status = dladm_datalink_id2info(portp->lp_linkid,
2079e7801d59Ssowmini 	    NULL, NULL, NULL, buf, sizeof (buf))) != DLADM_STATUS_OK) {
2080e7801d59Ssowmini 			goto err;
2081e7801d59Ssowmini 	}
2082e7801d59Ssowmini 	lstate = &(portp->lp_lacp_state);
2083e7801d59Ssowmini 
2084e7801d59Ssowmini 	switch (pf->pf_index) {
2085e7801d59Ssowmini 	case AGGR_L_LINK:
2086e7801d59Ssowmini 		(void) snprintf(buf, sizeof (buf), "%s",
2087e7801d59Ssowmini 		    (portnum > 0 ? "" : l->laggr_link));
2088e7801d59Ssowmini 		break;
2089e7801d59Ssowmini 
2090e7801d59Ssowmini 	case AGGR_L_PORT:
2091e7801d59Ssowmini 		break;
2092e7801d59Ssowmini 
2093e7801d59Ssowmini 	case AGGR_L_AGGREGATABLE:
2094e7801d59Ssowmini 		(void) snprintf(buf, sizeof (buf), "%s",
2095e7801d59Ssowmini 		    (lstate->bit.aggregation ? "yes" : "no"));
2096e7801d59Ssowmini 		break;
2097e7801d59Ssowmini 
2098e7801d59Ssowmini 	case AGGR_L_SYNC:
2099e7801d59Ssowmini 		(void) snprintf(buf, sizeof (buf), "%s",
2100e7801d59Ssowmini 		    (lstate->bit.sync ? "yes" : "no"));
2101e7801d59Ssowmini 		break;
2102e7801d59Ssowmini 
2103e7801d59Ssowmini 	case AGGR_L_COLL:
2104e7801d59Ssowmini 		(void) snprintf(buf, sizeof (buf), "%s",
2105e7801d59Ssowmini 		    (lstate->bit.collecting ? "yes" : "no"));
2106e7801d59Ssowmini 		break;
2107e7801d59Ssowmini 
2108e7801d59Ssowmini 	case AGGR_L_DIST:
2109e7801d59Ssowmini 		(void) snprintf(buf, sizeof (buf), "%s",
2110e7801d59Ssowmini 		    (lstate->bit.distributing ? "yes" : "no"));
2111e7801d59Ssowmini 		break;
2112e7801d59Ssowmini 
2113e7801d59Ssowmini 	case AGGR_L_DEFAULTED:
2114e7801d59Ssowmini 		(void) snprintf(buf, sizeof (buf), "%s",
2115e7801d59Ssowmini 		    (lstate->bit.defaulted ? "yes" : "no"));
2116e7801d59Ssowmini 		break;
2117e7801d59Ssowmini 
2118e7801d59Ssowmini 	case AGGR_L_EXPIRED:
2119e7801d59Ssowmini 		(void) snprintf(buf, sizeof (buf), "%s",
2120e7801d59Ssowmini 		    (lstate->bit.expired ? "yes" : "no"));
2121e7801d59Ssowmini 		break;
2122e7801d59Ssowmini 	}
2123e7801d59Ssowmini 
2124e7801d59Ssowmini 	*stat = DLADM_STATUS_OK;
2125e7801d59Ssowmini 	return (buf);
2126e7801d59Ssowmini 
2127e7801d59Ssowmini err:
2128e7801d59Ssowmini 	*stat = status;
2129e7801d59Ssowmini 	buf[0] = '\0';
2130e7801d59Ssowmini 	return (buf);
2131e7801d59Ssowmini }
2132e7801d59Ssowmini 
2133d62bc4baSyz147064 static dladm_status_t
2134d62bc4baSyz147064 print_aggr_lacp(show_grp_state_t *state, const char *link,
2135e7801d59Ssowmini     dladm_aggr_grp_attr_t *ginfop)
2136d62bc4baSyz147064 {
2137d62bc4baSyz147064 	int		i;
2138d62bc4baSyz147064 	dladm_status_t	status;
2139e7801d59Ssowmini 	laggr_args_t	largs;
2140d62bc4baSyz147064 
2141e7801d59Ssowmini 	if (!state->gs_parseable && !state->gs_printheader) {
2142e7801d59Ssowmini 		print_header(&state->gs_print);
2143e7801d59Ssowmini 		state->gs_printheader = B_TRUE;
2144d62bc4baSyz147064 	}
2145d62bc4baSyz147064 
2146e7801d59Ssowmini 	largs.laggr_link = link;
2147e7801d59Ssowmini 	largs.laggr_ginfop = ginfop;
2148e7801d59Ssowmini 	largs.laggr_status = &status;
2149d62bc4baSyz147064 
2150e7801d59Ssowmini 	for (i = 0; i < ginfop->lg_nports; i++) {
2151e7801d59Ssowmini 		largs.laggr_lport = i;
2152e7801d59Ssowmini 		dladm_print_output(&state->gs_print, state->gs_parseable,
2153e7801d59Ssowmini 		    print_lacp_callback, &largs);
2154d62bc4baSyz147064 		if (status != DLADM_STATUS_OK)
2155d62bc4baSyz147064 			goto done;
2156d62bc4baSyz147064 	}
2157d62bc4baSyz147064 
2158d62bc4baSyz147064 	status = DLADM_STATUS_OK;
2159d62bc4baSyz147064 done:
2160d62bc4baSyz147064 	return (status);
2161d62bc4baSyz147064 }
2162d62bc4baSyz147064 
2163e7801d59Ssowmini static char *
2164e7801d59Ssowmini print_aggr_stats_callback(print_field_t *pf, void *arg)
2165e7801d59Ssowmini {
2166e7801d59Ssowmini 	const laggr_args_t	*l = arg;
2167e7801d59Ssowmini 	int 			portnum;
2168e7801d59Ssowmini 	static char		buf[DLADM_STRSIZE];
2169e7801d59Ssowmini 	boolean_t		is_port = (l->laggr_lport >= 0);
2170e7801d59Ssowmini 	dladm_aggr_port_attr_t	*portp;
2171e7801d59Ssowmini 	dladm_phys_attr_t	dpa;
2172e7801d59Ssowmini 	dladm_status_t		*stat, status;
2173e7801d59Ssowmini 	pktsum_t		port_stat, diff_stats;
2174e7801d59Ssowmini 
2175e7801d59Ssowmini 	stat = l->laggr_status;
2176e7801d59Ssowmini 	*stat = DLADM_STATUS_OK;
2177e7801d59Ssowmini 
2178e7801d59Ssowmini 	if (is_port) {
2179e7801d59Ssowmini 		portnum = l->laggr_lport;
2180e7801d59Ssowmini 		portp = &(l->laggr_ginfop->lg_ports[portnum]);
2181e7801d59Ssowmini 		if ((status = dladm_phys_info(portp->lp_linkid, &dpa,
2182e7801d59Ssowmini 		    DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) {
2183e7801d59Ssowmini 			goto err;
2184e7801d59Ssowmini 		}
2185e7801d59Ssowmini 
2186e7801d59Ssowmini 		get_mac_stats(dpa.dp_dev, &port_stat);
2187e7801d59Ssowmini 
2188e7801d59Ssowmini 		if ((status = dladm_datalink_id2info(portp->lp_linkid, NULL,
2189e7801d59Ssowmini 		    NULL, NULL, buf, sizeof (buf))) != DLADM_STATUS_OK) {
2190e7801d59Ssowmini 			goto err;
2191e7801d59Ssowmini 		}
2192e7801d59Ssowmini 
2193e7801d59Ssowmini 		stats_diff(&diff_stats, &port_stat, l->laggr_prevstats);
2194e7801d59Ssowmini 	}
2195e7801d59Ssowmini 
2196e7801d59Ssowmini 	switch (pf->pf_index) {
2197e7801d59Ssowmini 	case AGGR_S_LINK:
2198e7801d59Ssowmini 		(void) snprintf(buf, sizeof (buf), "%s",
2199e7801d59Ssowmini 		    (is_port ? "" : l->laggr_link));
2200e7801d59Ssowmini 		break;
2201e7801d59Ssowmini 	case AGGR_S_PORT:
2202e7801d59Ssowmini 		if (is_port)
2203e7801d59Ssowmini 			break;
22040d365605Sschuster 		return ("");
2205e7801d59Ssowmini 		break;
2206e7801d59Ssowmini 
2207e7801d59Ssowmini 	case AGGR_S_IPKTS:
2208e7801d59Ssowmini 		if (is_port) {
2209e7801d59Ssowmini 			(void) snprintf(buf, sizeof (buf), "%llu",
2210e7801d59Ssowmini 			    diff_stats.ipackets);
2211e7801d59Ssowmini 		} else {
2212e7801d59Ssowmini 			(void) snprintf(buf, sizeof (buf), "%llu",
2213e7801d59Ssowmini 			    l->laggr_pktsumtot->ipackets);
2214e7801d59Ssowmini 		}
2215e7801d59Ssowmini 		break;
2216e7801d59Ssowmini 
2217e7801d59Ssowmini 	case AGGR_S_RBYTES:
2218e7801d59Ssowmini 		if (is_port) {
2219e7801d59Ssowmini 			(void) snprintf(buf, sizeof (buf), "%llu",
2220e7801d59Ssowmini 			    diff_stats.rbytes);
2221e7801d59Ssowmini 		} else {
2222e7801d59Ssowmini 			(void) snprintf(buf, sizeof (buf), "%llu",
2223e7801d59Ssowmini 			    l->laggr_pktsumtot->rbytes);
2224e7801d59Ssowmini 		}
2225e7801d59Ssowmini 		break;
2226e7801d59Ssowmini 
2227e7801d59Ssowmini 	case AGGR_S_OPKTS:
2228e7801d59Ssowmini 		if (is_port) {
2229e7801d59Ssowmini 			(void) snprintf(buf, sizeof (buf), "%llu",
2230e7801d59Ssowmini 			    diff_stats.opackets);
2231e7801d59Ssowmini 		} else {
2232e7801d59Ssowmini 			(void) snprintf(buf, sizeof (buf), "%llu",
2233e7801d59Ssowmini 			    l->laggr_pktsumtot->opackets);
2234e7801d59Ssowmini 		}
2235e7801d59Ssowmini 		break;
2236e7801d59Ssowmini 	case AGGR_S_OBYTES:
2237e7801d59Ssowmini 		if (is_port) {
2238e7801d59Ssowmini 			(void) snprintf(buf, sizeof (buf), "%llu",
2239e7801d59Ssowmini 			    diff_stats.obytes);
2240e7801d59Ssowmini 		} else {
2241e7801d59Ssowmini 			(void) snprintf(buf, sizeof (buf), "%llu",
2242e7801d59Ssowmini 			    l->laggr_pktsumtot->obytes);
2243e7801d59Ssowmini 
2244e7801d59Ssowmini 		}
2245e7801d59Ssowmini 		break;
2246e7801d59Ssowmini 
2247e7801d59Ssowmini 	case AGGR_S_IPKTDIST:
2248e7801d59Ssowmini 		if (is_port) {
2249e7801d59Ssowmini 			(void) snprintf(buf, sizeof (buf), "%-6.1f",
2250e7801d59Ssowmini 			    (double)diff_stats.opackets/
2251e7801d59Ssowmini 			    (double)l->laggr_pktsumtot->ipackets * 100);
2252e7801d59Ssowmini 		} else {
22530d365605Sschuster 			return ("");
2254e7801d59Ssowmini 		}
2255e7801d59Ssowmini 		break;
2256e7801d59Ssowmini 	case AGGR_S_OPKTDIST:
2257e7801d59Ssowmini 		if (is_port) {
2258e7801d59Ssowmini 			(void) snprintf(buf, sizeof (buf), "%-6.1f",
2259e7801d59Ssowmini 			    (double)diff_stats.opackets/
2260e7801d59Ssowmini 			    (double)l->laggr_pktsumtot->opackets * 100);
2261e7801d59Ssowmini 		} else {
22620d365605Sschuster 			return ("");
2263e7801d59Ssowmini 		}
2264e7801d59Ssowmini 		break;
2265e7801d59Ssowmini 	}
2266e7801d59Ssowmini 	return (buf);
2267e7801d59Ssowmini 
2268e7801d59Ssowmini err:
2269e7801d59Ssowmini 	*stat = status;
2270e7801d59Ssowmini 	buf[0] = '\0';
2271e7801d59Ssowmini 	return (buf);
2272e7801d59Ssowmini }
2273e7801d59Ssowmini 
2274d62bc4baSyz147064 static dladm_status_t
2275d62bc4baSyz147064 print_aggr_stats(show_grp_state_t *state, const char *link,
2276e7801d59Ssowmini     dladm_aggr_grp_attr_t *ginfop)
2277d62bc4baSyz147064 {
2278d62bc4baSyz147064 	dladm_phys_attr_t	dpa;
2279d62bc4baSyz147064 	dladm_aggr_port_attr_t	*portp;
2280d62bc4baSyz147064 	pktsum_t		pktsumtot, port_stat;
2281d62bc4baSyz147064 	dladm_status_t		status;
2282d62bc4baSyz147064 	int			i;
2283e7801d59Ssowmini 	laggr_args_t		largs;
22847c478bd9Sstevel@tonic-gate 
22857c478bd9Sstevel@tonic-gate 	/* sum the ports statistics */
22867c478bd9Sstevel@tonic-gate 	bzero(&pktsumtot, sizeof (pktsumtot));
2287d62bc4baSyz147064 
2288d62bc4baSyz147064 	for (i = 0; i < ginfop->lg_nports; i++) {
2289d62bc4baSyz147064 
2290d62bc4baSyz147064 		portp = &(ginfop->lg_ports[i]);
2291d62bc4baSyz147064 		if ((status = dladm_phys_info(portp->lp_linkid, &dpa,
2292d62bc4baSyz147064 		    DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) {
2293d62bc4baSyz147064 			goto done;
22947c478bd9Sstevel@tonic-gate 		}
22957c478bd9Sstevel@tonic-gate 
2296d62bc4baSyz147064 		get_mac_stats(dpa.dp_dev, &port_stat);
2297d62bc4baSyz147064 		stats_total(&pktsumtot, &port_stat, &state->gs_prevstats[i]);
22987c478bd9Sstevel@tonic-gate 	}
22997c478bd9Sstevel@tonic-gate 
2300e7801d59Ssowmini 	if (!state->gs_parseable && !state->gs_printheader) {
2301e7801d59Ssowmini 		print_header(&state->gs_print);
2302e7801d59Ssowmini 		state->gs_printheader = B_TRUE;
2303e7801d59Ssowmini 	}
2304e7801d59Ssowmini 
2305e7801d59Ssowmini 	largs.laggr_lport = -1;
2306e7801d59Ssowmini 	largs.laggr_link = link;
2307e7801d59Ssowmini 	largs.laggr_ginfop = ginfop;
2308e7801d59Ssowmini 	largs.laggr_status = &status;
2309e7801d59Ssowmini 	largs.laggr_pktsumtot = &pktsumtot;
2310e7801d59Ssowmini 
2311e7801d59Ssowmini 	dladm_print_output(&state->gs_print, state->gs_parseable,
2312e7801d59Ssowmini 	    print_aggr_stats_callback, &largs);
2313e7801d59Ssowmini 
2314e7801d59Ssowmini 	if (status != DLADM_STATUS_OK)
2315e7801d59Ssowmini 		goto done;
2316d62bc4baSyz147064 
2317d62bc4baSyz147064 	for (i = 0; i < ginfop->lg_nports; i++) {
2318e7801d59Ssowmini 		largs.laggr_lport = i;
2319e7801d59Ssowmini 		largs.laggr_prevstats = &state->gs_prevstats[i];
2320e7801d59Ssowmini 		dladm_print_output(&state->gs_print, state->gs_parseable,
2321e7801d59Ssowmini 		    print_aggr_stats_callback, &largs);
2322e7801d59Ssowmini 		if (status != DLADM_STATUS_OK)
2323d62bc4baSyz147064 			goto done;
2324d62bc4baSyz147064 	}
2325d62bc4baSyz147064 
2326d62bc4baSyz147064 	status = DLADM_STATUS_OK;
2327d62bc4baSyz147064 done:
2328d62bc4baSyz147064 	return (status);
2329d62bc4baSyz147064 }
2330d62bc4baSyz147064 
2331d62bc4baSyz147064 static dladm_status_t
2332e7801d59Ssowmini print_aggr(show_grp_state_t *state, datalink_id_t linkid)
2333d62bc4baSyz147064 {
2334d62bc4baSyz147064 	char			link[MAXLINKNAMELEN];
2335d62bc4baSyz147064 	dladm_aggr_grp_attr_t	ginfo;
2336d62bc4baSyz147064 	uint32_t		flags;
2337d62bc4baSyz147064 	dladm_status_t		status;
2338d62bc4baSyz147064 
23395f5c9f54SAnurag S. Maskey 	bzero(&ginfo, sizeof (dladm_aggr_grp_attr_t));
2340d62bc4baSyz147064 	if ((status = dladm_datalink_id2info(linkid, &flags, NULL, NULL, link,
2341e7801d59Ssowmini 	    MAXLINKNAMELEN)) != DLADM_STATUS_OK) {
2342d62bc4baSyz147064 		return (status);
2343d62bc4baSyz147064 	}
2344d62bc4baSyz147064 
2345d62bc4baSyz147064 	if (!(state->gs_flags & flags))
2346d62bc4baSyz147064 		return (DLADM_STATUS_NOTFOUND);
2347d62bc4baSyz147064 
2348d62bc4baSyz147064 	status = dladm_aggr_info(linkid, &ginfo, state->gs_flags);
2349d62bc4baSyz147064 	if (status != DLADM_STATUS_OK)
2350d62bc4baSyz147064 		return (status);
2351d62bc4baSyz147064 
2352d62bc4baSyz147064 	if (state->gs_lacp)
2353e7801d59Ssowmini 		status = print_aggr_lacp(state, link, &ginfo);
2354d62bc4baSyz147064 	else if (state->gs_extended)
2355e7801d59Ssowmini 		status = print_aggr_extended(state, link, &ginfo);
2356d62bc4baSyz147064 	else if (state->gs_stats)
2357e7801d59Ssowmini 		status = print_aggr_stats(state, link, &ginfo);
2358e7801d59Ssowmini 	else {
2359e7801d59Ssowmini 		status = print_aggr_info(state, link, &ginfo);
2360e7801d59Ssowmini 	}
2361d62bc4baSyz147064 
2362d62bc4baSyz147064 done:
2363d62bc4baSyz147064 	free(ginfo.lg_ports);
2364d62bc4baSyz147064 	return (status);
2365d62bc4baSyz147064 }
2366d62bc4baSyz147064 
2367d62bc4baSyz147064 static int
2368d62bc4baSyz147064 show_aggr(datalink_id_t linkid, void *arg)
2369d62bc4baSyz147064 {
2370d62bc4baSyz147064 	show_grp_state_t	*state = arg;
2371d62bc4baSyz147064 	dladm_status_t		status;
2372d62bc4baSyz147064 
2373e7801d59Ssowmini 	status = print_aggr(state, linkid);
2374d62bc4baSyz147064 	if (status != DLADM_STATUS_OK)
2375d62bc4baSyz147064 		goto done;
2376d62bc4baSyz147064 
2377d62bc4baSyz147064 done:
2378d62bc4baSyz147064 	state->gs_status = status;
2379d62bc4baSyz147064 	return (DLADM_WALK_CONTINUE);
23807c478bd9Sstevel@tonic-gate }
23817c478bd9Sstevel@tonic-gate 
2382e7801d59Ssowmini static char *
2383e7801d59Ssowmini print_dev(print_field_t *pf, void *arg)
23847c478bd9Sstevel@tonic-gate {
2385e7801d59Ssowmini 	const char *dev = arg;
2386e7801d59Ssowmini 	static char buf[DLADM_STRSIZE];
23877c478bd9Sstevel@tonic-gate 
2388e7801d59Ssowmini 	switch (pf->pf_index) {
2389e7801d59Ssowmini 	case DEV_LINK:
2390e7801d59Ssowmini 		(void) snprintf(buf, sizeof (buf), "%s", dev);
23917c478bd9Sstevel@tonic-gate 		break;
2392e7801d59Ssowmini 	case DEV_STATE:
2393e7801d59Ssowmini 		(void) get_linkstate(dev, B_FALSE, buf);
2394e7801d59Ssowmini 		break;
2395e7801d59Ssowmini 	case DEV_SPEED:
2396e7801d59Ssowmini 		(void) snprintf(buf, sizeof (buf), "%uMb",
2397e7801d59Ssowmini 		    (unsigned int)(get_ifspeed(dev, B_FALSE) / 1000000ull));
2398e7801d59Ssowmini 		break;
2399e7801d59Ssowmini 	case DEV_DUPLEX:
2400e7801d59Ssowmini 		(void) get_linkduplex(dev, B_FALSE, buf);
24017c478bd9Sstevel@tonic-gate 		break;
24027c478bd9Sstevel@tonic-gate 	default:
2403e7801d59Ssowmini 		die("invalid index '%d'", pf->pf_index);
2404e7801d59Ssowmini 		break;
24057c478bd9Sstevel@tonic-gate 	}
2406e7801d59Ssowmini 	return (buf);
24077c478bd9Sstevel@tonic-gate }
24087c478bd9Sstevel@tonic-gate 
2409d62bc4baSyz147064 static int
2410d62bc4baSyz147064 show_dev(const char *dev, void *arg)
24117c478bd9Sstevel@tonic-gate {
2412d62bc4baSyz147064 	show_state_t	*state = arg;
24137c478bd9Sstevel@tonic-gate 
2414e7801d59Ssowmini 	if (!state->ls_parseable && !state->ls_printheader) {
2415e7801d59Ssowmini 		print_header(&state->ls_print);
2416e7801d59Ssowmini 		state->ls_printheader = B_TRUE;
24177c478bd9Sstevel@tonic-gate 	}
24187c478bd9Sstevel@tonic-gate 
2419e7801d59Ssowmini 	dladm_print_output(&state->ls_print, state->ls_parseable,
2420e7801d59Ssowmini 	    print_dev, (void *)dev);
2421d62bc4baSyz147064 
2422d62bc4baSyz147064 	return (DLADM_WALK_CONTINUE);
2423d62bc4baSyz147064 }
2424d62bc4baSyz147064 
2425e7801d59Ssowmini static char *
2426e7801d59Ssowmini print_dev_stats(print_field_t *pf, void *arg)
2427e7801d59Ssowmini {
2428e7801d59Ssowmini 	dev_args_t *dargs = arg;
2429e7801d59Ssowmini 	pktsum_t *diff_stats = dargs->devs_psum;
2430e7801d59Ssowmini 	static char buf[DLADM_STRSIZE];
2431e7801d59Ssowmini 
2432e7801d59Ssowmini 	switch (pf->pf_index) {
2433e7801d59Ssowmini 	case DEVS_LINK:
2434e7801d59Ssowmini 		(void) snprintf(buf, sizeof (buf), "%s", dargs->devs_link);
2435e7801d59Ssowmini 		break;
2436e7801d59Ssowmini 	case DEVS_IPKTS:
2437e7801d59Ssowmini 		(void) snprintf(buf, sizeof (buf), "%llu",
2438e7801d59Ssowmini 		    diff_stats->ipackets);
2439e7801d59Ssowmini 		break;
2440e7801d59Ssowmini 	case DEVS_RBYTES:
2441e7801d59Ssowmini 		(void) snprintf(buf, sizeof (buf), "%llu",
2442e7801d59Ssowmini 		    diff_stats->rbytes);
2443e7801d59Ssowmini 		break;
2444e7801d59Ssowmini 	case DEVS_IERRORS:
2445e7801d59Ssowmini 		(void) snprintf(buf, sizeof (buf), "%u",
2446e7801d59Ssowmini 		    diff_stats->ierrors);
2447e7801d59Ssowmini 		break;
2448e7801d59Ssowmini 	case DEVS_OPKTS:
2449e7801d59Ssowmini 		(void) snprintf(buf, sizeof (buf), "%llu",
2450e7801d59Ssowmini 		    diff_stats->opackets);
2451e7801d59Ssowmini 		break;
2452e7801d59Ssowmini 	case DEVS_OBYTES:
2453e7801d59Ssowmini 		(void) snprintf(buf, sizeof (buf), "%llu",
2454e7801d59Ssowmini 		    diff_stats->obytes);
2455e7801d59Ssowmini 		break;
2456e7801d59Ssowmini 	case DEVS_OERRORS:
2457e7801d59Ssowmini 		(void) snprintf(buf, sizeof (buf), "%u",
2458e7801d59Ssowmini 		    diff_stats->oerrors);
2459e7801d59Ssowmini 		break;
2460e7801d59Ssowmini 	default:
2461e7801d59Ssowmini 		die("invalid input");
2462e7801d59Ssowmini 		break;
2463e7801d59Ssowmini 	}
2464e7801d59Ssowmini 	return (buf);
2465e7801d59Ssowmini }
2466e7801d59Ssowmini 
2467d62bc4baSyz147064 static int
2468d62bc4baSyz147064 show_dev_stats(const char *dev, void *arg)
24697c478bd9Sstevel@tonic-gate {
2470d62bc4baSyz147064 	show_state_t *state = arg;
24717c478bd9Sstevel@tonic-gate 	pktsum_t stats, diff_stats;
2472e7801d59Ssowmini 	dev_args_t dargs;
24737c478bd9Sstevel@tonic-gate 
2474d62bc4baSyz147064 	if (state->ls_firstonly) {
2475d62bc4baSyz147064 		if (state->ls_donefirst)
2476d62bc4baSyz147064 			return (DLADM_WALK_CONTINUE);
2477d62bc4baSyz147064 		state->ls_donefirst = B_TRUE;
24787c478bd9Sstevel@tonic-gate 	} else {
2479d62bc4baSyz147064 		bzero(&state->ls_prevstats, sizeof (state->ls_prevstats));
24807c478bd9Sstevel@tonic-gate 	}
24817c478bd9Sstevel@tonic-gate 
2482ba2e4443Sseb 	get_mac_stats(dev, &stats);
2483d62bc4baSyz147064 	stats_diff(&diff_stats, &stats, &state->ls_prevstats);
24847c478bd9Sstevel@tonic-gate 
2485e7801d59Ssowmini 	dargs.devs_link = (char *)dev;
2486e7801d59Ssowmini 	dargs.devs_psum = &diff_stats;
2487e7801d59Ssowmini 	dladm_print_output(&state->ls_print, state->ls_parseable,
2488e7801d59Ssowmini 	    print_dev_stats, &dargs);
24897c478bd9Sstevel@tonic-gate 
2490d62bc4baSyz147064 	state->ls_prevstats = stats;
2491d62bc4baSyz147064 	return (DLADM_WALK_CONTINUE);
24927c478bd9Sstevel@tonic-gate }
24937c478bd9Sstevel@tonic-gate 
24947c478bd9Sstevel@tonic-gate static void
24958d5c46e6Sam223141 do_show_link(int argc, char *argv[], const char *use)
24967c478bd9Sstevel@tonic-gate {
24977c478bd9Sstevel@tonic-gate 	int		option;
24987c478bd9Sstevel@tonic-gate 	boolean_t	s_arg = B_FALSE;
24997c478bd9Sstevel@tonic-gate 	boolean_t	i_arg = B_FALSE;
2500d62bc4baSyz147064 	uint32_t	flags = DLADM_OPT_ACTIVE;
2501d62bc4baSyz147064 	boolean_t	p_arg = B_FALSE;
2502d62bc4baSyz147064 	datalink_id_t	linkid = DATALINK_ALL_LINKID;
250333343a97Smeem 	int		interval = 0;
2504d62bc4baSyz147064 	show_state_t	state;
2505d62bc4baSyz147064 	dladm_status_t	status;
2506e7801d59Ssowmini 	boolean_t	o_arg = B_FALSE;
2507e7801d59Ssowmini 	char		*fields_str = NULL;
2508e7801d59Ssowmini 	print_field_t	**fields;
2509e7801d59Ssowmini 	uint_t		nfields;
2510e7801d59Ssowmini 	char		*all_active_fields = "link,class,mtu,state,over";
2511e7801d59Ssowmini 	char		*all_inactive_fields = "link,class,over";
25126be03d0bSVasumathi Sundaram - Sun Microsystems 	char		*allstat_fields =
25136be03d0bSVasumathi Sundaram - Sun Microsystems 	    "link,ipackets,rbytes,ierrors,opackets,obytes,oerrors";
2514e7801d59Ssowmini 
2515e7801d59Ssowmini 	bzero(&state, sizeof (state));
25167c478bd9Sstevel@tonic-gate 
25177c478bd9Sstevel@tonic-gate 	opterr = 0;
2518e7801d59Ssowmini 	while ((option = getopt_long(argc, argv, ":pPsi:o:",
2519d62bc4baSyz147064 	    show_lopts, NULL)) != -1) {
25207c478bd9Sstevel@tonic-gate 		switch (option) {
25217c478bd9Sstevel@tonic-gate 		case 'p':
2522d62bc4baSyz147064 			if (p_arg)
2523d62bc4baSyz147064 				die_optdup(option);
2524d62bc4baSyz147064 
2525d62bc4baSyz147064 			p_arg = B_TRUE;
25267c478bd9Sstevel@tonic-gate 			break;
25277c478bd9Sstevel@tonic-gate 		case 's':
252833343a97Smeem 			if (s_arg)
252933343a97Smeem 				die_optdup(option);
25307c478bd9Sstevel@tonic-gate 
25317c478bd9Sstevel@tonic-gate 			s_arg = B_TRUE;
25327c478bd9Sstevel@tonic-gate 			break;
2533d62bc4baSyz147064 		case 'P':
2534d62bc4baSyz147064 			if (flags != DLADM_OPT_ACTIVE)
2535d62bc4baSyz147064 				die_optdup(option);
2536d62bc4baSyz147064 
2537d62bc4baSyz147064 			flags = DLADM_OPT_PERSIST;
2538d62bc4baSyz147064 			break;
2539e7801d59Ssowmini 		case 'o':
2540e7801d59Ssowmini 			o_arg = B_TRUE;
2541e7801d59Ssowmini 			fields_str = optarg;
2542e7801d59Ssowmini 			break;
25437c478bd9Sstevel@tonic-gate 		case 'i':
254433343a97Smeem 			if (i_arg)
254533343a97Smeem 				die_optdup(option);
25467c478bd9Sstevel@tonic-gate 
25477c478bd9Sstevel@tonic-gate 			i_arg = B_TRUE;
254833343a97Smeem 			if (!str2int(optarg, &interval) || interval == 0)
254933343a97Smeem 				die("invalid interval value '%s'", optarg);
25507c478bd9Sstevel@tonic-gate 			break;
25517c478bd9Sstevel@tonic-gate 		default:
25528d5c46e6Sam223141 			die_opterr(optopt, option, use);
255333343a97Smeem 			break;
25547c478bd9Sstevel@tonic-gate 		}
25557c478bd9Sstevel@tonic-gate 	}
25567c478bd9Sstevel@tonic-gate 
255733343a97Smeem 	if (i_arg && !s_arg)
255833343a97Smeem 		die("the option -i can be used only with -s");
25597c478bd9Sstevel@tonic-gate 
25606be03d0bSVasumathi Sundaram - Sun Microsystems 	if (s_arg && flags != DLADM_OPT_ACTIVE)
25616be03d0bSVasumathi Sundaram - Sun Microsystems 		die("the option -P cannot be used with -s");
2562d62bc4baSyz147064 
25637c478bd9Sstevel@tonic-gate 	/* get link name (optional last argument) */
2564d62bc4baSyz147064 	if (optind == (argc-1)) {
2565d62bc4baSyz147064 		uint32_t	f;
2566d62bc4baSyz147064 
2567d62bc4baSyz147064 		if ((status = dladm_name2info(argv[optind], &linkid, &f,
2568d62bc4baSyz147064 		    NULL, NULL)) != DLADM_STATUS_OK) {
2569d62bc4baSyz147064 			die_dlerr(status, "link %s is not valid", argv[optind]);
2570d62bc4baSyz147064 		}
2571d62bc4baSyz147064 
2572d62bc4baSyz147064 		if (!(f & flags)) {
2573d62bc4baSyz147064 			die_dlerr(DLADM_STATUS_BADARG, "link %s is %s",
2574d62bc4baSyz147064 			    argv[optind], flags == DLADM_OPT_PERSIST ?
2575d62bc4baSyz147064 			    "a temporary link" : "temporarily removed");
2576d62bc4baSyz147064 		}
2577d62bc4baSyz147064 	} else if (optind != argc) {
25787c478bd9Sstevel@tonic-gate 		usage();
2579d62bc4baSyz147064 	}
25807c478bd9Sstevel@tonic-gate 
25810d365605Sschuster 	if (p_arg && !o_arg)
25820d365605Sschuster 		die("-p requires -o");
25830d365605Sschuster 
25840d365605Sschuster 	if (p_arg && strcasecmp(fields_str, "all") == 0)
25850d365605Sschuster 		die("\"-o all\" is invalid with -p");
25860d365605Sschuster 
2587e7801d59Ssowmini 	if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) {
25886be03d0bSVasumathi Sundaram - Sun Microsystems 		if (s_arg)
25896be03d0bSVasumathi Sundaram - Sun Microsystems 			fields_str = allstat_fields;
25906be03d0bSVasumathi Sundaram - Sun Microsystems 		else if (flags & DLADM_OPT_ACTIVE)
2591e7801d59Ssowmini 			fields_str = all_active_fields;
2592e7801d59Ssowmini 		else
2593e7801d59Ssowmini 			fields_str = all_inactive_fields;
2594e7801d59Ssowmini 	}
2595e7801d59Ssowmini 
25966be03d0bSVasumathi Sundaram - Sun Microsystems 	state.ls_parseable = p_arg;
25976be03d0bSVasumathi Sundaram - Sun Microsystems 	state.ls_flags = flags;
25986be03d0bSVasumathi Sundaram - Sun Microsystems 	state.ls_donefirst = B_FALSE;
25996be03d0bSVasumathi Sundaram - Sun Microsystems 
26006be03d0bSVasumathi Sundaram - Sun Microsystems 	if (s_arg) {
26016be03d0bSVasumathi Sundaram - Sun Microsystems 		link_stats(linkid, interval, fields_str, &state);
26026be03d0bSVasumathi Sundaram - Sun Microsystems 		return;
26036be03d0bSVasumathi Sundaram - Sun Microsystems 	}
26046be03d0bSVasumathi Sundaram - Sun Microsystems 
2605e7801d59Ssowmini 
2606e7801d59Ssowmini 	fields = parse_output_fields(fields_str, link_fields, DEV_LINK_FIELDS,
2607e7801d59Ssowmini 	    CMD_TYPE_ANY, &nfields);
2608e7801d59Ssowmini 
26090d365605Sschuster 	if (fields == NULL)
2610e7801d59Ssowmini 		die("invalid field(s) specified");
2611e7801d59Ssowmini 
2612e7801d59Ssowmini 	state.ls_print.ps_fields = fields;
2613e7801d59Ssowmini 	state.ls_print.ps_nfields = nfields;
2614e7801d59Ssowmini 
2615d62bc4baSyz147064 	if (linkid == DATALINK_ALL_LINKID) {
2616d62bc4baSyz147064 		(void) dladm_walk_datalink_id(show_link, &state,
2617d62bc4baSyz147064 		    DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE, flags);
2618210db224Sericheng 	} else {
2619d62bc4baSyz147064 		(void) show_link(linkid, &state);
2620d62bc4baSyz147064 		if (state.ls_status != DLADM_STATUS_OK) {
2621d62bc4baSyz147064 			die_dlerr(state.ls_status, "failed to show link %s",
2622d62bc4baSyz147064 			    argv[optind]);
2623d62bc4baSyz147064 		}
26247c478bd9Sstevel@tonic-gate 	}
2625210db224Sericheng }
26267c478bd9Sstevel@tonic-gate 
26277c478bd9Sstevel@tonic-gate static void
26288d5c46e6Sam223141 do_show_aggr(int argc, char *argv[], const char *use)
26297c478bd9Sstevel@tonic-gate {
26307c478bd9Sstevel@tonic-gate 	boolean_t		L_arg = B_FALSE;
26317c478bd9Sstevel@tonic-gate 	boolean_t		s_arg = B_FALSE;
26327c478bd9Sstevel@tonic-gate 	boolean_t		i_arg = B_FALSE;
2633d62bc4baSyz147064 	boolean_t		p_arg = B_FALSE;
2634d62bc4baSyz147064 	boolean_t		x_arg = B_FALSE;
26357c478bd9Sstevel@tonic-gate 	show_grp_state_t	state;
2636d62bc4baSyz147064 	uint32_t		flags = DLADM_OPT_ACTIVE;
2637d62bc4baSyz147064 	datalink_id_t		linkid = DATALINK_ALL_LINKID;
2638d62bc4baSyz147064 	int			option;
263933343a97Smeem 	int			interval = 0;
2640d62bc4baSyz147064 	int			key;
2641d62bc4baSyz147064 	dladm_status_t		status;
2642e7801d59Ssowmini 	boolean_t	o_arg = B_FALSE;
2643e7801d59Ssowmini 	char		*fields_str = NULL;
2644e7801d59Ssowmini 	print_field_t   **fields;
2645e7801d59Ssowmini 	uint_t		nfields;
2646e7801d59Ssowmini 	char		*all_fields =
2647e7801d59Ssowmini 	    "link,policy,addrpolicy,lacpactivity,lacptimer,flags";
2648e7801d59Ssowmini 	char		*all_lacp_fields =
2649e7801d59Ssowmini 	    "link,port,aggregatable,sync,coll,dist,defaulted,expired";
2650e7801d59Ssowmini 	char		*all_stats_fields =
2651e7801d59Ssowmini 	    "link,port,ipackets,rbytes,opackets,obytes,ipktdist,opktdist";
2652e7801d59Ssowmini 	char		*all_extended_fields =
2653e7801d59Ssowmini 	    "link,port,speed,duplex,state,address,portstate";
2654e7801d59Ssowmini 	print_field_t		*pf;
2655e7801d59Ssowmini 	int			pfmax;
2656e7801d59Ssowmini 
2657e7801d59Ssowmini 	bzero(&state, sizeof (state));
26587c478bd9Sstevel@tonic-gate 
26597c478bd9Sstevel@tonic-gate 	opterr = 0;
2660e7801d59Ssowmini 	while ((option = getopt_long(argc, argv, ":LpPxsi:o:",
2661d62bc4baSyz147064 	    show_lopts, NULL)) != -1) {
26627c478bd9Sstevel@tonic-gate 		switch (option) {
26637c478bd9Sstevel@tonic-gate 		case 'L':
266433343a97Smeem 			if (L_arg)
266533343a97Smeem 				die_optdup(option);
26667c478bd9Sstevel@tonic-gate 
26677c478bd9Sstevel@tonic-gate 			L_arg = B_TRUE;
26687c478bd9Sstevel@tonic-gate 			break;
26697c478bd9Sstevel@tonic-gate 		case 'p':
2670d62bc4baSyz147064 			if (p_arg)
2671d62bc4baSyz147064 				die_optdup(option);
2672d62bc4baSyz147064 
2673d62bc4baSyz147064 			p_arg = B_TRUE;
2674d62bc4baSyz147064 			break;
2675d62bc4baSyz147064 		case 'x':
2676d62bc4baSyz147064 			if (x_arg)
2677d62bc4baSyz147064 				die_optdup(option);
2678d62bc4baSyz147064 
2679d62bc4baSyz147064 			x_arg = B_TRUE;
2680d62bc4baSyz147064 			break;
2681d62bc4baSyz147064 		case 'P':
2682d62bc4baSyz147064 			if (flags != DLADM_OPT_ACTIVE)
2683d62bc4baSyz147064 				die_optdup(option);
2684d62bc4baSyz147064 
2685d62bc4baSyz147064 			flags = DLADM_OPT_PERSIST;
26867c478bd9Sstevel@tonic-gate 			break;
26877c478bd9Sstevel@tonic-gate 		case 's':
268833343a97Smeem 			if (s_arg)
268933343a97Smeem 				die_optdup(option);
26907c478bd9Sstevel@tonic-gate 
26917c478bd9Sstevel@tonic-gate 			s_arg = B_TRUE;
26927c478bd9Sstevel@tonic-gate 			break;
2693e7801d59Ssowmini 		case 'o':
2694e7801d59Ssowmini 			o_arg = B_TRUE;
2695e7801d59Ssowmini 			fields_str = optarg;
2696e7801d59Ssowmini 			break;
26977c478bd9Sstevel@tonic-gate 		case 'i':
269833343a97Smeem 			if (i_arg)
269933343a97Smeem 				die_optdup(option);
27007c478bd9Sstevel@tonic-gate 
27017c478bd9Sstevel@tonic-gate 			i_arg = B_TRUE;
270233343a97Smeem 			if (!str2int(optarg, &interval) || interval == 0)
270333343a97Smeem 				die("invalid interval value '%s'", optarg);
27047c478bd9Sstevel@tonic-gate 			break;
27057c478bd9Sstevel@tonic-gate 		default:
27068d5c46e6Sam223141 			die_opterr(optopt, option, use);
270733343a97Smeem 			break;
27087c478bd9Sstevel@tonic-gate 		}
27097c478bd9Sstevel@tonic-gate 	}
27107c478bd9Sstevel@tonic-gate 
27110d365605Sschuster 	if (p_arg && !o_arg)
27120d365605Sschuster 		die("-p requires -o");
27130d365605Sschuster 
27140d365605Sschuster 	if (p_arg && strcasecmp(fields_str, "all") == 0)
27150d365605Sschuster 		die("\"-o all\" is invalid with -p");
27160d365605Sschuster 
271733343a97Smeem 	if (i_arg && !s_arg)
271833343a97Smeem 		die("the option -i can be used only with -s");
27197c478bd9Sstevel@tonic-gate 
2720d62bc4baSyz147064 	if (s_arg && (L_arg || p_arg || x_arg || flags != DLADM_OPT_ACTIVE)) {
2721d62bc4baSyz147064 		die("the option -%c cannot be used with -s",
2722d62bc4baSyz147064 		    L_arg ? 'L' : (p_arg ? 'p' : (x_arg ? 'x' : 'P')));
2723d62bc4baSyz147064 	}
2724d62bc4baSyz147064 
2725d62bc4baSyz147064 	if (L_arg && flags != DLADM_OPT_ACTIVE)
2726d62bc4baSyz147064 		die("the option -P cannot be used with -L");
2727d62bc4baSyz147064 
2728d62bc4baSyz147064 	if (x_arg && (L_arg || flags != DLADM_OPT_ACTIVE))
2729d62bc4baSyz147064 		die("the option -%c cannot be used with -x", L_arg ? 'L' : 'P');
2730d62bc4baSyz147064 
2731d62bc4baSyz147064 	/* get aggregation key or aggrname (optional last argument) */
27327c478bd9Sstevel@tonic-gate 	if (optind == (argc-1)) {
2733d62bc4baSyz147064 		if (!str2int(argv[optind], &key)) {
2734d62bc4baSyz147064 			status = dladm_name2info(argv[optind], &linkid, NULL,
2735d62bc4baSyz147064 			    NULL, NULL);
2736d62bc4baSyz147064 		} else {
2737d62bc4baSyz147064 			status = dladm_key2linkid((uint16_t)key,
2738d62bc4baSyz147064 			    &linkid, DLADM_OPT_ACTIVE);
2739d62bc4baSyz147064 		}
2740d62bc4baSyz147064 
2741d62bc4baSyz147064 		if (status != DLADM_STATUS_OK)
2742d62bc4baSyz147064 			die("non-existent aggregation '%s'", argv[optind]);
2743d62bc4baSyz147064 
27447c478bd9Sstevel@tonic-gate 	} else if (optind != argc) {
27457c478bd9Sstevel@tonic-gate 		usage();
27467c478bd9Sstevel@tonic-gate 	}
27477c478bd9Sstevel@tonic-gate 
2748d62bc4baSyz147064 	bzero(&state, sizeof (state));
2749d62bc4baSyz147064 	state.gs_lacp = L_arg;
2750d62bc4baSyz147064 	state.gs_stats = s_arg;
2751d62bc4baSyz147064 	state.gs_flags = flags;
2752d62bc4baSyz147064 	state.gs_parseable = p_arg;
2753d62bc4baSyz147064 	state.gs_extended = x_arg;
2754d62bc4baSyz147064 
2755e7801d59Ssowmini 	if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) {
2756e7801d59Ssowmini 		if (state.gs_lacp)
2757e7801d59Ssowmini 			fields_str = all_lacp_fields;
2758e7801d59Ssowmini 		else if (state.gs_stats)
2759e7801d59Ssowmini 			fields_str = all_stats_fields;
2760e7801d59Ssowmini 		else if (state.gs_extended)
2761e7801d59Ssowmini 			fields_str = all_extended_fields;
2762e7801d59Ssowmini 		else
2763e7801d59Ssowmini 			fields_str = all_fields;
2764e7801d59Ssowmini 	}
2765e7801d59Ssowmini 
2766e7801d59Ssowmini 	if (state.gs_lacp) {
2767e7801d59Ssowmini 		pf = aggr_l_fields;
2768e7801d59Ssowmini 		pfmax = AGGR_L_MAX_FIELDS;
2769e7801d59Ssowmini 	} else if (state.gs_stats) {
2770e7801d59Ssowmini 		pf = aggr_s_fields;
2771e7801d59Ssowmini 		pfmax = AGGR_S_MAX_FIELDS;
2772e7801d59Ssowmini 	} else if (state.gs_extended) {
2773e7801d59Ssowmini 		pf = aggr_x_fields;
2774e7801d59Ssowmini 		pfmax = AGGR_X_MAX_FIELDS;
2775e7801d59Ssowmini 	} else {
2776e7801d59Ssowmini 		pf = laggr_fields;
2777e7801d59Ssowmini 		pfmax = LAGGR_MAX_FIELDS;
2778e7801d59Ssowmini 	}
2779e7801d59Ssowmini 	fields = parse_output_fields(fields_str, pf, pfmax, CMD_TYPE_ANY,
2780e7801d59Ssowmini 	    &nfields);
2781e7801d59Ssowmini 
2782e7801d59Ssowmini 	if (fields == NULL) {
2783e7801d59Ssowmini 		die("invalid field(s) specified");
2784e7801d59Ssowmini 		return;
2785e7801d59Ssowmini 	}
2786e7801d59Ssowmini 
2787e7801d59Ssowmini 	state.gs_print.ps_fields = fields;
2788e7801d59Ssowmini 	state.gs_print.ps_nfields = nfields;
2789e7801d59Ssowmini 
27907c478bd9Sstevel@tonic-gate 	if (s_arg) {
2791d62bc4baSyz147064 		aggr_stats(linkid, &state, interval);
27927c478bd9Sstevel@tonic-gate 		return;
27937c478bd9Sstevel@tonic-gate 	}
27947c478bd9Sstevel@tonic-gate 
2795d62bc4baSyz147064 	if (linkid == DATALINK_ALL_LINKID) {
2796d62bc4baSyz147064 		(void) dladm_walk_datalink_id(show_aggr, &state,
2797d62bc4baSyz147064 		    DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE, flags);
2798d62bc4baSyz147064 	} else {
2799d62bc4baSyz147064 		(void) show_aggr(linkid, &state);
2800d62bc4baSyz147064 		if (state.gs_status != DLADM_STATUS_OK) {
2801d62bc4baSyz147064 			die_dlerr(state.gs_status, "failed to show aggr %s",
2802d62bc4baSyz147064 			    argv[optind]);
2803d62bc4baSyz147064 		}
2804d62bc4baSyz147064 	}
28057c478bd9Sstevel@tonic-gate }
28067c478bd9Sstevel@tonic-gate 
28077c478bd9Sstevel@tonic-gate static void
28088d5c46e6Sam223141 do_show_dev(int argc, char *argv[], const char *use)
28097c478bd9Sstevel@tonic-gate {
28107c478bd9Sstevel@tonic-gate 	int		option;
28117c478bd9Sstevel@tonic-gate 	char		*dev = NULL;
28127c478bd9Sstevel@tonic-gate 	boolean_t	s_arg = B_FALSE;
28137c478bd9Sstevel@tonic-gate 	boolean_t	i_arg = B_FALSE;
2814e7801d59Ssowmini 	boolean_t	o_arg = B_FALSE;
2815d62bc4baSyz147064 	boolean_t	p_arg = B_FALSE;
2816d62bc4baSyz147064 	datalink_id_t	linkid;
281733343a97Smeem 	int		interval = 0;
2818d62bc4baSyz147064 	show_state_t	state;
2819e7801d59Ssowmini 	char		*fields_str = NULL;
2820e7801d59Ssowmini 	print_field_t	**fields;
2821e7801d59Ssowmini 	uint_t		nfields;
2822e7801d59Ssowmini 	char		*all_fields = "link,state,speed,duplex";
2823e7801d59Ssowmini 	static char	*allstat_fields =
2824e7801d59Ssowmini 	    "link,ipackets,rbytes,ierrors,opackets,obytes,oerrors";
2825e7801d59Ssowmini 
2826e7801d59Ssowmini 	bzero(&state, sizeof (state));
2827e7801d59Ssowmini 	fields_str = all_fields;
28287c478bd9Sstevel@tonic-gate 
28297c478bd9Sstevel@tonic-gate 	opterr = 0;
2830e7801d59Ssowmini 	while ((option = getopt_long(argc, argv, ":psi:o:",
2831d62bc4baSyz147064 	    show_lopts, NULL)) != -1) {
28327c478bd9Sstevel@tonic-gate 		switch (option) {
28337c478bd9Sstevel@tonic-gate 		case 'p':
2834d62bc4baSyz147064 			if (p_arg)
2835d62bc4baSyz147064 				die_optdup(option);
2836d62bc4baSyz147064 
2837d62bc4baSyz147064 			p_arg = B_TRUE;
28387c478bd9Sstevel@tonic-gate 			break;
28397c478bd9Sstevel@tonic-gate 		case 's':
284033343a97Smeem 			if (s_arg)
284133343a97Smeem 				die_optdup(option);
28427c478bd9Sstevel@tonic-gate 
28437c478bd9Sstevel@tonic-gate 			s_arg = B_TRUE;
28447c478bd9Sstevel@tonic-gate 			break;
2845e7801d59Ssowmini 		case 'o':
2846e7801d59Ssowmini 			o_arg = B_TRUE;
2847e7801d59Ssowmini 			fields_str = optarg;
2848e7801d59Ssowmini 			break;
28497c478bd9Sstevel@tonic-gate 		case 'i':
285033343a97Smeem 			if (i_arg)
285133343a97Smeem 				die_optdup(option);
28527c478bd9Sstevel@tonic-gate 
28537c478bd9Sstevel@tonic-gate 			i_arg = B_TRUE;
285433343a97Smeem 			if (!str2int(optarg, &interval) || interval == 0)
285533343a97Smeem 				die("invalid interval value '%s'", optarg);
28567c478bd9Sstevel@tonic-gate 			break;
28577c478bd9Sstevel@tonic-gate 		default:
28588d5c46e6Sam223141 			die_opterr(optopt, option, use);
285933343a97Smeem 			break;
28607c478bd9Sstevel@tonic-gate 		}
28617c478bd9Sstevel@tonic-gate 	}
28627c478bd9Sstevel@tonic-gate 
28630d365605Sschuster 	if (p_arg && !o_arg)
28640d365605Sschuster 		die("-p requires -o");
28650d365605Sschuster 
28660d365605Sschuster 	if (p_arg && strcasecmp(fields_str, "all") == 0)
28670d365605Sschuster 		die("\"-o all\" is invalid with -p");
28680d365605Sschuster 
286933343a97Smeem 	if (i_arg && !s_arg)
287033343a97Smeem 		die("the option -i can be used only with -s");
28717c478bd9Sstevel@tonic-gate 
2872e7801d59Ssowmini 	if (o_arg && strcasecmp(fields_str, "all") == 0) {
2873e7801d59Ssowmini 		if (!s_arg)
2874e7801d59Ssowmini 			fields_str = all_fields;
2875e7801d59Ssowmini 		else
2876e7801d59Ssowmini 			fields_str = allstat_fields;
2877e7801d59Ssowmini 	}
2878e7801d59Ssowmini 
2879e7801d59Ssowmini 	if (!o_arg && s_arg)
2880e7801d59Ssowmini 		fields_str = allstat_fields;
2881e7801d59Ssowmini 
2882d62bc4baSyz147064 	if (s_arg && p_arg)
2883d62bc4baSyz147064 		die("the option -s cannot be used with -p");
2884d62bc4baSyz147064 
28857c478bd9Sstevel@tonic-gate 	/* get dev name (optional last argument) */
2886d62bc4baSyz147064 	if (optind == (argc-1)) {
2887d62bc4baSyz147064 		uint32_t flags;
2888d62bc4baSyz147064 
28897c478bd9Sstevel@tonic-gate 		dev = argv[optind];
2890d62bc4baSyz147064 
2891d62bc4baSyz147064 		if (dladm_dev2linkid(dev, &linkid) != DLADM_STATUS_OK)
2892d62bc4baSyz147064 			die("invalid device %s", dev);
2893d62bc4baSyz147064 
2894d62bc4baSyz147064 		if ((dladm_datalink_id2info(linkid, &flags, NULL, NULL,
2895d62bc4baSyz147064 		    NULL, 0) != DLADM_STATUS_OK) ||
2896d62bc4baSyz147064 		    !(flags & DLADM_OPT_ACTIVE)) {
2897d62bc4baSyz147064 			die("device %s has been removed", dev);
2898d62bc4baSyz147064 		}
2899d62bc4baSyz147064 	} else if (optind != argc) {
29007c478bd9Sstevel@tonic-gate 		usage();
2901cd93090eSericheng 	}
29027c478bd9Sstevel@tonic-gate 
2903e7801d59Ssowmini 	state.ls_parseable = p_arg;
2904e7801d59Ssowmini 	state.ls_donefirst = B_FALSE;
2905e7801d59Ssowmini 
29067c478bd9Sstevel@tonic-gate 	if (s_arg) {
2907e7801d59Ssowmini 		dev_stats(dev, interval, fields_str, &state);
29087c478bd9Sstevel@tonic-gate 		return;
29097c478bd9Sstevel@tonic-gate 	}
29107c478bd9Sstevel@tonic-gate 
2911e7801d59Ssowmini 	fields = parse_output_fields(fields_str, dev_fields, DEV_MAX_FIELDS,
2912e7801d59Ssowmini 	    CMD_TYPE_ANY, &nfields);
2913e7801d59Ssowmini 
2914e7801d59Ssowmini 	if (fields == NULL) {
2915e7801d59Ssowmini 		die("invalid field(s) specified");
2916e7801d59Ssowmini 		return;
2917e7801d59Ssowmini 	}
2918e7801d59Ssowmini 
2919e7801d59Ssowmini 	state.ls_print.ps_fields = fields;
2920e7801d59Ssowmini 	state.ls_print.ps_nfields = nfields;
2921e7801d59Ssowmini 
2922d62bc4baSyz147064 	if (dev == NULL) {
2923f595a68aSyz147064 		(void) dladm_mac_walk(show_dev, &state);
2924d62bc4baSyz147064 	} else {
2925d62bc4baSyz147064 		(void) show_dev(dev, &state);
2926d62bc4baSyz147064 	}
29277c478bd9Sstevel@tonic-gate }
29287c478bd9Sstevel@tonic-gate 
2929d62bc4baSyz147064 
2930d62bc4baSyz147064 static dladm_status_t
2931e7801d59Ssowmini print_phys(show_state_t *state, datalink_id_t linkid, link_fields_buf_t *pattr)
2932d62bc4baSyz147064 {
2933d62bc4baSyz147064 	char			link[MAXLINKNAMELEN];
2934d62bc4baSyz147064 	dladm_phys_attr_t	dpa;
2935d62bc4baSyz147064 	uint32_t		flags;
2936d62bc4baSyz147064 	datalink_class_t	class;
2937d62bc4baSyz147064 	uint32_t		media;
2938d62bc4baSyz147064 	dladm_status_t		status;
2939d62bc4baSyz147064 
2940d62bc4baSyz147064 	if ((status = dladm_datalink_id2info(linkid, &flags, &class, &media,
2941e7801d59Ssowmini 	    link, MAXLINKNAMELEN)) != DLADM_STATUS_OK) {
2942d62bc4baSyz147064 		goto done;
2943d62bc4baSyz147064 	}
2944d62bc4baSyz147064 
2945d62bc4baSyz147064 	if (class != DATALINK_CLASS_PHYS) {
2946d62bc4baSyz147064 		status = DLADM_STATUS_BADARG;
2947d62bc4baSyz147064 		goto done;
2948d62bc4baSyz147064 	}
2949d62bc4baSyz147064 
2950d62bc4baSyz147064 	if (!(state->ls_flags & flags)) {
2951d62bc4baSyz147064 		status = DLADM_STATUS_NOTFOUND;
2952d62bc4baSyz147064 		goto done;
2953d62bc4baSyz147064 	}
2954d62bc4baSyz147064 
2955d62bc4baSyz147064 	status = dladm_phys_info(linkid, &dpa, state->ls_flags);
2956d62bc4baSyz147064 	if (status != DLADM_STATUS_OK)
2957d62bc4baSyz147064 		goto done;
2958d62bc4baSyz147064 
2959e7801d59Ssowmini 	(void) snprintf(pattr->link_phys_device,
2960e7801d59Ssowmini 	    sizeof (pattr->link_phys_device), "%s", dpa.dp_dev);
2961e7801d59Ssowmini 	(void) dladm_media2str(media, pattr->link_phys_media);
2962d62bc4baSyz147064 	if (state->ls_flags == DLADM_OPT_ACTIVE) {
2963d62bc4baSyz147064 		boolean_t	islink;
2964d62bc4baSyz147064 
2965d62bc4baSyz147064 		if (!dpa.dp_novanity) {
2966e7801d59Ssowmini 			(void) strlcpy(pattr->link_name, link,
2967e7801d59Ssowmini 			    sizeof (pattr->link_name));
2968d62bc4baSyz147064 			islink = B_TRUE;
2969d62bc4baSyz147064 		} else {
2970d62bc4baSyz147064 			/*
2971d62bc4baSyz147064 			 * This is a physical link that does not have
2972d62bc4baSyz147064 			 * vanity naming support.
2973d62bc4baSyz147064 			 */
2974e7801d59Ssowmini 			(void) strlcpy(pattr->link_name, dpa.dp_dev,
2975e7801d59Ssowmini 			    sizeof (pattr->link_name));
2976d62bc4baSyz147064 			islink = B_FALSE;
2977d62bc4baSyz147064 		}
2978d62bc4baSyz147064 
2979e7801d59Ssowmini 		(void) get_linkstate(pattr->link_name, islink,
2980e7801d59Ssowmini 		    pattr->link_phys_state);
2981e7801d59Ssowmini 		(void) snprintf(pattr->link_phys_speed,
2982e7801d59Ssowmini 		    sizeof (pattr->link_phys_speed), "%u",
2983e7801d59Ssowmini 		    (uint_t)((get_ifspeed(pattr->link_name,
2984e7801d59Ssowmini 		    islink)) / 1000000ull));
2985e7801d59Ssowmini 		(void) get_linkduplex(pattr->link_name, islink,
2986e7801d59Ssowmini 		    pattr->link_phys_duplex);
2987d62bc4baSyz147064 	} else {
2988e7801d59Ssowmini 		(void) snprintf(pattr->link_name, sizeof (pattr->link_name),
2989e7801d59Ssowmini 		    "%s", link);
2990e7801d59Ssowmini 		(void) snprintf(pattr->link_flags, sizeof (pattr->link_flags),
2991e7801d59Ssowmini 		    "%c----", flags & DLADM_OPT_ACTIVE ? '-' : 'r');
2992d62bc4baSyz147064 	}
2993d62bc4baSyz147064 
2994d62bc4baSyz147064 done:
2995d62bc4baSyz147064 	return (status);
2996d62bc4baSyz147064 }
2997d62bc4baSyz147064 
2998d62bc4baSyz147064 static int
2999d62bc4baSyz147064 show_phys(datalink_id_t linkid, void *arg)
3000d62bc4baSyz147064 {
3001d62bc4baSyz147064 	show_state_t		*state = arg;
3002d62bc4baSyz147064 	dladm_status_t		status;
3003e7801d59Ssowmini 	link_fields_buf_t	pattr;
3004d62bc4baSyz147064 
30055f5c9f54SAnurag S. Maskey 	bzero(&pattr, sizeof (link_fields_buf_t));
3006e7801d59Ssowmini 	status = print_phys(state, linkid, &pattr);
3007d62bc4baSyz147064 	if (status != DLADM_STATUS_OK)
3008d62bc4baSyz147064 		goto done;
3009e7801d59Ssowmini 
3010e7801d59Ssowmini 	if (!state->ls_parseable && !state->ls_printheader) {
3011e7801d59Ssowmini 		print_header(&state->ls_print);
3012e7801d59Ssowmini 		state->ls_printheader = B_TRUE;
3013e7801d59Ssowmini 	}
3014e7801d59Ssowmini 
3015e7801d59Ssowmini 	dladm_print_output(&state->ls_print, state->ls_parseable,
3016e7801d59Ssowmini 	    dladm_print_field, (void *)&pattr);
3017d62bc4baSyz147064 
3018d62bc4baSyz147064 done:
3019d62bc4baSyz147064 	state->ls_status = status;
3020d62bc4baSyz147064 	return (DLADM_WALK_CONTINUE);
3021d62bc4baSyz147064 }
3022d62bc4baSyz147064 
3023d62bc4baSyz147064 
3024d62bc4baSyz147064 /*
3025d62bc4baSyz147064  * Print the active topology information.
3026d62bc4baSyz147064  */
3027d62bc4baSyz147064 static dladm_status_t
3028e7801d59Ssowmini print_vlan(show_state_t *state, datalink_id_t linkid, link_fields_buf_t *l)
3029d62bc4baSyz147064 {
3030d62bc4baSyz147064 	dladm_vlan_attr_t	vinfo;
3031d62bc4baSyz147064 	uint32_t		flags;
3032d62bc4baSyz147064 	dladm_status_t		status;
3033d62bc4baSyz147064 
3034e7801d59Ssowmini 	if ((status = dladm_datalink_id2info(linkid, &flags, NULL, NULL,
3035e7801d59Ssowmini 	    l->link_name, sizeof (l->link_name))) != DLADM_STATUS_OK) {
3036d62bc4baSyz147064 		goto done;
3037d62bc4baSyz147064 	}
3038d62bc4baSyz147064 
3039d62bc4baSyz147064 	if (!(state->ls_flags & flags)) {
3040d62bc4baSyz147064 		status = DLADM_STATUS_NOTFOUND;
3041d62bc4baSyz147064 		goto done;
3042d62bc4baSyz147064 	}
3043d62bc4baSyz147064 
3044d62bc4baSyz147064 	if ((status = dladm_vlan_info(linkid, &vinfo, state->ls_flags)) !=
3045d62bc4baSyz147064 	    DLADM_STATUS_OK || (status = dladm_datalink_id2info(
3046e7801d59Ssowmini 	    vinfo.dv_linkid, NULL, NULL, NULL, l->link_over,
3047e7801d59Ssowmini 	    sizeof (l->link_over))) != DLADM_STATUS_OK) {
3048d62bc4baSyz147064 		goto done;
3049d62bc4baSyz147064 	}
3050d62bc4baSyz147064 
3051e7801d59Ssowmini 	(void) snprintf(l->link_vlan_vid, sizeof (l->link_vlan_vid), "%d",
3052e7801d59Ssowmini 	    vinfo.dv_vid);
3053e7801d59Ssowmini 	(void) snprintf(l->link_flags, sizeof (l->link_flags), "%c%c---",
3054e7801d59Ssowmini 	    vinfo.dv_force ? 'f' : '-', vinfo.dv_implicit ? 'i' : '-');
3055d62bc4baSyz147064 
3056d62bc4baSyz147064 done:
3057d62bc4baSyz147064 	return (status);
3058d62bc4baSyz147064 }
3059d62bc4baSyz147064 
3060d62bc4baSyz147064 static int
3061d62bc4baSyz147064 show_vlan(datalink_id_t linkid, void *arg)
3062d62bc4baSyz147064 {
3063d62bc4baSyz147064 	show_state_t		*state = arg;
3064d62bc4baSyz147064 	dladm_status_t		status;
3065e7801d59Ssowmini 	link_fields_buf_t	lbuf;
3066d62bc4baSyz147064 
30675f5c9f54SAnurag S. Maskey 	bzero(&lbuf, sizeof (link_fields_buf_t));
3068e7801d59Ssowmini 	status = print_vlan(state, linkid, &lbuf);
3069d62bc4baSyz147064 	if (status != DLADM_STATUS_OK)
3070d62bc4baSyz147064 		goto done;
3071e7801d59Ssowmini 
3072e7801d59Ssowmini 	if (!state->ls_parseable && !state->ls_printheader) {
3073e7801d59Ssowmini 		print_header(&state->ls_print);
3074e7801d59Ssowmini 		state->ls_printheader = B_TRUE;
3075e7801d59Ssowmini 	}
3076e7801d59Ssowmini 
3077e7801d59Ssowmini 	dladm_print_output(&state->ls_print, state->ls_parseable,
3078e7801d59Ssowmini 	    dladm_print_field, (void *)&lbuf);
3079d62bc4baSyz147064 
3080d62bc4baSyz147064 done:
3081d62bc4baSyz147064 	state->ls_status = status;
3082d62bc4baSyz147064 	return (DLADM_WALK_CONTINUE);
3083d62bc4baSyz147064 }
3084d62bc4baSyz147064 
3085d62bc4baSyz147064 static void
30868d5c46e6Sam223141 do_show_phys(int argc, char *argv[], const char *use)
3087d62bc4baSyz147064 {
3088d62bc4baSyz147064 	int		option;
3089d62bc4baSyz147064 	uint32_t	flags = DLADM_OPT_ACTIVE;
3090d62bc4baSyz147064 	boolean_t	p_arg = B_FALSE;
3091e7801d59Ssowmini 	boolean_t	o_arg = B_FALSE;
3092d62bc4baSyz147064 	datalink_id_t	linkid = DATALINK_ALL_LINKID;
3093d62bc4baSyz147064 	show_state_t	state;
3094d62bc4baSyz147064 	dladm_status_t	status;
3095e7801d59Ssowmini 	char		*fields_str = NULL;
3096e7801d59Ssowmini 	print_field_t	**fields;
3097e7801d59Ssowmini 	uint_t		nfields;
3098e7801d59Ssowmini 	char		*all_active_fields =
3099e7801d59Ssowmini 	    "link,media,state,speed,duplex,device";
31005f5c9f54SAnurag S. Maskey 	char		*all_inactive_fields = "link,device,media,flags";
3101d62bc4baSyz147064 
3102e7801d59Ssowmini 	bzero(&state, sizeof (state));
3103d62bc4baSyz147064 	opterr = 0;
3104e7801d59Ssowmini 	while ((option = getopt_long(argc, argv, ":pPo:",
3105d62bc4baSyz147064 	    show_lopts, NULL)) != -1) {
3106d62bc4baSyz147064 		switch (option) {
3107d62bc4baSyz147064 		case 'p':
3108d62bc4baSyz147064 			if (p_arg)
3109d62bc4baSyz147064 				die_optdup(option);
3110d62bc4baSyz147064 
3111d62bc4baSyz147064 			p_arg = B_TRUE;
3112d62bc4baSyz147064 			break;
3113d62bc4baSyz147064 		case 'P':
3114d62bc4baSyz147064 			if (flags != DLADM_OPT_ACTIVE)
3115d62bc4baSyz147064 				die_optdup(option);
3116d62bc4baSyz147064 
3117d62bc4baSyz147064 			flags = DLADM_OPT_PERSIST;
3118d62bc4baSyz147064 			break;
3119e7801d59Ssowmini 		case 'o':
3120e7801d59Ssowmini 			o_arg = B_TRUE;
3121e7801d59Ssowmini 			fields_str = optarg;
3122e7801d59Ssowmini 			break;
3123d62bc4baSyz147064 		default:
31248d5c46e6Sam223141 			die_opterr(optopt, option, use);
3125d62bc4baSyz147064 			break;
3126d62bc4baSyz147064 		}
3127d62bc4baSyz147064 	}
3128d62bc4baSyz147064 
31290d365605Sschuster 	if (p_arg && !o_arg)
31300d365605Sschuster 		die("-p requires -o");
31310d365605Sschuster 
31320d365605Sschuster 	if (p_arg && strcasecmp(fields_str, "all") == 0)
31330d365605Sschuster 		die("\"-o all\" is invalid with -p");
31340d365605Sschuster 
3135d62bc4baSyz147064 	/* get link name (optional last argument) */
3136d62bc4baSyz147064 	if (optind == (argc-1)) {
3137d62bc4baSyz147064 		if ((status = dladm_name2info(argv[optind], &linkid, NULL,
3138d62bc4baSyz147064 		    NULL, NULL)) != DLADM_STATUS_OK) {
3139d62bc4baSyz147064 			die_dlerr(status, "link %s is not valid", argv[optind]);
3140d62bc4baSyz147064 		}
3141d62bc4baSyz147064 	} else if (optind != argc) {
3142d62bc4baSyz147064 		usage();
3143d62bc4baSyz147064 	}
3144d62bc4baSyz147064 
3145d62bc4baSyz147064 	state.ls_parseable = p_arg;
3146d62bc4baSyz147064 	state.ls_flags = flags;
3147d62bc4baSyz147064 	state.ls_donefirst = B_FALSE;
3148d62bc4baSyz147064 
3149e7801d59Ssowmini 	if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) {
3150e7801d59Ssowmini 		if (state.ls_flags & DLADM_OPT_ACTIVE)
3151e7801d59Ssowmini 			fields_str = all_active_fields;
3152e7801d59Ssowmini 		else
3153e7801d59Ssowmini 			fields_str = all_inactive_fields;
3154e7801d59Ssowmini 	}
3155e7801d59Ssowmini 
3156e7801d59Ssowmini 	fields = parse_output_fields(fields_str, phys_fields,
3157e7801d59Ssowmini 	    PHYS_MAX_FIELDS, CMD_TYPE_ANY, &nfields);
3158e7801d59Ssowmini 
3159e7801d59Ssowmini 	if (fields == NULL) {
3160e7801d59Ssowmini 		die("invalid field(s) specified");
3161e7801d59Ssowmini 		return;
3162e7801d59Ssowmini 	}
3163e7801d59Ssowmini 
3164e7801d59Ssowmini 	state.ls_print.ps_fields = fields;
3165e7801d59Ssowmini 	state.ls_print.ps_nfields = nfields;
3166e7801d59Ssowmini 
3167d62bc4baSyz147064 	if (linkid == DATALINK_ALL_LINKID) {
3168d62bc4baSyz147064 		(void) dladm_walk_datalink_id(show_phys, &state,
3169d62bc4baSyz147064 		    DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE, flags);
3170d62bc4baSyz147064 	} else {
3171d62bc4baSyz147064 		(void) show_phys(linkid, &state);
3172d62bc4baSyz147064 		if (state.ls_status != DLADM_STATUS_OK) {
3173d62bc4baSyz147064 			die_dlerr(state.ls_status,
3174d62bc4baSyz147064 			    "failed to show physical link %s", argv[optind]);
3175d62bc4baSyz147064 		}
3176d62bc4baSyz147064 	}
3177d62bc4baSyz147064 }
3178d62bc4baSyz147064 
3179d62bc4baSyz147064 static void
31808d5c46e6Sam223141 do_show_vlan(int argc, char *argv[], const char *use)
3181d62bc4baSyz147064 {
3182d62bc4baSyz147064 	int		option;
3183d62bc4baSyz147064 	uint32_t	flags = DLADM_OPT_ACTIVE;
3184d62bc4baSyz147064 	boolean_t	p_arg = B_FALSE;
3185d62bc4baSyz147064 	datalink_id_t	linkid = DATALINK_ALL_LINKID;
3186d62bc4baSyz147064 	show_state_t	state;
3187d62bc4baSyz147064 	dladm_status_t	status;
3188e7801d59Ssowmini 	boolean_t	o_arg = B_FALSE;
3189e7801d59Ssowmini 	char		*fields_str = NULL;
3190e7801d59Ssowmini 	print_field_t	**fields;
3191e7801d59Ssowmini 	uint_t		nfields;
3192e7801d59Ssowmini 	char		*all_fields = "link,vid,over,flags";
3193e7801d59Ssowmini 
3194e7801d59Ssowmini 	bzero(&state, sizeof (state));
3195d62bc4baSyz147064 
3196d62bc4baSyz147064 	opterr = 0;
3197e7801d59Ssowmini 	while ((option = getopt_long(argc, argv, ":pPo:",
3198d62bc4baSyz147064 	    show_lopts, NULL)) != -1) {
3199d62bc4baSyz147064 		switch (option) {
3200d62bc4baSyz147064 		case 'p':
3201d62bc4baSyz147064 			if (p_arg)
3202d62bc4baSyz147064 				die_optdup(option);
3203d62bc4baSyz147064 
3204d62bc4baSyz147064 			p_arg = B_TRUE;
3205d62bc4baSyz147064 			break;
3206d62bc4baSyz147064 		case 'P':
3207d62bc4baSyz147064 			if (flags != DLADM_OPT_ACTIVE)
3208d62bc4baSyz147064 				die_optdup(option);
3209d62bc4baSyz147064 
3210d62bc4baSyz147064 			flags = DLADM_OPT_PERSIST;
3211d62bc4baSyz147064 			break;
3212e7801d59Ssowmini 		case 'o':
3213e7801d59Ssowmini 			o_arg = B_TRUE;
3214e7801d59Ssowmini 			fields_str = optarg;
3215e7801d59Ssowmini 			break;
3216d62bc4baSyz147064 		default:
32178d5c46e6Sam223141 			die_opterr(optopt, option, use);
3218d62bc4baSyz147064 			break;
3219d62bc4baSyz147064 		}
3220d62bc4baSyz147064 	}
3221d62bc4baSyz147064 
32220d365605Sschuster 	if (p_arg && !o_arg)
32230d365605Sschuster 		die("-p requires -o");
32240d365605Sschuster 
32250d365605Sschuster 	if (p_arg && strcasecmp(fields_str, "all") == 0)
32260d365605Sschuster 		die("\"-o all\" is invalid with -p");
32270d365605Sschuster 
3228d62bc4baSyz147064 	/* get link name (optional last argument) */
3229d62bc4baSyz147064 	if (optind == (argc-1)) {
3230d62bc4baSyz147064 		if ((status = dladm_name2info(argv[optind], &linkid, NULL,
3231d62bc4baSyz147064 		    NULL, NULL)) != DLADM_STATUS_OK) {
3232d62bc4baSyz147064 			die_dlerr(status, "link %s is not valid", argv[optind]);
3233d62bc4baSyz147064 		}
3234d62bc4baSyz147064 	} else if (optind != argc) {
3235d62bc4baSyz147064 		usage();
3236d62bc4baSyz147064 	}
3237d62bc4baSyz147064 
3238d62bc4baSyz147064 	state.ls_parseable = p_arg;
3239d62bc4baSyz147064 	state.ls_flags = flags;
3240d62bc4baSyz147064 	state.ls_donefirst = B_FALSE;
3241d62bc4baSyz147064 
3242e7801d59Ssowmini 	if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0))
3243e7801d59Ssowmini 		fields_str = all_fields;
3244e7801d59Ssowmini 
3245e7801d59Ssowmini 	fields = parse_output_fields(fields_str, vlan_fields, VLAN_MAX_FIELDS,
3246e7801d59Ssowmini 	    CMD_TYPE_ANY, &nfields);
3247e7801d59Ssowmini 
3248e7801d59Ssowmini 	if (fields == NULL) {
3249e7801d59Ssowmini 		die("invalid field(s) specified");
3250e7801d59Ssowmini 		return;
3251e7801d59Ssowmini 	}
3252e7801d59Ssowmini 	state.ls_print.ps_fields = fields;
3253e7801d59Ssowmini 	state.ls_print.ps_nfields = nfields;
3254e7801d59Ssowmini 
3255d62bc4baSyz147064 	if (linkid == DATALINK_ALL_LINKID) {
3256d62bc4baSyz147064 		(void) dladm_walk_datalink_id(show_vlan, &state,
3257d62bc4baSyz147064 		    DATALINK_CLASS_VLAN, DATALINK_ANY_MEDIATYPE, flags);
3258d62bc4baSyz147064 	} else {
3259d62bc4baSyz147064 		(void) show_vlan(linkid, &state);
3260d62bc4baSyz147064 		if (state.ls_status != DLADM_STATUS_OK) {
3261d62bc4baSyz147064 			die_dlerr(state.ls_status, "failed to show vlan %s",
3262d62bc4baSyz147064 			    argv[optind]);
3263d62bc4baSyz147064 		}
3264d62bc4baSyz147064 	}
3265d62bc4baSyz147064 }
3266d62bc4baSyz147064 
3267d62bc4baSyz147064 static void
32686be03d0bSVasumathi Sundaram - Sun Microsystems link_stats(datalink_id_t linkid, uint_t interval, char *fields_str,
32696be03d0bSVasumathi Sundaram - Sun Microsystems     show_state_t *state)
3270d62bc4baSyz147064 {
32716be03d0bSVasumathi Sundaram - Sun Microsystems 	print_field_t	**fields;
32726be03d0bSVasumathi Sundaram - Sun Microsystems 	uint_t		nfields;
327333343a97Smeem 
32746be03d0bSVasumathi Sundaram - Sun Microsystems 	fields = parse_output_fields(fields_str, devs_fields, DEVS_MAX_FIELDS,
32756be03d0bSVasumathi Sundaram - Sun Microsystems 	    CMD_TYPE_ANY, &nfields);
32766be03d0bSVasumathi Sundaram - Sun Microsystems 	if (fields == NULL) {
32776be03d0bSVasumathi Sundaram - Sun Microsystems 		die("invalid field(s) specified");
32786be03d0bSVasumathi Sundaram - Sun Microsystems 		return;
32796be03d0bSVasumathi Sundaram - Sun Microsystems 	}
32806be03d0bSVasumathi Sundaram - Sun Microsystems 
32816be03d0bSVasumathi Sundaram - Sun Microsystems 	state->ls_print.ps_fields = fields;
32826be03d0bSVasumathi Sundaram - Sun Microsystems 	state->ls_print.ps_nfields = nfields;
32837c478bd9Sstevel@tonic-gate 
32847c478bd9Sstevel@tonic-gate 	/*
32857c478bd9Sstevel@tonic-gate 	 * If an interval is specified, continuously show the stats
32867c478bd9Sstevel@tonic-gate 	 * only for the first MAC port.
32877c478bd9Sstevel@tonic-gate 	 */
32886be03d0bSVasumathi Sundaram - Sun Microsystems 	state->ls_firstonly = (interval != 0);
32897c478bd9Sstevel@tonic-gate 
32906be03d0bSVasumathi Sundaram - Sun Microsystems 	if (!state->ls_parseable)
32916be03d0bSVasumathi Sundaram - Sun Microsystems 		print_header(&state->ls_print);
32927c478bd9Sstevel@tonic-gate 	for (;;) {
32936be03d0bSVasumathi Sundaram - Sun Microsystems 		state->ls_donefirst = B_FALSE;
3294d62bc4baSyz147064 		if (linkid == DATALINK_ALL_LINKID) {
32956be03d0bSVasumathi Sundaram - Sun Microsystems 			(void) dladm_walk_datalink_id(show_link_stats, state,
3296d62bc4baSyz147064 			    DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE,
3297d62bc4baSyz147064 			    DLADM_OPT_ACTIVE);
3298d62bc4baSyz147064 		} else {
32996be03d0bSVasumathi Sundaram - Sun Microsystems 			(void) show_link_stats(linkid, state);
3300d62bc4baSyz147064 		}
33017c478bd9Sstevel@tonic-gate 
33027c478bd9Sstevel@tonic-gate 		if (interval == 0)
33037c478bd9Sstevel@tonic-gate 			break;
33047c478bd9Sstevel@tonic-gate 
33057c478bd9Sstevel@tonic-gate 		(void) sleep(interval);
33067c478bd9Sstevel@tonic-gate 	}
33077c478bd9Sstevel@tonic-gate }
33087c478bd9Sstevel@tonic-gate 
33097c478bd9Sstevel@tonic-gate static void
3310d62bc4baSyz147064 aggr_stats(datalink_id_t linkid, show_grp_state_t *state, uint_t interval)
33117c478bd9Sstevel@tonic-gate {
33127c478bd9Sstevel@tonic-gate 	/*
33137c478bd9Sstevel@tonic-gate 	 * If an interval is specified, continuously show the stats
33147c478bd9Sstevel@tonic-gate 	 * only for the first group.
33157c478bd9Sstevel@tonic-gate 	 */
3316d62bc4baSyz147064 	state->gs_firstonly = (interval != 0);
33177c478bd9Sstevel@tonic-gate 
33187c478bd9Sstevel@tonic-gate 	for (;;) {
3319d62bc4baSyz147064 		state->gs_donefirst = B_FALSE;
3320d62bc4baSyz147064 		if (linkid == DATALINK_ALL_LINKID)
3321d62bc4baSyz147064 			(void) dladm_walk_datalink_id(show_aggr, state,
3322d62bc4baSyz147064 			    DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE,
3323d62bc4baSyz147064 			    DLADM_OPT_ACTIVE);
3324d62bc4baSyz147064 		else
3325d62bc4baSyz147064 			(void) show_aggr(linkid, state);
33267c478bd9Sstevel@tonic-gate 
33277c478bd9Sstevel@tonic-gate 		if (interval == 0)
33287c478bd9Sstevel@tonic-gate 			break;
33297c478bd9Sstevel@tonic-gate 
33307c478bd9Sstevel@tonic-gate 		(void) sleep(interval);
33317c478bd9Sstevel@tonic-gate 	}
33327c478bd9Sstevel@tonic-gate }
33337c478bd9Sstevel@tonic-gate 
33347c478bd9Sstevel@tonic-gate static void
3335e7801d59Ssowmini dev_stats(const char *dev, uint32_t interval, char *fields_str,
3336e7801d59Ssowmini     show_state_t *state)
33377c478bd9Sstevel@tonic-gate {
3338e7801d59Ssowmini 	print_field_t	**fields;
3339e7801d59Ssowmini 	uint_t		nfields;
33407c478bd9Sstevel@tonic-gate 
3341e7801d59Ssowmini 	fields = parse_output_fields(fields_str, devs_fields, DEVS_MAX_FIELDS,
3342e7801d59Ssowmini 	    CMD_TYPE_ANY, &nfields);
3343e7801d59Ssowmini 
3344e7801d59Ssowmini 	if (fields == NULL) {
3345e7801d59Ssowmini 		die("invalid field(s) specified");
3346e7801d59Ssowmini 		return;
3347e7801d59Ssowmini 	}
3348e7801d59Ssowmini 
3349e7801d59Ssowmini 	state->ls_print.ps_fields = fields;
3350e7801d59Ssowmini 	state->ls_print.ps_nfields = nfields;
3351e7801d59Ssowmini 
33527c478bd9Sstevel@tonic-gate 
33537c478bd9Sstevel@tonic-gate 	/*
33547c478bd9Sstevel@tonic-gate 	 * If an interval is specified, continuously show the stats
33557c478bd9Sstevel@tonic-gate 	 * only for the first MAC port.
33567c478bd9Sstevel@tonic-gate 	 */
3357e7801d59Ssowmini 	state->ls_firstonly = (interval != 0);
33587c478bd9Sstevel@tonic-gate 
33597c478bd9Sstevel@tonic-gate 	for (;;) {
33607c478bd9Sstevel@tonic-gate 
3361e7801d59Ssowmini 		if (!state->ls_parseable)
3362e7801d59Ssowmini 			print_header(&state->ls_print);
3363e7801d59Ssowmini 		state->ls_donefirst = B_FALSE;
33647c478bd9Sstevel@tonic-gate 
3365210db224Sericheng 		if (dev == NULL)
3366e7801d59Ssowmini 			(void) dladm_mac_walk(show_dev_stats, state);
3367210db224Sericheng 		else
3368e7801d59Ssowmini 			(void) show_dev_stats(dev, state);
33697c478bd9Sstevel@tonic-gate 
33707c478bd9Sstevel@tonic-gate 		if (interval == 0)
33717c478bd9Sstevel@tonic-gate 			break;
33727c478bd9Sstevel@tonic-gate 
33737c478bd9Sstevel@tonic-gate 		(void) sleep(interval);
33747c478bd9Sstevel@tonic-gate 	}
3375d62bc4baSyz147064 
3376e7801d59Ssowmini 	if (dev != NULL && state->ls_status != DLADM_STATUS_OK)
3377e7801d59Ssowmini 		die_dlerr(state->ls_status, "cannot show device '%s'", dev);
33787c478bd9Sstevel@tonic-gate }
33797c478bd9Sstevel@tonic-gate 
33807c478bd9Sstevel@tonic-gate /* accumulate stats (s1 += (s2 - s3)) */
33817c478bd9Sstevel@tonic-gate static void
33827c478bd9Sstevel@tonic-gate stats_total(pktsum_t *s1, pktsum_t *s2, pktsum_t *s3)
33837c478bd9Sstevel@tonic-gate {
33847c478bd9Sstevel@tonic-gate 	s1->ipackets += (s2->ipackets - s3->ipackets);
33857c478bd9Sstevel@tonic-gate 	s1->opackets += (s2->opackets - s3->opackets);
33867c478bd9Sstevel@tonic-gate 	s1->rbytes += (s2->rbytes - s3->rbytes);
33877c478bd9Sstevel@tonic-gate 	s1->obytes += (s2->obytes - s3->obytes);
33887c478bd9Sstevel@tonic-gate 	s1->ierrors += (s2->ierrors - s3->ierrors);
33897c478bd9Sstevel@tonic-gate 	s1->oerrors += (s2->oerrors - s3->oerrors);
33907c478bd9Sstevel@tonic-gate }
33917c478bd9Sstevel@tonic-gate 
33927c478bd9Sstevel@tonic-gate /* compute stats differences (s1 = s2 - s3) */
33937c478bd9Sstevel@tonic-gate static void
33947c478bd9Sstevel@tonic-gate stats_diff(pktsum_t *s1, pktsum_t *s2, pktsum_t *s3)
33957c478bd9Sstevel@tonic-gate {
33967c478bd9Sstevel@tonic-gate 	s1->ipackets = s2->ipackets - s3->ipackets;
33977c478bd9Sstevel@tonic-gate 	s1->opackets = s2->opackets - s3->opackets;
33987c478bd9Sstevel@tonic-gate 	s1->rbytes = s2->rbytes - s3->rbytes;
33997c478bd9Sstevel@tonic-gate 	s1->obytes = s2->obytes - s3->obytes;
34007c478bd9Sstevel@tonic-gate 	s1->ierrors = s2->ierrors - s3->ierrors;
34017c478bd9Sstevel@tonic-gate 	s1->oerrors = s2->oerrors - s3->oerrors;
34027c478bd9Sstevel@tonic-gate }
34037c478bd9Sstevel@tonic-gate 
34047c478bd9Sstevel@tonic-gate static void
3405d62bc4baSyz147064 get_stats(char *module, int instance, const char *name, pktsum_t *stats)
34067c478bd9Sstevel@tonic-gate {
34077c478bd9Sstevel@tonic-gate 	kstat_ctl_t	*kcp;
34087c478bd9Sstevel@tonic-gate 	kstat_t		*ksp;
34097c478bd9Sstevel@tonic-gate 
34107c478bd9Sstevel@tonic-gate 	if ((kcp = kstat_open()) == NULL) {
341133343a97Smeem 		warn("kstat open operation failed");
34127c478bd9Sstevel@tonic-gate 		return;
34137c478bd9Sstevel@tonic-gate 	}
34147c478bd9Sstevel@tonic-gate 
3415d62bc4baSyz147064 	if ((ksp = kstat_lookup(kcp, module, instance, (char *)name)) == NULL) {
34167c478bd9Sstevel@tonic-gate 		/*
34177c478bd9Sstevel@tonic-gate 		 * The kstat query could fail if the underlying MAC
34187c478bd9Sstevel@tonic-gate 		 * driver was already detached.
34197c478bd9Sstevel@tonic-gate 		 */
34207c478bd9Sstevel@tonic-gate 		(void) kstat_close(kcp);
34217c478bd9Sstevel@tonic-gate 		return;
34227c478bd9Sstevel@tonic-gate 	}
34237c478bd9Sstevel@tonic-gate 
34247c478bd9Sstevel@tonic-gate 	if (kstat_read(kcp, ksp, NULL) == -1)
34257c478bd9Sstevel@tonic-gate 		goto bail;
34267c478bd9Sstevel@tonic-gate 
3427e7801d59Ssowmini 	if (dladm_kstat_value(ksp, "ipackets64", KSTAT_DATA_UINT64,
34287c478bd9Sstevel@tonic-gate 	    &stats->ipackets) < 0)
34297c478bd9Sstevel@tonic-gate 		goto bail;
34307c478bd9Sstevel@tonic-gate 
3431e7801d59Ssowmini 	if (dladm_kstat_value(ksp, "opackets64", KSTAT_DATA_UINT64,
34327c478bd9Sstevel@tonic-gate 	    &stats->opackets) < 0)
34337c478bd9Sstevel@tonic-gate 		goto bail;
34347c478bd9Sstevel@tonic-gate 
3435e7801d59Ssowmini 	if (dladm_kstat_value(ksp, "rbytes64", KSTAT_DATA_UINT64,
34367c478bd9Sstevel@tonic-gate 	    &stats->rbytes) < 0)
34377c478bd9Sstevel@tonic-gate 		goto bail;
34387c478bd9Sstevel@tonic-gate 
3439e7801d59Ssowmini 	if (dladm_kstat_value(ksp, "obytes64", KSTAT_DATA_UINT64,
34407c478bd9Sstevel@tonic-gate 	    &stats->obytes) < 0)
34417c478bd9Sstevel@tonic-gate 		goto bail;
34427c478bd9Sstevel@tonic-gate 
3443e7801d59Ssowmini 	if (dladm_kstat_value(ksp, "ierrors", KSTAT_DATA_UINT32,
34447c478bd9Sstevel@tonic-gate 	    &stats->ierrors) < 0)
34457c478bd9Sstevel@tonic-gate 		goto bail;
34467c478bd9Sstevel@tonic-gate 
3447e7801d59Ssowmini 	if (dladm_kstat_value(ksp, "oerrors", KSTAT_DATA_UINT32,
34487c478bd9Sstevel@tonic-gate 	    &stats->oerrors) < 0)
34497c478bd9Sstevel@tonic-gate 		goto bail;
34507c478bd9Sstevel@tonic-gate 
3451d62bc4baSyz147064 bail:
34527c478bd9Sstevel@tonic-gate 	(void) kstat_close(kcp);
34537c478bd9Sstevel@tonic-gate 	return;
34547c478bd9Sstevel@tonic-gate 
34557c478bd9Sstevel@tonic-gate }
34567c478bd9Sstevel@tonic-gate 
34577c478bd9Sstevel@tonic-gate static void
3458ba2e4443Sseb get_mac_stats(const char *dev, pktsum_t *stats)
34597c478bd9Sstevel@tonic-gate {
3460c7e4935fSss150715 	char module[DLPI_LINKNAME_MAX];
3461c7e4935fSss150715 	uint_t instance;
34627c478bd9Sstevel@tonic-gate 
3463d62bc4baSyz147064 	bzero(stats, sizeof (*stats));
3464c7e4935fSss150715 	if (dlpi_parselink(dev, module, &instance) != DLPI_SUCCESS)
3465ba2e4443Sseb 		return;
3466d62bc4baSyz147064 
3467ba2e4443Sseb 	get_stats(module, instance, "mac", stats);
34687c478bd9Sstevel@tonic-gate }
34697c478bd9Sstevel@tonic-gate 
34707c478bd9Sstevel@tonic-gate static void
34717c478bd9Sstevel@tonic-gate get_link_stats(const char *link, pktsum_t *stats)
34727c478bd9Sstevel@tonic-gate {
34737c478bd9Sstevel@tonic-gate 	bzero(stats, sizeof (*stats));
3474d62bc4baSyz147064 	get_stats("link", 0, link, stats);
34757c478bd9Sstevel@tonic-gate }
34767c478bd9Sstevel@tonic-gate 
3477ba2e4443Sseb static int
3478d62bc4baSyz147064 query_kstat(char *module, int instance, const char *name, const char *stat,
3479d62bc4baSyz147064     uint8_t type, void *val)
34807c478bd9Sstevel@tonic-gate {
34817c478bd9Sstevel@tonic-gate 	kstat_ctl_t	*kcp;
34827c478bd9Sstevel@tonic-gate 	kstat_t		*ksp;
34837c478bd9Sstevel@tonic-gate 
34847c478bd9Sstevel@tonic-gate 	if ((kcp = kstat_open()) == NULL) {
348533343a97Smeem 		warn("kstat open operation failed");
3486ba2e4443Sseb 		return (-1);
34877c478bd9Sstevel@tonic-gate 	}
34887c478bd9Sstevel@tonic-gate 
3489d62bc4baSyz147064 	if ((ksp = kstat_lookup(kcp, module, instance, (char *)name)) == NULL) {
34907c478bd9Sstevel@tonic-gate 		/*
34917c478bd9Sstevel@tonic-gate 		 * The kstat query could fail if the underlying MAC
34927c478bd9Sstevel@tonic-gate 		 * driver was already detached.
34937c478bd9Sstevel@tonic-gate 		 */
34947c478bd9Sstevel@tonic-gate 		goto bail;
34957c478bd9Sstevel@tonic-gate 	}
34967c478bd9Sstevel@tonic-gate 
34977c478bd9Sstevel@tonic-gate 	if (kstat_read(kcp, ksp, NULL) == -1) {
349833343a97Smeem 		warn("kstat read failed");
34997c478bd9Sstevel@tonic-gate 		goto bail;
35007c478bd9Sstevel@tonic-gate 	}
35017c478bd9Sstevel@tonic-gate 
3502e7801d59Ssowmini 	if (dladm_kstat_value(ksp, stat, type, val) < 0)
35037c478bd9Sstevel@tonic-gate 		goto bail;
3504ba2e4443Sseb 
3505ba2e4443Sseb 	(void) kstat_close(kcp);
3506ba2e4443Sseb 	return (0);
35077c478bd9Sstevel@tonic-gate 
35087c478bd9Sstevel@tonic-gate bail:
35097c478bd9Sstevel@tonic-gate 	(void) kstat_close(kcp);
3510ba2e4443Sseb 	return (-1);
3511ba2e4443Sseb }
3512ba2e4443Sseb 
3513d62bc4baSyz147064 static int
3514d62bc4baSyz147064 get_one_kstat(const char *name, const char *stat, uint8_t type,
3515d62bc4baSyz147064     void *val, boolean_t islink)
3516d62bc4baSyz147064 {
3517d62bc4baSyz147064 	char		module[DLPI_LINKNAME_MAX];
3518d62bc4baSyz147064 	uint_t		instance;
3519d62bc4baSyz147064 
3520d62bc4baSyz147064 	if (islink) {
3521d62bc4baSyz147064 		return (query_kstat("link", 0, name, stat, type, val));
3522d62bc4baSyz147064 	} else {
3523d62bc4baSyz147064 		if (dlpi_parselink(name, module, &instance) != DLPI_SUCCESS)
3524d62bc4baSyz147064 			return (-1);
3525d62bc4baSyz147064 
3526d62bc4baSyz147064 		return (query_kstat(module, instance, "mac", stat, type, val));
3527d62bc4baSyz147064 	}
3528d62bc4baSyz147064 }
3529d62bc4baSyz147064 
3530ba2e4443Sseb static uint64_t
3531d62bc4baSyz147064 get_ifspeed(const char *name, boolean_t islink)
3532ba2e4443Sseb {
3533ba2e4443Sseb 	uint64_t ifspeed = 0;
3534ba2e4443Sseb 
3535d62bc4baSyz147064 	(void) get_one_kstat(name, "ifspeed", KSTAT_DATA_UINT64,
3536d62bc4baSyz147064 	    &ifspeed, islink);
3537d62bc4baSyz147064 
35387c478bd9Sstevel@tonic-gate 	return (ifspeed);
35397c478bd9Sstevel@tonic-gate }
35407c478bd9Sstevel@tonic-gate 
3541f595a68aSyz147064 static const char *
3542d62bc4baSyz147064 get_linkstate(const char *name, boolean_t islink, char *buf)
35437c478bd9Sstevel@tonic-gate {
3544d62bc4baSyz147064 	link_state_t	linkstate;
35457c478bd9Sstevel@tonic-gate 
3546d62bc4baSyz147064 	if (get_one_kstat(name, "link_state", KSTAT_DATA_UINT32,
3547d62bc4baSyz147064 	    &linkstate, islink) != 0) {
35483a62633bSyz147064 		(void) strlcpy(buf, "unknown", DLADM_STRSIZE);
35493a62633bSyz147064 		return (buf);
35507c478bd9Sstevel@tonic-gate 	}
3551d62bc4baSyz147064 	return (dladm_linkstate2str(linkstate, buf));
35527c478bd9Sstevel@tonic-gate }
35537c478bd9Sstevel@tonic-gate 
3554f595a68aSyz147064 static const char *
3555d62bc4baSyz147064 get_linkduplex(const char *name, boolean_t islink, char *buf)
35567c478bd9Sstevel@tonic-gate {
3557d62bc4baSyz147064 	link_duplex_t	linkduplex;
35587c478bd9Sstevel@tonic-gate 
3559d62bc4baSyz147064 	if (get_one_kstat(name, "link_duplex", KSTAT_DATA_UINT32,
3560d62bc4baSyz147064 	    &linkduplex, islink) != 0) {
35613a62633bSyz147064 		(void) strlcpy(buf, "unknown", DLADM_STRSIZE);
35623a62633bSyz147064 		return (buf);
35637c478bd9Sstevel@tonic-gate 	}
35647c478bd9Sstevel@tonic-gate 
3565d62bc4baSyz147064 	return (dladm_linkduplex2str(linkduplex, buf));
35667c478bd9Sstevel@tonic-gate }
35670ba2cbe9Sxc151355 
35680ba2cbe9Sxc151355 typedef struct {
35690ba2cbe9Sxc151355 	char	*s_buf;
35700ba2cbe9Sxc151355 	char	**s_fields;	/* array of pointer to the fields in s_buf */
35710ba2cbe9Sxc151355 	uint_t	s_nfields;	/* the number of fields in s_buf */
35720ba2cbe9Sxc151355 } split_t;
35730ba2cbe9Sxc151355 
35740ba2cbe9Sxc151355 /*
35750ba2cbe9Sxc151355  * Free the split_t structure pointed to by `sp'.
35760ba2cbe9Sxc151355  */
35770ba2cbe9Sxc151355 static void
35780ba2cbe9Sxc151355 splitfree(split_t *sp)
35790ba2cbe9Sxc151355 {
35800ba2cbe9Sxc151355 	free(sp->s_buf);
35810ba2cbe9Sxc151355 	free(sp->s_fields);
35820ba2cbe9Sxc151355 	free(sp);
35830ba2cbe9Sxc151355 }
35840ba2cbe9Sxc151355 
35850ba2cbe9Sxc151355 /*
35860ba2cbe9Sxc151355  * Split `str' into at most `maxfields' fields, each field at most `maxlen' in
35870ba2cbe9Sxc151355  * length.  Return a pointer to a split_t containing the split fields, or NULL
35880ba2cbe9Sxc151355  * on failure.
35890ba2cbe9Sxc151355  */
35900ba2cbe9Sxc151355 static split_t *
35910ba2cbe9Sxc151355 split(const char *str, uint_t maxfields, uint_t maxlen)
35920ba2cbe9Sxc151355 {
35930ba2cbe9Sxc151355 	char	*field, *token, *lasts = NULL;
35940ba2cbe9Sxc151355 	split_t	*sp;
35950ba2cbe9Sxc151355 
35960ba2cbe9Sxc151355 	if (*str == '\0' || maxfields == 0 || maxlen == 0)
35970ba2cbe9Sxc151355 		return (NULL);
35980ba2cbe9Sxc151355 
35990ba2cbe9Sxc151355 	sp = calloc(sizeof (split_t), 1);
36000ba2cbe9Sxc151355 	if (sp == NULL)
36010ba2cbe9Sxc151355 		return (NULL);
36020ba2cbe9Sxc151355 
36030ba2cbe9Sxc151355 	sp->s_buf = strdup(str);
36040ba2cbe9Sxc151355 	sp->s_fields = malloc(sizeof (char *) * maxfields);
36050ba2cbe9Sxc151355 	if (sp->s_buf == NULL || sp->s_fields == NULL)
36060ba2cbe9Sxc151355 		goto fail;
36070ba2cbe9Sxc151355 
36080ba2cbe9Sxc151355 	token = sp->s_buf;
36090ba2cbe9Sxc151355 	while ((field = strtok_r(token, ",", &lasts)) != NULL) {
36100ba2cbe9Sxc151355 		if (sp->s_nfields == maxfields || strlen(field) > maxlen)
36110ba2cbe9Sxc151355 			goto fail;
36120ba2cbe9Sxc151355 		token = NULL;
36130ba2cbe9Sxc151355 		sp->s_fields[sp->s_nfields++] = field;
36140ba2cbe9Sxc151355 	}
36150ba2cbe9Sxc151355 	return (sp);
36160ba2cbe9Sxc151355 fail:
36170ba2cbe9Sxc151355 	splitfree(sp);
36180ba2cbe9Sxc151355 	return (NULL);
36190ba2cbe9Sxc151355 }
36200ba2cbe9Sxc151355 
36210ba2cbe9Sxc151355 static int
3622e7801d59Ssowmini parse_wifi_fields(char *str, print_field_t ***fields, uint_t *countp,
36230ba2cbe9Sxc151355     uint_t cmdtype)
36240ba2cbe9Sxc151355 {
36250ba2cbe9Sxc151355 
36260ba2cbe9Sxc151355 	if (cmdtype == WIFI_CMD_SCAN) {
36270ba2cbe9Sxc151355 		if (str == NULL)
36280ba2cbe9Sxc151355 			str = def_scan_wifi_fields;
36290ba2cbe9Sxc151355 		if (strcasecmp(str, "all") == 0)
36300ba2cbe9Sxc151355 			str = all_scan_wifi_fields;
36310ba2cbe9Sxc151355 	} else if (cmdtype == WIFI_CMD_SHOW) {
36320ba2cbe9Sxc151355 		if (str == NULL)
36330ba2cbe9Sxc151355 			str = def_show_wifi_fields;
36340ba2cbe9Sxc151355 		if (strcasecmp(str, "all") == 0)
36350ba2cbe9Sxc151355 			str = all_show_wifi_fields;
36360ba2cbe9Sxc151355 	} else {
36370ba2cbe9Sxc151355 		return (-1);
36380ba2cbe9Sxc151355 	}
3639e7801d59Ssowmini 	*fields = parse_output_fields(str, wifi_fields, WIFI_MAX_FIELDS,
3640e7801d59Ssowmini 	    cmdtype, countp);
3641e7801d59Ssowmini 	if (*fields != NULL)
3642e7801d59Ssowmini 		return (0);
36430ba2cbe9Sxc151355 	return (-1);
3644e7801d59Ssowmini }
3645e7801d59Ssowmini static print_field_t **
3646e7801d59Ssowmini parse_output_fields(char *str, print_field_t *template, int max_fields,
3647e7801d59Ssowmini     uint_t cmdtype, uint_t *countp)
3648e7801d59Ssowmini {
3649e7801d59Ssowmini 	split_t		*sp;
3650e7801d59Ssowmini 	boolean_t	good_match = B_FALSE;
3651e7801d59Ssowmini 	uint_t		i, j;
3652e7801d59Ssowmini 	print_field_t	**pf = NULL;
36530ba2cbe9Sxc151355 
3654e7801d59Ssowmini 	sp = split(str, max_fields, MAX_FIELD_LEN);
3655e7801d59Ssowmini 
3656e7801d59Ssowmini 	if (sp == NULL)
3657e7801d59Ssowmini 		return (NULL);
3658e7801d59Ssowmini 
3659e7801d59Ssowmini 	pf = malloc(sp->s_nfields * sizeof (print_field_t *));
3660e7801d59Ssowmini 	if (pf == NULL)
36610ba2cbe9Sxc151355 		goto fail;
36620ba2cbe9Sxc151355 
36630ba2cbe9Sxc151355 	for (i = 0; i < sp->s_nfields; i++) {
3664e7801d59Ssowmini 		for (j = 0; j < max_fields; j++) {
36650ba2cbe9Sxc151355 			if (strcasecmp(sp->s_fields[i],
3666e7801d59Ssowmini 			    template[j].pf_name) == 0) {
3667e7801d59Ssowmini 				good_match = template[j]. pf_cmdtype & cmdtype;
36680ba2cbe9Sxc151355 				break;
36690ba2cbe9Sxc151355 			}
36700ba2cbe9Sxc151355 		}
36710ba2cbe9Sxc151355 		if (!good_match)
36720ba2cbe9Sxc151355 			goto fail;
36730ba2cbe9Sxc151355 
36740ba2cbe9Sxc151355 		good_match = B_FALSE;
3675e7801d59Ssowmini 		pf[i] = &template[j];
36760ba2cbe9Sxc151355 	}
36770ba2cbe9Sxc151355 	*countp = i;
36780ba2cbe9Sxc151355 	splitfree(sp);
3679e7801d59Ssowmini 	return (pf);
36800ba2cbe9Sxc151355 fail:
3681e7801d59Ssowmini 	free(pf);
36820ba2cbe9Sxc151355 	splitfree(sp);
3683e7801d59Ssowmini 	return (NULL);
36840ba2cbe9Sxc151355 }
36850ba2cbe9Sxc151355 
36860ba2cbe9Sxc151355 typedef struct print_wifi_state {
3687d62bc4baSyz147064 	char		*ws_link;
36880ba2cbe9Sxc151355 	boolean_t	ws_parseable;
36890ba2cbe9Sxc151355 	boolean_t	ws_header;
3690e7801d59Ssowmini 	print_state_t	ws_print_state;
36910ba2cbe9Sxc151355 } print_wifi_state_t;
36920ba2cbe9Sxc151355 
3693e7801d59Ssowmini typedef struct  wlan_scan_args_s {
3694e7801d59Ssowmini 	print_wifi_state_t	*ws_state;
3695e7801d59Ssowmini 	void			*ws_attr;
3696e7801d59Ssowmini } wlan_scan_args_t;
36970ba2cbe9Sxc151355 
36980ba2cbe9Sxc151355 static void
3699e7801d59Ssowmini print_field(print_state_t *statep, print_field_t *pfp, const char *value,
3700e7801d59Ssowmini     boolean_t parseable)
37010ba2cbe9Sxc151355 {
3702e7801d59Ssowmini 	uint_t	width = pfp->pf_width;
37036be03d0bSVasumathi Sundaram - Sun Microsystems 	uint_t	valwidth;
37040ba2cbe9Sxc151355 	uint_t	compress;
37050ba2cbe9Sxc151355 
37060d365605Sschuster 	/*
37070d365605Sschuster 	 * Parsable fields are separated by ':'. If such a field contains
37080d365605Sschuster 	 * a ':' or '\', this character is prefixed by a '\'.
37090d365605Sschuster 	 */
3710e7801d59Ssowmini 	if (parseable) {
37110d365605Sschuster 		char	c;
37120d365605Sschuster 
37130d365605Sschuster 		if (statep->ps_nfields == 1) {
37140d365605Sschuster 			(void) printf("%s", value);
37150d365605Sschuster 			return;
37160d365605Sschuster 		}
37170d365605Sschuster 		while ((c = *value++) != '\0') {
37180d365605Sschuster 			if (c == ':' || c == '\\')
37190d365605Sschuster 				(void) putchar('\\');
37200d365605Sschuster 			(void) putchar(c);
37210d365605Sschuster 		}
37220d365605Sschuster 		if (!statep->ps_lastfield)
37230d365605Sschuster 			(void) putchar(':');
37240d365605Sschuster 		return;
37250ba2cbe9Sxc151355 	} else {
37260ba2cbe9Sxc151355 		if (value[0] == '\0')
3727e7801d59Ssowmini 			value = STR_UNDEF_VAL;
3728e7801d59Ssowmini 		if (statep->ps_lastfield) {
37290ba2cbe9Sxc151355 			(void) printf("%s", value);
37306be03d0bSVasumathi Sundaram - Sun Microsystems 			statep->ps_overflow = 0;
37310ba2cbe9Sxc151355 			return;
37320ba2cbe9Sxc151355 		}
37330ba2cbe9Sxc151355 
37346be03d0bSVasumathi Sundaram - Sun Microsystems 		valwidth = strlen(value);
37350ba2cbe9Sxc151355 		if (valwidth > width) {
3736e7801d59Ssowmini 			statep->ps_overflow += valwidth - width;
3737e7801d59Ssowmini 		} else if (valwidth < width && statep->ps_overflow > 0) {
3738e7801d59Ssowmini 			compress = min(statep->ps_overflow, width - valwidth);
3739e7801d59Ssowmini 			statep->ps_overflow -= compress;
37400ba2cbe9Sxc151355 			width -= compress;
37410ba2cbe9Sxc151355 		}
37420ba2cbe9Sxc151355 		(void) printf("%-*s", width, value);
37430ba2cbe9Sxc151355 	}
37440ba2cbe9Sxc151355 
3745e7801d59Ssowmini 	if (!statep->ps_lastfield)
37460ba2cbe9Sxc151355 		(void) putchar(' ');
37470ba2cbe9Sxc151355 }
37480ba2cbe9Sxc151355 
3749e7801d59Ssowmini static char *
3750e7801d59Ssowmini print_wlan_attr(print_field_t *wfp, void *warg)
37510ba2cbe9Sxc151355 {
3752e7801d59Ssowmini 	static char		buf[DLADM_STRSIZE];
3753e7801d59Ssowmini 	wlan_scan_args_t	*w = warg;
3754e7801d59Ssowmini 	print_wifi_state_t	*statep = w->ws_state;
3755e7801d59Ssowmini 	dladm_wlan_attr_t	*attrp = w->ws_attr;
37560ba2cbe9Sxc151355 
3757e7801d59Ssowmini 	if (wfp->pf_index == 0) {
3758e7801d59Ssowmini 		return ((char *)statep->ws_link);
37590ba2cbe9Sxc151355 	}
37600ba2cbe9Sxc151355 
3761e7801d59Ssowmini 	if ((wfp->pf_index & attrp->wa_valid) == 0) {
3762e7801d59Ssowmini 		return ("");
37630ba2cbe9Sxc151355 	}
37640ba2cbe9Sxc151355 
3765e7801d59Ssowmini 	switch (wfp->pf_index) {
3766f595a68aSyz147064 	case DLADM_WLAN_ATTR_ESSID:
3767e7801d59Ssowmini 		(void) dladm_wlan_essid2str(&attrp->wa_essid, buf);
37680ba2cbe9Sxc151355 		break;
3769f595a68aSyz147064 	case DLADM_WLAN_ATTR_BSSID:
3770e7801d59Ssowmini 		(void) dladm_wlan_bssid2str(&attrp->wa_bssid, buf);
37710ba2cbe9Sxc151355 		break;
3772f595a68aSyz147064 	case DLADM_WLAN_ATTR_SECMODE:
3773e7801d59Ssowmini 		(void) dladm_wlan_secmode2str(&attrp->wa_secmode, buf);
37740ba2cbe9Sxc151355 		break;
3775f595a68aSyz147064 	case DLADM_WLAN_ATTR_STRENGTH:
3776e7801d59Ssowmini 		(void) dladm_wlan_strength2str(&attrp->wa_strength, buf);
37770ba2cbe9Sxc151355 		break;
3778f595a68aSyz147064 	case DLADM_WLAN_ATTR_MODE:
3779e7801d59Ssowmini 		(void) dladm_wlan_mode2str(&attrp->wa_mode, buf);
37800ba2cbe9Sxc151355 		break;
3781f595a68aSyz147064 	case DLADM_WLAN_ATTR_SPEED:
3782e7801d59Ssowmini 		(void) dladm_wlan_speed2str(&attrp->wa_speed, buf);
37830ba2cbe9Sxc151355 		(void) strlcat(buf, "Mb", sizeof (buf));
37840ba2cbe9Sxc151355 		break;
3785f595a68aSyz147064 	case DLADM_WLAN_ATTR_AUTH:
3786e7801d59Ssowmini 		(void) dladm_wlan_auth2str(&attrp->wa_auth, buf);
37870ba2cbe9Sxc151355 		break;
3788f595a68aSyz147064 	case DLADM_WLAN_ATTR_BSSTYPE:
3789e7801d59Ssowmini 		(void) dladm_wlan_bsstype2str(&attrp->wa_bsstype, buf);
37900ba2cbe9Sxc151355 		break;
37910ba2cbe9Sxc151355 	}
37920ba2cbe9Sxc151355 
3793e7801d59Ssowmini 	return (buf);
37940ba2cbe9Sxc151355 }
37950ba2cbe9Sxc151355 
37960ba2cbe9Sxc151355 static boolean_t
3797f595a68aSyz147064 print_scan_results(void *arg, dladm_wlan_attr_t *attrp)
37980ba2cbe9Sxc151355 {
37990ba2cbe9Sxc151355 	print_wifi_state_t	*statep = arg;
3800e7801d59Ssowmini 	wlan_scan_args_t	warg;
38010ba2cbe9Sxc151355 
38020ba2cbe9Sxc151355 	if (statep->ws_header) {
38030ba2cbe9Sxc151355 		statep->ws_header = B_FALSE;
38040ba2cbe9Sxc151355 		if (!statep->ws_parseable)
3805e7801d59Ssowmini 			print_header(&statep->ws_print_state);
38060ba2cbe9Sxc151355 	}
38070ba2cbe9Sxc151355 
3808e7801d59Ssowmini 	statep->ws_print_state.ps_overflow = 0;
3809e7801d59Ssowmini 	bzero(&warg, sizeof (warg));
3810e7801d59Ssowmini 	warg.ws_state = statep;
3811e7801d59Ssowmini 	warg.ws_attr = attrp;
3812e7801d59Ssowmini 	dladm_print_output(&statep->ws_print_state, statep->ws_parseable,
3813e7801d59Ssowmini 	    print_wlan_attr, &warg);
38140ba2cbe9Sxc151355 	return (B_TRUE);
38150ba2cbe9Sxc151355 }
38160ba2cbe9Sxc151355 
3817d62bc4baSyz147064 static int
3818d62bc4baSyz147064 scan_wifi(datalink_id_t linkid, void *arg)
38190ba2cbe9Sxc151355 {
38200ba2cbe9Sxc151355 	print_wifi_state_t	*statep = arg;
3821f595a68aSyz147064 	dladm_status_t		status;
3822d62bc4baSyz147064 	char			link[MAXLINKNAMELEN];
3823d62bc4baSyz147064 
3824e7801d59Ssowmini 	if ((status = dladm_datalink_id2info(linkid, NULL, NULL, NULL, link,
3825e7801d59Ssowmini 	    sizeof (link))) != DLADM_STATUS_OK) {
3826d62bc4baSyz147064 		return (DLADM_WALK_CONTINUE);
3827d62bc4baSyz147064 	}
38280ba2cbe9Sxc151355 
38290ba2cbe9Sxc151355 	statep->ws_link = link;
3830d62bc4baSyz147064 	status = dladm_wlan_scan(linkid, statep, print_scan_results);
3831f595a68aSyz147064 	if (status != DLADM_STATUS_OK)
3832d62bc4baSyz147064 		die_dlerr(status, "cannot scan link '%s'", statep->ws_link);
383333343a97Smeem 
3834d62bc4baSyz147064 	return (DLADM_WALK_CONTINUE);
38350ba2cbe9Sxc151355 }
38360ba2cbe9Sxc151355 
3837e7801d59Ssowmini static char *
3838e7801d59Ssowmini print_link_attr(print_field_t *wfp, void *warg)
38390ba2cbe9Sxc151355 {
3840e7801d59Ssowmini 	static char		buf[DLADM_STRSIZE];
3841e7801d59Ssowmini 	char			*ptr;
3842e7801d59Ssowmini 	wlan_scan_args_t	*w = warg, w1;
3843e7801d59Ssowmini 	print_wifi_state_t	*statep = w->ws_state;
3844e7801d59Ssowmini 	dladm_wlan_linkattr_t	*attrp = w->ws_attr;
38450ba2cbe9Sxc151355 
3846e7801d59Ssowmini 	if (strcmp(wfp->pf_name, "status") == 0) {
3847e7801d59Ssowmini 		if ((wfp->pf_index & attrp->la_valid) != 0)
3848e7801d59Ssowmini 			(void) dladm_wlan_linkstatus2str(
3849e7801d59Ssowmini 			    &attrp->la_status, buf);
3850e7801d59Ssowmini 		return (buf);
38510ba2cbe9Sxc151355 	}
3852e7801d59Ssowmini 	statep->ws_print_state.ps_overflow = 0;
3853e7801d59Ssowmini 	bzero(&w1, sizeof (w1));
3854e7801d59Ssowmini 	w1.ws_state = statep;
3855e7801d59Ssowmini 	w1.ws_attr = &attrp->la_wlan_attr;
3856e7801d59Ssowmini 	ptr = print_wlan_attr(wfp, &w1);
3857e7801d59Ssowmini 	return (ptr);
38580ba2cbe9Sxc151355 }
38590ba2cbe9Sxc151355 
3860d62bc4baSyz147064 static int
3861d62bc4baSyz147064 show_wifi(datalink_id_t linkid, void *arg)
38620ba2cbe9Sxc151355 {
38630ba2cbe9Sxc151355 	print_wifi_state_t	*statep = arg;
3864f595a68aSyz147064 	dladm_wlan_linkattr_t	attr;
3865f595a68aSyz147064 	dladm_status_t		status;
3866d62bc4baSyz147064 	char			link[MAXLINKNAMELEN];
3867e7801d59Ssowmini 	wlan_scan_args_t	warg;
38680ba2cbe9Sxc151355 
3869e7801d59Ssowmini 	if ((status = dladm_datalink_id2info(linkid, NULL, NULL, NULL, link,
3870e7801d59Ssowmini 	    sizeof (link))) != DLADM_STATUS_OK) {
3871d62bc4baSyz147064 		return (DLADM_WALK_CONTINUE);
3872d62bc4baSyz147064 	}
3873d62bc4baSyz147064 
38745f5c9f54SAnurag S. Maskey 	/* dladm_wlan_get_linkattr() memsets attr with 0 */
3875d62bc4baSyz147064 	status = dladm_wlan_get_linkattr(linkid, &attr);
3876f595a68aSyz147064 	if (status != DLADM_STATUS_OK)
3877d62bc4baSyz147064 		die_dlerr(status, "cannot get link attributes for %s", link);
3878d62bc4baSyz147064 
3879d62bc4baSyz147064 	statep->ws_link = link;
38800ba2cbe9Sxc151355 
38810ba2cbe9Sxc151355 	if (statep->ws_header) {
38820ba2cbe9Sxc151355 		statep->ws_header = B_FALSE;
38830ba2cbe9Sxc151355 		if (!statep->ws_parseable)
3884e7801d59Ssowmini 			print_header(&statep->ws_print_state);
38850ba2cbe9Sxc151355 	}
38860ba2cbe9Sxc151355 
3887e7801d59Ssowmini 	statep->ws_print_state.ps_overflow = 0;
3888e7801d59Ssowmini 	bzero(&warg, sizeof (warg));
3889e7801d59Ssowmini 	warg.ws_state = statep;
3890e7801d59Ssowmini 	warg.ws_attr = &attr;
3891e7801d59Ssowmini 	dladm_print_output(&statep->ws_print_state, statep->ws_parseable,
3892e7801d59Ssowmini 	    print_link_attr, &warg);
3893d62bc4baSyz147064 	return (DLADM_WALK_CONTINUE);
38940ba2cbe9Sxc151355 }
38950ba2cbe9Sxc151355 
38960ba2cbe9Sxc151355 static void
38978d5c46e6Sam223141 do_display_wifi(int argc, char **argv, int cmd, const char *use)
38980ba2cbe9Sxc151355 {
38990ba2cbe9Sxc151355 	int			option;
39000ba2cbe9Sxc151355 	char			*fields_str = NULL;
3901e7801d59Ssowmini 	print_field_t		**fields;
3902d62bc4baSyz147064 	int			(*callback)(datalink_id_t, void *);
39030ba2cbe9Sxc151355 	uint_t			nfields;
39040ba2cbe9Sxc151355 	print_wifi_state_t	state;
3905d62bc4baSyz147064 	datalink_id_t		linkid = DATALINK_ALL_LINKID;
3906f595a68aSyz147064 	dladm_status_t		status;
39070ba2cbe9Sxc151355 
39080ba2cbe9Sxc151355 	if (cmd == WIFI_CMD_SCAN)
39090ba2cbe9Sxc151355 		callback = scan_wifi;
39100ba2cbe9Sxc151355 	else if (cmd == WIFI_CMD_SHOW)
39110ba2cbe9Sxc151355 		callback = show_wifi;
39120ba2cbe9Sxc151355 	else
39130ba2cbe9Sxc151355 		return;
39140ba2cbe9Sxc151355 
39150ba2cbe9Sxc151355 	state.ws_parseable = B_FALSE;
39160ba2cbe9Sxc151355 	state.ws_header = B_TRUE;
39170ba2cbe9Sxc151355 	opterr = 0;
39180ba2cbe9Sxc151355 	while ((option = getopt_long(argc, argv, ":o:p",
39190ba2cbe9Sxc151355 	    wifi_longopts, NULL)) != -1) {
39200ba2cbe9Sxc151355 		switch (option) {
39210ba2cbe9Sxc151355 		case 'o':
39220ba2cbe9Sxc151355 			fields_str = optarg;
39230ba2cbe9Sxc151355 			break;
39240ba2cbe9Sxc151355 		case 'p':
39250ba2cbe9Sxc151355 			state.ws_parseable = B_TRUE;
39260ba2cbe9Sxc151355 			break;
39270ba2cbe9Sxc151355 		default:
39288d5c46e6Sam223141 			die_opterr(optopt, option, use);
39290ba2cbe9Sxc151355 		}
39300ba2cbe9Sxc151355 	}
39310ba2cbe9Sxc151355 
39320d365605Sschuster 	if (state.ws_parseable && fields_str == NULL)
39330d365605Sschuster 		die("-p requires -o");
39340d365605Sschuster 
39350d365605Sschuster 	if (state.ws_parseable && strcasecmp(fields_str, "all") == 0)
39360d365605Sschuster 		die("\"-o all\" is invalid with -p");
39370d365605Sschuster 
3938d62bc4baSyz147064 	if (optind == (argc - 1)) {
3939d62bc4baSyz147064 		if ((status = dladm_name2info(argv[optind], &linkid, NULL,
3940d62bc4baSyz147064 		    NULL, NULL)) != DLADM_STATUS_OK) {
3941d62bc4baSyz147064 			die_dlerr(status, "link %s is not valid", argv[optind]);
3942d62bc4baSyz147064 		}
3943d62bc4baSyz147064 	} else if (optind != argc) {
39440ba2cbe9Sxc151355 		usage();
3945d62bc4baSyz147064 	}
39460ba2cbe9Sxc151355 
394733343a97Smeem 	if (parse_wifi_fields(fields_str, &fields, &nfields, cmd) < 0)
394833343a97Smeem 		die("invalid field(s) specified");
394933343a97Smeem 
3950e7801d59Ssowmini 	bzero(&state.ws_print_state, sizeof (state.ws_print_state));
3951e7801d59Ssowmini 	state.ws_print_state.ps_fields = fields;
3952e7801d59Ssowmini 	state.ws_print_state.ps_nfields = nfields;
39530ba2cbe9Sxc151355 
3954d62bc4baSyz147064 	if (linkid == DATALINK_ALL_LINKID) {
3955d62bc4baSyz147064 		(void) dladm_walk_datalink_id(callback, &state,
3956d62bc4baSyz147064 		    DATALINK_CLASS_PHYS, DL_WIFI, DLADM_OPT_ACTIVE);
39570ba2cbe9Sxc151355 	} else {
3958d62bc4baSyz147064 		(void) (*callback)(linkid, &state);
39590ba2cbe9Sxc151355 	}
39600ba2cbe9Sxc151355 	free(fields);
39610ba2cbe9Sxc151355 }
39620ba2cbe9Sxc151355 
39630ba2cbe9Sxc151355 static void
39648d5c46e6Sam223141 do_scan_wifi(int argc, char **argv, const char *use)
39650ba2cbe9Sxc151355 {
39668d5c46e6Sam223141 	do_display_wifi(argc, argv, WIFI_CMD_SCAN, use);
39670ba2cbe9Sxc151355 }
39680ba2cbe9Sxc151355 
39690ba2cbe9Sxc151355 static void
39708d5c46e6Sam223141 do_show_wifi(int argc, char **argv, const char *use)
39710ba2cbe9Sxc151355 {
39728d5c46e6Sam223141 	do_display_wifi(argc, argv, WIFI_CMD_SHOW, use);
39730ba2cbe9Sxc151355 }
39740ba2cbe9Sxc151355 
39750ba2cbe9Sxc151355 typedef struct wlan_count_attr {
39760ba2cbe9Sxc151355 	uint_t		wc_count;
3977d62bc4baSyz147064 	datalink_id_t	wc_linkid;
39780ba2cbe9Sxc151355 } wlan_count_attr_t;
39790ba2cbe9Sxc151355 
3980d62bc4baSyz147064 static int
3981d62bc4baSyz147064 do_count_wlan(datalink_id_t linkid, void *arg)
39820ba2cbe9Sxc151355 {
398333343a97Smeem 	wlan_count_attr_t *cp = arg;
39840ba2cbe9Sxc151355 
39850ba2cbe9Sxc151355 	if (cp->wc_count == 0)
3986d62bc4baSyz147064 		cp->wc_linkid = linkid;
39870ba2cbe9Sxc151355 	cp->wc_count++;
3988d62bc4baSyz147064 	return (DLADM_WALK_CONTINUE);
39890ba2cbe9Sxc151355 }
39900ba2cbe9Sxc151355 
39910ba2cbe9Sxc151355 static int
3992a399b765Szf162725 parse_wlan_keys(char *str, dladm_wlan_key_t **keys, uint_t *key_countp)
39930ba2cbe9Sxc151355 {
39940ba2cbe9Sxc151355 	uint_t			i;
39950ba2cbe9Sxc151355 	split_t			*sp;
3996a399b765Szf162725 	dladm_wlan_key_t	*wk;
39970ba2cbe9Sxc151355 
3998a399b765Szf162725 	sp = split(str, DLADM_WLAN_MAX_WEPKEYS, DLADM_WLAN_MAX_KEYNAME_LEN);
39990ba2cbe9Sxc151355 	if (sp == NULL)
40000ba2cbe9Sxc151355 		return (-1);
40010ba2cbe9Sxc151355 
4002a399b765Szf162725 	wk = malloc(sp->s_nfields * sizeof (dladm_wlan_key_t));
40030ba2cbe9Sxc151355 	if (wk == NULL)
40040ba2cbe9Sxc151355 		goto fail;
40050ba2cbe9Sxc151355 
40060ba2cbe9Sxc151355 	for (i = 0; i < sp->s_nfields; i++) {
40070ba2cbe9Sxc151355 		char			*s;
40080ba2cbe9Sxc151355 		dladm_secobj_class_t	class;
40090ba2cbe9Sxc151355 		dladm_status_t		status;
40100ba2cbe9Sxc151355 
40110ba2cbe9Sxc151355 		(void) strlcpy(wk[i].wk_name, sp->s_fields[i],
4012a399b765Szf162725 		    DLADM_WLAN_MAX_KEYNAME_LEN);
40130ba2cbe9Sxc151355 
40140ba2cbe9Sxc151355 		wk[i].wk_idx = 1;
40150ba2cbe9Sxc151355 		if ((s = strrchr(wk[i].wk_name, ':')) != NULL) {
40160ba2cbe9Sxc151355 			if (s[1] == '\0' || s[2] != '\0' || !isdigit(s[1]))
40170ba2cbe9Sxc151355 				goto fail;
40180ba2cbe9Sxc151355 
40190ba2cbe9Sxc151355 			wk[i].wk_idx = (uint_t)(s[1] - '0');
40200ba2cbe9Sxc151355 			*s = '\0';
40210ba2cbe9Sxc151355 		}
4022a399b765Szf162725 		wk[i].wk_len = DLADM_WLAN_MAX_KEY_LEN;
40230ba2cbe9Sxc151355 
40240ba2cbe9Sxc151355 		status = dladm_get_secobj(wk[i].wk_name, &class,
40250ba2cbe9Sxc151355 		    wk[i].wk_val, &wk[i].wk_len, 0);
40260ba2cbe9Sxc151355 		if (status != DLADM_STATUS_OK) {
40270ba2cbe9Sxc151355 			if (status == DLADM_STATUS_NOTFOUND) {
40280ba2cbe9Sxc151355 				status = dladm_get_secobj(wk[i].wk_name,
40290ba2cbe9Sxc151355 				    &class, wk[i].wk_val, &wk[i].wk_len,
40300ba2cbe9Sxc151355 				    DLADM_OPT_PERSIST);
40310ba2cbe9Sxc151355 			}
40320ba2cbe9Sxc151355 			if (status != DLADM_STATUS_OK)
40330ba2cbe9Sxc151355 				goto fail;
40340ba2cbe9Sxc151355 		}
4035a399b765Szf162725 		wk[i].wk_class = class;
40360ba2cbe9Sxc151355 	}
40370ba2cbe9Sxc151355 	*keys = wk;
40380ba2cbe9Sxc151355 	*key_countp = i;
40390ba2cbe9Sxc151355 	splitfree(sp);
40400ba2cbe9Sxc151355 	return (0);
40410ba2cbe9Sxc151355 fail:
40420ba2cbe9Sxc151355 	free(wk);
40430ba2cbe9Sxc151355 	splitfree(sp);
40440ba2cbe9Sxc151355 	return (-1);
40450ba2cbe9Sxc151355 }
40460ba2cbe9Sxc151355 
40470ba2cbe9Sxc151355 static void
40488d5c46e6Sam223141 do_connect_wifi(int argc, char **argv, const char *use)
40490ba2cbe9Sxc151355 {
40500ba2cbe9Sxc151355 	int			option;
4051f595a68aSyz147064 	dladm_wlan_attr_t	attr, *attrp;
4052f595a68aSyz147064 	dladm_status_t		status = DLADM_STATUS_OK;
4053f595a68aSyz147064 	int			timeout = DLADM_WLAN_CONNECT_TIMEOUT_DEFAULT;
4054d62bc4baSyz147064 	datalink_id_t		linkid = DATALINK_ALL_LINKID;
4055a399b765Szf162725 	dladm_wlan_key_t	*keys = NULL;
40560ba2cbe9Sxc151355 	uint_t			key_count = 0;
40570ba2cbe9Sxc151355 	uint_t			flags = 0;
4058f595a68aSyz147064 	dladm_wlan_secmode_t	keysecmode = DLADM_WLAN_SECMODE_NONE;
4059a399b765Szf162725 	char			buf[DLADM_STRSIZE];
40600ba2cbe9Sxc151355 
40610ba2cbe9Sxc151355 	opterr = 0;
40620ba2cbe9Sxc151355 	(void) memset(&attr, 0, sizeof (attr));
40630ba2cbe9Sxc151355 	while ((option = getopt_long(argc, argv, ":e:i:a:m:b:s:k:T:c",
40640ba2cbe9Sxc151355 	    wifi_longopts, NULL)) != -1) {
40650ba2cbe9Sxc151355 		switch (option) {
40660ba2cbe9Sxc151355 		case 'e':
4067f595a68aSyz147064 			status = dladm_wlan_str2essid(optarg, &attr.wa_essid);
4068f595a68aSyz147064 			if (status != DLADM_STATUS_OK)
406933343a97Smeem 				die("invalid ESSID '%s'", optarg);
407033343a97Smeem 
4071f595a68aSyz147064 			attr.wa_valid |= DLADM_WLAN_ATTR_ESSID;
40720ba2cbe9Sxc151355 			/*
40730ba2cbe9Sxc151355 			 * Try to connect without doing a scan.
40740ba2cbe9Sxc151355 			 */
4075f595a68aSyz147064 			flags |= DLADM_WLAN_CONNECT_NOSCAN;
40760ba2cbe9Sxc151355 			break;
40770ba2cbe9Sxc151355 		case 'i':
4078f595a68aSyz147064 			status = dladm_wlan_str2bssid(optarg, &attr.wa_bssid);
4079f595a68aSyz147064 			if (status != DLADM_STATUS_OK)
408033343a97Smeem 				die("invalid BSSID %s", optarg);
408133343a97Smeem 
4082f595a68aSyz147064 			attr.wa_valid |= DLADM_WLAN_ATTR_BSSID;
40830ba2cbe9Sxc151355 			break;
40840ba2cbe9Sxc151355 		case 'a':
4085f595a68aSyz147064 			status = dladm_wlan_str2auth(optarg, &attr.wa_auth);
4086f595a68aSyz147064 			if (status != DLADM_STATUS_OK)
408733343a97Smeem 				die("invalid authentication mode '%s'", optarg);
408833343a97Smeem 
4089f595a68aSyz147064 			attr.wa_valid |= DLADM_WLAN_ATTR_AUTH;
40900ba2cbe9Sxc151355 			break;
40910ba2cbe9Sxc151355 		case 'm':
4092f595a68aSyz147064 			status = dladm_wlan_str2mode(optarg, &attr.wa_mode);
4093f595a68aSyz147064 			if (status != DLADM_STATUS_OK)
409433343a97Smeem 				die("invalid mode '%s'", optarg);
409533343a97Smeem 
4096f595a68aSyz147064 			attr.wa_valid |= DLADM_WLAN_ATTR_MODE;
40970ba2cbe9Sxc151355 			break;
40980ba2cbe9Sxc151355 		case 'b':
4099f595a68aSyz147064 			if ((status = dladm_wlan_str2bsstype(optarg,
4100f595a68aSyz147064 			    &attr.wa_bsstype)) != DLADM_STATUS_OK) {
410133343a97Smeem 				die("invalid bsstype '%s'", optarg);
4102f595a68aSyz147064 			}
410333343a97Smeem 
4104f595a68aSyz147064 			attr.wa_valid |= DLADM_WLAN_ATTR_BSSTYPE;
41050ba2cbe9Sxc151355 			break;
41060ba2cbe9Sxc151355 		case 's':
4107f595a68aSyz147064 			if ((status = dladm_wlan_str2secmode(optarg,
4108f595a68aSyz147064 			    &attr.wa_secmode)) != DLADM_STATUS_OK) {
410933343a97Smeem 				die("invalid security mode '%s'", optarg);
4110f595a68aSyz147064 			}
411133343a97Smeem 
4112f595a68aSyz147064 			attr.wa_valid |= DLADM_WLAN_ATTR_SECMODE;
41130ba2cbe9Sxc151355 			break;
41140ba2cbe9Sxc151355 		case 'k':
4115a399b765Szf162725 			if (parse_wlan_keys(optarg, &keys, &key_count) < 0)
411633343a97Smeem 				die("invalid key(s) '%s'", optarg);
411733343a97Smeem 
4118a399b765Szf162725 			if (keys[0].wk_class == DLADM_SECOBJ_CLASS_WEP)
4119f595a68aSyz147064 				keysecmode = DLADM_WLAN_SECMODE_WEP;
4120a399b765Szf162725 			else
4121a399b765Szf162725 				keysecmode = DLADM_WLAN_SECMODE_WPA;
41220ba2cbe9Sxc151355 			break;
41230ba2cbe9Sxc151355 		case 'T':
41240ba2cbe9Sxc151355 			if (strcasecmp(optarg, "forever") == 0) {
41250ba2cbe9Sxc151355 				timeout = -1;
41260ba2cbe9Sxc151355 				break;
41270ba2cbe9Sxc151355 			}
412833343a97Smeem 			if (!str2int(optarg, &timeout) || timeout < 0)
412933343a97Smeem 				die("invalid timeout value '%s'", optarg);
41300ba2cbe9Sxc151355 			break;
41310ba2cbe9Sxc151355 		case 'c':
4132f595a68aSyz147064 			flags |= DLADM_WLAN_CONNECT_CREATEIBSS;
4133a399b765Szf162725 			flags |= DLADM_WLAN_CONNECT_CREATEIBSS;
41340ba2cbe9Sxc151355 			break;
41350ba2cbe9Sxc151355 		default:
41368d5c46e6Sam223141 			die_opterr(optopt, option, use);
41370ba2cbe9Sxc151355 			break;
41380ba2cbe9Sxc151355 		}
41390ba2cbe9Sxc151355 	}
41400ba2cbe9Sxc151355 
4141f595a68aSyz147064 	if (keysecmode == DLADM_WLAN_SECMODE_NONE) {
4142a399b765Szf162725 		if ((attr.wa_valid & DLADM_WLAN_ATTR_SECMODE) != 0) {
4143a399b765Szf162725 			die("key required for security mode '%s'",
4144a399b765Szf162725 			    dladm_wlan_secmode2str(&attr.wa_secmode, buf));
4145a399b765Szf162725 		}
41460ba2cbe9Sxc151355 	} else {
4147f595a68aSyz147064 		if ((attr.wa_valid & DLADM_WLAN_ATTR_SECMODE) != 0 &&
414833343a97Smeem 		    attr.wa_secmode != keysecmode)
414933343a97Smeem 			die("incompatible -s and -k options");
4150f595a68aSyz147064 		attr.wa_valid |= DLADM_WLAN_ATTR_SECMODE;
4151a399b765Szf162725 		attr.wa_secmode = keysecmode;
4152a399b765Szf162725 	}
41530ba2cbe9Sxc151355 
4154d62bc4baSyz147064 	if (optind == (argc - 1)) {
4155d62bc4baSyz147064 		if ((status = dladm_name2info(argv[optind], &linkid, NULL,
4156d62bc4baSyz147064 		    NULL, NULL)) != DLADM_STATUS_OK) {
4157d62bc4baSyz147064 			die_dlerr(status, "link %s is not valid", argv[optind]);
4158d62bc4baSyz147064 		}
4159d62bc4baSyz147064 	} else if (optind != argc) {
41600ba2cbe9Sxc151355 		usage();
4161d62bc4baSyz147064 	}
41620ba2cbe9Sxc151355 
4163d62bc4baSyz147064 	if (linkid == DATALINK_ALL_LINKID) {
41640ba2cbe9Sxc151355 		wlan_count_attr_t wcattr;
41650ba2cbe9Sxc151355 
4166d62bc4baSyz147064 		wcattr.wc_linkid = DATALINK_INVALID_LINKID;
41670ba2cbe9Sxc151355 		wcattr.wc_count = 0;
4168d62bc4baSyz147064 		(void) dladm_walk_datalink_id(do_count_wlan, &wcattr,
4169d62bc4baSyz147064 		    DATALINK_CLASS_PHYS, DL_WIFI, DLADM_OPT_ACTIVE);
41700ba2cbe9Sxc151355 		if (wcattr.wc_count == 0) {
417133343a97Smeem 			die("no wifi links are available");
41720ba2cbe9Sxc151355 		} else if (wcattr.wc_count > 1) {
417333343a97Smeem 			die("link name is required when more than one wifi "
417433343a97Smeem 			    "link is available");
41750ba2cbe9Sxc151355 		}
4176d62bc4baSyz147064 		linkid = wcattr.wc_linkid;
41770ba2cbe9Sxc151355 	}
41780ba2cbe9Sxc151355 	attrp = (attr.wa_valid == 0) ? NULL : &attr;
417933343a97Smeem again:
4180d62bc4baSyz147064 	if ((status = dladm_wlan_connect(linkid, attrp, timeout, keys,
4181f595a68aSyz147064 	    key_count, flags)) != DLADM_STATUS_OK) {
4182f595a68aSyz147064 		if ((flags & DLADM_WLAN_CONNECT_NOSCAN) != 0) {
41830ba2cbe9Sxc151355 			/*
418433343a97Smeem 			 * Try again with scanning and filtering.
41850ba2cbe9Sxc151355 			 */
4186f595a68aSyz147064 			flags &= ~DLADM_WLAN_CONNECT_NOSCAN;
418733343a97Smeem 			goto again;
41880ba2cbe9Sxc151355 		}
418933343a97Smeem 
4190f595a68aSyz147064 		if (status == DLADM_STATUS_NOTFOUND) {
41910ba2cbe9Sxc151355 			if (attr.wa_valid == 0) {
419233343a97Smeem 				die("no wifi networks are available");
41930ba2cbe9Sxc151355 			} else {
419433343a97Smeem 				die("no wifi networks with the specified "
419533343a97Smeem 				    "criteria are available");
41960ba2cbe9Sxc151355 			}
41970ba2cbe9Sxc151355 		}
4198d62bc4baSyz147064 		die_dlerr(status, "cannot connect");
41990ba2cbe9Sxc151355 	}
42000ba2cbe9Sxc151355 	free(keys);
42010ba2cbe9Sxc151355 }
42020ba2cbe9Sxc151355 
42030ba2cbe9Sxc151355 /* ARGSUSED */
4204d62bc4baSyz147064 static int
4205d62bc4baSyz147064 do_all_disconnect_wifi(datalink_id_t linkid, void *arg)
42060ba2cbe9Sxc151355 {
4207f595a68aSyz147064 	dladm_status_t	status;
42080ba2cbe9Sxc151355 
4209d62bc4baSyz147064 	status = dladm_wlan_disconnect(linkid);
4210f595a68aSyz147064 	if (status != DLADM_STATUS_OK)
4211d62bc4baSyz147064 		warn_dlerr(status, "cannot disconnect link");
421233343a97Smeem 
4213d62bc4baSyz147064 	return (DLADM_WALK_CONTINUE);
42140ba2cbe9Sxc151355 }
42150ba2cbe9Sxc151355 
42160ba2cbe9Sxc151355 static void
42178d5c46e6Sam223141 do_disconnect_wifi(int argc, char **argv, const char *use)
42180ba2cbe9Sxc151355 {
42190ba2cbe9Sxc151355 	int			option;
4220d62bc4baSyz147064 	datalink_id_t		linkid = DATALINK_ALL_LINKID;
42210ba2cbe9Sxc151355 	boolean_t		all_links = B_FALSE;
4222f595a68aSyz147064 	dladm_status_t		status;
42230ba2cbe9Sxc151355 	wlan_count_attr_t	wcattr;
42240ba2cbe9Sxc151355 
42250ba2cbe9Sxc151355 	opterr = 0;
42260ba2cbe9Sxc151355 	while ((option = getopt_long(argc, argv, ":a",
42270ba2cbe9Sxc151355 	    wifi_longopts, NULL)) != -1) {
42280ba2cbe9Sxc151355 		switch (option) {
42290ba2cbe9Sxc151355 		case 'a':
42300ba2cbe9Sxc151355 			all_links = B_TRUE;
42310ba2cbe9Sxc151355 			break;
42320ba2cbe9Sxc151355 		default:
42338d5c46e6Sam223141 			die_opterr(optopt, option, use);
42340ba2cbe9Sxc151355 			break;
42350ba2cbe9Sxc151355 		}
42360ba2cbe9Sxc151355 	}
42370ba2cbe9Sxc151355 
4238d62bc4baSyz147064 	if (optind == (argc - 1)) {
4239d62bc4baSyz147064 		if ((status = dladm_name2info(argv[optind], &linkid, NULL,
4240d62bc4baSyz147064 		    NULL, NULL)) != DLADM_STATUS_OK) {
4241d62bc4baSyz147064 			die_dlerr(status, "link %s is not valid", argv[optind]);
4242d62bc4baSyz147064 		}
4243d62bc4baSyz147064 	} else if (optind != argc) {
42440ba2cbe9Sxc151355 		usage();
4245d62bc4baSyz147064 	}
42460ba2cbe9Sxc151355 
4247d62bc4baSyz147064 	if (linkid == DATALINK_ALL_LINKID) {
42480ba2cbe9Sxc151355 		if (!all_links) {
4249d62bc4baSyz147064 			wcattr.wc_linkid = linkid;
42500ba2cbe9Sxc151355 			wcattr.wc_count = 0;
4251d62bc4baSyz147064 			(void) dladm_walk_datalink_id(do_count_wlan, &wcattr,
4252d62bc4baSyz147064 			    DATALINK_CLASS_PHYS, DL_WIFI, DLADM_OPT_ACTIVE);
42530ba2cbe9Sxc151355 			if (wcattr.wc_count == 0) {
425433343a97Smeem 				die("no wifi links are available");
42550ba2cbe9Sxc151355 			} else if (wcattr.wc_count > 1) {
425633343a97Smeem 				die("link name is required when more than "
425733343a97Smeem 				    "one wifi link is available");
42580ba2cbe9Sxc151355 			}
4259d62bc4baSyz147064 			linkid = wcattr.wc_linkid;
42600ba2cbe9Sxc151355 		} else {
4261d62bc4baSyz147064 			(void) dladm_walk_datalink_id(do_all_disconnect_wifi,
4262d62bc4baSyz147064 			    NULL, DATALINK_CLASS_PHYS, DL_WIFI,
4263d62bc4baSyz147064 			    DLADM_OPT_ACTIVE);
42640ba2cbe9Sxc151355 			return;
42650ba2cbe9Sxc151355 		}
42660ba2cbe9Sxc151355 	}
4267d62bc4baSyz147064 	status = dladm_wlan_disconnect(linkid);
4268f595a68aSyz147064 	if (status != DLADM_STATUS_OK)
4269d62bc4baSyz147064 		die_dlerr(status, "cannot disconnect");
42700ba2cbe9Sxc151355 }
42710ba2cbe9Sxc151355 
42720ba2cbe9Sxc151355 
42730ba2cbe9Sxc151355 static void
42740ba2cbe9Sxc151355 free_props(prop_list_t *list)
42750ba2cbe9Sxc151355 {
42760ba2cbe9Sxc151355 	if (list != NULL) {
42770ba2cbe9Sxc151355 		free(list->pl_buf);
42780ba2cbe9Sxc151355 		free(list);
42790ba2cbe9Sxc151355 	}
42800ba2cbe9Sxc151355 }
42810ba2cbe9Sxc151355 
42820ba2cbe9Sxc151355 static int
42830ba2cbe9Sxc151355 parse_props(char *str, prop_list_t **listp, boolean_t novalues)
42840ba2cbe9Sxc151355 {
42850ba2cbe9Sxc151355 	prop_list_t	*list;
42860ba2cbe9Sxc151355 	prop_info_t	*pip;
42870ba2cbe9Sxc151355 	char		*buf, *curr;
42880ba2cbe9Sxc151355 	int		len, i;
42890ba2cbe9Sxc151355 
42900ba2cbe9Sxc151355 	list = malloc(sizeof (prop_list_t));
42910ba2cbe9Sxc151355 	if (list == NULL)
42920ba2cbe9Sxc151355 		return (-1);
42930ba2cbe9Sxc151355 
42940ba2cbe9Sxc151355 	list->pl_count = 0;
42950ba2cbe9Sxc151355 	list->pl_buf = buf = strdup(str);
42960ba2cbe9Sxc151355 	if (buf == NULL)
42970ba2cbe9Sxc151355 		goto fail;
42980ba2cbe9Sxc151355 
4299e7801d59Ssowmini 	/*
4300e7801d59Ssowmini 	 * buf is a string of form [<propname>=<value>][,<propname>=<value>]+
4301e7801d59Ssowmini 	 * where each <value> string itself could be a comma-separated array.
4302e7801d59Ssowmini 	 * The loop below will count the number of propname assignments
4303e7801d59Ssowmini 	 * in pl_count; for each property, there is a pip entry with
4304e7801d59Ssowmini 	 * pi_name == <propname>, pi_count == # of elements in <value> array.
4305e7801d59Ssowmini 	 * pi_val[] contains the actual values.
4306e7801d59Ssowmini 	 *
4307e7801d59Ssowmini 	 * This could really be a combination of  calls to
4308e7801d59Ssowmini 	 * strtok (token delimiter is ",") and strchr (chr '=')
4309e7801d59Ssowmini 	 * with appropriate null/string-bound-checks.
4310e7801d59Ssowmini 	 */
4311e7801d59Ssowmini 
43120ba2cbe9Sxc151355 	curr = buf;
43130ba2cbe9Sxc151355 	len = strlen(buf);
43140ba2cbe9Sxc151355 	pip = NULL;
43150ba2cbe9Sxc151355 	for (i = 0; i < len; i++) {
43160ba2cbe9Sxc151355 		char		c = buf[i];
43170ba2cbe9Sxc151355 		boolean_t	match = (c == '=' || c == ',');
43180ba2cbe9Sxc151355 
43190ba2cbe9Sxc151355 		if (!match && i != len - 1)
43200ba2cbe9Sxc151355 			continue;
43210ba2cbe9Sxc151355 
43220ba2cbe9Sxc151355 		if (match) {
43230ba2cbe9Sxc151355 			buf[i] = '\0';
43240ba2cbe9Sxc151355 			if (*curr == '\0')
43250ba2cbe9Sxc151355 				goto fail;
43260ba2cbe9Sxc151355 		}
43270ba2cbe9Sxc151355 
43280ba2cbe9Sxc151355 		if (pip != NULL && c != '=') {
4329d62bc4baSyz147064 			if (pip->pi_count > DLADM_MAX_PROP_VALCNT)
43300ba2cbe9Sxc151355 				goto fail;
43310ba2cbe9Sxc151355 
43320ba2cbe9Sxc151355 			if (novalues)
43330ba2cbe9Sxc151355 				goto fail;
43340ba2cbe9Sxc151355 
43350ba2cbe9Sxc151355 			pip->pi_val[pip->pi_count] = curr;
43360ba2cbe9Sxc151355 			pip->pi_count++;
43370ba2cbe9Sxc151355 		} else {
43380ba2cbe9Sxc151355 			if (list->pl_count > MAX_PROPS)
43390ba2cbe9Sxc151355 				goto fail;
43400ba2cbe9Sxc151355 
43410ba2cbe9Sxc151355 			pip = &list->pl_info[list->pl_count];
43420ba2cbe9Sxc151355 			pip->pi_name = curr;
43430ba2cbe9Sxc151355 			pip->pi_count = 0;
43440ba2cbe9Sxc151355 			list->pl_count++;
43450ba2cbe9Sxc151355 			if (c == ',')
43460ba2cbe9Sxc151355 				pip = NULL;
43470ba2cbe9Sxc151355 		}
43480ba2cbe9Sxc151355 		curr = buf + i + 1;
43490ba2cbe9Sxc151355 	}
43500ba2cbe9Sxc151355 	*listp = list;
43510ba2cbe9Sxc151355 	return (0);
43520ba2cbe9Sxc151355 
43530ba2cbe9Sxc151355 fail:
43540ba2cbe9Sxc151355 	free_props(list);
43550ba2cbe9Sxc151355 	return (-1);
43560ba2cbe9Sxc151355 }
43570ba2cbe9Sxc151355 
43580ba2cbe9Sxc151355 static void
4359d62bc4baSyz147064 print_linkprop(datalink_id_t linkid, show_linkprop_state_t *statep,
4360e7801d59Ssowmini     const char *propname, dladm_prop_type_t type,
4361d62bc4baSyz147064     const char *format, char **pptr)
43620ba2cbe9Sxc151355 {
43630ba2cbe9Sxc151355 	int		i;
43640ba2cbe9Sxc151355 	char		*ptr, *lim;
43650ba2cbe9Sxc151355 	char		buf[DLADM_STRSIZE];
43660ba2cbe9Sxc151355 	char		*unknown = "?", *notsup = "";
43670ba2cbe9Sxc151355 	char		**propvals = statep->ls_propvals;
4368d62bc4baSyz147064 	uint_t		valcnt = DLADM_MAX_PROP_VALCNT;
43690ba2cbe9Sxc151355 	dladm_status_t	status;
43700ba2cbe9Sxc151355 
4371d62bc4baSyz147064 	status = dladm_get_linkprop(linkid, type, propname, propvals, &valcnt);
43720ba2cbe9Sxc151355 	if (status != DLADM_STATUS_OK) {
4373f595a68aSyz147064 		if (status == DLADM_STATUS_TEMPONLY) {
4374d62bc4baSyz147064 			if (type == DLADM_PROP_VAL_MODIFIABLE &&
4375d62bc4baSyz147064 			    statep->ls_persist) {
4376d62bc4baSyz147064 				valcnt = 1;
4377d62bc4baSyz147064 				propvals = &unknown;
4378d62bc4baSyz147064 			} else {
4379f595a68aSyz147064 				statep->ls_status = status;
4380e7801d59Ssowmini 				statep->ls_retstatus = status;
4381f595a68aSyz147064 				return;
4382d62bc4baSyz147064 			}
4383f595a68aSyz147064 		} else if (status == DLADM_STATUS_NOTSUP ||
4384f595a68aSyz147064 		    statep->ls_persist) {
43850ba2cbe9Sxc151355 			valcnt = 1;
43860ba2cbe9Sxc151355 			if (type == DLADM_PROP_VAL_CURRENT)
43870ba2cbe9Sxc151355 				propvals = &unknown;
43880ba2cbe9Sxc151355 			else
43890ba2cbe9Sxc151355 				propvals = &notsup;
4390*149b7eb2SSowmini Varadhan 		} else if (status == DLADM_STATUS_NOTDEFINED) {
4391*149b7eb2SSowmini Varadhan 			propvals = &notsup; /* STR_UNDEF_VAL */
43920ba2cbe9Sxc151355 		} else {
4393e7801d59Ssowmini 			if (statep->ls_proplist &&
4394e7801d59Ssowmini 			    statep->ls_status == DLADM_STATUS_OK) {
4395f595a68aSyz147064 				warn_dlerr(status,
4396f595a68aSyz147064 				    "cannot get link property '%s' for %s",
4397f595a68aSyz147064 				    propname, statep->ls_link);
4398d62bc4baSyz147064 			}
4399e7801d59Ssowmini 			statep->ls_status = status;
4400e7801d59Ssowmini 			statep->ls_retstatus = status;
4401f595a68aSyz147064 			return;
44020ba2cbe9Sxc151355 		}
44030ba2cbe9Sxc151355 	}
44040ba2cbe9Sxc151355 
4405e7801d59Ssowmini 	statep->ls_status = DLADM_STATUS_OK;
4406e7801d59Ssowmini 
44070ba2cbe9Sxc151355 	ptr = buf;
44080ba2cbe9Sxc151355 	lim = buf + DLADM_STRSIZE;
44090ba2cbe9Sxc151355 	for (i = 0; i < valcnt; i++) {
44100ba2cbe9Sxc151355 		if (propvals[i][0] == '\0' && !statep->ls_parseable)
4411e7801d59Ssowmini 			ptr += snprintf(ptr, lim - ptr, STR_UNDEF_VAL",");
44120ba2cbe9Sxc151355 		else
44130ba2cbe9Sxc151355 			ptr += snprintf(ptr, lim - ptr, "%s,", propvals[i]);
44140ba2cbe9Sxc151355 		if (ptr >= lim)
44150ba2cbe9Sxc151355 			break;
44160ba2cbe9Sxc151355 	}
44170ba2cbe9Sxc151355 	if (valcnt > 0)
44180ba2cbe9Sxc151355 		buf[strlen(buf) - 1] = '\0';
44190ba2cbe9Sxc151355 
44200ba2cbe9Sxc151355 	lim = statep->ls_line + MAX_PROP_LINE;
44210ba2cbe9Sxc151355 	if (statep->ls_parseable) {
44220ba2cbe9Sxc151355 		*pptr += snprintf(*pptr, lim - *pptr,
4423e7801d59Ssowmini 		    "%s", buf);
44240ba2cbe9Sxc151355 	} else {
44250ba2cbe9Sxc151355 		*pptr += snprintf(*pptr, lim - *pptr, format, buf);
44260ba2cbe9Sxc151355 	}
44270ba2cbe9Sxc151355 }
44280ba2cbe9Sxc151355 
4429e7801d59Ssowmini static char *
4430e7801d59Ssowmini linkprop_callback(print_field_t *pf, void *ls_arg)
4431e7801d59Ssowmini {
4432e7801d59Ssowmini 	linkprop_args_t		*arg = ls_arg;
4433e7801d59Ssowmini 	char 			*propname = arg->ls_propname;
4434e7801d59Ssowmini 	show_linkprop_state_t	*statep = arg->ls_state;
4435e7801d59Ssowmini 	char			*ptr = statep->ls_line;
4436e7801d59Ssowmini 	char			*lim = ptr + MAX_PROP_LINE;
4437e7801d59Ssowmini 	datalink_id_t		linkid = arg->ls_linkid;
4438e7801d59Ssowmini 
4439e7801d59Ssowmini 	switch (pf->pf_index) {
4440e7801d59Ssowmini 	case LINKPROP_LINK:
4441e7801d59Ssowmini 		(void) snprintf(ptr, lim - ptr, "%s", statep->ls_link);
4442e7801d59Ssowmini 		break;
4443e7801d59Ssowmini 	case LINKPROP_PROPERTY:
4444e7801d59Ssowmini 		(void) snprintf(ptr, lim - ptr, "%s", propname);
4445e7801d59Ssowmini 		break;
4446e7801d59Ssowmini 	case LINKPROP_VALUE:
4447e7801d59Ssowmini 		print_linkprop(linkid, statep, propname,
4448e7801d59Ssowmini 		    statep->ls_persist ? DLADM_PROP_VAL_PERSISTENT :
4449e7801d59Ssowmini 		    DLADM_PROP_VAL_CURRENT, "%s", &ptr);
4450e7801d59Ssowmini 		/*
4451e7801d59Ssowmini 		 * If we failed to query the link property, for example, query
4452e7801d59Ssowmini 		 * the persistent value of a non-persistable link property,
4453e7801d59Ssowmini 		 * simply skip the output.
4454e7801d59Ssowmini 		 */
4455e7801d59Ssowmini 		if (statep->ls_status != DLADM_STATUS_OK)
4456e7801d59Ssowmini 			goto skip;
4457e7801d59Ssowmini 		ptr = statep->ls_line;
4458e7801d59Ssowmini 		break;
4459e7801d59Ssowmini 	case LINKPROP_DEFAULT:
4460e7801d59Ssowmini 		print_linkprop(linkid, statep, propname,
4461e7801d59Ssowmini 		    DLADM_PROP_VAL_DEFAULT, "%s", &ptr);
4462e7801d59Ssowmini 		if (statep->ls_status != DLADM_STATUS_OK)
4463e7801d59Ssowmini 			goto skip;
4464e7801d59Ssowmini 		ptr = statep->ls_line;
4465e7801d59Ssowmini 		break;
4466e7801d59Ssowmini 	case LINKPROP_POSSIBLE:
4467e7801d59Ssowmini 		print_linkprop(linkid, statep, propname,
4468e7801d59Ssowmini 		    DLADM_PROP_VAL_MODIFIABLE, "%s ", &ptr);
4469e7801d59Ssowmini 		if (statep->ls_status != DLADM_STATUS_OK)
4470e7801d59Ssowmini 			goto skip;
4471e7801d59Ssowmini 		ptr = statep->ls_line;
4472e7801d59Ssowmini 		break;
4473e7801d59Ssowmini 	default:
4474e7801d59Ssowmini 		die("invalid input");
4475e7801d59Ssowmini 		break;
4476e7801d59Ssowmini 	}
4477e7801d59Ssowmini 	return (ptr);
4478e7801d59Ssowmini skip:
4479e7801d59Ssowmini 	if (statep->ls_status != DLADM_STATUS_OK)
4480e7801d59Ssowmini 		return (NULL);
4481e7801d59Ssowmini 	else
4482e7801d59Ssowmini 		return ("");
4483e7801d59Ssowmini }
4484e7801d59Ssowmini 
4485bcb5c89dSSowmini Varadhan static boolean_t
4486bcb5c89dSSowmini Varadhan linkprop_is_supported(datalink_id_t  linkid, const char *propname,
4487bcb5c89dSSowmini Varadhan     show_linkprop_state_t *statep)
4488bcb5c89dSSowmini Varadhan {
4489bcb5c89dSSowmini Varadhan 	dladm_status_t	status;
4490bcb5c89dSSowmini Varadhan 	uint_t		valcnt = DLADM_MAX_PROP_VALCNT;
4491bcb5c89dSSowmini Varadhan 
4492bcb5c89dSSowmini Varadhan 	status = dladm_get_linkprop(linkid, DLADM_PROP_VAL_DEFAULT,
4493bcb5c89dSSowmini Varadhan 	    propname, statep->ls_propvals, &valcnt);
4494bcb5c89dSSowmini Varadhan 
4495*149b7eb2SSowmini Varadhan 	if (status == DLADM_STATUS_OK)
4496*149b7eb2SSowmini Varadhan 		return (B_TRUE);
4497*149b7eb2SSowmini Varadhan 
4498*149b7eb2SSowmini Varadhan 	/*
4499*149b7eb2SSowmini Varadhan 	 * A system wide default value is not available for the
4500*149b7eb2SSowmini Varadhan 	 * property. Check if current value can be retrieved.
4501*149b7eb2SSowmini Varadhan 	 */
4502*149b7eb2SSowmini Varadhan 	status = dladm_get_linkprop(linkid, DLADM_PROP_VAL_CURRENT,
4503*149b7eb2SSowmini Varadhan 	    propname, statep->ls_propvals, &valcnt);
4504*149b7eb2SSowmini Varadhan 
4505*149b7eb2SSowmini Varadhan 	return (status == DLADM_STATUS_OK);
4506bcb5c89dSSowmini Varadhan }
4507bcb5c89dSSowmini Varadhan 
4508d62bc4baSyz147064 static int
4509d62bc4baSyz147064 show_linkprop(datalink_id_t linkid, const char *propname, void *arg)
45100ba2cbe9Sxc151355 {
45110ba2cbe9Sxc151355 	show_linkprop_state_t	*statep = arg;
4512e7801d59Ssowmini 	linkprop_args_t		ls_arg;
45130ba2cbe9Sxc151355 
4514e7801d59Ssowmini 	bzero(&ls_arg, sizeof (ls_arg));
4515e7801d59Ssowmini 	ls_arg.ls_state = statep;
4516e7801d59Ssowmini 	ls_arg.ls_propname = (char *)propname;
4517e7801d59Ssowmini 	ls_arg.ls_linkid = linkid;
45180ba2cbe9Sxc151355 
45190ba2cbe9Sxc151355 	if (statep->ls_header) {
45200ba2cbe9Sxc151355 		statep->ls_header = B_FALSE;
45210ba2cbe9Sxc151355 		if (!statep->ls_parseable)
4522e7801d59Ssowmini 			print_header(&statep->ls_print);
45230ba2cbe9Sxc151355 	}
4524*149b7eb2SSowmini Varadhan 	if (!statep->ls_parseable &&
4525*149b7eb2SSowmini Varadhan 	    !linkprop_is_supported(linkid, propname, statep))
4526bcb5c89dSSowmini Varadhan 		return (DLADM_WALK_CONTINUE);
4527bcb5c89dSSowmini Varadhan 
4528e7801d59Ssowmini 	dladm_print_output(&statep->ls_print, statep->ls_parseable,
4529e7801d59Ssowmini 	    linkprop_callback, (void *)&ls_arg);
4530e7801d59Ssowmini 
4531d62bc4baSyz147064 	return (DLADM_WALK_CONTINUE);
45320ba2cbe9Sxc151355 }
45330ba2cbe9Sxc151355 
45340ba2cbe9Sxc151355 static void
45358d5c46e6Sam223141 do_show_linkprop(int argc, char **argv, const char *use)
45360ba2cbe9Sxc151355 {
4537f4b3ec61Sdh155122 	int			option;
45380ba2cbe9Sxc151355 	prop_list_t		*proplist = NULL;
4539d62bc4baSyz147064 	datalink_id_t		linkid = DATALINK_ALL_LINKID;
45400ba2cbe9Sxc151355 	show_linkprop_state_t	state;
4541d62bc4baSyz147064 	uint32_t		flags = DLADM_OPT_ACTIVE;
4542d62bc4baSyz147064 	dladm_status_t		status;
4543e7801d59Ssowmini 	char			*fields_str = NULL;
4544e7801d59Ssowmini 	print_field_t		**fields;
4545e7801d59Ssowmini 	uint_t			nfields;
45460d365605Sschuster 	boolean_t		o_arg = B_FALSE;
4547e7801d59Ssowmini 	char			*all_fields =
4548e7801d59Ssowmini 	    "link,property,value,default,possible";
4549e7801d59Ssowmini 
4550e7801d59Ssowmini 	fields_str = all_fields;
45510ba2cbe9Sxc151355 
45520ba2cbe9Sxc151355 	opterr = 0;
45530ba2cbe9Sxc151355 	state.ls_propvals = NULL;
45540ba2cbe9Sxc151355 	state.ls_line = NULL;
45550ba2cbe9Sxc151355 	state.ls_parseable = B_FALSE;
45560ba2cbe9Sxc151355 	state.ls_persist = B_FALSE;
45570ba2cbe9Sxc151355 	state.ls_header = B_TRUE;
4558e7801d59Ssowmini 	state.ls_retstatus = DLADM_STATUS_OK;
4559e7801d59Ssowmini 	while ((option = getopt_long(argc, argv, ":p:cPo:",
45600ba2cbe9Sxc151355 	    prop_longopts, NULL)) != -1) {
45610ba2cbe9Sxc151355 		switch (option) {
45620ba2cbe9Sxc151355 		case 'p':
456333343a97Smeem 			if (parse_props(optarg, &proplist, B_TRUE) < 0)
456413994ee8Sxz162242 				die("invalid link properties specified");
45650ba2cbe9Sxc151355 			break;
45660ba2cbe9Sxc151355 		case 'c':
45670ba2cbe9Sxc151355 			state.ls_parseable = B_TRUE;
45680ba2cbe9Sxc151355 			break;
45690ba2cbe9Sxc151355 		case 'P':
45700ba2cbe9Sxc151355 			state.ls_persist = B_TRUE;
4571d62bc4baSyz147064 			flags = DLADM_OPT_PERSIST;
45720ba2cbe9Sxc151355 			break;
4573e7801d59Ssowmini 		case 'o':
45740d365605Sschuster 			o_arg = B_TRUE;
4575e7801d59Ssowmini 			if (strcasecmp(optarg, "all") == 0)
4576e7801d59Ssowmini 				fields_str = all_fields;
4577e7801d59Ssowmini 			else
4578e7801d59Ssowmini 				fields_str = optarg;
4579e7801d59Ssowmini 			break;
45800ba2cbe9Sxc151355 		default:
45818d5c46e6Sam223141 			die_opterr(optopt, option, use);
45820ba2cbe9Sxc151355 			break;
45830ba2cbe9Sxc151355 		}
45840ba2cbe9Sxc151355 	}
45850ba2cbe9Sxc151355 
45860d365605Sschuster 	if (state.ls_parseable && !o_arg)
45870d365605Sschuster 		die("-c requires -o");
45880d365605Sschuster 
45890d365605Sschuster 	if (state.ls_parseable && fields_str == all_fields)
45900d365605Sschuster 		die("\"-o all\" is invalid with -c");
45910d365605Sschuster 
4592d62bc4baSyz147064 	if (optind == (argc - 1)) {
4593d62bc4baSyz147064 		if ((status = dladm_name2info(argv[optind], &linkid, NULL,
4594d62bc4baSyz147064 		    NULL, NULL)) != DLADM_STATUS_OK) {
4595d62bc4baSyz147064 			die_dlerr(status, "link %s is not valid", argv[optind]);
4596d62bc4baSyz147064 		}
4597d62bc4baSyz147064 	} else if (optind != argc) {
45980ba2cbe9Sxc151355 		usage();
4599d62bc4baSyz147064 	}
46000ba2cbe9Sxc151355 
4601e7801d59Ssowmini 	bzero(&state.ls_print, sizeof (print_state_t));
4602f4b3ec61Sdh155122 	state.ls_proplist = proplist;
4603f595a68aSyz147064 	state.ls_status = DLADM_STATUS_OK;
4604f4b3ec61Sdh155122 
4605e7801d59Ssowmini 	fields = parse_output_fields(fields_str, linkprop_fields,
4606e7801d59Ssowmini 	    LINKPROP_MAX_FIELDS, CMD_TYPE_ANY, &nfields);
4607e7801d59Ssowmini 
4608e7801d59Ssowmini 	if (fields == NULL) {
4609e7801d59Ssowmini 		die("invalid field(s) specified");
4610e7801d59Ssowmini 		return;
4611e7801d59Ssowmini 	}
4612e7801d59Ssowmini 
4613e7801d59Ssowmini 	state.ls_print.ps_fields = fields;
4614e7801d59Ssowmini 	state.ls_print.ps_nfields = nfields;
4615d62bc4baSyz147064 	if (linkid == DATALINK_ALL_LINKID) {
4616d62bc4baSyz147064 		(void) dladm_walk_datalink_id(show_linkprop_onelink, &state,
4617d62bc4baSyz147064 		    DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE, flags);
4618f4b3ec61Sdh155122 	} else {
4619d62bc4baSyz147064 		(void) show_linkprop_onelink(linkid, &state);
4620f4b3ec61Sdh155122 	}
4621f4b3ec61Sdh155122 	free_props(proplist);
4622f595a68aSyz147064 
4623e7801d59Ssowmini 	if (state.ls_retstatus != DLADM_STATUS_OK)
4624f595a68aSyz147064 		exit(EXIT_FAILURE);
4625f4b3ec61Sdh155122 }
4626f4b3ec61Sdh155122 
4627d62bc4baSyz147064 static int
4628d62bc4baSyz147064 show_linkprop_onelink(datalink_id_t linkid, void *arg)
4629f4b3ec61Sdh155122 {
4630948f2876Sss150715 	int			i;
4631f4b3ec61Sdh155122 	char			*buf;
4632d62bc4baSyz147064 	uint32_t		flags;
4633f4b3ec61Sdh155122 	prop_list_t		*proplist = NULL;
4634d62bc4baSyz147064 	show_linkprop_state_t	*statep = arg;
4635d62bc4baSyz147064 	dlpi_handle_t		dh = NULL;
4636f4b3ec61Sdh155122 
4637d62bc4baSyz147064 	statep->ls_status = DLADM_STATUS_OK;
4638d62bc4baSyz147064 
4639d62bc4baSyz147064 	if (dladm_datalink_id2info(linkid, &flags, NULL, NULL, statep->ls_link,
4640d62bc4baSyz147064 	    MAXLINKNAMELEN) != DLADM_STATUS_OK) {
4641d62bc4baSyz147064 		statep->ls_status = DLADM_STATUS_NOTFOUND;
4642d62bc4baSyz147064 		return (DLADM_WALK_CONTINUE);
4643d62bc4baSyz147064 	}
4644d62bc4baSyz147064 
4645d62bc4baSyz147064 	if ((statep->ls_persist && !(flags & DLADM_OPT_PERSIST)) ||
4646d62bc4baSyz147064 	    (!statep->ls_persist && !(flags & DLADM_OPT_ACTIVE))) {
4647d62bc4baSyz147064 		statep->ls_status = DLADM_STATUS_BADARG;
4648d62bc4baSyz147064 		return (DLADM_WALK_CONTINUE);
4649d62bc4baSyz147064 	}
4650d62bc4baSyz147064 
4651f4b3ec61Sdh155122 	proplist = statep->ls_proplist;
46520ba2cbe9Sxc151355 
46530ba2cbe9Sxc151355 	/*
46540ba2cbe9Sxc151355 	 * When some WiFi links are opened for the first time, their hardware
46550ba2cbe9Sxc151355 	 * automatically scans for APs and does other slow operations.	Thus,
46560ba2cbe9Sxc151355 	 * if there are no open links, the retrieval of link properties
46570ba2cbe9Sxc151355 	 * (below) will proceed slowly unless we hold the link open.
4658d62bc4baSyz147064 	 *
4659d62bc4baSyz147064 	 * Note that failure of dlpi_open() does not necessarily mean invalid
4660d62bc4baSyz147064 	 * link properties, because dlpi_open() may fail because of incorrect
4661d62bc4baSyz147064 	 * autopush configuration. Therefore, we ingore the return value of
4662d62bc4baSyz147064 	 * dlpi_open().
46630ba2cbe9Sxc151355 	 */
4664d62bc4baSyz147064 	if (!statep->ls_persist)
4665d62bc4baSyz147064 		(void) dlpi_open(statep->ls_link, &dh, 0);
46660ba2cbe9Sxc151355 
4667d62bc4baSyz147064 	buf = malloc((sizeof (char *) + DLADM_PROP_VAL_MAX) *
4668d62bc4baSyz147064 	    DLADM_MAX_PROP_VALCNT + MAX_PROP_LINE);
466933343a97Smeem 	if (buf == NULL)
467033343a97Smeem 		die("insufficient memory");
467133343a97Smeem 
4672f4b3ec61Sdh155122 	statep->ls_propvals = (char **)(void *)buf;
4673d62bc4baSyz147064 	for (i = 0; i < DLADM_MAX_PROP_VALCNT; i++) {
4674d62bc4baSyz147064 		statep->ls_propvals[i] = buf +
4675d62bc4baSyz147064 		    sizeof (char *) * DLADM_MAX_PROP_VALCNT +
46760ba2cbe9Sxc151355 		    i * DLADM_PROP_VAL_MAX;
46770ba2cbe9Sxc151355 	}
4678f4b3ec61Sdh155122 	statep->ls_line = buf +
4679d62bc4baSyz147064 	    (sizeof (char *) + DLADM_PROP_VAL_MAX) * DLADM_MAX_PROP_VALCNT;
46800ba2cbe9Sxc151355 
46810ba2cbe9Sxc151355 	if (proplist != NULL) {
4682d62bc4baSyz147064 		for (i = 0; i < proplist->pl_count; i++) {
4683d62bc4baSyz147064 			(void) show_linkprop(linkid,
4684d62bc4baSyz147064 			    proplist->pl_info[i].pi_name, statep);
46850ba2cbe9Sxc151355 		}
4686d62bc4baSyz147064 	} else {
4687d62bc4baSyz147064 		(void) dladm_walk_linkprop(linkid, statep, show_linkprop);
4688d62bc4baSyz147064 	}
4689d62bc4baSyz147064 	if (dh != NULL)
4690948f2876Sss150715 		dlpi_close(dh);
46910ba2cbe9Sxc151355 	free(buf);
4692d62bc4baSyz147064 	return (DLADM_WALK_CONTINUE);
46930ba2cbe9Sxc151355 }
46940ba2cbe9Sxc151355 
46950ba2cbe9Sxc151355 static dladm_status_t
4696d62bc4baSyz147064 set_linkprop_persist(datalink_id_t linkid, const char *prop_name,
4697d62bc4baSyz147064     char **prop_val, uint_t val_cnt, boolean_t reset)
46980ba2cbe9Sxc151355 {
46990ba2cbe9Sxc151355 	dladm_status_t	status;
47000ba2cbe9Sxc151355 
4701d62bc4baSyz147064 	status = dladm_set_linkprop(linkid, prop_name, prop_val, val_cnt,
4702d62bc4baSyz147064 	    DLADM_OPT_PERSIST);
47030ba2cbe9Sxc151355 
47040ba2cbe9Sxc151355 	if (status != DLADM_STATUS_OK) {
4705d62bc4baSyz147064 		warn_dlerr(status, "cannot persistently %s link property",
4706d62bc4baSyz147064 		    reset ? "reset" : "set");
47070ba2cbe9Sxc151355 	}
47080ba2cbe9Sxc151355 	return (status);
47090ba2cbe9Sxc151355 }
47100ba2cbe9Sxc151355 
47110ba2cbe9Sxc151355 static void
47128d5c46e6Sam223141 set_linkprop(int argc, char **argv, boolean_t reset, const char *use)
47130ba2cbe9Sxc151355 {
47140ba2cbe9Sxc151355 	int		i, option;
47150ba2cbe9Sxc151355 	char		errmsg[DLADM_STRSIZE];
4716d62bc4baSyz147064 	char		*altroot = NULL;
4717d62bc4baSyz147064 	datalink_id_t	linkid;
47180ba2cbe9Sxc151355 	prop_list_t	*proplist = NULL;
47190ba2cbe9Sxc151355 	boolean_t	temp = B_FALSE;
47200ba2cbe9Sxc151355 	dladm_status_t	status = DLADM_STATUS_OK;
47210ba2cbe9Sxc151355 
47220ba2cbe9Sxc151355 	opterr = 0;
47230ba2cbe9Sxc151355 	while ((option = getopt_long(argc, argv, ":p:R:t",
47240ba2cbe9Sxc151355 	    prop_longopts, NULL)) != -1) {
47250ba2cbe9Sxc151355 		switch (option) {
47260ba2cbe9Sxc151355 		case 'p':
472733343a97Smeem 			if (parse_props(optarg, &proplist, reset) < 0)
472833343a97Smeem 				die("invalid link properties specified");
47290ba2cbe9Sxc151355 			break;
47300ba2cbe9Sxc151355 		case 't':
47310ba2cbe9Sxc151355 			temp = B_TRUE;
47320ba2cbe9Sxc151355 			break;
47330ba2cbe9Sxc151355 		case 'R':
4734d62bc4baSyz147064 			altroot = optarg;
47350ba2cbe9Sxc151355 			break;
47360ba2cbe9Sxc151355 		default:
47378d5c46e6Sam223141 			die_opterr(optopt, option, use);
47388d5c46e6Sam223141 
47390ba2cbe9Sxc151355 		}
47400ba2cbe9Sxc151355 	}
47410ba2cbe9Sxc151355 
4742d62bc4baSyz147064 	/* get link name (required last argument) */
4743d62bc4baSyz147064 	if (optind != (argc - 1))
47440ba2cbe9Sxc151355 		usage();
47450ba2cbe9Sxc151355 
4746d62bc4baSyz147064 	if (proplist == NULL && !reset)
474733343a97Smeem 		die("link property must be specified");
474833343a97Smeem 
4749d62bc4baSyz147064 	if (altroot != NULL) {
4750d62bc4baSyz147064 		free_props(proplist);
4751d62bc4baSyz147064 		altroot_cmd(altroot, argc, argv);
4752d62bc4baSyz147064 	}
4753d62bc4baSyz147064 
4754d62bc4baSyz147064 	status = dladm_name2info(argv[optind], &linkid, NULL, NULL, NULL);
4755d62bc4baSyz147064 	if (status != DLADM_STATUS_OK)
4756d62bc4baSyz147064 		die_dlerr(status, "link %s is not valid", argv[optind]);
4757d62bc4baSyz147064 
4758d62bc4baSyz147064 	if (proplist == NULL) {
4759e7801d59Ssowmini 		status = dladm_set_linkprop(linkid, NULL, NULL, 0,
4760e7801d59Ssowmini 		    DLADM_OPT_ACTIVE);
4761e7801d59Ssowmini 		if (status != DLADM_STATUS_OK) {
4762d62bc4baSyz147064 			warn_dlerr(status, "cannot reset link property "
4763d62bc4baSyz147064 			    "on '%s'", argv[optind]);
47640ba2cbe9Sxc151355 		}
47650ba2cbe9Sxc151355 		if (!temp) {
476613994ee8Sxz162242 			dladm_status_t	s;
476713994ee8Sxz162242 
4768d62bc4baSyz147064 			s = set_linkprop_persist(linkid, NULL, NULL, 0, reset);
476913994ee8Sxz162242 			if (s != DLADM_STATUS_OK)
477013994ee8Sxz162242 				status = s;
47710ba2cbe9Sxc151355 		}
47720ba2cbe9Sxc151355 		goto done;
47730ba2cbe9Sxc151355 	}
47740ba2cbe9Sxc151355 
47750ba2cbe9Sxc151355 	for (i = 0; i < proplist->pl_count; i++) {
47760ba2cbe9Sxc151355 		prop_info_t	*pip = &proplist->pl_info[i];
47770ba2cbe9Sxc151355 		char		**val;
47780ba2cbe9Sxc151355 		uint_t		count;
47790ba2cbe9Sxc151355 		dladm_status_t	s;
47800ba2cbe9Sxc151355 
47810ba2cbe9Sxc151355 		if (reset) {
47820ba2cbe9Sxc151355 			val = NULL;
47830ba2cbe9Sxc151355 			count = 0;
47840ba2cbe9Sxc151355 		} else {
47850ba2cbe9Sxc151355 			val = pip->pi_val;
47860ba2cbe9Sxc151355 			count = pip->pi_count;
47870ba2cbe9Sxc151355 			if (count == 0) {
478833343a97Smeem 				warn("no value specified for '%s'",
478933343a97Smeem 				    pip->pi_name);
47900ba2cbe9Sxc151355 				status = DLADM_STATUS_BADARG;
47910ba2cbe9Sxc151355 				continue;
47920ba2cbe9Sxc151355 			}
47930ba2cbe9Sxc151355 		}
4794d62bc4baSyz147064 		s = dladm_set_linkprop(linkid, pip->pi_name, val, count,
4795d62bc4baSyz147064 		    DLADM_OPT_ACTIVE);
47960ba2cbe9Sxc151355 		if (s == DLADM_STATUS_OK) {
47970ba2cbe9Sxc151355 			if (!temp) {
4798d62bc4baSyz147064 				s = set_linkprop_persist(linkid,
47990ba2cbe9Sxc151355 				    pip->pi_name, val, count, reset);
48000ba2cbe9Sxc151355 				if (s != DLADM_STATUS_OK)
48010ba2cbe9Sxc151355 					status = s;
48020ba2cbe9Sxc151355 			}
48030ba2cbe9Sxc151355 			continue;
48040ba2cbe9Sxc151355 		}
48050ba2cbe9Sxc151355 		status = s;
48060ba2cbe9Sxc151355 		switch (s) {
48070ba2cbe9Sxc151355 		case DLADM_STATUS_NOTFOUND:
480833343a97Smeem 			warn("invalid link property '%s'", pip->pi_name);
48090ba2cbe9Sxc151355 			break;
48100ba2cbe9Sxc151355 		case DLADM_STATUS_BADVAL: {
48110ba2cbe9Sxc151355 			int		j;
48120ba2cbe9Sxc151355 			char		*ptr, *lim;
48130ba2cbe9Sxc151355 			char		**propvals = NULL;
4814d62bc4baSyz147064 			uint_t		valcnt = DLADM_MAX_PROP_VALCNT;
48150ba2cbe9Sxc151355 
48160ba2cbe9Sxc151355 			ptr = malloc((sizeof (char *) +
4817d62bc4baSyz147064 			    DLADM_PROP_VAL_MAX) * DLADM_MAX_PROP_VALCNT +
48180ba2cbe9Sxc151355 			    MAX_PROP_LINE);
48190ba2cbe9Sxc151355 
48200ba2cbe9Sxc151355 			propvals = (char **)(void *)ptr;
482133343a97Smeem 			if (propvals == NULL)
482233343a97Smeem 				die("insufficient memory");
482333343a97Smeem 
4824d62bc4baSyz147064 			for (j = 0; j < DLADM_MAX_PROP_VALCNT; j++) {
48250ba2cbe9Sxc151355 				propvals[j] = ptr + sizeof (char *) *
4826d62bc4baSyz147064 				    DLADM_MAX_PROP_VALCNT +
48270ba2cbe9Sxc151355 				    j * DLADM_PROP_VAL_MAX;
48280ba2cbe9Sxc151355 			}
4829d62bc4baSyz147064 			s = dladm_get_linkprop(linkid,
4830d62bc4baSyz147064 			    DLADM_PROP_VAL_MODIFIABLE, pip->pi_name, propvals,
4831d62bc4baSyz147064 			    &valcnt);
4832d62bc4baSyz147064 
4833d62bc4baSyz147064 			if (s != DLADM_STATUS_OK) {
4834d62bc4baSyz147064 				warn_dlerr(status, "cannot set link property "
4835d62bc4baSyz147064 				    "'%s' on '%s'", pip->pi_name, argv[optind]);
4836d62bc4baSyz147064 				free(propvals);
4837d62bc4baSyz147064 				break;
4838d62bc4baSyz147064 			}
48390ba2cbe9Sxc151355 
48400ba2cbe9Sxc151355 			ptr = errmsg;
48410ba2cbe9Sxc151355 			lim = ptr + DLADM_STRSIZE;
48420ba2cbe9Sxc151355 			*ptr = '\0';
4843d62bc4baSyz147064 			for (j = 0; j < valcnt; j++) {
48440ba2cbe9Sxc151355 				ptr += snprintf(ptr, lim - ptr, "%s,",
48450ba2cbe9Sxc151355 				    propvals[j]);
48460ba2cbe9Sxc151355 				if (ptr >= lim)
48470ba2cbe9Sxc151355 					break;
48480ba2cbe9Sxc151355 			}
4849f4b3ec61Sdh155122 			if (ptr > errmsg) {
48500ba2cbe9Sxc151355 				*(ptr - 1) = '\0';
485133343a97Smeem 				warn("link property '%s' must be one of: %s",
485233343a97Smeem 				    pip->pi_name, errmsg);
4853f4b3ec61Sdh155122 			} else
4854f4b3ec61Sdh155122 				warn("invalid link property '%s'", *val);
48550ba2cbe9Sxc151355 			free(propvals);
48560ba2cbe9Sxc151355 			break;
48570ba2cbe9Sxc151355 		}
48580ba2cbe9Sxc151355 		default:
48590ba2cbe9Sxc151355 			if (reset) {
486033343a97Smeem 				warn_dlerr(status, "cannot reset link property "
4861d62bc4baSyz147064 				    "'%s' on '%s'", pip->pi_name, argv[optind]);
48620ba2cbe9Sxc151355 			} else {
486333343a97Smeem 				warn_dlerr(status, "cannot set link property "
4864d62bc4baSyz147064 				    "'%s' on '%s'", pip->pi_name, argv[optind]);
48650ba2cbe9Sxc151355 			}
48660ba2cbe9Sxc151355 			break;
48670ba2cbe9Sxc151355 		}
48680ba2cbe9Sxc151355 	}
48690ba2cbe9Sxc151355 done:
48700ba2cbe9Sxc151355 	free_props(proplist);
48710ba2cbe9Sxc151355 	if (status != DLADM_STATUS_OK)
48720ba2cbe9Sxc151355 		exit(1);
48730ba2cbe9Sxc151355 }
48740ba2cbe9Sxc151355 
48750ba2cbe9Sxc151355 static void
48768d5c46e6Sam223141 do_set_linkprop(int argc, char **argv, const char *use)
48770ba2cbe9Sxc151355 {
48788d5c46e6Sam223141 	set_linkprop(argc, argv, B_FALSE, use);
48790ba2cbe9Sxc151355 }
48800ba2cbe9Sxc151355 
48810ba2cbe9Sxc151355 static void
48828d5c46e6Sam223141 do_reset_linkprop(int argc, char **argv, const char *use)
48830ba2cbe9Sxc151355 {
48848d5c46e6Sam223141 	set_linkprop(argc, argv, B_TRUE, use);
48850ba2cbe9Sxc151355 }
48860ba2cbe9Sxc151355 
48870ba2cbe9Sxc151355 static int
48880ba2cbe9Sxc151355 convert_secobj(char *buf, uint_t len, uint8_t *obj_val, uint_t *obj_lenp,
48890ba2cbe9Sxc151355     dladm_secobj_class_t class)
48900ba2cbe9Sxc151355 {
48910ba2cbe9Sxc151355 	int error = 0;
48920ba2cbe9Sxc151355 
4893a399b765Szf162725 	if (class == DLADM_SECOBJ_CLASS_WPA) {
4894a399b765Szf162725 		if (len < 8 || len > 63)
4895a399b765Szf162725 			return (EINVAL);
4896a399b765Szf162725 		(void) memcpy(obj_val, buf, len);
4897a399b765Szf162725 		*obj_lenp = len;
4898a399b765Szf162725 		return (error);
4899a399b765Szf162725 	}
49000ba2cbe9Sxc151355 
4901a399b765Szf162725 	if (class == DLADM_SECOBJ_CLASS_WEP) {
49020ba2cbe9Sxc151355 		switch (len) {
49030ba2cbe9Sxc151355 		case 5:			/* ASCII key sizes */
49040ba2cbe9Sxc151355 		case 13:
49050ba2cbe9Sxc151355 			(void) memcpy(obj_val, buf, len);
49060ba2cbe9Sxc151355 			*obj_lenp = len;
49070ba2cbe9Sxc151355 			break;
49080ba2cbe9Sxc151355 		case 10:		/* Hex key sizes, not preceded by 0x */
49090ba2cbe9Sxc151355 		case 26:
49100ba2cbe9Sxc151355 			error = hexascii_to_octet(buf, len, obj_val, obj_lenp);
49110ba2cbe9Sxc151355 			break;
49120ba2cbe9Sxc151355 		case 12:		/* Hex key sizes, preceded by 0x */
49130ba2cbe9Sxc151355 		case 28:
49140ba2cbe9Sxc151355 			if (strncmp(buf, "0x", 2) != 0)
49150ba2cbe9Sxc151355 				return (EINVAL);
4916a399b765Szf162725 			error = hexascii_to_octet(buf + 2, len - 2,
4917a399b765Szf162725 			    obj_val, obj_lenp);
49180ba2cbe9Sxc151355 			break;
49190ba2cbe9Sxc151355 		default:
49200ba2cbe9Sxc151355 			return (EINVAL);
49210ba2cbe9Sxc151355 		}
49220ba2cbe9Sxc151355 		return (error);
49230ba2cbe9Sxc151355 	}
49240ba2cbe9Sxc151355 
4925a399b765Szf162725 	return (ENOENT);
4926a399b765Szf162725 }
4927a399b765Szf162725 
49280ba2cbe9Sxc151355 /* ARGSUSED */
49290ba2cbe9Sxc151355 static void
49300ba2cbe9Sxc151355 defersig(int sig)
49310ba2cbe9Sxc151355 {
49320ba2cbe9Sxc151355 	signalled = sig;
49330ba2cbe9Sxc151355 }
49340ba2cbe9Sxc151355 
49350ba2cbe9Sxc151355 static int
49360ba2cbe9Sxc151355 get_secobj_from_tty(uint_t try, const char *objname, char *buf)
49370ba2cbe9Sxc151355 {
49380ba2cbe9Sxc151355 	uint_t		len = 0;
49390ba2cbe9Sxc151355 	int		c;
49400ba2cbe9Sxc151355 	struct termios	stored, current;
49410ba2cbe9Sxc151355 	void		(*sigfunc)(int);
49420ba2cbe9Sxc151355 
49430ba2cbe9Sxc151355 	/*
49440ba2cbe9Sxc151355 	 * Turn off echo -- but before we do so, defer SIGINT handling
49450ba2cbe9Sxc151355 	 * so that a ^C doesn't leave the terminal corrupted.
49460ba2cbe9Sxc151355 	 */
49470ba2cbe9Sxc151355 	sigfunc = signal(SIGINT, defersig);
49480ba2cbe9Sxc151355 	(void) fflush(stdin);
49490ba2cbe9Sxc151355 	(void) tcgetattr(0, &stored);
49500ba2cbe9Sxc151355 	current = stored;
49510ba2cbe9Sxc151355 	current.c_lflag &= ~(ICANON|ECHO);
49520ba2cbe9Sxc151355 	current.c_cc[VTIME] = 0;
49530ba2cbe9Sxc151355 	current.c_cc[VMIN] = 1;
49540ba2cbe9Sxc151355 	(void) tcsetattr(0, TCSANOW, &current);
49550ba2cbe9Sxc151355 again:
49560ba2cbe9Sxc151355 	if (try == 1)
49570ba2cbe9Sxc151355 		(void) printf(gettext("provide value for '%s': "), objname);
49580ba2cbe9Sxc151355 	else
49590ba2cbe9Sxc151355 		(void) printf(gettext("confirm value for '%s': "), objname);
49600ba2cbe9Sxc151355 
49610ba2cbe9Sxc151355 	(void) fflush(stdout);
49620ba2cbe9Sxc151355 	while (signalled == 0) {
49630ba2cbe9Sxc151355 		c = getchar();
49640ba2cbe9Sxc151355 		if (c == '\n' || c == '\r') {
49650ba2cbe9Sxc151355 			if (len != 0)
49660ba2cbe9Sxc151355 				break;
49670ba2cbe9Sxc151355 			(void) putchar('\n');
49680ba2cbe9Sxc151355 			goto again;
49690ba2cbe9Sxc151355 		}
49700ba2cbe9Sxc151355 
49710ba2cbe9Sxc151355 		buf[len++] = c;
49720ba2cbe9Sxc151355 		if (len >= DLADM_SECOBJ_VAL_MAX - 1)
49730ba2cbe9Sxc151355 			break;
49740ba2cbe9Sxc151355 		(void) putchar('*');
49750ba2cbe9Sxc151355 	}
49760ba2cbe9Sxc151355 
49770ba2cbe9Sxc151355 	(void) putchar('\n');
49780ba2cbe9Sxc151355 	(void) fflush(stdin);
49790ba2cbe9Sxc151355 
49800ba2cbe9Sxc151355 	/*
49810ba2cbe9Sxc151355 	 * Restore terminal setting and handle deferred signals.
49820ba2cbe9Sxc151355 	 */
49830ba2cbe9Sxc151355 	(void) tcsetattr(0, TCSANOW, &stored);
49840ba2cbe9Sxc151355 
49850ba2cbe9Sxc151355 	(void) signal(SIGINT, sigfunc);
49860ba2cbe9Sxc151355 	if (signalled != 0)
49870ba2cbe9Sxc151355 		(void) kill(getpid(), signalled);
49880ba2cbe9Sxc151355 
49890ba2cbe9Sxc151355 	return (len);
49900ba2cbe9Sxc151355 }
49910ba2cbe9Sxc151355 
49920ba2cbe9Sxc151355 static int
49930ba2cbe9Sxc151355 get_secobj_val(char *obj_name, uint8_t *obj_val, uint_t *obj_lenp,
49940ba2cbe9Sxc151355     dladm_secobj_class_t class, FILE *filep)
49950ba2cbe9Sxc151355 {
49960ba2cbe9Sxc151355 	int		rval;
49970ba2cbe9Sxc151355 	uint_t		len, len2;
49980ba2cbe9Sxc151355 	char		buf[DLADM_SECOBJ_VAL_MAX], buf2[DLADM_SECOBJ_VAL_MAX];
49990ba2cbe9Sxc151355 
50000ba2cbe9Sxc151355 	if (filep == NULL) {
50010ba2cbe9Sxc151355 		len = get_secobj_from_tty(1, obj_name, buf);
50020ba2cbe9Sxc151355 		rval = convert_secobj(buf, len, obj_val, obj_lenp, class);
50030ba2cbe9Sxc151355 		if (rval == 0) {
50040ba2cbe9Sxc151355 			len2 = get_secobj_from_tty(2, obj_name, buf2);
50050ba2cbe9Sxc151355 			if (len != len2 || memcmp(buf, buf2, len) != 0)
50060ba2cbe9Sxc151355 				rval = ENOTSUP;
50070ba2cbe9Sxc151355 		}
50080ba2cbe9Sxc151355 		return (rval);
50090ba2cbe9Sxc151355 	} else {
50100ba2cbe9Sxc151355 		for (;;) {
50110ba2cbe9Sxc151355 			if (fgets(buf, sizeof (buf), filep) == NULL)
50120ba2cbe9Sxc151355 				break;
50130ba2cbe9Sxc151355 			if (isspace(buf[0]))
50140ba2cbe9Sxc151355 				continue;
50150ba2cbe9Sxc151355 
50160ba2cbe9Sxc151355 			len = strlen(buf);
50170ba2cbe9Sxc151355 			if (buf[len - 1] == '\n') {
50180ba2cbe9Sxc151355 				buf[len - 1] = '\0';
50190ba2cbe9Sxc151355 				len--;
50200ba2cbe9Sxc151355 			}
50210ba2cbe9Sxc151355 			break;
50220ba2cbe9Sxc151355 		}
50230ba2cbe9Sxc151355 		(void) fclose(filep);
50240ba2cbe9Sxc151355 	}
50250ba2cbe9Sxc151355 	return (convert_secobj(buf, len, obj_val, obj_lenp, class));
50260ba2cbe9Sxc151355 }
50270ba2cbe9Sxc151355 
50280ba2cbe9Sxc151355 static boolean_t
50290ba2cbe9Sxc151355 check_auth(const char *auth)
50300ba2cbe9Sxc151355 {
50310ba2cbe9Sxc151355 	struct passwd	*pw;
50320ba2cbe9Sxc151355 
50330ba2cbe9Sxc151355 	if ((pw = getpwuid(getuid())) == NULL)
50340ba2cbe9Sxc151355 		return (B_FALSE);
50350ba2cbe9Sxc151355 
50360ba2cbe9Sxc151355 	return (chkauthattr(auth, pw->pw_name) != 0);
50370ba2cbe9Sxc151355 }
50380ba2cbe9Sxc151355 
50390ba2cbe9Sxc151355 static void
50400ba2cbe9Sxc151355 audit_secobj(char *auth, char *class, char *obj,
50410ba2cbe9Sxc151355     boolean_t success, boolean_t create)
50420ba2cbe9Sxc151355 {
50430ba2cbe9Sxc151355 	adt_session_data_t	*ah;
50440ba2cbe9Sxc151355 	adt_event_data_t	*event;
50450ba2cbe9Sxc151355 	au_event_t		flag;
50460ba2cbe9Sxc151355 	char			*errstr;
50470ba2cbe9Sxc151355 
50480ba2cbe9Sxc151355 	if (create) {
50490ba2cbe9Sxc151355 		flag = ADT_dladm_create_secobj;
50500ba2cbe9Sxc151355 		errstr = "ADT_dladm_create_secobj";
50510ba2cbe9Sxc151355 	} else {
50520ba2cbe9Sxc151355 		flag = ADT_dladm_delete_secobj;
50530ba2cbe9Sxc151355 		errstr = "ADT_dladm_delete_secobj";
50540ba2cbe9Sxc151355 	}
50550ba2cbe9Sxc151355 
505633343a97Smeem 	if (adt_start_session(&ah, NULL, ADT_USE_PROC_DATA) != 0)
505733343a97Smeem 		die("adt_start_session: %s", strerror(errno));
50580ba2cbe9Sxc151355 
505933343a97Smeem 	if ((event = adt_alloc_event(ah, flag)) == NULL)
506033343a97Smeem 		die("adt_alloc_event (%s): %s", errstr, strerror(errno));
50610ba2cbe9Sxc151355 
50620ba2cbe9Sxc151355 	/* fill in audit info */
50630ba2cbe9Sxc151355 	if (create) {
50640ba2cbe9Sxc151355 		event->adt_dladm_create_secobj.auth_used = auth;
50650ba2cbe9Sxc151355 		event->adt_dladm_create_secobj.obj_class = class;
50660ba2cbe9Sxc151355 		event->adt_dladm_create_secobj.obj_name = obj;
50670ba2cbe9Sxc151355 	} else {
50680ba2cbe9Sxc151355 		event->adt_dladm_delete_secobj.auth_used = auth;
50690ba2cbe9Sxc151355 		event->adt_dladm_delete_secobj.obj_class = class;
50700ba2cbe9Sxc151355 		event->adt_dladm_delete_secobj.obj_name = obj;
50710ba2cbe9Sxc151355 	}
50720ba2cbe9Sxc151355 
50730ba2cbe9Sxc151355 	if (success) {
50740ba2cbe9Sxc151355 		if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS) != 0) {
507533343a97Smeem 			die("adt_put_event (%s, success): %s", errstr,
507633343a97Smeem 			    strerror(errno));
50770ba2cbe9Sxc151355 		}
50780ba2cbe9Sxc151355 	} else {
50790ba2cbe9Sxc151355 		if (adt_put_event(event, ADT_FAILURE,
50800ba2cbe9Sxc151355 		    ADT_FAIL_VALUE_AUTH) != 0) {
508133343a97Smeem 			die("adt_put_event: (%s, failure): %s", errstr,
508233343a97Smeem 			    strerror(errno));
50830ba2cbe9Sxc151355 		}
50840ba2cbe9Sxc151355 	}
50850ba2cbe9Sxc151355 
50860ba2cbe9Sxc151355 	adt_free_event(event);
50870ba2cbe9Sxc151355 	(void) adt_end_session(ah);
50880ba2cbe9Sxc151355 }
50890ba2cbe9Sxc151355 
50900ba2cbe9Sxc151355 #define	MAX_SECOBJS		32
50910ba2cbe9Sxc151355 #define	MAX_SECOBJ_NAMELEN	32
50920ba2cbe9Sxc151355 static void
50938d5c46e6Sam223141 do_create_secobj(int argc, char **argv, const char *use)
50940ba2cbe9Sxc151355 {
50950ba2cbe9Sxc151355 	int			option, rval;
50960ba2cbe9Sxc151355 	FILE			*filep = NULL;
50970ba2cbe9Sxc151355 	char			*obj_name = NULL;
50980ba2cbe9Sxc151355 	char			*class_name = NULL;
50990ba2cbe9Sxc151355 	uint8_t			obj_val[DLADM_SECOBJ_VAL_MAX];
51000ba2cbe9Sxc151355 	uint_t			obj_len;
51010ba2cbe9Sxc151355 	boolean_t		success, temp = B_FALSE;
51020ba2cbe9Sxc151355 	dladm_status_t		status;
51030ba2cbe9Sxc151355 	dladm_secobj_class_t	class = -1;
51040ba2cbe9Sxc151355 	uid_t			euid;
51050ba2cbe9Sxc151355 
51060ba2cbe9Sxc151355 	opterr = 0;
51070ba2cbe9Sxc151355 	(void) memset(obj_val, 0, DLADM_SECOBJ_VAL_MAX);
51080ba2cbe9Sxc151355 	while ((option = getopt_long(argc, argv, ":f:c:R:t",
51090ba2cbe9Sxc151355 	    wifi_longopts, NULL)) != -1) {
51100ba2cbe9Sxc151355 		switch (option) {
51110ba2cbe9Sxc151355 		case 'f':
51120ba2cbe9Sxc151355 			euid = geteuid();
51130ba2cbe9Sxc151355 			(void) seteuid(getuid());
51140ba2cbe9Sxc151355 			filep = fopen(optarg, "r");
51150ba2cbe9Sxc151355 			if (filep == NULL) {
511633343a97Smeem 				die("cannot open %s: %s", optarg,
511733343a97Smeem 				    strerror(errno));
51180ba2cbe9Sxc151355 			}
51190ba2cbe9Sxc151355 			(void) seteuid(euid);
51200ba2cbe9Sxc151355 			break;
51210ba2cbe9Sxc151355 		case 'c':
51220ba2cbe9Sxc151355 			class_name = optarg;
51230ba2cbe9Sxc151355 			status = dladm_str2secobjclass(optarg, &class);
51240ba2cbe9Sxc151355 			if (status != DLADM_STATUS_OK) {
512533343a97Smeem 				die("invalid secure object class '%s', "
5126a399b765Szf162725 				    "valid values are: wep, wpa", optarg);
51270ba2cbe9Sxc151355 			}
51280ba2cbe9Sxc151355 			break;
51290ba2cbe9Sxc151355 		case 't':
51300ba2cbe9Sxc151355 			temp = B_TRUE;
51310ba2cbe9Sxc151355 			break;
51320ba2cbe9Sxc151355 		case 'R':
51330ba2cbe9Sxc151355 			status = dladm_set_rootdir(optarg);
51340ba2cbe9Sxc151355 			if (status != DLADM_STATUS_OK) {
513533343a97Smeem 				die_dlerr(status, "invalid directory "
513633343a97Smeem 				    "specified");
51370ba2cbe9Sxc151355 			}
51380ba2cbe9Sxc151355 			break;
51390ba2cbe9Sxc151355 		default:
51408d5c46e6Sam223141 			die_opterr(optopt, option, use);
51410ba2cbe9Sxc151355 			break;
51420ba2cbe9Sxc151355 		}
51430ba2cbe9Sxc151355 	}
51440ba2cbe9Sxc151355 
51450ba2cbe9Sxc151355 	if (optind == (argc - 1))
51460ba2cbe9Sxc151355 		obj_name = argv[optind];
51470ba2cbe9Sxc151355 	else if (optind != argc)
51480ba2cbe9Sxc151355 		usage();
51490ba2cbe9Sxc151355 
515033343a97Smeem 	if (class == -1)
515133343a97Smeem 		die("secure object class required");
51520ba2cbe9Sxc151355 
515333343a97Smeem 	if (obj_name == NULL)
515433343a97Smeem 		die("secure object name required");
51550ba2cbe9Sxc151355 
51560ba2cbe9Sxc151355 	success = check_auth(LINK_SEC_AUTH);
51570ba2cbe9Sxc151355 	audit_secobj(LINK_SEC_AUTH, class_name, obj_name, success, B_TRUE);
515833343a97Smeem 	if (!success)
515933343a97Smeem 		die("authorization '%s' is required", LINK_SEC_AUTH);
51600ba2cbe9Sxc151355 
516133343a97Smeem 	rval = get_secobj_val(obj_name, obj_val, &obj_len, class, filep);
516233343a97Smeem 	if (rval != 0) {
51630ba2cbe9Sxc151355 		switch (rval) {
51640ba2cbe9Sxc151355 		case ENOENT:
516533343a97Smeem 			die("invalid secure object class");
51660ba2cbe9Sxc151355 			break;
51670ba2cbe9Sxc151355 		case EINVAL:
516833343a97Smeem 			die("invalid secure object value");
51690ba2cbe9Sxc151355 			break;
51700ba2cbe9Sxc151355 		case ENOTSUP:
517133343a97Smeem 			die("verification failed");
51720ba2cbe9Sxc151355 			break;
51730ba2cbe9Sxc151355 		default:
517433343a97Smeem 			die("invalid secure object: %s", strerror(rval));
51750ba2cbe9Sxc151355 			break;
51760ba2cbe9Sxc151355 		}
51770ba2cbe9Sxc151355 	}
51780ba2cbe9Sxc151355 
51790ba2cbe9Sxc151355 	status = dladm_set_secobj(obj_name, class, obj_val, obj_len,
5180d62bc4baSyz147064 	    DLADM_OPT_CREATE | DLADM_OPT_ACTIVE);
51810ba2cbe9Sxc151355 	if (status != DLADM_STATUS_OK) {
518233343a97Smeem 		die_dlerr(status, "could not create secure object '%s'",
518333343a97Smeem 		    obj_name);
51840ba2cbe9Sxc151355 	}
51850ba2cbe9Sxc151355 	if (temp)
51860ba2cbe9Sxc151355 		return;
51870ba2cbe9Sxc151355 
51880ba2cbe9Sxc151355 	status = dladm_set_secobj(obj_name, class, obj_val, obj_len,
51890ba2cbe9Sxc151355 	    DLADM_OPT_PERSIST);
51900ba2cbe9Sxc151355 	if (status != DLADM_STATUS_OK) {
519133343a97Smeem 		warn_dlerr(status, "could not persistently create secure "
519233343a97Smeem 		    "object '%s'", obj_name);
51930ba2cbe9Sxc151355 	}
51940ba2cbe9Sxc151355 }
51950ba2cbe9Sxc151355 
51960ba2cbe9Sxc151355 static void
51978d5c46e6Sam223141 do_delete_secobj(int argc, char **argv, const char *use)
51980ba2cbe9Sxc151355 {
51990ba2cbe9Sxc151355 	int		i, option;
52000ba2cbe9Sxc151355 	boolean_t	temp = B_FALSE;
52010ba2cbe9Sxc151355 	split_t		*sp = NULL;
52020ba2cbe9Sxc151355 	boolean_t	success;
52030ba2cbe9Sxc151355 	dladm_status_t	status, pstatus;
52040ba2cbe9Sxc151355 
52050ba2cbe9Sxc151355 	opterr = 0;
52060ba2cbe9Sxc151355 	status = pstatus = DLADM_STATUS_OK;
520733343a97Smeem 	while ((option = getopt_long(argc, argv, ":R:t",
52080ba2cbe9Sxc151355 	    wifi_longopts, NULL)) != -1) {
52090ba2cbe9Sxc151355 		switch (option) {
52100ba2cbe9Sxc151355 		case 't':
52110ba2cbe9Sxc151355 			temp = B_TRUE;
52120ba2cbe9Sxc151355 			break;
52130ba2cbe9Sxc151355 		case 'R':
52140ba2cbe9Sxc151355 			status = dladm_set_rootdir(optarg);
52150ba2cbe9Sxc151355 			if (status != DLADM_STATUS_OK) {
521633343a97Smeem 				die_dlerr(status, "invalid directory "
521733343a97Smeem 				    "specified");
52180ba2cbe9Sxc151355 			}
52190ba2cbe9Sxc151355 			break;
52200ba2cbe9Sxc151355 		default:
52218d5c46e6Sam223141 			die_opterr(optopt, option, use);
52220ba2cbe9Sxc151355 			break;
52230ba2cbe9Sxc151355 		}
52240ba2cbe9Sxc151355 	}
52250ba2cbe9Sxc151355 
52260ba2cbe9Sxc151355 	if (optind == (argc - 1)) {
52270ba2cbe9Sxc151355 		sp = split(argv[optind], MAX_SECOBJS, MAX_SECOBJ_NAMELEN);
52280ba2cbe9Sxc151355 		if (sp == NULL) {
522933343a97Smeem 			die("invalid secure object name(s): '%s'",
523033343a97Smeem 			    argv[optind]);
52310ba2cbe9Sxc151355 		}
52320ba2cbe9Sxc151355 	} else if (optind != argc)
52330ba2cbe9Sxc151355 		usage();
52340ba2cbe9Sxc151355 
523533343a97Smeem 	if (sp == NULL || sp->s_nfields < 1)
523633343a97Smeem 		die("secure object name required");
52370ba2cbe9Sxc151355 
52380ba2cbe9Sxc151355 	success = check_auth(LINK_SEC_AUTH);
5239a399b765Szf162725 	audit_secobj(LINK_SEC_AUTH, "unknown", argv[optind], success, B_FALSE);
524033343a97Smeem 	if (!success)
524133343a97Smeem 		die("authorization '%s' is required", LINK_SEC_AUTH);
52420ba2cbe9Sxc151355 
52430ba2cbe9Sxc151355 	for (i = 0; i < sp->s_nfields; i++) {
5244d62bc4baSyz147064 		status = dladm_unset_secobj(sp->s_fields[i], DLADM_OPT_ACTIVE);
52450ba2cbe9Sxc151355 		if (!temp) {
52460ba2cbe9Sxc151355 			pstatus = dladm_unset_secobj(sp->s_fields[i],
52470ba2cbe9Sxc151355 			    DLADM_OPT_PERSIST);
52480ba2cbe9Sxc151355 		} else {
52490ba2cbe9Sxc151355 			pstatus = DLADM_STATUS_OK;
52500ba2cbe9Sxc151355 		}
52510ba2cbe9Sxc151355 
52520ba2cbe9Sxc151355 		if (status != DLADM_STATUS_OK) {
525333343a97Smeem 			warn_dlerr(status, "could not delete secure object "
525433343a97Smeem 			    "'%s'", sp->s_fields[i]);
52550ba2cbe9Sxc151355 		}
52560ba2cbe9Sxc151355 		if (pstatus != DLADM_STATUS_OK) {
525733343a97Smeem 			warn_dlerr(pstatus, "could not persistently delete "
525833343a97Smeem 			    "secure object '%s'", sp->s_fields[i]);
52590ba2cbe9Sxc151355 		}
52600ba2cbe9Sxc151355 	}
52610ba2cbe9Sxc151355 	if (status != DLADM_STATUS_OK || pstatus != DLADM_STATUS_OK)
52620ba2cbe9Sxc151355 		exit(1);
52630ba2cbe9Sxc151355 }
52640ba2cbe9Sxc151355 
52650ba2cbe9Sxc151355 typedef struct show_secobj_state {
52660ba2cbe9Sxc151355 	boolean_t	ss_persist;
52670ba2cbe9Sxc151355 	boolean_t	ss_parseable;
52680ba2cbe9Sxc151355 	boolean_t	ss_header;
5269e7801d59Ssowmini 	print_state_t	ss_print;
52700ba2cbe9Sxc151355 } show_secobj_state_t;
52710ba2cbe9Sxc151355 
52720ba2cbe9Sxc151355 
52730ba2cbe9Sxc151355 static boolean_t
52740ba2cbe9Sxc151355 show_secobj(void *arg, const char *obj_name)
52750ba2cbe9Sxc151355 {
52760ba2cbe9Sxc151355 	uint_t			obj_len = DLADM_SECOBJ_VAL_MAX;
52770ba2cbe9Sxc151355 	uint8_t			obj_val[DLADM_SECOBJ_VAL_MAX];
52780ba2cbe9Sxc151355 	char			buf[DLADM_STRSIZE];
52790ba2cbe9Sxc151355 	uint_t			flags = 0;
52800ba2cbe9Sxc151355 	dladm_secobj_class_t	class;
52810ba2cbe9Sxc151355 	show_secobj_state_t	*statep = arg;
52820ba2cbe9Sxc151355 	dladm_status_t		status;
5283e7801d59Ssowmini 	secobj_fields_buf_t	sbuf;
52840ba2cbe9Sxc151355 
52855f5c9f54SAnurag S. Maskey 	bzero(&sbuf, sizeof (secobj_fields_buf_t));
52860ba2cbe9Sxc151355 	if (statep->ss_persist)
52870ba2cbe9Sxc151355 		flags |= DLADM_OPT_PERSIST;
52880ba2cbe9Sxc151355 
52890ba2cbe9Sxc151355 	status = dladm_get_secobj(obj_name, &class, obj_val, &obj_len, flags);
529033343a97Smeem 	if (status != DLADM_STATUS_OK)
529133343a97Smeem 		die_dlerr(status, "cannot get secure object '%s'", obj_name);
52920ba2cbe9Sxc151355 
52930ba2cbe9Sxc151355 	if (statep->ss_header) {
52940ba2cbe9Sxc151355 		statep->ss_header = B_FALSE;
52950ba2cbe9Sxc151355 		if (!statep->ss_parseable)
5296e7801d59Ssowmini 			print_header(&statep->ss_print);
52970ba2cbe9Sxc151355 	}
52980ba2cbe9Sxc151355 
5299e7801d59Ssowmini 	(void) snprintf(sbuf.ss_obj_name, sizeof (sbuf.ss_obj_name),
5300e7801d59Ssowmini 	    obj_name);
5301e7801d59Ssowmini 	(void) dladm_secobjclass2str(class, buf);
5302e7801d59Ssowmini 	(void) snprintf(sbuf.ss_class, sizeof (sbuf.ss_class), "%s", buf);
5303e7801d59Ssowmini 	if (getuid() == 0) {
53040ba2cbe9Sxc151355 		char	val[DLADM_SECOBJ_VAL_MAX * 2];
53050ba2cbe9Sxc151355 		uint_t	len = sizeof (val);
53060ba2cbe9Sxc151355 
5307e7801d59Ssowmini 		if (octet_to_hexascii(obj_val, obj_len, val, &len) == 0)
5308e7801d59Ssowmini 			(void) snprintf(sbuf.ss_val,
5309e7801d59Ssowmini 			    sizeof (sbuf.ss_val), "%s", val);
53100ba2cbe9Sxc151355 	}
5311e7801d59Ssowmini 	dladm_print_output(&statep->ss_print, statep->ss_parseable,
5312e7801d59Ssowmini 	    dladm_print_field, (void *)&sbuf);
53130ba2cbe9Sxc151355 	return (B_TRUE);
53140ba2cbe9Sxc151355 }
53150ba2cbe9Sxc151355 
53160ba2cbe9Sxc151355 static void
53178d5c46e6Sam223141 do_show_secobj(int argc, char **argv, const char *use)
53180ba2cbe9Sxc151355 {
53190ba2cbe9Sxc151355 	int			option;
53200ba2cbe9Sxc151355 	show_secobj_state_t	state;
53210ba2cbe9Sxc151355 	dladm_status_t		status;
53220d365605Sschuster 	boolean_t		o_arg = B_FALSE;
53230ba2cbe9Sxc151355 	uint_t			i;
53240ba2cbe9Sxc151355 	split_t			*sp;
53250ba2cbe9Sxc151355 	uint_t			flags;
5326e7801d59Ssowmini 	char			*fields_str = NULL;
5327e7801d59Ssowmini 	print_field_t		**fields;
5328e7801d59Ssowmini 	uint_t			nfields;
5329e7801d59Ssowmini 	char			*def_fields = "object,class";
5330e7801d59Ssowmini 	char			*all_fields = "object,class,value";
53310ba2cbe9Sxc151355 
53320ba2cbe9Sxc151355 	opterr = 0;
5333e7801d59Ssowmini 	bzero(&state, sizeof (state));
5334e7801d59Ssowmini 	state.ss_parseable = B_FALSE;
5335e7801d59Ssowmini 	fields_str = def_fields;
53360ba2cbe9Sxc151355 	state.ss_persist = B_FALSE;
53370ba2cbe9Sxc151355 	state.ss_parseable = B_FALSE;
53380ba2cbe9Sxc151355 	state.ss_header = B_TRUE;
5339e7801d59Ssowmini 	while ((option = getopt_long(argc, argv, ":pPo:",
53400ba2cbe9Sxc151355 	    wifi_longopts, NULL)) != -1) {
53410ba2cbe9Sxc151355 		switch (option) {
53420ba2cbe9Sxc151355 		case 'p':
53430ba2cbe9Sxc151355 			state.ss_parseable = B_TRUE;
53440ba2cbe9Sxc151355 			break;
53450ba2cbe9Sxc151355 		case 'P':
53460ba2cbe9Sxc151355 			state.ss_persist = B_TRUE;
53470ba2cbe9Sxc151355 			break;
5348e7801d59Ssowmini 		case 'o':
53490d365605Sschuster 			o_arg = B_TRUE;
5350e7801d59Ssowmini 			if (strcasecmp(optarg, "all") == 0)
5351e7801d59Ssowmini 				fields_str = all_fields;
5352e7801d59Ssowmini 			else
5353e7801d59Ssowmini 				fields_str = optarg;
53540ba2cbe9Sxc151355 			break;
53550ba2cbe9Sxc151355 		default:
53568d5c46e6Sam223141 			die_opterr(optopt, option, use);
53570ba2cbe9Sxc151355 			break;
53580ba2cbe9Sxc151355 		}
53590ba2cbe9Sxc151355 	}
53600ba2cbe9Sxc151355 
53610d365605Sschuster 	if (state.ss_parseable && !o_arg)
53620d365605Sschuster 		die("option -c requires -o");
53630d365605Sschuster 
53640d365605Sschuster 	if (state.ss_parseable && fields_str == all_fields)
53650d365605Sschuster 		die("\"-o all\" is invalid with -p");
53660d365605Sschuster 
5367e7801d59Ssowmini 	fields = parse_output_fields(fields_str, secobj_fields,
5368e7801d59Ssowmini 	    DEV_SOBJ_FIELDS, CMD_TYPE_ANY, &nfields);
5369e7801d59Ssowmini 
5370e7801d59Ssowmini 	if (fields == NULL) {
5371e7801d59Ssowmini 		die("invalid field(s) specified");
5372e7801d59Ssowmini 		return;
5373e7801d59Ssowmini 	}
5374e7801d59Ssowmini 	state.ss_print.ps_fields = fields;
5375e7801d59Ssowmini 	state.ss_print.ps_nfields = nfields;
5376e7801d59Ssowmini 
5377e7801d59Ssowmini 	flags = state.ss_persist ? DLADM_OPT_PERSIST : 0;
53780ba2cbe9Sxc151355 	if (optind == (argc - 1)) {
53790ba2cbe9Sxc151355 		sp = split(argv[optind], MAX_SECOBJS, MAX_SECOBJ_NAMELEN);
53800ba2cbe9Sxc151355 		if (sp == NULL) {
538133343a97Smeem 			die("invalid secure object name(s): '%s'",
538233343a97Smeem 			    argv[optind]);
53830ba2cbe9Sxc151355 		}
53840ba2cbe9Sxc151355 		for (i = 0; i < sp->s_nfields; i++) {
53850ba2cbe9Sxc151355 			if (!show_secobj(&state, sp->s_fields[i]))
53860ba2cbe9Sxc151355 				break;
53870ba2cbe9Sxc151355 		}
53880ba2cbe9Sxc151355 		splitfree(sp);
53890ba2cbe9Sxc151355 		return;
53900ba2cbe9Sxc151355 	} else if (optind != argc)
53910ba2cbe9Sxc151355 		usage();
53920ba2cbe9Sxc151355 
53930ba2cbe9Sxc151355 	status = dladm_walk_secobj(&state, show_secobj, flags);
539433343a97Smeem 	if (status != DLADM_STATUS_OK)
539533343a97Smeem 		die_dlerr(status, "show-secobj");
53960ba2cbe9Sxc151355 }
53970ba2cbe9Sxc151355 
53980ba2cbe9Sxc151355 /*ARGSUSED*/
5399d62bc4baSyz147064 static int
5400d62bc4baSyz147064 i_dladm_init_linkprop(datalink_id_t linkid, void *arg)
5401d62bc4baSyz147064 {
540230890389Sartem 	(void) dladm_init_linkprop(linkid, B_TRUE);
5403d62bc4baSyz147064 	return (DLADM_WALK_CONTINUE);
5404d62bc4baSyz147064 }
5405d62bc4baSyz147064 
54068d5c46e6Sam223141 /*ARGSUSED*/
54070ba2cbe9Sxc151355 static void
54088d5c46e6Sam223141 do_init_linkprop(int argc, char **argv, const char *use)
54090ba2cbe9Sxc151355 {
541030890389Sartem 	int			option;
541130890389Sartem 	dladm_status_t		status;
541230890389Sartem 	datalink_id_t		linkid = DATALINK_ALL_LINKID;
541330890389Sartem 	datalink_media_t	media = DATALINK_ANY_MEDIATYPE;
541430890389Sartem 	uint_t			any_media = B_TRUE;
541530890389Sartem 
541630890389Sartem 	opterr = 0;
541730890389Sartem 	while ((option = getopt(argc, argv, ":w")) != -1) {
541830890389Sartem 		switch (option) {
541930890389Sartem 		case 'w':
542030890389Sartem 			media = DL_WIFI;
542130890389Sartem 			any_media = B_FALSE;
542230890389Sartem 			break;
542330890389Sartem 		default:
54248d5c46e6Sam223141 			/*
54258d5c46e6Sam223141 			 * Because init-linkprop is not a public command,
54268d5c46e6Sam223141 			 * print the usage instead.
54278d5c46e6Sam223141 			 */
54288d5c46e6Sam223141 			usage();
542930890389Sartem 			break;
543030890389Sartem 		}
543130890389Sartem 	}
543230890389Sartem 
543330890389Sartem 	if (optind == (argc - 1)) {
543430890389Sartem 		if ((status = dladm_name2info(argv[optind], &linkid, NULL, NULL,
543530890389Sartem 		    NULL)) != DLADM_STATUS_OK)
543630890389Sartem 			die_dlerr(status, "link %s is not valid", argv[optind]);
543730890389Sartem 	} else if (optind != argc) {
543830890389Sartem 		usage();
543930890389Sartem 	}
544030890389Sartem 
544130890389Sartem 	if (linkid == DATALINK_ALL_LINKID) {
5442d62bc4baSyz147064 		/*
544330890389Sartem 		 * linkprops of links of other classes have been initialized as
5444d62bc4baSyz147064 		 * part of the dladm up-xxx operation.
5445d62bc4baSyz147064 		 */
5446d62bc4baSyz147064 		(void) dladm_walk_datalink_id(i_dladm_init_linkprop, NULL,
544730890389Sartem 		    DATALINK_CLASS_PHYS, media, DLADM_OPT_PERSIST);
544830890389Sartem 	} else {
544930890389Sartem 		(void) dladm_init_linkprop(linkid, any_media);
545030890389Sartem 	}
54510ba2cbe9Sxc151355 }
54520ba2cbe9Sxc151355 
54530ba2cbe9Sxc151355 /* ARGSUSED */
54540ba2cbe9Sxc151355 static void
54558d5c46e6Sam223141 do_show_ether(int argc, char **argv, const char *use)
5456e7801d59Ssowmini {
5457e7801d59Ssowmini 	int 			option;
5458e7801d59Ssowmini 	datalink_id_t		linkid;
5459e7801d59Ssowmini 	print_ether_state_t 	state;
5460e7801d59Ssowmini 	print_field_t 		**fields;
54610d365605Sschuster 	boolean_t		o_arg = B_FALSE;
5462e7801d59Ssowmini 	char			*fields_str;
5463e7801d59Ssowmini 	uint_t			nfields;
5464e7801d59Ssowmini 	char			*all_fields =
5465e7801d59Ssowmini 	    "link,ptype,state,auto,speed-duplex,pause,rem_fault";
5466e7801d59Ssowmini 	char			*default_fields =
5467e7801d59Ssowmini 	    "link,ptype,state,auto,speed-duplex,pause";
5468e7801d59Ssowmini 
5469e7801d59Ssowmini 	fields_str = default_fields;
5470e7801d59Ssowmini 	bzero(&state, sizeof (state));
5471e7801d59Ssowmini 	state.es_link = NULL;
5472e7801d59Ssowmini 	state.es_parseable = B_FALSE;
5473e7801d59Ssowmini 
5474e7801d59Ssowmini 	while ((option = getopt_long(argc, argv, "o:px",
5475e7801d59Ssowmini 	    showeth_lopts, NULL)) != -1) {
5476e7801d59Ssowmini 		switch (option) {
5477e7801d59Ssowmini 			case 'x':
5478e7801d59Ssowmini 				state.es_extended = B_TRUE;
5479e7801d59Ssowmini 				break;
5480e7801d59Ssowmini 			case 'p':
5481e7801d59Ssowmini 				state.es_parseable = B_TRUE;
5482e7801d59Ssowmini 				break;
5483e7801d59Ssowmini 			case 'o':
54840d365605Sschuster 				o_arg = B_TRUE;
5485e7801d59Ssowmini 				if (strcasecmp(optarg, "all") == 0)
5486e7801d59Ssowmini 					fields_str = all_fields;
5487e7801d59Ssowmini 				else
5488e7801d59Ssowmini 					fields_str = optarg;
5489e7801d59Ssowmini 				break;
5490e7801d59Ssowmini 			default:
54918d5c46e6Sam223141 				die_opterr(optopt, option, use);
5492e7801d59Ssowmini 				break;
5493e7801d59Ssowmini 		}
5494e7801d59Ssowmini 	}
5495e7801d59Ssowmini 
54960d365605Sschuster 	if (state.es_parseable && !o_arg)
54970d365605Sschuster 		die("-p requires -o");
54980d365605Sschuster 
54990d365605Sschuster 	if (state.es_parseable && fields_str == all_fields)
55000d365605Sschuster 		die("\"-o all\" is invalid with -p");
55010d365605Sschuster 
5502e7801d59Ssowmini 	if (optind == (argc - 1))
5503e7801d59Ssowmini 		state.es_link = argv[optind];
5504e7801d59Ssowmini 
5505e7801d59Ssowmini 	fields = parse_output_fields(fields_str, ether_fields,
5506e7801d59Ssowmini 	    ETHER_MAX_FIELDS, CMD_TYPE_ANY, &nfields);
5507e7801d59Ssowmini 
5508e7801d59Ssowmini 	if (fields == NULL) {
5509e7801d59Ssowmini 		die("invalid field(s) specified");
5510e7801d59Ssowmini 		exit(EXIT_FAILURE);
5511e7801d59Ssowmini 	}
5512e7801d59Ssowmini 	state.es_print.ps_fields = fields;
5513e7801d59Ssowmini 	state.es_print.ps_nfields = nfields;
5514e7801d59Ssowmini 
5515e7801d59Ssowmini 	if (state.es_link == NULL) {
5516e7801d59Ssowmini 		(void) dladm_walk_datalink_id(show_etherprop, &state,
5517e7801d59Ssowmini 		    DATALINK_CLASS_PHYS, DL_ETHER,
5518e7801d59Ssowmini 		    DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST);
5519e7801d59Ssowmini 	} else {
5520e7801d59Ssowmini 		if (!link_is_ether(state.es_link, &linkid)) {
5521e7801d59Ssowmini 			die("invalid link specified");
5522e7801d59Ssowmini 		}
5523e7801d59Ssowmini 		(void) show_etherprop(linkid, &state);
5524e7801d59Ssowmini 	}
5525e7801d59Ssowmini 
5526e7801d59Ssowmini 	exit(DLADM_STATUS_OK);
5527e7801d59Ssowmini 
5528e7801d59Ssowmini }
5529e7801d59Ssowmini 
5530e7801d59Ssowmini static char *
5531e7801d59Ssowmini dladm_print_field(print_field_t *pf, void *arg)
5532e7801d59Ssowmini {
5533e7801d59Ssowmini 	char *value;
5534e7801d59Ssowmini 
5535e7801d59Ssowmini 	value = (char *)arg + pf->pf_offset;
5536e7801d59Ssowmini 	return (value);
5537e7801d59Ssowmini }
5538e7801d59Ssowmini 
5539e7801d59Ssowmini static int
5540e7801d59Ssowmini show_etherprop(datalink_id_t linkid, void *arg)
5541e7801d59Ssowmini {
5542e7801d59Ssowmini 	print_ether_state_t	*statep = arg;
5543e7801d59Ssowmini 	char			buf[DLADM_STRSIZE];
5544e7801d59Ssowmini 	int			speed;
5545e7801d59Ssowmini 	uint64_t		s;
5546e7801d59Ssowmini 	uint32_t		autoneg, pause, asmpause, adv_rf, cap_rf, lp_rf;
5547e7801d59Ssowmini 	ether_fields_buf_t	ebuf;
5548e7801d59Ssowmini 	char			speed_unit = 'M';
5549e7801d59Ssowmini 
55505f5c9f54SAnurag S. Maskey 	bzero(&ebuf, sizeof (ether_fields_buf_t));
5551e7801d59Ssowmini 	if (dladm_datalink_id2info(linkid, NULL, NULL, NULL,
5552e7801d59Ssowmini 	    ebuf.eth_link, sizeof (ebuf.eth_link)) != DLADM_STATUS_OK) {
5553e7801d59Ssowmini 		return (DLADM_WALK_CONTINUE);
5554e7801d59Ssowmini 	}
5555e7801d59Ssowmini 
5556e7801d59Ssowmini 	if (!statep->es_header && !statep->es_parseable) {
5557e7801d59Ssowmini 		print_header(&statep->es_print);
5558e7801d59Ssowmini 		statep->es_header = B_TRUE;
5559e7801d59Ssowmini 	}
5560e7801d59Ssowmini 	(void) snprintf(ebuf.eth_ptype, sizeof (ebuf.eth_ptype),
5561e7801d59Ssowmini 	    "%s", "current");
5562e7801d59Ssowmini 
5563e7801d59Ssowmini 	(void) dladm_get_single_mac_stat(linkid, "link_autoneg",
5564e7801d59Ssowmini 	    KSTAT_DATA_UINT32, &autoneg);
5565e7801d59Ssowmini 	(void) snprintf(ebuf.eth_autoneg, sizeof (ebuf.eth_autoneg),
5566e7801d59Ssowmini 	    "%s", (autoneg ? "yes" : "no"));
5567e7801d59Ssowmini 
5568e7801d59Ssowmini 	(void) dladm_get_single_mac_stat(linkid, "link_pause",
5569e7801d59Ssowmini 	    KSTAT_DATA_UINT32, &pause);
5570e7801d59Ssowmini 	(void) dladm_get_single_mac_stat(linkid, "link_asmpause",
5571e7801d59Ssowmini 	    KSTAT_DATA_UINT32, &asmpause);
5572e7801d59Ssowmini 	(void) snprintf(ebuf.eth_pause, sizeof (ebuf.eth_pause),
5573e7801d59Ssowmini 	    "%s", pause_str(pause, asmpause));
5574e7801d59Ssowmini 
5575e7801d59Ssowmini 	(void) dladm_get_single_mac_stat(linkid, "ifspeed",
5576e7801d59Ssowmini 	    KSTAT_DATA_UINT64, &s);
5577e7801d59Ssowmini 	speed = (int)(s/1000000ull);
5578e7801d59Ssowmini 
5579e7801d59Ssowmini 	if (speed >= 1000) {
5580e7801d59Ssowmini 		speed = speed/1000;
5581e7801d59Ssowmini 		speed_unit = 'G';
5582e7801d59Ssowmini 	}
55834045d941Ssowmini 	(void) get_linkduplex(ebuf.eth_link, B_TRUE, buf);
5584e7801d59Ssowmini 	(void) snprintf(ebuf.eth_spdx, sizeof (ebuf.eth_spdx), "%d%c-%c",
5585e7801d59Ssowmini 	    speed, speed_unit, buf[0]);
5586e7801d59Ssowmini 
55874045d941Ssowmini 	(void) get_linkstate(ebuf.eth_link, B_TRUE, buf);
5588e7801d59Ssowmini 	(void) snprintf(ebuf.eth_state, sizeof (ebuf.eth_state),
5589e7801d59Ssowmini 	    "%s", buf);
5590e7801d59Ssowmini 
5591e7801d59Ssowmini 	(void) dladm_get_single_mac_stat(linkid, "adv_rem_fault",
5592e7801d59Ssowmini 	    KSTAT_DATA_UINT32, &adv_rf);
5593e7801d59Ssowmini 	(void) dladm_get_single_mac_stat(linkid, "cap_rem_fault",
5594e7801d59Ssowmini 	    KSTAT_DATA_UINT32, &cap_rf);
5595e7801d59Ssowmini 	(void) dladm_get_single_mac_stat(linkid, "lp_rem_fault",
5596e7801d59Ssowmini 	    KSTAT_DATA_UINT32, &lp_rf);
5597e7801d59Ssowmini 	(void) snprintf(ebuf.eth_rem_fault, sizeof (ebuf.eth_rem_fault),
5598e7801d59Ssowmini 	    "%s", (adv_rf == 0 && lp_rf == 0 ? "none" : "fault"));
5599e7801d59Ssowmini 
5600e7801d59Ssowmini 	dladm_print_output(&statep->es_print, statep->es_parseable,
5601e7801d59Ssowmini 	    dladm_print_field, &ebuf);
5602e7801d59Ssowmini 
5603e7801d59Ssowmini 	if (statep->es_extended)
5604e7801d59Ssowmini 		show_ether_xprop(linkid, arg);
5605e7801d59Ssowmini 
5606e7801d59Ssowmini 	return (DLADM_WALK_CONTINUE);
5607e7801d59Ssowmini }
5608e7801d59Ssowmini 
5609e7801d59Ssowmini /* ARGSUSED */
5610e7801d59Ssowmini static void
56118d5c46e6Sam223141 do_init_secobj(int argc, char **argv, const char *use)
56120ba2cbe9Sxc151355 {
56130ba2cbe9Sxc151355 	dladm_status_t status;
56140ba2cbe9Sxc151355 
56150ba2cbe9Sxc151355 	status = dladm_init_secobj();
561633343a97Smeem 	if (status != DLADM_STATUS_OK)
561733343a97Smeem 		die_dlerr(status, "secure object initialization failed");
561833343a97Smeem }
561933343a97Smeem 
5620d62bc4baSyz147064 /*
5621d62bc4baSyz147064  * "-R" option support. It is used for live upgrading. Append dladm commands
5622d62bc4baSyz147064  * to a upgrade script which will be run when the alternative root boots up:
5623d62bc4baSyz147064  *
5624b9e076dcSyz147064  * - If the /etc/dladm/datalink.conf file exists on the alternative root,
5625b9e076dcSyz147064  * append dladm commands to the <altroot>/var/svc/profile/upgrade_datalink
5626b9e076dcSyz147064  * script. This script will be run as part of the network/physical service.
5627b9e076dcSyz147064  * We cannot defer this to /var/svc/profile/upgrade because then the
5628b9e076dcSyz147064  * configuration will not be able to take effect before network/physical
5629b9e076dcSyz147064  * plumbs various interfaces.
5630d62bc4baSyz147064  *
5631b9e076dcSyz147064  * - If the /etc/dladm/datalink.conf file does not exist on the alternative
5632b9e076dcSyz147064  * root, append dladm commands to the <altroot>/var/svc/profile/upgrade script,
5633b9e076dcSyz147064  * which will be run in the manifest-import service.
5634d62bc4baSyz147064  *
5635d62bc4baSyz147064  * Note that the SMF team is considering to move the manifest-import service
5636d62bc4baSyz147064  * to be run at the very begining of boot. Once that is done, the need for
5637d62bc4baSyz147064  * the /var/svc/profile/upgrade_datalink script will not exist any more.
5638d62bc4baSyz147064  */
5639d62bc4baSyz147064 static void
5640d62bc4baSyz147064 altroot_cmd(char *altroot, int argc, char *argv[])
5641d62bc4baSyz147064 {
5642d62bc4baSyz147064 	char		path[MAXPATHLEN];
5643d62bc4baSyz147064 	struct stat	stbuf;
5644d62bc4baSyz147064 	FILE		*fp;
5645d62bc4baSyz147064 	int		i;
5646d62bc4baSyz147064 
5647d62bc4baSyz147064 	/*
5648b9e076dcSyz147064 	 * Check for the existence of the /etc/dladm/datalink.conf
5649b9e076dcSyz147064 	 * configuration file, and determine the name of script file.
5650d62bc4baSyz147064 	 */
5651b9e076dcSyz147064 	(void) snprintf(path, MAXPATHLEN, "/%s/etc/dladm/datalink.conf",
5652b9e076dcSyz147064 	    altroot);
5653d62bc4baSyz147064 	if (stat(path, &stbuf) < 0) {
5654d62bc4baSyz147064 		(void) snprintf(path, MAXPATHLEN, "/%s/%s", altroot,
5655d62bc4baSyz147064 		    SMF_UPGRADE_FILE);
5656d62bc4baSyz147064 	} else {
5657d62bc4baSyz147064 		(void) snprintf(path, MAXPATHLEN, "/%s/%s", altroot,
5658d62bc4baSyz147064 		    SMF_UPGRADEDATALINK_FILE);
5659d62bc4baSyz147064 	}
5660d62bc4baSyz147064 
5661d62bc4baSyz147064 	if ((fp = fopen(path, "a+")) == NULL)
5662d62bc4baSyz147064 		die("operation not supported on %s", altroot);
5663d62bc4baSyz147064 
5664d62bc4baSyz147064 	(void) fprintf(fp, "/sbin/dladm ");
5665d62bc4baSyz147064 	for (i = 0; i < argc; i++) {
5666d62bc4baSyz147064 		/*
5667d62bc4baSyz147064 		 * Directly write to the file if it is not the "-R <altroot>"
5668d62bc4baSyz147064 		 * option. In which case, skip it.
5669d62bc4baSyz147064 		 */
5670d62bc4baSyz147064 		if (strcmp(argv[i], "-R") != 0)
5671d62bc4baSyz147064 			(void) fprintf(fp, "%s ", argv[i]);
5672d62bc4baSyz147064 		else
5673d62bc4baSyz147064 			i ++;
5674d62bc4baSyz147064 	}
5675d62bc4baSyz147064 	(void) fprintf(fp, "%s\n", SMF_DLADM_UPGRADE_MSG);
5676d62bc4baSyz147064 	(void) fclose(fp);
5677d62bc4baSyz147064 	exit(0);
5678d62bc4baSyz147064 }
5679d62bc4baSyz147064 
5680d62bc4baSyz147064 /*
5681d62bc4baSyz147064  * Convert the string to an integer. Note that the string must not have any
5682d62bc4baSyz147064  * trailing non-integer characters.
5683d62bc4baSyz147064  */
568433343a97Smeem static boolean_t
568533343a97Smeem str2int(const char *str, int *valp)
568633343a97Smeem {
568733343a97Smeem 	int	val;
568833343a97Smeem 	char	*endp = NULL;
568933343a97Smeem 
569033343a97Smeem 	errno = 0;
569133343a97Smeem 	val = strtol(str, &endp, 10);
569233343a97Smeem 	if (errno != 0 || *endp != '\0')
569333343a97Smeem 		return (B_FALSE);
569433343a97Smeem 
569533343a97Smeem 	*valp = val;
569633343a97Smeem 	return (B_TRUE);
569733343a97Smeem }
569833343a97Smeem 
569933343a97Smeem /* PRINTFLIKE1 */
570033343a97Smeem static void
570133343a97Smeem warn(const char *format, ...)
570233343a97Smeem {
570333343a97Smeem 	va_list alist;
570433343a97Smeem 
570533343a97Smeem 	format = gettext(format);
570633343a97Smeem 	(void) fprintf(stderr, "%s: warning: ", progname);
570733343a97Smeem 
570833343a97Smeem 	va_start(alist, format);
570933343a97Smeem 	(void) vfprintf(stderr, format, alist);
571033343a97Smeem 	va_end(alist);
571133343a97Smeem 
571233343a97Smeem 	(void) putchar('\n');
571333343a97Smeem }
571433343a97Smeem 
571533343a97Smeem /* PRINTFLIKE2 */
571633343a97Smeem static void
571733343a97Smeem warn_dlerr(dladm_status_t err, const char *format, ...)
571833343a97Smeem {
571933343a97Smeem 	va_list alist;
572033343a97Smeem 	char	errmsg[DLADM_STRSIZE];
572133343a97Smeem 
572233343a97Smeem 	format = gettext(format);
572333343a97Smeem 	(void) fprintf(stderr, gettext("%s: warning: "), progname);
572433343a97Smeem 
572533343a97Smeem 	va_start(alist, format);
572633343a97Smeem 	(void) vfprintf(stderr, format, alist);
572733343a97Smeem 	va_end(alist);
572833343a97Smeem 	(void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg));
572933343a97Smeem }
573033343a97Smeem 
573133343a97Smeem /* PRINTFLIKE2 */
573233343a97Smeem static void
573333343a97Smeem die_dlerr(dladm_status_t err, const char *format, ...)
573433343a97Smeem {
573533343a97Smeem 	va_list alist;
573633343a97Smeem 	char	errmsg[DLADM_STRSIZE];
573733343a97Smeem 
573833343a97Smeem 	format = gettext(format);
573933343a97Smeem 	(void) fprintf(stderr, "%s: ", progname);
574033343a97Smeem 
574133343a97Smeem 	va_start(alist, format);
574233343a97Smeem 	(void) vfprintf(stderr, format, alist);
574333343a97Smeem 	va_end(alist);
574433343a97Smeem 	(void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg));
574533343a97Smeem 
574633343a97Smeem 	exit(EXIT_FAILURE);
574733343a97Smeem }
574833343a97Smeem 
574933343a97Smeem /* PRINTFLIKE1 */
575033343a97Smeem static void
575133343a97Smeem die(const char *format, ...)
575233343a97Smeem {
575333343a97Smeem 	va_list alist;
575433343a97Smeem 
575533343a97Smeem 	format = gettext(format);
575633343a97Smeem 	(void) fprintf(stderr, "%s: ", progname);
575733343a97Smeem 
575833343a97Smeem 	va_start(alist, format);
575933343a97Smeem 	(void) vfprintf(stderr, format, alist);
576033343a97Smeem 	va_end(alist);
576133343a97Smeem 
576233343a97Smeem 	(void) putchar('\n');
576333343a97Smeem 	exit(EXIT_FAILURE);
576433343a97Smeem }
576533343a97Smeem 
576633343a97Smeem static void
576733343a97Smeem die_optdup(int opt)
576833343a97Smeem {
576933343a97Smeem 	die("the option -%c cannot be specified more than once", opt);
577033343a97Smeem }
577133343a97Smeem 
577233343a97Smeem static void
57738d5c46e6Sam223141 die_opterr(int opt, int opterr, const char *usage)
577433343a97Smeem {
577533343a97Smeem 	switch (opterr) {
577633343a97Smeem 	case ':':
57778d5c46e6Sam223141 		die("option '-%c' requires a value\nusage: %s", opt,
57788d5c46e6Sam223141 		    gettext(usage));
577933343a97Smeem 		break;
578033343a97Smeem 	case '?':
578133343a97Smeem 	default:
57828d5c46e6Sam223141 		die("unrecognized option '-%c'\nusage: %s", opt,
57838d5c46e6Sam223141 		    gettext(usage));
578433343a97Smeem 		break;
57850ba2cbe9Sxc151355 	}
57860ba2cbe9Sxc151355 }
5787e7801d59Ssowmini 
5788e7801d59Ssowmini static void
5789e7801d59Ssowmini show_ether_xprop(datalink_id_t linkid, void *arg)
5790e7801d59Ssowmini {
5791e7801d59Ssowmini 	print_ether_state_t	*statep = arg;
5792e7801d59Ssowmini 	char			buf[DLADM_STRSIZE];
5793e7801d59Ssowmini 	uint32_t		autoneg, pause, asmpause, adv_rf, cap_rf, lp_rf;
5794e7801d59Ssowmini 	boolean_t		add_comma, r1;
5795e7801d59Ssowmini 	ether_fields_buf_t	ebuf;
5796e7801d59Ssowmini 
5797e7801d59Ssowmini 	/* capable */
5798e7801d59Ssowmini 	bzero(&ebuf, sizeof (ebuf));
5799e7801d59Ssowmini 	(void) snprintf(ebuf.eth_link, sizeof (ebuf.eth_link), "");
5800e7801d59Ssowmini 
5801e7801d59Ssowmini 	(void) snprintf(ebuf.eth_ptype, sizeof (ebuf.eth_ptype),
5802e7801d59Ssowmini 	    "%s", "capable");
58030d365605Sschuster 	(void) snprintf(ebuf.eth_state, sizeof (ebuf.eth_state), "");
5804e7801d59Ssowmini 
5805e7801d59Ssowmini 	(void) dladm_get_single_mac_stat(linkid, "cap_autoneg",
5806e7801d59Ssowmini 	    KSTAT_DATA_UINT32, &autoneg);
5807e7801d59Ssowmini 	(void) snprintf(ebuf.eth_autoneg, sizeof (ebuf.eth_autoneg),
5808e7801d59Ssowmini 	    "%s", (autoneg ? "yes" : "no"));
5809e7801d59Ssowmini 
5810e7801d59Ssowmini 	add_comma = B_FALSE;
5811e7801d59Ssowmini 	bzero(buf, sizeof (buf));
5812e7801d59Ssowmini 	r1 = get_speed_duplex(linkid, "cap_1000", buf, "1G", B_FALSE);
5813e7801d59Ssowmini 	if (r1)
5814e7801d59Ssowmini 		add_comma = B_TRUE;
5815e7801d59Ssowmini 	r1 = get_speed_duplex(linkid, "cap_100", buf, "100M", add_comma);
5816e7801d59Ssowmini 	if (r1)
5817e7801d59Ssowmini 		add_comma = B_TRUE;
5818e7801d59Ssowmini 	r1 = get_speed_duplex(linkid, "cap_10", buf, "10M", add_comma);
5819e7801d59Ssowmini 	add_comma = B_FALSE;
5820e7801d59Ssowmini 	(void) snprintf(ebuf.eth_spdx, sizeof (ebuf.eth_spdx), "%s", buf);
5821e7801d59Ssowmini 
5822e7801d59Ssowmini 	(void) dladm_get_single_mac_stat(linkid, "cap_pause",
5823e7801d59Ssowmini 	    KSTAT_DATA_UINT32, &pause);
5824e7801d59Ssowmini 	(void) dladm_get_single_mac_stat(linkid, "cap_asmpause",
5825e7801d59Ssowmini 	    KSTAT_DATA_UINT32, &asmpause);
5826e7801d59Ssowmini 	(void) snprintf(ebuf.eth_pause, sizeof (ebuf.eth_pause),
5827e7801d59Ssowmini 	    "%s", pause_str(pause, asmpause));
5828e7801d59Ssowmini 
5829e7801d59Ssowmini 	(void) dladm_get_single_mac_stat(linkid, "adv_rem_fault",
5830e7801d59Ssowmini 	    KSTAT_DATA_UINT32, &adv_rf);
5831e7801d59Ssowmini 	(void) dladm_get_single_mac_stat(linkid, "cap_rem_fault",
5832e7801d59Ssowmini 	    KSTAT_DATA_UINT32, &cap_rf);
5833e7801d59Ssowmini 	(void) dladm_get_single_mac_stat(linkid, "lp_rem_fault",
5834e7801d59Ssowmini 	    KSTAT_DATA_UINT32, &lp_rf);
5835e7801d59Ssowmini 
5836e7801d59Ssowmini 	(void) snprintf(ebuf.eth_rem_fault, sizeof (ebuf.eth_rem_fault),
5837e7801d59Ssowmini 	    "%s", (cap_rf ? "yes" : "no"));
5838e7801d59Ssowmini 
5839e7801d59Ssowmini 	dladm_print_output(&statep->es_print, statep->es_parseable,
5840e7801d59Ssowmini 	    dladm_print_field, &ebuf);
5841e7801d59Ssowmini 
5842e7801d59Ssowmini 	/* advertised */
5843e7801d59Ssowmini 	bzero(&ebuf, sizeof (ebuf));
5844e7801d59Ssowmini 	(void) snprintf(ebuf.eth_ptype, sizeof (ebuf.eth_ptype),
5845e7801d59Ssowmini 	    "%s", "adv");
58460d365605Sschuster 	(void) snprintf(ebuf.eth_state, sizeof (ebuf.eth_state), "");
5847e7801d59Ssowmini 
5848e7801d59Ssowmini 	(void) dladm_get_single_mac_stat(linkid, "adv_cap_autoneg",
5849e7801d59Ssowmini 	    KSTAT_DATA_UINT32, &autoneg);
5850e7801d59Ssowmini 	(void) snprintf(ebuf.eth_autoneg, sizeof (ebuf.eth_autoneg),
5851e7801d59Ssowmini 	    "%s", (autoneg ? "yes" : "no"));
5852e7801d59Ssowmini 
5853e7801d59Ssowmini 	add_comma = B_FALSE;
5854e7801d59Ssowmini 	bzero(buf, sizeof (buf));
5855e7801d59Ssowmini 	r1 = get_speed_duplex(linkid, "adv_cap_1000", buf, "1G", add_comma);
5856e7801d59Ssowmini 	if (r1)
5857e7801d59Ssowmini 		add_comma = B_TRUE;
5858e7801d59Ssowmini 	r1 = get_speed_duplex(linkid, "adv_cap_100", buf, "100M", add_comma);
5859e7801d59Ssowmini 	if (r1)
5860e7801d59Ssowmini 		add_comma = B_TRUE;
5861e7801d59Ssowmini 	r1 = get_speed_duplex(linkid, "adv_cap_10", buf, "10M", add_comma);
5862e7801d59Ssowmini 	add_comma = B_FALSE;
5863e7801d59Ssowmini 	(void) snprintf(ebuf.eth_spdx, sizeof (ebuf.eth_spdx), "%s", buf);
5864e7801d59Ssowmini 
5865e7801d59Ssowmini 	(void) dladm_get_single_mac_stat(linkid, "adv_cap_pause",
5866e7801d59Ssowmini 	    KSTAT_DATA_UINT32, &pause);
5867e7801d59Ssowmini 	(void) dladm_get_single_mac_stat(linkid, "adv_cap_asmpause",
5868e7801d59Ssowmini 	    KSTAT_DATA_UINT32, &asmpause);
5869e7801d59Ssowmini 	(void) snprintf(ebuf.eth_pause, sizeof (ebuf.eth_pause),
5870e7801d59Ssowmini 	    "%s", pause_str(pause, asmpause));
5871e7801d59Ssowmini 
5872e7801d59Ssowmini 	(void) snprintf(ebuf.eth_rem_fault, sizeof (ebuf.eth_rem_fault),
5873e7801d59Ssowmini 	    "%s", (adv_rf ? "fault" : "none"));
5874e7801d59Ssowmini 
5875e7801d59Ssowmini 	dladm_print_output(&statep->es_print, statep->es_parseable,
5876e7801d59Ssowmini 	    dladm_print_field, &ebuf);
5877e7801d59Ssowmini 
5878e7801d59Ssowmini 	/* peeradv */
5879e7801d59Ssowmini 	bzero(&ebuf, sizeof (ebuf));
5880e7801d59Ssowmini 	(void) snprintf(ebuf.eth_ptype, sizeof (ebuf.eth_ptype),
5881e7801d59Ssowmini 	    "%s", "peeradv");
58820d365605Sschuster 	(void) snprintf(ebuf.eth_state, sizeof (ebuf.eth_state), "");
5883e7801d59Ssowmini 	(void) dladm_get_single_mac_stat(linkid, "lp_cap_autoneg",
5884e7801d59Ssowmini 	    KSTAT_DATA_UINT32, &autoneg);
5885e7801d59Ssowmini 	(void) snprintf(ebuf.eth_autoneg, sizeof (ebuf.eth_autoneg),
5886e7801d59Ssowmini 	    "%s", (autoneg ? "yes" : "no"));
5887e7801d59Ssowmini 
5888e7801d59Ssowmini 	add_comma = B_FALSE;
5889e7801d59Ssowmini 	bzero(buf, sizeof (buf));
5890e7801d59Ssowmini 	r1 = get_speed_duplex(linkid, "lp_cap_1000", buf, "1G", add_comma);
5891e7801d59Ssowmini 	if (r1)
5892e7801d59Ssowmini 		add_comma = B_TRUE;
5893e7801d59Ssowmini 	r1 = get_speed_duplex(linkid, "lp_cap_100", buf, "100M", add_comma);
5894e7801d59Ssowmini 	if (r1)
5895e7801d59Ssowmini 		add_comma = B_TRUE;
5896e7801d59Ssowmini 	r1 = get_speed_duplex(linkid, "lp_cap_10", buf, "10M", add_comma);
5897e7801d59Ssowmini 	(void) snprintf(ebuf.eth_spdx, sizeof (ebuf.eth_spdx), "%s", buf);
5898e7801d59Ssowmini 
5899e7801d59Ssowmini 	(void) dladm_get_single_mac_stat(linkid, "lp_cap_pause",
5900e7801d59Ssowmini 	    KSTAT_DATA_UINT32, &pause);
5901e7801d59Ssowmini 	(void) dladm_get_single_mac_stat(linkid, "lp_cap_asmpause",
5902e7801d59Ssowmini 	    KSTAT_DATA_UINT32, &asmpause);
5903e7801d59Ssowmini 	(void) snprintf(ebuf.eth_pause, sizeof (ebuf.eth_pause),
5904e7801d59Ssowmini 	    "%s", pause_str(pause, asmpause));
5905e7801d59Ssowmini 
5906e7801d59Ssowmini 	(void) snprintf(ebuf.eth_rem_fault, sizeof (ebuf.eth_rem_fault),
5907e7801d59Ssowmini 	    "%s", (lp_rf ? "fault" : "none"));
5908e7801d59Ssowmini 
5909e7801d59Ssowmini 	dladm_print_output(&statep->es_print, statep->es_parseable,
5910e7801d59Ssowmini 	    dladm_print_field, &ebuf);
5911e7801d59Ssowmini }
5912e7801d59Ssowmini 
5913e7801d59Ssowmini static boolean_t
5914e7801d59Ssowmini get_speed_duplex(datalink_id_t linkid, const char *mii_prop_prefix,
5915e7801d59Ssowmini     char *spbuf, char *sp, boolean_t add_comma)
5916e7801d59Ssowmini {
5917e7801d59Ssowmini 	int speed, duplex = 0;
5918e7801d59Ssowmini 	boolean_t ret = B_FALSE;
5919e7801d59Ssowmini 	char mii_prop[DLADM_STRSIZE];
5920e7801d59Ssowmini 
5921e7801d59Ssowmini 	(void) snprintf(mii_prop, DLADM_STRSIZE, "%sfdx", mii_prop_prefix);
5922e7801d59Ssowmini 	(void) dladm_get_single_mac_stat(linkid, mii_prop, KSTAT_DATA_UINT32,
5923e7801d59Ssowmini 	    &speed);
5924e7801d59Ssowmini 	if (speed) {
5925e7801d59Ssowmini 		ret = B_TRUE;
5926e7801d59Ssowmini 		duplex  |= IS_FDX;
5927e7801d59Ssowmini 	}
5928e7801d59Ssowmini 	(void) snprintf(mii_prop, DLADM_STRSIZE, "%shdx", mii_prop_prefix);
5929e7801d59Ssowmini 	(void) dladm_get_single_mac_stat(linkid, mii_prop,
5930e7801d59Ssowmini 	    KSTAT_DATA_UINT32, &speed);
5931e7801d59Ssowmini 	if (speed) {
5932e7801d59Ssowmini 		ret = B_TRUE;
5933e7801d59Ssowmini 		duplex |= IS_HDX;
5934e7801d59Ssowmini 	}
5935e7801d59Ssowmini 	if (ret) {
5936e7801d59Ssowmini 		if (add_comma)
5937e7801d59Ssowmini 			(void) strncat(spbuf, ",", DLADM_STRSIZE);
5938e7801d59Ssowmini 		(void) strncat(spbuf, sp, DLADM_STRSIZE);
5939e7801d59Ssowmini 		if ((duplex & (IS_FDX|IS_HDX)) == (IS_FDX|IS_HDX))
5940e7801d59Ssowmini 			(void) strncat(spbuf, "-fh", DLADM_STRSIZE);
5941e7801d59Ssowmini 		else if (duplex & IS_FDX)
5942e7801d59Ssowmini 			(void) strncat(spbuf, "-f", DLADM_STRSIZE);
5943e7801d59Ssowmini 		else if (duplex & IS_HDX)
5944e7801d59Ssowmini 			(void) strncat(spbuf, "-h", DLADM_STRSIZE);
5945e7801d59Ssowmini 	}
5946e7801d59Ssowmini 	return (ret);
5947e7801d59Ssowmini }
5948e7801d59Ssowmini 
5949e7801d59Ssowmini static void
5950e7801d59Ssowmini dladm_print_output(print_state_t *statep, boolean_t parseable,
5951e7801d59Ssowmini     print_callback_t fn, void *arg)
5952e7801d59Ssowmini {
5953e7801d59Ssowmini 	int i;
5954e7801d59Ssowmini 	char *value;
5955e7801d59Ssowmini 	print_field_t **pf;
5956e7801d59Ssowmini 
5957e7801d59Ssowmini 	pf = statep->ps_fields;
5958e7801d59Ssowmini 	for (i = 0; i < statep->ps_nfields; i++) {
5959e7801d59Ssowmini 		statep->ps_lastfield = (i + 1 == statep->ps_nfields);
5960e7801d59Ssowmini 		value = (*fn)(pf[i], arg);
5961e7801d59Ssowmini 		if (value != NULL)
5962e7801d59Ssowmini 			print_field(statep, pf[i], value, parseable);
5963e7801d59Ssowmini 	}
5964e7801d59Ssowmini 	(void) putchar('\n');
5965e7801d59Ssowmini }
5966e7801d59Ssowmini 
5967e7801d59Ssowmini static void
5968e7801d59Ssowmini print_header(print_state_t *ps)
5969e7801d59Ssowmini {
5970e7801d59Ssowmini 	int i;
5971e7801d59Ssowmini 	print_field_t **pf;
5972e7801d59Ssowmini 
5973e7801d59Ssowmini 	pf = ps->ps_fields;
5974e7801d59Ssowmini 	for (i = 0; i < ps->ps_nfields; i++) {
5975e7801d59Ssowmini 		ps->ps_lastfield = (i + 1 == ps->ps_nfields);
5976e7801d59Ssowmini 		print_field(ps, pf[i], pf[i]->pf_header, B_FALSE);
5977e7801d59Ssowmini 	}
5978e7801d59Ssowmini 	(void) putchar('\n');
5979e7801d59Ssowmini }
5980e7801d59Ssowmini 
5981e7801d59Ssowmini static char *
5982e7801d59Ssowmini pause_str(int pause, int asmpause)
5983e7801d59Ssowmini {
5984e7801d59Ssowmini 	if (pause == 1)
5985e7801d59Ssowmini 		return ("bi");
5986e7801d59Ssowmini 	if (asmpause == 1)
5987e7801d59Ssowmini 		return ("tx");
5988e7801d59Ssowmini 	return ("none");
5989e7801d59Ssowmini }
5990e7801d59Ssowmini 
5991e7801d59Ssowmini static boolean_t
5992e7801d59Ssowmini link_is_ether(const char *link, datalink_id_t *linkid)
5993e7801d59Ssowmini {
5994e7801d59Ssowmini 	uint32_t media;
5995e7801d59Ssowmini 	datalink_class_t class;
5996e7801d59Ssowmini 
5997e7801d59Ssowmini 	if (dladm_name2info(link, linkid, NULL, &class, &media) ==
5998e7801d59Ssowmini 	    DLADM_STATUS_OK) {
5999e7801d59Ssowmini 		if (class == DATALINK_CLASS_PHYS && media == DL_ETHER)
6000e7801d59Ssowmini 			return (B_TRUE);
6001e7801d59Ssowmini 	}
6002e7801d59Ssowmini 	return (B_FALSE);
6003e7801d59Ssowmini }
6004