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