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