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