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