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