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