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