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