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