xref: /titanic_51/usr/src/cmd/dladm/dladm.c (revision 8cecff49db8e75ebf1858567ff985fdf50f1b899)
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 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <stdio.h>
29 #include <ctype.h>
30 #include <locale.h>
31 #include <signal.h>
32 #include <stdarg.h>
33 #include <stdlib.h>
34 #include <fcntl.h>
35 #include <string.h>
36 #include <stropts.h>
37 #include <errno.h>
38 #include <kstat.h>
39 #include <strings.h>
40 #include <getopt.h>
41 #include <unistd.h>
42 #include <priv.h>
43 #include <termios.h>
44 #include <pwd.h>
45 #include <auth_attr.h>
46 #include <auth_list.h>
47 #include <libintl.h>
48 #include <libdlpi.h>
49 #include <libdllink.h>
50 #include <libdlaggr.h>
51 #include <libdlwlan.h>
52 #include <libinetutil.h>
53 #include <bsm/adt.h>
54 #include <bsm/adt_event.h>
55 
56 #define	AGGR_DRV	"aggr"
57 #define	MAXPORT		256
58 #define	DUMP_LACP_FORMAT	"    %-9s %-8s %-7s %-12s "	\
59 	"%-5s %-4s %-4s %-9s %-7s\n"
60 
61 typedef struct pktsum_s {
62 	uint64_t	ipackets;
63 	uint64_t	opackets;
64 	uint64_t	rbytes;
65 	uint64_t	obytes;
66 	uint32_t	ierrors;
67 	uint32_t	oerrors;
68 } pktsum_t;
69 
70 typedef struct show_link_state {
71 	boolean_t	ls_firstonly;
72 	boolean_t	ls_donefirst;
73 	boolean_t	ls_stats;
74 	pktsum_t	ls_prevstats;
75 	boolean_t	ls_parseable;
76 } show_link_state_t;
77 
78 typedef struct show_grp_state {
79 	uint32_t	gs_key;
80 	boolean_t	gs_lacp;
81 	boolean_t	gs_found;
82 	boolean_t	gs_stats;
83 	boolean_t	gs_firstonly;
84 	pktsum_t	gs_prevstats[MAXPORT];
85 	boolean_t	gs_parseable;
86 } show_grp_state_t;
87 
88 typedef struct show_mac_state {
89 	boolean_t	ms_firstonly;
90 	boolean_t	ms_donefirst;
91 	pktsum_t	ms_prevstats;
92 	boolean_t	ms_parseable;
93 } show_mac_state_t;
94 
95 typedef	void cmdfunc_t(int, char **);
96 
97 static cmdfunc_t do_show_link, do_show_dev, do_show_wifi;
98 static cmdfunc_t do_create_aggr, do_delete_aggr, do_add_aggr, do_remove_aggr;
99 static cmdfunc_t do_modify_aggr, do_show_aggr, do_up_aggr, do_down_aggr;
100 static cmdfunc_t do_scan_wifi, do_connect_wifi, do_disconnect_wifi;
101 static cmdfunc_t do_show_linkprop, do_set_linkprop, do_reset_linkprop;
102 static cmdfunc_t do_create_secobj, do_delete_secobj, do_show_secobj;
103 static cmdfunc_t do_init_linkprop, do_init_secobj;
104 
105 static void	show_linkprop_onelink(void *, const char *);
106 
107 static void	link_stats(const char *, uint_t);
108 static void	aggr_stats(uint32_t, uint_t);
109 static void	dev_stats(const char *dev, uint32_t);
110 
111 static void	get_mac_stats(const char *, pktsum_t *);
112 static void	get_link_stats(const char *, pktsum_t *);
113 static uint64_t	mac_ifspeed(const char *);
114 static void	stats_total(pktsum_t *, pktsum_t *, pktsum_t *);
115 static void	stats_diff(pktsum_t *, pktsum_t *, pktsum_t *);
116 static const char	*mac_link_state(const char *, char *);
117 static const char	*mac_link_duplex(const char *, char *);
118 
119 static boolean_t str2int(const char *, int *);
120 static void	die(const char *, ...);
121 static void	die_optdup(int);
122 static void	die_opterr(int, int);
123 static void	die_dlerr(dladm_status_t, const char *, ...);
124 static void	warn(const char *, ...);
125 static void	warn_dlerr(dladm_status_t, const char *, ...);
126 
127 typedef struct	cmd {
128 	char		*c_name;
129 	cmdfunc_t	*c_fn;
130 } cmd_t;
131 
132 static cmd_t	cmds[] = {
133 	{ "show-link",		do_show_link		},
134 	{ "show-dev",		do_show_dev		},
135 	{ "create-aggr",	do_create_aggr		},
136 	{ "delete-aggr",	do_delete_aggr		},
137 	{ "add-aggr",		do_add_aggr		},
138 	{ "remove-aggr",	do_remove_aggr		},
139 	{ "modify-aggr",	do_modify_aggr		},
140 	{ "show-aggr",		do_show_aggr		},
141 	{ "up-aggr",		do_up_aggr		},
142 	{ "down-aggr",		do_down_aggr		},
143 	{ "scan-wifi",		do_scan_wifi		},
144 	{ "connect-wifi",	do_connect_wifi		},
145 	{ "disconnect-wifi",	do_disconnect_wifi	},
146 	{ "show-wifi",		do_show_wifi		},
147 	{ "show-linkprop",	do_show_linkprop	},
148 	{ "set-linkprop",	do_set_linkprop		},
149 	{ "reset-linkprop",	do_reset_linkprop	},
150 	{ "create-secobj",	do_create_secobj	},
151 	{ "delete-secobj",	do_delete_secobj	},
152 	{ "show-secobj",	do_show_secobj		},
153 	{ "init-linkprop",	do_init_linkprop	},
154 	{ "init-secobj",	do_init_secobj		}
155 };
156 
157 static const struct option longopts[] = {
158 	{"vlan-id",	required_argument,	0, 'v'	},
159 	{"dev",		required_argument,	0, 'd'	},
160 	{"policy",	required_argument,	0, 'P'	},
161 	{"lacp-mode",	required_argument,	0, 'l'	},
162 	{"lacp-timer",	required_argument,	0, 'T'	},
163 	{"unicast",	required_argument,	0, 'u'	},
164 	{"statistics",	no_argument,		0, 's'	},
165 	{"interval",	required_argument,	0, 'i'	},
166 	{"lacp",	no_argument,		0, 'L'	},
167 	{"temporary",	no_argument,		0, 't'	},
168 	{"root-dir",	required_argument,	0, 'r'	},
169 	{"parseable",	no_argument,		0, 'p'	},
170 	{ 0, 0, 0, 0 }
171 };
172 
173 static const struct option prop_longopts[] = {
174 	{"temporary",	no_argument,		0, 't'	},
175 	{"root-dir",	required_argument,	0, 'R'	},
176 	{"prop",	required_argument,	0, 'p'	},
177 	{"parseable",	no_argument,		0, 'c'	},
178 	{"persistent",	no_argument,		0, 'P'	},
179 	{ 0, 0, 0, 0 }
180 };
181 
182 static const struct option wifi_longopts[] = {
183 	{"parseable",	no_argument,		0, 'p'	},
184 	{"output",	required_argument,	0, 'o'	},
185 	{"essid",	required_argument,	0, 'e'	},
186 	{"bsstype",	required_argument,	0, 'b'	},
187 	{"mode",	required_argument,	0, 'm'	},
188 	{"key",		required_argument,	0, 'k'	},
189 	{"sec",		required_argument,	0, 's'	},
190 	{"auth",	required_argument,	0, 'a'	},
191 	{"create-ibss",	required_argument,	0, 'c'	},
192 	{"timeout",	required_argument,	0, 'T'	},
193 	{"all-links",	no_argument,		0, 'a'	},
194 	{"temporary",	no_argument,		0, 't'	},
195 	{"root-dir",	required_argument,	0, 'R'	},
196 	{"persistent",	no_argument,		0, 'P'	},
197 	{"file",	required_argument,	0, 'f'	},
198 	{ 0, 0, 0, 0 }
199 };
200 
201 static char *progname;
202 static sig_atomic_t signalled;
203 
204 static void
205 usage(void)
206 {
207 	(void) fprintf(stderr, gettext("usage:	dladm <subcommand> <args> ...\n"
208 	    "\tshow-link       [-p] [-s [-i <interval>]] [<name>]\n"
209 	    "\tshow-dev        [-p] [-s [-i <interval>]] [<dev>]\n"
210 	    "\n"
211 	    "\tcreate-aggr     [-t] [-R <root-dir>] [-P <policy>] [-l <mode>]\n"
212 	    "\t                [-T <time>] [-u <address>] -d <dev> ... <key>\n"
213 	    "\tmodify-aggr     [-t] [-R <root-dir>] [-P <policy>] [-l <mode>]\n"
214 	    "\t                [-T <time>] [-u <address>] <key>\n"
215 	    "\tdelete-aggr     [-t] [-R <root-dir>] <key>\n"
216 	    "\tadd-aggr        [-t] [-R <root-dir>] -d <dev> ... <key>\n"
217 	    "\tremove-aggr     [-t] [-R <root-dir>] -d <dev> ... <key>\n"
218 	    "\tshow-aggr       [-pL][-s [-i <interval>]] [<key>]\n"
219 	    "\n"
220 	    "\tscan-wifi       [-p] [-o <field>,...] [<name>]\n"
221 	    "\tconnect-wifi    [-e <essid>] [-i <bssid>] [-k <key>,...]"
222 	    " [-s wep|wpa]\n"
223 	    "\t                [-a open|shared] [-b bss|ibss] [-c] [-m a|b|g]\n"
224 	    "\t                [-T <time>] [<name>]\n"
225 	    "\tdisconnect-wifi [-a] [<name>]\n"
226 	    "\tshow-wifi       [-p] [-o <field>,...] [<name>]\n"
227 	    "\n"
228 	    "\tset-linkprop    [-t] [-R <root-dir>]  -p <prop>=<value>[,...]"
229 	    " <name>\n"
230 	    "\treset-linkprop  [-t] [-R <root-dir>] [-p <prop>,...] <name>\n"
231 	    "\tshow-linkprop   [-cP][-p <prop>,...] <name>\n"
232 	    "\n"
233 	    "\tcreate-secobj   [-t] [-R <root-dir>] [-f <file>] -c <class>"
234 	    " <secobj>\n"
235 	    "\tdelete-secobj   [-t] [-R <root-dir>] <secobj>[,...]\n"
236 	    "\tshow-secobj     [-pP][<secobj>,...]\n"));
237 	exit(1);
238 }
239 
240 int
241 main(int argc, char *argv[])
242 {
243 	int	i;
244 	cmd_t	*cmdp;
245 
246 	(void) setlocale(LC_ALL, "");
247 #if !defined(TEXT_DOMAIN)
248 #define	TEXT_DOMAIN "SYS_TEST"
249 #endif
250 	(void) textdomain(TEXT_DOMAIN);
251 
252 	progname = argv[0];
253 
254 	if (argc < 2)
255 		usage();
256 
257 	if (!priv_ineffect(PRIV_SYS_NET_CONFIG) ||
258 	    !priv_ineffect(PRIV_NET_RAWACCESS))
259 		die("insufficient privileges");
260 
261 	for (i = 0; i < sizeof (cmds) / sizeof (cmds[0]); i++) {
262 		cmdp = &cmds[i];
263 		if (strcmp(argv[1], cmdp->c_name) == 0) {
264 			cmdp->c_fn(argc - 1, &argv[1]);
265 			exit(0);
266 		}
267 	}
268 
269 	(void) fprintf(stderr, gettext("%s: unknown subcommand '%s'\n"),
270 	    progname, argv[1]);
271 	usage();
272 
273 	return (0);
274 }
275 
276 static void
277 do_create_aggr(int argc, char *argv[])
278 {
279 	char				option;
280 	int				key;
281 	uint32_t			policy = AGGR_POLICY_L4;
282 	aggr_lacp_mode_t		lacp_mode = AGGR_LACP_OFF;
283 	aggr_lacp_timer_t		lacp_timer = AGGR_LACP_TIMER_SHORT;
284 	dladm_aggr_port_attr_db_t	port[MAXPORT];
285 	uint_t				nport = 0;
286 	uint8_t				mac_addr[ETHERADDRL];
287 	boolean_t			mac_addr_fixed = B_FALSE;
288 	boolean_t			P_arg = B_FALSE;
289 	boolean_t			l_arg = B_FALSE;
290 	boolean_t			t_arg = B_FALSE;
291 	boolean_t			u_arg = B_FALSE;
292 	boolean_t			T_arg = B_FALSE;
293 	char				*altroot = NULL;
294 	dladm_status_t			status;
295 
296 	opterr = 0;
297 	while ((option = getopt_long(argc, argv, ":d:l:P:R:tu:T:",
298 	    longopts, NULL)) != -1) {
299 		switch (option) {
300 		case 'd':
301 			if (nport >= MAXPORT)
302 				die("too many <dev> arguments");
303 
304 			if (strlcpy(port[nport].lp_devname, optarg,
305 			    MAXNAMELEN) >= MAXNAMELEN)
306 				die("device name too long");
307 
308 			nport++;
309 			break;
310 		case 'P':
311 			if (P_arg)
312 				die_optdup(option);
313 
314 			P_arg = B_TRUE;
315 			if (!dladm_aggr_str2policy(optarg, &policy))
316 				die("invalid policy '%s'", optarg);
317 			break;
318 		case 'u':
319 			if (u_arg)
320 				die_optdup(option);
321 
322 			u_arg = B_TRUE;
323 			if (!dladm_aggr_str2macaddr(optarg, &mac_addr_fixed,
324 			    mac_addr))
325 				die("invalid MAC address '%s'", optarg);
326 			break;
327 		case 'l':
328 			if (l_arg)
329 				die_optdup(option);
330 
331 			l_arg = B_TRUE;
332 			if (!dladm_aggr_str2lacpmode(optarg, &lacp_mode))
333 				die("invalid LACP mode '%s'", optarg);
334 			break;
335 		case 'T':
336 			if (T_arg)
337 				die_optdup(option);
338 
339 			T_arg = B_TRUE;
340 			if (!dladm_aggr_str2lacptimer(optarg, &lacp_timer))
341 				die("invalid LACP timer value '%s'", optarg);
342 			break;
343 		case 't':
344 			t_arg = B_TRUE;
345 			break;
346 		case 'R':
347 			altroot = optarg;
348 			break;
349 		default:
350 			die_opterr(optopt, option);
351 			break;
352 		}
353 	}
354 
355 	if (nport == 0)
356 		usage();
357 
358 	/* get key value (required last argument) */
359 	if (optind != (argc-1))
360 		usage();
361 
362 	if (!str2int(argv[optind], &key) || key < 1)
363 		die("invalid key value '%s'", argv[optind]);
364 
365 	status = dladm_aggr_create(key, nport, port, policy, mac_addr_fixed,
366 	    mac_addr, lacp_mode, lacp_timer, t_arg, altroot);
367 	if (status != DLADM_STATUS_OK)
368 		die_dlerr(status, "create operation failed");
369 }
370 
371 static void
372 do_delete_aggr(int argc, char *argv[])
373 {
374 	int			key;
375 	char			option;
376 	boolean_t		t_arg = B_FALSE;
377 	char			*altroot = NULL;
378 	dladm_status_t		status;
379 
380 	opterr = 0;
381 	while ((option = getopt_long(argc, argv, ":R:t", longopts,
382 	    NULL)) != -1) {
383 		switch (option) {
384 		case 't':
385 			t_arg = B_TRUE;
386 			break;
387 		case 'R':
388 			altroot = optarg;
389 			break;
390 		default:
391 			die_opterr(optopt, option);
392 			break;
393 		}
394 	}
395 
396 	/* get key value (required last argument) */
397 	if (optind != (argc-1))
398 		usage();
399 
400 	if (!str2int(argv[optind], &key) || key < 1)
401 		die("invalid key value '%s'", argv[optind]);
402 
403 	status = dladm_aggr_delete(key, t_arg, altroot);
404 	if (status != DLADM_STATUS_OK)
405 		die_dlerr(status, "delete operation failed");
406 }
407 
408 static void
409 do_add_aggr(int argc, char *argv[])
410 {
411 	char				option;
412 	int				key;
413 	dladm_aggr_port_attr_db_t	port[MAXPORT];
414 	uint_t				nport = 0;
415 	boolean_t			t_arg = B_FALSE;
416 	char				*altroot = NULL;
417 	dladm_status_t			status;
418 
419 	opterr = 0;
420 	while ((option = getopt_long(argc, argv, ":d:R:t", longopts,
421 	    NULL)) != -1) {
422 		switch (option) {
423 		case 'd':
424 			if (nport >= MAXPORT)
425 				die("too many <dev> arguments");
426 
427 			if (strlcpy(port[nport].lp_devname, optarg,
428 			    MAXNAMELEN) >= MAXNAMELEN)
429 				die("device name too long");
430 
431 			nport++;
432 			break;
433 		case 't':
434 			t_arg = B_TRUE;
435 			break;
436 		case 'R':
437 			altroot = optarg;
438 			break;
439 		default:
440 			die_opterr(optopt, option);
441 			break;
442 		}
443 	}
444 
445 	if (nport == 0)
446 		usage();
447 
448 	/* get key value (required last argument) */
449 	if (optind != (argc-1))
450 		usage();
451 
452 	if (!str2int(argv[optind], &key) || key < 1)
453 		die("invalid key value '%s'", argv[optind]);
454 
455 	status = dladm_aggr_add(key, nport, port, t_arg, altroot);
456 	if (status != DLADM_STATUS_OK) {
457 		/*
458 		 * checking DLADM_STATUS_NOTSUP is a temporary workaround
459 		 * and should be removed once 6399681 is fixed.
460 		 */
461 		if (status == DLADM_STATUS_NOTSUP) {
462 			(void) fprintf(stderr,
463 			    gettext("%s: add operation failed: %s\n"),
464 			    progname,
465 			    gettext("device capabilities don't match"));
466 			exit(ENOTSUP);
467 		}
468 		die_dlerr(status, "add operation failed");
469 	}
470 }
471 
472 static void
473 do_remove_aggr(int argc, char *argv[])
474 {
475 	char				option;
476 	int				key;
477 	dladm_aggr_port_attr_db_t	port[MAXPORT];
478 	uint_t				nport = 0;
479 	boolean_t			t_arg = B_FALSE;
480 	char				*altroot = NULL;
481 	dladm_status_t			status;
482 
483 	opterr = 0;
484 	while ((option = getopt_long(argc, argv, ":d:R:t",
485 	    longopts, NULL)) != -1) {
486 		switch (option) {
487 		case 'd':
488 			if (nport >= MAXPORT)
489 				die("too many <dev> arguments");
490 
491 			if (strlcpy(port[nport].lp_devname, optarg,
492 			    MAXNAMELEN) >= MAXNAMELEN)
493 				die("device name too long");
494 
495 			nport++;
496 			break;
497 		case 't':
498 			t_arg = B_TRUE;
499 			break;
500 		case 'R':
501 			altroot = optarg;
502 			break;
503 		default:
504 			die_opterr(optopt, option);
505 			break;
506 		}
507 	}
508 
509 	if (nport == 0)
510 		usage();
511 
512 	/* get key value (required last argument) */
513 	if (optind != (argc-1))
514 		usage();
515 
516 	if (!str2int(argv[optind], &key) || key < 1)
517 		die("invalid key value '%s'", argv[optind]);
518 
519 	status = dladm_aggr_remove(key, nport, port, t_arg, altroot);
520 	if (status != DLADM_STATUS_OK)
521 		die_dlerr(status, "remove operation failed");
522 }
523 
524 static void
525 do_modify_aggr(int argc, char *argv[])
526 {
527 	char			option;
528 	int			key;
529 	uint32_t		policy = AGGR_POLICY_L4;
530 	aggr_lacp_mode_t	lacp_mode = AGGR_LACP_OFF;
531 	aggr_lacp_timer_t	lacp_timer = AGGR_LACP_TIMER_SHORT;
532 	uint8_t			mac_addr[ETHERADDRL];
533 	boolean_t		mac_addr_fixed = B_FALSE;
534 	uint8_t			modify_mask = 0;
535 	boolean_t		t_arg = B_FALSE;
536 	char			*altroot = NULL;
537 	dladm_status_t		status;
538 
539 	opterr = 0;
540 	while ((option = getopt_long(argc, argv, ":l:P:R:tu:T:", longopts,
541 	    NULL)) != -1) {
542 		switch (option) {
543 		case 'P':
544 			if (modify_mask & DLADM_AGGR_MODIFY_POLICY)
545 				die_optdup(option);
546 
547 			modify_mask |= DLADM_AGGR_MODIFY_POLICY;
548 
549 			if (!dladm_aggr_str2policy(optarg, &policy))
550 				die("invalid policy '%s'", optarg);
551 			break;
552 		case 'u':
553 			if (modify_mask & DLADM_AGGR_MODIFY_MAC)
554 				die_optdup(option);
555 
556 			modify_mask |= DLADM_AGGR_MODIFY_MAC;
557 
558 			if (!dladm_aggr_str2macaddr(optarg, &mac_addr_fixed,
559 			    mac_addr))
560 				die("invalid MAC address '%s'", optarg);
561 			break;
562 		case 'l':
563 			if (modify_mask & DLADM_AGGR_MODIFY_LACP_MODE)
564 				die_optdup(option);
565 
566 			modify_mask |= DLADM_AGGR_MODIFY_LACP_MODE;
567 
568 			if (!dladm_aggr_str2lacpmode(optarg, &lacp_mode))
569 				die("invalid LACP mode '%s'", optarg);
570 			break;
571 		case 'T':
572 			if (modify_mask & DLADM_AGGR_MODIFY_LACP_TIMER)
573 				die_optdup(option);
574 
575 			modify_mask |= DLADM_AGGR_MODIFY_LACP_TIMER;
576 
577 			if (!dladm_aggr_str2lacptimer(optarg, &lacp_timer))
578 				die("invalid LACP timer value '%s'", optarg);
579 			break;
580 		case 't':
581 			t_arg = B_TRUE;
582 			break;
583 		case 'R':
584 			altroot = optarg;
585 			break;
586 		default:
587 			die_opterr(optopt, option);
588 			break;
589 		}
590 	}
591 
592 	if (modify_mask == 0)
593 		die("at least one of the -PulT options must be specified");
594 
595 	/* get key value (required last argument) */
596 	if (optind != (argc-1))
597 		usage();
598 
599 	if (!str2int(argv[optind], &key) || key < 1)
600 		die("invalid key value '%s'", argv[optind]);
601 
602 	status = dladm_aggr_modify(key, modify_mask, policy, mac_addr_fixed,
603 	    mac_addr, lacp_mode, lacp_timer, t_arg, altroot);
604 	if (status != DLADM_STATUS_OK)
605 		die_dlerr(status, "modify operation failed");
606 }
607 
608 static void
609 do_up_aggr(int argc, char *argv[])
610 {
611 	int		key = 0;
612 	dladm_status_t	status;
613 
614 	/* get aggregation key (optional last argument) */
615 	if (argc == 2) {
616 		if (!str2int(argv[1], &key) || key < 1)
617 			die("invalid key value '%s'", argv[1]);
618 	} else if (argc > 2) {
619 		usage();
620 	}
621 
622 	if ((status = dladm_aggr_up(key, NULL)) != DLADM_STATUS_OK) {
623 		if (key != 0) {
624 			die_dlerr(status, "could not bring up aggregation '%u'",
625 			    key);
626 		} else {
627 			die_dlerr(status, "could not bring aggregations up");
628 		}
629 	}
630 }
631 
632 static void
633 do_down_aggr(int argc, char *argv[])
634 {
635 	dladm_status_t	status;
636 	int		key = 0;
637 
638 	/* get aggregation key (optional last argument) */
639 	if (argc == 2) {
640 		if (!str2int(argv[1], &key) || key < 1)
641 			die("invalid key value '%s'", argv[1]);
642 	} else if (argc > 2) {
643 		usage();
644 	}
645 
646 	if ((status = dladm_aggr_down(key)) != DLADM_STATUS_OK) {
647 		if (key != 0) {
648 			die_dlerr(status,
649 			    "could not bring down aggregation '%u'", key);
650 		} else {
651 			die_dlerr(status, "could not bring down aggregations");
652 		}
653 	}
654 }
655 
656 #define	TYPE_WIDTH	10
657 
658 static void
659 print_link_parseable(const char *name, dladm_attr_t *dap, boolean_t legacy)
660 {
661 	char	type[TYPE_WIDTH];
662 
663 	if (!legacy) {
664 		char	drv[DLPI_LINKNAME_MAX];
665 		uint_t	instance;
666 
667 		if (dap->da_vid != 0) {
668 			(void) snprintf(type, TYPE_WIDTH, "vlan %u",
669 			    dap->da_vid);
670 		} else {
671 			(void) snprintf(type, TYPE_WIDTH, "non-vlan");
672 		}
673 
674 		if (dlpi_parselink(dap->da_dev, drv, &instance) != DLPI_SUCCESS)
675 			return;
676 
677 		if (strncmp(drv, AGGR_DRV, sizeof (AGGR_DRV)) == 0) {
678 			(void) printf("%s type=%s mtu=%d key=%u\n",
679 			    name, type, dap->da_max_sdu, instance);
680 		} else {
681 			(void) printf("%s type=%s mtu=%d device=%s\n",
682 			    name, type, dap->da_max_sdu, dap->da_dev);
683 		}
684 	} else {
685 		(void) printf("%s type=legacy mtu=%d device=%s\n",
686 		    name, dap->da_max_sdu, name);
687 	}
688 }
689 
690 static void
691 print_link(const char *name, dladm_attr_t *dap, boolean_t legacy)
692 {
693 	char	type[TYPE_WIDTH];
694 
695 	if (!legacy) {
696 		char 	drv[DLPI_LINKNAME_MAX];
697 		uint_t	instance;
698 
699 		if (dap->da_vid != 0) {
700 			(void) snprintf(type, TYPE_WIDTH, gettext("vlan %u"),
701 			    dap->da_vid);
702 		} else {
703 			(void) snprintf(type, TYPE_WIDTH, gettext("non-vlan"));
704 		}
705 
706 		if (dlpi_parselink(dap->da_dev, drv, &instance) != DLPI_SUCCESS)
707 			return;
708 		if (strncmp(drv, AGGR_DRV, sizeof (AGGR_DRV)) == 0) {
709 			(void) printf(gettext("%-9s\ttype: %s\tmtu: %d"
710 			    "\taggregation: key %u\n"), name, type,
711 			    dap->da_max_sdu, instance);
712 		} else {
713 			(void) printf(gettext("%-9s\ttype: %s\tmtu: "
714 			    "%d\tdevice: %s\n"), name, type, dap->da_max_sdu,
715 			    dap->da_dev);
716 		}
717 	} else {
718 		(void) printf(gettext("%-9s\ttype: legacy\tmtu: "
719 		    "%d\tdevice: %s\n"), name, dap->da_max_sdu, name);
720 	}
721 }
722 
723 static int
724 get_if_info(const char *name, dladm_attr_t *dlattrp, boolean_t *legacy)
725 {
726 	int	err;
727 
728 	if ((err = dladm_info(name, dlattrp)) == 0) {
729 		*legacy = B_FALSE;
730 	} else if (err < 0 && errno == ENODEV) {
731 		dlpi_handle_t   dh;
732 		dlpi_info_t	dlinfo;
733 
734 		/*
735 		 * A return value of ENODEV means that the specified
736 		 * device is not gldv3.
737 		 */
738 		if (dlpi_open(name, &dh, 0) != DLPI_SUCCESS) {
739 			errno = ENOENT;
740 			return (-1);
741 		}
742 		if (dlpi_info(dh, &dlinfo, 0) != DLPI_SUCCESS) {
743 			dlpi_close(dh);
744 			errno = EINVAL;
745 			return (-1);
746 		}
747 		dlpi_close(dh);
748 		*legacy = B_TRUE;
749 		bzero(dlattrp, sizeof (*dlattrp));
750 		dlattrp->da_max_sdu = dlinfo.di_max_sdu;
751 
752 	} else {
753 		/*
754 		 * If the return value is not ENODEV, this means that
755 		 * user is either passing in a bogus interface name
756 		 * or a vlan interface name that doesn't exist yet.
757 		 */
758 		errno = ENOENT;
759 		return (-1);
760 	}
761 	return (0);
762 }
763 
764 /* ARGSUSED */
765 static void
766 show_link(void *arg, const char *name)
767 {
768 	dladm_attr_t	dlattr;
769 	boolean_t	legacy = B_TRUE;
770 	show_link_state_t *state = (show_link_state_t *)arg;
771 
772 	if (get_if_info(name, &dlattr, &legacy) < 0)
773 		die("invalid link '%s'", name);
774 
775 	if (state->ls_parseable) {
776 		print_link_parseable(name, &dlattr, legacy);
777 	} else {
778 		print_link(name, &dlattr, legacy);
779 	}
780 }
781 
782 static void
783 show_link_stats(void *arg, const char *name)
784 {
785 	show_link_state_t *state = (show_link_state_t *)arg;
786 	pktsum_t stats, diff_stats;
787 
788 	if (state->ls_firstonly) {
789 		if (state->ls_donefirst)
790 			return;
791 		state->ls_donefirst = B_TRUE;
792 	} else {
793 		bzero(&state->ls_prevstats, sizeof (state->ls_prevstats));
794 	}
795 
796 	get_link_stats(name, &stats);
797 	stats_diff(&diff_stats, &stats, &state->ls_prevstats);
798 
799 	(void) printf("%s", name);
800 	(void) printf("\t\t%-10llu", diff_stats.ipackets);
801 	(void) printf("%-12llu", diff_stats.rbytes);
802 	(void) printf("%-8u", diff_stats.ierrors);
803 	(void) printf("%-10llu", diff_stats.opackets);
804 	(void) printf("%-12llu", diff_stats.obytes);
805 	(void) printf("%-8u\n", diff_stats.oerrors);
806 
807 	state->ls_prevstats = stats;
808 }
809 
810 static void
811 dump_grp(dladm_aggr_grp_attr_t *grp, boolean_t parseable)
812 {
813 	char buf[DLADM_STRSIZE];
814 	char addr_str[ETHERADDRL * 3];
815 
816 	if (!parseable) {
817 		(void) printf(gettext("key: %d (0x%04x)"),
818 		    grp->lg_key, grp->lg_key);
819 
820 		(void) printf(gettext("\tpolicy: %s"),
821 		    dladm_aggr_policy2str(grp->lg_policy, buf));
822 
823 		(void) printf(gettext("\taddress: %s (%s)\n"),
824 		    dladm_aggr_macaddr2str(grp->lg_mac, addr_str),
825 		    (grp->lg_mac_fixed) ? gettext("fixed") : gettext("auto"));
826 	} else {
827 		(void) printf("aggr key=%d", grp->lg_key);
828 
829 		(void) printf(" policy=%s",
830 		    dladm_aggr_policy2str(grp->lg_policy, buf));
831 
832 		(void) printf(" address=%s",
833 		    dladm_aggr_macaddr2str(grp->lg_mac, addr_str));
834 
835 		(void) printf(" address-type=%s\n",
836 		    (grp->lg_mac_fixed) ? "fixed" : "auto");
837 	}
838 }
839 
840 static void
841 dump_grp_lacp(dladm_aggr_grp_attr_t *grp, boolean_t parseable)
842 {
843 	char lacp_mode_str[DLADM_STRSIZE];
844 	char lacp_timer_str[DLADM_STRSIZE];
845 
846 	(void) dladm_aggr_lacpmode2str(grp->lg_lacp_mode, lacp_mode_str);
847 	(void) dladm_aggr_lacptimer2str(grp->lg_lacp_timer, lacp_timer_str);
848 
849 	if (!parseable) {
850 		(void) printf(gettext("\t\tLACP mode: %s"), lacp_mode_str);
851 		(void) printf(gettext("\tLACP timer: %s\n"), lacp_timer_str);
852 	} else {
853 		(void) printf(" lacp-mode=%s", lacp_mode_str);
854 		(void) printf(" lacp-timer=%s\n", lacp_timer_str);
855 	}
856 }
857 
858 static void
859 dump_grp_stats(dladm_aggr_grp_attr_t *grp)
860 {
861 	(void) printf("key: %d", grp->lg_key);
862 	(void) printf("\tipackets  rbytes      opackets	 obytes		 ");
863 	(void) printf("%%ipkts	%%opkts\n");
864 }
865 
866 static void
867 dump_ports_lacp_head(void)
868 {
869 	(void) printf(DUMP_LACP_FORMAT, gettext("device"), gettext("activity"),
870 	    gettext("timeout"), gettext("aggregatable"), gettext("sync"),
871 	    gettext("coll"), gettext("dist"), gettext("defaulted"),
872 	    gettext("expired"));
873 }
874 
875 static void
876 dump_ports_head(void)
877 {
878 	(void) printf(gettext("	   device\taddress\t\t	speed\t\tduplex\tlink\t"
879 	    "state\n"));
880 }
881 
882 static void
883 dump_port(dladm_aggr_port_attr_t *port, boolean_t parseable)
884 {
885 	char *dev = port->lp_devname;
886 	char mac_addr[ETHERADDRL * 3];
887 	char buf[DLADM_STRSIZE];
888 
889 	if (!parseable) {
890 		(void) printf("	   %-9s\t%s", dev, dladm_aggr_macaddr2str(
891 		    port->lp_mac, mac_addr));
892 		(void) printf("\t %5uMb", (int)(mac_ifspeed(dev) /
893 		    1000000ull));
894 		(void) printf("\t%s", mac_link_duplex(dev, buf));
895 		(void) printf("\t%s", mac_link_state(dev, buf));
896 		(void) printf("\t%s\n",
897 		    dladm_aggr_portstate2str(port->lp_state, buf));
898 
899 	} else {
900 		(void) printf(" device=%s address=%s", dev,
901 		    dladm_aggr_macaddr2str(port->lp_mac, mac_addr));
902 		(void) printf(" speed=%u", (int)(mac_ifspeed(dev) /
903 		    1000000ull));
904 		(void) printf(" duplex=%s", mac_link_duplex(dev, buf));
905 		(void) printf(" link=%s", mac_link_state(dev, buf));
906 		(void) printf(" port=%s",
907 		    dladm_aggr_portstate2str(port->lp_state, buf));
908 	}
909 }
910 
911 static void
912 dump_port_lacp(dladm_aggr_port_attr_t *port)
913 {
914 	aggr_lacp_state_t *state = &port->lp_lacp_state;
915 
916 	(void) printf(DUMP_LACP_FORMAT,
917 	    port->lp_devname, state->bit.activity ? "active" : "passive",
918 	    state->bit.timeout ? "short" : "long",
919 	    state->bit.aggregation ? "yes" : "no",
920 	    state->bit.sync ? "yes" : "no",
921 	    state->bit.collecting ? "yes" : "no",
922 	    state->bit.distributing ? "yes" : "no",
923 	    state->bit.defaulted ? "yes" : "no",
924 	    state->bit.expired ? "yes" : "no");
925 }
926 
927 static void
928 dump_port_stat(int index, show_grp_state_t *state, pktsum_t *port_stats,
929     pktsum_t *tot_stats)
930 {
931 	pktsum_t	diff_stats;
932 	pktsum_t	*old_stats = &state->gs_prevstats[index];
933 
934 	stats_diff(&diff_stats, port_stats, old_stats);
935 
936 	(void) printf("\t%-10llu", diff_stats.ipackets);
937 	(void) printf("%-12llu", diff_stats.rbytes);
938 	(void) printf("%-10llu", diff_stats.opackets);
939 	(void) printf("%-12llu", diff_stats.obytes);
940 
941 	if (tot_stats->ipackets == 0)
942 		(void) printf("\t-");
943 	else
944 		(void) printf("\t%-6.1f", (double)diff_stats.ipackets/
945 		    (double)tot_stats->ipackets * 100);
946 
947 	if (tot_stats->opackets == 0)
948 		(void) printf("\t-");
949 	else
950 		(void) printf("\t%-6.1f", (double)diff_stats.opackets/
951 		    (double)tot_stats->opackets * 100);
952 
953 	(void) printf("\n");
954 
955 	*old_stats = *port_stats;
956 }
957 
958 static int
959 show_key(void *arg, dladm_aggr_grp_attr_t *grp)
960 {
961 	show_grp_state_t	*state = (show_grp_state_t *)arg;
962 	int			i;
963 	pktsum_t		pktsumtot, port_stat;
964 
965 	if (state->gs_key != 0 && state->gs_key != grp->lg_key)
966 		return (0);
967 	if (state->gs_firstonly) {
968 		if (state->gs_found)
969 			return (0);
970 	} else {
971 		bzero(&state->gs_prevstats, sizeof (state->gs_prevstats));
972 	}
973 
974 	state->gs_found = B_TRUE;
975 
976 	if (state->gs_stats) {
977 		/* show statistics */
978 		dump_grp_stats(grp);
979 
980 		/* sum the ports statistics */
981 		bzero(&pktsumtot, sizeof (pktsumtot));
982 		for (i = 0; i < grp->lg_nports; i++) {
983 			get_mac_stats(grp->lg_ports[i].lp_devname, &port_stat);
984 			stats_total(&pktsumtot, &port_stat,
985 			    &state->gs_prevstats[i]);
986 		}
987 
988 		(void) printf("	   Total");
989 		(void) printf("\t%-10llu", pktsumtot.ipackets);
990 		(void) printf("%-12llu", pktsumtot.rbytes);
991 		(void) printf("%-10llu", pktsumtot.opackets);
992 		(void) printf("%-12llu\n", pktsumtot.obytes);
993 
994 		for (i = 0; i < grp->lg_nports; i++) {
995 			get_mac_stats(grp->lg_ports[i].lp_devname, &port_stat);
996 			(void) printf("	   %s", grp->lg_ports[i].lp_devname);
997 			dump_port_stat(i, state, &port_stat, &pktsumtot);
998 		}
999 	} else if (state->gs_lacp) {
1000 		/* show LACP info */
1001 		dump_grp(grp, state->gs_parseable);
1002 		dump_grp_lacp(grp, state->gs_parseable);
1003 		dump_ports_lacp_head();
1004 		for (i = 0; i < grp->lg_nports; i++)
1005 			dump_port_lacp(&grp->lg_ports[i]);
1006 	} else {
1007 		dump_grp(grp, state->gs_parseable);
1008 		if (!state->gs_parseable)
1009 			dump_ports_head();
1010 		for (i = 0; i < grp->lg_nports; i++) {
1011 			if (state->gs_parseable)
1012 				(void) printf("dev key=%d", grp->lg_key);
1013 			dump_port(&grp->lg_ports[i], state->gs_parseable);
1014 			if (state->gs_parseable)
1015 				(void) printf("\n");
1016 		}
1017 	}
1018 
1019 	return (0);
1020 }
1021 
1022 static int
1023 kstat_value(kstat_t *ksp, const char *name, uint8_t type, void *buf)
1024 {
1025 	kstat_named_t	*knp;
1026 
1027 	if ((knp = kstat_data_lookup(ksp, (char *)name)) == NULL)
1028 		return (-1);
1029 
1030 	if (knp->data_type != type)
1031 		return (-1);
1032 
1033 	switch (type) {
1034 	case KSTAT_DATA_UINT64:
1035 		*(uint64_t *)buf = knp->value.ui64;
1036 		break;
1037 	case KSTAT_DATA_UINT32:
1038 		*(uint32_t *)buf = knp->value.ui32;
1039 		break;
1040 	default:
1041 		return (-1);
1042 	}
1043 
1044 	return (0);
1045 }
1046 
1047 static void
1048 show_dev(void *arg, const char *dev)
1049 {
1050 	show_mac_state_t *state = (show_mac_state_t *)arg;
1051 	char buf[DLADM_STRSIZE];
1052 
1053 	(void) printf("%s", dev);
1054 
1055 	if (!state->ms_parseable) {
1056 		(void) printf(gettext("\t\tlink: %s"),
1057 		    mac_link_state(dev, buf));
1058 		(void) printf(gettext("\tspeed: %5uMb"),
1059 		    (unsigned int)(mac_ifspeed(dev) / 1000000ull));
1060 		(void) printf(gettext("\tduplex: %s\n"),
1061 		    mac_link_duplex(dev, buf));
1062 	} else {
1063 		(void) printf(" link=%s", mac_link_state(dev, buf));
1064 		(void) printf(" speed=%u",
1065 		    (unsigned int)(mac_ifspeed(dev) / 1000000ull));
1066 		(void) printf(" duplex=%s\n", mac_link_duplex(dev, buf));
1067 	}
1068 }
1069 
1070 /*ARGSUSED*/
1071 static void
1072 show_dev_stats(void *arg, const char *dev)
1073 {
1074 	show_mac_state_t *state = (show_mac_state_t *)arg;
1075 	pktsum_t stats, diff_stats;
1076 
1077 	if (state->ms_firstonly) {
1078 		if (state->ms_donefirst)
1079 			return;
1080 		state->ms_donefirst = B_TRUE;
1081 	} else {
1082 		bzero(&state->ms_prevstats, sizeof (state->ms_prevstats));
1083 	}
1084 
1085 	get_mac_stats(dev, &stats);
1086 	stats_diff(&diff_stats, &stats, &state->ms_prevstats);
1087 
1088 	(void) printf("%s", dev);
1089 	(void) printf("\t\t%-10llu", diff_stats.ipackets);
1090 	(void) printf("%-12llu", diff_stats.rbytes);
1091 	(void) printf("%-8u", diff_stats.ierrors);
1092 	(void) printf("%-10llu", diff_stats.opackets);
1093 	(void) printf("%-12llu", diff_stats.obytes);
1094 	(void) printf("%-8u\n", diff_stats.oerrors);
1095 
1096 	state->ms_prevstats = stats;
1097 }
1098 
1099 static void
1100 do_show_link(int argc, char *argv[])
1101 {
1102 	char		*name = NULL;
1103 	int		option;
1104 	boolean_t	s_arg = B_FALSE;
1105 	boolean_t	i_arg = B_FALSE;
1106 	int		interval = 0;
1107 	show_link_state_t state;
1108 
1109 	state.ls_stats = B_FALSE;
1110 	state.ls_parseable = B_FALSE;
1111 
1112 	opterr = 0;
1113 	while ((option = getopt_long(argc, argv, ":psi:",
1114 	    longopts, NULL)) != -1) {
1115 		switch (option) {
1116 		case 'p':
1117 			state.ls_parseable = B_TRUE;
1118 			break;
1119 		case 's':
1120 			if (s_arg)
1121 				die_optdup(option);
1122 
1123 			s_arg = B_TRUE;
1124 			break;
1125 		case 'i':
1126 			if (i_arg)
1127 				die_optdup(option);
1128 
1129 			i_arg = B_TRUE;
1130 			if (!str2int(optarg, &interval) || interval == 0)
1131 				die("invalid interval value '%s'", optarg);
1132 			break;
1133 		default:
1134 			die_opterr(optopt, option);
1135 			break;
1136 		}
1137 	}
1138 
1139 	if (i_arg && !s_arg)
1140 		die("the option -i can be used only with -s");
1141 
1142 	/* get link name (optional last argument) */
1143 	if (optind == (argc-1))
1144 		name = argv[optind];
1145 	else if (optind != argc)
1146 		usage();
1147 
1148 	if (s_arg) {
1149 		link_stats(name, interval);
1150 		return;
1151 	}
1152 
1153 	if (name == NULL) {
1154 		(void) dladm_walk(show_link, &state);
1155 	} else {
1156 		show_link(&state, name);
1157 	}
1158 }
1159 
1160 static void
1161 do_show_aggr(int argc, char *argv[])
1162 {
1163 	int			option;
1164 	int			key = 0;
1165 	boolean_t		L_arg = B_FALSE;
1166 	boolean_t		s_arg = B_FALSE;
1167 	boolean_t		i_arg = B_FALSE;
1168 	show_grp_state_t	state;
1169 	int			interval = 0;
1170 
1171 	state.gs_stats = B_FALSE;
1172 	state.gs_lacp = B_FALSE;
1173 	state.gs_parseable = B_FALSE;
1174 
1175 	opterr = 0;
1176 	while ((option = getopt_long(argc, argv, ":Lpsi:",
1177 	    longopts, NULL)) != -1) {
1178 		switch (option) {
1179 		case 'L':
1180 			if (L_arg)
1181 				die_optdup(option);
1182 
1183 			if (s_arg || i_arg) {
1184 				die("the option -L cannot be used with -i "
1185 				    "or -s");
1186 			}
1187 
1188 			L_arg = B_TRUE;
1189 			state.gs_lacp = B_TRUE;
1190 			break;
1191 		case 'p':
1192 			state.gs_parseable = B_TRUE;
1193 			break;
1194 		case 's':
1195 			if (s_arg)
1196 				die_optdup(option);
1197 
1198 			if (L_arg)
1199 				die("the option -s cannot be used with -L");
1200 
1201 			s_arg = B_TRUE;
1202 			break;
1203 		case 'i':
1204 			if (i_arg)
1205 				die_optdup(option);
1206 
1207 			if (L_arg)
1208 				die("the option -i cannot be used with -L");
1209 
1210 			i_arg = B_TRUE;
1211 			if (!str2int(optarg, &interval) || interval == 0)
1212 				die("invalid interval value '%s'", optarg);
1213 			break;
1214 		default:
1215 			die_opterr(optopt, option);
1216 			break;
1217 		}
1218 	}
1219 
1220 	if (i_arg && !s_arg)
1221 		die("the option -i can be used only with -s");
1222 
1223 	/* get aggregation key (optional last argument) */
1224 	if (optind == (argc-1)) {
1225 		if (!str2int(argv[optind], &key) || key < 1)
1226 			die("invalid key value '%s'", argv[optind]);
1227 	} else if (optind != argc) {
1228 		usage();
1229 	}
1230 
1231 	if (s_arg) {
1232 		aggr_stats(key, interval);
1233 		return;
1234 	}
1235 
1236 	state.gs_key = key;
1237 	state.gs_found = B_FALSE;
1238 
1239 	(void) dladm_aggr_walk(show_key, &state);
1240 
1241 	if (key != 0 && !state.gs_found)
1242 		die("non-existent aggregation key '%u'", key);
1243 }
1244 
1245 static void
1246 do_show_dev(int argc, char *argv[])
1247 {
1248 	int		option;
1249 	char		*dev = NULL;
1250 	boolean_t	s_arg = B_FALSE;
1251 	boolean_t	i_arg = B_FALSE;
1252 	int		interval = 0;
1253 	show_mac_state_t state;
1254 
1255 	state.ms_parseable = B_FALSE;
1256 
1257 	opterr = 0;
1258 	while ((option = getopt_long(argc, argv, ":psi:",
1259 	    longopts, NULL)) != -1) {
1260 		switch (option) {
1261 		case 'p':
1262 			state.ms_parseable = B_TRUE;
1263 			break;
1264 		case 's':
1265 			if (s_arg)
1266 				die_optdup(option);
1267 
1268 			s_arg = B_TRUE;
1269 			break;
1270 		case 'i':
1271 			if (i_arg)
1272 				die_optdup(option);
1273 
1274 			i_arg = B_TRUE;
1275 			if (!str2int(optarg, &interval) || interval == 0)
1276 				die("invalid interval value '%s'", optarg);
1277 			break;
1278 		default:
1279 			die_opterr(optopt, option);
1280 			break;
1281 		}
1282 	}
1283 
1284 	if (i_arg && !s_arg)
1285 		die("the option -i can be used only with -s");
1286 
1287 	/* get dev name (optional last argument) */
1288 	if (optind == (argc-1))
1289 		dev = argv[optind];
1290 	else if (optind != argc)
1291 		usage();
1292 
1293 	if (dev != NULL) {
1294 		uint_t		ppa;
1295 		char		drv[DLPI_LINKNAME_MAX];
1296 		dladm_attr_t	dlattr;
1297 		boolean_t	legacy;
1298 
1299 		/*
1300 		 * Check for invalid devices.
1301 		 * aggregations and vlans are not considered devices.
1302 		 */
1303 		if (dlpi_parselink(dev, drv, &ppa) != DLPI_SUCCESS ||
1304 		    strcmp(drv, "aggr") == 0 || ppa >= 1000 ||
1305 		    get_if_info(dev, &dlattr, &legacy) < 0)
1306 			die("invalid device '%s'", dev);
1307 	}
1308 
1309 	if (s_arg) {
1310 		dev_stats(dev, interval);
1311 		return;
1312 	}
1313 
1314 	if (dev == NULL)
1315 		(void) dladm_mac_walk(show_dev, &state);
1316 	else
1317 		show_dev(&state, dev);
1318 }
1319 
1320 /* ARGSUSED */
1321 static void
1322 link_stats(const char *link, uint_t interval)
1323 {
1324 	dladm_attr_t		dlattr;
1325 	boolean_t		legacy;
1326 	show_link_state_t	state;
1327 
1328 	if (link != NULL && get_if_info(link, &dlattr, &legacy) < 0)
1329 		die("invalid link '%s'", link);
1330 
1331 	bzero(&state, sizeof (state));
1332 
1333 	/*
1334 	 * If an interval is specified, continuously show the stats
1335 	 * only for the first MAC port.
1336 	 */
1337 	state.ls_firstonly = (interval != 0);
1338 
1339 	for (;;) {
1340 		(void) printf("\t\tipackets  rbytes	 ierrors ");
1341 		(void) printf("opackets	 obytes	     oerrors\n");
1342 
1343 		state.ls_donefirst = B_FALSE;
1344 		if (link == NULL)
1345 			(void) dladm_walk(show_link_stats, &state);
1346 		else
1347 			show_link_stats(&state, link);
1348 
1349 		if (interval == 0)
1350 			break;
1351 
1352 		(void) sleep(interval);
1353 	}
1354 }
1355 
1356 /* ARGSUSED */
1357 static void
1358 aggr_stats(uint32_t key, uint_t interval)
1359 {
1360 	show_grp_state_t state;
1361 
1362 	bzero(&state, sizeof (state));
1363 	state.gs_stats = B_TRUE;
1364 	state.gs_key = key;
1365 
1366 	/*
1367 	 * If an interval is specified, continuously show the stats
1368 	 * only for the first group.
1369 	 */
1370 	state.gs_firstonly = (interval != 0);
1371 
1372 	for (;;) {
1373 		state.gs_found = B_FALSE;
1374 		(void) dladm_aggr_walk(show_key, &state);
1375 		if (state.gs_key != 0 && !state.gs_found)
1376 			die("non-existent aggregation key '%u'", key);
1377 
1378 		if (interval == 0)
1379 			break;
1380 
1381 		(void) sleep(interval);
1382 	}
1383 }
1384 
1385 /* ARGSUSED */
1386 static void
1387 dev_stats(const char *dev, uint32_t interval)
1388 {
1389 	show_mac_state_t state;
1390 
1391 	bzero(&state, sizeof (state));
1392 
1393 	/*
1394 	 * If an interval is specified, continuously show the stats
1395 	 * only for the first MAC port.
1396 	 */
1397 	state.ms_firstonly = (interval != 0);
1398 
1399 	for (;;) {
1400 
1401 		(void) printf("\t\tipackets  rbytes	 ierrors ");
1402 		(void) printf("opackets	 obytes	     oerrors\n");
1403 
1404 		state.ms_donefirst = B_FALSE;
1405 		if (dev == NULL)
1406 			(void) dladm_mac_walk(show_dev_stats, &state);
1407 		else
1408 			show_dev_stats(&state, dev);
1409 
1410 		if (interval == 0)
1411 			break;
1412 
1413 		(void) sleep(interval);
1414 	}
1415 }
1416 
1417 /* accumulate stats (s1 += (s2 - s3)) */
1418 static void
1419 stats_total(pktsum_t *s1, pktsum_t *s2, pktsum_t *s3)
1420 {
1421 	s1->ipackets += (s2->ipackets - s3->ipackets);
1422 	s1->opackets += (s2->opackets - s3->opackets);
1423 	s1->rbytes += (s2->rbytes - s3->rbytes);
1424 	s1->obytes += (s2->obytes - s3->obytes);
1425 	s1->ierrors += (s2->ierrors - s3->ierrors);
1426 	s1->oerrors += (s2->oerrors - s3->oerrors);
1427 }
1428 
1429 /* compute stats differences (s1 = s2 - s3) */
1430 static void
1431 stats_diff(pktsum_t *s1, pktsum_t *s2, pktsum_t *s3)
1432 {
1433 	s1->ipackets = s2->ipackets - s3->ipackets;
1434 	s1->opackets = s2->opackets - s3->opackets;
1435 	s1->rbytes = s2->rbytes - s3->rbytes;
1436 	s1->obytes = s2->obytes - s3->obytes;
1437 	s1->ierrors = s2->ierrors - s3->ierrors;
1438 	s1->oerrors = s2->oerrors - s3->oerrors;
1439 }
1440 
1441 /*
1442  * In the following routines, we do the first kstat_lookup() assuming that
1443  * the device is gldv3-based and that the kstat name is the one passed in
1444  * as the "name" argument. If the lookup fails, we redo the kstat_lookup()
1445  * omitting the kstat name. This second lookup is needed for getting kstats
1446  * from legacy devices. This can fail too if the device is not attached or
1447  * the device is legacy and doesn't export the kstats we need.
1448  */
1449 static void
1450 get_stats(char *module, int instance, char *name, pktsum_t *stats)
1451 {
1452 	kstat_ctl_t	*kcp;
1453 	kstat_t		*ksp;
1454 
1455 	if ((kcp = kstat_open()) == NULL) {
1456 		warn("kstat open operation failed");
1457 		return;
1458 	}
1459 
1460 	if ((ksp = kstat_lookup(kcp, module, instance, name)) == NULL &&
1461 	    (ksp = kstat_lookup(kcp, module, instance, NULL)) == NULL) {
1462 		/*
1463 		 * The kstat query could fail if the underlying MAC
1464 		 * driver was already detached.
1465 		 */
1466 		(void) kstat_close(kcp);
1467 		return;
1468 	}
1469 
1470 	if (kstat_read(kcp, ksp, NULL) == -1)
1471 		goto bail;
1472 
1473 	if (kstat_value(ksp, "ipackets64", KSTAT_DATA_UINT64,
1474 	    &stats->ipackets) < 0)
1475 		goto bail;
1476 
1477 	if (kstat_value(ksp, "opackets64", KSTAT_DATA_UINT64,
1478 	    &stats->opackets) < 0)
1479 		goto bail;
1480 
1481 	if (kstat_value(ksp, "rbytes64", KSTAT_DATA_UINT64,
1482 	    &stats->rbytes) < 0)
1483 		goto bail;
1484 
1485 	if (kstat_value(ksp, "obytes64", KSTAT_DATA_UINT64,
1486 	    &stats->obytes) < 0)
1487 		goto bail;
1488 
1489 	if (kstat_value(ksp, "ierrors", KSTAT_DATA_UINT32,
1490 	    &stats->ierrors) < 0)
1491 		goto bail;
1492 
1493 	if (kstat_value(ksp, "oerrors", KSTAT_DATA_UINT32,
1494 	    &stats->oerrors) < 0)
1495 		goto bail;
1496 
1497 	(void) kstat_close(kcp);
1498 	return;
1499 
1500 bail:
1501 	(void) kstat_close(kcp);
1502 }
1503 
1504 static void
1505 get_mac_stats(const char *dev, pktsum_t *stats)
1506 {
1507 	char	module[DLPI_LINKNAME_MAX];
1508 	uint_t	instance;
1509 
1510 	if (dlpi_parselink(dev, module, &instance) != DLPI_SUCCESS)
1511 		return;
1512 	bzero(stats, sizeof (*stats));
1513 	get_stats(module, instance, "mac", stats);
1514 }
1515 
1516 static void
1517 get_link_stats(const char *link, pktsum_t *stats)
1518 {
1519 	char	module[DLPI_LINKNAME_MAX];
1520 	uint_t	instance;
1521 
1522 	if (dlpi_parselink(link, module, &instance) != DLPI_SUCCESS)
1523 		return;
1524 	bzero(stats, sizeof (*stats));
1525 	get_stats(module, instance, (char *)link, stats);
1526 }
1527 
1528 static int
1529 get_single_mac_stat(const char *dev, const char *name, uint8_t type,
1530     void *val)
1531 {
1532 	char		module[DLPI_LINKNAME_MAX];
1533 	uint_t		instance;
1534 	kstat_ctl_t	*kcp;
1535 	kstat_t		*ksp;
1536 
1537 	if (dlpi_parselink(dev, module, &instance) != DLPI_SUCCESS)
1538 		return (-1);
1539 
1540 	if ((kcp = kstat_open()) == NULL) {
1541 		warn("kstat open operation failed");
1542 		return (-1);
1543 	}
1544 
1545 	if ((ksp = kstat_lookup(kcp, module, instance, "mac")) == NULL &&
1546 	    (ksp = kstat_lookup(kcp, module, instance, NULL)) == NULL) {
1547 		/*
1548 		 * The kstat query could fail if the underlying MAC
1549 		 * driver was already detached.
1550 		 */
1551 		goto bail;
1552 	}
1553 
1554 	if (kstat_read(kcp, ksp, NULL) == -1) {
1555 		warn("kstat read failed");
1556 		goto bail;
1557 	}
1558 
1559 	if (kstat_value(ksp, name, type, val) < 0)
1560 		goto bail;
1561 
1562 	(void) kstat_close(kcp);
1563 	return (0);
1564 
1565 bail:
1566 	(void) kstat_close(kcp);
1567 	return (-1);
1568 }
1569 
1570 static uint64_t
1571 mac_ifspeed(const char *dev)
1572 {
1573 	uint64_t ifspeed = 0;
1574 
1575 	(void) get_single_mac_stat(dev, "ifspeed", KSTAT_DATA_UINT64, &ifspeed);
1576 	return (ifspeed);
1577 }
1578 
1579 static const char *
1580 mac_link_state(const char *dev, char *buf)
1581 {
1582 	link_state_t	link_state;
1583 
1584 	if (get_single_mac_stat(dev, "link_state", KSTAT_DATA_UINT32,
1585 	    &link_state) != 0) {
1586 		(void) strlcpy(buf, "unknown", DLADM_STRSIZE);
1587 		return (buf);
1588 	}
1589 
1590 	return (dladm_linkstate2str(link_state, buf));
1591 }
1592 
1593 static const char *
1594 mac_link_duplex(const char *dev, char *buf)
1595 {
1596 	link_duplex_t	link_duplex;
1597 
1598 	if (get_single_mac_stat(dev, "link_duplex", KSTAT_DATA_UINT32,
1599 	    &link_duplex) != 0) {
1600 		(void) strlcpy(buf, "unknown", DLADM_STRSIZE);
1601 		return (buf);
1602 	}
1603 
1604 	return (dladm_linkduplex2str(link_duplex, buf));
1605 }
1606 
1607 #define	WIFI_CMD_SCAN	0x00000001
1608 #define	WIFI_CMD_SHOW	0x00000002
1609 #define	WIFI_CMD_ALL	(WIFI_CMD_SCAN | WIFI_CMD_SHOW)
1610 typedef struct wifi_field {
1611 	const char	*wf_name;
1612 	const char	*wf_header;
1613 	uint_t		wf_width;
1614 	uint_t		wf_mask;
1615 	uint_t		wf_cmdtype;
1616 } wifi_field_t;
1617 
1618 static wifi_field_t wifi_fields[] = {
1619 { "link",	"LINK",		10, 0,				WIFI_CMD_ALL},
1620 { "essid",	"ESSID",	19, DLADM_WLAN_ATTR_ESSID,	WIFI_CMD_ALL},
1621 { "bssid",	"BSSID/IBSSID", 17, DLADM_WLAN_ATTR_BSSID,	WIFI_CMD_ALL},
1622 { "ibssid",	"BSSID/IBSSID", 17, DLADM_WLAN_ATTR_BSSID,	WIFI_CMD_ALL},
1623 { "mode",	"MODE",		6,  DLADM_WLAN_ATTR_MODE,	WIFI_CMD_ALL},
1624 { "speed",	"SPEED",	6,  DLADM_WLAN_ATTR_SPEED,	WIFI_CMD_ALL},
1625 { "auth",	"AUTH",		8,  DLADM_WLAN_ATTR_AUTH,	WIFI_CMD_SHOW},
1626 { "bsstype",	"BSSTYPE",	8,  DLADM_WLAN_ATTR_BSSTYPE,	WIFI_CMD_ALL},
1627 { "sec",	"SEC",		6,  DLADM_WLAN_ATTR_SECMODE,	WIFI_CMD_ALL},
1628 { "status",	"STATUS",	17, DLADM_WLAN_LINKATTR_STATUS,	WIFI_CMD_SHOW},
1629 { "strength",	"STRENGTH",	10, DLADM_WLAN_ATTR_STRENGTH,	WIFI_CMD_ALL}}
1630 ;
1631 
1632 static char *all_scan_wifi_fields =
1633 	"link,essid,bssid,sec,strength,mode,speed,bsstype";
1634 static char *all_show_wifi_fields =
1635 	"link,status,essid,sec,strength,mode,speed,auth,bssid,bsstype";
1636 static char *def_scan_wifi_fields =
1637 	"link,essid,bssid,sec,strength,mode,speed";
1638 static char *def_show_wifi_fields =
1639 	"link,status,essid,sec,strength,mode,speed";
1640 
1641 #define	WIFI_MAX_FIELDS		(sizeof (wifi_fields) / sizeof (wifi_field_t))
1642 #define	WIFI_MAX_FIELD_LEN	32
1643 
1644 typedef struct {
1645 	char	*s_buf;
1646 	char	**s_fields;	/* array of pointer to the fields in s_buf */
1647 	uint_t	s_nfields;	/* the number of fields in s_buf */
1648 } split_t;
1649 
1650 /*
1651  * Free the split_t structure pointed to by `sp'.
1652  */
1653 static void
1654 splitfree(split_t *sp)
1655 {
1656 	free(sp->s_buf);
1657 	free(sp->s_fields);
1658 	free(sp);
1659 }
1660 
1661 /*
1662  * Split `str' into at most `maxfields' fields, each field at most `maxlen' in
1663  * length.  Return a pointer to a split_t containing the split fields, or NULL
1664  * on failure.
1665  */
1666 static split_t *
1667 split(const char *str, uint_t maxfields, uint_t maxlen)
1668 {
1669 	char	*field, *token, *lasts = NULL;
1670 	split_t	*sp;
1671 
1672 	if (*str == '\0' || maxfields == 0 || maxlen == 0)
1673 		return (NULL);
1674 
1675 	sp = calloc(sizeof (split_t), 1);
1676 	if (sp == NULL)
1677 		return (NULL);
1678 
1679 	sp->s_buf = strdup(str);
1680 	sp->s_fields = malloc(sizeof (char *) * maxfields);
1681 	if (sp->s_buf == NULL || sp->s_fields == NULL)
1682 		goto fail;
1683 
1684 	token = sp->s_buf;
1685 	while ((field = strtok_r(token, ",", &lasts)) != NULL) {
1686 		if (sp->s_nfields == maxfields || strlen(field) > maxlen)
1687 			goto fail;
1688 		token = NULL;
1689 		sp->s_fields[sp->s_nfields++] = field;
1690 	}
1691 	return (sp);
1692 fail:
1693 	splitfree(sp);
1694 	return (NULL);
1695 }
1696 
1697 static int
1698 parse_wifi_fields(char *str, wifi_field_t ***fields, uint_t *countp,
1699     uint_t cmdtype)
1700 {
1701 	uint_t		i, j;
1702 	wifi_field_t	**wf = NULL;
1703 	split_t		*sp;
1704 	boolean_t	good_match = B_FALSE;
1705 
1706 	if (cmdtype == WIFI_CMD_SCAN) {
1707 		if (str == NULL)
1708 			str = def_scan_wifi_fields;
1709 		if (strcasecmp(str, "all") == 0)
1710 			str = all_scan_wifi_fields;
1711 	} else if (cmdtype == WIFI_CMD_SHOW) {
1712 		if (str == NULL)
1713 			str = def_show_wifi_fields;
1714 		if (strcasecmp(str, "all") == 0)
1715 			str = all_show_wifi_fields;
1716 	} else {
1717 		return (-1);
1718 	}
1719 
1720 	sp = split(str, WIFI_MAX_FIELDS, WIFI_MAX_FIELD_LEN);
1721 	if (sp == NULL)
1722 		return (-1);
1723 
1724 	wf = malloc(sp->s_nfields * sizeof (wifi_field_t *));
1725 	if (wf == NULL)
1726 		goto fail;
1727 
1728 	for (i = 0; i < sp->s_nfields; i++) {
1729 		for (j = 0; j < WIFI_MAX_FIELDS; j++) {
1730 			if (strcasecmp(sp->s_fields[i],
1731 			    wifi_fields[j].wf_name) == 0) {
1732 				good_match = wifi_fields[j].
1733 				    wf_cmdtype & cmdtype;
1734 				break;
1735 			}
1736 		}
1737 		if (!good_match)
1738 			goto fail;
1739 
1740 		good_match = B_FALSE;
1741 		wf[i] = &wifi_fields[j];
1742 	}
1743 	*countp = i;
1744 	*fields = wf;
1745 	splitfree(sp);
1746 	return (0);
1747 fail:
1748 	free(wf);
1749 	splitfree(sp);
1750 	return (-1);
1751 }
1752 
1753 typedef struct print_wifi_state {
1754 	const char	*ws_link;
1755 	boolean_t	ws_parseable;
1756 	boolean_t	ws_header;
1757 	wifi_field_t	**ws_fields;
1758 	uint_t		ws_nfields;
1759 	boolean_t	ws_lastfield;
1760 	uint_t		ws_overflow;
1761 } print_wifi_state_t;
1762 
1763 static void
1764 print_wifi_head(print_wifi_state_t *statep)
1765 {
1766 	int		i;
1767 	wifi_field_t	*wfp;
1768 
1769 	for (i = 0; i < statep->ws_nfields; i++) {
1770 		wfp = statep->ws_fields[i];
1771 		if (i + 1 < statep->ws_nfields)
1772 			(void) printf("%-*s ", wfp->wf_width, wfp->wf_header);
1773 		else
1774 			(void) printf("%s", wfp->wf_header);
1775 	}
1776 	(void) printf("\n");
1777 }
1778 
1779 static void
1780 print_wifi_field(print_wifi_state_t *statep, wifi_field_t *wfp,
1781     const char *value)
1782 {
1783 	uint_t	width = wfp->wf_width;
1784 	uint_t	valwidth = strlen(value);
1785 	uint_t	compress;
1786 
1787 	if (statep->ws_parseable) {
1788 		(void) printf("%s=\"%s\"", wfp->wf_header, value);
1789 	} else {
1790 		if (value[0] == '\0')
1791 			value = "--";
1792 		if (statep->ws_lastfield) {
1793 			(void) printf("%s", value);
1794 			return;
1795 		}
1796 
1797 		if (valwidth > width) {
1798 			statep->ws_overflow += valwidth - width;
1799 		} else if (valwidth < width && statep->ws_overflow > 0) {
1800 			compress = min(statep->ws_overflow, width - valwidth);
1801 			statep->ws_overflow -= compress;
1802 			width -= compress;
1803 		}
1804 		(void) printf("%-*s", width, value);
1805 	}
1806 
1807 	if (!statep->ws_lastfield)
1808 		(void) putchar(' ');
1809 }
1810 
1811 static void
1812 print_wlan_attr(print_wifi_state_t *statep, wifi_field_t *wfp,
1813     dladm_wlan_attr_t *attrp)
1814 {
1815 	char		buf[DLADM_STRSIZE];
1816 	const char	*str = "";
1817 
1818 	if (wfp->wf_mask == 0) {
1819 		print_wifi_field(statep, wfp, statep->ws_link);
1820 		return;
1821 	}
1822 
1823 	if ((wfp->wf_mask & attrp->wa_valid) == 0) {
1824 		print_wifi_field(statep, wfp, "");
1825 		return;
1826 	}
1827 
1828 	switch (wfp->wf_mask) {
1829 	case DLADM_WLAN_ATTR_ESSID:
1830 		str = dladm_wlan_essid2str(&attrp->wa_essid, buf);
1831 		break;
1832 	case DLADM_WLAN_ATTR_BSSID:
1833 		str = dladm_wlan_bssid2str(&attrp->wa_bssid, buf);
1834 		break;
1835 	case DLADM_WLAN_ATTR_SECMODE:
1836 		str = dladm_wlan_secmode2str(&attrp->wa_secmode, buf);
1837 		break;
1838 	case DLADM_WLAN_ATTR_STRENGTH:
1839 		str = dladm_wlan_strength2str(&attrp->wa_strength, buf);
1840 		break;
1841 	case DLADM_WLAN_ATTR_MODE:
1842 		str = dladm_wlan_mode2str(&attrp->wa_mode, buf);
1843 		break;
1844 	case DLADM_WLAN_ATTR_SPEED:
1845 		str = dladm_wlan_speed2str(&attrp->wa_speed, buf);
1846 		(void) strlcat(buf, "Mb", sizeof (buf));
1847 		break;
1848 	case DLADM_WLAN_ATTR_AUTH:
1849 		str = dladm_wlan_auth2str(&attrp->wa_auth, buf);
1850 		break;
1851 	case DLADM_WLAN_ATTR_BSSTYPE:
1852 		str = dladm_wlan_bsstype2str(&attrp->wa_bsstype, buf);
1853 		break;
1854 	}
1855 
1856 	print_wifi_field(statep, wfp, str);
1857 }
1858 
1859 static boolean_t
1860 print_scan_results(void *arg, dladm_wlan_attr_t *attrp)
1861 {
1862 	print_wifi_state_t	*statep = arg;
1863 	int			i;
1864 
1865 	if (statep->ws_header) {
1866 		statep->ws_header = B_FALSE;
1867 		if (!statep->ws_parseable)
1868 			print_wifi_head(statep);
1869 	}
1870 
1871 	statep->ws_overflow = 0;
1872 	for (i = 0; i < statep->ws_nfields; i++) {
1873 		statep->ws_lastfield = (i + 1 == statep->ws_nfields);
1874 		print_wlan_attr(statep, statep->ws_fields[i], attrp);
1875 	}
1876 	(void) putchar('\n');
1877 	return (B_TRUE);
1878 }
1879 
1880 static boolean_t
1881 scan_wifi(void *arg, const char *link)
1882 {
1883 	print_wifi_state_t	*statep = arg;
1884 	dladm_status_t		status;
1885 
1886 	statep->ws_link = link;
1887 	status = dladm_wlan_scan(link, statep, print_scan_results);
1888 	if (status != DLADM_STATUS_OK)
1889 		die_dlerr(status, "cannot scan link '%s'", link);
1890 
1891 	return (B_TRUE);
1892 }
1893 
1894 static void
1895 print_link_attr(print_wifi_state_t *statep, wifi_field_t *wfp,
1896     dladm_wlan_linkattr_t *attrp)
1897 {
1898 	char		buf[DLADM_STRSIZE];
1899 	const char	*str = "";
1900 
1901 	if (strcmp(wfp->wf_name, "status") == 0) {
1902 		if ((wfp->wf_mask & attrp->la_valid) != 0)
1903 			str = dladm_wlan_linkstatus2str(&attrp->la_status, buf);
1904 		print_wifi_field(statep, wfp, str);
1905 		return;
1906 	}
1907 	print_wlan_attr(statep, wfp, &attrp->la_wlan_attr);
1908 }
1909 
1910 static boolean_t
1911 show_wifi(void *arg, const char *link)
1912 {
1913 	int			i;
1914 	print_wifi_state_t	*statep = arg;
1915 	dladm_wlan_linkattr_t	attr;
1916 	dladm_status_t		status;
1917 
1918 	status = dladm_wlan_get_linkattr(link, &attr);
1919 	if (status != DLADM_STATUS_OK)
1920 		die_dlerr(status, "cannot get link attributes for '%s'", link);
1921 
1922 	if (statep->ws_header) {
1923 		statep->ws_header = B_FALSE;
1924 		if (!statep->ws_parseable)
1925 			print_wifi_head(statep);
1926 	}
1927 
1928 	statep->ws_link = link;
1929 	statep->ws_overflow = 0;
1930 	for (i = 0; i < statep->ws_nfields; i++) {
1931 		statep->ws_lastfield = (i + 1 == statep->ws_nfields);
1932 		print_link_attr(statep, statep->ws_fields[i], &attr);
1933 	}
1934 	(void) putchar('\n');
1935 	return (B_TRUE);
1936 }
1937 
1938 static void
1939 do_display_wifi(int argc, char **argv, int cmd)
1940 {
1941 	int			option;
1942 	char			*fields_str = NULL;
1943 	wifi_field_t		**fields;
1944 	boolean_t		(*callback)(void *, const char *);
1945 	uint_t			nfields;
1946 	print_wifi_state_t	state;
1947 	dladm_status_t		status;
1948 
1949 	if (cmd == WIFI_CMD_SCAN)
1950 		callback = scan_wifi;
1951 	else if (cmd == WIFI_CMD_SHOW)
1952 		callback = show_wifi;
1953 	else
1954 		return;
1955 
1956 	state.ws_link = NULL;
1957 	state.ws_parseable = B_FALSE;
1958 	state.ws_header = B_TRUE;
1959 	opterr = 0;
1960 	while ((option = getopt_long(argc, argv, ":o:p",
1961 	    wifi_longopts, NULL)) != -1) {
1962 		switch (option) {
1963 		case 'o':
1964 			fields_str = optarg;
1965 			break;
1966 		case 'p':
1967 			state.ws_parseable = B_TRUE;
1968 			if (fields_str == NULL)
1969 				fields_str = "all";
1970 			break;
1971 		default:
1972 			die_opterr(optopt, option);
1973 			break;
1974 		}
1975 	}
1976 
1977 	if (optind == (argc - 1))
1978 		state.ws_link = argv[optind];
1979 	else if (optind != argc)
1980 		usage();
1981 
1982 	if (parse_wifi_fields(fields_str, &fields, &nfields, cmd) < 0)
1983 		die("invalid field(s) specified");
1984 
1985 	state.ws_fields = fields;
1986 	state.ws_nfields = nfields;
1987 
1988 	if (state.ws_link == NULL) {
1989 		status = dladm_wlan_walk(&state, callback);
1990 		if (status != DLADM_STATUS_OK)
1991 			die_dlerr(status, "cannot walk wifi links");
1992 	} else {
1993 		(void) (*callback)(&state, state.ws_link);
1994 	}
1995 	free(fields);
1996 }
1997 
1998 static void
1999 do_scan_wifi(int argc, char **argv)
2000 {
2001 	do_display_wifi(argc, argv, WIFI_CMD_SCAN);
2002 }
2003 
2004 static void
2005 do_show_wifi(int argc, char **argv)
2006 {
2007 	do_display_wifi(argc, argv, WIFI_CMD_SHOW);
2008 }
2009 
2010 typedef struct wlan_count_attr {
2011 	uint_t		wc_count;
2012 	const char	*wc_link;
2013 } wlan_count_attr_t;
2014 
2015 static boolean_t
2016 do_count_wlan(void *arg, const char *link)
2017 {
2018 	wlan_count_attr_t *cp = arg;
2019 
2020 	if (cp->wc_count == 0)
2021 		cp->wc_link = strdup(link);
2022 	cp->wc_count++;
2023 	return (B_TRUE);
2024 }
2025 
2026 static int
2027 parse_wlan_keys(char *str, dladm_wlan_key_t **keys, uint_t *key_countp)
2028 {
2029 	uint_t			i;
2030 	split_t			*sp;
2031 	dladm_wlan_key_t	*wk;
2032 
2033 	sp = split(str, DLADM_WLAN_MAX_WEPKEYS, DLADM_WLAN_MAX_KEYNAME_LEN);
2034 	if (sp == NULL)
2035 		return (-1);
2036 
2037 	wk = malloc(sp->s_nfields * sizeof (dladm_wlan_key_t));
2038 	if (wk == NULL)
2039 		goto fail;
2040 
2041 	for (i = 0; i < sp->s_nfields; i++) {
2042 		char			*s;
2043 		dladm_secobj_class_t	class;
2044 		dladm_status_t		status;
2045 
2046 		(void) strlcpy(wk[i].wk_name, sp->s_fields[i],
2047 		    DLADM_WLAN_MAX_KEYNAME_LEN);
2048 
2049 		wk[i].wk_idx = 1;
2050 		if ((s = strrchr(wk[i].wk_name, ':')) != NULL) {
2051 			if (s[1] == '\0' || s[2] != '\0' || !isdigit(s[1]))
2052 				goto fail;
2053 
2054 			wk[i].wk_idx = (uint_t)(s[1] - '0');
2055 			*s = '\0';
2056 		}
2057 		wk[i].wk_len = DLADM_WLAN_MAX_KEY_LEN;
2058 
2059 		status = dladm_get_secobj(wk[i].wk_name, &class,
2060 		    wk[i].wk_val, &wk[i].wk_len, 0);
2061 		if (status != DLADM_STATUS_OK) {
2062 			if (status == DLADM_STATUS_NOTFOUND) {
2063 				status = dladm_get_secobj(wk[i].wk_name,
2064 				    &class, wk[i].wk_val, &wk[i].wk_len,
2065 				    DLADM_OPT_PERSIST);
2066 			}
2067 			if (status != DLADM_STATUS_OK)
2068 				goto fail;
2069 		}
2070 		wk[i].wk_class = class;
2071 	}
2072 	*keys = wk;
2073 	*key_countp = i;
2074 	splitfree(sp);
2075 	return (0);
2076 fail:
2077 	free(wk);
2078 	splitfree(sp);
2079 	return (-1);
2080 }
2081 
2082 static void
2083 do_connect_wifi(int argc, char **argv)
2084 {
2085 	int			option;
2086 	dladm_wlan_attr_t	attr, *attrp;
2087 	dladm_status_t		status = DLADM_STATUS_OK;
2088 	int			timeout = DLADM_WLAN_CONNECT_TIMEOUT_DEFAULT;
2089 	const char		*link = NULL;
2090 	dladm_wlan_key_t	*keys = NULL;
2091 	uint_t			key_count = 0;
2092 	uint_t			flags = 0;
2093 	dladm_wlan_secmode_t	keysecmode = DLADM_WLAN_SECMODE_NONE;
2094 	char			buf[DLADM_STRSIZE];
2095 
2096 	opterr = 0;
2097 	(void) memset(&attr, 0, sizeof (attr));
2098 	while ((option = getopt_long(argc, argv, ":e:i:a:m:b:s:k:T:c",
2099 	    wifi_longopts, NULL)) != -1) {
2100 		switch (option) {
2101 		case 'e':
2102 			status = dladm_wlan_str2essid(optarg, &attr.wa_essid);
2103 			if (status != DLADM_STATUS_OK)
2104 				die("invalid ESSID '%s'", optarg);
2105 
2106 			attr.wa_valid |= DLADM_WLAN_ATTR_ESSID;
2107 			/*
2108 			 * Try to connect without doing a scan.
2109 			 */
2110 			flags |= DLADM_WLAN_CONNECT_NOSCAN;
2111 			break;
2112 		case 'i':
2113 			status = dladm_wlan_str2bssid(optarg, &attr.wa_bssid);
2114 			if (status != DLADM_STATUS_OK)
2115 				die("invalid BSSID %s", optarg);
2116 
2117 			attr.wa_valid |= DLADM_WLAN_ATTR_BSSID;
2118 			break;
2119 		case 'a':
2120 			status = dladm_wlan_str2auth(optarg, &attr.wa_auth);
2121 			if (status != DLADM_STATUS_OK)
2122 				die("invalid authentication mode '%s'", optarg);
2123 
2124 			attr.wa_valid |= DLADM_WLAN_ATTR_AUTH;
2125 			break;
2126 		case 'm':
2127 			status = dladm_wlan_str2mode(optarg, &attr.wa_mode);
2128 			if (status != DLADM_STATUS_OK)
2129 				die("invalid mode '%s'", optarg);
2130 
2131 			attr.wa_valid |= DLADM_WLAN_ATTR_MODE;
2132 			break;
2133 		case 'b':
2134 			if ((status = dladm_wlan_str2bsstype(optarg,
2135 			    &attr.wa_bsstype)) != DLADM_STATUS_OK) {
2136 				die("invalid bsstype '%s'", optarg);
2137 			}
2138 
2139 			attr.wa_valid |= DLADM_WLAN_ATTR_BSSTYPE;
2140 			break;
2141 		case 's':
2142 			if ((status = dladm_wlan_str2secmode(optarg,
2143 			    &attr.wa_secmode)) != DLADM_STATUS_OK) {
2144 				die("invalid security mode '%s'", optarg);
2145 			}
2146 
2147 			attr.wa_valid |= DLADM_WLAN_ATTR_SECMODE;
2148 			break;
2149 		case 'k':
2150 			if (parse_wlan_keys(optarg, &keys, &key_count) < 0)
2151 				die("invalid key(s) '%s'", optarg);
2152 
2153 			if (keys[0].wk_class == DLADM_SECOBJ_CLASS_WEP)
2154 				keysecmode = DLADM_WLAN_SECMODE_WEP;
2155 			else
2156 				keysecmode = DLADM_WLAN_SECMODE_WPA;
2157 			break;
2158 		case 'T':
2159 			if (strcasecmp(optarg, "forever") == 0) {
2160 				timeout = -1;
2161 				break;
2162 			}
2163 			if (!str2int(optarg, &timeout) || timeout < 0)
2164 				die("invalid timeout value '%s'", optarg);
2165 			break;
2166 		case 'c':
2167 			flags |= DLADM_WLAN_CONNECT_CREATEIBSS;
2168 			flags |= DLADM_WLAN_CONNECT_CREATEIBSS;
2169 			break;
2170 		default:
2171 			die_opterr(optopt, option);
2172 			break;
2173 		}
2174 	}
2175 
2176 	if (keysecmode == DLADM_WLAN_SECMODE_NONE) {
2177 		if ((attr.wa_valid & DLADM_WLAN_ATTR_SECMODE) != 0) {
2178 			die("key required for security mode '%s'",
2179 			    dladm_wlan_secmode2str(&attr.wa_secmode, buf));
2180 		}
2181 	} else {
2182 		if ((attr.wa_valid & DLADM_WLAN_ATTR_SECMODE) != 0 &&
2183 		    attr.wa_secmode != keysecmode)
2184 			die("incompatible -s and -k options");
2185 		attr.wa_valid |= DLADM_WLAN_ATTR_SECMODE;
2186 		attr.wa_secmode = keysecmode;
2187 	}
2188 
2189 	if (optind == (argc - 1))
2190 		link = argv[optind];
2191 	else if (optind != argc)
2192 		usage();
2193 
2194 	if (link == NULL) {
2195 		wlan_count_attr_t wcattr;
2196 
2197 		wcattr.wc_link = NULL;
2198 		wcattr.wc_count = 0;
2199 		(void) dladm_wlan_walk(&wcattr, do_count_wlan);
2200 		if (wcattr.wc_count == 0) {
2201 			die("no wifi links are available");
2202 		} else if (wcattr.wc_count > 1) {
2203 			die("link name is required when more than one wifi "
2204 			    "link is available");
2205 		}
2206 		link = wcattr.wc_link;
2207 	}
2208 	attrp = (attr.wa_valid == 0) ? NULL : &attr;
2209 again:
2210 	if ((status = dladm_wlan_connect(link, attrp, timeout, keys,
2211 	    key_count, flags)) != DLADM_STATUS_OK) {
2212 		if ((flags & DLADM_WLAN_CONNECT_NOSCAN) != 0) {
2213 			/*
2214 			 * Try again with scanning and filtering.
2215 			 */
2216 			flags &= ~DLADM_WLAN_CONNECT_NOSCAN;
2217 			goto again;
2218 		}
2219 
2220 		if (status == DLADM_STATUS_NOTFOUND) {
2221 			if (attr.wa_valid == 0) {
2222 				die("no wifi networks are available");
2223 			} else {
2224 				die("no wifi networks with the specified "
2225 				    "criteria are available");
2226 			}
2227 		}
2228 		die_dlerr(status, "cannot connect link '%s'", link);
2229 	}
2230 	free(keys);
2231 }
2232 
2233 /* ARGSUSED */
2234 static boolean_t
2235 do_all_disconnect_wifi(void *arg, const char *link)
2236 {
2237 	dladm_status_t	status;
2238 
2239 	status = dladm_wlan_disconnect(link);
2240 	if (status != DLADM_STATUS_OK)
2241 		warn_dlerr(status, "cannot disconnect link '%s'", link);
2242 
2243 	return (B_TRUE);
2244 }
2245 
2246 static void
2247 do_disconnect_wifi(int argc, char **argv)
2248 {
2249 	int			option;
2250 	const char		*link = NULL;
2251 	boolean_t		all_links = B_FALSE;
2252 	dladm_status_t		status;
2253 	wlan_count_attr_t	wcattr;
2254 
2255 	opterr = 0;
2256 	while ((option = getopt_long(argc, argv, ":a",
2257 	    wifi_longopts, NULL)) != -1) {
2258 		switch (option) {
2259 		case 'a':
2260 			all_links = B_TRUE;
2261 			break;
2262 		default:
2263 			die_opterr(optopt, option);
2264 			break;
2265 		}
2266 	}
2267 
2268 	if (optind == (argc - 1))
2269 		link = argv[optind];
2270 	else if (optind != argc)
2271 		usage();
2272 
2273 	if (link == NULL) {
2274 		if (!all_links) {
2275 			wcattr.wc_link = NULL;
2276 			wcattr.wc_count = 0;
2277 			(void) dladm_wlan_walk(&wcattr, do_count_wlan);
2278 			if (wcattr.wc_count == 0) {
2279 				die("no wifi links are available");
2280 			} else if (wcattr.wc_count > 1) {
2281 				die("link name is required when more than "
2282 				    "one wifi link is available");
2283 			}
2284 			link = wcattr.wc_link;
2285 		} else {
2286 			(void) dladm_wlan_walk(&all_links,
2287 			    do_all_disconnect_wifi);
2288 			return;
2289 		}
2290 	}
2291 	status = dladm_wlan_disconnect(link);
2292 	if (status != DLADM_STATUS_OK)
2293 		die_dlerr(status, "cannot disconnect link '%s'", link);
2294 }
2295 
2296 #define	MAX_PROPS		32
2297 #define	MAX_PROP_VALS		32
2298 #define	MAX_PROP_LINE		512
2299 
2300 typedef struct prop_info {
2301 	char		*pi_name;
2302 	char		*pi_val[MAX_PROP_VALS];
2303 	uint_t		pi_count;
2304 } prop_info_t;
2305 
2306 typedef struct prop_list {
2307 	prop_info_t	pl_info[MAX_PROPS];
2308 	uint_t		pl_count;
2309 	char		*pl_buf;
2310 } prop_list_t;
2311 
2312 typedef struct show_linkprop_state {
2313 	const char	*ls_link;
2314 	char		*ls_line;
2315 	char		**ls_propvals;
2316 	prop_list_t	*ls_proplist;
2317 	uint32_t	ls_parseable : 1,
2318 			ls_persist : 1,
2319 			ls_header : 1,
2320 			ls_pad_bits : 29;
2321 	dladm_status_t	ls_status;
2322 } show_linkprop_state_t;
2323 
2324 static void
2325 free_props(prop_list_t *list)
2326 {
2327 	if (list != NULL) {
2328 		free(list->pl_buf);
2329 		free(list);
2330 	}
2331 }
2332 
2333 static int
2334 parse_props(char *str, prop_list_t **listp, boolean_t novalues)
2335 {
2336 	prop_list_t	*list;
2337 	prop_info_t	*pip;
2338 	char		*buf, *curr;
2339 	int		len, i;
2340 
2341 	list = malloc(sizeof (prop_list_t));
2342 	if (list == NULL)
2343 		return (-1);
2344 
2345 	list->pl_count = 0;
2346 	list->pl_buf = buf = strdup(str);
2347 	if (buf == NULL)
2348 		goto fail;
2349 
2350 	curr = buf;
2351 	len = strlen(buf);
2352 	pip = NULL;
2353 	for (i = 0; i < len; i++) {
2354 		char		c = buf[i];
2355 		boolean_t	match = (c == '=' || c == ',');
2356 
2357 		if (!match && i != len - 1)
2358 			continue;
2359 
2360 		if (match) {
2361 			buf[i] = '\0';
2362 			if (*curr == '\0')
2363 				goto fail;
2364 		}
2365 
2366 		if (pip != NULL && c != '=') {
2367 			if (pip->pi_count > MAX_PROP_VALS)
2368 				goto fail;
2369 
2370 			if (novalues)
2371 				goto fail;
2372 
2373 			pip->pi_val[pip->pi_count] = curr;
2374 			pip->pi_count++;
2375 		} else {
2376 			if (list->pl_count > MAX_PROPS)
2377 				goto fail;
2378 
2379 			pip = &list->pl_info[list->pl_count];
2380 			pip->pi_name = curr;
2381 			pip->pi_count = 0;
2382 			list->pl_count++;
2383 			if (c == ',')
2384 				pip = NULL;
2385 		}
2386 		curr = buf + i + 1;
2387 	}
2388 	*listp = list;
2389 	return (0);
2390 
2391 fail:
2392 	free_props(list);
2393 	return (-1);
2394 }
2395 
2396 static void
2397 print_linkprop_head(void)
2398 {
2399 	(void) printf("%-12s %-15s %-14s %-14s %-20s \n",
2400 	    "LINK", "PROPERTY", "VALUE", "DEFAULT", "POSSIBLE");
2401 }
2402 
2403 static void
2404 print_linkprop(show_linkprop_state_t *statep, const char *propname,
2405     dladm_prop_type_t type, const char *typename, const char *format,
2406     char **pptr)
2407 {
2408 	int		i;
2409 	char		*ptr, *lim;
2410 	char		buf[DLADM_STRSIZE];
2411 	char		*unknown = "?", *notsup = "";
2412 	char		**propvals = statep->ls_propvals;
2413 	uint_t		valcnt = MAX_PROP_VALS;
2414 	dladm_status_t	status;
2415 
2416 	status = dladm_get_prop(statep->ls_link, type, propname,
2417 	    propvals, &valcnt);
2418 	if (status != DLADM_STATUS_OK) {
2419 		if (status == DLADM_STATUS_TEMPONLY) {
2420 			statep->ls_status = status;
2421 			return;
2422 		} else if (status == DLADM_STATUS_NOTSUP ||
2423 		    statep->ls_persist) {
2424 			valcnt = 1;
2425 			if (type == DLADM_PROP_VAL_CURRENT)
2426 				propvals = &unknown;
2427 			else
2428 				propvals = &notsup;
2429 		} else {
2430 			statep->ls_status = status;
2431 			warn_dlerr(status,
2432 			    "cannot get link property '%s' for %s",
2433 			    propname, statep->ls_link);
2434 			return;
2435 		}
2436 	}
2437 
2438 	ptr = buf;
2439 	lim = buf + DLADM_STRSIZE;
2440 	for (i = 0; i < valcnt; i++) {
2441 		if (propvals[i][0] == '\0' && !statep->ls_parseable)
2442 			ptr += snprintf(ptr, lim - ptr, "--,");
2443 		else
2444 			ptr += snprintf(ptr, lim - ptr, "%s,", propvals[i]);
2445 		if (ptr >= lim)
2446 			break;
2447 	}
2448 	if (valcnt > 0)
2449 		buf[strlen(buf) - 1] = '\0';
2450 
2451 	lim = statep->ls_line + MAX_PROP_LINE;
2452 	if (statep->ls_parseable) {
2453 		*pptr += snprintf(*pptr, lim - *pptr,
2454 		    "%s=\"%s\" ", typename, buf);
2455 	} else {
2456 		*pptr += snprintf(*pptr, lim - *pptr, format, buf);
2457 	}
2458 }
2459 
2460 static boolean_t
2461 show_linkprop(void *arg, const char *propname)
2462 {
2463 	show_linkprop_state_t	*statep = arg;
2464 	char			*ptr = statep->ls_line;
2465 	char			*lim = ptr + MAX_PROP_LINE;
2466 
2467 	if (statep->ls_parseable)
2468 		ptr += snprintf(ptr, lim - ptr, "LINK=\"%s\" ",
2469 		    statep->ls_link);
2470 	else
2471 		ptr += snprintf(ptr, lim - ptr, "%-12s ", statep->ls_link);
2472 
2473 	if (statep->ls_parseable)
2474 		ptr += snprintf(ptr, lim - ptr, "PROPERTY=\"%s\" ", propname);
2475 	else
2476 		ptr += snprintf(ptr, lim - ptr, "%-15s ", propname);
2477 
2478 	print_linkprop(statep, propname,
2479 	    statep->ls_persist ? DLADM_PROP_VAL_PERSISTENT :
2480 	    DLADM_PROP_VAL_CURRENT, "VALUE", "%-14s ", &ptr);
2481 
2482 	/*
2483 	 * If we failed to query the link property, for example, query
2484 	 * the persistent value of a non-persistable link property, simply
2485 	 * skip the output.
2486 	 */
2487 	if (statep->ls_status != DLADM_STATUS_OK)
2488 		return (B_TRUE);
2489 
2490 	print_linkprop(statep, propname, DLADM_PROP_VAL_DEFAULT,
2491 	    "DEFAULT", "%-14s ", &ptr);
2492 	if (statep->ls_status != DLADM_STATUS_OK)
2493 		return (B_TRUE);
2494 
2495 	print_linkprop(statep, propname, DLADM_PROP_VAL_MODIFIABLE,
2496 	    "POSSIBLE", "%-20s ", &ptr);
2497 	if (statep->ls_status != DLADM_STATUS_OK)
2498 		return (B_TRUE);
2499 
2500 	if (statep->ls_header) {
2501 		statep->ls_header = B_FALSE;
2502 		if (!statep->ls_parseable)
2503 			print_linkprop_head();
2504 	}
2505 	(void) printf("%s\n", statep->ls_line);
2506 	return (B_TRUE);
2507 }
2508 
2509 static void
2510 do_show_linkprop(int argc, char **argv)
2511 {
2512 	int			option;
2513 	prop_list_t		*proplist = NULL;
2514 	show_linkprop_state_t	state;
2515 
2516 	opterr = 0;
2517 	state.ls_link = NULL;
2518 	state.ls_propvals = NULL;
2519 	state.ls_line = NULL;
2520 	state.ls_parseable = B_FALSE;
2521 	state.ls_persist = B_FALSE;
2522 	state.ls_header = B_TRUE;
2523 	while ((option = getopt_long(argc, argv, ":p:cP",
2524 	    prop_longopts, NULL)) != -1) {
2525 		switch (option) {
2526 		case 'p':
2527 			if (parse_props(optarg, &proplist, B_TRUE) < 0)
2528 				die("invalid link properties specified");
2529 			break;
2530 		case 'c':
2531 			state.ls_parseable = B_TRUE;
2532 			break;
2533 		case 'P':
2534 			state.ls_persist = B_TRUE;
2535 			break;
2536 		default:
2537 			die_opterr(optopt, option);
2538 			break;
2539 		}
2540 	}
2541 
2542 	if (optind == (argc - 1))
2543 		state.ls_link = argv[optind];
2544 	else if (optind != argc)
2545 		usage();
2546 
2547 	state.ls_proplist = proplist;
2548 	state.ls_status = DLADM_STATUS_OK;
2549 
2550 	if (state.ls_link == NULL) {
2551 		(void) dladm_walk(show_linkprop_onelink, &state);
2552 	} else {
2553 		show_linkprop_onelink(&state, state.ls_link);
2554 	}
2555 	free_props(proplist);
2556 
2557 	if (state.ls_status != DLADM_STATUS_OK)
2558 		exit(EXIT_FAILURE);
2559 }
2560 
2561 static void
2562 show_linkprop_onelink(void *arg, const char *link)
2563 {
2564 	int			i, fd;
2565 	char			linkname[MAXPATHLEN];
2566 	char			*buf;
2567 	dladm_status_t		status;
2568 	prop_list_t		*proplist = NULL;
2569 	show_linkprop_state_t	*statep;
2570 	const char		*savep;
2571 
2572 	statep = (show_linkprop_state_t *)arg;
2573 	savep = statep->ls_link;
2574 	statep->ls_link = link;
2575 	proplist = statep->ls_proplist;
2576 
2577 	/*
2578 	 * When some WiFi links are opened for the first time, their hardware
2579 	 * automatically scans for APs and does other slow operations.	Thus,
2580 	 * if there are no open links, the retrieval of link properties
2581 	 * (below) will proceed slowly unless we hold the link open.
2582 	 */
2583 	(void) snprintf(linkname, MAXPATHLEN, "/dev/%s", link);
2584 	if ((fd = open(linkname, O_RDWR)) < 0) {
2585 		warn("cannot open %s: %s", link, strerror(errno));
2586 		statep->ls_status = DLADM_STATUS_NOTFOUND;
2587 		return;
2588 	}
2589 
2590 	buf = malloc((sizeof (char *) + DLADM_PROP_VAL_MAX) * MAX_PROP_VALS +
2591 	    MAX_PROP_LINE);
2592 	if (buf == NULL)
2593 		die("insufficient memory");
2594 
2595 	statep->ls_propvals = (char **)(void *)buf;
2596 	for (i = 0; i < MAX_PROP_VALS; i++) {
2597 		statep->ls_propvals[i] = buf + sizeof (char *) * MAX_PROP_VALS +
2598 		    i * DLADM_PROP_VAL_MAX;
2599 	}
2600 	statep->ls_line = buf +
2601 	    (sizeof (char *) + DLADM_PROP_VAL_MAX) * MAX_PROP_VALS;
2602 
2603 	if (proplist != NULL) {
2604 		for (i = 0; i < proplist->pl_count; i++)
2605 			(void) show_linkprop(statep,
2606 			    proplist->pl_info[i].pi_name);
2607 	} else {
2608 		status = dladm_walk_prop(link, statep, show_linkprop);
2609 		if (status != DLADM_STATUS_OK)
2610 			warn_dlerr(status, "show-linkprop failed for %s", link);
2611 	}
2612 	(void) close(fd);
2613 	free(buf);
2614 	statep->ls_link = savep;
2615 }
2616 
2617 static dladm_status_t
2618 set_linkprop_persist(const char *link, const char *prop_name, char **prop_val,
2619     uint_t val_cnt, boolean_t reset)
2620 {
2621 	dladm_status_t	status;
2622 	char		*errprop;
2623 
2624 	status = dladm_set_prop(link, prop_name, prop_val, val_cnt,
2625 	    DLADM_OPT_PERSIST, &errprop);
2626 
2627 	if (status != DLADM_STATUS_OK) {
2628 		if (reset) {
2629 			warn_dlerr(status, "cannot persistently reset link "
2630 			    "property '%s' on '%s'", errprop, link);
2631 		} else {
2632 			warn_dlerr(status, "cannot persistently set link "
2633 			    "property '%s' on '%s'", errprop, link);
2634 		}
2635 	}
2636 	return (status);
2637 }
2638 
2639 static void
2640 set_linkprop(int argc, char **argv, boolean_t reset)
2641 {
2642 	int		i, option;
2643 	char		errmsg[DLADM_STRSIZE];
2644 	const char	*link = NULL;
2645 	prop_list_t	*proplist = NULL;
2646 	boolean_t	temp = B_FALSE;
2647 	dladm_status_t	status = DLADM_STATUS_OK;
2648 
2649 	opterr = 0;
2650 	while ((option = getopt_long(argc, argv, ":p:R:t",
2651 	    prop_longopts, NULL)) != -1) {
2652 		switch (option) {
2653 		case 'p':
2654 			if (parse_props(optarg, &proplist, reset) < 0)
2655 				die("invalid link properties specified");
2656 			break;
2657 		case 't':
2658 			temp = B_TRUE;
2659 			break;
2660 		case 'R':
2661 			status = dladm_set_rootdir(optarg);
2662 			if (status != DLADM_STATUS_OK) {
2663 				die_dlerr(status, "invalid directory "
2664 				    "specified");
2665 			}
2666 			break;
2667 		default:
2668 			die_opterr(optopt, option);
2669 			break;
2670 		}
2671 	}
2672 
2673 	if (optind == (argc - 1))
2674 		link = argv[optind];
2675 	else if (optind != argc)
2676 		usage();
2677 
2678 	if (link == NULL)
2679 		die("link name must be specified");
2680 
2681 	if (proplist == NULL) {
2682 		char *errprop;
2683 
2684 		if (!reset)
2685 			die("link property must be specified");
2686 
2687 		status = dladm_set_prop(link, NULL, NULL, 0, DLADM_OPT_TEMP,
2688 		    &errprop);
2689 		if (status != DLADM_STATUS_OK) {
2690 			warn_dlerr(status, "cannot reset link property '%s' "
2691 			    "on '%s'", errprop, link);
2692 		}
2693 		if (!temp) {
2694 			dladm_status_t	s;
2695 
2696 			s = set_linkprop_persist(link, NULL, NULL, 0, reset);
2697 			if (s != DLADM_STATUS_OK)
2698 				status = s;
2699 		}
2700 		goto done;
2701 	}
2702 
2703 	for (i = 0; i < proplist->pl_count; i++) {
2704 		prop_info_t	*pip = &proplist->pl_info[i];
2705 		char		**val;
2706 		uint_t		count;
2707 		dladm_status_t	s;
2708 
2709 		if (reset) {
2710 			val = NULL;
2711 			count = 0;
2712 		} else {
2713 			val = pip->pi_val;
2714 			count = pip->pi_count;
2715 			if (count == 0) {
2716 				warn("no value specified for '%s'",
2717 				    pip->pi_name);
2718 				status = DLADM_STATUS_BADARG;
2719 				continue;
2720 			}
2721 		}
2722 		s = dladm_set_prop(link, pip->pi_name, val, count,
2723 		    DLADM_OPT_TEMP, NULL);
2724 		if (s == DLADM_STATUS_OK) {
2725 			if (!temp) {
2726 				s = set_linkprop_persist(link,
2727 				    pip->pi_name, val, count, reset);
2728 				if (s != DLADM_STATUS_OK)
2729 					status = s;
2730 			}
2731 			continue;
2732 		}
2733 		status = s;
2734 		switch (s) {
2735 		case DLADM_STATUS_NOTFOUND:
2736 			warn("invalid link property '%s'", pip->pi_name);
2737 			break;
2738 		case DLADM_STATUS_BADVAL: {
2739 			int		j;
2740 			char		*ptr, *lim;
2741 			char		**propvals = NULL;
2742 			uint_t		valcnt = MAX_PROP_VALS;
2743 
2744 			ptr = malloc((sizeof (char *) +
2745 			    DLADM_PROP_VAL_MAX) * MAX_PROP_VALS +
2746 			    MAX_PROP_LINE);
2747 
2748 			propvals = (char **)(void *)ptr;
2749 			if (propvals == NULL)
2750 				die("insufficient memory");
2751 
2752 			for (j = 0; j < MAX_PROP_VALS; j++) {
2753 				propvals[j] = ptr + sizeof (char *) *
2754 				    MAX_PROP_VALS +
2755 				    j * DLADM_PROP_VAL_MAX;
2756 			}
2757 			s = dladm_get_prop(link, DLADM_PROP_VAL_MODIFIABLE,
2758 			    pip->pi_name, propvals, &valcnt);
2759 
2760 			ptr = errmsg;
2761 			lim = ptr + DLADM_STRSIZE;
2762 			*ptr = '\0';
2763 			for (j = 0; j < valcnt && s == DLADM_STATUS_OK; j++) {
2764 				ptr += snprintf(ptr, lim - ptr, "%s,",
2765 				    propvals[j]);
2766 				if (ptr >= lim)
2767 					break;
2768 			}
2769 			if (ptr > errmsg) {
2770 				*(ptr - 1) = '\0';
2771 				warn("link property '%s' must be one of: %s",
2772 				    pip->pi_name, errmsg);
2773 			} else
2774 				warn("invalid link property '%s'", *val);
2775 			free(propvals);
2776 			break;
2777 		}
2778 		default:
2779 			if (reset) {
2780 				warn_dlerr(status, "cannot reset link property "
2781 				    "'%s' on '%s'", pip->pi_name, link);
2782 			} else {
2783 				warn_dlerr(status, "cannot set link property "
2784 				    "'%s' on '%s'", pip->pi_name, link);
2785 			}
2786 			break;
2787 		}
2788 	}
2789 done:
2790 	free_props(proplist);
2791 	if (status != DLADM_STATUS_OK)
2792 		exit(1);
2793 }
2794 
2795 static void
2796 do_set_linkprop(int argc, char **argv)
2797 {
2798 	set_linkprop(argc, argv, B_FALSE);
2799 }
2800 
2801 static void
2802 do_reset_linkprop(int argc, char **argv)
2803 {
2804 	set_linkprop(argc, argv, B_TRUE);
2805 }
2806 
2807 static int
2808 convert_secobj(char *buf, uint_t len, uint8_t *obj_val, uint_t *obj_lenp,
2809     dladm_secobj_class_t class)
2810 {
2811 	int error = 0;
2812 
2813 	if (class == DLADM_SECOBJ_CLASS_WPA) {
2814 		if (len < 8 || len > 63)
2815 			return (EINVAL);
2816 		(void) memcpy(obj_val, buf, len);
2817 		*obj_lenp = len;
2818 		return (error);
2819 	}
2820 
2821 	if (class == DLADM_SECOBJ_CLASS_WEP) {
2822 		switch (len) {
2823 		case 5:			/* ASCII key sizes */
2824 		case 13:
2825 			(void) memcpy(obj_val, buf, len);
2826 			*obj_lenp = len;
2827 			break;
2828 		case 10:		/* Hex key sizes, not preceded by 0x */
2829 		case 26:
2830 			error = hexascii_to_octet(buf, len, obj_val, obj_lenp);
2831 			break;
2832 		case 12:		/* Hex key sizes, preceded by 0x */
2833 		case 28:
2834 			if (strncmp(buf, "0x", 2) != 0)
2835 				return (EINVAL);
2836 			error = hexascii_to_octet(buf + 2, len - 2,
2837 			    obj_val, obj_lenp);
2838 			break;
2839 		default:
2840 			return (EINVAL);
2841 		}
2842 		return (error);
2843 	}
2844 
2845 	return (ENOENT);
2846 }
2847 
2848 /* ARGSUSED */
2849 static void
2850 defersig(int sig)
2851 {
2852 	signalled = sig;
2853 }
2854 
2855 static int
2856 get_secobj_from_tty(uint_t try, const char *objname, char *buf)
2857 {
2858 	uint_t		len = 0;
2859 	int		c;
2860 	struct termios	stored, current;
2861 	void		(*sigfunc)(int);
2862 
2863 	/*
2864 	 * Turn off echo -- but before we do so, defer SIGINT handling
2865 	 * so that a ^C doesn't leave the terminal corrupted.
2866 	 */
2867 	sigfunc = signal(SIGINT, defersig);
2868 	(void) fflush(stdin);
2869 	(void) tcgetattr(0, &stored);
2870 	current = stored;
2871 	current.c_lflag &= ~(ICANON|ECHO);
2872 	current.c_cc[VTIME] = 0;
2873 	current.c_cc[VMIN] = 1;
2874 	(void) tcsetattr(0, TCSANOW, &current);
2875 again:
2876 	if (try == 1)
2877 		(void) printf(gettext("provide value for '%s': "), objname);
2878 	else
2879 		(void) printf(gettext("confirm value for '%s': "), objname);
2880 
2881 	(void) fflush(stdout);
2882 	while (signalled == 0) {
2883 		c = getchar();
2884 		if (c == '\n' || c == '\r') {
2885 			if (len != 0)
2886 				break;
2887 			(void) putchar('\n');
2888 			goto again;
2889 		}
2890 
2891 		buf[len++] = c;
2892 		if (len >= DLADM_SECOBJ_VAL_MAX - 1)
2893 			break;
2894 		(void) putchar('*');
2895 	}
2896 
2897 	(void) putchar('\n');
2898 	(void) fflush(stdin);
2899 
2900 	/*
2901 	 * Restore terminal setting and handle deferred signals.
2902 	 */
2903 	(void) tcsetattr(0, TCSANOW, &stored);
2904 
2905 	(void) signal(SIGINT, sigfunc);
2906 	if (signalled != 0)
2907 		(void) kill(getpid(), signalled);
2908 
2909 	return (len);
2910 }
2911 
2912 static int
2913 get_secobj_val(char *obj_name, uint8_t *obj_val, uint_t *obj_lenp,
2914     dladm_secobj_class_t class, FILE *filep)
2915 {
2916 	int		rval;
2917 	uint_t		len, len2;
2918 	char		buf[DLADM_SECOBJ_VAL_MAX], buf2[DLADM_SECOBJ_VAL_MAX];
2919 
2920 	if (filep == NULL) {
2921 		len = get_secobj_from_tty(1, obj_name, buf);
2922 		rval = convert_secobj(buf, len, obj_val, obj_lenp, class);
2923 		if (rval == 0) {
2924 			len2 = get_secobj_from_tty(2, obj_name, buf2);
2925 			if (len != len2 || memcmp(buf, buf2, len) != 0)
2926 				rval = ENOTSUP;
2927 		}
2928 		return (rval);
2929 	} else {
2930 		for (;;) {
2931 			if (fgets(buf, sizeof (buf), filep) == NULL)
2932 				break;
2933 			if (isspace(buf[0]))
2934 				continue;
2935 
2936 			len = strlen(buf);
2937 			if (buf[len - 1] == '\n') {
2938 				buf[len - 1] = '\0';
2939 				len--;
2940 			}
2941 			break;
2942 		}
2943 		(void) fclose(filep);
2944 	}
2945 	return (convert_secobj(buf, len, obj_val, obj_lenp, class));
2946 }
2947 
2948 static boolean_t
2949 check_auth(const char *auth)
2950 {
2951 	struct passwd	*pw;
2952 
2953 	if ((pw = getpwuid(getuid())) == NULL)
2954 		return (B_FALSE);
2955 
2956 	return (chkauthattr(auth, pw->pw_name) != 0);
2957 }
2958 
2959 static void
2960 audit_secobj(char *auth, char *class, char *obj,
2961     boolean_t success, boolean_t create)
2962 {
2963 	adt_session_data_t	*ah;
2964 	adt_event_data_t	*event;
2965 	au_event_t		flag;
2966 	char			*errstr;
2967 
2968 	if (create) {
2969 		flag = ADT_dladm_create_secobj;
2970 		errstr = "ADT_dladm_create_secobj";
2971 	} else {
2972 		flag = ADT_dladm_delete_secobj;
2973 		errstr = "ADT_dladm_delete_secobj";
2974 	}
2975 
2976 	if (adt_start_session(&ah, NULL, ADT_USE_PROC_DATA) != 0)
2977 		die("adt_start_session: %s", strerror(errno));
2978 
2979 	if ((event = adt_alloc_event(ah, flag)) == NULL)
2980 		die("adt_alloc_event (%s): %s", errstr, strerror(errno));
2981 
2982 	/* fill in audit info */
2983 	if (create) {
2984 		event->adt_dladm_create_secobj.auth_used = auth;
2985 		event->adt_dladm_create_secobj.obj_class = class;
2986 		event->adt_dladm_create_secobj.obj_name = obj;
2987 	} else {
2988 		event->adt_dladm_delete_secobj.auth_used = auth;
2989 		event->adt_dladm_delete_secobj.obj_class = class;
2990 		event->adt_dladm_delete_secobj.obj_name = obj;
2991 	}
2992 
2993 	if (success) {
2994 		if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS) != 0) {
2995 			die("adt_put_event (%s, success): %s", errstr,
2996 			    strerror(errno));
2997 		}
2998 	} else {
2999 		if (adt_put_event(event, ADT_FAILURE,
3000 		    ADT_FAIL_VALUE_AUTH) != 0) {
3001 			die("adt_put_event: (%s, failure): %s", errstr,
3002 			    strerror(errno));
3003 		}
3004 	}
3005 
3006 	adt_free_event(event);
3007 	(void) adt_end_session(ah);
3008 }
3009 
3010 #define	MAX_SECOBJS		32
3011 #define	MAX_SECOBJ_NAMELEN	32
3012 static void
3013 do_create_secobj(int argc, char **argv)
3014 {
3015 	int			option, rval;
3016 	FILE			*filep = NULL;
3017 	char			*obj_name = NULL;
3018 	char			*class_name = NULL;
3019 	uint8_t			obj_val[DLADM_SECOBJ_VAL_MAX];
3020 	uint_t			obj_len;
3021 	boolean_t		success, temp = B_FALSE;
3022 	dladm_status_t		status;
3023 	dladm_secobj_class_t	class = -1;
3024 	uid_t			euid;
3025 
3026 	opterr = 0;
3027 	(void) memset(obj_val, 0, DLADM_SECOBJ_VAL_MAX);
3028 	while ((option = getopt_long(argc, argv, ":f:c:R:t",
3029 	    wifi_longopts, NULL)) != -1) {
3030 		switch (option) {
3031 		case 'f':
3032 			euid = geteuid();
3033 			(void) seteuid(getuid());
3034 			filep = fopen(optarg, "r");
3035 			if (filep == NULL) {
3036 				die("cannot open %s: %s", optarg,
3037 				    strerror(errno));
3038 			}
3039 			(void) seteuid(euid);
3040 			break;
3041 		case 'c':
3042 			class_name = optarg;
3043 			status = dladm_str2secobjclass(optarg, &class);
3044 			if (status != DLADM_STATUS_OK) {
3045 				die("invalid secure object class '%s', "
3046 				    "valid values are: wep, wpa", optarg);
3047 			}
3048 			break;
3049 		case 't':
3050 			temp = B_TRUE;
3051 			break;
3052 		case 'R':
3053 			status = dladm_set_rootdir(optarg);
3054 			if (status != DLADM_STATUS_OK) {
3055 				die_dlerr(status, "invalid directory "
3056 				    "specified");
3057 			}
3058 			break;
3059 		default:
3060 			die_opterr(optopt, option);
3061 			break;
3062 		}
3063 	}
3064 
3065 	if (optind == (argc - 1))
3066 		obj_name = argv[optind];
3067 	else if (optind != argc)
3068 		usage();
3069 
3070 	if (class == -1)
3071 		die("secure object class required");
3072 
3073 	if (obj_name == NULL)
3074 		die("secure object name required");
3075 
3076 	success = check_auth(LINK_SEC_AUTH);
3077 	audit_secobj(LINK_SEC_AUTH, class_name, obj_name, success, B_TRUE);
3078 	if (!success)
3079 		die("authorization '%s' is required", LINK_SEC_AUTH);
3080 
3081 	rval = get_secobj_val(obj_name, obj_val, &obj_len, class, filep);
3082 	if (rval != 0) {
3083 		switch (rval) {
3084 		case ENOENT:
3085 			die("invalid secure object class");
3086 			break;
3087 		case EINVAL:
3088 			die("invalid secure object value");
3089 			break;
3090 		case ENOTSUP:
3091 			die("verification failed");
3092 			break;
3093 		default:
3094 			die("invalid secure object: %s", strerror(rval));
3095 			break;
3096 		}
3097 	}
3098 
3099 	status = dladm_set_secobj(obj_name, class, obj_val, obj_len,
3100 	    DLADM_OPT_CREATE | DLADM_OPT_TEMP);
3101 	if (status != DLADM_STATUS_OK) {
3102 		die_dlerr(status, "could not create secure object '%s'",
3103 		    obj_name);
3104 	}
3105 	if (temp)
3106 		return;
3107 
3108 	status = dladm_set_secobj(obj_name, class, obj_val, obj_len,
3109 	    DLADM_OPT_PERSIST);
3110 	if (status != DLADM_STATUS_OK) {
3111 		warn_dlerr(status, "could not persistently create secure "
3112 		    "object '%s'", obj_name);
3113 	}
3114 }
3115 
3116 static void
3117 do_delete_secobj(int argc, char **argv)
3118 {
3119 	int		i, option;
3120 	boolean_t	temp = B_FALSE;
3121 	split_t		*sp = NULL;
3122 	boolean_t	success;
3123 	dladm_status_t	status, pstatus;
3124 
3125 	opterr = 0;
3126 	status = pstatus = DLADM_STATUS_OK;
3127 	while ((option = getopt_long(argc, argv, ":R:t",
3128 	    wifi_longopts, NULL)) != -1) {
3129 		switch (option) {
3130 		case 't':
3131 			temp = B_TRUE;
3132 			break;
3133 		case 'R':
3134 			status = dladm_set_rootdir(optarg);
3135 			if (status != DLADM_STATUS_OK) {
3136 				die_dlerr(status, "invalid directory "
3137 				    "specified");
3138 			}
3139 			break;
3140 		default:
3141 			die_opterr(optopt, option);
3142 			break;
3143 		}
3144 	}
3145 
3146 	if (optind == (argc - 1)) {
3147 		sp = split(argv[optind], MAX_SECOBJS, MAX_SECOBJ_NAMELEN);
3148 		if (sp == NULL) {
3149 			die("invalid secure object name(s): '%s'",
3150 			    argv[optind]);
3151 		}
3152 	} else if (optind != argc)
3153 		usage();
3154 
3155 	if (sp == NULL || sp->s_nfields < 1)
3156 		die("secure object name required");
3157 
3158 	success = check_auth(LINK_SEC_AUTH);
3159 	audit_secobj(LINK_SEC_AUTH, "unknown", argv[optind], success, B_FALSE);
3160 	if (!success)
3161 		die("authorization '%s' is required", LINK_SEC_AUTH);
3162 
3163 	for (i = 0; i < sp->s_nfields; i++) {
3164 		status = dladm_unset_secobj(sp->s_fields[i], DLADM_OPT_TEMP);
3165 		if (!temp) {
3166 			pstatus = dladm_unset_secobj(sp->s_fields[i],
3167 			    DLADM_OPT_PERSIST);
3168 		} else {
3169 			pstatus = DLADM_STATUS_OK;
3170 		}
3171 
3172 		if (status != DLADM_STATUS_OK) {
3173 			warn_dlerr(status, "could not delete secure object "
3174 			    "'%s'", sp->s_fields[i]);
3175 		}
3176 		if (pstatus != DLADM_STATUS_OK) {
3177 			warn_dlerr(pstatus, "could not persistently delete "
3178 			    "secure object '%s'", sp->s_fields[i]);
3179 		}
3180 	}
3181 	if (status != DLADM_STATUS_OK || pstatus != DLADM_STATUS_OK)
3182 		exit(1);
3183 }
3184 
3185 typedef struct show_secobj_state {
3186 	boolean_t	ss_persist;
3187 	boolean_t	ss_parseable;
3188 	boolean_t	ss_debug;
3189 	boolean_t	ss_header;
3190 } show_secobj_state_t;
3191 
3192 static void
3193 print_secobj_head(show_secobj_state_t *statep)
3194 {
3195 	(void) printf("%-20s %-20s ", "OBJECT", "CLASS");
3196 	if (statep->ss_debug)
3197 		(void) printf("%-30s", "VALUE");
3198 	(void) putchar('\n');
3199 }
3200 
3201 static boolean_t
3202 show_secobj(void *arg, const char *obj_name)
3203 {
3204 	uint_t			obj_len = DLADM_SECOBJ_VAL_MAX;
3205 	uint8_t			obj_val[DLADM_SECOBJ_VAL_MAX];
3206 	char			buf[DLADM_STRSIZE];
3207 	uint_t			flags = 0;
3208 	dladm_secobj_class_t	class;
3209 	show_secobj_state_t	*statep = arg;
3210 	dladm_status_t		status;
3211 
3212 	if (statep->ss_persist)
3213 		flags |= DLADM_OPT_PERSIST;
3214 
3215 	status = dladm_get_secobj(obj_name, &class, obj_val, &obj_len, flags);
3216 	if (status != DLADM_STATUS_OK)
3217 		die_dlerr(status, "cannot get secure object '%s'", obj_name);
3218 
3219 	if (statep->ss_header) {
3220 		statep->ss_header = B_FALSE;
3221 		if (!statep->ss_parseable)
3222 			print_secobj_head(statep);
3223 	}
3224 
3225 	if (statep->ss_parseable) {
3226 		(void) printf("OBJECT=\"%s\" CLASS=\"%s\" ", obj_name,
3227 		    dladm_secobjclass2str(class, buf));
3228 	} else {
3229 		(void) printf("%-20s %-20s ", obj_name,
3230 		    dladm_secobjclass2str(class, buf));
3231 	}
3232 
3233 	if (statep->ss_debug) {
3234 		char	val[DLADM_SECOBJ_VAL_MAX * 2];
3235 		uint_t	len = sizeof (val);
3236 
3237 		if (octet_to_hexascii(obj_val, obj_len, val, &len) == 0) {
3238 			if (statep->ss_parseable)
3239 				(void) printf("VALUE=\"0x%s\"", val);
3240 			else
3241 				(void) printf("0x%-30s", val);
3242 		}
3243 	}
3244 	(void) putchar('\n');
3245 	return (B_TRUE);
3246 }
3247 
3248 static void
3249 do_show_secobj(int argc, char **argv)
3250 {
3251 	int			option;
3252 	show_secobj_state_t	state;
3253 	dladm_status_t		status;
3254 	uint_t			i;
3255 	split_t			*sp;
3256 	uint_t			flags;
3257 
3258 	opterr = 0;
3259 	state.ss_persist = B_FALSE;
3260 	state.ss_parseable = B_FALSE;
3261 	state.ss_debug = B_FALSE;
3262 	state.ss_header = B_TRUE;
3263 	while ((option = getopt_long(argc, argv, ":pPd",
3264 	    wifi_longopts, NULL)) != -1) {
3265 		switch (option) {
3266 		case 'p':
3267 			state.ss_parseable = B_TRUE;
3268 			break;
3269 		case 'P':
3270 			state.ss_persist = B_TRUE;
3271 			break;
3272 		case 'd':
3273 			if (getuid() != 0)
3274 				die("insufficient privileges");
3275 			state.ss_debug = B_TRUE;
3276 			break;
3277 		default:
3278 			die_opterr(optopt, option);
3279 			break;
3280 		}
3281 	}
3282 
3283 	if (optind == (argc - 1)) {
3284 		sp = split(argv[optind], MAX_SECOBJS, MAX_SECOBJ_NAMELEN);
3285 		if (sp == NULL) {
3286 			die("invalid secure object name(s): '%s'",
3287 			    argv[optind]);
3288 		}
3289 		for (i = 0; i < sp->s_nfields; i++) {
3290 			if (!show_secobj(&state, sp->s_fields[i]))
3291 				break;
3292 		}
3293 		splitfree(sp);
3294 		return;
3295 	} else if (optind != argc)
3296 		usage();
3297 
3298 	flags = state.ss_persist ? DLADM_OPT_PERSIST : 0;
3299 	status = dladm_walk_secobj(&state, show_secobj, flags);
3300 	if (status != DLADM_STATUS_OK)
3301 		die_dlerr(status, "show-secobj");
3302 }
3303 
3304 /* ARGSUSED */
3305 static void
3306 do_init_linkprop(int argc, char **argv)
3307 {
3308 	dladm_status_t status;
3309 
3310 	status = dladm_init_linkprop();
3311 	if (status != DLADM_STATUS_OK)
3312 		die_dlerr(status, "link property initialization failed");
3313 }
3314 
3315 /* ARGSUSED */
3316 static void
3317 do_init_secobj(int argc, char **argv)
3318 {
3319 	dladm_status_t status;
3320 
3321 	status = dladm_init_secobj();
3322 	if (status != DLADM_STATUS_OK)
3323 		die_dlerr(status, "secure object initialization failed");
3324 }
3325 
3326 static boolean_t
3327 str2int(const char *str, int *valp)
3328 {
3329 	int	val;
3330 	char	*endp = NULL;
3331 
3332 	errno = 0;
3333 	val = strtol(str, &endp, 10);
3334 	if (errno != 0 || *endp != '\0')
3335 		return (B_FALSE);
3336 
3337 	*valp = val;
3338 	return (B_TRUE);
3339 }
3340 
3341 /* PRINTFLIKE1 */
3342 static void
3343 warn(const char *format, ...)
3344 {
3345 	va_list alist;
3346 
3347 	format = gettext(format);
3348 	(void) fprintf(stderr, "%s: warning: ", progname);
3349 
3350 	va_start(alist, format);
3351 	(void) vfprintf(stderr, format, alist);
3352 	va_end(alist);
3353 
3354 	(void) putchar('\n');
3355 }
3356 
3357 /* PRINTFLIKE2 */
3358 static void
3359 warn_dlerr(dladm_status_t err, const char *format, ...)
3360 {
3361 	va_list alist;
3362 	char	errmsg[DLADM_STRSIZE];
3363 
3364 	format = gettext(format);
3365 	(void) fprintf(stderr, gettext("%s: warning: "), progname);
3366 
3367 	va_start(alist, format);
3368 	(void) vfprintf(stderr, format, alist);
3369 	va_end(alist);
3370 	(void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg));
3371 }
3372 
3373 /* PRINTFLIKE2 */
3374 static void
3375 die_dlerr(dladm_status_t err, const char *format, ...)
3376 {
3377 	va_list alist;
3378 	char	errmsg[DLADM_STRSIZE];
3379 
3380 	format = gettext(format);
3381 	(void) fprintf(stderr, "%s: ", progname);
3382 
3383 	va_start(alist, format);
3384 	(void) vfprintf(stderr, format, alist);
3385 	va_end(alist);
3386 	(void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg));
3387 
3388 	exit(EXIT_FAILURE);
3389 }
3390 
3391 /* PRINTFLIKE1 */
3392 static void
3393 die(const char *format, ...)
3394 {
3395 	va_list alist;
3396 
3397 	format = gettext(format);
3398 	(void) fprintf(stderr, "%s: ", progname);
3399 
3400 	va_start(alist, format);
3401 	(void) vfprintf(stderr, format, alist);
3402 	va_end(alist);
3403 
3404 	(void) putchar('\n');
3405 	exit(EXIT_FAILURE);
3406 }
3407 
3408 static void
3409 die_optdup(int opt)
3410 {
3411 	die("the option -%c cannot be specified more than once", opt);
3412 }
3413 
3414 static void
3415 die_opterr(int opt, int opterr)
3416 {
3417 	switch (opterr) {
3418 	case ':':
3419 		die("option '-%c' requires a value", opt);
3420 		break;
3421 	case '?':
3422 	default:
3423 		die("unrecognized option '-%c'", opt);
3424 		break;
3425 	}
3426 }
3427