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