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