xref: /titanic_53/usr/src/cmd/dladm/dladm.c (revision 63a6526d84bd7ea2c75b4b0d009fa5f51a67a22a)
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 /*
22ad091ee1SMichael Lim  * Copyright 2009 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>
49da14cebeSEric Cheng #include <libdladm.h>
50f595a68aSyz147064 #include <libdllink.h>
51da14cebeSEric Cheng #include <libdlstat.h>
52f595a68aSyz147064 #include <libdlaggr.h>
53f595a68aSyz147064 #include <libdlwlan.h>
54d62bc4baSyz147064 #include <libdlvlan.h>
55d62bc4baSyz147064 #include <libdlvnic.h>
564784fcbdSSowmini Varadhan #include <libdlether.h>
570ba2cbe9Sxc151355 #include <libinetutil.h>
580ba2cbe9Sxc151355 #include <bsm/adt.h>
590ba2cbe9Sxc151355 #include <bsm/adt_event.h>
60da14cebeSEric Cheng #include <libdlvnic.h>
61da14cebeSEric Cheng #include <sys/types.h>
62da14cebeSEric Cheng #include <sys/socket.h>
63da14cebeSEric Cheng #include <sys/processor.h>
64da14cebeSEric Cheng #include <netinet/in.h>
65da14cebeSEric Cheng #include <arpa/inet.h>
66da14cebeSEric Cheng #include <net/if_types.h>
67e7801d59Ssowmini #include <stddef.h>
687c478bd9Sstevel@tonic-gate 
69e7801d59Ssowmini #define	STR_UNDEF_VAL		"--"
707c478bd9Sstevel@tonic-gate #define	MAXPORT			256
71da14cebeSEric Cheng #define	MAXVNIC			256
72d62bc4baSyz147064 #define	BUFLEN(lim, ptr)	(((lim) > (ptr)) ? ((lim) - (ptr)) : 0)
73d62bc4baSyz147064 #define	MAXLINELEN		1024
74d62bc4baSyz147064 #define	SMF_UPGRADE_FILE		"/var/svc/profile/upgrade"
75d62bc4baSyz147064 #define	SMF_UPGRADEDATALINK_FILE	"/var/svc/profile/upgrade_datalink"
76d62bc4baSyz147064 #define	SMF_DLADM_UPGRADE_MSG		" # added by dladm(1M)"
777c478bd9Sstevel@tonic-gate 
78e7801d59Ssowmini #define	CMD_TYPE_ANY		0xffffffff
79e7801d59Ssowmini #define	WIFI_CMD_SCAN		0x00000001
80e7801d59Ssowmini #define	WIFI_CMD_SHOW		0x00000002
81e7801d59Ssowmini #define	WIFI_CMD_ALL		(WIFI_CMD_SCAN | WIFI_CMD_SHOW)
82e7801d59Ssowmini 
83e7801d59Ssowmini /*
840d365605Sschuster  * Data structures and routines for printing output.
85e7801d59Ssowmini  * All non-parseable output is assumed to be in a columnar format.
860d365605Sschuster  * Multiple fields in parsable output are separated by ':'; single
870d365605Sschuster  * field output is printed as-is.
88e7801d59Ssowmini  *
89e7801d59Ssowmini  * Each sub-command is associated with a global array of pointers,
90e7801d59Ssowmini  * print_field_t *fields[], where the print_field_t contains information
91e7801d59Ssowmini  * about the format in which the output is to be printed.
92e7801d59Ssowmini  *
93e7801d59Ssowmini  * Sub-commands may be implemented in one of two ways:
94e7801d59Ssowmini  * (i)  the implementation could get all field values into a character
95e7801d59Ssowmini  *      buffer, with pf_offset containing the offset (for pf_name) within
96e7801d59Ssowmini  *      the buffer. The sub-command would make the needed system calls
97e7801d59Ssowmini  *      to obtain all possible column values and then invoke the
98e7801d59Ssowmini  *      dladm_print_field() function to print the specific fields
99e7801d59Ssowmini  *      requested in the command line. See the comments for dladm_print_field
100e7801d59Ssowmini  *      for further details.
101e7801d59Ssowmini  * (ii) Alternatively, each fields[i] entry could store a pf_index value
102e7801d59Ssowmini  *      that uniquely identifies the column to be printed. The implementation
103e7801d59Ssowmini  *      of the sub-command would then invoke dladm_print_output() with a
104e7801d59Ssowmini  *      callback function whose semantics are described below (see comments
105e7801d59Ssowmini  *      for dladm_print_output())
106e7801d59Ssowmini  *
107e7801d59Ssowmini  * Thus, an implementation of a sub-command must provide the following:
108e7801d59Ssowmini  *
109e7801d59Ssowmini  * static print_field_t sub_command_fields[] = {
110e7801d59Ssowmini  *	{<name>, <header>,<field width>,  <offset_or_index>, cmdtype},
111e7801d59Ssowmini  *	:
112e7801d59Ssowmini  *	{<name>, <header>,<field width>,  <offset_or_index>, cmdtype}
113e7801d59Ssowmini  * };
114e7801d59Ssowmini  *
115e7801d59Ssowmini  * #define	SUB_COMMAND_MAX_FIELDS sizeof \
116e7801d59Ssowmini  *		(sub_comand_fields) / sizeof (print_field_t))
117e7801d59Ssowmini  *
118e7801d59Ssowmini  * print_state_t sub_command_print_state;
119e7801d59Ssowmini  *
120e7801d59Ssowmini  * The function that parses command line arguments (typically
121e7801d59Ssowmini  * do_sub_command()) should then contain an invocation like:
122e7801d59Ssowmini  *
123e7801d59Ssowmini  *	fields = parse_output_fields(fields_str, sub_command_fields,
124e7801d59Ssowmini  *	    SUB_COMMAND_MAX_FIELDS, CMD_TYPE_ANY, &nfields);
125e7801d59Ssowmini  *
126e7801d59Ssowmini  * and store the resulting fields and nfields value in a print_state_t
127e7801d59Ssowmini  * structure tracked for the command.
128e7801d59Ssowmini  *
129e7801d59Ssowmini  *	sub_command_print_state.ps_fields = fields;
130e7801d59Ssowmini  *	sub_command_print_state.ps_nfields = nfields;
131e7801d59Ssowmini  *
132e7801d59Ssowmini  * To print the column header for the output, the print_header()
133e7801d59Ssowmini  * function must then be invoked by do_sub_command().
134e7801d59Ssowmini  *
135e7801d59Ssowmini  * Then if method (i) is used for the sub_command, the do_sub_command()
136e7801d59Ssowmini  * function should make the necessary system calls to fill up the buffer
137e7801d59Ssowmini  * and then invoke dladm_print_field(). An example of this method is
138e7801d59Ssowmini  * the implementation of do_show_link() and show_link();
139e7801d59Ssowmini  *
140e7801d59Ssowmini  * If method (ii) is used, do_sub_command should invoke dladm_print_output()
141e7801d59Ssowmini  * with a callback function that will be called for each field to be printed.
142e7801d59Ssowmini  * The callback function will be passed a pointer to the print_field_t
143e7801d59Ssowmini  * for the field, and the pf_index may then be used to identify the
144da14cebeSEric Cheng  * system call required to find the value to be printed.
145e7801d59Ssowmini  */
146e7801d59Ssowmini 
147e7801d59Ssowmini typedef struct print_field_s {
148e7801d59Ssowmini 	const char	*pf_name;	/* name of column to be printed */
149e7801d59Ssowmini 	const char	*pf_header;	/* header for this column */
150e7801d59Ssowmini 	uint_t		pf_width;
151e7801d59Ssowmini 	union {
152e7801d59Ssowmini 		uint_t	_pf_index;	/* private index for sub-command */
153e7801d59Ssowmini 		size_t	_pf_offset;
154e7801d59Ssowmini 	}_pf_un;
155e7801d59Ssowmini #define	pf_index	_pf_un._pf_index
156e7801d59Ssowmini #define	pf_offset	_pf_un._pf_offset;
157e7801d59Ssowmini 	uint_t		pf_cmdtype;
158e7801d59Ssowmini } print_field_t;
159e7801d59Ssowmini 
160e7801d59Ssowmini /*
161e7801d59Ssowmini  * The state of the output is tracked in a print_state_t structure.
162e7801d59Ssowmini  * Each ps_fields[i] entry points at the global print_field_t array for
163e7801d59Ssowmini  * the sub-command, where ps_nfields is the number of requested fields.
164e7801d59Ssowmini  */
165e7801d59Ssowmini typedef struct print_state_s {
166e7801d59Ssowmini 	print_field_t	**ps_fields;
167e7801d59Ssowmini 	uint_t		ps_nfields;
168e7801d59Ssowmini 	boolean_t	ps_lastfield;
169e7801d59Ssowmini 	uint_t		ps_overflow;
170e7801d59Ssowmini } print_state_t;
171e7801d59Ssowmini 
172e7801d59Ssowmini typedef char *(*print_callback_t)(print_field_t *, void *);
173e7801d59Ssowmini static print_field_t **parse_output_fields(char *, print_field_t *, int,
174e7801d59Ssowmini     uint_t, uint_t *);
175e7801d59Ssowmini /*
176e7801d59Ssowmini  * print the header for the output
177e7801d59Ssowmini  */
178e7801d59Ssowmini static void print_header(print_state_t *);
179e7801d59Ssowmini static void print_field(print_state_t *, print_field_t *, const char *,
180e7801d59Ssowmini     boolean_t);
181e7801d59Ssowmini 
182e7801d59Ssowmini /*
183e7801d59Ssowmini  * to print output values, call dladm_print_output with a callback
184e7801d59Ssowmini  * function (*func)() that should parse the args and return an
185e7801d59Ssowmini  * unformatted character buffer with the value to be printed.
186e7801d59Ssowmini  *
187e7801d59Ssowmini  * dladm_print_output() prints the character buffer using the formatting
188e7801d59Ssowmini  * information provided in the print_field_t for that column.
189e7801d59Ssowmini  */
190e7801d59Ssowmini static void dladm_print_output(print_state_t *, boolean_t,
191e7801d59Ssowmini     print_callback_t, void *);
192e7801d59Ssowmini 
193e7801d59Ssowmini /*
194e7801d59Ssowmini  * helper function that, when invoked as dladm_print_field(pf, buf)
1954ac67f02SAnurag S. Maskey  * prints string which is offset by pf->pf_offset within buf.
196e7801d59Ssowmini  */
197e7801d59Ssowmini static char *dladm_print_field(print_field_t *, void *);
198e7801d59Ssowmini 
199e7801d59Ssowmini 
200e7801d59Ssowmini #define	MAX_FIELD_LEN	32
201e7801d59Ssowmini 
202e7801d59Ssowmini 
203d62bc4baSyz147064 typedef struct show_state {
2047c478bd9Sstevel@tonic-gate 	boolean_t	ls_firstonly;
2057c478bd9Sstevel@tonic-gate 	boolean_t	ls_donefirst;
2067c478bd9Sstevel@tonic-gate 	pktsum_t	ls_prevstats;
207d62bc4baSyz147064 	uint32_t	ls_flags;
208d62bc4baSyz147064 	dladm_status_t	ls_status;
209e7801d59Ssowmini 	print_state_t	ls_print;
210e7801d59Ssowmini 	boolean_t	ls_parseable;
211e7801d59Ssowmini 	boolean_t	ls_printheader;
212da14cebeSEric Cheng 	boolean_t	ls_mac;
213da14cebeSEric Cheng 	boolean_t	ls_hwgrp;
214d62bc4baSyz147064 } show_state_t;
2157c478bd9Sstevel@tonic-gate 
2167c478bd9Sstevel@tonic-gate typedef struct show_grp_state {
217e7801d59Ssowmini 	pktsum_t	gs_prevstats[MAXPORT];
218e7801d59Ssowmini 	uint32_t	gs_flags;
219e7801d59Ssowmini 	dladm_status_t	gs_status;
220e7801d59Ssowmini 	boolean_t	gs_parseable;
2217c478bd9Sstevel@tonic-gate 	boolean_t	gs_lacp;
222d62bc4baSyz147064 	boolean_t	gs_extended;
2237c478bd9Sstevel@tonic-gate 	boolean_t	gs_stats;
2247c478bd9Sstevel@tonic-gate 	boolean_t	gs_firstonly;
225d62bc4baSyz147064 	boolean_t	gs_donefirst;
226e7801d59Ssowmini 	boolean_t	gs_printheader;
227e7801d59Ssowmini 	print_state_t	gs_print;
2287c478bd9Sstevel@tonic-gate } show_grp_state_t;
2297c478bd9Sstevel@tonic-gate 
230da14cebeSEric Cheng typedef struct show_vnic_state {
231da14cebeSEric Cheng 	datalink_id_t	vs_vnic_id;
232da14cebeSEric Cheng 	datalink_id_t	vs_link_id;
233da14cebeSEric Cheng 	char		vs_vnic[MAXLINKNAMELEN];
234da14cebeSEric Cheng 	char		vs_link[MAXLINKNAMELEN];
235da14cebeSEric Cheng 	boolean_t	vs_parseable;
236da14cebeSEric Cheng 	boolean_t	vs_printheader;
237da14cebeSEric Cheng 	boolean_t	vs_found;
238da14cebeSEric Cheng 	boolean_t	vs_firstonly;
239da14cebeSEric Cheng 	boolean_t	vs_donefirst;
240da14cebeSEric Cheng 	boolean_t	vs_stats;
241da14cebeSEric Cheng 	boolean_t	vs_printstats;
242da14cebeSEric Cheng 	pktsum_t	vs_totalstats;
243da14cebeSEric Cheng 	pktsum_t	vs_prevstats[MAXVNIC];
244da14cebeSEric Cheng 	boolean_t	vs_etherstub;
245da14cebeSEric Cheng 	dladm_status_t	vs_status;
246da14cebeSEric Cheng 	uint32_t	vs_flags;
247da14cebeSEric Cheng 	print_state_t	vs_print;
248da14cebeSEric Cheng } show_vnic_state_t;
249da14cebeSEric Cheng 
250da14cebeSEric Cheng typedef struct show_usage_state_s {
251da14cebeSEric Cheng 	boolean_t	us_plot;
252da14cebeSEric Cheng 	boolean_t	us_parseable;
253da14cebeSEric Cheng 	boolean_t	us_printheader;
254da14cebeSEric Cheng 	boolean_t	us_first;
255ae6aa22aSVenugopal Iyer 	boolean_t	us_showall;
256da14cebeSEric Cheng 	print_state_t	us_print;
257da14cebeSEric Cheng } show_usage_state_t;
258da14cebeSEric Cheng 
2598d5c46e6Sam223141 typedef void cmdfunc_t(int, char **, const char *);
2600ba2cbe9Sxc151355 
261da14cebeSEric Cheng static cmdfunc_t do_show_link, do_show_wifi, do_show_phys;
2620ba2cbe9Sxc151355 static cmdfunc_t do_create_aggr, do_delete_aggr, do_add_aggr, do_remove_aggr;
263d62bc4baSyz147064 static cmdfunc_t do_modify_aggr, do_show_aggr, do_up_aggr;
2640ba2cbe9Sxc151355 static cmdfunc_t do_scan_wifi, do_connect_wifi, do_disconnect_wifi;
2650ba2cbe9Sxc151355 static cmdfunc_t do_show_linkprop, do_set_linkprop, do_reset_linkprop;
2660ba2cbe9Sxc151355 static cmdfunc_t do_create_secobj, do_delete_secobj, do_show_secobj;
2670ba2cbe9Sxc151355 static cmdfunc_t do_init_linkprop, do_init_secobj;
268d62bc4baSyz147064 static cmdfunc_t do_create_vlan, do_delete_vlan, do_up_vlan, do_show_vlan;
269d62bc4baSyz147064 static cmdfunc_t do_rename_link, do_delete_phys, do_init_phys;
270d62bc4baSyz147064 static cmdfunc_t do_show_linkmap;
271e7801d59Ssowmini static cmdfunc_t do_show_ether;
272da14cebeSEric Cheng static cmdfunc_t do_create_vnic, do_delete_vnic, do_show_vnic;
273da14cebeSEric Cheng static cmdfunc_t do_up_vnic;
274da14cebeSEric Cheng static cmdfunc_t do_create_etherstub, do_delete_etherstub, do_show_etherstub;
275da14cebeSEric Cheng static cmdfunc_t do_show_usage;
276da14cebeSEric Cheng 
277da14cebeSEric Cheng static void 	do_up_vnic_common(int, char **, const char *, boolean_t);
2787c478bd9Sstevel@tonic-gate 
279d62bc4baSyz147064 static void	altroot_cmd(char *, int, char **);
2804ac67f02SAnurag S. Maskey static int	show_linkprop_onelink(dladm_handle_t, datalink_id_t, void *);
281f4b3ec61Sdh155122 
2826be03d0bSVasumathi Sundaram - Sun Microsystems static void	link_stats(datalink_id_t, uint_t, char *, show_state_t *);
283d62bc4baSyz147064 static void	aggr_stats(datalink_id_t, show_grp_state_t *, uint_t);
284da14cebeSEric Cheng static void	vnic_stats(show_vnic_state_t *, uint32_t);
2857c478bd9Sstevel@tonic-gate 
286d62bc4baSyz147064 static int	get_one_kstat(const char *, const char *, uint8_t,
287d62bc4baSyz147064 		    void *, boolean_t);
288ba2e4443Sseb static void	get_mac_stats(const char *, pktsum_t *);
2897c478bd9Sstevel@tonic-gate static void	get_link_stats(const char *, pktsum_t *);
290d62bc4baSyz147064 static uint64_t	get_ifspeed(const char *, boolean_t);
291d62bc4baSyz147064 static const char	*get_linkstate(const char *, boolean_t, char *);
292d62bc4baSyz147064 static const char	*get_linkduplex(const char *, boolean_t, char *);
2937c478bd9Sstevel@tonic-gate 
2944ac67f02SAnurag S. Maskey static int	show_etherprop(dladm_handle_t, datalink_id_t, void *);
2954784fcbdSSowmini Varadhan static void	show_ether_xprop(void *, dladm_ether_info_t *);
296e7801d59Ssowmini static boolean_t	link_is_ether(const char *, datalink_id_t *);
297e7801d59Ssowmini 
29833343a97Smeem static boolean_t str2int(const char *, int *);
29933343a97Smeem static void	die(const char *, ...);
30033343a97Smeem static void	die_optdup(int);
3018d5c46e6Sam223141 static void	die_opterr(int, int, const char *);
30233343a97Smeem static void	die_dlerr(dladm_status_t, const char *, ...);
30333343a97Smeem static void	warn(const char *, ...);
30433343a97Smeem static void	warn_dlerr(dladm_status_t, const char *, ...);
30533343a97Smeem 
3067c478bd9Sstevel@tonic-gate typedef struct	cmd {
3077c478bd9Sstevel@tonic-gate 	char		*c_name;
3080ba2cbe9Sxc151355 	cmdfunc_t	*c_fn;
3098d5c46e6Sam223141 	const char	*c_usage;
3107c478bd9Sstevel@tonic-gate } cmd_t;
3117c478bd9Sstevel@tonic-gate 
3127c478bd9Sstevel@tonic-gate static cmd_t	cmds[] = {
3138d5c46e6Sam223141 	{ "rename-link",	do_rename_link,
3140790b6dcSAnurag S. Maskey 	    "    rename-link      <oldlink> <newlink>"			},
3150790b6dcSAnurag S. Maskey 	{ "show-link",		do_show_link,
3160790b6dcSAnurag S. Maskey 	    "    show-link        [-pP] [-o <field>,..] [-s [-i <interval>]] "
3170790b6dcSAnurag S. Maskey 	    "[<link>]\n"						},
3188d5c46e6Sam223141 	{ "create-aggr",	do_create_aggr,
3190790b6dcSAnurag S. Maskey 	    "    create-aggr      [-t] [-P <policy>] [-L <mode>] [-T <time>] "
3200790b6dcSAnurag S. Maskey 	    "[-u <address>]\n"
3210790b6dcSAnurag S. Maskey 	    "\t\t     -l <link> [-l <link>...] <link>"			},
3228d5c46e6Sam223141 	{ "delete-aggr",	do_delete_aggr,
3230790b6dcSAnurag S. Maskey 	    "    delete-aggr      [-t] <link>"				},
3248d5c46e6Sam223141 	{ "add-aggr",		do_add_aggr,
3250790b6dcSAnurag S. Maskey 	    "    add-aggr         [-t] -l <link> [-l <link>...] <link>" },
3268d5c46e6Sam223141 	{ "remove-aggr",	do_remove_aggr,
3270790b6dcSAnurag S. Maskey 	    "    remove-aggr      [-t] -l <link> [-l <link>...] <link>" },
3288d5c46e6Sam223141 	{ "modify-aggr",	do_modify_aggr,
3290790b6dcSAnurag S. Maskey 	    "    modify-aggr      [-t] [-P <policy>] [-L <mode>] [-T <time>] "
3300790b6dcSAnurag S. Maskey 	    "[-u <address>]\n"
3310790b6dcSAnurag S. Maskey 	    "\t\t     <link>"						},
3328d5c46e6Sam223141 	{ "show-aggr",		do_show_aggr,
3330790b6dcSAnurag S. Maskey 	    "    show-aggr        [-pPLx] [-o <field>,..] [-s [-i <interval>]] "
3348d5c46e6Sam223141 	    "[<link>]\n"						},
3358d5c46e6Sam223141 	{ "up-aggr",		do_up_aggr,	NULL			},
3368d5c46e6Sam223141 	{ "scan-wifi",		do_scan_wifi,
3370790b6dcSAnurag S. Maskey 	    "    scan-wifi        [-p] [-o <field>,...] [<link>]"	},
3388d5c46e6Sam223141 	{ "connect-wifi",	do_connect_wifi,
3390790b6dcSAnurag S. Maskey 	    "    connect-wifi     [-e <essid>] [-i <bssid>] [-k <key>,...] "
3408d5c46e6Sam223141 	    "[-s wep|wpa]\n"
3410790b6dcSAnurag S. Maskey 	    "\t\t     [-a open|shared] [-b bss|ibss] [-c] [-m a|b|g] "
3420790b6dcSAnurag S. Maskey 	    "[-T <time>]\n"
3430790b6dcSAnurag S. Maskey 	    "\t\t     [<link>]"						},
3448d5c46e6Sam223141 	{ "disconnect-wifi",	do_disconnect_wifi,
3450790b6dcSAnurag S. Maskey 	    "    disconnect-wifi  [-a] [<link>]"			},
3468d5c46e6Sam223141 	{ "show-wifi",		do_show_wifi,
3470790b6dcSAnurag S. Maskey 	    "    show-wifi        [-p] [-o <field>,...] [<link>]\n"	},
3488d5c46e6Sam223141 	{ "set-linkprop",	do_set_linkprop,
3490790b6dcSAnurag S. Maskey 	    "    set-linkprop     [-t] -p <prop>=<value>[,...] <name>"	},
3508d5c46e6Sam223141 	{ "reset-linkprop",	do_reset_linkprop,
3510790b6dcSAnurag S. Maskey 	    "    reset-linkprop   [-t] [-p <prop>,...] <name>"		},
3520790b6dcSAnurag S. Maskey 	{ "show-linkprop",	do_show_linkprop,
3530790b6dcSAnurag S. Maskey 	    "    show-linkprop    [-cP] [-o <field>,...] [-p <prop>,...] "
3540790b6dcSAnurag S. Maskey 	    "<name>\n"							},
3558d5c46e6Sam223141 	{ "show-ether",		do_show_ether,
3560790b6dcSAnurag S. Maskey 	    "    show-ether       [-px][-o <field>,...] <link>\n"	},
3578d5c46e6Sam223141 	{ "create-secobj",	do_create_secobj,
3580790b6dcSAnurag S. Maskey 	    "    create-secobj    [-t] [-f <file>] -c <class> <secobj>"	},
3598d5c46e6Sam223141 	{ "delete-secobj",	do_delete_secobj,
3600790b6dcSAnurag S. Maskey 	    "    delete-secobj    [-t] <secobj>[,...]"			},
3618d5c46e6Sam223141 	{ "show-secobj",	do_show_secobj,
3620790b6dcSAnurag S. Maskey 	    "    show-secobj      [-pP] [-o <field>,...] [<secobj>,...]\n" },
3638d5c46e6Sam223141 	{ "init-linkprop",	do_init_linkprop,	NULL		},
3648d5c46e6Sam223141 	{ "init-secobj",	do_init_secobj,		NULL		},
3658d5c46e6Sam223141 	{ "create-vlan", 	do_create_vlan,
3660790b6dcSAnurag S. Maskey 	    "    create-vlan      [-ft] -l <link> -v <vid> [link]"	},
3678d5c46e6Sam223141 	{ "delete-vlan", 	do_delete_vlan,
3680790b6dcSAnurag S. Maskey 	    "    delete-vlan      [-t] <link>"				},
3698d5c46e6Sam223141 	{ "show-vlan",		do_show_vlan,
3700790b6dcSAnurag S. Maskey 	    "    show-vlan        [-pP] [-o <field>,..] [<link>]\n"	},
3718d5c46e6Sam223141 	{ "up-vlan",		do_up_vlan,		NULL		},
3728d5c46e6Sam223141 	{ "delete-phys",	do_delete_phys,
3730790b6dcSAnurag S. Maskey 	    "    delete-phys      <link>"				},
3748d5c46e6Sam223141 	{ "show-phys",		do_show_phys,
3750790b6dcSAnurag S. Maskey 	    "    show-phys        [-pP] [-o <field>,..] [-H] [<link>]\n"},
3768d5c46e6Sam223141 	{ "init-phys",		do_init_phys,		NULL		},
377da14cebeSEric Cheng 	{ "show-linkmap",	do_show_linkmap,	NULL		},
378da14cebeSEric Cheng 	{ "create-vnic",	do_create_vnic,
3790790b6dcSAnurag S. Maskey 	    "    create-vnic      [-t] -l <link> [-m <value> | auto |\n"
3800790b6dcSAnurag S. Maskey 	    "\t\t     {factory [-n <slot-id>]} | {random [-r <prefix>]}]\n"
3810790b6dcSAnurag S. Maskey 	    "\t\t     [-v <vid> [-f]] [-p <prop>=<value>[,...]] [-H] "
3820790b6dcSAnurag S. Maskey 	    "<vnic-link>"						},
383da14cebeSEric Cheng 	{ "delete-vnic",	do_delete_vnic,
3840790b6dcSAnurag S. Maskey 	    "    delete-vnic      [-t] <vnic-link>"			},
385da14cebeSEric Cheng 	{ "show-vnic",		do_show_vnic,
3860790b6dcSAnurag S. Maskey 	    "    show-vnic        [-pP] [-l <link>] [-s [-i <interval>]] "
3870790b6dcSAnurag S. Maskey 	    "[<link>]\n"						},
388da14cebeSEric Cheng 	{ "up-vnic",		do_up_vnic,		NULL		},
389da14cebeSEric Cheng 	{ "create-etherstub",	do_create_etherstub,
3900790b6dcSAnurag S. Maskey 	    "    create-etherstub [-t] <link>"				},
391da14cebeSEric Cheng 	{ "delete-etherstub",	do_delete_etherstub,
3920790b6dcSAnurag S. Maskey 	    "    delete-etherstub [-t] <link>"				},
393da14cebeSEric Cheng 	{ "show-etherstub",	do_show_etherstub,
3940790b6dcSAnurag S. Maskey 	    "    show-etherstub   [-t] [<link>]\n"			},
395da14cebeSEric Cheng 	{ "show-usage",		do_show_usage,
396ae6aa22aSVenugopal Iyer 	    "    show-usage       [-a] [-d | -F <format>] "
3970790b6dcSAnurag S. Maskey 	    "[-s <DD/MM/YYYY,HH:MM:SS>]\n"
3980790b6dcSAnurag S. Maskey 	    "\t\t     [-e <DD/MM/YYYY,HH:MM:SS>] -f <logfile> [<link>]"	}
3997c478bd9Sstevel@tonic-gate };
4007c478bd9Sstevel@tonic-gate 
401d62bc4baSyz147064 static const struct option lopts[] = {
4027c478bd9Sstevel@tonic-gate 	{"vlan-id",	required_argument,	0, 'v'},
403e7801d59Ssowmini 	{"output",	required_argument,	0, 'o'},
4047c478bd9Sstevel@tonic-gate 	{"dev",		required_argument,	0, 'd'},
4057c478bd9Sstevel@tonic-gate 	{"policy",	required_argument,	0, 'P'},
406d62bc4baSyz147064 	{"lacp-mode",	required_argument,	0, 'L'},
4077c478bd9Sstevel@tonic-gate 	{"lacp-timer",	required_argument,	0, 'T'},
4087c478bd9Sstevel@tonic-gate 	{"unicast",	required_argument,	0, 'u'},
409d62bc4baSyz147064 	{"temporary",	no_argument,		0, 't'},
410d62bc4baSyz147064 	{"root-dir",	required_argument,	0, 'R'},
411d62bc4baSyz147064 	{"link",	required_argument,	0, 'l'},
412d62bc4baSyz147064 	{"forcible",	no_argument,		0, 'f'},
413da14cebeSEric Cheng 	{"bw-limit",	required_argument,	0, 'b'},
414da14cebeSEric Cheng 	{"mac-address",	required_argument,	0, 'm'},
415da14cebeSEric Cheng 	{"slot",	required_argument,	0, 'n'},
416d62bc4baSyz147064 	{ 0, 0, 0, 0 }
417d62bc4baSyz147064 };
418d62bc4baSyz147064 
419d62bc4baSyz147064 static const struct option show_lopts[] = {
4207c478bd9Sstevel@tonic-gate 	{"statistics",	no_argument,		0, 's'},
421da14cebeSEric Cheng 	{"continuous",	no_argument,		0, 'S'},
4227c478bd9Sstevel@tonic-gate 	{"interval",	required_argument,	0, 'i'},
4237c478bd9Sstevel@tonic-gate 	{"parseable",	no_argument,		0, 'p'},
424d62bc4baSyz147064 	{"extended",	no_argument,		0, 'x'},
425e7801d59Ssowmini 	{"output",	required_argument,	0, 'o'},
426d62bc4baSyz147064 	{"persistent",	no_argument,		0, 'P'},
427d62bc4baSyz147064 	{"lacp",	no_argument,		0, 'L'},
4287c478bd9Sstevel@tonic-gate 	{ 0, 0, 0, 0 }
4297c478bd9Sstevel@tonic-gate };
4307c478bd9Sstevel@tonic-gate 
4310ba2cbe9Sxc151355 static const struct option prop_longopts[] = {
4320ba2cbe9Sxc151355 	{"temporary",	no_argument,		0, 't'  },
433e7801d59Ssowmini 	{"output",	required_argument,	0, 'o'  },
4340ba2cbe9Sxc151355 	{"root-dir",	required_argument,	0, 'R'  },
4350ba2cbe9Sxc151355 	{"prop",	required_argument,	0, 'p'  },
4360ba2cbe9Sxc151355 	{"parseable",	no_argument,		0, 'c'  },
4370ba2cbe9Sxc151355 	{"persistent",	no_argument,		0, 'P'  },
4380ba2cbe9Sxc151355 	{ 0, 0, 0, 0 }
4390ba2cbe9Sxc151355 };
4400ba2cbe9Sxc151355 
4410ba2cbe9Sxc151355 static const struct option wifi_longopts[] = {
4420ba2cbe9Sxc151355 	{"parseable",	no_argument,		0, 'p'  },
4430ba2cbe9Sxc151355 	{"output",	required_argument,	0, 'o'  },
4440ba2cbe9Sxc151355 	{"essid",	required_argument,	0, 'e'  },
4450ba2cbe9Sxc151355 	{"bsstype",	required_argument,	0, 'b'  },
4460ba2cbe9Sxc151355 	{"mode",	required_argument,	0, 'm'  },
4470ba2cbe9Sxc151355 	{"key",		required_argument,	0, 'k'  },
4480ba2cbe9Sxc151355 	{"sec",		required_argument,	0, 's'  },
4490ba2cbe9Sxc151355 	{"auth",	required_argument,	0, 'a'  },
4500ba2cbe9Sxc151355 	{"create-ibss",	required_argument,	0, 'c'  },
4510ba2cbe9Sxc151355 	{"timeout",	required_argument,	0, 'T'  },
4520ba2cbe9Sxc151355 	{"all-links",	no_argument,		0, 'a'  },
4530ba2cbe9Sxc151355 	{"temporary",	no_argument,		0, 't'  },
4540ba2cbe9Sxc151355 	{"root-dir",	required_argument,	0, 'R'  },
4550ba2cbe9Sxc151355 	{"persistent",	no_argument,		0, 'P'  },
4560ba2cbe9Sxc151355 	{"file",	required_argument,	0, 'f'  },
4570ba2cbe9Sxc151355 	{ 0, 0, 0, 0 }
4580ba2cbe9Sxc151355 };
459e7801d59Ssowmini static const struct option showeth_lopts[] = {
460e7801d59Ssowmini 	{"parseable",	no_argument,		0, 'p'	},
461e7801d59Ssowmini 	{"extended",	no_argument,		0, 'x'	},
462e7801d59Ssowmini 	{"output",	required_argument,	0, 'o'	},
463e7801d59Ssowmini 	{ 0, 0, 0, 0 }
464e7801d59Ssowmini };
465e7801d59Ssowmini 
466da14cebeSEric Cheng static const struct option vnic_lopts[] = {
467da14cebeSEric Cheng 	{"temporary",	no_argument,		0, 't'	},
468da14cebeSEric Cheng 	{"root-dir",	required_argument,	0, 'R'	},
469da14cebeSEric Cheng 	{"dev",		required_argument,	0, 'd'	},
470da14cebeSEric Cheng 	{"mac-address",	required_argument,	0, 'm'	},
471da14cebeSEric Cheng 	{"cpus",	required_argument,	0, 'c'	},
472da14cebeSEric Cheng 	{"bw-limit",	required_argument,	0, 'b'	},
473da14cebeSEric Cheng 	{"slot",	required_argument,	0, 'n'	},
474da14cebeSEric Cheng 	{"mac-prefix",	required_argument,	0, 'r'	},
475da14cebeSEric Cheng 	{ 0, 0, 0, 0 }
476da14cebeSEric Cheng };
477da14cebeSEric Cheng 
478da14cebeSEric Cheng static const struct option etherstub_lopts[] = {
479da14cebeSEric Cheng 	{"temporary",	no_argument,		0, 't'	},
480da14cebeSEric Cheng 	{"root-dir",	required_argument,	0, 'R'	},
481da14cebeSEric Cheng 	{ 0, 0, 0, 0 }
482da14cebeSEric Cheng };
483da14cebeSEric Cheng 
484ae6aa22aSVenugopal Iyer static const struct option usage_opts[] = {
485ae6aa22aSVenugopal Iyer 	{"file",	required_argument,	0, 'f'	},
486ae6aa22aSVenugopal Iyer 	{"format",	required_argument,	0, 'F'	},
487ae6aa22aSVenugopal Iyer 	{"start",	required_argument,	0, 's'	},
488ae6aa22aSVenugopal Iyer 	{"stop",	required_argument,	0, 'e'	},
489ae6aa22aSVenugopal Iyer 	{ 0, 0, 0, 0 }
490ae6aa22aSVenugopal Iyer };
491ae6aa22aSVenugopal Iyer 
492e7801d59Ssowmini /*
493e7801d59Ssowmini  * structures for 'dladm show-ether'
494e7801d59Ssowmini  */
4954784fcbdSSowmini Varadhan static const char *ptype[] = {LEI_ATTR_NAMES};
4964784fcbdSSowmini Varadhan 
497e7801d59Ssowmini typedef struct ether_fields_buf_s
498e7801d59Ssowmini {
499e7801d59Ssowmini 	char	eth_link[15];
500e7801d59Ssowmini 	char	eth_ptype[8];
501e7801d59Ssowmini 	char	eth_state[8];
502e7801d59Ssowmini 	char	eth_autoneg[5];
503e7801d59Ssowmini 	char	eth_spdx[31];
504e7801d59Ssowmini 	char	eth_pause[6];
505e7801d59Ssowmini 	char	eth_rem_fault[16];
506e7801d59Ssowmini } ether_fields_buf_t;
507e7801d59Ssowmini 
508e7801d59Ssowmini static print_field_t ether_fields[] = {
509e7801d59Ssowmini /* name,	header,			field width,  offset,	cmdtype */
510e7801d59Ssowmini { "link",	"LINK",			15,
511e7801d59Ssowmini     offsetof(ether_fields_buf_t, eth_link),	CMD_TYPE_ANY},
512e7801d59Ssowmini { "ptype",	"PTYPE",		8,
513e7801d59Ssowmini     offsetof(ether_fields_buf_t, eth_ptype),	CMD_TYPE_ANY},
514e7801d59Ssowmini { "state",	"STATE",		8,
515e7801d59Ssowmini     offsetof(ether_fields_buf_t, eth_state),	CMD_TYPE_ANY},
516e7801d59Ssowmini { "auto",	"AUTO",			5,
517e7801d59Ssowmini     offsetof(ether_fields_buf_t, eth_autoneg),	CMD_TYPE_ANY},
518e7801d59Ssowmini { "speed-duplex", "SPEED-DUPLEX",	31,
519e7801d59Ssowmini     offsetof(ether_fields_buf_t, eth_spdx),	CMD_TYPE_ANY},
520e7801d59Ssowmini { "pause",	"PAUSE",		6,
521e7801d59Ssowmini     offsetof(ether_fields_buf_t, eth_pause),	CMD_TYPE_ANY},
522e7801d59Ssowmini { "rem_fault",	"REM_FAULT",		16,
523e7801d59Ssowmini     offsetof(ether_fields_buf_t, eth_rem_fault),	CMD_TYPE_ANY}}
524e7801d59Ssowmini ;
525e7801d59Ssowmini #define	ETHER_MAX_FIELDS	(sizeof (ether_fields) / sizeof (print_field_t))
526e7801d59Ssowmini 
527e7801d59Ssowmini typedef struct print_ether_state {
528e7801d59Ssowmini 	const char	*es_link;
529e7801d59Ssowmini 	boolean_t	es_parseable;
530e7801d59Ssowmini 	boolean_t	es_header;
531e7801d59Ssowmini 	boolean_t	es_extended;
532e7801d59Ssowmini 	print_state_t	es_print;
533e7801d59Ssowmini } print_ether_state_t;
534e7801d59Ssowmini 
535e7801d59Ssowmini /*
536da14cebeSEric Cheng  * structures for 'dladm show-link -s' (print statistics)
537e7801d59Ssowmini  */
538e7801d59Ssowmini typedef enum {
539ae6aa22aSVenugopal Iyer 	LINK_S_LINK,
540ae6aa22aSVenugopal Iyer 	LINK_S_IPKTS,
541ae6aa22aSVenugopal Iyer 	LINK_S_RBYTES,
542ae6aa22aSVenugopal Iyer 	LINK_S_IERRORS,
543ae6aa22aSVenugopal Iyer 	LINK_S_OPKTS,
544ae6aa22aSVenugopal Iyer 	LINK_S_OBYTES,
545ae6aa22aSVenugopal Iyer 	LINK_S_OERRORS
546ae6aa22aSVenugopal Iyer } link_s_field_index_t;
547e7801d59Ssowmini 
548ae6aa22aSVenugopal Iyer static print_field_t link_s_fields[] = {
549e7801d59Ssowmini /* name,	header,		field width,	index,		cmdtype	*/
550ae6aa22aSVenugopal Iyer { "link",	"LINK",			15,	LINK_S_LINK,	CMD_TYPE_ANY},
551ae6aa22aSVenugopal Iyer { "ipackets",	"IPACKETS",		10,	LINK_S_IPKTS,	CMD_TYPE_ANY},
552ae6aa22aSVenugopal Iyer { "rbytes",	"RBYTES",		8,	LINK_S_RBYTES,	CMD_TYPE_ANY},
553ae6aa22aSVenugopal Iyer { "ierrors",	"IERRORS",		10,	LINK_S_IERRORS,	CMD_TYPE_ANY},
554ae6aa22aSVenugopal Iyer { "opackets",	"OPACKETS",		12,	LINK_S_OPKTS,	CMD_TYPE_ANY},
555ae6aa22aSVenugopal Iyer { "obytes",	"OBYTES",		12,	LINK_S_OBYTES,	CMD_TYPE_ANY},
556ae6aa22aSVenugopal Iyer { "oerrors",	"OERRORS",		8,	LINK_S_OERRORS,	CMD_TYPE_ANY}}
557e7801d59Ssowmini ;
558ae6aa22aSVenugopal Iyer #define	LINK_S_MAX_FIELDS \
559ae6aa22aSVenugopal Iyer 	(sizeof (link_s_fields) / sizeof (print_field_t))
560ae6aa22aSVenugopal Iyer 
561ae6aa22aSVenugopal Iyer typedef struct link_args_s {
562ae6aa22aSVenugopal Iyer 	char		*link_s_link;
563ae6aa22aSVenugopal Iyer 	pktsum_t	*link_s_psum;
564ae6aa22aSVenugopal Iyer } link_args_t;
565ae6aa22aSVenugopal Iyer static char *print_link_stats(print_field_t *, void *);
566e7801d59Ssowmini 
567e7801d59Ssowmini /*
568e7801d59Ssowmini  * buffer used by print functions for show-{link,phys,vlan} commands.
569e7801d59Ssowmini  */
570e7801d59Ssowmini typedef struct link_fields_buf_s {
571e7801d59Ssowmini 	char link_name[MAXLINKNAMELEN];
572e7801d59Ssowmini 	char link_class[DLADM_STRSIZE];
573c08e5e1aSdr146992 	char link_mtu[11];
574e7801d59Ssowmini 	char link_state[DLADM_STRSIZE];
575e7801d59Ssowmini 	char link_over[MAXLINKNAMELEN];
5764045d941Ssowmini 	char link_phys_state[DLADM_STRSIZE];
577e7801d59Ssowmini 	char link_phys_media[DLADM_STRSIZE];
578e7801d59Ssowmini 	char link_phys_speed[DLADM_STRSIZE];
579e7801d59Ssowmini 	char link_phys_duplex[DLPI_LINKNAME_MAX];
580e7801d59Ssowmini 	char link_phys_device[DLPI_LINKNAME_MAX];
581e7801d59Ssowmini 	char link_flags[6];
582e7801d59Ssowmini 	char link_vlan_vid[6];
583e7801d59Ssowmini } link_fields_buf_t;
584e7801d59Ssowmini 
585e7801d59Ssowmini /*
586e7801d59Ssowmini  * structures for 'dladm show-link'
587e7801d59Ssowmini  */
588e7801d59Ssowmini static print_field_t link_fields[] = {
589e7801d59Ssowmini /* name,	header,		field width,	offset,	cmdtype		*/
590e7801d59Ssowmini { "link",	"LINK",		11,
591e7801d59Ssowmini     offsetof(link_fields_buf_t, link_name),	CMD_TYPE_ANY},
592e7801d59Ssowmini { "class",	"CLASS",	 8,
593e7801d59Ssowmini     offsetof(link_fields_buf_t, link_class),	CMD_TYPE_ANY},
594e7801d59Ssowmini { "mtu",	"MTU",		 6,
595e7801d59Ssowmini     offsetof(link_fields_buf_t, link_mtu),	CMD_TYPE_ANY},
596e7801d59Ssowmini { "state",	"STATE",	 8,
597e7801d59Ssowmini     offsetof(link_fields_buf_t, link_state),	CMD_TYPE_ANY},
598e7801d59Ssowmini { "over",	"OVER",		DLPI_LINKNAME_MAX,
599e7801d59Ssowmini     offsetof(link_fields_buf_t, link_over),	CMD_TYPE_ANY}}
600e7801d59Ssowmini ;
601e7801d59Ssowmini #define	DEV_LINK_FIELDS	(sizeof (link_fields) / sizeof (print_field_t))
602e7801d59Ssowmini 
603e7801d59Ssowmini /*
604e7801d59Ssowmini  * structures for 'dladm show-aggr'
605e7801d59Ssowmini  */
606e7801d59Ssowmini typedef struct laggr_fields_buf_s {
607e7801d59Ssowmini 	char laggr_name[DLPI_LINKNAME_MAX];
608e7801d59Ssowmini 	char laggr_policy[9];
609e7801d59Ssowmini 	char laggr_addrpolicy[ETHERADDRL * 3 + 3];
610e7801d59Ssowmini 	char laggr_lacpactivity[14];
611e7801d59Ssowmini 	char laggr_lacptimer[DLADM_STRSIZE];
612e7801d59Ssowmini 	char laggr_flags[7];
613e7801d59Ssowmini } laggr_fields_buf_t;
614e7801d59Ssowmini 
615e7801d59Ssowmini typedef struct laggr_args_s {
616e7801d59Ssowmini 	int			laggr_lport; /* -1 indicates the aggr itself */
617e7801d59Ssowmini 	const char 		*laggr_link;
618e7801d59Ssowmini 	dladm_aggr_grp_attr_t	*laggr_ginfop;
619e7801d59Ssowmini 	dladm_status_t		*laggr_status;
620e7801d59Ssowmini 	pktsum_t		*laggr_pktsumtot; /* -s only */
621e7801d59Ssowmini 	pktsum_t		*laggr_prevstats; /* -s only */
622e7801d59Ssowmini 	boolean_t		laggr_parseable;
623e7801d59Ssowmini } laggr_args_t;
624e7801d59Ssowmini 
625e7801d59Ssowmini static print_field_t laggr_fields[] = {
626e7801d59Ssowmini /* name,		header,		field width,	offset,	cmdtype	*/
627e7801d59Ssowmini { "link",		"LINK",		15,
628e7801d59Ssowmini     offsetof(laggr_fields_buf_t, laggr_name),		CMD_TYPE_ANY},
629e7801d59Ssowmini { "policy",		"POLICY",	 8,
630e7801d59Ssowmini     offsetof(laggr_fields_buf_t, laggr_policy),	CMD_TYPE_ANY},
631e7801d59Ssowmini { "addrpolicy",		"ADDRPOLICY",	 ETHERADDRL * 3 + 2,
632e7801d59Ssowmini     offsetof(laggr_fields_buf_t, laggr_addrpolicy),	CMD_TYPE_ANY},
633e7801d59Ssowmini { "lacpactivity",	"LACPACTIVITY",	 13,
634e7801d59Ssowmini     offsetof(laggr_fields_buf_t, laggr_lacpactivity),	CMD_TYPE_ANY},
635e7801d59Ssowmini { "lacptimer",		"LACPTIMER",	 11,
636e7801d59Ssowmini     offsetof(laggr_fields_buf_t, laggr_lacptimer),	CMD_TYPE_ANY},
637e7801d59Ssowmini { "flags",		"FLAGS",	 7,
638e7801d59Ssowmini     offsetof(laggr_fields_buf_t, laggr_flags),	CMD_TYPE_ANY}}
639e7801d59Ssowmini ;
640e7801d59Ssowmini #define	LAGGR_MAX_FIELDS	(sizeof (laggr_fields) / sizeof (print_field_t))
641e7801d59Ssowmini 
642e7801d59Ssowmini /*
643e7801d59Ssowmini  * structures for 'dladm show-aggr -x'.
644e7801d59Ssowmini  */
645e7801d59Ssowmini typedef enum {
646e7801d59Ssowmini 	AGGR_X_LINK,
647e7801d59Ssowmini 	AGGR_X_PORT,
648e7801d59Ssowmini 	AGGR_X_SPEED,
649e7801d59Ssowmini 	AGGR_X_DUPLEX,
650e7801d59Ssowmini 	AGGR_X_STATE,
651e7801d59Ssowmini 	AGGR_X_ADDRESS,
652e7801d59Ssowmini 	AGGR_X_PORTSTATE
653e7801d59Ssowmini } aggr_x_field_index_t;
654e7801d59Ssowmini 
655e7801d59Ssowmini static print_field_t aggr_x_fields[] = {
656e7801d59Ssowmini /* name,	header,		field width,	index,		cmdtype	*/
657e7801d59Ssowmini { "link",	"LINK",			11,	AGGR_X_LINK,	CMD_TYPE_ANY},
658e7801d59Ssowmini { "port",	"PORT",			14,	AGGR_X_PORT,	CMD_TYPE_ANY},
659e7801d59Ssowmini { "speed",	"SPEED",		4,	AGGR_X_SPEED,	CMD_TYPE_ANY},
660e7801d59Ssowmini { "duplex",	"DUPLEX",		9,	AGGR_X_DUPLEX,	CMD_TYPE_ANY},
661e7801d59Ssowmini { "state",	"STATE",		9,	AGGR_X_STATE,	CMD_TYPE_ANY},
662e7801d59Ssowmini { "address",	"ADDRESS",		18,	AGGR_X_ADDRESS,	CMD_TYPE_ANY},
663e7801d59Ssowmini { "portstate",	"PORTSTATE",		15,	AGGR_X_PORTSTATE, CMD_TYPE_ANY}}
664e7801d59Ssowmini ;
665e7801d59Ssowmini #define	AGGR_X_MAX_FIELDS \
666e7801d59Ssowmini 	(sizeof (aggr_x_fields) / sizeof (print_field_t))
667e7801d59Ssowmini 
668e7801d59Ssowmini /*
669e7801d59Ssowmini  * structures for 'dladm show-aggr -s'.
670e7801d59Ssowmini  */
671e7801d59Ssowmini typedef enum {
672e7801d59Ssowmini 	AGGR_S_LINK,
673e7801d59Ssowmini 	AGGR_S_PORT,
674e7801d59Ssowmini 	AGGR_S_IPKTS,
675e7801d59Ssowmini 	AGGR_S_RBYTES,
676e7801d59Ssowmini 	AGGR_S_OPKTS,
677e7801d59Ssowmini 	AGGR_S_OBYTES,
678e7801d59Ssowmini 	AGGR_S_IPKTDIST,
679e7801d59Ssowmini 	AGGR_S_OPKTDIST
680e7801d59Ssowmini } aggr_s_field_index_t;
681e7801d59Ssowmini 
682e7801d59Ssowmini static print_field_t aggr_s_fields[] = {
683e7801d59Ssowmini /* name,		header,		field width,	index,	cmdtype	*/
684e7801d59Ssowmini { "link",		"LINK",		11,	AGGR_S_LINK,
685e7801d59Ssowmini     CMD_TYPE_ANY},
686e7801d59Ssowmini { "port",		"PORT",		9,	AGGR_S_PORT,
687e7801d59Ssowmini     CMD_TYPE_ANY},
688e7801d59Ssowmini { "ipackets",		"IPACKETS",	7,	AGGR_S_IPKTS,
689e7801d59Ssowmini     CMD_TYPE_ANY},
690e7801d59Ssowmini { "rbytes",		"RBYTES",	7,	AGGR_S_RBYTES,
691e7801d59Ssowmini     CMD_TYPE_ANY},
692e7801d59Ssowmini { "opackets",		"OPACKETS",	7,	AGGR_S_OPKTS,
693e7801d59Ssowmini     CMD_TYPE_ANY},
694e7801d59Ssowmini { "obytes",		"OBYTES",	7,	AGGR_S_OBYTES,
695e7801d59Ssowmini     CMD_TYPE_ANY},
696e7801d59Ssowmini { "ipktdist",		"IPKTDIST",	8,	AGGR_S_IPKTDIST,
697e7801d59Ssowmini     CMD_TYPE_ANY},
698e7801d59Ssowmini { "opktdist",		"OPKTDIST",	14,	AGGR_S_OPKTDIST,
699e7801d59Ssowmini     CMD_TYPE_ANY}}
700e7801d59Ssowmini ;
701e7801d59Ssowmini #define	AGGR_S_MAX_FIELDS \
702da14cebeSEric Cheng 	(sizeof (aggr_s_fields) / sizeof (print_field_t))
703e7801d59Ssowmini 
704e7801d59Ssowmini /*
705da14cebeSEric Cheng  * structures for 'dladm show-aggr -L'.
706e7801d59Ssowmini  */
707e7801d59Ssowmini typedef enum {
708e7801d59Ssowmini 	AGGR_L_LINK,
709e7801d59Ssowmini 	AGGR_L_PORT,
710e7801d59Ssowmini 	AGGR_L_AGGREGATABLE,
711e7801d59Ssowmini 	AGGR_L_SYNC,
712e7801d59Ssowmini 	AGGR_L_COLL,
713e7801d59Ssowmini 	AGGR_L_DIST,
714e7801d59Ssowmini 	AGGR_L_DEFAULTED,
715e7801d59Ssowmini 	AGGR_L_EXPIRED
716e7801d59Ssowmini } aggr_l_field_index_t;
717e7801d59Ssowmini 
718e7801d59Ssowmini static print_field_t aggr_l_fields[] = {
719e7801d59Ssowmini /* name,		header,		field width,	index,	cmdtype	*/
720e7801d59Ssowmini { "link",		"LINK",		11,	AGGR_L_LINK,
721e7801d59Ssowmini     CMD_TYPE_ANY},
722e7801d59Ssowmini { "port",		"PORT",		12,	AGGR_L_PORT,
723e7801d59Ssowmini     CMD_TYPE_ANY},
724e7801d59Ssowmini { "aggregatable",	"AGGREGATABLE",	12,	AGGR_L_AGGREGATABLE,
725e7801d59Ssowmini     CMD_TYPE_ANY},
726e7801d59Ssowmini { "sync",		"SYNC",		4,	AGGR_L_SYNC,
727e7801d59Ssowmini     CMD_TYPE_ANY},
728e7801d59Ssowmini { "coll",		"COLL",		4,	AGGR_L_COLL,
729e7801d59Ssowmini     CMD_TYPE_ANY},
730e7801d59Ssowmini { "dist",		"DIST",		4,	AGGR_L_DIST,
731e7801d59Ssowmini     CMD_TYPE_ANY},
732e7801d59Ssowmini { "defaulted",		"DEFAULTED",	9,	AGGR_L_DEFAULTED,
733e7801d59Ssowmini     CMD_TYPE_ANY},
734e7801d59Ssowmini { "expired",		"EXPIRED",	14,	AGGR_L_EXPIRED,
735e7801d59Ssowmini     CMD_TYPE_ANY}}
736e7801d59Ssowmini ;
737e7801d59Ssowmini #define	AGGR_L_MAX_FIELDS \
738e7801d59Ssowmini 	(sizeof (aggr_l_fields) / sizeof (print_field_t))
739e7801d59Ssowmini 
740e7801d59Ssowmini /*
741e7801d59Ssowmini  * structures for 'dladm show-phys'
742e7801d59Ssowmini  */
743e7801d59Ssowmini 
744e7801d59Ssowmini static print_field_t phys_fields[] = {
745e7801d59Ssowmini /* name,	header,		field width,	offset,	cmdtype		*/
746e7801d59Ssowmini { "link",	"LINK",			12,
747e7801d59Ssowmini     offsetof(link_fields_buf_t, link_name),		CMD_TYPE_ANY},
748e7801d59Ssowmini { "media",	"MEDIA",		20,
749e7801d59Ssowmini     offsetof(link_fields_buf_t, link_phys_media),	CMD_TYPE_ANY},
750e7801d59Ssowmini { "state",	"STATE",		10,
751e7801d59Ssowmini     offsetof(link_fields_buf_t, link_phys_state),	CMD_TYPE_ANY},
7526be03d0bSVasumathi Sundaram - Sun Microsystems { "speed",	"SPEED",		6,
753e7801d59Ssowmini     offsetof(link_fields_buf_t, link_phys_speed),	CMD_TYPE_ANY},
754e7801d59Ssowmini { "duplex",	"DUPLEX",		9,
755e7801d59Ssowmini     offsetof(link_fields_buf_t, link_phys_duplex),	CMD_TYPE_ANY},
756e7801d59Ssowmini { "device",	"DEVICE",		12,
757e7801d59Ssowmini     offsetof(link_fields_buf_t, link_phys_device),	CMD_TYPE_ANY},
758e7801d59Ssowmini { "flags",	"FLAGS",		6,
759e7801d59Ssowmini     offsetof(link_fields_buf_t, link_flags),		CMD_TYPE_ANY}}
760e7801d59Ssowmini ;
761e7801d59Ssowmini #define	PHYS_MAX_FIELDS	(sizeof (phys_fields) / sizeof (print_field_t))
762e7801d59Ssowmini 
763e7801d59Ssowmini /*
764da14cebeSEric Cheng  * structures for 'dladm show-phys -m'
765da14cebeSEric Cheng  */
766da14cebeSEric Cheng 
767da14cebeSEric Cheng typedef enum {
768da14cebeSEric Cheng 	PHYS_M_LINK,
769da14cebeSEric Cheng 	PHYS_M_SLOT,
770da14cebeSEric Cheng 	PHYS_M_ADDRESS,
771da14cebeSEric Cheng 	PHYS_M_INUSE,
772da14cebeSEric Cheng 	PHYS_M_CLIENT
773da14cebeSEric Cheng } phys_m_field_index_t;
774da14cebeSEric Cheng 
775da14cebeSEric Cheng static print_field_t phys_m_fields[] = {
776da14cebeSEric Cheng /* name,	header,		field width,	offset,	cmdtype		*/
777da14cebeSEric Cheng { "link",	"LINK",		12,	PHYS_M_LINK,	CMD_TYPE_ANY},
778da14cebeSEric Cheng { "slot",	"SLOT",		8,	PHYS_M_SLOT,	CMD_TYPE_ANY},
779da14cebeSEric Cheng { "address",	"ADDRESS",	18,	PHYS_M_ADDRESS,	CMD_TYPE_ANY},
780da14cebeSEric Cheng { "inuse",	"INUSE",	4,	PHYS_M_INUSE,	CMD_TYPE_ANY},
781da14cebeSEric Cheng { "client",	"CLIENT",	12,	PHYS_M_CLIENT,	CMD_TYPE_ANY}}
782da14cebeSEric Cheng ;
783da14cebeSEric Cheng #define	PHYS_M_MAX_FIELDS (sizeof (phys_m_fields) / sizeof (print_field_t))
784da14cebeSEric Cheng 
785da14cebeSEric Cheng /*
786da14cebeSEric Cheng  * structures for 'dladm show-phys -H'
787da14cebeSEric Cheng  */
788da14cebeSEric Cheng 
789da14cebeSEric Cheng typedef enum {
790da14cebeSEric Cheng 	PHYS_H_LINK,
791da14cebeSEric Cheng 	PHYS_H_GROUP,
792da14cebeSEric Cheng 	PHYS_H_GRPTYPE,
793da14cebeSEric Cheng 	PHYS_H_RINGS,
794da14cebeSEric Cheng 	PHYS_H_CLIENTS
795da14cebeSEric Cheng } phys_h_field_index_t;
796da14cebeSEric Cheng 
797da14cebeSEric Cheng static print_field_t phys_h_fields[] = {
798da14cebeSEric Cheng /* name,	header,		field width,	offset,	cmdtype		*/
799da14cebeSEric Cheng { "link",	"LINK",		12,	PHYS_H_LINK,	CMD_TYPE_ANY},
800da14cebeSEric Cheng { "group",	"GROUP",	8,	PHYS_H_GROUP,	CMD_TYPE_ANY},
801da14cebeSEric Cheng { "grouptype",	"TYPE",		6,	PHYS_H_GRPTYPE,	CMD_TYPE_ANY},
802da14cebeSEric Cheng { "rings",	"NUM-RINGS",	16,	PHYS_H_RINGS,	CMD_TYPE_ANY},
803da14cebeSEric Cheng { "clients",	"CLIENTS",	20,	PHYS_H_CLIENTS,	CMD_TYPE_ANY}}
804da14cebeSEric Cheng ;
805da14cebeSEric Cheng #define	PHYS_H_MAX_FIELDS (sizeof (phys_h_fields) / sizeof (print_field_t))
806da14cebeSEric Cheng 
807da14cebeSEric Cheng /*
808e7801d59Ssowmini  * structures for 'dladm show-vlan'
809e7801d59Ssowmini  */
810e7801d59Ssowmini static print_field_t vlan_fields[] = {
811e7801d59Ssowmini /* name,	header,		field width,	offset,	cmdtype		*/
812e7801d59Ssowmini { "link",	"LINK",			15,
813e7801d59Ssowmini     offsetof(link_fields_buf_t, link_name),		CMD_TYPE_ANY},
814e7801d59Ssowmini { "vid",	"VID",			8,
815e7801d59Ssowmini     offsetof(link_fields_buf_t, link_vlan_vid),	CMD_TYPE_ANY},
816e7801d59Ssowmini { "over",	"OVER",			12,
817e7801d59Ssowmini     offsetof(link_fields_buf_t, link_over),		CMD_TYPE_ANY},
818e7801d59Ssowmini { "flags",	"FLAGS",		6,
819e7801d59Ssowmini     offsetof(link_fields_buf_t, link_flags),		CMD_TYPE_ANY}}
820e7801d59Ssowmini ;
821e7801d59Ssowmini #define	VLAN_MAX_FIELDS	(sizeof (vlan_fields) / sizeof (print_field_t))
822e7801d59Ssowmini 
823da14cebeSEric Cheng 
824e7801d59Ssowmini /*
825e7801d59Ssowmini  * structures for 'dladm show-wifi'
826e7801d59Ssowmini  */
827e7801d59Ssowmini static print_field_t wifi_fields[] = {
828e7801d59Ssowmini { "link",	"LINK",		10, 0,			WIFI_CMD_ALL},
829e7801d59Ssowmini { "essid",	"ESSID",	19, DLADM_WLAN_ATTR_ESSID,	WIFI_CMD_ALL},
830e7801d59Ssowmini { "bssid",	"BSSID/IBSSID", 17, DLADM_WLAN_ATTR_BSSID,	WIFI_CMD_ALL},
831e7801d59Ssowmini { "ibssid",	"BSSID/IBSSID", 17, DLADM_WLAN_ATTR_BSSID,	WIFI_CMD_ALL},
832e7801d59Ssowmini { "mode",	"MODE",		6,  DLADM_WLAN_ATTR_MODE,	WIFI_CMD_ALL},
833e7801d59Ssowmini { "speed",	"SPEED",	6,  DLADM_WLAN_ATTR_SPEED,	WIFI_CMD_ALL},
834e7801d59Ssowmini { "auth",	"AUTH",		8,  DLADM_WLAN_ATTR_AUTH,	WIFI_CMD_SHOW},
835e7801d59Ssowmini { "bsstype",	"BSSTYPE",	8,  DLADM_WLAN_ATTR_BSSTYPE, WIFI_CMD_ALL},
836e7801d59Ssowmini { "sec",	"SEC",		6,  DLADM_WLAN_ATTR_SECMODE, WIFI_CMD_ALL},
837e7801d59Ssowmini { "status",	"STATUS",	17, DLADM_WLAN_LINKATTR_STATUS, WIFI_CMD_SHOW},
838e7801d59Ssowmini { "strength",	"STRENGTH",	10, DLADM_WLAN_ATTR_STRENGTH, WIFI_CMD_ALL}}
839e7801d59Ssowmini ;
840e7801d59Ssowmini 
841e7801d59Ssowmini static char *all_scan_wifi_fields =
842e7801d59Ssowmini 	"link,essid,bssid,sec,strength,mode,speed,bsstype";
843e7801d59Ssowmini static char *all_show_wifi_fields =
844e7801d59Ssowmini 	"link,status,essid,sec,strength,mode,speed,auth,bssid,bsstype";
845e7801d59Ssowmini static char *def_scan_wifi_fields =
846e7801d59Ssowmini 	"link,essid,bssid,sec,strength,mode,speed";
847e7801d59Ssowmini static char *def_show_wifi_fields =
848e7801d59Ssowmini 	"link,status,essid,sec,strength,mode,speed";
849e7801d59Ssowmini 
850e7801d59Ssowmini #define	WIFI_MAX_FIELDS		(sizeof (wifi_fields) / sizeof (print_field_t))
851e7801d59Ssowmini 
852e7801d59Ssowmini /*
853e7801d59Ssowmini  * structures for 'dladm show-linkprop'
854e7801d59Ssowmini  */
855e7801d59Ssowmini typedef enum {
856e7801d59Ssowmini 	LINKPROP_LINK,
857e7801d59Ssowmini 	LINKPROP_PROPERTY,
858afdda45fSVasumathi Sundaram - Sun Microsystems 	LINKPROP_PERM,
859e7801d59Ssowmini 	LINKPROP_VALUE,
860e7801d59Ssowmini 	LINKPROP_DEFAULT,
861e7801d59Ssowmini 	LINKPROP_POSSIBLE
862e7801d59Ssowmini } linkprop_field_index_t;
863e7801d59Ssowmini 
864e7801d59Ssowmini static print_field_t linkprop_fields[] = {
865e7801d59Ssowmini /* name,	header,		field width,  index,		cmdtype */
866e7801d59Ssowmini { "link",	"LINK",		12,	LINKPROP_LINK,		CMD_TYPE_ANY},
867e7801d59Ssowmini { "property",	"PROPERTY",	15,	LINKPROP_PROPERTY,	CMD_TYPE_ANY},
868afdda45fSVasumathi Sundaram - Sun Microsystems { "perm",	"PERM",		4,	LINKPROP_PERM,		CMD_TYPE_ANY},
869e7801d59Ssowmini { "value",	"VALUE",	14,	LINKPROP_VALUE,		CMD_TYPE_ANY},
870e7801d59Ssowmini { "default",	"DEFAULT",	14,	LINKPROP_DEFAULT, 	CMD_TYPE_ANY},
871e7801d59Ssowmini { "possible",	"POSSIBLE",	20,	LINKPROP_POSSIBLE,	CMD_TYPE_ANY}}
872e7801d59Ssowmini ;
873e7801d59Ssowmini #define	LINKPROP_MAX_FIELDS					\
874e7801d59Ssowmini 	(sizeof (linkprop_fields) / sizeof (print_field_t))
875e7801d59Ssowmini 
876e7801d59Ssowmini #define	MAX_PROP_LINE		512
877e7801d59Ssowmini 
878e7801d59Ssowmini typedef struct show_linkprop_state {
879e7801d59Ssowmini 	char			ls_link[MAXLINKNAMELEN];
880e7801d59Ssowmini 	char			*ls_line;
881e7801d59Ssowmini 	char			**ls_propvals;
882da14cebeSEric Cheng 	dladm_arg_list_t	*ls_proplist;
883e7801d59Ssowmini 	boolean_t		ls_parseable;
884e7801d59Ssowmini 	boolean_t		ls_persist;
885e7801d59Ssowmini 	boolean_t		ls_header;
886e7801d59Ssowmini 	dladm_status_t		ls_status;
887e7801d59Ssowmini 	dladm_status_t		ls_retstatus;
888e7801d59Ssowmini 	print_state_t		ls_print;
889e7801d59Ssowmini } show_linkprop_state_t;
890e7801d59Ssowmini 
891da14cebeSEric Cheng typedef struct set_linkprop_state {
892da14cebeSEric Cheng 	const char		*ls_name;
893da14cebeSEric Cheng 	boolean_t		ls_reset;
894da14cebeSEric Cheng 	boolean_t		ls_temp;
895da14cebeSEric Cheng 	dladm_status_t		ls_status;
896da14cebeSEric Cheng } set_linkprop_state_t;
897da14cebeSEric Cheng 
898e7801d59Ssowmini typedef struct linkprop_args_s {
899e7801d59Ssowmini 	show_linkprop_state_t	*ls_state;
900e7801d59Ssowmini 	char			*ls_propname;
901e7801d59Ssowmini 	datalink_id_t		ls_linkid;
902e7801d59Ssowmini } linkprop_args_t;
903e7801d59Ssowmini 
904e7801d59Ssowmini /*
905e7801d59Ssowmini  * structures for 'dladm show-secobj'
906e7801d59Ssowmini  */
907e7801d59Ssowmini typedef struct secobj_fields_buf_s {
908e7801d59Ssowmini 	char			ss_obj_name[DLADM_SECOBJ_VAL_MAX];
909e7801d59Ssowmini 	char			ss_class[20];
910e7801d59Ssowmini 	char			ss_val[30];
911e7801d59Ssowmini } secobj_fields_buf_t;
912e7801d59Ssowmini static print_field_t secobj_fields[] = {
913e7801d59Ssowmini /* name,	header,		field width,	offset,	cmdtype		*/
914e7801d59Ssowmini { "object",	"OBJECT",		20,
915e7801d59Ssowmini     offsetof(secobj_fields_buf_t, ss_obj_name),	CMD_TYPE_ANY},
916e7801d59Ssowmini { "class",	"CLASS",		20,
917e7801d59Ssowmini     offsetof(secobj_fields_buf_t, ss_class),	CMD_TYPE_ANY},
918e7801d59Ssowmini { "value",	"VALUE",		30,
919e7801d59Ssowmini     offsetof(secobj_fields_buf_t, ss_val),	CMD_TYPE_ANY}}
920e7801d59Ssowmini ;
921e7801d59Ssowmini #define	DEV_SOBJ_FIELDS	(sizeof (secobj_fields) / sizeof (print_field_t))
9220ba2cbe9Sxc151355 
923da14cebeSEric Cheng /*
924da14cebeSEric Cheng  * structures for 'dladm show-vnic'
925da14cebeSEric Cheng  */
926da14cebeSEric Cheng typedef struct vnic_fields_buf_s
927da14cebeSEric Cheng {
928da14cebeSEric Cheng 	char vnic_link[DLPI_LINKNAME_MAX];
929da14cebeSEric Cheng 	char vnic_over[DLPI_LINKNAME_MAX];
930da14cebeSEric Cheng 	char vnic_speed[6];
931da14cebeSEric Cheng 	char vnic_macaddr[19];
932da14cebeSEric Cheng 	char vnic_macaddrtype[19];
933da14cebeSEric Cheng 	char vnic_vid[6];
934da14cebeSEric Cheng } vnic_fields_buf_t;
935da14cebeSEric Cheng 
936da14cebeSEric Cheng static print_field_t vnic_fields[] = {
937da14cebeSEric Cheng /* name,		header,		field width,	offset,	cmdtype	*/
938da14cebeSEric Cheng { "link",		"LINK",		12,
939da14cebeSEric Cheng     offsetof(vnic_fields_buf_t, vnic_link),		CMD_TYPE_ANY},
940da14cebeSEric Cheng { "over",		"OVER",		12,
941da14cebeSEric Cheng     offsetof(vnic_fields_buf_t, vnic_over),		CMD_TYPE_ANY},
942da14cebeSEric Cheng { "speed",		"SPEED",	6,
943da14cebeSEric Cheng     offsetof(vnic_fields_buf_t, vnic_speed),		CMD_TYPE_ANY},
944ae6aa22aSVenugopal Iyer { "macaddress",		"MACADDRESS",	20,
945da14cebeSEric Cheng     offsetof(vnic_fields_buf_t, vnic_macaddr),		CMD_TYPE_ANY},
946da14cebeSEric Cheng { "macaddrtype",	"MACADDRTYPE",	19,
947da14cebeSEric Cheng     offsetof(vnic_fields_buf_t, vnic_macaddrtype),	CMD_TYPE_ANY},
948da14cebeSEric Cheng { "vid",		"VID",		6,
949da14cebeSEric Cheng     offsetof(vnic_fields_buf_t, vnic_vid),		CMD_TYPE_ANY}}
950da14cebeSEric Cheng ;
951da14cebeSEric Cheng #define	VNIC_MAX_FIELDS	(sizeof (vnic_fields) / sizeof (print_field_t))
952da14cebeSEric Cheng 
953da14cebeSEric Cheng /*
954da14cebeSEric Cheng  * structures for 'dladm show-usage'
955da14cebeSEric Cheng  */
956da14cebeSEric Cheng 
957da14cebeSEric Cheng typedef struct  usage_fields_buf_s {
958da14cebeSEric Cheng 	char	usage_link[12];
959da14cebeSEric Cheng 	char	usage_duration[10];
960da14cebeSEric Cheng 	char	usage_ipackets[9];
961da14cebeSEric Cheng 	char	usage_rbytes[10];
962da14cebeSEric Cheng 	char	usage_opackets[9];
963da14cebeSEric Cheng 	char	usage_obytes[10];
964da14cebeSEric Cheng 	char	usage_bandwidth[14];
965da14cebeSEric Cheng } usage_fields_buf_t;
966da14cebeSEric Cheng 
967da14cebeSEric Cheng static print_field_t usage_fields[] = {
968da14cebeSEric Cheng /* name,	header,		field width,	offset,	cmdtype		*/
969da14cebeSEric Cheng { "link",	"LINK",			12,
970da14cebeSEric Cheng     offsetof(usage_fields_buf_t, usage_link),		CMD_TYPE_ANY},
971da14cebeSEric Cheng { "duration",	"DURATION",		10,
972da14cebeSEric Cheng     offsetof(usage_fields_buf_t, usage_duration),	CMD_TYPE_ANY},
973da14cebeSEric Cheng { "ipackets",	"IPACKETS",		9,
974da14cebeSEric Cheng     offsetof(usage_fields_buf_t, usage_ipackets),	CMD_TYPE_ANY},
975da14cebeSEric Cheng { "rbytes",	"RBYTES",		10,
976da14cebeSEric Cheng     offsetof(usage_fields_buf_t, usage_rbytes),		CMD_TYPE_ANY},
977da14cebeSEric Cheng { "opackets",	"OPACKETS",		9,
978da14cebeSEric Cheng     offsetof(usage_fields_buf_t, usage_opackets),	CMD_TYPE_ANY},
979da14cebeSEric Cheng { "obytes",	"OBYTES",		10,
980da14cebeSEric Cheng     offsetof(usage_fields_buf_t, usage_obytes),		CMD_TYPE_ANY},
981da14cebeSEric Cheng { "bandwidth",	"BANDWIDTH",		14,
982da14cebeSEric Cheng     offsetof(usage_fields_buf_t, usage_bandwidth),	CMD_TYPE_ANY}}
983da14cebeSEric Cheng ;
984da14cebeSEric Cheng 
985da14cebeSEric Cheng #define	USAGE_MAX_FIELDS	(sizeof (usage_fields) / sizeof (print_field_t))
986da14cebeSEric Cheng 
987da14cebeSEric Cheng /*
988da14cebeSEric Cheng  * structures for 'dladm show-usage link'
989da14cebeSEric Cheng  */
990da14cebeSEric Cheng 
991da14cebeSEric Cheng typedef struct  usage_l_fields_buf_s {
992da14cebeSEric Cheng 	char	usage_l_link[12];
993da14cebeSEric Cheng 	char	usage_l_stime[13];
994da14cebeSEric Cheng 	char	usage_l_etime[13];
995da14cebeSEric Cheng 	char	usage_l_rbytes[8];
996da14cebeSEric Cheng 	char	usage_l_obytes[8];
997da14cebeSEric Cheng 	char	usage_l_bandwidth[14];
998da14cebeSEric Cheng } usage_l_fields_buf_t;
999da14cebeSEric Cheng 
1000da14cebeSEric Cheng static print_field_t usage_l_fields[] = {
1001da14cebeSEric Cheng /* name,	header,		field width,	offset,	cmdtype		*/
1002da14cebeSEric Cheng { "link",	"LINK",		12,
1003da14cebeSEric Cheng     offsetof(usage_l_fields_buf_t, usage_l_link),	CMD_TYPE_ANY},
1004da14cebeSEric Cheng { "start",	"START",	13,
1005da14cebeSEric Cheng     offsetof(usage_l_fields_buf_t, usage_l_stime),	CMD_TYPE_ANY},
1006da14cebeSEric Cheng { "end",	"END",		13,
1007da14cebeSEric Cheng     offsetof(usage_l_fields_buf_t, usage_l_etime),	CMD_TYPE_ANY},
1008da14cebeSEric Cheng { "rbytes",	"RBYTES",	8,
1009da14cebeSEric Cheng     offsetof(usage_l_fields_buf_t, usage_l_rbytes),	CMD_TYPE_ANY},
1010da14cebeSEric Cheng { "obytes",	"OBYTES",	8,
1011da14cebeSEric Cheng     offsetof(usage_l_fields_buf_t, usage_l_obytes),	CMD_TYPE_ANY},
1012da14cebeSEric Cheng { "bandwidth",	"BANDWIDTH",	14,
1013da14cebeSEric Cheng     offsetof(usage_l_fields_buf_t, usage_l_bandwidth),	CMD_TYPE_ANY}}
1014da14cebeSEric Cheng ;
1015da14cebeSEric Cheng 
1016da14cebeSEric Cheng #define	USAGE_L_MAX_FIELDS \
1017da14cebeSEric Cheng 	(sizeof (usage_l_fields) /sizeof (print_field_t))
1018da14cebeSEric Cheng 
10197c478bd9Sstevel@tonic-gate static char *progname;
10200ba2cbe9Sxc151355 static sig_atomic_t signalled;
10217c478bd9Sstevel@tonic-gate 
10224ac67f02SAnurag S. Maskey /*
10234ac67f02SAnurag S. Maskey  * Handle to libdladm.  Opened in main() before the sub-command
10244ac67f02SAnurag S. Maskey  * specific function is called.
10254ac67f02SAnurag S. Maskey  */
10264ac67f02SAnurag S. Maskey static dladm_handle_t handle = NULL;
10274ac67f02SAnurag S. Maskey 
1028da14cebeSEric Cheng #define	DLADM_ETHERSTUB_NAME	"etherstub"
1029da14cebeSEric Cheng #define	DLADM_IS_ETHERSTUB(id)	(id == DATALINK_INVALID_LINKID)
1030da14cebeSEric Cheng 
10317c478bd9Sstevel@tonic-gate static void
10327c478bd9Sstevel@tonic-gate usage(void)
10337c478bd9Sstevel@tonic-gate {
10348d5c46e6Sam223141 	int	i;
10358d5c46e6Sam223141 	cmd_t	*cmdp;
10368d5c46e6Sam223141 	(void) fprintf(stderr, gettext("usage:  dladm <subcommand> <args> ..."
10378d5c46e6Sam223141 	    "\n"));
10388d5c46e6Sam223141 	for (i = 0; i < sizeof (cmds) / sizeof (cmds[0]); i++) {
10398d5c46e6Sam223141 		cmdp = &cmds[i];
10408d5c46e6Sam223141 		if (cmdp->c_usage != NULL)
10418d5c46e6Sam223141 			(void) fprintf(stderr, "%s\n", gettext(cmdp->c_usage));
10428d5c46e6Sam223141 	}
10434ac67f02SAnurag S. Maskey 
10444ac67f02SAnurag S. Maskey 	/* close dladm handle if it was opened */
10454ac67f02SAnurag S. Maskey 	if (handle != NULL)
10464ac67f02SAnurag S. Maskey 		dladm_close(handle);
10474ac67f02SAnurag S. Maskey 
10487c478bd9Sstevel@tonic-gate 	exit(1);
10497c478bd9Sstevel@tonic-gate }
10507c478bd9Sstevel@tonic-gate 
10517c478bd9Sstevel@tonic-gate int
10527c478bd9Sstevel@tonic-gate main(int argc, char *argv[])
10537c478bd9Sstevel@tonic-gate {
10547c478bd9Sstevel@tonic-gate 	int	i;
10557c478bd9Sstevel@tonic-gate 	cmd_t	*cmdp;
10564ac67f02SAnurag S. Maskey 	dladm_status_t status;
10577c478bd9Sstevel@tonic-gate 
10587c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
10597c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)
10607c478bd9Sstevel@tonic-gate #define	TEXT_DOMAIN "SYS_TEST"
10617c478bd9Sstevel@tonic-gate #endif
10627c478bd9Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
10637c478bd9Sstevel@tonic-gate 
10647c478bd9Sstevel@tonic-gate 	progname = argv[0];
10657c478bd9Sstevel@tonic-gate 
10667c478bd9Sstevel@tonic-gate 	if (argc < 2)
10677c478bd9Sstevel@tonic-gate 		usage();
10687c478bd9Sstevel@tonic-gate 
10697c478bd9Sstevel@tonic-gate 	for (i = 0; i < sizeof (cmds) / sizeof (cmds[0]); i++) {
10707c478bd9Sstevel@tonic-gate 		cmdp = &cmds[i];
10717c478bd9Sstevel@tonic-gate 		if (strcmp(argv[1], cmdp->c_name) == 0) {
10724ac67f02SAnurag S. Maskey 			/* Open the libdladm handle */
10734ac67f02SAnurag S. Maskey 			if ((status = dladm_open(&handle)) != DLADM_STATUS_OK) {
10744ac67f02SAnurag S. Maskey 				die_dlerr(status,
10754ac67f02SAnurag S. Maskey 				    "could not open /dev/dld");
10764ac67f02SAnurag S. Maskey 			}
10774ac67f02SAnurag S. Maskey 
10788d5c46e6Sam223141 			cmdp->c_fn(argc - 1, &argv[1], cmdp->c_usage);
10794ac67f02SAnurag S. Maskey 
10804ac67f02SAnurag S. Maskey 			dladm_close(handle);
10817c478bd9Sstevel@tonic-gate 			exit(0);
10827c478bd9Sstevel@tonic-gate 		}
10837c478bd9Sstevel@tonic-gate 	}
10847c478bd9Sstevel@tonic-gate 
10857c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("%s: unknown subcommand '%s'\n"),
10867c478bd9Sstevel@tonic-gate 	    progname, argv[1]);
10877c478bd9Sstevel@tonic-gate 	usage();
10887c478bd9Sstevel@tonic-gate 
10897c478bd9Sstevel@tonic-gate 	return (0);
10907c478bd9Sstevel@tonic-gate }
10917c478bd9Sstevel@tonic-gate 
1092da14cebeSEric Cheng /*ARGSUSED*/
1093da14cebeSEric Cheng static int
1094da14cebeSEric Cheng show_usage_date(dladm_usage_t *usage, void *arg)
1095da14cebeSEric Cheng {
1096ae6aa22aSVenugopal Iyer 	show_usage_state_t	*state = (show_usage_state_t *)arg;
1097da14cebeSEric Cheng 	time_t			stime;
1098da14cebeSEric Cheng 	char			timebuf[20];
1099ae6aa22aSVenugopal Iyer 	dladm_status_t		status;
1100ae6aa22aSVenugopal Iyer 	uint32_t		flags;
1101ae6aa22aSVenugopal Iyer 
1102ae6aa22aSVenugopal Iyer 	/*
1103ae6aa22aSVenugopal Iyer 	 * Only show usage information for existing links unless '-a'
1104ae6aa22aSVenugopal Iyer 	 * is specified.
1105ae6aa22aSVenugopal Iyer 	 */
1106ae6aa22aSVenugopal Iyer 	if (!state->us_showall) {
1107ae6aa22aSVenugopal Iyer 		if ((status = dladm_name2info(handle, usage->du_name,
1108ae6aa22aSVenugopal Iyer 		    NULL, &flags, NULL, NULL)) != DLADM_STATUS_OK) {
1109ae6aa22aSVenugopal Iyer 			return (status);
1110ae6aa22aSVenugopal Iyer 		}
1111ae6aa22aSVenugopal Iyer 		if ((flags & DLADM_OPT_ACTIVE) == 0)
1112ae6aa22aSVenugopal Iyer 			return (DLADM_STATUS_LINKINVAL);
1113ae6aa22aSVenugopal Iyer 	}
1114da14cebeSEric Cheng 
1115da14cebeSEric Cheng 	stime = usage->du_stime;
1116da14cebeSEric Cheng 	(void) strftime(timebuf, sizeof (timebuf), "%m/%d/%Y",
1117da14cebeSEric Cheng 	    localtime(&stime));
1118da14cebeSEric Cheng 	(void) printf("%s\n", timebuf);
1119da14cebeSEric Cheng 
1120da14cebeSEric Cheng 	return (DLADM_STATUS_OK);
1121da14cebeSEric Cheng }
1122da14cebeSEric Cheng 
1123da14cebeSEric Cheng static int
1124da14cebeSEric Cheng show_usage_time(dladm_usage_t *usage, void *arg)
1125da14cebeSEric Cheng {
1126da14cebeSEric Cheng 	show_usage_state_t	*state = (show_usage_state_t *)arg;
1127da14cebeSEric Cheng 	char			buf[DLADM_STRSIZE];
1128da14cebeSEric Cheng 	usage_l_fields_buf_t 	ubuf;
1129da14cebeSEric Cheng 	time_t			time;
1130da14cebeSEric Cheng 	double			bw;
1131ae6aa22aSVenugopal Iyer 	dladm_status_t		status;
1132ae6aa22aSVenugopal Iyer 	uint32_t		flags;
1133ae6aa22aSVenugopal Iyer 
1134ae6aa22aSVenugopal Iyer 	/*
1135ae6aa22aSVenugopal Iyer 	 * Only show usage information for existing links unless '-a'
1136ae6aa22aSVenugopal Iyer 	 * is specified.
1137ae6aa22aSVenugopal Iyer 	 */
1138ae6aa22aSVenugopal Iyer 	if (!state->us_showall) {
1139ae6aa22aSVenugopal Iyer 		if ((status = dladm_name2info(handle, usage->du_name,
1140ae6aa22aSVenugopal Iyer 		    NULL, &flags, NULL, NULL)) != DLADM_STATUS_OK) {
1141ae6aa22aSVenugopal Iyer 			return (status);
1142ae6aa22aSVenugopal Iyer 		}
1143ae6aa22aSVenugopal Iyer 		if ((flags & DLADM_OPT_ACTIVE) == 0)
1144ae6aa22aSVenugopal Iyer 			return (DLADM_STATUS_LINKINVAL);
1145ae6aa22aSVenugopal Iyer 	}
1146da14cebeSEric Cheng 
1147da14cebeSEric Cheng 	if (state->us_plot) {
1148da14cebeSEric Cheng 		if (!state->us_printheader) {
1149da14cebeSEric Cheng 			if (state->us_first) {
1150da14cebeSEric Cheng 				(void) printf("# Time");
1151da14cebeSEric Cheng 				state->us_first = B_FALSE;
1152da14cebeSEric Cheng 			}
1153da14cebeSEric Cheng 			(void) printf(" %s", usage->du_name);
1154da14cebeSEric Cheng 			if (usage->du_last) {
1155da14cebeSEric Cheng 				(void) printf("\n");
1156da14cebeSEric Cheng 				state->us_first = B_TRUE;
1157da14cebeSEric Cheng 				state->us_printheader = B_TRUE;
1158da14cebeSEric Cheng 			}
1159da14cebeSEric Cheng 		} else {
1160da14cebeSEric Cheng 			if (state->us_first) {
1161da14cebeSEric Cheng 				time = usage->du_etime;
1162da14cebeSEric Cheng 				(void) strftime(buf, sizeof (buf), "%T",
1163da14cebeSEric Cheng 				    localtime(&time));
1164da14cebeSEric Cheng 				state->us_first = B_FALSE;
1165da14cebeSEric Cheng 				(void) printf("%s", buf);
1166da14cebeSEric Cheng 			}
1167da14cebeSEric Cheng 			bw = (double)usage->du_bandwidth/1000;
1168da14cebeSEric Cheng 			(void) printf(" %.2f", bw);
1169da14cebeSEric Cheng 			if (usage->du_last) {
1170da14cebeSEric Cheng 				(void) printf("\n");
1171da14cebeSEric Cheng 				state->us_first = B_TRUE;
1172da14cebeSEric Cheng 			}
1173da14cebeSEric Cheng 		}
1174da14cebeSEric Cheng 		return (DLADM_STATUS_OK);
1175da14cebeSEric Cheng 	}
1176da14cebeSEric Cheng 
1177da14cebeSEric Cheng 	bzero(&ubuf, sizeof (ubuf));
1178da14cebeSEric Cheng 
1179da14cebeSEric Cheng 	(void) snprintf(ubuf.usage_l_link, sizeof (ubuf.usage_l_link), "%s",
1180da14cebeSEric Cheng 	    usage->du_name);
1181da14cebeSEric Cheng 	time = usage->du_stime;
1182da14cebeSEric Cheng 	(void) strftime(buf, sizeof (buf), "%T", localtime(&time));
1183da14cebeSEric Cheng 	(void) snprintf(ubuf.usage_l_stime, sizeof (ubuf.usage_l_stime), "%s",
1184da14cebeSEric Cheng 	    buf);
1185da14cebeSEric Cheng 	time = usage->du_etime;
1186da14cebeSEric Cheng 	(void) strftime(buf, sizeof (buf), "%T", localtime(&time));
1187da14cebeSEric Cheng 	(void) snprintf(ubuf.usage_l_etime, sizeof (ubuf.usage_l_etime), "%s",
1188da14cebeSEric Cheng 	    buf);
1189da14cebeSEric Cheng 	(void) snprintf(ubuf.usage_l_rbytes, sizeof (ubuf.usage_l_rbytes),
1190da14cebeSEric Cheng 	    "%llu", usage->du_rbytes);
1191da14cebeSEric Cheng 	(void) snprintf(ubuf.usage_l_obytes, sizeof (ubuf.usage_l_obytes),
1192da14cebeSEric Cheng 	    "%llu", usage->du_obytes);
1193da14cebeSEric Cheng 	(void) snprintf(ubuf.usage_l_bandwidth, sizeof (ubuf.usage_l_bandwidth),
1194da14cebeSEric Cheng 	    "%s Mbps", dladm_bw2str(usage->du_bandwidth, buf));
1195da14cebeSEric Cheng 
1196da14cebeSEric Cheng 	if (!state->us_parseable && !state->us_printheader) {
1197da14cebeSEric Cheng 		print_header(&state->us_print);
1198da14cebeSEric Cheng 		state->us_printheader = B_TRUE;
1199da14cebeSEric Cheng 	}
1200da14cebeSEric Cheng 
1201da14cebeSEric Cheng 	dladm_print_output(&state->us_print, state->us_parseable,
1202da14cebeSEric Cheng 	    dladm_print_field, (void *)&ubuf);
1203da14cebeSEric Cheng 
1204da14cebeSEric Cheng 	return (DLADM_STATUS_OK);
1205da14cebeSEric Cheng }
1206da14cebeSEric Cheng 
1207da14cebeSEric Cheng static int
1208da14cebeSEric Cheng show_usage_res(dladm_usage_t *usage, void *arg)
1209da14cebeSEric Cheng {
1210da14cebeSEric Cheng 	show_usage_state_t	*state = (show_usage_state_t *)arg;
1211da14cebeSEric Cheng 	char			buf[DLADM_STRSIZE];
1212da14cebeSEric Cheng 	usage_fields_buf_t	ubuf;
1213ae6aa22aSVenugopal Iyer 	dladm_status_t		status;
1214ae6aa22aSVenugopal Iyer 	uint32_t		flags;
1215ae6aa22aSVenugopal Iyer 
1216ae6aa22aSVenugopal Iyer 	/*
1217ae6aa22aSVenugopal Iyer 	 * Only show usage information for existing links unless '-a'
1218ae6aa22aSVenugopal Iyer 	 * is specified.
1219ae6aa22aSVenugopal Iyer 	 */
1220ae6aa22aSVenugopal Iyer 	if (!state->us_showall) {
1221ae6aa22aSVenugopal Iyer 		if ((status = dladm_name2info(handle, usage->du_name,
1222ae6aa22aSVenugopal Iyer 		    NULL, &flags, NULL, NULL)) != DLADM_STATUS_OK) {
1223ae6aa22aSVenugopal Iyer 			return (status);
1224ae6aa22aSVenugopal Iyer 		}
1225ae6aa22aSVenugopal Iyer 		if ((flags & DLADM_OPT_ACTIVE) == 0)
1226ae6aa22aSVenugopal Iyer 			return (DLADM_STATUS_LINKINVAL);
1227ae6aa22aSVenugopal Iyer 	}
1228da14cebeSEric Cheng 
1229da14cebeSEric Cheng 	bzero(&ubuf, sizeof (ubuf));
1230da14cebeSEric Cheng 
1231da14cebeSEric Cheng 	(void) snprintf(ubuf.usage_link, sizeof (ubuf.usage_link), "%s",
1232da14cebeSEric Cheng 	    usage->du_name);
1233da14cebeSEric Cheng 	(void) snprintf(ubuf.usage_duration, sizeof (ubuf.usage_duration),
1234da14cebeSEric Cheng 	    "%llu", usage->du_duration);
1235da14cebeSEric Cheng 	(void) snprintf(ubuf.usage_ipackets, sizeof (ubuf.usage_ipackets),
1236da14cebeSEric Cheng 	    "%llu", usage->du_ipackets);
1237da14cebeSEric Cheng 	(void) snprintf(ubuf.usage_rbytes, sizeof (ubuf.usage_rbytes),
1238da14cebeSEric Cheng 	    "%llu", usage->du_rbytes);
1239da14cebeSEric Cheng 	(void) snprintf(ubuf.usage_opackets, sizeof (ubuf.usage_opackets),
1240da14cebeSEric Cheng 	    "%llu", usage->du_opackets);
1241da14cebeSEric Cheng 	(void) snprintf(ubuf.usage_obytes, sizeof (ubuf.usage_obytes),
1242da14cebeSEric Cheng 	    "%llu", usage->du_obytes);
1243da14cebeSEric Cheng 	(void) snprintf(ubuf.usage_bandwidth, sizeof (ubuf.usage_bandwidth),
1244da14cebeSEric Cheng 	    "%s Mbps", dladm_bw2str(usage->du_bandwidth, buf));
1245da14cebeSEric Cheng 
1246da14cebeSEric Cheng 	if (!state->us_parseable && !state->us_printheader) {
1247da14cebeSEric Cheng 		print_header(&state->us_print);
1248da14cebeSEric Cheng 		state->us_printheader = B_TRUE;
1249da14cebeSEric Cheng 	}
1250da14cebeSEric Cheng 
1251da14cebeSEric Cheng 	dladm_print_output(&state->us_print, state->us_parseable,
1252da14cebeSEric Cheng 	    dladm_print_field, (void *)&ubuf);
1253da14cebeSEric Cheng 
1254da14cebeSEric Cheng 	return (DLADM_STATUS_OK);
1255da14cebeSEric Cheng }
1256da14cebeSEric Cheng 
1257da14cebeSEric Cheng static boolean_t
1258da14cebeSEric Cheng valid_formatspec(char *formatspec_str)
1259da14cebeSEric Cheng {
1260da14cebeSEric Cheng 	if (strcmp(formatspec_str, "gnuplot") == 0)
1261da14cebeSEric Cheng 		return (B_TRUE);
1262da14cebeSEric Cheng 	return (B_FALSE);
1263da14cebeSEric Cheng 
1264da14cebeSEric Cheng }
1265da14cebeSEric Cheng 
1266da14cebeSEric Cheng /*ARGSUSED*/
1267da14cebeSEric Cheng static void
1268da14cebeSEric Cheng do_show_usage(int argc, char *argv[], const char *use)
1269da14cebeSEric Cheng {
1270da14cebeSEric Cheng 	char			*file = NULL;
1271da14cebeSEric Cheng 	int			opt;
1272da14cebeSEric Cheng 	dladm_status_t		status;
1273da14cebeSEric Cheng 	boolean_t		d_arg = B_FALSE;
1274da14cebeSEric Cheng 	char			*stime = NULL;
1275da14cebeSEric Cheng 	char			*etime = NULL;
1276da14cebeSEric Cheng 	char			*resource = NULL;
1277da14cebeSEric Cheng 	show_usage_state_t	state;
1278da14cebeSEric Cheng 	boolean_t		o_arg = B_FALSE;
1279da14cebeSEric Cheng 	boolean_t		F_arg = B_FALSE;
1280da14cebeSEric Cheng 	char			*fields_str = NULL;
1281da14cebeSEric Cheng 	char			*formatspec_str = NULL;
1282da14cebeSEric Cheng 	print_field_t		**fields;
1283da14cebeSEric Cheng 	uint_t			nfields;
1284da14cebeSEric Cheng 	char			*all_fields =
1285da14cebeSEric Cheng 	    "link,duration,ipackets,rbytes,opackets,obytes,bandwidth";
1286da14cebeSEric Cheng 	char			*all_l_fields =
1287da14cebeSEric Cheng 	    "link,start,end,rbytes,obytes,bandwidth";
1288da14cebeSEric Cheng 
1289da14cebeSEric Cheng 	bzero(&state, sizeof (show_usage_state_t));
1290da14cebeSEric Cheng 	state.us_parseable = B_FALSE;
1291da14cebeSEric Cheng 	state.us_printheader = B_FALSE;
1292da14cebeSEric Cheng 	state.us_plot = B_FALSE;
1293da14cebeSEric Cheng 	state.us_first = B_TRUE;
1294da14cebeSEric Cheng 
1295ae6aa22aSVenugopal Iyer 	while ((opt = getopt_long(argc, argv, "das:e:o:f:F:",
1296ae6aa22aSVenugopal Iyer 	    usage_opts, NULL)) != -1) {
1297da14cebeSEric Cheng 		switch (opt) {
1298da14cebeSEric Cheng 		case 'd':
1299da14cebeSEric Cheng 			d_arg = B_TRUE;
1300da14cebeSEric Cheng 			break;
1301ae6aa22aSVenugopal Iyer 		case 'a':
1302ae6aa22aSVenugopal Iyer 			state.us_showall = B_TRUE;
1303da14cebeSEric Cheng 			break;
1304da14cebeSEric Cheng 		case 'f':
1305da14cebeSEric Cheng 			file = optarg;
1306da14cebeSEric Cheng 			break;
1307da14cebeSEric Cheng 		case 's':
1308da14cebeSEric Cheng 			stime = optarg;
1309da14cebeSEric Cheng 			break;
1310da14cebeSEric Cheng 		case 'e':
1311da14cebeSEric Cheng 			etime = optarg;
1312da14cebeSEric Cheng 			break;
1313da14cebeSEric Cheng 		case 'o':
1314da14cebeSEric Cheng 			o_arg = B_TRUE;
1315da14cebeSEric Cheng 			fields_str = optarg;
1316da14cebeSEric Cheng 			break;
1317da14cebeSEric Cheng 		case 'F':
1318ae6aa22aSVenugopal Iyer 			state.us_plot = F_arg = B_TRUE;
1319da14cebeSEric Cheng 			formatspec_str = optarg;
1320da14cebeSEric Cheng 			break;
1321da14cebeSEric Cheng 		default:
1322da14cebeSEric Cheng 			die_opterr(optopt, opt, use);
1323da14cebeSEric Cheng 			break;
1324da14cebeSEric Cheng 		}
1325da14cebeSEric Cheng 	}
1326da14cebeSEric Cheng 
1327da14cebeSEric Cheng 	if (file == NULL)
1328da14cebeSEric Cheng 		die("show-usage requires a file");
1329da14cebeSEric Cheng 
1330da14cebeSEric Cheng 	if (optind == (argc-1)) {
1331ae6aa22aSVenugopal Iyer 		uint32_t 	flags;
1332ae6aa22aSVenugopal Iyer 
1333da14cebeSEric Cheng 		resource = argv[optind];
1334ae6aa22aSVenugopal Iyer 		if (!state.us_showall &&
1335ae6aa22aSVenugopal Iyer 		    (((status = dladm_name2info(handle, resource, NULL, &flags,
1336ae6aa22aSVenugopal Iyer 		    NULL, NULL)) != DLADM_STATUS_OK) ||
1337ae6aa22aSVenugopal Iyer 		    ((flags & DLADM_OPT_ACTIVE) == 0))) {
1338ae6aa22aSVenugopal Iyer 			die("invalid link: '%s'", resource);
1339ae6aa22aSVenugopal Iyer 		}
1340da14cebeSEric Cheng 	}
1341da14cebeSEric Cheng 
1342da14cebeSEric Cheng 	if (resource == NULL && stime == NULL && etime == NULL) {
1343da14cebeSEric Cheng 		if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0))
1344da14cebeSEric Cheng 			fields_str = all_fields;
1345da14cebeSEric Cheng 		fields = parse_output_fields(fields_str, usage_fields,
1346da14cebeSEric Cheng 		    USAGE_MAX_FIELDS, CMD_TYPE_ANY, &nfields);
1347da14cebeSEric Cheng 	} else {
1348da14cebeSEric Cheng 		if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0))
1349da14cebeSEric Cheng 			fields_str = all_l_fields;
1350da14cebeSEric Cheng 		fields = parse_output_fields(fields_str, usage_l_fields,
1351da14cebeSEric Cheng 		    USAGE_L_MAX_FIELDS, CMD_TYPE_ANY, &nfields);
1352da14cebeSEric Cheng 	}
1353da14cebeSEric Cheng 
1354da14cebeSEric Cheng 	if (fields == NULL) {
1355da14cebeSEric Cheng 		die("invalid fields(s) specified");
1356da14cebeSEric Cheng 		return;
1357da14cebeSEric Cheng 	}
1358da14cebeSEric Cheng 	state.us_print.ps_fields = fields;
1359da14cebeSEric Cheng 	state.us_print.ps_nfields = nfields;
1360da14cebeSEric Cheng 
1361ae6aa22aSVenugopal Iyer 	if (F_arg && d_arg)
1362ae6aa22aSVenugopal Iyer 		die("incompatible -d and -F options");
1363da14cebeSEric Cheng 
1364da14cebeSEric Cheng 	if (F_arg && valid_formatspec(formatspec_str) == B_FALSE)
1365da14cebeSEric Cheng 		die("Format specifier %s not supported", formatspec_str);
1366da14cebeSEric Cheng 
1367da14cebeSEric Cheng 	if (d_arg) {
1368da14cebeSEric Cheng 		/* Print log dates */
1369da14cebeSEric Cheng 		status = dladm_usage_dates(show_usage_date,
1370da14cebeSEric Cheng 		    DLADM_LOGTYPE_LINK, file, resource, &state);
1371da14cebeSEric Cheng 	} else if (resource == NULL && stime == NULL && etime == NULL &&
1372ae6aa22aSVenugopal Iyer 	    !F_arg) {
1373da14cebeSEric Cheng 		/* Print summary */
1374da14cebeSEric Cheng 		status = dladm_usage_summary(show_usage_res,
1375da14cebeSEric Cheng 		    DLADM_LOGTYPE_LINK, file, &state);
1376da14cebeSEric Cheng 	} else if (resource != NULL) {
1377da14cebeSEric Cheng 		/* Print log entries for named resource */
1378da14cebeSEric Cheng 		status = dladm_walk_usage_res(show_usage_time,
1379da14cebeSEric Cheng 		    DLADM_LOGTYPE_LINK, file, resource, stime, etime, &state);
1380da14cebeSEric Cheng 	} else {
1381da14cebeSEric Cheng 		/* Print time and information for each link */
1382da14cebeSEric Cheng 		status = dladm_walk_usage_time(show_usage_time,
1383da14cebeSEric Cheng 		    DLADM_LOGTYPE_LINK, file, stime, etime, &state);
1384da14cebeSEric Cheng 	}
1385da14cebeSEric Cheng 
1386da14cebeSEric Cheng 	if (status != DLADM_STATUS_OK)
1387da14cebeSEric Cheng 		die_dlerr(status, "show-usage");
1388da14cebeSEric Cheng }
1389da14cebeSEric Cheng 
13907c478bd9Sstevel@tonic-gate static void
13918d5c46e6Sam223141 do_create_aggr(int argc, char *argv[], const char *use)
13927c478bd9Sstevel@tonic-gate {
13937c478bd9Sstevel@tonic-gate 	char			option;
1394d62bc4baSyz147064 	int			key = 0;
13957c478bd9Sstevel@tonic-gate 	uint32_t		policy = AGGR_POLICY_L4;
13967c478bd9Sstevel@tonic-gate 	aggr_lacp_mode_t	lacp_mode = AGGR_LACP_OFF;
13977c478bd9Sstevel@tonic-gate 	aggr_lacp_timer_t	lacp_timer = AGGR_LACP_TIMER_SHORT;
1398f595a68aSyz147064 	dladm_aggr_port_attr_db_t	port[MAXPORT];
1399d62bc4baSyz147064 	uint_t			n, ndev, nlink;
14007c478bd9Sstevel@tonic-gate 	uint8_t			mac_addr[ETHERADDRL];
14017c478bd9Sstevel@tonic-gate 	boolean_t		mac_addr_fixed = B_FALSE;
14027c478bd9Sstevel@tonic-gate 	boolean_t		P_arg = B_FALSE;
14037c478bd9Sstevel@tonic-gate 	boolean_t		l_arg = B_FALSE;
14047c478bd9Sstevel@tonic-gate 	boolean_t		u_arg = B_FALSE;
14057c478bd9Sstevel@tonic-gate 	boolean_t		T_arg = B_FALSE;
1406d62bc4baSyz147064 	uint32_t		flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
14077c478bd9Sstevel@tonic-gate 	char			*altroot = NULL;
1408d62bc4baSyz147064 	char			name[MAXLINKNAMELEN];
1409d62bc4baSyz147064 	char			*devs[MAXPORT];
1410d62bc4baSyz147064 	char			*links[MAXPORT];
1411f595a68aSyz147064 	dladm_status_t		status;
1412da14cebeSEric Cheng 	dladm_status_t		pstatus;
1413*63a6526dSMichael Lim 	char			propstr[DLADM_STRSIZE];
1414da14cebeSEric Cheng 	dladm_arg_list_t	*proplist = NULL;
1415da14cebeSEric Cheng 	int			i;
1416da14cebeSEric Cheng 	datalink_id_t		linkid;
14177c478bd9Sstevel@tonic-gate 
1418d62bc4baSyz147064 	ndev = nlink = opterr = 0;
1419*63a6526dSMichael Lim 	bzero(propstr, DLADM_STRSIZE);
1420*63a6526dSMichael Lim 
1421da14cebeSEric Cheng 	while ((option = getopt_long(argc, argv, ":d:l:L:P:R:tfu:T:p:",
1422d62bc4baSyz147064 	    lopts, NULL)) != -1) {
14237c478bd9Sstevel@tonic-gate 		switch (option) {
14247c478bd9Sstevel@tonic-gate 		case 'd':
1425d62bc4baSyz147064 			if (ndev + nlink >= MAXPORT)
1426d62bc4baSyz147064 				die("too many ports specified");
14277c478bd9Sstevel@tonic-gate 
1428d62bc4baSyz147064 			devs[ndev++] = optarg;
14297c478bd9Sstevel@tonic-gate 			break;
14307c478bd9Sstevel@tonic-gate 		case 'P':
143133343a97Smeem 			if (P_arg)
143233343a97Smeem 				die_optdup(option);
14337c478bd9Sstevel@tonic-gate 
14347c478bd9Sstevel@tonic-gate 			P_arg = B_TRUE;
1435f595a68aSyz147064 			if (!dladm_aggr_str2policy(optarg, &policy))
143633343a97Smeem 				die("invalid policy '%s'", optarg);
14377c478bd9Sstevel@tonic-gate 			break;
14387c478bd9Sstevel@tonic-gate 		case 'u':
143933343a97Smeem 			if (u_arg)
144033343a97Smeem 				die_optdup(option);
14417c478bd9Sstevel@tonic-gate 
14427c478bd9Sstevel@tonic-gate 			u_arg = B_TRUE;
1443f595a68aSyz147064 			if (!dladm_aggr_str2macaddr(optarg, &mac_addr_fixed,
144433343a97Smeem 			    mac_addr))
144533343a97Smeem 				die("invalid MAC address '%s'", optarg);
14467c478bd9Sstevel@tonic-gate 			break;
14477c478bd9Sstevel@tonic-gate 		case 'l':
1448d62bc4baSyz147064 			if (isdigit(optarg[strlen(optarg) - 1])) {
1449d62bc4baSyz147064 
1450d62bc4baSyz147064 				/*
1451d62bc4baSyz147064 				 * Ended with digit, possibly a link name.
1452d62bc4baSyz147064 				 */
1453d62bc4baSyz147064 				if (ndev + nlink >= MAXPORT)
1454d62bc4baSyz147064 					die("too many ports specified");
1455d62bc4baSyz147064 
1456d62bc4baSyz147064 				links[nlink++] = optarg;
1457d62bc4baSyz147064 				break;
1458d62bc4baSyz147064 			}
1459d62bc4baSyz147064 			/* FALLTHROUGH */
1460d62bc4baSyz147064 		case 'L':
146133343a97Smeem 			if (l_arg)
146233343a97Smeem 				die_optdup(option);
14637c478bd9Sstevel@tonic-gate 
14647c478bd9Sstevel@tonic-gate 			l_arg = B_TRUE;
1465f595a68aSyz147064 			if (!dladm_aggr_str2lacpmode(optarg, &lacp_mode))
146633343a97Smeem 				die("invalid LACP mode '%s'", optarg);
14677c478bd9Sstevel@tonic-gate 			break;
14687c478bd9Sstevel@tonic-gate 		case 'T':
146933343a97Smeem 			if (T_arg)
147033343a97Smeem 				die_optdup(option);
14717c478bd9Sstevel@tonic-gate 
14727c478bd9Sstevel@tonic-gate 			T_arg = B_TRUE;
1473f595a68aSyz147064 			if (!dladm_aggr_str2lacptimer(optarg, &lacp_timer))
147433343a97Smeem 				die("invalid LACP timer value '%s'", optarg);
14757c478bd9Sstevel@tonic-gate 			break;
14767c478bd9Sstevel@tonic-gate 		case 't':
1477d62bc4baSyz147064 			flags &= ~DLADM_OPT_PERSIST;
1478d62bc4baSyz147064 			break;
1479d62bc4baSyz147064 		case 'f':
1480d62bc4baSyz147064 			flags |= DLADM_OPT_FORCE;
14817c478bd9Sstevel@tonic-gate 			break;
14827c478bd9Sstevel@tonic-gate 		case 'R':
14837c478bd9Sstevel@tonic-gate 			altroot = optarg;
14847c478bd9Sstevel@tonic-gate 			break;
1485da14cebeSEric Cheng 		case 'p':
1486*63a6526dSMichael Lim 			(void) strlcat(propstr, optarg, DLADM_STRSIZE);
1487*63a6526dSMichael Lim 			if (strlcat(propstr, ",", DLADM_STRSIZE) >=
1488*63a6526dSMichael Lim 			    DLADM_STRSIZE)
1489*63a6526dSMichael Lim 				die("property list too long '%s'", propstr);
1490da14cebeSEric Cheng 			break;
1491*63a6526dSMichael Lim 
14927c478bd9Sstevel@tonic-gate 		default:
14938d5c46e6Sam223141 			die_opterr(optopt, option, use);
149433343a97Smeem 			break;
14957c478bd9Sstevel@tonic-gate 		}
14967c478bd9Sstevel@tonic-gate 	}
14977c478bd9Sstevel@tonic-gate 
1498d62bc4baSyz147064 	if (ndev + nlink == 0)
14997c478bd9Sstevel@tonic-gate 		usage();
15007c478bd9Sstevel@tonic-gate 
1501d62bc4baSyz147064 	/* get key value or the aggregation name (required last argument) */
15027c478bd9Sstevel@tonic-gate 	if (optind != (argc-1))
15037c478bd9Sstevel@tonic-gate 		usage();
15047c478bd9Sstevel@tonic-gate 
1505d62bc4baSyz147064 	if (!str2int(argv[optind], &key)) {
1506d62bc4baSyz147064 		if (strlcpy(name, argv[optind], MAXLINKNAMELEN) >=
1507d62bc4baSyz147064 		    MAXLINKNAMELEN) {
1508d62bc4baSyz147064 			die("link name too long '%s'", argv[optind]);
1509d62bc4baSyz147064 		}
15107c478bd9Sstevel@tonic-gate 
1511d62bc4baSyz147064 		if (!dladm_valid_linkname(name))
1512d62bc4baSyz147064 			die("invalid link name '%s'", argv[optind]);
1513d62bc4baSyz147064 	} else {
1514d62bc4baSyz147064 		(void) snprintf(name, MAXLINKNAMELEN, "aggr%d", key);
1515d62bc4baSyz147064 	}
1516d62bc4baSyz147064 
1517d62bc4baSyz147064 	if (altroot != NULL)
1518d62bc4baSyz147064 		altroot_cmd(altroot, argc, argv);
1519d62bc4baSyz147064 
1520d62bc4baSyz147064 	for (n = 0; n < ndev; n++) {
15214ac67f02SAnurag S. Maskey 		if ((status = dladm_dev2linkid(handle, devs[n],
15224ac67f02SAnurag S. Maskey 		    &port[n].lp_linkid)) != DLADM_STATUS_OK) {
15234ac67f02SAnurag S. Maskey 			die_dlerr(status, "invalid dev name '%s'", devs[n]);
1524d62bc4baSyz147064 		}
1525d62bc4baSyz147064 	}
1526d62bc4baSyz147064 
1527d62bc4baSyz147064 	for (n = 0; n < nlink; n++) {
15284ac67f02SAnurag S. Maskey 		if ((status = dladm_name2info(handle, links[n],
15294ac67f02SAnurag S. Maskey 		    &port[ndev + n].lp_linkid, NULL, NULL, NULL)) !=
15304ac67f02SAnurag S. Maskey 		    DLADM_STATUS_OK) {
15314ac67f02SAnurag S. Maskey 			die_dlerr(status, "invalid link name '%s'", links[n]);
1532d62bc4baSyz147064 		}
1533d62bc4baSyz147064 	}
1534d62bc4baSyz147064 
15354ac67f02SAnurag S. Maskey 	status = dladm_aggr_create(handle, name, key, ndev + nlink, port,
15364ac67f02SAnurag S. Maskey 	    policy, mac_addr_fixed, (const uchar_t *)mac_addr, lacp_mode,
1537d62bc4baSyz147064 	    lacp_timer, flags);
1538da14cebeSEric Cheng 	if (status != DLADM_STATUS_OK)
1539da14cebeSEric Cheng 		goto done;
1540da14cebeSEric Cheng 
1541*63a6526dSMichael Lim 	if (dladm_parse_link_props(propstr, &proplist, B_FALSE)
1542*63a6526dSMichael Lim 	    != DLADM_STATUS_OK)
1543*63a6526dSMichael Lim 		die("invalid aggregation property");
1544*63a6526dSMichael Lim 
1545da14cebeSEric Cheng 	if (proplist == NULL)
1546da14cebeSEric Cheng 		return;
1547da14cebeSEric Cheng 
15484ac67f02SAnurag S. Maskey 	status = dladm_name2info(handle, name, &linkid, NULL, NULL, NULL);
1549da14cebeSEric Cheng 	if (status != DLADM_STATUS_OK)
1550da14cebeSEric Cheng 		goto done;
1551da14cebeSEric Cheng 
1552da14cebeSEric Cheng 	for (i = 0; i < proplist->al_count; i++) {
1553da14cebeSEric Cheng 		dladm_arg_info_t	*aip = &proplist->al_info[i];
1554da14cebeSEric Cheng 
15554ac67f02SAnurag S. Maskey 		pstatus = dladm_set_linkprop(handle, linkid, aip->ai_name,
1556da14cebeSEric Cheng 		    aip->ai_val, aip->ai_count, flags);
1557da14cebeSEric Cheng 
1558da14cebeSEric Cheng 		if (pstatus != DLADM_STATUS_OK) {
1559da14cebeSEric Cheng 			die_dlerr(pstatus,
1560da14cebeSEric Cheng 			    "aggr creation succeeded but "
1561da14cebeSEric Cheng 			    "could not set property '%s'", aip->ai_name);
1562da14cebeSEric Cheng 		}
1563da14cebeSEric Cheng 	}
1564d62bc4baSyz147064 done:
1565da14cebeSEric Cheng 	dladm_free_props(proplist);
1566d62bc4baSyz147064 	if (status != DLADM_STATUS_OK) {
1567d62bc4baSyz147064 		if (status == DLADM_STATUS_NONOTIF) {
1568d62bc4baSyz147064 			die_dlerr(status, "not all links have link up/down "
1569d62bc4baSyz147064 			    "detection; must use -f (see dladm(1M))\n");
1570d62bc4baSyz147064 		} else {
1571f595a68aSyz147064 			die_dlerr(status, "create operation failed");
15727c478bd9Sstevel@tonic-gate 		}
1573d62bc4baSyz147064 	}
1574d62bc4baSyz147064 }
1575d62bc4baSyz147064 
1576d62bc4baSyz147064 /*
1577d62bc4baSyz147064  * arg is either the key or the aggr name. Validate it and convert it to
1578d62bc4baSyz147064  * the linkid if altroot is NULL.
1579d62bc4baSyz147064  */
1580d62bc4baSyz147064 static dladm_status_t
1581d62bc4baSyz147064 i_dladm_aggr_get_linkid(const char *altroot, const char *arg,
1582d62bc4baSyz147064     datalink_id_t *linkidp, uint32_t flags)
1583d62bc4baSyz147064 {
1584d62bc4baSyz147064 	int		key = 0;
1585d62bc4baSyz147064 	char		*aggr = NULL;
1586d62bc4baSyz147064 	dladm_status_t	status;
1587d62bc4baSyz147064 
1588d62bc4baSyz147064 	if (!str2int(arg, &key))
1589d62bc4baSyz147064 		aggr = (char *)arg;
1590d62bc4baSyz147064 
1591d62bc4baSyz147064 	if (aggr == NULL && key == 0)
1592d62bc4baSyz147064 		return (DLADM_STATUS_LINKINVAL);
1593d62bc4baSyz147064 
1594d62bc4baSyz147064 	if (altroot != NULL)
1595d62bc4baSyz147064 		return (DLADM_STATUS_OK);
1596d62bc4baSyz147064 
1597d62bc4baSyz147064 	if (aggr != NULL) {
15984ac67f02SAnurag S. Maskey 		status = dladm_name2info(handle, aggr, linkidp, NULL, NULL,
15994ac67f02SAnurag S. Maskey 		    NULL);
1600d62bc4baSyz147064 	} else {
16014ac67f02SAnurag S. Maskey 		status = dladm_key2linkid(handle, key, linkidp, flags);
1602d62bc4baSyz147064 	}
1603d62bc4baSyz147064 
1604d62bc4baSyz147064 	return (status);
1605d62bc4baSyz147064 }
16067c478bd9Sstevel@tonic-gate 
16077c478bd9Sstevel@tonic-gate static void
16088d5c46e6Sam223141 do_delete_aggr(int argc, char *argv[], const char *use)
16097c478bd9Sstevel@tonic-gate {
16107c478bd9Sstevel@tonic-gate 	char			option;
16117c478bd9Sstevel@tonic-gate 	char			*altroot = NULL;
1612d62bc4baSyz147064 	uint32_t		flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
1613f595a68aSyz147064 	dladm_status_t		status;
1614d62bc4baSyz147064 	datalink_id_t		linkid;
16157c478bd9Sstevel@tonic-gate 
16167c478bd9Sstevel@tonic-gate 	opterr = 0;
1617d62bc4baSyz147064 	while ((option = getopt_long(argc, argv, ":R:t", lopts, NULL)) != -1) {
16187c478bd9Sstevel@tonic-gate 		switch (option) {
16197c478bd9Sstevel@tonic-gate 		case 't':
1620d62bc4baSyz147064 			flags &= ~DLADM_OPT_PERSIST;
16217c478bd9Sstevel@tonic-gate 			break;
16227c478bd9Sstevel@tonic-gate 		case 'R':
16237c478bd9Sstevel@tonic-gate 			altroot = optarg;
16247c478bd9Sstevel@tonic-gate 			break;
16257c478bd9Sstevel@tonic-gate 		default:
16268d5c46e6Sam223141 			die_opterr(optopt, option, use);
16277c478bd9Sstevel@tonic-gate 			break;
16287c478bd9Sstevel@tonic-gate 		}
16297c478bd9Sstevel@tonic-gate 	}
16307c478bd9Sstevel@tonic-gate 
1631d62bc4baSyz147064 	/* get key value or the aggregation name (required last argument) */
16327c478bd9Sstevel@tonic-gate 	if (optind != (argc-1))
16337c478bd9Sstevel@tonic-gate 		usage();
16347c478bd9Sstevel@tonic-gate 
1635d62bc4baSyz147064 	status = i_dladm_aggr_get_linkid(altroot, argv[optind], &linkid, flags);
1636d62bc4baSyz147064 	if (status != DLADM_STATUS_OK)
1637d62bc4baSyz147064 		goto done;
16387c478bd9Sstevel@tonic-gate 
1639d62bc4baSyz147064 	if (altroot != NULL)
1640d62bc4baSyz147064 		altroot_cmd(altroot, argc, argv);
1641d62bc4baSyz147064 
16424ac67f02SAnurag S. Maskey 	status = dladm_aggr_delete(handle, linkid, flags);
1643d62bc4baSyz147064 done:
1644f595a68aSyz147064 	if (status != DLADM_STATUS_OK)
1645f595a68aSyz147064 		die_dlerr(status, "delete operation failed");
16467c478bd9Sstevel@tonic-gate }
16477c478bd9Sstevel@tonic-gate 
16487c478bd9Sstevel@tonic-gate static void
16498d5c46e6Sam223141 do_add_aggr(int argc, char *argv[], const char *use)
16507c478bd9Sstevel@tonic-gate {
16517c478bd9Sstevel@tonic-gate 	char			option;
1652d62bc4baSyz147064 	uint_t			n, ndev, nlink;
16537c478bd9Sstevel@tonic-gate 	char			*altroot = NULL;
1654d62bc4baSyz147064 	uint32_t		flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
1655d62bc4baSyz147064 	datalink_id_t		linkid;
1656f595a68aSyz147064 	dladm_status_t		status;
1657d62bc4baSyz147064 	dladm_aggr_port_attr_db_t	port[MAXPORT];
1658d62bc4baSyz147064 	char			*devs[MAXPORT];
1659d62bc4baSyz147064 	char			*links[MAXPORT];
16607c478bd9Sstevel@tonic-gate 
1661d62bc4baSyz147064 	ndev = nlink = opterr = 0;
1662d62bc4baSyz147064 	while ((option = getopt_long(argc, argv, ":d:l:R:tf", lopts,
16637c478bd9Sstevel@tonic-gate 	    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;
1679d62bc4baSyz147064 			break;
1680d62bc4baSyz147064 		case 'f':
1681d62bc4baSyz147064 			flags |= DLADM_OPT_FORCE;
16827c478bd9Sstevel@tonic-gate 			break;
16837c478bd9Sstevel@tonic-gate 		case 'R':
16847c478bd9Sstevel@tonic-gate 			altroot = optarg;
16857c478bd9Sstevel@tonic-gate 			break;
16867c478bd9Sstevel@tonic-gate 		default:
16878d5c46e6Sam223141 			die_opterr(optopt, option, use);
168833343a97Smeem 			break;
16897c478bd9Sstevel@tonic-gate 		}
16907c478bd9Sstevel@tonic-gate 	}
16917c478bd9Sstevel@tonic-gate 
1692d62bc4baSyz147064 	if (ndev + nlink == 0)
16937c478bd9Sstevel@tonic-gate 		usage();
16947c478bd9Sstevel@tonic-gate 
1695d62bc4baSyz147064 	/* get key value or the aggregation name (required last argument) */
16967c478bd9Sstevel@tonic-gate 	if (optind != (argc-1))
16977c478bd9Sstevel@tonic-gate 		usage();
16987c478bd9Sstevel@tonic-gate 
1699d62bc4baSyz147064 	if ((status = i_dladm_aggr_get_linkid(altroot, argv[optind], &linkid,
1700d62bc4baSyz147064 	    flags & (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST))) !=
1701d62bc4baSyz147064 	    DLADM_STATUS_OK) {
1702d62bc4baSyz147064 		goto done;
1703d62bc4baSyz147064 	}
17047c478bd9Sstevel@tonic-gate 
1705d62bc4baSyz147064 	if (altroot != NULL)
1706d62bc4baSyz147064 		altroot_cmd(altroot, argc, argv);
1707d62bc4baSyz147064 
1708d62bc4baSyz147064 	for (n = 0; n < ndev; n++) {
17094ac67f02SAnurag S. Maskey 		if ((status = dladm_dev2linkid(handle, devs[n],
17104ac67f02SAnurag S. Maskey 		    &(port[n].lp_linkid))) != DLADM_STATUS_OK) {
17114ac67f02SAnurag S. Maskey 			die_dlerr(status, "invalid <dev> '%s'", devs[n]);
1712d62bc4baSyz147064 		}
1713d62bc4baSyz147064 	}
1714d62bc4baSyz147064 
1715d62bc4baSyz147064 	for (n = 0; n < nlink; n++) {
17164ac67f02SAnurag S. Maskey 		if ((status = dladm_name2info(handle, links[n],
17174ac67f02SAnurag S. Maskey 		    &port[n + ndev].lp_linkid, NULL, NULL, NULL)) !=
17184ac67f02SAnurag S. Maskey 		    DLADM_STATUS_OK) {
17194ac67f02SAnurag S. Maskey 			die_dlerr(status, "invalid <link> '%s'", links[n]);
1720d62bc4baSyz147064 		}
1721d62bc4baSyz147064 	}
1722d62bc4baSyz147064 
17234ac67f02SAnurag S. Maskey 	status = dladm_aggr_add(handle, linkid, ndev + nlink, port, flags);
1724d62bc4baSyz147064 done:
1725f595a68aSyz147064 	if (status != DLADM_STATUS_OK) {
1726219a2a31Shl157128 		/*
1727f595a68aSyz147064 		 * checking DLADM_STATUS_NOTSUP is a temporary workaround
1728219a2a31Shl157128 		 * and should be removed once 6399681 is fixed.
1729219a2a31Shl157128 		 */
1730f595a68aSyz147064 		if (status == DLADM_STATUS_NOTSUP) {
1731219a2a31Shl157128 			(void) fprintf(stderr,
1732219a2a31Shl157128 			    gettext("%s: add operation failed: %s\n"),
1733219a2a31Shl157128 			    progname,
1734d62bc4baSyz147064 			    gettext("link capabilities don't match"));
17354ac67f02SAnurag S. Maskey 			dladm_close(handle);
1736219a2a31Shl157128 			exit(ENOTSUP);
1737d62bc4baSyz147064 		} else if (status == DLADM_STATUS_NONOTIF) {
1738d62bc4baSyz147064 			die_dlerr(status, "not all links have link up/down "
1739d62bc4baSyz147064 			    "detection; must use -f (see dladm(1M))\n");
1740d62bc4baSyz147064 		} else {
1741f595a68aSyz147064 			die_dlerr(status, "add operation failed");
17427c478bd9Sstevel@tonic-gate 		}
17437c478bd9Sstevel@tonic-gate 	}
1744d62bc4baSyz147064 }
17457c478bd9Sstevel@tonic-gate 
17467c478bd9Sstevel@tonic-gate static void
17478d5c46e6Sam223141 do_remove_aggr(int argc, char *argv[], const char *use)
17487c478bd9Sstevel@tonic-gate {
17497c478bd9Sstevel@tonic-gate 	char				option;
1750f595a68aSyz147064 	dladm_aggr_port_attr_db_t	port[MAXPORT];
1751d62bc4baSyz147064 	uint_t				n, ndev, nlink;
1752d62bc4baSyz147064 	char				*devs[MAXPORT];
1753d62bc4baSyz147064 	char				*links[MAXPORT];
17547c478bd9Sstevel@tonic-gate 	char				*altroot = NULL;
1755d62bc4baSyz147064 	uint32_t			flags;
1756d62bc4baSyz147064 	datalink_id_t			linkid;
1757f595a68aSyz147064 	dladm_status_t			status;
17587c478bd9Sstevel@tonic-gate 
1759d62bc4baSyz147064 	flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
1760d62bc4baSyz147064 	ndev = nlink = opterr = 0;
1761d62bc4baSyz147064 	while ((option = getopt_long(argc, argv, ":d:l:R:t",
1762d62bc4baSyz147064 	    lopts, NULL)) != -1) {
17637c478bd9Sstevel@tonic-gate 		switch (option) {
17647c478bd9Sstevel@tonic-gate 		case 'd':
1765d62bc4baSyz147064 			if (ndev + nlink >= MAXPORT)
1766d62bc4baSyz147064 				die("too many ports specified");
17677c478bd9Sstevel@tonic-gate 
1768d62bc4baSyz147064 			devs[ndev++] = optarg;
1769d62bc4baSyz147064 			break;
1770d62bc4baSyz147064 		case 'l':
1771d62bc4baSyz147064 			if (ndev + nlink >= MAXPORT)
1772d62bc4baSyz147064 				die("too many ports specified");
177333343a97Smeem 
1774d62bc4baSyz147064 			links[nlink++] = optarg;
17757c478bd9Sstevel@tonic-gate 			break;
17767c478bd9Sstevel@tonic-gate 		case 't':
1777d62bc4baSyz147064 			flags &= ~DLADM_OPT_PERSIST;
17787c478bd9Sstevel@tonic-gate 			break;
17797c478bd9Sstevel@tonic-gate 		case 'R':
17807c478bd9Sstevel@tonic-gate 			altroot = optarg;
17817c478bd9Sstevel@tonic-gate 			break;
17827c478bd9Sstevel@tonic-gate 		default:
17838d5c46e6Sam223141 			die_opterr(optopt, option, use);
178433343a97Smeem 			break;
17857c478bd9Sstevel@tonic-gate 		}
17867c478bd9Sstevel@tonic-gate 	}
17877c478bd9Sstevel@tonic-gate 
1788d62bc4baSyz147064 	if (ndev + nlink == 0)
17897c478bd9Sstevel@tonic-gate 		usage();
17907c478bd9Sstevel@tonic-gate 
1791d62bc4baSyz147064 	/* get key value or the aggregation name (required last argument) */
17927c478bd9Sstevel@tonic-gate 	if (optind != (argc-1))
17937c478bd9Sstevel@tonic-gate 		usage();
17947c478bd9Sstevel@tonic-gate 
1795d62bc4baSyz147064 	status = i_dladm_aggr_get_linkid(altroot, argv[optind], &linkid, flags);
1796d62bc4baSyz147064 	if (status != DLADM_STATUS_OK)
1797d62bc4baSyz147064 		goto done;
17987c478bd9Sstevel@tonic-gate 
1799d62bc4baSyz147064 	if (altroot != NULL)
1800d62bc4baSyz147064 		altroot_cmd(altroot, argc, argv);
1801d62bc4baSyz147064 
1802d62bc4baSyz147064 	for (n = 0; n < ndev; n++) {
18034ac67f02SAnurag S. Maskey 		if ((status = dladm_dev2linkid(handle, devs[n],
18044ac67f02SAnurag S. Maskey 		    &(port[n].lp_linkid))) != DLADM_STATUS_OK) {
18054ac67f02SAnurag S. Maskey 			die_dlerr(status, "invalid <dev> '%s'", devs[n]);
1806d62bc4baSyz147064 		}
1807d62bc4baSyz147064 	}
1808d62bc4baSyz147064 
1809d62bc4baSyz147064 	for (n = 0; n < nlink; n++) {
18104ac67f02SAnurag S. Maskey 		if ((status = dladm_name2info(handle, links[n],
18114ac67f02SAnurag S. Maskey 		    &port[n + ndev].lp_linkid, NULL, NULL, NULL)) !=
18124ac67f02SAnurag S. Maskey 		    DLADM_STATUS_OK) {
18134ac67f02SAnurag S. Maskey 			die_dlerr(status, "invalid <link> '%s'", links[n]);
1814d62bc4baSyz147064 		}
1815d62bc4baSyz147064 	}
1816d62bc4baSyz147064 
18174ac67f02SAnurag S. Maskey 	status = dladm_aggr_remove(handle, linkid, ndev + nlink, port, flags);
1818d62bc4baSyz147064 done:
1819f595a68aSyz147064 	if (status != DLADM_STATUS_OK)
1820f595a68aSyz147064 		die_dlerr(status, "remove operation failed");
18217c478bd9Sstevel@tonic-gate }
18227c478bd9Sstevel@tonic-gate 
18237c478bd9Sstevel@tonic-gate static void
18248d5c46e6Sam223141 do_modify_aggr(int argc, char *argv[], const char *use)
18257c478bd9Sstevel@tonic-gate {
18267c478bd9Sstevel@tonic-gate 	char			option;
18277c478bd9Sstevel@tonic-gate 	uint32_t		policy = AGGR_POLICY_L4;
18287c478bd9Sstevel@tonic-gate 	aggr_lacp_mode_t	lacp_mode = AGGR_LACP_OFF;
18297c478bd9Sstevel@tonic-gate 	aggr_lacp_timer_t	lacp_timer = AGGR_LACP_TIMER_SHORT;
18307c478bd9Sstevel@tonic-gate 	uint8_t			mac_addr[ETHERADDRL];
18317c478bd9Sstevel@tonic-gate 	boolean_t		mac_addr_fixed = B_FALSE;
18327c478bd9Sstevel@tonic-gate 	uint8_t			modify_mask = 0;
18337c478bd9Sstevel@tonic-gate 	char			*altroot = NULL;
1834d62bc4baSyz147064 	uint32_t		flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
1835d62bc4baSyz147064 	datalink_id_t		linkid;
1836f595a68aSyz147064 	dladm_status_t		status;
18377c478bd9Sstevel@tonic-gate 
18387c478bd9Sstevel@tonic-gate 	opterr = 0;
1839d62bc4baSyz147064 	while ((option = getopt_long(argc, argv, ":L:l:P:R:tu:T:", lopts,
18407c478bd9Sstevel@tonic-gate 	    NULL)) != -1) {
18417c478bd9Sstevel@tonic-gate 		switch (option) {
18427c478bd9Sstevel@tonic-gate 		case 'P':
1843f595a68aSyz147064 			if (modify_mask & DLADM_AGGR_MODIFY_POLICY)
184433343a97Smeem 				die_optdup(option);
18457c478bd9Sstevel@tonic-gate 
1846f595a68aSyz147064 			modify_mask |= DLADM_AGGR_MODIFY_POLICY;
18477c478bd9Sstevel@tonic-gate 
1848f595a68aSyz147064 			if (!dladm_aggr_str2policy(optarg, &policy))
184933343a97Smeem 				die("invalid policy '%s'", optarg);
18507c478bd9Sstevel@tonic-gate 			break;
18517c478bd9Sstevel@tonic-gate 		case 'u':
1852f595a68aSyz147064 			if (modify_mask & DLADM_AGGR_MODIFY_MAC)
185333343a97Smeem 				die_optdup(option);
18547c478bd9Sstevel@tonic-gate 
1855f595a68aSyz147064 			modify_mask |= DLADM_AGGR_MODIFY_MAC;
18567c478bd9Sstevel@tonic-gate 
1857f595a68aSyz147064 			if (!dladm_aggr_str2macaddr(optarg, &mac_addr_fixed,
185833343a97Smeem 			    mac_addr))
185933343a97Smeem 				die("invalid MAC address '%s'", optarg);
18607c478bd9Sstevel@tonic-gate 			break;
18617c478bd9Sstevel@tonic-gate 		case 'l':
1862d62bc4baSyz147064 		case 'L':
1863f595a68aSyz147064 			if (modify_mask & DLADM_AGGR_MODIFY_LACP_MODE)
186433343a97Smeem 				die_optdup(option);
18657c478bd9Sstevel@tonic-gate 
1866f595a68aSyz147064 			modify_mask |= DLADM_AGGR_MODIFY_LACP_MODE;
18677c478bd9Sstevel@tonic-gate 
1868f595a68aSyz147064 			if (!dladm_aggr_str2lacpmode(optarg, &lacp_mode))
186933343a97Smeem 				die("invalid LACP mode '%s'", optarg);
18707c478bd9Sstevel@tonic-gate 			break;
18717c478bd9Sstevel@tonic-gate 		case 'T':
1872f595a68aSyz147064 			if (modify_mask & DLADM_AGGR_MODIFY_LACP_TIMER)
187333343a97Smeem 				die_optdup(option);
18747c478bd9Sstevel@tonic-gate 
1875f595a68aSyz147064 			modify_mask |= DLADM_AGGR_MODIFY_LACP_TIMER;
18767c478bd9Sstevel@tonic-gate 
1877f595a68aSyz147064 			if (!dladm_aggr_str2lacptimer(optarg, &lacp_timer))
187833343a97Smeem 				die("invalid LACP timer value '%s'", optarg);
18797c478bd9Sstevel@tonic-gate 			break;
18807c478bd9Sstevel@tonic-gate 		case 't':
1881d62bc4baSyz147064 			flags &= ~DLADM_OPT_PERSIST;
18827c478bd9Sstevel@tonic-gate 			break;
18837c478bd9Sstevel@tonic-gate 		case 'R':
18847c478bd9Sstevel@tonic-gate 			altroot = optarg;
18857c478bd9Sstevel@tonic-gate 			break;
18867c478bd9Sstevel@tonic-gate 		default:
18878d5c46e6Sam223141 			die_opterr(optopt, option, use);
188833343a97Smeem 			break;
18897c478bd9Sstevel@tonic-gate 		}
18907c478bd9Sstevel@tonic-gate 	}
18917c478bd9Sstevel@tonic-gate 
189233343a97Smeem 	if (modify_mask == 0)
189333343a97Smeem 		die("at least one of the -PulT options must be specified");
18947c478bd9Sstevel@tonic-gate 
1895d62bc4baSyz147064 	/* get key value or the aggregation name (required last argument) */
18967c478bd9Sstevel@tonic-gate 	if (optind != (argc-1))
18977c478bd9Sstevel@tonic-gate 		usage();
18987c478bd9Sstevel@tonic-gate 
1899d62bc4baSyz147064 	status = i_dladm_aggr_get_linkid(altroot, argv[optind], &linkid, flags);
1900d62bc4baSyz147064 	if (status != DLADM_STATUS_OK)
1901d62bc4baSyz147064 		goto done;
19027c478bd9Sstevel@tonic-gate 
1903d62bc4baSyz147064 	if (altroot != NULL)
1904d62bc4baSyz147064 		altroot_cmd(altroot, argc, argv);
1905d62bc4baSyz147064 
19064ac67f02SAnurag S. Maskey 	status = dladm_aggr_modify(handle, linkid, modify_mask, policy,
19074ac67f02SAnurag S. Maskey 	    mac_addr_fixed, (const uchar_t *)mac_addr, lacp_mode, lacp_timer,
19084ac67f02SAnurag S. Maskey 	    flags);
1909d62bc4baSyz147064 
1910d62bc4baSyz147064 done:
1911f595a68aSyz147064 	if (status != DLADM_STATUS_OK)
1912f595a68aSyz147064 		die_dlerr(status, "modify operation failed");
19137c478bd9Sstevel@tonic-gate }
19147c478bd9Sstevel@tonic-gate 
19158d5c46e6Sam223141 /*ARGSUSED*/
19167c478bd9Sstevel@tonic-gate static void
19178d5c46e6Sam223141 do_up_aggr(int argc, char *argv[], const char *use)
19187c478bd9Sstevel@tonic-gate {
1919d62bc4baSyz147064 	datalink_id_t	linkid = DATALINK_ALL_LINKID;
1920f595a68aSyz147064 	dladm_status_t	status;
19217c478bd9Sstevel@tonic-gate 
1922d62bc4baSyz147064 	/*
1923d62bc4baSyz147064 	 * get the key or the name of the aggregation (optional last argument)
1924d62bc4baSyz147064 	 */
19257c478bd9Sstevel@tonic-gate 	if (argc == 2) {
1926d62bc4baSyz147064 		if ((status = i_dladm_aggr_get_linkid(NULL, argv[1], &linkid,
19274ac67f02SAnurag S. Maskey 		    DLADM_OPT_PERSIST)) != DLADM_STATUS_OK)
1928d62bc4baSyz147064 			goto done;
19297c478bd9Sstevel@tonic-gate 	} else if (argc > 2) {
19307c478bd9Sstevel@tonic-gate 		usage();
19317c478bd9Sstevel@tonic-gate 	}
19327c478bd9Sstevel@tonic-gate 
19334ac67f02SAnurag S. Maskey 	status = dladm_aggr_up(handle, linkid);
1934d62bc4baSyz147064 done:
1935d62bc4baSyz147064 	if (status != DLADM_STATUS_OK) {
1936d62bc4baSyz147064 		if (argc == 2) {
1937d62bc4baSyz147064 			die_dlerr(status,
1938d62bc4baSyz147064 			    "could not bring up aggregation '%s'", argv[1]);
19397c478bd9Sstevel@tonic-gate 		} else {
1940f595a68aSyz147064 			die_dlerr(status, "could not bring aggregations up");
19417c478bd9Sstevel@tonic-gate 		}
19427c478bd9Sstevel@tonic-gate 	}
19437c478bd9Sstevel@tonic-gate }
19447c478bd9Sstevel@tonic-gate 
19457c478bd9Sstevel@tonic-gate static void
19468d5c46e6Sam223141 do_create_vlan(int argc, char *argv[], const char *use)
19477c478bd9Sstevel@tonic-gate {
1948d62bc4baSyz147064 	char			*link = NULL;
1949d62bc4baSyz147064 	char			drv[DLPI_LINKNAME_MAX];
1950d62bc4baSyz147064 	uint_t			ppa;
1951d62bc4baSyz147064 	datalink_id_t		linkid;
1952da14cebeSEric Cheng 	datalink_id_t		dev_linkid;
1953d62bc4baSyz147064 	int			vid = 0;
1954d62bc4baSyz147064 	char			option;
1955d62bc4baSyz147064 	uint32_t		flags = (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST);
1956d62bc4baSyz147064 	char			*altroot = NULL;
1957d62bc4baSyz147064 	char			vlan[MAXLINKNAMELEN];
1958*63a6526dSMichael Lim 	char			propstr[DLADM_STRSIZE];
1959da14cebeSEric Cheng 	dladm_arg_list_t	*proplist = NULL;
1960f595a68aSyz147064 	dladm_status_t		status;
19617c478bd9Sstevel@tonic-gate 
1962d62bc4baSyz147064 	opterr = 0;
1963*63a6526dSMichael Lim 	bzero(propstr, DLADM_STRSIZE);
1964*63a6526dSMichael Lim 
1965da14cebeSEric Cheng 	while ((option = getopt_long(argc, argv, ":tfR:l:v:p:",
1966d62bc4baSyz147064 	    lopts, NULL)) != -1) {
1967d62bc4baSyz147064 		switch (option) {
1968d62bc4baSyz147064 		case 'v':
1969d62bc4baSyz147064 			if (vid != 0)
1970d62bc4baSyz147064 				die_optdup(option);
1971d62bc4baSyz147064 
1972d62bc4baSyz147064 			if (!str2int(optarg, &vid) || vid < 1 || vid > 4094)
1973d62bc4baSyz147064 				die("invalid VLAN identifier '%s'", optarg);
1974d62bc4baSyz147064 
1975d62bc4baSyz147064 			break;
1976d62bc4baSyz147064 		case 'l':
1977d62bc4baSyz147064 			if (link != NULL)
1978d62bc4baSyz147064 				die_optdup(option);
1979d62bc4baSyz147064 
1980d62bc4baSyz147064 			link = optarg;
1981d62bc4baSyz147064 			break;
1982d62bc4baSyz147064 		case 't':
1983d62bc4baSyz147064 			flags &= ~DLADM_OPT_PERSIST;
1984d62bc4baSyz147064 			break;
1985d62bc4baSyz147064 		case 'R':
1986d62bc4baSyz147064 			altroot = optarg;
1987d62bc4baSyz147064 			break;
1988da14cebeSEric Cheng 		case 'p':
1989*63a6526dSMichael Lim 			(void) strlcat(propstr, optarg, DLADM_STRSIZE);
1990*63a6526dSMichael Lim 			if (strlcat(propstr, ",", DLADM_STRSIZE) >=
1991*63a6526dSMichael Lim 			    DLADM_STRSIZE)
1992*63a6526dSMichael Lim 				die("property list too long '%s'", propstr);
1993da14cebeSEric Cheng 			break;
1994da14cebeSEric Cheng 		case 'f':
1995da14cebeSEric Cheng 			flags |= DLADM_OPT_FORCE;
1996da14cebeSEric Cheng 			break;
1997d62bc4baSyz147064 		default:
19988d5c46e6Sam223141 			die_opterr(optopt, option, use);
1999d62bc4baSyz147064 			break;
2000d62bc4baSyz147064 		}
2001d62bc4baSyz147064 	}
2002d62bc4baSyz147064 
2003d62bc4baSyz147064 	/* get vlan name if there is any */
2004d62bc4baSyz147064 	if ((vid == 0) || (link == NULL) || (argc - optind > 1))
20057c478bd9Sstevel@tonic-gate 		usage();
2006d62bc4baSyz147064 
2007d62bc4baSyz147064 	if (optind == (argc - 1)) {
2008d62bc4baSyz147064 		if (strlcpy(vlan, argv[optind], MAXLINKNAMELEN) >=
2009d62bc4baSyz147064 		    MAXLINKNAMELEN) {
2010d62bc4baSyz147064 			die("vlan name too long '%s'", argv[optind]);
2011d62bc4baSyz147064 		}
2012d62bc4baSyz147064 	} else {
2013d62bc4baSyz147064 		if ((dlpi_parselink(link, drv, &ppa) != DLPI_SUCCESS) ||
2014d62bc4baSyz147064 		    (ppa >= 1000) ||
2015d62bc4baSyz147064 		    (dlpi_makelink(vlan, drv, vid * 1000 + ppa) !=
2016d62bc4baSyz147064 		    DLPI_SUCCESS)) {
2017d62bc4baSyz147064 			die("invalid link name '%s'", link);
2018d62bc4baSyz147064 		}
20197c478bd9Sstevel@tonic-gate 	}
20207c478bd9Sstevel@tonic-gate 
2021d62bc4baSyz147064 	if (altroot != NULL)
2022d62bc4baSyz147064 		altroot_cmd(altroot, argc, argv);
2023d62bc4baSyz147064 
20244ac67f02SAnurag S. Maskey 	if (dladm_name2info(handle, link, &dev_linkid, NULL, NULL, NULL) !=
2025d62bc4baSyz147064 	    DLADM_STATUS_OK) {
2026d62bc4baSyz147064 		die("invalid link name '%s'", link);
2027d62bc4baSyz147064 	}
2028d62bc4baSyz147064 
2029*63a6526dSMichael Lim 	if (dladm_parse_link_props(propstr, &proplist, B_FALSE)
2030*63a6526dSMichael Lim 	    != DLADM_STATUS_OK)
2031*63a6526dSMichael Lim 		die("invalid vlan property");
2032*63a6526dSMichael Lim 
20334ac67f02SAnurag S. Maskey 	if ((status = dladm_vlan_create(handle, vlan, dev_linkid, vid, proplist,
20344ac67f02SAnurag S. Maskey 	    flags, &linkid)) != DLADM_STATUS_OK) {
2035da14cebeSEric Cheng 		die_dlerr(status, "create operation over %s failed", link);
2036d62bc4baSyz147064 	}
2037d62bc4baSyz147064 }
2038d62bc4baSyz147064 
2039d62bc4baSyz147064 static void
20408d5c46e6Sam223141 do_delete_vlan(int argc, char *argv[], const char *use)
2041d62bc4baSyz147064 {
2042d62bc4baSyz147064 	char		option;
2043d62bc4baSyz147064 	uint32_t	flags = (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST);
2044d62bc4baSyz147064 	char		*altroot = NULL;
2045d62bc4baSyz147064 	datalink_id_t	linkid;
2046d62bc4baSyz147064 	dladm_status_t	status;
2047d62bc4baSyz147064 
2048d62bc4baSyz147064 	opterr = 0;
2049d62bc4baSyz147064 	while ((option = getopt_long(argc, argv, ":R:t", lopts, NULL)) != -1) {
2050d62bc4baSyz147064 		switch (option) {
2051d62bc4baSyz147064 		case 't':
2052d62bc4baSyz147064 			flags &= ~DLADM_OPT_PERSIST;
2053d62bc4baSyz147064 			break;
2054d62bc4baSyz147064 		case 'R':
2055d62bc4baSyz147064 			altroot = optarg;
2056d62bc4baSyz147064 			break;
2057d62bc4baSyz147064 		default:
20588d5c46e6Sam223141 			die_opterr(optopt, option, use);
2059d62bc4baSyz147064 			break;
2060d62bc4baSyz147064 		}
2061d62bc4baSyz147064 	}
2062d62bc4baSyz147064 
2063d62bc4baSyz147064 	/* get VLAN link name (required last argument) */
2064d62bc4baSyz147064 	if (optind != (argc - 1))
2065d62bc4baSyz147064 		usage();
2066d62bc4baSyz147064 
2067d62bc4baSyz147064 	if (altroot != NULL)
2068d62bc4baSyz147064 		altroot_cmd(altroot, argc, argv);
2069d62bc4baSyz147064 
20704ac67f02SAnurag S. Maskey 	status = dladm_name2info(handle, argv[optind], &linkid, NULL, NULL,
20714ac67f02SAnurag S. Maskey 	    NULL);
2072d62bc4baSyz147064 	if (status != DLADM_STATUS_OK)
2073d62bc4baSyz147064 		goto done;
2074d62bc4baSyz147064 
20754ac67f02SAnurag S. Maskey 	status = dladm_vlan_delete(handle, linkid, flags);
2076d62bc4baSyz147064 done:
2077d62bc4baSyz147064 	if (status != DLADM_STATUS_OK)
2078d62bc4baSyz147064 		die_dlerr(status, "delete operation failed");
2079d62bc4baSyz147064 }
2080d62bc4baSyz147064 
20818d5c46e6Sam223141 /*ARGSUSED*/
2082d62bc4baSyz147064 static void
20838d5c46e6Sam223141 do_up_vlan(int argc, char *argv[], const char *use)
2084d62bc4baSyz147064 {
2085da14cebeSEric Cheng 	do_up_vnic_common(argc, argv, use, B_TRUE);
20867c478bd9Sstevel@tonic-gate }
20877c478bd9Sstevel@tonic-gate 
2088210db224Sericheng static void
20898d5c46e6Sam223141 do_rename_link(int argc, char *argv[], const char *use)
2090210db224Sericheng {
2091d62bc4baSyz147064 	char		option;
2092d62bc4baSyz147064 	char		*link1, *link2;
2093d62bc4baSyz147064 	char		*altroot = NULL;
2094d62bc4baSyz147064 	dladm_status_t	status;
2095210db224Sericheng 
2096d62bc4baSyz147064 	opterr = 0;
2097d62bc4baSyz147064 	while ((option = getopt_long(argc, argv, ":R:", lopts, NULL)) != -1) {
2098d62bc4baSyz147064 		switch (option) {
2099d62bc4baSyz147064 		case 'R':
2100d62bc4baSyz147064 			altroot = optarg;
2101d62bc4baSyz147064 			break;
2102d62bc4baSyz147064 		default:
21038d5c46e6Sam223141 			die_opterr(optopt, option, use);
2104d62bc4baSyz147064 			break;
2105210db224Sericheng 		}
2106210db224Sericheng 	}
2107210db224Sericheng 
2108d62bc4baSyz147064 	/* get link1 and link2 name (required the last 2 arguments) */
2109d62bc4baSyz147064 	if (optind != (argc - 2))
2110d62bc4baSyz147064 		usage();
2111d62bc4baSyz147064 
2112d62bc4baSyz147064 	if (altroot != NULL)
2113d62bc4baSyz147064 		altroot_cmd(altroot, argc, argv);
2114d62bc4baSyz147064 
2115d62bc4baSyz147064 	link1 = argv[optind++];
2116d62bc4baSyz147064 	link2 = argv[optind];
21174ac67f02SAnurag S. Maskey 	if ((status = dladm_rename_link(handle, link1, link2)) !=
21184ac67f02SAnurag S. Maskey 	    DLADM_STATUS_OK)
2119d62bc4baSyz147064 		die_dlerr(status, "rename operation failed");
2120d62bc4baSyz147064 }
2121d62bc4baSyz147064 
21228d5c46e6Sam223141 /*ARGSUSED*/
2123d62bc4baSyz147064 static void
21248d5c46e6Sam223141 do_delete_phys(int argc, char *argv[], const char *use)
2125d62bc4baSyz147064 {
2126d62bc4baSyz147064 	datalink_id_t	linkid = DATALINK_ALL_LINKID;
2127d62bc4baSyz147064 	dladm_status_t	status;
2128d62bc4baSyz147064 
2129d62bc4baSyz147064 	/* get link name (required the last argument) */
2130d62bc4baSyz147064 	if (argc > 2)
2131d62bc4baSyz147064 		usage();
2132d62bc4baSyz147064 
2133d62bc4baSyz147064 	if (argc == 2) {
21344ac67f02SAnurag S. Maskey 		if ((status = dladm_name2info(handle, argv[1], &linkid, NULL,
21354ac67f02SAnurag S. Maskey 		    NULL, NULL)) != DLADM_STATUS_OK)
2136d62bc4baSyz147064 			die_dlerr(status, "cannot delete '%s'", argv[1]);
2137d62bc4baSyz147064 	}
2138d62bc4baSyz147064 
21394ac67f02SAnurag S. Maskey 	if ((status = dladm_phys_delete(handle, linkid)) != DLADM_STATUS_OK) {
2140d62bc4baSyz147064 		if (argc == 2)
2141d62bc4baSyz147064 			die_dlerr(status, "cannot delete '%s'", argv[1]);
2142d62bc4baSyz147064 		else
2143d62bc4baSyz147064 			die_dlerr(status, "delete operation failed");
2144d62bc4baSyz147064 	}
2145d62bc4baSyz147064 }
2146d62bc4baSyz147064 
2147d62bc4baSyz147064 /*ARGSUSED*/
2148210db224Sericheng static int
21494ac67f02SAnurag S. Maskey i_dladm_walk_linkmap(dladm_handle_t dh, datalink_id_t linkid, void *arg)
2150210db224Sericheng {
2151d62bc4baSyz147064 	char			name[MAXLINKNAMELEN];
2152d62bc4baSyz147064 	char			mediabuf[DLADM_STRSIZE];
2153d62bc4baSyz147064 	char			classbuf[DLADM_STRSIZE];
2154d62bc4baSyz147064 	datalink_class_t	class;
2155d62bc4baSyz147064 	uint32_t		media;
2156d62bc4baSyz147064 	uint32_t		flags;
2157210db224Sericheng 
21584ac67f02SAnurag S. Maskey 	if (dladm_datalink_id2info(dh, linkid, &flags, &class, &media, name,
2159d62bc4baSyz147064 	    MAXLINKNAMELEN) == DLADM_STATUS_OK) {
2160d62bc4baSyz147064 		(void) dladm_class2str(class, classbuf);
2161d62bc4baSyz147064 		(void) dladm_media2str(media, mediabuf);
2162d62bc4baSyz147064 		(void) printf("%-12s%8d  %-12s%-20s %6d\n", name,
2163d62bc4baSyz147064 		    linkid, classbuf, mediabuf, flags);
2164210db224Sericheng 	}
2165d62bc4baSyz147064 	return (DLADM_WALK_CONTINUE);
2166210db224Sericheng }
21677c478bd9Sstevel@tonic-gate 
21687c478bd9Sstevel@tonic-gate /*ARGSUSED*/
21697c478bd9Sstevel@tonic-gate static void
21708d5c46e6Sam223141 do_show_linkmap(int argc, char *argv[], const char *use)
21717c478bd9Sstevel@tonic-gate {
2172d62bc4baSyz147064 	if (argc != 1)
2173d62bc4baSyz147064 		die("invalid arguments");
21747c478bd9Sstevel@tonic-gate 
2175d62bc4baSyz147064 	(void) printf("%-12s%8s  %-12s%-20s %6s\n", "NAME", "LINKID",
2176d62bc4baSyz147064 	    "CLASS", "MEDIA", "FLAGS");
21774ac67f02SAnurag S. Maskey 
21784ac67f02SAnurag S. Maskey 	(void) dladm_walk_datalink_id(i_dladm_walk_linkmap, handle, NULL,
2179d62bc4baSyz147064 	    DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE,
2180d62bc4baSyz147064 	    DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST);
21817c478bd9Sstevel@tonic-gate }
2182d62bc4baSyz147064 
2183d62bc4baSyz147064 /*
2184d62bc4baSyz147064  * Delete inactive physical links.
2185d62bc4baSyz147064  */
2186d62bc4baSyz147064 /*ARGSUSED*/
2187d62bc4baSyz147064 static int
21884ac67f02SAnurag S. Maskey purge_phys(dladm_handle_t dh, datalink_id_t linkid, void *arg)
2189d62bc4baSyz147064 {
2190d62bc4baSyz147064 	datalink_class_t	class;
2191d62bc4baSyz147064 	uint32_t		flags;
2192d62bc4baSyz147064 
21934ac67f02SAnurag S. Maskey 	if (dladm_datalink_id2info(dh, linkid, &flags, &class, NULL, NULL, 0)
21944ac67f02SAnurag S. Maskey 	    != DLADM_STATUS_OK) {
2195d62bc4baSyz147064 		return (DLADM_WALK_CONTINUE);
2196d62bc4baSyz147064 	}
2197d62bc4baSyz147064 
2198d62bc4baSyz147064 	if (class == DATALINK_CLASS_PHYS && !(flags & DLADM_OPT_ACTIVE))
21994ac67f02SAnurag S. Maskey 		(void) dladm_phys_delete(dh, linkid);
2200d62bc4baSyz147064 
2201d62bc4baSyz147064 	return (DLADM_WALK_CONTINUE);
2202d62bc4baSyz147064 }
2203d62bc4baSyz147064 
2204d62bc4baSyz147064 /*ARGSUSED*/
2205d62bc4baSyz147064 static void
22068d5c46e6Sam223141 do_init_phys(int argc, char *argv[], const char *use)
2207d62bc4baSyz147064 {
2208d62bc4baSyz147064 	di_node_t	devtree;
2209d62bc4baSyz147064 
2210d62bc4baSyz147064 	if (argc > 1)
2211d62bc4baSyz147064 		usage();
2212d62bc4baSyz147064 
2213d62bc4baSyz147064 	/*
2214d62bc4baSyz147064 	 * Force all the devices to attach, therefore all the network physical
2215d62bc4baSyz147064 	 * devices can be known to the dlmgmtd daemon.
2216d62bc4baSyz147064 	 */
2217d62bc4baSyz147064 	if ((devtree = di_init("/", DINFOFORCE | DINFOSUBTREE)) != DI_NODE_NIL)
2218d62bc4baSyz147064 		di_fini(devtree);
2219d62bc4baSyz147064 
22204ac67f02SAnurag S. Maskey 	(void) dladm_walk_datalink_id(purge_phys, handle, NULL,
2221d62bc4baSyz147064 	    DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST);
22227c478bd9Sstevel@tonic-gate }
22237c478bd9Sstevel@tonic-gate 
2224d62bc4baSyz147064 
2225d62bc4baSyz147064 /*
2226d62bc4baSyz147064  * Print the active topology information.
2227d62bc4baSyz147064  */
2228d62bc4baSyz147064 static dladm_status_t
2229d62bc4baSyz147064 print_link_topology(show_state_t *state, datalink_id_t linkid,
2230e7801d59Ssowmini     datalink_class_t class, link_fields_buf_t *lbuf)
2231d62bc4baSyz147064 {
2232d62bc4baSyz147064 	uint32_t	flags = state->ls_flags;
2233d62bc4baSyz147064 	dladm_status_t	status = DLADM_STATUS_OK;
22346b9e797cSsowmini 	char		tmpbuf[MAXLINKNAMELEN];
2235d62bc4baSyz147064 
2236e7801d59Ssowmini 	if (!state->ls_parseable)
2237e7801d59Ssowmini 		(void) sprintf(lbuf->link_over, STR_UNDEF_VAL);
2238d62bc4baSyz147064 	else
2239e7801d59Ssowmini 		(void) sprintf(lbuf->link_over, "");
2240d62bc4baSyz147064 
2241d62bc4baSyz147064 	if (class == DATALINK_CLASS_VLAN) {
2242d62bc4baSyz147064 		dladm_vlan_attr_t	vinfo;
2243d62bc4baSyz147064 
22444ac67f02SAnurag S. Maskey 		status = dladm_vlan_info(handle, linkid, &vinfo, flags);
2245d62bc4baSyz147064 		if (status != DLADM_STATUS_OK)
2246d62bc4baSyz147064 			goto done;
22474ac67f02SAnurag S. Maskey 		status = dladm_datalink_id2info(handle, vinfo.dv_linkid, NULL,
22484ac67f02SAnurag S. Maskey 		    NULL, NULL, lbuf->link_over, sizeof (lbuf->link_over));
2249d62bc4baSyz147064 		if (status != DLADM_STATUS_OK)
2250d62bc4baSyz147064 			goto done;
2251d62bc4baSyz147064 	} else if (class == DATALINK_CLASS_AGGR) {
2252d62bc4baSyz147064 		dladm_aggr_grp_attr_t	ginfo;
2253d62bc4baSyz147064 		int			i;
2254d62bc4baSyz147064 
22556b9e797cSsowmini 		(void) sprintf(lbuf->link_over, "");
22566b9e797cSsowmini 
22574ac67f02SAnurag S. Maskey 		status = dladm_aggr_info(handle, linkid, &ginfo, flags);
2258d62bc4baSyz147064 		if (status != DLADM_STATUS_OK)
2259d62bc4baSyz147064 			goto done;
2260d62bc4baSyz147064 
2261d62bc4baSyz147064 		if (ginfo.lg_nports == 0) {
2262d62bc4baSyz147064 			status = DLADM_STATUS_BADVAL;
2263d62bc4baSyz147064 			goto done;
2264d62bc4baSyz147064 		}
2265d62bc4baSyz147064 		for (i = 0; i < ginfo.lg_nports; i++) {
22664ac67f02SAnurag S. Maskey 			status = dladm_datalink_id2info(handle,
2267e7801d59Ssowmini 			    ginfo.lg_ports[i].lp_linkid, NULL, NULL, NULL,
22686b9e797cSsowmini 			    tmpbuf, sizeof (tmpbuf));
2269d62bc4baSyz147064 			if (status != DLADM_STATUS_OK) {
2270d62bc4baSyz147064 				free(ginfo.lg_ports);
2271d62bc4baSyz147064 				goto done;
2272d62bc4baSyz147064 			}
22736b9e797cSsowmini 			(void) strlcat(lbuf->link_over, tmpbuf,
22746b9e797cSsowmini 			    sizeof (lbuf->link_over));
22756b9e797cSsowmini 			if (i != (ginfo.lg_nports - 1)) {
22766b9e797cSsowmini 				(void) strlcat(lbuf->link_over, " ",
22776b9e797cSsowmini 				    sizeof (lbuf->link_over));
22786b9e797cSsowmini 			}
2279d62bc4baSyz147064 		}
2280d62bc4baSyz147064 		free(ginfo.lg_ports);
2281d62bc4baSyz147064 	} else if (class == DATALINK_CLASS_VNIC) {
2282da14cebeSEric Cheng 		dladm_vnic_attr_t	vinfo;
2283d62bc4baSyz147064 
22844ac67f02SAnurag S. Maskey 		if ((status = dladm_vnic_info(handle, linkid, &vinfo, flags)) !=
22854ac67f02SAnurag S. Maskey 		    DLADM_STATUS_OK ||
22864ac67f02SAnurag S. Maskey 		    (status = dladm_datalink_id2info(handle, vinfo.va_link_id,
22874ac67f02SAnurag S. Maskey 		    NULL, NULL, NULL, lbuf->link_over,
2288e7801d59Ssowmini 		    sizeof (lbuf->link_over)) != DLADM_STATUS_OK)) {
2289d62bc4baSyz147064 			goto done;
2290d62bc4baSyz147064 		}
2291d62bc4baSyz147064 	}
2292d62bc4baSyz147064 done:
2293d62bc4baSyz147064 	return (status);
2294d62bc4baSyz147064 }
2295d62bc4baSyz147064 
2296d62bc4baSyz147064 static dladm_status_t
2297e7801d59Ssowmini print_link(show_state_t *state, datalink_id_t linkid, link_fields_buf_t *lbuf)
2298d62bc4baSyz147064 {
2299d62bc4baSyz147064 	char			link[MAXLINKNAMELEN];
2300d62bc4baSyz147064 	datalink_class_t	class;
2301d62bc4baSyz147064 	uint_t			mtu;
2302d62bc4baSyz147064 	uint32_t		flags;
2303d62bc4baSyz147064 	dladm_status_t		status;
2304d62bc4baSyz147064 
23054ac67f02SAnurag S. Maskey 	if ((status = dladm_datalink_id2info(handle, linkid, &flags, &class,
23064ac67f02SAnurag S. Maskey 	    NULL, link, sizeof (link))) != DLADM_STATUS_OK) {
2307d62bc4baSyz147064 		goto done;
2308d62bc4baSyz147064 	}
2309d62bc4baSyz147064 
2310d62bc4baSyz147064 	if (!(state->ls_flags & flags)) {
2311d62bc4baSyz147064 		status = DLADM_STATUS_NOTFOUND;
2312d62bc4baSyz147064 		goto done;
2313d62bc4baSyz147064 	}
2314d62bc4baSyz147064 
2315d62bc4baSyz147064 	if (state->ls_flags == DLADM_OPT_ACTIVE) {
2316d62bc4baSyz147064 		dladm_attr_t	dlattr;
2317d62bc4baSyz147064 
2318d62bc4baSyz147064 		if (class == DATALINK_CLASS_PHYS) {
2319d62bc4baSyz147064 			dladm_phys_attr_t	dpa;
2320d62bc4baSyz147064 			dlpi_handle_t		dh;
2321d62bc4baSyz147064 			dlpi_info_t		dlinfo;
2322d62bc4baSyz147064 
23234ac67f02SAnurag S. Maskey 			if ((status = dladm_phys_info(handle, linkid, &dpa,
2324d62bc4baSyz147064 			    DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) {
2325d62bc4baSyz147064 				goto done;
2326d62bc4baSyz147064 			}
2327d62bc4baSyz147064 
2328d62bc4baSyz147064 			if (!dpa.dp_novanity)
2329d62bc4baSyz147064 				goto link_mtu;
2330d62bc4baSyz147064 
2331d62bc4baSyz147064 			/*
2332d62bc4baSyz147064 			 * This is a physical link that does not have
2333d62bc4baSyz147064 			 * vanity naming support.
2334d62bc4baSyz147064 			 */
2335d62bc4baSyz147064 			if (dlpi_open(dpa.dp_dev, &dh, DLPI_DEVONLY) !=
2336d62bc4baSyz147064 			    DLPI_SUCCESS) {
2337d62bc4baSyz147064 				status = DLADM_STATUS_NOTFOUND;
2338d62bc4baSyz147064 				goto done;
2339d62bc4baSyz147064 			}
2340d62bc4baSyz147064 
2341d62bc4baSyz147064 			if (dlpi_info(dh, &dlinfo, 0) != DLPI_SUCCESS) {
2342d62bc4baSyz147064 				dlpi_close(dh);
2343d62bc4baSyz147064 				status = DLADM_STATUS_BADARG;
2344d62bc4baSyz147064 				goto done;
2345d62bc4baSyz147064 			}
2346d62bc4baSyz147064 
2347d62bc4baSyz147064 			dlpi_close(dh);
2348d62bc4baSyz147064 			mtu = dlinfo.di_max_sdu;
2349d62bc4baSyz147064 		} else {
2350d62bc4baSyz147064 link_mtu:
23514ac67f02SAnurag S. Maskey 			status = dladm_info(handle, linkid, &dlattr);
2352d62bc4baSyz147064 			if (status != DLADM_STATUS_OK)
2353d62bc4baSyz147064 				goto done;
2354d62bc4baSyz147064 			mtu = dlattr.da_max_sdu;
2355d62bc4baSyz147064 		}
2356d62bc4baSyz147064 	}
2357d62bc4baSyz147064 
2358e7801d59Ssowmini 	(void) snprintf(lbuf->link_name, sizeof (lbuf->link_name),
2359e7801d59Ssowmini 	    "%s", link);
2360e7801d59Ssowmini 	(void) dladm_class2str(class, lbuf->link_class);
2361d62bc4baSyz147064 	if (state->ls_flags == DLADM_OPT_ACTIVE) {
2362e7801d59Ssowmini 		(void) snprintf(lbuf->link_mtu, sizeof (lbuf->link_mtu),
2363c08e5e1aSdr146992 		    "%u", mtu);
2364e7801d59Ssowmini 		(void) get_linkstate(link, B_TRUE, lbuf->link_state);
2365d62bc4baSyz147064 	}
2366d62bc4baSyz147064 
2367e7801d59Ssowmini 	status = print_link_topology(state, linkid, class, lbuf);
2368d62bc4baSyz147064 	if (status != DLADM_STATUS_OK)
2369d62bc4baSyz147064 		goto done;
2370d62bc4baSyz147064 
2371d62bc4baSyz147064 done:
2372d62bc4baSyz147064 	return (status);
2373d62bc4baSyz147064 }
2374d62bc4baSyz147064 
23754ac67f02SAnurag S. Maskey /* ARGSUSED */
2376d62bc4baSyz147064 static int
23774ac67f02SAnurag S. Maskey show_link(dladm_handle_t dh, datalink_id_t linkid, void *arg)
2378d62bc4baSyz147064 {
2379e7801d59Ssowmini 	show_state_t		*state = (show_state_t *)arg;
2380d62bc4baSyz147064 	dladm_status_t		status;
2381e7801d59Ssowmini 	link_fields_buf_t	lbuf;
2382d62bc4baSyz147064 
2383e7801d59Ssowmini 	/*
2384e7801d59Ssowmini 	 * first get all the link attributes into lbuf;
2385e7801d59Ssowmini 	 */
23865f5c9f54SAnurag S. Maskey 	bzero(&lbuf, sizeof (link_fields_buf_t));
2387e7801d59Ssowmini 	status = print_link(state, linkid, &lbuf);
2388e7801d59Ssowmini 
2389d62bc4baSyz147064 	if (status != DLADM_STATUS_OK)
2390d62bc4baSyz147064 		goto done;
2391e7801d59Ssowmini 
2392e7801d59Ssowmini 	if (!state->ls_parseable && !state->ls_printheader) {
2393e7801d59Ssowmini 		print_header(&state->ls_print);
2394e7801d59Ssowmini 		state->ls_printheader = B_TRUE;
2395e7801d59Ssowmini 	}
2396e7801d59Ssowmini 
2397e7801d59Ssowmini 	dladm_print_output(&state->ls_print, state->ls_parseable,
2398e7801d59Ssowmini 	    dladm_print_field, (void *)&lbuf);
2399d62bc4baSyz147064 
2400d62bc4baSyz147064 done:
2401d62bc4baSyz147064 	state->ls_status = status;
2402d62bc4baSyz147064 	return (DLADM_WALK_CONTINUE);
2403d62bc4baSyz147064 }
2404d62bc4baSyz147064 
2405ae6aa22aSVenugopal Iyer static char *
2406ae6aa22aSVenugopal Iyer print_link_stats(print_field_t *pf, void *arg)
2407ae6aa22aSVenugopal Iyer {
2408ae6aa22aSVenugopal Iyer 	link_args_t *largs = arg;
2409ae6aa22aSVenugopal Iyer 	pktsum_t *diff_stats = largs->link_s_psum;
2410ae6aa22aSVenugopal Iyer 	static char buf[DLADM_STRSIZE];
2411ae6aa22aSVenugopal Iyer 
2412ae6aa22aSVenugopal Iyer 	switch (pf->pf_index) {
2413ae6aa22aSVenugopal Iyer 	case LINK_S_LINK:
2414ae6aa22aSVenugopal Iyer 		(void) snprintf(buf, sizeof (buf), "%s", largs->link_s_link);
2415ae6aa22aSVenugopal Iyer 		break;
2416ae6aa22aSVenugopal Iyer 	case LINK_S_IPKTS:
2417ae6aa22aSVenugopal Iyer 		(void) snprintf(buf, sizeof (buf), "%llu",
2418ae6aa22aSVenugopal Iyer 		    diff_stats->ipackets);
2419ae6aa22aSVenugopal Iyer 		break;
2420ae6aa22aSVenugopal Iyer 	case LINK_S_RBYTES:
2421ae6aa22aSVenugopal Iyer 		(void) snprintf(buf, sizeof (buf), "%llu",
2422ae6aa22aSVenugopal Iyer 		    diff_stats->rbytes);
2423ae6aa22aSVenugopal Iyer 		break;
2424ae6aa22aSVenugopal Iyer 	case LINK_S_IERRORS:
2425ae6aa22aSVenugopal Iyer 		(void) snprintf(buf, sizeof (buf), "%u",
2426ae6aa22aSVenugopal Iyer 		    diff_stats->ierrors);
2427ae6aa22aSVenugopal Iyer 		break;
2428ae6aa22aSVenugopal Iyer 	case LINK_S_OPKTS:
2429ae6aa22aSVenugopal Iyer 		(void) snprintf(buf, sizeof (buf), "%llu",
2430ae6aa22aSVenugopal Iyer 		    diff_stats->opackets);
2431ae6aa22aSVenugopal Iyer 		break;
2432ae6aa22aSVenugopal Iyer 	case LINK_S_OBYTES:
2433ae6aa22aSVenugopal Iyer 		(void) snprintf(buf, sizeof (buf), "%llu",
2434ae6aa22aSVenugopal Iyer 		    diff_stats->obytes);
2435ae6aa22aSVenugopal Iyer 		break;
2436ae6aa22aSVenugopal Iyer 	case LINK_S_OERRORS:
2437ae6aa22aSVenugopal Iyer 		(void) snprintf(buf, sizeof (buf), "%u",
2438ae6aa22aSVenugopal Iyer 		    diff_stats->oerrors);
2439ae6aa22aSVenugopal Iyer 		break;
2440ae6aa22aSVenugopal Iyer 	default:
2441ae6aa22aSVenugopal Iyer 		die("invalid input");
2442ae6aa22aSVenugopal Iyer 		break;
2443ae6aa22aSVenugopal Iyer 	}
2444ae6aa22aSVenugopal Iyer 	return (buf);
2445ae6aa22aSVenugopal Iyer }
2446ae6aa22aSVenugopal Iyer 
2447d62bc4baSyz147064 static int
24484ac67f02SAnurag S. Maskey show_link_stats(dladm_handle_t dh, datalink_id_t linkid, void *arg)
2449d62bc4baSyz147064 {
2450e7801d59Ssowmini 	char			link[DLPI_LINKNAME_MAX];
2451d62bc4baSyz147064 	datalink_class_t	class;
2452e7801d59Ssowmini 	show_state_t		*state = (show_state_t *)arg;
24537c478bd9Sstevel@tonic-gate 	pktsum_t		stats, diff_stats;
2454d62bc4baSyz147064 	dladm_phys_attr_t	dpa;
2455ae6aa22aSVenugopal Iyer 	link_args_t		largs;
24567c478bd9Sstevel@tonic-gate 
24577c478bd9Sstevel@tonic-gate 	if (state->ls_firstonly) {
24587c478bd9Sstevel@tonic-gate 		if (state->ls_donefirst)
2459d62bc4baSyz147064 			return (DLADM_WALK_CONTINUE);
24607c478bd9Sstevel@tonic-gate 		state->ls_donefirst = B_TRUE;
24617c478bd9Sstevel@tonic-gate 	} else {
24627c478bd9Sstevel@tonic-gate 		bzero(&state->ls_prevstats, sizeof (state->ls_prevstats));
24637c478bd9Sstevel@tonic-gate 	}
24647c478bd9Sstevel@tonic-gate 
24654ac67f02SAnurag S. Maskey 	if (dladm_datalink_id2info(dh, linkid, NULL, &class, NULL, link,
2466e7801d59Ssowmini 	    DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) {
2467d62bc4baSyz147064 		return (DLADM_WALK_CONTINUE);
2468d62bc4baSyz147064 	}
2469d62bc4baSyz147064 
2470d62bc4baSyz147064 	if (class == DATALINK_CLASS_PHYS) {
24714ac67f02SAnurag S. Maskey 		if (dladm_phys_info(dh, linkid, &dpa, DLADM_OPT_ACTIVE) !=
2472d62bc4baSyz147064 		    DLADM_STATUS_OK) {
2473d62bc4baSyz147064 			return (DLADM_WALK_CONTINUE);
2474d62bc4baSyz147064 		}
2475d62bc4baSyz147064 		if (dpa.dp_novanity)
2476d62bc4baSyz147064 			get_mac_stats(dpa.dp_dev, &stats);
2477d62bc4baSyz147064 		else
2478d62bc4baSyz147064 			get_link_stats(link, &stats);
2479d62bc4baSyz147064 	} else {
2480d62bc4baSyz147064 		get_link_stats(link, &stats);
2481d62bc4baSyz147064 	}
2482da14cebeSEric Cheng 	dladm_stats_diff(&diff_stats, &stats, &state->ls_prevstats);
24837c478bd9Sstevel@tonic-gate 
2484ae6aa22aSVenugopal Iyer 	largs.link_s_link = link;
2485ae6aa22aSVenugopal Iyer 	largs.link_s_psum = &diff_stats;
2486ae6aa22aSVenugopal Iyer 	dladm_print_output(&state->ls_print, state->ls_parseable,
2487ae6aa22aSVenugopal Iyer 	    print_link_stats, &largs);
24887c478bd9Sstevel@tonic-gate 
24897c478bd9Sstevel@tonic-gate 	state->ls_prevstats = stats;
2490d62bc4baSyz147064 	return (DLADM_WALK_CONTINUE);
24917c478bd9Sstevel@tonic-gate }
24927c478bd9Sstevel@tonic-gate 
2493d62bc4baSyz147064 
2494d62bc4baSyz147064 static dladm_status_t
2495d62bc4baSyz147064 print_aggr_info(show_grp_state_t *state, const char *link,
2496e7801d59Ssowmini     dladm_aggr_grp_attr_t *ginfop)
2497d62bc4baSyz147064 {
2498d62bc4baSyz147064 	char			addr_str[ETHERADDRL * 3];
2499e7801d59Ssowmini 	laggr_fields_buf_t	lbuf;
2500d62bc4baSyz147064 
2501e7801d59Ssowmini 	(void) snprintf(lbuf.laggr_name, sizeof (lbuf.laggr_name),
2502e7801d59Ssowmini 	    "%s", link);
2503e7801d59Ssowmini 
2504e7801d59Ssowmini 	(void) dladm_aggr_policy2str(ginfop->lg_policy,
2505e7801d59Ssowmini 	    lbuf.laggr_policy);
2506d62bc4baSyz147064 
2507d62bc4baSyz147064 	if (ginfop->lg_mac_fixed) {
2508d62bc4baSyz147064 		(void) dladm_aggr_macaddr2str(ginfop->lg_mac, addr_str);
2509e7801d59Ssowmini 		(void) snprintf(lbuf.laggr_addrpolicy,
2510e7801d59Ssowmini 		    sizeof (lbuf.laggr_addrpolicy), "fixed (%s)", addr_str);
2511d62bc4baSyz147064 	} else {
2512e7801d59Ssowmini 		(void) snprintf(lbuf.laggr_addrpolicy,
2513e7801d59Ssowmini 		    sizeof (lbuf.laggr_addrpolicy), "auto");
2514d62bc4baSyz147064 	}
2515d62bc4baSyz147064 
2516d62bc4baSyz147064 
2517e7801d59Ssowmini 	(void) dladm_aggr_lacpmode2str(ginfop->lg_lacp_mode,
2518e7801d59Ssowmini 	    lbuf.laggr_lacpactivity);
2519e7801d59Ssowmini 	(void) dladm_aggr_lacptimer2str(ginfop->lg_lacp_timer,
2520e7801d59Ssowmini 	    lbuf.laggr_lacptimer);
2521e7801d59Ssowmini 	(void) snprintf(lbuf.laggr_flags, sizeof (lbuf.laggr_flags), "%c----",
2522d62bc4baSyz147064 	    ginfop->lg_force ? 'f' : '-');
2523e7801d59Ssowmini 
2524e7801d59Ssowmini 	if (!state->gs_parseable && !state->gs_printheader) {
2525e7801d59Ssowmini 		print_header(&state->gs_print);
2526e7801d59Ssowmini 		state->gs_printheader = B_TRUE;
2527d62bc4baSyz147064 	}
2528d62bc4baSyz147064 
2529e7801d59Ssowmini 	dladm_print_output(&state->gs_print, state->gs_parseable,
2530e7801d59Ssowmini 	    dladm_print_field, (void *)&lbuf);
2531e7801d59Ssowmini 
2532d62bc4baSyz147064 	return (DLADM_STATUS_OK);
2533d62bc4baSyz147064 }
2534d62bc4baSyz147064 
2535e7801d59Ssowmini static char *
2536e7801d59Ssowmini print_xaggr_callback(print_field_t *pf, void *arg)
2537d62bc4baSyz147064 {
2538e7801d59Ssowmini 	const laggr_args_t 	*l = arg;
2539e7801d59Ssowmini 	int 			portnum;
2540e7801d59Ssowmini 	static char 		buf[DLADM_STRSIZE];
2541e7801d59Ssowmini 	boolean_t		is_port = (l->laggr_lport >= 0);
2542e7801d59Ssowmini 	dladm_aggr_port_attr_t *portp;
2543d62bc4baSyz147064 	dladm_phys_attr_t	dpa;
2544e7801d59Ssowmini 	dladm_status_t		*stat, status;
2545d62bc4baSyz147064 
2546e7801d59Ssowmini 	stat = l->laggr_status;
2547e7801d59Ssowmini 	*stat = DLADM_STATUS_OK;
2548d62bc4baSyz147064 
2549e7801d59Ssowmini 	if (is_port) {
2550e7801d59Ssowmini 		portnum = l->laggr_lport;
2551e7801d59Ssowmini 		portp = &(l->laggr_ginfop->lg_ports[portnum]);
25524ac67f02SAnurag S. Maskey 		if ((status = dladm_datalink_id2info(handle,
25534ac67f02SAnurag S. Maskey 		    portp->lp_linkid, NULL, NULL, NULL, buf, sizeof (buf))) !=
2554e7801d59Ssowmini 		    DLADM_STATUS_OK) {
2555e7801d59Ssowmini 			goto err;
2556d62bc4baSyz147064 		}
25574ac67f02SAnurag S. Maskey 
25584ac67f02SAnurag S. Maskey 		if ((status = dladm_phys_info(handle, portp->lp_linkid,
25594ac67f02SAnurag S. Maskey 		    &dpa, DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) {
2560e7801d59Ssowmini 			goto err;
2561e7801d59Ssowmini 		}
2562d62bc4baSyz147064 	}
2563d62bc4baSyz147064 
2564e7801d59Ssowmini 	switch (pf->pf_index) {
2565e7801d59Ssowmini 	case AGGR_X_LINK:
2566e7801d59Ssowmini 		(void) snprintf(buf, sizeof (buf), "%s",
2567e7801d59Ssowmini 		    (is_port && !l->laggr_parseable ? " " : l->laggr_link));
2568e7801d59Ssowmini 		break;
2569e7801d59Ssowmini 	case AGGR_X_PORT:
2570e7801d59Ssowmini 		if (is_port)
2571e7801d59Ssowmini 			break;
2572e7801d59Ssowmini 		return ("");
2573e7801d59Ssowmini 		break;
2574d62bc4baSyz147064 
2575e7801d59Ssowmini 	case AGGR_X_SPEED:
2576e7801d59Ssowmini 		if (is_port) {
2577e7801d59Ssowmini 			(void) snprintf(buf, sizeof (buf), "%uMb",
2578e7801d59Ssowmini 			    (uint_t)((get_ifspeed(dpa.dp_dev,
2579e7801d59Ssowmini 			    B_FALSE)) / 1000000ull));
2580e7801d59Ssowmini 		} else {
2581e7801d59Ssowmini 			(void) snprintf(buf, sizeof (buf), "%uMb",
2582e7801d59Ssowmini 			    (uint_t)((get_ifspeed(l->laggr_link,
2583e7801d59Ssowmini 			    B_TRUE)) / 1000000ull));
2584e7801d59Ssowmini 		}
2585e7801d59Ssowmini 		break;
2586e7801d59Ssowmini 
2587e7801d59Ssowmini 	case AGGR_X_DUPLEX:
2588e7801d59Ssowmini 		if (is_port)
2589e7801d59Ssowmini 			(void) get_linkduplex(dpa.dp_dev, B_FALSE, buf);
2590d62bc4baSyz147064 		else
2591e7801d59Ssowmini 			(void) get_linkduplex(l->laggr_link, B_TRUE, buf);
2592e7801d59Ssowmini 		break;
2593d62bc4baSyz147064 
2594e7801d59Ssowmini 	case AGGR_X_STATE:
25951a1811a0Svs226613 		if (is_port)
25961a1811a0Svs226613 			(void) get_linkstate(dpa.dp_dev,  B_FALSE, buf);
25971a1811a0Svs226613 		else
25981a1811a0Svs226613 			(void) get_linkstate(l->laggr_link, B_TRUE, buf);
2599e7801d59Ssowmini 		break;
2600e7801d59Ssowmini 	case AGGR_X_ADDRESS:
2601e7801d59Ssowmini 		(void) dladm_aggr_macaddr2str(
2602e7801d59Ssowmini 		    (is_port ? portp->lp_mac : l->laggr_ginfop->lg_mac),
2603e7801d59Ssowmini 		    buf);
2604e7801d59Ssowmini 		break;
2605e7801d59Ssowmini 	case AGGR_X_PORTSTATE:
26060d365605Sschuster 		if (is_port)
26070d365605Sschuster 			(void) dladm_aggr_portstate2str(
26080d365605Sschuster 			    portp->lp_state, buf);
26090d365605Sschuster 		else
26100d365605Sschuster 			return ("");
2611e7801d59Ssowmini 		break;
2612e7801d59Ssowmini 	}
2613e7801d59Ssowmini 	return (buf);
2614e7801d59Ssowmini 
2615e7801d59Ssowmini err:
2616e7801d59Ssowmini 	*stat = status;
2617e7801d59Ssowmini 	buf[0] = '\0';
2618e7801d59Ssowmini 	return (buf);
2619e7801d59Ssowmini }
2620e7801d59Ssowmini 
2621e7801d59Ssowmini static dladm_status_t
2622e7801d59Ssowmini print_aggr_extended(show_grp_state_t *state, const char *link,
2623e7801d59Ssowmini     dladm_aggr_grp_attr_t *ginfop)
2624e7801d59Ssowmini {
2625e7801d59Ssowmini 	int			i;
2626e7801d59Ssowmini 	dladm_status_t		status;
2627e7801d59Ssowmini 	laggr_args_t		largs;
2628e7801d59Ssowmini 
2629e7801d59Ssowmini 	if (!state->gs_parseable && !state->gs_printheader) {
2630e7801d59Ssowmini 		print_header(&state->gs_print);
2631e7801d59Ssowmini 		state->gs_printheader = B_TRUE;
2632e7801d59Ssowmini 	}
2633e7801d59Ssowmini 
2634e7801d59Ssowmini 	largs.laggr_lport = -1;
2635e7801d59Ssowmini 	largs.laggr_link = link;
2636e7801d59Ssowmini 	largs.laggr_ginfop = ginfop;
2637e7801d59Ssowmini 	largs.laggr_status = &status;
2638e7801d59Ssowmini 	largs.laggr_parseable = state->gs_parseable;
2639e7801d59Ssowmini 
2640e7801d59Ssowmini 	dladm_print_output(&state->gs_print, state->gs_parseable,
2641e7801d59Ssowmini 	    print_xaggr_callback, &largs);
2642e7801d59Ssowmini 
2643e7801d59Ssowmini 	if (status != DLADM_STATUS_OK)
2644e7801d59Ssowmini 		goto done;
2645e7801d59Ssowmini 
2646e7801d59Ssowmini 	for (i = 0; i < ginfop->lg_nports; i++) {
2647e7801d59Ssowmini 		largs.laggr_lport = i;
2648e7801d59Ssowmini 		dladm_print_output(&state->gs_print, state->gs_parseable,
2649e7801d59Ssowmini 		    print_xaggr_callback, &largs);
2650e7801d59Ssowmini 		if (status != DLADM_STATUS_OK)
2651e7801d59Ssowmini 			goto done;
2652d62bc4baSyz147064 	}
2653d62bc4baSyz147064 
2654d62bc4baSyz147064 	status = DLADM_STATUS_OK;
2655d62bc4baSyz147064 done:
2656d62bc4baSyz147064 	return (status);
2657d62bc4baSyz147064 }
2658d62bc4baSyz147064 
2659e7801d59Ssowmini 
2660e7801d59Ssowmini static char *
2661e7801d59Ssowmini print_lacp_callback(print_field_t *pf, void *arg)
2662e7801d59Ssowmini {
2663e7801d59Ssowmini 	const laggr_args_t	*l = arg;
2664e7801d59Ssowmini 	int			portnum;
2665e7801d59Ssowmini 	static char		buf[DLADM_STRSIZE];
2666e7801d59Ssowmini 	boolean_t		is_port = (l->laggr_lport >= 0);
2667e7801d59Ssowmini 	dladm_aggr_port_attr_t	*portp;
2668e7801d59Ssowmini 	dladm_status_t		*stat, status;
2669e7801d59Ssowmini 	aggr_lacp_state_t	*lstate;
2670e7801d59Ssowmini 
2671e7801d59Ssowmini 	if (!is_port) {
2672e7801d59Ssowmini 		return (NULL); /* cannot happen! */
2673e7801d59Ssowmini 	}
2674e7801d59Ssowmini 
2675e7801d59Ssowmini 	stat = l->laggr_status;
2676e7801d59Ssowmini 
2677e7801d59Ssowmini 	portnum = l->laggr_lport;
2678e7801d59Ssowmini 	portp = &(l->laggr_ginfop->lg_ports[portnum]);
26794ac67f02SAnurag S. Maskey 
26804ac67f02SAnurag S. Maskey 	if ((status = dladm_datalink_id2info(handle, portp->lp_linkid,
2681e7801d59Ssowmini 	    NULL, NULL, NULL, buf, sizeof (buf))) != DLADM_STATUS_OK) {
2682e7801d59Ssowmini 			goto err;
2683e7801d59Ssowmini 	}
2684e7801d59Ssowmini 	lstate = &(portp->lp_lacp_state);
2685e7801d59Ssowmini 
2686e7801d59Ssowmini 	switch (pf->pf_index) {
2687e7801d59Ssowmini 	case AGGR_L_LINK:
2688e7801d59Ssowmini 		(void) snprintf(buf, sizeof (buf), "%s",
2689e7801d59Ssowmini 		    (portnum > 0 ? "" : l->laggr_link));
2690e7801d59Ssowmini 		break;
2691e7801d59Ssowmini 
2692e7801d59Ssowmini 	case AGGR_L_PORT:
2693e7801d59Ssowmini 		break;
2694e7801d59Ssowmini 
2695e7801d59Ssowmini 	case AGGR_L_AGGREGATABLE:
2696e7801d59Ssowmini 		(void) snprintf(buf, sizeof (buf), "%s",
2697e7801d59Ssowmini 		    (lstate->bit.aggregation ? "yes" : "no"));
2698e7801d59Ssowmini 		break;
2699e7801d59Ssowmini 
2700e7801d59Ssowmini 	case AGGR_L_SYNC:
2701e7801d59Ssowmini 		(void) snprintf(buf, sizeof (buf), "%s",
2702e7801d59Ssowmini 		    (lstate->bit.sync ? "yes" : "no"));
2703e7801d59Ssowmini 		break;
2704e7801d59Ssowmini 
2705e7801d59Ssowmini 	case AGGR_L_COLL:
2706e7801d59Ssowmini 		(void) snprintf(buf, sizeof (buf), "%s",
2707e7801d59Ssowmini 		    (lstate->bit.collecting ? "yes" : "no"));
2708e7801d59Ssowmini 		break;
2709e7801d59Ssowmini 
2710e7801d59Ssowmini 	case AGGR_L_DIST:
2711e7801d59Ssowmini 		(void) snprintf(buf, sizeof (buf), "%s",
2712e7801d59Ssowmini 		    (lstate->bit.distributing ? "yes" : "no"));
2713e7801d59Ssowmini 		break;
2714e7801d59Ssowmini 
2715e7801d59Ssowmini 	case AGGR_L_DEFAULTED:
2716e7801d59Ssowmini 		(void) snprintf(buf, sizeof (buf), "%s",
2717e7801d59Ssowmini 		    (lstate->bit.defaulted ? "yes" : "no"));
2718e7801d59Ssowmini 		break;
2719e7801d59Ssowmini 
2720e7801d59Ssowmini 	case AGGR_L_EXPIRED:
2721e7801d59Ssowmini 		(void) snprintf(buf, sizeof (buf), "%s",
2722e7801d59Ssowmini 		    (lstate->bit.expired ? "yes" : "no"));
2723e7801d59Ssowmini 		break;
2724e7801d59Ssowmini 	}
2725e7801d59Ssowmini 
2726e7801d59Ssowmini 	*stat = DLADM_STATUS_OK;
2727e7801d59Ssowmini 	return (buf);
2728e7801d59Ssowmini 
2729e7801d59Ssowmini err:
2730e7801d59Ssowmini 	*stat = status;
2731e7801d59Ssowmini 	buf[0] = '\0';
2732e7801d59Ssowmini 	return (buf);
2733e7801d59Ssowmini }
2734e7801d59Ssowmini 
2735d62bc4baSyz147064 static dladm_status_t
2736d62bc4baSyz147064 print_aggr_lacp(show_grp_state_t *state, const char *link,
2737e7801d59Ssowmini     dladm_aggr_grp_attr_t *ginfop)
2738d62bc4baSyz147064 {
2739d62bc4baSyz147064 	int		i;
2740d62bc4baSyz147064 	dladm_status_t	status;
2741e7801d59Ssowmini 	laggr_args_t	largs;
2742d62bc4baSyz147064 
2743e7801d59Ssowmini 	if (!state->gs_parseable && !state->gs_printheader) {
2744e7801d59Ssowmini 		print_header(&state->gs_print);
2745e7801d59Ssowmini 		state->gs_printheader = B_TRUE;
2746d62bc4baSyz147064 	}
2747d62bc4baSyz147064 
2748e7801d59Ssowmini 	largs.laggr_link = link;
2749e7801d59Ssowmini 	largs.laggr_ginfop = ginfop;
2750e7801d59Ssowmini 	largs.laggr_status = &status;
2751d62bc4baSyz147064 
2752e7801d59Ssowmini 	for (i = 0; i < ginfop->lg_nports; i++) {
2753e7801d59Ssowmini 		largs.laggr_lport = i;
2754e7801d59Ssowmini 		dladm_print_output(&state->gs_print, state->gs_parseable,
2755e7801d59Ssowmini 		    print_lacp_callback, &largs);
2756d62bc4baSyz147064 		if (status != DLADM_STATUS_OK)
2757d62bc4baSyz147064 			goto done;
2758d62bc4baSyz147064 	}
2759d62bc4baSyz147064 
2760d62bc4baSyz147064 	status = DLADM_STATUS_OK;
2761d62bc4baSyz147064 done:
2762d62bc4baSyz147064 	return (status);
2763d62bc4baSyz147064 }
2764d62bc4baSyz147064 
2765e7801d59Ssowmini static char *
2766e7801d59Ssowmini print_aggr_stats_callback(print_field_t *pf, void *arg)
2767e7801d59Ssowmini {
2768e7801d59Ssowmini 	const laggr_args_t	*l = arg;
2769e7801d59Ssowmini 	int 			portnum;
2770e7801d59Ssowmini 	static char		buf[DLADM_STRSIZE];
2771e7801d59Ssowmini 	boolean_t		is_port = (l->laggr_lport >= 0);
2772e7801d59Ssowmini 	dladm_aggr_port_attr_t	*portp;
2773e7801d59Ssowmini 	dladm_phys_attr_t	dpa;
2774e7801d59Ssowmini 	dladm_status_t		*stat, status;
2775e7801d59Ssowmini 	pktsum_t		port_stat, diff_stats;
2776e7801d59Ssowmini 
2777e7801d59Ssowmini 	stat = l->laggr_status;
2778e7801d59Ssowmini 	*stat = DLADM_STATUS_OK;
2779e7801d59Ssowmini 
2780e7801d59Ssowmini 	if (is_port) {
2781e7801d59Ssowmini 		portnum = l->laggr_lport;
2782e7801d59Ssowmini 		portp = &(l->laggr_ginfop->lg_ports[portnum]);
27834ac67f02SAnurag S. Maskey 		if ((status = dladm_phys_info(handle, portp->lp_linkid,
27844ac67f02SAnurag S. Maskey 		    &dpa, DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) {
2785e7801d59Ssowmini 			goto err;
2786e7801d59Ssowmini 		}
2787e7801d59Ssowmini 
2788e7801d59Ssowmini 		get_mac_stats(dpa.dp_dev, &port_stat);
2789e7801d59Ssowmini 
27904ac67f02SAnurag S. Maskey 		if ((status = dladm_datalink_id2info(handle,
27914ac67f02SAnurag S. Maskey 		    portp->lp_linkid, NULL, NULL, NULL, buf, sizeof (buf))) !=
27924ac67f02SAnurag S. Maskey 		    DLADM_STATUS_OK) {
2793e7801d59Ssowmini 			goto err;
2794e7801d59Ssowmini 		}
2795e7801d59Ssowmini 
2796da14cebeSEric Cheng 		dladm_stats_diff(&diff_stats, &port_stat, l->laggr_prevstats);
2797e7801d59Ssowmini 	}
2798e7801d59Ssowmini 
2799e7801d59Ssowmini 	switch (pf->pf_index) {
2800e7801d59Ssowmini 	case AGGR_S_LINK:
2801e7801d59Ssowmini 		(void) snprintf(buf, sizeof (buf), "%s",
2802e7801d59Ssowmini 		    (is_port ? "" : l->laggr_link));
2803e7801d59Ssowmini 		break;
2804e7801d59Ssowmini 	case AGGR_S_PORT:
2805e7801d59Ssowmini 		if (is_port)
2806e7801d59Ssowmini 			break;
28070d365605Sschuster 		return ("");
2808e7801d59Ssowmini 		break;
2809e7801d59Ssowmini 
2810e7801d59Ssowmini 	case AGGR_S_IPKTS:
2811e7801d59Ssowmini 		if (is_port) {
2812e7801d59Ssowmini 			(void) snprintf(buf, sizeof (buf), "%llu",
2813e7801d59Ssowmini 			    diff_stats.ipackets);
2814e7801d59Ssowmini 		} else {
2815e7801d59Ssowmini 			(void) snprintf(buf, sizeof (buf), "%llu",
2816e7801d59Ssowmini 			    l->laggr_pktsumtot->ipackets);
2817e7801d59Ssowmini 		}
2818e7801d59Ssowmini 		break;
2819e7801d59Ssowmini 
2820e7801d59Ssowmini 	case AGGR_S_RBYTES:
2821e7801d59Ssowmini 		if (is_port) {
2822e7801d59Ssowmini 			(void) snprintf(buf, sizeof (buf), "%llu",
2823e7801d59Ssowmini 			    diff_stats.rbytes);
2824e7801d59Ssowmini 		} else {
2825e7801d59Ssowmini 			(void) snprintf(buf, sizeof (buf), "%llu",
2826e7801d59Ssowmini 			    l->laggr_pktsumtot->rbytes);
2827e7801d59Ssowmini 		}
2828e7801d59Ssowmini 		break;
2829e7801d59Ssowmini 
2830e7801d59Ssowmini 	case AGGR_S_OPKTS:
2831e7801d59Ssowmini 		if (is_port) {
2832e7801d59Ssowmini 			(void) snprintf(buf, sizeof (buf), "%llu",
2833e7801d59Ssowmini 			    diff_stats.opackets);
2834e7801d59Ssowmini 		} else {
2835e7801d59Ssowmini 			(void) snprintf(buf, sizeof (buf), "%llu",
2836e7801d59Ssowmini 			    l->laggr_pktsumtot->opackets);
2837e7801d59Ssowmini 		}
2838e7801d59Ssowmini 		break;
2839e7801d59Ssowmini 	case AGGR_S_OBYTES:
2840e7801d59Ssowmini 		if (is_port) {
2841e7801d59Ssowmini 			(void) snprintf(buf, sizeof (buf), "%llu",
2842e7801d59Ssowmini 			    diff_stats.obytes);
2843e7801d59Ssowmini 		} else {
2844e7801d59Ssowmini 			(void) snprintf(buf, sizeof (buf), "%llu",
2845e7801d59Ssowmini 			    l->laggr_pktsumtot->obytes);
2846e7801d59Ssowmini 		}
2847e7801d59Ssowmini 		break;
2848e7801d59Ssowmini 
2849e7801d59Ssowmini 	case AGGR_S_IPKTDIST:
2850e7801d59Ssowmini 		if (is_port) {
2851e7801d59Ssowmini 			(void) snprintf(buf, sizeof (buf), "%-6.1f",
2852e7801d59Ssowmini 			    (double)diff_stats.opackets/
2853e7801d59Ssowmini 			    (double)l->laggr_pktsumtot->ipackets * 100);
2854e7801d59Ssowmini 		} else {
28550d365605Sschuster 			return ("");
2856e7801d59Ssowmini 		}
2857e7801d59Ssowmini 		break;
2858e7801d59Ssowmini 	case AGGR_S_OPKTDIST:
2859e7801d59Ssowmini 		if (is_port) {
2860e7801d59Ssowmini 			(void) snprintf(buf, sizeof (buf), "%-6.1f",
2861e7801d59Ssowmini 			    (double)diff_stats.opackets/
2862e7801d59Ssowmini 			    (double)l->laggr_pktsumtot->opackets * 100);
2863e7801d59Ssowmini 		} else {
28640d365605Sschuster 			return ("");
2865e7801d59Ssowmini 		}
2866e7801d59Ssowmini 		break;
2867e7801d59Ssowmini 	}
2868e7801d59Ssowmini 	return (buf);
2869e7801d59Ssowmini 
2870e7801d59Ssowmini err:
2871e7801d59Ssowmini 	*stat = status;
2872e7801d59Ssowmini 	buf[0] = '\0';
2873e7801d59Ssowmini 	return (buf);
2874e7801d59Ssowmini }
2875e7801d59Ssowmini 
2876d62bc4baSyz147064 static dladm_status_t
2877d62bc4baSyz147064 print_aggr_stats(show_grp_state_t *state, const char *link,
2878e7801d59Ssowmini     dladm_aggr_grp_attr_t *ginfop)
2879d62bc4baSyz147064 {
2880d62bc4baSyz147064 	dladm_phys_attr_t	dpa;
2881d62bc4baSyz147064 	dladm_aggr_port_attr_t	*portp;
2882d62bc4baSyz147064 	pktsum_t		pktsumtot, port_stat;
2883d62bc4baSyz147064 	dladm_status_t		status;
2884d62bc4baSyz147064 	int			i;
2885e7801d59Ssowmini 	laggr_args_t		largs;
28867c478bd9Sstevel@tonic-gate 
28877c478bd9Sstevel@tonic-gate 	/* sum the ports statistics */
28887c478bd9Sstevel@tonic-gate 	bzero(&pktsumtot, sizeof (pktsumtot));
2889d62bc4baSyz147064 
2890d62bc4baSyz147064 	for (i = 0; i < ginfop->lg_nports; i++) {
2891d62bc4baSyz147064 
2892d62bc4baSyz147064 		portp = &(ginfop->lg_ports[i]);
28934ac67f02SAnurag S. Maskey 		if ((status = dladm_phys_info(handle, portp->lp_linkid, &dpa,
2894d62bc4baSyz147064 		    DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) {
2895d62bc4baSyz147064 			goto done;
28967c478bd9Sstevel@tonic-gate 		}
28977c478bd9Sstevel@tonic-gate 
2898d62bc4baSyz147064 		get_mac_stats(dpa.dp_dev, &port_stat);
2899da14cebeSEric Cheng 		dladm_stats_total(&pktsumtot, &port_stat,
2900da14cebeSEric Cheng 		    &state->gs_prevstats[i]);
29017c478bd9Sstevel@tonic-gate 	}
29027c478bd9Sstevel@tonic-gate 
2903e7801d59Ssowmini 	if (!state->gs_parseable && !state->gs_printheader) {
2904e7801d59Ssowmini 		print_header(&state->gs_print);
2905e7801d59Ssowmini 		state->gs_printheader = B_TRUE;
2906e7801d59Ssowmini 	}
2907e7801d59Ssowmini 
2908e7801d59Ssowmini 	largs.laggr_lport = -1;
2909e7801d59Ssowmini 	largs.laggr_link = link;
2910e7801d59Ssowmini 	largs.laggr_ginfop = ginfop;
2911e7801d59Ssowmini 	largs.laggr_status = &status;
2912e7801d59Ssowmini 	largs.laggr_pktsumtot = &pktsumtot;
2913e7801d59Ssowmini 
2914e7801d59Ssowmini 	dladm_print_output(&state->gs_print, state->gs_parseable,
2915e7801d59Ssowmini 	    print_aggr_stats_callback, &largs);
2916e7801d59Ssowmini 
2917e7801d59Ssowmini 	if (status != DLADM_STATUS_OK)
2918e7801d59Ssowmini 		goto done;
2919d62bc4baSyz147064 
2920d62bc4baSyz147064 	for (i = 0; i < ginfop->lg_nports; i++) {
2921e7801d59Ssowmini 		largs.laggr_lport = i;
2922e7801d59Ssowmini 		largs.laggr_prevstats = &state->gs_prevstats[i];
2923e7801d59Ssowmini 		dladm_print_output(&state->gs_print, state->gs_parseable,
2924e7801d59Ssowmini 		    print_aggr_stats_callback, &largs);
2925e7801d59Ssowmini 		if (status != DLADM_STATUS_OK)
2926d62bc4baSyz147064 			goto done;
2927d62bc4baSyz147064 	}
2928d62bc4baSyz147064 
2929d62bc4baSyz147064 	status = DLADM_STATUS_OK;
2930d62bc4baSyz147064 done:
2931d62bc4baSyz147064 	return (status);
2932d62bc4baSyz147064 }
2933d62bc4baSyz147064 
2934d62bc4baSyz147064 static dladm_status_t
2935e7801d59Ssowmini print_aggr(show_grp_state_t *state, datalink_id_t linkid)
2936d62bc4baSyz147064 {
2937d62bc4baSyz147064 	char			link[MAXLINKNAMELEN];
2938d62bc4baSyz147064 	dladm_aggr_grp_attr_t	ginfo;
2939d62bc4baSyz147064 	uint32_t		flags;
2940d62bc4baSyz147064 	dladm_status_t		status;
2941d62bc4baSyz147064 
29425f5c9f54SAnurag S. Maskey 	bzero(&ginfo, sizeof (dladm_aggr_grp_attr_t));
29434ac67f02SAnurag S. Maskey 	if ((status = dladm_datalink_id2info(handle, linkid, &flags, NULL,
29444ac67f02SAnurag S. Maskey 	    NULL, link, MAXLINKNAMELEN)) != DLADM_STATUS_OK) {
2945d62bc4baSyz147064 		return (status);
2946d62bc4baSyz147064 	}
2947d62bc4baSyz147064 
2948d62bc4baSyz147064 	if (!(state->gs_flags & flags))
2949d62bc4baSyz147064 		return (DLADM_STATUS_NOTFOUND);
2950d62bc4baSyz147064 
29514ac67f02SAnurag S. Maskey 	status = dladm_aggr_info(handle, linkid, &ginfo, state->gs_flags);
2952d62bc4baSyz147064 	if (status != DLADM_STATUS_OK)
2953d62bc4baSyz147064 		return (status);
2954d62bc4baSyz147064 
2955d62bc4baSyz147064 	if (state->gs_lacp)
2956e7801d59Ssowmini 		status = print_aggr_lacp(state, link, &ginfo);
2957d62bc4baSyz147064 	else if (state->gs_extended)
2958e7801d59Ssowmini 		status = print_aggr_extended(state, link, &ginfo);
2959d62bc4baSyz147064 	else if (state->gs_stats)
2960e7801d59Ssowmini 		status = print_aggr_stats(state, link, &ginfo);
29614ac67f02SAnurag S. Maskey 	else
2962e7801d59Ssowmini 		status = print_aggr_info(state, link, &ginfo);
2963d62bc4baSyz147064 
2964d62bc4baSyz147064 done:
2965d62bc4baSyz147064 	free(ginfo.lg_ports);
2966d62bc4baSyz147064 	return (status);
2967d62bc4baSyz147064 }
2968d62bc4baSyz147064 
29694ac67f02SAnurag S. Maskey /* ARGSUSED */
2970d62bc4baSyz147064 static int
29714ac67f02SAnurag S. Maskey show_aggr(dladm_handle_t dh, datalink_id_t linkid, void *arg)
2972d62bc4baSyz147064 {
2973d62bc4baSyz147064 	show_grp_state_t	*state = arg;
2974d62bc4baSyz147064 	dladm_status_t		status;
2975d62bc4baSyz147064 
29764ac67f02SAnurag S. Maskey 	if ((status = print_aggr(state, linkid)) != DLADM_STATUS_OK)
2977d62bc4baSyz147064 		goto done;
2978d62bc4baSyz147064 
2979d62bc4baSyz147064 done:
2980d62bc4baSyz147064 	state->gs_status = status;
2981d62bc4baSyz147064 	return (DLADM_WALK_CONTINUE);
29827c478bd9Sstevel@tonic-gate }
29837c478bd9Sstevel@tonic-gate 
29847c478bd9Sstevel@tonic-gate static void
29858d5c46e6Sam223141 do_show_link(int argc, char *argv[], const char *use)
29867c478bd9Sstevel@tonic-gate {
29877c478bd9Sstevel@tonic-gate 	int		option;
29887c478bd9Sstevel@tonic-gate 	boolean_t	s_arg = B_FALSE;
2989da14cebeSEric Cheng 	boolean_t	S_arg = B_FALSE;
29907c478bd9Sstevel@tonic-gate 	boolean_t	i_arg = B_FALSE;
2991d62bc4baSyz147064 	uint32_t	flags = DLADM_OPT_ACTIVE;
2992d62bc4baSyz147064 	boolean_t	p_arg = B_FALSE;
2993d62bc4baSyz147064 	datalink_id_t	linkid = DATALINK_ALL_LINKID;
2994da14cebeSEric Cheng 	char		linkname[MAXLINKNAMELEN];
2995*63a6526dSMichael Lim 	uint32_t	interval = 0;
2996d62bc4baSyz147064 	show_state_t	state;
2997d62bc4baSyz147064 	dladm_status_t	status;
2998e7801d59Ssowmini 	boolean_t	o_arg = B_FALSE;
2999e7801d59Ssowmini 	char		*fields_str = NULL;
3000e7801d59Ssowmini 	print_field_t	**fields;
3001e7801d59Ssowmini 	uint_t		nfields;
3002e7801d59Ssowmini 	char		*all_active_fields = "link,class,mtu,state,over";
3003e7801d59Ssowmini 	char		*all_inactive_fields = "link,class,over";
30046be03d0bSVasumathi Sundaram - Sun Microsystems 	char		*allstat_fields =
30056be03d0bSVasumathi Sundaram - Sun Microsystems 	    "link,ipackets,rbytes,ierrors,opackets,obytes,oerrors";
3006e7801d59Ssowmini 
3007e7801d59Ssowmini 	bzero(&state, sizeof (state));
30087c478bd9Sstevel@tonic-gate 
30097c478bd9Sstevel@tonic-gate 	opterr = 0;
3010da14cebeSEric Cheng 	while ((option = getopt_long(argc, argv, ":pPsSi:o:",
3011d62bc4baSyz147064 	    show_lopts, NULL)) != -1) {
30127c478bd9Sstevel@tonic-gate 		switch (option) {
30137c478bd9Sstevel@tonic-gate 		case 'p':
3014d62bc4baSyz147064 			if (p_arg)
3015d62bc4baSyz147064 				die_optdup(option);
3016d62bc4baSyz147064 
3017d62bc4baSyz147064 			p_arg = B_TRUE;
30187c478bd9Sstevel@tonic-gate 			break;
30197c478bd9Sstevel@tonic-gate 		case 's':
302033343a97Smeem 			if (s_arg)
302133343a97Smeem 				die_optdup(option);
30227c478bd9Sstevel@tonic-gate 
30237c478bd9Sstevel@tonic-gate 			s_arg = B_TRUE;
30247c478bd9Sstevel@tonic-gate 			break;
3025d62bc4baSyz147064 		case 'P':
3026d62bc4baSyz147064 			if (flags != DLADM_OPT_ACTIVE)
3027d62bc4baSyz147064 				die_optdup(option);
3028d62bc4baSyz147064 
3029d62bc4baSyz147064 			flags = DLADM_OPT_PERSIST;
3030d62bc4baSyz147064 			break;
3031da14cebeSEric Cheng 		case 'S':
3032da14cebeSEric Cheng 			if (S_arg)
3033da14cebeSEric Cheng 				die_optdup(option);
3034da14cebeSEric Cheng 
3035da14cebeSEric Cheng 			S_arg = B_TRUE;
3036da14cebeSEric Cheng 			break;
3037e7801d59Ssowmini 		case 'o':
3038e7801d59Ssowmini 			o_arg = B_TRUE;
3039e7801d59Ssowmini 			fields_str = optarg;
3040e7801d59Ssowmini 			break;
30417c478bd9Sstevel@tonic-gate 		case 'i':
304233343a97Smeem 			if (i_arg)
304333343a97Smeem 				die_optdup(option);
30447c478bd9Sstevel@tonic-gate 
30457c478bd9Sstevel@tonic-gate 			i_arg = B_TRUE;
3046*63a6526dSMichael Lim 			if (!dladm_str2interval(optarg, &interval))
304733343a97Smeem 				die("invalid interval value '%s'", optarg);
30487c478bd9Sstevel@tonic-gate 			break;
30497c478bd9Sstevel@tonic-gate 		default:
30508d5c46e6Sam223141 			die_opterr(optopt, option, use);
305133343a97Smeem 			break;
30527c478bd9Sstevel@tonic-gate 		}
30537c478bd9Sstevel@tonic-gate 	}
30547c478bd9Sstevel@tonic-gate 
3055da14cebeSEric Cheng 	if (i_arg && !(s_arg || S_arg))
3056da14cebeSEric Cheng 		die("the option -i can be used only with -s or -S");
3057da14cebeSEric Cheng 
3058da14cebeSEric Cheng 	if (s_arg && S_arg)
3059da14cebeSEric Cheng 		die("the -s option cannot be used with -S");
30607c478bd9Sstevel@tonic-gate 
30616be03d0bSVasumathi Sundaram - Sun Microsystems 	if (s_arg && flags != DLADM_OPT_ACTIVE)
30626be03d0bSVasumathi Sundaram - Sun Microsystems 		die("the option -P cannot be used with -s");
3063d62bc4baSyz147064 
3064da14cebeSEric Cheng 	if (S_arg && (p_arg || flags != DLADM_OPT_ACTIVE))
3065da14cebeSEric Cheng 		die("the option -%c cannot be used with -S", p_arg ? 'p' : 'P');
3066da14cebeSEric Cheng 
30677c478bd9Sstevel@tonic-gate 	/* get link name (optional last argument) */
3068d62bc4baSyz147064 	if (optind == (argc-1)) {
3069d62bc4baSyz147064 		uint32_t	f;
3070d62bc4baSyz147064 
3071da14cebeSEric Cheng 		if (strlcpy(linkname, argv[optind], MAXLINKNAMELEN)
3072da14cebeSEric Cheng 		    >= MAXLINKNAMELEN) {
3073da14cebeSEric Cheng 			(void) fprintf(stderr,
3074da14cebeSEric Cheng 			    gettext("%s: link name too long\n"),
3075da14cebeSEric Cheng 			    progname);
30764ac67f02SAnurag S. Maskey 			dladm_close(handle);
3077da14cebeSEric Cheng 			exit(1);
3078da14cebeSEric Cheng 		}
30794ac67f02SAnurag S. Maskey 		if ((status = dladm_name2info(handle, linkname, &linkid, &f,
3080d62bc4baSyz147064 		    NULL, NULL)) != DLADM_STATUS_OK) {
3081da14cebeSEric Cheng 			die_dlerr(status, "link %s is not valid", linkname);
3082d62bc4baSyz147064 		}
3083d62bc4baSyz147064 
3084d62bc4baSyz147064 		if (!(f & flags)) {
3085d62bc4baSyz147064 			die_dlerr(DLADM_STATUS_BADARG, "link %s is %s",
3086d62bc4baSyz147064 			    argv[optind], flags == DLADM_OPT_PERSIST ?
3087d62bc4baSyz147064 			    "a temporary link" : "temporarily removed");
3088d62bc4baSyz147064 		}
3089d62bc4baSyz147064 	} else if (optind != argc) {
30907c478bd9Sstevel@tonic-gate 		usage();
3091d62bc4baSyz147064 	}
30927c478bd9Sstevel@tonic-gate 
30930d365605Sschuster 	if (p_arg && !o_arg)
30940d365605Sschuster 		die("-p requires -o");
30950d365605Sschuster 
3096da14cebeSEric Cheng 	if (S_arg) {
30974ac67f02SAnurag S. Maskey 		dladm_continuous(handle, linkid, NULL, interval, LINK_REPORT);
3098da14cebeSEric Cheng 		return;
3099da14cebeSEric Cheng 	}
3100da14cebeSEric Cheng 
31010d365605Sschuster 	if (p_arg && strcasecmp(fields_str, "all") == 0)
31020d365605Sschuster 		die("\"-o all\" is invalid with -p");
31030d365605Sschuster 
3104e7801d59Ssowmini 	if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) {
31056be03d0bSVasumathi Sundaram - Sun Microsystems 		if (s_arg)
31066be03d0bSVasumathi Sundaram - Sun Microsystems 			fields_str = allstat_fields;
31076be03d0bSVasumathi Sundaram - Sun Microsystems 		else if (flags & DLADM_OPT_ACTIVE)
3108e7801d59Ssowmini 			fields_str = all_active_fields;
3109e7801d59Ssowmini 		else
3110e7801d59Ssowmini 			fields_str = all_inactive_fields;
3111e7801d59Ssowmini 	}
3112e7801d59Ssowmini 
31136be03d0bSVasumathi Sundaram - Sun Microsystems 	state.ls_parseable = p_arg;
31146be03d0bSVasumathi Sundaram - Sun Microsystems 	state.ls_flags = flags;
31156be03d0bSVasumathi Sundaram - Sun Microsystems 	state.ls_donefirst = B_FALSE;
31166be03d0bSVasumathi Sundaram - Sun Microsystems 
31176be03d0bSVasumathi Sundaram - Sun Microsystems 	if (s_arg) {
31186be03d0bSVasumathi Sundaram - Sun Microsystems 		link_stats(linkid, interval, fields_str, &state);
31196be03d0bSVasumathi Sundaram - Sun Microsystems 		return;
31206be03d0bSVasumathi Sundaram - Sun Microsystems 	}
31216be03d0bSVasumathi Sundaram - Sun Microsystems 
3122e7801d59Ssowmini 	fields = parse_output_fields(fields_str, link_fields, DEV_LINK_FIELDS,
3123e7801d59Ssowmini 	    CMD_TYPE_ANY, &nfields);
3124e7801d59Ssowmini 
31250d365605Sschuster 	if (fields == NULL)
3126e7801d59Ssowmini 		die("invalid field(s) specified");
3127e7801d59Ssowmini 
3128e7801d59Ssowmini 	state.ls_print.ps_fields = fields;
3129e7801d59Ssowmini 	state.ls_print.ps_nfields = nfields;
3130e7801d59Ssowmini 
3131d62bc4baSyz147064 	if (linkid == DATALINK_ALL_LINKID) {
31324ac67f02SAnurag S. Maskey 		(void) dladm_walk_datalink_id(show_link, handle, &state,
3133d62bc4baSyz147064 		    DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE, flags);
3134210db224Sericheng 	} else {
31354ac67f02SAnurag S. Maskey 		(void) show_link(handle, linkid, &state);
3136d62bc4baSyz147064 		if (state.ls_status != DLADM_STATUS_OK) {
3137d62bc4baSyz147064 			die_dlerr(state.ls_status, "failed to show link %s",
3138d62bc4baSyz147064 			    argv[optind]);
3139d62bc4baSyz147064 		}
31407c478bd9Sstevel@tonic-gate 	}
3141210db224Sericheng }
31427c478bd9Sstevel@tonic-gate 
31437c478bd9Sstevel@tonic-gate static void
31448d5c46e6Sam223141 do_show_aggr(int argc, char *argv[], const char *use)
31457c478bd9Sstevel@tonic-gate {
31467c478bd9Sstevel@tonic-gate 	boolean_t		L_arg = B_FALSE;
31477c478bd9Sstevel@tonic-gate 	boolean_t		s_arg = B_FALSE;
31487c478bd9Sstevel@tonic-gate 	boolean_t		i_arg = B_FALSE;
3149d62bc4baSyz147064 	boolean_t		p_arg = B_FALSE;
3150d62bc4baSyz147064 	boolean_t		x_arg = B_FALSE;
31517c478bd9Sstevel@tonic-gate 	show_grp_state_t	state;
3152d62bc4baSyz147064 	uint32_t		flags = DLADM_OPT_ACTIVE;
3153d62bc4baSyz147064 	datalink_id_t		linkid = DATALINK_ALL_LINKID;
3154d62bc4baSyz147064 	int			option;
3155*63a6526dSMichael Lim 	uint32_t		interval = 0;
3156d62bc4baSyz147064 	int			key;
3157d62bc4baSyz147064 	dladm_status_t		status;
3158e7801d59Ssowmini 	boolean_t		o_arg = B_FALSE;
3159e7801d59Ssowmini 	char			*fields_str = NULL;
3160e7801d59Ssowmini 	print_field_t		**fields;
3161e7801d59Ssowmini 	uint_t			nfields;
3162e7801d59Ssowmini 	char			*all_fields =
3163e7801d59Ssowmini 	    "link,policy,addrpolicy,lacpactivity,lacptimer,flags";
3164e7801d59Ssowmini 	char			*all_lacp_fields =
3165e7801d59Ssowmini 	    "link,port,aggregatable,sync,coll,dist,defaulted,expired";
3166e7801d59Ssowmini 	char			*all_stats_fields =
3167e7801d59Ssowmini 	    "link,port,ipackets,rbytes,opackets,obytes,ipktdist,opktdist";
3168e7801d59Ssowmini 	char			*all_extended_fields =
3169e7801d59Ssowmini 	    "link,port,speed,duplex,state,address,portstate";
3170e7801d59Ssowmini 	print_field_t		*pf;
3171e7801d59Ssowmini 	int			pfmax;
3172e7801d59Ssowmini 
3173e7801d59Ssowmini 	bzero(&state, sizeof (state));
31747c478bd9Sstevel@tonic-gate 
31757c478bd9Sstevel@tonic-gate 	opterr = 0;
3176e7801d59Ssowmini 	while ((option = getopt_long(argc, argv, ":LpPxsi:o:",
3177d62bc4baSyz147064 	    show_lopts, NULL)) != -1) {
31787c478bd9Sstevel@tonic-gate 		switch (option) {
31797c478bd9Sstevel@tonic-gate 		case 'L':
318033343a97Smeem 			if (L_arg)
318133343a97Smeem 				die_optdup(option);
31827c478bd9Sstevel@tonic-gate 
31837c478bd9Sstevel@tonic-gate 			L_arg = B_TRUE;
31847c478bd9Sstevel@tonic-gate 			break;
31857c478bd9Sstevel@tonic-gate 		case 'p':
3186d62bc4baSyz147064 			if (p_arg)
3187d62bc4baSyz147064 				die_optdup(option);
3188d62bc4baSyz147064 
3189d62bc4baSyz147064 			p_arg = B_TRUE;
3190d62bc4baSyz147064 			break;
3191d62bc4baSyz147064 		case 'x':
3192d62bc4baSyz147064 			if (x_arg)
3193d62bc4baSyz147064 				die_optdup(option);
3194d62bc4baSyz147064 
3195d62bc4baSyz147064 			x_arg = B_TRUE;
3196d62bc4baSyz147064 			break;
3197d62bc4baSyz147064 		case 'P':
3198d62bc4baSyz147064 			if (flags != DLADM_OPT_ACTIVE)
3199d62bc4baSyz147064 				die_optdup(option);
3200d62bc4baSyz147064 
3201d62bc4baSyz147064 			flags = DLADM_OPT_PERSIST;
32027c478bd9Sstevel@tonic-gate 			break;
32037c478bd9Sstevel@tonic-gate 		case 's':
320433343a97Smeem 			if (s_arg)
320533343a97Smeem 				die_optdup(option);
32067c478bd9Sstevel@tonic-gate 
32077c478bd9Sstevel@tonic-gate 			s_arg = B_TRUE;
32087c478bd9Sstevel@tonic-gate 			break;
3209e7801d59Ssowmini 		case 'o':
3210e7801d59Ssowmini 			o_arg = B_TRUE;
3211e7801d59Ssowmini 			fields_str = optarg;
3212e7801d59Ssowmini 			break;
32137c478bd9Sstevel@tonic-gate 		case 'i':
321433343a97Smeem 			if (i_arg)
321533343a97Smeem 				die_optdup(option);
32167c478bd9Sstevel@tonic-gate 
32177c478bd9Sstevel@tonic-gate 			i_arg = B_TRUE;
3218*63a6526dSMichael Lim 			if (!dladm_str2interval(optarg, &interval))
321933343a97Smeem 				die("invalid interval value '%s'", optarg);
32207c478bd9Sstevel@tonic-gate 			break;
32217c478bd9Sstevel@tonic-gate 		default:
32228d5c46e6Sam223141 			die_opterr(optopt, option, use);
322333343a97Smeem 			break;
32247c478bd9Sstevel@tonic-gate 		}
32257c478bd9Sstevel@tonic-gate 	}
32267c478bd9Sstevel@tonic-gate 
32270d365605Sschuster 	if (p_arg && !o_arg)
32280d365605Sschuster 		die("-p requires -o");
32290d365605Sschuster 
32300d365605Sschuster 	if (p_arg && strcasecmp(fields_str, "all") == 0)
32310d365605Sschuster 		die("\"-o all\" is invalid with -p");
32320d365605Sschuster 
323333343a97Smeem 	if (i_arg && !s_arg)
323433343a97Smeem 		die("the option -i can be used only with -s");
32357c478bd9Sstevel@tonic-gate 
3236d62bc4baSyz147064 	if (s_arg && (L_arg || p_arg || x_arg || flags != DLADM_OPT_ACTIVE)) {
3237d62bc4baSyz147064 		die("the option -%c cannot be used with -s",
3238d62bc4baSyz147064 		    L_arg ? 'L' : (p_arg ? 'p' : (x_arg ? 'x' : 'P')));
3239d62bc4baSyz147064 	}
3240d62bc4baSyz147064 
3241d62bc4baSyz147064 	if (L_arg && flags != DLADM_OPT_ACTIVE)
3242d62bc4baSyz147064 		die("the option -P cannot be used with -L");
3243d62bc4baSyz147064 
3244d62bc4baSyz147064 	if (x_arg && (L_arg || flags != DLADM_OPT_ACTIVE))
3245d62bc4baSyz147064 		die("the option -%c cannot be used with -x", L_arg ? 'L' : 'P');
3246d62bc4baSyz147064 
3247d62bc4baSyz147064 	/* get aggregation key or aggrname (optional last argument) */
32487c478bd9Sstevel@tonic-gate 	if (optind == (argc-1)) {
3249d62bc4baSyz147064 		if (!str2int(argv[optind], &key)) {
32504ac67f02SAnurag S. Maskey 			status = dladm_name2info(handle, argv[optind],
32514ac67f02SAnurag S. Maskey 			    &linkid, NULL, NULL, NULL);
3252d62bc4baSyz147064 		} else {
32534ac67f02SAnurag S. Maskey 			status = dladm_key2linkid(handle, (uint16_t)key,
3254d62bc4baSyz147064 			    &linkid, DLADM_OPT_ACTIVE);
3255d62bc4baSyz147064 		}
3256d62bc4baSyz147064 
3257d62bc4baSyz147064 		if (status != DLADM_STATUS_OK)
3258d62bc4baSyz147064 			die("non-existent aggregation '%s'", argv[optind]);
3259d62bc4baSyz147064 
32607c478bd9Sstevel@tonic-gate 	} else if (optind != argc) {
32617c478bd9Sstevel@tonic-gate 		usage();
32627c478bd9Sstevel@tonic-gate 	}
32637c478bd9Sstevel@tonic-gate 
3264d62bc4baSyz147064 	bzero(&state, sizeof (state));
3265d62bc4baSyz147064 	state.gs_lacp = L_arg;
3266d62bc4baSyz147064 	state.gs_stats = s_arg;
3267d62bc4baSyz147064 	state.gs_flags = flags;
3268d62bc4baSyz147064 	state.gs_parseable = p_arg;
3269d62bc4baSyz147064 	state.gs_extended = x_arg;
3270d62bc4baSyz147064 
3271e7801d59Ssowmini 	if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) {
3272e7801d59Ssowmini 		if (state.gs_lacp)
3273e7801d59Ssowmini 			fields_str = all_lacp_fields;
3274e7801d59Ssowmini 		else if (state.gs_stats)
3275e7801d59Ssowmini 			fields_str = all_stats_fields;
3276e7801d59Ssowmini 		else if (state.gs_extended)
3277e7801d59Ssowmini 			fields_str = all_extended_fields;
3278e7801d59Ssowmini 		else
3279e7801d59Ssowmini 			fields_str = all_fields;
3280e7801d59Ssowmini 	}
3281e7801d59Ssowmini 
3282e7801d59Ssowmini 	if (state.gs_lacp) {
3283e7801d59Ssowmini 		pf = aggr_l_fields;
3284e7801d59Ssowmini 		pfmax = AGGR_L_MAX_FIELDS;
3285e7801d59Ssowmini 	} else if (state.gs_stats) {
3286e7801d59Ssowmini 		pf = aggr_s_fields;
3287e7801d59Ssowmini 		pfmax = AGGR_S_MAX_FIELDS;
3288e7801d59Ssowmini 	} else if (state.gs_extended) {
3289e7801d59Ssowmini 		pf = aggr_x_fields;
3290e7801d59Ssowmini 		pfmax = AGGR_X_MAX_FIELDS;
3291e7801d59Ssowmini 	} else {
3292e7801d59Ssowmini 		pf = laggr_fields;
3293e7801d59Ssowmini 		pfmax = LAGGR_MAX_FIELDS;
3294e7801d59Ssowmini 	}
3295e7801d59Ssowmini 	fields = parse_output_fields(fields_str, pf, pfmax, CMD_TYPE_ANY,
3296e7801d59Ssowmini 	    &nfields);
3297e7801d59Ssowmini 
3298e7801d59Ssowmini 	if (fields == NULL) {
3299e7801d59Ssowmini 		die("invalid field(s) specified");
3300e7801d59Ssowmini 		return;
3301e7801d59Ssowmini 	}
3302e7801d59Ssowmini 
3303e7801d59Ssowmini 	state.gs_print.ps_fields = fields;
3304e7801d59Ssowmini 	state.gs_print.ps_nfields = nfields;
3305e7801d59Ssowmini 
33067c478bd9Sstevel@tonic-gate 	if (s_arg) {
3307d62bc4baSyz147064 		aggr_stats(linkid, &state, interval);
33087c478bd9Sstevel@tonic-gate 		return;
33097c478bd9Sstevel@tonic-gate 	}
33107c478bd9Sstevel@tonic-gate 
3311d62bc4baSyz147064 	if (linkid == DATALINK_ALL_LINKID) {
33124ac67f02SAnurag S. Maskey 		(void) dladm_walk_datalink_id(show_aggr, handle, &state,
3313d62bc4baSyz147064 		    DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE, flags);
3314d62bc4baSyz147064 	} else {
33154ac67f02SAnurag S. Maskey 		(void) show_aggr(handle, linkid, &state);
3316d62bc4baSyz147064 		if (state.gs_status != DLADM_STATUS_OK) {
3317d62bc4baSyz147064 			die_dlerr(state.gs_status, "failed to show aggr %s",
3318d62bc4baSyz147064 			    argv[optind]);
3319d62bc4baSyz147064 		}
3320d62bc4baSyz147064 	}
33217c478bd9Sstevel@tonic-gate }
33227c478bd9Sstevel@tonic-gate 
3323da14cebeSEric Cheng static dladm_status_t
3324da14cebeSEric Cheng print_phys_default(show_state_t *state, datalink_id_t linkid,
3325da14cebeSEric Cheng     const char *link, uint32_t flags, uint32_t media)
33267c478bd9Sstevel@tonic-gate {
3327da14cebeSEric Cheng 	dladm_phys_attr_t dpa;
3328da14cebeSEric Cheng 	dladm_status_t status;
3329da14cebeSEric Cheng 	link_fields_buf_t pattr;
3330e7801d59Ssowmini 
33314ac67f02SAnurag S. Maskey 	status = dladm_phys_info(handle, linkid, &dpa, state->ls_flags);
3332da14cebeSEric Cheng 	if (status != DLADM_STATUS_OK)
3333da14cebeSEric Cheng 		goto done;
33347c478bd9Sstevel@tonic-gate 
3335da14cebeSEric Cheng 	(void) snprintf(pattr.link_phys_device,
3336da14cebeSEric Cheng 	    sizeof (pattr.link_phys_device), "%s", dpa.dp_dev);
3337da14cebeSEric Cheng 	(void) dladm_media2str(media, pattr.link_phys_media);
3338da14cebeSEric Cheng 	if (state->ls_flags == DLADM_OPT_ACTIVE) {
3339da14cebeSEric Cheng 		boolean_t	islink;
3340d62bc4baSyz147064 
3341da14cebeSEric Cheng 		if (!dpa.dp_novanity) {
3342da14cebeSEric Cheng 			(void) strlcpy(pattr.link_name, link,
3343da14cebeSEric Cheng 			    sizeof (pattr.link_name));
3344da14cebeSEric Cheng 			islink = B_TRUE;
3345d62bc4baSyz147064 		} else {
3346da14cebeSEric Cheng 			/*
3347da14cebeSEric Cheng 			 * This is a physical link that does not have
3348da14cebeSEric Cheng 			 * vanity naming support.
3349da14cebeSEric Cheng 			 */
3350da14cebeSEric Cheng 			(void) strlcpy(pattr.link_name, dpa.dp_dev,
3351da14cebeSEric Cheng 			    sizeof (pattr.link_name));
3352da14cebeSEric Cheng 			islink = B_FALSE;
33537c478bd9Sstevel@tonic-gate 		}
33547c478bd9Sstevel@tonic-gate 
3355da14cebeSEric Cheng 		(void) get_linkstate(pattr.link_name, islink,
3356da14cebeSEric Cheng 		    pattr.link_phys_state);
3357da14cebeSEric Cheng 		(void) snprintf(pattr.link_phys_speed,
3358da14cebeSEric Cheng 		    sizeof (pattr.link_phys_speed), "%u",
3359da14cebeSEric Cheng 		    (uint_t)((get_ifspeed(pattr.link_name,
3360da14cebeSEric Cheng 		    islink)) / 1000000ull));
3361da14cebeSEric Cheng 		(void) get_linkduplex(pattr.link_name, islink,
3362da14cebeSEric Cheng 		    pattr.link_phys_duplex);
3363da14cebeSEric Cheng 	} else {
3364da14cebeSEric Cheng 		(void) snprintf(pattr.link_name, sizeof (pattr.link_name),
3365da14cebeSEric Cheng 		    "%s", link);
3366da14cebeSEric Cheng 		(void) snprintf(pattr.link_flags, sizeof (pattr.link_flags),
3367da14cebeSEric Cheng 		    "%c----", flags & DLADM_OPT_ACTIVE ? '-' : 'r');
3368da14cebeSEric Cheng 	}
3369da14cebeSEric Cheng 
3370da14cebeSEric Cheng 	if (!state->ls_parseable && !state->ls_printheader) {
3371da14cebeSEric Cheng 		print_header(&state->ls_print);
3372da14cebeSEric Cheng 		state->ls_printheader = B_TRUE;
3373da14cebeSEric Cheng 	}
3374da14cebeSEric Cheng 
3375da14cebeSEric Cheng 	dladm_print_output(&state->ls_print, state->ls_parseable,
3376da14cebeSEric Cheng 	    dladm_print_field, (void *)&pattr);
3377da14cebeSEric Cheng 
3378da14cebeSEric Cheng done:
3379da14cebeSEric Cheng 	return (status);
3380da14cebeSEric Cheng }
3381da14cebeSEric Cheng 
3382da14cebeSEric Cheng typedef struct {
3383da14cebeSEric Cheng 	show_state_t	*ms_state;
3384da14cebeSEric Cheng 	char		*ms_link;
3385da14cebeSEric Cheng 	dladm_macaddr_attr_t *ms_mac_attr;
3386da14cebeSEric Cheng } print_phys_mac_state_t;
3387da14cebeSEric Cheng 
3388da14cebeSEric Cheng /* callback of dladm_print_output() */
3389da14cebeSEric Cheng static char *
3390da14cebeSEric Cheng print_phys_one_mac_callback(print_field_t *pf, void *arg)
3391da14cebeSEric Cheng {
3392da14cebeSEric Cheng 	print_phys_mac_state_t *mac_state = arg;
3393da14cebeSEric Cheng 	dladm_macaddr_attr_t *attr = mac_state->ms_mac_attr;
3394da14cebeSEric Cheng 	static char buf[DLADM_STRSIZE];
3395da14cebeSEric Cheng 	boolean_t is_primary = (attr->ma_slot == 0);
3396da14cebeSEric Cheng 	boolean_t is_parseable = mac_state->ms_state->ls_parseable;
3397da14cebeSEric Cheng 
3398da14cebeSEric Cheng 	switch (pf->pf_index) {
3399da14cebeSEric Cheng 	case PHYS_M_LINK:
3400da14cebeSEric Cheng 		(void) snprintf(buf, sizeof (buf), "%s",
3401da14cebeSEric Cheng 		    (is_primary || is_parseable) ? mac_state->ms_link : " ");
3402da14cebeSEric Cheng 		break;
3403da14cebeSEric Cheng 	case PHYS_M_SLOT:
3404da14cebeSEric Cheng 		if (is_primary)
3405da14cebeSEric Cheng 			(void) snprintf(buf, sizeof (buf), gettext("primary"));
3406da14cebeSEric Cheng 		else
3407da14cebeSEric Cheng 			(void) snprintf(buf, sizeof (buf), "%d", attr->ma_slot);
3408da14cebeSEric Cheng 		break;
3409da14cebeSEric Cheng 	case PHYS_M_ADDRESS:
3410da14cebeSEric Cheng 		(void) dladm_aggr_macaddr2str(attr->ma_addr, buf);
3411da14cebeSEric Cheng 		break;
3412da14cebeSEric Cheng 	case PHYS_M_INUSE:
3413da14cebeSEric Cheng 		(void) snprintf(buf, sizeof (buf), "%s",
3414da14cebeSEric Cheng 		    attr->ma_flags & DLADM_MACADDR_USED ? gettext("yes") :
3415da14cebeSEric Cheng 		    gettext("no"));
3416da14cebeSEric Cheng 		break;
3417da14cebeSEric Cheng 	case PHYS_M_CLIENT:
3418da14cebeSEric Cheng 		/*
3419da14cebeSEric Cheng 		 * CR 6678526: resolve link id to actual link name if
3420da14cebeSEric Cheng 		 * it is valid.
3421da14cebeSEric Cheng 		 */
3422da14cebeSEric Cheng 		(void) snprintf(buf, sizeof (buf), "%s", attr->ma_client_name);
3423da14cebeSEric Cheng 		break;
3424da14cebeSEric Cheng 	}
3425da14cebeSEric Cheng 
3426da14cebeSEric Cheng 	return (buf);
3427da14cebeSEric Cheng }
3428da14cebeSEric Cheng 
3429da14cebeSEric Cheng typedef struct {
3430da14cebeSEric Cheng 	show_state_t	*hs_state;
3431da14cebeSEric Cheng 	char		*hs_link;
3432da14cebeSEric Cheng 	dladm_hwgrp_attr_t *hs_grp_attr;
3433da14cebeSEric Cheng } print_phys_hwgrp_state_t;
3434da14cebeSEric Cheng 
3435da14cebeSEric Cheng static char *
3436da14cebeSEric Cheng print_phys_one_hwgrp_callback(print_field_t *pf, void *arg)
3437da14cebeSEric Cheng {
3438da14cebeSEric Cheng 	print_phys_hwgrp_state_t *hg_state = arg;
3439da14cebeSEric Cheng 	dladm_hwgrp_attr_t *attr = hg_state->hs_grp_attr;
3440da14cebeSEric Cheng 	static char buf[DLADM_STRSIZE];
3441da14cebeSEric Cheng 
3442da14cebeSEric Cheng 	switch (pf->pf_index) {
3443da14cebeSEric Cheng 	case PHYS_H_LINK:
3444da14cebeSEric Cheng 		(void) snprintf(buf, sizeof (buf), "%s", attr->hg_link_name);
3445da14cebeSEric Cheng 		break;
3446da14cebeSEric Cheng 	case PHYS_H_GROUP:
3447da14cebeSEric Cheng 		(void) snprintf(buf, sizeof (buf), "%d", attr->hg_grp_num);
3448da14cebeSEric Cheng 		break;
3449da14cebeSEric Cheng 	case PHYS_H_GRPTYPE:
3450da14cebeSEric Cheng 		(void) snprintf(buf, sizeof (buf), "%s",
3451da14cebeSEric Cheng 		    attr->hg_grp_type == DLADM_HWGRP_TYPE_RX ? "RX" : "TX");
3452da14cebeSEric Cheng 		break;
3453da14cebeSEric Cheng 	case PHYS_H_RINGS:
3454da14cebeSEric Cheng 		(void) snprintf(buf, sizeof (buf), "%d", attr->hg_n_rings);
3455da14cebeSEric Cheng 		break;
3456da14cebeSEric Cheng 	case PHYS_H_CLIENTS:
3457da14cebeSEric Cheng 		if (attr->hg_client_names[0] == '\0') {
3458da14cebeSEric Cheng 			(void) snprintf(buf, sizeof (buf), "--");
3459da14cebeSEric Cheng 		} else {
3460da14cebeSEric Cheng 			(void) snprintf(buf, sizeof (buf), "%s ",
3461da14cebeSEric Cheng 			    attr->hg_client_names);
3462da14cebeSEric Cheng 		}
3463da14cebeSEric Cheng 		break;
3464da14cebeSEric Cheng 	}
3465da14cebeSEric Cheng 
3466da14cebeSEric Cheng 	return (buf);
3467da14cebeSEric Cheng }
3468da14cebeSEric Cheng 
3469da14cebeSEric Cheng /* callback of dladm_walk_macaddr, invoked for each MAC address slot */
3470da14cebeSEric Cheng static boolean_t
3471da14cebeSEric Cheng print_phys_mac_callback(void *arg, dladm_macaddr_attr_t *attr)
3472da14cebeSEric Cheng {
3473da14cebeSEric Cheng 	print_phys_mac_state_t *mac_state = arg;
3474da14cebeSEric Cheng 	show_state_t *state = mac_state->ms_state;
3475da14cebeSEric Cheng 
3476da14cebeSEric Cheng 	if (!state->ls_parseable && !state->ls_printheader) {
3477da14cebeSEric Cheng 		print_header(&state->ls_print);
3478da14cebeSEric Cheng 		state->ls_printheader = B_TRUE;
3479da14cebeSEric Cheng 	}
3480da14cebeSEric Cheng 
3481da14cebeSEric Cheng 	mac_state->ms_mac_attr = attr;
3482da14cebeSEric Cheng 	dladm_print_output(&state->ls_print, state->ls_parseable,
3483da14cebeSEric Cheng 	    print_phys_one_mac_callback, mac_state);
3484da14cebeSEric Cheng 
3485da14cebeSEric Cheng 	return (B_TRUE);
3486da14cebeSEric Cheng }
3487da14cebeSEric Cheng 
3488da14cebeSEric Cheng /* invoked by show-phys -m for each physical data-link */
3489da14cebeSEric Cheng static dladm_status_t
3490da14cebeSEric Cheng print_phys_mac(show_state_t *state, datalink_id_t linkid, char *link)
3491da14cebeSEric Cheng {
3492da14cebeSEric Cheng 	print_phys_mac_state_t mac_state;
3493da14cebeSEric Cheng 
3494da14cebeSEric Cheng 	mac_state.ms_state = state;
3495da14cebeSEric Cheng 	mac_state.ms_link = link;
3496da14cebeSEric Cheng 
34974ac67f02SAnurag S. Maskey 	return (dladm_walk_macaddr(handle, linkid, &mac_state,
3498da14cebeSEric Cheng 	    print_phys_mac_callback));
3499da14cebeSEric Cheng }
3500da14cebeSEric Cheng 
3501da14cebeSEric Cheng /* callback of dladm_walk_hwgrp, invoked for each MAC hwgrp */
3502da14cebeSEric Cheng static boolean_t
3503da14cebeSEric Cheng print_phys_hwgrp_callback(void *arg, dladm_hwgrp_attr_t *attr)
3504da14cebeSEric Cheng {
3505da14cebeSEric Cheng 	print_phys_hwgrp_state_t *hwgrp_state = arg;
3506da14cebeSEric Cheng 	show_state_t *state = hwgrp_state->hs_state;
3507da14cebeSEric Cheng 
3508da14cebeSEric Cheng 	if (!state->ls_parseable && !state->ls_printheader) {
3509da14cebeSEric Cheng 		print_header(&state->ls_print);
3510da14cebeSEric Cheng 		state->ls_printheader = B_TRUE;
3511da14cebeSEric Cheng 	}
3512da14cebeSEric Cheng 	hwgrp_state->hs_grp_attr = attr;
3513da14cebeSEric Cheng 	dladm_print_output(&state->ls_print, state->ls_parseable,
3514da14cebeSEric Cheng 	    print_phys_one_hwgrp_callback, hwgrp_state);
3515da14cebeSEric Cheng 
3516da14cebeSEric Cheng 	return (B_TRUE);
3517da14cebeSEric Cheng }
3518da14cebeSEric Cheng 
3519da14cebeSEric Cheng /* invoked by show-phys -H for each physical data-link */
3520da14cebeSEric Cheng static dladm_status_t
3521da14cebeSEric Cheng print_phys_hwgrp(show_state_t *state, datalink_id_t linkid, char *link)
3522da14cebeSEric Cheng {
3523da14cebeSEric Cheng 	print_phys_hwgrp_state_t hwgrp_state;
3524da14cebeSEric Cheng 
3525da14cebeSEric Cheng 	hwgrp_state.hs_state = state;
3526da14cebeSEric Cheng 	hwgrp_state.hs_link = link;
35274ac67f02SAnurag S. Maskey 	return (dladm_walk_hwgrp(handle, linkid, &hwgrp_state,
3528da14cebeSEric Cheng 	    print_phys_hwgrp_callback));
3529da14cebeSEric Cheng }
3530d62bc4baSyz147064 
3531d62bc4baSyz147064 static dladm_status_t
3532da14cebeSEric Cheng print_phys(show_state_t *state, datalink_id_t linkid)
3533d62bc4baSyz147064 {
3534d62bc4baSyz147064 	char			link[MAXLINKNAMELEN];
3535d62bc4baSyz147064 	uint32_t		flags;
3536da14cebeSEric Cheng 	dladm_status_t		status;
3537d62bc4baSyz147064 	datalink_class_t	class;
3538d62bc4baSyz147064 	uint32_t		media;
3539d62bc4baSyz147064 
35404ac67f02SAnurag S. Maskey 	if ((status = dladm_datalink_id2info(handle, linkid, &flags, &class,
35414ac67f02SAnurag S. Maskey 	    &media, link, MAXLINKNAMELEN)) != DLADM_STATUS_OK) {
3542d62bc4baSyz147064 		goto done;
3543d62bc4baSyz147064 	}
3544d62bc4baSyz147064 
3545d62bc4baSyz147064 	if (class != DATALINK_CLASS_PHYS) {
3546d62bc4baSyz147064 		status = DLADM_STATUS_BADARG;
3547d62bc4baSyz147064 		goto done;
3548d62bc4baSyz147064 	}
3549d62bc4baSyz147064 
3550d62bc4baSyz147064 	if (!(state->ls_flags & flags)) {
3551d62bc4baSyz147064 		status = DLADM_STATUS_NOTFOUND;
3552d62bc4baSyz147064 		goto done;
3553d62bc4baSyz147064 	}
3554d62bc4baSyz147064 
3555da14cebeSEric Cheng 	if (state->ls_mac)
3556da14cebeSEric Cheng 		status = print_phys_mac(state, linkid, link);
3557da14cebeSEric Cheng 	else if (state->ls_hwgrp)
3558da14cebeSEric Cheng 		status = print_phys_hwgrp(state, linkid, link);
3559da14cebeSEric Cheng 	else
3560da14cebeSEric Cheng 		status = print_phys_default(state, linkid, link, flags, media);
3561d62bc4baSyz147064 
3562d62bc4baSyz147064 done:
3563d62bc4baSyz147064 	return (status);
3564d62bc4baSyz147064 }
3565d62bc4baSyz147064 
35664ac67f02SAnurag S. Maskey /* ARGSUSED */
3567d62bc4baSyz147064 static int
35684ac67f02SAnurag S. Maskey show_phys(dladm_handle_t dh, datalink_id_t linkid, void *arg)
3569d62bc4baSyz147064 {
3570d62bc4baSyz147064 	show_state_t	*state = arg;
3571d62bc4baSyz147064 
3572da14cebeSEric Cheng 	state->ls_status = print_phys(state, linkid);
3573d62bc4baSyz147064 	return (DLADM_WALK_CONTINUE);
3574d62bc4baSyz147064 }
3575d62bc4baSyz147064 
3576d62bc4baSyz147064 /*
3577d62bc4baSyz147064  * Print the active topology information.
3578d62bc4baSyz147064  */
3579d62bc4baSyz147064 static dladm_status_t
3580e7801d59Ssowmini print_vlan(show_state_t *state, datalink_id_t linkid, link_fields_buf_t *l)
3581d62bc4baSyz147064 {
3582d62bc4baSyz147064 	dladm_vlan_attr_t	vinfo;
3583d62bc4baSyz147064 	uint32_t		flags;
3584d62bc4baSyz147064 	dladm_status_t		status;
3585d62bc4baSyz147064 
35864ac67f02SAnurag S. Maskey 	if ((status = dladm_datalink_id2info(handle, linkid, &flags, NULL, NULL,
3587e7801d59Ssowmini 	    l->link_name, sizeof (l->link_name))) != DLADM_STATUS_OK) {
3588d62bc4baSyz147064 		goto done;
3589d62bc4baSyz147064 	}
3590d62bc4baSyz147064 
3591d62bc4baSyz147064 	if (!(state->ls_flags & flags)) {
3592d62bc4baSyz147064 		status = DLADM_STATUS_NOTFOUND;
3593d62bc4baSyz147064 		goto done;
3594d62bc4baSyz147064 	}
3595d62bc4baSyz147064 
35964ac67f02SAnurag S. Maskey 	if ((status = dladm_vlan_info(handle, linkid, &vinfo,
35974ac67f02SAnurag S. Maskey 	    state->ls_flags)) != DLADM_STATUS_OK ||
35984ac67f02SAnurag S. Maskey 	    (status = dladm_datalink_id2info(handle, vinfo.dv_linkid, NULL,
35994ac67f02SAnurag S. Maskey 	    NULL, NULL, l->link_over, sizeof (l->link_over))) !=
36004ac67f02SAnurag S. Maskey 	    DLADM_STATUS_OK) {
3601d62bc4baSyz147064 		goto done;
3602d62bc4baSyz147064 	}
3603d62bc4baSyz147064 
3604e7801d59Ssowmini 	(void) snprintf(l->link_vlan_vid, sizeof (l->link_vlan_vid), "%d",
3605e7801d59Ssowmini 	    vinfo.dv_vid);
3606da14cebeSEric Cheng 	(void) snprintf(l->link_flags, sizeof (l->link_flags), "%c----",
3607da14cebeSEric Cheng 	    vinfo.dv_force ? 'f' : '-');
3608d62bc4baSyz147064 
3609d62bc4baSyz147064 done:
3610d62bc4baSyz147064 	return (status);
3611d62bc4baSyz147064 }
3612d62bc4baSyz147064 
36134ac67f02SAnurag S. Maskey /* ARGSUSED */
3614d62bc4baSyz147064 static int
36154ac67f02SAnurag S. Maskey show_vlan(dladm_handle_t dh, datalink_id_t linkid, void *arg)
3616d62bc4baSyz147064 {
3617d62bc4baSyz147064 	show_state_t		*state = arg;
3618d62bc4baSyz147064 	dladm_status_t		status;
3619e7801d59Ssowmini 	link_fields_buf_t	lbuf;
3620d62bc4baSyz147064 
36215f5c9f54SAnurag S. Maskey 	bzero(&lbuf, sizeof (link_fields_buf_t));
3622e7801d59Ssowmini 	status = print_vlan(state, linkid, &lbuf);
3623d62bc4baSyz147064 	if (status != DLADM_STATUS_OK)
3624d62bc4baSyz147064 		goto done;
3625e7801d59Ssowmini 
3626e7801d59Ssowmini 	if (!state->ls_parseable && !state->ls_printheader) {
3627e7801d59Ssowmini 		print_header(&state->ls_print);
3628e7801d59Ssowmini 		state->ls_printheader = B_TRUE;
3629e7801d59Ssowmini 	}
3630e7801d59Ssowmini 
3631e7801d59Ssowmini 	dladm_print_output(&state->ls_print, state->ls_parseable,
3632e7801d59Ssowmini 	    dladm_print_field, (void *)&lbuf);
3633d62bc4baSyz147064 
3634d62bc4baSyz147064 done:
3635d62bc4baSyz147064 	state->ls_status = status;
3636d62bc4baSyz147064 	return (DLADM_WALK_CONTINUE);
3637d62bc4baSyz147064 }
3638d62bc4baSyz147064 
3639d62bc4baSyz147064 static void
36408d5c46e6Sam223141 do_show_phys(int argc, char *argv[], const char *use)
3641d62bc4baSyz147064 {
3642d62bc4baSyz147064 	int		option;
3643d62bc4baSyz147064 	uint32_t	flags = DLADM_OPT_ACTIVE;
3644d62bc4baSyz147064 	boolean_t	p_arg = B_FALSE;
3645e7801d59Ssowmini 	boolean_t	o_arg = B_FALSE;
3646da14cebeSEric Cheng 	boolean_t	m_arg = B_FALSE;
3647da14cebeSEric Cheng 	boolean_t	H_arg = B_FALSE;
3648d62bc4baSyz147064 	datalink_id_t	linkid = DATALINK_ALL_LINKID;
3649d62bc4baSyz147064 	show_state_t	state;
3650d62bc4baSyz147064 	dladm_status_t	status;
3651e7801d59Ssowmini 	char		*fields_str = NULL;
3652e7801d59Ssowmini 	print_field_t	**fields;
3653e7801d59Ssowmini 	uint_t		nfields;
3654e7801d59Ssowmini 	char		*all_active_fields =
3655e7801d59Ssowmini 	    "link,media,state,speed,duplex,device";
36565f5c9f54SAnurag S. Maskey 	char		*all_inactive_fields = "link,device,media,flags";
3657da14cebeSEric Cheng 	char		*all_mac_fields = "link,slot,address,inuse,client";
3658da14cebeSEric Cheng 	char		*all_hwgrp_fields =
3659da14cebeSEric Cheng 	    "link,group,grouptype,rings,clients";
3660da14cebeSEric Cheng 	print_field_t	*pf;
3661da14cebeSEric Cheng 	int		pfmax;
3662d62bc4baSyz147064 
3663e7801d59Ssowmini 	bzero(&state, sizeof (state));
3664d62bc4baSyz147064 	opterr = 0;
3665da14cebeSEric Cheng 	while ((option = getopt_long(argc, argv, ":pPo:mH",
3666d62bc4baSyz147064 	    show_lopts, NULL)) != -1) {
3667d62bc4baSyz147064 		switch (option) {
3668d62bc4baSyz147064 		case 'p':
3669d62bc4baSyz147064 			if (p_arg)
3670d62bc4baSyz147064 				die_optdup(option);
3671d62bc4baSyz147064 
3672d62bc4baSyz147064 			p_arg = B_TRUE;
3673d62bc4baSyz147064 			break;
3674d62bc4baSyz147064 		case 'P':
3675d62bc4baSyz147064 			if (flags != DLADM_OPT_ACTIVE)
3676d62bc4baSyz147064 				die_optdup(option);
3677d62bc4baSyz147064 
3678d62bc4baSyz147064 			flags = DLADM_OPT_PERSIST;
3679d62bc4baSyz147064 			break;
3680e7801d59Ssowmini 		case 'o':
3681e7801d59Ssowmini 			o_arg = B_TRUE;
3682e7801d59Ssowmini 			fields_str = optarg;
3683e7801d59Ssowmini 			break;
3684da14cebeSEric Cheng 		case 'm':
3685da14cebeSEric Cheng 			m_arg = B_TRUE;
3686da14cebeSEric Cheng 			break;
3687da14cebeSEric Cheng 		case 'H':
3688da14cebeSEric Cheng 			H_arg = B_TRUE;
3689da14cebeSEric Cheng 			break;
3690d62bc4baSyz147064 		default:
36918d5c46e6Sam223141 			die_opterr(optopt, option, use);
3692d62bc4baSyz147064 			break;
3693d62bc4baSyz147064 		}
3694d62bc4baSyz147064 	}
3695d62bc4baSyz147064 
36960d365605Sschuster 	if (p_arg && !o_arg)
36970d365605Sschuster 		die("-p requires -o");
36980d365605Sschuster 
3699da14cebeSEric Cheng 	if (m_arg && H_arg)
3700da14cebeSEric Cheng 		die("-m cannot combine with -H");
3701da14cebeSEric Cheng 
37020d365605Sschuster 	if (p_arg && strcasecmp(fields_str, "all") == 0)
37030d365605Sschuster 		die("\"-o all\" is invalid with -p");
37040d365605Sschuster 
3705d62bc4baSyz147064 	/* get link name (optional last argument) */
3706d62bc4baSyz147064 	if (optind == (argc-1)) {
37074ac67f02SAnurag S. Maskey 		if ((status = dladm_name2info(handle, argv[optind], &linkid,
37084ac67f02SAnurag S. Maskey 		    NULL, NULL, NULL)) != DLADM_STATUS_OK) {
3709d62bc4baSyz147064 			die_dlerr(status, "link %s is not valid", argv[optind]);
3710d62bc4baSyz147064 		}
3711d62bc4baSyz147064 	} else if (optind != argc) {
3712d62bc4baSyz147064 		usage();
3713d62bc4baSyz147064 	}
3714d62bc4baSyz147064 
3715d62bc4baSyz147064 	state.ls_parseable = p_arg;
3716d62bc4baSyz147064 	state.ls_flags = flags;
3717d62bc4baSyz147064 	state.ls_donefirst = B_FALSE;
3718da14cebeSEric Cheng 	state.ls_mac = m_arg;
3719da14cebeSEric Cheng 	state.ls_hwgrp = H_arg;
3720d62bc4baSyz147064 
3721da14cebeSEric Cheng 	if (m_arg && !(flags & DLADM_OPT_ACTIVE)) {
3722da14cebeSEric Cheng 		/*
3723da14cebeSEric Cheng 		 * We can only display the factory MAC addresses of
3724da14cebeSEric Cheng 		 * active data-links.
3725da14cebeSEric Cheng 		 */
3726da14cebeSEric Cheng 		die("-m not compatible with -P");
3727e7801d59Ssowmini 	}
3728e7801d59Ssowmini 
3729da14cebeSEric Cheng 	if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) {
3730da14cebeSEric Cheng 		if (state.ls_mac)
3731da14cebeSEric Cheng 			fields_str = all_mac_fields;
3732da14cebeSEric Cheng 		else if (state.ls_hwgrp)
3733da14cebeSEric Cheng 			fields_str = all_hwgrp_fields;
3734da14cebeSEric Cheng 		else if (state.ls_flags & DLADM_OPT_ACTIVE) {
3735da14cebeSEric Cheng 			fields_str = all_active_fields;
3736da14cebeSEric Cheng 		} else {
3737da14cebeSEric Cheng 			fields_str = all_inactive_fields;
3738da14cebeSEric Cheng 		}
3739da14cebeSEric Cheng 	}
3740da14cebeSEric Cheng 
3741da14cebeSEric Cheng 	if (state.ls_mac) {
3742da14cebeSEric Cheng 		pf = phys_m_fields;
3743da14cebeSEric Cheng 		pfmax = PHYS_M_MAX_FIELDS;
3744da14cebeSEric Cheng 	} else if (state.ls_hwgrp) {
3745da14cebeSEric Cheng 		pf = phys_h_fields;
3746da14cebeSEric Cheng 		pfmax = PHYS_H_MAX_FIELDS;
3747da14cebeSEric Cheng 	} else {
3748da14cebeSEric Cheng 		pf = phys_fields;
3749da14cebeSEric Cheng 		pfmax = PHYS_MAX_FIELDS;
3750da14cebeSEric Cheng 	}
3751da14cebeSEric Cheng 
3752da14cebeSEric Cheng 	fields = parse_output_fields(fields_str, pf,
3753da14cebeSEric Cheng 	    pfmax, CMD_TYPE_ANY, &nfields);
3754e7801d59Ssowmini 
3755e7801d59Ssowmini 	if (fields == NULL) {
3756e7801d59Ssowmini 		die("invalid field(s) specified");
3757e7801d59Ssowmini 		return;
3758e7801d59Ssowmini 	}
3759e7801d59Ssowmini 
3760e7801d59Ssowmini 	state.ls_print.ps_fields = fields;
3761e7801d59Ssowmini 	state.ls_print.ps_nfields = nfields;
3762e7801d59Ssowmini 
3763d62bc4baSyz147064 	if (linkid == DATALINK_ALL_LINKID) {
37644ac67f02SAnurag S. Maskey 		(void) dladm_walk_datalink_id(show_phys, handle, &state,
3765d62bc4baSyz147064 		    DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE, flags);
3766d62bc4baSyz147064 	} else {
37674ac67f02SAnurag S. Maskey 		(void) show_phys(handle, linkid, &state);
3768d62bc4baSyz147064 		if (state.ls_status != DLADM_STATUS_OK) {
3769d62bc4baSyz147064 			die_dlerr(state.ls_status,
3770d62bc4baSyz147064 			    "failed to show physical link %s", argv[optind]);
3771d62bc4baSyz147064 		}
3772d62bc4baSyz147064 	}
3773d62bc4baSyz147064 }
3774d62bc4baSyz147064 
3775d62bc4baSyz147064 static void
37768d5c46e6Sam223141 do_show_vlan(int argc, char *argv[], const char *use)
3777d62bc4baSyz147064 {
3778d62bc4baSyz147064 	int		option;
3779d62bc4baSyz147064 	uint32_t	flags = DLADM_OPT_ACTIVE;
3780d62bc4baSyz147064 	boolean_t	p_arg = B_FALSE;
3781d62bc4baSyz147064 	datalink_id_t	linkid = DATALINK_ALL_LINKID;
3782d62bc4baSyz147064 	show_state_t	state;
3783d62bc4baSyz147064 	dladm_status_t	status;
3784e7801d59Ssowmini 	boolean_t	o_arg = B_FALSE;
3785e7801d59Ssowmini 	char		*fields_str = NULL;
3786e7801d59Ssowmini 	print_field_t	**fields;
3787e7801d59Ssowmini 	uint_t		nfields;
3788e7801d59Ssowmini 	char		*all_fields = "link,vid,over,flags";
3789e7801d59Ssowmini 
3790e7801d59Ssowmini 	bzero(&state, sizeof (state));
3791d62bc4baSyz147064 
3792d62bc4baSyz147064 	opterr = 0;
3793e7801d59Ssowmini 	while ((option = getopt_long(argc, argv, ":pPo:",
3794d62bc4baSyz147064 	    show_lopts, NULL)) != -1) {
3795d62bc4baSyz147064 		switch (option) {
3796d62bc4baSyz147064 		case 'p':
3797d62bc4baSyz147064 			if (p_arg)
3798d62bc4baSyz147064 				die_optdup(option);
3799d62bc4baSyz147064 
3800d62bc4baSyz147064 			p_arg = B_TRUE;
3801d62bc4baSyz147064 			break;
3802d62bc4baSyz147064 		case 'P':
3803d62bc4baSyz147064 			if (flags != DLADM_OPT_ACTIVE)
3804d62bc4baSyz147064 				die_optdup(option);
3805d62bc4baSyz147064 
3806d62bc4baSyz147064 			flags = DLADM_OPT_PERSIST;
3807d62bc4baSyz147064 			break;
3808e7801d59Ssowmini 		case 'o':
3809e7801d59Ssowmini 			o_arg = B_TRUE;
3810e7801d59Ssowmini 			fields_str = optarg;
3811e7801d59Ssowmini 			break;
3812d62bc4baSyz147064 		default:
38138d5c46e6Sam223141 			die_opterr(optopt, option, use);
3814d62bc4baSyz147064 			break;
3815d62bc4baSyz147064 		}
3816d62bc4baSyz147064 	}
3817d62bc4baSyz147064 
38180d365605Sschuster 	if (p_arg && !o_arg)
38190d365605Sschuster 		die("-p requires -o");
38200d365605Sschuster 
38210d365605Sschuster 	if (p_arg && strcasecmp(fields_str, "all") == 0)
38220d365605Sschuster 		die("\"-o all\" is invalid with -p");
38230d365605Sschuster 
3824d62bc4baSyz147064 	/* get link name (optional last argument) */
3825d62bc4baSyz147064 	if (optind == (argc-1)) {
38264ac67f02SAnurag S. Maskey 		if ((status = dladm_name2info(handle, argv[optind], &linkid,
38274ac67f02SAnurag S. Maskey 		    NULL, NULL, NULL)) != DLADM_STATUS_OK) {
3828d62bc4baSyz147064 			die_dlerr(status, "link %s is not valid", argv[optind]);
3829d62bc4baSyz147064 		}
3830d62bc4baSyz147064 	} else if (optind != argc) {
3831d62bc4baSyz147064 		usage();
3832d62bc4baSyz147064 	}
3833d62bc4baSyz147064 
3834d62bc4baSyz147064 	state.ls_parseable = p_arg;
3835d62bc4baSyz147064 	state.ls_flags = flags;
3836d62bc4baSyz147064 	state.ls_donefirst = B_FALSE;
3837d62bc4baSyz147064 
3838e7801d59Ssowmini 	if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0))
3839e7801d59Ssowmini 		fields_str = all_fields;
3840e7801d59Ssowmini 
3841e7801d59Ssowmini 	fields = parse_output_fields(fields_str, vlan_fields, VLAN_MAX_FIELDS,
3842e7801d59Ssowmini 	    CMD_TYPE_ANY, &nfields);
3843e7801d59Ssowmini 
3844e7801d59Ssowmini 	if (fields == NULL) {
3845e7801d59Ssowmini 		die("invalid field(s) specified");
3846e7801d59Ssowmini 		return;
3847e7801d59Ssowmini 	}
3848e7801d59Ssowmini 	state.ls_print.ps_fields = fields;
3849e7801d59Ssowmini 	state.ls_print.ps_nfields = nfields;
3850e7801d59Ssowmini 
3851d62bc4baSyz147064 	if (linkid == DATALINK_ALL_LINKID) {
38524ac67f02SAnurag S. Maskey 		(void) dladm_walk_datalink_id(show_vlan, handle, &state,
3853d62bc4baSyz147064 		    DATALINK_CLASS_VLAN, DATALINK_ANY_MEDIATYPE, flags);
3854d62bc4baSyz147064 	} else {
38554ac67f02SAnurag S. Maskey 		(void) show_vlan(handle, linkid, &state);
3856d62bc4baSyz147064 		if (state.ls_status != DLADM_STATUS_OK) {
3857d62bc4baSyz147064 			die_dlerr(state.ls_status, "failed to show vlan %s",
3858d62bc4baSyz147064 			    argv[optind]);
3859d62bc4baSyz147064 		}
3860d62bc4baSyz147064 	}
3861d62bc4baSyz147064 }
3862d62bc4baSyz147064 
3863d62bc4baSyz147064 static void
3864da14cebeSEric Cheng do_create_vnic(int argc, char *argv[], const char *use)
3865da14cebeSEric Cheng {
3866da14cebeSEric Cheng 	datalink_id_t		linkid, dev_linkid;
3867da14cebeSEric Cheng 	char			devname[MAXLINKNAMELEN];
3868da14cebeSEric Cheng 	char			name[MAXLINKNAMELEN];
3869da14cebeSEric Cheng 	boolean_t		l_arg = B_FALSE;
3870da14cebeSEric Cheng 	uint32_t		flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
3871da14cebeSEric Cheng 	char			*altroot = NULL;
3872da14cebeSEric Cheng 	char			option;
3873da14cebeSEric Cheng 	char			*endp = NULL;
3874da14cebeSEric Cheng 	dladm_status_t		status;
3875da14cebeSEric Cheng 	vnic_mac_addr_type_t	mac_addr_type = VNIC_MAC_ADDR_TYPE_AUTO;
3876da14cebeSEric Cheng 	uchar_t			*mac_addr;
3877da14cebeSEric Cheng 	int			mac_slot = -1, maclen = 0, mac_prefix_len = 0;
3878*63a6526dSMichael Lim 	char			propstr[DLADM_STRSIZE];
3879da14cebeSEric Cheng 	dladm_arg_list_t	*proplist = NULL;
3880285e94f9SMichael Lim 	int			vid = 0;
3881da14cebeSEric Cheng 
3882da14cebeSEric Cheng 	opterr = 0;
3883*63a6526dSMichael Lim 	bzero(propstr, DLADM_STRSIZE);
3884*63a6526dSMichael Lim 
3885da14cebeSEric Cheng 	while ((option = getopt_long(argc, argv, ":tfR:l:m:n:p:r:v:H",
3886da14cebeSEric Cheng 	    vnic_lopts, NULL)) != -1) {
3887da14cebeSEric Cheng 		switch (option) {
3888da14cebeSEric Cheng 		case 't':
3889da14cebeSEric Cheng 			flags &= ~DLADM_OPT_PERSIST;
3890da14cebeSEric Cheng 			break;
3891da14cebeSEric Cheng 		case 'R':
3892da14cebeSEric Cheng 			altroot = optarg;
3893da14cebeSEric Cheng 			break;
3894da14cebeSEric Cheng 		case 'l':
3895da14cebeSEric Cheng 			if (strlcpy(devname, optarg, MAXLINKNAMELEN) >=
3896da14cebeSEric Cheng 			    MAXLINKNAMELEN)
3897da14cebeSEric Cheng 				die("link name too long");
3898da14cebeSEric Cheng 			l_arg = B_TRUE;
3899da14cebeSEric Cheng 			break;
3900da14cebeSEric Cheng 		case 'm':
3901da14cebeSEric Cheng 			if (strcmp(optarg, "fixed") == 0) {
3902da14cebeSEric Cheng 				/*
3903da14cebeSEric Cheng 				 * A fixed MAC address must be specified
3904da14cebeSEric Cheng 				 * by its value, not by the keyword 'fixed'.
3905da14cebeSEric Cheng 				 */
3906da14cebeSEric Cheng 				die("'fixed' is not a valid MAC address");
3907da14cebeSEric Cheng 			}
3908da14cebeSEric Cheng 			if (dladm_vnic_str2macaddrtype(optarg,
3909da14cebeSEric Cheng 			    &mac_addr_type) != DLADM_STATUS_OK) {
3910da14cebeSEric Cheng 				mac_addr_type = VNIC_MAC_ADDR_TYPE_FIXED;
3911da14cebeSEric Cheng 				/* MAC address specified by value */
3912da14cebeSEric Cheng 				mac_addr = _link_aton(optarg, &maclen);
3913da14cebeSEric Cheng 				if (mac_addr == NULL) {
3914da14cebeSEric Cheng 					if (maclen == -1)
3915da14cebeSEric Cheng 						die("invalid MAC address");
3916da14cebeSEric Cheng 					else
3917da14cebeSEric Cheng 						die("out of memory");
3918da14cebeSEric Cheng 				}
3919da14cebeSEric Cheng 			}
3920da14cebeSEric Cheng 			break;
3921da14cebeSEric Cheng 		case 'n':
3922da14cebeSEric Cheng 			errno = 0;
3923da14cebeSEric Cheng 			mac_slot = (int)strtol(optarg, &endp, 10);
3924da14cebeSEric Cheng 			if (errno != 0 || *endp != '\0')
3925da14cebeSEric Cheng 				die("invalid slot number");
3926da14cebeSEric Cheng 			break;
3927da14cebeSEric Cheng 		case 'p':
3928*63a6526dSMichael Lim 			(void) strlcat(propstr, optarg, DLADM_STRSIZE);
3929*63a6526dSMichael Lim 			if (strlcat(propstr, ",", DLADM_STRSIZE) >=
3930*63a6526dSMichael Lim 			    DLADM_STRSIZE)
3931*63a6526dSMichael Lim 				die("property list too long '%s'", propstr);
3932da14cebeSEric Cheng 			break;
3933da14cebeSEric Cheng 		case 'r':
3934da14cebeSEric Cheng 			mac_addr = _link_aton(optarg, &mac_prefix_len);
3935da14cebeSEric Cheng 			if (mac_addr == NULL) {
3936da14cebeSEric Cheng 				if (mac_prefix_len == -1)
3937da14cebeSEric Cheng 					die("invalid MAC address");
3938da14cebeSEric Cheng 				else
3939da14cebeSEric Cheng 					die("out of memory");
3940da14cebeSEric Cheng 			}
3941da14cebeSEric Cheng 			break;
3942da14cebeSEric Cheng 		case 'v':
3943285e94f9SMichael Lim 			if (vid != 0)
3944285e94f9SMichael Lim 				die_optdup(option);
3945285e94f9SMichael Lim 
3946285e94f9SMichael Lim 			if (!str2int(optarg, &vid) || vid < 1 || vid > 4094)
3947285e94f9SMichael Lim 				die("invalid VLAN identifier '%s'", optarg);
3948285e94f9SMichael Lim 
3949da14cebeSEric Cheng 			break;
3950da14cebeSEric Cheng 		case 'f':
3951da14cebeSEric Cheng 			flags |= DLADM_OPT_FORCE;
3952da14cebeSEric Cheng 			break;
3953da14cebeSEric Cheng 		case 'H':
3954da14cebeSEric Cheng 			flags |= DLADM_OPT_HWRINGS;
3955da14cebeSEric Cheng 			break;
3956da14cebeSEric Cheng 		default:
3957da14cebeSEric Cheng 			die_opterr(optopt, option, use);
3958da14cebeSEric Cheng 		}
3959da14cebeSEric Cheng 	}
3960da14cebeSEric Cheng 
3961da14cebeSEric Cheng 	/*
3962da14cebeSEric Cheng 	 * 'f' - force, flag can be specified only with 'v' - vlan.
3963da14cebeSEric Cheng 	 */
3964da14cebeSEric Cheng 	if ((flags & DLADM_OPT_FORCE) != 0 && vid == 0)
3965da14cebeSEric Cheng 		die("-f option can only be used with -v");
3966da14cebeSEric Cheng 
3967da14cebeSEric Cheng 	if (mac_prefix_len != 0 && mac_addr_type != VNIC_MAC_ADDR_TYPE_RANDOM &&
3968da14cebeSEric Cheng 	    mac_addr_type != VNIC_MAC_ADDR_TYPE_FIXED)
3969da14cebeSEric Cheng 		usage();
3970da14cebeSEric Cheng 
3971da14cebeSEric Cheng 	/* check required options */
3972da14cebeSEric Cheng 	if (!l_arg)
3973da14cebeSEric Cheng 		usage();
3974da14cebeSEric Cheng 
3975da14cebeSEric Cheng 	if (mac_slot != -1 && mac_addr_type != VNIC_MAC_ADDR_TYPE_FACTORY)
3976da14cebeSEric Cheng 		usage();
3977da14cebeSEric Cheng 
3978da14cebeSEric Cheng 	/* the VNIC id is the required operand */
3979da14cebeSEric Cheng 	if (optind != (argc - 1))
3980da14cebeSEric Cheng 		usage();
3981da14cebeSEric Cheng 
3982da14cebeSEric Cheng 	if (strlcpy(name, argv[optind], MAXLINKNAMELEN) >= MAXLINKNAMELEN)
3983da14cebeSEric Cheng 		die("link name too long '%s'", argv[optind]);
3984da14cebeSEric Cheng 
3985da14cebeSEric Cheng 	if (!dladm_valid_linkname(name))
3986da14cebeSEric Cheng 		die("invalid link name '%s'", argv[optind]);
3987da14cebeSEric Cheng 
3988da14cebeSEric Cheng 	if (altroot != NULL)
3989da14cebeSEric Cheng 		altroot_cmd(altroot, argc, argv);
3990da14cebeSEric Cheng 
39914ac67f02SAnurag S. Maskey 	if (dladm_name2info(handle, devname, &dev_linkid, NULL, NULL, NULL) !=
3992da14cebeSEric Cheng 	    DLADM_STATUS_OK)
3993da14cebeSEric Cheng 		die("invalid link name '%s'", devname);
3994da14cebeSEric Cheng 
3995*63a6526dSMichael Lim 	if (dladm_parse_link_props(propstr, &proplist, B_FALSE)
3996*63a6526dSMichael Lim 	    != DLADM_STATUS_OK)
3997*63a6526dSMichael Lim 		die("invalid vnic property");
3998*63a6526dSMichael Lim 
39994ac67f02SAnurag S. Maskey 	status = dladm_vnic_create(handle, name, dev_linkid, mac_addr_type,
40004ac67f02SAnurag S. Maskey 	    mac_addr, maclen, &mac_slot, mac_prefix_len, vid, &linkid, proplist,
40014ac67f02SAnurag S. Maskey 	    flags);
4002da14cebeSEric Cheng 	if (status != DLADM_STATUS_OK)
4003da14cebeSEric Cheng 		die_dlerr(status, "vnic creation over %s failed", devname);
4004da14cebeSEric Cheng 
4005da14cebeSEric Cheng 	dladm_free_props(proplist);
4006da14cebeSEric Cheng }
4007da14cebeSEric Cheng 
4008da14cebeSEric Cheng static void
4009da14cebeSEric Cheng do_etherstub_check(const char *name, datalink_id_t linkid, boolean_t etherstub,
4010da14cebeSEric Cheng     uint32_t flags)
4011da14cebeSEric Cheng {
4012da14cebeSEric Cheng 	boolean_t is_etherstub;
4013da14cebeSEric Cheng 	dladm_vnic_attr_t attr;
4014da14cebeSEric Cheng 
40154ac67f02SAnurag S. Maskey 	if (dladm_vnic_info(handle, linkid, &attr, flags) != DLADM_STATUS_OK) {
4016da14cebeSEric Cheng 		/*
4017da14cebeSEric Cheng 		 * Let the delete continue anyway.
4018da14cebeSEric Cheng 		 */
4019da14cebeSEric Cheng 		return;
4020da14cebeSEric Cheng 	}
4021da14cebeSEric Cheng 	is_etherstub = (attr.va_link_id == DATALINK_INVALID_LINKID);
4022da14cebeSEric Cheng 	if (is_etherstub != etherstub) {
4023da14cebeSEric Cheng 		die("'%s' is not %s", name,
4024da14cebeSEric Cheng 		    (is_etherstub ? "a vnic" : "an etherstub"));
4025da14cebeSEric Cheng 	}
4026da14cebeSEric Cheng }
4027da14cebeSEric Cheng 
4028da14cebeSEric Cheng static void
4029da14cebeSEric Cheng do_delete_vnic_common(int argc, char *argv[], const char *use,
4030da14cebeSEric Cheng     boolean_t etherstub)
4031da14cebeSEric Cheng {
4032da14cebeSEric Cheng 	char option;
4033da14cebeSEric Cheng 	uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
4034da14cebeSEric Cheng 	datalink_id_t linkid;
4035da14cebeSEric Cheng 	char *altroot = NULL;
4036da14cebeSEric Cheng 	dladm_status_t status;
4037da14cebeSEric Cheng 
4038da14cebeSEric Cheng 	opterr = 0;
4039da14cebeSEric Cheng 	while ((option = getopt_long(argc, argv, ":R:t", lopts,
4040da14cebeSEric Cheng 	    NULL)) != -1) {
4041da14cebeSEric Cheng 		switch (option) {
4042da14cebeSEric Cheng 		case 't':
4043da14cebeSEric Cheng 			flags &= ~DLADM_OPT_PERSIST;
4044da14cebeSEric Cheng 			break;
4045da14cebeSEric Cheng 		case 'R':
4046da14cebeSEric Cheng 			altroot = optarg;
4047da14cebeSEric Cheng 			break;
4048da14cebeSEric Cheng 		default:
4049da14cebeSEric Cheng 			die_opterr(optopt, option, use);
4050da14cebeSEric Cheng 		}
4051da14cebeSEric Cheng 	}
4052da14cebeSEric Cheng 
4053da14cebeSEric Cheng 	/* get vnic name (required last argument) */
4054da14cebeSEric Cheng 	if (optind != (argc - 1))
4055da14cebeSEric Cheng 		usage();
4056da14cebeSEric Cheng 
4057da14cebeSEric Cheng 	if (altroot != NULL)
4058da14cebeSEric Cheng 		altroot_cmd(altroot, argc, argv);
4059da14cebeSEric Cheng 
40604ac67f02SAnurag S. Maskey 	status = dladm_name2info(handle, argv[optind], &linkid, NULL, NULL,
40614ac67f02SAnurag S. Maskey 	    NULL);
4062da14cebeSEric Cheng 	if (status != DLADM_STATUS_OK)
4063da14cebeSEric Cheng 		die("invalid link name '%s'", argv[optind]);
4064da14cebeSEric Cheng 
4065da14cebeSEric Cheng 	if ((flags & DLADM_OPT_ACTIVE) != 0) {
4066da14cebeSEric Cheng 		do_etherstub_check(argv[optind], linkid, etherstub,
4067da14cebeSEric Cheng 		    DLADM_OPT_ACTIVE);
4068da14cebeSEric Cheng 	}
4069da14cebeSEric Cheng 	if ((flags & DLADM_OPT_PERSIST) != 0) {
4070da14cebeSEric Cheng 		do_etherstub_check(argv[optind], linkid, etherstub,
4071da14cebeSEric Cheng 		    DLADM_OPT_PERSIST);
4072da14cebeSEric Cheng 	}
4073da14cebeSEric Cheng 
40744ac67f02SAnurag S. Maskey 	status = dladm_vnic_delete(handle, linkid, flags);
4075da14cebeSEric Cheng 	if (status != DLADM_STATUS_OK)
4076da14cebeSEric Cheng 		die_dlerr(status, "vnic deletion failed");
4077da14cebeSEric Cheng }
4078da14cebeSEric Cheng 
4079da14cebeSEric Cheng static void
4080da14cebeSEric Cheng do_delete_vnic(int argc, char *argv[], const char *use)
4081da14cebeSEric Cheng {
4082da14cebeSEric Cheng 	do_delete_vnic_common(argc, argv, use, B_FALSE);
4083da14cebeSEric Cheng }
4084da14cebeSEric Cheng 
4085da14cebeSEric Cheng /* ARGSUSED */
4086da14cebeSEric Cheng static void
4087da14cebeSEric Cheng do_up_vnic_common(int argc, char *argv[], const char *use, boolean_t vlan)
4088da14cebeSEric Cheng {
4089da14cebeSEric Cheng 	datalink_id_t	linkid = DATALINK_ALL_LINKID;
4090da14cebeSEric Cheng 	dladm_status_t	status;
4091da14cebeSEric Cheng 	char 		*type;
4092da14cebeSEric Cheng 
4093da14cebeSEric Cheng 	type = vlan ? "vlan" : "vnic";
4094da14cebeSEric Cheng 
4095da14cebeSEric Cheng 	/*
4096da14cebeSEric Cheng 	 * get the id or the name of the vnic/vlan (optional last argument)
4097da14cebeSEric Cheng 	 */
4098da14cebeSEric Cheng 	if (argc == 2) {
40994ac67f02SAnurag S. Maskey 		status = dladm_name2info(handle, argv[1], &linkid, NULL, NULL,
41004ac67f02SAnurag S. Maskey 		    NULL);
4101da14cebeSEric Cheng 		if (status != DLADM_STATUS_OK)
4102da14cebeSEric Cheng 			goto done;
4103da14cebeSEric Cheng 
4104da14cebeSEric Cheng 	} else if (argc > 2) {
4105da14cebeSEric Cheng 		usage();
4106da14cebeSEric Cheng 	}
4107da14cebeSEric Cheng 
4108da14cebeSEric Cheng 	if (vlan)
41094ac67f02SAnurag S. Maskey 		status = dladm_vlan_up(handle, linkid);
4110da14cebeSEric Cheng 	else
41114ac67f02SAnurag S. Maskey 		status = dladm_vnic_up(handle, linkid, 0);
4112da14cebeSEric Cheng 
4113da14cebeSEric Cheng done:
4114da14cebeSEric Cheng 	if (status != DLADM_STATUS_OK) {
4115da14cebeSEric Cheng 		if (argc == 2) {
4116da14cebeSEric Cheng 			die_dlerr(status,
4117da14cebeSEric Cheng 			    "could not bring up %s '%s'", type, argv[1]);
4118da14cebeSEric Cheng 		} else {
4119da14cebeSEric Cheng 			die_dlerr(status, "could not bring %ss up", type);
4120da14cebeSEric Cheng 		}
4121da14cebeSEric Cheng 	}
4122da14cebeSEric Cheng }
4123da14cebeSEric Cheng 
4124da14cebeSEric Cheng static void
4125da14cebeSEric Cheng do_up_vnic(int argc, char *argv[], const char *use)
4126da14cebeSEric Cheng {
4127da14cebeSEric Cheng 	do_up_vnic_common(argc, argv, use, B_FALSE);
4128da14cebeSEric Cheng }
4129da14cebeSEric Cheng 
4130da14cebeSEric Cheng static void
4131da14cebeSEric Cheng dump_vnics_head(const char *dev)
4132da14cebeSEric Cheng {
4133da14cebeSEric Cheng 	if (strlen(dev))
4134da14cebeSEric Cheng 		(void) printf("%s", dev);
4135da14cebeSEric Cheng 
4136da14cebeSEric Cheng 	(void) printf("\tipackets  rbytes      opackets  obytes          ");
4137da14cebeSEric Cheng 
4138da14cebeSEric Cheng 	if (strlen(dev))
4139da14cebeSEric Cheng 		(void) printf("%%ipkts  %%opkts\n");
4140da14cebeSEric Cheng 	else
4141da14cebeSEric Cheng 		(void) printf("\n");
4142da14cebeSEric Cheng }
4143da14cebeSEric Cheng 
4144da14cebeSEric Cheng static void
4145da14cebeSEric Cheng dump_vnic_stat(const char *name, datalink_id_t vnic_id,
4146da14cebeSEric Cheng     show_vnic_state_t *state, pktsum_t *vnic_stats, pktsum_t *tot_stats)
4147da14cebeSEric Cheng {
4148da14cebeSEric Cheng 	pktsum_t	diff_stats;
4149da14cebeSEric Cheng 	pktsum_t	*old_stats = &state->vs_prevstats[vnic_id];
4150da14cebeSEric Cheng 
4151da14cebeSEric Cheng 	dladm_stats_diff(&diff_stats, vnic_stats, old_stats);
4152da14cebeSEric Cheng 
4153da14cebeSEric Cheng 	(void) printf("%s", name);
4154da14cebeSEric Cheng 
4155da14cebeSEric Cheng 	(void) printf("\t%-10llu", diff_stats.ipackets);
4156da14cebeSEric Cheng 	(void) printf("%-12llu", diff_stats.rbytes);
4157da14cebeSEric Cheng 	(void) printf("%-10llu", diff_stats.opackets);
4158da14cebeSEric Cheng 	(void) printf("%-12llu", diff_stats.obytes);
4159da14cebeSEric Cheng 
4160da14cebeSEric Cheng 	if (tot_stats) {
4161da14cebeSEric Cheng 		if (tot_stats->ipackets == 0) {
4162da14cebeSEric Cheng 			(void) printf("\t-");
4163da14cebeSEric Cheng 		} else {
4164da14cebeSEric Cheng 			(void) printf("\t%-6.1f", (double)diff_stats.ipackets/
4165da14cebeSEric Cheng 			    (double)tot_stats->ipackets * 100);
4166da14cebeSEric Cheng 		}
4167da14cebeSEric Cheng 		if (tot_stats->opackets == 0) {
4168da14cebeSEric Cheng 			(void) printf("\t-");
4169da14cebeSEric Cheng 		} else {
4170da14cebeSEric Cheng 			(void) printf("\t%-6.1f", (double)diff_stats.opackets/
4171da14cebeSEric Cheng 			    (double)tot_stats->opackets * 100);
4172da14cebeSEric Cheng 		}
4173da14cebeSEric Cheng 	}
4174da14cebeSEric Cheng 	(void) printf("\n");
4175da14cebeSEric Cheng 
4176da14cebeSEric Cheng 	*old_stats = *vnic_stats;
4177da14cebeSEric Cheng }
4178da14cebeSEric Cheng 
4179da14cebeSEric Cheng /*
4180da14cebeSEric Cheng  * Called from the walker dladm_vnic_walk_sys() for each vnic to display
4181da14cebeSEric Cheng  * vnic information or statistics.
4182da14cebeSEric Cheng  */
4183da14cebeSEric Cheng static dladm_status_t
4184da14cebeSEric Cheng print_vnic(show_vnic_state_t *state, datalink_id_t linkid)
4185da14cebeSEric Cheng {
4186da14cebeSEric Cheng 	dladm_vnic_attr_t	attr, *vnic = &attr;
4187da14cebeSEric Cheng 	dladm_status_t		status;
4188da14cebeSEric Cheng 	boolean_t		is_etherstub;
4189da14cebeSEric Cheng 	char			devname[MAXLINKNAMELEN];
4190da14cebeSEric Cheng 	char			vnic_name[MAXLINKNAMELEN];
4191da14cebeSEric Cheng 	char			mstr[MAXMACADDRLEN * 3];
4192da14cebeSEric Cheng 	vnic_fields_buf_t	vbuf;
4193da14cebeSEric Cheng 
41944ac67f02SAnurag S. Maskey 	if ((status = dladm_vnic_info(handle, linkid, vnic, state->vs_flags)) !=
4195da14cebeSEric Cheng 	    DLADM_STATUS_OK)
4196da14cebeSEric Cheng 		return (status);
4197da14cebeSEric Cheng 
4198da14cebeSEric Cheng 	is_etherstub = (vnic->va_link_id == DATALINK_INVALID_LINKID);
4199da14cebeSEric Cheng 	if (state->vs_etherstub != is_etherstub) {
4200da14cebeSEric Cheng 		/*
4201da14cebeSEric Cheng 		 * Want all etherstub but it's not one, or want
4202da14cebeSEric Cheng 		 * non-etherstub and it's one.
4203da14cebeSEric Cheng 		 */
4204da14cebeSEric Cheng 		return (DLADM_STATUS_OK);
4205da14cebeSEric Cheng 	}
4206da14cebeSEric Cheng 
4207da14cebeSEric Cheng 	if (state->vs_link_id != DATALINK_ALL_LINKID) {
4208da14cebeSEric Cheng 		if (state->vs_link_id != vnic->va_link_id)
4209da14cebeSEric Cheng 			return (DLADM_STATUS_OK);
4210da14cebeSEric Cheng 	}
4211da14cebeSEric Cheng 
42124ac67f02SAnurag S. Maskey 	if (dladm_datalink_id2info(handle, linkid, NULL, NULL,
4213da14cebeSEric Cheng 	    NULL, vnic_name, sizeof (vnic_name)) != DLADM_STATUS_OK)
4214da14cebeSEric Cheng 		return (DLADM_STATUS_BADARG);
4215da14cebeSEric Cheng 
4216da14cebeSEric Cheng 	bzero(devname, sizeof (devname));
4217da14cebeSEric Cheng 	if (!is_etherstub &&
42184ac67f02SAnurag S. Maskey 	    dladm_datalink_id2info(handle, vnic->va_link_id, NULL, NULL,
4219da14cebeSEric Cheng 	    NULL, devname, sizeof (devname)) != DLADM_STATUS_OK)
4220da14cebeSEric Cheng 		return (DLADM_STATUS_BADARG);
4221da14cebeSEric Cheng 
4222da14cebeSEric Cheng 	state->vs_found = B_TRUE;
4223da14cebeSEric Cheng 	if (state->vs_stats) {
4224da14cebeSEric Cheng 		/* print vnic statistics */
4225da14cebeSEric Cheng 		pktsum_t vnic_stats;
4226da14cebeSEric Cheng 
4227da14cebeSEric Cheng 		if (state->vs_firstonly) {
4228da14cebeSEric Cheng 			if (state->vs_donefirst)
4229da14cebeSEric Cheng 				return (0);
4230da14cebeSEric Cheng 			state->vs_donefirst = B_TRUE;
4231da14cebeSEric Cheng 		}
4232da14cebeSEric Cheng 
4233da14cebeSEric Cheng 		if (!state->vs_printstats) {
4234da14cebeSEric Cheng 			/*
4235da14cebeSEric Cheng 			 * get vnic statistics and add to the sum for the
4236da14cebeSEric Cheng 			 * named device.
4237da14cebeSEric Cheng 			 */
4238da14cebeSEric Cheng 			get_link_stats(vnic_name, &vnic_stats);
4239da14cebeSEric Cheng 			dladm_stats_total(&state->vs_totalstats, &vnic_stats,
4240da14cebeSEric Cheng 			    &state->vs_prevstats[vnic->va_vnic_id]);
4241da14cebeSEric Cheng 		} else {
4242da14cebeSEric Cheng 			/* get and print vnic statistics */
4243da14cebeSEric Cheng 			get_link_stats(vnic_name, &vnic_stats);
4244da14cebeSEric Cheng 			dump_vnic_stat(vnic_name, linkid, state, &vnic_stats,
4245da14cebeSEric Cheng 			    &state->vs_totalstats);
4246da14cebeSEric Cheng 		}
4247da14cebeSEric Cheng 		return (DLADM_STATUS_OK);
4248da14cebeSEric Cheng 	} else {
4249da14cebeSEric Cheng 		(void) snprintf(vbuf.vnic_link, sizeof (vbuf.vnic_link),
4250da14cebeSEric Cheng 		    "%s", vnic_name);
4251da14cebeSEric Cheng 
4252da14cebeSEric Cheng 		if (!is_etherstub) {
4253da14cebeSEric Cheng 
4254da14cebeSEric Cheng 			(void) snprintf(vbuf.vnic_over, sizeof (vbuf.vnic_over),
4255da14cebeSEric Cheng 			    "%s", devname);
4256da14cebeSEric Cheng 			(void) snprintf(vbuf.vnic_speed,
4257da14cebeSEric Cheng 			    sizeof (vbuf.vnic_speed), "%u",
4258da14cebeSEric Cheng 			    (uint_t)((get_ifspeed(vnic_name, B_TRUE))
4259da14cebeSEric Cheng 			    / 1000000ull));
4260da14cebeSEric Cheng 
4261da14cebeSEric Cheng 			switch (vnic->va_mac_addr_type) {
4262da14cebeSEric Cheng 			case VNIC_MAC_ADDR_TYPE_FIXED:
4263da14cebeSEric Cheng 			case VNIC_MAC_ADDR_TYPE_PRIMARY:
4264da14cebeSEric Cheng 				(void) snprintf(vbuf.vnic_macaddrtype,
4265da14cebeSEric Cheng 				    sizeof (vbuf.vnic_macaddrtype),
4266da14cebeSEric Cheng 				    gettext("fixed"));
4267da14cebeSEric Cheng 				break;
4268da14cebeSEric Cheng 			case VNIC_MAC_ADDR_TYPE_RANDOM:
4269da14cebeSEric Cheng 				(void) snprintf(vbuf.vnic_macaddrtype,
4270da14cebeSEric Cheng 				    sizeof (vbuf.vnic_macaddrtype),
4271da14cebeSEric Cheng 				    gettext("random"));
4272da14cebeSEric Cheng 				break;
4273da14cebeSEric Cheng 			case VNIC_MAC_ADDR_TYPE_FACTORY:
4274da14cebeSEric Cheng 				(void) snprintf(vbuf.vnic_macaddrtype,
4275da14cebeSEric Cheng 				    sizeof (vbuf.vnic_macaddrtype),
4276da14cebeSEric Cheng 				    gettext("factory, slot %d"),
4277da14cebeSEric Cheng 				    vnic->va_mac_slot);
4278da14cebeSEric Cheng 				break;
4279da14cebeSEric Cheng 			}
4280da14cebeSEric Cheng 
4281da14cebeSEric Cheng 			if (strlen(vbuf.vnic_macaddrtype) > 0) {
4282da14cebeSEric Cheng 				(void) snprintf(vbuf.vnic_macaddr,
4283da14cebeSEric Cheng 				    sizeof (vbuf.vnic_macaddr), "%s",
4284da14cebeSEric Cheng 				    dladm_aggr_macaddr2str(vnic->va_mac_addr,
4285da14cebeSEric Cheng 				    mstr));
4286da14cebeSEric Cheng 			}
4287da14cebeSEric Cheng 
4288da14cebeSEric Cheng 			(void) snprintf(vbuf.vnic_vid, sizeof (vbuf.vnic_vid),
4289da14cebeSEric Cheng 			    "%d", vnic->va_vid);
4290da14cebeSEric Cheng 		}
4291da14cebeSEric Cheng 
4292da14cebeSEric Cheng 		if (!state->vs_parseable && !state->vs_printheader) {
4293da14cebeSEric Cheng 			print_header(&state->vs_print);
4294da14cebeSEric Cheng 			state->vs_printheader = B_TRUE;
4295da14cebeSEric Cheng 		}
4296da14cebeSEric Cheng 
4297da14cebeSEric Cheng 		dladm_print_output(&state->vs_print, state->vs_parseable,
4298da14cebeSEric Cheng 		    dladm_print_field, (void *)&vbuf);
4299da14cebeSEric Cheng 
4300da14cebeSEric Cheng 		return (DLADM_STATUS_OK);
4301da14cebeSEric Cheng 	}
4302da14cebeSEric Cheng }
4303da14cebeSEric Cheng 
43044ac67f02SAnurag S. Maskey /* ARGSUSED */
4305da14cebeSEric Cheng static int
43064ac67f02SAnurag S. Maskey show_vnic(dladm_handle_t dh, datalink_id_t linkid, void *arg)
4307da14cebeSEric Cheng {
4308da14cebeSEric Cheng 	show_vnic_state_t	*state = arg;
4309da14cebeSEric Cheng 
4310da14cebeSEric Cheng 	state->vs_status = print_vnic(state, linkid);
4311da14cebeSEric Cheng 	return (DLADM_WALK_CONTINUE);
4312da14cebeSEric Cheng }
4313da14cebeSEric Cheng 
4314da14cebeSEric Cheng static void
4315da14cebeSEric Cheng do_show_vnic_common(int argc, char *argv[], const char *use,
4316da14cebeSEric Cheng     boolean_t etherstub)
4317da14cebeSEric Cheng {
4318da14cebeSEric Cheng 	int			option;
4319da14cebeSEric Cheng 	boolean_t		s_arg = B_FALSE;
4320da14cebeSEric Cheng 	boolean_t		i_arg = B_FALSE;
4321da14cebeSEric Cheng 	boolean_t		l_arg = B_FALSE;
4322da14cebeSEric Cheng 	uint32_t		interval = 0, flags = DLADM_OPT_ACTIVE;
4323da14cebeSEric Cheng 	datalink_id_t		linkid = DATALINK_ALL_LINKID;
4324da14cebeSEric Cheng 	datalink_id_t		dev_linkid = DATALINK_ALL_LINKID;
4325da14cebeSEric Cheng 	show_vnic_state_t	state;
4326da14cebeSEric Cheng 	dladm_status_t		status;
4327da14cebeSEric Cheng 	boolean_t		o_arg = B_FALSE;
4328da14cebeSEric Cheng 	char			*fields_str = NULL;
4329da14cebeSEric Cheng 	print_field_t  		**fields;
4330da14cebeSEric Cheng 	print_field_t		*pf;
4331da14cebeSEric Cheng 	int			pfmax;
4332da14cebeSEric Cheng 	uint_t			nfields;
4333da14cebeSEric Cheng 	char			*all_fields =
4334ae6aa22aSVenugopal Iyer 	    "link,over,speed,macaddress,macaddrtype,vid";
4335da14cebeSEric Cheng 	char			*all_e_fields =
4336da14cebeSEric Cheng 	    "link";
4337da14cebeSEric Cheng 
4338da14cebeSEric Cheng 	bzero(&state, sizeof (state));
4339da14cebeSEric Cheng 	opterr = 0;
4340da14cebeSEric Cheng 	while ((option = getopt_long(argc, argv, ":pPl:si:o:", lopts,
4341da14cebeSEric Cheng 	    NULL)) != -1) {
4342da14cebeSEric Cheng 		switch (option) {
4343da14cebeSEric Cheng 		case 'p':
4344da14cebeSEric Cheng 			state.vs_parseable = B_TRUE;
4345da14cebeSEric Cheng 			break;
4346da14cebeSEric Cheng 		case 'P':
4347da14cebeSEric Cheng 			flags = DLADM_OPT_PERSIST;
4348da14cebeSEric Cheng 			break;
4349da14cebeSEric Cheng 		case 'l':
4350da14cebeSEric Cheng 			if (etherstub)
4351da14cebeSEric Cheng 				die("option not supported for this command");
4352da14cebeSEric Cheng 
4353da14cebeSEric Cheng 			if (strlcpy(state.vs_link, optarg, MAXLINKNAMELEN) >=
4354da14cebeSEric Cheng 			    MAXLINKNAMELEN)
4355da14cebeSEric Cheng 				die("link name too long");
4356da14cebeSEric Cheng 
4357da14cebeSEric Cheng 			l_arg = B_TRUE;
4358da14cebeSEric Cheng 			break;
4359da14cebeSEric Cheng 		case 's':
4360da14cebeSEric Cheng 			if (s_arg) {
4361da14cebeSEric Cheng 				die("the option -s cannot be specified "
4362da14cebeSEric Cheng 				    "more than once");
4363da14cebeSEric Cheng 			}
4364da14cebeSEric Cheng 			s_arg = B_TRUE;
4365da14cebeSEric Cheng 			break;
4366da14cebeSEric Cheng 		case 'i':
4367da14cebeSEric Cheng 			if (i_arg) {
4368da14cebeSEric Cheng 				die("the option -i cannot be specified "
4369da14cebeSEric Cheng 				    "more than once");
4370da14cebeSEric Cheng 			}
4371da14cebeSEric Cheng 			i_arg = B_TRUE;
4372*63a6526dSMichael Lim 			if (!dladm_str2interval(optarg, &interval))
4373da14cebeSEric Cheng 				die("invalid interval value '%s'", optarg);
4374da14cebeSEric Cheng 			break;
4375da14cebeSEric Cheng 		case 'o':
4376da14cebeSEric Cheng 			o_arg = B_TRUE;
4377da14cebeSEric Cheng 			fields_str = optarg;
4378da14cebeSEric Cheng 			break;
4379da14cebeSEric Cheng 		default:
4380da14cebeSEric Cheng 			die_opterr(optopt, option, use);
4381da14cebeSEric Cheng 		}
4382da14cebeSEric Cheng 	}
4383da14cebeSEric Cheng 
4384ad091ee1SMichael Lim 	if (state.vs_parseable && !o_arg)
4385ad091ee1SMichael Lim 		die("-p requires -o");
4386ad091ee1SMichael Lim 
4387ad091ee1SMichael Lim 	if (state.vs_parseable && strcasecmp(fields_str, "all") == 0)
4388ad091ee1SMichael Lim 		die("\"-o all\" is invalid with -p");
4389ad091ee1SMichael Lim 
4390da14cebeSEric Cheng 	if (i_arg && !s_arg)
4391da14cebeSEric Cheng 		die("the option -i can be used only with -s");
4392da14cebeSEric Cheng 
4393da14cebeSEric Cheng 	/* get vnic ID (optional last argument) */
4394da14cebeSEric Cheng 	if (optind == (argc - 1)) {
43954ac67f02SAnurag S. Maskey 		status = dladm_name2info(handle, argv[optind], &linkid, NULL,
4396da14cebeSEric Cheng 		    NULL, NULL);
4397da14cebeSEric Cheng 		if (status != DLADM_STATUS_OK) {
4398da14cebeSEric Cheng 			die_dlerr(status, "invalid vnic name '%s'",
4399da14cebeSEric Cheng 			    argv[optind]);
4400da14cebeSEric Cheng 		}
4401da14cebeSEric Cheng 		(void) strlcpy(state.vs_vnic, argv[optind], MAXLINKNAMELEN);
4402da14cebeSEric Cheng 	} else if (optind != argc) {
4403da14cebeSEric Cheng 		usage();
4404da14cebeSEric Cheng 	}
4405da14cebeSEric Cheng 
4406da14cebeSEric Cheng 	if (l_arg) {
44074ac67f02SAnurag S. Maskey 		status = dladm_name2info(handle, state.vs_link, &dev_linkid,
44084ac67f02SAnurag S. Maskey 		    NULL, NULL, NULL);
4409da14cebeSEric Cheng 		if (status != DLADM_STATUS_OK) {
4410da14cebeSEric Cheng 			die_dlerr(status, "invalid link name '%s'",
4411da14cebeSEric Cheng 			    state.vs_link);
4412da14cebeSEric Cheng 		}
4413da14cebeSEric Cheng 	}
4414da14cebeSEric Cheng 
4415da14cebeSEric Cheng 	state.vs_vnic_id = linkid;
4416da14cebeSEric Cheng 	state.vs_link_id = dev_linkid;
4417da14cebeSEric Cheng 	state.vs_etherstub = etherstub;
4418da14cebeSEric Cheng 	state.vs_found = B_FALSE;
4419da14cebeSEric Cheng 	state.vs_flags = flags;
4420da14cebeSEric Cheng 
4421da14cebeSEric Cheng 	if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) {
4422da14cebeSEric Cheng 		if (etherstub)
4423da14cebeSEric Cheng 			fields_str = all_e_fields;
4424da14cebeSEric Cheng 		else
4425da14cebeSEric Cheng 			fields_str = all_fields;
4426da14cebeSEric Cheng 	}
4427da14cebeSEric Cheng 
4428da14cebeSEric Cheng 	pf = vnic_fields;
4429da14cebeSEric Cheng 	pfmax = VNIC_MAX_FIELDS;
4430da14cebeSEric Cheng 
4431da14cebeSEric Cheng 	fields = parse_output_fields(fields_str, pf, pfmax, CMD_TYPE_ANY,
4432da14cebeSEric Cheng 	    &nfields);
4433da14cebeSEric Cheng 
4434da14cebeSEric Cheng 	if (fields == NULL) {
4435da14cebeSEric Cheng 		die("invalid field(s) specified");
4436da14cebeSEric Cheng 		return;
4437da14cebeSEric Cheng 	}
4438da14cebeSEric Cheng 
4439da14cebeSEric Cheng 	state.vs_print.ps_fields = fields;
4440da14cebeSEric Cheng 	state.vs_print.ps_nfields = nfields;
4441da14cebeSEric Cheng 
4442da14cebeSEric Cheng 	if (s_arg) {
4443da14cebeSEric Cheng 		/* Display vnic statistics */
4444da14cebeSEric Cheng 		vnic_stats(&state, interval);
4445da14cebeSEric Cheng 		return;
4446da14cebeSEric Cheng 	}
4447da14cebeSEric Cheng 
4448da14cebeSEric Cheng 	/* Display vnic information */
4449da14cebeSEric Cheng 	state.vs_donefirst = B_FALSE;
4450da14cebeSEric Cheng 
4451da14cebeSEric Cheng 	if (linkid == DATALINK_ALL_LINKID) {
44524ac67f02SAnurag S. Maskey 		(void) dladm_walk_datalink_id(show_vnic, handle, &state,
4453da14cebeSEric Cheng 		    DATALINK_CLASS_VNIC | DATALINK_CLASS_ETHERSTUB,
4454da14cebeSEric Cheng 		    DATALINK_ANY_MEDIATYPE, DLADM_OPT_ACTIVE);
4455da14cebeSEric Cheng 	} else {
44564ac67f02SAnurag S. Maskey 		(void) show_vnic(handle, linkid, &state);
4457da14cebeSEric Cheng 		if (state.vs_status != DLADM_STATUS_OK) {
4458da14cebeSEric Cheng 			die_dlerr(state.vs_status, "failed to show vnic '%s'",
4459da14cebeSEric Cheng 			    state.vs_vnic);
4460da14cebeSEric Cheng 		}
4461da14cebeSEric Cheng 	}
4462da14cebeSEric Cheng }
4463da14cebeSEric Cheng 
4464da14cebeSEric Cheng static void
4465da14cebeSEric Cheng do_show_vnic(int argc, char *argv[], const char *use)
4466da14cebeSEric Cheng {
4467da14cebeSEric Cheng 	do_show_vnic_common(argc, argv, use, B_FALSE);
4468da14cebeSEric Cheng }
4469da14cebeSEric Cheng 
4470da14cebeSEric Cheng static void
4471da14cebeSEric Cheng do_create_etherstub(int argc, char *argv[], const char *use)
4472da14cebeSEric Cheng {
4473da14cebeSEric Cheng 	uint32_t flags;
4474da14cebeSEric Cheng 	char *altroot = NULL;
4475da14cebeSEric Cheng 	char option;
4476da14cebeSEric Cheng 	dladm_status_t status;
4477da14cebeSEric Cheng 	char name[MAXLINKNAMELEN];
4478da14cebeSEric Cheng 	uchar_t mac_addr[ETHERADDRL];
4479da14cebeSEric Cheng 
4480da14cebeSEric Cheng 	name[0] = '\0';
4481da14cebeSEric Cheng 	bzero(mac_addr, sizeof (mac_addr));
4482da14cebeSEric Cheng 	flags = DLADM_OPT_ANCHOR | DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
4483da14cebeSEric Cheng 
4484da14cebeSEric Cheng 	opterr = 0;
4485da14cebeSEric Cheng 	while ((option = getopt_long(argc, argv, "tR:",
4486da14cebeSEric Cheng 	    etherstub_lopts, NULL)) != -1) {
4487da14cebeSEric Cheng 		switch (option) {
4488da14cebeSEric Cheng 		case 't':
4489da14cebeSEric Cheng 			flags &= ~DLADM_OPT_PERSIST;
4490da14cebeSEric Cheng 			break;
4491da14cebeSEric Cheng 		case 'R':
4492da14cebeSEric Cheng 			altroot = optarg;
4493da14cebeSEric Cheng 			break;
4494da14cebeSEric Cheng 		default:
4495da14cebeSEric Cheng 			die_opterr(optopt, option, use);
4496da14cebeSEric Cheng 		}
4497da14cebeSEric Cheng 	}
4498da14cebeSEric Cheng 
4499da14cebeSEric Cheng 	/* the etherstub id is the required operand */
4500da14cebeSEric Cheng 	if (optind != (argc - 1))
4501da14cebeSEric Cheng 		usage();
4502da14cebeSEric Cheng 
4503da14cebeSEric Cheng 	if (strlcpy(name, argv[optind], MAXLINKNAMELEN) >= MAXLINKNAMELEN)
4504da14cebeSEric Cheng 		die("link name too long '%s'", argv[optind]);
4505da14cebeSEric Cheng 
4506da14cebeSEric Cheng 	if (!dladm_valid_linkname(name))
4507da14cebeSEric Cheng 		die("invalid link name '%s'", argv[optind]);
4508da14cebeSEric Cheng 
4509da14cebeSEric Cheng 	if (altroot != NULL)
4510da14cebeSEric Cheng 		altroot_cmd(altroot, argc, argv);
4511da14cebeSEric Cheng 
45124ac67f02SAnurag S. Maskey 	status = dladm_vnic_create(handle, name, DATALINK_INVALID_LINKID,
4513da14cebeSEric Cheng 	    VNIC_MAC_ADDR_TYPE_AUTO, mac_addr, ETHERADDRL, NULL, 0, 0, NULL,
4514da14cebeSEric Cheng 	    NULL, flags);
4515da14cebeSEric Cheng 	if (status != DLADM_STATUS_OK)
4516da14cebeSEric Cheng 		die_dlerr(status, "etherstub creation failed");
4517da14cebeSEric Cheng 
4518da14cebeSEric Cheng 
4519da14cebeSEric Cheng }
4520da14cebeSEric Cheng 
4521da14cebeSEric Cheng static void
4522da14cebeSEric Cheng do_delete_etherstub(int argc, char *argv[], const char *use)
4523da14cebeSEric Cheng {
4524da14cebeSEric Cheng 	do_delete_vnic_common(argc, argv, use, B_TRUE);
4525da14cebeSEric Cheng }
4526da14cebeSEric Cheng 
4527da14cebeSEric Cheng /* ARGSUSED */
4528da14cebeSEric Cheng static void
4529da14cebeSEric Cheng do_show_etherstub(int argc, char *argv[], const char *use)
4530da14cebeSEric Cheng {
4531da14cebeSEric Cheng 	do_show_vnic_common(argc, argv, use, B_TRUE);
4532da14cebeSEric Cheng }
4533da14cebeSEric Cheng 
4534da14cebeSEric Cheng static void
45356be03d0bSVasumathi Sundaram - Sun Microsystems link_stats(datalink_id_t linkid, uint_t interval, char *fields_str,
45366be03d0bSVasumathi Sundaram - Sun Microsystems     show_state_t *state)
4537d62bc4baSyz147064 {
45386be03d0bSVasumathi Sundaram - Sun Microsystems 	print_field_t	**fields;
45396be03d0bSVasumathi Sundaram - Sun Microsystems 	uint_t		nfields;
454033343a97Smeem 
4541ae6aa22aSVenugopal Iyer 	fields = parse_output_fields(fields_str, link_s_fields,
4542ae6aa22aSVenugopal Iyer 	    LINK_S_MAX_FIELDS, CMD_TYPE_ANY, &nfields);
45436be03d0bSVasumathi Sundaram - Sun Microsystems 	if (fields == NULL) {
45446be03d0bSVasumathi Sundaram - Sun Microsystems 		die("invalid field(s) specified");
45456be03d0bSVasumathi Sundaram - Sun Microsystems 		return;
45466be03d0bSVasumathi Sundaram - Sun Microsystems 	}
45476be03d0bSVasumathi Sundaram - Sun Microsystems 
45486be03d0bSVasumathi Sundaram - Sun Microsystems 	state->ls_print.ps_fields = fields;
45496be03d0bSVasumathi Sundaram - Sun Microsystems 	state->ls_print.ps_nfields = nfields;
45507c478bd9Sstevel@tonic-gate 
45517c478bd9Sstevel@tonic-gate 	/*
45527c478bd9Sstevel@tonic-gate 	 * If an interval is specified, continuously show the stats
45537c478bd9Sstevel@tonic-gate 	 * only for the first MAC port.
45547c478bd9Sstevel@tonic-gate 	 */
45556be03d0bSVasumathi Sundaram - Sun Microsystems 	state->ls_firstonly = (interval != 0);
45567c478bd9Sstevel@tonic-gate 
45576be03d0bSVasumathi Sundaram - Sun Microsystems 	if (!state->ls_parseable)
45586be03d0bSVasumathi Sundaram - Sun Microsystems 		print_header(&state->ls_print);
45597c478bd9Sstevel@tonic-gate 	for (;;) {
45606be03d0bSVasumathi Sundaram - Sun Microsystems 		state->ls_donefirst = B_FALSE;
4561d62bc4baSyz147064 		if (linkid == DATALINK_ALL_LINKID) {
45624ac67f02SAnurag S. Maskey 			(void) dladm_walk_datalink_id(show_link_stats, handle,
45634ac67f02SAnurag S. Maskey 			    state, DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE,
4564d62bc4baSyz147064 			    DLADM_OPT_ACTIVE);
4565d62bc4baSyz147064 		} else {
45664ac67f02SAnurag S. Maskey 			(void) show_link_stats(handle, linkid, state);
4567d62bc4baSyz147064 		}
45687c478bd9Sstevel@tonic-gate 
45697c478bd9Sstevel@tonic-gate 		if (interval == 0)
45707c478bd9Sstevel@tonic-gate 			break;
45717c478bd9Sstevel@tonic-gate 
45727c478bd9Sstevel@tonic-gate 		(void) sleep(interval);
45737c478bd9Sstevel@tonic-gate 	}
45747c478bd9Sstevel@tonic-gate }
45757c478bd9Sstevel@tonic-gate 
45767c478bd9Sstevel@tonic-gate static void
4577d62bc4baSyz147064 aggr_stats(datalink_id_t linkid, show_grp_state_t *state, uint_t interval)
45787c478bd9Sstevel@tonic-gate {
45797c478bd9Sstevel@tonic-gate 	/*
45807c478bd9Sstevel@tonic-gate 	 * If an interval is specified, continuously show the stats
45817c478bd9Sstevel@tonic-gate 	 * only for the first group.
45827c478bd9Sstevel@tonic-gate 	 */
4583d62bc4baSyz147064 	state->gs_firstonly = (interval != 0);
45847c478bd9Sstevel@tonic-gate 
45857c478bd9Sstevel@tonic-gate 	for (;;) {
4586d62bc4baSyz147064 		state->gs_donefirst = B_FALSE;
4587d62bc4baSyz147064 		if (linkid == DATALINK_ALL_LINKID)
45884ac67f02SAnurag S. Maskey 			(void) dladm_walk_datalink_id(show_aggr, handle, state,
4589d62bc4baSyz147064 			    DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE,
4590d62bc4baSyz147064 			    DLADM_OPT_ACTIVE);
4591d62bc4baSyz147064 		else
45924ac67f02SAnurag S. Maskey 			(void) show_aggr(handle, linkid, state);
45937c478bd9Sstevel@tonic-gate 
45947c478bd9Sstevel@tonic-gate 		if (interval == 0)
45957c478bd9Sstevel@tonic-gate 			break;
45967c478bd9Sstevel@tonic-gate 
45977c478bd9Sstevel@tonic-gate 		(void) sleep(interval);
45987c478bd9Sstevel@tonic-gate 	}
45997c478bd9Sstevel@tonic-gate }
46007c478bd9Sstevel@tonic-gate 
4601da14cebeSEric Cheng /* ARGSUSED */
46027c478bd9Sstevel@tonic-gate static void
4603da14cebeSEric Cheng vnic_stats(show_vnic_state_t *sp, uint32_t interval)
46047c478bd9Sstevel@tonic-gate {
4605da14cebeSEric Cheng 	show_vnic_state_t	state;
4606da14cebeSEric Cheng 	boolean_t		specific_link, specific_dev;
46077c478bd9Sstevel@tonic-gate 
4608da14cebeSEric Cheng 	/* Display vnic statistics */
4609da14cebeSEric Cheng 	dump_vnics_head(sp->vs_link);
4610e7801d59Ssowmini 
4611da14cebeSEric Cheng 	bzero(&state, sizeof (state));
4612da14cebeSEric Cheng 	state.vs_stats = B_TRUE;
4613da14cebeSEric Cheng 	state.vs_vnic_id = sp->vs_vnic_id;
4614da14cebeSEric Cheng 	state.vs_link_id = sp->vs_link_id;
46157c478bd9Sstevel@tonic-gate 
46167c478bd9Sstevel@tonic-gate 	/*
4617da14cebeSEric Cheng 	 * If an interval is specified, and a vnic ID is not specified,
4618da14cebeSEric Cheng 	 * continuously show the stats only for the first vnic.
46197c478bd9Sstevel@tonic-gate 	 */
4620da14cebeSEric Cheng 	specific_link = (sp->vs_vnic_id != DATALINK_ALL_LINKID);
4621da14cebeSEric Cheng 	specific_dev = (sp->vs_link_id != DATALINK_ALL_LINKID);
46227c478bd9Sstevel@tonic-gate 
46237c478bd9Sstevel@tonic-gate 	for (;;) {
4624da14cebeSEric Cheng 		/* Get stats for each vnic */
4625da14cebeSEric Cheng 		state.vs_found = B_FALSE;
4626da14cebeSEric Cheng 		state.vs_donefirst = B_FALSE;
4627da14cebeSEric Cheng 		state.vs_printstats = B_FALSE;
4628da14cebeSEric Cheng 		state.vs_flags = DLADM_OPT_ACTIVE;
46297c478bd9Sstevel@tonic-gate 
4630da14cebeSEric Cheng 		if (!specific_link) {
46314ac67f02SAnurag S. Maskey 			(void) dladm_walk_datalink_id(show_vnic, handle, &state,
4632da14cebeSEric Cheng 			    DATALINK_CLASS_VNIC, DATALINK_ANY_MEDIATYPE,
4633da14cebeSEric Cheng 			    DLADM_OPT_ACTIVE);
4634da14cebeSEric Cheng 		} else {
46354ac67f02SAnurag S. Maskey 			(void) show_vnic(handle, sp->vs_vnic_id, &state);
4636da14cebeSEric Cheng 			if (state.vs_status != DLADM_STATUS_OK) {
4637da14cebeSEric Cheng 				die_dlerr(state.vs_status,
4638da14cebeSEric Cheng 				    "failed to show vnic '%s'", sp->vs_vnic);
4639da14cebeSEric Cheng 			}
4640da14cebeSEric Cheng 		}
46417c478bd9Sstevel@tonic-gate 
4642da14cebeSEric Cheng 		if (specific_link && !state.vs_found)
4643da14cebeSEric Cheng 			die("non-existent vnic '%s'", sp->vs_vnic);
4644da14cebeSEric Cheng 		if (specific_dev && !state.vs_found)
4645da14cebeSEric Cheng 			die("device %s has no vnics", sp->vs_link);
4646da14cebeSEric Cheng 
4647da14cebeSEric Cheng 		/* Show totals */
4648da14cebeSEric Cheng 		if ((specific_link | specific_dev) && !interval) {
4649da14cebeSEric Cheng 			(void) printf("Total");
4650da14cebeSEric Cheng 			(void) printf("\t%-10llu",
4651da14cebeSEric Cheng 			    state.vs_totalstats.ipackets);
4652da14cebeSEric Cheng 			(void) printf("%-12llu",
4653da14cebeSEric Cheng 			    state.vs_totalstats.rbytes);
4654da14cebeSEric Cheng 			(void) printf("%-10llu",
4655da14cebeSEric Cheng 			    state.vs_totalstats.opackets);
4656da14cebeSEric Cheng 			(void) printf("%-12llu\n",
4657da14cebeSEric Cheng 			    state.vs_totalstats.obytes);
4658da14cebeSEric Cheng 		}
4659da14cebeSEric Cheng 
4660da14cebeSEric Cheng 		/* Show stats for each vnic */
4661da14cebeSEric Cheng 		state.vs_donefirst = B_FALSE;
4662da14cebeSEric Cheng 		state.vs_printstats = B_TRUE;
4663da14cebeSEric Cheng 
4664da14cebeSEric Cheng 		if (!specific_link) {
46654ac67f02SAnurag S. Maskey 			(void) dladm_walk_datalink_id(show_vnic, handle, &state,
4666da14cebeSEric Cheng 			    DATALINK_CLASS_VNIC, DATALINK_ANY_MEDIATYPE,
4667da14cebeSEric Cheng 			    DLADM_OPT_ACTIVE);
4668da14cebeSEric Cheng 		} else {
46694ac67f02SAnurag S. Maskey 			(void) show_vnic(handle, sp->vs_vnic_id, &state);
4670da14cebeSEric Cheng 			if (state.vs_status != DLADM_STATUS_OK) {
4671da14cebeSEric Cheng 				die_dlerr(state.vs_status,
4672da14cebeSEric Cheng 				    "failed to show vnic '%s'", sp->vs_vnic);
4673da14cebeSEric Cheng 			}
4674da14cebeSEric Cheng 		}
46757c478bd9Sstevel@tonic-gate 
46767c478bd9Sstevel@tonic-gate 		if (interval == 0)
46777c478bd9Sstevel@tonic-gate 			break;
46787c478bd9Sstevel@tonic-gate 
46797c478bd9Sstevel@tonic-gate 		(void) sleep(interval);
46807c478bd9Sstevel@tonic-gate 	}
46817c478bd9Sstevel@tonic-gate }
46827c478bd9Sstevel@tonic-gate 
46837c478bd9Sstevel@tonic-gate static void
4684da14cebeSEric Cheng get_mac_stats(const char *dev, pktsum_t *stats)
46857c478bd9Sstevel@tonic-gate {
46867c478bd9Sstevel@tonic-gate 	kstat_ctl_t	*kcp;
46877c478bd9Sstevel@tonic-gate 	kstat_t		*ksp;
4688da14cebeSEric Cheng 	char module[DLPI_LINKNAME_MAX];
4689da14cebeSEric Cheng 	uint_t instance;
4690da14cebeSEric Cheng 
4691da14cebeSEric Cheng 
4692da14cebeSEric Cheng 	bzero(stats, sizeof (*stats));
4693da14cebeSEric Cheng 
4694da14cebeSEric Cheng 	if (dlpi_parselink(dev, module, &instance) != DLPI_SUCCESS)
4695da14cebeSEric Cheng 		return;
46967c478bd9Sstevel@tonic-gate 
46977c478bd9Sstevel@tonic-gate 	if ((kcp = kstat_open()) == NULL) {
469833343a97Smeem 		warn("kstat open operation failed");
46997c478bd9Sstevel@tonic-gate 		return;
47007c478bd9Sstevel@tonic-gate 	}
47017c478bd9Sstevel@tonic-gate 
4702da14cebeSEric Cheng 	ksp = dladm_kstat_lookup(kcp, module, instance, "mac", NULL);
4703da14cebeSEric Cheng 	if (ksp != NULL)
4704da14cebeSEric Cheng 		dladm_get_stats(kcp, ksp, stats);
4705da14cebeSEric Cheng 
47067c478bd9Sstevel@tonic-gate 	(void) kstat_close(kcp);
47077c478bd9Sstevel@tonic-gate 
47087c478bd9Sstevel@tonic-gate }
47097c478bd9Sstevel@tonic-gate 
47107c478bd9Sstevel@tonic-gate static void
47117c478bd9Sstevel@tonic-gate get_link_stats(const char *link, pktsum_t *stats)
47127c478bd9Sstevel@tonic-gate {
4713da14cebeSEric Cheng 	kstat_ctl_t	*kcp;
4714da14cebeSEric Cheng 	kstat_t		*ksp;
4715da14cebeSEric Cheng 
47167c478bd9Sstevel@tonic-gate 	bzero(stats, sizeof (*stats));
4717da14cebeSEric Cheng 
4718da14cebeSEric Cheng 	if ((kcp = kstat_open()) == NULL) {
4719da14cebeSEric Cheng 		warn("kstat_open operation failed");
4720da14cebeSEric Cheng 		return;
4721da14cebeSEric Cheng 	}
4722da14cebeSEric Cheng 
4723da14cebeSEric Cheng 	ksp = dladm_kstat_lookup(kcp, "link", 0, link, NULL);
4724da14cebeSEric Cheng 
4725da14cebeSEric Cheng 	if (ksp != NULL)
4726da14cebeSEric Cheng 		dladm_get_stats(kcp, ksp, stats);
4727da14cebeSEric Cheng 
4728da14cebeSEric Cheng 	(void) kstat_close(kcp);
47297c478bd9Sstevel@tonic-gate }
47307c478bd9Sstevel@tonic-gate 
4731ba2e4443Sseb static int
4732d62bc4baSyz147064 query_kstat(char *module, int instance, const char *name, const char *stat,
4733d62bc4baSyz147064     uint8_t type, void *val)
47347c478bd9Sstevel@tonic-gate {
47357c478bd9Sstevel@tonic-gate 	kstat_ctl_t	*kcp;
47367c478bd9Sstevel@tonic-gate 	kstat_t		*ksp;
47377c478bd9Sstevel@tonic-gate 
47387c478bd9Sstevel@tonic-gate 	if ((kcp = kstat_open()) == NULL) {
473933343a97Smeem 		warn("kstat open operation failed");
4740ba2e4443Sseb 		return (-1);
47417c478bd9Sstevel@tonic-gate 	}
47427c478bd9Sstevel@tonic-gate 
4743d62bc4baSyz147064 	if ((ksp = kstat_lookup(kcp, module, instance, (char *)name)) == NULL) {
47447c478bd9Sstevel@tonic-gate 		/*
47457c478bd9Sstevel@tonic-gate 		 * The kstat query could fail if the underlying MAC
47467c478bd9Sstevel@tonic-gate 		 * driver was already detached.
47477c478bd9Sstevel@tonic-gate 		 */
47487c478bd9Sstevel@tonic-gate 		goto bail;
47497c478bd9Sstevel@tonic-gate 	}
47507c478bd9Sstevel@tonic-gate 
47517c478bd9Sstevel@tonic-gate 	if (kstat_read(kcp, ksp, NULL) == -1) {
475233343a97Smeem 		warn("kstat read failed");
47537c478bd9Sstevel@tonic-gate 		goto bail;
47547c478bd9Sstevel@tonic-gate 	}
47557c478bd9Sstevel@tonic-gate 
4756e7801d59Ssowmini 	if (dladm_kstat_value(ksp, stat, type, val) < 0)
47577c478bd9Sstevel@tonic-gate 		goto bail;
4758ba2e4443Sseb 
4759ba2e4443Sseb 	(void) kstat_close(kcp);
4760ba2e4443Sseb 	return (0);
47617c478bd9Sstevel@tonic-gate 
47627c478bd9Sstevel@tonic-gate bail:
47637c478bd9Sstevel@tonic-gate 	(void) kstat_close(kcp);
4764ba2e4443Sseb 	return (-1);
4765ba2e4443Sseb }
4766ba2e4443Sseb 
4767d62bc4baSyz147064 static int
4768d62bc4baSyz147064 get_one_kstat(const char *name, const char *stat, uint8_t type,
4769d62bc4baSyz147064     void *val, boolean_t islink)
4770d62bc4baSyz147064 {
4771d62bc4baSyz147064 	char		module[DLPI_LINKNAME_MAX];
4772d62bc4baSyz147064 	uint_t		instance;
4773d62bc4baSyz147064 
4774d62bc4baSyz147064 	if (islink) {
4775d62bc4baSyz147064 		return (query_kstat("link", 0, name, stat, type, val));
4776d62bc4baSyz147064 	} else {
4777d62bc4baSyz147064 		if (dlpi_parselink(name, module, &instance) != DLPI_SUCCESS)
4778d62bc4baSyz147064 			return (-1);
4779d62bc4baSyz147064 
4780d62bc4baSyz147064 		return (query_kstat(module, instance, "mac", stat, type, val));
4781d62bc4baSyz147064 	}
4782d62bc4baSyz147064 }
4783d62bc4baSyz147064 
4784ba2e4443Sseb static uint64_t
4785d62bc4baSyz147064 get_ifspeed(const char *name, boolean_t islink)
4786ba2e4443Sseb {
4787ba2e4443Sseb 	uint64_t ifspeed = 0;
4788ba2e4443Sseb 
4789d62bc4baSyz147064 	(void) get_one_kstat(name, "ifspeed", KSTAT_DATA_UINT64,
4790d62bc4baSyz147064 	    &ifspeed, islink);
4791d62bc4baSyz147064 
47927c478bd9Sstevel@tonic-gate 	return (ifspeed);
47937c478bd9Sstevel@tonic-gate }
47947c478bd9Sstevel@tonic-gate 
4795f595a68aSyz147064 static const char *
4796d62bc4baSyz147064 get_linkstate(const char *name, boolean_t islink, char *buf)
47977c478bd9Sstevel@tonic-gate {
4798d62bc4baSyz147064 	link_state_t	linkstate;
47997c478bd9Sstevel@tonic-gate 
4800d62bc4baSyz147064 	if (get_one_kstat(name, "link_state", KSTAT_DATA_UINT32,
4801d62bc4baSyz147064 	    &linkstate, islink) != 0) {
4802da14cebeSEric Cheng 		(void) strlcpy(buf, "?", DLADM_STRSIZE);
48033a62633bSyz147064 		return (buf);
48047c478bd9Sstevel@tonic-gate 	}
4805d62bc4baSyz147064 	return (dladm_linkstate2str(linkstate, buf));
48067c478bd9Sstevel@tonic-gate }
48077c478bd9Sstevel@tonic-gate 
4808f595a68aSyz147064 static const char *
4809d62bc4baSyz147064 get_linkduplex(const char *name, boolean_t islink, char *buf)
48107c478bd9Sstevel@tonic-gate {
4811d62bc4baSyz147064 	link_duplex_t	linkduplex;
48127c478bd9Sstevel@tonic-gate 
4813d62bc4baSyz147064 	if (get_one_kstat(name, "link_duplex", KSTAT_DATA_UINT32,
4814d62bc4baSyz147064 	    &linkduplex, islink) != 0) {
48153a62633bSyz147064 		(void) strlcpy(buf, "unknown", DLADM_STRSIZE);
48163a62633bSyz147064 		return (buf);
48177c478bd9Sstevel@tonic-gate 	}
48187c478bd9Sstevel@tonic-gate 
4819d62bc4baSyz147064 	return (dladm_linkduplex2str(linkduplex, buf));
48207c478bd9Sstevel@tonic-gate }
48210ba2cbe9Sxc151355 
48220ba2cbe9Sxc151355 typedef struct {
48230ba2cbe9Sxc151355 	char	*s_buf;
48240ba2cbe9Sxc151355 	char	**s_fields;	/* array of pointer to the fields in s_buf */
48250ba2cbe9Sxc151355 	uint_t	s_nfields;	/* the number of fields in s_buf */
48260ba2cbe9Sxc151355 } split_t;
48270ba2cbe9Sxc151355 
48280ba2cbe9Sxc151355 /*
48290ba2cbe9Sxc151355  * Free the split_t structure pointed to by `sp'.
48300ba2cbe9Sxc151355  */
48310ba2cbe9Sxc151355 static void
48320ba2cbe9Sxc151355 splitfree(split_t *sp)
48330ba2cbe9Sxc151355 {
48340ba2cbe9Sxc151355 	free(sp->s_buf);
48350ba2cbe9Sxc151355 	free(sp->s_fields);
48360ba2cbe9Sxc151355 	free(sp);
48370ba2cbe9Sxc151355 }
48380ba2cbe9Sxc151355 
48390ba2cbe9Sxc151355 /*
48400ba2cbe9Sxc151355  * Split `str' into at most `maxfields' fields, each field at most `maxlen' in
48410ba2cbe9Sxc151355  * length.  Return a pointer to a split_t containing the split fields, or NULL
48420ba2cbe9Sxc151355  * on failure.
48430ba2cbe9Sxc151355  */
48440ba2cbe9Sxc151355 static split_t *
48450ba2cbe9Sxc151355 split(const char *str, uint_t maxfields, uint_t maxlen)
48460ba2cbe9Sxc151355 {
48470ba2cbe9Sxc151355 	char	*field, *token, *lasts = NULL;
48480ba2cbe9Sxc151355 	split_t	*sp;
48490ba2cbe9Sxc151355 
48500ba2cbe9Sxc151355 	if (*str == '\0' || maxfields == 0 || maxlen == 0)
48510ba2cbe9Sxc151355 		return (NULL);
48520ba2cbe9Sxc151355 
48530ba2cbe9Sxc151355 	sp = calloc(sizeof (split_t), 1);
48540ba2cbe9Sxc151355 	if (sp == NULL)
48550ba2cbe9Sxc151355 		return (NULL);
48560ba2cbe9Sxc151355 
48570ba2cbe9Sxc151355 	sp->s_buf = strdup(str);
48580ba2cbe9Sxc151355 	sp->s_fields = malloc(sizeof (char *) * maxfields);
48590ba2cbe9Sxc151355 	if (sp->s_buf == NULL || sp->s_fields == NULL)
48600ba2cbe9Sxc151355 		goto fail;
48610ba2cbe9Sxc151355 
48620ba2cbe9Sxc151355 	token = sp->s_buf;
48630ba2cbe9Sxc151355 	while ((field = strtok_r(token, ",", &lasts)) != NULL) {
48640ba2cbe9Sxc151355 		if (sp->s_nfields == maxfields || strlen(field) > maxlen)
48650ba2cbe9Sxc151355 			goto fail;
48660ba2cbe9Sxc151355 		token = NULL;
48670ba2cbe9Sxc151355 		sp->s_fields[sp->s_nfields++] = field;
48680ba2cbe9Sxc151355 	}
48690ba2cbe9Sxc151355 	return (sp);
48700ba2cbe9Sxc151355 fail:
48710ba2cbe9Sxc151355 	splitfree(sp);
48720ba2cbe9Sxc151355 	return (NULL);
48730ba2cbe9Sxc151355 }
48740ba2cbe9Sxc151355 
48750ba2cbe9Sxc151355 static int
4876e7801d59Ssowmini parse_wifi_fields(char *str, print_field_t ***fields, uint_t *countp,
48770ba2cbe9Sxc151355     uint_t cmdtype)
48780ba2cbe9Sxc151355 {
48790ba2cbe9Sxc151355 
48800ba2cbe9Sxc151355 	if (cmdtype == WIFI_CMD_SCAN) {
48810ba2cbe9Sxc151355 		if (str == NULL)
48820ba2cbe9Sxc151355 			str = def_scan_wifi_fields;
48830ba2cbe9Sxc151355 		if (strcasecmp(str, "all") == 0)
48840ba2cbe9Sxc151355 			str = all_scan_wifi_fields;
48850ba2cbe9Sxc151355 	} else if (cmdtype == WIFI_CMD_SHOW) {
48860ba2cbe9Sxc151355 		if (str == NULL)
48870ba2cbe9Sxc151355 			str = def_show_wifi_fields;
48880ba2cbe9Sxc151355 		if (strcasecmp(str, "all") == 0)
48890ba2cbe9Sxc151355 			str = all_show_wifi_fields;
48900ba2cbe9Sxc151355 	} else {
48910ba2cbe9Sxc151355 		return (-1);
48920ba2cbe9Sxc151355 	}
4893e7801d59Ssowmini 	*fields = parse_output_fields(str, wifi_fields, WIFI_MAX_FIELDS,
4894e7801d59Ssowmini 	    cmdtype, countp);
4895e7801d59Ssowmini 	if (*fields != NULL)
4896e7801d59Ssowmini 		return (0);
48970ba2cbe9Sxc151355 	return (-1);
4898e7801d59Ssowmini }
4899e7801d59Ssowmini static print_field_t **
4900e7801d59Ssowmini parse_output_fields(char *str, print_field_t *template, int max_fields,
4901e7801d59Ssowmini     uint_t cmdtype, uint_t *countp)
4902e7801d59Ssowmini {
4903e7801d59Ssowmini 	split_t		*sp;
4904e7801d59Ssowmini 	boolean_t	good_match = B_FALSE;
4905e7801d59Ssowmini 	uint_t		i, j;
4906e7801d59Ssowmini 	print_field_t	**pf = NULL;
49070ba2cbe9Sxc151355 
4908e7801d59Ssowmini 	sp = split(str, max_fields, MAX_FIELD_LEN);
4909e7801d59Ssowmini 
4910e7801d59Ssowmini 	if (sp == NULL)
4911e7801d59Ssowmini 		return (NULL);
4912e7801d59Ssowmini 
4913e7801d59Ssowmini 	pf = malloc(sp->s_nfields * sizeof (print_field_t *));
4914e7801d59Ssowmini 	if (pf == NULL)
49150ba2cbe9Sxc151355 		goto fail;
49160ba2cbe9Sxc151355 
49170ba2cbe9Sxc151355 	for (i = 0; i < sp->s_nfields; i++) {
4918e7801d59Ssowmini 		for (j = 0; j < max_fields; j++) {
49190ba2cbe9Sxc151355 			if (strcasecmp(sp->s_fields[i],
4920e7801d59Ssowmini 			    template[j].pf_name) == 0) {
4921e7801d59Ssowmini 				good_match = template[j]. pf_cmdtype & cmdtype;
49220ba2cbe9Sxc151355 				break;
49230ba2cbe9Sxc151355 			}
49240ba2cbe9Sxc151355 		}
49250ba2cbe9Sxc151355 		if (!good_match)
49260ba2cbe9Sxc151355 			goto fail;
49270ba2cbe9Sxc151355 
49280ba2cbe9Sxc151355 		good_match = B_FALSE;
4929e7801d59Ssowmini 		pf[i] = &template[j];
49300ba2cbe9Sxc151355 	}
49310ba2cbe9Sxc151355 	*countp = i;
49320ba2cbe9Sxc151355 	splitfree(sp);
4933e7801d59Ssowmini 	return (pf);
49340ba2cbe9Sxc151355 fail:
4935e7801d59Ssowmini 	free(pf);
49360ba2cbe9Sxc151355 	splitfree(sp);
4937e7801d59Ssowmini 	return (NULL);
49380ba2cbe9Sxc151355 }
49390ba2cbe9Sxc151355 
49400ba2cbe9Sxc151355 typedef struct print_wifi_state {
4941d62bc4baSyz147064 	char		*ws_link;
49420ba2cbe9Sxc151355 	boolean_t	ws_parseable;
49430ba2cbe9Sxc151355 	boolean_t	ws_header;
4944e7801d59Ssowmini 	print_state_t	ws_print_state;
49450ba2cbe9Sxc151355 } print_wifi_state_t;
49460ba2cbe9Sxc151355 
4947e7801d59Ssowmini typedef struct  wlan_scan_args_s {
4948e7801d59Ssowmini 	print_wifi_state_t	*ws_state;
4949e7801d59Ssowmini 	void			*ws_attr;
4950e7801d59Ssowmini } wlan_scan_args_t;
49510ba2cbe9Sxc151355 
49520ba2cbe9Sxc151355 static void
4953e7801d59Ssowmini print_field(print_state_t *statep, print_field_t *pfp, const char *value,
4954e7801d59Ssowmini     boolean_t parseable)
49550ba2cbe9Sxc151355 {
4956e7801d59Ssowmini 	uint_t	width = pfp->pf_width;
49576be03d0bSVasumathi Sundaram - Sun Microsystems 	uint_t	valwidth;
49580ba2cbe9Sxc151355 	uint_t	compress;
49590ba2cbe9Sxc151355 
49600d365605Sschuster 	/*
49610d365605Sschuster 	 * Parsable fields are separated by ':'. If such a field contains
49620d365605Sschuster 	 * a ':' or '\', this character is prefixed by a '\'.
49630d365605Sschuster 	 */
4964e7801d59Ssowmini 	if (parseable) {
49650d365605Sschuster 		char	c;
49660d365605Sschuster 
49670d365605Sschuster 		if (statep->ps_nfields == 1) {
49680d365605Sschuster 			(void) printf("%s", value);
49690d365605Sschuster 			return;
49700d365605Sschuster 		}
49710d365605Sschuster 		while ((c = *value++) != '\0') {
49720d365605Sschuster 			if (c == ':' || c == '\\')
49730d365605Sschuster 				(void) putchar('\\');
49740d365605Sschuster 			(void) putchar(c);
49750d365605Sschuster 		}
49760d365605Sschuster 		if (!statep->ps_lastfield)
49770d365605Sschuster 			(void) putchar(':');
49780d365605Sschuster 		return;
49790ba2cbe9Sxc151355 	} else {
49800ba2cbe9Sxc151355 		if (value[0] == '\0')
4981e7801d59Ssowmini 			value = STR_UNDEF_VAL;
4982e7801d59Ssowmini 		if (statep->ps_lastfield) {
49830ba2cbe9Sxc151355 			(void) printf("%s", value);
49846be03d0bSVasumathi Sundaram - Sun Microsystems 			statep->ps_overflow = 0;
49850ba2cbe9Sxc151355 			return;
49860ba2cbe9Sxc151355 		}
49870ba2cbe9Sxc151355 
49886be03d0bSVasumathi Sundaram - Sun Microsystems 		valwidth = strlen(value);
49890ba2cbe9Sxc151355 		if (valwidth > width) {
4990e7801d59Ssowmini 			statep->ps_overflow += valwidth - width;
4991e7801d59Ssowmini 		} else if (valwidth < width && statep->ps_overflow > 0) {
4992e7801d59Ssowmini 			compress = min(statep->ps_overflow, width - valwidth);
4993e7801d59Ssowmini 			statep->ps_overflow -= compress;
49940ba2cbe9Sxc151355 			width -= compress;
49950ba2cbe9Sxc151355 		}
49960ba2cbe9Sxc151355 		(void) printf("%-*s", width, value);
49970ba2cbe9Sxc151355 	}
49980ba2cbe9Sxc151355 
4999e7801d59Ssowmini 	if (!statep->ps_lastfield)
50000ba2cbe9Sxc151355 		(void) putchar(' ');
50010ba2cbe9Sxc151355 }
50020ba2cbe9Sxc151355 
5003e7801d59Ssowmini static char *
5004e7801d59Ssowmini print_wlan_attr(print_field_t *wfp, void *warg)
50050ba2cbe9Sxc151355 {
5006e7801d59Ssowmini 	static char		buf[DLADM_STRSIZE];
5007e7801d59Ssowmini 	wlan_scan_args_t	*w = warg;
5008e7801d59Ssowmini 	print_wifi_state_t	*statep = w->ws_state;
5009e7801d59Ssowmini 	dladm_wlan_attr_t	*attrp = w->ws_attr;
50100ba2cbe9Sxc151355 
5011e7801d59Ssowmini 	if (wfp->pf_index == 0) {
5012e7801d59Ssowmini 		return ((char *)statep->ws_link);
50130ba2cbe9Sxc151355 	}
50140ba2cbe9Sxc151355 
5015e7801d59Ssowmini 	if ((wfp->pf_index & attrp->wa_valid) == 0) {
5016e7801d59Ssowmini 		return ("");
50170ba2cbe9Sxc151355 	}
50180ba2cbe9Sxc151355 
5019e7801d59Ssowmini 	switch (wfp->pf_index) {
5020f595a68aSyz147064 	case DLADM_WLAN_ATTR_ESSID:
5021e7801d59Ssowmini 		(void) dladm_wlan_essid2str(&attrp->wa_essid, buf);
50220ba2cbe9Sxc151355 		break;
5023f595a68aSyz147064 	case DLADM_WLAN_ATTR_BSSID:
5024e7801d59Ssowmini 		(void) dladm_wlan_bssid2str(&attrp->wa_bssid, buf);
50250ba2cbe9Sxc151355 		break;
5026f595a68aSyz147064 	case DLADM_WLAN_ATTR_SECMODE:
5027e7801d59Ssowmini 		(void) dladm_wlan_secmode2str(&attrp->wa_secmode, buf);
50280ba2cbe9Sxc151355 		break;
5029f595a68aSyz147064 	case DLADM_WLAN_ATTR_STRENGTH:
5030e7801d59Ssowmini 		(void) dladm_wlan_strength2str(&attrp->wa_strength, buf);
50310ba2cbe9Sxc151355 		break;
5032f595a68aSyz147064 	case DLADM_WLAN_ATTR_MODE:
5033e7801d59Ssowmini 		(void) dladm_wlan_mode2str(&attrp->wa_mode, buf);
50340ba2cbe9Sxc151355 		break;
5035f595a68aSyz147064 	case DLADM_WLAN_ATTR_SPEED:
5036e7801d59Ssowmini 		(void) dladm_wlan_speed2str(&attrp->wa_speed, buf);
50370ba2cbe9Sxc151355 		(void) strlcat(buf, "Mb", sizeof (buf));
50380ba2cbe9Sxc151355 		break;
5039f595a68aSyz147064 	case DLADM_WLAN_ATTR_AUTH:
5040e7801d59Ssowmini 		(void) dladm_wlan_auth2str(&attrp->wa_auth, buf);
50410ba2cbe9Sxc151355 		break;
5042f595a68aSyz147064 	case DLADM_WLAN_ATTR_BSSTYPE:
5043e7801d59Ssowmini 		(void) dladm_wlan_bsstype2str(&attrp->wa_bsstype, buf);
50440ba2cbe9Sxc151355 		break;
50450ba2cbe9Sxc151355 	}
50460ba2cbe9Sxc151355 
5047e7801d59Ssowmini 	return (buf);
50480ba2cbe9Sxc151355 }
50490ba2cbe9Sxc151355 
50500ba2cbe9Sxc151355 static boolean_t
5051f595a68aSyz147064 print_scan_results(void *arg, dladm_wlan_attr_t *attrp)
50520ba2cbe9Sxc151355 {
50530ba2cbe9Sxc151355 	print_wifi_state_t	*statep = arg;
5054e7801d59Ssowmini 	wlan_scan_args_t	warg;
50550ba2cbe9Sxc151355 
50560ba2cbe9Sxc151355 	if (statep->ws_header) {
50570ba2cbe9Sxc151355 		statep->ws_header = B_FALSE;
50580ba2cbe9Sxc151355 		if (!statep->ws_parseable)
5059e7801d59Ssowmini 			print_header(&statep->ws_print_state);
50600ba2cbe9Sxc151355 	}
50610ba2cbe9Sxc151355 
5062e7801d59Ssowmini 	statep->ws_print_state.ps_overflow = 0;
5063e7801d59Ssowmini 	bzero(&warg, sizeof (warg));
5064e7801d59Ssowmini 	warg.ws_state = statep;
5065e7801d59Ssowmini 	warg.ws_attr = attrp;
5066e7801d59Ssowmini 	dladm_print_output(&statep->ws_print_state, statep->ws_parseable,
5067e7801d59Ssowmini 	    print_wlan_attr, &warg);
50680ba2cbe9Sxc151355 	return (B_TRUE);
50690ba2cbe9Sxc151355 }
50700ba2cbe9Sxc151355 
5071d62bc4baSyz147064 static int
50724ac67f02SAnurag S. Maskey scan_wifi(dladm_handle_t dh, datalink_id_t linkid, void *arg)
50730ba2cbe9Sxc151355 {
50740ba2cbe9Sxc151355 	print_wifi_state_t	*statep = arg;
5075f595a68aSyz147064 	dladm_status_t		status;
5076d62bc4baSyz147064 	char			link[MAXLINKNAMELEN];
5077d62bc4baSyz147064 
50784ac67f02SAnurag S. Maskey 	if ((status = dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, link,
5079e7801d59Ssowmini 	    sizeof (link))) != DLADM_STATUS_OK) {
5080d62bc4baSyz147064 		return (DLADM_WALK_CONTINUE);
5081d62bc4baSyz147064 	}
50820ba2cbe9Sxc151355 
50830ba2cbe9Sxc151355 	statep->ws_link = link;
50844ac67f02SAnurag S. Maskey 	status = dladm_wlan_scan(dh, linkid, statep, print_scan_results);
5085f595a68aSyz147064 	if (status != DLADM_STATUS_OK)
5086d62bc4baSyz147064 		die_dlerr(status, "cannot scan link '%s'", statep->ws_link);
508733343a97Smeem 
5088d62bc4baSyz147064 	return (DLADM_WALK_CONTINUE);
50890ba2cbe9Sxc151355 }
50900ba2cbe9Sxc151355 
5091e7801d59Ssowmini static char *
5092e7801d59Ssowmini print_link_attr(print_field_t *wfp, void *warg)
50930ba2cbe9Sxc151355 {
5094e7801d59Ssowmini 	static char		buf[DLADM_STRSIZE];
5095e7801d59Ssowmini 	char			*ptr;
5096e7801d59Ssowmini 	wlan_scan_args_t	*w = warg, w1;
5097e7801d59Ssowmini 	print_wifi_state_t	*statep = w->ws_state;
5098e7801d59Ssowmini 	dladm_wlan_linkattr_t	*attrp = w->ws_attr;
50990ba2cbe9Sxc151355 
5100e7801d59Ssowmini 	if (strcmp(wfp->pf_name, "status") == 0) {
5101e7801d59Ssowmini 		if ((wfp->pf_index & attrp->la_valid) != 0)
5102e7801d59Ssowmini 			(void) dladm_wlan_linkstatus2str(
5103e7801d59Ssowmini 			    &attrp->la_status, buf);
5104e7801d59Ssowmini 		return (buf);
51050ba2cbe9Sxc151355 	}
5106e7801d59Ssowmini 	statep->ws_print_state.ps_overflow = 0;
5107e7801d59Ssowmini 	bzero(&w1, sizeof (w1));
5108e7801d59Ssowmini 	w1.ws_state = statep;
5109e7801d59Ssowmini 	w1.ws_attr = &attrp->la_wlan_attr;
5110e7801d59Ssowmini 	ptr = print_wlan_attr(wfp, &w1);
5111e7801d59Ssowmini 	return (ptr);
51120ba2cbe9Sxc151355 }
51130ba2cbe9Sxc151355 
5114d62bc4baSyz147064 static int
51154ac67f02SAnurag S. Maskey show_wifi(dladm_handle_t dh, datalink_id_t linkid, void *arg)
51160ba2cbe9Sxc151355 {
51170ba2cbe9Sxc151355 	print_wifi_state_t	*statep = arg;
5118f595a68aSyz147064 	dladm_wlan_linkattr_t	attr;
5119f595a68aSyz147064 	dladm_status_t		status;
5120d62bc4baSyz147064 	char			link[MAXLINKNAMELEN];
5121e7801d59Ssowmini 	wlan_scan_args_t	warg;
51220ba2cbe9Sxc151355 
51234ac67f02SAnurag S. Maskey 	if ((status = dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, link,
5124e7801d59Ssowmini 	    sizeof (link))) != DLADM_STATUS_OK) {
5125d62bc4baSyz147064 		return (DLADM_WALK_CONTINUE);
5126d62bc4baSyz147064 	}
5127d62bc4baSyz147064 
51285f5c9f54SAnurag S. Maskey 	/* dladm_wlan_get_linkattr() memsets attr with 0 */
51294ac67f02SAnurag S. Maskey 	status = dladm_wlan_get_linkattr(dh, linkid, &attr);
5130f595a68aSyz147064 	if (status != DLADM_STATUS_OK)
5131d62bc4baSyz147064 		die_dlerr(status, "cannot get link attributes for %s", link);
5132d62bc4baSyz147064 
5133d62bc4baSyz147064 	statep->ws_link = link;
51340ba2cbe9Sxc151355 
51350ba2cbe9Sxc151355 	if (statep->ws_header) {
51360ba2cbe9Sxc151355 		statep->ws_header = B_FALSE;
51370ba2cbe9Sxc151355 		if (!statep->ws_parseable)
5138e7801d59Ssowmini 			print_header(&statep->ws_print_state);
51390ba2cbe9Sxc151355 	}
51400ba2cbe9Sxc151355 
5141e7801d59Ssowmini 	statep->ws_print_state.ps_overflow = 0;
5142e7801d59Ssowmini 	bzero(&warg, sizeof (warg));
5143e7801d59Ssowmini 	warg.ws_state = statep;
5144e7801d59Ssowmini 	warg.ws_attr = &attr;
5145e7801d59Ssowmini 	dladm_print_output(&statep->ws_print_state, statep->ws_parseable,
5146e7801d59Ssowmini 	    print_link_attr, &warg);
5147d62bc4baSyz147064 	return (DLADM_WALK_CONTINUE);
51480ba2cbe9Sxc151355 }
51490ba2cbe9Sxc151355 
51500ba2cbe9Sxc151355 static void
51518d5c46e6Sam223141 do_display_wifi(int argc, char **argv, int cmd, const char *use)
51520ba2cbe9Sxc151355 {
51530ba2cbe9Sxc151355 	int			option;
51540ba2cbe9Sxc151355 	char			*fields_str = NULL;
5155e7801d59Ssowmini 	print_field_t		**fields;
51564ac67f02SAnurag S. Maskey 	int		(*callback)(dladm_handle_t, datalink_id_t, void *);
51570ba2cbe9Sxc151355 	uint_t			nfields;
51580ba2cbe9Sxc151355 	print_wifi_state_t	state;
5159d62bc4baSyz147064 	datalink_id_t		linkid = DATALINK_ALL_LINKID;
5160f595a68aSyz147064 	dladm_status_t		status;
51610ba2cbe9Sxc151355 
51620ba2cbe9Sxc151355 	if (cmd == WIFI_CMD_SCAN)
51630ba2cbe9Sxc151355 		callback = scan_wifi;
51640ba2cbe9Sxc151355 	else if (cmd == WIFI_CMD_SHOW)
51650ba2cbe9Sxc151355 		callback = show_wifi;
51660ba2cbe9Sxc151355 	else
51670ba2cbe9Sxc151355 		return;
51680ba2cbe9Sxc151355 
51690ba2cbe9Sxc151355 	state.ws_parseable = B_FALSE;
51700ba2cbe9Sxc151355 	state.ws_header = B_TRUE;
51710ba2cbe9Sxc151355 	opterr = 0;
51720ba2cbe9Sxc151355 	while ((option = getopt_long(argc, argv, ":o:p",
51730ba2cbe9Sxc151355 	    wifi_longopts, NULL)) != -1) {
51740ba2cbe9Sxc151355 		switch (option) {
51750ba2cbe9Sxc151355 		case 'o':
51760ba2cbe9Sxc151355 			fields_str = optarg;
51770ba2cbe9Sxc151355 			break;
51780ba2cbe9Sxc151355 		case 'p':
51790ba2cbe9Sxc151355 			state.ws_parseable = B_TRUE;
51800ba2cbe9Sxc151355 			break;
51810ba2cbe9Sxc151355 		default:
51828d5c46e6Sam223141 			die_opterr(optopt, option, use);
51830ba2cbe9Sxc151355 		}
51840ba2cbe9Sxc151355 	}
51850ba2cbe9Sxc151355 
51860d365605Sschuster 	if (state.ws_parseable && fields_str == NULL)
51870d365605Sschuster 		die("-p requires -o");
51880d365605Sschuster 
51890d365605Sschuster 	if (state.ws_parseable && strcasecmp(fields_str, "all") == 0)
51900d365605Sschuster 		die("\"-o all\" is invalid with -p");
51910d365605Sschuster 
5192d62bc4baSyz147064 	if (optind == (argc - 1)) {
51934ac67f02SAnurag S. Maskey 		if ((status = dladm_name2info(handle, argv[optind], &linkid,
51944ac67f02SAnurag S. Maskey 		    NULL, NULL, NULL)) != DLADM_STATUS_OK) {
5195d62bc4baSyz147064 			die_dlerr(status, "link %s is not valid", argv[optind]);
5196d62bc4baSyz147064 		}
5197d62bc4baSyz147064 	} else if (optind != argc) {
51980ba2cbe9Sxc151355 		usage();
5199d62bc4baSyz147064 	}
52000ba2cbe9Sxc151355 
520133343a97Smeem 	if (parse_wifi_fields(fields_str, &fields, &nfields, cmd) < 0)
520233343a97Smeem 		die("invalid field(s) specified");
520333343a97Smeem 
5204e7801d59Ssowmini 	bzero(&state.ws_print_state, sizeof (state.ws_print_state));
5205e7801d59Ssowmini 	state.ws_print_state.ps_fields = fields;
5206e7801d59Ssowmini 	state.ws_print_state.ps_nfields = nfields;
52070ba2cbe9Sxc151355 
5208d62bc4baSyz147064 	if (linkid == DATALINK_ALL_LINKID) {
52094ac67f02SAnurag S. Maskey 		(void) dladm_walk_datalink_id(callback, handle, &state,
5210d62bc4baSyz147064 		    DATALINK_CLASS_PHYS, DL_WIFI, DLADM_OPT_ACTIVE);
52110ba2cbe9Sxc151355 	} else {
52124ac67f02SAnurag S. Maskey 		(void) (*callback)(handle, linkid, &state);
52130ba2cbe9Sxc151355 	}
52140ba2cbe9Sxc151355 	free(fields);
52150ba2cbe9Sxc151355 }
52160ba2cbe9Sxc151355 
52170ba2cbe9Sxc151355 static void
52188d5c46e6Sam223141 do_scan_wifi(int argc, char **argv, const char *use)
52190ba2cbe9Sxc151355 {
52208d5c46e6Sam223141 	do_display_wifi(argc, argv, WIFI_CMD_SCAN, use);
52210ba2cbe9Sxc151355 }
52220ba2cbe9Sxc151355 
52230ba2cbe9Sxc151355 static void
52248d5c46e6Sam223141 do_show_wifi(int argc, char **argv, const char *use)
52250ba2cbe9Sxc151355 {
52268d5c46e6Sam223141 	do_display_wifi(argc, argv, WIFI_CMD_SHOW, use);
52270ba2cbe9Sxc151355 }
52280ba2cbe9Sxc151355 
52290ba2cbe9Sxc151355 typedef struct wlan_count_attr {
52300ba2cbe9Sxc151355 	uint_t		wc_count;
5231d62bc4baSyz147064 	datalink_id_t	wc_linkid;
52320ba2cbe9Sxc151355 } wlan_count_attr_t;
52330ba2cbe9Sxc151355 
52344ac67f02SAnurag S. Maskey /* ARGSUSED */
5235d62bc4baSyz147064 static int
52364ac67f02SAnurag S. Maskey do_count_wlan(dladm_handle_t dh, datalink_id_t linkid, void *arg)
52370ba2cbe9Sxc151355 {
523833343a97Smeem 	wlan_count_attr_t *cp = arg;
52390ba2cbe9Sxc151355 
52400ba2cbe9Sxc151355 	if (cp->wc_count == 0)
5241d62bc4baSyz147064 		cp->wc_linkid = linkid;
52420ba2cbe9Sxc151355 	cp->wc_count++;
5243d62bc4baSyz147064 	return (DLADM_WALK_CONTINUE);
52440ba2cbe9Sxc151355 }
52450ba2cbe9Sxc151355 
52460ba2cbe9Sxc151355 static int
5247a399b765Szf162725 parse_wlan_keys(char *str, dladm_wlan_key_t **keys, uint_t *key_countp)
52480ba2cbe9Sxc151355 {
52490ba2cbe9Sxc151355 	uint_t			i;
52500ba2cbe9Sxc151355 	split_t			*sp;
5251a399b765Szf162725 	dladm_wlan_key_t	*wk;
52520ba2cbe9Sxc151355 
5253a399b765Szf162725 	sp = split(str, DLADM_WLAN_MAX_WEPKEYS, DLADM_WLAN_MAX_KEYNAME_LEN);
52540ba2cbe9Sxc151355 	if (sp == NULL)
52550ba2cbe9Sxc151355 		return (-1);
52560ba2cbe9Sxc151355 
5257a399b765Szf162725 	wk = malloc(sp->s_nfields * sizeof (dladm_wlan_key_t));
52580ba2cbe9Sxc151355 	if (wk == NULL)
52590ba2cbe9Sxc151355 		goto fail;
52600ba2cbe9Sxc151355 
52610ba2cbe9Sxc151355 	for (i = 0; i < sp->s_nfields; i++) {
52620ba2cbe9Sxc151355 		char			*s;
52630ba2cbe9Sxc151355 		dladm_secobj_class_t	class;
52640ba2cbe9Sxc151355 		dladm_status_t		status;
52650ba2cbe9Sxc151355 
52660ba2cbe9Sxc151355 		(void) strlcpy(wk[i].wk_name, sp->s_fields[i],
5267a399b765Szf162725 		    DLADM_WLAN_MAX_KEYNAME_LEN);
52680ba2cbe9Sxc151355 
52690ba2cbe9Sxc151355 		wk[i].wk_idx = 1;
52700ba2cbe9Sxc151355 		if ((s = strrchr(wk[i].wk_name, ':')) != NULL) {
52710ba2cbe9Sxc151355 			if (s[1] == '\0' || s[2] != '\0' || !isdigit(s[1]))
52720ba2cbe9Sxc151355 				goto fail;
52730ba2cbe9Sxc151355 
52740ba2cbe9Sxc151355 			wk[i].wk_idx = (uint_t)(s[1] - '0');
52750ba2cbe9Sxc151355 			*s = '\0';
52760ba2cbe9Sxc151355 		}
5277a399b765Szf162725 		wk[i].wk_len = DLADM_WLAN_MAX_KEY_LEN;
52780ba2cbe9Sxc151355 
52794ac67f02SAnurag S. Maskey 		status = dladm_get_secobj(handle, wk[i].wk_name, &class,
52800ba2cbe9Sxc151355 		    wk[i].wk_val, &wk[i].wk_len, 0);
52810ba2cbe9Sxc151355 		if (status != DLADM_STATUS_OK) {
52820ba2cbe9Sxc151355 			if (status == DLADM_STATUS_NOTFOUND) {
52834ac67f02SAnurag S. Maskey 				status = dladm_get_secobj(handle, wk[i].wk_name,
52840ba2cbe9Sxc151355 				    &class, wk[i].wk_val, &wk[i].wk_len,
52850ba2cbe9Sxc151355 				    DLADM_OPT_PERSIST);
52860ba2cbe9Sxc151355 			}
52870ba2cbe9Sxc151355 			if (status != DLADM_STATUS_OK)
52880ba2cbe9Sxc151355 				goto fail;
52890ba2cbe9Sxc151355 		}
5290a399b765Szf162725 		wk[i].wk_class = class;
52910ba2cbe9Sxc151355 	}
52920ba2cbe9Sxc151355 	*keys = wk;
52930ba2cbe9Sxc151355 	*key_countp = i;
52940ba2cbe9Sxc151355 	splitfree(sp);
52950ba2cbe9Sxc151355 	return (0);
52960ba2cbe9Sxc151355 fail:
52970ba2cbe9Sxc151355 	free(wk);
52980ba2cbe9Sxc151355 	splitfree(sp);
52990ba2cbe9Sxc151355 	return (-1);
53000ba2cbe9Sxc151355 }
53010ba2cbe9Sxc151355 
53020ba2cbe9Sxc151355 static void
53038d5c46e6Sam223141 do_connect_wifi(int argc, char **argv, const char *use)
53040ba2cbe9Sxc151355 {
53050ba2cbe9Sxc151355 	int			option;
5306f595a68aSyz147064 	dladm_wlan_attr_t	attr, *attrp;
5307f595a68aSyz147064 	dladm_status_t		status = DLADM_STATUS_OK;
5308f595a68aSyz147064 	int			timeout = DLADM_WLAN_CONNECT_TIMEOUT_DEFAULT;
5309d62bc4baSyz147064 	datalink_id_t		linkid = DATALINK_ALL_LINKID;
5310a399b765Szf162725 	dladm_wlan_key_t	*keys = NULL;
53110ba2cbe9Sxc151355 	uint_t			key_count = 0;
53120ba2cbe9Sxc151355 	uint_t			flags = 0;
5313f595a68aSyz147064 	dladm_wlan_secmode_t	keysecmode = DLADM_WLAN_SECMODE_NONE;
5314a399b765Szf162725 	char			buf[DLADM_STRSIZE];
53150ba2cbe9Sxc151355 
53160ba2cbe9Sxc151355 	opterr = 0;
53170ba2cbe9Sxc151355 	(void) memset(&attr, 0, sizeof (attr));
53180ba2cbe9Sxc151355 	while ((option = getopt_long(argc, argv, ":e:i:a:m:b:s:k:T:c",
53190ba2cbe9Sxc151355 	    wifi_longopts, NULL)) != -1) {
53200ba2cbe9Sxc151355 		switch (option) {
53210ba2cbe9Sxc151355 		case 'e':
5322f595a68aSyz147064 			status = dladm_wlan_str2essid(optarg, &attr.wa_essid);
5323f595a68aSyz147064 			if (status != DLADM_STATUS_OK)
532433343a97Smeem 				die("invalid ESSID '%s'", optarg);
532533343a97Smeem 
5326f595a68aSyz147064 			attr.wa_valid |= DLADM_WLAN_ATTR_ESSID;
53270ba2cbe9Sxc151355 			/*
53280ba2cbe9Sxc151355 			 * Try to connect without doing a scan.
53290ba2cbe9Sxc151355 			 */
5330f595a68aSyz147064 			flags |= DLADM_WLAN_CONNECT_NOSCAN;
53310ba2cbe9Sxc151355 			break;
53320ba2cbe9Sxc151355 		case 'i':
5333f595a68aSyz147064 			status = dladm_wlan_str2bssid(optarg, &attr.wa_bssid);
5334f595a68aSyz147064 			if (status != DLADM_STATUS_OK)
533533343a97Smeem 				die("invalid BSSID %s", optarg);
533633343a97Smeem 
5337f595a68aSyz147064 			attr.wa_valid |= DLADM_WLAN_ATTR_BSSID;
53380ba2cbe9Sxc151355 			break;
53390ba2cbe9Sxc151355 		case 'a':
5340f595a68aSyz147064 			status = dladm_wlan_str2auth(optarg, &attr.wa_auth);
5341f595a68aSyz147064 			if (status != DLADM_STATUS_OK)
534233343a97Smeem 				die("invalid authentication mode '%s'", optarg);
534333343a97Smeem 
5344f595a68aSyz147064 			attr.wa_valid |= DLADM_WLAN_ATTR_AUTH;
53450ba2cbe9Sxc151355 			break;
53460ba2cbe9Sxc151355 		case 'm':
5347f595a68aSyz147064 			status = dladm_wlan_str2mode(optarg, &attr.wa_mode);
5348f595a68aSyz147064 			if (status != DLADM_STATUS_OK)
534933343a97Smeem 				die("invalid mode '%s'", optarg);
535033343a97Smeem 
5351f595a68aSyz147064 			attr.wa_valid |= DLADM_WLAN_ATTR_MODE;
53520ba2cbe9Sxc151355 			break;
53530ba2cbe9Sxc151355 		case 'b':
5354f595a68aSyz147064 			if ((status = dladm_wlan_str2bsstype(optarg,
5355f595a68aSyz147064 			    &attr.wa_bsstype)) != DLADM_STATUS_OK) {
535633343a97Smeem 				die("invalid bsstype '%s'", optarg);
5357f595a68aSyz147064 			}
535833343a97Smeem 
5359f595a68aSyz147064 			attr.wa_valid |= DLADM_WLAN_ATTR_BSSTYPE;
53600ba2cbe9Sxc151355 			break;
53610ba2cbe9Sxc151355 		case 's':
5362f595a68aSyz147064 			if ((status = dladm_wlan_str2secmode(optarg,
5363f595a68aSyz147064 			    &attr.wa_secmode)) != DLADM_STATUS_OK) {
536433343a97Smeem 				die("invalid security mode '%s'", optarg);
5365f595a68aSyz147064 			}
536633343a97Smeem 
5367f595a68aSyz147064 			attr.wa_valid |= DLADM_WLAN_ATTR_SECMODE;
53680ba2cbe9Sxc151355 			break;
53690ba2cbe9Sxc151355 		case 'k':
5370a399b765Szf162725 			if (parse_wlan_keys(optarg, &keys, &key_count) < 0)
537133343a97Smeem 				die("invalid key(s) '%s'", optarg);
537233343a97Smeem 
5373a399b765Szf162725 			if (keys[0].wk_class == DLADM_SECOBJ_CLASS_WEP)
5374f595a68aSyz147064 				keysecmode = DLADM_WLAN_SECMODE_WEP;
5375a399b765Szf162725 			else
5376a399b765Szf162725 				keysecmode = DLADM_WLAN_SECMODE_WPA;
53770ba2cbe9Sxc151355 			break;
53780ba2cbe9Sxc151355 		case 'T':
53790ba2cbe9Sxc151355 			if (strcasecmp(optarg, "forever") == 0) {
53800ba2cbe9Sxc151355 				timeout = -1;
53810ba2cbe9Sxc151355 				break;
53820ba2cbe9Sxc151355 			}
538333343a97Smeem 			if (!str2int(optarg, &timeout) || timeout < 0)
538433343a97Smeem 				die("invalid timeout value '%s'", optarg);
53850ba2cbe9Sxc151355 			break;
53860ba2cbe9Sxc151355 		case 'c':
5387f595a68aSyz147064 			flags |= DLADM_WLAN_CONNECT_CREATEIBSS;
5388a399b765Szf162725 			flags |= DLADM_WLAN_CONNECT_CREATEIBSS;
53890ba2cbe9Sxc151355 			break;
53900ba2cbe9Sxc151355 		default:
53918d5c46e6Sam223141 			die_opterr(optopt, option, use);
53920ba2cbe9Sxc151355 			break;
53930ba2cbe9Sxc151355 		}
53940ba2cbe9Sxc151355 	}
53950ba2cbe9Sxc151355 
5396f595a68aSyz147064 	if (keysecmode == DLADM_WLAN_SECMODE_NONE) {
5397a399b765Szf162725 		if ((attr.wa_valid & DLADM_WLAN_ATTR_SECMODE) != 0) {
5398a399b765Szf162725 			die("key required for security mode '%s'",
5399a399b765Szf162725 			    dladm_wlan_secmode2str(&attr.wa_secmode, buf));
5400a399b765Szf162725 		}
54010ba2cbe9Sxc151355 	} else {
5402f595a68aSyz147064 		if ((attr.wa_valid & DLADM_WLAN_ATTR_SECMODE) != 0 &&
540333343a97Smeem 		    attr.wa_secmode != keysecmode)
540433343a97Smeem 			die("incompatible -s and -k options");
5405f595a68aSyz147064 		attr.wa_valid |= DLADM_WLAN_ATTR_SECMODE;
5406a399b765Szf162725 		attr.wa_secmode = keysecmode;
5407a399b765Szf162725 	}
54080ba2cbe9Sxc151355 
5409d62bc4baSyz147064 	if (optind == (argc - 1)) {
54104ac67f02SAnurag S. Maskey 		if ((status = dladm_name2info(handle, argv[optind], &linkid,
54114ac67f02SAnurag S. Maskey 		    NULL, NULL, NULL)) != DLADM_STATUS_OK) {
5412d62bc4baSyz147064 			die_dlerr(status, "link %s is not valid", argv[optind]);
5413d62bc4baSyz147064 		}
5414d62bc4baSyz147064 	} else if (optind != argc) {
54150ba2cbe9Sxc151355 		usage();
5416d62bc4baSyz147064 	}
54170ba2cbe9Sxc151355 
5418d62bc4baSyz147064 	if (linkid == DATALINK_ALL_LINKID) {
54190ba2cbe9Sxc151355 		wlan_count_attr_t wcattr;
54200ba2cbe9Sxc151355 
5421d62bc4baSyz147064 		wcattr.wc_linkid = DATALINK_INVALID_LINKID;
54220ba2cbe9Sxc151355 		wcattr.wc_count = 0;
54234ac67f02SAnurag S. Maskey 		(void) dladm_walk_datalink_id(do_count_wlan, handle, &wcattr,
5424d62bc4baSyz147064 		    DATALINK_CLASS_PHYS, DL_WIFI, DLADM_OPT_ACTIVE);
54250ba2cbe9Sxc151355 		if (wcattr.wc_count == 0) {
542633343a97Smeem 			die("no wifi links are available");
54270ba2cbe9Sxc151355 		} else if (wcattr.wc_count > 1) {
542833343a97Smeem 			die("link name is required when more than one wifi "
542933343a97Smeem 			    "link is available");
54300ba2cbe9Sxc151355 		}
5431d62bc4baSyz147064 		linkid = wcattr.wc_linkid;
54320ba2cbe9Sxc151355 	}
54330ba2cbe9Sxc151355 	attrp = (attr.wa_valid == 0) ? NULL : &attr;
543433343a97Smeem again:
54354ac67f02SAnurag S. Maskey 	if ((status = dladm_wlan_connect(handle, linkid, attrp, timeout, keys,
5436f595a68aSyz147064 	    key_count, flags)) != DLADM_STATUS_OK) {
5437f595a68aSyz147064 		if ((flags & DLADM_WLAN_CONNECT_NOSCAN) != 0) {
54380ba2cbe9Sxc151355 			/*
543933343a97Smeem 			 * Try again with scanning and filtering.
54400ba2cbe9Sxc151355 			 */
5441f595a68aSyz147064 			flags &= ~DLADM_WLAN_CONNECT_NOSCAN;
544233343a97Smeem 			goto again;
54430ba2cbe9Sxc151355 		}
544433343a97Smeem 
5445f595a68aSyz147064 		if (status == DLADM_STATUS_NOTFOUND) {
54460ba2cbe9Sxc151355 			if (attr.wa_valid == 0) {
544733343a97Smeem 				die("no wifi networks are available");
54480ba2cbe9Sxc151355 			} else {
544933343a97Smeem 				die("no wifi networks with the specified "
545033343a97Smeem 				    "criteria are available");
54510ba2cbe9Sxc151355 			}
54520ba2cbe9Sxc151355 		}
5453d62bc4baSyz147064 		die_dlerr(status, "cannot connect");
54540ba2cbe9Sxc151355 	}
54550ba2cbe9Sxc151355 	free(keys);
54560ba2cbe9Sxc151355 }
54570ba2cbe9Sxc151355 
54580ba2cbe9Sxc151355 /* ARGSUSED */
5459d62bc4baSyz147064 static int
54604ac67f02SAnurag S. Maskey do_all_disconnect_wifi(dladm_handle_t dh, datalink_id_t linkid, void *arg)
54610ba2cbe9Sxc151355 {
5462f595a68aSyz147064 	dladm_status_t	status;
54630ba2cbe9Sxc151355 
54644ac67f02SAnurag S. Maskey 	status = dladm_wlan_disconnect(dh, linkid);
5465f595a68aSyz147064 	if (status != DLADM_STATUS_OK)
5466d62bc4baSyz147064 		warn_dlerr(status, "cannot disconnect link");
546733343a97Smeem 
5468d62bc4baSyz147064 	return (DLADM_WALK_CONTINUE);
54690ba2cbe9Sxc151355 }
54700ba2cbe9Sxc151355 
54710ba2cbe9Sxc151355 static void
54728d5c46e6Sam223141 do_disconnect_wifi(int argc, char **argv, const char *use)
54730ba2cbe9Sxc151355 {
54740ba2cbe9Sxc151355 	int			option;
5475d62bc4baSyz147064 	datalink_id_t		linkid = DATALINK_ALL_LINKID;
54760ba2cbe9Sxc151355 	boolean_t		all_links = B_FALSE;
5477f595a68aSyz147064 	dladm_status_t		status;
54780ba2cbe9Sxc151355 	wlan_count_attr_t	wcattr;
54790ba2cbe9Sxc151355 
54800ba2cbe9Sxc151355 	opterr = 0;
54810ba2cbe9Sxc151355 	while ((option = getopt_long(argc, argv, ":a",
54820ba2cbe9Sxc151355 	    wifi_longopts, NULL)) != -1) {
54830ba2cbe9Sxc151355 		switch (option) {
54840ba2cbe9Sxc151355 		case 'a':
54850ba2cbe9Sxc151355 			all_links = B_TRUE;
54860ba2cbe9Sxc151355 			break;
54870ba2cbe9Sxc151355 		default:
54888d5c46e6Sam223141 			die_opterr(optopt, option, use);
54890ba2cbe9Sxc151355 			break;
54900ba2cbe9Sxc151355 		}
54910ba2cbe9Sxc151355 	}
54920ba2cbe9Sxc151355 
5493d62bc4baSyz147064 	if (optind == (argc - 1)) {
54944ac67f02SAnurag S. Maskey 		if ((status = dladm_name2info(handle, argv[optind], &linkid,
54954ac67f02SAnurag S. Maskey 		    NULL, NULL, NULL)) != DLADM_STATUS_OK) {
5496d62bc4baSyz147064 			die_dlerr(status, "link %s is not valid", argv[optind]);
5497d62bc4baSyz147064 		}
5498d62bc4baSyz147064 	} else if (optind != argc) {
54990ba2cbe9Sxc151355 		usage();
5500d62bc4baSyz147064 	}
55010ba2cbe9Sxc151355 
5502d62bc4baSyz147064 	if (linkid == DATALINK_ALL_LINKID) {
55030ba2cbe9Sxc151355 		if (!all_links) {
5504d62bc4baSyz147064 			wcattr.wc_linkid = linkid;
55050ba2cbe9Sxc151355 			wcattr.wc_count = 0;
55064ac67f02SAnurag S. Maskey 			(void) dladm_walk_datalink_id(do_count_wlan, handle,
55074ac67f02SAnurag S. Maskey 			    &wcattr, DATALINK_CLASS_PHYS, DL_WIFI,
55084ac67f02SAnurag S. Maskey 			    DLADM_OPT_ACTIVE);
55090ba2cbe9Sxc151355 			if (wcattr.wc_count == 0) {
551033343a97Smeem 				die("no wifi links are available");
55110ba2cbe9Sxc151355 			} else if (wcattr.wc_count > 1) {
551233343a97Smeem 				die("link name is required when more than "
551333343a97Smeem 				    "one wifi link is available");
55140ba2cbe9Sxc151355 			}
5515d62bc4baSyz147064 			linkid = wcattr.wc_linkid;
55160ba2cbe9Sxc151355 		} else {
5517d62bc4baSyz147064 			(void) dladm_walk_datalink_id(do_all_disconnect_wifi,
55184ac67f02SAnurag S. Maskey 			    handle, NULL, DATALINK_CLASS_PHYS, DL_WIFI,
5519d62bc4baSyz147064 			    DLADM_OPT_ACTIVE);
55200ba2cbe9Sxc151355 			return;
55210ba2cbe9Sxc151355 		}
55220ba2cbe9Sxc151355 	}
55234ac67f02SAnurag S. Maskey 	status = dladm_wlan_disconnect(handle, linkid);
5524f595a68aSyz147064 	if (status != DLADM_STATUS_OK)
5525d62bc4baSyz147064 		die_dlerr(status, "cannot disconnect");
55260ba2cbe9Sxc151355 }
55270ba2cbe9Sxc151355 
55280ba2cbe9Sxc151355 static void
5529d62bc4baSyz147064 print_linkprop(datalink_id_t linkid, show_linkprop_state_t *statep,
55304ac67f02SAnurag S. Maskey     const char *propname, dladm_prop_type_t type, const char *format,
55314ac67f02SAnurag S. Maskey     char **pptr)
55320ba2cbe9Sxc151355 {
55330ba2cbe9Sxc151355 	int		i;
55340ba2cbe9Sxc151355 	char		*ptr, *lim;
55350ba2cbe9Sxc151355 	char		buf[DLADM_STRSIZE];
5536da14cebeSEric Cheng 	char		*unknown = "--", *notsup = "";
55370ba2cbe9Sxc151355 	char		**propvals = statep->ls_propvals;
5538d62bc4baSyz147064 	uint_t		valcnt = DLADM_MAX_PROP_VALCNT;
55390ba2cbe9Sxc151355 	dladm_status_t	status;
55400ba2cbe9Sxc151355 
55414ac67f02SAnurag S. Maskey 	status = dladm_get_linkprop(handle, linkid, type, propname, propvals,
55424ac67f02SAnurag S. Maskey 	    &valcnt);
55430ba2cbe9Sxc151355 	if (status != DLADM_STATUS_OK) {
5544f595a68aSyz147064 		if (status == DLADM_STATUS_TEMPONLY) {
5545d62bc4baSyz147064 			if (type == DLADM_PROP_VAL_MODIFIABLE &&
5546d62bc4baSyz147064 			    statep->ls_persist) {
5547d62bc4baSyz147064 				valcnt = 1;
5548d62bc4baSyz147064 				propvals = &unknown;
5549d62bc4baSyz147064 			} else {
5550f595a68aSyz147064 				statep->ls_status = status;
5551e7801d59Ssowmini 				statep->ls_retstatus = status;
5552f595a68aSyz147064 				return;
5553d62bc4baSyz147064 			}
5554f595a68aSyz147064 		} else if (status == DLADM_STATUS_NOTSUP ||
5555f595a68aSyz147064 		    statep->ls_persist) {
55560ba2cbe9Sxc151355 			valcnt = 1;
5557afdda45fSVasumathi Sundaram - Sun Microsystems 			if (type == DLADM_PROP_VAL_CURRENT ||
5558afdda45fSVasumathi Sundaram - Sun Microsystems 			    type == DLADM_PROP_VAL_PERM)
55590ba2cbe9Sxc151355 				propvals = &unknown;
55600ba2cbe9Sxc151355 			else
55610ba2cbe9Sxc151355 				propvals = &notsup;
5562149b7eb2SSowmini Varadhan 		} else if (status == DLADM_STATUS_NOTDEFINED) {
5563149b7eb2SSowmini Varadhan 			propvals = &notsup; /* STR_UNDEF_VAL */
55640ba2cbe9Sxc151355 		} else {
5565e7801d59Ssowmini 			if (statep->ls_proplist &&
5566e7801d59Ssowmini 			    statep->ls_status == DLADM_STATUS_OK) {
5567f595a68aSyz147064 				warn_dlerr(status,
5568f595a68aSyz147064 				    "cannot get link property '%s' for %s",
5569f595a68aSyz147064 				    propname, statep->ls_link);
5570d62bc4baSyz147064 			}
5571e7801d59Ssowmini 			statep->ls_status = status;
5572e7801d59Ssowmini 			statep->ls_retstatus = status;
5573f595a68aSyz147064 			return;
55740ba2cbe9Sxc151355 		}
55750ba2cbe9Sxc151355 	}
55760ba2cbe9Sxc151355 
5577e7801d59Ssowmini 	statep->ls_status = DLADM_STATUS_OK;
5578e7801d59Ssowmini 
55790ba2cbe9Sxc151355 	ptr = buf;
55800ba2cbe9Sxc151355 	lim = buf + DLADM_STRSIZE;
55810ba2cbe9Sxc151355 	for (i = 0; i < valcnt; i++) {
55820ba2cbe9Sxc151355 		if (propvals[i][0] == '\0' && !statep->ls_parseable)
5583e7801d59Ssowmini 			ptr += snprintf(ptr, lim - ptr, STR_UNDEF_VAL",");
55840ba2cbe9Sxc151355 		else
55850ba2cbe9Sxc151355 			ptr += snprintf(ptr, lim - ptr, "%s,", propvals[i]);
55860ba2cbe9Sxc151355 		if (ptr >= lim)
55870ba2cbe9Sxc151355 			break;
55880ba2cbe9Sxc151355 	}
55890ba2cbe9Sxc151355 	if (valcnt > 0)
55900ba2cbe9Sxc151355 		buf[strlen(buf) - 1] = '\0';
55910ba2cbe9Sxc151355 
55920ba2cbe9Sxc151355 	lim = statep->ls_line + MAX_PROP_LINE;
55930ba2cbe9Sxc151355 	if (statep->ls_parseable) {
55940ba2cbe9Sxc151355 		*pptr += snprintf(*pptr, lim - *pptr,
5595e7801d59Ssowmini 		    "%s", buf);
55960ba2cbe9Sxc151355 	} else {
55970ba2cbe9Sxc151355 		*pptr += snprintf(*pptr, lim - *pptr, format, buf);
55980ba2cbe9Sxc151355 	}
55990ba2cbe9Sxc151355 }
56000ba2cbe9Sxc151355 
5601e7801d59Ssowmini static char *
5602e7801d59Ssowmini linkprop_callback(print_field_t *pf, void *ls_arg)
5603e7801d59Ssowmini {
5604e7801d59Ssowmini 	linkprop_args_t		*arg = ls_arg;
5605e7801d59Ssowmini 	char 			*propname = arg->ls_propname;
5606e7801d59Ssowmini 	show_linkprop_state_t	*statep = arg->ls_state;
5607e7801d59Ssowmini 	char			*ptr = statep->ls_line;
5608e7801d59Ssowmini 	char			*lim = ptr + MAX_PROP_LINE;
5609e7801d59Ssowmini 	datalink_id_t		linkid = arg->ls_linkid;
5610e7801d59Ssowmini 
5611e7801d59Ssowmini 	switch (pf->pf_index) {
5612e7801d59Ssowmini 	case LINKPROP_LINK:
5613e7801d59Ssowmini 		(void) snprintf(ptr, lim - ptr, "%s", statep->ls_link);
5614e7801d59Ssowmini 		break;
5615e7801d59Ssowmini 	case LINKPROP_PROPERTY:
5616e7801d59Ssowmini 		(void) snprintf(ptr, lim - ptr, "%s", propname);
5617e7801d59Ssowmini 		break;
5618e7801d59Ssowmini 	case LINKPROP_VALUE:
5619e7801d59Ssowmini 		print_linkprop(linkid, statep, propname,
5620e7801d59Ssowmini 		    statep->ls_persist ? DLADM_PROP_VAL_PERSISTENT :
5621e7801d59Ssowmini 		    DLADM_PROP_VAL_CURRENT, "%s", &ptr);
5622e7801d59Ssowmini 		/*
5623e7801d59Ssowmini 		 * If we failed to query the link property, for example, query
5624e7801d59Ssowmini 		 * the persistent value of a non-persistable link property,
5625e7801d59Ssowmini 		 * simply skip the output.
5626e7801d59Ssowmini 		 */
5627e7801d59Ssowmini 		if (statep->ls_status != DLADM_STATUS_OK)
5628e7801d59Ssowmini 			goto skip;
5629e7801d59Ssowmini 		ptr = statep->ls_line;
5630e7801d59Ssowmini 		break;
5631afdda45fSVasumathi Sundaram - Sun Microsystems 	case LINKPROP_PERM:
5632afdda45fSVasumathi Sundaram - Sun Microsystems 		print_linkprop(linkid, statep, propname,
5633afdda45fSVasumathi Sundaram - Sun Microsystems 		    DLADM_PROP_VAL_PERM, "%s", &ptr);
5634afdda45fSVasumathi Sundaram - Sun Microsystems 		if (statep->ls_status != DLADM_STATUS_OK)
5635afdda45fSVasumathi Sundaram - Sun Microsystems 			goto skip;
5636afdda45fSVasumathi Sundaram - Sun Microsystems 		ptr = statep->ls_line;
5637afdda45fSVasumathi Sundaram - Sun Microsystems 		break;
5638e7801d59Ssowmini 	case LINKPROP_DEFAULT:
5639e7801d59Ssowmini 		print_linkprop(linkid, statep, propname,
5640e7801d59Ssowmini 		    DLADM_PROP_VAL_DEFAULT, "%s", &ptr);
5641e7801d59Ssowmini 		if (statep->ls_status != DLADM_STATUS_OK)
5642e7801d59Ssowmini 			goto skip;
5643e7801d59Ssowmini 		ptr = statep->ls_line;
5644e7801d59Ssowmini 		break;
5645e7801d59Ssowmini 	case LINKPROP_POSSIBLE:
5646e7801d59Ssowmini 		print_linkprop(linkid, statep, propname,
5647e7801d59Ssowmini 		    DLADM_PROP_VAL_MODIFIABLE, "%s ", &ptr);
5648e7801d59Ssowmini 		if (statep->ls_status != DLADM_STATUS_OK)
5649e7801d59Ssowmini 			goto skip;
5650e7801d59Ssowmini 		ptr = statep->ls_line;
5651e7801d59Ssowmini 		break;
5652e7801d59Ssowmini 	default:
5653e7801d59Ssowmini 		die("invalid input");
5654e7801d59Ssowmini 		break;
5655e7801d59Ssowmini 	}
5656e7801d59Ssowmini 	return (ptr);
5657e7801d59Ssowmini skip:
5658e7801d59Ssowmini 	if (statep->ls_status != DLADM_STATUS_OK)
5659e7801d59Ssowmini 		return (NULL);
5660e7801d59Ssowmini 	else
5661e7801d59Ssowmini 		return ("");
5662e7801d59Ssowmini }
5663e7801d59Ssowmini 
5664bcb5c89dSSowmini Varadhan static boolean_t
5665bcb5c89dSSowmini Varadhan linkprop_is_supported(datalink_id_t  linkid, const char *propname,
5666bcb5c89dSSowmini Varadhan     show_linkprop_state_t *statep)
5667bcb5c89dSSowmini Varadhan {
5668bcb5c89dSSowmini Varadhan 	dladm_status_t	status;
5669bcb5c89dSSowmini Varadhan 	uint_t		valcnt = DLADM_MAX_PROP_VALCNT;
5670bcb5c89dSSowmini Varadhan 
56714784fcbdSSowmini Varadhan 	/* if used with -p flag, always print output */
56724784fcbdSSowmini Varadhan 	if (statep->ls_proplist != NULL)
56734784fcbdSSowmini Varadhan 		return (B_TRUE);
56744784fcbdSSowmini Varadhan 
56754ac67f02SAnurag S. Maskey 	status = dladm_get_linkprop(handle, linkid, DLADM_PROP_VAL_DEFAULT,
5676bcb5c89dSSowmini Varadhan 	    propname, statep->ls_propvals, &valcnt);
5677bcb5c89dSSowmini Varadhan 
5678149b7eb2SSowmini Varadhan 	if (status == DLADM_STATUS_OK)
5679149b7eb2SSowmini Varadhan 		return (B_TRUE);
5680149b7eb2SSowmini Varadhan 
5681149b7eb2SSowmini Varadhan 	/*
5682149b7eb2SSowmini Varadhan 	 * A system wide default value is not available for the
5683149b7eb2SSowmini Varadhan 	 * property. Check if current value can be retrieved.
5684149b7eb2SSowmini Varadhan 	 */
56854ac67f02SAnurag S. Maskey 	status = dladm_get_linkprop(handle, linkid, DLADM_PROP_VAL_CURRENT,
5686149b7eb2SSowmini Varadhan 	    propname, statep->ls_propvals, &valcnt);
5687149b7eb2SSowmini Varadhan 
5688149b7eb2SSowmini Varadhan 	return (status == DLADM_STATUS_OK);
5689bcb5c89dSSowmini Varadhan }
5690bcb5c89dSSowmini Varadhan 
56914ac67f02SAnurag S. Maskey /* ARGSUSED */
5692d62bc4baSyz147064 static int
56934ac67f02SAnurag S. Maskey show_linkprop(dladm_handle_t dh, datalink_id_t linkid, const char *propname,
56944ac67f02SAnurag S. Maskey     void *arg)
56950ba2cbe9Sxc151355 {
56960ba2cbe9Sxc151355 	show_linkprop_state_t	*statep = arg;
5697e7801d59Ssowmini 	linkprop_args_t		ls_arg;
56980ba2cbe9Sxc151355 
5699e7801d59Ssowmini 	bzero(&ls_arg, sizeof (ls_arg));
5700e7801d59Ssowmini 	ls_arg.ls_state = statep;
5701e7801d59Ssowmini 	ls_arg.ls_propname = (char *)propname;
5702e7801d59Ssowmini 	ls_arg.ls_linkid = linkid;
57030ba2cbe9Sxc151355 
57040ba2cbe9Sxc151355 	if (statep->ls_header) {
57050ba2cbe9Sxc151355 		statep->ls_header = B_FALSE;
57060ba2cbe9Sxc151355 		if (!statep->ls_parseable)
5707e7801d59Ssowmini 			print_header(&statep->ls_print);
57080ba2cbe9Sxc151355 	}
570962ee1d25SArtem Kachitchkine 	/*
571062ee1d25SArtem Kachitchkine 	 * This will need to be fixed when kernel interfaces are added
571162ee1d25SArtem Kachitchkine 	 * to enable walking of all known private properties. For now,
571262ee1d25SArtem Kachitchkine 	 * we are limited to walking persistent private properties only.
571362ee1d25SArtem Kachitchkine 	 */
571462ee1d25SArtem Kachitchkine 	if ((propname[0] == '_') && !statep->ls_persist &&
571562ee1d25SArtem Kachitchkine 	    (statep->ls_proplist == NULL))
571662ee1d25SArtem Kachitchkine 		return (DLADM_WALK_CONTINUE);
5717149b7eb2SSowmini Varadhan 	if (!statep->ls_parseable &&
5718149b7eb2SSowmini Varadhan 	    !linkprop_is_supported(linkid, propname, statep))
5719bcb5c89dSSowmini Varadhan 		return (DLADM_WALK_CONTINUE);
5720bcb5c89dSSowmini Varadhan 
5721e7801d59Ssowmini 	dladm_print_output(&statep->ls_print, statep->ls_parseable,
5722e7801d59Ssowmini 	    linkprop_callback, (void *)&ls_arg);
5723e7801d59Ssowmini 
5724d62bc4baSyz147064 	return (DLADM_WALK_CONTINUE);
57250ba2cbe9Sxc151355 }
57260ba2cbe9Sxc151355 
57270ba2cbe9Sxc151355 static void
57288d5c46e6Sam223141 do_show_linkprop(int argc, char **argv, const char *use)
57290ba2cbe9Sxc151355 {
5730f4b3ec61Sdh155122 	int			option;
5731*63a6526dSMichael Lim 	char			propstr[DLADM_STRSIZE];
5732da14cebeSEric Cheng 	dladm_arg_list_t	*proplist = NULL;
5733d62bc4baSyz147064 	datalink_id_t		linkid = DATALINK_ALL_LINKID;
57340ba2cbe9Sxc151355 	show_linkprop_state_t	state;
5735d62bc4baSyz147064 	uint32_t		flags = DLADM_OPT_ACTIVE;
5736d62bc4baSyz147064 	dladm_status_t		status;
5737e7801d59Ssowmini 	char			*fields_str = NULL;
5738e7801d59Ssowmini 	print_field_t		**fields;
5739e7801d59Ssowmini 	uint_t			nfields;
57400d365605Sschuster 	boolean_t		o_arg = B_FALSE;
5741e7801d59Ssowmini 	char			*all_fields =
5742afdda45fSVasumathi Sundaram - Sun Microsystems 	    "link,property,perm,value,default,possible";
5743e7801d59Ssowmini 
5744e7801d59Ssowmini 	fields_str = all_fields;
57450ba2cbe9Sxc151355 
5746*63a6526dSMichael Lim 	bzero(propstr, DLADM_STRSIZE);
57470ba2cbe9Sxc151355 	opterr = 0;
57480ba2cbe9Sxc151355 	state.ls_propvals = NULL;
57490ba2cbe9Sxc151355 	state.ls_line = NULL;
57500ba2cbe9Sxc151355 	state.ls_parseable = B_FALSE;
57510ba2cbe9Sxc151355 	state.ls_persist = B_FALSE;
57520ba2cbe9Sxc151355 	state.ls_header = B_TRUE;
5753e7801d59Ssowmini 	state.ls_retstatus = DLADM_STATUS_OK;
5754*63a6526dSMichael Lim 
5755e7801d59Ssowmini 	while ((option = getopt_long(argc, argv, ":p:cPo:",
57560ba2cbe9Sxc151355 	    prop_longopts, NULL)) != -1) {
57570ba2cbe9Sxc151355 		switch (option) {
57580ba2cbe9Sxc151355 		case 'p':
5759*63a6526dSMichael Lim 			(void) strlcat(propstr, optarg, DLADM_STRSIZE);
5760*63a6526dSMichael Lim 			if (strlcat(propstr, ",", DLADM_STRSIZE) >=
5761*63a6526dSMichael Lim 			    DLADM_STRSIZE)
5762*63a6526dSMichael Lim 				die("property list too long '%s'", propstr);
57630ba2cbe9Sxc151355 			break;
57640ba2cbe9Sxc151355 		case 'c':
57650ba2cbe9Sxc151355 			state.ls_parseable = B_TRUE;
57660ba2cbe9Sxc151355 			break;
57670ba2cbe9Sxc151355 		case 'P':
57680ba2cbe9Sxc151355 			state.ls_persist = B_TRUE;
5769d62bc4baSyz147064 			flags = DLADM_OPT_PERSIST;
57700ba2cbe9Sxc151355 			break;
5771e7801d59Ssowmini 		case 'o':
57720d365605Sschuster 			o_arg = B_TRUE;
5773e7801d59Ssowmini 			if (strcasecmp(optarg, "all") == 0)
5774e7801d59Ssowmini 				fields_str = all_fields;
5775e7801d59Ssowmini 			else
5776e7801d59Ssowmini 				fields_str = optarg;
5777e7801d59Ssowmini 			break;
57780ba2cbe9Sxc151355 		default:
57798d5c46e6Sam223141 			die_opterr(optopt, option, use);
57800ba2cbe9Sxc151355 			break;
57810ba2cbe9Sxc151355 		}
57820ba2cbe9Sxc151355 	}
57830ba2cbe9Sxc151355 
57840d365605Sschuster 	if (state.ls_parseable && !o_arg)
57850d365605Sschuster 		die("-c requires -o");
57860d365605Sschuster 
57870d365605Sschuster 	if (state.ls_parseable && fields_str == all_fields)
57880d365605Sschuster 		die("\"-o all\" is invalid with -c");
57890d365605Sschuster 
5790d62bc4baSyz147064 	if (optind == (argc - 1)) {
57914ac67f02SAnurag S. Maskey 		if ((status = dladm_name2info(handle, argv[optind], &linkid,
57924ac67f02SAnurag S. Maskey 		    NULL, NULL, NULL)) != DLADM_STATUS_OK) {
5793d62bc4baSyz147064 			die_dlerr(status, "link %s is not valid", argv[optind]);
5794d62bc4baSyz147064 		}
5795d62bc4baSyz147064 	} else if (optind != argc) {
57960ba2cbe9Sxc151355 		usage();
5797d62bc4baSyz147064 	}
57980ba2cbe9Sxc151355 
5799*63a6526dSMichael Lim 	if (dladm_parse_link_props(propstr, &proplist, B_TRUE)
5800*63a6526dSMichael Lim 	    != DLADM_STATUS_OK)
5801*63a6526dSMichael Lim 		die("invalid link properties specified");
5802*63a6526dSMichael Lim 
5803e7801d59Ssowmini 	bzero(&state.ls_print, sizeof (print_state_t));
5804f4b3ec61Sdh155122 	state.ls_proplist = proplist;
5805f595a68aSyz147064 	state.ls_status = DLADM_STATUS_OK;
5806f4b3ec61Sdh155122 
5807e7801d59Ssowmini 	fields = parse_output_fields(fields_str, linkprop_fields,
5808e7801d59Ssowmini 	    LINKPROP_MAX_FIELDS, CMD_TYPE_ANY, &nfields);
5809e7801d59Ssowmini 
5810e7801d59Ssowmini 	if (fields == NULL) {
5811e7801d59Ssowmini 		die("invalid field(s) specified");
5812e7801d59Ssowmini 		return;
5813e7801d59Ssowmini 	}
5814e7801d59Ssowmini 
5815e7801d59Ssowmini 	state.ls_print.ps_fields = fields;
5816e7801d59Ssowmini 	state.ls_print.ps_nfields = nfields;
5817d62bc4baSyz147064 	if (linkid == DATALINK_ALL_LINKID) {
58184ac67f02SAnurag S. Maskey 		(void) dladm_walk_datalink_id(show_linkprop_onelink, handle,
58194ac67f02SAnurag S. Maskey 		    &state, DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE, flags);
5820f4b3ec61Sdh155122 	} else {
58214ac67f02SAnurag S. Maskey 		(void) show_linkprop_onelink(handle, linkid, &state);
5822f4b3ec61Sdh155122 	}
5823da14cebeSEric Cheng 	dladm_free_props(proplist);
5824f595a68aSyz147064 
58254ac67f02SAnurag S. Maskey 	if (state.ls_retstatus != DLADM_STATUS_OK) {
58264ac67f02SAnurag S. Maskey 		dladm_close(handle);
5827f595a68aSyz147064 		exit(EXIT_FAILURE);
5828f4b3ec61Sdh155122 	}
58294ac67f02SAnurag S. Maskey }
5830f4b3ec61Sdh155122 
5831d62bc4baSyz147064 static int
58324ac67f02SAnurag S. Maskey show_linkprop_onelink(dladm_handle_t hdl, datalink_id_t linkid, void *arg)
5833f4b3ec61Sdh155122 {
5834948f2876Sss150715 	int			i;
5835f4b3ec61Sdh155122 	char			*buf;
5836d62bc4baSyz147064 	uint32_t		flags;
5837da14cebeSEric Cheng 	dladm_arg_list_t	*proplist = NULL;
5838d62bc4baSyz147064 	show_linkprop_state_t	*statep = arg;
5839d62bc4baSyz147064 	dlpi_handle_t		dh = NULL;
5840f4b3ec61Sdh155122 
5841d62bc4baSyz147064 	statep->ls_status = DLADM_STATUS_OK;
5842d62bc4baSyz147064 
58434ac67f02SAnurag S. Maskey 	if (dladm_datalink_id2info(hdl, linkid, &flags, NULL, NULL,
58444ac67f02SAnurag S. Maskey 	    statep->ls_link, MAXLINKNAMELEN) != DLADM_STATUS_OK) {
5845d62bc4baSyz147064 		statep->ls_status = DLADM_STATUS_NOTFOUND;
5846d62bc4baSyz147064 		return (DLADM_WALK_CONTINUE);
5847d62bc4baSyz147064 	}
5848d62bc4baSyz147064 
5849d62bc4baSyz147064 	if ((statep->ls_persist && !(flags & DLADM_OPT_PERSIST)) ||
5850d62bc4baSyz147064 	    (!statep->ls_persist && !(flags & DLADM_OPT_ACTIVE))) {
5851d62bc4baSyz147064 		statep->ls_status = DLADM_STATUS_BADARG;
5852d62bc4baSyz147064 		return (DLADM_WALK_CONTINUE);
5853d62bc4baSyz147064 	}
5854d62bc4baSyz147064 
5855f4b3ec61Sdh155122 	proplist = statep->ls_proplist;
58560ba2cbe9Sxc151355 
58570ba2cbe9Sxc151355 	/*
58580ba2cbe9Sxc151355 	 * When some WiFi links are opened for the first time, their hardware
58590ba2cbe9Sxc151355 	 * automatically scans for APs and does other slow operations.	Thus,
58600ba2cbe9Sxc151355 	 * if there are no open links, the retrieval of link properties
58610ba2cbe9Sxc151355 	 * (below) will proceed slowly unless we hold the link open.
5862d62bc4baSyz147064 	 *
5863d62bc4baSyz147064 	 * Note that failure of dlpi_open() does not necessarily mean invalid
5864d62bc4baSyz147064 	 * link properties, because dlpi_open() may fail because of incorrect
5865d62bc4baSyz147064 	 * autopush configuration. Therefore, we ingore the return value of
5866d62bc4baSyz147064 	 * dlpi_open().
58670ba2cbe9Sxc151355 	 */
5868d62bc4baSyz147064 	if (!statep->ls_persist)
5869d62bc4baSyz147064 		(void) dlpi_open(statep->ls_link, &dh, 0);
58700ba2cbe9Sxc151355 
5871d62bc4baSyz147064 	buf = malloc((sizeof (char *) + DLADM_PROP_VAL_MAX) *
5872d62bc4baSyz147064 	    DLADM_MAX_PROP_VALCNT + MAX_PROP_LINE);
587333343a97Smeem 	if (buf == NULL)
587433343a97Smeem 		die("insufficient memory");
587533343a97Smeem 
5876f4b3ec61Sdh155122 	statep->ls_propvals = (char **)(void *)buf;
5877d62bc4baSyz147064 	for (i = 0; i < DLADM_MAX_PROP_VALCNT; i++) {
5878d62bc4baSyz147064 		statep->ls_propvals[i] = buf +
5879d62bc4baSyz147064 		    sizeof (char *) * DLADM_MAX_PROP_VALCNT +
58800ba2cbe9Sxc151355 		    i * DLADM_PROP_VAL_MAX;
58810ba2cbe9Sxc151355 	}
5882f4b3ec61Sdh155122 	statep->ls_line = buf +
5883d62bc4baSyz147064 	    (sizeof (char *) + DLADM_PROP_VAL_MAX) * DLADM_MAX_PROP_VALCNT;
58840ba2cbe9Sxc151355 
58850ba2cbe9Sxc151355 	if (proplist != NULL) {
5886da14cebeSEric Cheng 		for (i = 0; i < proplist->al_count; i++) {
58874ac67f02SAnurag S. Maskey 			(void) show_linkprop(hdl, linkid,
5888da14cebeSEric Cheng 			    proplist->al_info[i].ai_name, statep);
58890ba2cbe9Sxc151355 		}
5890d62bc4baSyz147064 	} else {
58914ac67f02SAnurag S. Maskey 		(void) dladm_walk_linkprop(hdl, linkid, statep,
58924ac67f02SAnurag S. Maskey 		    show_linkprop);
5893d62bc4baSyz147064 	}
5894d62bc4baSyz147064 	if (dh != NULL)
5895948f2876Sss150715 		dlpi_close(dh);
58960ba2cbe9Sxc151355 	free(buf);
5897d62bc4baSyz147064 	return (DLADM_WALK_CONTINUE);
58980ba2cbe9Sxc151355 }
58990ba2cbe9Sxc151355 
59000ba2cbe9Sxc151355 static dladm_status_t
5901d62bc4baSyz147064 set_linkprop_persist(datalink_id_t linkid, const char *prop_name,
5902d62bc4baSyz147064     char **prop_val, uint_t val_cnt, boolean_t reset)
59030ba2cbe9Sxc151355 {
59040ba2cbe9Sxc151355 	dladm_status_t	status;
59050ba2cbe9Sxc151355 
59064ac67f02SAnurag S. Maskey 	status = dladm_set_linkprop(handle, linkid, prop_name, prop_val,
59074ac67f02SAnurag S. Maskey 	    val_cnt, DLADM_OPT_PERSIST);
59080ba2cbe9Sxc151355 
59090ba2cbe9Sxc151355 	if (status != DLADM_STATUS_OK) {
5910da14cebeSEric Cheng 		warn_dlerr(status, "cannot persistently %s link property '%s'",
5911da14cebeSEric Cheng 		    reset ? "reset" : "set", prop_name);
59120ba2cbe9Sxc151355 	}
59130ba2cbe9Sxc151355 	return (status);
59140ba2cbe9Sxc151355 }
59150ba2cbe9Sxc151355 
5916da14cebeSEric Cheng static int
59174ac67f02SAnurag S. Maskey reset_one_linkprop(dladm_handle_t dh, datalink_id_t linkid,
59184ac67f02SAnurag S. Maskey     const char *propname, void *arg)
5919da14cebeSEric Cheng {
5920da14cebeSEric Cheng 	set_linkprop_state_t	*statep = arg;
5921da14cebeSEric Cheng 	dladm_status_t		status;
5922da14cebeSEric Cheng 
59234ac67f02SAnurag S. Maskey 	status = dladm_set_linkprop(dh, linkid, propname, NULL, 0,
5924da14cebeSEric Cheng 	    DLADM_OPT_ACTIVE);
5925da14cebeSEric Cheng 	if (status != DLADM_STATUS_OK) {
5926da14cebeSEric Cheng 		warn_dlerr(status, "cannot reset link property '%s' on '%s'",
5927da14cebeSEric Cheng 		    propname, statep->ls_name);
5928da14cebeSEric Cheng 	}
5929da14cebeSEric Cheng 	if (!statep->ls_temp) {
5930da14cebeSEric Cheng 		dladm_status_t	s;
5931da14cebeSEric Cheng 
5932da14cebeSEric Cheng 		s = set_linkprop_persist(linkid, propname, NULL, 0,
5933da14cebeSEric Cheng 		    statep->ls_reset);
5934da14cebeSEric Cheng 		if (s != DLADM_STATUS_OK)
5935da14cebeSEric Cheng 			status = s;
5936da14cebeSEric Cheng 	}
5937da14cebeSEric Cheng 	if (status != DLADM_STATUS_OK)
5938da14cebeSEric Cheng 		statep->ls_status = status;
5939da14cebeSEric Cheng 
5940da14cebeSEric Cheng 	return (DLADM_WALK_CONTINUE);
5941da14cebeSEric Cheng }
5942da14cebeSEric Cheng 
59430ba2cbe9Sxc151355 static void
59448d5c46e6Sam223141 set_linkprop(int argc, char **argv, boolean_t reset, const char *use)
59450ba2cbe9Sxc151355 {
59460ba2cbe9Sxc151355 	int			i, option;
59470ba2cbe9Sxc151355 	char			errmsg[DLADM_STRSIZE];
5948d62bc4baSyz147064 	char			*altroot = NULL;
5949d62bc4baSyz147064 	datalink_id_t		linkid;
59500ba2cbe9Sxc151355 	boolean_t		temp = B_FALSE;
59510ba2cbe9Sxc151355 	dladm_status_t		status = DLADM_STATUS_OK;
5952*63a6526dSMichael Lim 	char			propstr[DLADM_STRSIZE];
5953da14cebeSEric Cheng 	dladm_arg_list_t	*proplist = NULL;
59540ba2cbe9Sxc151355 
59550ba2cbe9Sxc151355 	opterr = 0;
5956*63a6526dSMichael Lim 	bzero(propstr, DLADM_STRSIZE);
5957*63a6526dSMichael Lim 
59580ba2cbe9Sxc151355 	while ((option = getopt_long(argc, argv, ":p:R:t",
59590ba2cbe9Sxc151355 	    prop_longopts, NULL)) != -1) {
59600ba2cbe9Sxc151355 		switch (option) {
59610ba2cbe9Sxc151355 		case 'p':
5962*63a6526dSMichael Lim 			(void) strlcat(propstr, optarg, DLADM_STRSIZE);
5963*63a6526dSMichael Lim 			if (strlcat(propstr, ",", DLADM_STRSIZE) >=
5964*63a6526dSMichael Lim 			    DLADM_STRSIZE)
5965*63a6526dSMichael Lim 				die("property list too long '%s'", propstr);
59660ba2cbe9Sxc151355 			break;
59670ba2cbe9Sxc151355 		case 't':
59680ba2cbe9Sxc151355 			temp = B_TRUE;
59690ba2cbe9Sxc151355 			break;
59700ba2cbe9Sxc151355 		case 'R':
5971d62bc4baSyz147064 			altroot = optarg;
59720ba2cbe9Sxc151355 			break;
59730ba2cbe9Sxc151355 		default:
59748d5c46e6Sam223141 			die_opterr(optopt, option, use);
59758d5c46e6Sam223141 
59760ba2cbe9Sxc151355 		}
59770ba2cbe9Sxc151355 	}
59780ba2cbe9Sxc151355 
5979d62bc4baSyz147064 	/* get link name (required last argument) */
5980d62bc4baSyz147064 	if (optind != (argc - 1))
59810ba2cbe9Sxc151355 		usage();
59820ba2cbe9Sxc151355 
5983*63a6526dSMichael Lim 	if (dladm_parse_link_props(propstr, &proplist, reset) !=
5984*63a6526dSMichael Lim 	    DLADM_STATUS_OK)
5985*63a6526dSMichael Lim 		die("invalid link properties specified");
5986*63a6526dSMichael Lim 
5987d62bc4baSyz147064 	if (proplist == NULL && !reset)
598833343a97Smeem 		die("link property must be specified");
598933343a97Smeem 
5990d62bc4baSyz147064 	if (altroot != NULL) {
5991da14cebeSEric Cheng 		dladm_free_props(proplist);
5992d62bc4baSyz147064 		altroot_cmd(altroot, argc, argv);
5993d62bc4baSyz147064 	}
5994d62bc4baSyz147064 
59954ac67f02SAnurag S. Maskey 	status = dladm_name2info(handle, argv[optind], &linkid, NULL, NULL,
59964ac67f02SAnurag S. Maskey 	    NULL);
5997d62bc4baSyz147064 	if (status != DLADM_STATUS_OK)
5998d62bc4baSyz147064 		die_dlerr(status, "link %s is not valid", argv[optind]);
5999d62bc4baSyz147064 
6000d62bc4baSyz147064 	if (proplist == NULL) {
6001da14cebeSEric Cheng 		set_linkprop_state_t	state;
600213994ee8Sxz162242 
6003da14cebeSEric Cheng 		state.ls_name = argv[optind];
6004da14cebeSEric Cheng 		state.ls_reset = reset;
6005da14cebeSEric Cheng 		state.ls_temp = temp;
6006da14cebeSEric Cheng 		state.ls_status = DLADM_STATUS_OK;
6007da14cebeSEric Cheng 
60084ac67f02SAnurag S. Maskey 		(void) dladm_walk_linkprop(handle, linkid, &state,
60094ac67f02SAnurag S. Maskey 		    reset_one_linkprop);
6010da14cebeSEric Cheng 
6011da14cebeSEric Cheng 		status = state.ls_status;
60120ba2cbe9Sxc151355 		goto done;
60130ba2cbe9Sxc151355 	}
60140ba2cbe9Sxc151355 
6015da14cebeSEric Cheng 	for (i = 0; i < proplist->al_count; i++) {
6016da14cebeSEric Cheng 		dladm_arg_info_t	*aip = &proplist->al_info[i];
60170ba2cbe9Sxc151355 		char		**val;
60180ba2cbe9Sxc151355 		uint_t		count;
60190ba2cbe9Sxc151355 		dladm_status_t	s;
60200ba2cbe9Sxc151355 
60210ba2cbe9Sxc151355 		if (reset) {
60220ba2cbe9Sxc151355 			val = NULL;
60230ba2cbe9Sxc151355 			count = 0;
60240ba2cbe9Sxc151355 		} else {
6025da14cebeSEric Cheng 			val = aip->ai_val;
6026da14cebeSEric Cheng 			count = aip->ai_count;
60270ba2cbe9Sxc151355 			if (count == 0) {
602833343a97Smeem 				warn("no value specified for '%s'",
6029da14cebeSEric Cheng 				    aip->ai_name);
60300ba2cbe9Sxc151355 				status = DLADM_STATUS_BADARG;
60310ba2cbe9Sxc151355 				continue;
60320ba2cbe9Sxc151355 			}
60330ba2cbe9Sxc151355 		}
60344ac67f02SAnurag S. Maskey 		s = dladm_set_linkprop(handle, linkid, aip->ai_name, val, count,
6035d62bc4baSyz147064 		    DLADM_OPT_ACTIVE);
60360ba2cbe9Sxc151355 		if (s == DLADM_STATUS_OK) {
60370ba2cbe9Sxc151355 			if (!temp) {
6038d62bc4baSyz147064 				s = set_linkprop_persist(linkid,
6039da14cebeSEric Cheng 				    aip->ai_name, val, count, reset);
60400ba2cbe9Sxc151355 				if (s != DLADM_STATUS_OK)
60410ba2cbe9Sxc151355 					status = s;
60420ba2cbe9Sxc151355 			}
60430ba2cbe9Sxc151355 			continue;
60440ba2cbe9Sxc151355 		}
60450ba2cbe9Sxc151355 		status = s;
60460ba2cbe9Sxc151355 		switch (s) {
60470ba2cbe9Sxc151355 		case DLADM_STATUS_NOTFOUND:
6048da14cebeSEric Cheng 			warn("invalid link property '%s'", aip->ai_name);
60490ba2cbe9Sxc151355 			break;
60500ba2cbe9Sxc151355 		case DLADM_STATUS_BADVAL: {
60510ba2cbe9Sxc151355 			int		j;
60520ba2cbe9Sxc151355 			char		*ptr, *lim;
60530ba2cbe9Sxc151355 			char		**propvals = NULL;
6054d62bc4baSyz147064 			uint_t		valcnt = DLADM_MAX_PROP_VALCNT;
60550ba2cbe9Sxc151355 
60560ba2cbe9Sxc151355 			ptr = malloc((sizeof (char *) +
6057d62bc4baSyz147064 			    DLADM_PROP_VAL_MAX) * DLADM_MAX_PROP_VALCNT +
60580ba2cbe9Sxc151355 			    MAX_PROP_LINE);
60590ba2cbe9Sxc151355 
60600ba2cbe9Sxc151355 			propvals = (char **)(void *)ptr;
606133343a97Smeem 			if (propvals == NULL)
606233343a97Smeem 				die("insufficient memory");
606333343a97Smeem 
6064d62bc4baSyz147064 			for (j = 0; j < DLADM_MAX_PROP_VALCNT; j++) {
60650ba2cbe9Sxc151355 				propvals[j] = ptr + sizeof (char *) *
6066d62bc4baSyz147064 				    DLADM_MAX_PROP_VALCNT +
60670ba2cbe9Sxc151355 				    j * DLADM_PROP_VAL_MAX;
60680ba2cbe9Sxc151355 			}
60694ac67f02SAnurag S. Maskey 			s = dladm_get_linkprop(handle, linkid,
6070da14cebeSEric Cheng 			    DLADM_PROP_VAL_MODIFIABLE, aip->ai_name, propvals,
6071d62bc4baSyz147064 			    &valcnt);
6072d62bc4baSyz147064 
6073d62bc4baSyz147064 			if (s != DLADM_STATUS_OK) {
6074d62bc4baSyz147064 				warn_dlerr(status, "cannot set link property "
6075da14cebeSEric Cheng 				    "'%s' on '%s'", aip->ai_name, argv[optind]);
6076d62bc4baSyz147064 				free(propvals);
6077d62bc4baSyz147064 				break;
6078d62bc4baSyz147064 			}
60790ba2cbe9Sxc151355 
60800ba2cbe9Sxc151355 			ptr = errmsg;
60810ba2cbe9Sxc151355 			lim = ptr + DLADM_STRSIZE;
60820ba2cbe9Sxc151355 			*ptr = '\0';
6083d62bc4baSyz147064 			for (j = 0; j < valcnt; j++) {
60840ba2cbe9Sxc151355 				ptr += snprintf(ptr, lim - ptr, "%s,",
60850ba2cbe9Sxc151355 				    propvals[j]);
60860ba2cbe9Sxc151355 				if (ptr >= lim)
60870ba2cbe9Sxc151355 					break;
60880ba2cbe9Sxc151355 			}
6089f4b3ec61Sdh155122 			if (ptr > errmsg) {
60900ba2cbe9Sxc151355 				*(ptr - 1) = '\0';
609133343a97Smeem 				warn("link property '%s' must be one of: %s",
6092da14cebeSEric Cheng 				    aip->ai_name, errmsg);
6093f4b3ec61Sdh155122 			} else
6094f4b3ec61Sdh155122 				warn("invalid link property '%s'", *val);
60950ba2cbe9Sxc151355 			free(propvals);
60960ba2cbe9Sxc151355 			break;
60970ba2cbe9Sxc151355 		}
60980ba2cbe9Sxc151355 		default:
60990ba2cbe9Sxc151355 			if (reset) {
610033343a97Smeem 				warn_dlerr(status, "cannot reset link property "
6101da14cebeSEric Cheng 				    "'%s' on '%s'", aip->ai_name, argv[optind]);
61020ba2cbe9Sxc151355 			} else {
610333343a97Smeem 				warn_dlerr(status, "cannot set link property "
6104da14cebeSEric Cheng 				    "'%s' on '%s'", aip->ai_name, argv[optind]);
61050ba2cbe9Sxc151355 			}
61060ba2cbe9Sxc151355 			break;
61070ba2cbe9Sxc151355 		}
61080ba2cbe9Sxc151355 	}
61090ba2cbe9Sxc151355 done:
6110da14cebeSEric Cheng 	dladm_free_props(proplist);
61114ac67f02SAnurag S. Maskey 	if (status != DLADM_STATUS_OK) {
61124ac67f02SAnurag S. Maskey 		dladm_close(handle);
61130ba2cbe9Sxc151355 		exit(1);
61140ba2cbe9Sxc151355 	}
61154ac67f02SAnurag S. Maskey }
61160ba2cbe9Sxc151355 
61170ba2cbe9Sxc151355 static void
61188d5c46e6Sam223141 do_set_linkprop(int argc, char **argv, const char *use)
61190ba2cbe9Sxc151355 {
61208d5c46e6Sam223141 	set_linkprop(argc, argv, B_FALSE, use);
61210ba2cbe9Sxc151355 }
61220ba2cbe9Sxc151355 
61230ba2cbe9Sxc151355 static void
61248d5c46e6Sam223141 do_reset_linkprop(int argc, char **argv, const char *use)
61250ba2cbe9Sxc151355 {
61268d5c46e6Sam223141 	set_linkprop(argc, argv, B_TRUE, use);
61270ba2cbe9Sxc151355 }
61280ba2cbe9Sxc151355 
61290ba2cbe9Sxc151355 static int
61300ba2cbe9Sxc151355 convert_secobj(char *buf, uint_t len, uint8_t *obj_val, uint_t *obj_lenp,
61310ba2cbe9Sxc151355     dladm_secobj_class_t class)
61320ba2cbe9Sxc151355 {
61330ba2cbe9Sxc151355 	int error = 0;
61340ba2cbe9Sxc151355 
6135a399b765Szf162725 	if (class == DLADM_SECOBJ_CLASS_WPA) {
6136a399b765Szf162725 		if (len < 8 || len > 63)
6137a399b765Szf162725 			return (EINVAL);
6138a399b765Szf162725 		(void) memcpy(obj_val, buf, len);
6139a399b765Szf162725 		*obj_lenp = len;
6140a399b765Szf162725 		return (error);
6141a399b765Szf162725 	}
61420ba2cbe9Sxc151355 
6143a399b765Szf162725 	if (class == DLADM_SECOBJ_CLASS_WEP) {
61440ba2cbe9Sxc151355 		switch (len) {
61450ba2cbe9Sxc151355 		case 5:			/* ASCII key sizes */
61460ba2cbe9Sxc151355 		case 13:
61470ba2cbe9Sxc151355 			(void) memcpy(obj_val, buf, len);
61480ba2cbe9Sxc151355 			*obj_lenp = len;
61490ba2cbe9Sxc151355 			break;
61500ba2cbe9Sxc151355 		case 10:		/* Hex key sizes, not preceded by 0x */
61510ba2cbe9Sxc151355 		case 26:
61520ba2cbe9Sxc151355 			error = hexascii_to_octet(buf, len, obj_val, obj_lenp);
61530ba2cbe9Sxc151355 			break;
61540ba2cbe9Sxc151355 		case 12:		/* Hex key sizes, preceded by 0x */
61550ba2cbe9Sxc151355 		case 28:
61560ba2cbe9Sxc151355 			if (strncmp(buf, "0x", 2) != 0)
61570ba2cbe9Sxc151355 				return (EINVAL);
6158a399b765Szf162725 			error = hexascii_to_octet(buf + 2, len - 2,
6159a399b765Szf162725 			    obj_val, obj_lenp);
61600ba2cbe9Sxc151355 			break;
61610ba2cbe9Sxc151355 		default:
61620ba2cbe9Sxc151355 			return (EINVAL);
61630ba2cbe9Sxc151355 		}
61640ba2cbe9Sxc151355 		return (error);
61650ba2cbe9Sxc151355 	}
61660ba2cbe9Sxc151355 
6167a399b765Szf162725 	return (ENOENT);
6168a399b765Szf162725 }
6169a399b765Szf162725 
61700ba2cbe9Sxc151355 static void
61710ba2cbe9Sxc151355 defersig(int sig)
61720ba2cbe9Sxc151355 {
61730ba2cbe9Sxc151355 	signalled = sig;
61740ba2cbe9Sxc151355 }
61750ba2cbe9Sxc151355 
61760ba2cbe9Sxc151355 static int
61770ba2cbe9Sxc151355 get_secobj_from_tty(uint_t try, const char *objname, char *buf)
61780ba2cbe9Sxc151355 {
61790ba2cbe9Sxc151355 	uint_t		len = 0;
61800ba2cbe9Sxc151355 	int		c;
61810ba2cbe9Sxc151355 	struct termios	stored, current;
61820ba2cbe9Sxc151355 	void		(*sigfunc)(int);
61830ba2cbe9Sxc151355 
61840ba2cbe9Sxc151355 	/*
61850ba2cbe9Sxc151355 	 * Turn off echo -- but before we do so, defer SIGINT handling
61860ba2cbe9Sxc151355 	 * so that a ^C doesn't leave the terminal corrupted.
61870ba2cbe9Sxc151355 	 */
61880ba2cbe9Sxc151355 	sigfunc = signal(SIGINT, defersig);
61890ba2cbe9Sxc151355 	(void) fflush(stdin);
61900ba2cbe9Sxc151355 	(void) tcgetattr(0, &stored);
61910ba2cbe9Sxc151355 	current = stored;
61920ba2cbe9Sxc151355 	current.c_lflag &= ~(ICANON|ECHO);
61930ba2cbe9Sxc151355 	current.c_cc[VTIME] = 0;
61940ba2cbe9Sxc151355 	current.c_cc[VMIN] = 1;
61950ba2cbe9Sxc151355 	(void) tcsetattr(0, TCSANOW, &current);
61960ba2cbe9Sxc151355 again:
61970ba2cbe9Sxc151355 	if (try == 1)
61980ba2cbe9Sxc151355 		(void) printf(gettext("provide value for '%s': "), objname);
61990ba2cbe9Sxc151355 	else
62000ba2cbe9Sxc151355 		(void) printf(gettext("confirm value for '%s': "), objname);
62010ba2cbe9Sxc151355 
62020ba2cbe9Sxc151355 	(void) fflush(stdout);
62030ba2cbe9Sxc151355 	while (signalled == 0) {
62040ba2cbe9Sxc151355 		c = getchar();
62050ba2cbe9Sxc151355 		if (c == '\n' || c == '\r') {
62060ba2cbe9Sxc151355 			if (len != 0)
62070ba2cbe9Sxc151355 				break;
62080ba2cbe9Sxc151355 			(void) putchar('\n');
62090ba2cbe9Sxc151355 			goto again;
62100ba2cbe9Sxc151355 		}
62110ba2cbe9Sxc151355 
62120ba2cbe9Sxc151355 		buf[len++] = c;
62130ba2cbe9Sxc151355 		if (len >= DLADM_SECOBJ_VAL_MAX - 1)
62140ba2cbe9Sxc151355 			break;
62150ba2cbe9Sxc151355 		(void) putchar('*');
62160ba2cbe9Sxc151355 	}
62170ba2cbe9Sxc151355 
62180ba2cbe9Sxc151355 	(void) putchar('\n');
62190ba2cbe9Sxc151355 	(void) fflush(stdin);
62200ba2cbe9Sxc151355 
62210ba2cbe9Sxc151355 	/*
62220ba2cbe9Sxc151355 	 * Restore terminal setting and handle deferred signals.
62230ba2cbe9Sxc151355 	 */
62240ba2cbe9Sxc151355 	(void) tcsetattr(0, TCSANOW, &stored);
62250ba2cbe9Sxc151355 
62260ba2cbe9Sxc151355 	(void) signal(SIGINT, sigfunc);
62270ba2cbe9Sxc151355 	if (signalled != 0)
62280ba2cbe9Sxc151355 		(void) kill(getpid(), signalled);
62290ba2cbe9Sxc151355 
62300ba2cbe9Sxc151355 	return (len);
62310ba2cbe9Sxc151355 }
62320ba2cbe9Sxc151355 
62330ba2cbe9Sxc151355 static int
62340ba2cbe9Sxc151355 get_secobj_val(char *obj_name, uint8_t *obj_val, uint_t *obj_lenp,
62350ba2cbe9Sxc151355     dladm_secobj_class_t class, FILE *filep)
62360ba2cbe9Sxc151355 {
62370ba2cbe9Sxc151355 	int		rval;
62380ba2cbe9Sxc151355 	uint_t		len, len2;
62390ba2cbe9Sxc151355 	char		buf[DLADM_SECOBJ_VAL_MAX], buf2[DLADM_SECOBJ_VAL_MAX];
62400ba2cbe9Sxc151355 
62410ba2cbe9Sxc151355 	if (filep == NULL) {
62420ba2cbe9Sxc151355 		len = get_secobj_from_tty(1, obj_name, buf);
62430ba2cbe9Sxc151355 		rval = convert_secobj(buf, len, obj_val, obj_lenp, class);
62440ba2cbe9Sxc151355 		if (rval == 0) {
62450ba2cbe9Sxc151355 			len2 = get_secobj_from_tty(2, obj_name, buf2);
62460ba2cbe9Sxc151355 			if (len != len2 || memcmp(buf, buf2, len) != 0)
62470ba2cbe9Sxc151355 				rval = ENOTSUP;
62480ba2cbe9Sxc151355 		}
62490ba2cbe9Sxc151355 		return (rval);
62500ba2cbe9Sxc151355 	} else {
62510ba2cbe9Sxc151355 		for (;;) {
62520ba2cbe9Sxc151355 			if (fgets(buf, sizeof (buf), filep) == NULL)
62530ba2cbe9Sxc151355 				break;
62540ba2cbe9Sxc151355 			if (isspace(buf[0]))
62550ba2cbe9Sxc151355 				continue;
62560ba2cbe9Sxc151355 
62570ba2cbe9Sxc151355 			len = strlen(buf);
62580ba2cbe9Sxc151355 			if (buf[len - 1] == '\n') {
62590ba2cbe9Sxc151355 				buf[len - 1] = '\0';
62600ba2cbe9Sxc151355 				len--;
62610ba2cbe9Sxc151355 			}
62620ba2cbe9Sxc151355 			break;
62630ba2cbe9Sxc151355 		}
62640ba2cbe9Sxc151355 		(void) fclose(filep);
62650ba2cbe9Sxc151355 	}
62660ba2cbe9Sxc151355 	return (convert_secobj(buf, len, obj_val, obj_lenp, class));
62670ba2cbe9Sxc151355 }
62680ba2cbe9Sxc151355 
62690ba2cbe9Sxc151355 static boolean_t
62700ba2cbe9Sxc151355 check_auth(const char *auth)
62710ba2cbe9Sxc151355 {
62720ba2cbe9Sxc151355 	struct passwd	*pw;
62730ba2cbe9Sxc151355 
62740ba2cbe9Sxc151355 	if ((pw = getpwuid(getuid())) == NULL)
62750ba2cbe9Sxc151355 		return (B_FALSE);
62760ba2cbe9Sxc151355 
62770ba2cbe9Sxc151355 	return (chkauthattr(auth, pw->pw_name) != 0);
62780ba2cbe9Sxc151355 }
62790ba2cbe9Sxc151355 
62800ba2cbe9Sxc151355 static void
62810ba2cbe9Sxc151355 audit_secobj(char *auth, char *class, char *obj,
62820ba2cbe9Sxc151355     boolean_t success, boolean_t create)
62830ba2cbe9Sxc151355 {
62840ba2cbe9Sxc151355 	adt_session_data_t	*ah;
62850ba2cbe9Sxc151355 	adt_event_data_t	*event;
62860ba2cbe9Sxc151355 	au_event_t		flag;
62870ba2cbe9Sxc151355 	char			*errstr;
62880ba2cbe9Sxc151355 
62890ba2cbe9Sxc151355 	if (create) {
62900ba2cbe9Sxc151355 		flag = ADT_dladm_create_secobj;
62910ba2cbe9Sxc151355 		errstr = "ADT_dladm_create_secobj";
62920ba2cbe9Sxc151355 	} else {
62930ba2cbe9Sxc151355 		flag = ADT_dladm_delete_secobj;
62940ba2cbe9Sxc151355 		errstr = "ADT_dladm_delete_secobj";
62950ba2cbe9Sxc151355 	}
62960ba2cbe9Sxc151355 
629733343a97Smeem 	if (adt_start_session(&ah, NULL, ADT_USE_PROC_DATA) != 0)
629833343a97Smeem 		die("adt_start_session: %s", strerror(errno));
62990ba2cbe9Sxc151355 
630033343a97Smeem 	if ((event = adt_alloc_event(ah, flag)) == NULL)
630133343a97Smeem 		die("adt_alloc_event (%s): %s", errstr, strerror(errno));
63020ba2cbe9Sxc151355 
63030ba2cbe9Sxc151355 	/* fill in audit info */
63040ba2cbe9Sxc151355 	if (create) {
63050ba2cbe9Sxc151355 		event->adt_dladm_create_secobj.auth_used = auth;
63060ba2cbe9Sxc151355 		event->adt_dladm_create_secobj.obj_class = class;
63070ba2cbe9Sxc151355 		event->adt_dladm_create_secobj.obj_name = obj;
63080ba2cbe9Sxc151355 	} else {
63090ba2cbe9Sxc151355 		event->adt_dladm_delete_secobj.auth_used = auth;
63100ba2cbe9Sxc151355 		event->adt_dladm_delete_secobj.obj_class = class;
63110ba2cbe9Sxc151355 		event->adt_dladm_delete_secobj.obj_name = obj;
63120ba2cbe9Sxc151355 	}
63130ba2cbe9Sxc151355 
63140ba2cbe9Sxc151355 	if (success) {
63150ba2cbe9Sxc151355 		if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS) != 0) {
631633343a97Smeem 			die("adt_put_event (%s, success): %s", errstr,
631733343a97Smeem 			    strerror(errno));
63180ba2cbe9Sxc151355 		}
63190ba2cbe9Sxc151355 	} else {
63200ba2cbe9Sxc151355 		if (adt_put_event(event, ADT_FAILURE,
63210ba2cbe9Sxc151355 		    ADT_FAIL_VALUE_AUTH) != 0) {
632233343a97Smeem 			die("adt_put_event: (%s, failure): %s", errstr,
632333343a97Smeem 			    strerror(errno));
63240ba2cbe9Sxc151355 		}
63250ba2cbe9Sxc151355 	}
63260ba2cbe9Sxc151355 
63270ba2cbe9Sxc151355 	adt_free_event(event);
63280ba2cbe9Sxc151355 	(void) adt_end_session(ah);
63290ba2cbe9Sxc151355 }
63300ba2cbe9Sxc151355 
63310ba2cbe9Sxc151355 #define	MAX_SECOBJS		32
63320ba2cbe9Sxc151355 #define	MAX_SECOBJ_NAMELEN	32
63330ba2cbe9Sxc151355 static void
63348d5c46e6Sam223141 do_create_secobj(int argc, char **argv, const char *use)
63350ba2cbe9Sxc151355 {
63360ba2cbe9Sxc151355 	int			option, rval;
63370ba2cbe9Sxc151355 	FILE			*filep = NULL;
63380ba2cbe9Sxc151355 	char			*obj_name = NULL;
63390ba2cbe9Sxc151355 	char			*class_name = NULL;
63400ba2cbe9Sxc151355 	uint8_t			obj_val[DLADM_SECOBJ_VAL_MAX];
63410ba2cbe9Sxc151355 	uint_t			obj_len;
63420ba2cbe9Sxc151355 	boolean_t		success, temp = B_FALSE;
63430ba2cbe9Sxc151355 	dladm_status_t		status;
63440ba2cbe9Sxc151355 	dladm_secobj_class_t	class = -1;
63450ba2cbe9Sxc151355 	uid_t			euid;
63460ba2cbe9Sxc151355 
63470ba2cbe9Sxc151355 	opterr = 0;
63480ba2cbe9Sxc151355 	(void) memset(obj_val, 0, DLADM_SECOBJ_VAL_MAX);
63490ba2cbe9Sxc151355 	while ((option = getopt_long(argc, argv, ":f:c:R:t",
63500ba2cbe9Sxc151355 	    wifi_longopts, NULL)) != -1) {
63510ba2cbe9Sxc151355 		switch (option) {
63520ba2cbe9Sxc151355 		case 'f':
63530ba2cbe9Sxc151355 			euid = geteuid();
63540ba2cbe9Sxc151355 			(void) seteuid(getuid());
63550ba2cbe9Sxc151355 			filep = fopen(optarg, "r");
63560ba2cbe9Sxc151355 			if (filep == NULL) {
635733343a97Smeem 				die("cannot open %s: %s", optarg,
635833343a97Smeem 				    strerror(errno));
63590ba2cbe9Sxc151355 			}
63600ba2cbe9Sxc151355 			(void) seteuid(euid);
63610ba2cbe9Sxc151355 			break;
63620ba2cbe9Sxc151355 		case 'c':
63630ba2cbe9Sxc151355 			class_name = optarg;
63640ba2cbe9Sxc151355 			status = dladm_str2secobjclass(optarg, &class);
63650ba2cbe9Sxc151355 			if (status != DLADM_STATUS_OK) {
636633343a97Smeem 				die("invalid secure object class '%s', "
6367a399b765Szf162725 				    "valid values are: wep, wpa", optarg);
63680ba2cbe9Sxc151355 			}
63690ba2cbe9Sxc151355 			break;
63700ba2cbe9Sxc151355 		case 't':
63710ba2cbe9Sxc151355 			temp = B_TRUE;
63720ba2cbe9Sxc151355 			break;
63730ba2cbe9Sxc151355 		case 'R':
63740ba2cbe9Sxc151355 			status = dladm_set_rootdir(optarg);
63750ba2cbe9Sxc151355 			if (status != DLADM_STATUS_OK) {
637633343a97Smeem 				die_dlerr(status, "invalid directory "
637733343a97Smeem 				    "specified");
63780ba2cbe9Sxc151355 			}
63790ba2cbe9Sxc151355 			break;
63800ba2cbe9Sxc151355 		default:
63818d5c46e6Sam223141 			die_opterr(optopt, option, use);
63820ba2cbe9Sxc151355 			break;
63830ba2cbe9Sxc151355 		}
63840ba2cbe9Sxc151355 	}
63850ba2cbe9Sxc151355 
63860ba2cbe9Sxc151355 	if (optind == (argc - 1))
63870ba2cbe9Sxc151355 		obj_name = argv[optind];
63880ba2cbe9Sxc151355 	else if (optind != argc)
63890ba2cbe9Sxc151355 		usage();
63900ba2cbe9Sxc151355 
639133343a97Smeem 	if (class == -1)
639233343a97Smeem 		die("secure object class required");
63930ba2cbe9Sxc151355 
639433343a97Smeem 	if (obj_name == NULL)
639533343a97Smeem 		die("secure object name required");
63960ba2cbe9Sxc151355 
6397a9489f61SAnurag S. Maskey 	if (!dladm_valid_secobj_name(obj_name))
6398a9489f61SAnurag S. Maskey 		die("invalid secure object name '%s'", obj_name);
6399a9489f61SAnurag S. Maskey 
64000ba2cbe9Sxc151355 	success = check_auth(LINK_SEC_AUTH);
64010ba2cbe9Sxc151355 	audit_secobj(LINK_SEC_AUTH, class_name, obj_name, success, B_TRUE);
640233343a97Smeem 	if (!success)
640333343a97Smeem 		die("authorization '%s' is required", LINK_SEC_AUTH);
64040ba2cbe9Sxc151355 
640533343a97Smeem 	rval = get_secobj_val(obj_name, obj_val, &obj_len, class, filep);
640633343a97Smeem 	if (rval != 0) {
64070ba2cbe9Sxc151355 		switch (rval) {
64080ba2cbe9Sxc151355 		case ENOENT:
640933343a97Smeem 			die("invalid secure object class");
64100ba2cbe9Sxc151355 			break;
64110ba2cbe9Sxc151355 		case EINVAL:
641233343a97Smeem 			die("invalid secure object value");
64130ba2cbe9Sxc151355 			break;
64140ba2cbe9Sxc151355 		case ENOTSUP:
641533343a97Smeem 			die("verification failed");
64160ba2cbe9Sxc151355 			break;
64170ba2cbe9Sxc151355 		default:
641833343a97Smeem 			die("invalid secure object: %s", strerror(rval));
64190ba2cbe9Sxc151355 			break;
64200ba2cbe9Sxc151355 		}
64210ba2cbe9Sxc151355 	}
64220ba2cbe9Sxc151355 
64234ac67f02SAnurag S. Maskey 	status = dladm_set_secobj(handle, obj_name, class, obj_val, obj_len,
6424d62bc4baSyz147064 	    DLADM_OPT_CREATE | DLADM_OPT_ACTIVE);
64250ba2cbe9Sxc151355 	if (status != DLADM_STATUS_OK) {
642633343a97Smeem 		die_dlerr(status, "could not create secure object '%s'",
642733343a97Smeem 		    obj_name);
64280ba2cbe9Sxc151355 	}
64290ba2cbe9Sxc151355 	if (temp)
64300ba2cbe9Sxc151355 		return;
64310ba2cbe9Sxc151355 
64324ac67f02SAnurag S. Maskey 	status = dladm_set_secobj(handle, obj_name, class, obj_val, obj_len,
64330ba2cbe9Sxc151355 	    DLADM_OPT_PERSIST);
64340ba2cbe9Sxc151355 	if (status != DLADM_STATUS_OK) {
643533343a97Smeem 		warn_dlerr(status, "could not persistently create secure "
643633343a97Smeem 		    "object '%s'", obj_name);
64370ba2cbe9Sxc151355 	}
64380ba2cbe9Sxc151355 }
64390ba2cbe9Sxc151355 
64400ba2cbe9Sxc151355 static void
64418d5c46e6Sam223141 do_delete_secobj(int argc, char **argv, const char *use)
64420ba2cbe9Sxc151355 {
64430ba2cbe9Sxc151355 	int		i, option;
64440ba2cbe9Sxc151355 	boolean_t	temp = B_FALSE;
64450ba2cbe9Sxc151355 	split_t		*sp = NULL;
64460ba2cbe9Sxc151355 	boolean_t	success;
64470ba2cbe9Sxc151355 	dladm_status_t	status, pstatus;
64480ba2cbe9Sxc151355 
64490ba2cbe9Sxc151355 	opterr = 0;
64500ba2cbe9Sxc151355 	status = pstatus = DLADM_STATUS_OK;
645133343a97Smeem 	while ((option = getopt_long(argc, argv, ":R:t",
64520ba2cbe9Sxc151355 	    wifi_longopts, NULL)) != -1) {
64530ba2cbe9Sxc151355 		switch (option) {
64540ba2cbe9Sxc151355 		case 't':
64550ba2cbe9Sxc151355 			temp = B_TRUE;
64560ba2cbe9Sxc151355 			break;
64570ba2cbe9Sxc151355 		case 'R':
64580ba2cbe9Sxc151355 			status = dladm_set_rootdir(optarg);
64590ba2cbe9Sxc151355 			if (status != DLADM_STATUS_OK) {
646033343a97Smeem 				die_dlerr(status, "invalid directory "
646133343a97Smeem 				    "specified");
64620ba2cbe9Sxc151355 			}
64630ba2cbe9Sxc151355 			break;
64640ba2cbe9Sxc151355 		default:
64658d5c46e6Sam223141 			die_opterr(optopt, option, use);
64660ba2cbe9Sxc151355 			break;
64670ba2cbe9Sxc151355 		}
64680ba2cbe9Sxc151355 	}
64690ba2cbe9Sxc151355 
64700ba2cbe9Sxc151355 	if (optind == (argc - 1)) {
64710ba2cbe9Sxc151355 		sp = split(argv[optind], MAX_SECOBJS, MAX_SECOBJ_NAMELEN);
64720ba2cbe9Sxc151355 		if (sp == NULL) {
647333343a97Smeem 			die("invalid secure object name(s): '%s'",
647433343a97Smeem 			    argv[optind]);
64750ba2cbe9Sxc151355 		}
64760ba2cbe9Sxc151355 	} else if (optind != argc)
64770ba2cbe9Sxc151355 		usage();
64780ba2cbe9Sxc151355 
647933343a97Smeem 	if (sp == NULL || sp->s_nfields < 1)
648033343a97Smeem 		die("secure object name required");
64810ba2cbe9Sxc151355 
64820ba2cbe9Sxc151355 	success = check_auth(LINK_SEC_AUTH);
6483a399b765Szf162725 	audit_secobj(LINK_SEC_AUTH, "unknown", argv[optind], success, B_FALSE);
648433343a97Smeem 	if (!success)
648533343a97Smeem 		die("authorization '%s' is required", LINK_SEC_AUTH);
64860ba2cbe9Sxc151355 
64870ba2cbe9Sxc151355 	for (i = 0; i < sp->s_nfields; i++) {
64884ac67f02SAnurag S. Maskey 		status = dladm_unset_secobj(handle, sp->s_fields[i],
64894ac67f02SAnurag S. Maskey 		    DLADM_OPT_ACTIVE);
64900ba2cbe9Sxc151355 		if (!temp) {
64914ac67f02SAnurag S. Maskey 			pstatus = dladm_unset_secobj(handle, sp->s_fields[i],
64920ba2cbe9Sxc151355 			    DLADM_OPT_PERSIST);
64930ba2cbe9Sxc151355 		} else {
64940ba2cbe9Sxc151355 			pstatus = DLADM_STATUS_OK;
64950ba2cbe9Sxc151355 		}
64960ba2cbe9Sxc151355 
64970ba2cbe9Sxc151355 		if (status != DLADM_STATUS_OK) {
649833343a97Smeem 			warn_dlerr(status, "could not delete secure object "
649933343a97Smeem 			    "'%s'", sp->s_fields[i]);
65000ba2cbe9Sxc151355 		}
65010ba2cbe9Sxc151355 		if (pstatus != DLADM_STATUS_OK) {
650233343a97Smeem 			warn_dlerr(pstatus, "could not persistently delete "
650333343a97Smeem 			    "secure object '%s'", sp->s_fields[i]);
65040ba2cbe9Sxc151355 		}
65050ba2cbe9Sxc151355 	}
65064ac67f02SAnurag S. Maskey 
65074ac67f02SAnurag S. Maskey 	if (status != DLADM_STATUS_OK || pstatus != DLADM_STATUS_OK) {
65084ac67f02SAnurag S. Maskey 		dladm_close(handle);
65090ba2cbe9Sxc151355 		exit(1);
65100ba2cbe9Sxc151355 	}
65114ac67f02SAnurag S. Maskey }
65120ba2cbe9Sxc151355 
65130ba2cbe9Sxc151355 typedef struct show_secobj_state {
65140ba2cbe9Sxc151355 	boolean_t	ss_persist;
65150ba2cbe9Sxc151355 	boolean_t	ss_parseable;
65160ba2cbe9Sxc151355 	boolean_t	ss_header;
6517e7801d59Ssowmini 	print_state_t	ss_print;
65180ba2cbe9Sxc151355 } show_secobj_state_t;
65190ba2cbe9Sxc151355 
65200ba2cbe9Sxc151355 
65210ba2cbe9Sxc151355 static boolean_t
65224ac67f02SAnurag S. Maskey show_secobj(dladm_handle_t dh, void *arg, const char *obj_name)
65230ba2cbe9Sxc151355 {
65240ba2cbe9Sxc151355 	uint_t			obj_len = DLADM_SECOBJ_VAL_MAX;
65250ba2cbe9Sxc151355 	uint8_t			obj_val[DLADM_SECOBJ_VAL_MAX];
65260ba2cbe9Sxc151355 	char			buf[DLADM_STRSIZE];
65270ba2cbe9Sxc151355 	uint_t			flags = 0;
65280ba2cbe9Sxc151355 	dladm_secobj_class_t	class;
65290ba2cbe9Sxc151355 	show_secobj_state_t	*statep = arg;
65300ba2cbe9Sxc151355 	dladm_status_t		status;
6531e7801d59Ssowmini 	secobj_fields_buf_t	sbuf;
65320ba2cbe9Sxc151355 
65335f5c9f54SAnurag S. Maskey 	bzero(&sbuf, sizeof (secobj_fields_buf_t));
65340ba2cbe9Sxc151355 	if (statep->ss_persist)
65350ba2cbe9Sxc151355 		flags |= DLADM_OPT_PERSIST;
65360ba2cbe9Sxc151355 
65374ac67f02SAnurag S. Maskey 	status = dladm_get_secobj(dh, obj_name, &class, obj_val, &obj_len,
65384ac67f02SAnurag S. Maskey 	    flags);
653933343a97Smeem 	if (status != DLADM_STATUS_OK)
654033343a97Smeem 		die_dlerr(status, "cannot get secure object '%s'", obj_name);
65410ba2cbe9Sxc151355 
65420ba2cbe9Sxc151355 	if (statep->ss_header) {
65430ba2cbe9Sxc151355 		statep->ss_header = B_FALSE;
65440ba2cbe9Sxc151355 		if (!statep->ss_parseable)
6545e7801d59Ssowmini 			print_header(&statep->ss_print);
65460ba2cbe9Sxc151355 	}
65470ba2cbe9Sxc151355 
6548e7801d59Ssowmini 	(void) snprintf(sbuf.ss_obj_name, sizeof (sbuf.ss_obj_name),
6549e7801d59Ssowmini 	    obj_name);
6550e7801d59Ssowmini 	(void) dladm_secobjclass2str(class, buf);
6551e7801d59Ssowmini 	(void) snprintf(sbuf.ss_class, sizeof (sbuf.ss_class), "%s", buf);
6552e7801d59Ssowmini 	if (getuid() == 0) {
65530ba2cbe9Sxc151355 		char	val[DLADM_SECOBJ_VAL_MAX * 2];
65540ba2cbe9Sxc151355 		uint_t	len = sizeof (val);
65550ba2cbe9Sxc151355 
6556e7801d59Ssowmini 		if (octet_to_hexascii(obj_val, obj_len, val, &len) == 0)
6557e7801d59Ssowmini 			(void) snprintf(sbuf.ss_val,
6558e7801d59Ssowmini 			    sizeof (sbuf.ss_val), "%s", val);
65590ba2cbe9Sxc151355 	}
6560e7801d59Ssowmini 	dladm_print_output(&statep->ss_print, statep->ss_parseable,
6561e7801d59Ssowmini 	    dladm_print_field, (void *)&sbuf);
65620ba2cbe9Sxc151355 	return (B_TRUE);
65630ba2cbe9Sxc151355 }
65640ba2cbe9Sxc151355 
65650ba2cbe9Sxc151355 static void
65668d5c46e6Sam223141 do_show_secobj(int argc, char **argv, const char *use)
65670ba2cbe9Sxc151355 {
65680ba2cbe9Sxc151355 	int			option;
65690ba2cbe9Sxc151355 	show_secobj_state_t	state;
65700ba2cbe9Sxc151355 	dladm_status_t		status;
65710d365605Sschuster 	boolean_t		o_arg = B_FALSE;
65720ba2cbe9Sxc151355 	uint_t			i;
65730ba2cbe9Sxc151355 	split_t			*sp;
65740ba2cbe9Sxc151355 	uint_t			flags;
6575e7801d59Ssowmini 	char			*fields_str = NULL;
6576e7801d59Ssowmini 	print_field_t		**fields;
6577e7801d59Ssowmini 	uint_t			nfields;
6578e7801d59Ssowmini 	char			*def_fields = "object,class";
6579e7801d59Ssowmini 	char			*all_fields = "object,class,value";
65800ba2cbe9Sxc151355 
65810ba2cbe9Sxc151355 	opterr = 0;
6582e7801d59Ssowmini 	bzero(&state, sizeof (state));
6583e7801d59Ssowmini 	state.ss_parseable = B_FALSE;
6584e7801d59Ssowmini 	fields_str = def_fields;
65850ba2cbe9Sxc151355 	state.ss_persist = B_FALSE;
65860ba2cbe9Sxc151355 	state.ss_parseable = B_FALSE;
65870ba2cbe9Sxc151355 	state.ss_header = B_TRUE;
6588e7801d59Ssowmini 	while ((option = getopt_long(argc, argv, ":pPo:",
65890ba2cbe9Sxc151355 	    wifi_longopts, NULL)) != -1) {
65900ba2cbe9Sxc151355 		switch (option) {
65910ba2cbe9Sxc151355 		case 'p':
65920ba2cbe9Sxc151355 			state.ss_parseable = B_TRUE;
65930ba2cbe9Sxc151355 			break;
65940ba2cbe9Sxc151355 		case 'P':
65950ba2cbe9Sxc151355 			state.ss_persist = B_TRUE;
65960ba2cbe9Sxc151355 			break;
6597e7801d59Ssowmini 		case 'o':
65980d365605Sschuster 			o_arg = B_TRUE;
6599e7801d59Ssowmini 			if (strcasecmp(optarg, "all") == 0)
6600e7801d59Ssowmini 				fields_str = all_fields;
6601e7801d59Ssowmini 			else
6602e7801d59Ssowmini 				fields_str = optarg;
66030ba2cbe9Sxc151355 			break;
66040ba2cbe9Sxc151355 		default:
66058d5c46e6Sam223141 			die_opterr(optopt, option, use);
66060ba2cbe9Sxc151355 			break;
66070ba2cbe9Sxc151355 		}
66080ba2cbe9Sxc151355 	}
66090ba2cbe9Sxc151355 
66100d365605Sschuster 	if (state.ss_parseable && !o_arg)
66110d365605Sschuster 		die("option -c requires -o");
66120d365605Sschuster 
66130d365605Sschuster 	if (state.ss_parseable && fields_str == all_fields)
66140d365605Sschuster 		die("\"-o all\" is invalid with -p");
66150d365605Sschuster 
6616e7801d59Ssowmini 	fields = parse_output_fields(fields_str, secobj_fields,
6617e7801d59Ssowmini 	    DEV_SOBJ_FIELDS, CMD_TYPE_ANY, &nfields);
6618e7801d59Ssowmini 
6619e7801d59Ssowmini 	if (fields == NULL) {
6620e7801d59Ssowmini 		die("invalid field(s) specified");
6621e7801d59Ssowmini 		return;
6622e7801d59Ssowmini 	}
6623e7801d59Ssowmini 	state.ss_print.ps_fields = fields;
6624e7801d59Ssowmini 	state.ss_print.ps_nfields = nfields;
6625e7801d59Ssowmini 
6626e7801d59Ssowmini 	flags = state.ss_persist ? DLADM_OPT_PERSIST : 0;
66274ac67f02SAnurag S. Maskey 
66280ba2cbe9Sxc151355 	if (optind == (argc - 1)) {
66290ba2cbe9Sxc151355 		sp = split(argv[optind], MAX_SECOBJS, MAX_SECOBJ_NAMELEN);
66300ba2cbe9Sxc151355 		if (sp == NULL) {
663133343a97Smeem 			die("invalid secure object name(s): '%s'",
663233343a97Smeem 			    argv[optind]);
66330ba2cbe9Sxc151355 		}
66340ba2cbe9Sxc151355 		for (i = 0; i < sp->s_nfields; i++) {
66354ac67f02SAnurag S. Maskey 			if (!show_secobj(handle, &state, sp->s_fields[i]))
66360ba2cbe9Sxc151355 				break;
66370ba2cbe9Sxc151355 		}
66380ba2cbe9Sxc151355 		splitfree(sp);
66390ba2cbe9Sxc151355 		return;
66400ba2cbe9Sxc151355 	} else if (optind != argc)
66410ba2cbe9Sxc151355 		usage();
66420ba2cbe9Sxc151355 
66434ac67f02SAnurag S. Maskey 	status = dladm_walk_secobj(handle, &state, show_secobj, flags);
66444ac67f02SAnurag S. Maskey 
664533343a97Smeem 	if (status != DLADM_STATUS_OK)
664633343a97Smeem 		die_dlerr(status, "show-secobj");
66470ba2cbe9Sxc151355 }
66480ba2cbe9Sxc151355 
66490ba2cbe9Sxc151355 /*ARGSUSED*/
6650d62bc4baSyz147064 static int
66514ac67f02SAnurag S. Maskey i_dladm_init_linkprop(dladm_handle_t dh, datalink_id_t linkid, void *arg)
6652d62bc4baSyz147064 {
66534ac67f02SAnurag S. Maskey 	(void) dladm_init_linkprop(dh, linkid, B_TRUE);
6654d62bc4baSyz147064 	return (DLADM_WALK_CONTINUE);
6655d62bc4baSyz147064 }
6656d62bc4baSyz147064 
66578d5c46e6Sam223141 /*ARGSUSED*/
6658da14cebeSEric Cheng void
66598d5c46e6Sam223141 do_init_linkprop(int argc, char **argv, const char *use)
66600ba2cbe9Sxc151355 {
666130890389Sartem 	int			option;
666230890389Sartem 	dladm_status_t		status;
666330890389Sartem 	datalink_id_t		linkid = DATALINK_ALL_LINKID;
666430890389Sartem 	datalink_media_t	media = DATALINK_ANY_MEDIATYPE;
666530890389Sartem 	uint_t			any_media = B_TRUE;
666630890389Sartem 
666730890389Sartem 	opterr = 0;
666830890389Sartem 	while ((option = getopt(argc, argv, ":w")) != -1) {
666930890389Sartem 		switch (option) {
667030890389Sartem 		case 'w':
667130890389Sartem 			media = DL_WIFI;
667230890389Sartem 			any_media = B_FALSE;
667330890389Sartem 			break;
667430890389Sartem 		default:
66758d5c46e6Sam223141 			/*
66768d5c46e6Sam223141 			 * Because init-linkprop is not a public command,
66778d5c46e6Sam223141 			 * print the usage instead.
66788d5c46e6Sam223141 			 */
66798d5c46e6Sam223141 			usage();
668030890389Sartem 			break;
668130890389Sartem 		}
668230890389Sartem 	}
668330890389Sartem 
668430890389Sartem 	if (optind == (argc - 1)) {
66854ac67f02SAnurag S. Maskey 		if ((status = dladm_name2info(handle, argv[optind], &linkid,
66864ac67f02SAnurag S. Maskey 		    NULL, NULL, NULL)) != DLADM_STATUS_OK)
668730890389Sartem 			die_dlerr(status, "link %s is not valid", argv[optind]);
668830890389Sartem 	} else if (optind != argc) {
668930890389Sartem 		usage();
669030890389Sartem 	}
669130890389Sartem 
669230890389Sartem 	if (linkid == DATALINK_ALL_LINKID) {
6693d62bc4baSyz147064 		/*
669430890389Sartem 		 * linkprops of links of other classes have been initialized as
6695d62bc4baSyz147064 		 * part of the dladm up-xxx operation.
6696d62bc4baSyz147064 		 */
66974ac67f02SAnurag S. Maskey 		(void) dladm_walk_datalink_id(i_dladm_init_linkprop, handle,
66984ac67f02SAnurag S. Maskey 		    NULL, DATALINK_CLASS_PHYS, media, DLADM_OPT_PERSIST);
669930890389Sartem 	} else {
67004ac67f02SAnurag S. Maskey 		(void) dladm_init_linkprop(handle, linkid, any_media);
670130890389Sartem 	}
67020ba2cbe9Sxc151355 }
67030ba2cbe9Sxc151355 
67040ba2cbe9Sxc151355 static void
67058d5c46e6Sam223141 do_show_ether(int argc, char **argv, const char *use)
6706e7801d59Ssowmini {
6707e7801d59Ssowmini 	int 			option;
6708e7801d59Ssowmini 	datalink_id_t		linkid;
6709e7801d59Ssowmini 	print_ether_state_t 	state;
6710e7801d59Ssowmini 	print_field_t 		**fields;
67110d365605Sschuster 	boolean_t		o_arg = B_FALSE;
6712e7801d59Ssowmini 	char			*fields_str;
6713e7801d59Ssowmini 	uint_t			nfields;
6714e7801d59Ssowmini 	char			*all_fields =
6715e7801d59Ssowmini 	    "link,ptype,state,auto,speed-duplex,pause,rem_fault";
6716e7801d59Ssowmini 	char			*default_fields =
6717e7801d59Ssowmini 	    "link,ptype,state,auto,speed-duplex,pause";
6718e7801d59Ssowmini 
6719e7801d59Ssowmini 	fields_str = default_fields;
6720e7801d59Ssowmini 	bzero(&state, sizeof (state));
6721e7801d59Ssowmini 	state.es_link = NULL;
6722e7801d59Ssowmini 	state.es_parseable = B_FALSE;
6723e7801d59Ssowmini 
6724e7801d59Ssowmini 	while ((option = getopt_long(argc, argv, "o:px",
6725e7801d59Ssowmini 	    showeth_lopts, NULL)) != -1) {
6726e7801d59Ssowmini 		switch (option) {
6727e7801d59Ssowmini 			case 'x':
6728e7801d59Ssowmini 				state.es_extended = B_TRUE;
6729e7801d59Ssowmini 				break;
6730e7801d59Ssowmini 			case 'p':
6731e7801d59Ssowmini 				state.es_parseable = B_TRUE;
6732e7801d59Ssowmini 				break;
6733e7801d59Ssowmini 			case 'o':
67340d365605Sschuster 				o_arg = B_TRUE;
6735e7801d59Ssowmini 				if (strcasecmp(optarg, "all") == 0)
6736e7801d59Ssowmini 					fields_str = all_fields;
6737e7801d59Ssowmini 				else
6738e7801d59Ssowmini 					fields_str = optarg;
6739e7801d59Ssowmini 				break;
6740e7801d59Ssowmini 			default:
67418d5c46e6Sam223141 				die_opterr(optopt, option, use);
6742e7801d59Ssowmini 				break;
6743e7801d59Ssowmini 		}
6744e7801d59Ssowmini 	}
6745e7801d59Ssowmini 
67460d365605Sschuster 	if (state.es_parseable && !o_arg)
67470d365605Sschuster 		die("-p requires -o");
67480d365605Sschuster 
67490d365605Sschuster 	if (state.es_parseable && fields_str == all_fields)
67500d365605Sschuster 		die("\"-o all\" is invalid with -p");
67510d365605Sschuster 
6752e7801d59Ssowmini 	if (optind == (argc - 1))
6753e7801d59Ssowmini 		state.es_link = argv[optind];
6754e7801d59Ssowmini 
6755e7801d59Ssowmini 	fields = parse_output_fields(fields_str, ether_fields,
6756e7801d59Ssowmini 	    ETHER_MAX_FIELDS, CMD_TYPE_ANY, &nfields);
6757e7801d59Ssowmini 
67584ac67f02SAnurag S. Maskey 	if (fields == NULL)
6759e7801d59Ssowmini 		die("invalid field(s) specified");
67604ac67f02SAnurag S. Maskey 
6761e7801d59Ssowmini 	state.es_print.ps_fields = fields;
6762e7801d59Ssowmini 	state.es_print.ps_nfields = nfields;
6763e7801d59Ssowmini 
67644ac67f02SAnurag S. Maskey 
6765e7801d59Ssowmini 	if (state.es_link == NULL) {
67664ac67f02SAnurag S. Maskey 		(void) dladm_walk_datalink_id(show_etherprop, handle, &state,
6767e7801d59Ssowmini 		    DATALINK_CLASS_PHYS, DL_ETHER,
6768e7801d59Ssowmini 		    DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST);
6769e7801d59Ssowmini 	} else {
67704ac67f02SAnurag S. Maskey 		if (!link_is_ether(state.es_link, &linkid))
6771e7801d59Ssowmini 			die("invalid link specified");
67724ac67f02SAnurag S. Maskey 		(void) show_etherprop(handle, linkid, &state);
6773e7801d59Ssowmini 	}
6774e7801d59Ssowmini }
6775e7801d59Ssowmini 
6776e7801d59Ssowmini static char *
6777e7801d59Ssowmini dladm_print_field(print_field_t *pf, void *arg)
6778e7801d59Ssowmini {
6779e7801d59Ssowmini 	char *value;
6780e7801d59Ssowmini 
6781e7801d59Ssowmini 	value = (char *)arg + pf->pf_offset;
6782e7801d59Ssowmini 	return (value);
6783e7801d59Ssowmini }
6784e7801d59Ssowmini 
6785e7801d59Ssowmini static int
67864ac67f02SAnurag S. Maskey show_etherprop(dladm_handle_t dh, datalink_id_t linkid, void *arg)
6787e7801d59Ssowmini {
6788e7801d59Ssowmini 	print_ether_state_t	*statep = arg;
6789e7801d59Ssowmini 	ether_fields_buf_t	ebuf;
67904784fcbdSSowmini Varadhan 	dladm_ether_info_t	eattr;
67914784fcbdSSowmini Varadhan 	dladm_status_t		status;
6792e7801d59Ssowmini 
67935f5c9f54SAnurag S. Maskey 	bzero(&ebuf, sizeof (ether_fields_buf_t));
67944ac67f02SAnurag S. Maskey 	if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL,
6795e7801d59Ssowmini 	    ebuf.eth_link, sizeof (ebuf.eth_link)) != DLADM_STATUS_OK) {
6796e7801d59Ssowmini 		return (DLADM_WALK_CONTINUE);
6797e7801d59Ssowmini 	}
6798e7801d59Ssowmini 
6799e7801d59Ssowmini 	if (!statep->es_header && !statep->es_parseable) {
6800e7801d59Ssowmini 		print_header(&statep->es_print);
6801e7801d59Ssowmini 		statep->es_header = B_TRUE;
6802e7801d59Ssowmini 	}
6803e7801d59Ssowmini 
68044ac67f02SAnurag S. Maskey 	status = dladm_ether_info(dh, linkid, &eattr);
68054784fcbdSSowmini Varadhan 	if (status != DLADM_STATUS_OK)
68064784fcbdSSowmini Varadhan 		goto cleanup;
6807e7801d59Ssowmini 
68084784fcbdSSowmini Varadhan 	(void) strlcpy(ebuf.eth_ptype, "current", sizeof (ebuf.eth_ptype));
6809e7801d59Ssowmini 
68104784fcbdSSowmini Varadhan 	(void) dladm_ether_autoneg2str(ebuf.eth_autoneg,
68114784fcbdSSowmini Varadhan 	    sizeof (ebuf.eth_autoneg), &eattr, CURRENT);
68124784fcbdSSowmini Varadhan 	(void) dladm_ether_pause2str(ebuf.eth_pause,
68134784fcbdSSowmini Varadhan 	    sizeof (ebuf.eth_pause), &eattr, CURRENT);
68144784fcbdSSowmini Varadhan 	(void) dladm_ether_spdx2str(ebuf.eth_spdx,
68154784fcbdSSowmini Varadhan 	    sizeof (ebuf.eth_spdx), &eattr, CURRENT);
68164784fcbdSSowmini Varadhan 	(void) strlcpy(ebuf.eth_state,
68174784fcbdSSowmini Varadhan 	    dladm_linkstate2str(eattr.lei_state, ebuf.eth_state),
68184784fcbdSSowmini Varadhan 	    sizeof (ebuf.eth_state));
68194784fcbdSSowmini Varadhan 	(void) strlcpy(ebuf.eth_rem_fault,
68204784fcbdSSowmini Varadhan 	    (eattr.lei_attr[CURRENT].le_fault ? "fault" : "none"),
68214784fcbdSSowmini Varadhan 	    sizeof (ebuf.eth_rem_fault));
6822e7801d59Ssowmini 
6823e7801d59Ssowmini 	dladm_print_output(&statep->es_print, statep->es_parseable,
6824e7801d59Ssowmini 	    dladm_print_field, &ebuf);
6825e7801d59Ssowmini 
6826e7801d59Ssowmini 	if (statep->es_extended)
68274784fcbdSSowmini Varadhan 		show_ether_xprop(arg, &eattr);
6828e7801d59Ssowmini 
68294784fcbdSSowmini Varadhan cleanup:
68304784fcbdSSowmini Varadhan 	dladm_ether_info_done(&eattr);
6831e7801d59Ssowmini 	return (DLADM_WALK_CONTINUE);
6832e7801d59Ssowmini }
6833e7801d59Ssowmini 
6834e7801d59Ssowmini /* ARGSUSED */
6835e7801d59Ssowmini static void
68368d5c46e6Sam223141 do_init_secobj(int argc, char **argv, const char *use)
68370ba2cbe9Sxc151355 {
68380ba2cbe9Sxc151355 	dladm_status_t	status;
68390ba2cbe9Sxc151355 
68404ac67f02SAnurag S. Maskey 	status = dladm_init_secobj(handle);
684133343a97Smeem 	if (status != DLADM_STATUS_OK)
684233343a97Smeem 		die_dlerr(status, "secure object initialization failed");
684333343a97Smeem }
684433343a97Smeem 
6845d62bc4baSyz147064 /*
6846d62bc4baSyz147064  * "-R" option support. It is used for live upgrading. Append dladm commands
6847d62bc4baSyz147064  * to a upgrade script which will be run when the alternative root boots up:
6848d62bc4baSyz147064  *
6849b9e076dcSyz147064  * - If the /etc/dladm/datalink.conf file exists on the alternative root,
6850b9e076dcSyz147064  * append dladm commands to the <altroot>/var/svc/profile/upgrade_datalink
6851b9e076dcSyz147064  * script. This script will be run as part of the network/physical service.
6852b9e076dcSyz147064  * We cannot defer this to /var/svc/profile/upgrade because then the
6853b9e076dcSyz147064  * configuration will not be able to take effect before network/physical
6854b9e076dcSyz147064  * plumbs various interfaces.
6855d62bc4baSyz147064  *
6856b9e076dcSyz147064  * - If the /etc/dladm/datalink.conf file does not exist on the alternative
6857b9e076dcSyz147064  * root, append dladm commands to the <altroot>/var/svc/profile/upgrade script,
6858b9e076dcSyz147064  * which will be run in the manifest-import service.
6859d62bc4baSyz147064  *
6860d62bc4baSyz147064  * Note that the SMF team is considering to move the manifest-import service
6861d62bc4baSyz147064  * to be run at the very begining of boot. Once that is done, the need for
6862d62bc4baSyz147064  * the /var/svc/profile/upgrade_datalink script will not exist any more.
6863d62bc4baSyz147064  */
6864d62bc4baSyz147064 static void
6865d62bc4baSyz147064 altroot_cmd(char *altroot, int argc, char *argv[])
6866d62bc4baSyz147064 {
6867d62bc4baSyz147064 	char		path[MAXPATHLEN];
6868d62bc4baSyz147064 	struct stat	stbuf;
6869d62bc4baSyz147064 	FILE		*fp;
6870d62bc4baSyz147064 	int		i;
6871d62bc4baSyz147064 
6872d62bc4baSyz147064 	/*
6873b9e076dcSyz147064 	 * Check for the existence of the /etc/dladm/datalink.conf
6874b9e076dcSyz147064 	 * configuration file, and determine the name of script file.
6875d62bc4baSyz147064 	 */
6876b9e076dcSyz147064 	(void) snprintf(path, MAXPATHLEN, "/%s/etc/dladm/datalink.conf",
6877b9e076dcSyz147064 	    altroot);
6878d62bc4baSyz147064 	if (stat(path, &stbuf) < 0) {
6879d62bc4baSyz147064 		(void) snprintf(path, MAXPATHLEN, "/%s/%s", altroot,
6880d62bc4baSyz147064 		    SMF_UPGRADE_FILE);
6881d62bc4baSyz147064 	} else {
6882d62bc4baSyz147064 		(void) snprintf(path, MAXPATHLEN, "/%s/%s", altroot,
6883d62bc4baSyz147064 		    SMF_UPGRADEDATALINK_FILE);
6884d62bc4baSyz147064 	}
6885d62bc4baSyz147064 
6886d62bc4baSyz147064 	if ((fp = fopen(path, "a+")) == NULL)
6887d62bc4baSyz147064 		die("operation not supported on %s", altroot);
6888d62bc4baSyz147064 
6889d62bc4baSyz147064 	(void) fprintf(fp, "/sbin/dladm ");
6890d62bc4baSyz147064 	for (i = 0; i < argc; i++) {
6891d62bc4baSyz147064 		/*
6892d62bc4baSyz147064 		 * Directly write to the file if it is not the "-R <altroot>"
6893d62bc4baSyz147064 		 * option. In which case, skip it.
6894d62bc4baSyz147064 		 */
6895d62bc4baSyz147064 		if (strcmp(argv[i], "-R") != 0)
6896d62bc4baSyz147064 			(void) fprintf(fp, "%s ", argv[i]);
6897d62bc4baSyz147064 		else
6898d62bc4baSyz147064 			i ++;
6899d62bc4baSyz147064 	}
6900d62bc4baSyz147064 	(void) fprintf(fp, "%s\n", SMF_DLADM_UPGRADE_MSG);
6901d62bc4baSyz147064 	(void) fclose(fp);
69024ac67f02SAnurag S. Maskey 	dladm_close(handle);
6903d62bc4baSyz147064 	exit(0);
6904d62bc4baSyz147064 }
6905d62bc4baSyz147064 
6906d62bc4baSyz147064 /*
6907d62bc4baSyz147064  * Convert the string to an integer. Note that the string must not have any
6908d62bc4baSyz147064  * trailing non-integer characters.
6909d62bc4baSyz147064  */
691033343a97Smeem static boolean_t
691133343a97Smeem str2int(const char *str, int *valp)
691233343a97Smeem {
691333343a97Smeem 	int	val;
691433343a97Smeem 	char	*endp = NULL;
691533343a97Smeem 
691633343a97Smeem 	errno = 0;
691733343a97Smeem 	val = strtol(str, &endp, 10);
691833343a97Smeem 	if (errno != 0 || *endp != '\0')
691933343a97Smeem 		return (B_FALSE);
692033343a97Smeem 
692133343a97Smeem 	*valp = val;
692233343a97Smeem 	return (B_TRUE);
692333343a97Smeem }
692433343a97Smeem 
692533343a97Smeem /* PRINTFLIKE1 */
692633343a97Smeem static void
692733343a97Smeem warn(const char *format, ...)
692833343a97Smeem {
692933343a97Smeem 	va_list alist;
693033343a97Smeem 
693133343a97Smeem 	format = gettext(format);
693233343a97Smeem 	(void) fprintf(stderr, "%s: warning: ", progname);
693333343a97Smeem 
693433343a97Smeem 	va_start(alist, format);
693533343a97Smeem 	(void) vfprintf(stderr, format, alist);
693633343a97Smeem 	va_end(alist);
693733343a97Smeem 
693833343a97Smeem 	(void) putchar('\n');
693933343a97Smeem }
694033343a97Smeem 
694133343a97Smeem /* PRINTFLIKE2 */
694233343a97Smeem static void
694333343a97Smeem warn_dlerr(dladm_status_t err, const char *format, ...)
694433343a97Smeem {
694533343a97Smeem 	va_list alist;
694633343a97Smeem 	char	errmsg[DLADM_STRSIZE];
694733343a97Smeem 
694833343a97Smeem 	format = gettext(format);
694933343a97Smeem 	(void) fprintf(stderr, gettext("%s: warning: "), progname);
695033343a97Smeem 
695133343a97Smeem 	va_start(alist, format);
695233343a97Smeem 	(void) vfprintf(stderr, format, alist);
695333343a97Smeem 	va_end(alist);
695433343a97Smeem 	(void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg));
695533343a97Smeem }
695633343a97Smeem 
69574ac67f02SAnurag S. Maskey /*
69584ac67f02SAnurag S. Maskey  * Also closes the dladm handle if it is not NULL.
69594ac67f02SAnurag S. Maskey  */
696033343a97Smeem /* PRINTFLIKE2 */
696133343a97Smeem static void
696233343a97Smeem die_dlerr(dladm_status_t err, const char *format, ...)
696333343a97Smeem {
696433343a97Smeem 	va_list alist;
696533343a97Smeem 	char	errmsg[DLADM_STRSIZE];
696633343a97Smeem 
696733343a97Smeem 	format = gettext(format);
696833343a97Smeem 	(void) fprintf(stderr, "%s: ", progname);
696933343a97Smeem 
697033343a97Smeem 	va_start(alist, format);
697133343a97Smeem 	(void) vfprintf(stderr, format, alist);
697233343a97Smeem 	va_end(alist);
697333343a97Smeem 	(void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg));
697433343a97Smeem 
69754ac67f02SAnurag S. Maskey 	/* close dladm handle if it was opened */
69764ac67f02SAnurag S. Maskey 	if (handle != NULL)
69774ac67f02SAnurag S. Maskey 		dladm_close(handle);
69784ac67f02SAnurag S. Maskey 
697933343a97Smeem 	exit(EXIT_FAILURE);
698033343a97Smeem }
698133343a97Smeem 
698233343a97Smeem /* PRINTFLIKE1 */
698333343a97Smeem static void
698433343a97Smeem die(const char *format, ...)
698533343a97Smeem {
698633343a97Smeem 	va_list alist;
698733343a97Smeem 
698833343a97Smeem 	format = gettext(format);
698933343a97Smeem 	(void) fprintf(stderr, "%s: ", progname);
699033343a97Smeem 
699133343a97Smeem 	va_start(alist, format);
699233343a97Smeem 	(void) vfprintf(stderr, format, alist);
699333343a97Smeem 	va_end(alist);
699433343a97Smeem 
699533343a97Smeem 	(void) putchar('\n');
69964ac67f02SAnurag S. Maskey 
69974ac67f02SAnurag S. Maskey 	/* close dladm handle if it was opened */
69984ac67f02SAnurag S. Maskey 	if (handle != NULL)
69994ac67f02SAnurag S. Maskey 		dladm_close(handle);
70004ac67f02SAnurag S. Maskey 
700133343a97Smeem 	exit(EXIT_FAILURE);
700233343a97Smeem }
700333343a97Smeem 
700433343a97Smeem static void
700533343a97Smeem die_optdup(int opt)
700633343a97Smeem {
700733343a97Smeem 	die("the option -%c cannot be specified more than once", opt);
700833343a97Smeem }
700933343a97Smeem 
701033343a97Smeem static void
70118d5c46e6Sam223141 die_opterr(int opt, int opterr, const char *usage)
701233343a97Smeem {
701333343a97Smeem 	switch (opterr) {
701433343a97Smeem 	case ':':
70158d5c46e6Sam223141 		die("option '-%c' requires a value\nusage: %s", opt,
70168d5c46e6Sam223141 		    gettext(usage));
701733343a97Smeem 		break;
701833343a97Smeem 	case '?':
701933343a97Smeem 	default:
70208d5c46e6Sam223141 		die("unrecognized option '-%c'\nusage: %s", opt,
70218d5c46e6Sam223141 		    gettext(usage));
702233343a97Smeem 		break;
70230ba2cbe9Sxc151355 	}
70240ba2cbe9Sxc151355 }
7025e7801d59Ssowmini 
7026e7801d59Ssowmini static void
70274784fcbdSSowmini Varadhan show_ether_xprop(void *arg, dladm_ether_info_t *eattr)
7028e7801d59Ssowmini {
7029e7801d59Ssowmini 	print_ether_state_t	*statep = arg;
7030e7801d59Ssowmini 	ether_fields_buf_t	ebuf;
70314784fcbdSSowmini Varadhan 	int			i;
7032e7801d59Ssowmini 
70334784fcbdSSowmini Varadhan 	for (i = CAPABLE; i <= PEERADV; i++)  {
7034e7801d59Ssowmini 		bzero(&ebuf, sizeof (ebuf));
70354784fcbdSSowmini Varadhan 		(void) strlcpy(ebuf.eth_ptype, ptype[i],
70364784fcbdSSowmini Varadhan 		    sizeof (ebuf.eth_ptype));
70374784fcbdSSowmini Varadhan 		(void) dladm_ether_autoneg2str(ebuf.eth_autoneg,
70384784fcbdSSowmini Varadhan 		    sizeof (ebuf.eth_autoneg), eattr, i);
70394784fcbdSSowmini Varadhan 		(void) dladm_ether_spdx2str(ebuf.eth_spdx,
70404784fcbdSSowmini Varadhan 		    sizeof (ebuf.eth_spdx), eattr, i);
70414784fcbdSSowmini Varadhan 		(void) dladm_ether_pause2str(ebuf.eth_pause,
70424784fcbdSSowmini Varadhan 		    sizeof (ebuf.eth_pause), eattr, i);
70434784fcbdSSowmini Varadhan 		(void) strlcpy(ebuf.eth_rem_fault,
70444784fcbdSSowmini Varadhan 		    (eattr->lei_attr[i].le_fault ? "fault" : "none"),
70454784fcbdSSowmini Varadhan 		    sizeof (ebuf.eth_rem_fault));
7046e7801d59Ssowmini 		dladm_print_output(&statep->es_print, statep->es_parseable,
7047e7801d59Ssowmini 		    dladm_print_field, &ebuf);
7048e7801d59Ssowmini 	}
7049e7801d59Ssowmini 
7050e7801d59Ssowmini }
7051e7801d59Ssowmini 
7052e7801d59Ssowmini static void
7053e7801d59Ssowmini dladm_print_output(print_state_t *statep, boolean_t parseable,
7054e7801d59Ssowmini     print_callback_t fn, void *arg)
7055e7801d59Ssowmini {
7056e7801d59Ssowmini 	int i;
7057e7801d59Ssowmini 	char *value;
7058e7801d59Ssowmini 	print_field_t **pf;
7059e7801d59Ssowmini 
7060e7801d59Ssowmini 	pf = statep->ps_fields;
7061e7801d59Ssowmini 	for (i = 0; i < statep->ps_nfields; i++) {
7062e7801d59Ssowmini 		statep->ps_lastfield = (i + 1 == statep->ps_nfields);
7063e7801d59Ssowmini 		value = (*fn)(pf[i], arg);
7064e7801d59Ssowmini 		if (value != NULL)
7065e7801d59Ssowmini 			print_field(statep, pf[i], value, parseable);
7066e7801d59Ssowmini 	}
7067e7801d59Ssowmini 	(void) putchar('\n');
7068e7801d59Ssowmini }
7069e7801d59Ssowmini 
7070e7801d59Ssowmini static void
7071e7801d59Ssowmini print_header(print_state_t *ps)
7072e7801d59Ssowmini {
7073e7801d59Ssowmini 	int i;
7074e7801d59Ssowmini 	print_field_t **pf;
7075e7801d59Ssowmini 
7076e7801d59Ssowmini 	pf = ps->ps_fields;
7077e7801d59Ssowmini 	for (i = 0; i < ps->ps_nfields; i++) {
7078e7801d59Ssowmini 		ps->ps_lastfield = (i + 1 == ps->ps_nfields);
7079e7801d59Ssowmini 		print_field(ps, pf[i], pf[i]->pf_header, B_FALSE);
7080e7801d59Ssowmini 	}
7081e7801d59Ssowmini 	(void) putchar('\n');
7082e7801d59Ssowmini }
7083e7801d59Ssowmini 
7084e7801d59Ssowmini static boolean_t
7085e7801d59Ssowmini link_is_ether(const char *link, datalink_id_t *linkid)
7086e7801d59Ssowmini {
7087e7801d59Ssowmini 	uint32_t media;
7088e7801d59Ssowmini 	datalink_class_t class;
7089e7801d59Ssowmini 
70904ac67f02SAnurag S. Maskey 	if (dladm_name2info(handle, link, linkid, NULL, &class, &media) ==
7091e7801d59Ssowmini 	    DLADM_STATUS_OK) {
7092e7801d59Ssowmini 		if (class == DATALINK_CLASS_PHYS && media == DL_ETHER)
7093e7801d59Ssowmini 			return (B_TRUE);
7094e7801d59Ssowmini 	}
7095e7801d59Ssowmini 	return (B_FALSE);
7096e7801d59Ssowmini }
7097