1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
  24  * Copyright 2017 Nexenta Systems, Inc.
  25  */
  26 
  27 #include <arpa/inet.h>
  28 #include <errno.h>
  29 #include <getopt.h>
  30 #include <inet/ip.h>
  31 #include <inet/iptun.h>
  32 #include <inet/tunables.h>
  33 #include <libdladm.h>
  34 #include <libdliptun.h>
  35 #include <libdllink.h>
  36 #include <libinetutil.h>
  37 #include <libipadm.h>
  38 #include <locale.h>
  39 #include <netdb.h>
  40 #include <netinet/in.h>
  41 #include <ofmt.h>
  42 #include <stdarg.h>
  43 #include <stddef.h>
  44 #include <stdio.h>
  45 #include <stdlib.h>
  46 #include <string.h>
  47 #include <strings.h>
  48 #include <sys/stat.h>
  49 #include <sys/types.h>
  50 #include <zone.h>
  51 
  52 #define STR_UNKNOWN_VAL "?"
  53 #define LIFC_DEFAULT    (LIFC_NOXMIT | LIFC_TEMPORARY | LIFC_ALLZONES |\
  54                         LIFC_UNDER_IPMP)
  55 
  56 typedef void cmdfunc_t(int, char **, const char *);
  57 static cmdfunc_t do_create_if, do_delete_if, do_enable_if, do_disable_if;
  58 static cmdfunc_t do_show_if;
  59 static cmdfunc_t do_set_prop, do_show_prop, do_set_ifprop;
  60 static cmdfunc_t do_show_ifprop, do_reset_ifprop, do_reset_prop;
  61 static cmdfunc_t do_show_addrprop, do_set_addrprop, do_reset_addrprop;
  62 static cmdfunc_t do_create_addr, do_delete_addr, do_show_addr;
  63 static cmdfunc_t do_enable_addr, do_disable_addr;
  64 static cmdfunc_t do_up_addr, do_down_addr, do_refresh_addr;
  65 
  66 typedef struct  cmd {
  67         char            *c_name;
  68         cmdfunc_t       *c_fn;
  69         const char      *c_usage;
  70 } cmd_t;
  71 
  72 static cmd_t    cmds[] = {
  73         /* interface management related sub-commands */
  74         { "create-if",  do_create_if,   "\tcreate-if\t[-t] <interface>"   },
  75         { "disable-if", do_disable_if,  "\tdisable-if\t-t <interface>"    },
  76         { "enable-if",  do_enable_if,   "\tenable-if\t-t <interface>"     },
  77         { "delete-if",  do_delete_if,   "\tdelete-if\t<interface>"        },
  78         { "show-if",    do_show_if,
  79             "\tshow-if\t\t[[-p] -o <field>,...] [<interface>]\n"    },
  80         { "set-ifprop", do_set_ifprop,
  81             "\tset-ifprop\t[-t] -p <prop>=<value[,...]> -m <protocol> "
  82             "<interface>"                                                 },
  83         { "reset-ifprop", do_reset_ifprop,
  84             "\treset-ifprop\t[-t] -p <prop> -m <protocol> <interface>"        },
  85         { "show-ifprop", do_show_ifprop,
  86             "\tshow-ifprop\t[[-c] -o <field>,...] [-p <prop>,...]\n"
  87             "\t\t\t[-m <protocol>] [interface]\n"                         },
  88 
  89         /* address management related sub-commands */
  90         { "create-addr", do_create_addr,
  91             "\tcreate-addr\t[-t] -T static [-d] "
  92             "-a{local|remote}=addr[/prefixlen]\n\t\t\t<addrobj>\n"
  93             "\tcreate-addr\t[-t] -T dhcp [-w <seconds> | forever] <addrobj>\n"
  94             "\tcreate-addr\t[-t] -T addrconf [-i interface-id]\n"
  95             "\t\t\t[-p {stateful|stateless}={yes|no}] <addrobj>" },
  96         { "down-addr",  do_down_addr,   "\tdown-addr\t[-t] <addrobj>"     },
  97         { "up-addr",    do_up_addr,     "\tup-addr\t\t[-t] <addrobj>"     },
  98         { "disable-addr", do_disable_addr, "\tdisable-addr\t-t <addrobj>" },
  99         { "enable-addr", do_enable_addr, "\tenable-addr\t-t <addrobj>"    },
 100         { "refresh-addr", do_refresh_addr, "\trefresh-addr\t[-i] <addrobj>" },
 101         { "delete-addr", do_delete_addr, "\tdelete-addr\t[-r] <addrobj>" },
 102         { "show-addr",  do_show_addr,
 103             "\tshow-addr\t[[-p] -o <field>,...] [<addrobj>]\n"              },
 104         { "set-addrprop", do_set_addrprop,
 105             "\tset-addrprop\t[-t] -p <prop>=<value[,...]> <addrobj>"  },
 106         { "reset-addrprop", do_reset_addrprop,
 107             "\treset-addrprop\t[-t] -p <prop> <addrobj>"            },
 108         { "show-addrprop", do_show_addrprop,
 109             "\tshow-addrprop\t[[-c] -o <field>,...] [-p <prop>,...] "
 110             "<addrobj>\n"                                                 },
 111 
 112         /* protocol properties related sub-commands */
 113         { "set-prop",   do_set_prop,
 114             "\tset-prop\t[-t] -p <prop>[+|-]=<value[,...]> <protocol>"        },
 115         { "reset-prop", do_reset_prop,
 116             "\treset-prop\t[-t] -p <prop> <protocol>"                       },
 117         { "show-prop",  do_show_prop,
 118             "\tshow-prop\t[[-c] -o <field>,...] [-p <prop>,...]"
 119             " [protocol]"                                               }
 120 };
 121 
 122 static const struct option if_longopts[] = {
 123         {"temporary",   no_argument,            0, 't'  },
 124         { 0, 0, 0, 0 }
 125 };
 126 
 127 static const struct option show_prop_longopts[] = {
 128         {"parsable",    no_argument,            0, 'c'  },
 129         {"prop",        required_argument,      0, 'p'  },
 130         {"output",      required_argument,      0, 'o'  },
 131         { 0, 0, 0, 0 }
 132 };
 133 
 134 static const struct option show_ifprop_longopts[] = {
 135         {"module",      required_argument,      0, 'm'  },
 136         {"parsable",    no_argument,            0, 'c'  },
 137         {"prop",        required_argument,      0, 'p'  },
 138         {"output",      required_argument,      0, 'o'  },
 139         { 0, 0, 0, 0 }
 140 };
 141 
 142 static const struct option set_prop_longopts[] = {
 143         {"prop",        required_argument,      0, 'p'  },
 144         {"temporary",   no_argument,            0, 't'  },
 145         { 0, 0, 0, 0 }
 146 };
 147 
 148 static const struct option set_ifprop_longopts[] = {
 149         {"module",      required_argument,      0, 'm'  },
 150         {"prop",        required_argument,      0, 'p'  },
 151         {"temporary",   no_argument,            0, 't'  },
 152         { 0, 0, 0, 0 }
 153 };
 154 
 155 static const struct option addr_misc_longopts[] = {
 156         {"inform",      no_argument,            0, 'i'  },
 157         {"release",     no_argument,            0, 'r'  },
 158         {"temporary",   no_argument,            0, 't'  },
 159         { 0, 0, 0, 0 }
 160 };
 161 
 162 static const struct option addr_longopts[] = {
 163         {"address",     required_argument,      0, 'a'  },
 164         {"down",        no_argument,            0, 'd'  },
 165         {"interface-id", required_argument,     0, 'i'  },
 166         {"prop",        required_argument,      0, 'p'  },
 167         {"temporary",   no_argument,            0, 't'  },
 168         {"type",        required_argument,      0, 'T'  },
 169         {"wait",        required_argument,      0, 'w'  },
 170         { 0, 0, 0, 0 }
 171 };
 172 
 173 static const struct option show_addr_longopts[] = {
 174         {"parsable",    no_argument,            0, 'p'  },
 175         {"output",      required_argument,      0, 'o'  },
 176         { 0, 0, 0, 0 }
 177 };
 178 
 179 static const struct option show_if_longopts[] = {
 180         {"parsable",    no_argument,            0, 'p'  },
 181         {"output",      required_argument,      0, 'o'  },
 182         { 0, 0, 0, 0 }
 183 };
 184 
 185 /* callback functions to print show-* subcommands output */
 186 static ofmt_cb_t print_prop_cb;
 187 static ofmt_cb_t print_sa_cb;
 188 static ofmt_cb_t print_si_cb;
 189 
 190 /* structures for 'ipadm show-*' subcommands */
 191 typedef enum {
 192         IPADM_PROPFIELD_IFNAME,
 193         IPADM_PROPFIELD_PROTO,
 194         IPADM_PROPFIELD_ADDROBJ,
 195         IPADM_PROPFIELD_PROPERTY,
 196         IPADM_PROPFIELD_PERM,
 197         IPADM_PROPFIELD_CURRENT,
 198         IPADM_PROPFIELD_PERSISTENT,
 199         IPADM_PROPFIELD_DEFAULT,
 200         IPADM_PROPFIELD_POSSIBLE
 201 } ipadm_propfield_index_t;
 202 
 203 static ofmt_field_t intfprop_fields[] = {
 204 /* name,        field width,    index,                  callback */
 205 { "IFNAME",     12,     IPADM_PROPFIELD_IFNAME,         print_prop_cb},
 206 { "PROPERTY",   16,     IPADM_PROPFIELD_PROPERTY,       print_prop_cb},
 207 { "PROTO",      6,      IPADM_PROPFIELD_PROTO,          print_prop_cb},
 208 { "PERM",       5,      IPADM_PROPFIELD_PERM,           print_prop_cb},
 209 { "CURRENT",    11,     IPADM_PROPFIELD_CURRENT,        print_prop_cb},
 210 { "PERSISTENT", 11,     IPADM_PROPFIELD_PERSISTENT,     print_prop_cb},
 211 { "DEFAULT",    11,     IPADM_PROPFIELD_DEFAULT,        print_prop_cb},
 212 { "POSSIBLE",   16,     IPADM_PROPFIELD_POSSIBLE,       print_prop_cb},
 213 { NULL,         0,      0,                              NULL}
 214 };
 215 
 216 
 217 static ofmt_field_t modprop_fields[] = {
 218 /* name,        field width,    index,                  callback */
 219 { "PROTO",      6,      IPADM_PROPFIELD_PROTO,          print_prop_cb},
 220 { "PROPERTY",   22,     IPADM_PROPFIELD_PROPERTY,       print_prop_cb},
 221 { "PERM",       5,      IPADM_PROPFIELD_PERM,           print_prop_cb},
 222 { "CURRENT",    13,     IPADM_PROPFIELD_CURRENT,        print_prop_cb},
 223 { "PERSISTENT", 13,     IPADM_PROPFIELD_PERSISTENT,     print_prop_cb},
 224 { "DEFAULT",    13,     IPADM_PROPFIELD_DEFAULT,        print_prop_cb},
 225 { "POSSIBLE",   15,     IPADM_PROPFIELD_POSSIBLE,       print_prop_cb},
 226 { NULL,         0,      0,                              NULL}
 227 };
 228 
 229 static ofmt_field_t addrprop_fields[] = {
 230 /* name,        field width,    index,                  callback */
 231 { "ADDROBJ",    18,     IPADM_PROPFIELD_ADDROBJ,        print_prop_cb},
 232 { "PROPERTY",   11,     IPADM_PROPFIELD_PROPERTY,       print_prop_cb},
 233 { "PERM",       5,      IPADM_PROPFIELD_PERM,           print_prop_cb},
 234 { "CURRENT",    16,     IPADM_PROPFIELD_CURRENT,        print_prop_cb},
 235 { "PERSISTENT", 16,     IPADM_PROPFIELD_PERSISTENT,     print_prop_cb},
 236 { "DEFAULT",    16,     IPADM_PROPFIELD_DEFAULT,        print_prop_cb},
 237 { "POSSIBLE",   15,     IPADM_PROPFIELD_POSSIBLE,       print_prop_cb},
 238 { NULL,         0,      0,                              NULL}
 239 };
 240 
 241 typedef struct show_prop_state {
 242         char            sps_ifname[LIFNAMSIZ];
 243         char            sps_aobjname[IPADM_AOBJSIZ];
 244         const char      *sps_pname;
 245         uint_t          sps_proto;
 246         char            *sps_propval;
 247         nvlist_t        *sps_proplist;
 248         boolean_t       sps_parsable;
 249         boolean_t       sps_addrprop;
 250         boolean_t       sps_ifprop;
 251         boolean_t       sps_modprop;
 252         ipadm_status_t  sps_status;
 253         ipadm_status_t  sps_retstatus;
 254         ofmt_handle_t   sps_ofmt;
 255 } show_prop_state_t;
 256 
 257 typedef struct show_addr_state {
 258         boolean_t       sa_parsable;
 259         boolean_t       sa_persist;
 260         ofmt_handle_t   sa_ofmt;
 261 } show_addr_state_t;
 262 
 263 typedef struct show_if_state {
 264         boolean_t       si_parsable;
 265         ofmt_handle_t   si_ofmt;
 266 } show_if_state_t;
 267 
 268 typedef struct show_addr_args_s {
 269         show_addr_state_t       *sa_state;
 270         ipadm_addr_info_t       *sa_info;
 271 } show_addr_args_t;
 272 
 273 typedef struct show_if_args_s {
 274         show_if_state_t *si_state;
 275         ipadm_if_info_t *si_info;
 276 } show_if_args_t;
 277 
 278 typedef enum {
 279         SA_ADDROBJ,
 280         SA_TYPE,
 281         SA_STATE,
 282         SA_CURRENT,
 283         SA_PERSISTENT,
 284         SA_ADDR
 285 } sa_field_index_t;
 286 
 287 typedef enum {
 288         SI_IFNAME,
 289         SI_STATE,
 290         SI_CURRENT,
 291         SI_PERSISTENT
 292 } si_field_index_t;
 293 
 294 static ofmt_field_t show_addr_fields[] = {
 295 /* name,        field width,    id,             callback */
 296 { "ADDROBJ",    18,             SA_ADDROBJ,     print_sa_cb},
 297 { "TYPE",       9,              SA_TYPE,        print_sa_cb},
 298 { "STATE",      13,             SA_STATE,       print_sa_cb},
 299 { "CURRENT",    8,              SA_CURRENT,     print_sa_cb},
 300 { "PERSISTENT", 11,             SA_PERSISTENT,  print_sa_cb},
 301 { "ADDR",       46,             SA_ADDR,        print_sa_cb},
 302 { NULL,         0,              0,              NULL}
 303 };
 304 
 305 static ofmt_field_t show_if_fields[] = {
 306 /* name,        field width,    id,             callback */
 307 { "IFNAME",     11,             SI_IFNAME,      print_si_cb},
 308 { "STATE",      9,              SI_STATE,       print_si_cb},
 309 { "CURRENT",    13,             SI_CURRENT,     print_si_cb},
 310 { "PERSISTENT", 11,             SI_PERSISTENT,  print_si_cb},
 311 { NULL,         0,              0,              NULL}
 312 };
 313 
 314 #define IPADM_ALL_BITS  ((uint_t)-1)
 315 typedef struct intf_mask {
 316         char            *name;
 317         uint64_t        bits;
 318         uint64_t        mask;
 319 } fmask_t;
 320 
 321 /*
 322  * Handle to libipadm. Opened in main() before the sub-command specific
 323  * function is called and is closed before the program exits.
 324  */
 325 ipadm_handle_t  iph = NULL;
 326 
 327 /*
 328  * Opaque ipadm address object. Used by all the address management subcommands.
 329  */
 330 ipadm_addrobj_t ipaddr = NULL;
 331 
 332 static char *progname;
 333 
 334 static void     die(const char *, ...);
 335 static void     die_opterr(int, int, const char *);
 336 static void     warn_ipadmerr(ipadm_status_t, const char *, ...);
 337 static void     ipadm_ofmt_check(ofmt_status_t, boolean_t, ofmt_handle_t);
 338 static void     ipadm_check_propstr(const char *, boolean_t, const char *);
 339 static void     process_misc_addrargs(int, char **, const char *, int *,
 340                     uint32_t *);
 341 
 342 static void
 343 usage(void)
 344 {
 345         int     i;
 346         cmd_t   *cmdp;
 347 
 348         (void) fprintf(stderr,
 349             gettext("usage:  ipadm <subcommand> <args> ...\n"));
 350         for (i = 0; i < sizeof (cmds) / sizeof (cmds[0]); i++) {
 351                 cmdp = &cmds[i];
 352                 if (cmdp->c_usage != NULL)
 353                         (void) fprintf(stderr, "%s\n", gettext(cmdp->c_usage));
 354         }
 355 
 356         ipadm_destroy_addrobj(ipaddr);
 357         ipadm_close(iph);
 358         exit(1);
 359 }
 360 
 361 int
 362 main(int argc, char *argv[])
 363 {
 364         int     i;
 365         cmd_t   *cmdp;
 366         ipadm_status_t status;
 367 
 368         (void) setlocale(LC_ALL, "");
 369         (void) textdomain(TEXT_DOMAIN);
 370 
 371         if ((progname = strrchr(argv[0], '/')) == NULL)
 372                 progname = argv[0];
 373         else
 374                 progname++;
 375 
 376         if (argc < 2)
 377                 usage();
 378 
 379         status = ipadm_open(&iph, 0);
 380         if (status != IPADM_SUCCESS) {
 381                 die("Could not open handle to library - %s",
 382                     ipadm_status2str(status));
 383         }
 384 
 385         for (i = 0; i < sizeof (cmds) / sizeof (cmds[0]); i++) {
 386                 cmdp = &cmds[i];
 387                 if (strcmp(argv[1], cmdp->c_name) == 0) {
 388                         cmdp->c_fn(argc - 1, &argv[1], gettext(cmdp->c_usage));
 389                         ipadm_destroy_addrobj(ipaddr);
 390                         ipadm_close(iph);
 391                         exit(0);
 392                 }
 393         }
 394 
 395         (void) fprintf(stderr, gettext("%s: unknown subcommand '%s'\n"),
 396             progname, argv[1]);
 397         usage();
 398 
 399         return (0);
 400 }
 401 
 402 /*
 403  * Create an IP interface for which no saved configuration exists in the
 404  * persistent store.
 405  */
 406 static void
 407 do_create_if(int argc, char *argv[], const char *use)
 408 {
 409         ipadm_status_t  status;
 410         int             option;
 411         uint32_t        flags = IPADM_OPT_PERSIST|IPADM_OPT_ACTIVE;
 412 
 413         opterr = 0;
 414         while ((option = getopt_long(argc, argv, ":t", if_longopts,
 415             NULL)) != -1) {
 416                 switch (option) {
 417                 case 't':
 418                         /*
 419                          * "ifconfig" mode - plumb interface, but do not
 420                          * restore settings that may exist in db.
 421                          */
 422                         flags &= ~IPADM_OPT_PERSIST;
 423                         break;
 424                 default:
 425                         die_opterr(optopt, option, use);
 426                 }
 427         }
 428         if (optind != (argc - 1))
 429                 die("Usage: %s", use);
 430         status = ipadm_create_if(iph, argv[optind], AF_UNSPEC, flags);
 431         if (status != IPADM_SUCCESS) {
 432                 die("Could not create %s : %s",
 433                     argv[optind], ipadm_status2str(status));
 434         }
 435 }
 436 
 437 /*
 438  * Enable an IP interface based on the persistent configuration for
 439  * that interface.
 440  */
 441 static void
 442 do_enable_if(int argc, char *argv[], const char *use)
 443 {
 444         ipadm_status_t  status;
 445         int             index;
 446         uint32_t        flags = IPADM_OPT_ACTIVE|IPADM_OPT_PERSIST;
 447 
 448         process_misc_addrargs(argc, argv, use, &index, &flags);
 449         if (flags & IPADM_OPT_PERSIST)
 450                 die("persistent operation not supported for enable-if");
 451         status = ipadm_enable_if(iph, argv[index], flags);
 452         if (status == IPADM_ALL_ADDRS_NOT_ENABLED) {
 453                 warn_ipadmerr(status, "");
 454         } else if (status != IPADM_SUCCESS) {
 455                 die("Could not enable %s : %s",
 456                     argv[optind], ipadm_status2str(status));
 457         }
 458 }
 459 
 460 /*
 461  * Remove an IP interface from both active and persistent configuration.
 462  */
 463 static void
 464 do_delete_if(int argc, char *argv[], const char *use)
 465 {
 466         ipadm_status_t  status;
 467         uint32_t        flags = IPADM_OPT_ACTIVE|IPADM_OPT_PERSIST;
 468 
 469         if (argc != 2)
 470                 die("Usage: %s", use);
 471 
 472         status = ipadm_delete_if(iph, argv[1], AF_UNSPEC, flags);
 473         if (status != IPADM_SUCCESS) {
 474                 die("Could not delete %s: %s",
 475                     argv[optind], ipadm_status2str(status));
 476         }
 477 }
 478 
 479 /*
 480  * Disable an IP interface by removing it from active configuration.
 481  */
 482 static void
 483 do_disable_if(int argc, char *argv[], const char *use)
 484 {
 485         ipadm_status_t  status;
 486         int             index;
 487         uint32_t        flags = IPADM_OPT_ACTIVE|IPADM_OPT_PERSIST;
 488 
 489         process_misc_addrargs(argc, argv, use, &index, &flags);
 490         if (flags & IPADM_OPT_PERSIST)
 491                 die("persistent operation not supported for disable-if");
 492         status = ipadm_disable_if(iph, argv[index], flags);
 493         if (status != IPADM_SUCCESS) {
 494                 die("Could not disable %s: %s",
 495                     argv[optind], ipadm_status2str(status));
 496         }
 497 }
 498 
 499 /*
 500  * Print individual columns for the show-*prop subcommands.
 501  */
 502 static void
 503 print_prop(show_prop_state_t *statep, uint_t flags, char *buf, size_t bufsize)
 504 {
 505         const char              *prop_name = statep->sps_pname;
 506         char                    *ifname = statep->sps_ifname;
 507         char                    *propval = statep->sps_propval;
 508         uint_t                  proto = statep->sps_proto;
 509         size_t                  propsize = MAXPROPVALLEN;
 510         char                    *object;
 511         ipadm_status_t          status;
 512 
 513         if (statep->sps_ifprop) {
 514                 status = ipadm_get_ifprop(iph, ifname, prop_name, propval,
 515                     &propsize, proto, flags);
 516                 object = ifname;
 517         } else if (statep->sps_modprop) {
 518                 status = ipadm_get_prop(iph, prop_name, propval, &propsize,
 519                     proto, flags);
 520                 object = ipadm_proto2str(proto);
 521         } else {
 522                 status = ipadm_get_addrprop(iph, prop_name, propval, &propsize,
 523                     statep->sps_aobjname, flags);
 524                 object = statep->sps_aobjname;
 525         }
 526 
 527         if (status != IPADM_SUCCESS) {
 528                 if ((status == IPADM_NOTFOUND && (flags & IPADM_OPT_PERSIST)) ||
 529                     status == IPADM_ENXIO) {
 530                         propval[0] = '\0';
 531                         goto cont;
 532                 }
 533                 statep->sps_status = status;
 534                 statep->sps_retstatus = status;
 535                 return;
 536         }
 537 cont:
 538         statep->sps_status = IPADM_SUCCESS;
 539         (void) snprintf(buf, bufsize, "%s", propval);
 540 }
 541 
 542 /*
 543  * Callback function for show-*prop subcommands.
 544  */
 545 static boolean_t
 546 print_prop_cb(ofmt_arg_t *ofarg, char *buf, size_t bufsize)
 547 {
 548         show_prop_state_t       *statep = ofarg->ofmt_cbarg;
 549         const char              *propname = statep->sps_pname;
 550         uint_t                  proto = statep->sps_proto;
 551         boolean_t               cont = _B_TRUE;
 552 
 553         /*
 554          * Fail retrieving remaining fields, if you fail
 555          * to retrieve a field.
 556          */
 557         if (statep->sps_status != IPADM_SUCCESS)
 558                 return (_B_FALSE);
 559 
 560         switch (ofarg->ofmt_id) {
 561         case IPADM_PROPFIELD_IFNAME:
 562                 (void) snprintf(buf, bufsize, "%s", statep->sps_ifname);
 563                 break;
 564         case IPADM_PROPFIELD_PROTO:
 565                 (void) snprintf(buf, bufsize, "%s", ipadm_proto2str(proto));
 566                 break;
 567         case IPADM_PROPFIELD_ADDROBJ:
 568                 (void) snprintf(buf, bufsize, "%s", statep->sps_aobjname);
 569                 break;
 570         case IPADM_PROPFIELD_PROPERTY:
 571                 (void) snprintf(buf, bufsize, "%s", propname);
 572                 break;
 573         case IPADM_PROPFIELD_PERM:
 574                 print_prop(statep, IPADM_OPT_PERM, buf, bufsize);
 575                 break;
 576         case IPADM_PROPFIELD_CURRENT:
 577                 print_prop(statep, IPADM_OPT_ACTIVE, buf, bufsize);
 578                 break;
 579         case IPADM_PROPFIELD_PERSISTENT:
 580                 print_prop(statep, IPADM_OPT_PERSIST, buf, bufsize);
 581                 break;
 582         case IPADM_PROPFIELD_DEFAULT:
 583                 print_prop(statep, IPADM_OPT_DEFAULT, buf, bufsize);
 584                 break;
 585         case IPADM_PROPFIELD_POSSIBLE:
 586                 print_prop(statep, IPADM_OPT_POSSIBLE, buf, bufsize);
 587                 break;
 588         }
 589         if (statep->sps_status != IPADM_SUCCESS)
 590                 cont = _B_FALSE;
 591         return (cont);
 592 }
 593 
 594 /*
 595  * Callback function called by the property walker (ipadm_walk_prop() or
 596  * ipadm_walk_proptbl()), for every matched property. This function in turn
 597  * calls ofmt_print() to print property information.
 598  */
 599 boolean_t
 600 show_property(void *arg, const char *pname, uint_t proto)
 601 {
 602         show_prop_state_t       *statep = arg;
 603 
 604         statep->sps_pname = pname;
 605         statep->sps_proto = proto;
 606         statep->sps_status = IPADM_SUCCESS;
 607         ofmt_print(statep->sps_ofmt, arg);
 608 
 609         /*
 610          * if an object is not found or operation is not supported then
 611          * stop the walker.
 612          */
 613         if (statep->sps_status == IPADM_NOTFOUND ||
 614             statep->sps_status == IPADM_NOTSUP)
 615                 return (_B_FALSE);
 616         return (_B_TRUE);
 617 }
 618 
 619 /*
 620  * Properties to be displayed is in `statep->sps_proplist'. If it is NULL,
 621  * for all the properties for the specified object, relavant information, will
 622  * be displayed. Otherwise, for the selected property set, display relevant
 623  * information
 624  */
 625 static void
 626 show_properties(void *arg, int prop_class)
 627 {
 628         show_prop_state_t       *statep = arg;
 629         nvlist_t                *nvl = statep->sps_proplist;
 630         uint_t                  proto = statep->sps_proto;
 631         nvpair_t                *curr_nvp;
 632         char                    *buf, *name;
 633         ipadm_status_t          status;
 634 
 635         /* allocate sufficient buffer to hold a property value */
 636         if ((buf = malloc(MAXPROPVALLEN)) == NULL)
 637                 die("insufficient memory");
 638         statep->sps_propval = buf;
 639 
 640         /* if no properties were specified, display all the properties */
 641         if (nvl == NULL) {
 642                 (void) ipadm_walk_proptbl(proto, prop_class, show_property,
 643                     statep);
 644         } else {
 645                 for (curr_nvp = nvlist_next_nvpair(nvl, NULL); curr_nvp;
 646                     curr_nvp = nvlist_next_nvpair(nvl, curr_nvp)) {
 647                         name = nvpair_name(curr_nvp);
 648                         status = ipadm_walk_prop(name, proto, prop_class,
 649                             show_property, statep);
 650                         if (status == IPADM_PROP_UNKNOWN)
 651                                 (void) show_property(statep, name, proto);
 652                 }
 653         }
 654 
 655         free(buf);
 656 }
 657 
 658 /*
 659  * Display information for all or specific interface properties, either for a
 660  * given interface or for all the interfaces in the system.
 661  */
 662 static void
 663 do_show_ifprop(int argc, char **argv, const char *use)
 664 {
 665         int             option;
 666         nvlist_t        *proplist = NULL;
 667         char            *fields_str = NULL;
 668         char            *ifname;
 669         ofmt_handle_t   ofmt;
 670         ofmt_status_t   oferr;
 671         uint_t          ofmtflags = 0;
 672         uint_t          proto;
 673         boolean_t       m_arg = _B_FALSE;
 674         char            *protostr;
 675         ipadm_if_info_t *ifinfo, *ifp;
 676         ipadm_status_t  status;
 677         show_prop_state_t state;
 678 
 679         opterr = 0;
 680         bzero(&state, sizeof (state));
 681         state.sps_propval = NULL;
 682         state.sps_parsable = _B_FALSE;
 683         state.sps_ifprop = _B_TRUE;
 684         state.sps_status = state.sps_retstatus = IPADM_SUCCESS;
 685         while ((option = getopt_long(argc, argv, ":p:m:co:",
 686             show_ifprop_longopts, NULL)) != -1) {
 687                 switch (option) {
 688                 case 'p':
 689                         if (ipadm_str2nvlist(optarg, &proplist,
 690                             IPADM_NORVAL) != 0)
 691                                 die("invalid interface properties specified");
 692                         break;
 693                 case 'c':
 694                         state.sps_parsable = _B_TRUE;
 695                         break;
 696                 case 'o':
 697                         fields_str = optarg;
 698                         break;
 699                 case 'm':
 700                         if (m_arg)
 701                                 die("cannot specify more than one -m");
 702                         m_arg = _B_TRUE;
 703                         protostr = optarg;
 704                         break;
 705                 default:
 706                         die_opterr(optopt, option, use);
 707                         break;
 708                 }
 709         }
 710 
 711         if (optind == argc - 1)
 712                 ifname = argv[optind];
 713         else if (optind != argc)
 714                 die("Usage: %s", use);
 715         else
 716                 ifname = NULL;
 717 
 718         if (!m_arg)
 719                 protostr = "ip";
 720         if ((proto = ipadm_str2proto(protostr)) == MOD_PROTO_NONE)
 721                 die("invalid protocol '%s' specified", protostr);
 722 
 723         state.sps_proto = proto;
 724         state.sps_proplist = proplist;
 725 
 726         if (state.sps_parsable)
 727                 ofmtflags |= OFMT_PARSABLE;
 728         oferr = ofmt_open(fields_str, intfprop_fields, ofmtflags, 0, &ofmt);
 729         ipadm_ofmt_check(oferr, state.sps_parsable, ofmt);
 730         state.sps_ofmt = ofmt;
 731 
 732         /* retrieve interface(s) and print the properties */
 733         status = ipadm_if_info(iph, ifname, &ifinfo, 0, LIFC_DEFAULT);
 734         if (ifname != NULL && status == IPADM_ENXIO)
 735                 die("no such object '%s': %s", ifname,
 736                     ipadm_status2str(status));
 737         if (status != IPADM_SUCCESS)
 738                 die("Error retrieving interface(s): %s",
 739                     ipadm_status2str(status));
 740         for (ifp = ifinfo; ifp; ifp = ifp->ifi_next) {
 741                 (void) strlcpy(state.sps_ifname, ifp->ifi_name, LIFNAMSIZ);
 742                 state.sps_proto = proto;
 743                 show_properties(&state, IPADMPROP_CLASS_IF);
 744         }
 745         if (ifinfo)
 746                 ipadm_free_if_info(ifinfo);
 747 
 748         nvlist_free(proplist);
 749         ofmt_close(ofmt);
 750 
 751         if (state.sps_retstatus != IPADM_SUCCESS) {
 752                 ipadm_close(iph);
 753                 exit(EXIT_FAILURE);
 754         }
 755 }
 756 
 757 /*
 758  * set/reset the interface property for a given interface.
 759  */
 760 static void
 761 set_ifprop(int argc, char **argv, boolean_t reset, const char *use)
 762 {
 763         int                     option;
 764         ipadm_status_t          status = IPADM_SUCCESS;
 765         boolean_t               p_arg = _B_FALSE;
 766         boolean_t               m_arg = _B_FALSE;
 767         char                    *ifname, *nv, *protostr;
 768         char                    *prop_name, *prop_val;
 769         uint_t                  flags = IPADM_OPT_PERSIST;
 770         uint_t                  proto;
 771 
 772         opterr = 0;
 773         while ((option = getopt_long(argc, argv, ":m:p:t",
 774             set_ifprop_longopts, NULL)) != -1) {
 775                 switch (option) {
 776                 case 'p':
 777                         if (p_arg)
 778                                 die("-p must be specified once only");
 779                         p_arg = _B_TRUE;
 780 
 781                         ipadm_check_propstr(optarg, reset, use);
 782                         nv = optarg;
 783                         break;
 784                 case 'm':
 785                         if (m_arg)
 786                                 die("-m must be specified once only");
 787                         m_arg = _B_TRUE;
 788                         protostr = optarg;
 789                         break;
 790                 case 't':
 791                         flags &= ~IPADM_OPT_PERSIST;
 792                         break;
 793                 default:
 794                         die_opterr(optopt, option, use);
 795                 }
 796         }
 797 
 798         if (!m_arg || !p_arg || optind != argc - 1)
 799                 die("Usage: %s", use);
 800 
 801         ifname = argv[optind];
 802 
 803         prop_name = nv;
 804         prop_val = strchr(nv, '=');
 805         if (prop_val != NULL)
 806                 *prop_val++ = '\0';
 807 
 808         if ((proto = ipadm_str2proto(protostr)) == MOD_PROTO_NONE)
 809                 die("invalid protocol '%s' specified", protostr);
 810 
 811         if (reset)
 812                 flags |= IPADM_OPT_DEFAULT;
 813         else
 814                 flags |= IPADM_OPT_ACTIVE;
 815         status = ipadm_set_ifprop(iph, ifname, prop_name, prop_val, proto,
 816             flags);
 817 
 818 done:
 819         if (status != IPADM_SUCCESS) {
 820                 if (reset)
 821                         die("reset-ifprop: %s: %s",
 822                             prop_name, ipadm_status2str(status));
 823                 else
 824                         die("set-ifprop: %s: %s",
 825                             prop_name, ipadm_status2str(status));
 826         }
 827 }
 828 
 829 static void
 830 do_set_ifprop(int argc, char **argv, const char *use)
 831 {
 832         set_ifprop(argc, argv, _B_FALSE, use);
 833 }
 834 
 835 static void
 836 do_reset_ifprop(int argc, char **argv, const char *use)
 837 {
 838         set_ifprop(argc, argv, _B_TRUE, use);
 839 }
 840 
 841 /*
 842  * Display information for all or specific protocol properties, either for a
 843  * given protocol or for supported protocols (IP/IPv4/IPv6/TCP/UDP/SCTP)
 844  */
 845 static void
 846 do_show_prop(int argc, char **argv, const char *use)
 847 {
 848         char                    option;
 849         nvlist_t                *proplist = NULL;
 850         char                    *fields_str = NULL;
 851         char                    *protostr;
 852         show_prop_state_t       state;
 853         ofmt_handle_t           ofmt;
 854         ofmt_status_t           oferr;
 855         uint_t                  ofmtflags = 0;
 856         uint_t                  proto;
 857         boolean_t               p_arg = _B_FALSE;
 858 
 859         opterr = 0;
 860         bzero(&state, sizeof (state));
 861         state.sps_propval = NULL;
 862         state.sps_parsable = _B_FALSE;
 863         state.sps_modprop = _B_TRUE;
 864         state.sps_status = state.sps_retstatus = IPADM_SUCCESS;
 865         while ((option = getopt_long(argc, argv, ":p:co:", show_prop_longopts,
 866             NULL)) != -1) {
 867                 switch (option) {
 868                 case 'p':
 869                         if (p_arg)
 870                                 die("-p must be specified once only");
 871                         p_arg = _B_TRUE;
 872                         if (ipadm_str2nvlist(optarg, &proplist,
 873                             IPADM_NORVAL) != 0)
 874                                 die("invalid protocol properties specified");
 875                         break;
 876                 case 'c':
 877                         state.sps_parsable = _B_TRUE;
 878                         break;
 879                 case 'o':
 880                         fields_str = optarg;
 881                         break;
 882                 default:
 883                         die_opterr(optopt, option, use);
 884                         break;
 885                 }
 886         }
 887         if (optind == argc - 1) {
 888                 protostr =  argv[optind];
 889                 if ((proto = ipadm_str2proto(protostr)) == MOD_PROTO_NONE)
 890                         die("invalid protocol '%s' specified", protostr);
 891                 state.sps_proto = proto;
 892         } else if (optind != argc) {
 893                 die("Usage: %s", use);
 894         } else {
 895                 if (p_arg)
 896                         die("protocol must be specified when "
 897                             "property name is used");
 898                 state.sps_proto = MOD_PROTO_NONE;
 899         }
 900 
 901         state.sps_proplist = proplist;
 902 
 903         if (state.sps_parsable)
 904                 ofmtflags |= OFMT_PARSABLE;
 905         else
 906                 ofmtflags |= OFMT_WRAP;
 907         oferr = ofmt_open(fields_str, modprop_fields, ofmtflags, 0, &ofmt);
 908         ipadm_ofmt_check(oferr, state.sps_parsable, ofmt);
 909         state.sps_ofmt = ofmt;
 910 
 911         /* handles all the errors */
 912         show_properties(&state, IPADMPROP_CLASS_MODULE);
 913 
 914         nvlist_free(proplist);
 915         ofmt_close(ofmt);
 916 
 917         if (state.sps_retstatus != IPADM_SUCCESS) {
 918                 ipadm_close(iph);
 919                 exit(EXIT_FAILURE);
 920         }
 921 }
 922 
 923 /*
 924  * Checks to see if there are any modifiers, + or -. If there are modifiers
 925  * then sets IPADM_OPT_APPEND or IPADM_OPT_REMOVE, accordingly.
 926  */
 927 static void
 928 parse_modifiers(const char *pstr, uint_t *flags, const char *use)
 929 {
 930         char *p;
 931 
 932         if ((p = strchr(pstr, '=')) == NULL)
 933                 return;
 934 
 935         if (p == pstr)
 936                 die("Invalid prop=val specified\n%s", use);
 937 
 938         --p;
 939         if (*p == '+')
 940                 *flags |= IPADM_OPT_APPEND;
 941         else if (*p == '-')
 942                 *flags |= IPADM_OPT_REMOVE;
 943 }
 944 
 945 /*
 946  * set/reset the protocol property for a given protocol.
 947  */
 948 static void
 949 set_prop(int argc, char **argv, boolean_t reset, const char *use)
 950 {
 951         int                     option;
 952         ipadm_status_t          status = IPADM_SUCCESS;
 953         char                    *protostr, *nv, *prop_name, *prop_val;
 954         boolean_t               p_arg = _B_FALSE;
 955         uint_t                  proto;
 956         uint_t                  flags = IPADM_OPT_PERSIST;
 957 
 958         opterr = 0;
 959         while ((option = getopt_long(argc, argv, ":p:t", set_prop_longopts,
 960             NULL)) != -1) {
 961                 switch (option) {
 962                 case 'p':
 963                         if (p_arg)
 964                                 die("-p must be specified once only");
 965                         p_arg = _B_TRUE;
 966 
 967                         ipadm_check_propstr(optarg, reset, use);
 968                         nv = optarg;
 969                         break;
 970                 case 't':
 971                         flags &= ~IPADM_OPT_PERSIST;
 972                         break;
 973                 default:
 974                         die_opterr(optopt, option, use);
 975                 }
 976         }
 977 
 978         if (!p_arg || optind != argc - 1)
 979                 die("Usage: %s", use);
 980 
 981         parse_modifiers(nv, &flags, use);
 982         prop_name = nv;
 983         prop_val = strchr(nv, '=');
 984         if (prop_val != NULL) {
 985                 if (flags & (IPADM_OPT_APPEND|IPADM_OPT_REMOVE))
 986                         *(prop_val - 1) = '\0';
 987                 *prop_val++ = '\0';
 988         }
 989         protostr = argv[optind];
 990         if ((proto = ipadm_str2proto(protostr)) == MOD_PROTO_NONE)
 991                 die("invalid protocol '%s' specified", protostr);
 992 
 993         if (reset)
 994                 flags |= IPADM_OPT_DEFAULT;
 995         else
 996                 flags |= IPADM_OPT_ACTIVE;
 997         status = ipadm_set_prop(iph, prop_name, prop_val, proto, flags);
 998 done:
 999         if (status != IPADM_SUCCESS) {
1000                 if (reset)
1001                         die("reset-prop: %s: %s",
1002                             prop_name, ipadm_status2str(status));
1003                 else
1004                         die("set-prop: %s: %s",
1005                             prop_name, ipadm_status2str(status));
1006         }
1007 }
1008 
1009 static void
1010 do_set_prop(int argc, char **argv, const char *use)
1011 {
1012         set_prop(argc, argv, _B_FALSE, use);
1013 }
1014 
1015 static void
1016 do_reset_prop(int argc, char **argv, const char *use)
1017 {
1018         set_prop(argc, argv,  _B_TRUE, use);
1019 }
1020 
1021 /* PRINTFLIKE1 */
1022 static void
1023 warn(const char *format, ...)
1024 {
1025         va_list alist;
1026 
1027         format = gettext(format);
1028         (void) fprintf(stderr, gettext("%s: warning: "), progname);
1029 
1030         va_start(alist, format);
1031         (void) vfprintf(stderr, format, alist);
1032         va_end(alist);
1033 
1034         (void) fprintf(stderr, "\n");
1035 }
1036 
1037 /* PRINTFLIKE1 */
1038 static void
1039 die(const char *format, ...)
1040 {
1041         va_list alist;
1042 
1043         format = gettext(format);
1044         (void) fprintf(stderr, "%s: ", progname);
1045 
1046         va_start(alist, format);
1047         (void) vfprintf(stderr, format, alist);
1048         va_end(alist);
1049 
1050         (void) putchar('\n');
1051 
1052         ipadm_destroy_addrobj(ipaddr);
1053         ipadm_close(iph);
1054         exit(EXIT_FAILURE);
1055 }
1056 
1057 static void
1058 die_opterr(int opt, int opterr, const char *usage)
1059 {
1060         switch (opterr) {
1061         case ':':
1062                 die("option '-%c' requires a value\nusage: %s", opt,
1063                     gettext(usage));
1064                 break;
1065         case '?':
1066         default:
1067                 die("unrecognized option '-%c'\nusage: %s", opt,
1068                     gettext(usage));
1069                 break;
1070         }
1071 }
1072 
1073 /* PRINTFLIKE2 */
1074 static void
1075 warn_ipadmerr(ipadm_status_t err, const char *format, ...)
1076 {
1077         va_list alist;
1078 
1079         format = gettext(format);
1080         (void) fprintf(stderr, gettext("%s: warning: "), progname);
1081 
1082         va_start(alist, format);
1083         (void) vfprintf(stderr, format, alist);
1084         va_end(alist);
1085 
1086         (void) fprintf(stderr, "%s\n", ipadm_status2str(err));
1087 }
1088 
1089 static void
1090 process_static_addrargs(const char *use, char *addrarg, const char *aobjname)
1091 {
1092         int             option;
1093         char            *val;
1094         char            *laddr = NULL;
1095         char            *raddr = NULL;
1096         char            *save_input_arg = addrarg;
1097         boolean_t       found_mismatch = _B_FALSE;
1098         ipadm_status_t  status;
1099         enum            { A_LOCAL, A_REMOTE };
1100         static char     *addr_optstr[] = {
1101                 "local",
1102                 "remote",
1103                 NULL,
1104         };
1105 
1106         while (*addrarg != '\0') {
1107                 option = getsubopt(&addrarg, addr_optstr, &val);
1108                 switch (option) {
1109                 case A_LOCAL:
1110                         if (laddr != NULL)
1111                                 die("Multiple local addresses provided");
1112                         laddr = val;
1113                         break;
1114                 case A_REMOTE:
1115                         if (raddr != NULL)
1116                                 die("Multiple remote addresses provided");
1117                         raddr = val;
1118                         break;
1119                 default:
1120                         if (found_mismatch)
1121                                 die("Invalid address provided\nusage: %s", use);
1122                         found_mismatch = _B_TRUE;
1123                         break;
1124                 }
1125         }
1126         if (raddr != NULL && laddr == NULL)
1127                 die("Missing local address\nusage: %s", use);
1128 
1129         /* If only one address is provided, it is assumed a local address. */
1130         if (laddr == NULL) {
1131                 if (found_mismatch)
1132                         laddr = save_input_arg;
1133                 else
1134                         die("Missing local address\nusage: %s", use);
1135         }
1136 
1137         /* Initialize the addrobj for static addresses. */
1138         status = ipadm_create_addrobj(IPADM_ADDR_STATIC, aobjname, &ipaddr);
1139         if (status != IPADM_SUCCESS) {
1140                 die("Error in creating address object: %s",
1141                     ipadm_status2str(status));
1142         }
1143 
1144         /* Set the local and remote addresses */
1145         status = ipadm_set_addr(ipaddr, laddr, AF_UNSPEC);
1146         if (status != IPADM_SUCCESS) {
1147                 die("Error in setting local address: %s",
1148                     ipadm_status2str(status));
1149         }
1150         if (raddr != NULL) {
1151                 status = ipadm_set_dst_addr(ipaddr, raddr, AF_UNSPEC);
1152                 if (status != IPADM_SUCCESS) {
1153                         die("Error in setting remote address: %s",
1154                             ipadm_status2str(status));
1155                 }
1156         }
1157 }
1158 
1159 static void
1160 process_addrconf_addrargs(const char *use, char *addrarg)
1161 {
1162         int             option;
1163         char            *val;
1164         enum            { P_STATELESS, P_STATEFUL };
1165         static char     *addr_optstr[] = {
1166                 "stateless",
1167                 "stateful",
1168                 NULL,
1169         };
1170         boolean_t       stateless;
1171         boolean_t       stateless_arg = _B_FALSE;
1172         boolean_t       stateful;
1173         boolean_t       stateful_arg = _B_FALSE;
1174         ipadm_status_t  status;
1175 
1176         while (*addrarg != '\0') {
1177                 option = getsubopt(&addrarg, addr_optstr, &val);
1178                 switch (option) {
1179                 case P_STATELESS:
1180                         if (stateless_arg)
1181                                 die("Duplicate option");
1182                         if (val == NULL)
1183                                 die("Invalid argument");
1184                         if (strcmp(val, "yes") == 0)
1185                                 stateless = _B_TRUE;
1186                         else if (strcmp(val, "no") == 0)
1187                                 stateless = _B_FALSE;
1188                         else
1189                                 die("Invalid argument");
1190                         stateless_arg = _B_TRUE;
1191                         break;
1192                 case P_STATEFUL:
1193                         if (stateful_arg)
1194                                 die("Duplicate option");
1195                         if (val == NULL)
1196                                 die("Invalid argument");
1197                         if (strcmp(val, "yes") == 0)
1198                                 stateful = _B_TRUE;
1199                         else if (strcmp(val, "no") == 0)
1200                                 stateful = _B_FALSE;
1201                         else
1202                                 die("Invalid argument");
1203                         stateful_arg = _B_TRUE;
1204                         break;
1205                 default:
1206                         die_opterr(optopt, option, use);
1207                 }
1208         }
1209 
1210         if (!stateless_arg && !stateful_arg)
1211                 die("Invalid arguments for option -p");
1212 
1213         /* Set the addrobj fields for addrconf */
1214         if (stateless_arg) {
1215                 status = ipadm_set_stateless(ipaddr, stateless);
1216                 if (status != IPADM_SUCCESS) {
1217                         die("Error in setting stateless option: %s",
1218                             ipadm_status2str(status));
1219                 }
1220         }
1221         if (stateful_arg) {
1222                 status = ipadm_set_stateful(ipaddr, stateful);
1223                 if (status != IPADM_SUCCESS) {
1224                         die("Error in setting stateful option: %s",
1225                             ipadm_status2str(status));
1226                 }
1227         }
1228 }
1229 
1230 /*
1231  * Creates static, dhcp or addrconf addresses and associates the created
1232  * addresses with the specified address object name.
1233  */
1234 static void
1235 do_create_addr(int argc, char *argv[], const char *use)
1236 {
1237         ipadm_status_t  status;
1238         int             option;
1239         uint32_t        flags =
1240             IPADM_OPT_PERSIST|IPADM_OPT_ACTIVE|IPADM_OPT_UP|IPADM_OPT_V46;
1241         char            *cp;
1242         char            *atype = NULL;
1243         char            *static_arg = NULL;
1244         char            *addrconf_arg = NULL;
1245         char            *interface_id = NULL;
1246         char            *wait = NULL;
1247         boolean_t       s_opt = _B_FALSE;       /* static addr options */
1248         boolean_t       auto_opt = _B_FALSE;    /* Addrconf options */
1249         boolean_t       dhcp_opt = _B_FALSE;    /* dhcp options */
1250 
1251         opterr = 0;
1252         while ((option = getopt_long(argc, argv, ":T:a:di:p:w:t",
1253             addr_longopts, NULL)) != -1) {
1254                 switch (option) {
1255                 case 'T':
1256                         atype = optarg;
1257                         break;
1258                 case 'a':
1259                         static_arg = optarg;
1260                         s_opt = _B_TRUE;
1261                         break;
1262                 case 'd':
1263                         flags &= ~IPADM_OPT_UP;
1264                         s_opt = _B_TRUE;
1265                         break;
1266                 case 'i':
1267                         interface_id = optarg;
1268                         auto_opt = _B_TRUE;
1269                         break;
1270                 case 'p':
1271                         addrconf_arg = optarg;
1272                         auto_opt = _B_TRUE;
1273                         break;
1274                 case 'w':
1275                         wait = optarg;
1276                         dhcp_opt = _B_TRUE;
1277                         break;
1278                 case 't':
1279                         flags &= ~IPADM_OPT_PERSIST;
1280                         break;
1281                 default:
1282                         die_opterr(optopt, option, use);
1283                 }
1284         }
1285         if (atype == NULL || optind != (argc - 1)) {
1286                 die("Invalid arguments\nusage: %s", use);
1287         } else if ((cp = strchr(argv[optind], '/')) == NULL ||
1288             strlen(++cp) == 0) {
1289                 die("invalid address object name: %s\nusage: %s",
1290                     argv[optind], use);
1291         }
1292 
1293         /*
1294          * Allocate and initialize the addrobj based on the address type.
1295          */
1296         if (strcmp(atype, "static") == 0) {
1297                 if (static_arg == NULL || auto_opt || dhcp_opt) {
1298                         die("Invalid arguments for type %s\nusage: %s",
1299                             atype, use);
1300                 }
1301                 process_static_addrargs(use, static_arg, argv[optind]);
1302         } else if (strcmp(atype, "dhcp") == 0) {
1303                 if (auto_opt || s_opt) {
1304                         die("Invalid arguments for type %s\nusage: %s",
1305                             atype, use);
1306                 }
1307 
1308                 /* Initialize the addrobj for dhcp addresses. */
1309                 status = ipadm_create_addrobj(IPADM_ADDR_DHCP, argv[optind],
1310                     &ipaddr);
1311                 if (status != IPADM_SUCCESS) {
1312                         die("Error in creating address object: %s",
1313                             ipadm_status2str(status));
1314                 }
1315                 if (wait != NULL) {
1316                         int32_t ipadm_wait;
1317 
1318                         if (strcmp(wait, "forever") == 0) {
1319                                 ipadm_wait = IPADM_DHCP_WAIT_FOREVER;
1320                         } else {
1321                                 char *end;
1322                                 long timeout = strtol(wait, &end, 10);
1323 
1324                                 if (*end != '\0' || timeout < 0)
1325                                         die("Invalid argument");
1326                                 ipadm_wait = (int32_t)timeout;
1327                         }
1328                         status = ipadm_set_wait_time(ipaddr, ipadm_wait);
1329                         if (status != IPADM_SUCCESS) {
1330                                 die("Error in setting wait time: %s",
1331                                     ipadm_status2str(status));
1332                         }
1333                 }
1334         } else if (strcmp(atype, "addrconf") == 0) {
1335                 if (dhcp_opt || s_opt) {
1336                         die("Invalid arguments for type %s\nusage: %s",
1337                             atype, use);
1338                 }
1339 
1340                 /* Initialize the addrobj for dhcp addresses. */
1341                 status = ipadm_create_addrobj(IPADM_ADDR_IPV6_ADDRCONF,
1342                     argv[optind], &ipaddr);
1343                 if (status != IPADM_SUCCESS) {
1344                         die("Error in creating address object: %s",
1345                             ipadm_status2str(status));
1346                 }
1347                 if (interface_id != NULL) {
1348                         status = ipadm_set_interface_id(ipaddr, interface_id);
1349                         if (status != IPADM_SUCCESS) {
1350                                 die("Error in setting interface ID: %s",
1351                                     ipadm_status2str(status));
1352                         }
1353                 }
1354                 if (addrconf_arg)
1355                         process_addrconf_addrargs(use, addrconf_arg);
1356         } else {
1357                 die("Invalid address type %s", atype);
1358         }
1359 
1360         status = ipadm_create_addr(iph, ipaddr, flags);
1361         if (status == IPADM_DHCP_IPC_TIMEOUT)
1362                 warn_ipadmerr(status, "");
1363         else if (status != IPADM_SUCCESS)
1364                 die("Could not create address: %s", ipadm_status2str(status));
1365 }
1366 
1367 /*
1368  * Used by some address management functions to parse the command line
1369  * arguments and create `ipaddr' address object.
1370  */
1371 static void
1372 process_misc_addrargs(int argc, char *argv[], const char *use, int *index,
1373     uint32_t *flags)
1374 {
1375         int             option;
1376 
1377         opterr = 0;
1378         while ((option = getopt_long(argc, argv, ":t", addr_misc_longopts,
1379             NULL)) != -1) {
1380                 switch (option) {
1381                 case 't':
1382                         *flags &= ~IPADM_OPT_PERSIST;
1383                         break;
1384                 default:
1385                         die_opterr(optopt, option, use);
1386                 }
1387         }
1388         if (optind != (argc - 1))
1389                 die("Usage: %s", use);
1390 
1391         *index = optind;
1392 }
1393 
1394 /*
1395  * Remove an addrobj from both active and persistent configuration.
1396  */
1397 static void
1398 do_delete_addr(int argc, char *argv[], const char *use)
1399 {
1400         ipadm_status_t  status;
1401         uint32_t        flags = IPADM_OPT_ACTIVE|IPADM_OPT_PERSIST;
1402         int             option;
1403 
1404         opterr = 0;
1405         while ((option = getopt_long(argc, argv, ":r", addr_misc_longopts,
1406             NULL)) != -1) {
1407                 switch (option) {
1408                 case 'r':
1409                         flags |= IPADM_OPT_RELEASE;
1410                         break;
1411                 default:
1412                         die_opterr(optopt, option, use);
1413                 }
1414         }
1415         if (optind != (argc - 1))
1416                 die("Usage: %s", use);
1417 
1418         status = ipadm_delete_addr(iph, argv[optind], flags);
1419         if (status != IPADM_SUCCESS) {
1420                 die("could not delete address: %s",
1421                     ipadm_status2str(status));
1422         }
1423 }
1424 
1425 /*
1426  * Enable an IP address based on the persistent configuration for that
1427  * IP address
1428  */
1429 static void
1430 do_enable_addr(int argc, char *argv[], const char *use)
1431 {
1432         ipadm_status_t  status;
1433         int             index;
1434         uint32_t        flags = IPADM_OPT_ACTIVE|IPADM_OPT_PERSIST;
1435 
1436         process_misc_addrargs(argc, argv, use, &index, &flags);
1437         if (flags & IPADM_OPT_PERSIST)
1438                 die("persistent operation not supported for enable-addr");
1439 
1440         status = ipadm_enable_addr(iph, argv[index], flags);
1441         if (status != IPADM_SUCCESS)
1442                 die("could not enable address: %s", ipadm_status2str(status));
1443 }
1444 
1445 /*
1446  * Mark the address identified by addrobj 'up'
1447  */
1448 static void
1449 do_up_addr(int argc, char *argv[], const char *use)
1450 {
1451         ipadm_status_t  status;
1452         int             index;
1453         uint32_t        flags = IPADM_OPT_ACTIVE|IPADM_OPT_PERSIST;
1454 
1455         process_misc_addrargs(argc, argv, use, &index, &flags);
1456         status = ipadm_up_addr(iph, argv[index], flags);
1457         if (status != IPADM_SUCCESS) {
1458                 die("Could not mark the address up: %s",
1459                     ipadm_status2str(status));
1460         }
1461 }
1462 
1463 /*
1464  * Disable the specified addrobj by removing it from active cofiguration
1465  */
1466 static void
1467 do_disable_addr(int argc, char *argv[], const char *use)
1468 {
1469         ipadm_status_t  status;
1470         int             index;
1471         uint32_t        flags = IPADM_OPT_ACTIVE|IPADM_OPT_PERSIST;
1472 
1473         process_misc_addrargs(argc, argv, use, &index, &flags);
1474         if (flags & IPADM_OPT_PERSIST)
1475                 die("persistent operation not supported for disable-addr");
1476 
1477         status = ipadm_disable_addr(iph, argv[index], flags);
1478         if (status != IPADM_SUCCESS) {
1479                 die("could not disable address: %s",
1480                     ipadm_status2str(status));
1481         }
1482 }
1483 
1484 /*
1485  * Mark the address identified by addrobj 'down'
1486  */
1487 static void
1488 do_down_addr(int argc, char *argv[], const char *use)
1489 {
1490         ipadm_status_t  status;
1491         int             index;
1492         uint32_t        flags = IPADM_OPT_ACTIVE|IPADM_OPT_PERSIST;
1493 
1494         process_misc_addrargs(argc, argv, use, &index, &flags);
1495         status = ipadm_down_addr(iph, argv[index], flags);
1496         if (status != IPADM_SUCCESS)
1497                 die("Could not mark the address down: %s",
1498                     ipadm_status2str(status));
1499 }
1500 
1501 /*
1502  * Restart DAD for static address. Extend lease duration for DHCP addresses
1503  */
1504 static void
1505 do_refresh_addr(int argc, char *argv[], const char *use)
1506 {
1507         ipadm_status_t  status;
1508         int             option;
1509         uint32_t        flags = 0;
1510 
1511         opterr = 0;
1512         while ((option = getopt_long(argc, argv, ":i", addr_misc_longopts,
1513             NULL)) != -1) {
1514                 switch (option) {
1515                 case 'i':
1516                         flags |= IPADM_OPT_INFORM;
1517                         break;
1518                 default:
1519                         die_opterr(optopt, option, use);
1520                 }
1521         }
1522         if (optind != (argc - 1))
1523                 die("Usage: %s", use);
1524 
1525         status = ipadm_refresh_addr(iph, argv[optind], flags);
1526         if (status == IPADM_DHCP_IPC_TIMEOUT)
1527                 warn_ipadmerr(status, "");
1528         else if (status != IPADM_SUCCESS)
1529                 die("could not refresh address %s", ipadm_status2str(status));
1530 }
1531 
1532 static void
1533 sockaddr2str(const struct sockaddr_storage *ssp, char *buf, uint_t bufsize)
1534 {
1535         socklen_t socklen;
1536         struct sockaddr *sp = (struct sockaddr *)ssp;
1537 
1538         switch (ssp->ss_family) {
1539         case AF_INET:
1540                 socklen = sizeof (struct sockaddr_in);
1541                 break;
1542         case AF_INET6:
1543                 socklen = sizeof (struct sockaddr_in6);
1544                 break;
1545         default:
1546                 (void) strlcpy(buf, STR_UNKNOWN_VAL, bufsize);
1547                 return;
1548         }
1549 
1550         (void) getnameinfo(sp, socklen, buf, bufsize, NULL, 0,
1551             (NI_NOFQDN | NI_NUMERICHOST));
1552 }
1553 
1554 static void
1555 flags2str(uint64_t flags, fmask_t *tbl, boolean_t is_bits,
1556     char *buf, uint_t bufsize)
1557 {
1558         int             i;
1559         boolean_t       first = _B_TRUE;
1560 
1561         if (is_bits) {
1562                 for (i = 0;  tbl[i].name; i++) {
1563                         if ((flags & tbl[i].mask) == tbl[i].bits)
1564                                 (void) strlcat(buf, tbl[i].name, bufsize);
1565                         else
1566                                 (void) strlcat(buf, "-", bufsize);
1567                 }
1568         } else {
1569                 for (i = 0; tbl[i].name; i++) {
1570                         if ((flags & tbl[i].mask) == tbl[i].bits) {
1571                                 if (!first)
1572                                         (void) strlcat(buf, ",", bufsize);
1573                                 (void) strlcat(buf, tbl[i].name, bufsize);
1574                                 first = _B_FALSE;
1575                         }
1576                 }
1577         }
1578 }
1579 
1580 /*
1581  * return true if the address for lifname comes to us from the global zone
1582  * with 'allowed-ips' constraints.
1583  */
1584 static boolean_t
1585 is_from_gz(const char *lifname)
1586 {
1587         ipadm_if_info_t         *if_info;
1588         char                    phyname[LIFNAMSIZ], *cp;
1589         boolean_t               ret = _B_FALSE;
1590         ipadm_status_t          status;
1591         zoneid_t                zoneid;
1592         ushort_t                zflags;
1593 
1594         if ((zoneid = getzoneid()) == GLOBAL_ZONEID)
1595                 return (_B_FALSE); /* from-gz only  makes sense in a NGZ */
1596 
1597         if (zone_getattr(zoneid, ZONE_ATTR_FLAGS, &zflags, sizeof (zflags)) < 0)
1598                 return (_B_FALSE);
1599 
1600         if (!(zflags & ZF_NET_EXCL))
1601                 return (_B_TRUE);  /* everything is from the GZ for shared-ip */
1602 
1603         (void) strncpy(phyname, lifname, sizeof (phyname));
1604         if ((cp = strchr(phyname, ':')) != NULL)
1605                 *cp = '\0';
1606         status = ipadm_if_info(iph, phyname, &if_info, 0, LIFC_DEFAULT);
1607         if (status != IPADM_SUCCESS)
1608                 return (ret);
1609 
1610         if (if_info->ifi_cflags & IFIF_L3PROTECT)
1611                 ret = _B_TRUE;
1612         if (if_info)
1613                 ipadm_free_if_info(if_info);
1614         return (ret);
1615 }
1616 
1617 static boolean_t
1618 print_sa_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
1619 {
1620         show_addr_args_t        *arg = ofarg->ofmt_cbarg;
1621         ipadm_addr_info_t       *ainfo = arg->sa_info;
1622         char                    interface[LIFNAMSIZ];
1623         char                    addrbuf[MAXPROPVALLEN];
1624         char                    dstbuf[MAXPROPVALLEN];
1625         char                    prefixlenstr[MAXPROPVALLEN];
1626         int                     prefixlen;
1627         struct sockaddr_in      *sin;
1628         struct sockaddr_in6     *sin6;
1629         sa_family_t             af;
1630         char                    *phyname = NULL;
1631         struct ifaddrs          *ifa = &ainfo->ia_ifa;
1632         fmask_t cflags_mask[] = {
1633                 { "U",  IA_UP,                  IA_UP           },
1634                 { "u",  IA_UNNUMBERED,          IA_UNNUMBERED   },
1635                 { "p",  IA_PRIVATE,             IA_PRIVATE      },
1636                 { "t",  IA_TEMPORARY,           IA_TEMPORARY    },
1637                 { "d",  IA_DEPRECATED,          IA_DEPRECATED   },
1638                 { NULL,         0,                      0       }
1639         };
1640         fmask_t pflags_mask[] = {
1641                 { "U",  IA_UP,                  IA_UP           },
1642                 { "p",  IA_PRIVATE,             IA_PRIVATE      },
1643                 { "d",  IA_DEPRECATED,          IA_DEPRECATED   },
1644                 { NULL,         0,                      0       }
1645         };
1646         fmask_t type[] = {
1647                 { "static",     IPADM_ADDR_STATIC,      IPADM_ALL_BITS},
1648                 { "addrconf",   IPADM_ADDR_IPV6_ADDRCONF, IPADM_ALL_BITS},
1649                 { "dhcp",       IPADM_ADDR_DHCP,        IPADM_ALL_BITS},
1650                 { NULL,         0,                      0       }
1651         };
1652         fmask_t addr_state[] = {
1653                 { "disabled",   IFA_DISABLED,   IPADM_ALL_BITS},
1654                 { "duplicate",  IFA_DUPLICATE,  IPADM_ALL_BITS},
1655                 { "down",       IFA_DOWN,       IPADM_ALL_BITS},
1656                 { "tentative",  IFA_TENTATIVE,  IPADM_ALL_BITS},
1657                 { "ok",         IFA_OK,         IPADM_ALL_BITS},
1658                 { "inaccessible", IFA_INACCESSIBLE, IPADM_ALL_BITS},
1659                 { NULL,         0,              0       }
1660         };
1661 
1662         buf[0] = '\0';
1663         switch (ofarg->ofmt_id) {
1664         case SA_ADDROBJ:
1665                 if (ainfo->ia_aobjname[0] == '\0') {
1666                         (void) strncpy(interface, ifa->ifa_name, LIFNAMSIZ);
1667                         phyname = strrchr(interface, ':');
1668                         if (phyname)
1669                                 *phyname = '\0';
1670                         (void) snprintf(buf, bufsize, "%s/%s", interface,
1671                             STR_UNKNOWN_VAL);
1672                 } else {
1673                         (void) snprintf(buf, bufsize, "%s", ainfo->ia_aobjname);
1674                 }
1675                 break;
1676         case SA_STATE:
1677                 flags2str(ainfo->ia_state, addr_state, _B_FALSE,
1678                     buf, bufsize);
1679                 break;
1680         case SA_TYPE:
1681                 if (is_from_gz(ifa->ifa_name))
1682                         (void) snprintf(buf, bufsize, "from-gz");
1683                 else
1684                         flags2str(ainfo->ia_atype, type, _B_FALSE, buf,
1685                             bufsize);
1686                 break;
1687         case SA_CURRENT:
1688                 flags2str(ainfo->ia_cflags, cflags_mask, _B_TRUE, buf, bufsize);
1689                 break;
1690         case SA_PERSISTENT:
1691                 flags2str(ainfo->ia_pflags, pflags_mask, _B_TRUE, buf, bufsize);
1692                 break;
1693         case SA_ADDR:
1694                 af = ifa->ifa_addr->sa_family;
1695                 /*
1696                  * If the address is 0.0.0.0 or :: and the origin is DHCP,
1697                  * print STR_UNKNOWN_VAL.
1698                  */
1699                 if (ainfo->ia_atype == IPADM_ADDR_DHCP) {
1700                         sin = (struct sockaddr_in *)ifa->ifa_addr;
1701                         sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
1702                         if ((af == AF_INET &&
1703                             sin->sin_addr.s_addr == INADDR_ANY) ||
1704                             (af == AF_INET6 &&
1705                             IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr))) {
1706                                 (void) snprintf(buf, bufsize, STR_UNKNOWN_VAL);
1707                                 break;
1708                         }
1709                 }
1710                 if (ifa->ifa_netmask == NULL)
1711                         prefixlen = 0;
1712                 else
1713                         prefixlen = mask2plen(ifa->ifa_netmask);
1714                 bzero(prefixlenstr, sizeof (prefixlenstr));
1715                 if (prefixlen > 0) {
1716                         (void) snprintf(prefixlenstr, sizeof (prefixlenstr),
1717                             "/%d", prefixlen);
1718                 }
1719                 bzero(addrbuf, sizeof (addrbuf));
1720                 bzero(dstbuf, sizeof (dstbuf));
1721                 if (ainfo->ia_atype == IPADM_ADDR_STATIC) {
1722                         /*
1723                          * Print the hostname fields if the address is not
1724                          * in active configuration.
1725                          */
1726                         if (ainfo->ia_state == IFA_DISABLED) {
1727                                 (void) snprintf(buf, bufsize, "%s",
1728                                     ainfo->ia_sname);
1729                                 if (ainfo->ia_dname[0] != '\0') {
1730                                         (void) snprintf(dstbuf, sizeof (dstbuf),
1731                                             "->%s", ainfo->ia_dname);
1732                                         (void) strlcat(buf, dstbuf, bufsize);
1733                                 } else {
1734                                         (void) strlcat(buf, prefixlenstr,
1735                                             bufsize);
1736                                 }
1737                                 break;
1738                         }
1739                 }
1740                 /*
1741                  * For the non-persistent case, we need to show the
1742                  * currently configured addresses for source and
1743                  * destination.
1744                  */
1745                 sockaddr2str((struct sockaddr_storage *)ifa->ifa_addr,
1746                     addrbuf, sizeof (addrbuf));
1747                 if (ifa->ifa_flags & IFF_POINTOPOINT) {
1748                         sockaddr2str(
1749                             (struct sockaddr_storage *)ifa->ifa_dstaddr,
1750                             dstbuf, sizeof (dstbuf));
1751                         (void) snprintf(buf, bufsize, "%s->%s", addrbuf,
1752                             dstbuf);
1753                 } else {
1754                         (void) snprintf(buf, bufsize, "%s%s", addrbuf,
1755                             prefixlenstr);
1756                 }
1757                 break;
1758         default:
1759                 die("invalid input");
1760                 break;
1761         }
1762 
1763         return (_B_TRUE);
1764 }
1765 
1766 /*
1767  * Display address information, either for the given address or
1768  * for all the addresses managed by ipadm.
1769  */
1770 static void
1771 do_show_addr(int argc, char *argv[], const char *use)
1772 {
1773         ipadm_status_t          status;
1774         show_addr_state_t       state;
1775         char                    *def_fields_str = "addrobj,type,state,addr";
1776         char                    *fields_str = NULL;
1777         ipadm_addr_info_t       *ainfo;
1778         ipadm_addr_info_t       *ptr;
1779         show_addr_args_t        sargs;
1780         int                     option;
1781         ofmt_handle_t           ofmt;
1782         ofmt_status_t           oferr;
1783         uint_t                  ofmtflags = 0;
1784         char                    *aname;
1785         char                    *ifname = NULL;
1786         char                    *cp;
1787         boolean_t               found = _B_FALSE;
1788 
1789         opterr = 0;
1790         state.sa_parsable = _B_FALSE;
1791         state.sa_persist = _B_FALSE;
1792         while ((option = getopt_long(argc, argv, "po:", show_addr_longopts,
1793             NULL)) != -1) {
1794                 switch (option) {
1795                 case 'p':
1796                         state.sa_parsable = _B_TRUE;
1797                         break;
1798                 case 'o':
1799                         fields_str = optarg;
1800                         break;
1801                 default:
1802                         die_opterr(optopt, option, use);
1803                         break;
1804                 }
1805         }
1806         if (state.sa_parsable && fields_str == NULL)
1807                 die("-p requires -o");
1808 
1809         if (optind == argc - 1) {
1810                 aname = argv[optind];
1811                 if ((cp = strchr(aname, '/')) == NULL)
1812                         die("Invalid address object name provided");
1813                 if (*(cp + 1) == '\0') {
1814                         ifname = aname;
1815                         *cp = '\0';
1816                         aname = NULL;
1817                 }
1818         } else if (optind == argc) {
1819                 aname = NULL;
1820         } else {
1821                 die("Usage: %s", use);
1822         }
1823 
1824         if (state.sa_parsable)
1825                 ofmtflags |= OFMT_PARSABLE;
1826         if (fields_str == NULL)
1827                 fields_str = def_fields_str;
1828         oferr = ofmt_open(fields_str, show_addr_fields, ofmtflags, 0, &ofmt);
1829 
1830         ipadm_ofmt_check(oferr, state.sa_parsable, ofmt);
1831         state.sa_ofmt = ofmt;
1832 
1833         status = ipadm_addr_info(iph, ifname, &ainfo, 0, LIFC_DEFAULT);
1834         /*
1835          * Return without printing any error, if no addresses were found,
1836          * for the case where all addresses are requested.
1837          */
1838         if (status != IPADM_SUCCESS)
1839                 die("Could not get address: %s", ipadm_status2str(status));
1840         if (ainfo == NULL) {
1841                 ofmt_close(ofmt);
1842                 return;
1843         }
1844 
1845         bzero(&sargs, sizeof (sargs));
1846         sargs.sa_state = &state;
1847         for (ptr = ainfo; ptr != NULL; ptr = IA_NEXT(ptr)) {
1848                 sargs.sa_info = ptr;
1849                 if (aname != NULL) {
1850                         if (strcmp(sargs.sa_info->ia_aobjname, aname) != 0)
1851                                 continue;
1852                         found = _B_TRUE;
1853                 }
1854                 ofmt_print(state.sa_ofmt, &sargs);
1855         }
1856         if (ainfo)
1857                 ipadm_free_addr_info(ainfo);
1858         if (aname != NULL && !found)
1859                 die("Address object not found");
1860 }
1861 
1862 static boolean_t
1863 print_si_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
1864 {
1865         show_if_args_t          *arg = ofarg->ofmt_cbarg;
1866         ipadm_if_info_t         *ifinfo = arg->si_info;
1867         char                    *ifname = ifinfo->ifi_name;
1868         fmask_t intf_state[] = {
1869                 { "ok",         IFIS_OK,        IPADM_ALL_BITS},
1870                 { "down",       IFIS_DOWN,      IPADM_ALL_BITS},
1871                 { "disabled",   IFIS_DISABLED,  IPADM_ALL_BITS},
1872                 { "failed",     IFIS_FAILED,    IPADM_ALL_BITS},
1873                 { "offline",    IFIS_OFFLINE,   IPADM_ALL_BITS},
1874                 { NULL,         0,              0       }
1875         };
1876         fmask_t intf_pflags[] = {
1877                 { "s",  IFIF_STANDBY,           IFIF_STANDBY    },
1878                 { "4",  IFIF_IPV4,              IFIF_IPV4       },
1879                 { "6",  IFIF_IPV6,              IFIF_IPV6       },
1880                 { NULL, 0,                      0               }
1881         };
1882         fmask_t intf_cflags[] = {
1883                 { "b",  IFIF_BROADCAST,         IFIF_BROADCAST  },
1884                 { "m",  IFIF_MULTICAST,         IFIF_MULTICAST  },
1885                 { "p",  IFIF_POINTOPOINT,       IFIF_POINTOPOINT},
1886                 { "v",  IFIF_VIRTUAL,           IFIF_VIRTUAL    },
1887                 { "I",  IFIF_IPMP,              IFIF_IPMP       },
1888                 { "s",  IFIF_STANDBY,           IFIF_STANDBY    },
1889                 { "i",  IFIF_INACTIVE,          IFIF_INACTIVE   },
1890                 { "V",  IFIF_VRRP,              IFIF_VRRP       },
1891                 { "a",  IFIF_NOACCEPT,          IFIF_NOACCEPT   },
1892                 { "Z",  IFIF_L3PROTECT,         IFIF_L3PROTECT  },
1893                 { "4",  IFIF_IPV4,              IFIF_IPV4       },
1894                 { "6",  IFIF_IPV6,              IFIF_IPV6       },
1895                 { NULL, 0,                      0               }
1896         };
1897 
1898         buf[0] = '\0';
1899         switch (ofarg->ofmt_id) {
1900         case SI_IFNAME:
1901                 (void) snprintf(buf, bufsize, "%s", ifname);
1902                 break;
1903         case SI_STATE:
1904                 flags2str(ifinfo->ifi_state, intf_state, _B_FALSE,
1905                     buf, bufsize);
1906                 break;
1907         case SI_CURRENT:
1908                 flags2str(ifinfo->ifi_cflags, intf_cflags, _B_TRUE,
1909                     buf, bufsize);
1910                 break;
1911         case SI_PERSISTENT:
1912                 flags2str(ifinfo->ifi_pflags, intf_pflags, _B_TRUE,
1913                     buf, bufsize);
1914                 break;
1915         default:
1916                 die("invalid input");
1917                 break;
1918         }
1919 
1920         return (_B_TRUE);
1921 }
1922 
1923 /*
1924  * Display interface information, either for the given interface or
1925  * for all the interfaces in the system.
1926  */
1927 static void
1928 do_show_if(int argc, char *argv[], const char *use)
1929 {
1930         ipadm_status_t          status;
1931         show_if_state_t         state;
1932         char                    *fields_str = NULL;
1933         ipadm_if_info_t         *if_info, *ptr;
1934         show_if_args_t          sargs;
1935         int                     option;
1936         ofmt_handle_t           ofmt;
1937         ofmt_status_t           oferr;
1938         uint_t                  ofmtflags = 0;
1939         char                    *ifname = NULL;
1940 
1941         opterr = 0;
1942         state.si_parsable = _B_FALSE;
1943 
1944         while ((option = getopt_long(argc, argv, "po:", show_if_longopts,
1945             NULL)) != -1) {
1946                 switch (option) {
1947                 case 'p':
1948                         state.si_parsable = _B_TRUE;
1949                         break;
1950                 case 'o':
1951                         fields_str = optarg;
1952                         break;
1953                 default:
1954                         die_opterr(optopt, option, use);
1955                         break;
1956                 }
1957         }
1958         if (optind == argc - 1)
1959                 ifname = argv[optind];
1960         else if (optind != argc)
1961                 die("Usage: %s", use);
1962         if (state.si_parsable)
1963                 ofmtflags |= OFMT_PARSABLE;
1964         oferr = ofmt_open(fields_str, show_if_fields, ofmtflags, 0, &ofmt);
1965         ipadm_ofmt_check(oferr, state.si_parsable, ofmt);
1966         state.si_ofmt = ofmt;
1967         bzero(&sargs, sizeof (sargs));
1968         sargs.si_state = &state;
1969         status = ipadm_if_info(iph, ifname, &if_info, 0, LIFC_DEFAULT);
1970         /*
1971          * Return without printing any error, if no addresses were found.
1972          */
1973         if (status != IPADM_SUCCESS) {
1974                 die("Could not get interface(s): %s",
1975                     ipadm_status2str(status));
1976         }
1977 
1978         for (ptr = if_info; ptr; ptr = ptr->ifi_next) {
1979                 sargs.si_info = ptr;
1980                 ofmt_print(state.si_ofmt, &sargs);
1981         }
1982         if (if_info)
1983                 ipadm_free_if_info(if_info);
1984 }
1985 
1986 /*
1987  * set/reset the address property for a given address
1988  */
1989 static void
1990 set_addrprop(int argc, char **argv, boolean_t reset, const char *use)
1991 {
1992         int                     option;
1993         ipadm_status_t          status = IPADM_SUCCESS;
1994         boolean_t               p_arg = _B_FALSE;
1995         char                    *nv, *aobjname;
1996         char                    *prop_name, *prop_val;
1997         uint_t                  flags = IPADM_OPT_ACTIVE|IPADM_OPT_PERSIST;
1998 
1999         opterr = 0;
2000         while ((option = getopt_long(argc, argv, ":i:p:t", set_ifprop_longopts,
2001             NULL)) != -1) {
2002                 switch (option) {
2003                 case 'p':
2004                         if (p_arg)
2005                                 die("-p must be specified once only");
2006                         p_arg = _B_TRUE;
2007 
2008                         ipadm_check_propstr(optarg, reset, use);
2009                         nv = optarg;
2010                         break;
2011                 case 't':
2012                         flags &= ~IPADM_OPT_PERSIST;
2013                         break;
2014                 default:
2015                         die_opterr(optopt, option, use);
2016                 }
2017         }
2018 
2019         if (!p_arg || optind != (argc - 1))
2020                 die("Usage: %s", use);
2021 
2022         prop_name = nv;
2023         prop_val = strchr(nv, '=');
2024         if (prop_val != NULL)
2025                 *prop_val++ = '\0';
2026         aobjname = argv[optind];
2027         if (reset)
2028                 flags |= IPADM_OPT_DEFAULT;
2029         status = ipadm_set_addrprop(iph, prop_name, prop_val, aobjname, flags);
2030         if (status != IPADM_SUCCESS) {
2031                 if (reset)
2032                         die("reset-addrprop: %s: %s", prop_name,
2033                             ipadm_status2str(status));
2034                 else
2035                         die("set-addrprop: %s: %s", prop_name,
2036                             ipadm_status2str(status));
2037         }
2038 }
2039 
2040 /*
2041  * Sets a property on an address object.
2042  */
2043 static void
2044 do_set_addrprop(int argc, char **argv, const char *use)
2045 {
2046         set_addrprop(argc, argv, _B_FALSE, use);
2047 }
2048 
2049 /*
2050  * Resets a property to its default value on an address object.
2051  */
2052 static void
2053 do_reset_addrprop(int argc, char **argv, const char *use)
2054 {
2055         set_addrprop(argc, argv,  _B_TRUE, use);
2056 }
2057 
2058 /*
2059  * Display information for all or specific address properties, either for a
2060  * given address or for all the addresses in the system.
2061  */
2062 static void
2063 do_show_addrprop(int argc, char *argv[], const char *use)
2064 {
2065         int                     option;
2066         nvlist_t                *proplist = NULL;
2067         char                    *fields_str = NULL;
2068         show_prop_state_t       state;
2069         ofmt_handle_t           ofmt;
2070         ofmt_status_t           oferr;
2071         uint_t                  ofmtflags = 0;
2072         char                    *aobjname = NULL;
2073         char                    *ifname = NULL;
2074         char                    *cp;
2075         ipadm_addr_info_t       *ainfop = NULL;
2076         ipadm_addr_info_t       *ptr;
2077         ipadm_status_t          status;
2078         boolean_t               found = _B_FALSE;
2079 
2080         opterr = 0;
2081         bzero(&state, sizeof (state));
2082         state.sps_propval = NULL;
2083         state.sps_parsable = _B_FALSE;
2084         state.sps_addrprop = _B_TRUE;
2085         state.sps_proto = MOD_PROTO_NONE;
2086         state.sps_status = state.sps_retstatus = IPADM_SUCCESS;
2087         while ((option = getopt_long(argc, argv, ":p:i:cPo:",
2088             show_prop_longopts, NULL)) != -1) {
2089                 switch (option) {
2090                 case 'p':
2091                         if (ipadm_str2nvlist(optarg, &proplist,
2092                             IPADM_NORVAL) != 0)
2093                                 die("invalid addrobj properties specified");
2094                         break;
2095                 case 'c':
2096                         state.sps_parsable = _B_TRUE;
2097                         break;
2098                 case 'o':
2099                         fields_str = optarg;
2100                         break;
2101                 default:
2102                         die_opterr(optopt, option, use);
2103                         break;
2104                 }
2105         }
2106         if (optind == argc - 1) {
2107                 aobjname = argv[optind];
2108                 cp = strchr(aobjname, '/');
2109                 if (cp == NULL)
2110                         die("invalid addrobj name provided");
2111                 if (*(cp + 1) == '\0') {
2112                         ifname = aobjname;
2113                         *cp = '\0';
2114                         aobjname = NULL;
2115                 }
2116         } else if (optind != argc) {
2117                 die("Usage: %s", use);
2118         }
2119         state.sps_proplist = proplist;
2120         if (state.sps_parsable)
2121                 ofmtflags |= OFMT_PARSABLE;
2122         oferr = ofmt_open(fields_str, addrprop_fields, ofmtflags, 0, &ofmt);
2123         ipadm_ofmt_check(oferr, state.sps_parsable, ofmt);
2124         state.sps_ofmt = ofmt;
2125 
2126         status = ipadm_addr_info(iph, ifname, &ainfop, 0, LIFC_DEFAULT);
2127         /* Return without printing any error, if no addresses were found */
2128         if (status == IPADM_NOTFOUND)
2129                 return;
2130         if (status != IPADM_SUCCESS)
2131                 die("error retrieving address: %s", ipadm_status2str(status));
2132 
2133         for (ptr = ainfop; ptr != NULL; ptr = IA_NEXT(ptr)) {
2134                 char    *taobjname = ptr->ia_aobjname;
2135 
2136                 if (taobjname[0] == '\0')
2137                         continue;
2138                 if (aobjname != NULL) {
2139                         if (strcmp(aobjname, taobjname) == 0)
2140                                 found = _B_TRUE;
2141                         else
2142                                 continue;
2143                 }
2144                 if (ptr->ia_atype == IPADM_ADDR_IPV6_ADDRCONF) {
2145                         if (found)
2146                                 break;
2147                         else
2148                                 continue;
2149                 }
2150                 (void) strlcpy(state.sps_aobjname, taobjname,
2151                     sizeof (state.sps_aobjname));
2152                 show_properties(&state, IPADMPROP_CLASS_ADDR);
2153                 if (found)
2154                         break;
2155         }
2156         ipadm_free_addr_info(ainfop);
2157 
2158         if (aobjname != NULL && !found)
2159                 die("addrobj not found: %s", aobjname);
2160 
2161         nvlist_free(proplist);
2162         ofmt_close(ofmt);
2163         if (state.sps_retstatus != IPADM_SUCCESS) {
2164                 ipadm_close(iph);
2165                 exit(EXIT_FAILURE);
2166         }
2167 }
2168 
2169 static void
2170 ipadm_ofmt_check(ofmt_status_t oferr, boolean_t parsable,
2171     ofmt_handle_t ofmt)
2172 {
2173         char buf[OFMT_BUFSIZE];
2174 
2175         if (oferr == OFMT_SUCCESS)
2176                 return;
2177         (void) ofmt_strerror(ofmt, oferr, buf, sizeof (buf));
2178         /*
2179          * All errors are considered fatal in parsable mode.
2180          * NOMEM errors are always fatal, regardless of mode.
2181          * For other errors, we print diagnostics in human-readable
2182          * mode and processs what we can.
2183          */
2184         if (parsable || oferr == OFMT_ENOFIELDS) {
2185                 ofmt_close(ofmt);
2186                 die(buf);
2187         } else {
2188                 warn(buf);
2189         }
2190 }
2191 
2192 /*
2193  * check if the `pstr' adheres to following syntax
2194  *      - prop=<value[,...]>      (for set)
2195  *      - prop                  (for reset)
2196  */
2197 static void
2198 ipadm_check_propstr(const char *pstr, boolean_t reset, const char *use)
2199 {
2200         char    *nv;
2201 
2202         nv = strchr(pstr, '=');
2203         if (reset) {
2204                 if (nv != NULL)
2205                         die("incorrect syntax used for -p.\n%s", use);
2206         } else {
2207                 if (nv == NULL || *++nv == '\0')
2208                         die("please specify the value to be set.\n%s", use);
2209                 nv = strchr(nv, '=');
2210                 /* cannot have multiple 'prop=val' for single -p */
2211                 if (nv != NULL)
2212                         die("cannot specify more than one prop=val at "
2213                             "a time.\n%s", use);
2214         }
2215 }