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