xref: /titanic_52/usr/src/cmd/dladm/dladm.c (revision 73427c57f824c3ec3b396181b163f37d50c5b3b1)
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]\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_wep_keys(char *str, dladm_wlan_wepkey_t **keys, uint_t *key_countp)
2028 {
2029 	uint_t			i;
2030 	split_t			*sp;
2031 	dladm_wlan_wepkey_t	*wk;
2032 
2033 	sp = split(str, DLADM_WLAN_MAX_WEPKEYS, DLADM_WLAN_MAX_WEPKEYNAME_LEN);
2034 	if (sp == NULL)
2035 		return (-1);
2036 
2037 	wk = malloc(sp->s_nfields * sizeof (dladm_wlan_wepkey_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_WEPKEYNAME_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_WEPKEY_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 	}
2071 	*keys = wk;
2072 	*key_countp = i;
2073 	splitfree(sp);
2074 	return (0);
2075 fail:
2076 	free(wk);
2077 	splitfree(sp);
2078 	return (-1);
2079 }
2080 
2081 static void
2082 do_connect_wifi(int argc, char **argv)
2083 {
2084 	int			option;
2085 	dladm_wlan_attr_t	attr, *attrp;
2086 	dladm_status_t		status = DLADM_STATUS_OK;
2087 	int			timeout = DLADM_WLAN_CONNECT_TIMEOUT_DEFAULT;
2088 	const char		*link = NULL;
2089 	dladm_wlan_wepkey_t	*keys = NULL;
2090 	uint_t			key_count = 0;
2091 	uint_t			flags = 0;
2092 	dladm_wlan_secmode_t	keysecmode = DLADM_WLAN_SECMODE_NONE;
2093 
2094 	opterr = 0;
2095 	(void) memset(&attr, 0, sizeof (attr));
2096 	while ((option = getopt_long(argc, argv, ":e:i:a:m:b:s:k:T:c",
2097 	    wifi_longopts, NULL)) != -1) {
2098 		switch (option) {
2099 		case 'e':
2100 			status = dladm_wlan_str2essid(optarg, &attr.wa_essid);
2101 			if (status != DLADM_STATUS_OK)
2102 				die("invalid ESSID '%s'", optarg);
2103 
2104 			attr.wa_valid |= DLADM_WLAN_ATTR_ESSID;
2105 			/*
2106 			 * Try to connect without doing a scan.
2107 			 */
2108 			flags |= DLADM_WLAN_CONNECT_NOSCAN;
2109 			break;
2110 		case 'i':
2111 			status = dladm_wlan_str2bssid(optarg, &attr.wa_bssid);
2112 			if (status != DLADM_STATUS_OK)
2113 				die("invalid BSSID %s", optarg);
2114 
2115 			attr.wa_valid |= DLADM_WLAN_ATTR_BSSID;
2116 			break;
2117 		case 'a':
2118 			status = dladm_wlan_str2auth(optarg, &attr.wa_auth);
2119 			if (status != DLADM_STATUS_OK)
2120 				die("invalid authentication mode '%s'", optarg);
2121 
2122 			attr.wa_valid |= DLADM_WLAN_ATTR_AUTH;
2123 			break;
2124 		case 'm':
2125 			status = dladm_wlan_str2mode(optarg, &attr.wa_mode);
2126 			if (status != DLADM_STATUS_OK)
2127 				die("invalid mode '%s'", optarg);
2128 
2129 			attr.wa_valid |= DLADM_WLAN_ATTR_MODE;
2130 			break;
2131 		case 'b':
2132 			if ((status = dladm_wlan_str2bsstype(optarg,
2133 			    &attr.wa_bsstype)) != DLADM_STATUS_OK) {
2134 				die("invalid bsstype '%s'", optarg);
2135 			}
2136 
2137 			attr.wa_valid |= DLADM_WLAN_ATTR_BSSTYPE;
2138 			break;
2139 		case 's':
2140 			if ((status = dladm_wlan_str2secmode(optarg,
2141 			    &attr.wa_secmode)) != DLADM_STATUS_OK) {
2142 				die("invalid security mode '%s'", optarg);
2143 			}
2144 
2145 			attr.wa_valid |= DLADM_WLAN_ATTR_SECMODE;
2146 			break;
2147 		case 'k':
2148 			if (parse_wep_keys(optarg, &keys, &key_count) < 0)
2149 				die("invalid key(s) '%s'", optarg);
2150 
2151 			keysecmode = DLADM_WLAN_SECMODE_WEP;
2152 			break;
2153 		case 'T':
2154 			if (strcasecmp(optarg, "forever") == 0) {
2155 				timeout = -1;
2156 				break;
2157 			}
2158 			if (!str2int(optarg, &timeout) || timeout < 0)
2159 				die("invalid timeout value '%s'", optarg);
2160 			break;
2161 		case 'c':
2162 			flags |= DLADM_WLAN_CONNECT_CREATEIBSS;
2163 			break;
2164 		default:
2165 			die_opterr(optopt, option);
2166 			break;
2167 		}
2168 	}
2169 
2170 	if (keysecmode == DLADM_WLAN_SECMODE_NONE) {
2171 		if ((attr.wa_valid & DLADM_WLAN_ATTR_SECMODE) != 0 &&
2172 		    attr.wa_secmode == DLADM_WLAN_SECMODE_WEP)
2173 			die("key required for security mode 'wep'");
2174 	} else {
2175 		if ((attr.wa_valid & DLADM_WLAN_ATTR_SECMODE) != 0 &&
2176 		    attr.wa_secmode != keysecmode)
2177 			die("incompatible -s and -k options");
2178 	}
2179 	attr.wa_secmode = keysecmode;
2180 	attr.wa_valid |= DLADM_WLAN_ATTR_SECMODE;
2181 
2182 	if (optind == (argc - 1))
2183 		link = argv[optind];
2184 	else if (optind != argc)
2185 		usage();
2186 
2187 	if (link == NULL) {
2188 		wlan_count_attr_t wcattr;
2189 
2190 		wcattr.wc_link = NULL;
2191 		wcattr.wc_count = 0;
2192 		(void) dladm_wlan_walk(&wcattr, do_count_wlan);
2193 		if (wcattr.wc_count == 0) {
2194 			die("no wifi links are available");
2195 		} else if (wcattr.wc_count > 1) {
2196 			die("link name is required when more than one wifi "
2197 			    "link is available");
2198 		}
2199 		link = wcattr.wc_link;
2200 	}
2201 	attrp = (attr.wa_valid == 0) ? NULL : &attr;
2202 again:
2203 	if ((status = dladm_wlan_connect(link, attrp, timeout, keys,
2204 	    key_count, flags)) != DLADM_STATUS_OK) {
2205 		if ((flags & DLADM_WLAN_CONNECT_NOSCAN) != 0) {
2206 			/*
2207 			 * Try again with scanning and filtering.
2208 			 */
2209 			flags &= ~DLADM_WLAN_CONNECT_NOSCAN;
2210 			goto again;
2211 		}
2212 
2213 		if (status == DLADM_STATUS_NOTFOUND) {
2214 			if (attr.wa_valid == 0) {
2215 				die("no wifi networks are available");
2216 			} else {
2217 				die("no wifi networks with the specified "
2218 				    "criteria are available");
2219 			}
2220 		}
2221 		die_dlerr(status, "cannot connect link '%s'", link);
2222 	}
2223 	free(keys);
2224 }
2225 
2226 /* ARGSUSED */
2227 static boolean_t
2228 do_all_disconnect_wifi(void *arg, const char *link)
2229 {
2230 	dladm_status_t	status;
2231 
2232 	status = dladm_wlan_disconnect(link);
2233 	if (status != DLADM_STATUS_OK)
2234 		warn_dlerr(status, "cannot disconnect link '%s'", link);
2235 
2236 	return (B_TRUE);
2237 }
2238 
2239 static void
2240 do_disconnect_wifi(int argc, char **argv)
2241 {
2242 	int			option;
2243 	const char		*link = NULL;
2244 	boolean_t		all_links = B_FALSE;
2245 	dladm_status_t		status;
2246 	wlan_count_attr_t	wcattr;
2247 
2248 	opterr = 0;
2249 	while ((option = getopt_long(argc, argv, ":a",
2250 	    wifi_longopts, NULL)) != -1) {
2251 		switch (option) {
2252 		case 'a':
2253 			all_links = B_TRUE;
2254 			break;
2255 		default:
2256 			die_opterr(optopt, option);
2257 			break;
2258 		}
2259 	}
2260 
2261 	if (optind == (argc - 1))
2262 		link = argv[optind];
2263 	else if (optind != argc)
2264 		usage();
2265 
2266 	if (link == NULL) {
2267 		if (!all_links) {
2268 			wcattr.wc_link = NULL;
2269 			wcattr.wc_count = 0;
2270 			(void) dladm_wlan_walk(&wcattr, do_count_wlan);
2271 			if (wcattr.wc_count == 0) {
2272 				die("no wifi links are available");
2273 			} else if (wcattr.wc_count > 1) {
2274 				die("link name is required when more than "
2275 				    "one wifi link is available");
2276 			}
2277 			link = wcattr.wc_link;
2278 		} else {
2279 			(void) dladm_wlan_walk(&all_links,
2280 			    do_all_disconnect_wifi);
2281 			return;
2282 		}
2283 	}
2284 	status = dladm_wlan_disconnect(link);
2285 	if (status != DLADM_STATUS_OK)
2286 		die_dlerr(status, "cannot disconnect link '%s'", link);
2287 }
2288 
2289 #define	MAX_PROPS		32
2290 #define	MAX_PROP_VALS		32
2291 #define	MAX_PROP_LINE		512
2292 
2293 typedef struct prop_info {
2294 	char		*pi_name;
2295 	char		*pi_val[MAX_PROP_VALS];
2296 	uint_t		pi_count;
2297 } prop_info_t;
2298 
2299 typedef struct prop_list {
2300 	prop_info_t	pl_info[MAX_PROPS];
2301 	uint_t		pl_count;
2302 	char		*pl_buf;
2303 } prop_list_t;
2304 
2305 typedef struct show_linkprop_state {
2306 	const char	*ls_link;
2307 	char		*ls_line;
2308 	char		**ls_propvals;
2309 	prop_list_t	*ls_proplist;
2310 	uint32_t	ls_parseable : 1,
2311 			ls_persist : 1,
2312 			ls_header : 1,
2313 			ls_pad_bits : 29;
2314 	dladm_status_t	ls_status;
2315 } show_linkprop_state_t;
2316 
2317 static void
2318 free_props(prop_list_t *list)
2319 {
2320 	if (list != NULL) {
2321 		free(list->pl_buf);
2322 		free(list);
2323 	}
2324 }
2325 
2326 static int
2327 parse_props(char *str, prop_list_t **listp, boolean_t novalues)
2328 {
2329 	prop_list_t	*list;
2330 	prop_info_t	*pip;
2331 	char		*buf, *curr;
2332 	int		len, i;
2333 
2334 	list = malloc(sizeof (prop_list_t));
2335 	if (list == NULL)
2336 		return (-1);
2337 
2338 	list->pl_count = 0;
2339 	list->pl_buf = buf = strdup(str);
2340 	if (buf == NULL)
2341 		goto fail;
2342 
2343 	curr = buf;
2344 	len = strlen(buf);
2345 	pip = NULL;
2346 	for (i = 0; i < len; i++) {
2347 		char		c = buf[i];
2348 		boolean_t	match = (c == '=' || c == ',');
2349 
2350 		if (!match && i != len - 1)
2351 			continue;
2352 
2353 		if (match) {
2354 			buf[i] = '\0';
2355 			if (*curr == '\0')
2356 				goto fail;
2357 		}
2358 
2359 		if (pip != NULL && c != '=') {
2360 			if (pip->pi_count > MAX_PROP_VALS)
2361 				goto fail;
2362 
2363 			if (novalues)
2364 				goto fail;
2365 
2366 			pip->pi_val[pip->pi_count] = curr;
2367 			pip->pi_count++;
2368 		} else {
2369 			if (list->pl_count > MAX_PROPS)
2370 				goto fail;
2371 
2372 			pip = &list->pl_info[list->pl_count];
2373 			pip->pi_name = curr;
2374 			pip->pi_count = 0;
2375 			list->pl_count++;
2376 			if (c == ',')
2377 				pip = NULL;
2378 		}
2379 		curr = buf + i + 1;
2380 	}
2381 	*listp = list;
2382 	return (0);
2383 
2384 fail:
2385 	free_props(list);
2386 	return (-1);
2387 }
2388 
2389 static void
2390 print_linkprop_head(void)
2391 {
2392 	(void) printf("%-12s %-15s %-14s %-14s %-20s \n",
2393 	    "LINK", "PROPERTY", "VALUE", "DEFAULT", "POSSIBLE");
2394 }
2395 
2396 static void
2397 print_linkprop(show_linkprop_state_t *statep, const char *propname,
2398     dladm_prop_type_t type, const char *typename, const char *format,
2399     char **pptr)
2400 {
2401 	int		i;
2402 	char		*ptr, *lim;
2403 	char		buf[DLADM_STRSIZE];
2404 	char		*unknown = "?", *notsup = "";
2405 	char		**propvals = statep->ls_propvals;
2406 	uint_t		valcnt = MAX_PROP_VALS;
2407 	dladm_status_t	status;
2408 
2409 	status = dladm_get_prop(statep->ls_link, type, propname,
2410 	    propvals, &valcnt);
2411 	if (status != DLADM_STATUS_OK) {
2412 		if (status == DLADM_STATUS_TEMPONLY) {
2413 			statep->ls_status = status;
2414 			return;
2415 		} else if (status == DLADM_STATUS_NOTSUP ||
2416 		    statep->ls_persist) {
2417 			valcnt = 1;
2418 			if (type == DLADM_PROP_VAL_CURRENT)
2419 				propvals = &unknown;
2420 			else
2421 				propvals = &notsup;
2422 		} else {
2423 			statep->ls_status = status;
2424 			warn_dlerr(status,
2425 			    "cannot get link property '%s' for %s",
2426 			    propname, statep->ls_link);
2427 			return;
2428 		}
2429 	}
2430 
2431 	ptr = buf;
2432 	lim = buf + DLADM_STRSIZE;
2433 	for (i = 0; i < valcnt; i++) {
2434 		if (propvals[i][0] == '\0' && !statep->ls_parseable)
2435 			ptr += snprintf(ptr, lim - ptr, "--,");
2436 		else
2437 			ptr += snprintf(ptr, lim - ptr, "%s,", propvals[i]);
2438 		if (ptr >= lim)
2439 			break;
2440 	}
2441 	if (valcnt > 0)
2442 		buf[strlen(buf) - 1] = '\0';
2443 
2444 	lim = statep->ls_line + MAX_PROP_LINE;
2445 	if (statep->ls_parseable) {
2446 		*pptr += snprintf(*pptr, lim - *pptr,
2447 		    "%s=\"%s\" ", typename, buf);
2448 	} else {
2449 		*pptr += snprintf(*pptr, lim - *pptr, format, buf);
2450 	}
2451 }
2452 
2453 static boolean_t
2454 show_linkprop(void *arg, const char *propname)
2455 {
2456 	show_linkprop_state_t	*statep = arg;
2457 	char			*ptr = statep->ls_line;
2458 	char			*lim = ptr + MAX_PROP_LINE;
2459 
2460 	if (statep->ls_parseable)
2461 		ptr += snprintf(ptr, lim - ptr, "LINK=\"%s\" ",
2462 		    statep->ls_link);
2463 	else
2464 		ptr += snprintf(ptr, lim - ptr, "%-12s ", statep->ls_link);
2465 
2466 	if (statep->ls_parseable)
2467 		ptr += snprintf(ptr, lim - ptr, "PROPERTY=\"%s\" ", propname);
2468 	else
2469 		ptr += snprintf(ptr, lim - ptr, "%-15s ", propname);
2470 
2471 	print_linkprop(statep, propname,
2472 	    statep->ls_persist ? DLADM_PROP_VAL_PERSISTENT :
2473 	    DLADM_PROP_VAL_CURRENT, "VALUE", "%-14s ", &ptr);
2474 
2475 	/*
2476 	 * If we failed to query the link property, for example, query
2477 	 * the persistent value of a non-persistable link property, simply
2478 	 * skip the output.
2479 	 */
2480 	if (statep->ls_status != DLADM_STATUS_OK)
2481 		return (B_TRUE);
2482 
2483 	print_linkprop(statep, propname, DLADM_PROP_VAL_DEFAULT,
2484 	    "DEFAULT", "%-14s ", &ptr);
2485 	if (statep->ls_status != DLADM_STATUS_OK)
2486 		return (B_TRUE);
2487 
2488 	print_linkprop(statep, propname, DLADM_PROP_VAL_MODIFIABLE,
2489 	    "POSSIBLE", "%-20s ", &ptr);
2490 	if (statep->ls_status != DLADM_STATUS_OK)
2491 		return (B_TRUE);
2492 
2493 	if (statep->ls_header) {
2494 		statep->ls_header = B_FALSE;
2495 		if (!statep->ls_parseable)
2496 			print_linkprop_head();
2497 	}
2498 	(void) printf("%s\n", statep->ls_line);
2499 	return (B_TRUE);
2500 }
2501 
2502 static void
2503 do_show_linkprop(int argc, char **argv)
2504 {
2505 	int			option;
2506 	prop_list_t		*proplist = NULL;
2507 	show_linkprop_state_t	state;
2508 
2509 	opterr = 0;
2510 	state.ls_link = NULL;
2511 	state.ls_propvals = NULL;
2512 	state.ls_line = NULL;
2513 	state.ls_parseable = B_FALSE;
2514 	state.ls_persist = B_FALSE;
2515 	state.ls_header = B_TRUE;
2516 	while ((option = getopt_long(argc, argv, ":p:cP",
2517 	    prop_longopts, NULL)) != -1) {
2518 		switch (option) {
2519 		case 'p':
2520 			if (parse_props(optarg, &proplist, B_TRUE) < 0)
2521 				die("invalid link properties specified");
2522 			break;
2523 		case 'c':
2524 			state.ls_parseable = B_TRUE;
2525 			break;
2526 		case 'P':
2527 			state.ls_persist = B_TRUE;
2528 			break;
2529 		default:
2530 			die_opterr(optopt, option);
2531 			break;
2532 		}
2533 	}
2534 
2535 	if (optind == (argc - 1))
2536 		state.ls_link = argv[optind];
2537 	else if (optind != argc)
2538 		usage();
2539 
2540 	state.ls_proplist = proplist;
2541 	state.ls_status = DLADM_STATUS_OK;
2542 
2543 	if (state.ls_link == NULL) {
2544 		(void) dladm_walk(show_linkprop_onelink, &state);
2545 	} else {
2546 		show_linkprop_onelink(&state, state.ls_link);
2547 	}
2548 	free_props(proplist);
2549 
2550 	if (state.ls_status != DLADM_STATUS_OK)
2551 		exit(EXIT_FAILURE);
2552 }
2553 
2554 static void
2555 show_linkprop_onelink(void *arg, const char *link)
2556 {
2557 	int			i, fd;
2558 	char			linkname[MAXPATHLEN];
2559 	char			*buf;
2560 	dladm_status_t		status;
2561 	prop_list_t		*proplist = NULL;
2562 	show_linkprop_state_t	*statep;
2563 	const char		*savep;
2564 
2565 	statep = (show_linkprop_state_t *)arg;
2566 	savep = statep->ls_link;
2567 	statep->ls_link = link;
2568 	proplist = statep->ls_proplist;
2569 
2570 	/*
2571 	 * When some WiFi links are opened for the first time, their hardware
2572 	 * automatically scans for APs and does other slow operations.	Thus,
2573 	 * if there are no open links, the retrieval of link properties
2574 	 * (below) will proceed slowly unless we hold the link open.
2575 	 */
2576 	(void) snprintf(linkname, MAXPATHLEN, "/dev/%s", link);
2577 	if ((fd = open(linkname, O_RDWR)) < 0) {
2578 		warn("cannot open %s: %s", link, strerror(errno));
2579 		statep->ls_status = DLADM_STATUS_NOTFOUND;
2580 		return;
2581 	}
2582 
2583 	buf = malloc((sizeof (char *) + DLADM_PROP_VAL_MAX) * MAX_PROP_VALS +
2584 	    MAX_PROP_LINE);
2585 	if (buf == NULL)
2586 		die("insufficient memory");
2587 
2588 	statep->ls_propvals = (char **)(void *)buf;
2589 	for (i = 0; i < MAX_PROP_VALS; i++) {
2590 		statep->ls_propvals[i] = buf + sizeof (char *) * MAX_PROP_VALS +
2591 		    i * DLADM_PROP_VAL_MAX;
2592 	}
2593 	statep->ls_line = buf +
2594 	    (sizeof (char *) + DLADM_PROP_VAL_MAX) * MAX_PROP_VALS;
2595 
2596 	if (proplist != NULL) {
2597 		for (i = 0; i < proplist->pl_count; i++)
2598 			(void) show_linkprop(statep,
2599 			    proplist->pl_info[i].pi_name);
2600 	} else {
2601 		status = dladm_walk_prop(link, statep, show_linkprop);
2602 		if (status != DLADM_STATUS_OK)
2603 			warn_dlerr(status, "show-linkprop failed for %s", link);
2604 	}
2605 	(void) close(fd);
2606 	free(buf);
2607 	statep->ls_link = savep;
2608 }
2609 
2610 static dladm_status_t
2611 set_linkprop_persist(const char *link, const char *prop_name, char **prop_val,
2612     uint_t val_cnt, boolean_t reset)
2613 {
2614 	dladm_status_t	status;
2615 	char		*errprop;
2616 
2617 	status = dladm_set_prop(link, prop_name, prop_val, val_cnt,
2618 	    DLADM_OPT_PERSIST, &errprop);
2619 
2620 	if (status != DLADM_STATUS_OK) {
2621 		if (reset) {
2622 			warn_dlerr(status, "cannot persistently reset link "
2623 			    "property '%s' on '%s'", errprop, link);
2624 		} else {
2625 			warn_dlerr(status, "cannot persistently set link "
2626 			    "property '%s' on '%s'", errprop, link);
2627 		}
2628 	}
2629 	return (status);
2630 }
2631 
2632 static void
2633 set_linkprop(int argc, char **argv, boolean_t reset)
2634 {
2635 	int		i, option;
2636 	char		errmsg[DLADM_STRSIZE];
2637 	const char	*link = NULL;
2638 	prop_list_t	*proplist = NULL;
2639 	boolean_t	temp = B_FALSE;
2640 	dladm_status_t	status = DLADM_STATUS_OK;
2641 
2642 	opterr = 0;
2643 	while ((option = getopt_long(argc, argv, ":p:R:t",
2644 	    prop_longopts, NULL)) != -1) {
2645 		switch (option) {
2646 		case 'p':
2647 			if (parse_props(optarg, &proplist, reset) < 0)
2648 				die("invalid link properties specified");
2649 			break;
2650 		case 't':
2651 			temp = B_TRUE;
2652 			break;
2653 		case 'R':
2654 			status = dladm_set_rootdir(optarg);
2655 			if (status != DLADM_STATUS_OK) {
2656 				die_dlerr(status, "invalid directory "
2657 				    "specified");
2658 			}
2659 			break;
2660 		default:
2661 			die_opterr(optopt, option);
2662 			break;
2663 		}
2664 	}
2665 
2666 	if (optind == (argc - 1))
2667 		link = argv[optind];
2668 	else if (optind != argc)
2669 		usage();
2670 
2671 	if (link == NULL)
2672 		die("link name must be specified");
2673 
2674 	if (proplist == NULL) {
2675 		char *errprop;
2676 
2677 		if (!reset)
2678 			die("link property must be specified");
2679 
2680 		status = dladm_set_prop(link, NULL, NULL, 0, DLADM_OPT_TEMP,
2681 		    &errprop);
2682 		if (status != DLADM_STATUS_OK) {
2683 			warn_dlerr(status, "cannot reset link property '%s' "
2684 			    "on '%s'", errprop, link);
2685 		}
2686 		if (!temp) {
2687 			dladm_status_t	s;
2688 
2689 			s = set_linkprop_persist(link, NULL, NULL, 0, reset);
2690 			if (s != DLADM_STATUS_OK)
2691 				status = s;
2692 		}
2693 		goto done;
2694 	}
2695 
2696 	for (i = 0; i < proplist->pl_count; i++) {
2697 		prop_info_t	*pip = &proplist->pl_info[i];
2698 		char		**val;
2699 		uint_t		count;
2700 		dladm_status_t	s;
2701 
2702 		if (reset) {
2703 			val = NULL;
2704 			count = 0;
2705 		} else {
2706 			val = pip->pi_val;
2707 			count = pip->pi_count;
2708 			if (count == 0) {
2709 				warn("no value specified for '%s'",
2710 				    pip->pi_name);
2711 				status = DLADM_STATUS_BADARG;
2712 				continue;
2713 			}
2714 		}
2715 		s = dladm_set_prop(link, pip->pi_name, val, count,
2716 		    DLADM_OPT_TEMP, NULL);
2717 		if (s == DLADM_STATUS_OK) {
2718 			if (!temp) {
2719 				s = set_linkprop_persist(link,
2720 				    pip->pi_name, val, count, reset);
2721 				if (s != DLADM_STATUS_OK)
2722 					status = s;
2723 			}
2724 			continue;
2725 		}
2726 		status = s;
2727 		switch (s) {
2728 		case DLADM_STATUS_NOTFOUND:
2729 			warn("invalid link property '%s'", pip->pi_name);
2730 			break;
2731 		case DLADM_STATUS_BADVAL: {
2732 			int		j;
2733 			char		*ptr, *lim;
2734 			char		**propvals = NULL;
2735 			uint_t		valcnt = MAX_PROP_VALS;
2736 
2737 			ptr = malloc((sizeof (char *) +
2738 			    DLADM_PROP_VAL_MAX) * MAX_PROP_VALS +
2739 			    MAX_PROP_LINE);
2740 
2741 			propvals = (char **)(void *)ptr;
2742 			if (propvals == NULL)
2743 				die("insufficient memory");
2744 
2745 			for (j = 0; j < MAX_PROP_VALS; j++) {
2746 				propvals[j] = ptr + sizeof (char *) *
2747 				    MAX_PROP_VALS +
2748 				    j * DLADM_PROP_VAL_MAX;
2749 			}
2750 			s = dladm_get_prop(link, DLADM_PROP_VAL_MODIFIABLE,
2751 			    pip->pi_name, propvals, &valcnt);
2752 
2753 			ptr = errmsg;
2754 			lim = ptr + DLADM_STRSIZE;
2755 			*ptr = '\0';
2756 			for (j = 0; j < valcnt && s == DLADM_STATUS_OK; j++) {
2757 				ptr += snprintf(ptr, lim - ptr, "%s,",
2758 				    propvals[j]);
2759 				if (ptr >= lim)
2760 					break;
2761 			}
2762 			if (ptr > errmsg) {
2763 				*(ptr - 1) = '\0';
2764 				warn("link property '%s' must be one of: %s",
2765 				    pip->pi_name, errmsg);
2766 			} else
2767 				warn("invalid link property '%s'", *val);
2768 			free(propvals);
2769 			break;
2770 		}
2771 		default:
2772 			if (reset) {
2773 				warn_dlerr(status, "cannot reset link property "
2774 				    "'%s' on '%s'", pip->pi_name, link);
2775 			} else {
2776 				warn_dlerr(status, "cannot set link property "
2777 				    "'%s' on '%s'", pip->pi_name, link);
2778 			}
2779 			break;
2780 		}
2781 	}
2782 done:
2783 	free_props(proplist);
2784 	if (status != DLADM_STATUS_OK)
2785 		exit(1);
2786 }
2787 
2788 static void
2789 do_set_linkprop(int argc, char **argv)
2790 {
2791 	set_linkprop(argc, argv, B_FALSE);
2792 }
2793 
2794 static void
2795 do_reset_linkprop(int argc, char **argv)
2796 {
2797 	set_linkprop(argc, argv, B_TRUE);
2798 }
2799 
2800 static int
2801 convert_secobj(char *buf, uint_t len, uint8_t *obj_val, uint_t *obj_lenp,
2802     dladm_secobj_class_t class)
2803 {
2804 	int error = 0;
2805 
2806 	if (class != DLADM_SECOBJ_CLASS_WEP)
2807 		return (ENOENT);
2808 
2809 	switch (len) {
2810 	case 5:			/* ASCII key sizes */
2811 	case 13:
2812 		(void) memcpy(obj_val, buf, len);
2813 		*obj_lenp = len;
2814 		break;
2815 	case 10:		/* Hex key sizes, not preceded by 0x */
2816 	case 26:
2817 		error = hexascii_to_octet(buf, len, obj_val, obj_lenp);
2818 		break;
2819 	case 12:		/* Hex key sizes, preceded by 0x */
2820 	case 28:
2821 		if (strncmp(buf, "0x", 2) != 0)
2822 			return (EINVAL);
2823 		error = hexascii_to_octet(buf + 2, len - 2, obj_val, obj_lenp);
2824 		break;
2825 	default:
2826 		return (EINVAL);
2827 	}
2828 	return (error);
2829 }
2830 
2831 /* ARGSUSED */
2832 static void
2833 defersig(int sig)
2834 {
2835 	signalled = sig;
2836 }
2837 
2838 static int
2839 get_secobj_from_tty(uint_t try, const char *objname, char *buf)
2840 {
2841 	uint_t		len = 0;
2842 	int		c;
2843 	struct termios	stored, current;
2844 	void		(*sigfunc)(int);
2845 
2846 	/*
2847 	 * Turn off echo -- but before we do so, defer SIGINT handling
2848 	 * so that a ^C doesn't leave the terminal corrupted.
2849 	 */
2850 	sigfunc = signal(SIGINT, defersig);
2851 	(void) fflush(stdin);
2852 	(void) tcgetattr(0, &stored);
2853 	current = stored;
2854 	current.c_lflag &= ~(ICANON|ECHO);
2855 	current.c_cc[VTIME] = 0;
2856 	current.c_cc[VMIN] = 1;
2857 	(void) tcsetattr(0, TCSANOW, &current);
2858 again:
2859 	if (try == 1)
2860 		(void) printf(gettext("provide value for '%s': "), objname);
2861 	else
2862 		(void) printf(gettext("confirm value for '%s': "), objname);
2863 
2864 	(void) fflush(stdout);
2865 	while (signalled == 0) {
2866 		c = getchar();
2867 		if (c == '\n' || c == '\r') {
2868 			if (len != 0)
2869 				break;
2870 			(void) putchar('\n');
2871 			goto again;
2872 		}
2873 
2874 		buf[len++] = c;
2875 		if (len >= DLADM_SECOBJ_VAL_MAX - 1)
2876 			break;
2877 		(void) putchar('*');
2878 	}
2879 
2880 	(void) putchar('\n');
2881 	(void) fflush(stdin);
2882 
2883 	/*
2884 	 * Restore terminal setting and handle deferred signals.
2885 	 */
2886 	(void) tcsetattr(0, TCSANOW, &stored);
2887 
2888 	(void) signal(SIGINT, sigfunc);
2889 	if (signalled != 0)
2890 		(void) kill(getpid(), signalled);
2891 
2892 	return (len);
2893 }
2894 
2895 static int
2896 get_secobj_val(char *obj_name, uint8_t *obj_val, uint_t *obj_lenp,
2897     dladm_secobj_class_t class, FILE *filep)
2898 {
2899 	int		rval;
2900 	uint_t		len, len2;
2901 	char		buf[DLADM_SECOBJ_VAL_MAX], buf2[DLADM_SECOBJ_VAL_MAX];
2902 
2903 	if (filep == NULL) {
2904 		len = get_secobj_from_tty(1, obj_name, buf);
2905 		rval = convert_secobj(buf, len, obj_val, obj_lenp, class);
2906 		if (rval == 0) {
2907 			len2 = get_secobj_from_tty(2, obj_name, buf2);
2908 			if (len != len2 || memcmp(buf, buf2, len) != 0)
2909 				rval = ENOTSUP;
2910 		}
2911 		return (rval);
2912 	} else {
2913 		for (;;) {
2914 			if (fgets(buf, sizeof (buf), filep) == NULL)
2915 				break;
2916 			if (isspace(buf[0]))
2917 				continue;
2918 
2919 			len = strlen(buf);
2920 			if (buf[len - 1] == '\n') {
2921 				buf[len - 1] = '\0';
2922 				len--;
2923 			}
2924 			break;
2925 		}
2926 		(void) fclose(filep);
2927 	}
2928 	return (convert_secobj(buf, len, obj_val, obj_lenp, class));
2929 }
2930 
2931 static boolean_t
2932 check_auth(const char *auth)
2933 {
2934 	struct passwd	*pw;
2935 
2936 	if ((pw = getpwuid(getuid())) == NULL)
2937 		return (B_FALSE);
2938 
2939 	return (chkauthattr(auth, pw->pw_name) != 0);
2940 }
2941 
2942 static void
2943 audit_secobj(char *auth, char *class, char *obj,
2944     boolean_t success, boolean_t create)
2945 {
2946 	adt_session_data_t	*ah;
2947 	adt_event_data_t	*event;
2948 	au_event_t		flag;
2949 	char			*errstr;
2950 
2951 	if (create) {
2952 		flag = ADT_dladm_create_secobj;
2953 		errstr = "ADT_dladm_create_secobj";
2954 	} else {
2955 		flag = ADT_dladm_delete_secobj;
2956 		errstr = "ADT_dladm_delete_secobj";
2957 	}
2958 
2959 	if (adt_start_session(&ah, NULL, ADT_USE_PROC_DATA) != 0)
2960 		die("adt_start_session: %s", strerror(errno));
2961 
2962 	if ((event = adt_alloc_event(ah, flag)) == NULL)
2963 		die("adt_alloc_event (%s): %s", errstr, strerror(errno));
2964 
2965 	/* fill in audit info */
2966 	if (create) {
2967 		event->adt_dladm_create_secobj.auth_used = auth;
2968 		event->adt_dladm_create_secobj.obj_class = class;
2969 		event->adt_dladm_create_secobj.obj_name = obj;
2970 	} else {
2971 		event->adt_dladm_delete_secobj.auth_used = auth;
2972 		event->adt_dladm_delete_secobj.obj_class = class;
2973 		event->adt_dladm_delete_secobj.obj_name = obj;
2974 	}
2975 
2976 	if (success) {
2977 		if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS) != 0) {
2978 			die("adt_put_event (%s, success): %s", errstr,
2979 			    strerror(errno));
2980 		}
2981 	} else {
2982 		if (adt_put_event(event, ADT_FAILURE,
2983 		    ADT_FAIL_VALUE_AUTH) != 0) {
2984 			die("adt_put_event: (%s, failure): %s", errstr,
2985 			    strerror(errno));
2986 		}
2987 	}
2988 
2989 	adt_free_event(event);
2990 	(void) adt_end_session(ah);
2991 }
2992 
2993 #define	MAX_SECOBJS		32
2994 #define	MAX_SECOBJ_NAMELEN	32
2995 static void
2996 do_create_secobj(int argc, char **argv)
2997 {
2998 	int			option, rval;
2999 	FILE			*filep = NULL;
3000 	char			*obj_name = NULL;
3001 	char			*class_name = NULL;
3002 	uint8_t			obj_val[DLADM_SECOBJ_VAL_MAX];
3003 	uint_t			obj_len;
3004 	boolean_t		success, temp = B_FALSE;
3005 	dladm_status_t		status;
3006 	dladm_secobj_class_t	class = -1;
3007 	uid_t			euid;
3008 
3009 	opterr = 0;
3010 	(void) memset(obj_val, 0, DLADM_SECOBJ_VAL_MAX);
3011 	while ((option = getopt_long(argc, argv, ":f:c:R:t",
3012 	    wifi_longopts, NULL)) != -1) {
3013 		switch (option) {
3014 		case 'f':
3015 			euid = geteuid();
3016 			(void) seteuid(getuid());
3017 			filep = fopen(optarg, "r");
3018 			if (filep == NULL) {
3019 				die("cannot open %s: %s", optarg,
3020 				    strerror(errno));
3021 			}
3022 			(void) seteuid(euid);
3023 			break;
3024 		case 'c':
3025 			class_name = optarg;
3026 			status = dladm_str2secobjclass(optarg, &class);
3027 			if (status != DLADM_STATUS_OK) {
3028 				die("invalid secure object class '%s', "
3029 				    "valid values are: wep", optarg);
3030 			}
3031 			break;
3032 		case 't':
3033 			temp = B_TRUE;
3034 			break;
3035 		case 'R':
3036 			status = dladm_set_rootdir(optarg);
3037 			if (status != DLADM_STATUS_OK) {
3038 				die_dlerr(status, "invalid directory "
3039 				    "specified");
3040 			}
3041 			break;
3042 		default:
3043 			die_opterr(optopt, option);
3044 			break;
3045 		}
3046 	}
3047 
3048 	if (optind == (argc - 1))
3049 		obj_name = argv[optind];
3050 	else if (optind != argc)
3051 		usage();
3052 
3053 	if (class == -1)
3054 		die("secure object class required");
3055 
3056 	if (obj_name == NULL)
3057 		die("secure object name required");
3058 
3059 	success = check_auth(LINK_SEC_AUTH);
3060 	audit_secobj(LINK_SEC_AUTH, class_name, obj_name, success, B_TRUE);
3061 	if (!success)
3062 		die("authorization '%s' is required", LINK_SEC_AUTH);
3063 
3064 	rval = get_secobj_val(obj_name, obj_val, &obj_len, class, filep);
3065 	if (rval != 0) {
3066 		switch (rval) {
3067 		case ENOENT:
3068 			die("invalid secure object class");
3069 			break;
3070 		case EINVAL:
3071 			die("invalid secure object value");
3072 			break;
3073 		case ENOTSUP:
3074 			die("verification failed");
3075 			break;
3076 		default:
3077 			die("invalid secure object: %s", strerror(rval));
3078 			break;
3079 		}
3080 	}
3081 
3082 	status = dladm_set_secobj(obj_name, class, obj_val, obj_len,
3083 	    DLADM_OPT_CREATE | DLADM_OPT_TEMP);
3084 	if (status != DLADM_STATUS_OK) {
3085 		die_dlerr(status, "could not create secure object '%s'",
3086 		    obj_name);
3087 	}
3088 	if (temp)
3089 		return;
3090 
3091 	status = dladm_set_secobj(obj_name, class, obj_val, obj_len,
3092 	    DLADM_OPT_PERSIST);
3093 	if (status != DLADM_STATUS_OK) {
3094 		warn_dlerr(status, "could not persistently create secure "
3095 		    "object '%s'", obj_name);
3096 	}
3097 }
3098 
3099 static void
3100 do_delete_secobj(int argc, char **argv)
3101 {
3102 	int		i, option;
3103 	boolean_t	temp = B_FALSE;
3104 	split_t		*sp = NULL;
3105 	boolean_t	success;
3106 	dladm_status_t	status, pstatus;
3107 
3108 	opterr = 0;
3109 	status = pstatus = DLADM_STATUS_OK;
3110 	while ((option = getopt_long(argc, argv, ":R:t",
3111 	    wifi_longopts, NULL)) != -1) {
3112 		switch (option) {
3113 		case 't':
3114 			temp = B_TRUE;
3115 			break;
3116 		case 'R':
3117 			status = dladm_set_rootdir(optarg);
3118 			if (status != DLADM_STATUS_OK) {
3119 				die_dlerr(status, "invalid directory "
3120 				    "specified");
3121 			}
3122 			break;
3123 		default:
3124 			die_opterr(optopt, option);
3125 			break;
3126 		}
3127 	}
3128 
3129 	if (optind == (argc - 1)) {
3130 		sp = split(argv[optind], MAX_SECOBJS, MAX_SECOBJ_NAMELEN);
3131 		if (sp == NULL) {
3132 			die("invalid secure object name(s): '%s'",
3133 			    argv[optind]);
3134 		}
3135 	} else if (optind != argc)
3136 		usage();
3137 
3138 	if (sp == NULL || sp->s_nfields < 1)
3139 		die("secure object name required");
3140 
3141 	success = check_auth(LINK_SEC_AUTH);
3142 	audit_secobj(LINK_SEC_AUTH, "wep", argv[optind], success, B_FALSE);
3143 	if (!success)
3144 		die("authorization '%s' is required", LINK_SEC_AUTH);
3145 
3146 	for (i = 0; i < sp->s_nfields; i++) {
3147 		status = dladm_unset_secobj(sp->s_fields[i], DLADM_OPT_TEMP);
3148 		if (!temp) {
3149 			pstatus = dladm_unset_secobj(sp->s_fields[i],
3150 			    DLADM_OPT_PERSIST);
3151 		} else {
3152 			pstatus = DLADM_STATUS_OK;
3153 		}
3154 
3155 		if (status != DLADM_STATUS_OK) {
3156 			warn_dlerr(status, "could not delete secure object "
3157 			    "'%s'", sp->s_fields[i]);
3158 		}
3159 		if (pstatus != DLADM_STATUS_OK) {
3160 			warn_dlerr(pstatus, "could not persistently delete "
3161 			    "secure object '%s'", sp->s_fields[i]);
3162 		}
3163 	}
3164 	if (status != DLADM_STATUS_OK || pstatus != DLADM_STATUS_OK)
3165 		exit(1);
3166 }
3167 
3168 typedef struct show_secobj_state {
3169 	boolean_t	ss_persist;
3170 	boolean_t	ss_parseable;
3171 	boolean_t	ss_debug;
3172 	boolean_t	ss_header;
3173 } show_secobj_state_t;
3174 
3175 static void
3176 print_secobj_head(show_secobj_state_t *statep)
3177 {
3178 	(void) printf("%-20s %-20s ", "OBJECT", "CLASS");
3179 	if (statep->ss_debug)
3180 		(void) printf("%-30s", "VALUE");
3181 	(void) putchar('\n');
3182 }
3183 
3184 static boolean_t
3185 show_secobj(void *arg, const char *obj_name)
3186 {
3187 	uint_t			obj_len = DLADM_SECOBJ_VAL_MAX;
3188 	uint8_t			obj_val[DLADM_SECOBJ_VAL_MAX];
3189 	char			buf[DLADM_STRSIZE];
3190 	uint_t			flags = 0;
3191 	dladm_secobj_class_t	class;
3192 	show_secobj_state_t	*statep = arg;
3193 	dladm_status_t		status;
3194 
3195 	if (statep->ss_persist)
3196 		flags |= DLADM_OPT_PERSIST;
3197 
3198 	status = dladm_get_secobj(obj_name, &class, obj_val, &obj_len, flags);
3199 	if (status != DLADM_STATUS_OK)
3200 		die_dlerr(status, "cannot get secure object '%s'", obj_name);
3201 
3202 	if (statep->ss_header) {
3203 		statep->ss_header = B_FALSE;
3204 		if (!statep->ss_parseable)
3205 			print_secobj_head(statep);
3206 	}
3207 
3208 	if (statep->ss_parseable) {
3209 		(void) printf("OBJECT=\"%s\" CLASS=\"%s\" ", obj_name,
3210 		    dladm_secobjclass2str(class, buf));
3211 	} else {
3212 		(void) printf("%-20s %-20s ", obj_name,
3213 		    dladm_secobjclass2str(class, buf));
3214 	}
3215 
3216 	if (statep->ss_debug) {
3217 		char	val[DLADM_SECOBJ_VAL_MAX * 2];
3218 		uint_t	len = sizeof (val);
3219 
3220 		if (octet_to_hexascii(obj_val, obj_len, val, &len) == 0) {
3221 			if (statep->ss_parseable)
3222 				(void) printf("VALUE=\"0x%s\"", val);
3223 			else
3224 				(void) printf("0x%-30s", val);
3225 		}
3226 	}
3227 	(void) putchar('\n');
3228 	return (B_TRUE);
3229 }
3230 
3231 static void
3232 do_show_secobj(int argc, char **argv)
3233 {
3234 	int			option;
3235 	show_secobj_state_t	state;
3236 	dladm_status_t		status;
3237 	uint_t			i;
3238 	split_t			*sp;
3239 	uint_t			flags;
3240 
3241 	opterr = 0;
3242 	state.ss_persist = B_FALSE;
3243 	state.ss_parseable = B_FALSE;
3244 	state.ss_debug = B_FALSE;
3245 	state.ss_header = B_TRUE;
3246 	while ((option = getopt_long(argc, argv, ":pPd",
3247 	    wifi_longopts, NULL)) != -1) {
3248 		switch (option) {
3249 		case 'p':
3250 			state.ss_parseable = B_TRUE;
3251 			break;
3252 		case 'P':
3253 			state.ss_persist = B_TRUE;
3254 			break;
3255 		case 'd':
3256 			if (getuid() != 0)
3257 				die("insufficient privileges");
3258 			state.ss_debug = B_TRUE;
3259 			break;
3260 		default:
3261 			die_opterr(optopt, option);
3262 			break;
3263 		}
3264 	}
3265 
3266 	if (optind == (argc - 1)) {
3267 		sp = split(argv[optind], MAX_SECOBJS, MAX_SECOBJ_NAMELEN);
3268 		if (sp == NULL) {
3269 			die("invalid secure object name(s): '%s'",
3270 			    argv[optind]);
3271 		}
3272 		for (i = 0; i < sp->s_nfields; i++) {
3273 			if (!show_secobj(&state, sp->s_fields[i]))
3274 				break;
3275 		}
3276 		splitfree(sp);
3277 		return;
3278 	} else if (optind != argc)
3279 		usage();
3280 
3281 	flags = state.ss_persist ? DLADM_OPT_PERSIST : 0;
3282 	status = dladm_walk_secobj(&state, show_secobj, flags);
3283 	if (status != DLADM_STATUS_OK)
3284 		die_dlerr(status, "show-secobj");
3285 }
3286 
3287 /* ARGSUSED */
3288 static void
3289 do_init_linkprop(int argc, char **argv)
3290 {
3291 	dladm_status_t status;
3292 
3293 	status = dladm_init_linkprop();
3294 	if (status != DLADM_STATUS_OK)
3295 		die_dlerr(status, "link property initialization failed");
3296 }
3297 
3298 /* ARGSUSED */
3299 static void
3300 do_init_secobj(int argc, char **argv)
3301 {
3302 	dladm_status_t status;
3303 
3304 	status = dladm_init_secobj();
3305 	if (status != DLADM_STATUS_OK)
3306 		die_dlerr(status, "secure object initialization failed");
3307 }
3308 
3309 static boolean_t
3310 str2int(const char *str, int *valp)
3311 {
3312 	int	val;
3313 	char	*endp = NULL;
3314 
3315 	errno = 0;
3316 	val = strtol(str, &endp, 10);
3317 	if (errno != 0 || *endp != '\0')
3318 		return (B_FALSE);
3319 
3320 	*valp = val;
3321 	return (B_TRUE);
3322 }
3323 
3324 /* PRINTFLIKE1 */
3325 static void
3326 warn(const char *format, ...)
3327 {
3328 	va_list alist;
3329 
3330 	format = gettext(format);
3331 	(void) fprintf(stderr, "%s: warning: ", progname);
3332 
3333 	va_start(alist, format);
3334 	(void) vfprintf(stderr, format, alist);
3335 	va_end(alist);
3336 
3337 	(void) putchar('\n');
3338 }
3339 
3340 /* PRINTFLIKE2 */
3341 static void
3342 warn_dlerr(dladm_status_t err, const char *format, ...)
3343 {
3344 	va_list alist;
3345 	char	errmsg[DLADM_STRSIZE];
3346 
3347 	format = gettext(format);
3348 	(void) fprintf(stderr, gettext("%s: warning: "), progname);
3349 
3350 	va_start(alist, format);
3351 	(void) vfprintf(stderr, format, alist);
3352 	va_end(alist);
3353 	(void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg));
3354 }
3355 
3356 /* PRINTFLIKE2 */
3357 static void
3358 die_dlerr(dladm_status_t err, const char *format, ...)
3359 {
3360 	va_list alist;
3361 	char	errmsg[DLADM_STRSIZE];
3362 
3363 	format = gettext(format);
3364 	(void) fprintf(stderr, "%s: ", progname);
3365 
3366 	va_start(alist, format);
3367 	(void) vfprintf(stderr, format, alist);
3368 	va_end(alist);
3369 	(void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg));
3370 
3371 	exit(EXIT_FAILURE);
3372 }
3373 
3374 /* PRINTFLIKE1 */
3375 static void
3376 die(const char *format, ...)
3377 {
3378 	va_list alist;
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 
3387 	(void) putchar('\n');
3388 	exit(EXIT_FAILURE);
3389 }
3390 
3391 static void
3392 die_optdup(int opt)
3393 {
3394 	die("the option -%c cannot be specified more than once", opt);
3395 }
3396 
3397 static void
3398 die_opterr(int opt, int opterr)
3399 {
3400 	switch (opterr) {
3401 	case ':':
3402 		die("option '-%c' requires a value", opt);
3403 		break;
3404 	case '?':
3405 	default:
3406 		die("unrecognized option '-%c'", opt);
3407 		break;
3408 	}
3409 }
3410