xref: /titanic_53/usr/src/cmd/dladm/dladm.c (revision da14cebe459d3275048785f25bd869cb09b5307f)
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>
49*da14cebeSEric Cheng #include <libdladm.h>
50f595a68aSyz147064 #include <libdllink.h>
51*da14cebeSEric Cheng #include <libdlstat.h>
52f595a68aSyz147064 #include <libdlaggr.h>
53f595a68aSyz147064 #include <libdlwlan.h>
54d62bc4baSyz147064 #include <libdlvlan.h>
55d62bc4baSyz147064 #include <libdlvnic.h>
560ba2cbe9Sxc151355 #include <libinetutil.h>
570ba2cbe9Sxc151355 #include <bsm/adt.h>
580ba2cbe9Sxc151355 #include <bsm/adt_event.h>
59*da14cebeSEric Cheng #include <libdlvnic.h>
60*da14cebeSEric Cheng #include <sys/types.h>
61*da14cebeSEric Cheng #include <sys/socket.h>
62*da14cebeSEric Cheng #include <sys/processor.h>
63*da14cebeSEric Cheng #include <netinet/in.h>
64*da14cebeSEric Cheng #include <arpa/inet.h>
65*da14cebeSEric Cheng #include <net/if_types.h>
66e7801d59Ssowmini #include <stddef.h>
677c478bd9Sstevel@tonic-gate 
68e7801d59Ssowmini #define	STR_UNDEF_VAL		"--"
697c478bd9Sstevel@tonic-gate #define	MAXPORT			256
70*da14cebeSEric Cheng #define	MAXVNIC			256
71d62bc4baSyz147064 #define	BUFLEN(lim, ptr)	(((lim) > (ptr)) ? ((lim) - (ptr)) : 0)
72d62bc4baSyz147064 #define	MAXLINELEN		1024
73d62bc4baSyz147064 #define	SMF_UPGRADE_FILE		"/var/svc/profile/upgrade"
74d62bc4baSyz147064 #define	SMF_UPGRADEDATALINK_FILE	"/var/svc/profile/upgrade_datalink"
75d62bc4baSyz147064 #define	SMF_DLADM_UPGRADE_MSG		" # added by dladm(1M)"
767c478bd9Sstevel@tonic-gate 
77e7801d59Ssowmini #define	CMD_TYPE_ANY		0xffffffff
78e7801d59Ssowmini #define	WIFI_CMD_SCAN		0x00000001
79e7801d59Ssowmini #define	WIFI_CMD_SHOW		0x00000002
80e7801d59Ssowmini #define	WIFI_CMD_ALL		(WIFI_CMD_SCAN | WIFI_CMD_SHOW)
81e7801d59Ssowmini 
82e7801d59Ssowmini /*
830d365605Sschuster  * Data structures and routines for printing output.
84e7801d59Ssowmini  * All non-parseable output is assumed to be in a columnar format.
850d365605Sschuster  * Multiple fields in parsable output are separated by ':'; single
860d365605Sschuster  * field output is printed as-is.
87e7801d59Ssowmini  *
88e7801d59Ssowmini  * Each sub-command is associated with a global array of pointers,
89e7801d59Ssowmini  * print_field_t *fields[], where the print_field_t contains information
90e7801d59Ssowmini  * about the format in which the output is to be printed.
91e7801d59Ssowmini  *
92e7801d59Ssowmini  * Sub-commands may be implemented in one of two ways:
93e7801d59Ssowmini  * (i)  the implementation could get all field values into a character
94e7801d59Ssowmini  *      buffer, with pf_offset containing the offset (for pf_name) within
95e7801d59Ssowmini  *      the buffer. The sub-command would make the needed system calls
96e7801d59Ssowmini  *      to obtain all possible column values and then invoke the
97e7801d59Ssowmini  *      dladm_print_field() function to print the specific fields
98e7801d59Ssowmini  *      requested in the command line. See the comments for dladm_print_field
99e7801d59Ssowmini  *      for further details.
100e7801d59Ssowmini  * (ii) Alternatively, each fields[i] entry could store a pf_index value
101e7801d59Ssowmini  *      that uniquely identifies the column to be printed. The implementation
102e7801d59Ssowmini  *      of the sub-command would then invoke dladm_print_output() with a
103e7801d59Ssowmini  *      callback function whose semantics are described below (see comments
104e7801d59Ssowmini  *      for dladm_print_output())
105e7801d59Ssowmini  *
106e7801d59Ssowmini  * Thus, an implementation of a sub-command must provide the following:
107e7801d59Ssowmini  *
108e7801d59Ssowmini  * static print_field_t sub_command_fields[] = {
109e7801d59Ssowmini  *	{<name>, <header>,<field width>,  <offset_or_index>, cmdtype},
110e7801d59Ssowmini  *	:
111e7801d59Ssowmini  *	{<name>, <header>,<field width>,  <offset_or_index>, cmdtype}
112e7801d59Ssowmini  * };
113e7801d59Ssowmini  *
114e7801d59Ssowmini  * #define	SUB_COMMAND_MAX_FIELDS sizeof \
115e7801d59Ssowmini  *		(sub_comand_fields) / sizeof (print_field_t))
116e7801d59Ssowmini  *
117e7801d59Ssowmini  * print_state_t sub_command_print_state;
118e7801d59Ssowmini  *
119e7801d59Ssowmini  * The function that parses command line arguments (typically
120e7801d59Ssowmini  * do_sub_command()) should then contain an invocation like:
121e7801d59Ssowmini  *
122e7801d59Ssowmini  *	fields = parse_output_fields(fields_str, sub_command_fields,
123e7801d59Ssowmini  *	    SUB_COMMAND_MAX_FIELDS, CMD_TYPE_ANY, &nfields);
124e7801d59Ssowmini  *
125e7801d59Ssowmini  * and store the resulting fields and nfields value in a print_state_t
126e7801d59Ssowmini  * structure tracked for the command.
127e7801d59Ssowmini  *
128e7801d59Ssowmini  *	sub_command_print_state.ps_fields = fields;
129e7801d59Ssowmini  *	sub_command_print_state.ps_nfields = nfields;
130e7801d59Ssowmini  *
131e7801d59Ssowmini  * To print the column header for the output, the print_header()
132e7801d59Ssowmini  * function must then be invoked by do_sub_command().
133e7801d59Ssowmini  *
134e7801d59Ssowmini  * Then if method (i) is used for the sub_command, the do_sub_command()
135e7801d59Ssowmini  * function should make the necessary system calls to fill up the buffer
136e7801d59Ssowmini  * and then invoke dladm_print_field(). An example of this method is
137e7801d59Ssowmini  * the implementation of do_show_link() and show_link();
138e7801d59Ssowmini  *
139e7801d59Ssowmini  * If method (ii) is used, do_sub_command should invoke dladm_print_output()
140e7801d59Ssowmini  * with a callback function that will be called for each field to be printed.
141e7801d59Ssowmini  * The callback function will be passed a pointer to the print_field_t
142e7801d59Ssowmini  * for the field, and the pf_index may then be used to identify the
143*da14cebeSEric Cheng  * system call required to find the value to be printed.
144e7801d59Ssowmini  */
145e7801d59Ssowmini 
146e7801d59Ssowmini typedef struct print_field_s {
147e7801d59Ssowmini 	const char	*pf_name;	/* name of column to be printed */
148e7801d59Ssowmini 	const char	*pf_header;	/* header for this column */
149e7801d59Ssowmini 	uint_t		pf_width;
150e7801d59Ssowmini 	union {
151e7801d59Ssowmini 		uint_t	_pf_index;	/* private index for sub-command */
152e7801d59Ssowmini 		size_t	_pf_offset;
153e7801d59Ssowmini 	}_pf_un;
154e7801d59Ssowmini #define	pf_index	_pf_un._pf_index
155e7801d59Ssowmini #define	pf_offset	_pf_un._pf_offset;
156e7801d59Ssowmini 	uint_t		pf_cmdtype;
157e7801d59Ssowmini } print_field_t;
158e7801d59Ssowmini 
159e7801d59Ssowmini /*
160e7801d59Ssowmini  * The state of the output is tracked in a print_state_t structure.
161e7801d59Ssowmini  * Each ps_fields[i] entry points at the global print_field_t array for
162e7801d59Ssowmini  * the sub-command, where ps_nfields is the number of requested fields.
163e7801d59Ssowmini  */
164e7801d59Ssowmini typedef struct print_state_s {
165e7801d59Ssowmini 	print_field_t	**ps_fields;
166e7801d59Ssowmini 	uint_t		ps_nfields;
167e7801d59Ssowmini 	boolean_t	ps_lastfield;
168e7801d59Ssowmini 	uint_t		ps_overflow;
169e7801d59Ssowmini } print_state_t;
170e7801d59Ssowmini 
171e7801d59Ssowmini typedef char *(*print_callback_t)(print_field_t *, void *);
172e7801d59Ssowmini static print_field_t **parse_output_fields(char *, print_field_t *, int,
173e7801d59Ssowmini     uint_t, uint_t *);
174e7801d59Ssowmini /*
175e7801d59Ssowmini  * print the header for the output
176e7801d59Ssowmini  */
177e7801d59Ssowmini static void print_header(print_state_t *);
178e7801d59Ssowmini static void print_field(print_state_t *, print_field_t *, const char *,
179e7801d59Ssowmini     boolean_t);
180e7801d59Ssowmini 
181e7801d59Ssowmini /*
182e7801d59Ssowmini  * to print output values, call dladm_print_output with a callback
183e7801d59Ssowmini  * function (*func)() that should parse the args and return an
184e7801d59Ssowmini  * unformatted character buffer with the value to be printed.
185e7801d59Ssowmini  *
186e7801d59Ssowmini  * dladm_print_output() prints the character buffer using the formatting
187e7801d59Ssowmini  * information provided in the print_field_t for that column.
188e7801d59Ssowmini  */
189e7801d59Ssowmini static void dladm_print_output(print_state_t *, boolean_t,
190e7801d59Ssowmini     print_callback_t, void *);
191e7801d59Ssowmini 
192e7801d59Ssowmini /*
193e7801d59Ssowmini  * helper function that, when invoked as dladm_print_field(pf, buf)
194e7801d59Ssowmini  * prints string which is offset by pf->pf_offset  within buf
195e7801d59Ssowmini  */
196e7801d59Ssowmini static char *dladm_print_field(print_field_t *, void *);
197e7801d59Ssowmini 
198e7801d59Ssowmini 
199e7801d59Ssowmini #define	MAX_FIELD_LEN	32
200e7801d59Ssowmini 
201e7801d59Ssowmini 
202d62bc4baSyz147064 typedef struct show_state {
2037c478bd9Sstevel@tonic-gate 	boolean_t	ls_firstonly;
2047c478bd9Sstevel@tonic-gate 	boolean_t	ls_donefirst;
2057c478bd9Sstevel@tonic-gate 	pktsum_t	ls_prevstats;
206d62bc4baSyz147064 	uint32_t	ls_flags;
207d62bc4baSyz147064 	dladm_status_t	ls_status;
208e7801d59Ssowmini 	print_state_t	ls_print;
209e7801d59Ssowmini 	boolean_t	ls_parseable;
210e7801d59Ssowmini 	boolean_t	ls_printheader;
211*da14cebeSEric Cheng 	boolean_t	ls_mac;
212*da14cebeSEric Cheng 	boolean_t	ls_hwgrp;
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 
229*da14cebeSEric Cheng typedef struct show_vnic_state {
230*da14cebeSEric Cheng 	datalink_id_t	vs_vnic_id;
231*da14cebeSEric Cheng 	datalink_id_t	vs_link_id;
232*da14cebeSEric Cheng 	char		vs_vnic[MAXLINKNAMELEN];
233*da14cebeSEric Cheng 	char		vs_link[MAXLINKNAMELEN];
234*da14cebeSEric Cheng 	boolean_t	vs_parseable;
235*da14cebeSEric Cheng 	boolean_t	vs_printheader;
236*da14cebeSEric Cheng 	boolean_t	vs_found;
237*da14cebeSEric Cheng 	boolean_t	vs_firstonly;
238*da14cebeSEric Cheng 	boolean_t	vs_donefirst;
239*da14cebeSEric Cheng 	boolean_t	vs_stats;
240*da14cebeSEric Cheng 	boolean_t	vs_printstats;
241*da14cebeSEric Cheng 	pktsum_t	vs_totalstats;
242*da14cebeSEric Cheng 	pktsum_t	vs_prevstats[MAXVNIC];
243*da14cebeSEric Cheng 	boolean_t	vs_etherstub;
244*da14cebeSEric Cheng 	dladm_status_t	vs_status;
245*da14cebeSEric Cheng 	uint32_t	vs_flags;
246*da14cebeSEric Cheng 	print_state_t	vs_print;
247*da14cebeSEric Cheng } show_vnic_state_t;
248*da14cebeSEric Cheng 
249*da14cebeSEric Cheng typedef struct show_usage_state_s {
250*da14cebeSEric Cheng 	boolean_t	us_plot;
251*da14cebeSEric Cheng 	boolean_t	us_parseable;
252*da14cebeSEric Cheng 	boolean_t	us_printheader;
253*da14cebeSEric Cheng 	boolean_t	us_first;
254*da14cebeSEric Cheng 	print_state_t	us_print;
255*da14cebeSEric Cheng } show_usage_state_t;
256*da14cebeSEric Cheng 
2578d5c46e6Sam223141 typedef void cmdfunc_t(int, char **, const char *);
2580ba2cbe9Sxc151355 
259*da14cebeSEric Cheng static cmdfunc_t do_show_link, do_show_wifi, do_show_phys;
2600ba2cbe9Sxc151355 static cmdfunc_t do_create_aggr, do_delete_aggr, do_add_aggr, do_remove_aggr;
261d62bc4baSyz147064 static cmdfunc_t do_modify_aggr, do_show_aggr, do_up_aggr;
2620ba2cbe9Sxc151355 static cmdfunc_t do_scan_wifi, do_connect_wifi, do_disconnect_wifi;
2630ba2cbe9Sxc151355 static cmdfunc_t do_show_linkprop, do_set_linkprop, do_reset_linkprop;
2640ba2cbe9Sxc151355 static cmdfunc_t do_create_secobj, do_delete_secobj, do_show_secobj;
2650ba2cbe9Sxc151355 static cmdfunc_t do_init_linkprop, do_init_secobj;
266d62bc4baSyz147064 static cmdfunc_t do_create_vlan, do_delete_vlan, do_up_vlan, do_show_vlan;
267d62bc4baSyz147064 static cmdfunc_t do_rename_link, do_delete_phys, do_init_phys;
268d62bc4baSyz147064 static cmdfunc_t do_show_linkmap;
269e7801d59Ssowmini static cmdfunc_t do_show_ether;
270*da14cebeSEric Cheng static cmdfunc_t do_create_vnic, do_delete_vnic, do_show_vnic;
271*da14cebeSEric Cheng static cmdfunc_t do_up_vnic;
272*da14cebeSEric Cheng static cmdfunc_t do_create_etherstub, do_delete_etherstub, do_show_etherstub;
273*da14cebeSEric Cheng static cmdfunc_t do_show_usage;
274*da14cebeSEric Cheng 
275*da14cebeSEric Cheng static void 	do_up_vnic_common(int, char **, const char *, boolean_t);
2767c478bd9Sstevel@tonic-gate 
277d62bc4baSyz147064 static void	altroot_cmd(char *, int, char **);
278d62bc4baSyz147064 static int	show_linkprop_onelink(datalink_id_t, void *);
279f4b3ec61Sdh155122 
2806be03d0bSVasumathi Sundaram - Sun Microsystems static void	link_stats(datalink_id_t, uint_t, char *, show_state_t *);
281d62bc4baSyz147064 static void	aggr_stats(datalink_id_t, show_grp_state_t *, uint_t);
282*da14cebeSEric Cheng static void	vnic_stats(show_vnic_state_t *, uint32_t);
2837c478bd9Sstevel@tonic-gate 
284d62bc4baSyz147064 static int	get_one_kstat(const char *, const char *, uint8_t,
285d62bc4baSyz147064 		    void *, boolean_t);
286ba2e4443Sseb static void	get_mac_stats(const char *, pktsum_t *);
2877c478bd9Sstevel@tonic-gate static void	get_link_stats(const char *, pktsum_t *);
288d62bc4baSyz147064 static uint64_t	get_ifspeed(const char *, boolean_t);
289d62bc4baSyz147064 static const char	*get_linkstate(const char *, boolean_t, char *);
290d62bc4baSyz147064 static const char	*get_linkduplex(const char *, boolean_t, char *);
2917c478bd9Sstevel@tonic-gate 
292e7801d59Ssowmini static int	show_etherprop(datalink_id_t, void *);
293e7801d59Ssowmini static void	show_ether_xprop(datalink_id_t, void *);
294e7801d59Ssowmini static boolean_t get_speed_duplex(datalink_id_t, const char *, char *,
295e7801d59Ssowmini     char *, boolean_t);
296e7801d59Ssowmini static char 	*pause_str(int, int);
297e7801d59Ssowmini static boolean_t	link_is_ether(const char *, datalink_id_t *);
298e7801d59Ssowmini 
299e7801d59Ssowmini #define	IS_FDX	0x10
300e7801d59Ssowmini #define	IS_HDX	0x01
301e7801d59Ssowmini 
30233343a97Smeem static boolean_t str2int(const char *, int *);
30333343a97Smeem static void	die(const char *, ...);
30433343a97Smeem static void	die_optdup(int);
3058d5c46e6Sam223141 static void	die_opterr(int, int, const char *);
30633343a97Smeem static void	die_dlerr(dladm_status_t, const char *, ...);
30733343a97Smeem static void	warn(const char *, ...);
30833343a97Smeem static void	warn_dlerr(dladm_status_t, const char *, ...);
30933343a97Smeem 
3107c478bd9Sstevel@tonic-gate typedef struct	cmd {
3117c478bd9Sstevel@tonic-gate 	char		*c_name;
3120ba2cbe9Sxc151355 	cmdfunc_t	*c_fn;
3138d5c46e6Sam223141 	const char	*c_usage;
3147c478bd9Sstevel@tonic-gate } cmd_t;
3157c478bd9Sstevel@tonic-gate 
3167c478bd9Sstevel@tonic-gate static cmd_t	cmds[] = {
3178d5c46e6Sam223141 	{ "show-link",		do_show_link,
3188d5c46e6Sam223141 	    "\tshow-link\t[-pP] [-o <field>,..] [-s [-i <interval>]] [<link>]"},
3198d5c46e6Sam223141 	{ "rename-link",	do_rename_link,
3208d5c46e6Sam223141 	    "\trename-link\t[-R <root-dir>] <oldlink> <newlink>\n"	},
3218d5c46e6Sam223141 	{ "create-aggr",	do_create_aggr,
3228d5c46e6Sam223141 	    "\tcreate-aggr\t[-t] [-R <root-dir>] [-P <policy>] [-L <mode>]\n"
3238d5c46e6Sam223141 	    "\t\t\t[-T <time>] [-u <address>] [-l <link>] ... <link>"	},
3248d5c46e6Sam223141 	{ "delete-aggr",	do_delete_aggr,
3258d5c46e6Sam223141 	    "\tdelete-aggr\t[-t] [-R <root-dir>] <link>"		},
3268d5c46e6Sam223141 	{ "add-aggr",		do_add_aggr,
3278d5c46e6Sam223141 	    "\tadd-aggr\t[-t] [-R <root-dir>] [-l <link>] ... <link>"	},
3288d5c46e6Sam223141 	{ "remove-aggr",	do_remove_aggr,
3298d5c46e6Sam223141 	    "\tremove-aggr\t[-t] [-R <root-dir>] [-l <link>] ... <link>"},
3308d5c46e6Sam223141 	{ "modify-aggr",	do_modify_aggr,
3318d5c46e6Sam223141 	    "\tmodify-aggr\t[-t] [-R <root-dir>] [-P <policy>] [-L <mode>]\n"
3328d5c46e6Sam223141 	    "\t\t\t[-T <time>] [-u <address>] <link>"			},
3338d5c46e6Sam223141 	{ "show-aggr",		do_show_aggr,
3348d5c46e6Sam223141 	    "\tshow-aggr\t[-pPLx] [-o <field>,..] [-s [-i <interval>]] "
3358d5c46e6Sam223141 	    "[<link>]\n"						},
3368d5c46e6Sam223141 	{ "up-aggr",		do_up_aggr,		NULL		},
3378d5c46e6Sam223141 	{ "scan-wifi",		do_scan_wifi,
3388d5c46e6Sam223141 	    "\tscan-wifi\t[-p] [-o <field>,...] [<link>]"		},
3398d5c46e6Sam223141 	{ "connect-wifi",	do_connect_wifi,
3408d5c46e6Sam223141 	    "\tconnect-wifi\t[-e <essid>] [-i <bssid>] [-k <key>,...] "
3418d5c46e6Sam223141 	    "[-s wep|wpa]\n"
3428d5c46e6Sam223141 	    "\t\t\t[-a open|shared] [-b bss|ibss] [-c] [-m a|b|g]\n"
3438d5c46e6Sam223141 	    "\t\t\t[-T <time>] [<link>]"				},
3448d5c46e6Sam223141 	{ "disconnect-wifi",	do_disconnect_wifi,
3458d5c46e6Sam223141 	    "\tdisconnect-wifi\t[-a] [<link>]"				},
3468d5c46e6Sam223141 	{ "show-wifi",		do_show_wifi,
3478d5c46e6Sam223141 	    "\tshow-wifi\t[-p] [-o <field>,...] [<link>]\n"		},
3488d5c46e6Sam223141 	{ "show-linkprop",	do_show_linkprop,
3498d5c46e6Sam223141 	    "\tshow-linkprop\t[-cP] [-o <field>,...] [-p <prop>,...] <name>"},
3508d5c46e6Sam223141 	{ "set-linkprop",	do_set_linkprop,
3518d5c46e6Sam223141 	    "\tset-linkprop\t[-t] [-R <root-dir>] -p <prop>=<value>[,...] "
3528d5c46e6Sam223141 	    "<name>"							},
3538d5c46e6Sam223141 	{ "reset-linkprop",	do_reset_linkprop,
3548d5c46e6Sam223141 	    "\treset-linkprop\t[-t] [-R <root-dir>] [-p <prop>,...] <name>\n" },
3558d5c46e6Sam223141 	{ "show-ether",		do_show_ether,
3568d5c46e6Sam223141 	    "\tshow-ether\t[-px][-o <field>,...] <link>\n"		},
3578d5c46e6Sam223141 	{ "create-secobj",	do_create_secobj,
3588d5c46e6Sam223141 	    "\tcreate-secobj\t[-t] [-R <root-dir>] [-f <file>] -c <class> "
3598d5c46e6Sam223141 	    "<secobj>"							},
3608d5c46e6Sam223141 	{ "delete-secobj",	do_delete_secobj,
3618d5c46e6Sam223141 	    "\tdelete-secobj\t[-t] [-R <root-dir>] <secobj>[,...]"	},
3628d5c46e6Sam223141 	{ "show-secobj",	do_show_secobj,
3638d5c46e6Sam223141 	    "\tshow-secobj\t[-pP] [-o <field>,...] [<secobj>,...]\n"	},
3648d5c46e6Sam223141 	{ "init-linkprop",	do_init_linkprop,	NULL		},
3658d5c46e6Sam223141 	{ "init-secobj",	do_init_secobj,		NULL		},
3668d5c46e6Sam223141 	{ "create-vlan", 	do_create_vlan,
3678d5c46e6Sam223141 	    "\tcreate-vlan\t[-ft] [-R <root-dir>] -l <link> -v <vid> [link]" },
3688d5c46e6Sam223141 	{ "delete-vlan", 	do_delete_vlan,
3698d5c46e6Sam223141 	    "\tdelete-vlan\t[-t] [-R <root-dir>] <link>"		},
3708d5c46e6Sam223141 	{ "show-vlan",		do_show_vlan,
3718d5c46e6Sam223141 	    "\tshow-vlan\t[-pP] [-o <field>,..] [<link>]\n"		},
3728d5c46e6Sam223141 	{ "up-vlan",		do_up_vlan,		NULL		},
3738d5c46e6Sam223141 	{ "delete-phys",	do_delete_phys,
3748d5c46e6Sam223141 	    "\tdelete-phys\t<link>"					},
3758d5c46e6Sam223141 	{ "show-phys",		do_show_phys,
376*da14cebeSEric Cheng 	    "\tshow-phys\t[-pP] [-o <field>,..] [-H] [<link>]"		},
3778d5c46e6Sam223141 	{ "init-phys",		do_init_phys,		NULL		},
378*da14cebeSEric Cheng 	{ "show-linkmap",	do_show_linkmap,	NULL		},
379*da14cebeSEric Cheng 	{ "create-vnic",	do_create_vnic,
380*da14cebeSEric Cheng 	    "\tcreate-vnic     [-t] [-R <root-dir>] -l <link> [-m <value> |"
381*da14cebeSEric Cheng 	    " auto |\n"
382*da14cebeSEric Cheng 	    "\t                {factory [-n <slot-identifier>]} |\n"
383*da14cebeSEric Cheng 	    "\t                {random [-r <prefix>]}] [-v vlan-tag [-f]]\n"
384*da14cebeSEric Cheng 	    "\t                -p <prop>=<value>[,...] [-H]"
385*da14cebeSEric Cheng 	    " <vnic-link>\n"	},
386*da14cebeSEric Cheng 	{ "delete-vnic",	do_delete_vnic,
387*da14cebeSEric Cheng 	    "\tdelete-vnic     [-t] [-R <root-dir>] <vnic-link>\n" 	},
388*da14cebeSEric Cheng 	{ "show-vnic",		do_show_vnic,
389*da14cebeSEric Cheng 	    "\tshow-vnic       [-pP] [-l <link>] [-s [-i <interval>]]"	},
390*da14cebeSEric Cheng 	{ "up-vnic",		do_up_vnic,		NULL		},
391*da14cebeSEric Cheng 	{ "create-etherstub",	do_create_etherstub,
392*da14cebeSEric Cheng 	    "\tcreate-etherstub [-t] [-R <root-dir>] <link>\n"		},
393*da14cebeSEric Cheng 	{ "delete-etherstub",	do_delete_etherstub,
394*da14cebeSEric Cheng 	    "\tdelete-etherstub [-t] [-R <root-dir>] <link>\n"		},
395*da14cebeSEric Cheng 	{ "show-etherstub",	do_show_etherstub,
396*da14cebeSEric Cheng 	    "\tshow-etherstub  [-t] [-R <root-dir>] [<link>]\n" 	},
397*da14cebeSEric Cheng 	{ "show-usage",		do_show_usage,
398*da14cebeSEric Cheng 	    "\tshow-usage      [-d|-p -F <format>] [-f <filename>]\n"
399*da14cebeSEric Cheng 	    "\t                [-s <time>] [-e <time>] <link>\n"	}
4007c478bd9Sstevel@tonic-gate };
4017c478bd9Sstevel@tonic-gate 
402d62bc4baSyz147064 static const struct option lopts[] = {
4037c478bd9Sstevel@tonic-gate 	{"vlan-id",	required_argument,	0, 'v'},
404e7801d59Ssowmini 	{"output",	required_argument,	0, 'o'},
4057c478bd9Sstevel@tonic-gate 	{"dev",		required_argument,	0, 'd'},
4067c478bd9Sstevel@tonic-gate 	{"policy",	required_argument,	0, 'P'},
407d62bc4baSyz147064 	{"lacp-mode",	required_argument,	0, 'L'},
4087c478bd9Sstevel@tonic-gate 	{"lacp-timer",	required_argument,	0, 'T'},
4097c478bd9Sstevel@tonic-gate 	{"unicast",	required_argument,	0, 'u'},
410d62bc4baSyz147064 	{"temporary",	no_argument,		0, 't'},
411d62bc4baSyz147064 	{"root-dir",	required_argument,	0, 'R'},
412d62bc4baSyz147064 	{"link",	required_argument,	0, 'l'},
413d62bc4baSyz147064 	{"forcible",	no_argument,		0, 'f'},
414*da14cebeSEric Cheng 	{"bw-limit",	required_argument,	0, 'b'},
415*da14cebeSEric Cheng 	{"mac-address",	required_argument,	0, 'm'},
416*da14cebeSEric Cheng 	{"slot",	required_argument,	0, 'n'},
417d62bc4baSyz147064 	{ 0, 0, 0, 0 }
418d62bc4baSyz147064 };
419d62bc4baSyz147064 
420d62bc4baSyz147064 static const struct option show_lopts[] = {
4217c478bd9Sstevel@tonic-gate 	{"statistics",	no_argument,		0, 's'},
422*da14cebeSEric Cheng 	{"continuous",	no_argument,		0, 'S'},
4237c478bd9Sstevel@tonic-gate 	{"interval",	required_argument,	0, 'i'},
4247c478bd9Sstevel@tonic-gate 	{"parseable",	no_argument,		0, 'p'},
425d62bc4baSyz147064 	{"extended",	no_argument,		0, 'x'},
426e7801d59Ssowmini 	{"output",	required_argument,	0, 'o'},
427d62bc4baSyz147064 	{"persistent",	no_argument,		0, 'P'},
428d62bc4baSyz147064 	{"lacp",	no_argument,		0, 'L'},
4297c478bd9Sstevel@tonic-gate 	{ 0, 0, 0, 0 }
4307c478bd9Sstevel@tonic-gate };
4317c478bd9Sstevel@tonic-gate 
4320ba2cbe9Sxc151355 static const struct option prop_longopts[] = {
4330ba2cbe9Sxc151355 	{"temporary",	no_argument,		0, 't'  },
434e7801d59Ssowmini 	{"output",	required_argument,	0, 'o'  },
4350ba2cbe9Sxc151355 	{"root-dir",	required_argument,	0, 'R'  },
4360ba2cbe9Sxc151355 	{"prop",	required_argument,	0, 'p'  },
4370ba2cbe9Sxc151355 	{"parseable",	no_argument,		0, 'c'  },
4380ba2cbe9Sxc151355 	{"persistent",	no_argument,		0, 'P'  },
4390ba2cbe9Sxc151355 	{ 0, 0, 0, 0 }
4400ba2cbe9Sxc151355 };
4410ba2cbe9Sxc151355 
4420ba2cbe9Sxc151355 static const struct option wifi_longopts[] = {
4430ba2cbe9Sxc151355 	{"parseable",	no_argument,		0, 'p'  },
4440ba2cbe9Sxc151355 	{"output",	required_argument,	0, 'o'  },
4450ba2cbe9Sxc151355 	{"essid",	required_argument,	0, 'e'  },
4460ba2cbe9Sxc151355 	{"bsstype",	required_argument,	0, 'b'  },
4470ba2cbe9Sxc151355 	{"mode",	required_argument,	0, 'm'  },
4480ba2cbe9Sxc151355 	{"key",		required_argument,	0, 'k'  },
4490ba2cbe9Sxc151355 	{"sec",		required_argument,	0, 's'  },
4500ba2cbe9Sxc151355 	{"auth",	required_argument,	0, 'a'  },
4510ba2cbe9Sxc151355 	{"create-ibss",	required_argument,	0, 'c'  },
4520ba2cbe9Sxc151355 	{"timeout",	required_argument,	0, 'T'  },
4530ba2cbe9Sxc151355 	{"all-links",	no_argument,		0, 'a'  },
4540ba2cbe9Sxc151355 	{"temporary",	no_argument,		0, 't'  },
4550ba2cbe9Sxc151355 	{"root-dir",	required_argument,	0, 'R'  },
4560ba2cbe9Sxc151355 	{"persistent",	no_argument,		0, 'P'  },
4570ba2cbe9Sxc151355 	{"file",	required_argument,	0, 'f'  },
4580ba2cbe9Sxc151355 	{ 0, 0, 0, 0 }
4590ba2cbe9Sxc151355 };
460e7801d59Ssowmini static const struct option showeth_lopts[] = {
461e7801d59Ssowmini 	{"parseable",	no_argument,		0, 'p'	},
462e7801d59Ssowmini 	{"extended",	no_argument,		0, 'x'	},
463e7801d59Ssowmini 	{"output",	required_argument,	0, 'o'	},
464e7801d59Ssowmini 	{ 0, 0, 0, 0 }
465e7801d59Ssowmini };
466e7801d59Ssowmini 
467*da14cebeSEric Cheng static const struct option vnic_lopts[] = {
468*da14cebeSEric Cheng 	{"temporary",	no_argument,		0, 't'	},
469*da14cebeSEric Cheng 	{"root-dir",	required_argument,	0, 'R'	},
470*da14cebeSEric Cheng 	{"dev",		required_argument,	0, 'd'	},
471*da14cebeSEric Cheng 	{"mac-address",	required_argument,	0, 'm'	},
472*da14cebeSEric Cheng 	{"cpus",	required_argument,	0, 'c'	},
473*da14cebeSEric Cheng 	{"bw-limit",	required_argument,	0, 'b'	},
474*da14cebeSEric Cheng 	{"slot",	required_argument,	0, 'n'	},
475*da14cebeSEric Cheng 	{"mac-prefix",	required_argument,	0, 'r'	},
476*da14cebeSEric Cheng 	{ 0, 0, 0, 0 }
477*da14cebeSEric Cheng };
478*da14cebeSEric Cheng 
479*da14cebeSEric Cheng static const struct option etherstub_lopts[] = {
480*da14cebeSEric Cheng 	{"temporary",	no_argument,		0, 't'	},
481*da14cebeSEric Cheng 	{"root-dir",	required_argument,	0, 'R'	},
482*da14cebeSEric Cheng 	{ 0, 0, 0, 0 }
483*da14cebeSEric Cheng };
484*da14cebeSEric Cheng 
485e7801d59Ssowmini /*
486e7801d59Ssowmini  * structures for 'dladm show-ether'
487e7801d59Ssowmini  */
488e7801d59Ssowmini typedef struct ether_fields_buf_s
489e7801d59Ssowmini {
490e7801d59Ssowmini 	char	eth_link[15];
491e7801d59Ssowmini 	char	eth_ptype[8];
492e7801d59Ssowmini 	char	eth_state[8];
493e7801d59Ssowmini 	char	eth_autoneg[5];
494e7801d59Ssowmini 	char	eth_spdx[31];
495e7801d59Ssowmini 	char	eth_pause[6];
496e7801d59Ssowmini 	char	eth_rem_fault[16];
497e7801d59Ssowmini } ether_fields_buf_t;
498e7801d59Ssowmini 
499e7801d59Ssowmini static print_field_t ether_fields[] = {
500e7801d59Ssowmini /* name,	header,			field width,  offset,	cmdtype */
501e7801d59Ssowmini { "link",	"LINK",			15,
502e7801d59Ssowmini     offsetof(ether_fields_buf_t, eth_link),	CMD_TYPE_ANY},
503e7801d59Ssowmini { "ptype",	"PTYPE",		8,
504e7801d59Ssowmini     offsetof(ether_fields_buf_t, eth_ptype),	CMD_TYPE_ANY},
505e7801d59Ssowmini { "state",	"STATE",		8,
506e7801d59Ssowmini     offsetof(ether_fields_buf_t, eth_state),	CMD_TYPE_ANY},
507e7801d59Ssowmini { "auto",	"AUTO",			5,
508e7801d59Ssowmini     offsetof(ether_fields_buf_t, eth_autoneg),	CMD_TYPE_ANY},
509e7801d59Ssowmini { "speed-duplex", "SPEED-DUPLEX",	31,
510e7801d59Ssowmini     offsetof(ether_fields_buf_t, eth_spdx),	CMD_TYPE_ANY},
511e7801d59Ssowmini { "pause",	"PAUSE",		6,
512e7801d59Ssowmini     offsetof(ether_fields_buf_t, eth_pause),	CMD_TYPE_ANY},
513e7801d59Ssowmini { "rem_fault",	"REM_FAULT",		16,
514e7801d59Ssowmini     offsetof(ether_fields_buf_t, eth_rem_fault),	CMD_TYPE_ANY}}
515e7801d59Ssowmini ;
516e7801d59Ssowmini #define	ETHER_MAX_FIELDS	(sizeof (ether_fields) / sizeof (print_field_t))
517e7801d59Ssowmini 
518e7801d59Ssowmini typedef struct print_ether_state {
519e7801d59Ssowmini 	const char	*es_link;
520e7801d59Ssowmini 	boolean_t	es_parseable;
521e7801d59Ssowmini 	boolean_t	es_header;
522e7801d59Ssowmini 	boolean_t	es_extended;
523e7801d59Ssowmini 	print_state_t	es_print;
524e7801d59Ssowmini } print_ether_state_t;
525e7801d59Ssowmini 
526e7801d59Ssowmini /*
527*da14cebeSEric Cheng  * structures for 'dladm show-link -s' (print statistics)
528e7801d59Ssowmini  */
529e7801d59Ssowmini typedef enum {
530e7801d59Ssowmini 	DEVS_LINK,
531e7801d59Ssowmini 	DEVS_IPKTS,
532e7801d59Ssowmini 	DEVS_RBYTES,
533e7801d59Ssowmini 	DEVS_IERRORS,
534e7801d59Ssowmini 	DEVS_OPKTS,
535e7801d59Ssowmini 	DEVS_OBYTES,
536e7801d59Ssowmini 	DEVS_OERRORS
537e7801d59Ssowmini } devs_field_index_t;
538e7801d59Ssowmini 
539e7801d59Ssowmini static print_field_t devs_fields[] = {
540e7801d59Ssowmini /* name,	header,		field width,	index,		cmdtype	*/
541e7801d59Ssowmini { "link",	"LINK",			15,	DEVS_LINK,	CMD_TYPE_ANY},
542e7801d59Ssowmini { "ipackets",	"IPACKETS",		10,	DEVS_IPKTS,	CMD_TYPE_ANY},
543e7801d59Ssowmini { "rbytes",	"RBYTES",		8,	DEVS_RBYTES,	CMD_TYPE_ANY},
544e7801d59Ssowmini { "ierrors",	"IERRORS",		10,	DEVS_IERRORS,	CMD_TYPE_ANY},
545e7801d59Ssowmini { "opackets",	"OPACKETS",		12,	DEVS_OPKTS,	CMD_TYPE_ANY},
546e7801d59Ssowmini { "obytes",	"OBYTES",		12,	DEVS_OBYTES,	CMD_TYPE_ANY},
547e7801d59Ssowmini { "oerrors",	"OERRORS",		8,	DEVS_OERRORS,	CMD_TYPE_ANY}}
548e7801d59Ssowmini ;
549e7801d59Ssowmini #define	DEVS_MAX_FIELDS	(sizeof (devs_fields) / sizeof (print_field_t))
550e7801d59Ssowmini 
551e7801d59Ssowmini /*
552e7801d59Ssowmini  * buffer used by print functions for show-{link,phys,vlan} commands.
553e7801d59Ssowmini  */
554e7801d59Ssowmini typedef struct link_fields_buf_s {
555e7801d59Ssowmini 	char link_name[MAXLINKNAMELEN];
556e7801d59Ssowmini 	char link_class[DLADM_STRSIZE];
557c08e5e1aSdr146992 	char link_mtu[11];
558e7801d59Ssowmini 	char link_state[DLADM_STRSIZE];
559e7801d59Ssowmini 	char link_over[MAXLINKNAMELEN];
5604045d941Ssowmini 	char link_phys_state[DLADM_STRSIZE];
561e7801d59Ssowmini 	char link_phys_media[DLADM_STRSIZE];
562e7801d59Ssowmini 	char link_phys_speed[DLADM_STRSIZE];
563e7801d59Ssowmini 	char link_phys_duplex[DLPI_LINKNAME_MAX];
564e7801d59Ssowmini 	char link_phys_device[DLPI_LINKNAME_MAX];
565e7801d59Ssowmini 	char link_flags[6];
566e7801d59Ssowmini 	char link_vlan_vid[6];
567e7801d59Ssowmini } link_fields_buf_t;
568e7801d59Ssowmini 
569e7801d59Ssowmini /*
570e7801d59Ssowmini  * structures for 'dladm show-link'
571e7801d59Ssowmini  */
572e7801d59Ssowmini static print_field_t link_fields[] = {
573e7801d59Ssowmini /* name,	header,		field width,	offset,	cmdtype		*/
574e7801d59Ssowmini { "link",	"LINK",		11,
575e7801d59Ssowmini     offsetof(link_fields_buf_t, link_name),	CMD_TYPE_ANY},
576e7801d59Ssowmini { "class",	"CLASS",	 8,
577e7801d59Ssowmini     offsetof(link_fields_buf_t, link_class),	CMD_TYPE_ANY},
578e7801d59Ssowmini { "mtu",	"MTU",		 6,
579e7801d59Ssowmini     offsetof(link_fields_buf_t, link_mtu),	CMD_TYPE_ANY},
580e7801d59Ssowmini { "state",	"STATE",	 8,
581e7801d59Ssowmini     offsetof(link_fields_buf_t, link_state),	CMD_TYPE_ANY},
582e7801d59Ssowmini { "over",	"OVER",		DLPI_LINKNAME_MAX,
583e7801d59Ssowmini     offsetof(link_fields_buf_t, link_over),	CMD_TYPE_ANY}}
584e7801d59Ssowmini ;
585e7801d59Ssowmini #define	DEV_LINK_FIELDS	(sizeof (link_fields) / sizeof (print_field_t))
586e7801d59Ssowmini 
587e7801d59Ssowmini /*
588e7801d59Ssowmini  * structures for 'dladm show-aggr'
589e7801d59Ssowmini  */
590e7801d59Ssowmini typedef struct laggr_fields_buf_s {
591e7801d59Ssowmini 	char laggr_name[DLPI_LINKNAME_MAX];
592e7801d59Ssowmini 	char laggr_policy[9];
593e7801d59Ssowmini 	char laggr_addrpolicy[ETHERADDRL * 3 + 3];
594e7801d59Ssowmini 	char laggr_lacpactivity[14];
595e7801d59Ssowmini 	char laggr_lacptimer[DLADM_STRSIZE];
596e7801d59Ssowmini 	char laggr_flags[7];
597e7801d59Ssowmini } laggr_fields_buf_t;
598e7801d59Ssowmini 
599e7801d59Ssowmini typedef struct laggr_args_s {
600e7801d59Ssowmini 	int			laggr_lport; /* -1 indicates the aggr itself */
601e7801d59Ssowmini 	const char 		*laggr_link;
602e7801d59Ssowmini 	dladm_aggr_grp_attr_t	*laggr_ginfop;
603e7801d59Ssowmini 	dladm_status_t		*laggr_status;
604e7801d59Ssowmini 	pktsum_t		*laggr_pktsumtot; /* -s only */
605e7801d59Ssowmini 	pktsum_t		*laggr_prevstats; /* -s only */
606e7801d59Ssowmini 	boolean_t		laggr_parseable;
607e7801d59Ssowmini } laggr_args_t;
608e7801d59Ssowmini 
609e7801d59Ssowmini static print_field_t laggr_fields[] = {
610e7801d59Ssowmini /* name,		header,		field width,	offset,	cmdtype	*/
611e7801d59Ssowmini { "link",		"LINK",		15,
612e7801d59Ssowmini     offsetof(laggr_fields_buf_t, laggr_name),		CMD_TYPE_ANY},
613e7801d59Ssowmini { "policy",		"POLICY",	 8,
614e7801d59Ssowmini     offsetof(laggr_fields_buf_t, laggr_policy),	CMD_TYPE_ANY},
615e7801d59Ssowmini { "addrpolicy",		"ADDRPOLICY",	 ETHERADDRL * 3 + 2,
616e7801d59Ssowmini     offsetof(laggr_fields_buf_t, laggr_addrpolicy),	CMD_TYPE_ANY},
617e7801d59Ssowmini { "lacpactivity",	"LACPACTIVITY",	 13,
618e7801d59Ssowmini     offsetof(laggr_fields_buf_t, laggr_lacpactivity),	CMD_TYPE_ANY},
619e7801d59Ssowmini { "lacptimer",		"LACPTIMER",	 11,
620e7801d59Ssowmini     offsetof(laggr_fields_buf_t, laggr_lacptimer),	CMD_TYPE_ANY},
621e7801d59Ssowmini { "flags",		"FLAGS",	 7,
622e7801d59Ssowmini     offsetof(laggr_fields_buf_t, laggr_flags),	CMD_TYPE_ANY}}
623e7801d59Ssowmini ;
624e7801d59Ssowmini #define	LAGGR_MAX_FIELDS	(sizeof (laggr_fields) / sizeof (print_field_t))
625e7801d59Ssowmini 
626e7801d59Ssowmini /*
627e7801d59Ssowmini  * structures for 'dladm show-aggr -x'.
628e7801d59Ssowmini  */
629e7801d59Ssowmini typedef enum {
630e7801d59Ssowmini 	AGGR_X_LINK,
631e7801d59Ssowmini 	AGGR_X_PORT,
632e7801d59Ssowmini 	AGGR_X_SPEED,
633e7801d59Ssowmini 	AGGR_X_DUPLEX,
634e7801d59Ssowmini 	AGGR_X_STATE,
635e7801d59Ssowmini 	AGGR_X_ADDRESS,
636e7801d59Ssowmini 	AGGR_X_PORTSTATE
637e7801d59Ssowmini } aggr_x_field_index_t;
638e7801d59Ssowmini 
639e7801d59Ssowmini static print_field_t aggr_x_fields[] = {
640e7801d59Ssowmini /* name,	header,		field width,	index,		cmdtype	*/
641e7801d59Ssowmini { "link",	"LINK",			11,	AGGR_X_LINK,	CMD_TYPE_ANY},
642e7801d59Ssowmini { "port",	"PORT",			14,	AGGR_X_PORT,	CMD_TYPE_ANY},
643e7801d59Ssowmini { "speed",	"SPEED",		4,	AGGR_X_SPEED,	CMD_TYPE_ANY},
644e7801d59Ssowmini { "duplex",	"DUPLEX",		9,	AGGR_X_DUPLEX,	CMD_TYPE_ANY},
645e7801d59Ssowmini { "state",	"STATE",		9,	AGGR_X_STATE,	CMD_TYPE_ANY},
646e7801d59Ssowmini { "address",	"ADDRESS",		18,	AGGR_X_ADDRESS,	CMD_TYPE_ANY},
647e7801d59Ssowmini { "portstate",	"PORTSTATE",		15,	AGGR_X_PORTSTATE, CMD_TYPE_ANY}}
648e7801d59Ssowmini ;
649e7801d59Ssowmini #define	AGGR_X_MAX_FIELDS \
650e7801d59Ssowmini 	(sizeof (aggr_x_fields) / sizeof (print_field_t))
651e7801d59Ssowmini 
652e7801d59Ssowmini /*
653e7801d59Ssowmini  * structures for 'dladm show-aggr -s'.
654e7801d59Ssowmini  */
655e7801d59Ssowmini typedef enum {
656e7801d59Ssowmini 	AGGR_S_LINK,
657e7801d59Ssowmini 	AGGR_S_PORT,
658e7801d59Ssowmini 	AGGR_S_IPKTS,
659e7801d59Ssowmini 	AGGR_S_RBYTES,
660e7801d59Ssowmini 	AGGR_S_OPKTS,
661e7801d59Ssowmini 	AGGR_S_OBYTES,
662e7801d59Ssowmini 	AGGR_S_IPKTDIST,
663e7801d59Ssowmini 	AGGR_S_OPKTDIST
664e7801d59Ssowmini } aggr_s_field_index_t;
665e7801d59Ssowmini 
666e7801d59Ssowmini static print_field_t aggr_s_fields[] = {
667e7801d59Ssowmini /* name,		header,		field width,	index,	cmdtype	*/
668e7801d59Ssowmini { "link",		"LINK",		11,	AGGR_S_LINK,
669e7801d59Ssowmini     CMD_TYPE_ANY},
670e7801d59Ssowmini { "port",		"PORT",		9,	AGGR_S_PORT,
671e7801d59Ssowmini     CMD_TYPE_ANY},
672e7801d59Ssowmini { "ipackets",		"IPACKETS",	7,	AGGR_S_IPKTS,
673e7801d59Ssowmini     CMD_TYPE_ANY},
674e7801d59Ssowmini { "rbytes",		"RBYTES",	7,	AGGR_S_RBYTES,
675e7801d59Ssowmini     CMD_TYPE_ANY},
676e7801d59Ssowmini { "opackets",		"OPACKETS",	7,	AGGR_S_OPKTS,
677e7801d59Ssowmini     CMD_TYPE_ANY},
678e7801d59Ssowmini { "obytes",		"OBYTES",	7,	AGGR_S_OBYTES,
679e7801d59Ssowmini     CMD_TYPE_ANY},
680e7801d59Ssowmini { "ipktdist",		"IPKTDIST",	8,	AGGR_S_IPKTDIST,
681e7801d59Ssowmini     CMD_TYPE_ANY},
682e7801d59Ssowmini { "opktdist",		"OPKTDIST",	14,	AGGR_S_OPKTDIST,
683e7801d59Ssowmini     CMD_TYPE_ANY}}
684e7801d59Ssowmini ;
685e7801d59Ssowmini #define	AGGR_S_MAX_FIELDS \
686*da14cebeSEric Cheng 	(sizeof (aggr_s_fields) / sizeof (print_field_t))
687e7801d59Ssowmini 
688e7801d59Ssowmini /*
689*da14cebeSEric Cheng  * structures for 'dladm show-aggr -L'.
690e7801d59Ssowmini  */
691e7801d59Ssowmini typedef enum {
692e7801d59Ssowmini 	AGGR_L_LINK,
693e7801d59Ssowmini 	AGGR_L_PORT,
694e7801d59Ssowmini 	AGGR_L_AGGREGATABLE,
695e7801d59Ssowmini 	AGGR_L_SYNC,
696e7801d59Ssowmini 	AGGR_L_COLL,
697e7801d59Ssowmini 	AGGR_L_DIST,
698e7801d59Ssowmini 	AGGR_L_DEFAULTED,
699e7801d59Ssowmini 	AGGR_L_EXPIRED
700e7801d59Ssowmini } aggr_l_field_index_t;
701e7801d59Ssowmini 
702e7801d59Ssowmini static print_field_t aggr_l_fields[] = {
703e7801d59Ssowmini /* name,		header,		field width,	index,	cmdtype	*/
704e7801d59Ssowmini { "link",		"LINK",		11,	AGGR_L_LINK,
705e7801d59Ssowmini     CMD_TYPE_ANY},
706e7801d59Ssowmini { "port",		"PORT",		12,	AGGR_L_PORT,
707e7801d59Ssowmini     CMD_TYPE_ANY},
708e7801d59Ssowmini { "aggregatable",	"AGGREGATABLE",	12,	AGGR_L_AGGREGATABLE,
709e7801d59Ssowmini     CMD_TYPE_ANY},
710e7801d59Ssowmini { "sync",		"SYNC",		4,	AGGR_L_SYNC,
711e7801d59Ssowmini     CMD_TYPE_ANY},
712e7801d59Ssowmini { "coll",		"COLL",		4,	AGGR_L_COLL,
713e7801d59Ssowmini     CMD_TYPE_ANY},
714e7801d59Ssowmini { "dist",		"DIST",		4,	AGGR_L_DIST,
715e7801d59Ssowmini     CMD_TYPE_ANY},
716e7801d59Ssowmini { "defaulted",		"DEFAULTED",	9,	AGGR_L_DEFAULTED,
717e7801d59Ssowmini     CMD_TYPE_ANY},
718e7801d59Ssowmini { "expired",		"EXPIRED",	14,	AGGR_L_EXPIRED,
719e7801d59Ssowmini     CMD_TYPE_ANY}}
720e7801d59Ssowmini ;
721e7801d59Ssowmini #define	AGGR_L_MAX_FIELDS \
722e7801d59Ssowmini 	(sizeof (aggr_l_fields) / sizeof (print_field_t))
723e7801d59Ssowmini 
724e7801d59Ssowmini /*
725e7801d59Ssowmini  * structures for 'dladm show-phys'
726e7801d59Ssowmini  */
727e7801d59Ssowmini 
728e7801d59Ssowmini static print_field_t phys_fields[] = {
729e7801d59Ssowmini /* name,	header,		field width,	offset,	cmdtype		*/
730e7801d59Ssowmini { "link",	"LINK",			12,
731e7801d59Ssowmini     offsetof(link_fields_buf_t, link_name),		CMD_TYPE_ANY},
732e7801d59Ssowmini { "media",	"MEDIA",		20,
733e7801d59Ssowmini     offsetof(link_fields_buf_t, link_phys_media),	CMD_TYPE_ANY},
734e7801d59Ssowmini { "state",	"STATE",		10,
735e7801d59Ssowmini     offsetof(link_fields_buf_t, link_phys_state),	CMD_TYPE_ANY},
7366be03d0bSVasumathi Sundaram - Sun Microsystems { "speed",	"SPEED",		6,
737e7801d59Ssowmini     offsetof(link_fields_buf_t, link_phys_speed),	CMD_TYPE_ANY},
738e7801d59Ssowmini { "duplex",	"DUPLEX",		9,
739e7801d59Ssowmini     offsetof(link_fields_buf_t, link_phys_duplex),	CMD_TYPE_ANY},
740e7801d59Ssowmini { "device",	"DEVICE",		12,
741e7801d59Ssowmini     offsetof(link_fields_buf_t, link_phys_device),	CMD_TYPE_ANY},
742e7801d59Ssowmini { "flags",	"FLAGS",		6,
743e7801d59Ssowmini     offsetof(link_fields_buf_t, link_flags),		CMD_TYPE_ANY}}
744e7801d59Ssowmini ;
745e7801d59Ssowmini #define	PHYS_MAX_FIELDS	(sizeof (phys_fields) / sizeof (print_field_t))
746e7801d59Ssowmini 
747e7801d59Ssowmini /*
748*da14cebeSEric Cheng  * structures for 'dladm show-phys -m'
749*da14cebeSEric Cheng  */
750*da14cebeSEric Cheng 
751*da14cebeSEric Cheng typedef enum {
752*da14cebeSEric Cheng 	PHYS_M_LINK,
753*da14cebeSEric Cheng 	PHYS_M_SLOT,
754*da14cebeSEric Cheng 	PHYS_M_ADDRESS,
755*da14cebeSEric Cheng 	PHYS_M_INUSE,
756*da14cebeSEric Cheng 	PHYS_M_CLIENT
757*da14cebeSEric Cheng } phys_m_field_index_t;
758*da14cebeSEric Cheng 
759*da14cebeSEric Cheng static print_field_t phys_m_fields[] = {
760*da14cebeSEric Cheng /* name,	header,		field width,	offset,	cmdtype		*/
761*da14cebeSEric Cheng { "link",	"LINK",		12,	PHYS_M_LINK,	CMD_TYPE_ANY},
762*da14cebeSEric Cheng { "slot",	"SLOT",		8,	PHYS_M_SLOT,	CMD_TYPE_ANY},
763*da14cebeSEric Cheng { "address",	"ADDRESS",	18,	PHYS_M_ADDRESS,	CMD_TYPE_ANY},
764*da14cebeSEric Cheng { "inuse",	"INUSE",	4,	PHYS_M_INUSE,	CMD_TYPE_ANY},
765*da14cebeSEric Cheng { "client",	"CLIENT",	12,	PHYS_M_CLIENT,	CMD_TYPE_ANY}}
766*da14cebeSEric Cheng ;
767*da14cebeSEric Cheng #define	PHYS_M_MAX_FIELDS (sizeof (phys_m_fields) / sizeof (print_field_t))
768*da14cebeSEric Cheng 
769*da14cebeSEric Cheng /*
770*da14cebeSEric Cheng  * structures for 'dladm show-phys -H'
771*da14cebeSEric Cheng  */
772*da14cebeSEric Cheng 
773*da14cebeSEric Cheng typedef enum {
774*da14cebeSEric Cheng 	PHYS_H_LINK,
775*da14cebeSEric Cheng 	PHYS_H_GROUP,
776*da14cebeSEric Cheng 	PHYS_H_GRPTYPE,
777*da14cebeSEric Cheng 	PHYS_H_RINGS,
778*da14cebeSEric Cheng 	PHYS_H_CLIENTS
779*da14cebeSEric Cheng } phys_h_field_index_t;
780*da14cebeSEric Cheng 
781*da14cebeSEric Cheng static print_field_t phys_h_fields[] = {
782*da14cebeSEric Cheng /* name,	header,		field width,	offset,	cmdtype		*/
783*da14cebeSEric Cheng { "link",	"LINK",		12,	PHYS_H_LINK,	CMD_TYPE_ANY},
784*da14cebeSEric Cheng { "group",	"GROUP",	8,	PHYS_H_GROUP,	CMD_TYPE_ANY},
785*da14cebeSEric Cheng { "grouptype",	"TYPE",		6,	PHYS_H_GRPTYPE,	CMD_TYPE_ANY},
786*da14cebeSEric Cheng { "rings",	"NUM-RINGS",	16,	PHYS_H_RINGS,	CMD_TYPE_ANY},
787*da14cebeSEric Cheng { "clients",	"CLIENTS",	20,	PHYS_H_CLIENTS,	CMD_TYPE_ANY}}
788*da14cebeSEric Cheng ;
789*da14cebeSEric Cheng #define	PHYS_H_MAX_FIELDS (sizeof (phys_h_fields) / sizeof (print_field_t))
790*da14cebeSEric Cheng 
791*da14cebeSEric Cheng /*
792e7801d59Ssowmini  * structures for 'dladm show-vlan'
793e7801d59Ssowmini  */
794e7801d59Ssowmini static print_field_t vlan_fields[] = {
795e7801d59Ssowmini /* name,	header,		field width,	offset,	cmdtype		*/
796e7801d59Ssowmini { "link",	"LINK",			15,
797e7801d59Ssowmini     offsetof(link_fields_buf_t, link_name),		CMD_TYPE_ANY},
798e7801d59Ssowmini { "vid",	"VID",			8,
799e7801d59Ssowmini     offsetof(link_fields_buf_t, link_vlan_vid),	CMD_TYPE_ANY},
800e7801d59Ssowmini { "over",	"OVER",			12,
801e7801d59Ssowmini     offsetof(link_fields_buf_t, link_over),		CMD_TYPE_ANY},
802e7801d59Ssowmini { "flags",	"FLAGS",		6,
803e7801d59Ssowmini     offsetof(link_fields_buf_t, link_flags),		CMD_TYPE_ANY}}
804e7801d59Ssowmini ;
805e7801d59Ssowmini #define	VLAN_MAX_FIELDS	(sizeof (vlan_fields) / sizeof (print_field_t))
806e7801d59Ssowmini 
807*da14cebeSEric Cheng 
808e7801d59Ssowmini /*
809e7801d59Ssowmini  * structures for 'dladm show-wifi'
810e7801d59Ssowmini  */
811e7801d59Ssowmini static print_field_t wifi_fields[] = {
812e7801d59Ssowmini { "link",	"LINK",		10, 0,			WIFI_CMD_ALL},
813e7801d59Ssowmini { "essid",	"ESSID",	19, DLADM_WLAN_ATTR_ESSID,	WIFI_CMD_ALL},
814e7801d59Ssowmini { "bssid",	"BSSID/IBSSID", 17, DLADM_WLAN_ATTR_BSSID,	WIFI_CMD_ALL},
815e7801d59Ssowmini { "ibssid",	"BSSID/IBSSID", 17, DLADM_WLAN_ATTR_BSSID,	WIFI_CMD_ALL},
816e7801d59Ssowmini { "mode",	"MODE",		6,  DLADM_WLAN_ATTR_MODE,	WIFI_CMD_ALL},
817e7801d59Ssowmini { "speed",	"SPEED",	6,  DLADM_WLAN_ATTR_SPEED,	WIFI_CMD_ALL},
818e7801d59Ssowmini { "auth",	"AUTH",		8,  DLADM_WLAN_ATTR_AUTH,	WIFI_CMD_SHOW},
819e7801d59Ssowmini { "bsstype",	"BSSTYPE",	8,  DLADM_WLAN_ATTR_BSSTYPE, WIFI_CMD_ALL},
820e7801d59Ssowmini { "sec",	"SEC",		6,  DLADM_WLAN_ATTR_SECMODE, WIFI_CMD_ALL},
821e7801d59Ssowmini { "status",	"STATUS",	17, DLADM_WLAN_LINKATTR_STATUS, WIFI_CMD_SHOW},
822e7801d59Ssowmini { "strength",	"STRENGTH",	10, DLADM_WLAN_ATTR_STRENGTH, WIFI_CMD_ALL}}
823e7801d59Ssowmini ;
824e7801d59Ssowmini 
825e7801d59Ssowmini static char *all_scan_wifi_fields =
826e7801d59Ssowmini 	"link,essid,bssid,sec,strength,mode,speed,bsstype";
827e7801d59Ssowmini static char *all_show_wifi_fields =
828e7801d59Ssowmini 	"link,status,essid,sec,strength,mode,speed,auth,bssid,bsstype";
829e7801d59Ssowmini static char *def_scan_wifi_fields =
830e7801d59Ssowmini 	"link,essid,bssid,sec,strength,mode,speed";
831e7801d59Ssowmini static char *def_show_wifi_fields =
832e7801d59Ssowmini 	"link,status,essid,sec,strength,mode,speed";
833e7801d59Ssowmini 
834e7801d59Ssowmini #define	WIFI_MAX_FIELDS		(sizeof (wifi_fields) / sizeof (print_field_t))
835e7801d59Ssowmini 
836e7801d59Ssowmini /*
837e7801d59Ssowmini  * structures for 'dladm show-linkprop'
838e7801d59Ssowmini  */
839e7801d59Ssowmini typedef enum {
840e7801d59Ssowmini 	LINKPROP_LINK,
841e7801d59Ssowmini 	LINKPROP_PROPERTY,
842afdda45fSVasumathi Sundaram - Sun Microsystems 	LINKPROP_PERM,
843e7801d59Ssowmini 	LINKPROP_VALUE,
844e7801d59Ssowmini 	LINKPROP_DEFAULT,
845e7801d59Ssowmini 	LINKPROP_POSSIBLE
846e7801d59Ssowmini } linkprop_field_index_t;
847e7801d59Ssowmini 
848e7801d59Ssowmini static print_field_t linkprop_fields[] = {
849e7801d59Ssowmini /* name,	header,		field width,  index,		cmdtype */
850e7801d59Ssowmini { "link",	"LINK",		12,	LINKPROP_LINK,		CMD_TYPE_ANY},
851e7801d59Ssowmini { "property",	"PROPERTY",	15,	LINKPROP_PROPERTY,	CMD_TYPE_ANY},
852afdda45fSVasumathi Sundaram - Sun Microsystems { "perm",	"PERM",		4,	LINKPROP_PERM,		CMD_TYPE_ANY},
853e7801d59Ssowmini { "value",	"VALUE",	14,	LINKPROP_VALUE,		CMD_TYPE_ANY},
854e7801d59Ssowmini { "default",	"DEFAULT",	14,	LINKPROP_DEFAULT, 	CMD_TYPE_ANY},
855e7801d59Ssowmini { "possible",	"POSSIBLE",	20,	LINKPROP_POSSIBLE,	CMD_TYPE_ANY}}
856e7801d59Ssowmini ;
857e7801d59Ssowmini #define	LINKPROP_MAX_FIELDS					\
858e7801d59Ssowmini 	(sizeof (linkprop_fields) / sizeof (print_field_t))
859e7801d59Ssowmini 
860e7801d59Ssowmini #define	MAX_PROP_LINE		512
861e7801d59Ssowmini 
862e7801d59Ssowmini typedef struct show_linkprop_state {
863e7801d59Ssowmini 	char			ls_link[MAXLINKNAMELEN];
864e7801d59Ssowmini 	char			*ls_line;
865e7801d59Ssowmini 	char			**ls_propvals;
866*da14cebeSEric Cheng 	dladm_arg_list_t	*ls_proplist;
867e7801d59Ssowmini 	boolean_t		ls_parseable;
868e7801d59Ssowmini 	boolean_t		ls_persist;
869e7801d59Ssowmini 	boolean_t		ls_header;
870e7801d59Ssowmini 	dladm_status_t		ls_status;
871e7801d59Ssowmini 	dladm_status_t		ls_retstatus;
872e7801d59Ssowmini 	print_state_t		ls_print;
873e7801d59Ssowmini } show_linkprop_state_t;
874e7801d59Ssowmini 
875*da14cebeSEric Cheng typedef struct set_linkprop_state {
876*da14cebeSEric Cheng 	const char		*ls_name;
877*da14cebeSEric Cheng 	boolean_t		ls_reset;
878*da14cebeSEric Cheng 	boolean_t		ls_temp;
879*da14cebeSEric Cheng 	dladm_status_t		ls_status;
880*da14cebeSEric Cheng } set_linkprop_state_t;
881*da14cebeSEric Cheng 
882e7801d59Ssowmini typedef struct linkprop_args_s {
883e7801d59Ssowmini 	show_linkprop_state_t	*ls_state;
884e7801d59Ssowmini 	char			*ls_propname;
885e7801d59Ssowmini 	datalink_id_t		ls_linkid;
886e7801d59Ssowmini } linkprop_args_t;
887e7801d59Ssowmini 
888e7801d59Ssowmini /*
889e7801d59Ssowmini  * structures for 'dladm show-secobj'
890e7801d59Ssowmini  */
891e7801d59Ssowmini typedef struct secobj_fields_buf_s {
892e7801d59Ssowmini 	char			ss_obj_name[DLADM_SECOBJ_VAL_MAX];
893e7801d59Ssowmini 	char			ss_class[20];
894e7801d59Ssowmini 	char			ss_val[30];
895e7801d59Ssowmini } secobj_fields_buf_t;
896e7801d59Ssowmini static print_field_t secobj_fields[] = {
897e7801d59Ssowmini /* name,	header,		field width,	offset,	cmdtype		*/
898e7801d59Ssowmini { "object",	"OBJECT",		20,
899e7801d59Ssowmini     offsetof(secobj_fields_buf_t, ss_obj_name),	CMD_TYPE_ANY},
900e7801d59Ssowmini { "class",	"CLASS",		20,
901e7801d59Ssowmini     offsetof(secobj_fields_buf_t, ss_class),	CMD_TYPE_ANY},
902e7801d59Ssowmini { "value",	"VALUE",		30,
903e7801d59Ssowmini     offsetof(secobj_fields_buf_t, ss_val),	CMD_TYPE_ANY}}
904e7801d59Ssowmini ;
905e7801d59Ssowmini #define	DEV_SOBJ_FIELDS	(sizeof (secobj_fields) / sizeof (print_field_t))
9060ba2cbe9Sxc151355 
907*da14cebeSEric Cheng /*
908*da14cebeSEric Cheng  * structures for 'dladm show-vnic'
909*da14cebeSEric Cheng  */
910*da14cebeSEric Cheng typedef struct vnic_fields_buf_s
911*da14cebeSEric Cheng {
912*da14cebeSEric Cheng 	char vnic_link[DLPI_LINKNAME_MAX];
913*da14cebeSEric Cheng 	char vnic_over[DLPI_LINKNAME_MAX];
914*da14cebeSEric Cheng 	char vnic_speed[6];
915*da14cebeSEric Cheng 	char vnic_macaddr[19];
916*da14cebeSEric Cheng 	char vnic_macaddrtype[19];
917*da14cebeSEric Cheng 	char vnic_vid[6];
918*da14cebeSEric Cheng } vnic_fields_buf_t;
919*da14cebeSEric Cheng 
920*da14cebeSEric Cheng static print_field_t vnic_fields[] = {
921*da14cebeSEric Cheng /* name,		header,		field width,	offset,	cmdtype	*/
922*da14cebeSEric Cheng { "link",		"LINK",		12,
923*da14cebeSEric Cheng     offsetof(vnic_fields_buf_t, vnic_link),		CMD_TYPE_ANY},
924*da14cebeSEric Cheng { "over",		"OVER",		12,
925*da14cebeSEric Cheng     offsetof(vnic_fields_buf_t, vnic_over),		CMD_TYPE_ANY},
926*da14cebeSEric Cheng { "speed",		"SPEED",	6,
927*da14cebeSEric Cheng     offsetof(vnic_fields_buf_t, vnic_speed),		CMD_TYPE_ANY},
928*da14cebeSEric Cheng { "macaddr",		"MACADDRESS",	20,
929*da14cebeSEric Cheng     offsetof(vnic_fields_buf_t, vnic_macaddr),		CMD_TYPE_ANY},
930*da14cebeSEric Cheng { "macaddrtype",	"MACADDRTYPE",	19,
931*da14cebeSEric Cheng     offsetof(vnic_fields_buf_t, vnic_macaddrtype),	CMD_TYPE_ANY},
932*da14cebeSEric Cheng { "vid",		"VID",		6,
933*da14cebeSEric Cheng     offsetof(vnic_fields_buf_t, vnic_vid),		CMD_TYPE_ANY}}
934*da14cebeSEric Cheng ;
935*da14cebeSEric Cheng #define	VNIC_MAX_FIELDS	(sizeof (vnic_fields) / sizeof (print_field_t))
936*da14cebeSEric Cheng 
937*da14cebeSEric Cheng /*
938*da14cebeSEric Cheng  * structures for 'dladm show-usage'
939*da14cebeSEric Cheng  */
940*da14cebeSEric Cheng 
941*da14cebeSEric Cheng typedef struct  usage_fields_buf_s {
942*da14cebeSEric Cheng 	char	usage_link[12];
943*da14cebeSEric Cheng 	char	usage_duration[10];
944*da14cebeSEric Cheng 	char	usage_ipackets[9];
945*da14cebeSEric Cheng 	char	usage_rbytes[10];
946*da14cebeSEric Cheng 	char	usage_opackets[9];
947*da14cebeSEric Cheng 	char	usage_obytes[10];
948*da14cebeSEric Cheng 	char	usage_bandwidth[14];
949*da14cebeSEric Cheng } usage_fields_buf_t;
950*da14cebeSEric Cheng 
951*da14cebeSEric Cheng static print_field_t usage_fields[] = {
952*da14cebeSEric Cheng /* name,	header,		field width,	offset,	cmdtype		*/
953*da14cebeSEric Cheng { "link",	"LINK",			12,
954*da14cebeSEric Cheng     offsetof(usage_fields_buf_t, usage_link),		CMD_TYPE_ANY},
955*da14cebeSEric Cheng { "duration",	"DURATION",		10,
956*da14cebeSEric Cheng     offsetof(usage_fields_buf_t, usage_duration),	CMD_TYPE_ANY},
957*da14cebeSEric Cheng { "ipackets",	"IPACKETS",		9,
958*da14cebeSEric Cheng     offsetof(usage_fields_buf_t, usage_ipackets),	CMD_TYPE_ANY},
959*da14cebeSEric Cheng { "rbytes",	"RBYTES",		10,
960*da14cebeSEric Cheng     offsetof(usage_fields_buf_t, usage_rbytes),		CMD_TYPE_ANY},
961*da14cebeSEric Cheng { "opackets",	"OPACKETS",		9,
962*da14cebeSEric Cheng     offsetof(usage_fields_buf_t, usage_opackets),	CMD_TYPE_ANY},
963*da14cebeSEric Cheng { "obytes",	"OBYTES",		10,
964*da14cebeSEric Cheng     offsetof(usage_fields_buf_t, usage_obytes),		CMD_TYPE_ANY},
965*da14cebeSEric Cheng { "bandwidth",	"BANDWIDTH",		14,
966*da14cebeSEric Cheng     offsetof(usage_fields_buf_t, usage_bandwidth),	CMD_TYPE_ANY}}
967*da14cebeSEric Cheng ;
968*da14cebeSEric Cheng 
969*da14cebeSEric Cheng #define	USAGE_MAX_FIELDS	(sizeof (usage_fields) / sizeof (print_field_t))
970*da14cebeSEric Cheng 
971*da14cebeSEric Cheng /*
972*da14cebeSEric Cheng  * structures for 'dladm show-usage link'
973*da14cebeSEric Cheng  */
974*da14cebeSEric Cheng 
975*da14cebeSEric Cheng typedef struct  usage_l_fields_buf_s {
976*da14cebeSEric Cheng 	char	usage_l_link[12];
977*da14cebeSEric Cheng 	char	usage_l_stime[13];
978*da14cebeSEric Cheng 	char	usage_l_etime[13];
979*da14cebeSEric Cheng 	char	usage_l_rbytes[8];
980*da14cebeSEric Cheng 	char	usage_l_obytes[8];
981*da14cebeSEric Cheng 	char	usage_l_bandwidth[14];
982*da14cebeSEric Cheng } usage_l_fields_buf_t;
983*da14cebeSEric Cheng 
984*da14cebeSEric Cheng static print_field_t usage_l_fields[] = {
985*da14cebeSEric Cheng /* name,	header,		field width,	offset,	cmdtype		*/
986*da14cebeSEric Cheng { "link",	"LINK",		12,
987*da14cebeSEric Cheng     offsetof(usage_l_fields_buf_t, usage_l_link),	CMD_TYPE_ANY},
988*da14cebeSEric Cheng { "start",	"START",	13,
989*da14cebeSEric Cheng     offsetof(usage_l_fields_buf_t, usage_l_stime),	CMD_TYPE_ANY},
990*da14cebeSEric Cheng { "end",	"END",		13,
991*da14cebeSEric Cheng     offsetof(usage_l_fields_buf_t, usage_l_etime),	CMD_TYPE_ANY},
992*da14cebeSEric Cheng { "rbytes",	"RBYTES",	8,
993*da14cebeSEric Cheng     offsetof(usage_l_fields_buf_t, usage_l_rbytes),	CMD_TYPE_ANY},
994*da14cebeSEric Cheng { "obytes",	"OBYTES",	8,
995*da14cebeSEric Cheng     offsetof(usage_l_fields_buf_t, usage_l_obytes),	CMD_TYPE_ANY},
996*da14cebeSEric Cheng { "bandwidth",	"BANDWIDTH",	14,
997*da14cebeSEric Cheng     offsetof(usage_l_fields_buf_t, usage_l_bandwidth),	CMD_TYPE_ANY}}
998*da14cebeSEric Cheng ;
999*da14cebeSEric Cheng 
1000*da14cebeSEric Cheng #define	USAGE_L_MAX_FIELDS \
1001*da14cebeSEric Cheng 	(sizeof (usage_l_fields) /sizeof (print_field_t))
1002*da14cebeSEric Cheng 
10037c478bd9Sstevel@tonic-gate static char *progname;
10040ba2cbe9Sxc151355 static sig_atomic_t signalled;
10057c478bd9Sstevel@tonic-gate 
1006*da14cebeSEric Cheng #define	DLADM_ETHERSTUB_NAME	"etherstub"
1007*da14cebeSEric Cheng #define	DLADM_IS_ETHERSTUB(id)	(id == DATALINK_INVALID_LINKID)
1008*da14cebeSEric Cheng 
10097c478bd9Sstevel@tonic-gate static void
10107c478bd9Sstevel@tonic-gate usage(void)
10117c478bd9Sstevel@tonic-gate {
10128d5c46e6Sam223141 	int	i;
10138d5c46e6Sam223141 	cmd_t	*cmdp;
10148d5c46e6Sam223141 	(void) fprintf(stderr, gettext("usage:  dladm <subcommand> <args> ..."
10158d5c46e6Sam223141 	    "\n"));
10168d5c46e6Sam223141 	for (i = 0; i < sizeof (cmds) / sizeof (cmds[0]); i++) {
10178d5c46e6Sam223141 		cmdp = &cmds[i];
10188d5c46e6Sam223141 		if (cmdp->c_usage != NULL)
10198d5c46e6Sam223141 			(void) fprintf(stderr, "%s\n", gettext(cmdp->c_usage));
10208d5c46e6Sam223141 	}
10217c478bd9Sstevel@tonic-gate 	exit(1);
10227c478bd9Sstevel@tonic-gate }
10237c478bd9Sstevel@tonic-gate 
10247c478bd9Sstevel@tonic-gate int
10257c478bd9Sstevel@tonic-gate main(int argc, char *argv[])
10267c478bd9Sstevel@tonic-gate {
10277c478bd9Sstevel@tonic-gate 	int	i;
10287c478bd9Sstevel@tonic-gate 	cmd_t	*cmdp;
10297c478bd9Sstevel@tonic-gate 
10307c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
10317c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)
10327c478bd9Sstevel@tonic-gate #define	TEXT_DOMAIN "SYS_TEST"
10337c478bd9Sstevel@tonic-gate #endif
10347c478bd9Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
10357c478bd9Sstevel@tonic-gate 
10367c478bd9Sstevel@tonic-gate 	progname = argv[0];
10377c478bd9Sstevel@tonic-gate 
10387c478bd9Sstevel@tonic-gate 	if (argc < 2)
10397c478bd9Sstevel@tonic-gate 		usage();
10407c478bd9Sstevel@tonic-gate 
10417c478bd9Sstevel@tonic-gate 	for (i = 0; i < sizeof (cmds) / sizeof (cmds[0]); i++) {
10427c478bd9Sstevel@tonic-gate 		cmdp = &cmds[i];
10437c478bd9Sstevel@tonic-gate 		if (strcmp(argv[1], cmdp->c_name) == 0) {
10448d5c46e6Sam223141 			cmdp->c_fn(argc - 1, &argv[1], cmdp->c_usage);
10457c478bd9Sstevel@tonic-gate 			exit(0);
10467c478bd9Sstevel@tonic-gate 		}
10477c478bd9Sstevel@tonic-gate 	}
10487c478bd9Sstevel@tonic-gate 
10497c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("%s: unknown subcommand '%s'\n"),
10507c478bd9Sstevel@tonic-gate 	    progname, argv[1]);
10517c478bd9Sstevel@tonic-gate 	usage();
10527c478bd9Sstevel@tonic-gate 
10537c478bd9Sstevel@tonic-gate 	return (0);
10547c478bd9Sstevel@tonic-gate }
10557c478bd9Sstevel@tonic-gate 
1056*da14cebeSEric Cheng /*ARGSUSED*/
1057*da14cebeSEric Cheng static int
1058*da14cebeSEric Cheng show_usage_date(dladm_usage_t *usage, void *arg)
1059*da14cebeSEric Cheng {
1060*da14cebeSEric Cheng 
1061*da14cebeSEric Cheng 	time_t	stime;
1062*da14cebeSEric Cheng 	char	timebuf[20];
1063*da14cebeSEric Cheng 
1064*da14cebeSEric Cheng 	stime = usage->du_stime;
1065*da14cebeSEric Cheng 	(void) strftime(timebuf, sizeof (timebuf), "%m/%d/%Y",
1066*da14cebeSEric Cheng 	    localtime(&stime));
1067*da14cebeSEric Cheng 	(void) printf("%s\n", timebuf);
1068*da14cebeSEric Cheng 
1069*da14cebeSEric Cheng 	return (DLADM_STATUS_OK);
1070*da14cebeSEric Cheng }
1071*da14cebeSEric Cheng 
1072*da14cebeSEric Cheng static int
1073*da14cebeSEric Cheng show_usage_time(dladm_usage_t *usage, void *arg)
1074*da14cebeSEric Cheng {
1075*da14cebeSEric Cheng 	show_usage_state_t	*state = (show_usage_state_t *)arg;
1076*da14cebeSEric Cheng 	char			buf[DLADM_STRSIZE];
1077*da14cebeSEric Cheng 	usage_l_fields_buf_t 	ubuf;
1078*da14cebeSEric Cheng 	time_t			time;
1079*da14cebeSEric Cheng 	double			bw;
1080*da14cebeSEric Cheng 
1081*da14cebeSEric Cheng 	if (state->us_plot) {
1082*da14cebeSEric Cheng 		if (!state->us_printheader) {
1083*da14cebeSEric Cheng 			if (state->us_first) {
1084*da14cebeSEric Cheng 				(void) printf("# Time");
1085*da14cebeSEric Cheng 				state->us_first = B_FALSE;
1086*da14cebeSEric Cheng 			}
1087*da14cebeSEric Cheng 			(void) printf(" %s", usage->du_name);
1088*da14cebeSEric Cheng 			if (usage->du_last) {
1089*da14cebeSEric Cheng 				(void) printf("\n");
1090*da14cebeSEric Cheng 				state->us_first = B_TRUE;
1091*da14cebeSEric Cheng 				state->us_printheader = B_TRUE;
1092*da14cebeSEric Cheng 			}
1093*da14cebeSEric Cheng 		} else {
1094*da14cebeSEric Cheng 			if (state->us_first) {
1095*da14cebeSEric Cheng 				time = usage->du_etime;
1096*da14cebeSEric Cheng 				(void) strftime(buf, sizeof (buf), "%T",
1097*da14cebeSEric Cheng 				    localtime(&time));
1098*da14cebeSEric Cheng 				state->us_first = B_FALSE;
1099*da14cebeSEric Cheng 				(void) printf("%s", buf);
1100*da14cebeSEric Cheng 			}
1101*da14cebeSEric Cheng 			bw = (double)usage->du_bandwidth/1000;
1102*da14cebeSEric Cheng 			(void) printf(" %.2f", bw);
1103*da14cebeSEric Cheng 			if (usage->du_last) {
1104*da14cebeSEric Cheng 				(void) printf("\n");
1105*da14cebeSEric Cheng 				state->us_first = B_TRUE;
1106*da14cebeSEric Cheng 			}
1107*da14cebeSEric Cheng 		}
1108*da14cebeSEric Cheng 		return (DLADM_STATUS_OK);
1109*da14cebeSEric Cheng 	}
1110*da14cebeSEric Cheng 
1111*da14cebeSEric Cheng 	bzero(&ubuf, sizeof (ubuf));
1112*da14cebeSEric Cheng 
1113*da14cebeSEric Cheng 	(void) snprintf(ubuf.usage_l_link, sizeof (ubuf.usage_l_link), "%s",
1114*da14cebeSEric Cheng 	    usage->du_name);
1115*da14cebeSEric Cheng 	time = usage->du_stime;
1116*da14cebeSEric Cheng 	(void) strftime(buf, sizeof (buf), "%T", localtime(&time));
1117*da14cebeSEric Cheng 	(void) snprintf(ubuf.usage_l_stime, sizeof (ubuf.usage_l_stime), "%s",
1118*da14cebeSEric Cheng 	    buf);
1119*da14cebeSEric Cheng 	time = usage->du_etime;
1120*da14cebeSEric Cheng 	(void) strftime(buf, sizeof (buf), "%T", localtime(&time));
1121*da14cebeSEric Cheng 	(void) snprintf(ubuf.usage_l_etime, sizeof (ubuf.usage_l_etime), "%s",
1122*da14cebeSEric Cheng 	    buf);
1123*da14cebeSEric Cheng 	(void) snprintf(ubuf.usage_l_rbytes, sizeof (ubuf.usage_l_rbytes),
1124*da14cebeSEric Cheng 	    "%llu", usage->du_rbytes);
1125*da14cebeSEric Cheng 	(void) snprintf(ubuf.usage_l_obytes, sizeof (ubuf.usage_l_obytes),
1126*da14cebeSEric Cheng 	    "%llu", usage->du_obytes);
1127*da14cebeSEric Cheng 	(void) snprintf(ubuf.usage_l_bandwidth, sizeof (ubuf.usage_l_bandwidth),
1128*da14cebeSEric Cheng 	    "%s Mbps", dladm_bw2str(usage->du_bandwidth, buf));
1129*da14cebeSEric Cheng 
1130*da14cebeSEric Cheng 	if (!state->us_parseable && !state->us_printheader) {
1131*da14cebeSEric Cheng 		print_header(&state->us_print);
1132*da14cebeSEric Cheng 		state->us_printheader = B_TRUE;
1133*da14cebeSEric Cheng 	}
1134*da14cebeSEric Cheng 
1135*da14cebeSEric Cheng 	dladm_print_output(&state->us_print, state->us_parseable,
1136*da14cebeSEric Cheng 	    dladm_print_field, (void *)&ubuf);
1137*da14cebeSEric Cheng 
1138*da14cebeSEric Cheng 	return (DLADM_STATUS_OK);
1139*da14cebeSEric Cheng }
1140*da14cebeSEric Cheng 
1141*da14cebeSEric Cheng static int
1142*da14cebeSEric Cheng show_usage_res(dladm_usage_t *usage, void *arg)
1143*da14cebeSEric Cheng {
1144*da14cebeSEric Cheng 	show_usage_state_t	*state = (show_usage_state_t *)arg;
1145*da14cebeSEric Cheng 	char			buf[DLADM_STRSIZE];
1146*da14cebeSEric Cheng 	usage_fields_buf_t	ubuf;
1147*da14cebeSEric Cheng 
1148*da14cebeSEric Cheng 	bzero(&ubuf, sizeof (ubuf));
1149*da14cebeSEric Cheng 
1150*da14cebeSEric Cheng 	(void) snprintf(ubuf.usage_link, sizeof (ubuf.usage_link), "%s",
1151*da14cebeSEric Cheng 	    usage->du_name);
1152*da14cebeSEric Cheng 	(void) snprintf(ubuf.usage_duration, sizeof (ubuf.usage_duration),
1153*da14cebeSEric Cheng 	    "%llu", usage->du_duration);
1154*da14cebeSEric Cheng 	(void) snprintf(ubuf.usage_ipackets, sizeof (ubuf.usage_ipackets),
1155*da14cebeSEric Cheng 	    "%llu", usage->du_ipackets);
1156*da14cebeSEric Cheng 	(void) snprintf(ubuf.usage_rbytes, sizeof (ubuf.usage_rbytes),
1157*da14cebeSEric Cheng 	    "%llu", usage->du_rbytes);
1158*da14cebeSEric Cheng 	(void) snprintf(ubuf.usage_opackets, sizeof (ubuf.usage_opackets),
1159*da14cebeSEric Cheng 	    "%llu", usage->du_opackets);
1160*da14cebeSEric Cheng 	(void) snprintf(ubuf.usage_obytes, sizeof (ubuf.usage_obytes),
1161*da14cebeSEric Cheng 	    "%llu", usage->du_obytes);
1162*da14cebeSEric Cheng 	(void) snprintf(ubuf.usage_bandwidth, sizeof (ubuf.usage_bandwidth),
1163*da14cebeSEric Cheng 	    "%s Mbps", dladm_bw2str(usage->du_bandwidth, buf));
1164*da14cebeSEric Cheng 
1165*da14cebeSEric Cheng 	if (!state->us_parseable && !state->us_printheader) {
1166*da14cebeSEric Cheng 		print_header(&state->us_print);
1167*da14cebeSEric Cheng 		state->us_printheader = B_TRUE;
1168*da14cebeSEric Cheng 	}
1169*da14cebeSEric Cheng 
1170*da14cebeSEric Cheng 	dladm_print_output(&state->us_print, state->us_parseable,
1171*da14cebeSEric Cheng 	    dladm_print_field, (void *)&ubuf);
1172*da14cebeSEric Cheng 
1173*da14cebeSEric Cheng 	return (DLADM_STATUS_OK);
1174*da14cebeSEric Cheng }
1175*da14cebeSEric Cheng 
1176*da14cebeSEric Cheng static boolean_t
1177*da14cebeSEric Cheng valid_formatspec(char *formatspec_str)
1178*da14cebeSEric Cheng {
1179*da14cebeSEric Cheng 	if (strcmp(formatspec_str, "gnuplot") == 0)
1180*da14cebeSEric Cheng 		return (B_TRUE);
1181*da14cebeSEric Cheng 	return (B_FALSE);
1182*da14cebeSEric Cheng 
1183*da14cebeSEric Cheng }
1184*da14cebeSEric Cheng 
1185*da14cebeSEric Cheng /*ARGSUSED*/
1186*da14cebeSEric Cheng static void
1187*da14cebeSEric Cheng do_show_usage(int argc, char *argv[], const char *use)
1188*da14cebeSEric Cheng {
1189*da14cebeSEric Cheng 	char			*file = NULL;
1190*da14cebeSEric Cheng 	int			opt;
1191*da14cebeSEric Cheng 	dladm_status_t		status;
1192*da14cebeSEric Cheng 	boolean_t		d_arg = B_FALSE;
1193*da14cebeSEric Cheng 	boolean_t		p_arg = B_FALSE;
1194*da14cebeSEric Cheng 	char			*stime = NULL;
1195*da14cebeSEric Cheng 	char			*etime = NULL;
1196*da14cebeSEric Cheng 	char			*resource = NULL;
1197*da14cebeSEric Cheng 	show_usage_state_t	state;
1198*da14cebeSEric Cheng 	boolean_t		o_arg = B_FALSE;
1199*da14cebeSEric Cheng 	boolean_t		F_arg = B_FALSE;
1200*da14cebeSEric Cheng 	char			*fields_str = NULL;
1201*da14cebeSEric Cheng 	char			*formatspec_str = NULL;
1202*da14cebeSEric Cheng 	print_field_t		**fields;
1203*da14cebeSEric Cheng 	uint_t			nfields;
1204*da14cebeSEric Cheng 	char			*all_fields =
1205*da14cebeSEric Cheng 	    "link,duration,ipackets,rbytes,opackets,obytes,bandwidth";
1206*da14cebeSEric Cheng 	char			*all_l_fields =
1207*da14cebeSEric Cheng 	    "link,start,end,rbytes,obytes,bandwidth";
1208*da14cebeSEric Cheng 
1209*da14cebeSEric Cheng 	bzero(&state, sizeof (show_usage_state_t));
1210*da14cebeSEric Cheng 	state.us_parseable = B_FALSE;
1211*da14cebeSEric Cheng 	state.us_printheader = B_FALSE;
1212*da14cebeSEric Cheng 	state.us_plot = B_FALSE;
1213*da14cebeSEric Cheng 	state.us_first = B_TRUE;
1214*da14cebeSEric Cheng 
1215*da14cebeSEric Cheng 	while ((opt = getopt(argc, argv, "dps:e:o:f:F:")) != -1) {
1216*da14cebeSEric Cheng 		switch (opt) {
1217*da14cebeSEric Cheng 		case 'd':
1218*da14cebeSEric Cheng 			d_arg = B_TRUE;
1219*da14cebeSEric Cheng 			break;
1220*da14cebeSEric Cheng 		case 'p':
1221*da14cebeSEric Cheng 			state.us_plot = p_arg = B_TRUE;
1222*da14cebeSEric Cheng 			break;
1223*da14cebeSEric Cheng 		case 'f':
1224*da14cebeSEric Cheng 			file = optarg;
1225*da14cebeSEric Cheng 			break;
1226*da14cebeSEric Cheng 		case 's':
1227*da14cebeSEric Cheng 			stime = optarg;
1228*da14cebeSEric Cheng 			break;
1229*da14cebeSEric Cheng 		case 'e':
1230*da14cebeSEric Cheng 			etime = optarg;
1231*da14cebeSEric Cheng 			break;
1232*da14cebeSEric Cheng 		case 'o':
1233*da14cebeSEric Cheng 			o_arg = B_TRUE;
1234*da14cebeSEric Cheng 			fields_str = optarg;
1235*da14cebeSEric Cheng 			break;
1236*da14cebeSEric Cheng 		case 'F':
1237*da14cebeSEric Cheng 			F_arg = B_TRUE;
1238*da14cebeSEric Cheng 			formatspec_str = optarg;
1239*da14cebeSEric Cheng 			break;
1240*da14cebeSEric Cheng 		default:
1241*da14cebeSEric Cheng 			die_opterr(optopt, opt, use);
1242*da14cebeSEric Cheng 			break;
1243*da14cebeSEric Cheng 		}
1244*da14cebeSEric Cheng 	}
1245*da14cebeSEric Cheng 
1246*da14cebeSEric Cheng 	if (file == NULL)
1247*da14cebeSEric Cheng 		die("show-usage requires a file");
1248*da14cebeSEric Cheng 
1249*da14cebeSEric Cheng 	if (optind == (argc-1)) {
1250*da14cebeSEric Cheng 		resource = argv[optind];
1251*da14cebeSEric Cheng 	}
1252*da14cebeSEric Cheng 
1253*da14cebeSEric Cheng 	if (resource == NULL && stime == NULL && etime == NULL) {
1254*da14cebeSEric Cheng 		if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0))
1255*da14cebeSEric Cheng 			fields_str = all_fields;
1256*da14cebeSEric Cheng 		fields = parse_output_fields(fields_str, usage_fields,
1257*da14cebeSEric Cheng 		    USAGE_MAX_FIELDS, CMD_TYPE_ANY, &nfields);
1258*da14cebeSEric Cheng 	} else {
1259*da14cebeSEric Cheng 		if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0))
1260*da14cebeSEric Cheng 			fields_str = all_l_fields;
1261*da14cebeSEric Cheng 		fields = parse_output_fields(fields_str, usage_l_fields,
1262*da14cebeSEric Cheng 		    USAGE_L_MAX_FIELDS, CMD_TYPE_ANY, &nfields);
1263*da14cebeSEric Cheng 	}
1264*da14cebeSEric Cheng 
1265*da14cebeSEric Cheng 	if (fields == NULL) {
1266*da14cebeSEric Cheng 		die("invalid fields(s) specified");
1267*da14cebeSEric Cheng 		return;
1268*da14cebeSEric Cheng 	}
1269*da14cebeSEric Cheng 	state.us_print.ps_fields = fields;
1270*da14cebeSEric Cheng 	state.us_print.ps_nfields = nfields;
1271*da14cebeSEric Cheng 
1272*da14cebeSEric Cheng 	if (p_arg && d_arg)
1273*da14cebeSEric Cheng 		die("plot and date options are incompatible");
1274*da14cebeSEric Cheng 
1275*da14cebeSEric Cheng 	if (p_arg && !F_arg)
1276*da14cebeSEric Cheng 		die("specify format speicifier: -F <format>");
1277*da14cebeSEric Cheng 
1278*da14cebeSEric Cheng 	if (F_arg && valid_formatspec(formatspec_str) == B_FALSE)
1279*da14cebeSEric Cheng 		die("Format specifier %s not supported", formatspec_str);
1280*da14cebeSEric Cheng 
1281*da14cebeSEric Cheng 	if (d_arg) {
1282*da14cebeSEric Cheng 		/* Print log dates */
1283*da14cebeSEric Cheng 		status = dladm_usage_dates(show_usage_date,
1284*da14cebeSEric Cheng 		    DLADM_LOGTYPE_LINK, file, resource, &state);
1285*da14cebeSEric Cheng 	} else if (resource == NULL && stime == NULL && etime == NULL &&
1286*da14cebeSEric Cheng 	    !p_arg) {
1287*da14cebeSEric Cheng 		/* Print summary */
1288*da14cebeSEric Cheng 		status = dladm_usage_summary(show_usage_res,
1289*da14cebeSEric Cheng 		    DLADM_LOGTYPE_LINK, file, &state);
1290*da14cebeSEric Cheng 	} else if (resource != NULL) {
1291*da14cebeSEric Cheng 		/* Print log entries for named resource */
1292*da14cebeSEric Cheng 		status = dladm_walk_usage_res(show_usage_time,
1293*da14cebeSEric Cheng 		    DLADM_LOGTYPE_LINK, file, resource, stime, etime, &state);
1294*da14cebeSEric Cheng 	} else {
1295*da14cebeSEric Cheng 		/* Print time and information for each link */
1296*da14cebeSEric Cheng 		status = dladm_walk_usage_time(show_usage_time,
1297*da14cebeSEric Cheng 		    DLADM_LOGTYPE_LINK, file, stime, etime, &state);
1298*da14cebeSEric Cheng 	}
1299*da14cebeSEric Cheng 
1300*da14cebeSEric Cheng 	if (status != DLADM_STATUS_OK)
1301*da14cebeSEric Cheng 		die_dlerr(status, "show-usage");
1302*da14cebeSEric Cheng }
1303*da14cebeSEric Cheng 
13047c478bd9Sstevel@tonic-gate static void
13058d5c46e6Sam223141 do_create_aggr(int argc, char *argv[], const char *use)
13067c478bd9Sstevel@tonic-gate {
13077c478bd9Sstevel@tonic-gate 	char			option;
1308d62bc4baSyz147064 	int			key = 0;
13097c478bd9Sstevel@tonic-gate 	uint32_t		policy = AGGR_POLICY_L4;
13107c478bd9Sstevel@tonic-gate 	aggr_lacp_mode_t	lacp_mode = AGGR_LACP_OFF;
13117c478bd9Sstevel@tonic-gate 	aggr_lacp_timer_t	lacp_timer = AGGR_LACP_TIMER_SHORT;
1312f595a68aSyz147064 	dladm_aggr_port_attr_db_t	port[MAXPORT];
1313d62bc4baSyz147064 	uint_t			n, ndev, nlink;
13147c478bd9Sstevel@tonic-gate 	uint8_t			mac_addr[ETHERADDRL];
13157c478bd9Sstevel@tonic-gate 	boolean_t		mac_addr_fixed = B_FALSE;
13167c478bd9Sstevel@tonic-gate 	boolean_t		P_arg = B_FALSE;
13177c478bd9Sstevel@tonic-gate 	boolean_t		l_arg = B_FALSE;
13187c478bd9Sstevel@tonic-gate 	boolean_t		u_arg = B_FALSE;
13197c478bd9Sstevel@tonic-gate 	boolean_t		T_arg = B_FALSE;
1320d62bc4baSyz147064 	uint32_t		flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
13217c478bd9Sstevel@tonic-gate 	char			*altroot = NULL;
1322d62bc4baSyz147064 	char			name[MAXLINKNAMELEN];
1323d62bc4baSyz147064 	char			*devs[MAXPORT];
1324d62bc4baSyz147064 	char			*links[MAXPORT];
1325f595a68aSyz147064 	dladm_status_t		status;
1326*da14cebeSEric Cheng 	dladm_status_t		pstatus;
1327*da14cebeSEric Cheng 	dladm_arg_list_t	*proplist = NULL;
1328*da14cebeSEric Cheng 	int			i;
1329*da14cebeSEric Cheng 	datalink_id_t		linkid;
13307c478bd9Sstevel@tonic-gate 
1331d62bc4baSyz147064 	ndev = nlink = opterr = 0;
1332*da14cebeSEric Cheng 	while ((option = getopt_long(argc, argv, ":d:l:L:P:R:tfu:T:p:",
1333d62bc4baSyz147064 	    lopts, NULL)) != -1) {
13347c478bd9Sstevel@tonic-gate 		switch (option) {
13357c478bd9Sstevel@tonic-gate 		case 'd':
1336d62bc4baSyz147064 			if (ndev + nlink >= MAXPORT)
1337d62bc4baSyz147064 				die("too many ports specified");
13387c478bd9Sstevel@tonic-gate 
1339d62bc4baSyz147064 			devs[ndev++] = optarg;
13407c478bd9Sstevel@tonic-gate 			break;
13417c478bd9Sstevel@tonic-gate 		case 'P':
134233343a97Smeem 			if (P_arg)
134333343a97Smeem 				die_optdup(option);
13447c478bd9Sstevel@tonic-gate 
13457c478bd9Sstevel@tonic-gate 			P_arg = B_TRUE;
1346f595a68aSyz147064 			if (!dladm_aggr_str2policy(optarg, &policy))
134733343a97Smeem 				die("invalid policy '%s'", optarg);
13487c478bd9Sstevel@tonic-gate 			break;
13497c478bd9Sstevel@tonic-gate 		case 'u':
135033343a97Smeem 			if (u_arg)
135133343a97Smeem 				die_optdup(option);
13527c478bd9Sstevel@tonic-gate 
13537c478bd9Sstevel@tonic-gate 			u_arg = B_TRUE;
1354f595a68aSyz147064 			if (!dladm_aggr_str2macaddr(optarg, &mac_addr_fixed,
135533343a97Smeem 			    mac_addr))
135633343a97Smeem 				die("invalid MAC address '%s'", optarg);
13577c478bd9Sstevel@tonic-gate 			break;
13587c478bd9Sstevel@tonic-gate 		case 'l':
1359d62bc4baSyz147064 			if (isdigit(optarg[strlen(optarg) - 1])) {
1360d62bc4baSyz147064 
1361d62bc4baSyz147064 				/*
1362d62bc4baSyz147064 				 * Ended with digit, possibly a link name.
1363d62bc4baSyz147064 				 */
1364d62bc4baSyz147064 				if (ndev + nlink >= MAXPORT)
1365d62bc4baSyz147064 					die("too many ports specified");
1366d62bc4baSyz147064 
1367d62bc4baSyz147064 				links[nlink++] = optarg;
1368d62bc4baSyz147064 				break;
1369d62bc4baSyz147064 			}
1370d62bc4baSyz147064 			/* FALLTHROUGH */
1371d62bc4baSyz147064 		case 'L':
137233343a97Smeem 			if (l_arg)
137333343a97Smeem 				die_optdup(option);
13747c478bd9Sstevel@tonic-gate 
13757c478bd9Sstevel@tonic-gate 			l_arg = B_TRUE;
1376f595a68aSyz147064 			if (!dladm_aggr_str2lacpmode(optarg, &lacp_mode))
137733343a97Smeem 				die("invalid LACP mode '%s'", optarg);
13787c478bd9Sstevel@tonic-gate 			break;
13797c478bd9Sstevel@tonic-gate 		case 'T':
138033343a97Smeem 			if (T_arg)
138133343a97Smeem 				die_optdup(option);
13827c478bd9Sstevel@tonic-gate 
13837c478bd9Sstevel@tonic-gate 			T_arg = B_TRUE;
1384f595a68aSyz147064 			if (!dladm_aggr_str2lacptimer(optarg, &lacp_timer))
138533343a97Smeem 				die("invalid LACP timer value '%s'", optarg);
13867c478bd9Sstevel@tonic-gate 			break;
13877c478bd9Sstevel@tonic-gate 		case 't':
1388d62bc4baSyz147064 			flags &= ~DLADM_OPT_PERSIST;
1389d62bc4baSyz147064 			break;
1390d62bc4baSyz147064 		case 'f':
1391d62bc4baSyz147064 			flags |= DLADM_OPT_FORCE;
13927c478bd9Sstevel@tonic-gate 			break;
13937c478bd9Sstevel@tonic-gate 		case 'R':
13947c478bd9Sstevel@tonic-gate 			altroot = optarg;
13957c478bd9Sstevel@tonic-gate 			break;
1396*da14cebeSEric Cheng 		case 'p':
1397*da14cebeSEric Cheng 			if (dladm_parse_link_props(optarg, &proplist, B_FALSE)
1398*da14cebeSEric Cheng 			    != DLADM_STATUS_OK)
1399*da14cebeSEric Cheng 				die("invalid aggregation property");
1400*da14cebeSEric Cheng 			break;
14017c478bd9Sstevel@tonic-gate 		default:
14028d5c46e6Sam223141 			die_opterr(optopt, option, use);
140333343a97Smeem 			break;
14047c478bd9Sstevel@tonic-gate 		}
14057c478bd9Sstevel@tonic-gate 	}
14067c478bd9Sstevel@tonic-gate 
1407d62bc4baSyz147064 	if (ndev + nlink == 0)
14087c478bd9Sstevel@tonic-gate 		usage();
14097c478bd9Sstevel@tonic-gate 
1410d62bc4baSyz147064 	/* get key value or the aggregation name (required last argument) */
14117c478bd9Sstevel@tonic-gate 	if (optind != (argc-1))
14127c478bd9Sstevel@tonic-gate 		usage();
14137c478bd9Sstevel@tonic-gate 
1414d62bc4baSyz147064 	if (!str2int(argv[optind], &key)) {
1415d62bc4baSyz147064 		if (strlcpy(name, argv[optind], MAXLINKNAMELEN) >=
1416d62bc4baSyz147064 		    MAXLINKNAMELEN) {
1417d62bc4baSyz147064 			die("link name too long '%s'", argv[optind]);
1418d62bc4baSyz147064 		}
14197c478bd9Sstevel@tonic-gate 
1420d62bc4baSyz147064 		if (!dladm_valid_linkname(name))
1421d62bc4baSyz147064 			die("invalid link name '%s'", argv[optind]);
1422d62bc4baSyz147064 	} else {
1423d62bc4baSyz147064 		(void) snprintf(name, MAXLINKNAMELEN, "aggr%d", key);
1424d62bc4baSyz147064 	}
1425d62bc4baSyz147064 
1426d62bc4baSyz147064 	if (altroot != NULL)
1427d62bc4baSyz147064 		altroot_cmd(altroot, argc, argv);
1428d62bc4baSyz147064 
1429d62bc4baSyz147064 	for (n = 0; n < ndev; n++) {
1430d62bc4baSyz147064 		if (dladm_dev2linkid(devs[n], &port[n].lp_linkid) !=
1431d62bc4baSyz147064 		    DLADM_STATUS_OK) {
1432d62bc4baSyz147064 			die("invalid dev name '%s'", devs[n]);
1433d62bc4baSyz147064 		}
1434d62bc4baSyz147064 	}
1435d62bc4baSyz147064 
1436d62bc4baSyz147064 	for (n = 0; n < nlink; n++) {
1437d62bc4baSyz147064 		if (dladm_name2info(links[n], &port[ndev + n].lp_linkid,
1438d62bc4baSyz147064 		    NULL, NULL, NULL) != DLADM_STATUS_OK) {
1439d62bc4baSyz147064 			die("invalid link name '%s'", links[n]);
1440d62bc4baSyz147064 		}
1441d62bc4baSyz147064 	}
1442d62bc4baSyz147064 
1443d62bc4baSyz147064 	status = dladm_aggr_create(name, key, ndev + nlink, port, policy,
1444d62bc4baSyz147064 	    mac_addr_fixed, (const uchar_t *)mac_addr, lacp_mode,
1445d62bc4baSyz147064 	    lacp_timer, flags);
1446*da14cebeSEric Cheng 	if (status != DLADM_STATUS_OK)
1447*da14cebeSEric Cheng 		goto done;
1448*da14cebeSEric Cheng 
1449*da14cebeSEric Cheng 	if (proplist == NULL)
1450*da14cebeSEric Cheng 		return;
1451*da14cebeSEric Cheng 
1452*da14cebeSEric Cheng 	status = dladm_name2info(name, &linkid, NULL, NULL, NULL);
1453*da14cebeSEric Cheng 	if (status != DLADM_STATUS_OK)
1454*da14cebeSEric Cheng 		goto done;
1455*da14cebeSEric Cheng 
1456*da14cebeSEric Cheng 	for (i = 0; i < proplist->al_count; i++) {
1457*da14cebeSEric Cheng 		dladm_arg_info_t	*aip = &proplist->al_info[i];
1458*da14cebeSEric Cheng 
1459*da14cebeSEric Cheng 		pstatus = dladm_set_linkprop(linkid, aip->ai_name,
1460*da14cebeSEric Cheng 		    aip->ai_val, aip->ai_count, flags);
1461*da14cebeSEric Cheng 
1462*da14cebeSEric Cheng 		if (pstatus != DLADM_STATUS_OK) {
1463*da14cebeSEric Cheng 			die_dlerr(pstatus,
1464*da14cebeSEric Cheng 			    "aggr creation succeeded but "
1465*da14cebeSEric Cheng 			    "could not set property '%s'", aip->ai_name);
1466*da14cebeSEric Cheng 		}
1467*da14cebeSEric Cheng 	}
1468d62bc4baSyz147064 done:
1469*da14cebeSEric Cheng 	dladm_free_props(proplist);
1470d62bc4baSyz147064 	if (status != DLADM_STATUS_OK) {
1471d62bc4baSyz147064 		if (status == DLADM_STATUS_NONOTIF) {
1472d62bc4baSyz147064 			die_dlerr(status, "not all links have link up/down "
1473d62bc4baSyz147064 			    "detection; must use -f (see dladm(1M))\n");
1474d62bc4baSyz147064 		} else {
1475f595a68aSyz147064 			die_dlerr(status, "create operation failed");
14767c478bd9Sstevel@tonic-gate 		}
1477d62bc4baSyz147064 	}
1478d62bc4baSyz147064 }
1479d62bc4baSyz147064 
1480d62bc4baSyz147064 /*
1481d62bc4baSyz147064  * arg is either the key or the aggr name. Validate it and convert it to
1482d62bc4baSyz147064  * the linkid if altroot is NULL.
1483d62bc4baSyz147064  */
1484d62bc4baSyz147064 static dladm_status_t
1485d62bc4baSyz147064 i_dladm_aggr_get_linkid(const char *altroot, const char *arg,
1486d62bc4baSyz147064     datalink_id_t *linkidp, uint32_t flags)
1487d62bc4baSyz147064 {
1488d62bc4baSyz147064 	int		key = 0;
1489d62bc4baSyz147064 	char		*aggr = NULL;
1490d62bc4baSyz147064 	dladm_status_t	status;
1491d62bc4baSyz147064 
1492d62bc4baSyz147064 	if (!str2int(arg, &key))
1493d62bc4baSyz147064 		aggr = (char *)arg;
1494d62bc4baSyz147064 
1495d62bc4baSyz147064 	if (aggr == NULL && key == 0)
1496d62bc4baSyz147064 		return (DLADM_STATUS_LINKINVAL);
1497d62bc4baSyz147064 
1498d62bc4baSyz147064 	if (altroot != NULL)
1499d62bc4baSyz147064 		return (DLADM_STATUS_OK);
1500d62bc4baSyz147064 
1501d62bc4baSyz147064 	if (aggr != NULL) {
1502d62bc4baSyz147064 		status = dladm_name2info(aggr, linkidp, NULL, NULL, NULL);
1503d62bc4baSyz147064 	} else {
1504d62bc4baSyz147064 		status = dladm_key2linkid(key, linkidp, flags);
1505d62bc4baSyz147064 	}
1506d62bc4baSyz147064 
1507d62bc4baSyz147064 	return (status);
1508d62bc4baSyz147064 }
15097c478bd9Sstevel@tonic-gate 
15107c478bd9Sstevel@tonic-gate static void
15118d5c46e6Sam223141 do_delete_aggr(int argc, char *argv[], const char *use)
15127c478bd9Sstevel@tonic-gate {
15137c478bd9Sstevel@tonic-gate 	char			option;
15147c478bd9Sstevel@tonic-gate 	char			*altroot = NULL;
1515d62bc4baSyz147064 	uint32_t		flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
1516f595a68aSyz147064 	dladm_status_t		status;
1517d62bc4baSyz147064 	datalink_id_t		linkid;
15187c478bd9Sstevel@tonic-gate 
15197c478bd9Sstevel@tonic-gate 	opterr = 0;
1520d62bc4baSyz147064 	while ((option = getopt_long(argc, argv, ":R:t", lopts, NULL)) != -1) {
15217c478bd9Sstevel@tonic-gate 		switch (option) {
15227c478bd9Sstevel@tonic-gate 		case 't':
1523d62bc4baSyz147064 			flags &= ~DLADM_OPT_PERSIST;
15247c478bd9Sstevel@tonic-gate 			break;
15257c478bd9Sstevel@tonic-gate 		case 'R':
15267c478bd9Sstevel@tonic-gate 			altroot = optarg;
15277c478bd9Sstevel@tonic-gate 			break;
15287c478bd9Sstevel@tonic-gate 		default:
15298d5c46e6Sam223141 			die_opterr(optopt, option, use);
15307c478bd9Sstevel@tonic-gate 			break;
15317c478bd9Sstevel@tonic-gate 		}
15327c478bd9Sstevel@tonic-gate 	}
15337c478bd9Sstevel@tonic-gate 
1534d62bc4baSyz147064 	/* get key value or the aggregation name (required last argument) */
15357c478bd9Sstevel@tonic-gate 	if (optind != (argc-1))
15367c478bd9Sstevel@tonic-gate 		usage();
15377c478bd9Sstevel@tonic-gate 
1538d62bc4baSyz147064 	status = i_dladm_aggr_get_linkid(altroot, argv[optind], &linkid, flags);
1539d62bc4baSyz147064 	if (status != DLADM_STATUS_OK)
1540d62bc4baSyz147064 		goto done;
15417c478bd9Sstevel@tonic-gate 
1542d62bc4baSyz147064 	if (altroot != NULL)
1543d62bc4baSyz147064 		altroot_cmd(altroot, argc, argv);
1544d62bc4baSyz147064 
1545d62bc4baSyz147064 	status = dladm_aggr_delete(linkid, flags);
1546d62bc4baSyz147064 done:
1547f595a68aSyz147064 	if (status != DLADM_STATUS_OK)
1548f595a68aSyz147064 		die_dlerr(status, "delete operation failed");
15497c478bd9Sstevel@tonic-gate }
15507c478bd9Sstevel@tonic-gate 
15517c478bd9Sstevel@tonic-gate static void
15528d5c46e6Sam223141 do_add_aggr(int argc, char *argv[], const char *use)
15537c478bd9Sstevel@tonic-gate {
15547c478bd9Sstevel@tonic-gate 	char			option;
1555d62bc4baSyz147064 	uint_t			n, ndev, nlink;
15567c478bd9Sstevel@tonic-gate 	char			*altroot = NULL;
1557d62bc4baSyz147064 	uint32_t		flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
1558d62bc4baSyz147064 	datalink_id_t		linkid;
1559f595a68aSyz147064 	dladm_status_t		status;
1560d62bc4baSyz147064 	dladm_aggr_port_attr_db_t	port[MAXPORT];
1561d62bc4baSyz147064 	char			*devs[MAXPORT];
1562d62bc4baSyz147064 	char			*links[MAXPORT];
15637c478bd9Sstevel@tonic-gate 
1564d62bc4baSyz147064 	ndev = nlink = opterr = 0;
1565d62bc4baSyz147064 	while ((option = getopt_long(argc, argv, ":d:l:R:tf", lopts,
15667c478bd9Sstevel@tonic-gate 	    NULL)) != -1) {
15677c478bd9Sstevel@tonic-gate 		switch (option) {
15687c478bd9Sstevel@tonic-gate 		case 'd':
1569d62bc4baSyz147064 			if (ndev + nlink >= MAXPORT)
1570d62bc4baSyz147064 				die("too many ports specified");
15717c478bd9Sstevel@tonic-gate 
1572d62bc4baSyz147064 			devs[ndev++] = optarg;
1573d62bc4baSyz147064 			break;
1574d62bc4baSyz147064 		case 'l':
1575d62bc4baSyz147064 			if (ndev + nlink >= MAXPORT)
1576d62bc4baSyz147064 				die("too many ports specified");
157733343a97Smeem 
1578d62bc4baSyz147064 			links[nlink++] = optarg;
15797c478bd9Sstevel@tonic-gate 			break;
15807c478bd9Sstevel@tonic-gate 		case 't':
1581d62bc4baSyz147064 			flags &= ~DLADM_OPT_PERSIST;
1582d62bc4baSyz147064 			break;
1583d62bc4baSyz147064 		case 'f':
1584d62bc4baSyz147064 			flags |= DLADM_OPT_FORCE;
15857c478bd9Sstevel@tonic-gate 			break;
15867c478bd9Sstevel@tonic-gate 		case 'R':
15877c478bd9Sstevel@tonic-gate 			altroot = optarg;
15887c478bd9Sstevel@tonic-gate 			break;
15897c478bd9Sstevel@tonic-gate 		default:
15908d5c46e6Sam223141 			die_opterr(optopt, option, use);
159133343a97Smeem 			break;
15927c478bd9Sstevel@tonic-gate 		}
15937c478bd9Sstevel@tonic-gate 	}
15947c478bd9Sstevel@tonic-gate 
1595d62bc4baSyz147064 	if (ndev + nlink == 0)
15967c478bd9Sstevel@tonic-gate 		usage();
15977c478bd9Sstevel@tonic-gate 
1598d62bc4baSyz147064 	/* get key value or the aggregation name (required last argument) */
15997c478bd9Sstevel@tonic-gate 	if (optind != (argc-1))
16007c478bd9Sstevel@tonic-gate 		usage();
16017c478bd9Sstevel@tonic-gate 
1602d62bc4baSyz147064 	if ((status = i_dladm_aggr_get_linkid(altroot, argv[optind], &linkid,
1603d62bc4baSyz147064 	    flags & (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST))) !=
1604d62bc4baSyz147064 	    DLADM_STATUS_OK) {
1605d62bc4baSyz147064 		goto done;
1606d62bc4baSyz147064 	}
16077c478bd9Sstevel@tonic-gate 
1608d62bc4baSyz147064 	if (altroot != NULL)
1609d62bc4baSyz147064 		altroot_cmd(altroot, argc, argv);
1610d62bc4baSyz147064 
1611d62bc4baSyz147064 	for (n = 0; n < ndev; n++) {
1612d62bc4baSyz147064 		if (dladm_dev2linkid(devs[n], &(port[n].lp_linkid)) !=
1613d62bc4baSyz147064 		    DLADM_STATUS_OK) {
1614d62bc4baSyz147064 			die("invalid <dev> '%s'", devs[n]);
1615d62bc4baSyz147064 		}
1616d62bc4baSyz147064 	}
1617d62bc4baSyz147064 
1618d62bc4baSyz147064 	for (n = 0; n < nlink; n++) {
1619d62bc4baSyz147064 		if (dladm_name2info(links[n], &port[n + ndev].lp_linkid,
1620d62bc4baSyz147064 		    NULL, NULL, NULL) != DLADM_STATUS_OK) {
1621d62bc4baSyz147064 			die("invalid <link> '%s'", links[n]);
1622d62bc4baSyz147064 		}
1623d62bc4baSyz147064 	}
1624d62bc4baSyz147064 
1625d62bc4baSyz147064 	status = dladm_aggr_add(linkid, ndev + nlink, port, flags);
1626d62bc4baSyz147064 done:
1627f595a68aSyz147064 	if (status != DLADM_STATUS_OK) {
1628219a2a31Shl157128 		/*
1629f595a68aSyz147064 		 * checking DLADM_STATUS_NOTSUP is a temporary workaround
1630219a2a31Shl157128 		 * and should be removed once 6399681 is fixed.
1631219a2a31Shl157128 		 */
1632f595a68aSyz147064 		if (status == DLADM_STATUS_NOTSUP) {
1633219a2a31Shl157128 			(void) fprintf(stderr,
1634219a2a31Shl157128 			    gettext("%s: add operation failed: %s\n"),
1635219a2a31Shl157128 			    progname,
1636d62bc4baSyz147064 			    gettext("link capabilities don't match"));
1637219a2a31Shl157128 			exit(ENOTSUP);
1638d62bc4baSyz147064 		} else if (status == DLADM_STATUS_NONOTIF) {
1639d62bc4baSyz147064 			die_dlerr(status, "not all links have link up/down "
1640d62bc4baSyz147064 			    "detection; must use -f (see dladm(1M))\n");
1641d62bc4baSyz147064 		} else {
1642f595a68aSyz147064 			die_dlerr(status, "add operation failed");
16437c478bd9Sstevel@tonic-gate 		}
16447c478bd9Sstevel@tonic-gate 	}
1645d62bc4baSyz147064 }
16467c478bd9Sstevel@tonic-gate 
16477c478bd9Sstevel@tonic-gate static void
16488d5c46e6Sam223141 do_remove_aggr(int argc, char *argv[], const char *use)
16497c478bd9Sstevel@tonic-gate {
16507c478bd9Sstevel@tonic-gate 	char				option;
1651f595a68aSyz147064 	dladm_aggr_port_attr_db_t	port[MAXPORT];
1652d62bc4baSyz147064 	uint_t				n, ndev, nlink;
1653d62bc4baSyz147064 	char				*devs[MAXPORT];
1654d62bc4baSyz147064 	char				*links[MAXPORT];
16557c478bd9Sstevel@tonic-gate 	char				*altroot = NULL;
1656d62bc4baSyz147064 	uint32_t			flags;
1657d62bc4baSyz147064 	datalink_id_t			linkid;
1658f595a68aSyz147064 	dladm_status_t			status;
16597c478bd9Sstevel@tonic-gate 
1660d62bc4baSyz147064 	flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
1661d62bc4baSyz147064 	ndev = nlink = opterr = 0;
1662d62bc4baSyz147064 	while ((option = getopt_long(argc, argv, ":d:l:R:t",
1663d62bc4baSyz147064 	    lopts, NULL)) != -1) {
16647c478bd9Sstevel@tonic-gate 		switch (option) {
16657c478bd9Sstevel@tonic-gate 		case 'd':
1666d62bc4baSyz147064 			if (ndev + nlink >= MAXPORT)
1667d62bc4baSyz147064 				die("too many ports specified");
16687c478bd9Sstevel@tonic-gate 
1669d62bc4baSyz147064 			devs[ndev++] = optarg;
1670d62bc4baSyz147064 			break;
1671d62bc4baSyz147064 		case 'l':
1672d62bc4baSyz147064 			if (ndev + nlink >= MAXPORT)
1673d62bc4baSyz147064 				die("too many ports specified");
167433343a97Smeem 
1675d62bc4baSyz147064 			links[nlink++] = optarg;
16767c478bd9Sstevel@tonic-gate 			break;
16777c478bd9Sstevel@tonic-gate 		case 't':
1678d62bc4baSyz147064 			flags &= ~DLADM_OPT_PERSIST;
16797c478bd9Sstevel@tonic-gate 			break;
16807c478bd9Sstevel@tonic-gate 		case 'R':
16817c478bd9Sstevel@tonic-gate 			altroot = optarg;
16827c478bd9Sstevel@tonic-gate 			break;
16837c478bd9Sstevel@tonic-gate 		default:
16848d5c46e6Sam223141 			die_opterr(optopt, option, use);
168533343a97Smeem 			break;
16867c478bd9Sstevel@tonic-gate 		}
16877c478bd9Sstevel@tonic-gate 	}
16887c478bd9Sstevel@tonic-gate 
1689d62bc4baSyz147064 	if (ndev + nlink == 0)
16907c478bd9Sstevel@tonic-gate 		usage();
16917c478bd9Sstevel@tonic-gate 
1692d62bc4baSyz147064 	/* get key value or the aggregation name (required last argument) */
16937c478bd9Sstevel@tonic-gate 	if (optind != (argc-1))
16947c478bd9Sstevel@tonic-gate 		usage();
16957c478bd9Sstevel@tonic-gate 
1696d62bc4baSyz147064 	status = i_dladm_aggr_get_linkid(altroot, argv[optind], &linkid, flags);
1697d62bc4baSyz147064 	if (status != DLADM_STATUS_OK)
1698d62bc4baSyz147064 		goto done;
16997c478bd9Sstevel@tonic-gate 
1700d62bc4baSyz147064 	if (altroot != NULL)
1701d62bc4baSyz147064 		altroot_cmd(altroot, argc, argv);
1702d62bc4baSyz147064 
1703d62bc4baSyz147064 	for (n = 0; n < ndev; n++) {
1704d62bc4baSyz147064 		if (dladm_dev2linkid(devs[n], &(port[n].lp_linkid)) !=
1705d62bc4baSyz147064 		    DLADM_STATUS_OK) {
1706d62bc4baSyz147064 			die("invalid <dev> '%s'", devs[n]);
1707d62bc4baSyz147064 		}
1708d62bc4baSyz147064 	}
1709d62bc4baSyz147064 
1710d62bc4baSyz147064 	for (n = 0; n < nlink; n++) {
1711d62bc4baSyz147064 		if (dladm_name2info(links[n], &port[n + ndev].lp_linkid,
1712d62bc4baSyz147064 		    NULL, NULL, NULL) != DLADM_STATUS_OK) {
1713d62bc4baSyz147064 			die("invalid <link> '%s'", links[n]);
1714d62bc4baSyz147064 		}
1715d62bc4baSyz147064 	}
1716d62bc4baSyz147064 
1717d62bc4baSyz147064 	status = dladm_aggr_remove(linkid, ndev + nlink, port, flags);
1718d62bc4baSyz147064 done:
1719f595a68aSyz147064 	if (status != DLADM_STATUS_OK)
1720f595a68aSyz147064 		die_dlerr(status, "remove operation failed");
17217c478bd9Sstevel@tonic-gate }
17227c478bd9Sstevel@tonic-gate 
17237c478bd9Sstevel@tonic-gate static void
17248d5c46e6Sam223141 do_modify_aggr(int argc, char *argv[], const char *use)
17257c478bd9Sstevel@tonic-gate {
17267c478bd9Sstevel@tonic-gate 	char			option;
17277c478bd9Sstevel@tonic-gate 	uint32_t		policy = AGGR_POLICY_L4;
17287c478bd9Sstevel@tonic-gate 	aggr_lacp_mode_t	lacp_mode = AGGR_LACP_OFF;
17297c478bd9Sstevel@tonic-gate 	aggr_lacp_timer_t	lacp_timer = AGGR_LACP_TIMER_SHORT;
17307c478bd9Sstevel@tonic-gate 	uint8_t			mac_addr[ETHERADDRL];
17317c478bd9Sstevel@tonic-gate 	boolean_t		mac_addr_fixed = B_FALSE;
17327c478bd9Sstevel@tonic-gate 	uint8_t			modify_mask = 0;
17337c478bd9Sstevel@tonic-gate 	char			*altroot = NULL;
1734d62bc4baSyz147064 	uint32_t		flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
1735d62bc4baSyz147064 	datalink_id_t		linkid;
1736f595a68aSyz147064 	dladm_status_t		status;
17377c478bd9Sstevel@tonic-gate 
17387c478bd9Sstevel@tonic-gate 	opterr = 0;
1739d62bc4baSyz147064 	while ((option = getopt_long(argc, argv, ":L:l:P:R:tu:T:", lopts,
17407c478bd9Sstevel@tonic-gate 	    NULL)) != -1) {
17417c478bd9Sstevel@tonic-gate 		switch (option) {
17427c478bd9Sstevel@tonic-gate 		case 'P':
1743f595a68aSyz147064 			if (modify_mask & DLADM_AGGR_MODIFY_POLICY)
174433343a97Smeem 				die_optdup(option);
17457c478bd9Sstevel@tonic-gate 
1746f595a68aSyz147064 			modify_mask |= DLADM_AGGR_MODIFY_POLICY;
17477c478bd9Sstevel@tonic-gate 
1748f595a68aSyz147064 			if (!dladm_aggr_str2policy(optarg, &policy))
174933343a97Smeem 				die("invalid policy '%s'", optarg);
17507c478bd9Sstevel@tonic-gate 			break;
17517c478bd9Sstevel@tonic-gate 		case 'u':
1752f595a68aSyz147064 			if (modify_mask & DLADM_AGGR_MODIFY_MAC)
175333343a97Smeem 				die_optdup(option);
17547c478bd9Sstevel@tonic-gate 
1755f595a68aSyz147064 			modify_mask |= DLADM_AGGR_MODIFY_MAC;
17567c478bd9Sstevel@tonic-gate 
1757f595a68aSyz147064 			if (!dladm_aggr_str2macaddr(optarg, &mac_addr_fixed,
175833343a97Smeem 			    mac_addr))
175933343a97Smeem 				die("invalid MAC address '%s'", optarg);
17607c478bd9Sstevel@tonic-gate 			break;
17617c478bd9Sstevel@tonic-gate 		case 'l':
1762d62bc4baSyz147064 		case 'L':
1763f595a68aSyz147064 			if (modify_mask & DLADM_AGGR_MODIFY_LACP_MODE)
176433343a97Smeem 				die_optdup(option);
17657c478bd9Sstevel@tonic-gate 
1766f595a68aSyz147064 			modify_mask |= DLADM_AGGR_MODIFY_LACP_MODE;
17677c478bd9Sstevel@tonic-gate 
1768f595a68aSyz147064 			if (!dladm_aggr_str2lacpmode(optarg, &lacp_mode))
176933343a97Smeem 				die("invalid LACP mode '%s'", optarg);
17707c478bd9Sstevel@tonic-gate 			break;
17717c478bd9Sstevel@tonic-gate 		case 'T':
1772f595a68aSyz147064 			if (modify_mask & DLADM_AGGR_MODIFY_LACP_TIMER)
177333343a97Smeem 				die_optdup(option);
17747c478bd9Sstevel@tonic-gate 
1775f595a68aSyz147064 			modify_mask |= DLADM_AGGR_MODIFY_LACP_TIMER;
17767c478bd9Sstevel@tonic-gate 
1777f595a68aSyz147064 			if (!dladm_aggr_str2lacptimer(optarg, &lacp_timer))
177833343a97Smeem 				die("invalid LACP timer value '%s'", optarg);
17797c478bd9Sstevel@tonic-gate 			break;
17807c478bd9Sstevel@tonic-gate 		case 't':
1781d62bc4baSyz147064 			flags &= ~DLADM_OPT_PERSIST;
17827c478bd9Sstevel@tonic-gate 			break;
17837c478bd9Sstevel@tonic-gate 		case 'R':
17847c478bd9Sstevel@tonic-gate 			altroot = optarg;
17857c478bd9Sstevel@tonic-gate 			break;
17867c478bd9Sstevel@tonic-gate 		default:
17878d5c46e6Sam223141 			die_opterr(optopt, option, use);
178833343a97Smeem 			break;
17897c478bd9Sstevel@tonic-gate 		}
17907c478bd9Sstevel@tonic-gate 	}
17917c478bd9Sstevel@tonic-gate 
179233343a97Smeem 	if (modify_mask == 0)
179333343a97Smeem 		die("at least one of the -PulT options must be specified");
17947c478bd9Sstevel@tonic-gate 
1795d62bc4baSyz147064 	/* get key value or the aggregation name (required last argument) */
17967c478bd9Sstevel@tonic-gate 	if (optind != (argc-1))
17977c478bd9Sstevel@tonic-gate 		usage();
17987c478bd9Sstevel@tonic-gate 
1799d62bc4baSyz147064 	status = i_dladm_aggr_get_linkid(altroot, argv[optind], &linkid, flags);
1800d62bc4baSyz147064 	if (status != DLADM_STATUS_OK)
1801d62bc4baSyz147064 		goto done;
18027c478bd9Sstevel@tonic-gate 
1803d62bc4baSyz147064 	if (altroot != NULL)
1804d62bc4baSyz147064 		altroot_cmd(altroot, argc, argv);
1805d62bc4baSyz147064 
1806d62bc4baSyz147064 	status = dladm_aggr_modify(linkid, modify_mask, policy, mac_addr_fixed,
1807d62bc4baSyz147064 	    (const uchar_t *)mac_addr, lacp_mode, lacp_timer, flags);
1808d62bc4baSyz147064 
1809d62bc4baSyz147064 done:
1810f595a68aSyz147064 	if (status != DLADM_STATUS_OK)
1811f595a68aSyz147064 		die_dlerr(status, "modify operation failed");
18127c478bd9Sstevel@tonic-gate }
18137c478bd9Sstevel@tonic-gate 
18148d5c46e6Sam223141 /*ARGSUSED*/
18157c478bd9Sstevel@tonic-gate static void
18168d5c46e6Sam223141 do_up_aggr(int argc, char *argv[], const char *use)
18177c478bd9Sstevel@tonic-gate {
1818d62bc4baSyz147064 	datalink_id_t	linkid = DATALINK_ALL_LINKID;
1819f595a68aSyz147064 	dladm_status_t	status;
18207c478bd9Sstevel@tonic-gate 
1821d62bc4baSyz147064 	/*
1822d62bc4baSyz147064 	 * get the key or the name of the aggregation (optional last argument)
1823d62bc4baSyz147064 	 */
18247c478bd9Sstevel@tonic-gate 	if (argc == 2) {
1825d62bc4baSyz147064 		if ((status = i_dladm_aggr_get_linkid(NULL, argv[1], &linkid,
1826d62bc4baSyz147064 		    DLADM_OPT_PERSIST)) != DLADM_STATUS_OK) {
1827d62bc4baSyz147064 			goto done;
1828d62bc4baSyz147064 		}
18297c478bd9Sstevel@tonic-gate 	} else if (argc > 2) {
18307c478bd9Sstevel@tonic-gate 		usage();
18317c478bd9Sstevel@tonic-gate 	}
18327c478bd9Sstevel@tonic-gate 
1833d62bc4baSyz147064 	status = dladm_aggr_up(linkid);
1834d62bc4baSyz147064 done:
1835d62bc4baSyz147064 	if (status != DLADM_STATUS_OK) {
1836d62bc4baSyz147064 		if (argc == 2) {
1837d62bc4baSyz147064 			die_dlerr(status,
1838d62bc4baSyz147064 			    "could not bring up aggregation '%s'", argv[1]);
18397c478bd9Sstevel@tonic-gate 		} else {
1840f595a68aSyz147064 			die_dlerr(status, "could not bring aggregations up");
18417c478bd9Sstevel@tonic-gate 		}
18427c478bd9Sstevel@tonic-gate 	}
18437c478bd9Sstevel@tonic-gate }
18447c478bd9Sstevel@tonic-gate 
18457c478bd9Sstevel@tonic-gate static void
18468d5c46e6Sam223141 do_create_vlan(int argc, char *argv[], const char *use)
18477c478bd9Sstevel@tonic-gate {
1848d62bc4baSyz147064 	char			*link = NULL;
1849d62bc4baSyz147064 	char			drv[DLPI_LINKNAME_MAX];
1850d62bc4baSyz147064 	uint_t			ppa;
1851d62bc4baSyz147064 	datalink_id_t		linkid;
1852*da14cebeSEric Cheng 	datalink_id_t		dev_linkid;
1853d62bc4baSyz147064 	int			vid = 0;
1854d62bc4baSyz147064 	char			option;
1855d62bc4baSyz147064 	uint32_t		flags = (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST);
1856d62bc4baSyz147064 	char			*altroot = NULL;
1857d62bc4baSyz147064 	char			vlan[MAXLINKNAMELEN];
1858*da14cebeSEric Cheng 	dladm_arg_list_t	*proplist = NULL;
1859f595a68aSyz147064 	dladm_status_t		status;
18607c478bd9Sstevel@tonic-gate 
1861d62bc4baSyz147064 	opterr = 0;
1862*da14cebeSEric Cheng 	while ((option = getopt_long(argc, argv, ":tfR:l:v:p:",
1863d62bc4baSyz147064 	    lopts, NULL)) != -1) {
1864d62bc4baSyz147064 		switch (option) {
1865d62bc4baSyz147064 		case 'v':
1866d62bc4baSyz147064 			if (vid != 0)
1867d62bc4baSyz147064 				die_optdup(option);
1868d62bc4baSyz147064 
1869d62bc4baSyz147064 			if (!str2int(optarg, &vid) || vid < 1 || vid > 4094)
1870d62bc4baSyz147064 				die("invalid VLAN identifier '%s'", optarg);
1871d62bc4baSyz147064 
1872d62bc4baSyz147064 			break;
1873d62bc4baSyz147064 		case 'l':
1874d62bc4baSyz147064 			if (link != NULL)
1875d62bc4baSyz147064 				die_optdup(option);
1876d62bc4baSyz147064 
1877d62bc4baSyz147064 			link = optarg;
1878d62bc4baSyz147064 			break;
1879d62bc4baSyz147064 		case 't':
1880d62bc4baSyz147064 			flags &= ~DLADM_OPT_PERSIST;
1881d62bc4baSyz147064 			break;
1882d62bc4baSyz147064 		case 'R':
1883d62bc4baSyz147064 			altroot = optarg;
1884d62bc4baSyz147064 			break;
1885*da14cebeSEric Cheng 		case 'p':
1886*da14cebeSEric Cheng 			if (dladm_parse_link_props(optarg, &proplist, B_FALSE)
1887*da14cebeSEric Cheng 			    != DLADM_STATUS_OK) {
1888*da14cebeSEric Cheng 				die("invalid vlan property");
1889*da14cebeSEric Cheng 			}
1890*da14cebeSEric Cheng 			break;
1891*da14cebeSEric Cheng 		case 'f':
1892*da14cebeSEric Cheng 			flags |= DLADM_OPT_FORCE;
1893*da14cebeSEric Cheng 			break;
1894d62bc4baSyz147064 		default:
18958d5c46e6Sam223141 			die_opterr(optopt, option, use);
1896d62bc4baSyz147064 			break;
1897d62bc4baSyz147064 		}
1898d62bc4baSyz147064 	}
1899d62bc4baSyz147064 
1900d62bc4baSyz147064 	/* get vlan name if there is any */
1901d62bc4baSyz147064 	if ((vid == 0) || (link == NULL) || (argc - optind > 1))
19027c478bd9Sstevel@tonic-gate 		usage();
1903d62bc4baSyz147064 
1904d62bc4baSyz147064 	if (optind == (argc - 1)) {
1905d62bc4baSyz147064 		if (strlcpy(vlan, argv[optind], MAXLINKNAMELEN) >=
1906d62bc4baSyz147064 		    MAXLINKNAMELEN) {
1907d62bc4baSyz147064 			die("vlan name too long '%s'", argv[optind]);
1908d62bc4baSyz147064 		}
1909d62bc4baSyz147064 	} else {
1910d62bc4baSyz147064 		if ((dlpi_parselink(link, drv, &ppa) != DLPI_SUCCESS) ||
1911d62bc4baSyz147064 		    (ppa >= 1000) ||
1912d62bc4baSyz147064 		    (dlpi_makelink(vlan, drv, vid * 1000 + ppa) !=
1913d62bc4baSyz147064 		    DLPI_SUCCESS)) {
1914d62bc4baSyz147064 			die("invalid link name '%s'", link);
1915d62bc4baSyz147064 		}
19167c478bd9Sstevel@tonic-gate 	}
19177c478bd9Sstevel@tonic-gate 
1918d62bc4baSyz147064 	if (altroot != NULL)
1919d62bc4baSyz147064 		altroot_cmd(altroot, argc, argv);
1920d62bc4baSyz147064 
1921*da14cebeSEric Cheng 	if (dladm_name2info(link, &dev_linkid, NULL, NULL, NULL) !=
1922d62bc4baSyz147064 	    DLADM_STATUS_OK) {
1923d62bc4baSyz147064 		die("invalid link name '%s'", link);
1924d62bc4baSyz147064 	}
1925d62bc4baSyz147064 
1926*da14cebeSEric Cheng 	if ((status = dladm_vlan_create(vlan, dev_linkid, vid, proplist, flags,
1927*da14cebeSEric Cheng 	    &linkid)) != DLADM_STATUS_OK) {
1928*da14cebeSEric Cheng 		die_dlerr(status, "create operation over %s failed", link);
1929d62bc4baSyz147064 	}
1930d62bc4baSyz147064 }
1931d62bc4baSyz147064 
1932d62bc4baSyz147064 static void
19338d5c46e6Sam223141 do_delete_vlan(int argc, char *argv[], const char *use)
1934d62bc4baSyz147064 {
1935d62bc4baSyz147064 	char		option;
1936d62bc4baSyz147064 	uint32_t	flags = (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST);
1937d62bc4baSyz147064 	char		*altroot = NULL;
1938d62bc4baSyz147064 	datalink_id_t	linkid;
1939d62bc4baSyz147064 	dladm_status_t	status;
1940d62bc4baSyz147064 
1941d62bc4baSyz147064 	opterr = 0;
1942d62bc4baSyz147064 	while ((option = getopt_long(argc, argv, ":R:t", lopts, NULL)) != -1) {
1943d62bc4baSyz147064 		switch (option) {
1944d62bc4baSyz147064 		case 't':
1945d62bc4baSyz147064 			flags &= ~DLADM_OPT_PERSIST;
1946d62bc4baSyz147064 			break;
1947d62bc4baSyz147064 		case 'R':
1948d62bc4baSyz147064 			altroot = optarg;
1949d62bc4baSyz147064 			break;
1950d62bc4baSyz147064 		default:
19518d5c46e6Sam223141 			die_opterr(optopt, option, use);
1952d62bc4baSyz147064 			break;
1953d62bc4baSyz147064 		}
1954d62bc4baSyz147064 	}
1955d62bc4baSyz147064 
1956d62bc4baSyz147064 	/* get VLAN link name (required last argument) */
1957d62bc4baSyz147064 	if (optind != (argc - 1))
1958d62bc4baSyz147064 		usage();
1959d62bc4baSyz147064 
1960d62bc4baSyz147064 	if (altroot != NULL)
1961d62bc4baSyz147064 		altroot_cmd(altroot, argc, argv);
1962d62bc4baSyz147064 
1963d62bc4baSyz147064 	status = dladm_name2info(argv[optind], &linkid, NULL, NULL, NULL);
1964d62bc4baSyz147064 	if (status != DLADM_STATUS_OK)
1965d62bc4baSyz147064 		goto done;
1966d62bc4baSyz147064 
1967d62bc4baSyz147064 	status = dladm_vlan_delete(linkid, flags);
1968d62bc4baSyz147064 done:
1969d62bc4baSyz147064 	if (status != DLADM_STATUS_OK)
1970d62bc4baSyz147064 		die_dlerr(status, "delete operation failed");
1971d62bc4baSyz147064 }
1972d62bc4baSyz147064 
19738d5c46e6Sam223141 /*ARGSUSED*/
1974d62bc4baSyz147064 static void
19758d5c46e6Sam223141 do_up_vlan(int argc, char *argv[], const char *use)
1976d62bc4baSyz147064 {
1977*da14cebeSEric Cheng 	do_up_vnic_common(argc, argv, use, B_TRUE);
19787c478bd9Sstevel@tonic-gate }
19797c478bd9Sstevel@tonic-gate 
1980210db224Sericheng static void
19818d5c46e6Sam223141 do_rename_link(int argc, char *argv[], const char *use)
1982210db224Sericheng {
1983d62bc4baSyz147064 	char		option;
1984d62bc4baSyz147064 	char		*link1, *link2;
1985d62bc4baSyz147064 	char		*altroot = NULL;
1986d62bc4baSyz147064 	dladm_status_t	status;
1987210db224Sericheng 
1988d62bc4baSyz147064 	opterr = 0;
1989d62bc4baSyz147064 	while ((option = getopt_long(argc, argv, ":R:", lopts, NULL)) != -1) {
1990d62bc4baSyz147064 		switch (option) {
1991d62bc4baSyz147064 		case 'R':
1992d62bc4baSyz147064 			altroot = optarg;
1993d62bc4baSyz147064 			break;
1994d62bc4baSyz147064 		default:
19958d5c46e6Sam223141 			die_opterr(optopt, option, use);
1996d62bc4baSyz147064 			break;
1997210db224Sericheng 		}
1998210db224Sericheng 	}
1999210db224Sericheng 
2000d62bc4baSyz147064 	/* get link1 and link2 name (required the last 2 arguments) */
2001d62bc4baSyz147064 	if (optind != (argc - 2))
2002d62bc4baSyz147064 		usage();
2003d62bc4baSyz147064 
2004d62bc4baSyz147064 	if (altroot != NULL)
2005d62bc4baSyz147064 		altroot_cmd(altroot, argc, argv);
2006d62bc4baSyz147064 
2007d62bc4baSyz147064 	link1 = argv[optind++];
2008d62bc4baSyz147064 	link2 = argv[optind];
2009d62bc4baSyz147064 	if ((status = dladm_rename_link(link1, link2)) != DLADM_STATUS_OK)
2010d62bc4baSyz147064 		die_dlerr(status, "rename operation failed");
2011d62bc4baSyz147064 }
2012d62bc4baSyz147064 
20138d5c46e6Sam223141 /*ARGSUSED*/
2014d62bc4baSyz147064 static void
20158d5c46e6Sam223141 do_delete_phys(int argc, char *argv[], const char *use)
2016d62bc4baSyz147064 {
2017d62bc4baSyz147064 	datalink_id_t	linkid = DATALINK_ALL_LINKID;
2018d62bc4baSyz147064 	dladm_status_t	status;
2019d62bc4baSyz147064 
2020d62bc4baSyz147064 	/* get link name (required the last argument) */
2021d62bc4baSyz147064 	if (argc > 2)
2022d62bc4baSyz147064 		usage();
2023d62bc4baSyz147064 
2024d62bc4baSyz147064 	if (argc == 2) {
2025d62bc4baSyz147064 		status = dladm_name2info(argv[1], &linkid, NULL, NULL, NULL);
2026d62bc4baSyz147064 		if (status != DLADM_STATUS_OK)
2027d62bc4baSyz147064 			die_dlerr(status, "cannot delete '%s'", argv[1]);
2028d62bc4baSyz147064 	}
2029d62bc4baSyz147064 
2030d62bc4baSyz147064 	if ((status = dladm_phys_delete(linkid)) != DLADM_STATUS_OK) {
2031d62bc4baSyz147064 		if (argc == 2)
2032d62bc4baSyz147064 			die_dlerr(status, "cannot delete '%s'", argv[1]);
2033d62bc4baSyz147064 		else
2034d62bc4baSyz147064 			die_dlerr(status, "delete operation failed");
2035d62bc4baSyz147064 	}
2036d62bc4baSyz147064 }
2037d62bc4baSyz147064 
2038d62bc4baSyz147064 /*ARGSUSED*/
2039210db224Sericheng static int
2040d62bc4baSyz147064 i_dladm_walk_linkmap(datalink_id_t linkid, void *arg)
2041210db224Sericheng {
2042d62bc4baSyz147064 	char			name[MAXLINKNAMELEN];
2043d62bc4baSyz147064 	char			mediabuf[DLADM_STRSIZE];
2044d62bc4baSyz147064 	char			classbuf[DLADM_STRSIZE];
2045d62bc4baSyz147064 	datalink_class_t	class;
2046d62bc4baSyz147064 	uint32_t		media;
2047d62bc4baSyz147064 	uint32_t		flags;
2048210db224Sericheng 
2049d62bc4baSyz147064 	if (dladm_datalink_id2info(linkid, &flags, &class, &media, name,
2050d62bc4baSyz147064 	    MAXLINKNAMELEN) == DLADM_STATUS_OK) {
2051d62bc4baSyz147064 		(void) dladm_class2str(class, classbuf);
2052d62bc4baSyz147064 		(void) dladm_media2str(media, mediabuf);
2053d62bc4baSyz147064 		(void) printf("%-12s%8d  %-12s%-20s %6d\n", name,
2054d62bc4baSyz147064 		    linkid, classbuf, mediabuf, flags);
2055210db224Sericheng 	}
2056d62bc4baSyz147064 	return (DLADM_WALK_CONTINUE);
2057210db224Sericheng }
20587c478bd9Sstevel@tonic-gate 
20597c478bd9Sstevel@tonic-gate /*ARGSUSED*/
20607c478bd9Sstevel@tonic-gate static void
20618d5c46e6Sam223141 do_show_linkmap(int argc, char *argv[], const char *use)
20627c478bd9Sstevel@tonic-gate {
2063d62bc4baSyz147064 	if (argc != 1)
2064d62bc4baSyz147064 		die("invalid arguments");
20657c478bd9Sstevel@tonic-gate 
2066d62bc4baSyz147064 	(void) printf("%-12s%8s  %-12s%-20s %6s\n", "NAME", "LINKID",
2067d62bc4baSyz147064 	    "CLASS", "MEDIA", "FLAGS");
2068d62bc4baSyz147064 	(void) dladm_walk_datalink_id(i_dladm_walk_linkmap, NULL,
2069d62bc4baSyz147064 	    DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE,
2070d62bc4baSyz147064 	    DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST);
20717c478bd9Sstevel@tonic-gate }
2072d62bc4baSyz147064 
2073d62bc4baSyz147064 /*
2074d62bc4baSyz147064  * Delete inactive physical links.
2075d62bc4baSyz147064  */
2076d62bc4baSyz147064 /*ARGSUSED*/
2077d62bc4baSyz147064 static int
2078d62bc4baSyz147064 purge_phys(datalink_id_t linkid, void *arg)
2079d62bc4baSyz147064 {
2080d62bc4baSyz147064 	datalink_class_t	class;
2081d62bc4baSyz147064 	uint32_t		flags;
2082d62bc4baSyz147064 
2083d62bc4baSyz147064 	if (dladm_datalink_id2info(linkid, &flags, &class, NULL,
2084d62bc4baSyz147064 	    NULL, 0) != DLADM_STATUS_OK) {
2085d62bc4baSyz147064 		return (DLADM_WALK_CONTINUE);
2086d62bc4baSyz147064 	}
2087d62bc4baSyz147064 
2088d62bc4baSyz147064 	if (class == DATALINK_CLASS_PHYS && !(flags & DLADM_OPT_ACTIVE))
2089d62bc4baSyz147064 		(void) dladm_phys_delete(linkid);
2090d62bc4baSyz147064 
2091d62bc4baSyz147064 	return (DLADM_WALK_CONTINUE);
2092d62bc4baSyz147064 }
2093d62bc4baSyz147064 
2094d62bc4baSyz147064 /*ARGSUSED*/
2095d62bc4baSyz147064 static void
20968d5c46e6Sam223141 do_init_phys(int argc, char *argv[], const char *use)
2097d62bc4baSyz147064 {
2098d62bc4baSyz147064 	di_node_t devtree;
2099d62bc4baSyz147064 
2100d62bc4baSyz147064 	if (argc > 1)
2101d62bc4baSyz147064 		usage();
2102d62bc4baSyz147064 
2103d62bc4baSyz147064 	/*
2104d62bc4baSyz147064 	 * Force all the devices to attach, therefore all the network physical
2105d62bc4baSyz147064 	 * devices can be known to the dlmgmtd daemon.
2106d62bc4baSyz147064 	 */
2107d62bc4baSyz147064 	if ((devtree = di_init("/", DINFOFORCE | DINFOSUBTREE)) != DI_NODE_NIL)
2108d62bc4baSyz147064 		di_fini(devtree);
2109d62bc4baSyz147064 
2110d62bc4baSyz147064 	(void) dladm_walk_datalink_id(purge_phys, NULL,
2111d62bc4baSyz147064 	    DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST);
21127c478bd9Sstevel@tonic-gate }
21137c478bd9Sstevel@tonic-gate 
2114d62bc4baSyz147064 
2115d62bc4baSyz147064 /*
2116d62bc4baSyz147064  * Print the active topology information.
2117d62bc4baSyz147064  */
2118d62bc4baSyz147064 static dladm_status_t
2119d62bc4baSyz147064 print_link_topology(show_state_t *state, datalink_id_t linkid,
2120e7801d59Ssowmini     datalink_class_t class, link_fields_buf_t *lbuf)
2121d62bc4baSyz147064 {
2122d62bc4baSyz147064 	uint32_t	flags = state->ls_flags;
2123d62bc4baSyz147064 	dladm_status_t	status = DLADM_STATUS_OK;
21246b9e797cSsowmini 	char		tmpbuf[MAXLINKNAMELEN];
2125d62bc4baSyz147064 
2126e7801d59Ssowmini 	if (!state->ls_parseable)
2127e7801d59Ssowmini 		(void) sprintf(lbuf->link_over, STR_UNDEF_VAL);
2128d62bc4baSyz147064 	else
2129e7801d59Ssowmini 		(void) sprintf(lbuf->link_over, "");
2130d62bc4baSyz147064 
2131d62bc4baSyz147064 	if (class == DATALINK_CLASS_VLAN) {
2132d62bc4baSyz147064 		dladm_vlan_attr_t	vinfo;
2133d62bc4baSyz147064 
2134d62bc4baSyz147064 		status = dladm_vlan_info(linkid, &vinfo, flags);
2135d62bc4baSyz147064 		if (status != DLADM_STATUS_OK)
2136d62bc4baSyz147064 			goto done;
2137d62bc4baSyz147064 		status = dladm_datalink_id2info(vinfo.dv_linkid, NULL, NULL,
2138e7801d59Ssowmini 		    NULL, lbuf->link_over, sizeof (lbuf->link_over));
2139d62bc4baSyz147064 		if (status != DLADM_STATUS_OK)
2140d62bc4baSyz147064 			goto done;
2141d62bc4baSyz147064 	} else if (class == DATALINK_CLASS_AGGR) {
2142d62bc4baSyz147064 		dladm_aggr_grp_attr_t	ginfo;
2143d62bc4baSyz147064 		int			i;
2144d62bc4baSyz147064 
21456b9e797cSsowmini 		(void) sprintf(lbuf->link_over, "");
21466b9e797cSsowmini 
2147d62bc4baSyz147064 		status = dladm_aggr_info(linkid, &ginfo, flags);
2148d62bc4baSyz147064 		if (status != DLADM_STATUS_OK)
2149d62bc4baSyz147064 			goto done;
2150d62bc4baSyz147064 
2151d62bc4baSyz147064 		if (ginfo.lg_nports == 0) {
2152d62bc4baSyz147064 			status = DLADM_STATUS_BADVAL;
2153d62bc4baSyz147064 			goto done;
2154d62bc4baSyz147064 		}
2155d62bc4baSyz147064 		for (i = 0; i < ginfo.lg_nports; i++) {
2156d62bc4baSyz147064 			status = dladm_datalink_id2info(
2157e7801d59Ssowmini 			    ginfo.lg_ports[i].lp_linkid, NULL, NULL, NULL,
21586b9e797cSsowmini 			    tmpbuf, sizeof (tmpbuf));
2159d62bc4baSyz147064 			if (status != DLADM_STATUS_OK) {
2160d62bc4baSyz147064 				free(ginfo.lg_ports);
2161d62bc4baSyz147064 				goto done;
2162d62bc4baSyz147064 			}
21636b9e797cSsowmini 			(void) strlcat(lbuf->link_over, tmpbuf,
21646b9e797cSsowmini 			    sizeof (lbuf->link_over));
21656b9e797cSsowmini 			if (i != (ginfo.lg_nports - 1)) {
21666b9e797cSsowmini 				(void) strlcat(lbuf->link_over, " ",
21676b9e797cSsowmini 				    sizeof (lbuf->link_over));
21686b9e797cSsowmini 			}
2169d62bc4baSyz147064 		}
2170d62bc4baSyz147064 		free(ginfo.lg_ports);
2171d62bc4baSyz147064 	} else if (class == DATALINK_CLASS_VNIC) {
2172*da14cebeSEric Cheng 		dladm_vnic_attr_t	vinfo;
2173d62bc4baSyz147064 
2174d62bc4baSyz147064 		if ((status = dladm_vnic_info(linkid, &vinfo, flags)) !=
2175d62bc4baSyz147064 		    DLADM_STATUS_OK || (status = dladm_datalink_id2info(
2176e7801d59Ssowmini 		    vinfo.va_link_id, NULL, NULL, NULL, lbuf->link_over,
2177e7801d59Ssowmini 		    sizeof (lbuf->link_over)) != DLADM_STATUS_OK)) {
2178d62bc4baSyz147064 			goto done;
2179d62bc4baSyz147064 		}
2180d62bc4baSyz147064 	}
2181d62bc4baSyz147064 done:
2182d62bc4baSyz147064 	return (status);
2183d62bc4baSyz147064 }
2184d62bc4baSyz147064 
2185d62bc4baSyz147064 static dladm_status_t
2186e7801d59Ssowmini print_link(show_state_t *state, datalink_id_t linkid, link_fields_buf_t *lbuf)
2187d62bc4baSyz147064 {
2188d62bc4baSyz147064 	char			link[MAXLINKNAMELEN];
2189d62bc4baSyz147064 	datalink_class_t	class;
2190d62bc4baSyz147064 	uint_t			mtu;
2191d62bc4baSyz147064 	uint32_t		flags;
2192d62bc4baSyz147064 	dladm_status_t		status;
2193d62bc4baSyz147064 
2194d62bc4baSyz147064 	if ((status = dladm_datalink_id2info(linkid, &flags, &class, NULL,
2195d62bc4baSyz147064 	    link, sizeof (link))) != DLADM_STATUS_OK) {
2196d62bc4baSyz147064 		goto done;
2197d62bc4baSyz147064 	}
2198d62bc4baSyz147064 
2199d62bc4baSyz147064 	if (!(state->ls_flags & flags)) {
2200d62bc4baSyz147064 		status = DLADM_STATUS_NOTFOUND;
2201d62bc4baSyz147064 		goto done;
2202d62bc4baSyz147064 	}
2203d62bc4baSyz147064 
2204d62bc4baSyz147064 	if (state->ls_flags == DLADM_OPT_ACTIVE) {
2205d62bc4baSyz147064 		dladm_attr_t	dlattr;
2206d62bc4baSyz147064 
2207d62bc4baSyz147064 		if (class == DATALINK_CLASS_PHYS) {
2208d62bc4baSyz147064 			dladm_phys_attr_t	dpa;
2209d62bc4baSyz147064 			dlpi_handle_t		dh;
2210d62bc4baSyz147064 			dlpi_info_t		dlinfo;
2211d62bc4baSyz147064 
2212d62bc4baSyz147064 			if ((status = dladm_phys_info(linkid, &dpa,
2213d62bc4baSyz147064 			    DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) {
2214d62bc4baSyz147064 				goto done;
2215d62bc4baSyz147064 			}
2216d62bc4baSyz147064 
2217d62bc4baSyz147064 			if (!dpa.dp_novanity)
2218d62bc4baSyz147064 				goto link_mtu;
2219d62bc4baSyz147064 
2220d62bc4baSyz147064 			/*
2221d62bc4baSyz147064 			 * This is a physical link that does not have
2222d62bc4baSyz147064 			 * vanity naming support.
2223d62bc4baSyz147064 			 */
2224d62bc4baSyz147064 			if (dlpi_open(dpa.dp_dev, &dh, DLPI_DEVONLY) !=
2225d62bc4baSyz147064 			    DLPI_SUCCESS) {
2226d62bc4baSyz147064 				status = DLADM_STATUS_NOTFOUND;
2227d62bc4baSyz147064 				goto done;
2228d62bc4baSyz147064 			}
2229d62bc4baSyz147064 
2230d62bc4baSyz147064 			if (dlpi_info(dh, &dlinfo, 0) != DLPI_SUCCESS) {
2231d62bc4baSyz147064 				dlpi_close(dh);
2232d62bc4baSyz147064 				status = DLADM_STATUS_BADARG;
2233d62bc4baSyz147064 				goto done;
2234d62bc4baSyz147064 			}
2235d62bc4baSyz147064 
2236d62bc4baSyz147064 			dlpi_close(dh);
2237d62bc4baSyz147064 			mtu = dlinfo.di_max_sdu;
2238d62bc4baSyz147064 		} else {
2239d62bc4baSyz147064 link_mtu:
2240d62bc4baSyz147064 			status = dladm_info(linkid, &dlattr);
2241d62bc4baSyz147064 			if (status != DLADM_STATUS_OK)
2242d62bc4baSyz147064 				goto done;
2243d62bc4baSyz147064 			mtu = dlattr.da_max_sdu;
2244d62bc4baSyz147064 		}
2245d62bc4baSyz147064 	}
2246d62bc4baSyz147064 
2247e7801d59Ssowmini 	(void) snprintf(lbuf->link_name, sizeof (lbuf->link_name),
2248e7801d59Ssowmini 	    "%s", link);
2249e7801d59Ssowmini 	(void) dladm_class2str(class, lbuf->link_class);
2250d62bc4baSyz147064 	if (state->ls_flags == DLADM_OPT_ACTIVE) {
2251e7801d59Ssowmini 		(void) snprintf(lbuf->link_mtu, sizeof (lbuf->link_mtu),
2252c08e5e1aSdr146992 		    "%u", mtu);
2253e7801d59Ssowmini 		(void) get_linkstate(link, B_TRUE, lbuf->link_state);
2254d62bc4baSyz147064 	}
2255d62bc4baSyz147064 
2256e7801d59Ssowmini 	status = print_link_topology(state, linkid, class, lbuf);
2257d62bc4baSyz147064 	if (status != DLADM_STATUS_OK)
2258d62bc4baSyz147064 		goto done;
2259d62bc4baSyz147064 
2260d62bc4baSyz147064 done:
2261d62bc4baSyz147064 	return (status);
2262d62bc4baSyz147064 }
2263d62bc4baSyz147064 
2264d62bc4baSyz147064 static int
2265d62bc4baSyz147064 show_link(datalink_id_t linkid, void *arg)
2266d62bc4baSyz147064 {
2267e7801d59Ssowmini 	show_state_t		*state = (show_state_t *)arg;
2268d62bc4baSyz147064 	dladm_status_t		status;
2269e7801d59Ssowmini 	link_fields_buf_t	lbuf;
2270d62bc4baSyz147064 
2271e7801d59Ssowmini 	/*
2272e7801d59Ssowmini 	 * first get all the link attributes into lbuf;
2273e7801d59Ssowmini 	 */
22745f5c9f54SAnurag S. Maskey 	bzero(&lbuf, sizeof (link_fields_buf_t));
2275e7801d59Ssowmini 	status = print_link(state, linkid, &lbuf);
2276e7801d59Ssowmini 
2277d62bc4baSyz147064 	if (status != DLADM_STATUS_OK)
2278d62bc4baSyz147064 		goto done;
2279e7801d59Ssowmini 
2280e7801d59Ssowmini 	if (!state->ls_parseable && !state->ls_printheader) {
2281e7801d59Ssowmini 		print_header(&state->ls_print);
2282e7801d59Ssowmini 		state->ls_printheader = B_TRUE;
2283e7801d59Ssowmini 	}
2284e7801d59Ssowmini 
2285e7801d59Ssowmini 	dladm_print_output(&state->ls_print, state->ls_parseable,
2286e7801d59Ssowmini 	    dladm_print_field, (void *)&lbuf);
2287d62bc4baSyz147064 
2288d62bc4baSyz147064 done:
2289d62bc4baSyz147064 	state->ls_status = status;
2290d62bc4baSyz147064 	return (DLADM_WALK_CONTINUE);
2291d62bc4baSyz147064 }
2292d62bc4baSyz147064 
2293d62bc4baSyz147064 static int
2294d62bc4baSyz147064 show_link_stats(datalink_id_t linkid, void *arg)
2295d62bc4baSyz147064 {
2296e7801d59Ssowmini 	char			link[DLPI_LINKNAME_MAX];
2297d62bc4baSyz147064 	datalink_class_t	class;
2298e7801d59Ssowmini 	show_state_t		*state = (show_state_t *)arg;
22997c478bd9Sstevel@tonic-gate 	pktsum_t		stats, diff_stats;
2300d62bc4baSyz147064 	dladm_phys_attr_t	dpa;
23017c478bd9Sstevel@tonic-gate 
23027c478bd9Sstevel@tonic-gate 	if (state->ls_firstonly) {
23037c478bd9Sstevel@tonic-gate 		if (state->ls_donefirst)
2304d62bc4baSyz147064 			return (DLADM_WALK_CONTINUE);
23057c478bd9Sstevel@tonic-gate 		state->ls_donefirst = B_TRUE;
23067c478bd9Sstevel@tonic-gate 	} else {
23077c478bd9Sstevel@tonic-gate 		bzero(&state->ls_prevstats, sizeof (state->ls_prevstats));
23087c478bd9Sstevel@tonic-gate 	}
23097c478bd9Sstevel@tonic-gate 
2310d62bc4baSyz147064 	if (dladm_datalink_id2info(linkid, NULL, &class, NULL, link,
2311e7801d59Ssowmini 	    DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) {
2312d62bc4baSyz147064 		return (DLADM_WALK_CONTINUE);
2313d62bc4baSyz147064 	}
2314d62bc4baSyz147064 
2315d62bc4baSyz147064 	if (class == DATALINK_CLASS_PHYS) {
2316d62bc4baSyz147064 		if (dladm_phys_info(linkid, &dpa, DLADM_OPT_ACTIVE) !=
2317d62bc4baSyz147064 		    DLADM_STATUS_OK) {
2318d62bc4baSyz147064 			return (DLADM_WALK_CONTINUE);
2319d62bc4baSyz147064 		}
2320d62bc4baSyz147064 		if (dpa.dp_novanity)
2321d62bc4baSyz147064 			get_mac_stats(dpa.dp_dev, &stats);
2322d62bc4baSyz147064 		else
2323d62bc4baSyz147064 			get_link_stats(link, &stats);
2324d62bc4baSyz147064 	} else {
2325d62bc4baSyz147064 		get_link_stats(link, &stats);
2326d62bc4baSyz147064 	}
2327*da14cebeSEric Cheng 	dladm_stats_diff(&diff_stats, &stats, &state->ls_prevstats);
23287c478bd9Sstevel@tonic-gate 
2329*da14cebeSEric Cheng 	(void) printf("%-12s", link);
2330*da14cebeSEric Cheng 	(void) printf("%-10llu", diff_stats.ipackets);
2331*da14cebeSEric Cheng 	(void) printf("%-12llu", diff_stats.rbytes);
2332*da14cebeSEric Cheng 	(void) printf("%-8llu", diff_stats.ierrors);
2333*da14cebeSEric Cheng 	(void) printf("%-10llu", diff_stats.opackets);
2334*da14cebeSEric Cheng 	(void) printf("%-12llu", diff_stats.obytes);
2335*da14cebeSEric Cheng 	(void) printf("%-8llu\n", diff_stats.oerrors);
23367c478bd9Sstevel@tonic-gate 
23377c478bd9Sstevel@tonic-gate 	state->ls_prevstats = stats;
2338d62bc4baSyz147064 	return (DLADM_WALK_CONTINUE);
23397c478bd9Sstevel@tonic-gate }
23407c478bd9Sstevel@tonic-gate 
2341d62bc4baSyz147064 
2342d62bc4baSyz147064 static dladm_status_t
2343d62bc4baSyz147064 print_aggr_info(show_grp_state_t *state, const char *link,
2344e7801d59Ssowmini     dladm_aggr_grp_attr_t *ginfop)
2345d62bc4baSyz147064 {
2346d62bc4baSyz147064 	char			addr_str[ETHERADDRL * 3];
2347e7801d59Ssowmini 	laggr_fields_buf_t	lbuf;
2348d62bc4baSyz147064 
2349e7801d59Ssowmini 	(void) snprintf(lbuf.laggr_name, sizeof (lbuf.laggr_name),
2350e7801d59Ssowmini 	    "%s", link);
2351e7801d59Ssowmini 
2352e7801d59Ssowmini 	(void) dladm_aggr_policy2str(ginfop->lg_policy,
2353e7801d59Ssowmini 	    lbuf.laggr_policy);
2354d62bc4baSyz147064 
2355d62bc4baSyz147064 	if (ginfop->lg_mac_fixed) {
2356d62bc4baSyz147064 		(void) dladm_aggr_macaddr2str(ginfop->lg_mac, addr_str);
2357e7801d59Ssowmini 		(void) snprintf(lbuf.laggr_addrpolicy,
2358e7801d59Ssowmini 		    sizeof (lbuf.laggr_addrpolicy), "fixed (%s)", addr_str);
2359d62bc4baSyz147064 	} else {
2360e7801d59Ssowmini 		(void) snprintf(lbuf.laggr_addrpolicy,
2361e7801d59Ssowmini 		    sizeof (lbuf.laggr_addrpolicy), "auto");
2362d62bc4baSyz147064 	}
2363d62bc4baSyz147064 
2364d62bc4baSyz147064 
2365e7801d59Ssowmini 	(void) dladm_aggr_lacpmode2str(ginfop->lg_lacp_mode,
2366e7801d59Ssowmini 	    lbuf.laggr_lacpactivity);
2367e7801d59Ssowmini 	(void) dladm_aggr_lacptimer2str(ginfop->lg_lacp_timer,
2368e7801d59Ssowmini 	    lbuf.laggr_lacptimer);
2369e7801d59Ssowmini 	(void) snprintf(lbuf.laggr_flags, sizeof (lbuf.laggr_flags), "%c----",
2370d62bc4baSyz147064 	    ginfop->lg_force ? 'f' : '-');
2371e7801d59Ssowmini 
2372e7801d59Ssowmini 	if (!state->gs_parseable && !state->gs_printheader) {
2373e7801d59Ssowmini 		print_header(&state->gs_print);
2374e7801d59Ssowmini 		state->gs_printheader = B_TRUE;
2375d62bc4baSyz147064 	}
2376d62bc4baSyz147064 
2377e7801d59Ssowmini 	dladm_print_output(&state->gs_print, state->gs_parseable,
2378e7801d59Ssowmini 	    dladm_print_field, (void *)&lbuf);
2379e7801d59Ssowmini 
2380d62bc4baSyz147064 	return (DLADM_STATUS_OK);
2381d62bc4baSyz147064 }
2382d62bc4baSyz147064 
2383e7801d59Ssowmini static char *
2384e7801d59Ssowmini print_xaggr_callback(print_field_t *pf, void *arg)
2385d62bc4baSyz147064 {
2386e7801d59Ssowmini 	const laggr_args_t 	*l = arg;
2387e7801d59Ssowmini 	int 			portnum;
2388e7801d59Ssowmini 	static char 		buf[DLADM_STRSIZE];
2389e7801d59Ssowmini 	boolean_t		is_port = (l->laggr_lport >= 0);
2390e7801d59Ssowmini 	dladm_aggr_port_attr_t *portp;
2391d62bc4baSyz147064 	dladm_phys_attr_t	dpa;
2392e7801d59Ssowmini 	dladm_status_t		*stat, status;
2393d62bc4baSyz147064 
2394e7801d59Ssowmini 	stat = l->laggr_status;
2395e7801d59Ssowmini 	*stat = DLADM_STATUS_OK;
2396d62bc4baSyz147064 
2397e7801d59Ssowmini 	if (is_port) {
2398e7801d59Ssowmini 		portnum = l->laggr_lport;
2399e7801d59Ssowmini 		portp = &(l->laggr_ginfop->lg_ports[portnum]);
2400e7801d59Ssowmini 		if ((status = dladm_datalink_id2info(portp->lp_linkid,
2401e7801d59Ssowmini 		    NULL, NULL, NULL, buf, sizeof (buf))) !=
2402e7801d59Ssowmini 		    DLADM_STATUS_OK) {
2403e7801d59Ssowmini 			goto err;
2404d62bc4baSyz147064 		}
2405d62bc4baSyz147064 		if ((status = dladm_phys_info(portp->lp_linkid, &dpa,
2406d62bc4baSyz147064 		    DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) {
2407e7801d59Ssowmini 			goto err;
2408e7801d59Ssowmini 		}
2409d62bc4baSyz147064 	}
2410d62bc4baSyz147064 
2411e7801d59Ssowmini 	switch (pf->pf_index) {
2412e7801d59Ssowmini 	case AGGR_X_LINK:
2413e7801d59Ssowmini 		(void) snprintf(buf, sizeof (buf), "%s",
2414e7801d59Ssowmini 		    (is_port && !l->laggr_parseable ? " " : l->laggr_link));
2415e7801d59Ssowmini 		break;
2416e7801d59Ssowmini 	case AGGR_X_PORT:
2417e7801d59Ssowmini 		if (is_port)
2418e7801d59Ssowmini 			break;
2419e7801d59Ssowmini 		return ("");
2420e7801d59Ssowmini 		break;
2421d62bc4baSyz147064 
2422e7801d59Ssowmini 	case AGGR_X_SPEED:
2423e7801d59Ssowmini 		if (is_port) {
2424e7801d59Ssowmini 			(void) snprintf(buf, sizeof (buf), "%uMb",
2425e7801d59Ssowmini 			    (uint_t)((get_ifspeed(dpa.dp_dev,
2426e7801d59Ssowmini 			    B_FALSE)) / 1000000ull));
2427e7801d59Ssowmini 		} else {
2428e7801d59Ssowmini 			(void) snprintf(buf, sizeof (buf), "%uMb",
2429e7801d59Ssowmini 			    (uint_t)((get_ifspeed(l->laggr_link,
2430e7801d59Ssowmini 			    B_TRUE)) / 1000000ull));
2431e7801d59Ssowmini 		}
2432e7801d59Ssowmini 		break;
2433e7801d59Ssowmini 
2434e7801d59Ssowmini 	case AGGR_X_DUPLEX:
2435e7801d59Ssowmini 		if (is_port)
2436e7801d59Ssowmini 			(void) get_linkduplex(dpa.dp_dev, B_FALSE, buf);
2437d62bc4baSyz147064 		else
2438e7801d59Ssowmini 			(void) get_linkduplex(l->laggr_link, B_TRUE, buf);
2439e7801d59Ssowmini 		break;
2440d62bc4baSyz147064 
2441e7801d59Ssowmini 	case AGGR_X_STATE:
24421a1811a0Svs226613 		if (is_port)
24431a1811a0Svs226613 			(void) get_linkstate(dpa.dp_dev,  B_FALSE, buf);
24441a1811a0Svs226613 		else
24451a1811a0Svs226613 			(void) get_linkstate(l->laggr_link, B_TRUE, buf);
2446e7801d59Ssowmini 		break;
2447e7801d59Ssowmini 	case AGGR_X_ADDRESS:
2448e7801d59Ssowmini 		(void) dladm_aggr_macaddr2str(
2449e7801d59Ssowmini 		    (is_port ? portp->lp_mac : l->laggr_ginfop->lg_mac),
2450e7801d59Ssowmini 		    buf);
2451e7801d59Ssowmini 		break;
2452e7801d59Ssowmini 	case AGGR_X_PORTSTATE:
24530d365605Sschuster 		if (is_port)
24540d365605Sschuster 			(void) dladm_aggr_portstate2str(
24550d365605Sschuster 			    portp->lp_state, buf);
24560d365605Sschuster 		else
24570d365605Sschuster 			return ("");
2458e7801d59Ssowmini 		break;
2459e7801d59Ssowmini 	}
2460e7801d59Ssowmini 	return (buf);
2461e7801d59Ssowmini 
2462e7801d59Ssowmini err:
2463e7801d59Ssowmini 	*stat = status;
2464e7801d59Ssowmini 	buf[0] = '\0';
2465e7801d59Ssowmini 	return (buf);
2466e7801d59Ssowmini }
2467e7801d59Ssowmini 
2468e7801d59Ssowmini static dladm_status_t
2469e7801d59Ssowmini print_aggr_extended(show_grp_state_t *state, const char *link,
2470e7801d59Ssowmini     dladm_aggr_grp_attr_t *ginfop)
2471e7801d59Ssowmini {
2472e7801d59Ssowmini 	int			i;
2473e7801d59Ssowmini 	dladm_status_t		status;
2474e7801d59Ssowmini 	laggr_args_t		largs;
2475e7801d59Ssowmini 
2476e7801d59Ssowmini 	if (!state->gs_parseable && !state->gs_printheader) {
2477e7801d59Ssowmini 		print_header(&state->gs_print);
2478e7801d59Ssowmini 		state->gs_printheader = B_TRUE;
2479e7801d59Ssowmini 	}
2480e7801d59Ssowmini 
2481e7801d59Ssowmini 	largs.laggr_lport = -1;
2482e7801d59Ssowmini 	largs.laggr_link = link;
2483e7801d59Ssowmini 	largs.laggr_ginfop = ginfop;
2484e7801d59Ssowmini 	largs.laggr_status = &status;
2485e7801d59Ssowmini 	largs.laggr_parseable = state->gs_parseable;
2486e7801d59Ssowmini 
2487e7801d59Ssowmini 	dladm_print_output(&state->gs_print, state->gs_parseable,
2488e7801d59Ssowmini 	    print_xaggr_callback, &largs);
2489e7801d59Ssowmini 
2490e7801d59Ssowmini 	if (status != DLADM_STATUS_OK)
2491e7801d59Ssowmini 		goto done;
2492e7801d59Ssowmini 
2493e7801d59Ssowmini 	for (i = 0; i < ginfop->lg_nports; i++) {
2494e7801d59Ssowmini 		largs.laggr_lport = i;
2495e7801d59Ssowmini 		dladm_print_output(&state->gs_print, state->gs_parseable,
2496e7801d59Ssowmini 		    print_xaggr_callback, &largs);
2497e7801d59Ssowmini 		if (status != DLADM_STATUS_OK)
2498e7801d59Ssowmini 			goto done;
2499d62bc4baSyz147064 	}
2500d62bc4baSyz147064 
2501d62bc4baSyz147064 	status = DLADM_STATUS_OK;
2502d62bc4baSyz147064 done:
2503d62bc4baSyz147064 	return (status);
2504d62bc4baSyz147064 }
2505d62bc4baSyz147064 
2506e7801d59Ssowmini 
2507e7801d59Ssowmini static char *
2508e7801d59Ssowmini print_lacp_callback(print_field_t *pf, void *arg)
2509e7801d59Ssowmini {
2510e7801d59Ssowmini 	const laggr_args_t	*l = arg;
2511e7801d59Ssowmini 	int			portnum;
2512e7801d59Ssowmini 	static char		buf[DLADM_STRSIZE];
2513e7801d59Ssowmini 	boolean_t		is_port = (l->laggr_lport >= 0);
2514e7801d59Ssowmini 	dladm_aggr_port_attr_t	*portp;
2515e7801d59Ssowmini 	dladm_status_t		*stat, status;
2516e7801d59Ssowmini 	aggr_lacp_state_t	*lstate;
2517e7801d59Ssowmini 
2518e7801d59Ssowmini 	if (!is_port) {
2519e7801d59Ssowmini 		return (NULL); /* cannot happen! */
2520e7801d59Ssowmini 	}
2521e7801d59Ssowmini 
2522e7801d59Ssowmini 	stat = l->laggr_status;
2523e7801d59Ssowmini 
2524e7801d59Ssowmini 	portnum = l->laggr_lport;
2525e7801d59Ssowmini 	portp = &(l->laggr_ginfop->lg_ports[portnum]);
2526e7801d59Ssowmini 	if ((status = dladm_datalink_id2info(portp->lp_linkid,
2527e7801d59Ssowmini 	    NULL, NULL, NULL, buf, sizeof (buf))) != DLADM_STATUS_OK) {
2528e7801d59Ssowmini 			goto err;
2529e7801d59Ssowmini 	}
2530e7801d59Ssowmini 	lstate = &(portp->lp_lacp_state);
2531e7801d59Ssowmini 
2532e7801d59Ssowmini 	switch (pf->pf_index) {
2533e7801d59Ssowmini 	case AGGR_L_LINK:
2534e7801d59Ssowmini 		(void) snprintf(buf, sizeof (buf), "%s",
2535e7801d59Ssowmini 		    (portnum > 0 ? "" : l->laggr_link));
2536e7801d59Ssowmini 		break;
2537e7801d59Ssowmini 
2538e7801d59Ssowmini 	case AGGR_L_PORT:
2539e7801d59Ssowmini 		break;
2540e7801d59Ssowmini 
2541e7801d59Ssowmini 	case AGGR_L_AGGREGATABLE:
2542e7801d59Ssowmini 		(void) snprintf(buf, sizeof (buf), "%s",
2543e7801d59Ssowmini 		    (lstate->bit.aggregation ? "yes" : "no"));
2544e7801d59Ssowmini 		break;
2545e7801d59Ssowmini 
2546e7801d59Ssowmini 	case AGGR_L_SYNC:
2547e7801d59Ssowmini 		(void) snprintf(buf, sizeof (buf), "%s",
2548e7801d59Ssowmini 		    (lstate->bit.sync ? "yes" : "no"));
2549e7801d59Ssowmini 		break;
2550e7801d59Ssowmini 
2551e7801d59Ssowmini 	case AGGR_L_COLL:
2552e7801d59Ssowmini 		(void) snprintf(buf, sizeof (buf), "%s",
2553e7801d59Ssowmini 		    (lstate->bit.collecting ? "yes" : "no"));
2554e7801d59Ssowmini 		break;
2555e7801d59Ssowmini 
2556e7801d59Ssowmini 	case AGGR_L_DIST:
2557e7801d59Ssowmini 		(void) snprintf(buf, sizeof (buf), "%s",
2558e7801d59Ssowmini 		    (lstate->bit.distributing ? "yes" : "no"));
2559e7801d59Ssowmini 		break;
2560e7801d59Ssowmini 
2561e7801d59Ssowmini 	case AGGR_L_DEFAULTED:
2562e7801d59Ssowmini 		(void) snprintf(buf, sizeof (buf), "%s",
2563e7801d59Ssowmini 		    (lstate->bit.defaulted ? "yes" : "no"));
2564e7801d59Ssowmini 		break;
2565e7801d59Ssowmini 
2566e7801d59Ssowmini 	case AGGR_L_EXPIRED:
2567e7801d59Ssowmini 		(void) snprintf(buf, sizeof (buf), "%s",
2568e7801d59Ssowmini 		    (lstate->bit.expired ? "yes" : "no"));
2569e7801d59Ssowmini 		break;
2570e7801d59Ssowmini 	}
2571e7801d59Ssowmini 
2572e7801d59Ssowmini 	*stat = DLADM_STATUS_OK;
2573e7801d59Ssowmini 	return (buf);
2574e7801d59Ssowmini 
2575e7801d59Ssowmini err:
2576e7801d59Ssowmini 	*stat = status;
2577e7801d59Ssowmini 	buf[0] = '\0';
2578e7801d59Ssowmini 	return (buf);
2579e7801d59Ssowmini }
2580e7801d59Ssowmini 
2581d62bc4baSyz147064 static dladm_status_t
2582d62bc4baSyz147064 print_aggr_lacp(show_grp_state_t *state, const char *link,
2583e7801d59Ssowmini     dladm_aggr_grp_attr_t *ginfop)
2584d62bc4baSyz147064 {
2585d62bc4baSyz147064 	int		i;
2586d62bc4baSyz147064 	dladm_status_t	status;
2587e7801d59Ssowmini 	laggr_args_t	largs;
2588d62bc4baSyz147064 
2589e7801d59Ssowmini 	if (!state->gs_parseable && !state->gs_printheader) {
2590e7801d59Ssowmini 		print_header(&state->gs_print);
2591e7801d59Ssowmini 		state->gs_printheader = B_TRUE;
2592d62bc4baSyz147064 	}
2593d62bc4baSyz147064 
2594e7801d59Ssowmini 	largs.laggr_link = link;
2595e7801d59Ssowmini 	largs.laggr_ginfop = ginfop;
2596e7801d59Ssowmini 	largs.laggr_status = &status;
2597d62bc4baSyz147064 
2598e7801d59Ssowmini 	for (i = 0; i < ginfop->lg_nports; i++) {
2599e7801d59Ssowmini 		largs.laggr_lport = i;
2600e7801d59Ssowmini 		dladm_print_output(&state->gs_print, state->gs_parseable,
2601e7801d59Ssowmini 		    print_lacp_callback, &largs);
2602d62bc4baSyz147064 		if (status != DLADM_STATUS_OK)
2603d62bc4baSyz147064 			goto done;
2604d62bc4baSyz147064 	}
2605d62bc4baSyz147064 
2606d62bc4baSyz147064 	status = DLADM_STATUS_OK;
2607d62bc4baSyz147064 done:
2608d62bc4baSyz147064 	return (status);
2609d62bc4baSyz147064 }
2610d62bc4baSyz147064 
2611e7801d59Ssowmini static char *
2612e7801d59Ssowmini print_aggr_stats_callback(print_field_t *pf, void *arg)
2613e7801d59Ssowmini {
2614e7801d59Ssowmini 	const laggr_args_t	*l = arg;
2615e7801d59Ssowmini 	int 			portnum;
2616e7801d59Ssowmini 	static char		buf[DLADM_STRSIZE];
2617e7801d59Ssowmini 	boolean_t		is_port = (l->laggr_lport >= 0);
2618e7801d59Ssowmini 	dladm_aggr_port_attr_t	*portp;
2619e7801d59Ssowmini 	dladm_phys_attr_t	dpa;
2620e7801d59Ssowmini 	dladm_status_t		*stat, status;
2621e7801d59Ssowmini 	pktsum_t		port_stat, diff_stats;
2622e7801d59Ssowmini 
2623e7801d59Ssowmini 	stat = l->laggr_status;
2624e7801d59Ssowmini 	*stat = DLADM_STATUS_OK;
2625e7801d59Ssowmini 
2626e7801d59Ssowmini 	if (is_port) {
2627e7801d59Ssowmini 		portnum = l->laggr_lport;
2628e7801d59Ssowmini 		portp = &(l->laggr_ginfop->lg_ports[portnum]);
2629e7801d59Ssowmini 		if ((status = dladm_phys_info(portp->lp_linkid, &dpa,
2630e7801d59Ssowmini 		    DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) {
2631e7801d59Ssowmini 			goto err;
2632e7801d59Ssowmini 		}
2633e7801d59Ssowmini 
2634e7801d59Ssowmini 		get_mac_stats(dpa.dp_dev, &port_stat);
2635e7801d59Ssowmini 
2636e7801d59Ssowmini 		if ((status = dladm_datalink_id2info(portp->lp_linkid, NULL,
2637e7801d59Ssowmini 		    NULL, NULL, buf, sizeof (buf))) != DLADM_STATUS_OK) {
2638e7801d59Ssowmini 			goto err;
2639e7801d59Ssowmini 		}
2640e7801d59Ssowmini 
2641*da14cebeSEric Cheng 		dladm_stats_diff(&diff_stats, &port_stat, l->laggr_prevstats);
2642e7801d59Ssowmini 	}
2643e7801d59Ssowmini 
2644e7801d59Ssowmini 	switch (pf->pf_index) {
2645e7801d59Ssowmini 	case AGGR_S_LINK:
2646e7801d59Ssowmini 		(void) snprintf(buf, sizeof (buf), "%s",
2647e7801d59Ssowmini 		    (is_port ? "" : l->laggr_link));
2648e7801d59Ssowmini 		break;
2649e7801d59Ssowmini 	case AGGR_S_PORT:
2650e7801d59Ssowmini 		if (is_port)
2651e7801d59Ssowmini 			break;
26520d365605Sschuster 		return ("");
2653e7801d59Ssowmini 		break;
2654e7801d59Ssowmini 
2655e7801d59Ssowmini 	case AGGR_S_IPKTS:
2656e7801d59Ssowmini 		if (is_port) {
2657e7801d59Ssowmini 			(void) snprintf(buf, sizeof (buf), "%llu",
2658e7801d59Ssowmini 			    diff_stats.ipackets);
2659e7801d59Ssowmini 		} else {
2660e7801d59Ssowmini 			(void) snprintf(buf, sizeof (buf), "%llu",
2661e7801d59Ssowmini 			    l->laggr_pktsumtot->ipackets);
2662e7801d59Ssowmini 		}
2663e7801d59Ssowmini 		break;
2664e7801d59Ssowmini 
2665e7801d59Ssowmini 	case AGGR_S_RBYTES:
2666e7801d59Ssowmini 		if (is_port) {
2667e7801d59Ssowmini 			(void) snprintf(buf, sizeof (buf), "%llu",
2668e7801d59Ssowmini 			    diff_stats.rbytes);
2669e7801d59Ssowmini 		} else {
2670e7801d59Ssowmini 			(void) snprintf(buf, sizeof (buf), "%llu",
2671e7801d59Ssowmini 			    l->laggr_pktsumtot->rbytes);
2672e7801d59Ssowmini 		}
2673e7801d59Ssowmini 		break;
2674e7801d59Ssowmini 
2675e7801d59Ssowmini 	case AGGR_S_OPKTS:
2676e7801d59Ssowmini 		if (is_port) {
2677e7801d59Ssowmini 			(void) snprintf(buf, sizeof (buf), "%llu",
2678e7801d59Ssowmini 			    diff_stats.opackets);
2679e7801d59Ssowmini 		} else {
2680e7801d59Ssowmini 			(void) snprintf(buf, sizeof (buf), "%llu",
2681e7801d59Ssowmini 			    l->laggr_pktsumtot->opackets);
2682e7801d59Ssowmini 		}
2683e7801d59Ssowmini 		break;
2684e7801d59Ssowmini 	case AGGR_S_OBYTES:
2685e7801d59Ssowmini 		if (is_port) {
2686e7801d59Ssowmini 			(void) snprintf(buf, sizeof (buf), "%llu",
2687e7801d59Ssowmini 			    diff_stats.obytes);
2688e7801d59Ssowmini 		} else {
2689e7801d59Ssowmini 			(void) snprintf(buf, sizeof (buf), "%llu",
2690e7801d59Ssowmini 			    l->laggr_pktsumtot->obytes);
2691e7801d59Ssowmini 
2692e7801d59Ssowmini 		}
2693e7801d59Ssowmini 		break;
2694e7801d59Ssowmini 
2695e7801d59Ssowmini 	case AGGR_S_IPKTDIST:
2696e7801d59Ssowmini 		if (is_port) {
2697e7801d59Ssowmini 			(void) snprintf(buf, sizeof (buf), "%-6.1f",
2698e7801d59Ssowmini 			    (double)diff_stats.opackets/
2699e7801d59Ssowmini 			    (double)l->laggr_pktsumtot->ipackets * 100);
2700e7801d59Ssowmini 		} else {
27010d365605Sschuster 			return ("");
2702e7801d59Ssowmini 		}
2703e7801d59Ssowmini 		break;
2704e7801d59Ssowmini 	case AGGR_S_OPKTDIST:
2705e7801d59Ssowmini 		if (is_port) {
2706e7801d59Ssowmini 			(void) snprintf(buf, sizeof (buf), "%-6.1f",
2707e7801d59Ssowmini 			    (double)diff_stats.opackets/
2708e7801d59Ssowmini 			    (double)l->laggr_pktsumtot->opackets * 100);
2709e7801d59Ssowmini 		} else {
27100d365605Sschuster 			return ("");
2711e7801d59Ssowmini 		}
2712e7801d59Ssowmini 		break;
2713e7801d59Ssowmini 	}
2714e7801d59Ssowmini 	return (buf);
2715e7801d59Ssowmini 
2716e7801d59Ssowmini err:
2717e7801d59Ssowmini 	*stat = status;
2718e7801d59Ssowmini 	buf[0] = '\0';
2719e7801d59Ssowmini 	return (buf);
2720e7801d59Ssowmini }
2721e7801d59Ssowmini 
2722d62bc4baSyz147064 static dladm_status_t
2723d62bc4baSyz147064 print_aggr_stats(show_grp_state_t *state, const char *link,
2724e7801d59Ssowmini     dladm_aggr_grp_attr_t *ginfop)
2725d62bc4baSyz147064 {
2726d62bc4baSyz147064 	dladm_phys_attr_t	dpa;
2727d62bc4baSyz147064 	dladm_aggr_port_attr_t	*portp;
2728d62bc4baSyz147064 	pktsum_t		pktsumtot, port_stat;
2729d62bc4baSyz147064 	dladm_status_t		status;
2730d62bc4baSyz147064 	int			i;
2731e7801d59Ssowmini 	laggr_args_t		largs;
27327c478bd9Sstevel@tonic-gate 
27337c478bd9Sstevel@tonic-gate 	/* sum the ports statistics */
27347c478bd9Sstevel@tonic-gate 	bzero(&pktsumtot, sizeof (pktsumtot));
2735d62bc4baSyz147064 
2736d62bc4baSyz147064 	for (i = 0; i < ginfop->lg_nports; i++) {
2737d62bc4baSyz147064 
2738d62bc4baSyz147064 		portp = &(ginfop->lg_ports[i]);
2739d62bc4baSyz147064 		if ((status = dladm_phys_info(portp->lp_linkid, &dpa,
2740d62bc4baSyz147064 		    DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) {
2741d62bc4baSyz147064 			goto done;
27427c478bd9Sstevel@tonic-gate 		}
27437c478bd9Sstevel@tonic-gate 
2744d62bc4baSyz147064 		get_mac_stats(dpa.dp_dev, &port_stat);
2745*da14cebeSEric Cheng 		dladm_stats_total(&pktsumtot, &port_stat,
2746*da14cebeSEric Cheng 		    &state->gs_prevstats[i]);
27477c478bd9Sstevel@tonic-gate 	}
27487c478bd9Sstevel@tonic-gate 
2749e7801d59Ssowmini 	if (!state->gs_parseable && !state->gs_printheader) {
2750e7801d59Ssowmini 		print_header(&state->gs_print);
2751e7801d59Ssowmini 		state->gs_printheader = B_TRUE;
2752e7801d59Ssowmini 	}
2753e7801d59Ssowmini 
2754e7801d59Ssowmini 	largs.laggr_lport = -1;
2755e7801d59Ssowmini 	largs.laggr_link = link;
2756e7801d59Ssowmini 	largs.laggr_ginfop = ginfop;
2757e7801d59Ssowmini 	largs.laggr_status = &status;
2758e7801d59Ssowmini 	largs.laggr_pktsumtot = &pktsumtot;
2759e7801d59Ssowmini 
2760e7801d59Ssowmini 	dladm_print_output(&state->gs_print, state->gs_parseable,
2761e7801d59Ssowmini 	    print_aggr_stats_callback, &largs);
2762e7801d59Ssowmini 
2763e7801d59Ssowmini 	if (status != DLADM_STATUS_OK)
2764e7801d59Ssowmini 		goto done;
2765d62bc4baSyz147064 
2766d62bc4baSyz147064 	for (i = 0; i < ginfop->lg_nports; i++) {
2767e7801d59Ssowmini 		largs.laggr_lport = i;
2768e7801d59Ssowmini 		largs.laggr_prevstats = &state->gs_prevstats[i];
2769e7801d59Ssowmini 		dladm_print_output(&state->gs_print, state->gs_parseable,
2770e7801d59Ssowmini 		    print_aggr_stats_callback, &largs);
2771e7801d59Ssowmini 		if (status != DLADM_STATUS_OK)
2772d62bc4baSyz147064 			goto done;
2773d62bc4baSyz147064 	}
2774d62bc4baSyz147064 
2775d62bc4baSyz147064 	status = DLADM_STATUS_OK;
2776d62bc4baSyz147064 done:
2777d62bc4baSyz147064 	return (status);
2778d62bc4baSyz147064 }
2779d62bc4baSyz147064 
2780d62bc4baSyz147064 static dladm_status_t
2781e7801d59Ssowmini print_aggr(show_grp_state_t *state, datalink_id_t linkid)
2782d62bc4baSyz147064 {
2783d62bc4baSyz147064 	char			link[MAXLINKNAMELEN];
2784d62bc4baSyz147064 	dladm_aggr_grp_attr_t	ginfo;
2785d62bc4baSyz147064 	uint32_t		flags;
2786d62bc4baSyz147064 	dladm_status_t		status;
2787d62bc4baSyz147064 
27885f5c9f54SAnurag S. Maskey 	bzero(&ginfo, sizeof (dladm_aggr_grp_attr_t));
2789d62bc4baSyz147064 	if ((status = dladm_datalink_id2info(linkid, &flags, NULL, NULL, link,
2790e7801d59Ssowmini 	    MAXLINKNAMELEN)) != DLADM_STATUS_OK) {
2791d62bc4baSyz147064 		return (status);
2792d62bc4baSyz147064 	}
2793d62bc4baSyz147064 
2794d62bc4baSyz147064 	if (!(state->gs_flags & flags))
2795d62bc4baSyz147064 		return (DLADM_STATUS_NOTFOUND);
2796d62bc4baSyz147064 
2797d62bc4baSyz147064 	status = dladm_aggr_info(linkid, &ginfo, state->gs_flags);
2798d62bc4baSyz147064 	if (status != DLADM_STATUS_OK)
2799d62bc4baSyz147064 		return (status);
2800d62bc4baSyz147064 
2801d62bc4baSyz147064 	if (state->gs_lacp)
2802e7801d59Ssowmini 		status = print_aggr_lacp(state, link, &ginfo);
2803d62bc4baSyz147064 	else if (state->gs_extended)
2804e7801d59Ssowmini 		status = print_aggr_extended(state, link, &ginfo);
2805d62bc4baSyz147064 	else if (state->gs_stats)
2806e7801d59Ssowmini 		status = print_aggr_stats(state, link, &ginfo);
2807e7801d59Ssowmini 	else {
2808e7801d59Ssowmini 		status = print_aggr_info(state, link, &ginfo);
2809e7801d59Ssowmini 	}
2810d62bc4baSyz147064 
2811d62bc4baSyz147064 done:
2812d62bc4baSyz147064 	free(ginfo.lg_ports);
2813d62bc4baSyz147064 	return (status);
2814d62bc4baSyz147064 }
2815d62bc4baSyz147064 
2816d62bc4baSyz147064 static int
2817d62bc4baSyz147064 show_aggr(datalink_id_t linkid, void *arg)
2818d62bc4baSyz147064 {
2819d62bc4baSyz147064 	show_grp_state_t	*state = arg;
2820d62bc4baSyz147064 	dladm_status_t		status;
2821d62bc4baSyz147064 
2822e7801d59Ssowmini 	status = print_aggr(state, linkid);
2823d62bc4baSyz147064 	if (status != DLADM_STATUS_OK)
2824d62bc4baSyz147064 		goto done;
2825d62bc4baSyz147064 
2826d62bc4baSyz147064 done:
2827d62bc4baSyz147064 	state->gs_status = status;
2828d62bc4baSyz147064 	return (DLADM_WALK_CONTINUE);
28297c478bd9Sstevel@tonic-gate }
28307c478bd9Sstevel@tonic-gate 
28317c478bd9Sstevel@tonic-gate static void
28328d5c46e6Sam223141 do_show_link(int argc, char *argv[], const char *use)
28337c478bd9Sstevel@tonic-gate {
28347c478bd9Sstevel@tonic-gate 	int		option;
28357c478bd9Sstevel@tonic-gate 	boolean_t	s_arg = B_FALSE;
2836*da14cebeSEric Cheng 	boolean_t	S_arg = B_FALSE;
28377c478bd9Sstevel@tonic-gate 	boolean_t	i_arg = B_FALSE;
2838d62bc4baSyz147064 	uint32_t	flags = DLADM_OPT_ACTIVE;
2839d62bc4baSyz147064 	boolean_t	p_arg = B_FALSE;
2840d62bc4baSyz147064 	datalink_id_t	linkid = DATALINK_ALL_LINKID;
2841*da14cebeSEric Cheng 	char		linkname[MAXLINKNAMELEN];
284233343a97Smeem 	int		interval = 0;
2843d62bc4baSyz147064 	show_state_t	state;
2844d62bc4baSyz147064 	dladm_status_t	status;
2845e7801d59Ssowmini 	boolean_t	o_arg = B_FALSE;
2846e7801d59Ssowmini 	char		*fields_str = NULL;
2847e7801d59Ssowmini 	print_field_t	**fields;
2848e7801d59Ssowmini 	uint_t		nfields;
2849e7801d59Ssowmini 	char		*all_active_fields = "link,class,mtu,state,over";
2850e7801d59Ssowmini 	char		*all_inactive_fields = "link,class,over";
28516be03d0bSVasumathi Sundaram - Sun Microsystems 	char		*allstat_fields =
28526be03d0bSVasumathi Sundaram - Sun Microsystems 	    "link,ipackets,rbytes,ierrors,opackets,obytes,oerrors";
2853e7801d59Ssowmini 
2854e7801d59Ssowmini 	bzero(&state, sizeof (state));
28557c478bd9Sstevel@tonic-gate 
28567c478bd9Sstevel@tonic-gate 	opterr = 0;
2857*da14cebeSEric Cheng 	while ((option = getopt_long(argc, argv, ":pPsSi:o:",
2858d62bc4baSyz147064 	    show_lopts, NULL)) != -1) {
28597c478bd9Sstevel@tonic-gate 		switch (option) {
28607c478bd9Sstevel@tonic-gate 		case 'p':
2861d62bc4baSyz147064 			if (p_arg)
2862d62bc4baSyz147064 				die_optdup(option);
2863d62bc4baSyz147064 
2864d62bc4baSyz147064 			p_arg = B_TRUE;
28657c478bd9Sstevel@tonic-gate 			break;
28667c478bd9Sstevel@tonic-gate 		case 's':
286733343a97Smeem 			if (s_arg)
286833343a97Smeem 				die_optdup(option);
28697c478bd9Sstevel@tonic-gate 
28707c478bd9Sstevel@tonic-gate 			s_arg = B_TRUE;
28717c478bd9Sstevel@tonic-gate 			break;
2872d62bc4baSyz147064 		case 'P':
2873d62bc4baSyz147064 			if (flags != DLADM_OPT_ACTIVE)
2874d62bc4baSyz147064 				die_optdup(option);
2875d62bc4baSyz147064 
2876d62bc4baSyz147064 			flags = DLADM_OPT_PERSIST;
2877d62bc4baSyz147064 			break;
2878*da14cebeSEric Cheng 		case 'S':
2879*da14cebeSEric Cheng 			if (S_arg)
2880*da14cebeSEric Cheng 				die_optdup(option);
2881*da14cebeSEric Cheng 
2882*da14cebeSEric Cheng 			S_arg = B_TRUE;
2883*da14cebeSEric Cheng 			break;
2884e7801d59Ssowmini 		case 'o':
2885e7801d59Ssowmini 			o_arg = B_TRUE;
2886e7801d59Ssowmini 			fields_str = optarg;
2887e7801d59Ssowmini 			break;
28887c478bd9Sstevel@tonic-gate 		case 'i':
288933343a97Smeem 			if (i_arg)
289033343a97Smeem 				die_optdup(option);
28917c478bd9Sstevel@tonic-gate 
28927c478bd9Sstevel@tonic-gate 			i_arg = B_TRUE;
289333343a97Smeem 			if (!str2int(optarg, &interval) || interval == 0)
289433343a97Smeem 				die("invalid interval value '%s'", optarg);
28957c478bd9Sstevel@tonic-gate 			break;
28967c478bd9Sstevel@tonic-gate 		default:
28978d5c46e6Sam223141 			die_opterr(optopt, option, use);
289833343a97Smeem 			break;
28997c478bd9Sstevel@tonic-gate 		}
29007c478bd9Sstevel@tonic-gate 	}
29017c478bd9Sstevel@tonic-gate 
2902*da14cebeSEric Cheng 	if (i_arg && !(s_arg || S_arg))
2903*da14cebeSEric Cheng 		die("the option -i can be used only with -s or -S");
2904*da14cebeSEric Cheng 
2905*da14cebeSEric Cheng 	if (s_arg && S_arg)
2906*da14cebeSEric Cheng 		die("the -s option cannot be used with -S");
29077c478bd9Sstevel@tonic-gate 
29086be03d0bSVasumathi Sundaram - Sun Microsystems 	if (s_arg && flags != DLADM_OPT_ACTIVE)
29096be03d0bSVasumathi Sundaram - Sun Microsystems 		die("the option -P cannot be used with -s");
2910d62bc4baSyz147064 
2911*da14cebeSEric Cheng 	if (S_arg && (p_arg || flags != DLADM_OPT_ACTIVE))
2912*da14cebeSEric Cheng 		die("the option -%c cannot be used with -S", p_arg ? 'p' : 'P');
2913*da14cebeSEric Cheng 
29147c478bd9Sstevel@tonic-gate 	/* get link name (optional last argument) */
2915d62bc4baSyz147064 	if (optind == (argc-1)) {
2916d62bc4baSyz147064 		uint32_t	f;
2917d62bc4baSyz147064 
2918*da14cebeSEric Cheng 		if (strlcpy(linkname, argv[optind], MAXLINKNAMELEN)
2919*da14cebeSEric Cheng 		    >= MAXLINKNAMELEN) {
2920*da14cebeSEric Cheng 			(void) fprintf(stderr,
2921*da14cebeSEric Cheng 			    gettext("%s: link name too long\n"),
2922*da14cebeSEric Cheng 			    progname);
2923*da14cebeSEric Cheng 			exit(1);
2924*da14cebeSEric Cheng 		}
2925*da14cebeSEric Cheng 		if ((status = dladm_name2info(linkname, &linkid, &f,
2926d62bc4baSyz147064 		    NULL, NULL)) != DLADM_STATUS_OK) {
2927*da14cebeSEric Cheng 			die_dlerr(status, "link %s is not valid", linkname);
2928d62bc4baSyz147064 		}
2929d62bc4baSyz147064 
2930d62bc4baSyz147064 		if (!(f & flags)) {
2931d62bc4baSyz147064 			die_dlerr(DLADM_STATUS_BADARG, "link %s is %s",
2932d62bc4baSyz147064 			    argv[optind], flags == DLADM_OPT_PERSIST ?
2933d62bc4baSyz147064 			    "a temporary link" : "temporarily removed");
2934d62bc4baSyz147064 		}
2935d62bc4baSyz147064 	} else if (optind != argc) {
29367c478bd9Sstevel@tonic-gate 		usage();
2937d62bc4baSyz147064 	}
29387c478bd9Sstevel@tonic-gate 
29390d365605Sschuster 	if (p_arg && !o_arg)
29400d365605Sschuster 		die("-p requires -o");
29410d365605Sschuster 
2942*da14cebeSEric Cheng 	if (S_arg) {
2943*da14cebeSEric Cheng 		dladm_continuous(linkid, NULL, interval, LINK_REPORT);
2944*da14cebeSEric Cheng 		return;
2945*da14cebeSEric Cheng 	}
2946*da14cebeSEric Cheng 
29470d365605Sschuster 	if (p_arg && strcasecmp(fields_str, "all") == 0)
29480d365605Sschuster 		die("\"-o all\" is invalid with -p");
29490d365605Sschuster 
2950e7801d59Ssowmini 	if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) {
29516be03d0bSVasumathi Sundaram - Sun Microsystems 		if (s_arg)
29526be03d0bSVasumathi Sundaram - Sun Microsystems 			fields_str = allstat_fields;
29536be03d0bSVasumathi Sundaram - Sun Microsystems 		else if (flags & DLADM_OPT_ACTIVE)
2954e7801d59Ssowmini 			fields_str = all_active_fields;
2955e7801d59Ssowmini 		else
2956e7801d59Ssowmini 			fields_str = all_inactive_fields;
2957e7801d59Ssowmini 	}
2958e7801d59Ssowmini 
29596be03d0bSVasumathi Sundaram - Sun Microsystems 	state.ls_parseable = p_arg;
29606be03d0bSVasumathi Sundaram - Sun Microsystems 	state.ls_flags = flags;
29616be03d0bSVasumathi Sundaram - Sun Microsystems 	state.ls_donefirst = B_FALSE;
29626be03d0bSVasumathi Sundaram - Sun Microsystems 
29636be03d0bSVasumathi Sundaram - Sun Microsystems 	if (s_arg) {
29646be03d0bSVasumathi Sundaram - Sun Microsystems 		link_stats(linkid, interval, fields_str, &state);
29656be03d0bSVasumathi Sundaram - Sun Microsystems 		return;
29666be03d0bSVasumathi Sundaram - Sun Microsystems 	}
29676be03d0bSVasumathi Sundaram - Sun Microsystems 
2968e7801d59Ssowmini 	fields = parse_output_fields(fields_str, link_fields, DEV_LINK_FIELDS,
2969e7801d59Ssowmini 	    CMD_TYPE_ANY, &nfields);
2970e7801d59Ssowmini 
29710d365605Sschuster 	if (fields == NULL)
2972e7801d59Ssowmini 		die("invalid field(s) specified");
2973e7801d59Ssowmini 
2974e7801d59Ssowmini 	state.ls_print.ps_fields = fields;
2975e7801d59Ssowmini 	state.ls_print.ps_nfields = nfields;
2976e7801d59Ssowmini 
2977d62bc4baSyz147064 	if (linkid == DATALINK_ALL_LINKID) {
2978d62bc4baSyz147064 		(void) dladm_walk_datalink_id(show_link, &state,
2979d62bc4baSyz147064 		    DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE, flags);
2980210db224Sericheng 	} else {
2981d62bc4baSyz147064 		(void) show_link(linkid, &state);
2982d62bc4baSyz147064 		if (state.ls_status != DLADM_STATUS_OK) {
2983d62bc4baSyz147064 			die_dlerr(state.ls_status, "failed to show link %s",
2984d62bc4baSyz147064 			    argv[optind]);
2985d62bc4baSyz147064 		}
29867c478bd9Sstevel@tonic-gate 	}
2987210db224Sericheng }
29887c478bd9Sstevel@tonic-gate 
29897c478bd9Sstevel@tonic-gate static void
29908d5c46e6Sam223141 do_show_aggr(int argc, char *argv[], const char *use)
29917c478bd9Sstevel@tonic-gate {
29927c478bd9Sstevel@tonic-gate 	boolean_t		L_arg = B_FALSE;
29937c478bd9Sstevel@tonic-gate 	boolean_t		s_arg = B_FALSE;
29947c478bd9Sstevel@tonic-gate 	boolean_t		i_arg = B_FALSE;
2995d62bc4baSyz147064 	boolean_t		p_arg = B_FALSE;
2996d62bc4baSyz147064 	boolean_t		x_arg = B_FALSE;
29977c478bd9Sstevel@tonic-gate 	show_grp_state_t	state;
2998d62bc4baSyz147064 	uint32_t		flags = DLADM_OPT_ACTIVE;
2999d62bc4baSyz147064 	datalink_id_t		linkid = DATALINK_ALL_LINKID;
3000d62bc4baSyz147064 	int			option;
300133343a97Smeem 	int			interval = 0;
3002d62bc4baSyz147064 	int			key;
3003d62bc4baSyz147064 	dladm_status_t		status;
3004e7801d59Ssowmini 	boolean_t		o_arg = B_FALSE;
3005e7801d59Ssowmini 	char			*fields_str = NULL;
3006e7801d59Ssowmini 	print_field_t		**fields;
3007e7801d59Ssowmini 	uint_t			nfields;
3008e7801d59Ssowmini 	char			*all_fields =
3009e7801d59Ssowmini 	    "link,policy,addrpolicy,lacpactivity,lacptimer,flags";
3010e7801d59Ssowmini 	char			*all_lacp_fields =
3011e7801d59Ssowmini 	    "link,port,aggregatable,sync,coll,dist,defaulted,expired";
3012e7801d59Ssowmini 	char			*all_stats_fields =
3013e7801d59Ssowmini 	    "link,port,ipackets,rbytes,opackets,obytes,ipktdist,opktdist";
3014e7801d59Ssowmini 	char			*all_extended_fields =
3015e7801d59Ssowmini 	    "link,port,speed,duplex,state,address,portstate";
3016e7801d59Ssowmini 	print_field_t		*pf;
3017e7801d59Ssowmini 	int			pfmax;
3018e7801d59Ssowmini 
3019e7801d59Ssowmini 	bzero(&state, sizeof (state));
30207c478bd9Sstevel@tonic-gate 
30217c478bd9Sstevel@tonic-gate 	opterr = 0;
3022e7801d59Ssowmini 	while ((option = getopt_long(argc, argv, ":LpPxsi:o:",
3023d62bc4baSyz147064 	    show_lopts, NULL)) != -1) {
30247c478bd9Sstevel@tonic-gate 		switch (option) {
30257c478bd9Sstevel@tonic-gate 		case 'L':
302633343a97Smeem 			if (L_arg)
302733343a97Smeem 				die_optdup(option);
30287c478bd9Sstevel@tonic-gate 
30297c478bd9Sstevel@tonic-gate 			L_arg = B_TRUE;
30307c478bd9Sstevel@tonic-gate 			break;
30317c478bd9Sstevel@tonic-gate 		case 'p':
3032d62bc4baSyz147064 			if (p_arg)
3033d62bc4baSyz147064 				die_optdup(option);
3034d62bc4baSyz147064 
3035d62bc4baSyz147064 			p_arg = B_TRUE;
3036d62bc4baSyz147064 			break;
3037d62bc4baSyz147064 		case 'x':
3038d62bc4baSyz147064 			if (x_arg)
3039d62bc4baSyz147064 				die_optdup(option);
3040d62bc4baSyz147064 
3041d62bc4baSyz147064 			x_arg = B_TRUE;
3042d62bc4baSyz147064 			break;
3043d62bc4baSyz147064 		case 'P':
3044d62bc4baSyz147064 			if (flags != DLADM_OPT_ACTIVE)
3045d62bc4baSyz147064 				die_optdup(option);
3046d62bc4baSyz147064 
3047d62bc4baSyz147064 			flags = DLADM_OPT_PERSIST;
30487c478bd9Sstevel@tonic-gate 			break;
30497c478bd9Sstevel@tonic-gate 		case 's':
305033343a97Smeem 			if (s_arg)
305133343a97Smeem 				die_optdup(option);
30527c478bd9Sstevel@tonic-gate 
30537c478bd9Sstevel@tonic-gate 			s_arg = B_TRUE;
30547c478bd9Sstevel@tonic-gate 			break;
3055e7801d59Ssowmini 		case 'o':
3056e7801d59Ssowmini 			o_arg = B_TRUE;
3057e7801d59Ssowmini 			fields_str = optarg;
3058e7801d59Ssowmini 			break;
30597c478bd9Sstevel@tonic-gate 		case 'i':
306033343a97Smeem 			if (i_arg)
306133343a97Smeem 				die_optdup(option);
30627c478bd9Sstevel@tonic-gate 
30637c478bd9Sstevel@tonic-gate 			i_arg = B_TRUE;
306433343a97Smeem 			if (!str2int(optarg, &interval) || interval == 0)
306533343a97Smeem 				die("invalid interval value '%s'", optarg);
30667c478bd9Sstevel@tonic-gate 			break;
30677c478bd9Sstevel@tonic-gate 		default:
30688d5c46e6Sam223141 			die_opterr(optopt, option, use);
306933343a97Smeem 			break;
30707c478bd9Sstevel@tonic-gate 		}
30717c478bd9Sstevel@tonic-gate 	}
30727c478bd9Sstevel@tonic-gate 
30730d365605Sschuster 	if (p_arg && !o_arg)
30740d365605Sschuster 		die("-p requires -o");
30750d365605Sschuster 
30760d365605Sschuster 	if (p_arg && strcasecmp(fields_str, "all") == 0)
30770d365605Sschuster 		die("\"-o all\" is invalid with -p");
30780d365605Sschuster 
307933343a97Smeem 	if (i_arg && !s_arg)
308033343a97Smeem 		die("the option -i can be used only with -s");
30817c478bd9Sstevel@tonic-gate 
3082d62bc4baSyz147064 	if (s_arg && (L_arg || p_arg || x_arg || flags != DLADM_OPT_ACTIVE)) {
3083d62bc4baSyz147064 		die("the option -%c cannot be used with -s",
3084d62bc4baSyz147064 		    L_arg ? 'L' : (p_arg ? 'p' : (x_arg ? 'x' : 'P')));
3085d62bc4baSyz147064 	}
3086d62bc4baSyz147064 
3087d62bc4baSyz147064 	if (L_arg && flags != DLADM_OPT_ACTIVE)
3088d62bc4baSyz147064 		die("the option -P cannot be used with -L");
3089d62bc4baSyz147064 
3090d62bc4baSyz147064 	if (x_arg && (L_arg || flags != DLADM_OPT_ACTIVE))
3091d62bc4baSyz147064 		die("the option -%c cannot be used with -x", L_arg ? 'L' : 'P');
3092d62bc4baSyz147064 
3093d62bc4baSyz147064 	/* get aggregation key or aggrname (optional last argument) */
30947c478bd9Sstevel@tonic-gate 	if (optind == (argc-1)) {
3095d62bc4baSyz147064 		if (!str2int(argv[optind], &key)) {
3096d62bc4baSyz147064 			status = dladm_name2info(argv[optind], &linkid, NULL,
3097d62bc4baSyz147064 			    NULL, NULL);
3098d62bc4baSyz147064 		} else {
3099d62bc4baSyz147064 			status = dladm_key2linkid((uint16_t)key,
3100d62bc4baSyz147064 			    &linkid, DLADM_OPT_ACTIVE);
3101d62bc4baSyz147064 		}
3102d62bc4baSyz147064 
3103d62bc4baSyz147064 		if (status != DLADM_STATUS_OK)
3104d62bc4baSyz147064 			die("non-existent aggregation '%s'", argv[optind]);
3105d62bc4baSyz147064 
31067c478bd9Sstevel@tonic-gate 	} else if (optind != argc) {
31077c478bd9Sstevel@tonic-gate 		usage();
31087c478bd9Sstevel@tonic-gate 	}
31097c478bd9Sstevel@tonic-gate 
3110d62bc4baSyz147064 	bzero(&state, sizeof (state));
3111d62bc4baSyz147064 	state.gs_lacp = L_arg;
3112d62bc4baSyz147064 	state.gs_stats = s_arg;
3113d62bc4baSyz147064 	state.gs_flags = flags;
3114d62bc4baSyz147064 	state.gs_parseable = p_arg;
3115d62bc4baSyz147064 	state.gs_extended = x_arg;
3116d62bc4baSyz147064 
3117e7801d59Ssowmini 	if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) {
3118e7801d59Ssowmini 		if (state.gs_lacp)
3119e7801d59Ssowmini 			fields_str = all_lacp_fields;
3120e7801d59Ssowmini 		else if (state.gs_stats)
3121e7801d59Ssowmini 			fields_str = all_stats_fields;
3122e7801d59Ssowmini 		else if (state.gs_extended)
3123e7801d59Ssowmini 			fields_str = all_extended_fields;
3124e7801d59Ssowmini 		else
3125e7801d59Ssowmini 			fields_str = all_fields;
3126e7801d59Ssowmini 	}
3127e7801d59Ssowmini 
3128e7801d59Ssowmini 	if (state.gs_lacp) {
3129e7801d59Ssowmini 		pf = aggr_l_fields;
3130e7801d59Ssowmini 		pfmax = AGGR_L_MAX_FIELDS;
3131e7801d59Ssowmini 	} else if (state.gs_stats) {
3132e7801d59Ssowmini 		pf = aggr_s_fields;
3133e7801d59Ssowmini 		pfmax = AGGR_S_MAX_FIELDS;
3134e7801d59Ssowmini 	} else if (state.gs_extended) {
3135e7801d59Ssowmini 		pf = aggr_x_fields;
3136e7801d59Ssowmini 		pfmax = AGGR_X_MAX_FIELDS;
3137e7801d59Ssowmini 	} else {
3138e7801d59Ssowmini 		pf = laggr_fields;
3139e7801d59Ssowmini 		pfmax = LAGGR_MAX_FIELDS;
3140e7801d59Ssowmini 	}
3141e7801d59Ssowmini 	fields = parse_output_fields(fields_str, pf, pfmax, CMD_TYPE_ANY,
3142e7801d59Ssowmini 	    &nfields);
3143e7801d59Ssowmini 
3144e7801d59Ssowmini 	if (fields == NULL) {
3145e7801d59Ssowmini 		die("invalid field(s) specified");
3146e7801d59Ssowmini 		return;
3147e7801d59Ssowmini 	}
3148e7801d59Ssowmini 
3149e7801d59Ssowmini 	state.gs_print.ps_fields = fields;
3150e7801d59Ssowmini 	state.gs_print.ps_nfields = nfields;
3151e7801d59Ssowmini 
31527c478bd9Sstevel@tonic-gate 	if (s_arg) {
3153d62bc4baSyz147064 		aggr_stats(linkid, &state, interval);
31547c478bd9Sstevel@tonic-gate 		return;
31557c478bd9Sstevel@tonic-gate 	}
31567c478bd9Sstevel@tonic-gate 
3157d62bc4baSyz147064 	if (linkid == DATALINK_ALL_LINKID) {
3158d62bc4baSyz147064 		(void) dladm_walk_datalink_id(show_aggr, &state,
3159d62bc4baSyz147064 		    DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE, flags);
3160d62bc4baSyz147064 	} else {
3161d62bc4baSyz147064 		(void) show_aggr(linkid, &state);
3162d62bc4baSyz147064 		if (state.gs_status != DLADM_STATUS_OK) {
3163d62bc4baSyz147064 			die_dlerr(state.gs_status, "failed to show aggr %s",
3164d62bc4baSyz147064 			    argv[optind]);
3165d62bc4baSyz147064 		}
3166d62bc4baSyz147064 	}
31677c478bd9Sstevel@tonic-gate }
31687c478bd9Sstevel@tonic-gate 
3169*da14cebeSEric Cheng static dladm_status_t
3170*da14cebeSEric Cheng print_phys_default(show_state_t *state, datalink_id_t linkid,
3171*da14cebeSEric Cheng     const char *link, uint32_t flags, uint32_t media)
31727c478bd9Sstevel@tonic-gate {
3173*da14cebeSEric Cheng 	dladm_phys_attr_t dpa;
3174*da14cebeSEric Cheng 	dladm_status_t status;
3175*da14cebeSEric Cheng 	link_fields_buf_t pattr;
3176e7801d59Ssowmini 
3177*da14cebeSEric Cheng 	status = dladm_phys_info(linkid, &dpa, state->ls_flags);
3178*da14cebeSEric Cheng 	if (status != DLADM_STATUS_OK)
3179*da14cebeSEric Cheng 		goto done;
31807c478bd9Sstevel@tonic-gate 
3181*da14cebeSEric Cheng 	(void) snprintf(pattr.link_phys_device,
3182*da14cebeSEric Cheng 	    sizeof (pattr.link_phys_device), "%s", dpa.dp_dev);
3183*da14cebeSEric Cheng 	(void) dladm_media2str(media, pattr.link_phys_media);
3184*da14cebeSEric Cheng 	if (state->ls_flags == DLADM_OPT_ACTIVE) {
3185*da14cebeSEric Cheng 		boolean_t	islink;
3186d62bc4baSyz147064 
3187*da14cebeSEric Cheng 		if (!dpa.dp_novanity) {
3188*da14cebeSEric Cheng 			(void) strlcpy(pattr.link_name, link,
3189*da14cebeSEric Cheng 			    sizeof (pattr.link_name));
3190*da14cebeSEric Cheng 			islink = B_TRUE;
3191d62bc4baSyz147064 		} else {
3192*da14cebeSEric Cheng 			/*
3193*da14cebeSEric Cheng 			 * This is a physical link that does not have
3194*da14cebeSEric Cheng 			 * vanity naming support.
3195*da14cebeSEric Cheng 			 */
3196*da14cebeSEric Cheng 			(void) strlcpy(pattr.link_name, dpa.dp_dev,
3197*da14cebeSEric Cheng 			    sizeof (pattr.link_name));
3198*da14cebeSEric Cheng 			islink = B_FALSE;
31997c478bd9Sstevel@tonic-gate 		}
32007c478bd9Sstevel@tonic-gate 
3201*da14cebeSEric Cheng 		(void) get_linkstate(pattr.link_name, islink,
3202*da14cebeSEric Cheng 		    pattr.link_phys_state);
3203*da14cebeSEric Cheng 		(void) snprintf(pattr.link_phys_speed,
3204*da14cebeSEric Cheng 		    sizeof (pattr.link_phys_speed), "%u",
3205*da14cebeSEric Cheng 		    (uint_t)((get_ifspeed(pattr.link_name,
3206*da14cebeSEric Cheng 		    islink)) / 1000000ull));
3207*da14cebeSEric Cheng 		(void) get_linkduplex(pattr.link_name, islink,
3208*da14cebeSEric Cheng 		    pattr.link_phys_duplex);
3209*da14cebeSEric Cheng 	} else {
3210*da14cebeSEric Cheng 		(void) snprintf(pattr.link_name, sizeof (pattr.link_name),
3211*da14cebeSEric Cheng 		    "%s", link);
3212*da14cebeSEric Cheng 		(void) snprintf(pattr.link_flags, sizeof (pattr.link_flags),
3213*da14cebeSEric Cheng 		    "%c----", flags & DLADM_OPT_ACTIVE ? '-' : 'r');
3214*da14cebeSEric Cheng 	}
3215*da14cebeSEric Cheng 
3216*da14cebeSEric Cheng 	if (!state->ls_parseable && !state->ls_printheader) {
3217*da14cebeSEric Cheng 		print_header(&state->ls_print);
3218*da14cebeSEric Cheng 		state->ls_printheader = B_TRUE;
3219*da14cebeSEric Cheng 	}
3220*da14cebeSEric Cheng 
3221*da14cebeSEric Cheng 	dladm_print_output(&state->ls_print, state->ls_parseable,
3222*da14cebeSEric Cheng 	    dladm_print_field, (void *)&pattr);
3223*da14cebeSEric Cheng 
3224*da14cebeSEric Cheng done:
3225*da14cebeSEric Cheng 	return (status);
3226*da14cebeSEric Cheng }
3227*da14cebeSEric Cheng 
3228*da14cebeSEric Cheng typedef struct {
3229*da14cebeSEric Cheng 	show_state_t	*ms_state;
3230*da14cebeSEric Cheng 	char		*ms_link;
3231*da14cebeSEric Cheng 	dladm_macaddr_attr_t *ms_mac_attr;
3232*da14cebeSEric Cheng } print_phys_mac_state_t;
3233*da14cebeSEric Cheng 
3234*da14cebeSEric Cheng /* callback of dladm_print_output() */
3235*da14cebeSEric Cheng static char *
3236*da14cebeSEric Cheng print_phys_one_mac_callback(print_field_t *pf, void *arg)
3237*da14cebeSEric Cheng {
3238*da14cebeSEric Cheng 	print_phys_mac_state_t *mac_state = arg;
3239*da14cebeSEric Cheng 	dladm_macaddr_attr_t *attr = mac_state->ms_mac_attr;
3240*da14cebeSEric Cheng 	static char buf[DLADM_STRSIZE];
3241*da14cebeSEric Cheng 	boolean_t is_primary = (attr->ma_slot == 0);
3242*da14cebeSEric Cheng 	boolean_t is_parseable = mac_state->ms_state->ls_parseable;
3243*da14cebeSEric Cheng 
3244*da14cebeSEric Cheng 	switch (pf->pf_index) {
3245*da14cebeSEric Cheng 	case PHYS_M_LINK:
3246*da14cebeSEric Cheng 		(void) snprintf(buf, sizeof (buf), "%s",
3247*da14cebeSEric Cheng 		    (is_primary || is_parseable) ? mac_state->ms_link : " ");
3248*da14cebeSEric Cheng 		break;
3249*da14cebeSEric Cheng 	case PHYS_M_SLOT:
3250*da14cebeSEric Cheng 		if (is_primary)
3251*da14cebeSEric Cheng 			(void) snprintf(buf, sizeof (buf), gettext("primary"));
3252*da14cebeSEric Cheng 		else
3253*da14cebeSEric Cheng 			(void) snprintf(buf, sizeof (buf), "%d", attr->ma_slot);
3254*da14cebeSEric Cheng 		break;
3255*da14cebeSEric Cheng 	case PHYS_M_ADDRESS:
3256*da14cebeSEric Cheng 		(void) dladm_aggr_macaddr2str(attr->ma_addr, buf);
3257*da14cebeSEric Cheng 		break;
3258*da14cebeSEric Cheng 	case PHYS_M_INUSE:
3259*da14cebeSEric Cheng 		(void) snprintf(buf, sizeof (buf), "%s",
3260*da14cebeSEric Cheng 		    attr->ma_flags & DLADM_MACADDR_USED ? gettext("yes") :
3261*da14cebeSEric Cheng 		    gettext("no"));
3262*da14cebeSEric Cheng 		break;
3263*da14cebeSEric Cheng 	case PHYS_M_CLIENT:
3264*da14cebeSEric Cheng 		/*
3265*da14cebeSEric Cheng 		 * CR 6678526: resolve link id to actual link name if
3266*da14cebeSEric Cheng 		 * it is valid.
3267*da14cebeSEric Cheng 		 */
3268*da14cebeSEric Cheng 		(void) snprintf(buf, sizeof (buf), "%s", attr->ma_client_name);
3269*da14cebeSEric Cheng 		break;
3270*da14cebeSEric Cheng 	}
3271*da14cebeSEric Cheng 
3272*da14cebeSEric Cheng 	return (buf);
3273*da14cebeSEric Cheng }
3274*da14cebeSEric Cheng 
3275*da14cebeSEric Cheng typedef struct {
3276*da14cebeSEric Cheng 	show_state_t	*hs_state;
3277*da14cebeSEric Cheng 	char		*hs_link;
3278*da14cebeSEric Cheng 	dladm_hwgrp_attr_t *hs_grp_attr;
3279*da14cebeSEric Cheng } print_phys_hwgrp_state_t;
3280*da14cebeSEric Cheng 
3281*da14cebeSEric Cheng static char *
3282*da14cebeSEric Cheng print_phys_one_hwgrp_callback(print_field_t *pf, void *arg)
3283*da14cebeSEric Cheng {
3284*da14cebeSEric Cheng 	print_phys_hwgrp_state_t *hg_state = arg;
3285*da14cebeSEric Cheng 	dladm_hwgrp_attr_t *attr = hg_state->hs_grp_attr;
3286*da14cebeSEric Cheng 	static char buf[DLADM_STRSIZE];
3287*da14cebeSEric Cheng 
3288*da14cebeSEric Cheng 	switch (pf->pf_index) {
3289*da14cebeSEric Cheng 	case PHYS_H_LINK:
3290*da14cebeSEric Cheng 		(void) snprintf(buf, sizeof (buf), "%s", attr->hg_link_name);
3291*da14cebeSEric Cheng 		break;
3292*da14cebeSEric Cheng 	case PHYS_H_GROUP:
3293*da14cebeSEric Cheng 		(void) snprintf(buf, sizeof (buf), "%d", attr->hg_grp_num);
3294*da14cebeSEric Cheng 		break;
3295*da14cebeSEric Cheng 	case PHYS_H_GRPTYPE:
3296*da14cebeSEric Cheng 		(void) snprintf(buf, sizeof (buf), "%s",
3297*da14cebeSEric Cheng 		    attr->hg_grp_type == DLADM_HWGRP_TYPE_RX ? "RX" : "TX");
3298*da14cebeSEric Cheng 		break;
3299*da14cebeSEric Cheng 	case PHYS_H_RINGS:
3300*da14cebeSEric Cheng 		(void) snprintf(buf, sizeof (buf), "%d", attr->hg_n_rings);
3301*da14cebeSEric Cheng 		break;
3302*da14cebeSEric Cheng 	case PHYS_H_CLIENTS:
3303*da14cebeSEric Cheng 		if (attr->hg_client_names[0] == '\0') {
3304*da14cebeSEric Cheng 			(void) snprintf(buf, sizeof (buf), "--");
3305*da14cebeSEric Cheng 		} else {
3306*da14cebeSEric Cheng 			(void) snprintf(buf, sizeof (buf), "%s ",
3307*da14cebeSEric Cheng 			    attr->hg_client_names);
3308*da14cebeSEric Cheng 		}
3309*da14cebeSEric Cheng 		break;
3310*da14cebeSEric Cheng 	}
3311*da14cebeSEric Cheng 
3312*da14cebeSEric Cheng 	return (buf);
3313*da14cebeSEric Cheng }
3314*da14cebeSEric Cheng 
3315*da14cebeSEric Cheng /* callback of dladm_walk_macaddr, invoked for each MAC address slot */
3316*da14cebeSEric Cheng static boolean_t
3317*da14cebeSEric Cheng print_phys_mac_callback(void *arg, dladm_macaddr_attr_t *attr)
3318*da14cebeSEric Cheng {
3319*da14cebeSEric Cheng 	print_phys_mac_state_t *mac_state = arg;
3320*da14cebeSEric Cheng 	show_state_t *state = mac_state->ms_state;
3321*da14cebeSEric Cheng 
3322*da14cebeSEric Cheng 	if (!state->ls_parseable && !state->ls_printheader) {
3323*da14cebeSEric Cheng 		print_header(&state->ls_print);
3324*da14cebeSEric Cheng 		state->ls_printheader = B_TRUE;
3325*da14cebeSEric Cheng 	}
3326*da14cebeSEric Cheng 
3327*da14cebeSEric Cheng 	mac_state->ms_mac_attr = attr;
3328*da14cebeSEric Cheng 	dladm_print_output(&state->ls_print, state->ls_parseable,
3329*da14cebeSEric Cheng 	    print_phys_one_mac_callback, mac_state);
3330*da14cebeSEric Cheng 
3331*da14cebeSEric Cheng 	return (B_TRUE);
3332*da14cebeSEric Cheng }
3333*da14cebeSEric Cheng 
3334*da14cebeSEric Cheng /* invoked by show-phys -m for each physical data-link */
3335*da14cebeSEric Cheng static dladm_status_t
3336*da14cebeSEric Cheng print_phys_mac(show_state_t *state, datalink_id_t linkid, char *link)
3337*da14cebeSEric Cheng {
3338*da14cebeSEric Cheng 	print_phys_mac_state_t mac_state;
3339*da14cebeSEric Cheng 
3340*da14cebeSEric Cheng 	mac_state.ms_state = state;
3341*da14cebeSEric Cheng 	mac_state.ms_link = link;
3342*da14cebeSEric Cheng 
3343*da14cebeSEric Cheng 	return (dladm_walk_macaddr(linkid, &mac_state,
3344*da14cebeSEric Cheng 	    print_phys_mac_callback));
3345*da14cebeSEric Cheng }
3346*da14cebeSEric Cheng 
3347*da14cebeSEric Cheng /* callback of dladm_walk_hwgrp, invoked for each MAC hwgrp */
3348*da14cebeSEric Cheng static boolean_t
3349*da14cebeSEric Cheng print_phys_hwgrp_callback(void *arg, dladm_hwgrp_attr_t *attr)
3350*da14cebeSEric Cheng {
3351*da14cebeSEric Cheng 	print_phys_hwgrp_state_t *hwgrp_state = arg;
3352*da14cebeSEric Cheng 	show_state_t *state = hwgrp_state->hs_state;
3353*da14cebeSEric Cheng 
3354*da14cebeSEric Cheng 	if (!state->ls_parseable && !state->ls_printheader) {
3355*da14cebeSEric Cheng 		print_header(&state->ls_print);
3356*da14cebeSEric Cheng 		state->ls_printheader = B_TRUE;
3357*da14cebeSEric Cheng 	}
3358*da14cebeSEric Cheng 	hwgrp_state->hs_grp_attr = attr;
3359*da14cebeSEric Cheng 	dladm_print_output(&state->ls_print, state->ls_parseable,
3360*da14cebeSEric Cheng 	    print_phys_one_hwgrp_callback, hwgrp_state);
3361*da14cebeSEric Cheng 
3362*da14cebeSEric Cheng 	return (B_TRUE);
3363*da14cebeSEric Cheng }
3364*da14cebeSEric Cheng 
3365*da14cebeSEric Cheng /* invoked by show-phys -H for each physical data-link */
3366*da14cebeSEric Cheng static dladm_status_t
3367*da14cebeSEric Cheng print_phys_hwgrp(show_state_t *state, datalink_id_t linkid, char *link)
3368*da14cebeSEric Cheng {
3369*da14cebeSEric Cheng 	print_phys_hwgrp_state_t hwgrp_state;
3370*da14cebeSEric Cheng 
3371*da14cebeSEric Cheng 	hwgrp_state.hs_state = state;
3372*da14cebeSEric Cheng 	hwgrp_state.hs_link = link;
3373*da14cebeSEric Cheng 	return (dladm_walk_hwgrp(linkid, &hwgrp_state,
3374*da14cebeSEric Cheng 	    print_phys_hwgrp_callback));
3375*da14cebeSEric Cheng }
3376d62bc4baSyz147064 
3377d62bc4baSyz147064 static dladm_status_t
3378*da14cebeSEric Cheng print_phys(show_state_t *state, datalink_id_t linkid)
3379d62bc4baSyz147064 {
3380d62bc4baSyz147064 	char			link[MAXLINKNAMELEN];
3381d62bc4baSyz147064 	uint32_t		flags;
3382*da14cebeSEric Cheng 	dladm_status_t		status;
3383d62bc4baSyz147064 	datalink_class_t	class;
3384d62bc4baSyz147064 	uint32_t		media;
3385d62bc4baSyz147064 
3386d62bc4baSyz147064 	if ((status = dladm_datalink_id2info(linkid, &flags, &class, &media,
3387e7801d59Ssowmini 	    link, MAXLINKNAMELEN)) != DLADM_STATUS_OK) {
3388d62bc4baSyz147064 		goto done;
3389d62bc4baSyz147064 	}
3390d62bc4baSyz147064 
3391d62bc4baSyz147064 	if (class != DATALINK_CLASS_PHYS) {
3392d62bc4baSyz147064 		status = DLADM_STATUS_BADARG;
3393d62bc4baSyz147064 		goto done;
3394d62bc4baSyz147064 	}
3395d62bc4baSyz147064 
3396d62bc4baSyz147064 	if (!(state->ls_flags & flags)) {
3397d62bc4baSyz147064 		status = DLADM_STATUS_NOTFOUND;
3398d62bc4baSyz147064 		goto done;
3399d62bc4baSyz147064 	}
3400d62bc4baSyz147064 
3401*da14cebeSEric Cheng 	if (state->ls_mac)
3402*da14cebeSEric Cheng 		status = print_phys_mac(state, linkid, link);
3403*da14cebeSEric Cheng 	else if (state->ls_hwgrp)
3404*da14cebeSEric Cheng 		status = print_phys_hwgrp(state, linkid, link);
3405*da14cebeSEric Cheng 	else
3406*da14cebeSEric Cheng 		status = print_phys_default(state, linkid, link, flags, media);
3407d62bc4baSyz147064 
3408d62bc4baSyz147064 done:
3409d62bc4baSyz147064 	return (status);
3410d62bc4baSyz147064 }
3411d62bc4baSyz147064 
3412d62bc4baSyz147064 static int
3413d62bc4baSyz147064 show_phys(datalink_id_t linkid, void *arg)
3414d62bc4baSyz147064 {
3415d62bc4baSyz147064 	show_state_t	*state = arg;
3416d62bc4baSyz147064 
3417*da14cebeSEric Cheng 	state->ls_status = print_phys(state, linkid);
3418d62bc4baSyz147064 	return (DLADM_WALK_CONTINUE);
3419d62bc4baSyz147064 }
3420d62bc4baSyz147064 
3421d62bc4baSyz147064 /*
3422d62bc4baSyz147064  * Print the active topology information.
3423d62bc4baSyz147064  */
3424d62bc4baSyz147064 static dladm_status_t
3425e7801d59Ssowmini print_vlan(show_state_t *state, datalink_id_t linkid, link_fields_buf_t *l)
3426d62bc4baSyz147064 {
3427d62bc4baSyz147064 	dladm_vlan_attr_t	vinfo;
3428d62bc4baSyz147064 	uint32_t		flags;
3429d62bc4baSyz147064 	dladm_status_t		status;
3430d62bc4baSyz147064 
3431e7801d59Ssowmini 	if ((status = dladm_datalink_id2info(linkid, &flags, NULL, NULL,
3432e7801d59Ssowmini 	    l->link_name, sizeof (l->link_name))) != DLADM_STATUS_OK) {
3433d62bc4baSyz147064 		goto done;
3434d62bc4baSyz147064 	}
3435d62bc4baSyz147064 
3436d62bc4baSyz147064 	if (!(state->ls_flags & flags)) {
3437d62bc4baSyz147064 		status = DLADM_STATUS_NOTFOUND;
3438d62bc4baSyz147064 		goto done;
3439d62bc4baSyz147064 	}
3440d62bc4baSyz147064 
3441d62bc4baSyz147064 	if ((status = dladm_vlan_info(linkid, &vinfo, state->ls_flags)) !=
3442d62bc4baSyz147064 	    DLADM_STATUS_OK || (status = dladm_datalink_id2info(
3443e7801d59Ssowmini 	    vinfo.dv_linkid, NULL, NULL, NULL, l->link_over,
3444e7801d59Ssowmini 	    sizeof (l->link_over))) != DLADM_STATUS_OK) {
3445d62bc4baSyz147064 		goto done;
3446d62bc4baSyz147064 	}
3447d62bc4baSyz147064 
3448e7801d59Ssowmini 	(void) snprintf(l->link_vlan_vid, sizeof (l->link_vlan_vid), "%d",
3449e7801d59Ssowmini 	    vinfo.dv_vid);
3450*da14cebeSEric Cheng 	(void) snprintf(l->link_flags, sizeof (l->link_flags), "%c----",
3451*da14cebeSEric Cheng 	    vinfo.dv_force ? 'f' : '-');
3452d62bc4baSyz147064 
3453d62bc4baSyz147064 done:
3454d62bc4baSyz147064 	return (status);
3455d62bc4baSyz147064 }
3456d62bc4baSyz147064 
3457d62bc4baSyz147064 static int
3458d62bc4baSyz147064 show_vlan(datalink_id_t linkid, void *arg)
3459d62bc4baSyz147064 {
3460d62bc4baSyz147064 	show_state_t		*state = arg;
3461d62bc4baSyz147064 	dladm_status_t		status;
3462e7801d59Ssowmini 	link_fields_buf_t	lbuf;
3463d62bc4baSyz147064 
34645f5c9f54SAnurag S. Maskey 	bzero(&lbuf, sizeof (link_fields_buf_t));
3465e7801d59Ssowmini 	status = print_vlan(state, linkid, &lbuf);
3466d62bc4baSyz147064 	if (status != DLADM_STATUS_OK)
3467d62bc4baSyz147064 		goto done;
3468e7801d59Ssowmini 
3469e7801d59Ssowmini 	if (!state->ls_parseable && !state->ls_printheader) {
3470e7801d59Ssowmini 		print_header(&state->ls_print);
3471e7801d59Ssowmini 		state->ls_printheader = B_TRUE;
3472e7801d59Ssowmini 	}
3473e7801d59Ssowmini 
3474e7801d59Ssowmini 	dladm_print_output(&state->ls_print, state->ls_parseable,
3475e7801d59Ssowmini 	    dladm_print_field, (void *)&lbuf);
3476d62bc4baSyz147064 
3477d62bc4baSyz147064 done:
3478d62bc4baSyz147064 	state->ls_status = status;
3479d62bc4baSyz147064 	return (DLADM_WALK_CONTINUE);
3480d62bc4baSyz147064 }
3481d62bc4baSyz147064 
3482d62bc4baSyz147064 static void
34838d5c46e6Sam223141 do_show_phys(int argc, char *argv[], const char *use)
3484d62bc4baSyz147064 {
3485d62bc4baSyz147064 	int		option;
3486d62bc4baSyz147064 	uint32_t	flags = DLADM_OPT_ACTIVE;
3487d62bc4baSyz147064 	boolean_t	p_arg = B_FALSE;
3488e7801d59Ssowmini 	boolean_t	o_arg = B_FALSE;
3489*da14cebeSEric Cheng 	boolean_t	m_arg = B_FALSE;
3490*da14cebeSEric Cheng 	boolean_t	H_arg = B_FALSE;
3491d62bc4baSyz147064 	datalink_id_t	linkid = DATALINK_ALL_LINKID;
3492d62bc4baSyz147064 	show_state_t	state;
3493d62bc4baSyz147064 	dladm_status_t	status;
3494e7801d59Ssowmini 	char		*fields_str = NULL;
3495e7801d59Ssowmini 	print_field_t	**fields;
3496e7801d59Ssowmini 	uint_t		nfields;
3497e7801d59Ssowmini 	char		*all_active_fields =
3498e7801d59Ssowmini 	    "link,media,state,speed,duplex,device";
34995f5c9f54SAnurag S. Maskey 	char		*all_inactive_fields = "link,device,media,flags";
3500*da14cebeSEric Cheng 	char		*all_mac_fields = "link,slot,address,inuse,client";
3501*da14cebeSEric Cheng 	char		*all_hwgrp_fields =
3502*da14cebeSEric Cheng 	    "link,group,grouptype,rings,clients";
3503*da14cebeSEric Cheng 	print_field_t	*pf;
3504*da14cebeSEric Cheng 	int		pfmax;
3505d62bc4baSyz147064 
3506e7801d59Ssowmini 	bzero(&state, sizeof (state));
3507d62bc4baSyz147064 	opterr = 0;
3508*da14cebeSEric Cheng 	while ((option = getopt_long(argc, argv, ":pPo:mH",
3509d62bc4baSyz147064 	    show_lopts, NULL)) != -1) {
3510d62bc4baSyz147064 		switch (option) {
3511d62bc4baSyz147064 		case 'p':
3512d62bc4baSyz147064 			if (p_arg)
3513d62bc4baSyz147064 				die_optdup(option);
3514d62bc4baSyz147064 
3515d62bc4baSyz147064 			p_arg = B_TRUE;
3516d62bc4baSyz147064 			break;
3517d62bc4baSyz147064 		case 'P':
3518d62bc4baSyz147064 			if (flags != DLADM_OPT_ACTIVE)
3519d62bc4baSyz147064 				die_optdup(option);
3520d62bc4baSyz147064 
3521d62bc4baSyz147064 			flags = DLADM_OPT_PERSIST;
3522d62bc4baSyz147064 			break;
3523e7801d59Ssowmini 		case 'o':
3524e7801d59Ssowmini 			o_arg = B_TRUE;
3525e7801d59Ssowmini 			fields_str = optarg;
3526e7801d59Ssowmini 			break;
3527*da14cebeSEric Cheng 		case 'm':
3528*da14cebeSEric Cheng 			m_arg = B_TRUE;
3529*da14cebeSEric Cheng 			break;
3530*da14cebeSEric Cheng 		case 'H':
3531*da14cebeSEric Cheng 			H_arg = B_TRUE;
3532*da14cebeSEric Cheng 			break;
3533d62bc4baSyz147064 		default:
35348d5c46e6Sam223141 			die_opterr(optopt, option, use);
3535d62bc4baSyz147064 			break;
3536d62bc4baSyz147064 		}
3537d62bc4baSyz147064 	}
3538d62bc4baSyz147064 
35390d365605Sschuster 	if (p_arg && !o_arg)
35400d365605Sschuster 		die("-p requires -o");
35410d365605Sschuster 
3542*da14cebeSEric Cheng 	if (m_arg && H_arg)
3543*da14cebeSEric Cheng 		die("-m cannot combine with -H");
3544*da14cebeSEric Cheng 
35450d365605Sschuster 	if (p_arg && strcasecmp(fields_str, "all") == 0)
35460d365605Sschuster 		die("\"-o all\" is invalid with -p");
35470d365605Sschuster 
3548d62bc4baSyz147064 	/* get link name (optional last argument) */
3549d62bc4baSyz147064 	if (optind == (argc-1)) {
3550d62bc4baSyz147064 		if ((status = dladm_name2info(argv[optind], &linkid, NULL,
3551d62bc4baSyz147064 		    NULL, NULL)) != DLADM_STATUS_OK) {
3552d62bc4baSyz147064 			die_dlerr(status, "link %s is not valid", argv[optind]);
3553d62bc4baSyz147064 		}
3554d62bc4baSyz147064 	} else if (optind != argc) {
3555d62bc4baSyz147064 		usage();
3556d62bc4baSyz147064 	}
3557d62bc4baSyz147064 
3558d62bc4baSyz147064 	state.ls_parseable = p_arg;
3559d62bc4baSyz147064 	state.ls_flags = flags;
3560d62bc4baSyz147064 	state.ls_donefirst = B_FALSE;
3561*da14cebeSEric Cheng 	state.ls_mac = m_arg;
3562*da14cebeSEric Cheng 	state.ls_hwgrp = H_arg;
3563d62bc4baSyz147064 
3564*da14cebeSEric Cheng 	if (m_arg && !(flags & DLADM_OPT_ACTIVE)) {
3565*da14cebeSEric Cheng 		/*
3566*da14cebeSEric Cheng 		 * We can only display the factory MAC addresses of
3567*da14cebeSEric Cheng 		 * active data-links.
3568*da14cebeSEric Cheng 		 */
3569*da14cebeSEric Cheng 		die("-m not compatible with -P");
3570e7801d59Ssowmini 	}
3571e7801d59Ssowmini 
3572*da14cebeSEric Cheng 	if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) {
3573*da14cebeSEric Cheng 		if (state.ls_mac)
3574*da14cebeSEric Cheng 			fields_str = all_mac_fields;
3575*da14cebeSEric Cheng 		else if (state.ls_hwgrp)
3576*da14cebeSEric Cheng 			fields_str = all_hwgrp_fields;
3577*da14cebeSEric Cheng 		else if (state.ls_flags & DLADM_OPT_ACTIVE) {
3578*da14cebeSEric Cheng 			fields_str = all_active_fields;
3579*da14cebeSEric Cheng 		} else {
3580*da14cebeSEric Cheng 			fields_str = all_inactive_fields;
3581*da14cebeSEric Cheng 		}
3582*da14cebeSEric Cheng 	}
3583*da14cebeSEric Cheng 
3584*da14cebeSEric Cheng 	if (state.ls_mac) {
3585*da14cebeSEric Cheng 		pf = phys_m_fields;
3586*da14cebeSEric Cheng 		pfmax = PHYS_M_MAX_FIELDS;
3587*da14cebeSEric Cheng 	} else if (state.ls_hwgrp) {
3588*da14cebeSEric Cheng 		pf = phys_h_fields;
3589*da14cebeSEric Cheng 		pfmax = PHYS_H_MAX_FIELDS;
3590*da14cebeSEric Cheng 	} else {
3591*da14cebeSEric Cheng 		pf = phys_fields;
3592*da14cebeSEric Cheng 		pfmax = PHYS_MAX_FIELDS;
3593*da14cebeSEric Cheng 	}
3594*da14cebeSEric Cheng 
3595*da14cebeSEric Cheng 	fields = parse_output_fields(fields_str, pf,
3596*da14cebeSEric Cheng 	    pfmax, CMD_TYPE_ANY, &nfields);
3597e7801d59Ssowmini 
3598e7801d59Ssowmini 	if (fields == NULL) {
3599e7801d59Ssowmini 		die("invalid field(s) specified");
3600e7801d59Ssowmini 		return;
3601e7801d59Ssowmini 	}
3602e7801d59Ssowmini 
3603e7801d59Ssowmini 	state.ls_print.ps_fields = fields;
3604e7801d59Ssowmini 	state.ls_print.ps_nfields = nfields;
3605e7801d59Ssowmini 
3606d62bc4baSyz147064 	if (linkid == DATALINK_ALL_LINKID) {
3607d62bc4baSyz147064 		(void) dladm_walk_datalink_id(show_phys, &state,
3608d62bc4baSyz147064 		    DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE, flags);
3609d62bc4baSyz147064 	} else {
3610d62bc4baSyz147064 		(void) show_phys(linkid, &state);
3611d62bc4baSyz147064 		if (state.ls_status != DLADM_STATUS_OK) {
3612d62bc4baSyz147064 			die_dlerr(state.ls_status,
3613d62bc4baSyz147064 			    "failed to show physical link %s", argv[optind]);
3614d62bc4baSyz147064 		}
3615d62bc4baSyz147064 	}
3616d62bc4baSyz147064 }
3617d62bc4baSyz147064 
3618d62bc4baSyz147064 static void
36198d5c46e6Sam223141 do_show_vlan(int argc, char *argv[], const char *use)
3620d62bc4baSyz147064 {
3621d62bc4baSyz147064 	int		option;
3622d62bc4baSyz147064 	uint32_t	flags = DLADM_OPT_ACTIVE;
3623d62bc4baSyz147064 	boolean_t	p_arg = B_FALSE;
3624d62bc4baSyz147064 	datalink_id_t	linkid = DATALINK_ALL_LINKID;
3625d62bc4baSyz147064 	show_state_t	state;
3626d62bc4baSyz147064 	dladm_status_t	status;
3627e7801d59Ssowmini 	boolean_t	o_arg = B_FALSE;
3628e7801d59Ssowmini 	char		*fields_str = NULL;
3629e7801d59Ssowmini 	print_field_t	**fields;
3630e7801d59Ssowmini 	uint_t		nfields;
3631e7801d59Ssowmini 	char		*all_fields = "link,vid,over,flags";
3632e7801d59Ssowmini 
3633e7801d59Ssowmini 	bzero(&state, sizeof (state));
3634d62bc4baSyz147064 
3635d62bc4baSyz147064 	opterr = 0;
3636e7801d59Ssowmini 	while ((option = getopt_long(argc, argv, ":pPo:",
3637d62bc4baSyz147064 	    show_lopts, NULL)) != -1) {
3638d62bc4baSyz147064 		switch (option) {
3639d62bc4baSyz147064 		case 'p':
3640d62bc4baSyz147064 			if (p_arg)
3641d62bc4baSyz147064 				die_optdup(option);
3642d62bc4baSyz147064 
3643d62bc4baSyz147064 			p_arg = B_TRUE;
3644d62bc4baSyz147064 			break;
3645d62bc4baSyz147064 		case 'P':
3646d62bc4baSyz147064 			if (flags != DLADM_OPT_ACTIVE)
3647d62bc4baSyz147064 				die_optdup(option);
3648d62bc4baSyz147064 
3649d62bc4baSyz147064 			flags = DLADM_OPT_PERSIST;
3650d62bc4baSyz147064 			break;
3651e7801d59Ssowmini 		case 'o':
3652e7801d59Ssowmini 			o_arg = B_TRUE;
3653e7801d59Ssowmini 			fields_str = optarg;
3654e7801d59Ssowmini 			break;
3655d62bc4baSyz147064 		default:
36568d5c46e6Sam223141 			die_opterr(optopt, option, use);
3657d62bc4baSyz147064 			break;
3658d62bc4baSyz147064 		}
3659d62bc4baSyz147064 	}
3660d62bc4baSyz147064 
36610d365605Sschuster 	if (p_arg && !o_arg)
36620d365605Sschuster 		die("-p requires -o");
36630d365605Sschuster 
36640d365605Sschuster 	if (p_arg && strcasecmp(fields_str, "all") == 0)
36650d365605Sschuster 		die("\"-o all\" is invalid with -p");
36660d365605Sschuster 
3667d62bc4baSyz147064 	/* get link name (optional last argument) */
3668d62bc4baSyz147064 	if (optind == (argc-1)) {
3669d62bc4baSyz147064 		if ((status = dladm_name2info(argv[optind], &linkid, NULL,
3670d62bc4baSyz147064 		    NULL, NULL)) != DLADM_STATUS_OK) {
3671d62bc4baSyz147064 			die_dlerr(status, "link %s is not valid", argv[optind]);
3672d62bc4baSyz147064 		}
3673d62bc4baSyz147064 	} else if (optind != argc) {
3674d62bc4baSyz147064 		usage();
3675d62bc4baSyz147064 	}
3676d62bc4baSyz147064 
3677d62bc4baSyz147064 	state.ls_parseable = p_arg;
3678d62bc4baSyz147064 	state.ls_flags = flags;
3679d62bc4baSyz147064 	state.ls_donefirst = B_FALSE;
3680d62bc4baSyz147064 
3681e7801d59Ssowmini 	if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0))
3682e7801d59Ssowmini 		fields_str = all_fields;
3683e7801d59Ssowmini 
3684e7801d59Ssowmini 	fields = parse_output_fields(fields_str, vlan_fields, VLAN_MAX_FIELDS,
3685e7801d59Ssowmini 	    CMD_TYPE_ANY, &nfields);
3686e7801d59Ssowmini 
3687e7801d59Ssowmini 	if (fields == NULL) {
3688e7801d59Ssowmini 		die("invalid field(s) specified");
3689e7801d59Ssowmini 		return;
3690e7801d59Ssowmini 	}
3691e7801d59Ssowmini 	state.ls_print.ps_fields = fields;
3692e7801d59Ssowmini 	state.ls_print.ps_nfields = nfields;
3693e7801d59Ssowmini 
3694d62bc4baSyz147064 	if (linkid == DATALINK_ALL_LINKID) {
3695d62bc4baSyz147064 		(void) dladm_walk_datalink_id(show_vlan, &state,
3696d62bc4baSyz147064 		    DATALINK_CLASS_VLAN, DATALINK_ANY_MEDIATYPE, flags);
3697d62bc4baSyz147064 	} else {
3698d62bc4baSyz147064 		(void) show_vlan(linkid, &state);
3699d62bc4baSyz147064 		if (state.ls_status != DLADM_STATUS_OK) {
3700d62bc4baSyz147064 			die_dlerr(state.ls_status, "failed to show vlan %s",
3701d62bc4baSyz147064 			    argv[optind]);
3702d62bc4baSyz147064 		}
3703d62bc4baSyz147064 	}
3704d62bc4baSyz147064 }
3705d62bc4baSyz147064 
3706d62bc4baSyz147064 static void
3707*da14cebeSEric Cheng do_create_vnic(int argc, char *argv[], const char *use)
3708*da14cebeSEric Cheng {
3709*da14cebeSEric Cheng 	datalink_id_t		linkid, dev_linkid;
3710*da14cebeSEric Cheng 	char			devname[MAXLINKNAMELEN];
3711*da14cebeSEric Cheng 	char			name[MAXLINKNAMELEN];
3712*da14cebeSEric Cheng 	boolean_t		l_arg = B_FALSE;
3713*da14cebeSEric Cheng 	uint32_t		flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
3714*da14cebeSEric Cheng 	char			*altroot = NULL;
3715*da14cebeSEric Cheng 	char			option;
3716*da14cebeSEric Cheng 	char			*endp = NULL;
3717*da14cebeSEric Cheng 	dladm_status_t		status;
3718*da14cebeSEric Cheng 	vnic_mac_addr_type_t	mac_addr_type = VNIC_MAC_ADDR_TYPE_AUTO;
3719*da14cebeSEric Cheng 	uchar_t			*mac_addr;
3720*da14cebeSEric Cheng 	int			mac_slot = -1, maclen = 0, mac_prefix_len = 0;
3721*da14cebeSEric Cheng 	dladm_arg_list_t	*proplist = NULL;
3722*da14cebeSEric Cheng 	uint16_t		vid = 0;
3723*da14cebeSEric Cheng 
3724*da14cebeSEric Cheng 	opterr = 0;
3725*da14cebeSEric Cheng 	while ((option = getopt_long(argc, argv, ":tfR:l:m:n:p:r:v:H",
3726*da14cebeSEric Cheng 	    vnic_lopts, NULL)) != -1) {
3727*da14cebeSEric Cheng 		switch (option) {
3728*da14cebeSEric Cheng 		case 't':
3729*da14cebeSEric Cheng 			flags &= ~DLADM_OPT_PERSIST;
3730*da14cebeSEric Cheng 			break;
3731*da14cebeSEric Cheng 		case 'R':
3732*da14cebeSEric Cheng 			altroot = optarg;
3733*da14cebeSEric Cheng 			break;
3734*da14cebeSEric Cheng 		case 'l':
3735*da14cebeSEric Cheng 			if (strlcpy(devname, optarg, MAXLINKNAMELEN) >=
3736*da14cebeSEric Cheng 			    MAXLINKNAMELEN)
3737*da14cebeSEric Cheng 				die("link name too long");
3738*da14cebeSEric Cheng 			l_arg = B_TRUE;
3739*da14cebeSEric Cheng 			break;
3740*da14cebeSEric Cheng 		case 'm':
3741*da14cebeSEric Cheng 			if (strcmp(optarg, "fixed") == 0) {
3742*da14cebeSEric Cheng 				/*
3743*da14cebeSEric Cheng 				 * A fixed MAC address must be specified
3744*da14cebeSEric Cheng 				 * by its value, not by the keyword 'fixed'.
3745*da14cebeSEric Cheng 				 */
3746*da14cebeSEric Cheng 				die("'fixed' is not a valid MAC address");
3747*da14cebeSEric Cheng 			}
3748*da14cebeSEric Cheng 			if (dladm_vnic_str2macaddrtype(optarg,
3749*da14cebeSEric Cheng 			    &mac_addr_type) != DLADM_STATUS_OK) {
3750*da14cebeSEric Cheng 				mac_addr_type = VNIC_MAC_ADDR_TYPE_FIXED;
3751*da14cebeSEric Cheng 				/* MAC address specified by value */
3752*da14cebeSEric Cheng 				mac_addr = _link_aton(optarg, &maclen);
3753*da14cebeSEric Cheng 				if (mac_addr == NULL) {
3754*da14cebeSEric Cheng 					if (maclen == -1)
3755*da14cebeSEric Cheng 						die("invalid MAC address");
3756*da14cebeSEric Cheng 					else
3757*da14cebeSEric Cheng 						die("out of memory");
3758*da14cebeSEric Cheng 					exit(1);
3759*da14cebeSEric Cheng 				}
3760*da14cebeSEric Cheng 			}
3761*da14cebeSEric Cheng 			break;
3762*da14cebeSEric Cheng 		case 'n':
3763*da14cebeSEric Cheng 			errno = 0;
3764*da14cebeSEric Cheng 			mac_slot = (int)strtol(optarg, &endp, 10);
3765*da14cebeSEric Cheng 			if (errno != 0 || *endp != '\0')
3766*da14cebeSEric Cheng 				die("invalid slot number");
3767*da14cebeSEric Cheng 			break;
3768*da14cebeSEric Cheng 		case 'p':
3769*da14cebeSEric Cheng 			if (dladm_parse_link_props(optarg, &proplist, B_FALSE)
3770*da14cebeSEric Cheng 			    != DLADM_STATUS_OK)
3771*da14cebeSEric Cheng 				die("invalid vnic property");
3772*da14cebeSEric Cheng 			break;
3773*da14cebeSEric Cheng 		case 'r':
3774*da14cebeSEric Cheng 			mac_addr = _link_aton(optarg, &mac_prefix_len);
3775*da14cebeSEric Cheng 			if (mac_addr == NULL) {
3776*da14cebeSEric Cheng 				if (mac_prefix_len == -1)
3777*da14cebeSEric Cheng 					die("invalid MAC address");
3778*da14cebeSEric Cheng 				else
3779*da14cebeSEric Cheng 					die("out of memory");
3780*da14cebeSEric Cheng 				exit(1);
3781*da14cebeSEric Cheng 			}
3782*da14cebeSEric Cheng 			break;
3783*da14cebeSEric Cheng 		case 'v':
3784*da14cebeSEric Cheng 			vid = (int)strtol(optarg, &endp, 10);
3785*da14cebeSEric Cheng 			if (errno != 0 || *endp != '\0' || vid == 0)
3786*da14cebeSEric Cheng 				/* VID of 0 is invalid */
3787*da14cebeSEric Cheng 				die("invalid VLAN id");
3788*da14cebeSEric Cheng 			break;
3789*da14cebeSEric Cheng 		case 'f':
3790*da14cebeSEric Cheng 			flags |= DLADM_OPT_FORCE;
3791*da14cebeSEric Cheng 			break;
3792*da14cebeSEric Cheng 		case 'H':
3793*da14cebeSEric Cheng 			flags |= DLADM_OPT_HWRINGS;
3794*da14cebeSEric Cheng 			break;
3795*da14cebeSEric Cheng 		default:
3796*da14cebeSEric Cheng 			die_opterr(optopt, option, use);
3797*da14cebeSEric Cheng 		}
3798*da14cebeSEric Cheng 	}
3799*da14cebeSEric Cheng 
3800*da14cebeSEric Cheng 	/*
3801*da14cebeSEric Cheng 	 * 'f' - force, flag can be specified only with 'v' - vlan.
3802*da14cebeSEric Cheng 	 */
3803*da14cebeSEric Cheng 	if ((flags & DLADM_OPT_FORCE) != 0 && vid == 0)
3804*da14cebeSEric Cheng 		die("-f option can only be used with -v");
3805*da14cebeSEric Cheng 
3806*da14cebeSEric Cheng 	if (mac_prefix_len != 0 && mac_addr_type != VNIC_MAC_ADDR_TYPE_RANDOM &&
3807*da14cebeSEric Cheng 	    mac_addr_type != VNIC_MAC_ADDR_TYPE_FIXED)
3808*da14cebeSEric Cheng 		usage();
3809*da14cebeSEric Cheng 
3810*da14cebeSEric Cheng 	/* check required options */
3811*da14cebeSEric Cheng 	if (!l_arg)
3812*da14cebeSEric Cheng 		usage();
3813*da14cebeSEric Cheng 
3814*da14cebeSEric Cheng 	if (mac_slot != -1 && mac_addr_type != VNIC_MAC_ADDR_TYPE_FACTORY)
3815*da14cebeSEric Cheng 		usage();
3816*da14cebeSEric Cheng 
3817*da14cebeSEric Cheng 	/* the VNIC id is the required operand */
3818*da14cebeSEric Cheng 	if (optind != (argc - 1))
3819*da14cebeSEric Cheng 		usage();
3820*da14cebeSEric Cheng 
3821*da14cebeSEric Cheng 	if (strlcpy(name, argv[optind], MAXLINKNAMELEN) >= MAXLINKNAMELEN)
3822*da14cebeSEric Cheng 		die("link name too long '%s'", argv[optind]);
3823*da14cebeSEric Cheng 
3824*da14cebeSEric Cheng 	if (!dladm_valid_linkname(name))
3825*da14cebeSEric Cheng 		die("invalid link name '%s'", argv[optind]);
3826*da14cebeSEric Cheng 
3827*da14cebeSEric Cheng 	if (altroot != NULL)
3828*da14cebeSEric Cheng 		altroot_cmd(altroot, argc, argv);
3829*da14cebeSEric Cheng 
3830*da14cebeSEric Cheng 	if (dladm_name2info(devname, &dev_linkid, NULL, NULL, NULL) !=
3831*da14cebeSEric Cheng 	    DLADM_STATUS_OK)
3832*da14cebeSEric Cheng 		die("invalid link name '%s'", devname);
3833*da14cebeSEric Cheng 
3834*da14cebeSEric Cheng 	status = dladm_vnic_create(name, dev_linkid, mac_addr_type, mac_addr,
3835*da14cebeSEric Cheng 	    maclen, &mac_slot, mac_prefix_len, vid, &linkid, proplist, flags);
3836*da14cebeSEric Cheng 	if (status != DLADM_STATUS_OK)
3837*da14cebeSEric Cheng 		die_dlerr(status, "vnic creation over %s failed", devname);
3838*da14cebeSEric Cheng 
3839*da14cebeSEric Cheng 	dladm_free_props(proplist);
3840*da14cebeSEric Cheng }
3841*da14cebeSEric Cheng 
3842*da14cebeSEric Cheng static void
3843*da14cebeSEric Cheng do_etherstub_check(const char *name, datalink_id_t linkid, boolean_t etherstub,
3844*da14cebeSEric Cheng     uint32_t flags)
3845*da14cebeSEric Cheng {
3846*da14cebeSEric Cheng 	boolean_t is_etherstub;
3847*da14cebeSEric Cheng 	dladm_vnic_attr_t attr;
3848*da14cebeSEric Cheng 
3849*da14cebeSEric Cheng 	if (dladm_vnic_info(linkid, &attr, flags) != DLADM_STATUS_OK) {
3850*da14cebeSEric Cheng 		/*
3851*da14cebeSEric Cheng 		 * Let the delete continue anyway.
3852*da14cebeSEric Cheng 		 */
3853*da14cebeSEric Cheng 		return;
3854*da14cebeSEric Cheng 	}
3855*da14cebeSEric Cheng 	is_etherstub = (attr.va_link_id == DATALINK_INVALID_LINKID);
3856*da14cebeSEric Cheng 	if (is_etherstub != etherstub) {
3857*da14cebeSEric Cheng 		die("'%s' is not %s", name,
3858*da14cebeSEric Cheng 		    (is_etherstub ? "a vnic" : "an etherstub"));
3859*da14cebeSEric Cheng 	}
3860*da14cebeSEric Cheng }
3861*da14cebeSEric Cheng 
3862*da14cebeSEric Cheng static void
3863*da14cebeSEric Cheng do_delete_vnic_common(int argc, char *argv[], const char *use,
3864*da14cebeSEric Cheng     boolean_t etherstub)
3865*da14cebeSEric Cheng {
3866*da14cebeSEric Cheng 	char option;
3867*da14cebeSEric Cheng 	uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
3868*da14cebeSEric Cheng 	datalink_id_t linkid;
3869*da14cebeSEric Cheng 	char *altroot = NULL;
3870*da14cebeSEric Cheng 	dladm_status_t status;
3871*da14cebeSEric Cheng 
3872*da14cebeSEric Cheng 	opterr = 0;
3873*da14cebeSEric Cheng 	while ((option = getopt_long(argc, argv, ":R:t", lopts,
3874*da14cebeSEric Cheng 	    NULL)) != -1) {
3875*da14cebeSEric Cheng 		switch (option) {
3876*da14cebeSEric Cheng 		case 't':
3877*da14cebeSEric Cheng 			flags &= ~DLADM_OPT_PERSIST;
3878*da14cebeSEric Cheng 			break;
3879*da14cebeSEric Cheng 		case 'R':
3880*da14cebeSEric Cheng 			altroot = optarg;
3881*da14cebeSEric Cheng 			break;
3882*da14cebeSEric Cheng 		default:
3883*da14cebeSEric Cheng 			die_opterr(optopt, option, use);
3884*da14cebeSEric Cheng 		}
3885*da14cebeSEric Cheng 	}
3886*da14cebeSEric Cheng 
3887*da14cebeSEric Cheng 	/* get vnic name (required last argument) */
3888*da14cebeSEric Cheng 	if (optind != (argc - 1))
3889*da14cebeSEric Cheng 		usage();
3890*da14cebeSEric Cheng 
3891*da14cebeSEric Cheng 	if (altroot != NULL)
3892*da14cebeSEric Cheng 		altroot_cmd(altroot, argc, argv);
3893*da14cebeSEric Cheng 
3894*da14cebeSEric Cheng 	status = dladm_name2info(argv[optind], &linkid, NULL, NULL, NULL);
3895*da14cebeSEric Cheng 	if (status != DLADM_STATUS_OK)
3896*da14cebeSEric Cheng 		die("invalid link name '%s'", argv[optind]);
3897*da14cebeSEric Cheng 
3898*da14cebeSEric Cheng 	if ((flags & DLADM_OPT_ACTIVE) != 0) {
3899*da14cebeSEric Cheng 		do_etherstub_check(argv[optind], linkid, etherstub,
3900*da14cebeSEric Cheng 		    DLADM_OPT_ACTIVE);
3901*da14cebeSEric Cheng 	}
3902*da14cebeSEric Cheng 	if ((flags & DLADM_OPT_PERSIST) != 0) {
3903*da14cebeSEric Cheng 		do_etherstub_check(argv[optind], linkid, etherstub,
3904*da14cebeSEric Cheng 		    DLADM_OPT_PERSIST);
3905*da14cebeSEric Cheng 	}
3906*da14cebeSEric Cheng 
3907*da14cebeSEric Cheng 	status = dladm_vnic_delete(linkid, flags);
3908*da14cebeSEric Cheng 	if (status != DLADM_STATUS_OK)
3909*da14cebeSEric Cheng 		die_dlerr(status, "vnic deletion failed");
3910*da14cebeSEric Cheng }
3911*da14cebeSEric Cheng 
3912*da14cebeSEric Cheng static void
3913*da14cebeSEric Cheng do_delete_vnic(int argc, char *argv[], const char *use)
3914*da14cebeSEric Cheng {
3915*da14cebeSEric Cheng 	do_delete_vnic_common(argc, argv, use, B_FALSE);
3916*da14cebeSEric Cheng }
3917*da14cebeSEric Cheng 
3918*da14cebeSEric Cheng /* ARGSUSED */
3919*da14cebeSEric Cheng static void
3920*da14cebeSEric Cheng do_up_vnic_common(int argc, char *argv[], const char *use, boolean_t vlan)
3921*da14cebeSEric Cheng {
3922*da14cebeSEric Cheng 	datalink_id_t	linkid = DATALINK_ALL_LINKID;
3923*da14cebeSEric Cheng 	dladm_status_t	status;
3924*da14cebeSEric Cheng 	char 		*type;
3925*da14cebeSEric Cheng 
3926*da14cebeSEric Cheng 	type = vlan ? "vlan" : "vnic";
3927*da14cebeSEric Cheng 
3928*da14cebeSEric Cheng 	/*
3929*da14cebeSEric Cheng 	 * get the id or the name of the vnic/vlan (optional last argument)
3930*da14cebeSEric Cheng 	 */
3931*da14cebeSEric Cheng 	if (argc == 2) {
3932*da14cebeSEric Cheng 		status = dladm_name2info(argv[1], &linkid, NULL, NULL, NULL);
3933*da14cebeSEric Cheng 		if (status != DLADM_STATUS_OK)
3934*da14cebeSEric Cheng 			goto done;
3935*da14cebeSEric Cheng 
3936*da14cebeSEric Cheng 	} else if (argc > 2) {
3937*da14cebeSEric Cheng 		usage();
3938*da14cebeSEric Cheng 	}
3939*da14cebeSEric Cheng 
3940*da14cebeSEric Cheng 	if (vlan)
3941*da14cebeSEric Cheng 		status = dladm_vlan_up(linkid);
3942*da14cebeSEric Cheng 	else
3943*da14cebeSEric Cheng 		status = dladm_vnic_up(linkid, 0);
3944*da14cebeSEric Cheng 
3945*da14cebeSEric Cheng done:
3946*da14cebeSEric Cheng 	if (status != DLADM_STATUS_OK) {
3947*da14cebeSEric Cheng 		if (argc == 2) {
3948*da14cebeSEric Cheng 			die_dlerr(status,
3949*da14cebeSEric Cheng 			    "could not bring up %s '%s'", type, argv[1]);
3950*da14cebeSEric Cheng 		} else {
3951*da14cebeSEric Cheng 			die_dlerr(status, "could not bring %ss up", type);
3952*da14cebeSEric Cheng 		}
3953*da14cebeSEric Cheng 	}
3954*da14cebeSEric Cheng }
3955*da14cebeSEric Cheng 
3956*da14cebeSEric Cheng static void
3957*da14cebeSEric Cheng do_up_vnic(int argc, char *argv[], const char *use)
3958*da14cebeSEric Cheng {
3959*da14cebeSEric Cheng 	do_up_vnic_common(argc, argv, use, B_FALSE);
3960*da14cebeSEric Cheng }
3961*da14cebeSEric Cheng 
3962*da14cebeSEric Cheng static void
3963*da14cebeSEric Cheng dump_vnics_head(const char *dev)
3964*da14cebeSEric Cheng {
3965*da14cebeSEric Cheng 	if (strlen(dev))
3966*da14cebeSEric Cheng 		(void) printf("%s", dev);
3967*da14cebeSEric Cheng 
3968*da14cebeSEric Cheng 	(void) printf("\tipackets  rbytes      opackets  obytes          ");
3969*da14cebeSEric Cheng 
3970*da14cebeSEric Cheng 	if (strlen(dev))
3971*da14cebeSEric Cheng 		(void) printf("%%ipkts  %%opkts\n");
3972*da14cebeSEric Cheng 	else
3973*da14cebeSEric Cheng 		(void) printf("\n");
3974*da14cebeSEric Cheng }
3975*da14cebeSEric Cheng 
3976*da14cebeSEric Cheng static void
3977*da14cebeSEric Cheng dump_vnic_stat(const char *name, datalink_id_t vnic_id,
3978*da14cebeSEric Cheng     show_vnic_state_t *state, pktsum_t *vnic_stats, pktsum_t *tot_stats)
3979*da14cebeSEric Cheng {
3980*da14cebeSEric Cheng 	pktsum_t	diff_stats;
3981*da14cebeSEric Cheng 	pktsum_t	*old_stats = &state->vs_prevstats[vnic_id];
3982*da14cebeSEric Cheng 
3983*da14cebeSEric Cheng 	dladm_stats_diff(&diff_stats, vnic_stats, old_stats);
3984*da14cebeSEric Cheng 
3985*da14cebeSEric Cheng 	(void) printf("%s", name);
3986*da14cebeSEric Cheng 
3987*da14cebeSEric Cheng 	(void) printf("\t%-10llu", diff_stats.ipackets);
3988*da14cebeSEric Cheng 	(void) printf("%-12llu", diff_stats.rbytes);
3989*da14cebeSEric Cheng 	(void) printf("%-10llu", diff_stats.opackets);
3990*da14cebeSEric Cheng 	(void) printf("%-12llu", diff_stats.obytes);
3991*da14cebeSEric Cheng 
3992*da14cebeSEric Cheng 	if (tot_stats) {
3993*da14cebeSEric Cheng 		if (tot_stats->ipackets == 0) {
3994*da14cebeSEric Cheng 			(void) printf("\t-");
3995*da14cebeSEric Cheng 		} else {
3996*da14cebeSEric Cheng 			(void) printf("\t%-6.1f", (double)diff_stats.ipackets/
3997*da14cebeSEric Cheng 			    (double)tot_stats->ipackets * 100);
3998*da14cebeSEric Cheng 		}
3999*da14cebeSEric Cheng 		if (tot_stats->opackets == 0) {
4000*da14cebeSEric Cheng 			(void) printf("\t-");
4001*da14cebeSEric Cheng 		} else {
4002*da14cebeSEric Cheng 			(void) printf("\t%-6.1f", (double)diff_stats.opackets/
4003*da14cebeSEric Cheng 			    (double)tot_stats->opackets * 100);
4004*da14cebeSEric Cheng 		}
4005*da14cebeSEric Cheng 	}
4006*da14cebeSEric Cheng 	(void) printf("\n");
4007*da14cebeSEric Cheng 
4008*da14cebeSEric Cheng 	*old_stats = *vnic_stats;
4009*da14cebeSEric Cheng }
4010*da14cebeSEric Cheng 
4011*da14cebeSEric Cheng /*
4012*da14cebeSEric Cheng  * Called from the walker dladm_vnic_walk_sys() for each vnic to display
4013*da14cebeSEric Cheng  * vnic information or statistics.
4014*da14cebeSEric Cheng  */
4015*da14cebeSEric Cheng static dladm_status_t
4016*da14cebeSEric Cheng print_vnic(show_vnic_state_t *state, datalink_id_t linkid)
4017*da14cebeSEric Cheng {
4018*da14cebeSEric Cheng 	dladm_vnic_attr_t	attr, *vnic = &attr;
4019*da14cebeSEric Cheng 	dladm_status_t		status;
4020*da14cebeSEric Cheng 	boolean_t		is_etherstub;
4021*da14cebeSEric Cheng 	char			devname[MAXLINKNAMELEN];
4022*da14cebeSEric Cheng 	char			vnic_name[MAXLINKNAMELEN];
4023*da14cebeSEric Cheng 	char			mstr[MAXMACADDRLEN * 3];
4024*da14cebeSEric Cheng 	vnic_fields_buf_t	vbuf;
4025*da14cebeSEric Cheng 
4026*da14cebeSEric Cheng 	if ((status = dladm_vnic_info(linkid, vnic, state->vs_flags)) !=
4027*da14cebeSEric Cheng 	    DLADM_STATUS_OK)
4028*da14cebeSEric Cheng 		return (status);
4029*da14cebeSEric Cheng 
4030*da14cebeSEric Cheng 	is_etherstub = (vnic->va_link_id == DATALINK_INVALID_LINKID);
4031*da14cebeSEric Cheng 	if (state->vs_etherstub != is_etherstub) {
4032*da14cebeSEric Cheng 		/*
4033*da14cebeSEric Cheng 		 * Want all etherstub but it's not one, or want
4034*da14cebeSEric Cheng 		 * non-etherstub and it's one.
4035*da14cebeSEric Cheng 		 */
4036*da14cebeSEric Cheng 		return (DLADM_STATUS_OK);
4037*da14cebeSEric Cheng 	}
4038*da14cebeSEric Cheng 
4039*da14cebeSEric Cheng 	if (state->vs_link_id != DATALINK_ALL_LINKID) {
4040*da14cebeSEric Cheng 		if (state->vs_link_id != vnic->va_link_id)
4041*da14cebeSEric Cheng 			return (DLADM_STATUS_OK);
4042*da14cebeSEric Cheng 	}
4043*da14cebeSEric Cheng 
4044*da14cebeSEric Cheng 	if (dladm_datalink_id2info(linkid, NULL, NULL,
4045*da14cebeSEric Cheng 	    NULL, vnic_name, sizeof (vnic_name)) != DLADM_STATUS_OK)
4046*da14cebeSEric Cheng 		return (DLADM_STATUS_BADARG);
4047*da14cebeSEric Cheng 
4048*da14cebeSEric Cheng 	bzero(devname, sizeof (devname));
4049*da14cebeSEric Cheng 	if (!is_etherstub &&
4050*da14cebeSEric Cheng 	    dladm_datalink_id2info(vnic->va_link_id, NULL, NULL,
4051*da14cebeSEric Cheng 	    NULL, devname, sizeof (devname)) != DLADM_STATUS_OK)
4052*da14cebeSEric Cheng 		return (DLADM_STATUS_BADARG);
4053*da14cebeSEric Cheng 
4054*da14cebeSEric Cheng 	state->vs_found = B_TRUE;
4055*da14cebeSEric Cheng 	if (state->vs_stats) {
4056*da14cebeSEric Cheng 		/* print vnic statistics */
4057*da14cebeSEric Cheng 		pktsum_t vnic_stats;
4058*da14cebeSEric Cheng 
4059*da14cebeSEric Cheng 		if (state->vs_firstonly) {
4060*da14cebeSEric Cheng 			if (state->vs_donefirst)
4061*da14cebeSEric Cheng 				return (0);
4062*da14cebeSEric Cheng 			state->vs_donefirst = B_TRUE;
4063*da14cebeSEric Cheng 		}
4064*da14cebeSEric Cheng 
4065*da14cebeSEric Cheng 		if (!state->vs_printstats) {
4066*da14cebeSEric Cheng 			/*
4067*da14cebeSEric Cheng 			 * get vnic statistics and add to the sum for the
4068*da14cebeSEric Cheng 			 * named device.
4069*da14cebeSEric Cheng 			 */
4070*da14cebeSEric Cheng 			get_link_stats(vnic_name, &vnic_stats);
4071*da14cebeSEric Cheng 			dladm_stats_total(&state->vs_totalstats, &vnic_stats,
4072*da14cebeSEric Cheng 			    &state->vs_prevstats[vnic->va_vnic_id]);
4073*da14cebeSEric Cheng 		} else {
4074*da14cebeSEric Cheng 			/* get and print vnic statistics */
4075*da14cebeSEric Cheng 			get_link_stats(vnic_name, &vnic_stats);
4076*da14cebeSEric Cheng 			dump_vnic_stat(vnic_name, linkid, state, &vnic_stats,
4077*da14cebeSEric Cheng 			    &state->vs_totalstats);
4078*da14cebeSEric Cheng 		}
4079*da14cebeSEric Cheng 		return (DLADM_STATUS_OK);
4080*da14cebeSEric Cheng 	} else {
4081*da14cebeSEric Cheng 		(void) snprintf(vbuf.vnic_link, sizeof (vbuf.vnic_link),
4082*da14cebeSEric Cheng 		    "%s", vnic_name);
4083*da14cebeSEric Cheng 
4084*da14cebeSEric Cheng 		if (!is_etherstub) {
4085*da14cebeSEric Cheng 
4086*da14cebeSEric Cheng 			(void) snprintf(vbuf.vnic_over, sizeof (vbuf.vnic_over),
4087*da14cebeSEric Cheng 			    "%s", devname);
4088*da14cebeSEric Cheng 			(void) snprintf(vbuf.vnic_speed,
4089*da14cebeSEric Cheng 			    sizeof (vbuf.vnic_speed), "%u",
4090*da14cebeSEric Cheng 			    (uint_t)((get_ifspeed(vnic_name, B_TRUE))
4091*da14cebeSEric Cheng 			    / 1000000ull));
4092*da14cebeSEric Cheng 
4093*da14cebeSEric Cheng 			switch (vnic->va_mac_addr_type) {
4094*da14cebeSEric Cheng 			case VNIC_MAC_ADDR_TYPE_FIXED:
4095*da14cebeSEric Cheng 			case VNIC_MAC_ADDR_TYPE_PRIMARY:
4096*da14cebeSEric Cheng 				(void) snprintf(vbuf.vnic_macaddrtype,
4097*da14cebeSEric Cheng 				    sizeof (vbuf.vnic_macaddrtype),
4098*da14cebeSEric Cheng 				    gettext("fixed"));
4099*da14cebeSEric Cheng 				break;
4100*da14cebeSEric Cheng 			case VNIC_MAC_ADDR_TYPE_RANDOM:
4101*da14cebeSEric Cheng 				(void) snprintf(vbuf.vnic_macaddrtype,
4102*da14cebeSEric Cheng 				    sizeof (vbuf.vnic_macaddrtype),
4103*da14cebeSEric Cheng 				    gettext("random"));
4104*da14cebeSEric Cheng 				break;
4105*da14cebeSEric Cheng 			case VNIC_MAC_ADDR_TYPE_FACTORY:
4106*da14cebeSEric Cheng 				(void) snprintf(vbuf.vnic_macaddrtype,
4107*da14cebeSEric Cheng 				    sizeof (vbuf.vnic_macaddrtype),
4108*da14cebeSEric Cheng 				    gettext("factory, slot %d"),
4109*da14cebeSEric Cheng 				    vnic->va_mac_slot);
4110*da14cebeSEric Cheng 				break;
4111*da14cebeSEric Cheng 			}
4112*da14cebeSEric Cheng 
4113*da14cebeSEric Cheng 			if (strlen(vbuf.vnic_macaddrtype) > 0) {
4114*da14cebeSEric Cheng 				(void) snprintf(vbuf.vnic_macaddr,
4115*da14cebeSEric Cheng 				    sizeof (vbuf.vnic_macaddr), "%s",
4116*da14cebeSEric Cheng 				    dladm_aggr_macaddr2str(vnic->va_mac_addr,
4117*da14cebeSEric Cheng 				    mstr));
4118*da14cebeSEric Cheng 			}
4119*da14cebeSEric Cheng 
4120*da14cebeSEric Cheng 			(void) snprintf(vbuf.vnic_vid, sizeof (vbuf.vnic_vid),
4121*da14cebeSEric Cheng 			    "%d", vnic->va_vid);
4122*da14cebeSEric Cheng 		}
4123*da14cebeSEric Cheng 
4124*da14cebeSEric Cheng 		if (!state->vs_parseable && !state->vs_printheader) {
4125*da14cebeSEric Cheng 			print_header(&state->vs_print);
4126*da14cebeSEric Cheng 			state->vs_printheader = B_TRUE;
4127*da14cebeSEric Cheng 		}
4128*da14cebeSEric Cheng 
4129*da14cebeSEric Cheng 		dladm_print_output(&state->vs_print, state->vs_parseable,
4130*da14cebeSEric Cheng 		    dladm_print_field, (void *)&vbuf);
4131*da14cebeSEric Cheng 
4132*da14cebeSEric Cheng 		return (DLADM_STATUS_OK);
4133*da14cebeSEric Cheng 	}
4134*da14cebeSEric Cheng }
4135*da14cebeSEric Cheng 
4136*da14cebeSEric Cheng static int
4137*da14cebeSEric Cheng show_vnic(datalink_id_t linkid, void *arg)
4138*da14cebeSEric Cheng {
4139*da14cebeSEric Cheng 	show_vnic_state_t	*state = arg;
4140*da14cebeSEric Cheng 
4141*da14cebeSEric Cheng 	state->vs_status = print_vnic(state, linkid);
4142*da14cebeSEric Cheng 	return (DLADM_WALK_CONTINUE);
4143*da14cebeSEric Cheng }
4144*da14cebeSEric Cheng 
4145*da14cebeSEric Cheng static void
4146*da14cebeSEric Cheng do_show_vnic_common(int argc, char *argv[], const char *use,
4147*da14cebeSEric Cheng     boolean_t etherstub)
4148*da14cebeSEric Cheng {
4149*da14cebeSEric Cheng 	int			option;
4150*da14cebeSEric Cheng 	boolean_t		s_arg = B_FALSE;
4151*da14cebeSEric Cheng 	boolean_t		i_arg = B_FALSE;
4152*da14cebeSEric Cheng 	boolean_t		l_arg = B_FALSE;
4153*da14cebeSEric Cheng 	char			*endp = NULL;
4154*da14cebeSEric Cheng 	uint32_t		interval = 0, flags = DLADM_OPT_ACTIVE;
4155*da14cebeSEric Cheng 	datalink_id_t		linkid = DATALINK_ALL_LINKID;
4156*da14cebeSEric Cheng 	datalink_id_t		dev_linkid = DATALINK_ALL_LINKID;
4157*da14cebeSEric Cheng 	show_vnic_state_t	state;
4158*da14cebeSEric Cheng 	dladm_status_t		status;
4159*da14cebeSEric Cheng 	boolean_t		o_arg = B_FALSE;
4160*da14cebeSEric Cheng 	char			*fields_str = NULL;
4161*da14cebeSEric Cheng 	print_field_t  		**fields;
4162*da14cebeSEric Cheng 	print_field_t		*pf;
4163*da14cebeSEric Cheng 	int			pfmax;
4164*da14cebeSEric Cheng 	uint_t			nfields;
4165*da14cebeSEric Cheng 	char			*all_fields =
4166*da14cebeSEric Cheng 	    "link,over,speed,macaddr,macaddrtype,vid";
4167*da14cebeSEric Cheng 	char			*all_e_fields =
4168*da14cebeSEric Cheng 	    "link";
4169*da14cebeSEric Cheng 
4170*da14cebeSEric Cheng 	bzero(&state, sizeof (state));
4171*da14cebeSEric Cheng 	opterr = 0;
4172*da14cebeSEric Cheng 	while ((option = getopt_long(argc, argv, ":pPl:si:o:", lopts,
4173*da14cebeSEric Cheng 	    NULL)) != -1) {
4174*da14cebeSEric Cheng 		switch (option) {
4175*da14cebeSEric Cheng 		case 'p':
4176*da14cebeSEric Cheng 			state.vs_parseable = B_TRUE;
4177*da14cebeSEric Cheng 			break;
4178*da14cebeSEric Cheng 		case 'P':
4179*da14cebeSEric Cheng 			flags = DLADM_OPT_PERSIST;
4180*da14cebeSEric Cheng 			break;
4181*da14cebeSEric Cheng 		case 'l':
4182*da14cebeSEric Cheng 			if (etherstub)
4183*da14cebeSEric Cheng 				die("option not supported for this command");
4184*da14cebeSEric Cheng 
4185*da14cebeSEric Cheng 			if (strlcpy(state.vs_link, optarg, MAXLINKNAMELEN) >=
4186*da14cebeSEric Cheng 			    MAXLINKNAMELEN)
4187*da14cebeSEric Cheng 				die("link name too long");
4188*da14cebeSEric Cheng 
4189*da14cebeSEric Cheng 			l_arg = B_TRUE;
4190*da14cebeSEric Cheng 			break;
4191*da14cebeSEric Cheng 		case 's':
4192*da14cebeSEric Cheng 			if (s_arg) {
4193*da14cebeSEric Cheng 				die("the option -s cannot be specified "
4194*da14cebeSEric Cheng 				    "more than once");
4195*da14cebeSEric Cheng 			}
4196*da14cebeSEric Cheng 			s_arg = B_TRUE;
4197*da14cebeSEric Cheng 			break;
4198*da14cebeSEric Cheng 		case 'i':
4199*da14cebeSEric Cheng 			if (i_arg) {
4200*da14cebeSEric Cheng 				die("the option -i cannot be specified "
4201*da14cebeSEric Cheng 				    "more than once");
4202*da14cebeSEric Cheng 			}
4203*da14cebeSEric Cheng 			i_arg = B_TRUE;
4204*da14cebeSEric Cheng 			interval = (int)strtol(optarg, &endp, 10);
4205*da14cebeSEric Cheng 			if (errno != 0 || interval == 0 || *endp != '\0')
4206*da14cebeSEric Cheng 				die("invalid interval value '%s'", optarg);
4207*da14cebeSEric Cheng 			break;
4208*da14cebeSEric Cheng 		case 'o':
4209*da14cebeSEric Cheng 			o_arg = B_TRUE;
4210*da14cebeSEric Cheng 			fields_str = optarg;
4211*da14cebeSEric Cheng 			break;
4212*da14cebeSEric Cheng 		default:
4213*da14cebeSEric Cheng 			die_opterr(optopt, option, use);
4214*da14cebeSEric Cheng 		}
4215*da14cebeSEric Cheng 	}
4216*da14cebeSEric Cheng 
4217*da14cebeSEric Cheng 	if (i_arg && !s_arg)
4218*da14cebeSEric Cheng 		die("the option -i can be used only with -s");
4219*da14cebeSEric Cheng 
4220*da14cebeSEric Cheng 	/* get vnic ID (optional last argument) */
4221*da14cebeSEric Cheng 	if (optind == (argc - 1)) {
4222*da14cebeSEric Cheng 		status = dladm_name2info(argv[optind], &linkid, NULL,
4223*da14cebeSEric Cheng 		    NULL, NULL);
4224*da14cebeSEric Cheng 		if (status != DLADM_STATUS_OK) {
4225*da14cebeSEric Cheng 			die_dlerr(status, "invalid vnic name '%s'",
4226*da14cebeSEric Cheng 			    argv[optind]);
4227*da14cebeSEric Cheng 		}
4228*da14cebeSEric Cheng 		(void) strlcpy(state.vs_vnic, argv[optind], MAXLINKNAMELEN);
4229*da14cebeSEric Cheng 	} else if (optind != argc) {
4230*da14cebeSEric Cheng 		usage();
4231*da14cebeSEric Cheng 	}
4232*da14cebeSEric Cheng 
4233*da14cebeSEric Cheng 	if (l_arg) {
4234*da14cebeSEric Cheng 		status = dladm_name2info(state.vs_link, &dev_linkid, NULL,
4235*da14cebeSEric Cheng 		    NULL, NULL);
4236*da14cebeSEric Cheng 		if (status != DLADM_STATUS_OK) {
4237*da14cebeSEric Cheng 			die_dlerr(status, "invalid link name '%s'",
4238*da14cebeSEric Cheng 			    state.vs_link);
4239*da14cebeSEric Cheng 		}
4240*da14cebeSEric Cheng 	}
4241*da14cebeSEric Cheng 
4242*da14cebeSEric Cheng 	state.vs_vnic_id = linkid;
4243*da14cebeSEric Cheng 	state.vs_link_id = dev_linkid;
4244*da14cebeSEric Cheng 	state.vs_etherstub = etherstub;
4245*da14cebeSEric Cheng 	state.vs_found = B_FALSE;
4246*da14cebeSEric Cheng 	state.vs_flags = flags;
4247*da14cebeSEric Cheng 
4248*da14cebeSEric Cheng 	if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) {
4249*da14cebeSEric Cheng 		if (etherstub)
4250*da14cebeSEric Cheng 			fields_str = all_e_fields;
4251*da14cebeSEric Cheng 		else
4252*da14cebeSEric Cheng 			fields_str = all_fields;
4253*da14cebeSEric Cheng 	}
4254*da14cebeSEric Cheng 
4255*da14cebeSEric Cheng 	pf = vnic_fields;
4256*da14cebeSEric Cheng 	pfmax = VNIC_MAX_FIELDS;
4257*da14cebeSEric Cheng 
4258*da14cebeSEric Cheng 	fields = parse_output_fields(fields_str, pf, pfmax, CMD_TYPE_ANY,
4259*da14cebeSEric Cheng 	    &nfields);
4260*da14cebeSEric Cheng 
4261*da14cebeSEric Cheng 	if (fields == NULL) {
4262*da14cebeSEric Cheng 		die("invalid field(s) specified");
4263*da14cebeSEric Cheng 		return;
4264*da14cebeSEric Cheng 	}
4265*da14cebeSEric Cheng 
4266*da14cebeSEric Cheng 	state.vs_print.ps_fields = fields;
4267*da14cebeSEric Cheng 	state.vs_print.ps_nfields = nfields;
4268*da14cebeSEric Cheng 
4269*da14cebeSEric Cheng 	if (s_arg) {
4270*da14cebeSEric Cheng 		/* Display vnic statistics */
4271*da14cebeSEric Cheng 		vnic_stats(&state, interval);
4272*da14cebeSEric Cheng 		return;
4273*da14cebeSEric Cheng 	}
4274*da14cebeSEric Cheng 
4275*da14cebeSEric Cheng 	/* Display vnic information */
4276*da14cebeSEric Cheng 	state.vs_donefirst = B_FALSE;
4277*da14cebeSEric Cheng 
4278*da14cebeSEric Cheng 	if (linkid == DATALINK_ALL_LINKID) {
4279*da14cebeSEric Cheng 		(void) dladm_walk_datalink_id(show_vnic, &state,
4280*da14cebeSEric Cheng 		    DATALINK_CLASS_VNIC | DATALINK_CLASS_ETHERSTUB,
4281*da14cebeSEric Cheng 		    DATALINK_ANY_MEDIATYPE, DLADM_OPT_ACTIVE);
4282*da14cebeSEric Cheng 	} else {
4283*da14cebeSEric Cheng 		(void) show_vnic(linkid, &state);
4284*da14cebeSEric Cheng 		if (state.vs_status != DLADM_STATUS_OK) {
4285*da14cebeSEric Cheng 			die_dlerr(state.vs_status, "failed to show vnic '%s'",
4286*da14cebeSEric Cheng 			    state.vs_vnic);
4287*da14cebeSEric Cheng 		}
4288*da14cebeSEric Cheng 	}
4289*da14cebeSEric Cheng }
4290*da14cebeSEric Cheng 
4291*da14cebeSEric Cheng static void
4292*da14cebeSEric Cheng do_show_vnic(int argc, char *argv[], const char *use)
4293*da14cebeSEric Cheng {
4294*da14cebeSEric Cheng 	do_show_vnic_common(argc, argv, use, B_FALSE);
4295*da14cebeSEric Cheng }
4296*da14cebeSEric Cheng 
4297*da14cebeSEric Cheng static void
4298*da14cebeSEric Cheng do_create_etherstub(int argc, char *argv[], const char *use)
4299*da14cebeSEric Cheng {
4300*da14cebeSEric Cheng 	uint32_t flags;
4301*da14cebeSEric Cheng 	char *altroot = NULL;
4302*da14cebeSEric Cheng 	char option;
4303*da14cebeSEric Cheng 	dladm_status_t status;
4304*da14cebeSEric Cheng 	char name[MAXLINKNAMELEN];
4305*da14cebeSEric Cheng 	uchar_t mac_addr[ETHERADDRL];
4306*da14cebeSEric Cheng 
4307*da14cebeSEric Cheng 	name[0] = '\0';
4308*da14cebeSEric Cheng 	bzero(mac_addr, sizeof (mac_addr));
4309*da14cebeSEric Cheng 	flags = DLADM_OPT_ANCHOR | DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
4310*da14cebeSEric Cheng 
4311*da14cebeSEric Cheng 	opterr = 0;
4312*da14cebeSEric Cheng 	while ((option = getopt_long(argc, argv, "tR:",
4313*da14cebeSEric Cheng 	    etherstub_lopts, NULL)) != -1) {
4314*da14cebeSEric Cheng 		switch (option) {
4315*da14cebeSEric Cheng 		case 't':
4316*da14cebeSEric Cheng 			flags &= ~DLADM_OPT_PERSIST;
4317*da14cebeSEric Cheng 			break;
4318*da14cebeSEric Cheng 		case 'R':
4319*da14cebeSEric Cheng 			altroot = optarg;
4320*da14cebeSEric Cheng 			break;
4321*da14cebeSEric Cheng 		default:
4322*da14cebeSEric Cheng 			die_opterr(optopt, option, use);
4323*da14cebeSEric Cheng 		}
4324*da14cebeSEric Cheng 	}
4325*da14cebeSEric Cheng 
4326*da14cebeSEric Cheng 	/* the etherstub id is the required operand */
4327*da14cebeSEric Cheng 	if (optind != (argc - 1))
4328*da14cebeSEric Cheng 		usage();
4329*da14cebeSEric Cheng 
4330*da14cebeSEric Cheng 	if (strlcpy(name, argv[optind], MAXLINKNAMELEN) >= MAXLINKNAMELEN)
4331*da14cebeSEric Cheng 		die("link name too long '%s'", argv[optind]);
4332*da14cebeSEric Cheng 
4333*da14cebeSEric Cheng 	if (!dladm_valid_linkname(name))
4334*da14cebeSEric Cheng 		die("invalid link name '%s'", argv[optind]);
4335*da14cebeSEric Cheng 
4336*da14cebeSEric Cheng 	if (altroot != NULL)
4337*da14cebeSEric Cheng 		altroot_cmd(altroot, argc, argv);
4338*da14cebeSEric Cheng 
4339*da14cebeSEric Cheng 	status = dladm_vnic_create(name, DATALINK_INVALID_LINKID,
4340*da14cebeSEric Cheng 	    VNIC_MAC_ADDR_TYPE_AUTO, mac_addr, ETHERADDRL, NULL, 0, 0, NULL,
4341*da14cebeSEric Cheng 	    NULL, flags);
4342*da14cebeSEric Cheng 	if (status != DLADM_STATUS_OK)
4343*da14cebeSEric Cheng 		die_dlerr(status, "etherstub creation failed");
4344*da14cebeSEric Cheng 
4345*da14cebeSEric Cheng 
4346*da14cebeSEric Cheng }
4347*da14cebeSEric Cheng 
4348*da14cebeSEric Cheng static void
4349*da14cebeSEric Cheng do_delete_etherstub(int argc, char *argv[], const char *use)
4350*da14cebeSEric Cheng {
4351*da14cebeSEric Cheng 	do_delete_vnic_common(argc, argv, use, B_TRUE);
4352*da14cebeSEric Cheng }
4353*da14cebeSEric Cheng 
4354*da14cebeSEric Cheng /* ARGSUSED */
4355*da14cebeSEric Cheng static void
4356*da14cebeSEric Cheng do_show_etherstub(int argc, char *argv[], const char *use)
4357*da14cebeSEric Cheng {
4358*da14cebeSEric Cheng 	do_show_vnic_common(argc, argv, use, B_TRUE);
4359*da14cebeSEric Cheng }
4360*da14cebeSEric Cheng 
4361*da14cebeSEric Cheng static void
43626be03d0bSVasumathi Sundaram - Sun Microsystems link_stats(datalink_id_t linkid, uint_t interval, char *fields_str,
43636be03d0bSVasumathi Sundaram - Sun Microsystems     show_state_t *state)
4364d62bc4baSyz147064 {
43656be03d0bSVasumathi Sundaram - Sun Microsystems 	print_field_t	**fields;
43666be03d0bSVasumathi Sundaram - Sun Microsystems 	uint_t		nfields;
436733343a97Smeem 
43686be03d0bSVasumathi Sundaram - Sun Microsystems 	fields = parse_output_fields(fields_str, devs_fields, DEVS_MAX_FIELDS,
43696be03d0bSVasumathi Sundaram - Sun Microsystems 	    CMD_TYPE_ANY, &nfields);
43706be03d0bSVasumathi Sundaram - Sun Microsystems 	if (fields == NULL) {
43716be03d0bSVasumathi Sundaram - Sun Microsystems 		die("invalid field(s) specified");
43726be03d0bSVasumathi Sundaram - Sun Microsystems 		return;
43736be03d0bSVasumathi Sundaram - Sun Microsystems 	}
43746be03d0bSVasumathi Sundaram - Sun Microsystems 
43756be03d0bSVasumathi Sundaram - Sun Microsystems 	state->ls_print.ps_fields = fields;
43766be03d0bSVasumathi Sundaram - Sun Microsystems 	state->ls_print.ps_nfields = nfields;
43777c478bd9Sstevel@tonic-gate 
43787c478bd9Sstevel@tonic-gate 	/*
43797c478bd9Sstevel@tonic-gate 	 * If an interval is specified, continuously show the stats
43807c478bd9Sstevel@tonic-gate 	 * only for the first MAC port.
43817c478bd9Sstevel@tonic-gate 	 */
43826be03d0bSVasumathi Sundaram - Sun Microsystems 	state->ls_firstonly = (interval != 0);
43837c478bd9Sstevel@tonic-gate 
43846be03d0bSVasumathi Sundaram - Sun Microsystems 	if (!state->ls_parseable)
43856be03d0bSVasumathi Sundaram - Sun Microsystems 		print_header(&state->ls_print);
43867c478bd9Sstevel@tonic-gate 	for (;;) {
43876be03d0bSVasumathi Sundaram - Sun Microsystems 		state->ls_donefirst = B_FALSE;
4388d62bc4baSyz147064 		if (linkid == DATALINK_ALL_LINKID) {
43896be03d0bSVasumathi Sundaram - Sun Microsystems 			(void) dladm_walk_datalink_id(show_link_stats, state,
4390d62bc4baSyz147064 			    DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE,
4391d62bc4baSyz147064 			    DLADM_OPT_ACTIVE);
4392d62bc4baSyz147064 		} else {
43936be03d0bSVasumathi Sundaram - Sun Microsystems 			(void) show_link_stats(linkid, state);
4394d62bc4baSyz147064 		}
43957c478bd9Sstevel@tonic-gate 
43967c478bd9Sstevel@tonic-gate 		if (interval == 0)
43977c478bd9Sstevel@tonic-gate 			break;
43987c478bd9Sstevel@tonic-gate 
43997c478bd9Sstevel@tonic-gate 		(void) sleep(interval);
44007c478bd9Sstevel@tonic-gate 	}
44017c478bd9Sstevel@tonic-gate }
44027c478bd9Sstevel@tonic-gate 
44037c478bd9Sstevel@tonic-gate static void
4404d62bc4baSyz147064 aggr_stats(datalink_id_t linkid, show_grp_state_t *state, uint_t interval)
44057c478bd9Sstevel@tonic-gate {
44067c478bd9Sstevel@tonic-gate 	/*
44077c478bd9Sstevel@tonic-gate 	 * If an interval is specified, continuously show the stats
44087c478bd9Sstevel@tonic-gate 	 * only for the first group.
44097c478bd9Sstevel@tonic-gate 	 */
4410d62bc4baSyz147064 	state->gs_firstonly = (interval != 0);
44117c478bd9Sstevel@tonic-gate 
44127c478bd9Sstevel@tonic-gate 	for (;;) {
4413d62bc4baSyz147064 		state->gs_donefirst = B_FALSE;
4414d62bc4baSyz147064 		if (linkid == DATALINK_ALL_LINKID)
4415d62bc4baSyz147064 			(void) dladm_walk_datalink_id(show_aggr, state,
4416d62bc4baSyz147064 			    DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE,
4417d62bc4baSyz147064 			    DLADM_OPT_ACTIVE);
4418d62bc4baSyz147064 		else
4419d62bc4baSyz147064 			(void) show_aggr(linkid, state);
44207c478bd9Sstevel@tonic-gate 
44217c478bd9Sstevel@tonic-gate 		if (interval == 0)
44227c478bd9Sstevel@tonic-gate 			break;
44237c478bd9Sstevel@tonic-gate 
44247c478bd9Sstevel@tonic-gate 		(void) sleep(interval);
44257c478bd9Sstevel@tonic-gate 	}
44267c478bd9Sstevel@tonic-gate }
44277c478bd9Sstevel@tonic-gate 
4428*da14cebeSEric Cheng /* ARGSUSED */
44297c478bd9Sstevel@tonic-gate static void
4430*da14cebeSEric Cheng vnic_stats(show_vnic_state_t *sp, uint32_t interval)
44317c478bd9Sstevel@tonic-gate {
4432*da14cebeSEric Cheng 	show_vnic_state_t	state;
4433*da14cebeSEric Cheng 	boolean_t		specific_link, specific_dev;
44347c478bd9Sstevel@tonic-gate 
4435*da14cebeSEric Cheng 	/* Display vnic statistics */
4436*da14cebeSEric Cheng 	dump_vnics_head(sp->vs_link);
4437e7801d59Ssowmini 
4438*da14cebeSEric Cheng 	bzero(&state, sizeof (state));
4439*da14cebeSEric Cheng 	state.vs_stats = B_TRUE;
4440*da14cebeSEric Cheng 	state.vs_vnic_id = sp->vs_vnic_id;
4441*da14cebeSEric Cheng 	state.vs_link_id = sp->vs_link_id;
44427c478bd9Sstevel@tonic-gate 
44437c478bd9Sstevel@tonic-gate 	/*
4444*da14cebeSEric Cheng 	 * If an interval is specified, and a vnic ID is not specified,
4445*da14cebeSEric Cheng 	 * continuously show the stats only for the first vnic.
44467c478bd9Sstevel@tonic-gate 	 */
4447*da14cebeSEric Cheng 	specific_link = (sp->vs_vnic_id != DATALINK_ALL_LINKID);
4448*da14cebeSEric Cheng 	specific_dev = (sp->vs_link_id != DATALINK_ALL_LINKID);
44497c478bd9Sstevel@tonic-gate 
44507c478bd9Sstevel@tonic-gate 	for (;;) {
4451*da14cebeSEric Cheng 		/* Get stats for each vnic */
4452*da14cebeSEric Cheng 		state.vs_found = B_FALSE;
4453*da14cebeSEric Cheng 		state.vs_donefirst = B_FALSE;
4454*da14cebeSEric Cheng 		state.vs_printstats = B_FALSE;
4455*da14cebeSEric Cheng 		state.vs_flags = DLADM_OPT_ACTIVE;
44567c478bd9Sstevel@tonic-gate 
4457*da14cebeSEric Cheng 		if (!specific_link) {
4458*da14cebeSEric Cheng 			(void) dladm_walk_datalink_id(show_vnic, &state,
4459*da14cebeSEric Cheng 			    DATALINK_CLASS_VNIC, DATALINK_ANY_MEDIATYPE,
4460*da14cebeSEric Cheng 			    DLADM_OPT_ACTIVE);
4461*da14cebeSEric Cheng 		} else {
4462*da14cebeSEric Cheng 			(void) show_vnic(sp->vs_vnic_id, &state);
4463*da14cebeSEric Cheng 			if (state.vs_status != DLADM_STATUS_OK) {
4464*da14cebeSEric Cheng 				die_dlerr(state.vs_status,
4465*da14cebeSEric Cheng 				    "failed to show vnic '%s'", sp->vs_vnic);
4466*da14cebeSEric Cheng 			}
4467*da14cebeSEric Cheng 		}
44687c478bd9Sstevel@tonic-gate 
4469*da14cebeSEric Cheng 		if (specific_link && !state.vs_found)
4470*da14cebeSEric Cheng 			die("non-existent vnic '%s'", sp->vs_vnic);
4471*da14cebeSEric Cheng 		if (specific_dev && !state.vs_found)
4472*da14cebeSEric Cheng 			die("device %s has no vnics", sp->vs_link);
4473*da14cebeSEric Cheng 
4474*da14cebeSEric Cheng 		/* Show totals */
4475*da14cebeSEric Cheng 		if ((specific_link | specific_dev) && !interval) {
4476*da14cebeSEric Cheng 			(void) printf("Total");
4477*da14cebeSEric Cheng 			(void) printf("\t%-10llu",
4478*da14cebeSEric Cheng 			    state.vs_totalstats.ipackets);
4479*da14cebeSEric Cheng 			(void) printf("%-12llu",
4480*da14cebeSEric Cheng 			    state.vs_totalstats.rbytes);
4481*da14cebeSEric Cheng 			(void) printf("%-10llu",
4482*da14cebeSEric Cheng 			    state.vs_totalstats.opackets);
4483*da14cebeSEric Cheng 			(void) printf("%-12llu\n",
4484*da14cebeSEric Cheng 			    state.vs_totalstats.obytes);
4485*da14cebeSEric Cheng 		}
4486*da14cebeSEric Cheng 
4487*da14cebeSEric Cheng 		/* Show stats for each vnic */
4488*da14cebeSEric Cheng 		state.vs_donefirst = B_FALSE;
4489*da14cebeSEric Cheng 		state.vs_printstats = B_TRUE;
4490*da14cebeSEric Cheng 
4491*da14cebeSEric Cheng 		if (!specific_link) {
4492*da14cebeSEric Cheng 			(void) dladm_walk_datalink_id(show_vnic, &state,
4493*da14cebeSEric Cheng 			    DATALINK_CLASS_VNIC, DATALINK_ANY_MEDIATYPE,
4494*da14cebeSEric Cheng 			    DLADM_OPT_ACTIVE);
4495*da14cebeSEric Cheng 		} else {
4496*da14cebeSEric Cheng 			(void) show_vnic(sp->vs_vnic_id, &state);
4497*da14cebeSEric Cheng 			if (state.vs_status != DLADM_STATUS_OK) {
4498*da14cebeSEric Cheng 				die_dlerr(state.vs_status,
4499*da14cebeSEric Cheng 				    "failed to show vnic '%s'", sp->vs_vnic);
4500*da14cebeSEric Cheng 			}
4501*da14cebeSEric Cheng 		}
45027c478bd9Sstevel@tonic-gate 
45037c478bd9Sstevel@tonic-gate 		if (interval == 0)
45047c478bd9Sstevel@tonic-gate 			break;
45057c478bd9Sstevel@tonic-gate 
45067c478bd9Sstevel@tonic-gate 		(void) sleep(interval);
45077c478bd9Sstevel@tonic-gate 	}
45087c478bd9Sstevel@tonic-gate }
45097c478bd9Sstevel@tonic-gate 
45107c478bd9Sstevel@tonic-gate static void
4511*da14cebeSEric Cheng get_mac_stats(const char *dev, pktsum_t *stats)
45127c478bd9Sstevel@tonic-gate {
45137c478bd9Sstevel@tonic-gate 	kstat_ctl_t	*kcp;
45147c478bd9Sstevel@tonic-gate 	kstat_t		*ksp;
4515*da14cebeSEric Cheng 	char module[DLPI_LINKNAME_MAX];
4516*da14cebeSEric Cheng 	uint_t instance;
4517*da14cebeSEric Cheng 
4518*da14cebeSEric Cheng 
4519*da14cebeSEric Cheng 	bzero(stats, sizeof (*stats));
4520*da14cebeSEric Cheng 
4521*da14cebeSEric Cheng 	if (dlpi_parselink(dev, module, &instance) != DLPI_SUCCESS)
4522*da14cebeSEric Cheng 		return;
45237c478bd9Sstevel@tonic-gate 
45247c478bd9Sstevel@tonic-gate 	if ((kcp = kstat_open()) == NULL) {
452533343a97Smeem 		warn("kstat open operation failed");
45267c478bd9Sstevel@tonic-gate 		return;
45277c478bd9Sstevel@tonic-gate 	}
45287c478bd9Sstevel@tonic-gate 
4529*da14cebeSEric Cheng 	ksp = dladm_kstat_lookup(kcp, module, instance, "mac", NULL);
4530*da14cebeSEric Cheng 	if (ksp != NULL)
4531*da14cebeSEric Cheng 		dladm_get_stats(kcp, ksp, stats);
4532*da14cebeSEric Cheng 
45337c478bd9Sstevel@tonic-gate 	(void) kstat_close(kcp);
45347c478bd9Sstevel@tonic-gate 
45357c478bd9Sstevel@tonic-gate }
45367c478bd9Sstevel@tonic-gate 
45377c478bd9Sstevel@tonic-gate static void
45387c478bd9Sstevel@tonic-gate get_link_stats(const char *link, pktsum_t *stats)
45397c478bd9Sstevel@tonic-gate {
4540*da14cebeSEric Cheng 	kstat_ctl_t	*kcp;
4541*da14cebeSEric Cheng 	kstat_t		*ksp;
4542*da14cebeSEric Cheng 
45437c478bd9Sstevel@tonic-gate 	bzero(stats, sizeof (*stats));
4544*da14cebeSEric Cheng 
4545*da14cebeSEric Cheng 	if ((kcp = kstat_open()) == NULL) {
4546*da14cebeSEric Cheng 		warn("kstat_open operation failed");
4547*da14cebeSEric Cheng 		return;
4548*da14cebeSEric Cheng 	}
4549*da14cebeSEric Cheng 
4550*da14cebeSEric Cheng 	ksp = dladm_kstat_lookup(kcp, "link", 0, link, NULL);
4551*da14cebeSEric Cheng 
4552*da14cebeSEric Cheng 	if (ksp != NULL)
4553*da14cebeSEric Cheng 		dladm_get_stats(kcp, ksp, stats);
4554*da14cebeSEric Cheng 
4555*da14cebeSEric Cheng 	(void) kstat_close(kcp);
45567c478bd9Sstevel@tonic-gate }
45577c478bd9Sstevel@tonic-gate 
4558ba2e4443Sseb static int
4559d62bc4baSyz147064 query_kstat(char *module, int instance, const char *name, const char *stat,
4560d62bc4baSyz147064     uint8_t type, void *val)
45617c478bd9Sstevel@tonic-gate {
45627c478bd9Sstevel@tonic-gate 	kstat_ctl_t	*kcp;
45637c478bd9Sstevel@tonic-gate 	kstat_t		*ksp;
45647c478bd9Sstevel@tonic-gate 
45657c478bd9Sstevel@tonic-gate 	if ((kcp = kstat_open()) == NULL) {
456633343a97Smeem 		warn("kstat open operation failed");
4567ba2e4443Sseb 		return (-1);
45687c478bd9Sstevel@tonic-gate 	}
45697c478bd9Sstevel@tonic-gate 
4570d62bc4baSyz147064 	if ((ksp = kstat_lookup(kcp, module, instance, (char *)name)) == NULL) {
45717c478bd9Sstevel@tonic-gate 		/*
45727c478bd9Sstevel@tonic-gate 		 * The kstat query could fail if the underlying MAC
45737c478bd9Sstevel@tonic-gate 		 * driver was already detached.
45747c478bd9Sstevel@tonic-gate 		 */
45757c478bd9Sstevel@tonic-gate 		goto bail;
45767c478bd9Sstevel@tonic-gate 	}
45777c478bd9Sstevel@tonic-gate 
45787c478bd9Sstevel@tonic-gate 	if (kstat_read(kcp, ksp, NULL) == -1) {
457933343a97Smeem 		warn("kstat read failed");
45807c478bd9Sstevel@tonic-gate 		goto bail;
45817c478bd9Sstevel@tonic-gate 	}
45827c478bd9Sstevel@tonic-gate 
4583e7801d59Ssowmini 	if (dladm_kstat_value(ksp, stat, type, val) < 0)
45847c478bd9Sstevel@tonic-gate 		goto bail;
4585ba2e4443Sseb 
4586ba2e4443Sseb 	(void) kstat_close(kcp);
4587ba2e4443Sseb 	return (0);
45887c478bd9Sstevel@tonic-gate 
45897c478bd9Sstevel@tonic-gate bail:
45907c478bd9Sstevel@tonic-gate 	(void) kstat_close(kcp);
4591ba2e4443Sseb 	return (-1);
4592ba2e4443Sseb }
4593ba2e4443Sseb 
4594d62bc4baSyz147064 static int
4595d62bc4baSyz147064 get_one_kstat(const char *name, const char *stat, uint8_t type,
4596d62bc4baSyz147064     void *val, boolean_t islink)
4597d62bc4baSyz147064 {
4598d62bc4baSyz147064 	char		module[DLPI_LINKNAME_MAX];
4599d62bc4baSyz147064 	uint_t		instance;
4600d62bc4baSyz147064 
4601d62bc4baSyz147064 	if (islink) {
4602d62bc4baSyz147064 		return (query_kstat("link", 0, name, stat, type, val));
4603d62bc4baSyz147064 	} else {
4604d62bc4baSyz147064 		if (dlpi_parselink(name, module, &instance) != DLPI_SUCCESS)
4605d62bc4baSyz147064 			return (-1);
4606d62bc4baSyz147064 
4607d62bc4baSyz147064 		return (query_kstat(module, instance, "mac", stat, type, val));
4608d62bc4baSyz147064 	}
4609d62bc4baSyz147064 }
4610d62bc4baSyz147064 
4611ba2e4443Sseb static uint64_t
4612d62bc4baSyz147064 get_ifspeed(const char *name, boolean_t islink)
4613ba2e4443Sseb {
4614ba2e4443Sseb 	uint64_t ifspeed = 0;
4615ba2e4443Sseb 
4616d62bc4baSyz147064 	(void) get_one_kstat(name, "ifspeed", KSTAT_DATA_UINT64,
4617d62bc4baSyz147064 	    &ifspeed, islink);
4618d62bc4baSyz147064 
46197c478bd9Sstevel@tonic-gate 	return (ifspeed);
46207c478bd9Sstevel@tonic-gate }
46217c478bd9Sstevel@tonic-gate 
4622f595a68aSyz147064 static const char *
4623d62bc4baSyz147064 get_linkstate(const char *name, boolean_t islink, char *buf)
46247c478bd9Sstevel@tonic-gate {
4625d62bc4baSyz147064 	link_state_t	linkstate;
46267c478bd9Sstevel@tonic-gate 
4627d62bc4baSyz147064 	if (get_one_kstat(name, "link_state", KSTAT_DATA_UINT32,
4628d62bc4baSyz147064 	    &linkstate, islink) != 0) {
4629*da14cebeSEric Cheng 		(void) strlcpy(buf, "?", DLADM_STRSIZE);
46303a62633bSyz147064 		return (buf);
46317c478bd9Sstevel@tonic-gate 	}
4632d62bc4baSyz147064 	return (dladm_linkstate2str(linkstate, buf));
46337c478bd9Sstevel@tonic-gate }
46347c478bd9Sstevel@tonic-gate 
4635f595a68aSyz147064 static const char *
4636d62bc4baSyz147064 get_linkduplex(const char *name, boolean_t islink, char *buf)
46377c478bd9Sstevel@tonic-gate {
4638d62bc4baSyz147064 	link_duplex_t	linkduplex;
46397c478bd9Sstevel@tonic-gate 
4640d62bc4baSyz147064 	if (get_one_kstat(name, "link_duplex", KSTAT_DATA_UINT32,
4641d62bc4baSyz147064 	    &linkduplex, islink) != 0) {
46423a62633bSyz147064 		(void) strlcpy(buf, "unknown", DLADM_STRSIZE);
46433a62633bSyz147064 		return (buf);
46447c478bd9Sstevel@tonic-gate 	}
46457c478bd9Sstevel@tonic-gate 
4646d62bc4baSyz147064 	return (dladm_linkduplex2str(linkduplex, buf));
46477c478bd9Sstevel@tonic-gate }
46480ba2cbe9Sxc151355 
46490ba2cbe9Sxc151355 typedef struct {
46500ba2cbe9Sxc151355 	char	*s_buf;
46510ba2cbe9Sxc151355 	char	**s_fields;	/* array of pointer to the fields in s_buf */
46520ba2cbe9Sxc151355 	uint_t	s_nfields;	/* the number of fields in s_buf */
46530ba2cbe9Sxc151355 } split_t;
46540ba2cbe9Sxc151355 
46550ba2cbe9Sxc151355 /*
46560ba2cbe9Sxc151355  * Free the split_t structure pointed to by `sp'.
46570ba2cbe9Sxc151355  */
46580ba2cbe9Sxc151355 static void
46590ba2cbe9Sxc151355 splitfree(split_t *sp)
46600ba2cbe9Sxc151355 {
46610ba2cbe9Sxc151355 	free(sp->s_buf);
46620ba2cbe9Sxc151355 	free(sp->s_fields);
46630ba2cbe9Sxc151355 	free(sp);
46640ba2cbe9Sxc151355 }
46650ba2cbe9Sxc151355 
46660ba2cbe9Sxc151355 /*
46670ba2cbe9Sxc151355  * Split `str' into at most `maxfields' fields, each field at most `maxlen' in
46680ba2cbe9Sxc151355  * length.  Return a pointer to a split_t containing the split fields, or NULL
46690ba2cbe9Sxc151355  * on failure.
46700ba2cbe9Sxc151355  */
46710ba2cbe9Sxc151355 static split_t *
46720ba2cbe9Sxc151355 split(const char *str, uint_t maxfields, uint_t maxlen)
46730ba2cbe9Sxc151355 {
46740ba2cbe9Sxc151355 	char	*field, *token, *lasts = NULL;
46750ba2cbe9Sxc151355 	split_t	*sp;
46760ba2cbe9Sxc151355 
46770ba2cbe9Sxc151355 	if (*str == '\0' || maxfields == 0 || maxlen == 0)
46780ba2cbe9Sxc151355 		return (NULL);
46790ba2cbe9Sxc151355 
46800ba2cbe9Sxc151355 	sp = calloc(sizeof (split_t), 1);
46810ba2cbe9Sxc151355 	if (sp == NULL)
46820ba2cbe9Sxc151355 		return (NULL);
46830ba2cbe9Sxc151355 
46840ba2cbe9Sxc151355 	sp->s_buf = strdup(str);
46850ba2cbe9Sxc151355 	sp->s_fields = malloc(sizeof (char *) * maxfields);
46860ba2cbe9Sxc151355 	if (sp->s_buf == NULL || sp->s_fields == NULL)
46870ba2cbe9Sxc151355 		goto fail;
46880ba2cbe9Sxc151355 
46890ba2cbe9Sxc151355 	token = sp->s_buf;
46900ba2cbe9Sxc151355 	while ((field = strtok_r(token, ",", &lasts)) != NULL) {
46910ba2cbe9Sxc151355 		if (sp->s_nfields == maxfields || strlen(field) > maxlen)
46920ba2cbe9Sxc151355 			goto fail;
46930ba2cbe9Sxc151355 		token = NULL;
46940ba2cbe9Sxc151355 		sp->s_fields[sp->s_nfields++] = field;
46950ba2cbe9Sxc151355 	}
46960ba2cbe9Sxc151355 	return (sp);
46970ba2cbe9Sxc151355 fail:
46980ba2cbe9Sxc151355 	splitfree(sp);
46990ba2cbe9Sxc151355 	return (NULL);
47000ba2cbe9Sxc151355 }
47010ba2cbe9Sxc151355 
47020ba2cbe9Sxc151355 static int
4703e7801d59Ssowmini parse_wifi_fields(char *str, print_field_t ***fields, uint_t *countp,
47040ba2cbe9Sxc151355     uint_t cmdtype)
47050ba2cbe9Sxc151355 {
47060ba2cbe9Sxc151355 
47070ba2cbe9Sxc151355 	if (cmdtype == WIFI_CMD_SCAN) {
47080ba2cbe9Sxc151355 		if (str == NULL)
47090ba2cbe9Sxc151355 			str = def_scan_wifi_fields;
47100ba2cbe9Sxc151355 		if (strcasecmp(str, "all") == 0)
47110ba2cbe9Sxc151355 			str = all_scan_wifi_fields;
47120ba2cbe9Sxc151355 	} else if (cmdtype == WIFI_CMD_SHOW) {
47130ba2cbe9Sxc151355 		if (str == NULL)
47140ba2cbe9Sxc151355 			str = def_show_wifi_fields;
47150ba2cbe9Sxc151355 		if (strcasecmp(str, "all") == 0)
47160ba2cbe9Sxc151355 			str = all_show_wifi_fields;
47170ba2cbe9Sxc151355 	} else {
47180ba2cbe9Sxc151355 		return (-1);
47190ba2cbe9Sxc151355 	}
4720e7801d59Ssowmini 	*fields = parse_output_fields(str, wifi_fields, WIFI_MAX_FIELDS,
4721e7801d59Ssowmini 	    cmdtype, countp);
4722e7801d59Ssowmini 	if (*fields != NULL)
4723e7801d59Ssowmini 		return (0);
47240ba2cbe9Sxc151355 	return (-1);
4725e7801d59Ssowmini }
4726e7801d59Ssowmini static print_field_t **
4727e7801d59Ssowmini parse_output_fields(char *str, print_field_t *template, int max_fields,
4728e7801d59Ssowmini     uint_t cmdtype, uint_t *countp)
4729e7801d59Ssowmini {
4730e7801d59Ssowmini 	split_t		*sp;
4731e7801d59Ssowmini 	boolean_t	good_match = B_FALSE;
4732e7801d59Ssowmini 	uint_t		i, j;
4733e7801d59Ssowmini 	print_field_t	**pf = NULL;
47340ba2cbe9Sxc151355 
4735e7801d59Ssowmini 	sp = split(str, max_fields, MAX_FIELD_LEN);
4736e7801d59Ssowmini 
4737e7801d59Ssowmini 	if (sp == NULL)
4738e7801d59Ssowmini 		return (NULL);
4739e7801d59Ssowmini 
4740e7801d59Ssowmini 	pf = malloc(sp->s_nfields * sizeof (print_field_t *));
4741e7801d59Ssowmini 	if (pf == NULL)
47420ba2cbe9Sxc151355 		goto fail;
47430ba2cbe9Sxc151355 
47440ba2cbe9Sxc151355 	for (i = 0; i < sp->s_nfields; i++) {
4745e7801d59Ssowmini 		for (j = 0; j < max_fields; j++) {
47460ba2cbe9Sxc151355 			if (strcasecmp(sp->s_fields[i],
4747e7801d59Ssowmini 			    template[j].pf_name) == 0) {
4748e7801d59Ssowmini 				good_match = template[j]. pf_cmdtype & cmdtype;
47490ba2cbe9Sxc151355 				break;
47500ba2cbe9Sxc151355 			}
47510ba2cbe9Sxc151355 		}
47520ba2cbe9Sxc151355 		if (!good_match)
47530ba2cbe9Sxc151355 			goto fail;
47540ba2cbe9Sxc151355 
47550ba2cbe9Sxc151355 		good_match = B_FALSE;
4756e7801d59Ssowmini 		pf[i] = &template[j];
47570ba2cbe9Sxc151355 	}
47580ba2cbe9Sxc151355 	*countp = i;
47590ba2cbe9Sxc151355 	splitfree(sp);
4760e7801d59Ssowmini 	return (pf);
47610ba2cbe9Sxc151355 fail:
4762e7801d59Ssowmini 	free(pf);
47630ba2cbe9Sxc151355 	splitfree(sp);
4764e7801d59Ssowmini 	return (NULL);
47650ba2cbe9Sxc151355 }
47660ba2cbe9Sxc151355 
47670ba2cbe9Sxc151355 typedef struct print_wifi_state {
4768d62bc4baSyz147064 	char		*ws_link;
47690ba2cbe9Sxc151355 	boolean_t	ws_parseable;
47700ba2cbe9Sxc151355 	boolean_t	ws_header;
4771e7801d59Ssowmini 	print_state_t	ws_print_state;
47720ba2cbe9Sxc151355 } print_wifi_state_t;
47730ba2cbe9Sxc151355 
4774e7801d59Ssowmini typedef struct  wlan_scan_args_s {
4775e7801d59Ssowmini 	print_wifi_state_t	*ws_state;
4776e7801d59Ssowmini 	void			*ws_attr;
4777e7801d59Ssowmini } wlan_scan_args_t;
47780ba2cbe9Sxc151355 
47790ba2cbe9Sxc151355 static void
4780e7801d59Ssowmini print_field(print_state_t *statep, print_field_t *pfp, const char *value,
4781e7801d59Ssowmini     boolean_t parseable)
47820ba2cbe9Sxc151355 {
4783e7801d59Ssowmini 	uint_t	width = pfp->pf_width;
47846be03d0bSVasumathi Sundaram - Sun Microsystems 	uint_t	valwidth;
47850ba2cbe9Sxc151355 	uint_t	compress;
47860ba2cbe9Sxc151355 
47870d365605Sschuster 	/*
47880d365605Sschuster 	 * Parsable fields are separated by ':'. If such a field contains
47890d365605Sschuster 	 * a ':' or '\', this character is prefixed by a '\'.
47900d365605Sschuster 	 */
4791e7801d59Ssowmini 	if (parseable) {
47920d365605Sschuster 		char	c;
47930d365605Sschuster 
47940d365605Sschuster 		if (statep->ps_nfields == 1) {
47950d365605Sschuster 			(void) printf("%s", value);
47960d365605Sschuster 			return;
47970d365605Sschuster 		}
47980d365605Sschuster 		while ((c = *value++) != '\0') {
47990d365605Sschuster 			if (c == ':' || c == '\\')
48000d365605Sschuster 				(void) putchar('\\');
48010d365605Sschuster 			(void) putchar(c);
48020d365605Sschuster 		}
48030d365605Sschuster 		if (!statep->ps_lastfield)
48040d365605Sschuster 			(void) putchar(':');
48050d365605Sschuster 		return;
48060ba2cbe9Sxc151355 	} else {
48070ba2cbe9Sxc151355 		if (value[0] == '\0')
4808e7801d59Ssowmini 			value = STR_UNDEF_VAL;
4809e7801d59Ssowmini 		if (statep->ps_lastfield) {
48100ba2cbe9Sxc151355 			(void) printf("%s", value);
48116be03d0bSVasumathi Sundaram - Sun Microsystems 			statep->ps_overflow = 0;
48120ba2cbe9Sxc151355 			return;
48130ba2cbe9Sxc151355 		}
48140ba2cbe9Sxc151355 
48156be03d0bSVasumathi Sundaram - Sun Microsystems 		valwidth = strlen(value);
48160ba2cbe9Sxc151355 		if (valwidth > width) {
4817e7801d59Ssowmini 			statep->ps_overflow += valwidth - width;
4818e7801d59Ssowmini 		} else if (valwidth < width && statep->ps_overflow > 0) {
4819e7801d59Ssowmini 			compress = min(statep->ps_overflow, width - valwidth);
4820e7801d59Ssowmini 			statep->ps_overflow -= compress;
48210ba2cbe9Sxc151355 			width -= compress;
48220ba2cbe9Sxc151355 		}
48230ba2cbe9Sxc151355 		(void) printf("%-*s", width, value);
48240ba2cbe9Sxc151355 	}
48250ba2cbe9Sxc151355 
4826e7801d59Ssowmini 	if (!statep->ps_lastfield)
48270ba2cbe9Sxc151355 		(void) putchar(' ');
48280ba2cbe9Sxc151355 }
48290ba2cbe9Sxc151355 
4830e7801d59Ssowmini static char *
4831e7801d59Ssowmini print_wlan_attr(print_field_t *wfp, void *warg)
48320ba2cbe9Sxc151355 {
4833e7801d59Ssowmini 	static char		buf[DLADM_STRSIZE];
4834e7801d59Ssowmini 	wlan_scan_args_t	*w = warg;
4835e7801d59Ssowmini 	print_wifi_state_t	*statep = w->ws_state;
4836e7801d59Ssowmini 	dladm_wlan_attr_t	*attrp = w->ws_attr;
48370ba2cbe9Sxc151355 
4838e7801d59Ssowmini 	if (wfp->pf_index == 0) {
4839e7801d59Ssowmini 		return ((char *)statep->ws_link);
48400ba2cbe9Sxc151355 	}
48410ba2cbe9Sxc151355 
4842e7801d59Ssowmini 	if ((wfp->pf_index & attrp->wa_valid) == 0) {
4843e7801d59Ssowmini 		return ("");
48440ba2cbe9Sxc151355 	}
48450ba2cbe9Sxc151355 
4846e7801d59Ssowmini 	switch (wfp->pf_index) {
4847f595a68aSyz147064 	case DLADM_WLAN_ATTR_ESSID:
4848e7801d59Ssowmini 		(void) dladm_wlan_essid2str(&attrp->wa_essid, buf);
48490ba2cbe9Sxc151355 		break;
4850f595a68aSyz147064 	case DLADM_WLAN_ATTR_BSSID:
4851e7801d59Ssowmini 		(void) dladm_wlan_bssid2str(&attrp->wa_bssid, buf);
48520ba2cbe9Sxc151355 		break;
4853f595a68aSyz147064 	case DLADM_WLAN_ATTR_SECMODE:
4854e7801d59Ssowmini 		(void) dladm_wlan_secmode2str(&attrp->wa_secmode, buf);
48550ba2cbe9Sxc151355 		break;
4856f595a68aSyz147064 	case DLADM_WLAN_ATTR_STRENGTH:
4857e7801d59Ssowmini 		(void) dladm_wlan_strength2str(&attrp->wa_strength, buf);
48580ba2cbe9Sxc151355 		break;
4859f595a68aSyz147064 	case DLADM_WLAN_ATTR_MODE:
4860e7801d59Ssowmini 		(void) dladm_wlan_mode2str(&attrp->wa_mode, buf);
48610ba2cbe9Sxc151355 		break;
4862f595a68aSyz147064 	case DLADM_WLAN_ATTR_SPEED:
4863e7801d59Ssowmini 		(void) dladm_wlan_speed2str(&attrp->wa_speed, buf);
48640ba2cbe9Sxc151355 		(void) strlcat(buf, "Mb", sizeof (buf));
48650ba2cbe9Sxc151355 		break;
4866f595a68aSyz147064 	case DLADM_WLAN_ATTR_AUTH:
4867e7801d59Ssowmini 		(void) dladm_wlan_auth2str(&attrp->wa_auth, buf);
48680ba2cbe9Sxc151355 		break;
4869f595a68aSyz147064 	case DLADM_WLAN_ATTR_BSSTYPE:
4870e7801d59Ssowmini 		(void) dladm_wlan_bsstype2str(&attrp->wa_bsstype, buf);
48710ba2cbe9Sxc151355 		break;
48720ba2cbe9Sxc151355 	}
48730ba2cbe9Sxc151355 
4874e7801d59Ssowmini 	return (buf);
48750ba2cbe9Sxc151355 }
48760ba2cbe9Sxc151355 
48770ba2cbe9Sxc151355 static boolean_t
4878f595a68aSyz147064 print_scan_results(void *arg, dladm_wlan_attr_t *attrp)
48790ba2cbe9Sxc151355 {
48800ba2cbe9Sxc151355 	print_wifi_state_t	*statep = arg;
4881e7801d59Ssowmini 	wlan_scan_args_t	warg;
48820ba2cbe9Sxc151355 
48830ba2cbe9Sxc151355 	if (statep->ws_header) {
48840ba2cbe9Sxc151355 		statep->ws_header = B_FALSE;
48850ba2cbe9Sxc151355 		if (!statep->ws_parseable)
4886e7801d59Ssowmini 			print_header(&statep->ws_print_state);
48870ba2cbe9Sxc151355 	}
48880ba2cbe9Sxc151355 
4889e7801d59Ssowmini 	statep->ws_print_state.ps_overflow = 0;
4890e7801d59Ssowmini 	bzero(&warg, sizeof (warg));
4891e7801d59Ssowmini 	warg.ws_state = statep;
4892e7801d59Ssowmini 	warg.ws_attr = attrp;
4893e7801d59Ssowmini 	dladm_print_output(&statep->ws_print_state, statep->ws_parseable,
4894e7801d59Ssowmini 	    print_wlan_attr, &warg);
48950ba2cbe9Sxc151355 	return (B_TRUE);
48960ba2cbe9Sxc151355 }
48970ba2cbe9Sxc151355 
4898d62bc4baSyz147064 static int
4899d62bc4baSyz147064 scan_wifi(datalink_id_t linkid, void *arg)
49000ba2cbe9Sxc151355 {
49010ba2cbe9Sxc151355 	print_wifi_state_t	*statep = arg;
4902f595a68aSyz147064 	dladm_status_t		status;
4903d62bc4baSyz147064 	char			link[MAXLINKNAMELEN];
4904d62bc4baSyz147064 
4905e7801d59Ssowmini 	if ((status = dladm_datalink_id2info(linkid, NULL, NULL, NULL, link,
4906e7801d59Ssowmini 	    sizeof (link))) != DLADM_STATUS_OK) {
4907d62bc4baSyz147064 		return (DLADM_WALK_CONTINUE);
4908d62bc4baSyz147064 	}
49090ba2cbe9Sxc151355 
49100ba2cbe9Sxc151355 	statep->ws_link = link;
4911d62bc4baSyz147064 	status = dladm_wlan_scan(linkid, statep, print_scan_results);
4912f595a68aSyz147064 	if (status != DLADM_STATUS_OK)
4913d62bc4baSyz147064 		die_dlerr(status, "cannot scan link '%s'", statep->ws_link);
491433343a97Smeem 
4915d62bc4baSyz147064 	return (DLADM_WALK_CONTINUE);
49160ba2cbe9Sxc151355 }
49170ba2cbe9Sxc151355 
4918e7801d59Ssowmini static char *
4919e7801d59Ssowmini print_link_attr(print_field_t *wfp, void *warg)
49200ba2cbe9Sxc151355 {
4921e7801d59Ssowmini 	static char		buf[DLADM_STRSIZE];
4922e7801d59Ssowmini 	char			*ptr;
4923e7801d59Ssowmini 	wlan_scan_args_t	*w = warg, w1;
4924e7801d59Ssowmini 	print_wifi_state_t	*statep = w->ws_state;
4925e7801d59Ssowmini 	dladm_wlan_linkattr_t	*attrp = w->ws_attr;
49260ba2cbe9Sxc151355 
4927e7801d59Ssowmini 	if (strcmp(wfp->pf_name, "status") == 0) {
4928e7801d59Ssowmini 		if ((wfp->pf_index & attrp->la_valid) != 0)
4929e7801d59Ssowmini 			(void) dladm_wlan_linkstatus2str(
4930e7801d59Ssowmini 			    &attrp->la_status, buf);
4931e7801d59Ssowmini 		return (buf);
49320ba2cbe9Sxc151355 	}
4933e7801d59Ssowmini 	statep->ws_print_state.ps_overflow = 0;
4934e7801d59Ssowmini 	bzero(&w1, sizeof (w1));
4935e7801d59Ssowmini 	w1.ws_state = statep;
4936e7801d59Ssowmini 	w1.ws_attr = &attrp->la_wlan_attr;
4937e7801d59Ssowmini 	ptr = print_wlan_attr(wfp, &w1);
4938e7801d59Ssowmini 	return (ptr);
49390ba2cbe9Sxc151355 }
49400ba2cbe9Sxc151355 
4941d62bc4baSyz147064 static int
4942d62bc4baSyz147064 show_wifi(datalink_id_t linkid, void *arg)
49430ba2cbe9Sxc151355 {
49440ba2cbe9Sxc151355 	print_wifi_state_t	*statep = arg;
4945f595a68aSyz147064 	dladm_wlan_linkattr_t	attr;
4946f595a68aSyz147064 	dladm_status_t		status;
4947d62bc4baSyz147064 	char			link[MAXLINKNAMELEN];
4948e7801d59Ssowmini 	wlan_scan_args_t	warg;
49490ba2cbe9Sxc151355 
4950e7801d59Ssowmini 	if ((status = dladm_datalink_id2info(linkid, NULL, NULL, NULL, link,
4951e7801d59Ssowmini 	    sizeof (link))) != DLADM_STATUS_OK) {
4952d62bc4baSyz147064 		return (DLADM_WALK_CONTINUE);
4953d62bc4baSyz147064 	}
4954d62bc4baSyz147064 
49555f5c9f54SAnurag S. Maskey 	/* dladm_wlan_get_linkattr() memsets attr with 0 */
4956d62bc4baSyz147064 	status = dladm_wlan_get_linkattr(linkid, &attr);
4957f595a68aSyz147064 	if (status != DLADM_STATUS_OK)
4958d62bc4baSyz147064 		die_dlerr(status, "cannot get link attributes for %s", link);
4959d62bc4baSyz147064 
4960d62bc4baSyz147064 	statep->ws_link = link;
49610ba2cbe9Sxc151355 
49620ba2cbe9Sxc151355 	if (statep->ws_header) {
49630ba2cbe9Sxc151355 		statep->ws_header = B_FALSE;
49640ba2cbe9Sxc151355 		if (!statep->ws_parseable)
4965e7801d59Ssowmini 			print_header(&statep->ws_print_state);
49660ba2cbe9Sxc151355 	}
49670ba2cbe9Sxc151355 
4968e7801d59Ssowmini 	statep->ws_print_state.ps_overflow = 0;
4969e7801d59Ssowmini 	bzero(&warg, sizeof (warg));
4970e7801d59Ssowmini 	warg.ws_state = statep;
4971e7801d59Ssowmini 	warg.ws_attr = &attr;
4972e7801d59Ssowmini 	dladm_print_output(&statep->ws_print_state, statep->ws_parseable,
4973e7801d59Ssowmini 	    print_link_attr, &warg);
4974d62bc4baSyz147064 	return (DLADM_WALK_CONTINUE);
49750ba2cbe9Sxc151355 }
49760ba2cbe9Sxc151355 
49770ba2cbe9Sxc151355 static void
49788d5c46e6Sam223141 do_display_wifi(int argc, char **argv, int cmd, const char *use)
49790ba2cbe9Sxc151355 {
49800ba2cbe9Sxc151355 	int			option;
49810ba2cbe9Sxc151355 	char			*fields_str = NULL;
4982e7801d59Ssowmini 	print_field_t		**fields;
4983d62bc4baSyz147064 	int			(*callback)(datalink_id_t, void *);
49840ba2cbe9Sxc151355 	uint_t			nfields;
49850ba2cbe9Sxc151355 	print_wifi_state_t	state;
4986d62bc4baSyz147064 	datalink_id_t		linkid = DATALINK_ALL_LINKID;
4987f595a68aSyz147064 	dladm_status_t		status;
49880ba2cbe9Sxc151355 
49890ba2cbe9Sxc151355 	if (cmd == WIFI_CMD_SCAN)
49900ba2cbe9Sxc151355 		callback = scan_wifi;
49910ba2cbe9Sxc151355 	else if (cmd == WIFI_CMD_SHOW)
49920ba2cbe9Sxc151355 		callback = show_wifi;
49930ba2cbe9Sxc151355 	else
49940ba2cbe9Sxc151355 		return;
49950ba2cbe9Sxc151355 
49960ba2cbe9Sxc151355 	state.ws_parseable = B_FALSE;
49970ba2cbe9Sxc151355 	state.ws_header = B_TRUE;
49980ba2cbe9Sxc151355 	opterr = 0;
49990ba2cbe9Sxc151355 	while ((option = getopt_long(argc, argv, ":o:p",
50000ba2cbe9Sxc151355 	    wifi_longopts, NULL)) != -1) {
50010ba2cbe9Sxc151355 		switch (option) {
50020ba2cbe9Sxc151355 		case 'o':
50030ba2cbe9Sxc151355 			fields_str = optarg;
50040ba2cbe9Sxc151355 			break;
50050ba2cbe9Sxc151355 		case 'p':
50060ba2cbe9Sxc151355 			state.ws_parseable = B_TRUE;
50070ba2cbe9Sxc151355 			break;
50080ba2cbe9Sxc151355 		default:
50098d5c46e6Sam223141 			die_opterr(optopt, option, use);
50100ba2cbe9Sxc151355 		}
50110ba2cbe9Sxc151355 	}
50120ba2cbe9Sxc151355 
50130d365605Sschuster 	if (state.ws_parseable && fields_str == NULL)
50140d365605Sschuster 		die("-p requires -o");
50150d365605Sschuster 
50160d365605Sschuster 	if (state.ws_parseable && strcasecmp(fields_str, "all") == 0)
50170d365605Sschuster 		die("\"-o all\" is invalid with -p");
50180d365605Sschuster 
5019d62bc4baSyz147064 	if (optind == (argc - 1)) {
5020d62bc4baSyz147064 		if ((status = dladm_name2info(argv[optind], &linkid, NULL,
5021d62bc4baSyz147064 		    NULL, NULL)) != DLADM_STATUS_OK) {
5022d62bc4baSyz147064 			die_dlerr(status, "link %s is not valid", argv[optind]);
5023d62bc4baSyz147064 		}
5024d62bc4baSyz147064 	} else if (optind != argc) {
50250ba2cbe9Sxc151355 		usage();
5026d62bc4baSyz147064 	}
50270ba2cbe9Sxc151355 
502833343a97Smeem 	if (parse_wifi_fields(fields_str, &fields, &nfields, cmd) < 0)
502933343a97Smeem 		die("invalid field(s) specified");
503033343a97Smeem 
5031e7801d59Ssowmini 	bzero(&state.ws_print_state, sizeof (state.ws_print_state));
5032e7801d59Ssowmini 	state.ws_print_state.ps_fields = fields;
5033e7801d59Ssowmini 	state.ws_print_state.ps_nfields = nfields;
50340ba2cbe9Sxc151355 
5035d62bc4baSyz147064 	if (linkid == DATALINK_ALL_LINKID) {
5036d62bc4baSyz147064 		(void) dladm_walk_datalink_id(callback, &state,
5037d62bc4baSyz147064 		    DATALINK_CLASS_PHYS, DL_WIFI, DLADM_OPT_ACTIVE);
50380ba2cbe9Sxc151355 	} else {
5039d62bc4baSyz147064 		(void) (*callback)(linkid, &state);
50400ba2cbe9Sxc151355 	}
50410ba2cbe9Sxc151355 	free(fields);
50420ba2cbe9Sxc151355 }
50430ba2cbe9Sxc151355 
50440ba2cbe9Sxc151355 static void
50458d5c46e6Sam223141 do_scan_wifi(int argc, char **argv, const char *use)
50460ba2cbe9Sxc151355 {
50478d5c46e6Sam223141 	do_display_wifi(argc, argv, WIFI_CMD_SCAN, use);
50480ba2cbe9Sxc151355 }
50490ba2cbe9Sxc151355 
50500ba2cbe9Sxc151355 static void
50518d5c46e6Sam223141 do_show_wifi(int argc, char **argv, const char *use)
50520ba2cbe9Sxc151355 {
50538d5c46e6Sam223141 	do_display_wifi(argc, argv, WIFI_CMD_SHOW, use);
50540ba2cbe9Sxc151355 }
50550ba2cbe9Sxc151355 
50560ba2cbe9Sxc151355 typedef struct wlan_count_attr {
50570ba2cbe9Sxc151355 	uint_t		wc_count;
5058d62bc4baSyz147064 	datalink_id_t	wc_linkid;
50590ba2cbe9Sxc151355 } wlan_count_attr_t;
50600ba2cbe9Sxc151355 
5061d62bc4baSyz147064 static int
5062d62bc4baSyz147064 do_count_wlan(datalink_id_t linkid, void *arg)
50630ba2cbe9Sxc151355 {
506433343a97Smeem 	wlan_count_attr_t *cp = arg;
50650ba2cbe9Sxc151355 
50660ba2cbe9Sxc151355 	if (cp->wc_count == 0)
5067d62bc4baSyz147064 		cp->wc_linkid = linkid;
50680ba2cbe9Sxc151355 	cp->wc_count++;
5069d62bc4baSyz147064 	return (DLADM_WALK_CONTINUE);
50700ba2cbe9Sxc151355 }
50710ba2cbe9Sxc151355 
50720ba2cbe9Sxc151355 static int
5073a399b765Szf162725 parse_wlan_keys(char *str, dladm_wlan_key_t **keys, uint_t *key_countp)
50740ba2cbe9Sxc151355 {
50750ba2cbe9Sxc151355 	uint_t			i;
50760ba2cbe9Sxc151355 	split_t			*sp;
5077a399b765Szf162725 	dladm_wlan_key_t	*wk;
50780ba2cbe9Sxc151355 
5079a399b765Szf162725 	sp = split(str, DLADM_WLAN_MAX_WEPKEYS, DLADM_WLAN_MAX_KEYNAME_LEN);
50800ba2cbe9Sxc151355 	if (sp == NULL)
50810ba2cbe9Sxc151355 		return (-1);
50820ba2cbe9Sxc151355 
5083a399b765Szf162725 	wk = malloc(sp->s_nfields * sizeof (dladm_wlan_key_t));
50840ba2cbe9Sxc151355 	if (wk == NULL)
50850ba2cbe9Sxc151355 		goto fail;
50860ba2cbe9Sxc151355 
50870ba2cbe9Sxc151355 	for (i = 0; i < sp->s_nfields; i++) {
50880ba2cbe9Sxc151355 		char			*s;
50890ba2cbe9Sxc151355 		dladm_secobj_class_t	class;
50900ba2cbe9Sxc151355 		dladm_status_t		status;
50910ba2cbe9Sxc151355 
50920ba2cbe9Sxc151355 		(void) strlcpy(wk[i].wk_name, sp->s_fields[i],
5093a399b765Szf162725 		    DLADM_WLAN_MAX_KEYNAME_LEN);
50940ba2cbe9Sxc151355 
50950ba2cbe9Sxc151355 		wk[i].wk_idx = 1;
50960ba2cbe9Sxc151355 		if ((s = strrchr(wk[i].wk_name, ':')) != NULL) {
50970ba2cbe9Sxc151355 			if (s[1] == '\0' || s[2] != '\0' || !isdigit(s[1]))
50980ba2cbe9Sxc151355 				goto fail;
50990ba2cbe9Sxc151355 
51000ba2cbe9Sxc151355 			wk[i].wk_idx = (uint_t)(s[1] - '0');
51010ba2cbe9Sxc151355 			*s = '\0';
51020ba2cbe9Sxc151355 		}
5103a399b765Szf162725 		wk[i].wk_len = DLADM_WLAN_MAX_KEY_LEN;
51040ba2cbe9Sxc151355 
51050ba2cbe9Sxc151355 		status = dladm_get_secobj(wk[i].wk_name, &class,
51060ba2cbe9Sxc151355 		    wk[i].wk_val, &wk[i].wk_len, 0);
51070ba2cbe9Sxc151355 		if (status != DLADM_STATUS_OK) {
51080ba2cbe9Sxc151355 			if (status == DLADM_STATUS_NOTFOUND) {
51090ba2cbe9Sxc151355 				status = dladm_get_secobj(wk[i].wk_name,
51100ba2cbe9Sxc151355 				    &class, wk[i].wk_val, &wk[i].wk_len,
51110ba2cbe9Sxc151355 				    DLADM_OPT_PERSIST);
51120ba2cbe9Sxc151355 			}
51130ba2cbe9Sxc151355 			if (status != DLADM_STATUS_OK)
51140ba2cbe9Sxc151355 				goto fail;
51150ba2cbe9Sxc151355 		}
5116a399b765Szf162725 		wk[i].wk_class = class;
51170ba2cbe9Sxc151355 	}
51180ba2cbe9Sxc151355 	*keys = wk;
51190ba2cbe9Sxc151355 	*key_countp = i;
51200ba2cbe9Sxc151355 	splitfree(sp);
51210ba2cbe9Sxc151355 	return (0);
51220ba2cbe9Sxc151355 fail:
51230ba2cbe9Sxc151355 	free(wk);
51240ba2cbe9Sxc151355 	splitfree(sp);
51250ba2cbe9Sxc151355 	return (-1);
51260ba2cbe9Sxc151355 }
51270ba2cbe9Sxc151355 
51280ba2cbe9Sxc151355 static void
51298d5c46e6Sam223141 do_connect_wifi(int argc, char **argv, const char *use)
51300ba2cbe9Sxc151355 {
51310ba2cbe9Sxc151355 	int			option;
5132f595a68aSyz147064 	dladm_wlan_attr_t	attr, *attrp;
5133f595a68aSyz147064 	dladm_status_t		status = DLADM_STATUS_OK;
5134f595a68aSyz147064 	int			timeout = DLADM_WLAN_CONNECT_TIMEOUT_DEFAULT;
5135d62bc4baSyz147064 	datalink_id_t		linkid = DATALINK_ALL_LINKID;
5136a399b765Szf162725 	dladm_wlan_key_t	*keys = NULL;
51370ba2cbe9Sxc151355 	uint_t			key_count = 0;
51380ba2cbe9Sxc151355 	uint_t			flags = 0;
5139f595a68aSyz147064 	dladm_wlan_secmode_t	keysecmode = DLADM_WLAN_SECMODE_NONE;
5140a399b765Szf162725 	char			buf[DLADM_STRSIZE];
51410ba2cbe9Sxc151355 
51420ba2cbe9Sxc151355 	opterr = 0;
51430ba2cbe9Sxc151355 	(void) memset(&attr, 0, sizeof (attr));
51440ba2cbe9Sxc151355 	while ((option = getopt_long(argc, argv, ":e:i:a:m:b:s:k:T:c",
51450ba2cbe9Sxc151355 	    wifi_longopts, NULL)) != -1) {
51460ba2cbe9Sxc151355 		switch (option) {
51470ba2cbe9Sxc151355 		case 'e':
5148f595a68aSyz147064 			status = dladm_wlan_str2essid(optarg, &attr.wa_essid);
5149f595a68aSyz147064 			if (status != DLADM_STATUS_OK)
515033343a97Smeem 				die("invalid ESSID '%s'", optarg);
515133343a97Smeem 
5152f595a68aSyz147064 			attr.wa_valid |= DLADM_WLAN_ATTR_ESSID;
51530ba2cbe9Sxc151355 			/*
51540ba2cbe9Sxc151355 			 * Try to connect without doing a scan.
51550ba2cbe9Sxc151355 			 */
5156f595a68aSyz147064 			flags |= DLADM_WLAN_CONNECT_NOSCAN;
51570ba2cbe9Sxc151355 			break;
51580ba2cbe9Sxc151355 		case 'i':
5159f595a68aSyz147064 			status = dladm_wlan_str2bssid(optarg, &attr.wa_bssid);
5160f595a68aSyz147064 			if (status != DLADM_STATUS_OK)
516133343a97Smeem 				die("invalid BSSID %s", optarg);
516233343a97Smeem 
5163f595a68aSyz147064 			attr.wa_valid |= DLADM_WLAN_ATTR_BSSID;
51640ba2cbe9Sxc151355 			break;
51650ba2cbe9Sxc151355 		case 'a':
5166f595a68aSyz147064 			status = dladm_wlan_str2auth(optarg, &attr.wa_auth);
5167f595a68aSyz147064 			if (status != DLADM_STATUS_OK)
516833343a97Smeem 				die("invalid authentication mode '%s'", optarg);
516933343a97Smeem 
5170f595a68aSyz147064 			attr.wa_valid |= DLADM_WLAN_ATTR_AUTH;
51710ba2cbe9Sxc151355 			break;
51720ba2cbe9Sxc151355 		case 'm':
5173f595a68aSyz147064 			status = dladm_wlan_str2mode(optarg, &attr.wa_mode);
5174f595a68aSyz147064 			if (status != DLADM_STATUS_OK)
517533343a97Smeem 				die("invalid mode '%s'", optarg);
517633343a97Smeem 
5177f595a68aSyz147064 			attr.wa_valid |= DLADM_WLAN_ATTR_MODE;
51780ba2cbe9Sxc151355 			break;
51790ba2cbe9Sxc151355 		case 'b':
5180f595a68aSyz147064 			if ((status = dladm_wlan_str2bsstype(optarg,
5181f595a68aSyz147064 			    &attr.wa_bsstype)) != DLADM_STATUS_OK) {
518233343a97Smeem 				die("invalid bsstype '%s'", optarg);
5183f595a68aSyz147064 			}
518433343a97Smeem 
5185f595a68aSyz147064 			attr.wa_valid |= DLADM_WLAN_ATTR_BSSTYPE;
51860ba2cbe9Sxc151355 			break;
51870ba2cbe9Sxc151355 		case 's':
5188f595a68aSyz147064 			if ((status = dladm_wlan_str2secmode(optarg,
5189f595a68aSyz147064 			    &attr.wa_secmode)) != DLADM_STATUS_OK) {
519033343a97Smeem 				die("invalid security mode '%s'", optarg);
5191f595a68aSyz147064 			}
519233343a97Smeem 
5193f595a68aSyz147064 			attr.wa_valid |= DLADM_WLAN_ATTR_SECMODE;
51940ba2cbe9Sxc151355 			break;
51950ba2cbe9Sxc151355 		case 'k':
5196a399b765Szf162725 			if (parse_wlan_keys(optarg, &keys, &key_count) < 0)
519733343a97Smeem 				die("invalid key(s) '%s'", optarg);
519833343a97Smeem 
5199a399b765Szf162725 			if (keys[0].wk_class == DLADM_SECOBJ_CLASS_WEP)
5200f595a68aSyz147064 				keysecmode = DLADM_WLAN_SECMODE_WEP;
5201a399b765Szf162725 			else
5202a399b765Szf162725 				keysecmode = DLADM_WLAN_SECMODE_WPA;
52030ba2cbe9Sxc151355 			break;
52040ba2cbe9Sxc151355 		case 'T':
52050ba2cbe9Sxc151355 			if (strcasecmp(optarg, "forever") == 0) {
52060ba2cbe9Sxc151355 				timeout = -1;
52070ba2cbe9Sxc151355 				break;
52080ba2cbe9Sxc151355 			}
520933343a97Smeem 			if (!str2int(optarg, &timeout) || timeout < 0)
521033343a97Smeem 				die("invalid timeout value '%s'", optarg);
52110ba2cbe9Sxc151355 			break;
52120ba2cbe9Sxc151355 		case 'c':
5213f595a68aSyz147064 			flags |= DLADM_WLAN_CONNECT_CREATEIBSS;
5214a399b765Szf162725 			flags |= DLADM_WLAN_CONNECT_CREATEIBSS;
52150ba2cbe9Sxc151355 			break;
52160ba2cbe9Sxc151355 		default:
52178d5c46e6Sam223141 			die_opterr(optopt, option, use);
52180ba2cbe9Sxc151355 			break;
52190ba2cbe9Sxc151355 		}
52200ba2cbe9Sxc151355 	}
52210ba2cbe9Sxc151355 
5222f595a68aSyz147064 	if (keysecmode == DLADM_WLAN_SECMODE_NONE) {
5223a399b765Szf162725 		if ((attr.wa_valid & DLADM_WLAN_ATTR_SECMODE) != 0) {
5224a399b765Szf162725 			die("key required for security mode '%s'",
5225a399b765Szf162725 			    dladm_wlan_secmode2str(&attr.wa_secmode, buf));
5226a399b765Szf162725 		}
52270ba2cbe9Sxc151355 	} else {
5228f595a68aSyz147064 		if ((attr.wa_valid & DLADM_WLAN_ATTR_SECMODE) != 0 &&
522933343a97Smeem 		    attr.wa_secmode != keysecmode)
523033343a97Smeem 			die("incompatible -s and -k options");
5231f595a68aSyz147064 		attr.wa_valid |= DLADM_WLAN_ATTR_SECMODE;
5232a399b765Szf162725 		attr.wa_secmode = keysecmode;
5233a399b765Szf162725 	}
52340ba2cbe9Sxc151355 
5235d62bc4baSyz147064 	if (optind == (argc - 1)) {
5236d62bc4baSyz147064 		if ((status = dladm_name2info(argv[optind], &linkid, NULL,
5237d62bc4baSyz147064 		    NULL, NULL)) != DLADM_STATUS_OK) {
5238d62bc4baSyz147064 			die_dlerr(status, "link %s is not valid", argv[optind]);
5239d62bc4baSyz147064 		}
5240d62bc4baSyz147064 	} else if (optind != argc) {
52410ba2cbe9Sxc151355 		usage();
5242d62bc4baSyz147064 	}
52430ba2cbe9Sxc151355 
5244d62bc4baSyz147064 	if (linkid == DATALINK_ALL_LINKID) {
52450ba2cbe9Sxc151355 		wlan_count_attr_t wcattr;
52460ba2cbe9Sxc151355 
5247d62bc4baSyz147064 		wcattr.wc_linkid = DATALINK_INVALID_LINKID;
52480ba2cbe9Sxc151355 		wcattr.wc_count = 0;
5249d62bc4baSyz147064 		(void) dladm_walk_datalink_id(do_count_wlan, &wcattr,
5250d62bc4baSyz147064 		    DATALINK_CLASS_PHYS, DL_WIFI, DLADM_OPT_ACTIVE);
52510ba2cbe9Sxc151355 		if (wcattr.wc_count == 0) {
525233343a97Smeem 			die("no wifi links are available");
52530ba2cbe9Sxc151355 		} else if (wcattr.wc_count > 1) {
525433343a97Smeem 			die("link name is required when more than one wifi "
525533343a97Smeem 			    "link is available");
52560ba2cbe9Sxc151355 		}
5257d62bc4baSyz147064 		linkid = wcattr.wc_linkid;
52580ba2cbe9Sxc151355 	}
52590ba2cbe9Sxc151355 	attrp = (attr.wa_valid == 0) ? NULL : &attr;
526033343a97Smeem again:
5261d62bc4baSyz147064 	if ((status = dladm_wlan_connect(linkid, attrp, timeout, keys,
5262f595a68aSyz147064 	    key_count, flags)) != DLADM_STATUS_OK) {
5263f595a68aSyz147064 		if ((flags & DLADM_WLAN_CONNECT_NOSCAN) != 0) {
52640ba2cbe9Sxc151355 			/*
526533343a97Smeem 			 * Try again with scanning and filtering.
52660ba2cbe9Sxc151355 			 */
5267f595a68aSyz147064 			flags &= ~DLADM_WLAN_CONNECT_NOSCAN;
526833343a97Smeem 			goto again;
52690ba2cbe9Sxc151355 		}
527033343a97Smeem 
5271f595a68aSyz147064 		if (status == DLADM_STATUS_NOTFOUND) {
52720ba2cbe9Sxc151355 			if (attr.wa_valid == 0) {
527333343a97Smeem 				die("no wifi networks are available");
52740ba2cbe9Sxc151355 			} else {
527533343a97Smeem 				die("no wifi networks with the specified "
527633343a97Smeem 				    "criteria are available");
52770ba2cbe9Sxc151355 			}
52780ba2cbe9Sxc151355 		}
5279d62bc4baSyz147064 		die_dlerr(status, "cannot connect");
52800ba2cbe9Sxc151355 	}
52810ba2cbe9Sxc151355 	free(keys);
52820ba2cbe9Sxc151355 }
52830ba2cbe9Sxc151355 
52840ba2cbe9Sxc151355 /* ARGSUSED */
5285d62bc4baSyz147064 static int
5286d62bc4baSyz147064 do_all_disconnect_wifi(datalink_id_t linkid, void *arg)
52870ba2cbe9Sxc151355 {
5288f595a68aSyz147064 	dladm_status_t	status;
52890ba2cbe9Sxc151355 
5290d62bc4baSyz147064 	status = dladm_wlan_disconnect(linkid);
5291f595a68aSyz147064 	if (status != DLADM_STATUS_OK)
5292d62bc4baSyz147064 		warn_dlerr(status, "cannot disconnect link");
529333343a97Smeem 
5294d62bc4baSyz147064 	return (DLADM_WALK_CONTINUE);
52950ba2cbe9Sxc151355 }
52960ba2cbe9Sxc151355 
52970ba2cbe9Sxc151355 static void
52988d5c46e6Sam223141 do_disconnect_wifi(int argc, char **argv, const char *use)
52990ba2cbe9Sxc151355 {
53000ba2cbe9Sxc151355 	int			option;
5301d62bc4baSyz147064 	datalink_id_t		linkid = DATALINK_ALL_LINKID;
53020ba2cbe9Sxc151355 	boolean_t		all_links = B_FALSE;
5303f595a68aSyz147064 	dladm_status_t		status;
53040ba2cbe9Sxc151355 	wlan_count_attr_t	wcattr;
53050ba2cbe9Sxc151355 
53060ba2cbe9Sxc151355 	opterr = 0;
53070ba2cbe9Sxc151355 	while ((option = getopt_long(argc, argv, ":a",
53080ba2cbe9Sxc151355 	    wifi_longopts, NULL)) != -1) {
53090ba2cbe9Sxc151355 		switch (option) {
53100ba2cbe9Sxc151355 		case 'a':
53110ba2cbe9Sxc151355 			all_links = B_TRUE;
53120ba2cbe9Sxc151355 			break;
53130ba2cbe9Sxc151355 		default:
53148d5c46e6Sam223141 			die_opterr(optopt, option, use);
53150ba2cbe9Sxc151355 			break;
53160ba2cbe9Sxc151355 		}
53170ba2cbe9Sxc151355 	}
53180ba2cbe9Sxc151355 
5319d62bc4baSyz147064 	if (optind == (argc - 1)) {
5320d62bc4baSyz147064 		if ((status = dladm_name2info(argv[optind], &linkid, NULL,
5321d62bc4baSyz147064 		    NULL, NULL)) != DLADM_STATUS_OK) {
5322d62bc4baSyz147064 			die_dlerr(status, "link %s is not valid", argv[optind]);
5323d62bc4baSyz147064 		}
5324d62bc4baSyz147064 	} else if (optind != argc) {
53250ba2cbe9Sxc151355 		usage();
5326d62bc4baSyz147064 	}
53270ba2cbe9Sxc151355 
5328d62bc4baSyz147064 	if (linkid == DATALINK_ALL_LINKID) {
53290ba2cbe9Sxc151355 		if (!all_links) {
5330d62bc4baSyz147064 			wcattr.wc_linkid = linkid;
53310ba2cbe9Sxc151355 			wcattr.wc_count = 0;
5332d62bc4baSyz147064 			(void) dladm_walk_datalink_id(do_count_wlan, &wcattr,
5333d62bc4baSyz147064 			    DATALINK_CLASS_PHYS, DL_WIFI, DLADM_OPT_ACTIVE);
53340ba2cbe9Sxc151355 			if (wcattr.wc_count == 0) {
533533343a97Smeem 				die("no wifi links are available");
53360ba2cbe9Sxc151355 			} else if (wcattr.wc_count > 1) {
533733343a97Smeem 				die("link name is required when more than "
533833343a97Smeem 				    "one wifi link is available");
53390ba2cbe9Sxc151355 			}
5340d62bc4baSyz147064 			linkid = wcattr.wc_linkid;
53410ba2cbe9Sxc151355 		} else {
5342d62bc4baSyz147064 			(void) dladm_walk_datalink_id(do_all_disconnect_wifi,
5343d62bc4baSyz147064 			    NULL, DATALINK_CLASS_PHYS, DL_WIFI,
5344d62bc4baSyz147064 			    DLADM_OPT_ACTIVE);
53450ba2cbe9Sxc151355 			return;
53460ba2cbe9Sxc151355 		}
53470ba2cbe9Sxc151355 	}
5348d62bc4baSyz147064 	status = dladm_wlan_disconnect(linkid);
5349f595a68aSyz147064 	if (status != DLADM_STATUS_OK)
5350d62bc4baSyz147064 		die_dlerr(status, "cannot disconnect");
53510ba2cbe9Sxc151355 }
53520ba2cbe9Sxc151355 
53530ba2cbe9Sxc151355 static void
5354d62bc4baSyz147064 print_linkprop(datalink_id_t linkid, show_linkprop_state_t *statep,
5355e7801d59Ssowmini     const char *propname, dladm_prop_type_t type,
5356d62bc4baSyz147064     const char *format, char **pptr)
53570ba2cbe9Sxc151355 {
53580ba2cbe9Sxc151355 	int		i;
53590ba2cbe9Sxc151355 	char		*ptr, *lim;
53600ba2cbe9Sxc151355 	char		buf[DLADM_STRSIZE];
5361*da14cebeSEric Cheng 	char		*unknown = "--", *notsup = "";
53620ba2cbe9Sxc151355 	char		**propvals = statep->ls_propvals;
5363d62bc4baSyz147064 	uint_t		valcnt = DLADM_MAX_PROP_VALCNT;
53640ba2cbe9Sxc151355 	dladm_status_t	status;
53650ba2cbe9Sxc151355 
5366d62bc4baSyz147064 	status = dladm_get_linkprop(linkid, type, propname, propvals, &valcnt);
53670ba2cbe9Sxc151355 	if (status != DLADM_STATUS_OK) {
5368f595a68aSyz147064 		if (status == DLADM_STATUS_TEMPONLY) {
5369d62bc4baSyz147064 			if (type == DLADM_PROP_VAL_MODIFIABLE &&
5370d62bc4baSyz147064 			    statep->ls_persist) {
5371d62bc4baSyz147064 				valcnt = 1;
5372d62bc4baSyz147064 				propvals = &unknown;
5373d62bc4baSyz147064 			} else {
5374f595a68aSyz147064 				statep->ls_status = status;
5375e7801d59Ssowmini 				statep->ls_retstatus = status;
5376f595a68aSyz147064 				return;
5377d62bc4baSyz147064 			}
5378f595a68aSyz147064 		} else if (status == DLADM_STATUS_NOTSUP ||
5379f595a68aSyz147064 		    statep->ls_persist) {
53800ba2cbe9Sxc151355 			valcnt = 1;
5381afdda45fSVasumathi Sundaram - Sun Microsystems 			if (type == DLADM_PROP_VAL_CURRENT ||
5382afdda45fSVasumathi Sundaram - Sun Microsystems 			    type == DLADM_PROP_VAL_PERM)
53830ba2cbe9Sxc151355 				propvals = &unknown;
53840ba2cbe9Sxc151355 			else
53850ba2cbe9Sxc151355 				propvals = &notsup;
5386149b7eb2SSowmini Varadhan 		} else if (status == DLADM_STATUS_NOTDEFINED) {
5387149b7eb2SSowmini Varadhan 			propvals = &notsup; /* STR_UNDEF_VAL */
53880ba2cbe9Sxc151355 		} else {
5389e7801d59Ssowmini 			if (statep->ls_proplist &&
5390e7801d59Ssowmini 			    statep->ls_status == DLADM_STATUS_OK) {
5391f595a68aSyz147064 				warn_dlerr(status,
5392f595a68aSyz147064 				    "cannot get link property '%s' for %s",
5393f595a68aSyz147064 				    propname, statep->ls_link);
5394d62bc4baSyz147064 			}
5395e7801d59Ssowmini 			statep->ls_status = status;
5396e7801d59Ssowmini 			statep->ls_retstatus = status;
5397f595a68aSyz147064 			return;
53980ba2cbe9Sxc151355 		}
53990ba2cbe9Sxc151355 	}
54000ba2cbe9Sxc151355 
5401e7801d59Ssowmini 	statep->ls_status = DLADM_STATUS_OK;
5402e7801d59Ssowmini 
54030ba2cbe9Sxc151355 	ptr = buf;
54040ba2cbe9Sxc151355 	lim = buf + DLADM_STRSIZE;
54050ba2cbe9Sxc151355 	for (i = 0; i < valcnt; i++) {
54060ba2cbe9Sxc151355 		if (propvals[i][0] == '\0' && !statep->ls_parseable)
5407e7801d59Ssowmini 			ptr += snprintf(ptr, lim - ptr, STR_UNDEF_VAL",");
54080ba2cbe9Sxc151355 		else
54090ba2cbe9Sxc151355 			ptr += snprintf(ptr, lim - ptr, "%s,", propvals[i]);
54100ba2cbe9Sxc151355 		if (ptr >= lim)
54110ba2cbe9Sxc151355 			break;
54120ba2cbe9Sxc151355 	}
54130ba2cbe9Sxc151355 	if (valcnt > 0)
54140ba2cbe9Sxc151355 		buf[strlen(buf) - 1] = '\0';
54150ba2cbe9Sxc151355 
54160ba2cbe9Sxc151355 	lim = statep->ls_line + MAX_PROP_LINE;
54170ba2cbe9Sxc151355 	if (statep->ls_parseable) {
54180ba2cbe9Sxc151355 		*pptr += snprintf(*pptr, lim - *pptr,
5419e7801d59Ssowmini 		    "%s", buf);
54200ba2cbe9Sxc151355 	} else {
54210ba2cbe9Sxc151355 		*pptr += snprintf(*pptr, lim - *pptr, format, buf);
54220ba2cbe9Sxc151355 	}
54230ba2cbe9Sxc151355 }
54240ba2cbe9Sxc151355 
5425e7801d59Ssowmini static char *
5426e7801d59Ssowmini linkprop_callback(print_field_t *pf, void *ls_arg)
5427e7801d59Ssowmini {
5428e7801d59Ssowmini 	linkprop_args_t		*arg = ls_arg;
5429e7801d59Ssowmini 	char 			*propname = arg->ls_propname;
5430e7801d59Ssowmini 	show_linkprop_state_t	*statep = arg->ls_state;
5431e7801d59Ssowmini 	char			*ptr = statep->ls_line;
5432e7801d59Ssowmini 	char			*lim = ptr + MAX_PROP_LINE;
5433e7801d59Ssowmini 	datalink_id_t		linkid = arg->ls_linkid;
5434e7801d59Ssowmini 
5435e7801d59Ssowmini 	switch (pf->pf_index) {
5436e7801d59Ssowmini 	case LINKPROP_LINK:
5437e7801d59Ssowmini 		(void) snprintf(ptr, lim - ptr, "%s", statep->ls_link);
5438e7801d59Ssowmini 		break;
5439e7801d59Ssowmini 	case LINKPROP_PROPERTY:
5440e7801d59Ssowmini 		(void) snprintf(ptr, lim - ptr, "%s", propname);
5441e7801d59Ssowmini 		break;
5442e7801d59Ssowmini 	case LINKPROP_VALUE:
5443e7801d59Ssowmini 		print_linkprop(linkid, statep, propname,
5444e7801d59Ssowmini 		    statep->ls_persist ? DLADM_PROP_VAL_PERSISTENT :
5445e7801d59Ssowmini 		    DLADM_PROP_VAL_CURRENT, "%s", &ptr);
5446e7801d59Ssowmini 		/*
5447e7801d59Ssowmini 		 * If we failed to query the link property, for example, query
5448e7801d59Ssowmini 		 * the persistent value of a non-persistable link property,
5449e7801d59Ssowmini 		 * simply skip the output.
5450e7801d59Ssowmini 		 */
5451e7801d59Ssowmini 		if (statep->ls_status != DLADM_STATUS_OK)
5452e7801d59Ssowmini 			goto skip;
5453e7801d59Ssowmini 		ptr = statep->ls_line;
5454e7801d59Ssowmini 		break;
5455afdda45fSVasumathi Sundaram - Sun Microsystems 	case LINKPROP_PERM:
5456afdda45fSVasumathi Sundaram - Sun Microsystems 		print_linkprop(linkid, statep, propname,
5457afdda45fSVasumathi Sundaram - Sun Microsystems 		    DLADM_PROP_VAL_PERM, "%s", &ptr);
5458afdda45fSVasumathi Sundaram - Sun Microsystems 		if (statep->ls_status != DLADM_STATUS_OK)
5459afdda45fSVasumathi Sundaram - Sun Microsystems 			goto skip;
5460afdda45fSVasumathi Sundaram - Sun Microsystems 		ptr = statep->ls_line;
5461afdda45fSVasumathi Sundaram - Sun Microsystems 		break;
5462e7801d59Ssowmini 	case LINKPROP_DEFAULT:
5463e7801d59Ssowmini 		print_linkprop(linkid, statep, propname,
5464e7801d59Ssowmini 		    DLADM_PROP_VAL_DEFAULT, "%s", &ptr);
5465e7801d59Ssowmini 		if (statep->ls_status != DLADM_STATUS_OK)
5466e7801d59Ssowmini 			goto skip;
5467e7801d59Ssowmini 		ptr = statep->ls_line;
5468e7801d59Ssowmini 		break;
5469e7801d59Ssowmini 	case LINKPROP_POSSIBLE:
5470e7801d59Ssowmini 		print_linkprop(linkid, statep, propname,
5471e7801d59Ssowmini 		    DLADM_PROP_VAL_MODIFIABLE, "%s ", &ptr);
5472e7801d59Ssowmini 		if (statep->ls_status != DLADM_STATUS_OK)
5473e7801d59Ssowmini 			goto skip;
5474e7801d59Ssowmini 		ptr = statep->ls_line;
5475e7801d59Ssowmini 		break;
5476e7801d59Ssowmini 	default:
5477e7801d59Ssowmini 		die("invalid input");
5478e7801d59Ssowmini 		break;
5479e7801d59Ssowmini 	}
5480e7801d59Ssowmini 	return (ptr);
5481e7801d59Ssowmini skip:
5482e7801d59Ssowmini 	if (statep->ls_status != DLADM_STATUS_OK)
5483e7801d59Ssowmini 		return (NULL);
5484e7801d59Ssowmini 	else
5485e7801d59Ssowmini 		return ("");
5486e7801d59Ssowmini }
5487e7801d59Ssowmini 
5488bcb5c89dSSowmini Varadhan static boolean_t
5489bcb5c89dSSowmini Varadhan linkprop_is_supported(datalink_id_t  linkid, const char *propname,
5490bcb5c89dSSowmini Varadhan     show_linkprop_state_t *statep)
5491bcb5c89dSSowmini Varadhan {
5492bcb5c89dSSowmini Varadhan 	dladm_status_t	status;
5493bcb5c89dSSowmini Varadhan 	uint_t		valcnt = DLADM_MAX_PROP_VALCNT;
5494bcb5c89dSSowmini Varadhan 
5495bcb5c89dSSowmini Varadhan 	status = dladm_get_linkprop(linkid, DLADM_PROP_VAL_DEFAULT,
5496bcb5c89dSSowmini Varadhan 	    propname, statep->ls_propvals, &valcnt);
5497bcb5c89dSSowmini Varadhan 
5498149b7eb2SSowmini Varadhan 	if (status == DLADM_STATUS_OK)
5499149b7eb2SSowmini Varadhan 		return (B_TRUE);
5500149b7eb2SSowmini Varadhan 
5501149b7eb2SSowmini Varadhan 	/*
5502149b7eb2SSowmini Varadhan 	 * A system wide default value is not available for the
5503149b7eb2SSowmini Varadhan 	 * property. Check if current value can be retrieved.
5504149b7eb2SSowmini Varadhan 	 */
5505149b7eb2SSowmini Varadhan 	status = dladm_get_linkprop(linkid, DLADM_PROP_VAL_CURRENT,
5506149b7eb2SSowmini Varadhan 	    propname, statep->ls_propvals, &valcnt);
5507149b7eb2SSowmini Varadhan 
5508149b7eb2SSowmini Varadhan 	return (status == DLADM_STATUS_OK);
5509bcb5c89dSSowmini Varadhan }
5510bcb5c89dSSowmini Varadhan 
5511d62bc4baSyz147064 static int
5512d62bc4baSyz147064 show_linkprop(datalink_id_t linkid, const char *propname, void *arg)
55130ba2cbe9Sxc151355 {
55140ba2cbe9Sxc151355 	show_linkprop_state_t	*statep = arg;
5515e7801d59Ssowmini 	linkprop_args_t		ls_arg;
55160ba2cbe9Sxc151355 
5517e7801d59Ssowmini 	bzero(&ls_arg, sizeof (ls_arg));
5518e7801d59Ssowmini 	ls_arg.ls_state = statep;
5519e7801d59Ssowmini 	ls_arg.ls_propname = (char *)propname;
5520e7801d59Ssowmini 	ls_arg.ls_linkid = linkid;
55210ba2cbe9Sxc151355 
55220ba2cbe9Sxc151355 	if (statep->ls_header) {
55230ba2cbe9Sxc151355 		statep->ls_header = B_FALSE;
55240ba2cbe9Sxc151355 		if (!statep->ls_parseable)
5525e7801d59Ssowmini 			print_header(&statep->ls_print);
55260ba2cbe9Sxc151355 	}
5527149b7eb2SSowmini Varadhan 	if (!statep->ls_parseable &&
5528149b7eb2SSowmini Varadhan 	    !linkprop_is_supported(linkid, propname, statep))
5529bcb5c89dSSowmini Varadhan 		return (DLADM_WALK_CONTINUE);
5530bcb5c89dSSowmini Varadhan 
5531e7801d59Ssowmini 	dladm_print_output(&statep->ls_print, statep->ls_parseable,
5532e7801d59Ssowmini 	    linkprop_callback, (void *)&ls_arg);
5533e7801d59Ssowmini 
5534d62bc4baSyz147064 	return (DLADM_WALK_CONTINUE);
55350ba2cbe9Sxc151355 }
55360ba2cbe9Sxc151355 
55370ba2cbe9Sxc151355 static void
55388d5c46e6Sam223141 do_show_linkprop(int argc, char **argv, const char *use)
55390ba2cbe9Sxc151355 {
5540f4b3ec61Sdh155122 	int			option;
5541*da14cebeSEric Cheng 	dladm_arg_list_t	*proplist = NULL;
5542d62bc4baSyz147064 	datalink_id_t		linkid = DATALINK_ALL_LINKID;
55430ba2cbe9Sxc151355 	show_linkprop_state_t	state;
5544d62bc4baSyz147064 	uint32_t		flags = DLADM_OPT_ACTIVE;
5545d62bc4baSyz147064 	dladm_status_t		status;
5546e7801d59Ssowmini 	char			*fields_str = NULL;
5547e7801d59Ssowmini 	print_field_t		**fields;
5548e7801d59Ssowmini 	uint_t			nfields;
55490d365605Sschuster 	boolean_t		o_arg = B_FALSE;
5550e7801d59Ssowmini 	char			*all_fields =
5551afdda45fSVasumathi Sundaram - Sun Microsystems 	    "link,property,perm,value,default,possible";
5552e7801d59Ssowmini 
5553e7801d59Ssowmini 	fields_str = all_fields;
55540ba2cbe9Sxc151355 
55550ba2cbe9Sxc151355 	opterr = 0;
55560ba2cbe9Sxc151355 	state.ls_propvals = NULL;
55570ba2cbe9Sxc151355 	state.ls_line = NULL;
55580ba2cbe9Sxc151355 	state.ls_parseable = B_FALSE;
55590ba2cbe9Sxc151355 	state.ls_persist = B_FALSE;
55600ba2cbe9Sxc151355 	state.ls_header = B_TRUE;
5561e7801d59Ssowmini 	state.ls_retstatus = DLADM_STATUS_OK;
5562e7801d59Ssowmini 	while ((option = getopt_long(argc, argv, ":p:cPo:",
55630ba2cbe9Sxc151355 	    prop_longopts, NULL)) != -1) {
55640ba2cbe9Sxc151355 		switch (option) {
55650ba2cbe9Sxc151355 		case 'p':
5566*da14cebeSEric Cheng 			if (dladm_parse_link_props(optarg, &proplist, B_TRUE)
5567*da14cebeSEric Cheng 			    != DLADM_STATUS_OK)
556813994ee8Sxz162242 				die("invalid link properties specified");
55690ba2cbe9Sxc151355 			break;
55700ba2cbe9Sxc151355 		case 'c':
55710ba2cbe9Sxc151355 			state.ls_parseable = B_TRUE;
55720ba2cbe9Sxc151355 			break;
55730ba2cbe9Sxc151355 		case 'P':
55740ba2cbe9Sxc151355 			state.ls_persist = B_TRUE;
5575d62bc4baSyz147064 			flags = DLADM_OPT_PERSIST;
55760ba2cbe9Sxc151355 			break;
5577e7801d59Ssowmini 		case 'o':
55780d365605Sschuster 			o_arg = B_TRUE;
5579e7801d59Ssowmini 			if (strcasecmp(optarg, "all") == 0)
5580e7801d59Ssowmini 				fields_str = all_fields;
5581e7801d59Ssowmini 			else
5582e7801d59Ssowmini 				fields_str = optarg;
5583e7801d59Ssowmini 			break;
55840ba2cbe9Sxc151355 		default:
55858d5c46e6Sam223141 			die_opterr(optopt, option, use);
55860ba2cbe9Sxc151355 			break;
55870ba2cbe9Sxc151355 		}
55880ba2cbe9Sxc151355 	}
55890ba2cbe9Sxc151355 
55900d365605Sschuster 	if (state.ls_parseable && !o_arg)
55910d365605Sschuster 		die("-c requires -o");
55920d365605Sschuster 
55930d365605Sschuster 	if (state.ls_parseable && fields_str == all_fields)
55940d365605Sschuster 		die("\"-o all\" is invalid with -c");
55950d365605Sschuster 
5596d62bc4baSyz147064 	if (optind == (argc - 1)) {
5597d62bc4baSyz147064 		if ((status = dladm_name2info(argv[optind], &linkid, NULL,
5598d62bc4baSyz147064 		    NULL, NULL)) != DLADM_STATUS_OK) {
5599d62bc4baSyz147064 			die_dlerr(status, "link %s is not valid", argv[optind]);
5600d62bc4baSyz147064 		}
5601d62bc4baSyz147064 	} else if (optind != argc) {
56020ba2cbe9Sxc151355 		usage();
5603d62bc4baSyz147064 	}
56040ba2cbe9Sxc151355 
5605e7801d59Ssowmini 	bzero(&state.ls_print, sizeof (print_state_t));
5606f4b3ec61Sdh155122 	state.ls_proplist = proplist;
5607f595a68aSyz147064 	state.ls_status = DLADM_STATUS_OK;
5608f4b3ec61Sdh155122 
5609e7801d59Ssowmini 	fields = parse_output_fields(fields_str, linkprop_fields,
5610e7801d59Ssowmini 	    LINKPROP_MAX_FIELDS, CMD_TYPE_ANY, &nfields);
5611e7801d59Ssowmini 
5612e7801d59Ssowmini 	if (fields == NULL) {
5613e7801d59Ssowmini 		die("invalid field(s) specified");
5614e7801d59Ssowmini 		return;
5615e7801d59Ssowmini 	}
5616e7801d59Ssowmini 
5617e7801d59Ssowmini 	state.ls_print.ps_fields = fields;
5618e7801d59Ssowmini 	state.ls_print.ps_nfields = nfields;
5619d62bc4baSyz147064 	if (linkid == DATALINK_ALL_LINKID) {
5620d62bc4baSyz147064 		(void) dladm_walk_datalink_id(show_linkprop_onelink, &state,
5621d62bc4baSyz147064 		    DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE, flags);
5622f4b3ec61Sdh155122 	} else {
5623d62bc4baSyz147064 		(void) show_linkprop_onelink(linkid, &state);
5624f4b3ec61Sdh155122 	}
5625*da14cebeSEric Cheng 	dladm_free_props(proplist);
5626f595a68aSyz147064 
5627e7801d59Ssowmini 	if (state.ls_retstatus != DLADM_STATUS_OK)
5628f595a68aSyz147064 		exit(EXIT_FAILURE);
5629f4b3ec61Sdh155122 }
5630f4b3ec61Sdh155122 
5631d62bc4baSyz147064 static int
5632d62bc4baSyz147064 show_linkprop_onelink(datalink_id_t linkid, void *arg)
5633f4b3ec61Sdh155122 {
5634948f2876Sss150715 	int			i;
5635f4b3ec61Sdh155122 	char			*buf;
5636d62bc4baSyz147064 	uint32_t		flags;
5637*da14cebeSEric Cheng 	dladm_arg_list_t	*proplist = NULL;
5638d62bc4baSyz147064 	show_linkprop_state_t	*statep = arg;
5639d62bc4baSyz147064 	dlpi_handle_t		dh = NULL;
5640f4b3ec61Sdh155122 
5641d62bc4baSyz147064 	statep->ls_status = DLADM_STATUS_OK;
5642d62bc4baSyz147064 
5643d62bc4baSyz147064 	if (dladm_datalink_id2info(linkid, &flags, NULL, NULL, statep->ls_link,
5644d62bc4baSyz147064 	    MAXLINKNAMELEN) != DLADM_STATUS_OK) {
5645d62bc4baSyz147064 		statep->ls_status = DLADM_STATUS_NOTFOUND;
5646d62bc4baSyz147064 		return (DLADM_WALK_CONTINUE);
5647d62bc4baSyz147064 	}
5648d62bc4baSyz147064 
5649d62bc4baSyz147064 	if ((statep->ls_persist && !(flags & DLADM_OPT_PERSIST)) ||
5650d62bc4baSyz147064 	    (!statep->ls_persist && !(flags & DLADM_OPT_ACTIVE))) {
5651d62bc4baSyz147064 		statep->ls_status = DLADM_STATUS_BADARG;
5652d62bc4baSyz147064 		return (DLADM_WALK_CONTINUE);
5653d62bc4baSyz147064 	}
5654d62bc4baSyz147064 
5655f4b3ec61Sdh155122 	proplist = statep->ls_proplist;
56560ba2cbe9Sxc151355 
56570ba2cbe9Sxc151355 	/*
56580ba2cbe9Sxc151355 	 * When some WiFi links are opened for the first time, their hardware
56590ba2cbe9Sxc151355 	 * automatically scans for APs and does other slow operations.	Thus,
56600ba2cbe9Sxc151355 	 * if there are no open links, the retrieval of link properties
56610ba2cbe9Sxc151355 	 * (below) will proceed slowly unless we hold the link open.
5662d62bc4baSyz147064 	 *
5663d62bc4baSyz147064 	 * Note that failure of dlpi_open() does not necessarily mean invalid
5664d62bc4baSyz147064 	 * link properties, because dlpi_open() may fail because of incorrect
5665d62bc4baSyz147064 	 * autopush configuration. Therefore, we ingore the return value of
5666d62bc4baSyz147064 	 * dlpi_open().
56670ba2cbe9Sxc151355 	 */
5668d62bc4baSyz147064 	if (!statep->ls_persist)
5669d62bc4baSyz147064 		(void) dlpi_open(statep->ls_link, &dh, 0);
56700ba2cbe9Sxc151355 
5671d62bc4baSyz147064 	buf = malloc((sizeof (char *) + DLADM_PROP_VAL_MAX) *
5672d62bc4baSyz147064 	    DLADM_MAX_PROP_VALCNT + MAX_PROP_LINE);
567333343a97Smeem 	if (buf == NULL)
567433343a97Smeem 		die("insufficient memory");
567533343a97Smeem 
5676f4b3ec61Sdh155122 	statep->ls_propvals = (char **)(void *)buf;
5677d62bc4baSyz147064 	for (i = 0; i < DLADM_MAX_PROP_VALCNT; i++) {
5678d62bc4baSyz147064 		statep->ls_propvals[i] = buf +
5679d62bc4baSyz147064 		    sizeof (char *) * DLADM_MAX_PROP_VALCNT +
56800ba2cbe9Sxc151355 		    i * DLADM_PROP_VAL_MAX;
56810ba2cbe9Sxc151355 	}
5682f4b3ec61Sdh155122 	statep->ls_line = buf +
5683d62bc4baSyz147064 	    (sizeof (char *) + DLADM_PROP_VAL_MAX) * DLADM_MAX_PROP_VALCNT;
56840ba2cbe9Sxc151355 
56850ba2cbe9Sxc151355 	if (proplist != NULL) {
5686*da14cebeSEric Cheng 		for (i = 0; i < proplist->al_count; i++) {
5687d62bc4baSyz147064 			(void) show_linkprop(linkid,
5688*da14cebeSEric Cheng 			    proplist->al_info[i].ai_name, statep);
56890ba2cbe9Sxc151355 		}
5690d62bc4baSyz147064 	} else {
5691d62bc4baSyz147064 		(void) dladm_walk_linkprop(linkid, statep, show_linkprop);
5692d62bc4baSyz147064 	}
5693d62bc4baSyz147064 	if (dh != NULL)
5694948f2876Sss150715 		dlpi_close(dh);
56950ba2cbe9Sxc151355 	free(buf);
5696d62bc4baSyz147064 	return (DLADM_WALK_CONTINUE);
56970ba2cbe9Sxc151355 }
56980ba2cbe9Sxc151355 
56990ba2cbe9Sxc151355 static dladm_status_t
5700d62bc4baSyz147064 set_linkprop_persist(datalink_id_t linkid, const char *prop_name,
5701d62bc4baSyz147064     char **prop_val, uint_t val_cnt, boolean_t reset)
57020ba2cbe9Sxc151355 {
57030ba2cbe9Sxc151355 	dladm_status_t	status;
57040ba2cbe9Sxc151355 
5705d62bc4baSyz147064 	status = dladm_set_linkprop(linkid, prop_name, prop_val, val_cnt,
5706d62bc4baSyz147064 	    DLADM_OPT_PERSIST);
57070ba2cbe9Sxc151355 
57080ba2cbe9Sxc151355 	if (status != DLADM_STATUS_OK) {
5709*da14cebeSEric Cheng 		warn_dlerr(status, "cannot persistently %s link property '%s'",
5710*da14cebeSEric Cheng 		    reset ? "reset" : "set", prop_name);
57110ba2cbe9Sxc151355 	}
57120ba2cbe9Sxc151355 	return (status);
57130ba2cbe9Sxc151355 }
57140ba2cbe9Sxc151355 
5715*da14cebeSEric Cheng static int
5716*da14cebeSEric Cheng reset_one_linkprop(datalink_id_t linkid, const char *propname, void *arg)
5717*da14cebeSEric Cheng {
5718*da14cebeSEric Cheng 	set_linkprop_state_t	*statep = arg;
5719*da14cebeSEric Cheng 	dladm_status_t		status;
5720*da14cebeSEric Cheng 
5721*da14cebeSEric Cheng 	status = dladm_set_linkprop(linkid, propname, NULL, 0,
5722*da14cebeSEric Cheng 	    DLADM_OPT_ACTIVE);
5723*da14cebeSEric Cheng 	if (status != DLADM_STATUS_OK) {
5724*da14cebeSEric Cheng 		warn_dlerr(status, "cannot reset link property '%s' on '%s'",
5725*da14cebeSEric Cheng 		    propname, statep->ls_name);
5726*da14cebeSEric Cheng 	}
5727*da14cebeSEric Cheng 	if (!statep->ls_temp) {
5728*da14cebeSEric Cheng 		dladm_status_t	s;
5729*da14cebeSEric Cheng 
5730*da14cebeSEric Cheng 		s = set_linkprop_persist(linkid, propname, NULL, 0,
5731*da14cebeSEric Cheng 		    statep->ls_reset);
5732*da14cebeSEric Cheng 		if (s != DLADM_STATUS_OK)
5733*da14cebeSEric Cheng 			status = s;
5734*da14cebeSEric Cheng 	}
5735*da14cebeSEric Cheng 	if (status != DLADM_STATUS_OK)
5736*da14cebeSEric Cheng 		statep->ls_status = status;
5737*da14cebeSEric Cheng 
5738*da14cebeSEric Cheng 	return (DLADM_WALK_CONTINUE);
5739*da14cebeSEric Cheng }
5740*da14cebeSEric Cheng 
57410ba2cbe9Sxc151355 static void
57428d5c46e6Sam223141 set_linkprop(int argc, char **argv, boolean_t reset, const char *use)
57430ba2cbe9Sxc151355 {
57440ba2cbe9Sxc151355 	int			i, option;
57450ba2cbe9Sxc151355 	char			errmsg[DLADM_STRSIZE];
5746d62bc4baSyz147064 	char			*altroot = NULL;
5747d62bc4baSyz147064 	datalink_id_t		linkid;
57480ba2cbe9Sxc151355 	boolean_t		temp = B_FALSE;
57490ba2cbe9Sxc151355 	dladm_status_t		status = DLADM_STATUS_OK;
5750*da14cebeSEric Cheng 	dladm_arg_list_t	*proplist = NULL;
57510ba2cbe9Sxc151355 
57520ba2cbe9Sxc151355 	opterr = 0;
57530ba2cbe9Sxc151355 	while ((option = getopt_long(argc, argv, ":p:R:t",
57540ba2cbe9Sxc151355 	    prop_longopts, NULL)) != -1) {
57550ba2cbe9Sxc151355 		switch (option) {
57560ba2cbe9Sxc151355 		case 'p':
5757*da14cebeSEric Cheng 			if (dladm_parse_link_props(optarg, &proplist, reset) !=
5758*da14cebeSEric Cheng 			    DLADM_STATUS_OK) {
575933343a97Smeem 				die("invalid link properties specified");
5760*da14cebeSEric Cheng 			}
57610ba2cbe9Sxc151355 			break;
57620ba2cbe9Sxc151355 		case 't':
57630ba2cbe9Sxc151355 			temp = B_TRUE;
57640ba2cbe9Sxc151355 			break;
57650ba2cbe9Sxc151355 		case 'R':
5766d62bc4baSyz147064 			altroot = optarg;
57670ba2cbe9Sxc151355 			break;
57680ba2cbe9Sxc151355 		default:
57698d5c46e6Sam223141 			die_opterr(optopt, option, use);
57708d5c46e6Sam223141 
57710ba2cbe9Sxc151355 		}
57720ba2cbe9Sxc151355 	}
57730ba2cbe9Sxc151355 
5774d62bc4baSyz147064 	/* get link name (required last argument) */
5775d62bc4baSyz147064 	if (optind != (argc - 1))
57760ba2cbe9Sxc151355 		usage();
57770ba2cbe9Sxc151355 
5778d62bc4baSyz147064 	if (proplist == NULL && !reset)
577933343a97Smeem 		die("link property must be specified");
578033343a97Smeem 
5781d62bc4baSyz147064 	if (altroot != NULL) {
5782*da14cebeSEric Cheng 		dladm_free_props(proplist);
5783d62bc4baSyz147064 		altroot_cmd(altroot, argc, argv);
5784d62bc4baSyz147064 	}
5785d62bc4baSyz147064 
5786d62bc4baSyz147064 	status = dladm_name2info(argv[optind], &linkid, NULL, NULL, NULL);
5787d62bc4baSyz147064 	if (status != DLADM_STATUS_OK)
5788d62bc4baSyz147064 		die_dlerr(status, "link %s is not valid", argv[optind]);
5789d62bc4baSyz147064 
5790d62bc4baSyz147064 	if (proplist == NULL) {
5791*da14cebeSEric Cheng 		set_linkprop_state_t	state;
579213994ee8Sxz162242 
5793*da14cebeSEric Cheng 		state.ls_name = argv[optind];
5794*da14cebeSEric Cheng 		state.ls_reset = reset;
5795*da14cebeSEric Cheng 		state.ls_temp = temp;
5796*da14cebeSEric Cheng 		state.ls_status = DLADM_STATUS_OK;
5797*da14cebeSEric Cheng 
5798*da14cebeSEric Cheng 		(void) dladm_walk_linkprop(linkid, &state, reset_one_linkprop);
5799*da14cebeSEric Cheng 
5800*da14cebeSEric Cheng 		status = state.ls_status;
58010ba2cbe9Sxc151355 		goto done;
58020ba2cbe9Sxc151355 	}
58030ba2cbe9Sxc151355 
5804*da14cebeSEric Cheng 	for (i = 0; i < proplist->al_count; i++) {
5805*da14cebeSEric Cheng 		dladm_arg_info_t	*aip = &proplist->al_info[i];
58060ba2cbe9Sxc151355 		char		**val;
58070ba2cbe9Sxc151355 		uint_t		count;
58080ba2cbe9Sxc151355 		dladm_status_t	s;
58090ba2cbe9Sxc151355 
58100ba2cbe9Sxc151355 		if (reset) {
58110ba2cbe9Sxc151355 			val = NULL;
58120ba2cbe9Sxc151355 			count = 0;
58130ba2cbe9Sxc151355 		} else {
5814*da14cebeSEric Cheng 			val = aip->ai_val;
5815*da14cebeSEric Cheng 			count = aip->ai_count;
58160ba2cbe9Sxc151355 			if (count == 0) {
581733343a97Smeem 				warn("no value specified for '%s'",
5818*da14cebeSEric Cheng 				    aip->ai_name);
58190ba2cbe9Sxc151355 				status = DLADM_STATUS_BADARG;
58200ba2cbe9Sxc151355 				continue;
58210ba2cbe9Sxc151355 			}
58220ba2cbe9Sxc151355 		}
5823*da14cebeSEric Cheng 		s = dladm_set_linkprop(linkid, aip->ai_name, val, count,
5824d62bc4baSyz147064 		    DLADM_OPT_ACTIVE);
58250ba2cbe9Sxc151355 		if (s == DLADM_STATUS_OK) {
58260ba2cbe9Sxc151355 			if (!temp) {
5827d62bc4baSyz147064 				s = set_linkprop_persist(linkid,
5828*da14cebeSEric Cheng 				    aip->ai_name, val, count, reset);
58290ba2cbe9Sxc151355 				if (s != DLADM_STATUS_OK)
58300ba2cbe9Sxc151355 					status = s;
58310ba2cbe9Sxc151355 			}
58320ba2cbe9Sxc151355 			continue;
58330ba2cbe9Sxc151355 		}
58340ba2cbe9Sxc151355 		status = s;
58350ba2cbe9Sxc151355 		switch (s) {
58360ba2cbe9Sxc151355 		case DLADM_STATUS_NOTFOUND:
5837*da14cebeSEric Cheng 			warn("invalid link property '%s'", aip->ai_name);
58380ba2cbe9Sxc151355 			break;
58390ba2cbe9Sxc151355 		case DLADM_STATUS_BADVAL: {
58400ba2cbe9Sxc151355 			int		j;
58410ba2cbe9Sxc151355 			char		*ptr, *lim;
58420ba2cbe9Sxc151355 			char		**propvals = NULL;
5843d62bc4baSyz147064 			uint_t		valcnt = DLADM_MAX_PROP_VALCNT;
58440ba2cbe9Sxc151355 
58450ba2cbe9Sxc151355 			ptr = malloc((sizeof (char *) +
5846d62bc4baSyz147064 			    DLADM_PROP_VAL_MAX) * DLADM_MAX_PROP_VALCNT +
58470ba2cbe9Sxc151355 			    MAX_PROP_LINE);
58480ba2cbe9Sxc151355 
58490ba2cbe9Sxc151355 			propvals = (char **)(void *)ptr;
585033343a97Smeem 			if (propvals == NULL)
585133343a97Smeem 				die("insufficient memory");
585233343a97Smeem 
5853d62bc4baSyz147064 			for (j = 0; j < DLADM_MAX_PROP_VALCNT; j++) {
58540ba2cbe9Sxc151355 				propvals[j] = ptr + sizeof (char *) *
5855d62bc4baSyz147064 				    DLADM_MAX_PROP_VALCNT +
58560ba2cbe9Sxc151355 				    j * DLADM_PROP_VAL_MAX;
58570ba2cbe9Sxc151355 			}
5858d62bc4baSyz147064 			s = dladm_get_linkprop(linkid,
5859*da14cebeSEric Cheng 			    DLADM_PROP_VAL_MODIFIABLE, aip->ai_name, propvals,
5860d62bc4baSyz147064 			    &valcnt);
5861d62bc4baSyz147064 
5862d62bc4baSyz147064 			if (s != DLADM_STATUS_OK) {
5863d62bc4baSyz147064 				warn_dlerr(status, "cannot set link property "
5864*da14cebeSEric Cheng 				    "'%s' on '%s'", aip->ai_name, argv[optind]);
5865d62bc4baSyz147064 				free(propvals);
5866d62bc4baSyz147064 				break;
5867d62bc4baSyz147064 			}
58680ba2cbe9Sxc151355 
58690ba2cbe9Sxc151355 			ptr = errmsg;
58700ba2cbe9Sxc151355 			lim = ptr + DLADM_STRSIZE;
58710ba2cbe9Sxc151355 			*ptr = '\0';
5872d62bc4baSyz147064 			for (j = 0; j < valcnt; j++) {
58730ba2cbe9Sxc151355 				ptr += snprintf(ptr, lim - ptr, "%s,",
58740ba2cbe9Sxc151355 				    propvals[j]);
58750ba2cbe9Sxc151355 				if (ptr >= lim)
58760ba2cbe9Sxc151355 					break;
58770ba2cbe9Sxc151355 			}
5878f4b3ec61Sdh155122 			if (ptr > errmsg) {
58790ba2cbe9Sxc151355 				*(ptr - 1) = '\0';
588033343a97Smeem 				warn("link property '%s' must be one of: %s",
5881*da14cebeSEric Cheng 				    aip->ai_name, errmsg);
5882f4b3ec61Sdh155122 			} else
5883f4b3ec61Sdh155122 				warn("invalid link property '%s'", *val);
58840ba2cbe9Sxc151355 			free(propvals);
58850ba2cbe9Sxc151355 			break;
58860ba2cbe9Sxc151355 		}
58870ba2cbe9Sxc151355 		default:
58880ba2cbe9Sxc151355 			if (reset) {
588933343a97Smeem 				warn_dlerr(status, "cannot reset link property "
5890*da14cebeSEric Cheng 				    "'%s' on '%s'", aip->ai_name, argv[optind]);
58910ba2cbe9Sxc151355 			} else {
589233343a97Smeem 				warn_dlerr(status, "cannot set link property "
5893*da14cebeSEric Cheng 				    "'%s' on '%s'", aip->ai_name, argv[optind]);
58940ba2cbe9Sxc151355 			}
58950ba2cbe9Sxc151355 			break;
58960ba2cbe9Sxc151355 		}
58970ba2cbe9Sxc151355 	}
58980ba2cbe9Sxc151355 done:
5899*da14cebeSEric Cheng 	dladm_free_props(proplist);
59000ba2cbe9Sxc151355 	if (status != DLADM_STATUS_OK)
59010ba2cbe9Sxc151355 		exit(1);
59020ba2cbe9Sxc151355 }
59030ba2cbe9Sxc151355 
59040ba2cbe9Sxc151355 static void
59058d5c46e6Sam223141 do_set_linkprop(int argc, char **argv, const char *use)
59060ba2cbe9Sxc151355 {
59078d5c46e6Sam223141 	set_linkprop(argc, argv, B_FALSE, use);
59080ba2cbe9Sxc151355 }
59090ba2cbe9Sxc151355 
59100ba2cbe9Sxc151355 static void
59118d5c46e6Sam223141 do_reset_linkprop(int argc, char **argv, const char *use)
59120ba2cbe9Sxc151355 {
59138d5c46e6Sam223141 	set_linkprop(argc, argv, B_TRUE, use);
59140ba2cbe9Sxc151355 }
59150ba2cbe9Sxc151355 
59160ba2cbe9Sxc151355 static int
59170ba2cbe9Sxc151355 convert_secobj(char *buf, uint_t len, uint8_t *obj_val, uint_t *obj_lenp,
59180ba2cbe9Sxc151355     dladm_secobj_class_t class)
59190ba2cbe9Sxc151355 {
59200ba2cbe9Sxc151355 	int error = 0;
59210ba2cbe9Sxc151355 
5922a399b765Szf162725 	if (class == DLADM_SECOBJ_CLASS_WPA) {
5923a399b765Szf162725 		if (len < 8 || len > 63)
5924a399b765Szf162725 			return (EINVAL);
5925a399b765Szf162725 		(void) memcpy(obj_val, buf, len);
5926a399b765Szf162725 		*obj_lenp = len;
5927a399b765Szf162725 		return (error);
5928a399b765Szf162725 	}
59290ba2cbe9Sxc151355 
5930a399b765Szf162725 	if (class == DLADM_SECOBJ_CLASS_WEP) {
59310ba2cbe9Sxc151355 		switch (len) {
59320ba2cbe9Sxc151355 		case 5:			/* ASCII key sizes */
59330ba2cbe9Sxc151355 		case 13:
59340ba2cbe9Sxc151355 			(void) memcpy(obj_val, buf, len);
59350ba2cbe9Sxc151355 			*obj_lenp = len;
59360ba2cbe9Sxc151355 			break;
59370ba2cbe9Sxc151355 		case 10:		/* Hex key sizes, not preceded by 0x */
59380ba2cbe9Sxc151355 		case 26:
59390ba2cbe9Sxc151355 			error = hexascii_to_octet(buf, len, obj_val, obj_lenp);
59400ba2cbe9Sxc151355 			break;
59410ba2cbe9Sxc151355 		case 12:		/* Hex key sizes, preceded by 0x */
59420ba2cbe9Sxc151355 		case 28:
59430ba2cbe9Sxc151355 			if (strncmp(buf, "0x", 2) != 0)
59440ba2cbe9Sxc151355 				return (EINVAL);
5945a399b765Szf162725 			error = hexascii_to_octet(buf + 2, len - 2,
5946a399b765Szf162725 			    obj_val, obj_lenp);
59470ba2cbe9Sxc151355 			break;
59480ba2cbe9Sxc151355 		default:
59490ba2cbe9Sxc151355 			return (EINVAL);
59500ba2cbe9Sxc151355 		}
59510ba2cbe9Sxc151355 		return (error);
59520ba2cbe9Sxc151355 	}
59530ba2cbe9Sxc151355 
5954a399b765Szf162725 	return (ENOENT);
5955a399b765Szf162725 }
5956a399b765Szf162725 
59570ba2cbe9Sxc151355 /* ARGSUSED */
59580ba2cbe9Sxc151355 static void
59590ba2cbe9Sxc151355 defersig(int sig)
59600ba2cbe9Sxc151355 {
59610ba2cbe9Sxc151355 	signalled = sig;
59620ba2cbe9Sxc151355 }
59630ba2cbe9Sxc151355 
59640ba2cbe9Sxc151355 static int
59650ba2cbe9Sxc151355 get_secobj_from_tty(uint_t try, const char *objname, char *buf)
59660ba2cbe9Sxc151355 {
59670ba2cbe9Sxc151355 	uint_t		len = 0;
59680ba2cbe9Sxc151355 	int		c;
59690ba2cbe9Sxc151355 	struct termios	stored, current;
59700ba2cbe9Sxc151355 	void		(*sigfunc)(int);
59710ba2cbe9Sxc151355 
59720ba2cbe9Sxc151355 	/*
59730ba2cbe9Sxc151355 	 * Turn off echo -- but before we do so, defer SIGINT handling
59740ba2cbe9Sxc151355 	 * so that a ^C doesn't leave the terminal corrupted.
59750ba2cbe9Sxc151355 	 */
59760ba2cbe9Sxc151355 	sigfunc = signal(SIGINT, defersig);
59770ba2cbe9Sxc151355 	(void) fflush(stdin);
59780ba2cbe9Sxc151355 	(void) tcgetattr(0, &stored);
59790ba2cbe9Sxc151355 	current = stored;
59800ba2cbe9Sxc151355 	current.c_lflag &= ~(ICANON|ECHO);
59810ba2cbe9Sxc151355 	current.c_cc[VTIME] = 0;
59820ba2cbe9Sxc151355 	current.c_cc[VMIN] = 1;
59830ba2cbe9Sxc151355 	(void) tcsetattr(0, TCSANOW, &current);
59840ba2cbe9Sxc151355 again:
59850ba2cbe9Sxc151355 	if (try == 1)
59860ba2cbe9Sxc151355 		(void) printf(gettext("provide value for '%s': "), objname);
59870ba2cbe9Sxc151355 	else
59880ba2cbe9Sxc151355 		(void) printf(gettext("confirm value for '%s': "), objname);
59890ba2cbe9Sxc151355 
59900ba2cbe9Sxc151355 	(void) fflush(stdout);
59910ba2cbe9Sxc151355 	while (signalled == 0) {
59920ba2cbe9Sxc151355 		c = getchar();
59930ba2cbe9Sxc151355 		if (c == '\n' || c == '\r') {
59940ba2cbe9Sxc151355 			if (len != 0)
59950ba2cbe9Sxc151355 				break;
59960ba2cbe9Sxc151355 			(void) putchar('\n');
59970ba2cbe9Sxc151355 			goto again;
59980ba2cbe9Sxc151355 		}
59990ba2cbe9Sxc151355 
60000ba2cbe9Sxc151355 		buf[len++] = c;
60010ba2cbe9Sxc151355 		if (len >= DLADM_SECOBJ_VAL_MAX - 1)
60020ba2cbe9Sxc151355 			break;
60030ba2cbe9Sxc151355 		(void) putchar('*');
60040ba2cbe9Sxc151355 	}
60050ba2cbe9Sxc151355 
60060ba2cbe9Sxc151355 	(void) putchar('\n');
60070ba2cbe9Sxc151355 	(void) fflush(stdin);
60080ba2cbe9Sxc151355 
60090ba2cbe9Sxc151355 	/*
60100ba2cbe9Sxc151355 	 * Restore terminal setting and handle deferred signals.
60110ba2cbe9Sxc151355 	 */
60120ba2cbe9Sxc151355 	(void) tcsetattr(0, TCSANOW, &stored);
60130ba2cbe9Sxc151355 
60140ba2cbe9Sxc151355 	(void) signal(SIGINT, sigfunc);
60150ba2cbe9Sxc151355 	if (signalled != 0)
60160ba2cbe9Sxc151355 		(void) kill(getpid(), signalled);
60170ba2cbe9Sxc151355 
60180ba2cbe9Sxc151355 	return (len);
60190ba2cbe9Sxc151355 }
60200ba2cbe9Sxc151355 
60210ba2cbe9Sxc151355 static int
60220ba2cbe9Sxc151355 get_secobj_val(char *obj_name, uint8_t *obj_val, uint_t *obj_lenp,
60230ba2cbe9Sxc151355     dladm_secobj_class_t class, FILE *filep)
60240ba2cbe9Sxc151355 {
60250ba2cbe9Sxc151355 	int		rval;
60260ba2cbe9Sxc151355 	uint_t		len, len2;
60270ba2cbe9Sxc151355 	char		buf[DLADM_SECOBJ_VAL_MAX], buf2[DLADM_SECOBJ_VAL_MAX];
60280ba2cbe9Sxc151355 
60290ba2cbe9Sxc151355 	if (filep == NULL) {
60300ba2cbe9Sxc151355 		len = get_secobj_from_tty(1, obj_name, buf);
60310ba2cbe9Sxc151355 		rval = convert_secobj(buf, len, obj_val, obj_lenp, class);
60320ba2cbe9Sxc151355 		if (rval == 0) {
60330ba2cbe9Sxc151355 			len2 = get_secobj_from_tty(2, obj_name, buf2);
60340ba2cbe9Sxc151355 			if (len != len2 || memcmp(buf, buf2, len) != 0)
60350ba2cbe9Sxc151355 				rval = ENOTSUP;
60360ba2cbe9Sxc151355 		}
60370ba2cbe9Sxc151355 		return (rval);
60380ba2cbe9Sxc151355 	} else {
60390ba2cbe9Sxc151355 		for (;;) {
60400ba2cbe9Sxc151355 			if (fgets(buf, sizeof (buf), filep) == NULL)
60410ba2cbe9Sxc151355 				break;
60420ba2cbe9Sxc151355 			if (isspace(buf[0]))
60430ba2cbe9Sxc151355 				continue;
60440ba2cbe9Sxc151355 
60450ba2cbe9Sxc151355 			len = strlen(buf);
60460ba2cbe9Sxc151355 			if (buf[len - 1] == '\n') {
60470ba2cbe9Sxc151355 				buf[len - 1] = '\0';
60480ba2cbe9Sxc151355 				len--;
60490ba2cbe9Sxc151355 			}
60500ba2cbe9Sxc151355 			break;
60510ba2cbe9Sxc151355 		}
60520ba2cbe9Sxc151355 		(void) fclose(filep);
60530ba2cbe9Sxc151355 	}
60540ba2cbe9Sxc151355 	return (convert_secobj(buf, len, obj_val, obj_lenp, class));
60550ba2cbe9Sxc151355 }
60560ba2cbe9Sxc151355 
60570ba2cbe9Sxc151355 static boolean_t
60580ba2cbe9Sxc151355 check_auth(const char *auth)
60590ba2cbe9Sxc151355 {
60600ba2cbe9Sxc151355 	struct passwd	*pw;
60610ba2cbe9Sxc151355 
60620ba2cbe9Sxc151355 	if ((pw = getpwuid(getuid())) == NULL)
60630ba2cbe9Sxc151355 		return (B_FALSE);
60640ba2cbe9Sxc151355 
60650ba2cbe9Sxc151355 	return (chkauthattr(auth, pw->pw_name) != 0);
60660ba2cbe9Sxc151355 }
60670ba2cbe9Sxc151355 
60680ba2cbe9Sxc151355 static void
60690ba2cbe9Sxc151355 audit_secobj(char *auth, char *class, char *obj,
60700ba2cbe9Sxc151355     boolean_t success, boolean_t create)
60710ba2cbe9Sxc151355 {
60720ba2cbe9Sxc151355 	adt_session_data_t	*ah;
60730ba2cbe9Sxc151355 	adt_event_data_t	*event;
60740ba2cbe9Sxc151355 	au_event_t		flag;
60750ba2cbe9Sxc151355 	char			*errstr;
60760ba2cbe9Sxc151355 
60770ba2cbe9Sxc151355 	if (create) {
60780ba2cbe9Sxc151355 		flag = ADT_dladm_create_secobj;
60790ba2cbe9Sxc151355 		errstr = "ADT_dladm_create_secobj";
60800ba2cbe9Sxc151355 	} else {
60810ba2cbe9Sxc151355 		flag = ADT_dladm_delete_secobj;
60820ba2cbe9Sxc151355 		errstr = "ADT_dladm_delete_secobj";
60830ba2cbe9Sxc151355 	}
60840ba2cbe9Sxc151355 
608533343a97Smeem 	if (adt_start_session(&ah, NULL, ADT_USE_PROC_DATA) != 0)
608633343a97Smeem 		die("adt_start_session: %s", strerror(errno));
60870ba2cbe9Sxc151355 
608833343a97Smeem 	if ((event = adt_alloc_event(ah, flag)) == NULL)
608933343a97Smeem 		die("adt_alloc_event (%s): %s", errstr, strerror(errno));
60900ba2cbe9Sxc151355 
60910ba2cbe9Sxc151355 	/* fill in audit info */
60920ba2cbe9Sxc151355 	if (create) {
60930ba2cbe9Sxc151355 		event->adt_dladm_create_secobj.auth_used = auth;
60940ba2cbe9Sxc151355 		event->adt_dladm_create_secobj.obj_class = class;
60950ba2cbe9Sxc151355 		event->adt_dladm_create_secobj.obj_name = obj;
60960ba2cbe9Sxc151355 	} else {
60970ba2cbe9Sxc151355 		event->adt_dladm_delete_secobj.auth_used = auth;
60980ba2cbe9Sxc151355 		event->adt_dladm_delete_secobj.obj_class = class;
60990ba2cbe9Sxc151355 		event->adt_dladm_delete_secobj.obj_name = obj;
61000ba2cbe9Sxc151355 	}
61010ba2cbe9Sxc151355 
61020ba2cbe9Sxc151355 	if (success) {
61030ba2cbe9Sxc151355 		if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS) != 0) {
610433343a97Smeem 			die("adt_put_event (%s, success): %s", errstr,
610533343a97Smeem 			    strerror(errno));
61060ba2cbe9Sxc151355 		}
61070ba2cbe9Sxc151355 	} else {
61080ba2cbe9Sxc151355 		if (adt_put_event(event, ADT_FAILURE,
61090ba2cbe9Sxc151355 		    ADT_FAIL_VALUE_AUTH) != 0) {
611033343a97Smeem 			die("adt_put_event: (%s, failure): %s", errstr,
611133343a97Smeem 			    strerror(errno));
61120ba2cbe9Sxc151355 		}
61130ba2cbe9Sxc151355 	}
61140ba2cbe9Sxc151355 
61150ba2cbe9Sxc151355 	adt_free_event(event);
61160ba2cbe9Sxc151355 	(void) adt_end_session(ah);
61170ba2cbe9Sxc151355 }
61180ba2cbe9Sxc151355 
61190ba2cbe9Sxc151355 #define	MAX_SECOBJS		32
61200ba2cbe9Sxc151355 #define	MAX_SECOBJ_NAMELEN	32
61210ba2cbe9Sxc151355 static void
61228d5c46e6Sam223141 do_create_secobj(int argc, char **argv, const char *use)
61230ba2cbe9Sxc151355 {
61240ba2cbe9Sxc151355 	int			option, rval;
61250ba2cbe9Sxc151355 	FILE			*filep = NULL;
61260ba2cbe9Sxc151355 	char			*obj_name = NULL;
61270ba2cbe9Sxc151355 	char			*class_name = NULL;
61280ba2cbe9Sxc151355 	uint8_t			obj_val[DLADM_SECOBJ_VAL_MAX];
61290ba2cbe9Sxc151355 	uint_t			obj_len;
61300ba2cbe9Sxc151355 	boolean_t		success, temp = B_FALSE;
61310ba2cbe9Sxc151355 	dladm_status_t		status;
61320ba2cbe9Sxc151355 	dladm_secobj_class_t	class = -1;
61330ba2cbe9Sxc151355 	uid_t			euid;
61340ba2cbe9Sxc151355 
61350ba2cbe9Sxc151355 	opterr = 0;
61360ba2cbe9Sxc151355 	(void) memset(obj_val, 0, DLADM_SECOBJ_VAL_MAX);
61370ba2cbe9Sxc151355 	while ((option = getopt_long(argc, argv, ":f:c:R:t",
61380ba2cbe9Sxc151355 	    wifi_longopts, NULL)) != -1) {
61390ba2cbe9Sxc151355 		switch (option) {
61400ba2cbe9Sxc151355 		case 'f':
61410ba2cbe9Sxc151355 			euid = geteuid();
61420ba2cbe9Sxc151355 			(void) seteuid(getuid());
61430ba2cbe9Sxc151355 			filep = fopen(optarg, "r");
61440ba2cbe9Sxc151355 			if (filep == NULL) {
614533343a97Smeem 				die("cannot open %s: %s", optarg,
614633343a97Smeem 				    strerror(errno));
61470ba2cbe9Sxc151355 			}
61480ba2cbe9Sxc151355 			(void) seteuid(euid);
61490ba2cbe9Sxc151355 			break;
61500ba2cbe9Sxc151355 		case 'c':
61510ba2cbe9Sxc151355 			class_name = optarg;
61520ba2cbe9Sxc151355 			status = dladm_str2secobjclass(optarg, &class);
61530ba2cbe9Sxc151355 			if (status != DLADM_STATUS_OK) {
615433343a97Smeem 				die("invalid secure object class '%s', "
6155a399b765Szf162725 				    "valid values are: wep, wpa", optarg);
61560ba2cbe9Sxc151355 			}
61570ba2cbe9Sxc151355 			break;
61580ba2cbe9Sxc151355 		case 't':
61590ba2cbe9Sxc151355 			temp = B_TRUE;
61600ba2cbe9Sxc151355 			break;
61610ba2cbe9Sxc151355 		case 'R':
61620ba2cbe9Sxc151355 			status = dladm_set_rootdir(optarg);
61630ba2cbe9Sxc151355 			if (status != DLADM_STATUS_OK) {
616433343a97Smeem 				die_dlerr(status, "invalid directory "
616533343a97Smeem 				    "specified");
61660ba2cbe9Sxc151355 			}
61670ba2cbe9Sxc151355 			break;
61680ba2cbe9Sxc151355 		default:
61698d5c46e6Sam223141 			die_opterr(optopt, option, use);
61700ba2cbe9Sxc151355 			break;
61710ba2cbe9Sxc151355 		}
61720ba2cbe9Sxc151355 	}
61730ba2cbe9Sxc151355 
61740ba2cbe9Sxc151355 	if (optind == (argc - 1))
61750ba2cbe9Sxc151355 		obj_name = argv[optind];
61760ba2cbe9Sxc151355 	else if (optind != argc)
61770ba2cbe9Sxc151355 		usage();
61780ba2cbe9Sxc151355 
617933343a97Smeem 	if (class == -1)
618033343a97Smeem 		die("secure object class required");
61810ba2cbe9Sxc151355 
618233343a97Smeem 	if (obj_name == NULL)
618333343a97Smeem 		die("secure object name required");
61840ba2cbe9Sxc151355 
61850ba2cbe9Sxc151355 	success = check_auth(LINK_SEC_AUTH);
61860ba2cbe9Sxc151355 	audit_secobj(LINK_SEC_AUTH, class_name, obj_name, success, B_TRUE);
618733343a97Smeem 	if (!success)
618833343a97Smeem 		die("authorization '%s' is required", LINK_SEC_AUTH);
61890ba2cbe9Sxc151355 
619033343a97Smeem 	rval = get_secobj_val(obj_name, obj_val, &obj_len, class, filep);
619133343a97Smeem 	if (rval != 0) {
61920ba2cbe9Sxc151355 		switch (rval) {
61930ba2cbe9Sxc151355 		case ENOENT:
619433343a97Smeem 			die("invalid secure object class");
61950ba2cbe9Sxc151355 			break;
61960ba2cbe9Sxc151355 		case EINVAL:
619733343a97Smeem 			die("invalid secure object value");
61980ba2cbe9Sxc151355 			break;
61990ba2cbe9Sxc151355 		case ENOTSUP:
620033343a97Smeem 			die("verification failed");
62010ba2cbe9Sxc151355 			break;
62020ba2cbe9Sxc151355 		default:
620333343a97Smeem 			die("invalid secure object: %s", strerror(rval));
62040ba2cbe9Sxc151355 			break;
62050ba2cbe9Sxc151355 		}
62060ba2cbe9Sxc151355 	}
62070ba2cbe9Sxc151355 
62080ba2cbe9Sxc151355 	status = dladm_set_secobj(obj_name, class, obj_val, obj_len,
6209d62bc4baSyz147064 	    DLADM_OPT_CREATE | DLADM_OPT_ACTIVE);
62100ba2cbe9Sxc151355 	if (status != DLADM_STATUS_OK) {
621133343a97Smeem 		die_dlerr(status, "could not create secure object '%s'",
621233343a97Smeem 		    obj_name);
62130ba2cbe9Sxc151355 	}
62140ba2cbe9Sxc151355 	if (temp)
62150ba2cbe9Sxc151355 		return;
62160ba2cbe9Sxc151355 
62170ba2cbe9Sxc151355 	status = dladm_set_secobj(obj_name, class, obj_val, obj_len,
62180ba2cbe9Sxc151355 	    DLADM_OPT_PERSIST);
62190ba2cbe9Sxc151355 	if (status != DLADM_STATUS_OK) {
622033343a97Smeem 		warn_dlerr(status, "could not persistently create secure "
622133343a97Smeem 		    "object '%s'", obj_name);
62220ba2cbe9Sxc151355 	}
62230ba2cbe9Sxc151355 }
62240ba2cbe9Sxc151355 
62250ba2cbe9Sxc151355 static void
62268d5c46e6Sam223141 do_delete_secobj(int argc, char **argv, const char *use)
62270ba2cbe9Sxc151355 {
62280ba2cbe9Sxc151355 	int		i, option;
62290ba2cbe9Sxc151355 	boolean_t	temp = B_FALSE;
62300ba2cbe9Sxc151355 	split_t		*sp = NULL;
62310ba2cbe9Sxc151355 	boolean_t	success;
62320ba2cbe9Sxc151355 	dladm_status_t	status, pstatus;
62330ba2cbe9Sxc151355 
62340ba2cbe9Sxc151355 	opterr = 0;
62350ba2cbe9Sxc151355 	status = pstatus = DLADM_STATUS_OK;
623633343a97Smeem 	while ((option = getopt_long(argc, argv, ":R:t",
62370ba2cbe9Sxc151355 	    wifi_longopts, NULL)) != -1) {
62380ba2cbe9Sxc151355 		switch (option) {
62390ba2cbe9Sxc151355 		case 't':
62400ba2cbe9Sxc151355 			temp = B_TRUE;
62410ba2cbe9Sxc151355 			break;
62420ba2cbe9Sxc151355 		case 'R':
62430ba2cbe9Sxc151355 			status = dladm_set_rootdir(optarg);
62440ba2cbe9Sxc151355 			if (status != DLADM_STATUS_OK) {
624533343a97Smeem 				die_dlerr(status, "invalid directory "
624633343a97Smeem 				    "specified");
62470ba2cbe9Sxc151355 			}
62480ba2cbe9Sxc151355 			break;
62490ba2cbe9Sxc151355 		default:
62508d5c46e6Sam223141 			die_opterr(optopt, option, use);
62510ba2cbe9Sxc151355 			break;
62520ba2cbe9Sxc151355 		}
62530ba2cbe9Sxc151355 	}
62540ba2cbe9Sxc151355 
62550ba2cbe9Sxc151355 	if (optind == (argc - 1)) {
62560ba2cbe9Sxc151355 		sp = split(argv[optind], MAX_SECOBJS, MAX_SECOBJ_NAMELEN);
62570ba2cbe9Sxc151355 		if (sp == NULL) {
625833343a97Smeem 			die("invalid secure object name(s): '%s'",
625933343a97Smeem 			    argv[optind]);
62600ba2cbe9Sxc151355 		}
62610ba2cbe9Sxc151355 	} else if (optind != argc)
62620ba2cbe9Sxc151355 		usage();
62630ba2cbe9Sxc151355 
626433343a97Smeem 	if (sp == NULL || sp->s_nfields < 1)
626533343a97Smeem 		die("secure object name required");
62660ba2cbe9Sxc151355 
62670ba2cbe9Sxc151355 	success = check_auth(LINK_SEC_AUTH);
6268a399b765Szf162725 	audit_secobj(LINK_SEC_AUTH, "unknown", argv[optind], success, B_FALSE);
626933343a97Smeem 	if (!success)
627033343a97Smeem 		die("authorization '%s' is required", LINK_SEC_AUTH);
62710ba2cbe9Sxc151355 
62720ba2cbe9Sxc151355 	for (i = 0; i < sp->s_nfields; i++) {
6273d62bc4baSyz147064 		status = dladm_unset_secobj(sp->s_fields[i], DLADM_OPT_ACTIVE);
62740ba2cbe9Sxc151355 		if (!temp) {
62750ba2cbe9Sxc151355 			pstatus = dladm_unset_secobj(sp->s_fields[i],
62760ba2cbe9Sxc151355 			    DLADM_OPT_PERSIST);
62770ba2cbe9Sxc151355 		} else {
62780ba2cbe9Sxc151355 			pstatus = DLADM_STATUS_OK;
62790ba2cbe9Sxc151355 		}
62800ba2cbe9Sxc151355 
62810ba2cbe9Sxc151355 		if (status != DLADM_STATUS_OK) {
628233343a97Smeem 			warn_dlerr(status, "could not delete secure object "
628333343a97Smeem 			    "'%s'", sp->s_fields[i]);
62840ba2cbe9Sxc151355 		}
62850ba2cbe9Sxc151355 		if (pstatus != DLADM_STATUS_OK) {
628633343a97Smeem 			warn_dlerr(pstatus, "could not persistently delete "
628733343a97Smeem 			    "secure object '%s'", sp->s_fields[i]);
62880ba2cbe9Sxc151355 		}
62890ba2cbe9Sxc151355 	}
62900ba2cbe9Sxc151355 	if (status != DLADM_STATUS_OK || pstatus != DLADM_STATUS_OK)
62910ba2cbe9Sxc151355 		exit(1);
62920ba2cbe9Sxc151355 }
62930ba2cbe9Sxc151355 
62940ba2cbe9Sxc151355 typedef struct show_secobj_state {
62950ba2cbe9Sxc151355 	boolean_t	ss_persist;
62960ba2cbe9Sxc151355 	boolean_t	ss_parseable;
62970ba2cbe9Sxc151355 	boolean_t	ss_header;
6298e7801d59Ssowmini 	print_state_t	ss_print;
62990ba2cbe9Sxc151355 } show_secobj_state_t;
63000ba2cbe9Sxc151355 
63010ba2cbe9Sxc151355 
63020ba2cbe9Sxc151355 static boolean_t
63030ba2cbe9Sxc151355 show_secobj(void *arg, const char *obj_name)
63040ba2cbe9Sxc151355 {
63050ba2cbe9Sxc151355 	uint_t			obj_len = DLADM_SECOBJ_VAL_MAX;
63060ba2cbe9Sxc151355 	uint8_t			obj_val[DLADM_SECOBJ_VAL_MAX];
63070ba2cbe9Sxc151355 	char			buf[DLADM_STRSIZE];
63080ba2cbe9Sxc151355 	uint_t			flags = 0;
63090ba2cbe9Sxc151355 	dladm_secobj_class_t	class;
63100ba2cbe9Sxc151355 	show_secobj_state_t	*statep = arg;
63110ba2cbe9Sxc151355 	dladm_status_t		status;
6312e7801d59Ssowmini 	secobj_fields_buf_t	sbuf;
63130ba2cbe9Sxc151355 
63145f5c9f54SAnurag S. Maskey 	bzero(&sbuf, sizeof (secobj_fields_buf_t));
63150ba2cbe9Sxc151355 	if (statep->ss_persist)
63160ba2cbe9Sxc151355 		flags |= DLADM_OPT_PERSIST;
63170ba2cbe9Sxc151355 
63180ba2cbe9Sxc151355 	status = dladm_get_secobj(obj_name, &class, obj_val, &obj_len, flags);
631933343a97Smeem 	if (status != DLADM_STATUS_OK)
632033343a97Smeem 		die_dlerr(status, "cannot get secure object '%s'", obj_name);
63210ba2cbe9Sxc151355 
63220ba2cbe9Sxc151355 	if (statep->ss_header) {
63230ba2cbe9Sxc151355 		statep->ss_header = B_FALSE;
63240ba2cbe9Sxc151355 		if (!statep->ss_parseable)
6325e7801d59Ssowmini 			print_header(&statep->ss_print);
63260ba2cbe9Sxc151355 	}
63270ba2cbe9Sxc151355 
6328e7801d59Ssowmini 	(void) snprintf(sbuf.ss_obj_name, sizeof (sbuf.ss_obj_name),
6329e7801d59Ssowmini 	    obj_name);
6330e7801d59Ssowmini 	(void) dladm_secobjclass2str(class, buf);
6331e7801d59Ssowmini 	(void) snprintf(sbuf.ss_class, sizeof (sbuf.ss_class), "%s", buf);
6332e7801d59Ssowmini 	if (getuid() == 0) {
63330ba2cbe9Sxc151355 		char	val[DLADM_SECOBJ_VAL_MAX * 2];
63340ba2cbe9Sxc151355 		uint_t	len = sizeof (val);
63350ba2cbe9Sxc151355 
6336e7801d59Ssowmini 		if (octet_to_hexascii(obj_val, obj_len, val, &len) == 0)
6337e7801d59Ssowmini 			(void) snprintf(sbuf.ss_val,
6338e7801d59Ssowmini 			    sizeof (sbuf.ss_val), "%s", val);
63390ba2cbe9Sxc151355 	}
6340e7801d59Ssowmini 	dladm_print_output(&statep->ss_print, statep->ss_parseable,
6341e7801d59Ssowmini 	    dladm_print_field, (void *)&sbuf);
63420ba2cbe9Sxc151355 	return (B_TRUE);
63430ba2cbe9Sxc151355 }
63440ba2cbe9Sxc151355 
63450ba2cbe9Sxc151355 static void
63468d5c46e6Sam223141 do_show_secobj(int argc, char **argv, const char *use)
63470ba2cbe9Sxc151355 {
63480ba2cbe9Sxc151355 	int			option;
63490ba2cbe9Sxc151355 	show_secobj_state_t	state;
63500ba2cbe9Sxc151355 	dladm_status_t		status;
63510d365605Sschuster 	boolean_t		o_arg = B_FALSE;
63520ba2cbe9Sxc151355 	uint_t			i;
63530ba2cbe9Sxc151355 	split_t			*sp;
63540ba2cbe9Sxc151355 	uint_t			flags;
6355e7801d59Ssowmini 	char			*fields_str = NULL;
6356e7801d59Ssowmini 	print_field_t		**fields;
6357e7801d59Ssowmini 	uint_t			nfields;
6358e7801d59Ssowmini 	char			*def_fields = "object,class";
6359e7801d59Ssowmini 	char			*all_fields = "object,class,value";
63600ba2cbe9Sxc151355 
63610ba2cbe9Sxc151355 	opterr = 0;
6362e7801d59Ssowmini 	bzero(&state, sizeof (state));
6363e7801d59Ssowmini 	state.ss_parseable = B_FALSE;
6364e7801d59Ssowmini 	fields_str = def_fields;
63650ba2cbe9Sxc151355 	state.ss_persist = B_FALSE;
63660ba2cbe9Sxc151355 	state.ss_parseable = B_FALSE;
63670ba2cbe9Sxc151355 	state.ss_header = B_TRUE;
6368e7801d59Ssowmini 	while ((option = getopt_long(argc, argv, ":pPo:",
63690ba2cbe9Sxc151355 	    wifi_longopts, NULL)) != -1) {
63700ba2cbe9Sxc151355 		switch (option) {
63710ba2cbe9Sxc151355 		case 'p':
63720ba2cbe9Sxc151355 			state.ss_parseable = B_TRUE;
63730ba2cbe9Sxc151355 			break;
63740ba2cbe9Sxc151355 		case 'P':
63750ba2cbe9Sxc151355 			state.ss_persist = B_TRUE;
63760ba2cbe9Sxc151355 			break;
6377e7801d59Ssowmini 		case 'o':
63780d365605Sschuster 			o_arg = B_TRUE;
6379e7801d59Ssowmini 			if (strcasecmp(optarg, "all") == 0)
6380e7801d59Ssowmini 				fields_str = all_fields;
6381e7801d59Ssowmini 			else
6382e7801d59Ssowmini 				fields_str = optarg;
63830ba2cbe9Sxc151355 			break;
63840ba2cbe9Sxc151355 		default:
63858d5c46e6Sam223141 			die_opterr(optopt, option, use);
63860ba2cbe9Sxc151355 			break;
63870ba2cbe9Sxc151355 		}
63880ba2cbe9Sxc151355 	}
63890ba2cbe9Sxc151355 
63900d365605Sschuster 	if (state.ss_parseable && !o_arg)
63910d365605Sschuster 		die("option -c requires -o");
63920d365605Sschuster 
63930d365605Sschuster 	if (state.ss_parseable && fields_str == all_fields)
63940d365605Sschuster 		die("\"-o all\" is invalid with -p");
63950d365605Sschuster 
6396e7801d59Ssowmini 	fields = parse_output_fields(fields_str, secobj_fields,
6397e7801d59Ssowmini 	    DEV_SOBJ_FIELDS, CMD_TYPE_ANY, &nfields);
6398e7801d59Ssowmini 
6399e7801d59Ssowmini 	if (fields == NULL) {
6400e7801d59Ssowmini 		die("invalid field(s) specified");
6401e7801d59Ssowmini 		return;
6402e7801d59Ssowmini 	}
6403e7801d59Ssowmini 	state.ss_print.ps_fields = fields;
6404e7801d59Ssowmini 	state.ss_print.ps_nfields = nfields;
6405e7801d59Ssowmini 
6406e7801d59Ssowmini 	flags = state.ss_persist ? DLADM_OPT_PERSIST : 0;
64070ba2cbe9Sxc151355 	if (optind == (argc - 1)) {
64080ba2cbe9Sxc151355 		sp = split(argv[optind], MAX_SECOBJS, MAX_SECOBJ_NAMELEN);
64090ba2cbe9Sxc151355 		if (sp == NULL) {
641033343a97Smeem 			die("invalid secure object name(s): '%s'",
641133343a97Smeem 			    argv[optind]);
64120ba2cbe9Sxc151355 		}
64130ba2cbe9Sxc151355 		for (i = 0; i < sp->s_nfields; i++) {
64140ba2cbe9Sxc151355 			if (!show_secobj(&state, sp->s_fields[i]))
64150ba2cbe9Sxc151355 				break;
64160ba2cbe9Sxc151355 		}
64170ba2cbe9Sxc151355 		splitfree(sp);
64180ba2cbe9Sxc151355 		return;
64190ba2cbe9Sxc151355 	} else if (optind != argc)
64200ba2cbe9Sxc151355 		usage();
64210ba2cbe9Sxc151355 
64220ba2cbe9Sxc151355 	status = dladm_walk_secobj(&state, show_secobj, flags);
642333343a97Smeem 	if (status != DLADM_STATUS_OK)
642433343a97Smeem 		die_dlerr(status, "show-secobj");
64250ba2cbe9Sxc151355 }
64260ba2cbe9Sxc151355 
64270ba2cbe9Sxc151355 /*ARGSUSED*/
6428d62bc4baSyz147064 static int
6429d62bc4baSyz147064 i_dladm_init_linkprop(datalink_id_t linkid, void *arg)
6430d62bc4baSyz147064 {
643130890389Sartem 	(void) dladm_init_linkprop(linkid, B_TRUE);
6432d62bc4baSyz147064 	return (DLADM_WALK_CONTINUE);
6433d62bc4baSyz147064 }
6434d62bc4baSyz147064 
64358d5c46e6Sam223141 /*ARGSUSED*/
6436*da14cebeSEric Cheng void
64378d5c46e6Sam223141 do_init_linkprop(int argc, char **argv, const char *use)
64380ba2cbe9Sxc151355 {
643930890389Sartem 	int			option;
644030890389Sartem 	dladm_status_t		status;
644130890389Sartem 	datalink_id_t		linkid = DATALINK_ALL_LINKID;
644230890389Sartem 	datalink_media_t	media = DATALINK_ANY_MEDIATYPE;
644330890389Sartem 	uint_t			any_media = B_TRUE;
644430890389Sartem 
644530890389Sartem 	opterr = 0;
644630890389Sartem 	while ((option = getopt(argc, argv, ":w")) != -1) {
644730890389Sartem 		switch (option) {
644830890389Sartem 		case 'w':
644930890389Sartem 			media = DL_WIFI;
645030890389Sartem 			any_media = B_FALSE;
645130890389Sartem 			break;
645230890389Sartem 		default:
64538d5c46e6Sam223141 			/*
64548d5c46e6Sam223141 			 * Because init-linkprop is not a public command,
64558d5c46e6Sam223141 			 * print the usage instead.
64568d5c46e6Sam223141 			 */
64578d5c46e6Sam223141 			usage();
645830890389Sartem 			break;
645930890389Sartem 		}
646030890389Sartem 	}
646130890389Sartem 
646230890389Sartem 	if (optind == (argc - 1)) {
646330890389Sartem 		if ((status = dladm_name2info(argv[optind], &linkid, NULL, NULL,
646430890389Sartem 		    NULL)) != DLADM_STATUS_OK)
646530890389Sartem 			die_dlerr(status, "link %s is not valid", argv[optind]);
646630890389Sartem 	} else if (optind != argc) {
646730890389Sartem 		usage();
646830890389Sartem 	}
646930890389Sartem 
647030890389Sartem 	if (linkid == DATALINK_ALL_LINKID) {
6471d62bc4baSyz147064 		/*
647230890389Sartem 		 * linkprops of links of other classes have been initialized as
6473d62bc4baSyz147064 		 * part of the dladm up-xxx operation.
6474d62bc4baSyz147064 		 */
6475d62bc4baSyz147064 		(void) dladm_walk_datalink_id(i_dladm_init_linkprop, NULL,
647630890389Sartem 		    DATALINK_CLASS_PHYS, media, DLADM_OPT_PERSIST);
647730890389Sartem 	} else {
647830890389Sartem 		(void) dladm_init_linkprop(linkid, any_media);
647930890389Sartem 	}
64800ba2cbe9Sxc151355 }
64810ba2cbe9Sxc151355 
64820ba2cbe9Sxc151355 /* ARGSUSED */
64830ba2cbe9Sxc151355 static void
64848d5c46e6Sam223141 do_show_ether(int argc, char **argv, const char *use)
6485e7801d59Ssowmini {
6486e7801d59Ssowmini 	int 			option;
6487e7801d59Ssowmini 	datalink_id_t		linkid;
6488e7801d59Ssowmini 	print_ether_state_t 	state;
6489e7801d59Ssowmini 	print_field_t 		**fields;
64900d365605Sschuster 	boolean_t		o_arg = B_FALSE;
6491e7801d59Ssowmini 	char			*fields_str;
6492e7801d59Ssowmini 	uint_t			nfields;
6493e7801d59Ssowmini 	char			*all_fields =
6494e7801d59Ssowmini 	    "link,ptype,state,auto,speed-duplex,pause,rem_fault";
6495e7801d59Ssowmini 	char			*default_fields =
6496e7801d59Ssowmini 	    "link,ptype,state,auto,speed-duplex,pause";
6497e7801d59Ssowmini 
6498e7801d59Ssowmini 	fields_str = default_fields;
6499e7801d59Ssowmini 	bzero(&state, sizeof (state));
6500e7801d59Ssowmini 	state.es_link = NULL;
6501e7801d59Ssowmini 	state.es_parseable = B_FALSE;
6502e7801d59Ssowmini 
6503e7801d59Ssowmini 	while ((option = getopt_long(argc, argv, "o:px",
6504e7801d59Ssowmini 	    showeth_lopts, NULL)) != -1) {
6505e7801d59Ssowmini 		switch (option) {
6506e7801d59Ssowmini 			case 'x':
6507e7801d59Ssowmini 				state.es_extended = B_TRUE;
6508e7801d59Ssowmini 				break;
6509e7801d59Ssowmini 			case 'p':
6510e7801d59Ssowmini 				state.es_parseable = B_TRUE;
6511e7801d59Ssowmini 				break;
6512e7801d59Ssowmini 			case 'o':
65130d365605Sschuster 				o_arg = B_TRUE;
6514e7801d59Ssowmini 				if (strcasecmp(optarg, "all") == 0)
6515e7801d59Ssowmini 					fields_str = all_fields;
6516e7801d59Ssowmini 				else
6517e7801d59Ssowmini 					fields_str = optarg;
6518e7801d59Ssowmini 				break;
6519e7801d59Ssowmini 			default:
65208d5c46e6Sam223141 				die_opterr(optopt, option, use);
6521e7801d59Ssowmini 				break;
6522e7801d59Ssowmini 		}
6523e7801d59Ssowmini 	}
6524e7801d59Ssowmini 
65250d365605Sschuster 	if (state.es_parseable && !o_arg)
65260d365605Sschuster 		die("-p requires -o");
65270d365605Sschuster 
65280d365605Sschuster 	if (state.es_parseable && fields_str == all_fields)
65290d365605Sschuster 		die("\"-o all\" is invalid with -p");
65300d365605Sschuster 
6531e7801d59Ssowmini 	if (optind == (argc - 1))
6532e7801d59Ssowmini 		state.es_link = argv[optind];
6533e7801d59Ssowmini 
6534e7801d59Ssowmini 	fields = parse_output_fields(fields_str, ether_fields,
6535e7801d59Ssowmini 	    ETHER_MAX_FIELDS, CMD_TYPE_ANY, &nfields);
6536e7801d59Ssowmini 
6537e7801d59Ssowmini 	if (fields == NULL) {
6538e7801d59Ssowmini 		die("invalid field(s) specified");
6539e7801d59Ssowmini 		exit(EXIT_FAILURE);
6540e7801d59Ssowmini 	}
6541e7801d59Ssowmini 	state.es_print.ps_fields = fields;
6542e7801d59Ssowmini 	state.es_print.ps_nfields = nfields;
6543e7801d59Ssowmini 
6544e7801d59Ssowmini 	if (state.es_link == NULL) {
6545e7801d59Ssowmini 		(void) dladm_walk_datalink_id(show_etherprop, &state,
6546e7801d59Ssowmini 		    DATALINK_CLASS_PHYS, DL_ETHER,
6547e7801d59Ssowmini 		    DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST);
6548e7801d59Ssowmini 	} else {
6549e7801d59Ssowmini 		if (!link_is_ether(state.es_link, &linkid)) {
6550e7801d59Ssowmini 			die("invalid link specified");
6551e7801d59Ssowmini 		}
6552e7801d59Ssowmini 		(void) show_etherprop(linkid, &state);
6553e7801d59Ssowmini 	}
6554e7801d59Ssowmini 
6555e7801d59Ssowmini 	exit(DLADM_STATUS_OK);
6556e7801d59Ssowmini 
6557e7801d59Ssowmini }
6558e7801d59Ssowmini 
6559e7801d59Ssowmini static char *
6560e7801d59Ssowmini dladm_print_field(print_field_t *pf, void *arg)
6561e7801d59Ssowmini {
6562e7801d59Ssowmini 	char *value;
6563e7801d59Ssowmini 
6564e7801d59Ssowmini 	value = (char *)arg + pf->pf_offset;
6565e7801d59Ssowmini 	return (value);
6566e7801d59Ssowmini }
6567e7801d59Ssowmini 
6568e7801d59Ssowmini static int
6569e7801d59Ssowmini show_etherprop(datalink_id_t linkid, void *arg)
6570e7801d59Ssowmini {
6571e7801d59Ssowmini 	print_ether_state_t	*statep = arg;
6572e7801d59Ssowmini 	char			buf[DLADM_STRSIZE];
6573e7801d59Ssowmini 	int			speed;
6574e7801d59Ssowmini 	uint64_t		s;
6575e7801d59Ssowmini 	uint32_t		autoneg, pause, asmpause, adv_rf, cap_rf, lp_rf;
6576e7801d59Ssowmini 	ether_fields_buf_t	ebuf;
6577e7801d59Ssowmini 	char			speed_unit = 'M';
6578e7801d59Ssowmini 
65795f5c9f54SAnurag S. Maskey 	bzero(&ebuf, sizeof (ether_fields_buf_t));
6580e7801d59Ssowmini 	if (dladm_datalink_id2info(linkid, NULL, NULL, NULL,
6581e7801d59Ssowmini 	    ebuf.eth_link, sizeof (ebuf.eth_link)) != DLADM_STATUS_OK) {
6582e7801d59Ssowmini 		return (DLADM_WALK_CONTINUE);
6583e7801d59Ssowmini 	}
6584e7801d59Ssowmini 
6585e7801d59Ssowmini 	if (!statep->es_header && !statep->es_parseable) {
6586e7801d59Ssowmini 		print_header(&statep->es_print);
6587e7801d59Ssowmini 		statep->es_header = B_TRUE;
6588e7801d59Ssowmini 	}
6589e7801d59Ssowmini 	(void) snprintf(ebuf.eth_ptype, sizeof (ebuf.eth_ptype),
6590e7801d59Ssowmini 	    "%s", "current");
6591e7801d59Ssowmini 
6592e7801d59Ssowmini 	(void) dladm_get_single_mac_stat(linkid, "link_autoneg",
6593e7801d59Ssowmini 	    KSTAT_DATA_UINT32, &autoneg);
6594e7801d59Ssowmini 	(void) snprintf(ebuf.eth_autoneg, sizeof (ebuf.eth_autoneg),
6595e7801d59Ssowmini 	    "%s", (autoneg ? "yes" : "no"));
6596e7801d59Ssowmini 
6597e7801d59Ssowmini 	(void) dladm_get_single_mac_stat(linkid, "link_pause",
6598e7801d59Ssowmini 	    KSTAT_DATA_UINT32, &pause);
6599e7801d59Ssowmini 	(void) dladm_get_single_mac_stat(linkid, "link_asmpause",
6600e7801d59Ssowmini 	    KSTAT_DATA_UINT32, &asmpause);
6601e7801d59Ssowmini 	(void) snprintf(ebuf.eth_pause, sizeof (ebuf.eth_pause),
6602e7801d59Ssowmini 	    "%s", pause_str(pause, asmpause));
6603e7801d59Ssowmini 
6604e7801d59Ssowmini 	(void) dladm_get_single_mac_stat(linkid, "ifspeed",
6605e7801d59Ssowmini 	    KSTAT_DATA_UINT64, &s);
6606e7801d59Ssowmini 	speed = (int)(s/1000000ull);
6607e7801d59Ssowmini 
6608e7801d59Ssowmini 	if (speed >= 1000) {
6609e7801d59Ssowmini 		speed = speed/1000;
6610e7801d59Ssowmini 		speed_unit = 'G';
6611e7801d59Ssowmini 	}
66124045d941Ssowmini 	(void) get_linkduplex(ebuf.eth_link, B_TRUE, buf);
6613e7801d59Ssowmini 	(void) snprintf(ebuf.eth_spdx, sizeof (ebuf.eth_spdx), "%d%c-%c",
6614e7801d59Ssowmini 	    speed, speed_unit, buf[0]);
6615e7801d59Ssowmini 
66164045d941Ssowmini 	(void) get_linkstate(ebuf.eth_link, B_TRUE, buf);
6617e7801d59Ssowmini 	(void) snprintf(ebuf.eth_state, sizeof (ebuf.eth_state),
6618e7801d59Ssowmini 	    "%s", buf);
6619e7801d59Ssowmini 
6620e7801d59Ssowmini 	(void) dladm_get_single_mac_stat(linkid, "adv_rem_fault",
6621e7801d59Ssowmini 	    KSTAT_DATA_UINT32, &adv_rf);
6622e7801d59Ssowmini 	(void) dladm_get_single_mac_stat(linkid, "cap_rem_fault",
6623e7801d59Ssowmini 	    KSTAT_DATA_UINT32, &cap_rf);
6624e7801d59Ssowmini 	(void) dladm_get_single_mac_stat(linkid, "lp_rem_fault",
6625e7801d59Ssowmini 	    KSTAT_DATA_UINT32, &lp_rf);
6626e7801d59Ssowmini 	(void) snprintf(ebuf.eth_rem_fault, sizeof (ebuf.eth_rem_fault),
6627e7801d59Ssowmini 	    "%s", (adv_rf == 0 && lp_rf == 0 ? "none" : "fault"));
6628e7801d59Ssowmini 
6629e7801d59Ssowmini 	dladm_print_output(&statep->es_print, statep->es_parseable,
6630e7801d59Ssowmini 	    dladm_print_field, &ebuf);
6631e7801d59Ssowmini 
6632e7801d59Ssowmini 	if (statep->es_extended)
6633e7801d59Ssowmini 		show_ether_xprop(linkid, arg);
6634e7801d59Ssowmini 
6635e7801d59Ssowmini 	return (DLADM_WALK_CONTINUE);
6636e7801d59Ssowmini }
6637e7801d59Ssowmini 
6638e7801d59Ssowmini /* ARGSUSED */
6639e7801d59Ssowmini static void
66408d5c46e6Sam223141 do_init_secobj(int argc, char **argv, const char *use)
66410ba2cbe9Sxc151355 {
66420ba2cbe9Sxc151355 	dladm_status_t status;
66430ba2cbe9Sxc151355 
66440ba2cbe9Sxc151355 	status = dladm_init_secobj();
664533343a97Smeem 	if (status != DLADM_STATUS_OK)
664633343a97Smeem 		die_dlerr(status, "secure object initialization failed");
664733343a97Smeem }
664833343a97Smeem 
6649d62bc4baSyz147064 /*
6650d62bc4baSyz147064  * "-R" option support. It is used for live upgrading. Append dladm commands
6651d62bc4baSyz147064  * to a upgrade script which will be run when the alternative root boots up:
6652d62bc4baSyz147064  *
6653b9e076dcSyz147064  * - If the /etc/dladm/datalink.conf file exists on the alternative root,
6654b9e076dcSyz147064  * append dladm commands to the <altroot>/var/svc/profile/upgrade_datalink
6655b9e076dcSyz147064  * script. This script will be run as part of the network/physical service.
6656b9e076dcSyz147064  * We cannot defer this to /var/svc/profile/upgrade because then the
6657b9e076dcSyz147064  * configuration will not be able to take effect before network/physical
6658b9e076dcSyz147064  * plumbs various interfaces.
6659d62bc4baSyz147064  *
6660b9e076dcSyz147064  * - If the /etc/dladm/datalink.conf file does not exist on the alternative
6661b9e076dcSyz147064  * root, append dladm commands to the <altroot>/var/svc/profile/upgrade script,
6662b9e076dcSyz147064  * which will be run in the manifest-import service.
6663d62bc4baSyz147064  *
6664d62bc4baSyz147064  * Note that the SMF team is considering to move the manifest-import service
6665d62bc4baSyz147064  * to be run at the very begining of boot. Once that is done, the need for
6666d62bc4baSyz147064  * the /var/svc/profile/upgrade_datalink script will not exist any more.
6667d62bc4baSyz147064  */
6668d62bc4baSyz147064 static void
6669d62bc4baSyz147064 altroot_cmd(char *altroot, int argc, char *argv[])
6670d62bc4baSyz147064 {
6671d62bc4baSyz147064 	char		path[MAXPATHLEN];
6672d62bc4baSyz147064 	struct stat	stbuf;
6673d62bc4baSyz147064 	FILE		*fp;
6674d62bc4baSyz147064 	int		i;
6675d62bc4baSyz147064 
6676d62bc4baSyz147064 	/*
6677b9e076dcSyz147064 	 * Check for the existence of the /etc/dladm/datalink.conf
6678b9e076dcSyz147064 	 * configuration file, and determine the name of script file.
6679d62bc4baSyz147064 	 */
6680b9e076dcSyz147064 	(void) snprintf(path, MAXPATHLEN, "/%s/etc/dladm/datalink.conf",
6681b9e076dcSyz147064 	    altroot);
6682d62bc4baSyz147064 	if (stat(path, &stbuf) < 0) {
6683d62bc4baSyz147064 		(void) snprintf(path, MAXPATHLEN, "/%s/%s", altroot,
6684d62bc4baSyz147064 		    SMF_UPGRADE_FILE);
6685d62bc4baSyz147064 	} else {
6686d62bc4baSyz147064 		(void) snprintf(path, MAXPATHLEN, "/%s/%s", altroot,
6687d62bc4baSyz147064 		    SMF_UPGRADEDATALINK_FILE);
6688d62bc4baSyz147064 	}
6689d62bc4baSyz147064 
6690d62bc4baSyz147064 	if ((fp = fopen(path, "a+")) == NULL)
6691d62bc4baSyz147064 		die("operation not supported on %s", altroot);
6692d62bc4baSyz147064 
6693d62bc4baSyz147064 	(void) fprintf(fp, "/sbin/dladm ");
6694d62bc4baSyz147064 	for (i = 0; i < argc; i++) {
6695d62bc4baSyz147064 		/*
6696d62bc4baSyz147064 		 * Directly write to the file if it is not the "-R <altroot>"
6697d62bc4baSyz147064 		 * option. In which case, skip it.
6698d62bc4baSyz147064 		 */
6699d62bc4baSyz147064 		if (strcmp(argv[i], "-R") != 0)
6700d62bc4baSyz147064 			(void) fprintf(fp, "%s ", argv[i]);
6701d62bc4baSyz147064 		else
6702d62bc4baSyz147064 			i ++;
6703d62bc4baSyz147064 	}
6704d62bc4baSyz147064 	(void) fprintf(fp, "%s\n", SMF_DLADM_UPGRADE_MSG);
6705d62bc4baSyz147064 	(void) fclose(fp);
6706d62bc4baSyz147064 	exit(0);
6707d62bc4baSyz147064 }
6708d62bc4baSyz147064 
6709d62bc4baSyz147064 /*
6710d62bc4baSyz147064  * Convert the string to an integer. Note that the string must not have any
6711d62bc4baSyz147064  * trailing non-integer characters.
6712d62bc4baSyz147064  */
671333343a97Smeem static boolean_t
671433343a97Smeem str2int(const char *str, int *valp)
671533343a97Smeem {
671633343a97Smeem 	int	val;
671733343a97Smeem 	char	*endp = NULL;
671833343a97Smeem 
671933343a97Smeem 	errno = 0;
672033343a97Smeem 	val = strtol(str, &endp, 10);
672133343a97Smeem 	if (errno != 0 || *endp != '\0')
672233343a97Smeem 		return (B_FALSE);
672333343a97Smeem 
672433343a97Smeem 	*valp = val;
672533343a97Smeem 	return (B_TRUE);
672633343a97Smeem }
672733343a97Smeem 
672833343a97Smeem /* PRINTFLIKE1 */
672933343a97Smeem static void
673033343a97Smeem warn(const char *format, ...)
673133343a97Smeem {
673233343a97Smeem 	va_list alist;
673333343a97Smeem 
673433343a97Smeem 	format = gettext(format);
673533343a97Smeem 	(void) fprintf(stderr, "%s: warning: ", progname);
673633343a97Smeem 
673733343a97Smeem 	va_start(alist, format);
673833343a97Smeem 	(void) vfprintf(stderr, format, alist);
673933343a97Smeem 	va_end(alist);
674033343a97Smeem 
674133343a97Smeem 	(void) putchar('\n');
674233343a97Smeem }
674333343a97Smeem 
674433343a97Smeem /* PRINTFLIKE2 */
674533343a97Smeem static void
674633343a97Smeem warn_dlerr(dladm_status_t err, const char *format, ...)
674733343a97Smeem {
674833343a97Smeem 	va_list alist;
674933343a97Smeem 	char	errmsg[DLADM_STRSIZE];
675033343a97Smeem 
675133343a97Smeem 	format = gettext(format);
675233343a97Smeem 	(void) fprintf(stderr, gettext("%s: warning: "), progname);
675333343a97Smeem 
675433343a97Smeem 	va_start(alist, format);
675533343a97Smeem 	(void) vfprintf(stderr, format, alist);
675633343a97Smeem 	va_end(alist);
675733343a97Smeem 	(void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg));
675833343a97Smeem }
675933343a97Smeem 
676033343a97Smeem /* PRINTFLIKE2 */
676133343a97Smeem static void
676233343a97Smeem die_dlerr(dladm_status_t err, const char *format, ...)
676333343a97Smeem {
676433343a97Smeem 	va_list alist;
676533343a97Smeem 	char	errmsg[DLADM_STRSIZE];
676633343a97Smeem 
676733343a97Smeem 	format = gettext(format);
676833343a97Smeem 	(void) fprintf(stderr, "%s: ", progname);
676933343a97Smeem 
677033343a97Smeem 	va_start(alist, format);
677133343a97Smeem 	(void) vfprintf(stderr, format, alist);
677233343a97Smeem 	va_end(alist);
677333343a97Smeem 	(void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg));
677433343a97Smeem 
677533343a97Smeem 	exit(EXIT_FAILURE);
677633343a97Smeem }
677733343a97Smeem 
677833343a97Smeem /* PRINTFLIKE1 */
677933343a97Smeem static void
678033343a97Smeem die(const char *format, ...)
678133343a97Smeem {
678233343a97Smeem 	va_list alist;
678333343a97Smeem 
678433343a97Smeem 	format = gettext(format);
678533343a97Smeem 	(void) fprintf(stderr, "%s: ", progname);
678633343a97Smeem 
678733343a97Smeem 	va_start(alist, format);
678833343a97Smeem 	(void) vfprintf(stderr, format, alist);
678933343a97Smeem 	va_end(alist);
679033343a97Smeem 
679133343a97Smeem 	(void) putchar('\n');
679233343a97Smeem 	exit(EXIT_FAILURE);
679333343a97Smeem }
679433343a97Smeem 
679533343a97Smeem static void
679633343a97Smeem die_optdup(int opt)
679733343a97Smeem {
679833343a97Smeem 	die("the option -%c cannot be specified more than once", opt);
679933343a97Smeem }
680033343a97Smeem 
680133343a97Smeem static void
68028d5c46e6Sam223141 die_opterr(int opt, int opterr, const char *usage)
680333343a97Smeem {
680433343a97Smeem 	switch (opterr) {
680533343a97Smeem 	case ':':
68068d5c46e6Sam223141 		die("option '-%c' requires a value\nusage: %s", opt,
68078d5c46e6Sam223141 		    gettext(usage));
680833343a97Smeem 		break;
680933343a97Smeem 	case '?':
681033343a97Smeem 	default:
68118d5c46e6Sam223141 		die("unrecognized option '-%c'\nusage: %s", opt,
68128d5c46e6Sam223141 		    gettext(usage));
681333343a97Smeem 		break;
68140ba2cbe9Sxc151355 	}
68150ba2cbe9Sxc151355 }
6816e7801d59Ssowmini 
6817e7801d59Ssowmini static void
6818e7801d59Ssowmini show_ether_xprop(datalink_id_t linkid, void *arg)
6819e7801d59Ssowmini {
6820e7801d59Ssowmini 	print_ether_state_t	*statep = arg;
6821e7801d59Ssowmini 	char			buf[DLADM_STRSIZE];
6822e7801d59Ssowmini 	uint32_t		autoneg, pause, asmpause, adv_rf, cap_rf, lp_rf;
6823e7801d59Ssowmini 	boolean_t		add_comma, r1;
6824e7801d59Ssowmini 	ether_fields_buf_t	ebuf;
6825e7801d59Ssowmini 
6826e7801d59Ssowmini 	/* capable */
6827e7801d59Ssowmini 	bzero(&ebuf, sizeof (ebuf));
6828e7801d59Ssowmini 	(void) snprintf(ebuf.eth_link, sizeof (ebuf.eth_link), "");
6829e7801d59Ssowmini 
6830e7801d59Ssowmini 	(void) snprintf(ebuf.eth_ptype, sizeof (ebuf.eth_ptype),
6831e7801d59Ssowmini 	    "%s", "capable");
68320d365605Sschuster 	(void) snprintf(ebuf.eth_state, sizeof (ebuf.eth_state), "");
6833e7801d59Ssowmini 
6834e7801d59Ssowmini 	(void) dladm_get_single_mac_stat(linkid, "cap_autoneg",
6835e7801d59Ssowmini 	    KSTAT_DATA_UINT32, &autoneg);
6836e7801d59Ssowmini 	(void) snprintf(ebuf.eth_autoneg, sizeof (ebuf.eth_autoneg),
6837e7801d59Ssowmini 	    "%s", (autoneg ? "yes" : "no"));
6838e7801d59Ssowmini 
6839e7801d59Ssowmini 	add_comma = B_FALSE;
6840e7801d59Ssowmini 	bzero(buf, sizeof (buf));
6841e7801d59Ssowmini 	r1 = get_speed_duplex(linkid, "cap_1000", buf, "1G", B_FALSE);
6842e7801d59Ssowmini 	if (r1)
6843e7801d59Ssowmini 		add_comma = B_TRUE;
6844e7801d59Ssowmini 	r1 = get_speed_duplex(linkid, "cap_100", buf, "100M", add_comma);
6845e7801d59Ssowmini 	if (r1)
6846e7801d59Ssowmini 		add_comma = B_TRUE;
6847e7801d59Ssowmini 	r1 = get_speed_duplex(linkid, "cap_10", buf, "10M", add_comma);
6848e7801d59Ssowmini 	add_comma = B_FALSE;
6849e7801d59Ssowmini 	(void) snprintf(ebuf.eth_spdx, sizeof (ebuf.eth_spdx), "%s", buf);
6850e7801d59Ssowmini 
6851e7801d59Ssowmini 	(void) dladm_get_single_mac_stat(linkid, "cap_pause",
6852e7801d59Ssowmini 	    KSTAT_DATA_UINT32, &pause);
6853e7801d59Ssowmini 	(void) dladm_get_single_mac_stat(linkid, "cap_asmpause",
6854e7801d59Ssowmini 	    KSTAT_DATA_UINT32, &asmpause);
6855e7801d59Ssowmini 	(void) snprintf(ebuf.eth_pause, sizeof (ebuf.eth_pause),
6856e7801d59Ssowmini 	    "%s", pause_str(pause, asmpause));
6857e7801d59Ssowmini 
6858e7801d59Ssowmini 	(void) dladm_get_single_mac_stat(linkid, "adv_rem_fault",
6859e7801d59Ssowmini 	    KSTAT_DATA_UINT32, &adv_rf);
6860e7801d59Ssowmini 	(void) dladm_get_single_mac_stat(linkid, "cap_rem_fault",
6861e7801d59Ssowmini 	    KSTAT_DATA_UINT32, &cap_rf);
6862e7801d59Ssowmini 	(void) dladm_get_single_mac_stat(linkid, "lp_rem_fault",
6863e7801d59Ssowmini 	    KSTAT_DATA_UINT32, &lp_rf);
6864e7801d59Ssowmini 
6865e7801d59Ssowmini 	(void) snprintf(ebuf.eth_rem_fault, sizeof (ebuf.eth_rem_fault),
6866e7801d59Ssowmini 	    "%s", (cap_rf ? "yes" : "no"));
6867e7801d59Ssowmini 
6868e7801d59Ssowmini 	dladm_print_output(&statep->es_print, statep->es_parseable,
6869e7801d59Ssowmini 	    dladm_print_field, &ebuf);
6870e7801d59Ssowmini 
6871e7801d59Ssowmini 	/* advertised */
6872e7801d59Ssowmini 	bzero(&ebuf, sizeof (ebuf));
6873e7801d59Ssowmini 	(void) snprintf(ebuf.eth_ptype, sizeof (ebuf.eth_ptype),
6874e7801d59Ssowmini 	    "%s", "adv");
68750d365605Sschuster 	(void) snprintf(ebuf.eth_state, sizeof (ebuf.eth_state), "");
6876e7801d59Ssowmini 
6877e7801d59Ssowmini 	(void) dladm_get_single_mac_stat(linkid, "adv_cap_autoneg",
6878e7801d59Ssowmini 	    KSTAT_DATA_UINT32, &autoneg);
6879e7801d59Ssowmini 	(void) snprintf(ebuf.eth_autoneg, sizeof (ebuf.eth_autoneg),
6880e7801d59Ssowmini 	    "%s", (autoneg ? "yes" : "no"));
6881e7801d59Ssowmini 
6882e7801d59Ssowmini 	add_comma = B_FALSE;
6883e7801d59Ssowmini 	bzero(buf, sizeof (buf));
6884e7801d59Ssowmini 	r1 = get_speed_duplex(linkid, "adv_cap_1000", buf, "1G", add_comma);
6885e7801d59Ssowmini 	if (r1)
6886e7801d59Ssowmini 		add_comma = B_TRUE;
6887e7801d59Ssowmini 	r1 = get_speed_duplex(linkid, "adv_cap_100", buf, "100M", add_comma);
6888e7801d59Ssowmini 	if (r1)
6889e7801d59Ssowmini 		add_comma = B_TRUE;
6890e7801d59Ssowmini 	r1 = get_speed_duplex(linkid, "adv_cap_10", buf, "10M", add_comma);
6891e7801d59Ssowmini 	add_comma = B_FALSE;
6892e7801d59Ssowmini 	(void) snprintf(ebuf.eth_spdx, sizeof (ebuf.eth_spdx), "%s", buf);
6893e7801d59Ssowmini 
6894e7801d59Ssowmini 	(void) dladm_get_single_mac_stat(linkid, "adv_cap_pause",
6895e7801d59Ssowmini 	    KSTAT_DATA_UINT32, &pause);
6896e7801d59Ssowmini 	(void) dladm_get_single_mac_stat(linkid, "adv_cap_asmpause",
6897e7801d59Ssowmini 	    KSTAT_DATA_UINT32, &asmpause);
6898e7801d59Ssowmini 	(void) snprintf(ebuf.eth_pause, sizeof (ebuf.eth_pause),
6899e7801d59Ssowmini 	    "%s", pause_str(pause, asmpause));
6900e7801d59Ssowmini 
6901e7801d59Ssowmini 	(void) snprintf(ebuf.eth_rem_fault, sizeof (ebuf.eth_rem_fault),
6902e7801d59Ssowmini 	    "%s", (adv_rf ? "fault" : "none"));
6903e7801d59Ssowmini 
6904e7801d59Ssowmini 	dladm_print_output(&statep->es_print, statep->es_parseable,
6905e7801d59Ssowmini 	    dladm_print_field, &ebuf);
6906e7801d59Ssowmini 
6907e7801d59Ssowmini 	/* peeradv */
6908e7801d59Ssowmini 	bzero(&ebuf, sizeof (ebuf));
6909e7801d59Ssowmini 	(void) snprintf(ebuf.eth_ptype, sizeof (ebuf.eth_ptype),
6910e7801d59Ssowmini 	    "%s", "peeradv");
69110d365605Sschuster 	(void) snprintf(ebuf.eth_state, sizeof (ebuf.eth_state), "");
6912*da14cebeSEric Cheng 
6913e7801d59Ssowmini 	(void) dladm_get_single_mac_stat(linkid, "lp_cap_autoneg",
6914e7801d59Ssowmini 	    KSTAT_DATA_UINT32, &autoneg);
6915e7801d59Ssowmini 	(void) snprintf(ebuf.eth_autoneg, sizeof (ebuf.eth_autoneg),
6916e7801d59Ssowmini 	    "%s", (autoneg ? "yes" : "no"));
6917e7801d59Ssowmini 
6918e7801d59Ssowmini 	add_comma = B_FALSE;
6919e7801d59Ssowmini 	bzero(buf, sizeof (buf));
6920e7801d59Ssowmini 	r1 = get_speed_duplex(linkid, "lp_cap_1000", buf, "1G", add_comma);
6921e7801d59Ssowmini 	if (r1)
6922e7801d59Ssowmini 		add_comma = B_TRUE;
6923e7801d59Ssowmini 	r1 = get_speed_duplex(linkid, "lp_cap_100", buf, "100M", add_comma);
6924e7801d59Ssowmini 	if (r1)
6925e7801d59Ssowmini 		add_comma = B_TRUE;
6926e7801d59Ssowmini 	r1 = get_speed_duplex(linkid, "lp_cap_10", buf, "10M", add_comma);
6927e7801d59Ssowmini 	(void) snprintf(ebuf.eth_spdx, sizeof (ebuf.eth_spdx), "%s", buf);
6928e7801d59Ssowmini 
6929e7801d59Ssowmini 	(void) dladm_get_single_mac_stat(linkid, "lp_cap_pause",
6930e7801d59Ssowmini 	    KSTAT_DATA_UINT32, &pause);
6931e7801d59Ssowmini 	(void) dladm_get_single_mac_stat(linkid, "lp_cap_asmpause",
6932e7801d59Ssowmini 	    KSTAT_DATA_UINT32, &asmpause);
6933e7801d59Ssowmini 	(void) snprintf(ebuf.eth_pause, sizeof (ebuf.eth_pause),
6934e7801d59Ssowmini 	    "%s", pause_str(pause, asmpause));
6935e7801d59Ssowmini 
6936e7801d59Ssowmini 	(void) snprintf(ebuf.eth_rem_fault, sizeof (ebuf.eth_rem_fault),
6937e7801d59Ssowmini 	    "%s", (lp_rf ? "fault" : "none"));
6938e7801d59Ssowmini 
6939e7801d59Ssowmini 	dladm_print_output(&statep->es_print, statep->es_parseable,
6940e7801d59Ssowmini 	    dladm_print_field, &ebuf);
6941e7801d59Ssowmini }
6942e7801d59Ssowmini 
6943e7801d59Ssowmini static boolean_t
6944e7801d59Ssowmini get_speed_duplex(datalink_id_t linkid, const char *mii_prop_prefix,
6945e7801d59Ssowmini     char *spbuf, char *sp, boolean_t add_comma)
6946e7801d59Ssowmini {
6947e7801d59Ssowmini 	int speed, duplex = 0;
6948e7801d59Ssowmini 	boolean_t ret = B_FALSE;
6949e7801d59Ssowmini 	char mii_prop[DLADM_STRSIZE];
6950e7801d59Ssowmini 
6951e7801d59Ssowmini 	(void) snprintf(mii_prop, DLADM_STRSIZE, "%sfdx", mii_prop_prefix);
6952e7801d59Ssowmini 	(void) dladm_get_single_mac_stat(linkid, mii_prop, KSTAT_DATA_UINT32,
6953e7801d59Ssowmini 	    &speed);
6954e7801d59Ssowmini 	if (speed) {
6955e7801d59Ssowmini 		ret = B_TRUE;
6956e7801d59Ssowmini 		duplex  |= IS_FDX;
6957e7801d59Ssowmini 	}
6958e7801d59Ssowmini 	(void) snprintf(mii_prop, DLADM_STRSIZE, "%shdx", mii_prop_prefix);
6959e7801d59Ssowmini 	(void) dladm_get_single_mac_stat(linkid, mii_prop,
6960e7801d59Ssowmini 	    KSTAT_DATA_UINT32, &speed);
6961e7801d59Ssowmini 	if (speed) {
6962e7801d59Ssowmini 		ret = B_TRUE;
6963e7801d59Ssowmini 		duplex |= IS_HDX;
6964e7801d59Ssowmini 	}
6965e7801d59Ssowmini 	if (ret) {
6966e7801d59Ssowmini 		if (add_comma)
6967e7801d59Ssowmini 			(void) strncat(spbuf, ",", DLADM_STRSIZE);
6968e7801d59Ssowmini 		(void) strncat(spbuf, sp, DLADM_STRSIZE);
6969e7801d59Ssowmini 		if ((duplex & (IS_FDX|IS_HDX)) == (IS_FDX|IS_HDX))
6970e7801d59Ssowmini 			(void) strncat(spbuf, "-fh", DLADM_STRSIZE);
6971e7801d59Ssowmini 		else if (duplex & IS_FDX)
6972e7801d59Ssowmini 			(void) strncat(spbuf, "-f", DLADM_STRSIZE);
6973e7801d59Ssowmini 		else if (duplex & IS_HDX)
6974e7801d59Ssowmini 			(void) strncat(spbuf, "-h", DLADM_STRSIZE);
6975e7801d59Ssowmini 	}
6976e7801d59Ssowmini 	return (ret);
6977e7801d59Ssowmini }
6978e7801d59Ssowmini 
6979e7801d59Ssowmini static void
6980e7801d59Ssowmini dladm_print_output(print_state_t *statep, boolean_t parseable,
6981e7801d59Ssowmini     print_callback_t fn, void *arg)
6982e7801d59Ssowmini {
6983e7801d59Ssowmini 	int i;
6984e7801d59Ssowmini 	char *value;
6985e7801d59Ssowmini 	print_field_t **pf;
6986e7801d59Ssowmini 
6987e7801d59Ssowmini 	pf = statep->ps_fields;
6988e7801d59Ssowmini 	for (i = 0; i < statep->ps_nfields; i++) {
6989e7801d59Ssowmini 		statep->ps_lastfield = (i + 1 == statep->ps_nfields);
6990e7801d59Ssowmini 		value = (*fn)(pf[i], arg);
6991e7801d59Ssowmini 		if (value != NULL)
6992e7801d59Ssowmini 			print_field(statep, pf[i], value, parseable);
6993e7801d59Ssowmini 	}
6994e7801d59Ssowmini 	(void) putchar('\n');
6995e7801d59Ssowmini }
6996e7801d59Ssowmini 
6997e7801d59Ssowmini static void
6998e7801d59Ssowmini print_header(print_state_t *ps)
6999e7801d59Ssowmini {
7000e7801d59Ssowmini 	int i;
7001e7801d59Ssowmini 	print_field_t **pf;
7002e7801d59Ssowmini 
7003e7801d59Ssowmini 	pf = ps->ps_fields;
7004e7801d59Ssowmini 	for (i = 0; i < ps->ps_nfields; i++) {
7005e7801d59Ssowmini 		ps->ps_lastfield = (i + 1 == ps->ps_nfields);
7006e7801d59Ssowmini 		print_field(ps, pf[i], pf[i]->pf_header, B_FALSE);
7007e7801d59Ssowmini 	}
7008e7801d59Ssowmini 	(void) putchar('\n');
7009e7801d59Ssowmini }
7010e7801d59Ssowmini 
7011e7801d59Ssowmini static char *
7012e7801d59Ssowmini pause_str(int pause, int asmpause)
7013e7801d59Ssowmini {
7014e7801d59Ssowmini 	if (pause == 1)
7015e7801d59Ssowmini 		return ("bi");
7016e7801d59Ssowmini 	if (asmpause == 1)
7017e7801d59Ssowmini 		return ("tx");
7018e7801d59Ssowmini 	return ("none");
7019e7801d59Ssowmini }
7020e7801d59Ssowmini 
7021e7801d59Ssowmini static boolean_t
7022e7801d59Ssowmini link_is_ether(const char *link, datalink_id_t *linkid)
7023e7801d59Ssowmini {
7024e7801d59Ssowmini 	uint32_t media;
7025e7801d59Ssowmini 	datalink_class_t class;
7026e7801d59Ssowmini 
7027e7801d59Ssowmini 	if (dladm_name2info(link, linkid, NULL, &class, &media) ==
7028e7801d59Ssowmini 	    DLADM_STATUS_OK) {
7029e7801d59Ssowmini 		if (class == DATALINK_CLASS_PHYS && media == DL_ETHER)
7030e7801d59Ssowmini 			return (B_TRUE);
7031e7801d59Ssowmini 	}
7032e7801d59Ssowmini 	return (B_FALSE);
7033e7801d59Ssowmini }
7034