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