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