xref: /titanic_41/usr/src/cmd/dladm/dladm.c (revision 3333c089e384cb7188dd6bab8d6280ecc95b2294)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #include <stdio.h>
27 #include <ctype.h>
28 #include <locale.h>
29 #include <signal.h>
30 #include <stdarg.h>
31 #include <stdlib.h>
32 #include <fcntl.h>
33 #include <string.h>
34 #include <stropts.h>
35 #include <sys/stat.h>
36 #include <errno.h>
37 #include <kstat.h>
38 #include <strings.h>
39 #include <getopt.h>
40 #include <unistd.h>
41 #include <priv.h>
42 #include <termios.h>
43 #include <pwd.h>
44 #include <auth_attr.h>
45 #include <auth_list.h>
46 #include <libintl.h>
47 #include <libdevinfo.h>
48 #include <libdlpi.h>
49 #include <libdladm.h>
50 #include <libdllink.h>
51 #include <libdlstat.h>
52 #include <libdlaggr.h>
53 #include <libdlwlan.h>
54 #include <libdlvlan.h>
55 #include <libdlvnic.h>
56 #include <libdlether.h>
57 #include <libdlsim.h>
58 #include <libinetutil.h>
59 #include <bsm/adt.h>
60 #include <bsm/adt_event.h>
61 #include <libdlvnic.h>
62 #include <sys/types.h>
63 #include <sys/socket.h>
64 #include <sys/processor.h>
65 #include <netinet/in.h>
66 #include <arpa/inet.h>
67 #include <net/if_types.h>
68 #include <stddef.h>
69 #include <ofmt.h>
70 
71 #define	MAXPORT			256
72 #define	MAXVNIC			256
73 #define	BUFLEN(lim, ptr)	(((lim) > (ptr)) ? ((lim) - (ptr)) : 0)
74 #define	MAXLINELEN		1024
75 #define	SMF_UPGRADE_FILE		"/var/svc/profile/upgrade"
76 #define	SMF_UPGRADEDATALINK_FILE	"/var/svc/profile/upgrade_datalink"
77 #define	SMF_DLADM_UPGRADE_MSG		" # added by dladm(1M)"
78 #define	DLADM_DEFAULT_COL	80
79 
80 /*
81  * used by the wifi show-* commands to set up ofmt_field_t structures.
82  */
83 #define	WIFI_CMD_SCAN		0x00000001
84 #define	WIFI_CMD_SHOW		0x00000002
85 #define	WIFI_CMD_ALL		(WIFI_CMD_SCAN | WIFI_CMD_SHOW)
86 
87 typedef struct show_state {
88 	boolean_t	ls_firstonly;
89 	boolean_t	ls_donefirst;
90 	pktsum_t	ls_prevstats;
91 	uint32_t	ls_flags;
92 	dladm_status_t	ls_status;
93 	ofmt_handle_t	ls_ofmt;
94 	boolean_t	ls_parsable;
95 	boolean_t	ls_mac;
96 	boolean_t	ls_hwgrp;
97 } show_state_t;
98 
99 typedef struct show_grp_state {
100 	pktsum_t	gs_prevstats[MAXPORT];
101 	uint32_t	gs_flags;
102 	dladm_status_t	gs_status;
103 	boolean_t	gs_parsable;
104 	boolean_t	gs_lacp;
105 	boolean_t	gs_extended;
106 	boolean_t	gs_stats;
107 	boolean_t	gs_firstonly;
108 	boolean_t	gs_donefirst;
109 	ofmt_handle_t	gs_ofmt;
110 } show_grp_state_t;
111 
112 typedef struct show_vnic_state {
113 	datalink_id_t	vs_vnic_id;
114 	datalink_id_t	vs_link_id;
115 	char		vs_vnic[MAXLINKNAMELEN];
116 	char		vs_link[MAXLINKNAMELEN];
117 	boolean_t	vs_parsable;
118 	boolean_t	vs_found;
119 	boolean_t	vs_firstonly;
120 	boolean_t	vs_donefirst;
121 	boolean_t	vs_stats;
122 	boolean_t	vs_printstats;
123 	pktsum_t	vs_totalstats;
124 	pktsum_t	vs_prevstats[MAXVNIC];
125 	boolean_t	vs_etherstub;
126 	dladm_status_t	vs_status;
127 	uint32_t	vs_flags;
128 	ofmt_handle_t	vs_ofmt;
129 } show_vnic_state_t;
130 
131 typedef struct show_usage_state_s {
132 	boolean_t	us_plot;
133 	boolean_t	us_parsable;
134 	boolean_t	us_printheader;
135 	boolean_t	us_first;
136 	boolean_t	us_showall;
137 	ofmt_handle_t	us_ofmt;
138 } show_usage_state_t;
139 
140 /*
141  * callback functions for printing output and error diagnostics.
142  */
143 static ofmt_cb_t print_default_cb, print_link_stats_cb, print_linkprop_cb;
144 static ofmt_cb_t print_lacp_cb, print_phys_one_mac_cb;
145 static ofmt_cb_t print_xaggr_cb, print_aggr_stats_cb;
146 static ofmt_cb_t print_phys_one_hwgrp_cb, print_wlan_attr_cb;
147 static ofmt_cb_t print_wifi_status_cb, print_link_attr_cb;
148 static void dladm_ofmt_check(ofmt_status_t, boolean_t, ofmt_handle_t);
149 
150 typedef void cmdfunc_t(int, char **, const char *);
151 
152 static cmdfunc_t do_show_link, do_show_wifi, do_show_phys;
153 static cmdfunc_t do_create_aggr, do_delete_aggr, do_add_aggr, do_remove_aggr;
154 static cmdfunc_t do_modify_aggr, do_show_aggr, do_up_aggr;
155 static cmdfunc_t do_scan_wifi, do_connect_wifi, do_disconnect_wifi;
156 static cmdfunc_t do_show_linkprop, do_set_linkprop, do_reset_linkprop;
157 static cmdfunc_t do_create_secobj, do_delete_secobj, do_show_secobj;
158 static cmdfunc_t do_init_linkprop, do_init_secobj;
159 static cmdfunc_t do_create_vlan, do_delete_vlan, do_up_vlan, do_show_vlan;
160 static cmdfunc_t do_rename_link, do_delete_phys, do_init_phys;
161 static cmdfunc_t do_show_linkmap;
162 static cmdfunc_t do_show_ether;
163 static cmdfunc_t do_create_vnic, do_delete_vnic, do_show_vnic;
164 static cmdfunc_t do_up_vnic;
165 static cmdfunc_t do_create_etherstub, do_delete_etherstub, do_show_etherstub;
166 static cmdfunc_t do_create_simnet, do_modify_simnet;
167 static cmdfunc_t do_delete_simnet, do_show_simnet, do_up_simnet;
168 static cmdfunc_t do_show_usage;
169 
170 static void 	do_up_vnic_common(int, char **, const char *, boolean_t);
171 
172 static void	altroot_cmd(char *, int, char **);
173 static int	show_linkprop_onelink(dladm_handle_t, datalink_id_t, void *);
174 
175 static void	link_stats(datalink_id_t, uint_t, char *, show_state_t *);
176 static void	aggr_stats(datalink_id_t, show_grp_state_t *, uint_t);
177 static void	vnic_stats(show_vnic_state_t *, uint32_t);
178 
179 static int	get_one_kstat(const char *, const char *, uint8_t,
180 		    void *, boolean_t);
181 static void	get_mac_stats(const char *, pktsum_t *);
182 static void	get_link_stats(const char *, pktsum_t *);
183 static uint64_t	get_ifspeed(const char *, boolean_t);
184 static const char	*get_linkstate(const char *, boolean_t, char *);
185 static const char	*get_linkduplex(const char *, boolean_t, char *);
186 
187 static int	show_etherprop(dladm_handle_t, datalink_id_t, void *);
188 static void	show_ether_xprop(void *, dladm_ether_info_t *);
189 static boolean_t	link_is_ether(const char *, datalink_id_t *);
190 
191 static boolean_t str2int(const char *, int *);
192 static void	die(const char *, ...);
193 static void	die_optdup(int);
194 static void	die_opterr(int, int, const char *);
195 static void	die_dlerr(dladm_status_t, const char *, ...);
196 static void	warn(const char *, ...);
197 static void	warn_dlerr(dladm_status_t, const char *, ...);
198 
199 typedef struct	cmd {
200 	char		*c_name;
201 	cmdfunc_t	*c_fn;
202 	const char	*c_usage;
203 } cmd_t;
204 
205 static cmd_t	cmds[] = {
206 	{ "rename-link",	do_rename_link,
207 	    "    rename-link      <oldlink> <newlink>"			},
208 	{ "show-link",		do_show_link,
209 	    "    show-link        [-pP] [-o <field>,..] [-s [-i <interval>]] "
210 	    "[<link>]\n"						},
211 	{ "create-aggr",	do_create_aggr,
212 	    "    create-aggr      [-t] [-P <policy>] [-L <mode>] [-T <time>] "
213 	    "[-u <address>]\n"
214 	    "\t\t     -l <link> [-l <link>...] <link>"			},
215 	{ "delete-aggr",	do_delete_aggr,
216 	    "    delete-aggr      [-t] <link>"				},
217 	{ "add-aggr",		do_add_aggr,
218 	    "    add-aggr         [-t] -l <link> [-l <link>...] <link>" },
219 	{ "remove-aggr",	do_remove_aggr,
220 	    "    remove-aggr      [-t] -l <link> [-l <link>...] <link>" },
221 	{ "modify-aggr",	do_modify_aggr,
222 	    "    modify-aggr      [-t] [-P <policy>] [-L <mode>] [-T <time>] "
223 	    "[-u <address>]\n"
224 	    "\t\t     <link>"						},
225 	{ "show-aggr",		do_show_aggr,
226 	    "    show-aggr        [-pPLx] [-o <field>,..] [-s [-i <interval>]] "
227 	    "[<link>]\n"						},
228 	{ "up-aggr",		do_up_aggr,	NULL			},
229 	{ "scan-wifi",		do_scan_wifi,
230 	    "    scan-wifi        [-p] [-o <field>,...] [<link>]"	},
231 	{ "connect-wifi",	do_connect_wifi,
232 	    "    connect-wifi     [-e <essid>] [-i <bssid>] [-k <key>,...] "
233 	    "[-s wep|wpa]\n"
234 	    "\t\t     [-a open|shared] [-b bss|ibss] [-c] [-m a|b|g] "
235 	    "[-T <time>]\n"
236 	    "\t\t     [<link>]"						},
237 	{ "disconnect-wifi",	do_disconnect_wifi,
238 	    "    disconnect-wifi  [-a] [<link>]"			},
239 	{ "show-wifi",		do_show_wifi,
240 	    "    show-wifi        [-p] [-o <field>,...] [<link>]\n"	},
241 	{ "set-linkprop",	do_set_linkprop,
242 	    "    set-linkprop     [-t] -p <prop>=<value>[,...] <name>"	},
243 	{ "reset-linkprop",	do_reset_linkprop,
244 	    "    reset-linkprop   [-t] [-p <prop>,...] <name>"		},
245 	{ "show-linkprop",	do_show_linkprop,
246 	    "    show-linkprop    [-cP] [-o <field>,...] [-p <prop>,...] "
247 	    "<name>\n"							},
248 	{ "show-ether",		do_show_ether,
249 	    "    show-ether       [-px][-o <field>,...] <link>\n"	},
250 	{ "create-secobj",	do_create_secobj,
251 	    "    create-secobj    [-t] [-f <file>] -c <class> <secobj>"	},
252 	{ "delete-secobj",	do_delete_secobj,
253 	    "    delete-secobj    [-t] <secobj>[,...]"			},
254 	{ "show-secobj",	do_show_secobj,
255 	    "    show-secobj      [-pP] [-o <field>,...] [<secobj>,...]\n" },
256 	{ "init-linkprop",	do_init_linkprop,	NULL		},
257 	{ "init-secobj",	do_init_secobj,		NULL		},
258 	{ "create-vlan", 	do_create_vlan,
259 	    "    create-vlan      [-ft] -l <link> -v <vid> [link]"	},
260 	{ "delete-vlan", 	do_delete_vlan,
261 	    "    delete-vlan      [-t] <link>"				},
262 	{ "show-vlan",		do_show_vlan,
263 	    "    show-vlan        [-pP] [-o <field>,..] [<link>]\n"	},
264 	{ "up-vlan",		do_up_vlan,		NULL		},
265 	{ "delete-phys",	do_delete_phys,
266 	    "    delete-phys      <link>"				},
267 	{ "show-phys",		do_show_phys,
268 	    "    show-phys        [-pP] [-o <field>,..] [-H] [<link>]\n"},
269 	{ "init-phys",		do_init_phys,		NULL		},
270 	{ "show-linkmap",	do_show_linkmap,	NULL		},
271 	{ "create-vnic",	do_create_vnic,
272 	    "    create-vnic      [-t] -l <link> [-m <value> | auto |\n"
273 	    "\t\t     {factory [-n <slot-id>]} | {random [-r <prefix>]}]\n"
274 	    "\t\t     [-v <vid> [-f]] [-p <prop>=<value>[,...]] [-H] "
275 	    "<vnic-link>"						},
276 	{ "delete-vnic",	do_delete_vnic,
277 	    "    delete-vnic      [-t] <vnic-link>"			},
278 	{ "show-vnic",		do_show_vnic,
279 	    "    show-vnic        [-pP] [-l <link>] [-s [-i <interval>]] "
280 	    "[<link>]\n"						},
281 	{ "up-vnic",		do_up_vnic,		NULL		},
282 	{ "create-etherstub",	do_create_etherstub,
283 	    "    create-etherstub [-t] <link>"				},
284 	{ "delete-etherstub",	do_delete_etherstub,
285 	    "    delete-etherstub [-t] <link>"				},
286 	{ "show-etherstub",	do_show_etherstub,
287 	    "    show-etherstub   [-t] [<link>]\n"			},
288 	{ "create-simnet",	do_create_simnet,	NULL		},
289 	{ "modify-simnet",	do_modify_simnet,	NULL		},
290 	{ "delete-simnet",	do_delete_simnet,	NULL		},
291 	{ "show-simnet",	do_show_simnet,		NULL		},
292 	{ "up-simnet",		do_up_simnet,		NULL		},
293 	{ "show-usage",		do_show_usage,
294 	    "    show-usage       [-a] [-d | -F <format>] "
295 	    "[-s <DD/MM/YYYY,HH:MM:SS>]\n"
296 	    "\t\t     [-e <DD/MM/YYYY,HH:MM:SS>] -f <logfile> [<link>]"	}
297 };
298 
299 static const struct option lopts[] = {
300 	{"vlan-id",	required_argument,	0, 'v'},
301 	{"output",	required_argument,	0, 'o'},
302 	{"dev",		required_argument,	0, 'd'},
303 	{"policy",	required_argument,	0, 'P'},
304 	{"lacp-mode",	required_argument,	0, 'L'},
305 	{"lacp-timer",	required_argument,	0, 'T'},
306 	{"unicast",	required_argument,	0, 'u'},
307 	{"temporary",	no_argument,		0, 't'},
308 	{"root-dir",	required_argument,	0, 'R'},
309 	{"link",	required_argument,	0, 'l'},
310 	{"forcible",	no_argument,		0, 'f'},
311 	{"bw-limit",	required_argument,	0, 'b'},
312 	{"mac-address",	required_argument,	0, 'm'},
313 	{"slot",	required_argument,	0, 'n'},
314 	{ 0, 0, 0, 0 }
315 };
316 
317 static const struct option show_lopts[] = {
318 	{"statistics",	no_argument,		0, 's'},
319 	{"continuous",	no_argument,		0, 'S'},
320 	{"interval",	required_argument,	0, 'i'},
321 	{"parsable",	no_argument,		0, 'p'},
322 	{"parseable",	no_argument,		0, 'p'},
323 	{"extended",	no_argument,		0, 'x'},
324 	{"output",	required_argument,	0, 'o'},
325 	{"persistent",	no_argument,		0, 'P'},
326 	{"lacp",	no_argument,		0, 'L'},
327 	{ 0, 0, 0, 0 }
328 };
329 
330 static const struct option prop_longopts[] = {
331 	{"temporary",	no_argument,		0, 't'  },
332 	{"output",	required_argument,	0, 'o'  },
333 	{"root-dir",	required_argument,	0, 'R'  },
334 	{"prop",	required_argument,	0, 'p'  },
335 	{"parsable",	no_argument,		0, 'c'  },
336 	{"parseable",	no_argument,		0, 'c'  },
337 	{"persistent",	no_argument,		0, 'P'  },
338 	{ 0, 0, 0, 0 }
339 };
340 
341 static const struct option wifi_longopts[] = {
342 	{"parsable",	no_argument,		0, 'p'  },
343 	{"parseable",	no_argument,		0, 'p'  },
344 	{"output",	required_argument,	0, 'o'  },
345 	{"essid",	required_argument,	0, 'e'  },
346 	{"bsstype",	required_argument,	0, 'b'  },
347 	{"mode",	required_argument,	0, 'm'  },
348 	{"key",		required_argument,	0, 'k'  },
349 	{"sec",		required_argument,	0, 's'  },
350 	{"auth",	required_argument,	0, 'a'  },
351 	{"create-ibss",	required_argument,	0, 'c'  },
352 	{"timeout",	required_argument,	0, 'T'  },
353 	{"all-links",	no_argument,		0, 'a'  },
354 	{"temporary",	no_argument,		0, 't'  },
355 	{"root-dir",	required_argument,	0, 'R'  },
356 	{"persistent",	no_argument,		0, 'P'  },
357 	{"file",	required_argument,	0, 'f'  },
358 	{ 0, 0, 0, 0 }
359 };
360 static const struct option showeth_lopts[] = {
361 	{"parsable",	no_argument,		0, 'p'	},
362 	{"parseable",	no_argument,		0, 'p'	},
363 	{"extended",	no_argument,		0, 'x'	},
364 	{"output",	required_argument,	0, 'o'	},
365 	{ 0, 0, 0, 0 }
366 };
367 
368 static const struct option vnic_lopts[] = {
369 	{"temporary",	no_argument,		0, 't'	},
370 	{"root-dir",	required_argument,	0, 'R'	},
371 	{"dev",		required_argument,	0, 'd'	},
372 	{"mac-address",	required_argument,	0, 'm'	},
373 	{"cpus",	required_argument,	0, 'c'	},
374 	{"bw-limit",	required_argument,	0, 'b'	},
375 	{"slot",	required_argument,	0, 'n'	},
376 	{"mac-prefix",	required_argument,	0, 'r'	},
377 	{ 0, 0, 0, 0 }
378 };
379 
380 static const struct option etherstub_lopts[] = {
381 	{"temporary",	no_argument,		0, 't'	},
382 	{"root-dir",	required_argument,	0, 'R'	},
383 	{ 0, 0, 0, 0 }
384 };
385 
386 static const struct option usage_opts[] = {
387 	{"file",	required_argument,	0, 'f'	},
388 	{"format",	required_argument,	0, 'F'	},
389 	{"start",	required_argument,	0, 's'	},
390 	{"stop",	required_argument,	0, 'e'	},
391 	{ 0, 0, 0, 0 }
392 };
393 
394 static const struct option simnet_lopts[] = {
395 	{"temporary",	no_argument,		0, 't'	},
396 	{"root-dir",	required_argument,	0, 'R'	},
397 	{"media",	required_argument,	0, 'm'	},
398 	{"peer",	required_argument,	0, 'p'	},
399 	{ 0, 0, 0, 0 }
400 };
401 
402 /*
403  * structures for 'dladm show-ether'
404  */
405 static const char *ptype[] = {LEI_ATTR_NAMES};
406 
407 typedef struct ether_fields_buf_s
408 {
409 	char	eth_link[15];
410 	char	eth_ptype[8];
411 	char	eth_state[8];
412 	char	eth_autoneg[5];
413 	char	eth_spdx[31];
414 	char	eth_pause[6];
415 	char	eth_rem_fault[16];
416 } ether_fields_buf_t;
417 
418 static ofmt_field_t ether_fields[] = {
419 /* name,	field width,	offset	    callback */
420 { "LINK",	16,
421 	offsetof(ether_fields_buf_t, eth_link), print_default_cb},
422 { "PTYPE",	9,
423 	offsetof(ether_fields_buf_t, eth_ptype), print_default_cb},
424 { "STATE",	9,
425 	offsetof(ether_fields_buf_t, eth_state),
426 	print_default_cb},
427 { "AUTO",	6,
428 	offsetof(ether_fields_buf_t, eth_autoneg), print_default_cb},
429 { "SPEED-DUPLEX", 32,
430 	offsetof(ether_fields_buf_t, eth_spdx), print_default_cb},
431 { "PAUSE",	7,
432 	offsetof(ether_fields_buf_t, eth_pause), print_default_cb},
433 { "REM_FAULT",	17,
434 	offsetof(ether_fields_buf_t, eth_rem_fault), print_default_cb},
435 {NULL,		0,
436 	0, 	NULL}}
437 ;
438 
439 typedef struct print_ether_state {
440 	const char	*es_link;
441 	boolean_t	es_parsable;
442 	boolean_t	es_header;
443 	boolean_t	es_extended;
444 	ofmt_handle_t	es_ofmt;
445 } print_ether_state_t;
446 
447 /*
448  * structures for 'dladm show-link -s' (print statistics)
449  */
450 typedef enum {
451 	LINK_S_LINK,
452 	LINK_S_IPKTS,
453 	LINK_S_RBYTES,
454 	LINK_S_IERRORS,
455 	LINK_S_OPKTS,
456 	LINK_S_OBYTES,
457 	LINK_S_OERRORS
458 } link_s_field_index_t;
459 
460 static ofmt_field_t link_s_fields[] = {
461 /* name,	field width,	index,		callback	*/
462 { "LINK",	15,		LINK_S_LINK,	print_link_stats_cb},
463 { "IPACKETS",	10,		LINK_S_IPKTS,	print_link_stats_cb},
464 { "RBYTES",	8,		LINK_S_RBYTES,	print_link_stats_cb},
465 { "IERRORS",	10,		LINK_S_IERRORS,	print_link_stats_cb},
466 { "OPACKETS",	12,		LINK_S_OPKTS,	print_link_stats_cb},
467 { "OBYTES",	12,		LINK_S_OBYTES,	print_link_stats_cb},
468 { "OERRORS",	8,		LINK_S_OERRORS,	print_link_stats_cb}}
469 ;
470 
471 typedef struct link_args_s {
472 	char		*link_s_link;
473 	pktsum_t	*link_s_psum;
474 } link_args_t;
475 
476 /*
477  * buffer used by print functions for show-{link,phys,vlan} commands.
478  */
479 typedef struct link_fields_buf_s {
480 	char link_name[MAXLINKNAMELEN];
481 	char link_class[DLADM_STRSIZE];
482 	char link_mtu[11];
483 	char link_state[DLADM_STRSIZE];
484 	char link_over[MAXLINKNAMELEN];
485 	char link_phys_state[DLADM_STRSIZE];
486 	char link_phys_media[DLADM_STRSIZE];
487 	char link_phys_speed[DLADM_STRSIZE];
488 	char link_phys_duplex[DLPI_LINKNAME_MAX];
489 	char link_phys_device[DLPI_LINKNAME_MAX];
490 	char link_flags[6];
491 	char link_vlan_vid[6];
492 } link_fields_buf_t;
493 
494 /*
495  * structures for 'dladm show-link'
496  */
497 static ofmt_field_t link_fields[] = {
498 /* name,	field width,	index,	callback */
499 { "LINK",	12,
500 	offsetof(link_fields_buf_t, link_name), print_default_cb},
501 { "CLASS",	9,
502 	offsetof(link_fields_buf_t, link_class), print_default_cb},
503 { "MTU",	7,
504 	offsetof(link_fields_buf_t, link_mtu), print_default_cb},
505 { "STATE",	9,
506 	offsetof(link_fields_buf_t, link_state), print_default_cb},
507 { "OVER",	DLPI_LINKNAME_MAX,
508 	offsetof(link_fields_buf_t, link_over), print_default_cb},
509 { NULL,		0, 0, NULL}}
510 ;
511 
512 /*
513  * structures for 'dladm show-aggr'
514  */
515 typedef struct laggr_fields_buf_s {
516 	char laggr_name[DLPI_LINKNAME_MAX];
517 	char laggr_policy[9];
518 	char laggr_addrpolicy[ETHERADDRL * 3 + 3];
519 	char laggr_lacpactivity[14];
520 	char laggr_lacptimer[DLADM_STRSIZE];
521 	char laggr_flags[7];
522 } laggr_fields_buf_t;
523 
524 typedef struct laggr_args_s {
525 	int			laggr_lport; /* -1 indicates the aggr itself */
526 	const char 		*laggr_link;
527 	dladm_aggr_grp_attr_t	*laggr_ginfop;
528 	dladm_status_t		*laggr_status;
529 	pktsum_t		*laggr_pktsumtot; /* -s only */
530 	pktsum_t		*laggr_diffstats; /* -s only */
531 	boolean_t		laggr_parsable;
532 } laggr_args_t;
533 
534 static ofmt_field_t laggr_fields[] = {
535 /* name,	field width,	offset,	callback */
536 { "LINK",	16,
537 	offsetof(laggr_fields_buf_t, laggr_name), print_default_cb},
538 { "POLICY",	9,
539 	offsetof(laggr_fields_buf_t, laggr_policy), print_default_cb},
540 { "ADDRPOLICY",	ETHERADDRL * 3 + 3,
541 	offsetof(laggr_fields_buf_t, laggr_addrpolicy), print_default_cb},
542 { "LACPACTIVITY", 14,
543 	offsetof(laggr_fields_buf_t, laggr_lacpactivity), print_default_cb},
544 { "LACPTIMER",	12,
545 	offsetof(laggr_fields_buf_t, laggr_lacptimer), print_default_cb},
546 { "FLAGS",	8,
547 	offsetof(laggr_fields_buf_t, laggr_flags), print_default_cb},
548 { NULL,		0, 0, NULL}}
549 ;
550 
551 /*
552  * structures for 'dladm show-aggr -x'.
553  */
554 typedef enum {
555 	AGGR_X_LINK,
556 	AGGR_X_PORT,
557 	AGGR_X_SPEED,
558 	AGGR_X_DUPLEX,
559 	AGGR_X_STATE,
560 	AGGR_X_ADDRESS,
561 	AGGR_X_PORTSTATE
562 } aggr_x_field_index_t;
563 
564 static ofmt_field_t aggr_x_fields[] = {
565 /* name,	field width,	index		callback */
566 { "LINK",	12,	AGGR_X_LINK,		print_xaggr_cb},
567 { "PORT",	15,	AGGR_X_PORT,		print_xaggr_cb},
568 { "SPEED",	5,	AGGR_X_SPEED,		print_xaggr_cb},
569 { "DUPLEX",	10,	AGGR_X_DUPLEX,		print_xaggr_cb},
570 { "STATE",	10,	AGGR_X_STATE,		print_xaggr_cb},
571 { "ADDRESS",	19,	AGGR_X_ADDRESS,		print_xaggr_cb},
572 { "PORTSTATE",	16,	AGGR_X_PORTSTATE,	print_xaggr_cb},
573 { NULL,		0,	0,			NULL}}
574 ;
575 
576 /*
577  * structures for 'dladm show-aggr -s'.
578  */
579 typedef enum {
580 	AGGR_S_LINK,
581 	AGGR_S_PORT,
582 	AGGR_S_IPKTS,
583 	AGGR_S_RBYTES,
584 	AGGR_S_OPKTS,
585 	AGGR_S_OBYTES,
586 	AGGR_S_IPKTDIST,
587 	AGGR_S_OPKTDIST
588 } aggr_s_field_index_t;
589 
590 static ofmt_field_t aggr_s_fields[] = {
591 { "LINK",		12,	AGGR_S_LINK, print_aggr_stats_cb},
592 { "PORT",		10,	AGGR_S_PORT, print_aggr_stats_cb},
593 { "IPACKETS",		8,	AGGR_S_IPKTS, print_aggr_stats_cb},
594 { "RBYTES",		8,	AGGR_S_RBYTES, print_aggr_stats_cb},
595 { "OPACKETS",		8,	AGGR_S_OPKTS, print_aggr_stats_cb},
596 { "OBYTES",		8,	AGGR_S_OBYTES, print_aggr_stats_cb},
597 { "IPKTDIST",		9,	AGGR_S_IPKTDIST, print_aggr_stats_cb},
598 { "OPKTDIST",		15,	AGGR_S_OPKTDIST, print_aggr_stats_cb},
599 { NULL,			0,	0,		NULL}}
600 ;
601 
602 /*
603  * structures for 'dladm show-aggr -L'.
604  */
605 typedef enum {
606 	AGGR_L_LINK,
607 	AGGR_L_PORT,
608 	AGGR_L_AGGREGATABLE,
609 	AGGR_L_SYNC,
610 	AGGR_L_COLL,
611 	AGGR_L_DIST,
612 	AGGR_L_DEFAULTED,
613 	AGGR_L_EXPIRED
614 } aggr_l_field_index_t;
615 
616 static ofmt_field_t aggr_l_fields[] = {
617 /* name,		field width,	index */
618 { "LINK",		12,	AGGR_L_LINK,		print_lacp_cb},
619 { "PORT",		13,	AGGR_L_PORT,		print_lacp_cb},
620 { "AGGREGATABLE",	13,	AGGR_L_AGGREGATABLE,	print_lacp_cb},
621 { "SYNC",		5,	AGGR_L_SYNC,		print_lacp_cb},
622 { "COLL",		5,	AGGR_L_COLL,		print_lacp_cb},
623 { "DIST",		5,	AGGR_L_DIST,		print_lacp_cb},
624 { "DEFAULTED",		10,	AGGR_L_DEFAULTED,	print_lacp_cb},
625 { "EXPIRED",		15,	AGGR_L_EXPIRED,		print_lacp_cb},
626 { NULL,			0,	0,			NULL}}
627 ;
628 
629 /*
630  * structures for 'dladm show-phys'
631  */
632 
633 static ofmt_field_t phys_fields[] = {
634 /* name,	field width,	offset */
635 { "LINK",	13,
636 	offsetof(link_fields_buf_t, link_name), print_default_cb},
637 { "MEDIA",	21,
638 	offsetof(link_fields_buf_t, link_phys_media), print_default_cb},
639 { "STATE",	11,
640 	offsetof(link_fields_buf_t, link_phys_state), print_default_cb},
641 { "SPEED",	7,
642 	offsetof(link_fields_buf_t, link_phys_speed), print_default_cb},
643 { "DUPLEX",	10,
644 	offsetof(link_fields_buf_t, link_phys_duplex), print_default_cb},
645 { "DEVICE",	13,
646 	offsetof(link_fields_buf_t, link_phys_device), print_default_cb},
647 { "FLAGS",	7,
648 	offsetof(link_fields_buf_t, link_flags), print_default_cb},
649 { NULL,		0, NULL, 0}}
650 ;
651 
652 /*
653  * structures for 'dladm show-phys -m'
654  */
655 
656 typedef enum {
657 	PHYS_M_LINK,
658 	PHYS_M_SLOT,
659 	PHYS_M_ADDRESS,
660 	PHYS_M_INUSE,
661 	PHYS_M_CLIENT
662 } phys_m_field_index_t;
663 
664 static ofmt_field_t phys_m_fields[] = {
665 /* name,	field width,	offset */
666 { "LINK",	13,	PHYS_M_LINK,	print_phys_one_mac_cb},
667 { "SLOT",	9,	PHYS_M_SLOT,	print_phys_one_mac_cb},
668 { "ADDRESS",	19,	PHYS_M_ADDRESS,	print_phys_one_mac_cb},
669 { "INUSE",	5,	PHYS_M_INUSE,	print_phys_one_mac_cb},
670 { "CLIENT",	13,	PHYS_M_CLIENT,	print_phys_one_mac_cb},
671 { NULL,		0,	0,		NULL}}
672 ;
673 
674 /*
675  * structures for 'dladm show-phys -H'
676  */
677 
678 typedef enum {
679 	PHYS_H_LINK,
680 	PHYS_H_GROUP,
681 	PHYS_H_GRPTYPE,
682 	PHYS_H_RINGS,
683 	PHYS_H_CLIENTS
684 } phys_h_field_index_t;
685 
686 static ofmt_field_t phys_h_fields[] = {
687 { "LINK",	13,	PHYS_H_LINK,	print_phys_one_hwgrp_cb},
688 { "GROUP",	9,	PHYS_H_GROUP,	print_phys_one_hwgrp_cb},
689 { "GROUPTYPE",	7,	PHYS_H_GRPTYPE,	print_phys_one_hwgrp_cb},
690 { "RINGS",	17,	PHYS_H_RINGS,	print_phys_one_hwgrp_cb},
691 { "CLIENTS",	21,	PHYS_H_CLIENTS,	print_phys_one_hwgrp_cb},
692 { NULL,		0,	0,		NULL}}
693 ;
694 
695 /*
696  * structures for 'dladm show-vlan'
697  */
698 static ofmt_field_t vlan_fields[] = {
699 { "LINK",	16,
700 	offsetof(link_fields_buf_t, link_name), print_default_cb},
701 { "VID",	9,
702 	offsetof(link_fields_buf_t, link_vlan_vid), print_default_cb},
703 { "OVER",	13,
704 	offsetof(link_fields_buf_t, link_over), print_default_cb},
705 { "FLAGS",	7,
706 	offsetof(link_fields_buf_t, link_flags), print_default_cb},
707 { NULL,		0, 0, NULL}}
708 ;
709 
710 /*
711  * structures common to 'dladm scan-wifi' and 'dladm show-wifi'
712  * callback will be determined in parse_wifi_fields.
713  */
714 static ofmt_field_t wifi_common_fields[] = {
715 { "LINK",	11, 0,				NULL},
716 { "ESSID",	20, DLADM_WLAN_ATTR_ESSID,	NULL},
717 { "BSSID",	18, DLADM_WLAN_ATTR_BSSID,	NULL},
718 { "IBSSID",	18, DLADM_WLAN_ATTR_BSSID,	NULL},
719 { "MODE",	7,  DLADM_WLAN_ATTR_MODE,	NULL},
720 { "SPEED",	7,  DLADM_WLAN_ATTR_SPEED,	NULL},
721 { "BSSTYPE",	9,  DLADM_WLAN_ATTR_BSSTYPE,	NULL},
722 { "SEC",	7,  DLADM_WLAN_ATTR_SECMODE,	NULL},
723 { "STRENGTH",	11, DLADM_WLAN_ATTR_STRENGTH,	NULL},
724 { NULL,		0,  0,				NULL}};
725 
726 /*
727  * the 'show-wifi' command supports all the fields in wifi_common_fields
728  * plus the AUTH and STATUS fields.
729  */
730 static ofmt_field_t wifi_show_fields[A_CNT(wifi_common_fields) + 2] = {
731 { "AUTH",	9,  DLADM_WLAN_ATTR_AUTH,	NULL},
732 { "STATUS",	18, DLADM_WLAN_LINKATTR_STATUS,	print_wifi_status_cb},
733 /* copy wifi_common_fields here */
734 };
735 
736 static char *all_scan_wifi_fields =
737 	"link,essid,bssid,sec,strength,mode,speed,bsstype";
738 static char *all_show_wifi_fields =
739 	"link,status,essid,sec,strength,mode,speed,auth,bssid,bsstype";
740 static char *def_scan_wifi_fields =
741 	"link,essid,bssid,sec,strength,mode,speed";
742 static char *def_show_wifi_fields =
743 	"link,status,essid,sec,strength,mode,speed";
744 
745 /*
746  * structures for 'dladm show-linkprop'
747  */
748 typedef enum {
749 	LINKPROP_LINK,
750 	LINKPROP_PROPERTY,
751 	LINKPROP_PERM,
752 	LINKPROP_VALUE,
753 	LINKPROP_DEFAULT,
754 	LINKPROP_POSSIBLE
755 } linkprop_field_index_t;
756 
757 static ofmt_field_t linkprop_fields[] = {
758 /* name,	field width,  index */
759 { "LINK",	13,	LINKPROP_LINK,		print_linkprop_cb},
760 { "PROPERTY",	16,	LINKPROP_PROPERTY,	print_linkprop_cb},
761 { "PERM",	5,	LINKPROP_PERM,		print_linkprop_cb},
762 { "VALUE",	15,	LINKPROP_VALUE,		print_linkprop_cb},
763 { "DEFAULT",	15,	LINKPROP_DEFAULT,	print_linkprop_cb},
764 { "POSSIBLE",	21,	LINKPROP_POSSIBLE,	print_linkprop_cb},
765 { NULL,		0,	0,			NULL}}
766 ;
767 
768 #define	MAX_PROP_LINE		512
769 
770 typedef struct show_linkprop_state {
771 	char			ls_link[MAXLINKNAMELEN];
772 	char			*ls_line;
773 	char			**ls_propvals;
774 	dladm_arg_list_t	*ls_proplist;
775 	boolean_t		ls_parsable;
776 	boolean_t		ls_persist;
777 	boolean_t		ls_header;
778 	dladm_status_t		ls_status;
779 	dladm_status_t		ls_retstatus;
780 	ofmt_handle_t		ls_ofmt;
781 } show_linkprop_state_t;
782 
783 typedef struct set_linkprop_state {
784 	const char		*ls_name;
785 	boolean_t		ls_reset;
786 	boolean_t		ls_temp;
787 	dladm_status_t		ls_status;
788 } set_linkprop_state_t;
789 
790 typedef struct linkprop_args_s {
791 	show_linkprop_state_t	*ls_state;
792 	char			*ls_propname;
793 	datalink_id_t		ls_linkid;
794 } linkprop_args_t;
795 
796 /*
797  * structures for 'dladm show-secobj'
798  */
799 typedef struct secobj_fields_buf_s {
800 	char			ss_obj_name[DLADM_SECOBJ_VAL_MAX];
801 	char			ss_class[20];
802 	char			ss_val[30];
803 } secobj_fields_buf_t;
804 
805 static ofmt_field_t secobj_fields[] = {
806 { "OBJECT",	21,
807 	offsetof(secobj_fields_buf_t, ss_obj_name), print_default_cb},
808 { "CLASS",	21,
809 	offsetof(secobj_fields_buf_t, ss_class), print_default_cb},
810 { "VALUE",	31,
811 	offsetof(secobj_fields_buf_t, ss_val), print_default_cb},
812 { NULL,		0, 0, NULL}}
813 ;
814 
815 /*
816  * structures for 'dladm show-vnic'
817  */
818 typedef struct vnic_fields_buf_s
819 {
820 	char vnic_link[DLPI_LINKNAME_MAX];
821 	char vnic_over[DLPI_LINKNAME_MAX];
822 	char vnic_speed[6];
823 	char vnic_macaddr[18];
824 	char vnic_macaddrtype[19];
825 	char vnic_vid[6];
826 } vnic_fields_buf_t;
827 
828 static ofmt_field_t vnic_fields[] = {
829 { "LINK",		13,
830 	offsetof(vnic_fields_buf_t, vnic_link),	print_default_cb},
831 { "OVER",		13,
832 	offsetof(vnic_fields_buf_t, vnic_over),	print_default_cb},
833 { "SPEED",		7,
834 	offsetof(vnic_fields_buf_t, vnic_speed), print_default_cb},
835 { "MACADDRESS",		18,
836 	offsetof(vnic_fields_buf_t, vnic_macaddr), print_default_cb},
837 { "MACADDRTYPE",	20,
838 	offsetof(vnic_fields_buf_t, vnic_macaddrtype), print_default_cb},
839 { "VID",		7,
840 	offsetof(vnic_fields_buf_t, vnic_vid), print_default_cb},
841 { NULL,			0, 0, NULL}}
842 ;
843 
844 /*
845  * structures for 'dladm show-simnet'
846  */
847 typedef struct simnet_fields_buf_s
848 {
849 	char simnet_name[DLPI_LINKNAME_MAX];
850 	char simnet_media[DLADM_STRSIZE];
851 	char simnet_macaddr[18];
852 	char simnet_otherlink[DLPI_LINKNAME_MAX];
853 } simnet_fields_buf_t;
854 
855 static ofmt_field_t simnet_fields[] = {
856 { "LINK",		12,
857 	offsetof(simnet_fields_buf_t, simnet_name), print_default_cb},
858 { "MEDIA",		20,
859 	offsetof(simnet_fields_buf_t, simnet_media), print_default_cb},
860 { "MACADDRESS",		18,
861 	offsetof(simnet_fields_buf_t, simnet_macaddr), print_default_cb},
862 { "OTHERLINK",		12,
863 	offsetof(simnet_fields_buf_t, simnet_otherlink), print_default_cb},
864 { NULL,			0, 0, NULL}}
865 ;
866 
867 /*
868  * structures for 'dladm show-usage'
869  */
870 
871 typedef struct  usage_fields_buf_s {
872 	char	usage_link[12];
873 	char	usage_duration[10];
874 	char	usage_ipackets[9];
875 	char	usage_rbytes[10];
876 	char	usage_opackets[9];
877 	char	usage_obytes[10];
878 	char	usage_bandwidth[14];
879 } usage_fields_buf_t;
880 
881 static ofmt_field_t usage_fields[] = {
882 { "LINK",	13,
883 	offsetof(usage_fields_buf_t, usage_link), print_default_cb},
884 { "DURATION",	11,
885 	offsetof(usage_fields_buf_t, usage_duration), print_default_cb},
886 { "IPACKETS",	10,
887 	offsetof(usage_fields_buf_t, usage_ipackets), print_default_cb},
888 { "RBYTES",	11,
889 	offsetof(usage_fields_buf_t, usage_rbytes), print_default_cb},
890 { "OPACKETS",	10,
891 	offsetof(usage_fields_buf_t, usage_opackets), print_default_cb},
892 { "OBYTES",	11,
893 	offsetof(usage_fields_buf_t, usage_obytes), print_default_cb},
894 { "BANDWIDTH",	15,
895 	offsetof(usage_fields_buf_t, usage_bandwidth), print_default_cb},
896 { NULL,		0, 0, NULL}}
897 ;
898 
899 
900 /*
901  * structures for 'dladm show-usage link'
902  */
903 
904 typedef struct  usage_l_fields_buf_s {
905 	char	usage_l_link[12];
906 	char	usage_l_stime[13];
907 	char	usage_l_etime[13];
908 	char	usage_l_rbytes[8];
909 	char	usage_l_obytes[8];
910 	char	usage_l_bandwidth[14];
911 } usage_l_fields_buf_t;
912 
913 static ofmt_field_t usage_l_fields[] = {
914 /* name,	field width,	offset */
915 { "LINK",	13,
916 	offsetof(usage_l_fields_buf_t, usage_l_link), print_default_cb},
917 { "START",	14,
918 	offsetof(usage_l_fields_buf_t, usage_l_stime), print_default_cb},
919 { "END",	14,
920 	offsetof(usage_l_fields_buf_t, usage_l_etime), print_default_cb},
921 { "RBYTES",	9,
922 	offsetof(usage_l_fields_buf_t, usage_l_rbytes), print_default_cb},
923 { "OBYTES",	9,
924 	offsetof(usage_l_fields_buf_t, usage_l_obytes), print_default_cb},
925 { "BANDWIDTH",	15,
926 	offsetof(usage_l_fields_buf_t, usage_l_bandwidth), print_default_cb},
927 { NULL,		0, 0, NULL}}
928 ;
929 
930 static char *progname;
931 static sig_atomic_t signalled;
932 
933 /*
934  * Handle to libdladm.  Opened in main() before the sub-command
935  * specific function is called.
936  */
937 static dladm_handle_t handle = NULL;
938 
939 #define	DLADM_ETHERSTUB_NAME	"etherstub"
940 #define	DLADM_IS_ETHERSTUB(id)	(id == DATALINK_INVALID_LINKID)
941 
942 static void
943 usage(void)
944 {
945 	int	i;
946 	cmd_t	*cmdp;
947 	(void) fprintf(stderr, gettext("usage:  dladm <subcommand> <args> ..."
948 	    "\n"));
949 	for (i = 0; i < sizeof (cmds) / sizeof (cmds[0]); i++) {
950 		cmdp = &cmds[i];
951 		if (cmdp->c_usage != NULL)
952 			(void) fprintf(stderr, "%s\n", gettext(cmdp->c_usage));
953 	}
954 
955 	/* close dladm handle if it was opened */
956 	if (handle != NULL)
957 		dladm_close(handle);
958 
959 	exit(1);
960 }
961 
962 int
963 main(int argc, char *argv[])
964 {
965 	int	i;
966 	cmd_t	*cmdp;
967 	dladm_status_t status;
968 
969 	(void) setlocale(LC_ALL, "");
970 #if !defined(TEXT_DOMAIN)
971 #define	TEXT_DOMAIN "SYS_TEST"
972 #endif
973 	(void) textdomain(TEXT_DOMAIN);
974 
975 	progname = argv[0];
976 
977 	if (argc < 2)
978 		usage();
979 
980 	for (i = 0; i < sizeof (cmds) / sizeof (cmds[0]); i++) {
981 		cmdp = &cmds[i];
982 		if (strcmp(argv[1], cmdp->c_name) == 0) {
983 			/* Open the libdladm handle */
984 			if ((status = dladm_open(&handle)) != DLADM_STATUS_OK) {
985 				die_dlerr(status,
986 				    "could not open /dev/dld");
987 			}
988 
989 			cmdp->c_fn(argc - 1, &argv[1], cmdp->c_usage);
990 
991 			dladm_close(handle);
992 			exit(0);
993 		}
994 	}
995 
996 	(void) fprintf(stderr, gettext("%s: unknown subcommand '%s'\n"),
997 	    progname, argv[1]);
998 	usage();
999 
1000 	return (0);
1001 }
1002 
1003 /*ARGSUSED*/
1004 static int
1005 show_usage_date(dladm_usage_t *usage, void *arg)
1006 {
1007 	show_usage_state_t	*state = (show_usage_state_t *)arg;
1008 	time_t			stime;
1009 	char			timebuf[20];
1010 	dladm_status_t		status;
1011 	uint32_t		flags;
1012 
1013 	/*
1014 	 * Only show usage information for existing links unless '-a'
1015 	 * is specified.
1016 	 */
1017 	if (!state->us_showall) {
1018 		if ((status = dladm_name2info(handle, usage->du_name,
1019 		    NULL, &flags, NULL, NULL)) != DLADM_STATUS_OK) {
1020 			return (status);
1021 		}
1022 		if ((flags & DLADM_OPT_ACTIVE) == 0)
1023 			return (DLADM_STATUS_LINKINVAL);
1024 	}
1025 
1026 	stime = usage->du_stime;
1027 	(void) strftime(timebuf, sizeof (timebuf), "%m/%d/%Y",
1028 	    localtime(&stime));
1029 	(void) printf("%s\n", timebuf);
1030 
1031 	return (DLADM_STATUS_OK);
1032 }
1033 
1034 static int
1035 show_usage_time(dladm_usage_t *usage, void *arg)
1036 {
1037 	show_usage_state_t	*state = (show_usage_state_t *)arg;
1038 	char			buf[DLADM_STRSIZE];
1039 	usage_l_fields_buf_t 	ubuf;
1040 	time_t			time;
1041 	double			bw;
1042 	dladm_status_t		status;
1043 	uint32_t		flags;
1044 
1045 	/*
1046 	 * Only show usage information for existing links unless '-a'
1047 	 * is specified.
1048 	 */
1049 	if (!state->us_showall) {
1050 		if ((status = dladm_name2info(handle, usage->du_name,
1051 		    NULL, &flags, NULL, NULL)) != DLADM_STATUS_OK) {
1052 			return (status);
1053 		}
1054 		if ((flags & DLADM_OPT_ACTIVE) == 0)
1055 			return (DLADM_STATUS_LINKINVAL);
1056 	}
1057 
1058 	if (state->us_plot) {
1059 		if (!state->us_printheader) {
1060 			if (state->us_first) {
1061 				(void) printf("# Time");
1062 				state->us_first = B_FALSE;
1063 			}
1064 			(void) printf(" %s", usage->du_name);
1065 			if (usage->du_last) {
1066 				(void) printf("\n");
1067 				state->us_first = B_TRUE;
1068 				state->us_printheader = B_TRUE;
1069 			}
1070 		} else {
1071 			if (state->us_first) {
1072 				time = usage->du_etime;
1073 				(void) strftime(buf, sizeof (buf), "%T",
1074 				    localtime(&time));
1075 				state->us_first = B_FALSE;
1076 				(void) printf("%s", buf);
1077 			}
1078 			bw = (double)usage->du_bandwidth/1000;
1079 			(void) printf(" %.2f", bw);
1080 			if (usage->du_last) {
1081 				(void) printf("\n");
1082 				state->us_first = B_TRUE;
1083 			}
1084 		}
1085 		return (DLADM_STATUS_OK);
1086 	}
1087 
1088 	bzero(&ubuf, sizeof (ubuf));
1089 
1090 	(void) snprintf(ubuf.usage_l_link, sizeof (ubuf.usage_l_link), "%s",
1091 	    usage->du_name);
1092 	time = usage->du_stime;
1093 	(void) strftime(buf, sizeof (buf), "%T", localtime(&time));
1094 	(void) snprintf(ubuf.usage_l_stime, sizeof (ubuf.usage_l_stime), "%s",
1095 	    buf);
1096 	time = usage->du_etime;
1097 	(void) strftime(buf, sizeof (buf), "%T", localtime(&time));
1098 	(void) snprintf(ubuf.usage_l_etime, sizeof (ubuf.usage_l_etime), "%s",
1099 	    buf);
1100 	(void) snprintf(ubuf.usage_l_rbytes, sizeof (ubuf.usage_l_rbytes),
1101 	    "%llu", usage->du_rbytes);
1102 	(void) snprintf(ubuf.usage_l_obytes, sizeof (ubuf.usage_l_obytes),
1103 	    "%llu", usage->du_obytes);
1104 	(void) snprintf(ubuf.usage_l_bandwidth, sizeof (ubuf.usage_l_bandwidth),
1105 	    "%s Mbps", dladm_bw2str(usage->du_bandwidth, buf));
1106 
1107 	ofmt_print(state->us_ofmt, &ubuf);
1108 	return (DLADM_STATUS_OK);
1109 }
1110 
1111 static int
1112 show_usage_res(dladm_usage_t *usage, void *arg)
1113 {
1114 	show_usage_state_t	*state = (show_usage_state_t *)arg;
1115 	char			buf[DLADM_STRSIZE];
1116 	usage_fields_buf_t	ubuf;
1117 	dladm_status_t		status;
1118 	uint32_t		flags;
1119 
1120 	/*
1121 	 * Only show usage information for existing links unless '-a'
1122 	 * is specified.
1123 	 */
1124 	if (!state->us_showall) {
1125 		if ((status = dladm_name2info(handle, usage->du_name,
1126 		    NULL, &flags, NULL, NULL)) != DLADM_STATUS_OK) {
1127 			return (status);
1128 		}
1129 		if ((flags & DLADM_OPT_ACTIVE) == 0)
1130 			return (DLADM_STATUS_LINKINVAL);
1131 	}
1132 
1133 	bzero(&ubuf, sizeof (ubuf));
1134 
1135 	(void) snprintf(ubuf.usage_link, sizeof (ubuf.usage_link), "%s",
1136 	    usage->du_name);
1137 	(void) snprintf(ubuf.usage_duration, sizeof (ubuf.usage_duration),
1138 	    "%llu", usage->du_duration);
1139 	(void) snprintf(ubuf.usage_ipackets, sizeof (ubuf.usage_ipackets),
1140 	    "%llu", usage->du_ipackets);
1141 	(void) snprintf(ubuf.usage_rbytes, sizeof (ubuf.usage_rbytes),
1142 	    "%llu", usage->du_rbytes);
1143 	(void) snprintf(ubuf.usage_opackets, sizeof (ubuf.usage_opackets),
1144 	    "%llu", usage->du_opackets);
1145 	(void) snprintf(ubuf.usage_obytes, sizeof (ubuf.usage_obytes),
1146 	    "%llu", usage->du_obytes);
1147 	(void) snprintf(ubuf.usage_bandwidth, sizeof (ubuf.usage_bandwidth),
1148 	    "%s Mbps", dladm_bw2str(usage->du_bandwidth, buf));
1149 
1150 	ofmt_print(state->us_ofmt, &ubuf);
1151 
1152 	return (DLADM_STATUS_OK);
1153 }
1154 
1155 static boolean_t
1156 valid_formatspec(char *formatspec_str)
1157 {
1158 	if (strcmp(formatspec_str, "gnuplot") == 0)
1159 		return (B_TRUE);
1160 	return (B_FALSE);
1161 
1162 }
1163 
1164 /*ARGSUSED*/
1165 static void
1166 do_show_usage(int argc, char *argv[], const char *use)
1167 {
1168 	char			*file = NULL;
1169 	int			opt;
1170 	dladm_status_t		status;
1171 	boolean_t		d_arg = B_FALSE;
1172 	char			*stime = NULL;
1173 	char			*etime = NULL;
1174 	char			*resource = NULL;
1175 	show_usage_state_t	state;
1176 	boolean_t		o_arg = B_FALSE;
1177 	boolean_t		F_arg = B_FALSE;
1178 	char			*fields_str = NULL;
1179 	char			*formatspec_str = NULL;
1180 	char			*all_l_fields =
1181 	    "link,start,end,rbytes,obytes,bandwidth";
1182 	ofmt_handle_t		ofmt;
1183 	ofmt_status_t		oferr;
1184 	uint_t			ofmtflags = 0;
1185 
1186 	bzero(&state, sizeof (show_usage_state_t));
1187 	state.us_parsable = B_FALSE;
1188 	state.us_printheader = B_FALSE;
1189 	state.us_plot = B_FALSE;
1190 	state.us_first = B_TRUE;
1191 
1192 	while ((opt = getopt_long(argc, argv, "das:e:o:f:F:",
1193 	    usage_opts, NULL)) != -1) {
1194 		switch (opt) {
1195 		case 'd':
1196 			d_arg = B_TRUE;
1197 			break;
1198 		case 'a':
1199 			state.us_showall = B_TRUE;
1200 			break;
1201 		case 'f':
1202 			file = optarg;
1203 			break;
1204 		case 's':
1205 			stime = optarg;
1206 			break;
1207 		case 'e':
1208 			etime = optarg;
1209 			break;
1210 		case 'o':
1211 			o_arg = B_TRUE;
1212 			fields_str = optarg;
1213 			break;
1214 		case 'F':
1215 			state.us_plot = F_arg = B_TRUE;
1216 			formatspec_str = optarg;
1217 			break;
1218 		default:
1219 			die_opterr(optopt, opt, use);
1220 			break;
1221 		}
1222 	}
1223 
1224 	if (file == NULL)
1225 		die("show-usage requires a file");
1226 
1227 	if (optind == (argc-1)) {
1228 		uint32_t 	flags;
1229 
1230 		resource = argv[optind];
1231 		if (!state.us_showall &&
1232 		    (((status = dladm_name2info(handle, resource, NULL, &flags,
1233 		    NULL, NULL)) != DLADM_STATUS_OK) ||
1234 		    ((flags & DLADM_OPT_ACTIVE) == 0))) {
1235 			die("invalid link: '%s'", resource);
1236 		}
1237 	}
1238 
1239 	if (F_arg && d_arg)
1240 		die("incompatible -d and -F options");
1241 
1242 	if (F_arg && valid_formatspec(formatspec_str) == B_FALSE)
1243 		die("Format specifier %s not supported", formatspec_str);
1244 
1245 	if (state.us_parsable)
1246 		ofmtflags |= OFMT_PARSABLE;
1247 
1248 	if (resource == NULL && stime == NULL && etime == NULL) {
1249 		oferr = ofmt_open(fields_str, usage_fields, ofmtflags, 0,
1250 		    &ofmt);
1251 	} else {
1252 		if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0))
1253 			fields_str = all_l_fields;
1254 		oferr = ofmt_open(fields_str, usage_l_fields, ofmtflags, 0,
1255 		    &ofmt);
1256 
1257 	}
1258 	dladm_ofmt_check(oferr, state.us_parsable, ofmt);
1259 	state.us_ofmt = ofmt;
1260 
1261 	if (d_arg) {
1262 		/* Print log dates */
1263 		status = dladm_usage_dates(show_usage_date,
1264 		    DLADM_LOGTYPE_LINK, file, resource, &state);
1265 	} else if (resource == NULL && stime == NULL && etime == NULL &&
1266 	    !F_arg) {
1267 		/* Print summary */
1268 		status = dladm_usage_summary(show_usage_res,
1269 		    DLADM_LOGTYPE_LINK, file, &state);
1270 	} else if (resource != NULL) {
1271 		/* Print log entries for named resource */
1272 		status = dladm_walk_usage_res(show_usage_time,
1273 		    DLADM_LOGTYPE_LINK, file, resource, stime, etime, &state);
1274 	} else {
1275 		/* Print time and information for each link */
1276 		status = dladm_walk_usage_time(show_usage_time,
1277 		    DLADM_LOGTYPE_LINK, file, stime, etime, &state);
1278 	}
1279 
1280 	if (status != DLADM_STATUS_OK)
1281 		die_dlerr(status, "show-usage");
1282 	ofmt_close(ofmt);
1283 }
1284 
1285 static void
1286 do_create_aggr(int argc, char *argv[], const char *use)
1287 {
1288 	int			option;
1289 	int			key = 0;
1290 	uint32_t		policy = AGGR_POLICY_L4;
1291 	aggr_lacp_mode_t	lacp_mode = AGGR_LACP_OFF;
1292 	aggr_lacp_timer_t	lacp_timer = AGGR_LACP_TIMER_SHORT;
1293 	dladm_aggr_port_attr_db_t	port[MAXPORT];
1294 	uint_t			n, ndev, nlink;
1295 	uint8_t			mac_addr[ETHERADDRL];
1296 	boolean_t		mac_addr_fixed = B_FALSE;
1297 	boolean_t		P_arg = B_FALSE;
1298 	boolean_t		l_arg = B_FALSE;
1299 	boolean_t		u_arg = B_FALSE;
1300 	boolean_t		T_arg = B_FALSE;
1301 	uint32_t		flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
1302 	char			*altroot = NULL;
1303 	char			name[MAXLINKNAMELEN];
1304 	char			*devs[MAXPORT];
1305 	char			*links[MAXPORT];
1306 	dladm_status_t		status;
1307 	dladm_status_t		pstatus;
1308 	char			propstr[DLADM_STRSIZE];
1309 	dladm_arg_list_t	*proplist = NULL;
1310 	int			i;
1311 	datalink_id_t		linkid;
1312 
1313 	ndev = nlink = opterr = 0;
1314 	bzero(propstr, DLADM_STRSIZE);
1315 
1316 	while ((option = getopt_long(argc, argv, ":d:l:L:P:R:tfu:T:p:",
1317 	    lopts, NULL)) != -1) {
1318 		switch (option) {
1319 		case 'd':
1320 			if (ndev + nlink >= MAXPORT)
1321 				die("too many ports specified");
1322 
1323 			devs[ndev++] = optarg;
1324 			break;
1325 		case 'P':
1326 			if (P_arg)
1327 				die_optdup(option);
1328 
1329 			P_arg = B_TRUE;
1330 			if (!dladm_aggr_str2policy(optarg, &policy))
1331 				die("invalid policy '%s'", optarg);
1332 			break;
1333 		case 'u':
1334 			if (u_arg)
1335 				die_optdup(option);
1336 
1337 			u_arg = B_TRUE;
1338 			if (!dladm_aggr_str2macaddr(optarg, &mac_addr_fixed,
1339 			    mac_addr))
1340 				die("invalid MAC address '%s'", optarg);
1341 			break;
1342 		case 'l':
1343 			if (isdigit(optarg[strlen(optarg) - 1])) {
1344 
1345 				/*
1346 				 * Ended with digit, possibly a link name.
1347 				 */
1348 				if (ndev + nlink >= MAXPORT)
1349 					die("too many ports specified");
1350 
1351 				links[nlink++] = optarg;
1352 				break;
1353 			}
1354 			/* FALLTHROUGH */
1355 		case 'L':
1356 			if (l_arg)
1357 				die_optdup(option);
1358 
1359 			l_arg = B_TRUE;
1360 			if (!dladm_aggr_str2lacpmode(optarg, &lacp_mode))
1361 				die("invalid LACP mode '%s'", optarg);
1362 			break;
1363 		case 'T':
1364 			if (T_arg)
1365 				die_optdup(option);
1366 
1367 			T_arg = B_TRUE;
1368 			if (!dladm_aggr_str2lacptimer(optarg, &lacp_timer))
1369 				die("invalid LACP timer value '%s'", optarg);
1370 			break;
1371 		case 't':
1372 			flags &= ~DLADM_OPT_PERSIST;
1373 			break;
1374 		case 'f':
1375 			flags |= DLADM_OPT_FORCE;
1376 			break;
1377 		case 'R':
1378 			altroot = optarg;
1379 			break;
1380 		case 'p':
1381 			(void) strlcat(propstr, optarg, DLADM_STRSIZE);
1382 			if (strlcat(propstr, ",", DLADM_STRSIZE) >=
1383 			    DLADM_STRSIZE)
1384 				die("property list too long '%s'", propstr);
1385 			break;
1386 
1387 		default:
1388 			die_opterr(optopt, option, use);
1389 			break;
1390 		}
1391 	}
1392 
1393 	if (ndev + nlink == 0)
1394 		usage();
1395 
1396 	/* get key value or the aggregation name (required last argument) */
1397 	if (optind != (argc-1))
1398 		usage();
1399 
1400 	if (!str2int(argv[optind], &key)) {
1401 		if (strlcpy(name, argv[optind], MAXLINKNAMELEN) >=
1402 		    MAXLINKNAMELEN) {
1403 			die("link name too long '%s'", argv[optind]);
1404 		}
1405 
1406 		if (!dladm_valid_linkname(name))
1407 			die("invalid link name '%s'", argv[optind]);
1408 	} else {
1409 		(void) snprintf(name, MAXLINKNAMELEN, "aggr%d", key);
1410 	}
1411 
1412 	if (altroot != NULL)
1413 		altroot_cmd(altroot, argc, argv);
1414 
1415 	for (n = 0; n < ndev; n++) {
1416 		if ((status = dladm_dev2linkid(handle, devs[n],
1417 		    &port[n].lp_linkid)) != DLADM_STATUS_OK) {
1418 			die_dlerr(status, "invalid dev name '%s'", devs[n]);
1419 		}
1420 	}
1421 
1422 	for (n = 0; n < nlink; n++) {
1423 		if ((status = dladm_name2info(handle, links[n],
1424 		    &port[ndev + n].lp_linkid, NULL, NULL, NULL)) !=
1425 		    DLADM_STATUS_OK) {
1426 			die_dlerr(status, "invalid link name '%s'", links[n]);
1427 		}
1428 	}
1429 
1430 	status = dladm_aggr_create(handle, name, key, ndev + nlink, port,
1431 	    policy, mac_addr_fixed, (const uchar_t *)mac_addr, lacp_mode,
1432 	    lacp_timer, flags);
1433 	if (status != DLADM_STATUS_OK)
1434 		goto done;
1435 
1436 	if (dladm_parse_link_props(propstr, &proplist, B_FALSE)
1437 	    != DLADM_STATUS_OK)
1438 		die("invalid aggregation property");
1439 
1440 	if (proplist == NULL)
1441 		return;
1442 
1443 	status = dladm_name2info(handle, name, &linkid, NULL, NULL, NULL);
1444 	if (status != DLADM_STATUS_OK)
1445 		goto done;
1446 
1447 	for (i = 0; i < proplist->al_count; i++) {
1448 		dladm_arg_info_t	*aip = &proplist->al_info[i];
1449 
1450 		pstatus = dladm_set_linkprop(handle, linkid, aip->ai_name,
1451 		    aip->ai_val, aip->ai_count, flags);
1452 
1453 		if (pstatus != DLADM_STATUS_OK) {
1454 			die_dlerr(pstatus,
1455 			    "aggr creation succeeded but "
1456 			    "could not set property '%s'", aip->ai_name);
1457 		}
1458 	}
1459 done:
1460 	dladm_free_props(proplist);
1461 	if (status != DLADM_STATUS_OK) {
1462 		if (status == DLADM_STATUS_NONOTIF) {
1463 			die_dlerr(status, "not all links have link up/down "
1464 			    "detection; must use -f (see dladm(1M))\n");
1465 		} else {
1466 			die_dlerr(status, "create operation failed");
1467 		}
1468 	}
1469 }
1470 
1471 /*
1472  * arg is either the key or the aggr name. Validate it and convert it to
1473  * the linkid if altroot is NULL.
1474  */
1475 static dladm_status_t
1476 i_dladm_aggr_get_linkid(const char *altroot, const char *arg,
1477     datalink_id_t *linkidp, uint32_t flags)
1478 {
1479 	int		key = 0;
1480 	char		*aggr = NULL;
1481 	dladm_status_t	status;
1482 
1483 	if (!str2int(arg, &key))
1484 		aggr = (char *)arg;
1485 
1486 	if (aggr == NULL && key == 0)
1487 		return (DLADM_STATUS_LINKINVAL);
1488 
1489 	if (altroot != NULL)
1490 		return (DLADM_STATUS_OK);
1491 
1492 	if (aggr != NULL) {
1493 		status = dladm_name2info(handle, aggr, linkidp, NULL, NULL,
1494 		    NULL);
1495 	} else {
1496 		status = dladm_key2linkid(handle, key, linkidp, flags);
1497 	}
1498 
1499 	return (status);
1500 }
1501 
1502 static void
1503 do_delete_aggr(int argc, char *argv[], const char *use)
1504 {
1505 	int			option;
1506 	char			*altroot = NULL;
1507 	uint32_t		flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
1508 	dladm_status_t		status;
1509 	datalink_id_t		linkid;
1510 
1511 	opterr = 0;
1512 	while ((option = getopt_long(argc, argv, ":R:t", lopts, NULL)) != -1) {
1513 		switch (option) {
1514 		case 't':
1515 			flags &= ~DLADM_OPT_PERSIST;
1516 			break;
1517 		case 'R':
1518 			altroot = optarg;
1519 			break;
1520 		default:
1521 			die_opterr(optopt, option, use);
1522 			break;
1523 		}
1524 	}
1525 
1526 	/* get key value or the aggregation name (required last argument) */
1527 	if (optind != (argc-1))
1528 		usage();
1529 
1530 	status = i_dladm_aggr_get_linkid(altroot, argv[optind], &linkid, flags);
1531 	if (status != DLADM_STATUS_OK)
1532 		goto done;
1533 
1534 	if (altroot != NULL)
1535 		altroot_cmd(altroot, argc, argv);
1536 
1537 	status = dladm_aggr_delete(handle, linkid, flags);
1538 done:
1539 	if (status != DLADM_STATUS_OK)
1540 		die_dlerr(status, "delete operation failed");
1541 }
1542 
1543 static void
1544 do_add_aggr(int argc, char *argv[], const char *use)
1545 {
1546 	int			option;
1547 	uint_t			n, ndev, nlink;
1548 	char			*altroot = NULL;
1549 	uint32_t		flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
1550 	datalink_id_t		linkid;
1551 	dladm_status_t		status;
1552 	dladm_aggr_port_attr_db_t	port[MAXPORT];
1553 	char			*devs[MAXPORT];
1554 	char			*links[MAXPORT];
1555 
1556 	ndev = nlink = opterr = 0;
1557 	while ((option = getopt_long(argc, argv, ":d:l:R:tf", lopts,
1558 	    NULL)) != -1) {
1559 		switch (option) {
1560 		case 'd':
1561 			if (ndev + nlink >= MAXPORT)
1562 				die("too many ports specified");
1563 
1564 			devs[ndev++] = optarg;
1565 			break;
1566 		case 'l':
1567 			if (ndev + nlink >= MAXPORT)
1568 				die("too many ports specified");
1569 
1570 			links[nlink++] = optarg;
1571 			break;
1572 		case 't':
1573 			flags &= ~DLADM_OPT_PERSIST;
1574 			break;
1575 		case 'f':
1576 			flags |= DLADM_OPT_FORCE;
1577 			break;
1578 		case 'R':
1579 			altroot = optarg;
1580 			break;
1581 		default:
1582 			die_opterr(optopt, option, use);
1583 			break;
1584 		}
1585 	}
1586 
1587 	if (ndev + nlink == 0)
1588 		usage();
1589 
1590 	/* get key value or the aggregation name (required last argument) */
1591 	if (optind != (argc-1))
1592 		usage();
1593 
1594 	if ((status = i_dladm_aggr_get_linkid(altroot, argv[optind], &linkid,
1595 	    flags & (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST))) !=
1596 	    DLADM_STATUS_OK) {
1597 		goto done;
1598 	}
1599 
1600 	if (altroot != NULL)
1601 		altroot_cmd(altroot, argc, argv);
1602 
1603 	for (n = 0; n < ndev; n++) {
1604 		if ((status = dladm_dev2linkid(handle, devs[n],
1605 		    &(port[n].lp_linkid))) != DLADM_STATUS_OK) {
1606 			die_dlerr(status, "invalid <dev> '%s'", devs[n]);
1607 		}
1608 	}
1609 
1610 	for (n = 0; n < nlink; n++) {
1611 		if ((status = dladm_name2info(handle, links[n],
1612 		    &port[n + ndev].lp_linkid, NULL, NULL, NULL)) !=
1613 		    DLADM_STATUS_OK) {
1614 			die_dlerr(status, "invalid <link> '%s'", links[n]);
1615 		}
1616 	}
1617 
1618 	status = dladm_aggr_add(handle, linkid, ndev + nlink, port, flags);
1619 done:
1620 	if (status != DLADM_STATUS_OK) {
1621 		/*
1622 		 * checking DLADM_STATUS_NOTSUP is a temporary workaround
1623 		 * and should be removed once 6399681 is fixed.
1624 		 */
1625 		if (status == DLADM_STATUS_NOTSUP) {
1626 			(void) fprintf(stderr,
1627 			    gettext("%s: add operation failed: %s\n"),
1628 			    progname,
1629 			    gettext("link capabilities don't match"));
1630 			dladm_close(handle);
1631 			exit(ENOTSUP);
1632 		} else if (status == DLADM_STATUS_NONOTIF) {
1633 			die_dlerr(status, "not all links have link up/down "
1634 			    "detection; must use -f (see dladm(1M))\n");
1635 		} else {
1636 			die_dlerr(status, "add operation failed");
1637 		}
1638 	}
1639 }
1640 
1641 static void
1642 do_remove_aggr(int argc, char *argv[], const char *use)
1643 {
1644 	int				option;
1645 	dladm_aggr_port_attr_db_t	port[MAXPORT];
1646 	uint_t				n, ndev, nlink;
1647 	char				*devs[MAXPORT];
1648 	char				*links[MAXPORT];
1649 	char				*altroot = NULL;
1650 	uint32_t			flags;
1651 	datalink_id_t			linkid;
1652 	dladm_status_t			status;
1653 
1654 	flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
1655 	ndev = nlink = opterr = 0;
1656 	while ((option = getopt_long(argc, argv, ":d:l:R:t",
1657 	    lopts, NULL)) != -1) {
1658 		switch (option) {
1659 		case 'd':
1660 			if (ndev + nlink >= MAXPORT)
1661 				die("too many ports specified");
1662 
1663 			devs[ndev++] = optarg;
1664 			break;
1665 		case 'l':
1666 			if (ndev + nlink >= MAXPORT)
1667 				die("too many ports specified");
1668 
1669 			links[nlink++] = optarg;
1670 			break;
1671 		case 't':
1672 			flags &= ~DLADM_OPT_PERSIST;
1673 			break;
1674 		case 'R':
1675 			altroot = optarg;
1676 			break;
1677 		default:
1678 			die_opterr(optopt, option, use);
1679 			break;
1680 		}
1681 	}
1682 
1683 	if (ndev + nlink == 0)
1684 		usage();
1685 
1686 	/* get key value or the aggregation name (required last argument) */
1687 	if (optind != (argc-1))
1688 		usage();
1689 
1690 	status = i_dladm_aggr_get_linkid(altroot, argv[optind], &linkid, flags);
1691 	if (status != DLADM_STATUS_OK)
1692 		goto done;
1693 
1694 	if (altroot != NULL)
1695 		altroot_cmd(altroot, argc, argv);
1696 
1697 	for (n = 0; n < ndev; n++) {
1698 		if ((status = dladm_dev2linkid(handle, devs[n],
1699 		    &(port[n].lp_linkid))) != DLADM_STATUS_OK) {
1700 			die_dlerr(status, "invalid <dev> '%s'", devs[n]);
1701 		}
1702 	}
1703 
1704 	for (n = 0; n < nlink; n++) {
1705 		if ((status = dladm_name2info(handle, links[n],
1706 		    &port[n + ndev].lp_linkid, NULL, NULL, NULL)) !=
1707 		    DLADM_STATUS_OK) {
1708 			die_dlerr(status, "invalid <link> '%s'", links[n]);
1709 		}
1710 	}
1711 
1712 	status = dladm_aggr_remove(handle, linkid, ndev + nlink, port, flags);
1713 done:
1714 	if (status != DLADM_STATUS_OK)
1715 		die_dlerr(status, "remove operation failed");
1716 }
1717 
1718 static void
1719 do_modify_aggr(int argc, char *argv[], const char *use)
1720 {
1721 	int			option;
1722 	uint32_t		policy = AGGR_POLICY_L4;
1723 	aggr_lacp_mode_t	lacp_mode = AGGR_LACP_OFF;
1724 	aggr_lacp_timer_t	lacp_timer = AGGR_LACP_TIMER_SHORT;
1725 	uint8_t			mac_addr[ETHERADDRL];
1726 	boolean_t		mac_addr_fixed = B_FALSE;
1727 	uint8_t			modify_mask = 0;
1728 	char			*altroot = NULL;
1729 	uint32_t		flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
1730 	datalink_id_t		linkid;
1731 	dladm_status_t		status;
1732 
1733 	opterr = 0;
1734 	while ((option = getopt_long(argc, argv, ":L:l:P:R:tu:T:", lopts,
1735 	    NULL)) != -1) {
1736 		switch (option) {
1737 		case 'P':
1738 			if (modify_mask & DLADM_AGGR_MODIFY_POLICY)
1739 				die_optdup(option);
1740 
1741 			modify_mask |= DLADM_AGGR_MODIFY_POLICY;
1742 
1743 			if (!dladm_aggr_str2policy(optarg, &policy))
1744 				die("invalid policy '%s'", optarg);
1745 			break;
1746 		case 'u':
1747 			if (modify_mask & DLADM_AGGR_MODIFY_MAC)
1748 				die_optdup(option);
1749 
1750 			modify_mask |= DLADM_AGGR_MODIFY_MAC;
1751 
1752 			if (!dladm_aggr_str2macaddr(optarg, &mac_addr_fixed,
1753 			    mac_addr))
1754 				die("invalid MAC address '%s'", optarg);
1755 			break;
1756 		case 'l':
1757 		case 'L':
1758 			if (modify_mask & DLADM_AGGR_MODIFY_LACP_MODE)
1759 				die_optdup(option);
1760 
1761 			modify_mask |= DLADM_AGGR_MODIFY_LACP_MODE;
1762 
1763 			if (!dladm_aggr_str2lacpmode(optarg, &lacp_mode))
1764 				die("invalid LACP mode '%s'", optarg);
1765 			break;
1766 		case 'T':
1767 			if (modify_mask & DLADM_AGGR_MODIFY_LACP_TIMER)
1768 				die_optdup(option);
1769 
1770 			modify_mask |= DLADM_AGGR_MODIFY_LACP_TIMER;
1771 
1772 			if (!dladm_aggr_str2lacptimer(optarg, &lacp_timer))
1773 				die("invalid LACP timer value '%s'", optarg);
1774 			break;
1775 		case 't':
1776 			flags &= ~DLADM_OPT_PERSIST;
1777 			break;
1778 		case 'R':
1779 			altroot = optarg;
1780 			break;
1781 		default:
1782 			die_opterr(optopt, option, use);
1783 			break;
1784 		}
1785 	}
1786 
1787 	if (modify_mask == 0)
1788 		die("at least one of the -PulT options must be specified");
1789 
1790 	/* get key value or the aggregation name (required last argument) */
1791 	if (optind != (argc-1))
1792 		usage();
1793 
1794 	status = i_dladm_aggr_get_linkid(altroot, argv[optind], &linkid, flags);
1795 	if (status != DLADM_STATUS_OK)
1796 		goto done;
1797 
1798 	if (altroot != NULL)
1799 		altroot_cmd(altroot, argc, argv);
1800 
1801 	status = dladm_aggr_modify(handle, linkid, modify_mask, policy,
1802 	    mac_addr_fixed, (const uchar_t *)mac_addr, lacp_mode, lacp_timer,
1803 	    flags);
1804 
1805 done:
1806 	if (status != DLADM_STATUS_OK)
1807 		die_dlerr(status, "modify operation failed");
1808 }
1809 
1810 /*ARGSUSED*/
1811 static void
1812 do_up_aggr(int argc, char *argv[], const char *use)
1813 {
1814 	datalink_id_t	linkid = DATALINK_ALL_LINKID;
1815 	dladm_status_t	status;
1816 
1817 	/*
1818 	 * get the key or the name of the aggregation (optional last argument)
1819 	 */
1820 	if (argc == 2) {
1821 		if ((status = i_dladm_aggr_get_linkid(NULL, argv[1], &linkid,
1822 		    DLADM_OPT_PERSIST)) != DLADM_STATUS_OK)
1823 			goto done;
1824 	} else if (argc > 2) {
1825 		usage();
1826 	}
1827 
1828 	status = dladm_aggr_up(handle, linkid);
1829 done:
1830 	if (status != DLADM_STATUS_OK) {
1831 		if (argc == 2) {
1832 			die_dlerr(status,
1833 			    "could not bring up aggregation '%s'", argv[1]);
1834 		} else {
1835 			die_dlerr(status, "could not bring aggregations up");
1836 		}
1837 	}
1838 }
1839 
1840 static void
1841 do_create_vlan(int argc, char *argv[], const char *use)
1842 {
1843 	char			*link = NULL;
1844 	char			drv[DLPI_LINKNAME_MAX];
1845 	uint_t			ppa;
1846 	datalink_id_t		linkid;
1847 	datalink_id_t		dev_linkid;
1848 	int			vid = 0;
1849 	int			option;
1850 	uint32_t		flags = (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST);
1851 	char			*altroot = NULL;
1852 	char			vlan[MAXLINKNAMELEN];
1853 	char			propstr[DLADM_STRSIZE];
1854 	dladm_arg_list_t	*proplist = NULL;
1855 	dladm_status_t		status;
1856 
1857 	opterr = 0;
1858 	bzero(propstr, DLADM_STRSIZE);
1859 
1860 	while ((option = getopt_long(argc, argv, ":tfR:l:v:p:",
1861 	    lopts, NULL)) != -1) {
1862 		switch (option) {
1863 		case 'v':
1864 			if (vid != 0)
1865 				die_optdup(option);
1866 
1867 			if (!str2int(optarg, &vid) || vid < 1 || vid > 4094)
1868 				die("invalid VLAN identifier '%s'", optarg);
1869 
1870 			break;
1871 		case 'l':
1872 			if (link != NULL)
1873 				die_optdup(option);
1874 
1875 			link = optarg;
1876 			break;
1877 		case 't':
1878 			flags &= ~DLADM_OPT_PERSIST;
1879 			break;
1880 		case 'R':
1881 			altroot = optarg;
1882 			break;
1883 		case 'p':
1884 			(void) strlcat(propstr, optarg, DLADM_STRSIZE);
1885 			if (strlcat(propstr, ",", DLADM_STRSIZE) >=
1886 			    DLADM_STRSIZE)
1887 				die("property list too long '%s'", propstr);
1888 			break;
1889 		case 'f':
1890 			flags |= DLADM_OPT_FORCE;
1891 			break;
1892 		default:
1893 			die_opterr(optopt, option, use);
1894 			break;
1895 		}
1896 	}
1897 
1898 	/* get vlan name if there is any */
1899 	if ((vid == 0) || (link == NULL) || (argc - optind > 1))
1900 		usage();
1901 
1902 	if (optind == (argc - 1)) {
1903 		if (strlcpy(vlan, argv[optind], MAXLINKNAMELEN) >=
1904 		    MAXLINKNAMELEN) {
1905 			die("vlan name too long '%s'", argv[optind]);
1906 		}
1907 	} else {
1908 		if ((dlpi_parselink(link, drv, &ppa) != DLPI_SUCCESS) ||
1909 		    (ppa >= 1000) ||
1910 		    (dlpi_makelink(vlan, drv, vid * 1000 + ppa) !=
1911 		    DLPI_SUCCESS)) {
1912 			die("invalid link name '%s'", link);
1913 		}
1914 	}
1915 
1916 	if (altroot != NULL)
1917 		altroot_cmd(altroot, argc, argv);
1918 
1919 	if (dladm_name2info(handle, link, &dev_linkid, NULL, NULL, NULL) !=
1920 	    DLADM_STATUS_OK) {
1921 		die("invalid link name '%s'", link);
1922 	}
1923 
1924 	if (dladm_parse_link_props(propstr, &proplist, B_FALSE)
1925 	    != DLADM_STATUS_OK)
1926 		die("invalid vlan property");
1927 
1928 	if ((status = dladm_vlan_create(handle, vlan, dev_linkid, vid, proplist,
1929 	    flags, &linkid)) != DLADM_STATUS_OK) {
1930 		die_dlerr(status, "create operation over %s failed", link);
1931 	}
1932 }
1933 
1934 static void
1935 do_delete_vlan(int argc, char *argv[], const char *use)
1936 {
1937 	int		option;
1938 	uint32_t	flags = (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST);
1939 	char		*altroot = NULL;
1940 	datalink_id_t	linkid;
1941 	dladm_status_t	status;
1942 
1943 	opterr = 0;
1944 	while ((option = getopt_long(argc, argv, ":R:t", lopts, NULL)) != -1) {
1945 		switch (option) {
1946 		case 't':
1947 			flags &= ~DLADM_OPT_PERSIST;
1948 			break;
1949 		case 'R':
1950 			altroot = optarg;
1951 			break;
1952 		default:
1953 			die_opterr(optopt, option, use);
1954 			break;
1955 		}
1956 	}
1957 
1958 	/* get VLAN link name (required last argument) */
1959 	if (optind != (argc - 1))
1960 		usage();
1961 
1962 	if (altroot != NULL)
1963 		altroot_cmd(altroot, argc, argv);
1964 
1965 	status = dladm_name2info(handle, argv[optind], &linkid, NULL, NULL,
1966 	    NULL);
1967 	if (status != DLADM_STATUS_OK)
1968 		goto done;
1969 
1970 	status = dladm_vlan_delete(handle, linkid, flags);
1971 done:
1972 	if (status != DLADM_STATUS_OK)
1973 		die_dlerr(status, "delete operation failed");
1974 }
1975 
1976 /*ARGSUSED*/
1977 static void
1978 do_up_vlan(int argc, char *argv[], const char *use)
1979 {
1980 	do_up_vnic_common(argc, argv, use, B_TRUE);
1981 }
1982 
1983 static void
1984 do_rename_link(int argc, char *argv[], const char *use)
1985 {
1986 	int		option;
1987 	char		*link1, *link2;
1988 	char		*altroot = NULL;
1989 	dladm_status_t	status;
1990 
1991 	opterr = 0;
1992 	while ((option = getopt_long(argc, argv, ":R:", lopts, NULL)) != -1) {
1993 		switch (option) {
1994 		case 'R':
1995 			altroot = optarg;
1996 			break;
1997 		default:
1998 			die_opterr(optopt, option, use);
1999 			break;
2000 		}
2001 	}
2002 
2003 	/* get link1 and link2 name (required the last 2 arguments) */
2004 	if (optind != (argc - 2))
2005 		usage();
2006 
2007 	if (altroot != NULL)
2008 		altroot_cmd(altroot, argc, argv);
2009 
2010 	link1 = argv[optind++];
2011 	link2 = argv[optind];
2012 	if ((status = dladm_rename_link(handle, link1, link2)) !=
2013 	    DLADM_STATUS_OK)
2014 		die_dlerr(status, "rename operation failed");
2015 }
2016 
2017 /*ARGSUSED*/
2018 static void
2019 do_delete_phys(int argc, char *argv[], const char *use)
2020 {
2021 	datalink_id_t	linkid = DATALINK_ALL_LINKID;
2022 	dladm_status_t	status;
2023 
2024 	/* get link name (required the last argument) */
2025 	if (argc > 2)
2026 		usage();
2027 
2028 	if (argc == 2) {
2029 		if ((status = dladm_name2info(handle, argv[1], &linkid, NULL,
2030 		    NULL, NULL)) != DLADM_STATUS_OK)
2031 			die_dlerr(status, "cannot delete '%s'", argv[1]);
2032 	}
2033 
2034 	if ((status = dladm_phys_delete(handle, linkid)) != DLADM_STATUS_OK) {
2035 		if (argc == 2)
2036 			die_dlerr(status, "cannot delete '%s'", argv[1]);
2037 		else
2038 			die_dlerr(status, "delete operation failed");
2039 	}
2040 }
2041 
2042 /*ARGSUSED*/
2043 static int
2044 i_dladm_walk_linkmap(dladm_handle_t dh, datalink_id_t linkid, void *arg)
2045 {
2046 	char			name[MAXLINKNAMELEN];
2047 	char			mediabuf[DLADM_STRSIZE];
2048 	char			classbuf[DLADM_STRSIZE];
2049 	datalink_class_t	class;
2050 	uint32_t		media;
2051 	uint32_t		flags;
2052 
2053 	if (dladm_datalink_id2info(dh, linkid, &flags, &class, &media, name,
2054 	    MAXLINKNAMELEN) == DLADM_STATUS_OK) {
2055 		(void) dladm_class2str(class, classbuf);
2056 		(void) dladm_media2str(media, mediabuf);
2057 		(void) printf("%-12s%8d  %-12s%-20s %6d\n", name,
2058 		    linkid, classbuf, mediabuf, flags);
2059 	}
2060 	return (DLADM_WALK_CONTINUE);
2061 }
2062 
2063 /*ARGSUSED*/
2064 static void
2065 do_show_linkmap(int argc, char *argv[], const char *use)
2066 {
2067 	if (argc != 1)
2068 		die("invalid arguments");
2069 
2070 	(void) printf("%-12s%8s  %-12s%-20s %6s\n", "NAME", "LINKID",
2071 	    "CLASS", "MEDIA", "FLAGS");
2072 
2073 	(void) dladm_walk_datalink_id(i_dladm_walk_linkmap, handle, NULL,
2074 	    DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE,
2075 	    DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST);
2076 }
2077 
2078 /*
2079  * Delete inactive physical links.
2080  */
2081 /*ARGSUSED*/
2082 static int
2083 purge_phys(dladm_handle_t dh, datalink_id_t linkid, void *arg)
2084 {
2085 	datalink_class_t	class;
2086 	uint32_t		flags;
2087 
2088 	if (dladm_datalink_id2info(dh, linkid, &flags, &class, NULL, NULL, 0)
2089 	    != DLADM_STATUS_OK) {
2090 		return (DLADM_WALK_CONTINUE);
2091 	}
2092 
2093 	if (class == DATALINK_CLASS_PHYS && !(flags & DLADM_OPT_ACTIVE))
2094 		(void) dladm_phys_delete(dh, linkid);
2095 
2096 	return (DLADM_WALK_CONTINUE);
2097 }
2098 
2099 /*ARGSUSED*/
2100 static void
2101 do_init_phys(int argc, char *argv[], const char *use)
2102 {
2103 	di_node_t	devtree;
2104 
2105 	if (argc > 1)
2106 		usage();
2107 
2108 	/*
2109 	 * Force all the devices to attach, therefore all the network physical
2110 	 * devices can be known to the dlmgmtd daemon.
2111 	 */
2112 	if ((devtree = di_init("/", DINFOFORCE | DINFOSUBTREE)) != DI_NODE_NIL)
2113 		di_fini(devtree);
2114 
2115 	(void) dladm_walk_datalink_id(purge_phys, handle, NULL,
2116 	    DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST);
2117 }
2118 
2119 
2120 /*
2121  * Print the active topology information.
2122  */
2123 static dladm_status_t
2124 print_link_topology(show_state_t *state, datalink_id_t linkid,
2125     datalink_class_t class, link_fields_buf_t *lbuf)
2126 {
2127 	uint32_t	flags = state->ls_flags;
2128 	dladm_status_t	status = DLADM_STATUS_OK;
2129 	char		tmpbuf[MAXLINKNAMELEN];
2130 
2131 	lbuf->link_over[0] = '\0';
2132 
2133 	switch (class) {
2134 	case DATALINK_CLASS_VLAN: {
2135 		dladm_vlan_attr_t	vinfo;
2136 
2137 		status = dladm_vlan_info(handle, linkid, &vinfo, flags);
2138 		if (status != DLADM_STATUS_OK)
2139 			break;
2140 		status = dladm_datalink_id2info(handle, vinfo.dv_linkid, NULL,
2141 		    NULL, NULL, lbuf->link_over, sizeof (lbuf->link_over));
2142 		break;
2143 	}
2144 
2145 	case DATALINK_CLASS_AGGR: {
2146 		dladm_aggr_grp_attr_t	ginfo;
2147 		int			i;
2148 
2149 		status = dladm_aggr_info(handle, linkid, &ginfo, flags);
2150 		if (status != DLADM_STATUS_OK)
2151 			break;
2152 
2153 		if (ginfo.lg_nports == 0) {
2154 			status = DLADM_STATUS_BADVAL;
2155 			break;
2156 		}
2157 		for (i = 0; i < ginfo.lg_nports; i++) {
2158 			status = dladm_datalink_id2info(handle,
2159 			    ginfo.lg_ports[i].lp_linkid, NULL, NULL, NULL,
2160 			    tmpbuf, sizeof (tmpbuf));
2161 			if (status != DLADM_STATUS_OK) {
2162 				free(ginfo.lg_ports);
2163 				break;
2164 			}
2165 			(void) strlcat(lbuf->link_over, tmpbuf,
2166 			    sizeof (lbuf->link_over));
2167 			if (i != (ginfo.lg_nports - 1)) {
2168 				(void) strlcat(lbuf->link_over, " ",
2169 				    sizeof (lbuf->link_over));
2170 			}
2171 		}
2172 		free(ginfo.lg_ports);
2173 		break;
2174 	}
2175 
2176 	case DATALINK_CLASS_VNIC: {
2177 		dladm_vnic_attr_t	vinfo;
2178 
2179 		status = dladm_vnic_info(handle, linkid, &vinfo, flags);
2180 		if (status == DLADM_STATUS_OK)
2181 			status = dladm_datalink_id2info(handle,
2182 			    vinfo.va_link_id, NULL, NULL, NULL, lbuf->link_over,
2183 			    sizeof (lbuf->link_over));
2184 		break;
2185 	}
2186 
2187 	case DATALINK_CLASS_SIMNET: {
2188 		dladm_simnet_attr_t	slinfo;
2189 
2190 		status = dladm_simnet_info(handle, linkid, &slinfo, flags);
2191 		if (status == DLADM_STATUS_OK &&
2192 		    slinfo.sna_peer_link_id != DATALINK_INVALID_LINKID)
2193 			status = dladm_datalink_id2info(handle,
2194 			    slinfo.sna_peer_link_id, NULL, NULL, NULL,
2195 			    lbuf->link_over, sizeof (lbuf->link_over));
2196 		break;
2197 	}
2198 	}
2199 
2200 	return (status);
2201 }
2202 
2203 static dladm_status_t
2204 print_link(show_state_t *state, datalink_id_t linkid, link_fields_buf_t *lbuf)
2205 {
2206 	char			link[MAXLINKNAMELEN];
2207 	datalink_class_t	class;
2208 	uint_t			mtu;
2209 	uint32_t		flags;
2210 	dladm_status_t		status;
2211 
2212 	if ((status = dladm_datalink_id2info(handle, linkid, &flags, &class,
2213 	    NULL, link, sizeof (link))) != DLADM_STATUS_OK) {
2214 		goto done;
2215 	}
2216 
2217 	if (!(state->ls_flags & flags)) {
2218 		status = DLADM_STATUS_NOTFOUND;
2219 		goto done;
2220 	}
2221 
2222 	if (state->ls_flags == DLADM_OPT_ACTIVE) {
2223 		dladm_attr_t	dlattr;
2224 
2225 		if (class == DATALINK_CLASS_PHYS) {
2226 			dladm_phys_attr_t	dpa;
2227 			dlpi_handle_t		dh;
2228 			dlpi_info_t		dlinfo;
2229 
2230 			if ((status = dladm_phys_info(handle, linkid, &dpa,
2231 			    DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) {
2232 				goto done;
2233 			}
2234 
2235 			if (!dpa.dp_novanity)
2236 				goto link_mtu;
2237 
2238 			/*
2239 			 * This is a physical link that does not have
2240 			 * vanity naming support.
2241 			 */
2242 			if (dlpi_open(dpa.dp_dev, &dh, DLPI_DEVONLY) !=
2243 			    DLPI_SUCCESS) {
2244 				status = DLADM_STATUS_NOTFOUND;
2245 				goto done;
2246 			}
2247 
2248 			if (dlpi_info(dh, &dlinfo, 0) != DLPI_SUCCESS) {
2249 				dlpi_close(dh);
2250 				status = DLADM_STATUS_BADARG;
2251 				goto done;
2252 			}
2253 
2254 			dlpi_close(dh);
2255 			mtu = dlinfo.di_max_sdu;
2256 		} else {
2257 link_mtu:
2258 			status = dladm_info(handle, linkid, &dlattr);
2259 			if (status != DLADM_STATUS_OK)
2260 				goto done;
2261 			mtu = dlattr.da_max_sdu;
2262 		}
2263 	}
2264 
2265 	(void) snprintf(lbuf->link_name, sizeof (lbuf->link_name),
2266 	    "%s", link);
2267 	(void) dladm_class2str(class, lbuf->link_class);
2268 	if (state->ls_flags == DLADM_OPT_ACTIVE) {
2269 		(void) snprintf(lbuf->link_mtu, sizeof (lbuf->link_mtu),
2270 		    "%u", mtu);
2271 		(void) get_linkstate(link, B_TRUE, lbuf->link_state);
2272 	}
2273 
2274 	status = print_link_topology(state, linkid, class, lbuf);
2275 	if (status != DLADM_STATUS_OK)
2276 		goto done;
2277 
2278 done:
2279 	return (status);
2280 }
2281 
2282 /* ARGSUSED */
2283 static int
2284 show_link(dladm_handle_t dh, datalink_id_t linkid, void *arg)
2285 {
2286 	show_state_t		*state = (show_state_t *)arg;
2287 	dladm_status_t		status;
2288 	link_fields_buf_t	lbuf;
2289 
2290 	/*
2291 	 * first get all the link attributes into lbuf;
2292 	 */
2293 	bzero(&lbuf, sizeof (link_fields_buf_t));
2294 	status = print_link(state, linkid, &lbuf);
2295 
2296 	if (status != DLADM_STATUS_OK)
2297 		goto done;
2298 
2299 	ofmt_print(state->ls_ofmt, &lbuf);
2300 
2301 done:
2302 	state->ls_status = status;
2303 	return (DLADM_WALK_CONTINUE);
2304 }
2305 
2306 static boolean_t
2307 print_link_stats_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
2308 {
2309 	link_args_t *largs = ofarg->ofmt_cbarg;
2310 	pktsum_t *diff_stats = largs->link_s_psum;
2311 
2312 	switch (ofarg->ofmt_id) {
2313 	case LINK_S_LINK:
2314 		(void) snprintf(buf, bufsize, "%s", largs->link_s_link);
2315 		break;
2316 	case LINK_S_IPKTS:
2317 		(void) snprintf(buf, bufsize, "%llu", diff_stats->ipackets);
2318 		break;
2319 	case LINK_S_RBYTES:
2320 		(void) snprintf(buf, bufsize, "%llu", diff_stats->rbytes);
2321 		break;
2322 	case LINK_S_IERRORS:
2323 		(void) snprintf(buf, bufsize, "%u", diff_stats->ierrors);
2324 		break;
2325 	case LINK_S_OPKTS:
2326 		(void) snprintf(buf, bufsize, "%llu", diff_stats->opackets);
2327 		break;
2328 	case LINK_S_OBYTES:
2329 		(void) snprintf(buf, bufsize, "%llu", diff_stats->obytes);
2330 		break;
2331 	case LINK_S_OERRORS:
2332 		(void) snprintf(buf, bufsize, "%u", diff_stats->oerrors);
2333 		break;
2334 	default:
2335 		die("invalid input");
2336 		break;
2337 	}
2338 	return (B_TRUE);
2339 }
2340 
2341 static int
2342 show_link_stats(dladm_handle_t dh, datalink_id_t linkid, void *arg)
2343 {
2344 	char			link[DLPI_LINKNAME_MAX];
2345 	datalink_class_t	class;
2346 	show_state_t		*state = (show_state_t *)arg;
2347 	pktsum_t		stats, diff_stats;
2348 	dladm_phys_attr_t	dpa;
2349 	link_args_t		largs;
2350 
2351 	if (state->ls_firstonly) {
2352 		if (state->ls_donefirst)
2353 			return (DLADM_WALK_CONTINUE);
2354 		state->ls_donefirst = B_TRUE;
2355 	} else {
2356 		bzero(&state->ls_prevstats, sizeof (state->ls_prevstats));
2357 	}
2358 
2359 	if (dladm_datalink_id2info(dh, linkid, NULL, &class, NULL, link,
2360 	    DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) {
2361 		return (DLADM_WALK_CONTINUE);
2362 	}
2363 
2364 	if (class == DATALINK_CLASS_PHYS) {
2365 		if (dladm_phys_info(dh, linkid, &dpa, DLADM_OPT_ACTIVE) !=
2366 		    DLADM_STATUS_OK) {
2367 			return (DLADM_WALK_CONTINUE);
2368 		}
2369 		if (dpa.dp_novanity)
2370 			get_mac_stats(dpa.dp_dev, &stats);
2371 		else
2372 			get_link_stats(link, &stats);
2373 	} else {
2374 		get_link_stats(link, &stats);
2375 	}
2376 	dladm_stats_diff(&diff_stats, &stats, &state->ls_prevstats);
2377 
2378 	largs.link_s_link = link;
2379 	largs.link_s_psum = &diff_stats;
2380 	ofmt_print(state->ls_ofmt, &largs);
2381 
2382 	state->ls_prevstats = stats;
2383 	return (DLADM_WALK_CONTINUE);
2384 }
2385 
2386 
2387 static dladm_status_t
2388 print_aggr_info(show_grp_state_t *state, const char *link,
2389     dladm_aggr_grp_attr_t *ginfop)
2390 {
2391 	char			addr_str[ETHERADDRL * 3];
2392 	laggr_fields_buf_t	lbuf;
2393 
2394 	(void) snprintf(lbuf.laggr_name, sizeof (lbuf.laggr_name),
2395 	    "%s", link);
2396 
2397 	(void) dladm_aggr_policy2str(ginfop->lg_policy,
2398 	    lbuf.laggr_policy);
2399 
2400 	if (ginfop->lg_mac_fixed) {
2401 		(void) dladm_aggr_macaddr2str(ginfop->lg_mac, addr_str);
2402 		(void) snprintf(lbuf.laggr_addrpolicy,
2403 		    sizeof (lbuf.laggr_addrpolicy), "fixed (%s)", addr_str);
2404 	} else {
2405 		(void) snprintf(lbuf.laggr_addrpolicy,
2406 		    sizeof (lbuf.laggr_addrpolicy), "auto");
2407 	}
2408 
2409 
2410 	(void) dladm_aggr_lacpmode2str(ginfop->lg_lacp_mode,
2411 	    lbuf.laggr_lacpactivity);
2412 	(void) dladm_aggr_lacptimer2str(ginfop->lg_lacp_timer,
2413 	    lbuf.laggr_lacptimer);
2414 	(void) snprintf(lbuf.laggr_flags, sizeof (lbuf.laggr_flags), "%c----",
2415 	    ginfop->lg_force ? 'f' : '-');
2416 
2417 	ofmt_print(state->gs_ofmt, &lbuf);
2418 
2419 	return (DLADM_STATUS_OK);
2420 }
2421 
2422 static boolean_t
2423 print_xaggr_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
2424 {
2425 	const laggr_args_t 	*l = ofarg->ofmt_cbarg;
2426 	int 			portnum;
2427 	boolean_t		is_port = (l->laggr_lport >= 0);
2428 	static char		tmpbuf[DLADM_STRSIZE];
2429 	dladm_aggr_port_attr_t *portp;
2430 	dladm_phys_attr_t	dpa;
2431 	dladm_status_t		*stat, status = DLADM_STATUS_OK;
2432 
2433 	stat = l->laggr_status;
2434 
2435 	if (is_port) {
2436 		portnum = l->laggr_lport;
2437 		portp = &(l->laggr_ginfop->lg_ports[portnum]);
2438 		if ((status = dladm_datalink_id2info(handle,
2439 		    portp->lp_linkid, NULL, NULL, NULL, buf, bufsize)) !=
2440 		    DLADM_STATUS_OK) {
2441 			goto err;
2442 		}
2443 
2444 		if ((status = dladm_phys_info(handle, portp->lp_linkid,
2445 		    &dpa, DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) {
2446 			goto err;
2447 		}
2448 	}
2449 
2450 	switch (ofarg->ofmt_id) {
2451 	case AGGR_X_LINK:
2452 		(void) snprintf(buf, bufsize, "%s",
2453 		    (is_port && !l->laggr_parsable ? " " : l->laggr_link));
2454 		break;
2455 	case AGGR_X_PORT:
2456 		if (is_port)
2457 			break;
2458 		*stat = DLADM_STATUS_OK;
2459 		return (B_TRUE);
2460 
2461 	case AGGR_X_SPEED:
2462 		if (is_port) {
2463 			(void) snprintf(buf, bufsize, "%uMb",
2464 			    (uint_t)((get_ifspeed(dpa.dp_dev,
2465 			    B_FALSE)) / 1000000ull));
2466 		} else {
2467 			(void) snprintf(buf, bufsize, "%uMb",
2468 			    (uint_t)((get_ifspeed(l->laggr_link,
2469 			    B_TRUE)) / 1000000ull));
2470 		}
2471 		break;
2472 
2473 	case AGGR_X_DUPLEX:
2474 		if (is_port)
2475 			(void) get_linkduplex(dpa.dp_dev, B_FALSE, tmpbuf);
2476 		else
2477 			(void) get_linkduplex(l->laggr_link, B_TRUE, tmpbuf);
2478 		(void) strlcpy(buf, tmpbuf, bufsize);
2479 		break;
2480 
2481 	case AGGR_X_STATE:
2482 		if (is_port)
2483 			(void) get_linkstate(dpa.dp_dev,  B_FALSE, tmpbuf);
2484 		else
2485 			(void) get_linkstate(l->laggr_link, B_TRUE, tmpbuf);
2486 		(void) strlcpy(buf, tmpbuf, bufsize);
2487 		break;
2488 	case AGGR_X_ADDRESS:
2489 		(void) dladm_aggr_macaddr2str(
2490 		    (is_port ? portp->lp_mac : l->laggr_ginfop->lg_mac),
2491 		    tmpbuf);
2492 		(void) strlcpy(buf, tmpbuf, bufsize);
2493 		break;
2494 	case AGGR_X_PORTSTATE:
2495 		if (is_port) {
2496 			(void) dladm_aggr_portstate2str(portp->lp_state,
2497 			    tmpbuf);
2498 			(void) strlcpy(buf, tmpbuf, bufsize);
2499 		}
2500 		break;
2501 	}
2502 err:
2503 	*stat = status;
2504 	return (B_TRUE);
2505 }
2506 
2507 static dladm_status_t
2508 print_aggr_extended(show_grp_state_t *state, const char *link,
2509     dladm_aggr_grp_attr_t *ginfop)
2510 {
2511 	int			i;
2512 	dladm_status_t		status;
2513 	laggr_args_t		largs;
2514 
2515 	largs.laggr_lport = -1;
2516 	largs.laggr_link = link;
2517 	largs.laggr_ginfop = ginfop;
2518 	largs.laggr_status = &status;
2519 	largs.laggr_parsable = state->gs_parsable;
2520 
2521 	ofmt_print(state->gs_ofmt, &largs);
2522 
2523 	if (status != DLADM_STATUS_OK)
2524 		goto done;
2525 
2526 	for (i = 0; i < ginfop->lg_nports; i++) {
2527 		largs.laggr_lport = i;
2528 		ofmt_print(state->gs_ofmt, &largs);
2529 		if (status != DLADM_STATUS_OK)
2530 			goto done;
2531 	}
2532 
2533 	status = DLADM_STATUS_OK;
2534 done:
2535 	return (status);
2536 }
2537 
2538 static boolean_t
2539 print_lacp_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
2540 {
2541 	const laggr_args_t	*l = ofarg->ofmt_cbarg;
2542 	int			portnum;
2543 	boolean_t		is_port = (l->laggr_lport >= 0);
2544 	dladm_aggr_port_attr_t	*portp;
2545 	dladm_status_t		*stat, status;
2546 	aggr_lacp_state_t	*lstate;
2547 
2548 	if (!is_port) {
2549 		return (B_FALSE); /* cannot happen! */
2550 	}
2551 
2552 	stat = l->laggr_status;
2553 
2554 	portnum = l->laggr_lport;
2555 	portp = &(l->laggr_ginfop->lg_ports[portnum]);
2556 
2557 	if ((status = dladm_datalink_id2info(handle, portp->lp_linkid,
2558 	    NULL, NULL, NULL, buf, bufsize)) != DLADM_STATUS_OK) {
2559 			goto err;
2560 	}
2561 	lstate = &(portp->lp_lacp_state);
2562 
2563 	switch (ofarg->ofmt_id) {
2564 	case AGGR_L_LINK:
2565 		(void) snprintf(buf, bufsize, "%s",
2566 		    (portnum > 0 ? "" : l->laggr_link));
2567 		break;
2568 
2569 	case AGGR_L_PORT:
2570 		/*
2571 		 * buf already contains portname as a result of the
2572 		 * earlier call to dladm_datalink_id2info().
2573 		 */
2574 		break;
2575 
2576 	case AGGR_L_AGGREGATABLE:
2577 		(void) snprintf(buf, bufsize, "%s",
2578 		    (lstate->bit.aggregation ? "yes" : "no"));
2579 		break;
2580 
2581 	case AGGR_L_SYNC:
2582 		(void) snprintf(buf, bufsize, "%s",
2583 		    (lstate->bit.sync ? "yes" : "no"));
2584 		break;
2585 
2586 	case AGGR_L_COLL:
2587 		(void) snprintf(buf, bufsize, "%s",
2588 		    (lstate->bit.collecting ? "yes" : "no"));
2589 		break;
2590 
2591 	case AGGR_L_DIST:
2592 		(void) snprintf(buf, bufsize, "%s",
2593 		    (lstate->bit.distributing ? "yes" : "no"));
2594 		break;
2595 
2596 	case AGGR_L_DEFAULTED:
2597 		(void) snprintf(buf, bufsize, "%s",
2598 		    (lstate->bit.defaulted ? "yes" : "no"));
2599 		break;
2600 
2601 	case AGGR_L_EXPIRED:
2602 		(void) snprintf(buf, bufsize, "%s",
2603 		    (lstate->bit.expired ? "yes" : "no"));
2604 		break;
2605 	}
2606 
2607 	*stat = DLADM_STATUS_OK;
2608 	return (B_TRUE);
2609 
2610 err:
2611 	*stat = status;
2612 	return (B_TRUE);
2613 }
2614 
2615 static dladm_status_t
2616 print_aggr_lacp(show_grp_state_t *state, const char *link,
2617     dladm_aggr_grp_attr_t *ginfop)
2618 {
2619 	int		i;
2620 	dladm_status_t	status;
2621 	laggr_args_t	largs;
2622 
2623 	largs.laggr_link = link;
2624 	largs.laggr_ginfop = ginfop;
2625 	largs.laggr_status = &status;
2626 
2627 	for (i = 0; i < ginfop->lg_nports; i++) {
2628 		largs.laggr_lport = i;
2629 		ofmt_print(state->gs_ofmt, &largs);
2630 		if (status != DLADM_STATUS_OK)
2631 			goto done;
2632 	}
2633 
2634 	status = DLADM_STATUS_OK;
2635 done:
2636 	return (status);
2637 }
2638 
2639 static boolean_t
2640 print_aggr_stats_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
2641 {
2642 	const laggr_args_t	*l = ofarg->ofmt_cbarg;
2643 	int 			portnum;
2644 	boolean_t		is_port = (l->laggr_lport >= 0);
2645 	dladm_aggr_port_attr_t	*portp;
2646 	dladm_status_t		*stat, status;
2647 	pktsum_t		*diff_stats;
2648 
2649 	stat = l->laggr_status;
2650 	*stat = DLADM_STATUS_OK;
2651 
2652 	if (is_port) {
2653 		portnum = l->laggr_lport;
2654 		portp = &(l->laggr_ginfop->lg_ports[portnum]);
2655 
2656 		if ((status = dladm_datalink_id2info(handle,
2657 		    portp->lp_linkid, NULL, NULL, NULL, buf, bufsize)) !=
2658 		    DLADM_STATUS_OK) {
2659 			goto err;
2660 		}
2661 		diff_stats = l->laggr_diffstats;
2662 	}
2663 
2664 	switch (ofarg->ofmt_id) {
2665 	case AGGR_S_LINK:
2666 		(void) snprintf(buf, bufsize, "%s",
2667 		    (is_port ? "" : l->laggr_link));
2668 		break;
2669 	case AGGR_S_PORT:
2670 		/*
2671 		 * if (is_port), buf has port name. Otherwise we print
2672 		 * STR_UNDEF_VAL
2673 		 */
2674 		break;
2675 
2676 	case AGGR_S_IPKTS:
2677 		if (is_port) {
2678 			(void) snprintf(buf, bufsize, "%llu",
2679 			    diff_stats->ipackets);
2680 		} else {
2681 			(void) snprintf(buf, bufsize, "%llu",
2682 			    l->laggr_pktsumtot->ipackets);
2683 		}
2684 		break;
2685 
2686 	case AGGR_S_RBYTES:
2687 		if (is_port) {
2688 			(void) snprintf(buf, bufsize, "%llu",
2689 			    diff_stats->rbytes);
2690 		} else {
2691 			(void) snprintf(buf, bufsize, "%llu",
2692 			    l->laggr_pktsumtot->rbytes);
2693 		}
2694 		break;
2695 
2696 	case AGGR_S_OPKTS:
2697 		if (is_port) {
2698 			(void) snprintf(buf, bufsize, "%llu",
2699 			    diff_stats->opackets);
2700 		} else {
2701 			(void) snprintf(buf, bufsize, "%llu",
2702 			    l->laggr_pktsumtot->opackets);
2703 		}
2704 		break;
2705 	case AGGR_S_OBYTES:
2706 		if (is_port) {
2707 			(void) snprintf(buf, bufsize, "%llu",
2708 			    diff_stats->obytes);
2709 		} else {
2710 			(void) snprintf(buf, bufsize, "%llu",
2711 			    l->laggr_pktsumtot->obytes);
2712 		}
2713 		break;
2714 
2715 	case AGGR_S_IPKTDIST:
2716 		if (is_port) {
2717 			(void) snprintf(buf, bufsize, "%-6.1f",
2718 			    (double)diff_stats->ipackets/
2719 			    (double)l->laggr_pktsumtot->ipackets * 100);
2720 		}
2721 		break;
2722 	case AGGR_S_OPKTDIST:
2723 		if (is_port) {
2724 			(void) snprintf(buf, bufsize, "%-6.1f",
2725 			    (double)diff_stats->opackets/
2726 			    (double)l->laggr_pktsumtot->opackets * 100);
2727 		}
2728 		break;
2729 	}
2730 	return (B_TRUE);
2731 
2732 err:
2733 	*stat = status;
2734 	return (B_TRUE);
2735 }
2736 
2737 static dladm_status_t
2738 print_aggr_stats(show_grp_state_t *state, const char *link,
2739     dladm_aggr_grp_attr_t *ginfop)
2740 {
2741 	dladm_phys_attr_t	dpa;
2742 	dladm_aggr_port_attr_t	*portp;
2743 	pktsum_t		pktsumtot, *port_stat;
2744 	dladm_status_t		status;
2745 	int			i;
2746 	laggr_args_t		largs;
2747 
2748 	/* sum the ports statistics */
2749 	bzero(&pktsumtot, sizeof (pktsumtot));
2750 
2751 	/* Allocate memory to keep stats of each port */
2752 	port_stat = malloc(ginfop->lg_nports * sizeof (pktsum_t));
2753 	if (port_stat == NULL) {
2754 		/* Bail out; no memory */
2755 		return (DLADM_STATUS_NOMEM);
2756 	}
2757 
2758 
2759 	for (i = 0; i < ginfop->lg_nports; i++) {
2760 
2761 		portp = &(ginfop->lg_ports[i]);
2762 		if ((status = dladm_phys_info(handle, portp->lp_linkid, &dpa,
2763 		    DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) {
2764 			goto done;
2765 		}
2766 
2767 		get_mac_stats(dpa.dp_dev, &port_stat[i]);
2768 
2769 		/*
2770 		 * Let's re-use gs_prevstats[] to store the difference of the
2771 		 * counters since last use. We will store the new stats from
2772 		 * port_stat[] once we have the stats displayed.
2773 		 */
2774 
2775 		dladm_stats_diff(&state->gs_prevstats[i], &port_stat[i],
2776 		    &state->gs_prevstats[i]);
2777 		dladm_stats_total(&pktsumtot, &pktsumtot,
2778 		    &state->gs_prevstats[i]);
2779 	}
2780 
2781 	largs.laggr_lport = -1;
2782 	largs.laggr_link = link;
2783 	largs.laggr_ginfop = ginfop;
2784 	largs.laggr_status = &status;
2785 	largs.laggr_pktsumtot = &pktsumtot;
2786 
2787 	ofmt_print(state->gs_ofmt, &largs);
2788 
2789 	if (status != DLADM_STATUS_OK)
2790 		goto done;
2791 
2792 	for (i = 0; i < ginfop->lg_nports; i++) {
2793 		largs.laggr_lport = i;
2794 		largs.laggr_diffstats = &state->gs_prevstats[i];
2795 		ofmt_print(state->gs_ofmt, &largs);
2796 		if (status != DLADM_STATUS_OK)
2797 			goto done;
2798 	}
2799 
2800 	status = DLADM_STATUS_OK;
2801 	for (i = 0; i < ginfop->lg_nports; i++)
2802 		state->gs_prevstats[i] = port_stat[i];
2803 
2804 done:
2805 	free(port_stat);
2806 	return (status);
2807 }
2808 
2809 static dladm_status_t
2810 print_aggr(show_grp_state_t *state, datalink_id_t linkid)
2811 {
2812 	char			link[MAXLINKNAMELEN];
2813 	dladm_aggr_grp_attr_t	ginfo;
2814 	uint32_t		flags;
2815 	dladm_status_t		status;
2816 
2817 	bzero(&ginfo, sizeof (dladm_aggr_grp_attr_t));
2818 	if ((status = dladm_datalink_id2info(handle, linkid, &flags, NULL,
2819 	    NULL, link, MAXLINKNAMELEN)) != DLADM_STATUS_OK) {
2820 		return (status);
2821 	}
2822 
2823 	if (!(state->gs_flags & flags))
2824 		return (DLADM_STATUS_NOTFOUND);
2825 
2826 	status = dladm_aggr_info(handle, linkid, &ginfo, state->gs_flags);
2827 	if (status != DLADM_STATUS_OK)
2828 		return (status);
2829 
2830 	if (state->gs_lacp)
2831 		status = print_aggr_lacp(state, link, &ginfo);
2832 	else if (state->gs_extended)
2833 		status = print_aggr_extended(state, link, &ginfo);
2834 	else if (state->gs_stats)
2835 		status = print_aggr_stats(state, link, &ginfo);
2836 	else
2837 		status = print_aggr_info(state, link, &ginfo);
2838 
2839 done:
2840 	free(ginfo.lg_ports);
2841 	return (status);
2842 }
2843 
2844 /* ARGSUSED */
2845 static int
2846 show_aggr(dladm_handle_t dh, datalink_id_t linkid, void *arg)
2847 {
2848 	show_grp_state_t	*state = arg;
2849 
2850 	state->gs_status = print_aggr(state, linkid);
2851 	return (DLADM_WALK_CONTINUE);
2852 }
2853 
2854 static void
2855 do_show_link(int argc, char *argv[], const char *use)
2856 {
2857 	int		option;
2858 	boolean_t	s_arg = B_FALSE;
2859 	boolean_t	S_arg = B_FALSE;
2860 	boolean_t	i_arg = B_FALSE;
2861 	uint32_t	flags = DLADM_OPT_ACTIVE;
2862 	boolean_t	p_arg = B_FALSE;
2863 	datalink_id_t	linkid = DATALINK_ALL_LINKID;
2864 	char		linkname[MAXLINKNAMELEN];
2865 	uint32_t	interval = 0;
2866 	show_state_t	state;
2867 	dladm_status_t	status;
2868 	boolean_t	o_arg = B_FALSE;
2869 	char		*fields_str = NULL;
2870 	char		*all_active_fields = "link,class,mtu,state,over";
2871 	char		*all_inactive_fields = "link,class,over";
2872 	char		*allstat_fields =
2873 	    "link,ipackets,rbytes,ierrors,opackets,obytes,oerrors";
2874 	ofmt_handle_t	ofmt;
2875 	ofmt_status_t	oferr;
2876 	uint_t		ofmtflags = 0;
2877 
2878 	bzero(&state, sizeof (state));
2879 
2880 	opterr = 0;
2881 	while ((option = getopt_long(argc, argv, ":pPsSi:o:",
2882 	    show_lopts, NULL)) != -1) {
2883 		switch (option) {
2884 		case 'p':
2885 			if (p_arg)
2886 				die_optdup(option);
2887 
2888 			p_arg = B_TRUE;
2889 			break;
2890 		case 's':
2891 			if (s_arg)
2892 				die_optdup(option);
2893 
2894 			s_arg = B_TRUE;
2895 			break;
2896 		case 'P':
2897 			if (flags != DLADM_OPT_ACTIVE)
2898 				die_optdup(option);
2899 
2900 			flags = DLADM_OPT_PERSIST;
2901 			break;
2902 		case 'S':
2903 			if (S_arg)
2904 				die_optdup(option);
2905 
2906 			S_arg = B_TRUE;
2907 			break;
2908 		case 'o':
2909 			o_arg = B_TRUE;
2910 			fields_str = optarg;
2911 			break;
2912 		case 'i':
2913 			if (i_arg)
2914 				die_optdup(option);
2915 
2916 			i_arg = B_TRUE;
2917 			if (!dladm_str2interval(optarg, &interval))
2918 				die("invalid interval value '%s'", optarg);
2919 			break;
2920 		default:
2921 			die_opterr(optopt, option, use);
2922 			break;
2923 		}
2924 	}
2925 
2926 	if (i_arg && !(s_arg || S_arg))
2927 		die("the option -i can be used only with -s or -S");
2928 
2929 	if (s_arg && S_arg)
2930 		die("the -s option cannot be used with -S");
2931 
2932 	if (s_arg && flags != DLADM_OPT_ACTIVE)
2933 		die("the option -P cannot be used with -s");
2934 
2935 	if (S_arg && (p_arg || flags != DLADM_OPT_ACTIVE))
2936 		die("the option -%c cannot be used with -S", p_arg ? 'p' : 'P');
2937 
2938 	/* get link name (optional last argument) */
2939 	if (optind == (argc-1)) {
2940 		uint32_t	f;
2941 
2942 		if (strlcpy(linkname, argv[optind], MAXLINKNAMELEN)
2943 		    >= MAXLINKNAMELEN) {
2944 			(void) fprintf(stderr,
2945 			    gettext("%s: link name too long\n"),
2946 			    progname);
2947 			dladm_close(handle);
2948 			exit(1);
2949 		}
2950 		if ((status = dladm_name2info(handle, linkname, &linkid, &f,
2951 		    NULL, NULL)) != DLADM_STATUS_OK) {
2952 			die_dlerr(status, "link %s is not valid", linkname);
2953 		}
2954 
2955 		if (!(f & flags)) {
2956 			die_dlerr(DLADM_STATUS_BADARG, "link %s is %s",
2957 			    argv[optind], flags == DLADM_OPT_PERSIST ?
2958 			    "a temporary link" : "temporarily removed");
2959 		}
2960 	} else if (optind != argc) {
2961 		usage();
2962 	}
2963 
2964 	if (p_arg && !o_arg)
2965 		die("-p requires -o");
2966 
2967 	if (S_arg) {
2968 		dladm_continuous(handle, linkid, NULL, interval, LINK_REPORT);
2969 		return;
2970 	}
2971 
2972 	if (p_arg && strcasecmp(fields_str, "all") == 0)
2973 		die("\"-o all\" is invalid with -p");
2974 
2975 	if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) {
2976 		if (s_arg)
2977 			fields_str = allstat_fields;
2978 		else if (flags & DLADM_OPT_ACTIVE)
2979 			fields_str = all_active_fields;
2980 		else
2981 			fields_str = all_inactive_fields;
2982 	}
2983 
2984 	state.ls_parsable = p_arg;
2985 	state.ls_flags = flags;
2986 	state.ls_donefirst = B_FALSE;
2987 
2988 	if (s_arg) {
2989 		link_stats(linkid, interval, fields_str, &state);
2990 		return;
2991 	}
2992 	if (state.ls_parsable)
2993 		ofmtflags |= OFMT_PARSABLE;
2994 	oferr = ofmt_open(fields_str, link_fields, ofmtflags, 0, &ofmt);
2995 	dladm_ofmt_check(oferr, state.ls_parsable, ofmt);
2996 	state.ls_ofmt = ofmt;
2997 
2998 	if (linkid == DATALINK_ALL_LINKID) {
2999 		(void) dladm_walk_datalink_id(show_link, handle, &state,
3000 		    DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE, flags);
3001 	} else {
3002 		(void) show_link(handle, linkid, &state);
3003 		if (state.ls_status != DLADM_STATUS_OK) {
3004 			die_dlerr(state.ls_status, "failed to show link %s",
3005 			    argv[optind]);
3006 		}
3007 	}
3008 	ofmt_close(ofmt);
3009 }
3010 
3011 static void
3012 do_show_aggr(int argc, char *argv[], const char *use)
3013 {
3014 	boolean_t		L_arg = B_FALSE;
3015 	boolean_t		s_arg = B_FALSE;
3016 	boolean_t		i_arg = B_FALSE;
3017 	boolean_t		p_arg = B_FALSE;
3018 	boolean_t		x_arg = B_FALSE;
3019 	show_grp_state_t	state;
3020 	uint32_t		flags = DLADM_OPT_ACTIVE;
3021 	datalink_id_t		linkid = DATALINK_ALL_LINKID;
3022 	int			option;
3023 	uint32_t		interval = 0;
3024 	int			key;
3025 	dladm_status_t		status;
3026 	boolean_t		o_arg = B_FALSE;
3027 	char			*fields_str = NULL;
3028 	char			*all_fields =
3029 	    "link,policy,addrpolicy,lacpactivity,lacptimer,flags";
3030 	char			*all_lacp_fields =
3031 	    "link,port,aggregatable,sync,coll,dist,defaulted,expired";
3032 	char			*all_stats_fields =
3033 	    "link,port,ipackets,rbytes,opackets,obytes,ipktdist,opktdist";
3034 	char			*all_extended_fields =
3035 	    "link,port,speed,duplex,state,address,portstate";
3036 	ofmt_field_t		*pf;
3037 	ofmt_handle_t		ofmt;
3038 	ofmt_status_t		oferr;
3039 	uint_t			ofmtflags = 0;
3040 
3041 	opterr = 0;
3042 	while ((option = getopt_long(argc, argv, ":LpPxsi:o:",
3043 	    show_lopts, NULL)) != -1) {
3044 		switch (option) {
3045 		case 'L':
3046 			if (L_arg)
3047 				die_optdup(option);
3048 
3049 			L_arg = B_TRUE;
3050 			break;
3051 		case 'p':
3052 			if (p_arg)
3053 				die_optdup(option);
3054 
3055 			p_arg = B_TRUE;
3056 			break;
3057 		case 'x':
3058 			if (x_arg)
3059 				die_optdup(option);
3060 
3061 			x_arg = B_TRUE;
3062 			break;
3063 		case 'P':
3064 			if (flags != DLADM_OPT_ACTIVE)
3065 				die_optdup(option);
3066 
3067 			flags = DLADM_OPT_PERSIST;
3068 			break;
3069 		case 's':
3070 			if (s_arg)
3071 				die_optdup(option);
3072 
3073 			s_arg = B_TRUE;
3074 			break;
3075 		case 'o':
3076 			o_arg = B_TRUE;
3077 			fields_str = optarg;
3078 			break;
3079 		case 'i':
3080 			if (i_arg)
3081 				die_optdup(option);
3082 
3083 			i_arg = B_TRUE;
3084 			if (!dladm_str2interval(optarg, &interval))
3085 				die("invalid interval value '%s'", optarg);
3086 			break;
3087 		default:
3088 			die_opterr(optopt, option, use);
3089 			break;
3090 		}
3091 	}
3092 
3093 	if (p_arg && !o_arg)
3094 		die("-p requires -o");
3095 
3096 	if (p_arg && strcasecmp(fields_str, "all") == 0)
3097 		die("\"-o all\" is invalid with -p");
3098 
3099 	if (i_arg && !s_arg)
3100 		die("the option -i can be used only with -s");
3101 
3102 	if (s_arg && (L_arg || p_arg || x_arg || flags != DLADM_OPT_ACTIVE)) {
3103 		die("the option -%c cannot be used with -s",
3104 		    L_arg ? 'L' : (p_arg ? 'p' : (x_arg ? 'x' : 'P')));
3105 	}
3106 
3107 	if (L_arg && flags != DLADM_OPT_ACTIVE)
3108 		die("the option -P cannot be used with -L");
3109 
3110 	if (x_arg && (L_arg || flags != DLADM_OPT_ACTIVE))
3111 		die("the option -%c cannot be used with -x", L_arg ? 'L' : 'P');
3112 
3113 	/* get aggregation key or aggrname (optional last argument) */
3114 	if (optind == (argc-1)) {
3115 		if (!str2int(argv[optind], &key)) {
3116 			status = dladm_name2info(handle, argv[optind],
3117 			    &linkid, NULL, NULL, NULL);
3118 		} else {
3119 			status = dladm_key2linkid(handle, (uint16_t)key,
3120 			    &linkid, DLADM_OPT_ACTIVE);
3121 		}
3122 
3123 		if (status != DLADM_STATUS_OK)
3124 			die("non-existent aggregation '%s'", argv[optind]);
3125 
3126 	} else if (optind != argc) {
3127 		usage();
3128 	}
3129 
3130 	bzero(&state, sizeof (state));
3131 	state.gs_lacp = L_arg;
3132 	state.gs_stats = s_arg;
3133 	state.gs_flags = flags;
3134 	state.gs_parsable = p_arg;
3135 	state.gs_extended = x_arg;
3136 
3137 	if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) {
3138 		if (state.gs_lacp)
3139 			fields_str = all_lacp_fields;
3140 		else if (state.gs_stats)
3141 			fields_str = all_stats_fields;
3142 		else if (state.gs_extended)
3143 			fields_str = all_extended_fields;
3144 		else
3145 			fields_str = all_fields;
3146 	}
3147 
3148 	if (state.gs_lacp) {
3149 		pf = aggr_l_fields;
3150 	} else if (state.gs_stats) {
3151 		pf = aggr_s_fields;
3152 	} else if (state.gs_extended) {
3153 		pf = aggr_x_fields;
3154 	} else {
3155 		pf = laggr_fields;
3156 	}
3157 
3158 	if (state.gs_parsable)
3159 		ofmtflags |= OFMT_PARSABLE;
3160 	oferr = ofmt_open(fields_str, pf, ofmtflags, 0, &ofmt);
3161 	dladm_ofmt_check(oferr, state.gs_parsable, ofmt);
3162 	state.gs_ofmt = ofmt;
3163 
3164 	if (s_arg) {
3165 		aggr_stats(linkid, &state, interval);
3166 		ofmt_close(ofmt);
3167 		return;
3168 	}
3169 
3170 	if (linkid == DATALINK_ALL_LINKID) {
3171 		(void) dladm_walk_datalink_id(show_aggr, handle, &state,
3172 		    DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE, flags);
3173 	} else {
3174 		(void) show_aggr(handle, linkid, &state);
3175 		if (state.gs_status != DLADM_STATUS_OK) {
3176 			die_dlerr(state.gs_status, "failed to show aggr %s",
3177 			    argv[optind]);
3178 		}
3179 	}
3180 	ofmt_close(ofmt);
3181 }
3182 
3183 static dladm_status_t
3184 print_phys_default(show_state_t *state, datalink_id_t linkid,
3185     const char *link, uint32_t flags, uint32_t media)
3186 {
3187 	dladm_phys_attr_t dpa;
3188 	dladm_status_t status;
3189 	link_fields_buf_t pattr;
3190 
3191 	status = dladm_phys_info(handle, linkid, &dpa, state->ls_flags);
3192 	if (status != DLADM_STATUS_OK)
3193 		goto done;
3194 
3195 	(void) snprintf(pattr.link_phys_device,
3196 	    sizeof (pattr.link_phys_device), "%s", dpa.dp_dev);
3197 	(void) dladm_media2str(media, pattr.link_phys_media);
3198 	if (state->ls_flags == DLADM_OPT_ACTIVE) {
3199 		boolean_t	islink;
3200 
3201 		if (!dpa.dp_novanity) {
3202 			(void) strlcpy(pattr.link_name, link,
3203 			    sizeof (pattr.link_name));
3204 			islink = B_TRUE;
3205 		} else {
3206 			/*
3207 			 * This is a physical link that does not have
3208 			 * vanity naming support.
3209 			 */
3210 			(void) strlcpy(pattr.link_name, dpa.dp_dev,
3211 			    sizeof (pattr.link_name));
3212 			islink = B_FALSE;
3213 		}
3214 
3215 		(void) get_linkstate(pattr.link_name, islink,
3216 		    pattr.link_phys_state);
3217 		(void) snprintf(pattr.link_phys_speed,
3218 		    sizeof (pattr.link_phys_speed), "%u",
3219 		    (uint_t)((get_ifspeed(pattr.link_name,
3220 		    islink)) / 1000000ull));
3221 		(void) get_linkduplex(pattr.link_name, islink,
3222 		    pattr.link_phys_duplex);
3223 	} else {
3224 		(void) snprintf(pattr.link_name, sizeof (pattr.link_name),
3225 		    "%s", link);
3226 		(void) snprintf(pattr.link_flags, sizeof (pattr.link_flags),
3227 		    "%c----", flags & DLADM_OPT_ACTIVE ? '-' : 'r');
3228 	}
3229 
3230 	ofmt_print(state->ls_ofmt, &pattr);
3231 
3232 done:
3233 	return (status);
3234 }
3235 
3236 typedef struct {
3237 	show_state_t	*ms_state;
3238 	char		*ms_link;
3239 	dladm_macaddr_attr_t *ms_mac_attr;
3240 } print_phys_mac_state_t;
3241 
3242 /*
3243  *  callback for ofmt_print()
3244  */
3245 static boolean_t
3246 print_phys_one_mac_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
3247 {
3248 	print_phys_mac_state_t *mac_state = ofarg->ofmt_cbarg;
3249 	dladm_macaddr_attr_t *attr = mac_state->ms_mac_attr;
3250 	boolean_t is_primary = (attr->ma_slot == 0);
3251 	boolean_t is_parsable = mac_state->ms_state->ls_parsable;
3252 
3253 	switch (ofarg->ofmt_id) {
3254 	case PHYS_M_LINK:
3255 		(void) snprintf(buf, bufsize, "%s",
3256 		    (is_primary || is_parsable) ? mac_state->ms_link : " ");
3257 		break;
3258 	case PHYS_M_SLOT:
3259 		if (is_primary)
3260 			(void) snprintf(buf, bufsize, gettext("primary"));
3261 		else
3262 			(void) snprintf(buf, bufsize, "%d", attr->ma_slot);
3263 		break;
3264 	case PHYS_M_ADDRESS:
3265 		(void) dladm_aggr_macaddr2str(attr->ma_addr, buf);
3266 		break;
3267 	case PHYS_M_INUSE:
3268 		(void) snprintf(buf, bufsize, "%s",
3269 		    attr->ma_flags & DLADM_MACADDR_USED ? gettext("yes") :
3270 		    gettext("no"));
3271 		break;
3272 	case PHYS_M_CLIENT:
3273 		/*
3274 		 * CR 6678526: resolve link id to actual link name if
3275 		 * it is valid.
3276 		 */
3277 		(void) snprintf(buf, bufsize, "%s", attr->ma_client_name);
3278 		break;
3279 	}
3280 
3281 	return (B_TRUE);
3282 }
3283 
3284 typedef struct {
3285 	show_state_t	*hs_state;
3286 	char		*hs_link;
3287 	dladm_hwgrp_attr_t *hs_grp_attr;
3288 } print_phys_hwgrp_state_t;
3289 
3290 static boolean_t
3291 print_phys_one_hwgrp_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
3292 {
3293 	print_phys_hwgrp_state_t *hg_state = ofarg->ofmt_cbarg;
3294 	dladm_hwgrp_attr_t *attr = hg_state->hs_grp_attr;
3295 
3296 	switch (ofarg->ofmt_id) {
3297 	case PHYS_H_LINK:
3298 		(void) snprintf(buf, bufsize, "%s", attr->hg_link_name);
3299 		break;
3300 	case PHYS_H_GROUP:
3301 		(void) snprintf(buf, bufsize, "%d", attr->hg_grp_num);
3302 		break;
3303 	case PHYS_H_GRPTYPE:
3304 		(void) snprintf(buf, bufsize, "%s",
3305 		    attr->hg_grp_type == DLADM_HWGRP_TYPE_RX ? "RX" : "TX");
3306 		break;
3307 	case PHYS_H_RINGS:
3308 		(void) snprintf(buf, bufsize, "%d", attr->hg_n_rings);
3309 		break;
3310 	case PHYS_H_CLIENTS:
3311 		if (attr->hg_client_names[0] == '\0') {
3312 			(void) snprintf(buf, bufsize, "--");
3313 		} else {
3314 			(void) snprintf(buf, bufsize, "%s ",
3315 			    attr->hg_client_names);
3316 		}
3317 		break;
3318 	}
3319 
3320 	return (B_TRUE);
3321 }
3322 
3323 /*
3324  * callback for dladm_walk_macaddr, invoked for each MAC address slot
3325  */
3326 static boolean_t
3327 print_phys_mac_callback(void *arg, dladm_macaddr_attr_t *attr)
3328 {
3329 	print_phys_mac_state_t *mac_state = arg;
3330 	show_state_t *state = mac_state->ms_state;
3331 
3332 	mac_state->ms_mac_attr = attr;
3333 	ofmt_print(state->ls_ofmt, mac_state);
3334 
3335 	return (B_TRUE);
3336 }
3337 
3338 /*
3339  * invoked by show-phys -m for each physical data-link
3340  */
3341 static dladm_status_t
3342 print_phys_mac(show_state_t *state, datalink_id_t linkid, char *link)
3343 {
3344 	print_phys_mac_state_t mac_state;
3345 
3346 	mac_state.ms_state = state;
3347 	mac_state.ms_link = link;
3348 
3349 	return (dladm_walk_macaddr(handle, linkid, &mac_state,
3350 	    print_phys_mac_callback));
3351 }
3352 
3353 /*
3354  * callback for dladm_walk_hwgrp, invoked for each MAC hwgrp
3355  */
3356 static boolean_t
3357 print_phys_hwgrp_callback(void *arg, dladm_hwgrp_attr_t *attr)
3358 {
3359 	print_phys_hwgrp_state_t *hwgrp_state = arg;
3360 	show_state_t *state = hwgrp_state->hs_state;
3361 
3362 	hwgrp_state->hs_grp_attr = attr;
3363 	ofmt_print(state->ls_ofmt, hwgrp_state);
3364 
3365 	return (B_TRUE);
3366 }
3367 
3368 /* invoked by show-phys -H for each physical data-link */
3369 static dladm_status_t
3370 print_phys_hwgrp(show_state_t *state, datalink_id_t linkid, char *link)
3371 {
3372 	print_phys_hwgrp_state_t hwgrp_state;
3373 
3374 	hwgrp_state.hs_state = state;
3375 	hwgrp_state.hs_link = link;
3376 	return (dladm_walk_hwgrp(handle, linkid, &hwgrp_state,
3377 	    print_phys_hwgrp_callback));
3378 }
3379 
3380 static dladm_status_t
3381 print_phys(show_state_t *state, datalink_id_t linkid)
3382 {
3383 	char			link[MAXLINKNAMELEN];
3384 	uint32_t		flags;
3385 	dladm_status_t		status;
3386 	datalink_class_t	class;
3387 	uint32_t		media;
3388 
3389 	if ((status = dladm_datalink_id2info(handle, linkid, &flags, &class,
3390 	    &media, link, MAXLINKNAMELEN)) != DLADM_STATUS_OK) {
3391 		goto done;
3392 	}
3393 
3394 	if (class != DATALINK_CLASS_PHYS) {
3395 		status = DLADM_STATUS_BADARG;
3396 		goto done;
3397 	}
3398 
3399 	if (!(state->ls_flags & flags)) {
3400 		status = DLADM_STATUS_NOTFOUND;
3401 		goto done;
3402 	}
3403 
3404 	if (state->ls_mac)
3405 		status = print_phys_mac(state, linkid, link);
3406 	else if (state->ls_hwgrp)
3407 		status = print_phys_hwgrp(state, linkid, link);
3408 	else
3409 		status = print_phys_default(state, linkid, link, flags, media);
3410 
3411 done:
3412 	return (status);
3413 }
3414 
3415 /* ARGSUSED */
3416 static int
3417 show_phys(dladm_handle_t dh, datalink_id_t linkid, void *arg)
3418 {
3419 	show_state_t	*state = arg;
3420 
3421 	state->ls_status = print_phys(state, linkid);
3422 	return (DLADM_WALK_CONTINUE);
3423 }
3424 
3425 /*
3426  * Print the active topology information.
3427  */
3428 static dladm_status_t
3429 print_vlan(show_state_t *state, datalink_id_t linkid, link_fields_buf_t *l)
3430 {
3431 	dladm_vlan_attr_t	vinfo;
3432 	uint32_t		flags;
3433 	dladm_status_t		status;
3434 
3435 	if ((status = dladm_datalink_id2info(handle, linkid, &flags, NULL, NULL,
3436 	    l->link_name, sizeof (l->link_name))) != DLADM_STATUS_OK) {
3437 		goto done;
3438 	}
3439 
3440 	if (!(state->ls_flags & flags)) {
3441 		status = DLADM_STATUS_NOTFOUND;
3442 		goto done;
3443 	}
3444 
3445 	if ((status = dladm_vlan_info(handle, linkid, &vinfo,
3446 	    state->ls_flags)) != DLADM_STATUS_OK ||
3447 	    (status = dladm_datalink_id2info(handle, vinfo.dv_linkid, NULL,
3448 	    NULL, NULL, l->link_over, sizeof (l->link_over))) !=
3449 	    DLADM_STATUS_OK) {
3450 		goto done;
3451 	}
3452 
3453 	(void) snprintf(l->link_vlan_vid, sizeof (l->link_vlan_vid), "%d",
3454 	    vinfo.dv_vid);
3455 	(void) snprintf(l->link_flags, sizeof (l->link_flags), "%c----",
3456 	    vinfo.dv_force ? 'f' : '-');
3457 
3458 done:
3459 	return (status);
3460 }
3461 
3462 /* ARGSUSED */
3463 static int
3464 show_vlan(dladm_handle_t dh, datalink_id_t linkid, void *arg)
3465 {
3466 	show_state_t		*state = arg;
3467 	dladm_status_t		status;
3468 	link_fields_buf_t	lbuf;
3469 
3470 	bzero(&lbuf, sizeof (link_fields_buf_t));
3471 	status = print_vlan(state, linkid, &lbuf);
3472 	if (status != DLADM_STATUS_OK)
3473 		goto done;
3474 
3475 	ofmt_print(state->ls_ofmt, &lbuf);
3476 
3477 done:
3478 	state->ls_status = status;
3479 	return (DLADM_WALK_CONTINUE);
3480 }
3481 
3482 static void
3483 do_show_phys(int argc, char *argv[], const char *use)
3484 {
3485 	int		option;
3486 	uint32_t	flags = DLADM_OPT_ACTIVE;
3487 	boolean_t	p_arg = B_FALSE;
3488 	boolean_t	o_arg = B_FALSE;
3489 	boolean_t	m_arg = B_FALSE;
3490 	boolean_t	H_arg = B_FALSE;
3491 	datalink_id_t	linkid = DATALINK_ALL_LINKID;
3492 	show_state_t	state;
3493 	dladm_status_t	status;
3494 	char		*fields_str = NULL;
3495 	char		*all_active_fields =
3496 	    "link,media,state,speed,duplex,device";
3497 	char		*all_inactive_fields = "link,device,media,flags";
3498 	char		*all_mac_fields = "link,slot,address,inuse,client";
3499 	char		*all_hwgrp_fields =
3500 	    "link,group,grouptype,rings,clients";
3501 	ofmt_field_t	*pf;
3502 	ofmt_handle_t	ofmt;
3503 	ofmt_status_t	oferr;
3504 	uint_t		ofmtflags = 0;
3505 
3506 	bzero(&state, sizeof (state));
3507 	opterr = 0;
3508 	while ((option = getopt_long(argc, argv, ":pPo:mH",
3509 	    show_lopts, NULL)) != -1) {
3510 		switch (option) {
3511 		case 'p':
3512 			if (p_arg)
3513 				die_optdup(option);
3514 
3515 			p_arg = B_TRUE;
3516 			break;
3517 		case 'P':
3518 			if (flags != DLADM_OPT_ACTIVE)
3519 				die_optdup(option);
3520 
3521 			flags = DLADM_OPT_PERSIST;
3522 			break;
3523 		case 'o':
3524 			o_arg = B_TRUE;
3525 			fields_str = optarg;
3526 			break;
3527 		case 'm':
3528 			m_arg = B_TRUE;
3529 			break;
3530 		case 'H':
3531 			H_arg = B_TRUE;
3532 			break;
3533 		default:
3534 			die_opterr(optopt, option, use);
3535 			break;
3536 		}
3537 	}
3538 
3539 	if (p_arg && !o_arg)
3540 		die("-p requires -o");
3541 
3542 	if (m_arg && H_arg)
3543 		die("-m cannot combine with -H");
3544 
3545 	if (p_arg && strcasecmp(fields_str, "all") == 0)
3546 		die("\"-o all\" is invalid with -p");
3547 
3548 	/* get link name (optional last argument) */
3549 	if (optind == (argc-1)) {
3550 		if ((status = dladm_name2info(handle, argv[optind], &linkid,
3551 		    NULL, NULL, NULL)) != DLADM_STATUS_OK) {
3552 			die_dlerr(status, "link %s is not valid", argv[optind]);
3553 		}
3554 	} else if (optind != argc) {
3555 		usage();
3556 	}
3557 
3558 	state.ls_parsable = p_arg;
3559 	state.ls_flags = flags;
3560 	state.ls_donefirst = B_FALSE;
3561 	state.ls_mac = m_arg;
3562 	state.ls_hwgrp = H_arg;
3563 
3564 	if (m_arg && !(flags & DLADM_OPT_ACTIVE)) {
3565 		/*
3566 		 * We can only display the factory MAC addresses of
3567 		 * active data-links.
3568 		 */
3569 		die("-m not compatible with -P");
3570 	}
3571 
3572 	if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) {
3573 		if (state.ls_mac)
3574 			fields_str = all_mac_fields;
3575 		else if (state.ls_hwgrp)
3576 			fields_str = all_hwgrp_fields;
3577 		else if (state.ls_flags & DLADM_OPT_ACTIVE) {
3578 			fields_str = all_active_fields;
3579 		} else {
3580 			fields_str = all_inactive_fields;
3581 		}
3582 	}
3583 
3584 	if (state.ls_mac) {
3585 		pf = phys_m_fields;
3586 	} else if (state.ls_hwgrp) {
3587 		pf = phys_h_fields;
3588 	} else {
3589 		pf = phys_fields;
3590 	}
3591 
3592 	if (state.ls_parsable)
3593 		ofmtflags |= OFMT_PARSABLE;
3594 	oferr = ofmt_open(fields_str, pf, ofmtflags, 0, &ofmt);
3595 	dladm_ofmt_check(oferr, state.ls_parsable, ofmt);
3596 	state.ls_ofmt = ofmt;
3597 
3598 	if (linkid == DATALINK_ALL_LINKID) {
3599 		(void) dladm_walk_datalink_id(show_phys, handle, &state,
3600 		    DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE, flags);
3601 	} else {
3602 		(void) show_phys(handle, linkid, &state);
3603 		if (state.ls_status != DLADM_STATUS_OK) {
3604 			die_dlerr(state.ls_status,
3605 			    "failed to show physical link %s", argv[optind]);
3606 		}
3607 	}
3608 	ofmt_close(ofmt);
3609 }
3610 
3611 static void
3612 do_show_vlan(int argc, char *argv[], const char *use)
3613 {
3614 	int		option;
3615 	uint32_t	flags = DLADM_OPT_ACTIVE;
3616 	boolean_t	p_arg = B_FALSE;
3617 	datalink_id_t	linkid = DATALINK_ALL_LINKID;
3618 	show_state_t	state;
3619 	dladm_status_t	status;
3620 	boolean_t	o_arg = B_FALSE;
3621 	char		*fields_str = NULL;
3622 	ofmt_handle_t	ofmt;
3623 	ofmt_status_t	oferr;
3624 	uint_t		ofmtflags = 0;
3625 
3626 	bzero(&state, sizeof (state));
3627 
3628 	opterr = 0;
3629 	while ((option = getopt_long(argc, argv, ":pPo:",
3630 	    show_lopts, NULL)) != -1) {
3631 		switch (option) {
3632 		case 'p':
3633 			if (p_arg)
3634 				die_optdup(option);
3635 
3636 			p_arg = B_TRUE;
3637 			break;
3638 		case 'P':
3639 			if (flags != DLADM_OPT_ACTIVE)
3640 				die_optdup(option);
3641 
3642 			flags = DLADM_OPT_PERSIST;
3643 			break;
3644 		case 'o':
3645 			o_arg = B_TRUE;
3646 			fields_str = optarg;
3647 			break;
3648 		default:
3649 			die_opterr(optopt, option, use);
3650 			break;
3651 		}
3652 	}
3653 
3654 	/* get link name (optional last argument) */
3655 	if (optind == (argc-1)) {
3656 		if ((status = dladm_name2info(handle, argv[optind], &linkid,
3657 		    NULL, NULL, NULL)) != DLADM_STATUS_OK) {
3658 			die_dlerr(status, "link %s is not valid", argv[optind]);
3659 		}
3660 	} else if (optind != argc) {
3661 		usage();
3662 	}
3663 
3664 	state.ls_parsable = p_arg;
3665 	state.ls_flags = flags;
3666 	state.ls_donefirst = B_FALSE;
3667 
3668 	if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0))
3669 		fields_str = NULL;
3670 
3671 	if (state.ls_parsable)
3672 		ofmtflags |= OFMT_PARSABLE;
3673 	oferr = ofmt_open(fields_str, vlan_fields, ofmtflags, 0, &ofmt);
3674 	dladm_ofmt_check(oferr, state.ls_parsable, ofmt);
3675 	state.ls_ofmt = ofmt;
3676 
3677 	if (linkid == DATALINK_ALL_LINKID) {
3678 		(void) dladm_walk_datalink_id(show_vlan, handle, &state,
3679 		    DATALINK_CLASS_VLAN, DATALINK_ANY_MEDIATYPE, flags);
3680 	} else {
3681 		(void) show_vlan(handle, linkid, &state);
3682 		if (state.ls_status != DLADM_STATUS_OK) {
3683 			die_dlerr(state.ls_status, "failed to show vlan %s",
3684 			    argv[optind]);
3685 		}
3686 	}
3687 	ofmt_close(ofmt);
3688 }
3689 
3690 static void
3691 do_create_vnic(int argc, char *argv[], const char *use)
3692 {
3693 	datalink_id_t		linkid, dev_linkid;
3694 	char			devname[MAXLINKNAMELEN];
3695 	char			name[MAXLINKNAMELEN];
3696 	boolean_t		l_arg = B_FALSE;
3697 	uint32_t		flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
3698 	char			*altroot = NULL;
3699 	int			option;
3700 	char			*endp = NULL;
3701 	dladm_status_t		status;
3702 	vnic_mac_addr_type_t	mac_addr_type = VNIC_MAC_ADDR_TYPE_AUTO;
3703 	uchar_t			*mac_addr;
3704 	int			mac_slot = -1, maclen = 0, mac_prefix_len = 0;
3705 	char			propstr[DLADM_STRSIZE];
3706 	dladm_arg_list_t	*proplist = NULL;
3707 	int			vid = 0;
3708 
3709 	opterr = 0;
3710 	bzero(propstr, DLADM_STRSIZE);
3711 
3712 	while ((option = getopt_long(argc, argv, ":tfR:l:m:n:p:r:v:H",
3713 	    vnic_lopts, NULL)) != -1) {
3714 		switch (option) {
3715 		case 't':
3716 			flags &= ~DLADM_OPT_PERSIST;
3717 			break;
3718 		case 'R':
3719 			altroot = optarg;
3720 			break;
3721 		case 'l':
3722 			if (strlcpy(devname, optarg, MAXLINKNAMELEN) >=
3723 			    MAXLINKNAMELEN)
3724 				die("link name too long");
3725 			l_arg = B_TRUE;
3726 			break;
3727 		case 'm':
3728 			if (strcmp(optarg, "fixed") == 0) {
3729 				/*
3730 				 * A fixed MAC address must be specified
3731 				 * by its value, not by the keyword 'fixed'.
3732 				 */
3733 				die("'fixed' is not a valid MAC address");
3734 			}
3735 			if (dladm_vnic_str2macaddrtype(optarg,
3736 			    &mac_addr_type) != DLADM_STATUS_OK) {
3737 				mac_addr_type = VNIC_MAC_ADDR_TYPE_FIXED;
3738 				/* MAC address specified by value */
3739 				mac_addr = _link_aton(optarg, &maclen);
3740 				if (mac_addr == NULL) {
3741 					if (maclen == -1)
3742 						die("invalid MAC address");
3743 					else
3744 						die("out of memory");
3745 				}
3746 			}
3747 			break;
3748 		case 'n':
3749 			errno = 0;
3750 			mac_slot = (int)strtol(optarg, &endp, 10);
3751 			if (errno != 0 || *endp != '\0')
3752 				die("invalid slot number");
3753 			break;
3754 		case 'p':
3755 			(void) strlcat(propstr, optarg, DLADM_STRSIZE);
3756 			if (strlcat(propstr, ",", DLADM_STRSIZE) >=
3757 			    DLADM_STRSIZE)
3758 				die("property list too long '%s'", propstr);
3759 			break;
3760 		case 'r':
3761 			mac_addr = _link_aton(optarg, &mac_prefix_len);
3762 			if (mac_addr == NULL) {
3763 				if (mac_prefix_len == -1)
3764 					die("invalid MAC address");
3765 				else
3766 					die("out of memory");
3767 			}
3768 			break;
3769 		case 'v':
3770 			if (vid != 0)
3771 				die_optdup(option);
3772 
3773 			if (!str2int(optarg, &vid) || vid < 1 || vid > 4094)
3774 				die("invalid VLAN identifier '%s'", optarg);
3775 
3776 			break;
3777 		case 'f':
3778 			flags |= DLADM_OPT_FORCE;
3779 			break;
3780 		case 'H':
3781 			flags |= DLADM_OPT_HWRINGS;
3782 			break;
3783 		default:
3784 			die_opterr(optopt, option, use);
3785 		}
3786 	}
3787 
3788 	/*
3789 	 * 'f' - force, flag can be specified only with 'v' - vlan.
3790 	 */
3791 	if ((flags & DLADM_OPT_FORCE) != 0 && vid == 0)
3792 		die("-f option can only be used with -v");
3793 
3794 	if (mac_prefix_len != 0 && mac_addr_type != VNIC_MAC_ADDR_TYPE_RANDOM &&
3795 	    mac_addr_type != VNIC_MAC_ADDR_TYPE_FIXED)
3796 		usage();
3797 
3798 	/* check required options */
3799 	if (!l_arg)
3800 		usage();
3801 
3802 	if (mac_slot != -1 && mac_addr_type != VNIC_MAC_ADDR_TYPE_FACTORY)
3803 		usage();
3804 
3805 	/* the VNIC id is the required operand */
3806 	if (optind != (argc - 1))
3807 		usage();
3808 
3809 	if (strlcpy(name, argv[optind], MAXLINKNAMELEN) >= MAXLINKNAMELEN)
3810 		die("link name too long '%s'", argv[optind]);
3811 
3812 	if (!dladm_valid_linkname(name))
3813 		die("invalid link name '%s'", argv[optind]);
3814 
3815 	if (altroot != NULL)
3816 		altroot_cmd(altroot, argc, argv);
3817 
3818 	if (dladm_name2info(handle, devname, &dev_linkid, NULL, NULL, NULL) !=
3819 	    DLADM_STATUS_OK)
3820 		die("invalid link name '%s'", devname);
3821 
3822 	if (dladm_parse_link_props(propstr, &proplist, B_FALSE)
3823 	    != DLADM_STATUS_OK)
3824 		die("invalid vnic property");
3825 
3826 	status = dladm_vnic_create(handle, name, dev_linkid, mac_addr_type,
3827 	    mac_addr, maclen, &mac_slot, mac_prefix_len, vid, &linkid, proplist,
3828 	    flags);
3829 	if (status != DLADM_STATUS_OK)
3830 		die_dlerr(status, "vnic creation over %s failed", devname);
3831 
3832 	dladm_free_props(proplist);
3833 }
3834 
3835 static void
3836 do_etherstub_check(const char *name, datalink_id_t linkid, boolean_t etherstub,
3837     uint32_t flags)
3838 {
3839 	boolean_t is_etherstub;
3840 	dladm_vnic_attr_t attr;
3841 
3842 	if (dladm_vnic_info(handle, linkid, &attr, flags) != DLADM_STATUS_OK) {
3843 		/*
3844 		 * Let the delete continue anyway.
3845 		 */
3846 		return;
3847 	}
3848 	is_etherstub = (attr.va_link_id == DATALINK_INVALID_LINKID);
3849 	if (is_etherstub != etherstub) {
3850 		die("'%s' is not %s", name,
3851 		    (is_etherstub ? "a vnic" : "an etherstub"));
3852 	}
3853 }
3854 
3855 static void
3856 do_delete_vnic_common(int argc, char *argv[], const char *use,
3857     boolean_t etherstub)
3858 {
3859 	int option;
3860 	uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
3861 	datalink_id_t linkid;
3862 	char *altroot = NULL;
3863 	dladm_status_t status;
3864 
3865 	opterr = 0;
3866 	while ((option = getopt_long(argc, argv, ":R:t", lopts,
3867 	    NULL)) != -1) {
3868 		switch (option) {
3869 		case 't':
3870 			flags &= ~DLADM_OPT_PERSIST;
3871 			break;
3872 		case 'R':
3873 			altroot = optarg;
3874 			break;
3875 		default:
3876 			die_opterr(optopt, option, use);
3877 		}
3878 	}
3879 
3880 	/* get vnic name (required last argument) */
3881 	if (optind != (argc - 1))
3882 		usage();
3883 
3884 	if (altroot != NULL)
3885 		altroot_cmd(altroot, argc, argv);
3886 
3887 	status = dladm_name2info(handle, argv[optind], &linkid, NULL, NULL,
3888 	    NULL);
3889 	if (status != DLADM_STATUS_OK)
3890 		die("invalid link name '%s'", argv[optind]);
3891 
3892 	if ((flags & DLADM_OPT_ACTIVE) != 0) {
3893 		do_etherstub_check(argv[optind], linkid, etherstub,
3894 		    DLADM_OPT_ACTIVE);
3895 	}
3896 	if ((flags & DLADM_OPT_PERSIST) != 0) {
3897 		do_etherstub_check(argv[optind], linkid, etherstub,
3898 		    DLADM_OPT_PERSIST);
3899 	}
3900 
3901 	status = dladm_vnic_delete(handle, linkid, flags);
3902 	if (status != DLADM_STATUS_OK)
3903 		die_dlerr(status, "vnic deletion failed");
3904 }
3905 
3906 static void
3907 do_delete_vnic(int argc, char *argv[], const char *use)
3908 {
3909 	do_delete_vnic_common(argc, argv, use, B_FALSE);
3910 }
3911 
3912 /* ARGSUSED */
3913 static void
3914 do_up_vnic_common(int argc, char *argv[], const char *use, boolean_t vlan)
3915 {
3916 	datalink_id_t	linkid = DATALINK_ALL_LINKID;
3917 	dladm_status_t	status;
3918 	char 		*type;
3919 
3920 	type = vlan ? "vlan" : "vnic";
3921 
3922 	/*
3923 	 * get the id or the name of the vnic/vlan (optional last argument)
3924 	 */
3925 	if (argc == 2) {
3926 		status = dladm_name2info(handle, argv[1], &linkid, NULL, NULL,
3927 		    NULL);
3928 		if (status != DLADM_STATUS_OK)
3929 			goto done;
3930 
3931 	} else if (argc > 2) {
3932 		usage();
3933 	}
3934 
3935 	if (vlan)
3936 		status = dladm_vlan_up(handle, linkid);
3937 	else
3938 		status = dladm_vnic_up(handle, linkid, 0);
3939 
3940 done:
3941 	if (status != DLADM_STATUS_OK) {
3942 		if (argc == 2) {
3943 			die_dlerr(status,
3944 			    "could not bring up %s '%s'", type, argv[1]);
3945 		} else {
3946 			die_dlerr(status, "could not bring %ss up", type);
3947 		}
3948 	}
3949 }
3950 
3951 static void
3952 do_up_vnic(int argc, char *argv[], const char *use)
3953 {
3954 	do_up_vnic_common(argc, argv, use, B_FALSE);
3955 }
3956 
3957 static void
3958 dump_vnics_head(const char *dev)
3959 {
3960 	if (strlen(dev))
3961 		(void) printf("%s", dev);
3962 
3963 	(void) printf("\tipackets  rbytes      opackets  obytes          ");
3964 
3965 	if (strlen(dev))
3966 		(void) printf("%%ipkts  %%opkts\n");
3967 	else
3968 		(void) printf("\n");
3969 }
3970 
3971 static void
3972 dump_vnic_stat(const char *name, datalink_id_t vnic_id,
3973     show_vnic_state_t *state, pktsum_t *vnic_stats, pktsum_t *tot_stats)
3974 {
3975 	pktsum_t	diff_stats;
3976 	pktsum_t	*old_stats = &state->vs_prevstats[vnic_id];
3977 
3978 	dladm_stats_diff(&diff_stats, vnic_stats, old_stats);
3979 
3980 	(void) printf("%s", name);
3981 
3982 	(void) printf("\t%-10llu", diff_stats.ipackets);
3983 	(void) printf("%-12llu", diff_stats.rbytes);
3984 	(void) printf("%-10llu", diff_stats.opackets);
3985 	(void) printf("%-12llu", diff_stats.obytes);
3986 
3987 	if (tot_stats) {
3988 		if (tot_stats->ipackets == 0) {
3989 			(void) printf("\t-");
3990 		} else {
3991 			(void) printf("\t%-6.1f", (double)diff_stats.ipackets/
3992 			    (double)tot_stats->ipackets * 100);
3993 		}
3994 		if (tot_stats->opackets == 0) {
3995 			(void) printf("\t-");
3996 		} else {
3997 			(void) printf("\t%-6.1f", (double)diff_stats.opackets/
3998 			    (double)tot_stats->opackets * 100);
3999 		}
4000 	}
4001 	(void) printf("\n");
4002 
4003 	*old_stats = *vnic_stats;
4004 }
4005 
4006 /*
4007  * Called from the walker dladm_vnic_walk_sys() for each vnic to display
4008  * vnic information or statistics.
4009  */
4010 static dladm_status_t
4011 print_vnic(show_vnic_state_t *state, datalink_id_t linkid)
4012 {
4013 	dladm_vnic_attr_t	attr, *vnic = &attr;
4014 	dladm_status_t		status;
4015 	boolean_t		is_etherstub;
4016 	char			devname[MAXLINKNAMELEN];
4017 	char			vnic_name[MAXLINKNAMELEN];
4018 	char			mstr[MAXMACADDRLEN * 3];
4019 	vnic_fields_buf_t	vbuf;
4020 
4021 	if ((status = dladm_vnic_info(handle, linkid, vnic, state->vs_flags)) !=
4022 	    DLADM_STATUS_OK)
4023 		return (status);
4024 
4025 	is_etherstub = (vnic->va_link_id == DATALINK_INVALID_LINKID);
4026 	if (state->vs_etherstub != is_etherstub) {
4027 		/*
4028 		 * Want all etherstub but it's not one, or want
4029 		 * non-etherstub and it's one.
4030 		 */
4031 		return (DLADM_STATUS_OK);
4032 	}
4033 
4034 	if (state->vs_link_id != DATALINK_ALL_LINKID) {
4035 		if (state->vs_link_id != vnic->va_link_id)
4036 			return (DLADM_STATUS_OK);
4037 	}
4038 
4039 	if (dladm_datalink_id2info(handle, linkid, NULL, NULL,
4040 	    NULL, vnic_name, sizeof (vnic_name)) != DLADM_STATUS_OK)
4041 		return (DLADM_STATUS_BADARG);
4042 
4043 	bzero(devname, sizeof (devname));
4044 	if (!is_etherstub &&
4045 	    dladm_datalink_id2info(handle, vnic->va_link_id, NULL, NULL,
4046 	    NULL, devname, sizeof (devname)) != DLADM_STATUS_OK)
4047 		return (DLADM_STATUS_BADARG);
4048 
4049 	state->vs_found = B_TRUE;
4050 	if (state->vs_stats) {
4051 		/* print vnic statistics */
4052 		pktsum_t vnic_stats;
4053 
4054 		if (state->vs_firstonly) {
4055 			if (state->vs_donefirst)
4056 				return (0);
4057 			state->vs_donefirst = B_TRUE;
4058 		}
4059 
4060 		if (!state->vs_printstats) {
4061 			/*
4062 			 * get vnic statistics and add to the sum for the
4063 			 * named device.
4064 			 */
4065 			get_link_stats(vnic_name, &vnic_stats);
4066 			dladm_stats_total(&state->vs_totalstats, &vnic_stats,
4067 			    &state->vs_prevstats[vnic->va_vnic_id]);
4068 		} else {
4069 			/* get and print vnic statistics */
4070 			get_link_stats(vnic_name, &vnic_stats);
4071 			dump_vnic_stat(vnic_name, linkid, state, &vnic_stats,
4072 			    &state->vs_totalstats);
4073 		}
4074 		return (DLADM_STATUS_OK);
4075 	} else {
4076 		(void) snprintf(vbuf.vnic_link, sizeof (vbuf.vnic_link),
4077 		    "%s", vnic_name);
4078 
4079 		if (!is_etherstub) {
4080 
4081 			(void) snprintf(vbuf.vnic_over, sizeof (vbuf.vnic_over),
4082 			    "%s", devname);
4083 			(void) snprintf(vbuf.vnic_speed,
4084 			    sizeof (vbuf.vnic_speed), "%u",
4085 			    (uint_t)((get_ifspeed(vnic_name, B_TRUE))
4086 			    / 1000000ull));
4087 
4088 			switch (vnic->va_mac_addr_type) {
4089 			case VNIC_MAC_ADDR_TYPE_FIXED:
4090 			case VNIC_MAC_ADDR_TYPE_PRIMARY:
4091 				(void) snprintf(vbuf.vnic_macaddrtype,
4092 				    sizeof (vbuf.vnic_macaddrtype),
4093 				    gettext("fixed"));
4094 				break;
4095 			case VNIC_MAC_ADDR_TYPE_RANDOM:
4096 				(void) snprintf(vbuf.vnic_macaddrtype,
4097 				    sizeof (vbuf.vnic_macaddrtype),
4098 				    gettext("random"));
4099 				break;
4100 			case VNIC_MAC_ADDR_TYPE_FACTORY:
4101 				(void) snprintf(vbuf.vnic_macaddrtype,
4102 				    sizeof (vbuf.vnic_macaddrtype),
4103 				    gettext("factory, slot %d"),
4104 				    vnic->va_mac_slot);
4105 				break;
4106 			}
4107 
4108 			if (strlen(vbuf.vnic_macaddrtype) > 0) {
4109 				(void) snprintf(vbuf.vnic_macaddr,
4110 				    sizeof (vbuf.vnic_macaddr), "%s",
4111 				    dladm_aggr_macaddr2str(vnic->va_mac_addr,
4112 				    mstr));
4113 			}
4114 
4115 			(void) snprintf(vbuf.vnic_vid, sizeof (vbuf.vnic_vid),
4116 			    "%d", vnic->va_vid);
4117 		}
4118 
4119 		ofmt_print(state->vs_ofmt, &vbuf);
4120 
4121 		return (DLADM_STATUS_OK);
4122 	}
4123 }
4124 
4125 /* ARGSUSED */
4126 static int
4127 show_vnic(dladm_handle_t dh, datalink_id_t linkid, void *arg)
4128 {
4129 	show_vnic_state_t	*state = arg;
4130 
4131 	state->vs_status = print_vnic(state, linkid);
4132 	return (DLADM_WALK_CONTINUE);
4133 }
4134 
4135 static void
4136 do_show_vnic_common(int argc, char *argv[], const char *use,
4137     boolean_t etherstub)
4138 {
4139 	int			option;
4140 	boolean_t		s_arg = B_FALSE;
4141 	boolean_t		i_arg = B_FALSE;
4142 	boolean_t		l_arg = B_FALSE;
4143 	uint32_t		interval = 0, flags = DLADM_OPT_ACTIVE;
4144 	datalink_id_t		linkid = DATALINK_ALL_LINKID;
4145 	datalink_id_t		dev_linkid = DATALINK_ALL_LINKID;
4146 	show_vnic_state_t	state;
4147 	dladm_status_t		status;
4148 	boolean_t		o_arg = B_FALSE;
4149 	char			*fields_str = NULL;
4150 	ofmt_field_t		*pf;
4151 	char			*all_e_fields = "link";
4152 	ofmt_handle_t		ofmt;
4153 	ofmt_status_t		oferr;
4154 	uint_t			ofmtflags = 0;
4155 
4156 	bzero(&state, sizeof (state));
4157 	opterr = 0;
4158 	while ((option = getopt_long(argc, argv, ":pPl:si:o:", lopts,
4159 	    NULL)) != -1) {
4160 		switch (option) {
4161 		case 'p':
4162 			state.vs_parsable = B_TRUE;
4163 			break;
4164 		case 'P':
4165 			flags = DLADM_OPT_PERSIST;
4166 			break;
4167 		case 'l':
4168 			if (etherstub)
4169 				die("option not supported for this command");
4170 
4171 			if (strlcpy(state.vs_link, optarg, MAXLINKNAMELEN) >=
4172 			    MAXLINKNAMELEN)
4173 				die("link name too long");
4174 
4175 			l_arg = B_TRUE;
4176 			break;
4177 		case 's':
4178 			if (s_arg) {
4179 				die("the option -s cannot be specified "
4180 				    "more than once");
4181 			}
4182 			s_arg = B_TRUE;
4183 			break;
4184 		case 'i':
4185 			if (i_arg) {
4186 				die("the option -i cannot be specified "
4187 				    "more than once");
4188 			}
4189 			i_arg = B_TRUE;
4190 			if (!dladm_str2interval(optarg, &interval))
4191 				die("invalid interval value '%s'", optarg);
4192 			break;
4193 		case 'o':
4194 			o_arg = B_TRUE;
4195 			fields_str = optarg;
4196 			break;
4197 		default:
4198 			die_opterr(optopt, option, use);
4199 		}
4200 	}
4201 
4202 	if (i_arg && !s_arg)
4203 		die("the option -i can be used only with -s");
4204 
4205 	/* get vnic ID (optional last argument) */
4206 	if (optind == (argc - 1)) {
4207 		status = dladm_name2info(handle, argv[optind], &linkid, NULL,
4208 		    NULL, NULL);
4209 		if (status != DLADM_STATUS_OK) {
4210 			die_dlerr(status, "invalid vnic name '%s'",
4211 			    argv[optind]);
4212 		}
4213 		(void) strlcpy(state.vs_vnic, argv[optind], MAXLINKNAMELEN);
4214 	} else if (optind != argc) {
4215 		usage();
4216 	}
4217 
4218 	if (l_arg) {
4219 		status = dladm_name2info(handle, state.vs_link, &dev_linkid,
4220 		    NULL, NULL, NULL);
4221 		if (status != DLADM_STATUS_OK) {
4222 			die_dlerr(status, "invalid link name '%s'",
4223 			    state.vs_link);
4224 		}
4225 	}
4226 
4227 	state.vs_vnic_id = linkid;
4228 	state.vs_link_id = dev_linkid;
4229 	state.vs_etherstub = etherstub;
4230 	state.vs_found = B_FALSE;
4231 	state.vs_flags = flags;
4232 
4233 	if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) {
4234 		if (etherstub)
4235 			fields_str = all_e_fields;
4236 	}
4237 	pf = vnic_fields;
4238 
4239 	if (state.vs_parsable)
4240 		ofmtflags |= OFMT_PARSABLE;
4241 	oferr = ofmt_open(fields_str, pf, ofmtflags, 0, &ofmt);
4242 	dladm_ofmt_check(oferr, state.vs_parsable, ofmt);
4243 	state.vs_ofmt = ofmt;
4244 
4245 	if (s_arg) {
4246 		/* Display vnic statistics */
4247 		vnic_stats(&state, interval);
4248 		ofmt_close(ofmt);
4249 		return;
4250 	}
4251 
4252 	/* Display vnic information */
4253 	state.vs_donefirst = B_FALSE;
4254 
4255 	if (linkid == DATALINK_ALL_LINKID) {
4256 		(void) dladm_walk_datalink_id(show_vnic, handle, &state,
4257 		    DATALINK_CLASS_VNIC | DATALINK_CLASS_ETHERSTUB,
4258 		    DATALINK_ANY_MEDIATYPE, flags);
4259 	} else {
4260 		(void) show_vnic(handle, linkid, &state);
4261 		if (state.vs_status != DLADM_STATUS_OK) {
4262 			ofmt_close(ofmt);
4263 			die_dlerr(state.vs_status, "failed to show vnic '%s'",
4264 			    state.vs_vnic);
4265 		}
4266 	}
4267 	ofmt_close(ofmt);
4268 }
4269 
4270 static void
4271 do_show_vnic(int argc, char *argv[], const char *use)
4272 {
4273 	do_show_vnic_common(argc, argv, use, B_FALSE);
4274 }
4275 
4276 static void
4277 do_create_etherstub(int argc, char *argv[], const char *use)
4278 {
4279 	uint32_t flags;
4280 	char *altroot = NULL;
4281 	int option;
4282 	dladm_status_t status;
4283 	char name[MAXLINKNAMELEN];
4284 	uchar_t mac_addr[ETHERADDRL];
4285 
4286 	name[0] = '\0';
4287 	bzero(mac_addr, sizeof (mac_addr));
4288 	flags = DLADM_OPT_ANCHOR | DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
4289 
4290 	opterr = 0;
4291 	while ((option = getopt_long(argc, argv, "tR:",
4292 	    etherstub_lopts, NULL)) != -1) {
4293 		switch (option) {
4294 		case 't':
4295 			flags &= ~DLADM_OPT_PERSIST;
4296 			break;
4297 		case 'R':
4298 			altroot = optarg;
4299 			break;
4300 		default:
4301 			die_opterr(optopt, option, use);
4302 		}
4303 	}
4304 
4305 	/* the etherstub id is the required operand */
4306 	if (optind != (argc - 1))
4307 		usage();
4308 
4309 	if (strlcpy(name, argv[optind], MAXLINKNAMELEN) >= MAXLINKNAMELEN)
4310 		die("link name too long '%s'", argv[optind]);
4311 
4312 	if (!dladm_valid_linkname(name))
4313 		die("invalid link name '%s'", argv[optind]);
4314 
4315 	if (altroot != NULL)
4316 		altroot_cmd(altroot, argc, argv);
4317 
4318 	status = dladm_vnic_create(handle, name, DATALINK_INVALID_LINKID,
4319 	    VNIC_MAC_ADDR_TYPE_AUTO, mac_addr, ETHERADDRL, NULL, 0, 0, NULL,
4320 	    NULL, flags);
4321 	if (status != DLADM_STATUS_OK)
4322 		die_dlerr(status, "etherstub creation failed");
4323 }
4324 
4325 static void
4326 do_delete_etherstub(int argc, char *argv[], const char *use)
4327 {
4328 	do_delete_vnic_common(argc, argv, use, B_TRUE);
4329 }
4330 
4331 /* ARGSUSED */
4332 static void
4333 do_show_etherstub(int argc, char *argv[], const char *use)
4334 {
4335 	do_show_vnic_common(argc, argv, use, B_TRUE);
4336 }
4337 
4338 /* ARGSUSED */
4339 static void
4340 do_up_simnet(int argc, char *argv[], const char *use)
4341 {
4342 	(void) dladm_simnet_up(handle, DATALINK_ALL_LINKID, 0);
4343 }
4344 
4345 static void
4346 do_create_simnet(int argc, char *argv[], const char *use)
4347 {
4348 	uint32_t flags;
4349 	char *altroot = NULL;
4350 	char *media = NULL;
4351 	uint32_t mtype = DL_ETHER;
4352 	int option;
4353 	dladm_status_t status;
4354 	char name[MAXLINKNAMELEN];
4355 
4356 	name[0] = '\0';
4357 	flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
4358 
4359 	opterr = 0;
4360 	while ((option = getopt_long(argc, argv, ":tR:m:",
4361 	    simnet_lopts, NULL)) != -1) {
4362 		switch (option) {
4363 		case 't':
4364 			flags &= ~DLADM_OPT_PERSIST;
4365 			break;
4366 		case 'R':
4367 			altroot = optarg;
4368 			break;
4369 		case 'm':
4370 			media = optarg;
4371 			break;
4372 		default:
4373 			die_opterr(optopt, option, use);
4374 		}
4375 	}
4376 
4377 	/* the simnet id is the required operand */
4378 	if (optind != (argc - 1))
4379 		usage();
4380 
4381 	if (strlcpy(name, argv[optind], MAXLINKNAMELEN) >= MAXLINKNAMELEN)
4382 		die("link name too long '%s'", argv[optind]);
4383 
4384 	if (!dladm_valid_linkname(name))
4385 		die("invalid link name '%s'", name);
4386 
4387 	if (media != NULL) {
4388 		mtype = dladm_str2media(media);
4389 		if (mtype != DL_ETHER && mtype != DL_WIFI)
4390 			die("media type '%s' is not supported", media);
4391 	}
4392 
4393 	if (altroot != NULL)
4394 		altroot_cmd(altroot, argc, argv);
4395 
4396 	status = dladm_simnet_create(handle, name, mtype, flags);
4397 	if (status != DLADM_STATUS_OK)
4398 		die_dlerr(status, "simnet creation failed");
4399 }
4400 
4401 static void
4402 do_delete_simnet(int argc, char *argv[], const char *use)
4403 {
4404 	int option;
4405 	uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
4406 	datalink_id_t linkid;
4407 	char *altroot = NULL;
4408 	dladm_status_t status;
4409 	dladm_simnet_attr_t slinfo;
4410 
4411 	opterr = 0;
4412 	while ((option = getopt_long(argc, argv, ":tR:", simnet_lopts,
4413 	    NULL)) != -1) {
4414 		switch (option) {
4415 		case 't':
4416 			flags &= ~DLADM_OPT_PERSIST;
4417 			break;
4418 		case 'R':
4419 			altroot = optarg;
4420 			break;
4421 		default:
4422 			die_opterr(optopt, option, use);
4423 		}
4424 	}
4425 
4426 	/* get simnet name (required last argument) */
4427 	if (optind != (argc - 1))
4428 		usage();
4429 
4430 	if (!dladm_valid_linkname(argv[optind]))
4431 		die("invalid link name '%s'", argv[optind]);
4432 
4433 	if (altroot != NULL)
4434 		altroot_cmd(altroot, argc, argv);
4435 
4436 	status = dladm_name2info(handle, argv[optind], &linkid, NULL, NULL,
4437 	    NULL);
4438 	if (status != DLADM_STATUS_OK)
4439 		die("simnet '%s' not found", argv[optind]);
4440 
4441 	if ((status = dladm_simnet_info(handle, linkid, &slinfo,
4442 	    flags)) != DLADM_STATUS_OK)
4443 		die_dlerr(status, "failed to retrieve simnet information");
4444 
4445 	status = dladm_simnet_delete(handle, linkid, flags);
4446 	if (status != DLADM_STATUS_OK)
4447 		die_dlerr(status, "simnet deletion failed");
4448 }
4449 
4450 static void
4451 do_modify_simnet(int argc, char *argv[], const char *use)
4452 {
4453 	int option;
4454 	uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
4455 	datalink_id_t linkid;
4456 	datalink_id_t peer_linkid;
4457 	char *altroot = NULL;
4458 	dladm_status_t status;
4459 	boolean_t p_arg = B_FALSE;
4460 
4461 	opterr = 0;
4462 	while ((option = getopt_long(argc, argv, ":tR:p:", simnet_lopts,
4463 	    NULL)) != -1) {
4464 		switch (option) {
4465 		case 't':
4466 			flags &= ~DLADM_OPT_PERSIST;
4467 			break;
4468 		case 'R':
4469 			altroot = optarg;
4470 			break;
4471 		case 'p':
4472 			if (p_arg)
4473 				die_optdup(option);
4474 			p_arg = B_TRUE;
4475 			if (strcasecmp(optarg, "none") == 0)
4476 				peer_linkid = DATALINK_INVALID_LINKID;
4477 			else if (dladm_name2info(handle, optarg, &peer_linkid,
4478 			    NULL, NULL, NULL) != DLADM_STATUS_OK)
4479 				die("invalid peer link name '%s'", optarg);
4480 			break;
4481 		default:
4482 			die_opterr(optopt, option, use);
4483 		}
4484 	}
4485 
4486 	/* get simnet name (required last argument) */
4487 	if (optind != (argc - 1))
4488 		usage();
4489 
4490 	/* Nothing to do if no peer link argument */
4491 	if (!p_arg)
4492 		return;
4493 
4494 	if (altroot != NULL)
4495 		altroot_cmd(altroot, argc, argv);
4496 
4497 	status = dladm_name2info(handle, argv[optind], &linkid, NULL, NULL,
4498 	    NULL);
4499 	if (status != DLADM_STATUS_OK)
4500 		die("invalid link name '%s'", argv[optind]);
4501 
4502 	status = dladm_simnet_modify(handle, linkid, peer_linkid, flags);
4503 	if (status != DLADM_STATUS_OK)
4504 		die_dlerr(status, "simnet modification failed");
4505 }
4506 
4507 static dladm_status_t
4508 print_simnet(show_state_t *state, datalink_id_t linkid)
4509 {
4510 	dladm_simnet_attr_t	slinfo;
4511 	uint32_t		flags;
4512 	dladm_status_t		status;
4513 	simnet_fields_buf_t	slbuf;
4514 	char			mstr[ETHERADDRL * 3];
4515 
4516 	bzero(&slbuf, sizeof (slbuf));
4517 	if ((status = dladm_datalink_id2info(handle, linkid, &flags, NULL, NULL,
4518 	    slbuf.simnet_name, sizeof (slbuf.simnet_name)))
4519 	    != DLADM_STATUS_OK)
4520 		return (status);
4521 
4522 	if (!(state->ls_flags & flags))
4523 		return (DLADM_STATUS_NOTFOUND);
4524 
4525 	if ((status = dladm_simnet_info(handle, linkid, &slinfo,
4526 	    state->ls_flags)) != DLADM_STATUS_OK)
4527 		return (status);
4528 
4529 	if (slinfo.sna_peer_link_id != DATALINK_INVALID_LINKID &&
4530 	    (status = dladm_datalink_id2info(handle, slinfo.sna_peer_link_id,
4531 	    NULL, NULL, NULL, slbuf.simnet_otherlink,
4532 	    sizeof (slbuf.simnet_otherlink))) !=
4533 	    DLADM_STATUS_OK)
4534 		return (status);
4535 
4536 	if (slinfo.sna_mac_len > sizeof (slbuf.simnet_macaddr))
4537 		return (DLADM_STATUS_BADVAL);
4538 
4539 	(void) strlcpy(slbuf.simnet_macaddr,
4540 	    dladm_aggr_macaddr2str(slinfo.sna_mac_addr, mstr),
4541 	    sizeof (slbuf.simnet_macaddr));
4542 	(void) dladm_media2str(slinfo.sna_type, slbuf.simnet_media);
4543 
4544 	ofmt_print(state->ls_ofmt, &slbuf);
4545 	return (status);
4546 }
4547 
4548 /* ARGSUSED */
4549 static int
4550 show_simnet(dladm_handle_t dh, datalink_id_t linkid, void *arg)
4551 {
4552 	show_state_t		*state = arg;
4553 
4554 	state->ls_status = print_simnet(state, linkid);
4555 	return (DLADM_WALK_CONTINUE);
4556 }
4557 
4558 static void
4559 do_show_simnet(int argc, char *argv[], const char *use)
4560 {
4561 	int		option;
4562 	uint32_t	flags = DLADM_OPT_ACTIVE;
4563 	boolean_t	p_arg = B_FALSE;
4564 	datalink_id_t	linkid = DATALINK_ALL_LINKID;
4565 	show_state_t	state;
4566 	dladm_status_t	status;
4567 	boolean_t	o_arg = B_FALSE;
4568 	ofmt_handle_t	ofmt;
4569 	ofmt_status_t	oferr;
4570 	char		*all_fields = "link,media,macaddress,otherlink";
4571 	char		*fields_str = all_fields;
4572 	uint_t		ofmtflags = 0;
4573 
4574 	bzero(&state, sizeof (state));
4575 
4576 	opterr = 0;
4577 	while ((option = getopt_long(argc, argv, ":pPo:",
4578 	    show_lopts, NULL)) != -1) {
4579 		switch (option) {
4580 		case 'p':
4581 			if (p_arg)
4582 				die_optdup(option);
4583 
4584 			p_arg = B_TRUE;
4585 			state.ls_parsable = p_arg;
4586 			break;
4587 		case 'P':
4588 			if (flags != DLADM_OPT_ACTIVE)
4589 				die_optdup(option);
4590 
4591 			flags = DLADM_OPT_PERSIST;
4592 			break;
4593 		case 'o':
4594 			o_arg = B_TRUE;
4595 			fields_str = optarg;
4596 			break;
4597 		default:
4598 			die_opterr(optopt, option, use);
4599 			break;
4600 		}
4601 	}
4602 
4603 	if (p_arg && !o_arg)
4604 		die("-p requires -o");
4605 
4606 	if (strcasecmp(fields_str, "all") == 0) {
4607 		if (p_arg)
4608 			die("\"-o all\" is invalid with -p");
4609 		fields_str = all_fields;
4610 	}
4611 
4612 	/* get link name (optional last argument) */
4613 	if (optind == (argc-1)) {
4614 		if ((status = dladm_name2info(handle, argv[optind], &linkid,
4615 		    NULL, NULL, NULL)) != DLADM_STATUS_OK) {
4616 			die_dlerr(status, "link %s is not valid", argv[optind]);
4617 		}
4618 	} else if (optind != argc) {
4619 		usage();
4620 	}
4621 
4622 	state.ls_flags = flags;
4623 	state.ls_donefirst = B_FALSE;
4624 	if (state.ls_parsable)
4625 		ofmtflags |= OFMT_PARSABLE;
4626 	oferr = ofmt_open(fields_str, simnet_fields, ofmtflags, 0, &ofmt);
4627 	dladm_ofmt_check(oferr, state.ls_parsable, ofmt);
4628 	state.ls_ofmt = ofmt;
4629 
4630 	if (linkid == DATALINK_ALL_LINKID) {
4631 		(void) dladm_walk_datalink_id(show_simnet, handle, &state,
4632 		    DATALINK_CLASS_SIMNET, DATALINK_ANY_MEDIATYPE, flags);
4633 	} else {
4634 		(void) show_simnet(handle, linkid, &state);
4635 		if (state.ls_status != DLADM_STATUS_OK) {
4636 			ofmt_close(ofmt);
4637 			die_dlerr(state.ls_status, "failed to show simnet %s",
4638 			    argv[optind]);
4639 		}
4640 	}
4641 	ofmt_close(ofmt);
4642 }
4643 
4644 static void
4645 link_stats(datalink_id_t linkid, uint_t interval, char *fields_str,
4646     show_state_t *state)
4647 {
4648 	ofmt_handle_t	ofmt;
4649 	ofmt_status_t	oferr;
4650 	uint_t		ofmtflags = 0;
4651 
4652 	if (state->ls_parsable)
4653 		ofmtflags |= OFMT_PARSABLE;
4654 	oferr = ofmt_open(fields_str, link_s_fields, ofmtflags, 0, &ofmt);
4655 	dladm_ofmt_check(oferr, state->ls_parsable, ofmt);
4656 	state->ls_ofmt = ofmt;
4657 
4658 	/*
4659 	 * If an interval is specified, continuously show the stats
4660 	 * only for the first MAC port.
4661 	 */
4662 	state->ls_firstonly = (interval != 0);
4663 
4664 	for (;;) {
4665 		state->ls_donefirst = B_FALSE;
4666 		if (linkid == DATALINK_ALL_LINKID) {
4667 			(void) dladm_walk_datalink_id(show_link_stats, handle,
4668 			    state, DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE,
4669 			    DLADM_OPT_ACTIVE);
4670 		} else {
4671 			(void) show_link_stats(handle, linkid, state);
4672 		}
4673 
4674 		if (interval == 0)
4675 			break;
4676 
4677 		(void) fflush(stdout);
4678 		(void) sleep(interval);
4679 	}
4680 	ofmt_close(ofmt);
4681 }
4682 
4683 static void
4684 aggr_stats(datalink_id_t linkid, show_grp_state_t *state, uint_t interval)
4685 {
4686 	/*
4687 	 * If an interval is specified, continuously show the stats
4688 	 * only for the first group.
4689 	 */
4690 	state->gs_firstonly = (interval != 0);
4691 
4692 	for (;;) {
4693 		state->gs_donefirst = B_FALSE;
4694 		if (linkid == DATALINK_ALL_LINKID)
4695 			(void) dladm_walk_datalink_id(show_aggr, handle, state,
4696 			    DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE,
4697 			    DLADM_OPT_ACTIVE);
4698 		else
4699 			(void) show_aggr(handle, linkid, state);
4700 
4701 		if (interval == 0)
4702 			break;
4703 
4704 		(void) fflush(stdout);
4705 		(void) sleep(interval);
4706 	}
4707 }
4708 
4709 /* ARGSUSED */
4710 static void
4711 vnic_stats(show_vnic_state_t *sp, uint32_t interval)
4712 {
4713 	show_vnic_state_t	state;
4714 	boolean_t		specific_link, specific_dev;
4715 
4716 	/* Display vnic statistics */
4717 	dump_vnics_head(sp->vs_link);
4718 
4719 	bzero(&state, sizeof (state));
4720 	state.vs_stats = B_TRUE;
4721 	state.vs_vnic_id = sp->vs_vnic_id;
4722 	state.vs_link_id = sp->vs_link_id;
4723 
4724 	/*
4725 	 * If an interval is specified, and a vnic ID is not specified,
4726 	 * continuously show the stats only for the first vnic.
4727 	 */
4728 	specific_link = (sp->vs_vnic_id != DATALINK_ALL_LINKID);
4729 	specific_dev = (sp->vs_link_id != DATALINK_ALL_LINKID);
4730 
4731 	for (;;) {
4732 		/* Get stats for each vnic */
4733 		state.vs_found = B_FALSE;
4734 		state.vs_donefirst = B_FALSE;
4735 		state.vs_printstats = B_FALSE;
4736 		state.vs_flags = DLADM_OPT_ACTIVE;
4737 
4738 		if (!specific_link) {
4739 			(void) dladm_walk_datalink_id(show_vnic, handle, &state,
4740 			    DATALINK_CLASS_VNIC, DATALINK_ANY_MEDIATYPE,
4741 			    DLADM_OPT_ACTIVE);
4742 		} else {
4743 			(void) show_vnic(handle, sp->vs_vnic_id, &state);
4744 			if (state.vs_status != DLADM_STATUS_OK) {
4745 				die_dlerr(state.vs_status,
4746 				    "failed to show vnic '%s'", sp->vs_vnic);
4747 			}
4748 		}
4749 
4750 		if (specific_link && !state.vs_found)
4751 			die("non-existent vnic '%s'", sp->vs_vnic);
4752 		if (specific_dev && !state.vs_found)
4753 			die("device %s has no vnics", sp->vs_link);
4754 
4755 		/* Show totals */
4756 		if ((specific_link | specific_dev) && !interval) {
4757 			(void) printf("Total");
4758 			(void) printf("\t%-10llu",
4759 			    state.vs_totalstats.ipackets);
4760 			(void) printf("%-12llu",
4761 			    state.vs_totalstats.rbytes);
4762 			(void) printf("%-10llu",
4763 			    state.vs_totalstats.opackets);
4764 			(void) printf("%-12llu\n",
4765 			    state.vs_totalstats.obytes);
4766 		}
4767 
4768 		/* Show stats for each vnic */
4769 		state.vs_donefirst = B_FALSE;
4770 		state.vs_printstats = B_TRUE;
4771 
4772 		if (!specific_link) {
4773 			(void) dladm_walk_datalink_id(show_vnic, handle, &state,
4774 			    DATALINK_CLASS_VNIC, DATALINK_ANY_MEDIATYPE,
4775 			    DLADM_OPT_ACTIVE);
4776 		} else {
4777 			(void) show_vnic(handle, sp->vs_vnic_id, &state);
4778 			if (state.vs_status != DLADM_STATUS_OK) {
4779 				die_dlerr(state.vs_status,
4780 				    "failed to show vnic '%s'", sp->vs_vnic);
4781 			}
4782 		}
4783 
4784 		if (interval == 0)
4785 			break;
4786 
4787 		(void) fflush(stdout);
4788 		(void) sleep(interval);
4789 	}
4790 }
4791 
4792 static void
4793 get_mac_stats(const char *dev, pktsum_t *stats)
4794 {
4795 	kstat_ctl_t	*kcp;
4796 	kstat_t		*ksp;
4797 	char module[DLPI_LINKNAME_MAX];
4798 	uint_t instance;
4799 
4800 
4801 	bzero(stats, sizeof (*stats));
4802 
4803 	if (dlpi_parselink(dev, module, &instance) != DLPI_SUCCESS)
4804 		return;
4805 
4806 	if ((kcp = kstat_open()) == NULL) {
4807 		warn("kstat open operation failed");
4808 		return;
4809 	}
4810 
4811 	ksp = dladm_kstat_lookup(kcp, module, instance, "mac", NULL);
4812 	if (ksp != NULL)
4813 		dladm_get_stats(kcp, ksp, stats);
4814 
4815 	(void) kstat_close(kcp);
4816 
4817 }
4818 
4819 static void
4820 get_link_stats(const char *link, pktsum_t *stats)
4821 {
4822 	kstat_ctl_t	*kcp;
4823 	kstat_t		*ksp;
4824 
4825 	bzero(stats, sizeof (*stats));
4826 
4827 	if ((kcp = kstat_open()) == NULL) {
4828 		warn("kstat_open operation failed");
4829 		return;
4830 	}
4831 
4832 	ksp = dladm_kstat_lookup(kcp, "link", 0, link, NULL);
4833 
4834 	if (ksp != NULL)
4835 		dladm_get_stats(kcp, ksp, stats);
4836 
4837 	(void) kstat_close(kcp);
4838 }
4839 
4840 static int
4841 query_kstat(char *module, int instance, const char *name, const char *stat,
4842     uint8_t type, void *val)
4843 {
4844 	kstat_ctl_t	*kcp;
4845 	kstat_t		*ksp;
4846 
4847 	if ((kcp = kstat_open()) == NULL) {
4848 		warn("kstat open operation failed");
4849 		return (-1);
4850 	}
4851 
4852 	if ((ksp = kstat_lookup(kcp, module, instance, (char *)name)) == NULL) {
4853 		/*
4854 		 * The kstat query could fail if the underlying MAC
4855 		 * driver was already detached.
4856 		 */
4857 		goto bail;
4858 	}
4859 
4860 	if (kstat_read(kcp, ksp, NULL) == -1) {
4861 		warn("kstat read failed");
4862 		goto bail;
4863 	}
4864 
4865 	if (dladm_kstat_value(ksp, stat, type, val) < 0)
4866 		goto bail;
4867 
4868 	(void) kstat_close(kcp);
4869 	return (0);
4870 
4871 bail:
4872 	(void) kstat_close(kcp);
4873 	return (-1);
4874 }
4875 
4876 static int
4877 get_one_kstat(const char *name, const char *stat, uint8_t type,
4878     void *val, boolean_t islink)
4879 {
4880 	char		module[DLPI_LINKNAME_MAX];
4881 	uint_t		instance;
4882 
4883 	if (islink) {
4884 		return (query_kstat("link", 0, name, stat, type, val));
4885 	} else {
4886 		if (dlpi_parselink(name, module, &instance) != DLPI_SUCCESS)
4887 			return (-1);
4888 
4889 		return (query_kstat(module, instance, "mac", stat, type, val));
4890 	}
4891 }
4892 
4893 static uint64_t
4894 get_ifspeed(const char *name, boolean_t islink)
4895 {
4896 	uint64_t ifspeed = 0;
4897 
4898 	(void) get_one_kstat(name, "ifspeed", KSTAT_DATA_UINT64,
4899 	    &ifspeed, islink);
4900 
4901 	return (ifspeed);
4902 }
4903 
4904 static const char *
4905 get_linkstate(const char *name, boolean_t islink, char *buf)
4906 {
4907 	link_state_t	linkstate;
4908 
4909 	if (get_one_kstat(name, "link_state", KSTAT_DATA_UINT32,
4910 	    &linkstate, islink) != 0) {
4911 		(void) strlcpy(buf, "?", DLADM_STRSIZE);
4912 		return (buf);
4913 	}
4914 	return (dladm_linkstate2str(linkstate, buf));
4915 }
4916 
4917 static const char *
4918 get_linkduplex(const char *name, boolean_t islink, char *buf)
4919 {
4920 	link_duplex_t	linkduplex;
4921 
4922 	if (get_one_kstat(name, "link_duplex", KSTAT_DATA_UINT32,
4923 	    &linkduplex, islink) != 0) {
4924 		(void) strlcpy(buf, "unknown", DLADM_STRSIZE);
4925 		return (buf);
4926 	}
4927 
4928 	return (dladm_linkduplex2str(linkduplex, buf));
4929 }
4930 
4931 static int
4932 parse_wifi_fields(char *str, ofmt_handle_t *ofmt, uint_t cmdtype,
4933     boolean_t parsable)
4934 {
4935 	ofmt_field_t	*template, *of;
4936 	ofmt_cb_t	*fn;
4937 	ofmt_status_t	oferr;
4938 
4939 	if (cmdtype == WIFI_CMD_SCAN) {
4940 		template = wifi_common_fields;
4941 		if (str == NULL)
4942 			str = def_scan_wifi_fields;
4943 		if (strcasecmp(str, "all") == 0)
4944 			str = all_scan_wifi_fields;
4945 		fn = print_wlan_attr_cb;
4946 	} else if (cmdtype == WIFI_CMD_SHOW) {
4947 		bcopy(wifi_common_fields, &wifi_show_fields[2],
4948 		    sizeof (wifi_common_fields));
4949 		template = wifi_show_fields;
4950 		if (str == NULL)
4951 			str = def_show_wifi_fields;
4952 		if (strcasecmp(str, "all") == 0)
4953 			str = all_show_wifi_fields;
4954 		fn = print_link_attr_cb;
4955 	} else {
4956 		return (-1);
4957 	}
4958 
4959 	for (of = template; of->of_name != NULL; of++) {
4960 		if (of->of_cb == NULL)
4961 			of->of_cb = fn;
4962 	}
4963 
4964 	oferr = ofmt_open(str, template, (parsable ? OFMT_PARSABLE : 0),
4965 	    0, ofmt);
4966 	dladm_ofmt_check(oferr, parsable, *ofmt);
4967 	return (0);
4968 }
4969 
4970 typedef struct print_wifi_state {
4971 	char		*ws_link;
4972 	boolean_t	ws_parsable;
4973 	boolean_t	ws_header;
4974 	ofmt_handle_t	ws_ofmt;
4975 } print_wifi_state_t;
4976 
4977 typedef struct  wlan_scan_args_s {
4978 	print_wifi_state_t	*ws_state;
4979 	void			*ws_attr;
4980 } wlan_scan_args_t;
4981 
4982 static boolean_t
4983 print_wlan_attr_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
4984 {
4985 	wlan_scan_args_t	*w = ofarg->ofmt_cbarg;
4986 	print_wifi_state_t	*statep = w->ws_state;
4987 	dladm_wlan_attr_t	*attrp = w->ws_attr;
4988 	char			tmpbuf[DLADM_STRSIZE];
4989 
4990 	if (ofarg->ofmt_id == 0) {
4991 		(void) strlcpy(buf, (char *)statep->ws_link, bufsize);
4992 		return (B_TRUE);
4993 	}
4994 
4995 	if ((ofarg->ofmt_id & attrp->wa_valid) == 0)
4996 		return (B_TRUE);
4997 
4998 	switch (ofarg->ofmt_id) {
4999 	case DLADM_WLAN_ATTR_ESSID:
5000 		(void) dladm_wlan_essid2str(&attrp->wa_essid, tmpbuf);
5001 		break;
5002 	case DLADM_WLAN_ATTR_BSSID:
5003 		(void) dladm_wlan_bssid2str(&attrp->wa_bssid, tmpbuf);
5004 		break;
5005 	case DLADM_WLAN_ATTR_SECMODE:
5006 		(void) dladm_wlan_secmode2str(&attrp->wa_secmode, tmpbuf);
5007 		break;
5008 	case DLADM_WLAN_ATTR_STRENGTH:
5009 		(void) dladm_wlan_strength2str(&attrp->wa_strength, tmpbuf);
5010 		break;
5011 	case DLADM_WLAN_ATTR_MODE:
5012 		(void) dladm_wlan_mode2str(&attrp->wa_mode, tmpbuf);
5013 		break;
5014 	case DLADM_WLAN_ATTR_SPEED:
5015 		(void) dladm_wlan_speed2str(&attrp->wa_speed, tmpbuf);
5016 		(void) strlcat(tmpbuf, "Mb", sizeof (tmpbuf));
5017 		break;
5018 	case DLADM_WLAN_ATTR_AUTH:
5019 		(void) dladm_wlan_auth2str(&attrp->wa_auth, tmpbuf);
5020 		break;
5021 	case DLADM_WLAN_ATTR_BSSTYPE:
5022 		(void) dladm_wlan_bsstype2str(&attrp->wa_bsstype, tmpbuf);
5023 		break;
5024 	}
5025 	(void) strlcpy(buf, tmpbuf, bufsize);
5026 
5027 	return (B_TRUE);
5028 }
5029 
5030 static boolean_t
5031 print_scan_results(void *arg, dladm_wlan_attr_t *attrp)
5032 {
5033 	print_wifi_state_t	*statep = arg;
5034 	wlan_scan_args_t	warg;
5035 
5036 	bzero(&warg, sizeof (warg));
5037 	warg.ws_state = statep;
5038 	warg.ws_attr = attrp;
5039 	ofmt_print(statep->ws_ofmt, &warg);
5040 	return (B_TRUE);
5041 }
5042 
5043 static int
5044 scan_wifi(dladm_handle_t dh, datalink_id_t linkid, void *arg)
5045 {
5046 	print_wifi_state_t	*statep = arg;
5047 	dladm_status_t		status;
5048 	char			link[MAXLINKNAMELEN];
5049 
5050 	if ((status = dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, link,
5051 	    sizeof (link))) != DLADM_STATUS_OK) {
5052 		return (DLADM_WALK_CONTINUE);
5053 	}
5054 
5055 	statep->ws_link = link;
5056 	status = dladm_wlan_scan(dh, linkid, statep, print_scan_results);
5057 	if (status != DLADM_STATUS_OK)
5058 		die_dlerr(status, "cannot scan link '%s'", statep->ws_link);
5059 
5060 	return (DLADM_WALK_CONTINUE);
5061 }
5062 
5063 static boolean_t
5064 print_wifi_status_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
5065 {
5066 	static char		tmpbuf[DLADM_STRSIZE];
5067 	wlan_scan_args_t	*w = ofarg->ofmt_cbarg;
5068 	dladm_wlan_linkattr_t	*attrp = w->ws_attr;
5069 
5070 	if ((ofarg->ofmt_id & attrp->la_valid) != 0) {
5071 		(void) dladm_wlan_linkstatus2str(&attrp->la_status, tmpbuf);
5072 		(void) strlcpy(buf, tmpbuf, bufsize);
5073 	}
5074 	return (B_TRUE);
5075 }
5076 
5077 static boolean_t
5078 print_link_attr_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
5079 {
5080 	wlan_scan_args_t	*w = ofarg->ofmt_cbarg, w1;
5081 	print_wifi_state_t	*statep = w->ws_state;
5082 	dladm_wlan_linkattr_t	*attrp = w->ws_attr;
5083 
5084 	bzero(&w1, sizeof (w1));
5085 	w1.ws_state = statep;
5086 	w1.ws_attr = &attrp->la_wlan_attr;
5087 	ofarg->ofmt_cbarg = &w1;
5088 	return (print_wlan_attr_cb(ofarg, buf, bufsize));
5089 }
5090 
5091 static int
5092 show_wifi(dladm_handle_t dh, datalink_id_t linkid, void *arg)
5093 {
5094 	print_wifi_state_t	*statep = arg;
5095 	dladm_wlan_linkattr_t	attr;
5096 	dladm_status_t		status;
5097 	char			link[MAXLINKNAMELEN];
5098 	wlan_scan_args_t	warg;
5099 
5100 	if ((status = dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, link,
5101 	    sizeof (link))) != DLADM_STATUS_OK) {
5102 		return (DLADM_WALK_CONTINUE);
5103 	}
5104 
5105 	/* dladm_wlan_get_linkattr() memsets attr with 0 */
5106 	status = dladm_wlan_get_linkattr(dh, linkid, &attr);
5107 	if (status != DLADM_STATUS_OK)
5108 		die_dlerr(status, "cannot get link attributes for %s", link);
5109 
5110 	statep->ws_link = link;
5111 
5112 	bzero(&warg, sizeof (warg));
5113 	warg.ws_state = statep;
5114 	warg.ws_attr = &attr;
5115 	ofmt_print(statep->ws_ofmt, &warg);
5116 	return (DLADM_WALK_CONTINUE);
5117 }
5118 
5119 static void
5120 do_display_wifi(int argc, char **argv, int cmd, const char *use)
5121 {
5122 	int			option;
5123 	char			*fields_str = NULL;
5124 	int		(*callback)(dladm_handle_t, datalink_id_t, void *);
5125 	print_wifi_state_t	state;
5126 	datalink_id_t		linkid = DATALINK_ALL_LINKID;
5127 	dladm_status_t		status;
5128 
5129 	if (cmd == WIFI_CMD_SCAN)
5130 		callback = scan_wifi;
5131 	else if (cmd == WIFI_CMD_SHOW)
5132 		callback = show_wifi;
5133 	else
5134 		return;
5135 
5136 	state.ws_parsable = B_FALSE;
5137 	state.ws_header = B_TRUE;
5138 	opterr = 0;
5139 	while ((option = getopt_long(argc, argv, ":o:p",
5140 	    wifi_longopts, NULL)) != -1) {
5141 		switch (option) {
5142 		case 'o':
5143 			fields_str = optarg;
5144 			break;
5145 		case 'p':
5146 			state.ws_parsable = B_TRUE;
5147 			break;
5148 		default:
5149 			die_opterr(optopt, option, use);
5150 		}
5151 	}
5152 
5153 	if (state.ws_parsable && fields_str == NULL)
5154 		die("-p requires -o");
5155 
5156 	if (state.ws_parsable && strcasecmp(fields_str, "all") == 0)
5157 		die("\"-o all\" is invalid with -p");
5158 
5159 	if (optind == (argc - 1)) {
5160 		if ((status = dladm_name2info(handle, argv[optind], &linkid,
5161 		    NULL, NULL, NULL)) != DLADM_STATUS_OK) {
5162 			die_dlerr(status, "link %s is not valid", argv[optind]);
5163 		}
5164 	} else if (optind != argc) {
5165 		usage();
5166 	}
5167 
5168 	if (parse_wifi_fields(fields_str, &state.ws_ofmt, cmd,
5169 	    state.ws_parsable) < 0)
5170 		die("invalid field(s) specified");
5171 
5172 	if (linkid == DATALINK_ALL_LINKID) {
5173 		(void) dladm_walk_datalink_id(callback, handle, &state,
5174 		    DATALINK_CLASS_PHYS | DATALINK_CLASS_SIMNET,
5175 		    DL_WIFI, DLADM_OPT_ACTIVE);
5176 	} else {
5177 		(void) (*callback)(handle, linkid, &state);
5178 	}
5179 	ofmt_close(state.ws_ofmt);
5180 }
5181 
5182 static void
5183 do_scan_wifi(int argc, char **argv, const char *use)
5184 {
5185 	do_display_wifi(argc, argv, WIFI_CMD_SCAN, use);
5186 }
5187 
5188 static void
5189 do_show_wifi(int argc, char **argv, const char *use)
5190 {
5191 	do_display_wifi(argc, argv, WIFI_CMD_SHOW, use);
5192 }
5193 
5194 typedef struct wlan_count_attr {
5195 	uint_t		wc_count;
5196 	datalink_id_t	wc_linkid;
5197 } wlan_count_attr_t;
5198 
5199 /* ARGSUSED */
5200 static int
5201 do_count_wlan(dladm_handle_t dh, datalink_id_t linkid, void *arg)
5202 {
5203 	wlan_count_attr_t *cp = arg;
5204 
5205 	if (cp->wc_count == 0)
5206 		cp->wc_linkid = linkid;
5207 	cp->wc_count++;
5208 	return (DLADM_WALK_CONTINUE);
5209 }
5210 
5211 static int
5212 parse_wlan_keys(char *str, dladm_wlan_key_t **keys, uint_t *key_countp)
5213 {
5214 	uint_t			i;
5215 	dladm_wlan_key_t	*wk;
5216 	int			nfields = 1;
5217 	char			*field, *token, *lasts = NULL, c;
5218 
5219 	token = str;
5220 	while ((c = *token++) != NULL) {
5221 		if (c == ',')
5222 			nfields++;
5223 	}
5224 	token = strdup(str);
5225 	if (token == NULL)
5226 		return (-1);
5227 
5228 	wk = malloc(nfields * sizeof (dladm_wlan_key_t));
5229 	if (wk == NULL)
5230 		goto fail;
5231 
5232 	token = str;
5233 	for (i = 0; i < nfields; i++) {
5234 		char			*s;
5235 		dladm_secobj_class_t	class;
5236 		dladm_status_t		status;
5237 
5238 		field = strtok_r(token, ",", &lasts);
5239 		token = NULL;
5240 
5241 		(void) strlcpy(wk[i].wk_name, field,
5242 		    DLADM_WLAN_MAX_KEYNAME_LEN);
5243 
5244 		wk[i].wk_idx = 1;
5245 		if ((s = strrchr(wk[i].wk_name, ':')) != NULL) {
5246 			if (s[1] == '\0' || s[2] != '\0' || !isdigit(s[1]))
5247 				goto fail;
5248 
5249 			wk[i].wk_idx = (uint_t)(s[1] - '0');
5250 			*s = '\0';
5251 		}
5252 		wk[i].wk_len = DLADM_WLAN_MAX_KEY_LEN;
5253 
5254 		status = dladm_get_secobj(handle, wk[i].wk_name, &class,
5255 		    wk[i].wk_val, &wk[i].wk_len, 0);
5256 		if (status != DLADM_STATUS_OK) {
5257 			if (status == DLADM_STATUS_NOTFOUND) {
5258 				status = dladm_get_secobj(handle, wk[i].wk_name,
5259 				    &class, wk[i].wk_val, &wk[i].wk_len,
5260 				    DLADM_OPT_PERSIST);
5261 			}
5262 			if (status != DLADM_STATUS_OK)
5263 				goto fail;
5264 		}
5265 		wk[i].wk_class = class;
5266 	}
5267 	*keys = wk;
5268 	*key_countp = i;
5269 	free(token);
5270 	return (0);
5271 fail:
5272 	free(wk);
5273 	free(token);
5274 	return (-1);
5275 }
5276 
5277 static void
5278 do_connect_wifi(int argc, char **argv, const char *use)
5279 {
5280 	int			option;
5281 	dladm_wlan_attr_t	attr, *attrp;
5282 	dladm_status_t		status = DLADM_STATUS_OK;
5283 	int			timeout = DLADM_WLAN_CONNECT_TIMEOUT_DEFAULT;
5284 	datalink_id_t		linkid = DATALINK_ALL_LINKID;
5285 	dladm_wlan_key_t	*keys = NULL;
5286 	uint_t			key_count = 0;
5287 	uint_t			flags = 0;
5288 	dladm_wlan_secmode_t	keysecmode = DLADM_WLAN_SECMODE_NONE;
5289 	char			buf[DLADM_STRSIZE];
5290 
5291 	opterr = 0;
5292 	(void) memset(&attr, 0, sizeof (attr));
5293 	while ((option = getopt_long(argc, argv, ":e:i:a:m:b:s:k:T:c",
5294 	    wifi_longopts, NULL)) != -1) {
5295 		switch (option) {
5296 		case 'e':
5297 			status = dladm_wlan_str2essid(optarg, &attr.wa_essid);
5298 			if (status != DLADM_STATUS_OK)
5299 				die("invalid ESSID '%s'", optarg);
5300 
5301 			attr.wa_valid |= DLADM_WLAN_ATTR_ESSID;
5302 			/*
5303 			 * Try to connect without doing a scan.
5304 			 */
5305 			flags |= DLADM_WLAN_CONNECT_NOSCAN;
5306 			break;
5307 		case 'i':
5308 			status = dladm_wlan_str2bssid(optarg, &attr.wa_bssid);
5309 			if (status != DLADM_STATUS_OK)
5310 				die("invalid BSSID %s", optarg);
5311 
5312 			attr.wa_valid |= DLADM_WLAN_ATTR_BSSID;
5313 			break;
5314 		case 'a':
5315 			status = dladm_wlan_str2auth(optarg, &attr.wa_auth);
5316 			if (status != DLADM_STATUS_OK)
5317 				die("invalid authentication mode '%s'", optarg);
5318 
5319 			attr.wa_valid |= DLADM_WLAN_ATTR_AUTH;
5320 			break;
5321 		case 'm':
5322 			status = dladm_wlan_str2mode(optarg, &attr.wa_mode);
5323 			if (status != DLADM_STATUS_OK)
5324 				die("invalid mode '%s'", optarg);
5325 
5326 			attr.wa_valid |= DLADM_WLAN_ATTR_MODE;
5327 			break;
5328 		case 'b':
5329 			if ((status = dladm_wlan_str2bsstype(optarg,
5330 			    &attr.wa_bsstype)) != DLADM_STATUS_OK) {
5331 				die("invalid bsstype '%s'", optarg);
5332 			}
5333 
5334 			attr.wa_valid |= DLADM_WLAN_ATTR_BSSTYPE;
5335 			break;
5336 		case 's':
5337 			if ((status = dladm_wlan_str2secmode(optarg,
5338 			    &attr.wa_secmode)) != DLADM_STATUS_OK) {
5339 				die("invalid security mode '%s'", optarg);
5340 			}
5341 
5342 			attr.wa_valid |= DLADM_WLAN_ATTR_SECMODE;
5343 			break;
5344 		case 'k':
5345 			if (parse_wlan_keys(optarg, &keys, &key_count) < 0)
5346 				die("invalid key(s) '%s'", optarg);
5347 
5348 			if (keys[0].wk_class == DLADM_SECOBJ_CLASS_WEP)
5349 				keysecmode = DLADM_WLAN_SECMODE_WEP;
5350 			else
5351 				keysecmode = DLADM_WLAN_SECMODE_WPA;
5352 			break;
5353 		case 'T':
5354 			if (strcasecmp(optarg, "forever") == 0) {
5355 				timeout = -1;
5356 				break;
5357 			}
5358 			if (!str2int(optarg, &timeout) || timeout < 0)
5359 				die("invalid timeout value '%s'", optarg);
5360 			break;
5361 		case 'c':
5362 			flags |= DLADM_WLAN_CONNECT_CREATEIBSS;
5363 			flags |= DLADM_WLAN_CONNECT_CREATEIBSS;
5364 			break;
5365 		default:
5366 			die_opterr(optopt, option, use);
5367 			break;
5368 		}
5369 	}
5370 
5371 	if (keysecmode == DLADM_WLAN_SECMODE_NONE) {
5372 		if ((attr.wa_valid & DLADM_WLAN_ATTR_SECMODE) != 0) {
5373 			die("key required for security mode '%s'",
5374 			    dladm_wlan_secmode2str(&attr.wa_secmode, buf));
5375 		}
5376 	} else {
5377 		if ((attr.wa_valid & DLADM_WLAN_ATTR_SECMODE) != 0 &&
5378 		    attr.wa_secmode != keysecmode)
5379 			die("incompatible -s and -k options");
5380 		attr.wa_valid |= DLADM_WLAN_ATTR_SECMODE;
5381 		attr.wa_secmode = keysecmode;
5382 	}
5383 
5384 	if (optind == (argc - 1)) {
5385 		if ((status = dladm_name2info(handle, argv[optind], &linkid,
5386 		    NULL, NULL, NULL)) != DLADM_STATUS_OK) {
5387 			die_dlerr(status, "link %s is not valid", argv[optind]);
5388 		}
5389 	} else if (optind != argc) {
5390 		usage();
5391 	}
5392 
5393 	if (linkid == DATALINK_ALL_LINKID) {
5394 		wlan_count_attr_t wcattr;
5395 
5396 		wcattr.wc_linkid = DATALINK_INVALID_LINKID;
5397 		wcattr.wc_count = 0;
5398 		(void) dladm_walk_datalink_id(do_count_wlan, handle, &wcattr,
5399 		    DATALINK_CLASS_PHYS | DATALINK_CLASS_SIMNET,
5400 		    DL_WIFI, DLADM_OPT_ACTIVE);
5401 		if (wcattr.wc_count == 0) {
5402 			die("no wifi links are available");
5403 		} else if (wcattr.wc_count > 1) {
5404 			die("link name is required when more than one wifi "
5405 			    "link is available");
5406 		}
5407 		linkid = wcattr.wc_linkid;
5408 	}
5409 	attrp = (attr.wa_valid == 0) ? NULL : &attr;
5410 again:
5411 	if ((status = dladm_wlan_connect(handle, linkid, attrp, timeout, keys,
5412 	    key_count, flags)) != DLADM_STATUS_OK) {
5413 		if ((flags & DLADM_WLAN_CONNECT_NOSCAN) != 0) {
5414 			/*
5415 			 * Try again with scanning and filtering.
5416 			 */
5417 			flags &= ~DLADM_WLAN_CONNECT_NOSCAN;
5418 			goto again;
5419 		}
5420 
5421 		if (status == DLADM_STATUS_NOTFOUND) {
5422 			if (attr.wa_valid == 0) {
5423 				die("no wifi networks are available");
5424 			} else {
5425 				die("no wifi networks with the specified "
5426 				    "criteria are available");
5427 			}
5428 		}
5429 		die_dlerr(status, "cannot connect");
5430 	}
5431 	free(keys);
5432 }
5433 
5434 /* ARGSUSED */
5435 static int
5436 do_all_disconnect_wifi(dladm_handle_t dh, datalink_id_t linkid, void *arg)
5437 {
5438 	dladm_status_t	status;
5439 
5440 	status = dladm_wlan_disconnect(dh, linkid);
5441 	if (status != DLADM_STATUS_OK)
5442 		warn_dlerr(status, "cannot disconnect link");
5443 
5444 	return (DLADM_WALK_CONTINUE);
5445 }
5446 
5447 static void
5448 do_disconnect_wifi(int argc, char **argv, const char *use)
5449 {
5450 	int			option;
5451 	datalink_id_t		linkid = DATALINK_ALL_LINKID;
5452 	boolean_t		all_links = B_FALSE;
5453 	dladm_status_t		status;
5454 	wlan_count_attr_t	wcattr;
5455 
5456 	opterr = 0;
5457 	while ((option = getopt_long(argc, argv, ":a",
5458 	    wifi_longopts, NULL)) != -1) {
5459 		switch (option) {
5460 		case 'a':
5461 			all_links = B_TRUE;
5462 			break;
5463 		default:
5464 			die_opterr(optopt, option, use);
5465 			break;
5466 		}
5467 	}
5468 
5469 	if (optind == (argc - 1)) {
5470 		if ((status = dladm_name2info(handle, argv[optind], &linkid,
5471 		    NULL, NULL, NULL)) != DLADM_STATUS_OK) {
5472 			die_dlerr(status, "link %s is not valid", argv[optind]);
5473 		}
5474 	} else if (optind != argc) {
5475 		usage();
5476 	}
5477 
5478 	if (linkid == DATALINK_ALL_LINKID) {
5479 		if (!all_links) {
5480 			wcattr.wc_linkid = linkid;
5481 			wcattr.wc_count = 0;
5482 			(void) dladm_walk_datalink_id(do_count_wlan, handle,
5483 			    &wcattr,
5484 			    DATALINK_CLASS_PHYS | DATALINK_CLASS_SIMNET,
5485 			    DL_WIFI, DLADM_OPT_ACTIVE);
5486 			if (wcattr.wc_count == 0) {
5487 				die("no wifi links are available");
5488 			} else if (wcattr.wc_count > 1) {
5489 				die("link name is required when more than "
5490 				    "one wifi link is available");
5491 			}
5492 			linkid = wcattr.wc_linkid;
5493 		} else {
5494 			(void) dladm_walk_datalink_id(do_all_disconnect_wifi,
5495 			    handle, NULL,
5496 			    DATALINK_CLASS_PHYS | DATALINK_CLASS_SIMNET,
5497 			    DL_WIFI, DLADM_OPT_ACTIVE);
5498 			return;
5499 		}
5500 	}
5501 	status = dladm_wlan_disconnect(handle, linkid);
5502 	if (status != DLADM_STATUS_OK)
5503 		die_dlerr(status, "cannot disconnect");
5504 }
5505 
5506 static void
5507 print_linkprop(datalink_id_t linkid, show_linkprop_state_t *statep,
5508     const char *propname, dladm_prop_type_t type, const char *format,
5509     char **pptr)
5510 {
5511 	int		i;
5512 	char		*ptr, *lim;
5513 	char		buf[DLADM_STRSIZE];
5514 	char		*unknown = "--", *notsup = "";
5515 	char		**propvals = statep->ls_propvals;
5516 	uint_t		valcnt = DLADM_MAX_PROP_VALCNT;
5517 	dladm_status_t	status;
5518 
5519 	status = dladm_get_linkprop(handle, linkid, type, propname, propvals,
5520 	    &valcnt);
5521 	if (status != DLADM_STATUS_OK) {
5522 		if (status == DLADM_STATUS_TEMPONLY) {
5523 			if (type == DLADM_PROP_VAL_MODIFIABLE &&
5524 			    statep->ls_persist) {
5525 				valcnt = 1;
5526 				propvals = &unknown;
5527 			} else {
5528 				statep->ls_status = status;
5529 				statep->ls_retstatus = status;
5530 				return;
5531 			}
5532 		} else if (status == DLADM_STATUS_NOTSUP ||
5533 		    statep->ls_persist) {
5534 			valcnt = 1;
5535 			if (type == DLADM_PROP_VAL_CURRENT ||
5536 			    type == DLADM_PROP_VAL_PERM)
5537 				propvals = &unknown;
5538 			else
5539 				propvals = &notsup;
5540 		} else if (status == DLADM_STATUS_NOTDEFINED) {
5541 			propvals = &notsup; /* STR_UNDEF_VAL */
5542 		} else {
5543 			if (statep->ls_proplist &&
5544 			    statep->ls_status == DLADM_STATUS_OK) {
5545 				warn_dlerr(status,
5546 				    "cannot get link property '%s' for %s",
5547 				    propname, statep->ls_link);
5548 			}
5549 			statep->ls_status = status;
5550 			statep->ls_retstatus = status;
5551 			return;
5552 		}
5553 	}
5554 
5555 	statep->ls_status = DLADM_STATUS_OK;
5556 
5557 	ptr = buf;
5558 	lim = buf + DLADM_STRSIZE;
5559 	for (i = 0; i < valcnt; i++) {
5560 		if (propvals[i][0] == '\0' && !statep->ls_parsable)
5561 			ptr += snprintf(ptr, lim - ptr, "--,");
5562 		else
5563 			ptr += snprintf(ptr, lim - ptr, "%s,", propvals[i]);
5564 		if (ptr >= lim)
5565 			break;
5566 	}
5567 	if (valcnt > 0)
5568 		buf[strlen(buf) - 1] = '\0';
5569 
5570 	lim = statep->ls_line + MAX_PROP_LINE;
5571 	if (statep->ls_parsable) {
5572 		*pptr += snprintf(*pptr, lim - *pptr,
5573 		    "%s", buf);
5574 	} else {
5575 		*pptr += snprintf(*pptr, lim - *pptr, format, buf);
5576 	}
5577 }
5578 
5579 static boolean_t
5580 print_linkprop_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
5581 {
5582 	linkprop_args_t		*arg = ofarg->ofmt_cbarg;
5583 	char 			*propname = arg->ls_propname;
5584 	show_linkprop_state_t	*statep = arg->ls_state;
5585 	char			*ptr = statep->ls_line;
5586 	char			*lim = ptr + MAX_PROP_LINE;
5587 	datalink_id_t		linkid = arg->ls_linkid;
5588 
5589 	switch (ofarg->ofmt_id) {
5590 	case LINKPROP_LINK:
5591 		(void) snprintf(ptr, lim - ptr, "%s", statep->ls_link);
5592 		break;
5593 	case LINKPROP_PROPERTY:
5594 		(void) snprintf(ptr, lim - ptr, "%s", propname);
5595 		break;
5596 	case LINKPROP_VALUE:
5597 		print_linkprop(linkid, statep, propname,
5598 		    statep->ls_persist ? DLADM_PROP_VAL_PERSISTENT :
5599 		    DLADM_PROP_VAL_CURRENT, "%s", &ptr);
5600 		/*
5601 		 * If we failed to query the link property, for example, query
5602 		 * the persistent value of a non-persistable link property,
5603 		 * simply skip the output.
5604 		 */
5605 		if (statep->ls_status != DLADM_STATUS_OK)
5606 			goto skip;
5607 		ptr = statep->ls_line;
5608 		break;
5609 	case LINKPROP_PERM:
5610 		print_linkprop(linkid, statep, propname,
5611 		    DLADM_PROP_VAL_PERM, "%s", &ptr);
5612 		if (statep->ls_status != DLADM_STATUS_OK)
5613 			goto skip;
5614 		ptr = statep->ls_line;
5615 		break;
5616 	case LINKPROP_DEFAULT:
5617 		print_linkprop(linkid, statep, propname,
5618 		    DLADM_PROP_VAL_DEFAULT, "%s", &ptr);
5619 		if (statep->ls_status != DLADM_STATUS_OK)
5620 			goto skip;
5621 		ptr = statep->ls_line;
5622 		break;
5623 	case LINKPROP_POSSIBLE:
5624 		print_linkprop(linkid, statep, propname,
5625 		    DLADM_PROP_VAL_MODIFIABLE, "%s ", &ptr);
5626 		if (statep->ls_status != DLADM_STATUS_OK)
5627 			goto skip;
5628 		ptr = statep->ls_line;
5629 		break;
5630 	default:
5631 		die("invalid input");
5632 		break;
5633 	}
5634 	(void) strlcpy(buf, ptr, bufsize);
5635 	return (B_TRUE);
5636 skip:
5637 	return ((statep->ls_status == DLADM_STATUS_OK) ?
5638 	    B_TRUE : B_FALSE);
5639 }
5640 
5641 static boolean_t
5642 linkprop_is_supported(datalink_id_t  linkid, const char *propname,
5643     show_linkprop_state_t *statep)
5644 {
5645 	dladm_status_t	status;
5646 	uint_t		valcnt = DLADM_MAX_PROP_VALCNT;
5647 
5648 	/* if used with -p flag, always print output */
5649 	if (statep->ls_proplist != NULL)
5650 		return (B_TRUE);
5651 
5652 	status = dladm_get_linkprop(handle, linkid, DLADM_PROP_VAL_DEFAULT,
5653 	    propname, statep->ls_propvals, &valcnt);
5654 
5655 	if (status == DLADM_STATUS_OK)
5656 		return (B_TRUE);
5657 
5658 	/*
5659 	 * A system wide default value is not available for the
5660 	 * property. Check if current value can be retrieved.
5661 	 */
5662 	status = dladm_get_linkprop(handle, linkid, DLADM_PROP_VAL_CURRENT,
5663 	    propname, statep->ls_propvals, &valcnt);
5664 
5665 	return (status == DLADM_STATUS_OK);
5666 }
5667 
5668 /* ARGSUSED */
5669 static int
5670 show_linkprop(dladm_handle_t dh, datalink_id_t linkid, const char *propname,
5671     void *arg)
5672 {
5673 	show_linkprop_state_t	*statep = arg;
5674 	linkprop_args_t		ls_arg;
5675 
5676 	bzero(&ls_arg, sizeof (ls_arg));
5677 	ls_arg.ls_state = statep;
5678 	ls_arg.ls_propname = (char *)propname;
5679 	ls_arg.ls_linkid = linkid;
5680 
5681 	/*
5682 	 * This will need to be fixed when kernel interfaces are added
5683 	 * to enable walking of all known private properties. For now,
5684 	 * we are limited to walking persistent private properties only.
5685 	 */
5686 	if ((propname[0] == '_') && !statep->ls_persist &&
5687 	    (statep->ls_proplist == NULL))
5688 		return (DLADM_WALK_CONTINUE);
5689 	if (!statep->ls_parsable &&
5690 	    !linkprop_is_supported(linkid, propname, statep))
5691 		return (DLADM_WALK_CONTINUE);
5692 
5693 	ofmt_print(statep->ls_ofmt, &ls_arg);
5694 
5695 	return (DLADM_WALK_CONTINUE);
5696 }
5697 
5698 static void
5699 do_show_linkprop(int argc, char **argv, const char *use)
5700 {
5701 	int			option;
5702 	char			propstr[DLADM_STRSIZE];
5703 	dladm_arg_list_t	*proplist = NULL;
5704 	datalink_id_t		linkid = DATALINK_ALL_LINKID;
5705 	show_linkprop_state_t	state;
5706 	uint32_t		flags = DLADM_OPT_ACTIVE;
5707 	dladm_status_t		status;
5708 	char			*fields_str = NULL;
5709 	ofmt_handle_t		ofmt;
5710 	ofmt_status_t		oferr;
5711 	uint_t			ofmtflags = 0;
5712 
5713 	bzero(propstr, DLADM_STRSIZE);
5714 	opterr = 0;
5715 	state.ls_propvals = NULL;
5716 	state.ls_line = NULL;
5717 	state.ls_parsable = B_FALSE;
5718 	state.ls_persist = B_FALSE;
5719 	state.ls_header = B_TRUE;
5720 	state.ls_retstatus = DLADM_STATUS_OK;
5721 
5722 	while ((option = getopt_long(argc, argv, ":p:cPo:",
5723 	    prop_longopts, NULL)) != -1) {
5724 		switch (option) {
5725 		case 'p':
5726 			(void) strlcat(propstr, optarg, DLADM_STRSIZE);
5727 			if (strlcat(propstr, ",", DLADM_STRSIZE) >=
5728 			    DLADM_STRSIZE)
5729 				die("property list too long '%s'", propstr);
5730 			break;
5731 		case 'c':
5732 			state.ls_parsable = B_TRUE;
5733 			break;
5734 		case 'P':
5735 			state.ls_persist = B_TRUE;
5736 			flags = DLADM_OPT_PERSIST;
5737 			break;
5738 		case 'o':
5739 			fields_str = optarg;
5740 			break;
5741 		default:
5742 			die_opterr(optopt, option, use);
5743 			break;
5744 		}
5745 	}
5746 
5747 	if (optind == (argc - 1)) {
5748 		if ((status = dladm_name2info(handle, argv[optind], &linkid,
5749 		    NULL, NULL, NULL)) != DLADM_STATUS_OK) {
5750 			die_dlerr(status, "link %s is not valid", argv[optind]);
5751 		}
5752 	} else if (optind != argc) {
5753 		usage();
5754 	}
5755 
5756 	if (dladm_parse_link_props(propstr, &proplist, B_TRUE)
5757 	    != DLADM_STATUS_OK)
5758 		die("invalid link properties specified");
5759 	state.ls_proplist = proplist;
5760 	state.ls_status = DLADM_STATUS_OK;
5761 
5762 	if (state.ls_parsable)
5763 		ofmtflags |= OFMT_PARSABLE;
5764 	oferr = ofmt_open(fields_str, linkprop_fields, ofmtflags, 0, &ofmt);
5765 	dladm_ofmt_check(oferr, state.ls_parsable, ofmt);
5766 	state.ls_ofmt = ofmt;
5767 
5768 	if (linkid == DATALINK_ALL_LINKID) {
5769 		(void) dladm_walk_datalink_id(show_linkprop_onelink, handle,
5770 		    &state, DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE, flags);
5771 	} else {
5772 		(void) show_linkprop_onelink(handle, linkid, &state);
5773 	}
5774 	ofmt_close(ofmt);
5775 	dladm_free_props(proplist);
5776 
5777 	if (state.ls_retstatus != DLADM_STATUS_OK) {
5778 		dladm_close(handle);
5779 		exit(EXIT_FAILURE);
5780 	}
5781 }
5782 
5783 static int
5784 show_linkprop_onelink(dladm_handle_t hdl, datalink_id_t linkid, void *arg)
5785 {
5786 	int			i;
5787 	char			*buf;
5788 	uint32_t		flags;
5789 	dladm_arg_list_t	*proplist = NULL;
5790 	show_linkprop_state_t	*statep = arg;
5791 	dlpi_handle_t		dh = NULL;
5792 
5793 	statep->ls_status = DLADM_STATUS_OK;
5794 
5795 	if (dladm_datalink_id2info(hdl, linkid, &flags, NULL, NULL,
5796 	    statep->ls_link, MAXLINKNAMELEN) != DLADM_STATUS_OK) {
5797 		statep->ls_status = DLADM_STATUS_NOTFOUND;
5798 		return (DLADM_WALK_CONTINUE);
5799 	}
5800 
5801 	if ((statep->ls_persist && !(flags & DLADM_OPT_PERSIST)) ||
5802 	    (!statep->ls_persist && !(flags & DLADM_OPT_ACTIVE))) {
5803 		statep->ls_status = DLADM_STATUS_BADARG;
5804 		return (DLADM_WALK_CONTINUE);
5805 	}
5806 
5807 	proplist = statep->ls_proplist;
5808 
5809 	/*
5810 	 * When some WiFi links are opened for the first time, their hardware
5811 	 * automatically scans for APs and does other slow operations.	Thus,
5812 	 * if there are no open links, the retrieval of link properties
5813 	 * (below) will proceed slowly unless we hold the link open.
5814 	 *
5815 	 * Note that failure of dlpi_open() does not necessarily mean invalid
5816 	 * link properties, because dlpi_open() may fail because of incorrect
5817 	 * autopush configuration. Therefore, we ingore the return value of
5818 	 * dlpi_open().
5819 	 */
5820 	if (!statep->ls_persist)
5821 		(void) dlpi_open(statep->ls_link, &dh, 0);
5822 
5823 	buf = malloc((sizeof (char *) + DLADM_PROP_VAL_MAX) *
5824 	    DLADM_MAX_PROP_VALCNT + MAX_PROP_LINE);
5825 	if (buf == NULL)
5826 		die("insufficient memory");
5827 
5828 	statep->ls_propvals = (char **)(void *)buf;
5829 	for (i = 0; i < DLADM_MAX_PROP_VALCNT; i++) {
5830 		statep->ls_propvals[i] = buf +
5831 		    sizeof (char *) * DLADM_MAX_PROP_VALCNT +
5832 		    i * DLADM_PROP_VAL_MAX;
5833 	}
5834 	statep->ls_line = buf +
5835 	    (sizeof (char *) + DLADM_PROP_VAL_MAX) * DLADM_MAX_PROP_VALCNT;
5836 
5837 	if (proplist != NULL) {
5838 		for (i = 0; i < proplist->al_count; i++) {
5839 			(void) show_linkprop(hdl, linkid,
5840 			    proplist->al_info[i].ai_name, statep);
5841 		}
5842 	} else {
5843 		(void) dladm_walk_linkprop(hdl, linkid, statep,
5844 		    show_linkprop);
5845 	}
5846 	if (dh != NULL)
5847 		dlpi_close(dh);
5848 	free(buf);
5849 	return (DLADM_WALK_CONTINUE);
5850 }
5851 
5852 static dladm_status_t
5853 set_linkprop_persist(datalink_id_t linkid, const char *prop_name,
5854     char **prop_val, uint_t val_cnt, boolean_t reset)
5855 {
5856 	dladm_status_t	status;
5857 
5858 	status = dladm_set_linkprop(handle, linkid, prop_name, prop_val,
5859 	    val_cnt, DLADM_OPT_PERSIST);
5860 
5861 	if (status != DLADM_STATUS_OK) {
5862 		warn_dlerr(status, "cannot persistently %s link property '%s'",
5863 		    reset ? "reset" : "set", prop_name);
5864 	}
5865 	return (status);
5866 }
5867 
5868 static int
5869 reset_one_linkprop(dladm_handle_t dh, datalink_id_t linkid,
5870     const char *propname, void *arg)
5871 {
5872 	set_linkprop_state_t	*statep = arg;
5873 	dladm_status_t		status;
5874 
5875 	status = dladm_set_linkprop(dh, linkid, propname, NULL, 0,
5876 	    DLADM_OPT_ACTIVE);
5877 	if (status != DLADM_STATUS_OK &&
5878 	    status != DLADM_STATUS_PROPRDONLY &&
5879 	    status != DLADM_STATUS_NOTSUP) {
5880 		warn_dlerr(status, "cannot reset link property '%s' on '%s'",
5881 		    propname, statep->ls_name);
5882 	}
5883 	if (!statep->ls_temp) {
5884 		dladm_status_t	s;
5885 
5886 		s = set_linkprop_persist(linkid, propname, NULL, 0,
5887 		    statep->ls_reset);
5888 		if (s != DLADM_STATUS_OK)
5889 			status = s;
5890 	}
5891 	if (status != DLADM_STATUS_OK)
5892 		statep->ls_status = status;
5893 
5894 	return (DLADM_WALK_CONTINUE);
5895 }
5896 
5897 static void
5898 set_linkprop(int argc, char **argv, boolean_t reset, const char *use)
5899 {
5900 	int			i, option;
5901 	char			errmsg[DLADM_STRSIZE];
5902 	char			*altroot = NULL;
5903 	datalink_id_t		linkid;
5904 	boolean_t		temp = B_FALSE;
5905 	dladm_status_t		status = DLADM_STATUS_OK;
5906 	char			propstr[DLADM_STRSIZE];
5907 	dladm_arg_list_t	*proplist = NULL;
5908 
5909 	opterr = 0;
5910 	bzero(propstr, DLADM_STRSIZE);
5911 
5912 	while ((option = getopt_long(argc, argv, ":p:R:t",
5913 	    prop_longopts, NULL)) != -1) {
5914 		switch (option) {
5915 		case 'p':
5916 			(void) strlcat(propstr, optarg, DLADM_STRSIZE);
5917 			if (strlcat(propstr, ",", DLADM_STRSIZE) >=
5918 			    DLADM_STRSIZE)
5919 				die("property list too long '%s'", propstr);
5920 			break;
5921 		case 't':
5922 			temp = B_TRUE;
5923 			break;
5924 		case 'R':
5925 			altroot = optarg;
5926 			break;
5927 		default:
5928 			die_opterr(optopt, option, use);
5929 
5930 		}
5931 	}
5932 
5933 	/* get link name (required last argument) */
5934 	if (optind != (argc - 1))
5935 		usage();
5936 
5937 	if (dladm_parse_link_props(propstr, &proplist, reset) !=
5938 	    DLADM_STATUS_OK)
5939 		die("invalid link properties specified");
5940 
5941 	if (proplist == NULL && !reset)
5942 		die("link property must be specified");
5943 
5944 	if (altroot != NULL) {
5945 		dladm_free_props(proplist);
5946 		altroot_cmd(altroot, argc, argv);
5947 	}
5948 
5949 	status = dladm_name2info(handle, argv[optind], &linkid, NULL, NULL,
5950 	    NULL);
5951 	if (status != DLADM_STATUS_OK)
5952 		die_dlerr(status, "link %s is not valid", argv[optind]);
5953 
5954 	if (proplist == NULL) {
5955 		set_linkprop_state_t	state;
5956 
5957 		state.ls_name = argv[optind];
5958 		state.ls_reset = reset;
5959 		state.ls_temp = temp;
5960 		state.ls_status = DLADM_STATUS_OK;
5961 
5962 		(void) dladm_walk_linkprop(handle, linkid, &state,
5963 		    reset_one_linkprop);
5964 
5965 		status = state.ls_status;
5966 		goto done;
5967 	}
5968 
5969 	for (i = 0; i < proplist->al_count; i++) {
5970 		dladm_arg_info_t	*aip = &proplist->al_info[i];
5971 		char		**val;
5972 		uint_t		count;
5973 		dladm_status_t	s;
5974 
5975 		if (reset) {
5976 			val = NULL;
5977 			count = 0;
5978 		} else {
5979 			val = aip->ai_val;
5980 			count = aip->ai_count;
5981 			if (count == 0) {
5982 				warn("no value specified for '%s'",
5983 				    aip->ai_name);
5984 				status = DLADM_STATUS_BADARG;
5985 				continue;
5986 			}
5987 		}
5988 		s = dladm_set_linkprop(handle, linkid, aip->ai_name, val, count,
5989 		    DLADM_OPT_ACTIVE);
5990 		if (s == DLADM_STATUS_OK) {
5991 			if (!temp) {
5992 				s = set_linkprop_persist(linkid,
5993 				    aip->ai_name, val, count, reset);
5994 				if (s != DLADM_STATUS_OK)
5995 					status = s;
5996 			}
5997 			continue;
5998 		}
5999 		status = s;
6000 		switch (s) {
6001 		case DLADM_STATUS_NOTFOUND:
6002 			warn("invalid link property '%s'", aip->ai_name);
6003 			break;
6004 		case DLADM_STATUS_BADVAL: {
6005 			int		j;
6006 			char		*ptr, *lim;
6007 			char		**propvals = NULL;
6008 			uint_t		valcnt = DLADM_MAX_PROP_VALCNT;
6009 
6010 			ptr = malloc((sizeof (char *) +
6011 			    DLADM_PROP_VAL_MAX) * DLADM_MAX_PROP_VALCNT +
6012 			    MAX_PROP_LINE);
6013 
6014 			propvals = (char **)(void *)ptr;
6015 			if (propvals == NULL)
6016 				die("insufficient memory");
6017 
6018 			for (j = 0; j < DLADM_MAX_PROP_VALCNT; j++) {
6019 				propvals[j] = ptr + sizeof (char *) *
6020 				    DLADM_MAX_PROP_VALCNT +
6021 				    j * DLADM_PROP_VAL_MAX;
6022 			}
6023 			s = dladm_get_linkprop(handle, linkid,
6024 			    DLADM_PROP_VAL_MODIFIABLE, aip->ai_name, propvals,
6025 			    &valcnt);
6026 
6027 			if (s != DLADM_STATUS_OK) {
6028 				warn_dlerr(status, "cannot set link property "
6029 				    "'%s' on '%s'", aip->ai_name, argv[optind]);
6030 				free(propvals);
6031 				break;
6032 			}
6033 
6034 			ptr = errmsg;
6035 			lim = ptr + DLADM_STRSIZE;
6036 			*ptr = '\0';
6037 			for (j = 0; j < valcnt; j++) {
6038 				ptr += snprintf(ptr, lim - ptr, "%s,",
6039 				    propvals[j]);
6040 				if (ptr >= lim)
6041 					break;
6042 			}
6043 			if (ptr > errmsg) {
6044 				*(ptr - 1) = '\0';
6045 				warn("link property '%s' must be one of: %s",
6046 				    aip->ai_name, errmsg);
6047 			} else
6048 				warn("invalid link property '%s'", *val);
6049 			free(propvals);
6050 			break;
6051 		}
6052 		default:
6053 			if (reset) {
6054 				warn_dlerr(status, "cannot reset link property "
6055 				    "'%s' on '%s'", aip->ai_name, argv[optind]);
6056 			} else {
6057 				warn_dlerr(status, "cannot set link property "
6058 				    "'%s' on '%s'", aip->ai_name, argv[optind]);
6059 			}
6060 			break;
6061 		}
6062 	}
6063 done:
6064 	dladm_free_props(proplist);
6065 	if (status != DLADM_STATUS_OK) {
6066 		dladm_close(handle);
6067 		exit(1);
6068 	}
6069 }
6070 
6071 static void
6072 do_set_linkprop(int argc, char **argv, const char *use)
6073 {
6074 	set_linkprop(argc, argv, B_FALSE, use);
6075 }
6076 
6077 static void
6078 do_reset_linkprop(int argc, char **argv, const char *use)
6079 {
6080 	set_linkprop(argc, argv, B_TRUE, use);
6081 }
6082 
6083 static int
6084 convert_secobj(char *buf, uint_t len, uint8_t *obj_val, uint_t *obj_lenp,
6085     dladm_secobj_class_t class)
6086 {
6087 	int error = 0;
6088 
6089 	if (class == DLADM_SECOBJ_CLASS_WPA) {
6090 		if (len < 8 || len > 63)
6091 			return (EINVAL);
6092 		(void) memcpy(obj_val, buf, len);
6093 		*obj_lenp = len;
6094 		return (error);
6095 	}
6096 
6097 	if (class == DLADM_SECOBJ_CLASS_WEP) {
6098 		switch (len) {
6099 		case 5:			/* ASCII key sizes */
6100 		case 13:
6101 			(void) memcpy(obj_val, buf, len);
6102 			*obj_lenp = len;
6103 			break;
6104 		case 10:		/* Hex key sizes, not preceded by 0x */
6105 		case 26:
6106 			error = hexascii_to_octet(buf, len, obj_val, obj_lenp);
6107 			break;
6108 		case 12:		/* Hex key sizes, preceded by 0x */
6109 		case 28:
6110 			if (strncmp(buf, "0x", 2) != 0)
6111 				return (EINVAL);
6112 			error = hexascii_to_octet(buf + 2, len - 2,
6113 			    obj_val, obj_lenp);
6114 			break;
6115 		default:
6116 			return (EINVAL);
6117 		}
6118 		return (error);
6119 	}
6120 
6121 	return (ENOENT);
6122 }
6123 
6124 static void
6125 defersig(int sig)
6126 {
6127 	signalled = sig;
6128 }
6129 
6130 static int
6131 get_secobj_from_tty(uint_t try, const char *objname, char *buf)
6132 {
6133 	uint_t		len = 0;
6134 	int		c;
6135 	struct termios	stored, current;
6136 	void		(*sigfunc)(int);
6137 
6138 	/*
6139 	 * Turn off echo -- but before we do so, defer SIGINT handling
6140 	 * so that a ^C doesn't leave the terminal corrupted.
6141 	 */
6142 	sigfunc = signal(SIGINT, defersig);
6143 	(void) fflush(stdin);
6144 	(void) tcgetattr(0, &stored);
6145 	current = stored;
6146 	current.c_lflag &= ~(ICANON|ECHO);
6147 	current.c_cc[VTIME] = 0;
6148 	current.c_cc[VMIN] = 1;
6149 	(void) tcsetattr(0, TCSANOW, &current);
6150 again:
6151 	if (try == 1)
6152 		(void) printf(gettext("provide value for '%s': "), objname);
6153 	else
6154 		(void) printf(gettext("confirm value for '%s': "), objname);
6155 
6156 	(void) fflush(stdout);
6157 	while (signalled == 0) {
6158 		c = getchar();
6159 		if (c == '\n' || c == '\r') {
6160 			if (len != 0)
6161 				break;
6162 			(void) putchar('\n');
6163 			goto again;
6164 		}
6165 
6166 		buf[len++] = c;
6167 		if (len >= DLADM_SECOBJ_VAL_MAX - 1)
6168 			break;
6169 		(void) putchar('*');
6170 	}
6171 
6172 	(void) putchar('\n');
6173 	(void) fflush(stdin);
6174 
6175 	/*
6176 	 * Restore terminal setting and handle deferred signals.
6177 	 */
6178 	(void) tcsetattr(0, TCSANOW, &stored);
6179 
6180 	(void) signal(SIGINT, sigfunc);
6181 	if (signalled != 0)
6182 		(void) kill(getpid(), signalled);
6183 
6184 	return (len);
6185 }
6186 
6187 static int
6188 get_secobj_val(char *obj_name, uint8_t *obj_val, uint_t *obj_lenp,
6189     dladm_secobj_class_t class, FILE *filep)
6190 {
6191 	int		rval;
6192 	uint_t		len, len2;
6193 	char		buf[DLADM_SECOBJ_VAL_MAX], buf2[DLADM_SECOBJ_VAL_MAX];
6194 
6195 	if (filep == NULL) {
6196 		len = get_secobj_from_tty(1, obj_name, buf);
6197 		rval = convert_secobj(buf, len, obj_val, obj_lenp, class);
6198 		if (rval == 0) {
6199 			len2 = get_secobj_from_tty(2, obj_name, buf2);
6200 			if (len != len2 || memcmp(buf, buf2, len) != 0)
6201 				rval = ENOTSUP;
6202 		}
6203 		return (rval);
6204 	} else {
6205 		for (;;) {
6206 			if (fgets(buf, sizeof (buf), filep) == NULL)
6207 				break;
6208 			if (isspace(buf[0]))
6209 				continue;
6210 
6211 			len = strlen(buf);
6212 			if (buf[len - 1] == '\n') {
6213 				buf[len - 1] = '\0';
6214 				len--;
6215 			}
6216 			break;
6217 		}
6218 		(void) fclose(filep);
6219 	}
6220 	return (convert_secobj(buf, len, obj_val, obj_lenp, class));
6221 }
6222 
6223 static boolean_t
6224 check_auth(const char *auth)
6225 {
6226 	struct passwd	*pw;
6227 
6228 	if ((pw = getpwuid(getuid())) == NULL)
6229 		return (B_FALSE);
6230 
6231 	return (chkauthattr(auth, pw->pw_name) != 0);
6232 }
6233 
6234 static void
6235 audit_secobj(char *auth, char *class, char *obj,
6236     boolean_t success, boolean_t create)
6237 {
6238 	adt_session_data_t	*ah;
6239 	adt_event_data_t	*event;
6240 	au_event_t		flag;
6241 	char			*errstr;
6242 
6243 	if (create) {
6244 		flag = ADT_dladm_create_secobj;
6245 		errstr = "ADT_dladm_create_secobj";
6246 	} else {
6247 		flag = ADT_dladm_delete_secobj;
6248 		errstr = "ADT_dladm_delete_secobj";
6249 	}
6250 
6251 	if (adt_start_session(&ah, NULL, ADT_USE_PROC_DATA) != 0)
6252 		die("adt_start_session: %s", strerror(errno));
6253 
6254 	if ((event = adt_alloc_event(ah, flag)) == NULL)
6255 		die("adt_alloc_event (%s): %s", errstr, strerror(errno));
6256 
6257 	/* fill in audit info */
6258 	if (create) {
6259 		event->adt_dladm_create_secobj.auth_used = auth;
6260 		event->adt_dladm_create_secobj.obj_class = class;
6261 		event->adt_dladm_create_secobj.obj_name = obj;
6262 	} else {
6263 		event->adt_dladm_delete_secobj.auth_used = auth;
6264 		event->adt_dladm_delete_secobj.obj_class = class;
6265 		event->adt_dladm_delete_secobj.obj_name = obj;
6266 	}
6267 
6268 	if (success) {
6269 		if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS) != 0) {
6270 			die("adt_put_event (%s, success): %s", errstr,
6271 			    strerror(errno));
6272 		}
6273 	} else {
6274 		if (adt_put_event(event, ADT_FAILURE,
6275 		    ADT_FAIL_VALUE_AUTH) != 0) {
6276 			die("adt_put_event: (%s, failure): %s", errstr,
6277 			    strerror(errno));
6278 		}
6279 	}
6280 
6281 	adt_free_event(event);
6282 	(void) adt_end_session(ah);
6283 }
6284 
6285 #define	MAX_SECOBJS		32
6286 #define	MAX_SECOBJ_NAMELEN	32
6287 static void
6288 do_create_secobj(int argc, char **argv, const char *use)
6289 {
6290 	int			option, rval;
6291 	FILE			*filep = NULL;
6292 	char			*obj_name = NULL;
6293 	char			*class_name = NULL;
6294 	uint8_t			obj_val[DLADM_SECOBJ_VAL_MAX];
6295 	uint_t			obj_len;
6296 	boolean_t		success, temp = B_FALSE;
6297 	dladm_status_t		status;
6298 	dladm_secobj_class_t	class = -1;
6299 	uid_t			euid;
6300 
6301 	opterr = 0;
6302 	(void) memset(obj_val, 0, DLADM_SECOBJ_VAL_MAX);
6303 	while ((option = getopt_long(argc, argv, ":f:c:R:t",
6304 	    wifi_longopts, NULL)) != -1) {
6305 		switch (option) {
6306 		case 'f':
6307 			euid = geteuid();
6308 			(void) seteuid(getuid());
6309 			filep = fopen(optarg, "r");
6310 			if (filep == NULL) {
6311 				die("cannot open %s: %s", optarg,
6312 				    strerror(errno));
6313 			}
6314 			(void) seteuid(euid);
6315 			break;
6316 		case 'c':
6317 			class_name = optarg;
6318 			status = dladm_str2secobjclass(optarg, &class);
6319 			if (status != DLADM_STATUS_OK) {
6320 				die("invalid secure object class '%s', "
6321 				    "valid values are: wep, wpa", optarg);
6322 			}
6323 			break;
6324 		case 't':
6325 			temp = B_TRUE;
6326 			break;
6327 		case 'R':
6328 			status = dladm_set_rootdir(optarg);
6329 			if (status != DLADM_STATUS_OK) {
6330 				die_dlerr(status, "invalid directory "
6331 				    "specified");
6332 			}
6333 			break;
6334 		default:
6335 			die_opterr(optopt, option, use);
6336 			break;
6337 		}
6338 	}
6339 
6340 	if (optind == (argc - 1))
6341 		obj_name = argv[optind];
6342 	else if (optind != argc)
6343 		usage();
6344 
6345 	if (class == -1)
6346 		die("secure object class required");
6347 
6348 	if (obj_name == NULL)
6349 		die("secure object name required");
6350 
6351 	if (!dladm_valid_secobj_name(obj_name))
6352 		die("invalid secure object name '%s'", obj_name);
6353 
6354 	success = check_auth(LINK_SEC_AUTH);
6355 	audit_secobj(LINK_SEC_AUTH, class_name, obj_name, success, B_TRUE);
6356 	if (!success)
6357 		die("authorization '%s' is required", LINK_SEC_AUTH);
6358 
6359 	rval = get_secobj_val(obj_name, obj_val, &obj_len, class, filep);
6360 	if (rval != 0) {
6361 		switch (rval) {
6362 		case ENOENT:
6363 			die("invalid secure object class");
6364 			break;
6365 		case EINVAL:
6366 			die("invalid secure object value");
6367 			break;
6368 		case ENOTSUP:
6369 			die("verification failed");
6370 			break;
6371 		default:
6372 			die("invalid secure object: %s", strerror(rval));
6373 			break;
6374 		}
6375 	}
6376 
6377 	status = dladm_set_secobj(handle, obj_name, class, obj_val, obj_len,
6378 	    DLADM_OPT_CREATE | DLADM_OPT_ACTIVE);
6379 	if (status != DLADM_STATUS_OK) {
6380 		die_dlerr(status, "could not create secure object '%s'",
6381 		    obj_name);
6382 	}
6383 	if (temp)
6384 		return;
6385 
6386 	status = dladm_set_secobj(handle, obj_name, class, obj_val, obj_len,
6387 	    DLADM_OPT_PERSIST);
6388 	if (status != DLADM_STATUS_OK) {
6389 		warn_dlerr(status, "could not persistently create secure "
6390 		    "object '%s'", obj_name);
6391 	}
6392 }
6393 
6394 static void
6395 do_delete_secobj(int argc, char **argv, const char *use)
6396 {
6397 	int		i, option;
6398 	boolean_t	temp = B_FALSE;
6399 	boolean_t	success;
6400 	dladm_status_t	status, pstatus;
6401 	int		nfields = 1;
6402 	char		*field, *token, *lasts = NULL, c;
6403 
6404 	opterr = 0;
6405 	status = pstatus = DLADM_STATUS_OK;
6406 	while ((option = getopt_long(argc, argv, ":R:t",
6407 	    wifi_longopts, NULL)) != -1) {
6408 		switch (option) {
6409 		case 't':
6410 			temp = B_TRUE;
6411 			break;
6412 		case 'R':
6413 			status = dladm_set_rootdir(optarg);
6414 			if (status != DLADM_STATUS_OK) {
6415 				die_dlerr(status, "invalid directory "
6416 				    "specified");
6417 			}
6418 			break;
6419 		default:
6420 			die_opterr(optopt, option, use);
6421 			break;
6422 		}
6423 	}
6424 
6425 	if (optind == (argc - 1)) {
6426 		token = argv[optind];
6427 		if (token == NULL)
6428 			die("secure object name required");
6429 		while ((c = *token++) != NULL) {
6430 			if (c == ',')
6431 				nfields++;
6432 		}
6433 		token = strdup(argv[optind]);
6434 		if (token == NULL)
6435 			die("no memory");
6436 	} else if (optind != argc)
6437 		usage();
6438 
6439 	success = check_auth(LINK_SEC_AUTH);
6440 	audit_secobj(LINK_SEC_AUTH, "unknown", argv[optind], success, B_FALSE);
6441 	if (!success)
6442 		die("authorization '%s' is required", LINK_SEC_AUTH);
6443 
6444 	for (i = 0; i < nfields; i++) {
6445 
6446 		field = strtok_r(token, ",", &lasts);
6447 		token = NULL;
6448 		status = dladm_unset_secobj(handle, field, DLADM_OPT_ACTIVE);
6449 		if (!temp) {
6450 			pstatus = dladm_unset_secobj(handle, field,
6451 			    DLADM_OPT_PERSIST);
6452 		} else {
6453 			pstatus = DLADM_STATUS_OK;
6454 		}
6455 
6456 		if (status != DLADM_STATUS_OK) {
6457 			warn_dlerr(status, "could not delete secure object "
6458 			    "'%s'", field);
6459 		}
6460 		if (pstatus != DLADM_STATUS_OK) {
6461 			warn_dlerr(pstatus, "could not persistently delete "
6462 			    "secure object '%s'", field);
6463 		}
6464 	}
6465 	free(token);
6466 
6467 	if (status != DLADM_STATUS_OK || pstatus != DLADM_STATUS_OK) {
6468 		dladm_close(handle);
6469 		exit(1);
6470 	}
6471 }
6472 
6473 typedef struct show_secobj_state {
6474 	boolean_t	ss_persist;
6475 	boolean_t	ss_parsable;
6476 	boolean_t	ss_header;
6477 	ofmt_handle_t	ss_ofmt;
6478 } show_secobj_state_t;
6479 
6480 
6481 static boolean_t
6482 show_secobj(dladm_handle_t dh, void *arg, const char *obj_name)
6483 {
6484 	uint_t			obj_len = DLADM_SECOBJ_VAL_MAX;
6485 	uint8_t			obj_val[DLADM_SECOBJ_VAL_MAX];
6486 	char			buf[DLADM_STRSIZE];
6487 	uint_t			flags = 0;
6488 	dladm_secobj_class_t	class;
6489 	show_secobj_state_t	*statep = arg;
6490 	dladm_status_t		status;
6491 	secobj_fields_buf_t	sbuf;
6492 
6493 	bzero(&sbuf, sizeof (secobj_fields_buf_t));
6494 	if (statep->ss_persist)
6495 		flags |= DLADM_OPT_PERSIST;
6496 
6497 	status = dladm_get_secobj(dh, obj_name, &class, obj_val, &obj_len,
6498 	    flags);
6499 	if (status != DLADM_STATUS_OK)
6500 		die_dlerr(status, "cannot get secure object '%s'", obj_name);
6501 
6502 	(void) snprintf(sbuf.ss_obj_name, sizeof (sbuf.ss_obj_name),
6503 	    obj_name);
6504 	(void) dladm_secobjclass2str(class, buf);
6505 	(void) snprintf(sbuf.ss_class, sizeof (sbuf.ss_class), "%s", buf);
6506 	if (getuid() == 0) {
6507 		char	val[DLADM_SECOBJ_VAL_MAX * 2];
6508 		uint_t	len = sizeof (val);
6509 
6510 		if (octet_to_hexascii(obj_val, obj_len, val, &len) == 0)
6511 			(void) snprintf(sbuf.ss_val,
6512 			    sizeof (sbuf.ss_val), "%s", val);
6513 	}
6514 	ofmt_print(statep->ss_ofmt, &sbuf);
6515 	return (B_TRUE);
6516 }
6517 
6518 static void
6519 do_show_secobj(int argc, char **argv, const char *use)
6520 {
6521 	int			option;
6522 	show_secobj_state_t	state;
6523 	dladm_status_t		status;
6524 	boolean_t		o_arg = B_FALSE;
6525 	uint_t			i;
6526 	uint_t			flags;
6527 	char			*fields_str = NULL;
6528 	char			*def_fields = "object,class";
6529 	char			*all_fields = "object,class,value";
6530 	char			*field, *token, *lasts = NULL, c;
6531 	ofmt_handle_t		ofmt;
6532 	ofmt_status_t		oferr;
6533 	uint_t			ofmtflags = 0;
6534 
6535 	opterr = 0;
6536 	bzero(&state, sizeof (state));
6537 	state.ss_parsable = B_FALSE;
6538 	fields_str = def_fields;
6539 	state.ss_persist = B_FALSE;
6540 	state.ss_parsable = B_FALSE;
6541 	state.ss_header = B_TRUE;
6542 	while ((option = getopt_long(argc, argv, ":pPo:",
6543 	    wifi_longopts, NULL)) != -1) {
6544 		switch (option) {
6545 		case 'p':
6546 			state.ss_parsable = B_TRUE;
6547 			break;
6548 		case 'P':
6549 			state.ss_persist = B_TRUE;
6550 			break;
6551 		case 'o':
6552 			o_arg = B_TRUE;
6553 			if (strcasecmp(optarg, "all") == 0)
6554 				fields_str = all_fields;
6555 			else
6556 				fields_str = optarg;
6557 			break;
6558 		default:
6559 			die_opterr(optopt, option, use);
6560 			break;
6561 		}
6562 	}
6563 
6564 	if (state.ss_parsable && !o_arg)
6565 		die("option -c requires -o");
6566 
6567 	if (state.ss_parsable && fields_str == all_fields)
6568 		die("\"-o all\" is invalid with -p");
6569 
6570 	if (state.ss_parsable)
6571 		ofmtflags |= OFMT_PARSABLE;
6572 	oferr = ofmt_open(fields_str, secobj_fields, ofmtflags, 0, &ofmt);
6573 	dladm_ofmt_check(oferr, state.ss_parsable, ofmt);
6574 	state.ss_ofmt = ofmt;
6575 
6576 	flags = state.ss_persist ? DLADM_OPT_PERSIST : 0;
6577 
6578 	if (optind == (argc - 1)) {
6579 		uint_t obj_fields = 1;
6580 
6581 		token = argv[optind];
6582 		if (token == NULL)
6583 			die("secure object name required");
6584 		while ((c = *token++) != NULL) {
6585 			if (c == ',')
6586 				obj_fields++;
6587 		}
6588 		token = strdup(argv[optind]);
6589 		if (token == NULL)
6590 			die("no memory");
6591 		for (i = 0; i < obj_fields; i++) {
6592 			field = strtok_r(token, ",", &lasts);
6593 			token = NULL;
6594 			if (!show_secobj(handle, &state, field))
6595 				break;
6596 		}
6597 		free(token);
6598 		ofmt_close(ofmt);
6599 		return;
6600 	} else if (optind != argc)
6601 		usage();
6602 
6603 	status = dladm_walk_secobj(handle, &state, show_secobj, flags);
6604 
6605 	if (status != DLADM_STATUS_OK)
6606 		die_dlerr(status, "show-secobj");
6607 	ofmt_close(ofmt);
6608 }
6609 
6610 /*ARGSUSED*/
6611 static int
6612 i_dladm_init_linkprop(dladm_handle_t dh, datalink_id_t linkid, void *arg)
6613 {
6614 	(void) dladm_init_linkprop(dh, linkid, B_TRUE);
6615 	return (DLADM_WALK_CONTINUE);
6616 }
6617 
6618 /*ARGSUSED*/
6619 void
6620 do_init_linkprop(int argc, char **argv, const char *use)
6621 {
6622 	int			option;
6623 	dladm_status_t		status;
6624 	datalink_id_t		linkid = DATALINK_ALL_LINKID;
6625 	datalink_media_t	media = DATALINK_ANY_MEDIATYPE;
6626 	uint_t			any_media = B_TRUE;
6627 
6628 	opterr = 0;
6629 	while ((option = getopt(argc, argv, ":w")) != -1) {
6630 		switch (option) {
6631 		case 'w':
6632 			media = DL_WIFI;
6633 			any_media = B_FALSE;
6634 			break;
6635 		default:
6636 			/*
6637 			 * Because init-linkprop is not a public command,
6638 			 * print the usage instead.
6639 			 */
6640 			usage();
6641 			break;
6642 		}
6643 	}
6644 
6645 	if (optind == (argc - 1)) {
6646 		if ((status = dladm_name2info(handle, argv[optind], &linkid,
6647 		    NULL, NULL, NULL)) != DLADM_STATUS_OK)
6648 			die_dlerr(status, "link %s is not valid", argv[optind]);
6649 	} else if (optind != argc) {
6650 		usage();
6651 	}
6652 
6653 	if (linkid == DATALINK_ALL_LINKID) {
6654 		/*
6655 		 * linkprops of links of other classes have been initialized as
6656 		 * part of the dladm up-xxx operation.
6657 		 */
6658 		(void) dladm_walk_datalink_id(i_dladm_init_linkprop, handle,
6659 		    NULL, DATALINK_CLASS_PHYS, media, DLADM_OPT_PERSIST);
6660 	} else {
6661 		(void) dladm_init_linkprop(handle, linkid, any_media);
6662 	}
6663 }
6664 
6665 static void
6666 do_show_ether(int argc, char **argv, const char *use)
6667 {
6668 	int 			option;
6669 	datalink_id_t		linkid;
6670 	print_ether_state_t 	state;
6671 	char			*fields_str = NULL;
6672 	ofmt_handle_t		ofmt;
6673 	ofmt_status_t		oferr;
6674 	uint_t			ofmtflags = 0;
6675 
6676 	bzero(&state, sizeof (state));
6677 	state.es_link = NULL;
6678 	state.es_parsable = B_FALSE;
6679 
6680 	while ((option = getopt_long(argc, argv, "o:px",
6681 	    showeth_lopts, NULL)) != -1) {
6682 		switch (option) {
6683 			case 'x':
6684 				state.es_extended = B_TRUE;
6685 				break;
6686 			case 'p':
6687 				state.es_parsable = B_TRUE;
6688 				break;
6689 			case 'o':
6690 				fields_str = optarg;
6691 				break;
6692 			default:
6693 				die_opterr(optopt, option, use);
6694 				break;
6695 		}
6696 	}
6697 
6698 	if (optind == (argc - 1))
6699 		state.es_link = argv[optind];
6700 
6701 	if (state.es_parsable)
6702 		ofmtflags |= OFMT_PARSABLE;
6703 	oferr = ofmt_open(fields_str, ether_fields, ofmtflags,
6704 	    DLADM_DEFAULT_COL, &ofmt);
6705 	dladm_ofmt_check(oferr, state.es_parsable, ofmt);
6706 	state.es_ofmt = ofmt;
6707 
6708 	if (state.es_link == NULL) {
6709 		(void) dladm_walk_datalink_id(show_etherprop, handle, &state,
6710 		    DATALINK_CLASS_PHYS, DL_ETHER, DLADM_OPT_ACTIVE);
6711 	} else {
6712 		if (!link_is_ether(state.es_link, &linkid))
6713 			die("invalid link specified");
6714 		(void) show_etherprop(handle, linkid, &state);
6715 	}
6716 	ofmt_close(ofmt);
6717 }
6718 
6719 static int
6720 show_etherprop(dladm_handle_t dh, datalink_id_t linkid, void *arg)
6721 {
6722 	print_ether_state_t	*statep = arg;
6723 	ether_fields_buf_t	ebuf;
6724 	dladm_ether_info_t	eattr;
6725 	dladm_status_t		status;
6726 
6727 	bzero(&ebuf, sizeof (ether_fields_buf_t));
6728 	if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL,
6729 	    ebuf.eth_link, sizeof (ebuf.eth_link)) != DLADM_STATUS_OK) {
6730 		return (DLADM_WALK_CONTINUE);
6731 	}
6732 
6733 	status = dladm_ether_info(dh, linkid, &eattr);
6734 	if (status != DLADM_STATUS_OK)
6735 		goto cleanup;
6736 
6737 	(void) strlcpy(ebuf.eth_ptype, "current", sizeof (ebuf.eth_ptype));
6738 
6739 	(void) dladm_ether_autoneg2str(ebuf.eth_autoneg,
6740 	    sizeof (ebuf.eth_autoneg), &eattr, CURRENT);
6741 	(void) dladm_ether_pause2str(ebuf.eth_pause,
6742 	    sizeof (ebuf.eth_pause), &eattr, CURRENT);
6743 	(void) dladm_ether_spdx2str(ebuf.eth_spdx,
6744 	    sizeof (ebuf.eth_spdx), &eattr, CURRENT);
6745 	(void) strlcpy(ebuf.eth_state,
6746 	    dladm_linkstate2str(eattr.lei_state, ebuf.eth_state),
6747 	    sizeof (ebuf.eth_state));
6748 	(void) strlcpy(ebuf.eth_rem_fault,
6749 	    (eattr.lei_attr[CURRENT].le_fault ? "fault" : "none"),
6750 	    sizeof (ebuf.eth_rem_fault));
6751 
6752 	ofmt_print(statep->es_ofmt, &ebuf);
6753 
6754 	if (statep->es_extended)
6755 		show_ether_xprop(arg, &eattr);
6756 
6757 cleanup:
6758 	dladm_ether_info_done(&eattr);
6759 	return (DLADM_WALK_CONTINUE);
6760 }
6761 
6762 /* ARGSUSED */
6763 static void
6764 do_init_secobj(int argc, char **argv, const char *use)
6765 {
6766 	dladm_status_t	status;
6767 
6768 	status = dladm_init_secobj(handle);
6769 	if (status != DLADM_STATUS_OK)
6770 		die_dlerr(status, "secure object initialization failed");
6771 }
6772 
6773 /*
6774  * "-R" option support. It is used for live upgrading. Append dladm commands
6775  * to a upgrade script which will be run when the alternative root boots up:
6776  *
6777  * - If the /etc/dladm/datalink.conf file exists on the alternative root,
6778  * append dladm commands to the <altroot>/var/svc/profile/upgrade_datalink
6779  * script. This script will be run as part of the network/physical service.
6780  * We cannot defer this to /var/svc/profile/upgrade because then the
6781  * configuration will not be able to take effect before network/physical
6782  * plumbs various interfaces.
6783  *
6784  * - If the /etc/dladm/datalink.conf file does not exist on the alternative
6785  * root, append dladm commands to the <altroot>/var/svc/profile/upgrade script,
6786  * which will be run in the manifest-import service.
6787  *
6788  * Note that the SMF team is considering to move the manifest-import service
6789  * to be run at the very begining of boot. Once that is done, the need for
6790  * the /var/svc/profile/upgrade_datalink script will not exist any more.
6791  */
6792 static void
6793 altroot_cmd(char *altroot, int argc, char *argv[])
6794 {
6795 	char		path[MAXPATHLEN];
6796 	struct stat	stbuf;
6797 	FILE		*fp;
6798 	int		i;
6799 
6800 	/*
6801 	 * Check for the existence of the /etc/dladm/datalink.conf
6802 	 * configuration file, and determine the name of script file.
6803 	 */
6804 	(void) snprintf(path, MAXPATHLEN, "/%s/etc/dladm/datalink.conf",
6805 	    altroot);
6806 	if (stat(path, &stbuf) < 0) {
6807 		(void) snprintf(path, MAXPATHLEN, "/%s/%s", altroot,
6808 		    SMF_UPGRADE_FILE);
6809 	} else {
6810 		(void) snprintf(path, MAXPATHLEN, "/%s/%s", altroot,
6811 		    SMF_UPGRADEDATALINK_FILE);
6812 	}
6813 
6814 	if ((fp = fopen(path, "a+")) == NULL)
6815 		die("operation not supported on %s", altroot);
6816 
6817 	(void) fprintf(fp, "/sbin/dladm ");
6818 	for (i = 0; i < argc; i++) {
6819 		/*
6820 		 * Directly write to the file if it is not the "-R <altroot>"
6821 		 * option. In which case, skip it.
6822 		 */
6823 		if (strcmp(argv[i], "-R") != 0)
6824 			(void) fprintf(fp, "%s ", argv[i]);
6825 		else
6826 			i ++;
6827 	}
6828 	(void) fprintf(fp, "%s\n", SMF_DLADM_UPGRADE_MSG);
6829 	(void) fclose(fp);
6830 	dladm_close(handle);
6831 	exit(0);
6832 }
6833 
6834 /*
6835  * Convert the string to an integer. Note that the string must not have any
6836  * trailing non-integer characters.
6837  */
6838 static boolean_t
6839 str2int(const char *str, int *valp)
6840 {
6841 	int	val;
6842 	char	*endp = NULL;
6843 
6844 	errno = 0;
6845 	val = strtol(str, &endp, 10);
6846 	if (errno != 0 || *endp != '\0')
6847 		return (B_FALSE);
6848 
6849 	*valp = val;
6850 	return (B_TRUE);
6851 }
6852 
6853 /* PRINTFLIKE1 */
6854 static void
6855 warn(const char *format, ...)
6856 {
6857 	va_list alist;
6858 
6859 	format = gettext(format);
6860 	(void) fprintf(stderr, "%s: warning: ", progname);
6861 
6862 	va_start(alist, format);
6863 	(void) vfprintf(stderr, format, alist);
6864 	va_end(alist);
6865 
6866 	(void) putchar('\n');
6867 }
6868 
6869 /* PRINTFLIKE2 */
6870 static void
6871 warn_dlerr(dladm_status_t err, const char *format, ...)
6872 {
6873 	va_list alist;
6874 	char	errmsg[DLADM_STRSIZE];
6875 
6876 	format = gettext(format);
6877 	(void) fprintf(stderr, gettext("%s: warning: "), progname);
6878 
6879 	va_start(alist, format);
6880 	(void) vfprintf(stderr, format, alist);
6881 	va_end(alist);
6882 	(void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg));
6883 }
6884 
6885 /*
6886  * Also closes the dladm handle if it is not NULL.
6887  */
6888 /* PRINTFLIKE2 */
6889 static void
6890 die_dlerr(dladm_status_t err, const char *format, ...)
6891 {
6892 	va_list alist;
6893 	char	errmsg[DLADM_STRSIZE];
6894 
6895 	format = gettext(format);
6896 	(void) fprintf(stderr, "%s: ", progname);
6897 
6898 	va_start(alist, format);
6899 	(void) vfprintf(stderr, format, alist);
6900 	va_end(alist);
6901 	(void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg));
6902 
6903 	/* close dladm handle if it was opened */
6904 	if (handle != NULL)
6905 		dladm_close(handle);
6906 
6907 	exit(EXIT_FAILURE);
6908 }
6909 
6910 /* PRINTFLIKE1 */
6911 static void
6912 die(const char *format, ...)
6913 {
6914 	va_list alist;
6915 
6916 	format = gettext(format);
6917 	(void) fprintf(stderr, "%s: ", progname);
6918 
6919 	va_start(alist, format);
6920 	(void) vfprintf(stderr, format, alist);
6921 	va_end(alist);
6922 
6923 	(void) putchar('\n');
6924 
6925 	/* close dladm handle if it was opened */
6926 	if (handle != NULL)
6927 		dladm_close(handle);
6928 
6929 	exit(EXIT_FAILURE);
6930 }
6931 
6932 static void
6933 die_optdup(int opt)
6934 {
6935 	die("the option -%c cannot be specified more than once", opt);
6936 }
6937 
6938 static void
6939 die_opterr(int opt, int opterr, const char *usage)
6940 {
6941 	switch (opterr) {
6942 	case ':':
6943 		die("option '-%c' requires a value\nusage: %s", opt,
6944 		    gettext(usage));
6945 		break;
6946 	case '?':
6947 	default:
6948 		die("unrecognized option '-%c'\nusage: %s", opt,
6949 		    gettext(usage));
6950 		break;
6951 	}
6952 }
6953 
6954 static void
6955 show_ether_xprop(void *arg, dladm_ether_info_t *eattr)
6956 {
6957 	print_ether_state_t	*statep = arg;
6958 	ether_fields_buf_t	ebuf;
6959 	int			i;
6960 
6961 	for (i = CAPABLE; i <= PEERADV; i++)  {
6962 		bzero(&ebuf, sizeof (ebuf));
6963 		(void) strlcpy(ebuf.eth_ptype, ptype[i],
6964 		    sizeof (ebuf.eth_ptype));
6965 		(void) dladm_ether_autoneg2str(ebuf.eth_autoneg,
6966 		    sizeof (ebuf.eth_autoneg), eattr, i);
6967 		(void) dladm_ether_spdx2str(ebuf.eth_spdx,
6968 		    sizeof (ebuf.eth_spdx), eattr, i);
6969 		(void) dladm_ether_pause2str(ebuf.eth_pause,
6970 		    sizeof (ebuf.eth_pause), eattr, i);
6971 		(void) strlcpy(ebuf.eth_rem_fault,
6972 		    (eattr->lei_attr[i].le_fault ? "fault" : "none"),
6973 		    sizeof (ebuf.eth_rem_fault));
6974 		ofmt_print(statep->es_ofmt, &ebuf);
6975 	}
6976 
6977 }
6978 
6979 static boolean_t
6980 link_is_ether(const char *link, datalink_id_t *linkid)
6981 {
6982 	uint32_t media;
6983 	datalink_class_t class;
6984 
6985 	if (dladm_name2info(handle, link, linkid, NULL, &class, &media) ==
6986 	    DLADM_STATUS_OK) {
6987 		if (class == DATALINK_CLASS_PHYS && media == DL_ETHER)
6988 			return (B_TRUE);
6989 	}
6990 	return (B_FALSE);
6991 }
6992 
6993 /*
6994  * default output callback function that, when invoked,
6995  * prints string which is offset by ofmt_arg->ofmt_id within buf.
6996  */
6997 static boolean_t
6998 print_default_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
6999 {
7000 	char *value;
7001 
7002 	value = (char *)ofarg->ofmt_cbarg + ofarg->ofmt_id;
7003 	(void) strlcpy(buf, value, bufsize);
7004 	return (B_TRUE);
7005 }
7006 
7007 static void
7008 dladm_ofmt_check(ofmt_status_t oferr, boolean_t parsable,
7009     ofmt_handle_t ofmt)
7010 {
7011 	char buf[OFMT_BUFSIZE];
7012 
7013 	if (oferr == OFMT_SUCCESS)
7014 		return;
7015 	(void) ofmt_strerror(ofmt, oferr, buf, sizeof (buf));
7016 	/*
7017 	 * All errors are considered fatal in parsable mode.
7018 	 * NOMEM errors are always fatal, regardless of mode.
7019 	 * For other errors, we print diagnostics in human-readable
7020 	 * mode and processs what we can.
7021 	 */
7022 	if (parsable || oferr == OFMT_ENOFIELDS) {
7023 		ofmt_close(ofmt);
7024 		die(buf);
7025 	} else {
7026 		warn(buf);
7027 	}
7028 }
7029