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


   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
  23  * Copyright (c) 2013 by Delphix. All rights reserved.

  24  */
  25 
  26 /*
  27  * This file contains functions for address management such as creating
  28  * an address, deleting an address, enabling an address, disabling an
  29  * address, bringing an address down or up, setting/getting properties
  30  * on an address object and listing address information
  31  * for all addresses in active as well as persistent configuration.
  32  */
  33 #include <sys/types.h>
  34 #include <sys/socket.h>

  35 #include <netdb.h>
  36 #include <inet/ip.h>
  37 #include <string.h>
  38 #include <strings.h>
  39 #include <assert.h>
  40 #include <sys/sockio.h>
  41 #include <errno.h>
  42 #include <unistd.h>
  43 #include <stropts.h>
  44 #include <zone.h>
  45 #include <netinet/in.h>
  46 #include <arpa/inet.h>
  47 #include <fcntl.h>
  48 #include <ctype.h>
  49 #include <dhcpagent_util.h>
  50 #include <dhcpagent_ipc.h>


  51 #include <ipadm_ndpd.h>
  52 #include <libdladm.h>
  53 #include <libdllink.h>
  54 #include <libdliptun.h>
  55 #include <ifaddrs.h>
  56 #include "libipadm_impl.h"
  57 
  58 #define SIN6(a)         ((struct sockaddr_in6 *)a)
  59 #define SIN(a)          ((struct sockaddr_in *)a)
  60 
  61 static ipadm_status_t   i_ipadm_create_addr(ipadm_handle_t, ipadm_addrobj_t,
  62                             uint32_t);
  63 static ipadm_status_t   i_ipadm_create_dhcp(ipadm_handle_t, ipadm_addrobj_t,
  64                             uint32_t);
  65 static ipadm_status_t   i_ipadm_delete_dhcp(ipadm_handle_t, ipadm_addrobj_t,
  66                             boolean_t);

  67 static ipadm_status_t   i_ipadm_get_db_addr(ipadm_handle_t, const char *,
  68                             const char *, nvlist_t **);
  69 static ipadm_status_t   i_ipadm_op_dhcp(ipadm_addrobj_t, dhcp_ipc_type_t,
  70                             int *);
  71 static ipadm_status_t   i_ipadm_validate_create_addr(ipadm_handle_t,
  72                             ipadm_addrobj_t, uint32_t);
  73 static ipadm_status_t   i_ipadm_addr_persist_nvl(ipadm_handle_t, nvlist_t *,
  74                             uint32_t);
  75 static ipadm_status_t   i_ipadm_get_default_prefixlen(struct sockaddr_storage *,
  76                             uint32_t *);
  77 static ipadm_status_t   i_ipadm_get_static_addr_db(ipadm_handle_t,
  78                             ipadm_addrobj_t);
  79 static boolean_t        i_ipadm_is_user_aobjname_valid(const char *);

  80 
  81 /*
  82  * Callback functions to retrieve property values from the kernel. These
  83  * functions, when required, translate the values from the kernel to a format
  84  * suitable for printing. They also retrieve DEFAULT, PERM and POSSIBLE values
  85  * for a given property.
  86  */
  87 static ipadm_pd_getf_t  i_ipadm_get_prefixlen, i_ipadm_get_addr_flag,
  88                         i_ipadm_get_zone, i_ipadm_get_broadcast;

  89 
  90 /*
  91  * Callback functions to set property values. These functions translate the
  92  * values to a format suitable for kernel consumption, allocate the necessary
  93  * ioctl buffers and then invoke ioctl().

  94  */
  95 static ipadm_pd_setf_t  i_ipadm_set_prefixlen, i_ipadm_set_addr_flag,
  96                         i_ipadm_set_zone;
  97 



  98 /* address properties description table */
  99 ipadm_prop_desc_t ipadm_addrprop_table[] = {
 100         { "broadcast", NULL, IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE, 0,
 101             NULL, NULL, i_ipadm_get_broadcast },
 102 
 103         { "deprecated", NULL, IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE, 0,
 104             i_ipadm_set_addr_flag, i_ipadm_get_onoff,
 105             i_ipadm_get_addr_flag },
 106 
 107         { "prefixlen", NULL, IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE, 0,
 108             i_ipadm_set_prefixlen, i_ipadm_get_prefixlen,
 109             i_ipadm_get_prefixlen },
 110 








 111         { "private", NULL, IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE, 0,
 112             i_ipadm_set_addr_flag, i_ipadm_get_onoff, i_ipadm_get_addr_flag },
 113 



 114         { "transmit", NULL, IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE, 0,
 115             i_ipadm_set_addr_flag, i_ipadm_get_onoff, i_ipadm_get_addr_flag },
 116 
 117         { "zone", NULL, IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE, 0,
 118             i_ipadm_set_zone, NULL, i_ipadm_get_zone },
 119 
 120         { NULL, NULL, 0, 0, 0, NULL, NULL, NULL }
 121 };
 122 
 123 static ipadm_prop_desc_t up_addrprop = { "up", NULL, IPADMPROP_CLASS_ADDR,
 124                                         MOD_PROTO_NONE, 0, NULL, NULL, NULL };
 125 
 126 /*
 127  * Helper function that initializes the `ipadm_ifname', `ipadm_aobjname', and
 128  * `ipadm_atype' fields of the given `ipaddr'.
 129  */
 130 void
 131 i_ipadm_init_addr(ipadm_addrobj_t ipaddr, const char *ifname,
 132     const char *aobjname, ipadm_addr_type_t atype)
 133 {


 184         ipmgmt_aobjop_arg_t     larg;
 185         ipmgmt_aobjop_rval_t    rval, *rvalp;
 186         int                     err = 0;
 187 
 188         /* populate the door_call argument structure */
 189         larg.ia_cmd = IPMGMT_CMD_AOBJNAME2ADDROBJ;
 190         (void) strlcpy(larg.ia_aobjname, ipaddr->ipadm_aobjname,
 191             sizeof (larg.ia_aobjname));
 192 
 193         rvalp = &rval;
 194         err = ipadm_door_call(iph, &larg, sizeof (larg), (void **)&rvalp,
 195             sizeof (rval), B_FALSE);
 196         if (err != 0)
 197                 return (ipadm_errno2status(err));
 198         (void) strlcpy(ipaddr->ipadm_ifname, rval.ir_ifname,
 199             sizeof (ipaddr->ipadm_ifname));
 200         ipaddr->ipadm_lifnum = rval.ir_lnum;
 201         ipaddr->ipadm_atype = rval.ir_atype;
 202         ipaddr->ipadm_af = rval.ir_family;
 203         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));








 207         }
 208 
 209         return (IPADM_SUCCESS);
 210 }
 211 
 212 /*
 213  * Retrieves the static address (IPv4 or IPv6) for the given address object
 214  * in `ipaddr' from persistent DB.
 215  */
 216 static ipadm_status_t
 217 i_ipadm_get_static_addr_db(ipadm_handle_t iph, ipadm_addrobj_t ipaddr)
 218 {
 219         ipadm_status_t          status;
 220         nvlist_t                *onvl;
 221         nvlist_t                *anvl = NULL;
 222         nvlist_t                *nvladdr;
 223         nvpair_t                *nvp;
 224         char                    *name;
 225         char                    *aobjname = ipaddr->ipadm_aobjname;
 226         char                    *sname;


1024                         /* zone must be ready or running */
1025                         if ((zoneid = getzoneidbyname(pval)) == -1)
1026                                 return (ipadm_errno2status(errno));
1027                 }
1028         } else {
1029                 return (IPADM_INVALID_ARG);
1030         }
1031 
1032         s = (af == AF_INET ? iph->iph_sock : iph->iph_sock6);
1033         bzero(&lifr, sizeof (lifr));
1034         i_ipadm_addrobj2lifname((ipadm_addrobj_t)arg, lifr.lifr_name,
1035             sizeof (lifr.lifr_name));
1036         lifr.lifr_zoneid = zoneid;
1037         if (ioctl(s, SIOCSLIFZONE, (caddr_t)&lifr) < 0)
1038                 return (ipadm_errno2status(errno));
1039 
1040         return (IPADM_SUCCESS);
1041 }
1042 
1043 /*














































































1044  * Callback function that gets the property `broadcast' for the address
1045  * object in `arg'.
1046  */
1047 /* ARGSUSED */
1048 static ipadm_status_t
1049 i_ipadm_get_broadcast(ipadm_handle_t iph, const void *arg,
1050     ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t af,
1051     uint_t valtype)
1052 {
1053         struct sockaddr_in      *sin;
1054         struct lifreq           lifr;
1055         char                    lifname[LIFNAMSIZ];
1056         ipadm_addrobj_t         ipaddr = (ipadm_addrobj_t)arg;
1057         ipadm_status_t          status;
1058         size_t                  nbytes = 0;
1059         uint64_t                ifflags = 0;
1060 
1061         i_ipadm_addrobj2lifname(ipaddr, lifname, sizeof (lifname));
1062         if (ipaddr->ipadm_flags & IPMGMT_ACTIVE) {
1063                 status = i_ipadm_get_flags(iph, lifname, af, &ifflags);


1354                         nbytes = snprintf(buf, *bufsize, "%s", "all-zones");
1355                 } else if (getzonenamebyid(lifr.lifr_zoneid, zone_name,
1356                     sizeof (zone_name)) < 0) {
1357                         return (ipadm_errno2status(errno));
1358                 } else {
1359                         nbytes = snprintf(buf, *bufsize, "%s", zone_name);
1360                 }
1361                 break;
1362         default:
1363                 return (IPADM_INVALID_ARG);
1364         }
1365         if (nbytes >= *bufsize) {
1366                 /* insufficient buffer space */
1367                 *bufsize = nbytes + 1;
1368                 return (IPADM_NO_BUFS);
1369         }
1370 
1371         return (IPADM_SUCCESS);
1372 }
1373 








































































1374 static ipadm_prop_desc_t *
1375 i_ipadm_get_addrprop_desc(const char *pname)
1376 {
1377         int i;
1378 
1379         for (i = 0; ipadm_addrprop_table[i].ipd_name != NULL; i++) {
1380                 if (strcmp(pname, ipadm_addrprop_table[i].ipd_name) == 0 ||
1381                     (ipadm_addrprop_table[i].ipd_old_name != NULL &&
1382                     strcmp(pname, ipadm_addrprop_table[i].ipd_old_name) == 0))
1383                         return (&ipadm_addrprop_table[i]);
1384         }
1385         return (NULL);
1386 }
1387 
1388 /*
1389  * Gets the value of the given address property `pname' for the address
1390  * object with name `aobjname'.
1391  */
1392 ipadm_status_t
1393 ipadm_get_addrprop(ipadm_handle_t iph, const char *pname, char *buf,


1758                 ipaddr->ipadm_static_prefixlen = prefixlen;
1759         }
1760         return (status);
1761 }
1762 
1763 /*
1764  * Gets the static source address from the address object in `ipaddr'.
1765  * Memory for `addr' should be already allocated by the caller.
1766  */
1767 ipadm_status_t
1768 ipadm_get_addr(const ipadm_addrobj_t ipaddr, struct sockaddr_storage *addr)
1769 {
1770         if (ipaddr == NULL || ipaddr->ipadm_atype != IPADM_ADDR_STATIC ||
1771             addr == NULL) {
1772                 return (IPADM_INVALID_ARG);
1773         }
1774         *addr = ipaddr->ipadm_static_addr;
1775 
1776         return (IPADM_SUCCESS);
1777 }

1778 /*
1779  * Set up tunnel destination address in ipaddr by contacting DNS.
1780  * The function works similar to ipadm_set_addr().
1781  * The dst_addr must resolve to exactly one address. IPADM_BAD_ADDR is returned
1782  * if dst_addr resolves to more than one address. The caller has to verify
1783  * that ipadm_static_addr and ipadm_static_dst_addr have the same ss_family
1784  */
1785 ipadm_status_t
1786 ipadm_set_dst_addr(ipadm_addrobj_t ipaddr, const char *daddrstr, sa_family_t af)
1787 {
1788         ipadm_status_t  status;
1789 
1790         /* mask lengths are not meaningful for point-to-point interfaces. */
1791         if (strchr(daddrstr, '/') != NULL)
1792                 return (IPADM_BAD_ADDR);
1793 
1794         status = i_ipadm_resolve_addr(daddrstr, af,
1795             &ipaddr->ipadm_static_dst_addr);
1796         if (status == IPADM_SUCCESS) {
1797                 (void) strlcpy(ipaddr->ipadm_static_dname, daddrstr,


1884  * Sets the dhcp parameter `ipadm_wait' in the address object `ipaddr'.
1885  * This field is used during the address creation with address type
1886  * IPADM_ADDR_DHCP. It specifies how long the API ipadm_create_addr()
1887  * should wait before returning while the dhcp address is being acquired
1888  * by the dhcpagent.
1889  * Possible values:
1890  * - IPADM_DHCP_WAIT_FOREVER : Do not return until dhcpagent returns.
1891  * - IPADM_DHCP_WAIT_DEFAULT : Wait a default amount of time before returning.
1892  * - <integer>       : Wait the specified number of seconds before returning.
1893  */
1894 ipadm_status_t
1895 ipadm_set_wait_time(ipadm_addrobj_t ipaddr, int32_t wait)
1896 {
1897         if (ipaddr == NULL || ipaddr->ipadm_atype != IPADM_ADDR_DHCP)
1898                 return (IPADM_INVALID_ARG);
1899         ipaddr->ipadm_wait = wait;
1900         return (IPADM_SUCCESS);
1901 }
1902 
1903 /*






















1904  * Creates a placeholder for the `ipadm_aobjname' in the ipmgmtd `aobjmap'.
1905  * If the `aobjname' already exists in the daemon's `aobjmap' then
1906  * IPADM_ADDROBJ_EXISTS will be returned.
1907  *
1908  * If the libipadm consumer set `ipaddr.ipadm_aobjname[0]' to `\0', then the
1909  * daemon will generate an `aobjname' for the given `ipaddr'.
1910  */
1911 ipadm_status_t
1912 i_ipadm_lookupadd_addrobj(ipadm_handle_t iph, ipadm_addrobj_t ipaddr)
1913 {
1914         ipmgmt_aobjop_arg_t     larg;
1915         ipmgmt_aobjop_rval_t    rval, *rvalp;
1916         int                     err;
1917 
1918         bzero(&larg, sizeof (larg));
1919         larg.ia_cmd = IPMGMT_CMD_ADDROBJ_LOOKUPADD;
1920         (void) strlcpy(larg.ia_aobjname, ipaddr->ipadm_aobjname,
1921             sizeof (larg.ia_aobjname));
1922         (void) strlcpy(larg.ia_ifname, ipaddr->ipadm_ifname,
1923             sizeof (larg.ia_ifname));


2033                 status = ipadm_set_addr(&ipaddr, sname, af);
2034         }
2035         if (status != IPADM_SUCCESS)
2036                 return (status);
2037 
2038         if (dname != NULL) {
2039                 status = ipadm_set_dst_addr(&ipaddr, dname, af);
2040                 if (status != IPADM_SUCCESS)
2041                         return (status);
2042         }
2043         return (i_ipadm_create_addr(iph, &ipaddr, flags));
2044 }
2045 
2046 /*
2047  * Creates a dhcp address on the interface `ifname' based on the
2048  * IPADM_ADDR_DHCP address object parameters from the nvlist `nvl'.
2049  */
2050 ipadm_status_t
2051 i_ipadm_enable_dhcp(ipadm_handle_t iph, const char *ifname, nvlist_t *nvl)
2052 {
2053         int32_t                 wait;
2054         boolean_t               primary;
2055         nvlist_t                *nvdhcp;
2056         nvpair_t                *nvp;
2057         char                    *name;
2058         struct ipadm_addrobj_s  ipaddr;
2059         char                    *aobjname;
2060         int                     err = 0;

2061 
2062         /* Extract the dhcp parameters */
2063         for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL;
2064             nvp = nvlist_next_nvpair(nvl, nvp)) {
2065                 name = nvpair_name(nvp);
2066                 if (strcmp(name, IPADM_NVP_DHCP) == 0)
2067                         err = nvpair_value_nvlist(nvp, &nvdhcp);
2068                 else if (strcmp(name, IPADM_NVP_AOBJNAME) == 0)
2069                         err = nvpair_value_string(nvp, &aobjname);


2070                 if (err != 0)
2071                         return (ipadm_errno2status(err));
2072         }
2073         for (nvp = nvlist_next_nvpair(nvdhcp, NULL); nvp != NULL;
2074             nvp = nvlist_next_nvpair(nvdhcp, nvp)) {
2075                 name = nvpair_name(nvp);
2076                 if (strcmp(name, IPADM_NVP_WAIT) == 0)
2077                         err = nvpair_value_int32(nvp, &wait);
2078                 else if (strcmp(name, IPADM_NVP_PRIMARY) == 0)
2079                         err = nvpair_value_boolean_value(nvp, &primary);
2080                 if (err != 0)
2081                         return (ipadm_errno2status(err));
2082         }
2083 
2084         /* Build the address object */
2085         i_ipadm_init_addr(&ipaddr, ifname, aobjname, IPADM_ADDR_DHCP);
2086         ipaddr.ipadm_primary = primary;
2087         if (iph->iph_flags & IPH_INIT)
2088                 ipaddr.ipadm_wait = 0;
2089         else
2090                 ipaddr.ipadm_wait = wait;



2091         ipaddr.ipadm_af = AF_INET;
2092         return (i_ipadm_create_dhcp(iph, &ipaddr, IPADM_OPT_ACTIVE));
2093 }
2094 
2095 /*
2096  * Creates auto-configured addresses on the interface `ifname' based on
2097  * the IPADM_ADDR_IPV6_ADDRCONF address object parameters from the nvlist `nvl'.
2098  */
2099 ipadm_status_t
2100 i_ipadm_enable_addrconf(ipadm_handle_t iph, const char *ifname, nvlist_t *nvl)
2101 {
2102         struct ipadm_addrobj_s  ipaddr;
2103         char            *stateful = NULL, *stateless = NULL;
2104         uint_t          n;
2105         uint8_t         *addr6 = NULL;
2106         uint32_t        intfidlen = 0;
2107         char            *aobjname;
2108         nvlist_t        *nvaddr;
2109         nvpair_t        *nvp;
2110         char            *name;


2713         if (status == IPADM_SUCCESS && !is_boot) {
2714                 /*
2715                  * For IPH_LEGACY, we might be modifying the address on
2716                  * an address object that already exists e.g. by doing
2717                  * "ifconfig bge0:1 <addr>; ifconfig bge0:1 <newaddr>"
2718                  * So, we need to store the object only if it does not
2719                  * already exist in ipmgmtd.
2720                  */
2721                 if (legacy) {
2722                         bzero(&legacy_addr, sizeof (legacy_addr));
2723                         (void) strlcpy(legacy_addr.ipadm_aobjname,
2724                             ipaddr->ipadm_aobjname,
2725                             sizeof (legacy_addr.ipadm_aobjname));
2726                         status = i_ipadm_get_addrobj(iph, &legacy_addr);
2727                         if (status == IPADM_SUCCESS &&
2728                             legacy_addr.ipadm_lifnum >= 0) {
2729                                 return (status);
2730                         }
2731                 }
2732                 status = i_ipadm_addr_persist(iph, ipaddr, default_prefixlen,
2733                     flags);
2734         }
2735 ret:
2736         if (status != IPADM_SUCCESS && !legacy)
2737                 (void) i_ipadm_delete_addr(iph, ipaddr);
2738         return (status);
2739 }
2740 
2741 /*
2742  * Removes the address object identified by `aobjname' from both active and
2743  * persistent configuration. The address object will be removed from only
2744  * active configuration if IPH_LEGACY is set in `iph->iph_flags'.
2745  *
2746  * If the address type is IPADM_ADDR_STATIC or IPADM_ADDR_DHCP, the address
2747  * in the address object will be removed from the physical interface.
2748  * If the address type is IPADM_ADDR_DHCP, the flag IPADM_OPT_RELEASE specifies
2749  * whether the lease should be released. If IPADM_OPT_RELEASE is not
2750  * specified, the lease will be dropped. This option is not supported
2751  * for other address types.
2752  *
2753  * If the address type is IPADM_ADDR_IPV6_ADDRCONF, the link-local address and


2870          */
2871         if (!(iph->iph_flags & IPH_INIT)) {
2872                 status = i_ipadm_setlifnum_addrobj(iph, addr);
2873                 if (status == IPADM_ADDROBJ_EXISTS)
2874                         goto retry;
2875                 if (status != IPADM_SUCCESS)
2876                         return (status);
2877         }
2878         /* Send DHCP_START to the dhcpagent. */
2879         status = i_ipadm_op_dhcp(addr, DHCP_START, NULL);
2880         /*
2881          * We do not undo the create-addr operation for IPADM_DHCP_IPC_TIMEOUT
2882          * since it is only a soft error to indicate the caller that the lease
2883          * might be required after the function returns.
2884          */
2885         if (status != IPADM_SUCCESS && status != IPADM_DHCP_IPC_TIMEOUT)
2886                 goto fail;
2887         dh_status = status;
2888 
2889         /* Persist the address object information in ipmgmtd. */
2890         status = i_ipadm_addr_persist(iph, addr, B_FALSE, flags);
2891         if (status != IPADM_SUCCESS)
2892                 goto fail;
2893 
2894         return (dh_status);
2895 fail:
2896         /* In case of error, delete the dhcp address */
2897         (void) i_ipadm_delete_dhcp(iph, addr, B_TRUE);
2898         return (status);
2899 }
2900 
2901 /*
2902  * Releases/drops the dhcp lease on the logical interface in the address
2903  * object `addr'. If `release' is set to B_FALSE, the lease will be dropped.
2904  */
2905 static ipadm_status_t
2906 i_ipadm_delete_dhcp(ipadm_handle_t iph, ipadm_addrobj_t addr, boolean_t release)
2907 {
2908         ipadm_status_t  status;
2909         int             dherr;
2910 


2930                 bzero(&lifr, sizeof (lifr));
2931                 i_ipadm_addrobj2lifname(addr, lifr.lifr_name,
2932                     sizeof (lifr.lifr_name));
2933                 if (ioctl(iph->iph_sock, SIOCLIFREMOVEIF, (caddr_t)&lifr) < 0)
2934                         return (ipadm_errno2status(errno));
2935         }
2936 
2937         return (IPADM_SUCCESS);
2938 }
2939 
2940 /*
2941  * Communicates with the dhcpagent to send a dhcp message of type `type'.
2942  * It returns the dhcp error in `dhcperror' if a non-null pointer is provided
2943  * in `dhcperror'.
2944  */
2945 static ipadm_status_t
2946 i_ipadm_op_dhcp(ipadm_addrobj_t addr, dhcp_ipc_type_t type, int *dhcperror)
2947 {
2948         dhcp_ipc_request_t      *request;
2949         dhcp_ipc_reply_t        *reply  = NULL;




2950         char                    ifname[LIFNAMSIZ];
2951         int                     error;
2952         int                     dhcp_timeout;
2953 
2954         /* Construct a message to the dhcpagent. */
2955         bzero(&ifname, sizeof (ifname));
2956         i_ipadm_addrobj2lifname(addr, ifname, sizeof (ifname));
2957         if (addr->ipadm_primary)
2958                 type |= DHCP_PRIMARY;
2959         request = dhcp_ipc_alloc_request(type, ifname, NULL, 0, DHCP_TYPE_NONE);
2960         if (request == NULL)




























2961                 return (IPADM_NO_MEMORY);

2962 
2963         if (addr->ipadm_wait == IPADM_DHCP_WAIT_FOREVER)
2964                 dhcp_timeout = DHCP_IPC_WAIT_FOREVER;
2965         else if (addr->ipadm_wait == IPADM_DHCP_WAIT_DEFAULT)
2966                 dhcp_timeout = DHCP_IPC_WAIT_DEFAULT;
2967         else
2968                 dhcp_timeout = addr->ipadm_wait;
2969         /* Send the message to dhcpagent. */
2970         error = dhcp_ipc_make_request(request, &reply, dhcp_timeout);
2971         free(request);

2972         if (error == 0) {
2973                 error = reply->return_code;
2974                 free(reply);
2975         }
2976         if (error != 0) {
2977                 if (dhcperror != NULL)
2978                         *dhcperror = error;
2979                 if (error != DHCP_IPC_E_TIMEOUT)
2980                         return (IPADM_DHCP_IPC_ERROR);
2981                 else if (dhcp_timeout != 0)
2982                         return (IPADM_DHCP_IPC_TIMEOUT);
2983         }
2984 
2985         return (IPADM_SUCCESS);
2986 }
2987 
2988 /*
2989  * Returns the IP addresses of the specified interface in both the
2990  * active and the persistent configuration. If no
2991  * interface is specified, it returns all non-zero IP addresses


3009                 return (IPADM_INVALID_ARG);
3010         if (ifname != NULL &&
3011             (!ifparse_ifspec(ifname, &ifsp) || ifsp.ifsp_lunvalid)) {
3012                 return (IPADM_INVALID_ARG);
3013         }
3014         return (i_ipadm_get_all_addr_info(iph, ifname, addrinfo,
3015             flags, lifc_flags));
3016 }
3017 
3018 /*
3019  * Frees the structure allocated by ipadm_addr_info().
3020  */
3021 void
3022 ipadm_free_addr_info(ipadm_addr_info_t *ainfo)
3023 {
3024         freeifaddrs((struct ifaddrs *)ainfo);
3025 }
3026 
3027 /*
3028  * 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
3030  * remember address object to be recreated on next reboot or on an
3031  * ipadm_enable_addr()/ipadm_enable_if() call.
3032  */
3033 ipadm_status_t
3034 i_ipadm_addr_persist(ipadm_handle_t iph, const ipadm_addrobj_t ipaddr,
3035     boolean_t default_prefixlen, uint32_t flags)
3036 {
3037         char                    *aname = ipaddr->ipadm_aobjname;
3038         nvlist_t                *nvl;
3039         int                     err = 0;
3040         ipadm_status_t          status;
3041         char                    pval[MAXPROPVALLEN];
3042         uint_t                  pflags = 0;
3043         ipadm_prop_desc_t       *pdp = NULL;
3044 
3045         /*
3046          * Construct the nvl to send to the door.
3047          */
3048         if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
3049                 return (IPADM_NO_MEMORY);
3050         if ((err = nvlist_add_string(nvl, IPADM_NVP_IFNAME,
3051             ipaddr->ipadm_ifname)) != 0 ||
3052             (err = nvlist_add_string(nvl, IPADM_NVP_AOBJNAME, aname)) != 0 ||
3053             (err = nvlist_add_int32(nvl, IPADM_NVP_LIFNUM,
3054             ipaddr->ipadm_lifnum)) != 0) {
3055                 status = ipadm_errno2status(err);
3056                 goto ret;
3057         }
3058         switch (ipaddr->ipadm_atype) {
3059         case IPADM_ADDR_STATIC:
3060                 status = i_ipadm_add_ipaddr2nvl(nvl, ipaddr);
3061                 if (status != IPADM_SUCCESS)
3062                         goto ret;
3063                 (void) snprintf(pval, sizeof (pval), "%d",
3064                     ipaddr->ipadm_static_prefixlen);
3065                 if (flags & IPADM_OPT_UP)
3066                         err = nvlist_add_string(nvl, "up", "yes");
3067                 else
3068                         err = nvlist_add_string(nvl, "up", "no");
3069                 status = ipadm_errno2status(err);
3070                 break;
3071         case IPADM_ADDR_DHCP:
3072                 status = i_ipadm_add_dhcp2nvl(nvl, ipaddr->ipadm_primary,
3073                     ipaddr->ipadm_wait);












3074                 break;
3075         case IPADM_ADDR_IPV6_ADDRCONF:
3076                 status = i_ipadm_add_intfid2nvl(nvl, ipaddr);
3077                 break;
3078         }
3079         if (status != IPADM_SUCCESS)
3080                 goto ret;
3081 
3082         if (iph->iph_flags & IPH_INIT) {
3083                 /*
3084                  * IPMGMT_INIT tells the ipmgmtd to set both IPMGMT_ACTIVE and
3085                  * IPMGMT_PERSIST on the address object in its `aobjmap'.
3086                  * For the callers ipadm_enable_if() and ipadm_enable_addr(),
3087                  * IPADM_OPT_PERSIST is not set in their flags. They send
3088                  * IPH_INIT in iph_flags, so that the address object will be
3089                  * set as both IPMGMT_ACTIVE and IPMGMT_PERSIST.
3090                  */
3091                 pflags |= IPMGMT_INIT;
3092         } else {
3093                 if (flags & IPADM_OPT_ACTIVE)
3094                         pflags |= IPMGMT_ACTIVE;
3095                 if (flags & IPADM_OPT_PERSIST)
3096                         pflags |= IPMGMT_PERSIST;


3097         }
3098         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;





3112                 }






3113                 assert(pdp != NULL);
3114                 status = i_ipadm_persist_propval(iph, pdp, pval, ipaddr, flags);

3115         }


3116 ret:
3117         nvlist_free(nvl);
3118         return (status);
3119 }
3120 
3121 /*
3122  * Makes the door call to ipmgmtd to store the address object in the
3123  * nvlist `nvl'.
3124  */
3125 static ipadm_status_t
3126 i_ipadm_addr_persist_nvl(ipadm_handle_t iph, nvlist_t *nvl, uint32_t flags)
3127 {
3128         char                    *buf = NULL, *nvlbuf = NULL;
3129         size_t                  nvlsize, bufsize;
3130         ipmgmt_setaddr_arg_t    *sargp;
3131         int                     err;
3132 
3133         err = nvlist_pack(nvl, &nvlbuf, &nvlsize, NV_ENCODE_NATIVE, 0);
3134         if (err != 0)
3135                 return (ipadm_errno2status(err));


3305  * Refreshes the address in the address object `aobjname'. If the address object
3306  * is of type IPADM_ADDR_STATIC, DAD is re-initiated on the address. If
3307  * `ipadm_flags' has IPADM_OPT_INFORM set, a DHCP_INFORM message is sent to the
3308  * dhcpagent for this static address. If the address object is of type
3309  * IPADM_ADDR_DHCP, a DHCP_EXTEND message is sent to the dhcpagent.
3310  * If a dhcp address has not yet been acquired, a DHCP_START is sent to the
3311  * dhcpagent. This operation is not supported for an address object of
3312  * type IPADM_ADDR_IPV6_ADDRCONF.
3313  */
3314 ipadm_status_t
3315 ipadm_refresh_addr(ipadm_handle_t iph, const char *aobjname,
3316     uint32_t ipadm_flags)
3317 {
3318         ipadm_status_t          status = IPADM_SUCCESS;
3319         uint64_t                flags;
3320         struct ipadm_addrobj_s  ipaddr;
3321         sa_family_t             af;
3322         char                    lifname[LIFNAMSIZ];
3323         boolean_t               inform =
3324             ((ipadm_flags & IPADM_OPT_INFORM) != 0);
3325         int                     dherr;
3326 
3327         /* check for solaris.network.interface.config authorization */
3328         if (!ipadm_check_auth())
3329                 return (IPADM_EAUTH);
3330 
3331         bzero(&ipaddr, sizeof (ipaddr));
3332         /* validate input */
3333         if (aobjname == NULL || strlcpy(ipaddr.ipadm_aobjname, aobjname,
3334             IPADM_AOBJSIZ) >= IPADM_AOBJSIZ) {
3335                 return (IPADM_INVALID_ARG);
3336         }
3337 
3338         /* Retrieve the address object information. */
3339         status = i_ipadm_get_addrobj(iph, &ipaddr);
3340         if (status != IPADM_SUCCESS)
3341                 return (status);
3342 
3343         if (!(ipaddr.ipadm_flags & IPMGMT_ACTIVE))
3344                 return (IPADM_OP_DISABLE_OBJ);
3345 


3347                 return (IPADM_NOTSUP);
3348         if (inform && ipaddr.ipadm_atype != IPADM_ADDR_STATIC)
3349                 return (IPADM_INVALID_ARG);
3350         af = ipaddr.ipadm_af;
3351         if (ipaddr.ipadm_atype == IPADM_ADDR_STATIC) {
3352                 i_ipadm_addrobj2lifname(&ipaddr, lifname, sizeof (lifname));
3353                 status = i_ipadm_get_flags(iph, lifname, af, &flags);
3354                 if (status != IPADM_SUCCESS)
3355                         return (status);
3356                 if (inform) {
3357                         if (dhcp_start_agent(DHCP_IPC_MAX_WAIT) == -1)
3358                                 return (IPADM_DHCP_START_ERROR);
3359 
3360                         ipaddr.ipadm_wait = IPADM_DHCP_WAIT_DEFAULT;
3361                         return (i_ipadm_op_dhcp(&ipaddr, DHCP_INFORM, NULL));
3362                 }
3363                 if (!(flags & IFF_DUPLICATE))
3364                         return (IPADM_SUCCESS);
3365                 status = i_ipadm_set_flags(iph, lifname, af, IFF_UP, 0);
3366         } 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                 }
3376         } else {
3377                 status = IPADM_NOTSUP;
3378         }
3379         return (status);
3380 }
3381 
3382 /*
3383  * This is called from ipadm_create_addr() to validate the address parameters.
3384  * It does the following steps:
3385  * 1. Validates the interface name.
3386  * 2. Verifies that the interface is not an IPMP meta-interface or an
3387  *      underlying interface.
3388  * 3. In case of a persistent operation, verifies that the interface
3389  *      is persistent. Returns error if interface is not enabled but
3390  *      is in persistent config.
3391  * 4. Verifies that the destination address is not set or the address type is
3392  *      not DHCP or ADDRCONF when the interface is a loopback interface.
3393  * 5. Verifies that the address type is not DHCP or ADDRCONF when the interface
3394  *      has IFF_VRRP interface flag set.
3395  */
3396 static ipadm_status_t
3397 i_ipadm_validate_create_addr(ipadm_handle_t iph, ipadm_addrobj_t ipaddr,
3398     uint32_t flags)


3477                         return (IPADM_BAD_ADDR);
3478                 break;
3479         case IPADM_ADDR_DHCP:
3480                 if (islo || (ifflags & IFF_VRRP))
3481                         return (IPADM_NOTSUP);
3482                 break;
3483         case IPADM_ADDR_IPV6_ADDRCONF:
3484                 if (islo || (ifflags & IFF_VRRP) ||
3485                     i_ipadm_is_6to4(iph, ifname)) {
3486                         return (IPADM_NOTSUP);
3487                 }
3488                 break;
3489         default:
3490                 return (IPADM_INVALID_ARG);
3491         }
3492 
3493         return (IPADM_SUCCESS);
3494 }
3495 
3496 ipadm_status_t
3497 i_ipadm_merge_prefixlen_from_nvl(nvlist_t *invl, nvlist_t *onvl,
3498     const char *aobjname)
3499 {
3500         nvpair_t        *nvp, *prefixnvp;




3501         nvlist_t        *tnvl;
3502         char            *aname;


3503         int             err;
3504 



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));
3518                         }

3519                         return (ipadm_errno2status(err));

3520                 }
3521         }

3522         return (IPADM_SUCCESS);
3523 }
3524 
3525 /*
3526  * Re-enables the address object `aobjname' based on the saved
3527  * configuration for `aobjname'.
3528  */
3529 ipadm_status_t
3530 ipadm_enable_addr(ipadm_handle_t iph, const char *aobjname, uint32_t flags)
3531 {
3532         nvlist_t        *addrnvl, *nvl;
3533         nvpair_t        *nvp;
3534         ipadm_status_t  status;
3535         struct ipadm_addrobj_s ipaddr;
3536 
3537         /* check for solaris.network.interface.config authorization */
3538         if (!ipadm_check_auth())
3539                 return (IPADM_EAUTH);
3540 
3541         /* validate input */


3548 
3549         /* Retrieve the address object information. */
3550         status = i_ipadm_get_addrobj(iph, &ipaddr);
3551         if (status != IPADM_SUCCESS)
3552                 return (status);
3553         if (ipaddr.ipadm_flags & IPMGMT_ACTIVE)
3554                 return (IPADM_ADDROBJ_EXISTS);
3555 
3556         status = i_ipadm_get_db_addr(iph, NULL, aobjname, &addrnvl);
3557         if (status != IPADM_SUCCESS)
3558                 return (status);
3559 
3560         assert(addrnvl != NULL);
3561 
3562         for (nvp = nvlist_next_nvpair(addrnvl, NULL); nvp != NULL;
3563             nvp = nvlist_next_nvpair(addrnvl, nvp)) {
3564                 if (nvpair_value_nvlist(nvp, &nvl) != 0)
3565                         continue;
3566 
3567                 if (nvlist_exists(nvl, IPADM_NVP_IPV4ADDR) ||
3568                     nvlist_exists(nvl, IPADM_NVP_IPV6ADDR)) {
3569                         status = i_ipadm_merge_prefixlen_from_nvl(addrnvl, nvl,

3570                             aobjname);
3571                         if (status != IPADM_SUCCESS)
3572                                 continue;
3573                 }
3574                 iph->iph_flags |= IPH_INIT;
3575                 status = i_ipadm_init_addrobj(iph, nvl);
3576                 iph->iph_flags &= ~IPH_INIT;
3577                 if (status != IPADM_SUCCESS)
3578                         break;
3579         }
3580 
3581         return (status);
3582 }
3583 
3584 /*
3585  * Disables the address object in `aobjname' from the active configuration.
3586  * Error code return values follow the model in ipadm_delete_addr().
3587  */
3588 ipadm_status_t
3589 ipadm_disable_addr(ipadm_handle_t iph, const char *aobjname, uint32_t flags)


   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
  23  * Copyright (c) 2013 by Delphix. All rights reserved.
  24  * Copyright (c) 2016, Chris Fraire <cfraire@me.com>.
  25  */
  26 
  27 /*
  28  * This file contains functions for address management such as creating
  29  * an address, deleting an address, enabling an address, disabling an
  30  * address, bringing an address down or up, setting/getting properties
  31  * on an address object and listing address information
  32  * for all addresses in active as well as persistent configuration.
  33  */
  34 #include <sys/types.h>
  35 #include <sys/socket.h>
  36 #include <sys/param.h>
  37 #include <netdb.h>
  38 #include <inet/ip.h>
  39 #include <string.h>
  40 #include <strings.h>
  41 #include <assert.h>
  42 #include <sys/sockio.h>
  43 #include <errno.h>
  44 #include <unistd.h>
  45 #include <stropts.h>
  46 #include <zone.h>
  47 #include <netinet/in.h>
  48 #include <arpa/inet.h>
  49 #include <fcntl.h>
  50 #include <ctype.h>
  51 #include <dhcpagent_util.h>
  52 #include <dhcpagent_ipc.h>
  53 #include <dhcp_inittab.h>
  54 #include <dhcp_symbol.h>
  55 #include <ipadm_ndpd.h>
  56 #include <libdladm.h>
  57 #include <libdllink.h>
  58 #include <libdliptun.h>
  59 #include <ifaddrs.h>
  60 #include "libipadm_impl.h"
  61 
  62 #define SIN6(a)         ((struct sockaddr_in6 *)a)
  63 #define SIN(a)          ((struct sockaddr_in *)a)
  64 
  65 static ipadm_status_t   i_ipadm_create_addr(ipadm_handle_t, ipadm_addrobj_t,
  66                             uint32_t);
  67 static ipadm_status_t   i_ipadm_create_dhcp(ipadm_handle_t, ipadm_addrobj_t,
  68                             uint32_t);
  69 static ipadm_status_t   i_ipadm_delete_dhcp(ipadm_handle_t, ipadm_addrobj_t,
  70                             boolean_t);
  71 static ipadm_status_t   i_ipadm_refresh_dhcp(ipadm_addrobj_t);
  72 static ipadm_status_t   i_ipadm_get_db_addr(ipadm_handle_t, const char *,
  73                             const char *, nvlist_t **);
  74 static ipadm_status_t   i_ipadm_op_dhcp(ipadm_addrobj_t, dhcp_ipc_type_t,
  75                             int *);
  76 static ipadm_status_t   i_ipadm_validate_create_addr(ipadm_handle_t,
  77                             ipadm_addrobj_t, uint32_t);
  78 static ipadm_status_t   i_ipadm_addr_persist_nvl(ipadm_handle_t, nvlist_t *,
  79                             uint32_t);
  80 static ipadm_status_t   i_ipadm_get_default_prefixlen(struct sockaddr_storage *,
  81                             uint32_t *);
  82 static ipadm_status_t   i_ipadm_get_static_addr_db(ipadm_handle_t,
  83                             ipadm_addrobj_t);
  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);
  86 
  87 /*
  88  * Callback functions to retrieve property values from the kernel. These
  89  * functions, when required, translate the values from the kernel to a format
  90  * suitable for printing. They also retrieve DEFAULT, PERM and POSSIBLE values
  91  * for a given property.
  92  */
  93 static ipadm_pd_getf_t  i_ipadm_get_prefixlen, i_ipadm_get_addr_flag,
  94                         i_ipadm_get_zone, i_ipadm_get_broadcast, i_ipadm_get_primary,
  95                         i_ipadm_get_reqhost;
  96 
  97 /*
  98  * Callback functions to set property values. These functions translate the
  99  * values to a format suitable for kernel consumption, allocate the necessary
 100  * ioctl buffers and then invoke ioctl(); or in the case of reqhost, get the
 101  * collaborating agent to set the value.
 102  */
 103 static ipadm_pd_setf_t  i_ipadm_set_prefixlen, i_ipadm_set_addr_flag,
 104                         i_ipadm_set_zone, i_ipadm_set_reqhost;
 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 
 109 /* address properties description table */
 110 ipadm_prop_desc_t ipadm_addrprop_table[] = {
 111         { "broadcast", NULL, IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE, 0,
 112             NULL, NULL, i_ipadm_get_broadcast },
 113 
 114         { "deprecated", NULL, IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE, 0,
 115             i_ipadm_set_addr_flag, i_ipadm_get_onoff,
 116             i_ipadm_get_addr_flag },
 117 
 118         { IPADM_NVP_PREFIXLEN, NULL, IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE, 0,
 119             i_ipadm_set_prefixlen, i_ipadm_get_prefixlen,
 120             i_ipadm_get_prefixlen },
 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 
 130         { "private", NULL, IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE, 0,
 131             i_ipadm_set_addr_flag, i_ipadm_get_onoff, i_ipadm_get_addr_flag },
 132 
 133         { IPADM_NVP_REQHOST, NULL, IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE, 0,
 134             i_ipadm_set_reqhost, NULL, i_ipadm_get_reqhost },
 135 
 136         { "transmit", NULL, IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE, 0,
 137             i_ipadm_set_addr_flag, i_ipadm_get_onoff, i_ipadm_get_addr_flag },
 138 
 139         { "zone", NULL, IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE, 0,
 140             i_ipadm_set_zone, NULL, i_ipadm_get_zone },
 141 
 142         { NULL, NULL, 0, 0, 0, NULL, NULL, NULL }
 143 };
 144 
 145 static ipadm_prop_desc_t up_addrprop = { "up", NULL, IPADMPROP_CLASS_ADDR,
 146                                         MOD_PROTO_NONE, 0, NULL, NULL, NULL };
 147 
 148 /*
 149  * Helper function that initializes the `ipadm_ifname', `ipadm_aobjname', and
 150  * `ipadm_atype' fields of the given `ipaddr'.
 151  */
 152 void
 153 i_ipadm_init_addr(ipadm_addrobj_t ipaddr, const char *ifname,
 154     const char *aobjname, ipadm_addr_type_t atype)
 155 {


 206         ipmgmt_aobjop_arg_t     larg;
 207         ipmgmt_aobjop_rval_t    rval, *rvalp;
 208         int                     err = 0;
 209 
 210         /* populate the door_call argument structure */
 211         larg.ia_cmd = IPMGMT_CMD_AOBJNAME2ADDROBJ;
 212         (void) strlcpy(larg.ia_aobjname, ipaddr->ipadm_aobjname,
 213             sizeof (larg.ia_aobjname));
 214 
 215         rvalp = &rval;
 216         err = ipadm_door_call(iph, &larg, sizeof (larg), (void **)&rvalp,
 217             sizeof (rval), B_FALSE);
 218         if (err != 0)
 219                 return (ipadm_errno2status(err));
 220         (void) strlcpy(ipaddr->ipadm_ifname, rval.ir_ifname,
 221             sizeof (ipaddr->ipadm_ifname));
 222         ipaddr->ipadm_lifnum = rval.ir_lnum;
 223         ipaddr->ipadm_atype = rval.ir_atype;
 224         ipaddr->ipadm_af = rval.ir_family;
 225         ipaddr->ipadm_flags = rval.ir_flags;
 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;
 237         }
 238 
 239         return (IPADM_SUCCESS);
 240 }
 241 
 242 /*
 243  * Retrieves the static address (IPv4 or IPv6) for the given address object
 244  * in `ipaddr' from persistent DB.
 245  */
 246 static ipadm_status_t
 247 i_ipadm_get_static_addr_db(ipadm_handle_t iph, ipadm_addrobj_t ipaddr)
 248 {
 249         ipadm_status_t          status;
 250         nvlist_t                *onvl;
 251         nvlist_t                *anvl = NULL;
 252         nvlist_t                *nvladdr;
 253         nvpair_t                *nvp;
 254         char                    *name;
 255         char                    *aobjname = ipaddr->ipadm_aobjname;
 256         char                    *sname;


1054                         /* zone must be ready or running */
1055                         if ((zoneid = getzoneidbyname(pval)) == -1)
1056                                 return (ipadm_errno2status(errno));
1057                 }
1058         } else {
1059                 return (IPADM_INVALID_ARG);
1060         }
1061 
1062         s = (af == AF_INET ? iph->iph_sock : iph->iph_sock6);
1063         bzero(&lifr, sizeof (lifr));
1064         i_ipadm_addrobj2lifname((ipadm_addrobj_t)arg, lifr.lifr_name,
1065             sizeof (lifr.lifr_name));
1066         lifr.lifr_zoneid = zoneid;
1067         if (ioctl(s, SIOCSLIFZONE, (caddr_t)&lifr) < 0)
1068                 return (ipadm_errno2status(errno));
1069 
1070         return (IPADM_SUCCESS);
1071 }
1072 
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 /*
1152  * Callback function that gets the property `broadcast' for the address
1153  * object in `arg'.
1154  */
1155 /* ARGSUSED */
1156 static ipadm_status_t
1157 i_ipadm_get_broadcast(ipadm_handle_t iph, const void *arg,
1158     ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t af,
1159     uint_t valtype)
1160 {
1161         struct sockaddr_in      *sin;
1162         struct lifreq           lifr;
1163         char                    lifname[LIFNAMSIZ];
1164         ipadm_addrobj_t         ipaddr = (ipadm_addrobj_t)arg;
1165         ipadm_status_t          status;
1166         size_t                  nbytes = 0;
1167         uint64_t                ifflags = 0;
1168 
1169         i_ipadm_addrobj2lifname(ipaddr, lifname, sizeof (lifname));
1170         if (ipaddr->ipadm_flags & IPMGMT_ACTIVE) {
1171                 status = i_ipadm_get_flags(iph, lifname, af, &ifflags);


1462                         nbytes = snprintf(buf, *bufsize, "%s", "all-zones");
1463                 } else if (getzonenamebyid(lifr.lifr_zoneid, zone_name,
1464                     sizeof (zone_name)) < 0) {
1465                         return (ipadm_errno2status(errno));
1466                 } else {
1467                         nbytes = snprintf(buf, *bufsize, "%s", zone_name);
1468                 }
1469                 break;
1470         default:
1471                 return (IPADM_INVALID_ARG);
1472         }
1473         if (nbytes >= *bufsize) {
1474                 /* insufficient buffer space */
1475                 *bufsize = nbytes + 1;
1476                 return (IPADM_NO_BUFS);
1477         }
1478 
1479         return (IPADM_SUCCESS);
1480 }
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 
1554 static ipadm_prop_desc_t *
1555 i_ipadm_get_addrprop_desc(const char *pname)
1556 {
1557         int i;
1558 
1559         for (i = 0; ipadm_addrprop_table[i].ipd_name != NULL; i++) {
1560                 if (strcmp(pname, ipadm_addrprop_table[i].ipd_name) == 0 ||
1561                     (ipadm_addrprop_table[i].ipd_old_name != NULL &&
1562                     strcmp(pname, ipadm_addrprop_table[i].ipd_old_name) == 0))
1563                         return (&ipadm_addrprop_table[i]);
1564         }
1565         return (NULL);
1566 }
1567 
1568 /*
1569  * Gets the value of the given address property `pname' for the address
1570  * object with name `aobjname'.
1571  */
1572 ipadm_status_t
1573 ipadm_get_addrprop(ipadm_handle_t iph, const char *pname, char *buf,


1938                 ipaddr->ipadm_static_prefixlen = prefixlen;
1939         }
1940         return (status);
1941 }
1942 
1943 /*
1944  * Gets the static source address from the address object in `ipaddr'.
1945  * Memory for `addr' should be already allocated by the caller.
1946  */
1947 ipadm_status_t
1948 ipadm_get_addr(const ipadm_addrobj_t ipaddr, struct sockaddr_storage *addr)
1949 {
1950         if (ipaddr == NULL || ipaddr->ipadm_atype != IPADM_ADDR_STATIC ||
1951             addr == NULL) {
1952                 return (IPADM_INVALID_ARG);
1953         }
1954         *addr = ipaddr->ipadm_static_addr;
1955 
1956         return (IPADM_SUCCESS);
1957 }
1958 
1959 /*
1960  * Set up tunnel destination address in ipaddr by contacting DNS.
1961  * The function works similar to ipadm_set_addr().
1962  * The dst_addr must resolve to exactly one address. IPADM_BAD_ADDR is returned
1963  * if dst_addr resolves to more than one address. The caller has to verify
1964  * that ipadm_static_addr and ipadm_static_dst_addr have the same ss_family
1965  */
1966 ipadm_status_t
1967 ipadm_set_dst_addr(ipadm_addrobj_t ipaddr, const char *daddrstr, sa_family_t af)
1968 {
1969         ipadm_status_t  status;
1970 
1971         /* mask lengths are not meaningful for point-to-point interfaces. */
1972         if (strchr(daddrstr, '/') != NULL)
1973                 return (IPADM_BAD_ADDR);
1974 
1975         status = i_ipadm_resolve_addr(daddrstr, af,
1976             &ipaddr->ipadm_static_dst_addr);
1977         if (status == IPADM_SUCCESS) {
1978                 (void) strlcpy(ipaddr->ipadm_static_dname, daddrstr,


2065  * Sets the dhcp parameter `ipadm_wait' in the address object `ipaddr'.
2066  * This field is used during the address creation with address type
2067  * IPADM_ADDR_DHCP. It specifies how long the API ipadm_create_addr()
2068  * should wait before returning while the dhcp address is being acquired
2069  * by the dhcpagent.
2070  * Possible values:
2071  * - IPADM_DHCP_WAIT_FOREVER : Do not return until dhcpagent returns.
2072  * - IPADM_DHCP_WAIT_DEFAULT : Wait a default amount of time before returning.
2073  * - <integer>       : Wait the specified number of seconds before returning.
2074  */
2075 ipadm_status_t
2076 ipadm_set_wait_time(ipadm_addrobj_t ipaddr, int32_t wait)
2077 {
2078         if (ipaddr == NULL || ipaddr->ipadm_atype != IPADM_ADDR_DHCP)
2079                 return (IPADM_INVALID_ARG);
2080         ipaddr->ipadm_wait = wait;
2081         return (IPADM_SUCCESS);
2082 }
2083 
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 /*
2107  * Creates a placeholder for the `ipadm_aobjname' in the ipmgmtd `aobjmap'.
2108  * If the `aobjname' already exists in the daemon's `aobjmap' then
2109  * IPADM_ADDROBJ_EXISTS will be returned.
2110  *
2111  * If the libipadm consumer set `ipaddr.ipadm_aobjname[0]' to `\0', then the
2112  * daemon will generate an `aobjname' for the given `ipaddr'.
2113  */
2114 ipadm_status_t
2115 i_ipadm_lookupadd_addrobj(ipadm_handle_t iph, ipadm_addrobj_t ipaddr)
2116 {
2117         ipmgmt_aobjop_arg_t     larg;
2118         ipmgmt_aobjop_rval_t    rval, *rvalp;
2119         int                     err;
2120 
2121         bzero(&larg, sizeof (larg));
2122         larg.ia_cmd = IPMGMT_CMD_ADDROBJ_LOOKUPADD;
2123         (void) strlcpy(larg.ia_aobjname, ipaddr->ipadm_aobjname,
2124             sizeof (larg.ia_aobjname));
2125         (void) strlcpy(larg.ia_ifname, ipaddr->ipadm_ifname,
2126             sizeof (larg.ia_ifname));


2236                 status = ipadm_set_addr(&ipaddr, sname, af);
2237         }
2238         if (status != IPADM_SUCCESS)
2239                 return (status);
2240 
2241         if (dname != NULL) {
2242                 status = ipadm_set_dst_addr(&ipaddr, dname, af);
2243                 if (status != IPADM_SUCCESS)
2244                         return (status);
2245         }
2246         return (i_ipadm_create_addr(iph, &ipaddr, flags));
2247 }
2248 
2249 /*
2250  * Creates a dhcp address on the interface `ifname' based on the
2251  * IPADM_ADDR_DHCP address object parameters from the nvlist `nvl'.
2252  */
2253 ipadm_status_t
2254 i_ipadm_enable_dhcp(ipadm_handle_t iph, const char *ifname, nvlist_t *nvl)
2255 {
2256         int32_t                 wait = IPADM_DHCP_WAIT_DEFAULT;
2257         boolean_t               primary = B_FALSE;
2258         nvlist_t                *nvdhcp = NULL;
2259         nvpair_t                *nvp;
2260         char                    *name;
2261         struct ipadm_addrobj_s  ipaddr;
2262         char                    *aobjname = NULL, *reqhost = NULL;
2263         int                     err = 0;
2264         ipadm_status_t  ipadm_err = IPADM_SUCCESS;
2265 
2266         /* Extract the dhcp parameters */
2267         for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL;
2268             nvp = nvlist_next_nvpair(nvl, nvp)) {
2269                 name = nvpair_name(nvp);
2270                 if (strcmp(name, IPADM_NVP_DHCP) == 0)
2271                         err = nvpair_value_nvlist(nvp, &nvdhcp);
2272                 else if (strcmp(name, IPADM_NVP_AOBJNAME) == 0)
2273                         err = nvpair_value_string(nvp, &aobjname);
2274                 else if (strcmp(name, IPADM_NVP_REQHOST) == 0)
2275                         err = nvpair_value_string(nvp, &reqhost);
2276                 if (err != 0)
2277                         return (ipadm_errno2status(err));
2278         }
2279         for (nvp = nvlist_next_nvpair(nvdhcp, NULL); nvp != NULL;
2280             nvp = nvlist_next_nvpair(nvdhcp, nvp)) {
2281                 name = nvpair_name(nvp);
2282                 if (strcmp(name, IPADM_NVP_WAIT) == 0)
2283                         err = nvpair_value_int32(nvp, &wait);
2284                 else if (strcmp(name, IPADM_NVP_PRIMARY) == 0)
2285                         err = nvpair_value_boolean_value(nvp, &primary);
2286                 if (err != 0)
2287                         return (ipadm_errno2status(err));
2288         }
2289 
2290         /* Build the address object */
2291         i_ipadm_init_addr(&ipaddr, ifname, aobjname, IPADM_ADDR_DHCP);
2292         ipaddr.ipadm_primary = primary;
2293         if (iph->iph_flags & IPH_INIT)
2294                 ipaddr.ipadm_wait = 0;
2295         else
2296                 ipaddr.ipadm_wait = wait;
2297         ipadm_err = ipadm_set_reqhost(&ipaddr, reqhost);
2298         if (ipadm_err != IPADM_SUCCESS)
2299                 return ipadm_err;
2300         ipaddr.ipadm_af = AF_INET;
2301         return (i_ipadm_create_dhcp(iph, &ipaddr, IPADM_OPT_ACTIVE));
2302 }
2303 
2304 /*
2305  * Creates auto-configured addresses on the interface `ifname' based on
2306  * the IPADM_ADDR_IPV6_ADDRCONF address object parameters from the nvlist `nvl'.
2307  */
2308 ipadm_status_t
2309 i_ipadm_enable_addrconf(ipadm_handle_t iph, const char *ifname, nvlist_t *nvl)
2310 {
2311         struct ipadm_addrobj_s  ipaddr;
2312         char            *stateful = NULL, *stateless = NULL;
2313         uint_t          n;
2314         uint8_t         *addr6 = NULL;
2315         uint32_t        intfidlen = 0;
2316         char            *aobjname;
2317         nvlist_t        *nvaddr;
2318         nvpair_t        *nvp;
2319         char            *name;


2922         if (status == IPADM_SUCCESS && !is_boot) {
2923                 /*
2924                  * For IPH_LEGACY, we might be modifying the address on
2925                  * an address object that already exists e.g. by doing
2926                  * "ifconfig bge0:1 <addr>; ifconfig bge0:1 <newaddr>"
2927                  * So, we need to store the object only if it does not
2928                  * already exist in ipmgmtd.
2929                  */
2930                 if (legacy) {
2931                         bzero(&legacy_addr, sizeof (legacy_addr));
2932                         (void) strlcpy(legacy_addr.ipadm_aobjname,
2933                             ipaddr->ipadm_aobjname,
2934                             sizeof (legacy_addr.ipadm_aobjname));
2935                         status = i_ipadm_get_addrobj(iph, &legacy_addr);
2936                         if (status == IPADM_SUCCESS &&
2937                             legacy_addr.ipadm_lifnum >= 0) {
2938                                 return (status);
2939                         }
2940                 }
2941                 status = i_ipadm_addr_persist(iph, ipaddr, default_prefixlen,
2942                     flags, NULL);
2943         }
2944 ret:
2945         if (status != IPADM_SUCCESS && !legacy)
2946                 (void) i_ipadm_delete_addr(iph, ipaddr);
2947         return (status);
2948 }
2949 
2950 /*
2951  * Removes the address object identified by `aobjname' from both active and
2952  * persistent configuration. The address object will be removed from only
2953  * active configuration if IPH_LEGACY is set in `iph->iph_flags'.
2954  *
2955  * If the address type is IPADM_ADDR_STATIC or IPADM_ADDR_DHCP, the address
2956  * in the address object will be removed from the physical interface.
2957  * If the address type is IPADM_ADDR_DHCP, the flag IPADM_OPT_RELEASE specifies
2958  * whether the lease should be released. If IPADM_OPT_RELEASE is not
2959  * specified, the lease will be dropped. This option is not supported
2960  * for other address types.
2961  *
2962  * If the address type is IPADM_ADDR_IPV6_ADDRCONF, the link-local address and


3079          */
3080         if (!(iph->iph_flags & IPH_INIT)) {
3081                 status = i_ipadm_setlifnum_addrobj(iph, addr);
3082                 if (status == IPADM_ADDROBJ_EXISTS)
3083                         goto retry;
3084                 if (status != IPADM_SUCCESS)
3085                         return (status);
3086         }
3087         /* Send DHCP_START to the dhcpagent. */
3088         status = i_ipadm_op_dhcp(addr, DHCP_START, NULL);
3089         /*
3090          * We do not undo the create-addr operation for IPADM_DHCP_IPC_TIMEOUT
3091          * since it is only a soft error to indicate the caller that the lease
3092          * might be required after the function returns.
3093          */
3094         if (status != IPADM_SUCCESS && status != IPADM_DHCP_IPC_TIMEOUT)
3095                 goto fail;
3096         dh_status = status;
3097 
3098         /* Persist the address object information in ipmgmtd. */
3099         status = i_ipadm_addr_persist(iph, addr, B_FALSE, flags, NULL);
3100         if (status != IPADM_SUCCESS)
3101                 goto fail;
3102 
3103         return (dh_status);
3104 fail:
3105         /* In case of error, delete the dhcp address */
3106         (void) i_ipadm_delete_dhcp(iph, addr, B_TRUE);
3107         return (status);
3108 }
3109 
3110 /*
3111  * Releases/drops the dhcp lease on the logical interface in the address
3112  * object `addr'. If `release' is set to B_FALSE, the lease will be dropped.
3113  */
3114 static ipadm_status_t
3115 i_ipadm_delete_dhcp(ipadm_handle_t iph, ipadm_addrobj_t addr, boolean_t release)
3116 {
3117         ipadm_status_t  status;
3118         int             dherr;
3119 


3139                 bzero(&lifr, sizeof (lifr));
3140                 i_ipadm_addrobj2lifname(addr, lifr.lifr_name,
3141                     sizeof (lifr.lifr_name));
3142                 if (ioctl(iph->iph_sock, SIOCLIFREMOVEIF, (caddr_t)&lifr) < 0)
3143                         return (ipadm_errno2status(errno));
3144         }
3145 
3146         return (IPADM_SUCCESS);
3147 }
3148 
3149 /*
3150  * Communicates with the dhcpagent to send a dhcp message of type `type'.
3151  * It returns the dhcp error in `dhcperror' if a non-null pointer is provided
3152  * in `dhcperror'.
3153  */
3154 static ipadm_status_t
3155 i_ipadm_op_dhcp(ipadm_addrobj_t addr, dhcp_ipc_type_t type, int *dhcperror)
3156 {
3157         dhcp_ipc_request_t      *request;
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;
3163         char                    ifname[LIFNAMSIZ];
3164         int                     error;
3165         int                     dhcp_timeout;
3166 
3167         /* Construct a message to the dhcpagent. */
3168         bzero(&ifname, sizeof (ifname));
3169         i_ipadm_addrobj2lifname(addr, ifname, sizeof (ifname));
3170         if (addr->ipadm_primary)
3171                 type |= DHCP_PRIMARY;
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);
3202                 return (IPADM_NO_MEMORY);
3203         }
3204 
3205         if (addr->ipadm_wait == IPADM_DHCP_WAIT_FOREVER)
3206                 dhcp_timeout = DHCP_IPC_WAIT_FOREVER;
3207         else if (addr->ipadm_wait == IPADM_DHCP_WAIT_DEFAULT)
3208                 dhcp_timeout = DHCP_IPC_WAIT_DEFAULT;
3209         else
3210                 dhcp_timeout = addr->ipadm_wait;
3211         /* Send the message to dhcpagent. */
3212         error = dhcp_ipc_make_request(request, &reply, dhcp_timeout);
3213         free(request);
3214         free(d4o);
3215         if (error == 0) {
3216                 error = reply->return_code;
3217                 free(reply);
3218         }
3219         if (error != 0) {
3220                 if (dhcperror != NULL)
3221                         *dhcperror = error;
3222                 if (error != DHCP_IPC_E_TIMEOUT)
3223                         return (IPADM_DHCP_IPC_ERROR);
3224                 else if (dhcp_timeout != 0)
3225                         return (IPADM_DHCP_IPC_TIMEOUT);
3226         }
3227 
3228         return (IPADM_SUCCESS);
3229 }
3230 
3231 /*
3232  * Returns the IP addresses of the specified interface in both the
3233  * active and the persistent configuration. If no
3234  * interface is specified, it returns all non-zero IP addresses


3252                 return (IPADM_INVALID_ARG);
3253         if (ifname != NULL &&
3254             (!ifparse_ifspec(ifname, &ifsp) || ifsp.ifsp_lunvalid)) {
3255                 return (IPADM_INVALID_ARG);
3256         }
3257         return (i_ipadm_get_all_addr_info(iph, ifname, addrinfo,
3258             flags, lifc_flags));
3259 }
3260 
3261 /*
3262  * Frees the structure allocated by ipadm_addr_info().
3263  */
3264 void
3265 ipadm_free_addr_info(ipadm_addr_info_t *ainfo)
3266 {
3267         freeifaddrs((struct ifaddrs *)ainfo);
3268 }
3269 
3270 /*
3271  * Makes a door call to ipmgmtd to update its `aobjmap' with the address
3272  * object in `ipaddr'. This door call also can update the persistent DB to
3273  * remember address object to be recreated on next reboot or on an
3274  * ipadm_enable_addr()/ipadm_enable_if() call.
3275  */
3276 ipadm_status_t
3277 i_ipadm_addr_persist(ipadm_handle_t iph, const ipadm_addrobj_t ipaddr,
3278     boolean_t default_prefixlen, uint32_t flags, const char *propname)
3279 {
3280         char                    *aname = ipaddr->ipadm_aobjname;
3281         nvlist_t                *nvl;
3282         int                     err = 0;
3283         ipadm_status_t          status;

3284         uint_t                  pflags = 0;

3285 
3286         /*
3287          * Construct the nvl to send to the door.
3288          */
3289         if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
3290                 return (IPADM_NO_MEMORY);
3291         if ((err = nvlist_add_string(nvl, IPADM_NVP_IFNAME,
3292             ipaddr->ipadm_ifname)) != 0 ||
3293             (err = nvlist_add_string(nvl, IPADM_NVP_AOBJNAME, aname)) != 0 ||
3294             (err = nvlist_add_int32(nvl, IPADM_NVP_LIFNUM,
3295             ipaddr->ipadm_lifnum)) != 0) {
3296                 status = ipadm_errno2status(err);
3297                 goto ret;
3298         }
3299         switch (ipaddr->ipadm_atype) {
3300         case IPADM_ADDR_STATIC:
3301                 status = i_ipadm_add_ipaddr2nvl(nvl, ipaddr);
3302                 if (status != IPADM_SUCCESS)
3303                         goto ret;


3304                 if (flags & IPADM_OPT_UP)
3305                         err = nvlist_add_string(nvl, "up", "yes");
3306                 else
3307                         err = nvlist_add_string(nvl, "up", "no");
3308                 status = ipadm_errno2status(err);
3309                 break;
3310         case IPADM_ADDR_DHCP:
3311                 status = i_ipadm_add_dhcp2nvl(nvl, ipaddr->ipadm_primary,
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);
3325                 break;
3326         case IPADM_ADDR_IPV6_ADDRCONF:
3327                 status = i_ipadm_add_intfid2nvl(nvl, ipaddr);
3328                 break;
3329         }
3330         if (status != IPADM_SUCCESS)
3331                 goto ret;
3332 
3333         if (iph->iph_flags & IPH_INIT) {
3334                 /*
3335                  * IPMGMT_INIT tells the ipmgmtd to set both IPMGMT_ACTIVE and
3336                  * IPMGMT_PERSIST on the address object in its `aobjmap'.
3337                  * For the callers ipadm_enable_if() and ipadm_enable_addr(),
3338                  * IPADM_OPT_PERSIST is not set in their flags. They send
3339                  * IPH_INIT in iph_flags, so that the address object will be
3340                  * set as both IPMGMT_ACTIVE and IPMGMT_PERSIST.
3341                  */
3342                 pflags |= IPMGMT_INIT;
3343         } else {
3344                 if (flags & IPADM_OPT_ACTIVE)
3345                         pflags |= IPMGMT_ACTIVE;
3346                 if (flags & IPADM_OPT_PERSIST)
3347                         pflags |= IPMGMT_PERSIST;
3348                 if (flags & IPADM_OPT_SET_PROPS)
3349                         pflags |= IPMGMT_PROPS_ONLY;
3350         }
3351         status = i_ipadm_addr_persist_nvl(iph, nvl, pflags);
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;
3395                 }
3396 
3397                 if (pval != NULL) {
3398                         assert(pdp != NULL);
3399                         status = i_ipadm_persist_propval(iph, pdp, pval,
3400                                 ipaddr, flags);
3401                 }
3402         }
3403 
3404 ret:
3405         nvlist_free(nvl);
3406         return (status);
3407 }
3408 
3409 /*
3410  * Makes the door call to ipmgmtd to store the address object in the
3411  * nvlist `nvl'.
3412  */
3413 static ipadm_status_t
3414 i_ipadm_addr_persist_nvl(ipadm_handle_t iph, nvlist_t *nvl, uint32_t flags)
3415 {
3416         char                    *buf = NULL, *nvlbuf = NULL;
3417         size_t                  nvlsize, bufsize;
3418         ipmgmt_setaddr_arg_t    *sargp;
3419         int                     err;
3420 
3421         err = nvlist_pack(nvl, &nvlbuf, &nvlsize, NV_ENCODE_NATIVE, 0);
3422         if (err != 0)
3423                 return (ipadm_errno2status(err));


3593  * Refreshes the address in the address object `aobjname'. If the address object
3594  * is of type IPADM_ADDR_STATIC, DAD is re-initiated on the address. If
3595  * `ipadm_flags' has IPADM_OPT_INFORM set, a DHCP_INFORM message is sent to the
3596  * dhcpagent for this static address. If the address object is of type
3597  * IPADM_ADDR_DHCP, a DHCP_EXTEND message is sent to the dhcpagent.
3598  * If a dhcp address has not yet been acquired, a DHCP_START is sent to the
3599  * dhcpagent. This operation is not supported for an address object of
3600  * type IPADM_ADDR_IPV6_ADDRCONF.
3601  */
3602 ipadm_status_t
3603 ipadm_refresh_addr(ipadm_handle_t iph, const char *aobjname,
3604     uint32_t ipadm_flags)
3605 {
3606         ipadm_status_t          status = IPADM_SUCCESS;
3607         uint64_t                flags;
3608         struct ipadm_addrobj_s  ipaddr;
3609         sa_family_t             af;
3610         char                    lifname[LIFNAMSIZ];
3611         boolean_t               inform =
3612             ((ipadm_flags & IPADM_OPT_INFORM) != 0);

3613 
3614         /* check for solaris.network.interface.config authorization */
3615         if (!ipadm_check_auth())
3616                 return (IPADM_EAUTH);
3617 
3618         bzero(&ipaddr, sizeof (ipaddr));
3619         /* validate input */
3620         if (aobjname == NULL || strlcpy(ipaddr.ipadm_aobjname, aobjname,
3621             IPADM_AOBJSIZ) >= IPADM_AOBJSIZ) {
3622                 return (IPADM_INVALID_ARG);
3623         }
3624 
3625         /* Retrieve the address object information. */
3626         status = i_ipadm_get_addrobj(iph, &ipaddr);
3627         if (status != IPADM_SUCCESS)
3628                 return (status);
3629 
3630         if (!(ipaddr.ipadm_flags & IPMGMT_ACTIVE))
3631                 return (IPADM_OP_DISABLE_OBJ);
3632 


3634                 return (IPADM_NOTSUP);
3635         if (inform && ipaddr.ipadm_atype != IPADM_ADDR_STATIC)
3636                 return (IPADM_INVALID_ARG);
3637         af = ipaddr.ipadm_af;
3638         if (ipaddr.ipadm_atype == IPADM_ADDR_STATIC) {
3639                 i_ipadm_addrobj2lifname(&ipaddr, lifname, sizeof (lifname));
3640                 status = i_ipadm_get_flags(iph, lifname, af, &flags);
3641                 if (status != IPADM_SUCCESS)
3642                         return (status);
3643                 if (inform) {
3644                         if (dhcp_start_agent(DHCP_IPC_MAX_WAIT) == -1)
3645                                 return (IPADM_DHCP_START_ERROR);
3646 
3647                         ipaddr.ipadm_wait = IPADM_DHCP_WAIT_DEFAULT;
3648                         return (i_ipadm_op_dhcp(&ipaddr, DHCP_INFORM, NULL));
3649                 }
3650                 if (!(flags & IFF_DUPLICATE))
3651                         return (IPADM_SUCCESS);
3652                 status = i_ipadm_set_flags(iph, lifname, af, IFF_UP, 0);
3653         } else if (ipaddr.ipadm_atype == IPADM_ADDR_DHCP) {
3654                 status = i_ipadm_refresh_dhcp(&ipaddr);
3655         } else {
3656                 status = IPADM_NOTSUP;
3657         }
3658         return (status);
3659 }
3660 
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 /*
3686  * This is called from ipadm_create_addr() to validate the address parameters.
3687  * It does the following steps:
3688  * 1. Validates the interface name.
3689  * 2. Verifies that the interface is not an IPMP meta-interface or an
3690  *      underlying interface.
3691  * 3. In case of a persistent operation, verifies that the interface
3692  *      is persistent. Returns error if interface is not enabled but
3693  *      is in persistent config.
3694  * 4. Verifies that the destination address is not set or the address type is
3695  *      not DHCP or ADDRCONF when the interface is a loopback interface.
3696  * 5. Verifies that the address type is not DHCP or ADDRCONF when the interface
3697  *      has IFF_VRRP interface flag set.
3698  */
3699 static ipadm_status_t
3700 i_ipadm_validate_create_addr(ipadm_handle_t iph, ipadm_addrobj_t ipaddr,
3701     uint32_t flags)


3780                         return (IPADM_BAD_ADDR);
3781                 break;
3782         case IPADM_ADDR_DHCP:
3783                 if (islo || (ifflags & IFF_VRRP))
3784                         return (IPADM_NOTSUP);
3785                 break;
3786         case IPADM_ADDR_IPV6_ADDRCONF:
3787                 if (islo || (ifflags & IFF_VRRP) ||
3788                     i_ipadm_is_6to4(iph, ifname)) {
3789                         return (IPADM_NOTSUP);
3790                 }
3791                 break;
3792         default:
3793                 return (IPADM_INVALID_ARG);
3794         }
3795 
3796         return (IPADM_SUCCESS);
3797 }
3798 
3799 ipadm_status_t
3800 i_ipadm_merge_addrprops_from_nvl(nvlist_t *invl, nvlist_t *onvl,
3801     const char *aobjname)
3802 {
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;
3808         nvlist_t        *tnvl;
3809         char            *aname;
3810         const char      *propname;
3811         size_t          i;
3812         int             err;
3813 
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;
3834                         }
3835                 }
3836         }
3837         return (IPADM_SUCCESS);
3838 }
3839 
3840 /*
3841  * Re-enables the address object `aobjname' based on the saved
3842  * configuration for `aobjname'.
3843  */
3844 ipadm_status_t
3845 ipadm_enable_addr(ipadm_handle_t iph, const char *aobjname, uint32_t flags)
3846 {
3847         nvlist_t        *addrnvl, *nvl;
3848         nvpair_t        *nvp;
3849         ipadm_status_t  status;
3850         struct ipadm_addrobj_s ipaddr;
3851 
3852         /* check for solaris.network.interface.config authorization */
3853         if (!ipadm_check_auth())
3854                 return (IPADM_EAUTH);
3855 
3856         /* validate input */


3863 
3864         /* Retrieve the address object information. */
3865         status = i_ipadm_get_addrobj(iph, &ipaddr);
3866         if (status != IPADM_SUCCESS)
3867                 return (status);
3868         if (ipaddr.ipadm_flags & IPMGMT_ACTIVE)
3869                 return (IPADM_ADDROBJ_EXISTS);
3870 
3871         status = i_ipadm_get_db_addr(iph, NULL, aobjname, &addrnvl);
3872         if (status != IPADM_SUCCESS)
3873                 return (status);
3874 
3875         assert(addrnvl != NULL);
3876 
3877         for (nvp = nvlist_next_nvpair(addrnvl, NULL); nvp != NULL;
3878             nvp = nvlist_next_nvpair(addrnvl, nvp)) {
3879                 if (nvpair_value_nvlist(nvp, &nvl) != 0)
3880                         continue;
3881 
3882                 if (nvlist_exists(nvl, IPADM_NVP_IPV4ADDR) ||
3883                     nvlist_exists(nvl, IPADM_NVP_IPV6ADDR) ||
3884                     nvlist_exists(nvl, IPADM_NVP_DHCP)) {
3885                         status = i_ipadm_merge_addrprops_from_nvl(addrnvl, nvl,
3886                             aobjname);
3887                         if (status != IPADM_SUCCESS)
3888                                 continue;
3889                 }
3890                 iph->iph_flags |= IPH_INIT;
3891                 status = i_ipadm_init_addrobj(iph, nvl);
3892                 iph->iph_flags &= ~IPH_INIT;
3893                 if (status != IPADM_SUCCESS)
3894                         break;
3895         }
3896 
3897         return (status);
3898 }
3899 
3900 /*
3901  * Disables the address object in `aobjname' from the active configuration.
3902  * Error code return values follow the model in ipadm_delete_addr().
3903  */
3904 ipadm_status_t
3905 ipadm_disable_addr(ipadm_handle_t iph, const char *aobjname, uint32_t flags)