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