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