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