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 /*
  23  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
  24  * Copyright 2016 Nexenta Systems, Inc.
  25  * Copyright (c) 2015 Joyent, Inc. All rights reserved.
  26  * Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
  27  * Copyright 2020 Peter Tribble.
  28  */
  29 
  30 #include <stdio.h>
  31 #include <ctype.h>
  32 #include <dlfcn.h>
  33 #include <locale.h>
  34 #include <signal.h>
  35 #include <stdarg.h>
  36 #include <stdlib.h>
  37 #include <fcntl.h>
  38 #include <string.h>
  39 #include <stropts.h>
  40 #include <sys/stat.h>
  41 #include <errno.h>
  42 #include <kstat.h>
  43 #include <strings.h>
  44 #include <getopt.h>
  45 #include <unistd.h>
  46 #include <priv.h>
  47 #include <limits.h>
  48 #include <termios.h>
  49 #include <pwd.h>
  50 #include <auth_attr.h>
  51 #include <auth_list.h>
  52 #include <libintl.h>
  53 #include <libdevinfo.h>
  54 #include <libdlpi.h>
  55 #include <libdladm.h>
  56 #include <libdllink.h>
  57 #include <libdlstat.h>
  58 #include <libdlaggr.h>
  59 #include <libdlwlan.h>
  60 #include <libdlvlan.h>
  61 #include <libdlvnic.h>
  62 #include <libdlib.h>
  63 #include <libdlether.h>
  64 #include <libdliptun.h>
  65 #include <libdlsim.h>
  66 #include <libdlbridge.h>
  67 #include <libdloverlay.h>
  68 #include <libinetutil.h>
  69 #include <libvrrpadm.h>
  70 #include <bsm/adt.h>
  71 #include <bsm/adt_event.h>
  72 #include <libdlvnic.h>
  73 #include <sys/types.h>
  74 #include <sys/socket.h>
  75 #include <sys/ib/ib_types.h>
  76 #include <sys/processor.h>
  77 #include <netinet/in.h>
  78 #include <arpa/inet.h>
  79 #include <net/if_types.h>
  80 #include <stddef.h>
  81 #include <stp_in.h>
  82 #include <ofmt.h>
  83 #include <libcustr.h>
  84 
  85 #define MAXPORT                 256
  86 #define MAXVNIC                 256
  87 #define BUFLEN(lim, ptr)        (((lim) > (ptr)) ? ((lim) - (ptr)) : 0)
  88 #define MAXLINELEN              1024
  89 #define SMF_UPGRADE_FILE                "/var/svc/profile/upgrade"
  90 #define SMF_UPGRADEDATALINK_FILE        "/var/svc/profile/upgrade_datalink"
  91 #define SMF_DLADM_UPGRADE_MSG           " # added by dladm(1M)"
  92 #define DLADM_DEFAULT_COL       80
  93 
  94 /*
  95  * used by the wifi show-* commands to set up ofmt_field_t structures.
  96  */
  97 #define WIFI_CMD_SCAN           0x00000001
  98 #define WIFI_CMD_SHOW           0x00000002
  99 #define WIFI_CMD_ALL            (WIFI_CMD_SCAN | WIFI_CMD_SHOW)
 100 
 101 /* No larger than pktsum_t */
 102 typedef struct brsum_s {
 103         uint64_t        drops;
 104         uint64_t        forward_dir;
 105         uint64_t        forward_mb;
 106         uint64_t        forward_unk;
 107         uint64_t        recv;
 108         uint64_t        sent;
 109 } brsum_t;
 110 
 111 /* No larger than pktsum_t */
 112 typedef struct brlsum_s {
 113         uint32_t        cfgbpdu;
 114         uint32_t        tcnbpdu;
 115         uint32_t        rstpbpdu;
 116         uint32_t        txbpdu;
 117         uint64_t        drops;
 118         uint64_t        recv;
 119         uint64_t        xmit;
 120 } brlsum_t;
 121 
 122 typedef struct show_state {
 123         boolean_t       ls_firstonly;
 124         boolean_t       ls_donefirst;
 125         pktsum_t        ls_prevstats;
 126         uint32_t        ls_flags;
 127         dladm_status_t  ls_status;
 128         ofmt_handle_t   ls_ofmt;
 129         boolean_t       ls_parsable;
 130         boolean_t       ls_mac;
 131         boolean_t       ls_hwgrp;
 132 } show_state_t;
 133 
 134 typedef struct show_grp_state {
 135         pktsum_t        gs_prevstats[MAXPORT];
 136         uint32_t        gs_flags;
 137         dladm_status_t  gs_status;
 138         boolean_t       gs_parsable;
 139         boolean_t       gs_lacp;
 140         boolean_t       gs_extended;
 141         boolean_t       gs_stats;
 142         boolean_t       gs_firstonly;
 143         boolean_t       gs_donefirst;
 144         ofmt_handle_t   gs_ofmt;
 145 } show_grp_state_t;
 146 
 147 typedef struct show_vnic_state {
 148         datalink_id_t   vs_vnic_id;
 149         datalink_id_t   vs_link_id;
 150         char            vs_vnic[MAXLINKNAMELEN];
 151         char            vs_link[MAXLINKNAMELEN];
 152         boolean_t       vs_parsable;
 153         boolean_t       vs_found;
 154         boolean_t       vs_firstonly;
 155         boolean_t       vs_donefirst;
 156         boolean_t       vs_stats;
 157         boolean_t       vs_printstats;
 158         pktsum_t        vs_totalstats;
 159         pktsum_t        vs_prevstats[MAXVNIC];
 160         boolean_t       vs_etherstub;
 161         dladm_status_t  vs_status;
 162         uint32_t        vs_flags;
 163         ofmt_handle_t   vs_ofmt;
 164 } show_vnic_state_t;
 165 
 166 typedef struct show_part_state {
 167         datalink_id_t   ps_over_id;
 168         char            ps_part[MAXLINKNAMELEN];
 169         boolean_t       ps_parsable;
 170         boolean_t       ps_found;
 171         dladm_status_t  ps_status;
 172         uint32_t        ps_flags;
 173         ofmt_handle_t   ps_ofmt;
 174 } show_part_state_t;
 175 
 176 typedef struct show_ib_state {
 177         datalink_id_t   is_link_id;
 178         char            is_link[MAXLINKNAMELEN];
 179         boolean_t       is_parsable;
 180         dladm_status_t  is_status;
 181         uint32_t        is_flags;
 182         ofmt_handle_t   is_ofmt;
 183 } show_ib_state_t;
 184 
 185 typedef struct show_usage_state_s {
 186         boolean_t       us_plot;
 187         boolean_t       us_parsable;
 188         boolean_t       us_printheader;
 189         boolean_t       us_first;
 190         boolean_t       us_showall;
 191         ofmt_handle_t   us_ofmt;
 192 } show_usage_state_t;
 193 
 194 typedef struct show_overlay_request_s {
 195         boolean_t       sor_failed;
 196         ofmt_handle_t   sor_ofmt;
 197 } show_overlay_request_t;
 198 
 199 /*
 200  * callback functions for printing output and error diagnostics.
 201  */
 202 static ofmt_cb_t print_default_cb, print_link_stats_cb, print_linkprop_cb;
 203 static ofmt_cb_t print_lacp_cb, print_phys_one_mac_cb;
 204 static ofmt_cb_t print_xaggr_cb, print_aggr_stats_cb;
 205 static ofmt_cb_t print_phys_one_hwgrp_cb, print_wlan_attr_cb;
 206 static ofmt_cb_t print_wifi_status_cb, print_link_attr_cb;
 207 static ofmt_cb_t print_overlay_cb, print_overlay_fma_cb, print_overlay_targ_cb;
 208 
 209 typedef void cmdfunc_t(int, char **, const char *);
 210 
 211 static cmdfunc_t do_show_link, do_show_wifi, do_show_phys;
 212 static cmdfunc_t do_create_aggr, do_delete_aggr, do_add_aggr, do_remove_aggr;
 213 static cmdfunc_t do_modify_aggr, do_show_aggr, do_up_aggr;
 214 static cmdfunc_t do_scan_wifi, do_connect_wifi, do_disconnect_wifi;
 215 static cmdfunc_t do_show_linkprop, do_set_linkprop, do_reset_linkprop;
 216 static cmdfunc_t do_create_secobj, do_delete_secobj, do_show_secobj;
 217 static cmdfunc_t do_init_linkprop, do_init_secobj;
 218 static cmdfunc_t do_create_vlan, do_delete_vlan, do_up_vlan, do_show_vlan;
 219 static cmdfunc_t do_rename_link, do_delete_phys, do_init_phys;
 220 static cmdfunc_t do_show_linkmap;
 221 static cmdfunc_t do_show_ether;
 222 static cmdfunc_t do_create_vnic, do_delete_vnic, do_show_vnic;
 223 static cmdfunc_t do_up_vnic;
 224 static cmdfunc_t do_create_part, do_delete_part, do_show_part, do_show_ib;
 225 static cmdfunc_t do_up_part;
 226 static cmdfunc_t do_create_etherstub, do_delete_etherstub, do_show_etherstub;
 227 static cmdfunc_t do_create_simnet, do_modify_simnet;
 228 static cmdfunc_t do_delete_simnet, do_show_simnet, do_up_simnet;
 229 static cmdfunc_t do_show_usage;
 230 static cmdfunc_t do_create_bridge, do_modify_bridge, do_delete_bridge;
 231 static cmdfunc_t do_add_bridge, do_remove_bridge, do_show_bridge;
 232 static cmdfunc_t do_create_iptun, do_modify_iptun, do_delete_iptun;
 233 static cmdfunc_t do_show_iptun, do_up_iptun, do_down_iptun;
 234 static cmdfunc_t do_create_overlay, do_delete_overlay, do_modify_overlay;
 235 static cmdfunc_t do_show_overlay, do_up_overlay;
 236 
 237 static void     do_up_vnic_common(int, char **, const char *, boolean_t);
 238 
 239 static int show_part(dladm_handle_t, datalink_id_t, void *);
 240 
 241 static void     altroot_cmd(char *, int, char **);
 242 static int      show_linkprop_onelink(dladm_handle_t, datalink_id_t, void *);
 243 
 244 static void     link_stats(datalink_id_t, uint_t, char *, show_state_t *);
 245 static void     aggr_stats(datalink_id_t, show_grp_state_t *, uint_t);
 246 static void     vnic_stats(show_vnic_state_t *, uint32_t);
 247 
 248 static int      get_one_kstat(const char *, const char *, uint8_t,
 249                     void *, boolean_t);
 250 static void     get_mac_stats(const char *, pktsum_t *);
 251 static void     get_link_stats(const char *, pktsum_t *);
 252 static uint64_t get_ifspeed(const char *, boolean_t);
 253 static const char       *get_linkstate(const char *, boolean_t, char *);
 254 static const char       *get_linkduplex(const char *, boolean_t, char *);
 255 
 256 static iptun_type_t     iptun_gettypebyname(char *);
 257 static const char       *iptun_gettypebyvalue(iptun_type_t);
 258 static dladm_status_t   print_iptun(dladm_handle_t, datalink_id_t,
 259                             show_state_t *);
 260 static int      print_iptun_walker(dladm_handle_t, datalink_id_t, void *);
 261 
 262 static int      show_etherprop(dladm_handle_t, datalink_id_t, void *);
 263 static void     show_ether_xprop(void *, dladm_ether_info_t *);
 264 static boolean_t        link_is_ether(const char *, datalink_id_t *);
 265 
 266 static boolean_t str2int(const char *, int *);
 267 static void     die(const char *, ...);
 268 static void     die_optdup(int);
 269 static void     die_opterr(int, int, const char *);
 270 static void     die_dlerr(dladm_status_t, const char *, ...);
 271 static void     die_dlerrlist(dladm_status_t, dladm_errlist_t *,
 272     const char *, ...);
 273 static void     warn(const char *, ...);
 274 static void     warn_dlerr(dladm_status_t, const char *, ...);
 275 static void     warn_dlerrlist(dladm_errlist_t *);
 276 
 277 typedef struct  cmd {
 278         char            *c_name;
 279         cmdfunc_t       *c_fn;
 280         const char      *c_usage;
 281 } cmd_t;
 282 
 283 static cmd_t    cmds[] = {
 284         { "rename-link",        do_rename_link,
 285             "    rename-link      <oldlink> <newlink>"                      },
 286         { "show-link",          do_show_link,
 287             "    show-link        [-pP] [-o <field>,..] [-s [-i <interval>]] "
 288             "[<link>]\n"                                          },
 289         { "create-aggr",        do_create_aggr,
 290             "    create-aggr      [-t] [-P <policy>] [-L <mode>] [-T <time>] "
 291             "[-u <address>]\n"
 292             "\t\t     -l <link> [-l <link>...] <link>"                        },
 293         { "delete-aggr",        do_delete_aggr,
 294             "    delete-aggr      [-t] <link>"                            },
 295         { "add-aggr",           do_add_aggr,
 296             "    add-aggr         [-t] -l <link> [-l <link>...] <link>" },
 297         { "remove-aggr",        do_remove_aggr,
 298             "    remove-aggr      [-t] -l <link> [-l <link>...] <link>" },
 299         { "modify-aggr",        do_modify_aggr,
 300             "    modify-aggr      [-t] [-P <policy>] [-L <mode>] [-T <time>] "
 301             "[-u <address>]\n"
 302             "\t\t     <link>"                                             },
 303         { "show-aggr",          do_show_aggr,
 304             "    show-aggr        [-pPLx] [-o <field>,..] [-s [-i <interval>]] "
 305             "[<link>]\n"                                          },
 306         { "up-aggr",            do_up_aggr,     NULL                    },
 307         { "scan-wifi",          do_scan_wifi,
 308             "    scan-wifi        [-p] [-o <field>,...] [<link>]"   },
 309         { "connect-wifi",       do_connect_wifi,
 310             "    connect-wifi     [-e <essid>] [-i <bssid>] [-k <key>,...] "
 311             "[-s wep|wpa]\n"
 312             "\t\t     [-a open|shared] [-b bss|ibss] [-c] [-m a|b|g] "
 313             "[-T <time>]\n"
 314             "\t\t     [<link>]"                                           },
 315         { "disconnect-wifi",    do_disconnect_wifi,
 316             "    disconnect-wifi  [-a] [<link>]"                  },
 317         { "show-wifi",          do_show_wifi,
 318             "    show-wifi        [-p] [-o <field>,...] [<link>]\n" },
 319         { "set-linkprop",       do_set_linkprop,
 320             "    set-linkprop     [-t] -p <prop>=<value>[,...] <name>"        },
 321         { "reset-linkprop",     do_reset_linkprop,
 322             "    reset-linkprop   [-t] [-p <prop>,...] <name>"              },
 323         { "show-linkprop",      do_show_linkprop,
 324             "    show-linkprop    [-cP] [-o <field>,...] [-p <prop>,...] "
 325             "<name>\n"                                                    },
 326         { "show-ether",         do_show_ether,
 327             "    show-ether       [-px][-o <field>,...] <link>\n"   },
 328         { "create-secobj",      do_create_secobj,
 329             "    create-secobj    [-t] [-f <file>] -c <class> <secobj>"       },
 330         { "delete-secobj",      do_delete_secobj,
 331             "    delete-secobj    [-t] <secobj>[,...]"                    },
 332         { "show-secobj",        do_show_secobj,
 333             "    show-secobj      [-pP] [-o <field>,...] [<secobj>,...]\n" },
 334         { "init-linkprop",      do_init_linkprop,       NULL            },
 335         { "init-secobj",        do_init_secobj,         NULL            },
 336         { "create-vlan",        do_create_vlan,
 337             "    create-vlan      [-ft] -l <link> -v <vid> [link]"  },
 338         { "delete-vlan",        do_delete_vlan,
 339             "    delete-vlan      [-t] <link>"                            },
 340         { "show-vlan",          do_show_vlan,
 341             "    show-vlan        [-pP] [-o <field>,..] [<link>]\n" },
 342         { "up-vlan",            do_up_vlan,             NULL            },
 343         { "create-iptun",       do_create_iptun,
 344             "    create-iptun     [-t] -T <type> "
 345             "[-a {local|remote}=<addr>,...] <link>]" },
 346         { "delete-iptun",       do_delete_iptun,
 347             "    delete-iptun     [-t] <link>"                            },
 348         { "modify-iptun",       do_modify_iptun,
 349             "    modify-iptun     [-t] -a {local|remote}=<addr>,... <link>" },
 350         { "show-iptun",         do_show_iptun,
 351             "    show-iptun       [-pP] [-o <field>,..] [<link>]\n" },
 352         { "up-iptun",           do_up_iptun,            NULL            },
 353         { "down-iptun",         do_down_iptun,          NULL            },
 354         { "delete-phys",        do_delete_phys,
 355             "    delete-phys      <link>"                         },
 356         { "show-phys",          do_show_phys,
 357             "    show-phys        [-m | -H | -P] [[-p] [-o <field>[,...]] "
 358             "[<link>]\n"                                          },
 359         { "init-phys",          do_init_phys,           NULL            },
 360         { "show-linkmap",       do_show_linkmap,        NULL            },
 361         { "create-vnic",        do_create_vnic,
 362             "    create-vnic      [-t] -l <link> [-m <value> | auto |\n"
 363             "\t\t     {factory [-n <slot-id>]} | {random [-r <prefix>]} |\n"
 364             "\t\t     {vrrp -V <vrid> -A {inet | inet6}} [-v <vid> [-f]]\n"
 365             "\t\t     [-p <prop>=<value>[,...]] <vnic-link>"  },
 366         { "delete-vnic",        do_delete_vnic,
 367             "    delete-vnic      [-t] <vnic-link>"                       },
 368         { "show-vnic",          do_show_vnic,
 369             "    show-vnic        [-pP] [-l <link>] [-s [-i <interval>]] "
 370             "[<link>]\n"                                          },
 371         { "up-vnic",            do_up_vnic,             NULL            },
 372         { "create-part",        do_create_part,
 373             "    create-part      [-t] [-f] -l <link> [-P <pkey>]\n"
 374             "\t\t     [-R <root-dir>] <part-link>"                  },
 375         { "delete-part",        do_delete_part,
 376             "    delete-part      [-t] [-R <root-dir>] <part-link>"},
 377         { "show-part",          do_show_part,
 378             "    show-part        [-pP] [-o <field>,...][-l <linkover>]\n"
 379             "\t\t     [<part-link>]"              },
 380         { "show-ib",            do_show_ib,
 381             "    show-ib          [-p] [-o <field>,...] [<link>]\n" },
 382         { "up-part",            do_up_part,             NULL            },
 383         { "create-etherstub",   do_create_etherstub,
 384             "    create-etherstub [-t] <link>"                            },
 385         { "delete-etherstub",   do_delete_etherstub,
 386             "    delete-etherstub [-t] <link>"                            },
 387         { "show-etherstub",     do_show_etherstub,
 388             "    show-etherstub   [-t] [<link>]\n"                        },
 389         { "create-simnet",      do_create_simnet,       NULL            },
 390         { "modify-simnet",      do_modify_simnet,       NULL            },
 391         { "delete-simnet",      do_delete_simnet,       NULL            },
 392         { "show-simnet",        do_show_simnet,         NULL            },
 393         { "up-simnet",          do_up_simnet,           NULL            },
 394         { "create-bridge",      do_create_bridge,
 395             "    create-bridge    [-R <root-dir>] [-P <protect>] "
 396             "[-p <priority>]\n"
 397             "\t\t     [-m <max-age>] [-h <hello-time>] [-d <forward-delay>]\n"
 398             "\t\t     [-f <force-protocol>] [-l <link>]... <bridge>"  },
 399         { "modify-bridge",      do_modify_bridge,
 400             "    modify-bridge    [-R <root-dir>] [-P <protect>] "
 401             "[-p <priority>]\n"
 402             "\t\t     [-m <max-age>] [-h <hello-time>] [-d <forward-delay>]\n"
 403             "\t\t     [-f <force-protocol>] <bridge>"                       },
 404         { "delete-bridge",      do_delete_bridge,
 405             "    delete-bridge    [-R <root-dir>] <bridge>"         },
 406         { "add-bridge",         do_add_bridge,
 407             "    add-bridge       [-R <root-dir>] -l <link> [-l <link>]... "
 408             "<bridge>"                                                    },
 409         { "remove-bridge",      do_remove_bridge,
 410             "    remove-bridge    [-R <root-dir>] -l <link> [-l <link>]... "
 411             "<bridge>"                                                    },
 412         { "show-bridge",        do_show_bridge,
 413             "    show-bridge      [-p] [-o <field>,...] [-s [-i <interval>]] "
 414             "[<bridge>]\n"
 415             "    show-bridge      -l [-p] [-o <field>,...] [-s [-i <interval>]]"
 416             " <bridge>\n"
 417             "    show-bridge      -f [-p] [-o <field>,...] [-s [-i <interval>]]"
 418             " <bridge>\n"
 419             "    show-bridge      -t [-p] [-o <field>,...] [-s [-i <interval>]]"
 420             " <bridge>\n"                                         },
 421         { "create-overlay",     do_create_overlay,
 422             "    create-overlay   [-t] -e <encap> -s <search> -v <vnetid>\n"
 423             "\t\t     [ -p <prop>=<value>[,...]] <overlay>"   },
 424         { "delete-overlay",     do_delete_overlay,
 425             "    delete-overlay   [-t] <overlay>"                 },
 426         { "modify-overlay",     do_modify_overlay,
 427             "    modify-overlay   -d mac | -f | -s mac=ip:port "
 428             "<overlay>"                                           },
 429         { "show-overlay",       do_show_overlay,
 430             "    show-overlay     [-f | -t] [[-p] -o <field>,...] "
 431             "[<overlay>]\n"                                               },
 432         { "up-overlay",         do_up_overlay,          NULL            },
 433         { "show-usage",         do_show_usage,
 434             "    show-usage       [-a] [-d | -F <format>] "
 435             "[-s <DD/MM/YYYY,HH:MM:SS>]\n"
 436             "\t\t     [-e <DD/MM/YYYY,HH:MM:SS>] -f <logfile> [<link>]"       }
 437 };
 438 
 439 static const struct option lopts[] = {
 440         {"vlan-id",     required_argument,      0, 'v'},
 441         {"output",      required_argument,      0, 'o'},
 442         {"dev",         required_argument,      0, 'd'},
 443         {"policy",      required_argument,      0, 'P'},
 444         {"lacp-mode",   required_argument,      0, 'L'},
 445         {"lacp-timer",  required_argument,      0, 'T'},
 446         {"unicast",     required_argument,      0, 'u'},
 447         {"temporary",   no_argument,            0, 't'},
 448         {"root-dir",    required_argument,      0, 'R'},
 449         {"link",        required_argument,      0, 'l'},
 450         {"forcible",    no_argument,            0, 'f'},
 451         {"bw-limit",    required_argument,      0, 'b'},
 452         {"mac-address", required_argument,      0, 'm'},
 453         {"slot",        required_argument,      0, 'n'},
 454         { NULL, 0, NULL, 0 }
 455 };
 456 
 457 static const struct option show_lopts[] = {
 458         {"statistics",  no_argument,            0, 's'},
 459         {"continuous",  no_argument,            0, 'S'},
 460         {"interval",    required_argument,      0, 'i'},
 461         {"parsable",    no_argument,            0, 'p'},
 462         {"parseable",   no_argument,            0, 'p'},
 463         {"extended",    no_argument,            0, 'x'},
 464         {"output",      required_argument,      0, 'o'},
 465         {"persistent",  no_argument,            0, 'P'},
 466         {"lacp",        no_argument,            0, 'L'},
 467         { NULL, 0, NULL, 0 }
 468 };
 469 
 470 static const struct option iptun_lopts[] = {
 471         {"output",      required_argument,      0, 'o'},
 472         {"tunnel-type", required_argument,      0, 'T'},
 473         {"address",     required_argument,      0, 'a'},
 474         {"root-dir",    required_argument,      0, 'R'},
 475         {"parsable",    no_argument,            0, 'p'},
 476         {"parseable",   no_argument,            0, 'p'},
 477         {"persistent",  no_argument,            0, 'P'},
 478         { NULL, 0, NULL, 0 }
 479 };
 480 
 481 static char * const iptun_addropts[] = {
 482 #define IPTUN_LOCAL     0
 483         "local",
 484 #define IPTUN_REMOTE    1
 485         "remote",
 486         NULL};
 487 
 488 static const struct {
 489         const char      *type_name;
 490         iptun_type_t    type_value;
 491 } iptun_types[] = {
 492         {"ipv4",        IPTUN_TYPE_IPV4},
 493         {"ipv6",        IPTUN_TYPE_IPV6},
 494         {"6to4",        IPTUN_TYPE_6TO4},
 495         {NULL,          0}
 496 };
 497 
 498 static const struct option prop_longopts[] = {
 499         {"temporary",   no_argument,            0, 't'  },
 500         {"output",      required_argument,      0, 'o'  },
 501         {"root-dir",    required_argument,      0, 'R'  },
 502         {"prop",        required_argument,      0, 'p'  },
 503         {"parsable",    no_argument,            0, 'c'  },
 504         {"parseable",   no_argument,            0, 'c'  },
 505         {"persistent",  no_argument,            0, 'P'  },
 506         { NULL, 0, NULL, 0 }
 507 };
 508 
 509 static const struct option wifi_longopts[] = {
 510         {"parsable",    no_argument,            0, 'p'  },
 511         {"parseable",   no_argument,            0, 'p'  },
 512         {"output",      required_argument,      0, 'o'  },
 513         {"essid",       required_argument,      0, 'e'  },
 514         {"bsstype",     required_argument,      0, 'b'  },
 515         {"mode",        required_argument,      0, 'm'  },
 516         {"key",         required_argument,      0, 'k'  },
 517         {"sec",         required_argument,      0, 's'  },
 518         {"auth",        required_argument,      0, 'a'  },
 519         {"create-ibss", required_argument,      0, 'c'  },
 520         {"timeout",     required_argument,      0, 'T'  },
 521         {"all-links",   no_argument,            0, 'a'  },
 522         {"temporary",   no_argument,            0, 't'  },
 523         {"root-dir",    required_argument,      0, 'R'  },
 524         {"persistent",  no_argument,            0, 'P'  },
 525         {"file",        required_argument,      0, 'f'  },
 526         { NULL, 0, NULL, 0 }
 527 };
 528 
 529 static const struct option showeth_lopts[] = {
 530         {"parsable",    no_argument,            0, 'p'  },
 531         {"parseable",   no_argument,            0, 'p'  },
 532         {"extended",    no_argument,            0, 'x'  },
 533         {"output",      required_argument,      0, 'o'  },
 534         { NULL, 0, NULL, 0 }
 535 };
 536 
 537 static const struct option vnic_lopts[] = {
 538         {"temporary",   no_argument,            0, 't'  },
 539         {"root-dir",    required_argument,      0, 'R'  },
 540         {"dev",         required_argument,      0, 'd'  },
 541         {"mac-address", required_argument,      0, 'm'  },
 542         {"cpus",        required_argument,      0, 'c'  },
 543         {"bw-limit",    required_argument,      0, 'b'  },
 544         {"slot",        required_argument,      0, 'n'  },
 545         {"mac-prefix",  required_argument,      0, 'r'  },
 546         {"vrid",        required_argument,      0, 'V'  },
 547         {"address-family",      required_argument,      0, 'A'  },
 548         { NULL, 0, NULL, 0 }
 549 };
 550 
 551 static const struct option part_lopts[] = {
 552         {"temporary",   no_argument,            0, 't'  },
 553         {"pkey",        required_argument,      0, 'P'  },
 554         {"link",        required_argument,      0, 'l'  },
 555         {"force",       no_argument,            0, 'f'  },
 556         {"root-dir",    required_argument,      0, 'R'  },
 557         {"prop",        required_argument,      0, 'p'  },
 558         { NULL, 0, NULL, 0 }
 559 };
 560 
 561 static const struct option show_part_lopts[] = {
 562         {"parsable",    no_argument,            0, 'p'  },
 563         {"parseable",   no_argument,            0, 'p'  },
 564         {"link",        required_argument,      0, 'l'  },
 565         {"persistent",  no_argument,            0, 'P'  },
 566         {"output",      required_argument,      0, 'o'  },
 567         { NULL, 0, NULL, 0 }
 568 };
 569 
 570 static const struct option etherstub_lopts[] = {
 571         {"temporary",   no_argument,            0, 't'  },
 572         {"root-dir",    required_argument,      0, 'R'  },
 573         { NULL, 0, NULL, 0 }
 574 };
 575 
 576 static const struct option usage_opts[] = {
 577         {"file",        required_argument,      0, 'f'  },
 578         {"format",      required_argument,      0, 'F'  },
 579         {"start",       required_argument,      0, 's'  },
 580         {"stop",        required_argument,      0, 'e'  },
 581         { NULL, 0, NULL, 0 }
 582 };
 583 
 584 static const struct option simnet_lopts[] = {
 585         {"temporary",   no_argument,            0, 't'  },
 586         {"root-dir",    required_argument,      0, 'R'  },
 587         {"media",       required_argument,      0, 'm'  },
 588         {"peer",        required_argument,      0, 'p'  },
 589         { NULL, 0, NULL, 0 }
 590 };
 591 
 592 static const struct option bridge_lopts[] = {
 593         { "protect",            required_argument,      0, 'P' },
 594         { "root-dir",           required_argument,      0, 'R'  },
 595         { "forward-delay",      required_argument,      0, 'd'  },
 596         { "force-protocol",     required_argument,      0, 'f'  },
 597         { "hello-time",         required_argument,      0, 'h'  },
 598         { "link",               required_argument,      0, 'l'  },
 599         { "max-age",            required_argument,      0, 'm'  },
 600         { "priority",           required_argument,      0, 'p'  },
 601         { NULL, 0, NULL, 0 }
 602 };
 603 
 604 static const struct option bridge_show_lopts[] = {
 605         { "forwarding", no_argument,            0, 'f' },
 606         { "interval",   required_argument,      0, 'i' },
 607         { "link",       no_argument,            0, 'l' },
 608         { "output",     required_argument,      0, 'o' },
 609         { "parsable",   no_argument,            0, 'p' },
 610         { "parseable",  no_argument,            0, 'p' },
 611         { "statistics", no_argument,            0, 's' },
 612         { "trill",      no_argument,            0, 't' },
 613         { NULL, 0, NULL, 0 }
 614 };
 615 
 616 /*
 617  * structures for 'dladm show-ether'
 618  */
 619 static const char *ptype[] = {LEI_ATTR_NAMES};
 620 
 621 typedef struct ether_fields_buf_s
 622 {
 623         char    eth_link[15];
 624         char    eth_ptype[8];
 625         char    eth_state[8];
 626         char    eth_autoneg[5];
 627         char    eth_spdx[31];
 628         char    eth_pause[6];
 629         char    eth_rem_fault[16];
 630 } ether_fields_buf_t;
 631 
 632 static const ofmt_field_t ether_fields[] = {
 633 /* name,        field width,    offset      callback */
 634 { "LINK",       16,
 635         offsetof(ether_fields_buf_t, eth_link), print_default_cb},
 636 { "PTYPE",      9,
 637         offsetof(ether_fields_buf_t, eth_ptype), print_default_cb},
 638 { "STATE",      9,
 639         offsetof(ether_fields_buf_t, eth_state),
 640         print_default_cb},
 641 { "AUTO",       6,
 642         offsetof(ether_fields_buf_t, eth_autoneg), print_default_cb},
 643 { "SPEED-DUPLEX", 32,
 644         offsetof(ether_fields_buf_t, eth_spdx), print_default_cb},
 645 { "PAUSE",      7,
 646         offsetof(ether_fields_buf_t, eth_pause), print_default_cb},
 647 { "REM_FAULT",  17,
 648         offsetof(ether_fields_buf_t, eth_rem_fault), print_default_cb},
 649 {NULL,          0,
 650         0,      NULL}}
 651 ;
 652 
 653 typedef struct print_ether_state {
 654         const char      *es_link;
 655         boolean_t       es_parsable;
 656         boolean_t       es_header;
 657         boolean_t       es_extended;
 658         ofmt_handle_t   es_ofmt;
 659 } print_ether_state_t;
 660 
 661 /*
 662  * structures for 'dladm show-link -s' (print statistics)
 663  */
 664 typedef enum {
 665         LINK_S_LINK,
 666         LINK_S_IPKTS,
 667         LINK_S_RBYTES,
 668         LINK_S_IERRORS,
 669         LINK_S_OPKTS,
 670         LINK_S_OBYTES,
 671         LINK_S_OERRORS
 672 } link_s_field_index_t;
 673 
 674 static const ofmt_field_t link_s_fields[] = {
 675 /* name,        field width,    index,          callback        */
 676 { "LINK",       15,             LINK_S_LINK,    print_link_stats_cb},
 677 { "IPACKETS",   10,             LINK_S_IPKTS,   print_link_stats_cb},
 678 { "RBYTES",     8,              LINK_S_RBYTES,  print_link_stats_cb},
 679 { "IERRORS",    10,             LINK_S_IERRORS, print_link_stats_cb},
 680 { "OPACKETS",   12,             LINK_S_OPKTS,   print_link_stats_cb},
 681 { "OBYTES",     12,             LINK_S_OBYTES,  print_link_stats_cb},
 682 { "OERRORS",    8,              LINK_S_OERRORS, print_link_stats_cb},
 683 { NULL,         0,              0,              NULL}};
 684 
 685 typedef struct link_args_s {
 686         char            *link_s_link;
 687         pktsum_t        *link_s_psum;
 688 } link_args_t;
 689 
 690 /*
 691  * buffer used by print functions for show-{link,phys,vlan} commands.
 692  */
 693 typedef struct link_fields_buf_s {
 694         char link_name[MAXLINKNAMELEN];
 695         char link_class[DLADM_STRSIZE];
 696         char link_mtu[11];
 697         char link_state[DLADM_STRSIZE];
 698         char link_bridge[MAXLINKNAMELEN * MAXPORT];
 699         char link_over[MAXLINKNAMELEN * MAXPORT];
 700         char link_phys_state[DLADM_STRSIZE];
 701         char link_phys_media[DLADM_STRSIZE];
 702         char link_phys_speed[DLADM_STRSIZE];
 703         char link_phys_duplex[DLPI_LINKNAME_MAX];
 704         char link_phys_device[DLPI_LINKNAME_MAX];
 705         char link_flags[6];
 706         char link_vlan_vid[6];
 707 } link_fields_buf_t;
 708 
 709 /*
 710  * structures for 'dladm show-link'
 711  */
 712 static const ofmt_field_t link_fields[] = {
 713 /* name,        field width,    index,  callback */
 714 { "LINK",       12,
 715         offsetof(link_fields_buf_t, link_name), print_default_cb},
 716 { "CLASS",      10,
 717         offsetof(link_fields_buf_t, link_class), print_default_cb},
 718 { "MTU",        7,
 719         offsetof(link_fields_buf_t, link_mtu), print_default_cb},
 720 { "STATE",      9,
 721         offsetof(link_fields_buf_t, link_state), print_default_cb},
 722 { "BRIDGE",     11,
 723     offsetof(link_fields_buf_t, link_bridge), print_default_cb},
 724 { "OVER",       30,
 725         offsetof(link_fields_buf_t, link_over), print_default_cb},
 726 { NULL,         0, 0, NULL}}
 727 ;
 728 
 729 /*
 730  * structures for 'dladm show-aggr'
 731  */
 732 typedef struct laggr_fields_buf_s {
 733         char laggr_name[DLPI_LINKNAME_MAX];
 734         char laggr_policy[9];
 735         char laggr_addrpolicy[ETHERADDRL * 3 + 3];
 736         char laggr_lacpactivity[14];
 737         char laggr_lacptimer[DLADM_STRSIZE];
 738         char laggr_flags[7];
 739 } laggr_fields_buf_t;
 740 
 741 typedef struct laggr_args_s {
 742         int                     laggr_lport; /* -1 indicates the aggr itself */
 743         const char              *laggr_link;
 744         dladm_aggr_grp_attr_t   *laggr_ginfop;
 745         dladm_status_t          *laggr_status;
 746         pktsum_t                *laggr_pktsumtot; /* -s only */
 747         pktsum_t                *laggr_diffstats; /* -s only */
 748         boolean_t               laggr_parsable;
 749 } laggr_args_t;
 750 
 751 static const ofmt_field_t laggr_fields[] = {
 752 /* name,        field width,    offset, callback */
 753 { "LINK",       16,
 754         offsetof(laggr_fields_buf_t, laggr_name), print_default_cb},
 755 { "POLICY",     9,
 756         offsetof(laggr_fields_buf_t, laggr_policy), print_default_cb},
 757 { "ADDRPOLICY", ETHERADDRL * 3 + 3,
 758         offsetof(laggr_fields_buf_t, laggr_addrpolicy), print_default_cb},
 759 { "LACPACTIVITY", 14,
 760         offsetof(laggr_fields_buf_t, laggr_lacpactivity), print_default_cb},
 761 { "LACPTIMER",  12,
 762         offsetof(laggr_fields_buf_t, laggr_lacptimer), print_default_cb},
 763 { "FLAGS",      8,
 764         offsetof(laggr_fields_buf_t, laggr_flags), print_default_cb},
 765 { NULL,         0, 0, NULL}}
 766 ;
 767 
 768 /*
 769  * structures for 'dladm show-aggr -x'.
 770  */
 771 typedef enum {
 772         AGGR_X_LINK,
 773         AGGR_X_PORT,
 774         AGGR_X_SPEED,
 775         AGGR_X_DUPLEX,
 776         AGGR_X_STATE,
 777         AGGR_X_ADDRESS,
 778         AGGR_X_PORTSTATE
 779 } aggr_x_field_index_t;
 780 
 781 static const ofmt_field_t aggr_x_fields[] = {
 782 /* name,        field width,    index           callback */
 783 { "LINK",       12,     AGGR_X_LINK,            print_xaggr_cb},
 784 { "PORT",       15,     AGGR_X_PORT,            print_xaggr_cb},
 785 { "SPEED",      5,      AGGR_X_SPEED,           print_xaggr_cb},
 786 { "DUPLEX",     10,     AGGR_X_DUPLEX,          print_xaggr_cb},
 787 { "STATE",      10,     AGGR_X_STATE,           print_xaggr_cb},
 788 { "ADDRESS",    19,     AGGR_X_ADDRESS,         print_xaggr_cb},
 789 { "PORTSTATE",  16,     AGGR_X_PORTSTATE,       print_xaggr_cb},
 790 { NULL,         0,      0,                      NULL}}
 791 ;
 792 
 793 /*
 794  * structures for 'dladm show-aggr -s'.
 795  */
 796 typedef enum {
 797         AGGR_S_LINK,
 798         AGGR_S_PORT,
 799         AGGR_S_IPKTS,
 800         AGGR_S_RBYTES,
 801         AGGR_S_OPKTS,
 802         AGGR_S_OBYTES,
 803         AGGR_S_IPKTDIST,
 804         AGGR_S_OPKTDIST
 805 } aggr_s_field_index_t;
 806 
 807 static const ofmt_field_t aggr_s_fields[] = {
 808 { "LINK",               12,     AGGR_S_LINK, print_aggr_stats_cb},
 809 { "PORT",               10,     AGGR_S_PORT, print_aggr_stats_cb},
 810 { "IPACKETS",           8,      AGGR_S_IPKTS, print_aggr_stats_cb},
 811 { "RBYTES",             8,      AGGR_S_RBYTES, print_aggr_stats_cb},
 812 { "OPACKETS",           8,      AGGR_S_OPKTS, print_aggr_stats_cb},
 813 { "OBYTES",             8,      AGGR_S_OBYTES, print_aggr_stats_cb},
 814 { "IPKTDIST",           9,      AGGR_S_IPKTDIST, print_aggr_stats_cb},
 815 { "OPKTDIST",           15,     AGGR_S_OPKTDIST, print_aggr_stats_cb},
 816 { NULL,                 0,      0,              NULL}}
 817 ;
 818 
 819 /*
 820  * structures for 'dladm show-aggr -L'.
 821  */
 822 typedef enum {
 823         AGGR_L_LINK,
 824         AGGR_L_PORT,
 825         AGGR_L_AGGREGATABLE,
 826         AGGR_L_SYNC,
 827         AGGR_L_COLL,
 828         AGGR_L_DIST,
 829         AGGR_L_DEFAULTED,
 830         AGGR_L_EXPIRED
 831 } aggr_l_field_index_t;
 832 
 833 static const ofmt_field_t aggr_l_fields[] = {
 834 /* name,                field width,    index */
 835 { "LINK",               12,     AGGR_L_LINK,            print_lacp_cb},
 836 { "PORT",               13,     AGGR_L_PORT,            print_lacp_cb},
 837 { "AGGREGATABLE",       13,     AGGR_L_AGGREGATABLE,    print_lacp_cb},
 838 { "SYNC",               5,      AGGR_L_SYNC,            print_lacp_cb},
 839 { "COLL",               5,      AGGR_L_COLL,            print_lacp_cb},
 840 { "DIST",               5,      AGGR_L_DIST,            print_lacp_cb},
 841 { "DEFAULTED",          10,     AGGR_L_DEFAULTED,       print_lacp_cb},
 842 { "EXPIRED",            15,     AGGR_L_EXPIRED,         print_lacp_cb},
 843 { NULL,                 0,      0,                      NULL}}
 844 ;
 845 
 846 /*
 847  * structures for 'dladm show-phys'
 848  */
 849 
 850 static const ofmt_field_t phys_fields[] = {
 851 /* name,        field width,    offset */
 852 { "LINK",       13,
 853         offsetof(link_fields_buf_t, link_name), print_default_cb},
 854 { "MEDIA",      21,
 855         offsetof(link_fields_buf_t, link_phys_media), print_default_cb},
 856 { "STATE",      11,
 857         offsetof(link_fields_buf_t, link_phys_state), print_default_cb},
 858 { "SPEED",      7,
 859         offsetof(link_fields_buf_t, link_phys_speed), print_default_cb},
 860 { "DUPLEX",     10,
 861         offsetof(link_fields_buf_t, link_phys_duplex), print_default_cb},
 862 { "DEVICE",     13,
 863         offsetof(link_fields_buf_t, link_phys_device), print_default_cb},
 864 { "FLAGS",      7,
 865         offsetof(link_fields_buf_t, link_flags), print_default_cb},
 866 { NULL,         0, 0, NULL}}
 867 ;
 868 
 869 /*
 870  * structures for 'dladm show-phys -m'
 871  */
 872 
 873 typedef enum {
 874         PHYS_M_LINK,
 875         PHYS_M_SLOT,
 876         PHYS_M_ADDRESS,
 877         PHYS_M_INUSE,
 878         PHYS_M_CLIENT
 879 } phys_m_field_index_t;
 880 
 881 static const ofmt_field_t phys_m_fields[] = {
 882 /* name,        field width,    offset */
 883 { "LINK",       13,     PHYS_M_LINK,    print_phys_one_mac_cb},
 884 { "SLOT",       9,      PHYS_M_SLOT,    print_phys_one_mac_cb},
 885 { "ADDRESS",    19,     PHYS_M_ADDRESS, print_phys_one_mac_cb},
 886 { "INUSE",      5,      PHYS_M_INUSE,   print_phys_one_mac_cb},
 887 { "CLIENT",     13,     PHYS_M_CLIENT,  print_phys_one_mac_cb},
 888 { NULL,         0,      0,              NULL}}
 889 ;
 890 
 891 /*
 892  * structures for 'dladm show-phys -H'
 893  */
 894 
 895 typedef enum {
 896         PHYS_H_LINK,
 897         PHYS_H_RINGTYPE,
 898         PHYS_H_RINGS,
 899         PHYS_H_CLIENTS
 900 } phys_h_field_index_t;
 901 
 902 #define RINGSTRLEN      21
 903 
 904 static const ofmt_field_t phys_h_fields[] = {
 905 { "LINK",       13,     PHYS_H_LINK,    print_phys_one_hwgrp_cb},
 906 { "RINGTYPE",   9,      PHYS_H_RINGTYPE,        print_phys_one_hwgrp_cb},
 907 { "RINGS",      RINGSTRLEN,     PHYS_H_RINGS,   print_phys_one_hwgrp_cb},
 908 { "CLIENTS",    24,     PHYS_H_CLIENTS, print_phys_one_hwgrp_cb},
 909 { NULL,         0,      0,              NULL}}
 910 ;
 911 
 912 /*
 913  * structures for 'dladm show-vlan'
 914  */
 915 static const ofmt_field_t vlan_fields[] = {
 916 { "LINK",       16,
 917         offsetof(link_fields_buf_t, link_name), print_default_cb},
 918 { "VID",        9,
 919         offsetof(link_fields_buf_t, link_vlan_vid), print_default_cb},
 920 { "OVER",       13,
 921         offsetof(link_fields_buf_t, link_over), print_default_cb},
 922 { "FLAGS",      7,
 923         offsetof(link_fields_buf_t, link_flags), print_default_cb},
 924 { NULL,         0, 0, NULL}}
 925 ;
 926 
 927 /*
 928  * structures common to 'dladm scan-wifi' and 'dladm show-wifi'
 929  * callback will be determined in parse_wifi_fields.
 930  */
 931 static ofmt_field_t wifi_common_fields[] = {
 932 { "LINK",       11, 0,                          NULL},
 933 { "ESSID",      20, DLADM_WLAN_ATTR_ESSID,      NULL},
 934 { "BSSID",      18, DLADM_WLAN_ATTR_BSSID,      NULL},
 935 { "IBSSID",     18, DLADM_WLAN_ATTR_BSSID,      NULL},
 936 { "MODE",       7,  DLADM_WLAN_ATTR_MODE,       NULL},
 937 { "SPEED",      7,  DLADM_WLAN_ATTR_SPEED,      NULL},
 938 { "BSSTYPE",    9,  DLADM_WLAN_ATTR_BSSTYPE,    NULL},
 939 { "SEC",        7,  DLADM_WLAN_ATTR_SECMODE,    NULL},
 940 { "STRENGTH",   11, DLADM_WLAN_ATTR_STRENGTH,   NULL},
 941 { NULL,         0,  0,                          NULL}};
 942 
 943 /*
 944  * the 'show-wifi' command supports all the fields in wifi_common_fields
 945  * plus the AUTH and STATUS fields.
 946  */
 947 static ofmt_field_t wifi_show_fields[A_CNT(wifi_common_fields) + 2] = {
 948 { "AUTH",       9,  DLADM_WLAN_ATTR_AUTH,       NULL},
 949 { "STATUS",     18, DLADM_WLAN_LINKATTR_STATUS, print_wifi_status_cb},
 950 /* copy wifi_common_fields here */
 951 };
 952 
 953 static char *all_scan_wifi_fields =
 954         "link,essid,bssid,sec,strength,mode,speed,bsstype";
 955 static char *all_show_wifi_fields =
 956         "link,status,essid,sec,strength,mode,speed,auth,bssid,bsstype";
 957 static char *def_scan_wifi_fields =
 958         "link,essid,bssid,sec,strength,mode,speed";
 959 static char *def_show_wifi_fields =
 960         "link,status,essid,sec,strength,mode,speed";
 961 
 962 /*
 963  * structures for 'dladm show-linkprop'
 964  */
 965 typedef enum {
 966         LINKPROP_LINK,
 967         LINKPROP_PROPERTY,
 968         LINKPROP_PERM,
 969         LINKPROP_VALUE,
 970         LINKPROP_DEFAULT,
 971         LINKPROP_POSSIBLE
 972 } linkprop_field_index_t;
 973 
 974 static const ofmt_field_t linkprop_fields[] = {
 975 /* name,        field width,  index */
 976 { "LINK",       13,     LINKPROP_LINK,          print_linkprop_cb},
 977 { "PROPERTY",   16,     LINKPROP_PROPERTY,      print_linkprop_cb},
 978 { "PERM",       5,      LINKPROP_PERM,          print_linkprop_cb},
 979 { "VALUE",      15,     LINKPROP_VALUE,         print_linkprop_cb},
 980 { "DEFAULT",    15,     LINKPROP_DEFAULT,       print_linkprop_cb},
 981 { "POSSIBLE",   20,     LINKPROP_POSSIBLE,      print_linkprop_cb},
 982 { NULL,         0,      0,                      NULL}}
 983 ;
 984 
 985 #define MAX_PROP_LINE           512
 986 
 987 typedef struct show_linkprop_state {
 988         char                    ls_link[MAXLINKNAMELEN];
 989         char                    *ls_line;
 990         char                    **ls_propvals;
 991         dladm_arg_list_t        *ls_proplist;
 992         boolean_t               ls_parsable;
 993         boolean_t               ls_persist;
 994         boolean_t               ls_header;
 995         dladm_status_t          ls_status;
 996         dladm_status_t          ls_retstatus;
 997         ofmt_handle_t           ls_ofmt;
 998 } show_linkprop_state_t;
 999 
1000 typedef struct set_linkprop_state {
1001         const char              *ls_name;
1002         boolean_t               ls_reset;
1003         boolean_t               ls_temp;
1004         dladm_status_t          ls_status;
1005 } set_linkprop_state_t;
1006 
1007 typedef struct linkprop_args_s {
1008         show_linkprop_state_t   *ls_state;
1009         char                    *ls_propname;
1010         datalink_id_t           ls_linkid;
1011 } linkprop_args_t;
1012 
1013 /*
1014  * structures for 'dladm show-secobj'
1015  */
1016 typedef struct secobj_fields_buf_s {
1017         char                    ss_obj_name[DLADM_SECOBJ_VAL_MAX];
1018         char                    ss_class[20];
1019         char                    ss_val[30];
1020 } secobj_fields_buf_t;
1021 
1022 static const ofmt_field_t secobj_fields[] = {
1023 { "OBJECT",     21,
1024         offsetof(secobj_fields_buf_t, ss_obj_name), print_default_cb},
1025 { "CLASS",      21,
1026         offsetof(secobj_fields_buf_t, ss_class), print_default_cb},
1027 { "VALUE",      31,
1028         offsetof(secobj_fields_buf_t, ss_val), print_default_cb},
1029 { NULL,         0, 0, NULL}}
1030 ;
1031 
1032 /*
1033  * structures for 'dladm show-vnic'
1034  */
1035 typedef struct vnic_fields_buf_s
1036 {
1037         char vnic_link[DLPI_LINKNAME_MAX];
1038         char vnic_over[DLPI_LINKNAME_MAX];
1039         char vnic_speed[6];
1040         char vnic_macaddr[18];
1041         char vnic_macaddrtype[19];
1042         char vnic_vid[6];
1043         char vnic_zone[ZONENAME_MAX];
1044 } vnic_fields_buf_t;
1045 
1046 static const ofmt_field_t vnic_fields[] = {
1047 { "LINK",               13,
1048         offsetof(vnic_fields_buf_t, vnic_link), print_default_cb},
1049 { "OVER",               11,
1050         offsetof(vnic_fields_buf_t, vnic_over), print_default_cb},
1051 { "SPEED",              6,
1052         offsetof(vnic_fields_buf_t, vnic_speed), print_default_cb},
1053 { "MACADDRESS",         18,
1054         offsetof(vnic_fields_buf_t, vnic_macaddr), print_default_cb},
1055 { "MACADDRTYPE",        12,
1056         offsetof(vnic_fields_buf_t, vnic_macaddrtype), print_default_cb},
1057 { "VID",                5,
1058         offsetof(vnic_fields_buf_t, vnic_vid), print_default_cb},
1059 { "ZONE",               20,
1060         offsetof(vnic_fields_buf_t, vnic_zone), print_default_cb},
1061 { NULL,                 0, 0, NULL}}
1062 ;
1063 
1064 /*
1065  * structures for 'dladm show-ib'
1066  */
1067 typedef struct ib_fields_buf_s
1068 {
1069         char ib_link[DLPI_LINKNAME_MAX];
1070         char ib_hcaguid[17];
1071         char ib_portguid[17];
1072         char ib_portnum[4];
1073         char ib_state[6];
1074         char ib_pkeys[MAXPKEYSTRSZ];
1075 } ib_fields_buf_t;
1076 
1077 static const ofmt_field_t ib_fields[] = {
1078 { "LINK",               13,
1079         offsetof(ib_fields_buf_t, ib_link),     print_default_cb},
1080 { "HCAGUID",            IBGUIDSTRLEN,
1081         offsetof(ib_fields_buf_t, ib_hcaguid),  print_default_cb},
1082 { "PORTGUID",           IBGUIDSTRLEN,
1083         offsetof(ib_fields_buf_t, ib_portguid), print_default_cb},
1084 { "PORT",               IBPORTSTRLEN,
1085         offsetof(ib_fields_buf_t, ib_portnum), print_default_cb},
1086 { "STATE",              7,
1087         offsetof(ib_fields_buf_t, ib_state), print_default_cb},
1088 { "PKEYS",      18,
1089         offsetof(ib_fields_buf_t, ib_pkeys), print_default_cb},
1090 { NULL,                 0, 0, NULL}};
1091 
1092 /*
1093  * structures for 'dladm show-part'
1094  */
1095 typedef struct part_fields_buf_s
1096 {
1097         char part_link[DLPI_LINKNAME_MAX];
1098         char part_pkey[5];
1099         char part_over[DLPI_LINKNAME_MAX];
1100         char part_state[8];
1101         char part_flags[5];
1102 } part_fields_buf_t;
1103 
1104 static const ofmt_field_t part_fields[] = {
1105 { "LINK",               13,
1106         offsetof(part_fields_buf_t, part_link), print_default_cb},
1107 { "PKEY",               MAXPKEYLEN,
1108         offsetof(part_fields_buf_t, part_pkey), print_default_cb},
1109 { "OVER",               13,
1110         offsetof(part_fields_buf_t, part_over), print_default_cb},
1111 { "STATE",              9,
1112         offsetof(part_fields_buf_t, part_state), print_default_cb},
1113 { "FLAGS",      5,
1114         offsetof(part_fields_buf_t, part_flags), print_default_cb},
1115 { NULL,                 0, 0, NULL}};
1116 
1117 /*
1118  * structures for 'dladm show-simnet'
1119  */
1120 typedef struct simnet_fields_buf_s
1121 {
1122         char simnet_name[DLPI_LINKNAME_MAX];
1123         char simnet_media[DLADM_STRSIZE];
1124         char simnet_macaddr[18];
1125         char simnet_otherlink[DLPI_LINKNAME_MAX];
1126 } simnet_fields_buf_t;
1127 
1128 static const ofmt_field_t simnet_fields[] = {
1129 { "LINK",               12,
1130         offsetof(simnet_fields_buf_t, simnet_name), print_default_cb},
1131 { "MEDIA",              20,
1132         offsetof(simnet_fields_buf_t, simnet_media), print_default_cb},
1133 { "MACADDRESS",         18,
1134         offsetof(simnet_fields_buf_t, simnet_macaddr), print_default_cb},
1135 { "OTHERLINK",          12,
1136         offsetof(simnet_fields_buf_t, simnet_otherlink), print_default_cb},
1137 { NULL,                 0, 0, NULL}}
1138 ;
1139 
1140 /*
1141  * structures for 'dladm show-usage'
1142  */
1143 
1144 typedef struct  usage_fields_buf_s {
1145         char    usage_link[12];
1146         char    usage_duration[10];
1147         char    usage_ipackets[9];
1148         char    usage_rbytes[10];
1149         char    usage_opackets[9];
1150         char    usage_obytes[10];
1151         char    usage_bandwidth[15];
1152 } usage_fields_buf_t;
1153 
1154 static const ofmt_field_t usage_fields[] = {
1155 { "LINK",       13,
1156         offsetof(usage_fields_buf_t, usage_link), print_default_cb},
1157 { "DURATION",   11,
1158         offsetof(usage_fields_buf_t, usage_duration), print_default_cb},
1159 { "IPACKETS",   10,
1160         offsetof(usage_fields_buf_t, usage_ipackets), print_default_cb},
1161 { "RBYTES",     11,
1162         offsetof(usage_fields_buf_t, usage_rbytes), print_default_cb},
1163 { "OPACKETS",   10,
1164         offsetof(usage_fields_buf_t, usage_opackets), print_default_cb},
1165 { "OBYTES",     11,
1166         offsetof(usage_fields_buf_t, usage_obytes), print_default_cb},
1167 { "BANDWIDTH",  16,
1168         offsetof(usage_fields_buf_t, usage_bandwidth), print_default_cb},
1169 { NULL,         0, 0, NULL}}
1170 ;
1171 
1172 
1173 /*
1174  * structures for 'dladm show-usage link'
1175  */
1176 
1177 typedef struct  usage_l_fields_buf_s {
1178         char    usage_l_link[12];
1179         char    usage_l_stime[13];
1180         char    usage_l_etime[13];
1181         char    usage_l_rbytes[8];
1182         char    usage_l_obytes[8];
1183         char    usage_l_bandwidth[15];
1184 } usage_l_fields_buf_t;
1185 
1186 static const ofmt_field_t usage_l_fields[] = {
1187 /* name,        field width,    offset */
1188 { "LINK",       13,
1189         offsetof(usage_l_fields_buf_t, usage_l_link), print_default_cb},
1190 { "START",      14,
1191         offsetof(usage_l_fields_buf_t, usage_l_stime), print_default_cb},
1192 { "END",        14,
1193         offsetof(usage_l_fields_buf_t, usage_l_etime), print_default_cb},
1194 { "RBYTES",     9,
1195         offsetof(usage_l_fields_buf_t, usage_l_rbytes), print_default_cb},
1196 { "OBYTES",     9,
1197         offsetof(usage_l_fields_buf_t, usage_l_obytes), print_default_cb},
1198 { "BANDWIDTH",  16,
1199         offsetof(usage_l_fields_buf_t, usage_l_bandwidth), print_default_cb},
1200 { NULL,         0, 0, NULL}}
1201 ;
1202 
1203 /* IPTUN_*FLAG_INDEX values are indices into iptun_flags below. */
1204 enum { IPTUN_SFLAG_INDEX, IPTUN_IFLAG_INDEX, IPTUN_NUM_FLAGS };
1205 
1206 /*
1207  * structures for 'dladm show-iptun'
1208  */
1209 typedef struct iptun_fields_buf_s {
1210         char    iptun_name[MAXLINKNAMELEN];
1211         char    iptun_type[5];
1212         char    iptun_laddr[NI_MAXHOST];
1213         char    iptun_raddr[NI_MAXHOST];
1214         char    iptun_flags[IPTUN_NUM_FLAGS + 1];
1215 } iptun_fields_buf_t;
1216 
1217 static const ofmt_field_t iptun_fields[] = {
1218 { "LINK",       16,
1219         offsetof(iptun_fields_buf_t, iptun_name), print_default_cb },
1220 { "TYPE",       6,
1221         offsetof(iptun_fields_buf_t, iptun_type), print_default_cb },
1222 { "FLAGS",      7,
1223         offsetof(iptun_fields_buf_t, iptun_flags), print_default_cb },
1224 { "LOCAL",      20,
1225         offsetof(iptun_fields_buf_t, iptun_laddr), print_default_cb },
1226 { "REMOTE",     20,
1227         offsetof(iptun_fields_buf_t, iptun_raddr), print_default_cb },
1228 { NULL, 0, 0, NULL}
1229 };
1230 
1231 /*
1232  * structures for 'dladm show-bridge'.  These are based on sections 14.8.1.1.3
1233  * and 14.8.1.2.2 of IEEE 802.1D-2004.
1234  */
1235 typedef struct bridge_fields_buf_s {
1236         char bridge_name[MAXLINKNAMELEN]; /* 14.4.1.2.3(b) */
1237         char bridge_protect[7];         /* stp or trill */
1238         char bridge_address[24];        /* 17.18.3, 7.12.5, 14.4.1.2.3(a) */
1239         char bridge_priority[7];        /* 17.18.3 9.2.5 - only upper 4 bits */
1240         char bridge_bmaxage[7];         /* 17.18.4 configured */
1241         char bridge_bhellotime[7];      /* 17.18.4 configured */
1242         char bridge_bfwddelay[7];       /* 17.18.4 configured */
1243         char bridge_forceproto[3];      /* 17.13.4 configured */
1244         char bridge_tctime[12];         /* 14.8.1.1.3(b) */
1245         char bridge_tccount[12];        /* 17.17.8 */
1246         char bridge_tchange[12];        /* 17.17.8 */
1247         char bridge_desroot[24];        /* 17.18.6 priority "/" MAC */
1248         char bridge_rootcost[12];       /* 17.18.6 */
1249         char bridge_rootport[12];       /* 17.18.6 */
1250         char bridge_maxage[7];          /* 17.18.7 for root */
1251         char bridge_hellotime[7];       /* 17.13.6 for root */
1252         char bridge_fwddelay[7];        /* 17.13.5 for root */
1253         char bridge_holdtime[12];       /* 17.13.12 for root */
1254 } bridge_fields_buf_t;
1255 
1256 static ofmt_field_t bridge_fields[] = {
1257 /* name,        field width,    offset, callback        */
1258 { "BRIDGE",     12,
1259     offsetof(bridge_fields_buf_t, bridge_name), print_default_cb },
1260 { "PROTECT",    8,
1261     offsetof(bridge_fields_buf_t, bridge_protect), print_default_cb },
1262 { "ADDRESS",    19,
1263     offsetof(bridge_fields_buf_t, bridge_address), print_default_cb },
1264 { "PRIORITY",   9,
1265     offsetof(bridge_fields_buf_t, bridge_priority), print_default_cb },
1266 { "BMAXAGE",    8,
1267     offsetof(bridge_fields_buf_t, bridge_bmaxage), print_default_cb },
1268 { "BHELLOTIME", 11,
1269     offsetof(bridge_fields_buf_t, bridge_bhellotime), print_default_cb },
1270 { "BFWDDELAY",  10,
1271     offsetof(bridge_fields_buf_t, bridge_bfwddelay), print_default_cb },
1272 { "FORCEPROTO", 11,
1273     offsetof(bridge_fields_buf_t, bridge_forceproto), print_default_cb },
1274 { "TCTIME",     10,
1275     offsetof(bridge_fields_buf_t, bridge_tctime), print_default_cb },
1276 { "TCCOUNT",    10,
1277     offsetof(bridge_fields_buf_t, bridge_tccount), print_default_cb },
1278 { "TCHANGE",    10,
1279     offsetof(bridge_fields_buf_t, bridge_tchange), print_default_cb },
1280 { "DESROOT",    23,
1281     offsetof(bridge_fields_buf_t, bridge_desroot), print_default_cb },
1282 { "ROOTCOST",   11,
1283     offsetof(bridge_fields_buf_t, bridge_rootcost), print_default_cb },
1284 { "ROOTPORT",   11,
1285     offsetof(bridge_fields_buf_t, bridge_rootport), print_default_cb },
1286 { "MAXAGE",     8,
1287     offsetof(bridge_fields_buf_t, bridge_maxage), print_default_cb },
1288 { "HELLOTIME",  10,
1289     offsetof(bridge_fields_buf_t, bridge_hellotime), print_default_cb },
1290 { "FWDDELAY",   9,
1291     offsetof(bridge_fields_buf_t, bridge_fwddelay), print_default_cb },
1292 { "HOLDTIME",   9,
1293     offsetof(bridge_fields_buf_t, bridge_holdtime), print_default_cb },
1294 { NULL,         0, 0, NULL}};
1295 
1296 /*
1297  * structures for 'dladm show-bridge -l'.  These are based on 14.4.1.2.3 and
1298  * 14.8.2.1.3 of IEEE 802.1D-2004.
1299  */
1300 typedef struct bridge_link_fields_buf_s {
1301         char bridgel_link[MAXLINKNAMELEN];
1302         char bridgel_index[7];                  /* 14.4.1.2.3(d1) */
1303         char bridgel_state[11];                 /* 14.8.2.1.3(b) */
1304         char bridgel_uptime[7];                 /* 14.8.2.1.3(a) */
1305         char bridgel_opercost[7]                /* 14.8.2.1.3(d) */;
1306         char bridgel_operp2p[4];                /* 14.8.2.1.3(p) */
1307         char bridgel_operedge[4];               /* 14.8.2.1.3(k) */
1308         char bridgel_desroot[23];               /* 14.8.2.1.3(e) */
1309         char bridgel_descost[12];               /* 14.8.2.1.3(f) */
1310         char bridgel_desbridge[23];             /* 14.8.2.1.3(g) */
1311         char bridgel_desport[7];                /* 14.8.2.1.3(h) */
1312         char bridgel_tcack[4];                  /* 14.8.2.1.3(i) */
1313 } bridge_link_fields_buf_t;
1314 
1315 static ofmt_field_t bridge_link_fields[] = {
1316 /* name,        field width,    offset, callback        */
1317 { "LINK",               12,
1318     offsetof(bridge_link_fields_buf_t, bridgel_link), print_default_cb },
1319 { "INDEX",      8,
1320     offsetof(bridge_link_fields_buf_t, bridgel_index), print_default_cb },
1321 { "STATE",      12,
1322     offsetof(bridge_link_fields_buf_t, bridgel_state), print_default_cb },
1323 { "UPTIME",     8,
1324     offsetof(bridge_link_fields_buf_t, bridgel_uptime), print_default_cb },
1325 { "OPERCOST",   9,
1326     offsetof(bridge_link_fields_buf_t, bridgel_opercost), print_default_cb },
1327 { "OPERP2P",    8,
1328     offsetof(bridge_link_fields_buf_t, bridgel_operp2p), print_default_cb },
1329 { "OPEREDGE",   9,
1330     offsetof(bridge_link_fields_buf_t, bridgel_operedge), print_default_cb },
1331 { "DESROOT",    22,
1332     offsetof(bridge_link_fields_buf_t, bridgel_desroot), print_default_cb },
1333 { "DESCOST",    11,
1334     offsetof(bridge_link_fields_buf_t, bridgel_descost), print_default_cb },
1335 { "DESBRIDGE",  22,
1336     offsetof(bridge_link_fields_buf_t, bridgel_desbridge), print_default_cb },
1337 { "DESPORT",    8,
1338     offsetof(bridge_link_fields_buf_t, bridgel_desport), print_default_cb },
1339 { "TCACK",      6,
1340     offsetof(bridge_link_fields_buf_t, bridgel_tcack), print_default_cb },
1341 { NULL,         0, 0, NULL}};
1342 
1343 /*
1344  * structures for 'dladm show-bridge -s'.  These are not based on IEEE
1345  * 802.1D-2004.
1346  */
1347 #define ULONG_DIG       (((sizeof (ulong_t) * NBBY) * 3 / 10) + 1)
1348 #define UINT64_DIG      (((sizeof (uint64_t) * NBBY) * 3 / 10) + 1)
1349 typedef struct bridge_statfields_buf_s {
1350         char bridges_name[MAXLINKNAMELEN];
1351         char bridges_drops[UINT64_DIG];
1352         char bridges_forwards[UINT64_DIG];
1353         char bridges_mbcast[UINT64_DIG];
1354         char bridges_unknown[UINT64_DIG];
1355         char bridges_recv[UINT64_DIG];
1356         char bridges_sent[UINT64_DIG];
1357 } bridge_statfields_buf_t;
1358 
1359 static ofmt_field_t bridge_statfields[] = {
1360 /* name,        field width,    offset, callback        */
1361 { "BRIDGE",     12,
1362     offsetof(bridge_statfields_buf_t, bridges_name), print_default_cb },
1363 { "DROPS",      12,
1364     offsetof(bridge_statfields_buf_t, bridges_drops), print_default_cb },
1365 { "FORWARDS",   12,
1366     offsetof(bridge_statfields_buf_t, bridges_forwards), print_default_cb },
1367 { "MBCAST",     12,
1368     offsetof(bridge_statfields_buf_t, bridges_mbcast), print_default_cb },
1369 { "UNKNOWN",    12,
1370     offsetof(bridge_statfields_buf_t, bridges_unknown), print_default_cb },
1371 { "RECV",       12,
1372     offsetof(bridge_statfields_buf_t, bridges_recv), print_default_cb },
1373 { "SENT",       12,
1374     offsetof(bridge_statfields_buf_t, bridges_sent), print_default_cb },
1375 { NULL,         0, 0, NULL}};
1376 
1377 /*
1378  * structures for 'dladm show-bridge -s -l'.  These are based in part on
1379  * section 14.6.1.1.3 of IEEE 802.1D-2004.
1380  */
1381 typedef struct bridge_link_statfields_buf_s {
1382         char bridgels_link[MAXLINKNAMELEN];
1383         char bridgels_cfgbpdu[ULONG_DIG];
1384         char bridgels_tcnbpdu[ULONG_DIG];
1385         char bridgels_rstpbpdu[ULONG_DIG];
1386         char bridgels_txbpdu[ULONG_DIG];
1387         char bridgels_drops[UINT64_DIG];        /* 14.6.1.1.3(d) */
1388         char bridgels_recv[UINT64_DIG];         /* 14.6.1.1.3(a) */
1389         char bridgels_xmit[UINT64_DIG];         /* 14.6.1.1.3(c) */
1390 } bridge_link_statfields_buf_t;
1391 
1392 static ofmt_field_t bridge_link_statfields[] = {
1393 /* name,        field width,    offset, callback        */
1394 { "LINK",       12,
1395     offsetof(bridge_link_statfields_buf_t, bridgels_link), print_default_cb },
1396 { "CFGBPDU",    9,
1397     offsetof(bridge_link_statfields_buf_t, bridgels_cfgbpdu),
1398     print_default_cb },
1399 { "TCNBPDU",    9,
1400     offsetof(bridge_link_statfields_buf_t, bridgels_tcnbpdu),
1401     print_default_cb },
1402 { "RSTPBPDU",   9,
1403     offsetof(bridge_link_statfields_buf_t, bridgels_rstpbpdu),
1404     print_default_cb },
1405 { "TXBPDU",     9,
1406     offsetof(bridge_link_statfields_buf_t, bridgels_txbpdu), print_default_cb },
1407 { "DROPS",      9,
1408     offsetof(bridge_link_statfields_buf_t, bridgels_drops), print_default_cb },
1409 { "RECV",       9,
1410     offsetof(bridge_link_statfields_buf_t, bridgels_recv), print_default_cb },
1411 { "XMIT",       9,
1412     offsetof(bridge_link_statfields_buf_t, bridgels_xmit), print_default_cb },
1413 { NULL,         0, 0, NULL}};
1414 
1415 /*
1416  * structures for 'dladm show-bridge -f'.  These are based in part on
1417  * section  14.7.6.3.3 of IEEE 802.1D-2004.
1418  */
1419 typedef struct bridge_fwd_fields_buf_s {
1420         char bridgef_dest[18];                  /* 14.7.6.3.3(a) */
1421         char bridgef_age[8];
1422         char bridgef_flags[6];
1423         char bridgef_output[MAXLINKNAMELEN];    /* 14.7.6.3.3(c) */
1424 } bridge_fwd_fields_buf_t;
1425 
1426 static ofmt_field_t bridge_fwd_fields[] = {
1427 /* name,        field width,    offset, callback        */
1428 { "DEST",       17,
1429     offsetof(bridge_fwd_fields_buf_t, bridgef_dest), print_default_cb },
1430 { "AGE",        7,
1431     offsetof(bridge_fwd_fields_buf_t, bridgef_age), print_default_cb },
1432 { "FLAGS",      6,
1433     offsetof(bridge_fwd_fields_buf_t, bridgef_flags), print_default_cb },
1434 { "OUTPUT",     12,
1435     offsetof(bridge_fwd_fields_buf_t, bridgef_output), print_default_cb },
1436 { NULL,         0, 0, NULL}};
1437 
1438 /*
1439  * structures for 'dladm show-bridge -t'.
1440  */
1441 typedef struct bridge_trill_fields_buf_s {
1442         char bridget_nick[6];
1443         char bridget_flags[6];
1444         char bridget_link[MAXLINKNAMELEN];
1445         char bridget_nexthop[18];
1446 } bridge_trill_fields_buf_t;
1447 
1448 static ofmt_field_t bridge_trill_fields[] = {
1449 /* name,        field width,    offset, callback        */
1450 { "NICK",       5,
1451     offsetof(bridge_trill_fields_buf_t, bridget_nick), print_default_cb },
1452 { "FLAGS",      6,
1453     offsetof(bridge_trill_fields_buf_t, bridget_flags), print_default_cb },
1454 { "LINK",       12,
1455     offsetof(bridge_trill_fields_buf_t, bridget_link), print_default_cb },
1456 { "NEXTHOP",    17,
1457     offsetof(bridge_trill_fields_buf_t, bridget_nexthop), print_default_cb },
1458 { NULL,         0, 0, NULL}};
1459 
1460 static const struct option overlay_create_lopts[] = {
1461         { "encap",      required_argument,      NULL,   'e' },
1462         { "prop",       required_argument,      NULL,   'p' },
1463         { "search",     required_argument,      NULL,   's' },
1464         { "temporary",  no_argument,            NULL,   't' },
1465         { "vnetid",     required_argument,      NULL,   'v' },
1466         { NULL,         0,                      NULL,   0 }
1467 };
1468 
1469 static const struct option overlay_modify_lopts[] = {
1470         { "delete-entry",       required_argument,      NULL,   'd' },
1471         { "flush-table",        no_argument,            NULL,   'f' },
1472         { "set-entry",          required_argument,      NULL,   's' },
1473         { NULL,                 0,                      NULL,   0 }
1474 };
1475 
1476 static const struct option overlay_show_lopts[] = {
1477         { "fma",        no_argument,            NULL,   'f' },
1478         { "target",     no_argument,            NULL,   't' },
1479         { "parsable",   no_argument,            NULL,   'p' },
1480         { "parseable",  no_argument,            NULL,   'p' },
1481         { "output",     required_argument,      NULL,   'o' },
1482         { NULL,         0,                      NULL,   0 }
1483 };
1484 
1485 /*
1486  * Structures for dladm show-overlay
1487  */
1488 typedef enum {
1489         OVERLAY_LINK,
1490         OVERLAY_PROPERTY,
1491         OVERLAY_PERM,
1492         OVERLAY_REQ,
1493         OVERLAY_VALUE,
1494         OVERLAY_DEFAULT,
1495         OVERLAY_POSSIBLE
1496 } overlay_field_index_t;
1497 
1498 static const ofmt_field_t overlay_fields[] = {
1499 /* name,        field width,  index */
1500 { "LINK",       19,     OVERLAY_LINK,           print_overlay_cb },
1501 { "PROPERTY",   19,     OVERLAY_PROPERTY,       print_overlay_cb },
1502 { "PERM",       5,      OVERLAY_PERM,           print_overlay_cb },
1503 { "REQ",        4,      OVERLAY_REQ,            print_overlay_cb },
1504 { "VALUE",      11,     OVERLAY_VALUE,          print_overlay_cb },
1505 { "DEFAULT",    10,     OVERLAY_DEFAULT,        print_overlay_cb },
1506 { "POSSIBLE",   10,     OVERLAY_POSSIBLE,       print_overlay_cb },
1507 { NULL,         0,      0,      NULL }
1508 };
1509 
1510 typedef enum {
1511         OVERLAY_FMA_LINK,
1512         OVERLAY_FMA_STATUS,
1513         OVERLAY_FMA_DETAILS
1514 } overlay_fma_field_index_t;
1515 
1516 static const ofmt_field_t overlay_fma_fields[] = {
1517 { "LINK",       20,     OVERLAY_FMA_LINK,       print_overlay_fma_cb },
1518 { "STATUS",     8,      OVERLAY_FMA_STATUS,     print_overlay_fma_cb },
1519 { "DETAILS",    52,     OVERLAY_FMA_DETAILS,    print_overlay_fma_cb },
1520 { NULL,         0,      0,                      NULL }
1521 };
1522 
1523 typedef enum {
1524         OVERLAY_TARG_LINK,
1525         OVERLAY_TARG_TARGET,
1526         OVERLAY_TARG_DEST
1527 } overlay_targ_field_index_t;
1528 
1529 static const ofmt_field_t overlay_targ_fields[] = {
1530 { "LINK",               20,     OVERLAY_TARG_LINK,      print_overlay_targ_cb },
1531 { "TARGET",             18,     OVERLAY_TARG_TARGET,    print_overlay_targ_cb },
1532 { "DESTINATION",        42,     OVERLAY_TARG_DEST,      print_overlay_targ_cb },
1533 { NULL,                 0,      0,                      NULL }
1534 };
1535 
1536 static char *progname;
1537 static sig_atomic_t signalled;
1538 
1539 /*
1540  * Handle to libdladm.  Opened in main() before the sub-command
1541  * specific function is called.
1542  */
1543 static dladm_handle_t handle = NULL;
1544 
1545 /*
1546  * Global error list that all routines can use. It's initialized by the main
1547  * code.
1548  */
1549 static dladm_errlist_t errlist;
1550 
1551 #define DLADM_ETHERSTUB_NAME    "etherstub"
1552 #define DLADM_IS_ETHERSTUB(id)  (id == DATALINK_INVALID_LINKID)
1553 
1554 static void
1555 usage(void)
1556 {
1557         int     i;
1558         cmd_t   *cmdp;
1559         (void) fprintf(stderr, gettext("usage:  dladm <subcommand> <args> ..."
1560             "\n"));
1561         for (i = 0; i < sizeof (cmds) / sizeof (cmds[0]); i++) {
1562                 cmdp = &cmds[i];
1563                 if (cmdp->c_usage != NULL)
1564                         (void) fprintf(stderr, "%s\n", gettext(cmdp->c_usage));
1565         }
1566 
1567         /* close dladm handle if it was opened */
1568         if (handle != NULL)
1569                 dladm_close(handle);
1570 
1571         exit(EXIT_FAILURE);
1572 }
1573 
1574 int
1575 main(int argc, char *argv[])
1576 {
1577         int     i;
1578         cmd_t   *cmdp;
1579         dladm_status_t status;
1580 
1581         (void) setlocale(LC_ALL, "");
1582 #if !defined(TEXT_DOMAIN)
1583 #define TEXT_DOMAIN "SYS_TEST"
1584 #endif
1585         (void) textdomain(TEXT_DOMAIN);
1586 
1587         if ((progname = strrchr(argv[0], '/')) == NULL)
1588                 progname = argv[0];
1589         else
1590                 progname++;
1591 
1592         if (argc < 2) {
1593                 /*
1594                  * do_show_link() does not care if argv is null terminated
1595                  * so replace the null with "show-link" as the default command.
1596                  */
1597                 argv[1] = "show-link";
1598                 argc = 2;
1599         }
1600 
1601         for (i = 0; i < sizeof (cmds) / sizeof (cmds[0]); i++) {
1602                 cmdp = &cmds[i];
1603                 if (strcmp(argv[1], cmdp->c_name) == 0) {
1604                         /* Open the libdladm handle */
1605                         if ((status = dladm_open(&handle)) != DLADM_STATUS_OK) {
1606                                 die_dlerr(status,
1607                                     "could not open /dev/dld");
1608                         }
1609 
1610                         dladm_errlist_init(&errlist);
1611 
1612                         cmdp->c_fn(argc - 1, &argv[1], cmdp->c_usage);
1613 
1614                         dladm_close(handle);
1615                         return (EXIT_SUCCESS);
1616                 }
1617         }
1618 
1619         (void) fprintf(stderr, gettext("%s: unknown subcommand '%s'\n"),
1620             progname, argv[1]);
1621         usage();
1622         return (EXIT_FAILURE);
1623 }
1624 
1625 /*ARGSUSED*/
1626 static int
1627 show_usage_date(dladm_usage_t *usage, void *arg)
1628 {
1629         show_usage_state_t      *state = (show_usage_state_t *)arg;
1630         time_t                  stime;
1631         char                    timebuf[20];
1632         dladm_status_t          status;
1633         uint32_t                flags;
1634 
1635         /*
1636          * Only show usage information for existing links unless '-a'
1637          * is specified.
1638          */
1639         if (!state->us_showall) {
1640                 if ((status = dladm_name2info(handle, usage->du_name,
1641                     NULL, &flags, NULL, NULL)) != DLADM_STATUS_OK) {
1642                         return (status);
1643                 }
1644                 if ((flags & DLADM_OPT_ACTIVE) == 0)
1645                         return (DLADM_STATUS_LINKINVAL);
1646         }
1647 
1648         stime = usage->du_stime;
1649         (void) strftime(timebuf, sizeof (timebuf), "%m/%d/%Y",
1650             localtime(&stime));
1651         (void) printf("%s\n", timebuf);
1652 
1653         return (DLADM_STATUS_OK);
1654 }
1655 
1656 static int
1657 show_usage_time(dladm_usage_t *usage, void *arg)
1658 {
1659         show_usage_state_t      *state = (show_usage_state_t *)arg;
1660         char                    buf[DLADM_STRSIZE];
1661         usage_l_fields_buf_t    ubuf;
1662         time_t                  time;
1663         double                  bw;
1664         dladm_status_t          status;
1665         uint32_t                flags;
1666 
1667         /*
1668          * Only show usage information for existing links unless '-a'
1669          * is specified.
1670          */
1671         if (!state->us_showall) {
1672                 if ((status = dladm_name2info(handle, usage->du_name,
1673                     NULL, &flags, NULL, NULL)) != DLADM_STATUS_OK) {
1674                         return (status);
1675                 }
1676                 if ((flags & DLADM_OPT_ACTIVE) == 0)
1677                         return (DLADM_STATUS_LINKINVAL);
1678         }
1679 
1680         if (state->us_plot) {
1681                 if (!state->us_printheader) {
1682                         if (state->us_first) {
1683                                 (void) printf("# Time");
1684                                 state->us_first = B_FALSE;
1685                         }
1686                         (void) printf(" %s", usage->du_name);
1687                         if (usage->du_last) {
1688                                 (void) printf("\n");
1689                                 state->us_first = B_TRUE;
1690                                 state->us_printheader = B_TRUE;
1691                         }
1692                 } else {
1693                         if (state->us_first) {
1694                                 time = usage->du_etime;
1695                                 (void) strftime(buf, sizeof (buf), "%T",
1696                                     localtime(&time));
1697                                 state->us_first = B_FALSE;
1698                                 (void) printf("%s", buf);
1699                         }
1700                         bw = (double)usage->du_bandwidth/1000;
1701                         (void) printf(" %.2f", bw);
1702                         if (usage->du_last) {
1703                                 (void) printf("\n");
1704                                 state->us_first = B_TRUE;
1705                         }
1706                 }
1707                 return (DLADM_STATUS_OK);
1708         }
1709 
1710         bzero(&ubuf, sizeof (ubuf));
1711 
1712         (void) snprintf(ubuf.usage_l_link, sizeof (ubuf.usage_l_link), "%s",
1713             usage->du_name);
1714         time = usage->du_stime;
1715         (void) strftime(buf, sizeof (buf), "%T", localtime(&time));
1716         (void) snprintf(ubuf.usage_l_stime, sizeof (ubuf.usage_l_stime), "%s",
1717             buf);
1718         time = usage->du_etime;
1719         (void) strftime(buf, sizeof (buf), "%T", localtime(&time));
1720         (void) snprintf(ubuf.usage_l_etime, sizeof (ubuf.usage_l_etime), "%s",
1721             buf);
1722         (void) snprintf(ubuf.usage_l_rbytes, sizeof (ubuf.usage_l_rbytes),
1723             "%llu", usage->du_rbytes);
1724         (void) snprintf(ubuf.usage_l_obytes, sizeof (ubuf.usage_l_obytes),
1725             "%llu", usage->du_obytes);
1726         (void) snprintf(ubuf.usage_l_bandwidth, sizeof (ubuf.usage_l_bandwidth),
1727             "%s Mbps", dladm_bw2str(usage->du_bandwidth, buf));
1728 
1729         ofmt_print(state->us_ofmt, &ubuf);
1730         return (DLADM_STATUS_OK);
1731 }
1732 
1733 static int
1734 show_usage_res(dladm_usage_t *usage, void *arg)
1735 {
1736         show_usage_state_t      *state = (show_usage_state_t *)arg;
1737         char                    buf[DLADM_STRSIZE];
1738         usage_fields_buf_t      ubuf;
1739         dladm_status_t          status;
1740         uint32_t                flags;
1741 
1742         /*
1743          * Only show usage information for existing links unless '-a'
1744          * is specified.
1745          */
1746         if (!state->us_showall) {
1747                 if ((status = dladm_name2info(handle, usage->du_name,
1748                     NULL, &flags, NULL, NULL)) != DLADM_STATUS_OK) {
1749                         return (status);
1750                 }
1751                 if ((flags & DLADM_OPT_ACTIVE) == 0)
1752                         return (DLADM_STATUS_LINKINVAL);
1753         }
1754 
1755         bzero(&ubuf, sizeof (ubuf));
1756 
1757         (void) snprintf(ubuf.usage_link, sizeof (ubuf.usage_link), "%s",
1758             usage->du_name);
1759         (void) snprintf(ubuf.usage_duration, sizeof (ubuf.usage_duration),
1760             "%llu", usage->du_duration);
1761         (void) snprintf(ubuf.usage_ipackets, sizeof (ubuf.usage_ipackets),
1762             "%llu", usage->du_ipackets);
1763         (void) snprintf(ubuf.usage_rbytes, sizeof (ubuf.usage_rbytes),
1764             "%llu", usage->du_rbytes);
1765         (void) snprintf(ubuf.usage_opackets, sizeof (ubuf.usage_opackets),
1766             "%llu", usage->du_opackets);
1767         (void) snprintf(ubuf.usage_obytes, sizeof (ubuf.usage_obytes),
1768             "%llu", usage->du_obytes);
1769         (void) snprintf(ubuf.usage_bandwidth, sizeof (ubuf.usage_bandwidth),
1770             "%s Mbps", dladm_bw2str(usage->du_bandwidth, buf));
1771 
1772         ofmt_print(state->us_ofmt, &ubuf);
1773 
1774         return (DLADM_STATUS_OK);
1775 }
1776 
1777 static boolean_t
1778 valid_formatspec(char *formatspec_str)
1779 {
1780         if (strcmp(formatspec_str, "gnuplot") == 0)
1781                 return (B_TRUE);
1782         return (B_FALSE);
1783 
1784 }
1785 
1786 /*ARGSUSED*/
1787 static void
1788 do_show_usage(int argc, char *argv[], const char *use)
1789 {
1790         char                    *file = NULL;
1791         int                     opt;
1792         dladm_status_t          status;
1793         boolean_t               d_arg = B_FALSE;
1794         char                    *stime = NULL;
1795         char                    *etime = NULL;
1796         char                    *resource = NULL;
1797         show_usage_state_t      state;
1798         boolean_t               o_arg = B_FALSE;
1799         boolean_t               F_arg = B_FALSE;
1800         char                    *fields_str = NULL;
1801         char                    *formatspec_str = NULL;
1802         char                    *all_l_fields =
1803             "link,start,end,rbytes,obytes,bandwidth";
1804         ofmt_handle_t           ofmt;
1805         ofmt_status_t           oferr;
1806         uint_t                  ofmtflags = 0;
1807 
1808         bzero(&state, sizeof (show_usage_state_t));
1809         state.us_parsable = B_FALSE;
1810         state.us_printheader = B_FALSE;
1811         state.us_plot = B_FALSE;
1812         state.us_first = B_TRUE;
1813 
1814         while ((opt = getopt_long(argc, argv, "das:e:o:f:F:",
1815             usage_opts, NULL)) != -1) {
1816                 switch (opt) {
1817                 case 'd':
1818                         d_arg = B_TRUE;
1819                         break;
1820                 case 'a':
1821                         state.us_showall = B_TRUE;
1822                         break;
1823                 case 'f':
1824                         file = optarg;
1825                         break;
1826                 case 's':
1827                         stime = optarg;
1828                         break;
1829                 case 'e':
1830                         etime = optarg;
1831                         break;
1832                 case 'o':
1833                         o_arg = B_TRUE;
1834                         fields_str = optarg;
1835                         break;
1836                 case 'F':
1837                         state.us_plot = F_arg = B_TRUE;
1838                         formatspec_str = optarg;
1839                         break;
1840                 default:
1841                         die_opterr(optopt, opt, use);
1842                         break;
1843                 }
1844         }
1845 
1846         if (file == NULL)
1847                 die("show-usage requires a file");
1848 
1849         if (optind == (argc-1)) {
1850                 uint32_t        flags;
1851 
1852                 resource = argv[optind];
1853                 if (!state.us_showall &&
1854                     (((status = dladm_name2info(handle, resource, NULL, &flags,
1855                     NULL, NULL)) != DLADM_STATUS_OK) ||
1856                     ((flags & DLADM_OPT_ACTIVE) == 0))) {
1857                         die("invalid link: '%s'", resource);
1858                 }
1859         }
1860 
1861         if (F_arg && d_arg)
1862                 die("incompatible -d and -F options");
1863 
1864         if (F_arg && valid_formatspec(formatspec_str) == B_FALSE)
1865                 die("Format specifier %s not supported", formatspec_str);
1866 
1867         if (state.us_parsable)
1868                 ofmtflags |= OFMT_PARSABLE;
1869 
1870         if (resource == NULL && stime == NULL && etime == NULL) {
1871                 oferr = ofmt_open(fields_str, usage_fields, ofmtflags, 0,
1872                     &ofmt);
1873         } else {
1874                 if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0))
1875                         fields_str = all_l_fields;
1876                 oferr = ofmt_open(fields_str, usage_l_fields, ofmtflags, 0,
1877                     &ofmt);
1878 
1879         }
1880         ofmt_check(oferr, state.us_parsable, ofmt, die, warn);
1881         state.us_ofmt = ofmt;
1882 
1883         if (d_arg) {
1884                 /* Print log dates */
1885                 status = dladm_usage_dates(show_usage_date,
1886                     DLADM_LOGTYPE_LINK, file, resource, &state);
1887         } else if (resource == NULL && stime == NULL && etime == NULL &&
1888             !F_arg) {
1889                 /* Print summary */
1890                 status = dladm_usage_summary(show_usage_res,
1891                     DLADM_LOGTYPE_LINK, file, &state);
1892         } else if (resource != NULL) {
1893                 /* Print log entries for named resource */
1894                 status = dladm_walk_usage_res(show_usage_time,
1895                     DLADM_LOGTYPE_LINK, file, resource, stime, etime, &state);
1896         } else {
1897                 /* Print time and information for each link */
1898                 status = dladm_walk_usage_time(show_usage_time,
1899                     DLADM_LOGTYPE_LINK, file, stime, etime, &state);
1900         }
1901 
1902         if (status != DLADM_STATUS_OK)
1903                 die_dlerr(status, "show-usage");
1904         ofmt_close(ofmt);
1905 }
1906 
1907 static void
1908 do_create_aggr(int argc, char *argv[], const char *use)
1909 {
1910         int                     option;
1911         int                     key = 0;
1912         uint32_t                policy = AGGR_POLICY_L4;
1913         aggr_lacp_mode_t        lacp_mode = AGGR_LACP_OFF;
1914         aggr_lacp_timer_t       lacp_timer = AGGR_LACP_TIMER_SHORT;
1915         dladm_aggr_port_attr_db_t       port[MAXPORT];
1916         uint_t                  n, ndev, nlink;
1917         uint8_t                 mac_addr[ETHERADDRL];
1918         boolean_t               mac_addr_fixed = B_FALSE;
1919         boolean_t               P_arg = B_FALSE;
1920         boolean_t               l_arg = B_FALSE;
1921         boolean_t               u_arg = B_FALSE;
1922         boolean_t               T_arg = B_FALSE;
1923         uint32_t                flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
1924         char                    *altroot = NULL;
1925         char                    name[MAXLINKNAMELEN];
1926         char                    *devs[MAXPORT];
1927         char                    *links[MAXPORT];
1928         dladm_status_t          status;
1929         dladm_status_t          pstatus;
1930         char                    propstr[DLADM_STRSIZE];
1931         dladm_arg_list_t        *proplist = NULL;
1932         int                     i;
1933         datalink_id_t           linkid;
1934 
1935         ndev = nlink = opterr = 0;
1936         bzero(propstr, DLADM_STRSIZE);
1937 
1938         while ((option = getopt_long(argc, argv, ":d:l:L:P:R:tfu:T:p:",
1939             lopts, NULL)) != -1) {
1940                 switch (option) {
1941                 case 'd':
1942                         if (ndev + nlink >= MAXPORT)
1943                                 die("too many ports specified");
1944 
1945                         devs[ndev++] = optarg;
1946                         break;
1947                 case 'P':
1948                         if (P_arg)
1949                                 die_optdup(option);
1950 
1951                         P_arg = B_TRUE;
1952                         if (!dladm_aggr_str2policy(optarg, &policy))
1953                                 die("invalid policy '%s'", optarg);
1954                         break;
1955                 case 'u':
1956                         if (u_arg)
1957                                 die_optdup(option);
1958 
1959                         u_arg = B_TRUE;
1960                         if (!dladm_aggr_str2macaddr(optarg, &mac_addr_fixed,
1961                             mac_addr))
1962                                 die("invalid MAC address '%s'", optarg);
1963                         break;
1964                 case 'l':
1965                         if (isdigit(optarg[strlen(optarg) - 1])) {
1966 
1967                                 /*
1968                                  * Ended with digit, possibly a link name.
1969                                  */
1970                                 if (ndev + nlink >= MAXPORT)
1971                                         die("too many ports specified");
1972 
1973                                 links[nlink++] = optarg;
1974                                 break;
1975                         }
1976                         /* FALLTHROUGH */
1977                 case 'L':
1978                         if (l_arg)
1979                                 die_optdup(option);
1980 
1981                         l_arg = B_TRUE;
1982                         if (!dladm_aggr_str2lacpmode(optarg, &lacp_mode))
1983                                 die("invalid LACP mode '%s'", optarg);
1984                         break;
1985                 case 'T':
1986                         if (T_arg)
1987                                 die_optdup(option);
1988 
1989                         T_arg = B_TRUE;
1990                         if (!dladm_aggr_str2lacptimer(optarg, &lacp_timer))
1991                                 die("invalid LACP timer value '%s'", optarg);
1992                         break;
1993                 case 't':
1994                         flags &= ~DLADM_OPT_PERSIST;
1995                         break;
1996                 case 'f':
1997                         flags |= DLADM_OPT_FORCE;
1998                         break;
1999                 case 'R':
2000                         altroot = optarg;
2001                         break;
2002                 case 'p':
2003                         (void) strlcat(propstr, optarg, DLADM_STRSIZE);
2004                         if (strlcat(propstr, ",", DLADM_STRSIZE) >=
2005                             DLADM_STRSIZE)
2006                                 die("property list too long '%s'", propstr);
2007                         break;
2008 
2009                 default:
2010                         die_opterr(optopt, option, use);
2011                         break;
2012                 }
2013         }
2014 
2015         if (ndev + nlink == 0)
2016                 usage();
2017 
2018         /* get key value or the aggregation name (required last argument) */
2019         if (optind != (argc-1))
2020                 usage();
2021 
2022         if (!str2int(argv[optind], &key)) {
2023                 if (strlcpy(name, argv[optind], MAXLINKNAMELEN) >=
2024                     MAXLINKNAMELEN) {
2025                         die("link name too long '%s'", argv[optind]);
2026                 }
2027 
2028                 if (!dladm_valid_linkname(name))
2029                         die("invalid link name '%s'", argv[optind]);
2030         } else {
2031                 (void) snprintf(name, MAXLINKNAMELEN, "aggr%d", key);
2032         }
2033 
2034         if (altroot != NULL)
2035                 altroot_cmd(altroot, argc, argv);
2036 
2037         for (n = 0; n < ndev; n++) {
2038                 if ((status = dladm_dev2linkid(handle, devs[n],
2039                     &port[n].lp_linkid)) != DLADM_STATUS_OK) {
2040                         die_dlerr(status, "invalid dev name '%s'", devs[n]);
2041                 }
2042         }
2043 
2044         for (n = 0; n < nlink; n++) {
2045                 if ((status = dladm_name2info(handle, links[n],
2046                     &port[ndev + n].lp_linkid, NULL, NULL, NULL)) !=
2047                     DLADM_STATUS_OK) {
2048                         die_dlerr(status, "invalid link name '%s'", links[n]);
2049                 }
2050         }
2051 
2052         status = dladm_aggr_create(handle, name, key, ndev + nlink, port,
2053             policy, mac_addr_fixed, (const uchar_t *)mac_addr, lacp_mode,
2054             lacp_timer, flags);
2055         if (status != DLADM_STATUS_OK)
2056                 goto done;
2057 
2058         if (dladm_parse_link_props(propstr, &proplist, B_FALSE)
2059             != DLADM_STATUS_OK)
2060                 die("invalid aggregation property");
2061 
2062         if (proplist == NULL)
2063                 return;
2064 
2065         status = dladm_name2info(handle, name, &linkid, NULL, NULL, NULL);
2066         if (status != DLADM_STATUS_OK)
2067                 goto done;
2068 
2069         for (i = 0; i < proplist->al_count; i++) {
2070                 dladm_arg_info_t        *aip = &proplist->al_info[i];
2071 
2072                 pstatus = dladm_set_linkprop(handle, linkid, aip->ai_name,
2073                     aip->ai_val, aip->ai_count, flags);
2074 
2075                 if (pstatus != DLADM_STATUS_OK) {
2076                         die_dlerr(pstatus,
2077                             "aggr creation succeeded but "
2078                             "could not set property '%s'", aip->ai_name);
2079                 }
2080         }
2081 done:
2082         dladm_free_props(proplist);
2083         if (status != DLADM_STATUS_OK) {
2084                 if (status == DLADM_STATUS_NONOTIF) {
2085                         die("not all links have link up/down detection; must "
2086                             "use -f (see dladm(1M))");
2087                 } else {
2088                         die_dlerr(status, "create operation failed");
2089                 }
2090         }
2091 }
2092 
2093 /*
2094  * arg is either the key or the aggr name. Validate it and convert it to
2095  * the linkid if altroot is NULL.
2096  */
2097 static dladm_status_t
2098 i_dladm_aggr_get_linkid(const char *altroot, const char *arg,
2099     datalink_id_t *linkidp, uint32_t flags)
2100 {
2101         int             key = 0;
2102         char            *aggr = NULL;
2103         dladm_status_t  status;
2104 
2105         if (!str2int(arg, &key))
2106                 aggr = (char *)arg;
2107 
2108         if (aggr == NULL && key == 0)
2109                 return (DLADM_STATUS_LINKINVAL);
2110 
2111         if (altroot != NULL)
2112                 return (DLADM_STATUS_OK);
2113 
2114         if (aggr != NULL) {
2115                 status = dladm_name2info(handle, aggr, linkidp, NULL, NULL,
2116                     NULL);
2117         } else {
2118                 status = dladm_key2linkid(handle, key, linkidp, flags);
2119         }
2120 
2121         return (status);
2122 }
2123 
2124 static void
2125 do_delete_aggr(int argc, char *argv[], const char *use)
2126 {
2127         int                     option;
2128         char                    *altroot = NULL;
2129         uint32_t                flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
2130         dladm_status_t          status;
2131         datalink_id_t           linkid;
2132 
2133         opterr = 0;
2134         while ((option = getopt_long(argc, argv, ":R:t", lopts, NULL)) != -1) {
2135                 switch (option) {
2136                 case 't':
2137                         flags &= ~DLADM_OPT_PERSIST;
2138                         break;
2139                 case 'R':
2140                         altroot = optarg;
2141                         break;
2142                 default:
2143                         die_opterr(optopt, option, use);
2144                         break;
2145                 }
2146         }
2147 
2148         /* get key value or the aggregation name (required last argument) */
2149         if (optind != (argc-1))
2150                 usage();
2151 
2152         status = i_dladm_aggr_get_linkid(altroot, argv[optind], &linkid, flags);
2153         if (status != DLADM_STATUS_OK)
2154                 goto done;
2155 
2156         if (altroot != NULL)
2157                 altroot_cmd(altroot, argc, argv);
2158 
2159         status = dladm_aggr_delete(handle, linkid, flags);
2160 done:
2161         if (status != DLADM_STATUS_OK)
2162                 die_dlerr(status, "delete operation failed");
2163 }
2164 
2165 static void
2166 do_add_aggr(int argc, char *argv[], const char *use)
2167 {
2168         int                     option;
2169         uint_t                  n, ndev, nlink;
2170         char                    *altroot = NULL;
2171         uint32_t                flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
2172         datalink_id_t           linkid;
2173         dladm_status_t          status;
2174         dladm_aggr_port_attr_db_t       port[MAXPORT];
2175         char                    *devs[MAXPORT];
2176         char                    *links[MAXPORT];
2177 
2178         ndev = nlink = opterr = 0;
2179         while ((option = getopt_long(argc, argv, ":d:l:R:tf", lopts,
2180             NULL)) != -1) {
2181                 switch (option) {
2182                 case 'd':
2183                         if (ndev + nlink >= MAXPORT)
2184                                 die("too many ports specified");
2185 
2186                         devs[ndev++] = optarg;
2187                         break;
2188                 case 'l':
2189                         if (ndev + nlink >= MAXPORT)
2190                                 die("too many ports specified");
2191 
2192                         links[nlink++] = optarg;
2193                         break;
2194                 case 't':
2195                         flags &= ~DLADM_OPT_PERSIST;
2196                         break;
2197                 case 'f':
2198                         flags |= DLADM_OPT_FORCE;
2199                         break;
2200                 case 'R':
2201                         altroot = optarg;
2202                         break;
2203                 default:
2204                         die_opterr(optopt, option, use);
2205                         break;
2206                 }
2207         }
2208 
2209         if (ndev + nlink == 0)
2210                 usage();
2211 
2212         /* get key value or the aggregation name (required last argument) */
2213         if (optind != (argc-1))
2214                 usage();
2215 
2216         if ((status = i_dladm_aggr_get_linkid(altroot, argv[optind], &linkid,
2217             flags & (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST))) !=
2218             DLADM_STATUS_OK) {
2219                 goto done;
2220         }
2221 
2222         if (altroot != NULL)
2223                 altroot_cmd(altroot, argc, argv);
2224 
2225         for (n = 0; n < ndev; n++) {
2226                 if ((status = dladm_dev2linkid(handle, devs[n],
2227                     &(port[n].lp_linkid))) != DLADM_STATUS_OK) {
2228                         die_dlerr(status, "invalid <dev> '%s'", devs[n]);
2229                 }
2230         }
2231 
2232         for (n = 0; n < nlink; n++) {
2233                 if ((status = dladm_name2info(handle, links[n],
2234                     &port[n + ndev].lp_linkid, NULL, NULL, NULL)) !=
2235                     DLADM_STATUS_OK) {
2236                         die_dlerr(status, "invalid <link> '%s'", links[n]);
2237                 }
2238         }
2239 
2240         status = dladm_aggr_add(handle, linkid, ndev + nlink, port, flags);
2241 done:
2242         if (status != DLADM_STATUS_OK) {
2243                 /*
2244                  * checking DLADM_STATUS_NOTSUP is a temporary workaround
2245                  * and should be removed once 6399681 is fixed.
2246                  */
2247                 if (status == DLADM_STATUS_NOTSUP) {
2248                         die("add operation failed: link capabilities don't "
2249                             "match");
2250                 } else if (status == DLADM_STATUS_NONOTIF) {
2251                         die("not all links have link up/down detection; must "
2252                             "use -f (see dladm(1M))");
2253                 } else {
2254                         die_dlerr(status, "add operation failed");
2255                 }
2256         }
2257 }
2258 
2259 static void
2260 do_remove_aggr(int argc, char *argv[], const char *use)
2261 {
2262         int                             option;
2263         dladm_aggr_port_attr_db_t       port[MAXPORT];
2264         uint_t                          n, ndev, nlink;
2265         char                            *devs[MAXPORT];
2266         char                            *links[MAXPORT];
2267         char                            *altroot = NULL;
2268         uint32_t                        flags;
2269         datalink_id_t                   linkid;
2270         dladm_status_t                  status;
2271 
2272         flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
2273         ndev = nlink = opterr = 0;
2274         while ((option = getopt_long(argc, argv, ":d:l:R:t",
2275             lopts, NULL)) != -1) {
2276                 switch (option) {
2277                 case 'd':
2278                         if (ndev + nlink >= MAXPORT)
2279                                 die("too many ports specified");
2280 
2281                         devs[ndev++] = optarg;
2282                         break;
2283                 case 'l':
2284                         if (ndev + nlink >= MAXPORT)
2285                                 die("too many ports specified");
2286 
2287                         links[nlink++] = optarg;
2288                         break;
2289                 case 't':
2290                         flags &= ~DLADM_OPT_PERSIST;
2291                         break;
2292                 case 'R':
2293                         altroot = optarg;
2294                         break;
2295                 default:
2296                         die_opterr(optopt, option, use);
2297                         break;
2298                 }
2299         }
2300 
2301         if (ndev + nlink == 0)
2302                 usage();
2303 
2304         /* get key value or the aggregation name (required last argument) */
2305         if (optind != (argc-1))
2306                 usage();
2307 
2308         status = i_dladm_aggr_get_linkid(altroot, argv[optind], &linkid, flags);
2309         if (status != DLADM_STATUS_OK)
2310                 goto done;
2311 
2312         if (altroot != NULL)
2313                 altroot_cmd(altroot, argc, argv);
2314 
2315         for (n = 0; n < ndev; n++) {
2316                 if ((status = dladm_dev2linkid(handle, devs[n],
2317                     &(port[n].lp_linkid))) != DLADM_STATUS_OK) {
2318                         die_dlerr(status, "invalid <dev> '%s'", devs[n]);
2319                 }
2320         }
2321 
2322         for (n = 0; n < nlink; n++) {
2323                 if ((status = dladm_name2info(handle, links[n],
2324                     &port[n + ndev].lp_linkid, NULL, NULL, NULL)) !=
2325                     DLADM_STATUS_OK) {
2326                         die_dlerr(status, "invalid <link> '%s'", links[n]);
2327                 }
2328         }
2329 
2330         status = dladm_aggr_remove(handle, linkid, ndev + nlink, port, flags);
2331 done:
2332         if (status != DLADM_STATUS_OK)
2333                 die_dlerr(status, "remove operation failed");
2334 }
2335 
2336 static void
2337 do_modify_aggr(int argc, char *argv[], const char *use)
2338 {
2339         int                     option;
2340         uint32_t                policy = AGGR_POLICY_L4;
2341         aggr_lacp_mode_t        lacp_mode = AGGR_LACP_OFF;
2342         aggr_lacp_timer_t       lacp_timer = AGGR_LACP_TIMER_SHORT;
2343         uint8_t                 mac_addr[ETHERADDRL];
2344         boolean_t               mac_addr_fixed = B_FALSE;
2345         uint8_t                 modify_mask = 0;
2346         char                    *altroot = NULL;
2347         uint32_t                flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
2348         datalink_id_t           linkid;
2349         dladm_status_t          status;
2350 
2351         opterr = 0;
2352         while ((option = getopt_long(argc, argv, ":L:l:P:R:tu:T:", lopts,
2353             NULL)) != -1) {
2354                 switch (option) {
2355                 case 'P':
2356                         if (modify_mask & DLADM_AGGR_MODIFY_POLICY)
2357                                 die_optdup(option);
2358 
2359                         modify_mask |= DLADM_AGGR_MODIFY_POLICY;
2360 
2361                         if (!dladm_aggr_str2policy(optarg, &policy))
2362                                 die("invalid policy '%s'", optarg);
2363                         break;
2364                 case 'u':
2365                         if (modify_mask & DLADM_AGGR_MODIFY_MAC)
2366                                 die_optdup(option);
2367 
2368                         modify_mask |= DLADM_AGGR_MODIFY_MAC;
2369 
2370                         if (!dladm_aggr_str2macaddr(optarg, &mac_addr_fixed,
2371                             mac_addr))
2372                                 die("invalid MAC address '%s'", optarg);
2373                         break;
2374                 case 'l':
2375                 case 'L':
2376                         if (modify_mask & DLADM_AGGR_MODIFY_LACP_MODE)
2377                                 die_optdup(option);
2378 
2379                         modify_mask |= DLADM_AGGR_MODIFY_LACP_MODE;
2380 
2381                         if (!dladm_aggr_str2lacpmode(optarg, &lacp_mode))
2382                                 die("invalid LACP mode '%s'", optarg);
2383                         break;
2384                 case 'T':
2385                         if (modify_mask & DLADM_AGGR_MODIFY_LACP_TIMER)
2386                                 die_optdup(option);
2387 
2388                         modify_mask |= DLADM_AGGR_MODIFY_LACP_TIMER;
2389 
2390                         if (!dladm_aggr_str2lacptimer(optarg, &lacp_timer))
2391                                 die("invalid LACP timer value '%s'", optarg);
2392                         break;
2393                 case 't':
2394                         flags &= ~DLADM_OPT_PERSIST;
2395                         break;
2396                 case 'R':
2397                         altroot = optarg;
2398                         break;
2399                 default:
2400                         die_opterr(optopt, option, use);
2401                         break;
2402                 }
2403         }
2404 
2405         if (modify_mask == 0)
2406                 die("at least one of the -PulT options must be specified");
2407 
2408         /* get key value or the aggregation name (required last argument) */
2409         if (optind != (argc-1))
2410                 usage();
2411 
2412         status = i_dladm_aggr_get_linkid(altroot, argv[optind], &linkid, flags);
2413         if (status != DLADM_STATUS_OK)
2414                 goto done;
2415 
2416         if (altroot != NULL)
2417                 altroot_cmd(altroot, argc, argv);
2418 
2419         status = dladm_aggr_modify(handle, linkid, modify_mask, policy,
2420             mac_addr_fixed, (const uchar_t *)mac_addr, lacp_mode, lacp_timer,
2421             flags);
2422 
2423 done:
2424         if (status != DLADM_STATUS_OK)
2425                 die_dlerr(status, "modify operation failed");
2426 }
2427 
2428 /*ARGSUSED*/
2429 static void
2430 do_up_aggr(int argc, char *argv[], const char *use)
2431 {
2432         datalink_id_t   linkid = DATALINK_ALL_LINKID;
2433         dladm_status_t  status;
2434 
2435         /*
2436          * get the key or the name of the aggregation (optional last argument)
2437          */
2438         if (argc == 2) {
2439                 if ((status = i_dladm_aggr_get_linkid(NULL, argv[1], &linkid,
2440                     DLADM_OPT_PERSIST)) != DLADM_STATUS_OK)
2441                         goto done;
2442         } else if (argc > 2) {
2443                 usage();
2444         }
2445 
2446         status = dladm_aggr_up(handle, linkid);
2447 done:
2448         if (status != DLADM_STATUS_OK) {
2449                 if (argc == 2) {
2450                         die_dlerr(status,
2451                             "could not bring up aggregation '%s'", argv[1]);
2452                 } else {
2453                         die_dlerr(status, "could not bring aggregations up");
2454                 }
2455         }
2456 }
2457 
2458 static void
2459 do_create_vlan(int argc, char *argv[], const char *use)
2460 {
2461         char                    *link = NULL;
2462         char                    drv[DLPI_LINKNAME_MAX];
2463         uint_t                  ppa;
2464         datalink_id_t           linkid;
2465         datalink_id_t           dev_linkid;
2466         int                     vid = 0;
2467         int                     option;
2468         uint32_t                flags = (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST);
2469         char                    *altroot = NULL;
2470         char                    vlan[MAXLINKNAMELEN];
2471         char                    propstr[DLADM_STRSIZE];
2472         dladm_arg_list_t        *proplist = NULL;
2473         dladm_status_t          status;
2474 
2475         opterr = 0;
2476         bzero(propstr, DLADM_STRSIZE);
2477 
2478         while ((option = getopt_long(argc, argv, ":tfR:l:v:p:",
2479             lopts, NULL)) != -1) {
2480                 switch (option) {
2481                 case 'v':
2482                         if (vid != 0)
2483                                 die_optdup(option);
2484 
2485                         if (!str2int(optarg, &vid) || vid < 1 || vid > 4094)
2486                                 die("invalid VLAN identifier '%s'", optarg);
2487 
2488                         break;
2489                 case 'l':
2490                         if (link != NULL)
2491                                 die_optdup(option);
2492 
2493                         link = optarg;
2494                         break;
2495                 case 't':
2496                         flags &= ~DLADM_OPT_PERSIST;
2497                         break;
2498                 case 'R':
2499                         altroot = optarg;
2500                         break;
2501                 case 'p':
2502                         (void) strlcat(propstr, optarg, DLADM_STRSIZE);
2503                         if (strlcat(propstr, ",", DLADM_STRSIZE) >=
2504                             DLADM_STRSIZE)
2505                                 die("property list too long '%s'", propstr);
2506                         break;
2507                 case 'f':
2508                         flags |= DLADM_OPT_FORCE;
2509                         break;
2510                 default:
2511                         die_opterr(optopt, option, use);
2512                         break;
2513                 }
2514         }
2515 
2516         /* get vlan name if there is any */
2517         if ((vid == 0) || (link == NULL) || (argc - optind > 1))
2518                 usage();
2519 
2520         if (optind == (argc - 1)) {
2521                 if (strlcpy(vlan, argv[optind], MAXLINKNAMELEN) >=
2522                     MAXLINKNAMELEN) {
2523                         die("vlan name too long '%s'", argv[optind]);
2524                 }
2525         } else {
2526                 if ((dlpi_parselink(link, drv, &ppa) != DLPI_SUCCESS) ||
2527                     (ppa >= 1000) ||
2528                     (dlpi_makelink(vlan, drv, vid * 1000 + ppa) !=
2529                     DLPI_SUCCESS)) {
2530                         die("invalid link name '%s'", link);
2531                 }
2532         }
2533 
2534         if (altroot != NULL)
2535                 altroot_cmd(altroot, argc, argv);
2536 
2537         if (dladm_name2info(handle, link, &dev_linkid, NULL, NULL, NULL) !=
2538             DLADM_STATUS_OK) {
2539                 die("invalid link name '%s'", link);
2540         }
2541 
2542         if (dladm_parse_link_props(propstr, &proplist, B_FALSE)
2543             != DLADM_STATUS_OK)
2544                 die("invalid vlan property");
2545 
2546         status = dladm_vlan_create(handle, vlan, dev_linkid, vid, proplist,
2547             flags, &linkid);
2548         switch (status) {
2549         case DLADM_STATUS_OK:
2550                 break;
2551 
2552         case DLADM_STATUS_NOTSUP:
2553                 die("VLAN over '%s' may require lowered MTU; must use -f (see "
2554                     "dladm(1M))", link);
2555                 break;
2556 
2557         case DLADM_STATUS_LINKBUSY:
2558                 die("VLAN over '%s' may not use default_tag ID "
2559                     "(see dladm(1M))", link);
2560                 break;
2561 
2562         default:
2563                 die_dlerr(status, "create operation failed");
2564         }
2565 }
2566 
2567 static void
2568 do_delete_vlan(int argc, char *argv[], const char *use)
2569 {
2570         int             option;
2571         uint32_t        flags = (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST);
2572         char            *altroot = NULL;
2573         datalink_id_t   linkid;
2574         dladm_status_t  status;
2575 
2576         opterr = 0;
2577         while ((option = getopt_long(argc, argv, ":R:t", lopts, NULL)) != -1) {
2578                 switch (option) {
2579                 case 't':
2580                         flags &= ~DLADM_OPT_PERSIST;
2581                         break;
2582                 case 'R':
2583                         altroot = optarg;
2584                         break;
2585                 default:
2586                         die_opterr(optopt, option, use);
2587                         break;
2588                 }
2589         }
2590 
2591         /* get VLAN link name (required last argument) */
2592         if (optind != (argc - 1))
2593                 usage();
2594 
2595         if (altroot != NULL)
2596                 altroot_cmd(altroot, argc, argv);
2597 
2598         status = dladm_name2info(handle, argv[optind], &linkid, NULL, NULL,
2599             NULL);
2600         if (status != DLADM_STATUS_OK)
2601                 goto done;
2602 
2603         status = dladm_vlan_delete(handle, linkid, flags);
2604 done:
2605         if (status != DLADM_STATUS_OK)
2606                 die_dlerr(status, "delete operation failed");
2607 }
2608 
2609 /*ARGSUSED*/
2610 static void
2611 do_up_vlan(int argc, char *argv[], const char *use)
2612 {
2613         do_up_vnic_common(argc, argv, use, B_TRUE);
2614 }
2615 
2616 static void
2617 do_rename_link(int argc, char *argv[], const char *use)
2618 {
2619         int             option;
2620         char            *link1, *link2;
2621         char            *altroot = NULL;
2622         dladm_status_t  status;
2623 
2624         opterr = 0;
2625         while ((option = getopt_long(argc, argv, ":R:", lopts, NULL)) != -1) {
2626                 switch (option) {
2627                 case 'R':
2628                         altroot = optarg;
2629                         break;
2630                 default:
2631                         die_opterr(optopt, option, use);
2632                         break;
2633                 }
2634         }
2635 
2636         /* get link1 and link2 name (required the last 2 arguments) */
2637         if (optind != (argc - 2))
2638                 usage();
2639 
2640         if (altroot != NULL)
2641                 altroot_cmd(altroot, argc, argv);
2642 
2643         link1 = argv[optind++];
2644         link2 = argv[optind];
2645         if ((status = dladm_rename_link(handle, link1, link2)) !=
2646             DLADM_STATUS_OK)
2647                 die_dlerr(status, "rename operation failed");
2648 }
2649 
2650 /*ARGSUSED*/
2651 static void
2652 do_delete_phys(int argc, char *argv[], const char *use)
2653 {
2654         datalink_id_t   linkid = DATALINK_ALL_LINKID;
2655         dladm_status_t  status;
2656 
2657         /* get link name (required the last argument) */
2658         if (argc > 2)
2659                 usage();
2660 
2661         if (argc == 2) {
2662                 if ((status = dladm_name2info(handle, argv[1], &linkid, NULL,
2663                     NULL, NULL)) != DLADM_STATUS_OK)
2664                         die_dlerr(status, "cannot delete '%s'", argv[1]);
2665         }
2666 
2667         if ((status = dladm_phys_delete(handle, linkid)) != DLADM_STATUS_OK) {
2668                 if (argc == 2)
2669                         die_dlerr(status, "cannot delete '%s'", argv[1]);
2670                 else
2671                         die_dlerr(status, "delete operation failed");
2672         }
2673 }
2674 
2675 /*ARGSUSED*/
2676 static int
2677 i_dladm_walk_linkmap(dladm_handle_t dh, datalink_id_t linkid, void *arg)
2678 {
2679         char                    name[MAXLINKNAMELEN];
2680         char                    mediabuf[DLADM_STRSIZE];
2681         char                    classbuf[DLADM_STRSIZE];
2682         datalink_class_t        class;
2683         uint32_t                media;
2684         uint32_t                flags;
2685 
2686         if (dladm_datalink_id2info(dh, linkid, &flags, &class, &media, name,
2687             MAXLINKNAMELEN) == DLADM_STATUS_OK) {
2688                 (void) dladm_class2str(class, classbuf);
2689                 (void) dladm_media2str(media, mediabuf);
2690                 (void) printf("%-12s%8d  %-12s%-20s %6d\n", name,
2691                     linkid, classbuf, mediabuf, flags);
2692         }
2693         return (DLADM_WALK_CONTINUE);
2694 }
2695 
2696 /*ARGSUSED*/
2697 static void
2698 do_show_linkmap(int argc, char *argv[], const char *use)
2699 {
2700         if (argc != 1)
2701                 die("invalid arguments");
2702 
2703         (void) printf("%-12s%8s  %-12s%-20s %6s\n", "NAME", "LINKID",
2704             "CLASS", "MEDIA", "FLAGS");
2705 
2706         (void) dladm_walk_datalink_id(i_dladm_walk_linkmap, handle, NULL,
2707             DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE,
2708             DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST);
2709 }
2710 
2711 /*
2712  * Delete inactive physical links.
2713  */
2714 /*ARGSUSED*/
2715 static int
2716 purge_phys(dladm_handle_t dh, datalink_id_t linkid, void *arg)
2717 {
2718         datalink_class_t        class;
2719         uint32_t                flags;
2720 
2721         if (dladm_datalink_id2info(dh, linkid, &flags, &class, NULL, NULL, 0)
2722             != DLADM_STATUS_OK) {
2723                 return (DLADM_WALK_CONTINUE);
2724         }
2725 
2726         if (class == DATALINK_CLASS_PHYS && !(flags & DLADM_OPT_ACTIVE))
2727                 (void) dladm_phys_delete(dh, linkid);
2728 
2729         return (DLADM_WALK_CONTINUE);
2730 }
2731 
2732 /*ARGSUSED*/
2733 static void
2734 do_init_phys(int argc, char *argv[], const char *use)
2735 {
2736         di_node_t       devtree;
2737 
2738         if (argc > 1)
2739                 usage();
2740 
2741         /*
2742          * Force all the devices to attach, therefore all the network physical
2743          * devices can be known to the dlmgmtd daemon.
2744          */
2745         if ((devtree = di_init("/", DINFOFORCE | DINFOSUBTREE)) != DI_NODE_NIL)
2746                 di_fini(devtree);
2747 
2748         (void) dladm_walk_datalink_id(purge_phys, handle, NULL,
2749             DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST);
2750 }
2751 
2752 /*
2753  * Print the active topology information.
2754  */
2755 void
2756 print_link_topology(show_state_t *state, datalink_id_t linkid,
2757     datalink_class_t class, link_fields_buf_t *lbuf)
2758 {
2759         uint32_t        flags = state->ls_flags;
2760         dladm_status_t  status;
2761         char            tmpbuf[MAXLINKNAMELEN];
2762 
2763         lbuf->link_over[0] = '\0';
2764         lbuf->link_bridge[0] = '\0';
2765 
2766         switch (class) {
2767         case DATALINK_CLASS_AGGR:
2768         case DATALINK_CLASS_PHYS:
2769         case DATALINK_CLASS_ETHERSTUB:
2770                 status = dladm_bridge_getlink(handle, linkid, lbuf->link_bridge,
2771                     sizeof (lbuf->link_bridge));
2772                 if (status != DLADM_STATUS_OK &&
2773                     status != DLADM_STATUS_NOTFOUND)
2774                         (void) strcpy(lbuf->link_bridge, "?");
2775                 break;
2776         }
2777 
2778         switch (class) {
2779         case DATALINK_CLASS_VLAN: {
2780                 dladm_vlan_attr_t       vinfo;
2781 
2782                 if (dladm_vlan_info(handle, linkid, &vinfo, flags) !=
2783                     DLADM_STATUS_OK) {
2784                         (void) strcpy(lbuf->link_over, "?");
2785                         break;
2786                 }
2787                 if (dladm_datalink_id2info(handle, vinfo.dv_linkid, NULL, NULL,
2788                     NULL, lbuf->link_over, sizeof (lbuf->link_over)) !=
2789                     DLADM_STATUS_OK)
2790                         (void) strcpy(lbuf->link_over, "?");
2791                 break;
2792         }
2793         case DATALINK_CLASS_AGGR: {
2794                 dladm_aggr_grp_attr_t   ginfo;
2795                 int                     i;
2796 
2797                 if (dladm_aggr_info(handle, linkid, &ginfo, flags) !=
2798                     DLADM_STATUS_OK || ginfo.lg_nports == 0) {
2799                         (void) strcpy(lbuf->link_over, "?");
2800                         break;
2801                 }
2802                 for (i = 0; i < ginfo.lg_nports; i++) {
2803                         if (dladm_datalink_id2info(handle,
2804                             ginfo.lg_ports[i].lp_linkid, NULL, NULL, NULL,
2805                             tmpbuf, sizeof (tmpbuf)) != DLADM_STATUS_OK) {
2806                                 (void) strcpy(lbuf->link_over, "?");
2807                                 break;
2808                         }
2809                         (void) strlcat(lbuf->link_over, tmpbuf,
2810                             sizeof (lbuf->link_over));
2811                         if (i != (ginfo.lg_nports - 1)) {
2812                                 (void) strlcat(lbuf->link_over, ",",
2813                                     sizeof (lbuf->link_over));
2814                         }
2815                 }
2816                 free(ginfo.lg_ports);
2817                 break;
2818         }
2819         case DATALINK_CLASS_VNIC: {
2820                 dladm_vnic_attr_t       vinfo;
2821 
2822                 if (dladm_vnic_info(handle, linkid, &vinfo, flags) !=
2823                     DLADM_STATUS_OK) {
2824                         (void) strcpy(lbuf->link_over, "?");
2825                         break;
2826                 }
2827                 if (dladm_datalink_id2info(handle, vinfo.va_link_id, NULL, NULL,
2828                     NULL, lbuf->link_over, sizeof (lbuf->link_over)) !=
2829                     DLADM_STATUS_OK)
2830                         (void) strcpy(lbuf->link_over, "?");
2831                 break;
2832         }
2833 
2834         case DATALINK_CLASS_PART: {
2835                 dladm_part_attr_t       pinfo;
2836 
2837                 if (dladm_part_info(handle, linkid, &pinfo, flags) !=
2838                     DLADM_STATUS_OK) {
2839                         (void) strcpy(lbuf->link_over, "?");
2840                         break;
2841                 }
2842                 if (dladm_datalink_id2info(handle, pinfo.dia_physlinkid, NULL,
2843                     NULL, NULL, lbuf->link_over, sizeof (lbuf->link_over)) !=
2844                     DLADM_STATUS_OK)
2845                         (void) strcpy(lbuf->link_over, "?");
2846                 break;
2847         }
2848 
2849         case DATALINK_CLASS_BRIDGE: {
2850                 datalink_id_t *dlp;
2851                 uint_t i, nports;
2852 
2853                 if (dladm_datalink_id2info(handle, linkid, NULL, NULL,
2854                     NULL, tmpbuf, sizeof (tmpbuf)) != DLADM_STATUS_OK) {
2855                         (void) strcpy(lbuf->link_over, "?");
2856                         break;
2857                 }
2858                 if (tmpbuf[0] != '\0')
2859                         tmpbuf[strlen(tmpbuf) - 1] = '\0';
2860                 dlp = dladm_bridge_get_portlist(tmpbuf, &nports);
2861                 if (dlp == NULL) {
2862                         (void) strcpy(lbuf->link_over, "?");
2863                         break;
2864                 }
2865                 for (i = 0; i < nports; i++) {
2866                         if (dladm_datalink_id2info(handle, dlp[i], NULL,
2867                             NULL, NULL, tmpbuf, sizeof (tmpbuf)) !=
2868                             DLADM_STATUS_OK) {
2869                                 (void) strcpy(lbuf->link_over, "?");
2870                                 break;
2871                         }
2872                         (void) strlcat(lbuf->link_over, tmpbuf,
2873                             sizeof (lbuf->link_over));
2874                         if (i != nports - 1) {
2875                                 (void) strlcat(lbuf->link_over, ",",
2876                                     sizeof (lbuf->link_over));
2877                         }
2878                 }
2879                 dladm_bridge_free_portlist(dlp);
2880                 break;
2881         }
2882 
2883         case DATALINK_CLASS_SIMNET: {
2884                 dladm_simnet_attr_t     slinfo;
2885 
2886                 if (dladm_simnet_info(handle, linkid, &slinfo, flags) !=
2887                     DLADM_STATUS_OK) {
2888                         (void) strcpy(lbuf->link_over, "?");
2889                         break;
2890                 }
2891                 if (slinfo.sna_peer_link_id != DATALINK_INVALID_LINKID) {
2892                         if (dladm_datalink_id2info(handle,
2893                             slinfo.sna_peer_link_id, NULL, NULL, NULL,
2894                             lbuf->link_over, sizeof (lbuf->link_over)) !=
2895                             DLADM_STATUS_OK)
2896                                 (void) strcpy(lbuf->link_over, "?");
2897                 }
2898                 break;
2899         }
2900         }
2901 }
2902 
2903 static dladm_status_t
2904 print_link(show_state_t *state, datalink_id_t linkid, link_fields_buf_t *lbuf)
2905 {
2906         char                    link[MAXLINKNAMELEN];
2907         datalink_class_t        class;
2908         uint_t                  mtu;
2909         uint32_t                flags;
2910         dladm_status_t          status;
2911 
2912         if ((status = dladm_datalink_id2info(handle, linkid, &flags, &class,
2913             NULL, link, sizeof (link))) != DLADM_STATUS_OK) {
2914                 goto done;
2915         }
2916 
2917         if (!(state->ls_flags & flags)) {
2918                 status = DLADM_STATUS_NOTFOUND;
2919                 goto done;
2920         }
2921 
2922         if (state->ls_flags == DLADM_OPT_ACTIVE) {
2923                 dladm_attr_t    dlattr;
2924 
2925                 if (class == DATALINK_CLASS_PHYS) {
2926                         dladm_phys_attr_t       dpa;
2927                         dlpi_handle_t           dh;
2928                         dlpi_info_t             dlinfo;
2929 
2930                         if ((status = dladm_phys_info(handle, linkid, &dpa,
2931                             DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) {
2932                                 goto done;
2933                         }
2934 
2935                         if (!dpa.dp_novanity)
2936                                 goto link_mtu;
2937 
2938                         /*
2939                          * This is a physical link that does not have
2940                          * vanity naming support.
2941                          */
2942                         if (dlpi_open(dpa.dp_dev, &dh, DLPI_DEVONLY) !=
2943                             DLPI_SUCCESS) {
2944                                 status = DLADM_STATUS_NOTFOUND;
2945                                 goto done;
2946                         }
2947 
2948                         if (dlpi_info(dh, &dlinfo, 0) != DLPI_SUCCESS) {
2949                                 dlpi_close(dh);
2950                                 status = DLADM_STATUS_BADARG;
2951                                 goto done;
2952                         }
2953 
2954                         dlpi_close(dh);
2955                         mtu = dlinfo.di_max_sdu;
2956                 } else {
2957 link_mtu:
2958                         status = dladm_info(handle, linkid, &dlattr);
2959                         if (status != DLADM_STATUS_OK)
2960                                 goto done;
2961                         mtu = dlattr.da_max_sdu;
2962                 }
2963         }
2964 
2965         (void) snprintf(lbuf->link_name, sizeof (lbuf->link_name),
2966             "%s", link);
2967         (void) dladm_class2str(class, lbuf->link_class);
2968         if (state->ls_flags == DLADM_OPT_ACTIVE) {
2969                 (void) snprintf(lbuf->link_mtu, sizeof (lbuf->link_mtu),
2970                     "%u", mtu);
2971                 (void) get_linkstate(link, B_TRUE, lbuf->link_state);
2972         }
2973 
2974         print_link_topology(state, linkid, class, lbuf);
2975 done:
2976         return (status);
2977 }
2978 
2979 /* ARGSUSED */
2980 static int
2981 show_link(dladm_handle_t dh, datalink_id_t linkid, void *arg)
2982 {
2983         show_state_t            *state = (show_state_t *)arg;
2984         dladm_status_t          status;
2985         link_fields_buf_t       lbuf;
2986 
2987         /*
2988          * first get all the link attributes into lbuf;
2989          */
2990         bzero(&lbuf, sizeof (link_fields_buf_t));
2991         if ((status = print_link(state, linkid, &lbuf)) == DLADM_STATUS_OK)
2992                 ofmt_print(state->ls_ofmt, &lbuf);
2993         state->ls_status = status;
2994         return (DLADM_WALK_CONTINUE);
2995 }
2996 
2997 static boolean_t
2998 print_link_stats_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
2999 {
3000         link_args_t *largs = ofarg->ofmt_cbarg;
3001         pktsum_t *diff_stats = largs->link_s_psum;
3002 
3003         switch (ofarg->ofmt_id) {
3004         case LINK_S_LINK:
3005                 (void) snprintf(buf, bufsize, "%s", largs->link_s_link);
3006                 break;
3007         case LINK_S_IPKTS:
3008                 (void) snprintf(buf, bufsize, "%llu", diff_stats->ipackets);
3009                 break;
3010         case LINK_S_RBYTES:
3011                 (void) snprintf(buf, bufsize, "%llu", diff_stats->rbytes);
3012                 break;
3013         case LINK_S_IERRORS:
3014                 (void) snprintf(buf, bufsize, "%u", diff_stats->ierrors);
3015                 break;
3016         case LINK_S_OPKTS:
3017                 (void) snprintf(buf, bufsize, "%llu", diff_stats->opackets);
3018                 break;
3019         case LINK_S_OBYTES:
3020                 (void) snprintf(buf, bufsize, "%llu", diff_stats->obytes);
3021                 break;
3022         case LINK_S_OERRORS:
3023                 (void) snprintf(buf, bufsize, "%u", diff_stats->oerrors);
3024                 break;
3025         default:
3026                 die("invalid input");
3027                 break;
3028         }
3029         return (B_TRUE);
3030 }
3031 
3032 static int
3033 show_link_stats(dladm_handle_t dh, datalink_id_t linkid, void *arg)
3034 {
3035         char                    link[DLPI_LINKNAME_MAX];
3036         datalink_class_t        class;
3037         show_state_t            *state = arg;
3038         pktsum_t                stats, diff_stats;
3039         dladm_phys_attr_t       dpa;
3040         link_args_t             largs;
3041 
3042         if (state->ls_firstonly) {
3043                 if (state->ls_donefirst)
3044                         return (DLADM_WALK_CONTINUE);
3045                 state->ls_donefirst = B_TRUE;
3046         } else {
3047                 bzero(&state->ls_prevstats, sizeof (state->ls_prevstats));
3048         }
3049 
3050         if (dladm_datalink_id2info(dh, linkid, NULL, &class, NULL, link,
3051             DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) {
3052                 return (DLADM_WALK_CONTINUE);
3053         }
3054 
3055         if (class == DATALINK_CLASS_PHYS) {
3056                 if (dladm_phys_info(dh, linkid, &dpa, DLADM_OPT_ACTIVE) !=
3057                     DLADM_STATUS_OK) {
3058                         return (DLADM_WALK_CONTINUE);
3059                 }
3060                 if (dpa.dp_novanity)
3061                         get_mac_stats(dpa.dp_dev, &stats);
3062                 else
3063                         get_link_stats(link, &stats);
3064         } else {
3065                 get_link_stats(link, &stats);
3066         }
3067         dladm_stats_diff(&diff_stats, &stats, &state->ls_prevstats);
3068 
3069         largs.link_s_link = link;
3070         largs.link_s_psum = &diff_stats;
3071         ofmt_print(state->ls_ofmt, &largs);
3072 
3073         state->ls_prevstats = stats;
3074         return (DLADM_WALK_CONTINUE);
3075 }
3076 
3077 
3078 static dladm_status_t
3079 print_aggr_info(show_grp_state_t *state, const char *link,
3080     dladm_aggr_grp_attr_t *ginfop)
3081 {
3082         char                    addr_str[ETHERADDRL * 3];
3083         laggr_fields_buf_t      lbuf;
3084 
3085         (void) snprintf(lbuf.laggr_name, sizeof (lbuf.laggr_name),
3086             "%s", link);
3087 
3088         (void) dladm_aggr_policy2str(ginfop->lg_policy,
3089             lbuf.laggr_policy);
3090 
3091         if (ginfop->lg_mac_fixed) {
3092                 (void) dladm_aggr_macaddr2str(ginfop->lg_mac, addr_str);
3093                 (void) snprintf(lbuf.laggr_addrpolicy,
3094                     sizeof (lbuf.laggr_addrpolicy), "fixed (%s)", addr_str);
3095         } else {
3096                 (void) snprintf(lbuf.laggr_addrpolicy,
3097                     sizeof (lbuf.laggr_addrpolicy), "auto");
3098         }
3099 
3100         (void) dladm_aggr_lacpmode2str(ginfop->lg_lacp_mode,
3101             lbuf.laggr_lacpactivity);
3102         (void) dladm_aggr_lacptimer2str(ginfop->lg_lacp_timer,
3103             lbuf.laggr_lacptimer);
3104         (void) snprintf(lbuf.laggr_flags, sizeof (lbuf.laggr_flags), "%c----",
3105             ginfop->lg_force ? 'f' : '-');
3106 
3107         ofmt_print(state->gs_ofmt, &lbuf);
3108 
3109         return (DLADM_STATUS_OK);
3110 }
3111 
3112 static boolean_t
3113 print_xaggr_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
3114 {
3115         const laggr_args_t      *l = ofarg->ofmt_cbarg;
3116         boolean_t               is_port = (l->laggr_lport >= 0);
3117         char                    tmpbuf[DLADM_STRSIZE];
3118         const char              *objname;
3119         dladm_aggr_port_attr_t  *portp;
3120         dladm_phys_attr_t       dpa;
3121 
3122         if (is_port) {
3123                 portp = &(l->laggr_ginfop->lg_ports[l->laggr_lport]);
3124                 if (dladm_phys_info(handle, portp->lp_linkid, &dpa,
3125                     DLADM_OPT_ACTIVE) != DLADM_STATUS_OK)
3126                         objname = "?";
3127                 else
3128                         objname = dpa.dp_dev;
3129         } else {
3130                 objname = l->laggr_link;
3131         }
3132 
3133         switch (ofarg->ofmt_id) {
3134         case AGGR_X_LINK:
3135                 (void) snprintf(buf, bufsize, "%s",
3136                     (is_port && !l->laggr_parsable ? " " : l->laggr_link));
3137                 break;
3138         case AGGR_X_PORT:
3139                 if (is_port) {
3140                         if (dladm_datalink_id2info(handle, portp->lp_linkid,
3141                             NULL, NULL, NULL, buf, bufsize) != DLADM_STATUS_OK)
3142                                 (void) sprintf(buf, "?");
3143                 }
3144                 break;
3145 
3146         case AGGR_X_SPEED:
3147                 (void) snprintf(buf, bufsize, "%uMb",
3148                     (uint_t)((get_ifspeed(objname, !is_port)) / 1000000ull));
3149                 break;
3150 
3151         case AGGR_X_DUPLEX:
3152                 (void) get_linkduplex(objname, !is_port, tmpbuf);
3153                 (void) strlcpy(buf, tmpbuf, bufsize);
3154                 break;
3155 
3156         case AGGR_X_STATE:
3157                 (void) get_linkstate(objname, !is_port, tmpbuf);
3158                 (void) strlcpy(buf, tmpbuf, bufsize);
3159                 break;
3160         case AGGR_X_ADDRESS:
3161                 (void) dladm_aggr_macaddr2str(
3162                     (is_port ? portp->lp_mac : l->laggr_ginfop->lg_mac),
3163                     tmpbuf);
3164                 (void) strlcpy(buf, tmpbuf, bufsize);
3165                 break;
3166         case AGGR_X_PORTSTATE:
3167                 if (is_port) {
3168                         (void) dladm_aggr_portstate2str(portp->lp_state,
3169                             tmpbuf);
3170                         (void) strlcpy(buf, tmpbuf, bufsize);
3171                 }
3172                 break;
3173         }
3174 err:
3175         *(l->laggr_status) = DLADM_STATUS_OK;
3176         return (B_TRUE);
3177 }
3178 
3179 static dladm_status_t
3180 print_aggr_extended(show_grp_state_t *state, const char *link,
3181     dladm_aggr_grp_attr_t *ginfop)
3182 {
3183         int                     i;
3184         dladm_status_t          status;
3185         laggr_args_t            largs;
3186 
3187         largs.laggr_lport = -1;
3188         largs.laggr_link = link;
3189         largs.laggr_ginfop = ginfop;
3190         largs.laggr_status = &status;
3191         largs.laggr_parsable = state->gs_parsable;
3192 
3193         ofmt_print(state->gs_ofmt, &largs);
3194 
3195         if (status != DLADM_STATUS_OK)
3196                 goto done;
3197 
3198         for (i = 0; i < ginfop->lg_nports; i++) {
3199                 largs.laggr_lport = i;
3200                 ofmt_print(state->gs_ofmt, &largs);
3201                 if (status != DLADM_STATUS_OK)
3202                         goto done;
3203         }
3204 
3205         status = DLADM_STATUS_OK;
3206 done:
3207         return (status);
3208 }
3209 
3210 static boolean_t
3211 print_lacp_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
3212 {
3213         const laggr_args_t      *l = ofarg->ofmt_cbarg;
3214         int                     portnum;
3215         boolean_t               is_port = (l->laggr_lport >= 0);
3216         dladm_aggr_port_attr_t  *portp;
3217         aggr_lacp_state_t       *lstate;
3218 
3219         if (!is_port)
3220                 return (B_FALSE); /* cannot happen! */
3221 
3222         portnum = l->laggr_lport;
3223         portp = &(l->laggr_ginfop->lg_ports[portnum]);
3224         lstate = &(portp->lp_lacp_state);
3225 
3226         switch (ofarg->ofmt_id) {
3227         case AGGR_L_LINK:
3228                 (void) snprintf(buf, bufsize, "%s",
3229                     (portnum > 0 ? "" : l->laggr_link));
3230                 break;
3231 
3232         case AGGR_L_PORT:
3233                 if (dladm_datalink_id2info(handle, portp->lp_linkid, NULL, NULL,
3234                     NULL, buf, bufsize) != DLADM_STATUS_OK)
3235                         (void) sprintf(buf, "?");
3236                 break;
3237 
3238         case AGGR_L_AGGREGATABLE:
3239                 (void) snprintf(buf, bufsize, "%s",
3240                     (lstate->bit.aggregation ? "yes" : "no"));
3241                 break;
3242 
3243         case AGGR_L_SYNC:
3244                 (void) snprintf(buf, bufsize, "%s",
3245                     (lstate->bit.sync ? "yes" : "no"));
3246                 break;
3247 
3248         case AGGR_L_COLL:
3249                 (void) snprintf(buf, bufsize, "%s",
3250                     (lstate->bit.collecting ? "yes" : "no"));
3251                 break;
3252 
3253         case AGGR_L_DIST:
3254                 (void) snprintf(buf, bufsize, "%s",
3255                     (lstate->bit.distributing ? "yes" : "no"));
3256                 break;
3257 
3258         case AGGR_L_DEFAULTED:
3259                 (void) snprintf(buf, bufsize, "%s",
3260                     (lstate->bit.defaulted ? "yes" : "no"));
3261                 break;
3262 
3263         case AGGR_L_EXPIRED:
3264                 (void) snprintf(buf, bufsize, "%s",
3265                     (lstate->bit.expired ? "yes" : "no"));
3266                 break;
3267         }
3268 
3269         *(l->laggr_status) = DLADM_STATUS_OK;
3270         return (B_TRUE);
3271 }
3272 
3273 static dladm_status_t
3274 print_aggr_lacp(show_grp_state_t *state, const char *link,
3275     dladm_aggr_grp_attr_t *ginfop)
3276 {
3277         int             i;
3278         dladm_status_t  status;
3279         laggr_args_t    largs;
3280 
3281         largs.laggr_link = link;
3282         largs.laggr_ginfop = ginfop;
3283         largs.laggr_status = &status;
3284 
3285         for (i = 0; i < ginfop->lg_nports; i++) {
3286                 largs.laggr_lport = i;
3287                 ofmt_print(state->gs_ofmt, &largs);
3288                 if (status != DLADM_STATUS_OK)
3289                         goto done;
3290         }
3291 
3292         status = DLADM_STATUS_OK;
3293 done:
3294         return (status);
3295 }
3296 
3297 static boolean_t
3298 print_aggr_stats_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
3299 {
3300         const laggr_args_t      *l = ofarg->ofmt_cbarg;
3301         int                     portnum;
3302         boolean_t               is_port = (l->laggr_lport >= 0);
3303         dladm_aggr_port_attr_t  *portp;
3304         dladm_status_t          *stat, status;
3305         pktsum_t                *diff_stats;
3306 
3307         stat = l->laggr_status;
3308         *stat = DLADM_STATUS_OK;
3309 
3310         if (is_port) {
3311                 portnum = l->laggr_lport;
3312                 portp = &(l->laggr_ginfop->lg_ports[portnum]);
3313 
3314                 if ((status = dladm_datalink_id2info(handle,
3315                     portp->lp_linkid, NULL, NULL, NULL, buf, bufsize)) !=
3316                     DLADM_STATUS_OK) {
3317                         goto err;
3318                 }
3319                 diff_stats = l->laggr_diffstats;
3320         }
3321 
3322         switch (ofarg->ofmt_id) {
3323         case AGGR_S_LINK:
3324                 (void) snprintf(buf, bufsize, "%s",
3325                     (is_port ? "" : l->laggr_link));
3326                 break;
3327         case AGGR_S_PORT:
3328                 /*
3329                  * if (is_port), buf has port name. Otherwise we print
3330                  * STR_UNDEF_VAL
3331                  */
3332                 break;
3333 
3334         case AGGR_S_IPKTS:
3335                 if (is_port) {
3336                         (void) snprintf(buf, bufsize, "%llu",
3337                             diff_stats->ipackets);
3338                 } else {
3339                         (void) snprintf(buf, bufsize, "%llu",
3340                             l->laggr_pktsumtot->ipackets);
3341                 }
3342                 break;
3343 
3344         case AGGR_S_RBYTES:
3345                 if (is_port) {
3346                         (void) snprintf(buf, bufsize, "%llu",
3347                             diff_stats->rbytes);
3348                 } else {
3349                         (void) snprintf(buf, bufsize, "%llu",
3350                             l->laggr_pktsumtot->rbytes);
3351                 }
3352                 break;
3353 
3354         case AGGR_S_OPKTS:
3355                 if (is_port) {
3356                         (void) snprintf(buf, bufsize, "%llu",
3357                             diff_stats->opackets);
3358                 } else {
3359                         (void) snprintf(buf, bufsize, "%llu",
3360                             l->laggr_pktsumtot->opackets);
3361                 }
3362                 break;
3363         case AGGR_S_OBYTES:
3364                 if (is_port) {
3365                         (void) snprintf(buf, bufsize, "%llu",
3366                             diff_stats->obytes);
3367                 } else {
3368                         (void) snprintf(buf, bufsize, "%llu",
3369                             l->laggr_pktsumtot->obytes);
3370                 }
3371                 break;
3372 
3373         case AGGR_S_IPKTDIST:
3374                 if (is_port) {
3375                         (void) snprintf(buf, bufsize, "%-6.1f",
3376                             (double)diff_stats->ipackets/
3377                             (double)l->laggr_pktsumtot->ipackets * 100);
3378                 }
3379                 break;
3380         case AGGR_S_OPKTDIST:
3381                 if (is_port) {
3382                         (void) snprintf(buf, bufsize, "%-6.1f",
3383                             (double)diff_stats->opackets/
3384                             (double)l->laggr_pktsumtot->opackets * 100);
3385                 }
3386                 break;
3387         }
3388         return (B_TRUE);
3389 
3390 err:
3391         *stat = status;
3392         return (B_TRUE);
3393 }
3394 
3395 static dladm_status_t
3396 print_aggr_stats(show_grp_state_t *state, const char *link,
3397     dladm_aggr_grp_attr_t *ginfop)
3398 {
3399         dladm_phys_attr_t       dpa;
3400         dladm_aggr_port_attr_t  *portp;
3401         pktsum_t                pktsumtot, *port_stat;
3402         dladm_status_t          status;
3403         int                     i;
3404         laggr_args_t            largs;
3405 
3406         /* sum the ports statistics */
3407         bzero(&pktsumtot, sizeof (pktsumtot));
3408 
3409         /* Allocate memory to keep stats of each port */
3410         port_stat = malloc(ginfop->lg_nports * sizeof (pktsum_t));
3411         if (port_stat == NULL) {
3412                 /* Bail out; no memory */
3413                 return (DLADM_STATUS_NOMEM);
3414         }
3415 
3416 
3417         for (i = 0; i < ginfop->lg_nports; i++) {
3418 
3419                 portp = &(ginfop->lg_ports[i]);
3420                 if ((status = dladm_phys_info(handle, portp->lp_linkid, &dpa,
3421                     DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) {
3422                         goto done;
3423                 }
3424 
3425                 get_mac_stats(dpa.dp_dev, &port_stat[i]);
3426 
3427                 /*
3428                  * Let's re-use gs_prevstats[] to store the difference of the
3429                  * counters since last use. We will store the new stats from
3430                  * port_stat[] once we have the stats displayed.
3431                  */
3432 
3433                 dladm_stats_diff(&state->gs_prevstats[i], &port_stat[i],
3434                     &state->gs_prevstats[i]);
3435                 dladm_stats_total(&pktsumtot, &pktsumtot,
3436                     &state->gs_prevstats[i]);
3437         }
3438 
3439         largs.laggr_lport = -1;
3440         largs.laggr_link = link;
3441         largs.laggr_ginfop = ginfop;
3442         largs.laggr_status = &status;
3443         largs.laggr_pktsumtot = &pktsumtot;
3444 
3445         ofmt_print(state->gs_ofmt, &largs);
3446 
3447         if (status != DLADM_STATUS_OK)
3448                 goto done;
3449 
3450         for (i = 0; i < ginfop->lg_nports; i++) {
3451                 largs.laggr_lport = i;
3452                 largs.laggr_diffstats = &state->gs_prevstats[i];
3453                 ofmt_print(state->gs_ofmt, &largs);
3454                 if (status != DLADM_STATUS_OK)
3455                         goto done;
3456         }
3457 
3458         status = DLADM_STATUS_OK;
3459         for (i = 0; i < ginfop->lg_nports; i++)
3460                 state->gs_prevstats[i] = port_stat[i];
3461 
3462 done:
3463         free(port_stat);
3464         return (status);
3465 }
3466 
3467 static dladm_status_t
3468 print_aggr(show_grp_state_t *state, datalink_id_t linkid)
3469 {
3470         char                    link[MAXLINKNAMELEN];
3471         dladm_aggr_grp_attr_t   ginfo;
3472         uint32_t                flags;
3473         dladm_status_t          status;
3474 
3475         bzero(&ginfo, sizeof (dladm_aggr_grp_attr_t));
3476         if ((status = dladm_datalink_id2info(handle, linkid, &flags, NULL,
3477             NULL, link, MAXLINKNAMELEN)) != DLADM_STATUS_OK) {
3478                 return (status);
3479         }
3480 
3481         if (!(state->gs_flags & flags))
3482                 return (DLADM_STATUS_NOTFOUND);
3483 
3484         status = dladm_aggr_info(handle, linkid, &ginfo, state->gs_flags);
3485         if (status != DLADM_STATUS_OK)
3486                 return (status);
3487 
3488         if (state->gs_lacp)
3489                 status = print_aggr_lacp(state, link, &ginfo);
3490         else if (state->gs_extended)
3491                 status = print_aggr_extended(state, link, &ginfo);
3492         else if (state->gs_stats)
3493                 status = print_aggr_stats(state, link, &ginfo);
3494         else
3495                 status = print_aggr_info(state, link, &ginfo);
3496 
3497 done:
3498         free(ginfo.lg_ports);
3499         return (status);
3500 }
3501 
3502 /* ARGSUSED */
3503 static int
3504 show_aggr(dladm_handle_t dh, datalink_id_t linkid, void *arg)
3505 {
3506         show_grp_state_t        *state = arg;
3507 
3508         state->gs_status = print_aggr(state, linkid);
3509         return (DLADM_WALK_CONTINUE);
3510 }
3511 
3512 static void
3513 do_show_link(int argc, char *argv[], const char *use)
3514 {
3515         int             option;
3516         boolean_t       s_arg = B_FALSE;
3517         boolean_t       i_arg = B_FALSE;
3518         uint32_t        flags = DLADM_OPT_ACTIVE;
3519         boolean_t       p_arg = B_FALSE;
3520         datalink_id_t   linkid = DATALINK_ALL_LINKID;
3521         char            linkname[MAXLINKNAMELEN];
3522         uint32_t        interval = 0;
3523         show_state_t    state;
3524         dladm_status_t  status;
3525         boolean_t       o_arg = B_FALSE;
3526         char            *fields_str = NULL;
3527         char            *all_active_fields = "link,class,mtu,state,bridge,over";
3528         char            *all_inactive_fields = "link,class,bridge,over";
3529         char            *allstat_fields =
3530             "link,ipackets,rbytes,ierrors,opackets,obytes,oerrors";
3531         ofmt_handle_t   ofmt;
3532         ofmt_status_t   oferr;
3533         uint_t          ofmtflags = 0;
3534 
3535         bzero(&state, sizeof (state));
3536 
3537         opterr = 0;
3538         while ((option = getopt_long(argc, argv, ":pPsi:o:",
3539             show_lopts, NULL)) != -1) {
3540                 switch (option) {
3541                 case 'p':
3542                         if (p_arg)
3543                                 die_optdup(option);
3544 
3545                         p_arg = B_TRUE;
3546                         break;
3547                 case 's':
3548                         if (s_arg)
3549                                 die_optdup(option);
3550 
3551                         s_arg = B_TRUE;
3552                         break;
3553                 case 'P':
3554                         if (flags != DLADM_OPT_ACTIVE)
3555                                 die_optdup(option);
3556 
3557                         flags = DLADM_OPT_PERSIST;
3558                         break;
3559                 case 'o':
3560                         o_arg = B_TRUE;
3561                         fields_str = optarg;
3562                         break;
3563                 case 'i':
3564                         if (i_arg)
3565                                 die_optdup(option);
3566 
3567                         i_arg = B_TRUE;
3568                         if (!dladm_str2interval(optarg, &interval))
3569                                 die("invalid interval value '%s'", optarg);
3570                         break;
3571                 default:
3572                         die_opterr(optopt, option, use);
3573                         break;
3574                 }
3575         }
3576 
3577         if (i_arg && !s_arg)
3578                 die("the option -i can be used only with -s");
3579 
3580         if (s_arg && flags != DLADM_OPT_ACTIVE)
3581                 die("the option -P cannot be used with -s");
3582 
3583         /* get link name (optional last argument) */
3584         if (optind == (argc-1)) {
3585                 uint32_t        f;
3586 
3587                 if (strlcpy(linkname, argv[optind], MAXLINKNAMELEN) >=
3588                     MAXLINKNAMELEN)
3589                         die("link name too long");
3590                 if ((status = dladm_name2info(handle, linkname, &linkid, &f,
3591                     NULL, NULL)) != DLADM_STATUS_OK) {
3592                         die_dlerr(status, "link %s is not valid", linkname);
3593                 }
3594 
3595                 if (!(f & flags)) {
3596                         die_dlerr(DLADM_STATUS_BADARG, "link %s is %s",
3597                             argv[optind], flags == DLADM_OPT_PERSIST ?
3598                             "a temporary link" : "temporarily removed");
3599                 }
3600         } else if (optind != argc) {
3601                 usage();
3602         }
3603 
3604         if (p_arg && !o_arg)
3605                 die("-p requires -o");
3606 
3607         if (p_arg && strcasecmp(fields_str, "all") == 0)
3608                 die("\"-o all\" is invalid with -p");
3609 
3610         if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) {
3611                 if (s_arg)
3612                         fields_str = allstat_fields;
3613                 else if (flags & DLADM_OPT_ACTIVE)
3614                         fields_str = all_active_fields;
3615                 else
3616                         fields_str = all_inactive_fields;
3617         }
3618 
3619         state.ls_parsable = p_arg;
3620         state.ls_flags = flags;
3621         state.ls_donefirst = B_FALSE;
3622 
3623         if (s_arg) {
3624                 link_stats(linkid, interval, fields_str, &state);
3625                 return;
3626         }
3627         if (state.ls_parsable)
3628                 ofmtflags |= OFMT_PARSABLE;
3629         else
3630                 ofmtflags |= OFMT_WRAP;
3631 
3632         oferr = ofmt_open(fields_str, link_fields, ofmtflags, 0, &ofmt);
3633         ofmt_check(oferr, state.ls_parsable, ofmt, die, warn);
3634         state.ls_ofmt = ofmt;
3635 
3636         if (linkid == DATALINK_ALL_LINKID) {
3637                 (void) dladm_walk_datalink_id(show_link, handle, &state,
3638                     DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE, flags);
3639         } else {
3640                 (void) show_link(handle, linkid, &state);
3641                 if (state.ls_status != DLADM_STATUS_OK) {
3642                         die_dlerr(state.ls_status, "failed to show link %s",
3643                             argv[optind]);
3644                 }
3645         }
3646         ofmt_close(ofmt);
3647 }
3648 
3649 static void
3650 do_show_aggr(int argc, char *argv[], const char *use)
3651 {
3652         boolean_t               L_arg = B_FALSE;
3653         boolean_t               s_arg = B_FALSE;
3654         boolean_t               i_arg = B_FALSE;
3655         boolean_t               p_arg = B_FALSE;
3656         boolean_t               x_arg = B_FALSE;
3657         show_grp_state_t        state;
3658         uint32_t                flags = DLADM_OPT_ACTIVE;
3659         datalink_id_t           linkid = DATALINK_ALL_LINKID;
3660         int                     option;
3661         uint32_t                interval = 0;
3662         int                     key;
3663         dladm_status_t          status;
3664         boolean_t               o_arg = B_FALSE;
3665         char                    *fields_str = NULL;
3666         char                    *all_fields =
3667             "link,policy,addrpolicy,lacpactivity,lacptimer,flags";
3668         char                    *all_lacp_fields =
3669             "link,port,aggregatable,sync,coll,dist,defaulted,expired";
3670         char                    *all_stats_fields =
3671             "link,port,ipackets,rbytes,opackets,obytes,ipktdist,opktdist";
3672         char                    *all_extended_fields =
3673             "link,port,speed,duplex,state,address,portstate";
3674         const ofmt_field_t      *pf;
3675         ofmt_handle_t           ofmt;
3676         ofmt_status_t           oferr;
3677         uint_t                  ofmtflags = 0;
3678 
3679         opterr = 0;
3680         while ((option = getopt_long(argc, argv, ":LpPxsi:o:",
3681             show_lopts, NULL)) != -1) {
3682                 switch (option) {
3683                 case 'L':
3684                         if (L_arg)
3685                                 die_optdup(option);
3686 
3687                         L_arg = B_TRUE;
3688                         break;
3689                 case 'p':
3690                         if (p_arg)
3691                                 die_optdup(option);
3692 
3693                         p_arg = B_TRUE;
3694                         break;
3695                 case 'x':
3696                         if (x_arg)
3697                                 die_optdup(option);
3698 
3699                         x_arg = B_TRUE;
3700                         break;
3701                 case 'P':
3702                         if (flags != DLADM_OPT_ACTIVE)
3703                                 die_optdup(option);
3704 
3705                         flags = DLADM_OPT_PERSIST;
3706                         break;
3707                 case 's':
3708                         if (s_arg)
3709                                 die_optdup(option);
3710 
3711                         s_arg = B_TRUE;
3712                         break;
3713                 case 'o':
3714                         o_arg = B_TRUE;
3715                         fields_str = optarg;
3716                         break;
3717                 case 'i':
3718                         if (i_arg)
3719                                 die_optdup(option);
3720 
3721                         i_arg = B_TRUE;
3722                         if (!dladm_str2interval(optarg, &interval))
3723                                 die("invalid interval value '%s'", optarg);
3724                         break;
3725                 default:
3726                         die_opterr(optopt, option, use);
3727                         break;
3728                 }
3729         }
3730 
3731         if (p_arg && !o_arg)
3732                 die("-p requires -o");
3733 
3734         if (p_arg && strcasecmp(fields_str, "all") == 0)
3735                 die("\"-o all\" is invalid with -p");
3736 
3737         if (i_arg && !s_arg)
3738                 die("the option -i can be used only with -s");
3739 
3740         if (s_arg && (L_arg || p_arg || x_arg || flags != DLADM_OPT_ACTIVE)) {
3741                 die("the option -%c cannot be used with -s",
3742                     L_arg ? 'L' : (p_arg ? 'p' : (x_arg ? 'x' : 'P')));
3743         }
3744 
3745         if (L_arg && flags != DLADM_OPT_ACTIVE)
3746                 die("the option -P cannot be used with -L");
3747 
3748         if (x_arg && (L_arg || flags != DLADM_OPT_ACTIVE))
3749                 die("the option -%c cannot be used with -x", L_arg ? 'L' : 'P');
3750 
3751         /* get aggregation key or aggrname (optional last argument) */
3752         if (optind == (argc-1)) {
3753                 if (!str2int(argv[optind], &key)) {
3754                         status = dladm_name2info(handle, argv[optind],
3755                             &linkid, NULL, NULL, NULL);
3756                 } else {
3757                         status = dladm_key2linkid(handle, (uint16_t)key,
3758                             &linkid, DLADM_OPT_ACTIVE);
3759                 }
3760 
3761                 if (status != DLADM_STATUS_OK)
3762                         die("non-existent aggregation '%s'", argv[optind]);
3763 
3764         } else if (optind != argc) {
3765                 usage();
3766         }
3767 
3768         bzero(&state, sizeof (state));
3769         state.gs_lacp = L_arg;
3770         state.gs_stats = s_arg;
3771         state.gs_flags = flags;
3772         state.gs_parsable = p_arg;
3773         state.gs_extended = x_arg;
3774 
3775         if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) {
3776                 if (state.gs_lacp)
3777                         fields_str = all_lacp_fields;
3778                 else if (state.gs_stats)
3779                         fields_str = all_stats_fields;
3780                 else if (state.gs_extended)
3781                         fields_str = all_extended_fields;
3782                 else
3783                         fields_str = all_fields;
3784         }
3785 
3786         if (state.gs_lacp) {
3787                 pf = aggr_l_fields;
3788         } else if (state.gs_stats) {
3789                 pf = aggr_s_fields;
3790         } else if (state.gs_extended) {
3791                 pf = aggr_x_fields;
3792         } else {
3793                 pf = laggr_fields;
3794         }
3795 
3796         if (state.gs_parsable)
3797                 ofmtflags |= OFMT_PARSABLE;
3798         oferr = ofmt_open(fields_str, pf, ofmtflags, 0, &ofmt);
3799         ofmt_check(oferr, state.gs_parsable, ofmt, die, warn);
3800         state.gs_ofmt = ofmt;
3801 
3802         if (s_arg) {
3803                 aggr_stats(linkid, &state, interval);
3804                 ofmt_close(ofmt);
3805                 return;
3806         }
3807 
3808         if (linkid == DATALINK_ALL_LINKID) {
3809                 (void) dladm_walk_datalink_id(show_aggr, handle, &state,
3810                     DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE, flags);
3811         } else {
3812                 (void) show_aggr(handle, linkid, &state);
3813                 if (state.gs_status != DLADM_STATUS_OK) {
3814                         die_dlerr(state.gs_status, "failed to show aggr %s",
3815                             argv[optind]);
3816                 }
3817         }
3818         ofmt_close(ofmt);
3819 }
3820 
3821 static dladm_status_t
3822 print_phys_default(show_state_t *state, datalink_id_t linkid,
3823     const char *link, uint32_t flags, uint32_t media)
3824 {
3825         dladm_phys_attr_t dpa;
3826         dladm_status_t status;
3827         link_fields_buf_t pattr;
3828 
3829         status = dladm_phys_info(handle, linkid, &dpa, state->ls_flags);
3830         if (status != DLADM_STATUS_OK)
3831                 goto done;
3832 
3833         bzero(&pattr, sizeof (pattr));
3834         (void) snprintf(pattr.link_phys_device,
3835             sizeof (pattr.link_phys_device), "%s", dpa.dp_dev);
3836         (void) dladm_media2str(media, pattr.link_phys_media);
3837         if (state->ls_flags == DLADM_OPT_ACTIVE) {
3838                 boolean_t       islink;
3839 
3840                 if (!dpa.dp_novanity) {
3841                         (void) strlcpy(pattr.link_name, link,
3842                             sizeof (pattr.link_name));
3843                         islink = B_TRUE;
3844                 } else {
3845                         /*
3846                          * This is a physical link that does not have
3847                          * vanity naming support.
3848                          */
3849                         (void) strlcpy(pattr.link_name, dpa.dp_dev,
3850                             sizeof (pattr.link_name));
3851                         islink = B_FALSE;
3852                 }
3853 
3854                 (void) get_linkstate(pattr.link_name, islink,
3855                     pattr.link_phys_state);
3856                 (void) snprintf(pattr.link_phys_speed,
3857                     sizeof (pattr.link_phys_speed), "%u",
3858                     (uint_t)((get_ifspeed(pattr.link_name,
3859                     islink)) / 1000000ull));
3860                 (void) get_linkduplex(pattr.link_name, islink,
3861                     pattr.link_phys_duplex);
3862         } else {
3863                 (void) snprintf(pattr.link_name, sizeof (pattr.link_name),
3864                     "%s", link);
3865                 (void) snprintf(pattr.link_flags, sizeof (pattr.link_flags),
3866                     "%c----", flags & DLADM_OPT_ACTIVE ? '-' : 'r');
3867         }
3868 
3869         ofmt_print(state->ls_ofmt, &pattr);
3870 
3871 done:
3872         return (status);
3873 }
3874 
3875 typedef struct {
3876         show_state_t    *ms_state;
3877         char            *ms_link;
3878         dladm_macaddr_attr_t *ms_mac_attr;
3879 } print_phys_mac_state_t;
3880 
3881 /*
3882  *  callback for ofmt_print()
3883  */
3884 static boolean_t
3885 print_phys_one_mac_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
3886 {
3887         print_phys_mac_state_t *mac_state = ofarg->ofmt_cbarg;
3888         dladm_macaddr_attr_t *attr = mac_state->ms_mac_attr;
3889         boolean_t is_primary = (attr->ma_slot == 0);
3890         boolean_t is_parsable = mac_state->ms_state->ls_parsable;
3891 
3892         switch (ofarg->ofmt_id) {
3893         case PHYS_M_LINK:
3894                 (void) snprintf(buf, bufsize, "%s",
3895                     (is_primary || is_parsable) ? mac_state->ms_link : " ");
3896                 break;
3897         case PHYS_M_SLOT:
3898                 if (is_primary)
3899                         (void) snprintf(buf, bufsize, gettext("primary"));
3900                 else
3901                         (void) snprintf(buf, bufsize, "%d", attr->ma_slot);
3902                 break;
3903         case PHYS_M_ADDRESS:
3904                 (void) dladm_aggr_macaddr2str(attr->ma_addr, buf);
3905                 break;
3906         case PHYS_M_INUSE:
3907                 (void) snprintf(buf, bufsize, "%s",
3908                     attr->ma_flags & DLADM_MACADDR_USED ? gettext("yes") :
3909                     gettext("no"));
3910                 break;
3911         case PHYS_M_CLIENT:
3912                 /*
3913                  * CR 6678526: resolve link id to actual link name if
3914                  * it is valid.
3915                  */
3916                 (void) snprintf(buf, bufsize, "%s", attr->ma_client_name);
3917                 break;
3918         }
3919 
3920         return (B_TRUE);
3921 }
3922 
3923 typedef struct {
3924         show_state_t    *hs_state;
3925         char            *hs_link;
3926         dladm_hwgrp_attr_t *hs_grp_attr;
3927 } print_phys_hwgrp_state_t;
3928 
3929 static boolean_t
3930 print_phys_one_hwgrp_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
3931 {
3932         int             i;
3933         boolean_t       first = B_TRUE;
3934         int             start = -1;
3935         int             end = -1;
3936         char            ringstr[RINGSTRLEN];
3937         char            ringsubstr[RINGSTRLEN];
3938 
3939         print_phys_hwgrp_state_t *hg_state = ofarg->ofmt_cbarg;
3940         dladm_hwgrp_attr_t *attr = hg_state->hs_grp_attr;
3941 
3942         switch (ofarg->ofmt_id) {
3943         case PHYS_H_LINK:
3944                 (void) snprintf(buf, bufsize, "%s", attr->hg_link_name);
3945                 break;
3946         case PHYS_H_RINGTYPE:
3947                 (void) snprintf(buf, bufsize, "%s",
3948                     attr->hg_grp_type == DLADM_HWGRP_TYPE_RX ? "RX" : "TX");
3949                 break;
3950         case PHYS_H_RINGS:
3951                 ringstr[0] = '\0';
3952                 for (i = 0; i < attr->hg_n_rings; i++) {
3953                         uint_t  index = attr->hg_rings[i];
3954 
3955                         if (start == -1) {
3956                                 start = index;
3957                                 end = index;
3958                         } else if (index == end + 1) {
3959                                 end = index;
3960                         } else {
3961                                 if (start == end) {
3962                                         if (first) {
3963                                                 (void) snprintf(
3964                                                     ringsubstr,
3965                                                     RINGSTRLEN, "%d",
3966                                                     start);
3967                                                 first = B_FALSE;
3968                                         } else {
3969                                                 (void) snprintf(
3970                                                     ringsubstr,
3971                                                     RINGSTRLEN, ",%d",
3972                                                     start);
3973                                         }
3974                                 } else {
3975                                         if (first) {
3976                                                 (void) snprintf(
3977                                                     ringsubstr,
3978                                                     RINGSTRLEN,
3979                                                     "%d-%d",
3980                                                     start, end);
3981                                                 first = B_FALSE;
3982                                         } else {
3983                                                 (void) snprintf(
3984                                                     ringsubstr,
3985                                                     RINGSTRLEN,
3986                                                     ",%d-%d",
3987                                                     start, end);
3988                                         }
3989                                 }
3990                                 (void) strlcat(ringstr, ringsubstr,
3991                                     RINGSTRLEN);
3992                                 start = index;
3993                                 end = index;
3994                         }
3995                 }
3996                 /* The last one */
3997                 if (start != -1) {
3998                         if (first) {
3999                                 if (start == end) {
4000                                         (void) snprintf(buf, bufsize, "%d",
4001                                             start);
4002                                 } else {
4003                                         (void) snprintf(buf, bufsize, "%d-%d",
4004                                             start, end);
4005                                 }
4006                         } else {
4007                                 if (start == end) {
4008                                         (void) snprintf(ringsubstr, RINGSTRLEN,
4009                                             ",%d", start);
4010                                 } else {
4011                                         (void) snprintf(ringsubstr, RINGSTRLEN,
4012                                             ",%d-%d", start, end);
4013                                 }
4014                                 (void) strlcat(ringstr, ringsubstr, RINGSTRLEN);
4015                                 (void) snprintf(buf, bufsize, "%s", ringstr);
4016                         }
4017                 }
4018                 break;
4019         case PHYS_H_CLIENTS:
4020                 if (attr->hg_client_names[0] == '\0') {
4021                         (void) snprintf(buf, bufsize, "--");
4022                 } else {
4023                         (void) snprintf(buf, bufsize, "%s ",
4024                             attr->hg_client_names);
4025                 }
4026                 break;
4027         }
4028 
4029         return (B_TRUE);
4030 }
4031 
4032 /*
4033  * callback for dladm_walk_macaddr, invoked for each MAC address slot
4034  */
4035 static boolean_t
4036 print_phys_mac_callback(void *arg, dladm_macaddr_attr_t *attr)
4037 {
4038         print_phys_mac_state_t *mac_state = arg;
4039         show_state_t *state = mac_state->ms_state;
4040 
4041         mac_state->ms_mac_attr = attr;
4042         ofmt_print(state->ls_ofmt, mac_state);
4043 
4044         return (B_TRUE);
4045 }
4046 
4047 /*
4048  * invoked by show-phys -m for each physical data-link
4049  */
4050 static dladm_status_t
4051 print_phys_mac(show_state_t *state, datalink_id_t linkid, char *link)
4052 {
4053         print_phys_mac_state_t mac_state;
4054 
4055         mac_state.ms_state = state;
4056         mac_state.ms_link = link;
4057 
4058         return (dladm_walk_macaddr(handle, linkid, &mac_state,
4059             print_phys_mac_callback));
4060 }
4061 
4062 /*
4063  * callback for dladm_walk_hwgrp, invoked for each MAC hwgrp
4064  */
4065 static boolean_t
4066 print_phys_hwgrp_callback(void *arg, dladm_hwgrp_attr_t *attr)
4067 {
4068         print_phys_hwgrp_state_t *hwgrp_state = arg;
4069         show_state_t *state = hwgrp_state->hs_state;
4070 
4071         hwgrp_state->hs_grp_attr = attr;
4072         ofmt_print(state->ls_ofmt, hwgrp_state);
4073 
4074         return (B_TRUE);
4075 }
4076 
4077 /* invoked by show-phys -H for each physical data-link */
4078 static dladm_status_t
4079 print_phys_hwgrp(show_state_t *state, datalink_id_t linkid, char *link)
4080 {
4081         print_phys_hwgrp_state_t hwgrp_state;
4082 
4083         hwgrp_state.hs_state = state;
4084         hwgrp_state.hs_link = link;
4085         return (dladm_walk_hwgrp(handle, linkid, &hwgrp_state,
4086             print_phys_hwgrp_callback));
4087 }
4088 
4089 /*
4090  * Parse the "local=<laddr>,remote=<raddr>" sub-options for the -a option of
4091  * *-iptun subcommands.
4092  */
4093 static void
4094 iptun_process_addrarg(char *addrarg, iptun_params_t *params)
4095 {
4096         char *addrval;
4097 
4098         while (*addrarg != '\0') {
4099                 switch (getsubopt(&addrarg, iptun_addropts, &addrval)) {
4100                 case IPTUN_LOCAL:
4101                         if (addrval == NULL)
4102                                 die("tunnel source address value is missing");
4103                         params->iptun_param_flags |= IPTUN_PARAM_LADDR;
4104                         if (strlcpy(params->iptun_param_laddr, addrval,
4105                             sizeof (params->iptun_param_laddr)) >=
4106                             sizeof (params->iptun_param_laddr))
4107                                 die("tunnel source address is too long");
4108                         break;
4109                 case IPTUN_REMOTE:
4110                         if (addrval == NULL)
4111                                 die("tunnel destination address value "
4112                                     "is missing");
4113                         params->iptun_param_flags |= IPTUN_PARAM_RADDR;
4114                         if (strlcpy(params->iptun_param_raddr, addrval,
4115                             sizeof (params->iptun_param_raddr)) >=
4116                             sizeof (params->iptun_param_raddr))
4117                                 die("tunnel destination address is too long");
4118                         break;
4119                 default:
4120                         die("invalid address type: %s", addrval);
4121                         break;
4122                 }
4123         }
4124 }
4125 
4126 /*
4127  * Convenience routine to process iptun-create/modify/delete subcommand
4128  * arguments.
4129  */
4130 static void
4131 iptun_process_args(int argc, char *argv[], const char *opts,
4132     iptun_params_t *params, uint32_t *flags, char *name, const char *use)
4133 {
4134         int     option;
4135         char    *altroot = NULL;
4136 
4137         if (params != NULL)
4138                 bzero(params, sizeof (*params));
4139         *flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
4140 
4141         opterr = 0;
4142         while ((option = getopt_long(argc, argv, opts, iptun_lopts, NULL)) !=
4143             -1) {
4144                 switch (option) {
4145                 case 'a':
4146                         iptun_process_addrarg(optarg, params);
4147                         break;
4148                 case 'R':
4149                         altroot = optarg;
4150                         break;
4151                 case 't':
4152                         *flags &= ~DLADM_OPT_PERSIST;
4153                         break;
4154                 case 'T':
4155                         params->iptun_param_type = iptun_gettypebyname(optarg);
4156                         if (params->iptun_param_type == IPTUN_TYPE_UNKNOWN)
4157                                 die("unknown tunnel type: %s", optarg);
4158                         params->iptun_param_flags |= IPTUN_PARAM_TYPE;
4159                         break;
4160                 default:
4161                         die_opterr(optopt, option, use);
4162                         break;
4163                 }
4164         }
4165 
4166         /* Get the required tunnel name argument. */
4167         if (argc - optind != 1)
4168                 usage();
4169 
4170         if (strlcpy(name, argv[optind], MAXLINKNAMELEN) >= MAXLINKNAMELEN)
4171                 die("tunnel name is too long");
4172 
4173         if (altroot != NULL)
4174                 altroot_cmd(altroot, argc, argv);
4175 }
4176 
4177 static void
4178 do_create_iptun(int argc, char *argv[], const char *use)
4179 {
4180         iptun_params_t  params;
4181         dladm_status_t  status;
4182         uint32_t        flags;
4183         char            name[MAXLINKNAMELEN];
4184 
4185         iptun_process_args(argc, argv, ":a:R:tT:", &params, &flags, name,
4186             use);
4187 
4188         status = dladm_iptun_create(handle, name, &params, flags);
4189         if (status != DLADM_STATUS_OK)
4190                 die_dlerr(status, "could not create tunnel");
4191 }
4192 
4193 static void
4194 do_delete_iptun(int argc, char *argv[], const char *use)
4195 {
4196         uint32_t        flags;
4197         datalink_id_t   linkid;
4198         dladm_status_t  status;
4199         char            name[MAXLINKNAMELEN];
4200 
4201         iptun_process_args(argc, argv, ":R:t", NULL, &flags, name, use);
4202 
4203         status = dladm_name2info(handle, name, &linkid, NULL, NULL, NULL);
4204         if (status != DLADM_STATUS_OK)
4205                 die_dlerr(status, "could not delete tunnel");
4206         status = dladm_iptun_delete(handle, linkid, flags);
4207         if (status != DLADM_STATUS_OK)
4208                 die_dlerr(status, "could not delete tunnel");
4209 }
4210 
4211 static void
4212 do_modify_iptun(int argc, char *argv[], const char *use)
4213 {
4214         iptun_params_t  params;
4215         uint32_t        flags;
4216         dladm_status_t  status;
4217         char            name[MAXLINKNAMELEN];
4218 
4219         iptun_process_args(argc, argv, ":a:R:t", &params, &flags, name, use);
4220 
4221         if ((status = dladm_name2info(handle, name, &params.iptun_param_linkid,
4222             NULL, NULL, NULL)) != DLADM_STATUS_OK)
4223                 die_dlerr(status, "could not modify tunnel");
4224         status = dladm_iptun_modify(handle, &params, flags);
4225         if (status != DLADM_STATUS_OK)
4226                 die_dlerr(status, "could not modify tunnel");
4227 }
4228 
4229 static void
4230 do_show_iptun(int argc, char *argv[], const char *use)
4231 {
4232         char            option;
4233         datalink_id_t   linkid;
4234         uint32_t        flags = DLADM_OPT_ACTIVE;
4235         char            *name = NULL;
4236         dladm_status_t  status;
4237         const char      *fields_str = NULL;
4238         show_state_t    state;
4239         ofmt_handle_t   ofmt;
4240         ofmt_status_t   oferr;
4241         uint_t          ofmtflags = 0;
4242 
4243         bzero(&state, sizeof (state));
4244         opterr = 0;
4245         while ((option = getopt_long(argc, argv, ":pPo:",
4246             iptun_lopts, NULL)) != -1) {
4247                 switch (option) {
4248                 case 'o':
4249                         fields_str = optarg;
4250                         break;
4251                 case 'p':
4252                         state.ls_parsable = B_TRUE;
4253                         ofmtflags = OFMT_PARSABLE;
4254                         break;
4255                 case 'P':
4256                         flags = DLADM_OPT_PERSIST;
4257                         break;
4258                 default:
4259                         die_opterr(optopt, option, use);
4260                         break;
4261                 }
4262         }
4263 
4264         /*
4265          * Get the optional tunnel name argument.  If there is one, it must
4266          * be the last thing remaining on the command-line.
4267          */
4268         if (argc - optind > 1)
4269                 die(gettext(use));
4270         if (argc - optind == 1)
4271                 name = argv[optind];
4272 
4273         oferr = ofmt_open(fields_str, iptun_fields, ofmtflags,
4274             DLADM_DEFAULT_COL, &ofmt);
4275         ofmt_check(oferr, state.ls_parsable, ofmt, die, warn);
4276 
4277         state.ls_ofmt = ofmt;
4278         state.ls_flags = flags;
4279 
4280         if (name == NULL) {
4281                 (void) dladm_walk_datalink_id(print_iptun_walker, handle,
4282                     &state, DATALINK_CLASS_IPTUN, DATALINK_ANY_MEDIATYPE,
4283                     flags);
4284                 status = state.ls_status;
4285         } else {
4286                 if ((status = dladm_name2info(handle, name, &linkid, NULL, NULL,
4287                     NULL)) == DLADM_STATUS_OK)
4288                         status = print_iptun(handle, linkid, &state);
4289         }
4290 
4291         if (status != DLADM_STATUS_OK)
4292                 die_dlerr(status, "unable to obtain tunnel status");
4293 }
4294 
4295 /* ARGSUSED */
4296 static void
4297 do_up_iptun(int argc, char *argv[], const char *use)
4298 {
4299         datalink_id_t   linkid = DATALINK_ALL_LINKID;
4300         dladm_status_t  status = DLADM_STATUS_OK;
4301 
4302         /*
4303          * Get the optional tunnel name argument.  If there is one, it must
4304          * be the last thing remaining on the command-line.
4305          */
4306         if (argc - optind > 1)
4307                 usage();
4308         if (argc - optind == 1) {
4309                 status = dladm_name2info(handle, argv[optind], &linkid, NULL,
4310                     NULL, NULL);
4311         }
4312         if (status == DLADM_STATUS_OK)
4313                 status = dladm_iptun_up(handle, linkid);
4314         if (status != DLADM_STATUS_OK)
4315                 die_dlerr(status, "unable to configure IP tunnel links");
4316 }
4317 
4318 /* ARGSUSED */
4319 static void
4320 do_down_iptun(int argc, char *argv[], const char *use)
4321 {
4322         datalink_id_t   linkid = DATALINK_ALL_LINKID;
4323         dladm_status_t  status = DLADM_STATUS_OK;
4324 
4325         /*
4326          * Get the optional tunnel name argument.  If there is one, it must
4327          * be the last thing remaining on the command-line.
4328          */
4329         if (argc - optind > 1)
4330                 usage();
4331         if (argc - optind == 1) {
4332                 status = dladm_name2info(handle, argv[optind], &linkid, NULL,
4333                     NULL, NULL);
4334         }
4335         if (status == DLADM_STATUS_OK)
4336                 status = dladm_iptun_down(handle, linkid);
4337         if (status != DLADM_STATUS_OK)
4338                 die_dlerr(status, "unable to bring down IP tunnel links");
4339 }
4340 
4341 static iptun_type_t
4342 iptun_gettypebyname(char *typestr)
4343 {
4344         int i;
4345 
4346         for (i = 0; iptun_types[i].type_name != NULL; i++) {
4347                 if (strncmp(iptun_types[i].type_name, typestr,
4348                     strlen(iptun_types[i].type_name)) == 0) {
4349                         return (iptun_types[i].type_value);
4350                 }
4351         }
4352         return (IPTUN_TYPE_UNKNOWN);
4353 }
4354 
4355 static const char *
4356 iptun_gettypebyvalue(iptun_type_t type)
4357 {
4358         int i;
4359 
4360         for (i = 0; iptun_types[i].type_name != NULL; i++) {
4361                 if (iptun_types[i].type_value == type)
4362                         return (iptun_types[i].type_name);
4363         }
4364         return (NULL);
4365 }
4366 
4367 static dladm_status_t
4368 print_iptun(dladm_handle_t dh, datalink_id_t linkid, show_state_t *state)
4369 {
4370         dladm_status_t          status;
4371         iptun_params_t          params;
4372         iptun_fields_buf_t      lbuf;
4373         const char              *laddr;
4374         const char              *raddr;
4375 
4376         params.iptun_param_linkid = linkid;
4377         status = dladm_iptun_getparams(dh, &params, state->ls_flags);
4378         if (status != DLADM_STATUS_OK)
4379                 return (status);
4380 
4381         /* LINK */
4382         status = dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL,
4383             lbuf.iptun_name, sizeof (lbuf.iptun_name));
4384         if (status != DLADM_STATUS_OK)
4385                 return (status);
4386 
4387         /* TYPE */
4388         (void) strlcpy(lbuf.iptun_type,
4389             iptun_gettypebyvalue(params.iptun_param_type),
4390             sizeof (lbuf.iptun_type));
4391 
4392         /* FLAGS */
4393         (void) memset(lbuf.iptun_flags, '-', IPTUN_NUM_FLAGS);
4394         lbuf.iptun_flags[IPTUN_NUM_FLAGS] = '\0';
4395         if (params.iptun_param_flags & IPTUN_PARAM_IPSECPOL)
4396                 lbuf.iptun_flags[IPTUN_SFLAG_INDEX] = 's';
4397         if (params.iptun_param_flags & IPTUN_PARAM_IMPLICIT)
4398                 lbuf.iptun_flags[IPTUN_IFLAG_INDEX] = 'i';
4399 
4400         /* LOCAL */
4401         if (params.iptun_param_flags & IPTUN_PARAM_LADDR)
4402                 laddr = params.iptun_param_laddr;
4403         else
4404                 laddr = (state->ls_parsable) ? "" : "--";
4405         (void) strlcpy(lbuf.iptun_laddr, laddr, sizeof (lbuf.iptun_laddr));
4406 
4407         /* REMOTE */
4408         if (params.iptun_param_flags & IPTUN_PARAM_RADDR)
4409                 raddr = params.iptun_param_raddr;
4410         else
4411                 raddr = (state->ls_parsable) ? "" : "--";
4412         (void) strlcpy(lbuf.iptun_raddr, raddr, sizeof (lbuf.iptun_raddr));
4413 
4414         ofmt_print(state->ls_ofmt, &lbuf);
4415 
4416         return (DLADM_STATUS_OK);
4417 }
4418 
4419 static int
4420 print_iptun_walker(dladm_handle_t dh, datalink_id_t linkid, void *arg)
4421 {
4422         ((show_state_t *)arg)->ls_status = print_iptun(dh, linkid, arg);
4423         return (DLADM_WALK_CONTINUE);
4424 }
4425 
4426 static dladm_status_t
4427 print_phys(show_state_t *state, datalink_id_t linkid)
4428 {
4429         char                    link[MAXLINKNAMELEN];
4430         uint32_t                flags;
4431         dladm_status_t          status;
4432         datalink_class_t        class;
4433         uint32_t                media;
4434 
4435         if ((status = dladm_datalink_id2info(handle, linkid, &flags, &class,
4436             &media, link, MAXLINKNAMELEN)) != DLADM_STATUS_OK) {
4437                 goto done;
4438         }
4439 
4440         if (class != DATALINK_CLASS_PHYS) {
4441                 status = DLADM_STATUS_BADARG;
4442                 goto done;
4443         }
4444 
4445         if (!(state->ls_flags & flags)) {
4446                 status = DLADM_STATUS_NOTFOUND;
4447                 goto done;
4448         }
4449 
4450         if (state->ls_mac)
4451                 status = print_phys_mac(state, linkid, link);
4452         else if (state->ls_hwgrp)
4453                 status = print_phys_hwgrp(state, linkid, link);
4454         else
4455                 status = print_phys_default(state, linkid, link, flags, media);
4456 
4457 done:
4458         return (status);
4459 }
4460 
4461 /* ARGSUSED */
4462 static int
4463 show_phys(dladm_handle_t dh, datalink_id_t linkid, void *arg)
4464 {
4465         show_state_t    *state = arg;
4466 
4467         state->ls_status = print_phys(state, linkid);
4468         return (DLADM_WALK_CONTINUE);
4469 }
4470 
4471 /*
4472  * Print the active topology information.
4473  */
4474 static dladm_status_t
4475 print_vlan(show_state_t *state, datalink_id_t linkid, link_fields_buf_t *l)
4476 {
4477         dladm_vlan_attr_t       vinfo;
4478         uint32_t                flags;
4479         dladm_status_t          status;
4480 
4481         if ((status = dladm_datalink_id2info(handle, linkid, &flags, NULL, NULL,
4482             l->link_name, sizeof (l->link_name))) != DLADM_STATUS_OK) {
4483                 goto done;
4484         }
4485 
4486         if (!(state->ls_flags & flags)) {
4487                 status = DLADM_STATUS_NOTFOUND;
4488                 goto done;
4489         }
4490 
4491         if ((status = dladm_vlan_info(handle, linkid, &vinfo,
4492             state->ls_flags)) != DLADM_STATUS_OK ||
4493             (status = dladm_datalink_id2info(handle, vinfo.dv_linkid, NULL,
4494             NULL, NULL, l->link_over, sizeof (l->link_over))) !=
4495             DLADM_STATUS_OK) {
4496                 goto done;
4497         }
4498 
4499         (void) snprintf(l->link_vlan_vid, sizeof (l->link_vlan_vid), "%d",
4500             vinfo.dv_vid);
4501         (void) snprintf(l->link_flags, sizeof (l->link_flags), "%c----",
4502             vinfo.dv_force ? 'f' : '-');
4503 
4504 done:
4505         return (status);
4506 }
4507 
4508 /* ARGSUSED */
4509 static int
4510 show_vlan(dladm_handle_t dh, datalink_id_t linkid, void *arg)
4511 {
4512         show_state_t            *state = arg;
4513         dladm_status_t          status;
4514         link_fields_buf_t       lbuf;
4515 
4516         bzero(&lbuf, sizeof (link_fields_buf_t));
4517         status = print_vlan(state, linkid, &lbuf);
4518         if (status != DLADM_STATUS_OK)
4519                 goto done;
4520 
4521         ofmt_print(state->ls_ofmt, &lbuf);
4522 
4523 done:
4524         state->ls_status = status;
4525         return (DLADM_WALK_CONTINUE);
4526 }
4527 
4528 static void
4529 do_show_phys(int argc, char *argv[], const char *use)
4530 {
4531         int             option;
4532         uint32_t        flags = DLADM_OPT_ACTIVE;
4533         boolean_t       p_arg = B_FALSE;
4534         boolean_t       o_arg = B_FALSE;
4535         boolean_t       m_arg = B_FALSE;
4536         boolean_t       H_arg = B_FALSE;
4537         datalink_id_t   linkid = DATALINK_ALL_LINKID;
4538         show_state_t    state;
4539         dladm_status_t  status;
4540         char            *fields_str = NULL;
4541         char            *all_active_fields =
4542             "link,media,state,speed,duplex,device";
4543         char            *all_inactive_fields = "link,device,media,flags";
4544         char            *all_mac_fields = "link,slot,address,inuse,client";
4545         char            *all_hwgrp_fields = "link,ringtype,rings,clients";
4546         const ofmt_field_t *pf;
4547         ofmt_handle_t   ofmt;
4548         ofmt_status_t   oferr;
4549         uint_t          ofmtflags = 0;
4550 
4551         bzero(&state, sizeof (state));
4552         opterr = 0;
4553         while ((option = getopt_long(argc, argv, ":pPo:mH",
4554             show_lopts, NULL)) != -1) {
4555                 switch (option) {
4556                 case 'p':
4557                         if (p_arg)
4558                                 die_optdup(option);
4559 
4560                         p_arg = B_TRUE;
4561                         break;
4562                 case 'P':
4563                         if (flags != DLADM_OPT_ACTIVE)
4564                                 die_optdup(option);
4565 
4566                         flags = DLADM_OPT_PERSIST;
4567                         break;
4568                 case 'o':
4569                         o_arg = B_TRUE;
4570                         fields_str = optarg;
4571                         break;
4572                 case 'm':
4573                         m_arg = B_TRUE;
4574                         break;
4575                 case 'H':
4576                         H_arg = B_TRUE;
4577                         break;
4578                 default:
4579                         die_opterr(optopt, option, use);
4580                         break;
4581                 }
4582         }
4583 
4584         if (p_arg && !o_arg)
4585                 die("-p requires -o");
4586 
4587         if (m_arg && H_arg)
4588                 die("-m cannot combine with -H");
4589 
4590         if (p_arg && strcasecmp(fields_str, "all") == 0)
4591                 die("\"-o all\" is invalid with -p");
4592 
4593         /* get link name (optional last argument) */
4594         if (optind == (argc-1)) {
4595                 if ((status = dladm_name2info(handle, argv[optind], &linkid,
4596                     NULL, NULL, NULL)) != DLADM_STATUS_OK) {
4597                         die_dlerr(status, "link %s is not valid", argv[optind]);
4598                 }
4599         } else if (optind != argc) {
4600                 usage();
4601         }
4602 
4603         state.ls_parsable = p_arg;
4604         state.ls_flags = flags;
4605         state.ls_donefirst = B_FALSE;
4606         state.ls_mac = m_arg;
4607         state.ls_hwgrp = H_arg;
4608 
4609         if (m_arg && !(flags & DLADM_OPT_ACTIVE)) {
4610                 /*
4611                  * We can only display the factory MAC addresses of
4612                  * active data-links.
4613                  */
4614                 die("-m not compatible with -P");
4615         }
4616 
4617         if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) {
4618                 if (state.ls_mac)
4619                         fields_str = all_mac_fields;
4620                 else if (state.ls_hwgrp)
4621                         fields_str = all_hwgrp_fields;
4622                 else if (state.ls_flags & DLADM_OPT_ACTIVE) {
4623                         fields_str = all_active_fields;
4624                 } else {
4625                         fields_str = all_inactive_fields;
4626                 }
4627         }
4628 
4629         if (state.ls_mac) {
4630                 pf = phys_m_fields;
4631         } else if (state.ls_hwgrp) {
4632                 pf = phys_h_fields;
4633         } else {
4634                 pf = phys_fields;
4635         }
4636 
4637         if (state.ls_parsable)
4638                 ofmtflags |= OFMT_PARSABLE;
4639         oferr = ofmt_open(fields_str, pf, ofmtflags, 0, &ofmt);
4640         ofmt_check(oferr, state.ls_parsable, ofmt, die, warn);
4641         state.ls_ofmt = ofmt;
4642 
4643         if (linkid == DATALINK_ALL_LINKID) {
4644                 (void) dladm_walk_datalink_id(show_phys, handle, &state,
4645                     DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE, flags);
4646         } else {
4647                 (void) show_phys(handle, linkid, &state);
4648                 if (state.ls_status != DLADM_STATUS_OK) {
4649                         die_dlerr(state.ls_status,
4650                             "failed to show physical link %s", argv[optind]);
4651                 }
4652         }
4653         ofmt_close(ofmt);
4654 }
4655 
4656 static void
4657 do_show_vlan(int argc, char *argv[], const char *use)
4658 {
4659         int             option;
4660         uint32_t        flags = DLADM_OPT_ACTIVE;
4661         boolean_t       p_arg = B_FALSE;
4662         datalink_id_t   linkid = DATALINK_ALL_LINKID;
4663         show_state_t    state;
4664         dladm_status_t  status;
4665         boolean_t       o_arg = B_FALSE;
4666         char            *fields_str = NULL;
4667         ofmt_handle_t   ofmt;
4668         ofmt_status_t   oferr;
4669         uint_t          ofmtflags = 0;
4670 
4671         bzero(&state, sizeof (state));
4672 
4673         opterr = 0;
4674         while ((option = getopt_long(argc, argv, ":pPo:",
4675             show_lopts, NULL)) != -1) {
4676                 switch (option) {
4677                 case 'p':
4678                         if (p_arg)
4679                                 die_optdup(option);
4680 
4681                         p_arg = B_TRUE;
4682                         break;
4683                 case 'P':
4684                         if (flags != DLADM_OPT_ACTIVE)
4685                                 die_optdup(option);
4686 
4687                         flags = DLADM_OPT_PERSIST;
4688                         break;
4689                 case 'o':
4690                         o_arg = B_TRUE;
4691                         fields_str = optarg;
4692                         break;
4693                 default:
4694                         die_opterr(optopt, option, use);
4695                         break;
4696                 }
4697         }
4698 
4699         /* get link name (optional last argument) */
4700         if (optind == (argc-1)) {
4701                 if ((status = dladm_name2info(handle, argv[optind], &linkid,
4702                     NULL, NULL, NULL)) != DLADM_STATUS_OK) {
4703                         die_dlerr(status, "link %s is not valid", argv[optind]);
4704                 }
4705         } else if (optind != argc) {
4706                 usage();
4707         }
4708 
4709         state.ls_parsable = p_arg;
4710         state.ls_flags = flags;
4711         state.ls_donefirst = B_FALSE;
4712 
4713         if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0))
4714                 fields_str = NULL;
4715 
4716         if (state.ls_parsable)
4717                 ofmtflags |= OFMT_PARSABLE;
4718         oferr = ofmt_open(fields_str, vlan_fields, ofmtflags, 0, &ofmt);
4719         ofmt_check(oferr, state.ls_parsable, ofmt, die, warn);
4720         state.ls_ofmt = ofmt;
4721 
4722         if (linkid == DATALINK_ALL_LINKID) {
4723                 (void) dladm_walk_datalink_id(show_vlan, handle, &state,
4724                     DATALINK_CLASS_VLAN, DATALINK_ANY_MEDIATYPE, flags);
4725         } else {
4726                 (void) show_vlan(handle, linkid, &state);
4727                 if (state.ls_status != DLADM_STATUS_OK) {
4728                         die_dlerr(state.ls_status, "failed to show vlan %s",
4729                             argv[optind]);
4730                 }
4731         }
4732         ofmt_close(ofmt);
4733 }
4734 
4735 static void
4736 do_create_vnic(int argc, char *argv[], const char *use)
4737 {
4738         datalink_id_t           linkid, dev_linkid;
4739         char                    devname[MAXLINKNAMELEN];
4740         char                    name[MAXLINKNAMELEN];
4741         boolean_t               l_arg = B_FALSE;
4742         uint32_t                flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
4743         char                    *altroot = NULL;
4744         int                     option;
4745         char                    *endp = NULL;
4746         dladm_status_t          status;
4747         vnic_mac_addr_type_t    mac_addr_type = VNIC_MAC_ADDR_TYPE_UNKNOWN;
4748         uchar_t                 *mac_addr = NULL;
4749         int                     mac_slot = -1;
4750         uint_t                  maclen = 0, mac_prefix_len = 0;
4751         char                    propstr[DLADM_STRSIZE];
4752         dladm_arg_list_t        *proplist = NULL;
4753         int                     vid = 0;
4754         int                     af = AF_UNSPEC;
4755         vrid_t                  vrid = VRRP_VRID_NONE;
4756 
4757         opterr = 0;
4758         bzero(propstr, DLADM_STRSIZE);
4759 
4760         while ((option = getopt_long(argc, argv, ":tfR:l:m:n:p:r:v:V:A:H",
4761             vnic_lopts, NULL)) != -1) {
4762                 switch (option) {
4763                 case 't':
4764                         flags &= ~DLADM_OPT_PERSIST;
4765                         break;
4766                 case 'R':
4767                         altroot = optarg;
4768                         break;
4769                 case 'l':
4770                         if (strlcpy(devname, optarg, MAXLINKNAMELEN) >=
4771                             MAXLINKNAMELEN)
4772                                 die("link name too long");
4773                         l_arg = B_TRUE;
4774                         break;
4775                 case 'm':
4776                         if (mac_addr_type != VNIC_MAC_ADDR_TYPE_UNKNOWN)
4777                                 die("cannot specify -m option twice");
4778 
4779                         if (strcmp(optarg, "fixed") == 0) {
4780                                 /*
4781                                  * A fixed MAC address must be specified
4782                                  * by its value, not by the keyword 'fixed'.
4783                                  */
4784                                 die("'fixed' is not a valid MAC address");
4785                         }
4786                         if (dladm_vnic_str2macaddrtype(optarg,
4787                             &mac_addr_type) != DLADM_STATUS_OK) {
4788                                 mac_addr_type = VNIC_MAC_ADDR_TYPE_FIXED;
4789                                 /* MAC address specified by value */
4790                                 mac_addr = _link_aton(optarg, (int *)&maclen);
4791                                 if (mac_addr == NULL) {
4792                                         if (maclen == (uint_t)-1)
4793                                                 die("invalid MAC address");
4794                                         else
4795                                                 die("out of memory");
4796                                 }
4797                         }
4798                         break;
4799                 case 'n':
4800                         errno = 0;
4801                         mac_slot = (int)strtol(optarg, &endp, 10);
4802                         if (errno != 0 || *endp != '\0')
4803                                 die("invalid slot number");
4804                         break;
4805                 case 'p':
4806                         (void) strlcat(propstr, optarg, DLADM_STRSIZE);
4807                         if (strlcat(propstr, ",", DLADM_STRSIZE) >=
4808                             DLADM_STRSIZE)
4809                                 die("property list too long '%s'", propstr);
4810                         break;
4811                 case 'r':
4812                         mac_addr = _link_aton(optarg, (int *)&mac_prefix_len);
4813                         if (mac_addr == NULL) {
4814                                 if (mac_prefix_len == (uint_t)-1)
4815                                         die("invalid MAC address");
4816                                 else
4817                                         die("out of memory");
4818                         }
4819                         break;
4820                 case 'V':
4821                         if (!str2int(optarg, (int *)&vrid) ||
4822                             vrid < VRRP_VRID_MIN || vrid > VRRP_VRID_MAX) {
4823                                 die("invalid VRRP identifier '%s'", optarg);
4824                         }
4825 
4826                         break;
4827                 case 'A':
4828                         if (strcmp(optarg, "inet") == 0)
4829                                 af = AF_INET;
4830                         else if (strcmp(optarg, "inet6") == 0)
4831                                 af = AF_INET6;
4832                         else
4833                                 die("invalid address family '%s'", optarg);
4834                         break;
4835                 case 'v':
4836                         if (vid != 0)
4837                                 die_optdup(option);
4838 
4839                         if (!str2int(optarg, &vid) || vid < 1 || vid > 4094)
4840                                 die("invalid VLAN identifier '%s'", optarg);
4841 
4842                         break;
4843                 case 'f':
4844                         flags |= DLADM_OPT_FORCE;
4845                         break;
4846                 default:
4847                         die_opterr(optopt, option, use);
4848                 }
4849         }
4850 
4851         if (mac_addr_type == VNIC_MAC_ADDR_TYPE_UNKNOWN)
4852                 mac_addr_type = VNIC_MAC_ADDR_TYPE_AUTO;
4853 
4854         /*
4855          * 'f' - force, flag can be specified only with 'v' - vlan.
4856          */
4857         if ((flags & DLADM_OPT_FORCE) != 0 && vid == 0)
4858                 die("-f option can only be used with -v");
4859 
4860         if (mac_prefix_len != 0 && mac_addr_type != VNIC_MAC_ADDR_TYPE_RANDOM &&
4861             mac_addr_type != VNIC_MAC_ADDR_TYPE_FIXED)
4862                 usage();
4863 
4864         if (mac_addr_type == VNIC_MAC_ADDR_TYPE_VRID) {
4865                 if (vrid == VRRP_VRID_NONE || af == AF_UNSPEC ||
4866                     mac_addr != NULL || maclen != 0 || mac_slot != -1 ||
4867                     mac_prefix_len != 0) {
4868                         usage();
4869                 }
4870         } else if ((af != AF_UNSPEC || vrid != VRRP_VRID_NONE)) {
4871                 usage();
4872         }
4873 
4874         /* check required options */
4875         if (!l_arg)
4876                 usage();
4877 
4878         if (mac_slot != -1 && mac_addr_type != VNIC_MAC_ADDR_TYPE_FACTORY)
4879                 usage();
4880 
4881         /* the VNIC id is the required operand */
4882         if (optind != (argc - 1))
4883                 usage();
4884 
4885         if (strlcpy(name, argv[optind], MAXLINKNAMELEN) >= MAXLINKNAMELEN)
4886                 die("link name too long '%s'", argv[optind]);
4887 
4888         if (!dladm_valid_linkname(name))
4889                 die("invalid link name '%s'", argv[optind]);
4890 
4891         if (altroot != NULL)
4892                 altroot_cmd(altroot, argc, argv);
4893 
4894         if (dladm_name2info(handle, devname, &dev_linkid, NULL, NULL, NULL) !=
4895             DLADM_STATUS_OK)
4896                 die("invalid link name '%s'", devname);
4897 
4898         if (dladm_parse_link_props(propstr, &proplist, B_FALSE)
4899             != DLADM_STATUS_OK)
4900                 die("invalid vnic property");
4901 
4902         status = dladm_vnic_create(handle, name, dev_linkid, mac_addr_type,
4903             mac_addr, maclen, &mac_slot, mac_prefix_len, vid, vrid, af,
4904             &linkid, proplist, &errlist, flags);
4905         switch (status) {
4906         case DLADM_STATUS_OK:
4907                 break;
4908 
4909         case DLADM_STATUS_LINKBUSY:
4910                 die("VLAN over '%s' may not use default_tag ID "
4911                     "(see dladm(1M))", devname);
4912                 break;
4913 
4914         default:
4915                 die_dlerrlist(status, &errlist, "vnic creation over %s failed",
4916                     devname);
4917         }
4918 
4919         dladm_free_props(proplist);
4920         free(mac_addr);
4921 }
4922 
4923 static void
4924 do_etherstub_check(const char *name, datalink_id_t linkid, boolean_t etherstub,
4925     uint32_t flags)
4926 {
4927         boolean_t is_etherstub;
4928         dladm_vnic_attr_t attr;
4929 
4930         if (dladm_vnic_info(handle, linkid, &attr, flags) != DLADM_STATUS_OK) {
4931                 /*
4932                  * Let the delete continue anyway.
4933                  */
4934                 return;
4935         }
4936         is_etherstub = (attr.va_link_id == DATALINK_INVALID_LINKID);
4937         if (is_etherstub != etherstub) {
4938                 die("'%s' is not %s", name,
4939                     (is_etherstub ? "a vnic" : "an etherstub"));
4940         }
4941 }
4942 
4943 static void
4944 do_delete_vnic_common(int argc, char *argv[], const char *use,
4945     boolean_t etherstub)
4946 {
4947         int option;
4948         uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
4949         datalink_id_t linkid;
4950         char *altroot = NULL;
4951         dladm_status_t status;
4952 
4953         opterr = 0;
4954         while ((option = getopt_long(argc, argv, ":R:t", lopts,
4955             NULL)) != -1) {
4956                 switch (option) {
4957                 case 't':
4958                         flags &= ~DLADM_OPT_PERSIST;
4959                         break;
4960                 case 'R':
4961                         altroot = optarg;
4962                         break;
4963                 default:
4964                         die_opterr(optopt, option, use);
4965                 }
4966         }
4967 
4968         /* get vnic name (required last argument) */
4969         if (optind != (argc - 1))
4970                 usage();
4971 
4972         if (altroot != NULL)
4973                 altroot_cmd(altroot, argc, argv);
4974 
4975         status = dladm_name2info(handle, argv[optind], &linkid, NULL, NULL,
4976             NULL);
4977         if (status != DLADM_STATUS_OK)
4978                 die("invalid link name '%s'", argv[optind]);
4979 
4980         if ((flags & DLADM_OPT_ACTIVE) != 0) {
4981                 do_etherstub_check(argv[optind], linkid, etherstub,
4982                     DLADM_OPT_ACTIVE);
4983         }
4984         if ((flags & DLADM_OPT_PERSIST) != 0) {
4985                 do_etherstub_check(argv[optind], linkid, etherstub,
4986                     DLADM_OPT_PERSIST);
4987         }
4988 
4989         status = dladm_vnic_delete(handle, linkid, flags);
4990         if (status != DLADM_STATUS_OK)
4991                 die_dlerr(status, "vnic deletion failed");
4992 }
4993 
4994 static void
4995 do_delete_vnic(int argc, char *argv[], const char *use)
4996 {
4997         do_delete_vnic_common(argc, argv, use, B_FALSE);
4998 }
4999 
5000 /* ARGSUSED */
5001 static void
5002 do_up_vnic_common(int argc, char *argv[], const char *use, boolean_t vlan)
5003 {
5004         datalink_id_t   linkid = DATALINK_ALL_LINKID;
5005         dladm_status_t  status;
5006         char            *type;
5007 
5008         type = vlan ? "vlan" : "vnic";
5009 
5010         /*
5011          * get the id or the name of the vnic/vlan (optional last argument)
5012          */
5013         if (argc == 2) {
5014                 status = dladm_name2info(handle, argv[1], &linkid, NULL, NULL,
5015                     NULL);
5016                 if (status != DLADM_STATUS_OK)
5017                         goto done;
5018 
5019         } else if (argc > 2) {
5020                 usage();
5021         }
5022 
5023         if (vlan)
5024                 status = dladm_vlan_up(handle, linkid);
5025         else
5026                 status = dladm_vnic_up(handle, linkid, 0);
5027 
5028 done:
5029         if (status != DLADM_STATUS_OK) {
5030                 if (argc == 2) {
5031                         die_dlerr(status,
5032                             "could not bring up %s '%s'", type, argv[1]);
5033                 } else {
5034                         die_dlerr(status, "could not bring %ss up", type);
5035                 }
5036         }
5037 }
5038 
5039 static void
5040 do_up_vnic(int argc, char *argv[], const char *use)
5041 {
5042         do_up_vnic_common(argc, argv, use, B_FALSE);
5043 }
5044 
5045 static void
5046 dump_vnics_head(const char *dev)
5047 {
5048         if (strlen(dev))
5049                 (void) printf("%s", dev);
5050 
5051         (void) printf("\tipackets  rbytes      opackets  obytes          ");
5052 
5053         if (strlen(dev))
5054                 (void) printf("%%ipkts  %%opkts\n");
5055         else
5056                 (void) printf("\n");
5057 }
5058 
5059 static void
5060 dump_vnic_stat(const char *name, datalink_id_t vnic_id,
5061     show_vnic_state_t *state, pktsum_t *vnic_stats, pktsum_t *tot_stats)
5062 {
5063         pktsum_t        diff_stats;
5064         pktsum_t        *old_stats = &state->vs_prevstats[vnic_id];
5065 
5066         dladm_stats_diff(&diff_stats, vnic_stats, old_stats);
5067 
5068         (void) printf("%s", name);
5069 
5070         (void) printf("\t%-10llu", diff_stats.ipackets);
5071         (void) printf("%-12llu", diff_stats.rbytes);
5072         (void) printf("%-10llu", diff_stats.opackets);
5073         (void) printf("%-12llu", diff_stats.obytes);
5074 
5075         if (tot_stats) {
5076                 if (tot_stats->ipackets == 0) {
5077                         (void) printf("\t-");
5078                 } else {
5079                         (void) printf("\t%-6.1f", (double)diff_stats.ipackets/
5080                             (double)tot_stats->ipackets * 100);
5081                 }
5082                 if (tot_stats->opackets == 0) {
5083                         (void) printf("\t-");
5084                 } else {
5085                         (void) printf("\t%-6.1f", (double)diff_stats.opackets/
5086                             (double)tot_stats->opackets * 100);
5087                 }
5088         }
5089         (void) printf("\n");
5090 
5091         *old_stats = *vnic_stats;
5092 }
5093 
5094 /*
5095  * Called from the walker dladm_vnic_walk_sys() for each vnic to display
5096  * vnic information or statistics.
5097  */
5098 static dladm_status_t
5099 print_vnic(show_vnic_state_t *state, datalink_id_t linkid)
5100 {
5101         dladm_vnic_attr_t       attr, *vnic = &attr;
5102         dladm_status_t          status;
5103         boolean_t               is_etherstub;
5104         char                    devname[MAXLINKNAMELEN];
5105         char                    vnic_name[MAXLINKNAMELEN];
5106         char                    mstr[MAXMACADDRLEN * 3];
5107         vnic_fields_buf_t       vbuf;
5108         uint_t                  valcnt = 1;
5109         char                    zonename[DLADM_PROP_VAL_MAX + 1];
5110         char                    *valptr[1];
5111 
5112         if ((status = dladm_vnic_info(handle, linkid, vnic, state->vs_flags)) !=
5113             DLADM_STATUS_OK)
5114                 return (status);
5115 
5116         is_etherstub = (vnic->va_link_id == DATALINK_INVALID_LINKID);
5117         if (state->vs_etherstub != is_etherstub) {
5118                 /*
5119                  * Want all etherstub but it's not one, or want
5120                  * non-etherstub and it's one.
5121                  */
5122                 return (DLADM_STATUS_OK);
5123         }
5124 
5125         if (state->vs_link_id != DATALINK_ALL_LINKID) {
5126                 if (state->vs_link_id != vnic->va_link_id)
5127                         return (DLADM_STATUS_OK);
5128         }
5129 
5130         if (dladm_datalink_id2info(handle, linkid, NULL, NULL,
5131             NULL, vnic_name, sizeof (vnic_name)) != DLADM_STATUS_OK)
5132                 return (DLADM_STATUS_BADARG);
5133 
5134         bzero(devname, sizeof (devname));
5135         if (!is_etherstub &&
5136             dladm_datalink_id2info(handle, vnic->va_link_id, NULL, NULL,
5137             NULL, devname, sizeof (devname)) != DLADM_STATUS_OK)
5138                 (void) sprintf(devname, "?");
5139 
5140         zonename[0] = '\0';
5141         if (!is_etherstub) {
5142                 valptr[0] = zonename;
5143                 (void) dladm_get_linkprop(handle, linkid,
5144                     DLADM_PROP_VAL_CURRENT, "zone", (char **)valptr, &valcnt);
5145         }
5146 
5147         state->vs_found = B_TRUE;
5148         if (state->vs_stats) {
5149                 /* print vnic statistics */
5150                 pktsum_t vnic_stats;
5151 
5152                 if (state->vs_firstonly) {
5153                         if (state->vs_donefirst)
5154                                 return (0);
5155                         state->vs_donefirst = B_TRUE;
5156                 }
5157 
5158                 if (!state->vs_printstats) {
5159                         /*
5160                          * get vnic statistics and add to the sum for the
5161                          * named device.
5162                          */
5163                         get_link_stats(vnic_name, &vnic_stats);
5164                         dladm_stats_total(&state->vs_totalstats, &vnic_stats,
5165                             &state->vs_prevstats[vnic->va_vnic_id]);
5166                 } else {
5167                         /* get and print vnic statistics */
5168                         get_link_stats(vnic_name, &vnic_stats);
5169                         dump_vnic_stat(vnic_name, linkid, state, &vnic_stats,
5170                             &state->vs_totalstats);
5171                 }
5172                 return (DLADM_STATUS_OK);
5173         } else {
5174                 (void) snprintf(vbuf.vnic_link, sizeof (vbuf.vnic_link),
5175                     "%s", vnic_name);
5176 
5177                 if (!is_etherstub) {
5178 
5179                         (void) snprintf(vbuf.vnic_over, sizeof (vbuf.vnic_over),
5180                             "%s", devname);
5181                         (void) snprintf(vbuf.vnic_speed,
5182                             sizeof (vbuf.vnic_speed), "%u",
5183                             (uint_t)((get_ifspeed(vnic_name, B_TRUE))
5184                             / 1000000ull));
5185 
5186                         switch (vnic->va_mac_addr_type) {
5187                         case VNIC_MAC_ADDR_TYPE_FIXED:
5188                         case VNIC_MAC_ADDR_TYPE_PRIMARY:
5189                                 (void) snprintf(vbuf.vnic_macaddrtype,
5190                                     sizeof (vbuf.vnic_macaddrtype),
5191                                     gettext("fixed"));
5192                                 break;
5193                         case VNIC_MAC_ADDR_TYPE_RANDOM:
5194                                 (void) snprintf(vbuf.vnic_macaddrtype,
5195                                     sizeof (vbuf.vnic_macaddrtype),
5196                                     gettext("random"));
5197                                 break;
5198                         case VNIC_MAC_ADDR_TYPE_FACTORY:
5199                                 (void) snprintf(vbuf.vnic_macaddrtype,
5200                                     sizeof (vbuf.vnic_macaddrtype),
5201                                     gettext("factory, slot %d"),
5202                                     vnic->va_mac_slot);
5203                                 break;
5204                         case VNIC_MAC_ADDR_TYPE_VRID:
5205                                 (void) snprintf(vbuf.vnic_macaddrtype,
5206                                     sizeof (vbuf.vnic_macaddrtype),
5207                                     gettext("vrrp, %d/%s"),
5208                                     vnic->va_vrid, vnic->va_af == AF_INET ?
5209                                     "inet" : "inet6");
5210                                 break;
5211                         }
5212 
5213                         if (strlen(vbuf.vnic_macaddrtype) > 0) {
5214                                 (void) snprintf(vbuf.vnic_macaddr,
5215                                     sizeof (vbuf.vnic_macaddr), "%s",
5216                                     dladm_aggr_macaddr2str(vnic->va_mac_addr,
5217                                     mstr));
5218                         }
5219 
5220                         (void) snprintf(vbuf.vnic_vid, sizeof (vbuf.vnic_vid),
5221                             "%d", vnic->va_vid);
5222 
5223                         if (zonename[0] != '\0')
5224                                 (void) snprintf(vbuf.vnic_zone,
5225                                     sizeof (vbuf.vnic_zone), "%s", zonename);
5226                         else
5227                                 (void) strlcpy(vbuf.vnic_zone, "--",
5228                                     sizeof (vbuf.vnic_zone));
5229                 }
5230 
5231                 ofmt_print(state->vs_ofmt, &vbuf);
5232 
5233                 return (DLADM_STATUS_OK);
5234         }
5235 }
5236 
5237 /* ARGSUSED */
5238 static int
5239 show_vnic(dladm_handle_t dh, datalink_id_t linkid, void *arg)
5240 {
5241         show_vnic_state_t       *state = arg;
5242 
5243         state->vs_status = print_vnic(state, linkid);
5244         return (DLADM_WALK_CONTINUE);
5245 }
5246 
5247 static void
5248 do_show_vnic_common(int argc, char *argv[], const char *use,
5249     boolean_t etherstub)
5250 {
5251         int                     option;
5252         boolean_t               s_arg = B_FALSE;
5253         boolean_t               i_arg = B_FALSE;
5254         boolean_t               l_arg = B_FALSE;
5255         uint32_t                interval = 0, flags = DLADM_OPT_ACTIVE;
5256         datalink_id_t           linkid = DATALINK_ALL_LINKID;
5257         datalink_id_t           dev_linkid = DATALINK_ALL_LINKID;
5258         show_vnic_state_t       state;
5259         dladm_status_t          status;
5260         boolean_t               o_arg = B_FALSE;
5261         char                    *fields_str = NULL;
5262         const ofmt_field_t      *pf;
5263         char                    *all_e_fields = "link";
5264         ofmt_handle_t           ofmt;
5265         ofmt_status_t           oferr;
5266         uint_t                  ofmtflags = 0;
5267 
5268         bzero(&state, sizeof (state));
5269         opterr = 0;
5270         while ((option = getopt_long(argc, argv, ":pPl:si:o:", lopts,
5271             NULL)) != -1) {
5272                 switch (option) {
5273                 case 'p':
5274                         state.vs_parsable = B_TRUE;
5275                         break;
5276                 case 'P':
5277                         flags = DLADM_OPT_PERSIST;
5278                         break;
5279                 case 'l':
5280                         if (etherstub)
5281                                 die("option not supported for this command");
5282 
5283                         if (strlcpy(state.vs_link, optarg, MAXLINKNAMELEN) >=
5284                             MAXLINKNAMELEN)
5285                                 die("link name too long");
5286 
5287                         l_arg = B_TRUE;
5288                         break;
5289                 case 's':
5290                         if (s_arg) {
5291                                 die("the option -s cannot be specified "
5292                                     "more than once");
5293                         }
5294                         s_arg = B_TRUE;
5295                         break;
5296                 case 'i':
5297                         if (i_arg) {
5298                                 die("the option -i cannot be specified "
5299                                     "more than once");
5300                         }
5301                         i_arg = B_TRUE;
5302                         if (!dladm_str2interval(optarg, &interval))
5303                                 die("invalid interval value '%s'", optarg);
5304                         break;
5305                 case 'o':
5306                         o_arg = B_TRUE;
5307                         fields_str = optarg;
5308                         break;
5309                 default:
5310                         die_opterr(optopt, option, use);
5311                 }
5312         }
5313 
5314         if (i_arg && !s_arg)
5315                 die("the option -i can be used only with -s");
5316 
5317         /* get vnic ID (optional last argument) */
5318         if (optind == (argc - 1)) {
5319                 status = dladm_name2info(handle, argv[optind], &linkid, NULL,
5320                     NULL, NULL);
5321                 if (status != DLADM_STATUS_OK) {
5322                         die_dlerr(status, "invalid vnic name '%s'",
5323                             argv[optind]);
5324                 }
5325                 (void) strlcpy(state.vs_vnic, argv[optind], MAXLINKNAMELEN);
5326         } else if (optind != argc) {
5327                 usage();
5328         }
5329 
5330         if (l_arg) {
5331                 status = dladm_name2info(handle, state.vs_link, &dev_linkid,
5332                     NULL, NULL, NULL);
5333                 if (status != DLADM_STATUS_OK) {
5334                         die_dlerr(status, "invalid link name '%s'",
5335                             state.vs_link);
5336                 }
5337         }
5338 
5339         state.vs_vnic_id = linkid;
5340         state.vs_link_id = dev_linkid;
5341         state.vs_etherstub = etherstub;
5342         state.vs_found = B_FALSE;
5343         state.vs_flags = flags;
5344 
5345         if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) {
5346                 if (etherstub)
5347                         fields_str = all_e_fields;
5348         }
5349         pf = vnic_fields;
5350 
5351         if (state.vs_parsable)
5352                 ofmtflags |= OFMT_PARSABLE;
5353         oferr = ofmt_open(fields_str, pf, ofmtflags, 0, &ofmt);
5354         ofmt_check(oferr, state.vs_parsable, ofmt, die, warn);
5355         state.vs_ofmt = ofmt;
5356 
5357         if (s_arg) {
5358                 /* Display vnic statistics */
5359                 vnic_stats(&state, interval);
5360                 ofmt_close(ofmt);
5361                 return;
5362         }
5363 
5364         /* Display vnic information */
5365         state.vs_donefirst = B_FALSE;
5366 
5367         if (linkid == DATALINK_ALL_LINKID) {
5368                 (void) dladm_walk_datalink_id(show_vnic, handle, &state,
5369                     DATALINK_CLASS_VNIC | DATALINK_CLASS_ETHERSTUB,
5370                     DATALINK_ANY_MEDIATYPE, flags);
5371         } else {
5372                 (void) show_vnic(handle, linkid, &state);
5373                 if (state.vs_status != DLADM_STATUS_OK) {
5374                         ofmt_close(ofmt);
5375                         die_dlerr(state.vs_status, "failed to show vnic '%s'",
5376                             state.vs_vnic);
5377                 }
5378         }
5379         ofmt_close(ofmt);
5380 }
5381 
5382 static void
5383 do_show_vnic(int argc, char *argv[], const char *use)
5384 {
5385         do_show_vnic_common(argc, argv, use, B_FALSE);
5386 }
5387 
5388 static void
5389 do_create_etherstub(int argc, char *argv[], const char *use)
5390 {
5391         uint32_t flags;
5392         char *altroot = NULL;
5393         int option;
5394         dladm_status_t status;
5395         char name[MAXLINKNAMELEN];
5396         uchar_t mac_addr[ETHERADDRL];
5397 
5398         name[0] = '\0';
5399         bzero(mac_addr, sizeof (mac_addr));
5400         flags = DLADM_OPT_ANCHOR | DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
5401 
5402         opterr = 0;
5403         while ((option = getopt_long(argc, argv, "tR:",
5404             etherstub_lopts, NULL)) != -1) {
5405                 switch (option) {
5406                 case 't':
5407                         flags &= ~DLADM_OPT_PERSIST;
5408                         break;
5409                 case 'R':
5410                         altroot = optarg;
5411                         break;
5412                 default:
5413                         die_opterr(optopt, option, use);
5414                 }
5415         }
5416 
5417         /* the etherstub id is the required operand */
5418         if (optind != (argc - 1))
5419                 usage();
5420 
5421         if (strlcpy(name, argv[optind], MAXLINKNAMELEN) >= MAXLINKNAMELEN)
5422                 die("link name too long '%s'", argv[optind]);
5423 
5424         if (!dladm_valid_linkname(name))
5425                 die("invalid link name '%s'", argv[optind]);
5426 
5427         if (altroot != NULL)
5428                 altroot_cmd(altroot, argc, argv);
5429 
5430         status = dladm_vnic_create(handle, name, DATALINK_INVALID_LINKID,
5431             VNIC_MAC_ADDR_TYPE_AUTO, mac_addr, ETHERADDRL, NULL, 0, 0,
5432             VRRP_VRID_NONE, AF_UNSPEC, NULL, NULL, &errlist, flags);
5433         if (status != DLADM_STATUS_OK)
5434                 die_dlerr(status, "etherstub creation failed");
5435 }
5436 
5437 static void
5438 do_delete_etherstub(int argc, char *argv[], const char *use)
5439 {
5440         do_delete_vnic_common(argc, argv, use, B_TRUE);
5441 }
5442 
5443 /* ARGSUSED */
5444 static void
5445 do_show_etherstub(int argc, char *argv[], const char *use)
5446 {
5447         do_show_vnic_common(argc, argv, use, B_TRUE);
5448 }
5449 
5450 /* ARGSUSED */
5451 static void
5452 do_up_simnet(int argc, char *argv[], const char *use)
5453 {
5454         (void) dladm_simnet_up(handle, DATALINK_ALL_LINKID, 0);
5455 }
5456 
5457 static void
5458 do_create_simnet(int argc, char *argv[], const char *use)
5459 {
5460         uint32_t flags;
5461         char *altroot = NULL;
5462         char *media = NULL;
5463         uint32_t mtype = DL_ETHER;
5464         int option;
5465         dladm_status_t status;
5466         char name[MAXLINKNAMELEN];
5467 
5468         name[0] = '\0';
5469         flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
5470 
5471         opterr = 0;
5472         while ((option = getopt_long(argc, argv, ":tR:m:",
5473             simnet_lopts, NULL)) != -1) {
5474                 switch (option) {
5475                 case 't':
5476                         flags &= ~DLADM_OPT_PERSIST;
5477                         break;
5478                 case 'R':
5479                         altroot = optarg;
5480                         break;
5481                 case 'm':
5482                         media = optarg;
5483                         break;
5484                 default:
5485                         die_opterr(optopt, option, use);
5486                 }
5487         }
5488 
5489         /* the simnet id is the required operand */
5490         if (optind != (argc - 1))
5491                 usage();
5492 
5493         if (strlcpy(name, argv[optind], MAXLINKNAMELEN) >= MAXLINKNAMELEN)
5494                 die("link name too long '%s'", argv[optind]);
5495 
5496         if (!dladm_valid_linkname(name))
5497                 die("invalid link name '%s'", name);
5498 
5499         if (media != NULL) {
5500                 mtype = dladm_str2media(media);
5501                 if (mtype != DL_ETHER && mtype != DL_WIFI)
5502                         die("media type '%s' is not supported", media);
5503         }
5504 
5505         if (altroot != NULL)
5506                 altroot_cmd(altroot, argc, argv);
5507 
5508         status = dladm_simnet_create(handle, name, mtype, flags);
5509         if (status != DLADM_STATUS_OK)
5510                 die_dlerr(status, "simnet creation failed");
5511 }
5512 
5513 static void
5514 do_delete_simnet(int argc, char *argv[], const char *use)
5515 {
5516         int option;
5517         uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
5518         datalink_id_t linkid;
5519         char *altroot = NULL;
5520         dladm_status_t status;
5521         dladm_simnet_attr_t slinfo;
5522 
5523         opterr = 0;
5524         while ((option = getopt_long(argc, argv, ":tR:", simnet_lopts,
5525             NULL)) != -1) {
5526                 switch (option) {
5527                 case 't':
5528                         flags &= ~DLADM_OPT_PERSIST;
5529                         break;
5530                 case 'R':
5531                         altroot = optarg;
5532                         break;
5533                 default:
5534                         die_opterr(optopt, option, use);
5535                 }
5536         }
5537 
5538         /* get simnet name (required last argument) */
5539         if (optind != (argc - 1))
5540                 usage();
5541 
5542         if (!dladm_valid_linkname(argv[optind]))
5543                 die("invalid link name '%s'", argv[optind]);
5544 
5545         if (altroot != NULL)
5546                 altroot_cmd(altroot, argc, argv);
5547 
5548         status = dladm_name2info(handle, argv[optind], &linkid, NULL, NULL,
5549             NULL);
5550         if (status != DLADM_STATUS_OK)
5551                 die("simnet '%s' not found", argv[optind]);
5552 
5553         if ((status = dladm_simnet_info(handle, linkid, &slinfo,
5554             flags)) != DLADM_STATUS_OK)
5555                 die_dlerr(status, "failed to retrieve simnet information");
5556 
5557         status = dladm_simnet_delete(handle, linkid, flags);
5558         if (status != DLADM_STATUS_OK)
5559                 die_dlerr(status, "simnet deletion failed");
5560 }
5561 
5562 static void
5563 do_modify_simnet(int argc, char *argv[], const char *use)
5564 {
5565         int option;
5566         uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
5567         datalink_id_t linkid;
5568         datalink_id_t peer_linkid;
5569         char *altroot = NULL;
5570         dladm_status_t status;
5571         boolean_t p_arg = B_FALSE;
5572 
5573         opterr = 0;
5574         while ((option = getopt_long(argc, argv, ":tR:p:", simnet_lopts,
5575             NULL)) != -1) {
5576                 switch (option) {
5577                 case 't':
5578                         flags &= ~DLADM_OPT_PERSIST;
5579                         break;
5580                 case 'R':
5581                         altroot = optarg;
5582                         break;
5583                 case 'p':
5584                         if (p_arg)
5585                                 die_optdup(option);
5586                         p_arg = B_TRUE;
5587                         if (strcasecmp(optarg, "none") == 0)
5588                                 peer_linkid = DATALINK_INVALID_LINKID;
5589                         else if (dladm_name2info(handle, optarg, &peer_linkid,
5590                             NULL, NULL, NULL) != DLADM_STATUS_OK)
5591                                 die("invalid peer link name '%s'", optarg);
5592                         break;
5593                 default:
5594                         die_opterr(optopt, option, use);
5595                 }
5596         }
5597 
5598         /* get simnet name (required last argument) */
5599         if (optind != (argc - 1))
5600                 usage();
5601 
5602         /* Nothing to do if no peer link argument */
5603         if (!p_arg)
5604                 return;
5605 
5606         if (altroot != NULL)
5607                 altroot_cmd(altroot, argc, argv);
5608 
5609         status = dladm_name2info(handle, argv[optind], &linkid, NULL, NULL,
5610             NULL);
5611         if (status != DLADM_STATUS_OK)
5612                 die("invalid link name '%s'", argv[optind]);
5613 
5614         status = dladm_simnet_modify(handle, linkid, peer_linkid, flags);
5615         if (status != DLADM_STATUS_OK)
5616                 die_dlerr(status, "simnet modification failed");
5617 }
5618 
5619 static dladm_status_t
5620 print_simnet(show_state_t *state, datalink_id_t linkid)
5621 {
5622         dladm_simnet_attr_t     slinfo;
5623         uint32_t                flags;
5624         dladm_status_t          status;
5625         simnet_fields_buf_t     slbuf;
5626         char                    mstr[ETHERADDRL * 3];
5627 
5628         bzero(&slbuf, sizeof (slbuf));
5629         if ((status = dladm_datalink_id2info(handle, linkid, &flags, NULL, NULL,
5630             slbuf.simnet_name, sizeof (slbuf.simnet_name)))
5631             != DLADM_STATUS_OK)
5632                 return (status);
5633 
5634         if (!(state->ls_flags & flags))
5635                 return (DLADM_STATUS_NOTFOUND);
5636 
5637         if ((status = dladm_simnet_info(handle, linkid, &slinfo,
5638             state->ls_flags)) != DLADM_STATUS_OK)
5639                 return (status);
5640 
5641         if (slinfo.sna_peer_link_id != DATALINK_INVALID_LINKID &&
5642             (status = dladm_datalink_id2info(handle, slinfo.sna_peer_link_id,
5643             NULL, NULL, NULL, slbuf.simnet_otherlink,
5644             sizeof (slbuf.simnet_otherlink))) !=
5645             DLADM_STATUS_OK)
5646                 return (status);
5647 
5648         if (slinfo.sna_mac_len > sizeof (slbuf.simnet_macaddr))
5649                 return (DLADM_STATUS_BADVAL);
5650 
5651         (void) strlcpy(slbuf.simnet_macaddr,
5652             dladm_aggr_macaddr2str(slinfo.sna_mac_addr, mstr),
5653             sizeof (slbuf.simnet_macaddr));
5654         (void) dladm_media2str(slinfo.sna_type, slbuf.simnet_media);
5655 
5656         ofmt_print(state->ls_ofmt, &slbuf);
5657         return (status);
5658 }
5659 
5660 /* ARGSUSED */
5661 static int
5662 show_simnet(dladm_handle_t dh, datalink_id_t linkid, void *arg)
5663 {
5664         show_state_t            *state = arg;
5665 
5666         state->ls_status = print_simnet(state, linkid);
5667         return (DLADM_WALK_CONTINUE);
5668 }
5669 
5670 static void
5671 do_show_simnet(int argc, char *argv[], const char *use)
5672 {
5673         int             option;
5674         uint32_t        flags = DLADM_OPT_ACTIVE;
5675         boolean_t       p_arg = B_FALSE;
5676         datalink_id_t   linkid = DATALINK_ALL_LINKID;
5677         show_state_t    state;
5678         dladm_status_t  status;
5679         boolean_t       o_arg = B_FALSE;
5680         ofmt_handle_t   ofmt;
5681         ofmt_status_t   oferr;
5682         char            *all_fields = "link,media,macaddress,otherlink";
5683         char            *fields_str = all_fields;
5684         uint_t          ofmtflags = 0;
5685 
5686         bzero(&state, sizeof (state));
5687 
5688         opterr = 0;
5689         while ((option = getopt_long(argc, argv, ":pPo:",
5690             show_lopts, NULL)) != -1) {
5691                 switch (option) {
5692                 case 'p':
5693                         if (p_arg)
5694                                 die_optdup(option);
5695 
5696                         p_arg = B_TRUE;
5697                         state.ls_parsable = p_arg;
5698                         break;
5699                 case 'P':
5700                         if (flags != DLADM_OPT_ACTIVE)
5701                                 die_optdup(option);
5702 
5703                         flags = DLADM_OPT_PERSIST;
5704                         break;
5705                 case 'o':
5706                         o_arg = B_TRUE;
5707                         fields_str = optarg;
5708                         break;
5709                 default:
5710                         die_opterr(optopt, option, use);
5711                         break;
5712                 }
5713         }
5714 
5715         if (p_arg && !o_arg)
5716                 die("-p requires -o");
5717 
5718         if (strcasecmp(fields_str, "all") == 0) {
5719                 if (p_arg)
5720                         die("\"-o all\" is invalid with -p");
5721                 fields_str = all_fields;
5722         }
5723 
5724         /* get link name (optional last argument) */
5725         if (optind == (argc-1)) {
5726                 if ((status = dladm_name2info(handle, argv[optind], &linkid,
5727                     NULL, NULL, NULL)) != DLADM_STATUS_OK) {
5728                         die_dlerr(status, "link %s is not valid", argv[optind]);
5729                 }
5730         } else if (optind != argc) {
5731                 usage();
5732         }
5733 
5734         state.ls_flags = flags;
5735         state.ls_donefirst = B_FALSE;
5736         if (state.ls_parsable)
5737                 ofmtflags |= OFMT_PARSABLE;
5738         oferr = ofmt_open(fields_str, simnet_fields, ofmtflags, 0, &ofmt);
5739         ofmt_check(oferr, state.ls_parsable, ofmt, die, warn);
5740         state.ls_ofmt = ofmt;
5741 
5742         if (linkid == DATALINK_ALL_LINKID) {
5743                 (void) dladm_walk_datalink_id(show_simnet, handle, &state,
5744                     DATALINK_CLASS_SIMNET, DATALINK_ANY_MEDIATYPE, flags);
5745         } else {
5746                 (void) show_simnet(handle, linkid, &state);
5747                 if (state.ls_status != DLADM_STATUS_OK) {
5748                         ofmt_close(ofmt);
5749                         die_dlerr(state.ls_status, "failed to show simnet %s",
5750                             argv[optind]);
5751                 }
5752         }
5753         ofmt_close(ofmt);
5754 }
5755 
5756 static void
5757 link_stats(datalink_id_t linkid, uint_t interval, char *fields_str,
5758     show_state_t *state)
5759 {
5760         ofmt_handle_t   ofmt;
5761         ofmt_status_t   oferr;
5762         uint_t          ofmtflags = 0;
5763 
5764         if (state->ls_parsable)
5765                 ofmtflags |= OFMT_PARSABLE;
5766         oferr = ofmt_open(fields_str, link_s_fields, ofmtflags, 0, &ofmt);
5767         ofmt_check(oferr, state->ls_parsable, ofmt, die, warn);
5768         state->ls_ofmt = ofmt;
5769 
5770         /*
5771          * If an interval is specified, continuously show the stats
5772          * only for the first MAC port.
5773          */
5774         state->ls_firstonly = (interval != 0);
5775 
5776         for (;;) {
5777                 state->ls_donefirst = B_FALSE;
5778                 if (linkid == DATALINK_ALL_LINKID) {
5779                         (void) dladm_walk_datalink_id(show_link_stats, handle,
5780                             state, DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE,
5781                             DLADM_OPT_ACTIVE);
5782                 } else {
5783                         (void) show_link_stats(handle, linkid, state);
5784                 }
5785 
5786                 if (interval == 0)
5787                         break;
5788 
5789                 (void) fflush(stdout);
5790                 (void) sleep(interval);
5791         }
5792         ofmt_close(ofmt);
5793 }
5794 
5795 static void
5796 aggr_stats(datalink_id_t linkid, show_grp_state_t *state, uint_t interval)
5797 {
5798         /*
5799          * If an interval is specified, continuously show the stats
5800          * only for the first group.
5801          */
5802         state->gs_firstonly = (interval != 0);
5803 
5804         for (;;) {
5805                 state->gs_donefirst = B_FALSE;
5806                 if (linkid == DATALINK_ALL_LINKID)
5807                         (void) dladm_walk_datalink_id(show_aggr, handle, state,
5808                             DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE,
5809                             DLADM_OPT_ACTIVE);
5810                 else
5811                         (void) show_aggr(handle, linkid, state);
5812 
5813                 if (interval == 0)
5814                         break;
5815 
5816                 (void) fflush(stdout);
5817                 (void) sleep(interval);
5818         }
5819 }
5820 
5821 /* ARGSUSED */
5822 static void
5823 vnic_stats(show_vnic_state_t *sp, uint32_t interval)
5824 {
5825         show_vnic_state_t       state;
5826         boolean_t               specific_link, specific_dev;
5827 
5828         /* Display vnic statistics */
5829         dump_vnics_head(sp->vs_link);
5830 
5831         bzero(&state, sizeof (state));
5832         state.vs_stats = B_TRUE;
5833         state.vs_vnic_id = sp->vs_vnic_id;
5834         state.vs_link_id = sp->vs_link_id;
5835 
5836         /*
5837          * If an interval is specified, and a vnic ID is not specified,
5838          * continuously show the stats only for the first vnic.
5839          */
5840         specific_link = (sp->vs_vnic_id != DATALINK_ALL_LINKID);
5841         specific_dev = (sp->vs_link_id != DATALINK_ALL_LINKID);
5842 
5843         for (;;) {
5844                 /* Get stats for each vnic */
5845                 state.vs_found = B_FALSE;
5846                 state.vs_donefirst = B_FALSE;
5847                 state.vs_printstats = B_FALSE;
5848                 state.vs_flags = DLADM_OPT_ACTIVE;
5849 
5850                 if (!specific_link) {
5851                         (void) dladm_walk_datalink_id(show_vnic, handle, &state,
5852                             DATALINK_CLASS_VNIC, DATALINK_ANY_MEDIATYPE,
5853                             DLADM_OPT_ACTIVE);
5854                 } else {
5855                         (void) show_vnic(handle, sp->vs_vnic_id, &state);
5856                         if (state.vs_status != DLADM_STATUS_OK) {
5857                                 die_dlerr(state.vs_status,
5858                                     "failed to show vnic '%s'", sp->vs_vnic);
5859                         }
5860                 }
5861 
5862                 if (specific_link && !state.vs_found)
5863                         die("non-existent vnic '%s'", sp->vs_vnic);
5864                 if (specific_dev && !state.vs_found)
5865                         die("device %s has no vnics", sp->vs_link);
5866 
5867                 /* Show totals */
5868                 if ((specific_link | specific_dev) && !interval) {
5869                         (void) printf("Total");
5870                         (void) printf("\t%-10llu",
5871                             state.vs_totalstats.ipackets);
5872                         (void) printf("%-12llu",
5873                             state.vs_totalstats.rbytes);
5874                         (void) printf("%-10llu",
5875                             state.vs_totalstats.opackets);
5876                         (void) printf("%-12llu\n",
5877                             state.vs_totalstats.obytes);
5878                 }
5879 
5880                 /* Show stats for each vnic */
5881                 state.vs_donefirst = B_FALSE;
5882                 state.vs_printstats = B_TRUE;
5883 
5884                 if (!specific_link) {
5885                         (void) dladm_walk_datalink_id(show_vnic, handle, &state,
5886                             DATALINK_CLASS_VNIC, DATALINK_ANY_MEDIATYPE,
5887                             DLADM_OPT_ACTIVE);
5888                 } else {
5889                         (void) show_vnic(handle, sp->vs_vnic_id, &state);
5890                         if (state.vs_status != DLADM_STATUS_OK) {
5891                                 die_dlerr(state.vs_status,
5892                                     "failed to show vnic '%s'", sp->vs_vnic);
5893                         }
5894                 }
5895 
5896                 if (interval == 0)
5897                         break;
5898 
5899                 (void) fflush(stdout);
5900                 (void) sleep(interval);
5901         }
5902 }
5903 
5904 static void
5905 get_mac_stats(const char *dev, pktsum_t *stats)
5906 {
5907         kstat_ctl_t     *kcp;
5908         kstat_t         *ksp;
5909         char module[DLPI_LINKNAME_MAX];
5910         uint_t instance;
5911 
5912 
5913         bzero(stats, sizeof (*stats));
5914 
5915         if (dlpi_parselink(dev, module, &instance) != DLPI_SUCCESS)
5916                 return;
5917 
5918         if ((kcp = kstat_open()) == NULL) {
5919                 warn("kstat open operation failed");
5920                 return;
5921         }
5922 
5923         ksp = dladm_kstat_lookup(kcp, module, instance, "mac", NULL);
5924         if (ksp != NULL)
5925                 dladm_get_stats(kcp, ksp, stats);
5926 
5927         (void) kstat_close(kcp);
5928 
5929 }
5930 
5931 static void
5932 get_link_stats(const char *link, pktsum_t *stats)
5933 {
5934         kstat_ctl_t     *kcp;
5935         kstat_t         *ksp;
5936 
5937         bzero(stats, sizeof (*stats));
5938 
5939         if ((kcp = kstat_open()) == NULL) {
5940                 warn("kstat_open operation failed");
5941                 return;
5942         }
5943 
5944         ksp = dladm_kstat_lookup(kcp, "link", 0, link, NULL);
5945 
5946         if (ksp != NULL)
5947                 dladm_get_stats(kcp, ksp, stats);
5948 
5949         (void) kstat_close(kcp);
5950 }
5951 
5952 static int
5953 query_kstat(char *module, int instance, const char *name, const char *stat,
5954     uint8_t type, void *val)
5955 {
5956         kstat_ctl_t     *kcp;
5957         kstat_t         *ksp;
5958 
5959         if ((kcp = kstat_open()) == NULL) {
5960                 warn("kstat open operation failed");
5961                 return (-1);
5962         }
5963 
5964         if ((ksp = kstat_lookup(kcp, module, instance, (char *)name)) == NULL) {
5965                 /*
5966                  * The kstat query could fail if the underlying MAC
5967                  * driver was already detached.
5968                  */
5969                 goto bail;
5970         }
5971 
5972         if (kstat_read(kcp, ksp, NULL) == -1) {
5973                 warn("kstat read failed");
5974                 goto bail;
5975         }
5976 
5977         if (dladm_kstat_value(ksp, stat, type, val) < 0)
5978                 goto bail;
5979 
5980         (void) kstat_close(kcp);
5981         return (0);
5982 
5983 bail:
5984         (void) kstat_close(kcp);
5985         return (-1);
5986 }
5987 
5988 static int
5989 get_one_kstat(const char *name, const char *stat, uint8_t type,
5990     void *val, boolean_t islink)
5991 {
5992         char            module[DLPI_LINKNAME_MAX];
5993         uint_t          instance;
5994 
5995         if (islink) {
5996                 return (query_kstat("link", 0, name, stat, type, val));
5997         } else {
5998                 if (dlpi_parselink(name, module, &instance) != DLPI_SUCCESS)
5999                         return (-1);
6000 
6001                 return (query_kstat(module, instance, "mac", stat, type, val));
6002         }
6003 }
6004 
6005 static uint64_t
6006 get_ifspeed(const char *name, boolean_t islink)
6007 {
6008         uint64_t ifspeed = 0;
6009 
6010         (void) get_one_kstat(name, "ifspeed", KSTAT_DATA_UINT64,
6011             &ifspeed, islink);
6012 
6013         return (ifspeed);
6014 }
6015 
6016 static const char *
6017 get_linkstate(const char *name, boolean_t islink, char *buf)
6018 {
6019         link_state_t    linkstate;
6020 
6021         if (get_one_kstat(name, "link_state", KSTAT_DATA_UINT32,
6022             &linkstate, islink) != 0) {
6023                 (void) strlcpy(buf, "?", DLADM_STRSIZE);
6024                 return (buf);
6025         }
6026         return (dladm_linkstate2str(linkstate, buf));
6027 }
6028 
6029 static const char *
6030 get_linkduplex(const char *name, boolean_t islink, char *buf)
6031 {
6032         link_duplex_t   linkduplex;
6033 
6034         if (get_one_kstat(name, "link_duplex", KSTAT_DATA_UINT32,
6035             &linkduplex, islink) != 0) {
6036                 (void) strlcpy(buf, "unknown", DLADM_STRSIZE);
6037                 return (buf);
6038         }
6039 
6040         return (dladm_linkduplex2str(linkduplex, buf));
6041 }
6042 
6043 static int
6044 parse_wifi_fields(char *str, ofmt_handle_t *ofmt, uint_t cmdtype,
6045     boolean_t parsable)
6046 {
6047         ofmt_field_t    *template, *of;
6048         ofmt_cb_t       *fn;
6049         ofmt_status_t   oferr;
6050 
6051         if (cmdtype == WIFI_CMD_SCAN) {
6052                 template = wifi_common_fields;
6053                 if (str == NULL)
6054                         str = def_scan_wifi_fields;
6055                 if (strcasecmp(str, "all") == 0)
6056                         str = all_scan_wifi_fields;
6057                 fn = print_wlan_attr_cb;
6058         } else if (cmdtype == WIFI_CMD_SHOW) {
6059                 bcopy(wifi_common_fields, &wifi_show_fields[2],
6060                     sizeof (wifi_common_fields));
6061                 template = wifi_show_fields;
6062                 if (str == NULL)
6063                         str = def_show_wifi_fields;
6064                 if (strcasecmp(str, "all") == 0)
6065                         str = all_show_wifi_fields;
6066                 fn = print_link_attr_cb;
6067         } else {
6068                 return (-1);
6069         }
6070 
6071         for (of = template; of->of_name != NULL; of++) {
6072                 if (of->of_cb == NULL)
6073                         of->of_cb = fn;
6074         }
6075 
6076         oferr = ofmt_open(str, template, (parsable ? OFMT_PARSABLE : 0),
6077             0, ofmt);
6078         ofmt_check(oferr, parsable, *ofmt, die, warn);
6079         return (0);
6080 }
6081 
6082 typedef struct print_wifi_state {
6083         char            *ws_link;
6084         boolean_t       ws_parsable;
6085         boolean_t       ws_header;
6086         ofmt_handle_t   ws_ofmt;
6087 } print_wifi_state_t;
6088 
6089 typedef struct  wlan_scan_args_s {
6090         print_wifi_state_t      *ws_state;
6091         void                    *ws_attr;
6092 } wlan_scan_args_t;
6093 
6094 static boolean_t
6095 print_wlan_attr_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
6096 {
6097         wlan_scan_args_t        *w = ofarg->ofmt_cbarg;
6098         print_wifi_state_t      *statep = w->ws_state;
6099         dladm_wlan_attr_t       *attrp = w->ws_attr;
6100         char                    tmpbuf[DLADM_STRSIZE];
6101 
6102         if (ofarg->ofmt_id == 0) {
6103                 (void) strlcpy(buf, (char *)statep->ws_link, bufsize);
6104                 return (B_TRUE);
6105         }
6106 
6107         if ((ofarg->ofmt_id & attrp->wa_valid) == 0)
6108                 return (B_TRUE);
6109 
6110         switch (ofarg->ofmt_id) {
6111         case DLADM_WLAN_ATTR_ESSID:
6112                 (void) dladm_wlan_essid2str(&attrp->wa_essid, tmpbuf);
6113                 break;
6114         case DLADM_WLAN_ATTR_BSSID:
6115                 (void) dladm_wlan_bssid2str(&attrp->wa_bssid, tmpbuf);
6116                 break;
6117         case DLADM_WLAN_ATTR_SECMODE:
6118                 (void) dladm_wlan_secmode2str(&attrp->wa_secmode, tmpbuf);
6119                 break;
6120         case DLADM_WLAN_ATTR_STRENGTH:
6121                 (void) dladm_wlan_strength2str(&attrp->wa_strength, tmpbuf);
6122                 break;
6123         case DLADM_WLAN_ATTR_MODE:
6124                 (void) dladm_wlan_mode2str(&attrp->wa_mode, tmpbuf);
6125                 break;
6126         case DLADM_WLAN_ATTR_SPEED:
6127                 (void) dladm_wlan_speed2str(&attrp->wa_speed, tmpbuf);
6128                 (void) strlcat(tmpbuf, "Mb", sizeof (tmpbuf));
6129                 break;
6130         case DLADM_WLAN_ATTR_AUTH:
6131                 (void) dladm_wlan_auth2str(&attrp->wa_auth, tmpbuf);
6132                 break;
6133         case DLADM_WLAN_ATTR_BSSTYPE:
6134                 (void) dladm_wlan_bsstype2str(&attrp->wa_bsstype, tmpbuf);
6135                 break;
6136         }
6137         (void) strlcpy(buf, tmpbuf, bufsize);
6138 
6139         return (B_TRUE);
6140 }
6141 
6142 static boolean_t
6143 print_scan_results(void *arg, dladm_wlan_attr_t *attrp)
6144 {
6145         print_wifi_state_t      *statep = arg;
6146         wlan_scan_args_t        warg;
6147 
6148         bzero(&warg, sizeof (warg));
6149         warg.ws_state = statep;
6150         warg.ws_attr = attrp;
6151         ofmt_print(statep->ws_ofmt, &warg);
6152         return (B_TRUE);
6153 }
6154 
6155 static int
6156 scan_wifi(dladm_handle_t dh, datalink_id_t linkid, void *arg)
6157 {
6158         print_wifi_state_t      *statep = arg;
6159         dladm_status_t          status;
6160         char                    link[MAXLINKNAMELEN];
6161 
6162         if ((status = dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, link,
6163             sizeof (link))) != DLADM_STATUS_OK) {
6164                 return (DLADM_WALK_CONTINUE);
6165         }
6166 
6167         statep->ws_link = link;
6168         status = dladm_wlan_scan(dh, linkid, statep, print_scan_results);
6169         if (status != DLADM_STATUS_OK)
6170                 die_dlerr(status, "cannot scan link '%s'", statep->ws_link);
6171 
6172         return (DLADM_WALK_CONTINUE);
6173 }
6174 
6175 static boolean_t
6176 print_wifi_status_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
6177 {
6178         static char             tmpbuf[DLADM_STRSIZE];
6179         wlan_scan_args_t        *w = ofarg->ofmt_cbarg;
6180         dladm_wlan_linkattr_t   *attrp = w->ws_attr;
6181 
6182         if ((ofarg->ofmt_id & attrp->la_valid) != 0) {
6183                 (void) dladm_wlan_linkstatus2str(&attrp->la_status, tmpbuf);
6184                 (void) strlcpy(buf, tmpbuf, bufsize);
6185         }
6186         return (B_TRUE);
6187 }
6188 
6189 static boolean_t
6190 print_link_attr_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
6191 {
6192         wlan_scan_args_t        *w = ofarg->ofmt_cbarg, w1;
6193         print_wifi_state_t      *statep = w->ws_state;
6194         dladm_wlan_linkattr_t   *attrp = w->ws_attr;
6195 
6196         bzero(&w1, sizeof (w1));
6197         w1.ws_state = statep;
6198         w1.ws_attr = &attrp->la_wlan_attr;
6199         ofarg->ofmt_cbarg = &w1;
6200         return (print_wlan_attr_cb(ofarg, buf, bufsize));
6201 }
6202 
6203 static int
6204 show_wifi(dladm_handle_t dh, datalink_id_t linkid, void *arg)
6205 {
6206         print_wifi_state_t      *statep = arg;
6207         dladm_wlan_linkattr_t   attr;
6208         dladm_status_t          status;
6209         char                    link[MAXLINKNAMELEN];
6210         wlan_scan_args_t        warg;
6211 
6212         if ((status = dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, link,
6213             sizeof (link))) != DLADM_STATUS_OK) {
6214                 return (DLADM_WALK_CONTINUE);
6215         }
6216 
6217         /* dladm_wlan_get_linkattr() memsets attr with 0 */
6218         status = dladm_wlan_get_linkattr(dh, linkid, &attr);
6219         if (status != DLADM_STATUS_OK)
6220                 die_dlerr(status, "cannot get link attributes for %s", link);
6221 
6222         statep->ws_link = link;
6223 
6224         bzero(&warg, sizeof (warg));
6225         warg.ws_state = statep;
6226         warg.ws_attr = &attr;
6227         ofmt_print(statep->ws_ofmt, &warg);
6228         return (DLADM_WALK_CONTINUE);
6229 }
6230 
6231 static void
6232 do_display_wifi(int argc, char **argv, int cmd, const char *use)
6233 {
6234         int                     option;
6235         char                    *fields_str = NULL;
6236         int             (*callback)(dladm_handle_t, datalink_id_t, void *);
6237         print_wifi_state_t      state;
6238         datalink_id_t           linkid = DATALINK_ALL_LINKID;
6239         dladm_status_t          status;
6240 
6241         if (cmd == WIFI_CMD_SCAN)
6242                 callback = scan_wifi;
6243         else if (cmd == WIFI_CMD_SHOW)
6244                 callback = show_wifi;
6245         else
6246                 return;
6247 
6248         state.ws_parsable = B_FALSE;
6249         state.ws_header = B_TRUE;
6250         opterr = 0;
6251         while ((option = getopt_long(argc, argv, ":o:p",
6252             wifi_longopts, NULL)) != -1) {
6253                 switch (option) {
6254                 case 'o':
6255                         fields_str = optarg;
6256                         break;
6257                 case 'p':
6258                         state.ws_parsable = B_TRUE;
6259                         break;
6260                 default:
6261                         die_opterr(optopt, option, use);
6262                 }
6263         }
6264 
6265         if (state.ws_parsable && fields_str == NULL)
6266                 die("-p requires -o");
6267 
6268         if (state.ws_parsable && strcasecmp(fields_str, "all") == 0)
6269                 die("\"-o all\" is invalid with -p");
6270 
6271         if (optind == (argc - 1)) {
6272                 if ((status = dladm_name2info(handle, argv[optind], &linkid,
6273                     NULL, NULL, NULL)) != DLADM_STATUS_OK) {
6274                         die_dlerr(status, "link %s is not valid", argv[optind]);
6275                 }
6276         } else if (optind != argc) {
6277                 usage();
6278         }
6279 
6280         if (parse_wifi_fields(fields_str, &state.ws_ofmt, cmd,
6281             state.ws_parsable) < 0)
6282                 die("invalid field(s) specified");
6283 
6284         if (linkid == DATALINK_ALL_LINKID) {
6285                 (void) dladm_walk_datalink_id(callback, handle, &state,
6286                     DATALINK_CLASS_PHYS | DATALINK_CLASS_SIMNET,
6287                     DL_WIFI, DLADM_OPT_ACTIVE);
6288         } else {
6289                 (void) (*callback)(handle, linkid, &state);
6290         }
6291         ofmt_close(state.ws_ofmt);
6292 }
6293 
6294 static void
6295 do_scan_wifi(int argc, char **argv, const char *use)
6296 {
6297         do_display_wifi(argc, argv, WIFI_CMD_SCAN, use);
6298 }
6299 
6300 static void
6301 do_show_wifi(int argc, char **argv, const char *use)
6302 {
6303         do_display_wifi(argc, argv, WIFI_CMD_SHOW, use);
6304 }
6305 
6306 typedef struct wlan_count_attr {
6307         uint_t          wc_count;
6308         datalink_id_t   wc_linkid;
6309 } wlan_count_attr_t;
6310 
6311 /* ARGSUSED */
6312 static int
6313 do_count_wlan(dladm_handle_t dh, datalink_id_t linkid, void *arg)
6314 {
6315         wlan_count_attr_t *cp = arg;
6316 
6317         if (cp->wc_count == 0)
6318                 cp->wc_linkid = linkid;
6319         cp->wc_count++;
6320         return (DLADM_WALK_CONTINUE);
6321 }
6322 
6323 static int
6324 parse_wlan_keys(char *str, dladm_wlan_key_t **keys, uint_t *key_countp)
6325 {
6326         uint_t                  i;
6327         dladm_wlan_key_t        *wk;
6328         int                     nfields = 1;
6329         char                    *field, *token, *lasts = NULL, c;
6330 
6331         token = str;
6332         while ((c = *token++) != '\0') {
6333                 if (c == ',')
6334                         nfields++;
6335         }
6336         token = strdup(str);
6337         if (token == NULL)
6338                 return (-1);
6339 
6340         wk = malloc(nfields * sizeof (dladm_wlan_key_t));
6341         if (wk == NULL)
6342                 goto fail;
6343 
6344         token = str;
6345         for (i = 0; i < nfields; i++) {
6346                 char                    *s;
6347                 dladm_secobj_class_t    class;
6348                 dladm_status_t          status;
6349 
6350                 field = strtok_r(token, ",", &lasts);
6351                 token = NULL;
6352 
6353                 (void) strlcpy(wk[i].wk_name, field,
6354                     DLADM_WLAN_MAX_KEYNAME_LEN);
6355 
6356                 wk[i].wk_idx = 1;
6357                 if ((s = strrchr(wk[i].wk_name, ':')) != NULL) {
6358                         if (s[1] == '\0' || s[2] != '\0' || !isdigit(s[1]))
6359                                 goto fail;
6360 
6361                         wk[i].wk_idx = (uint_t)(s[1] - '0');
6362                         *s = '\0';
6363                 }
6364                 wk[i].wk_len = DLADM_WLAN_MAX_KEY_LEN;
6365 
6366                 status = dladm_get_secobj(handle, wk[i].wk_name, &class,
6367                     wk[i].wk_val, &wk[i].wk_len, 0);
6368                 if (status != DLADM_STATUS_OK) {
6369                         if (status == DLADM_STATUS_NOTFOUND) {
6370                                 status = dladm_get_secobj(handle, wk[i].wk_name,
6371                                     &class, wk[i].wk_val, &wk[i].wk_len,
6372                                     DLADM_OPT_PERSIST);
6373                         }
6374                         if (status != DLADM_STATUS_OK)
6375                                 goto fail;
6376                 }
6377                 wk[i].wk_class = class;
6378         }
6379         *keys = wk;
6380         *key_countp = i;
6381         free(token);
6382         return (0);
6383 fail:
6384         free(wk);
6385         free(token);
6386         return (-1);
6387 }
6388 
6389 static void
6390 do_connect_wifi(int argc, char **argv, const char *use)
6391 {
6392         int                     option;
6393         dladm_wlan_attr_t       attr, *attrp;
6394         dladm_status_t          status = DLADM_STATUS_OK;
6395         int                     timeout = DLADM_WLAN_CONNECT_TIMEOUT_DEFAULT;
6396         datalink_id_t           linkid = DATALINK_ALL_LINKID;
6397         dladm_wlan_key_t        *keys = NULL;
6398         uint_t                  key_count = 0;
6399         uint_t                  flags = 0;
6400         dladm_wlan_secmode_t    keysecmode = DLADM_WLAN_SECMODE_NONE;
6401         char                    buf[DLADM_STRSIZE];
6402 
6403         opterr = 0;
6404         (void) memset(&attr, 0, sizeof (attr));
6405         while ((option = getopt_long(argc, argv, ":e:i:a:m:b:s:k:T:c",
6406             wifi_longopts, NULL)) != -1) {
6407                 switch (option) {
6408                 case 'e':
6409                         status = dladm_wlan_str2essid(optarg, &attr.wa_essid);
6410                         if (status != DLADM_STATUS_OK)
6411                                 die("invalid ESSID '%s'", optarg);
6412 
6413                         attr.wa_valid |= DLADM_WLAN_ATTR_ESSID;
6414                         /*
6415                          * Try to connect without doing a scan.
6416                          */
6417                         flags |= DLADM_WLAN_CONNECT_NOSCAN;
6418                         break;
6419                 case 'i':
6420                         status = dladm_wlan_str2bssid(optarg, &attr.wa_bssid);
6421                         if (status != DLADM_STATUS_OK)
6422                                 die("invalid BSSID %s", optarg);
6423 
6424                         attr.wa_valid |= DLADM_WLAN_ATTR_BSSID;
6425                         break;
6426                 case 'a':
6427                         status = dladm_wlan_str2auth(optarg, &attr.wa_auth);
6428                         if (status != DLADM_STATUS_OK)
6429                                 die("invalid authentication mode '%s'", optarg);
6430 
6431                         attr.wa_valid |= DLADM_WLAN_ATTR_AUTH;
6432                         break;
6433                 case 'm':
6434                         status = dladm_wlan_str2mode(optarg, &attr.wa_mode);
6435                         if (status != DLADM_STATUS_OK)
6436                                 die("invalid mode '%s'", optarg);
6437 
6438                         attr.wa_valid |= DLADM_WLAN_ATTR_MODE;
6439                         break;
6440                 case 'b':
6441                         if ((status = dladm_wlan_str2bsstype(optarg,
6442                             &attr.wa_bsstype)) != DLADM_STATUS_OK) {
6443                                 die("invalid bsstype '%s'", optarg);
6444                         }
6445 
6446                         attr.wa_valid |= DLADM_WLAN_ATTR_BSSTYPE;
6447                         break;
6448                 case 's':
6449                         if ((status = dladm_wlan_str2secmode(optarg,
6450                             &attr.wa_secmode)) != DLADM_STATUS_OK) {
6451                                 die("invalid security mode '%s'", optarg);
6452                         }
6453 
6454                         attr.wa_valid |= DLADM_WLAN_ATTR_SECMODE;
6455                         break;
6456                 case 'k':
6457                         if (parse_wlan_keys(optarg, &keys, &key_count) < 0)
6458                                 die("invalid key(s) '%s'", optarg);
6459 
6460                         if (keys[0].wk_class == DLADM_SECOBJ_CLASS_WEP)
6461                                 keysecmode = DLADM_WLAN_SECMODE_WEP;
6462                         else
6463                                 keysecmode = DLADM_WLAN_SECMODE_WPA;
6464                         break;
6465                 case 'T':
6466                         if (strcasecmp(optarg, "forever") == 0) {
6467                                 timeout = -1;
6468                                 break;
6469                         }
6470                         if (!str2int(optarg, &timeout) || timeout < 0)
6471                                 die("invalid timeout value '%s'", optarg);
6472                         break;
6473                 case 'c':
6474                         flags |= DLADM_WLAN_CONNECT_CREATEIBSS;
6475                         flags |= DLADM_WLAN_CONNECT_CREATEIBSS;
6476                         break;
6477                 default:
6478                         die_opterr(optopt, option, use);
6479                         break;
6480                 }
6481         }
6482 
6483         if (keysecmode == DLADM_WLAN_SECMODE_NONE) {
6484                 if ((attr.wa_valid & DLADM_WLAN_ATTR_SECMODE) != 0) {
6485                         die("key required for security mode '%s'",
6486                             dladm_wlan_secmode2str(&attr.wa_secmode, buf));
6487                 }
6488         } else {
6489                 if ((attr.wa_valid & DLADM_WLAN_ATTR_SECMODE) != 0 &&
6490                     attr.wa_secmode != keysecmode)
6491                         die("incompatible -s and -k options");
6492                 attr.wa_valid |= DLADM_WLAN_ATTR_SECMODE;
6493                 attr.wa_secmode = keysecmode;
6494         }
6495 
6496         if (optind == (argc - 1)) {
6497                 if ((status = dladm_name2info(handle, argv[optind], &linkid,
6498                     NULL, NULL, NULL)) != DLADM_STATUS_OK) {
6499                         die_dlerr(status, "link %s is not valid", argv[optind]);
6500                 }
6501         } else if (optind != argc) {
6502                 usage();
6503         }
6504 
6505         if (linkid == DATALINK_ALL_LINKID) {
6506                 wlan_count_attr_t wcattr;
6507 
6508                 wcattr.wc_linkid = DATALINK_INVALID_LINKID;
6509                 wcattr.wc_count = 0;
6510                 (void) dladm_walk_datalink_id(do_count_wlan, handle, &wcattr,
6511                     DATALINK_CLASS_PHYS | DATALINK_CLASS_SIMNET,
6512                     DL_WIFI, DLADM_OPT_ACTIVE);
6513                 if (wcattr.wc_count == 0) {
6514                         die("no wifi links are available");
6515                 } else if (wcattr.wc_count > 1) {
6516                         die("link name is required when more than one wifi "
6517                             "link is available");
6518                 }
6519                 linkid = wcattr.wc_linkid;
6520         }
6521         attrp = (attr.wa_valid == 0) ? NULL : &attr;
6522 again:
6523         if ((status = dladm_wlan_connect(handle, linkid, attrp, timeout, keys,
6524             key_count, flags)) != DLADM_STATUS_OK) {
6525                 if ((flags & DLADM_WLAN_CONNECT_NOSCAN) != 0) {
6526                         /*
6527                          * Try again with scanning and filtering.
6528                          */
6529                         flags &= ~DLADM_WLAN_CONNECT_NOSCAN;
6530                         goto again;
6531                 }
6532 
6533                 if (status == DLADM_STATUS_NOTFOUND) {
6534                         if (attr.wa_valid == 0) {
6535                                 die("no wifi networks are available");
6536                         } else {
6537                                 die("no wifi networks with the specified "
6538                                     "criteria are available");
6539                         }
6540                 }
6541                 die_dlerr(status, "cannot connect");
6542         }
6543         free(keys);
6544 }
6545 
6546 /* ARGSUSED */
6547 static int
6548 do_all_disconnect_wifi(dladm_handle_t dh, datalink_id_t linkid, void *arg)
6549 {
6550         dladm_status_t  status;
6551 
6552         status = dladm_wlan_disconnect(dh, linkid);
6553         if (status != DLADM_STATUS_OK)
6554                 warn_dlerr(status, "cannot disconnect link");
6555 
6556         return (DLADM_WALK_CONTINUE);
6557 }
6558 
6559 static void
6560 do_disconnect_wifi(int argc, char **argv, const char *use)
6561 {
6562         int                     option;
6563         datalink_id_t           linkid = DATALINK_ALL_LINKID;
6564         boolean_t               all_links = B_FALSE;
6565         dladm_status_t          status;
6566         wlan_count_attr_t       wcattr;
6567 
6568         opterr = 0;
6569         while ((option = getopt_long(argc, argv, ":a",
6570             wifi_longopts, NULL)) != -1) {
6571                 switch (option) {
6572                 case 'a':
6573                         all_links = B_TRUE;
6574                         break;
6575                 default:
6576                         die_opterr(optopt, option, use);
6577                         break;
6578                 }
6579         }
6580 
6581         if (optind == (argc - 1)) {
6582                 if ((status = dladm_name2info(handle, argv[optind], &linkid,
6583                     NULL, NULL, NULL)) != DLADM_STATUS_OK) {
6584                         die_dlerr(status, "link %s is not valid", argv[optind]);
6585                 }
6586         } else if (optind != argc) {
6587                 usage();
6588         }
6589 
6590         if (linkid == DATALINK_ALL_LINKID) {
6591                 if (!all_links) {
6592                         wcattr.wc_linkid = linkid;
6593                         wcattr.wc_count = 0;
6594                         (void) dladm_walk_datalink_id(do_count_wlan, handle,
6595                             &wcattr,
6596                             DATALINK_CLASS_PHYS | DATALINK_CLASS_SIMNET,
6597                             DL_WIFI, DLADM_OPT_ACTIVE);
6598                         if (wcattr.wc_count == 0) {
6599                                 die("no wifi links are available");
6600                         } else if (wcattr.wc_count > 1) {
6601                                 die("link name is required when more than "
6602                                     "one wifi link is available");
6603                         }
6604                         linkid = wcattr.wc_linkid;
6605                 } else {
6606                         (void) dladm_walk_datalink_id(do_all_disconnect_wifi,
6607                             handle, NULL,
6608                             DATALINK_CLASS_PHYS | DATALINK_CLASS_SIMNET,
6609                             DL_WIFI, DLADM_OPT_ACTIVE);
6610                         return;
6611                 }
6612         }
6613         status = dladm_wlan_disconnect(handle, linkid);
6614         if (status != DLADM_STATUS_OK)
6615                 die_dlerr(status, "cannot disconnect");
6616 }
6617 
6618 static void
6619 print_linkprop(datalink_id_t linkid, show_linkprop_state_t *statep,
6620     const char *propname, dladm_prop_type_t type, const char *format,
6621     char **pptr)
6622 {
6623         int             i;
6624         char            *ptr, *lim;
6625         char            buf[DLADM_STRSIZE];
6626         char            *unknown = "--", *notsup = "";
6627         char            **propvals = statep->ls_propvals;
6628         uint_t          valcnt = DLADM_MAX_PROP_VALCNT;
6629         dladm_status_t  status;
6630 
6631         status = dladm_get_linkprop(handle, linkid, type, propname, propvals,
6632             &valcnt);
6633         if (status != DLADM_STATUS_OK) {
6634                 if (status == DLADM_STATUS_TEMPONLY) {
6635                         if (type == DLADM_PROP_VAL_MODIFIABLE &&
6636                             statep->ls_persist) {
6637                                 valcnt = 1;
6638                                 propvals = &unknown;
6639                         } else {
6640                                 statep->ls_status = status;
6641                                 statep->ls_retstatus = status;
6642                                 return;
6643                         }
6644                 } else if (status == DLADM_STATUS_NOTSUP ||
6645                     statep->ls_persist) {
6646                         valcnt = 1;
6647                         if (type == DLADM_PROP_VAL_CURRENT ||
6648                             type == DLADM_PROP_VAL_PERM)
6649                                 propvals = &unknown;
6650                         else
6651                                 propvals = &notsup;
6652                 } else if (status == DLADM_STATUS_NOTDEFINED) {
6653                         propvals = &notsup; /* STR_UNDEF_VAL */
6654                 } else {
6655                         if (statep->ls_proplist &&
6656                             statep->ls_status == DLADM_STATUS_OK) {
6657                                 warn_dlerr(status,
6658                                     "cannot get link property '%s' for %s",
6659                                     propname, statep->ls_link);
6660                         }
6661                         statep->ls_status = status;
6662                         statep->ls_retstatus = status;
6663                         return;
6664                 }
6665         }
6666 
6667         statep->ls_status = DLADM_STATUS_OK;
6668 
6669         buf[0] = '\0';
6670         ptr = buf;
6671         lim = buf + DLADM_STRSIZE;
6672         for (i = 0; i < valcnt; i++) {
6673                 if (propvals[i][0] == '\0' && !statep->ls_parsable)
6674                         ptr += snprintf(ptr, lim - ptr, "--,");
6675                 else
6676                         ptr += snprintf(ptr, lim - ptr, "%s,", propvals[i]);
6677                 if (ptr >= lim)
6678                         break;
6679         }
6680         if (valcnt > 0)
6681                 buf[strlen(buf) - 1] = '\0';
6682 
6683         lim = statep->ls_line + MAX_PROP_LINE;
6684         if (statep->ls_parsable) {
6685                 *pptr += snprintf(*pptr, lim - *pptr,
6686                     "%s", buf);
6687         } else {
6688                 *pptr += snprintf(*pptr, lim - *pptr, format, buf);
6689         }
6690 }
6691 
6692 static boolean_t
6693 print_linkprop_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
6694 {
6695         linkprop_args_t         *arg = ofarg->ofmt_cbarg;
6696         char                    *propname = arg->ls_propname;
6697         show_linkprop_state_t   *statep = arg->ls_state;
6698         char                    *ptr = statep->ls_line;
6699         char                    *lim = ptr + MAX_PROP_LINE;
6700         datalink_id_t           linkid = arg->ls_linkid;
6701 
6702         switch (ofarg->ofmt_id) {
6703         case LINKPROP_LINK:
6704                 (void) snprintf(ptr, lim - ptr, "%s", statep->ls_link);
6705                 break;
6706         case LINKPROP_PROPERTY:
6707                 (void) snprintf(ptr, lim - ptr, "%s", propname);
6708                 break;
6709         case LINKPROP_VALUE:
6710                 print_linkprop(linkid, statep, propname,
6711                     statep->ls_persist ? DLADM_PROP_VAL_PERSISTENT :
6712                     DLADM_PROP_VAL_CURRENT, "%s", &ptr);
6713                 /*
6714                  * If we failed to query the link property, for example, query
6715                  * the persistent value of a non-persistable link property,
6716                  * simply skip the output.
6717                  */
6718                 if (statep->ls_status != DLADM_STATUS_OK) {
6719                         /*
6720                          * Ignore the temponly error when we skip printing
6721                          * link properties to avoid returning failure on exit.
6722                          */
6723                         if (statep->ls_retstatus == DLADM_STATUS_TEMPONLY)
6724                                 statep->ls_retstatus = DLADM_STATUS_OK;
6725                         goto skip;
6726                 }
6727                 ptr = statep->ls_line;
6728                 break;
6729         case LINKPROP_PERM:
6730                 print_linkprop(linkid, statep, propname,
6731                     DLADM_PROP_VAL_PERM, "%s", &ptr);
6732                 if (statep->ls_status != DLADM_STATUS_OK)
6733                         goto skip;
6734                 ptr = statep->ls_line;
6735                 break;
6736         case LINKPROP_DEFAULT:
6737                 print_linkprop(linkid, statep, propname,
6738                     DLADM_PROP_VAL_DEFAULT, "%s", &ptr);
6739                 if (statep->ls_status != DLADM_STATUS_OK)
6740                         goto skip;
6741                 ptr = statep->ls_line;
6742                 break;
6743         case LINKPROP_POSSIBLE:
6744                 print_linkprop(linkid, statep, propname,
6745                     DLADM_PROP_VAL_MODIFIABLE, "%s ", &ptr);
6746                 if (statep->ls_status != DLADM_STATUS_OK)
6747                         goto skip;
6748                 ptr = statep->ls_line;
6749                 break;
6750         default:
6751                 die("invalid input");
6752                 break;
6753         }
6754         (void) strlcpy(buf, ptr, bufsize);
6755         return (B_TRUE);
6756 skip:
6757         return ((statep->ls_status == DLADM_STATUS_OK) ?
6758             B_TRUE : B_FALSE);
6759 }
6760 
6761 static boolean_t
6762 linkprop_is_supported(datalink_id_t  linkid, const char *propname,
6763     show_linkprop_state_t *statep)
6764 {
6765         dladm_status_t  status;
6766         uint_t          valcnt = DLADM_MAX_PROP_VALCNT;
6767 
6768         /* if used with -p flag, always print output */
6769         if (statep->ls_proplist != NULL)
6770                 return (B_TRUE);
6771 
6772         status = dladm_get_linkprop(handle, linkid, DLADM_PROP_VAL_DEFAULT,
6773             propname, statep->ls_propvals, &valcnt);
6774 
6775         if (status == DLADM_STATUS_OK)
6776                 return (B_TRUE);
6777 
6778         /*
6779          * A system wide default value is not available for the
6780          * property. Check if current value can be retrieved.
6781          */
6782         status = dladm_get_linkprop(handle, linkid, DLADM_PROP_VAL_CURRENT,
6783             propname, statep->ls_propvals, &valcnt);
6784 
6785         return (status == DLADM_STATUS_OK);
6786 }
6787 
6788 /* ARGSUSED */
6789 static int
6790 show_linkprop(dladm_handle_t dh, datalink_id_t linkid, const char *propname,
6791     void *arg)
6792 {
6793         show_linkprop_state_t   *statep = arg;
6794         linkprop_args_t         ls_arg;
6795 
6796         bzero(&ls_arg, sizeof (ls_arg));
6797         ls_arg.ls_state = statep;
6798         ls_arg.ls_propname = (char *)propname;
6799         ls_arg.ls_linkid = linkid;
6800 
6801         /*
6802          * This will need to be fixed when kernel interfaces are added
6803          * to enable walking of all known private properties. For now,
6804          * we are limited to walking persistent private properties only.
6805          */
6806         if ((propname[0] == '_') && !statep->ls_persist &&
6807             (statep->ls_proplist == NULL))
6808                 return (DLADM_WALK_CONTINUE);
6809         if (!statep->ls_parsable &&
6810             !linkprop_is_supported(linkid, propname, statep))
6811                 return (DLADM_WALK_CONTINUE);
6812 
6813         ofmt_print(statep->ls_ofmt, &ls_arg);
6814 
6815         return (DLADM_WALK_CONTINUE);
6816 }
6817 
6818 static void
6819 do_show_linkprop(int argc, char **argv, const char *use)
6820 {
6821         int                     option;
6822         char                    propstr[DLADM_STRSIZE];
6823         dladm_arg_list_t        *proplist = NULL;
6824         datalink_id_t           linkid = DATALINK_ALL_LINKID;
6825         show_linkprop_state_t   state;
6826         uint32_t                flags = DLADM_OPT_ACTIVE;
6827         dladm_status_t          status;
6828         char                    *fields_str = NULL;
6829         ofmt_handle_t           ofmt;
6830         ofmt_status_t           oferr;
6831         uint_t                  ofmtflags = 0;
6832 
6833         bzero(propstr, DLADM_STRSIZE);
6834         opterr = 0;
6835         state.ls_propvals = NULL;
6836         state.ls_line = NULL;
6837         state.ls_parsable = B_FALSE;
6838         state.ls_persist = B_FALSE;
6839         state.ls_header = B_TRUE;
6840         state.ls_retstatus = DLADM_STATUS_OK;
6841 
6842         while ((option = getopt_long(argc, argv, ":p:cPo:",
6843             prop_longopts, NULL)) != -1) {
6844                 switch (option) {
6845                 case 'p':
6846                         (void) strlcat(propstr, optarg, DLADM_STRSIZE);
6847                         if (strlcat(propstr, ",", DLADM_STRSIZE) >=
6848                             DLADM_STRSIZE)
6849                                 die("property list too long '%s'", propstr);
6850                         break;
6851                 case 'c':
6852                         state.ls_parsable = B_TRUE;
6853                         break;
6854                 case 'P':
6855                         state.ls_persist = B_TRUE;
6856                         flags = DLADM_OPT_PERSIST;
6857                         break;
6858                 case 'o':
6859                         fields_str = optarg;
6860                         break;
6861                 default:
6862                         die_opterr(optopt, option, use);
6863                         break;
6864                 }
6865         }
6866 
6867         if (optind == (argc - 1)) {
6868                 if ((status = dladm_name2info(handle, argv[optind], &linkid,
6869                     NULL, NULL, NULL)) != DLADM_STATUS_OK) {
6870                         die_dlerr(status, "link %s is not valid", argv[optind]);
6871                 }
6872         } else if (optind != argc) {
6873                 usage();
6874         }
6875 
6876         if (dladm_parse_link_props(propstr, &proplist, B_TRUE)
6877             != DLADM_STATUS_OK)
6878                 die("invalid link properties specified");
6879         state.ls_proplist = proplist;
6880         state.ls_status = DLADM_STATUS_OK;
6881 
6882         if (state.ls_parsable)
6883                 ofmtflags |= OFMT_PARSABLE;
6884         else
6885                 ofmtflags |= OFMT_WRAP;
6886 
6887         oferr = ofmt_open(fields_str, linkprop_fields, ofmtflags, 0, &ofmt);
6888         ofmt_check(oferr, state.ls_parsable, ofmt, die, warn);
6889         state.ls_ofmt = ofmt;
6890 
6891         if (linkid == DATALINK_ALL_LINKID) {
6892                 (void) dladm_walk_datalink_id(show_linkprop_onelink, handle,
6893                     &state, DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE, flags);
6894         } else {
6895                 (void) show_linkprop_onelink(handle, linkid, &state);
6896         }
6897         ofmt_close(ofmt);
6898         dladm_free_props(proplist);
6899 
6900         if (state.ls_retstatus != DLADM_STATUS_OK) {
6901                 dladm_close(handle);
6902                 exit(EXIT_FAILURE);
6903         }
6904 }
6905 
6906 static int
6907 show_linkprop_onelink(dladm_handle_t hdl, datalink_id_t linkid, void *arg)
6908 {
6909         int                     i;
6910         char                    *buf;
6911         uint32_t                flags;
6912         dladm_arg_list_t        *proplist = NULL;
6913         show_linkprop_state_t   *statep = arg;
6914         dlpi_handle_t           dh = NULL;
6915 
6916         statep->ls_status = DLADM_STATUS_OK;
6917 
6918         if (dladm_datalink_id2info(hdl, linkid, &flags, NULL, NULL,
6919             statep->ls_link, MAXLINKNAMELEN) != DLADM_STATUS_OK) {
6920                 statep->ls_status = DLADM_STATUS_NOTFOUND;
6921                 return (DLADM_WALK_CONTINUE);
6922         }
6923 
6924         if ((statep->ls_persist && !(flags & DLADM_OPT_PERSIST)) ||
6925             (!statep->ls_persist && !(flags & DLADM_OPT_ACTIVE))) {
6926                 statep->ls_status = DLADM_STATUS_BADARG;
6927                 return (DLADM_WALK_CONTINUE);
6928         }
6929 
6930         proplist = statep->ls_proplist;
6931 
6932         /*
6933          * When some WiFi links are opened for the first time, their hardware
6934          * automatically scans for APs and does other slow operations.  Thus,
6935          * if there are no open links, the retrieval of link properties
6936          * (below) will proceed slowly unless we hold the link open.
6937          *
6938          * Note that failure of dlpi_open() does not necessarily mean invalid
6939          * link properties, because dlpi_open() may fail because of incorrect
6940          * autopush configuration. Therefore, we ingore the return value of
6941          * dlpi_open().
6942          */
6943         if (!statep->ls_persist)
6944                 (void) dlpi_open(statep->ls_link, &dh, 0);
6945 
6946         buf = malloc((sizeof (char *) + DLADM_PROP_VAL_MAX) *
6947             DLADM_MAX_PROP_VALCNT + MAX_PROP_LINE);
6948         if (buf == NULL)
6949                 die("insufficient memory");
6950 
6951         statep->ls_propvals = (char **)(void *)buf;
6952         for (i = 0; i < DLADM_MAX_PROP_VALCNT; i++) {
6953                 statep->ls_propvals[i] = buf +
6954                     sizeof (char *) * DLADM_MAX_PROP_VALCNT +
6955                     i * DLADM_PROP_VAL_MAX;
6956         }
6957         statep->ls_line = buf +
6958             (sizeof (char *) + DLADM_PROP_VAL_MAX) * DLADM_MAX_PROP_VALCNT;
6959 
6960         if (proplist != NULL) {
6961                 for (i = 0; i < proplist->al_count; i++) {
6962                         (void) show_linkprop(hdl, linkid,
6963                             proplist->al_info[i].ai_name, statep);
6964                 }
6965         } else {
6966                 (void) dladm_walk_linkprop(hdl, linkid, statep,
6967                     show_linkprop);
6968         }
6969         if (dh != NULL)
6970                 dlpi_close(dh);
6971         free(buf);
6972         return (DLADM_WALK_CONTINUE);
6973 }
6974 
6975 static int
6976 reset_one_linkprop(dladm_handle_t dh, datalink_id_t linkid,
6977     const char *propname, void *arg)
6978 {
6979         set_linkprop_state_t    *statep = arg;
6980         dladm_status_t          status;
6981 
6982         status = dladm_set_linkprop(dh, linkid, propname, NULL, 0,
6983             DLADM_OPT_ACTIVE | (statep->ls_temp ? 0 : DLADM_OPT_PERSIST));
6984         if (status != DLADM_STATUS_OK &&
6985             status != DLADM_STATUS_PROPRDONLY &&
6986             status != DLADM_STATUS_NOTSUP) {
6987                 warn_dlerr(status, "cannot reset link property '%s' on '%s'",
6988                     propname, statep->ls_name);
6989                 statep->ls_status = status;
6990         }
6991 
6992         return (DLADM_WALK_CONTINUE);
6993 }
6994 
6995 static void
6996 set_linkprop(int argc, char **argv, boolean_t reset, const char *use)
6997 {
6998         int                     i, option;
6999         char                    errmsg[DLADM_STRSIZE];
7000         char                    *altroot = NULL;
7001         datalink_id_t           linkid;
7002         boolean_t               temp = B_FALSE;
7003         dladm_status_t          status = DLADM_STATUS_OK;
7004         char                    propstr[DLADM_STRSIZE];
7005         dladm_arg_list_t        *proplist = NULL;
7006 
7007         opterr = 0;
7008         bzero(propstr, DLADM_STRSIZE);
7009 
7010         while ((option = getopt_long(argc, argv, ":p:R:t",
7011             prop_longopts, NULL)) != -1) {
7012                 switch (option) {
7013                 case 'p':
7014                         (void) strlcat(propstr, optarg, DLADM_STRSIZE);
7015                         if (strlcat(propstr, ",", DLADM_STRSIZE) >=
7016                             DLADM_STRSIZE)
7017                                 die("property list too long '%s'", propstr);
7018                         break;
7019                 case 't':
7020                         temp = B_TRUE;
7021                         break;
7022                 case 'R':
7023                         altroot = optarg;
7024                         break;
7025                 default:
7026                         die_opterr(optopt, option, use);
7027 
7028                 }
7029         }
7030 
7031         /* get link name (required last argument) */
7032         if (optind != (argc - 1))
7033                 usage();
7034 
7035         if (dladm_parse_link_props(propstr, &proplist, reset) !=
7036             DLADM_STATUS_OK)
7037                 die("invalid link properties specified");
7038 
7039         if (proplist == NULL && !reset)
7040                 die("link property must be specified");
7041 
7042         if (altroot != NULL) {
7043                 dladm_free_props(proplist);
7044                 altroot_cmd(altroot, argc, argv);
7045         }
7046 
7047         status = dladm_name2info(handle, argv[optind], &linkid, NULL, NULL,
7048             NULL);
7049         if (status != DLADM_STATUS_OK)
7050                 die_dlerr(status, "link %s is not valid", argv[optind]);
7051 
7052         if (proplist == NULL) {
7053                 set_linkprop_state_t    state;
7054 
7055                 state.ls_name = argv[optind];
7056                 state.ls_reset = reset;
7057                 state.ls_temp = temp;
7058                 state.ls_status = DLADM_STATUS_OK;
7059 
7060                 (void) dladm_walk_linkprop(handle, linkid, &state,
7061                     reset_one_linkprop);
7062 
7063                 status = state.ls_status;
7064                 goto done;
7065         }
7066 
7067         for (i = 0; i < proplist->al_count; i++) {
7068                 dladm_arg_info_t        *aip = &proplist->al_info[i];
7069                 char            **val;
7070                 uint_t          count;
7071 
7072                 if (reset) {
7073                         val = NULL;
7074                         count = 0;
7075                 } else {
7076                         val = aip->ai_val;
7077                         count = aip->ai_count;
7078                         if (count == 0) {
7079                                 warn("no value specified for '%s'",
7080                                     aip->ai_name);
7081                                 status = DLADM_STATUS_BADARG;
7082                                 continue;
7083                         }
7084                 }
7085                 status = dladm_set_linkprop(handle, linkid, aip->ai_name, val,
7086                     count, DLADM_OPT_ACTIVE | (temp ? 0 : DLADM_OPT_PERSIST));
7087                 switch (status) {
7088                 case DLADM_STATUS_OK:
7089                         break;
7090                 case DLADM_STATUS_NOTFOUND:
7091                         warn("invalid link property '%s'", aip->ai_name);
7092                         break;
7093                 case DLADM_STATUS_BADVAL: {
7094                         int             j;
7095                         char            *ptr, *lim;
7096                         char            **propvals = NULL;
7097                         uint_t          valcnt = DLADM_MAX_PROP_VALCNT;
7098                         dladm_status_t  s;
7099 
7100                         ptr = malloc((sizeof (char *) +
7101                             DLADM_PROP_VAL_MAX) * DLADM_MAX_PROP_VALCNT +
7102                             MAX_PROP_LINE);
7103 
7104                         propvals = (char **)(void *)ptr;
7105                         if (propvals == NULL)
7106                                 die("insufficient memory");
7107 
7108                         for (j = 0; j < DLADM_MAX_PROP_VALCNT; j++) {
7109                                 propvals[j] = ptr + sizeof (char *) *
7110                                     DLADM_MAX_PROP_VALCNT +
7111                                     j * DLADM_PROP_VAL_MAX;
7112                         }
7113                         s = dladm_get_linkprop(handle, linkid,
7114                             DLADM_PROP_VAL_MODIFIABLE, aip->ai_name, propvals,
7115                             &valcnt);
7116 
7117                         if (s != DLADM_STATUS_OK) {
7118                                 warn_dlerr(status, "cannot set link property "
7119                                     "'%s' on '%s'", aip->ai_name, argv[optind]);
7120                                 free(propvals);
7121                                 break;
7122                         }
7123 
7124                         ptr = errmsg;
7125                         lim = ptr + DLADM_STRSIZE;
7126                         *ptr = '\0';
7127                         for (j = 0; j < valcnt; j++) {
7128                                 ptr += snprintf(ptr, lim - ptr, "%s,",
7129                                     propvals[j]);
7130                                 if (ptr >= lim)
7131                                         break;
7132                         }
7133                         if (ptr > errmsg) {
7134                                 *(ptr - 1) = '\0';
7135                                 warn("link property '%s' must be one of: %s",
7136                                     aip->ai_name, errmsg);
7137                         } else
7138                                 warn("invalid link property '%s'", *val);
7139                         free(propvals);
7140                         break;
7141                 }
7142                 default:
7143                         if (reset) {
7144                                 warn_dlerr(status, "cannot reset link property "
7145                                     "'%s' on '%s'", aip->ai_name, argv[optind]);
7146                         } else {
7147                                 warn_dlerr(status, "cannot set link property "
7148                                     "'%s' on '%s'", aip->ai_name, argv[optind]);
7149                         }
7150                         break;
7151                 }
7152         }
7153 done:
7154         dladm_free_props(proplist);
7155         if (status != DLADM_STATUS_OK) {
7156                 dladm_close(handle);
7157                 exit(EXIT_FAILURE);
7158         }
7159 }
7160 
7161 static void
7162 do_set_linkprop(int argc, char **argv, const char *use)
7163 {
7164         set_linkprop(argc, argv, B_FALSE, use);
7165 }
7166 
7167 static void
7168 do_reset_linkprop(int argc, char **argv, const char *use)
7169 {
7170         set_linkprop(argc, argv, B_TRUE, use);
7171 }
7172 
7173 static int
7174 convert_secobj(char *buf, uint_t len, uint8_t *obj_val, uint_t *obj_lenp,
7175     dladm_secobj_class_t class)
7176 {
7177         int error = 0;
7178 
7179         if (class == DLADM_SECOBJ_CLASS_WPA) {
7180                 if (len < 8 || len > 63)
7181                         return (EINVAL);
7182                 (void) memcpy(obj_val, buf, len);
7183                 *obj_lenp = len;
7184                 return (error);
7185         }
7186 
7187         if (class == DLADM_SECOBJ_CLASS_WEP) {
7188                 switch (len) {
7189                 case 5:                 /* ASCII key sizes */
7190                 case 13:
7191                         (void) memcpy(obj_val, buf, len);
7192                         *obj_lenp = len;
7193                         break;
7194                 case 10:                /* Hex key sizes, not preceded by 0x */
7195                 case 26:
7196                         error = hexascii_to_octet(buf, len, obj_val, obj_lenp);
7197                         break;
7198                 case 12:                /* Hex key sizes, preceded by 0x */
7199                 case 28:
7200                         if (strncmp(buf, "0x", 2) != 0)
7201                                 return (EINVAL);
7202                         error = hexascii_to_octet(buf + 2, len - 2,
7203                             obj_val, obj_lenp);
7204                         break;
7205                 default:
7206                         return (EINVAL);
7207                 }
7208                 return (error);
7209         }
7210 
7211         return (ENOENT);
7212 }
7213 
7214 static void
7215 defersig(int sig)
7216 {
7217         signalled = sig;
7218 }
7219 
7220 static int
7221 get_secobj_from_tty(uint_t try, const char *objname, char *buf)
7222 {
7223         uint_t          len = 0;
7224         int             c;
7225         struct termios  stored, current;
7226         void            (*sigfunc)(int);
7227 
7228         /*
7229          * Turn off echo -- but before we do so, defer SIGINT handling
7230          * so that a ^C doesn't leave the terminal corrupted.
7231          */
7232         sigfunc = signal(SIGINT, defersig);
7233         (void) fflush(stdin);
7234         (void) tcgetattr(0, &stored);
7235         current = stored;
7236         current.c_lflag &= ~(ICANON|ECHO);
7237         current.c_cc[VTIME] = 0;
7238         current.c_cc[VMIN] = 1;
7239         (void) tcsetattr(0, TCSANOW, &current);
7240 again:
7241         if (try == 1)
7242                 (void) printf(gettext("provide value for '%s': "), objname);
7243         else
7244                 (void) printf(gettext("confirm value for '%s': "), objname);
7245 
7246         (void) fflush(stdout);
7247         while (signalled == 0) {
7248                 c = getchar();
7249                 if (c == '\n' || c == '\r') {
7250                         if (len != 0)
7251                                 break;
7252                         (void) putchar('\n');
7253                         goto again;
7254                 }
7255 
7256                 buf[len++] = c;
7257                 if (len >= DLADM_SECOBJ_VAL_MAX - 1)
7258                         break;
7259                 (void) putchar('*');
7260         }
7261 
7262         (void) putchar('\n');
7263         (void) fflush(stdin);
7264 
7265         /*
7266          * Restore terminal setting and handle deferred signals.
7267          */
7268         (void) tcsetattr(0, TCSANOW, &stored);
7269 
7270         (void) signal(SIGINT, sigfunc);
7271         if (signalled != 0)
7272                 (void) kill(getpid(), signalled);
7273 
7274         return (len);
7275 }
7276 
7277 static int
7278 get_secobj_val(char *obj_name, uint8_t *obj_val, uint_t *obj_lenp,
7279     dladm_secobj_class_t class, FILE *filep)
7280 {
7281         int             rval;
7282         uint_t          len, len2;
7283         char            buf[DLADM_SECOBJ_VAL_MAX], buf2[DLADM_SECOBJ_VAL_MAX];
7284 
7285         if (filep == NULL) {
7286                 len = get_secobj_from_tty(1, obj_name, buf);
7287                 rval = convert_secobj(buf, len, obj_val, obj_lenp, class);
7288                 if (rval == 0) {
7289                         len2 = get_secobj_from_tty(2, obj_name, buf2);
7290                         if (len != len2 || memcmp(buf, buf2, len) != 0)
7291                                 rval = ENOTSUP;
7292                 }
7293                 return (rval);
7294         } else {
7295                 for (;;) {
7296                         if (fgets(buf, sizeof (buf), filep) == NULL)
7297                                 break;
7298                         if (isspace(buf[0]))
7299                                 continue;
7300 
7301                         len = strlen(buf);
7302                         if (buf[len - 1] == '\n') {
7303                                 buf[len - 1] = '\0';
7304                                 len--;
7305                         }
7306                         break;
7307                 }
7308                 (void) fclose(filep);
7309         }
7310         return (convert_secobj(buf, len, obj_val, obj_lenp, class));
7311 }
7312 
7313 static boolean_t
7314 check_auth(const char *auth)
7315 {
7316         struct passwd   *pw;
7317 
7318         if ((pw = getpwuid(getuid())) == NULL)
7319                 return (B_FALSE);
7320 
7321         return (chkauthattr(auth, pw->pw_name) != 0);
7322 }
7323 
7324 static void
7325 audit_secobj(char *auth, char *class, char *obj,
7326     boolean_t success, boolean_t create)
7327 {
7328         adt_session_data_t      *ah;
7329         adt_event_data_t        *event;
7330         au_event_t              flag;
7331         char                    *errstr;
7332 
7333         if (create) {
7334                 flag = ADT_dladm_create_secobj;
7335                 errstr = "ADT_dladm_create_secobj";
7336         } else {
7337                 flag = ADT_dladm_delete_secobj;
7338                 errstr = "ADT_dladm_delete_secobj";
7339         }
7340 
7341         if (adt_start_session(&ah, NULL, ADT_USE_PROC_DATA) != 0)
7342                 die("adt_start_session: %s", strerror(errno));
7343 
7344         if ((event = adt_alloc_event(ah, flag)) == NULL)
7345                 die("adt_alloc_event (%s): %s", errstr, strerror(errno));
7346 
7347         /* fill in audit info */
7348         if (create) {
7349                 event->adt_dladm_create_secobj.auth_used = auth;
7350                 event->adt_dladm_create_secobj.obj_class = class;
7351                 event->adt_dladm_create_secobj.obj_name = obj;
7352         } else {
7353                 event->adt_dladm_delete_secobj.auth_used = auth;
7354                 event->adt_dladm_delete_secobj.obj_class = class;
7355                 event->adt_dladm_delete_secobj.obj_name = obj;
7356         }
7357 
7358         if (success) {
7359                 if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS) != 0) {
7360                         die("adt_put_event (%s, success): %s", errstr,
7361                             strerror(errno));
7362                 }
7363         } else {
7364                 if (adt_put_event(event, ADT_FAILURE,
7365                     ADT_FAIL_VALUE_AUTH) != 0) {
7366                         die("adt_put_event: (%s, failure): %s", errstr,
7367                             strerror(errno));
7368                 }
7369         }
7370 
7371         adt_free_event(event);
7372         (void) adt_end_session(ah);
7373 }
7374 
7375 static void
7376 do_create_secobj(int argc, char **argv, const char *use)
7377 {
7378         int                     option, rval;
7379         FILE                    *filep = NULL;
7380         char                    *obj_name = NULL;
7381         char                    *class_name = NULL;
7382         uint8_t                 obj_val[DLADM_SECOBJ_VAL_MAX];
7383         uint_t                  obj_len;
7384         boolean_t               success, temp = B_FALSE;
7385         dladm_status_t          status;
7386         dladm_secobj_class_t    class = -1;
7387         uid_t                   euid;
7388 
7389         opterr = 0;
7390         (void) memset(obj_val, 0, DLADM_SECOBJ_VAL_MAX);
7391         while ((option = getopt_long(argc, argv, ":f:c:R:t",
7392             wifi_longopts, NULL)) != -1) {
7393                 switch (option) {
7394                 case 'f':
7395                         euid = geteuid();
7396                         (void) seteuid(getuid());
7397                         filep = fopen(optarg, "r");
7398                         if (filep == NULL) {
7399                                 die("cannot open %s: %s", optarg,
7400                                     strerror(errno));
7401                         }
7402                         (void) seteuid(euid);
7403                         break;
7404                 case 'c':
7405                         class_name = optarg;
7406                         status = dladm_str2secobjclass(optarg, &class);
7407                         if (status != DLADM_STATUS_OK) {
7408                                 die("invalid secure object class '%s', "
7409                                     "valid values are: wep, wpa", optarg);
7410                         }
7411                         break;
7412                 case 't':
7413                         temp = B_TRUE;
7414                         break;
7415                 case 'R':
7416                         status = dladm_set_rootdir(optarg);
7417                         if (status != DLADM_STATUS_OK) {
7418                                 die_dlerr(status, "invalid directory "
7419                                     "specified");
7420                         }
7421                         break;
7422                 default:
7423                         die_opterr(optopt, option, use);
7424                         break;
7425                 }
7426         }
7427 
7428         if (optind == (argc - 1))
7429                 obj_name = argv[optind];
7430         else if (optind != argc)
7431                 usage();
7432 
7433         if (class == -1)
7434                 die("secure object class required");
7435 
7436         if (obj_name == NULL)
7437                 die("secure object name required");
7438 
7439         if (!dladm_valid_secobj_name(obj_name))
7440                 die("invalid secure object name '%s'", obj_name);
7441 
7442         success = check_auth(LINK_SEC_AUTH);
7443         audit_secobj(LINK_SEC_AUTH, class_name, obj_name, success, B_TRUE);
7444         if (!success)
7445                 die("authorization '%s' is required", LINK_SEC_AUTH);
7446 
7447         rval = get_secobj_val(obj_name, obj_val, &obj_len, class, filep);
7448         if (rval != 0) {
7449                 switch (rval) {
7450                 case ENOENT:
7451                         die("invalid secure object class");
7452                         break;
7453                 case EINVAL:
7454                         die("invalid secure object value");
7455                         break;
7456                 case ENOTSUP:
7457                         die("verification failed");
7458                         break;
7459                 default:
7460                         die("invalid secure object: %s", strerror(rval));
7461                         break;
7462                 }
7463         }
7464 
7465         status = dladm_set_secobj(handle, obj_name, class, obj_val, obj_len,
7466             DLADM_OPT_CREATE | DLADM_OPT_ACTIVE);
7467         if (status != DLADM_STATUS_OK) {
7468                 die_dlerr(status, "could not create secure object '%s'",
7469                     obj_name);
7470         }
7471         if (temp)
7472                 return;
7473 
7474         status = dladm_set_secobj(handle, obj_name, class, obj_val, obj_len,
7475             DLADM_OPT_PERSIST);
7476         if (status != DLADM_STATUS_OK) {
7477                 warn_dlerr(status, "could not persistently create secure "
7478                     "object '%s'", obj_name);
7479         }
7480 }
7481 
7482 static void
7483 do_delete_secobj(int argc, char **argv, const char *use)
7484 {
7485         int             i, option;
7486         boolean_t       temp = B_FALSE;
7487         boolean_t       success;
7488         dladm_status_t  status, pstatus;
7489         int             nfields = 1;
7490         char            *field, *token, *lasts = NULL, c;
7491 
7492         opterr = 0;
7493         status = pstatus = DLADM_STATUS_OK;
7494         while ((option = getopt_long(argc, argv, ":R:t",
7495             wifi_longopts, NULL)) != -1) {
7496                 switch (option) {
7497                 case 't':
7498                         temp = B_TRUE;
7499                         break;
7500                 case 'R':
7501                         status = dladm_set_rootdir(optarg);
7502                         if (status != DLADM_STATUS_OK) {
7503                                 die_dlerr(status, "invalid directory "
7504                                     "specified");
7505                         }
7506                         break;
7507                 default:
7508                         die_opterr(optopt, option, use);
7509                         break;
7510                 }
7511         }
7512 
7513         if (optind != (argc - 1))
7514                 die("secure object name required");
7515 
7516         token = argv[optind];
7517         while ((c = *token++) != '\0') {
7518                 if (c == ',')
7519                         nfields++;
7520         }
7521         token = strdup(argv[optind]);
7522         if (token == NULL)
7523                 die("no memory");
7524 
7525         success = check_auth(LINK_SEC_AUTH);
7526         audit_secobj(LINK_SEC_AUTH, "unknown", argv[optind], success, B_FALSE);
7527         if (!success)
7528                 die("authorization '%s' is required", LINK_SEC_AUTH);
7529 
7530         for (i = 0; i < nfields; i++) {
7531 
7532                 field = strtok_r(token, ",", &lasts);
7533                 token = NULL;
7534                 status = dladm_unset_secobj(handle, field, DLADM_OPT_ACTIVE);
7535                 if (!temp) {
7536                         pstatus = dladm_unset_secobj(handle, field,
7537                             DLADM_OPT_PERSIST);
7538                 } else {
7539                         pstatus = DLADM_STATUS_OK;
7540                 }
7541 
7542                 if (status != DLADM_STATUS_OK) {
7543                         warn_dlerr(status, "could not delete secure object "
7544                             "'%s'", field);
7545                 }
7546                 if (pstatus != DLADM_STATUS_OK) {
7547                         warn_dlerr(pstatus, "could not persistently delete "
7548                             "secure object '%s'", field);
7549                 }
7550         }
7551         free(token);
7552 
7553         if (status != DLADM_STATUS_OK || pstatus != DLADM_STATUS_OK) {
7554                 dladm_close(handle);
7555                 exit(EXIT_FAILURE);
7556         }
7557 }
7558 
7559 typedef struct show_secobj_state {
7560         boolean_t       ss_persist;
7561         boolean_t       ss_parsable;
7562         boolean_t       ss_header;
7563         ofmt_handle_t   ss_ofmt;
7564 } show_secobj_state_t;
7565 
7566 
7567 static boolean_t
7568 show_secobj(dladm_handle_t dh, void *arg, const char *obj_name)
7569 {
7570         uint_t                  obj_len = DLADM_SECOBJ_VAL_MAX;
7571         uint8_t                 obj_val[DLADM_SECOBJ_VAL_MAX];
7572         char                    buf[DLADM_STRSIZE];
7573         uint_t                  flags = 0;
7574         dladm_secobj_class_t    class;
7575         show_secobj_state_t     *statep = arg;
7576         dladm_status_t          status;
7577         secobj_fields_buf_t     sbuf;
7578 
7579         bzero(&sbuf, sizeof (secobj_fields_buf_t));
7580         if (statep->ss_persist)
7581                 flags |= DLADM_OPT_PERSIST;
7582 
7583         status = dladm_get_secobj(dh, obj_name, &class, obj_val, &obj_len,
7584             flags);
7585         if (status != DLADM_STATUS_OK)
7586                 die_dlerr(status, "cannot get secure object '%s'", obj_name);
7587 
7588         (void) snprintf(sbuf.ss_obj_name, sizeof (sbuf.ss_obj_name),
7589             obj_name);
7590         (void) dladm_secobjclass2str(class, buf);
7591         (void) snprintf(sbuf.ss_class, sizeof (sbuf.ss_class), "%s", buf);
7592         if (getuid() == 0) {
7593                 char    val[DLADM_SECOBJ_VAL_MAX * 2];
7594                 uint_t  len = sizeof (val);
7595 
7596                 if (octet_to_hexascii(obj_val, obj_len, val, &len) == 0)
7597                         (void) snprintf(sbuf.ss_val,
7598                             sizeof (sbuf.ss_val), "%s", val);
7599         }
7600         ofmt_print(statep->ss_ofmt, &sbuf);
7601         return (B_TRUE);
7602 }
7603 
7604 static void
7605 do_show_secobj(int argc, char **argv, const char *use)
7606 {
7607         int                     option;
7608         show_secobj_state_t     state;
7609         dladm_status_t          status;
7610         boolean_t               o_arg = B_FALSE;
7611         uint_t                  i;
7612         uint_t                  flags;
7613         char                    *fields_str = NULL;
7614         char                    *def_fields = "object,class";
7615         char                    *all_fields = "object,class,value";
7616         char                    *field, *token, *lasts = NULL, c;
7617         ofmt_handle_t           ofmt;
7618         ofmt_status_t           oferr;
7619         uint_t                  ofmtflags = 0;
7620 
7621         opterr = 0;
7622         bzero(&state, sizeof (state));
7623         state.ss_parsable = B_FALSE;
7624         fields_str = def_fields;
7625         state.ss_persist = B_FALSE;
7626         state.ss_parsable = B_FALSE;
7627         state.ss_header = B_TRUE;
7628         while ((option = getopt_long(argc, argv, ":pPo:",
7629             wifi_longopts, NULL)) != -1) {
7630                 switch (option) {
7631                 case 'p':
7632                         state.ss_parsable = B_TRUE;
7633                         break;
7634                 case 'P':
7635                         state.ss_persist = B_TRUE;
7636                         break;
7637                 case 'o':
7638                         o_arg = B_TRUE;
7639                         if (strcasecmp(optarg, "all") == 0)
7640                                 fields_str = all_fields;
7641                         else
7642                                 fields_str = optarg;
7643                         break;
7644                 default:
7645                         die_opterr(optopt, option, use);
7646                         break;
7647                 }
7648         }
7649 
7650         if (state.ss_parsable && !o_arg)
7651                 die("option -c requires -o");
7652 
7653         if (state.ss_parsable && fields_str == all_fields)
7654                 die("\"-o all\" is invalid with -p");
7655 
7656         if (state.ss_parsable)
7657                 ofmtflags |= OFMT_PARSABLE;
7658         oferr = ofmt_open(fields_str, secobj_fields, ofmtflags, 0, &ofmt);
7659         ofmt_check(oferr, state.ss_parsable, ofmt, die, warn);
7660         state.ss_ofmt = ofmt;
7661 
7662         flags = state.ss_persist ? DLADM_OPT_PERSIST : 0;
7663 
7664         if (optind == (argc - 1)) {
7665                 uint_t obj_fields = 1;
7666 
7667                 token = argv[optind];
7668                 if (token == NULL)
7669                         die("secure object name required");
7670                 while ((c = *token++) != '\0') {
7671                         if (c == ',')
7672                                 obj_fields++;
7673                 }
7674                 token = strdup(argv[optind]);
7675                 if (token == NULL)
7676                         die("no memory");
7677                 for (i = 0; i < obj_fields; i++) {
7678                         field = strtok_r(token, ",", &lasts);
7679                         token = NULL;
7680                         if (!show_secobj(handle, &state, field))
7681                                 break;
7682                 }
7683                 free(token);
7684                 ofmt_close(ofmt);
7685                 return;
7686         } else if (optind != argc)
7687                 usage();
7688 
7689         status = dladm_walk_secobj(handle, &state, show_secobj, flags);
7690 
7691         if (status != DLADM_STATUS_OK)
7692                 die_dlerr(status, "show-secobj");
7693         ofmt_close(ofmt);
7694 }
7695 
7696 /*ARGSUSED*/
7697 static int
7698 i_dladm_init_linkprop(dladm_handle_t dh, datalink_id_t linkid, void *arg)
7699 {
7700         (void) dladm_init_linkprop(dh, linkid, B_TRUE);
7701         return (DLADM_WALK_CONTINUE);
7702 }
7703 
7704 /*ARGSUSED*/
7705 void
7706 do_init_linkprop(int argc, char **argv, const char *use)
7707 {
7708         int                     option;
7709         dladm_status_t          status;
7710         datalink_id_t           linkid = DATALINK_ALL_LINKID;
7711         datalink_media_t        media = DATALINK_ANY_MEDIATYPE;
7712         uint_t                  any_media = B_TRUE;
7713 
7714         opterr = 0;
7715         while ((option = getopt(argc, argv, ":w")) != -1) {
7716                 switch (option) {
7717                 case 'w':
7718                         media = DL_WIFI;
7719                         any_media = B_FALSE;
7720                         break;
7721                 default:
7722                         /*
7723                          * Because init-linkprop is not a public command,
7724                          * print the usage instead.
7725                          */
7726                         usage();
7727                         break;
7728                 }
7729         }
7730 
7731         if (optind == (argc - 1)) {
7732                 if ((status = dladm_name2info(handle, argv[optind], &linkid,
7733                     NULL, NULL, NULL)) != DLADM_STATUS_OK)
7734                         die_dlerr(status, "link %s is not valid", argv[optind]);
7735         } else if (optind != argc) {
7736                 usage();
7737         }
7738 
7739         if (linkid == DATALINK_ALL_LINKID) {
7740                 /*
7741                  * linkprops of links of other classes have been initialized as
7742                  * part of the dladm up-xxx operation.
7743                  */
7744                 (void) dladm_walk_datalink_id(i_dladm_init_linkprop, handle,
7745                     NULL, DATALINK_CLASS_PHYS, media, DLADM_OPT_PERSIST);
7746         } else {
7747                 (void) dladm_init_linkprop(handle, linkid, any_media);
7748         }
7749 }
7750 
7751 static void
7752 do_show_ether(int argc, char **argv, const char *use)
7753 {
7754         int                     option;
7755         datalink_id_t           linkid;
7756         print_ether_state_t     state;
7757         char                    *fields_str = NULL;
7758         ofmt_handle_t           ofmt;
7759         ofmt_status_t           oferr;
7760         uint_t                  ofmtflags = 0;
7761 
7762         bzero(&state, sizeof (state));
7763         state.es_link = NULL;
7764         state.es_parsable = B_FALSE;
7765 
7766         while ((option = getopt_long(argc, argv, "o:px",
7767             showeth_lopts, NULL)) != -1) {
7768                 switch (option) {
7769                         case 'x':
7770                                 state.es_extended = B_TRUE;
7771                                 break;
7772                         case 'p':
7773                                 state.es_parsable = B_TRUE;
7774                                 break;
7775                         case 'o':
7776                                 fields_str = optarg;
7777                                 break;
7778                         default:
7779                                 die_opterr(optopt, option, use);
7780                                 break;
7781                 }
7782         }
7783 
7784         if (optind == (argc - 1))
7785                 state.es_link = argv[optind];
7786 
7787         if (state.es_parsable)
7788                 ofmtflags |= OFMT_PARSABLE;
7789         oferr = ofmt_open(fields_str, ether_fields, ofmtflags,
7790             DLADM_DEFAULT_COL, &ofmt);
7791         ofmt_check(oferr, state.es_parsable, ofmt, die, warn);
7792         state.es_ofmt = ofmt;
7793 
7794         if (state.es_link == NULL) {
7795                 (void) dladm_walk_datalink_id(show_etherprop, handle, &state,
7796                     DATALINK_CLASS_PHYS, DL_ETHER, DLADM_OPT_ACTIVE);
7797         } else {
7798                 if (!link_is_ether(state.es_link, &linkid))
7799                         die("invalid link specified");
7800                 (void) show_etherprop(handle, linkid, &state);
7801         }
7802         ofmt_close(ofmt);
7803 }
7804 
7805 static int
7806 show_etherprop(dladm_handle_t dh, datalink_id_t linkid, void *arg)
7807 {
7808         print_ether_state_t     *statep = arg;
7809         ether_fields_buf_t      ebuf;
7810         dladm_ether_info_t      eattr;
7811         dladm_status_t          status;
7812 
7813         bzero(&ebuf, sizeof (ether_fields_buf_t));
7814         if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL,
7815             ebuf.eth_link, sizeof (ebuf.eth_link)) != DLADM_STATUS_OK) {
7816                 return (DLADM_WALK_CONTINUE);
7817         }
7818 
7819         status = dladm_ether_info(dh, linkid, &eattr);
7820         if (status != DLADM_STATUS_OK)
7821                 goto cleanup;
7822 
7823         (void) strlcpy(ebuf.eth_ptype, "current", sizeof (ebuf.eth_ptype));
7824 
7825         (void) dladm_ether_autoneg2str(ebuf.eth_autoneg,
7826             sizeof (ebuf.eth_autoneg), &eattr, CURRENT);
7827         (void) dladm_ether_pause2str(ebuf.eth_pause,
7828             sizeof (ebuf.eth_pause), &eattr, CURRENT);
7829         (void) dladm_ether_spdx2str(ebuf.eth_spdx,
7830             sizeof (ebuf.eth_spdx), &eattr, CURRENT);
7831         (void) strlcpy(ebuf.eth_state,
7832             dladm_linkstate2str(eattr.lei_state, ebuf.eth_state),
7833             sizeof (ebuf.eth_state));
7834         (void) strlcpy(ebuf.eth_rem_fault,
7835             (eattr.lei_attr[CURRENT].le_fault ? "fault" : "none"),
7836             sizeof (ebuf.eth_rem_fault));
7837 
7838         ofmt_print(statep->es_ofmt, &ebuf);
7839 
7840         if (statep->es_extended)
7841                 show_ether_xprop(arg, &eattr);
7842 
7843 cleanup:
7844         dladm_ether_info_done(&eattr);
7845         return (DLADM_WALK_CONTINUE);
7846 }
7847 
7848 /* ARGSUSED */
7849 static void
7850 do_init_secobj(int argc, char **argv, const char *use)
7851 {
7852         dladm_status_t  status;
7853 
7854         status = dladm_init_secobj(handle);
7855         if (status != DLADM_STATUS_OK)
7856                 die_dlerr(status, "secure object initialization failed");
7857 }
7858 
7859 enum bridge_func {
7860         brCreate, brAdd, brModify
7861 };
7862 
7863 static void
7864 create_modify_add_bridge(int argc, char **argv, const char *use,
7865     enum bridge_func func)
7866 {
7867         int                     option;
7868         uint_t                  n, i, nlink;
7869         uint32_t                flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
7870         char                    *altroot = NULL;
7871         char                    *links[MAXPORT];
7872         datalink_id_t           linkids[MAXPORT];
7873         dladm_status_t          status;
7874         const char              *bridge;
7875         UID_STP_CFG_T           cfg, cfg_old;
7876         dladm_bridge_prot_t     brprot = DLADM_BRIDGE_PROT_UNKNOWN;
7877         dladm_bridge_prot_t     brprot_old;
7878 
7879         /* Set up the default configuration values */
7880         cfg.field_mask = 0;
7881         cfg.bridge_priority = DEF_BR_PRIO;
7882         cfg.max_age = DEF_BR_MAXAGE;
7883         cfg.hello_time = DEF_BR_HELLOT;
7884         cfg.forward_delay = DEF_BR_FWDELAY;
7885         cfg.force_version = DEF_FORCE_VERS;
7886 
7887         nlink = opterr = 0;
7888         while ((option = getopt_long(argc, argv, ":P:R:d:f:h:l:m:p:",
7889             bridge_lopts, NULL)) != -1) {
7890                 switch (option) {
7891                 case 'P':
7892                         if (func == brAdd)
7893                                 die_opterr(optopt, option, use);
7894                         status = dladm_bridge_str2prot(optarg, &brprot);
7895                         if (status != DLADM_STATUS_OK)
7896                                 die_dlerr(status, "protection %s", optarg);
7897                         break;
7898                 case 'R':
7899                         altroot = optarg;
7900                         break;
7901                 case 'd':
7902                         if (func == brAdd)
7903                                 die_opterr(optopt, option, use);
7904                         if (cfg.field_mask & BR_CFG_DELAY)
7905                                 die("forwarding delay set more than once");
7906                         if (!str2int(optarg, &cfg.forward_delay) ||
7907                             cfg.forward_delay < MIN_BR_FWDELAY ||
7908                             cfg.forward_delay > MAX_BR_FWDELAY)
7909                                 die("incorrect forwarding delay");
7910                         cfg.field_mask |= BR_CFG_DELAY;
7911                         break;
7912                 case 'f':
7913                         if (func == brAdd)
7914                                 die_opterr(optopt, option, use);
7915                         if (cfg.field_mask & BR_CFG_FORCE_VER)
7916                                 die("force protocol set more than once");
7917                         if (!str2int(optarg, &cfg.force_version) ||
7918                             cfg.force_version < 0)
7919                                 die("incorrect force protocol");
7920                         cfg.field_mask |= BR_CFG_FORCE_VER;
7921                         break;
7922                 case 'h':
7923                         if (func == brAdd)
7924                                 die_opterr(optopt, option, use);
7925                         if (cfg.field_mask & BR_CFG_HELLO)
7926                                 die("hello time set more than once");
7927                         if (!str2int(optarg, &cfg.hello_time) ||
7928                             cfg.hello_time < MIN_BR_HELLOT ||
7929                             cfg.hello_time > MAX_BR_HELLOT)
7930                                 die("incorrect hello time");
7931                         cfg.field_mask |= BR_CFG_HELLO;
7932                         break;
7933                 case 'l':
7934                         if (func == brModify)
7935                                 die_opterr(optopt, option, use);
7936                         if (nlink >= MAXPORT)
7937                                 die("too many links specified");
7938                         links[nlink++] = optarg;
7939                         break;
7940                 case 'm':
7941                         if (func == brAdd)
7942                                 die_opterr(optopt, option, use);
7943                         if (cfg.field_mask & BR_CFG_AGE)
7944                                 die("max age set more than once");
7945                         if (!str2int(optarg, &cfg.max_age) ||
7946                             cfg.max_age < MIN_BR_MAXAGE ||
7947                             cfg.max_age > MAX_BR_MAXAGE)
7948                                 die("incorrect max age");
7949                         cfg.field_mask |= BR_CFG_AGE;
7950                         break;
7951                 case 'p':
7952                         if (func == brAdd)
7953                                 die_opterr(optopt, option, use);
7954                         if (cfg.field_mask & BR_CFG_PRIO)
7955                                 die("priority set more than once");
7956                         if (!str2int(optarg, &cfg.bridge_priority) ||
7957                             cfg.bridge_priority < MIN_BR_PRIO ||
7958                             cfg.bridge_priority > MAX_BR_PRIO)
7959                                 die("incorrect priority");
7960                         cfg.bridge_priority &= 0xF000;
7961                         cfg.field_mask |= BR_CFG_PRIO;
7962                         break;
7963                 default:
7964                         die_opterr(optopt, option, use);
7965                         break;
7966                 }
7967         }
7968 
7969         /* get the bridge name (required last argument) */
7970         if (optind != (argc-1))
7971                 usage();
7972 
7973         bridge = argv[optind];
7974         if (!dladm_valid_bridgename(bridge))
7975                 die("invalid bridge name '%s'", bridge);
7976 
7977         /*
7978          * Get the current properties, if any, and merge in with changes.  This
7979          * is necessary (even with the field_mask feature) so that the
7980          * value-checking macros will produce the right results with proposed
7981          * changes to existing configuration.  We only need it for those
7982          * parameters, though.
7983          */
7984         (void) dladm_bridge_get_properties(bridge, &cfg_old, &brprot_old);
7985         if (brprot == DLADM_BRIDGE_PROT_UNKNOWN)
7986                 brprot = brprot_old;
7987         if (!(cfg.field_mask & BR_CFG_AGE))
7988                 cfg.max_age = cfg_old.max_age;
7989         if (!(cfg.field_mask & BR_CFG_HELLO))
7990                 cfg.hello_time = cfg_old.hello_time;
7991         if (!(cfg.field_mask & BR_CFG_DELAY))
7992                 cfg.forward_delay = cfg_old.forward_delay;
7993 
7994         if (!CHECK_BRIDGE_CONFIG(cfg)) {
7995                 warn("illegal forward delay / max age / hello time "
7996                     "combination");
7997                 if (NO_MAXAGE(cfg)) {
7998                         die("no max age possible: need forward delay >= %d or "
7999                             "hello time <= %d", MIN_FWDELAY_NOM(cfg),
8000                             MAX_HELLOTIME_NOM(cfg));
8001                 } else if (SMALL_MAXAGE(cfg)) {
8002                         if (CAPPED_MAXAGE(cfg))
8003                                 die("max age too small: need age >= %d and "
8004                                     "<= %d or hello time <= %d",
8005                                     MIN_MAXAGE(cfg), MAX_MAXAGE(cfg),
8006                                     MAX_HELLOTIME(cfg));
8007                         else
8008                                 die("max age too small: need age >= %d or "
8009                                     "hello time <= %d",
8010                                     MIN_MAXAGE(cfg), MAX_HELLOTIME(cfg));
8011                 } else if (FLOORED_MAXAGE(cfg)) {
8012                         die("max age too large: need age >= %d and <= %d or "
8013                             "forward delay >= %d",
8014                             MIN_MAXAGE(cfg), MAX_MAXAGE(cfg),
8015                             MIN_FWDELAY(cfg));
8016                 } else {
8017                         die("max age too large: need age <= %d or forward "
8018                             "delay >= %d",
8019                             MAX_MAXAGE(cfg), MIN_FWDELAY(cfg));
8020                 }
8021         }
8022 
8023         if (altroot != NULL)
8024                 altroot_cmd(altroot, argc, argv);
8025 
8026         for (n = 0; n < nlink; n++) {
8027                 datalink_class_t class;
8028                 uint32_t media;
8029                 char pointless[DLADM_STRSIZE];
8030 
8031                 if (dladm_name2info(handle, links[n], &linkids[n], NULL, &class,
8032                     &media) != DLADM_STATUS_OK)
8033                         die("invalid link name '%s'", links[n]);
8034                 if (class & ~(DATALINK_CLASS_PHYS | DATALINK_CLASS_AGGR |
8035                     DATALINK_CLASS_ETHERSTUB | DATALINK_CLASS_SIMNET))
8036                         die("%s %s cannot be bridged",
8037                             dladm_class2str(class, pointless), links[n]);
8038                 if (media != DL_ETHER && media != DL_100VG &&
8039                     media != DL_ETH_CSMA && media != DL_100BT)
8040                         die("%s interface %s cannot be bridged",
8041                             dladm_media2str(media, pointless), links[n]);
8042         }
8043 
8044         if (func == brCreate)
8045                 flags |= DLADM_OPT_CREATE;
8046 
8047         if (func != brAdd) {
8048                 status = dladm_bridge_configure(handle, bridge, &cfg, brprot,
8049                     flags);
8050                 if (status != DLADM_STATUS_OK)
8051                         die_dlerr(status, "create operation failed");
8052         }
8053 
8054         status = DLADM_STATUS_OK;
8055         for (n = 0; n < nlink; n++) {
8056                 status = dladm_bridge_setlink(handle, linkids[n], bridge);
8057                 if (status != DLADM_STATUS_OK)
8058                         break;
8059         }
8060 
8061         if (n >= nlink) {
8062                 /*
8063                  * We were successful.  If we're creating a new bridge, then
8064                  * there's just one more step: enabling.  If we're modifying or
8065                  * just adding links, then we're done.
8066                  */
8067                 if (func != brCreate ||
8068                     (status = dladm_bridge_enable(bridge)) == DLADM_STATUS_OK)
8069                         return;
8070         }
8071 
8072         /* clean up the partial configuration */
8073         for (i = 0; i < n; i++)
8074                 (void) dladm_bridge_setlink(handle, linkids[i], "");
8075 
8076         /* if failure for brCreate, then delete the bridge */
8077         if (func == brCreate)
8078                 (void) dladm_bridge_delete(handle, bridge, flags);
8079 
8080         if (n < nlink)
8081                 die_dlerr(status, "unable to add link %s to bridge %s",
8082                     links[n], bridge);
8083         else
8084                 die_dlerr(status, "unable to enable bridge %s", bridge);
8085 }
8086 
8087 static void
8088 do_create_bridge(int argc, char **argv, const char *use)
8089 {
8090         create_modify_add_bridge(argc, argv, use, brCreate);
8091 }
8092 
8093 static void
8094 do_modify_bridge(int argc, char **argv, const char *use)
8095 {
8096         create_modify_add_bridge(argc, argv, use, brModify);
8097 }
8098 
8099 static void
8100 do_add_bridge(int argc, char **argv, const char *use)
8101 {
8102         create_modify_add_bridge(argc, argv, use, brAdd);
8103 }
8104 
8105 static void
8106 do_delete_bridge(int argc, char **argv, const char *use)
8107 {
8108         char                    option;
8109         char                    *altroot = NULL;
8110         uint32_t                flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
8111         dladm_status_t          status;
8112 
8113         opterr = 0;
8114         while ((option = getopt_long(argc, argv, ":R:", bridge_lopts, NULL)) !=
8115             -1) {
8116                 switch (option) {
8117                 case 'R':
8118                         altroot = optarg;
8119                         break;
8120                 default:
8121                         die_opterr(optopt, option, use);
8122                         break;
8123                 }
8124         }
8125 
8126         /* get the bridge name (required last argument) */
8127         if (optind != (argc-1))
8128                 usage();
8129 
8130         if (altroot != NULL)
8131                 altroot_cmd(altroot, argc, argv);
8132 
8133         status = dladm_bridge_delete(handle, argv[optind], flags);
8134         if (status != DLADM_STATUS_OK)
8135                 die_dlerr(status, "delete operation failed");
8136 }
8137 
8138 static void
8139 do_remove_bridge(int argc, char **argv, const char *use)
8140 {
8141         char            option;
8142         uint_t          n, nlink;
8143         char            *links[MAXPORT];
8144         datalink_id_t   linkids[MAXPORT];
8145         char            *altroot = NULL;
8146         dladm_status_t  status;
8147         boolean_t       removed_one;
8148 
8149         nlink = opterr = 0;
8150         while ((option = getopt_long(argc, argv, ":R:l:", bridge_lopts,
8151             NULL)) != -1) {
8152                 switch (option) {
8153                 case 'R':
8154                         altroot = optarg;
8155                         break;
8156                 case 'l':
8157                         if (nlink >= MAXPORT)
8158                                 die("too many links specified");
8159                         links[nlink++] = optarg;
8160                         break;
8161                 default:
8162                         die_opterr(optopt, option, use);
8163                         break;
8164                 }
8165         }
8166 
8167         if (nlink == 0)
8168                 usage();
8169 
8170         /* get the bridge name (required last argument) */
8171         if (optind != (argc-1))
8172                 usage();
8173 
8174         if (altroot != NULL)
8175                 altroot_cmd(altroot, argc, argv);
8176 
8177         for (n = 0; n < nlink; n++) {
8178                 char bridge[MAXLINKNAMELEN];
8179 
8180                 if (dladm_name2info(handle, links[n], &linkids[n], NULL, NULL,
8181                     NULL) != DLADM_STATUS_OK)
8182                         die("invalid link name '%s'", links[n]);
8183                 status = dladm_bridge_getlink(handle, linkids[n], bridge,
8184                     sizeof (bridge));
8185                 if (status != DLADM_STATUS_OK &&
8186                     status != DLADM_STATUS_NOTFOUND) {
8187                         die_dlerr(status, "cannot get bridge status on %s",
8188                             links[n]);
8189                 }
8190                 if (status == DLADM_STATUS_NOTFOUND ||
8191                     strcmp(bridge, argv[optind]) != 0)
8192                         die("link %s is not on bridge %s", links[n],
8193                             argv[optind]);
8194         }
8195 
8196         removed_one = B_FALSE;
8197         for (n = 0; n < nlink; n++) {
8198                 status = dladm_bridge_setlink(handle, linkids[n], "");
8199                 if (status == DLADM_STATUS_OK) {
8200                         removed_one = B_TRUE;
8201                 } else {
8202                         warn_dlerr(status,
8203                             "cannot remove link %s from bridge %s",
8204                             links[n], argv[optind]);
8205                 }
8206         }
8207         if (!removed_one)
8208                 die("unable to remove any links from bridge %s", argv[optind]);
8209 }
8210 
8211 static void
8212 fmt_int(char *buf, size_t buflen, int value, int runvalue,
8213     boolean_t printstar)
8214 {
8215         (void) snprintf(buf, buflen, "%d", value);
8216         if (value != runvalue && printstar)
8217                 (void) strlcat(buf, "*", buflen);
8218 }
8219 
8220 static void
8221 fmt_bridge_id(char *buf, size_t buflen, UID_BRIDGE_ID_T *bid)
8222 {
8223         (void) snprintf(buf, buflen, "%u/%x:%x:%x:%x:%x:%x", bid->prio,
8224             bid->addr[0], bid->addr[1], bid->addr[2], bid->addr[3],
8225             bid->addr[4], bid->addr[5]);
8226 }
8227 
8228 static dladm_status_t
8229 print_bridge(show_state_t *state, datalink_id_t linkid,
8230     bridge_fields_buf_t *bbuf)
8231 {
8232         char                    link[MAXLINKNAMELEN];
8233         datalink_class_t        class;
8234         uint32_t                flags;
8235         dladm_status_t          status;
8236         UID_STP_CFG_T           smfcfg, runcfg;
8237         UID_STP_STATE_T         stpstate;
8238         dladm_bridge_prot_t     smfprot, runprot;
8239 
8240         if ((status = dladm_datalink_id2info(handle, linkid, &flags, &class,
8241             NULL, link, sizeof (link))) != DLADM_STATUS_OK)
8242                 return (status);
8243 
8244         if (!(state->ls_flags & flags))
8245                 return (DLADM_STATUS_NOTFOUND);
8246 
8247         /* Convert observability node name back to bridge name */
8248         if (!dladm_observe_to_bridge(link))
8249                 return (DLADM_STATUS_NOTFOUND);
8250         (void) strlcpy(bbuf->bridge_name, link, sizeof (bbuf->bridge_name));
8251 
8252         /*
8253          * If the running value differs from the one in SMF, and parsable
8254          * output is not requested, then we show the running value with an
8255          * asterisk.
8256          */
8257         (void) dladm_bridge_get_properties(bbuf->bridge_name, &smfcfg,
8258             &smfprot);
8259         (void) dladm_bridge_run_properties(bbuf->bridge_name, &runcfg,
8260             &runprot);
8261         (void) snprintf(bbuf->bridge_protect, sizeof (bbuf->bridge_protect),
8262             "%s%s", state->ls_parsable || smfprot == runprot ? "" : "*",
8263             dladm_bridge_prot2str(runprot));
8264         fmt_int(bbuf->bridge_priority, sizeof (bbuf->bridge_priority),
8265             smfcfg.bridge_priority, runcfg.bridge_priority,
8266             !state->ls_parsable && (runcfg.field_mask & BR_CFG_AGE));
8267         fmt_int(bbuf->bridge_bmaxage, sizeof (bbuf->bridge_bmaxage),
8268             smfcfg.max_age, runcfg.max_age,
8269             !state->ls_parsable && (runcfg.field_mask & BR_CFG_AGE));
8270         fmt_int(bbuf->bridge_bhellotime,
8271             sizeof (bbuf->bridge_bhellotime), smfcfg.hello_time,
8272             runcfg.hello_time,
8273             !state->ls_parsable && (runcfg.field_mask & BR_CFG_HELLO));
8274         fmt_int(bbuf->bridge_bfwddelay, sizeof (bbuf->bridge_bfwddelay),
8275             smfcfg.forward_delay, runcfg.forward_delay,
8276             !state->ls_parsable && (runcfg.field_mask & BR_CFG_DELAY));
8277         fmt_int(bbuf->bridge_forceproto, sizeof (bbuf->bridge_forceproto),
8278             smfcfg.force_version, runcfg.force_version,
8279             !state->ls_parsable && (runcfg.field_mask & BR_CFG_FORCE_VER));
8280         fmt_int(bbuf->bridge_holdtime, sizeof (bbuf->bridge_holdtime),
8281             smfcfg.hold_time, runcfg.hold_time,
8282             !state->ls_parsable && (runcfg.field_mask & BR_CFG_HOLD_TIME));
8283 
8284         if (dladm_bridge_state(bbuf->bridge_name, &stpstate) ==
8285             DLADM_STATUS_OK) {
8286                 fmt_bridge_id(bbuf->bridge_address,
8287                     sizeof (bbuf->bridge_address), &stpstate.bridge_id);
8288                 (void) snprintf(bbuf->bridge_tctime,
8289                     sizeof (bbuf->bridge_tctime), "%lu",
8290                     stpstate.timeSince_Topo_Change);
8291                 (void) snprintf(bbuf->bridge_tccount,
8292                     sizeof (bbuf->bridge_tccount), "%lu",
8293                     stpstate.Topo_Change_Count);
8294                 (void) snprintf(bbuf->bridge_tchange,
8295                     sizeof (bbuf->bridge_tchange), "%u", stpstate.Topo_Change);
8296                 fmt_bridge_id(bbuf->bridge_desroot,
8297                     sizeof (bbuf->bridge_desroot), &stpstate.designated_root);
8298                 (void) snprintf(bbuf->bridge_rootcost,
8299                     sizeof (bbuf->bridge_rootcost), "%lu",
8300                     stpstate.root_path_cost);
8301                 (void) snprintf(bbuf->bridge_rootport,
8302                     sizeof (bbuf->bridge_rootport), "%u", stpstate.root_port);
8303                 (void) snprintf(bbuf->bridge_maxage,
8304                     sizeof (bbuf->bridge_maxage), "%d", stpstate.max_age);
8305                 (void) snprintf(bbuf->bridge_hellotime,
8306                     sizeof (bbuf->bridge_hellotime), "%d", stpstate.hello_time);
8307                 (void) snprintf(bbuf->bridge_fwddelay,
8308                     sizeof (bbuf->bridge_fwddelay), "%d",
8309                     stpstate.forward_delay);
8310         }
8311         return (DLADM_STATUS_OK);
8312 }
8313 
8314 static dladm_status_t
8315 print_bridge_stats(show_state_t *state, datalink_id_t linkid,
8316     bridge_statfields_buf_t *bbuf)
8317 {
8318         char                    link[MAXLINKNAMELEN];
8319         datalink_class_t        class;
8320         uint32_t                flags;
8321         dladm_status_t          status;
8322         kstat_ctl_t             *kcp;
8323         kstat_t                 *ksp;
8324         brsum_t                 *brsum = (brsum_t *)&state->ls_prevstats;
8325         brsum_t                 newval;
8326 
8327 #ifndef lint
8328         /* This is a compile-time assertion; optimizer normally fixes this */
8329         extern void brsum_t_is_too_large(void);
8330 
8331         if (sizeof (*brsum) > sizeof (state->ls_prevstats))
8332                 brsum_t_is_too_large();
8333 #endif
8334 
8335         if (state->ls_firstonly) {
8336                 if (state->ls_donefirst)
8337                         return (DLADM_WALK_CONTINUE);
8338                 state->ls_donefirst = B_TRUE;
8339         } else {
8340                 bzero(brsum, sizeof (*brsum));
8341         }
8342         bzero(&newval, sizeof (newval));
8343 
8344         if ((status = dladm_datalink_id2info(handle, linkid, &flags, &class,
8345             NULL, link, sizeof (link))) != DLADM_STATUS_OK)
8346                 return (status);
8347 
8348         if (!(state->ls_flags & flags))
8349                 return (DLADM_STATUS_NOTFOUND);
8350 
8351         if ((kcp = kstat_open()) == NULL) {
8352                 warn("kstat open operation failed");
8353                 return (DLADM_STATUS_OK);
8354         }
8355         if ((ksp = kstat_lookup(kcp, "bridge", 0, link)) != NULL &&
8356             kstat_read(kcp, ksp, NULL) != -1) {
8357                 if (dladm_kstat_value(ksp, "drops", KSTAT_DATA_UINT64,
8358                     &newval.drops) == DLADM_STATUS_OK) {
8359                         (void) snprintf(bbuf->bridges_drops,
8360                             sizeof (bbuf->bridges_drops), "%llu",
8361                             newval.drops - brsum->drops);
8362                 }
8363                 if (dladm_kstat_value(ksp, "forward_direct", KSTAT_DATA_UINT64,
8364                     &newval.forward_dir) == DLADM_STATUS_OK) {
8365                         (void) snprintf(bbuf->bridges_forwards,
8366                             sizeof (bbuf->bridges_forwards), "%llu",
8367                             newval.forward_dir - brsum->forward_dir);
8368                 }
8369                 if (dladm_kstat_value(ksp, "forward_mbcast", KSTAT_DATA_UINT64,
8370                     &newval.forward_mb) == DLADM_STATUS_OK) {
8371                         (void) snprintf(bbuf->bridges_mbcast,
8372                             sizeof (bbuf->bridges_mbcast), "%llu",
8373                             newval.forward_mb - brsum->forward_mb);
8374                 }
8375                 if (dladm_kstat_value(ksp, "forward_unknown", KSTAT_DATA_UINT64,
8376                     &newval.forward_unk) == DLADM_STATUS_OK) {
8377                         (void) snprintf(bbuf->bridges_unknown,
8378                             sizeof (bbuf->bridges_unknown), "%llu",
8379                             newval.forward_unk - brsum->forward_unk);
8380                 }
8381                 if (dladm_kstat_value(ksp, "recv", KSTAT_DATA_UINT64,
8382                     &newval.recv) == DLADM_STATUS_OK) {
8383                         (void) snprintf(bbuf->bridges_recv,
8384                             sizeof (bbuf->bridges_recv), "%llu",
8385                             newval.recv - brsum->recv);
8386                 }
8387                 if (dladm_kstat_value(ksp, "sent", KSTAT_DATA_UINT64,
8388                     &newval.sent) == DLADM_STATUS_OK) {
8389                         (void) snprintf(bbuf->bridges_sent,
8390                             sizeof (bbuf->bridges_sent), "%llu",
8391                             newval.sent - brsum->sent);
8392                 }
8393         }
8394         (void) kstat_close(kcp);
8395 
8396         /* Convert observability node name back to bridge name */
8397         if (!dladm_observe_to_bridge(link))
8398                 return (DLADM_STATUS_NOTFOUND);
8399         (void) strlcpy(bbuf->bridges_name, link, sizeof (bbuf->bridges_name));
8400 
8401         *brsum = newval;
8402 
8403         return (DLADM_STATUS_OK);
8404 }
8405 
8406 /*
8407  * This structure carries around extra state information for the show-bridge
8408  * command and allows us to use common support functions.
8409  */
8410 typedef struct {
8411         show_state_t    state;
8412         boolean_t       show_stats;
8413         const char      *bridge;
8414 } show_brstate_t;
8415 
8416 /* ARGSUSED */
8417 static int
8418 show_bridge(dladm_handle_t handle, datalink_id_t linkid, void *arg)
8419 {
8420         show_brstate_t  *brstate = arg;
8421         void *buf;
8422 
8423         if (brstate->show_stats) {
8424                 bridge_statfields_buf_t bbuf;
8425 
8426                 bzero(&bbuf, sizeof (bbuf));
8427                 brstate->state.ls_status = print_bridge_stats(&brstate->state,
8428                     linkid, &bbuf);
8429                 buf = &bbuf;
8430         } else {
8431                 bridge_fields_buf_t bbuf;
8432 
8433                 bzero(&bbuf, sizeof (bbuf));
8434                 brstate->state.ls_status = print_bridge(&brstate->state, linkid,
8435                     &bbuf);
8436                 buf = &bbuf;
8437         }
8438         if (brstate->state.ls_status == DLADM_STATUS_OK)
8439                 ofmt_print(brstate->state.ls_ofmt, buf);
8440         return (DLADM_WALK_CONTINUE);
8441 }
8442 
8443 static void
8444 fmt_bool(char *buf, size_t buflen, int val)
8445 {
8446         (void) strlcpy(buf, val ? "yes" : "no", buflen);
8447 }
8448 
8449 static dladm_status_t
8450 print_bridge_link(show_state_t *state, datalink_id_t linkid,
8451     bridge_link_fields_buf_t *bbuf)
8452 {
8453         datalink_class_t        class;
8454         uint32_t                flags;
8455         dladm_status_t          status;
8456         UID_STP_PORT_STATE_T    stpstate;
8457 
8458         status = dladm_datalink_id2info(handle, linkid, &flags, &class, NULL,
8459             bbuf->bridgel_link, sizeof (bbuf->bridgel_link));
8460         if (status != DLADM_STATUS_OK)
8461                 return (status);
8462 
8463         if (!(state->ls_flags & flags))
8464                 return (DLADM_STATUS_NOTFOUND);
8465 
8466         if (dladm_bridge_link_state(handle, linkid, &stpstate) ==
8467             DLADM_STATUS_OK) {
8468                 (void) snprintf(bbuf->bridgel_index,
8469                     sizeof (bbuf->bridgel_index), "%u", stpstate.port_no);
8470                 if (dlsym(RTLD_PROBE, "STP_IN_state2str")) {
8471                         (void) strlcpy(bbuf->bridgel_state,
8472                             STP_IN_state2str(stpstate.state),
8473                             sizeof (bbuf->bridgel_state));
8474                 } else {
8475                         (void) snprintf(bbuf->bridgel_state,
8476                             sizeof (bbuf->bridgel_state), "%u",
8477                             stpstate.state);
8478                 }
8479                 (void) snprintf(bbuf->bridgel_uptime,
8480                     sizeof (bbuf->bridgel_uptime), "%lu", stpstate.uptime);
8481                 (void) snprintf(bbuf->bridgel_opercost,
8482                     sizeof (bbuf->bridgel_opercost), "%lu",
8483                     stpstate.oper_port_path_cost);
8484                 fmt_bool(bbuf->bridgel_operp2p, sizeof (bbuf->bridgel_operp2p),
8485                     stpstate.oper_point2point);
8486                 fmt_bool(bbuf->bridgel_operedge,
8487                     sizeof (bbuf->bridgel_operedge), stpstate.oper_edge);
8488                 fmt_bridge_id(bbuf->bridgel_desroot,
8489                     sizeof (bbuf->bridgel_desroot), &stpstate.designated_root);
8490                 (void) snprintf(bbuf->bridgel_descost,
8491                     sizeof (bbuf->bridgel_descost), "%lu",
8492                     stpstate.designated_cost);
8493                 fmt_bridge_id(bbuf->bridgel_desbridge,
8494                     sizeof (bbuf->bridgel_desbridge),
8495                     &stpstate.designated_bridge);
8496                 (void) snprintf(bbuf->bridgel_desport,
8497                     sizeof (bbuf->bridgel_desport), "%u",
8498                     stpstate.designated_port);
8499                 fmt_bool(bbuf->bridgel_tcack, sizeof (bbuf->bridgel_tcack),
8500                     stpstate.top_change_ack);
8501         }
8502         return (DLADM_STATUS_OK);
8503 }
8504 
8505 static dladm_status_t
8506 print_bridge_link_stats(show_state_t *state, datalink_id_t linkid,
8507     bridge_link_statfields_buf_t *bbuf)
8508 {
8509         datalink_class_t        class;
8510         uint32_t                flags;
8511         dladm_status_t          status;
8512         UID_STP_PORT_STATE_T    stpstate;
8513         kstat_ctl_t             *kcp;
8514         kstat_t                 *ksp;
8515         char                    bridge[MAXLINKNAMELEN];
8516         char                    kstatname[MAXLINKNAMELEN*2 + 1];
8517         brlsum_t                *brlsum = (brlsum_t *)&state->ls_prevstats;
8518         brlsum_t                newval;
8519 
8520 #ifndef lint
8521         /* This is a compile-time assertion; optimizer normally fixes this */
8522         extern void brlsum_t_is_too_large(void);
8523 
8524         if (sizeof (*brlsum) > sizeof (state->ls_prevstats))
8525                 brlsum_t_is_too_large();
8526 #endif
8527 
8528         if (state->ls_firstonly) {
8529                 if (state->ls_donefirst)
8530                         return (DLADM_WALK_CONTINUE);
8531                 state->ls_donefirst = B_TRUE;
8532         } else {
8533                 bzero(brlsum, sizeof (*brlsum));
8534         }
8535         bzero(&newval, sizeof (newval));
8536 
8537         status = dladm_datalink_id2info(handle, linkid, &flags, &class, NULL,
8538             bbuf->bridgels_link, sizeof (bbuf->bridgels_link));
8539         if (status != DLADM_STATUS_OK)
8540                 return (status);
8541 
8542         if (!(state->ls_flags & flags))
8543                 return (DLADM_STATUS_NOTFOUND);
8544 
8545         if (dladm_bridge_link_state(handle, linkid, &stpstate) ==
8546             DLADM_STATUS_OK) {
8547                 newval.cfgbpdu = stpstate.rx_cfg_bpdu_cnt;
8548                 newval.tcnbpdu = stpstate.rx_tcn_bpdu_cnt;
8549                 newval.rstpbpdu = stpstate.rx_rstp_bpdu_cnt;
8550                 newval.txbpdu = stpstate.txCount;
8551 
8552                 (void) snprintf(bbuf->bridgels_cfgbpdu,
8553                     sizeof (bbuf->bridgels_cfgbpdu), "%lu",
8554                     newval.cfgbpdu - brlsum->cfgbpdu);
8555                 (void) snprintf(bbuf->bridgels_tcnbpdu,
8556                     sizeof (bbuf->bridgels_tcnbpdu), "%lu",
8557                     newval.tcnbpdu - brlsum->tcnbpdu);
8558                 (void) snprintf(bbuf->bridgels_rstpbpdu,
8559                     sizeof (bbuf->bridgels_rstpbpdu), "%lu",
8560                     newval.rstpbpdu - brlsum->rstpbpdu);
8561                 (void) snprintf(bbuf->bridgels_txbpdu,
8562                     sizeof (bbuf->bridgels_txbpdu), "%lu",
8563                     newval.txbpdu - brlsum->txbpdu);
8564         }
8565 
8566         if ((status = dladm_bridge_getlink(handle, linkid, bridge,
8567             sizeof (bridge))) != DLADM_STATUS_OK)
8568                 goto bls_out;
8569         (void) snprintf(kstatname, sizeof (kstatname), "%s0-%s", bridge,
8570             bbuf->bridgels_link);
8571         if ((kcp = kstat_open()) == NULL) {
8572                 warn("kstat open operation failed");
8573                 goto bls_out;
8574         }
8575         if ((ksp = kstat_lookup(kcp, "bridge", 0, kstatname)) != NULL &&
8576             kstat_read(kcp, ksp, NULL) != -1) {
8577                 if (dladm_kstat_value(ksp, "drops", KSTAT_DATA_UINT64,
8578                     &newval.drops) != -1) {
8579                         (void) snprintf(bbuf->bridgels_drops,
8580                             sizeof (bbuf->bridgels_drops), "%llu",
8581                             newval.drops - brlsum->drops);
8582                 }
8583                 if (dladm_kstat_value(ksp, "recv", KSTAT_DATA_UINT64,
8584                     &newval.recv) != -1) {
8585                         (void) snprintf(bbuf->bridgels_recv,
8586                             sizeof (bbuf->bridgels_recv), "%llu",
8587                             newval.recv - brlsum->recv);
8588                 }
8589                 if (dladm_kstat_value(ksp, "xmit", KSTAT_DATA_UINT64,
8590                     &newval.xmit) != -1) {
8591                         (void) snprintf(bbuf->bridgels_xmit,
8592                             sizeof (bbuf->bridgels_xmit), "%llu",
8593                             newval.xmit - brlsum->xmit);
8594                 }
8595         }
8596         (void) kstat_close(kcp);
8597 bls_out:
8598         *brlsum = newval;
8599 
8600         return (status);
8601 }
8602 
8603 static void
8604 show_bridge_link(datalink_id_t linkid, show_brstate_t *brstate)
8605 {
8606         void *buf;
8607 
8608         if (brstate->show_stats) {
8609                 bridge_link_statfields_buf_t bbuf;
8610 
8611                 bzero(&bbuf, sizeof (bbuf));
8612                 brstate->state.ls_status = print_bridge_link_stats(
8613                     &brstate->state, linkid, &bbuf);
8614                 buf = &bbuf;
8615         } else {
8616                 bridge_link_fields_buf_t bbuf;
8617 
8618                 bzero(&bbuf, sizeof (bbuf));
8619                 brstate->state.ls_status = print_bridge_link(&brstate->state,
8620                     linkid, &bbuf);
8621                 buf = &bbuf;
8622         }
8623         if (brstate->state.ls_status == DLADM_STATUS_OK)
8624                 ofmt_print(brstate->state.ls_ofmt, buf);
8625 }
8626 
8627 /* ARGSUSED */
8628 static int
8629 show_bridge_link_walk(dladm_handle_t handle, datalink_id_t linkid, void *arg)
8630 {
8631         show_brstate_t  *brstate = arg;
8632         char bridge[MAXLINKNAMELEN];
8633 
8634         if (dladm_bridge_getlink(handle, linkid, bridge, sizeof (bridge)) ==
8635             DLADM_STATUS_OK && strcmp(bridge, brstate->bridge) == 0) {
8636                 show_bridge_link(linkid, brstate);
8637         }
8638         return (DLADM_WALK_CONTINUE);
8639 }
8640 
8641 static void
8642 show_bridge_fwd(dladm_handle_t handle, bridge_listfwd_t *blf,
8643     show_state_t *state)
8644 {
8645         bridge_fwd_fields_buf_t bbuf;
8646 
8647         bzero(&bbuf, sizeof (bbuf));
8648         (void) snprintf(bbuf.bridgef_dest, sizeof (bbuf.bridgef_dest),
8649             "%s", ether_ntoa((struct ether_addr *)blf->blf_dest));
8650         if (blf->blf_is_local) {
8651                 (void) strlcpy(bbuf.bridgef_flags, "L",
8652                     sizeof (bbuf.bridgef_flags));
8653         } else {
8654                 (void) snprintf(bbuf.bridgef_age, sizeof (bbuf.bridgef_age),
8655                     "%2d.%03d", blf->blf_ms_age / 1000, blf->blf_ms_age % 1000);
8656                 if (blf->blf_trill_nick != 0) {
8657                         (void) snprintf(bbuf.bridgef_output,
8658                             sizeof (bbuf.bridgef_output), "%u",
8659                             blf->blf_trill_nick);
8660                 }
8661         }
8662         if (blf->blf_linkid != DATALINK_INVALID_LINKID &&
8663             blf->blf_trill_nick == 0) {
8664                 state->ls_status = dladm_datalink_id2info(handle,
8665                     blf->blf_linkid, NULL, NULL, NULL, bbuf.bridgef_output,
8666                     sizeof (bbuf.bridgef_output));
8667         }
8668         if (state->ls_status == DLADM_STATUS_OK)
8669                 ofmt_print(state->ls_ofmt, &bbuf);
8670 }
8671 
8672 static void
8673 show_bridge_trillnick(trill_listnick_t *tln, show_state_t *state)
8674 {
8675         bridge_trill_fields_buf_t bbuf;
8676 
8677         bzero(&bbuf, sizeof (bbuf));
8678         (void) snprintf(bbuf.bridget_nick, sizeof (bbuf.bridget_nick),
8679             "%u", tln->tln_nick);
8680         if (tln->tln_ours) {
8681                 (void) strlcpy(bbuf.bridget_flags, "L",
8682                     sizeof (bbuf.bridget_flags));
8683         } else {
8684                 state->ls_status = dladm_datalink_id2info(handle,
8685                     tln->tln_linkid, NULL, NULL, NULL, bbuf.bridget_link,
8686                     sizeof (bbuf.bridget_link));
8687                 (void) snprintf(bbuf.bridget_nexthop,
8688                     sizeof (bbuf.bridget_nexthop), "%s",
8689                     ether_ntoa((struct ether_addr *)tln->tln_nexthop));
8690         }
8691         if (state->ls_status == DLADM_STATUS_OK)
8692                 ofmt_print(state->ls_ofmt, &bbuf);
8693 }
8694 
8695 static void
8696 do_show_bridge(int argc, char **argv, const char *use)
8697 {
8698         int             option;
8699         enum {
8700                 bridgeMode, linkMode, fwdMode, trillMode
8701         }               op_mode = bridgeMode;
8702         uint32_t        flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
8703         boolean_t       parsable = B_FALSE;
8704         datalink_id_t   linkid = DATALINK_ALL_LINKID;
8705         int             interval = 0;
8706         show_brstate_t  brstate;
8707         dladm_status_t  status;
8708         char            *fields_str = NULL;
8709         /* default: bridge-related data */
8710         char            *all_fields = "bridge,protect,address,priority,bmaxage,"
8711             "bhellotime,bfwddelay,forceproto,tctime,tccount,tchange,"
8712             "desroot,rootcost,rootport,maxage,hellotime,fwddelay,holdtime";
8713         char            *default_fields = "bridge,protect,address,priority,"
8714             "desroot";
8715         char            *all_statfields = "bridge,drops,forwards,mbcast,"
8716             "unknown,recv,sent";
8717         char            *default_statfields = "bridge,drops,forwards,mbcast,"
8718             "unknown";
8719         /* -l: link-related data */
8720         char            *all_link_fields = "link,index,state,uptime,opercost,"
8721             "operp2p,operedge,desroot,descost,desbridge,desport,tcack";
8722         char            *default_link_fields = "link,state,uptime,desroot";
8723         char            *all_link_statfields = "link,cfgbpdu,tcnbpdu,rstpbpdu,"
8724             "txbpdu,drops,recv,xmit";
8725         char            *default_link_statfields = "link,drops,recv,xmit";
8726         /* -f: bridge forwarding table related data */
8727         char            *default_fwd_fields = "dest,age,flags,output";
8728         /* -t: TRILL nickname table related data */
8729         char            *default_trill_fields = "nick,flags,link,nexthop";
8730         char            *default_str;
8731         char            *all_str;
8732         ofmt_field_t    *field_arr;
8733         ofmt_handle_t   ofmt;
8734         ofmt_status_t   oferr;
8735         uint_t          ofmtflags = 0;
8736 
8737         bzero(&brstate, sizeof (brstate));
8738 
8739         opterr = 0;
8740         while ((option = getopt_long(argc, argv, ":fi:lo:pst",
8741             bridge_show_lopts, NULL)) != -1) {
8742                 switch (option) {
8743                 case 'f':
8744                         if (op_mode != bridgeMode && op_mode != fwdMode)
8745                                 die("-f is incompatible with -l or -t");
8746                         op_mode = fwdMode;
8747                         break;
8748                 case 'i':
8749                         if (interval != 0)
8750                                 die_optdup(option);
8751                         if (!str2int(optarg, &interval) || interval == 0)
8752                                 die("invalid interval value '%s'", optarg);
8753                         break;
8754                 case 'l':
8755                         if (op_mode != bridgeMode && op_mode != linkMode)
8756                                 die("-l is incompatible with -f or -t");
8757                         op_mode = linkMode;
8758                         break;
8759                 case 'o':
8760                         fields_str = optarg;
8761                         break;
8762                 case 'p':
8763                         if (parsable)
8764                                 die_optdup(option);
8765                         parsable = B_TRUE;
8766                         break;
8767                 case 's':
8768                         if (brstate.show_stats)
8769                                 die_optdup(option);
8770                         brstate.show_stats = B_TRUE;
8771                         break;
8772                 case 't':
8773                         if (op_mode != bridgeMode && op_mode != trillMode)
8774                                 die("-t is incompatible with -f or -l");
8775                         op_mode = trillMode;
8776                         break;
8777                 default:
8778                         die_opterr(optopt, option, use);
8779                         break;
8780                 }
8781         }
8782 
8783         if (interval != 0 && !brstate.show_stats)
8784                 die("the -i option can be used only with -s");
8785 
8786         if ((op_mode == fwdMode || op_mode == trillMode) && brstate.show_stats)
8787                 die("the -f/-t and -s options cannot be used together");
8788 
8789         /* get the bridge name (optional last argument) */
8790         if (optind == (argc-1)) {
8791                 char lname[MAXLINKNAMELEN];
8792                 uint32_t lnkflg;
8793                 datalink_class_t class;
8794 
8795                 brstate.bridge = argv[optind];
8796                 (void) snprintf(lname, sizeof (lname), "%s0", brstate.bridge);
8797                 if ((status = dladm_name2info(handle, lname, &linkid, &lnkflg,
8798                     &class, NULL)) != DLADM_STATUS_OK) {
8799                         die_dlerr(status, "bridge %s is not valid",
8800                             brstate.bridge);
8801                 }
8802 
8803                 if (class != DATALINK_CLASS_BRIDGE)
8804                         die("%s is not a bridge", brstate.bridge);
8805 
8806                 if (!(lnkflg & flags)) {
8807                         die_dlerr(DLADM_STATUS_BADARG,
8808                             "bridge %s is temporarily removed", brstate.bridge);
8809                 }
8810         } else if (optind != argc) {
8811                 usage();
8812         } else if (op_mode != bridgeMode) {
8813                 die("bridge name required for -l, -f, or -t");
8814                 return;
8815         }
8816 
8817         brstate.state.ls_parsable = parsable;
8818         brstate.state.ls_flags = flags;
8819         brstate.state.ls_firstonly = (interval != 0);
8820 
8821         switch (op_mode) {
8822         case bridgeMode:
8823                 if (brstate.show_stats) {
8824                         default_str = default_statfields;
8825                         all_str = all_statfields;
8826                         field_arr = bridge_statfields;
8827                 } else {
8828                         default_str = default_fields;
8829                         all_str = all_fields;
8830                         field_arr = bridge_fields;
8831                 }
8832                 break;
8833 
8834         case linkMode:
8835                 if (brstate.show_stats) {
8836                         default_str = default_link_statfields;
8837                         all_str = all_link_statfields;
8838                         field_arr = bridge_link_statfields;
8839                 } else {
8840                         default_str = default_link_fields;
8841                         all_str = all_link_fields;
8842                         field_arr = bridge_link_fields;
8843                 }
8844                 break;
8845 
8846         case fwdMode:
8847                 default_str = all_str = default_fwd_fields;
8848                 field_arr = bridge_fwd_fields;
8849                 break;
8850 
8851         case trillMode:
8852                 default_str = all_str = default_trill_fields;
8853                 field_arr = bridge_trill_fields;
8854                 break;
8855         }
8856 
8857         if (fields_str == NULL)
8858                 fields_str = default_str;
8859         else if (strcasecmp(fields_str, "all") == 0)
8860                 fields_str = all_str;
8861 
8862         if (parsable)
8863                 ofmtflags |= OFMT_PARSABLE;
8864         oferr = ofmt_open(fields_str, field_arr, ofmtflags, 0, &ofmt);
8865         ofmt_check(oferr, brstate.state.ls_parsable, ofmt, die, warn);
8866         brstate.state.ls_ofmt = ofmt;
8867 
8868         for (;;) {
8869                 brstate.state.ls_donefirst = B_FALSE;
8870                 switch (op_mode) {
8871                 case bridgeMode:
8872                         if (linkid == DATALINK_ALL_LINKID) {
8873                                 (void) dladm_walk_datalink_id(show_bridge,
8874                                     handle, &brstate, DATALINK_CLASS_BRIDGE,
8875                                     DATALINK_ANY_MEDIATYPE, flags);
8876                         } else {
8877                                 (void) show_bridge(handle, linkid, &brstate);
8878                                 if (brstate.state.ls_status !=
8879                                     DLADM_STATUS_OK) {
8880                                         die_dlerr(brstate.state.ls_status,
8881                                             "failed to show bridge %s",
8882                                             brstate.bridge);
8883                                 }
8884                         }
8885                         break;
8886 
8887                 case linkMode: {
8888                         datalink_id_t *dlp;
8889                         uint_t i, nlinks;
8890 
8891                         dlp = dladm_bridge_get_portlist(brstate.bridge,
8892                             &nlinks);
8893                         if (dlp != NULL) {
8894                                 for (i = 0; i < nlinks; i++)
8895                                         show_bridge_link(dlp[i], &brstate);
8896                                 dladm_bridge_free_portlist(dlp);
8897                         } else if (errno == ENOENT) {
8898                                 /* bridge not running; iterate on libdladm */
8899                                 (void) dladm_walk_datalink_id(
8900                                     show_bridge_link_walk, handle,
8901                                     &brstate, DATALINK_CLASS_PHYS |
8902                                     DATALINK_CLASS_AGGR |
8903                                     DATALINK_CLASS_ETHERSTUB,
8904                                     DATALINK_ANY_MEDIATYPE, flags);
8905                         } else {
8906                                 die("unable to get port list for bridge %s: %s",
8907                                     brstate.bridge, strerror(errno));
8908                         }
8909                         break;
8910                 }
8911 
8912                 case fwdMode: {
8913                         bridge_listfwd_t *blf;
8914                         uint_t i, nfwd;
8915 
8916                         blf = dladm_bridge_get_fwdtable(handle, brstate.bridge,
8917                             &nfwd);
8918                         if (blf == NULL) {
8919                                 die("unable to get forwarding entries for "
8920                                     "bridge %s", brstate.bridge);
8921                         } else {
8922                                 for (i = 0; i < nfwd; i++)
8923                                         show_bridge_fwd(handle, blf + i,
8924                                             &brstate.state);
8925                                 dladm_bridge_free_fwdtable(blf);
8926                         }
8927                         break;
8928                 }
8929 
8930                 case trillMode: {
8931                         trill_listnick_t *tln;
8932                         uint_t i, nnick;
8933 
8934                         tln = dladm_bridge_get_trillnick(brstate.bridge,
8935                             &nnick);
8936                         if (tln == NULL) {
8937                                 if (errno == ENOENT)
8938                                         die("bridge %s is not running TRILL",
8939                                             brstate.bridge);
8940                                 else
8941                                         die("unable to get TRILL nickname "
8942                                             "entries for bridge %s",
8943                                             brstate.bridge);
8944                         } else {
8945                                 for (i = 0; i < nnick; i++)
8946                                         show_bridge_trillnick(tln + i,
8947                                             &brstate.state);
8948                                 dladm_bridge_free_trillnick(tln);
8949                         }
8950                         break;
8951                 }
8952                 }
8953                 if (interval == 0)
8954                         break;
8955                 (void) sleep(interval);
8956         }
8957 }
8958 
8959 /*
8960  * "-R" option support. It is used for live upgrading. Append dladm commands
8961  * to a upgrade script which will be run when the alternative root boots up:
8962  *
8963  * - If the /etc/dladm/datalink.conf file exists on the alternative root,
8964  * append dladm commands to the <altroot>/var/svc/profile/upgrade_datalink
8965  * script. This script will be run as part of the network/physical service.
8966  * We cannot defer this to /var/svc/profile/upgrade because then the
8967  * configuration will not be able to take effect before network/physical
8968  * plumbs various interfaces.
8969  *
8970  * - If the /etc/dladm/datalink.conf file does not exist on the alternative
8971  * root, append dladm commands to the <altroot>/var/svc/profile/upgrade script,
8972  * which will be run in the manifest-import service.
8973  *
8974  * Note that the SMF team is considering to move the manifest-import service
8975  * to be run at the very begining of boot. Once that is done, the need for
8976  * the /var/svc/profile/upgrade_datalink script will not exist any more.
8977  */
8978 static void
8979 altroot_cmd(char *altroot, int argc, char *argv[])
8980 {
8981         char            path[MAXPATHLEN];
8982         struct stat     stbuf;
8983         FILE            *fp;
8984         int             i;
8985 
8986         /*
8987          * Check for the existence of the /etc/dladm/datalink.conf
8988          * configuration file, and determine the name of script file.
8989          */
8990         (void) snprintf(path, MAXPATHLEN, "/%s/etc/dladm/datalink.conf",
8991             altroot);
8992         if (stat(path, &stbuf) < 0) {
8993                 (void) snprintf(path, MAXPATHLEN, "/%s/%s", altroot,
8994                     SMF_UPGRADE_FILE);
8995         } else {
8996                 (void) snprintf(path, MAXPATHLEN, "/%s/%s", altroot,
8997                     SMF_UPGRADEDATALINK_FILE);
8998         }
8999 
9000         if ((fp = fopen(path, "a+")) == NULL)
9001                 die("operation not supported on %s", altroot);
9002 
9003         (void) fprintf(fp, "/sbin/dladm ");
9004         for (i = 0; i < argc; i++) {
9005                 /*
9006                  * Directly write to the file if it is not the "-R <altroot>"
9007                  * option. In which case, skip it.
9008                  */
9009                 if (strcmp(argv[i], "-R") != 0)
9010                         (void) fprintf(fp, "%s ", argv[i]);
9011                 else
9012                         i ++;
9013         }
9014         (void) fprintf(fp, "%s\n", SMF_DLADM_UPGRADE_MSG);
9015         (void) fclose(fp);
9016         dladm_close(handle);
9017         exit(EXIT_SUCCESS);
9018 }
9019 
9020 /*
9021  * Convert the string to an integer. Note that the string must not have any
9022  * trailing non-integer characters.
9023  */
9024 static boolean_t
9025 str2int(const char *str, int *valp)
9026 {
9027         int     val;
9028         char    *endp = NULL;
9029 
9030         errno = 0;
9031         val = strtol(str, &endp, 10);
9032         if (errno != 0 || *endp != '\0')
9033                 return (B_FALSE);
9034 
9035         *valp = val;
9036         return (B_TRUE);
9037 }
9038 
9039 /* PRINTFLIKE1 */
9040 static void
9041 warn(const char *format, ...)
9042 {
9043         va_list alist;
9044 
9045         format = gettext(format);
9046         (void) fprintf(stderr, "%s: warning: ", progname);
9047 
9048         va_start(alist, format);
9049         (void) vfprintf(stderr, format, alist);
9050         va_end(alist);
9051 
9052         (void) putc('\n', stderr);
9053 }
9054 
9055 /* PRINTFLIKE2 */
9056 static void
9057 warn_dlerr(dladm_status_t err, const char *format, ...)
9058 {
9059         va_list alist;
9060         char    errmsg[DLADM_STRSIZE];
9061 
9062         format = gettext(format);
9063         (void) fprintf(stderr, gettext("%s: warning: "), progname);
9064 
9065         va_start(alist, format);
9066         (void) vfprintf(stderr, format, alist);
9067         va_end(alist);
9068         (void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg));
9069 }
9070 
9071 static void
9072 warn_dlerrlist(dladm_errlist_t *errlist)
9073 {
9074         if (errlist != NULL && errlist->el_count > 0) {
9075                 int i;
9076                 for (i = 0; i < errlist->el_count; i++) {
9077                         (void) fprintf(stderr, gettext("%s: warning: "),
9078                             progname);
9079 
9080                         (void) fprintf(stderr, "%s\n",
9081                             gettext(errlist->el_errs[i]));
9082                 }
9083         }
9084 }
9085 
9086 /*
9087  * Also closes the dladm handle if it is not NULL.
9088  */
9089 /* PRINTFLIKE2 */
9090 static void
9091 die_dlerr(dladm_status_t err, const char *format, ...)
9092 {
9093         va_list alist;
9094         char    errmsg[DLADM_STRSIZE];
9095 
9096         format = gettext(format);
9097         (void) fprintf(stderr, "%s: ", progname);
9098 
9099         va_start(alist, format);
9100         (void) vfprintf(stderr, format, alist);
9101         va_end(alist);
9102         (void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg));
9103 
9104         /* close dladm handle if it was opened */
9105         if (handle != NULL)
9106                 dladm_close(handle);
9107 
9108         exit(EXIT_FAILURE);
9109 }
9110 
9111 /*
9112  * Like die_dlerr, but uses the errlist for additional information.
9113  */
9114 /* PRINTFLIKE3 */
9115 static void
9116 die_dlerrlist(dladm_status_t err, dladm_errlist_t *errlist,
9117     const char *format, ...)
9118 {
9119         va_list alist;
9120         char    errmsg[DLADM_STRSIZE];
9121 
9122         warn_dlerrlist(errlist);
9123         format = gettext(format);
9124         (void) fprintf(stderr, "%s: ", progname);
9125 
9126         va_start(alist, format);
9127         (void) vfprintf(stderr, format, alist);
9128         va_end(alist);
9129         (void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg));
9130 
9131         /* close dladm handle if it was opened */
9132         if (handle != NULL)
9133                 dladm_close(handle);
9134 
9135         exit(EXIT_FAILURE);
9136 
9137 }
9138 
9139 /* PRINTFLIKE1 */
9140 static void
9141 die(const char *format, ...)
9142 {
9143         va_list alist;
9144 
9145         format = gettext(format);
9146         (void) fprintf(stderr, "%s: ", progname);
9147 
9148         va_start(alist, format);
9149         (void) vfprintf(stderr, format, alist);
9150         va_end(alist);
9151 
9152         (void) putc('\n', stderr);
9153 
9154         /* close dladm handle if it was opened */
9155         if (handle != NULL)
9156                 dladm_close(handle);
9157 
9158         exit(EXIT_FAILURE);
9159 }
9160 
9161 static void
9162 die_optdup(int opt)
9163 {
9164         die("the option -%c cannot be specified more than once", opt);
9165 }
9166 
9167 static void
9168 die_opterr(int opt, int opterr, const char *usage)
9169 {
9170         switch (opterr) {
9171         case ':':
9172                 die("option '-%c' requires a value\nusage: %s", opt,
9173                     gettext(usage));
9174                 break;
9175         case '?':
9176         default:
9177                 die("unrecognized option '-%c'\nusage: %s", opt,
9178                     gettext(usage));
9179                 break;
9180         }
9181 }
9182 
9183 static void
9184 show_ether_xprop(void *arg, dladm_ether_info_t *eattr)
9185 {
9186         print_ether_state_t     *statep = arg;
9187         ether_fields_buf_t      ebuf;
9188         int                     i;
9189 
9190         for (i = CAPABLE; i <= PEERADV; i++)  {
9191                 bzero(&ebuf, sizeof (ebuf));
9192                 (void) strlcpy(ebuf.eth_ptype, ptype[i],
9193                     sizeof (ebuf.eth_ptype));
9194                 (void) dladm_ether_autoneg2str(ebuf.eth_autoneg,
9195                     sizeof (ebuf.eth_autoneg), eattr, i);
9196                 (void) dladm_ether_spdx2str(ebuf.eth_spdx,
9197                     sizeof (ebuf.eth_spdx), eattr, i);
9198                 (void) dladm_ether_pause2str(ebuf.eth_pause,
9199                     sizeof (ebuf.eth_pause), eattr, i);
9200                 (void) strlcpy(ebuf.eth_rem_fault,
9201                     (eattr->lei_attr[i].le_fault ? "fault" : "none"),
9202                     sizeof (ebuf.eth_rem_fault));
9203                 ofmt_print(statep->es_ofmt, &ebuf);
9204         }
9205 
9206 }
9207 
9208 static boolean_t
9209 link_is_ether(const char *link, datalink_id_t *linkid)
9210 {
9211         uint32_t media;
9212         datalink_class_t class;
9213 
9214         if (dladm_name2info(handle, link, linkid, NULL, &class, &media) ==
9215             DLADM_STATUS_OK) {
9216                 if (class == DATALINK_CLASS_PHYS && media == DL_ETHER)
9217                         return (B_TRUE);
9218         }
9219         return (B_FALSE);
9220 }
9221 
9222 /*
9223  * default output callback function that, when invoked,
9224  * prints string which is offset by ofmt_arg->ofmt_id within buf.
9225  */
9226 static boolean_t
9227 print_default_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
9228 {
9229         char *value;
9230 
9231         value = (char *)ofarg->ofmt_cbarg + ofarg->ofmt_id;
9232         (void) strlcpy(buf, value, bufsize);
9233         return (B_TRUE);
9234 }
9235 
9236 /*
9237  * Called from the walker dladm_walk_datalink_id() for each IB partition to
9238  * display IB partition specific information.
9239  */
9240 static dladm_status_t
9241 print_part(show_part_state_t *state, datalink_id_t linkid)
9242 {
9243         dladm_part_attr_t       attr;
9244         dladm_status_t          status;
9245         dladm_conf_t            conf;
9246         char                    part_over[MAXLINKNAMELEN];
9247         char                    part_name[MAXLINKNAMELEN];
9248         part_fields_buf_t       pbuf;
9249         boolean_t               force_in_conf = B_FALSE;
9250 
9251         /*
9252          * Get the information about the IB partition from the partition
9253          * datlink ID 'linkid'.
9254          */
9255         if ((status = dladm_part_info(handle, linkid, &attr, state->ps_flags))
9256             != DLADM_STATUS_OK)
9257                 return (status);
9258 
9259         /*
9260          * If an IB Phys link name was provided on the command line we have
9261          * the Phys link's datalink ID in the ps_over_id field of the state
9262          * structure. Proceed only if the IB partition represented by 'linkid'
9263          * was created over Phys link denoted by ps_over_id. The
9264          * 'dia_physlinkid' field of dladm_part_attr_t represents the IB Phys
9265          * link over which the partition was created.
9266          */
9267         if (state->ps_over_id != DATALINK_ALL_LINKID)
9268                 if (state->ps_over_id != attr.dia_physlinkid)
9269                         return (DLADM_STATUS_OK);
9270 
9271         /*
9272          * The linkid argument passed to this function is the datalink ID
9273          * of the IB Partition. Get the partitions name from this linkid.
9274          */
9275         if (dladm_datalink_id2info(handle, linkid, NULL, NULL,
9276             NULL, part_name, sizeof (part_name)) != DLADM_STATUS_OK)
9277                 return (DLADM_STATUS_BADARG);
9278 
9279         bzero(part_over, sizeof (part_over));
9280 
9281         /*
9282          * The 'dia_physlinkid' field contains the datalink ID of the IB Phys
9283          * link over which the partition was created. Use this linkid to get the
9284          * linkover field.
9285          */
9286         if (dladm_datalink_id2info(handle, attr.dia_physlinkid, NULL, NULL,
9287             NULL, part_over, sizeof (part_over)) != DLADM_STATUS_OK)
9288                 (void) sprintf(part_over, "?");
9289         state->ps_found = B_TRUE;
9290 
9291         /*
9292          * Read the FFORCE field from this datalink's persistent configuration
9293          * database line to determine if this datalink was created forcibly.
9294          * If this datalink is a temporary datalink, then it will not have an
9295          * entry in the persistent configuration, so check if force create flag
9296          * is set in the partition attributes.
9297          *
9298          * We need this two level check since persistent partitions brought up
9299          * by up-part during boot will have force create flag always set, since
9300          * we want up-part to always succeed even if the port is currently down
9301          * or P_Key is not yet available in the subnet.
9302          */
9303         if ((status = dladm_getsnap_conf(handle, linkid, &conf)) ==
9304             DLADM_STATUS_OK) {
9305                 (void) dladm_get_conf_field(handle, conf, FFORCE,
9306                     &force_in_conf, sizeof (boolean_t));
9307                 dladm_destroy_conf(handle, conf);
9308         } else if (status == DLADM_STATUS_NOTFOUND) {
9309                 /*
9310                  * for a temp link the force create flag will determine
9311                  * whether it was created with force flag.
9312                  */
9313                 force_in_conf = ((attr.dia_flags & DLADM_PART_FORCE_CREATE)
9314                     != 0);
9315         }
9316 
9317         (void) snprintf(pbuf.part_link, sizeof (pbuf.part_link),
9318             "%s", part_name);
9319 
9320         (void) snprintf(pbuf.part_over, sizeof (pbuf.part_over),
9321             "%s", part_over);
9322 
9323         (void) snprintf(pbuf.part_pkey, sizeof (pbuf.part_pkey),
9324             "%X", attr.dia_pkey);
9325 
9326         (void) get_linkstate(pbuf.part_link, B_TRUE, pbuf.part_state);
9327 
9328         (void) snprintf(pbuf.part_flags, sizeof (pbuf.part_flags),
9329             "%c----", force_in_conf ? 'f' : '-');
9330 
9331         ofmt_print(state->ps_ofmt, &pbuf);
9332 
9333         return (DLADM_STATUS_OK);
9334 }
9335 
9336 /* ARGSUSED */
9337 static int
9338 show_part(dladm_handle_t dh, datalink_id_t linkid, void *arg)
9339 {
9340         ((show_part_state_t *)arg)->ps_status = print_part(arg, linkid);
9341         return (DLADM_WALK_CONTINUE);
9342 }
9343 
9344 /*
9345  * Show the information about the IB partition objects.
9346  */
9347 static void
9348 do_show_part(int argc, char *argv[], const char *use)
9349 {
9350         int                     option;
9351         boolean_t               l_arg = B_FALSE;
9352         uint32_t                flags = DLADM_OPT_ACTIVE;
9353         datalink_id_t           linkid = DATALINK_ALL_LINKID;
9354         datalink_id_t           over_linkid = DATALINK_ALL_LINKID;
9355         char                    over_link[MAXLINKNAMELEN];
9356         show_part_state_t       state;
9357         dladm_status_t          status;
9358         boolean_t               o_arg = B_FALSE;
9359         char                    *fields_str = NULL;
9360         ofmt_handle_t           ofmt;
9361         ofmt_status_t           oferr;
9362         uint_t                  ofmtflags = 0;
9363 
9364         bzero(&state, sizeof (state));
9365         opterr = 0;
9366         while ((option = getopt_long(argc, argv, ":pPl:o:", show_part_lopts,
9367             NULL)) != -1) {
9368                 switch (option) {
9369                 case 'p':
9370                         state.ps_parsable = B_TRUE;
9371                         break;
9372                 case 'P':
9373                         flags = DLADM_OPT_PERSIST;
9374                         break;
9375                 case 'l':
9376                         /*
9377                          * The data link ID of the IB Phys link. When this
9378                          * argument is provided we list only the partition
9379                          * objects created over this IB Phys link.
9380                          */
9381                         if (strlcpy(over_link, optarg, MAXLINKNAMELEN) >=
9382                             MAXLINKNAMELEN)
9383                                 die("link name too long");
9384 
9385                         l_arg = B_TRUE;
9386                         break;
9387                 case 'o':
9388                         o_arg = B_TRUE;
9389                         fields_str = optarg;
9390                         break;
9391                 default:
9392                         die_opterr(optopt, option, use);
9393                 }
9394         }
9395 
9396         /*
9397          * Get the partition ID (optional last argument).
9398          */
9399         if (optind == (argc - 1)) {
9400                 status = dladm_name2info(handle, argv[optind], &linkid, NULL,
9401                     NULL, NULL);
9402                 if (status != DLADM_STATUS_OK) {
9403                         die_dlerr(status, "invalid partition link name '%s'",
9404                             argv[optind]);
9405                 }
9406                 (void) strlcpy(state.ps_part, argv[optind], MAXLINKNAMELEN);
9407         } else if (optind != argc) {
9408                 usage();
9409         }
9410 
9411         if (state.ps_parsable && !o_arg)
9412                 die("-p requires -o");
9413 
9414         /*
9415          * If an IB Phys link name was provided as an argument, then get its
9416          * datalink ID.
9417          */
9418         if (l_arg) {
9419                 status = dladm_name2info(handle, over_link, &over_linkid, NULL,
9420                     NULL, NULL);
9421                 if (status != DLADM_STATUS_OK) {
9422                         die_dlerr(status, "invalid link name '%s'", over_link);
9423                 }
9424         }
9425 
9426         state.ps_over_id = over_linkid; /* IB Phys link ID */
9427         state.ps_found = B_FALSE;
9428         state.ps_flags = flags;
9429 
9430         if (state.ps_parsable)
9431                 ofmtflags |= OFMT_PARSABLE;
9432         oferr = ofmt_open(fields_str, part_fields, ofmtflags, 0, &ofmt);
9433         ofmt_check(oferr, state.ps_parsable, ofmt, die, warn);
9434         state.ps_ofmt = ofmt;
9435 
9436         /*
9437          * If a specific IB partition name was not provided as an argument,
9438          * walk all the datalinks and display the information for all
9439          * IB partitions. If IB Phys link was provided limit it to only
9440          * IB partitions created over that IB Phys link.
9441          */
9442         if (linkid == DATALINK_ALL_LINKID) {
9443                 (void) dladm_walk_datalink_id(show_part, handle, &state,
9444                     DATALINK_CLASS_PART, DATALINK_ANY_MEDIATYPE, flags);
9445         } else {
9446                 (void) show_part(handle, linkid, &state);
9447                 if (state.ps_status != DLADM_STATUS_OK) {
9448                         ofmt_close(ofmt);
9449                         die_dlerr(state.ps_status, "failed to show IB partition"
9450                             " '%s'", state.ps_part);
9451                 }
9452         }
9453         ofmt_close(ofmt);
9454 }
9455 
9456 
9457 /*
9458  * Called from the walker dladm_walk_datalink_id() for each IB Phys link to
9459  * display IB specific information for these Phys links.
9460  */
9461 static dladm_status_t
9462 print_ib(show_ib_state_t *state, datalink_id_t phys_linkid)
9463 {
9464         dladm_ib_attr_t         attr;
9465         dladm_status_t          status;
9466         char                    linkname[MAXLINKNAMELEN];
9467         char                    pkeystr[MAXPKEYLEN];
9468         int                     i;
9469         ib_fields_buf_t         ibuf;
9470 
9471         bzero(&attr, sizeof (attr));
9472 
9473         /*
9474          * Get the attributes of the IB Phys link from active/Persistent config
9475          * based on the flag passed.
9476          */
9477         if ((status = dladm_ib_info(handle, phys_linkid, &attr,
9478             state->is_flags)) != DLADM_STATUS_OK)
9479                 return (status);
9480 
9481         if ((state->is_link_id != DATALINK_ALL_LINKID) && (state->is_link_id
9482             != attr.dia_physlinkid)) {
9483                 dladm_free_ib_info(&attr);
9484                 return (DLADM_STATUS_OK);
9485         }
9486 
9487         /*
9488          * Get the data link name for the phys_linkid. If we are doing show-ib
9489          * for all IB Phys links, we have only the datalink IDs not the
9490          * datalink name.
9491          */
9492         if (dladm_datalink_id2info(handle, phys_linkid, NULL, NULL, NULL,
9493             linkname, MAXLINKNAMELEN) != DLADM_STATUS_OK)
9494                 return (status);
9495 
9496         (void) snprintf(ibuf.ib_link, sizeof (ibuf.ib_link),
9497             "%s", linkname);
9498 
9499         (void) snprintf(ibuf.ib_portnum, sizeof (ibuf.ib_portnum),
9500             "%d", attr.dia_portnum);
9501 
9502         (void) snprintf(ibuf.ib_hcaguid, sizeof (ibuf.ib_hcaguid),
9503             "%llX", attr.dia_hca_guid);
9504 
9505         (void) snprintf(ibuf.ib_portguid, sizeof (ibuf.ib_portguid),
9506             "%llX", attr.dia_port_guid);
9507 
9508         (void) get_linkstate(linkname, B_TRUE, ibuf.ib_state);
9509 
9510         /*
9511          * Create a comma separated list of pkeys from the pkey table returned
9512          * by the IP over IB driver instance.
9513          */
9514         bzero(ibuf.ib_pkeys, attr.dia_port_pkey_tbl_sz * sizeof (ib_pkey_t));
9515         for (i = 0; i < attr.dia_port_pkey_tbl_sz; i++) {
9516                 if (attr.dia_port_pkeys[i] != IB_PKEY_INVALID_FULL &&
9517                     attr.dia_port_pkeys[i] != IB_PKEY_INVALID_LIMITED) {
9518                         if (i == 0)
9519                                 (void) snprintf(pkeystr, MAXPKEYLEN, "%X",
9520                                     attr.dia_port_pkeys[i]);
9521                         else
9522                                 (void) snprintf(pkeystr, MAXPKEYLEN, ",%X",
9523                                     attr.dia_port_pkeys[i]);
9524                         (void) strlcat(ibuf.ib_pkeys, pkeystr, MAXPKEYSTRSZ);
9525                 }
9526         }
9527 
9528         dladm_free_ib_info(&attr);
9529 
9530         ofmt_print(state->is_ofmt, &ibuf);
9531 
9532         return (DLADM_STATUS_OK);
9533 }
9534 
9535 /* ARGSUSED */
9536 static int
9537 show_ib(dladm_handle_t dh, datalink_id_t linkid, void *arg)
9538 {
9539         ((show_ib_state_t *)arg)->is_status = print_ib(arg, linkid);
9540         return (DLADM_WALK_CONTINUE);
9541 }
9542 
9543 /*
9544  * Show the properties of one/all IB Phys links. This is different from
9545  * show-phys command since this will display IB specific information about the
9546  * Phys link like, HCA GUID, PORT GUID, PKEYS active for this port etc.
9547  */
9548 static void
9549 do_show_ib(int argc, char *argv[], const char *use)
9550 {
9551         int                     option;
9552         uint32_t                flags = DLADM_OPT_ACTIVE;
9553         datalink_id_t           linkid = DATALINK_ALL_LINKID;
9554         show_ib_state_t         state;
9555         dladm_status_t          status;
9556         boolean_t               o_arg = B_FALSE;
9557         char                    *fields_str = NULL;
9558         ofmt_handle_t           ofmt;
9559         ofmt_status_t           oferr;
9560         uint_t                  ofmtflags = 0;
9561 
9562         bzero(&state, sizeof (state));
9563         opterr = 0;
9564         while ((option = getopt_long(argc, argv, ":po:", show_lopts,
9565             NULL)) != -1) {
9566                 switch (option) {
9567                 case 'p':
9568                         state.is_parsable = B_TRUE;
9569                         break;
9570                 case 'o':
9571                         o_arg = B_TRUE;
9572                         fields_str = optarg;
9573                         break;
9574                 default:
9575                         die_opterr(optopt, option, use);
9576                 }
9577         }
9578 
9579         /* get IB Phys link ID (optional last argument) */
9580         if (optind == (argc - 1)) {
9581                 status = dladm_name2info(handle, argv[optind], &linkid, NULL,
9582                     NULL, NULL);
9583                 if (status != DLADM_STATUS_OK) {
9584                         die_dlerr(status, "invalid IB port name '%s'",
9585                             argv[optind]);
9586                 }
9587                 (void) strlcpy(state.is_link, argv[optind], MAXLINKNAMELEN);
9588         } else if (optind != argc) {
9589                 usage();
9590         }
9591 
9592         if (state.is_parsable && !o_arg)
9593                 die("-p requires -o");
9594 
9595         /*
9596          * linkid is the data link ID of the IB Phys link. By default it will
9597          * be DATALINK_ALL_LINKID.
9598          */
9599         state.is_link_id = linkid;
9600         state.is_flags = flags;
9601 
9602         if (state.is_parsable)
9603                 ofmtflags |= OFMT_PARSABLE;
9604         oferr = ofmt_open(fields_str, ib_fields, ofmtflags, 0, &ofmt);
9605         ofmt_check(oferr, state.is_parsable, ofmt, die, warn);
9606         state.is_ofmt = ofmt;
9607 
9608         /*
9609          * If we are going to display the information for all IB Phys links
9610          * then we'll walk through all the datalinks for datalinks of Phys
9611          * class and media type IB.
9612          */
9613         if (linkid == DATALINK_ALL_LINKID) {
9614                 (void) dladm_walk_datalink_id(show_ib, handle, &state,
9615                     DATALINK_CLASS_PHYS, DL_IB, flags);
9616         } else {
9617                 /*
9618                  * We need to display the information only for the IB phys link
9619                  * linkid. Call show_ib for this link.
9620                  */
9621                 (void) show_ib(handle, linkid, &state);
9622                 if (state.is_status != DLADM_STATUS_OK) {
9623                         ofmt_close(ofmt);
9624                         die_dlerr(state.is_status, "failed to show IB Phys link"
9625                             " '%s'", state.is_link);
9626                 }
9627         }
9628         ofmt_close(ofmt);
9629 }
9630 
9631 /*
9632  * Create an IP over Infiniband partition object over an IB Phys link. The IB
9633  * Phys link is associated with an Infiniband HCA port. The IB partition object
9634  * is created over a port, pkey combination. This partition object represents
9635  * an instance of IP over IB interface.
9636  */
9637 /* ARGSUSED */
9638 static void
9639 do_create_part(int argc, char *argv[], const char *use)
9640 {
9641         int             status, option;
9642         int             flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
9643         char            *pname;
9644         char            *l_arg = NULL;
9645         char            *altroot = NULL;
9646         datalink_id_t   physlinkid = 0;
9647         datalink_id_t   partlinkid = 0;
9648         unsigned long   opt_pkey;
9649         ib_pkey_t       pkey = 0;
9650         char            *endp = NULL;
9651         char            propstr[DLADM_STRSIZE];
9652         dladm_arg_list_t        *proplist = NULL;
9653 
9654         propstr[0] = '\0';
9655         while ((option = getopt_long(argc, argv, ":tfl:P:R:p:",
9656             part_lopts, NULL)) != -1) {
9657                 switch (option) {
9658                 case 't':
9659                         /*
9660                          * Create a temporary IB partition object. This
9661                          * instance is not entered into the persistent database
9662                          * so it will not be recreated automatically on a
9663                          * reboot.
9664                          */
9665                         flags &= ~DLADM_OPT_PERSIST;
9666                         break;
9667                 case 'l':
9668                         /*
9669                          * The IB phys link over which the partition object will
9670                          * be created.
9671                          */
9672                         l_arg = optarg;
9673                         break;
9674                 case 'R':
9675                         altroot = optarg;
9676                         break;
9677                 case 'p':
9678                         (void) strlcat(propstr, optarg, DLADM_STRSIZE);
9679                         if (strlcat(propstr, ",", DLADM_STRSIZE) >=
9680                             DLADM_STRSIZE)
9681                                 die("property list too long '%s'", propstr);
9682                         break;
9683                 case 'P':
9684                         /*
9685                          * The P_Key for the port, pkey tuple of the partition
9686                          * object. This P_Key should exist in the IB subnet.
9687                          * The partition creation for a non-existent P_Key will
9688                          * fail unless the -f option is used.
9689                          *
9690                          * The P_Key is expected to be a hexadecimal number.
9691                          */
9692                         opt_pkey = strtoul(optarg, &endp, 16);
9693                         if (errno == ERANGE || opt_pkey > USHRT_MAX ||
9694                             *endp != '\0')
9695                                 die("Invalid pkey");
9696 
9697                         pkey = (ib_pkey_t)opt_pkey;
9698                         break;
9699                 case 'f':
9700                         flags |= DLADM_OPT_FORCE;
9701                         break;
9702                 default:
9703                         die_opterr(optopt, option, use);
9704                         break;
9705                 }
9706         }
9707 
9708         /* check required options */
9709         if (!l_arg)
9710                 usage();
9711 
9712         /* the partition name is a required operand */
9713         if (optind != (argc - 1))
9714                 usage();
9715 
9716         pname = argv[argc - 1];
9717 
9718         /*
9719          * Verify that the partition object's name is in the valid link name
9720          * format.
9721          */
9722         if (!dladm_valid_linkname(pname))
9723                 die("Invalid link name '%s'", pname);
9724 
9725         /* pkey is a mandatory argument */
9726         if (pkey == 0)
9727                 usage();
9728 
9729         if (altroot != NULL)
9730                 altroot_cmd(altroot, argc, argv);
9731 
9732         /*
9733          * Get the data link id of the IB Phys link over which we will be
9734          * creating partition object.
9735          */
9736         if (dladm_name2info(handle, l_arg,
9737             &physlinkid, NULL, NULL, NULL) != DLADM_STATUS_OK)
9738                 die("invalid link name '%s'", l_arg);
9739 
9740         /*
9741          * parse the property list provided with -p option.
9742          */
9743         if (dladm_parse_link_props(propstr, &proplist, B_FALSE)
9744             != DLADM_STATUS_OK)
9745                 die("invalid IB partition property");
9746 
9747         /*
9748          * Call the library routine to create the partition object.
9749          */
9750         status = dladm_part_create(handle, physlinkid, pkey, flags, pname,
9751             &partlinkid, proplist);
9752         if (status != DLADM_STATUS_OK)
9753                 die_dlerr(status,
9754                     "partition %x creation over %s failed", pkey, l_arg);
9755 }
9756 
9757 /*
9758  * Delete an IP over Infiniband partition object. The partition object should
9759  * be unplumbed before attempting the delete.
9760  */
9761 static void
9762 do_delete_part(int argc, char *argv[], const char *use)
9763 {
9764         int option, flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
9765         int status;
9766         char *altroot = NULL;
9767         datalink_id_t   partid;
9768 
9769         opterr = 0;
9770         while ((option = getopt_long(argc, argv, "R:t", part_lopts,
9771             NULL)) != -1) {
9772                 switch (option) {
9773                 case 't':
9774                         flags &= ~DLADM_OPT_PERSIST;
9775                         break;
9776                 case 'R':
9777                         altroot = optarg;
9778                         break;
9779                 default:
9780                         die_opterr(optopt, option, use);
9781                 }
9782         }
9783 
9784         /* get partition name (required last argument) */
9785         if (optind != (argc - 1))
9786                 usage();
9787 
9788         if (altroot != NULL)
9789                 altroot_cmd(altroot, argc, argv);
9790 
9791         /*
9792          * Get the data link id of the partition object given the partition
9793          * name.
9794          */
9795         status = dladm_name2info(handle, argv[optind], &partid, NULL, NULL,
9796             NULL);
9797         if (status != DLADM_STATUS_OK)
9798                 die("invalid link name '%s'", argv[optind]);
9799 
9800         /*
9801          * Call the library routine to delete the IB partition. This will
9802          * result in the IB partition object and all its resources getting
9803          * deleted.
9804          */
9805         status = dladm_part_delete(handle, partid, flags);
9806         if (status != DLADM_STATUS_OK)
9807                 die_dlerr(status, "%s: partition deletion failed",
9808                     argv[optind]);
9809 }
9810 
9811 /*
9812  * Bring up all or one IB partition already present in the persistent database
9813  * but not active yet.
9814  *
9815  * This sub-command is used during the system boot up to bring up all IB
9816  * partitions present in the persistent database. This is similar to a
9817  * create partition except that, the partitions are always created even if the
9818  * HCA port is down or P_Key is not present in the IB subnet. This is similar
9819  * to using the 'force' option while creating the partition except that the 'f'
9820  * flag will be set in the flags field only if the create-part for this command
9821  * was called with '-f' option.
9822  */
9823 /* ARGSUSED */
9824 static void
9825 do_up_part(int argc, char *argv[], const char *use)
9826 {
9827         datalink_id_t   partid = DATALINK_ALL_LINKID;
9828         dladm_status_t status;
9829 
9830         /*
9831          * If a partition name was passed as an argument, get its data link
9832          * id. By default we'll attempt to bring up all IB partition data
9833          * links.
9834          */
9835         if (argc == 2) {
9836                 status = dladm_name2info(handle, argv[argc - 1], &partid, NULL,
9837                     NULL, NULL);
9838                 if (status != DLADM_STATUS_OK)
9839                         return;
9840         } else if (argc > 2) {
9841                 usage();
9842         }
9843 
9844         (void) dladm_part_up(handle, partid, 0);
9845 }
9846 
9847 static void
9848 do_create_overlay(int argc, char *argv[], const char *use)
9849 {
9850         int                     opt;
9851         char                    *encap = NULL, *endp, *search = NULL;
9852         char                    name[MAXLINKNAMELEN];
9853         dladm_status_t          status;
9854         uint32_t                flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
9855         uint64_t                vid;
9856         boolean_t               havevid = B_FALSE;
9857         char                    propstr[DLADM_STRSIZE];
9858         dladm_arg_list_t        *proplist = NULL;
9859 
9860         bzero(propstr, sizeof (propstr));
9861         while ((opt = getopt_long(argc, argv, ":te:v:p:s:",
9862             overlay_create_lopts, NULL)) != -1) {
9863                 switch (opt) {
9864                 case 'e':
9865                         encap = optarg;
9866                         break;
9867                 case 's':
9868                         search = optarg;
9869                         break;
9870                 case 't':
9871                         flags &= ~DLADM_OPT_PERSIST;
9872                         break;
9873                 case 'p':
9874                         (void) strlcat(propstr, optarg, DLADM_STRSIZE);
9875                         if (strlcat(propstr, ",", DLADM_STRSIZE) >=
9876                             DLADM_STRSIZE)
9877                                 die("property list too long '%s'", propstr);
9878                         break;
9879                 case 'v':
9880                         vid = strtoul(optarg, &endp, 10);
9881                         if (*endp != '\0' || (vid == 0 && errno == EINVAL))
9882                                 die("couldn't parse virtual networkd id: %s",
9883                                     optarg);
9884                         if (vid == ULONG_MAX && errno == ERANGE)
9885                                 die("virtual networkd id too large: %s",
9886                                     optarg);
9887                         havevid = B_TRUE;
9888                         break;
9889                 default:
9890                         die_opterr(optopt, opt, use);
9891                 }
9892         }
9893 
9894         if (havevid == B_FALSE)
9895                 die("missing required virtual network id");
9896 
9897         if (encap == NULL)
9898                 die("missing required encapsulation plugin");
9899 
9900         if (search == NULL)
9901                 die("missing required search plugin");
9902 
9903         if (optind != (argc - 1))
9904                 die("missing device name");
9905 
9906         if (strlcpy(name, argv[optind], MAXLINKNAMELEN) >= MAXLINKNAMELEN)
9907                 die("link name too long '%s'", argv[optind]);
9908 
9909         if (!dladm_valid_linkname(name))
9910                 die("invalid link name '%s'", argv[optind]);
9911 
9912         if (strlen(encap) + 1 > MAXLINKNAMELEN)
9913                 die("encapsulation plugin name too long '%s'", encap);
9914 
9915         if (strlen(search) + 1 > MAXLINKNAMELEN)
9916                 die("search plugin name too long '%s'", encap);
9917 
9918         if (dladm_parse_link_props(propstr, &proplist, B_FALSE)
9919             != DLADM_STATUS_OK)
9920                 die("invalid overlay property");
9921 
9922         status = dladm_overlay_create(handle, name, encap, search, vid,
9923             proplist, &errlist, flags);
9924         dladm_free_props(proplist);
9925         if (status != DLADM_STATUS_OK) {
9926                 die_dlerrlist(status, &errlist, "overlay creation failed");
9927         }
9928 }
9929 
9930 /* ARGSUSED */
9931 static void
9932 do_delete_overlay(int argc, char *argv[], const char *use)
9933 {
9934         datalink_id_t   linkid = DATALINK_ALL_LINKID;
9935         dladm_status_t  status;
9936         int option;
9937         uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
9938 
9939         opterr = 0;
9940         while ((option = getopt_long(argc, argv, ":t", lopts,
9941             NULL)) != -1) {
9942                 switch (option) {
9943                 case 't':
9944                         flags &= ~DLADM_OPT_PERSIST;
9945                         break;
9946                 default:
9947                         die_opterr(optopt, option, use);
9948                 }
9949         }
9950 
9951         /* get overlay name (required last argument) */
9952         if (optind != (argc - 1))
9953                 usage();
9954 
9955         status = dladm_name2info(handle, argv[optind], &linkid,
9956             NULL, NULL, NULL);
9957         if (status != DLADM_STATUS_OK)
9958                 die_dlerr(status, "failed to delete %s", argv[optind]);
9959 
9960         status = dladm_overlay_delete(handle, linkid, flags);
9961         if (status != DLADM_STATUS_OK)
9962                 die_dlerr(status, "failed to delete %s", argv[optind]);
9963 }
9964 
9965 typedef struct showoverlay_state {
9966         ofmt_handle_t           sho_ofmt;
9967         const char              *sho_linkname;
9968         dladm_overlay_propinfo_handle_t sho_info;
9969         uint8_t                 sho_value[DLADM_OVERLAY_PROP_SIZEMAX];
9970         uint32_t                sho_size;
9971 } showoverlay_state_t;
9972 
9973 typedef struct showoverlay_fma_state {
9974         ofmt_handle_t           shof_ofmt;
9975         const char              *shof_linkname;
9976         dladm_overlay_status_t  *shof_status;
9977 } showoverlay_fma_state_t;
9978 
9979 typedef struct showoverlay_targ_state {
9980         ofmt_handle_t                   shot_ofmt;
9981         const char                      *shot_linkname;
9982         const struct ether_addr         *shot_key;
9983         const dladm_overlay_point_t     *shot_point;
9984 } showoverlay_targ_state_t;
9985 
9986 static void
9987 print_overlay_value(char *outbuf, uint_t bufsize, uint_t type, const void *pbuf,
9988     const size_t psize)
9989 {
9990         const struct in6_addr *ipv6;
9991         struct in_addr ip;
9992 
9993         switch (type) {
9994         case OVERLAY_PROP_T_INT:
9995                 if (psize != 1 && psize != 2 && psize != 4 && psize != 8) {
9996                         (void) snprintf(outbuf, bufsize, "?");
9997                         break;
9998                 }
9999                 if (psize == 1)
10000                         (void) snprintf(outbuf, bufsize, "%d", *(int8_t *)pbuf);
10001                 if (psize == 2)
10002                         (void) snprintf(outbuf, bufsize, "%d",
10003                             *(int16_t *)pbuf);
10004                 if (psize == 4)
10005                         (void) snprintf(outbuf, bufsize, "%d",
10006                             *(int32_t *)pbuf);
10007                 if (psize == 8)
10008                         (void) snprintf(outbuf, bufsize, "%d",
10009                             *(int64_t *)pbuf);
10010                 break;
10011         case OVERLAY_PROP_T_UINT:
10012                 if (psize != 1 && psize != 2 && psize != 4 && psize != 8) {
10013                         (void) snprintf(outbuf, bufsize, "?");
10014                         break;
10015                 }
10016                 if (psize == 1)
10017                         (void) snprintf(outbuf, bufsize, "%d",
10018                             *(uint8_t *)pbuf);
10019                 if (psize == 2)
10020                         (void) snprintf(outbuf, bufsize, "%d",
10021                             *(uint16_t *)pbuf);
10022                 if (psize == 4)
10023                         (void) snprintf(outbuf, bufsize, "%d",
10024                             *(uint32_t *)pbuf);
10025                 if (psize == 8)
10026                         (void) snprintf(outbuf, bufsize, "%d",
10027                             *(uint64_t *)pbuf);
10028                 break;
10029         case OVERLAY_PROP_T_IP:
10030                 if (psize != sizeof (struct in6_addr)) {
10031                         warn("malformed overlay IP property: %d bytes\n",
10032                             psize);
10033                         (void) snprintf(outbuf, bufsize, "--");
10034                         break;
10035                 }
10036 
10037                 ipv6 = pbuf;
10038                 if (IN6_IS_ADDR_V4MAPPED(ipv6)) {
10039                         IN6_V4MAPPED_TO_INADDR(ipv6, &ip);
10040                         if (inet_ntop(AF_INET, &ip, outbuf, bufsize) == NULL) {
10041                                 warn("malformed overlay IP property\n");
10042                                 (void) snprintf(outbuf, bufsize, "--");
10043                                 break;
10044                         }
10045                 } else {
10046                         if (inet_ntop(AF_INET6, ipv6, outbuf, bufsize) ==
10047                             NULL) {
10048                                 warn("malformed overlay IP property\n");
10049                                 (void) snprintf(outbuf, bufsize, "--");
10050                                 break;
10051                         }
10052                 }
10053 
10054                 break;
10055         case OVERLAY_PROP_T_STRING:
10056                 (void) snprintf(outbuf, bufsize, "%s", pbuf);
10057                 break;
10058         default:
10059                 abort();
10060         }
10061 
10062         return;
10063 
10064 }
10065 
10066 static boolean_t
10067 print_overlay_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
10068 {
10069         dladm_status_t                  status;
10070         showoverlay_state_t             *sp = ofarg->ofmt_cbarg;
10071         dladm_overlay_propinfo_handle_t infop = sp->sho_info;
10072         const char                      *pname;
10073         uint_t                          type, prot;
10074         const void                      *def;
10075         uint32_t                        defsize;
10076         const mac_propval_range_t       *rangep;
10077 
10078         if ((status = dladm_overlay_prop_info(infop, &pname, &type, &prot, &def,
10079             &defsize, &rangep)) != DLADM_STATUS_OK) {
10080                 warn_dlerr(status, "failed to get get property info");
10081                 return (B_TRUE);
10082         }
10083 
10084         switch (ofarg->ofmt_id) {
10085         case OVERLAY_LINK:
10086                 (void) snprintf(buf, bufsize, "%s", sp->sho_linkname);
10087                 break;
10088         case OVERLAY_PROPERTY:
10089                 (void) snprintf(buf, bufsize, "%s", pname);
10090                 break;
10091         case OVERLAY_PERM:
10092                 if ((prot & OVERLAY_PROP_PERM_RW) == OVERLAY_PROP_PERM_RW) {
10093                         (void) snprintf(buf, bufsize, "%s", "rw");
10094                 } else if ((prot & OVERLAY_PROP_PERM_RW) ==
10095                     OVERLAY_PROP_PERM_READ) {
10096                         (void) snprintf(buf, bufsize, "%s", "r-");
10097                 } else {
10098                         (void) snprintf(buf, bufsize, "%s", "--");
10099                 }
10100                 break;
10101         case OVERLAY_REQ:
10102                 (void) snprintf(buf, bufsize, "%s",
10103                     prot & OVERLAY_PROP_PERM_REQ ? "y" : "-");
10104                 break;
10105         case OVERLAY_VALUE:
10106                 if (sp->sho_size == 0) {
10107                         (void) snprintf(buf, bufsize, "%s", "--");
10108                 } else {
10109                         print_overlay_value(buf, bufsize, type, sp->sho_value,
10110                             sp->sho_size);
10111                 }
10112                 break;
10113         case OVERLAY_DEFAULT:
10114                 if (defsize == 0) {
10115                         (void) snprintf(buf, bufsize, "%s", "--");
10116                 } else {
10117                         print_overlay_value(buf, bufsize, type, def, defsize);
10118                 }
10119                 break;
10120         case OVERLAY_POSSIBLE: {
10121                 int i;
10122                 char **vals, *ptr, *lim;
10123                 if (rangep->mpr_count == 0) {
10124                         (void) snprintf(buf, bufsize, "%s", "--");
10125                         break;
10126                 }
10127 
10128                 vals = malloc((sizeof (char *) + DLADM_PROP_VAL_MAX) *
10129                     rangep->mpr_count);
10130                 if (vals == NULL)
10131                         die("insufficient memory");
10132                 for (i = 0; i < rangep->mpr_count; i++) {
10133                         vals[i] = (char *)vals + sizeof (char *) *
10134                             rangep->mpr_count + i * DLADM_MAX_PROP_VALCNT;
10135                 }
10136 
10137                 if (dladm_range2strs(rangep, vals) != 0) {
10138                         free(vals);
10139                         (void) snprintf(buf, bufsize, "%s", "?");
10140                         break;
10141                 }
10142 
10143                 ptr = buf;
10144                 lim = buf + bufsize;
10145                 for (i = 0; i < rangep->mpr_count; i++) {
10146                         ptr += snprintf(ptr, lim - ptr, "%s,", vals[i]);
10147                         if (ptr >= lim)
10148                                 break;
10149                 }
10150                 if (rangep->mpr_count > 0)
10151                         buf[strlen(buf) - 1] = '\0';
10152                 free(vals);
10153                 break;
10154         }
10155         default:
10156                 abort();
10157         }
10158         return (B_TRUE);
10159 }
10160 
10161 static int
10162 dladm_overlay_show_one(dladm_handle_t handle, datalink_id_t linkid,
10163     dladm_overlay_propinfo_handle_t phdl, void *arg)
10164 {
10165         showoverlay_state_t *sp = arg;
10166         sp->sho_info = phdl;
10167 
10168         sp->sho_size = sizeof (sp->sho_value);
10169         if (dladm_overlay_get_prop(handle, linkid, phdl, &sp->sho_value,
10170             &sp->sho_size) != DLADM_STATUS_OK)
10171                 return (DLADM_WALK_CONTINUE);
10172 
10173         ofmt_print(sp->sho_ofmt, sp);
10174         return (DLADM_WALK_CONTINUE);
10175 }
10176 
10177 static int
10178 show_one_overlay(dladm_handle_t hdl, datalink_id_t linkid, void *arg)
10179 {
10180         char                    buf[MAXLINKNAMELEN];
10181         dladm_status_t          info_status;
10182         showoverlay_state_t     state;
10183         datalink_class_t        class;
10184         show_overlay_request_t  *req = arg;
10185 
10186         if ((info_status = dladm_datalink_id2info(hdl, linkid, NULL, &class,
10187             NULL, buf, MAXLINKNAMELEN)) != DLADM_STATUS_OK) {
10188                 warn_dlerr(info_status, "failed to get info for "
10189                     "datalink id %u", linkid);
10190                 req->sor_failed = B_TRUE;
10191                 return (DLADM_WALK_CONTINUE);
10192         }
10193 
10194         if (class != DATALINK_CLASS_OVERLAY) {
10195                 warn("%s is not an overlay", buf);
10196                 req->sor_failed = B_TRUE;
10197                 return (DLADM_WALK_CONTINUE);
10198         }
10199 
10200         state.sho_linkname = buf;
10201         state.sho_ofmt = req->sor_ofmt;
10202 
10203         dladm_errlist_reset(&errlist);
10204         (void) dladm_overlay_walk_prop(handle, linkid, dladm_overlay_show_one,
10205             &state, &errlist);
10206         warn_dlerrlist(&errlist);
10207         if (errlist.el_count) {
10208                 req->sor_failed = B_TRUE;
10209         }
10210 
10211         return (DLADM_WALK_CONTINUE);
10212 }
10213 
10214 static boolean_t
10215 print_overlay_targ_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
10216 {
10217         char                            keybuf[ETHERADDRSTRL];
10218         const showoverlay_targ_state_t  *shot = ofarg->ofmt_cbarg;
10219         const dladm_overlay_point_t     *point = shot->shot_point;
10220         char                            macbuf[ETHERADDRSTRL];
10221         char                            ipbuf[INET6_ADDRSTRLEN];
10222         custr_t                         *cus;
10223 
10224         switch (ofarg->ofmt_id) {
10225         case OVERLAY_TARG_LINK:
10226                 (void) snprintf(buf, bufsize, shot->shot_linkname);
10227                 break;
10228         case OVERLAY_TARG_TARGET:
10229                 if ((point->dop_flags & DLADM_OVERLAY_F_DEFAULT) != 0) {
10230                         (void) snprintf(buf, bufsize, "*:*:*:*:*:*");
10231                 } else {
10232                         if (ether_ntoa_r(shot->shot_key, keybuf) == NULL) {
10233                                 warn("encountered malformed mac address key\n");
10234                                 return (B_FALSE);
10235                         }
10236                         (void) snprintf(buf, bufsize, "%s", keybuf);
10237                 }
10238                 break;
10239         case OVERLAY_TARG_DEST:
10240                 if (custr_alloc_buf(&cus, buf, bufsize) != 0) {
10241                         die("ran out of memory for printing the overlay "
10242                             "target destination");
10243                 }
10244 
10245                 if (point->dop_dest & OVERLAY_PLUGIN_D_ETHERNET) {
10246                         if (ether_ntoa_r(&point->dop_mac, macbuf) == NULL) {
10247                                 warn("encountered malformed mac address target "
10248                                     "for key %s\n", keybuf);
10249                                 return (B_FALSE);
10250                         }
10251                         (void) custr_append(cus, macbuf);
10252                 }
10253 
10254                 if (point->dop_dest & OVERLAY_PLUGIN_D_IP) {
10255                         if (IN6_IS_ADDR_V4MAPPED(&point->dop_ip)) {
10256                                 struct in_addr v4;
10257                                 IN6_V4MAPPED_TO_INADDR(&point->dop_ip, &v4);
10258                                 if (inet_ntop(AF_INET, &v4, ipbuf,
10259                                     sizeof (ipbuf)) == NULL)
10260                                         abort();
10261                         } else if (inet_ntop(AF_INET6, &point->dop_ip, ipbuf,
10262                             sizeof (ipbuf)) == NULL) {
10263                                 /*
10264                                  * The only failrues we should get are
10265                                  * EAFNOSUPPORT and ENOSPC because of buffer
10266                                  * exhaustion. In either of these cases, that
10267                                  * means something has gone horribly wrong.
10268                                  */
10269                                 abort();
10270                         }
10271                         if (point->dop_dest & OVERLAY_PLUGIN_D_ETHERNET)
10272                                 (void) custr_appendc(cus, ',');
10273                         (void) custr_append(cus, ipbuf);
10274                 }
10275 
10276                 if (point->dop_dest & OVERLAY_PLUGIN_D_PORT) {
10277                         if (point->dop_dest & OVERLAY_PLUGIN_D_IP)
10278                                 (void) custr_appendc(cus, ':');
10279                         else if (point->dop_dest & OVERLAY_PLUGIN_D_ETHERNET)
10280                                 (void) custr_appendc(cus, ',');
10281                         (void) custr_append_printf(cus, "%u", point->dop_port);
10282                 }
10283 
10284                 custr_free(cus);
10285 
10286                 break;
10287         }
10288         return (B_TRUE);
10289 }
10290 
10291 /* ARGSUSED */
10292 static int
10293 show_one_overlay_table_entry(dladm_handle_t handle, datalink_id_t linkid,
10294     const struct ether_addr *key, const dladm_overlay_point_t *point, void *arg)
10295 {
10296         showoverlay_targ_state_t        *shot = arg;
10297 
10298         shot->shot_key = key;
10299         shot->shot_point = point;
10300         ofmt_print(shot->shot_ofmt, shot);
10301 
10302         return (DLADM_WALK_CONTINUE);
10303 }
10304 
10305 /* ARGSUSED */
10306 static int
10307 show_one_overlay_table(dladm_handle_t handle, datalink_id_t linkid, void *arg)
10308 {
10309         char                            linkbuf[MAXLINKNAMELEN];
10310         dladm_status_t                  info_status;
10311         showoverlay_targ_state_t        shot;
10312         datalink_class_t                class;
10313         show_overlay_request_t          *req = arg;
10314 
10315         if ((info_status = dladm_datalink_id2info(handle, linkid, NULL, &class,
10316             NULL, linkbuf, MAXLINKNAMELEN)) != DLADM_STATUS_OK) {
10317                 warn_dlerr(info_status, "failed to get info for "
10318                     "datalink id %u", linkid);
10319                 req->sor_failed = B_TRUE;
10320                 return (DLADM_WALK_CONTINUE);
10321         }
10322 
10323         if (class != DATALINK_CLASS_OVERLAY) {
10324                 warn("%s is not an overlay", linkbuf);
10325                 req->sor_failed = B_TRUE;
10326                 return (DLADM_WALK_CONTINUE);
10327         }
10328 
10329         shot.shot_ofmt = req->sor_ofmt;
10330         shot.shot_linkname = linkbuf;
10331 
10332         (void) dladm_overlay_walk_cache(handle, linkid,
10333             show_one_overlay_table_entry, &shot);
10334 
10335         return (DLADM_WALK_CONTINUE);
10336 }
10337 
10338 static boolean_t
10339 print_overlay_fma_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
10340 {
10341         showoverlay_fma_state_t *shof = ofarg->ofmt_cbarg;
10342         dladm_overlay_status_t  *st = shof->shof_status;
10343 
10344         switch (ofarg->ofmt_id) {
10345         case OVERLAY_FMA_LINK:
10346                 (void) snprintf(buf, bufsize, "%s", shof->shof_linkname);
10347                 break;
10348         case OVERLAY_FMA_STATUS:
10349                 (void) snprintf(buf, bufsize, st->dos_degraded == B_TRUE ?
10350                     "DEGRADED": "ONLINE");
10351                 break;
10352         case OVERLAY_FMA_DETAILS:
10353                 (void) snprintf(buf, bufsize, "%s", st->dos_degraded == B_TRUE ?
10354                     st->dos_fmamsg : "-");
10355                 break;
10356         default:
10357                 abort();
10358         }
10359         return (B_TRUE);
10360 }
10361 
10362 /* ARGSUSED */
10363 static void
10364 show_one_overlay_fma_cb(dladm_handle_t handle, datalink_id_t linkid,
10365     dladm_overlay_status_t *stat, void *arg)
10366 {
10367         showoverlay_fma_state_t *shof = arg;
10368         shof->shof_status = stat;
10369         ofmt_print(shof->shof_ofmt, shof);
10370 }
10371 
10372 
10373 static int
10374 show_one_overlay_fma(dladm_handle_t handle, datalink_id_t linkid, void *arg)
10375 {
10376         dladm_status_t          status;
10377         char                    linkbuf[MAXLINKNAMELEN];
10378         datalink_class_t        class;
10379         showoverlay_fma_state_t shof;
10380         show_overlay_request_t  *req = arg;
10381 
10382         if (dladm_datalink_id2info(handle, linkid, NULL, &class, NULL, linkbuf,
10383             MAXLINKNAMELEN) != DLADM_STATUS_OK ||
10384             class != DATALINK_CLASS_OVERLAY) {
10385                 die("datalink %s is not an overlay device\n", linkbuf);
10386         }
10387 
10388         shof.shof_ofmt = req->sor_ofmt;
10389         shof.shof_linkname = linkbuf;
10390 
10391         status = dladm_overlay_status(handle, linkid,
10392             show_one_overlay_fma_cb, &shof);
10393         if (status != DLADM_STATUS_OK)
10394                 die_dlerr(status, "failed to obtain device status for %s",
10395                     linkbuf);
10396 
10397         return (DLADM_WALK_CONTINUE);
10398 }
10399 
10400 static void
10401 do_show_overlay(int argc, char *argv[], const char *use)
10402 {
10403         int                     i, opt;
10404         datalink_id_t           linkid = DATALINK_ALL_LINKID;
10405         dladm_status_t          status;
10406         int                     (*funcp)(dladm_handle_t, datalink_id_t, void *);
10407         char                    *fields_str = NULL;
10408         const ofmt_field_t      *fieldsp;
10409         ofmt_status_t           oferr;
10410         boolean_t               parse;
10411         show_overlay_request_t  req;
10412         uint_t                  ofmtflags;
10413         int                     err;
10414 
10415         funcp = show_one_overlay;
10416         fieldsp = overlay_fields;
10417         parse = B_FALSE;
10418         req.sor_failed = B_FALSE;
10419         ofmtflags = OFMT_WRAP;
10420         while ((opt = getopt_long(argc, argv, ":o:pft", overlay_show_lopts,
10421             NULL)) != -1) {
10422                 switch (opt) {
10423                 case 'f':
10424                         funcp = show_one_overlay_fma;
10425                         fieldsp = overlay_fma_fields;
10426                         break;
10427                 case 'o':
10428                         fields_str = optarg;
10429                         break;
10430                 case 'p':
10431                         parse = B_TRUE;
10432                         ofmtflags = OFMT_PARSABLE;
10433                         break;
10434                 case 't':
10435                         funcp = show_one_overlay_table;
10436                         fieldsp = overlay_targ_fields;
10437                         break;
10438                 default:
10439                         die_opterr(optopt, opt, use);
10440                 }
10441         }
10442 
10443         if (fields_str != NULL && strcasecmp(fields_str, "all") == 0)
10444                 fields_str = NULL;
10445 
10446         oferr = ofmt_open(fields_str, fieldsp, ofmtflags, 0, &req.sor_ofmt);
10447         ofmt_check(oferr, parse, req.sor_ofmt, die, warn);
10448 
10449         err = 0;
10450         if (argc > optind) {
10451                 for (i = optind; i < argc; i++) {
10452                         status = dladm_name2info(handle, argv[i], &linkid,
10453                             NULL, NULL, NULL);
10454                         if (status != DLADM_STATUS_OK) {
10455                                 warn_dlerr(status, "failed to find %s",
10456                                     argv[i]);
10457                                 err = 1;
10458                                 continue;
10459                         }
10460                         (void) funcp(handle, linkid, &req);
10461                 }
10462         } else {
10463                 (void) dladm_walk_datalink_id(funcp, handle, &req,
10464                     DATALINK_CLASS_OVERLAY, DATALINK_ANY_MEDIATYPE,
10465                     DLADM_OPT_ACTIVE);
10466         }
10467         if (req.sor_failed) {
10468                 err = 1;
10469         }
10470         ofmt_close(req.sor_ofmt);
10471 
10472         exit(err);
10473 }
10474 
10475 static void
10476 do_modify_overlay(int argc, char *argv[], const char *use)
10477 {
10478         int                     opt, ocnt = 0;
10479         boolean_t               flush, set, delete;
10480         struct ether_addr       e;
10481         char                    *dest;
10482         datalink_id_t           linkid = DATALINK_ALL_LINKID;
10483         dladm_status_t          status;
10484 
10485         flush = set = delete = B_FALSE;
10486         while ((opt = getopt_long(argc, argv, ":fd:s:", overlay_modify_lopts,
10487             NULL)) != -1) {
10488                 switch (opt) {
10489                 case 'd':
10490                         if (delete == B_TRUE)
10491                                 die_optdup('d');
10492                         delete = B_TRUE;
10493                         ocnt++;
10494                         if (ether_aton_r(optarg, &e) == NULL)
10495                                 die("invalid mac address: %s\n", optarg);
10496                         break;
10497                 case 'f':
10498                         if (flush == B_TRUE)
10499                                 die_optdup('f');
10500                         flush = B_TRUE;
10501                         ocnt++;
10502                         break;
10503                 case 's':
10504                         if (set == B_TRUE)
10505                                 die_optdup('s');
10506                         set = B_TRUE;
10507                         ocnt++;
10508                         dest = strchr(optarg, '=');
10509                         *dest = '\0';
10510                         dest++;
10511                         if (dest == NULL)
10512                                 die("malformed value, expected mac=dest, "
10513                                     "got: %s\n", optarg);
10514                         if (ether_aton_r(optarg, &e) == NULL)
10515                                 die("invalid mac address: %s\n", optarg);
10516                         break;
10517                 default:
10518                         die_opterr(optopt, opt, use);
10519                 }
10520         }
10521 
10522         if (ocnt == 0)
10523                 die("need to specify one of -d, -f, or -s");
10524         if (ocnt > 1)
10525                 die("only one of -d, -f, or -s may be used");
10526 
10527         if (argv[optind] == NULL)
10528                 die("missing required overlay device\n");
10529         if (argc > optind + 1)
10530                 die("only one overlay device may be specified\n");
10531 
10532         status = dladm_name2info(handle, argv[optind], &linkid, NULL, NULL,
10533             NULL);
10534         if (status != DLADM_STATUS_OK) {
10535                 die_dlerr(status, "failed to find overlay %s", argv[optind]);
10536         }
10537 
10538         if (flush == B_TRUE) {
10539                 status = dladm_overlay_cache_flush(handle, linkid);
10540                 if (status != DLADM_STATUS_OK)
10541                         die_dlerr(status, "failed to flush target cache for "
10542                             "overlay %s", argv[optind]);
10543         }
10544 
10545         if (delete == B_TRUE) {
10546                 status = dladm_overlay_cache_delete(handle, linkid, &e);
10547                 if (status != DLADM_STATUS_OK)
10548                         die_dlerr(status, "failed to flush target %s from "
10549                             "overlay target cache %s", optarg, argv[optind]);
10550         }
10551 
10552         if (set == B_TRUE) {
10553                 status = dladm_overlay_cache_set(handle, linkid, &e, dest);
10554                 if (status != DLADM_STATUS_OK)
10555                         die_dlerr(status, "failed to set target %s for overlay "
10556                             "target cache %s", optarg, argv[optind]);
10557         }
10558 
10559 }
10560 
10561 static void
10562 do_up_overlay(int argc, char *argv[], const char *use)
10563 {
10564         datalink_id_t   linkid = DATALINK_ALL_LINKID;
10565         dladm_status_t  status;
10566 
10567         /*
10568          * get the id or the name of the overlay (optional last argument)
10569          */
10570         if (argc == 2) {
10571                 status = dladm_name2info(handle, argv[1], &linkid, NULL, NULL,
10572                     NULL);
10573                 if (status != DLADM_STATUS_OK)
10574                         goto done;
10575         } else if (argc > 2) {
10576                 usage();
10577         }
10578 
10579         status = dladm_overlay_up(handle, linkid, &errlist);
10580 
10581 done:
10582         if (status != DLADM_STATUS_OK) {
10583                 if (argc == 2) {
10584                         die_dlerrlist(status, &errlist,
10585                             "could not bring up overlay '%s'", argv[1]);
10586                 } else {
10587                         die_dlerrlist(status, &errlist,
10588                             "could not bring overlays up");
10589                 }
10590         }
10591 }