xref: /titanic_52/usr/src/cmd/dladm/dladm.c (revision b9e93c10c0a2a4bb069d38bb311021a9478c4711)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #include <stdio.h>
27 #include <ctype.h>
28 #include <locale.h>
29 #include <signal.h>
30 #include <stdarg.h>
31 #include <stdlib.h>
32 #include <fcntl.h>
33 #include <string.h>
34 #include <stropts.h>
35 #include <sys/stat.h>
36 #include <errno.h>
37 #include <kstat.h>
38 #include <strings.h>
39 #include <getopt.h>
40 #include <unistd.h>
41 #include <priv.h>
42 #include <termios.h>
43 #include <pwd.h>
44 #include <auth_attr.h>
45 #include <auth_list.h>
46 #include <libintl.h>
47 #include <libdevinfo.h>
48 #include <libdlpi.h>
49 #include <libdladm.h>
50 #include <libdllink.h>
51 #include <libdlstat.h>
52 #include <libdlaggr.h>
53 #include <libdlwlan.h>
54 #include <libdlvlan.h>
55 #include <libdlvnic.h>
56 #include <libdlether.h>
57 #include <libinetutil.h>
58 #include <bsm/adt.h>
59 #include <bsm/adt_event.h>
60 #include <libdlvnic.h>
61 #include <sys/types.h>
62 #include <sys/socket.h>
63 #include <sys/processor.h>
64 #include <netinet/in.h>
65 #include <arpa/inet.h>
66 #include <net/if_types.h>
67 #include <stddef.h>
68 
69 #define	STR_UNDEF_VAL		"--"
70 #define	MAXPORT			256
71 #define	MAXVNIC			256
72 #define	BUFLEN(lim, ptr)	(((lim) > (ptr)) ? ((lim) - (ptr)) : 0)
73 #define	MAXLINELEN		1024
74 #define	SMF_UPGRADE_FILE		"/var/svc/profile/upgrade"
75 #define	SMF_UPGRADEDATALINK_FILE	"/var/svc/profile/upgrade_datalink"
76 #define	SMF_DLADM_UPGRADE_MSG		" # added by dladm(1M)"
77 
78 #define	CMD_TYPE_ANY		0xffffffff
79 #define	WIFI_CMD_SCAN		0x00000001
80 #define	WIFI_CMD_SHOW		0x00000002
81 #define	WIFI_CMD_ALL		(WIFI_CMD_SCAN | WIFI_CMD_SHOW)
82 
83 /*
84  * Data structures and routines for printing output.
85  * All non-parseable output is assumed to be in a columnar format.
86  * Multiple fields in parsable output are separated by ':'; single
87  * field output is printed as-is.
88  *
89  * Each sub-command is associated with a global array of pointers,
90  * print_field_t *fields[], where the print_field_t contains information
91  * about the format in which the output is to be printed.
92  *
93  * Sub-commands may be implemented in one of two ways:
94  * (i)  the implementation could get all field values into a character
95  *      buffer, with pf_offset containing the offset (for pf_name) within
96  *      the buffer. The sub-command would make the needed system calls
97  *      to obtain all possible column values and then invoke the
98  *      dladm_print_field() function to print the specific fields
99  *      requested in the command line. See the comments for dladm_print_field
100  *      for further details.
101  * (ii) Alternatively, each fields[i] entry could store a pf_index value
102  *      that uniquely identifies the column to be printed. The implementation
103  *      of the sub-command would then invoke dladm_print_output() with a
104  *      callback function whose semantics are described below (see comments
105  *      for dladm_print_output())
106  *
107  * Thus, an implementation of a sub-command must provide the following:
108  *
109  * static print_field_t sub_command_fields[] = {
110  *	{<name>, <header>,<field width>,  <offset_or_index>, cmdtype},
111  *	:
112  *	{<name>, <header>,<field width>,  <offset_or_index>, cmdtype}
113  * };
114  *
115  * #define	SUB_COMMAND_MAX_FIELDS sizeof \
116  *		(sub_comand_fields) / sizeof (print_field_t))
117  *
118  * print_state_t sub_command_print_state;
119  *
120  * The function that parses command line arguments (typically
121  * do_sub_command()) should then contain an invocation like:
122  *
123  *	fields = parse_output_fields(fields_str, sub_command_fields,
124  *	    SUB_COMMAND_MAX_FIELDS, CMD_TYPE_ANY, &nfields);
125  *
126  * and store the resulting fields and nfields value in a print_state_t
127  * structure tracked for the command.
128  *
129  *	sub_command_print_state.ps_fields = fields;
130  *	sub_command_print_state.ps_nfields = nfields;
131  *
132  * To print the column header for the output, the print_header()
133  * function must then be invoked by do_sub_command().
134  *
135  * Then if method (i) is used for the sub_command, the do_sub_command()
136  * function should make the necessary system calls to fill up the buffer
137  * and then invoke dladm_print_field(). An example of this method is
138  * the implementation of do_show_link() and show_link();
139  *
140  * If method (ii) is used, do_sub_command should invoke dladm_print_output()
141  * with a callback function that will be called for each field to be printed.
142  * The callback function will be passed a pointer to the print_field_t
143  * for the field, and the pf_index may then be used to identify the
144  * system call required to find the value to be printed.
145  */
146 
147 typedef struct print_field_s {
148 	const char	*pf_name;	/* name of column to be printed */
149 	const char	*pf_header;	/* header for this column */
150 	uint_t		pf_width;
151 	union {
152 		uint_t	_pf_index;	/* private index for sub-command */
153 		size_t	_pf_offset;
154 	}_pf_un;
155 #define	pf_index	_pf_un._pf_index
156 #define	pf_offset	_pf_un._pf_offset;
157 	uint_t		pf_cmdtype;
158 } print_field_t;
159 
160 /*
161  * The state of the output is tracked in a print_state_t structure.
162  * Each ps_fields[i] entry points at the global print_field_t array for
163  * the sub-command, where ps_nfields is the number of requested fields.
164  */
165 typedef struct print_state_s {
166 	print_field_t	**ps_fields;
167 	uint_t		ps_nfields;
168 	boolean_t	ps_lastfield;
169 	uint_t		ps_overflow;
170 } print_state_t;
171 
172 typedef char *(*print_callback_t)(print_field_t *, void *);
173 static print_field_t **parse_output_fields(char *, print_field_t *, int,
174     uint_t, uint_t *);
175 /*
176  * print the header for the output
177  */
178 static void print_header(print_state_t *);
179 static void print_field(print_state_t *, print_field_t *, const char *,
180     boolean_t);
181 
182 /*
183  * to print output values, call dladm_print_output with a callback
184  * function (*func)() that should parse the args and return an
185  * unformatted character buffer with the value to be printed.
186  *
187  * dladm_print_output() prints the character buffer using the formatting
188  * information provided in the print_field_t for that column.
189  */
190 static void dladm_print_output(print_state_t *, boolean_t,
191     print_callback_t, void *);
192 
193 /*
194  * helper function that, when invoked as dladm_print_field(pf, buf)
195  * prints string which is offset by pf->pf_offset within buf.
196  */
197 static char *dladm_print_field(print_field_t *, void *);
198 
199 
200 #define	MAX_FIELD_LEN	32
201 
202 
203 typedef struct show_state {
204 	boolean_t	ls_firstonly;
205 	boolean_t	ls_donefirst;
206 	pktsum_t	ls_prevstats;
207 	uint32_t	ls_flags;
208 	dladm_status_t	ls_status;
209 	print_state_t	ls_print;
210 	boolean_t	ls_parseable;
211 	boolean_t	ls_printheader;
212 	boolean_t	ls_mac;
213 	boolean_t	ls_hwgrp;
214 } show_state_t;
215 
216 typedef struct show_grp_state {
217 	pktsum_t	gs_prevstats[MAXPORT];
218 	uint32_t	gs_flags;
219 	dladm_status_t	gs_status;
220 	boolean_t	gs_parseable;
221 	boolean_t	gs_lacp;
222 	boolean_t	gs_extended;
223 	boolean_t	gs_stats;
224 	boolean_t	gs_firstonly;
225 	boolean_t	gs_donefirst;
226 	boolean_t	gs_printheader;
227 	print_state_t	gs_print;
228 } show_grp_state_t;
229 
230 typedef struct show_vnic_state {
231 	datalink_id_t	vs_vnic_id;
232 	datalink_id_t	vs_link_id;
233 	char		vs_vnic[MAXLINKNAMELEN];
234 	char		vs_link[MAXLINKNAMELEN];
235 	boolean_t	vs_parseable;
236 	boolean_t	vs_printheader;
237 	boolean_t	vs_found;
238 	boolean_t	vs_firstonly;
239 	boolean_t	vs_donefirst;
240 	boolean_t	vs_stats;
241 	boolean_t	vs_printstats;
242 	pktsum_t	vs_totalstats;
243 	pktsum_t	vs_prevstats[MAXVNIC];
244 	boolean_t	vs_etherstub;
245 	dladm_status_t	vs_status;
246 	uint32_t	vs_flags;
247 	print_state_t	vs_print;
248 } show_vnic_state_t;
249 
250 typedef struct show_usage_state_s {
251 	boolean_t	us_plot;
252 	boolean_t	us_parseable;
253 	boolean_t	us_printheader;
254 	boolean_t	us_first;
255 	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 (state.vs_parseable && !o_arg)
4255 		die("-p requires -o");
4256 
4257 	if (state.vs_parseable && strcasecmp(fields_str, "all") == 0)
4258 		die("\"-o all\" is invalid with -p");
4259 
4260 	if (i_arg && !s_arg)
4261 		die("the option -i can be used only with -s");
4262 
4263 	/* get vnic ID (optional last argument) */
4264 	if (optind == (argc - 1)) {
4265 		status = dladm_name2info(handle, argv[optind], &linkid, NULL,
4266 		    NULL, NULL);
4267 		if (status != DLADM_STATUS_OK) {
4268 			die_dlerr(status, "invalid vnic name '%s'",
4269 			    argv[optind]);
4270 		}
4271 		(void) strlcpy(state.vs_vnic, argv[optind], MAXLINKNAMELEN);
4272 	} else if (optind != argc) {
4273 		usage();
4274 	}
4275 
4276 	if (l_arg) {
4277 		status = dladm_name2info(handle, state.vs_link, &dev_linkid,
4278 		    NULL, NULL, NULL);
4279 		if (status != DLADM_STATUS_OK) {
4280 			die_dlerr(status, "invalid link name '%s'",
4281 			    state.vs_link);
4282 		}
4283 	}
4284 
4285 	state.vs_vnic_id = linkid;
4286 	state.vs_link_id = dev_linkid;
4287 	state.vs_etherstub = etherstub;
4288 	state.vs_found = B_FALSE;
4289 	state.vs_flags = flags;
4290 
4291 	if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) {
4292 		if (etherstub)
4293 			fields_str = all_e_fields;
4294 		else
4295 			fields_str = all_fields;
4296 	}
4297 
4298 	pf = vnic_fields;
4299 	pfmax = VNIC_MAX_FIELDS;
4300 
4301 	fields = parse_output_fields(fields_str, pf, pfmax, CMD_TYPE_ANY,
4302 	    &nfields);
4303 
4304 	if (fields == NULL) {
4305 		die("invalid field(s) specified");
4306 		return;
4307 	}
4308 
4309 	state.vs_print.ps_fields = fields;
4310 	state.vs_print.ps_nfields = nfields;
4311 
4312 	if (s_arg) {
4313 		/* Display vnic statistics */
4314 		vnic_stats(&state, interval);
4315 		return;
4316 	}
4317 
4318 	/* Display vnic information */
4319 	state.vs_donefirst = B_FALSE;
4320 
4321 	if (linkid == DATALINK_ALL_LINKID) {
4322 		(void) dladm_walk_datalink_id(show_vnic, handle, &state,
4323 		    DATALINK_CLASS_VNIC | DATALINK_CLASS_ETHERSTUB,
4324 		    DATALINK_ANY_MEDIATYPE, DLADM_OPT_ACTIVE);
4325 	} else {
4326 		(void) show_vnic(handle, linkid, &state);
4327 		if (state.vs_status != DLADM_STATUS_OK) {
4328 			die_dlerr(state.vs_status, "failed to show vnic '%s'",
4329 			    state.vs_vnic);
4330 		}
4331 	}
4332 }
4333 
4334 static void
4335 do_show_vnic(int argc, char *argv[], const char *use)
4336 {
4337 	do_show_vnic_common(argc, argv, use, B_FALSE);
4338 }
4339 
4340 static void
4341 do_create_etherstub(int argc, char *argv[], const char *use)
4342 {
4343 	uint32_t flags;
4344 	char *altroot = NULL;
4345 	char option;
4346 	dladm_status_t status;
4347 	char name[MAXLINKNAMELEN];
4348 	uchar_t mac_addr[ETHERADDRL];
4349 
4350 	name[0] = '\0';
4351 	bzero(mac_addr, sizeof (mac_addr));
4352 	flags = DLADM_OPT_ANCHOR | DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
4353 
4354 	opterr = 0;
4355 	while ((option = getopt_long(argc, argv, "tR:",
4356 	    etherstub_lopts, NULL)) != -1) {
4357 		switch (option) {
4358 		case 't':
4359 			flags &= ~DLADM_OPT_PERSIST;
4360 			break;
4361 		case 'R':
4362 			altroot = optarg;
4363 			break;
4364 		default:
4365 			die_opterr(optopt, option, use);
4366 		}
4367 	}
4368 
4369 	/* the etherstub id is the required operand */
4370 	if (optind != (argc - 1))
4371 		usage();
4372 
4373 	if (strlcpy(name, argv[optind], MAXLINKNAMELEN) >= MAXLINKNAMELEN)
4374 		die("link name too long '%s'", argv[optind]);
4375 
4376 	if (!dladm_valid_linkname(name))
4377 		die("invalid link name '%s'", argv[optind]);
4378 
4379 	if (altroot != NULL)
4380 		altroot_cmd(altroot, argc, argv);
4381 
4382 	status = dladm_vnic_create(handle, name, DATALINK_INVALID_LINKID,
4383 	    VNIC_MAC_ADDR_TYPE_AUTO, mac_addr, ETHERADDRL, NULL, 0, 0, NULL,
4384 	    NULL, flags);
4385 	if (status != DLADM_STATUS_OK)
4386 		die_dlerr(status, "etherstub creation failed");
4387 
4388 
4389 }
4390 
4391 static void
4392 do_delete_etherstub(int argc, char *argv[], const char *use)
4393 {
4394 	do_delete_vnic_common(argc, argv, use, B_TRUE);
4395 }
4396 
4397 /* ARGSUSED */
4398 static void
4399 do_show_etherstub(int argc, char *argv[], const char *use)
4400 {
4401 	do_show_vnic_common(argc, argv, use, B_TRUE);
4402 }
4403 
4404 static void
4405 link_stats(datalink_id_t linkid, uint_t interval, char *fields_str,
4406     show_state_t *state)
4407 {
4408 	print_field_t	**fields;
4409 	uint_t		nfields;
4410 
4411 	fields = parse_output_fields(fields_str, devs_fields, DEVS_MAX_FIELDS,
4412 	    CMD_TYPE_ANY, &nfields);
4413 	if (fields == NULL) {
4414 		die("invalid field(s) specified");
4415 		return;
4416 	}
4417 
4418 	state->ls_print.ps_fields = fields;
4419 	state->ls_print.ps_nfields = nfields;
4420 
4421 	/*
4422 	 * If an interval is specified, continuously show the stats
4423 	 * only for the first MAC port.
4424 	 */
4425 	state->ls_firstonly = (interval != 0);
4426 
4427 	if (!state->ls_parseable)
4428 		print_header(&state->ls_print);
4429 	for (;;) {
4430 		state->ls_donefirst = B_FALSE;
4431 		if (linkid == DATALINK_ALL_LINKID) {
4432 			(void) dladm_walk_datalink_id(show_link_stats, handle,
4433 			    state, DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE,
4434 			    DLADM_OPT_ACTIVE);
4435 		} else {
4436 			(void) show_link_stats(handle, linkid, state);
4437 		}
4438 
4439 		if (interval == 0)
4440 			break;
4441 
4442 		(void) sleep(interval);
4443 	}
4444 }
4445 
4446 static void
4447 aggr_stats(datalink_id_t linkid, show_grp_state_t *state, uint_t interval)
4448 {
4449 	/*
4450 	 * If an interval is specified, continuously show the stats
4451 	 * only for the first group.
4452 	 */
4453 	state->gs_firstonly = (interval != 0);
4454 
4455 	for (;;) {
4456 		state->gs_donefirst = B_FALSE;
4457 		if (linkid == DATALINK_ALL_LINKID)
4458 			(void) dladm_walk_datalink_id(show_aggr, handle, state,
4459 			    DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE,
4460 			    DLADM_OPT_ACTIVE);
4461 		else
4462 			(void) show_aggr(handle, linkid, state);
4463 
4464 		if (interval == 0)
4465 			break;
4466 
4467 		(void) sleep(interval);
4468 	}
4469 }
4470 
4471 /* ARGSUSED */
4472 static void
4473 vnic_stats(show_vnic_state_t *sp, uint32_t interval)
4474 {
4475 	show_vnic_state_t	state;
4476 	boolean_t		specific_link, specific_dev;
4477 
4478 	/* Display vnic statistics */
4479 	dump_vnics_head(sp->vs_link);
4480 
4481 	bzero(&state, sizeof (state));
4482 	state.vs_stats = B_TRUE;
4483 	state.vs_vnic_id = sp->vs_vnic_id;
4484 	state.vs_link_id = sp->vs_link_id;
4485 
4486 	/*
4487 	 * If an interval is specified, and a vnic ID is not specified,
4488 	 * continuously show the stats only for the first vnic.
4489 	 */
4490 	specific_link = (sp->vs_vnic_id != DATALINK_ALL_LINKID);
4491 	specific_dev = (sp->vs_link_id != DATALINK_ALL_LINKID);
4492 
4493 	for (;;) {
4494 		/* Get stats for each vnic */
4495 		state.vs_found = B_FALSE;
4496 		state.vs_donefirst = B_FALSE;
4497 		state.vs_printstats = B_FALSE;
4498 		state.vs_flags = DLADM_OPT_ACTIVE;
4499 
4500 		if (!specific_link) {
4501 			(void) dladm_walk_datalink_id(show_vnic, handle, &state,
4502 			    DATALINK_CLASS_VNIC, DATALINK_ANY_MEDIATYPE,
4503 			    DLADM_OPT_ACTIVE);
4504 		} else {
4505 			(void) show_vnic(handle, sp->vs_vnic_id, &state);
4506 			if (state.vs_status != DLADM_STATUS_OK) {
4507 				die_dlerr(state.vs_status,
4508 				    "failed to show vnic '%s'", sp->vs_vnic);
4509 			}
4510 		}
4511 
4512 		if (specific_link && !state.vs_found)
4513 			die("non-existent vnic '%s'", sp->vs_vnic);
4514 		if (specific_dev && !state.vs_found)
4515 			die("device %s has no vnics", sp->vs_link);
4516 
4517 		/* Show totals */
4518 		if ((specific_link | specific_dev) && !interval) {
4519 			(void) printf("Total");
4520 			(void) printf("\t%-10llu",
4521 			    state.vs_totalstats.ipackets);
4522 			(void) printf("%-12llu",
4523 			    state.vs_totalstats.rbytes);
4524 			(void) printf("%-10llu",
4525 			    state.vs_totalstats.opackets);
4526 			(void) printf("%-12llu\n",
4527 			    state.vs_totalstats.obytes);
4528 		}
4529 
4530 		/* Show stats for each vnic */
4531 		state.vs_donefirst = B_FALSE;
4532 		state.vs_printstats = B_TRUE;
4533 
4534 		if (!specific_link) {
4535 			(void) dladm_walk_datalink_id(show_vnic, handle, &state,
4536 			    DATALINK_CLASS_VNIC, DATALINK_ANY_MEDIATYPE,
4537 			    DLADM_OPT_ACTIVE);
4538 		} else {
4539 			(void) show_vnic(handle, sp->vs_vnic_id, &state);
4540 			if (state.vs_status != DLADM_STATUS_OK) {
4541 				die_dlerr(state.vs_status,
4542 				    "failed to show vnic '%s'", sp->vs_vnic);
4543 			}
4544 		}
4545 
4546 		if (interval == 0)
4547 			break;
4548 
4549 		(void) sleep(interval);
4550 	}
4551 }
4552 
4553 static void
4554 get_mac_stats(const char *dev, pktsum_t *stats)
4555 {
4556 	kstat_ctl_t	*kcp;
4557 	kstat_t		*ksp;
4558 	char module[DLPI_LINKNAME_MAX];
4559 	uint_t instance;
4560 
4561 
4562 	bzero(stats, sizeof (*stats));
4563 
4564 	if (dlpi_parselink(dev, module, &instance) != DLPI_SUCCESS)
4565 		return;
4566 
4567 	if ((kcp = kstat_open()) == NULL) {
4568 		warn("kstat open operation failed");
4569 		return;
4570 	}
4571 
4572 	ksp = dladm_kstat_lookup(kcp, module, instance, "mac", NULL);
4573 	if (ksp != NULL)
4574 		dladm_get_stats(kcp, ksp, stats);
4575 
4576 	(void) kstat_close(kcp);
4577 
4578 }
4579 
4580 static void
4581 get_link_stats(const char *link, pktsum_t *stats)
4582 {
4583 	kstat_ctl_t	*kcp;
4584 	kstat_t		*ksp;
4585 
4586 	bzero(stats, sizeof (*stats));
4587 
4588 	if ((kcp = kstat_open()) == NULL) {
4589 		warn("kstat_open operation failed");
4590 		return;
4591 	}
4592 
4593 	ksp = dladm_kstat_lookup(kcp, "link", 0, link, NULL);
4594 
4595 	if (ksp != NULL)
4596 		dladm_get_stats(kcp, ksp, stats);
4597 
4598 	(void) kstat_close(kcp);
4599 }
4600 
4601 static int
4602 query_kstat(char *module, int instance, const char *name, const char *stat,
4603     uint8_t type, void *val)
4604 {
4605 	kstat_ctl_t	*kcp;
4606 	kstat_t		*ksp;
4607 
4608 	if ((kcp = kstat_open()) == NULL) {
4609 		warn("kstat open operation failed");
4610 		return (-1);
4611 	}
4612 
4613 	if ((ksp = kstat_lookup(kcp, module, instance, (char *)name)) == NULL) {
4614 		/*
4615 		 * The kstat query could fail if the underlying MAC
4616 		 * driver was already detached.
4617 		 */
4618 		goto bail;
4619 	}
4620 
4621 	if (kstat_read(kcp, ksp, NULL) == -1) {
4622 		warn("kstat read failed");
4623 		goto bail;
4624 	}
4625 
4626 	if (dladm_kstat_value(ksp, stat, type, val) < 0)
4627 		goto bail;
4628 
4629 	(void) kstat_close(kcp);
4630 	return (0);
4631 
4632 bail:
4633 	(void) kstat_close(kcp);
4634 	return (-1);
4635 }
4636 
4637 static int
4638 get_one_kstat(const char *name, const char *stat, uint8_t type,
4639     void *val, boolean_t islink)
4640 {
4641 	char		module[DLPI_LINKNAME_MAX];
4642 	uint_t		instance;
4643 
4644 	if (islink) {
4645 		return (query_kstat("link", 0, name, stat, type, val));
4646 	} else {
4647 		if (dlpi_parselink(name, module, &instance) != DLPI_SUCCESS)
4648 			return (-1);
4649 
4650 		return (query_kstat(module, instance, "mac", stat, type, val));
4651 	}
4652 }
4653 
4654 static uint64_t
4655 get_ifspeed(const char *name, boolean_t islink)
4656 {
4657 	uint64_t ifspeed = 0;
4658 
4659 	(void) get_one_kstat(name, "ifspeed", KSTAT_DATA_UINT64,
4660 	    &ifspeed, islink);
4661 
4662 	return (ifspeed);
4663 }
4664 
4665 static const char *
4666 get_linkstate(const char *name, boolean_t islink, char *buf)
4667 {
4668 	link_state_t	linkstate;
4669 
4670 	if (get_one_kstat(name, "link_state", KSTAT_DATA_UINT32,
4671 	    &linkstate, islink) != 0) {
4672 		(void) strlcpy(buf, "?", DLADM_STRSIZE);
4673 		return (buf);
4674 	}
4675 	return (dladm_linkstate2str(linkstate, buf));
4676 }
4677 
4678 static const char *
4679 get_linkduplex(const char *name, boolean_t islink, char *buf)
4680 {
4681 	link_duplex_t	linkduplex;
4682 
4683 	if (get_one_kstat(name, "link_duplex", KSTAT_DATA_UINT32,
4684 	    &linkduplex, islink) != 0) {
4685 		(void) strlcpy(buf, "unknown", DLADM_STRSIZE);
4686 		return (buf);
4687 	}
4688 
4689 	return (dladm_linkduplex2str(linkduplex, buf));
4690 }
4691 
4692 typedef struct {
4693 	char	*s_buf;
4694 	char	**s_fields;	/* array of pointer to the fields in s_buf */
4695 	uint_t	s_nfields;	/* the number of fields in s_buf */
4696 } split_t;
4697 
4698 /*
4699  * Free the split_t structure pointed to by `sp'.
4700  */
4701 static void
4702 splitfree(split_t *sp)
4703 {
4704 	free(sp->s_buf);
4705 	free(sp->s_fields);
4706 	free(sp);
4707 }
4708 
4709 /*
4710  * Split `str' into at most `maxfields' fields, each field at most `maxlen' in
4711  * length.  Return a pointer to a split_t containing the split fields, or NULL
4712  * on failure.
4713  */
4714 static split_t *
4715 split(const char *str, uint_t maxfields, uint_t maxlen)
4716 {
4717 	char	*field, *token, *lasts = NULL;
4718 	split_t	*sp;
4719 
4720 	if (*str == '\0' || maxfields == 0 || maxlen == 0)
4721 		return (NULL);
4722 
4723 	sp = calloc(sizeof (split_t), 1);
4724 	if (sp == NULL)
4725 		return (NULL);
4726 
4727 	sp->s_buf = strdup(str);
4728 	sp->s_fields = malloc(sizeof (char *) * maxfields);
4729 	if (sp->s_buf == NULL || sp->s_fields == NULL)
4730 		goto fail;
4731 
4732 	token = sp->s_buf;
4733 	while ((field = strtok_r(token, ",", &lasts)) != NULL) {
4734 		if (sp->s_nfields == maxfields || strlen(field) > maxlen)
4735 			goto fail;
4736 		token = NULL;
4737 		sp->s_fields[sp->s_nfields++] = field;
4738 	}
4739 	return (sp);
4740 fail:
4741 	splitfree(sp);
4742 	return (NULL);
4743 }
4744 
4745 static int
4746 parse_wifi_fields(char *str, print_field_t ***fields, uint_t *countp,
4747     uint_t cmdtype)
4748 {
4749 
4750 	if (cmdtype == WIFI_CMD_SCAN) {
4751 		if (str == NULL)
4752 			str = def_scan_wifi_fields;
4753 		if (strcasecmp(str, "all") == 0)
4754 			str = all_scan_wifi_fields;
4755 	} else if (cmdtype == WIFI_CMD_SHOW) {
4756 		if (str == NULL)
4757 			str = def_show_wifi_fields;
4758 		if (strcasecmp(str, "all") == 0)
4759 			str = all_show_wifi_fields;
4760 	} else {
4761 		return (-1);
4762 	}
4763 	*fields = parse_output_fields(str, wifi_fields, WIFI_MAX_FIELDS,
4764 	    cmdtype, countp);
4765 	if (*fields != NULL)
4766 		return (0);
4767 	return (-1);
4768 }
4769 static print_field_t **
4770 parse_output_fields(char *str, print_field_t *template, int max_fields,
4771     uint_t cmdtype, uint_t *countp)
4772 {
4773 	split_t		*sp;
4774 	boolean_t	good_match = B_FALSE;
4775 	uint_t		i, j;
4776 	print_field_t	**pf = NULL;
4777 
4778 	sp = split(str, max_fields, MAX_FIELD_LEN);
4779 
4780 	if (sp == NULL)
4781 		return (NULL);
4782 
4783 	pf = malloc(sp->s_nfields * sizeof (print_field_t *));
4784 	if (pf == NULL)
4785 		goto fail;
4786 
4787 	for (i = 0; i < sp->s_nfields; i++) {
4788 		for (j = 0; j < max_fields; j++) {
4789 			if (strcasecmp(sp->s_fields[i],
4790 			    template[j].pf_name) == 0) {
4791 				good_match = template[j]. pf_cmdtype & cmdtype;
4792 				break;
4793 			}
4794 		}
4795 		if (!good_match)
4796 			goto fail;
4797 
4798 		good_match = B_FALSE;
4799 		pf[i] = &template[j];
4800 	}
4801 	*countp = i;
4802 	splitfree(sp);
4803 	return (pf);
4804 fail:
4805 	free(pf);
4806 	splitfree(sp);
4807 	return (NULL);
4808 }
4809 
4810 typedef struct print_wifi_state {
4811 	char		*ws_link;
4812 	boolean_t	ws_parseable;
4813 	boolean_t	ws_header;
4814 	print_state_t	ws_print_state;
4815 } print_wifi_state_t;
4816 
4817 typedef struct  wlan_scan_args_s {
4818 	print_wifi_state_t	*ws_state;
4819 	void			*ws_attr;
4820 } wlan_scan_args_t;
4821 
4822 static void
4823 print_field(print_state_t *statep, print_field_t *pfp, const char *value,
4824     boolean_t parseable)
4825 {
4826 	uint_t	width = pfp->pf_width;
4827 	uint_t	valwidth;
4828 	uint_t	compress;
4829 
4830 	/*
4831 	 * Parsable fields are separated by ':'. If such a field contains
4832 	 * a ':' or '\', this character is prefixed by a '\'.
4833 	 */
4834 	if (parseable) {
4835 		char	c;
4836 
4837 		if (statep->ps_nfields == 1) {
4838 			(void) printf("%s", value);
4839 			return;
4840 		}
4841 		while ((c = *value++) != '\0') {
4842 			if (c == ':' || c == '\\')
4843 				(void) putchar('\\');
4844 			(void) putchar(c);
4845 		}
4846 		if (!statep->ps_lastfield)
4847 			(void) putchar(':');
4848 		return;
4849 	} else {
4850 		if (value[0] == '\0')
4851 			value = STR_UNDEF_VAL;
4852 		if (statep->ps_lastfield) {
4853 			(void) printf("%s", value);
4854 			statep->ps_overflow = 0;
4855 			return;
4856 		}
4857 
4858 		valwidth = strlen(value);
4859 		if (valwidth > width) {
4860 			statep->ps_overflow += valwidth - width;
4861 		} else if (valwidth < width && statep->ps_overflow > 0) {
4862 			compress = min(statep->ps_overflow, width - valwidth);
4863 			statep->ps_overflow -= compress;
4864 			width -= compress;
4865 		}
4866 		(void) printf("%-*s", width, value);
4867 	}
4868 
4869 	if (!statep->ps_lastfield)
4870 		(void) putchar(' ');
4871 }
4872 
4873 static char *
4874 print_wlan_attr(print_field_t *wfp, void *warg)
4875 {
4876 	static char		buf[DLADM_STRSIZE];
4877 	wlan_scan_args_t	*w = warg;
4878 	print_wifi_state_t	*statep = w->ws_state;
4879 	dladm_wlan_attr_t	*attrp = w->ws_attr;
4880 
4881 	if (wfp->pf_index == 0) {
4882 		return ((char *)statep->ws_link);
4883 	}
4884 
4885 	if ((wfp->pf_index & attrp->wa_valid) == 0) {
4886 		return ("");
4887 	}
4888 
4889 	switch (wfp->pf_index) {
4890 	case DLADM_WLAN_ATTR_ESSID:
4891 		(void) dladm_wlan_essid2str(&attrp->wa_essid, buf);
4892 		break;
4893 	case DLADM_WLAN_ATTR_BSSID:
4894 		(void) dladm_wlan_bssid2str(&attrp->wa_bssid, buf);
4895 		break;
4896 	case DLADM_WLAN_ATTR_SECMODE:
4897 		(void) dladm_wlan_secmode2str(&attrp->wa_secmode, buf);
4898 		break;
4899 	case DLADM_WLAN_ATTR_STRENGTH:
4900 		(void) dladm_wlan_strength2str(&attrp->wa_strength, buf);
4901 		break;
4902 	case DLADM_WLAN_ATTR_MODE:
4903 		(void) dladm_wlan_mode2str(&attrp->wa_mode, buf);
4904 		break;
4905 	case DLADM_WLAN_ATTR_SPEED:
4906 		(void) dladm_wlan_speed2str(&attrp->wa_speed, buf);
4907 		(void) strlcat(buf, "Mb", sizeof (buf));
4908 		break;
4909 	case DLADM_WLAN_ATTR_AUTH:
4910 		(void) dladm_wlan_auth2str(&attrp->wa_auth, buf);
4911 		break;
4912 	case DLADM_WLAN_ATTR_BSSTYPE:
4913 		(void) dladm_wlan_bsstype2str(&attrp->wa_bsstype, buf);
4914 		break;
4915 	}
4916 
4917 	return (buf);
4918 }
4919 
4920 static boolean_t
4921 print_scan_results(void *arg, dladm_wlan_attr_t *attrp)
4922 {
4923 	print_wifi_state_t	*statep = arg;
4924 	wlan_scan_args_t	warg;
4925 
4926 	if (statep->ws_header) {
4927 		statep->ws_header = B_FALSE;
4928 		if (!statep->ws_parseable)
4929 			print_header(&statep->ws_print_state);
4930 	}
4931 
4932 	statep->ws_print_state.ps_overflow = 0;
4933 	bzero(&warg, sizeof (warg));
4934 	warg.ws_state = statep;
4935 	warg.ws_attr = attrp;
4936 	dladm_print_output(&statep->ws_print_state, statep->ws_parseable,
4937 	    print_wlan_attr, &warg);
4938 	return (B_TRUE);
4939 }
4940 
4941 static int
4942 scan_wifi(dladm_handle_t dh, datalink_id_t linkid, void *arg)
4943 {
4944 	print_wifi_state_t	*statep = arg;
4945 	dladm_status_t		status;
4946 	char			link[MAXLINKNAMELEN];
4947 
4948 	if ((status = dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, link,
4949 	    sizeof (link))) != DLADM_STATUS_OK) {
4950 		return (DLADM_WALK_CONTINUE);
4951 	}
4952 
4953 	statep->ws_link = link;
4954 	status = dladm_wlan_scan(dh, linkid, statep, print_scan_results);
4955 	if (status != DLADM_STATUS_OK)
4956 		die_dlerr(status, "cannot scan link '%s'", statep->ws_link);
4957 
4958 	return (DLADM_WALK_CONTINUE);
4959 }
4960 
4961 static char *
4962 print_link_attr(print_field_t *wfp, void *warg)
4963 {
4964 	static char		buf[DLADM_STRSIZE];
4965 	char			*ptr;
4966 	wlan_scan_args_t	*w = warg, w1;
4967 	print_wifi_state_t	*statep = w->ws_state;
4968 	dladm_wlan_linkattr_t	*attrp = w->ws_attr;
4969 
4970 	if (strcmp(wfp->pf_name, "status") == 0) {
4971 		if ((wfp->pf_index & attrp->la_valid) != 0)
4972 			(void) dladm_wlan_linkstatus2str(
4973 			    &attrp->la_status, buf);
4974 		return (buf);
4975 	}
4976 	statep->ws_print_state.ps_overflow = 0;
4977 	bzero(&w1, sizeof (w1));
4978 	w1.ws_state = statep;
4979 	w1.ws_attr = &attrp->la_wlan_attr;
4980 	ptr = print_wlan_attr(wfp, &w1);
4981 	return (ptr);
4982 }
4983 
4984 static int
4985 show_wifi(dladm_handle_t dh, datalink_id_t linkid, void *arg)
4986 {
4987 	print_wifi_state_t	*statep = arg;
4988 	dladm_wlan_linkattr_t	attr;
4989 	dladm_status_t		status;
4990 	char			link[MAXLINKNAMELEN];
4991 	wlan_scan_args_t	warg;
4992 
4993 	if ((status = dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, link,
4994 	    sizeof (link))) != DLADM_STATUS_OK) {
4995 		return (DLADM_WALK_CONTINUE);
4996 	}
4997 
4998 	/* dladm_wlan_get_linkattr() memsets attr with 0 */
4999 	status = dladm_wlan_get_linkattr(dh, linkid, &attr);
5000 	if (status != DLADM_STATUS_OK)
5001 		die_dlerr(status, "cannot get link attributes for %s", link);
5002 
5003 	statep->ws_link = link;
5004 
5005 	if (statep->ws_header) {
5006 		statep->ws_header = B_FALSE;
5007 		if (!statep->ws_parseable)
5008 			print_header(&statep->ws_print_state);
5009 	}
5010 
5011 	statep->ws_print_state.ps_overflow = 0;
5012 	bzero(&warg, sizeof (warg));
5013 	warg.ws_state = statep;
5014 	warg.ws_attr = &attr;
5015 	dladm_print_output(&statep->ws_print_state, statep->ws_parseable,
5016 	    print_link_attr, &warg);
5017 	return (DLADM_WALK_CONTINUE);
5018 }
5019 
5020 static void
5021 do_display_wifi(int argc, char **argv, int cmd, const char *use)
5022 {
5023 	int			option;
5024 	char			*fields_str = NULL;
5025 	print_field_t		**fields;
5026 	int		(*callback)(dladm_handle_t, datalink_id_t, void *);
5027 	uint_t			nfields;
5028 	print_wifi_state_t	state;
5029 	datalink_id_t		linkid = DATALINK_ALL_LINKID;
5030 	dladm_status_t		status;
5031 
5032 	if (cmd == WIFI_CMD_SCAN)
5033 		callback = scan_wifi;
5034 	else if (cmd == WIFI_CMD_SHOW)
5035 		callback = show_wifi;
5036 	else
5037 		return;
5038 
5039 	state.ws_parseable = B_FALSE;
5040 	state.ws_header = B_TRUE;
5041 	opterr = 0;
5042 	while ((option = getopt_long(argc, argv, ":o:p",
5043 	    wifi_longopts, NULL)) != -1) {
5044 		switch (option) {
5045 		case 'o':
5046 			fields_str = optarg;
5047 			break;
5048 		case 'p':
5049 			state.ws_parseable = B_TRUE;
5050 			break;
5051 		default:
5052 			die_opterr(optopt, option, use);
5053 		}
5054 	}
5055 
5056 	if (state.ws_parseable && fields_str == NULL)
5057 		die("-p requires -o");
5058 
5059 	if (state.ws_parseable && strcasecmp(fields_str, "all") == 0)
5060 		die("\"-o all\" is invalid with -p");
5061 
5062 	if (optind == (argc - 1)) {
5063 		if ((status = dladm_name2info(handle, argv[optind], &linkid,
5064 		    NULL, NULL, NULL)) != DLADM_STATUS_OK) {
5065 			die_dlerr(status, "link %s is not valid", argv[optind]);
5066 		}
5067 	} else if (optind != argc) {
5068 		usage();
5069 	}
5070 
5071 	if (parse_wifi_fields(fields_str, &fields, &nfields, cmd) < 0)
5072 		die("invalid field(s) specified");
5073 
5074 	bzero(&state.ws_print_state, sizeof (state.ws_print_state));
5075 	state.ws_print_state.ps_fields = fields;
5076 	state.ws_print_state.ps_nfields = nfields;
5077 
5078 	if (linkid == DATALINK_ALL_LINKID) {
5079 		(void) dladm_walk_datalink_id(callback, handle, &state,
5080 		    DATALINK_CLASS_PHYS, DL_WIFI, DLADM_OPT_ACTIVE);
5081 	} else {
5082 		(void) (*callback)(handle, linkid, &state);
5083 	}
5084 	free(fields);
5085 }
5086 
5087 static void
5088 do_scan_wifi(int argc, char **argv, const char *use)
5089 {
5090 	do_display_wifi(argc, argv, WIFI_CMD_SCAN, use);
5091 }
5092 
5093 static void
5094 do_show_wifi(int argc, char **argv, const char *use)
5095 {
5096 	do_display_wifi(argc, argv, WIFI_CMD_SHOW, use);
5097 }
5098 
5099 typedef struct wlan_count_attr {
5100 	uint_t		wc_count;
5101 	datalink_id_t	wc_linkid;
5102 } wlan_count_attr_t;
5103 
5104 /* ARGSUSED */
5105 static int
5106 do_count_wlan(dladm_handle_t dh, datalink_id_t linkid, void *arg)
5107 {
5108 	wlan_count_attr_t *cp = arg;
5109 
5110 	if (cp->wc_count == 0)
5111 		cp->wc_linkid = linkid;
5112 	cp->wc_count++;
5113 	return (DLADM_WALK_CONTINUE);
5114 }
5115 
5116 static int
5117 parse_wlan_keys(char *str, dladm_wlan_key_t **keys, uint_t *key_countp)
5118 {
5119 	uint_t			i;
5120 	split_t			*sp;
5121 	dladm_wlan_key_t	*wk;
5122 
5123 	sp = split(str, DLADM_WLAN_MAX_WEPKEYS, DLADM_WLAN_MAX_KEYNAME_LEN);
5124 	if (sp == NULL)
5125 		return (-1);
5126 
5127 	wk = malloc(sp->s_nfields * sizeof (dladm_wlan_key_t));
5128 	if (wk == NULL)
5129 		goto fail;
5130 
5131 	for (i = 0; i < sp->s_nfields; i++) {
5132 		char			*s;
5133 		dladm_secobj_class_t	class;
5134 		dladm_status_t		status;
5135 
5136 		(void) strlcpy(wk[i].wk_name, sp->s_fields[i],
5137 		    DLADM_WLAN_MAX_KEYNAME_LEN);
5138 
5139 		wk[i].wk_idx = 1;
5140 		if ((s = strrchr(wk[i].wk_name, ':')) != NULL) {
5141 			if (s[1] == '\0' || s[2] != '\0' || !isdigit(s[1]))
5142 				goto fail;
5143 
5144 			wk[i].wk_idx = (uint_t)(s[1] - '0');
5145 			*s = '\0';
5146 		}
5147 		wk[i].wk_len = DLADM_WLAN_MAX_KEY_LEN;
5148 
5149 		status = dladm_get_secobj(handle, wk[i].wk_name, &class,
5150 		    wk[i].wk_val, &wk[i].wk_len, 0);
5151 		if (status != DLADM_STATUS_OK) {
5152 			if (status == DLADM_STATUS_NOTFOUND) {
5153 				status = dladm_get_secobj(handle, wk[i].wk_name,
5154 				    &class, wk[i].wk_val, &wk[i].wk_len,
5155 				    DLADM_OPT_PERSIST);
5156 			}
5157 			if (status != DLADM_STATUS_OK)
5158 				goto fail;
5159 		}
5160 		wk[i].wk_class = class;
5161 	}
5162 	*keys = wk;
5163 	*key_countp = i;
5164 	splitfree(sp);
5165 	return (0);
5166 fail:
5167 	free(wk);
5168 	splitfree(sp);
5169 	return (-1);
5170 }
5171 
5172 static void
5173 do_connect_wifi(int argc, char **argv, const char *use)
5174 {
5175 	int			option;
5176 	dladm_wlan_attr_t	attr, *attrp;
5177 	dladm_status_t		status = DLADM_STATUS_OK;
5178 	int			timeout = DLADM_WLAN_CONNECT_TIMEOUT_DEFAULT;
5179 	datalink_id_t		linkid = DATALINK_ALL_LINKID;
5180 	dladm_wlan_key_t	*keys = NULL;
5181 	uint_t			key_count = 0;
5182 	uint_t			flags = 0;
5183 	dladm_wlan_secmode_t	keysecmode = DLADM_WLAN_SECMODE_NONE;
5184 	char			buf[DLADM_STRSIZE];
5185 
5186 	opterr = 0;
5187 	(void) memset(&attr, 0, sizeof (attr));
5188 	while ((option = getopt_long(argc, argv, ":e:i:a:m:b:s:k:T:c",
5189 	    wifi_longopts, NULL)) != -1) {
5190 		switch (option) {
5191 		case 'e':
5192 			status = dladm_wlan_str2essid(optarg, &attr.wa_essid);
5193 			if (status != DLADM_STATUS_OK)
5194 				die("invalid ESSID '%s'", optarg);
5195 
5196 			attr.wa_valid |= DLADM_WLAN_ATTR_ESSID;
5197 			/*
5198 			 * Try to connect without doing a scan.
5199 			 */
5200 			flags |= DLADM_WLAN_CONNECT_NOSCAN;
5201 			break;
5202 		case 'i':
5203 			status = dladm_wlan_str2bssid(optarg, &attr.wa_bssid);
5204 			if (status != DLADM_STATUS_OK)
5205 				die("invalid BSSID %s", optarg);
5206 
5207 			attr.wa_valid |= DLADM_WLAN_ATTR_BSSID;
5208 			break;
5209 		case 'a':
5210 			status = dladm_wlan_str2auth(optarg, &attr.wa_auth);
5211 			if (status != DLADM_STATUS_OK)
5212 				die("invalid authentication mode '%s'", optarg);
5213 
5214 			attr.wa_valid |= DLADM_WLAN_ATTR_AUTH;
5215 			break;
5216 		case 'm':
5217 			status = dladm_wlan_str2mode(optarg, &attr.wa_mode);
5218 			if (status != DLADM_STATUS_OK)
5219 				die("invalid mode '%s'", optarg);
5220 
5221 			attr.wa_valid |= DLADM_WLAN_ATTR_MODE;
5222 			break;
5223 		case 'b':
5224 			if ((status = dladm_wlan_str2bsstype(optarg,
5225 			    &attr.wa_bsstype)) != DLADM_STATUS_OK) {
5226 				die("invalid bsstype '%s'", optarg);
5227 			}
5228 
5229 			attr.wa_valid |= DLADM_WLAN_ATTR_BSSTYPE;
5230 			break;
5231 		case 's':
5232 			if ((status = dladm_wlan_str2secmode(optarg,
5233 			    &attr.wa_secmode)) != DLADM_STATUS_OK) {
5234 				die("invalid security mode '%s'", optarg);
5235 			}
5236 
5237 			attr.wa_valid |= DLADM_WLAN_ATTR_SECMODE;
5238 			break;
5239 		case 'k':
5240 			if (parse_wlan_keys(optarg, &keys, &key_count) < 0)
5241 				die("invalid key(s) '%s'", optarg);
5242 
5243 			if (keys[0].wk_class == DLADM_SECOBJ_CLASS_WEP)
5244 				keysecmode = DLADM_WLAN_SECMODE_WEP;
5245 			else
5246 				keysecmode = DLADM_WLAN_SECMODE_WPA;
5247 			break;
5248 		case 'T':
5249 			if (strcasecmp(optarg, "forever") == 0) {
5250 				timeout = -1;
5251 				break;
5252 			}
5253 			if (!str2int(optarg, &timeout) || timeout < 0)
5254 				die("invalid timeout value '%s'", optarg);
5255 			break;
5256 		case 'c':
5257 			flags |= DLADM_WLAN_CONNECT_CREATEIBSS;
5258 			flags |= DLADM_WLAN_CONNECT_CREATEIBSS;
5259 			break;
5260 		default:
5261 			die_opterr(optopt, option, use);
5262 			break;
5263 		}
5264 	}
5265 
5266 	if (keysecmode == DLADM_WLAN_SECMODE_NONE) {
5267 		if ((attr.wa_valid & DLADM_WLAN_ATTR_SECMODE) != 0) {
5268 			die("key required for security mode '%s'",
5269 			    dladm_wlan_secmode2str(&attr.wa_secmode, buf));
5270 		}
5271 	} else {
5272 		if ((attr.wa_valid & DLADM_WLAN_ATTR_SECMODE) != 0 &&
5273 		    attr.wa_secmode != keysecmode)
5274 			die("incompatible -s and -k options");
5275 		attr.wa_valid |= DLADM_WLAN_ATTR_SECMODE;
5276 		attr.wa_secmode = keysecmode;
5277 	}
5278 
5279 	if (optind == (argc - 1)) {
5280 		if ((status = dladm_name2info(handle, argv[optind], &linkid,
5281 		    NULL, NULL, NULL)) != DLADM_STATUS_OK) {
5282 			die_dlerr(status, "link %s is not valid", argv[optind]);
5283 		}
5284 	} else if (optind != argc) {
5285 		usage();
5286 	}
5287 
5288 	if (linkid == DATALINK_ALL_LINKID) {
5289 		wlan_count_attr_t wcattr;
5290 
5291 		wcattr.wc_linkid = DATALINK_INVALID_LINKID;
5292 		wcattr.wc_count = 0;
5293 		(void) dladm_walk_datalink_id(do_count_wlan, handle, &wcattr,
5294 		    DATALINK_CLASS_PHYS, DL_WIFI, DLADM_OPT_ACTIVE);
5295 		if (wcattr.wc_count == 0) {
5296 			die("no wifi links are available");
5297 		} else if (wcattr.wc_count > 1) {
5298 			die("link name is required when more than one wifi "
5299 			    "link is available");
5300 		}
5301 		linkid = wcattr.wc_linkid;
5302 	}
5303 	attrp = (attr.wa_valid == 0) ? NULL : &attr;
5304 again:
5305 	if ((status = dladm_wlan_connect(handle, linkid, attrp, timeout, keys,
5306 	    key_count, flags)) != DLADM_STATUS_OK) {
5307 		if ((flags & DLADM_WLAN_CONNECT_NOSCAN) != 0) {
5308 			/*
5309 			 * Try again with scanning and filtering.
5310 			 */
5311 			flags &= ~DLADM_WLAN_CONNECT_NOSCAN;
5312 			goto again;
5313 		}
5314 
5315 		if (status == DLADM_STATUS_NOTFOUND) {
5316 			if (attr.wa_valid == 0) {
5317 				die("no wifi networks are available");
5318 			} else {
5319 				die("no wifi networks with the specified "
5320 				    "criteria are available");
5321 			}
5322 		}
5323 		die_dlerr(status, "cannot connect");
5324 	}
5325 	free(keys);
5326 }
5327 
5328 /* ARGSUSED */
5329 static int
5330 do_all_disconnect_wifi(dladm_handle_t dh, datalink_id_t linkid, void *arg)
5331 {
5332 	dladm_status_t	status;
5333 
5334 	status = dladm_wlan_disconnect(dh, linkid);
5335 	if (status != DLADM_STATUS_OK)
5336 		warn_dlerr(status, "cannot disconnect link");
5337 
5338 	return (DLADM_WALK_CONTINUE);
5339 }
5340 
5341 static void
5342 do_disconnect_wifi(int argc, char **argv, const char *use)
5343 {
5344 	int			option;
5345 	datalink_id_t		linkid = DATALINK_ALL_LINKID;
5346 	boolean_t		all_links = B_FALSE;
5347 	dladm_status_t		status;
5348 	wlan_count_attr_t	wcattr;
5349 
5350 	opterr = 0;
5351 	while ((option = getopt_long(argc, argv, ":a",
5352 	    wifi_longopts, NULL)) != -1) {
5353 		switch (option) {
5354 		case 'a':
5355 			all_links = B_TRUE;
5356 			break;
5357 		default:
5358 			die_opterr(optopt, option, use);
5359 			break;
5360 		}
5361 	}
5362 
5363 	if (optind == (argc - 1)) {
5364 		if ((status = dladm_name2info(handle, argv[optind], &linkid,
5365 		    NULL, NULL, NULL)) != DLADM_STATUS_OK) {
5366 			die_dlerr(status, "link %s is not valid", argv[optind]);
5367 		}
5368 	} else if (optind != argc) {
5369 		usage();
5370 	}
5371 
5372 	if (linkid == DATALINK_ALL_LINKID) {
5373 		if (!all_links) {
5374 			wcattr.wc_linkid = linkid;
5375 			wcattr.wc_count = 0;
5376 			(void) dladm_walk_datalink_id(do_count_wlan, handle,
5377 			    &wcattr, DATALINK_CLASS_PHYS, DL_WIFI,
5378 			    DLADM_OPT_ACTIVE);
5379 			if (wcattr.wc_count == 0) {
5380 				die("no wifi links are available");
5381 			} else if (wcattr.wc_count > 1) {
5382 				die("link name is required when more than "
5383 				    "one wifi link is available");
5384 			}
5385 			linkid = wcattr.wc_linkid;
5386 		} else {
5387 			(void) dladm_walk_datalink_id(do_all_disconnect_wifi,
5388 			    handle, NULL, DATALINK_CLASS_PHYS, DL_WIFI,
5389 			    DLADM_OPT_ACTIVE);
5390 			return;
5391 		}
5392 	}
5393 	status = dladm_wlan_disconnect(handle, linkid);
5394 	if (status != DLADM_STATUS_OK)
5395 		die_dlerr(status, "cannot disconnect");
5396 }
5397 
5398 static void
5399 print_linkprop(datalink_id_t linkid, show_linkprop_state_t *statep,
5400     const char *propname, dladm_prop_type_t type, const char *format,
5401     char **pptr)
5402 {
5403 	int		i;
5404 	char		*ptr, *lim;
5405 	char		buf[DLADM_STRSIZE];
5406 	char		*unknown = "--", *notsup = "";
5407 	char		**propvals = statep->ls_propvals;
5408 	uint_t		valcnt = DLADM_MAX_PROP_VALCNT;
5409 	dladm_status_t	status;
5410 
5411 	status = dladm_get_linkprop(handle, linkid, type, propname, propvals,
5412 	    &valcnt);
5413 	if (status != DLADM_STATUS_OK) {
5414 		if (status == DLADM_STATUS_TEMPONLY) {
5415 			if (type == DLADM_PROP_VAL_MODIFIABLE &&
5416 			    statep->ls_persist) {
5417 				valcnt = 1;
5418 				propvals = &unknown;
5419 			} else {
5420 				statep->ls_status = status;
5421 				statep->ls_retstatus = status;
5422 				return;
5423 			}
5424 		} else if (status == DLADM_STATUS_NOTSUP ||
5425 		    statep->ls_persist) {
5426 			valcnt = 1;
5427 			if (type == DLADM_PROP_VAL_CURRENT ||
5428 			    type == DLADM_PROP_VAL_PERM)
5429 				propvals = &unknown;
5430 			else
5431 				propvals = &notsup;
5432 		} else if (status == DLADM_STATUS_NOTDEFINED) {
5433 			propvals = &notsup; /* STR_UNDEF_VAL */
5434 		} else {
5435 			if (statep->ls_proplist &&
5436 			    statep->ls_status == DLADM_STATUS_OK) {
5437 				warn_dlerr(status,
5438 				    "cannot get link property '%s' for %s",
5439 				    propname, statep->ls_link);
5440 			}
5441 			statep->ls_status = status;
5442 			statep->ls_retstatus = status;
5443 			return;
5444 		}
5445 	}
5446 
5447 	statep->ls_status = DLADM_STATUS_OK;
5448 
5449 	ptr = buf;
5450 	lim = buf + DLADM_STRSIZE;
5451 	for (i = 0; i < valcnt; i++) {
5452 		if (propvals[i][0] == '\0' && !statep->ls_parseable)
5453 			ptr += snprintf(ptr, lim - ptr, STR_UNDEF_VAL",");
5454 		else
5455 			ptr += snprintf(ptr, lim - ptr, "%s,", propvals[i]);
5456 		if (ptr >= lim)
5457 			break;
5458 	}
5459 	if (valcnt > 0)
5460 		buf[strlen(buf) - 1] = '\0';
5461 
5462 	lim = statep->ls_line + MAX_PROP_LINE;
5463 	if (statep->ls_parseable) {
5464 		*pptr += snprintf(*pptr, lim - *pptr,
5465 		    "%s", buf);
5466 	} else {
5467 		*pptr += snprintf(*pptr, lim - *pptr, format, buf);
5468 	}
5469 }
5470 
5471 static char *
5472 linkprop_callback(print_field_t *pf, void *ls_arg)
5473 {
5474 	linkprop_args_t		*arg = ls_arg;
5475 	char 			*propname = arg->ls_propname;
5476 	show_linkprop_state_t	*statep = arg->ls_state;
5477 	char			*ptr = statep->ls_line;
5478 	char			*lim = ptr + MAX_PROP_LINE;
5479 	datalink_id_t		linkid = arg->ls_linkid;
5480 
5481 	switch (pf->pf_index) {
5482 	case LINKPROP_LINK:
5483 		(void) snprintf(ptr, lim - ptr, "%s", statep->ls_link);
5484 		break;
5485 	case LINKPROP_PROPERTY:
5486 		(void) snprintf(ptr, lim - ptr, "%s", propname);
5487 		break;
5488 	case LINKPROP_VALUE:
5489 		print_linkprop(linkid, statep, propname,
5490 		    statep->ls_persist ? DLADM_PROP_VAL_PERSISTENT :
5491 		    DLADM_PROP_VAL_CURRENT, "%s", &ptr);
5492 		/*
5493 		 * If we failed to query the link property, for example, query
5494 		 * the persistent value of a non-persistable link property,
5495 		 * simply skip the output.
5496 		 */
5497 		if (statep->ls_status != DLADM_STATUS_OK)
5498 			goto skip;
5499 		ptr = statep->ls_line;
5500 		break;
5501 	case LINKPROP_PERM:
5502 		print_linkprop(linkid, statep, propname,
5503 		    DLADM_PROP_VAL_PERM, "%s", &ptr);
5504 		if (statep->ls_status != DLADM_STATUS_OK)
5505 			goto skip;
5506 		ptr = statep->ls_line;
5507 		break;
5508 	case LINKPROP_DEFAULT:
5509 		print_linkprop(linkid, statep, propname,
5510 		    DLADM_PROP_VAL_DEFAULT, "%s", &ptr);
5511 		if (statep->ls_status != DLADM_STATUS_OK)
5512 			goto skip;
5513 		ptr = statep->ls_line;
5514 		break;
5515 	case LINKPROP_POSSIBLE:
5516 		print_linkprop(linkid, statep, propname,
5517 		    DLADM_PROP_VAL_MODIFIABLE, "%s ", &ptr);
5518 		if (statep->ls_status != DLADM_STATUS_OK)
5519 			goto skip;
5520 		ptr = statep->ls_line;
5521 		break;
5522 	default:
5523 		die("invalid input");
5524 		break;
5525 	}
5526 	return (ptr);
5527 skip:
5528 	if (statep->ls_status != DLADM_STATUS_OK)
5529 		return (NULL);
5530 	else
5531 		return ("");
5532 }
5533 
5534 static boolean_t
5535 linkprop_is_supported(datalink_id_t  linkid, const char *propname,
5536     show_linkprop_state_t *statep)
5537 {
5538 	dladm_status_t	status;
5539 	uint_t		valcnt = DLADM_MAX_PROP_VALCNT;
5540 
5541 	/* if used with -p flag, always print output */
5542 	if (statep->ls_proplist != NULL)
5543 		return (B_TRUE);
5544 
5545 	status = dladm_get_linkprop(handle, linkid, DLADM_PROP_VAL_DEFAULT,
5546 	    propname, statep->ls_propvals, &valcnt);
5547 
5548 	if (status == DLADM_STATUS_OK)
5549 		return (B_TRUE);
5550 
5551 	/*
5552 	 * A system wide default value is not available for the
5553 	 * property. Check if current value can be retrieved.
5554 	 */
5555 	status = dladm_get_linkprop(handle, linkid, DLADM_PROP_VAL_CURRENT,
5556 	    propname, statep->ls_propvals, &valcnt);
5557 
5558 	return (status == DLADM_STATUS_OK);
5559 }
5560 
5561 /* ARGSUSED */
5562 static int
5563 show_linkprop(dladm_handle_t dh, datalink_id_t linkid, const char *propname,
5564     void *arg)
5565 {
5566 	show_linkprop_state_t	*statep = arg;
5567 	linkprop_args_t		ls_arg;
5568 
5569 	bzero(&ls_arg, sizeof (ls_arg));
5570 	ls_arg.ls_state = statep;
5571 	ls_arg.ls_propname = (char *)propname;
5572 	ls_arg.ls_linkid = linkid;
5573 
5574 	if (statep->ls_header) {
5575 		statep->ls_header = B_FALSE;
5576 		if (!statep->ls_parseable)
5577 			print_header(&statep->ls_print);
5578 	}
5579 	/*
5580 	 * This will need to be fixed when kernel interfaces are added
5581 	 * to enable walking of all known private properties. For now,
5582 	 * we are limited to walking persistent private properties only.
5583 	 */
5584 	if ((propname[0] == '_') && !statep->ls_persist &&
5585 	    (statep->ls_proplist == NULL))
5586 		return (DLADM_WALK_CONTINUE);
5587 	if (!statep->ls_parseable &&
5588 	    !linkprop_is_supported(linkid, propname, statep))
5589 		return (DLADM_WALK_CONTINUE);
5590 
5591 	dladm_print_output(&statep->ls_print, statep->ls_parseable,
5592 	    linkprop_callback, (void *)&ls_arg);
5593 
5594 	return (DLADM_WALK_CONTINUE);
5595 }
5596 
5597 static void
5598 do_show_linkprop(int argc, char **argv, const char *use)
5599 {
5600 	int			option;
5601 	dladm_arg_list_t	*proplist = NULL;
5602 	datalink_id_t		linkid = DATALINK_ALL_LINKID;
5603 	show_linkprop_state_t	state;
5604 	uint32_t		flags = DLADM_OPT_ACTIVE;
5605 	dladm_status_t		status;
5606 	char			*fields_str = NULL;
5607 	print_field_t		**fields;
5608 	uint_t			nfields;
5609 	boolean_t		o_arg = B_FALSE;
5610 	char			*all_fields =
5611 	    "link,property,perm,value,default,possible";
5612 
5613 	fields_str = all_fields;
5614 
5615 	opterr = 0;
5616 	state.ls_propvals = NULL;
5617 	state.ls_line = NULL;
5618 	state.ls_parseable = B_FALSE;
5619 	state.ls_persist = B_FALSE;
5620 	state.ls_header = B_TRUE;
5621 	state.ls_retstatus = DLADM_STATUS_OK;
5622 	while ((option = getopt_long(argc, argv, ":p:cPo:",
5623 	    prop_longopts, NULL)) != -1) {
5624 		switch (option) {
5625 		case 'p':
5626 			if (dladm_parse_link_props(optarg, &proplist, B_TRUE)
5627 			    != DLADM_STATUS_OK)
5628 				die("invalid link properties specified");
5629 			break;
5630 		case 'c':
5631 			state.ls_parseable = B_TRUE;
5632 			break;
5633 		case 'P':
5634 			state.ls_persist = B_TRUE;
5635 			flags = DLADM_OPT_PERSIST;
5636 			break;
5637 		case 'o':
5638 			o_arg = B_TRUE;
5639 			if (strcasecmp(optarg, "all") == 0)
5640 				fields_str = all_fields;
5641 			else
5642 				fields_str = optarg;
5643 			break;
5644 		default:
5645 			die_opterr(optopt, option, use);
5646 			break;
5647 		}
5648 	}
5649 
5650 	if (state.ls_parseable && !o_arg)
5651 		die("-c requires -o");
5652 
5653 	if (state.ls_parseable && fields_str == all_fields)
5654 		die("\"-o all\" is invalid with -c");
5655 
5656 	if (optind == (argc - 1)) {
5657 		if ((status = dladm_name2info(handle, argv[optind], &linkid,
5658 		    NULL, NULL, NULL)) != DLADM_STATUS_OK) {
5659 			die_dlerr(status, "link %s is not valid", argv[optind]);
5660 		}
5661 	} else if (optind != argc) {
5662 		usage();
5663 	}
5664 
5665 	bzero(&state.ls_print, sizeof (print_state_t));
5666 	state.ls_proplist = proplist;
5667 	state.ls_status = DLADM_STATUS_OK;
5668 
5669 	fields = parse_output_fields(fields_str, linkprop_fields,
5670 	    LINKPROP_MAX_FIELDS, CMD_TYPE_ANY, &nfields);
5671 
5672 	if (fields == NULL) {
5673 		die("invalid field(s) specified");
5674 		return;
5675 	}
5676 
5677 	state.ls_print.ps_fields = fields;
5678 	state.ls_print.ps_nfields = nfields;
5679 	if (linkid == DATALINK_ALL_LINKID) {
5680 		(void) dladm_walk_datalink_id(show_linkprop_onelink, handle,
5681 		    &state, DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE, flags);
5682 	} else {
5683 		(void) show_linkprop_onelink(handle, linkid, &state);
5684 	}
5685 	dladm_free_props(proplist);
5686 
5687 	if (state.ls_retstatus != DLADM_STATUS_OK) {
5688 		dladm_close(handle);
5689 		exit(EXIT_FAILURE);
5690 	}
5691 }
5692 
5693 static int
5694 show_linkprop_onelink(dladm_handle_t hdl, datalink_id_t linkid, void *arg)
5695 {
5696 	int			i;
5697 	char			*buf;
5698 	uint32_t		flags;
5699 	dladm_arg_list_t	*proplist = NULL;
5700 	show_linkprop_state_t	*statep = arg;
5701 	dlpi_handle_t		dh = NULL;
5702 
5703 	statep->ls_status = DLADM_STATUS_OK;
5704 
5705 	if (dladm_datalink_id2info(hdl, linkid, &flags, NULL, NULL,
5706 	    statep->ls_link, MAXLINKNAMELEN) != DLADM_STATUS_OK) {
5707 		statep->ls_status = DLADM_STATUS_NOTFOUND;
5708 		return (DLADM_WALK_CONTINUE);
5709 	}
5710 
5711 	if ((statep->ls_persist && !(flags & DLADM_OPT_PERSIST)) ||
5712 	    (!statep->ls_persist && !(flags & DLADM_OPT_ACTIVE))) {
5713 		statep->ls_status = DLADM_STATUS_BADARG;
5714 		return (DLADM_WALK_CONTINUE);
5715 	}
5716 
5717 	proplist = statep->ls_proplist;
5718 
5719 	/*
5720 	 * When some WiFi links are opened for the first time, their hardware
5721 	 * automatically scans for APs and does other slow operations.	Thus,
5722 	 * if there are no open links, the retrieval of link properties
5723 	 * (below) will proceed slowly unless we hold the link open.
5724 	 *
5725 	 * Note that failure of dlpi_open() does not necessarily mean invalid
5726 	 * link properties, because dlpi_open() may fail because of incorrect
5727 	 * autopush configuration. Therefore, we ingore the return value of
5728 	 * dlpi_open().
5729 	 */
5730 	if (!statep->ls_persist)
5731 		(void) dlpi_open(statep->ls_link, &dh, 0);
5732 
5733 	buf = malloc((sizeof (char *) + DLADM_PROP_VAL_MAX) *
5734 	    DLADM_MAX_PROP_VALCNT + MAX_PROP_LINE);
5735 	if (buf == NULL)
5736 		die("insufficient memory");
5737 
5738 	statep->ls_propvals = (char **)(void *)buf;
5739 	for (i = 0; i < DLADM_MAX_PROP_VALCNT; i++) {
5740 		statep->ls_propvals[i] = buf +
5741 		    sizeof (char *) * DLADM_MAX_PROP_VALCNT +
5742 		    i * DLADM_PROP_VAL_MAX;
5743 	}
5744 	statep->ls_line = buf +
5745 	    (sizeof (char *) + DLADM_PROP_VAL_MAX) * DLADM_MAX_PROP_VALCNT;
5746 
5747 	if (proplist != NULL) {
5748 		for (i = 0; i < proplist->al_count; i++) {
5749 			(void) show_linkprop(hdl, linkid,
5750 			    proplist->al_info[i].ai_name, statep);
5751 		}
5752 	} else {
5753 		(void) dladm_walk_linkprop(hdl, linkid, statep,
5754 		    show_linkprop);
5755 	}
5756 	if (dh != NULL)
5757 		dlpi_close(dh);
5758 	free(buf);
5759 	return (DLADM_WALK_CONTINUE);
5760 }
5761 
5762 static dladm_status_t
5763 set_linkprop_persist(datalink_id_t linkid, const char *prop_name,
5764     char **prop_val, uint_t val_cnt, boolean_t reset)
5765 {
5766 	dladm_status_t	status;
5767 
5768 	status = dladm_set_linkprop(handle, linkid, prop_name, prop_val,
5769 	    val_cnt, DLADM_OPT_PERSIST);
5770 
5771 	if (status != DLADM_STATUS_OK) {
5772 		warn_dlerr(status, "cannot persistently %s link property '%s'",
5773 		    reset ? "reset" : "set", prop_name);
5774 	}
5775 	return (status);
5776 }
5777 
5778 static int
5779 reset_one_linkprop(dladm_handle_t dh, datalink_id_t linkid,
5780     const char *propname, void *arg)
5781 {
5782 	set_linkprop_state_t	*statep = arg;
5783 	dladm_status_t		status;
5784 
5785 	status = dladm_set_linkprop(dh, linkid, propname, NULL, 0,
5786 	    DLADM_OPT_ACTIVE);
5787 	if (status != DLADM_STATUS_OK) {
5788 		warn_dlerr(status, "cannot reset link property '%s' on '%s'",
5789 		    propname, statep->ls_name);
5790 	}
5791 	if (!statep->ls_temp) {
5792 		dladm_status_t	s;
5793 
5794 		s = set_linkprop_persist(linkid, propname, NULL, 0,
5795 		    statep->ls_reset);
5796 		if (s != DLADM_STATUS_OK)
5797 			status = s;
5798 	}
5799 	if (status != DLADM_STATUS_OK)
5800 		statep->ls_status = status;
5801 
5802 	return (DLADM_WALK_CONTINUE);
5803 }
5804 
5805 static void
5806 set_linkprop(int argc, char **argv, boolean_t reset, const char *use)
5807 {
5808 	int			i, option;
5809 	char			errmsg[DLADM_STRSIZE];
5810 	char			*altroot = NULL;
5811 	datalink_id_t		linkid;
5812 	boolean_t		temp = B_FALSE;
5813 	dladm_status_t		status = DLADM_STATUS_OK;
5814 	dladm_arg_list_t	*proplist = NULL;
5815 
5816 	opterr = 0;
5817 	while ((option = getopt_long(argc, argv, ":p:R:t",
5818 	    prop_longopts, NULL)) != -1) {
5819 		switch (option) {
5820 		case 'p':
5821 			if (dladm_parse_link_props(optarg, &proplist, reset) !=
5822 			    DLADM_STATUS_OK) {
5823 				die("invalid link properties specified");
5824 			}
5825 			break;
5826 		case 't':
5827 			temp = B_TRUE;
5828 			break;
5829 		case 'R':
5830 			altroot = optarg;
5831 			break;
5832 		default:
5833 			die_opterr(optopt, option, use);
5834 
5835 		}
5836 	}
5837 
5838 	/* get link name (required last argument) */
5839 	if (optind != (argc - 1))
5840 		usage();
5841 
5842 	if (proplist == NULL && !reset)
5843 		die("link property must be specified");
5844 
5845 	if (altroot != NULL) {
5846 		dladm_free_props(proplist);
5847 		altroot_cmd(altroot, argc, argv);
5848 	}
5849 
5850 	status = dladm_name2info(handle, argv[optind], &linkid, NULL, NULL,
5851 	    NULL);
5852 	if (status != DLADM_STATUS_OK)
5853 		die_dlerr(status, "link %s is not valid", argv[optind]);
5854 
5855 	if (proplist == NULL) {
5856 		set_linkprop_state_t	state;
5857 
5858 		state.ls_name = argv[optind];
5859 		state.ls_reset = reset;
5860 		state.ls_temp = temp;
5861 		state.ls_status = DLADM_STATUS_OK;
5862 
5863 		(void) dladm_walk_linkprop(handle, linkid, &state,
5864 		    reset_one_linkprop);
5865 
5866 		status = state.ls_status;
5867 		goto done;
5868 	}
5869 
5870 	for (i = 0; i < proplist->al_count; i++) {
5871 		dladm_arg_info_t	*aip = &proplist->al_info[i];
5872 		char		**val;
5873 		uint_t		count;
5874 		dladm_status_t	s;
5875 
5876 		if (reset) {
5877 			val = NULL;
5878 			count = 0;
5879 		} else {
5880 			val = aip->ai_val;
5881 			count = aip->ai_count;
5882 			if (count == 0) {
5883 				warn("no value specified for '%s'",
5884 				    aip->ai_name);
5885 				status = DLADM_STATUS_BADARG;
5886 				continue;
5887 			}
5888 		}
5889 		s = dladm_set_linkprop(handle, linkid, aip->ai_name, val, count,
5890 		    DLADM_OPT_ACTIVE);
5891 		if (s == DLADM_STATUS_OK) {
5892 			if (!temp) {
5893 				s = set_linkprop_persist(linkid,
5894 				    aip->ai_name, val, count, reset);
5895 				if (s != DLADM_STATUS_OK)
5896 					status = s;
5897 			}
5898 			continue;
5899 		}
5900 		status = s;
5901 		switch (s) {
5902 		case DLADM_STATUS_NOTFOUND:
5903 			warn("invalid link property '%s'", aip->ai_name);
5904 			break;
5905 		case DLADM_STATUS_BADVAL: {
5906 			int		j;
5907 			char		*ptr, *lim;
5908 			char		**propvals = NULL;
5909 			uint_t		valcnt = DLADM_MAX_PROP_VALCNT;
5910 
5911 			ptr = malloc((sizeof (char *) +
5912 			    DLADM_PROP_VAL_MAX) * DLADM_MAX_PROP_VALCNT +
5913 			    MAX_PROP_LINE);
5914 
5915 			propvals = (char **)(void *)ptr;
5916 			if (propvals == NULL)
5917 				die("insufficient memory");
5918 
5919 			for (j = 0; j < DLADM_MAX_PROP_VALCNT; j++) {
5920 				propvals[j] = ptr + sizeof (char *) *
5921 				    DLADM_MAX_PROP_VALCNT +
5922 				    j * DLADM_PROP_VAL_MAX;
5923 			}
5924 			s = dladm_get_linkprop(handle, linkid,
5925 			    DLADM_PROP_VAL_MODIFIABLE, aip->ai_name, propvals,
5926 			    &valcnt);
5927 
5928 			if (s != DLADM_STATUS_OK) {
5929 				warn_dlerr(status, "cannot set link property "
5930 				    "'%s' on '%s'", aip->ai_name, argv[optind]);
5931 				free(propvals);
5932 				break;
5933 			}
5934 
5935 			ptr = errmsg;
5936 			lim = ptr + DLADM_STRSIZE;
5937 			*ptr = '\0';
5938 			for (j = 0; j < valcnt; j++) {
5939 				ptr += snprintf(ptr, lim - ptr, "%s,",
5940 				    propvals[j]);
5941 				if (ptr >= lim)
5942 					break;
5943 			}
5944 			if (ptr > errmsg) {
5945 				*(ptr - 1) = '\0';
5946 				warn("link property '%s' must be one of: %s",
5947 				    aip->ai_name, errmsg);
5948 			} else
5949 				warn("invalid link property '%s'", *val);
5950 			free(propvals);
5951 			break;
5952 		}
5953 		default:
5954 			if (reset) {
5955 				warn_dlerr(status, "cannot reset link property "
5956 				    "'%s' on '%s'", aip->ai_name, argv[optind]);
5957 			} else {
5958 				warn_dlerr(status, "cannot set link property "
5959 				    "'%s' on '%s'", aip->ai_name, argv[optind]);
5960 			}
5961 			break;
5962 		}
5963 	}
5964 done:
5965 	dladm_free_props(proplist);
5966 	if (status != DLADM_STATUS_OK) {
5967 		dladm_close(handle);
5968 		exit(1);
5969 	}
5970 }
5971 
5972 static void
5973 do_set_linkprop(int argc, char **argv, const char *use)
5974 {
5975 	set_linkprop(argc, argv, B_FALSE, use);
5976 }
5977 
5978 static void
5979 do_reset_linkprop(int argc, char **argv, const char *use)
5980 {
5981 	set_linkprop(argc, argv, B_TRUE, use);
5982 }
5983 
5984 static int
5985 convert_secobj(char *buf, uint_t len, uint8_t *obj_val, uint_t *obj_lenp,
5986     dladm_secobj_class_t class)
5987 {
5988 	int error = 0;
5989 
5990 	if (class == DLADM_SECOBJ_CLASS_WPA) {
5991 		if (len < 8 || len > 63)
5992 			return (EINVAL);
5993 		(void) memcpy(obj_val, buf, len);
5994 		*obj_lenp = len;
5995 		return (error);
5996 	}
5997 
5998 	if (class == DLADM_SECOBJ_CLASS_WEP) {
5999 		switch (len) {
6000 		case 5:			/* ASCII key sizes */
6001 		case 13:
6002 			(void) memcpy(obj_val, buf, len);
6003 			*obj_lenp = len;
6004 			break;
6005 		case 10:		/* Hex key sizes, not preceded by 0x */
6006 		case 26:
6007 			error = hexascii_to_octet(buf, len, obj_val, obj_lenp);
6008 			break;
6009 		case 12:		/* Hex key sizes, preceded by 0x */
6010 		case 28:
6011 			if (strncmp(buf, "0x", 2) != 0)
6012 				return (EINVAL);
6013 			error = hexascii_to_octet(buf + 2, len - 2,
6014 			    obj_val, obj_lenp);
6015 			break;
6016 		default:
6017 			return (EINVAL);
6018 		}
6019 		return (error);
6020 	}
6021 
6022 	return (ENOENT);
6023 }
6024 
6025 static void
6026 defersig(int sig)
6027 {
6028 	signalled = sig;
6029 }
6030 
6031 static int
6032 get_secobj_from_tty(uint_t try, const char *objname, char *buf)
6033 {
6034 	uint_t		len = 0;
6035 	int		c;
6036 	struct termios	stored, current;
6037 	void		(*sigfunc)(int);
6038 
6039 	/*
6040 	 * Turn off echo -- but before we do so, defer SIGINT handling
6041 	 * so that a ^C doesn't leave the terminal corrupted.
6042 	 */
6043 	sigfunc = signal(SIGINT, defersig);
6044 	(void) fflush(stdin);
6045 	(void) tcgetattr(0, &stored);
6046 	current = stored;
6047 	current.c_lflag &= ~(ICANON|ECHO);
6048 	current.c_cc[VTIME] = 0;
6049 	current.c_cc[VMIN] = 1;
6050 	(void) tcsetattr(0, TCSANOW, &current);
6051 again:
6052 	if (try == 1)
6053 		(void) printf(gettext("provide value for '%s': "), objname);
6054 	else
6055 		(void) printf(gettext("confirm value for '%s': "), objname);
6056 
6057 	(void) fflush(stdout);
6058 	while (signalled == 0) {
6059 		c = getchar();
6060 		if (c == '\n' || c == '\r') {
6061 			if (len != 0)
6062 				break;
6063 			(void) putchar('\n');
6064 			goto again;
6065 		}
6066 
6067 		buf[len++] = c;
6068 		if (len >= DLADM_SECOBJ_VAL_MAX - 1)
6069 			break;
6070 		(void) putchar('*');
6071 	}
6072 
6073 	(void) putchar('\n');
6074 	(void) fflush(stdin);
6075 
6076 	/*
6077 	 * Restore terminal setting and handle deferred signals.
6078 	 */
6079 	(void) tcsetattr(0, TCSANOW, &stored);
6080 
6081 	(void) signal(SIGINT, sigfunc);
6082 	if (signalled != 0)
6083 		(void) kill(getpid(), signalled);
6084 
6085 	return (len);
6086 }
6087 
6088 static int
6089 get_secobj_val(char *obj_name, uint8_t *obj_val, uint_t *obj_lenp,
6090     dladm_secobj_class_t class, FILE *filep)
6091 {
6092 	int		rval;
6093 	uint_t		len, len2;
6094 	char		buf[DLADM_SECOBJ_VAL_MAX], buf2[DLADM_SECOBJ_VAL_MAX];
6095 
6096 	if (filep == NULL) {
6097 		len = get_secobj_from_tty(1, obj_name, buf);
6098 		rval = convert_secobj(buf, len, obj_val, obj_lenp, class);
6099 		if (rval == 0) {
6100 			len2 = get_secobj_from_tty(2, obj_name, buf2);
6101 			if (len != len2 || memcmp(buf, buf2, len) != 0)
6102 				rval = ENOTSUP;
6103 		}
6104 		return (rval);
6105 	} else {
6106 		for (;;) {
6107 			if (fgets(buf, sizeof (buf), filep) == NULL)
6108 				break;
6109 			if (isspace(buf[0]))
6110 				continue;
6111 
6112 			len = strlen(buf);
6113 			if (buf[len - 1] == '\n') {
6114 				buf[len - 1] = '\0';
6115 				len--;
6116 			}
6117 			break;
6118 		}
6119 		(void) fclose(filep);
6120 	}
6121 	return (convert_secobj(buf, len, obj_val, obj_lenp, class));
6122 }
6123 
6124 static boolean_t
6125 check_auth(const char *auth)
6126 {
6127 	struct passwd	*pw;
6128 
6129 	if ((pw = getpwuid(getuid())) == NULL)
6130 		return (B_FALSE);
6131 
6132 	return (chkauthattr(auth, pw->pw_name) != 0);
6133 }
6134 
6135 static void
6136 audit_secobj(char *auth, char *class, char *obj,
6137     boolean_t success, boolean_t create)
6138 {
6139 	adt_session_data_t	*ah;
6140 	adt_event_data_t	*event;
6141 	au_event_t		flag;
6142 	char			*errstr;
6143 
6144 	if (create) {
6145 		flag = ADT_dladm_create_secobj;
6146 		errstr = "ADT_dladm_create_secobj";
6147 	} else {
6148 		flag = ADT_dladm_delete_secobj;
6149 		errstr = "ADT_dladm_delete_secobj";
6150 	}
6151 
6152 	if (adt_start_session(&ah, NULL, ADT_USE_PROC_DATA) != 0)
6153 		die("adt_start_session: %s", strerror(errno));
6154 
6155 	if ((event = adt_alloc_event(ah, flag)) == NULL)
6156 		die("adt_alloc_event (%s): %s", errstr, strerror(errno));
6157 
6158 	/* fill in audit info */
6159 	if (create) {
6160 		event->adt_dladm_create_secobj.auth_used = auth;
6161 		event->adt_dladm_create_secobj.obj_class = class;
6162 		event->adt_dladm_create_secobj.obj_name = obj;
6163 	} else {
6164 		event->adt_dladm_delete_secobj.auth_used = auth;
6165 		event->adt_dladm_delete_secobj.obj_class = class;
6166 		event->adt_dladm_delete_secobj.obj_name = obj;
6167 	}
6168 
6169 	if (success) {
6170 		if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS) != 0) {
6171 			die("adt_put_event (%s, success): %s", errstr,
6172 			    strerror(errno));
6173 		}
6174 	} else {
6175 		if (adt_put_event(event, ADT_FAILURE,
6176 		    ADT_FAIL_VALUE_AUTH) != 0) {
6177 			die("adt_put_event: (%s, failure): %s", errstr,
6178 			    strerror(errno));
6179 		}
6180 	}
6181 
6182 	adt_free_event(event);
6183 	(void) adt_end_session(ah);
6184 }
6185 
6186 #define	MAX_SECOBJS		32
6187 #define	MAX_SECOBJ_NAMELEN	32
6188 static void
6189 do_create_secobj(int argc, char **argv, const char *use)
6190 {
6191 	int			option, rval;
6192 	FILE			*filep = NULL;
6193 	char			*obj_name = NULL;
6194 	char			*class_name = NULL;
6195 	uint8_t			obj_val[DLADM_SECOBJ_VAL_MAX];
6196 	uint_t			obj_len;
6197 	boolean_t		success, temp = B_FALSE;
6198 	dladm_status_t		status;
6199 	dladm_secobj_class_t	class = -1;
6200 	uid_t			euid;
6201 
6202 	opterr = 0;
6203 	(void) memset(obj_val, 0, DLADM_SECOBJ_VAL_MAX);
6204 	while ((option = getopt_long(argc, argv, ":f:c:R:t",
6205 	    wifi_longopts, NULL)) != -1) {
6206 		switch (option) {
6207 		case 'f':
6208 			euid = geteuid();
6209 			(void) seteuid(getuid());
6210 			filep = fopen(optarg, "r");
6211 			if (filep == NULL) {
6212 				die("cannot open %s: %s", optarg,
6213 				    strerror(errno));
6214 			}
6215 			(void) seteuid(euid);
6216 			break;
6217 		case 'c':
6218 			class_name = optarg;
6219 			status = dladm_str2secobjclass(optarg, &class);
6220 			if (status != DLADM_STATUS_OK) {
6221 				die("invalid secure object class '%s', "
6222 				    "valid values are: wep, wpa", optarg);
6223 			}
6224 			break;
6225 		case 't':
6226 			temp = B_TRUE;
6227 			break;
6228 		case 'R':
6229 			status = dladm_set_rootdir(optarg);
6230 			if (status != DLADM_STATUS_OK) {
6231 				die_dlerr(status, "invalid directory "
6232 				    "specified");
6233 			}
6234 			break;
6235 		default:
6236 			die_opterr(optopt, option, use);
6237 			break;
6238 		}
6239 	}
6240 
6241 	if (optind == (argc - 1))
6242 		obj_name = argv[optind];
6243 	else if (optind != argc)
6244 		usage();
6245 
6246 	if (class == -1)
6247 		die("secure object class required");
6248 
6249 	if (obj_name == NULL)
6250 		die("secure object name required");
6251 
6252 	if (!dladm_valid_secobj_name(obj_name))
6253 		die("invalid secure object name '%s'", obj_name);
6254 
6255 	success = check_auth(LINK_SEC_AUTH);
6256 	audit_secobj(LINK_SEC_AUTH, class_name, obj_name, success, B_TRUE);
6257 	if (!success)
6258 		die("authorization '%s' is required", LINK_SEC_AUTH);
6259 
6260 	rval = get_secobj_val(obj_name, obj_val, &obj_len, class, filep);
6261 	if (rval != 0) {
6262 		switch (rval) {
6263 		case ENOENT:
6264 			die("invalid secure object class");
6265 			break;
6266 		case EINVAL:
6267 			die("invalid secure object value");
6268 			break;
6269 		case ENOTSUP:
6270 			die("verification failed");
6271 			break;
6272 		default:
6273 			die("invalid secure object: %s", strerror(rval));
6274 			break;
6275 		}
6276 	}
6277 
6278 	status = dladm_set_secobj(handle, obj_name, class, obj_val, obj_len,
6279 	    DLADM_OPT_CREATE | DLADM_OPT_ACTIVE);
6280 	if (status != DLADM_STATUS_OK) {
6281 		die_dlerr(status, "could not create secure object '%s'",
6282 		    obj_name);
6283 	}
6284 	if (temp)
6285 		return;
6286 
6287 	status = dladm_set_secobj(handle, obj_name, class, obj_val, obj_len,
6288 	    DLADM_OPT_PERSIST);
6289 	if (status != DLADM_STATUS_OK) {
6290 		warn_dlerr(status, "could not persistently create secure "
6291 		    "object '%s'", obj_name);
6292 	}
6293 }
6294 
6295 static void
6296 do_delete_secobj(int argc, char **argv, const char *use)
6297 {
6298 	int		i, option;
6299 	boolean_t	temp = B_FALSE;
6300 	split_t		*sp = NULL;
6301 	boolean_t	success;
6302 	dladm_status_t	status, pstatus;
6303 
6304 	opterr = 0;
6305 	status = pstatus = DLADM_STATUS_OK;
6306 	while ((option = getopt_long(argc, argv, ":R:t",
6307 	    wifi_longopts, NULL)) != -1) {
6308 		switch (option) {
6309 		case 't':
6310 			temp = B_TRUE;
6311 			break;
6312 		case 'R':
6313 			status = dladm_set_rootdir(optarg);
6314 			if (status != DLADM_STATUS_OK) {
6315 				die_dlerr(status, "invalid directory "
6316 				    "specified");
6317 			}
6318 			break;
6319 		default:
6320 			die_opterr(optopt, option, use);
6321 			break;
6322 		}
6323 	}
6324 
6325 	if (optind == (argc - 1)) {
6326 		sp = split(argv[optind], MAX_SECOBJS, MAX_SECOBJ_NAMELEN);
6327 		if (sp == NULL) {
6328 			die("invalid secure object name(s): '%s'",
6329 			    argv[optind]);
6330 		}
6331 	} else if (optind != argc)
6332 		usage();
6333 
6334 	if (sp == NULL || sp->s_nfields < 1)
6335 		die("secure object name required");
6336 
6337 	success = check_auth(LINK_SEC_AUTH);
6338 	audit_secobj(LINK_SEC_AUTH, "unknown", argv[optind], success, B_FALSE);
6339 	if (!success)
6340 		die("authorization '%s' is required", LINK_SEC_AUTH);
6341 
6342 	for (i = 0; i < sp->s_nfields; i++) {
6343 		status = dladm_unset_secobj(handle, sp->s_fields[i],
6344 		    DLADM_OPT_ACTIVE);
6345 		if (!temp) {
6346 			pstatus = dladm_unset_secobj(handle, sp->s_fields[i],
6347 			    DLADM_OPT_PERSIST);
6348 		} else {
6349 			pstatus = DLADM_STATUS_OK;
6350 		}
6351 
6352 		if (status != DLADM_STATUS_OK) {
6353 			warn_dlerr(status, "could not delete secure object "
6354 			    "'%s'", sp->s_fields[i]);
6355 		}
6356 		if (pstatus != DLADM_STATUS_OK) {
6357 			warn_dlerr(pstatus, "could not persistently delete "
6358 			    "secure object '%s'", sp->s_fields[i]);
6359 		}
6360 	}
6361 
6362 	if (status != DLADM_STATUS_OK || pstatus != DLADM_STATUS_OK) {
6363 		dladm_close(handle);
6364 		exit(1);
6365 	}
6366 }
6367 
6368 typedef struct show_secobj_state {
6369 	boolean_t	ss_persist;
6370 	boolean_t	ss_parseable;
6371 	boolean_t	ss_header;
6372 	print_state_t	ss_print;
6373 } show_secobj_state_t;
6374 
6375 
6376 static boolean_t
6377 show_secobj(dladm_handle_t dh, void *arg, const char *obj_name)
6378 {
6379 	uint_t			obj_len = DLADM_SECOBJ_VAL_MAX;
6380 	uint8_t			obj_val[DLADM_SECOBJ_VAL_MAX];
6381 	char			buf[DLADM_STRSIZE];
6382 	uint_t			flags = 0;
6383 	dladm_secobj_class_t	class;
6384 	show_secobj_state_t	*statep = arg;
6385 	dladm_status_t		status;
6386 	secobj_fields_buf_t	sbuf;
6387 
6388 	bzero(&sbuf, sizeof (secobj_fields_buf_t));
6389 	if (statep->ss_persist)
6390 		flags |= DLADM_OPT_PERSIST;
6391 
6392 	status = dladm_get_secobj(dh, obj_name, &class, obj_val, &obj_len,
6393 	    flags);
6394 	if (status != DLADM_STATUS_OK)
6395 		die_dlerr(status, "cannot get secure object '%s'", obj_name);
6396 
6397 	if (statep->ss_header) {
6398 		statep->ss_header = B_FALSE;
6399 		if (!statep->ss_parseable)
6400 			print_header(&statep->ss_print);
6401 	}
6402 
6403 	(void) snprintf(sbuf.ss_obj_name, sizeof (sbuf.ss_obj_name),
6404 	    obj_name);
6405 	(void) dladm_secobjclass2str(class, buf);
6406 	(void) snprintf(sbuf.ss_class, sizeof (sbuf.ss_class), "%s", buf);
6407 	if (getuid() == 0) {
6408 		char	val[DLADM_SECOBJ_VAL_MAX * 2];
6409 		uint_t	len = sizeof (val);
6410 
6411 		if (octet_to_hexascii(obj_val, obj_len, val, &len) == 0)
6412 			(void) snprintf(sbuf.ss_val,
6413 			    sizeof (sbuf.ss_val), "%s", val);
6414 	}
6415 	dladm_print_output(&statep->ss_print, statep->ss_parseable,
6416 	    dladm_print_field, (void *)&sbuf);
6417 	return (B_TRUE);
6418 }
6419 
6420 static void
6421 do_show_secobj(int argc, char **argv, const char *use)
6422 {
6423 	int			option;
6424 	show_secobj_state_t	state;
6425 	dladm_status_t		status;
6426 	boolean_t		o_arg = B_FALSE;
6427 	uint_t			i;
6428 	split_t			*sp;
6429 	uint_t			flags;
6430 	char			*fields_str = NULL;
6431 	print_field_t		**fields;
6432 	uint_t			nfields;
6433 	char			*def_fields = "object,class";
6434 	char			*all_fields = "object,class,value";
6435 
6436 	opterr = 0;
6437 	bzero(&state, sizeof (state));
6438 	state.ss_parseable = B_FALSE;
6439 	fields_str = def_fields;
6440 	state.ss_persist = B_FALSE;
6441 	state.ss_parseable = B_FALSE;
6442 	state.ss_header = B_TRUE;
6443 	while ((option = getopt_long(argc, argv, ":pPo:",
6444 	    wifi_longopts, NULL)) != -1) {
6445 		switch (option) {
6446 		case 'p':
6447 			state.ss_parseable = B_TRUE;
6448 			break;
6449 		case 'P':
6450 			state.ss_persist = B_TRUE;
6451 			break;
6452 		case 'o':
6453 			o_arg = B_TRUE;
6454 			if (strcasecmp(optarg, "all") == 0)
6455 				fields_str = all_fields;
6456 			else
6457 				fields_str = optarg;
6458 			break;
6459 		default:
6460 			die_opterr(optopt, option, use);
6461 			break;
6462 		}
6463 	}
6464 
6465 	if (state.ss_parseable && !o_arg)
6466 		die("option -c requires -o");
6467 
6468 	if (state.ss_parseable && fields_str == all_fields)
6469 		die("\"-o all\" is invalid with -p");
6470 
6471 	fields = parse_output_fields(fields_str, secobj_fields,
6472 	    DEV_SOBJ_FIELDS, CMD_TYPE_ANY, &nfields);
6473 
6474 	if (fields == NULL) {
6475 		die("invalid field(s) specified");
6476 		return;
6477 	}
6478 	state.ss_print.ps_fields = fields;
6479 	state.ss_print.ps_nfields = nfields;
6480 
6481 	flags = state.ss_persist ? DLADM_OPT_PERSIST : 0;
6482 
6483 	if (optind == (argc - 1)) {
6484 		sp = split(argv[optind], MAX_SECOBJS, MAX_SECOBJ_NAMELEN);
6485 		if (sp == NULL) {
6486 			die("invalid secure object name(s): '%s'",
6487 			    argv[optind]);
6488 		}
6489 		for (i = 0; i < sp->s_nfields; i++) {
6490 			if (!show_secobj(handle, &state, sp->s_fields[i]))
6491 				break;
6492 		}
6493 		splitfree(sp);
6494 		return;
6495 	} else if (optind != argc)
6496 		usage();
6497 
6498 	status = dladm_walk_secobj(handle, &state, show_secobj, flags);
6499 
6500 	if (status != DLADM_STATUS_OK)
6501 		die_dlerr(status, "show-secobj");
6502 }
6503 
6504 /*ARGSUSED*/
6505 static int
6506 i_dladm_init_linkprop(dladm_handle_t dh, datalink_id_t linkid, void *arg)
6507 {
6508 	(void) dladm_init_linkprop(dh, linkid, B_TRUE);
6509 	return (DLADM_WALK_CONTINUE);
6510 }
6511 
6512 /*ARGSUSED*/
6513 void
6514 do_init_linkprop(int argc, char **argv, const char *use)
6515 {
6516 	int			option;
6517 	dladm_status_t		status;
6518 	datalink_id_t		linkid = DATALINK_ALL_LINKID;
6519 	datalink_media_t	media = DATALINK_ANY_MEDIATYPE;
6520 	uint_t			any_media = B_TRUE;
6521 
6522 	opterr = 0;
6523 	while ((option = getopt(argc, argv, ":w")) != -1) {
6524 		switch (option) {
6525 		case 'w':
6526 			media = DL_WIFI;
6527 			any_media = B_FALSE;
6528 			break;
6529 		default:
6530 			/*
6531 			 * Because init-linkprop is not a public command,
6532 			 * print the usage instead.
6533 			 */
6534 			usage();
6535 			break;
6536 		}
6537 	}
6538 
6539 	if (optind == (argc - 1)) {
6540 		if ((status = dladm_name2info(handle, argv[optind], &linkid,
6541 		    NULL, NULL, NULL)) != DLADM_STATUS_OK)
6542 			die_dlerr(status, "link %s is not valid", argv[optind]);
6543 	} else if (optind != argc) {
6544 		usage();
6545 	}
6546 
6547 	if (linkid == DATALINK_ALL_LINKID) {
6548 		/*
6549 		 * linkprops of links of other classes have been initialized as
6550 		 * part of the dladm up-xxx operation.
6551 		 */
6552 		(void) dladm_walk_datalink_id(i_dladm_init_linkprop, handle,
6553 		    NULL, DATALINK_CLASS_PHYS, media, DLADM_OPT_PERSIST);
6554 	} else {
6555 		(void) dladm_init_linkprop(handle, linkid, any_media);
6556 	}
6557 }
6558 
6559 static void
6560 do_show_ether(int argc, char **argv, const char *use)
6561 {
6562 	int 			option;
6563 	datalink_id_t		linkid;
6564 	print_ether_state_t 	state;
6565 	print_field_t 		**fields;
6566 	boolean_t		o_arg = B_FALSE;
6567 	char			*fields_str;
6568 	uint_t			nfields;
6569 	char			*all_fields =
6570 	    "link,ptype,state,auto,speed-duplex,pause,rem_fault";
6571 	char			*default_fields =
6572 	    "link,ptype,state,auto,speed-duplex,pause";
6573 
6574 	fields_str = default_fields;
6575 	bzero(&state, sizeof (state));
6576 	state.es_link = NULL;
6577 	state.es_parseable = B_FALSE;
6578 
6579 	while ((option = getopt_long(argc, argv, "o:px",
6580 	    showeth_lopts, NULL)) != -1) {
6581 		switch (option) {
6582 			case 'x':
6583 				state.es_extended = B_TRUE;
6584 				break;
6585 			case 'p':
6586 				state.es_parseable = B_TRUE;
6587 				break;
6588 			case 'o':
6589 				o_arg = B_TRUE;
6590 				if (strcasecmp(optarg, "all") == 0)
6591 					fields_str = all_fields;
6592 				else
6593 					fields_str = optarg;
6594 				break;
6595 			default:
6596 				die_opterr(optopt, option, use);
6597 				break;
6598 		}
6599 	}
6600 
6601 	if (state.es_parseable && !o_arg)
6602 		die("-p requires -o");
6603 
6604 	if (state.es_parseable && fields_str == all_fields)
6605 		die("\"-o all\" is invalid with -p");
6606 
6607 	if (optind == (argc - 1))
6608 		state.es_link = argv[optind];
6609 
6610 	fields = parse_output_fields(fields_str, ether_fields,
6611 	    ETHER_MAX_FIELDS, CMD_TYPE_ANY, &nfields);
6612 
6613 	if (fields == NULL)
6614 		die("invalid field(s) specified");
6615 
6616 	state.es_print.ps_fields = fields;
6617 	state.es_print.ps_nfields = nfields;
6618 
6619 
6620 	if (state.es_link == NULL) {
6621 		(void) dladm_walk_datalink_id(show_etherprop, handle, &state,
6622 		    DATALINK_CLASS_PHYS, DL_ETHER,
6623 		    DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST);
6624 	} else {
6625 		if (!link_is_ether(state.es_link, &linkid))
6626 			die("invalid link specified");
6627 		(void) show_etherprop(handle, linkid, &state);
6628 	}
6629 }
6630 
6631 static char *
6632 dladm_print_field(print_field_t *pf, void *arg)
6633 {
6634 	char *value;
6635 
6636 	value = (char *)arg + pf->pf_offset;
6637 	return (value);
6638 }
6639 
6640 static int
6641 show_etherprop(dladm_handle_t dh, datalink_id_t linkid, void *arg)
6642 {
6643 	print_ether_state_t	*statep = arg;
6644 	ether_fields_buf_t	ebuf;
6645 	dladm_ether_info_t	eattr;
6646 	dladm_status_t		status;
6647 
6648 	bzero(&ebuf, sizeof (ether_fields_buf_t));
6649 	if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL,
6650 	    ebuf.eth_link, sizeof (ebuf.eth_link)) != DLADM_STATUS_OK) {
6651 		return (DLADM_WALK_CONTINUE);
6652 	}
6653 
6654 	if (!statep->es_header && !statep->es_parseable) {
6655 		print_header(&statep->es_print);
6656 		statep->es_header = B_TRUE;
6657 	}
6658 
6659 	status = dladm_ether_info(dh, linkid, &eattr);
6660 	if (status != DLADM_STATUS_OK)
6661 		goto cleanup;
6662 
6663 	(void) strlcpy(ebuf.eth_ptype, "current", sizeof (ebuf.eth_ptype));
6664 
6665 	(void) dladm_ether_autoneg2str(ebuf.eth_autoneg,
6666 	    sizeof (ebuf.eth_autoneg), &eattr, CURRENT);
6667 	(void) dladm_ether_pause2str(ebuf.eth_pause,
6668 	    sizeof (ebuf.eth_pause), &eattr, CURRENT);
6669 	(void) dladm_ether_spdx2str(ebuf.eth_spdx,
6670 	    sizeof (ebuf.eth_spdx), &eattr, CURRENT);
6671 	(void) strlcpy(ebuf.eth_state,
6672 	    dladm_linkstate2str(eattr.lei_state, ebuf.eth_state),
6673 	    sizeof (ebuf.eth_state));
6674 	(void) strlcpy(ebuf.eth_rem_fault,
6675 	    (eattr.lei_attr[CURRENT].le_fault ? "fault" : "none"),
6676 	    sizeof (ebuf.eth_rem_fault));
6677 
6678 	dladm_print_output(&statep->es_print, statep->es_parseable,
6679 	    dladm_print_field, &ebuf);
6680 
6681 	if (statep->es_extended)
6682 		show_ether_xprop(arg, &eattr);
6683 
6684 cleanup:
6685 	dladm_ether_info_done(&eattr);
6686 	return (DLADM_WALK_CONTINUE);
6687 }
6688 
6689 /* ARGSUSED */
6690 static void
6691 do_init_secobj(int argc, char **argv, const char *use)
6692 {
6693 	dladm_status_t	status;
6694 
6695 	status = dladm_init_secobj(handle);
6696 	if (status != DLADM_STATUS_OK)
6697 		die_dlerr(status, "secure object initialization failed");
6698 }
6699 
6700 /*
6701  * "-R" option support. It is used for live upgrading. Append dladm commands
6702  * to a upgrade script which will be run when the alternative root boots up:
6703  *
6704  * - If the /etc/dladm/datalink.conf file exists on the alternative root,
6705  * append dladm commands to the <altroot>/var/svc/profile/upgrade_datalink
6706  * script. This script will be run as part of the network/physical service.
6707  * We cannot defer this to /var/svc/profile/upgrade because then the
6708  * configuration will not be able to take effect before network/physical
6709  * plumbs various interfaces.
6710  *
6711  * - If the /etc/dladm/datalink.conf file does not exist on the alternative
6712  * root, append dladm commands to the <altroot>/var/svc/profile/upgrade script,
6713  * which will be run in the manifest-import service.
6714  *
6715  * Note that the SMF team is considering to move the manifest-import service
6716  * to be run at the very begining of boot. Once that is done, the need for
6717  * the /var/svc/profile/upgrade_datalink script will not exist any more.
6718  */
6719 static void
6720 altroot_cmd(char *altroot, int argc, char *argv[])
6721 {
6722 	char		path[MAXPATHLEN];
6723 	struct stat	stbuf;
6724 	FILE		*fp;
6725 	int		i;
6726 
6727 	/*
6728 	 * Check for the existence of the /etc/dladm/datalink.conf
6729 	 * configuration file, and determine the name of script file.
6730 	 */
6731 	(void) snprintf(path, MAXPATHLEN, "/%s/etc/dladm/datalink.conf",
6732 	    altroot);
6733 	if (stat(path, &stbuf) < 0) {
6734 		(void) snprintf(path, MAXPATHLEN, "/%s/%s", altroot,
6735 		    SMF_UPGRADE_FILE);
6736 	} else {
6737 		(void) snprintf(path, MAXPATHLEN, "/%s/%s", altroot,
6738 		    SMF_UPGRADEDATALINK_FILE);
6739 	}
6740 
6741 	if ((fp = fopen(path, "a+")) == NULL)
6742 		die("operation not supported on %s", altroot);
6743 
6744 	(void) fprintf(fp, "/sbin/dladm ");
6745 	for (i = 0; i < argc; i++) {
6746 		/*
6747 		 * Directly write to the file if it is not the "-R <altroot>"
6748 		 * option. In which case, skip it.
6749 		 */
6750 		if (strcmp(argv[i], "-R") != 0)
6751 			(void) fprintf(fp, "%s ", argv[i]);
6752 		else
6753 			i ++;
6754 	}
6755 	(void) fprintf(fp, "%s\n", SMF_DLADM_UPGRADE_MSG);
6756 	(void) fclose(fp);
6757 	dladm_close(handle);
6758 	exit(0);
6759 }
6760 
6761 /*
6762  * Convert the string to an integer. Note that the string must not have any
6763  * trailing non-integer characters.
6764  */
6765 static boolean_t
6766 str2int(const char *str, int *valp)
6767 {
6768 	int	val;
6769 	char	*endp = NULL;
6770 
6771 	errno = 0;
6772 	val = strtol(str, &endp, 10);
6773 	if (errno != 0 || *endp != '\0')
6774 		return (B_FALSE);
6775 
6776 	*valp = val;
6777 	return (B_TRUE);
6778 }
6779 
6780 /* PRINTFLIKE1 */
6781 static void
6782 warn(const char *format, ...)
6783 {
6784 	va_list alist;
6785 
6786 	format = gettext(format);
6787 	(void) fprintf(stderr, "%s: warning: ", progname);
6788 
6789 	va_start(alist, format);
6790 	(void) vfprintf(stderr, format, alist);
6791 	va_end(alist);
6792 
6793 	(void) putchar('\n');
6794 }
6795 
6796 /* PRINTFLIKE2 */
6797 static void
6798 warn_dlerr(dladm_status_t err, const char *format, ...)
6799 {
6800 	va_list alist;
6801 	char	errmsg[DLADM_STRSIZE];
6802 
6803 	format = gettext(format);
6804 	(void) fprintf(stderr, gettext("%s: warning: "), progname);
6805 
6806 	va_start(alist, format);
6807 	(void) vfprintf(stderr, format, alist);
6808 	va_end(alist);
6809 	(void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg));
6810 }
6811 
6812 /*
6813  * Also closes the dladm handle if it is not NULL.
6814  */
6815 /* PRINTFLIKE2 */
6816 static void
6817 die_dlerr(dladm_status_t err, const char *format, ...)
6818 {
6819 	va_list alist;
6820 	char	errmsg[DLADM_STRSIZE];
6821 
6822 	format = gettext(format);
6823 	(void) fprintf(stderr, "%s: ", progname);
6824 
6825 	va_start(alist, format);
6826 	(void) vfprintf(stderr, format, alist);
6827 	va_end(alist);
6828 	(void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg));
6829 
6830 	/* close dladm handle if it was opened */
6831 	if (handle != NULL)
6832 		dladm_close(handle);
6833 
6834 	exit(EXIT_FAILURE);
6835 }
6836 
6837 /* PRINTFLIKE1 */
6838 static void
6839 die(const char *format, ...)
6840 {
6841 	va_list alist;
6842 
6843 	format = gettext(format);
6844 	(void) fprintf(stderr, "%s: ", progname);
6845 
6846 	va_start(alist, format);
6847 	(void) vfprintf(stderr, format, alist);
6848 	va_end(alist);
6849 
6850 	(void) putchar('\n');
6851 
6852 	/* close dladm handle if it was opened */
6853 	if (handle != NULL)
6854 		dladm_close(handle);
6855 
6856 	exit(EXIT_FAILURE);
6857 }
6858 
6859 static void
6860 die_optdup(int opt)
6861 {
6862 	die("the option -%c cannot be specified more than once", opt);
6863 }
6864 
6865 static void
6866 die_opterr(int opt, int opterr, const char *usage)
6867 {
6868 	switch (opterr) {
6869 	case ':':
6870 		die("option '-%c' requires a value\nusage: %s", opt,
6871 		    gettext(usage));
6872 		break;
6873 	case '?':
6874 	default:
6875 		die("unrecognized option '-%c'\nusage: %s", opt,
6876 		    gettext(usage));
6877 		break;
6878 	}
6879 }
6880 
6881 static void
6882 show_ether_xprop(void *arg, dladm_ether_info_t *eattr)
6883 {
6884 	print_ether_state_t	*statep = arg;
6885 	ether_fields_buf_t	ebuf;
6886 	int			i;
6887 
6888 	for (i = CAPABLE; i <= PEERADV; i++)  {
6889 		bzero(&ebuf, sizeof (ebuf));
6890 		(void) strlcpy(ebuf.eth_ptype, ptype[i],
6891 		    sizeof (ebuf.eth_ptype));
6892 		(void) dladm_ether_autoneg2str(ebuf.eth_autoneg,
6893 		    sizeof (ebuf.eth_autoneg), eattr, i);
6894 		(void) dladm_ether_spdx2str(ebuf.eth_spdx,
6895 		    sizeof (ebuf.eth_spdx), eattr, i);
6896 		(void) dladm_ether_pause2str(ebuf.eth_pause,
6897 		    sizeof (ebuf.eth_pause), eattr, i);
6898 		(void) strlcpy(ebuf.eth_rem_fault,
6899 		    (eattr->lei_attr[i].le_fault ? "fault" : "none"),
6900 		    sizeof (ebuf.eth_rem_fault));
6901 		dladm_print_output(&statep->es_print, statep->es_parseable,
6902 		    dladm_print_field, &ebuf);
6903 	}
6904 
6905 }
6906 
6907 static void
6908 dladm_print_output(print_state_t *statep, boolean_t parseable,
6909     print_callback_t fn, void *arg)
6910 {
6911 	int i;
6912 	char *value;
6913 	print_field_t **pf;
6914 
6915 	pf = statep->ps_fields;
6916 	for (i = 0; i < statep->ps_nfields; i++) {
6917 		statep->ps_lastfield = (i + 1 == statep->ps_nfields);
6918 		value = (*fn)(pf[i], arg);
6919 		if (value != NULL)
6920 			print_field(statep, pf[i], value, parseable);
6921 	}
6922 	(void) putchar('\n');
6923 }
6924 
6925 static void
6926 print_header(print_state_t *ps)
6927 {
6928 	int i;
6929 	print_field_t **pf;
6930 
6931 	pf = ps->ps_fields;
6932 	for (i = 0; i < ps->ps_nfields; i++) {
6933 		ps->ps_lastfield = (i + 1 == ps->ps_nfields);
6934 		print_field(ps, pf[i], pf[i]->pf_header, B_FALSE);
6935 	}
6936 	(void) putchar('\n');
6937 }
6938 
6939 static boolean_t
6940 link_is_ether(const char *link, datalink_id_t *linkid)
6941 {
6942 	uint32_t media;
6943 	datalink_class_t class;
6944 
6945 	if (dladm_name2info(handle, link, linkid, NULL, &class, &media) ==
6946 	    DLADM_STATUS_OK) {
6947 		if (class == DATALINK_CLASS_PHYS && media == DL_ETHER)
6948 			return (B_TRUE);
6949 	}
6950 	return (B_FALSE);
6951 }
6952