xref: /titanic_53/usr/src/cmd/dladm/dladm.c (revision 8002d4117c1ea26aff1f16f584ae97bdbd5b21d5)
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>
68*8002d411SSowmini Varadhan #include <ofmt.h>
697c478bd9Sstevel@tonic-gate 
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)"
77*8002d411SSowmini Varadhan #define	DLADM_DEFAULT_COL	80
787c478bd9Sstevel@tonic-gate 
79*8002d411SSowmini Varadhan /*
80*8002d411SSowmini Varadhan  * used by the wifi show-* commands to set up ofmt_field_t structures.
81*8002d411SSowmini Varadhan  */
82e7801d59Ssowmini #define	WIFI_CMD_SCAN		0x00000001
83e7801d59Ssowmini #define	WIFI_CMD_SHOW		0x00000002
84e7801d59Ssowmini #define	WIFI_CMD_ALL		(WIFI_CMD_SCAN | WIFI_CMD_SHOW)
85e7801d59Ssowmini 
86d62bc4baSyz147064 typedef struct show_state {
877c478bd9Sstevel@tonic-gate 	boolean_t	ls_firstonly;
887c478bd9Sstevel@tonic-gate 	boolean_t	ls_donefirst;
897c478bd9Sstevel@tonic-gate 	pktsum_t	ls_prevstats;
90d62bc4baSyz147064 	uint32_t	ls_flags;
91d62bc4baSyz147064 	dladm_status_t	ls_status;
92*8002d411SSowmini Varadhan 	ofmt_handle_t	ls_ofmt;
93*8002d411SSowmini Varadhan 	boolean_t	ls_parsable;
94da14cebeSEric Cheng 	boolean_t	ls_mac;
95da14cebeSEric Cheng 	boolean_t	ls_hwgrp;
96d62bc4baSyz147064 } show_state_t;
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate typedef struct show_grp_state {
99e7801d59Ssowmini 	pktsum_t	gs_prevstats[MAXPORT];
100e7801d59Ssowmini 	uint32_t	gs_flags;
101e7801d59Ssowmini 	dladm_status_t	gs_status;
102*8002d411SSowmini Varadhan 	boolean_t	gs_parsable;
1037c478bd9Sstevel@tonic-gate 	boolean_t	gs_lacp;
104d62bc4baSyz147064 	boolean_t	gs_extended;
1057c478bd9Sstevel@tonic-gate 	boolean_t	gs_stats;
1067c478bd9Sstevel@tonic-gate 	boolean_t	gs_firstonly;
107d62bc4baSyz147064 	boolean_t	gs_donefirst;
108*8002d411SSowmini Varadhan 	ofmt_handle_t	gs_ofmt;
1097c478bd9Sstevel@tonic-gate } show_grp_state_t;
1107c478bd9Sstevel@tonic-gate 
111da14cebeSEric Cheng typedef struct show_vnic_state {
112da14cebeSEric Cheng 	datalink_id_t	vs_vnic_id;
113da14cebeSEric Cheng 	datalink_id_t	vs_link_id;
114da14cebeSEric Cheng 	char		vs_vnic[MAXLINKNAMELEN];
115da14cebeSEric Cheng 	char		vs_link[MAXLINKNAMELEN];
116*8002d411SSowmini Varadhan 	boolean_t	vs_parsable;
117da14cebeSEric Cheng 	boolean_t	vs_found;
118da14cebeSEric Cheng 	boolean_t	vs_firstonly;
119da14cebeSEric Cheng 	boolean_t	vs_donefirst;
120da14cebeSEric Cheng 	boolean_t	vs_stats;
121da14cebeSEric Cheng 	boolean_t	vs_printstats;
122da14cebeSEric Cheng 	pktsum_t	vs_totalstats;
123da14cebeSEric Cheng 	pktsum_t	vs_prevstats[MAXVNIC];
124da14cebeSEric Cheng 	boolean_t	vs_etherstub;
125da14cebeSEric Cheng 	dladm_status_t	vs_status;
126da14cebeSEric Cheng 	uint32_t	vs_flags;
127*8002d411SSowmini Varadhan 	ofmt_handle_t	vs_ofmt;
128da14cebeSEric Cheng } show_vnic_state_t;
129da14cebeSEric Cheng 
130da14cebeSEric Cheng typedef struct show_usage_state_s {
131da14cebeSEric Cheng 	boolean_t	us_plot;
132*8002d411SSowmini Varadhan 	boolean_t	us_parsable;
133da14cebeSEric Cheng 	boolean_t	us_printheader;
134da14cebeSEric Cheng 	boolean_t	us_first;
135ae6aa22aSVenugopal Iyer 	boolean_t	us_showall;
136*8002d411SSowmini Varadhan 	ofmt_handle_t	us_ofmt;
137da14cebeSEric Cheng } show_usage_state_t;
138da14cebeSEric Cheng 
139*8002d411SSowmini Varadhan /*
140*8002d411SSowmini Varadhan  * callback functions for printing output and error diagnostics.
141*8002d411SSowmini Varadhan  */
142*8002d411SSowmini Varadhan static ofmt_cb_t print_default_cb, print_link_stats_cb, print_linkprop_cb;
143*8002d411SSowmini Varadhan static ofmt_cb_t print_lacp_cb, print_phys_one_mac_cb;
144*8002d411SSowmini Varadhan static ofmt_cb_t print_xaggr_cb, print_aggr_stats_cb;
145*8002d411SSowmini Varadhan static ofmt_cb_t print_phys_one_hwgrp_cb, print_wlan_attr_cb;
146*8002d411SSowmini Varadhan static ofmt_cb_t print_wifi_status_cb, print_link_attr_cb;
147*8002d411SSowmini Varadhan static void dladm_ofmt_check(ofmt_status_t, boolean_t, ofmt_handle_t);
148*8002d411SSowmini Varadhan 
1498d5c46e6Sam223141 typedef void cmdfunc_t(int, char **, const char *);
1500ba2cbe9Sxc151355 
151da14cebeSEric Cheng static cmdfunc_t do_show_link, do_show_wifi, do_show_phys;
1520ba2cbe9Sxc151355 static cmdfunc_t do_create_aggr, do_delete_aggr, do_add_aggr, do_remove_aggr;
153d62bc4baSyz147064 static cmdfunc_t do_modify_aggr, do_show_aggr, do_up_aggr;
1540ba2cbe9Sxc151355 static cmdfunc_t do_scan_wifi, do_connect_wifi, do_disconnect_wifi;
1550ba2cbe9Sxc151355 static cmdfunc_t do_show_linkprop, do_set_linkprop, do_reset_linkprop;
1560ba2cbe9Sxc151355 static cmdfunc_t do_create_secobj, do_delete_secobj, do_show_secobj;
1570ba2cbe9Sxc151355 static cmdfunc_t do_init_linkprop, do_init_secobj;
158d62bc4baSyz147064 static cmdfunc_t do_create_vlan, do_delete_vlan, do_up_vlan, do_show_vlan;
159d62bc4baSyz147064 static cmdfunc_t do_rename_link, do_delete_phys, do_init_phys;
160d62bc4baSyz147064 static cmdfunc_t do_show_linkmap;
161e7801d59Ssowmini static cmdfunc_t do_show_ether;
162da14cebeSEric Cheng static cmdfunc_t do_create_vnic, do_delete_vnic, do_show_vnic;
163da14cebeSEric Cheng static cmdfunc_t do_up_vnic;
164da14cebeSEric Cheng static cmdfunc_t do_create_etherstub, do_delete_etherstub, do_show_etherstub;
165da14cebeSEric Cheng static cmdfunc_t do_show_usage;
166da14cebeSEric Cheng 
167da14cebeSEric Cheng static void 	do_up_vnic_common(int, char **, const char *, boolean_t);
1687c478bd9Sstevel@tonic-gate 
169d62bc4baSyz147064 static void	altroot_cmd(char *, int, char **);
1704ac67f02SAnurag S. Maskey static int	show_linkprop_onelink(dladm_handle_t, datalink_id_t, void *);
171f4b3ec61Sdh155122 
1726be03d0bSVasumathi Sundaram - Sun Microsystems static void	link_stats(datalink_id_t, uint_t, char *, show_state_t *);
173d62bc4baSyz147064 static void	aggr_stats(datalink_id_t, show_grp_state_t *, uint_t);
174da14cebeSEric Cheng static void	vnic_stats(show_vnic_state_t *, uint32_t);
1757c478bd9Sstevel@tonic-gate 
176d62bc4baSyz147064 static int	get_one_kstat(const char *, const char *, uint8_t,
177d62bc4baSyz147064 		    void *, boolean_t);
178ba2e4443Sseb static void	get_mac_stats(const char *, pktsum_t *);
1797c478bd9Sstevel@tonic-gate static void	get_link_stats(const char *, pktsum_t *);
180d62bc4baSyz147064 static uint64_t	get_ifspeed(const char *, boolean_t);
181d62bc4baSyz147064 static const char	*get_linkstate(const char *, boolean_t, char *);
182d62bc4baSyz147064 static const char	*get_linkduplex(const char *, boolean_t, char *);
1837c478bd9Sstevel@tonic-gate 
1844ac67f02SAnurag S. Maskey static int	show_etherprop(dladm_handle_t, datalink_id_t, void *);
1854784fcbdSSowmini Varadhan static void	show_ether_xprop(void *, dladm_ether_info_t *);
186e7801d59Ssowmini static boolean_t	link_is_ether(const char *, datalink_id_t *);
187e7801d59Ssowmini 
18833343a97Smeem static boolean_t str2int(const char *, int *);
18933343a97Smeem static void	die(const char *, ...);
19033343a97Smeem static void	die_optdup(int);
1918d5c46e6Sam223141 static void	die_opterr(int, int, const char *);
19233343a97Smeem static void	die_dlerr(dladm_status_t, const char *, ...);
19333343a97Smeem static void	warn(const char *, ...);
19433343a97Smeem static void	warn_dlerr(dladm_status_t, const char *, ...);
19533343a97Smeem 
1967c478bd9Sstevel@tonic-gate typedef struct	cmd {
1977c478bd9Sstevel@tonic-gate 	char		*c_name;
1980ba2cbe9Sxc151355 	cmdfunc_t	*c_fn;
1998d5c46e6Sam223141 	const char	*c_usage;
2007c478bd9Sstevel@tonic-gate } cmd_t;
2017c478bd9Sstevel@tonic-gate 
2027c478bd9Sstevel@tonic-gate static cmd_t	cmds[] = {
2038d5c46e6Sam223141 	{ "rename-link",	do_rename_link,
2040790b6dcSAnurag S. Maskey 	    "    rename-link      <oldlink> <newlink>"			},
2050790b6dcSAnurag S. Maskey 	{ "show-link",		do_show_link,
2060790b6dcSAnurag S. Maskey 	    "    show-link        [-pP] [-o <field>,..] [-s [-i <interval>]] "
2070790b6dcSAnurag S. Maskey 	    "[<link>]\n"						},
2088d5c46e6Sam223141 	{ "create-aggr",	do_create_aggr,
2090790b6dcSAnurag S. Maskey 	    "    create-aggr      [-t] [-P <policy>] [-L <mode>] [-T <time>] "
2100790b6dcSAnurag S. Maskey 	    "[-u <address>]\n"
2110790b6dcSAnurag S. Maskey 	    "\t\t     -l <link> [-l <link>...] <link>"			},
2128d5c46e6Sam223141 	{ "delete-aggr",	do_delete_aggr,
2130790b6dcSAnurag S. Maskey 	    "    delete-aggr      [-t] <link>"				},
2148d5c46e6Sam223141 	{ "add-aggr",		do_add_aggr,
2150790b6dcSAnurag S. Maskey 	    "    add-aggr         [-t] -l <link> [-l <link>...] <link>" },
2168d5c46e6Sam223141 	{ "remove-aggr",	do_remove_aggr,
2170790b6dcSAnurag S. Maskey 	    "    remove-aggr      [-t] -l <link> [-l <link>...] <link>" },
2188d5c46e6Sam223141 	{ "modify-aggr",	do_modify_aggr,
2190790b6dcSAnurag S. Maskey 	    "    modify-aggr      [-t] [-P <policy>] [-L <mode>] [-T <time>] "
2200790b6dcSAnurag S. Maskey 	    "[-u <address>]\n"
2210790b6dcSAnurag S. Maskey 	    "\t\t     <link>"						},
2228d5c46e6Sam223141 	{ "show-aggr",		do_show_aggr,
2230790b6dcSAnurag S. Maskey 	    "    show-aggr        [-pPLx] [-o <field>,..] [-s [-i <interval>]] "
2248d5c46e6Sam223141 	    "[<link>]\n"						},
2258d5c46e6Sam223141 	{ "up-aggr",		do_up_aggr,	NULL			},
2268d5c46e6Sam223141 	{ "scan-wifi",		do_scan_wifi,
2270790b6dcSAnurag S. Maskey 	    "    scan-wifi        [-p] [-o <field>,...] [<link>]"	},
2288d5c46e6Sam223141 	{ "connect-wifi",	do_connect_wifi,
2290790b6dcSAnurag S. Maskey 	    "    connect-wifi     [-e <essid>] [-i <bssid>] [-k <key>,...] "
2308d5c46e6Sam223141 	    "[-s wep|wpa]\n"
2310790b6dcSAnurag S. Maskey 	    "\t\t     [-a open|shared] [-b bss|ibss] [-c] [-m a|b|g] "
2320790b6dcSAnurag S. Maskey 	    "[-T <time>]\n"
2330790b6dcSAnurag S. Maskey 	    "\t\t     [<link>]"						},
2348d5c46e6Sam223141 	{ "disconnect-wifi",	do_disconnect_wifi,
2350790b6dcSAnurag S. Maskey 	    "    disconnect-wifi  [-a] [<link>]"			},
2368d5c46e6Sam223141 	{ "show-wifi",		do_show_wifi,
2370790b6dcSAnurag S. Maskey 	    "    show-wifi        [-p] [-o <field>,...] [<link>]\n"	},
2388d5c46e6Sam223141 	{ "set-linkprop",	do_set_linkprop,
2390790b6dcSAnurag S. Maskey 	    "    set-linkprop     [-t] -p <prop>=<value>[,...] <name>"	},
2408d5c46e6Sam223141 	{ "reset-linkprop",	do_reset_linkprop,
2410790b6dcSAnurag S. Maskey 	    "    reset-linkprop   [-t] [-p <prop>,...] <name>"		},
2420790b6dcSAnurag S. Maskey 	{ "show-linkprop",	do_show_linkprop,
2430790b6dcSAnurag S. Maskey 	    "    show-linkprop    [-cP] [-o <field>,...] [-p <prop>,...] "
2440790b6dcSAnurag S. Maskey 	    "<name>\n"							},
2458d5c46e6Sam223141 	{ "show-ether",		do_show_ether,
2460790b6dcSAnurag S. Maskey 	    "    show-ether       [-px][-o <field>,...] <link>\n"	},
2478d5c46e6Sam223141 	{ "create-secobj",	do_create_secobj,
2480790b6dcSAnurag S. Maskey 	    "    create-secobj    [-t] [-f <file>] -c <class> <secobj>"	},
2498d5c46e6Sam223141 	{ "delete-secobj",	do_delete_secobj,
2500790b6dcSAnurag S. Maskey 	    "    delete-secobj    [-t] <secobj>[,...]"			},
2518d5c46e6Sam223141 	{ "show-secobj",	do_show_secobj,
2520790b6dcSAnurag S. Maskey 	    "    show-secobj      [-pP] [-o <field>,...] [<secobj>,...]\n" },
2538d5c46e6Sam223141 	{ "init-linkprop",	do_init_linkprop,	NULL		},
2548d5c46e6Sam223141 	{ "init-secobj",	do_init_secobj,		NULL		},
2558d5c46e6Sam223141 	{ "create-vlan", 	do_create_vlan,
2560790b6dcSAnurag S. Maskey 	    "    create-vlan      [-ft] -l <link> -v <vid> [link]"	},
2578d5c46e6Sam223141 	{ "delete-vlan", 	do_delete_vlan,
2580790b6dcSAnurag S. Maskey 	    "    delete-vlan      [-t] <link>"				},
2598d5c46e6Sam223141 	{ "show-vlan",		do_show_vlan,
2600790b6dcSAnurag S. Maskey 	    "    show-vlan        [-pP] [-o <field>,..] [<link>]\n"	},
2618d5c46e6Sam223141 	{ "up-vlan",		do_up_vlan,		NULL		},
2628d5c46e6Sam223141 	{ "delete-phys",	do_delete_phys,
2630790b6dcSAnurag S. Maskey 	    "    delete-phys      <link>"				},
2648d5c46e6Sam223141 	{ "show-phys",		do_show_phys,
2650790b6dcSAnurag S. Maskey 	    "    show-phys        [-pP] [-o <field>,..] [-H] [<link>]\n"},
2668d5c46e6Sam223141 	{ "init-phys",		do_init_phys,		NULL		},
267da14cebeSEric Cheng 	{ "show-linkmap",	do_show_linkmap,	NULL		},
268da14cebeSEric Cheng 	{ "create-vnic",	do_create_vnic,
2690790b6dcSAnurag S. Maskey 	    "    create-vnic      [-t] -l <link> [-m <value> | auto |\n"
2700790b6dcSAnurag S. Maskey 	    "\t\t     {factory [-n <slot-id>]} | {random [-r <prefix>]}]\n"
2710790b6dcSAnurag S. Maskey 	    "\t\t     [-v <vid> [-f]] [-p <prop>=<value>[,...]] [-H] "
2720790b6dcSAnurag S. Maskey 	    "<vnic-link>"						},
273da14cebeSEric Cheng 	{ "delete-vnic",	do_delete_vnic,
2740790b6dcSAnurag S. Maskey 	    "    delete-vnic      [-t] <vnic-link>"			},
275da14cebeSEric Cheng 	{ "show-vnic",		do_show_vnic,
2760790b6dcSAnurag S. Maskey 	    "    show-vnic        [-pP] [-l <link>] [-s [-i <interval>]] "
2770790b6dcSAnurag S. Maskey 	    "[<link>]\n"						},
278da14cebeSEric Cheng 	{ "up-vnic",		do_up_vnic,		NULL		},
279da14cebeSEric Cheng 	{ "create-etherstub",	do_create_etherstub,
2800790b6dcSAnurag S. Maskey 	    "    create-etherstub [-t] <link>"				},
281da14cebeSEric Cheng 	{ "delete-etherstub",	do_delete_etherstub,
2820790b6dcSAnurag S. Maskey 	    "    delete-etherstub [-t] <link>"				},
283da14cebeSEric Cheng 	{ "show-etherstub",	do_show_etherstub,
2840790b6dcSAnurag S. Maskey 	    "    show-etherstub   [-t] [<link>]\n"			},
285da14cebeSEric Cheng 	{ "show-usage",		do_show_usage,
286ae6aa22aSVenugopal Iyer 	    "    show-usage       [-a] [-d | -F <format>] "
2870790b6dcSAnurag S. Maskey 	    "[-s <DD/MM/YYYY,HH:MM:SS>]\n"
2880790b6dcSAnurag S. Maskey 	    "\t\t     [-e <DD/MM/YYYY,HH:MM:SS>] -f <logfile> [<link>]"	}
2897c478bd9Sstevel@tonic-gate };
2907c478bd9Sstevel@tonic-gate 
291d62bc4baSyz147064 static const struct option lopts[] = {
2927c478bd9Sstevel@tonic-gate 	{"vlan-id",	required_argument,	0, 'v'},
293e7801d59Ssowmini 	{"output",	required_argument,	0, 'o'},
2947c478bd9Sstevel@tonic-gate 	{"dev",		required_argument,	0, 'd'},
2957c478bd9Sstevel@tonic-gate 	{"policy",	required_argument,	0, 'P'},
296d62bc4baSyz147064 	{"lacp-mode",	required_argument,	0, 'L'},
2977c478bd9Sstevel@tonic-gate 	{"lacp-timer",	required_argument,	0, 'T'},
2987c478bd9Sstevel@tonic-gate 	{"unicast",	required_argument,	0, 'u'},
299d62bc4baSyz147064 	{"temporary",	no_argument,		0, 't'},
300d62bc4baSyz147064 	{"root-dir",	required_argument,	0, 'R'},
301d62bc4baSyz147064 	{"link",	required_argument,	0, 'l'},
302d62bc4baSyz147064 	{"forcible",	no_argument,		0, 'f'},
303da14cebeSEric Cheng 	{"bw-limit",	required_argument,	0, 'b'},
304da14cebeSEric Cheng 	{"mac-address",	required_argument,	0, 'm'},
305da14cebeSEric Cheng 	{"slot",	required_argument,	0, 'n'},
306d62bc4baSyz147064 	{ 0, 0, 0, 0 }
307d62bc4baSyz147064 };
308d62bc4baSyz147064 
309d62bc4baSyz147064 static const struct option show_lopts[] = {
3107c478bd9Sstevel@tonic-gate 	{"statistics",	no_argument,		0, 's'},
311da14cebeSEric Cheng 	{"continuous",	no_argument,		0, 'S'},
3127c478bd9Sstevel@tonic-gate 	{"interval",	required_argument,	0, 'i'},
313*8002d411SSowmini Varadhan 	{"parsable",	no_argument,		0, 'p'},
3147c478bd9Sstevel@tonic-gate 	{"parseable",	no_argument,		0, 'p'},
315d62bc4baSyz147064 	{"extended",	no_argument,		0, 'x'},
316e7801d59Ssowmini 	{"output",	required_argument,	0, 'o'},
317d62bc4baSyz147064 	{"persistent",	no_argument,		0, 'P'},
318d62bc4baSyz147064 	{"lacp",	no_argument,		0, 'L'},
3197c478bd9Sstevel@tonic-gate 	{ 0, 0, 0, 0 }
3207c478bd9Sstevel@tonic-gate };
3217c478bd9Sstevel@tonic-gate 
3220ba2cbe9Sxc151355 static const struct option prop_longopts[] = {
3230ba2cbe9Sxc151355 	{"temporary",	no_argument,		0, 't'  },
324e7801d59Ssowmini 	{"output",	required_argument,	0, 'o'  },
3250ba2cbe9Sxc151355 	{"root-dir",	required_argument,	0, 'R'  },
3260ba2cbe9Sxc151355 	{"prop",	required_argument,	0, 'p'  },
327*8002d411SSowmini Varadhan 	{"parsable",	no_argument,		0, 'c'  },
3280ba2cbe9Sxc151355 	{"parseable",	no_argument,		0, 'c'  },
3290ba2cbe9Sxc151355 	{"persistent",	no_argument,		0, 'P'  },
3300ba2cbe9Sxc151355 	{ 0, 0, 0, 0 }
3310ba2cbe9Sxc151355 };
3320ba2cbe9Sxc151355 
3330ba2cbe9Sxc151355 static const struct option wifi_longopts[] = {
334*8002d411SSowmini Varadhan 	{"parsable",	no_argument,		0, 'p'  },
3350ba2cbe9Sxc151355 	{"parseable",	no_argument,		0, 'p'  },
3360ba2cbe9Sxc151355 	{"output",	required_argument,	0, 'o'  },
3370ba2cbe9Sxc151355 	{"essid",	required_argument,	0, 'e'  },
3380ba2cbe9Sxc151355 	{"bsstype",	required_argument,	0, 'b'  },
3390ba2cbe9Sxc151355 	{"mode",	required_argument,	0, 'm'  },
3400ba2cbe9Sxc151355 	{"key",		required_argument,	0, 'k'  },
3410ba2cbe9Sxc151355 	{"sec",		required_argument,	0, 's'  },
3420ba2cbe9Sxc151355 	{"auth",	required_argument,	0, 'a'  },
3430ba2cbe9Sxc151355 	{"create-ibss",	required_argument,	0, 'c'  },
3440ba2cbe9Sxc151355 	{"timeout",	required_argument,	0, 'T'  },
3450ba2cbe9Sxc151355 	{"all-links",	no_argument,		0, 'a'  },
3460ba2cbe9Sxc151355 	{"temporary",	no_argument,		0, 't'  },
3470ba2cbe9Sxc151355 	{"root-dir",	required_argument,	0, 'R'  },
3480ba2cbe9Sxc151355 	{"persistent",	no_argument,		0, 'P'  },
3490ba2cbe9Sxc151355 	{"file",	required_argument,	0, 'f'  },
3500ba2cbe9Sxc151355 	{ 0, 0, 0, 0 }
3510ba2cbe9Sxc151355 };
352e7801d59Ssowmini static const struct option showeth_lopts[] = {
353*8002d411SSowmini Varadhan 	{"parsable",	no_argument,		0, 'p'	},
354e7801d59Ssowmini 	{"parseable",	no_argument,		0, 'p'	},
355e7801d59Ssowmini 	{"extended",	no_argument,		0, 'x'	},
356e7801d59Ssowmini 	{"output",	required_argument,	0, 'o'	},
357e7801d59Ssowmini 	{ 0, 0, 0, 0 }
358e7801d59Ssowmini };
359e7801d59Ssowmini 
360da14cebeSEric Cheng static const struct option vnic_lopts[] = {
361da14cebeSEric Cheng 	{"temporary",	no_argument,		0, 't'	},
362da14cebeSEric Cheng 	{"root-dir",	required_argument,	0, 'R'	},
363da14cebeSEric Cheng 	{"dev",		required_argument,	0, 'd'	},
364da14cebeSEric Cheng 	{"mac-address",	required_argument,	0, 'm'	},
365da14cebeSEric Cheng 	{"cpus",	required_argument,	0, 'c'	},
366da14cebeSEric Cheng 	{"bw-limit",	required_argument,	0, 'b'	},
367da14cebeSEric Cheng 	{"slot",	required_argument,	0, 'n'	},
368da14cebeSEric Cheng 	{"mac-prefix",	required_argument,	0, 'r'	},
369da14cebeSEric Cheng 	{ 0, 0, 0, 0 }
370da14cebeSEric Cheng };
371da14cebeSEric Cheng 
372da14cebeSEric Cheng static const struct option etherstub_lopts[] = {
373da14cebeSEric Cheng 	{"temporary",	no_argument,		0, 't'	},
374da14cebeSEric Cheng 	{"root-dir",	required_argument,	0, 'R'	},
375da14cebeSEric Cheng 	{ 0, 0, 0, 0 }
376da14cebeSEric Cheng };
377da14cebeSEric Cheng 
378ae6aa22aSVenugopal Iyer static const struct option usage_opts[] = {
379ae6aa22aSVenugopal Iyer 	{"file",	required_argument,	0, 'f'	},
380ae6aa22aSVenugopal Iyer 	{"format",	required_argument,	0, 'F'	},
381ae6aa22aSVenugopal Iyer 	{"start",	required_argument,	0, 's'	},
382ae6aa22aSVenugopal Iyer 	{"stop",	required_argument,	0, 'e'	},
383ae6aa22aSVenugopal Iyer 	{ 0, 0, 0, 0 }
384ae6aa22aSVenugopal Iyer };
385ae6aa22aSVenugopal Iyer 
386e7801d59Ssowmini /*
387e7801d59Ssowmini  * structures for 'dladm show-ether'
388e7801d59Ssowmini  */
3894784fcbdSSowmini Varadhan static const char *ptype[] = {LEI_ATTR_NAMES};
3904784fcbdSSowmini Varadhan 
391e7801d59Ssowmini typedef struct ether_fields_buf_s
392e7801d59Ssowmini {
393e7801d59Ssowmini 	char	eth_link[15];
394e7801d59Ssowmini 	char	eth_ptype[8];
395e7801d59Ssowmini 	char	eth_state[8];
396e7801d59Ssowmini 	char	eth_autoneg[5];
397e7801d59Ssowmini 	char	eth_spdx[31];
398e7801d59Ssowmini 	char	eth_pause[6];
399e7801d59Ssowmini 	char	eth_rem_fault[16];
400e7801d59Ssowmini } ether_fields_buf_t;
401e7801d59Ssowmini 
402*8002d411SSowmini Varadhan static ofmt_field_t ether_fields[] = {
403*8002d411SSowmini Varadhan /* name,	field width,	offset	    callback */
404*8002d411SSowmini Varadhan { "LINK",	16,
405*8002d411SSowmini Varadhan 	offsetof(ether_fields_buf_t, eth_link), print_default_cb},
406*8002d411SSowmini Varadhan { "PTYPE",	9,
407*8002d411SSowmini Varadhan 	offsetof(ether_fields_buf_t, eth_ptype), print_default_cb},
408*8002d411SSowmini Varadhan { "STATE",	9,
409*8002d411SSowmini Varadhan 	offsetof(ether_fields_buf_t, eth_state),
410*8002d411SSowmini Varadhan 	print_default_cb},
411*8002d411SSowmini Varadhan { "AUTO",	6,
412*8002d411SSowmini Varadhan 	offsetof(ether_fields_buf_t, eth_autoneg), print_default_cb},
413*8002d411SSowmini Varadhan { "SPEED-DUPLEX", 32,
414*8002d411SSowmini Varadhan 	offsetof(ether_fields_buf_t, eth_spdx), print_default_cb},
415*8002d411SSowmini Varadhan { "PAUSE",	7,
416*8002d411SSowmini Varadhan 	offsetof(ether_fields_buf_t, eth_pause), print_default_cb},
417*8002d411SSowmini Varadhan { "REM_FAULT",	17,
418*8002d411SSowmini Varadhan 	offsetof(ether_fields_buf_t, eth_rem_fault), print_default_cb},
419*8002d411SSowmini Varadhan {NULL,		0,
420*8002d411SSowmini Varadhan 	0, 	NULL}}
421e7801d59Ssowmini ;
422e7801d59Ssowmini 
423e7801d59Ssowmini typedef struct print_ether_state {
424e7801d59Ssowmini 	const char	*es_link;
425*8002d411SSowmini Varadhan 	boolean_t	es_parsable;
426e7801d59Ssowmini 	boolean_t	es_header;
427e7801d59Ssowmini 	boolean_t	es_extended;
428*8002d411SSowmini Varadhan 	ofmt_handle_t	es_ofmt;
429e7801d59Ssowmini } print_ether_state_t;
430e7801d59Ssowmini 
431e7801d59Ssowmini /*
432da14cebeSEric Cheng  * structures for 'dladm show-link -s' (print statistics)
433e7801d59Ssowmini  */
434e7801d59Ssowmini typedef enum {
435ae6aa22aSVenugopal Iyer 	LINK_S_LINK,
436ae6aa22aSVenugopal Iyer 	LINK_S_IPKTS,
437ae6aa22aSVenugopal Iyer 	LINK_S_RBYTES,
438ae6aa22aSVenugopal Iyer 	LINK_S_IERRORS,
439ae6aa22aSVenugopal Iyer 	LINK_S_OPKTS,
440ae6aa22aSVenugopal Iyer 	LINK_S_OBYTES,
441ae6aa22aSVenugopal Iyer 	LINK_S_OERRORS
442ae6aa22aSVenugopal Iyer } link_s_field_index_t;
443e7801d59Ssowmini 
444*8002d411SSowmini Varadhan static ofmt_field_t link_s_fields[] = {
445*8002d411SSowmini Varadhan /* name,	field width,	index,		callback	*/
446*8002d411SSowmini Varadhan { "LINK",	15,		LINK_S_LINK,	print_link_stats_cb},
447*8002d411SSowmini Varadhan { "IPACKETS",	10,		LINK_S_IPKTS,	print_link_stats_cb},
448*8002d411SSowmini Varadhan { "RBYTES",	8,		LINK_S_RBYTES,	print_link_stats_cb},
449*8002d411SSowmini Varadhan { "IERRORS",	10,		LINK_S_IERRORS,	print_link_stats_cb},
450*8002d411SSowmini Varadhan { "OPACKETS",	12,		LINK_S_OPKTS,	print_link_stats_cb},
451*8002d411SSowmini Varadhan { "OBYTES",	12,		LINK_S_OBYTES,	print_link_stats_cb},
452*8002d411SSowmini Varadhan { "OERRORS",	8,		LINK_S_OERRORS,	print_link_stats_cb}}
453e7801d59Ssowmini ;
454ae6aa22aSVenugopal Iyer 
455ae6aa22aSVenugopal Iyer typedef struct link_args_s {
456ae6aa22aSVenugopal Iyer 	char		*link_s_link;
457ae6aa22aSVenugopal Iyer 	pktsum_t	*link_s_psum;
458ae6aa22aSVenugopal Iyer } link_args_t;
459e7801d59Ssowmini 
460e7801d59Ssowmini /*
461e7801d59Ssowmini  * buffer used by print functions for show-{link,phys,vlan} commands.
462e7801d59Ssowmini  */
463e7801d59Ssowmini typedef struct link_fields_buf_s {
464e7801d59Ssowmini 	char link_name[MAXLINKNAMELEN];
465e7801d59Ssowmini 	char link_class[DLADM_STRSIZE];
466c08e5e1aSdr146992 	char link_mtu[11];
467e7801d59Ssowmini 	char link_state[DLADM_STRSIZE];
468e7801d59Ssowmini 	char link_over[MAXLINKNAMELEN];
4694045d941Ssowmini 	char link_phys_state[DLADM_STRSIZE];
470e7801d59Ssowmini 	char link_phys_media[DLADM_STRSIZE];
471e7801d59Ssowmini 	char link_phys_speed[DLADM_STRSIZE];
472e7801d59Ssowmini 	char link_phys_duplex[DLPI_LINKNAME_MAX];
473e7801d59Ssowmini 	char link_phys_device[DLPI_LINKNAME_MAX];
474e7801d59Ssowmini 	char link_flags[6];
475e7801d59Ssowmini 	char link_vlan_vid[6];
476e7801d59Ssowmini } link_fields_buf_t;
477e7801d59Ssowmini 
478e7801d59Ssowmini /*
479e7801d59Ssowmini  * structures for 'dladm show-link'
480e7801d59Ssowmini  */
481*8002d411SSowmini Varadhan static ofmt_field_t link_fields[] = {
482*8002d411SSowmini Varadhan /* name,	field width,	index,	callback */
483*8002d411SSowmini Varadhan { "LINK",	12,
484*8002d411SSowmini Varadhan 	offsetof(link_fields_buf_t, link_name), print_default_cb},
485*8002d411SSowmini Varadhan { "CLASS",	9,
486*8002d411SSowmini Varadhan 	offsetof(link_fields_buf_t, link_class), print_default_cb},
487*8002d411SSowmini Varadhan { "MTU",	7,
488*8002d411SSowmini Varadhan 	offsetof(link_fields_buf_t, link_mtu), print_default_cb},
489*8002d411SSowmini Varadhan { "STATE",	9,
490*8002d411SSowmini Varadhan 	offsetof(link_fields_buf_t, link_state), print_default_cb},
491*8002d411SSowmini Varadhan { "OVER",	DLPI_LINKNAME_MAX,
492*8002d411SSowmini Varadhan 	offsetof(link_fields_buf_t, link_over), print_default_cb},
493*8002d411SSowmini Varadhan { NULL,		0, 0, NULL}}
494e7801d59Ssowmini ;
495e7801d59Ssowmini 
496e7801d59Ssowmini /*
497e7801d59Ssowmini  * structures for 'dladm show-aggr'
498e7801d59Ssowmini  */
499e7801d59Ssowmini typedef struct laggr_fields_buf_s {
500e7801d59Ssowmini 	char laggr_name[DLPI_LINKNAME_MAX];
501e7801d59Ssowmini 	char laggr_policy[9];
502e7801d59Ssowmini 	char laggr_addrpolicy[ETHERADDRL * 3 + 3];
503e7801d59Ssowmini 	char laggr_lacpactivity[14];
504e7801d59Ssowmini 	char laggr_lacptimer[DLADM_STRSIZE];
505e7801d59Ssowmini 	char laggr_flags[7];
506e7801d59Ssowmini } laggr_fields_buf_t;
507e7801d59Ssowmini 
508e7801d59Ssowmini typedef struct laggr_args_s {
509e7801d59Ssowmini 	int			laggr_lport; /* -1 indicates the aggr itself */
510e7801d59Ssowmini 	const char 		*laggr_link;
511e7801d59Ssowmini 	dladm_aggr_grp_attr_t	*laggr_ginfop;
512e7801d59Ssowmini 	dladm_status_t		*laggr_status;
513e7801d59Ssowmini 	pktsum_t		*laggr_pktsumtot; /* -s only */
514e7801d59Ssowmini 	pktsum_t		*laggr_prevstats; /* -s only */
515*8002d411SSowmini Varadhan 	boolean_t		laggr_parsable;
516e7801d59Ssowmini } laggr_args_t;
517e7801d59Ssowmini 
518*8002d411SSowmini Varadhan static ofmt_field_t laggr_fields[] = {
519*8002d411SSowmini Varadhan /* name,	field width,	offset,	callback */
520*8002d411SSowmini Varadhan { "LINK",	16,
521*8002d411SSowmini Varadhan 	offsetof(laggr_fields_buf_t, laggr_name), print_default_cb},
522*8002d411SSowmini Varadhan { "POLICY",	9,
523*8002d411SSowmini Varadhan 	offsetof(laggr_fields_buf_t, laggr_policy), print_default_cb},
524*8002d411SSowmini Varadhan { "ADDRPOLICY",	ETHERADDRL * 3 + 3,
525*8002d411SSowmini Varadhan 	offsetof(laggr_fields_buf_t, laggr_addrpolicy), print_default_cb},
526*8002d411SSowmini Varadhan { "LACPACTIVITY", 14,
527*8002d411SSowmini Varadhan 	offsetof(laggr_fields_buf_t, laggr_lacpactivity), print_default_cb},
528*8002d411SSowmini Varadhan { "LACPTIMER",	12,
529*8002d411SSowmini Varadhan 	offsetof(laggr_fields_buf_t, laggr_lacptimer), print_default_cb},
530*8002d411SSowmini Varadhan { "FLAGS",	8,
531*8002d411SSowmini Varadhan 	offsetof(laggr_fields_buf_t, laggr_flags), print_default_cb},
532*8002d411SSowmini Varadhan { NULL,		0, 0, NULL}}
533e7801d59Ssowmini ;
534e7801d59Ssowmini 
535e7801d59Ssowmini /*
536e7801d59Ssowmini  * structures for 'dladm show-aggr -x'.
537e7801d59Ssowmini  */
538e7801d59Ssowmini typedef enum {
539e7801d59Ssowmini 	AGGR_X_LINK,
540e7801d59Ssowmini 	AGGR_X_PORT,
541e7801d59Ssowmini 	AGGR_X_SPEED,
542e7801d59Ssowmini 	AGGR_X_DUPLEX,
543e7801d59Ssowmini 	AGGR_X_STATE,
544e7801d59Ssowmini 	AGGR_X_ADDRESS,
545e7801d59Ssowmini 	AGGR_X_PORTSTATE
546e7801d59Ssowmini } aggr_x_field_index_t;
547e7801d59Ssowmini 
548*8002d411SSowmini Varadhan static ofmt_field_t aggr_x_fields[] = {
549*8002d411SSowmini Varadhan /* name,	field width,	index		callback */
550*8002d411SSowmini Varadhan { "LINK",	12,	AGGR_X_LINK,		print_xaggr_cb},
551*8002d411SSowmini Varadhan { "PORT",	15,	AGGR_X_PORT,		print_xaggr_cb},
552*8002d411SSowmini Varadhan { "SPEED",	5,	AGGR_X_SPEED,		print_xaggr_cb},
553*8002d411SSowmini Varadhan { "DUPLEX",	10,	AGGR_X_DUPLEX,		print_xaggr_cb},
554*8002d411SSowmini Varadhan { "STATE",	10,	AGGR_X_STATE,		print_xaggr_cb},
555*8002d411SSowmini Varadhan { "ADDRESS",	19,	AGGR_X_ADDRESS,		print_xaggr_cb},
556*8002d411SSowmini Varadhan { "PORTSTATE",	16,	AGGR_X_PORTSTATE,	print_xaggr_cb},
557*8002d411SSowmini Varadhan { NULL,		0,	0,			NULL}}
558e7801d59Ssowmini ;
559e7801d59Ssowmini 
560e7801d59Ssowmini /*
561e7801d59Ssowmini  * structures for 'dladm show-aggr -s'.
562e7801d59Ssowmini  */
563e7801d59Ssowmini typedef enum {
564e7801d59Ssowmini 	AGGR_S_LINK,
565e7801d59Ssowmini 	AGGR_S_PORT,
566e7801d59Ssowmini 	AGGR_S_IPKTS,
567e7801d59Ssowmini 	AGGR_S_RBYTES,
568e7801d59Ssowmini 	AGGR_S_OPKTS,
569e7801d59Ssowmini 	AGGR_S_OBYTES,
570e7801d59Ssowmini 	AGGR_S_IPKTDIST,
571e7801d59Ssowmini 	AGGR_S_OPKTDIST
572e7801d59Ssowmini } aggr_s_field_index_t;
573e7801d59Ssowmini 
574*8002d411SSowmini Varadhan static ofmt_field_t aggr_s_fields[] = {
575*8002d411SSowmini Varadhan { "LINK",		12,	AGGR_S_LINK, print_aggr_stats_cb},
576*8002d411SSowmini Varadhan { "PORT",		10,	AGGR_S_PORT, print_aggr_stats_cb},
577*8002d411SSowmini Varadhan { "IPACKETS",		8,	AGGR_S_IPKTS, print_aggr_stats_cb},
578*8002d411SSowmini Varadhan { "RBYTES",		8,	AGGR_S_RBYTES, print_aggr_stats_cb},
579*8002d411SSowmini Varadhan { "OPACKETS",		8,	AGGR_S_OPKTS, print_aggr_stats_cb},
580*8002d411SSowmini Varadhan { "OBYTES",		8,	AGGR_S_OBYTES, print_aggr_stats_cb},
581*8002d411SSowmini Varadhan { "IPKTDIST",		9,	AGGR_S_IPKTDIST, print_aggr_stats_cb},
582*8002d411SSowmini Varadhan { "OPKTDIST",		15,	AGGR_S_OPKTDIST, print_aggr_stats_cb},
583*8002d411SSowmini Varadhan { NULL,			0,	0,		NULL}}
584e7801d59Ssowmini ;
585e7801d59Ssowmini 
586e7801d59Ssowmini /*
587da14cebeSEric Cheng  * structures for 'dladm show-aggr -L'.
588e7801d59Ssowmini  */
589e7801d59Ssowmini typedef enum {
590e7801d59Ssowmini 	AGGR_L_LINK,
591e7801d59Ssowmini 	AGGR_L_PORT,
592e7801d59Ssowmini 	AGGR_L_AGGREGATABLE,
593e7801d59Ssowmini 	AGGR_L_SYNC,
594e7801d59Ssowmini 	AGGR_L_COLL,
595e7801d59Ssowmini 	AGGR_L_DIST,
596e7801d59Ssowmini 	AGGR_L_DEFAULTED,
597e7801d59Ssowmini 	AGGR_L_EXPIRED
598e7801d59Ssowmini } aggr_l_field_index_t;
599e7801d59Ssowmini 
600*8002d411SSowmini Varadhan static ofmt_field_t aggr_l_fields[] = {
601*8002d411SSowmini Varadhan /* name,		field width,	index */
602*8002d411SSowmini Varadhan { "LINK",		12,	AGGR_L_LINK,		print_lacp_cb},
603*8002d411SSowmini Varadhan { "PORT",		13,	AGGR_L_PORT,		print_lacp_cb},
604*8002d411SSowmini Varadhan { "AGGREGATABLE",	13,	AGGR_L_AGGREGATABLE,	print_lacp_cb},
605*8002d411SSowmini Varadhan { "SYNC",		5,	AGGR_L_SYNC,		print_lacp_cb},
606*8002d411SSowmini Varadhan { "COLL",		5,	AGGR_L_COLL,		print_lacp_cb},
607*8002d411SSowmini Varadhan { "DIST",		5,	AGGR_L_DIST,		print_lacp_cb},
608*8002d411SSowmini Varadhan { "DEFAULTED",		10,	AGGR_L_DEFAULTED,	print_lacp_cb},
609*8002d411SSowmini Varadhan { "EXPIRED",		15,	AGGR_L_EXPIRED,		print_lacp_cb},
610*8002d411SSowmini Varadhan { NULL,			0,	0,			NULL}}
611e7801d59Ssowmini ;
612e7801d59Ssowmini 
613e7801d59Ssowmini /*
614e7801d59Ssowmini  * structures for 'dladm show-phys'
615e7801d59Ssowmini  */
616e7801d59Ssowmini 
617*8002d411SSowmini Varadhan static ofmt_field_t phys_fields[] = {
618*8002d411SSowmini Varadhan /* name,	field width,	offset */
619*8002d411SSowmini Varadhan { "LINK",	13,
620*8002d411SSowmini Varadhan 	offsetof(link_fields_buf_t, link_name), print_default_cb},
621*8002d411SSowmini Varadhan { "MEDIA",	21,
622*8002d411SSowmini Varadhan 	offsetof(link_fields_buf_t, link_phys_media), print_default_cb},
623*8002d411SSowmini Varadhan { "STATE",	11,
624*8002d411SSowmini Varadhan 	offsetof(link_fields_buf_t, link_phys_state), print_default_cb},
625*8002d411SSowmini Varadhan { "SPEED",	7,
626*8002d411SSowmini Varadhan 	offsetof(link_fields_buf_t, link_phys_speed), print_default_cb},
627*8002d411SSowmini Varadhan { "DUPLEX",	10,
628*8002d411SSowmini Varadhan 	offsetof(link_fields_buf_t, link_phys_duplex), print_default_cb},
629*8002d411SSowmini Varadhan { "DEVICE",	13,
630*8002d411SSowmini Varadhan 	offsetof(link_fields_buf_t, link_phys_device), print_default_cb},
631*8002d411SSowmini Varadhan { "FLAGS",	7,
632*8002d411SSowmini Varadhan 	offsetof(link_fields_buf_t, link_flags), print_default_cb},
633*8002d411SSowmini Varadhan { NULL,		0, NULL, 0}}
634e7801d59Ssowmini ;
635e7801d59Ssowmini 
636e7801d59Ssowmini /*
637da14cebeSEric Cheng  * structures for 'dladm show-phys -m'
638da14cebeSEric Cheng  */
639da14cebeSEric Cheng 
640da14cebeSEric Cheng typedef enum {
641da14cebeSEric Cheng 	PHYS_M_LINK,
642da14cebeSEric Cheng 	PHYS_M_SLOT,
643da14cebeSEric Cheng 	PHYS_M_ADDRESS,
644da14cebeSEric Cheng 	PHYS_M_INUSE,
645da14cebeSEric Cheng 	PHYS_M_CLIENT
646da14cebeSEric Cheng } phys_m_field_index_t;
647da14cebeSEric Cheng 
648*8002d411SSowmini Varadhan static ofmt_field_t phys_m_fields[] = {
649*8002d411SSowmini Varadhan /* name,	field width,	offset */
650*8002d411SSowmini Varadhan { "LINK",	13,	PHYS_M_LINK,	print_phys_one_mac_cb},
651*8002d411SSowmini Varadhan { "SLOT",	9,	PHYS_M_SLOT,	print_phys_one_mac_cb},
652*8002d411SSowmini Varadhan { "ADDRESS",	19,	PHYS_M_ADDRESS,	print_phys_one_mac_cb},
653*8002d411SSowmini Varadhan { "INUSE",	5,	PHYS_M_INUSE,	print_phys_one_mac_cb},
654*8002d411SSowmini Varadhan { "CLIENT",	13,	PHYS_M_CLIENT,	print_phys_one_mac_cb},
655*8002d411SSowmini Varadhan { NULL,		0,	0,		NULL}}
656da14cebeSEric Cheng ;
657da14cebeSEric Cheng 
658da14cebeSEric Cheng /*
659da14cebeSEric Cheng  * structures for 'dladm show-phys -H'
660da14cebeSEric Cheng  */
661da14cebeSEric Cheng 
662da14cebeSEric Cheng typedef enum {
663da14cebeSEric Cheng 	PHYS_H_LINK,
664da14cebeSEric Cheng 	PHYS_H_GROUP,
665da14cebeSEric Cheng 	PHYS_H_GRPTYPE,
666da14cebeSEric Cheng 	PHYS_H_RINGS,
667da14cebeSEric Cheng 	PHYS_H_CLIENTS
668da14cebeSEric Cheng } phys_h_field_index_t;
669da14cebeSEric Cheng 
670*8002d411SSowmini Varadhan static ofmt_field_t phys_h_fields[] = {
671*8002d411SSowmini Varadhan { "LINK",	13,	PHYS_H_LINK,	print_phys_one_hwgrp_cb},
672*8002d411SSowmini Varadhan { "GROUP",	9,	PHYS_H_GROUP,	print_phys_one_hwgrp_cb},
673*8002d411SSowmini Varadhan { "GROUPTYPE",	7,	PHYS_H_GRPTYPE,	print_phys_one_hwgrp_cb},
674*8002d411SSowmini Varadhan { "RINGS",	17,	PHYS_H_RINGS,	print_phys_one_hwgrp_cb},
675*8002d411SSowmini Varadhan { "CLIENTS",	21,	PHYS_H_CLIENTS,	print_phys_one_hwgrp_cb},
676*8002d411SSowmini Varadhan { NULL,		0,	0,		NULL}}
677da14cebeSEric Cheng ;
678da14cebeSEric Cheng 
679da14cebeSEric Cheng /*
680e7801d59Ssowmini  * structures for 'dladm show-vlan'
681e7801d59Ssowmini  */
682*8002d411SSowmini Varadhan static ofmt_field_t vlan_fields[] = {
683*8002d411SSowmini Varadhan { "LINK",	16,
684*8002d411SSowmini Varadhan 	offsetof(link_fields_buf_t, link_name), print_default_cb},
685*8002d411SSowmini Varadhan { "VID",	9,
686*8002d411SSowmini Varadhan 	offsetof(link_fields_buf_t, link_vlan_vid), print_default_cb},
687*8002d411SSowmini Varadhan { "OVER",	13,
688*8002d411SSowmini Varadhan 	offsetof(link_fields_buf_t, link_over), print_default_cb},
689*8002d411SSowmini Varadhan { "FLAGS",	7,
690*8002d411SSowmini Varadhan 	offsetof(link_fields_buf_t, link_flags), print_default_cb},
691*8002d411SSowmini Varadhan { NULL,		0, 0, NULL}}
692e7801d59Ssowmini ;
693da14cebeSEric Cheng 
694e7801d59Ssowmini /*
695*8002d411SSowmini Varadhan  * structures common to 'dladm scan-wifi' and 'dladm show-wifi'
696*8002d411SSowmini Varadhan  * callback will be determined in parse_wifi_fields.
697e7801d59Ssowmini  */
698*8002d411SSowmini Varadhan static ofmt_field_t wifi_common_fields[] = {
699*8002d411SSowmini Varadhan { "LINK",	11, 0,				NULL},
700*8002d411SSowmini Varadhan { "ESSID",	20, DLADM_WLAN_ATTR_ESSID,	NULL},
701*8002d411SSowmini Varadhan { "BSSID",	18, DLADM_WLAN_ATTR_BSSID,	NULL},
702*8002d411SSowmini Varadhan { "IBSSID",	18, DLADM_WLAN_ATTR_BSSID,	NULL},
703*8002d411SSowmini Varadhan { "MODE",	7,  DLADM_WLAN_ATTR_MODE,	NULL},
704*8002d411SSowmini Varadhan { "SPEED",	7,  DLADM_WLAN_ATTR_SPEED,	NULL},
705*8002d411SSowmini Varadhan { "BSSTYPE",	9,  DLADM_WLAN_ATTR_BSSTYPE,	NULL},
706*8002d411SSowmini Varadhan { "SEC",	7,  DLADM_WLAN_ATTR_SECMODE,	NULL},
707*8002d411SSowmini Varadhan { "STRENGTH",	11, DLADM_WLAN_ATTR_STRENGTH,	NULL},
708*8002d411SSowmini Varadhan { NULL,		0,  0,				NULL}};
709*8002d411SSowmini Varadhan 
710*8002d411SSowmini Varadhan /*
711*8002d411SSowmini Varadhan  * the 'show-wifi' command supports all the fields in wifi_common_fields
712*8002d411SSowmini Varadhan  * plus the AUTH and STATUS fields.
713*8002d411SSowmini Varadhan  */
714*8002d411SSowmini Varadhan static ofmt_field_t wifi_show_fields[A_CNT(wifi_common_fields) + 2] = {
715*8002d411SSowmini Varadhan { "AUTH",	9,  DLADM_WLAN_ATTR_AUTH,	NULL},
716*8002d411SSowmini Varadhan { "STATUS",	18, DLADM_WLAN_LINKATTR_STATUS,	print_wifi_status_cb},
717*8002d411SSowmini Varadhan /* copy wifi_common_fields here */
718*8002d411SSowmini Varadhan };
719e7801d59Ssowmini 
720e7801d59Ssowmini static char *all_scan_wifi_fields =
721e7801d59Ssowmini 	"link,essid,bssid,sec,strength,mode,speed,bsstype";
722e7801d59Ssowmini static char *all_show_wifi_fields =
723e7801d59Ssowmini 	"link,status,essid,sec,strength,mode,speed,auth,bssid,bsstype";
724e7801d59Ssowmini static char *def_scan_wifi_fields =
725e7801d59Ssowmini 	"link,essid,bssid,sec,strength,mode,speed";
726e7801d59Ssowmini static char *def_show_wifi_fields =
727e7801d59Ssowmini 	"link,status,essid,sec,strength,mode,speed";
728e7801d59Ssowmini 
729e7801d59Ssowmini /*
730e7801d59Ssowmini  * structures for 'dladm show-linkprop'
731e7801d59Ssowmini  */
732e7801d59Ssowmini typedef enum {
733e7801d59Ssowmini 	LINKPROP_LINK,
734e7801d59Ssowmini 	LINKPROP_PROPERTY,
735afdda45fSVasumathi Sundaram - Sun Microsystems 	LINKPROP_PERM,
736e7801d59Ssowmini 	LINKPROP_VALUE,
737e7801d59Ssowmini 	LINKPROP_DEFAULT,
738e7801d59Ssowmini 	LINKPROP_POSSIBLE
739e7801d59Ssowmini } linkprop_field_index_t;
740e7801d59Ssowmini 
741*8002d411SSowmini Varadhan static ofmt_field_t linkprop_fields[] = {
742*8002d411SSowmini Varadhan /* name,	field width,  index */
743*8002d411SSowmini Varadhan { "LINK",	13,	LINKPROP_LINK,		print_linkprop_cb},
744*8002d411SSowmini Varadhan { "PROPERTY",	16,	LINKPROP_PROPERTY,	print_linkprop_cb},
745*8002d411SSowmini Varadhan { "PERM",	5,	LINKPROP_PERM,		print_linkprop_cb},
746*8002d411SSowmini Varadhan { "VALUE",	15,	LINKPROP_VALUE,		print_linkprop_cb},
747*8002d411SSowmini Varadhan { "DEFAULT",	15,	LINKPROP_DEFAULT,	print_linkprop_cb},
748*8002d411SSowmini Varadhan { "POSSIBLE",	21,	LINKPROP_POSSIBLE,	print_linkprop_cb},
749*8002d411SSowmini Varadhan { NULL,		0,	0,			NULL}}
750e7801d59Ssowmini ;
751e7801d59Ssowmini 
752e7801d59Ssowmini #define	MAX_PROP_LINE		512
753e7801d59Ssowmini 
754e7801d59Ssowmini typedef struct show_linkprop_state {
755e7801d59Ssowmini 	char			ls_link[MAXLINKNAMELEN];
756e7801d59Ssowmini 	char			*ls_line;
757e7801d59Ssowmini 	char			**ls_propvals;
758da14cebeSEric Cheng 	dladm_arg_list_t	*ls_proplist;
759*8002d411SSowmini Varadhan 	boolean_t		ls_parsable;
760e7801d59Ssowmini 	boolean_t		ls_persist;
761e7801d59Ssowmini 	boolean_t		ls_header;
762e7801d59Ssowmini 	dladm_status_t		ls_status;
763e7801d59Ssowmini 	dladm_status_t		ls_retstatus;
764*8002d411SSowmini Varadhan 	ofmt_handle_t		ls_ofmt;
765e7801d59Ssowmini } show_linkprop_state_t;
766e7801d59Ssowmini 
767da14cebeSEric Cheng typedef struct set_linkprop_state {
768da14cebeSEric Cheng 	const char		*ls_name;
769da14cebeSEric Cheng 	boolean_t		ls_reset;
770da14cebeSEric Cheng 	boolean_t		ls_temp;
771da14cebeSEric Cheng 	dladm_status_t		ls_status;
772da14cebeSEric Cheng } set_linkprop_state_t;
773da14cebeSEric Cheng 
774e7801d59Ssowmini typedef struct linkprop_args_s {
775e7801d59Ssowmini 	show_linkprop_state_t	*ls_state;
776e7801d59Ssowmini 	char			*ls_propname;
777e7801d59Ssowmini 	datalink_id_t		ls_linkid;
778e7801d59Ssowmini } linkprop_args_t;
779e7801d59Ssowmini 
780e7801d59Ssowmini /*
781e7801d59Ssowmini  * structures for 'dladm show-secobj'
782e7801d59Ssowmini  */
783e7801d59Ssowmini typedef struct secobj_fields_buf_s {
784e7801d59Ssowmini 	char			ss_obj_name[DLADM_SECOBJ_VAL_MAX];
785e7801d59Ssowmini 	char			ss_class[20];
786e7801d59Ssowmini 	char			ss_val[30];
787e7801d59Ssowmini } secobj_fields_buf_t;
788*8002d411SSowmini Varadhan 
789*8002d411SSowmini Varadhan static ofmt_field_t secobj_fields[] = {
790*8002d411SSowmini Varadhan { "OBJECT",	21,
791*8002d411SSowmini Varadhan 	offsetof(secobj_fields_buf_t, ss_obj_name), print_default_cb},
792*8002d411SSowmini Varadhan { "CLASS",	21,
793*8002d411SSowmini Varadhan 	offsetof(secobj_fields_buf_t, ss_class), print_default_cb},
794*8002d411SSowmini Varadhan { "VALUE",	31,
795*8002d411SSowmini Varadhan 	offsetof(secobj_fields_buf_t, ss_val), print_default_cb},
796*8002d411SSowmini Varadhan { NULL,		0, 0, NULL}}
797e7801d59Ssowmini ;
7980ba2cbe9Sxc151355 
799da14cebeSEric Cheng /*
800da14cebeSEric Cheng  * structures for 'dladm show-vnic'
801da14cebeSEric Cheng  */
802da14cebeSEric Cheng typedef struct vnic_fields_buf_s
803da14cebeSEric Cheng {
804da14cebeSEric Cheng 	char vnic_link[DLPI_LINKNAME_MAX];
805da14cebeSEric Cheng 	char vnic_over[DLPI_LINKNAME_MAX];
806da14cebeSEric Cheng 	char vnic_speed[6];
807da14cebeSEric Cheng 	char vnic_macaddr[19];
808da14cebeSEric Cheng 	char vnic_macaddrtype[19];
809da14cebeSEric Cheng 	char vnic_vid[6];
810da14cebeSEric Cheng } vnic_fields_buf_t;
811da14cebeSEric Cheng 
812*8002d411SSowmini Varadhan static ofmt_field_t vnic_fields[] = {
813*8002d411SSowmini Varadhan { "LINK",		13,
814*8002d411SSowmini Varadhan 	offsetof(vnic_fields_buf_t, vnic_link),	print_default_cb},
815*8002d411SSowmini Varadhan { "OVER",		13,
816*8002d411SSowmini Varadhan 	offsetof(vnic_fields_buf_t, vnic_over),	print_default_cb},
817*8002d411SSowmini Varadhan { "SPEED",		7,
818*8002d411SSowmini Varadhan 	offsetof(vnic_fields_buf_t, vnic_speed), print_default_cb},
819*8002d411SSowmini Varadhan { "MACADDRESS",		21,
820*8002d411SSowmini Varadhan 	offsetof(vnic_fields_buf_t, vnic_macaddr), print_default_cb},
821*8002d411SSowmini Varadhan { "MACADDRTYPE",	20,
822*8002d411SSowmini Varadhan 	offsetof(vnic_fields_buf_t, vnic_macaddrtype), print_default_cb},
823*8002d411SSowmini Varadhan { "VID",		7,
824*8002d411SSowmini Varadhan 	offsetof(vnic_fields_buf_t, vnic_vid), print_default_cb},
825*8002d411SSowmini Varadhan { NULL,			0, 0, NULL}}
826da14cebeSEric Cheng ;
827da14cebeSEric Cheng 
828da14cebeSEric Cheng /*
829da14cebeSEric Cheng  * structures for 'dladm show-usage'
830da14cebeSEric Cheng  */
831da14cebeSEric Cheng 
832da14cebeSEric Cheng typedef struct  usage_fields_buf_s {
833da14cebeSEric Cheng 	char	usage_link[12];
834da14cebeSEric Cheng 	char	usage_duration[10];
835da14cebeSEric Cheng 	char	usage_ipackets[9];
836da14cebeSEric Cheng 	char	usage_rbytes[10];
837da14cebeSEric Cheng 	char	usage_opackets[9];
838da14cebeSEric Cheng 	char	usage_obytes[10];
839da14cebeSEric Cheng 	char	usage_bandwidth[14];
840da14cebeSEric Cheng } usage_fields_buf_t;
841da14cebeSEric Cheng 
842*8002d411SSowmini Varadhan static ofmt_field_t usage_fields[] = {
843*8002d411SSowmini Varadhan { "LINK",	13,
844*8002d411SSowmini Varadhan 	offsetof(usage_fields_buf_t, usage_link), print_default_cb},
845*8002d411SSowmini Varadhan { "DURATION",	11,
846*8002d411SSowmini Varadhan 	offsetof(usage_fields_buf_t, usage_duration), print_default_cb},
847*8002d411SSowmini Varadhan { "IPACKETS",	10,
848*8002d411SSowmini Varadhan 	offsetof(usage_fields_buf_t, usage_ipackets), print_default_cb},
849*8002d411SSowmini Varadhan { "RBYTES",	11,
850*8002d411SSowmini Varadhan 	offsetof(usage_fields_buf_t, usage_rbytes), print_default_cb},
851*8002d411SSowmini Varadhan { "OPACKETS",	10,
852*8002d411SSowmini Varadhan 	offsetof(usage_fields_buf_t, usage_opackets), print_default_cb},
853*8002d411SSowmini Varadhan { "OBYTES",	11,
854*8002d411SSowmini Varadhan 	offsetof(usage_fields_buf_t, usage_obytes), print_default_cb},
855*8002d411SSowmini Varadhan { "BANDWIDTH",	15,
856*8002d411SSowmini Varadhan 	offsetof(usage_fields_buf_t, usage_bandwidth), print_default_cb},
857*8002d411SSowmini Varadhan { NULL,		0, 0, NULL}}
858da14cebeSEric Cheng ;
859da14cebeSEric Cheng 
860da14cebeSEric Cheng 
861da14cebeSEric Cheng /*
862da14cebeSEric Cheng  * structures for 'dladm show-usage link'
863da14cebeSEric Cheng  */
864da14cebeSEric Cheng 
865da14cebeSEric Cheng typedef struct  usage_l_fields_buf_s {
866da14cebeSEric Cheng 	char	usage_l_link[12];
867da14cebeSEric Cheng 	char	usage_l_stime[13];
868da14cebeSEric Cheng 	char	usage_l_etime[13];
869da14cebeSEric Cheng 	char	usage_l_rbytes[8];
870da14cebeSEric Cheng 	char	usage_l_obytes[8];
871da14cebeSEric Cheng 	char	usage_l_bandwidth[14];
872da14cebeSEric Cheng } usage_l_fields_buf_t;
873da14cebeSEric Cheng 
874*8002d411SSowmini Varadhan static ofmt_field_t usage_l_fields[] = {
875*8002d411SSowmini Varadhan /* name,	field width,	offset */
876*8002d411SSowmini Varadhan { "LINK",	13,
877*8002d411SSowmini Varadhan 	offsetof(usage_l_fields_buf_t, usage_l_link), print_default_cb},
878*8002d411SSowmini Varadhan { "START",	14,
879*8002d411SSowmini Varadhan 	offsetof(usage_l_fields_buf_t, usage_l_stime), print_default_cb},
880*8002d411SSowmini Varadhan { "END",	14,
881*8002d411SSowmini Varadhan 	offsetof(usage_l_fields_buf_t, usage_l_etime), print_default_cb},
882*8002d411SSowmini Varadhan { "RBYTES",	9,
883*8002d411SSowmini Varadhan 	offsetof(usage_l_fields_buf_t, usage_l_rbytes), print_default_cb},
884*8002d411SSowmini Varadhan { "OBYTES",	9,
885*8002d411SSowmini Varadhan 	offsetof(usage_l_fields_buf_t, usage_l_obytes), print_default_cb},
886*8002d411SSowmini Varadhan { "BANDWIDTH",	15,
887*8002d411SSowmini Varadhan 	offsetof(usage_l_fields_buf_t, usage_l_bandwidth), print_default_cb},
888*8002d411SSowmini Varadhan { NULL,		0, 0, NULL}}
889da14cebeSEric Cheng ;
890da14cebeSEric Cheng 
8917c478bd9Sstevel@tonic-gate static char *progname;
8920ba2cbe9Sxc151355 static sig_atomic_t signalled;
8937c478bd9Sstevel@tonic-gate 
8944ac67f02SAnurag S. Maskey /*
8954ac67f02SAnurag S. Maskey  * Handle to libdladm.  Opened in main() before the sub-command
8964ac67f02SAnurag S. Maskey  * specific function is called.
8974ac67f02SAnurag S. Maskey  */
8984ac67f02SAnurag S. Maskey static dladm_handle_t handle = NULL;
8994ac67f02SAnurag S. Maskey 
900da14cebeSEric Cheng #define	DLADM_ETHERSTUB_NAME	"etherstub"
901da14cebeSEric Cheng #define	DLADM_IS_ETHERSTUB(id)	(id == DATALINK_INVALID_LINKID)
902da14cebeSEric Cheng 
9037c478bd9Sstevel@tonic-gate static void
9047c478bd9Sstevel@tonic-gate usage(void)
9057c478bd9Sstevel@tonic-gate {
9068d5c46e6Sam223141 	int	i;
9078d5c46e6Sam223141 	cmd_t	*cmdp;
9088d5c46e6Sam223141 	(void) fprintf(stderr, gettext("usage:  dladm <subcommand> <args> ..."
9098d5c46e6Sam223141 	    "\n"));
9108d5c46e6Sam223141 	for (i = 0; i < sizeof (cmds) / sizeof (cmds[0]); i++) {
9118d5c46e6Sam223141 		cmdp = &cmds[i];
9128d5c46e6Sam223141 		if (cmdp->c_usage != NULL)
9138d5c46e6Sam223141 			(void) fprintf(stderr, "%s\n", gettext(cmdp->c_usage));
9148d5c46e6Sam223141 	}
9154ac67f02SAnurag S. Maskey 
9164ac67f02SAnurag S. Maskey 	/* close dladm handle if it was opened */
9174ac67f02SAnurag S. Maskey 	if (handle != NULL)
9184ac67f02SAnurag S. Maskey 		dladm_close(handle);
9194ac67f02SAnurag S. Maskey 
9207c478bd9Sstevel@tonic-gate 	exit(1);
9217c478bd9Sstevel@tonic-gate }
9227c478bd9Sstevel@tonic-gate 
9237c478bd9Sstevel@tonic-gate int
9247c478bd9Sstevel@tonic-gate main(int argc, char *argv[])
9257c478bd9Sstevel@tonic-gate {
9267c478bd9Sstevel@tonic-gate 	int	i;
9277c478bd9Sstevel@tonic-gate 	cmd_t	*cmdp;
9284ac67f02SAnurag S. Maskey 	dladm_status_t status;
9297c478bd9Sstevel@tonic-gate 
9307c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
9317c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)
9327c478bd9Sstevel@tonic-gate #define	TEXT_DOMAIN "SYS_TEST"
9337c478bd9Sstevel@tonic-gate #endif
9347c478bd9Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
9357c478bd9Sstevel@tonic-gate 
9367c478bd9Sstevel@tonic-gate 	progname = argv[0];
9377c478bd9Sstevel@tonic-gate 
9387c478bd9Sstevel@tonic-gate 	if (argc < 2)
9397c478bd9Sstevel@tonic-gate 		usage();
9407c478bd9Sstevel@tonic-gate 
9417c478bd9Sstevel@tonic-gate 	for (i = 0; i < sizeof (cmds) / sizeof (cmds[0]); i++) {
9427c478bd9Sstevel@tonic-gate 		cmdp = &cmds[i];
9437c478bd9Sstevel@tonic-gate 		if (strcmp(argv[1], cmdp->c_name) == 0) {
9444ac67f02SAnurag S. Maskey 			/* Open the libdladm handle */
9454ac67f02SAnurag S. Maskey 			if ((status = dladm_open(&handle)) != DLADM_STATUS_OK) {
9464ac67f02SAnurag S. Maskey 				die_dlerr(status,
9474ac67f02SAnurag S. Maskey 				    "could not open /dev/dld");
9484ac67f02SAnurag S. Maskey 			}
9494ac67f02SAnurag S. Maskey 
9508d5c46e6Sam223141 			cmdp->c_fn(argc - 1, &argv[1], cmdp->c_usage);
9514ac67f02SAnurag S. Maskey 
9524ac67f02SAnurag S. Maskey 			dladm_close(handle);
9537c478bd9Sstevel@tonic-gate 			exit(0);
9547c478bd9Sstevel@tonic-gate 		}
9557c478bd9Sstevel@tonic-gate 	}
9567c478bd9Sstevel@tonic-gate 
9577c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("%s: unknown subcommand '%s'\n"),
9587c478bd9Sstevel@tonic-gate 	    progname, argv[1]);
9597c478bd9Sstevel@tonic-gate 	usage();
9607c478bd9Sstevel@tonic-gate 
9617c478bd9Sstevel@tonic-gate 	return (0);
9627c478bd9Sstevel@tonic-gate }
9637c478bd9Sstevel@tonic-gate 
964da14cebeSEric Cheng /*ARGSUSED*/
965da14cebeSEric Cheng static int
966da14cebeSEric Cheng show_usage_date(dladm_usage_t *usage, void *arg)
967da14cebeSEric Cheng {
968ae6aa22aSVenugopal Iyer 	show_usage_state_t	*state = (show_usage_state_t *)arg;
969da14cebeSEric Cheng 	time_t			stime;
970da14cebeSEric Cheng 	char			timebuf[20];
971ae6aa22aSVenugopal Iyer 	dladm_status_t		status;
972ae6aa22aSVenugopal Iyer 	uint32_t		flags;
973ae6aa22aSVenugopal Iyer 
974ae6aa22aSVenugopal Iyer 	/*
975ae6aa22aSVenugopal Iyer 	 * Only show usage information for existing links unless '-a'
976ae6aa22aSVenugopal Iyer 	 * is specified.
977ae6aa22aSVenugopal Iyer 	 */
978ae6aa22aSVenugopal Iyer 	if (!state->us_showall) {
979ae6aa22aSVenugopal Iyer 		if ((status = dladm_name2info(handle, usage->du_name,
980ae6aa22aSVenugopal Iyer 		    NULL, &flags, NULL, NULL)) != DLADM_STATUS_OK) {
981ae6aa22aSVenugopal Iyer 			return (status);
982ae6aa22aSVenugopal Iyer 		}
983ae6aa22aSVenugopal Iyer 		if ((flags & DLADM_OPT_ACTIVE) == 0)
984ae6aa22aSVenugopal Iyer 			return (DLADM_STATUS_LINKINVAL);
985ae6aa22aSVenugopal Iyer 	}
986da14cebeSEric Cheng 
987da14cebeSEric Cheng 	stime = usage->du_stime;
988da14cebeSEric Cheng 	(void) strftime(timebuf, sizeof (timebuf), "%m/%d/%Y",
989da14cebeSEric Cheng 	    localtime(&stime));
990da14cebeSEric Cheng 	(void) printf("%s\n", timebuf);
991da14cebeSEric Cheng 
992da14cebeSEric Cheng 	return (DLADM_STATUS_OK);
993da14cebeSEric Cheng }
994da14cebeSEric Cheng 
995da14cebeSEric Cheng static int
996da14cebeSEric Cheng show_usage_time(dladm_usage_t *usage, void *arg)
997da14cebeSEric Cheng {
998da14cebeSEric Cheng 	show_usage_state_t	*state = (show_usage_state_t *)arg;
999da14cebeSEric Cheng 	char			buf[DLADM_STRSIZE];
1000da14cebeSEric Cheng 	usage_l_fields_buf_t 	ubuf;
1001da14cebeSEric Cheng 	time_t			time;
1002da14cebeSEric Cheng 	double			bw;
1003ae6aa22aSVenugopal Iyer 	dladm_status_t		status;
1004ae6aa22aSVenugopal Iyer 	uint32_t		flags;
1005ae6aa22aSVenugopal Iyer 
1006ae6aa22aSVenugopal Iyer 	/*
1007ae6aa22aSVenugopal Iyer 	 * Only show usage information for existing links unless '-a'
1008ae6aa22aSVenugopal Iyer 	 * is specified.
1009ae6aa22aSVenugopal Iyer 	 */
1010ae6aa22aSVenugopal Iyer 	if (!state->us_showall) {
1011ae6aa22aSVenugopal Iyer 		if ((status = dladm_name2info(handle, usage->du_name,
1012ae6aa22aSVenugopal Iyer 		    NULL, &flags, NULL, NULL)) != DLADM_STATUS_OK) {
1013ae6aa22aSVenugopal Iyer 			return (status);
1014ae6aa22aSVenugopal Iyer 		}
1015ae6aa22aSVenugopal Iyer 		if ((flags & DLADM_OPT_ACTIVE) == 0)
1016ae6aa22aSVenugopal Iyer 			return (DLADM_STATUS_LINKINVAL);
1017ae6aa22aSVenugopal Iyer 	}
1018da14cebeSEric Cheng 
1019da14cebeSEric Cheng 	if (state->us_plot) {
1020da14cebeSEric Cheng 		if (!state->us_printheader) {
1021da14cebeSEric Cheng 			if (state->us_first) {
1022da14cebeSEric Cheng 				(void) printf("# Time");
1023da14cebeSEric Cheng 				state->us_first = B_FALSE;
1024da14cebeSEric Cheng 			}
1025da14cebeSEric Cheng 			(void) printf(" %s", usage->du_name);
1026da14cebeSEric Cheng 			if (usage->du_last) {
1027da14cebeSEric Cheng 				(void) printf("\n");
1028da14cebeSEric Cheng 				state->us_first = B_TRUE;
1029da14cebeSEric Cheng 				state->us_printheader = B_TRUE;
1030da14cebeSEric Cheng 			}
1031da14cebeSEric Cheng 		} else {
1032da14cebeSEric Cheng 			if (state->us_first) {
1033da14cebeSEric Cheng 				time = usage->du_etime;
1034da14cebeSEric Cheng 				(void) strftime(buf, sizeof (buf), "%T",
1035da14cebeSEric Cheng 				    localtime(&time));
1036da14cebeSEric Cheng 				state->us_first = B_FALSE;
1037da14cebeSEric Cheng 				(void) printf("%s", buf);
1038da14cebeSEric Cheng 			}
1039da14cebeSEric Cheng 			bw = (double)usage->du_bandwidth/1000;
1040da14cebeSEric Cheng 			(void) printf(" %.2f", bw);
1041da14cebeSEric Cheng 			if (usage->du_last) {
1042da14cebeSEric Cheng 				(void) printf("\n");
1043da14cebeSEric Cheng 				state->us_first = B_TRUE;
1044da14cebeSEric Cheng 			}
1045da14cebeSEric Cheng 		}
1046da14cebeSEric Cheng 		return (DLADM_STATUS_OK);
1047da14cebeSEric Cheng 	}
1048da14cebeSEric Cheng 
1049da14cebeSEric Cheng 	bzero(&ubuf, sizeof (ubuf));
1050da14cebeSEric Cheng 
1051da14cebeSEric Cheng 	(void) snprintf(ubuf.usage_l_link, sizeof (ubuf.usage_l_link), "%s",
1052da14cebeSEric Cheng 	    usage->du_name);
1053da14cebeSEric Cheng 	time = usage->du_stime;
1054da14cebeSEric Cheng 	(void) strftime(buf, sizeof (buf), "%T", localtime(&time));
1055da14cebeSEric Cheng 	(void) snprintf(ubuf.usage_l_stime, sizeof (ubuf.usage_l_stime), "%s",
1056da14cebeSEric Cheng 	    buf);
1057da14cebeSEric Cheng 	time = usage->du_etime;
1058da14cebeSEric Cheng 	(void) strftime(buf, sizeof (buf), "%T", localtime(&time));
1059da14cebeSEric Cheng 	(void) snprintf(ubuf.usage_l_etime, sizeof (ubuf.usage_l_etime), "%s",
1060da14cebeSEric Cheng 	    buf);
1061da14cebeSEric Cheng 	(void) snprintf(ubuf.usage_l_rbytes, sizeof (ubuf.usage_l_rbytes),
1062da14cebeSEric Cheng 	    "%llu", usage->du_rbytes);
1063da14cebeSEric Cheng 	(void) snprintf(ubuf.usage_l_obytes, sizeof (ubuf.usage_l_obytes),
1064da14cebeSEric Cheng 	    "%llu", usage->du_obytes);
1065da14cebeSEric Cheng 	(void) snprintf(ubuf.usage_l_bandwidth, sizeof (ubuf.usage_l_bandwidth),
1066da14cebeSEric Cheng 	    "%s Mbps", dladm_bw2str(usage->du_bandwidth, buf));
1067da14cebeSEric Cheng 
1068*8002d411SSowmini Varadhan 	ofmt_print(state->us_ofmt, &ubuf);
1069da14cebeSEric Cheng 	return (DLADM_STATUS_OK);
1070da14cebeSEric Cheng }
1071da14cebeSEric Cheng 
1072da14cebeSEric Cheng static int
1073da14cebeSEric Cheng show_usage_res(dladm_usage_t *usage, void *arg)
1074da14cebeSEric Cheng {
1075da14cebeSEric Cheng 	show_usage_state_t	*state = (show_usage_state_t *)arg;
1076da14cebeSEric Cheng 	char			buf[DLADM_STRSIZE];
1077da14cebeSEric Cheng 	usage_fields_buf_t	ubuf;
1078ae6aa22aSVenugopal Iyer 	dladm_status_t		status;
1079ae6aa22aSVenugopal Iyer 	uint32_t		flags;
1080ae6aa22aSVenugopal Iyer 
1081ae6aa22aSVenugopal Iyer 	/*
1082ae6aa22aSVenugopal Iyer 	 * Only show usage information for existing links unless '-a'
1083ae6aa22aSVenugopal Iyer 	 * is specified.
1084ae6aa22aSVenugopal Iyer 	 */
1085ae6aa22aSVenugopal Iyer 	if (!state->us_showall) {
1086ae6aa22aSVenugopal Iyer 		if ((status = dladm_name2info(handle, usage->du_name,
1087ae6aa22aSVenugopal Iyer 		    NULL, &flags, NULL, NULL)) != DLADM_STATUS_OK) {
1088ae6aa22aSVenugopal Iyer 			return (status);
1089ae6aa22aSVenugopal Iyer 		}
1090ae6aa22aSVenugopal Iyer 		if ((flags & DLADM_OPT_ACTIVE) == 0)
1091ae6aa22aSVenugopal Iyer 			return (DLADM_STATUS_LINKINVAL);
1092ae6aa22aSVenugopal Iyer 	}
1093da14cebeSEric Cheng 
1094da14cebeSEric Cheng 	bzero(&ubuf, sizeof (ubuf));
1095da14cebeSEric Cheng 
1096da14cebeSEric Cheng 	(void) snprintf(ubuf.usage_link, sizeof (ubuf.usage_link), "%s",
1097da14cebeSEric Cheng 	    usage->du_name);
1098da14cebeSEric Cheng 	(void) snprintf(ubuf.usage_duration, sizeof (ubuf.usage_duration),
1099da14cebeSEric Cheng 	    "%llu", usage->du_duration);
1100da14cebeSEric Cheng 	(void) snprintf(ubuf.usage_ipackets, sizeof (ubuf.usage_ipackets),
1101da14cebeSEric Cheng 	    "%llu", usage->du_ipackets);
1102da14cebeSEric Cheng 	(void) snprintf(ubuf.usage_rbytes, sizeof (ubuf.usage_rbytes),
1103da14cebeSEric Cheng 	    "%llu", usage->du_rbytes);
1104da14cebeSEric Cheng 	(void) snprintf(ubuf.usage_opackets, sizeof (ubuf.usage_opackets),
1105da14cebeSEric Cheng 	    "%llu", usage->du_opackets);
1106da14cebeSEric Cheng 	(void) snprintf(ubuf.usage_obytes, sizeof (ubuf.usage_obytes),
1107da14cebeSEric Cheng 	    "%llu", usage->du_obytes);
1108da14cebeSEric Cheng 	(void) snprintf(ubuf.usage_bandwidth, sizeof (ubuf.usage_bandwidth),
1109da14cebeSEric Cheng 	    "%s Mbps", dladm_bw2str(usage->du_bandwidth, buf));
1110da14cebeSEric Cheng 
1111*8002d411SSowmini Varadhan 	ofmt_print(state->us_ofmt, &ubuf);
1112da14cebeSEric Cheng 
1113da14cebeSEric Cheng 	return (DLADM_STATUS_OK);
1114da14cebeSEric Cheng }
1115da14cebeSEric Cheng 
1116da14cebeSEric Cheng static boolean_t
1117da14cebeSEric Cheng valid_formatspec(char *formatspec_str)
1118da14cebeSEric Cheng {
1119da14cebeSEric Cheng 	if (strcmp(formatspec_str, "gnuplot") == 0)
1120da14cebeSEric Cheng 		return (B_TRUE);
1121da14cebeSEric Cheng 	return (B_FALSE);
1122da14cebeSEric Cheng 
1123da14cebeSEric Cheng }
1124da14cebeSEric Cheng 
1125da14cebeSEric Cheng /*ARGSUSED*/
1126da14cebeSEric Cheng static void
1127da14cebeSEric Cheng do_show_usage(int argc, char *argv[], const char *use)
1128da14cebeSEric Cheng {
1129da14cebeSEric Cheng 	char			*file = NULL;
1130da14cebeSEric Cheng 	int			opt;
1131da14cebeSEric Cheng 	dladm_status_t		status;
1132da14cebeSEric Cheng 	boolean_t		d_arg = B_FALSE;
1133da14cebeSEric Cheng 	char			*stime = NULL;
1134da14cebeSEric Cheng 	char			*etime = NULL;
1135da14cebeSEric Cheng 	char			*resource = NULL;
1136da14cebeSEric Cheng 	show_usage_state_t	state;
1137da14cebeSEric Cheng 	boolean_t		o_arg = B_FALSE;
1138da14cebeSEric Cheng 	boolean_t		F_arg = B_FALSE;
1139da14cebeSEric Cheng 	char			*fields_str = NULL;
1140da14cebeSEric Cheng 	char			*formatspec_str = NULL;
1141da14cebeSEric Cheng 	char			*all_l_fields =
1142da14cebeSEric Cheng 	    "link,start,end,rbytes,obytes,bandwidth";
1143*8002d411SSowmini Varadhan 	ofmt_handle_t		ofmt;
1144*8002d411SSowmini Varadhan 	ofmt_status_t		oferr;
1145*8002d411SSowmini Varadhan 	uint_t			ofmtflags = 0;
1146da14cebeSEric Cheng 
1147da14cebeSEric Cheng 	bzero(&state, sizeof (show_usage_state_t));
1148*8002d411SSowmini Varadhan 	state.us_parsable = B_FALSE;
1149da14cebeSEric Cheng 	state.us_printheader = B_FALSE;
1150da14cebeSEric Cheng 	state.us_plot = B_FALSE;
1151da14cebeSEric Cheng 	state.us_first = B_TRUE;
1152da14cebeSEric Cheng 
1153ae6aa22aSVenugopal Iyer 	while ((opt = getopt_long(argc, argv, "das:e:o:f:F:",
1154ae6aa22aSVenugopal Iyer 	    usage_opts, NULL)) != -1) {
1155da14cebeSEric Cheng 		switch (opt) {
1156da14cebeSEric Cheng 		case 'd':
1157da14cebeSEric Cheng 			d_arg = B_TRUE;
1158da14cebeSEric Cheng 			break;
1159ae6aa22aSVenugopal Iyer 		case 'a':
1160ae6aa22aSVenugopal Iyer 			state.us_showall = B_TRUE;
1161da14cebeSEric Cheng 			break;
1162da14cebeSEric Cheng 		case 'f':
1163da14cebeSEric Cheng 			file = optarg;
1164da14cebeSEric Cheng 			break;
1165da14cebeSEric Cheng 		case 's':
1166da14cebeSEric Cheng 			stime = optarg;
1167da14cebeSEric Cheng 			break;
1168da14cebeSEric Cheng 		case 'e':
1169da14cebeSEric Cheng 			etime = optarg;
1170da14cebeSEric Cheng 			break;
1171da14cebeSEric Cheng 		case 'o':
1172da14cebeSEric Cheng 			o_arg = B_TRUE;
1173da14cebeSEric Cheng 			fields_str = optarg;
1174da14cebeSEric Cheng 			break;
1175da14cebeSEric Cheng 		case 'F':
1176ae6aa22aSVenugopal Iyer 			state.us_plot = F_arg = B_TRUE;
1177da14cebeSEric Cheng 			formatspec_str = optarg;
1178da14cebeSEric Cheng 			break;
1179da14cebeSEric Cheng 		default:
1180da14cebeSEric Cheng 			die_opterr(optopt, opt, use);
1181da14cebeSEric Cheng 			break;
1182da14cebeSEric Cheng 		}
1183da14cebeSEric Cheng 	}
1184da14cebeSEric Cheng 
1185da14cebeSEric Cheng 	if (file == NULL)
1186da14cebeSEric Cheng 		die("show-usage requires a file");
1187da14cebeSEric Cheng 
1188da14cebeSEric Cheng 	if (optind == (argc-1)) {
1189ae6aa22aSVenugopal Iyer 		uint32_t 	flags;
1190ae6aa22aSVenugopal Iyer 
1191da14cebeSEric Cheng 		resource = argv[optind];
1192ae6aa22aSVenugopal Iyer 		if (!state.us_showall &&
1193ae6aa22aSVenugopal Iyer 		    (((status = dladm_name2info(handle, resource, NULL, &flags,
1194ae6aa22aSVenugopal Iyer 		    NULL, NULL)) != DLADM_STATUS_OK) ||
1195ae6aa22aSVenugopal Iyer 		    ((flags & DLADM_OPT_ACTIVE) == 0))) {
1196ae6aa22aSVenugopal Iyer 			die("invalid link: '%s'", resource);
1197ae6aa22aSVenugopal Iyer 		}
1198da14cebeSEric Cheng 	}
1199da14cebeSEric Cheng 
1200ae6aa22aSVenugopal Iyer 	if (F_arg && d_arg)
1201ae6aa22aSVenugopal Iyer 		die("incompatible -d and -F options");
1202da14cebeSEric Cheng 
1203da14cebeSEric Cheng 	if (F_arg && valid_formatspec(formatspec_str) == B_FALSE)
1204da14cebeSEric Cheng 		die("Format specifier %s not supported", formatspec_str);
1205da14cebeSEric Cheng 
1206*8002d411SSowmini Varadhan 	if (state.us_parsable)
1207*8002d411SSowmini Varadhan 		ofmtflags |= OFMT_PARSABLE;
1208*8002d411SSowmini Varadhan 
1209*8002d411SSowmini Varadhan 	if (resource == NULL && stime == NULL && etime == NULL) {
1210*8002d411SSowmini Varadhan 		oferr = ofmt_open(fields_str, usage_fields, ofmtflags, 0,
1211*8002d411SSowmini Varadhan 		    &ofmt);
1212*8002d411SSowmini Varadhan 	} else {
1213*8002d411SSowmini Varadhan 		if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0))
1214*8002d411SSowmini Varadhan 			fields_str = all_l_fields;
1215*8002d411SSowmini Varadhan 		oferr = ofmt_open(fields_str, usage_l_fields, ofmtflags, 0,
1216*8002d411SSowmini Varadhan 		    &ofmt);
1217*8002d411SSowmini Varadhan 
1218*8002d411SSowmini Varadhan 	}
1219*8002d411SSowmini Varadhan 	dladm_ofmt_check(oferr, state.us_parsable, ofmt);
1220*8002d411SSowmini Varadhan 	state.us_ofmt = ofmt;
1221*8002d411SSowmini Varadhan 
1222da14cebeSEric Cheng 	if (d_arg) {
1223da14cebeSEric Cheng 		/* Print log dates */
1224da14cebeSEric Cheng 		status = dladm_usage_dates(show_usage_date,
1225da14cebeSEric Cheng 		    DLADM_LOGTYPE_LINK, file, resource, &state);
1226da14cebeSEric Cheng 	} else if (resource == NULL && stime == NULL && etime == NULL &&
1227ae6aa22aSVenugopal Iyer 	    !F_arg) {
1228da14cebeSEric Cheng 		/* Print summary */
1229da14cebeSEric Cheng 		status = dladm_usage_summary(show_usage_res,
1230da14cebeSEric Cheng 		    DLADM_LOGTYPE_LINK, file, &state);
1231da14cebeSEric Cheng 	} else if (resource != NULL) {
1232da14cebeSEric Cheng 		/* Print log entries for named resource */
1233da14cebeSEric Cheng 		status = dladm_walk_usage_res(show_usage_time,
1234da14cebeSEric Cheng 		    DLADM_LOGTYPE_LINK, file, resource, stime, etime, &state);
1235da14cebeSEric Cheng 	} else {
1236da14cebeSEric Cheng 		/* Print time and information for each link */
1237da14cebeSEric Cheng 		status = dladm_walk_usage_time(show_usage_time,
1238da14cebeSEric Cheng 		    DLADM_LOGTYPE_LINK, file, stime, etime, &state);
1239da14cebeSEric Cheng 	}
1240da14cebeSEric Cheng 
1241da14cebeSEric Cheng 	if (status != DLADM_STATUS_OK)
1242da14cebeSEric Cheng 		die_dlerr(status, "show-usage");
1243*8002d411SSowmini Varadhan 	ofmt_close(ofmt);
1244da14cebeSEric Cheng }
1245da14cebeSEric Cheng 
12467c478bd9Sstevel@tonic-gate static void
12478d5c46e6Sam223141 do_create_aggr(int argc, char *argv[], const char *use)
12487c478bd9Sstevel@tonic-gate {
12497c478bd9Sstevel@tonic-gate 	char			option;
1250d62bc4baSyz147064 	int			key = 0;
12517c478bd9Sstevel@tonic-gate 	uint32_t		policy = AGGR_POLICY_L4;
12527c478bd9Sstevel@tonic-gate 	aggr_lacp_mode_t	lacp_mode = AGGR_LACP_OFF;
12537c478bd9Sstevel@tonic-gate 	aggr_lacp_timer_t	lacp_timer = AGGR_LACP_TIMER_SHORT;
1254f595a68aSyz147064 	dladm_aggr_port_attr_db_t	port[MAXPORT];
1255d62bc4baSyz147064 	uint_t			n, ndev, nlink;
12567c478bd9Sstevel@tonic-gate 	uint8_t			mac_addr[ETHERADDRL];
12577c478bd9Sstevel@tonic-gate 	boolean_t		mac_addr_fixed = B_FALSE;
12587c478bd9Sstevel@tonic-gate 	boolean_t		P_arg = B_FALSE;
12597c478bd9Sstevel@tonic-gate 	boolean_t		l_arg = B_FALSE;
12607c478bd9Sstevel@tonic-gate 	boolean_t		u_arg = B_FALSE;
12617c478bd9Sstevel@tonic-gate 	boolean_t		T_arg = B_FALSE;
1262d62bc4baSyz147064 	uint32_t		flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
12637c478bd9Sstevel@tonic-gate 	char			*altroot = NULL;
1264d62bc4baSyz147064 	char			name[MAXLINKNAMELEN];
1265d62bc4baSyz147064 	char			*devs[MAXPORT];
1266d62bc4baSyz147064 	char			*links[MAXPORT];
1267f595a68aSyz147064 	dladm_status_t		status;
1268da14cebeSEric Cheng 	dladm_status_t		pstatus;
126963a6526dSMichael Lim 	char			propstr[DLADM_STRSIZE];
1270da14cebeSEric Cheng 	dladm_arg_list_t	*proplist = NULL;
1271da14cebeSEric Cheng 	int			i;
1272da14cebeSEric Cheng 	datalink_id_t		linkid;
12737c478bd9Sstevel@tonic-gate 
1274d62bc4baSyz147064 	ndev = nlink = opterr = 0;
127563a6526dSMichael Lim 	bzero(propstr, DLADM_STRSIZE);
127663a6526dSMichael Lim 
1277da14cebeSEric Cheng 	while ((option = getopt_long(argc, argv, ":d:l:L:P:R:tfu:T:p:",
1278d62bc4baSyz147064 	    lopts, NULL)) != -1) {
12797c478bd9Sstevel@tonic-gate 		switch (option) {
12807c478bd9Sstevel@tonic-gate 		case 'd':
1281d62bc4baSyz147064 			if (ndev + nlink >= MAXPORT)
1282d62bc4baSyz147064 				die("too many ports specified");
12837c478bd9Sstevel@tonic-gate 
1284d62bc4baSyz147064 			devs[ndev++] = optarg;
12857c478bd9Sstevel@tonic-gate 			break;
12867c478bd9Sstevel@tonic-gate 		case 'P':
128733343a97Smeem 			if (P_arg)
128833343a97Smeem 				die_optdup(option);
12897c478bd9Sstevel@tonic-gate 
12907c478bd9Sstevel@tonic-gate 			P_arg = B_TRUE;
1291f595a68aSyz147064 			if (!dladm_aggr_str2policy(optarg, &policy))
129233343a97Smeem 				die("invalid policy '%s'", optarg);
12937c478bd9Sstevel@tonic-gate 			break;
12947c478bd9Sstevel@tonic-gate 		case 'u':
129533343a97Smeem 			if (u_arg)
129633343a97Smeem 				die_optdup(option);
12977c478bd9Sstevel@tonic-gate 
12987c478bd9Sstevel@tonic-gate 			u_arg = B_TRUE;
1299f595a68aSyz147064 			if (!dladm_aggr_str2macaddr(optarg, &mac_addr_fixed,
130033343a97Smeem 			    mac_addr))
130133343a97Smeem 				die("invalid MAC address '%s'", optarg);
13027c478bd9Sstevel@tonic-gate 			break;
13037c478bd9Sstevel@tonic-gate 		case 'l':
1304d62bc4baSyz147064 			if (isdigit(optarg[strlen(optarg) - 1])) {
1305d62bc4baSyz147064 
1306d62bc4baSyz147064 				/*
1307d62bc4baSyz147064 				 * Ended with digit, possibly a link name.
1308d62bc4baSyz147064 				 */
1309d62bc4baSyz147064 				if (ndev + nlink >= MAXPORT)
1310d62bc4baSyz147064 					die("too many ports specified");
1311d62bc4baSyz147064 
1312d62bc4baSyz147064 				links[nlink++] = optarg;
1313d62bc4baSyz147064 				break;
1314d62bc4baSyz147064 			}
1315d62bc4baSyz147064 			/* FALLTHROUGH */
1316d62bc4baSyz147064 		case 'L':
131733343a97Smeem 			if (l_arg)
131833343a97Smeem 				die_optdup(option);
13197c478bd9Sstevel@tonic-gate 
13207c478bd9Sstevel@tonic-gate 			l_arg = B_TRUE;
1321f595a68aSyz147064 			if (!dladm_aggr_str2lacpmode(optarg, &lacp_mode))
132233343a97Smeem 				die("invalid LACP mode '%s'", optarg);
13237c478bd9Sstevel@tonic-gate 			break;
13247c478bd9Sstevel@tonic-gate 		case 'T':
132533343a97Smeem 			if (T_arg)
132633343a97Smeem 				die_optdup(option);
13277c478bd9Sstevel@tonic-gate 
13287c478bd9Sstevel@tonic-gate 			T_arg = B_TRUE;
1329f595a68aSyz147064 			if (!dladm_aggr_str2lacptimer(optarg, &lacp_timer))
133033343a97Smeem 				die("invalid LACP timer value '%s'", optarg);
13317c478bd9Sstevel@tonic-gate 			break;
13327c478bd9Sstevel@tonic-gate 		case 't':
1333d62bc4baSyz147064 			flags &= ~DLADM_OPT_PERSIST;
1334d62bc4baSyz147064 			break;
1335d62bc4baSyz147064 		case 'f':
1336d62bc4baSyz147064 			flags |= DLADM_OPT_FORCE;
13377c478bd9Sstevel@tonic-gate 			break;
13387c478bd9Sstevel@tonic-gate 		case 'R':
13397c478bd9Sstevel@tonic-gate 			altroot = optarg;
13407c478bd9Sstevel@tonic-gate 			break;
1341da14cebeSEric Cheng 		case 'p':
134263a6526dSMichael Lim 			(void) strlcat(propstr, optarg, DLADM_STRSIZE);
134363a6526dSMichael Lim 			if (strlcat(propstr, ",", DLADM_STRSIZE) >=
134463a6526dSMichael Lim 			    DLADM_STRSIZE)
134563a6526dSMichael Lim 				die("property list too long '%s'", propstr);
1346da14cebeSEric Cheng 			break;
134763a6526dSMichael Lim 
13487c478bd9Sstevel@tonic-gate 		default:
13498d5c46e6Sam223141 			die_opterr(optopt, option, use);
135033343a97Smeem 			break;
13517c478bd9Sstevel@tonic-gate 		}
13527c478bd9Sstevel@tonic-gate 	}
13537c478bd9Sstevel@tonic-gate 
1354d62bc4baSyz147064 	if (ndev + nlink == 0)
13557c478bd9Sstevel@tonic-gate 		usage();
13567c478bd9Sstevel@tonic-gate 
1357d62bc4baSyz147064 	/* get key value or the aggregation name (required last argument) */
13587c478bd9Sstevel@tonic-gate 	if (optind != (argc-1))
13597c478bd9Sstevel@tonic-gate 		usage();
13607c478bd9Sstevel@tonic-gate 
1361d62bc4baSyz147064 	if (!str2int(argv[optind], &key)) {
1362d62bc4baSyz147064 		if (strlcpy(name, argv[optind], MAXLINKNAMELEN) >=
1363d62bc4baSyz147064 		    MAXLINKNAMELEN) {
1364d62bc4baSyz147064 			die("link name too long '%s'", argv[optind]);
1365d62bc4baSyz147064 		}
13667c478bd9Sstevel@tonic-gate 
1367d62bc4baSyz147064 		if (!dladm_valid_linkname(name))
1368d62bc4baSyz147064 			die("invalid link name '%s'", argv[optind]);
1369d62bc4baSyz147064 	} else {
1370d62bc4baSyz147064 		(void) snprintf(name, MAXLINKNAMELEN, "aggr%d", key);
1371d62bc4baSyz147064 	}
1372d62bc4baSyz147064 
1373d62bc4baSyz147064 	if (altroot != NULL)
1374d62bc4baSyz147064 		altroot_cmd(altroot, argc, argv);
1375d62bc4baSyz147064 
1376d62bc4baSyz147064 	for (n = 0; n < ndev; n++) {
13774ac67f02SAnurag S. Maskey 		if ((status = dladm_dev2linkid(handle, devs[n],
13784ac67f02SAnurag S. Maskey 		    &port[n].lp_linkid)) != DLADM_STATUS_OK) {
13794ac67f02SAnurag S. Maskey 			die_dlerr(status, "invalid dev name '%s'", devs[n]);
1380d62bc4baSyz147064 		}
1381d62bc4baSyz147064 	}
1382d62bc4baSyz147064 
1383d62bc4baSyz147064 	for (n = 0; n < nlink; n++) {
13844ac67f02SAnurag S. Maskey 		if ((status = dladm_name2info(handle, links[n],
13854ac67f02SAnurag S. Maskey 		    &port[ndev + n].lp_linkid, NULL, NULL, NULL)) !=
13864ac67f02SAnurag S. Maskey 		    DLADM_STATUS_OK) {
13874ac67f02SAnurag S. Maskey 			die_dlerr(status, "invalid link name '%s'", links[n]);
1388d62bc4baSyz147064 		}
1389d62bc4baSyz147064 	}
1390d62bc4baSyz147064 
13914ac67f02SAnurag S. Maskey 	status = dladm_aggr_create(handle, name, key, ndev + nlink, port,
13924ac67f02SAnurag S. Maskey 	    policy, mac_addr_fixed, (const uchar_t *)mac_addr, lacp_mode,
1393d62bc4baSyz147064 	    lacp_timer, flags);
1394da14cebeSEric Cheng 	if (status != DLADM_STATUS_OK)
1395da14cebeSEric Cheng 		goto done;
1396da14cebeSEric Cheng 
139763a6526dSMichael Lim 	if (dladm_parse_link_props(propstr, &proplist, B_FALSE)
139863a6526dSMichael Lim 	    != DLADM_STATUS_OK)
139963a6526dSMichael Lim 		die("invalid aggregation property");
140063a6526dSMichael Lim 
1401da14cebeSEric Cheng 	if (proplist == NULL)
1402da14cebeSEric Cheng 		return;
1403da14cebeSEric Cheng 
14044ac67f02SAnurag S. Maskey 	status = dladm_name2info(handle, name, &linkid, NULL, NULL, NULL);
1405da14cebeSEric Cheng 	if (status != DLADM_STATUS_OK)
1406da14cebeSEric Cheng 		goto done;
1407da14cebeSEric Cheng 
1408da14cebeSEric Cheng 	for (i = 0; i < proplist->al_count; i++) {
1409da14cebeSEric Cheng 		dladm_arg_info_t	*aip = &proplist->al_info[i];
1410da14cebeSEric Cheng 
14114ac67f02SAnurag S. Maskey 		pstatus = dladm_set_linkprop(handle, linkid, aip->ai_name,
1412da14cebeSEric Cheng 		    aip->ai_val, aip->ai_count, flags);
1413da14cebeSEric Cheng 
1414da14cebeSEric Cheng 		if (pstatus != DLADM_STATUS_OK) {
1415da14cebeSEric Cheng 			die_dlerr(pstatus,
1416da14cebeSEric Cheng 			    "aggr creation succeeded but "
1417da14cebeSEric Cheng 			    "could not set property '%s'", aip->ai_name);
1418da14cebeSEric Cheng 		}
1419da14cebeSEric Cheng 	}
1420d62bc4baSyz147064 done:
1421da14cebeSEric Cheng 	dladm_free_props(proplist);
1422d62bc4baSyz147064 	if (status != DLADM_STATUS_OK) {
1423d62bc4baSyz147064 		if (status == DLADM_STATUS_NONOTIF) {
1424d62bc4baSyz147064 			die_dlerr(status, "not all links have link up/down "
1425d62bc4baSyz147064 			    "detection; must use -f (see dladm(1M))\n");
1426d62bc4baSyz147064 		} else {
1427f595a68aSyz147064 			die_dlerr(status, "create operation failed");
14287c478bd9Sstevel@tonic-gate 		}
1429d62bc4baSyz147064 	}
1430d62bc4baSyz147064 }
1431d62bc4baSyz147064 
1432d62bc4baSyz147064 /*
1433d62bc4baSyz147064  * arg is either the key or the aggr name. Validate it and convert it to
1434d62bc4baSyz147064  * the linkid if altroot is NULL.
1435d62bc4baSyz147064  */
1436d62bc4baSyz147064 static dladm_status_t
1437d62bc4baSyz147064 i_dladm_aggr_get_linkid(const char *altroot, const char *arg,
1438d62bc4baSyz147064     datalink_id_t *linkidp, uint32_t flags)
1439d62bc4baSyz147064 {
1440d62bc4baSyz147064 	int		key = 0;
1441d62bc4baSyz147064 	char		*aggr = NULL;
1442d62bc4baSyz147064 	dladm_status_t	status;
1443d62bc4baSyz147064 
1444d62bc4baSyz147064 	if (!str2int(arg, &key))
1445d62bc4baSyz147064 		aggr = (char *)arg;
1446d62bc4baSyz147064 
1447d62bc4baSyz147064 	if (aggr == NULL && key == 0)
1448d62bc4baSyz147064 		return (DLADM_STATUS_LINKINVAL);
1449d62bc4baSyz147064 
1450d62bc4baSyz147064 	if (altroot != NULL)
1451d62bc4baSyz147064 		return (DLADM_STATUS_OK);
1452d62bc4baSyz147064 
1453d62bc4baSyz147064 	if (aggr != NULL) {
14544ac67f02SAnurag S. Maskey 		status = dladm_name2info(handle, aggr, linkidp, NULL, NULL,
14554ac67f02SAnurag S. Maskey 		    NULL);
1456d62bc4baSyz147064 	} else {
14574ac67f02SAnurag S. Maskey 		status = dladm_key2linkid(handle, key, linkidp, flags);
1458d62bc4baSyz147064 	}
1459d62bc4baSyz147064 
1460d62bc4baSyz147064 	return (status);
1461d62bc4baSyz147064 }
14627c478bd9Sstevel@tonic-gate 
14637c478bd9Sstevel@tonic-gate static void
14648d5c46e6Sam223141 do_delete_aggr(int argc, char *argv[], const char *use)
14657c478bd9Sstevel@tonic-gate {
14667c478bd9Sstevel@tonic-gate 	char			option;
14677c478bd9Sstevel@tonic-gate 	char			*altroot = NULL;
1468d62bc4baSyz147064 	uint32_t		flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
1469f595a68aSyz147064 	dladm_status_t		status;
1470d62bc4baSyz147064 	datalink_id_t		linkid;
14717c478bd9Sstevel@tonic-gate 
14727c478bd9Sstevel@tonic-gate 	opterr = 0;
1473d62bc4baSyz147064 	while ((option = getopt_long(argc, argv, ":R:t", lopts, NULL)) != -1) {
14747c478bd9Sstevel@tonic-gate 		switch (option) {
14757c478bd9Sstevel@tonic-gate 		case 't':
1476d62bc4baSyz147064 			flags &= ~DLADM_OPT_PERSIST;
14777c478bd9Sstevel@tonic-gate 			break;
14787c478bd9Sstevel@tonic-gate 		case 'R':
14797c478bd9Sstevel@tonic-gate 			altroot = optarg;
14807c478bd9Sstevel@tonic-gate 			break;
14817c478bd9Sstevel@tonic-gate 		default:
14828d5c46e6Sam223141 			die_opterr(optopt, option, use);
14837c478bd9Sstevel@tonic-gate 			break;
14847c478bd9Sstevel@tonic-gate 		}
14857c478bd9Sstevel@tonic-gate 	}
14867c478bd9Sstevel@tonic-gate 
1487d62bc4baSyz147064 	/* get key value or the aggregation name (required last argument) */
14887c478bd9Sstevel@tonic-gate 	if (optind != (argc-1))
14897c478bd9Sstevel@tonic-gate 		usage();
14907c478bd9Sstevel@tonic-gate 
1491d62bc4baSyz147064 	status = i_dladm_aggr_get_linkid(altroot, argv[optind], &linkid, flags);
1492d62bc4baSyz147064 	if (status != DLADM_STATUS_OK)
1493d62bc4baSyz147064 		goto done;
14947c478bd9Sstevel@tonic-gate 
1495d62bc4baSyz147064 	if (altroot != NULL)
1496d62bc4baSyz147064 		altroot_cmd(altroot, argc, argv);
1497d62bc4baSyz147064 
14984ac67f02SAnurag S. Maskey 	status = dladm_aggr_delete(handle, linkid, flags);
1499d62bc4baSyz147064 done:
1500f595a68aSyz147064 	if (status != DLADM_STATUS_OK)
1501f595a68aSyz147064 		die_dlerr(status, "delete operation failed");
15027c478bd9Sstevel@tonic-gate }
15037c478bd9Sstevel@tonic-gate 
15047c478bd9Sstevel@tonic-gate static void
15058d5c46e6Sam223141 do_add_aggr(int argc, char *argv[], const char *use)
15067c478bd9Sstevel@tonic-gate {
15077c478bd9Sstevel@tonic-gate 	char			option;
1508d62bc4baSyz147064 	uint_t			n, ndev, nlink;
15097c478bd9Sstevel@tonic-gate 	char			*altroot = NULL;
1510d62bc4baSyz147064 	uint32_t		flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
1511d62bc4baSyz147064 	datalink_id_t		linkid;
1512f595a68aSyz147064 	dladm_status_t		status;
1513d62bc4baSyz147064 	dladm_aggr_port_attr_db_t	port[MAXPORT];
1514d62bc4baSyz147064 	char			*devs[MAXPORT];
1515d62bc4baSyz147064 	char			*links[MAXPORT];
15167c478bd9Sstevel@tonic-gate 
1517d62bc4baSyz147064 	ndev = nlink = opterr = 0;
1518d62bc4baSyz147064 	while ((option = getopt_long(argc, argv, ":d:l:R:tf", lopts,
15197c478bd9Sstevel@tonic-gate 	    NULL)) != -1) {
15207c478bd9Sstevel@tonic-gate 		switch (option) {
15217c478bd9Sstevel@tonic-gate 		case 'd':
1522d62bc4baSyz147064 			if (ndev + nlink >= MAXPORT)
1523d62bc4baSyz147064 				die("too many ports specified");
15247c478bd9Sstevel@tonic-gate 
1525d62bc4baSyz147064 			devs[ndev++] = optarg;
1526d62bc4baSyz147064 			break;
1527d62bc4baSyz147064 		case 'l':
1528d62bc4baSyz147064 			if (ndev + nlink >= MAXPORT)
1529d62bc4baSyz147064 				die("too many ports specified");
153033343a97Smeem 
1531d62bc4baSyz147064 			links[nlink++] = optarg;
15327c478bd9Sstevel@tonic-gate 			break;
15337c478bd9Sstevel@tonic-gate 		case 't':
1534d62bc4baSyz147064 			flags &= ~DLADM_OPT_PERSIST;
1535d62bc4baSyz147064 			break;
1536d62bc4baSyz147064 		case 'f':
1537d62bc4baSyz147064 			flags |= DLADM_OPT_FORCE;
15387c478bd9Sstevel@tonic-gate 			break;
15397c478bd9Sstevel@tonic-gate 		case 'R':
15407c478bd9Sstevel@tonic-gate 			altroot = optarg;
15417c478bd9Sstevel@tonic-gate 			break;
15427c478bd9Sstevel@tonic-gate 		default:
15438d5c46e6Sam223141 			die_opterr(optopt, option, use);
154433343a97Smeem 			break;
15457c478bd9Sstevel@tonic-gate 		}
15467c478bd9Sstevel@tonic-gate 	}
15477c478bd9Sstevel@tonic-gate 
1548d62bc4baSyz147064 	if (ndev + nlink == 0)
15497c478bd9Sstevel@tonic-gate 		usage();
15507c478bd9Sstevel@tonic-gate 
1551d62bc4baSyz147064 	/* get key value or the aggregation name (required last argument) */
15527c478bd9Sstevel@tonic-gate 	if (optind != (argc-1))
15537c478bd9Sstevel@tonic-gate 		usage();
15547c478bd9Sstevel@tonic-gate 
1555d62bc4baSyz147064 	if ((status = i_dladm_aggr_get_linkid(altroot, argv[optind], &linkid,
1556d62bc4baSyz147064 	    flags & (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST))) !=
1557d62bc4baSyz147064 	    DLADM_STATUS_OK) {
1558d62bc4baSyz147064 		goto done;
1559d62bc4baSyz147064 	}
15607c478bd9Sstevel@tonic-gate 
1561d62bc4baSyz147064 	if (altroot != NULL)
1562d62bc4baSyz147064 		altroot_cmd(altroot, argc, argv);
1563d62bc4baSyz147064 
1564d62bc4baSyz147064 	for (n = 0; n < ndev; n++) {
15654ac67f02SAnurag S. Maskey 		if ((status = dladm_dev2linkid(handle, devs[n],
15664ac67f02SAnurag S. Maskey 		    &(port[n].lp_linkid))) != DLADM_STATUS_OK) {
15674ac67f02SAnurag S. Maskey 			die_dlerr(status, "invalid <dev> '%s'", devs[n]);
1568d62bc4baSyz147064 		}
1569d62bc4baSyz147064 	}
1570d62bc4baSyz147064 
1571d62bc4baSyz147064 	for (n = 0; n < nlink; n++) {
15724ac67f02SAnurag S. Maskey 		if ((status = dladm_name2info(handle, links[n],
15734ac67f02SAnurag S. Maskey 		    &port[n + ndev].lp_linkid, NULL, NULL, NULL)) !=
15744ac67f02SAnurag S. Maskey 		    DLADM_STATUS_OK) {
15754ac67f02SAnurag S. Maskey 			die_dlerr(status, "invalid <link> '%s'", links[n]);
1576d62bc4baSyz147064 		}
1577d62bc4baSyz147064 	}
1578d62bc4baSyz147064 
15794ac67f02SAnurag S. Maskey 	status = dladm_aggr_add(handle, linkid, ndev + nlink, port, flags);
1580d62bc4baSyz147064 done:
1581f595a68aSyz147064 	if (status != DLADM_STATUS_OK) {
1582219a2a31Shl157128 		/*
1583f595a68aSyz147064 		 * checking DLADM_STATUS_NOTSUP is a temporary workaround
1584219a2a31Shl157128 		 * and should be removed once 6399681 is fixed.
1585219a2a31Shl157128 		 */
1586f595a68aSyz147064 		if (status == DLADM_STATUS_NOTSUP) {
1587219a2a31Shl157128 			(void) fprintf(stderr,
1588219a2a31Shl157128 			    gettext("%s: add operation failed: %s\n"),
1589219a2a31Shl157128 			    progname,
1590d62bc4baSyz147064 			    gettext("link capabilities don't match"));
15914ac67f02SAnurag S. Maskey 			dladm_close(handle);
1592219a2a31Shl157128 			exit(ENOTSUP);
1593d62bc4baSyz147064 		} else if (status == DLADM_STATUS_NONOTIF) {
1594d62bc4baSyz147064 			die_dlerr(status, "not all links have link up/down "
1595d62bc4baSyz147064 			    "detection; must use -f (see dladm(1M))\n");
1596d62bc4baSyz147064 		} else {
1597f595a68aSyz147064 			die_dlerr(status, "add operation failed");
15987c478bd9Sstevel@tonic-gate 		}
15997c478bd9Sstevel@tonic-gate 	}
1600d62bc4baSyz147064 }
16017c478bd9Sstevel@tonic-gate 
16027c478bd9Sstevel@tonic-gate static void
16038d5c46e6Sam223141 do_remove_aggr(int argc, char *argv[], const char *use)
16047c478bd9Sstevel@tonic-gate {
16057c478bd9Sstevel@tonic-gate 	char				option;
1606f595a68aSyz147064 	dladm_aggr_port_attr_db_t	port[MAXPORT];
1607d62bc4baSyz147064 	uint_t				n, ndev, nlink;
1608d62bc4baSyz147064 	char				*devs[MAXPORT];
1609d62bc4baSyz147064 	char				*links[MAXPORT];
16107c478bd9Sstevel@tonic-gate 	char				*altroot = NULL;
1611d62bc4baSyz147064 	uint32_t			flags;
1612d62bc4baSyz147064 	datalink_id_t			linkid;
1613f595a68aSyz147064 	dladm_status_t			status;
16147c478bd9Sstevel@tonic-gate 
1615d62bc4baSyz147064 	flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
1616d62bc4baSyz147064 	ndev = nlink = opterr = 0;
1617d62bc4baSyz147064 	while ((option = getopt_long(argc, argv, ":d:l:R:t",
1618d62bc4baSyz147064 	    lopts, NULL)) != -1) {
16197c478bd9Sstevel@tonic-gate 		switch (option) {
16207c478bd9Sstevel@tonic-gate 		case 'd':
1621d62bc4baSyz147064 			if (ndev + nlink >= MAXPORT)
1622d62bc4baSyz147064 				die("too many ports specified");
16237c478bd9Sstevel@tonic-gate 
1624d62bc4baSyz147064 			devs[ndev++] = optarg;
1625d62bc4baSyz147064 			break;
1626d62bc4baSyz147064 		case 'l':
1627d62bc4baSyz147064 			if (ndev + nlink >= MAXPORT)
1628d62bc4baSyz147064 				die("too many ports specified");
162933343a97Smeem 
1630d62bc4baSyz147064 			links[nlink++] = optarg;
16317c478bd9Sstevel@tonic-gate 			break;
16327c478bd9Sstevel@tonic-gate 		case 't':
1633d62bc4baSyz147064 			flags &= ~DLADM_OPT_PERSIST;
16347c478bd9Sstevel@tonic-gate 			break;
16357c478bd9Sstevel@tonic-gate 		case 'R':
16367c478bd9Sstevel@tonic-gate 			altroot = optarg;
16377c478bd9Sstevel@tonic-gate 			break;
16387c478bd9Sstevel@tonic-gate 		default:
16398d5c46e6Sam223141 			die_opterr(optopt, option, use);
164033343a97Smeem 			break;
16417c478bd9Sstevel@tonic-gate 		}
16427c478bd9Sstevel@tonic-gate 	}
16437c478bd9Sstevel@tonic-gate 
1644d62bc4baSyz147064 	if (ndev + nlink == 0)
16457c478bd9Sstevel@tonic-gate 		usage();
16467c478bd9Sstevel@tonic-gate 
1647d62bc4baSyz147064 	/* get key value or the aggregation name (required last argument) */
16487c478bd9Sstevel@tonic-gate 	if (optind != (argc-1))
16497c478bd9Sstevel@tonic-gate 		usage();
16507c478bd9Sstevel@tonic-gate 
1651d62bc4baSyz147064 	status = i_dladm_aggr_get_linkid(altroot, argv[optind], &linkid, flags);
1652d62bc4baSyz147064 	if (status != DLADM_STATUS_OK)
1653d62bc4baSyz147064 		goto done;
16547c478bd9Sstevel@tonic-gate 
1655d62bc4baSyz147064 	if (altroot != NULL)
1656d62bc4baSyz147064 		altroot_cmd(altroot, argc, argv);
1657d62bc4baSyz147064 
1658d62bc4baSyz147064 	for (n = 0; n < ndev; n++) {
16594ac67f02SAnurag S. Maskey 		if ((status = dladm_dev2linkid(handle, devs[n],
16604ac67f02SAnurag S. Maskey 		    &(port[n].lp_linkid))) != DLADM_STATUS_OK) {
16614ac67f02SAnurag S. Maskey 			die_dlerr(status, "invalid <dev> '%s'", devs[n]);
1662d62bc4baSyz147064 		}
1663d62bc4baSyz147064 	}
1664d62bc4baSyz147064 
1665d62bc4baSyz147064 	for (n = 0; n < nlink; n++) {
16664ac67f02SAnurag S. Maskey 		if ((status = dladm_name2info(handle, links[n],
16674ac67f02SAnurag S. Maskey 		    &port[n + ndev].lp_linkid, NULL, NULL, NULL)) !=
16684ac67f02SAnurag S. Maskey 		    DLADM_STATUS_OK) {
16694ac67f02SAnurag S. Maskey 			die_dlerr(status, "invalid <link> '%s'", links[n]);
1670d62bc4baSyz147064 		}
1671d62bc4baSyz147064 	}
1672d62bc4baSyz147064 
16734ac67f02SAnurag S. Maskey 	status = dladm_aggr_remove(handle, linkid, ndev + nlink, port, flags);
1674d62bc4baSyz147064 done:
1675f595a68aSyz147064 	if (status != DLADM_STATUS_OK)
1676f595a68aSyz147064 		die_dlerr(status, "remove operation failed");
16777c478bd9Sstevel@tonic-gate }
16787c478bd9Sstevel@tonic-gate 
16797c478bd9Sstevel@tonic-gate static void
16808d5c46e6Sam223141 do_modify_aggr(int argc, char *argv[], const char *use)
16817c478bd9Sstevel@tonic-gate {
16827c478bd9Sstevel@tonic-gate 	char			option;
16837c478bd9Sstevel@tonic-gate 	uint32_t		policy = AGGR_POLICY_L4;
16847c478bd9Sstevel@tonic-gate 	aggr_lacp_mode_t	lacp_mode = AGGR_LACP_OFF;
16857c478bd9Sstevel@tonic-gate 	aggr_lacp_timer_t	lacp_timer = AGGR_LACP_TIMER_SHORT;
16867c478bd9Sstevel@tonic-gate 	uint8_t			mac_addr[ETHERADDRL];
16877c478bd9Sstevel@tonic-gate 	boolean_t		mac_addr_fixed = B_FALSE;
16887c478bd9Sstevel@tonic-gate 	uint8_t			modify_mask = 0;
16897c478bd9Sstevel@tonic-gate 	char			*altroot = NULL;
1690d62bc4baSyz147064 	uint32_t		flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
1691d62bc4baSyz147064 	datalink_id_t		linkid;
1692f595a68aSyz147064 	dladm_status_t		status;
16937c478bd9Sstevel@tonic-gate 
16947c478bd9Sstevel@tonic-gate 	opterr = 0;
1695d62bc4baSyz147064 	while ((option = getopt_long(argc, argv, ":L:l:P:R:tu:T:", lopts,
16967c478bd9Sstevel@tonic-gate 	    NULL)) != -1) {
16977c478bd9Sstevel@tonic-gate 		switch (option) {
16987c478bd9Sstevel@tonic-gate 		case 'P':
1699f595a68aSyz147064 			if (modify_mask & DLADM_AGGR_MODIFY_POLICY)
170033343a97Smeem 				die_optdup(option);
17017c478bd9Sstevel@tonic-gate 
1702f595a68aSyz147064 			modify_mask |= DLADM_AGGR_MODIFY_POLICY;
17037c478bd9Sstevel@tonic-gate 
1704f595a68aSyz147064 			if (!dladm_aggr_str2policy(optarg, &policy))
170533343a97Smeem 				die("invalid policy '%s'", optarg);
17067c478bd9Sstevel@tonic-gate 			break;
17077c478bd9Sstevel@tonic-gate 		case 'u':
1708f595a68aSyz147064 			if (modify_mask & DLADM_AGGR_MODIFY_MAC)
170933343a97Smeem 				die_optdup(option);
17107c478bd9Sstevel@tonic-gate 
1711f595a68aSyz147064 			modify_mask |= DLADM_AGGR_MODIFY_MAC;
17127c478bd9Sstevel@tonic-gate 
1713f595a68aSyz147064 			if (!dladm_aggr_str2macaddr(optarg, &mac_addr_fixed,
171433343a97Smeem 			    mac_addr))
171533343a97Smeem 				die("invalid MAC address '%s'", optarg);
17167c478bd9Sstevel@tonic-gate 			break;
17177c478bd9Sstevel@tonic-gate 		case 'l':
1718d62bc4baSyz147064 		case 'L':
1719f595a68aSyz147064 			if (modify_mask & DLADM_AGGR_MODIFY_LACP_MODE)
172033343a97Smeem 				die_optdup(option);
17217c478bd9Sstevel@tonic-gate 
1722f595a68aSyz147064 			modify_mask |= DLADM_AGGR_MODIFY_LACP_MODE;
17237c478bd9Sstevel@tonic-gate 
1724f595a68aSyz147064 			if (!dladm_aggr_str2lacpmode(optarg, &lacp_mode))
172533343a97Smeem 				die("invalid LACP mode '%s'", optarg);
17267c478bd9Sstevel@tonic-gate 			break;
17277c478bd9Sstevel@tonic-gate 		case 'T':
1728f595a68aSyz147064 			if (modify_mask & DLADM_AGGR_MODIFY_LACP_TIMER)
172933343a97Smeem 				die_optdup(option);
17307c478bd9Sstevel@tonic-gate 
1731f595a68aSyz147064 			modify_mask |= DLADM_AGGR_MODIFY_LACP_TIMER;
17327c478bd9Sstevel@tonic-gate 
1733f595a68aSyz147064 			if (!dladm_aggr_str2lacptimer(optarg, &lacp_timer))
173433343a97Smeem 				die("invalid LACP timer value '%s'", optarg);
17357c478bd9Sstevel@tonic-gate 			break;
17367c478bd9Sstevel@tonic-gate 		case 't':
1737d62bc4baSyz147064 			flags &= ~DLADM_OPT_PERSIST;
17387c478bd9Sstevel@tonic-gate 			break;
17397c478bd9Sstevel@tonic-gate 		case 'R':
17407c478bd9Sstevel@tonic-gate 			altroot = optarg;
17417c478bd9Sstevel@tonic-gate 			break;
17427c478bd9Sstevel@tonic-gate 		default:
17438d5c46e6Sam223141 			die_opterr(optopt, option, use);
174433343a97Smeem 			break;
17457c478bd9Sstevel@tonic-gate 		}
17467c478bd9Sstevel@tonic-gate 	}
17477c478bd9Sstevel@tonic-gate 
174833343a97Smeem 	if (modify_mask == 0)
174933343a97Smeem 		die("at least one of the -PulT options must be specified");
17507c478bd9Sstevel@tonic-gate 
1751d62bc4baSyz147064 	/* get key value or the aggregation name (required last argument) */
17527c478bd9Sstevel@tonic-gate 	if (optind != (argc-1))
17537c478bd9Sstevel@tonic-gate 		usage();
17547c478bd9Sstevel@tonic-gate 
1755d62bc4baSyz147064 	status = i_dladm_aggr_get_linkid(altroot, argv[optind], &linkid, flags);
1756d62bc4baSyz147064 	if (status != DLADM_STATUS_OK)
1757d62bc4baSyz147064 		goto done;
17587c478bd9Sstevel@tonic-gate 
1759d62bc4baSyz147064 	if (altroot != NULL)
1760d62bc4baSyz147064 		altroot_cmd(altroot, argc, argv);
1761d62bc4baSyz147064 
17624ac67f02SAnurag S. Maskey 	status = dladm_aggr_modify(handle, linkid, modify_mask, policy,
17634ac67f02SAnurag S. Maskey 	    mac_addr_fixed, (const uchar_t *)mac_addr, lacp_mode, lacp_timer,
17644ac67f02SAnurag S. Maskey 	    flags);
1765d62bc4baSyz147064 
1766d62bc4baSyz147064 done:
1767f595a68aSyz147064 	if (status != DLADM_STATUS_OK)
1768f595a68aSyz147064 		die_dlerr(status, "modify operation failed");
17697c478bd9Sstevel@tonic-gate }
17707c478bd9Sstevel@tonic-gate 
17718d5c46e6Sam223141 /*ARGSUSED*/
17727c478bd9Sstevel@tonic-gate static void
17738d5c46e6Sam223141 do_up_aggr(int argc, char *argv[], const char *use)
17747c478bd9Sstevel@tonic-gate {
1775d62bc4baSyz147064 	datalink_id_t	linkid = DATALINK_ALL_LINKID;
1776f595a68aSyz147064 	dladm_status_t	status;
17777c478bd9Sstevel@tonic-gate 
1778d62bc4baSyz147064 	/*
1779d62bc4baSyz147064 	 * get the key or the name of the aggregation (optional last argument)
1780d62bc4baSyz147064 	 */
17817c478bd9Sstevel@tonic-gate 	if (argc == 2) {
1782d62bc4baSyz147064 		if ((status = i_dladm_aggr_get_linkid(NULL, argv[1], &linkid,
17834ac67f02SAnurag S. Maskey 		    DLADM_OPT_PERSIST)) != DLADM_STATUS_OK)
1784d62bc4baSyz147064 			goto done;
17857c478bd9Sstevel@tonic-gate 	} else if (argc > 2) {
17867c478bd9Sstevel@tonic-gate 		usage();
17877c478bd9Sstevel@tonic-gate 	}
17887c478bd9Sstevel@tonic-gate 
17894ac67f02SAnurag S. Maskey 	status = dladm_aggr_up(handle, linkid);
1790d62bc4baSyz147064 done:
1791d62bc4baSyz147064 	if (status != DLADM_STATUS_OK) {
1792d62bc4baSyz147064 		if (argc == 2) {
1793d62bc4baSyz147064 			die_dlerr(status,
1794d62bc4baSyz147064 			    "could not bring up aggregation '%s'", argv[1]);
17957c478bd9Sstevel@tonic-gate 		} else {
1796f595a68aSyz147064 			die_dlerr(status, "could not bring aggregations up");
17977c478bd9Sstevel@tonic-gate 		}
17987c478bd9Sstevel@tonic-gate 	}
17997c478bd9Sstevel@tonic-gate }
18007c478bd9Sstevel@tonic-gate 
18017c478bd9Sstevel@tonic-gate static void
18028d5c46e6Sam223141 do_create_vlan(int argc, char *argv[], const char *use)
18037c478bd9Sstevel@tonic-gate {
1804d62bc4baSyz147064 	char			*link = NULL;
1805d62bc4baSyz147064 	char			drv[DLPI_LINKNAME_MAX];
1806d62bc4baSyz147064 	uint_t			ppa;
1807d62bc4baSyz147064 	datalink_id_t		linkid;
1808da14cebeSEric Cheng 	datalink_id_t		dev_linkid;
1809d62bc4baSyz147064 	int			vid = 0;
1810d62bc4baSyz147064 	char			option;
1811d62bc4baSyz147064 	uint32_t		flags = (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST);
1812d62bc4baSyz147064 	char			*altroot = NULL;
1813d62bc4baSyz147064 	char			vlan[MAXLINKNAMELEN];
181463a6526dSMichael Lim 	char			propstr[DLADM_STRSIZE];
1815da14cebeSEric Cheng 	dladm_arg_list_t	*proplist = NULL;
1816f595a68aSyz147064 	dladm_status_t		status;
18177c478bd9Sstevel@tonic-gate 
1818d62bc4baSyz147064 	opterr = 0;
181963a6526dSMichael Lim 	bzero(propstr, DLADM_STRSIZE);
182063a6526dSMichael Lim 
1821da14cebeSEric Cheng 	while ((option = getopt_long(argc, argv, ":tfR:l:v:p:",
1822d62bc4baSyz147064 	    lopts, NULL)) != -1) {
1823d62bc4baSyz147064 		switch (option) {
1824d62bc4baSyz147064 		case 'v':
1825d62bc4baSyz147064 			if (vid != 0)
1826d62bc4baSyz147064 				die_optdup(option);
1827d62bc4baSyz147064 
1828d62bc4baSyz147064 			if (!str2int(optarg, &vid) || vid < 1 || vid > 4094)
1829d62bc4baSyz147064 				die("invalid VLAN identifier '%s'", optarg);
1830d62bc4baSyz147064 
1831d62bc4baSyz147064 			break;
1832d62bc4baSyz147064 		case 'l':
1833d62bc4baSyz147064 			if (link != NULL)
1834d62bc4baSyz147064 				die_optdup(option);
1835d62bc4baSyz147064 
1836d62bc4baSyz147064 			link = optarg;
1837d62bc4baSyz147064 			break;
1838d62bc4baSyz147064 		case 't':
1839d62bc4baSyz147064 			flags &= ~DLADM_OPT_PERSIST;
1840d62bc4baSyz147064 			break;
1841d62bc4baSyz147064 		case 'R':
1842d62bc4baSyz147064 			altroot = optarg;
1843d62bc4baSyz147064 			break;
1844da14cebeSEric Cheng 		case 'p':
184563a6526dSMichael Lim 			(void) strlcat(propstr, optarg, DLADM_STRSIZE);
184663a6526dSMichael Lim 			if (strlcat(propstr, ",", DLADM_STRSIZE) >=
184763a6526dSMichael Lim 			    DLADM_STRSIZE)
184863a6526dSMichael Lim 				die("property list too long '%s'", propstr);
1849da14cebeSEric Cheng 			break;
1850da14cebeSEric Cheng 		case 'f':
1851da14cebeSEric Cheng 			flags |= DLADM_OPT_FORCE;
1852da14cebeSEric Cheng 			break;
1853d62bc4baSyz147064 		default:
18548d5c46e6Sam223141 			die_opterr(optopt, option, use);
1855d62bc4baSyz147064 			break;
1856d62bc4baSyz147064 		}
1857d62bc4baSyz147064 	}
1858d62bc4baSyz147064 
1859d62bc4baSyz147064 	/* get vlan name if there is any */
1860d62bc4baSyz147064 	if ((vid == 0) || (link == NULL) || (argc - optind > 1))
18617c478bd9Sstevel@tonic-gate 		usage();
1862d62bc4baSyz147064 
1863d62bc4baSyz147064 	if (optind == (argc - 1)) {
1864d62bc4baSyz147064 		if (strlcpy(vlan, argv[optind], MAXLINKNAMELEN) >=
1865d62bc4baSyz147064 		    MAXLINKNAMELEN) {
1866d62bc4baSyz147064 			die("vlan name too long '%s'", argv[optind]);
1867d62bc4baSyz147064 		}
1868d62bc4baSyz147064 	} else {
1869d62bc4baSyz147064 		if ((dlpi_parselink(link, drv, &ppa) != DLPI_SUCCESS) ||
1870d62bc4baSyz147064 		    (ppa >= 1000) ||
1871d62bc4baSyz147064 		    (dlpi_makelink(vlan, drv, vid * 1000 + ppa) !=
1872d62bc4baSyz147064 		    DLPI_SUCCESS)) {
1873d62bc4baSyz147064 			die("invalid link name '%s'", link);
1874d62bc4baSyz147064 		}
18757c478bd9Sstevel@tonic-gate 	}
18767c478bd9Sstevel@tonic-gate 
1877d62bc4baSyz147064 	if (altroot != NULL)
1878d62bc4baSyz147064 		altroot_cmd(altroot, argc, argv);
1879d62bc4baSyz147064 
18804ac67f02SAnurag S. Maskey 	if (dladm_name2info(handle, link, &dev_linkid, NULL, NULL, NULL) !=
1881d62bc4baSyz147064 	    DLADM_STATUS_OK) {
1882d62bc4baSyz147064 		die("invalid link name '%s'", link);
1883d62bc4baSyz147064 	}
1884d62bc4baSyz147064 
188563a6526dSMichael Lim 	if (dladm_parse_link_props(propstr, &proplist, B_FALSE)
188663a6526dSMichael Lim 	    != DLADM_STATUS_OK)
188763a6526dSMichael Lim 		die("invalid vlan property");
188863a6526dSMichael Lim 
18894ac67f02SAnurag S. Maskey 	if ((status = dladm_vlan_create(handle, vlan, dev_linkid, vid, proplist,
18904ac67f02SAnurag S. Maskey 	    flags, &linkid)) != DLADM_STATUS_OK) {
1891da14cebeSEric Cheng 		die_dlerr(status, "create operation over %s failed", link);
1892d62bc4baSyz147064 	}
1893d62bc4baSyz147064 }
1894d62bc4baSyz147064 
1895d62bc4baSyz147064 static void
18968d5c46e6Sam223141 do_delete_vlan(int argc, char *argv[], const char *use)
1897d62bc4baSyz147064 {
1898d62bc4baSyz147064 	char		option;
1899d62bc4baSyz147064 	uint32_t	flags = (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST);
1900d62bc4baSyz147064 	char		*altroot = NULL;
1901d62bc4baSyz147064 	datalink_id_t	linkid;
1902d62bc4baSyz147064 	dladm_status_t	status;
1903d62bc4baSyz147064 
1904d62bc4baSyz147064 	opterr = 0;
1905d62bc4baSyz147064 	while ((option = getopt_long(argc, argv, ":R:t", lopts, NULL)) != -1) {
1906d62bc4baSyz147064 		switch (option) {
1907d62bc4baSyz147064 		case 't':
1908d62bc4baSyz147064 			flags &= ~DLADM_OPT_PERSIST;
1909d62bc4baSyz147064 			break;
1910d62bc4baSyz147064 		case 'R':
1911d62bc4baSyz147064 			altroot = optarg;
1912d62bc4baSyz147064 			break;
1913d62bc4baSyz147064 		default:
19148d5c46e6Sam223141 			die_opterr(optopt, option, use);
1915d62bc4baSyz147064 			break;
1916d62bc4baSyz147064 		}
1917d62bc4baSyz147064 	}
1918d62bc4baSyz147064 
1919d62bc4baSyz147064 	/* get VLAN link name (required last argument) */
1920d62bc4baSyz147064 	if (optind != (argc - 1))
1921d62bc4baSyz147064 		usage();
1922d62bc4baSyz147064 
1923d62bc4baSyz147064 	if (altroot != NULL)
1924d62bc4baSyz147064 		altroot_cmd(altroot, argc, argv);
1925d62bc4baSyz147064 
19264ac67f02SAnurag S. Maskey 	status = dladm_name2info(handle, argv[optind], &linkid, NULL, NULL,
19274ac67f02SAnurag S. Maskey 	    NULL);
1928d62bc4baSyz147064 	if (status != DLADM_STATUS_OK)
1929d62bc4baSyz147064 		goto done;
1930d62bc4baSyz147064 
19314ac67f02SAnurag S. Maskey 	status = dladm_vlan_delete(handle, linkid, flags);
1932d62bc4baSyz147064 done:
1933d62bc4baSyz147064 	if (status != DLADM_STATUS_OK)
1934d62bc4baSyz147064 		die_dlerr(status, "delete operation failed");
1935d62bc4baSyz147064 }
1936d62bc4baSyz147064 
19378d5c46e6Sam223141 /*ARGSUSED*/
1938d62bc4baSyz147064 static void
19398d5c46e6Sam223141 do_up_vlan(int argc, char *argv[], const char *use)
1940d62bc4baSyz147064 {
1941da14cebeSEric Cheng 	do_up_vnic_common(argc, argv, use, B_TRUE);
19427c478bd9Sstevel@tonic-gate }
19437c478bd9Sstevel@tonic-gate 
1944210db224Sericheng static void
19458d5c46e6Sam223141 do_rename_link(int argc, char *argv[], const char *use)
1946210db224Sericheng {
1947d62bc4baSyz147064 	char		option;
1948d62bc4baSyz147064 	char		*link1, *link2;
1949d62bc4baSyz147064 	char		*altroot = NULL;
1950d62bc4baSyz147064 	dladm_status_t	status;
1951210db224Sericheng 
1952d62bc4baSyz147064 	opterr = 0;
1953d62bc4baSyz147064 	while ((option = getopt_long(argc, argv, ":R:", lopts, NULL)) != -1) {
1954d62bc4baSyz147064 		switch (option) {
1955d62bc4baSyz147064 		case 'R':
1956d62bc4baSyz147064 			altroot = optarg;
1957d62bc4baSyz147064 			break;
1958d62bc4baSyz147064 		default:
19598d5c46e6Sam223141 			die_opterr(optopt, option, use);
1960d62bc4baSyz147064 			break;
1961210db224Sericheng 		}
1962210db224Sericheng 	}
1963210db224Sericheng 
1964d62bc4baSyz147064 	/* get link1 and link2 name (required the last 2 arguments) */
1965d62bc4baSyz147064 	if (optind != (argc - 2))
1966d62bc4baSyz147064 		usage();
1967d62bc4baSyz147064 
1968d62bc4baSyz147064 	if (altroot != NULL)
1969d62bc4baSyz147064 		altroot_cmd(altroot, argc, argv);
1970d62bc4baSyz147064 
1971d62bc4baSyz147064 	link1 = argv[optind++];
1972d62bc4baSyz147064 	link2 = argv[optind];
19734ac67f02SAnurag S. Maskey 	if ((status = dladm_rename_link(handle, link1, link2)) !=
19744ac67f02SAnurag S. Maskey 	    DLADM_STATUS_OK)
1975d62bc4baSyz147064 		die_dlerr(status, "rename operation failed");
1976d62bc4baSyz147064 }
1977d62bc4baSyz147064 
19788d5c46e6Sam223141 /*ARGSUSED*/
1979d62bc4baSyz147064 static void
19808d5c46e6Sam223141 do_delete_phys(int argc, char *argv[], const char *use)
1981d62bc4baSyz147064 {
1982d62bc4baSyz147064 	datalink_id_t	linkid = DATALINK_ALL_LINKID;
1983d62bc4baSyz147064 	dladm_status_t	status;
1984d62bc4baSyz147064 
1985d62bc4baSyz147064 	/* get link name (required the last argument) */
1986d62bc4baSyz147064 	if (argc > 2)
1987d62bc4baSyz147064 		usage();
1988d62bc4baSyz147064 
1989d62bc4baSyz147064 	if (argc == 2) {
19904ac67f02SAnurag S. Maskey 		if ((status = dladm_name2info(handle, argv[1], &linkid, NULL,
19914ac67f02SAnurag S. Maskey 		    NULL, NULL)) != DLADM_STATUS_OK)
1992d62bc4baSyz147064 			die_dlerr(status, "cannot delete '%s'", argv[1]);
1993d62bc4baSyz147064 	}
1994d62bc4baSyz147064 
19954ac67f02SAnurag S. Maskey 	if ((status = dladm_phys_delete(handle, linkid)) != DLADM_STATUS_OK) {
1996d62bc4baSyz147064 		if (argc == 2)
1997d62bc4baSyz147064 			die_dlerr(status, "cannot delete '%s'", argv[1]);
1998d62bc4baSyz147064 		else
1999d62bc4baSyz147064 			die_dlerr(status, "delete operation failed");
2000d62bc4baSyz147064 	}
2001d62bc4baSyz147064 }
2002d62bc4baSyz147064 
2003d62bc4baSyz147064 /*ARGSUSED*/
2004210db224Sericheng static int
20054ac67f02SAnurag S. Maskey i_dladm_walk_linkmap(dladm_handle_t dh, datalink_id_t linkid, void *arg)
2006210db224Sericheng {
2007d62bc4baSyz147064 	char			name[MAXLINKNAMELEN];
2008d62bc4baSyz147064 	char			mediabuf[DLADM_STRSIZE];
2009d62bc4baSyz147064 	char			classbuf[DLADM_STRSIZE];
2010d62bc4baSyz147064 	datalink_class_t	class;
2011d62bc4baSyz147064 	uint32_t		media;
2012d62bc4baSyz147064 	uint32_t		flags;
2013210db224Sericheng 
20144ac67f02SAnurag S. Maskey 	if (dladm_datalink_id2info(dh, linkid, &flags, &class, &media, name,
2015d62bc4baSyz147064 	    MAXLINKNAMELEN) == DLADM_STATUS_OK) {
2016d62bc4baSyz147064 		(void) dladm_class2str(class, classbuf);
2017d62bc4baSyz147064 		(void) dladm_media2str(media, mediabuf);
2018d62bc4baSyz147064 		(void) printf("%-12s%8d  %-12s%-20s %6d\n", name,
2019d62bc4baSyz147064 		    linkid, classbuf, mediabuf, flags);
2020210db224Sericheng 	}
2021d62bc4baSyz147064 	return (DLADM_WALK_CONTINUE);
2022210db224Sericheng }
20237c478bd9Sstevel@tonic-gate 
20247c478bd9Sstevel@tonic-gate /*ARGSUSED*/
20257c478bd9Sstevel@tonic-gate static void
20268d5c46e6Sam223141 do_show_linkmap(int argc, char *argv[], const char *use)
20277c478bd9Sstevel@tonic-gate {
2028d62bc4baSyz147064 	if (argc != 1)
2029d62bc4baSyz147064 		die("invalid arguments");
20307c478bd9Sstevel@tonic-gate 
2031d62bc4baSyz147064 	(void) printf("%-12s%8s  %-12s%-20s %6s\n", "NAME", "LINKID",
2032d62bc4baSyz147064 	    "CLASS", "MEDIA", "FLAGS");
20334ac67f02SAnurag S. Maskey 
20344ac67f02SAnurag S. Maskey 	(void) dladm_walk_datalink_id(i_dladm_walk_linkmap, handle, NULL,
2035d62bc4baSyz147064 	    DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE,
2036d62bc4baSyz147064 	    DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST);
20377c478bd9Sstevel@tonic-gate }
2038d62bc4baSyz147064 
2039d62bc4baSyz147064 /*
2040d62bc4baSyz147064  * Delete inactive physical links.
2041d62bc4baSyz147064  */
2042d62bc4baSyz147064 /*ARGSUSED*/
2043d62bc4baSyz147064 static int
20444ac67f02SAnurag S. Maskey purge_phys(dladm_handle_t dh, datalink_id_t linkid, void *arg)
2045d62bc4baSyz147064 {
2046d62bc4baSyz147064 	datalink_class_t	class;
2047d62bc4baSyz147064 	uint32_t		flags;
2048d62bc4baSyz147064 
20494ac67f02SAnurag S. Maskey 	if (dladm_datalink_id2info(dh, linkid, &flags, &class, NULL, NULL, 0)
20504ac67f02SAnurag S. Maskey 	    != DLADM_STATUS_OK) {
2051d62bc4baSyz147064 		return (DLADM_WALK_CONTINUE);
2052d62bc4baSyz147064 	}
2053d62bc4baSyz147064 
2054d62bc4baSyz147064 	if (class == DATALINK_CLASS_PHYS && !(flags & DLADM_OPT_ACTIVE))
20554ac67f02SAnurag S. Maskey 		(void) dladm_phys_delete(dh, linkid);
2056d62bc4baSyz147064 
2057d62bc4baSyz147064 	return (DLADM_WALK_CONTINUE);
2058d62bc4baSyz147064 }
2059d62bc4baSyz147064 
2060d62bc4baSyz147064 /*ARGSUSED*/
2061d62bc4baSyz147064 static void
20628d5c46e6Sam223141 do_init_phys(int argc, char *argv[], const char *use)
2063d62bc4baSyz147064 {
2064d62bc4baSyz147064 	di_node_t	devtree;
2065d62bc4baSyz147064 
2066d62bc4baSyz147064 	if (argc > 1)
2067d62bc4baSyz147064 		usage();
2068d62bc4baSyz147064 
2069d62bc4baSyz147064 	/*
2070d62bc4baSyz147064 	 * Force all the devices to attach, therefore all the network physical
2071d62bc4baSyz147064 	 * devices can be known to the dlmgmtd daemon.
2072d62bc4baSyz147064 	 */
2073d62bc4baSyz147064 	if ((devtree = di_init("/", DINFOFORCE | DINFOSUBTREE)) != DI_NODE_NIL)
2074d62bc4baSyz147064 		di_fini(devtree);
2075d62bc4baSyz147064 
20764ac67f02SAnurag S. Maskey 	(void) dladm_walk_datalink_id(purge_phys, handle, NULL,
2077d62bc4baSyz147064 	    DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST);
20787c478bd9Sstevel@tonic-gate }
20797c478bd9Sstevel@tonic-gate 
2080d62bc4baSyz147064 
2081d62bc4baSyz147064 /*
2082d62bc4baSyz147064  * Print the active topology information.
2083d62bc4baSyz147064  */
2084d62bc4baSyz147064 static dladm_status_t
2085d62bc4baSyz147064 print_link_topology(show_state_t *state, datalink_id_t linkid,
2086e7801d59Ssowmini     datalink_class_t class, link_fields_buf_t *lbuf)
2087d62bc4baSyz147064 {
2088d62bc4baSyz147064 	uint32_t	flags = state->ls_flags;
2089d62bc4baSyz147064 	dladm_status_t	status = DLADM_STATUS_OK;
20906b9e797cSsowmini 	char		tmpbuf[MAXLINKNAMELEN];
2091d62bc4baSyz147064 
2092e7801d59Ssowmini 	(void) sprintf(lbuf->link_over, "");
2093d62bc4baSyz147064 	if (class == DATALINK_CLASS_VLAN) {
2094d62bc4baSyz147064 		dladm_vlan_attr_t	vinfo;
2095d62bc4baSyz147064 
20964ac67f02SAnurag S. Maskey 		status = dladm_vlan_info(handle, linkid, &vinfo, flags);
2097d62bc4baSyz147064 		if (status != DLADM_STATUS_OK)
2098d62bc4baSyz147064 			goto done;
20994ac67f02SAnurag S. Maskey 		status = dladm_datalink_id2info(handle, vinfo.dv_linkid, NULL,
21004ac67f02SAnurag S. Maskey 		    NULL, NULL, lbuf->link_over, sizeof (lbuf->link_over));
2101d62bc4baSyz147064 		if (status != DLADM_STATUS_OK)
2102d62bc4baSyz147064 			goto done;
2103d62bc4baSyz147064 	} else if (class == DATALINK_CLASS_AGGR) {
2104d62bc4baSyz147064 		dladm_aggr_grp_attr_t	ginfo;
2105d62bc4baSyz147064 		int			i;
2106d62bc4baSyz147064 
21076b9e797cSsowmini 		(void) sprintf(lbuf->link_over, "");
21086b9e797cSsowmini 
21094ac67f02SAnurag S. Maskey 		status = dladm_aggr_info(handle, linkid, &ginfo, flags);
2110d62bc4baSyz147064 		if (status != DLADM_STATUS_OK)
2111d62bc4baSyz147064 			goto done;
2112d62bc4baSyz147064 
2113d62bc4baSyz147064 		if (ginfo.lg_nports == 0) {
2114d62bc4baSyz147064 			status = DLADM_STATUS_BADVAL;
2115d62bc4baSyz147064 			goto done;
2116d62bc4baSyz147064 		}
2117d62bc4baSyz147064 		for (i = 0; i < ginfo.lg_nports; i++) {
21184ac67f02SAnurag S. Maskey 			status = dladm_datalink_id2info(handle,
2119e7801d59Ssowmini 			    ginfo.lg_ports[i].lp_linkid, NULL, NULL, NULL,
21206b9e797cSsowmini 			    tmpbuf, sizeof (tmpbuf));
2121d62bc4baSyz147064 			if (status != DLADM_STATUS_OK) {
2122d62bc4baSyz147064 				free(ginfo.lg_ports);
2123d62bc4baSyz147064 				goto done;
2124d62bc4baSyz147064 			}
21256b9e797cSsowmini 			(void) strlcat(lbuf->link_over, tmpbuf,
21266b9e797cSsowmini 			    sizeof (lbuf->link_over));
21276b9e797cSsowmini 			if (i != (ginfo.lg_nports - 1)) {
21286b9e797cSsowmini 				(void) strlcat(lbuf->link_over, " ",
21296b9e797cSsowmini 				    sizeof (lbuf->link_over));
21306b9e797cSsowmini 			}
2131d62bc4baSyz147064 		}
2132d62bc4baSyz147064 		free(ginfo.lg_ports);
2133d62bc4baSyz147064 	} else if (class == DATALINK_CLASS_VNIC) {
2134da14cebeSEric Cheng 		dladm_vnic_attr_t	vinfo;
2135d62bc4baSyz147064 
21364ac67f02SAnurag S. Maskey 		if ((status = dladm_vnic_info(handle, linkid, &vinfo, flags)) !=
21374ac67f02SAnurag S. Maskey 		    DLADM_STATUS_OK ||
21384ac67f02SAnurag S. Maskey 		    (status = dladm_datalink_id2info(handle, vinfo.va_link_id,
21394ac67f02SAnurag S. Maskey 		    NULL, NULL, NULL, lbuf->link_over,
2140e7801d59Ssowmini 		    sizeof (lbuf->link_over)) != DLADM_STATUS_OK)) {
2141d62bc4baSyz147064 			goto done;
2142d62bc4baSyz147064 		}
2143d62bc4baSyz147064 	}
2144d62bc4baSyz147064 done:
2145d62bc4baSyz147064 	return (status);
2146d62bc4baSyz147064 }
2147d62bc4baSyz147064 
2148d62bc4baSyz147064 static dladm_status_t
2149e7801d59Ssowmini print_link(show_state_t *state, datalink_id_t linkid, link_fields_buf_t *lbuf)
2150d62bc4baSyz147064 {
2151d62bc4baSyz147064 	char			link[MAXLINKNAMELEN];
2152d62bc4baSyz147064 	datalink_class_t	class;
2153d62bc4baSyz147064 	uint_t			mtu;
2154d62bc4baSyz147064 	uint32_t		flags;
2155d62bc4baSyz147064 	dladm_status_t		status;
2156d62bc4baSyz147064 
21574ac67f02SAnurag S. Maskey 	if ((status = dladm_datalink_id2info(handle, linkid, &flags, &class,
21584ac67f02SAnurag S. Maskey 	    NULL, link, sizeof (link))) != DLADM_STATUS_OK) {
2159d62bc4baSyz147064 		goto done;
2160d62bc4baSyz147064 	}
2161d62bc4baSyz147064 
2162d62bc4baSyz147064 	if (!(state->ls_flags & flags)) {
2163d62bc4baSyz147064 		status = DLADM_STATUS_NOTFOUND;
2164d62bc4baSyz147064 		goto done;
2165d62bc4baSyz147064 	}
2166d62bc4baSyz147064 
2167d62bc4baSyz147064 	if (state->ls_flags == DLADM_OPT_ACTIVE) {
2168d62bc4baSyz147064 		dladm_attr_t	dlattr;
2169d62bc4baSyz147064 
2170d62bc4baSyz147064 		if (class == DATALINK_CLASS_PHYS) {
2171d62bc4baSyz147064 			dladm_phys_attr_t	dpa;
2172d62bc4baSyz147064 			dlpi_handle_t		dh;
2173d62bc4baSyz147064 			dlpi_info_t		dlinfo;
2174d62bc4baSyz147064 
21754ac67f02SAnurag S. Maskey 			if ((status = dladm_phys_info(handle, linkid, &dpa,
2176d62bc4baSyz147064 			    DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) {
2177d62bc4baSyz147064 				goto done;
2178d62bc4baSyz147064 			}
2179d62bc4baSyz147064 
2180d62bc4baSyz147064 			if (!dpa.dp_novanity)
2181d62bc4baSyz147064 				goto link_mtu;
2182d62bc4baSyz147064 
2183d62bc4baSyz147064 			/*
2184d62bc4baSyz147064 			 * This is a physical link that does not have
2185d62bc4baSyz147064 			 * vanity naming support.
2186d62bc4baSyz147064 			 */
2187d62bc4baSyz147064 			if (dlpi_open(dpa.dp_dev, &dh, DLPI_DEVONLY) !=
2188d62bc4baSyz147064 			    DLPI_SUCCESS) {
2189d62bc4baSyz147064 				status = DLADM_STATUS_NOTFOUND;
2190d62bc4baSyz147064 				goto done;
2191d62bc4baSyz147064 			}
2192d62bc4baSyz147064 
2193d62bc4baSyz147064 			if (dlpi_info(dh, &dlinfo, 0) != DLPI_SUCCESS) {
2194d62bc4baSyz147064 				dlpi_close(dh);
2195d62bc4baSyz147064 				status = DLADM_STATUS_BADARG;
2196d62bc4baSyz147064 				goto done;
2197d62bc4baSyz147064 			}
2198d62bc4baSyz147064 
2199d62bc4baSyz147064 			dlpi_close(dh);
2200d62bc4baSyz147064 			mtu = dlinfo.di_max_sdu;
2201d62bc4baSyz147064 		} else {
2202d62bc4baSyz147064 link_mtu:
22034ac67f02SAnurag S. Maskey 			status = dladm_info(handle, linkid, &dlattr);
2204d62bc4baSyz147064 			if (status != DLADM_STATUS_OK)
2205d62bc4baSyz147064 				goto done;
2206d62bc4baSyz147064 			mtu = dlattr.da_max_sdu;
2207d62bc4baSyz147064 		}
2208d62bc4baSyz147064 	}
2209d62bc4baSyz147064 
2210e7801d59Ssowmini 	(void) snprintf(lbuf->link_name, sizeof (lbuf->link_name),
2211e7801d59Ssowmini 	    "%s", link);
2212e7801d59Ssowmini 	(void) dladm_class2str(class, lbuf->link_class);
2213d62bc4baSyz147064 	if (state->ls_flags == DLADM_OPT_ACTIVE) {
2214e7801d59Ssowmini 		(void) snprintf(lbuf->link_mtu, sizeof (lbuf->link_mtu),
2215c08e5e1aSdr146992 		    "%u", mtu);
2216e7801d59Ssowmini 		(void) get_linkstate(link, B_TRUE, lbuf->link_state);
2217d62bc4baSyz147064 	}
2218d62bc4baSyz147064 
2219e7801d59Ssowmini 	status = print_link_topology(state, linkid, class, lbuf);
2220d62bc4baSyz147064 	if (status != DLADM_STATUS_OK)
2221d62bc4baSyz147064 		goto done;
2222d62bc4baSyz147064 
2223d62bc4baSyz147064 done:
2224d62bc4baSyz147064 	return (status);
2225d62bc4baSyz147064 }
2226d62bc4baSyz147064 
22274ac67f02SAnurag S. Maskey /* ARGSUSED */
2228d62bc4baSyz147064 static int
22294ac67f02SAnurag S. Maskey show_link(dladm_handle_t dh, datalink_id_t linkid, void *arg)
2230d62bc4baSyz147064 {
2231e7801d59Ssowmini 	show_state_t		*state = (show_state_t *)arg;
2232d62bc4baSyz147064 	dladm_status_t		status;
2233e7801d59Ssowmini 	link_fields_buf_t	lbuf;
2234d62bc4baSyz147064 
2235e7801d59Ssowmini 	/*
2236e7801d59Ssowmini 	 * first get all the link attributes into lbuf;
2237e7801d59Ssowmini 	 */
22385f5c9f54SAnurag S. Maskey 	bzero(&lbuf, sizeof (link_fields_buf_t));
2239e7801d59Ssowmini 	status = print_link(state, linkid, &lbuf);
2240e7801d59Ssowmini 
2241d62bc4baSyz147064 	if (status != DLADM_STATUS_OK)
2242d62bc4baSyz147064 		goto done;
2243e7801d59Ssowmini 
2244*8002d411SSowmini Varadhan 	ofmt_print(state->ls_ofmt, &lbuf);
2245d62bc4baSyz147064 
2246d62bc4baSyz147064 done:
2247d62bc4baSyz147064 	state->ls_status = status;
2248d62bc4baSyz147064 	return (DLADM_WALK_CONTINUE);
2249d62bc4baSyz147064 }
2250d62bc4baSyz147064 
2251*8002d411SSowmini Varadhan static boolean_t
2252*8002d411SSowmini Varadhan print_link_stats_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
2253ae6aa22aSVenugopal Iyer {
2254*8002d411SSowmini Varadhan 	link_args_t *largs = ofarg->ofmt_cbarg;
2255ae6aa22aSVenugopal Iyer 	pktsum_t *diff_stats = largs->link_s_psum;
2256ae6aa22aSVenugopal Iyer 
2257*8002d411SSowmini Varadhan 	switch (ofarg->ofmt_id) {
2258ae6aa22aSVenugopal Iyer 	case LINK_S_LINK:
2259*8002d411SSowmini Varadhan 		(void) snprintf(buf, bufsize, "%s", largs->link_s_link);
2260ae6aa22aSVenugopal Iyer 		break;
2261ae6aa22aSVenugopal Iyer 	case LINK_S_IPKTS:
2262*8002d411SSowmini Varadhan 		(void) snprintf(buf, bufsize, "%llu", diff_stats->ipackets);
2263ae6aa22aSVenugopal Iyer 		break;
2264ae6aa22aSVenugopal Iyer 	case LINK_S_RBYTES:
2265*8002d411SSowmini Varadhan 		(void) snprintf(buf, bufsize, "%llu", diff_stats->rbytes);
2266ae6aa22aSVenugopal Iyer 		break;
2267ae6aa22aSVenugopal Iyer 	case LINK_S_IERRORS:
2268*8002d411SSowmini Varadhan 		(void) snprintf(buf, bufsize, "%u", diff_stats->ierrors);
2269ae6aa22aSVenugopal Iyer 		break;
2270ae6aa22aSVenugopal Iyer 	case LINK_S_OPKTS:
2271*8002d411SSowmini Varadhan 		(void) snprintf(buf, bufsize, "%llu", diff_stats->opackets);
2272ae6aa22aSVenugopal Iyer 		break;
2273ae6aa22aSVenugopal Iyer 	case LINK_S_OBYTES:
2274*8002d411SSowmini Varadhan 		(void) snprintf(buf, bufsize, "%llu", diff_stats->obytes);
2275ae6aa22aSVenugopal Iyer 		break;
2276ae6aa22aSVenugopal Iyer 	case LINK_S_OERRORS:
2277*8002d411SSowmini Varadhan 		(void) snprintf(buf, bufsize, "%u", diff_stats->oerrors);
2278ae6aa22aSVenugopal Iyer 		break;
2279ae6aa22aSVenugopal Iyer 	default:
2280ae6aa22aSVenugopal Iyer 		die("invalid input");
2281ae6aa22aSVenugopal Iyer 		break;
2282ae6aa22aSVenugopal Iyer 	}
2283*8002d411SSowmini Varadhan 	return (B_TRUE);
2284ae6aa22aSVenugopal Iyer }
2285ae6aa22aSVenugopal Iyer 
2286d62bc4baSyz147064 static int
22874ac67f02SAnurag S. Maskey show_link_stats(dladm_handle_t dh, datalink_id_t linkid, void *arg)
2288d62bc4baSyz147064 {
2289e7801d59Ssowmini 	char			link[DLPI_LINKNAME_MAX];
2290d62bc4baSyz147064 	datalink_class_t	class;
2291e7801d59Ssowmini 	show_state_t		*state = (show_state_t *)arg;
22927c478bd9Sstevel@tonic-gate 	pktsum_t		stats, diff_stats;
2293d62bc4baSyz147064 	dladm_phys_attr_t	dpa;
2294ae6aa22aSVenugopal Iyer 	link_args_t		largs;
22957c478bd9Sstevel@tonic-gate 
22967c478bd9Sstevel@tonic-gate 	if (state->ls_firstonly) {
22977c478bd9Sstevel@tonic-gate 		if (state->ls_donefirst)
2298d62bc4baSyz147064 			return (DLADM_WALK_CONTINUE);
22997c478bd9Sstevel@tonic-gate 		state->ls_donefirst = B_TRUE;
23007c478bd9Sstevel@tonic-gate 	} else {
23017c478bd9Sstevel@tonic-gate 		bzero(&state->ls_prevstats, sizeof (state->ls_prevstats));
23027c478bd9Sstevel@tonic-gate 	}
23037c478bd9Sstevel@tonic-gate 
23044ac67f02SAnurag S. Maskey 	if (dladm_datalink_id2info(dh, linkid, NULL, &class, NULL, link,
2305e7801d59Ssowmini 	    DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) {
2306d62bc4baSyz147064 		return (DLADM_WALK_CONTINUE);
2307d62bc4baSyz147064 	}
2308d62bc4baSyz147064 
2309d62bc4baSyz147064 	if (class == DATALINK_CLASS_PHYS) {
23104ac67f02SAnurag S. Maskey 		if (dladm_phys_info(dh, linkid, &dpa, DLADM_OPT_ACTIVE) !=
2311d62bc4baSyz147064 		    DLADM_STATUS_OK) {
2312d62bc4baSyz147064 			return (DLADM_WALK_CONTINUE);
2313d62bc4baSyz147064 		}
2314d62bc4baSyz147064 		if (dpa.dp_novanity)
2315d62bc4baSyz147064 			get_mac_stats(dpa.dp_dev, &stats);
2316d62bc4baSyz147064 		else
2317d62bc4baSyz147064 			get_link_stats(link, &stats);
2318d62bc4baSyz147064 	} else {
2319d62bc4baSyz147064 		get_link_stats(link, &stats);
2320d62bc4baSyz147064 	}
2321da14cebeSEric Cheng 	dladm_stats_diff(&diff_stats, &stats, &state->ls_prevstats);
23227c478bd9Sstevel@tonic-gate 
2323ae6aa22aSVenugopal Iyer 	largs.link_s_link = link;
2324ae6aa22aSVenugopal Iyer 	largs.link_s_psum = &diff_stats;
2325*8002d411SSowmini Varadhan 	ofmt_print(state->ls_ofmt, &largs);
23267c478bd9Sstevel@tonic-gate 
23277c478bd9Sstevel@tonic-gate 	state->ls_prevstats = stats;
2328d62bc4baSyz147064 	return (DLADM_WALK_CONTINUE);
23297c478bd9Sstevel@tonic-gate }
23307c478bd9Sstevel@tonic-gate 
2331d62bc4baSyz147064 
2332d62bc4baSyz147064 static dladm_status_t
2333d62bc4baSyz147064 print_aggr_info(show_grp_state_t *state, const char *link,
2334e7801d59Ssowmini     dladm_aggr_grp_attr_t *ginfop)
2335d62bc4baSyz147064 {
2336d62bc4baSyz147064 	char			addr_str[ETHERADDRL * 3];
2337e7801d59Ssowmini 	laggr_fields_buf_t	lbuf;
2338d62bc4baSyz147064 
2339e7801d59Ssowmini 	(void) snprintf(lbuf.laggr_name, sizeof (lbuf.laggr_name),
2340e7801d59Ssowmini 	    "%s", link);
2341e7801d59Ssowmini 
2342e7801d59Ssowmini 	(void) dladm_aggr_policy2str(ginfop->lg_policy,
2343e7801d59Ssowmini 	    lbuf.laggr_policy);
2344d62bc4baSyz147064 
2345d62bc4baSyz147064 	if (ginfop->lg_mac_fixed) {
2346d62bc4baSyz147064 		(void) dladm_aggr_macaddr2str(ginfop->lg_mac, addr_str);
2347e7801d59Ssowmini 		(void) snprintf(lbuf.laggr_addrpolicy,
2348e7801d59Ssowmini 		    sizeof (lbuf.laggr_addrpolicy), "fixed (%s)", addr_str);
2349d62bc4baSyz147064 	} else {
2350e7801d59Ssowmini 		(void) snprintf(lbuf.laggr_addrpolicy,
2351e7801d59Ssowmini 		    sizeof (lbuf.laggr_addrpolicy), "auto");
2352d62bc4baSyz147064 	}
2353d62bc4baSyz147064 
2354d62bc4baSyz147064 
2355e7801d59Ssowmini 	(void) dladm_aggr_lacpmode2str(ginfop->lg_lacp_mode,
2356e7801d59Ssowmini 	    lbuf.laggr_lacpactivity);
2357e7801d59Ssowmini 	(void) dladm_aggr_lacptimer2str(ginfop->lg_lacp_timer,
2358e7801d59Ssowmini 	    lbuf.laggr_lacptimer);
2359e7801d59Ssowmini 	(void) snprintf(lbuf.laggr_flags, sizeof (lbuf.laggr_flags), "%c----",
2360d62bc4baSyz147064 	    ginfop->lg_force ? 'f' : '-');
2361e7801d59Ssowmini 
2362*8002d411SSowmini Varadhan 	ofmt_print(state->gs_ofmt, &lbuf);
2363e7801d59Ssowmini 
2364d62bc4baSyz147064 	return (DLADM_STATUS_OK);
2365d62bc4baSyz147064 }
2366d62bc4baSyz147064 
2367*8002d411SSowmini Varadhan static boolean_t
2368*8002d411SSowmini Varadhan print_xaggr_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
2369d62bc4baSyz147064 {
2370*8002d411SSowmini Varadhan 	const laggr_args_t 	*l = ofarg->ofmt_cbarg;
2371e7801d59Ssowmini 	int 			portnum;
2372e7801d59Ssowmini 	boolean_t		is_port = (l->laggr_lport >= 0);
2373*8002d411SSowmini Varadhan 	static char		tmpbuf[DLADM_STRSIZE];
2374e7801d59Ssowmini 	dladm_aggr_port_attr_t *portp;
2375d62bc4baSyz147064 	dladm_phys_attr_t	dpa;
2376*8002d411SSowmini Varadhan 	dladm_status_t		*stat, status = DLADM_STATUS_OK;
2377d62bc4baSyz147064 
2378e7801d59Ssowmini 	stat = l->laggr_status;
2379d62bc4baSyz147064 
2380e7801d59Ssowmini 	if (is_port) {
2381e7801d59Ssowmini 		portnum = l->laggr_lport;
2382e7801d59Ssowmini 		portp = &(l->laggr_ginfop->lg_ports[portnum]);
23834ac67f02SAnurag S. Maskey 		if ((status = dladm_datalink_id2info(handle,
2384*8002d411SSowmini Varadhan 		    portp->lp_linkid, NULL, NULL, NULL, buf, bufsize)) !=
2385e7801d59Ssowmini 		    DLADM_STATUS_OK) {
2386e7801d59Ssowmini 			goto err;
2387d62bc4baSyz147064 		}
23884ac67f02SAnurag S. Maskey 
23894ac67f02SAnurag S. Maskey 		if ((status = dladm_phys_info(handle, portp->lp_linkid,
23904ac67f02SAnurag S. Maskey 		    &dpa, DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) {
2391e7801d59Ssowmini 			goto err;
2392e7801d59Ssowmini 		}
2393d62bc4baSyz147064 	}
2394d62bc4baSyz147064 
2395*8002d411SSowmini Varadhan 	switch (ofarg->ofmt_id) {
2396e7801d59Ssowmini 	case AGGR_X_LINK:
2397*8002d411SSowmini Varadhan 		(void) snprintf(buf, bufsize, "%s",
2398*8002d411SSowmini Varadhan 		    (is_port && !l->laggr_parsable ? " " : l->laggr_link));
2399e7801d59Ssowmini 		break;
2400e7801d59Ssowmini 	case AGGR_X_PORT:
2401e7801d59Ssowmini 		if (is_port)
2402e7801d59Ssowmini 			break;
2403*8002d411SSowmini Varadhan 		*stat = DLADM_STATUS_OK;
2404*8002d411SSowmini Varadhan 		return (B_TRUE);
2405d62bc4baSyz147064 
2406e7801d59Ssowmini 	case AGGR_X_SPEED:
2407e7801d59Ssowmini 		if (is_port) {
2408*8002d411SSowmini Varadhan 			(void) snprintf(buf, bufsize, "%uMb",
2409e7801d59Ssowmini 			    (uint_t)((get_ifspeed(dpa.dp_dev,
2410e7801d59Ssowmini 			    B_FALSE)) / 1000000ull));
2411e7801d59Ssowmini 		} else {
2412*8002d411SSowmini Varadhan 			(void) snprintf(buf, bufsize, "%uMb",
2413e7801d59Ssowmini 			    (uint_t)((get_ifspeed(l->laggr_link,
2414e7801d59Ssowmini 			    B_TRUE)) / 1000000ull));
2415e7801d59Ssowmini 		}
2416e7801d59Ssowmini 		break;
2417e7801d59Ssowmini 
2418e7801d59Ssowmini 	case AGGR_X_DUPLEX:
2419e7801d59Ssowmini 		if (is_port)
2420*8002d411SSowmini Varadhan 			(void) get_linkduplex(dpa.dp_dev, B_FALSE, tmpbuf);
2421d62bc4baSyz147064 		else
2422*8002d411SSowmini Varadhan 			(void) get_linkduplex(l->laggr_link, B_TRUE, tmpbuf);
2423*8002d411SSowmini Varadhan 		(void) strlcpy(buf, tmpbuf, bufsize);
2424e7801d59Ssowmini 		break;
2425d62bc4baSyz147064 
2426e7801d59Ssowmini 	case AGGR_X_STATE:
24271a1811a0Svs226613 		if (is_port)
2428*8002d411SSowmini Varadhan 			(void) get_linkstate(dpa.dp_dev,  B_FALSE, tmpbuf);
24291a1811a0Svs226613 		else
2430*8002d411SSowmini Varadhan 			(void) get_linkstate(l->laggr_link, B_TRUE, tmpbuf);
2431*8002d411SSowmini Varadhan 		(void) strlcpy(buf, tmpbuf, bufsize);
2432e7801d59Ssowmini 		break;
2433e7801d59Ssowmini 	case AGGR_X_ADDRESS:
2434e7801d59Ssowmini 		(void) dladm_aggr_macaddr2str(
2435e7801d59Ssowmini 		    (is_port ? portp->lp_mac : l->laggr_ginfop->lg_mac),
2436*8002d411SSowmini Varadhan 		    tmpbuf);
2437*8002d411SSowmini Varadhan 		(void) strlcpy(buf, tmpbuf, bufsize);
2438e7801d59Ssowmini 		break;
2439e7801d59Ssowmini 	case AGGR_X_PORTSTATE:
2440*8002d411SSowmini Varadhan 		if (is_port) {
2441*8002d411SSowmini Varadhan 			(void) dladm_aggr_portstate2str(portp->lp_state,
2442*8002d411SSowmini Varadhan 			    tmpbuf);
2443*8002d411SSowmini Varadhan 			(void) strlcpy(buf, tmpbuf, bufsize);
2444*8002d411SSowmini Varadhan 		}
2445e7801d59Ssowmini 		break;
2446e7801d59Ssowmini 	}
2447e7801d59Ssowmini err:
2448e7801d59Ssowmini 	*stat = status;
2449*8002d411SSowmini Varadhan 	return (B_TRUE);
2450e7801d59Ssowmini }
2451e7801d59Ssowmini 
2452e7801d59Ssowmini static dladm_status_t
2453e7801d59Ssowmini print_aggr_extended(show_grp_state_t *state, const char *link,
2454e7801d59Ssowmini     dladm_aggr_grp_attr_t *ginfop)
2455e7801d59Ssowmini {
2456e7801d59Ssowmini 	int			i;
2457e7801d59Ssowmini 	dladm_status_t		status;
2458e7801d59Ssowmini 	laggr_args_t		largs;
2459e7801d59Ssowmini 
2460e7801d59Ssowmini 	largs.laggr_lport = -1;
2461e7801d59Ssowmini 	largs.laggr_link = link;
2462e7801d59Ssowmini 	largs.laggr_ginfop = ginfop;
2463e7801d59Ssowmini 	largs.laggr_status = &status;
2464*8002d411SSowmini Varadhan 	largs.laggr_parsable = state->gs_parsable;
2465e7801d59Ssowmini 
2466*8002d411SSowmini Varadhan 	ofmt_print(state->gs_ofmt, &largs);
2467e7801d59Ssowmini 
2468e7801d59Ssowmini 	if (status != DLADM_STATUS_OK)
2469e7801d59Ssowmini 		goto done;
2470e7801d59Ssowmini 
2471e7801d59Ssowmini 	for (i = 0; i < ginfop->lg_nports; i++) {
2472e7801d59Ssowmini 		largs.laggr_lport = i;
2473*8002d411SSowmini Varadhan 		ofmt_print(state->gs_ofmt, &largs);
2474e7801d59Ssowmini 		if (status != DLADM_STATUS_OK)
2475e7801d59Ssowmini 			goto done;
2476d62bc4baSyz147064 	}
2477d62bc4baSyz147064 
2478d62bc4baSyz147064 	status = DLADM_STATUS_OK;
2479d62bc4baSyz147064 done:
2480d62bc4baSyz147064 	return (status);
2481d62bc4baSyz147064 }
2482d62bc4baSyz147064 
2483*8002d411SSowmini Varadhan static boolean_t
2484*8002d411SSowmini Varadhan print_lacp_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
2485e7801d59Ssowmini {
2486*8002d411SSowmini Varadhan 	const laggr_args_t	*l = ofarg->ofmt_cbarg;
2487e7801d59Ssowmini 	int			portnum;
2488e7801d59Ssowmini 	boolean_t		is_port = (l->laggr_lport >= 0);
2489e7801d59Ssowmini 	dladm_aggr_port_attr_t	*portp;
2490e7801d59Ssowmini 	dladm_status_t		*stat, status;
2491e7801d59Ssowmini 	aggr_lacp_state_t	*lstate;
2492e7801d59Ssowmini 
2493e7801d59Ssowmini 	if (!is_port) {
2494*8002d411SSowmini Varadhan 		return (B_FALSE); /* cannot happen! */
2495e7801d59Ssowmini 	}
2496e7801d59Ssowmini 
2497e7801d59Ssowmini 	stat = l->laggr_status;
2498e7801d59Ssowmini 
2499e7801d59Ssowmini 	portnum = l->laggr_lport;
2500e7801d59Ssowmini 	portp = &(l->laggr_ginfop->lg_ports[portnum]);
25014ac67f02SAnurag S. Maskey 
25024ac67f02SAnurag S. Maskey 	if ((status = dladm_datalink_id2info(handle, portp->lp_linkid,
2503*8002d411SSowmini Varadhan 	    NULL, NULL, NULL, buf, bufsize)) != DLADM_STATUS_OK) {
2504e7801d59Ssowmini 			goto err;
2505e7801d59Ssowmini 	}
2506e7801d59Ssowmini 	lstate = &(portp->lp_lacp_state);
2507e7801d59Ssowmini 
2508*8002d411SSowmini Varadhan 	switch (ofarg->ofmt_id) {
2509e7801d59Ssowmini 	case AGGR_L_LINK:
2510*8002d411SSowmini Varadhan 		(void) snprintf(buf, bufsize, "%s",
2511e7801d59Ssowmini 		    (portnum > 0 ? "" : l->laggr_link));
2512e7801d59Ssowmini 		break;
2513e7801d59Ssowmini 
2514e7801d59Ssowmini 	case AGGR_L_PORT:
2515*8002d411SSowmini Varadhan 		/*
2516*8002d411SSowmini Varadhan 		 * buf already contains portname as a result of the
2517*8002d411SSowmini Varadhan 		 * earlier call to dladm_datalink_id2info().
2518*8002d411SSowmini Varadhan 		 */
2519e7801d59Ssowmini 		break;
2520e7801d59Ssowmini 
2521e7801d59Ssowmini 	case AGGR_L_AGGREGATABLE:
2522*8002d411SSowmini Varadhan 		(void) snprintf(buf, bufsize, "%s",
2523e7801d59Ssowmini 		    (lstate->bit.aggregation ? "yes" : "no"));
2524e7801d59Ssowmini 		break;
2525e7801d59Ssowmini 
2526e7801d59Ssowmini 	case AGGR_L_SYNC:
2527*8002d411SSowmini Varadhan 		(void) snprintf(buf, bufsize, "%s",
2528e7801d59Ssowmini 		    (lstate->bit.sync ? "yes" : "no"));
2529e7801d59Ssowmini 		break;
2530e7801d59Ssowmini 
2531e7801d59Ssowmini 	case AGGR_L_COLL:
2532*8002d411SSowmini Varadhan 		(void) snprintf(buf, bufsize, "%s",
2533e7801d59Ssowmini 		    (lstate->bit.collecting ? "yes" : "no"));
2534e7801d59Ssowmini 		break;
2535e7801d59Ssowmini 
2536e7801d59Ssowmini 	case AGGR_L_DIST:
2537*8002d411SSowmini Varadhan 		(void) snprintf(buf, bufsize, "%s",
2538e7801d59Ssowmini 		    (lstate->bit.distributing ? "yes" : "no"));
2539e7801d59Ssowmini 		break;
2540e7801d59Ssowmini 
2541e7801d59Ssowmini 	case AGGR_L_DEFAULTED:
2542*8002d411SSowmini Varadhan 		(void) snprintf(buf, bufsize, "%s",
2543e7801d59Ssowmini 		    (lstate->bit.defaulted ? "yes" : "no"));
2544e7801d59Ssowmini 		break;
2545e7801d59Ssowmini 
2546e7801d59Ssowmini 	case AGGR_L_EXPIRED:
2547*8002d411SSowmini Varadhan 		(void) snprintf(buf, bufsize, "%s",
2548e7801d59Ssowmini 		    (lstate->bit.expired ? "yes" : "no"));
2549e7801d59Ssowmini 		break;
2550e7801d59Ssowmini 	}
2551e7801d59Ssowmini 
2552e7801d59Ssowmini 	*stat = DLADM_STATUS_OK;
2553*8002d411SSowmini Varadhan 	return (B_TRUE);
2554e7801d59Ssowmini 
2555e7801d59Ssowmini err:
2556e7801d59Ssowmini 	*stat = status;
2557*8002d411SSowmini Varadhan 	return (B_TRUE);
2558e7801d59Ssowmini }
2559e7801d59Ssowmini 
2560d62bc4baSyz147064 static dladm_status_t
2561d62bc4baSyz147064 print_aggr_lacp(show_grp_state_t *state, const char *link,
2562e7801d59Ssowmini     dladm_aggr_grp_attr_t *ginfop)
2563d62bc4baSyz147064 {
2564d62bc4baSyz147064 	int		i;
2565d62bc4baSyz147064 	dladm_status_t	status;
2566e7801d59Ssowmini 	laggr_args_t	largs;
2567d62bc4baSyz147064 
2568e7801d59Ssowmini 	largs.laggr_link = link;
2569e7801d59Ssowmini 	largs.laggr_ginfop = ginfop;
2570e7801d59Ssowmini 	largs.laggr_status = &status;
2571d62bc4baSyz147064 
2572e7801d59Ssowmini 	for (i = 0; i < ginfop->lg_nports; i++) {
2573e7801d59Ssowmini 		largs.laggr_lport = i;
2574*8002d411SSowmini Varadhan 		ofmt_print(state->gs_ofmt, &largs);
2575d62bc4baSyz147064 		if (status != DLADM_STATUS_OK)
2576d62bc4baSyz147064 			goto done;
2577d62bc4baSyz147064 	}
2578d62bc4baSyz147064 
2579d62bc4baSyz147064 	status = DLADM_STATUS_OK;
2580d62bc4baSyz147064 done:
2581d62bc4baSyz147064 	return (status);
2582d62bc4baSyz147064 }
2583d62bc4baSyz147064 
2584*8002d411SSowmini Varadhan static boolean_t
2585*8002d411SSowmini Varadhan print_aggr_stats_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
2586e7801d59Ssowmini {
2587*8002d411SSowmini Varadhan 	const laggr_args_t	*l = ofarg->ofmt_cbarg;
2588e7801d59Ssowmini 	int 			portnum;
2589e7801d59Ssowmini 	boolean_t		is_port = (l->laggr_lport >= 0);
2590e7801d59Ssowmini 	dladm_aggr_port_attr_t	*portp;
2591e7801d59Ssowmini 	dladm_phys_attr_t	dpa;
2592e7801d59Ssowmini 	dladm_status_t		*stat, status;
2593e7801d59Ssowmini 	pktsum_t		port_stat, diff_stats;
2594e7801d59Ssowmini 
2595e7801d59Ssowmini 	stat = l->laggr_status;
2596e7801d59Ssowmini 	*stat = DLADM_STATUS_OK;
2597e7801d59Ssowmini 
2598e7801d59Ssowmini 	if (is_port) {
2599e7801d59Ssowmini 		portnum = l->laggr_lport;
2600e7801d59Ssowmini 		portp = &(l->laggr_ginfop->lg_ports[portnum]);
26014ac67f02SAnurag S. Maskey 		if ((status = dladm_phys_info(handle, portp->lp_linkid,
26024ac67f02SAnurag S. Maskey 		    &dpa, DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) {
2603e7801d59Ssowmini 			goto err;
2604e7801d59Ssowmini 		}
2605e7801d59Ssowmini 
2606e7801d59Ssowmini 		get_mac_stats(dpa.dp_dev, &port_stat);
2607e7801d59Ssowmini 
26084ac67f02SAnurag S. Maskey 		if ((status = dladm_datalink_id2info(handle,
2609*8002d411SSowmini Varadhan 		    portp->lp_linkid, NULL, NULL, NULL, buf, bufsize)) !=
26104ac67f02SAnurag S. Maskey 		    DLADM_STATUS_OK) {
2611e7801d59Ssowmini 			goto err;
2612e7801d59Ssowmini 		}
2613e7801d59Ssowmini 
2614da14cebeSEric Cheng 		dladm_stats_diff(&diff_stats, &port_stat, l->laggr_prevstats);
2615e7801d59Ssowmini 	}
2616e7801d59Ssowmini 
2617*8002d411SSowmini Varadhan 	switch (ofarg->ofmt_id) {
2618e7801d59Ssowmini 	case AGGR_S_LINK:
2619*8002d411SSowmini Varadhan 		(void) snprintf(buf, bufsize, "%s",
2620e7801d59Ssowmini 		    (is_port ? "" : l->laggr_link));
2621e7801d59Ssowmini 		break;
2622e7801d59Ssowmini 	case AGGR_S_PORT:
2623*8002d411SSowmini Varadhan 		/*
2624*8002d411SSowmini Varadhan 		 * if (is_port), buf has port name. Otherwise we print
2625*8002d411SSowmini Varadhan 		 * STR_UNDEF_VAL
2626*8002d411SSowmini Varadhan 		 */
2627e7801d59Ssowmini 		break;
2628e7801d59Ssowmini 
2629e7801d59Ssowmini 	case AGGR_S_IPKTS:
2630e7801d59Ssowmini 		if (is_port) {
2631*8002d411SSowmini Varadhan 			(void) snprintf(buf, bufsize, "%llu",
2632e7801d59Ssowmini 			    diff_stats.ipackets);
2633e7801d59Ssowmini 		} else {
2634*8002d411SSowmini Varadhan 			(void) snprintf(buf, bufsize, "%llu",
2635e7801d59Ssowmini 			    l->laggr_pktsumtot->ipackets);
2636e7801d59Ssowmini 		}
2637e7801d59Ssowmini 		break;
2638e7801d59Ssowmini 
2639e7801d59Ssowmini 	case AGGR_S_RBYTES:
2640e7801d59Ssowmini 		if (is_port) {
2641*8002d411SSowmini Varadhan 			(void) snprintf(buf, bufsize, "%llu",
2642e7801d59Ssowmini 			    diff_stats.rbytes);
2643e7801d59Ssowmini 		} else {
2644*8002d411SSowmini Varadhan 			(void) snprintf(buf, bufsize, "%llu",
2645e7801d59Ssowmini 			    l->laggr_pktsumtot->rbytes);
2646e7801d59Ssowmini 		}
2647e7801d59Ssowmini 		break;
2648e7801d59Ssowmini 
2649e7801d59Ssowmini 	case AGGR_S_OPKTS:
2650e7801d59Ssowmini 		if (is_port) {
2651*8002d411SSowmini Varadhan 			(void) snprintf(buf, bufsize, "%llu",
2652e7801d59Ssowmini 			    diff_stats.opackets);
2653e7801d59Ssowmini 		} else {
2654*8002d411SSowmini Varadhan 			(void) snprintf(buf, bufsize, "%llu",
2655e7801d59Ssowmini 			    l->laggr_pktsumtot->opackets);
2656e7801d59Ssowmini 		}
2657e7801d59Ssowmini 		break;
2658e7801d59Ssowmini 	case AGGR_S_OBYTES:
2659e7801d59Ssowmini 		if (is_port) {
2660*8002d411SSowmini Varadhan 			(void) snprintf(buf, bufsize, "%llu",
2661e7801d59Ssowmini 			    diff_stats.obytes);
2662e7801d59Ssowmini 		} else {
2663*8002d411SSowmini Varadhan 			(void) snprintf(buf, bufsize, "%llu",
2664e7801d59Ssowmini 			    l->laggr_pktsumtot->obytes);
2665e7801d59Ssowmini 		}
2666e7801d59Ssowmini 		break;
2667e7801d59Ssowmini 
2668e7801d59Ssowmini 	case AGGR_S_IPKTDIST:
2669e7801d59Ssowmini 		if (is_port) {
2670*8002d411SSowmini Varadhan 			(void) snprintf(buf, bufsize, "%-6.1f",
2671e7801d59Ssowmini 			    (double)diff_stats.opackets/
2672e7801d59Ssowmini 			    (double)l->laggr_pktsumtot->ipackets * 100);
2673e7801d59Ssowmini 		}
2674e7801d59Ssowmini 		break;
2675e7801d59Ssowmini 	case AGGR_S_OPKTDIST:
2676e7801d59Ssowmini 		if (is_port) {
2677*8002d411SSowmini Varadhan 			(void) snprintf(buf, bufsize, "%-6.1f",
2678e7801d59Ssowmini 			    (double)diff_stats.opackets/
2679e7801d59Ssowmini 			    (double)l->laggr_pktsumtot->opackets * 100);
2680e7801d59Ssowmini 		}
2681e7801d59Ssowmini 		break;
2682e7801d59Ssowmini 	}
2683*8002d411SSowmini Varadhan 	return (B_TRUE);
2684e7801d59Ssowmini 
2685e7801d59Ssowmini err:
2686e7801d59Ssowmini 	*stat = status;
2687*8002d411SSowmini Varadhan 	return (B_TRUE);
2688e7801d59Ssowmini }
2689e7801d59Ssowmini 
2690d62bc4baSyz147064 static dladm_status_t
2691d62bc4baSyz147064 print_aggr_stats(show_grp_state_t *state, const char *link,
2692e7801d59Ssowmini     dladm_aggr_grp_attr_t *ginfop)
2693d62bc4baSyz147064 {
2694d62bc4baSyz147064 	dladm_phys_attr_t	dpa;
2695d62bc4baSyz147064 	dladm_aggr_port_attr_t	*portp;
2696d62bc4baSyz147064 	pktsum_t		pktsumtot, port_stat;
2697d62bc4baSyz147064 	dladm_status_t		status;
2698d62bc4baSyz147064 	int			i;
2699e7801d59Ssowmini 	laggr_args_t		largs;
27007c478bd9Sstevel@tonic-gate 
27017c478bd9Sstevel@tonic-gate 	/* sum the ports statistics */
27027c478bd9Sstevel@tonic-gate 	bzero(&pktsumtot, sizeof (pktsumtot));
2703d62bc4baSyz147064 
2704d62bc4baSyz147064 	for (i = 0; i < ginfop->lg_nports; i++) {
2705d62bc4baSyz147064 
2706d62bc4baSyz147064 		portp = &(ginfop->lg_ports[i]);
27074ac67f02SAnurag S. Maskey 		if ((status = dladm_phys_info(handle, portp->lp_linkid, &dpa,
2708d62bc4baSyz147064 		    DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) {
2709d62bc4baSyz147064 			goto done;
27107c478bd9Sstevel@tonic-gate 		}
27117c478bd9Sstevel@tonic-gate 
2712d62bc4baSyz147064 		get_mac_stats(dpa.dp_dev, &port_stat);
2713da14cebeSEric Cheng 		dladm_stats_total(&pktsumtot, &port_stat,
2714da14cebeSEric Cheng 		    &state->gs_prevstats[i]);
27157c478bd9Sstevel@tonic-gate 	}
27167c478bd9Sstevel@tonic-gate 
2717e7801d59Ssowmini 	largs.laggr_lport = -1;
2718e7801d59Ssowmini 	largs.laggr_link = link;
2719e7801d59Ssowmini 	largs.laggr_ginfop = ginfop;
2720e7801d59Ssowmini 	largs.laggr_status = &status;
2721e7801d59Ssowmini 	largs.laggr_pktsumtot = &pktsumtot;
2722e7801d59Ssowmini 
2723*8002d411SSowmini Varadhan 	ofmt_print(state->gs_ofmt, &largs);
2724e7801d59Ssowmini 
2725e7801d59Ssowmini 	if (status != DLADM_STATUS_OK)
2726e7801d59Ssowmini 		goto done;
2727d62bc4baSyz147064 
2728d62bc4baSyz147064 	for (i = 0; i < ginfop->lg_nports; i++) {
2729e7801d59Ssowmini 		largs.laggr_lport = i;
2730e7801d59Ssowmini 		largs.laggr_prevstats = &state->gs_prevstats[i];
2731*8002d411SSowmini Varadhan 		ofmt_print(state->gs_ofmt, &largs);
2732e7801d59Ssowmini 		if (status != DLADM_STATUS_OK)
2733d62bc4baSyz147064 			goto done;
2734d62bc4baSyz147064 	}
2735d62bc4baSyz147064 
2736d62bc4baSyz147064 	status = DLADM_STATUS_OK;
2737d62bc4baSyz147064 done:
2738d62bc4baSyz147064 	return (status);
2739d62bc4baSyz147064 }
2740d62bc4baSyz147064 
2741d62bc4baSyz147064 static dladm_status_t
2742e7801d59Ssowmini print_aggr(show_grp_state_t *state, datalink_id_t linkid)
2743d62bc4baSyz147064 {
2744d62bc4baSyz147064 	char			link[MAXLINKNAMELEN];
2745d62bc4baSyz147064 	dladm_aggr_grp_attr_t	ginfo;
2746d62bc4baSyz147064 	uint32_t		flags;
2747d62bc4baSyz147064 	dladm_status_t		status;
2748d62bc4baSyz147064 
27495f5c9f54SAnurag S. Maskey 	bzero(&ginfo, sizeof (dladm_aggr_grp_attr_t));
27504ac67f02SAnurag S. Maskey 	if ((status = dladm_datalink_id2info(handle, linkid, &flags, NULL,
27514ac67f02SAnurag S. Maskey 	    NULL, link, MAXLINKNAMELEN)) != DLADM_STATUS_OK) {
2752d62bc4baSyz147064 		return (status);
2753d62bc4baSyz147064 	}
2754d62bc4baSyz147064 
2755d62bc4baSyz147064 	if (!(state->gs_flags & flags))
2756d62bc4baSyz147064 		return (DLADM_STATUS_NOTFOUND);
2757d62bc4baSyz147064 
27584ac67f02SAnurag S. Maskey 	status = dladm_aggr_info(handle, linkid, &ginfo, state->gs_flags);
2759d62bc4baSyz147064 	if (status != DLADM_STATUS_OK)
2760d62bc4baSyz147064 		return (status);
2761d62bc4baSyz147064 
2762d62bc4baSyz147064 	if (state->gs_lacp)
2763e7801d59Ssowmini 		status = print_aggr_lacp(state, link, &ginfo);
2764d62bc4baSyz147064 	else if (state->gs_extended)
2765e7801d59Ssowmini 		status = print_aggr_extended(state, link, &ginfo);
2766d62bc4baSyz147064 	else if (state->gs_stats)
2767e7801d59Ssowmini 		status = print_aggr_stats(state, link, &ginfo);
27684ac67f02SAnurag S. Maskey 	else
2769e7801d59Ssowmini 		status = print_aggr_info(state, link, &ginfo);
2770d62bc4baSyz147064 
2771d62bc4baSyz147064 done:
2772d62bc4baSyz147064 	free(ginfo.lg_ports);
2773d62bc4baSyz147064 	return (status);
2774d62bc4baSyz147064 }
2775d62bc4baSyz147064 
27764ac67f02SAnurag S. Maskey /* ARGSUSED */
2777d62bc4baSyz147064 static int
27784ac67f02SAnurag S. Maskey show_aggr(dladm_handle_t dh, datalink_id_t linkid, void *arg)
2779d62bc4baSyz147064 {
2780d62bc4baSyz147064 	show_grp_state_t	*state = arg;
2781d62bc4baSyz147064 
2782*8002d411SSowmini Varadhan 	state->gs_status = print_aggr(state, linkid);
2783d62bc4baSyz147064 	return (DLADM_WALK_CONTINUE);
27847c478bd9Sstevel@tonic-gate }
27857c478bd9Sstevel@tonic-gate 
27867c478bd9Sstevel@tonic-gate static void
27878d5c46e6Sam223141 do_show_link(int argc, char *argv[], const char *use)
27887c478bd9Sstevel@tonic-gate {
27897c478bd9Sstevel@tonic-gate 	int		option;
27907c478bd9Sstevel@tonic-gate 	boolean_t	s_arg = B_FALSE;
2791da14cebeSEric Cheng 	boolean_t	S_arg = B_FALSE;
27927c478bd9Sstevel@tonic-gate 	boolean_t	i_arg = B_FALSE;
2793d62bc4baSyz147064 	uint32_t	flags = DLADM_OPT_ACTIVE;
2794d62bc4baSyz147064 	boolean_t	p_arg = B_FALSE;
2795d62bc4baSyz147064 	datalink_id_t	linkid = DATALINK_ALL_LINKID;
2796da14cebeSEric Cheng 	char		linkname[MAXLINKNAMELEN];
279763a6526dSMichael Lim 	uint32_t	interval = 0;
2798d62bc4baSyz147064 	show_state_t	state;
2799d62bc4baSyz147064 	dladm_status_t	status;
2800e7801d59Ssowmini 	boolean_t	o_arg = B_FALSE;
2801e7801d59Ssowmini 	char		*fields_str = NULL;
2802e7801d59Ssowmini 	char		*all_active_fields = "link,class,mtu,state,over";
2803e7801d59Ssowmini 	char		*all_inactive_fields = "link,class,over";
28046be03d0bSVasumathi Sundaram - Sun Microsystems 	char		*allstat_fields =
28056be03d0bSVasumathi Sundaram - Sun Microsystems 	    "link,ipackets,rbytes,ierrors,opackets,obytes,oerrors";
2806*8002d411SSowmini Varadhan 	ofmt_handle_t	ofmt;
2807*8002d411SSowmini Varadhan 	ofmt_status_t	oferr;
2808*8002d411SSowmini Varadhan 	uint_t		ofmtflags = 0;
2809e7801d59Ssowmini 
2810e7801d59Ssowmini 	bzero(&state, sizeof (state));
28117c478bd9Sstevel@tonic-gate 
28127c478bd9Sstevel@tonic-gate 	opterr = 0;
2813da14cebeSEric Cheng 	while ((option = getopt_long(argc, argv, ":pPsSi:o:",
2814d62bc4baSyz147064 	    show_lopts, NULL)) != -1) {
28157c478bd9Sstevel@tonic-gate 		switch (option) {
28167c478bd9Sstevel@tonic-gate 		case 'p':
2817d62bc4baSyz147064 			if (p_arg)
2818d62bc4baSyz147064 				die_optdup(option);
2819d62bc4baSyz147064 
2820d62bc4baSyz147064 			p_arg = B_TRUE;
28217c478bd9Sstevel@tonic-gate 			break;
28227c478bd9Sstevel@tonic-gate 		case 's':
282333343a97Smeem 			if (s_arg)
282433343a97Smeem 				die_optdup(option);
28257c478bd9Sstevel@tonic-gate 
28267c478bd9Sstevel@tonic-gate 			s_arg = B_TRUE;
28277c478bd9Sstevel@tonic-gate 			break;
2828d62bc4baSyz147064 		case 'P':
2829d62bc4baSyz147064 			if (flags != DLADM_OPT_ACTIVE)
2830d62bc4baSyz147064 				die_optdup(option);
2831d62bc4baSyz147064 
2832d62bc4baSyz147064 			flags = DLADM_OPT_PERSIST;
2833d62bc4baSyz147064 			break;
2834da14cebeSEric Cheng 		case 'S':
2835da14cebeSEric Cheng 			if (S_arg)
2836da14cebeSEric Cheng 				die_optdup(option);
2837da14cebeSEric Cheng 
2838da14cebeSEric Cheng 			S_arg = B_TRUE;
2839da14cebeSEric Cheng 			break;
2840e7801d59Ssowmini 		case 'o':
2841e7801d59Ssowmini 			o_arg = B_TRUE;
2842e7801d59Ssowmini 			fields_str = optarg;
2843e7801d59Ssowmini 			break;
28447c478bd9Sstevel@tonic-gate 		case 'i':
284533343a97Smeem 			if (i_arg)
284633343a97Smeem 				die_optdup(option);
28477c478bd9Sstevel@tonic-gate 
28487c478bd9Sstevel@tonic-gate 			i_arg = B_TRUE;
284963a6526dSMichael Lim 			if (!dladm_str2interval(optarg, &interval))
285033343a97Smeem 				die("invalid interval value '%s'", optarg);
28517c478bd9Sstevel@tonic-gate 			break;
28527c478bd9Sstevel@tonic-gate 		default:
28538d5c46e6Sam223141 			die_opterr(optopt, option, use);
285433343a97Smeem 			break;
28557c478bd9Sstevel@tonic-gate 		}
28567c478bd9Sstevel@tonic-gate 	}
28577c478bd9Sstevel@tonic-gate 
2858da14cebeSEric Cheng 	if (i_arg && !(s_arg || S_arg))
2859da14cebeSEric Cheng 		die("the option -i can be used only with -s or -S");
2860da14cebeSEric Cheng 
2861da14cebeSEric Cheng 	if (s_arg && S_arg)
2862da14cebeSEric Cheng 		die("the -s option cannot be used with -S");
28637c478bd9Sstevel@tonic-gate 
28646be03d0bSVasumathi Sundaram - Sun Microsystems 	if (s_arg && flags != DLADM_OPT_ACTIVE)
28656be03d0bSVasumathi Sundaram - Sun Microsystems 		die("the option -P cannot be used with -s");
2866d62bc4baSyz147064 
2867da14cebeSEric Cheng 	if (S_arg && (p_arg || flags != DLADM_OPT_ACTIVE))
2868da14cebeSEric Cheng 		die("the option -%c cannot be used with -S", p_arg ? 'p' : 'P');
2869da14cebeSEric Cheng 
28707c478bd9Sstevel@tonic-gate 	/* get link name (optional last argument) */
2871d62bc4baSyz147064 	if (optind == (argc-1)) {
2872d62bc4baSyz147064 		uint32_t	f;
2873d62bc4baSyz147064 
2874da14cebeSEric Cheng 		if (strlcpy(linkname, argv[optind], MAXLINKNAMELEN)
2875da14cebeSEric Cheng 		    >= MAXLINKNAMELEN) {
2876da14cebeSEric Cheng 			(void) fprintf(stderr,
2877da14cebeSEric Cheng 			    gettext("%s: link name too long\n"),
2878da14cebeSEric Cheng 			    progname);
28794ac67f02SAnurag S. Maskey 			dladm_close(handle);
2880da14cebeSEric Cheng 			exit(1);
2881da14cebeSEric Cheng 		}
28824ac67f02SAnurag S. Maskey 		if ((status = dladm_name2info(handle, linkname, &linkid, &f,
2883d62bc4baSyz147064 		    NULL, NULL)) != DLADM_STATUS_OK) {
2884da14cebeSEric Cheng 			die_dlerr(status, "link %s is not valid", linkname);
2885d62bc4baSyz147064 		}
2886d62bc4baSyz147064 
2887d62bc4baSyz147064 		if (!(f & flags)) {
2888d62bc4baSyz147064 			die_dlerr(DLADM_STATUS_BADARG, "link %s is %s",
2889d62bc4baSyz147064 			    argv[optind], flags == DLADM_OPT_PERSIST ?
2890d62bc4baSyz147064 			    "a temporary link" : "temporarily removed");
2891d62bc4baSyz147064 		}
2892d62bc4baSyz147064 	} else if (optind != argc) {
28937c478bd9Sstevel@tonic-gate 		usage();
2894d62bc4baSyz147064 	}
28957c478bd9Sstevel@tonic-gate 
28960d365605Sschuster 	if (p_arg && !o_arg)
28970d365605Sschuster 		die("-p requires -o");
28980d365605Sschuster 
2899da14cebeSEric Cheng 	if (S_arg) {
29004ac67f02SAnurag S. Maskey 		dladm_continuous(handle, linkid, NULL, interval, LINK_REPORT);
2901da14cebeSEric Cheng 		return;
2902da14cebeSEric Cheng 	}
2903da14cebeSEric Cheng 
29040d365605Sschuster 	if (p_arg && strcasecmp(fields_str, "all") == 0)
29050d365605Sschuster 		die("\"-o all\" is invalid with -p");
29060d365605Sschuster 
2907e7801d59Ssowmini 	if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) {
29086be03d0bSVasumathi Sundaram - Sun Microsystems 		if (s_arg)
29096be03d0bSVasumathi Sundaram - Sun Microsystems 			fields_str = allstat_fields;
29106be03d0bSVasumathi Sundaram - Sun Microsystems 		else if (flags & DLADM_OPT_ACTIVE)
2911e7801d59Ssowmini 			fields_str = all_active_fields;
2912e7801d59Ssowmini 		else
2913e7801d59Ssowmini 			fields_str = all_inactive_fields;
2914e7801d59Ssowmini 	}
2915e7801d59Ssowmini 
2916*8002d411SSowmini Varadhan 	state.ls_parsable = p_arg;
29176be03d0bSVasumathi Sundaram - Sun Microsystems 	state.ls_flags = flags;
29186be03d0bSVasumathi Sundaram - Sun Microsystems 	state.ls_donefirst = B_FALSE;
29196be03d0bSVasumathi Sundaram - Sun Microsystems 
29206be03d0bSVasumathi Sundaram - Sun Microsystems 	if (s_arg) {
29216be03d0bSVasumathi Sundaram - Sun Microsystems 		link_stats(linkid, interval, fields_str, &state);
29226be03d0bSVasumathi Sundaram - Sun Microsystems 		return;
29236be03d0bSVasumathi Sundaram - Sun Microsystems 	}
2924*8002d411SSowmini Varadhan 	if (state.ls_parsable)
2925*8002d411SSowmini Varadhan 		ofmtflags |= OFMT_PARSABLE;
2926*8002d411SSowmini Varadhan 	oferr = ofmt_open(fields_str, link_fields, ofmtflags, 0, &ofmt);
2927*8002d411SSowmini Varadhan 	dladm_ofmt_check(oferr, state.ls_parsable, ofmt);
2928*8002d411SSowmini Varadhan 	state.ls_ofmt = ofmt;
2929e7801d59Ssowmini 
2930d62bc4baSyz147064 	if (linkid == DATALINK_ALL_LINKID) {
29314ac67f02SAnurag S. Maskey 		(void) dladm_walk_datalink_id(show_link, handle, &state,
2932d62bc4baSyz147064 		    DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE, flags);
2933210db224Sericheng 	} else {
29344ac67f02SAnurag S. Maskey 		(void) show_link(handle, linkid, &state);
2935d62bc4baSyz147064 		if (state.ls_status != DLADM_STATUS_OK) {
2936d62bc4baSyz147064 			die_dlerr(state.ls_status, "failed to show link %s",
2937d62bc4baSyz147064 			    argv[optind]);
2938d62bc4baSyz147064 		}
29397c478bd9Sstevel@tonic-gate 	}
2940*8002d411SSowmini Varadhan 	ofmt_close(ofmt);
2941210db224Sericheng }
29427c478bd9Sstevel@tonic-gate 
29437c478bd9Sstevel@tonic-gate static void
29448d5c46e6Sam223141 do_show_aggr(int argc, char *argv[], const char *use)
29457c478bd9Sstevel@tonic-gate {
29467c478bd9Sstevel@tonic-gate 	boolean_t		L_arg = B_FALSE;
29477c478bd9Sstevel@tonic-gate 	boolean_t		s_arg = B_FALSE;
29487c478bd9Sstevel@tonic-gate 	boolean_t		i_arg = B_FALSE;
2949d62bc4baSyz147064 	boolean_t		p_arg = B_FALSE;
2950d62bc4baSyz147064 	boolean_t		x_arg = B_FALSE;
29517c478bd9Sstevel@tonic-gate 	show_grp_state_t	state;
2952d62bc4baSyz147064 	uint32_t		flags = DLADM_OPT_ACTIVE;
2953d62bc4baSyz147064 	datalink_id_t		linkid = DATALINK_ALL_LINKID;
2954d62bc4baSyz147064 	int			option;
295563a6526dSMichael Lim 	uint32_t		interval = 0;
2956d62bc4baSyz147064 	int			key;
2957d62bc4baSyz147064 	dladm_status_t		status;
2958e7801d59Ssowmini 	boolean_t		o_arg = B_FALSE;
2959e7801d59Ssowmini 	char			*fields_str = NULL;
2960e7801d59Ssowmini 	char			*all_fields =
2961e7801d59Ssowmini 	    "link,policy,addrpolicy,lacpactivity,lacptimer,flags";
2962e7801d59Ssowmini 	char			*all_lacp_fields =
2963e7801d59Ssowmini 	    "link,port,aggregatable,sync,coll,dist,defaulted,expired";
2964e7801d59Ssowmini 	char			*all_stats_fields =
2965e7801d59Ssowmini 	    "link,port,ipackets,rbytes,opackets,obytes,ipktdist,opktdist";
2966e7801d59Ssowmini 	char			*all_extended_fields =
2967e7801d59Ssowmini 	    "link,port,speed,duplex,state,address,portstate";
2968*8002d411SSowmini Varadhan 	ofmt_field_t		*pf;
2969*8002d411SSowmini Varadhan 	ofmt_handle_t		ofmt;
2970*8002d411SSowmini Varadhan 	ofmt_status_t		oferr;
2971*8002d411SSowmini Varadhan 	uint_t			ofmtflags = 0;
2972e7801d59Ssowmini 
2973e7801d59Ssowmini 	bzero(&state, sizeof (state));
29747c478bd9Sstevel@tonic-gate 
29757c478bd9Sstevel@tonic-gate 	opterr = 0;
2976e7801d59Ssowmini 	while ((option = getopt_long(argc, argv, ":LpPxsi:o:",
2977d62bc4baSyz147064 	    show_lopts, NULL)) != -1) {
29787c478bd9Sstevel@tonic-gate 		switch (option) {
29797c478bd9Sstevel@tonic-gate 		case 'L':
298033343a97Smeem 			if (L_arg)
298133343a97Smeem 				die_optdup(option);
29827c478bd9Sstevel@tonic-gate 
29837c478bd9Sstevel@tonic-gate 			L_arg = B_TRUE;
29847c478bd9Sstevel@tonic-gate 			break;
29857c478bd9Sstevel@tonic-gate 		case 'p':
2986d62bc4baSyz147064 			if (p_arg)
2987d62bc4baSyz147064 				die_optdup(option);
2988d62bc4baSyz147064 
2989d62bc4baSyz147064 			p_arg = B_TRUE;
2990d62bc4baSyz147064 			break;
2991d62bc4baSyz147064 		case 'x':
2992d62bc4baSyz147064 			if (x_arg)
2993d62bc4baSyz147064 				die_optdup(option);
2994d62bc4baSyz147064 
2995d62bc4baSyz147064 			x_arg = B_TRUE;
2996d62bc4baSyz147064 			break;
2997d62bc4baSyz147064 		case 'P':
2998d62bc4baSyz147064 			if (flags != DLADM_OPT_ACTIVE)
2999d62bc4baSyz147064 				die_optdup(option);
3000d62bc4baSyz147064 
3001d62bc4baSyz147064 			flags = DLADM_OPT_PERSIST;
30027c478bd9Sstevel@tonic-gate 			break;
30037c478bd9Sstevel@tonic-gate 		case 's':
300433343a97Smeem 			if (s_arg)
300533343a97Smeem 				die_optdup(option);
30067c478bd9Sstevel@tonic-gate 
30077c478bd9Sstevel@tonic-gate 			s_arg = B_TRUE;
30087c478bd9Sstevel@tonic-gate 			break;
3009e7801d59Ssowmini 		case 'o':
3010e7801d59Ssowmini 			o_arg = B_TRUE;
3011e7801d59Ssowmini 			fields_str = optarg;
3012e7801d59Ssowmini 			break;
30137c478bd9Sstevel@tonic-gate 		case 'i':
301433343a97Smeem 			if (i_arg)
301533343a97Smeem 				die_optdup(option);
30167c478bd9Sstevel@tonic-gate 
30177c478bd9Sstevel@tonic-gate 			i_arg = B_TRUE;
301863a6526dSMichael Lim 			if (!dladm_str2interval(optarg, &interval))
301933343a97Smeem 				die("invalid interval value '%s'", optarg);
30207c478bd9Sstevel@tonic-gate 			break;
30217c478bd9Sstevel@tonic-gate 		default:
30228d5c46e6Sam223141 			die_opterr(optopt, option, use);
302333343a97Smeem 			break;
30247c478bd9Sstevel@tonic-gate 		}
30257c478bd9Sstevel@tonic-gate 	}
30267c478bd9Sstevel@tonic-gate 
30270d365605Sschuster 	if (p_arg && !o_arg)
30280d365605Sschuster 		die("-p requires -o");
30290d365605Sschuster 
30300d365605Sschuster 	if (p_arg && strcasecmp(fields_str, "all") == 0)
30310d365605Sschuster 		die("\"-o all\" is invalid with -p");
30320d365605Sschuster 
303333343a97Smeem 	if (i_arg && !s_arg)
303433343a97Smeem 		die("the option -i can be used only with -s");
30357c478bd9Sstevel@tonic-gate 
3036d62bc4baSyz147064 	if (s_arg && (L_arg || p_arg || x_arg || flags != DLADM_OPT_ACTIVE)) {
3037d62bc4baSyz147064 		die("the option -%c cannot be used with -s",
3038d62bc4baSyz147064 		    L_arg ? 'L' : (p_arg ? 'p' : (x_arg ? 'x' : 'P')));
3039d62bc4baSyz147064 	}
3040d62bc4baSyz147064 
3041d62bc4baSyz147064 	if (L_arg && flags != DLADM_OPT_ACTIVE)
3042d62bc4baSyz147064 		die("the option -P cannot be used with -L");
3043d62bc4baSyz147064 
3044d62bc4baSyz147064 	if (x_arg && (L_arg || flags != DLADM_OPT_ACTIVE))
3045d62bc4baSyz147064 		die("the option -%c cannot be used with -x", L_arg ? 'L' : 'P');
3046d62bc4baSyz147064 
3047d62bc4baSyz147064 	/* get aggregation key or aggrname (optional last argument) */
30487c478bd9Sstevel@tonic-gate 	if (optind == (argc-1)) {
3049d62bc4baSyz147064 		if (!str2int(argv[optind], &key)) {
30504ac67f02SAnurag S. Maskey 			status = dladm_name2info(handle, argv[optind],
30514ac67f02SAnurag S. Maskey 			    &linkid, NULL, NULL, NULL);
3052d62bc4baSyz147064 		} else {
30534ac67f02SAnurag S. Maskey 			status = dladm_key2linkid(handle, (uint16_t)key,
3054d62bc4baSyz147064 			    &linkid, DLADM_OPT_ACTIVE);
3055d62bc4baSyz147064 		}
3056d62bc4baSyz147064 
3057d62bc4baSyz147064 		if (status != DLADM_STATUS_OK)
3058d62bc4baSyz147064 			die("non-existent aggregation '%s'", argv[optind]);
3059d62bc4baSyz147064 
30607c478bd9Sstevel@tonic-gate 	} else if (optind != argc) {
30617c478bd9Sstevel@tonic-gate 		usage();
30627c478bd9Sstevel@tonic-gate 	}
30637c478bd9Sstevel@tonic-gate 
3064d62bc4baSyz147064 	bzero(&state, sizeof (state));
3065d62bc4baSyz147064 	state.gs_lacp = L_arg;
3066d62bc4baSyz147064 	state.gs_stats = s_arg;
3067d62bc4baSyz147064 	state.gs_flags = flags;
3068*8002d411SSowmini Varadhan 	state.gs_parsable = p_arg;
3069d62bc4baSyz147064 	state.gs_extended = x_arg;
3070d62bc4baSyz147064 
3071e7801d59Ssowmini 	if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) {
3072e7801d59Ssowmini 		if (state.gs_lacp)
3073e7801d59Ssowmini 			fields_str = all_lacp_fields;
3074e7801d59Ssowmini 		else if (state.gs_stats)
3075e7801d59Ssowmini 			fields_str = all_stats_fields;
3076e7801d59Ssowmini 		else if (state.gs_extended)
3077e7801d59Ssowmini 			fields_str = all_extended_fields;
3078e7801d59Ssowmini 		else
3079e7801d59Ssowmini 			fields_str = all_fields;
3080e7801d59Ssowmini 	}
3081e7801d59Ssowmini 
3082e7801d59Ssowmini 	if (state.gs_lacp) {
3083e7801d59Ssowmini 		pf = aggr_l_fields;
3084e7801d59Ssowmini 	} else if (state.gs_stats) {
3085e7801d59Ssowmini 		pf = aggr_s_fields;
3086e7801d59Ssowmini 	} else if (state.gs_extended) {
3087e7801d59Ssowmini 		pf = aggr_x_fields;
3088e7801d59Ssowmini 	} else {
3089e7801d59Ssowmini 		pf = laggr_fields;
3090e7801d59Ssowmini 	}
3091e7801d59Ssowmini 
3092*8002d411SSowmini Varadhan 	if (state.gs_parsable)
3093*8002d411SSowmini Varadhan 		ofmtflags |= OFMT_PARSABLE;
3094*8002d411SSowmini Varadhan 	oferr = ofmt_open(fields_str, pf, ofmtflags, 0, &ofmt);
3095*8002d411SSowmini Varadhan 	dladm_ofmt_check(oferr, state.gs_parsable, ofmt);
3096*8002d411SSowmini Varadhan 	state.gs_ofmt = ofmt;
3097e7801d59Ssowmini 
30987c478bd9Sstevel@tonic-gate 	if (s_arg) {
3099d62bc4baSyz147064 		aggr_stats(linkid, &state, interval);
3100*8002d411SSowmini Varadhan 		ofmt_close(ofmt);
31017c478bd9Sstevel@tonic-gate 		return;
31027c478bd9Sstevel@tonic-gate 	}
31037c478bd9Sstevel@tonic-gate 
3104d62bc4baSyz147064 	if (linkid == DATALINK_ALL_LINKID) {
31054ac67f02SAnurag S. Maskey 		(void) dladm_walk_datalink_id(show_aggr, handle, &state,
3106d62bc4baSyz147064 		    DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE, flags);
3107d62bc4baSyz147064 	} else {
31084ac67f02SAnurag S. Maskey 		(void) show_aggr(handle, linkid, &state);
3109d62bc4baSyz147064 		if (state.gs_status != DLADM_STATUS_OK) {
3110d62bc4baSyz147064 			die_dlerr(state.gs_status, "failed to show aggr %s",
3111d62bc4baSyz147064 			    argv[optind]);
3112d62bc4baSyz147064 		}
3113d62bc4baSyz147064 	}
3114*8002d411SSowmini Varadhan 	ofmt_close(ofmt);
31157c478bd9Sstevel@tonic-gate }
31167c478bd9Sstevel@tonic-gate 
3117da14cebeSEric Cheng static dladm_status_t
3118da14cebeSEric Cheng print_phys_default(show_state_t *state, datalink_id_t linkid,
3119da14cebeSEric Cheng     const char *link, uint32_t flags, uint32_t media)
31207c478bd9Sstevel@tonic-gate {
3121da14cebeSEric Cheng 	dladm_phys_attr_t dpa;
3122da14cebeSEric Cheng 	dladm_status_t status;
3123da14cebeSEric Cheng 	link_fields_buf_t pattr;
3124e7801d59Ssowmini 
31254ac67f02SAnurag S. Maskey 	status = dladm_phys_info(handle, linkid, &dpa, state->ls_flags);
3126da14cebeSEric Cheng 	if (status != DLADM_STATUS_OK)
3127da14cebeSEric Cheng 		goto done;
31287c478bd9Sstevel@tonic-gate 
3129da14cebeSEric Cheng 	(void) snprintf(pattr.link_phys_device,
3130da14cebeSEric Cheng 	    sizeof (pattr.link_phys_device), "%s", dpa.dp_dev);
3131da14cebeSEric Cheng 	(void) dladm_media2str(media, pattr.link_phys_media);
3132da14cebeSEric Cheng 	if (state->ls_flags == DLADM_OPT_ACTIVE) {
3133da14cebeSEric Cheng 		boolean_t	islink;
3134d62bc4baSyz147064 
3135da14cebeSEric Cheng 		if (!dpa.dp_novanity) {
3136da14cebeSEric Cheng 			(void) strlcpy(pattr.link_name, link,
3137da14cebeSEric Cheng 			    sizeof (pattr.link_name));
3138da14cebeSEric Cheng 			islink = B_TRUE;
3139d62bc4baSyz147064 		} else {
3140da14cebeSEric Cheng 			/*
3141da14cebeSEric Cheng 			 * This is a physical link that does not have
3142da14cebeSEric Cheng 			 * vanity naming support.
3143da14cebeSEric Cheng 			 */
3144da14cebeSEric Cheng 			(void) strlcpy(pattr.link_name, dpa.dp_dev,
3145da14cebeSEric Cheng 			    sizeof (pattr.link_name));
3146da14cebeSEric Cheng 			islink = B_FALSE;
31477c478bd9Sstevel@tonic-gate 		}
31487c478bd9Sstevel@tonic-gate 
3149da14cebeSEric Cheng 		(void) get_linkstate(pattr.link_name, islink,
3150da14cebeSEric Cheng 		    pattr.link_phys_state);
3151da14cebeSEric Cheng 		(void) snprintf(pattr.link_phys_speed,
3152da14cebeSEric Cheng 		    sizeof (pattr.link_phys_speed), "%u",
3153da14cebeSEric Cheng 		    (uint_t)((get_ifspeed(pattr.link_name,
3154da14cebeSEric Cheng 		    islink)) / 1000000ull));
3155da14cebeSEric Cheng 		(void) get_linkduplex(pattr.link_name, islink,
3156da14cebeSEric Cheng 		    pattr.link_phys_duplex);
3157da14cebeSEric Cheng 	} else {
3158da14cebeSEric Cheng 		(void) snprintf(pattr.link_name, sizeof (pattr.link_name),
3159da14cebeSEric Cheng 		    "%s", link);
3160da14cebeSEric Cheng 		(void) snprintf(pattr.link_flags, sizeof (pattr.link_flags),
3161da14cebeSEric Cheng 		    "%c----", flags & DLADM_OPT_ACTIVE ? '-' : 'r');
3162da14cebeSEric Cheng 	}
3163da14cebeSEric Cheng 
3164*8002d411SSowmini Varadhan 	ofmt_print(state->ls_ofmt, &pattr);
3165da14cebeSEric Cheng 
3166da14cebeSEric Cheng done:
3167da14cebeSEric Cheng 	return (status);
3168da14cebeSEric Cheng }
3169da14cebeSEric Cheng 
3170da14cebeSEric Cheng typedef struct {
3171da14cebeSEric Cheng 	show_state_t	*ms_state;
3172da14cebeSEric Cheng 	char		*ms_link;
3173da14cebeSEric Cheng 	dladm_macaddr_attr_t *ms_mac_attr;
3174da14cebeSEric Cheng } print_phys_mac_state_t;
3175da14cebeSEric Cheng 
3176*8002d411SSowmini Varadhan /*
3177*8002d411SSowmini Varadhan  *  callback for ofmt_print()
3178*8002d411SSowmini Varadhan  */
3179*8002d411SSowmini Varadhan static boolean_t
3180*8002d411SSowmini Varadhan print_phys_one_mac_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
3181da14cebeSEric Cheng {
3182*8002d411SSowmini Varadhan 	print_phys_mac_state_t *mac_state = ofarg->ofmt_cbarg;
3183da14cebeSEric Cheng 	dladm_macaddr_attr_t *attr = mac_state->ms_mac_attr;
3184da14cebeSEric Cheng 	boolean_t is_primary = (attr->ma_slot == 0);
3185*8002d411SSowmini Varadhan 	boolean_t is_parsable = mac_state->ms_state->ls_parsable;
3186da14cebeSEric Cheng 
3187*8002d411SSowmini Varadhan 	switch (ofarg->ofmt_id) {
3188da14cebeSEric Cheng 	case PHYS_M_LINK:
3189*8002d411SSowmini Varadhan 		(void) snprintf(buf, bufsize, "%s",
3190*8002d411SSowmini Varadhan 		    (is_primary || is_parsable) ? mac_state->ms_link : " ");
3191da14cebeSEric Cheng 		break;
3192da14cebeSEric Cheng 	case PHYS_M_SLOT:
3193da14cebeSEric Cheng 		if (is_primary)
3194*8002d411SSowmini Varadhan 			(void) snprintf(buf, bufsize, gettext("primary"));
3195da14cebeSEric Cheng 		else
3196*8002d411SSowmini Varadhan 			(void) snprintf(buf, bufsize, "%d", attr->ma_slot);
3197da14cebeSEric Cheng 		break;
3198da14cebeSEric Cheng 	case PHYS_M_ADDRESS:
3199da14cebeSEric Cheng 		(void) dladm_aggr_macaddr2str(attr->ma_addr, buf);
3200da14cebeSEric Cheng 		break;
3201da14cebeSEric Cheng 	case PHYS_M_INUSE:
3202*8002d411SSowmini Varadhan 		(void) snprintf(buf, bufsize, "%s",
3203da14cebeSEric Cheng 		    attr->ma_flags & DLADM_MACADDR_USED ? gettext("yes") :
3204da14cebeSEric Cheng 		    gettext("no"));
3205da14cebeSEric Cheng 		break;
3206da14cebeSEric Cheng 	case PHYS_M_CLIENT:
3207da14cebeSEric Cheng 		/*
3208da14cebeSEric Cheng 		 * CR 6678526: resolve link id to actual link name if
3209da14cebeSEric Cheng 		 * it is valid.
3210da14cebeSEric Cheng 		 */
3211*8002d411SSowmini Varadhan 		(void) snprintf(buf, bufsize, "%s", attr->ma_client_name);
3212da14cebeSEric Cheng 		break;
3213da14cebeSEric Cheng 	}
3214da14cebeSEric Cheng 
3215*8002d411SSowmini Varadhan 	return (B_TRUE);
3216da14cebeSEric Cheng }
3217da14cebeSEric Cheng 
3218da14cebeSEric Cheng typedef struct {
3219da14cebeSEric Cheng 	show_state_t	*hs_state;
3220da14cebeSEric Cheng 	char		*hs_link;
3221da14cebeSEric Cheng 	dladm_hwgrp_attr_t *hs_grp_attr;
3222da14cebeSEric Cheng } print_phys_hwgrp_state_t;
3223da14cebeSEric Cheng 
3224*8002d411SSowmini Varadhan static boolean_t
3225*8002d411SSowmini Varadhan print_phys_one_hwgrp_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
3226da14cebeSEric Cheng {
3227*8002d411SSowmini Varadhan 	print_phys_hwgrp_state_t *hg_state = ofarg->ofmt_cbarg;
3228da14cebeSEric Cheng 	dladm_hwgrp_attr_t *attr = hg_state->hs_grp_attr;
3229da14cebeSEric Cheng 
3230*8002d411SSowmini Varadhan 	switch (ofarg->ofmt_id) {
3231da14cebeSEric Cheng 	case PHYS_H_LINK:
3232*8002d411SSowmini Varadhan 		(void) snprintf(buf, bufsize, "%s", attr->hg_link_name);
3233da14cebeSEric Cheng 		break;
3234da14cebeSEric Cheng 	case PHYS_H_GROUP:
3235*8002d411SSowmini Varadhan 		(void) snprintf(buf, bufsize, "%d", attr->hg_grp_num);
3236da14cebeSEric Cheng 		break;
3237da14cebeSEric Cheng 	case PHYS_H_GRPTYPE:
3238*8002d411SSowmini Varadhan 		(void) snprintf(buf, bufsize, "%s",
3239da14cebeSEric Cheng 		    attr->hg_grp_type == DLADM_HWGRP_TYPE_RX ? "RX" : "TX");
3240da14cebeSEric Cheng 		break;
3241da14cebeSEric Cheng 	case PHYS_H_RINGS:
3242*8002d411SSowmini Varadhan 		(void) snprintf(buf, bufsize, "%d", attr->hg_n_rings);
3243da14cebeSEric Cheng 		break;
3244da14cebeSEric Cheng 	case PHYS_H_CLIENTS:
3245da14cebeSEric Cheng 		if (attr->hg_client_names[0] == '\0') {
3246*8002d411SSowmini Varadhan 			(void) snprintf(buf, bufsize, "--");
3247da14cebeSEric Cheng 		} else {
3248*8002d411SSowmini Varadhan 			(void) snprintf(buf, bufsize, "%s ",
3249da14cebeSEric Cheng 			    attr->hg_client_names);
3250da14cebeSEric Cheng 		}
3251da14cebeSEric Cheng 		break;
3252da14cebeSEric Cheng 	}
3253da14cebeSEric Cheng 
3254*8002d411SSowmini Varadhan 	return (B_TRUE);
3255da14cebeSEric Cheng }
3256da14cebeSEric Cheng 
3257*8002d411SSowmini Varadhan /*
3258*8002d411SSowmini Varadhan  * callback for dladm_walk_macaddr, invoked for each MAC address slot
3259*8002d411SSowmini Varadhan  */
3260da14cebeSEric Cheng static boolean_t
3261da14cebeSEric Cheng print_phys_mac_callback(void *arg, dladm_macaddr_attr_t *attr)
3262da14cebeSEric Cheng {
3263da14cebeSEric Cheng 	print_phys_mac_state_t *mac_state = arg;
3264da14cebeSEric Cheng 	show_state_t *state = mac_state->ms_state;
3265da14cebeSEric Cheng 
3266da14cebeSEric Cheng 	mac_state->ms_mac_attr = attr;
3267*8002d411SSowmini Varadhan 	ofmt_print(state->ls_ofmt, mac_state);
3268da14cebeSEric Cheng 
3269da14cebeSEric Cheng 	return (B_TRUE);
3270da14cebeSEric Cheng }
3271da14cebeSEric Cheng 
3272*8002d411SSowmini Varadhan /*
3273*8002d411SSowmini Varadhan  * invoked by show-phys -m for each physical data-link
3274*8002d411SSowmini Varadhan  */
3275da14cebeSEric Cheng static dladm_status_t
3276da14cebeSEric Cheng print_phys_mac(show_state_t *state, datalink_id_t linkid, char *link)
3277da14cebeSEric Cheng {
3278da14cebeSEric Cheng 	print_phys_mac_state_t mac_state;
3279da14cebeSEric Cheng 
3280da14cebeSEric Cheng 	mac_state.ms_state = state;
3281da14cebeSEric Cheng 	mac_state.ms_link = link;
3282da14cebeSEric Cheng 
32834ac67f02SAnurag S. Maskey 	return (dladm_walk_macaddr(handle, linkid, &mac_state,
3284da14cebeSEric Cheng 	    print_phys_mac_callback));
3285da14cebeSEric Cheng }
3286da14cebeSEric Cheng 
3287*8002d411SSowmini Varadhan /*
3288*8002d411SSowmini Varadhan  * callback for dladm_walk_hwgrp, invoked for each MAC hwgrp
3289*8002d411SSowmini Varadhan  */
3290da14cebeSEric Cheng static boolean_t
3291da14cebeSEric Cheng print_phys_hwgrp_callback(void *arg, dladm_hwgrp_attr_t *attr)
3292da14cebeSEric Cheng {
3293da14cebeSEric Cheng 	print_phys_hwgrp_state_t *hwgrp_state = arg;
3294da14cebeSEric Cheng 	show_state_t *state = hwgrp_state->hs_state;
3295da14cebeSEric Cheng 
3296da14cebeSEric Cheng 	hwgrp_state->hs_grp_attr = attr;
3297*8002d411SSowmini Varadhan 	ofmt_print(state->ls_ofmt, hwgrp_state);
3298da14cebeSEric Cheng 
3299da14cebeSEric Cheng 	return (B_TRUE);
3300da14cebeSEric Cheng }
3301da14cebeSEric Cheng 
3302da14cebeSEric Cheng /* invoked by show-phys -H for each physical data-link */
3303da14cebeSEric Cheng static dladm_status_t
3304da14cebeSEric Cheng print_phys_hwgrp(show_state_t *state, datalink_id_t linkid, char *link)
3305da14cebeSEric Cheng {
3306da14cebeSEric Cheng 	print_phys_hwgrp_state_t hwgrp_state;
3307da14cebeSEric Cheng 
3308da14cebeSEric Cheng 	hwgrp_state.hs_state = state;
3309da14cebeSEric Cheng 	hwgrp_state.hs_link = link;
33104ac67f02SAnurag S. Maskey 	return (dladm_walk_hwgrp(handle, linkid, &hwgrp_state,
3311da14cebeSEric Cheng 	    print_phys_hwgrp_callback));
3312da14cebeSEric Cheng }
3313d62bc4baSyz147064 
3314d62bc4baSyz147064 static dladm_status_t
3315da14cebeSEric Cheng print_phys(show_state_t *state, datalink_id_t linkid)
3316d62bc4baSyz147064 {
3317d62bc4baSyz147064 	char			link[MAXLINKNAMELEN];
3318d62bc4baSyz147064 	uint32_t		flags;
3319da14cebeSEric Cheng 	dladm_status_t		status;
3320d62bc4baSyz147064 	datalink_class_t	class;
3321d62bc4baSyz147064 	uint32_t		media;
3322d62bc4baSyz147064 
33234ac67f02SAnurag S. Maskey 	if ((status = dladm_datalink_id2info(handle, linkid, &flags, &class,
33244ac67f02SAnurag S. Maskey 	    &media, link, MAXLINKNAMELEN)) != DLADM_STATUS_OK) {
3325d62bc4baSyz147064 		goto done;
3326d62bc4baSyz147064 	}
3327d62bc4baSyz147064 
3328d62bc4baSyz147064 	if (class != DATALINK_CLASS_PHYS) {
3329d62bc4baSyz147064 		status = DLADM_STATUS_BADARG;
3330d62bc4baSyz147064 		goto done;
3331d62bc4baSyz147064 	}
3332d62bc4baSyz147064 
3333d62bc4baSyz147064 	if (!(state->ls_flags & flags)) {
3334d62bc4baSyz147064 		status = DLADM_STATUS_NOTFOUND;
3335d62bc4baSyz147064 		goto done;
3336d62bc4baSyz147064 	}
3337d62bc4baSyz147064 
3338da14cebeSEric Cheng 	if (state->ls_mac)
3339da14cebeSEric Cheng 		status = print_phys_mac(state, linkid, link);
3340da14cebeSEric Cheng 	else if (state->ls_hwgrp)
3341da14cebeSEric Cheng 		status = print_phys_hwgrp(state, linkid, link);
3342da14cebeSEric Cheng 	else
3343da14cebeSEric Cheng 		status = print_phys_default(state, linkid, link, flags, media);
3344d62bc4baSyz147064 
3345d62bc4baSyz147064 done:
3346d62bc4baSyz147064 	return (status);
3347d62bc4baSyz147064 }
3348d62bc4baSyz147064 
33494ac67f02SAnurag S. Maskey /* ARGSUSED */
3350d62bc4baSyz147064 static int
33514ac67f02SAnurag S. Maskey show_phys(dladm_handle_t dh, datalink_id_t linkid, void *arg)
3352d62bc4baSyz147064 {
3353d62bc4baSyz147064 	show_state_t	*state = arg;
3354d62bc4baSyz147064 
3355da14cebeSEric Cheng 	state->ls_status = print_phys(state, linkid);
3356d62bc4baSyz147064 	return (DLADM_WALK_CONTINUE);
3357d62bc4baSyz147064 }
3358d62bc4baSyz147064 
3359d62bc4baSyz147064 /*
3360d62bc4baSyz147064  * Print the active topology information.
3361d62bc4baSyz147064  */
3362d62bc4baSyz147064 static dladm_status_t
3363e7801d59Ssowmini print_vlan(show_state_t *state, datalink_id_t linkid, link_fields_buf_t *l)
3364d62bc4baSyz147064 {
3365d62bc4baSyz147064 	dladm_vlan_attr_t	vinfo;
3366d62bc4baSyz147064 	uint32_t		flags;
3367d62bc4baSyz147064 	dladm_status_t		status;
3368d62bc4baSyz147064 
33694ac67f02SAnurag S. Maskey 	if ((status = dladm_datalink_id2info(handle, linkid, &flags, NULL, NULL,
3370e7801d59Ssowmini 	    l->link_name, sizeof (l->link_name))) != DLADM_STATUS_OK) {
3371d62bc4baSyz147064 		goto done;
3372d62bc4baSyz147064 	}
3373d62bc4baSyz147064 
3374d62bc4baSyz147064 	if (!(state->ls_flags & flags)) {
3375d62bc4baSyz147064 		status = DLADM_STATUS_NOTFOUND;
3376d62bc4baSyz147064 		goto done;
3377d62bc4baSyz147064 	}
3378d62bc4baSyz147064 
33794ac67f02SAnurag S. Maskey 	if ((status = dladm_vlan_info(handle, linkid, &vinfo,
33804ac67f02SAnurag S. Maskey 	    state->ls_flags)) != DLADM_STATUS_OK ||
33814ac67f02SAnurag S. Maskey 	    (status = dladm_datalink_id2info(handle, vinfo.dv_linkid, NULL,
33824ac67f02SAnurag S. Maskey 	    NULL, NULL, l->link_over, sizeof (l->link_over))) !=
33834ac67f02SAnurag S. Maskey 	    DLADM_STATUS_OK) {
3384d62bc4baSyz147064 		goto done;
3385d62bc4baSyz147064 	}
3386d62bc4baSyz147064 
3387e7801d59Ssowmini 	(void) snprintf(l->link_vlan_vid, sizeof (l->link_vlan_vid), "%d",
3388e7801d59Ssowmini 	    vinfo.dv_vid);
3389da14cebeSEric Cheng 	(void) snprintf(l->link_flags, sizeof (l->link_flags), "%c----",
3390da14cebeSEric Cheng 	    vinfo.dv_force ? 'f' : '-');
3391d62bc4baSyz147064 
3392d62bc4baSyz147064 done:
3393d62bc4baSyz147064 	return (status);
3394d62bc4baSyz147064 }
3395d62bc4baSyz147064 
33964ac67f02SAnurag S. Maskey /* ARGSUSED */
3397d62bc4baSyz147064 static int
33984ac67f02SAnurag S. Maskey show_vlan(dladm_handle_t dh, datalink_id_t linkid, void *arg)
3399d62bc4baSyz147064 {
3400d62bc4baSyz147064 	show_state_t		*state = arg;
3401d62bc4baSyz147064 	dladm_status_t		status;
3402e7801d59Ssowmini 	link_fields_buf_t	lbuf;
3403d62bc4baSyz147064 
34045f5c9f54SAnurag S. Maskey 	bzero(&lbuf, sizeof (link_fields_buf_t));
3405e7801d59Ssowmini 	status = print_vlan(state, linkid, &lbuf);
3406d62bc4baSyz147064 	if (status != DLADM_STATUS_OK)
3407d62bc4baSyz147064 		goto done;
3408e7801d59Ssowmini 
3409*8002d411SSowmini Varadhan 	ofmt_print(state->ls_ofmt, &lbuf);
3410d62bc4baSyz147064 
3411d62bc4baSyz147064 done:
3412d62bc4baSyz147064 	state->ls_status = status;
3413d62bc4baSyz147064 	return (DLADM_WALK_CONTINUE);
3414d62bc4baSyz147064 }
3415d62bc4baSyz147064 
3416d62bc4baSyz147064 static void
34178d5c46e6Sam223141 do_show_phys(int argc, char *argv[], const char *use)
3418d62bc4baSyz147064 {
3419d62bc4baSyz147064 	int		option;
3420d62bc4baSyz147064 	uint32_t	flags = DLADM_OPT_ACTIVE;
3421d62bc4baSyz147064 	boolean_t	p_arg = B_FALSE;
3422e7801d59Ssowmini 	boolean_t	o_arg = B_FALSE;
3423da14cebeSEric Cheng 	boolean_t	m_arg = B_FALSE;
3424da14cebeSEric Cheng 	boolean_t	H_arg = B_FALSE;
3425d62bc4baSyz147064 	datalink_id_t	linkid = DATALINK_ALL_LINKID;
3426d62bc4baSyz147064 	show_state_t	state;
3427d62bc4baSyz147064 	dladm_status_t	status;
3428e7801d59Ssowmini 	char		*fields_str = NULL;
3429e7801d59Ssowmini 	char		*all_active_fields =
3430e7801d59Ssowmini 	    "link,media,state,speed,duplex,device";
34315f5c9f54SAnurag S. Maskey 	char		*all_inactive_fields = "link,device,media,flags";
3432da14cebeSEric Cheng 	char		*all_mac_fields = "link,slot,address,inuse,client";
3433da14cebeSEric Cheng 	char		*all_hwgrp_fields =
3434da14cebeSEric Cheng 	    "link,group,grouptype,rings,clients";
3435*8002d411SSowmini Varadhan 	ofmt_field_t	*pf;
3436*8002d411SSowmini Varadhan 	ofmt_handle_t	ofmt;
3437*8002d411SSowmini Varadhan 	ofmt_status_t	oferr;
3438*8002d411SSowmini Varadhan 	uint_t		ofmtflags = 0;
3439d62bc4baSyz147064 
3440e7801d59Ssowmini 	bzero(&state, sizeof (state));
3441d62bc4baSyz147064 	opterr = 0;
3442da14cebeSEric Cheng 	while ((option = getopt_long(argc, argv, ":pPo:mH",
3443d62bc4baSyz147064 	    show_lopts, NULL)) != -1) {
3444d62bc4baSyz147064 		switch (option) {
3445d62bc4baSyz147064 		case 'p':
3446d62bc4baSyz147064 			if (p_arg)
3447d62bc4baSyz147064 				die_optdup(option);
3448d62bc4baSyz147064 
3449d62bc4baSyz147064 			p_arg = B_TRUE;
3450d62bc4baSyz147064 			break;
3451d62bc4baSyz147064 		case 'P':
3452d62bc4baSyz147064 			if (flags != DLADM_OPT_ACTIVE)
3453d62bc4baSyz147064 				die_optdup(option);
3454d62bc4baSyz147064 
3455d62bc4baSyz147064 			flags = DLADM_OPT_PERSIST;
3456d62bc4baSyz147064 			break;
3457e7801d59Ssowmini 		case 'o':
3458e7801d59Ssowmini 			o_arg = B_TRUE;
3459e7801d59Ssowmini 			fields_str = optarg;
3460e7801d59Ssowmini 			break;
3461da14cebeSEric Cheng 		case 'm':
3462da14cebeSEric Cheng 			m_arg = B_TRUE;
3463da14cebeSEric Cheng 			break;
3464da14cebeSEric Cheng 		case 'H':
3465da14cebeSEric Cheng 			H_arg = B_TRUE;
3466da14cebeSEric Cheng 			break;
3467d62bc4baSyz147064 		default:
34688d5c46e6Sam223141 			die_opterr(optopt, option, use);
3469d62bc4baSyz147064 			break;
3470d62bc4baSyz147064 		}
3471d62bc4baSyz147064 	}
3472d62bc4baSyz147064 
34730d365605Sschuster 	if (p_arg && !o_arg)
34740d365605Sschuster 		die("-p requires -o");
34750d365605Sschuster 
3476da14cebeSEric Cheng 	if (m_arg && H_arg)
3477da14cebeSEric Cheng 		die("-m cannot combine with -H");
3478da14cebeSEric Cheng 
34790d365605Sschuster 	if (p_arg && strcasecmp(fields_str, "all") == 0)
34800d365605Sschuster 		die("\"-o all\" is invalid with -p");
34810d365605Sschuster 
3482d62bc4baSyz147064 	/* get link name (optional last argument) */
3483d62bc4baSyz147064 	if (optind == (argc-1)) {
34844ac67f02SAnurag S. Maskey 		if ((status = dladm_name2info(handle, argv[optind], &linkid,
34854ac67f02SAnurag S. Maskey 		    NULL, NULL, NULL)) != DLADM_STATUS_OK) {
3486d62bc4baSyz147064 			die_dlerr(status, "link %s is not valid", argv[optind]);
3487d62bc4baSyz147064 		}
3488d62bc4baSyz147064 	} else if (optind != argc) {
3489d62bc4baSyz147064 		usage();
3490d62bc4baSyz147064 	}
3491d62bc4baSyz147064 
3492*8002d411SSowmini Varadhan 	state.ls_parsable = p_arg;
3493d62bc4baSyz147064 	state.ls_flags = flags;
3494d62bc4baSyz147064 	state.ls_donefirst = B_FALSE;
3495da14cebeSEric Cheng 	state.ls_mac = m_arg;
3496da14cebeSEric Cheng 	state.ls_hwgrp = H_arg;
3497d62bc4baSyz147064 
3498da14cebeSEric Cheng 	if (m_arg && !(flags & DLADM_OPT_ACTIVE)) {
3499da14cebeSEric Cheng 		/*
3500da14cebeSEric Cheng 		 * We can only display the factory MAC addresses of
3501da14cebeSEric Cheng 		 * active data-links.
3502da14cebeSEric Cheng 		 */
3503da14cebeSEric Cheng 		die("-m not compatible with -P");
3504e7801d59Ssowmini 	}
3505e7801d59Ssowmini 
3506da14cebeSEric Cheng 	if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) {
3507da14cebeSEric Cheng 		if (state.ls_mac)
3508da14cebeSEric Cheng 			fields_str = all_mac_fields;
3509da14cebeSEric Cheng 		else if (state.ls_hwgrp)
3510da14cebeSEric Cheng 			fields_str = all_hwgrp_fields;
3511da14cebeSEric Cheng 		else if (state.ls_flags & DLADM_OPT_ACTIVE) {
3512da14cebeSEric Cheng 			fields_str = all_active_fields;
3513da14cebeSEric Cheng 		} else {
3514da14cebeSEric Cheng 			fields_str = all_inactive_fields;
3515da14cebeSEric Cheng 		}
3516da14cebeSEric Cheng 	}
3517da14cebeSEric Cheng 
3518da14cebeSEric Cheng 	if (state.ls_mac) {
3519da14cebeSEric Cheng 		pf = phys_m_fields;
3520da14cebeSEric Cheng 	} else if (state.ls_hwgrp) {
3521da14cebeSEric Cheng 		pf = phys_h_fields;
3522da14cebeSEric Cheng 	} else {
3523da14cebeSEric Cheng 		pf = phys_fields;
3524da14cebeSEric Cheng 	}
3525da14cebeSEric Cheng 
3526*8002d411SSowmini Varadhan 	if (state.ls_parsable)
3527*8002d411SSowmini Varadhan 		ofmtflags |= OFMT_PARSABLE;
3528*8002d411SSowmini Varadhan 	oferr = ofmt_open(fields_str, pf, ofmtflags, 0, &ofmt);
3529*8002d411SSowmini Varadhan 	dladm_ofmt_check(oferr, state.ls_parsable, ofmt);
3530*8002d411SSowmini Varadhan 	state.ls_ofmt = ofmt;
3531e7801d59Ssowmini 
3532d62bc4baSyz147064 	if (linkid == DATALINK_ALL_LINKID) {
35334ac67f02SAnurag S. Maskey 		(void) dladm_walk_datalink_id(show_phys, handle, &state,
3534d62bc4baSyz147064 		    DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE, flags);
3535d62bc4baSyz147064 	} else {
35364ac67f02SAnurag S. Maskey 		(void) show_phys(handle, linkid, &state);
3537d62bc4baSyz147064 		if (state.ls_status != DLADM_STATUS_OK) {
3538d62bc4baSyz147064 			die_dlerr(state.ls_status,
3539d62bc4baSyz147064 			    "failed to show physical link %s", argv[optind]);
3540d62bc4baSyz147064 		}
3541d62bc4baSyz147064 	}
3542*8002d411SSowmini Varadhan 	ofmt_close(ofmt);
3543d62bc4baSyz147064 }
3544d62bc4baSyz147064 
3545d62bc4baSyz147064 static void
35468d5c46e6Sam223141 do_show_vlan(int argc, char *argv[], const char *use)
3547d62bc4baSyz147064 {
3548d62bc4baSyz147064 	int		option;
3549d62bc4baSyz147064 	uint32_t	flags = DLADM_OPT_ACTIVE;
3550d62bc4baSyz147064 	boolean_t	p_arg = B_FALSE;
3551d62bc4baSyz147064 	datalink_id_t	linkid = DATALINK_ALL_LINKID;
3552d62bc4baSyz147064 	show_state_t	state;
3553d62bc4baSyz147064 	dladm_status_t	status;
3554e7801d59Ssowmini 	boolean_t	o_arg = B_FALSE;
3555e7801d59Ssowmini 	char		*fields_str = NULL;
3556*8002d411SSowmini Varadhan 	ofmt_handle_t	ofmt;
3557*8002d411SSowmini Varadhan 	ofmt_status_t	oferr;
3558*8002d411SSowmini Varadhan 	uint_t		ofmtflags = 0;
3559e7801d59Ssowmini 
3560e7801d59Ssowmini 	bzero(&state, sizeof (state));
3561d62bc4baSyz147064 
3562d62bc4baSyz147064 	opterr = 0;
3563e7801d59Ssowmini 	while ((option = getopt_long(argc, argv, ":pPo:",
3564d62bc4baSyz147064 	    show_lopts, NULL)) != -1) {
3565d62bc4baSyz147064 		switch (option) {
3566d62bc4baSyz147064 		case 'p':
3567d62bc4baSyz147064 			if (p_arg)
3568d62bc4baSyz147064 				die_optdup(option);
3569d62bc4baSyz147064 
3570d62bc4baSyz147064 			p_arg = B_TRUE;
3571d62bc4baSyz147064 			break;
3572d62bc4baSyz147064 		case 'P':
3573d62bc4baSyz147064 			if (flags != DLADM_OPT_ACTIVE)
3574d62bc4baSyz147064 				die_optdup(option);
3575d62bc4baSyz147064 
3576d62bc4baSyz147064 			flags = DLADM_OPT_PERSIST;
3577d62bc4baSyz147064 			break;
3578e7801d59Ssowmini 		case 'o':
3579e7801d59Ssowmini 			o_arg = B_TRUE;
3580e7801d59Ssowmini 			fields_str = optarg;
3581e7801d59Ssowmini 			break;
3582d62bc4baSyz147064 		default:
35838d5c46e6Sam223141 			die_opterr(optopt, option, use);
3584d62bc4baSyz147064 			break;
3585d62bc4baSyz147064 		}
3586d62bc4baSyz147064 	}
3587d62bc4baSyz147064 
3588d62bc4baSyz147064 	/* get link name (optional last argument) */
3589d62bc4baSyz147064 	if (optind == (argc-1)) {
35904ac67f02SAnurag S. Maskey 		if ((status = dladm_name2info(handle, argv[optind], &linkid,
35914ac67f02SAnurag S. Maskey 		    NULL, NULL, NULL)) != DLADM_STATUS_OK) {
3592d62bc4baSyz147064 			die_dlerr(status, "link %s is not valid", argv[optind]);
3593d62bc4baSyz147064 		}
3594d62bc4baSyz147064 	} else if (optind != argc) {
3595d62bc4baSyz147064 		usage();
3596d62bc4baSyz147064 	}
3597d62bc4baSyz147064 
3598*8002d411SSowmini Varadhan 	state.ls_parsable = p_arg;
3599d62bc4baSyz147064 	state.ls_flags = flags;
3600d62bc4baSyz147064 	state.ls_donefirst = B_FALSE;
3601d62bc4baSyz147064 
3602e7801d59Ssowmini 	if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0))
3603*8002d411SSowmini Varadhan 		fields_str = NULL;
3604e7801d59Ssowmini 
3605*8002d411SSowmini Varadhan 	if (state.ls_parsable)
3606*8002d411SSowmini Varadhan 		ofmtflags |= OFMT_PARSABLE;
3607*8002d411SSowmini Varadhan 	oferr = ofmt_open(fields_str, vlan_fields, ofmtflags, 0, &ofmt);
3608*8002d411SSowmini Varadhan 	dladm_ofmt_check(oferr, state.ls_parsable, ofmt);
3609*8002d411SSowmini Varadhan 	state.ls_ofmt = ofmt;
3610e7801d59Ssowmini 
3611d62bc4baSyz147064 	if (linkid == DATALINK_ALL_LINKID) {
36124ac67f02SAnurag S. Maskey 		(void) dladm_walk_datalink_id(show_vlan, handle, &state,
3613d62bc4baSyz147064 		    DATALINK_CLASS_VLAN, DATALINK_ANY_MEDIATYPE, flags);
3614d62bc4baSyz147064 	} else {
36154ac67f02SAnurag S. Maskey 		(void) show_vlan(handle, linkid, &state);
3616d62bc4baSyz147064 		if (state.ls_status != DLADM_STATUS_OK) {
3617d62bc4baSyz147064 			die_dlerr(state.ls_status, "failed to show vlan %s",
3618d62bc4baSyz147064 			    argv[optind]);
3619d62bc4baSyz147064 		}
3620d62bc4baSyz147064 	}
3621*8002d411SSowmini Varadhan 	ofmt_close(ofmt);
3622d62bc4baSyz147064 }
3623d62bc4baSyz147064 
3624d62bc4baSyz147064 static void
3625da14cebeSEric Cheng do_create_vnic(int argc, char *argv[], const char *use)
3626da14cebeSEric Cheng {
3627da14cebeSEric Cheng 	datalink_id_t		linkid, dev_linkid;
3628da14cebeSEric Cheng 	char			devname[MAXLINKNAMELEN];
3629da14cebeSEric Cheng 	char			name[MAXLINKNAMELEN];
3630da14cebeSEric Cheng 	boolean_t		l_arg = B_FALSE;
3631da14cebeSEric Cheng 	uint32_t		flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
3632da14cebeSEric Cheng 	char			*altroot = NULL;
3633da14cebeSEric Cheng 	char			option;
3634da14cebeSEric Cheng 	char			*endp = NULL;
3635da14cebeSEric Cheng 	dladm_status_t		status;
3636da14cebeSEric Cheng 	vnic_mac_addr_type_t	mac_addr_type = VNIC_MAC_ADDR_TYPE_AUTO;
3637da14cebeSEric Cheng 	uchar_t			*mac_addr;
3638da14cebeSEric Cheng 	int			mac_slot = -1, maclen = 0, mac_prefix_len = 0;
363963a6526dSMichael Lim 	char			propstr[DLADM_STRSIZE];
3640da14cebeSEric Cheng 	dladm_arg_list_t	*proplist = NULL;
3641285e94f9SMichael Lim 	int			vid = 0;
3642da14cebeSEric Cheng 
3643da14cebeSEric Cheng 	opterr = 0;
364463a6526dSMichael Lim 	bzero(propstr, DLADM_STRSIZE);
364563a6526dSMichael Lim 
3646da14cebeSEric Cheng 	while ((option = getopt_long(argc, argv, ":tfR:l:m:n:p:r:v:H",
3647da14cebeSEric Cheng 	    vnic_lopts, NULL)) != -1) {
3648da14cebeSEric Cheng 		switch (option) {
3649da14cebeSEric Cheng 		case 't':
3650da14cebeSEric Cheng 			flags &= ~DLADM_OPT_PERSIST;
3651da14cebeSEric Cheng 			break;
3652da14cebeSEric Cheng 		case 'R':
3653da14cebeSEric Cheng 			altroot = optarg;
3654da14cebeSEric Cheng 			break;
3655da14cebeSEric Cheng 		case 'l':
3656da14cebeSEric Cheng 			if (strlcpy(devname, optarg, MAXLINKNAMELEN) >=
3657da14cebeSEric Cheng 			    MAXLINKNAMELEN)
3658da14cebeSEric Cheng 				die("link name too long");
3659da14cebeSEric Cheng 			l_arg = B_TRUE;
3660da14cebeSEric Cheng 			break;
3661da14cebeSEric Cheng 		case 'm':
3662da14cebeSEric Cheng 			if (strcmp(optarg, "fixed") == 0) {
3663da14cebeSEric Cheng 				/*
3664da14cebeSEric Cheng 				 * A fixed MAC address must be specified
3665da14cebeSEric Cheng 				 * by its value, not by the keyword 'fixed'.
3666da14cebeSEric Cheng 				 */
3667da14cebeSEric Cheng 				die("'fixed' is not a valid MAC address");
3668da14cebeSEric Cheng 			}
3669da14cebeSEric Cheng 			if (dladm_vnic_str2macaddrtype(optarg,
3670da14cebeSEric Cheng 			    &mac_addr_type) != DLADM_STATUS_OK) {
3671da14cebeSEric Cheng 				mac_addr_type = VNIC_MAC_ADDR_TYPE_FIXED;
3672da14cebeSEric Cheng 				/* MAC address specified by value */
3673da14cebeSEric Cheng 				mac_addr = _link_aton(optarg, &maclen);
3674da14cebeSEric Cheng 				if (mac_addr == NULL) {
3675da14cebeSEric Cheng 					if (maclen == -1)
3676da14cebeSEric Cheng 						die("invalid MAC address");
3677da14cebeSEric Cheng 					else
3678da14cebeSEric Cheng 						die("out of memory");
3679da14cebeSEric Cheng 				}
3680da14cebeSEric Cheng 			}
3681da14cebeSEric Cheng 			break;
3682da14cebeSEric Cheng 		case 'n':
3683da14cebeSEric Cheng 			errno = 0;
3684da14cebeSEric Cheng 			mac_slot = (int)strtol(optarg, &endp, 10);
3685da14cebeSEric Cheng 			if (errno != 0 || *endp != '\0')
3686da14cebeSEric Cheng 				die("invalid slot number");
3687da14cebeSEric Cheng 			break;
3688da14cebeSEric Cheng 		case 'p':
368963a6526dSMichael Lim 			(void) strlcat(propstr, optarg, DLADM_STRSIZE);
369063a6526dSMichael Lim 			if (strlcat(propstr, ",", DLADM_STRSIZE) >=
369163a6526dSMichael Lim 			    DLADM_STRSIZE)
369263a6526dSMichael Lim 				die("property list too long '%s'", propstr);
3693da14cebeSEric Cheng 			break;
3694da14cebeSEric Cheng 		case 'r':
3695da14cebeSEric Cheng 			mac_addr = _link_aton(optarg, &mac_prefix_len);
3696da14cebeSEric Cheng 			if (mac_addr == NULL) {
3697da14cebeSEric Cheng 				if (mac_prefix_len == -1)
3698da14cebeSEric Cheng 					die("invalid MAC address");
3699da14cebeSEric Cheng 				else
3700da14cebeSEric Cheng 					die("out of memory");
3701da14cebeSEric Cheng 			}
3702da14cebeSEric Cheng 			break;
3703da14cebeSEric Cheng 		case 'v':
3704285e94f9SMichael Lim 			if (vid != 0)
3705285e94f9SMichael Lim 				die_optdup(option);
3706285e94f9SMichael Lim 
3707285e94f9SMichael Lim 			if (!str2int(optarg, &vid) || vid < 1 || vid > 4094)
3708285e94f9SMichael Lim 				die("invalid VLAN identifier '%s'", optarg);
3709285e94f9SMichael Lim 
3710da14cebeSEric Cheng 			break;
3711da14cebeSEric Cheng 		case 'f':
3712da14cebeSEric Cheng 			flags |= DLADM_OPT_FORCE;
3713da14cebeSEric Cheng 			break;
3714da14cebeSEric Cheng 		case 'H':
3715da14cebeSEric Cheng 			flags |= DLADM_OPT_HWRINGS;
3716da14cebeSEric Cheng 			break;
3717da14cebeSEric Cheng 		default:
3718da14cebeSEric Cheng 			die_opterr(optopt, option, use);
3719da14cebeSEric Cheng 		}
3720da14cebeSEric Cheng 	}
3721da14cebeSEric Cheng 
3722da14cebeSEric Cheng 	/*
3723da14cebeSEric Cheng 	 * 'f' - force, flag can be specified only with 'v' - vlan.
3724da14cebeSEric Cheng 	 */
3725da14cebeSEric Cheng 	if ((flags & DLADM_OPT_FORCE) != 0 && vid == 0)
3726da14cebeSEric Cheng 		die("-f option can only be used with -v");
3727da14cebeSEric Cheng 
3728da14cebeSEric Cheng 	if (mac_prefix_len != 0 && mac_addr_type != VNIC_MAC_ADDR_TYPE_RANDOM &&
3729da14cebeSEric Cheng 	    mac_addr_type != VNIC_MAC_ADDR_TYPE_FIXED)
3730da14cebeSEric Cheng 		usage();
3731da14cebeSEric Cheng 
3732da14cebeSEric Cheng 	/* check required options */
3733da14cebeSEric Cheng 	if (!l_arg)
3734da14cebeSEric Cheng 		usage();
3735da14cebeSEric Cheng 
3736da14cebeSEric Cheng 	if (mac_slot != -1 && mac_addr_type != VNIC_MAC_ADDR_TYPE_FACTORY)
3737da14cebeSEric Cheng 		usage();
3738da14cebeSEric Cheng 
3739da14cebeSEric Cheng 	/* the VNIC id is the required operand */
3740da14cebeSEric Cheng 	if (optind != (argc - 1))
3741da14cebeSEric Cheng 		usage();
3742da14cebeSEric Cheng 
3743da14cebeSEric Cheng 	if (strlcpy(name, argv[optind], MAXLINKNAMELEN) >= MAXLINKNAMELEN)
3744da14cebeSEric Cheng 		die("link name too long '%s'", argv[optind]);
3745da14cebeSEric Cheng 
3746da14cebeSEric Cheng 	if (!dladm_valid_linkname(name))
3747da14cebeSEric Cheng 		die("invalid link name '%s'", argv[optind]);
3748da14cebeSEric Cheng 
3749da14cebeSEric Cheng 	if (altroot != NULL)
3750da14cebeSEric Cheng 		altroot_cmd(altroot, argc, argv);
3751da14cebeSEric Cheng 
37524ac67f02SAnurag S. Maskey 	if (dladm_name2info(handle, devname, &dev_linkid, NULL, NULL, NULL) !=
3753da14cebeSEric Cheng 	    DLADM_STATUS_OK)
3754da14cebeSEric Cheng 		die("invalid link name '%s'", devname);
3755da14cebeSEric Cheng 
375663a6526dSMichael Lim 	if (dladm_parse_link_props(propstr, &proplist, B_FALSE)
375763a6526dSMichael Lim 	    != DLADM_STATUS_OK)
375863a6526dSMichael Lim 		die("invalid vnic property");
375963a6526dSMichael Lim 
37604ac67f02SAnurag S. Maskey 	status = dladm_vnic_create(handle, name, dev_linkid, mac_addr_type,
37614ac67f02SAnurag S. Maskey 	    mac_addr, maclen, &mac_slot, mac_prefix_len, vid, &linkid, proplist,
37624ac67f02SAnurag S. Maskey 	    flags);
3763da14cebeSEric Cheng 	if (status != DLADM_STATUS_OK)
3764da14cebeSEric Cheng 		die_dlerr(status, "vnic creation over %s failed", devname);
3765da14cebeSEric Cheng 
3766da14cebeSEric Cheng 	dladm_free_props(proplist);
3767da14cebeSEric Cheng }
3768da14cebeSEric Cheng 
3769da14cebeSEric Cheng static void
3770da14cebeSEric Cheng do_etherstub_check(const char *name, datalink_id_t linkid, boolean_t etherstub,
3771da14cebeSEric Cheng     uint32_t flags)
3772da14cebeSEric Cheng {
3773da14cebeSEric Cheng 	boolean_t is_etherstub;
3774da14cebeSEric Cheng 	dladm_vnic_attr_t attr;
3775da14cebeSEric Cheng 
37764ac67f02SAnurag S. Maskey 	if (dladm_vnic_info(handle, linkid, &attr, flags) != DLADM_STATUS_OK) {
3777da14cebeSEric Cheng 		/*
3778da14cebeSEric Cheng 		 * Let the delete continue anyway.
3779da14cebeSEric Cheng 		 */
3780da14cebeSEric Cheng 		return;
3781da14cebeSEric Cheng 	}
3782da14cebeSEric Cheng 	is_etherstub = (attr.va_link_id == DATALINK_INVALID_LINKID);
3783da14cebeSEric Cheng 	if (is_etherstub != etherstub) {
3784da14cebeSEric Cheng 		die("'%s' is not %s", name,
3785da14cebeSEric Cheng 		    (is_etherstub ? "a vnic" : "an etherstub"));
3786da14cebeSEric Cheng 	}
3787da14cebeSEric Cheng }
3788da14cebeSEric Cheng 
3789da14cebeSEric Cheng static void
3790da14cebeSEric Cheng do_delete_vnic_common(int argc, char *argv[], const char *use,
3791da14cebeSEric Cheng     boolean_t etherstub)
3792da14cebeSEric Cheng {
3793da14cebeSEric Cheng 	char option;
3794da14cebeSEric Cheng 	uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
3795da14cebeSEric Cheng 	datalink_id_t linkid;
3796da14cebeSEric Cheng 	char *altroot = NULL;
3797da14cebeSEric Cheng 	dladm_status_t status;
3798da14cebeSEric Cheng 
3799da14cebeSEric Cheng 	opterr = 0;
3800da14cebeSEric Cheng 	while ((option = getopt_long(argc, argv, ":R:t", lopts,
3801da14cebeSEric Cheng 	    NULL)) != -1) {
3802da14cebeSEric Cheng 		switch (option) {
3803da14cebeSEric Cheng 		case 't':
3804da14cebeSEric Cheng 			flags &= ~DLADM_OPT_PERSIST;
3805da14cebeSEric Cheng 			break;
3806da14cebeSEric Cheng 		case 'R':
3807da14cebeSEric Cheng 			altroot = optarg;
3808da14cebeSEric Cheng 			break;
3809da14cebeSEric Cheng 		default:
3810da14cebeSEric Cheng 			die_opterr(optopt, option, use);
3811da14cebeSEric Cheng 		}
3812da14cebeSEric Cheng 	}
3813da14cebeSEric Cheng 
3814da14cebeSEric Cheng 	/* get vnic name (required last argument) */
3815da14cebeSEric Cheng 	if (optind != (argc - 1))
3816da14cebeSEric Cheng 		usage();
3817da14cebeSEric Cheng 
3818da14cebeSEric Cheng 	if (altroot != NULL)
3819da14cebeSEric Cheng 		altroot_cmd(altroot, argc, argv);
3820da14cebeSEric Cheng 
38214ac67f02SAnurag S. Maskey 	status = dladm_name2info(handle, argv[optind], &linkid, NULL, NULL,
38224ac67f02SAnurag S. Maskey 	    NULL);
3823da14cebeSEric Cheng 	if (status != DLADM_STATUS_OK)
3824da14cebeSEric Cheng 		die("invalid link name '%s'", argv[optind]);
3825da14cebeSEric Cheng 
3826da14cebeSEric Cheng 	if ((flags & DLADM_OPT_ACTIVE) != 0) {
3827da14cebeSEric Cheng 		do_etherstub_check(argv[optind], linkid, etherstub,
3828da14cebeSEric Cheng 		    DLADM_OPT_ACTIVE);
3829da14cebeSEric Cheng 	}
3830da14cebeSEric Cheng 	if ((flags & DLADM_OPT_PERSIST) != 0) {
3831da14cebeSEric Cheng 		do_etherstub_check(argv[optind], linkid, etherstub,
3832da14cebeSEric Cheng 		    DLADM_OPT_PERSIST);
3833da14cebeSEric Cheng 	}
3834da14cebeSEric Cheng 
38354ac67f02SAnurag S. Maskey 	status = dladm_vnic_delete(handle, linkid, flags);
3836da14cebeSEric Cheng 	if (status != DLADM_STATUS_OK)
3837da14cebeSEric Cheng 		die_dlerr(status, "vnic deletion failed");
3838da14cebeSEric Cheng }
3839da14cebeSEric Cheng 
3840da14cebeSEric Cheng static void
3841da14cebeSEric Cheng do_delete_vnic(int argc, char *argv[], const char *use)
3842da14cebeSEric Cheng {
3843da14cebeSEric Cheng 	do_delete_vnic_common(argc, argv, use, B_FALSE);
3844da14cebeSEric Cheng }
3845da14cebeSEric Cheng 
3846da14cebeSEric Cheng /* ARGSUSED */
3847da14cebeSEric Cheng static void
3848da14cebeSEric Cheng do_up_vnic_common(int argc, char *argv[], const char *use, boolean_t vlan)
3849da14cebeSEric Cheng {
3850da14cebeSEric Cheng 	datalink_id_t	linkid = DATALINK_ALL_LINKID;
3851da14cebeSEric Cheng 	dladm_status_t	status;
3852da14cebeSEric Cheng 	char 		*type;
3853da14cebeSEric Cheng 
3854da14cebeSEric Cheng 	type = vlan ? "vlan" : "vnic";
3855da14cebeSEric Cheng 
3856da14cebeSEric Cheng 	/*
3857da14cebeSEric Cheng 	 * get the id or the name of the vnic/vlan (optional last argument)
3858da14cebeSEric Cheng 	 */
3859da14cebeSEric Cheng 	if (argc == 2) {
38604ac67f02SAnurag S. Maskey 		status = dladm_name2info(handle, argv[1], &linkid, NULL, NULL,
38614ac67f02SAnurag S. Maskey 		    NULL);
3862da14cebeSEric Cheng 		if (status != DLADM_STATUS_OK)
3863da14cebeSEric Cheng 			goto done;
3864da14cebeSEric Cheng 
3865da14cebeSEric Cheng 	} else if (argc > 2) {
3866da14cebeSEric Cheng 		usage();
3867da14cebeSEric Cheng 	}
3868da14cebeSEric Cheng 
3869da14cebeSEric Cheng 	if (vlan)
38704ac67f02SAnurag S. Maskey 		status = dladm_vlan_up(handle, linkid);
3871da14cebeSEric Cheng 	else
38724ac67f02SAnurag S. Maskey 		status = dladm_vnic_up(handle, linkid, 0);
3873da14cebeSEric Cheng 
3874da14cebeSEric Cheng done:
3875da14cebeSEric Cheng 	if (status != DLADM_STATUS_OK) {
3876da14cebeSEric Cheng 		if (argc == 2) {
3877da14cebeSEric Cheng 			die_dlerr(status,
3878da14cebeSEric Cheng 			    "could not bring up %s '%s'", type, argv[1]);
3879da14cebeSEric Cheng 		} else {
3880da14cebeSEric Cheng 			die_dlerr(status, "could not bring %ss up", type);
3881da14cebeSEric Cheng 		}
3882da14cebeSEric Cheng 	}
3883da14cebeSEric Cheng }
3884da14cebeSEric Cheng 
3885da14cebeSEric Cheng static void
3886da14cebeSEric Cheng do_up_vnic(int argc, char *argv[], const char *use)
3887da14cebeSEric Cheng {
3888da14cebeSEric Cheng 	do_up_vnic_common(argc, argv, use, B_FALSE);
3889da14cebeSEric Cheng }
3890da14cebeSEric Cheng 
3891da14cebeSEric Cheng static void
3892da14cebeSEric Cheng dump_vnics_head(const char *dev)
3893da14cebeSEric Cheng {
3894da14cebeSEric Cheng 	if (strlen(dev))
3895da14cebeSEric Cheng 		(void) printf("%s", dev);
3896da14cebeSEric Cheng 
3897da14cebeSEric Cheng 	(void) printf("\tipackets  rbytes      opackets  obytes          ");
3898da14cebeSEric Cheng 
3899da14cebeSEric Cheng 	if (strlen(dev))
3900da14cebeSEric Cheng 		(void) printf("%%ipkts  %%opkts\n");
3901da14cebeSEric Cheng 	else
3902da14cebeSEric Cheng 		(void) printf("\n");
3903da14cebeSEric Cheng }
3904da14cebeSEric Cheng 
3905da14cebeSEric Cheng static void
3906da14cebeSEric Cheng dump_vnic_stat(const char *name, datalink_id_t vnic_id,
3907da14cebeSEric Cheng     show_vnic_state_t *state, pktsum_t *vnic_stats, pktsum_t *tot_stats)
3908da14cebeSEric Cheng {
3909da14cebeSEric Cheng 	pktsum_t	diff_stats;
3910da14cebeSEric Cheng 	pktsum_t	*old_stats = &state->vs_prevstats[vnic_id];
3911da14cebeSEric Cheng 
3912da14cebeSEric Cheng 	dladm_stats_diff(&diff_stats, vnic_stats, old_stats);
3913da14cebeSEric Cheng 
3914da14cebeSEric Cheng 	(void) printf("%s", name);
3915da14cebeSEric Cheng 
3916da14cebeSEric Cheng 	(void) printf("\t%-10llu", diff_stats.ipackets);
3917da14cebeSEric Cheng 	(void) printf("%-12llu", diff_stats.rbytes);
3918da14cebeSEric Cheng 	(void) printf("%-10llu", diff_stats.opackets);
3919da14cebeSEric Cheng 	(void) printf("%-12llu", diff_stats.obytes);
3920da14cebeSEric Cheng 
3921da14cebeSEric Cheng 	if (tot_stats) {
3922da14cebeSEric Cheng 		if (tot_stats->ipackets == 0) {
3923da14cebeSEric Cheng 			(void) printf("\t-");
3924da14cebeSEric Cheng 		} else {
3925da14cebeSEric Cheng 			(void) printf("\t%-6.1f", (double)diff_stats.ipackets/
3926da14cebeSEric Cheng 			    (double)tot_stats->ipackets * 100);
3927da14cebeSEric Cheng 		}
3928da14cebeSEric Cheng 		if (tot_stats->opackets == 0) {
3929da14cebeSEric Cheng 			(void) printf("\t-");
3930da14cebeSEric Cheng 		} else {
3931da14cebeSEric Cheng 			(void) printf("\t%-6.1f", (double)diff_stats.opackets/
3932da14cebeSEric Cheng 			    (double)tot_stats->opackets * 100);
3933da14cebeSEric Cheng 		}
3934da14cebeSEric Cheng 	}
3935da14cebeSEric Cheng 	(void) printf("\n");
3936da14cebeSEric Cheng 
3937da14cebeSEric Cheng 	*old_stats = *vnic_stats;
3938da14cebeSEric Cheng }
3939da14cebeSEric Cheng 
3940da14cebeSEric Cheng /*
3941da14cebeSEric Cheng  * Called from the walker dladm_vnic_walk_sys() for each vnic to display
3942da14cebeSEric Cheng  * vnic information or statistics.
3943da14cebeSEric Cheng  */
3944da14cebeSEric Cheng static dladm_status_t
3945da14cebeSEric Cheng print_vnic(show_vnic_state_t *state, datalink_id_t linkid)
3946da14cebeSEric Cheng {
3947da14cebeSEric Cheng 	dladm_vnic_attr_t	attr, *vnic = &attr;
3948da14cebeSEric Cheng 	dladm_status_t		status;
3949da14cebeSEric Cheng 	boolean_t		is_etherstub;
3950da14cebeSEric Cheng 	char			devname[MAXLINKNAMELEN];
3951da14cebeSEric Cheng 	char			vnic_name[MAXLINKNAMELEN];
3952da14cebeSEric Cheng 	char			mstr[MAXMACADDRLEN * 3];
3953da14cebeSEric Cheng 	vnic_fields_buf_t	vbuf;
3954da14cebeSEric Cheng 
39554ac67f02SAnurag S. Maskey 	if ((status = dladm_vnic_info(handle, linkid, vnic, state->vs_flags)) !=
3956da14cebeSEric Cheng 	    DLADM_STATUS_OK)
3957da14cebeSEric Cheng 		return (status);
3958da14cebeSEric Cheng 
3959da14cebeSEric Cheng 	is_etherstub = (vnic->va_link_id == DATALINK_INVALID_LINKID);
3960da14cebeSEric Cheng 	if (state->vs_etherstub != is_etherstub) {
3961da14cebeSEric Cheng 		/*
3962da14cebeSEric Cheng 		 * Want all etherstub but it's not one, or want
3963da14cebeSEric Cheng 		 * non-etherstub and it's one.
3964da14cebeSEric Cheng 		 */
3965da14cebeSEric Cheng 		return (DLADM_STATUS_OK);
3966da14cebeSEric Cheng 	}
3967da14cebeSEric Cheng 
3968da14cebeSEric Cheng 	if (state->vs_link_id != DATALINK_ALL_LINKID) {
3969da14cebeSEric Cheng 		if (state->vs_link_id != vnic->va_link_id)
3970da14cebeSEric Cheng 			return (DLADM_STATUS_OK);
3971da14cebeSEric Cheng 	}
3972da14cebeSEric Cheng 
39734ac67f02SAnurag S. Maskey 	if (dladm_datalink_id2info(handle, linkid, NULL, NULL,
3974da14cebeSEric Cheng 	    NULL, vnic_name, sizeof (vnic_name)) != DLADM_STATUS_OK)
3975da14cebeSEric Cheng 		return (DLADM_STATUS_BADARG);
3976da14cebeSEric Cheng 
3977da14cebeSEric Cheng 	bzero(devname, sizeof (devname));
3978da14cebeSEric Cheng 	if (!is_etherstub &&
39794ac67f02SAnurag S. Maskey 	    dladm_datalink_id2info(handle, vnic->va_link_id, NULL, NULL,
3980da14cebeSEric Cheng 	    NULL, devname, sizeof (devname)) != DLADM_STATUS_OK)
3981da14cebeSEric Cheng 		return (DLADM_STATUS_BADARG);
3982da14cebeSEric Cheng 
3983da14cebeSEric Cheng 	state->vs_found = B_TRUE;
3984da14cebeSEric Cheng 	if (state->vs_stats) {
3985da14cebeSEric Cheng 		/* print vnic statistics */
3986da14cebeSEric Cheng 		pktsum_t vnic_stats;
3987da14cebeSEric Cheng 
3988da14cebeSEric Cheng 		if (state->vs_firstonly) {
3989da14cebeSEric Cheng 			if (state->vs_donefirst)
3990da14cebeSEric Cheng 				return (0);
3991da14cebeSEric Cheng 			state->vs_donefirst = B_TRUE;
3992da14cebeSEric Cheng 		}
3993da14cebeSEric Cheng 
3994da14cebeSEric Cheng 		if (!state->vs_printstats) {
3995da14cebeSEric Cheng 			/*
3996da14cebeSEric Cheng 			 * get vnic statistics and add to the sum for the
3997da14cebeSEric Cheng 			 * named device.
3998da14cebeSEric Cheng 			 */
3999da14cebeSEric Cheng 			get_link_stats(vnic_name, &vnic_stats);
4000da14cebeSEric Cheng 			dladm_stats_total(&state->vs_totalstats, &vnic_stats,
4001da14cebeSEric Cheng 			    &state->vs_prevstats[vnic->va_vnic_id]);
4002da14cebeSEric Cheng 		} else {
4003da14cebeSEric Cheng 			/* get and print vnic statistics */
4004da14cebeSEric Cheng 			get_link_stats(vnic_name, &vnic_stats);
4005da14cebeSEric Cheng 			dump_vnic_stat(vnic_name, linkid, state, &vnic_stats,
4006da14cebeSEric Cheng 			    &state->vs_totalstats);
4007da14cebeSEric Cheng 		}
4008da14cebeSEric Cheng 		return (DLADM_STATUS_OK);
4009da14cebeSEric Cheng 	} else {
4010da14cebeSEric Cheng 		(void) snprintf(vbuf.vnic_link, sizeof (vbuf.vnic_link),
4011da14cebeSEric Cheng 		    "%s", vnic_name);
4012da14cebeSEric Cheng 
4013da14cebeSEric Cheng 		if (!is_etherstub) {
4014da14cebeSEric Cheng 
4015da14cebeSEric Cheng 			(void) snprintf(vbuf.vnic_over, sizeof (vbuf.vnic_over),
4016da14cebeSEric Cheng 			    "%s", devname);
4017da14cebeSEric Cheng 			(void) snprintf(vbuf.vnic_speed,
4018da14cebeSEric Cheng 			    sizeof (vbuf.vnic_speed), "%u",
4019da14cebeSEric Cheng 			    (uint_t)((get_ifspeed(vnic_name, B_TRUE))
4020da14cebeSEric Cheng 			    / 1000000ull));
4021da14cebeSEric Cheng 
4022da14cebeSEric Cheng 			switch (vnic->va_mac_addr_type) {
4023da14cebeSEric Cheng 			case VNIC_MAC_ADDR_TYPE_FIXED:
4024da14cebeSEric Cheng 			case VNIC_MAC_ADDR_TYPE_PRIMARY:
4025da14cebeSEric Cheng 				(void) snprintf(vbuf.vnic_macaddrtype,
4026da14cebeSEric Cheng 				    sizeof (vbuf.vnic_macaddrtype),
4027da14cebeSEric Cheng 				    gettext("fixed"));
4028da14cebeSEric Cheng 				break;
4029da14cebeSEric Cheng 			case VNIC_MAC_ADDR_TYPE_RANDOM:
4030da14cebeSEric Cheng 				(void) snprintf(vbuf.vnic_macaddrtype,
4031da14cebeSEric Cheng 				    sizeof (vbuf.vnic_macaddrtype),
4032da14cebeSEric Cheng 				    gettext("random"));
4033da14cebeSEric Cheng 				break;
4034da14cebeSEric Cheng 			case VNIC_MAC_ADDR_TYPE_FACTORY:
4035da14cebeSEric Cheng 				(void) snprintf(vbuf.vnic_macaddrtype,
4036da14cebeSEric Cheng 				    sizeof (vbuf.vnic_macaddrtype),
4037da14cebeSEric Cheng 				    gettext("factory, slot %d"),
4038da14cebeSEric Cheng 				    vnic->va_mac_slot);
4039da14cebeSEric Cheng 				break;
4040da14cebeSEric Cheng 			}
4041da14cebeSEric Cheng 
4042da14cebeSEric Cheng 			if (strlen(vbuf.vnic_macaddrtype) > 0) {
4043da14cebeSEric Cheng 				(void) snprintf(vbuf.vnic_macaddr,
4044da14cebeSEric Cheng 				    sizeof (vbuf.vnic_macaddr), "%s",
4045da14cebeSEric Cheng 				    dladm_aggr_macaddr2str(vnic->va_mac_addr,
4046da14cebeSEric Cheng 				    mstr));
4047da14cebeSEric Cheng 			}
4048da14cebeSEric Cheng 
4049da14cebeSEric Cheng 			(void) snprintf(vbuf.vnic_vid, sizeof (vbuf.vnic_vid),
4050da14cebeSEric Cheng 			    "%d", vnic->va_vid);
4051da14cebeSEric Cheng 		}
4052da14cebeSEric Cheng 
4053*8002d411SSowmini Varadhan 		ofmt_print(state->vs_ofmt, &vbuf);
4054da14cebeSEric Cheng 
4055da14cebeSEric Cheng 		return (DLADM_STATUS_OK);
4056da14cebeSEric Cheng 	}
4057da14cebeSEric Cheng }
4058da14cebeSEric Cheng 
40594ac67f02SAnurag S. Maskey /* ARGSUSED */
4060da14cebeSEric Cheng static int
40614ac67f02SAnurag S. Maskey show_vnic(dladm_handle_t dh, datalink_id_t linkid, void *arg)
4062da14cebeSEric Cheng {
4063da14cebeSEric Cheng 	show_vnic_state_t	*state = arg;
4064da14cebeSEric Cheng 
4065da14cebeSEric Cheng 	state->vs_status = print_vnic(state, linkid);
4066da14cebeSEric Cheng 	return (DLADM_WALK_CONTINUE);
4067da14cebeSEric Cheng }
4068da14cebeSEric Cheng 
4069da14cebeSEric Cheng static void
4070da14cebeSEric Cheng do_show_vnic_common(int argc, char *argv[], const char *use,
4071da14cebeSEric Cheng     boolean_t etherstub)
4072da14cebeSEric Cheng {
4073da14cebeSEric Cheng 	int			option;
4074da14cebeSEric Cheng 	boolean_t		s_arg = B_FALSE;
4075da14cebeSEric Cheng 	boolean_t		i_arg = B_FALSE;
4076da14cebeSEric Cheng 	boolean_t		l_arg = B_FALSE;
4077da14cebeSEric Cheng 	uint32_t		interval = 0, flags = DLADM_OPT_ACTIVE;
4078da14cebeSEric Cheng 	datalink_id_t		linkid = DATALINK_ALL_LINKID;
4079da14cebeSEric Cheng 	datalink_id_t		dev_linkid = DATALINK_ALL_LINKID;
4080da14cebeSEric Cheng 	show_vnic_state_t	state;
4081da14cebeSEric Cheng 	dladm_status_t		status;
4082da14cebeSEric Cheng 	boolean_t		o_arg = B_FALSE;
4083da14cebeSEric Cheng 	char			*fields_str = NULL;
4084*8002d411SSowmini Varadhan 	ofmt_field_t		*pf;
4085*8002d411SSowmini Varadhan 	char			*all_e_fields = "link";
4086*8002d411SSowmini Varadhan 	ofmt_handle_t		ofmt;
4087*8002d411SSowmini Varadhan 	ofmt_status_t		oferr;
4088*8002d411SSowmini Varadhan 	uint_t			ofmtflags = 0;
4089da14cebeSEric Cheng 
4090da14cebeSEric Cheng 	bzero(&state, sizeof (state));
4091da14cebeSEric Cheng 	opterr = 0;
4092da14cebeSEric Cheng 	while ((option = getopt_long(argc, argv, ":pPl:si:o:", lopts,
4093da14cebeSEric Cheng 	    NULL)) != -1) {
4094da14cebeSEric Cheng 		switch (option) {
4095da14cebeSEric Cheng 		case 'p':
4096*8002d411SSowmini Varadhan 			state.vs_parsable = B_TRUE;
4097da14cebeSEric Cheng 			break;
4098da14cebeSEric Cheng 		case 'P':
4099da14cebeSEric Cheng 			flags = DLADM_OPT_PERSIST;
4100da14cebeSEric Cheng 			break;
4101da14cebeSEric Cheng 		case 'l':
4102da14cebeSEric Cheng 			if (etherstub)
4103da14cebeSEric Cheng 				die("option not supported for this command");
4104da14cebeSEric Cheng 
4105da14cebeSEric Cheng 			if (strlcpy(state.vs_link, optarg, MAXLINKNAMELEN) >=
4106da14cebeSEric Cheng 			    MAXLINKNAMELEN)
4107da14cebeSEric Cheng 				die("link name too long");
4108da14cebeSEric Cheng 
4109da14cebeSEric Cheng 			l_arg = B_TRUE;
4110da14cebeSEric Cheng 			break;
4111da14cebeSEric Cheng 		case 's':
4112da14cebeSEric Cheng 			if (s_arg) {
4113da14cebeSEric Cheng 				die("the option -s cannot be specified "
4114da14cebeSEric Cheng 				    "more than once");
4115da14cebeSEric Cheng 			}
4116da14cebeSEric Cheng 			s_arg = B_TRUE;
4117da14cebeSEric Cheng 			break;
4118da14cebeSEric Cheng 		case 'i':
4119da14cebeSEric Cheng 			if (i_arg) {
4120da14cebeSEric Cheng 				die("the option -i cannot be specified "
4121da14cebeSEric Cheng 				    "more than once");
4122da14cebeSEric Cheng 			}
4123da14cebeSEric Cheng 			i_arg = B_TRUE;
412463a6526dSMichael Lim 			if (!dladm_str2interval(optarg, &interval))
4125da14cebeSEric Cheng 				die("invalid interval value '%s'", optarg);
4126da14cebeSEric Cheng 			break;
4127da14cebeSEric Cheng 		case 'o':
4128da14cebeSEric Cheng 			o_arg = B_TRUE;
4129da14cebeSEric Cheng 			fields_str = optarg;
4130da14cebeSEric Cheng 			break;
4131da14cebeSEric Cheng 		default:
4132da14cebeSEric Cheng 			die_opterr(optopt, option, use);
4133da14cebeSEric Cheng 		}
4134da14cebeSEric Cheng 	}
4135da14cebeSEric Cheng 
4136da14cebeSEric Cheng 	if (i_arg && !s_arg)
4137da14cebeSEric Cheng 		die("the option -i can be used only with -s");
4138da14cebeSEric Cheng 
4139da14cebeSEric Cheng 	/* get vnic ID (optional last argument) */
4140da14cebeSEric Cheng 	if (optind == (argc - 1)) {
41414ac67f02SAnurag S. Maskey 		status = dladm_name2info(handle, argv[optind], &linkid, NULL,
4142da14cebeSEric Cheng 		    NULL, NULL);
4143da14cebeSEric Cheng 		if (status != DLADM_STATUS_OK) {
4144da14cebeSEric Cheng 			die_dlerr(status, "invalid vnic name '%s'",
4145da14cebeSEric Cheng 			    argv[optind]);
4146da14cebeSEric Cheng 		}
4147da14cebeSEric Cheng 		(void) strlcpy(state.vs_vnic, argv[optind], MAXLINKNAMELEN);
4148da14cebeSEric Cheng 	} else if (optind != argc) {
4149da14cebeSEric Cheng 		usage();
4150da14cebeSEric Cheng 	}
4151da14cebeSEric Cheng 
4152da14cebeSEric Cheng 	if (l_arg) {
41534ac67f02SAnurag S. Maskey 		status = dladm_name2info(handle, state.vs_link, &dev_linkid,
41544ac67f02SAnurag S. Maskey 		    NULL, NULL, NULL);
4155da14cebeSEric Cheng 		if (status != DLADM_STATUS_OK) {
4156da14cebeSEric Cheng 			die_dlerr(status, "invalid link name '%s'",
4157da14cebeSEric Cheng 			    state.vs_link);
4158da14cebeSEric Cheng 		}
4159da14cebeSEric Cheng 	}
4160da14cebeSEric Cheng 
4161da14cebeSEric Cheng 	state.vs_vnic_id = linkid;
4162da14cebeSEric Cheng 	state.vs_link_id = dev_linkid;
4163da14cebeSEric Cheng 	state.vs_etherstub = etherstub;
4164da14cebeSEric Cheng 	state.vs_found = B_FALSE;
4165da14cebeSEric Cheng 	state.vs_flags = flags;
4166da14cebeSEric Cheng 
4167da14cebeSEric Cheng 	if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) {
4168da14cebeSEric Cheng 		if (etherstub)
4169da14cebeSEric Cheng 			fields_str = all_e_fields;
4170da14cebeSEric Cheng 	}
4171da14cebeSEric Cheng 	pf = vnic_fields;
4172da14cebeSEric Cheng 
4173*8002d411SSowmini Varadhan 	if (state.vs_parsable)
4174*8002d411SSowmini Varadhan 		ofmtflags |= OFMT_PARSABLE;
4175*8002d411SSowmini Varadhan 	oferr = ofmt_open(fields_str, pf, ofmtflags, 0, &ofmt);
4176*8002d411SSowmini Varadhan 	dladm_ofmt_check(oferr, state.vs_parsable, ofmt);
4177*8002d411SSowmini Varadhan 	state.vs_ofmt = ofmt;
4178da14cebeSEric Cheng 
4179da14cebeSEric Cheng 	if (s_arg) {
4180da14cebeSEric Cheng 		/* Display vnic statistics */
4181da14cebeSEric Cheng 		vnic_stats(&state, interval);
4182*8002d411SSowmini Varadhan 		ofmt_close(ofmt);
4183da14cebeSEric Cheng 		return;
4184da14cebeSEric Cheng 	}
4185da14cebeSEric Cheng 
4186da14cebeSEric Cheng 	/* Display vnic information */
4187da14cebeSEric Cheng 	state.vs_donefirst = B_FALSE;
4188da14cebeSEric Cheng 
4189da14cebeSEric Cheng 	if (linkid == DATALINK_ALL_LINKID) {
41904ac67f02SAnurag S. Maskey 		(void) dladm_walk_datalink_id(show_vnic, handle, &state,
4191da14cebeSEric Cheng 		    DATALINK_CLASS_VNIC | DATALINK_CLASS_ETHERSTUB,
4192da14cebeSEric Cheng 		    DATALINK_ANY_MEDIATYPE, DLADM_OPT_ACTIVE);
4193da14cebeSEric Cheng 	} else {
41944ac67f02SAnurag S. Maskey 		(void) show_vnic(handle, linkid, &state);
4195da14cebeSEric Cheng 		if (state.vs_status != DLADM_STATUS_OK) {
4196*8002d411SSowmini Varadhan 			ofmt_close(ofmt);
4197da14cebeSEric Cheng 			die_dlerr(state.vs_status, "failed to show vnic '%s'",
4198da14cebeSEric Cheng 			    state.vs_vnic);
4199da14cebeSEric Cheng 		}
4200da14cebeSEric Cheng 	}
4201*8002d411SSowmini Varadhan 	ofmt_close(ofmt);
4202da14cebeSEric Cheng }
4203da14cebeSEric Cheng 
4204da14cebeSEric Cheng static void
4205da14cebeSEric Cheng do_show_vnic(int argc, char *argv[], const char *use)
4206da14cebeSEric Cheng {
4207da14cebeSEric Cheng 	do_show_vnic_common(argc, argv, use, B_FALSE);
4208da14cebeSEric Cheng }
4209da14cebeSEric Cheng 
4210da14cebeSEric Cheng static void
4211da14cebeSEric Cheng do_create_etherstub(int argc, char *argv[], const char *use)
4212da14cebeSEric Cheng {
4213da14cebeSEric Cheng 	uint32_t flags;
4214da14cebeSEric Cheng 	char *altroot = NULL;
4215da14cebeSEric Cheng 	char option;
4216da14cebeSEric Cheng 	dladm_status_t status;
4217da14cebeSEric Cheng 	char name[MAXLINKNAMELEN];
4218da14cebeSEric Cheng 	uchar_t mac_addr[ETHERADDRL];
4219da14cebeSEric Cheng 
4220da14cebeSEric Cheng 	name[0] = '\0';
4221da14cebeSEric Cheng 	bzero(mac_addr, sizeof (mac_addr));
4222da14cebeSEric Cheng 	flags = DLADM_OPT_ANCHOR | DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
4223da14cebeSEric Cheng 
4224da14cebeSEric Cheng 	opterr = 0;
4225da14cebeSEric Cheng 	while ((option = getopt_long(argc, argv, "tR:",
4226da14cebeSEric Cheng 	    etherstub_lopts, NULL)) != -1) {
4227da14cebeSEric Cheng 		switch (option) {
4228da14cebeSEric Cheng 		case 't':
4229da14cebeSEric Cheng 			flags &= ~DLADM_OPT_PERSIST;
4230da14cebeSEric Cheng 			break;
4231da14cebeSEric Cheng 		case 'R':
4232da14cebeSEric Cheng 			altroot = optarg;
4233da14cebeSEric Cheng 			break;
4234da14cebeSEric Cheng 		default:
4235da14cebeSEric Cheng 			die_opterr(optopt, option, use);
4236da14cebeSEric Cheng 		}
4237da14cebeSEric Cheng 	}
4238da14cebeSEric Cheng 
4239da14cebeSEric Cheng 	/* the etherstub id is the required operand */
4240da14cebeSEric Cheng 	if (optind != (argc - 1))
4241da14cebeSEric Cheng 		usage();
4242da14cebeSEric Cheng 
4243da14cebeSEric Cheng 	if (strlcpy(name, argv[optind], MAXLINKNAMELEN) >= MAXLINKNAMELEN)
4244da14cebeSEric Cheng 		die("link name too long '%s'", argv[optind]);
4245da14cebeSEric Cheng 
4246da14cebeSEric Cheng 	if (!dladm_valid_linkname(name))
4247da14cebeSEric Cheng 		die("invalid link name '%s'", argv[optind]);
4248da14cebeSEric Cheng 
4249da14cebeSEric Cheng 	if (altroot != NULL)
4250da14cebeSEric Cheng 		altroot_cmd(altroot, argc, argv);
4251da14cebeSEric Cheng 
42524ac67f02SAnurag S. Maskey 	status = dladm_vnic_create(handle, name, DATALINK_INVALID_LINKID,
4253da14cebeSEric Cheng 	    VNIC_MAC_ADDR_TYPE_AUTO, mac_addr, ETHERADDRL, NULL, 0, 0, NULL,
4254da14cebeSEric Cheng 	    NULL, flags);
4255da14cebeSEric Cheng 	if (status != DLADM_STATUS_OK)
4256da14cebeSEric Cheng 		die_dlerr(status, "etherstub creation failed");
4257da14cebeSEric Cheng 
4258da14cebeSEric Cheng 
4259da14cebeSEric Cheng }
4260da14cebeSEric Cheng 
4261da14cebeSEric Cheng static void
4262da14cebeSEric Cheng do_delete_etherstub(int argc, char *argv[], const char *use)
4263da14cebeSEric Cheng {
4264da14cebeSEric Cheng 	do_delete_vnic_common(argc, argv, use, B_TRUE);
4265da14cebeSEric Cheng }
4266da14cebeSEric Cheng 
4267da14cebeSEric Cheng /* ARGSUSED */
4268da14cebeSEric Cheng static void
4269da14cebeSEric Cheng do_show_etherstub(int argc, char *argv[], const char *use)
4270da14cebeSEric Cheng {
4271da14cebeSEric Cheng 	do_show_vnic_common(argc, argv, use, B_TRUE);
4272da14cebeSEric Cheng }
4273da14cebeSEric Cheng 
4274da14cebeSEric Cheng static void
42756be03d0bSVasumathi Sundaram - Sun Microsystems link_stats(datalink_id_t linkid, uint_t interval, char *fields_str,
42766be03d0bSVasumathi Sundaram - Sun Microsystems     show_state_t *state)
4277d62bc4baSyz147064 {
4278*8002d411SSowmini Varadhan 	ofmt_handle_t	ofmt;
4279*8002d411SSowmini Varadhan 	ofmt_status_t	oferr;
4280*8002d411SSowmini Varadhan 	uint_t		ofmtflags = 0;
428133343a97Smeem 
4282*8002d411SSowmini Varadhan 	if (state->ls_parsable)
4283*8002d411SSowmini Varadhan 		ofmtflags |= OFMT_PARSABLE;
4284*8002d411SSowmini Varadhan 	oferr = ofmt_open(fields_str, link_s_fields, ofmtflags, 0, &ofmt);
4285*8002d411SSowmini Varadhan 	dladm_ofmt_check(oferr, state->ls_parsable, ofmt);
4286*8002d411SSowmini Varadhan 	state->ls_ofmt = ofmt;
42877c478bd9Sstevel@tonic-gate 
42887c478bd9Sstevel@tonic-gate 	/*
42897c478bd9Sstevel@tonic-gate 	 * If an interval is specified, continuously show the stats
42907c478bd9Sstevel@tonic-gate 	 * only for the first MAC port.
42917c478bd9Sstevel@tonic-gate 	 */
42926be03d0bSVasumathi Sundaram - Sun Microsystems 	state->ls_firstonly = (interval != 0);
42937c478bd9Sstevel@tonic-gate 
42947c478bd9Sstevel@tonic-gate 	for (;;) {
42956be03d0bSVasumathi Sundaram - Sun Microsystems 		state->ls_donefirst = B_FALSE;
4296d62bc4baSyz147064 		if (linkid == DATALINK_ALL_LINKID) {
42974ac67f02SAnurag S. Maskey 			(void) dladm_walk_datalink_id(show_link_stats, handle,
42984ac67f02SAnurag S. Maskey 			    state, DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE,
4299d62bc4baSyz147064 			    DLADM_OPT_ACTIVE);
4300d62bc4baSyz147064 		} else {
43014ac67f02SAnurag S. Maskey 			(void) show_link_stats(handle, linkid, state);
4302d62bc4baSyz147064 		}
43037c478bd9Sstevel@tonic-gate 
43047c478bd9Sstevel@tonic-gate 		if (interval == 0)
43057c478bd9Sstevel@tonic-gate 			break;
43067c478bd9Sstevel@tonic-gate 
43077c478bd9Sstevel@tonic-gate 		(void) sleep(interval);
43087c478bd9Sstevel@tonic-gate 	}
4309*8002d411SSowmini Varadhan 	ofmt_close(ofmt);
43107c478bd9Sstevel@tonic-gate }
43117c478bd9Sstevel@tonic-gate 
43127c478bd9Sstevel@tonic-gate static void
4313d62bc4baSyz147064 aggr_stats(datalink_id_t linkid, show_grp_state_t *state, uint_t interval)
43147c478bd9Sstevel@tonic-gate {
43157c478bd9Sstevel@tonic-gate 	/*
43167c478bd9Sstevel@tonic-gate 	 * If an interval is specified, continuously show the stats
43177c478bd9Sstevel@tonic-gate 	 * only for the first group.
43187c478bd9Sstevel@tonic-gate 	 */
4319d62bc4baSyz147064 	state->gs_firstonly = (interval != 0);
43207c478bd9Sstevel@tonic-gate 
43217c478bd9Sstevel@tonic-gate 	for (;;) {
4322d62bc4baSyz147064 		state->gs_donefirst = B_FALSE;
4323d62bc4baSyz147064 		if (linkid == DATALINK_ALL_LINKID)
43244ac67f02SAnurag S. Maskey 			(void) dladm_walk_datalink_id(show_aggr, handle, state,
4325d62bc4baSyz147064 			    DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE,
4326d62bc4baSyz147064 			    DLADM_OPT_ACTIVE);
4327d62bc4baSyz147064 		else
43284ac67f02SAnurag S. Maskey 			(void) show_aggr(handle, linkid, state);
43297c478bd9Sstevel@tonic-gate 
43307c478bd9Sstevel@tonic-gate 		if (interval == 0)
43317c478bd9Sstevel@tonic-gate 			break;
43327c478bd9Sstevel@tonic-gate 
43337c478bd9Sstevel@tonic-gate 		(void) sleep(interval);
43347c478bd9Sstevel@tonic-gate 	}
43357c478bd9Sstevel@tonic-gate }
43367c478bd9Sstevel@tonic-gate 
4337da14cebeSEric Cheng /* ARGSUSED */
43387c478bd9Sstevel@tonic-gate static void
4339da14cebeSEric Cheng vnic_stats(show_vnic_state_t *sp, uint32_t interval)
43407c478bd9Sstevel@tonic-gate {
4341da14cebeSEric Cheng 	show_vnic_state_t	state;
4342da14cebeSEric Cheng 	boolean_t		specific_link, specific_dev;
43437c478bd9Sstevel@tonic-gate 
4344da14cebeSEric Cheng 	/* Display vnic statistics */
4345da14cebeSEric Cheng 	dump_vnics_head(sp->vs_link);
4346e7801d59Ssowmini 
4347da14cebeSEric Cheng 	bzero(&state, sizeof (state));
4348da14cebeSEric Cheng 	state.vs_stats = B_TRUE;
4349da14cebeSEric Cheng 	state.vs_vnic_id = sp->vs_vnic_id;
4350da14cebeSEric Cheng 	state.vs_link_id = sp->vs_link_id;
43517c478bd9Sstevel@tonic-gate 
43527c478bd9Sstevel@tonic-gate 	/*
4353da14cebeSEric Cheng 	 * If an interval is specified, and a vnic ID is not specified,
4354da14cebeSEric Cheng 	 * continuously show the stats only for the first vnic.
43557c478bd9Sstevel@tonic-gate 	 */
4356da14cebeSEric Cheng 	specific_link = (sp->vs_vnic_id != DATALINK_ALL_LINKID);
4357da14cebeSEric Cheng 	specific_dev = (sp->vs_link_id != DATALINK_ALL_LINKID);
43587c478bd9Sstevel@tonic-gate 
43597c478bd9Sstevel@tonic-gate 	for (;;) {
4360da14cebeSEric Cheng 		/* Get stats for each vnic */
4361da14cebeSEric Cheng 		state.vs_found = B_FALSE;
4362da14cebeSEric Cheng 		state.vs_donefirst = B_FALSE;
4363da14cebeSEric Cheng 		state.vs_printstats = B_FALSE;
4364da14cebeSEric Cheng 		state.vs_flags = DLADM_OPT_ACTIVE;
43657c478bd9Sstevel@tonic-gate 
4366da14cebeSEric Cheng 		if (!specific_link) {
43674ac67f02SAnurag S. Maskey 			(void) dladm_walk_datalink_id(show_vnic, handle, &state,
4368da14cebeSEric Cheng 			    DATALINK_CLASS_VNIC, DATALINK_ANY_MEDIATYPE,
4369da14cebeSEric Cheng 			    DLADM_OPT_ACTIVE);
4370da14cebeSEric Cheng 		} else {
43714ac67f02SAnurag S. Maskey 			(void) show_vnic(handle, sp->vs_vnic_id, &state);
4372da14cebeSEric Cheng 			if (state.vs_status != DLADM_STATUS_OK) {
4373da14cebeSEric Cheng 				die_dlerr(state.vs_status,
4374da14cebeSEric Cheng 				    "failed to show vnic '%s'", sp->vs_vnic);
4375da14cebeSEric Cheng 			}
4376da14cebeSEric Cheng 		}
43777c478bd9Sstevel@tonic-gate 
4378da14cebeSEric Cheng 		if (specific_link && !state.vs_found)
4379da14cebeSEric Cheng 			die("non-existent vnic '%s'", sp->vs_vnic);
4380da14cebeSEric Cheng 		if (specific_dev && !state.vs_found)
4381da14cebeSEric Cheng 			die("device %s has no vnics", sp->vs_link);
4382da14cebeSEric Cheng 
4383da14cebeSEric Cheng 		/* Show totals */
4384da14cebeSEric Cheng 		if ((specific_link | specific_dev) && !interval) {
4385da14cebeSEric Cheng 			(void) printf("Total");
4386da14cebeSEric Cheng 			(void) printf("\t%-10llu",
4387da14cebeSEric Cheng 			    state.vs_totalstats.ipackets);
4388da14cebeSEric Cheng 			(void) printf("%-12llu",
4389da14cebeSEric Cheng 			    state.vs_totalstats.rbytes);
4390da14cebeSEric Cheng 			(void) printf("%-10llu",
4391da14cebeSEric Cheng 			    state.vs_totalstats.opackets);
4392da14cebeSEric Cheng 			(void) printf("%-12llu\n",
4393da14cebeSEric Cheng 			    state.vs_totalstats.obytes);
4394da14cebeSEric Cheng 		}
4395da14cebeSEric Cheng 
4396da14cebeSEric Cheng 		/* Show stats for each vnic */
4397da14cebeSEric Cheng 		state.vs_donefirst = B_FALSE;
4398da14cebeSEric Cheng 		state.vs_printstats = B_TRUE;
4399da14cebeSEric Cheng 
4400da14cebeSEric Cheng 		if (!specific_link) {
44014ac67f02SAnurag S. Maskey 			(void) dladm_walk_datalink_id(show_vnic, handle, &state,
4402da14cebeSEric Cheng 			    DATALINK_CLASS_VNIC, DATALINK_ANY_MEDIATYPE,
4403da14cebeSEric Cheng 			    DLADM_OPT_ACTIVE);
4404da14cebeSEric Cheng 		} else {
44054ac67f02SAnurag S. Maskey 			(void) show_vnic(handle, sp->vs_vnic_id, &state);
4406da14cebeSEric Cheng 			if (state.vs_status != DLADM_STATUS_OK) {
4407da14cebeSEric Cheng 				die_dlerr(state.vs_status,
4408da14cebeSEric Cheng 				    "failed to show vnic '%s'", sp->vs_vnic);
4409da14cebeSEric Cheng 			}
4410da14cebeSEric Cheng 		}
44117c478bd9Sstevel@tonic-gate 
44127c478bd9Sstevel@tonic-gate 		if (interval == 0)
44137c478bd9Sstevel@tonic-gate 			break;
44147c478bd9Sstevel@tonic-gate 
44157c478bd9Sstevel@tonic-gate 		(void) sleep(interval);
44167c478bd9Sstevel@tonic-gate 	}
44177c478bd9Sstevel@tonic-gate }
44187c478bd9Sstevel@tonic-gate 
44197c478bd9Sstevel@tonic-gate static void
4420da14cebeSEric Cheng get_mac_stats(const char *dev, pktsum_t *stats)
44217c478bd9Sstevel@tonic-gate {
44227c478bd9Sstevel@tonic-gate 	kstat_ctl_t	*kcp;
44237c478bd9Sstevel@tonic-gate 	kstat_t		*ksp;
4424da14cebeSEric Cheng 	char module[DLPI_LINKNAME_MAX];
4425da14cebeSEric Cheng 	uint_t instance;
4426da14cebeSEric Cheng 
4427da14cebeSEric Cheng 
4428da14cebeSEric Cheng 	bzero(stats, sizeof (*stats));
4429da14cebeSEric Cheng 
4430da14cebeSEric Cheng 	if (dlpi_parselink(dev, module, &instance) != DLPI_SUCCESS)
4431da14cebeSEric Cheng 		return;
44327c478bd9Sstevel@tonic-gate 
44337c478bd9Sstevel@tonic-gate 	if ((kcp = kstat_open()) == NULL) {
443433343a97Smeem 		warn("kstat open operation failed");
44357c478bd9Sstevel@tonic-gate 		return;
44367c478bd9Sstevel@tonic-gate 	}
44377c478bd9Sstevel@tonic-gate 
4438da14cebeSEric Cheng 	ksp = dladm_kstat_lookup(kcp, module, instance, "mac", NULL);
4439da14cebeSEric Cheng 	if (ksp != NULL)
4440da14cebeSEric Cheng 		dladm_get_stats(kcp, ksp, stats);
4441da14cebeSEric Cheng 
44427c478bd9Sstevel@tonic-gate 	(void) kstat_close(kcp);
44437c478bd9Sstevel@tonic-gate 
44447c478bd9Sstevel@tonic-gate }
44457c478bd9Sstevel@tonic-gate 
44467c478bd9Sstevel@tonic-gate static void
44477c478bd9Sstevel@tonic-gate get_link_stats(const char *link, pktsum_t *stats)
44487c478bd9Sstevel@tonic-gate {
4449da14cebeSEric Cheng 	kstat_ctl_t	*kcp;
4450da14cebeSEric Cheng 	kstat_t		*ksp;
4451da14cebeSEric Cheng 
44527c478bd9Sstevel@tonic-gate 	bzero(stats, sizeof (*stats));
4453da14cebeSEric Cheng 
4454da14cebeSEric Cheng 	if ((kcp = kstat_open()) == NULL) {
4455da14cebeSEric Cheng 		warn("kstat_open operation failed");
4456da14cebeSEric Cheng 		return;
4457da14cebeSEric Cheng 	}
4458da14cebeSEric Cheng 
4459da14cebeSEric Cheng 	ksp = dladm_kstat_lookup(kcp, "link", 0, link, NULL);
4460da14cebeSEric Cheng 
4461da14cebeSEric Cheng 	if (ksp != NULL)
4462da14cebeSEric Cheng 		dladm_get_stats(kcp, ksp, stats);
4463da14cebeSEric Cheng 
4464da14cebeSEric Cheng 	(void) kstat_close(kcp);
44657c478bd9Sstevel@tonic-gate }
44667c478bd9Sstevel@tonic-gate 
4467ba2e4443Sseb static int
4468d62bc4baSyz147064 query_kstat(char *module, int instance, const char *name, const char *stat,
4469d62bc4baSyz147064     uint8_t type, void *val)
44707c478bd9Sstevel@tonic-gate {
44717c478bd9Sstevel@tonic-gate 	kstat_ctl_t	*kcp;
44727c478bd9Sstevel@tonic-gate 	kstat_t		*ksp;
44737c478bd9Sstevel@tonic-gate 
44747c478bd9Sstevel@tonic-gate 	if ((kcp = kstat_open()) == NULL) {
447533343a97Smeem 		warn("kstat open operation failed");
4476ba2e4443Sseb 		return (-1);
44777c478bd9Sstevel@tonic-gate 	}
44787c478bd9Sstevel@tonic-gate 
4479d62bc4baSyz147064 	if ((ksp = kstat_lookup(kcp, module, instance, (char *)name)) == NULL) {
44807c478bd9Sstevel@tonic-gate 		/*
44817c478bd9Sstevel@tonic-gate 		 * The kstat query could fail if the underlying MAC
44827c478bd9Sstevel@tonic-gate 		 * driver was already detached.
44837c478bd9Sstevel@tonic-gate 		 */
44847c478bd9Sstevel@tonic-gate 		goto bail;
44857c478bd9Sstevel@tonic-gate 	}
44867c478bd9Sstevel@tonic-gate 
44877c478bd9Sstevel@tonic-gate 	if (kstat_read(kcp, ksp, NULL) == -1) {
448833343a97Smeem 		warn("kstat read failed");
44897c478bd9Sstevel@tonic-gate 		goto bail;
44907c478bd9Sstevel@tonic-gate 	}
44917c478bd9Sstevel@tonic-gate 
4492e7801d59Ssowmini 	if (dladm_kstat_value(ksp, stat, type, val) < 0)
44937c478bd9Sstevel@tonic-gate 		goto bail;
4494ba2e4443Sseb 
4495ba2e4443Sseb 	(void) kstat_close(kcp);
4496ba2e4443Sseb 	return (0);
44977c478bd9Sstevel@tonic-gate 
44987c478bd9Sstevel@tonic-gate bail:
44997c478bd9Sstevel@tonic-gate 	(void) kstat_close(kcp);
4500ba2e4443Sseb 	return (-1);
4501ba2e4443Sseb }
4502ba2e4443Sseb 
4503d62bc4baSyz147064 static int
4504d62bc4baSyz147064 get_one_kstat(const char *name, const char *stat, uint8_t type,
4505d62bc4baSyz147064     void *val, boolean_t islink)
4506d62bc4baSyz147064 {
4507d62bc4baSyz147064 	char		module[DLPI_LINKNAME_MAX];
4508d62bc4baSyz147064 	uint_t		instance;
4509d62bc4baSyz147064 
4510d62bc4baSyz147064 	if (islink) {
4511d62bc4baSyz147064 		return (query_kstat("link", 0, name, stat, type, val));
4512d62bc4baSyz147064 	} else {
4513d62bc4baSyz147064 		if (dlpi_parselink(name, module, &instance) != DLPI_SUCCESS)
4514d62bc4baSyz147064 			return (-1);
4515d62bc4baSyz147064 
4516d62bc4baSyz147064 		return (query_kstat(module, instance, "mac", stat, type, val));
4517d62bc4baSyz147064 	}
4518d62bc4baSyz147064 }
4519d62bc4baSyz147064 
4520ba2e4443Sseb static uint64_t
4521d62bc4baSyz147064 get_ifspeed(const char *name, boolean_t islink)
4522ba2e4443Sseb {
4523ba2e4443Sseb 	uint64_t ifspeed = 0;
4524ba2e4443Sseb 
4525d62bc4baSyz147064 	(void) get_one_kstat(name, "ifspeed", KSTAT_DATA_UINT64,
4526d62bc4baSyz147064 	    &ifspeed, islink);
4527d62bc4baSyz147064 
45287c478bd9Sstevel@tonic-gate 	return (ifspeed);
45297c478bd9Sstevel@tonic-gate }
45307c478bd9Sstevel@tonic-gate 
4531f595a68aSyz147064 static const char *
4532d62bc4baSyz147064 get_linkstate(const char *name, boolean_t islink, char *buf)
45337c478bd9Sstevel@tonic-gate {
4534d62bc4baSyz147064 	link_state_t	linkstate;
45357c478bd9Sstevel@tonic-gate 
4536d62bc4baSyz147064 	if (get_one_kstat(name, "link_state", KSTAT_DATA_UINT32,
4537d62bc4baSyz147064 	    &linkstate, islink) != 0) {
4538da14cebeSEric Cheng 		(void) strlcpy(buf, "?", DLADM_STRSIZE);
45393a62633bSyz147064 		return (buf);
45407c478bd9Sstevel@tonic-gate 	}
4541d62bc4baSyz147064 	return (dladm_linkstate2str(linkstate, buf));
45427c478bd9Sstevel@tonic-gate }
45437c478bd9Sstevel@tonic-gate 
4544f595a68aSyz147064 static const char *
4545d62bc4baSyz147064 get_linkduplex(const char *name, boolean_t islink, char *buf)
45467c478bd9Sstevel@tonic-gate {
4547d62bc4baSyz147064 	link_duplex_t	linkduplex;
45487c478bd9Sstevel@tonic-gate 
4549d62bc4baSyz147064 	if (get_one_kstat(name, "link_duplex", KSTAT_DATA_UINT32,
4550d62bc4baSyz147064 	    &linkduplex, islink) != 0) {
45513a62633bSyz147064 		(void) strlcpy(buf, "unknown", DLADM_STRSIZE);
45523a62633bSyz147064 		return (buf);
45537c478bd9Sstevel@tonic-gate 	}
45547c478bd9Sstevel@tonic-gate 
4555d62bc4baSyz147064 	return (dladm_linkduplex2str(linkduplex, buf));
45567c478bd9Sstevel@tonic-gate }
45570ba2cbe9Sxc151355 
45580ba2cbe9Sxc151355 static int
4559*8002d411SSowmini Varadhan parse_wifi_fields(char *str, ofmt_handle_t *ofmt, uint_t cmdtype,
4560*8002d411SSowmini Varadhan     boolean_t parsable)
45610ba2cbe9Sxc151355 {
4562*8002d411SSowmini Varadhan 	ofmt_field_t	*template, *of;
4563*8002d411SSowmini Varadhan 	ofmt_cb_t	*fn;
4564*8002d411SSowmini Varadhan 	ofmt_status_t	oferr;
45650ba2cbe9Sxc151355 
45660ba2cbe9Sxc151355 	if (cmdtype == WIFI_CMD_SCAN) {
4567*8002d411SSowmini Varadhan 		template = wifi_common_fields;
45680ba2cbe9Sxc151355 		if (str == NULL)
45690ba2cbe9Sxc151355 			str = def_scan_wifi_fields;
45700ba2cbe9Sxc151355 		if (strcasecmp(str, "all") == 0)
45710ba2cbe9Sxc151355 			str = all_scan_wifi_fields;
4572*8002d411SSowmini Varadhan 		fn = print_wlan_attr_cb;
45730ba2cbe9Sxc151355 	} else if (cmdtype == WIFI_CMD_SHOW) {
4574*8002d411SSowmini Varadhan 		bcopy(wifi_common_fields, &wifi_show_fields[2],
4575*8002d411SSowmini Varadhan 		    sizeof (wifi_common_fields));
4576*8002d411SSowmini Varadhan 		template = wifi_show_fields;
45770ba2cbe9Sxc151355 		if (str == NULL)
45780ba2cbe9Sxc151355 			str = def_show_wifi_fields;
45790ba2cbe9Sxc151355 		if (strcasecmp(str, "all") == 0)
45800ba2cbe9Sxc151355 			str = all_show_wifi_fields;
4581*8002d411SSowmini Varadhan 		fn = print_link_attr_cb;
45820ba2cbe9Sxc151355 	} else {
45830ba2cbe9Sxc151355 		return (-1);
45840ba2cbe9Sxc151355 	}
4585*8002d411SSowmini Varadhan 
4586*8002d411SSowmini Varadhan 	for (of = template; of->of_name != NULL; of++) {
4587*8002d411SSowmini Varadhan 		if (of->of_cb == NULL)
4588*8002d411SSowmini Varadhan 			of->of_cb = fn;
4589*8002d411SSowmini Varadhan 	}
4590*8002d411SSowmini Varadhan 
4591*8002d411SSowmini Varadhan 	oferr = ofmt_open(str, template, (parsable ? OFMT_PARSABLE : 0),
4592*8002d411SSowmini Varadhan 	    0, ofmt);
4593*8002d411SSowmini Varadhan 	dladm_ofmt_check(oferr, parsable, *ofmt);
4594e7801d59Ssowmini 	return (0);
45950ba2cbe9Sxc151355 }
45960ba2cbe9Sxc151355 
45970ba2cbe9Sxc151355 typedef struct print_wifi_state {
4598d62bc4baSyz147064 	char		*ws_link;
4599*8002d411SSowmini Varadhan 	boolean_t	ws_parsable;
46000ba2cbe9Sxc151355 	boolean_t	ws_header;
4601*8002d411SSowmini Varadhan 	ofmt_handle_t	ws_ofmt;
46020ba2cbe9Sxc151355 } print_wifi_state_t;
46030ba2cbe9Sxc151355 
4604e7801d59Ssowmini typedef struct  wlan_scan_args_s {
4605e7801d59Ssowmini 	print_wifi_state_t	*ws_state;
4606e7801d59Ssowmini 	void			*ws_attr;
4607e7801d59Ssowmini } wlan_scan_args_t;
46080ba2cbe9Sxc151355 
4609*8002d411SSowmini Varadhan static boolean_t
4610*8002d411SSowmini Varadhan print_wlan_attr_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
46110ba2cbe9Sxc151355 {
4612*8002d411SSowmini Varadhan 	wlan_scan_args_t	*w = ofarg->ofmt_cbarg;
4613e7801d59Ssowmini 	print_wifi_state_t	*statep = w->ws_state;
4614e7801d59Ssowmini 	dladm_wlan_attr_t	*attrp = w->ws_attr;
4615*8002d411SSowmini Varadhan 	char			tmpbuf[DLADM_STRSIZE];
46160ba2cbe9Sxc151355 
4617*8002d411SSowmini Varadhan 	if (ofarg->ofmt_id == 0) {
4618*8002d411SSowmini Varadhan 		(void) strlcpy(buf, (char *)statep->ws_link, bufsize);
4619*8002d411SSowmini Varadhan 		return (B_TRUE);
46200ba2cbe9Sxc151355 	}
46210ba2cbe9Sxc151355 
4622*8002d411SSowmini Varadhan 	if ((ofarg->ofmt_id & attrp->wa_valid) == 0)
4623*8002d411SSowmini Varadhan 		return (B_TRUE);
46240ba2cbe9Sxc151355 
4625*8002d411SSowmini Varadhan 	switch (ofarg->ofmt_id) {
4626f595a68aSyz147064 	case DLADM_WLAN_ATTR_ESSID:
4627*8002d411SSowmini Varadhan 		(void) dladm_wlan_essid2str(&attrp->wa_essid, tmpbuf);
46280ba2cbe9Sxc151355 		break;
4629f595a68aSyz147064 	case DLADM_WLAN_ATTR_BSSID:
4630*8002d411SSowmini Varadhan 		(void) dladm_wlan_bssid2str(&attrp->wa_bssid, tmpbuf);
46310ba2cbe9Sxc151355 		break;
4632f595a68aSyz147064 	case DLADM_WLAN_ATTR_SECMODE:
4633*8002d411SSowmini Varadhan 		(void) dladm_wlan_secmode2str(&attrp->wa_secmode, tmpbuf);
46340ba2cbe9Sxc151355 		break;
4635f595a68aSyz147064 	case DLADM_WLAN_ATTR_STRENGTH:
4636*8002d411SSowmini Varadhan 		(void) dladm_wlan_strength2str(&attrp->wa_strength, tmpbuf);
46370ba2cbe9Sxc151355 		break;
4638f595a68aSyz147064 	case DLADM_WLAN_ATTR_MODE:
4639*8002d411SSowmini Varadhan 		(void) dladm_wlan_mode2str(&attrp->wa_mode, tmpbuf);
46400ba2cbe9Sxc151355 		break;
4641f595a68aSyz147064 	case DLADM_WLAN_ATTR_SPEED:
4642*8002d411SSowmini Varadhan 		(void) dladm_wlan_speed2str(&attrp->wa_speed, tmpbuf);
4643*8002d411SSowmini Varadhan 		(void) strlcat(tmpbuf, "Mb", sizeof (tmpbuf));
46440ba2cbe9Sxc151355 		break;
4645f595a68aSyz147064 	case DLADM_WLAN_ATTR_AUTH:
4646*8002d411SSowmini Varadhan 		(void) dladm_wlan_auth2str(&attrp->wa_auth, tmpbuf);
46470ba2cbe9Sxc151355 		break;
4648f595a68aSyz147064 	case DLADM_WLAN_ATTR_BSSTYPE:
4649*8002d411SSowmini Varadhan 		(void) dladm_wlan_bsstype2str(&attrp->wa_bsstype, tmpbuf);
46500ba2cbe9Sxc151355 		break;
46510ba2cbe9Sxc151355 	}
4652*8002d411SSowmini Varadhan 	(void) strlcpy(buf, tmpbuf, bufsize);
46530ba2cbe9Sxc151355 
4654*8002d411SSowmini Varadhan 	return (B_TRUE);
46550ba2cbe9Sxc151355 }
46560ba2cbe9Sxc151355 
46570ba2cbe9Sxc151355 static boolean_t
4658f595a68aSyz147064 print_scan_results(void *arg, dladm_wlan_attr_t *attrp)
46590ba2cbe9Sxc151355 {
46600ba2cbe9Sxc151355 	print_wifi_state_t	*statep = arg;
4661e7801d59Ssowmini 	wlan_scan_args_t	warg;
46620ba2cbe9Sxc151355 
4663e7801d59Ssowmini 	bzero(&warg, sizeof (warg));
4664e7801d59Ssowmini 	warg.ws_state = statep;
4665e7801d59Ssowmini 	warg.ws_attr = attrp;
4666*8002d411SSowmini Varadhan 	ofmt_print(statep->ws_ofmt, &warg);
46670ba2cbe9Sxc151355 	return (B_TRUE);
46680ba2cbe9Sxc151355 }
46690ba2cbe9Sxc151355 
4670d62bc4baSyz147064 static int
46714ac67f02SAnurag S. Maskey scan_wifi(dladm_handle_t dh, datalink_id_t linkid, void *arg)
46720ba2cbe9Sxc151355 {
46730ba2cbe9Sxc151355 	print_wifi_state_t	*statep = arg;
4674f595a68aSyz147064 	dladm_status_t		status;
4675d62bc4baSyz147064 	char			link[MAXLINKNAMELEN];
4676d62bc4baSyz147064 
46774ac67f02SAnurag S. Maskey 	if ((status = dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, link,
4678e7801d59Ssowmini 	    sizeof (link))) != DLADM_STATUS_OK) {
4679d62bc4baSyz147064 		return (DLADM_WALK_CONTINUE);
4680d62bc4baSyz147064 	}
46810ba2cbe9Sxc151355 
46820ba2cbe9Sxc151355 	statep->ws_link = link;
46834ac67f02SAnurag S. Maskey 	status = dladm_wlan_scan(dh, linkid, statep, print_scan_results);
4684f595a68aSyz147064 	if (status != DLADM_STATUS_OK)
4685d62bc4baSyz147064 		die_dlerr(status, "cannot scan link '%s'", statep->ws_link);
468633343a97Smeem 
4687d62bc4baSyz147064 	return (DLADM_WALK_CONTINUE);
46880ba2cbe9Sxc151355 }
46890ba2cbe9Sxc151355 
4690*8002d411SSowmini Varadhan static boolean_t
4691*8002d411SSowmini Varadhan print_wifi_status_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
46920ba2cbe9Sxc151355 {
4693*8002d411SSowmini Varadhan 	static char		tmpbuf[DLADM_STRSIZE];
4694*8002d411SSowmini Varadhan 	wlan_scan_args_t	*w = ofarg->ofmt_cbarg;
4695*8002d411SSowmini Varadhan 	dladm_wlan_linkattr_t	*attrp = w->ws_attr;
4696*8002d411SSowmini Varadhan 
4697*8002d411SSowmini Varadhan 	if ((ofarg->ofmt_id & attrp->la_valid) != 0) {
4698*8002d411SSowmini Varadhan 		(void) dladm_wlan_linkstatus2str(&attrp->la_status, tmpbuf);
4699*8002d411SSowmini Varadhan 		(void) strlcpy(buf, tmpbuf, bufsize);
4700*8002d411SSowmini Varadhan 	}
4701*8002d411SSowmini Varadhan 	return (B_TRUE);
4702*8002d411SSowmini Varadhan }
4703*8002d411SSowmini Varadhan 
4704*8002d411SSowmini Varadhan static boolean_t
4705*8002d411SSowmini Varadhan print_link_attr_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
4706*8002d411SSowmini Varadhan {
4707*8002d411SSowmini Varadhan 	wlan_scan_args_t	*w = ofarg->ofmt_cbarg, w1;
4708e7801d59Ssowmini 	print_wifi_state_t	*statep = w->ws_state;
4709e7801d59Ssowmini 	dladm_wlan_linkattr_t	*attrp = w->ws_attr;
47100ba2cbe9Sxc151355 
4711e7801d59Ssowmini 	bzero(&w1, sizeof (w1));
4712e7801d59Ssowmini 	w1.ws_state = statep;
4713e7801d59Ssowmini 	w1.ws_attr = &attrp->la_wlan_attr;
4714*8002d411SSowmini Varadhan 	ofarg->ofmt_cbarg = &w1;
4715*8002d411SSowmini Varadhan 	return (print_wlan_attr_cb(ofarg, buf, bufsize));
47160ba2cbe9Sxc151355 }
47170ba2cbe9Sxc151355 
4718d62bc4baSyz147064 static int
47194ac67f02SAnurag S. Maskey show_wifi(dladm_handle_t dh, datalink_id_t linkid, void *arg)
47200ba2cbe9Sxc151355 {
47210ba2cbe9Sxc151355 	print_wifi_state_t	*statep = arg;
4722f595a68aSyz147064 	dladm_wlan_linkattr_t	attr;
4723f595a68aSyz147064 	dladm_status_t		status;
4724d62bc4baSyz147064 	char			link[MAXLINKNAMELEN];
4725e7801d59Ssowmini 	wlan_scan_args_t	warg;
47260ba2cbe9Sxc151355 
47274ac67f02SAnurag S. Maskey 	if ((status = dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, link,
4728e7801d59Ssowmini 	    sizeof (link))) != DLADM_STATUS_OK) {
4729d62bc4baSyz147064 		return (DLADM_WALK_CONTINUE);
4730d62bc4baSyz147064 	}
4731d62bc4baSyz147064 
47325f5c9f54SAnurag S. Maskey 	/* dladm_wlan_get_linkattr() memsets attr with 0 */
47334ac67f02SAnurag S. Maskey 	status = dladm_wlan_get_linkattr(dh, linkid, &attr);
4734f595a68aSyz147064 	if (status != DLADM_STATUS_OK)
4735d62bc4baSyz147064 		die_dlerr(status, "cannot get link attributes for %s", link);
4736d62bc4baSyz147064 
4737d62bc4baSyz147064 	statep->ws_link = link;
47380ba2cbe9Sxc151355 
4739e7801d59Ssowmini 	bzero(&warg, sizeof (warg));
4740e7801d59Ssowmini 	warg.ws_state = statep;
4741e7801d59Ssowmini 	warg.ws_attr = &attr;
4742*8002d411SSowmini Varadhan 	ofmt_print(statep->ws_ofmt, &warg);
4743d62bc4baSyz147064 	return (DLADM_WALK_CONTINUE);
47440ba2cbe9Sxc151355 }
47450ba2cbe9Sxc151355 
47460ba2cbe9Sxc151355 static void
47478d5c46e6Sam223141 do_display_wifi(int argc, char **argv, int cmd, const char *use)
47480ba2cbe9Sxc151355 {
47490ba2cbe9Sxc151355 	int			option;
47500ba2cbe9Sxc151355 	char			*fields_str = NULL;
47514ac67f02SAnurag S. Maskey 	int		(*callback)(dladm_handle_t, datalink_id_t, void *);
47520ba2cbe9Sxc151355 	print_wifi_state_t	state;
4753d62bc4baSyz147064 	datalink_id_t		linkid = DATALINK_ALL_LINKID;
4754f595a68aSyz147064 	dladm_status_t		status;
47550ba2cbe9Sxc151355 
47560ba2cbe9Sxc151355 	if (cmd == WIFI_CMD_SCAN)
47570ba2cbe9Sxc151355 		callback = scan_wifi;
47580ba2cbe9Sxc151355 	else if (cmd == WIFI_CMD_SHOW)
47590ba2cbe9Sxc151355 		callback = show_wifi;
47600ba2cbe9Sxc151355 	else
47610ba2cbe9Sxc151355 		return;
47620ba2cbe9Sxc151355 
4763*8002d411SSowmini Varadhan 	state.ws_parsable = B_FALSE;
47640ba2cbe9Sxc151355 	state.ws_header = B_TRUE;
47650ba2cbe9Sxc151355 	opterr = 0;
47660ba2cbe9Sxc151355 	while ((option = getopt_long(argc, argv, ":o:p",
47670ba2cbe9Sxc151355 	    wifi_longopts, NULL)) != -1) {
47680ba2cbe9Sxc151355 		switch (option) {
47690ba2cbe9Sxc151355 		case 'o':
47700ba2cbe9Sxc151355 			fields_str = optarg;
47710ba2cbe9Sxc151355 			break;
47720ba2cbe9Sxc151355 		case 'p':
4773*8002d411SSowmini Varadhan 			state.ws_parsable = B_TRUE;
47740ba2cbe9Sxc151355 			break;
47750ba2cbe9Sxc151355 		default:
47768d5c46e6Sam223141 			die_opterr(optopt, option, use);
47770ba2cbe9Sxc151355 		}
47780ba2cbe9Sxc151355 	}
47790ba2cbe9Sxc151355 
4780*8002d411SSowmini Varadhan 	if (state.ws_parsable && fields_str == NULL)
47810d365605Sschuster 		die("-p requires -o");
47820d365605Sschuster 
4783*8002d411SSowmini Varadhan 	if (state.ws_parsable && strcasecmp(fields_str, "all") == 0)
47840d365605Sschuster 		die("\"-o all\" is invalid with -p");
47850d365605Sschuster 
4786d62bc4baSyz147064 	if (optind == (argc - 1)) {
47874ac67f02SAnurag S. Maskey 		if ((status = dladm_name2info(handle, argv[optind], &linkid,
47884ac67f02SAnurag S. Maskey 		    NULL, NULL, NULL)) != DLADM_STATUS_OK) {
4789d62bc4baSyz147064 			die_dlerr(status, "link %s is not valid", argv[optind]);
4790d62bc4baSyz147064 		}
4791d62bc4baSyz147064 	} else if (optind != argc) {
47920ba2cbe9Sxc151355 		usage();
4793d62bc4baSyz147064 	}
47940ba2cbe9Sxc151355 
4795*8002d411SSowmini Varadhan 	if (parse_wifi_fields(fields_str, &state.ws_ofmt, cmd,
4796*8002d411SSowmini Varadhan 	    state.ws_parsable) < 0)
479733343a97Smeem 		die("invalid field(s) specified");
479833343a97Smeem 
4799d62bc4baSyz147064 	if (linkid == DATALINK_ALL_LINKID) {
48004ac67f02SAnurag S. Maskey 		(void) dladm_walk_datalink_id(callback, handle, &state,
4801d62bc4baSyz147064 		    DATALINK_CLASS_PHYS, DL_WIFI, DLADM_OPT_ACTIVE);
48020ba2cbe9Sxc151355 	} else {
48034ac67f02SAnurag S. Maskey 		(void) (*callback)(handle, linkid, &state);
48040ba2cbe9Sxc151355 	}
4805*8002d411SSowmini Varadhan 	ofmt_close(state.ws_ofmt);
48060ba2cbe9Sxc151355 }
48070ba2cbe9Sxc151355 
48080ba2cbe9Sxc151355 static void
48098d5c46e6Sam223141 do_scan_wifi(int argc, char **argv, const char *use)
48100ba2cbe9Sxc151355 {
48118d5c46e6Sam223141 	do_display_wifi(argc, argv, WIFI_CMD_SCAN, use);
48120ba2cbe9Sxc151355 }
48130ba2cbe9Sxc151355 
48140ba2cbe9Sxc151355 static void
48158d5c46e6Sam223141 do_show_wifi(int argc, char **argv, const char *use)
48160ba2cbe9Sxc151355 {
48178d5c46e6Sam223141 	do_display_wifi(argc, argv, WIFI_CMD_SHOW, use);
48180ba2cbe9Sxc151355 }
48190ba2cbe9Sxc151355 
48200ba2cbe9Sxc151355 typedef struct wlan_count_attr {
48210ba2cbe9Sxc151355 	uint_t		wc_count;
4822d62bc4baSyz147064 	datalink_id_t	wc_linkid;
48230ba2cbe9Sxc151355 } wlan_count_attr_t;
48240ba2cbe9Sxc151355 
48254ac67f02SAnurag S. Maskey /* ARGSUSED */
4826d62bc4baSyz147064 static int
48274ac67f02SAnurag S. Maskey do_count_wlan(dladm_handle_t dh, datalink_id_t linkid, void *arg)
48280ba2cbe9Sxc151355 {
482933343a97Smeem 	wlan_count_attr_t *cp = arg;
48300ba2cbe9Sxc151355 
48310ba2cbe9Sxc151355 	if (cp->wc_count == 0)
4832d62bc4baSyz147064 		cp->wc_linkid = linkid;
48330ba2cbe9Sxc151355 	cp->wc_count++;
4834d62bc4baSyz147064 	return (DLADM_WALK_CONTINUE);
48350ba2cbe9Sxc151355 }
48360ba2cbe9Sxc151355 
48370ba2cbe9Sxc151355 static int
4838a399b765Szf162725 parse_wlan_keys(char *str, dladm_wlan_key_t **keys, uint_t *key_countp)
48390ba2cbe9Sxc151355 {
48400ba2cbe9Sxc151355 	uint_t			i;
4841a399b765Szf162725 	dladm_wlan_key_t	*wk;
4842*8002d411SSowmini Varadhan 	int			nfields = 1;
4843*8002d411SSowmini Varadhan 	char			*field, *token, *lasts = NULL, c;
48440ba2cbe9Sxc151355 
4845*8002d411SSowmini Varadhan 	token = str;
4846*8002d411SSowmini Varadhan 	while ((c = *token++) != NULL) {
4847*8002d411SSowmini Varadhan 		if (c == ',')
4848*8002d411SSowmini Varadhan 			nfields++;
4849*8002d411SSowmini Varadhan 	}
4850*8002d411SSowmini Varadhan 	token = strdup(str);
4851*8002d411SSowmini Varadhan 	if (token == NULL)
48520ba2cbe9Sxc151355 		return (-1);
48530ba2cbe9Sxc151355 
4854*8002d411SSowmini Varadhan 	wk = malloc(nfields * sizeof (dladm_wlan_key_t));
48550ba2cbe9Sxc151355 	if (wk == NULL)
48560ba2cbe9Sxc151355 		goto fail;
48570ba2cbe9Sxc151355 
4858*8002d411SSowmini Varadhan 	token = str;
4859*8002d411SSowmini Varadhan 	for (i = 0; i < nfields; i++) {
48600ba2cbe9Sxc151355 		char			*s;
48610ba2cbe9Sxc151355 		dladm_secobj_class_t	class;
48620ba2cbe9Sxc151355 		dladm_status_t		status;
48630ba2cbe9Sxc151355 
4864*8002d411SSowmini Varadhan 		field = strtok_r(token, ",", &lasts);
4865*8002d411SSowmini Varadhan 		token = NULL;
4866*8002d411SSowmini Varadhan 
4867*8002d411SSowmini Varadhan 		(void) strlcpy(wk[i].wk_name, field,
4868a399b765Szf162725 		    DLADM_WLAN_MAX_KEYNAME_LEN);
48690ba2cbe9Sxc151355 
48700ba2cbe9Sxc151355 		wk[i].wk_idx = 1;
48710ba2cbe9Sxc151355 		if ((s = strrchr(wk[i].wk_name, ':')) != NULL) {
48720ba2cbe9Sxc151355 			if (s[1] == '\0' || s[2] != '\0' || !isdigit(s[1]))
48730ba2cbe9Sxc151355 				goto fail;
48740ba2cbe9Sxc151355 
48750ba2cbe9Sxc151355 			wk[i].wk_idx = (uint_t)(s[1] - '0');
48760ba2cbe9Sxc151355 			*s = '\0';
48770ba2cbe9Sxc151355 		}
4878a399b765Szf162725 		wk[i].wk_len = DLADM_WLAN_MAX_KEY_LEN;
48790ba2cbe9Sxc151355 
48804ac67f02SAnurag S. Maskey 		status = dladm_get_secobj(handle, wk[i].wk_name, &class,
48810ba2cbe9Sxc151355 		    wk[i].wk_val, &wk[i].wk_len, 0);
48820ba2cbe9Sxc151355 		if (status != DLADM_STATUS_OK) {
48830ba2cbe9Sxc151355 			if (status == DLADM_STATUS_NOTFOUND) {
48844ac67f02SAnurag S. Maskey 				status = dladm_get_secobj(handle, wk[i].wk_name,
48850ba2cbe9Sxc151355 				    &class, wk[i].wk_val, &wk[i].wk_len,
48860ba2cbe9Sxc151355 				    DLADM_OPT_PERSIST);
48870ba2cbe9Sxc151355 			}
48880ba2cbe9Sxc151355 			if (status != DLADM_STATUS_OK)
48890ba2cbe9Sxc151355 				goto fail;
48900ba2cbe9Sxc151355 		}
4891a399b765Szf162725 		wk[i].wk_class = class;
48920ba2cbe9Sxc151355 	}
48930ba2cbe9Sxc151355 	*keys = wk;
48940ba2cbe9Sxc151355 	*key_countp = i;
4895*8002d411SSowmini Varadhan 	free(token);
48960ba2cbe9Sxc151355 	return (0);
48970ba2cbe9Sxc151355 fail:
48980ba2cbe9Sxc151355 	free(wk);
4899*8002d411SSowmini Varadhan 	free(token);
49000ba2cbe9Sxc151355 	return (-1);
49010ba2cbe9Sxc151355 }
49020ba2cbe9Sxc151355 
49030ba2cbe9Sxc151355 static void
49048d5c46e6Sam223141 do_connect_wifi(int argc, char **argv, const char *use)
49050ba2cbe9Sxc151355 {
49060ba2cbe9Sxc151355 	int			option;
4907f595a68aSyz147064 	dladm_wlan_attr_t	attr, *attrp;
4908f595a68aSyz147064 	dladm_status_t		status = DLADM_STATUS_OK;
4909f595a68aSyz147064 	int			timeout = DLADM_WLAN_CONNECT_TIMEOUT_DEFAULT;
4910d62bc4baSyz147064 	datalink_id_t		linkid = DATALINK_ALL_LINKID;
4911a399b765Szf162725 	dladm_wlan_key_t	*keys = NULL;
49120ba2cbe9Sxc151355 	uint_t			key_count = 0;
49130ba2cbe9Sxc151355 	uint_t			flags = 0;
4914f595a68aSyz147064 	dladm_wlan_secmode_t	keysecmode = DLADM_WLAN_SECMODE_NONE;
4915a399b765Szf162725 	char			buf[DLADM_STRSIZE];
49160ba2cbe9Sxc151355 
49170ba2cbe9Sxc151355 	opterr = 0;
49180ba2cbe9Sxc151355 	(void) memset(&attr, 0, sizeof (attr));
49190ba2cbe9Sxc151355 	while ((option = getopt_long(argc, argv, ":e:i:a:m:b:s:k:T:c",
49200ba2cbe9Sxc151355 	    wifi_longopts, NULL)) != -1) {
49210ba2cbe9Sxc151355 		switch (option) {
49220ba2cbe9Sxc151355 		case 'e':
4923f595a68aSyz147064 			status = dladm_wlan_str2essid(optarg, &attr.wa_essid);
4924f595a68aSyz147064 			if (status != DLADM_STATUS_OK)
492533343a97Smeem 				die("invalid ESSID '%s'", optarg);
492633343a97Smeem 
4927f595a68aSyz147064 			attr.wa_valid |= DLADM_WLAN_ATTR_ESSID;
49280ba2cbe9Sxc151355 			/*
49290ba2cbe9Sxc151355 			 * Try to connect without doing a scan.
49300ba2cbe9Sxc151355 			 */
4931f595a68aSyz147064 			flags |= DLADM_WLAN_CONNECT_NOSCAN;
49320ba2cbe9Sxc151355 			break;
49330ba2cbe9Sxc151355 		case 'i':
4934f595a68aSyz147064 			status = dladm_wlan_str2bssid(optarg, &attr.wa_bssid);
4935f595a68aSyz147064 			if (status != DLADM_STATUS_OK)
493633343a97Smeem 				die("invalid BSSID %s", optarg);
493733343a97Smeem 
4938f595a68aSyz147064 			attr.wa_valid |= DLADM_WLAN_ATTR_BSSID;
49390ba2cbe9Sxc151355 			break;
49400ba2cbe9Sxc151355 		case 'a':
4941f595a68aSyz147064 			status = dladm_wlan_str2auth(optarg, &attr.wa_auth);
4942f595a68aSyz147064 			if (status != DLADM_STATUS_OK)
494333343a97Smeem 				die("invalid authentication mode '%s'", optarg);
494433343a97Smeem 
4945f595a68aSyz147064 			attr.wa_valid |= DLADM_WLAN_ATTR_AUTH;
49460ba2cbe9Sxc151355 			break;
49470ba2cbe9Sxc151355 		case 'm':
4948f595a68aSyz147064 			status = dladm_wlan_str2mode(optarg, &attr.wa_mode);
4949f595a68aSyz147064 			if (status != DLADM_STATUS_OK)
495033343a97Smeem 				die("invalid mode '%s'", optarg);
495133343a97Smeem 
4952f595a68aSyz147064 			attr.wa_valid |= DLADM_WLAN_ATTR_MODE;
49530ba2cbe9Sxc151355 			break;
49540ba2cbe9Sxc151355 		case 'b':
4955f595a68aSyz147064 			if ((status = dladm_wlan_str2bsstype(optarg,
4956f595a68aSyz147064 			    &attr.wa_bsstype)) != DLADM_STATUS_OK) {
495733343a97Smeem 				die("invalid bsstype '%s'", optarg);
4958f595a68aSyz147064 			}
495933343a97Smeem 
4960f595a68aSyz147064 			attr.wa_valid |= DLADM_WLAN_ATTR_BSSTYPE;
49610ba2cbe9Sxc151355 			break;
49620ba2cbe9Sxc151355 		case 's':
4963f595a68aSyz147064 			if ((status = dladm_wlan_str2secmode(optarg,
4964f595a68aSyz147064 			    &attr.wa_secmode)) != DLADM_STATUS_OK) {
496533343a97Smeem 				die("invalid security mode '%s'", optarg);
4966f595a68aSyz147064 			}
496733343a97Smeem 
4968f595a68aSyz147064 			attr.wa_valid |= DLADM_WLAN_ATTR_SECMODE;
49690ba2cbe9Sxc151355 			break;
49700ba2cbe9Sxc151355 		case 'k':
4971a399b765Szf162725 			if (parse_wlan_keys(optarg, &keys, &key_count) < 0)
497233343a97Smeem 				die("invalid key(s) '%s'", optarg);
497333343a97Smeem 
4974a399b765Szf162725 			if (keys[0].wk_class == DLADM_SECOBJ_CLASS_WEP)
4975f595a68aSyz147064 				keysecmode = DLADM_WLAN_SECMODE_WEP;
4976a399b765Szf162725 			else
4977a399b765Szf162725 				keysecmode = DLADM_WLAN_SECMODE_WPA;
49780ba2cbe9Sxc151355 			break;
49790ba2cbe9Sxc151355 		case 'T':
49800ba2cbe9Sxc151355 			if (strcasecmp(optarg, "forever") == 0) {
49810ba2cbe9Sxc151355 				timeout = -1;
49820ba2cbe9Sxc151355 				break;
49830ba2cbe9Sxc151355 			}
498433343a97Smeem 			if (!str2int(optarg, &timeout) || timeout < 0)
498533343a97Smeem 				die("invalid timeout value '%s'", optarg);
49860ba2cbe9Sxc151355 			break;
49870ba2cbe9Sxc151355 		case 'c':
4988f595a68aSyz147064 			flags |= DLADM_WLAN_CONNECT_CREATEIBSS;
4989a399b765Szf162725 			flags |= DLADM_WLAN_CONNECT_CREATEIBSS;
49900ba2cbe9Sxc151355 			break;
49910ba2cbe9Sxc151355 		default:
49928d5c46e6Sam223141 			die_opterr(optopt, option, use);
49930ba2cbe9Sxc151355 			break;
49940ba2cbe9Sxc151355 		}
49950ba2cbe9Sxc151355 	}
49960ba2cbe9Sxc151355 
4997f595a68aSyz147064 	if (keysecmode == DLADM_WLAN_SECMODE_NONE) {
4998a399b765Szf162725 		if ((attr.wa_valid & DLADM_WLAN_ATTR_SECMODE) != 0) {
4999a399b765Szf162725 			die("key required for security mode '%s'",
5000a399b765Szf162725 			    dladm_wlan_secmode2str(&attr.wa_secmode, buf));
5001a399b765Szf162725 		}
50020ba2cbe9Sxc151355 	} else {
5003f595a68aSyz147064 		if ((attr.wa_valid & DLADM_WLAN_ATTR_SECMODE) != 0 &&
500433343a97Smeem 		    attr.wa_secmode != keysecmode)
500533343a97Smeem 			die("incompatible -s and -k options");
5006f595a68aSyz147064 		attr.wa_valid |= DLADM_WLAN_ATTR_SECMODE;
5007a399b765Szf162725 		attr.wa_secmode = keysecmode;
5008a399b765Szf162725 	}
50090ba2cbe9Sxc151355 
5010d62bc4baSyz147064 	if (optind == (argc - 1)) {
50114ac67f02SAnurag S. Maskey 		if ((status = dladm_name2info(handle, argv[optind], &linkid,
50124ac67f02SAnurag S. Maskey 		    NULL, NULL, NULL)) != DLADM_STATUS_OK) {
5013d62bc4baSyz147064 			die_dlerr(status, "link %s is not valid", argv[optind]);
5014d62bc4baSyz147064 		}
5015d62bc4baSyz147064 	} else if (optind != argc) {
50160ba2cbe9Sxc151355 		usage();
5017d62bc4baSyz147064 	}
50180ba2cbe9Sxc151355 
5019d62bc4baSyz147064 	if (linkid == DATALINK_ALL_LINKID) {
50200ba2cbe9Sxc151355 		wlan_count_attr_t wcattr;
50210ba2cbe9Sxc151355 
5022d62bc4baSyz147064 		wcattr.wc_linkid = DATALINK_INVALID_LINKID;
50230ba2cbe9Sxc151355 		wcattr.wc_count = 0;
50244ac67f02SAnurag S. Maskey 		(void) dladm_walk_datalink_id(do_count_wlan, handle, &wcattr,
5025d62bc4baSyz147064 		    DATALINK_CLASS_PHYS, DL_WIFI, DLADM_OPT_ACTIVE);
50260ba2cbe9Sxc151355 		if (wcattr.wc_count == 0) {
502733343a97Smeem 			die("no wifi links are available");
50280ba2cbe9Sxc151355 		} else if (wcattr.wc_count > 1) {
502933343a97Smeem 			die("link name is required when more than one wifi "
503033343a97Smeem 			    "link is available");
50310ba2cbe9Sxc151355 		}
5032d62bc4baSyz147064 		linkid = wcattr.wc_linkid;
50330ba2cbe9Sxc151355 	}
50340ba2cbe9Sxc151355 	attrp = (attr.wa_valid == 0) ? NULL : &attr;
503533343a97Smeem again:
50364ac67f02SAnurag S. Maskey 	if ((status = dladm_wlan_connect(handle, linkid, attrp, timeout, keys,
5037f595a68aSyz147064 	    key_count, flags)) != DLADM_STATUS_OK) {
5038f595a68aSyz147064 		if ((flags & DLADM_WLAN_CONNECT_NOSCAN) != 0) {
50390ba2cbe9Sxc151355 			/*
504033343a97Smeem 			 * Try again with scanning and filtering.
50410ba2cbe9Sxc151355 			 */
5042f595a68aSyz147064 			flags &= ~DLADM_WLAN_CONNECT_NOSCAN;
504333343a97Smeem 			goto again;
50440ba2cbe9Sxc151355 		}
504533343a97Smeem 
5046f595a68aSyz147064 		if (status == DLADM_STATUS_NOTFOUND) {
50470ba2cbe9Sxc151355 			if (attr.wa_valid == 0) {
504833343a97Smeem 				die("no wifi networks are available");
50490ba2cbe9Sxc151355 			} else {
505033343a97Smeem 				die("no wifi networks with the specified "
505133343a97Smeem 				    "criteria are available");
50520ba2cbe9Sxc151355 			}
50530ba2cbe9Sxc151355 		}
5054d62bc4baSyz147064 		die_dlerr(status, "cannot connect");
50550ba2cbe9Sxc151355 	}
50560ba2cbe9Sxc151355 	free(keys);
50570ba2cbe9Sxc151355 }
50580ba2cbe9Sxc151355 
50590ba2cbe9Sxc151355 /* ARGSUSED */
5060d62bc4baSyz147064 static int
50614ac67f02SAnurag S. Maskey do_all_disconnect_wifi(dladm_handle_t dh, datalink_id_t linkid, void *arg)
50620ba2cbe9Sxc151355 {
5063f595a68aSyz147064 	dladm_status_t	status;
50640ba2cbe9Sxc151355 
50654ac67f02SAnurag S. Maskey 	status = dladm_wlan_disconnect(dh, linkid);
5066f595a68aSyz147064 	if (status != DLADM_STATUS_OK)
5067d62bc4baSyz147064 		warn_dlerr(status, "cannot disconnect link");
506833343a97Smeem 
5069d62bc4baSyz147064 	return (DLADM_WALK_CONTINUE);
50700ba2cbe9Sxc151355 }
50710ba2cbe9Sxc151355 
50720ba2cbe9Sxc151355 static void
50738d5c46e6Sam223141 do_disconnect_wifi(int argc, char **argv, const char *use)
50740ba2cbe9Sxc151355 {
50750ba2cbe9Sxc151355 	int			option;
5076d62bc4baSyz147064 	datalink_id_t		linkid = DATALINK_ALL_LINKID;
50770ba2cbe9Sxc151355 	boolean_t		all_links = B_FALSE;
5078f595a68aSyz147064 	dladm_status_t		status;
50790ba2cbe9Sxc151355 	wlan_count_attr_t	wcattr;
50800ba2cbe9Sxc151355 
50810ba2cbe9Sxc151355 	opterr = 0;
50820ba2cbe9Sxc151355 	while ((option = getopt_long(argc, argv, ":a",
50830ba2cbe9Sxc151355 	    wifi_longopts, NULL)) != -1) {
50840ba2cbe9Sxc151355 		switch (option) {
50850ba2cbe9Sxc151355 		case 'a':
50860ba2cbe9Sxc151355 			all_links = B_TRUE;
50870ba2cbe9Sxc151355 			break;
50880ba2cbe9Sxc151355 		default:
50898d5c46e6Sam223141 			die_opterr(optopt, option, use);
50900ba2cbe9Sxc151355 			break;
50910ba2cbe9Sxc151355 		}
50920ba2cbe9Sxc151355 	}
50930ba2cbe9Sxc151355 
5094d62bc4baSyz147064 	if (optind == (argc - 1)) {
50954ac67f02SAnurag S. Maskey 		if ((status = dladm_name2info(handle, argv[optind], &linkid,
50964ac67f02SAnurag S. Maskey 		    NULL, NULL, NULL)) != DLADM_STATUS_OK) {
5097d62bc4baSyz147064 			die_dlerr(status, "link %s is not valid", argv[optind]);
5098d62bc4baSyz147064 		}
5099d62bc4baSyz147064 	} else if (optind != argc) {
51000ba2cbe9Sxc151355 		usage();
5101d62bc4baSyz147064 	}
51020ba2cbe9Sxc151355 
5103d62bc4baSyz147064 	if (linkid == DATALINK_ALL_LINKID) {
51040ba2cbe9Sxc151355 		if (!all_links) {
5105d62bc4baSyz147064 			wcattr.wc_linkid = linkid;
51060ba2cbe9Sxc151355 			wcattr.wc_count = 0;
51074ac67f02SAnurag S. Maskey 			(void) dladm_walk_datalink_id(do_count_wlan, handle,
51084ac67f02SAnurag S. Maskey 			    &wcattr, DATALINK_CLASS_PHYS, DL_WIFI,
51094ac67f02SAnurag S. Maskey 			    DLADM_OPT_ACTIVE);
51100ba2cbe9Sxc151355 			if (wcattr.wc_count == 0) {
511133343a97Smeem 				die("no wifi links are available");
51120ba2cbe9Sxc151355 			} else if (wcattr.wc_count > 1) {
511333343a97Smeem 				die("link name is required when more than "
511433343a97Smeem 				    "one wifi link is available");
51150ba2cbe9Sxc151355 			}
5116d62bc4baSyz147064 			linkid = wcattr.wc_linkid;
51170ba2cbe9Sxc151355 		} else {
5118d62bc4baSyz147064 			(void) dladm_walk_datalink_id(do_all_disconnect_wifi,
51194ac67f02SAnurag S. Maskey 			    handle, NULL, DATALINK_CLASS_PHYS, DL_WIFI,
5120d62bc4baSyz147064 			    DLADM_OPT_ACTIVE);
51210ba2cbe9Sxc151355 			return;
51220ba2cbe9Sxc151355 		}
51230ba2cbe9Sxc151355 	}
51244ac67f02SAnurag S. Maskey 	status = dladm_wlan_disconnect(handle, linkid);
5125f595a68aSyz147064 	if (status != DLADM_STATUS_OK)
5126d62bc4baSyz147064 		die_dlerr(status, "cannot disconnect");
51270ba2cbe9Sxc151355 }
51280ba2cbe9Sxc151355 
51290ba2cbe9Sxc151355 static void
5130d62bc4baSyz147064 print_linkprop(datalink_id_t linkid, show_linkprop_state_t *statep,
51314ac67f02SAnurag S. Maskey     const char *propname, dladm_prop_type_t type, const char *format,
51324ac67f02SAnurag S. Maskey     char **pptr)
51330ba2cbe9Sxc151355 {
51340ba2cbe9Sxc151355 	int		i;
51350ba2cbe9Sxc151355 	char		*ptr, *lim;
51360ba2cbe9Sxc151355 	char		buf[DLADM_STRSIZE];
5137da14cebeSEric Cheng 	char		*unknown = "--", *notsup = "";
51380ba2cbe9Sxc151355 	char		**propvals = statep->ls_propvals;
5139d62bc4baSyz147064 	uint_t		valcnt = DLADM_MAX_PROP_VALCNT;
51400ba2cbe9Sxc151355 	dladm_status_t	status;
51410ba2cbe9Sxc151355 
51424ac67f02SAnurag S. Maskey 	status = dladm_get_linkprop(handle, linkid, type, propname, propvals,
51434ac67f02SAnurag S. Maskey 	    &valcnt);
51440ba2cbe9Sxc151355 	if (status != DLADM_STATUS_OK) {
5145f595a68aSyz147064 		if (status == DLADM_STATUS_TEMPONLY) {
5146d62bc4baSyz147064 			if (type == DLADM_PROP_VAL_MODIFIABLE &&
5147d62bc4baSyz147064 			    statep->ls_persist) {
5148d62bc4baSyz147064 				valcnt = 1;
5149d62bc4baSyz147064 				propvals = &unknown;
5150d62bc4baSyz147064 			} else {
5151f595a68aSyz147064 				statep->ls_status = status;
5152e7801d59Ssowmini 				statep->ls_retstatus = status;
5153f595a68aSyz147064 				return;
5154d62bc4baSyz147064 			}
5155f595a68aSyz147064 		} else if (status == DLADM_STATUS_NOTSUP ||
5156f595a68aSyz147064 		    statep->ls_persist) {
51570ba2cbe9Sxc151355 			valcnt = 1;
5158afdda45fSVasumathi Sundaram - Sun Microsystems 			if (type == DLADM_PROP_VAL_CURRENT ||
5159afdda45fSVasumathi Sundaram - Sun Microsystems 			    type == DLADM_PROP_VAL_PERM)
51600ba2cbe9Sxc151355 				propvals = &unknown;
51610ba2cbe9Sxc151355 			else
51620ba2cbe9Sxc151355 				propvals = &notsup;
5163149b7eb2SSowmini Varadhan 		} else if (status == DLADM_STATUS_NOTDEFINED) {
5164149b7eb2SSowmini Varadhan 			propvals = &notsup; /* STR_UNDEF_VAL */
51650ba2cbe9Sxc151355 		} else {
5166e7801d59Ssowmini 			if (statep->ls_proplist &&
5167e7801d59Ssowmini 			    statep->ls_status == DLADM_STATUS_OK) {
5168f595a68aSyz147064 				warn_dlerr(status,
5169f595a68aSyz147064 				    "cannot get link property '%s' for %s",
5170f595a68aSyz147064 				    propname, statep->ls_link);
5171d62bc4baSyz147064 			}
5172e7801d59Ssowmini 			statep->ls_status = status;
5173e7801d59Ssowmini 			statep->ls_retstatus = status;
5174f595a68aSyz147064 			return;
51750ba2cbe9Sxc151355 		}
51760ba2cbe9Sxc151355 	}
51770ba2cbe9Sxc151355 
5178e7801d59Ssowmini 	statep->ls_status = DLADM_STATUS_OK;
5179e7801d59Ssowmini 
51800ba2cbe9Sxc151355 	ptr = buf;
51810ba2cbe9Sxc151355 	lim = buf + DLADM_STRSIZE;
51820ba2cbe9Sxc151355 	for (i = 0; i < valcnt; i++) {
5183*8002d411SSowmini Varadhan 		if (propvals[i][0] == '\0' && !statep->ls_parsable)
5184*8002d411SSowmini Varadhan 			ptr += snprintf(ptr, lim - ptr, "--,");
51850ba2cbe9Sxc151355 		else
51860ba2cbe9Sxc151355 			ptr += snprintf(ptr, lim - ptr, "%s,", propvals[i]);
51870ba2cbe9Sxc151355 		if (ptr >= lim)
51880ba2cbe9Sxc151355 			break;
51890ba2cbe9Sxc151355 	}
51900ba2cbe9Sxc151355 	if (valcnt > 0)
51910ba2cbe9Sxc151355 		buf[strlen(buf) - 1] = '\0';
51920ba2cbe9Sxc151355 
51930ba2cbe9Sxc151355 	lim = statep->ls_line + MAX_PROP_LINE;
5194*8002d411SSowmini Varadhan 	if (statep->ls_parsable) {
51950ba2cbe9Sxc151355 		*pptr += snprintf(*pptr, lim - *pptr,
5196e7801d59Ssowmini 		    "%s", buf);
51970ba2cbe9Sxc151355 	} else {
51980ba2cbe9Sxc151355 		*pptr += snprintf(*pptr, lim - *pptr, format, buf);
51990ba2cbe9Sxc151355 	}
52000ba2cbe9Sxc151355 }
52010ba2cbe9Sxc151355 
5202*8002d411SSowmini Varadhan static boolean_t
5203*8002d411SSowmini Varadhan print_linkprop_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
5204e7801d59Ssowmini {
5205*8002d411SSowmini Varadhan 	linkprop_args_t		*arg = ofarg->ofmt_cbarg;
5206e7801d59Ssowmini 	char 			*propname = arg->ls_propname;
5207e7801d59Ssowmini 	show_linkprop_state_t	*statep = arg->ls_state;
5208e7801d59Ssowmini 	char			*ptr = statep->ls_line;
5209e7801d59Ssowmini 	char			*lim = ptr + MAX_PROP_LINE;
5210e7801d59Ssowmini 	datalink_id_t		linkid = arg->ls_linkid;
5211e7801d59Ssowmini 
5212*8002d411SSowmini Varadhan 	switch (ofarg->ofmt_id) {
5213e7801d59Ssowmini 	case LINKPROP_LINK:
5214e7801d59Ssowmini 		(void) snprintf(ptr, lim - ptr, "%s", statep->ls_link);
5215e7801d59Ssowmini 		break;
5216e7801d59Ssowmini 	case LINKPROP_PROPERTY:
5217e7801d59Ssowmini 		(void) snprintf(ptr, lim - ptr, "%s", propname);
5218e7801d59Ssowmini 		break;
5219e7801d59Ssowmini 	case LINKPROP_VALUE:
5220e7801d59Ssowmini 		print_linkprop(linkid, statep, propname,
5221e7801d59Ssowmini 		    statep->ls_persist ? DLADM_PROP_VAL_PERSISTENT :
5222e7801d59Ssowmini 		    DLADM_PROP_VAL_CURRENT, "%s", &ptr);
5223e7801d59Ssowmini 		/*
5224e7801d59Ssowmini 		 * If we failed to query the link property, for example, query
5225e7801d59Ssowmini 		 * the persistent value of a non-persistable link property,
5226e7801d59Ssowmini 		 * simply skip the output.
5227e7801d59Ssowmini 		 */
5228e7801d59Ssowmini 		if (statep->ls_status != DLADM_STATUS_OK)
5229e7801d59Ssowmini 			goto skip;
5230e7801d59Ssowmini 		ptr = statep->ls_line;
5231e7801d59Ssowmini 		break;
5232afdda45fSVasumathi Sundaram - Sun Microsystems 	case LINKPROP_PERM:
5233afdda45fSVasumathi Sundaram - Sun Microsystems 		print_linkprop(linkid, statep, propname,
5234afdda45fSVasumathi Sundaram - Sun Microsystems 		    DLADM_PROP_VAL_PERM, "%s", &ptr);
5235afdda45fSVasumathi Sundaram - Sun Microsystems 		if (statep->ls_status != DLADM_STATUS_OK)
5236afdda45fSVasumathi Sundaram - Sun Microsystems 			goto skip;
5237afdda45fSVasumathi Sundaram - Sun Microsystems 		ptr = statep->ls_line;
5238afdda45fSVasumathi Sundaram - Sun Microsystems 		break;
5239e7801d59Ssowmini 	case LINKPROP_DEFAULT:
5240e7801d59Ssowmini 		print_linkprop(linkid, statep, propname,
5241e7801d59Ssowmini 		    DLADM_PROP_VAL_DEFAULT, "%s", &ptr);
5242e7801d59Ssowmini 		if (statep->ls_status != DLADM_STATUS_OK)
5243e7801d59Ssowmini 			goto skip;
5244e7801d59Ssowmini 		ptr = statep->ls_line;
5245e7801d59Ssowmini 		break;
5246e7801d59Ssowmini 	case LINKPROP_POSSIBLE:
5247e7801d59Ssowmini 		print_linkprop(linkid, statep, propname,
5248e7801d59Ssowmini 		    DLADM_PROP_VAL_MODIFIABLE, "%s ", &ptr);
5249e7801d59Ssowmini 		if (statep->ls_status != DLADM_STATUS_OK)
5250e7801d59Ssowmini 			goto skip;
5251e7801d59Ssowmini 		ptr = statep->ls_line;
5252e7801d59Ssowmini 		break;
5253e7801d59Ssowmini 	default:
5254e7801d59Ssowmini 		die("invalid input");
5255e7801d59Ssowmini 		break;
5256e7801d59Ssowmini 	}
5257*8002d411SSowmini Varadhan 	(void) strlcpy(buf, ptr, bufsize);
5258*8002d411SSowmini Varadhan 	return (B_TRUE);
5259e7801d59Ssowmini skip:
5260*8002d411SSowmini Varadhan 	return ((statep->ls_status == DLADM_STATUS_OK) ?
5261*8002d411SSowmini Varadhan 	    B_TRUE : B_FALSE);
5262e7801d59Ssowmini }
5263e7801d59Ssowmini 
5264bcb5c89dSSowmini Varadhan static boolean_t
5265bcb5c89dSSowmini Varadhan linkprop_is_supported(datalink_id_t  linkid, const char *propname,
5266bcb5c89dSSowmini Varadhan     show_linkprop_state_t *statep)
5267bcb5c89dSSowmini Varadhan {
5268bcb5c89dSSowmini Varadhan 	dladm_status_t	status;
5269bcb5c89dSSowmini Varadhan 	uint_t		valcnt = DLADM_MAX_PROP_VALCNT;
5270bcb5c89dSSowmini Varadhan 
52714784fcbdSSowmini Varadhan 	/* if used with -p flag, always print output */
52724784fcbdSSowmini Varadhan 	if (statep->ls_proplist != NULL)
52734784fcbdSSowmini Varadhan 		return (B_TRUE);
52744784fcbdSSowmini Varadhan 
52754ac67f02SAnurag S. Maskey 	status = dladm_get_linkprop(handle, linkid, DLADM_PROP_VAL_DEFAULT,
5276bcb5c89dSSowmini Varadhan 	    propname, statep->ls_propvals, &valcnt);
5277bcb5c89dSSowmini Varadhan 
5278149b7eb2SSowmini Varadhan 	if (status == DLADM_STATUS_OK)
5279149b7eb2SSowmini Varadhan 		return (B_TRUE);
5280149b7eb2SSowmini Varadhan 
5281149b7eb2SSowmini Varadhan 	/*
5282149b7eb2SSowmini Varadhan 	 * A system wide default value is not available for the
5283149b7eb2SSowmini Varadhan 	 * property. Check if current value can be retrieved.
5284149b7eb2SSowmini Varadhan 	 */
52854ac67f02SAnurag S. Maskey 	status = dladm_get_linkprop(handle, linkid, DLADM_PROP_VAL_CURRENT,
5286149b7eb2SSowmini Varadhan 	    propname, statep->ls_propvals, &valcnt);
5287149b7eb2SSowmini Varadhan 
5288149b7eb2SSowmini Varadhan 	return (status == DLADM_STATUS_OK);
5289bcb5c89dSSowmini Varadhan }
5290bcb5c89dSSowmini Varadhan 
52914ac67f02SAnurag S. Maskey /* ARGSUSED */
5292d62bc4baSyz147064 static int
52934ac67f02SAnurag S. Maskey show_linkprop(dladm_handle_t dh, datalink_id_t linkid, const char *propname,
52944ac67f02SAnurag S. Maskey     void *arg)
52950ba2cbe9Sxc151355 {
52960ba2cbe9Sxc151355 	show_linkprop_state_t	*statep = arg;
5297e7801d59Ssowmini 	linkprop_args_t		ls_arg;
52980ba2cbe9Sxc151355 
5299e7801d59Ssowmini 	bzero(&ls_arg, sizeof (ls_arg));
5300e7801d59Ssowmini 	ls_arg.ls_state = statep;
5301e7801d59Ssowmini 	ls_arg.ls_propname = (char *)propname;
5302e7801d59Ssowmini 	ls_arg.ls_linkid = linkid;
53030ba2cbe9Sxc151355 
530462ee1d25SArtem Kachitchkine 	/*
530562ee1d25SArtem Kachitchkine 	 * This will need to be fixed when kernel interfaces are added
530662ee1d25SArtem Kachitchkine 	 * to enable walking of all known private properties. For now,
530762ee1d25SArtem Kachitchkine 	 * we are limited to walking persistent private properties only.
530862ee1d25SArtem Kachitchkine 	 */
530962ee1d25SArtem Kachitchkine 	if ((propname[0] == '_') && !statep->ls_persist &&
531062ee1d25SArtem Kachitchkine 	    (statep->ls_proplist == NULL))
531162ee1d25SArtem Kachitchkine 		return (DLADM_WALK_CONTINUE);
5312*8002d411SSowmini Varadhan 	if (!statep->ls_parsable &&
5313149b7eb2SSowmini Varadhan 	    !linkprop_is_supported(linkid, propname, statep))
5314bcb5c89dSSowmini Varadhan 		return (DLADM_WALK_CONTINUE);
5315bcb5c89dSSowmini Varadhan 
5316*8002d411SSowmini Varadhan 	ofmt_print(statep->ls_ofmt, &ls_arg);
5317e7801d59Ssowmini 
5318d62bc4baSyz147064 	return (DLADM_WALK_CONTINUE);
53190ba2cbe9Sxc151355 }
53200ba2cbe9Sxc151355 
53210ba2cbe9Sxc151355 static void
53228d5c46e6Sam223141 do_show_linkprop(int argc, char **argv, const char *use)
53230ba2cbe9Sxc151355 {
5324f4b3ec61Sdh155122 	int			option;
532563a6526dSMichael Lim 	char			propstr[DLADM_STRSIZE];
5326da14cebeSEric Cheng 	dladm_arg_list_t	*proplist = NULL;
5327d62bc4baSyz147064 	datalink_id_t		linkid = DATALINK_ALL_LINKID;
53280ba2cbe9Sxc151355 	show_linkprop_state_t	state;
5329d62bc4baSyz147064 	uint32_t		flags = DLADM_OPT_ACTIVE;
5330d62bc4baSyz147064 	dladm_status_t		status;
5331e7801d59Ssowmini 	char			*fields_str = NULL;
5332*8002d411SSowmini Varadhan 	ofmt_handle_t		ofmt;
5333*8002d411SSowmini Varadhan 	ofmt_status_t		oferr;
5334*8002d411SSowmini Varadhan 	uint_t			ofmtflags = 0;
53350ba2cbe9Sxc151355 
533663a6526dSMichael Lim 	bzero(propstr, DLADM_STRSIZE);
53370ba2cbe9Sxc151355 	opterr = 0;
53380ba2cbe9Sxc151355 	state.ls_propvals = NULL;
53390ba2cbe9Sxc151355 	state.ls_line = NULL;
5340*8002d411SSowmini Varadhan 	state.ls_parsable = B_FALSE;
53410ba2cbe9Sxc151355 	state.ls_persist = B_FALSE;
53420ba2cbe9Sxc151355 	state.ls_header = B_TRUE;
5343e7801d59Ssowmini 	state.ls_retstatus = DLADM_STATUS_OK;
534463a6526dSMichael Lim 
5345e7801d59Ssowmini 	while ((option = getopt_long(argc, argv, ":p:cPo:",
53460ba2cbe9Sxc151355 	    prop_longopts, NULL)) != -1) {
53470ba2cbe9Sxc151355 		switch (option) {
53480ba2cbe9Sxc151355 		case 'p':
534963a6526dSMichael Lim 			(void) strlcat(propstr, optarg, DLADM_STRSIZE);
535063a6526dSMichael Lim 			if (strlcat(propstr, ",", DLADM_STRSIZE) >=
535163a6526dSMichael Lim 			    DLADM_STRSIZE)
535263a6526dSMichael Lim 				die("property list too long '%s'", propstr);
53530ba2cbe9Sxc151355 			break;
53540ba2cbe9Sxc151355 		case 'c':
5355*8002d411SSowmini Varadhan 			state.ls_parsable = B_TRUE;
53560ba2cbe9Sxc151355 			break;
53570ba2cbe9Sxc151355 		case 'P':
53580ba2cbe9Sxc151355 			state.ls_persist = B_TRUE;
5359d62bc4baSyz147064 			flags = DLADM_OPT_PERSIST;
53600ba2cbe9Sxc151355 			break;
5361e7801d59Ssowmini 		case 'o':
5362e7801d59Ssowmini 			fields_str = optarg;
5363e7801d59Ssowmini 			break;
53640ba2cbe9Sxc151355 		default:
53658d5c46e6Sam223141 			die_opterr(optopt, option, use);
53660ba2cbe9Sxc151355 			break;
53670ba2cbe9Sxc151355 		}
53680ba2cbe9Sxc151355 	}
53690ba2cbe9Sxc151355 
5370d62bc4baSyz147064 	if (optind == (argc - 1)) {
53714ac67f02SAnurag S. Maskey 		if ((status = dladm_name2info(handle, argv[optind], &linkid,
53724ac67f02SAnurag S. Maskey 		    NULL, NULL, NULL)) != DLADM_STATUS_OK) {
5373d62bc4baSyz147064 			die_dlerr(status, "link %s is not valid", argv[optind]);
5374d62bc4baSyz147064 		}
5375d62bc4baSyz147064 	} else if (optind != argc) {
53760ba2cbe9Sxc151355 		usage();
5377d62bc4baSyz147064 	}
53780ba2cbe9Sxc151355 
537963a6526dSMichael Lim 	if (dladm_parse_link_props(propstr, &proplist, B_TRUE)
538063a6526dSMichael Lim 	    != DLADM_STATUS_OK)
538163a6526dSMichael Lim 		die("invalid link properties specified");
5382f4b3ec61Sdh155122 	state.ls_proplist = proplist;
5383f595a68aSyz147064 	state.ls_status = DLADM_STATUS_OK;
5384f4b3ec61Sdh155122 
5385*8002d411SSowmini Varadhan 	if (state.ls_parsable)
5386*8002d411SSowmini Varadhan 		ofmtflags |= OFMT_PARSABLE;
5387*8002d411SSowmini Varadhan 	oferr = ofmt_open(fields_str, linkprop_fields, ofmtflags, 0, &ofmt);
5388*8002d411SSowmini Varadhan 	dladm_ofmt_check(oferr, state.ls_parsable, ofmt);
5389*8002d411SSowmini Varadhan 	state.ls_ofmt = ofmt;
5390e7801d59Ssowmini 
5391d62bc4baSyz147064 	if (linkid == DATALINK_ALL_LINKID) {
53924ac67f02SAnurag S. Maskey 		(void) dladm_walk_datalink_id(show_linkprop_onelink, handle,
53934ac67f02SAnurag S. Maskey 		    &state, DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE, flags);
5394f4b3ec61Sdh155122 	} else {
53954ac67f02SAnurag S. Maskey 		(void) show_linkprop_onelink(handle, linkid, &state);
5396f4b3ec61Sdh155122 	}
5397*8002d411SSowmini Varadhan 	ofmt_close(ofmt);
5398da14cebeSEric Cheng 	dladm_free_props(proplist);
5399f595a68aSyz147064 
54004ac67f02SAnurag S. Maskey 	if (state.ls_retstatus != DLADM_STATUS_OK) {
54014ac67f02SAnurag S. Maskey 		dladm_close(handle);
5402f595a68aSyz147064 		exit(EXIT_FAILURE);
5403f4b3ec61Sdh155122 	}
54044ac67f02SAnurag S. Maskey }
5405f4b3ec61Sdh155122 
5406d62bc4baSyz147064 static int
54074ac67f02SAnurag S. Maskey show_linkprop_onelink(dladm_handle_t hdl, datalink_id_t linkid, void *arg)
5408f4b3ec61Sdh155122 {
5409948f2876Sss150715 	int			i;
5410f4b3ec61Sdh155122 	char			*buf;
5411d62bc4baSyz147064 	uint32_t		flags;
5412da14cebeSEric Cheng 	dladm_arg_list_t	*proplist = NULL;
5413d62bc4baSyz147064 	show_linkprop_state_t	*statep = arg;
5414d62bc4baSyz147064 	dlpi_handle_t		dh = NULL;
5415f4b3ec61Sdh155122 
5416d62bc4baSyz147064 	statep->ls_status = DLADM_STATUS_OK;
5417d62bc4baSyz147064 
54184ac67f02SAnurag S. Maskey 	if (dladm_datalink_id2info(hdl, linkid, &flags, NULL, NULL,
54194ac67f02SAnurag S. Maskey 	    statep->ls_link, MAXLINKNAMELEN) != DLADM_STATUS_OK) {
5420d62bc4baSyz147064 		statep->ls_status = DLADM_STATUS_NOTFOUND;
5421d62bc4baSyz147064 		return (DLADM_WALK_CONTINUE);
5422d62bc4baSyz147064 	}
5423d62bc4baSyz147064 
5424d62bc4baSyz147064 	if ((statep->ls_persist && !(flags & DLADM_OPT_PERSIST)) ||
5425d62bc4baSyz147064 	    (!statep->ls_persist && !(flags & DLADM_OPT_ACTIVE))) {
5426d62bc4baSyz147064 		statep->ls_status = DLADM_STATUS_BADARG;
5427d62bc4baSyz147064 		return (DLADM_WALK_CONTINUE);
5428d62bc4baSyz147064 	}
5429d62bc4baSyz147064 
5430f4b3ec61Sdh155122 	proplist = statep->ls_proplist;
54310ba2cbe9Sxc151355 
54320ba2cbe9Sxc151355 	/*
54330ba2cbe9Sxc151355 	 * When some WiFi links are opened for the first time, their hardware
54340ba2cbe9Sxc151355 	 * automatically scans for APs and does other slow operations.	Thus,
54350ba2cbe9Sxc151355 	 * if there are no open links, the retrieval of link properties
54360ba2cbe9Sxc151355 	 * (below) will proceed slowly unless we hold the link open.
5437d62bc4baSyz147064 	 *
5438d62bc4baSyz147064 	 * Note that failure of dlpi_open() does not necessarily mean invalid
5439d62bc4baSyz147064 	 * link properties, because dlpi_open() may fail because of incorrect
5440d62bc4baSyz147064 	 * autopush configuration. Therefore, we ingore the return value of
5441d62bc4baSyz147064 	 * dlpi_open().
54420ba2cbe9Sxc151355 	 */
5443d62bc4baSyz147064 	if (!statep->ls_persist)
5444d62bc4baSyz147064 		(void) dlpi_open(statep->ls_link, &dh, 0);
54450ba2cbe9Sxc151355 
5446d62bc4baSyz147064 	buf = malloc((sizeof (char *) + DLADM_PROP_VAL_MAX) *
5447d62bc4baSyz147064 	    DLADM_MAX_PROP_VALCNT + MAX_PROP_LINE);
544833343a97Smeem 	if (buf == NULL)
544933343a97Smeem 		die("insufficient memory");
545033343a97Smeem 
5451f4b3ec61Sdh155122 	statep->ls_propvals = (char **)(void *)buf;
5452d62bc4baSyz147064 	for (i = 0; i < DLADM_MAX_PROP_VALCNT; i++) {
5453d62bc4baSyz147064 		statep->ls_propvals[i] = buf +
5454d62bc4baSyz147064 		    sizeof (char *) * DLADM_MAX_PROP_VALCNT +
54550ba2cbe9Sxc151355 		    i * DLADM_PROP_VAL_MAX;
54560ba2cbe9Sxc151355 	}
5457f4b3ec61Sdh155122 	statep->ls_line = buf +
5458d62bc4baSyz147064 	    (sizeof (char *) + DLADM_PROP_VAL_MAX) * DLADM_MAX_PROP_VALCNT;
54590ba2cbe9Sxc151355 
54600ba2cbe9Sxc151355 	if (proplist != NULL) {
5461da14cebeSEric Cheng 		for (i = 0; i < proplist->al_count; i++) {
54624ac67f02SAnurag S. Maskey 			(void) show_linkprop(hdl, linkid,
5463da14cebeSEric Cheng 			    proplist->al_info[i].ai_name, statep);
54640ba2cbe9Sxc151355 		}
5465d62bc4baSyz147064 	} else {
54664ac67f02SAnurag S. Maskey 		(void) dladm_walk_linkprop(hdl, linkid, statep,
54674ac67f02SAnurag S. Maskey 		    show_linkprop);
5468d62bc4baSyz147064 	}
5469d62bc4baSyz147064 	if (dh != NULL)
5470948f2876Sss150715 		dlpi_close(dh);
54710ba2cbe9Sxc151355 	free(buf);
5472d62bc4baSyz147064 	return (DLADM_WALK_CONTINUE);
54730ba2cbe9Sxc151355 }
54740ba2cbe9Sxc151355 
54750ba2cbe9Sxc151355 static dladm_status_t
5476d62bc4baSyz147064 set_linkprop_persist(datalink_id_t linkid, const char *prop_name,
5477d62bc4baSyz147064     char **prop_val, uint_t val_cnt, boolean_t reset)
54780ba2cbe9Sxc151355 {
54790ba2cbe9Sxc151355 	dladm_status_t	status;
54800ba2cbe9Sxc151355 
54814ac67f02SAnurag S. Maskey 	status = dladm_set_linkprop(handle, linkid, prop_name, prop_val,
54824ac67f02SAnurag S. Maskey 	    val_cnt, DLADM_OPT_PERSIST);
54830ba2cbe9Sxc151355 
54840ba2cbe9Sxc151355 	if (status != DLADM_STATUS_OK) {
5485da14cebeSEric Cheng 		warn_dlerr(status, "cannot persistently %s link property '%s'",
5486da14cebeSEric Cheng 		    reset ? "reset" : "set", prop_name);
54870ba2cbe9Sxc151355 	}
54880ba2cbe9Sxc151355 	return (status);
54890ba2cbe9Sxc151355 }
54900ba2cbe9Sxc151355 
5491da14cebeSEric Cheng static int
54924ac67f02SAnurag S. Maskey reset_one_linkprop(dladm_handle_t dh, datalink_id_t linkid,
54934ac67f02SAnurag S. Maskey     const char *propname, void *arg)
5494da14cebeSEric Cheng {
5495da14cebeSEric Cheng 	set_linkprop_state_t	*statep = arg;
5496da14cebeSEric Cheng 	dladm_status_t		status;
5497da14cebeSEric Cheng 
54984ac67f02SAnurag S. Maskey 	status = dladm_set_linkprop(dh, linkid, propname, NULL, 0,
5499da14cebeSEric Cheng 	    DLADM_OPT_ACTIVE);
5500da14cebeSEric Cheng 	if (status != DLADM_STATUS_OK) {
5501da14cebeSEric Cheng 		warn_dlerr(status, "cannot reset link property '%s' on '%s'",
5502da14cebeSEric Cheng 		    propname, statep->ls_name);
5503da14cebeSEric Cheng 	}
5504da14cebeSEric Cheng 	if (!statep->ls_temp) {
5505da14cebeSEric Cheng 		dladm_status_t	s;
5506da14cebeSEric Cheng 
5507da14cebeSEric Cheng 		s = set_linkprop_persist(linkid, propname, NULL, 0,
5508da14cebeSEric Cheng 		    statep->ls_reset);
5509da14cebeSEric Cheng 		if (s != DLADM_STATUS_OK)
5510da14cebeSEric Cheng 			status = s;
5511da14cebeSEric Cheng 	}
5512da14cebeSEric Cheng 	if (status != DLADM_STATUS_OK)
5513da14cebeSEric Cheng 		statep->ls_status = status;
5514da14cebeSEric Cheng 
5515da14cebeSEric Cheng 	return (DLADM_WALK_CONTINUE);
5516da14cebeSEric Cheng }
5517da14cebeSEric Cheng 
55180ba2cbe9Sxc151355 static void
55198d5c46e6Sam223141 set_linkprop(int argc, char **argv, boolean_t reset, const char *use)
55200ba2cbe9Sxc151355 {
55210ba2cbe9Sxc151355 	int			i, option;
55220ba2cbe9Sxc151355 	char			errmsg[DLADM_STRSIZE];
5523d62bc4baSyz147064 	char			*altroot = NULL;
5524d62bc4baSyz147064 	datalink_id_t		linkid;
55250ba2cbe9Sxc151355 	boolean_t		temp = B_FALSE;
55260ba2cbe9Sxc151355 	dladm_status_t		status = DLADM_STATUS_OK;
552763a6526dSMichael Lim 	char			propstr[DLADM_STRSIZE];
5528da14cebeSEric Cheng 	dladm_arg_list_t	*proplist = NULL;
55290ba2cbe9Sxc151355 
55300ba2cbe9Sxc151355 	opterr = 0;
553163a6526dSMichael Lim 	bzero(propstr, DLADM_STRSIZE);
553263a6526dSMichael Lim 
55330ba2cbe9Sxc151355 	while ((option = getopt_long(argc, argv, ":p:R:t",
55340ba2cbe9Sxc151355 	    prop_longopts, NULL)) != -1) {
55350ba2cbe9Sxc151355 		switch (option) {
55360ba2cbe9Sxc151355 		case 'p':
553763a6526dSMichael Lim 			(void) strlcat(propstr, optarg, DLADM_STRSIZE);
553863a6526dSMichael Lim 			if (strlcat(propstr, ",", DLADM_STRSIZE) >=
553963a6526dSMichael Lim 			    DLADM_STRSIZE)
554063a6526dSMichael Lim 				die("property list too long '%s'", propstr);
55410ba2cbe9Sxc151355 			break;
55420ba2cbe9Sxc151355 		case 't':
55430ba2cbe9Sxc151355 			temp = B_TRUE;
55440ba2cbe9Sxc151355 			break;
55450ba2cbe9Sxc151355 		case 'R':
5546d62bc4baSyz147064 			altroot = optarg;
55470ba2cbe9Sxc151355 			break;
55480ba2cbe9Sxc151355 		default:
55498d5c46e6Sam223141 			die_opterr(optopt, option, use);
55508d5c46e6Sam223141 
55510ba2cbe9Sxc151355 		}
55520ba2cbe9Sxc151355 	}
55530ba2cbe9Sxc151355 
5554d62bc4baSyz147064 	/* get link name (required last argument) */
5555d62bc4baSyz147064 	if (optind != (argc - 1))
55560ba2cbe9Sxc151355 		usage();
55570ba2cbe9Sxc151355 
555863a6526dSMichael Lim 	if (dladm_parse_link_props(propstr, &proplist, reset) !=
555963a6526dSMichael Lim 	    DLADM_STATUS_OK)
556063a6526dSMichael Lim 		die("invalid link properties specified");
556163a6526dSMichael Lim 
5562d62bc4baSyz147064 	if (proplist == NULL && !reset)
556333343a97Smeem 		die("link property must be specified");
556433343a97Smeem 
5565d62bc4baSyz147064 	if (altroot != NULL) {
5566da14cebeSEric Cheng 		dladm_free_props(proplist);
5567d62bc4baSyz147064 		altroot_cmd(altroot, argc, argv);
5568d62bc4baSyz147064 	}
5569d62bc4baSyz147064 
55704ac67f02SAnurag S. Maskey 	status = dladm_name2info(handle, argv[optind], &linkid, NULL, NULL,
55714ac67f02SAnurag S. Maskey 	    NULL);
5572d62bc4baSyz147064 	if (status != DLADM_STATUS_OK)
5573d62bc4baSyz147064 		die_dlerr(status, "link %s is not valid", argv[optind]);
5574d62bc4baSyz147064 
5575d62bc4baSyz147064 	if (proplist == NULL) {
5576da14cebeSEric Cheng 		set_linkprop_state_t	state;
557713994ee8Sxz162242 
5578da14cebeSEric Cheng 		state.ls_name = argv[optind];
5579da14cebeSEric Cheng 		state.ls_reset = reset;
5580da14cebeSEric Cheng 		state.ls_temp = temp;
5581da14cebeSEric Cheng 		state.ls_status = DLADM_STATUS_OK;
5582da14cebeSEric Cheng 
55834ac67f02SAnurag S. Maskey 		(void) dladm_walk_linkprop(handle, linkid, &state,
55844ac67f02SAnurag S. Maskey 		    reset_one_linkprop);
5585da14cebeSEric Cheng 
5586da14cebeSEric Cheng 		status = state.ls_status;
55870ba2cbe9Sxc151355 		goto done;
55880ba2cbe9Sxc151355 	}
55890ba2cbe9Sxc151355 
5590da14cebeSEric Cheng 	for (i = 0; i < proplist->al_count; i++) {
5591da14cebeSEric Cheng 		dladm_arg_info_t	*aip = &proplist->al_info[i];
55920ba2cbe9Sxc151355 		char		**val;
55930ba2cbe9Sxc151355 		uint_t		count;
55940ba2cbe9Sxc151355 		dladm_status_t	s;
55950ba2cbe9Sxc151355 
55960ba2cbe9Sxc151355 		if (reset) {
55970ba2cbe9Sxc151355 			val = NULL;
55980ba2cbe9Sxc151355 			count = 0;
55990ba2cbe9Sxc151355 		} else {
5600da14cebeSEric Cheng 			val = aip->ai_val;
5601da14cebeSEric Cheng 			count = aip->ai_count;
56020ba2cbe9Sxc151355 			if (count == 0) {
560333343a97Smeem 				warn("no value specified for '%s'",
5604da14cebeSEric Cheng 				    aip->ai_name);
56050ba2cbe9Sxc151355 				status = DLADM_STATUS_BADARG;
56060ba2cbe9Sxc151355 				continue;
56070ba2cbe9Sxc151355 			}
56080ba2cbe9Sxc151355 		}
56094ac67f02SAnurag S. Maskey 		s = dladm_set_linkprop(handle, linkid, aip->ai_name, val, count,
5610d62bc4baSyz147064 		    DLADM_OPT_ACTIVE);
56110ba2cbe9Sxc151355 		if (s == DLADM_STATUS_OK) {
56120ba2cbe9Sxc151355 			if (!temp) {
5613d62bc4baSyz147064 				s = set_linkprop_persist(linkid,
5614da14cebeSEric Cheng 				    aip->ai_name, val, count, reset);
56150ba2cbe9Sxc151355 				if (s != DLADM_STATUS_OK)
56160ba2cbe9Sxc151355 					status = s;
56170ba2cbe9Sxc151355 			}
56180ba2cbe9Sxc151355 			continue;
56190ba2cbe9Sxc151355 		}
56200ba2cbe9Sxc151355 		status = s;
56210ba2cbe9Sxc151355 		switch (s) {
56220ba2cbe9Sxc151355 		case DLADM_STATUS_NOTFOUND:
5623da14cebeSEric Cheng 			warn("invalid link property '%s'", aip->ai_name);
56240ba2cbe9Sxc151355 			break;
56250ba2cbe9Sxc151355 		case DLADM_STATUS_BADVAL: {
56260ba2cbe9Sxc151355 			int		j;
56270ba2cbe9Sxc151355 			char		*ptr, *lim;
56280ba2cbe9Sxc151355 			char		**propvals = NULL;
5629d62bc4baSyz147064 			uint_t		valcnt = DLADM_MAX_PROP_VALCNT;
56300ba2cbe9Sxc151355 
56310ba2cbe9Sxc151355 			ptr = malloc((sizeof (char *) +
5632d62bc4baSyz147064 			    DLADM_PROP_VAL_MAX) * DLADM_MAX_PROP_VALCNT +
56330ba2cbe9Sxc151355 			    MAX_PROP_LINE);
56340ba2cbe9Sxc151355 
56350ba2cbe9Sxc151355 			propvals = (char **)(void *)ptr;
563633343a97Smeem 			if (propvals == NULL)
563733343a97Smeem 				die("insufficient memory");
563833343a97Smeem 
5639d62bc4baSyz147064 			for (j = 0; j < DLADM_MAX_PROP_VALCNT; j++) {
56400ba2cbe9Sxc151355 				propvals[j] = ptr + sizeof (char *) *
5641d62bc4baSyz147064 				    DLADM_MAX_PROP_VALCNT +
56420ba2cbe9Sxc151355 				    j * DLADM_PROP_VAL_MAX;
56430ba2cbe9Sxc151355 			}
56444ac67f02SAnurag S. Maskey 			s = dladm_get_linkprop(handle, linkid,
5645da14cebeSEric Cheng 			    DLADM_PROP_VAL_MODIFIABLE, aip->ai_name, propvals,
5646d62bc4baSyz147064 			    &valcnt);
5647d62bc4baSyz147064 
5648d62bc4baSyz147064 			if (s != DLADM_STATUS_OK) {
5649d62bc4baSyz147064 				warn_dlerr(status, "cannot set link property "
5650da14cebeSEric Cheng 				    "'%s' on '%s'", aip->ai_name, argv[optind]);
5651d62bc4baSyz147064 				free(propvals);
5652d62bc4baSyz147064 				break;
5653d62bc4baSyz147064 			}
56540ba2cbe9Sxc151355 
56550ba2cbe9Sxc151355 			ptr = errmsg;
56560ba2cbe9Sxc151355 			lim = ptr + DLADM_STRSIZE;
56570ba2cbe9Sxc151355 			*ptr = '\0';
5658d62bc4baSyz147064 			for (j = 0; j < valcnt; j++) {
56590ba2cbe9Sxc151355 				ptr += snprintf(ptr, lim - ptr, "%s,",
56600ba2cbe9Sxc151355 				    propvals[j]);
56610ba2cbe9Sxc151355 				if (ptr >= lim)
56620ba2cbe9Sxc151355 					break;
56630ba2cbe9Sxc151355 			}
5664f4b3ec61Sdh155122 			if (ptr > errmsg) {
56650ba2cbe9Sxc151355 				*(ptr - 1) = '\0';
566633343a97Smeem 				warn("link property '%s' must be one of: %s",
5667da14cebeSEric Cheng 				    aip->ai_name, errmsg);
5668f4b3ec61Sdh155122 			} else
5669f4b3ec61Sdh155122 				warn("invalid link property '%s'", *val);
56700ba2cbe9Sxc151355 			free(propvals);
56710ba2cbe9Sxc151355 			break;
56720ba2cbe9Sxc151355 		}
56730ba2cbe9Sxc151355 		default:
56740ba2cbe9Sxc151355 			if (reset) {
567533343a97Smeem 				warn_dlerr(status, "cannot reset link property "
5676da14cebeSEric Cheng 				    "'%s' on '%s'", aip->ai_name, argv[optind]);
56770ba2cbe9Sxc151355 			} else {
567833343a97Smeem 				warn_dlerr(status, "cannot set link property "
5679da14cebeSEric Cheng 				    "'%s' on '%s'", aip->ai_name, argv[optind]);
56800ba2cbe9Sxc151355 			}
56810ba2cbe9Sxc151355 			break;
56820ba2cbe9Sxc151355 		}
56830ba2cbe9Sxc151355 	}
56840ba2cbe9Sxc151355 done:
5685da14cebeSEric Cheng 	dladm_free_props(proplist);
56864ac67f02SAnurag S. Maskey 	if (status != DLADM_STATUS_OK) {
56874ac67f02SAnurag S. Maskey 		dladm_close(handle);
56880ba2cbe9Sxc151355 		exit(1);
56890ba2cbe9Sxc151355 	}
56904ac67f02SAnurag S. Maskey }
56910ba2cbe9Sxc151355 
56920ba2cbe9Sxc151355 static void
56938d5c46e6Sam223141 do_set_linkprop(int argc, char **argv, const char *use)
56940ba2cbe9Sxc151355 {
56958d5c46e6Sam223141 	set_linkprop(argc, argv, B_FALSE, use);
56960ba2cbe9Sxc151355 }
56970ba2cbe9Sxc151355 
56980ba2cbe9Sxc151355 static void
56998d5c46e6Sam223141 do_reset_linkprop(int argc, char **argv, const char *use)
57000ba2cbe9Sxc151355 {
57018d5c46e6Sam223141 	set_linkprop(argc, argv, B_TRUE, use);
57020ba2cbe9Sxc151355 }
57030ba2cbe9Sxc151355 
57040ba2cbe9Sxc151355 static int
57050ba2cbe9Sxc151355 convert_secobj(char *buf, uint_t len, uint8_t *obj_val, uint_t *obj_lenp,
57060ba2cbe9Sxc151355     dladm_secobj_class_t class)
57070ba2cbe9Sxc151355 {
57080ba2cbe9Sxc151355 	int error = 0;
57090ba2cbe9Sxc151355 
5710a399b765Szf162725 	if (class == DLADM_SECOBJ_CLASS_WPA) {
5711a399b765Szf162725 		if (len < 8 || len > 63)
5712a399b765Szf162725 			return (EINVAL);
5713a399b765Szf162725 		(void) memcpy(obj_val, buf, len);
5714a399b765Szf162725 		*obj_lenp = len;
5715a399b765Szf162725 		return (error);
5716a399b765Szf162725 	}
57170ba2cbe9Sxc151355 
5718a399b765Szf162725 	if (class == DLADM_SECOBJ_CLASS_WEP) {
57190ba2cbe9Sxc151355 		switch (len) {
57200ba2cbe9Sxc151355 		case 5:			/* ASCII key sizes */
57210ba2cbe9Sxc151355 		case 13:
57220ba2cbe9Sxc151355 			(void) memcpy(obj_val, buf, len);
57230ba2cbe9Sxc151355 			*obj_lenp = len;
57240ba2cbe9Sxc151355 			break;
57250ba2cbe9Sxc151355 		case 10:		/* Hex key sizes, not preceded by 0x */
57260ba2cbe9Sxc151355 		case 26:
57270ba2cbe9Sxc151355 			error = hexascii_to_octet(buf, len, obj_val, obj_lenp);
57280ba2cbe9Sxc151355 			break;
57290ba2cbe9Sxc151355 		case 12:		/* Hex key sizes, preceded by 0x */
57300ba2cbe9Sxc151355 		case 28:
57310ba2cbe9Sxc151355 			if (strncmp(buf, "0x", 2) != 0)
57320ba2cbe9Sxc151355 				return (EINVAL);
5733a399b765Szf162725 			error = hexascii_to_octet(buf + 2, len - 2,
5734a399b765Szf162725 			    obj_val, obj_lenp);
57350ba2cbe9Sxc151355 			break;
57360ba2cbe9Sxc151355 		default:
57370ba2cbe9Sxc151355 			return (EINVAL);
57380ba2cbe9Sxc151355 		}
57390ba2cbe9Sxc151355 		return (error);
57400ba2cbe9Sxc151355 	}
57410ba2cbe9Sxc151355 
5742a399b765Szf162725 	return (ENOENT);
5743a399b765Szf162725 }
5744a399b765Szf162725 
57450ba2cbe9Sxc151355 static void
57460ba2cbe9Sxc151355 defersig(int sig)
57470ba2cbe9Sxc151355 {
57480ba2cbe9Sxc151355 	signalled = sig;
57490ba2cbe9Sxc151355 }
57500ba2cbe9Sxc151355 
57510ba2cbe9Sxc151355 static int
57520ba2cbe9Sxc151355 get_secobj_from_tty(uint_t try, const char *objname, char *buf)
57530ba2cbe9Sxc151355 {
57540ba2cbe9Sxc151355 	uint_t		len = 0;
57550ba2cbe9Sxc151355 	int		c;
57560ba2cbe9Sxc151355 	struct termios	stored, current;
57570ba2cbe9Sxc151355 	void		(*sigfunc)(int);
57580ba2cbe9Sxc151355 
57590ba2cbe9Sxc151355 	/*
57600ba2cbe9Sxc151355 	 * Turn off echo -- but before we do so, defer SIGINT handling
57610ba2cbe9Sxc151355 	 * so that a ^C doesn't leave the terminal corrupted.
57620ba2cbe9Sxc151355 	 */
57630ba2cbe9Sxc151355 	sigfunc = signal(SIGINT, defersig);
57640ba2cbe9Sxc151355 	(void) fflush(stdin);
57650ba2cbe9Sxc151355 	(void) tcgetattr(0, &stored);
57660ba2cbe9Sxc151355 	current = stored;
57670ba2cbe9Sxc151355 	current.c_lflag &= ~(ICANON|ECHO);
57680ba2cbe9Sxc151355 	current.c_cc[VTIME] = 0;
57690ba2cbe9Sxc151355 	current.c_cc[VMIN] = 1;
57700ba2cbe9Sxc151355 	(void) tcsetattr(0, TCSANOW, &current);
57710ba2cbe9Sxc151355 again:
57720ba2cbe9Sxc151355 	if (try == 1)
57730ba2cbe9Sxc151355 		(void) printf(gettext("provide value for '%s': "), objname);
57740ba2cbe9Sxc151355 	else
57750ba2cbe9Sxc151355 		(void) printf(gettext("confirm value for '%s': "), objname);
57760ba2cbe9Sxc151355 
57770ba2cbe9Sxc151355 	(void) fflush(stdout);
57780ba2cbe9Sxc151355 	while (signalled == 0) {
57790ba2cbe9Sxc151355 		c = getchar();
57800ba2cbe9Sxc151355 		if (c == '\n' || c == '\r') {
57810ba2cbe9Sxc151355 			if (len != 0)
57820ba2cbe9Sxc151355 				break;
57830ba2cbe9Sxc151355 			(void) putchar('\n');
57840ba2cbe9Sxc151355 			goto again;
57850ba2cbe9Sxc151355 		}
57860ba2cbe9Sxc151355 
57870ba2cbe9Sxc151355 		buf[len++] = c;
57880ba2cbe9Sxc151355 		if (len >= DLADM_SECOBJ_VAL_MAX - 1)
57890ba2cbe9Sxc151355 			break;
57900ba2cbe9Sxc151355 		(void) putchar('*');
57910ba2cbe9Sxc151355 	}
57920ba2cbe9Sxc151355 
57930ba2cbe9Sxc151355 	(void) putchar('\n');
57940ba2cbe9Sxc151355 	(void) fflush(stdin);
57950ba2cbe9Sxc151355 
57960ba2cbe9Sxc151355 	/*
57970ba2cbe9Sxc151355 	 * Restore terminal setting and handle deferred signals.
57980ba2cbe9Sxc151355 	 */
57990ba2cbe9Sxc151355 	(void) tcsetattr(0, TCSANOW, &stored);
58000ba2cbe9Sxc151355 
58010ba2cbe9Sxc151355 	(void) signal(SIGINT, sigfunc);
58020ba2cbe9Sxc151355 	if (signalled != 0)
58030ba2cbe9Sxc151355 		(void) kill(getpid(), signalled);
58040ba2cbe9Sxc151355 
58050ba2cbe9Sxc151355 	return (len);
58060ba2cbe9Sxc151355 }
58070ba2cbe9Sxc151355 
58080ba2cbe9Sxc151355 static int
58090ba2cbe9Sxc151355 get_secobj_val(char *obj_name, uint8_t *obj_val, uint_t *obj_lenp,
58100ba2cbe9Sxc151355     dladm_secobj_class_t class, FILE *filep)
58110ba2cbe9Sxc151355 {
58120ba2cbe9Sxc151355 	int		rval;
58130ba2cbe9Sxc151355 	uint_t		len, len2;
58140ba2cbe9Sxc151355 	char		buf[DLADM_SECOBJ_VAL_MAX], buf2[DLADM_SECOBJ_VAL_MAX];
58150ba2cbe9Sxc151355 
58160ba2cbe9Sxc151355 	if (filep == NULL) {
58170ba2cbe9Sxc151355 		len = get_secobj_from_tty(1, obj_name, buf);
58180ba2cbe9Sxc151355 		rval = convert_secobj(buf, len, obj_val, obj_lenp, class);
58190ba2cbe9Sxc151355 		if (rval == 0) {
58200ba2cbe9Sxc151355 			len2 = get_secobj_from_tty(2, obj_name, buf2);
58210ba2cbe9Sxc151355 			if (len != len2 || memcmp(buf, buf2, len) != 0)
58220ba2cbe9Sxc151355 				rval = ENOTSUP;
58230ba2cbe9Sxc151355 		}
58240ba2cbe9Sxc151355 		return (rval);
58250ba2cbe9Sxc151355 	} else {
58260ba2cbe9Sxc151355 		for (;;) {
58270ba2cbe9Sxc151355 			if (fgets(buf, sizeof (buf), filep) == NULL)
58280ba2cbe9Sxc151355 				break;
58290ba2cbe9Sxc151355 			if (isspace(buf[0]))
58300ba2cbe9Sxc151355 				continue;
58310ba2cbe9Sxc151355 
58320ba2cbe9Sxc151355 			len = strlen(buf);
58330ba2cbe9Sxc151355 			if (buf[len - 1] == '\n') {
58340ba2cbe9Sxc151355 				buf[len - 1] = '\0';
58350ba2cbe9Sxc151355 				len--;
58360ba2cbe9Sxc151355 			}
58370ba2cbe9Sxc151355 			break;
58380ba2cbe9Sxc151355 		}
58390ba2cbe9Sxc151355 		(void) fclose(filep);
58400ba2cbe9Sxc151355 	}
58410ba2cbe9Sxc151355 	return (convert_secobj(buf, len, obj_val, obj_lenp, class));
58420ba2cbe9Sxc151355 }
58430ba2cbe9Sxc151355 
58440ba2cbe9Sxc151355 static boolean_t
58450ba2cbe9Sxc151355 check_auth(const char *auth)
58460ba2cbe9Sxc151355 {
58470ba2cbe9Sxc151355 	struct passwd	*pw;
58480ba2cbe9Sxc151355 
58490ba2cbe9Sxc151355 	if ((pw = getpwuid(getuid())) == NULL)
58500ba2cbe9Sxc151355 		return (B_FALSE);
58510ba2cbe9Sxc151355 
58520ba2cbe9Sxc151355 	return (chkauthattr(auth, pw->pw_name) != 0);
58530ba2cbe9Sxc151355 }
58540ba2cbe9Sxc151355 
58550ba2cbe9Sxc151355 static void
58560ba2cbe9Sxc151355 audit_secobj(char *auth, char *class, char *obj,
58570ba2cbe9Sxc151355     boolean_t success, boolean_t create)
58580ba2cbe9Sxc151355 {
58590ba2cbe9Sxc151355 	adt_session_data_t	*ah;
58600ba2cbe9Sxc151355 	adt_event_data_t	*event;
58610ba2cbe9Sxc151355 	au_event_t		flag;
58620ba2cbe9Sxc151355 	char			*errstr;
58630ba2cbe9Sxc151355 
58640ba2cbe9Sxc151355 	if (create) {
58650ba2cbe9Sxc151355 		flag = ADT_dladm_create_secobj;
58660ba2cbe9Sxc151355 		errstr = "ADT_dladm_create_secobj";
58670ba2cbe9Sxc151355 	} else {
58680ba2cbe9Sxc151355 		flag = ADT_dladm_delete_secobj;
58690ba2cbe9Sxc151355 		errstr = "ADT_dladm_delete_secobj";
58700ba2cbe9Sxc151355 	}
58710ba2cbe9Sxc151355 
587233343a97Smeem 	if (adt_start_session(&ah, NULL, ADT_USE_PROC_DATA) != 0)
587333343a97Smeem 		die("adt_start_session: %s", strerror(errno));
58740ba2cbe9Sxc151355 
587533343a97Smeem 	if ((event = adt_alloc_event(ah, flag)) == NULL)
587633343a97Smeem 		die("adt_alloc_event (%s): %s", errstr, strerror(errno));
58770ba2cbe9Sxc151355 
58780ba2cbe9Sxc151355 	/* fill in audit info */
58790ba2cbe9Sxc151355 	if (create) {
58800ba2cbe9Sxc151355 		event->adt_dladm_create_secobj.auth_used = auth;
58810ba2cbe9Sxc151355 		event->adt_dladm_create_secobj.obj_class = class;
58820ba2cbe9Sxc151355 		event->adt_dladm_create_secobj.obj_name = obj;
58830ba2cbe9Sxc151355 	} else {
58840ba2cbe9Sxc151355 		event->adt_dladm_delete_secobj.auth_used = auth;
58850ba2cbe9Sxc151355 		event->adt_dladm_delete_secobj.obj_class = class;
58860ba2cbe9Sxc151355 		event->adt_dladm_delete_secobj.obj_name = obj;
58870ba2cbe9Sxc151355 	}
58880ba2cbe9Sxc151355 
58890ba2cbe9Sxc151355 	if (success) {
58900ba2cbe9Sxc151355 		if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS) != 0) {
589133343a97Smeem 			die("adt_put_event (%s, success): %s", errstr,
589233343a97Smeem 			    strerror(errno));
58930ba2cbe9Sxc151355 		}
58940ba2cbe9Sxc151355 	} else {
58950ba2cbe9Sxc151355 		if (adt_put_event(event, ADT_FAILURE,
58960ba2cbe9Sxc151355 		    ADT_FAIL_VALUE_AUTH) != 0) {
589733343a97Smeem 			die("adt_put_event: (%s, failure): %s", errstr,
589833343a97Smeem 			    strerror(errno));
58990ba2cbe9Sxc151355 		}
59000ba2cbe9Sxc151355 	}
59010ba2cbe9Sxc151355 
59020ba2cbe9Sxc151355 	adt_free_event(event);
59030ba2cbe9Sxc151355 	(void) adt_end_session(ah);
59040ba2cbe9Sxc151355 }
59050ba2cbe9Sxc151355 
59060ba2cbe9Sxc151355 #define	MAX_SECOBJS		32
59070ba2cbe9Sxc151355 #define	MAX_SECOBJ_NAMELEN	32
59080ba2cbe9Sxc151355 static void
59098d5c46e6Sam223141 do_create_secobj(int argc, char **argv, const char *use)
59100ba2cbe9Sxc151355 {
59110ba2cbe9Sxc151355 	int			option, rval;
59120ba2cbe9Sxc151355 	FILE			*filep = NULL;
59130ba2cbe9Sxc151355 	char			*obj_name = NULL;
59140ba2cbe9Sxc151355 	char			*class_name = NULL;
59150ba2cbe9Sxc151355 	uint8_t			obj_val[DLADM_SECOBJ_VAL_MAX];
59160ba2cbe9Sxc151355 	uint_t			obj_len;
59170ba2cbe9Sxc151355 	boolean_t		success, temp = B_FALSE;
59180ba2cbe9Sxc151355 	dladm_status_t		status;
59190ba2cbe9Sxc151355 	dladm_secobj_class_t	class = -1;
59200ba2cbe9Sxc151355 	uid_t			euid;
59210ba2cbe9Sxc151355 
59220ba2cbe9Sxc151355 	opterr = 0;
59230ba2cbe9Sxc151355 	(void) memset(obj_val, 0, DLADM_SECOBJ_VAL_MAX);
59240ba2cbe9Sxc151355 	while ((option = getopt_long(argc, argv, ":f:c:R:t",
59250ba2cbe9Sxc151355 	    wifi_longopts, NULL)) != -1) {
59260ba2cbe9Sxc151355 		switch (option) {
59270ba2cbe9Sxc151355 		case 'f':
59280ba2cbe9Sxc151355 			euid = geteuid();
59290ba2cbe9Sxc151355 			(void) seteuid(getuid());
59300ba2cbe9Sxc151355 			filep = fopen(optarg, "r");
59310ba2cbe9Sxc151355 			if (filep == NULL) {
593233343a97Smeem 				die("cannot open %s: %s", optarg,
593333343a97Smeem 				    strerror(errno));
59340ba2cbe9Sxc151355 			}
59350ba2cbe9Sxc151355 			(void) seteuid(euid);
59360ba2cbe9Sxc151355 			break;
59370ba2cbe9Sxc151355 		case 'c':
59380ba2cbe9Sxc151355 			class_name = optarg;
59390ba2cbe9Sxc151355 			status = dladm_str2secobjclass(optarg, &class);
59400ba2cbe9Sxc151355 			if (status != DLADM_STATUS_OK) {
594133343a97Smeem 				die("invalid secure object class '%s', "
5942a399b765Szf162725 				    "valid values are: wep, wpa", optarg);
59430ba2cbe9Sxc151355 			}
59440ba2cbe9Sxc151355 			break;
59450ba2cbe9Sxc151355 		case 't':
59460ba2cbe9Sxc151355 			temp = B_TRUE;
59470ba2cbe9Sxc151355 			break;
59480ba2cbe9Sxc151355 		case 'R':
59490ba2cbe9Sxc151355 			status = dladm_set_rootdir(optarg);
59500ba2cbe9Sxc151355 			if (status != DLADM_STATUS_OK) {
595133343a97Smeem 				die_dlerr(status, "invalid directory "
595233343a97Smeem 				    "specified");
59530ba2cbe9Sxc151355 			}
59540ba2cbe9Sxc151355 			break;
59550ba2cbe9Sxc151355 		default:
59568d5c46e6Sam223141 			die_opterr(optopt, option, use);
59570ba2cbe9Sxc151355 			break;
59580ba2cbe9Sxc151355 		}
59590ba2cbe9Sxc151355 	}
59600ba2cbe9Sxc151355 
59610ba2cbe9Sxc151355 	if (optind == (argc - 1))
59620ba2cbe9Sxc151355 		obj_name = argv[optind];
59630ba2cbe9Sxc151355 	else if (optind != argc)
59640ba2cbe9Sxc151355 		usage();
59650ba2cbe9Sxc151355 
596633343a97Smeem 	if (class == -1)
596733343a97Smeem 		die("secure object class required");
59680ba2cbe9Sxc151355 
596933343a97Smeem 	if (obj_name == NULL)
597033343a97Smeem 		die("secure object name required");
59710ba2cbe9Sxc151355 
5972a9489f61SAnurag S. Maskey 	if (!dladm_valid_secobj_name(obj_name))
5973a9489f61SAnurag S. Maskey 		die("invalid secure object name '%s'", obj_name);
5974a9489f61SAnurag S. Maskey 
59750ba2cbe9Sxc151355 	success = check_auth(LINK_SEC_AUTH);
59760ba2cbe9Sxc151355 	audit_secobj(LINK_SEC_AUTH, class_name, obj_name, success, B_TRUE);
597733343a97Smeem 	if (!success)
597833343a97Smeem 		die("authorization '%s' is required", LINK_SEC_AUTH);
59790ba2cbe9Sxc151355 
598033343a97Smeem 	rval = get_secobj_val(obj_name, obj_val, &obj_len, class, filep);
598133343a97Smeem 	if (rval != 0) {
59820ba2cbe9Sxc151355 		switch (rval) {
59830ba2cbe9Sxc151355 		case ENOENT:
598433343a97Smeem 			die("invalid secure object class");
59850ba2cbe9Sxc151355 			break;
59860ba2cbe9Sxc151355 		case EINVAL:
598733343a97Smeem 			die("invalid secure object value");
59880ba2cbe9Sxc151355 			break;
59890ba2cbe9Sxc151355 		case ENOTSUP:
599033343a97Smeem 			die("verification failed");
59910ba2cbe9Sxc151355 			break;
59920ba2cbe9Sxc151355 		default:
599333343a97Smeem 			die("invalid secure object: %s", strerror(rval));
59940ba2cbe9Sxc151355 			break;
59950ba2cbe9Sxc151355 		}
59960ba2cbe9Sxc151355 	}
59970ba2cbe9Sxc151355 
59984ac67f02SAnurag S. Maskey 	status = dladm_set_secobj(handle, obj_name, class, obj_val, obj_len,
5999d62bc4baSyz147064 	    DLADM_OPT_CREATE | DLADM_OPT_ACTIVE);
60000ba2cbe9Sxc151355 	if (status != DLADM_STATUS_OK) {
600133343a97Smeem 		die_dlerr(status, "could not create secure object '%s'",
600233343a97Smeem 		    obj_name);
60030ba2cbe9Sxc151355 	}
60040ba2cbe9Sxc151355 	if (temp)
60050ba2cbe9Sxc151355 		return;
60060ba2cbe9Sxc151355 
60074ac67f02SAnurag S. Maskey 	status = dladm_set_secobj(handle, obj_name, class, obj_val, obj_len,
60080ba2cbe9Sxc151355 	    DLADM_OPT_PERSIST);
60090ba2cbe9Sxc151355 	if (status != DLADM_STATUS_OK) {
601033343a97Smeem 		warn_dlerr(status, "could not persistently create secure "
601133343a97Smeem 		    "object '%s'", obj_name);
60120ba2cbe9Sxc151355 	}
60130ba2cbe9Sxc151355 }
60140ba2cbe9Sxc151355 
60150ba2cbe9Sxc151355 static void
60168d5c46e6Sam223141 do_delete_secobj(int argc, char **argv, const char *use)
60170ba2cbe9Sxc151355 {
60180ba2cbe9Sxc151355 	int		i, option;
60190ba2cbe9Sxc151355 	boolean_t	temp = B_FALSE;
60200ba2cbe9Sxc151355 	boolean_t	success;
60210ba2cbe9Sxc151355 	dladm_status_t	status, pstatus;
6022*8002d411SSowmini Varadhan 	int		nfields = 1;
6023*8002d411SSowmini Varadhan 	char		*field, *token, *lasts = NULL, c;
60240ba2cbe9Sxc151355 
60250ba2cbe9Sxc151355 	opterr = 0;
60260ba2cbe9Sxc151355 	status = pstatus = DLADM_STATUS_OK;
602733343a97Smeem 	while ((option = getopt_long(argc, argv, ":R:t",
60280ba2cbe9Sxc151355 	    wifi_longopts, NULL)) != -1) {
60290ba2cbe9Sxc151355 		switch (option) {
60300ba2cbe9Sxc151355 		case 't':
60310ba2cbe9Sxc151355 			temp = B_TRUE;
60320ba2cbe9Sxc151355 			break;
60330ba2cbe9Sxc151355 		case 'R':
60340ba2cbe9Sxc151355 			status = dladm_set_rootdir(optarg);
60350ba2cbe9Sxc151355 			if (status != DLADM_STATUS_OK) {
603633343a97Smeem 				die_dlerr(status, "invalid directory "
603733343a97Smeem 				    "specified");
60380ba2cbe9Sxc151355 			}
60390ba2cbe9Sxc151355 			break;
60400ba2cbe9Sxc151355 		default:
60418d5c46e6Sam223141 			die_opterr(optopt, option, use);
60420ba2cbe9Sxc151355 			break;
60430ba2cbe9Sxc151355 		}
60440ba2cbe9Sxc151355 	}
60450ba2cbe9Sxc151355 
60460ba2cbe9Sxc151355 	if (optind == (argc - 1)) {
6047*8002d411SSowmini Varadhan 		token = argv[optind];
6048*8002d411SSowmini Varadhan 		if (token == NULL)
6049*8002d411SSowmini Varadhan 			die("secure object name required");
6050*8002d411SSowmini Varadhan 		while ((c = *token++) != NULL) {
6051*8002d411SSowmini Varadhan 			if (c == ',')
6052*8002d411SSowmini Varadhan 				nfields++;
60530ba2cbe9Sxc151355 		}
6054*8002d411SSowmini Varadhan 		token = strdup(argv[optind]);
6055*8002d411SSowmini Varadhan 		if (token == NULL)
6056*8002d411SSowmini Varadhan 			die("no memory");
60570ba2cbe9Sxc151355 	} else if (optind != argc)
60580ba2cbe9Sxc151355 		usage();
60590ba2cbe9Sxc151355 
60600ba2cbe9Sxc151355 	success = check_auth(LINK_SEC_AUTH);
6061a399b765Szf162725 	audit_secobj(LINK_SEC_AUTH, "unknown", argv[optind], success, B_FALSE);
606233343a97Smeem 	if (!success)
606333343a97Smeem 		die("authorization '%s' is required", LINK_SEC_AUTH);
60640ba2cbe9Sxc151355 
6065*8002d411SSowmini Varadhan 	for (i = 0; i < nfields; i++) {
6066*8002d411SSowmini Varadhan 
6067*8002d411SSowmini Varadhan 		field = strtok_r(token, ",", &lasts);
6068*8002d411SSowmini Varadhan 		token = NULL;
6069*8002d411SSowmini Varadhan 		status = dladm_unset_secobj(handle, field, DLADM_OPT_ACTIVE);
60700ba2cbe9Sxc151355 		if (!temp) {
6071*8002d411SSowmini Varadhan 			pstatus = dladm_unset_secobj(handle, field,
60720ba2cbe9Sxc151355 			    DLADM_OPT_PERSIST);
60730ba2cbe9Sxc151355 		} else {
60740ba2cbe9Sxc151355 			pstatus = DLADM_STATUS_OK;
60750ba2cbe9Sxc151355 		}
60760ba2cbe9Sxc151355 
60770ba2cbe9Sxc151355 		if (status != DLADM_STATUS_OK) {
607833343a97Smeem 			warn_dlerr(status, "could not delete secure object "
6079*8002d411SSowmini Varadhan 			    "'%s'", field);
60800ba2cbe9Sxc151355 		}
60810ba2cbe9Sxc151355 		if (pstatus != DLADM_STATUS_OK) {
608233343a97Smeem 			warn_dlerr(pstatus, "could not persistently delete "
6083*8002d411SSowmini Varadhan 			    "secure object '%s'", field);
60840ba2cbe9Sxc151355 		}
60850ba2cbe9Sxc151355 	}
6086*8002d411SSowmini Varadhan 	free(token);
60874ac67f02SAnurag S. Maskey 
60884ac67f02SAnurag S. Maskey 	if (status != DLADM_STATUS_OK || pstatus != DLADM_STATUS_OK) {
60894ac67f02SAnurag S. Maskey 		dladm_close(handle);
60900ba2cbe9Sxc151355 		exit(1);
60910ba2cbe9Sxc151355 	}
60924ac67f02SAnurag S. Maskey }
60930ba2cbe9Sxc151355 
60940ba2cbe9Sxc151355 typedef struct show_secobj_state {
60950ba2cbe9Sxc151355 	boolean_t	ss_persist;
6096*8002d411SSowmini Varadhan 	boolean_t	ss_parsable;
60970ba2cbe9Sxc151355 	boolean_t	ss_header;
6098*8002d411SSowmini Varadhan 	ofmt_handle_t	ss_ofmt;
60990ba2cbe9Sxc151355 } show_secobj_state_t;
61000ba2cbe9Sxc151355 
61010ba2cbe9Sxc151355 
61020ba2cbe9Sxc151355 static boolean_t
61034ac67f02SAnurag S. Maskey show_secobj(dladm_handle_t dh, void *arg, const char *obj_name)
61040ba2cbe9Sxc151355 {
61050ba2cbe9Sxc151355 	uint_t			obj_len = DLADM_SECOBJ_VAL_MAX;
61060ba2cbe9Sxc151355 	uint8_t			obj_val[DLADM_SECOBJ_VAL_MAX];
61070ba2cbe9Sxc151355 	char			buf[DLADM_STRSIZE];
61080ba2cbe9Sxc151355 	uint_t			flags = 0;
61090ba2cbe9Sxc151355 	dladm_secobj_class_t	class;
61100ba2cbe9Sxc151355 	show_secobj_state_t	*statep = arg;
61110ba2cbe9Sxc151355 	dladm_status_t		status;
6112e7801d59Ssowmini 	secobj_fields_buf_t	sbuf;
61130ba2cbe9Sxc151355 
61145f5c9f54SAnurag S. Maskey 	bzero(&sbuf, sizeof (secobj_fields_buf_t));
61150ba2cbe9Sxc151355 	if (statep->ss_persist)
61160ba2cbe9Sxc151355 		flags |= DLADM_OPT_PERSIST;
61170ba2cbe9Sxc151355 
61184ac67f02SAnurag S. Maskey 	status = dladm_get_secobj(dh, obj_name, &class, obj_val, &obj_len,
61194ac67f02SAnurag S. Maskey 	    flags);
612033343a97Smeem 	if (status != DLADM_STATUS_OK)
612133343a97Smeem 		die_dlerr(status, "cannot get secure object '%s'", obj_name);
61220ba2cbe9Sxc151355 
6123e7801d59Ssowmini 	(void) snprintf(sbuf.ss_obj_name, sizeof (sbuf.ss_obj_name),
6124e7801d59Ssowmini 	    obj_name);
6125e7801d59Ssowmini 	(void) dladm_secobjclass2str(class, buf);
6126e7801d59Ssowmini 	(void) snprintf(sbuf.ss_class, sizeof (sbuf.ss_class), "%s", buf);
6127e7801d59Ssowmini 	if (getuid() == 0) {
61280ba2cbe9Sxc151355 		char	val[DLADM_SECOBJ_VAL_MAX * 2];
61290ba2cbe9Sxc151355 		uint_t	len = sizeof (val);
61300ba2cbe9Sxc151355 
6131e7801d59Ssowmini 		if (octet_to_hexascii(obj_val, obj_len, val, &len) == 0)
6132e7801d59Ssowmini 			(void) snprintf(sbuf.ss_val,
6133e7801d59Ssowmini 			    sizeof (sbuf.ss_val), "%s", val);
61340ba2cbe9Sxc151355 	}
6135*8002d411SSowmini Varadhan 	ofmt_print(statep->ss_ofmt, &sbuf);
61360ba2cbe9Sxc151355 	return (B_TRUE);
61370ba2cbe9Sxc151355 }
61380ba2cbe9Sxc151355 
61390ba2cbe9Sxc151355 static void
61408d5c46e6Sam223141 do_show_secobj(int argc, char **argv, const char *use)
61410ba2cbe9Sxc151355 {
61420ba2cbe9Sxc151355 	int			option;
61430ba2cbe9Sxc151355 	show_secobj_state_t	state;
61440ba2cbe9Sxc151355 	dladm_status_t		status;
61450d365605Sschuster 	boolean_t		o_arg = B_FALSE;
61460ba2cbe9Sxc151355 	uint_t			i;
61470ba2cbe9Sxc151355 	uint_t			flags;
6148e7801d59Ssowmini 	char			*fields_str = NULL;
6149e7801d59Ssowmini 	char			*def_fields = "object,class";
6150e7801d59Ssowmini 	char			*all_fields = "object,class,value";
6151*8002d411SSowmini Varadhan 	char			*field, *token, *lasts = NULL, c;
6152*8002d411SSowmini Varadhan 	ofmt_handle_t		ofmt;
6153*8002d411SSowmini Varadhan 	ofmt_status_t		oferr;
6154*8002d411SSowmini Varadhan 	uint_t			ofmtflags = 0;
61550ba2cbe9Sxc151355 
61560ba2cbe9Sxc151355 	opterr = 0;
6157e7801d59Ssowmini 	bzero(&state, sizeof (state));
6158*8002d411SSowmini Varadhan 	state.ss_parsable = B_FALSE;
6159e7801d59Ssowmini 	fields_str = def_fields;
61600ba2cbe9Sxc151355 	state.ss_persist = B_FALSE;
6161*8002d411SSowmini Varadhan 	state.ss_parsable = B_FALSE;
61620ba2cbe9Sxc151355 	state.ss_header = B_TRUE;
6163e7801d59Ssowmini 	while ((option = getopt_long(argc, argv, ":pPo:",
61640ba2cbe9Sxc151355 	    wifi_longopts, NULL)) != -1) {
61650ba2cbe9Sxc151355 		switch (option) {
61660ba2cbe9Sxc151355 		case 'p':
6167*8002d411SSowmini Varadhan 			state.ss_parsable = B_TRUE;
61680ba2cbe9Sxc151355 			break;
61690ba2cbe9Sxc151355 		case 'P':
61700ba2cbe9Sxc151355 			state.ss_persist = B_TRUE;
61710ba2cbe9Sxc151355 			break;
6172e7801d59Ssowmini 		case 'o':
61730d365605Sschuster 			o_arg = B_TRUE;
6174e7801d59Ssowmini 			if (strcasecmp(optarg, "all") == 0)
6175e7801d59Ssowmini 				fields_str = all_fields;
6176e7801d59Ssowmini 			else
6177e7801d59Ssowmini 				fields_str = optarg;
61780ba2cbe9Sxc151355 			break;
61790ba2cbe9Sxc151355 		default:
61808d5c46e6Sam223141 			die_opterr(optopt, option, use);
61810ba2cbe9Sxc151355 			break;
61820ba2cbe9Sxc151355 		}
61830ba2cbe9Sxc151355 	}
61840ba2cbe9Sxc151355 
6185*8002d411SSowmini Varadhan 	if (state.ss_parsable && !o_arg)
61860d365605Sschuster 		die("option -c requires -o");
61870d365605Sschuster 
6188*8002d411SSowmini Varadhan 	if (state.ss_parsable && fields_str == all_fields)
61890d365605Sschuster 		die("\"-o all\" is invalid with -p");
61900d365605Sschuster 
6191*8002d411SSowmini Varadhan 	if (state.ss_parsable)
6192*8002d411SSowmini Varadhan 		ofmtflags |= OFMT_PARSABLE;
6193*8002d411SSowmini Varadhan 	oferr = ofmt_open(fields_str, secobj_fields, ofmtflags, 0, &ofmt);
6194*8002d411SSowmini Varadhan 	dladm_ofmt_check(oferr, state.ss_parsable, ofmt);
6195*8002d411SSowmini Varadhan 	state.ss_ofmt = ofmt;
6196e7801d59Ssowmini 
6197e7801d59Ssowmini 	flags = state.ss_persist ? DLADM_OPT_PERSIST : 0;
61984ac67f02SAnurag S. Maskey 
61990ba2cbe9Sxc151355 	if (optind == (argc - 1)) {
6200*8002d411SSowmini Varadhan 		uint_t obj_fields = 1;
6201*8002d411SSowmini Varadhan 
6202*8002d411SSowmini Varadhan 		token = argv[optind];
6203*8002d411SSowmini Varadhan 		if (token == NULL)
6204*8002d411SSowmini Varadhan 			die("secure object name required");
6205*8002d411SSowmini Varadhan 		while ((c = *token++) != NULL) {
6206*8002d411SSowmini Varadhan 			if (c == ',')
6207*8002d411SSowmini Varadhan 				obj_fields++;
62080ba2cbe9Sxc151355 		}
6209*8002d411SSowmini Varadhan 		token = strdup(argv[optind]);
6210*8002d411SSowmini Varadhan 		if (token == NULL)
6211*8002d411SSowmini Varadhan 			die("no memory");
6212*8002d411SSowmini Varadhan 		for (i = 0; i < obj_fields; i++) {
6213*8002d411SSowmini Varadhan 			field = strtok_r(token, ",", &lasts);
6214*8002d411SSowmini Varadhan 			token = NULL;
6215*8002d411SSowmini Varadhan 			if (!show_secobj(handle, &state, field))
62160ba2cbe9Sxc151355 				break;
62170ba2cbe9Sxc151355 		}
6218*8002d411SSowmini Varadhan 		free(token);
6219*8002d411SSowmini Varadhan 		ofmt_close(ofmt);
62200ba2cbe9Sxc151355 		return;
62210ba2cbe9Sxc151355 	} else if (optind != argc)
62220ba2cbe9Sxc151355 		usage();
62230ba2cbe9Sxc151355 
62244ac67f02SAnurag S. Maskey 	status = dladm_walk_secobj(handle, &state, show_secobj, flags);
62254ac67f02SAnurag S. Maskey 
622633343a97Smeem 	if (status != DLADM_STATUS_OK)
622733343a97Smeem 		die_dlerr(status, "show-secobj");
6228*8002d411SSowmini Varadhan 	ofmt_close(ofmt);
62290ba2cbe9Sxc151355 }
62300ba2cbe9Sxc151355 
62310ba2cbe9Sxc151355 /*ARGSUSED*/
6232d62bc4baSyz147064 static int
62334ac67f02SAnurag S. Maskey i_dladm_init_linkprop(dladm_handle_t dh, datalink_id_t linkid, void *arg)
6234d62bc4baSyz147064 {
62354ac67f02SAnurag S. Maskey 	(void) dladm_init_linkprop(dh, linkid, B_TRUE);
6236d62bc4baSyz147064 	return (DLADM_WALK_CONTINUE);
6237d62bc4baSyz147064 }
6238d62bc4baSyz147064 
62398d5c46e6Sam223141 /*ARGSUSED*/
6240da14cebeSEric Cheng void
62418d5c46e6Sam223141 do_init_linkprop(int argc, char **argv, const char *use)
62420ba2cbe9Sxc151355 {
624330890389Sartem 	int			option;
624430890389Sartem 	dladm_status_t		status;
624530890389Sartem 	datalink_id_t		linkid = DATALINK_ALL_LINKID;
624630890389Sartem 	datalink_media_t	media = DATALINK_ANY_MEDIATYPE;
624730890389Sartem 	uint_t			any_media = B_TRUE;
624830890389Sartem 
624930890389Sartem 	opterr = 0;
625030890389Sartem 	while ((option = getopt(argc, argv, ":w")) != -1) {
625130890389Sartem 		switch (option) {
625230890389Sartem 		case 'w':
625330890389Sartem 			media = DL_WIFI;
625430890389Sartem 			any_media = B_FALSE;
625530890389Sartem 			break;
625630890389Sartem 		default:
62578d5c46e6Sam223141 			/*
62588d5c46e6Sam223141 			 * Because init-linkprop is not a public command,
62598d5c46e6Sam223141 			 * print the usage instead.
62608d5c46e6Sam223141 			 */
62618d5c46e6Sam223141 			usage();
626230890389Sartem 			break;
626330890389Sartem 		}
626430890389Sartem 	}
626530890389Sartem 
626630890389Sartem 	if (optind == (argc - 1)) {
62674ac67f02SAnurag S. Maskey 		if ((status = dladm_name2info(handle, argv[optind], &linkid,
62684ac67f02SAnurag S. Maskey 		    NULL, NULL, NULL)) != DLADM_STATUS_OK)
626930890389Sartem 			die_dlerr(status, "link %s is not valid", argv[optind]);
627030890389Sartem 	} else if (optind != argc) {
627130890389Sartem 		usage();
627230890389Sartem 	}
627330890389Sartem 
627430890389Sartem 	if (linkid == DATALINK_ALL_LINKID) {
6275d62bc4baSyz147064 		/*
627630890389Sartem 		 * linkprops of links of other classes have been initialized as
6277d62bc4baSyz147064 		 * part of the dladm up-xxx operation.
6278d62bc4baSyz147064 		 */
62794ac67f02SAnurag S. Maskey 		(void) dladm_walk_datalink_id(i_dladm_init_linkprop, handle,
62804ac67f02SAnurag S. Maskey 		    NULL, DATALINK_CLASS_PHYS, media, DLADM_OPT_PERSIST);
628130890389Sartem 	} else {
62824ac67f02SAnurag S. Maskey 		(void) dladm_init_linkprop(handle, linkid, any_media);
628330890389Sartem 	}
62840ba2cbe9Sxc151355 }
62850ba2cbe9Sxc151355 
62860ba2cbe9Sxc151355 static void
62878d5c46e6Sam223141 do_show_ether(int argc, char **argv, const char *use)
6288e7801d59Ssowmini {
6289e7801d59Ssowmini 	int 			option;
6290e7801d59Ssowmini 	datalink_id_t		linkid;
6291e7801d59Ssowmini 	print_ether_state_t 	state;
6292*8002d411SSowmini Varadhan 	char			*fields_str = NULL;
6293*8002d411SSowmini Varadhan 	ofmt_handle_t		ofmt;
6294*8002d411SSowmini Varadhan 	ofmt_status_t		oferr;
6295*8002d411SSowmini Varadhan 	uint_t			ofmtflags = 0;
6296e7801d59Ssowmini 
6297e7801d59Ssowmini 	bzero(&state, sizeof (state));
6298e7801d59Ssowmini 	state.es_link = NULL;
6299*8002d411SSowmini Varadhan 	state.es_parsable = B_FALSE;
6300e7801d59Ssowmini 
6301e7801d59Ssowmini 	while ((option = getopt_long(argc, argv, "o:px",
6302e7801d59Ssowmini 	    showeth_lopts, NULL)) != -1) {
6303e7801d59Ssowmini 		switch (option) {
6304e7801d59Ssowmini 			case 'x':
6305e7801d59Ssowmini 				state.es_extended = B_TRUE;
6306e7801d59Ssowmini 				break;
6307e7801d59Ssowmini 			case 'p':
6308*8002d411SSowmini Varadhan 				state.es_parsable = B_TRUE;
6309e7801d59Ssowmini 				break;
6310e7801d59Ssowmini 			case 'o':
6311e7801d59Ssowmini 				fields_str = optarg;
6312e7801d59Ssowmini 				break;
6313e7801d59Ssowmini 			default:
63148d5c46e6Sam223141 				die_opterr(optopt, option, use);
6315e7801d59Ssowmini 				break;
6316e7801d59Ssowmini 		}
6317e7801d59Ssowmini 	}
6318e7801d59Ssowmini 
6319e7801d59Ssowmini 	if (optind == (argc - 1))
6320e7801d59Ssowmini 		state.es_link = argv[optind];
6321e7801d59Ssowmini 
6322*8002d411SSowmini Varadhan 	if (state.es_parsable)
6323*8002d411SSowmini Varadhan 		ofmtflags |= OFMT_PARSABLE;
6324*8002d411SSowmini Varadhan 	oferr = ofmt_open(fields_str, ether_fields, ofmtflags,
6325*8002d411SSowmini Varadhan 	    DLADM_DEFAULT_COL, &ofmt);
6326*8002d411SSowmini Varadhan 	dladm_ofmt_check(oferr, state.es_parsable, ofmt);
6327*8002d411SSowmini Varadhan 	state.es_ofmt = ofmt;
63284ac67f02SAnurag S. Maskey 
6329e7801d59Ssowmini 	if (state.es_link == NULL) {
63304ac67f02SAnurag S. Maskey 		(void) dladm_walk_datalink_id(show_etherprop, handle, &state,
6331e7801d59Ssowmini 		    DATALINK_CLASS_PHYS, DL_ETHER,
6332e7801d59Ssowmini 		    DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST);
6333e7801d59Ssowmini 	} else {
63344ac67f02SAnurag S. Maskey 		if (!link_is_ether(state.es_link, &linkid))
6335e7801d59Ssowmini 			die("invalid link specified");
63364ac67f02SAnurag S. Maskey 		(void) show_etherprop(handle, linkid, &state);
6337e7801d59Ssowmini 	}
6338*8002d411SSowmini Varadhan 	ofmt_close(ofmt);
6339e7801d59Ssowmini }
6340e7801d59Ssowmini 
6341e7801d59Ssowmini static int
63424ac67f02SAnurag S. Maskey show_etherprop(dladm_handle_t dh, datalink_id_t linkid, void *arg)
6343e7801d59Ssowmini {
6344e7801d59Ssowmini 	print_ether_state_t	*statep = arg;
6345e7801d59Ssowmini 	ether_fields_buf_t	ebuf;
63464784fcbdSSowmini Varadhan 	dladm_ether_info_t	eattr;
63474784fcbdSSowmini Varadhan 	dladm_status_t		status;
6348e7801d59Ssowmini 
63495f5c9f54SAnurag S. Maskey 	bzero(&ebuf, sizeof (ether_fields_buf_t));
63504ac67f02SAnurag S. Maskey 	if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL,
6351e7801d59Ssowmini 	    ebuf.eth_link, sizeof (ebuf.eth_link)) != DLADM_STATUS_OK) {
6352e7801d59Ssowmini 		return (DLADM_WALK_CONTINUE);
6353e7801d59Ssowmini 	}
6354e7801d59Ssowmini 
63554ac67f02SAnurag S. Maskey 	status = dladm_ether_info(dh, linkid, &eattr);
63564784fcbdSSowmini Varadhan 	if (status != DLADM_STATUS_OK)
63574784fcbdSSowmini Varadhan 		goto cleanup;
6358e7801d59Ssowmini 
63594784fcbdSSowmini Varadhan 	(void) strlcpy(ebuf.eth_ptype, "current", sizeof (ebuf.eth_ptype));
6360e7801d59Ssowmini 
63614784fcbdSSowmini Varadhan 	(void) dladm_ether_autoneg2str(ebuf.eth_autoneg,
63624784fcbdSSowmini Varadhan 	    sizeof (ebuf.eth_autoneg), &eattr, CURRENT);
63634784fcbdSSowmini Varadhan 	(void) dladm_ether_pause2str(ebuf.eth_pause,
63644784fcbdSSowmini Varadhan 	    sizeof (ebuf.eth_pause), &eattr, CURRENT);
63654784fcbdSSowmini Varadhan 	(void) dladm_ether_spdx2str(ebuf.eth_spdx,
63664784fcbdSSowmini Varadhan 	    sizeof (ebuf.eth_spdx), &eattr, CURRENT);
63674784fcbdSSowmini Varadhan 	(void) strlcpy(ebuf.eth_state,
63684784fcbdSSowmini Varadhan 	    dladm_linkstate2str(eattr.lei_state, ebuf.eth_state),
63694784fcbdSSowmini Varadhan 	    sizeof (ebuf.eth_state));
63704784fcbdSSowmini Varadhan 	(void) strlcpy(ebuf.eth_rem_fault,
63714784fcbdSSowmini Varadhan 	    (eattr.lei_attr[CURRENT].le_fault ? "fault" : "none"),
63724784fcbdSSowmini Varadhan 	    sizeof (ebuf.eth_rem_fault));
6373e7801d59Ssowmini 
6374*8002d411SSowmini Varadhan 	ofmt_print(statep->es_ofmt, &ebuf);
6375e7801d59Ssowmini 
6376e7801d59Ssowmini 	if (statep->es_extended)
63774784fcbdSSowmini Varadhan 		show_ether_xprop(arg, &eattr);
6378e7801d59Ssowmini 
63794784fcbdSSowmini Varadhan cleanup:
63804784fcbdSSowmini Varadhan 	dladm_ether_info_done(&eattr);
6381e7801d59Ssowmini 	return (DLADM_WALK_CONTINUE);
6382e7801d59Ssowmini }
6383e7801d59Ssowmini 
6384e7801d59Ssowmini /* ARGSUSED */
6385e7801d59Ssowmini static void
63868d5c46e6Sam223141 do_init_secobj(int argc, char **argv, const char *use)
63870ba2cbe9Sxc151355 {
63880ba2cbe9Sxc151355 	dladm_status_t	status;
63890ba2cbe9Sxc151355 
63904ac67f02SAnurag S. Maskey 	status = dladm_init_secobj(handle);
639133343a97Smeem 	if (status != DLADM_STATUS_OK)
639233343a97Smeem 		die_dlerr(status, "secure object initialization failed");
639333343a97Smeem }
639433343a97Smeem 
6395d62bc4baSyz147064 /*
6396d62bc4baSyz147064  * "-R" option support. It is used for live upgrading. Append dladm commands
6397d62bc4baSyz147064  * to a upgrade script which will be run when the alternative root boots up:
6398d62bc4baSyz147064  *
6399b9e076dcSyz147064  * - If the /etc/dladm/datalink.conf file exists on the alternative root,
6400b9e076dcSyz147064  * append dladm commands to the <altroot>/var/svc/profile/upgrade_datalink
6401b9e076dcSyz147064  * script. This script will be run as part of the network/physical service.
6402b9e076dcSyz147064  * We cannot defer this to /var/svc/profile/upgrade because then the
6403b9e076dcSyz147064  * configuration will not be able to take effect before network/physical
6404b9e076dcSyz147064  * plumbs various interfaces.
6405d62bc4baSyz147064  *
6406b9e076dcSyz147064  * - If the /etc/dladm/datalink.conf file does not exist on the alternative
6407b9e076dcSyz147064  * root, append dladm commands to the <altroot>/var/svc/profile/upgrade script,
6408b9e076dcSyz147064  * which will be run in the manifest-import service.
6409d62bc4baSyz147064  *
6410d62bc4baSyz147064  * Note that the SMF team is considering to move the manifest-import service
6411d62bc4baSyz147064  * to be run at the very begining of boot. Once that is done, the need for
6412d62bc4baSyz147064  * the /var/svc/profile/upgrade_datalink script will not exist any more.
6413d62bc4baSyz147064  */
6414d62bc4baSyz147064 static void
6415d62bc4baSyz147064 altroot_cmd(char *altroot, int argc, char *argv[])
6416d62bc4baSyz147064 {
6417d62bc4baSyz147064 	char		path[MAXPATHLEN];
6418d62bc4baSyz147064 	struct stat	stbuf;
6419d62bc4baSyz147064 	FILE		*fp;
6420d62bc4baSyz147064 	int		i;
6421d62bc4baSyz147064 
6422d62bc4baSyz147064 	/*
6423b9e076dcSyz147064 	 * Check for the existence of the /etc/dladm/datalink.conf
6424b9e076dcSyz147064 	 * configuration file, and determine the name of script file.
6425d62bc4baSyz147064 	 */
6426b9e076dcSyz147064 	(void) snprintf(path, MAXPATHLEN, "/%s/etc/dladm/datalink.conf",
6427b9e076dcSyz147064 	    altroot);
6428d62bc4baSyz147064 	if (stat(path, &stbuf) < 0) {
6429d62bc4baSyz147064 		(void) snprintf(path, MAXPATHLEN, "/%s/%s", altroot,
6430d62bc4baSyz147064 		    SMF_UPGRADE_FILE);
6431d62bc4baSyz147064 	} else {
6432d62bc4baSyz147064 		(void) snprintf(path, MAXPATHLEN, "/%s/%s", altroot,
6433d62bc4baSyz147064 		    SMF_UPGRADEDATALINK_FILE);
6434d62bc4baSyz147064 	}
6435d62bc4baSyz147064 
6436d62bc4baSyz147064 	if ((fp = fopen(path, "a+")) == NULL)
6437d62bc4baSyz147064 		die("operation not supported on %s", altroot);
6438d62bc4baSyz147064 
6439d62bc4baSyz147064 	(void) fprintf(fp, "/sbin/dladm ");
6440d62bc4baSyz147064 	for (i = 0; i < argc; i++) {
6441d62bc4baSyz147064 		/*
6442d62bc4baSyz147064 		 * Directly write to the file if it is not the "-R <altroot>"
6443d62bc4baSyz147064 		 * option. In which case, skip it.
6444d62bc4baSyz147064 		 */
6445d62bc4baSyz147064 		if (strcmp(argv[i], "-R") != 0)
6446d62bc4baSyz147064 			(void) fprintf(fp, "%s ", argv[i]);
6447d62bc4baSyz147064 		else
6448d62bc4baSyz147064 			i ++;
6449d62bc4baSyz147064 	}
6450d62bc4baSyz147064 	(void) fprintf(fp, "%s\n", SMF_DLADM_UPGRADE_MSG);
6451d62bc4baSyz147064 	(void) fclose(fp);
64524ac67f02SAnurag S. Maskey 	dladm_close(handle);
6453d62bc4baSyz147064 	exit(0);
6454d62bc4baSyz147064 }
6455d62bc4baSyz147064 
6456d62bc4baSyz147064 /*
6457d62bc4baSyz147064  * Convert the string to an integer. Note that the string must not have any
6458d62bc4baSyz147064  * trailing non-integer characters.
6459d62bc4baSyz147064  */
646033343a97Smeem static boolean_t
646133343a97Smeem str2int(const char *str, int *valp)
646233343a97Smeem {
646333343a97Smeem 	int	val;
646433343a97Smeem 	char	*endp = NULL;
646533343a97Smeem 
646633343a97Smeem 	errno = 0;
646733343a97Smeem 	val = strtol(str, &endp, 10);
646833343a97Smeem 	if (errno != 0 || *endp != '\0')
646933343a97Smeem 		return (B_FALSE);
647033343a97Smeem 
647133343a97Smeem 	*valp = val;
647233343a97Smeem 	return (B_TRUE);
647333343a97Smeem }
647433343a97Smeem 
647533343a97Smeem /* PRINTFLIKE1 */
647633343a97Smeem static void
647733343a97Smeem warn(const char *format, ...)
647833343a97Smeem {
647933343a97Smeem 	va_list alist;
648033343a97Smeem 
648133343a97Smeem 	format = gettext(format);
648233343a97Smeem 	(void) fprintf(stderr, "%s: warning: ", progname);
648333343a97Smeem 
648433343a97Smeem 	va_start(alist, format);
648533343a97Smeem 	(void) vfprintf(stderr, format, alist);
648633343a97Smeem 	va_end(alist);
648733343a97Smeem 
648833343a97Smeem 	(void) putchar('\n');
648933343a97Smeem }
649033343a97Smeem 
649133343a97Smeem /* PRINTFLIKE2 */
649233343a97Smeem static void
649333343a97Smeem warn_dlerr(dladm_status_t err, const char *format, ...)
649433343a97Smeem {
649533343a97Smeem 	va_list alist;
649633343a97Smeem 	char	errmsg[DLADM_STRSIZE];
649733343a97Smeem 
649833343a97Smeem 	format = gettext(format);
649933343a97Smeem 	(void) fprintf(stderr, gettext("%s: warning: "), progname);
650033343a97Smeem 
650133343a97Smeem 	va_start(alist, format);
650233343a97Smeem 	(void) vfprintf(stderr, format, alist);
650333343a97Smeem 	va_end(alist);
650433343a97Smeem 	(void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg));
650533343a97Smeem }
650633343a97Smeem 
65074ac67f02SAnurag S. Maskey /*
65084ac67f02SAnurag S. Maskey  * Also closes the dladm handle if it is not NULL.
65094ac67f02SAnurag S. Maskey  */
651033343a97Smeem /* PRINTFLIKE2 */
651133343a97Smeem static void
651233343a97Smeem die_dlerr(dladm_status_t err, const char *format, ...)
651333343a97Smeem {
651433343a97Smeem 	va_list alist;
651533343a97Smeem 	char	errmsg[DLADM_STRSIZE];
651633343a97Smeem 
651733343a97Smeem 	format = gettext(format);
651833343a97Smeem 	(void) fprintf(stderr, "%s: ", progname);
651933343a97Smeem 
652033343a97Smeem 	va_start(alist, format);
652133343a97Smeem 	(void) vfprintf(stderr, format, alist);
652233343a97Smeem 	va_end(alist);
652333343a97Smeem 	(void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg));
652433343a97Smeem 
65254ac67f02SAnurag S. Maskey 	/* close dladm handle if it was opened */
65264ac67f02SAnurag S. Maskey 	if (handle != NULL)
65274ac67f02SAnurag S. Maskey 		dladm_close(handle);
65284ac67f02SAnurag S. Maskey 
652933343a97Smeem 	exit(EXIT_FAILURE);
653033343a97Smeem }
653133343a97Smeem 
653233343a97Smeem /* PRINTFLIKE1 */
653333343a97Smeem static void
653433343a97Smeem die(const char *format, ...)
653533343a97Smeem {
653633343a97Smeem 	va_list alist;
653733343a97Smeem 
653833343a97Smeem 	format = gettext(format);
653933343a97Smeem 	(void) fprintf(stderr, "%s: ", progname);
654033343a97Smeem 
654133343a97Smeem 	va_start(alist, format);
654233343a97Smeem 	(void) vfprintf(stderr, format, alist);
654333343a97Smeem 	va_end(alist);
654433343a97Smeem 
654533343a97Smeem 	(void) putchar('\n');
65464ac67f02SAnurag S. Maskey 
65474ac67f02SAnurag S. Maskey 	/* close dladm handle if it was opened */
65484ac67f02SAnurag S. Maskey 	if (handle != NULL)
65494ac67f02SAnurag S. Maskey 		dladm_close(handle);
65504ac67f02SAnurag S. Maskey 
655133343a97Smeem 	exit(EXIT_FAILURE);
655233343a97Smeem }
655333343a97Smeem 
655433343a97Smeem static void
655533343a97Smeem die_optdup(int opt)
655633343a97Smeem {
655733343a97Smeem 	die("the option -%c cannot be specified more than once", opt);
655833343a97Smeem }
655933343a97Smeem 
656033343a97Smeem static void
65618d5c46e6Sam223141 die_opterr(int opt, int opterr, const char *usage)
656233343a97Smeem {
656333343a97Smeem 	switch (opterr) {
656433343a97Smeem 	case ':':
65658d5c46e6Sam223141 		die("option '-%c' requires a value\nusage: %s", opt,
65668d5c46e6Sam223141 		    gettext(usage));
656733343a97Smeem 		break;
656833343a97Smeem 	case '?':
656933343a97Smeem 	default:
65708d5c46e6Sam223141 		die("unrecognized option '-%c'\nusage: %s", opt,
65718d5c46e6Sam223141 		    gettext(usage));
657233343a97Smeem 		break;
65730ba2cbe9Sxc151355 	}
65740ba2cbe9Sxc151355 }
6575e7801d59Ssowmini 
6576e7801d59Ssowmini static void
65774784fcbdSSowmini Varadhan show_ether_xprop(void *arg, dladm_ether_info_t *eattr)
6578e7801d59Ssowmini {
6579e7801d59Ssowmini 	print_ether_state_t	*statep = arg;
6580e7801d59Ssowmini 	ether_fields_buf_t	ebuf;
65814784fcbdSSowmini Varadhan 	int			i;
6582e7801d59Ssowmini 
65834784fcbdSSowmini Varadhan 	for (i = CAPABLE; i <= PEERADV; i++)  {
6584e7801d59Ssowmini 		bzero(&ebuf, sizeof (ebuf));
65854784fcbdSSowmini Varadhan 		(void) strlcpy(ebuf.eth_ptype, ptype[i],
65864784fcbdSSowmini Varadhan 		    sizeof (ebuf.eth_ptype));
65874784fcbdSSowmini Varadhan 		(void) dladm_ether_autoneg2str(ebuf.eth_autoneg,
65884784fcbdSSowmini Varadhan 		    sizeof (ebuf.eth_autoneg), eattr, i);
65894784fcbdSSowmini Varadhan 		(void) dladm_ether_spdx2str(ebuf.eth_spdx,
65904784fcbdSSowmini Varadhan 		    sizeof (ebuf.eth_spdx), eattr, i);
65914784fcbdSSowmini Varadhan 		(void) dladm_ether_pause2str(ebuf.eth_pause,
65924784fcbdSSowmini Varadhan 		    sizeof (ebuf.eth_pause), eattr, i);
65934784fcbdSSowmini Varadhan 		(void) strlcpy(ebuf.eth_rem_fault,
65944784fcbdSSowmini Varadhan 		    (eattr->lei_attr[i].le_fault ? "fault" : "none"),
65954784fcbdSSowmini Varadhan 		    sizeof (ebuf.eth_rem_fault));
6596*8002d411SSowmini Varadhan 		ofmt_print(statep->es_ofmt, &ebuf);
6597e7801d59Ssowmini 	}
6598e7801d59Ssowmini 
6599e7801d59Ssowmini }
6600e7801d59Ssowmini 
6601e7801d59Ssowmini static boolean_t
6602e7801d59Ssowmini link_is_ether(const char *link, datalink_id_t *linkid)
6603e7801d59Ssowmini {
6604e7801d59Ssowmini 	uint32_t media;
6605e7801d59Ssowmini 	datalink_class_t class;
6606e7801d59Ssowmini 
66074ac67f02SAnurag S. Maskey 	if (dladm_name2info(handle, link, linkid, NULL, &class, &media) ==
6608e7801d59Ssowmini 	    DLADM_STATUS_OK) {
6609e7801d59Ssowmini 		if (class == DATALINK_CLASS_PHYS && media == DL_ETHER)
6610e7801d59Ssowmini 			return (B_TRUE);
6611e7801d59Ssowmini 	}
6612e7801d59Ssowmini 	return (B_FALSE);
6613e7801d59Ssowmini }
6614*8002d411SSowmini Varadhan 
6615*8002d411SSowmini Varadhan /*
6616*8002d411SSowmini Varadhan  * default output callback function that, when invoked,
6617*8002d411SSowmini Varadhan  * prints string which is offset by ofmt_arg->ofmt_id within buf.
6618*8002d411SSowmini Varadhan  */
6619*8002d411SSowmini Varadhan static boolean_t
6620*8002d411SSowmini Varadhan print_default_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
6621*8002d411SSowmini Varadhan {
6622*8002d411SSowmini Varadhan 	char *value;
6623*8002d411SSowmini Varadhan 
6624*8002d411SSowmini Varadhan 	value = (char *)ofarg->ofmt_cbarg + ofarg->ofmt_id;
6625*8002d411SSowmini Varadhan 	(void) strlcpy(buf, value, bufsize);
6626*8002d411SSowmini Varadhan 	return (B_TRUE);
6627*8002d411SSowmini Varadhan }
6628*8002d411SSowmini Varadhan 
6629*8002d411SSowmini Varadhan static void
6630*8002d411SSowmini Varadhan dladm_ofmt_check(ofmt_status_t oferr, boolean_t parsable,
6631*8002d411SSowmini Varadhan     ofmt_handle_t ofmt)
6632*8002d411SSowmini Varadhan {
6633*8002d411SSowmini Varadhan 	char buf[OFMT_BUFSIZE];
6634*8002d411SSowmini Varadhan 
6635*8002d411SSowmini Varadhan 	if (oferr == OFMT_SUCCESS)
6636*8002d411SSowmini Varadhan 		return;
6637*8002d411SSowmini Varadhan 	(void) ofmt_strerror(ofmt, oferr, buf, sizeof (buf));
6638*8002d411SSowmini Varadhan 	/*
6639*8002d411SSowmini Varadhan 	 * All errors are considered fatal in parsable mode.
6640*8002d411SSowmini Varadhan 	 * NOMEM errors are always fatal, regardless of mode.
6641*8002d411SSowmini Varadhan 	 * For other errors, we print diagnostics in human-readable
6642*8002d411SSowmini Varadhan 	 * mode and processs what we can.
6643*8002d411SSowmini Varadhan 	 */
6644*8002d411SSowmini Varadhan 	if (parsable || oferr == OFMT_ENOFIELDS) {
6645*8002d411SSowmini Varadhan 		ofmt_close(ofmt);
6646*8002d411SSowmini Varadhan 		die(buf);
6647*8002d411SSowmini Varadhan 	} else {
6648*8002d411SSowmini Varadhan 		warn(buf);
6649*8002d411SSowmini Varadhan 	}
6650*8002d411SSowmini Varadhan }
6651