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