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)
|