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