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