Print this page
    
    
      
        | Split | 
	Close | 
      
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_door.c
          +++ new/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_door.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 2014, Joyent, Inc. All rights reserved.
  25   25   */
  26   26  
  27   27  /*
  28   28   * Main door handler functions used by ipmgmtd to process the different door
  29   29   * call requests, issued by the library libipadm.so.
  30   30   */
  31   31  
  32   32  #include <alloca.h>
  33   33  #include <pwd.h>
  34   34  #include <auth_attr.h>
  35   35  #include <secdb.h>
  36   36  #include <stdlib.h>
  37   37  #include <stdio.h>
  38   38  #include <string.h>
  39   39  #include <strings.h>
  40   40  #include <errno.h>
  41   41  #include <assert.h>
  42   42  #include <libnvpair.h>
  43   43  #include "ipmgmt_impl.h"
  44   44  
  45   45  /* Handler declaration for each door command */
  46   46  typedef void ipmgmt_door_handler_t(void *argp);
  47   47  
  48   48  static ipmgmt_door_handler_t    ipmgmt_getaddr_handler,
  49   49                                  ipmgmt_getprop_handler,
  50   50                                  ipmgmt_getif_handler,
  51   51                                  ipmgmt_initif_handler,
  52   52                                  ipmgmt_aobjop_handler,
  53   53                                  ipmgmt_resetaddr_handler,
  54   54                                  ipmgmt_setif_handler,
  55   55                                  ipmgmt_resetif_handler,
  56   56                                  ipmgmt_resetprop_handler,
  57   57                                  ipmgmt_setaddr_handler,
  58   58                                  ipmgmt_setprop_handler;
  59   59  
  60   60  typedef struct ipmgmt_door_info_s {
  61   61          uint_t                  idi_cmd;
  62   62          boolean_t               idi_set;
  63   63          ipmgmt_door_handler_t   *idi_handler;
  64   64  } ipmgmt_door_info_t;
  65   65  
  66   66  /* maps door commands to door handler functions */
  67   67  static ipmgmt_door_info_t i_ipmgmt_door_info_tbl[] = {
  68   68          { IPMGMT_CMD_SETPROP,           B_TRUE,  ipmgmt_setprop_handler },
  69   69          { IPMGMT_CMD_SETIF,             B_TRUE,  ipmgmt_setif_handler },
  70   70          { IPMGMT_CMD_SETADDR,           B_TRUE,  ipmgmt_setaddr_handler },
  71   71          { IPMGMT_CMD_GETPROP,           B_FALSE, ipmgmt_getprop_handler },
  72   72          { IPMGMT_CMD_GETIF,             B_FALSE, ipmgmt_getif_handler },
  73   73          { IPMGMT_CMD_GETADDR,           B_FALSE, ipmgmt_getaddr_handler },
  74   74          { IPMGMT_CMD_RESETIF,           B_TRUE,  ipmgmt_resetif_handler },
  75   75          { IPMGMT_CMD_RESETADDR,         B_TRUE,  ipmgmt_resetaddr_handler },
  76   76          { IPMGMT_CMD_RESETPROP,         B_TRUE,  ipmgmt_resetprop_handler },
  77   77          { IPMGMT_CMD_INITIF,            B_TRUE,  ipmgmt_initif_handler },
  78   78          { IPMGMT_CMD_ADDROBJ_LOOKUPADD, B_TRUE,  ipmgmt_aobjop_handler },
  79   79          { IPMGMT_CMD_ADDROBJ_SETLIFNUM, B_TRUE,  ipmgmt_aobjop_handler },
  80   80          { IPMGMT_CMD_ADDROBJ_ADD,       B_TRUE,  ipmgmt_aobjop_handler },
  81   81          { IPMGMT_CMD_AOBJNAME2ADDROBJ,  B_FALSE, ipmgmt_aobjop_handler },
  82   82          { IPMGMT_CMD_LIF2ADDROBJ,       B_FALSE, ipmgmt_aobjop_handler },
  83   83          { 0, 0, NULL },
  84   84  };
  85   85  
  86   86  /*
  87   87   * The main server procedure function that gets invoked for any of the incoming
  88   88   * door commands. Inside this function we identify the incoming command and
  89   89   * invoke the right door handler function.
  90   90   */
  91   91  /* ARGSUSED */
  92   92  void
  93   93  ipmgmt_handler(void *cookie, char *argp, size_t argsz, door_desc_t *dp,
  94   94      uint_t n_desc)
  95   95  {
  96   96          ipmgmt_door_info_t      *infop = NULL;
  97   97          ipmgmt_retval_t         retval;
  98   98          int                     i;
  99   99          uint_t                  err;
 100  100          ucred_t                 *cred = NULL;
 101  101  
 102  102          for (i = 0; i_ipmgmt_door_info_tbl[i].idi_cmd != 0; i++) {
 103  103                  if (i_ipmgmt_door_info_tbl[i].idi_cmd ==
 104  104                      ((ipmgmt_arg_t *)(void *)argp)->ia_cmd) {
 105  105                          infop = &i_ipmgmt_door_info_tbl[i];
 106  106                          break;
 107  107                  }
 108  108          }
 109  109  
 110  110          if (infop == NULL) {
 111  111                  ipmgmt_log(LOG_ERR, "Invalid door command specified");
 112  112                  err = EINVAL;
 113  113                  goto fail;
 114  114          }
 115  115  
 116  116          /*
 117  117           * if not root, check for solaris.network.interface.config authorization
 118  118           */
 119  119          if (infop->idi_set) {
 120  120                  uid_t           uid;
 121  121                  struct passwd   pwd;
 122  122                  char            buf[1024];
 123  123  
 124  124                  if (door_ucred(&cred) != 0) {
 125  125                          err = errno;
 126  126                          ipmgmt_log(LOG_ERR, "Could not get user credentials.");
 127  127                          goto fail;
 128  128                  }
 129  129                  uid = ucred_getruid(cred);
 130  130                  ucred_free(cred);
 131  131                  if ((int)uid < 0) {
 132  132                          err = errno;
 133  133                          ipmgmt_log(LOG_ERR, "Could not get user id.");
 134  134                          goto fail;
 135  135                  }
 136  136  
 137  137                  /*
 138  138                   * Branded zones may have different auth, but root always
 139  139                   * allowed.
 140  140                   */
 141  141                  if (uid != 0) {
 142  142                          if (getpwuid_r(uid, &pwd, buf, sizeof (buf)) == NULL) {
 143  143                                  err = errno;
 144  144                                  ipmgmt_log(LOG_ERR,
 145  145                                      "Could not get password entry.");
 146  146                                  goto fail;
 147  147                          }
 148  148                          if (chkauthattr(NETWORK_INTERFACE_CONFIG_AUTH,
 149  149                              pwd.pw_name) != 1) {
 150  150                                  err = EPERM;
 151  151                                  ipmgmt_log(LOG_ERR,
 152  152                                      "Not authorized for operation.");
 153  153                                  goto fail;
 154  154                          }
 155  155                  }
 156  156          }
 157  157  
 158  158          /* individual handlers take care of calling door_return */
 159  159          infop->idi_handler((void *)argp);
 160  160          return;
 161  161  fail:
 162  162          ucred_free(cred);
 163  163          retval.ir_err = err;
 164  164          (void) door_return((char *)&retval, sizeof (retval), NULL, 0);
 165  165  }
 166  166  
 167  167  /*
 168  168   * Handles the door command IPMGMT_CMD_GETPROP. It retrieves the persisted
 169  169   * property value for the given property.
 170  170   */
 171  171  static void
 172  172  ipmgmt_getprop_handler(void *argp)
 173  173  {
 174  174          ipmgmt_prop_arg_t       *pargp = argp;
 175  175          ipmgmt_getprop_rval_t   rval, *rvalp = &rval;
 176  176  
 177  177          assert(pargp->ia_cmd == IPMGMT_CMD_GETPROP);
 178  178  
 179  179          rvalp->ir_err = ipmgmt_db_walk(ipmgmt_db_getprop, pargp, IPADM_DB_READ);
 180  180          if (rvalp->ir_err == 0)
 181  181                  (void) strlcpy(rvalp->ir_pval, pargp->ia_pval,
 182  182                      sizeof (rvalp->ir_pval));
 183  183          (void) door_return((char *)rvalp, sizeof (*rvalp), NULL, 0);
 184  184  }
 185  185  
 186  186  /*
 187  187   * Handles the door command IPMGMT_CMD_SETPROP. It persists the property value
 188  188   * for the given property in the DB.
 189  189   */
 190  190  static void
 191  191  ipmgmt_setprop_handler(void *argp)
 192  192  {
 193  193          ipmgmt_prop_arg_t       *pargp = argp;
 194  194          ipmgmt_retval_t         rval;
 195  195          ipadm_dbwrite_cbarg_t   cb;
 196  196          nvlist_t                *nvl = NULL;
 197  197          int                     err;
 198  198  
 199  199          assert(pargp->ia_cmd == IPMGMT_CMD_SETPROP);
 200  200  
 201  201          if ((err = nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0)) != 0)
 202  202                  goto fail;
 203  203          if (pargp->ia_module[0] != '\0' &&
 204  204              (err = nvlist_add_string(nvl, IPADM_NVP_PROTONAME,
 205  205              pargp->ia_module)) != 0) {
 206  206                  goto fail;
 207  207          }
 208  208          if (pargp->ia_ifname[0] != '\0' &&
 209  209              (err = nvlist_add_string(nvl, IPADM_NVP_IFNAME,
 210  210              pargp->ia_ifname)) != 0)
 211  211                  goto fail;
 212  212          if (pargp->ia_aobjname[0] != '\0' &&
 213  213              (err = nvlist_add_string(nvl, IPADM_NVP_AOBJNAME,
 214  214              pargp->ia_aobjname)) != 0)
 215  215                  goto fail;
 216  216          if ((err = nvlist_add_string(nvl, pargp->ia_pname,
 217  217              pargp->ia_pval)) != 0)
 218  218                  goto fail;
 219  219  
 220  220          cb.dbw_nvl = nvl;
 221  221          cb.dbw_flags = pargp->ia_flags;
 222  222          err = ipmgmt_db_walk(ipmgmt_db_update, &cb, IPADM_DB_WRITE);
 223  223  fail:
 224  224          nvlist_free(nvl);
 225  225          rval.ir_err = err;
 226  226          (void) door_return((char *)&rval, sizeof (rval), NULL, 0);
 227  227  }
 228  228  
 229  229  /*
 230  230   * Helper function for ipmgmt_setaddr_handler().
 231  231   * It converts the nvlist_t, `nvl', to aobjmap node `nodep'.
 232  232   */
 233  233  static int
 234  234  i_ipmgmt_nvl2aobjnode(nvlist_t *nvl, ipmgmt_aobjmap_t *nodep)
 235  235  {
 236  236          char                    *aobjname = NULL, *ifname = NULL;
 237  237          int32_t                 lnum;
 238  238          nvlist_t                *nvladdr;
 239  239          struct sockaddr_storage addr;
 240  240          uint_t                  n;
 241  241          sa_family_t             af = AF_UNSPEC;
 242  242          ipadm_addr_type_t       addrtype = IPADM_ADDR_NONE;
 243  243          int                     err = 0;
 244  244  
 245  245          /*
 246  246           * Retrieve all the information needed to build '*nodep' from
 247  247           * nvlist_t nvl.
 248  248           */
 249  249          if ((err = nvlist_lookup_string(nvl, IPADM_NVP_AOBJNAME,
 250  250              &aobjname)) != 0 ||
 251  251              (err = nvlist_lookup_string(nvl, IPADM_NVP_IFNAME, &ifname)) != 0 ||
 252  252              (err = nvlist_lookup_int32(nvl, IPADM_NVP_LIFNUM, &lnum)) != 0) {
 253  253                  return (err);
 254  254          }
 255  255          if (nvlist_exists(nvl, IPADM_NVP_IPV4ADDR)) {
 256  256                  af = AF_INET;
 257  257                  addrtype = IPADM_ADDR_STATIC;
 258  258          } else if (nvlist_exists(nvl, IPADM_NVP_DHCP)) {
 259  259                  af = AF_INET;
 260  260                  addrtype = IPADM_ADDR_DHCP;
 261  261          } else if (nvlist_exists(nvl, IPADM_NVP_IPV6ADDR)) {
 262  262                  af = AF_INET6;
 263  263                  addrtype = IPADM_ADDR_STATIC;
 264  264          } else if (nvlist_lookup_nvlist(nvl, IPADM_NVP_INTFID, &nvladdr) == 0) {
 265  265                  struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&addr;
 266  266                  uint8_t *addr6;
 267  267                  uint32_t plen;
 268  268  
 269  269                  af = AF_INET6;
 270  270                  addrtype = IPADM_ADDR_IPV6_ADDRCONF;
 271  271                  if (nvlist_lookup_uint32(nvladdr, IPADM_NVP_PREFIXLEN,
 272  272                      &plen) != 0)
 273  273                          return (EINVAL);
 274  274                  if (plen != 0) {
 275  275                          if (nvlist_lookup_uint8_array(nvladdr,
 276  276                              IPADM_NVP_IPNUMADDR, &addr6, &n) != 0)
 277  277                                  return (EINVAL);
 278  278                          bcopy(addr6, &sin6->sin6_addr, n);
 279  279                  } else {
 280  280                          bzero(&sin6->sin6_addr, sizeof (sin6->sin6_addr));
 281  281                  }
 282  282          }
 283  283  
 284  284          /*
 285  285           * populate the `*nodep' with retrieved values.
 286  286           */
 287  287          (void) strlcpy(nodep->am_ifname, ifname, sizeof (nodep->am_ifname));
 288  288          (void) strlcpy(nodep->am_aobjname, aobjname,
 289  289              sizeof (nodep->am_aobjname));
 290  290          nodep->am_lnum = lnum;
 291  291          nodep->am_family = af;
 292  292          nodep->am_atype = addrtype;
 293  293          if (addrtype == IPADM_ADDR_IPV6_ADDRCONF) {
 294  294                  nodep->am_linklocal = B_TRUE;
 295  295                  nodep->am_ifid = addr;
 296  296          }
 297  297          nodep->am_next = NULL;
 298  298  
 299  299          /*
 300  300           * Do not store logical interface number in persistent store as it
 301  301           * takes different value on reboot. So remove it from `nvl'.
 302  302           */
 303  303          if (nvlist_exists(nvl, IPADM_NVP_LIFNUM))
 304  304                  (void) nvlist_remove(nvl, IPADM_NVP_LIFNUM, DATA_TYPE_INT32);
 305  305  
 306  306          return (0);
 307  307  }
 308  308  
 309  309  /*
 310  310   * Handles the door command IPMGMT_CMD_SETADDR. It adds a new address object
 311  311   * node to the list `aobjmap' and then persists the address information in the
 312  312   * DB.
 313  313   */
 314  314  static void
 315  315  ipmgmt_setaddr_handler(void *argp)
 316  316  {
 317  317          ipmgmt_setaddr_arg_t    *sargp = argp;
 318  318          ipmgmt_retval_t         rval;
 319  319          ipmgmt_aobjmap_t        node;
 320  320          nvlist_t                *nvl = NULL;
 321  321          char                    *nvlbuf;
 322  322          size_t                  nvlsize = sargp->ia_nvlsize;
 323  323          uint32_t                flags = sargp->ia_flags;
 324  324          int                     err = 0;
 325  325  
 326  326          nvlbuf = (char *)argp + sizeof (ipmgmt_setaddr_arg_t);
 327  327          if ((err = nvlist_unpack(nvlbuf, nvlsize, &nvl, NV_ENCODE_NATIVE)) != 0)
 328  328                  goto ret;
 329  329          if (flags & (IPMGMT_ACTIVE|IPMGMT_INIT)) {
 330  330                  if ((err = i_ipmgmt_nvl2aobjnode(nvl, &node)) != 0)
 331  331                          goto ret;
 332  332                  if (flags & IPMGMT_INIT)
 333  333                          node.am_flags = (IPMGMT_ACTIVE|IPMGMT_PERSIST);
 334  334                  else
 335  335                          node.am_flags = flags;
 336  336                  if ((err = ipmgmt_aobjmap_op(&node, ADDROBJ_ADD)) != 0)
 337  337                          goto ret;
 338  338          }
 339  339          if (flags & IPMGMT_PERSIST) {
 340  340                  ipadm_dbwrite_cbarg_t   cb;
 341  341  
 342  342                  cb.dbw_nvl = nvl;
 343  343                  cb.dbw_flags = 0;
 344  344                  err = ipmgmt_db_walk(ipmgmt_db_add, &cb, IPADM_DB_WRITE);
 345  345          }
 346  346  ret:
 347  347          nvlist_free(nvl);
 348  348          rval.ir_err = err;
 349  349          (void) door_return((char *)&rval, sizeof (rval), NULL, 0);
 350  350  }
 351  351  
 352  352  /*
 353  353   * Handles the door commands that modify the `aobjmap' structure.
 354  354   *
 355  355   * IPMGMT_CMD_ADDROBJ_LOOKUPADD - places a stub address object in `aobjmap'
 356  356   *      after ensuring that the namespace is not taken. If required, also
 357  357   *      generates an `aobjname' for address object for the library to use.
 358  358   * IPMGMT_CMD_ADDROBJ_ADD - add/update address object in `aobjmap'
 359  359   * IPMGMT_CMD_LIF2ADDROBJ - given a logical interface, return address object
 360  360   *      associated with that logical interface.
 361  361   * IPMGMT_CMD_AOBJNAME2ADDROBJ - given an address object name return logical
 362  362   *      interface associated with that address object.
 363  363   */
 364  364  static void
 365  365  ipmgmt_aobjop_handler(void *argp)
 366  366  {
 367  367          ipmgmt_aobjop_arg_t     *largp = argp;
 368  368          ipmgmt_retval_t         rval;
 369  369          ipmgmt_aobjop_rval_t    aobjrval;
 370  370          void                    *rvalp;
 371  371          size_t                  rsize;
 372  372          ipmgmt_aobjmap_t        node;
 373  373          int                     err = 0;
 374  374          char                    *ifname = largp->ia_ifname;
 375  375          char                    *aobjname = largp->ia_aobjname;
 376  376          int32_t                 lnum = largp->ia_lnum;
 377  377          sa_family_t             af = largp->ia_family;
 378  378          ipadm_addr_type_t       atype = largp->ia_atype;
 379  379          ipmgmt_aobjmap_t        *head;
 380  380  
 381  381          switch (largp->ia_cmd) {
 382  382          case IPMGMT_CMD_ADDROBJ_LOOKUPADD:
 383  383                  rsize = sizeof (ipmgmt_aobjop_rval_t);
 384  384                  rvalp = &aobjrval;
 385  385                  bzero(&node, sizeof (node));
 386  386                  (void) strlcpy(node.am_aobjname, aobjname,
 387  387                      sizeof (node.am_aobjname));
 388  388                  (void) strlcpy(node.am_ifname, ifname,
 389  389                      sizeof (node.am_ifname));
 390  390                  node.am_family = af;
 391  391                  node.am_atype = atype;
 392  392                  /* no logical number is associated with this addrobj yet */
 393  393                  node.am_lnum = -1;
 394  394                  /* The address object is not persisted yet. */
 395  395                  node.am_flags = IPMGMT_ACTIVE;
 396  396                  err = ipmgmt_aobjmap_op(&node, ADDROBJ_LOOKUPADD);
 397  397                  if (err == 0) {
 398  398                          (void) strlcpy(aobjrval.ir_aobjname, node.am_aobjname,
 399  399                              sizeof (aobjrval.ir_aobjname));
 400  400                  }
 401  401                  break;
 402  402          case IPMGMT_CMD_ADDROBJ_SETLIFNUM:
 403  403                  rsize = sizeof (ipmgmt_retval_t);
 404  404                  rvalp = &rval;
 405  405                  bzero(&node, sizeof (node));
 406  406                  (void) strlcpy(node.am_aobjname, aobjname,
 407  407                      sizeof (node.am_aobjname));
 408  408                  (void) strlcpy(node.am_ifname, ifname,
 409  409                      sizeof (node.am_ifname));
 410  410                  node.am_family = af;
 411  411                  node.am_lnum = lnum;
 412  412                  err = ipmgmt_aobjmap_op(&node, ADDROBJ_SETLIFNUM);
 413  413                  break;
 414  414          case IPMGMT_CMD_ADDROBJ_ADD:
 415  415                  rsize = sizeof (ipmgmt_retval_t);
 416  416                  rvalp = &rval;
 417  417                  if (aobjname[0] == '\0' || ifname[0] == '\0' || lnum == -1 ||
 418  418                      af == AF_UNSPEC) {
 419  419                          err = EINVAL;
 420  420                          break;
 421  421                  }
 422  422                  bzero(&node, sizeof (node));
 423  423                  (void) strlcpy(node.am_aobjname, aobjname,
 424  424                      sizeof (node.am_aobjname));
 425  425                  (void) strlcpy(node.am_ifname, ifname,
 426  426                      sizeof (node.am_ifname));
 427  427                  node.am_atype = atype;
 428  428                  node.am_lnum = lnum;
 429  429                  node.am_family = af;
 430  430                  /* The address object is not persisted. */
 431  431                  node.am_flags = IPMGMT_ACTIVE;
 432  432                  err = ipmgmt_aobjmap_op(&node, ADDROBJ_ADD);
 433  433                  break;
 434  434          case IPMGMT_CMD_AOBJNAME2ADDROBJ:
 435  435                  rsize = sizeof (ipmgmt_aobjop_rval_t);
 436  436                  rvalp = &aobjrval;
 437  437                  bzero(&aobjrval, sizeof (aobjrval));
 438  438                  if (aobjname[0] == '\0') {
 439  439                          err = EINVAL;
 440  440                          break;
 441  441                  }
 442  442                  (void) pthread_rwlock_rdlock(&aobjmap.aobjmap_rwlock);
 443  443                  head = aobjmap.aobjmap_head;
 444  444                  for (; head; head = head->am_next) {
 445  445                          if (strcmp(head->am_aobjname, aobjname) != 0)
 446  446                                  continue;
 447  447                          /*
 448  448                           * For an auto-configured interface, return
 449  449                           * the lifnum that has the link-local on it.
 450  450                           * Other logical interfaces were created for
 451  451                           * prefixes and dhcpv6 addresses and do not
 452  452                           * have am_ifid set.
 453  453                           */
 454  454                          if (head->am_atype != IPADM_ADDR_IPV6_ADDRCONF ||
 455  455                              head->am_linklocal) {
 456  456                                  break;
 457  457                          }
 458  458                  }
 459  459                  if (head == NULL) {
 460  460                          err = ENOENT;
 461  461                          (void) pthread_rwlock_unlock(&aobjmap.aobjmap_rwlock);
 462  462                          break;
 463  463                  }
 464  464                  (void) strlcpy(aobjrval.ir_ifname, head->am_ifname,
 465  465                      sizeof (aobjrval.ir_ifname));
 466  466                  aobjrval.ir_lnum = head->am_lnum;
 467  467                  aobjrval.ir_family = head->am_family;
 468  468                  aobjrval.ir_flags = head->am_flags;
 469  469                  aobjrval.ir_atype = head->am_atype;
 470  470                  if (head->am_atype == IPADM_ADDR_IPV6_ADDRCONF &&
 471  471                      head->am_linklocal)
 472  472                          aobjrval.ir_ifid = head->am_ifid;
 473  473                  (void) pthread_rwlock_unlock(&aobjmap.aobjmap_rwlock);
 474  474                  break;
 475  475          case IPMGMT_CMD_LIF2ADDROBJ:
 476  476                  rsize = sizeof (ipmgmt_aobjop_rval_t);
 477  477                  rvalp = &aobjrval;
 478  478                  bzero(&aobjrval, sizeof (aobjrval));
 479  479                  if (ifname[0] == '\0') {
 480  480                          err = EINVAL;
 481  481                          break;
 482  482                  }
 483  483                  (void) pthread_rwlock_rdlock(&aobjmap.aobjmap_rwlock);
 484  484                  head = aobjmap.aobjmap_head;
 485  485                  for (; head; head = head->am_next) {
 486  486                          if (strcmp(head->am_ifname, ifname) == 0 &&
 487  487                              head->am_lnum == lnum &&
 488  488                              head->am_family == af) {
 489  489                                  break;
 490  490                          }
 491  491                  }
 492  492                  if (head == NULL) {
 493  493                          err = ENOENT;
 494  494                          (void) pthread_rwlock_unlock(&aobjmap.aobjmap_rwlock);
 495  495                          break;
 496  496                  }
 497  497                  (void) strlcpy(aobjrval.ir_aobjname, head->am_aobjname,
 498  498                      sizeof (aobjrval.ir_aobjname));
 499  499                  aobjrval.ir_atype = head->am_atype;
 500  500                  aobjrval.ir_flags = head->am_flags;
 501  501                  (void) pthread_rwlock_unlock(&aobjmap.aobjmap_rwlock);
 502  502                  break;
 503  503          default:
 504  504                  rsize = sizeof (ipmgmt_retval_t);
 505  505                  rvalp = &rval;
 506  506                  err = EINVAL;
 507  507          }
 508  508          ((ipmgmt_retval_t *)rvalp)->ir_err = err;
 509  509          (void) door_return((char *)rvalp, rsize, NULL, 0);
 510  510  }
 511  511  
 512  512  /*
 513  513   * Given an interface name and family, deletes all the address objects
 514  514   * associated with it.
 515  515   */
 516  516  void
 517  517  i_ipmgmt_delif_aobjs(char *ifname, sa_family_t af, uint32_t flags)
 518  518  {
 519  519          ipmgmt_aobjmap_t        *head, *next, *prev;
 520  520          ipadm_db_op_t           db_op;
 521  521  
 522  522          prev = NULL;
 523  523  
 524  524          (void) pthread_rwlock_wrlock(&aobjmap.aobjmap_rwlock);
 525  525          head = aobjmap.aobjmap_head;
 526  526          for (; head; head = next) {
 527  527                  next = head->am_next;
 528  528                  if (strcmp(head->am_ifname, ifname) != 0 ||
 529  529                      head->am_family != af) {
 530  530                          prev = head;
 531  531                          continue;
 532  532                  }
 533  533  
 534  534                  if (head->am_flags == (IPMGMT_ACTIVE|IPMGMT_PERSIST) &&
 535  535                      flags == IPMGMT_ACTIVE) {
 536  536                          /*
 537  537                           * If the addres is present in both active and
 538  538                           * persistent store, and if we are performing
 539  539                           * a temporary delete, we update the node to
 540  540                           * indicate that the address is only present in
 541  541                           * persistent store and we proceed. Otherwise
 542  542                           * we always delete the node from aobjmap.
 543  543                           */
 544  544                          head->am_flags &= ~IPMGMT_ACTIVE;
 545  545                          head->am_lnum = -1;
 546  546                          db_op = IPADM_DB_WRITE;
 547  547                  } else {
 548  548                          db_op = IPADM_DB_DELETE;
 549  549                          if (prev == NULL)
 550  550                                  aobjmap.aobjmap_head = next;
 551  551                          else
 552  552                                  prev->am_next = next;
 553  553                  }
 554  554                  (void) ipmgmt_persist_aobjmap(head, db_op);
 555  555                  if (db_op == IPADM_DB_DELETE)
 556  556                          free(head);
 557  557          }
 558  558          (void) pthread_rwlock_unlock(&aobjmap.aobjmap_rwlock);
 559  559  }
 560  560  
 561  561  /*
 562  562   * Handles the door command IPMGMT_CMD_SETIF. It persists the interface
 563  563   * information in the DB.
 564  564   */
 565  565  static void
 566  566  ipmgmt_setif_handler(void *argp)
 567  567  {
 568  568          ipmgmt_retval_t         rval;
 569  569  
 570  570          rval.ir_err = ipmgmt_persist_if(argp);
 571  571          (void) door_return((char *)&rval, sizeof (rval), NULL, 0);
 572  572  }
 573  573  
 574  574  /*
 575  575   * Handles the door command IPMGMT_CMD_RESETIF. For the given interface,
 576  576   * deletes all the persisted interface configuration. It also deletes, from
 577  577   * `aobjmap', all the address objects configured on the given interface.
 578  578   */
 579  579  static void
 580  580  ipmgmt_resetif_handler(void *argp)
 581  581  {
 582  582          ipmgmt_if_arg_t         *rargp = argp;
 583  583          ipmgmt_retval_t         rval;
 584  584          ipmgmt_if_cbarg_t       cbarg;
 585  585          uint32_t                flags = rargp->ia_flags;
 586  586          int                     err = 0;
 587  587  
 588  588          cbarg.cb_family = rargp->ia_family;
 589  589          cbarg.cb_ifname = rargp->ia_ifname;
 590  590          if (flags & IPMGMT_PERSIST)
 591  591                  err = ipmgmt_db_walk(ipmgmt_db_resetif, &cbarg,
 592  592                      IPADM_DB_DELETE);
 593  593  
 594  594          if (flags & IPMGMT_ACTIVE)
 595  595                  i_ipmgmt_delif_aobjs(rargp->ia_ifname, rargp->ia_family,
 596  596                      flags);
 597  597  
 598  598          rval.ir_err = err;
 599  599          (void) door_return((char *)&rval, sizeof (rval), NULL, 0);
 600  600  }
 601  601  
 602  602  /*
 603  603   * Handles the door command IPMGMT_CMD_RESETADDR. For the given addrobj
 604  604   * deletes all the persisted addrobj configuration. It also deletes the
 605  605   * corresponding node, from `aobjmap'.
 606  606   */
 607  607  static void
 608  608  ipmgmt_resetaddr_handler(void *argp)
 609  609  {
 610  610          ipmgmt_addr_arg_t       *rargp = argp;
 611  611          ipmgmt_retval_t         rval;
 612  612          ipmgmt_aobjmap_t        node;
 613  613          uint32_t                flags = rargp->ia_flags;
 614  614          int                     err = 0;
 615  615          ipmgmt_resetaddr_cbarg_t cbarg;
 616  616  
 617  617          cbarg.cb_aobjname = rargp->ia_aobjname;
 618  618  
 619  619          if (flags & IPMGMT_PERSIST)
 620  620                  err = ipmgmt_db_walk(ipmgmt_db_resetaddr, &cbarg,
 621  621                      IPADM_DB_DELETE);
 622  622  
 623  623          if (flags & IPMGMT_ACTIVE) {
 624  624                  bzero(&node, sizeof (node));
 625  625                  (void) strlcpy(node.am_aobjname, rargp->ia_aobjname,
 626  626                      sizeof (node.am_aobjname));
 627  627  
 628  628                  /*
 629  629                   * am_lnum is used only for IPv6 autoconf case, since there
 630  630                   * can be multiple nodes with the same aobjname.
 631  631                   */
 632  632                  node.am_lnum = rargp->ia_lnum;
 633  633                  node.am_flags = flags;
 634  634                  (void) ipmgmt_aobjmap_op(&node, ADDROBJ_DELETE);
 635  635          }
 636  636  
 637  637          rval.ir_err = err;
 638  638          (void) door_return((char *)&rval, sizeof (rval), NULL, 0);
 639  639  }
 640  640  
 641  641  /*
 642  642   * Handles the door command IPMGMT_CMD_GETADDR. It retrieves the persisted
 643  643   * address for a given `gargp->ia_aobjname'. If it is not defined then it
 644  644   * retrieves all the addresses configured on `gargp->ia_ifname'. The
 645  645   * "ipadm show-addr addrobj" or "ipadm show-addr <ifname>/\*" will call this
 646  646   * handler through library.
 647  647   */
 648  648  static void
 649  649  ipmgmt_getaddr_handler(void *argp)
 650  650  {
 651  651          size_t                  buflen, onvlsize;
 652  652          char                    *buf, *onvlbuf;
 653  653          ipmgmt_getaddr_arg_t    *gargp = argp;
 654  654          ipmgmt_getaddr_cbarg_t  cbarg;
 655  655          ipmgmt_get_rval_t       rval, *rvalp = &rval;
 656  656          int                     err = 0;
 657  657  
 658  658          cbarg.cb_ifname = gargp->ia_ifname;
 659  659          cbarg.cb_aobjname = gargp->ia_aobjname;
 660  660          cbarg.cb_ocnt = 0;
 661  661          if (nvlist_alloc(&cbarg.cb_onvl, NV_UNIQUE_NAME, 0) != 0)
 662  662                  goto fail;
 663  663          err = ipmgmt_db_walk(ipmgmt_db_getaddr, &cbarg, IPADM_DB_READ);
 664  664          if (err == ENOENT && cbarg.cb_ocnt > 0) {
 665  665                  /*
 666  666                   * If there is atleast one entry in the nvlist,
 667  667                   * do not return error.
 668  668                   */
 669  669                  err = 0;
 670  670          }
 671  671          if (err != 0)
 672  672                  goto fail;
 673  673  
 674  674          if ((err = nvlist_size(cbarg.cb_onvl, &onvlsize,
 675  675              NV_ENCODE_NATIVE)) != 0) {
 676  676                  goto fail;
 677  677          }
 678  678          buflen = onvlsize + sizeof (ipmgmt_get_rval_t);
 679  679          /*
 680  680           * We cannot use malloc() here because door_return never returns, and
 681  681           * memory allocated by malloc() would get leaked. Use alloca() instead.
 682  682           */
 683  683          buf = alloca(buflen);
 684  684          onvlbuf = buf + sizeof (ipmgmt_get_rval_t);
 685  685          if ((err = nvlist_pack(cbarg.cb_onvl, &onvlbuf, &onvlsize,
 686  686              NV_ENCODE_NATIVE, 0)) != 0) {
 687  687                  goto fail;
 688  688          }
 689  689          nvlist_free(cbarg.cb_onvl);
 690  690          rvalp = (ipmgmt_get_rval_t *)(void *)buf;
 691  691          rvalp->ir_err = 0;
 692  692          rvalp->ir_nvlsize = onvlsize;
 693  693  
 694  694          (void) door_return(buf, buflen, NULL, 0);
 695  695          return;
 696  696  fail:
 697  697          nvlist_free(cbarg.cb_onvl);
 698  698          rvalp->ir_err = err;
 699  699          (void) door_return((char *)rvalp, sizeof (*rvalp), NULL, 0);
 700  700  }
 701  701  
 702  702  /*
 703  703   * Handles the door command IPMGMT_CMD_RESETPROP. It deletes the property line
 704  704   * from the DB.
 705  705   */
 706  706  static void
 707  707  ipmgmt_resetprop_handler(void *argp)
 708  708  {
 709  709          ipmgmt_prop_arg_t       *pargp = argp;
 710  710          ipmgmt_retval_t         rval;
 711  711  
 712  712          assert(pargp->ia_cmd == IPMGMT_CMD_RESETPROP);
 713  713  
 714  714          rval.ir_err = ipmgmt_db_walk(ipmgmt_db_resetprop, pargp,
 715  715              IPADM_DB_DELETE);
 716  716          (void) door_return((char *)&rval, sizeof (rval), NULL, 0);
 717  717  }
 718  718  
 719  719  /*
 720  720   * Handles the door command IPMGMT_CMD_GETIF. It retrieves the name of all the
 721  721   * persisted interfaces and the IP protocols (IPv4 or IPv6) they support.
 722  722   */
 723  723  static void
 724  724  ipmgmt_getif_handler(void *argp)
 725  725  {
 726  726          ipmgmt_getif_arg_t      *getif = argp;
 727  727          ipmgmt_getif_rval_t     *rvalp;
 728  728          ipmgmt_retval_t         rval;
 729  729          ipmgmt_getif_cbarg_t    cbarg;
 730  730          ipadm_if_info_t         *ifp, *rifp, *curifp;
 731  731          int                     i, err = 0, count = 0;
 732  732          size_t                  rbufsize;
 733  733  
 734  734          assert(getif->ia_cmd == IPMGMT_CMD_GETIF);
 735  735  
 736  736          bzero(&cbarg, sizeof (cbarg));
 737  737          cbarg.cb_ifname = getif->ia_ifname;
 738  738          err = ipmgmt_db_walk(ipmgmt_db_getif, &cbarg, IPADM_DB_READ);
 739  739          if (err == ENOENT && cbarg.cb_ifinfo) {
 740  740                  /*
 741  741                   * If there is atleast one entry in the nvlist,
 742  742                   * do not return error.
 743  743                   */
 744  744                  err = 0;
 745  745          }
 746  746          if (err != 0) {
 747  747                  rval.ir_err = err;
 748  748                  (void) door_return((char *)&rval, sizeof (rval), NULL, 0);
 749  749                  return;
 750  750          }
 751  751  
 752  752          /* allocate sufficient buffer to return the interface info */
 753  753          for (ifp = cbarg.cb_ifinfo; ifp != NULL; ifp = ifp->ifi_next)
 754  754                  ++count;
 755  755          rbufsize = sizeof (*rvalp) + count * sizeof (*ifp);
 756  756          rvalp = alloca(rbufsize);
 757  757          bzero(rvalp, rbufsize);
 758  758  
 759  759          rvalp->ir_ifcnt = count;
 760  760          rifp = rvalp->ir_ifinfo;
 761  761          ifp = cbarg.cb_ifinfo;
 762  762  
 763  763          /*
 764  764           * copy the interface info to buffer allocated on stack. The reason
 765  765           * we do this is to avoid memory leak, as door_return() would never
 766  766           * return
 767  767           */
 768  768          for (i = 0; i < count; i++) {
 769  769                  rifp = rvalp->ir_ifinfo + i;
 770  770                  (void) bcopy(ifp, rifp, sizeof (*rifp));
 771  771                  rifp->ifi_next = NULL;
 772  772                  curifp = ifp->ifi_next;
 773  773                  free(ifp);
 774  774                  ifp = curifp;
 775  775          }
 776  776          rvalp->ir_err = err;
 777  777          (void) door_return((char *)rvalp, rbufsize, NULL, 0);
 778  778  }
 779  779  
 780  780  /*
 781  781   * Handles the door command IPMGMT_CMD_INITIF. It retrieves all the persisted
 782  782   * interface configuration (interface properties and addresses), for all those
 783  783   * interfaces that need to be initialized.
 784  784   */
 785  785  static void
 786  786  ipmgmt_initif_handler(void *argp)
 787  787  {
 788  788          ipmgmt_initif_arg_t     *initif = argp;
 789  789          size_t                  buflen, nvlsize;
 790  790          char                    *buf = NULL, *onvlbuf, *invlbuf;
 791  791          ipmgmt_get_rval_t       rval, *rvalp = &rval;
 792  792          ipmgmt_initif_cbarg_t   cbarg;
 793  793          int                     err;
 794  794  
 795  795          assert(initif->ia_cmd == IPMGMT_CMD_INITIF);
 796  796  
 797  797          bzero(&cbarg, sizeof (cbarg));
 798  798          invlbuf = (char *)argp + sizeof (ipmgmt_initif_arg_t);
 799  799          nvlsize = initif->ia_nvlsize;
 800  800          err = nvlist_unpack(invlbuf, nvlsize, &cbarg.cb_invl, NV_ENCODE_NATIVE);
 801  801          if (err != 0)
 802  802                  goto fail;
 803  803  
 804  804          cbarg.cb_family = initif->ia_family;
 805  805          if (nvlist_alloc(&cbarg.cb_onvl, NV_UNIQUE_NAME, 0) != 0)
 806  806                  goto fail;
 807  807  
 808  808          err = ipmgmt_db_walk(ipmgmt_db_initif, &cbarg, IPADM_DB_READ);
 809  809          if (err == ENOENT && cbarg.cb_ocnt > 0) {
 810  810                  /*
 811  811                   * If there is atleast one entry in the nvlist,
 812  812                   * do not return error.
 813  813                   */
 814  814                  err = 0;
 815  815          }
 816  816          if (err != 0)
 817  817                  goto fail;
 818  818  
 819  819          if ((err = nvlist_size(cbarg.cb_onvl, &nvlsize, NV_ENCODE_NATIVE)) != 0)
 820  820                  goto fail;
 821  821          buflen = nvlsize + sizeof (ipmgmt_get_rval_t);
 822  822          /*
 823  823           * We cannot use malloc() here because door_return never returns, and
 824  824           * memory allocated by malloc() would get leaked. Use alloca() instead.
 825  825           */
 826  826          buf = alloca(buflen);
 827  827          onvlbuf = buf + sizeof (ipmgmt_get_rval_t);
 828  828          if ((err = nvlist_pack(cbarg.cb_onvl, &onvlbuf, &nvlsize,
 829  829              NV_ENCODE_NATIVE, 0)) != 0) {
 830  830                  goto fail;
 831  831          }
 832  832          nvlist_free(cbarg.cb_invl);
 833  833          nvlist_free(cbarg.cb_onvl);
 834  834          rvalp = (ipmgmt_get_rval_t *)(void *)buf;
 835  835          rvalp->ir_err = 0;
 836  836          rvalp->ir_nvlsize = nvlsize;
 837  837  
 838  838          (void) door_return(buf, buflen, NULL, 0);
 839  839          return;
 840  840  fail:
 841  841          nvlist_free(cbarg.cb_invl);
 842  842          nvlist_free(cbarg.cb_onvl);
 843  843          rvalp->ir_err = err;
 844  844          (void) door_return((char *)rvalp, sizeof (*rvalp), NULL, 0);
 845  845  }
 846  846  
 847  847  int
 848  848  ipmgmt_persist_if(ipmgmt_if_arg_t *sargp)
 849  849  {
 850  850          ipadm_dbwrite_cbarg_t   cb;
 851  851          uint32_t                flags = sargp->ia_flags;
 852  852          nvlist_t                *nvl = NULL;
 853  853          int                     err = 0;
 854  854          char                    strval[IPMGMT_STRSIZE];
 855  855  
 856  856          if (!(flags & IPMGMT_PERSIST) || sargp->ia_family == AF_UNSPEC ||
 857  857              sargp->ia_ifname[0] == '\0') {
 858  858                  err = EINVAL;
 859  859                  goto ret;
 860  860          }
 861  861          if ((err = nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0)) != 0)
 862  862                  goto ret;
 863  863          if ((err = nvlist_add_string(nvl, IPADM_NVP_IFNAME,
 864  864              sargp->ia_ifname)) != 0)
 865  865                  goto ret;
 866  866          (void) snprintf(strval, IPMGMT_STRSIZE, "%d", sargp->ia_family);
 867  867          if ((err = nvlist_add_string(nvl, IPADM_NVP_FAMILY, strval)) != 0)
 868  868                  goto ret;
 869  869          cb.dbw_nvl = nvl;
 870  870          cb.dbw_flags = 0;
 871  871          err = ipmgmt_db_walk(ipmgmt_db_add, &cb, IPADM_DB_WRITE);
 872  872  ret:
 873  873          nvlist_free(nvl);
 874  874          return (err);
 875  875  }
  
    | 
      ↓ open down ↓ | 
    875 lines elided | 
    
      ↑ open up ↑ | 
  
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX