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