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