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