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