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