Print this page
7388 Support DHCP Client FQDN. Allow IAID/DUID for all v4.

Split Close
Expand all
Collapse all
          --- old/usr/src/lib/libipadm/common/ipadm_addr.c
          +++ new/usr/src/lib/libipadm/common/ipadm_addr.c
↓ 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   * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
  23   23   * Copyright (c) 2013 by Delphix. All rights reserved.
       24 + * Copyright (c) 2016, Chris Fraire <cfraire@me.com>.
  24   25   */
  25   26  
  26   27  /*
  27   28   * This file contains functions for address management such as creating
  28   29   * an address, deleting an address, enabling an address, disabling an
  29   30   * address, bringing an address down or up, setting/getting properties
  30   31   * on an address object and listing address information
  31   32   * for all addresses in active as well as persistent configuration.
  32   33   */
  33   34  #include <sys/types.h>
  34   35  #include <sys/socket.h>
       36 +#include <sys/param.h>
  35   37  #include <netdb.h>
  36   38  #include <inet/ip.h>
  37   39  #include <string.h>
  38   40  #include <strings.h>
  39   41  #include <assert.h>
  40   42  #include <sys/sockio.h>
  41   43  #include <errno.h>
  42   44  #include <unistd.h>
  43   45  #include <stropts.h>
  44   46  #include <zone.h>
  45   47  #include <netinet/in.h>
  46   48  #include <arpa/inet.h>
  47   49  #include <fcntl.h>
  48   50  #include <ctype.h>
  49   51  #include <dhcpagent_util.h>
  50   52  #include <dhcpagent_ipc.h>
       53 +#include <dhcp_inittab.h>
       54 +#include <dhcp_symbol.h>
  51   55  #include <ipadm_ndpd.h>
  52   56  #include <libdladm.h>
  53   57  #include <libdllink.h>
  54   58  #include <libdliptun.h>
  55   59  #include <ifaddrs.h>
  56   60  #include "libipadm_impl.h"
  57   61  
  58   62  #define SIN6(a)         ((struct sockaddr_in6 *)a)
  59   63  #define SIN(a)          ((struct sockaddr_in *)a)
  60   64  
  61   65  static ipadm_status_t   i_ipadm_create_addr(ipadm_handle_t, ipadm_addrobj_t,
  62   66                              uint32_t);
  63   67  static ipadm_status_t   i_ipadm_create_dhcp(ipadm_handle_t, ipadm_addrobj_t,
  64   68                              uint32_t);
  65   69  static ipadm_status_t   i_ipadm_delete_dhcp(ipadm_handle_t, ipadm_addrobj_t,
  66   70                              boolean_t);
       71 +static ipadm_status_t   i_ipadm_refresh_dhcp(ipadm_addrobj_t);
  67   72  static ipadm_status_t   i_ipadm_get_db_addr(ipadm_handle_t, const char *,
  68   73                              const char *, nvlist_t **);
  69   74  static ipadm_status_t   i_ipadm_op_dhcp(ipadm_addrobj_t, dhcp_ipc_type_t,
  70   75                              int *);
  71   76  static ipadm_status_t   i_ipadm_validate_create_addr(ipadm_handle_t,
  72   77                              ipadm_addrobj_t, uint32_t);
  73   78  static ipadm_status_t   i_ipadm_addr_persist_nvl(ipadm_handle_t, nvlist_t *,
  74   79                              uint32_t);
  75   80  static ipadm_status_t   i_ipadm_get_default_prefixlen(struct sockaddr_storage *,
  76   81                              uint32_t *);
  77   82  static ipadm_status_t   i_ipadm_get_static_addr_db(ipadm_handle_t,
  78   83                              ipadm_addrobj_t);
  79   84  static boolean_t        i_ipadm_is_user_aobjname_valid(const char *);
       85 +static ipadm_prop_desc_t *      i_ipadm_get_addrprop_desc(const char *pname);
  80   86  
  81   87  /*
  82   88   * Callback functions to retrieve property values from the kernel. These
  83   89   * functions, when required, translate the values from the kernel to a format
  84   90   * suitable for printing. They also retrieve DEFAULT, PERM and POSSIBLE values
  85   91   * for a given property.
  86   92   */
  87   93  static ipadm_pd_getf_t  i_ipadm_get_prefixlen, i_ipadm_get_addr_flag,
  88      -                        i_ipadm_get_zone, i_ipadm_get_broadcast;
       94 +                        i_ipadm_get_zone, i_ipadm_get_broadcast, i_ipadm_get_primary,
       95 +                        i_ipadm_get_reqhost;
  89   96  
  90   97  /*
  91   98   * Callback functions to set property values. These functions translate the
  92   99   * values to a format suitable for kernel consumption, allocate the necessary
  93      - * ioctl buffers and then invoke ioctl().
      100 + * ioctl buffers and then invoke ioctl(); or in the case of reqhost, get the
      101 + * collaborating agent to set the value.
  94  102   */
  95  103  static ipadm_pd_setf_t  i_ipadm_set_prefixlen, i_ipadm_set_addr_flag,
  96      -                        i_ipadm_set_zone;
      104 +                        i_ipadm_set_zone, i_ipadm_set_reqhost;
  97  105  
      106 +static ipadm_status_t   i_ipadm_set_aobj_addrprop(ipadm_handle_t iph,
      107 +                        ipadm_addrobj_t ipaddr, uint_t flags, const char *propname);
      108 +
  98  109  /* address properties description table */
  99  110  ipadm_prop_desc_t ipadm_addrprop_table[] = {
 100  111          { "broadcast", NULL, IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE, 0,
 101  112              NULL, NULL, i_ipadm_get_broadcast },
 102  113  
 103  114          { "deprecated", NULL, IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE, 0,
 104  115              i_ipadm_set_addr_flag, i_ipadm_get_onoff,
 105  116              i_ipadm_get_addr_flag },
 106  117  
 107      -        { "prefixlen", NULL, IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE, 0,
      118 +        { IPADM_NVP_PREFIXLEN, NULL, IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE, 0,
 108  119              i_ipadm_set_prefixlen, i_ipadm_get_prefixlen,
 109  120              i_ipadm_get_prefixlen },
 110  121  
      122 +        /*
      123 +         * primary is read-only because there is no operation to un-set
      124 +         * DHCP_IF_PRIMARY in dhcpagent except to delete-addr and then
      125 +         * re-create-addr.
      126 +         */
      127 +        { "primary", NULL, IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE, 0,
      128 +                NULL, NULL, i_ipadm_get_primary },
      129 +
 111  130          { "private", NULL, IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE, 0,
 112  131              i_ipadm_set_addr_flag, i_ipadm_get_onoff, i_ipadm_get_addr_flag },
 113  132  
      133 +        { IPADM_NVP_REQHOST, NULL, IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE, 0,
      134 +            i_ipadm_set_reqhost, NULL, i_ipadm_get_reqhost },
      135 +
 114  136          { "transmit", NULL, IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE, 0,
 115  137              i_ipadm_set_addr_flag, i_ipadm_get_onoff, i_ipadm_get_addr_flag },
 116  138  
 117  139          { "zone", NULL, IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE, 0,
 118  140              i_ipadm_set_zone, NULL, i_ipadm_get_zone },
 119  141  
 120  142          { NULL, NULL, 0, 0, 0, NULL, NULL, NULL }
 121  143  };
 122  144  
 123  145  static ipadm_prop_desc_t up_addrprop = { "up", NULL, IPADMPROP_CLASS_ADDR,
↓ open down ↓ 70 lines elided ↑ open up ↑
 194  216          err = ipadm_door_call(iph, &larg, sizeof (larg), (void **)&rvalp,
 195  217              sizeof (rval), B_FALSE);
 196  218          if (err != 0)
 197  219                  return (ipadm_errno2status(err));
 198  220          (void) strlcpy(ipaddr->ipadm_ifname, rval.ir_ifname,
 199  221              sizeof (ipaddr->ipadm_ifname));
 200  222          ipaddr->ipadm_lifnum = rval.ir_lnum;
 201  223          ipaddr->ipadm_atype = rval.ir_atype;
 202  224          ipaddr->ipadm_af = rval.ir_family;
 203  225          ipaddr->ipadm_flags = rval.ir_flags;
 204      -        if (rval.ir_atype == IPADM_ADDR_IPV6_ADDRCONF) {
 205      -                (void) memcpy(&ipaddr->ipadm_intfid, &rval.ir_ifid,
 206      -                    sizeof (ipaddr->ipadm_intfid));
      226 +        switch (rval.ir_atype) {
      227 +        case IPADM_ADDR_IPV6_ADDRCONF:
      228 +                ipaddr->ipadm_intfid = rval.ipmgmt_ir_intfid;
      229 +                break;
      230 +        case IPADM_ADDR_DHCP:
      231 +                ipaddr->ipadm_primary = rval.ipmgmt_ir_primary;
      232 +                (void) strlcpy(ipaddr->ipadm_reqhost, rval.ipmgmt_ir_reqhost,
      233 +                    sizeof (ipaddr->ipadm_reqhost));
      234 +                break;
      235 +        default:
      236 +                break;
 207  237          }
 208  238  
 209  239          return (IPADM_SUCCESS);
 210  240  }
 211  241  
 212  242  /*
 213  243   * Retrieves the static address (IPv4 or IPv6) for the given address object
 214  244   * in `ipaddr' from persistent DB.
 215  245   */
 216  246  static ipadm_status_t
↓ open down ↓ 817 lines elided ↑ open up ↑
1034 1064          i_ipadm_addrobj2lifname((ipadm_addrobj_t)arg, lifr.lifr_name,
1035 1065              sizeof (lifr.lifr_name));
1036 1066          lifr.lifr_zoneid = zoneid;
1037 1067          if (ioctl(s, SIOCSLIFZONE, (caddr_t)&lifr) < 0)
1038 1068                  return (ipadm_errno2status(errno));
1039 1069  
1040 1070          return (IPADM_SUCCESS);
1041 1071  }
1042 1072  
1043 1073  /*
     1074 + * Callback function that sets the property `reqhost' on the address
     1075 + * object in `arg' to the value in `pval'.
     1076 + */
     1077 +/* ARGSUSED */
     1078 +static ipadm_status_t
     1079 +i_ipadm_set_reqhost(ipadm_handle_t iph, const void *arg,
     1080 +    ipadm_prop_desc_t *pdp, const void *pval, uint_t af, uint_t flags)
     1081 +{
     1082 +        ipadm_status_t  status;
     1083 +        ipadm_addrobj_t         ipaddr = (ipadm_addrobj_t)arg;
     1084 +
     1085 +        if (ipaddr->ipadm_atype != IPADM_ADDR_DHCP)
     1086 +                return (IPADM_NOTSUP);
     1087 +
     1088 +        /*
     1089 +         * If requested to set reqhost just from active config but the
     1090 +         * address is not in active config, return error.
     1091 +         */
     1092 +        if (!(ipaddr->ipadm_flags & IPMGMT_ACTIVE) &&
     1093 +            (flags & IPADM_OPT_ACTIVE) && !(flags & IPADM_OPT_PERSIST)) {
     1094 +                return (IPADM_NOTFOUND);
     1095 +        }
     1096 +
     1097 +        status = ipadm_set_reqhost(ipaddr, pval);
     1098 +        if (status != IPADM_SUCCESS)
     1099 +                return (status);
     1100 +
     1101 +        if (ipaddr->ipadm_flags & IPMGMT_ACTIVE) {
     1102 +                status = i_ipadm_refresh_dhcp(ipaddr);
     1103 +
     1104 +                /*
     1105 +                 * We do not report a problem for IPADM_DHCP_IPC_TIMEOUT since it is
     1106 +                 * only a soft error to indicate the caller that the lease might be
     1107 +                 * renewed after the function returns.
     1108 +                 */
     1109 +                if (status != IPADM_SUCCESS && status != IPADM_DHCP_IPC_TIMEOUT)
     1110 +                        return (status);
     1111 +        }
     1112 +
     1113 +        status = i_ipadm_set_aobj_addrprop(iph, ipaddr, flags,
     1114 +            IPADM_NVP_REQHOST);
     1115 +        return (status);
     1116 +}
     1117 +
     1118 +/*
     1119 + * Used by address object property callback functions that need to do a
     1120 + * two-stage update because the addrprop is cached on the address object.
     1121 + */
     1122 +static ipadm_status_t
     1123 +i_ipadm_set_aobj_addrprop(ipadm_handle_t iph, ipadm_addrobj_t ipaddr,
     1124 +                        uint_t flags, const char *propname)
     1125 +{
     1126 +        ipadm_status_t  status;
     1127 +        uint32_t                two_stage_flags;
     1128 +
     1129 +        /*
     1130 +         * Send the updated address object information to ipmgmtd, since the
     1131 +         * cached version of an addrprop resides on an aobjmap, but do
     1132 +         * not change the ACTIVE/PERSIST state of the aobjmap. Instead, request
     1133 +         * a two-stage, SET_PROPS update with ACTIVE/PERSIST as the first stage
     1134 +         * per the existing aobjmap flags and a second stage encoded in
     1135 +         * IPADM_OPT_PERSIST_PROPS.
     1136 +         */
     1137 +        two_stage_flags = (flags | IPADM_OPT_SET_PROPS)
     1138 +            & ~(IPADM_OPT_ACTIVE | IPADM_OPT_PERSIST);
     1139 +        if (ipaddr->ipadm_flags & IPMGMT_ACTIVE)
     1140 +                two_stage_flags |= IPADM_OPT_ACTIVE;
     1141 +        if (ipaddr->ipadm_flags & IPMGMT_PERSIST)
     1142 +                two_stage_flags |= IPADM_OPT_PERSIST;
     1143 +        if (flags & IPADM_OPT_PERSIST)
     1144 +                two_stage_flags |= IPADM_OPT_PERSIST_PROPS;
     1145 +
     1146 +        status = i_ipadm_addr_persist(iph, ipaddr, B_FALSE, two_stage_flags,
     1147 +            propname);
     1148 +        return (status);
     1149 +}
     1150 +
     1151 +/*
1044 1152   * Callback function that gets the property `broadcast' for the address
1045 1153   * object in `arg'.
1046 1154   */
1047 1155  /* ARGSUSED */
1048 1156  static ipadm_status_t
1049 1157  i_ipadm_get_broadcast(ipadm_handle_t iph, const void *arg,
1050 1158      ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t af,
1051 1159      uint_t valtype)
1052 1160  {
1053 1161          struct sockaddr_in      *sin;
↓ open down ↓ 310 lines elided ↑ open up ↑
1364 1472          }
1365 1473          if (nbytes >= *bufsize) {
1366 1474                  /* insufficient buffer space */
1367 1475                  *bufsize = nbytes + 1;
1368 1476                  return (IPADM_NO_BUFS);
1369 1477          }
1370 1478  
1371 1479          return (IPADM_SUCCESS);
1372 1480  }
1373 1481  
     1482 +/*
     1483 + * Callback function that retrieves the value of the property `primary'
     1484 + * for the address object in `arg'.
     1485 + */
     1486 +/* ARGSUSED */
     1487 +static ipadm_status_t
     1488 +i_ipadm_get_primary(ipadm_handle_t iph, const void *arg,
     1489 +    ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t af,
     1490 +    uint_t valtype)
     1491 +{
     1492 +        ipadm_addrobj_t ipaddr = (ipadm_addrobj_t)arg;
     1493 +        const char *    onoff = "";
     1494 +        size_t          nbytes;
     1495 +
     1496 +        switch (valtype) {
     1497 +        case MOD_PROP_DEFAULT:
     1498 +                if (ipaddr->ipadm_atype == IPADM_ADDR_DHCP)
     1499 +                        onoff = IPADM_OFFSTR;
     1500 +                break;
     1501 +        case MOD_PROP_ACTIVE:
     1502 +                if (ipaddr->ipadm_atype == IPADM_ADDR_DHCP)
     1503 +                        onoff = ipaddr->ipadm_primary ? IPADM_ONSTR : IPADM_OFFSTR;
     1504 +                break;
     1505 +        default:
     1506 +                return (IPADM_INVALID_ARG);
     1507 +        }
     1508 +
     1509 +        nbytes = strlcpy(buf, onoff, *bufsize);
     1510 +        if (nbytes >= *bufsize) {
     1511 +                /* insufficient buffer space */
     1512 +                *bufsize = nbytes + 1;
     1513 +                return (IPADM_NO_BUFS);
     1514 +        }
     1515 +
     1516 +        return (IPADM_SUCCESS);
     1517 +}
     1518 +
     1519 +/*
     1520 + * Callback function that retrieves the value of the property `reqhost'
     1521 + * for the address object in `arg'.
     1522 + */
     1523 +/* ARGSUSED */
     1524 +static ipadm_status_t
     1525 +i_ipadm_get_reqhost(ipadm_handle_t iph, const void *arg,
     1526 +    ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t af,
     1527 +    uint_t valtype)
     1528 +{
     1529 +        ipadm_addrobj_t ipaddr = (ipadm_addrobj_t)arg;
     1530 +        const char *    reqhost = "";
     1531 +        size_t          nbytes;
     1532 +
     1533 +        switch (valtype) {
     1534 +        case MOD_PROP_DEFAULT:
     1535 +                break;
     1536 +        case MOD_PROP_ACTIVE:
     1537 +                if (ipaddr->ipadm_atype == IPADM_ADDR_DHCP)
     1538 +                        reqhost = ipaddr->ipadm_reqhost;
     1539 +                break;
     1540 +        default:
     1541 +                return (IPADM_INVALID_ARG);
     1542 +        }
     1543 +
     1544 +        nbytes = strlcpy(buf, reqhost, *bufsize);
     1545 +        if (nbytes >= *bufsize) {
     1546 +                /* insufficient buffer space */
     1547 +                *bufsize = nbytes + 1;
     1548 +                return (IPADM_NO_BUFS);
     1549 +        }
     1550 +
     1551 +        return (IPADM_SUCCESS);
     1552 +}
     1553 +
1374 1554  static ipadm_prop_desc_t *
1375 1555  i_ipadm_get_addrprop_desc(const char *pname)
1376 1556  {
1377 1557          int i;
1378 1558  
1379 1559          for (i = 0; ipadm_addrprop_table[i].ipd_name != NULL; i++) {
1380 1560                  if (strcmp(pname, ipadm_addrprop_table[i].ipd_name) == 0 ||
1381 1561                      (ipadm_addrprop_table[i].ipd_old_name != NULL &&
1382 1562                      strcmp(pname, ipadm_addrprop_table[i].ipd_old_name) == 0))
1383 1563                          return (&ipadm_addrprop_table[i]);
↓ open down ↓ 384 lines elided ↑ open up ↑
1768 1948  ipadm_get_addr(const ipadm_addrobj_t ipaddr, struct sockaddr_storage *addr)
1769 1949  {
1770 1950          if (ipaddr == NULL || ipaddr->ipadm_atype != IPADM_ADDR_STATIC ||
1771 1951              addr == NULL) {
1772 1952                  return (IPADM_INVALID_ARG);
1773 1953          }
1774 1954          *addr = ipaddr->ipadm_static_addr;
1775 1955  
1776 1956          return (IPADM_SUCCESS);
1777 1957  }
     1958 +
1778 1959  /*
1779 1960   * Set up tunnel destination address in ipaddr by contacting DNS.
1780 1961   * The function works similar to ipadm_set_addr().
1781 1962   * The dst_addr must resolve to exactly one address. IPADM_BAD_ADDR is returned
1782 1963   * if dst_addr resolves to more than one address. The caller has to verify
1783 1964   * that ipadm_static_addr and ipadm_static_dst_addr have the same ss_family
1784 1965   */
1785 1966  ipadm_status_t
1786 1967  ipadm_set_dst_addr(ipadm_addrobj_t ipaddr, const char *daddrstr, sa_family_t af)
1787 1968  {
↓ open down ↓ 106 lines elided ↑ open up ↑
1894 2075  ipadm_status_t
1895 2076  ipadm_set_wait_time(ipadm_addrobj_t ipaddr, int32_t wait)
1896 2077  {
1897 2078          if (ipaddr == NULL || ipaddr->ipadm_atype != IPADM_ADDR_DHCP)
1898 2079                  return (IPADM_INVALID_ARG);
1899 2080          ipaddr->ipadm_wait = wait;
1900 2081          return (IPADM_SUCCESS);
1901 2082  }
1902 2083  
1903 2084  /*
     2085 + * Sets the dhcp parameter `ipadm_reqhost' in the address object `ipaddr',
     2086 + * but validate any non-nil value using ipadm_is_valid_hostname() and also
     2087 + * check length.
     2088 + */
     2089 +ipadm_status_t
     2090 +ipadm_set_reqhost(ipadm_addrobj_t ipaddr, const char *reqhost)
     2091 +{
     2092 +        const size_t HNLEN = sizeof (ipaddr->ipadm_reqhost);
     2093 +
     2094 +        if (ipaddr == NULL || ipaddr->ipadm_atype != IPADM_ADDR_DHCP)
     2095 +                return (IPADM_INVALID_ARG);
     2096 +
     2097 +        if (ipadm_is_nil_hostname(reqhost))
     2098 +                *ipaddr->ipadm_reqhost = '\0';
     2099 +        else if (!ipadm_is_valid_hostname(reqhost))
     2100 +                return (IPADM_INVALID_ARG);
     2101 +        else if (strlcpy(ipaddr->ipadm_reqhost, reqhost, HNLEN) >= HNLEN)
     2102 +                return (IPADM_INVALID_ARG);
     2103 +        return (IPADM_SUCCESS);
     2104 +}
     2105 +
     2106 +/*
1904 2107   * Creates a placeholder for the `ipadm_aobjname' in the ipmgmtd `aobjmap'.
1905 2108   * If the `aobjname' already exists in the daemon's `aobjmap' then
1906 2109   * IPADM_ADDROBJ_EXISTS will be returned.
1907 2110   *
1908 2111   * If the libipadm consumer set `ipaddr.ipadm_aobjname[0]' to `\0', then the
1909 2112   * daemon will generate an `aobjname' for the given `ipaddr'.
1910 2113   */
1911 2114  ipadm_status_t
1912 2115  i_ipadm_lookupadd_addrobj(ipadm_handle_t iph, ipadm_addrobj_t ipaddr)
1913 2116  {
↓ open down ↓ 129 lines elided ↑ open up ↑
2043 2246          return (i_ipadm_create_addr(iph, &ipaddr, flags));
2044 2247  }
2045 2248  
2046 2249  /*
2047 2250   * Creates a dhcp address on the interface `ifname' based on the
2048 2251   * IPADM_ADDR_DHCP address object parameters from the nvlist `nvl'.
2049 2252   */
2050 2253  ipadm_status_t
2051 2254  i_ipadm_enable_dhcp(ipadm_handle_t iph, const char *ifname, nvlist_t *nvl)
2052 2255  {
2053      -        int32_t                 wait;
2054      -        boolean_t               primary;
2055      -        nvlist_t                *nvdhcp;
     2256 +        int32_t                 wait = IPADM_DHCP_WAIT_DEFAULT;
     2257 +        boolean_t               primary = B_FALSE;
     2258 +        nvlist_t                *nvdhcp = NULL;
2056 2259          nvpair_t                *nvp;
2057 2260          char                    *name;
2058 2261          struct ipadm_addrobj_s  ipaddr;
2059      -        char                    *aobjname;
     2262 +        char                    *aobjname = NULL, *reqhost = NULL;
2060 2263          int                     err = 0;
     2264 +        ipadm_status_t  ipadm_err = IPADM_SUCCESS;
2061 2265  
2062 2266          /* Extract the dhcp parameters */
2063 2267          for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL;
2064 2268              nvp = nvlist_next_nvpair(nvl, nvp)) {
2065 2269                  name = nvpair_name(nvp);
2066 2270                  if (strcmp(name, IPADM_NVP_DHCP) == 0)
2067 2271                          err = nvpair_value_nvlist(nvp, &nvdhcp);
2068 2272                  else if (strcmp(name, IPADM_NVP_AOBJNAME) == 0)
2069 2273                          err = nvpair_value_string(nvp, &aobjname);
     2274 +                else if (strcmp(name, IPADM_NVP_REQHOST) == 0)
     2275 +                        err = nvpair_value_string(nvp, &reqhost);
2070 2276                  if (err != 0)
2071 2277                          return (ipadm_errno2status(err));
2072 2278          }
2073 2279          for (nvp = nvlist_next_nvpair(nvdhcp, NULL); nvp != NULL;
2074 2280              nvp = nvlist_next_nvpair(nvdhcp, nvp)) {
2075 2281                  name = nvpair_name(nvp);
2076 2282                  if (strcmp(name, IPADM_NVP_WAIT) == 0)
2077 2283                          err = nvpair_value_int32(nvp, &wait);
2078 2284                  else if (strcmp(name, IPADM_NVP_PRIMARY) == 0)
2079 2285                          err = nvpair_value_boolean_value(nvp, &primary);
↓ open down ↓ 1 lines elided ↑ open up ↑
2081 2287                          return (ipadm_errno2status(err));
2082 2288          }
2083 2289  
2084 2290          /* Build the address object */
2085 2291          i_ipadm_init_addr(&ipaddr, ifname, aobjname, IPADM_ADDR_DHCP);
2086 2292          ipaddr.ipadm_primary = primary;
2087 2293          if (iph->iph_flags & IPH_INIT)
2088 2294                  ipaddr.ipadm_wait = 0;
2089 2295          else
2090 2296                  ipaddr.ipadm_wait = wait;
     2297 +        ipadm_err = ipadm_set_reqhost(&ipaddr, reqhost);
     2298 +        if (ipadm_err != IPADM_SUCCESS)
     2299 +                return ipadm_err;
2091 2300          ipaddr.ipadm_af = AF_INET;
2092 2301          return (i_ipadm_create_dhcp(iph, &ipaddr, IPADM_OPT_ACTIVE));
2093 2302  }
2094 2303  
2095 2304  /*
2096 2305   * Creates auto-configured addresses on the interface `ifname' based on
2097 2306   * the IPADM_ADDR_IPV6_ADDRCONF address object parameters from the nvlist `nvl'.
2098 2307   */
2099 2308  ipadm_status_t
2100 2309  i_ipadm_enable_addrconf(ipadm_handle_t iph, const char *ifname, nvlist_t *nvl)
↓ open down ↓ 622 lines elided ↑ open up ↑
2723 2932                          (void) strlcpy(legacy_addr.ipadm_aobjname,
2724 2933                              ipaddr->ipadm_aobjname,
2725 2934                              sizeof (legacy_addr.ipadm_aobjname));
2726 2935                          status = i_ipadm_get_addrobj(iph, &legacy_addr);
2727 2936                          if (status == IPADM_SUCCESS &&
2728 2937                              legacy_addr.ipadm_lifnum >= 0) {
2729 2938                                  return (status);
2730 2939                          }
2731 2940                  }
2732 2941                  status = i_ipadm_addr_persist(iph, ipaddr, default_prefixlen,
2733      -                    flags);
     2942 +                    flags, NULL);
2734 2943          }
2735 2944  ret:
2736 2945          if (status != IPADM_SUCCESS && !legacy)
2737 2946                  (void) i_ipadm_delete_addr(iph, ipaddr);
2738 2947          return (status);
2739 2948  }
2740 2949  
2741 2950  /*
2742 2951   * Removes the address object identified by `aobjname' from both active and
2743 2952   * persistent configuration. The address object will be removed from only
↓ open down ↓ 136 lines elided ↑ open up ↑
2880 3089          /*
2881 3090           * We do not undo the create-addr operation for IPADM_DHCP_IPC_TIMEOUT
2882 3091           * since it is only a soft error to indicate the caller that the lease
2883 3092           * might be required after the function returns.
2884 3093           */
2885 3094          if (status != IPADM_SUCCESS && status != IPADM_DHCP_IPC_TIMEOUT)
2886 3095                  goto fail;
2887 3096          dh_status = status;
2888 3097  
2889 3098          /* Persist the address object information in ipmgmtd. */
2890      -        status = i_ipadm_addr_persist(iph, addr, B_FALSE, flags);
     3099 +        status = i_ipadm_addr_persist(iph, addr, B_FALSE, flags, NULL);
2891 3100          if (status != IPADM_SUCCESS)
2892 3101                  goto fail;
2893 3102  
2894 3103          return (dh_status);
2895 3104  fail:
2896 3105          /* In case of error, delete the dhcp address */
2897 3106          (void) i_ipadm_delete_dhcp(iph, addr, B_TRUE);
2898 3107          return (status);
2899 3108  }
2900 3109  
↓ open down ↓ 39 lines elided ↑ open up ↑
2940 3149  /*
2941 3150   * Communicates with the dhcpagent to send a dhcp message of type `type'.
2942 3151   * It returns the dhcp error in `dhcperror' if a non-null pointer is provided
2943 3152   * in `dhcperror'.
2944 3153   */
2945 3154  static ipadm_status_t
2946 3155  i_ipadm_op_dhcp(ipadm_addrobj_t addr, dhcp_ipc_type_t type, int *dhcperror)
2947 3156  {
2948 3157          dhcp_ipc_request_t      *request;
2949 3158          dhcp_ipc_reply_t        *reply  = NULL;
     3159 +        dhcp_symbol_t           *entry = NULL;
     3160 +        dhcp_data_type_t        dtype = DHCP_TYPE_NONE;
     3161 +        void                            *d4o = NULL;
     3162 +        uint16_t                        d4olen = 0;
2950 3163          char                    ifname[LIFNAMSIZ];
2951 3164          int                     error;
2952 3165          int                     dhcp_timeout;
2953 3166  
2954 3167          /* Construct a message to the dhcpagent. */
2955 3168          bzero(&ifname, sizeof (ifname));
2956 3169          i_ipadm_addrobj2lifname(addr, ifname, sizeof (ifname));
2957 3170          if (addr->ipadm_primary)
2958 3171                  type |= DHCP_PRIMARY;
2959      -        request = dhcp_ipc_alloc_request(type, ifname, NULL, 0, DHCP_TYPE_NONE);
2960      -        if (request == NULL)
     3172 +
     3173 +        /* Set up a CD_HOSTNAME option, if applicable, to send through IPC */
     3174 +        switch (DHCP_IPC_CMD(type)) {
     3175 +        case DHCP_START:
     3176 +        case DHCP_EXTEND:
     3177 +                if (addr->ipadm_af == AF_INET && addr->ipadm_reqhost != NULL
     3178 +                    && *addr->ipadm_reqhost != '\0')
     3179 +                {
     3180 +                        entry = inittab_getbycode(ITAB_CAT_STANDARD, ITAB_CONS_INFO,
     3181 +                            CD_HOSTNAME);
     3182 +                        if (entry == NULL) {
     3183 +                                return (IPADM_FAILURE);
     3184 +                        } else {
     3185 +                                d4o = inittab_encode(entry, addr->ipadm_reqhost, &d4olen,
     3186 +                                    B_FALSE);
     3187 +                                free(entry);
     3188 +                                entry = NULL;
     3189 +                                if (d4o == NULL)
     3190 +                                        return (IPADM_FAILURE);
     3191 +                                dtype = DHCP_TYPE_OPTION;
     3192 +                        }
     3193 +                }
     3194 +                break;
     3195 +        default:
     3196 +                break;
     3197 +        }
     3198 +
     3199 +        request = dhcp_ipc_alloc_request(type, ifname, d4o, d4olen, dtype);
     3200 +        if (request == NULL) {
     3201 +                free(d4o);
2961 3202                  return (IPADM_NO_MEMORY);
     3203 +        }
2962 3204  
2963 3205          if (addr->ipadm_wait == IPADM_DHCP_WAIT_FOREVER)
2964 3206                  dhcp_timeout = DHCP_IPC_WAIT_FOREVER;
2965 3207          else if (addr->ipadm_wait == IPADM_DHCP_WAIT_DEFAULT)
2966 3208                  dhcp_timeout = DHCP_IPC_WAIT_DEFAULT;
2967 3209          else
2968 3210                  dhcp_timeout = addr->ipadm_wait;
2969 3211          /* Send the message to dhcpagent. */
2970 3212          error = dhcp_ipc_make_request(request, &reply, dhcp_timeout);
2971 3213          free(request);
     3214 +        free(d4o);
2972 3215          if (error == 0) {
2973 3216                  error = reply->return_code;
2974 3217                  free(reply);
2975 3218          }
2976 3219          if (error != 0) {
2977 3220                  if (dhcperror != NULL)
2978 3221                          *dhcperror = error;
2979 3222                  if (error != DHCP_IPC_E_TIMEOUT)
2980 3223                          return (IPADM_DHCP_IPC_ERROR);
2981 3224                  else if (dhcp_timeout != 0)
↓ open down ↓ 37 lines elided ↑ open up ↑
3019 3262   * Frees the structure allocated by ipadm_addr_info().
3020 3263   */
3021 3264  void
3022 3265  ipadm_free_addr_info(ipadm_addr_info_t *ainfo)
3023 3266  {
3024 3267          freeifaddrs((struct ifaddrs *)ainfo);
3025 3268  }
3026 3269  
3027 3270  /*
3028 3271   * Makes a door call to ipmgmtd to update its `aobjmap' with the address
3029      - * object in `ipaddr'. This door call also updates the persistent DB to
     3272 + * object in `ipaddr'. This door call also can update the persistent DB to
3030 3273   * remember address object to be recreated on next reboot or on an
3031 3274   * ipadm_enable_addr()/ipadm_enable_if() call.
3032 3275   */
3033 3276  ipadm_status_t
3034 3277  i_ipadm_addr_persist(ipadm_handle_t iph, const ipadm_addrobj_t ipaddr,
3035      -    boolean_t default_prefixlen, uint32_t flags)
     3278 +    boolean_t default_prefixlen, uint32_t flags, const char *propname)
3036 3279  {
3037 3280          char                    *aname = ipaddr->ipadm_aobjname;
3038 3281          nvlist_t                *nvl;
3039 3282          int                     err = 0;
3040 3283          ipadm_status_t          status;
3041      -        char                    pval[MAXPROPVALLEN];
3042 3284          uint_t                  pflags = 0;
3043      -        ipadm_prop_desc_t       *pdp = NULL;
3044 3285  
3045 3286          /*
3046 3287           * Construct the nvl to send to the door.
3047 3288           */
3048 3289          if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
3049 3290                  return (IPADM_NO_MEMORY);
3050 3291          if ((err = nvlist_add_string(nvl, IPADM_NVP_IFNAME,
3051 3292              ipaddr->ipadm_ifname)) != 0 ||
3052 3293              (err = nvlist_add_string(nvl, IPADM_NVP_AOBJNAME, aname)) != 0 ||
3053 3294              (err = nvlist_add_int32(nvl, IPADM_NVP_LIFNUM,
3054 3295              ipaddr->ipadm_lifnum)) != 0) {
3055 3296                  status = ipadm_errno2status(err);
3056 3297                  goto ret;
3057 3298          }
3058 3299          switch (ipaddr->ipadm_atype) {
3059 3300          case IPADM_ADDR_STATIC:
3060 3301                  status = i_ipadm_add_ipaddr2nvl(nvl, ipaddr);
3061 3302                  if (status != IPADM_SUCCESS)
3062 3303                          goto ret;
3063      -                (void) snprintf(pval, sizeof (pval), "%d",
3064      -                    ipaddr->ipadm_static_prefixlen);
3065 3304                  if (flags & IPADM_OPT_UP)
3066 3305                          err = nvlist_add_string(nvl, "up", "yes");
3067 3306                  else
3068 3307                          err = nvlist_add_string(nvl, "up", "no");
3069 3308                  status = ipadm_errno2status(err);
3070 3309                  break;
3071 3310          case IPADM_ADDR_DHCP:
3072 3311                  status = i_ipadm_add_dhcp2nvl(nvl, ipaddr->ipadm_primary,
3073 3312                      ipaddr->ipadm_wait);
     3313 +                if (status != IPADM_SUCCESS)
     3314 +                        goto ret;
     3315 +
     3316 +                /*
     3317 +                 * For purposes of updating the ipmgmtd cached representation of
     3318 +                 * reqhost (ipmgmt_am_reqhost), include a value here in `nvl', but
     3319 +                 * the value is actually fully persisted as a separate
     3320 +                 * i_ipadm_persist_propval below.
     3321 +                 */
     3322 +                err = nvlist_add_string(nvl, IPADM_NVP_REQHOST,
     3323 +                    ipaddr->ipadm_reqhost);
     3324 +                status = ipadm_errno2status(err);
3074 3325                  break;
3075 3326          case IPADM_ADDR_IPV6_ADDRCONF:
3076 3327                  status = i_ipadm_add_intfid2nvl(nvl, ipaddr);
3077 3328                  break;
3078 3329          }
3079 3330          if (status != IPADM_SUCCESS)
3080 3331                  goto ret;
3081 3332  
3082 3333          if (iph->iph_flags & IPH_INIT) {
3083 3334                  /*
↓ open down ↓ 3 lines elided ↑ open up ↑
3087 3338                   * IPADM_OPT_PERSIST is not set in their flags. They send
3088 3339                   * IPH_INIT in iph_flags, so that the address object will be
3089 3340                   * set as both IPMGMT_ACTIVE and IPMGMT_PERSIST.
3090 3341                   */
3091 3342                  pflags |= IPMGMT_INIT;
3092 3343          } else {
3093 3344                  if (flags & IPADM_OPT_ACTIVE)
3094 3345                          pflags |= IPMGMT_ACTIVE;
3095 3346                  if (flags & IPADM_OPT_PERSIST)
3096 3347                          pflags |= IPMGMT_PERSIST;
     3348 +                if (flags & IPADM_OPT_SET_PROPS)
     3349 +                        pflags |= IPMGMT_PROPS_ONLY;
3097 3350          }
3098 3351          status = i_ipadm_addr_persist_nvl(iph, nvl, pflags);
3099      -        /*
3100      -         * prefixlen is stored in a separate line in the DB and not along
3101      -         * with the address itself, since it is also an address property and
3102      -         * all address properties are stored in separate lines. We need to
3103      -         * persist the prefixlen by calling the function that persists
3104      -         * address properties.
3105      -         */
3106      -        if (status == IPADM_SUCCESS && !default_prefixlen &&
3107      -            ipaddr->ipadm_atype == IPADM_ADDR_STATIC &&
3108      -            (flags & IPADM_OPT_PERSIST)) {
3109      -                for (pdp = ipadm_addrprop_table; pdp->ipd_name != NULL; pdp++) {
3110      -                        if (strcmp("prefixlen", pdp->ipd_name) == 0)
3111      -                                break;
     3352 +
     3353 +        if (flags & IPADM_OPT_SET_PROPS) {
     3354 +                /*
     3355 +                 * Set PERSIST per IPADM_OPT_PROPS_PERSIST, and then un-set the
     3356 +                 * SET_PROPS bits.
     3357 +                 */
     3358 +                flags |= IPADM_OPT_ACTIVE;
     3359 +                if (flags & IPADM_OPT_PERSIST_PROPS)
     3360 +                        flags |= IPADM_OPT_PERSIST;
     3361 +                else
     3362 +                        flags &= ~IPADM_OPT_PERSIST;
     3363 +                flags &= ~(IPADM_OPT_SET_PROPS | IPADM_OPT_PERSIST_PROPS);
     3364 +        }
     3365 +
     3366 +        if (status == IPADM_SUCCESS && (flags & IPADM_OPT_PERSIST)) {
     3367 +                char    pbuf[MAXPROPVALLEN], *pval = NULL;
     3368 +                ipadm_prop_desc_t       *pdp = NULL;
     3369 +
     3370 +                /*
     3371 +                 * addprop properties are stored on separate lines in the DB and
     3372 +                 * not along with the address itself. Call the function that
     3373 +                 * persists address properties.
     3374 +                 */
     3375 +
     3376 +                switch (ipaddr->ipadm_atype) {
     3377 +                case IPADM_ADDR_STATIC:
     3378 +                        if (!default_prefixlen && (propname == NULL ||
     3379 +                            strcmp(propname, IPADM_NVP_PREFIXLEN) == 0)) {
     3380 +                                pdp = i_ipadm_get_addrprop_desc(IPADM_NVP_PREFIXLEN);
     3381 +                                (void) snprintf(pbuf, sizeof (pbuf), "%u",
     3382 +                                    ipaddr->ipadm_static_prefixlen);
     3383 +                                pval = pbuf;
     3384 +                        }
     3385 +                        break;
     3386 +                case IPADM_ADDR_DHCP:
     3387 +                        if (propname == NULL ||
     3388 +                            strcmp(propname, IPADM_NVP_REQHOST) == 0) {
     3389 +                                pdp = i_ipadm_get_addrprop_desc(IPADM_NVP_REQHOST);
     3390 +                                pval = ipaddr->ipadm_reqhost;
     3391 +                        }
     3392 +                        break;
     3393 +                default:
     3394 +                        break;
3112 3395                  }
3113      -                assert(pdp != NULL);
3114      -                status = i_ipadm_persist_propval(iph, pdp, pval, ipaddr, flags);
     3396 +
     3397 +                if (pval != NULL) {
     3398 +                        assert(pdp != NULL);
     3399 +                        status = i_ipadm_persist_propval(iph, pdp, pval,
     3400 +                                ipaddr, flags);
     3401 +                }
3115 3402          }
     3403 +
3116 3404  ret:
3117 3405          nvlist_free(nvl);
3118 3406          return (status);
3119 3407  }
3120 3408  
3121 3409  /*
3122 3410   * Makes the door call to ipmgmtd to store the address object in the
3123 3411   * nvlist `nvl'.
3124 3412   */
3125 3413  static ipadm_status_t
↓ open down ↓ 189 lines elided ↑ open up ↑
3315 3603  ipadm_refresh_addr(ipadm_handle_t iph, const char *aobjname,
3316 3604      uint32_t ipadm_flags)
3317 3605  {
3318 3606          ipadm_status_t          status = IPADM_SUCCESS;
3319 3607          uint64_t                flags;
3320 3608          struct ipadm_addrobj_s  ipaddr;
3321 3609          sa_family_t             af;
3322 3610          char                    lifname[LIFNAMSIZ];
3323 3611          boolean_t               inform =
3324 3612              ((ipadm_flags & IPADM_OPT_INFORM) != 0);
3325      -        int                     dherr;
3326 3613  
3327 3614          /* check for solaris.network.interface.config authorization */
3328 3615          if (!ipadm_check_auth())
3329 3616                  return (IPADM_EAUTH);
3330 3617  
3331 3618          bzero(&ipaddr, sizeof (ipaddr));
3332 3619          /* validate input */
3333 3620          if (aobjname == NULL || strlcpy(ipaddr.ipadm_aobjname, aobjname,
3334 3621              IPADM_AOBJSIZ) >= IPADM_AOBJSIZ) {
3335 3622                  return (IPADM_INVALID_ARG);
↓ open down ↓ 21 lines elided ↑ open up ↑
3357 3644                          if (dhcp_start_agent(DHCP_IPC_MAX_WAIT) == -1)
3358 3645                                  return (IPADM_DHCP_START_ERROR);
3359 3646  
3360 3647                          ipaddr.ipadm_wait = IPADM_DHCP_WAIT_DEFAULT;
3361 3648                          return (i_ipadm_op_dhcp(&ipaddr, DHCP_INFORM, NULL));
3362 3649                  }
3363 3650                  if (!(flags & IFF_DUPLICATE))
3364 3651                          return (IPADM_SUCCESS);
3365 3652                  status = i_ipadm_set_flags(iph, lifname, af, IFF_UP, 0);
3366 3653          } else if (ipaddr.ipadm_atype == IPADM_ADDR_DHCP) {
3367      -                status = i_ipadm_op_dhcp(&ipaddr, DHCP_EXTEND, &dherr);
3368      -                /*
3369      -                 * Restart the dhcp address negotiation with server if no
3370      -                 * address has been acquired yet.
3371      -                 */
3372      -                if (status != IPADM_SUCCESS && dherr == DHCP_IPC_E_OUTSTATE) {
3373      -                        ipaddr.ipadm_wait = IPADM_DHCP_WAIT_DEFAULT;
3374      -                        status = i_ipadm_op_dhcp(&ipaddr, DHCP_START, NULL);
3375      -                }
     3654 +                status = i_ipadm_refresh_dhcp(&ipaddr);
3376 3655          } else {
3377 3656                  status = IPADM_NOTSUP;
3378 3657          }
3379 3658          return (status);
3380 3659  }
3381 3660  
3382 3661  /*
     3662 + * This is called from ipadm_refresh_addr() and i_ipadm_set_reqhost() to
     3663 + * send a DHCP_EXTEND message and possibly a DHCP_START message
     3664 + * to the dhcpagent.
     3665 + */
     3666 +static ipadm_status_t
     3667 +i_ipadm_refresh_dhcp(ipadm_addrobj_t ipaddr)
     3668 +{
     3669 +        ipadm_status_t          status;
     3670 +        int                     dherr;
     3671 +
     3672 +        status = i_ipadm_op_dhcp(ipaddr, DHCP_EXTEND, &dherr);
     3673 +        /*
     3674 +         * Restart the dhcp address negotiation with server if no
     3675 +         * address has been acquired yet.
     3676 +         */
     3677 +        if (status != IPADM_SUCCESS && dherr == DHCP_IPC_E_OUTSTATE) {
     3678 +                ipaddr->ipadm_wait = IPADM_DHCP_WAIT_DEFAULT;
     3679 +                status = i_ipadm_op_dhcp(ipaddr, DHCP_START, NULL);
     3680 +        }
     3681 +
     3682 +        return (status);
     3683 +}
     3684 +
     3685 +/*
3383 3686   * This is called from ipadm_create_addr() to validate the address parameters.
3384 3687   * It does the following steps:
3385 3688   * 1. Validates the interface name.
3386 3689   * 2. Verifies that the interface is not an IPMP meta-interface or an
3387 3690   *      underlying interface.
3388 3691   * 3. In case of a persistent operation, verifies that the interface
3389 3692   *      is persistent. Returns error if interface is not enabled but
3390 3693   *      is in persistent config.
3391 3694   * 4. Verifies that the destination address is not set or the address type is
3392 3695   *      not DHCP or ADDRCONF when the interface is a loopback interface.
↓ open down ↓ 94 lines elided ↑ open up ↑
3487 3790                  }
3488 3791                  break;
3489 3792          default:
3490 3793                  return (IPADM_INVALID_ARG);
3491 3794          }
3492 3795  
3493 3796          return (IPADM_SUCCESS);
3494 3797  }
3495 3798  
3496 3799  ipadm_status_t
3497      -i_ipadm_merge_prefixlen_from_nvl(nvlist_t *invl, nvlist_t *onvl,
     3800 +i_ipadm_merge_addrprops_from_nvl(nvlist_t *invl, nvlist_t *onvl,
3498 3801      const char *aobjname)
3499 3802  {
3500      -        nvpair_t        *nvp, *prefixnvp;
     3803 +        const char * const      ADDRPROPS[] =
     3804 +            { IPADM_NVP_PREFIXLEN, IPADM_NVP_REQHOST };
     3805 +        const size_t            ADDRPROPSLEN =
     3806 +            sizeof (ADDRPROPS) / sizeof (*ADDRPROPS);
     3807 +        nvpair_t        *nvp, *propnvp;
3501 3808          nvlist_t        *tnvl;
3502 3809          char            *aname;
     3810 +        const char      *propname;
     3811 +        size_t          i;
3503 3812          int             err;
3504 3813  
3505      -        for (nvp = nvlist_next_nvpair(invl, NULL); nvp != NULL;
3506      -            nvp = nvlist_next_nvpair(invl, nvp)) {
3507      -                if (nvpair_value_nvlist(nvp, &tnvl) == 0 &&
3508      -                    nvlist_exists(tnvl, IPADM_NVP_PREFIXLEN) &&
3509      -                    nvlist_lookup_string(tnvl, IPADM_NVP_AOBJNAME,
3510      -                    &aname) == 0 && strcmp(aname, aobjname) == 0) {
3511      -                        /* prefixlen exists for given address object */
3512      -                        (void) nvlist_lookup_nvpair(tnvl, IPADM_NVP_PREFIXLEN,
3513      -                            &prefixnvp);
3514      -                        err = nvlist_add_nvpair(onvl, prefixnvp);
3515      -                        if (err == 0) {
3516      -                                err = nvlist_remove(invl, nvpair_name(nvp),
3517      -                                    nvpair_type(nvp));
     3814 +        for (i = 0; i < ADDRPROPSLEN; ++i) {
     3815 +                propname = ADDRPROPS[i];
     3816 +
     3817 +                for (nvp = nvlist_next_nvpair(invl, NULL); nvp != NULL;
     3818 +                        nvp = nvlist_next_nvpair(invl, nvp)) {
     3819 +                        if (nvpair_value_nvlist(nvp, &tnvl) == 0 &&
     3820 +                            nvlist_exists(tnvl, propname) &&
     3821 +                            nvlist_lookup_string(tnvl, IPADM_NVP_AOBJNAME,
     3822 +                            &aname) == 0 && strcmp(aname, aobjname) == 0) {
     3823 +
     3824 +                                /* property named `propname' exists for given aobj */
     3825 +                                (void) nvlist_lookup_nvpair(tnvl, propname, &propnvp);
     3826 +                                err = nvlist_add_nvpair(onvl, propnvp);
     3827 +                                if (err == 0) {
     3828 +                                        err = nvlist_remove(invl, nvpair_name(nvp),
     3829 +                                            nvpair_type(nvp));
     3830 +                                }
     3831 +                                if (err != 0)
     3832 +                                        return (ipadm_errno2status(err));
     3833 +                                break;
3518 3834                          }
3519      -                        return (ipadm_errno2status(err));
3520 3835                  }
3521 3836          }
3522 3837          return (IPADM_SUCCESS);
3523 3838  }
3524 3839  
3525 3840  /*
3526 3841   * Re-enables the address object `aobjname' based on the saved
3527 3842   * configuration for `aobjname'.
3528 3843   */
3529 3844  ipadm_status_t
↓ open down ↓ 28 lines elided ↑ open up ↑
3558 3873                  return (status);
3559 3874  
3560 3875          assert(addrnvl != NULL);
3561 3876  
3562 3877          for (nvp = nvlist_next_nvpair(addrnvl, NULL); nvp != NULL;
3563 3878              nvp = nvlist_next_nvpair(addrnvl, nvp)) {
3564 3879                  if (nvpair_value_nvlist(nvp, &nvl) != 0)
3565 3880                          continue;
3566 3881  
3567 3882                  if (nvlist_exists(nvl, IPADM_NVP_IPV4ADDR) ||
3568      -                    nvlist_exists(nvl, IPADM_NVP_IPV6ADDR)) {
3569      -                        status = i_ipadm_merge_prefixlen_from_nvl(addrnvl, nvl,
     3883 +                    nvlist_exists(nvl, IPADM_NVP_IPV6ADDR) ||
     3884 +                    nvlist_exists(nvl, IPADM_NVP_DHCP)) {
     3885 +                        status = i_ipadm_merge_addrprops_from_nvl(addrnvl, nvl,
3570 3886                              aobjname);
3571 3887                          if (status != IPADM_SUCCESS)
3572 3888                                  continue;
3573 3889                  }
3574 3890                  iph->iph_flags |= IPH_INIT;
3575 3891                  status = i_ipadm_init_addrobj(iph, nvl);
3576 3892                  iph->iph_flags &= ~IPH_INIT;
3577 3893                  if (status != IPADM_SUCCESS)
3578 3894                          break;
3579 3895          }
↓ open down ↓ 17 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX