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