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 2013 Nexenta Systems, Inc. All rights reserved.
  24  */
  25 
  26 #include <stdio.h>
  27 #include <stdlib.h>
  28 #include <string.h>
  29 #include <errno.h>
  30 #include <fcntl.h>
  31 #include <unistd.h>
  32 #include <stropts.h>
  33 #include <sys/sockio.h>
  34 #include <sys/types.h>
  35 #include <sys/stat.h>
  36 #include <sys/socket.h>
  37 #include <net/route.h>
  38 #include <netinet/in.h>
  39 #include <inet/ip.h>
  40 #include <arpa/inet.h>
  41 #include <libintl.h>
  42 #include <libdlpi.h>
  43 #include <libinetutil.h>
  44 #include <libdladm.h>
  45 #include <libdllink.h>
  46 #include <libdliptun.h>
  47 #include <strings.h>
  48 #include <zone.h>
  49 #include <ctype.h>
  50 #include <limits.h>
  51 #include <assert.h>
  52 #include <netdb.h>
  53 #include <pwd.h>
  54 #include <auth_attr.h>
  55 #include <secdb.h>
  56 #include <nss_dbdefs.h>
  57 #include "libipadm_impl.h"
  58 
  59 /* error codes and text description */
  60 static struct ipadm_error_info {
  61         ipadm_status_t  error_code;
  62         const char      *error_desc;
  63 } ipadm_errors[] = {
  64         { IPADM_SUCCESS,        "Operation succeeded" },
  65         { IPADM_FAILURE,        "Operation failed" },
  66         { IPADM_EAUTH,          "Insufficient user authorizations" },
  67         { IPADM_EPERM,          "Permission denied" },
  68         { IPADM_NO_BUFS,        "No buffer space available" },
  69         { IPADM_NO_MEMORY,      "Insufficient memory" },
  70         { IPADM_BAD_ADDR,       "Invalid address" },
  71         { IPADM_BAD_PROTOCOL,   "Incorrect protocol family for operation" },
  72         { IPADM_DAD_FOUND,      "Duplicate address detected" },
  73         { IPADM_EXISTS,         "Already exists" },
  74         { IPADM_IF_EXISTS,      "Interface already exists" },
  75         { IPADM_ADDROBJ_EXISTS, "Address object already exists" },
  76         { IPADM_ADDRCONF_EXISTS, "Addrconf already in progress" },
  77         { IPADM_ENXIO,          "Interface does not exist" },
  78         { IPADM_GRP_NOTEMPTY,   "IPMP group is not empty" },
  79         { IPADM_INVALID_ARG,    "Invalid argument provided" },
  80         { IPADM_INVALID_NAME,   "Invalid name" },
  81         { IPADM_DLPI_FAILURE,   "Could not open DLPI link" },
  82         { IPADM_DLADM_FAILURE,  "Datalink does not exist" },
  83         { IPADM_PROP_UNKNOWN,   "Unknown property" },
  84         { IPADM_ERANGE,         "Value is outside the allowed range" },
  85         { IPADM_ESRCH,          "Value does not exist" },
  86         { IPADM_EOVERFLOW,      "Number of values exceeds the allowed limit" },
  87         { IPADM_NOTFOUND,       "Object not found" },
  88         { IPADM_IF_INUSE,       "Interface already in use" },
  89         { IPADM_ADDR_INUSE,     "Address already in use" },
  90         { IPADM_BAD_HOSTNAME,   "Hostname maps to multiple IP addresses" },
  91         { IPADM_ADDR_NOTAVAIL,  "Can't assign requested address" },
  92         { IPADM_ALL_ADDRS_NOT_ENABLED, "All addresses could not be enabled" },
  93         { IPADM_NDPD_NOT_RUNNING, "IPv6 autoconf daemon in.ndpd not running" },
  94         { IPADM_DHCP_START_ERROR, "Could not start dhcpagent" },
  95         { IPADM_DHCP_IPC_ERROR, "Could not communicate with dhcpagent" },
  96         { IPADM_DHCP_IPC_TIMEOUT, "Communication with dhcpagent timed out" },
  97         { IPADM_TEMPORARY_OBJ,  "Persistent operation on temporary object" },
  98         { IPADM_IPC_ERROR,      "Could not communicate with ipmgmtd" },
  99         { IPADM_NOTSUP,         "Operation not supported" },
 100         { IPADM_OP_DISABLE_OBJ, "Operation not supported on disabled object" },
 101         { IPADM_EBADE,          "Invalid data exchange with daemon" },
 102         { IPADM_GZ_PERM,        "Operation not permitted on from-gz interface"}
 103 };
 104 
 105 #define IPADM_NUM_ERRORS        (sizeof (ipadm_errors) / sizeof (*ipadm_errors))
 106 
 107 ipadm_status_t
 108 ipadm_errno2status(int error)
 109 {
 110         switch (error) {
 111         case 0:
 112                 return (IPADM_SUCCESS);
 113         case ENXIO:
 114                 return (IPADM_ENXIO);
 115         case ENOMEM:
 116                 return (IPADM_NO_MEMORY);
 117         case ENOBUFS:
 118                 return (IPADM_NO_BUFS);
 119         case EINVAL:
 120                 return (IPADM_INVALID_ARG);
 121         case EBUSY:
 122                 return (IPADM_IF_INUSE);
 123         case EEXIST:
 124                 return (IPADM_EXISTS);
 125         case EADDRNOTAVAIL:
 126                 return (IPADM_ADDR_NOTAVAIL);
 127         case EADDRINUSE:
 128                 return (IPADM_ADDR_INUSE);
 129         case ENOENT:
 130                 return (IPADM_NOTFOUND);
 131         case ERANGE:
 132                 return (IPADM_ERANGE);
 133         case EPERM:
 134                 return (IPADM_EPERM);
 135         case ENOTSUP:
 136         case EOPNOTSUPP:
 137                 return (IPADM_NOTSUP);
 138         case EBADF:
 139                 return (IPADM_IPC_ERROR);
 140         case EBADE:
 141                 return (IPADM_EBADE);
 142         case ESRCH:
 143                 return (IPADM_ESRCH);
 144         case EOVERFLOW:
 145                 return (IPADM_EOVERFLOW);
 146         default:
 147                 return (IPADM_FAILURE);
 148         }
 149 }
 150 
 151 /*
 152  * Returns a message string for the given libipadm error status.
 153  */
 154 const char *
 155 ipadm_status2str(ipadm_status_t status)
 156 {
 157         int     i;
 158 
 159         for (i = 0; i < IPADM_NUM_ERRORS; i++) {
 160                 if (status == ipadm_errors[i].error_code)
 161                         return (dgettext(TEXT_DOMAIN,
 162                             ipadm_errors[i].error_desc));
 163         }
 164 
 165         return (dgettext(TEXT_DOMAIN, "<unknown error>"));
 166 }
 167 
 168 /*
 169  * Opens a handle to libipadm.
 170  * Possible values for flags:
 171  *  IPH_VRRP:   Used by VRRP daemon to set the socket option SO_VRRP.
 172  *  IPH_LEGACY: This is used whenever an application needs to provide a
 173  *              logical interface name while creating or deleting
 174  *              interfaces and static addresses.
 175  *  IPH_INIT:   Used by ipadm_init_prop(), to initialize protocol properties
 176  *              on reboot.
 177  */
 178 ipadm_status_t
 179 ipadm_open(ipadm_handle_t *handle, uint32_t flags)
 180 {
 181         ipadm_handle_t  iph;
 182         ipadm_status_t  status = IPADM_SUCCESS;
 183         zoneid_t        zoneid;
 184         ushort_t        zflags;
 185         int             on = B_TRUE;
 186 
 187         if (handle == NULL)
 188                 return (IPADM_INVALID_ARG);
 189         *handle = NULL;
 190 
 191         if (flags & ~(IPH_VRRP|IPH_LEGACY|IPH_INIT|IPH_IPMGMTD))
 192                 return (IPADM_INVALID_ARG);
 193 
 194         if ((iph = calloc(1, sizeof (struct ipadm_handle))) == NULL)
 195                 return (IPADM_NO_MEMORY);
 196         iph->iph_sock = -1;
 197         iph->iph_sock6 = -1;
 198         iph->iph_door_fd = -1;
 199         iph->iph_rtsock = -1;
 200         iph->iph_flags = flags;
 201         (void) pthread_mutex_init(&iph->iph_lock, NULL);
 202 
 203         if ((iph->iph_sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ||
 204             (iph->iph_sock6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
 205                 goto errnofail;
 206         }
 207 
 208         /*
 209          * We open a handle to libdladm here, to facilitate some daemons (like
 210          * nwamd) which opens handle to libipadm before devfsadmd installs the
 211          * right device permissions into the kernel and requires "all"
 212          * privileges to open DLD_CONTROL_DEV.
 213          *
 214          * In a non-global shared-ip zone there will be no DLD_CONTROL_DEV node
 215          * and dladm_open() will fail. So, we avoid this by not calling
 216          * dladm_open() for such zones.
 217          */
 218         zoneid = getzoneid();
 219         iph->iph_zoneid = zoneid;
 220         if (zoneid != GLOBAL_ZONEID) {
 221                 if (zone_getattr(zoneid, ZONE_ATTR_FLAGS, &zflags,
 222                     sizeof (zflags)) < 0) {
 223                         goto errnofail;
 224                 }
 225         }
 226         if ((zoneid == GLOBAL_ZONEID) || (zflags & ZF_NET_EXCL)) {
 227                 if (dladm_open(&iph->iph_dlh) != DLADM_STATUS_OK) {
 228                         ipadm_close(iph);
 229                         return (IPADM_DLADM_FAILURE);
 230                 }
 231                 if (zoneid != GLOBAL_ZONEID) {
 232                         iph->iph_rtsock = socket(PF_ROUTE, SOCK_RAW, 0);
 233                         /*
 234                          * Failure to open rtsock is ignored as this is
 235                          * only used in non-global zones to initialize
 236                          * routing socket information.
 237                          */
 238                 }
 239         } else {
 240                 assert(zoneid != GLOBAL_ZONEID);
 241                 iph->iph_dlh = NULL;
 242         }
 243         if (flags & IPH_VRRP) {
 244                 if (setsockopt(iph->iph_sock6, SOL_SOCKET, SO_VRRP, &on,
 245                     sizeof (on)) < 0 || setsockopt(iph->iph_sock, SOL_SOCKET,
 246                     SO_VRRP, &on, sizeof (on)) < 0) {
 247                         goto errnofail;
 248                 }
 249         }
 250         *handle = iph;
 251         return (status);
 252 
 253 errnofail:
 254         status = ipadm_errno2status(errno);
 255         ipadm_close(iph);
 256         return (status);
 257 }
 258 
 259 /*
 260  * Closes and frees the libipadm handle.
 261  */
 262 void
 263 ipadm_close(ipadm_handle_t iph)
 264 {
 265         if (iph == NULL)
 266                 return;
 267         if (iph->iph_sock != -1)
 268                 (void) close(iph->iph_sock);
 269         if (iph->iph_sock6 != -1)
 270                 (void) close(iph->iph_sock6);
 271         if (iph->iph_rtsock != -1)
 272                 (void) close(iph->iph_rtsock);
 273         if (iph->iph_door_fd != -1)
 274                 (void) close(iph->iph_door_fd);
 275         dladm_close(iph->iph_dlh);
 276         (void) pthread_mutex_destroy(&iph->iph_lock);
 277         free(iph);
 278 }
 279 
 280 /*
 281  * Checks if the caller has the authorization to configure network
 282  * interfaces.
 283  */
 284 boolean_t
 285 ipadm_check_auth(void)
 286 {
 287         struct passwd   pwd;
 288         char            buf[NSS_BUFLEN_PASSWD];
 289 
 290         /* get the password entry for the given user ID */
 291         if (getpwuid_r(getuid(), &pwd, buf, sizeof (buf)) == NULL)
 292                 return (B_FALSE);
 293 
 294         /* check for presence of given authorization */
 295         return (chkauthattr(NETWORK_INTERFACE_CONFIG_AUTH, pwd.pw_name) != 0);
 296 }
 297 
 298 /*
 299  * Stores the index value of the interface in `ifname' for the address
 300  * family `af' into the buffer pointed to by `index'.
 301  */
 302 static ipadm_status_t
 303 i_ipadm_get_index(ipadm_handle_t iph, const char *ifname, sa_family_t af,
 304     int *index)
 305 {
 306         struct lifreq   lifr;
 307         int             sock;
 308 
 309         bzero(&lifr, sizeof (lifr));
 310         (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
 311         if (af == AF_INET)
 312                 sock = iph->iph_sock;
 313         else
 314                 sock = iph->iph_sock6;
 315 
 316         if (ioctl(sock, SIOCGLIFINDEX, (caddr_t)&lifr) < 0)
 317                 return (ipadm_errno2status(errno));
 318         *index = lifr.lifr_index;
 319 
 320         return (IPADM_SUCCESS);
 321 }
 322 
 323 /*
 324  * Maximum amount of time (in milliseconds) to wait for Duplicate Address
 325  * Detection to complete in the kernel.
 326  */
 327 #define DAD_WAIT_TIME           1000
 328 
 329 /*
 330  * Any time that flags are changed on an interface where either the new or the
 331  * existing flags have IFF_UP set, we'll get a RTM_NEWADDR message to
 332  * announce the new address added and its flag status.
 333  * We wait here for that message and look for IFF_UP.
 334  * If something's amiss with the kernel, though, we don't wait forever.
 335  * (Note that IFF_DUPLICATE is a high-order bit, and we cannot see
 336  * it in the routing socket messages.)
 337  */
 338 static ipadm_status_t
 339 i_ipadm_dad_wait(ipadm_handle_t handle, const char *lifname, sa_family_t af,
 340     int rtsock)
 341 {
 342         struct pollfd   fds[1];
 343         union {
 344                 struct if_msghdr ifm;
 345                 char buf[1024];
 346         } msg;
 347         int             index;
 348         ipadm_status_t  retv;
 349         uint64_t        flags;
 350         hrtime_t        starttime, now;
 351 
 352         fds[0].fd = rtsock;
 353         fds[0].events = POLLIN;
 354         fds[0].revents = 0;
 355 
 356         retv = i_ipadm_get_index(handle, lifname, af, &index);
 357         if (retv != IPADM_SUCCESS)
 358                 return (retv);
 359 
 360         starttime = gethrtime();
 361         for (;;) {
 362                 now = gethrtime();
 363                 now = (now - starttime) / 1000000;
 364                 if (now >= DAD_WAIT_TIME)
 365                         break;
 366                 if (poll(fds, 1, DAD_WAIT_TIME - (int)now) <= 0)
 367                         break;
 368                 if (read(rtsock, &msg, sizeof (msg)) <= 0)
 369                         break;
 370                 if (msg.ifm.ifm_type != RTM_NEWADDR)
 371                         continue;
 372                 /* Note that ifm_index is just 16 bits */
 373                 if (index == msg.ifm.ifm_index && (msg.ifm.ifm_flags & IFF_UP))
 374                         return (IPADM_SUCCESS);
 375         }
 376 
 377         retv = i_ipadm_get_flags(handle, lifname, af, &flags);
 378         if (retv != IPADM_SUCCESS)
 379                 return (retv);
 380         if (flags & IFF_DUPLICATE)
 381                 return (IPADM_DAD_FOUND);
 382 
 383         return (IPADM_SUCCESS);
 384 }
 385 
 386 /*
 387  * Sets the flags `on_flags' and resets the flags `off_flags' for the logical
 388  * interface in `lifname'.
 389  *
 390  * If the new flags value will transition the interface from "down" to "up"
 391  * then duplicate address detection is performed by the kernel.  This routine
 392  * waits to get the outcome of that test.
 393  */
 394 ipadm_status_t
 395 i_ipadm_set_flags(ipadm_handle_t iph, const char *lifname, sa_family_t af,
 396     uint64_t on_flags, uint64_t off_flags)
 397 {
 398         struct lifreq   lifr;
 399         uint64_t        oflags;
 400         ipadm_status_t  ret;
 401         int             rtsock = -1;
 402         int             sock, err;
 403 
 404         ret = i_ipadm_get_flags(iph, lifname, af, &oflags);
 405         if (ret != IPADM_SUCCESS)
 406                 return (ret);
 407 
 408         sock = (af == AF_INET ? iph->iph_sock : iph->iph_sock6);
 409 
 410         /*
 411          * Any time flags are changed on an interface that has IFF_UP set,
 412          * we get a routing socket message.  We care about the status,
 413          * though, only when the new flags are marked "up."
 414          */
 415         if (!(oflags & IFF_UP) && (on_flags & IFF_UP))
 416                 rtsock = socket(PF_ROUTE, SOCK_RAW, af);
 417 
 418         oflags |= on_flags;
 419         oflags &= ~off_flags;
 420         bzero(&lifr, sizeof (lifr));
 421         (void) strlcpy(lifr.lifr_name, lifname, sizeof (lifr.lifr_name));
 422         lifr.lifr_flags = oflags;
 423         if (ioctl(sock, SIOCSLIFFLAGS, (caddr_t)&lifr) < 0) {
 424                 err = errno;
 425                 if (rtsock != -1)
 426                         (void) close(rtsock);
 427                 return (ipadm_errno2status(err));
 428         }
 429         if (rtsock == -1) {
 430                 return (IPADM_SUCCESS);
 431         } else {
 432                 /* Wait for DAD to complete. */
 433                 ret = i_ipadm_dad_wait(iph, lifname, af, rtsock);
 434                 (void) close(rtsock);
 435                 return (ret);
 436         }
 437 }
 438 
 439 /*
 440  * Returns the flags value for the logical interface in `lifname'
 441  * in the buffer pointed to by `flags'.
 442  */
 443 ipadm_status_t
 444 i_ipadm_get_flags(ipadm_handle_t iph, const char *lifname, sa_family_t af,
 445     uint64_t *flags)
 446 {
 447         struct lifreq   lifr;
 448         int             sock;
 449 
 450         bzero(&lifr, sizeof (lifr));
 451         (void) strlcpy(lifr.lifr_name, lifname, sizeof (lifr.lifr_name));
 452         if (af == AF_INET)
 453                 sock = iph->iph_sock;
 454         else
 455                 sock = iph->iph_sock6;
 456 
 457         if (ioctl(sock, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) {
 458                 return (ipadm_errno2status(errno));
 459         }
 460         *flags = lifr.lifr_flags;
 461 
 462         return (IPADM_SUCCESS);
 463 }
 464 
 465 /*
 466  * Determines whether or not an interface name represents a loopback
 467  * interface, before the interface has been plumbed.
 468  * It is assumed that the interface name in `ifname' is of correct format
 469  * as verified by ifparse_ifspec().
 470  *
 471  * Returns: B_TRUE if loopback, B_FALSE if not.
 472  */
 473 boolean_t
 474 i_ipadm_is_loopback(const char *ifname)
 475 {
 476         int len = strlen(LOOPBACK_IF);
 477 
 478         return (strncmp(ifname, LOOPBACK_IF, len) == 0 &&
 479             (ifname[len] == '\0' || ifname[len] == IPADM_LOGICAL_SEP));
 480 }
 481 
 482 /*
 483  * Determines whether or not an interface name represents a vni
 484  * interface, before the interface has been plumbed.
 485  * It is assumed that the interface name in `ifname' is of correct format
 486  * as verified by ifparse_ifspec().
 487  *
 488  * Returns: B_TRUE if vni, B_FALSE if not.
 489  */
 490 boolean_t
 491 i_ipadm_is_vni(const char *ifname)
 492 {
 493         ifspec_t        ifsp;
 494 
 495         return (ifparse_ifspec(ifname, &ifsp) &&
 496             strcmp(ifsp.ifsp_devnm, "vni") == 0);
 497 }
 498 
 499 /*
 500  * Returns B_TRUE if `ifname' is an IP interface on a 6to4 tunnel.
 501  */
 502 boolean_t
 503 i_ipadm_is_6to4(ipadm_handle_t iph, char *ifname)
 504 {
 505         dladm_status_t          dlstatus;
 506         datalink_class_t        class;
 507         iptun_params_t          params;
 508         datalink_id_t           linkid;
 509 
 510         if (iph->iph_dlh == NULL) {
 511                 assert(iph->iph_zoneid != GLOBAL_ZONEID);
 512                 return (B_FALSE);
 513         }
 514         dlstatus = dladm_name2info(iph->iph_dlh, ifname, &linkid, NULL,
 515             &class, NULL);
 516         if (dlstatus == DLADM_STATUS_OK && class == DATALINK_CLASS_IPTUN) {
 517                 params.iptun_param_linkid = linkid;
 518                 dlstatus = dladm_iptun_getparams(iph->iph_dlh, &params,
 519                     DLADM_OPT_ACTIVE);
 520                 if (dlstatus == DLADM_STATUS_OK &&
 521                     params.iptun_param_type == IPTUN_TYPE_6TO4) {
 522                         return (B_TRUE);
 523                 }
 524         }
 525         return (B_FALSE);
 526 }
 527 
 528 /*
 529  * For a given interface name, ipadm_if_enabled() checks if v4
 530  * or v6 or both IP interfaces exist in the active configuration.
 531  */
 532 boolean_t
 533 ipadm_if_enabled(ipadm_handle_t iph, const char *ifname, sa_family_t af)
 534 {
 535         struct lifreq   lifr;
 536         int             s4 = iph->iph_sock;
 537         int             s6 = iph->iph_sock6;
 538 
 539         bzero(&lifr, sizeof (lifr));
 540         (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
 541         switch (af) {
 542         case AF_INET:
 543                 if (ioctl(s4, SIOCGLIFFLAGS, (caddr_t)&lifr) == 0)
 544                         return (B_TRUE);
 545                 break;
 546         case AF_INET6:
 547                 if (ioctl(s6, SIOCGLIFFLAGS, (caddr_t)&lifr) == 0)
 548                         return (B_TRUE);
 549                 break;
 550         case AF_UNSPEC:
 551                 if (ioctl(s4, SIOCGLIFFLAGS, (caddr_t)&lifr) == 0 ||
 552                     ioctl(s6, SIOCGLIFFLAGS, (caddr_t)&lifr) == 0) {
 553                         return (B_TRUE);
 554                 }
 555         }
 556         return (B_FALSE);
 557 }
 558 
 559 /*
 560  * Apply the interface property by retrieving information from nvl.
 561  */
 562 static ipadm_status_t
 563 i_ipadm_init_ifprop(ipadm_handle_t iph, nvlist_t *nvl)
 564 {
 565         nvpair_t        *nvp;
 566         char            *name, *pname = NULL;
 567         char            *protostr = NULL, *ifname = NULL, *pval = NULL;
 568         uint_t          proto;
 569         int             err = 0;
 570 
 571         for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL;
 572             nvp = nvlist_next_nvpair(nvl, nvp)) {
 573                 name = nvpair_name(nvp);
 574                 if (strcmp(name, IPADM_NVP_IFNAME) == 0) {
 575                         if ((err = nvpair_value_string(nvp, &ifname)) != 0)
 576                                 break;
 577                 } else if (strcmp(name, IPADM_NVP_PROTONAME) == 0) {
 578                         if ((err = nvpair_value_string(nvp, &protostr)) != 0)
 579                                 break;
 580                 } else {
 581                         assert(!IPADM_PRIV_NVP(name));
 582                         pname = name;
 583                         if ((err = nvpair_value_string(nvp, &pval)) != 0)
 584                                 break;
 585                 }
 586         }
 587         if (err != 0)
 588                 return (ipadm_errno2status(err));
 589         proto = ipadm_str2proto(protostr);
 590         return (ipadm_set_ifprop(iph, ifname, pname, pval, proto,
 591             IPADM_OPT_ACTIVE));
 592 }
 593 
 594 /*
 595  * Instantiate the address object or set the address object property by
 596  * retrieving the configuration from the nvlist `nvl'.
 597  */
 598 ipadm_status_t
 599 i_ipadm_init_addrobj(ipadm_handle_t iph, nvlist_t *nvl)
 600 {
 601         nvpair_t        *nvp;
 602         char            *name;
 603         char            *aobjname = NULL, *pval = NULL, *ifname = NULL;
 604         sa_family_t     af = AF_UNSPEC;
 605         ipadm_addr_type_t atype = IPADM_ADDR_NONE;
 606         int             err = 0;
 607         ipadm_status_t  status = IPADM_SUCCESS;
 608 
 609         for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL;
 610             nvp = nvlist_next_nvpair(nvl, nvp)) {
 611                 name = nvpair_name(nvp);
 612                 if (strcmp(name, IPADM_NVP_IFNAME) == 0) {
 613                         if ((err = nvpair_value_string(nvp, &ifname)) != 0)
 614                                 break;
 615                 } else if (strcmp(name, IPADM_NVP_AOBJNAME) == 0) {
 616                         if ((err = nvpair_value_string(nvp, &aobjname)) != 0)
 617                                 break;
 618                 } else if (i_ipadm_name2atype(name, &af, &atype)) {
 619                         break;
 620                 } else {
 621                         assert(!IPADM_PRIV_NVP(name));
 622                         err = nvpair_value_string(nvp, &pval);
 623                         break;
 624                 }
 625         }
 626         if (err != 0)
 627                 return (ipadm_errno2status(err));
 628 
 629         switch (atype) {
 630         case IPADM_ADDR_STATIC:
 631                 status = i_ipadm_enable_static(iph, ifname, nvl, af);
 632                 break;
 633         case IPADM_ADDR_DHCP:
 634                 status = i_ipadm_enable_dhcp(iph, ifname, nvl);
 635                 if (status == IPADM_DHCP_IPC_TIMEOUT)
 636                         status = IPADM_SUCCESS;
 637                 break;
 638         case IPADM_ADDR_IPV6_ADDRCONF:
 639                 status = i_ipadm_enable_addrconf(iph, ifname, nvl);
 640                 break;
 641         case IPADM_ADDR_NONE:
 642                 status = ipadm_set_addrprop(iph, name, pval, aobjname,
 643                     IPADM_OPT_ACTIVE);
 644                 break;
 645         }
 646 
 647         return (status);
 648 }
 649 
 650 /*
 651  * Instantiate the interface object by retrieving the configuration from
 652  * `ifnvl'. The nvlist `ifnvl' contains all the persistent configuration
 653  * (interface properties and address objects on that interface) for the
 654  * given `ifname'.
 655  */
 656 ipadm_status_t
 657 i_ipadm_init_ifobj(ipadm_handle_t iph, const char *ifname, nvlist_t *ifnvl)
 658 {
 659         nvlist_t        *nvl = NULL;
 660         nvpair_t        *nvp;
 661         ipadm_status_t  status;
 662         ipadm_status_t  ret_status = IPADM_SUCCESS;
 663         char            newifname[LIFNAMSIZ];
 664         char            *aobjstr;
 665         char    *ifclass_str, *gif_name;
 666         uint16_t        *families;
 667         uint_t  nelem = 0;
 668         char **members;
 669         uint32_t        ipadm_flags;
 670         boolean_t       is_ngz = (iph->iph_zoneid != GLOBAL_ZONEID);
 671         boolean_t   init_from_gz = B_FALSE;
 672 
 673         (void) strlcpy(newifname, ifname, sizeof (newifname));
 674         /*
 675          * First plumb the given interface and then apply all the persistent
 676          * interface properties and then instantiate any persistent addresses
 677          * objects on that interface.
 678          */
 679         for (nvp = nvlist_next_nvpair(ifnvl, NULL); nvp != NULL;
 680             nvp = nvlist_next_nvpair(ifnvl, nvp)) {
 681 
 682                 if (nvpair_value_nvlist(nvp, &nvl) != 0)
 683                         continue;
 684 
 685 
 686                 if (nvlist_lookup_uint16_array(nvl, IPADM_NVP_FAMILIES,
 687                     &families, &nelem) == 0) {
 688 
 689                         ipadm_flags = IPADM_OPT_ACTIVE;
 690 
 691                         if (nvlist_lookup_string(nvl, IPADM_NVP_IFCLASS, &ifclass_str) == 0 &&
 692                             atoi(ifclass_str) == IPADM_IF_CLASS_IPMP)
 693                                 ipadm_flags |= IPADM_OPT_IPMP;
 694 
 695                         while (nelem--) {
 696                                 assert(families[nelem] == AF_INET ||
 697                                     families[nelem] == AF_INET6);
 698 
 699                                 status = i_ipadm_plumb_if(iph, newifname, families[nelem],
 700                                     ipadm_flags);
 701 
 702                                 if (status == IPADM_IF_EXISTS)
 703                                         status = IPADM_SUCCESS;
 704 
 705                                 /* plumbing can fail for ipmp, this is expected */
 706                                 if (status != IPADM_SUCCESS && !(ipadm_flags & IPADM_OPT_IPMP))
 707                                         break;
 708                         }
 709                         /* does this interface belong to ipmp ? */
 710                         if (nvlist_lookup_string(nvl, IPADM_NVP_GIFNAME, &gif_name) == 0) {
 711                                 (void) ipadm_create_if(iph, gif_name, AF_INET, IPADM_OPT_IPMP |
 712                                     IPADM_OPT_ACTIVE);
 713                                 (void) ipadm_create_if(iph, gif_name, AF_INET6, IPADM_OPT_IPMP |
 714                                    IPADM_OPT_ACTIVE);
 715                                 /** add itself to the group */
 716                                 status = ipadm_add_ipmp_member(iph, gif_name, newifname, IPADM_OPT_ACTIVE);
 717                                 if (status != IPADM_SUCCESS && status != IPADM_IF_EXISTS)
 718                                         break;
 719                         }
 720                         if (is_ngz)
 721                                 init_from_gz = B_TRUE;
 722                  } else if (nvlist_lookup_string(nvl, IPADM_NVP_AOBJNAME,
 723                     &aobjstr) == 0) {
 724                         /*
 725                          * For a static address, we need to search for
 726                          * the prefixlen in the nvlist `ifnvl'.
 727                          */
 728                         if (nvlist_exists(nvl, IPADM_NVP_IPV4ADDR) ||
 729                             nvlist_exists(nvl, IPADM_NVP_IPV6ADDR)) {
 730                                 status = i_ipadm_merge_prefixlen_from_nvl(ifnvl,
 731                                     nvl, aobjstr);
 732 
 733                                 if (status != IPADM_SUCCESS)
 734                                         continue;
 735                         }
 736                         status = i_ipadm_init_addrobj(iph, nvl);
 737                         /*
 738                          * If this address is in use on some other interface,
 739                          * we want to record an error to be returned as
 740                          * a soft error and continue processing the rest of
 741                          * the addresses.
 742                          */
 743                         if (status == IPADM_ADDR_NOTAVAIL) {
 744                                 ret_status = IPADM_ALL_ADDRS_NOT_ENABLED;
 745                                 status = IPADM_SUCCESS;
 746                         }
 747                 } else {
 748                         assert(nvlist_exists(nvl, IPADM_NVP_PROTONAME));
 749                         status = i_ipadm_init_ifprop(iph, nvl);
 750                 }
 751                 if (status != IPADM_SUCCESS)
 752                         return (status);
 753         }
 754         if (init_from_gz)
 755                 ret_status = ipadm_init_net_from_gz(iph, newifname, NULL);
 756 
 757         return (ret_status);
 758 }
 759 
 760 /*
 761  * Retrieves the persistent configuration for the given interface(s) in `ifs'
 762  * by contacting the daemon and dumps the information in `allifs'.
 763  */
 764 ipadm_status_t
 765 i_ipadm_init_ifs(ipadm_handle_t iph, const char *ifs, nvlist_t **allifs)
 766 {
 767         nvlist_t                *nvl = NULL;
 768         size_t                  nvlsize, bufsize;
 769         ipmgmt_initif_arg_t     *iargp;
 770         char                    *buf = NULL, *nvlbuf = NULL;
 771         ipmgmt_get_rval_t       *rvalp = NULL;
 772         int                     err;
 773         ipadm_status_t          status = IPADM_SUCCESS;
 774 
 775         if ((err = ipadm_str2nvlist(ifs, &nvl, IPADM_NORVAL)) != 0)
 776                 return (ipadm_errno2status(err));
 777 
 778         err = nvlist_pack(nvl, &nvlbuf, &nvlsize, NV_ENCODE_NATIVE, 0);
 779         if (err != 0) {
 780                 status = ipadm_errno2status(err);
 781                 goto done;
 782         }
 783         bufsize = sizeof (*iargp) + nvlsize;
 784         if ((buf = malloc(bufsize)) == NULL) {
 785                 status = ipadm_errno2status(errno);
 786                 goto done;
 787         }
 788 
 789         /* populate the door_call argument structure */
 790         iargp = (void *)buf;
 791         iargp->ia_cmd = IPMGMT_CMD_INITIF;
 792         iargp->ia_flags = 0;
 793         iargp->ia_family = AF_UNSPEC;
 794         iargp->ia_nvlsize = nvlsize;
 795         (void) bcopy(nvlbuf, buf + sizeof (*iargp), nvlsize);
 796 
 797         if ((rvalp = malloc(sizeof (ipmgmt_get_rval_t))) == NULL) {
 798                 status = ipadm_errno2status(errno);
 799                 goto done;
 800         }
 801         if ((err = ipadm_door_call(iph, iargp, bufsize, (void **)&rvalp,
 802             sizeof (*rvalp), B_TRUE)) != 0) {
 803                 status = ipadm_errno2status(err);
 804                 goto done;
 805         }
 806         nvlsize = rvalp->ir_nvlsize;
 807         nvlbuf = (char *)rvalp + sizeof (ipmgmt_get_rval_t);
 808 
 809         /*
 810          * nvlbuf contains a list of nvlists, each of which represents
 811          * configuration information for the given interface(s)
 812          */
 813         err = nvlist_unpack(nvlbuf, nvlsize, allifs, NV_ENCODE_NATIVE);
 814         if (err != 0)
 815                 status = ipadm_errno2status(err);
 816 done:
 817         nvlist_free(nvl);
 818         free(buf);
 819         free(nvlbuf);
 820         free(rvalp);
 821         return (status);
 822 }
 823 
 824 /*
 825  * Returns B_FALSE if
 826  * (1) `ifname' is NULL or has no string or has a string of invalid length
 827  * (2) ifname is a logical interface and IPH_LEGACY is not set, or
 828  */
 829 boolean_t
 830 i_ipadm_validate_ifname(ipadm_handle_t iph, const char *ifname)
 831 {
 832         ifspec_t ifsp;
 833 
 834         if (ifname == NULL || ifname[0] == '\0' ||
 835             !ifparse_ifspec(ifname, &ifsp))
 836                 return (B_FALSE);
 837         if (ifsp.ifsp_lunvalid)
 838                 return (ifsp.ifsp_lun > 0 && (iph->iph_flags & IPH_LEGACY));
 839         return (B_TRUE);
 840 }
 841 
 842 /*
 843  * Wrapper for sending a non-transparent I_STR ioctl().
 844  * Returns: Result from ioctl().
 845  */
 846 int
 847 i_ipadm_strioctl(int s, int cmd, char *buf, int buflen)
 848 {
 849         struct strioctl ioc;
 850 
 851         (void) memset(&ioc, 0, sizeof (ioc));
 852         ioc.ic_cmd = cmd;
 853         ioc.ic_timout = 0;
 854         ioc.ic_len = buflen;
 855         ioc.ic_dp = buf;
 856 
 857         return (ioctl(s, I_STR, (char *)&ioc));
 858 }
 859 
 860 /*
 861  * Make a door call to the server and checks if the door call succeeded or not.
 862  * `is_varsize' specifies that the data returned by ipmgmtd daemon is of
 863  * variable size and door will allocate buffer using mmap(). In such cases
 864  * we re-allocate the required memory,n assign it to `rbufp', copy the data to
 865  * `rbufp' and then call munmap() (see below).
 866  *
 867  * It also checks to see if the server side procedure ran successfully by
 868  * checking for ir_err. Therefore, for some callers who just care about the
 869  * return status can set `rbufp' to NULL and set `rsize' to 0.
 870  */
 871 int
 872 ipadm_door_call(ipadm_handle_t iph, void *arg, size_t asize, void **rbufp,
 873     size_t rsize, boolean_t is_varsize)
 874 {
 875         door_arg_t      darg;
 876         int             err;
 877         ipmgmt_retval_t rval, *rvalp;
 878         boolean_t       reopen = B_FALSE;
 879 
 880         if (rbufp == NULL) {
 881                 rvalp = &rval;
 882                 rbufp = (void **)&rvalp;
 883                 rsize = sizeof (rval);
 884         }
 885 
 886         darg.data_ptr = arg;
 887         darg.data_size = asize;
 888         darg.desc_ptr = NULL;
 889         darg.desc_num = 0;
 890         darg.rbuf = *rbufp;
 891         darg.rsize = rsize;
 892 
 893 reopen:
 894         (void) pthread_mutex_lock(&iph->iph_lock);
 895         /* The door descriptor is opened if it isn't already */
 896         if (iph->iph_door_fd == -1) {
 897                 if ((iph->iph_door_fd = open(IPMGMT_DOOR, O_RDONLY)) < 0) {
 898                         err = errno;
 899                         (void) pthread_mutex_unlock(&iph->iph_lock);
 900                         return (err);
 901                 }
 902         }
 903         (void) pthread_mutex_unlock(&iph->iph_lock);
 904 
 905         if (door_call(iph->iph_door_fd, &darg) == -1) {
 906                 /*
 907                  * Stale door descriptor is possible if ipmgmtd was restarted
 908                  * since last iph_door_fd was opened, so try re-opening door
 909                  * descriptor.
 910                  */
 911                 if (!reopen && errno == EBADF) {
 912                         (void) close(iph->iph_door_fd);
 913                         iph->iph_door_fd = -1;
 914                         reopen = B_TRUE;
 915                         goto reopen;
 916                 }
 917                 return (errno);
 918         }
 919         err = ((ipmgmt_retval_t *)(void *)(darg.rbuf))->ir_err;
 920         if (darg.rbuf != *rbufp) {
 921                 /*
 922                  * if the caller is expecting the result to fit in specified
 923                  * buffer then return failure.
 924                  */
 925                 if (!is_varsize)
 926                         err = EBADE;
 927                 /*
 928                  * The size of the buffer `*rbufp' was not big enough
 929                  * and the door itself allocated buffer, for us. We will
 930                  * hit this, on several occasion as for some cases
 931                  * we cannot predict the size of the return structure.
 932                  * Reallocate the buffer `*rbufp' and memcpy() the contents
 933                  * to new buffer.
 934                  */
 935                 if (err == 0) {
 936                         void *newp;
 937 
 938                         /* allocated memory will be freed by the caller */
 939                         if ((newp = realloc(*rbufp, darg.rsize)) == NULL) {
 940                                 err = ENOMEM;
 941                         } else {
 942                                 *rbufp = newp;
 943                                 (void) memcpy(*rbufp, darg.rbuf, darg.rsize);
 944                         }
 945                 }
 946                 /* munmap() the door buffer */
 947                 (void) munmap(darg.rbuf, darg.rsize);
 948         } else {
 949                 if (darg.rsize != rsize)
 950                         err = EBADE;
 951         }
 952         return (err);
 953 }
 954 
 955 /*
 956  * A helper that is used by i_ipadm_get_db_addr and i_ipadm_get_db_if
 957  * to do a door_call to ipmgmtd, that should return persistent information
 958  * about interfaces or/and addresses from ipadm DB
 959  */
 960 ipadm_status_t
 961 i_ipadm_call_ipmgmtd(ipadm_handle_t iph, void *garg,
 962         size_t garg_size, nvlist_t **onvl)
 963 {
 964         ipmgmt_get_rval_t       *rvalp;
 965         int                     err;
 966         size_t                  nvlsize;
 967         char                    *nvlbuf;
 968 
 969         rvalp = malloc(sizeof (ipmgmt_get_rval_t));
 970         err = ipadm_door_call(iph, garg, garg_size, (void **)&rvalp,
 971             sizeof (*rvalp), B_TRUE);
 972         if (err == 0) {
 973                 nvlsize = rvalp->ir_nvlsize;
 974                 nvlbuf = (char *)rvalp + sizeof (ipmgmt_get_rval_t);
 975                 err = nvlist_unpack(nvlbuf, nvlsize, onvl, NV_ENCODE_NATIVE);
 976         }
 977         free(rvalp);
 978 
 979         return (ipadm_errno2status(err));
 980 }