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