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 (c) 2013 by Delphix. All rights reserved.
  24  * Copyright (c) 2016, Chris Fraire <cfraire@me.com>.
  25  */
  26 
  27 /*
  28  * This file contains functions for address management such as creating
  29  * an address, deleting an address, enabling an address, disabling an
  30  * address, bringing an address down or up, setting/getting properties
  31  * on an address object and listing address information
  32  * for all addresses in active as well as persistent configuration.
  33  */
  34 #include <sys/types.h>
  35 #include <sys/socket.h>
  36 #include <sys/param.h>
  37 #include <netdb.h>
  38 #include <inet/ip.h>
  39 #include <string.h>
  40 #include <strings.h>
  41 #include <assert.h>
  42 #include <sys/sockio.h>
  43 #include <errno.h>
  44 #include <unistd.h>
  45 #include <stropts.h>
  46 #include <zone.h>
  47 #include <netinet/in.h>
  48 #include <arpa/inet.h>
  49 #include <fcntl.h>
  50 #include <ctype.h>
  51 #include <dhcpagent_util.h>
  52 #include <dhcpagent_ipc.h>
  53 #include <dhcp_inittab.h>
  54 #include <dhcp_symbol.h>
  55 #include <ipadm_ndpd.h>
  56 #include <libdladm.h>
  57 #include <libdllink.h>
  58 #include <libdliptun.h>
  59 #include <ifaddrs.h>
  60 #include "libipadm_impl.h"
  61 
  62 #define SIN6(a)         ((struct sockaddr_in6 *)a)
  63 #define SIN(a)          ((struct sockaddr_in *)a)
  64 
  65 static ipadm_status_t   i_ipadm_create_addr(ipadm_handle_t, ipadm_addrobj_t,
  66                             uint32_t);
  67 static ipadm_status_t   i_ipadm_create_dhcp(ipadm_handle_t, ipadm_addrobj_t,
  68                             uint32_t);
  69 static ipadm_status_t   i_ipadm_delete_dhcp(ipadm_handle_t, ipadm_addrobj_t,
  70                             boolean_t);
  71 static ipadm_status_t   i_ipadm_refresh_dhcp(ipadm_addrobj_t);
  72 static ipadm_status_t   i_ipadm_get_db_addr(ipadm_handle_t, const char *,
  73                             const char *, nvlist_t **);
  74 static ipadm_status_t   i_ipadm_op_dhcp(ipadm_addrobj_t, dhcp_ipc_type_t,
  75                             int *);
  76 static ipadm_status_t   i_ipadm_validate_create_addr(ipadm_handle_t,
  77                             ipadm_addrobj_t, uint32_t);
  78 static ipadm_status_t   i_ipadm_addr_persist_nvl(ipadm_handle_t, nvlist_t *,
  79                             uint32_t);
  80 static ipadm_status_t   i_ipadm_get_default_prefixlen(struct sockaddr_storage *,
  81                             uint32_t *);
  82 static ipadm_status_t   i_ipadm_get_static_addr_db(ipadm_handle_t,
  83                             ipadm_addrobj_t);
  84 static boolean_t        i_ipadm_is_user_aobjname_valid(const char *);
  85 static ipadm_prop_desc_t *      i_ipadm_get_addrprop_desc(const char *pname);
  86 
  87 /*
  88  * Callback functions to retrieve property values from the kernel. These
  89  * functions, when required, translate the values from the kernel to a format
  90  * suitable for printing. They also retrieve DEFAULT, PERM and POSSIBLE values
  91  * for a given property.
  92  */
  93 static ipadm_pd_getf_t  i_ipadm_get_prefixlen, i_ipadm_get_addr_flag,
  94                         i_ipadm_get_zone, i_ipadm_get_broadcast, i_ipadm_get_primary,
  95                         i_ipadm_get_reqhost;
  96 
  97 /*
  98  * Callback functions to set property values. These functions translate the
  99  * values to a format suitable for kernel consumption, allocate the necessary
 100  * ioctl buffers and then invoke ioctl(); or in the case of reqhost, get the
 101  * collaborating agent to set the value.
 102  */
 103 static ipadm_pd_setf_t  i_ipadm_set_prefixlen, i_ipadm_set_addr_flag,
 104                         i_ipadm_set_zone, i_ipadm_set_reqhost;
 105 
 106 static ipadm_status_t   i_ipadm_set_aobj_addrprop(ipadm_handle_t iph,
 107                         ipadm_addrobj_t ipaddr, uint_t flags, const char *propname);
 108 
 109 /* address properties description table */
 110 ipadm_prop_desc_t ipadm_addrprop_table[] = {
 111         { "broadcast", NULL, IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE, 0,
 112             NULL, NULL, i_ipadm_get_broadcast },
 113 
 114         { "deprecated", NULL, IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE, 0,
 115             i_ipadm_set_addr_flag, i_ipadm_get_onoff,
 116             i_ipadm_get_addr_flag },
 117 
 118         { IPADM_NVP_PREFIXLEN, NULL, IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE, 0,
 119             i_ipadm_set_prefixlen, i_ipadm_get_prefixlen,
 120             i_ipadm_get_prefixlen },
 121 
 122         /*
 123          * primary is read-only because there is no operation to un-set
 124          * DHCP_IF_PRIMARY in dhcpagent except to delete-addr and then
 125          * re-create-addr.
 126          */
 127         { "primary", NULL, IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE, 0,
 128                 NULL, NULL, i_ipadm_get_primary },
 129 
 130         { "private", NULL, IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE, 0,
 131             i_ipadm_set_addr_flag, i_ipadm_get_onoff, i_ipadm_get_addr_flag },
 132 
 133         { IPADM_NVP_REQHOST, NULL, IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE, 0,
 134             i_ipadm_set_reqhost, NULL, i_ipadm_get_reqhost },
 135 
 136         { "transmit", NULL, IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE, 0,
 137             i_ipadm_set_addr_flag, i_ipadm_get_onoff, i_ipadm_get_addr_flag },
 138 
 139         { "zone", NULL, IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE, 0,
 140             i_ipadm_set_zone, NULL, i_ipadm_get_zone },
 141 
 142         { NULL, NULL, 0, 0, 0, NULL, NULL, NULL }
 143 };
 144 
 145 static ipadm_prop_desc_t up_addrprop = { "up", NULL, IPADMPROP_CLASS_ADDR,
 146                                         MOD_PROTO_NONE, 0, NULL, NULL, NULL };
 147 
 148 /*
 149  * Helper function that initializes the `ipadm_ifname', `ipadm_aobjname', and
 150  * `ipadm_atype' fields of the given `ipaddr'.
 151  */
 152 void
 153 i_ipadm_init_addr(ipadm_addrobj_t ipaddr, const char *ifname,
 154     const char *aobjname, ipadm_addr_type_t atype)
 155 {
 156         bzero(ipaddr, sizeof (struct ipadm_addrobj_s));
 157         (void) strlcpy(ipaddr->ipadm_ifname, ifname,
 158             sizeof (ipaddr->ipadm_ifname));
 159         (void) strlcpy(ipaddr->ipadm_aobjname, aobjname,
 160             sizeof (ipaddr->ipadm_aobjname));
 161         ipaddr->ipadm_atype = atype;
 162 }
 163 
 164 /*
 165  * Determine the permission of the property depending on whether it has a
 166  * set() and/or get() callback functions.
 167  */
 168 static ipadm_status_t
 169 i_ipadm_pd2permstr(ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize)
 170 {
 171         uint_t  perm;
 172         size_t  nbytes;
 173 
 174         perm = 0;
 175         if (pdp->ipd_set != NULL)
 176                 perm |= MOD_PROP_PERM_WRITE;
 177         if (pdp->ipd_get != NULL)
 178                 perm |= MOD_PROP_PERM_READ;
 179 
 180         nbytes = snprintf(buf, *bufsize, "%c%c",
 181             ((perm & MOD_PROP_PERM_READ) != 0) ? 'r' : '-',
 182             ((perm & MOD_PROP_PERM_WRITE) != 0) ? 'w' : '-');
 183 
 184         if (nbytes >= *bufsize) {
 185                 /* insufficient buffer space */
 186                 *bufsize = nbytes + 1;
 187                 return (IPADM_NO_BUFS);
 188         }
 189         return (IPADM_SUCCESS);
 190 }
 191 
 192 /*
 193  * Given an addrobj with `ipadm_aobjname' filled in, i_ipadm_get_addrobj()
 194  * retrieves the information necessary for any operation on the object,
 195  * such as delete-addr, enable-addr, disable-addr, up-addr, down-addr,
 196  * refresh-addr, get-addrprop or set-addrprop. The information include
 197  * the logical interface number, address type, address family,
 198  * the interface id (if the address type is IPADM_ADDR_IPV6_ADDRCONF) and
 199  * the ipadm_flags that indicate if the address is present in
 200  * active configuration or persistent configuration or both. If the address
 201  * is not found, IPADM_NOTSUP is returned.
 202  */
 203 ipadm_status_t
 204 i_ipadm_get_addrobj(ipadm_handle_t iph, ipadm_addrobj_t ipaddr)
 205 {
 206         ipmgmt_aobjop_arg_t     larg;
 207         ipmgmt_aobjop_rval_t    rval, *rvalp;
 208         int                     err = 0;
 209 
 210         /* populate the door_call argument structure */
 211         larg.ia_cmd = IPMGMT_CMD_AOBJNAME2ADDROBJ;
 212         (void) strlcpy(larg.ia_aobjname, ipaddr->ipadm_aobjname,
 213             sizeof (larg.ia_aobjname));
 214 
 215         rvalp = &rval;
 216         err = ipadm_door_call(iph, &larg, sizeof (larg), (void **)&rvalp,
 217             sizeof (rval), B_FALSE);
 218         if (err != 0)
 219                 return (ipadm_errno2status(err));
 220         (void) strlcpy(ipaddr->ipadm_ifname, rval.ir_ifname,
 221             sizeof (ipaddr->ipadm_ifname));
 222         ipaddr->ipadm_lifnum = rval.ir_lnum;
 223         ipaddr->ipadm_atype = rval.ir_atype;
 224         ipaddr->ipadm_af = rval.ir_family;
 225         ipaddr->ipadm_flags = rval.ir_flags;
 226         switch (rval.ir_atype) {
 227         case IPADM_ADDR_IPV6_ADDRCONF:
 228                 ipaddr->ipadm_intfid = rval.ipmgmt_ir_intfid;
 229                 break;
 230         case IPADM_ADDR_DHCP:
 231                 ipaddr->ipadm_primary = rval.ipmgmt_ir_primary;
 232                 (void) strlcpy(ipaddr->ipadm_reqhost, rval.ipmgmt_ir_reqhost,
 233                     sizeof (ipaddr->ipadm_reqhost));
 234                 break;
 235         default:
 236                 break;
 237         }
 238 
 239         return (IPADM_SUCCESS);
 240 }
 241 
 242 /*
 243  * Retrieves the static address (IPv4 or IPv6) for the given address object
 244  * in `ipaddr' from persistent DB.
 245  */
 246 static ipadm_status_t
 247 i_ipadm_get_static_addr_db(ipadm_handle_t iph, ipadm_addrobj_t ipaddr)
 248 {
 249         ipadm_status_t          status;
 250         nvlist_t                *onvl;
 251         nvlist_t                *anvl = NULL;
 252         nvlist_t                *nvladdr;
 253         nvpair_t                *nvp;
 254         char                    *name;
 255         char                    *aobjname = ipaddr->ipadm_aobjname;
 256         char                    *sname;
 257         sa_family_t             af = AF_UNSPEC;
 258 
 259         /*
 260          * Get the address line in the nvlist `onvl' from ipmgmtd daemon.
 261          */
 262         status = i_ipadm_get_db_addr(iph, NULL, aobjname, &onvl);
 263         if (status != IPADM_SUCCESS)
 264                 return (status);
 265         /*
 266          * Walk through the nvlist `onvl' to extract the IPADM_NVP_IPV4ADDR
 267          * or the IPADM_NVP_IPV6ADDR name-value pair.
 268          */
 269         for (nvp = nvlist_next_nvpair(onvl, NULL); nvp != NULL;
 270             nvp = nvlist_next_nvpair(onvl, NULL)) {
 271                 if (nvpair_value_nvlist(nvp, &anvl) != 0)
 272                         continue;
 273                 if (nvlist_exists(anvl, IPADM_NVP_IPV4ADDR) ||
 274                     nvlist_exists(anvl, IPADM_NVP_IPV6ADDR))
 275                         break;
 276         }
 277         if (nvp == NULL)
 278                 goto fail;
 279         for (nvp = nvlist_next_nvpair(anvl, NULL);
 280             nvp != NULL; nvp = nvlist_next_nvpair(anvl, nvp)) {
 281                 name = nvpair_name(nvp);
 282                 if (strcmp(name, IPADM_NVP_IPV4ADDR) == 0) {
 283                         af = AF_INET;
 284                         break;
 285                 } else if (strcmp(name, IPADM_NVP_IPV6ADDR) == 0) {
 286                         af = AF_INET6;
 287                         break;
 288                 }
 289         }
 290         assert(af != AF_UNSPEC);
 291         if (nvpair_value_nvlist(nvp, &nvladdr) != 0 ||
 292             nvlist_lookup_string(nvladdr, IPADM_NVP_IPADDRHNAME, &sname) != 0 ||
 293             ipadm_set_addr(ipaddr, sname, af) != IPADM_SUCCESS) {
 294                 goto fail;
 295         }
 296         nvlist_free(onvl);
 297         return (IPADM_SUCCESS);
 298 fail:
 299         nvlist_free(onvl);
 300         return (IPADM_NOTFOUND);
 301 }
 302 
 303 /*
 304  * For the given `addrobj->ipadm_lifnum' and `addrobj->ipadm_af', this function
 305  * fills in the address objname, the address type and the ipadm_flags.
 306  */
 307 ipadm_status_t
 308 i_ipadm_get_lif2addrobj(ipadm_handle_t iph, ipadm_addrobj_t addrobj)
 309 {
 310         ipmgmt_aobjop_arg_t     larg;
 311         ipmgmt_aobjop_rval_t    rval, *rvalp;
 312         int                     err;
 313 
 314         larg.ia_cmd = IPMGMT_CMD_LIF2ADDROBJ;
 315         (void) strlcpy(larg.ia_ifname, addrobj->ipadm_ifname,
 316             sizeof (larg.ia_ifname));
 317         larg.ia_lnum = addrobj->ipadm_lifnum;
 318         larg.ia_family = addrobj->ipadm_af;
 319 
 320         rvalp = &rval;
 321         err = ipadm_door_call(iph, &larg, sizeof (larg), (void **)&rvalp,
 322             sizeof (rval), B_FALSE);
 323         if (err != 0)
 324                 return (ipadm_errno2status(err));
 325         (void) strlcpy(addrobj->ipadm_aobjname, rval.ir_aobjname,
 326             sizeof (addrobj->ipadm_aobjname));
 327         addrobj->ipadm_atype = rval.ir_atype;
 328         addrobj->ipadm_flags = rval.ir_flags;
 329 
 330         return (IPADM_SUCCESS);
 331 }
 332 
 333 /*
 334  * Adds an addrobj to ipmgmtd daemon's aobjmap (active configuration).
 335  * with the given name and logical interface number.
 336  * This API is called by in.ndpd to add addrobjs when new prefixes or
 337  * dhcpv6 addresses are configured.
 338  */
 339 ipadm_status_t
 340 ipadm_add_aobjname(ipadm_handle_t iph, const char *ifname, sa_family_t af,
 341     const char *aobjname, ipadm_addr_type_t atype, int lnum)
 342 {
 343         ipmgmt_aobjop_arg_t     larg;
 344         int                     err;
 345 
 346         larg.ia_cmd = IPMGMT_CMD_ADDROBJ_ADD;
 347         (void) strlcpy(larg.ia_ifname, ifname, sizeof (larg.ia_ifname));
 348         (void) strlcpy(larg.ia_aobjname, aobjname, sizeof (larg.ia_aobjname));
 349         larg.ia_atype = atype;
 350         larg.ia_lnum = lnum;
 351         larg.ia_family = af;
 352         err = ipadm_door_call(iph, &larg, sizeof (larg), NULL, 0, B_FALSE);
 353         return (ipadm_errno2status(err));
 354 }
 355 
 356 /*
 357  * Deletes an address object with given name and logical number from ipmgmtd
 358  * daemon's aobjmap (active configuration). This API is called by in.ndpd to
 359  * remove addrobjs when auto-configured prefixes or dhcpv6 addresses are
 360  * removed.
 361  */
 362 ipadm_status_t
 363 ipadm_delete_aobjname(ipadm_handle_t iph, const char *ifname, sa_family_t af,
 364     const char *aobjname, ipadm_addr_type_t atype, int lnum)
 365 {
 366         struct ipadm_addrobj_s  aobj;
 367 
 368         i_ipadm_init_addr(&aobj, ifname, aobjname, atype);
 369         aobj.ipadm_af = af;
 370         aobj.ipadm_lifnum = lnum;
 371         return (i_ipadm_delete_addrobj(iph, &aobj, IPADM_OPT_ACTIVE));
 372 }
 373 
 374 /*
 375  * Gets all the addresses from active configuration and populates the
 376  * address information in `addrinfo'.
 377  */
 378 static ipadm_status_t
 379 i_ipadm_active_addr_info(ipadm_handle_t iph, const char *ifname,
 380     ipadm_addr_info_t **addrinfo, uint32_t ipadm_flags, int64_t lifc_flags)
 381 {
 382         ipadm_status_t          status;
 383         struct ifaddrs          *ifap, *ifa;
 384         ipadm_addr_info_t       *curr, *prev = NULL;
 385         struct ifaddrs          *cifaddr;
 386         struct lifreq           lifr;
 387         int                     sock;
 388         uint64_t                flags;
 389         char                    cifname[LIFNAMSIZ];
 390         struct sockaddr_in6     *sin6;
 391         struct ipadm_addrobj_s  ipaddr;
 392         char                    *sep;
 393         int                     lnum;
 394 
 395 retry:
 396         *addrinfo = NULL;
 397 
 398         /* Get all the configured addresses */
 399         if (getallifaddrs(AF_UNSPEC, &ifa, lifc_flags) < 0)
 400                 return (ipadm_errno2status(errno));
 401         /* Return if there is nothing to process. */
 402         if (ifa == NULL)
 403                 return (IPADM_SUCCESS);
 404         bzero(&lifr, sizeof (lifr));
 405         for (ifap = ifa; ifap != NULL; ifap = ifap->ifa_next) {
 406                 struct sockaddr_storage data;
 407 
 408                 (void) strlcpy(cifname, ifap->ifa_name, sizeof (cifname));
 409                 lnum = 0;
 410                 if ((sep = strrchr(cifname, ':')) != NULL) {
 411                         *sep++ = '\0';
 412                         lnum = atoi(sep);
 413                 }
 414                 if (ifname != NULL && strcmp(cifname, ifname) != 0)
 415                         continue;
 416                 if (!(ipadm_flags & IPADM_OPT_ZEROADDR) &&
 417                     sockaddrunspec(ifap->ifa_addr) &&
 418                     !(ifap->ifa_flags & IFF_DHCPRUNNING))
 419                         continue;
 420 
 421                 /* Allocate and populate the current node in the list. */
 422                 if ((curr = calloc(1, sizeof (ipadm_addr_info_t))) == NULL)
 423                         goto fail;
 424 
 425                 /* Link to the list in `addrinfo'. */
 426                 if (prev != NULL)
 427                         prev->ia_ifa.ifa_next = &curr->ia_ifa;
 428                 else
 429                         *addrinfo = curr;
 430                 prev = curr;
 431 
 432                 cifaddr = &curr->ia_ifa;
 433                 if ((cifaddr->ifa_name = strdup(ifap->ifa_name)) == NULL)
 434                         goto fail;
 435                 cifaddr->ifa_flags = ifap->ifa_flags;
 436                 cifaddr->ifa_addr = malloc(sizeof (struct sockaddr_storage));
 437                 if (cifaddr->ifa_addr == NULL)
 438                         goto fail;
 439                 (void) memcpy(cifaddr->ifa_addr, ifap->ifa_addr,
 440                     sizeof (struct sockaddr_storage));
 441                 cifaddr->ifa_netmask = malloc(sizeof (struct sockaddr_storage));
 442                 if (cifaddr->ifa_netmask == NULL)
 443                         goto fail;
 444                 (void) memcpy(cifaddr->ifa_netmask, ifap->ifa_netmask,
 445                     sizeof (struct sockaddr_storage));
 446                 if (ifap->ifa_flags & IFF_POINTOPOINT) {
 447                         cifaddr->ifa_dstaddr = malloc(
 448                             sizeof (struct sockaddr_storage));
 449                         if (cifaddr->ifa_dstaddr == NULL)
 450                                 goto fail;
 451                         (void) memcpy(cifaddr->ifa_dstaddr, ifap->ifa_dstaddr,
 452                             sizeof (struct sockaddr_storage));
 453                 } else if (ifap->ifa_flags & IFF_BROADCAST) {
 454                         cifaddr->ifa_broadaddr = malloc(
 455                             sizeof (struct sockaddr_storage));
 456                         if (cifaddr->ifa_broadaddr == NULL)
 457                                 goto fail;
 458                         (void) memcpy(cifaddr->ifa_broadaddr,
 459                             ifap->ifa_broadaddr,
 460                             sizeof (struct sockaddr_storage));
 461                 }
 462                 /* Get the addrobj name stored for this logical interface. */
 463                 ipaddr.ipadm_aobjname[0] = '\0';
 464                 (void) strlcpy(ipaddr.ipadm_ifname, cifname,
 465                     sizeof (ipaddr.ipadm_ifname));
 466                 ipaddr.ipadm_lifnum = lnum;
 467                 ipaddr.ipadm_af = ifap->ifa_addr->sa_family;
 468                 status = i_ipadm_get_lif2addrobj(iph, &ipaddr);
 469 
 470                 /*
 471                  * Find address type from ifa_flags, if we could not get it
 472                  * from daemon.
 473                  */
 474                 (void) memcpy(&data, ifap->ifa_addr,
 475                     sizeof (struct sockaddr_in6));
 476                 sin6 = SIN6(&data);
 477                 flags = ifap->ifa_flags;
 478                 if (status == IPADM_SUCCESS) {
 479                         (void) strlcpy(curr->ia_aobjname, ipaddr.ipadm_aobjname,
 480                             sizeof (curr->ia_aobjname));
 481                         curr->ia_atype = ipaddr.ipadm_atype;
 482                 } else if ((flags & IFF_DHCPRUNNING) && (!(flags & IFF_IPV6) ||
 483                     !IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))) {
 484                         curr->ia_atype = IPADM_ADDR_DHCP;
 485                 } else if (flags & IFF_ADDRCONF) {
 486                         curr->ia_atype = IPADM_ADDR_IPV6_ADDRCONF;
 487                 } else {
 488                         curr->ia_atype = IPADM_ADDR_STATIC;
 489                 }
 490                 /*
 491                  * Populate the flags for the active configuration from the
 492                  * `ifa_flags'.
 493                  */
 494                 if (!(flags & IFF_UP)) {
 495                         if (flags & IFF_DUPLICATE)
 496                                 curr->ia_state = IFA_DUPLICATE;
 497                         else
 498                                 curr->ia_state = IFA_DOWN;
 499                 } else {
 500                         curr->ia_cflags |= IA_UP;
 501                         if (flags & IFF_RUNNING) {
 502                                 (void) strlcpy(lifr.lifr_name, ifap->ifa_name,
 503                                     sizeof (lifr.lifr_name));
 504                                 sock = (ifap->ifa_addr->sa_family == AF_INET) ?
 505                                     iph->iph_sock : iph->iph_sock6;
 506                                 if (ioctl(sock, SIOCGLIFDADSTATE,
 507                                     (caddr_t)&lifr) < 0) {
 508                                         if (errno == ENXIO) {
 509                                                 freeifaddrs(ifa);
 510                                                 ipadm_free_addr_info(*addrinfo);
 511                                                 goto retry;
 512                                         }
 513                                         goto fail;
 514                                 }
 515                                 if (lifr.lifr_dadstate == DAD_IN_PROGRESS)
 516                                         curr->ia_state = IFA_TENTATIVE;
 517                                 else
 518                                         curr->ia_state = IFA_OK;
 519                         } else {
 520                                 curr->ia_state = IFA_INACCESSIBLE;
 521                         }
 522                 }
 523                 if (flags & IFF_UNNUMBERED)
 524                         curr->ia_cflags |= IA_UNNUMBERED;
 525                 if (flags & IFF_PRIVATE)
 526                         curr->ia_cflags |= IA_PRIVATE;
 527                 if (flags & IFF_TEMPORARY)
 528                         curr->ia_cflags |= IA_TEMPORARY;
 529                 if (flags & IFF_DEPRECATED)
 530                         curr->ia_cflags |= IA_DEPRECATED;
 531 
 532         }
 533 
 534         freeifaddrs(ifa);
 535         return (IPADM_SUCCESS);
 536 
 537 fail:
 538         /* On error, cleanup everything and return. */
 539         ipadm_free_addr_info(*addrinfo);
 540         *addrinfo = NULL;
 541         freeifaddrs(ifa);
 542         return (ipadm_errno2status(errno));
 543 }
 544 
 545 /*
 546  * From the given `name', i_ipadm_name2atype() deduces the address type
 547  * and address family. If the `name' implies an address, it returns B_TRUE.
 548  * Else, returns B_FALSE and leaves the output parameters unchanged.
 549  */
 550 boolean_t
 551 i_ipadm_name2atype(const char *name, sa_family_t *af, ipadm_addr_type_t *type)
 552 {
 553         boolean_t       is_addr = B_TRUE;
 554 
 555         if (strcmp(name, IPADM_NVP_IPV4ADDR) == 0) {
 556                 *af = AF_INET;
 557                 *type = IPADM_ADDR_STATIC;
 558         } else if (strcmp(name, IPADM_NVP_IPV6ADDR) == 0) {
 559                 *af = AF_INET6;
 560                 *type = IPADM_ADDR_STATIC;
 561         } else if (strcmp(name, IPADM_NVP_DHCP) == 0) {
 562                 *af = AF_INET;
 563                 *type = IPADM_ADDR_DHCP;
 564         } else if (strcmp(name, IPADM_NVP_INTFID) == 0) {
 565                 *af = AF_INET6;
 566                 *type = IPADM_ADDR_IPV6_ADDRCONF;
 567         } else {
 568                 is_addr = B_FALSE;
 569         }
 570 
 571         return (is_addr);
 572 }
 573 
 574 /*
 575  * Parses the given nvlist `nvl' for an address or an address property.
 576  * The input nvlist must contain either an address or an address property.
 577  * `ainfo' is an input as well as output parameter. When an address or an
 578  * address property is found, `ainfo' is updated with the information found.
 579  * Some of the fields may be already filled in by the calling function.
 580  *
 581  * The fields that will be filled/updated by this function are `ia_pflags',
 582  * `ia_sname' and `ia_dname'. Values for `ia_pflags' are obtained if the `nvl'
 583  * contains an address property. `ia_sname', `ia_dname', and `ia_pflags' are
 584  * obtained if `nvl' contains an address.
 585  */
 586 static ipadm_status_t
 587 i_ipadm_nvl2ainfo_common(nvlist_t *nvl, ipadm_addr_info_t *ainfo)
 588 {
 589         nvlist_t                *nvladdr;
 590         char                    *name;
 591         char                    *propstr = NULL;
 592         char                    *sname, *dname;
 593         nvpair_t                *nvp;
 594         sa_family_t             af;
 595         ipadm_addr_type_t       atype;
 596         boolean_t               is_addr = B_FALSE;
 597         int                     err;
 598 
 599         for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL;
 600             nvp = nvlist_next_nvpair(nvl, nvp)) {
 601                 name = nvpair_name(nvp);
 602                 if (i_ipadm_name2atype(name, &af, &atype)) {
 603                         err = nvpair_value_nvlist(nvp, &nvladdr);
 604                         is_addr = B_TRUE;
 605                 } else if (IPADM_PRIV_NVP(name)) {
 606                         continue;
 607                 } else {
 608                         err = nvpair_value_string(nvp, &propstr);
 609                 }
 610                 if (err != 0)
 611                         return (ipadm_errno2status(err));
 612         }
 613 
 614         if (is_addr) {
 615                 /*
 616                  * We got an address from the nvlist `nvl'.
 617                  * Parse `nvladdr' and populate relevant information
 618                  * in `ainfo'.
 619                  */
 620                 switch (atype) {
 621                 case IPADM_ADDR_STATIC:
 622                         if (strcmp(name, "up") == 0 &&
 623                             strcmp(propstr, "yes") == 0) {
 624                                 ainfo->ia_pflags |= IA_UP;
 625                         }
 626                         /*
 627                          * For static addresses, we need to get the hostnames.
 628                          */
 629                         err = nvlist_lookup_string(nvladdr,
 630                             IPADM_NVP_IPADDRHNAME, &sname);
 631                         if (err != 0)
 632                                 return (ipadm_errno2status(err));
 633                         (void) strlcpy(ainfo->ia_sname, sname,
 634                             sizeof (ainfo->ia_sname));
 635                         err = nvlist_lookup_string(nvladdr,
 636                             IPADM_NVP_IPDADDRHNAME, &dname);
 637                         if (err == 0) {
 638                                 (void) strlcpy(ainfo->ia_dname, dname,
 639                                     sizeof (ainfo->ia_dname));
 640                         }
 641                         break;
 642                 case IPADM_ADDR_DHCP:
 643                 case IPADM_ADDR_IPV6_ADDRCONF:
 644                         /*
 645                          * dhcp and addrconf address objects are always
 646                          * marked up when re-enabled.
 647                          */
 648                         ainfo->ia_pflags |= IA_UP;
 649                         break;
 650                 default:
 651                         return (IPADM_FAILURE);
 652                 }
 653         } else {
 654                 /*
 655                  * We got an address property from `nvl'. Parse the
 656                  * name and the property value. Update the `ainfo->ia_pflags'
 657                  * for the flags.
 658                  */
 659                 if (strcmp(name, "deprecated") == 0) {
 660                         if (strcmp(propstr, IPADM_ONSTR) == 0)
 661                                 ainfo->ia_pflags |= IA_DEPRECATED;
 662                 } else if (strcmp(name, "private") == 0) {
 663                         if (strcmp(propstr, IPADM_ONSTR) == 0)
 664                                 ainfo->ia_pflags |= IA_PRIVATE;
 665                 }
 666         }
 667 
 668         return (IPADM_SUCCESS);
 669 }
 670 
 671 /*
 672  * Parses the given nvlist `nvl' for an address or an address property.
 673  * The input nvlist must contain either an address or an address property.
 674  * `ainfo' is an input as well as output parameter. When an address or an
 675  * address property is found, `ainfo' is updated with the information found.
 676  * Some of the fields may be already filled in by the calling function,
 677  * because of previous calls to i_ipadm_nvl2ainfo_active().
 678  *
 679  * Since the address object in `nvl' is also in the active configuration, the
 680  * fields that will be filled/updated by this function are `ia_pflags',
 681  * `ia_sname' and `ia_dname'.
 682  *
 683  * If this function returns an error, the calling function will take
 684  * care of freeing the fields in `ainfo'.
 685  */
 686 static ipadm_status_t
 687 i_ipadm_nvl2ainfo_active(nvlist_t *nvl, ipadm_addr_info_t *ainfo)
 688 {
 689         return (i_ipadm_nvl2ainfo_common(nvl, ainfo));
 690 }
 691 
 692 /*
 693  * Parses the given nvlist `nvl' for an address or an address property.
 694  * The input nvlist must contain either an address or an address property.
 695  * `ainfo' is an input as well as output parameter. When an address or an
 696  * address property is found, `ainfo' is updated with the information found.
 697  * Some of the fields may be already filled in by the calling function,
 698  * because of previous calls to i_ipadm_nvl2ainfo_persist().
 699  *
 700  * All the relevant fields in `ainfo' will be filled by this function based
 701  * on what we find in `nvl'.
 702  *
 703  * If this function returns an error, the calling function will take
 704  * care of freeing the fields in `ainfo'.
 705  */
 706 static ipadm_status_t
 707 i_ipadm_nvl2ainfo_persist(nvlist_t *nvl, ipadm_addr_info_t *ainfo)
 708 {
 709         nvlist_t                *nvladdr;
 710         struct ifaddrs          *ifa;
 711         char                    *name;
 712         char                    *ifname = NULL;
 713         char                    *aobjname = NULL;
 714         char                    *propstr = NULL;
 715         nvpair_t                *nvp;
 716         sa_family_t             af;
 717         ipadm_addr_type_t       atype;
 718         boolean_t               is_addr = B_FALSE;
 719         size_t                  size = sizeof (struct sockaddr_storage);
 720         uint32_t                plen = 0;
 721         int                     err;
 722         ipadm_status_t          status;
 723 
 724         status = i_ipadm_nvl2ainfo_common(nvl, ainfo);
 725         if (status != IPADM_SUCCESS)
 726                 return (status);
 727 
 728         for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL;
 729             nvp = nvlist_next_nvpair(nvl, nvp)) {
 730                 name = nvpair_name(nvp);
 731                 if (strcmp(name, IPADM_NVP_IFNAME) == 0) {
 732                         err = nvpair_value_string(nvp, &ifname);
 733                 } else if (strcmp(name, IPADM_NVP_AOBJNAME) == 0) {
 734                         err = nvpair_value_string(nvp, &aobjname);
 735                 } else if (i_ipadm_name2atype(name, &af, &atype)) {
 736                         err = nvpair_value_nvlist(nvp, &nvladdr);
 737                         is_addr = B_TRUE;
 738                 } else {
 739                         err = nvpair_value_string(nvp, &propstr);
 740                 }
 741                 if (err != 0)
 742                         return (ipadm_errno2status(err));
 743         }
 744 
 745         ifa = &ainfo->ia_ifa;
 746         (void) strlcpy(ainfo->ia_aobjname, aobjname,
 747             sizeof (ainfo->ia_aobjname));
 748         if (ifa->ifa_name == NULL && (ifa->ifa_name = strdup(ifname)) == NULL)
 749                 return (IPADM_NO_MEMORY);
 750         if (is_addr) {
 751                 struct sockaddr_in6 data;
 752 
 753                 /*
 754                  * We got an address from the nvlist `nvl'.
 755                  * Parse `nvladdr' and populate `ifa->ifa_addr'.
 756                  */
 757                 ainfo->ia_atype = atype;
 758                 if ((ifa->ifa_addr = calloc(1, size)) == NULL)
 759                         return (IPADM_NO_MEMORY);
 760                 switch (atype) {
 761                 case IPADM_ADDR_STATIC:
 762                         ifa->ifa_addr->sa_family = af;
 763                         break;
 764                 case IPADM_ADDR_DHCP:
 765                         ifa->ifa_addr->sa_family = AF_INET;
 766                         break;
 767                 case IPADM_ADDR_IPV6_ADDRCONF:
 768                         data.sin6_family = AF_INET6;
 769                         if (i_ipadm_nvl2in6_addr(nvladdr, IPADM_NVP_IPNUMADDR,
 770                             &data.sin6_addr) != IPADM_SUCCESS)
 771                                 return (IPADM_NO_MEMORY);
 772                         err = nvlist_lookup_uint32(nvladdr, IPADM_NVP_PREFIXLEN,
 773                             &plen);
 774                         if (err != 0)
 775                                 return (ipadm_errno2status(err));
 776                         if ((ifa->ifa_netmask = malloc(size)) == NULL)
 777                                 return (IPADM_NO_MEMORY);
 778                         if ((err = plen2mask(plen, af, ifa->ifa_netmask)) != 0)
 779                                 return (ipadm_errno2status(err));
 780                         (void) memcpy(ifa->ifa_addr, &data, sizeof (data));
 781                         break;
 782                 default:
 783                         return (IPADM_FAILURE);
 784                 }
 785         } else {
 786                 if (strcmp(name, "prefixlen") == 0) {
 787                         /*
 788                          * If a prefixlen was found, update the
 789                          * `ainfo->ia_ifa.ifa_netmask'.
 790                          */
 791 
 792                         if ((ifa->ifa_netmask = malloc(size)) == NULL)
 793                                 return (IPADM_NO_MEMORY);
 794                         /*
 795                          * Address property lines always follow the address
 796                          * line itself in the persistent db. We must have
 797                          * found a valid `ainfo->ia_ifa.ifa_addr' by now.
 798                          */
 799                         assert(ifa->ifa_addr != NULL);
 800                         err = plen2mask(atoi(propstr), ifa->ifa_addr->sa_family,
 801                             ifa->ifa_netmask);
 802                         if (err != 0)
 803                                 return (ipadm_errno2status(err));
 804                 }
 805         }
 806 
 807         return (IPADM_SUCCESS);
 808 }
 809 
 810 /*
 811  * Retrieves all addresses from active config and appends to it the
 812  * addresses that are found only in persistent config. In addition,
 813  * it updates the persistent fields for each address from information
 814  * found in persistent config. The output parameter `addrinfo' contains
 815  * complete information regarding all addresses in active as well as
 816  * persistent config.
 817  */
 818 static ipadm_status_t
 819 i_ipadm_get_all_addr_info(ipadm_handle_t iph, const char *ifname,
 820     ipadm_addr_info_t **addrinfo, uint32_t ipadm_flags, int64_t lifc_flags)
 821 {
 822         nvlist_t                *nvladdr = NULL;
 823         nvlist_t                *onvl = NULL;
 824         nvpair_t                *nvp;
 825         ipadm_status_t          status;
 826         ipadm_addr_info_t       *ainfo = NULL;
 827         ipadm_addr_info_t       *curr;
 828         ipadm_addr_info_t       *last = NULL;
 829         char                    *aobjname;
 830 
 831         /* Get all addresses from active config. */
 832         status = i_ipadm_active_addr_info(iph, ifname, &ainfo, ipadm_flags,
 833             lifc_flags);
 834         if (status != IPADM_SUCCESS)
 835                 goto fail;
 836 
 837         /* Get all addresses from persistent config. */
 838         status = i_ipadm_get_db_addr(iph, ifname, NULL, &onvl);
 839         /*
 840          * If no address was found in persistent config, just
 841          * return what we found in active config.
 842          */
 843         if (status == IPADM_NOTFOUND) {
 844                 /*
 845                  * If nothing was found neither active nor persistent
 846                  * config, this means that the interface does not exist,
 847                  * if one was provided in `ifname'.
 848                  */
 849                 if (ainfo == NULL && ifname != NULL)
 850                         return (IPADM_ENXIO);
 851                 *addrinfo = ainfo;
 852                 return (IPADM_SUCCESS);
 853         }
 854         /* In case of any other error, cleanup and return. */
 855         if (status != IPADM_SUCCESS)
 856                 goto fail;
 857         /* we append to make sure, loopback addresses are first */
 858         if (ainfo != NULL) {
 859                 for (curr = ainfo; IA_NEXT(curr) != NULL; curr = IA_NEXT(curr))
 860                         ;
 861                 last = curr;
 862         }
 863 
 864         /*
 865          * `onvl' will contain all the address lines from the db. Each line
 866          * could contain the address itself or an address property. Addresses
 867          * and address properties are found in separate lines.
 868          *
 869          * If an address A was found in active, we will already have `ainfo',
 870          * and it is present in persistent configuration as well, we need to
 871          * update `ainfo' with persistent information (`ia_pflags).
 872          * For each address B found only in persistent configuration,
 873          * append the address to the list with the address info for B from
 874          * `onvl'.
 875          */
 876         for (nvp = nvlist_next_nvpair(onvl, NULL); nvp != NULL;
 877             nvp = nvlist_next_nvpair(onvl, nvp)) {
 878                 if (nvpair_value_nvlist(nvp, &nvladdr) != 0)
 879                         continue;
 880                 if (nvlist_lookup_string(nvladdr, IPADM_NVP_AOBJNAME,
 881                     &aobjname) != 0)
 882                         continue;
 883                 for (curr = ainfo; curr != NULL; curr = IA_NEXT(curr)) {
 884                         if (strcmp(curr->ia_aobjname, aobjname) == 0)
 885                                 break;
 886                 }
 887                 if (curr == NULL) {
 888                         /*
 889                          * We did not find this address object in `ainfo'.
 890                          * This means that the address object exists only
 891                          * in the persistent configuration. Get its
 892                          * details and append to `ainfo'.
 893                          */
 894                         curr = calloc(1, sizeof (ipadm_addr_info_t));
 895                         if (curr == NULL)
 896                                 goto fail;
 897                         curr->ia_state = IFA_DISABLED;
 898                         if (last != NULL)
 899                                 last->ia_ifa.ifa_next = &curr->ia_ifa;
 900                         else
 901                                 ainfo = curr;
 902                         last = curr;
 903                 }
 904                 /*
 905                  * Fill relevant fields of `curr' from the persistent info
 906                  * in `nvladdr'. Call the appropriate function based on the
 907                  * `ia_state' value.
 908                  */
 909                 if (curr->ia_state == IFA_DISABLED)
 910                         status = i_ipadm_nvl2ainfo_persist(nvladdr, curr);
 911                 else
 912                         status = i_ipadm_nvl2ainfo_active(nvladdr, curr);
 913                 if (status != IPADM_SUCCESS)
 914                         goto fail;
 915         }
 916         *addrinfo = ainfo;
 917         nvlist_free(onvl);
 918         return (status);
 919 fail:
 920         /* On error, cleanup and return. */
 921         nvlist_free(onvl);
 922         ipadm_free_addr_info(ainfo);
 923         *addrinfo = NULL;
 924         return (status);
 925 }
 926 
 927 /*
 928  * Callback function that sets the property `prefixlen' on the address
 929  * object in `arg' to the value in `pval'.
 930  */
 931 /* ARGSUSED */
 932 static ipadm_status_t
 933 i_ipadm_set_prefixlen(ipadm_handle_t iph, const void *arg,
 934     ipadm_prop_desc_t *pdp, const void *pval, uint_t af, uint_t flags)
 935 {
 936         struct sockaddr_storage netmask;
 937         struct lifreq           lifr;
 938         int                     err, s;
 939         unsigned long           prefixlen, abits;
 940         char                    *end;
 941         ipadm_addrobj_t         ipaddr = (ipadm_addrobj_t)arg;
 942 
 943         if (ipaddr->ipadm_atype == IPADM_ADDR_DHCP)
 944                 return (IPADM_NOTSUP);
 945 
 946         errno = 0;
 947         prefixlen = strtoul(pval, &end, 10);
 948         if (errno != 0 || *end != '\0')
 949                 return (IPADM_INVALID_ARG);
 950 
 951         abits = (af == AF_INET ? IP_ABITS : IPV6_ABITS);
 952         if (prefixlen == 0 || prefixlen == (abits - 1))
 953                 return (IPADM_INVALID_ARG);
 954 
 955         if ((err = plen2mask(prefixlen, af, (struct sockaddr *)&netmask)) != 0)
 956                 return (ipadm_errno2status(err));
 957 
 958         s = (af == AF_INET ? iph->iph_sock : iph->iph_sock6);
 959 
 960         bzero(&lifr, sizeof (lifr));
 961         i_ipadm_addrobj2lifname(ipaddr, lifr.lifr_name,
 962             sizeof (lifr.lifr_name));
 963         (void) memcpy(&lifr.lifr_addr, &netmask, sizeof (netmask));
 964         if (ioctl(s, SIOCSLIFNETMASK, (caddr_t)&lifr) < 0)
 965                 return (ipadm_errno2status(errno));
 966 
 967         /* now, change the broadcast address to reflect the prefixlen */
 968         if (af == AF_INET) {
 969                 /*
 970                  * get the interface address and set it, this should reset
 971                  * the broadcast address.
 972                  */
 973                 (void) ioctl(s, SIOCGLIFADDR, (caddr_t)&lifr);
 974                 (void) ioctl(s, SIOCSLIFADDR, (caddr_t)&lifr);
 975         }
 976 
 977         return (IPADM_SUCCESS);
 978 }
 979 
 980 
 981 /*
 982  * Callback function that sets the given value `pval' to one of the
 983  * properties among `deprecated', `private', and `transmit' as defined in
 984  * `pdp', on the address object in `arg'.
 985  */
 986 /* ARGSUSED */
 987 static ipadm_status_t
 988 i_ipadm_set_addr_flag(ipadm_handle_t iph, const void *arg,
 989     ipadm_prop_desc_t *pdp, const void *pval, uint_t af, uint_t flags)
 990 {
 991         char            lifname[LIFNAMSIZ];
 992         uint64_t        on_flags = 0, off_flags = 0;
 993         boolean_t       on;
 994         ipadm_addrobj_t ipaddr = (ipadm_addrobj_t)arg;
 995 
 996         if (ipaddr->ipadm_atype == IPADM_ADDR_DHCP &&
 997             strcmp(pdp->ipd_name, "deprecated") == 0)
 998                 return (IPADM_NOTSUP);
 999 
1000         if (strcmp(pval, IPADM_ONSTR) == 0)
1001                 on = B_TRUE;
1002         else if (strcmp(pval, IPADM_OFFSTR) == 0)
1003                 on = B_FALSE;
1004         else
1005                 return (IPADM_INVALID_ARG);
1006 
1007         if (strcmp(pdp->ipd_name, "private") == 0) {
1008                 if (on)
1009                         on_flags = IFF_PRIVATE;
1010                 else
1011                         off_flags = IFF_PRIVATE;
1012         } else if (strcmp(pdp->ipd_name, "transmit") == 0) {
1013                 if (on)
1014                         off_flags = IFF_NOXMIT;
1015                 else
1016                         on_flags = IFF_NOXMIT;
1017         } else if (strcmp(pdp->ipd_name, "deprecated") == 0) {
1018                 if (on)
1019                         on_flags = IFF_DEPRECATED;
1020                 else
1021                         off_flags = IFF_DEPRECATED;
1022         } else {
1023                 return (IPADM_PROP_UNKNOWN);
1024         }
1025 
1026         i_ipadm_addrobj2lifname(ipaddr, lifname, sizeof (lifname));
1027         return (i_ipadm_set_flags(iph, lifname, af, on_flags, off_flags));
1028 }
1029 
1030 /*
1031  * Callback function that sets the property `zone' on the address
1032  * object in `arg' to the value in `pval'.
1033  */
1034 /* ARGSUSED */
1035 static ipadm_status_t
1036 i_ipadm_set_zone(ipadm_handle_t iph, const void *arg,
1037     ipadm_prop_desc_t *pdp, const void *pval, uint_t af, uint_t flags)
1038 {
1039         struct lifreq   lifr;
1040         zoneid_t        zoneid;
1041         int             s;
1042 
1043         /*
1044          * To modify the zone assignment such that it persists across
1045          * reboots, zonecfg(1M) must be used.
1046          */
1047         if (flags & IPADM_OPT_PERSIST) {
1048                 return (IPADM_NOTSUP);
1049         } else if (flags & IPADM_OPT_ACTIVE) {
1050                 /* put logical interface into all zones */
1051                 if (strcmp(pval, "all-zones") == 0) {
1052                         zoneid = ALL_ZONES;
1053                 } else {
1054                         /* zone must be ready or running */
1055                         if ((zoneid = getzoneidbyname(pval)) == -1)
1056                                 return (ipadm_errno2status(errno));
1057                 }
1058         } else {
1059                 return (IPADM_INVALID_ARG);
1060         }
1061 
1062         s = (af == AF_INET ? iph->iph_sock : iph->iph_sock6);
1063         bzero(&lifr, sizeof (lifr));
1064         i_ipadm_addrobj2lifname((ipadm_addrobj_t)arg, lifr.lifr_name,
1065             sizeof (lifr.lifr_name));
1066         lifr.lifr_zoneid = zoneid;
1067         if (ioctl(s, SIOCSLIFZONE, (caddr_t)&lifr) < 0)
1068                 return (ipadm_errno2status(errno));
1069 
1070         return (IPADM_SUCCESS);
1071 }
1072 
1073 /*
1074  * Callback function that sets the property `reqhost' on the address
1075  * object in `arg' to the value in `pval'.
1076  */
1077 /* ARGSUSED */
1078 static ipadm_status_t
1079 i_ipadm_set_reqhost(ipadm_handle_t iph, const void *arg,
1080     ipadm_prop_desc_t *pdp, const void *pval, uint_t af, uint_t flags)
1081 {
1082         ipadm_status_t  status;
1083         ipadm_addrobj_t         ipaddr = (ipadm_addrobj_t)arg;
1084 
1085         if (ipaddr->ipadm_atype != IPADM_ADDR_DHCP)
1086                 return (IPADM_NOTSUP);
1087 
1088         /*
1089          * If requested to set reqhost just from active config but the
1090          * address is not in active config, return error.
1091          */
1092         if (!(ipaddr->ipadm_flags & IPMGMT_ACTIVE) &&
1093             (flags & IPADM_OPT_ACTIVE) && !(flags & IPADM_OPT_PERSIST)) {
1094                 return (IPADM_NOTFOUND);
1095         }
1096 
1097         status = ipadm_set_reqhost(ipaddr, pval);
1098         if (status != IPADM_SUCCESS)
1099                 return (status);
1100 
1101         if (ipaddr->ipadm_flags & IPMGMT_ACTIVE) {
1102                 status = i_ipadm_refresh_dhcp(ipaddr);
1103 
1104                 /*
1105                  * We do not report a problem for IPADM_DHCP_IPC_TIMEOUT since it is
1106                  * only a soft error to indicate the caller that the lease might be
1107                  * renewed after the function returns.
1108                  */
1109                 if (status != IPADM_SUCCESS && status != IPADM_DHCP_IPC_TIMEOUT)
1110                         return (status);
1111         }
1112 
1113         status = i_ipadm_set_aobj_addrprop(iph, ipaddr, flags,
1114             IPADM_NVP_REQHOST);
1115         return (status);
1116 }
1117 
1118 /*
1119  * Used by address object property callback functions that need to do a
1120  * two-stage update because the addrprop is cached on the address object.
1121  */
1122 static ipadm_status_t
1123 i_ipadm_set_aobj_addrprop(ipadm_handle_t iph, ipadm_addrobj_t ipaddr,
1124                         uint_t flags, const char *propname)
1125 {
1126         ipadm_status_t  status;
1127         uint32_t                two_stage_flags;
1128 
1129         /*
1130          * Send the updated address object information to ipmgmtd, since the
1131          * cached version of an addrprop resides on an aobjmap, but do
1132          * not change the ACTIVE/PERSIST state of the aobjmap. Instead, request
1133          * a two-stage, SET_PROPS update with ACTIVE/PERSIST as the first stage
1134          * per the existing aobjmap flags and a second stage encoded in
1135          * IPADM_OPT_PERSIST_PROPS.
1136          */
1137         two_stage_flags = (flags | IPADM_OPT_SET_PROPS)
1138             & ~(IPADM_OPT_ACTIVE | IPADM_OPT_PERSIST);
1139         if (ipaddr->ipadm_flags & IPMGMT_ACTIVE)
1140                 two_stage_flags |= IPADM_OPT_ACTIVE;
1141         if (ipaddr->ipadm_flags & IPMGMT_PERSIST)
1142                 two_stage_flags |= IPADM_OPT_PERSIST;
1143         if (flags & IPADM_OPT_PERSIST)
1144                 two_stage_flags |= IPADM_OPT_PERSIST_PROPS;
1145 
1146         status = i_ipadm_addr_persist(iph, ipaddr, B_FALSE, two_stage_flags,
1147             propname);
1148         return (status);
1149 }
1150 
1151 /*
1152  * Callback function that gets the property `broadcast' for the address
1153  * object in `arg'.
1154  */
1155 /* ARGSUSED */
1156 static ipadm_status_t
1157 i_ipadm_get_broadcast(ipadm_handle_t iph, const void *arg,
1158     ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t af,
1159     uint_t valtype)
1160 {
1161         struct sockaddr_in      *sin;
1162         struct lifreq           lifr;
1163         char                    lifname[LIFNAMSIZ];
1164         ipadm_addrobj_t         ipaddr = (ipadm_addrobj_t)arg;
1165         ipadm_status_t          status;
1166         size_t                  nbytes = 0;
1167         uint64_t                ifflags = 0;
1168 
1169         i_ipadm_addrobj2lifname(ipaddr, lifname, sizeof (lifname));
1170         if (ipaddr->ipadm_flags & IPMGMT_ACTIVE) {
1171                 status = i_ipadm_get_flags(iph, lifname, af, &ifflags);
1172                 if (status != IPADM_SUCCESS)
1173                         return (status);
1174                 if (!(ifflags & IFF_BROADCAST)) {
1175                         buf[0] = '\0';
1176                         return (IPADM_SUCCESS);
1177                 }
1178         }
1179 
1180         switch (valtype) {
1181         case MOD_PROP_DEFAULT: {
1182                 struct sockaddr_storage mask;
1183                 struct in_addr          broadaddr;
1184                 uint_t                  plen;
1185                 in_addr_t               addr, maddr;
1186                 char                    val[MAXPROPVALLEN];
1187                 uint_t                  valsz = MAXPROPVALLEN;
1188                 ipadm_status_t          status;
1189                 int                     err;
1190                 struct sockaddr_in      *sin;
1191 
1192                 if (!(ipaddr->ipadm_flags & IPMGMT_ACTIVE)) {
1193                         /*
1194                          * Since the address is unknown we cannot
1195                          * obtain default prefixlen
1196                          */
1197                         if (ipaddr->ipadm_atype == IPADM_ADDR_DHCP ||
1198                             ipaddr->ipadm_af == AF_INET6) {
1199                                 buf[0] = '\0';
1200                                 return (IPADM_SUCCESS);
1201                         }
1202                         /*
1203                          * For the static address, we get the address from the
1204                          * persistent db.
1205                          */
1206                         status = i_ipadm_get_static_addr_db(iph, ipaddr);
1207                         if (status != IPADM_SUCCESS)
1208                                 return (status);
1209                         sin = SIN(&ipaddr->ipadm_static_addr);
1210                         addr = sin->sin_addr.s_addr;
1211                 } else {
1212                         /*
1213                          * If the address object is active, we retrieve the
1214                          * address from kernel.
1215                          */
1216                         bzero(&lifr, sizeof (lifr));
1217                         (void) strlcpy(lifr.lifr_name, lifname,
1218                             sizeof (lifr.lifr_name));
1219                         if (ioctl(iph->iph_sock, SIOCGLIFADDR,
1220                             (caddr_t)&lifr) < 0)
1221                                 return (ipadm_errno2status(errno));
1222 
1223                         addr = (SIN(&lifr.lifr_addr))->sin_addr.s_addr;
1224                 }
1225                 /*
1226                  * For default broadcast address, get the address and the
1227                  * default prefixlen for that address and then compute the
1228                  * broadcast address.
1229                  */
1230                 status = i_ipadm_get_prefixlen(iph, arg, NULL, val, &valsz, af,
1231                     MOD_PROP_DEFAULT);
1232                 if (status != IPADM_SUCCESS)
1233                         return (status);
1234 
1235                 plen = atoi(val);
1236                 if ((err = plen2mask(plen, AF_INET,
1237                     (struct sockaddr *)&mask)) != 0)
1238                         return (ipadm_errno2status(err));
1239                 maddr = (SIN(&mask))->sin_addr.s_addr;
1240                 broadaddr.s_addr = (addr & maddr) | ~maddr;
1241                 nbytes = snprintf(buf, *bufsize, "%s", inet_ntoa(broadaddr));
1242                 break;
1243         }
1244         case MOD_PROP_ACTIVE:
1245                 bzero(&lifr, sizeof (lifr));
1246                 (void) strlcpy(lifr.lifr_name, lifname,
1247                     sizeof (lifr.lifr_name));
1248                 if (ioctl(iph->iph_sock, SIOCGLIFBRDADDR,
1249                     (caddr_t)&lifr) < 0) {
1250                         return (ipadm_errno2status(errno));
1251                 } else {
1252                         sin = SIN(&lifr.lifr_addr);
1253                         nbytes = snprintf(buf, *bufsize, "%s",
1254                             inet_ntoa(sin->sin_addr));
1255                 }
1256                 break;
1257         default:
1258                 return (IPADM_INVALID_ARG);
1259         }
1260         if (nbytes >= *bufsize) {
1261                 /* insufficient buffer space */
1262                 *bufsize = nbytes + 1;
1263                 return (IPADM_NO_BUFS);
1264         }
1265         return (IPADM_SUCCESS);
1266 }
1267 
1268 /*
1269  * Callback function that retrieves the value of the property `prefixlen'
1270  * for the address object in `arg'.
1271  */
1272 /* ARGSUSED */
1273 static ipadm_status_t
1274 i_ipadm_get_prefixlen(ipadm_handle_t iph, const void *arg,
1275     ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t af,
1276     uint_t valtype)
1277 {
1278         struct lifreq   lifr;
1279         ipadm_addrobj_t ipaddr = (ipadm_addrobj_t)arg;
1280         char            lifname[LIFNAMSIZ];
1281         int             s;
1282         uint32_t        prefixlen;
1283         size_t          nbytes;
1284         ipadm_status_t  status;
1285         uint64_t        lifflags;
1286 
1287         i_ipadm_addrobj2lifname(ipaddr, lifname, sizeof (lifname));
1288         if (ipaddr->ipadm_flags & IPMGMT_ACTIVE) {
1289                 status = i_ipadm_get_flags(iph, lifname, af, &lifflags);
1290                 if (status != IPADM_SUCCESS) {
1291                         return (status);
1292                 } else if (lifflags & IFF_POINTOPOINT) {
1293                         buf[0] = '\0';
1294                         return (status);
1295                 }
1296         }
1297 
1298         s = (af == AF_INET ? iph->iph_sock : iph->iph_sock6);
1299         bzero(&lifr, sizeof (lifr));
1300         (void) strlcpy(lifr.lifr_name, lifname, sizeof (lifr.lifr_name));
1301         switch (valtype) {
1302         case MOD_PROP_POSSIBLE:
1303                 if (af == AF_INET)
1304                         nbytes = snprintf(buf, *bufsize, "1-30,32");
1305                 else
1306                         nbytes = snprintf(buf, *bufsize, "1-126,128");
1307                 break;
1308         case MOD_PROP_DEFAULT:
1309                 if (ipaddr->ipadm_flags & IPMGMT_ACTIVE) {
1310                         /*
1311                          * For static addresses, we retrieve the address
1312                          * from kernel if it is active.
1313                          */
1314                         if (ioctl(s, SIOCGLIFADDR, (caddr_t)&lifr) < 0)
1315                                 return (ipadm_errno2status(errno));
1316                         status = i_ipadm_get_default_prefixlen(
1317                             &lifr.lifr_addr, &prefixlen);
1318                         if (status != IPADM_SUCCESS)
1319                                 return (status);
1320                 } else if ((ipaddr->ipadm_flags & IPMGMT_PERSIST) &&
1321                     ipaddr->ipadm_atype == IPADM_ADDR_DHCP) {
1322                         /*
1323                          * Since the address is unknown we cannot
1324                          * obtain default prefixlen
1325                          */
1326                         buf[0] = '\0';
1327                         return (IPADM_SUCCESS);
1328                 } else {
1329                         /*
1330                          * If not in active config, we use the address
1331                          * from persistent store.
1332                          */
1333                         status = i_ipadm_get_static_addr_db(iph, ipaddr);
1334                         if (status != IPADM_SUCCESS)
1335                                 return (status);
1336                         status = i_ipadm_get_default_prefixlen(
1337                             &ipaddr->ipadm_static_addr, &prefixlen);
1338                         if (status != IPADM_SUCCESS)
1339                                 return (status);
1340                 }
1341                 nbytes = snprintf(buf, *bufsize, "%u", prefixlen);
1342                 break;
1343         case MOD_PROP_ACTIVE:
1344                 if (ioctl(s, SIOCGLIFNETMASK, (caddr_t)&lifr) < 0)
1345                         return (ipadm_errno2status(errno));
1346                 prefixlen = lifr.lifr_addrlen;
1347                 nbytes = snprintf(buf, *bufsize, "%u", prefixlen);
1348                 break;
1349         default:
1350                 return (IPADM_INVALID_ARG);
1351         }
1352         if (nbytes >= *bufsize) {
1353                 /* insufficient buffer space */
1354                 *bufsize = nbytes + 1;
1355                 return (IPADM_NO_BUFS);
1356         }
1357         return (IPADM_SUCCESS);
1358 }
1359 
1360 /*
1361  * Callback function that retrieves the value of one of the properties
1362  * among `deprecated', `private', and `transmit' for the address object
1363  * in `arg'.
1364  */
1365 /* ARGSUSED */
1366 static ipadm_status_t
1367 i_ipadm_get_addr_flag(ipadm_handle_t iph, const void *arg,
1368     ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t af,
1369     uint_t valtype)
1370 {
1371         boolean_t       on = B_FALSE;
1372         char            lifname[LIFNAMSIZ];
1373         ipadm_status_t  status = IPADM_SUCCESS;
1374         uint64_t        ifflags;
1375         size_t          nbytes;
1376         ipadm_addrobj_t ipaddr = (ipadm_addrobj_t)arg;
1377 
1378         switch (valtype) {
1379         case MOD_PROP_DEFAULT:
1380                 if (strcmp(pdp->ipd_name, "private") == 0 ||
1381                     strcmp(pdp->ipd_name, "deprecated") == 0) {
1382                         on = B_FALSE;
1383                 } else if (strcmp(pdp->ipd_name, "transmit") == 0) {
1384                         on = B_TRUE;
1385                 } else {
1386                         return (IPADM_PROP_UNKNOWN);
1387                 }
1388                 break;
1389         case MOD_PROP_ACTIVE:
1390                 /*
1391                  * If the address is present in active configuration, we
1392                  * retrieve it from kernel to get the property value.
1393                  * Else, there is no value to return.
1394                  */
1395                 i_ipadm_addrobj2lifname(ipaddr, lifname, sizeof (lifname));
1396                 status = i_ipadm_get_flags(iph, lifname, af, &ifflags);
1397                 if (status != IPADM_SUCCESS)
1398                         return (status);
1399                 if (strcmp(pdp->ipd_name, "private") == 0)
1400                         on = (ifflags & IFF_PRIVATE);
1401                 else if (strcmp(pdp->ipd_name, "transmit") == 0)
1402                         on = !(ifflags & IFF_NOXMIT);
1403                 else if (strcmp(pdp->ipd_name, "deprecated") == 0)
1404                         on = (ifflags & IFF_DEPRECATED);
1405                 break;
1406         default:
1407                 return (IPADM_INVALID_ARG);
1408         }
1409         nbytes = snprintf(buf, *bufsize, "%s",
1410             (on ? IPADM_ONSTR : IPADM_OFFSTR));
1411         if (nbytes >= *bufsize) {
1412                 /* insufficient buffer space */
1413                 *bufsize = nbytes + 1;
1414                 status = IPADM_NO_BUFS;
1415         }
1416 
1417         return (status);
1418 }
1419 
1420 /*
1421  * Callback function that retrieves the value of the property `zone'
1422  * for the address object in `arg'.
1423  */
1424 /* ARGSUSED */
1425 static ipadm_status_t
1426 i_ipadm_get_zone(ipadm_handle_t iph, const void *arg,
1427     ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t af,
1428     uint_t valtype)
1429 {
1430         struct lifreq   lifr;
1431         char            zone_name[ZONENAME_MAX];
1432         int             s;
1433         size_t          nbytes = 0;
1434 
1435         if (iph->iph_zoneid != GLOBAL_ZONEID) {
1436                 buf[0] = '\0';
1437                 return (IPADM_SUCCESS);
1438         }
1439 
1440         /*
1441          * we are in global zone. See if the lifname is assigned to shared-ip
1442          * zone or global zone.
1443          */
1444         switch (valtype) {
1445         case MOD_PROP_DEFAULT:
1446                 if (getzonenamebyid(GLOBAL_ZONEID, zone_name,
1447                     sizeof (zone_name)) > 0)
1448                         nbytes = snprintf(buf, *bufsize, "%s", zone_name);
1449                 else
1450                         return (ipadm_errno2status(errno));
1451                 break;
1452         case MOD_PROP_ACTIVE:
1453                 bzero(&lifr, sizeof (lifr));
1454                 i_ipadm_addrobj2lifname((ipadm_addrobj_t)arg, lifr.lifr_name,
1455                     sizeof (lifr.lifr_name));
1456                 s = (af == AF_INET ? iph->iph_sock : iph->iph_sock6);
1457 
1458                 if (ioctl(s, SIOCGLIFZONE, (caddr_t)&lifr) == -1)
1459                         return (ipadm_errno2status(errno));
1460 
1461                 if (lifr.lifr_zoneid == ALL_ZONES) {
1462                         nbytes = snprintf(buf, *bufsize, "%s", "all-zones");
1463                 } else if (getzonenamebyid(lifr.lifr_zoneid, zone_name,
1464                     sizeof (zone_name)) < 0) {
1465                         return (ipadm_errno2status(errno));
1466                 } else {
1467                         nbytes = snprintf(buf, *bufsize, "%s", zone_name);
1468                 }
1469                 break;
1470         default:
1471                 return (IPADM_INVALID_ARG);
1472         }
1473         if (nbytes >= *bufsize) {
1474                 /* insufficient buffer space */
1475                 *bufsize = nbytes + 1;
1476                 return (IPADM_NO_BUFS);
1477         }
1478 
1479         return (IPADM_SUCCESS);
1480 }
1481 
1482 /*
1483  * Callback function that retrieves the value of the property `primary'
1484  * for the address object in `arg'.
1485  */
1486 /* ARGSUSED */
1487 static ipadm_status_t
1488 i_ipadm_get_primary(ipadm_handle_t iph, const void *arg,
1489     ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t af,
1490     uint_t valtype)
1491 {
1492         ipadm_addrobj_t ipaddr = (ipadm_addrobj_t)arg;
1493         const char *    onoff = "";
1494         size_t          nbytes;
1495 
1496         switch (valtype) {
1497         case MOD_PROP_DEFAULT:
1498                 if (ipaddr->ipadm_atype == IPADM_ADDR_DHCP)
1499                         onoff = IPADM_OFFSTR;
1500                 break;
1501         case MOD_PROP_ACTIVE:
1502                 if (ipaddr->ipadm_atype == IPADM_ADDR_DHCP)
1503                         onoff = ipaddr->ipadm_primary ? IPADM_ONSTR : IPADM_OFFSTR;
1504                 break;
1505         default:
1506                 return (IPADM_INVALID_ARG);
1507         }
1508 
1509         nbytes = strlcpy(buf, onoff, *bufsize);
1510         if (nbytes >= *bufsize) {
1511                 /* insufficient buffer space */
1512                 *bufsize = nbytes + 1;
1513                 return (IPADM_NO_BUFS);
1514         }
1515 
1516         return (IPADM_SUCCESS);
1517 }
1518 
1519 /*
1520  * Callback function that retrieves the value of the property `reqhost'
1521  * for the address object in `arg'.
1522  */
1523 /* ARGSUSED */
1524 static ipadm_status_t
1525 i_ipadm_get_reqhost(ipadm_handle_t iph, const void *arg,
1526     ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t af,
1527     uint_t valtype)
1528 {
1529         ipadm_addrobj_t ipaddr = (ipadm_addrobj_t)arg;
1530         const char *    reqhost = "";
1531         size_t          nbytes;
1532 
1533         switch (valtype) {
1534         case MOD_PROP_DEFAULT:
1535                 break;
1536         case MOD_PROP_ACTIVE:
1537                 if (ipaddr->ipadm_atype == IPADM_ADDR_DHCP)
1538                         reqhost = ipaddr->ipadm_reqhost;
1539                 break;
1540         default:
1541                 return (IPADM_INVALID_ARG);
1542         }
1543 
1544         nbytes = strlcpy(buf, reqhost, *bufsize);
1545         if (nbytes >= *bufsize) {
1546                 /* insufficient buffer space */
1547                 *bufsize = nbytes + 1;
1548                 return (IPADM_NO_BUFS);
1549         }
1550 
1551         return (IPADM_SUCCESS);
1552 }
1553 
1554 static ipadm_prop_desc_t *
1555 i_ipadm_get_addrprop_desc(const char *pname)
1556 {
1557         int i;
1558 
1559         for (i = 0; ipadm_addrprop_table[i].ipd_name != NULL; i++) {
1560                 if (strcmp(pname, ipadm_addrprop_table[i].ipd_name) == 0 ||
1561                     (ipadm_addrprop_table[i].ipd_old_name != NULL &&
1562                     strcmp(pname, ipadm_addrprop_table[i].ipd_old_name) == 0))
1563                         return (&ipadm_addrprop_table[i]);
1564         }
1565         return (NULL);
1566 }
1567 
1568 /*
1569  * Gets the value of the given address property `pname' for the address
1570  * object with name `aobjname'.
1571  */
1572 ipadm_status_t
1573 ipadm_get_addrprop(ipadm_handle_t iph, const char *pname, char *buf,
1574     uint_t *bufsize, const char *aobjname, uint_t valtype)
1575 {
1576         struct ipadm_addrobj_s  ipaddr;
1577         ipadm_status_t          status = IPADM_SUCCESS;
1578         sa_family_t             af;
1579         ipadm_prop_desc_t       *pdp = NULL;
1580 
1581         if (iph == NULL || pname == NULL || buf == NULL ||
1582             bufsize == NULL || *bufsize == 0 || aobjname == NULL) {
1583                 return (IPADM_INVALID_ARG);
1584         }
1585 
1586         /* find the property in the property description table */
1587         if ((pdp = i_ipadm_get_addrprop_desc(pname)) == NULL)
1588                 return (IPADM_PROP_UNKNOWN);
1589 
1590         /*
1591          * For the given aobjname, get the addrobj it represents and
1592          * retrieve the property value for that object.
1593          */
1594         i_ipadm_init_addr(&ipaddr, "", aobjname, IPADM_ADDR_NONE);
1595         if ((status = i_ipadm_get_addrobj(iph, &ipaddr)) != IPADM_SUCCESS)
1596                 return (status);
1597 
1598         if (ipaddr.ipadm_atype == IPADM_ADDR_IPV6_ADDRCONF)
1599                 return (IPADM_NOTSUP);
1600         af = ipaddr.ipadm_af;
1601 
1602         /*
1603          * Call the appropriate callback function to based on the field
1604          * that was asked for.
1605          */
1606         switch (valtype) {
1607         case IPADM_OPT_PERM:
1608                 status = i_ipadm_pd2permstr(pdp, buf, bufsize);
1609                 break;
1610         case IPADM_OPT_ACTIVE:
1611                 if (!(ipaddr.ipadm_flags & IPMGMT_ACTIVE)) {
1612                         buf[0] = '\0';
1613                 } else {
1614                         status = pdp->ipd_get(iph, &ipaddr, pdp, buf, bufsize,
1615                             af, MOD_PROP_ACTIVE);
1616                 }
1617                 break;
1618         case IPADM_OPT_DEFAULT:
1619                 status = pdp->ipd_get(iph, &ipaddr, pdp, buf, bufsize,
1620                     af, MOD_PROP_DEFAULT);
1621                 break;
1622         case IPADM_OPT_POSSIBLE:
1623                 if (pdp->ipd_get_range != NULL) {
1624                         status = pdp->ipd_get_range(iph, &ipaddr, pdp, buf,
1625                             bufsize, af, MOD_PROP_POSSIBLE);
1626                         break;
1627                 }
1628                 buf[0] = '\0';
1629                 break;
1630         case IPADM_OPT_PERSIST:
1631                 status = i_ipadm_get_persist_propval(iph, pdp, buf, bufsize,
1632                     &ipaddr);
1633                 break;
1634         default:
1635                 status = IPADM_INVALID_ARG;
1636                 break;
1637         }
1638 
1639         return (status);
1640 }
1641 
1642 /*
1643  * Sets the value of the given address property `pname' to `pval' for the
1644  * address object with name `aobjname'.
1645  */
1646 ipadm_status_t
1647 ipadm_set_addrprop(ipadm_handle_t iph, const char *pname,
1648     const char *pval, const char *aobjname, uint_t pflags)
1649 {
1650         struct ipadm_addrobj_s  ipaddr;
1651         sa_family_t             af;
1652         ipadm_prop_desc_t       *pdp = NULL;
1653         char                    defbuf[MAXPROPVALLEN];
1654         uint_t                  defbufsize = MAXPROPVALLEN;
1655         boolean_t               reset = (pflags & IPADM_OPT_DEFAULT);
1656         ipadm_status_t          status = IPADM_SUCCESS;
1657 
1658         /* Check for solaris.network.interface.config authorization */
1659         if (!ipadm_check_auth())
1660                 return (IPADM_EAUTH);
1661 
1662         if (iph == NULL || pname == NULL || aobjname == NULL || pflags == 0 ||
1663             pflags == IPADM_OPT_PERSIST ||
1664             (pflags & ~(IPADM_COMMON_OPT_MASK|IPADM_OPT_DEFAULT)) ||
1665             (!reset && pval == NULL)) {
1666                 return (IPADM_INVALID_ARG);
1667         }
1668 
1669         /* find the property in the property description table */
1670         if ((pdp = i_ipadm_get_addrprop_desc(pname)) == NULL)
1671                 return (IPADM_PROP_UNKNOWN);
1672 
1673         if (pdp->ipd_set == NULL || (reset && pdp->ipd_get == NULL))
1674                 return (IPADM_NOTSUP);
1675 
1676         if (!(pdp->ipd_flags & IPADMPROP_MULVAL) &&
1677             (pflags & (IPADM_OPT_APPEND|IPADM_OPT_REMOVE))) {
1678                 return (IPADM_INVALID_ARG);
1679         }
1680 
1681         /*
1682          * For the given aobjname, get the addrobj it represents and
1683          * set the property value for that object.
1684          */
1685         i_ipadm_init_addr(&ipaddr, "", aobjname, IPADM_ADDR_NONE);
1686         if ((status = i_ipadm_get_addrobj(iph, &ipaddr)) != IPADM_SUCCESS)
1687                 return (status);
1688 
1689         if (!(ipaddr.ipadm_flags & IPMGMT_ACTIVE))
1690                 return (IPADM_OP_DISABLE_OBJ);
1691 
1692         /* Persistent operation not allowed on a temporary object. */
1693         if ((pflags & IPADM_OPT_PERSIST) &&
1694             !(ipaddr.ipadm_flags & IPMGMT_PERSIST))
1695                 return (IPADM_TEMPORARY_OBJ);
1696 
1697         /*
1698          * Currently, setting an address property on an address object of type
1699          * IPADM_ADDR_IPV6_ADDRCONF is not supported. Supporting it involves
1700          * in.ndpd retrieving the address properties from ipmgmtd for given
1701          * address object and then setting them on auto-configured addresses,
1702          * whenever in.ndpd gets a new prefix. This will be supported in
1703          * future releases.
1704          */
1705         if (ipaddr.ipadm_atype == IPADM_ADDR_IPV6_ADDRCONF)
1706                 return (IPADM_NOTSUP);
1707 
1708         /*
1709          * Setting an address property on an address object that is
1710          * not present in active configuration is not supported.
1711          */
1712         if (!(ipaddr.ipadm_flags & IPMGMT_ACTIVE))
1713                 return (IPADM_NOTSUP);
1714 
1715         af = ipaddr.ipadm_af;
1716         if (reset) {
1717                 /*
1718                  * If we were asked to reset the value, we need to fetch
1719                  * the default value and set the default value.
1720                  */
1721                 status = pdp->ipd_get(iph, &ipaddr, pdp, defbuf, &defbufsize,
1722                     af, MOD_PROP_DEFAULT);
1723                 if (status != IPADM_SUCCESS)
1724                         return (status);
1725                 pval = defbuf;
1726         }
1727         /* set the user provided or default property value */
1728         status = pdp->ipd_set(iph, &ipaddr, pdp, pval, af, pflags);
1729         if (status != IPADM_SUCCESS)
1730                 return (status);
1731 
1732         /*
1733          * If IPADM_OPT_PERSIST was set in `flags', we need to store
1734          * property and its value in persistent DB.
1735          */
1736         if (pflags & IPADM_OPT_PERSIST) {
1737                 status = i_ipadm_persist_propval(iph, pdp, pval, &ipaddr,
1738                     pflags);
1739         }
1740 
1741         return (status);
1742 }
1743 
1744 /*
1745  * Remove the address specified by the address object in `addr'
1746  * from kernel. If the address is on a non-zero logical interface, we do a
1747  * SIOCLIFREMOVEIF, otherwise we set the address to INADDR_ANY for IPv4 or
1748  * :: for IPv6.
1749  */
1750 ipadm_status_t
1751 i_ipadm_delete_addr(ipadm_handle_t iph, ipadm_addrobj_t addr)
1752 {
1753         struct lifreq   lifr;
1754         int             sock;
1755         ipadm_status_t  status;
1756 
1757         bzero(&lifr, sizeof (lifr));
1758         i_ipadm_addrobj2lifname(addr, lifr.lifr_name, sizeof (lifr.lifr_name));
1759         sock = (addr->ipadm_af == AF_INET ? iph->iph_sock : iph->iph_sock6);
1760         if (addr->ipadm_lifnum == 0) {
1761                 /*
1762                  * Fake the deletion of the 0'th address by
1763                  * clearing IFF_UP and setting it to as 0.0.0.0 or ::.
1764                  */
1765                 status = i_ipadm_set_flags(iph, addr->ipadm_ifname,
1766                     addr->ipadm_af, 0, IFF_UP);
1767                 if (status != IPADM_SUCCESS)
1768                         return (status);
1769                 bzero(&lifr.lifr_addr, sizeof (lifr.lifr_addr));
1770                 lifr.lifr_addr.ss_family = addr->ipadm_af;
1771                 if (ioctl(sock, SIOCSLIFADDR, (caddr_t)&lifr) < 0)
1772                         return (ipadm_errno2status(errno));
1773                 if (ioctl(sock, SIOCSLIFDSTADDR, (caddr_t)&lifr) < 0)
1774                         return (ipadm_errno2status(errno));
1775         } else if (ioctl(sock, SIOCLIFREMOVEIF, (caddr_t)&lifr) < 0) {
1776                 return (ipadm_errno2status(errno));
1777         }
1778 
1779         return (IPADM_SUCCESS);
1780 }
1781 
1782 /*
1783  * Extracts the IPv6 address from the nvlist in `nvl'.
1784  */
1785 ipadm_status_t
1786 i_ipadm_nvl2in6_addr(nvlist_t *nvl, char *addr_type, in6_addr_t *in6_addr)
1787 {
1788         uint8_t *addr6;
1789         uint_t  n;
1790 
1791         if (nvlist_lookup_uint8_array(nvl, addr_type, &addr6, &n) != 0)
1792                 return (IPADM_NOTFOUND);
1793         assert(n == 16);
1794         bcopy(addr6, in6_addr->s6_addr, n);
1795         return (IPADM_SUCCESS);
1796 }
1797 
1798 /*
1799  * Used to validate the given addrobj name string. Length of `aobjname'
1800  * cannot exceed IPADM_AOBJ_USTRSIZ. `aobjname' should start with an
1801  * alphabetic character and it can only contain alphanumeric characters.
1802  */
1803 static boolean_t
1804 i_ipadm_is_user_aobjname_valid(const char *aobjname)
1805 {
1806         const char      *cp;
1807 
1808         if (aobjname == NULL || strlen(aobjname) >= IPADM_AOBJ_USTRSIZ ||
1809             !isalpha(*aobjname)) {
1810                 return (B_FALSE);
1811         }
1812         for (cp = aobjname + 1; *cp && isalnum(*cp); cp++)
1813                 ;
1814         return (*cp == '\0');
1815 }
1816 
1817 /*
1818  * Computes the prefixlen for the given `addr' based on the netmask found using
1819  * the order specified in /etc/nsswitch.conf. If not found, then the
1820  * prefixlen is computed using the Classful subnetting semantics defined
1821  * in RFC 791 for IPv4 and RFC 4291 for IPv6.
1822  */
1823 static ipadm_status_t
1824 i_ipadm_get_default_prefixlen(struct sockaddr_storage *addr, uint32_t *plen)
1825 {
1826         sa_family_t af = addr->ss_family;
1827         struct sockaddr_storage mask;
1828         struct sockaddr_in *m = (struct sockaddr_in *)&mask;
1829         struct sockaddr_in6 *sin6;
1830         struct sockaddr_in *sin;
1831         struct in_addr ia;
1832         uint32_t prefixlen = 0;
1833 
1834         switch (af) {
1835         case AF_INET:
1836                 sin = SIN(addr);
1837                 ia.s_addr = ntohl(sin->sin_addr.s_addr);
1838                 get_netmask4(&ia, &m->sin_addr);
1839                 m->sin_addr.s_addr = htonl(m->sin_addr.s_addr);
1840                 m->sin_family = AF_INET;
1841                 prefixlen = mask2plen((struct sockaddr *)&mask);
1842                 break;
1843         case AF_INET6:
1844                 sin6 = SIN6(addr);
1845                 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
1846                         prefixlen = 10;
1847                 else
1848                         prefixlen = 64;
1849                 break;
1850         default:
1851                 return (IPADM_INVALID_ARG);
1852         }
1853         *plen = prefixlen;
1854         return (IPADM_SUCCESS);
1855 }
1856 
1857 ipadm_status_t
1858 i_ipadm_resolve_addr(const char *name, sa_family_t af,
1859     struct sockaddr_storage *ss)
1860 {
1861         struct addrinfo hints, *ai;
1862         int rc;
1863         struct sockaddr_in6 *sin6;
1864         struct sockaddr_in *sin;
1865         boolean_t is_mapped;
1866 
1867         (void) memset(&hints, 0, sizeof (hints));
1868         hints.ai_family = af;
1869         hints.ai_flags = (AI_ALL | AI_V4MAPPED);
1870         rc = getaddrinfo(name, NULL, &hints, &ai);
1871         if (rc != 0) {
1872                 if (rc == EAI_NONAME)
1873                         return (IPADM_BAD_ADDR);
1874                 else
1875                         return (IPADM_FAILURE);
1876         }
1877         if (ai->ai_next != NULL) {
1878                 /* maps to more than one hostname */
1879                 freeaddrinfo(ai);
1880                 return (IPADM_BAD_HOSTNAME);
1881         }
1882         /* LINTED E_BAD_PTR_CAST_ALIGN */
1883         is_mapped = IN6_IS_ADDR_V4MAPPED(&(SIN6(ai->ai_addr))->sin6_addr);
1884         if (is_mapped) {
1885                 sin = SIN(ss);
1886                 sin->sin_family = AF_INET;
1887                 /* LINTED E_BAD_PTR_CAST_ALIGN */
1888                 IN6_V4MAPPED_TO_INADDR(&(SIN6(ai->ai_addr))->sin6_addr,
1889                     &sin->sin_addr);
1890         } else {
1891                 sin6 = SIN6(ss);
1892                 sin6->sin6_family = AF_INET6;
1893                 bcopy(ai->ai_addr, sin6, sizeof (*sin6));
1894         }
1895         freeaddrinfo(ai);
1896         return (IPADM_SUCCESS);
1897 }
1898 
1899 /*
1900  * This takes a static address string <addr>[/<mask>] or a hostname
1901  * and maps it to a single numeric IP address, consulting DNS if
1902  * hostname was provided. If a specific address family was requested,
1903  * an error is returned if the given hostname does not map to an address
1904  * of the given family. Note that this function returns failure
1905  * if the name maps to more than one IP address.
1906  */
1907 ipadm_status_t
1908 ipadm_set_addr(ipadm_addrobj_t ipaddr, const char *astr, sa_family_t af)
1909 {
1910         char            *prefixlenstr;
1911         uint32_t        prefixlen = 0;
1912         char            *endp;
1913         /*
1914          * We use (NI_MAXHOST + 5) because the longest possible
1915          * astr will have (NI_MAXHOST + '/' + {a maximum of 32 for IPv4
1916          * or a maximum of 128 for IPv6 + '\0') chars
1917          */
1918         char            addrstr[NI_MAXHOST + 5];
1919         ipadm_status_t  status;
1920 
1921         (void) snprintf(addrstr, sizeof (addrstr), "%s", astr);
1922         if ((prefixlenstr = strchr(addrstr, '/')) != NULL) {
1923                 *prefixlenstr++ = '\0';
1924                 errno = 0;
1925                 prefixlen = strtoul(prefixlenstr, &endp, 10);
1926                 if (errno != 0 || *endp != '\0')
1927                         return (IPADM_INVALID_ARG);
1928                 if ((af == AF_INET && prefixlen > IP_ABITS) ||
1929                     (af == AF_INET6 && prefixlen > IPV6_ABITS))
1930                         return (IPADM_INVALID_ARG);
1931         }
1932 
1933         status = i_ipadm_resolve_addr(addrstr, af, &ipaddr->ipadm_static_addr);
1934         if (status == IPADM_SUCCESS) {
1935                 (void) strlcpy(ipaddr->ipadm_static_aname, addrstr,
1936                     sizeof (ipaddr->ipadm_static_aname));
1937                 ipaddr->ipadm_af = ipaddr->ipadm_static_addr.ss_family;
1938                 ipaddr->ipadm_static_prefixlen = prefixlen;
1939         }
1940         return (status);
1941 }
1942 
1943 /*
1944  * Gets the static source address from the address object in `ipaddr'.
1945  * Memory for `addr' should be already allocated by the caller.
1946  */
1947 ipadm_status_t
1948 ipadm_get_addr(const ipadm_addrobj_t ipaddr, struct sockaddr_storage *addr)
1949 {
1950         if (ipaddr == NULL || ipaddr->ipadm_atype != IPADM_ADDR_STATIC ||
1951             addr == NULL) {
1952                 return (IPADM_INVALID_ARG);
1953         }
1954         *addr = ipaddr->ipadm_static_addr;
1955 
1956         return (IPADM_SUCCESS);
1957 }
1958 
1959 /*
1960  * Set up tunnel destination address in ipaddr by contacting DNS.
1961  * The function works similar to ipadm_set_addr().
1962  * The dst_addr must resolve to exactly one address. IPADM_BAD_ADDR is returned
1963  * if dst_addr resolves to more than one address. The caller has to verify
1964  * that ipadm_static_addr and ipadm_static_dst_addr have the same ss_family
1965  */
1966 ipadm_status_t
1967 ipadm_set_dst_addr(ipadm_addrobj_t ipaddr, const char *daddrstr, sa_family_t af)
1968 {
1969         ipadm_status_t  status;
1970 
1971         /* mask lengths are not meaningful for point-to-point interfaces. */
1972         if (strchr(daddrstr, '/') != NULL)
1973                 return (IPADM_BAD_ADDR);
1974 
1975         status = i_ipadm_resolve_addr(daddrstr, af,
1976             &ipaddr->ipadm_static_dst_addr);
1977         if (status == IPADM_SUCCESS) {
1978                 (void) strlcpy(ipaddr->ipadm_static_dname, daddrstr,
1979                     sizeof (ipaddr->ipadm_static_dname));
1980         }
1981         return (status);
1982 }
1983 
1984 /*
1985  * Sets the interface ID in the address object `ipaddr' with the address
1986  * in the string `interface_id'. This interface ID will be used when
1987  * ipadm_create_addr() is called with `ipaddr' with address type
1988  * set to IPADM_ADDR_IPV6_ADDRCONF.
1989  */
1990 ipadm_status_t
1991 ipadm_set_interface_id(ipadm_addrobj_t ipaddr, const char *interface_id)
1992 {
1993         struct sockaddr_in6     *sin6;
1994         char                    *end;
1995         char                    *cp;
1996         uint32_t                prefixlen;
1997         char                    addrstr[INET6_ADDRSTRLEN + 1];
1998 
1999         if (ipaddr == NULL || interface_id == NULL ||
2000             ipaddr->ipadm_atype != IPADM_ADDR_IPV6_ADDRCONF)
2001                 return (IPADM_INVALID_ARG);
2002 
2003         (void) strlcpy(addrstr, interface_id, sizeof (addrstr));
2004         if ((cp = strchr(addrstr, '/')) == NULL)
2005                 return (IPADM_INVALID_ARG);
2006         *cp++ = '\0';
2007         sin6 = &ipaddr->ipadm_intfid;
2008         if (inet_pton(AF_INET6, addrstr, &sin6->sin6_addr) == 1) {
2009                 errno = 0;
2010                 prefixlen = strtoul(cp, &end, 10);
2011                 if (errno != 0 || *end != '\0' || prefixlen > IPV6_ABITS)
2012                         return (IPADM_INVALID_ARG);
2013                 sin6->sin6_family = AF_INET6;
2014                 ipaddr->ipadm_intfidlen = prefixlen;
2015                 return (IPADM_SUCCESS);
2016         }
2017         return (IPADM_INVALID_ARG);
2018 }
2019 
2020 /*
2021  * Sets the value for the field `ipadm_stateless' in address object `ipaddr'.
2022  */
2023 ipadm_status_t
2024 ipadm_set_stateless(ipadm_addrobj_t ipaddr, boolean_t stateless)
2025 {
2026         if (ipaddr == NULL ||
2027             ipaddr->ipadm_atype != IPADM_ADDR_IPV6_ADDRCONF)
2028                 return (IPADM_INVALID_ARG);
2029         ipaddr->ipadm_stateless = stateless;
2030 
2031         return (IPADM_SUCCESS);
2032 }
2033 
2034 /*
2035  * Sets the value for the field `ipadm_stateful' in address object `ipaddr'.
2036  */
2037 ipadm_status_t
2038 ipadm_set_stateful(ipadm_addrobj_t ipaddr, boolean_t stateful)
2039 {
2040         if (ipaddr == NULL ||
2041             ipaddr->ipadm_atype != IPADM_ADDR_IPV6_ADDRCONF)
2042                 return (IPADM_INVALID_ARG);
2043         ipaddr->ipadm_stateful = stateful;
2044 
2045         return (IPADM_SUCCESS);
2046 }
2047 
2048 /*
2049  * Sets the dhcp parameter `ipadm_primary' in the address object `ipaddr'.
2050  * The field is used during the address creation with address
2051  * type IPADM_ADDR_DHCP. It specifies if the interface should be set
2052  * as a primary interface for getting dhcp global options from the DHCP server.
2053  */
2054 ipadm_status_t
2055 ipadm_set_primary(ipadm_addrobj_t ipaddr, boolean_t primary)
2056 {
2057         if (ipaddr == NULL || ipaddr->ipadm_atype != IPADM_ADDR_DHCP)
2058                 return (IPADM_INVALID_ARG);
2059         ipaddr->ipadm_primary = primary;
2060 
2061         return (IPADM_SUCCESS);
2062 }
2063 
2064 /*
2065  * Sets the dhcp parameter `ipadm_wait' in the address object `ipaddr'.
2066  * This field is used during the address creation with address type
2067  * IPADM_ADDR_DHCP. It specifies how long the API ipadm_create_addr()
2068  * should wait before returning while the dhcp address is being acquired
2069  * by the dhcpagent.
2070  * Possible values:
2071  * - IPADM_DHCP_WAIT_FOREVER : Do not return until dhcpagent returns.
2072  * - IPADM_DHCP_WAIT_DEFAULT : Wait a default amount of time before returning.
2073  * - <integer>       : Wait the specified number of seconds before returning.
2074  */
2075 ipadm_status_t
2076 ipadm_set_wait_time(ipadm_addrobj_t ipaddr, int32_t wait)
2077 {
2078         if (ipaddr == NULL || ipaddr->ipadm_atype != IPADM_ADDR_DHCP)
2079                 return (IPADM_INVALID_ARG);
2080         ipaddr->ipadm_wait = wait;
2081         return (IPADM_SUCCESS);
2082 }
2083 
2084 /*
2085  * Sets the dhcp parameter `ipadm_reqhost' in the address object `ipaddr',
2086  * but validate any non-nil value using ipadm_is_valid_hostname() and also
2087  * check length.
2088  */
2089 ipadm_status_t
2090 ipadm_set_reqhost(ipadm_addrobj_t ipaddr, const char *reqhost)
2091 {
2092         const size_t HNLEN = sizeof (ipaddr->ipadm_reqhost);
2093 
2094         if (ipaddr == NULL || ipaddr->ipadm_atype != IPADM_ADDR_DHCP)
2095                 return (IPADM_INVALID_ARG);
2096 
2097         if (ipadm_is_nil_hostname(reqhost))
2098                 *ipaddr->ipadm_reqhost = '\0';
2099         else if (!ipadm_is_valid_hostname(reqhost))
2100                 return (IPADM_INVALID_ARG);
2101         else if (strlcpy(ipaddr->ipadm_reqhost, reqhost, HNLEN) >= HNLEN)
2102                 return (IPADM_INVALID_ARG);
2103         return (IPADM_SUCCESS);
2104 }
2105 
2106 /*
2107  * Creates a placeholder for the `ipadm_aobjname' in the ipmgmtd `aobjmap'.
2108  * If the `aobjname' already exists in the daemon's `aobjmap' then
2109  * IPADM_ADDROBJ_EXISTS will be returned.
2110  *
2111  * If the libipadm consumer set `ipaddr.ipadm_aobjname[0]' to `\0', then the
2112  * daemon will generate an `aobjname' for the given `ipaddr'.
2113  */
2114 ipadm_status_t
2115 i_ipadm_lookupadd_addrobj(ipadm_handle_t iph, ipadm_addrobj_t ipaddr)
2116 {
2117         ipmgmt_aobjop_arg_t     larg;
2118         ipmgmt_aobjop_rval_t    rval, *rvalp;
2119         int                     err;
2120 
2121         bzero(&larg, sizeof (larg));
2122         larg.ia_cmd = IPMGMT_CMD_ADDROBJ_LOOKUPADD;
2123         (void) strlcpy(larg.ia_aobjname, ipaddr->ipadm_aobjname,
2124             sizeof (larg.ia_aobjname));
2125         (void) strlcpy(larg.ia_ifname, ipaddr->ipadm_ifname,
2126             sizeof (larg.ia_ifname));
2127         larg.ia_family = ipaddr->ipadm_af;
2128         larg.ia_atype = ipaddr->ipadm_atype;
2129 
2130         rvalp = &rval;
2131         err = ipadm_door_call(iph, &larg, sizeof (larg), (void **)&rvalp,
2132             sizeof (rval), B_FALSE);
2133         if (err == 0 && ipaddr->ipadm_aobjname[0] == '\0') {
2134                 /* copy the daemon generated `aobjname' into `ipadddr' */
2135                 (void) strlcpy(ipaddr->ipadm_aobjname, rval.ir_aobjname,
2136                     sizeof (ipaddr->ipadm_aobjname));
2137         }
2138         if (err == EEXIST)
2139                 return (IPADM_ADDROBJ_EXISTS);
2140         return (ipadm_errno2status(err));
2141 }
2142 
2143 /*
2144  * Sets the logical interface number in the ipmgmtd's memory map for the
2145  * address object `ipaddr'. If another address object has the same
2146  * logical interface number, IPADM_ADDROBJ_EXISTS is returned.
2147  */
2148 ipadm_status_t
2149 i_ipadm_setlifnum_addrobj(ipadm_handle_t iph, ipadm_addrobj_t ipaddr)
2150 {
2151         ipmgmt_aobjop_arg_t     larg;
2152         ipmgmt_retval_t         rval, *rvalp;
2153         int                     err;
2154 
2155         if (iph->iph_flags & IPH_IPMGMTD)
2156                 return (IPADM_SUCCESS);
2157 
2158         bzero(&larg, sizeof (larg));
2159         larg.ia_cmd = IPMGMT_CMD_ADDROBJ_SETLIFNUM;
2160         (void) strlcpy(larg.ia_aobjname, ipaddr->ipadm_aobjname,
2161             sizeof (larg.ia_aobjname));
2162         larg.ia_lnum = ipaddr->ipadm_lifnum;
2163         (void) strlcpy(larg.ia_ifname, ipaddr->ipadm_ifname,
2164             sizeof (larg.ia_ifname));
2165         larg.ia_family = ipaddr->ipadm_af;
2166 
2167         rvalp = &rval;
2168         err = ipadm_door_call(iph, &larg, sizeof (larg), (void **)&rvalp,
2169             sizeof (rval), B_FALSE);
2170         if (err == EEXIST)
2171                 return (IPADM_ADDROBJ_EXISTS);
2172         return (ipadm_errno2status(err));
2173 }
2174 
2175 /*
2176  * Creates the IPv4 or IPv6 address in the nvlist `nvl' on the interface
2177  * `ifname'. If a hostname is present, it is resolved before the address
2178  * is created.
2179  */
2180 ipadm_status_t
2181 i_ipadm_enable_static(ipadm_handle_t iph, const char *ifname, nvlist_t *nvl,
2182     sa_family_t af)
2183 {
2184         char                    *prefixlenstr = NULL;
2185         char                    *upstr = NULL;
2186         char                    *sname = NULL, *dname = NULL;
2187         struct ipadm_addrobj_s  ipaddr;
2188         char                    *aobjname = NULL;
2189         nvlist_t                *nvaddr = NULL;
2190         nvpair_t                *nvp;
2191         char                    *cidraddr;
2192         char                    *name;
2193         ipadm_status_t          status;
2194         int                     err = 0;
2195         uint32_t                flags = IPADM_OPT_ACTIVE;
2196 
2197         /* retrieve the address information */
2198         for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL;
2199             nvp = nvlist_next_nvpair(nvl, nvp)) {
2200                 name = nvpair_name(nvp);
2201                 if (strcmp(name, IPADM_NVP_IPV4ADDR) == 0 ||
2202                     strcmp(name, IPADM_NVP_IPV6ADDR) == 0) {
2203                         err = nvpair_value_nvlist(nvp, &nvaddr);
2204                 } else if (strcmp(name, IPADM_NVP_AOBJNAME) == 0) {
2205                         err = nvpair_value_string(nvp, &aobjname);
2206                 } else if (strcmp(name, IPADM_NVP_PREFIXLEN) == 0) {
2207                         err = nvpair_value_string(nvp, &prefixlenstr);
2208                 } else if (strcmp(name, "up") == 0) {
2209                         err = nvpair_value_string(nvp, &upstr);
2210                 }
2211                 if (err != 0)
2212                         return (ipadm_errno2status(err));
2213         }
2214         for (nvp = nvlist_next_nvpair(nvaddr, NULL); nvp != NULL;
2215             nvp = nvlist_next_nvpair(nvaddr, nvp)) {
2216                 name = nvpair_name(nvp);
2217                 if (strcmp(name, IPADM_NVP_IPADDRHNAME) == 0)
2218                         err = nvpair_value_string(nvp, &sname);
2219                 else if (strcmp(name, IPADM_NVP_IPDADDRHNAME) == 0)
2220                         err = nvpair_value_string(nvp, &dname);
2221                 if (err != 0)
2222                         return (ipadm_errno2status(err));
2223         }
2224 
2225         if (strcmp(upstr, "yes") == 0)
2226                 flags |= IPADM_OPT_UP;
2227 
2228         /* build the address object from the above information */
2229         i_ipadm_init_addr(&ipaddr, ifname, aobjname, IPADM_ADDR_STATIC);
2230         if (prefixlenstr != NULL && atoi(prefixlenstr) > 0) {
2231                 if (asprintf(&cidraddr, "%s/%s", sname, prefixlenstr) == -1)
2232                         return (IPADM_NO_MEMORY);
2233                 status = ipadm_set_addr(&ipaddr, cidraddr, af);
2234                 free(cidraddr);
2235         } else {
2236                 status = ipadm_set_addr(&ipaddr, sname, af);
2237         }
2238         if (status != IPADM_SUCCESS)
2239                 return (status);
2240 
2241         if (dname != NULL) {
2242                 status = ipadm_set_dst_addr(&ipaddr, dname, af);
2243                 if (status != IPADM_SUCCESS)
2244                         return (status);
2245         }
2246         return (i_ipadm_create_addr(iph, &ipaddr, flags));
2247 }
2248 
2249 /*
2250  * Creates a dhcp address on the interface `ifname' based on the
2251  * IPADM_ADDR_DHCP address object parameters from the nvlist `nvl'.
2252  */
2253 ipadm_status_t
2254 i_ipadm_enable_dhcp(ipadm_handle_t iph, const char *ifname, nvlist_t *nvl)
2255 {
2256         int32_t                 wait = IPADM_DHCP_WAIT_DEFAULT;
2257         boolean_t               primary = B_FALSE;
2258         nvlist_t                *nvdhcp = NULL;
2259         nvpair_t                *nvp;
2260         char                    *name;
2261         struct ipadm_addrobj_s  ipaddr;
2262         char                    *aobjname = NULL, *reqhost = NULL;
2263         int                     err = 0;
2264         ipadm_status_t  ipadm_err = IPADM_SUCCESS;
2265 
2266         /* Extract the dhcp parameters */
2267         for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL;
2268             nvp = nvlist_next_nvpair(nvl, nvp)) {
2269                 name = nvpair_name(nvp);
2270                 if (strcmp(name, IPADM_NVP_DHCP) == 0)
2271                         err = nvpair_value_nvlist(nvp, &nvdhcp);
2272                 else if (strcmp(name, IPADM_NVP_AOBJNAME) == 0)
2273                         err = nvpair_value_string(nvp, &aobjname);
2274                 else if (strcmp(name, IPADM_NVP_REQHOST) == 0)
2275                         err = nvpair_value_string(nvp, &reqhost);
2276                 if (err != 0)
2277                         return (ipadm_errno2status(err));
2278         }
2279         for (nvp = nvlist_next_nvpair(nvdhcp, NULL); nvp != NULL;
2280             nvp = nvlist_next_nvpair(nvdhcp, nvp)) {
2281                 name = nvpair_name(nvp);
2282                 if (strcmp(name, IPADM_NVP_WAIT) == 0)
2283                         err = nvpair_value_int32(nvp, &wait);
2284                 else if (strcmp(name, IPADM_NVP_PRIMARY) == 0)
2285                         err = nvpair_value_boolean_value(nvp, &primary);
2286                 if (err != 0)
2287                         return (ipadm_errno2status(err));
2288         }
2289 
2290         /* Build the address object */
2291         i_ipadm_init_addr(&ipaddr, ifname, aobjname, IPADM_ADDR_DHCP);
2292         ipaddr.ipadm_primary = primary;
2293         if (iph->iph_flags & IPH_INIT)
2294                 ipaddr.ipadm_wait = 0;
2295         else
2296                 ipaddr.ipadm_wait = wait;
2297         ipadm_err = ipadm_set_reqhost(&ipaddr, reqhost);
2298         if (ipadm_err != IPADM_SUCCESS)
2299                 return ipadm_err;
2300         ipaddr.ipadm_af = AF_INET;
2301         return (i_ipadm_create_dhcp(iph, &ipaddr, IPADM_OPT_ACTIVE));
2302 }
2303 
2304 /*
2305  * Creates auto-configured addresses on the interface `ifname' based on
2306  * the IPADM_ADDR_IPV6_ADDRCONF address object parameters from the nvlist `nvl'.
2307  */
2308 ipadm_status_t
2309 i_ipadm_enable_addrconf(ipadm_handle_t iph, const char *ifname, nvlist_t *nvl)
2310 {
2311         struct ipadm_addrobj_s  ipaddr;
2312         char            *stateful = NULL, *stateless = NULL;
2313         uint_t          n;
2314         uint8_t         *addr6 = NULL;
2315         uint32_t        intfidlen = 0;
2316         char            *aobjname;
2317         nvlist_t        *nvaddr;
2318         nvpair_t        *nvp;
2319         char            *name;
2320         int             err = 0;
2321 
2322         /* Extract the parameters */
2323         for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL;
2324             nvp = nvlist_next_nvpair(nvl, nvp)) {
2325                 name = nvpair_name(nvp);
2326                 if (strcmp(name, IPADM_NVP_INTFID) == 0)
2327                         err = nvpair_value_nvlist(nvp, &nvaddr);
2328                 else if (strcmp(name, IPADM_NVP_AOBJNAME) == 0)
2329                         err = nvpair_value_string(nvp, &aobjname);
2330                 if (err != 0)
2331                         return (ipadm_errno2status(err));
2332         }
2333         for (nvp = nvlist_next_nvpair(nvaddr, NULL); nvp != NULL;
2334             nvp = nvlist_next_nvpair(nvaddr, nvp)) {
2335                 name = nvpair_name(nvp);
2336                 if (strcmp(name, IPADM_NVP_IPNUMADDR) == 0)
2337                         err = nvpair_value_uint8_array(nvp, &addr6, &n);
2338                 if (strcmp(name, IPADM_NVP_PREFIXLEN) == 0)
2339                         err = nvpair_value_uint32(nvp, &intfidlen);
2340                 else if (strcmp(name, IPADM_NVP_STATELESS) == 0)
2341                         err = nvpair_value_string(nvp, &stateless);
2342                 else if (strcmp(name, IPADM_NVP_STATEFUL) == 0)
2343                         err = nvpair_value_string(nvp, &stateful);
2344                 if (err != 0)
2345                         return (ipadm_errno2status(err));
2346         }
2347         /* Build the address object. */
2348         i_ipadm_init_addr(&ipaddr, ifname, aobjname, IPADM_ADDR_IPV6_ADDRCONF);
2349         if (intfidlen > 0) {
2350                 ipaddr.ipadm_intfidlen = intfidlen;
2351                 bcopy(addr6, &ipaddr.ipadm_intfid.sin6_addr.s6_addr, n);
2352         }
2353         ipaddr.ipadm_stateless = (strcmp(stateless, "yes") == 0);
2354         ipaddr.ipadm_stateful = (strcmp(stateful, "yes") == 0);
2355         return (i_ipadm_create_ipv6addrs(iph, &ipaddr, IPADM_OPT_ACTIVE));
2356 }
2357 
2358 /*
2359  * Allocates `ipadm_addrobj_t' and populates the relevant member fields based on
2360  * the provided `type'. `aobjname' represents the address object name, which
2361  * is of the form `<ifname>/<addressname>'.
2362  *
2363  * The caller has to minimally provide <ifname>. If <addressname> is not
2364  * provided, then a default one will be generated by the API.
2365  */
2366 ipadm_status_t
2367 ipadm_create_addrobj(ipadm_addr_type_t type, const char *aobjname,
2368     ipadm_addrobj_t *ipaddr)
2369 {
2370         ipadm_addrobj_t newaddr;
2371         ipadm_status_t  status;
2372         char            *aname, *cp;
2373         char            ifname[IPADM_AOBJSIZ];
2374         ifspec_t        ifsp;
2375 
2376         if (ipaddr == NULL)
2377                 return (IPADM_INVALID_ARG);
2378         *ipaddr = NULL;
2379 
2380         if (aobjname == NULL || aobjname[0] == '\0')
2381                 return (IPADM_INVALID_ARG);
2382 
2383         if (strlcpy(ifname, aobjname, IPADM_AOBJSIZ) >= IPADM_AOBJSIZ)
2384                 return (IPADM_INVALID_ARG);
2385 
2386         if ((aname = strchr(ifname, '/')) != NULL)
2387                 *aname++ = '\0';
2388 
2389         /* Check if the interface name is valid. */
2390         if (!ifparse_ifspec(ifname, &ifsp))
2391                 return (IPADM_INVALID_ARG);
2392 
2393         /* Check if the given addrobj name is valid. */
2394         if (aname != NULL && !i_ipadm_is_user_aobjname_valid(aname))
2395                 return (IPADM_INVALID_ARG);
2396 
2397         if ((newaddr = calloc(1, sizeof (struct ipadm_addrobj_s))) == NULL)
2398                 return (IPADM_NO_MEMORY);
2399 
2400         /*
2401          * If the ifname has logical interface number, extract it and assign
2402          * it to `ipadm_lifnum'. Only applications with IPH_LEGACY set will do
2403          * this today. We will check for the validity later in
2404          * i_ipadm_validate_create_addr().
2405          */
2406         if (ifsp.ifsp_lunvalid) {
2407                 newaddr->ipadm_lifnum = ifsp.ifsp_lun;
2408                 cp = strchr(ifname, IPADM_LOGICAL_SEP);
2409                 *cp = '\0';
2410         }
2411         (void) strlcpy(newaddr->ipadm_ifname, ifname,
2412             sizeof (newaddr->ipadm_ifname));
2413 
2414         if (aname != NULL) {
2415                 (void) snprintf(newaddr->ipadm_aobjname,
2416                     sizeof (newaddr->ipadm_aobjname), "%s/%s", ifname, aname);
2417         }
2418 
2419         switch (type) {
2420         case IPADM_ADDR_IPV6_ADDRCONF:
2421                 newaddr->ipadm_intfidlen = 0;
2422                 newaddr->ipadm_stateful = B_TRUE;
2423                 newaddr->ipadm_stateless = B_TRUE;
2424                 newaddr->ipadm_af = AF_INET6;
2425                 break;
2426 
2427         case IPADM_ADDR_DHCP:
2428                 newaddr->ipadm_primary = B_FALSE;
2429                 newaddr->ipadm_wait = IPADM_DHCP_WAIT_DEFAULT;
2430                 newaddr->ipadm_af = AF_INET;
2431                 break;
2432 
2433         case IPADM_ADDR_STATIC:
2434                 newaddr->ipadm_af = AF_UNSPEC;
2435                 newaddr->ipadm_static_prefixlen = 0;
2436                 break;
2437 
2438         default:
2439                 status = IPADM_INVALID_ARG;
2440                 goto fail;
2441         }
2442         newaddr->ipadm_atype = type;
2443         *ipaddr = newaddr;
2444         return (IPADM_SUCCESS);
2445 fail:
2446         free(newaddr);
2447         return (status);
2448 }
2449 
2450 /*
2451  * Returns `aobjname' from the address object in `ipaddr'.
2452  */
2453 ipadm_status_t
2454 ipadm_get_aobjname(const ipadm_addrobj_t ipaddr, char *aobjname, size_t len)
2455 {
2456         if (ipaddr == NULL || aobjname == NULL)
2457                 return (IPADM_INVALID_ARG);
2458         if (strlcpy(aobjname, ipaddr->ipadm_aobjname, len) >= len)
2459                 return (IPADM_INVALID_ARG);
2460 
2461         return (IPADM_SUCCESS);
2462 }
2463 
2464 /*
2465  * Frees the address object in `ipaddr'.
2466  */
2467 void
2468 ipadm_destroy_addrobj(ipadm_addrobj_t ipaddr)
2469 {
2470         free(ipaddr);
2471 }
2472 
2473 /*
2474  * Retrieves the logical interface name from `ipaddr' and stores the
2475  * string in `lifname'.
2476  */
2477 void
2478 i_ipadm_addrobj2lifname(ipadm_addrobj_t ipaddr, char *lifname, int lifnamesize)
2479 {
2480         if (ipaddr->ipadm_lifnum != 0) {
2481                 (void) snprintf(lifname, lifnamesize, "%s:%d",
2482                     ipaddr->ipadm_ifname, ipaddr->ipadm_lifnum);
2483         } else {
2484                 (void) snprintf(lifname, lifnamesize, "%s",
2485                     ipaddr->ipadm_ifname);
2486         }
2487 }
2488 
2489 /*
2490  * Checks if a non-zero static address is present on the 0th logical interface
2491  * of the given IPv4 or IPv6 physical interface. For an IPv4 interface, it
2492  * also checks if the interface is under DHCP control. If the condition is true,
2493  * the output argument `exists' will be set to B_TRUE. Otherwise, `exists'
2494  * is set to B_FALSE.
2495  *
2496  * Note that *exists will not be initialized if an error is encountered.
2497  */
2498 static ipadm_status_t
2499 i_ipadm_addr_exists_on_if(ipadm_handle_t iph, const char *ifname,
2500     sa_family_t af, boolean_t *exists)
2501 {
2502         struct lifreq   lifr;
2503         int             sock;
2504 
2505         /* For IPH_LEGACY, a new logical interface will never be added. */
2506         if (iph->iph_flags & IPH_LEGACY) {
2507                 *exists = B_FALSE;
2508                 return (IPADM_SUCCESS);
2509         }
2510         bzero(&lifr, sizeof (lifr));
2511         (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
2512         if (af == AF_INET) {
2513                 sock = iph->iph_sock;
2514                 if (ioctl(sock, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0)
2515                         return (ipadm_errno2status(errno));
2516                 if (lifr.lifr_flags & IFF_DHCPRUNNING) {
2517                         *exists = B_TRUE;
2518                         return (IPADM_SUCCESS);
2519                 }
2520         } else {
2521                 sock = iph->iph_sock6;
2522         }
2523         if (ioctl(sock, SIOCGLIFADDR, (caddr_t)&lifr) < 0)
2524                 return (ipadm_errno2status(errno));
2525         *exists = !sockaddrunspec((struct sockaddr *)&lifr.lifr_addr);
2526 
2527         return (IPADM_SUCCESS);
2528 }
2529 
2530 /*
2531  * Adds a new logical interface in the kernel for interface
2532  * `addr->ipadm_ifname', if there is a non-zero address on the 0th
2533  * logical interface or if the 0th logical interface is under DHCP
2534  * control. On success, it sets the lifnum in the address object `addr'.
2535  */
2536 ipadm_status_t
2537 i_ipadm_do_addif(ipadm_handle_t iph, ipadm_addrobj_t addr)
2538 {
2539         ipadm_status_t  status;
2540         boolean_t       addif;
2541         struct lifreq   lifr;
2542         int             sock;
2543 
2544         addr->ipadm_lifnum = 0;
2545         status = i_ipadm_addr_exists_on_if(iph, addr->ipadm_ifname,
2546             addr->ipadm_af, &addif);
2547         if (status != IPADM_SUCCESS)
2548                 return (status);
2549         if (addif) {
2550                 /*
2551                  * If there is an address on 0th logical interface,
2552                  * add a new logical interface.
2553                  */
2554                 bzero(&lifr, sizeof (lifr));
2555                 (void) strlcpy(lifr.lifr_name, addr->ipadm_ifname,
2556                     sizeof (lifr.lifr_name));
2557                 sock = (addr->ipadm_af == AF_INET ? iph->iph_sock :
2558                     iph->iph_sock6);
2559                 if (ioctl(sock, SIOCLIFADDIF, (caddr_t)&lifr) < 0)
2560                         return (ipadm_errno2status(errno));
2561                 addr->ipadm_lifnum = i_ipadm_get_lnum(lifr.lifr_name);
2562         }
2563         return (IPADM_SUCCESS);
2564 }
2565 
2566 /*
2567  * Reads all the address lines from the persistent DB into the nvlist `onvl',
2568  * when both `ifname' and `aobjname' are NULL. If an `ifname' is provided,
2569  * it returns all the addresses for the given interface `ifname'.
2570  * If an `aobjname' is specified, then the address line corresponding to
2571  * that name will be returned.
2572  */
2573 static ipadm_status_t
2574 i_ipadm_get_db_addr(ipadm_handle_t iph, const char *ifname,
2575     const char *aobjname, nvlist_t **onvl)
2576 {
2577         ipmgmt_getaddr_arg_t    garg;
2578         ipmgmt_get_rval_t       *rvalp;
2579         int                     err;
2580         size_t                  nvlsize;
2581         char                    *nvlbuf;
2582 
2583         /* Populate the door_call argument structure */
2584         bzero(&garg, sizeof (garg));
2585         garg.ia_cmd = IPMGMT_CMD_GETADDR;
2586         if (aobjname != NULL)
2587                 (void) strlcpy(garg.ia_aobjname, aobjname,
2588                     sizeof (garg.ia_aobjname));
2589         if (ifname != NULL)
2590                 (void) strlcpy(garg.ia_ifname, ifname, sizeof (garg.ia_ifname));
2591 
2592         rvalp = malloc(sizeof (ipmgmt_get_rval_t));
2593         err = ipadm_door_call(iph, &garg, sizeof (garg), (void **)&rvalp,
2594             sizeof (*rvalp), B_TRUE);
2595         if (err == 0) {
2596                 nvlsize = rvalp->ir_nvlsize;
2597                 nvlbuf = (char *)rvalp + sizeof (ipmgmt_get_rval_t);
2598                 err = nvlist_unpack(nvlbuf, nvlsize, onvl, NV_ENCODE_NATIVE);
2599         }
2600         free(rvalp);
2601         return (ipadm_errno2status(err));
2602 }
2603 
2604 /*
2605  * Adds the IP address contained in the 'ipaddr' argument to the physical
2606  * interface represented by 'ifname' after doing the required validation.
2607  * If the interface does not exist, it is created before the address is
2608  * added.
2609  *
2610  * If IPH_LEGACY is set in iph_flags, flags has to be IPADM_OPT_ACTIVE
2611  * and a default addrobj name will be generated. Input `addr->ipadm_aobjname',
2612  * if provided, will be ignored and replaced with the newly generated name.
2613  * The interface name provided has to be a logical interface name that
2614  * already exists. No new logical interface will be added in this function.
2615  *
2616  * If IPADM_OPT_V46 is passed in the flags, then both IPv4 and IPv6 interfaces
2617  * are plumbed (if they haven't been already).  Otherwise, just the interface
2618  * specified in `addr' is plumbed.
2619  */
2620 ipadm_status_t
2621 ipadm_create_addr(ipadm_handle_t iph, ipadm_addrobj_t addr, uint32_t flags)
2622 {
2623         ipadm_status_t          status;
2624         sa_family_t             af;
2625         sa_family_t             daf;
2626         sa_family_t             other_af;
2627         boolean_t               created_af = B_FALSE;
2628         boolean_t               created_other_af = B_FALSE;
2629         ipadm_addr_type_t       type;
2630         char                    *ifname = addr->ipadm_ifname;
2631         boolean_t               legacy = (iph->iph_flags & IPH_LEGACY);
2632         boolean_t               aobjfound;
2633         boolean_t               is_6to4;
2634         struct lifreq           lifr;
2635         uint64_t                ifflags;
2636         boolean_t               is_boot = (iph->iph_flags & IPH_IPMGMTD);
2637 
2638         /* check for solaris.network.interface.config authorization */
2639         if (!ipadm_check_auth())
2640                 return (IPADM_EAUTH);
2641 
2642         /* Validate the addrobj. This also fills in addr->ipadm_ifname. */
2643         status = i_ipadm_validate_create_addr(iph, addr, flags);
2644         if (status != IPADM_SUCCESS)
2645                 return (status);
2646 
2647         /*
2648          * For Legacy case, check if an addrobj already exists for the
2649          * given logical interface name. If one does not exist,
2650          * a default name will be generated and added to the daemon's
2651          * aobjmap.
2652          */
2653         if (legacy) {
2654                 struct ipadm_addrobj_s  ipaddr;
2655 
2656                 ipaddr = *addr;
2657                 status = i_ipadm_get_lif2addrobj(iph, &ipaddr);
2658                 if (status == IPADM_SUCCESS) {
2659                         aobjfound = B_TRUE;
2660                         /*
2661                          * With IPH_LEGACY, modifying an address that is not
2662                          * a static address will return with an error.
2663                          */
2664                         if (ipaddr.ipadm_atype != IPADM_ADDR_STATIC)
2665                                 return (IPADM_NOTSUP);
2666                         /*
2667                          * we found the addrobj in daemon, copy over the
2668                          * aobjname to `addr'.
2669                          */
2670                         (void) strlcpy(addr->ipadm_aobjname,
2671                             ipaddr.ipadm_aobjname, IPADM_AOBJSIZ);
2672                 } else if (status == IPADM_NOTFOUND) {
2673                         aobjfound = B_FALSE;
2674                 } else {
2675                         return (status);
2676                 }
2677         }
2678 
2679         af = addr->ipadm_af;
2680         /*
2681          * Create a placeholder for this address object in the daemon.
2682          * Skip this step if we are booting a zone (and therefore being called
2683          * from ipmgmtd itself), and, for IPH_LEGACY case if the
2684          * addrobj already exists.
2685          *
2686          * Note that the placeholder is not needed in the NGZ boot case,
2687          * when zoneadmd has itself applied the "allowed-ips" property to clamp
2688          * down any interface configuration, so the namespace for the interface
2689          * is fully controlled by the GZ.
2690          */
2691         if (!is_boot && (!legacy || !aobjfound)) {
2692                 status = i_ipadm_lookupadd_addrobj(iph, addr);
2693                 if (status != IPADM_SUCCESS)
2694                         return (status);
2695         }
2696 
2697         is_6to4 = i_ipadm_is_6to4(iph, ifname);
2698         /* Plumb the IP interfaces if necessary */
2699         status = i_ipadm_create_if(iph, ifname, af, flags);
2700         if (status != IPADM_SUCCESS && status != IPADM_IF_EXISTS) {
2701                 (void) i_ipadm_delete_addrobj(iph, addr, IPADM_OPT_ACTIVE);
2702                 return (status);
2703         }
2704         if (status == IPADM_SUCCESS)
2705                 created_af = B_TRUE;
2706         if (!is_6to4 && !legacy && (flags & IPADM_OPT_V46)) {
2707                 other_af = (af == AF_INET ? AF_INET6 : AF_INET);
2708                 status = i_ipadm_create_if(iph, ifname, other_af, flags);
2709                 if (status != IPADM_SUCCESS && status != IPADM_IF_EXISTS) {
2710                         (void) i_ipadm_delete_if(iph, ifname, af, flags);
2711                         return (status);
2712                 }
2713                 if (status == IPADM_SUCCESS)
2714                         created_other_af = B_TRUE;
2715         }
2716 
2717         /*
2718          * Some input validation based on the interface flags:
2719          * 1. in non-global zones, make sure that we are not persistently
2720          *    creating addresses on interfaces that are acquiring
2721          *    address from the global zone.
2722          * 2. Validate static addresses for IFF_POINTOPOINT interfaces.
2723          */
2724         if (addr->ipadm_atype == IPADM_ADDR_STATIC) {
2725                 status = i_ipadm_get_flags(iph, ifname, af, &ifflags);
2726                 if (status != IPADM_SUCCESS)
2727                         goto fail;
2728 
2729                 if (iph->iph_zoneid != GLOBAL_ZONEID &&
2730                     (ifflags & IFF_L3PROTECT) && (flags & IPADM_OPT_PERSIST)) {
2731                         status = IPADM_GZ_PERM;
2732                         goto fail;
2733                 }
2734                 daf = addr->ipadm_static_dst_addr.ss_family;
2735                 if (ifflags & IFF_POINTOPOINT) {
2736                         if (is_6to4) {
2737                                 if (af != AF_INET6 || daf != AF_UNSPEC) {
2738                                         status = IPADM_INVALID_ARG;
2739                                         goto fail;
2740                                 }
2741                         } else {
2742                                 if (daf != af) {
2743                                         status = IPADM_INVALID_ARG;
2744                                         goto fail;
2745                                 }
2746                                 /* Check for a valid dst address. */
2747                                 if (!legacy && sockaddrunspec(
2748                                     (struct sockaddr *)
2749                                     &addr->ipadm_static_dst_addr)) {
2750                                         status = IPADM_BAD_ADDR;
2751                                         goto fail;
2752                                 }
2753                         }
2754                 } else {
2755                         /*
2756                          * Disallow setting of dstaddr when the link is not
2757                          * a point-to-point link.
2758                          */
2759                         if (daf != AF_UNSPEC)
2760                                 return (IPADM_INVALID_ARG);
2761                 }
2762         }
2763 
2764         /*
2765          * For 6to4 interfaces, kernel configures a default link-local
2766          * address. We need to replace it, if the caller has provided
2767          * an address that is different from the default link-local.
2768          */
2769         if (status == IPADM_SUCCESS && is_6to4) {
2770                 bzero(&lifr, sizeof (lifr));
2771                 (void) strlcpy(lifr.lifr_name, addr->ipadm_ifname,
2772                     sizeof (lifr.lifr_name));
2773                 if (ioctl(iph->iph_sock6, SIOCGLIFADDR, &lifr) < 0) {
2774                         status = ipadm_errno2status(errno);
2775                         goto fail;
2776                 }
2777                 if (sockaddrcmp(&lifr.lifr_addr, &addr->ipadm_static_addr))
2778                         return (IPADM_SUCCESS);
2779         }
2780 
2781         /* Create the address. */
2782         type = addr->ipadm_atype;
2783         switch (type) {
2784         case IPADM_ADDR_STATIC:
2785                 status = i_ipadm_create_addr(iph, addr, flags);
2786                 break;
2787         case IPADM_ADDR_DHCP:
2788                 status = i_ipadm_create_dhcp(iph, addr, flags);
2789                 break;
2790         case IPADM_ADDR_IPV6_ADDRCONF:
2791                 status = i_ipadm_create_ipv6addrs(iph, addr, flags);
2792                 break;
2793         default:
2794                 status = IPADM_INVALID_ARG;
2795                 break;
2796         }
2797 
2798         /*
2799          * If address was not created successfully, unplumb the interface
2800          * if it was plumbed implicitly in this function and remove the
2801          * addrobj created by the ipmgmtd daemon as a placeholder.
2802          * If IPH_LEGACY is set, then remove the addrobj only if it was
2803          * created in this function.
2804          */
2805 fail:
2806         if (status != IPADM_DHCP_IPC_TIMEOUT &&
2807             status != IPADM_SUCCESS) {
2808                 if (!legacy) {
2809                         if (created_af || created_other_af) {
2810                                 if (created_af) {
2811                                         (void) i_ipadm_delete_if(iph, ifname,
2812                                             af, flags);
2813                                 }
2814                                 if (created_other_af) {
2815                                         (void) i_ipadm_delete_if(iph, ifname,
2816                                             other_af, flags);
2817                                 }
2818                         } else {
2819                                 (void) i_ipadm_delete_addrobj(iph, addr, flags);
2820                         }
2821                 } else if (!aobjfound) {
2822                         (void) i_ipadm_delete_addrobj(iph, addr, flags);
2823                 }
2824         }
2825 
2826         return (status);
2827 }
2828 
2829 /*
2830  * Creates the static address in `ipaddr' in kernel. After successfully
2831  * creating it, it updates the ipmgmtd daemon's aobjmap with the logical
2832  * interface information.
2833  */
2834 static ipadm_status_t
2835 i_ipadm_create_addr(ipadm_handle_t iph, ipadm_addrobj_t ipaddr, uint32_t flags)
2836 {
2837         struct lifreq                   lifr;
2838         ipadm_status_t                  status = IPADM_SUCCESS;
2839         int                             sock;
2840         struct sockaddr_storage         m, *mask = &m;
2841         const struct sockaddr_storage   *addr = &ipaddr->ipadm_static_addr;
2842         const struct sockaddr_storage   *daddr = &ipaddr->ipadm_static_dst_addr;
2843         sa_family_t                     af;
2844         boolean_t                       legacy = (iph->iph_flags & IPH_LEGACY);
2845         struct ipadm_addrobj_s          legacy_addr;
2846         boolean_t                       default_prefixlen = B_FALSE;
2847         boolean_t                       is_boot;
2848 
2849         is_boot = ((iph->iph_flags & IPH_IPMGMTD) != 0);
2850         af = ipaddr->ipadm_af;
2851         sock = (af == AF_INET ? iph->iph_sock : iph->iph_sock6);
2852 
2853         /* If prefixlen was not provided, get default prefixlen */
2854         if (ipaddr->ipadm_static_prefixlen == 0) {
2855                 /* prefixlen was not provided, get default prefixlen */
2856                 status = i_ipadm_get_default_prefixlen(
2857                     &ipaddr->ipadm_static_addr,
2858                     &ipaddr->ipadm_static_prefixlen);
2859                 if (status != IPADM_SUCCESS)
2860                         return (status);
2861                 default_prefixlen = B_TRUE;
2862         }
2863         (void) plen2mask(ipaddr->ipadm_static_prefixlen, af,
2864             (struct sockaddr *)mask);
2865 
2866         /*
2867          * Create a new logical interface if needed; otherwise, just
2868          * use the 0th logical interface.
2869          */
2870 retry:
2871         if (!(iph->iph_flags & IPH_LEGACY)) {
2872                 status = i_ipadm_do_addif(iph, ipaddr);
2873                 if (status != IPADM_SUCCESS)
2874                         return (status);
2875                 /*
2876                  * We don't have to set the lifnum for IPH_INIT case, because
2877                  * there is no placeholder created for the address object in
2878                  * this case. For IPH_LEGACY, we don't do this because the
2879                  * lifnum is given by the caller and it will be set in the
2880                  * end while we call the i_ipadm_addr_persist().
2881                  */
2882                 if (!(iph->iph_flags & IPH_INIT)) {
2883                         status = i_ipadm_setlifnum_addrobj(iph, ipaddr);
2884                         if (status == IPADM_ADDROBJ_EXISTS)
2885                                 goto retry;
2886                         if (status != IPADM_SUCCESS)
2887                                 return (status);
2888                 }
2889         }
2890         i_ipadm_addrobj2lifname(ipaddr, lifr.lifr_name,
2891             sizeof (lifr.lifr_name));
2892         lifr.lifr_addr = *mask;
2893         if (ioctl(sock, SIOCSLIFNETMASK, (caddr_t)&lifr) < 0) {
2894                 status = ipadm_errno2status(errno);
2895                 goto ret;
2896         }
2897         lifr.lifr_addr = *addr;
2898         if (ioctl(sock, SIOCSLIFADDR, (caddr_t)&lifr) < 0) {
2899                 status = ipadm_errno2status(errno);
2900                 goto ret;
2901         }
2902         /* Set the destination address, if one is given. */
2903         if (daddr->ss_family != AF_UNSPEC) {
2904                 lifr.lifr_addr = *daddr;
2905                 if (ioctl(sock, SIOCSLIFDSTADDR, (caddr_t)&lifr) < 0) {
2906                         status = ipadm_errno2status(errno);
2907                         goto ret;
2908                 }
2909         }
2910 
2911         if (flags & IPADM_OPT_UP) {
2912                 status = i_ipadm_set_flags(iph, lifr.lifr_name, af, IFF_UP, 0);
2913 
2914                 /*
2915                  * IPADM_DAD_FOUND is a soft-error for create-addr.
2916                  * No need to tear down the address.
2917                  */
2918                 if (status == IPADM_DAD_FOUND)
2919                         status = IPADM_SUCCESS;
2920         }
2921 
2922         if (status == IPADM_SUCCESS && !is_boot) {
2923                 /*
2924                  * For IPH_LEGACY, we might be modifying the address on
2925                  * an address object that already exists e.g. by doing
2926                  * "ifconfig bge0:1 <addr>; ifconfig bge0:1 <newaddr>"
2927                  * So, we need to store the object only if it does not
2928                  * already exist in ipmgmtd.
2929                  */
2930                 if (legacy) {
2931                         bzero(&legacy_addr, sizeof (legacy_addr));
2932                         (void) strlcpy(legacy_addr.ipadm_aobjname,
2933                             ipaddr->ipadm_aobjname,
2934                             sizeof (legacy_addr.ipadm_aobjname));
2935                         status = i_ipadm_get_addrobj(iph, &legacy_addr);
2936                         if (status == IPADM_SUCCESS &&
2937                             legacy_addr.ipadm_lifnum >= 0) {
2938                                 return (status);
2939                         }
2940                 }
2941                 status = i_ipadm_addr_persist(iph, ipaddr, default_prefixlen,
2942                     flags, NULL);
2943         }
2944 ret:
2945         if (status != IPADM_SUCCESS && !legacy)
2946                 (void) i_ipadm_delete_addr(iph, ipaddr);
2947         return (status);
2948 }
2949 
2950 /*
2951  * Removes the address object identified by `aobjname' from both active and
2952  * persistent configuration. The address object will be removed from only
2953  * active configuration if IPH_LEGACY is set in `iph->iph_flags'.
2954  *
2955  * If the address type is IPADM_ADDR_STATIC or IPADM_ADDR_DHCP, the address
2956  * in the address object will be removed from the physical interface.
2957  * If the address type is IPADM_ADDR_DHCP, the flag IPADM_OPT_RELEASE specifies
2958  * whether the lease should be released. If IPADM_OPT_RELEASE is not
2959  * specified, the lease will be dropped. This option is not supported
2960  * for other address types.
2961  *
2962  * If the address type is IPADM_ADDR_IPV6_ADDRCONF, the link-local address and
2963  * all the autoconfigured addresses will be removed.
2964  * Finally, the address object is also removed from ipmgmtd's aobjmap and from
2965  * the persistent DB.
2966  */
2967 ipadm_status_t
2968 ipadm_delete_addr(ipadm_handle_t iph, const char *aobjname, uint32_t flags)
2969 {
2970         ipadm_status_t          status;
2971         struct ipadm_addrobj_s  ipaddr;
2972         boolean_t               release = ((flags & IPADM_OPT_RELEASE) != 0);
2973 
2974         /* check for solaris.network.interface.config authorization */
2975         if (!ipadm_check_auth())
2976                 return (IPADM_EAUTH);
2977 
2978         /* validate input */
2979         if (flags == 0 || ((flags & IPADM_OPT_PERSIST) &&
2980             !(flags & IPADM_OPT_ACTIVE)) ||
2981             (flags & ~(IPADM_COMMON_OPT_MASK|IPADM_OPT_RELEASE))) {
2982                 return (IPADM_INVALID_ARG);
2983         }
2984         bzero(&ipaddr, sizeof (ipaddr));
2985         if (aobjname == NULL || strlcpy(ipaddr.ipadm_aobjname, aobjname,
2986             IPADM_AOBJSIZ) >= IPADM_AOBJSIZ) {
2987                 return (IPADM_INVALID_ARG);
2988         }
2989 
2990         /* Retrieve the address object information from ipmgmtd. */
2991         status = i_ipadm_get_addrobj(iph, &ipaddr);
2992         if (status != IPADM_SUCCESS)
2993                 return (status);
2994 
2995         if (release && ipaddr.ipadm_atype != IPADM_ADDR_DHCP)
2996                 return (IPADM_NOTSUP);
2997         /*
2998          * If requested to delete just from active config but the address
2999          * is not in active config, return error.
3000          */
3001         if (!(ipaddr.ipadm_flags & IPMGMT_ACTIVE) &&
3002             (flags & IPADM_OPT_ACTIVE) && !(flags & IPADM_OPT_PERSIST)) {
3003                 return (IPADM_NOTFOUND);
3004         }
3005 
3006         /*
3007          * If address is present in active config, remove it from
3008          * kernel.
3009          */
3010         if (ipaddr.ipadm_flags & IPMGMT_ACTIVE) {
3011                 switch (ipaddr.ipadm_atype) {
3012                 case IPADM_ADDR_STATIC:
3013                         status = i_ipadm_delete_addr(iph, &ipaddr);
3014                         break;
3015                 case IPADM_ADDR_DHCP:
3016                         status = i_ipadm_delete_dhcp(iph, &ipaddr, release);
3017                         break;
3018                 case IPADM_ADDR_IPV6_ADDRCONF:
3019                         status = i_ipadm_delete_ipv6addrs(iph, &ipaddr);
3020                         break;
3021                 default:
3022                         /*
3023                          * This is the case of address object name residing in
3024                          * daemon's aobjmap (added by ADDROBJ_LOOKUPADD). Fall
3025                          * through and delete that address object.
3026                          */
3027                         break;
3028                 }
3029 
3030                 /*
3031                  * If the address was previously deleted from the active
3032                  * config, we will get a IPADM_ENXIO from kernel.
3033                  * We will still proceed and purge the address information
3034                  * in the DB.
3035                  */
3036                 if (status == IPADM_ENXIO)
3037                         status = IPADM_SUCCESS;
3038                 else if (status != IPADM_SUCCESS)
3039                         return (status);
3040         }
3041 
3042         if (!(ipaddr.ipadm_flags & IPMGMT_PERSIST) &&
3043             (flags & IPADM_OPT_PERSIST)) {
3044                 flags &= ~IPADM_OPT_PERSIST;
3045         }
3046         status = i_ipadm_delete_addrobj(iph, &ipaddr, flags);
3047         if (status == IPADM_NOTFOUND)
3048                 return (status);
3049         return (IPADM_SUCCESS);
3050 }
3051 
3052 /*
3053  * Starts the dhcpagent and sends it the message DHCP_START to start
3054  * configuring a dhcp address on the given interface in `addr'.
3055  * After making the dhcpagent request, it also updates the
3056  * address object information in ipmgmtd's aobjmap and creates an
3057  * entry in persistent DB if IPADM_OPT_PERSIST is set in `flags'.
3058  */
3059 static ipadm_status_t
3060 i_ipadm_create_dhcp(ipadm_handle_t iph, ipadm_addrobj_t addr, uint32_t flags)
3061 {
3062         ipadm_status_t  status;
3063         ipadm_status_t  dh_status;
3064 
3065         if (dhcp_start_agent(DHCP_IPC_MAX_WAIT) == -1)
3066                 return (IPADM_DHCP_START_ERROR);
3067         /*
3068          * Create a new logical interface if needed; otherwise, just
3069          * use the 0th logical interface.
3070          */
3071 retry:
3072         status = i_ipadm_do_addif(iph, addr);
3073         if (status != IPADM_SUCCESS)
3074                 return (status);
3075         /*
3076          * We don't have to set the lifnum for IPH_INIT case, because
3077          * there is no placeholder created for the address object in this
3078          * case.
3079          */
3080         if (!(iph->iph_flags & IPH_INIT)) {
3081                 status = i_ipadm_setlifnum_addrobj(iph, addr);
3082                 if (status == IPADM_ADDROBJ_EXISTS)
3083                         goto retry;
3084                 if (status != IPADM_SUCCESS)
3085                         return (status);
3086         }
3087         /* Send DHCP_START to the dhcpagent. */
3088         status = i_ipadm_op_dhcp(addr, DHCP_START, NULL);
3089         /*
3090          * We do not undo the create-addr operation for IPADM_DHCP_IPC_TIMEOUT
3091          * since it is only a soft error to indicate the caller that the lease
3092          * might be required after the function returns.
3093          */
3094         if (status != IPADM_SUCCESS && status != IPADM_DHCP_IPC_TIMEOUT)
3095                 goto fail;
3096         dh_status = status;
3097 
3098         /* Persist the address object information in ipmgmtd. */
3099         status = i_ipadm_addr_persist(iph, addr, B_FALSE, flags, NULL);
3100         if (status != IPADM_SUCCESS)
3101                 goto fail;
3102 
3103         return (dh_status);
3104 fail:
3105         /* In case of error, delete the dhcp address */
3106         (void) i_ipadm_delete_dhcp(iph, addr, B_TRUE);
3107         return (status);
3108 }
3109 
3110 /*
3111  * Releases/drops the dhcp lease on the logical interface in the address
3112  * object `addr'. If `release' is set to B_FALSE, the lease will be dropped.
3113  */
3114 static ipadm_status_t
3115 i_ipadm_delete_dhcp(ipadm_handle_t iph, ipadm_addrobj_t addr, boolean_t release)
3116 {
3117         ipadm_status_t  status;
3118         int             dherr;
3119 
3120         /* Send DHCP_RELEASE or DHCP_DROP to the dhcpagent */
3121         if (release) {
3122                 status = i_ipadm_op_dhcp(addr, DHCP_RELEASE, &dherr);
3123                 /*
3124                  * If no lease was obtained on the object, we should
3125                  * drop the dhcp control on the interface.
3126                  */
3127                 if (status != IPADM_SUCCESS && dherr == DHCP_IPC_E_OUTSTATE)
3128                         status = i_ipadm_op_dhcp(addr, DHCP_DROP, NULL);
3129         } else {
3130                 status = i_ipadm_op_dhcp(addr, DHCP_DROP, NULL);
3131         }
3132         if (status != IPADM_SUCCESS)
3133                 return (status);
3134 
3135         /* Delete the logical interface */
3136         if (addr->ipadm_lifnum != 0) {
3137                 struct lifreq lifr;
3138 
3139                 bzero(&lifr, sizeof (lifr));
3140                 i_ipadm_addrobj2lifname(addr, lifr.lifr_name,
3141                     sizeof (lifr.lifr_name));
3142                 if (ioctl(iph->iph_sock, SIOCLIFREMOVEIF, (caddr_t)&lifr) < 0)
3143                         return (ipadm_errno2status(errno));
3144         }
3145 
3146         return (IPADM_SUCCESS);
3147 }
3148 
3149 /*
3150  * Communicates with the dhcpagent to send a dhcp message of type `type'.
3151  * It returns the dhcp error in `dhcperror' if a non-null pointer is provided
3152  * in `dhcperror'.
3153  */
3154 static ipadm_status_t
3155 i_ipadm_op_dhcp(ipadm_addrobj_t addr, dhcp_ipc_type_t type, int *dhcperror)
3156 {
3157         dhcp_ipc_request_t      *request;
3158         dhcp_ipc_reply_t        *reply  = NULL;
3159         dhcp_symbol_t           *entry = NULL;
3160         dhcp_data_type_t        dtype = DHCP_TYPE_NONE;
3161         void                            *d4o = NULL;
3162         uint16_t                        d4olen = 0;
3163         char                    ifname[LIFNAMSIZ];
3164         int                     error;
3165         int                     dhcp_timeout;
3166 
3167         /* Construct a message to the dhcpagent. */
3168         bzero(&ifname, sizeof (ifname));
3169         i_ipadm_addrobj2lifname(addr, ifname, sizeof (ifname));
3170         if (addr->ipadm_primary)
3171                 type |= DHCP_PRIMARY;
3172 
3173         /* Set up a CD_HOSTNAME option, if applicable, to send through IPC */
3174         switch (DHCP_IPC_CMD(type)) {
3175         case DHCP_START:
3176         case DHCP_EXTEND:
3177                 if (addr->ipadm_af == AF_INET && addr->ipadm_reqhost != NULL
3178                     && *addr->ipadm_reqhost != '\0')
3179                 {
3180                         entry = inittab_getbycode(ITAB_CAT_STANDARD, ITAB_CONS_INFO,
3181                             CD_HOSTNAME);
3182                         if (entry == NULL) {
3183                                 return (IPADM_FAILURE);
3184                         } else {
3185                                 d4o = inittab_encode(entry, addr->ipadm_reqhost, &d4olen,
3186                                     B_FALSE);
3187                                 free(entry);
3188                                 entry = NULL;
3189                                 if (d4o == NULL)
3190                                         return (IPADM_FAILURE);
3191                                 dtype = DHCP_TYPE_OPTION;
3192                         }
3193                 }
3194                 break;
3195         default:
3196                 break;
3197         }
3198 
3199         request = dhcp_ipc_alloc_request(type, ifname, d4o, d4olen, dtype);
3200         if (request == NULL) {
3201                 free(d4o);
3202                 return (IPADM_NO_MEMORY);
3203         }
3204 
3205         if (addr->ipadm_wait == IPADM_DHCP_WAIT_FOREVER)
3206                 dhcp_timeout = DHCP_IPC_WAIT_FOREVER;
3207         else if (addr->ipadm_wait == IPADM_DHCP_WAIT_DEFAULT)
3208                 dhcp_timeout = DHCP_IPC_WAIT_DEFAULT;
3209         else
3210                 dhcp_timeout = addr->ipadm_wait;
3211         /* Send the message to dhcpagent. */
3212         error = dhcp_ipc_make_request(request, &reply, dhcp_timeout);
3213         free(request);
3214         free(d4o);
3215         if (error == 0) {
3216                 error = reply->return_code;
3217                 free(reply);
3218         }
3219         if (error != 0) {
3220                 if (dhcperror != NULL)
3221                         *dhcperror = error;
3222                 if (error != DHCP_IPC_E_TIMEOUT)
3223                         return (IPADM_DHCP_IPC_ERROR);
3224                 else if (dhcp_timeout != 0)
3225                         return (IPADM_DHCP_IPC_TIMEOUT);
3226         }
3227 
3228         return (IPADM_SUCCESS);
3229 }
3230 
3231 /*
3232  * Returns the IP addresses of the specified interface in both the
3233  * active and the persistent configuration. If no
3234  * interface is specified, it returns all non-zero IP addresses
3235  * configured on all interfaces in active and persistent
3236  * configurations.
3237  * `addrinfo' will contain addresses that are
3238  * (1) in both active and persistent configuration (created persistently)
3239  * (2) only in active configuration (created temporarily)
3240  * (3) only in persistent configuration (disabled addresses)
3241  *
3242  * Address list that is returned by this function must be freed
3243  * using the ipadm_freeaddr_info() function.
3244  */
3245 ipadm_status_t
3246 ipadm_addr_info(ipadm_handle_t iph, const char *ifname,
3247     ipadm_addr_info_t **addrinfo, uint32_t flags, int64_t lifc_flags)
3248 {
3249         ifspec_t        ifsp;
3250 
3251         if (addrinfo == NULL || iph == NULL)
3252                 return (IPADM_INVALID_ARG);
3253         if (ifname != NULL &&
3254             (!ifparse_ifspec(ifname, &ifsp) || ifsp.ifsp_lunvalid)) {
3255                 return (IPADM_INVALID_ARG);
3256         }
3257         return (i_ipadm_get_all_addr_info(iph, ifname, addrinfo,
3258             flags, lifc_flags));
3259 }
3260 
3261 /*
3262  * Frees the structure allocated by ipadm_addr_info().
3263  */
3264 void
3265 ipadm_free_addr_info(ipadm_addr_info_t *ainfo)
3266 {
3267         freeifaddrs((struct ifaddrs *)ainfo);
3268 }
3269 
3270 /*
3271  * Makes a door call to ipmgmtd to update its `aobjmap' with the address
3272  * object in `ipaddr'. This door call also can update the persistent DB to
3273  * remember address object to be recreated on next reboot or on an
3274  * ipadm_enable_addr()/ipadm_enable_if() call.
3275  */
3276 ipadm_status_t
3277 i_ipadm_addr_persist(ipadm_handle_t iph, const ipadm_addrobj_t ipaddr,
3278     boolean_t default_prefixlen, uint32_t flags, const char *propname)
3279 {
3280         char                    *aname = ipaddr->ipadm_aobjname;
3281         nvlist_t                *nvl;
3282         int                     err = 0;
3283         ipadm_status_t          status;
3284         uint_t                  pflags = 0;
3285 
3286         /*
3287          * Construct the nvl to send to the door.
3288          */
3289         if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
3290                 return (IPADM_NO_MEMORY);
3291         if ((err = nvlist_add_string(nvl, IPADM_NVP_IFNAME,
3292             ipaddr->ipadm_ifname)) != 0 ||
3293             (err = nvlist_add_string(nvl, IPADM_NVP_AOBJNAME, aname)) != 0 ||
3294             (err = nvlist_add_int32(nvl, IPADM_NVP_LIFNUM,
3295             ipaddr->ipadm_lifnum)) != 0) {
3296                 status = ipadm_errno2status(err);
3297                 goto ret;
3298         }
3299         switch (ipaddr->ipadm_atype) {
3300         case IPADM_ADDR_STATIC:
3301                 status = i_ipadm_add_ipaddr2nvl(nvl, ipaddr);
3302                 if (status != IPADM_SUCCESS)
3303                         goto ret;
3304                 if (flags & IPADM_OPT_UP)
3305                         err = nvlist_add_string(nvl, "up", "yes");
3306                 else
3307                         err = nvlist_add_string(nvl, "up", "no");
3308                 status = ipadm_errno2status(err);
3309                 break;
3310         case IPADM_ADDR_DHCP:
3311                 status = i_ipadm_add_dhcp2nvl(nvl, ipaddr->ipadm_primary,
3312                     ipaddr->ipadm_wait);
3313                 if (status != IPADM_SUCCESS)
3314                         goto ret;
3315 
3316                 /*
3317                  * For purposes of updating the ipmgmtd cached representation of
3318                  * reqhost (ipmgmt_am_reqhost), include a value here in `nvl', but
3319                  * the value is actually fully persisted as a separate
3320                  * i_ipadm_persist_propval below.
3321                  */
3322                 err = nvlist_add_string(nvl, IPADM_NVP_REQHOST,
3323                     ipaddr->ipadm_reqhost);
3324                 status = ipadm_errno2status(err);
3325                 break;
3326         case IPADM_ADDR_IPV6_ADDRCONF:
3327                 status = i_ipadm_add_intfid2nvl(nvl, ipaddr);
3328                 break;
3329         }
3330         if (status != IPADM_SUCCESS)
3331                 goto ret;
3332 
3333         if (iph->iph_flags & IPH_INIT) {
3334                 /*
3335                  * IPMGMT_INIT tells the ipmgmtd to set both IPMGMT_ACTIVE and
3336                  * IPMGMT_PERSIST on the address object in its `aobjmap'.
3337                  * For the callers ipadm_enable_if() and ipadm_enable_addr(),
3338                  * IPADM_OPT_PERSIST is not set in their flags. They send
3339                  * IPH_INIT in iph_flags, so that the address object will be
3340                  * set as both IPMGMT_ACTIVE and IPMGMT_PERSIST.
3341                  */
3342                 pflags |= IPMGMT_INIT;
3343         } else {
3344                 if (flags & IPADM_OPT_ACTIVE)
3345                         pflags |= IPMGMT_ACTIVE;
3346                 if (flags & IPADM_OPT_PERSIST)
3347                         pflags |= IPMGMT_PERSIST;
3348                 if (flags & IPADM_OPT_SET_PROPS)
3349                         pflags |= IPMGMT_PROPS_ONLY;
3350         }
3351         status = i_ipadm_addr_persist_nvl(iph, nvl, pflags);
3352 
3353         if (flags & IPADM_OPT_SET_PROPS) {
3354                 /*
3355                  * Set PERSIST per IPADM_OPT_PROPS_PERSIST, and then un-set the
3356                  * SET_PROPS bits.
3357                  */
3358                 flags |= IPADM_OPT_ACTIVE;
3359                 if (flags & IPADM_OPT_PERSIST_PROPS)
3360                         flags |= IPADM_OPT_PERSIST;
3361                 else
3362                         flags &= ~IPADM_OPT_PERSIST;
3363                 flags &= ~(IPADM_OPT_SET_PROPS | IPADM_OPT_PERSIST_PROPS);
3364         }
3365 
3366         if (status == IPADM_SUCCESS && (flags & IPADM_OPT_PERSIST)) {
3367                 char    pbuf[MAXPROPVALLEN], *pval = NULL;
3368                 ipadm_prop_desc_t       *pdp = NULL;
3369 
3370                 /*
3371                  * addprop properties are stored on separate lines in the DB and
3372                  * not along with the address itself. Call the function that
3373                  * persists address properties.
3374                  */
3375 
3376                 switch (ipaddr->ipadm_atype) {
3377                 case IPADM_ADDR_STATIC:
3378                         if (!default_prefixlen && (propname == NULL ||
3379                             strcmp(propname, IPADM_NVP_PREFIXLEN) == 0)) {
3380                                 pdp = i_ipadm_get_addrprop_desc(IPADM_NVP_PREFIXLEN);
3381                                 (void) snprintf(pbuf, sizeof (pbuf), "%u",
3382                                     ipaddr->ipadm_static_prefixlen);
3383                                 pval = pbuf;
3384                         }
3385                         break;
3386                 case IPADM_ADDR_DHCP:
3387                         if (propname == NULL ||
3388                             strcmp(propname, IPADM_NVP_REQHOST) == 0) {
3389                                 pdp = i_ipadm_get_addrprop_desc(IPADM_NVP_REQHOST);
3390                                 pval = ipaddr->ipadm_reqhost;
3391                         }
3392                         break;
3393                 default:
3394                         break;
3395                 }
3396 
3397                 if (pval != NULL) {
3398                         assert(pdp != NULL);
3399                         status = i_ipadm_persist_propval(iph, pdp, pval,
3400                                 ipaddr, flags);
3401                 }
3402         }
3403 
3404 ret:
3405         nvlist_free(nvl);
3406         return (status);
3407 }
3408 
3409 /*
3410  * Makes the door call to ipmgmtd to store the address object in the
3411  * nvlist `nvl'.
3412  */
3413 static ipadm_status_t
3414 i_ipadm_addr_persist_nvl(ipadm_handle_t iph, nvlist_t *nvl, uint32_t flags)
3415 {
3416         char                    *buf = NULL, *nvlbuf = NULL;
3417         size_t                  nvlsize, bufsize;
3418         ipmgmt_setaddr_arg_t    *sargp;
3419         int                     err;
3420 
3421         err = nvlist_pack(nvl, &nvlbuf, &nvlsize, NV_ENCODE_NATIVE, 0);
3422         if (err != 0)
3423                 return (ipadm_errno2status(err));
3424         bufsize = sizeof (*sargp) + nvlsize;
3425         buf = calloc(1, bufsize);
3426         sargp = (void *)buf;
3427         sargp->ia_cmd = IPMGMT_CMD_SETADDR;
3428         sargp->ia_flags = flags;
3429         sargp->ia_nvlsize = nvlsize;
3430         (void) bcopy(nvlbuf, buf + sizeof (*sargp), nvlsize);
3431         err = ipadm_door_call(iph, buf, bufsize, NULL, 0, B_FALSE);
3432         free(buf);
3433         free(nvlbuf);
3434         return (ipadm_errno2status(err));
3435 }
3436 
3437 /*
3438  * Makes a door call to ipmgmtd to remove the address object in `ipaddr'
3439  * from its `aobjmap'. This door call also removes the address object and all
3440  * its properties from the persistent DB if IPADM_OPT_PERSIST is set in
3441  * `flags', so that the object will not be recreated on next reboot or on an
3442  * ipadm_enable_addr()/ipadm_enable_if() call.
3443  */
3444 ipadm_status_t
3445 i_ipadm_delete_addrobj(ipadm_handle_t iph, const ipadm_addrobj_t ipaddr,
3446     uint32_t flags)
3447 {
3448         ipmgmt_addr_arg_t       arg;
3449         int                     err;
3450 
3451         arg.ia_cmd = IPMGMT_CMD_RESETADDR;
3452         arg.ia_flags = 0;
3453         if (flags & IPADM_OPT_ACTIVE)
3454                 arg.ia_flags |= IPMGMT_ACTIVE;
3455         if (flags & IPADM_OPT_PERSIST)
3456                 arg.ia_flags |= IPMGMT_PERSIST;
3457         (void) strlcpy(arg.ia_aobjname, ipaddr->ipadm_aobjname,
3458             sizeof (arg.ia_aobjname));
3459         arg.ia_lnum = ipaddr->ipadm_lifnum;
3460         err = ipadm_door_call(iph, &arg, sizeof (arg), NULL, 0, B_FALSE);
3461         return (ipadm_errno2status(err));
3462 }
3463 
3464 /*
3465  * Checks if the caller is authorized for the up/down operation.
3466  * Retrieves the address object corresponding to `aobjname' from ipmgmtd
3467  * and retrieves the address flags for that object from kernel.
3468  * The arguments `ipaddr' and `ifflags' must be allocated by the caller.
3469  */
3470 static ipadm_status_t
3471 i_ipadm_updown_common(ipadm_handle_t iph, const char *aobjname,
3472     ipadm_addrobj_t ipaddr, uint32_t ipadm_flags, uint64_t *ifflags)
3473 {
3474         ipadm_status_t  status;
3475         char            lifname[LIFNAMSIZ];
3476 
3477         /* check for solaris.network.interface.config authorization */
3478         if (!ipadm_check_auth())
3479                 return (IPADM_EAUTH);
3480 
3481         /* validate input */
3482         if (aobjname == NULL || strlcpy(ipaddr->ipadm_aobjname, aobjname,
3483             IPADM_AOBJSIZ) >= IPADM_AOBJSIZ) {
3484                 return (IPADM_INVALID_ARG);
3485         }
3486 
3487         /* Retrieve the address object information. */
3488         status = i_ipadm_get_addrobj(iph, ipaddr);
3489         if (status != IPADM_SUCCESS)
3490                 return (status);
3491 
3492         if (!(ipaddr->ipadm_flags & IPMGMT_ACTIVE))
3493                 return (IPADM_OP_DISABLE_OBJ);
3494         if ((ipadm_flags & IPADM_OPT_PERSIST) &&
3495             !(ipaddr->ipadm_flags & IPMGMT_PERSIST))
3496                 return (IPADM_TEMPORARY_OBJ);
3497         if (ipaddr->ipadm_atype == IPADM_ADDR_IPV6_ADDRCONF ||
3498             (ipaddr->ipadm_atype == IPADM_ADDR_DHCP &&
3499             (ipadm_flags & IPADM_OPT_PERSIST)))
3500                 return (IPADM_NOTSUP);
3501 
3502         i_ipadm_addrobj2lifname(ipaddr, lifname, sizeof (lifname));
3503         return (i_ipadm_get_flags(iph, lifname, ipaddr->ipadm_af, ifflags));
3504 }
3505 
3506 /*
3507  * Marks the address in the address object `aobjname' up. This operation is
3508  * not supported for an address object of type IPADM_ADDR_IPV6_ADDRCONF.
3509  * For an address object of type IPADM_ADDR_DHCP, this operation can
3510  * only be temporary and no updates will be made to the persistent DB.
3511  */
3512 ipadm_status_t
3513 ipadm_up_addr(ipadm_handle_t iph, const char *aobjname, uint32_t ipadm_flags)
3514 {
3515         struct ipadm_addrobj_s ipaddr;
3516         ipadm_status_t  status;
3517         uint64_t        flags;
3518         char            lifname[LIFNAMSIZ];
3519 
3520         status = i_ipadm_updown_common(iph, aobjname, &ipaddr, ipadm_flags,
3521             &flags);
3522         if (status != IPADM_SUCCESS)
3523                 return (status);
3524         if (flags & IFF_UP)
3525                 goto persist;
3526         /*
3527          * If the address is already a duplicate, then refresh-addr
3528          * should be used to mark it up.
3529          */
3530         if (flags & IFF_DUPLICATE)
3531                 return (IPADM_DAD_FOUND);
3532 
3533         i_ipadm_addrobj2lifname(&ipaddr, lifname, sizeof (lifname));
3534         status = i_ipadm_set_flags(iph, lifname, ipaddr.ipadm_af, IFF_UP, 0);
3535         if (status != IPADM_SUCCESS)
3536                 return (status);
3537 
3538 persist:
3539         /* Update persistent DB. */
3540         if (ipadm_flags & IPADM_OPT_PERSIST) {
3541                 status = i_ipadm_persist_propval(iph, &up_addrprop,
3542                     "yes", &ipaddr, 0);
3543         }
3544 
3545         return (status);
3546 }
3547 
3548 /*
3549  * Marks the address in the address object `aobjname' down. This operation is
3550  * not supported for an address object of type IPADM_ADDR_IPV6_ADDRCONF.
3551  * For an address object of type IPADM_ADDR_DHCP, this operation can
3552  * only be temporary and no updates will be made to the persistent DB.
3553  */
3554 ipadm_status_t
3555 ipadm_down_addr(ipadm_handle_t iph, const char *aobjname, uint32_t ipadm_flags)
3556 {
3557         struct ipadm_addrobj_s ipaddr;
3558         ipadm_status_t  status;
3559         struct lifreq   lifr;
3560         uint64_t        flags;
3561 
3562         status = i_ipadm_updown_common(iph, aobjname, &ipaddr, ipadm_flags,
3563             &flags);
3564         if (status != IPADM_SUCCESS)
3565                 return (status);
3566         i_ipadm_addrobj2lifname(&ipaddr, lifr.lifr_name,
3567             sizeof (lifr.lifr_name));
3568         if (flags & IFF_UP) {
3569                 status = i_ipadm_set_flags(iph, lifr.lifr_name,
3570                     ipaddr.ipadm_af, 0, IFF_UP);
3571                 if (status != IPADM_SUCCESS)
3572                         return (status);
3573         } else if (flags & IFF_DUPLICATE) {
3574                 /*
3575                  * Clear the IFF_DUPLICATE flag.
3576                  */
3577                 if (ioctl(iph->iph_sock, SIOCGLIFADDR, &lifr) < 0)
3578                         return (ipadm_errno2status(errno));
3579                 if (ioctl(iph->iph_sock, SIOCSLIFADDR, &lifr) < 0)
3580                         return (ipadm_errno2status(errno));
3581         }
3582 
3583         /* Update persistent DB */
3584         if (ipadm_flags & IPADM_OPT_PERSIST) {
3585                 status = i_ipadm_persist_propval(iph, &up_addrprop,
3586                     "no", &ipaddr, 0);
3587         }
3588 
3589         return (status);
3590 }
3591 
3592 /*
3593  * Refreshes the address in the address object `aobjname'. If the address object
3594  * is of type IPADM_ADDR_STATIC, DAD is re-initiated on the address. If
3595  * `ipadm_flags' has IPADM_OPT_INFORM set, a DHCP_INFORM message is sent to the
3596  * dhcpagent for this static address. If the address object is of type
3597  * IPADM_ADDR_DHCP, a DHCP_EXTEND message is sent to the dhcpagent.
3598  * If a dhcp address has not yet been acquired, a DHCP_START is sent to the
3599  * dhcpagent. This operation is not supported for an address object of
3600  * type IPADM_ADDR_IPV6_ADDRCONF.
3601  */
3602 ipadm_status_t
3603 ipadm_refresh_addr(ipadm_handle_t iph, const char *aobjname,
3604     uint32_t ipadm_flags)
3605 {
3606         ipadm_status_t          status = IPADM_SUCCESS;
3607         uint64_t                flags;
3608         struct ipadm_addrobj_s  ipaddr;
3609         sa_family_t             af;
3610         char                    lifname[LIFNAMSIZ];
3611         boolean_t               inform =
3612             ((ipadm_flags & IPADM_OPT_INFORM) != 0);
3613 
3614         /* check for solaris.network.interface.config authorization */
3615         if (!ipadm_check_auth())
3616                 return (IPADM_EAUTH);
3617 
3618         bzero(&ipaddr, sizeof (ipaddr));
3619         /* validate input */
3620         if (aobjname == NULL || strlcpy(ipaddr.ipadm_aobjname, aobjname,
3621             IPADM_AOBJSIZ) >= IPADM_AOBJSIZ) {
3622                 return (IPADM_INVALID_ARG);
3623         }
3624 
3625         /* Retrieve the address object information. */
3626         status = i_ipadm_get_addrobj(iph, &ipaddr);
3627         if (status != IPADM_SUCCESS)
3628                 return (status);
3629 
3630         if (!(ipaddr.ipadm_flags & IPMGMT_ACTIVE))
3631                 return (IPADM_OP_DISABLE_OBJ);
3632 
3633         if (i_ipadm_is_vni(ipaddr.ipadm_ifname))
3634                 return (IPADM_NOTSUP);
3635         if (inform && ipaddr.ipadm_atype != IPADM_ADDR_STATIC)
3636                 return (IPADM_INVALID_ARG);
3637         af = ipaddr.ipadm_af;
3638         if (ipaddr.ipadm_atype == IPADM_ADDR_STATIC) {
3639                 i_ipadm_addrobj2lifname(&ipaddr, lifname, sizeof (lifname));
3640                 status = i_ipadm_get_flags(iph, lifname, af, &flags);
3641                 if (status != IPADM_SUCCESS)
3642                         return (status);
3643                 if (inform) {
3644                         if (dhcp_start_agent(DHCP_IPC_MAX_WAIT) == -1)
3645                                 return (IPADM_DHCP_START_ERROR);
3646 
3647                         ipaddr.ipadm_wait = IPADM_DHCP_WAIT_DEFAULT;
3648                         return (i_ipadm_op_dhcp(&ipaddr, DHCP_INFORM, NULL));
3649                 }
3650                 if (!(flags & IFF_DUPLICATE))
3651                         return (IPADM_SUCCESS);
3652                 status = i_ipadm_set_flags(iph, lifname, af, IFF_UP, 0);
3653         } else if (ipaddr.ipadm_atype == IPADM_ADDR_DHCP) {
3654                 status = i_ipadm_refresh_dhcp(&ipaddr);
3655         } else {
3656                 status = IPADM_NOTSUP;
3657         }
3658         return (status);
3659 }
3660 
3661 /*
3662  * This is called from ipadm_refresh_addr() and i_ipadm_set_reqhost() to
3663  * send a DHCP_EXTEND message and possibly a DHCP_START message
3664  * to the dhcpagent.
3665  */
3666 static ipadm_status_t
3667 i_ipadm_refresh_dhcp(ipadm_addrobj_t ipaddr)
3668 {
3669         ipadm_status_t          status;
3670         int                     dherr;
3671 
3672         status = i_ipadm_op_dhcp(ipaddr, DHCP_EXTEND, &dherr);
3673         /*
3674          * Restart the dhcp address negotiation with server if no
3675          * address has been acquired yet.
3676          */
3677         if (status != IPADM_SUCCESS && dherr == DHCP_IPC_E_OUTSTATE) {
3678                 ipaddr->ipadm_wait = IPADM_DHCP_WAIT_DEFAULT;
3679                 status = i_ipadm_op_dhcp(ipaddr, DHCP_START, NULL);
3680         }
3681 
3682         return (status);
3683 }
3684 
3685 /*
3686  * This is called from ipadm_create_addr() to validate the address parameters.
3687  * It does the following steps:
3688  * 1. Validates the interface name.
3689  * 2. Verifies that the interface is not an IPMP meta-interface or an
3690  *      underlying interface.
3691  * 3. In case of a persistent operation, verifies that the interface
3692  *      is persistent. Returns error if interface is not enabled but
3693  *      is in persistent config.
3694  * 4. Verifies that the destination address is not set or the address type is
3695  *      not DHCP or ADDRCONF when the interface is a loopback interface.
3696  * 5. Verifies that the address type is not DHCP or ADDRCONF when the interface
3697  *      has IFF_VRRP interface flag set.
3698  */
3699 static ipadm_status_t
3700 i_ipadm_validate_create_addr(ipadm_handle_t iph, ipadm_addrobj_t ipaddr,
3701     uint32_t flags)
3702 {
3703         sa_family_t             af;
3704         sa_family_t             other_af;
3705         char                    *ifname;
3706         ipadm_status_t          status;
3707         boolean_t               legacy = (iph->iph_flags & IPH_LEGACY);
3708         boolean_t               islo, isvni;
3709         uint64_t                ifflags = 0;
3710         boolean_t               p_exists;
3711         boolean_t               af_exists, other_af_exists, a_exists;
3712 
3713         if (ipaddr == NULL || flags == 0 || flags == IPADM_OPT_PERSIST ||
3714             (flags & ~(IPADM_COMMON_OPT_MASK|IPADM_OPT_UP|IPADM_OPT_V46))) {
3715                 return (IPADM_INVALID_ARG);
3716         }
3717 
3718         if (ipaddr->ipadm_af == AF_UNSPEC)
3719                 return (IPADM_BAD_ADDR);
3720 
3721         if (!legacy && ipaddr->ipadm_lifnum != 0)
3722                 return (IPADM_INVALID_ARG);
3723 
3724         if (legacy && ipaddr->ipadm_atype != IPADM_ADDR_STATIC)
3725                 return (IPADM_NOTSUP);
3726 
3727         ifname = ipaddr->ipadm_ifname;
3728 
3729         if (i_ipadm_is_ipmp(iph, ifname) || i_ipadm_is_under_ipmp(iph, ifname))
3730                 return (IPADM_NOTSUP);
3731 
3732         af = ipaddr->ipadm_af;
3733         af_exists = ipadm_if_enabled(iph, ifname, af);
3734         /*
3735          * For legacy case, interfaces are not implicitly plumbed. We need to
3736          * check if the interface exists in the active configuration.
3737          */
3738         if (legacy && !af_exists)
3739                 return (IPADM_ENXIO);
3740 
3741         other_af = (af == AF_INET ? AF_INET6 : AF_INET);
3742         other_af_exists = ipadm_if_enabled(iph, ifname, other_af);
3743         /*
3744          * Check if one of the v4 or the v6 interfaces exists in the
3745          * active configuration. An interface is considered disabled only
3746          * if both v4 and v6 are not active.
3747          */
3748         a_exists = (af_exists || other_af_exists);
3749 
3750         /* Check if interface exists in the persistent configuration. */
3751         status = i_ipadm_if_pexists(iph, ifname, af, &p_exists);
3752         if (status != IPADM_SUCCESS)
3753                 return (status);
3754         if (!a_exists && p_exists)
3755                 return (IPADM_OP_DISABLE_OBJ);
3756         if ((flags & IPADM_OPT_PERSIST) && a_exists && !p_exists) {
3757                 /*
3758                  * If address has to be created persistently,
3759                  * and the interface does not exist in the persistent
3760                  * store but in active config, fail.
3761                  */
3762                 return (IPADM_TEMPORARY_OBJ);
3763         }
3764         if (af_exists) {
3765                 status = i_ipadm_get_flags(iph, ifname, af, &ifflags);
3766                 if (status != IPADM_SUCCESS)
3767                         return (status);
3768         }
3769 
3770         /* Perform validation steps (4) and (5) */
3771         islo = i_ipadm_is_loopback(ifname);
3772         isvni = i_ipadm_is_vni(ifname);
3773         switch (ipaddr->ipadm_atype) {
3774         case IPADM_ADDR_STATIC:
3775                 if ((islo || isvni) && ipaddr->ipadm_static_dname[0] != '\0')
3776                         return (IPADM_INVALID_ARG);
3777                 /* Check for a valid src address */
3778                 if (!legacy && sockaddrunspec(
3779                     (struct sockaddr *)&ipaddr->ipadm_static_addr))
3780                         return (IPADM_BAD_ADDR);
3781                 break;
3782         case IPADM_ADDR_DHCP:
3783                 if (islo || (ifflags & IFF_VRRP))
3784                         return (IPADM_NOTSUP);
3785                 break;
3786         case IPADM_ADDR_IPV6_ADDRCONF:
3787                 if (islo || (ifflags & IFF_VRRP) ||
3788                     i_ipadm_is_6to4(iph, ifname)) {
3789                         return (IPADM_NOTSUP);
3790                 }
3791                 break;
3792         default:
3793                 return (IPADM_INVALID_ARG);
3794         }
3795 
3796         return (IPADM_SUCCESS);
3797 }
3798 
3799 ipadm_status_t
3800 i_ipadm_merge_addrprops_from_nvl(nvlist_t *invl, nvlist_t *onvl,
3801     const char *aobjname)
3802 {
3803         const char * const      ADDRPROPS[] =
3804             { IPADM_NVP_PREFIXLEN, IPADM_NVP_REQHOST };
3805         const size_t            ADDRPROPSLEN =
3806             sizeof (ADDRPROPS) / sizeof (*ADDRPROPS);
3807         nvpair_t        *nvp, *propnvp;
3808         nvlist_t        *tnvl;
3809         char            *aname;
3810         const char      *propname;
3811         size_t          i;
3812         int             err;
3813 
3814         for (i = 0; i < ADDRPROPSLEN; ++i) {
3815                 propname = ADDRPROPS[i];
3816 
3817                 for (nvp = nvlist_next_nvpair(invl, NULL); nvp != NULL;
3818                         nvp = nvlist_next_nvpair(invl, nvp)) {
3819                         if (nvpair_value_nvlist(nvp, &tnvl) == 0 &&
3820                             nvlist_exists(tnvl, propname) &&
3821                             nvlist_lookup_string(tnvl, IPADM_NVP_AOBJNAME,
3822                             &aname) == 0 && strcmp(aname, aobjname) == 0) {
3823 
3824                                 /* property named `propname' exists for given aobj */
3825                                 (void) nvlist_lookup_nvpair(tnvl, propname, &propnvp);
3826                                 err = nvlist_add_nvpair(onvl, propnvp);
3827                                 if (err == 0) {
3828                                         err = nvlist_remove(invl, nvpair_name(nvp),
3829                                             nvpair_type(nvp));
3830                                 }
3831                                 if (err != 0)
3832                                         return (ipadm_errno2status(err));
3833                                 break;
3834                         }
3835                 }
3836         }
3837         return (IPADM_SUCCESS);
3838 }
3839 
3840 /*
3841  * Re-enables the address object `aobjname' based on the saved
3842  * configuration for `aobjname'.
3843  */
3844 ipadm_status_t
3845 ipadm_enable_addr(ipadm_handle_t iph, const char *aobjname, uint32_t flags)
3846 {
3847         nvlist_t        *addrnvl, *nvl;
3848         nvpair_t        *nvp;
3849         ipadm_status_t  status;
3850         struct ipadm_addrobj_s ipaddr;
3851 
3852         /* check for solaris.network.interface.config authorization */
3853         if (!ipadm_check_auth())
3854                 return (IPADM_EAUTH);
3855 
3856         /* validate input */
3857         if (flags & IPADM_OPT_PERSIST)
3858                 return (IPADM_NOTSUP);
3859         if (aobjname == NULL || strlcpy(ipaddr.ipadm_aobjname, aobjname,
3860             IPADM_AOBJSIZ) >= IPADM_AOBJSIZ) {
3861                 return (IPADM_INVALID_ARG);
3862         }
3863 
3864         /* Retrieve the address object information. */
3865         status = i_ipadm_get_addrobj(iph, &ipaddr);
3866         if (status != IPADM_SUCCESS)
3867                 return (status);
3868         if (ipaddr.ipadm_flags & IPMGMT_ACTIVE)
3869                 return (IPADM_ADDROBJ_EXISTS);
3870 
3871         status = i_ipadm_get_db_addr(iph, NULL, aobjname, &addrnvl);
3872         if (status != IPADM_SUCCESS)
3873                 return (status);
3874 
3875         assert(addrnvl != NULL);
3876 
3877         for (nvp = nvlist_next_nvpair(addrnvl, NULL); nvp != NULL;
3878             nvp = nvlist_next_nvpair(addrnvl, nvp)) {
3879                 if (nvpair_value_nvlist(nvp, &nvl) != 0)
3880                         continue;
3881 
3882                 if (nvlist_exists(nvl, IPADM_NVP_IPV4ADDR) ||
3883                     nvlist_exists(nvl, IPADM_NVP_IPV6ADDR) ||
3884                     nvlist_exists(nvl, IPADM_NVP_DHCP)) {
3885                         status = i_ipadm_merge_addrprops_from_nvl(addrnvl, nvl,
3886                             aobjname);
3887                         if (status != IPADM_SUCCESS)
3888                                 continue;
3889                 }
3890                 iph->iph_flags |= IPH_INIT;
3891                 status = i_ipadm_init_addrobj(iph, nvl);
3892                 iph->iph_flags &= ~IPH_INIT;
3893                 if (status != IPADM_SUCCESS)
3894                         break;
3895         }
3896 
3897         return (status);
3898 }
3899 
3900 /*
3901  * Disables the address object in `aobjname' from the active configuration.
3902  * Error code return values follow the model in ipadm_delete_addr().
3903  */
3904 ipadm_status_t
3905 ipadm_disable_addr(ipadm_handle_t iph, const char *aobjname, uint32_t flags)
3906 {
3907         /* validate input */
3908         if (flags & IPADM_OPT_PERSIST)
3909                 return (IPADM_NOTSUP);
3910 
3911         return (ipadm_delete_addr(iph, aobjname, IPADM_OPT_ACTIVE));
3912 }