xref: /illumos-gate/usr/src/lib/libipadm/common/ipadm_addr.c (revision dd72704bd9e794056c558153663c739e2012d721)
1 /*
2  * CDDL HEADER START
3  *
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 /*
23  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
24  * Copyright (c) 2013 by Delphix. All rights reserved.
25  * Copyright (c) 2016-2017, Chris Fraire <cfraire@me.com>.
26  * Copyright 2021 Tintri by DDN, Inc. All rights reserved.
27  */
28 
29 /*
30  * This file contains functions for address management such as creating
31  * an address, deleting an address, enabling an address, disabling an
32  * address, bringing an address down or up, setting/getting properties
33  * on an address object and listing address information
34  * for all addresses in active as well as persistent configuration.
35  */
36 #include <sys/types.h>
37 #include <sys/socket.h>
38 #include <sys/param.h>
39 #include <netdb.h>
40 #include <inet/ip.h>
41 #include <string.h>
42 #include <strings.h>
43 #include <assert.h>
44 #include <sys/sockio.h>
45 #include <errno.h>
46 #include <unistd.h>
47 #include <stropts.h>
48 #include <zone.h>
49 #include <netinet/in.h>
50 #include <arpa/inet.h>
51 #include <fcntl.h>
52 #include <ctype.h>
53 #include <dhcpagent_util.h>
54 #include <dhcpagent_ipc.h>
55 #include <dhcp_inittab.h>
56 #include <dhcp_symbol.h>
57 #include <ipadm_ndpd.h>
58 #include <libdladm.h>
59 #include <libdllink.h>
60 #include <libdliptun.h>
61 #include <ifaddrs.h>
62 #include "libipadm_impl.h"
63 
64 #define	SIN6(a)		((struct sockaddr_in6 *)a)
65 #define	SIN(a)		((struct sockaddr_in *)a)
66 
67 static ipadm_status_t	i_ipadm_create_addr(ipadm_handle_t, ipadm_addrobj_t,
68 			    uint32_t);
69 static ipadm_status_t	i_ipadm_create_dhcp(ipadm_handle_t, ipadm_addrobj_t,
70 			    uint32_t);
71 static ipadm_status_t	i_ipadm_delete_dhcp(ipadm_handle_t, ipadm_addrobj_t,
72 			    boolean_t);
73 static ipadm_status_t	i_ipadm_refresh_dhcp(ipadm_addrobj_t);
74 static ipadm_status_t	i_ipadm_get_db_addr(ipadm_handle_t, const char *,
75 			    const char *, nvlist_t **);
76 static ipadm_status_t	i_ipadm_op_dhcp(ipadm_addrobj_t, dhcp_ipc_type_t,
77 			    int *);
78 static ipadm_status_t	i_ipadm_dhcp_status(ipadm_addrobj_t addr,
79 			    dhcp_status_t *status, int *dhcperror);
80 static ipadm_status_t	i_ipadm_validate_create_addr(ipadm_handle_t,
81 			    ipadm_addrobj_t, uint32_t);
82 static ipadm_status_t	i_ipadm_addr_persist_nvl(ipadm_handle_t, nvlist_t *,
83 			    uint32_t);
84 static ipadm_status_t	i_ipadm_get_default_prefixlen(struct sockaddr_storage *,
85 			    uint32_t *);
86 static ipadm_status_t	i_ipadm_get_static_addr_db(ipadm_handle_t,
87 			    ipadm_addrobj_t);
88 static boolean_t	i_ipadm_is_user_aobjname_valid(const char *);
89 static ipadm_prop_desc_t	*i_ipadm_get_addrprop_desc(const char *pname);
90 
91 /*
92  * Callback functions to retrieve property values from the kernel. These
93  * functions, when required, translate the values from the kernel to a format
94  * suitable for printing. They also retrieve DEFAULT, PERM and POSSIBLE values
95  * for a given property.
96  */
97 static ipadm_pd_getf_t	i_ipadm_get_prefixlen, i_ipadm_get_addr_flag,
98 			i_ipadm_get_zone, i_ipadm_get_broadcast,
99 			i_ipadm_get_primary, i_ipadm_get_reqhost;
100 
101 /*
102  * Callback functions to set property values. These functions translate the
103  * values to a format suitable for kernel consumption, allocate the necessary
104  * ioctl buffers and then invoke ioctl(); or in the case of reqhost, get the
105  * collaborating agent to set the value.
106  */
107 static ipadm_pd_setf_t	i_ipadm_set_prefixlen, i_ipadm_set_addr_flag,
108 			i_ipadm_set_zone, i_ipadm_set_reqhost;
109 
110 static ipadm_status_t	i_ipadm_set_aobj_addrprop(ipadm_handle_t iph,
111     ipadm_addrobj_t ipaddr, uint_t flags, const char *propname);
112 
113 /* address properties description table */
114 ipadm_prop_desc_t ipadm_addrprop_table[] = {
115 	{ "broadcast", NULL, IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE, 0,
116 	    NULL, NULL, i_ipadm_get_broadcast },
117 
118 	{ "deprecated", NULL, IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE, 0,
119 	    i_ipadm_set_addr_flag, i_ipadm_get_onoff,
120 	    i_ipadm_get_addr_flag },
121 
122 	{ IPADM_NVP_PREFIXLEN, NULL, IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE, 0,
123 	    i_ipadm_set_prefixlen, i_ipadm_get_prefixlen,
124 	    i_ipadm_get_prefixlen },
125 
126 	/*
127 	 * primary is read-only because there is no operation to un-set
128 	 * DHCP_IF_PRIMARY in dhcpagent except to delete-addr and then
129 	 * re-create-addr.
130 	 */
131 	{ "primary", NULL, IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE, 0,
132 		NULL, NULL, i_ipadm_get_primary },
133 
134 	{ "private", NULL, IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE, 0,
135 	    i_ipadm_set_addr_flag, i_ipadm_get_onoff, i_ipadm_get_addr_flag },
136 
137 	{ IPADM_NVP_REQHOST, NULL, IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE, 0,
138 	    i_ipadm_set_reqhost, NULL, i_ipadm_get_reqhost },
139 
140 	{ "transmit", NULL, IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE, 0,
141 	    i_ipadm_set_addr_flag, i_ipadm_get_onoff, i_ipadm_get_addr_flag },
142 
143 	{ "zone", NULL, IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE, 0,
144 	    i_ipadm_set_zone, NULL, i_ipadm_get_zone },
145 
146 	{ NULL, NULL, 0, 0, 0, NULL, NULL, NULL }
147 };
148 
149 static ipadm_prop_desc_t up_addrprop = { "up", NULL, IPADMPROP_CLASS_ADDR,
150 					MOD_PROTO_NONE, 0, NULL, NULL, NULL };
151 
152 /*
153  * Helper function that initializes the `ipadm_ifname', `ipadm_aobjname', and
154  * `ipadm_atype' fields of the given `ipaddr'.
155  */
156 void
157 i_ipadm_init_addr(ipadm_addrobj_t ipaddr, const char *ifname,
158     const char *aobjname, ipadm_addr_type_t atype)
159 {
160 	bzero(ipaddr, sizeof (struct ipadm_addrobj_s));
161 	(void) strlcpy(ipaddr->ipadm_ifname, ifname,
162 	    sizeof (ipaddr->ipadm_ifname));
163 	(void) strlcpy(ipaddr->ipadm_aobjname, aobjname,
164 	    sizeof (ipaddr->ipadm_aobjname));
165 	ipaddr->ipadm_atype = atype;
166 }
167 
168 /*
169  * Determine the permission of the property depending on whether it has a
170  * set() and/or get() callback functions.
171  */
172 static ipadm_status_t
173 i_ipadm_pd2permstr(ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize)
174 {
175 	uint_t	perm;
176 	size_t	nbytes;
177 
178 	perm = 0;
179 	if (pdp->ipd_set != NULL)
180 		perm |= MOD_PROP_PERM_WRITE;
181 	if (pdp->ipd_get != NULL)
182 		perm |= MOD_PROP_PERM_READ;
183 
184 	nbytes = snprintf(buf, *bufsize, "%c%c",
185 	    ((perm & MOD_PROP_PERM_READ) != 0) ? 'r' : '-',
186 	    ((perm & MOD_PROP_PERM_WRITE) != 0) ? 'w' : '-');
187 
188 	if (nbytes >= *bufsize) {
189 		/* insufficient buffer space */
190 		*bufsize = nbytes + 1;
191 		return (IPADM_NO_BUFS);
192 	}
193 	return (IPADM_SUCCESS);
194 }
195 
196 /*
197  * Given an addrobj with `ipadm_aobjname' filled in, i_ipadm_get_addrobj()
198  * retrieves the information necessary for any operation on the object,
199  * such as delete-addr, enable-addr, disable-addr, up-addr, down-addr,
200  * refresh-addr, get-addrprop or set-addrprop. The information include
201  * the logical interface number, address type, address family,
202  * the interface id (if the address type is IPADM_ADDR_IPV6_ADDRCONF) and
203  * the ipadm_flags that indicate if the address is present in
204  * active configuration or persistent configuration or both. If the address
205  * is not found, IPADM_NOTSUP is returned.
206  */
207 ipadm_status_t
208 i_ipadm_get_addrobj(ipadm_handle_t iph, ipadm_addrobj_t ipaddr)
209 {
210 	ipmgmt_aobjop_arg_t	larg;
211 	ipmgmt_aobjop_rval_t	rval, *rvalp;
212 	int			err = 0;
213 
214 	/* populate the door_call argument structure */
215 	larg.ia_cmd = IPMGMT_CMD_AOBJNAME2ADDROBJ;
216 	(void) strlcpy(larg.ia_aobjname, ipaddr->ipadm_aobjname,
217 	    sizeof (larg.ia_aobjname));
218 
219 	rvalp = &rval;
220 	err = ipadm_door_call(iph, &larg, sizeof (larg), (void **)&rvalp,
221 	    sizeof (rval), B_FALSE);
222 	if (err != 0)
223 		return (ipadm_errno2status(err));
224 	(void) strlcpy(ipaddr->ipadm_ifname, rval.ir_ifname,
225 	    sizeof (ipaddr->ipadm_ifname));
226 	ipaddr->ipadm_lifnum = rval.ir_lnum;
227 	ipaddr->ipadm_atype = rval.ir_atype;
228 	ipaddr->ipadm_af = rval.ir_family;
229 	ipaddr->ipadm_flags = rval.ir_flags;
230 	switch (rval.ir_atype) {
231 	case IPADM_ADDR_IPV6_ADDRCONF:
232 		ipaddr->ipadm_intfid = rval.ipmgmt_ir_intfid;
233 		break;
234 	case IPADM_ADDR_DHCP:
235 		if (strlcpy(ipaddr->ipadm_reqhost, rval.ipmgmt_ir_reqhost,
236 		    sizeof (ipaddr->ipadm_reqhost)) >=
237 		    sizeof (ipaddr->ipadm_reqhost)) {
238 			/*
239 			 * shouldn't get here as the buffers are defined
240 			 * with same length, MAX_NAME_LEN
241 			 */
242 			return (IPADM_FAILURE);
243 		}
244 		break;
245 	default:
246 		break;
247 	}
248 
249 	return (IPADM_SUCCESS);
250 }
251 
252 /*
253  * Retrieves the static address (IPv4 or IPv6) for the given address object
254  * in `ipaddr' from persistent DB.
255  */
256 static ipadm_status_t
257 i_ipadm_get_static_addr_db(ipadm_handle_t iph, ipadm_addrobj_t ipaddr)
258 {
259 	ipadm_status_t		status;
260 	nvlist_t		*onvl;
261 	nvlist_t		*anvl = NULL;
262 	nvlist_t		*nvladdr;
263 	nvpair_t		*nvp;
264 	char			*name;
265 	char			*aobjname = ipaddr->ipadm_aobjname;
266 	char			*sname;
267 	sa_family_t		af = AF_UNSPEC;
268 
269 	/*
270 	 * Get the address line in the nvlist `onvl' from ipmgmtd daemon.
271 	 */
272 	status = i_ipadm_get_db_addr(iph, NULL, aobjname, &onvl);
273 	if (status != IPADM_SUCCESS)
274 		return (status);
275 	/*
276 	 * Walk through the nvlist `onvl' to extract the IPADM_NVP_IPV4ADDR
277 	 * or the IPADM_NVP_IPV6ADDR name-value pair.
278 	 */
279 	for (nvp = nvlist_next_nvpair(onvl, NULL); nvp != NULL;
280 	    nvp = nvlist_next_nvpair(onvl, NULL)) {
281 		if (nvpair_value_nvlist(nvp, &anvl) != 0)
282 			continue;
283 		if (nvlist_exists(anvl, IPADM_NVP_IPV4ADDR) ||
284 		    nvlist_exists(anvl, IPADM_NVP_IPV6ADDR))
285 			break;
286 	}
287 	nvlist_free(onvl);
288 
289 	if (nvp == NULL)
290 		return (IPADM_NOTFOUND);
291 
292 	for (nvp = nvlist_next_nvpair(anvl, NULL);
293 	    nvp != NULL; nvp = nvlist_next_nvpair(anvl, nvp)) {
294 		name = nvpair_name(nvp);
295 		if (strcmp(name, IPADM_NVP_IPV4ADDR) == 0) {
296 			af = AF_INET;
297 			break;
298 		} else if (strcmp(name, IPADM_NVP_IPV6ADDR) == 0) {
299 			af = AF_INET6;
300 			break;
301 		}
302 	}
303 	assert(af != AF_UNSPEC);
304 
305 	if (nvpair_value_nvlist(nvp, &nvladdr) != 0 ||
306 	    nvlist_lookup_string(nvladdr, IPADM_NVP_IPADDRHNAME, &sname) != 0 ||
307 	    ipadm_set_addr(ipaddr, sname, af) != IPADM_SUCCESS)
308 		return (IPADM_NOTFOUND);
309 
310 	return (IPADM_SUCCESS);
311 }
312 
313 /*
314  * For the given `addrobj->ipadm_lifnum' and `addrobj->ipadm_af', this function
315  * fills in the address objname, the address type and the ipadm_flags.
316  */
317 ipadm_status_t
318 i_ipadm_get_lif2addrobj(ipadm_handle_t iph, ipadm_addrobj_t addrobj)
319 {
320 	ipmgmt_aobjop_arg_t	larg;
321 	ipmgmt_aobjop_rval_t	rval, *rvalp;
322 	int			err;
323 
324 	larg.ia_cmd = IPMGMT_CMD_LIF2ADDROBJ;
325 	(void) strlcpy(larg.ia_ifname, addrobj->ipadm_ifname,
326 	    sizeof (larg.ia_ifname));
327 	larg.ia_lnum = addrobj->ipadm_lifnum;
328 	larg.ia_family = addrobj->ipadm_af;
329 
330 	rvalp = &rval;
331 	err = ipadm_door_call(iph, &larg, sizeof (larg), (void **)&rvalp,
332 	    sizeof (rval), B_FALSE);
333 	if (err != 0)
334 		return (ipadm_errno2status(err));
335 	(void) strlcpy(addrobj->ipadm_aobjname, rval.ir_aobjname,
336 	    sizeof (addrobj->ipadm_aobjname));
337 	addrobj->ipadm_atype = rval.ir_atype;
338 	addrobj->ipadm_flags = rval.ir_flags;
339 
340 	return (IPADM_SUCCESS);
341 }
342 
343 /*
344  * Adds an addrobj to ipmgmtd daemon's aobjmap (active configuration).
345  * with the given name and logical interface number.
346  * This API is called by in.ndpd to add addrobjs when new prefixes or
347  * dhcpv6 addresses are configured.
348  */
349 ipadm_status_t
350 ipadm_add_aobjname(ipadm_handle_t iph, const char *ifname, sa_family_t af,
351     const char *aobjname, ipadm_addr_type_t atype, int lnum)
352 {
353 	ipmgmt_aobjop_arg_t	larg;
354 	int			err;
355 
356 	larg.ia_cmd = IPMGMT_CMD_ADDROBJ_ADD;
357 	(void) strlcpy(larg.ia_ifname, ifname, sizeof (larg.ia_ifname));
358 	(void) strlcpy(larg.ia_aobjname, aobjname, sizeof (larg.ia_aobjname));
359 	larg.ia_atype = atype;
360 	larg.ia_lnum = lnum;
361 	larg.ia_family = af;
362 	err = ipadm_door_call(iph, &larg, sizeof (larg), NULL, 0, B_FALSE);
363 	return (ipadm_errno2status(err));
364 }
365 
366 /*
367  * Deletes an address object with given name and logical number from ipmgmtd
368  * daemon's aobjmap (active configuration). This API is called by in.ndpd to
369  * remove addrobjs when auto-configured prefixes or dhcpv6 addresses are
370  * removed.
371  */
372 ipadm_status_t
373 ipadm_delete_aobjname(ipadm_handle_t iph, const char *ifname, sa_family_t af,
374     const char *aobjname, ipadm_addr_type_t atype, int lnum)
375 {
376 	struct ipadm_addrobj_s	aobj;
377 
378 	i_ipadm_init_addr(&aobj, ifname, aobjname, atype);
379 	aobj.ipadm_af = af;
380 	aobj.ipadm_lifnum = lnum;
381 	return (i_ipadm_delete_addrobj(iph, &aobj, IPADM_OPT_ACTIVE));
382 }
383 
384 /*
385  * Gets all the addresses from active configuration and populates the
386  * address information in `addrinfo'.
387  */
388 ipadm_status_t
389 i_ipadm_active_addr_info(ipadm_handle_t iph, const char *ifname,
390     ipadm_addr_info_t **addrinfo, uint32_t ipadm_flags, int64_t lifc_flags)
391 {
392 	ipadm_status_t		status;
393 	struct ifaddrs		*ifap, *ifa;
394 	ipadm_addr_info_t	*curr, *prev = NULL;
395 	struct ifaddrs		*cifaddr;
396 	struct lifreq		lifr;
397 	int			sock;
398 	uint64_t		flags;
399 	char			cifname[LIFNAMSIZ];
400 	struct sockaddr_in6	*sin6;
401 	struct ipadm_addrobj_s	ipaddr;
402 	char			*sep;
403 	int			lnum;
404 
405 retry:
406 	*addrinfo = NULL;
407 
408 	/* Get all the configured addresses */
409 	if (getallifaddrs(AF_UNSPEC, &ifa, lifc_flags) < 0)
410 		return (ipadm_errno2status(errno));
411 	/* Return if there is nothing to process. */
412 	if (ifa == NULL)
413 		return (IPADM_SUCCESS);
414 	bzero(&lifr, sizeof (lifr));
415 	for (ifap = ifa; ifap != NULL; ifap = ifap->ifa_next) {
416 		struct sockaddr_storage data;
417 
418 		if (ifap->ifa_addr->sa_family == AF_LINK)
419 			continue;
420 
421 		(void) strlcpy(cifname, ifap->ifa_name, sizeof (cifname));
422 		lnum = 0;
423 		if ((sep = strrchr(cifname, ':')) != NULL) {
424 			*sep++ = '\0';
425 			lnum = atoi(sep);
426 		}
427 		if (ifname != NULL && strcmp(cifname, ifname) != 0)
428 			continue;
429 		if (!(ipadm_flags & IPADM_OPT_ZEROADDR) &&
430 		    sockaddrunspec(ifap->ifa_addr) &&
431 		    !(ifap->ifa_flags & IFF_DHCPRUNNING))
432 			continue;
433 
434 		/* Allocate and populate the current node in the list. */
435 		if ((curr = calloc(1, sizeof (ipadm_addr_info_t))) == NULL)
436 			goto fail;
437 
438 		/* Link to the list in `addrinfo'. */
439 		if (prev != NULL)
440 			prev->ia_ifa.ifa_next = &curr->ia_ifa;
441 		else
442 			*addrinfo = curr;
443 		prev = curr;
444 
445 		cifaddr = &curr->ia_ifa;
446 		if ((cifaddr->ifa_name = strdup(ifap->ifa_name)) == NULL)
447 			goto fail;
448 		cifaddr->ifa_flags = ifap->ifa_flags;
449 		cifaddr->ifa_addr = malloc(sizeof (struct sockaddr_storage));
450 		if (cifaddr->ifa_addr == NULL)
451 			goto fail;
452 		(void) memcpy(cifaddr->ifa_addr, ifap->ifa_addr,
453 		    sizeof (struct sockaddr_storage));
454 		cifaddr->ifa_netmask = malloc(sizeof (struct sockaddr_storage));
455 		if (cifaddr->ifa_netmask == NULL)
456 			goto fail;
457 		(void) memcpy(cifaddr->ifa_netmask, ifap->ifa_netmask,
458 		    sizeof (struct sockaddr_storage));
459 		if (ifap->ifa_flags & IFF_POINTOPOINT) {
460 			cifaddr->ifa_dstaddr = malloc(
461 			    sizeof (struct sockaddr_storage));
462 			if (cifaddr->ifa_dstaddr == NULL)
463 				goto fail;
464 			(void) memcpy(cifaddr->ifa_dstaddr, ifap->ifa_dstaddr,
465 			    sizeof (struct sockaddr_storage));
466 		} else if (ifap->ifa_flags & IFF_BROADCAST) {
467 			cifaddr->ifa_broadaddr = malloc(
468 			    sizeof (struct sockaddr_storage));
469 			if (cifaddr->ifa_broadaddr == NULL)
470 				goto fail;
471 			(void) memcpy(cifaddr->ifa_broadaddr,
472 			    ifap->ifa_broadaddr,
473 			    sizeof (struct sockaddr_storage));
474 		}
475 		/* Get the addrobj name stored for this logical interface. */
476 		ipaddr.ipadm_aobjname[0] = '\0';
477 		(void) strlcpy(ipaddr.ipadm_ifname, cifname,
478 		    sizeof (ipaddr.ipadm_ifname));
479 		ipaddr.ipadm_lifnum = lnum;
480 		ipaddr.ipadm_af = ifap->ifa_addr->sa_family;
481 		status = i_ipadm_get_lif2addrobj(iph, &ipaddr);
482 
483 		/*
484 		 * Find address type from ifa_flags, if we could not get it
485 		 * from daemon.
486 		 */
487 		(void) memcpy(&data, ifap->ifa_addr,
488 		    sizeof (struct sockaddr_in6));
489 		sin6 = SIN6(&data);
490 		flags = ifap->ifa_flags;
491 		if (status == IPADM_SUCCESS) {
492 			(void) strlcpy(curr->ia_aobjname, ipaddr.ipadm_aobjname,
493 			    sizeof (curr->ia_aobjname));
494 			curr->ia_atype = ipaddr.ipadm_atype;
495 		} else if ((flags & IFF_DHCPRUNNING) && (!(flags & IFF_IPV6) ||
496 		    !IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))) {
497 			curr->ia_atype = IPADM_ADDR_DHCP;
498 		} else if (flags & IFF_ADDRCONF) {
499 			curr->ia_atype = IPADM_ADDR_IPV6_ADDRCONF;
500 		} else {
501 			curr->ia_atype = IPADM_ADDR_STATIC;
502 		}
503 		/*
504 		 * Populate the flags for the active configuration from the
505 		 * `ifa_flags'.
506 		 */
507 		if (!(flags & IFF_UP)) {
508 			if (flags & IFF_DUPLICATE)
509 				curr->ia_state = IFA_DUPLICATE;
510 			else
511 				curr->ia_state = IFA_DOWN;
512 		} else {
513 			curr->ia_cflags |= IA_UP;
514 			if (flags & IFF_RUNNING) {
515 				(void) strlcpy(lifr.lifr_name, ifap->ifa_name,
516 				    sizeof (lifr.lifr_name));
517 				sock = (ifap->ifa_addr->sa_family == AF_INET) ?
518 				    iph->iph_sock : iph->iph_sock6;
519 				if (ioctl(sock, SIOCGLIFDADSTATE,
520 				    (caddr_t)&lifr) < 0) {
521 					if (errno == ENXIO) {
522 						freeifaddrs(ifa);
523 						ipadm_free_addr_info(*addrinfo);
524 						goto retry;
525 					}
526 					goto fail;
527 				}
528 				if (lifr.lifr_dadstate == DAD_IN_PROGRESS)
529 					curr->ia_state = IFA_TENTATIVE;
530 				else
531 					curr->ia_state = IFA_OK;
532 			} else {
533 				curr->ia_state = IFA_INACCESSIBLE;
534 			}
535 		}
536 		if (flags & IFF_UNNUMBERED)
537 			curr->ia_cflags |= IA_UNNUMBERED;
538 		if (flags & IFF_PRIVATE)
539 			curr->ia_cflags |= IA_PRIVATE;
540 		if (flags & IFF_TEMPORARY)
541 			curr->ia_cflags |= IA_TEMPORARY;
542 		if (flags & IFF_DEPRECATED)
543 			curr->ia_cflags |= IA_DEPRECATED;
544 
545 	}
546 
547 	freeifaddrs(ifa);
548 	return (IPADM_SUCCESS);
549 
550 fail:
551 	/* On error, cleanup everything and return. */
552 	ipadm_free_addr_info(*addrinfo);
553 	*addrinfo = NULL;
554 	freeifaddrs(ifa);
555 	return (ipadm_errno2status(errno));
556 }
557 
558 /*
559  * From the given `name', i_ipadm_name2atype() deduces the address type
560  * and address family. If the `name' implies an address, it returns B_TRUE.
561  * Else, returns B_FALSE and leaves the output parameters unchanged.
562  */
563 boolean_t
564 i_ipadm_name2atype(const char *name, sa_family_t *af, ipadm_addr_type_t *type)
565 {
566 	boolean_t	is_addr = B_TRUE;
567 
568 	if (strcmp(name, IPADM_NVP_IPV4ADDR) == 0) {
569 		*af = AF_INET;
570 		*type = IPADM_ADDR_STATIC;
571 	} else if (strcmp(name, IPADM_NVP_IPV6ADDR) == 0) {
572 		*af = AF_INET6;
573 		*type = IPADM_ADDR_STATIC;
574 	} else if (strcmp(name, IPADM_NVP_DHCP) == 0) {
575 		*af = AF_INET;
576 		*type = IPADM_ADDR_DHCP;
577 	} else if (strcmp(name, IPADM_NVP_INTFID) == 0) {
578 		*af = AF_INET6;
579 		*type = IPADM_ADDR_IPV6_ADDRCONF;
580 	} else {
581 		is_addr = B_FALSE;
582 	}
583 
584 	return (is_addr);
585 }
586 
587 /*
588  * Parses the given nvlist `nvl' for an address or an address property.
589  * The input nvlist must contain either an address or an address property.
590  * `ainfo' is an input as well as output parameter. When an address or an
591  * address property is found, `ainfo' is updated with the information found.
592  * Some of the fields may be already filled in by the calling function.
593  *
594  * The fields that will be filled/updated by this function are `ia_pflags',
595  * `ia_sname' and `ia_dname'. Values for `ia_pflags' are obtained if the `nvl'
596  * contains an address property. `ia_sname', `ia_dname', and `ia_pflags' are
597  * obtained if `nvl' contains an address.
598  */
599 static ipadm_status_t
600 i_ipadm_nvl2ainfo_common(nvlist_t *nvl, ipadm_addr_info_t *ainfo)
601 {
602 	nvlist_t		*nvladdr;
603 	char			*name;
604 	char			*propstr = NULL;
605 	char			*sname, *dname;
606 	nvpair_t		*nvp;
607 	sa_family_t		af;
608 	ipadm_addr_type_t	atype;
609 	boolean_t		is_addr = B_FALSE;
610 	int			err;
611 
612 	for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL;
613 	    nvp = nvlist_next_nvpair(nvl, nvp)) {
614 		name = nvpair_name(nvp);
615 		if (i_ipadm_name2atype(name, &af, &atype)) {
616 			err = nvpair_value_nvlist(nvp, &nvladdr);
617 			is_addr = B_TRUE;
618 		} else if (IPADM_PRIV_NVP(name)) {
619 			continue;
620 		} else {
621 			err = nvpair_value_string(nvp, &propstr);
622 		}
623 		if (err != 0)
624 			return (ipadm_errno2status(err));
625 	}
626 
627 	if (is_addr) {
628 		/*
629 		 * We got an address from the nvlist `nvl'.
630 		 * Parse `nvladdr' and populate relevant information
631 		 * in `ainfo'.
632 		 */
633 		switch (atype) {
634 		case IPADM_ADDR_STATIC:
635 			if (strcmp(name, "up") == 0 &&
636 			    strcmp(propstr, "yes") == 0) {
637 				ainfo->ia_pflags |= IA_UP;
638 			}
639 			/*
640 			 * For static addresses, we need to get the hostnames.
641 			 */
642 			err = nvlist_lookup_string(nvladdr,
643 			    IPADM_NVP_IPADDRHNAME, &sname);
644 			if (err != 0)
645 				return (ipadm_errno2status(err));
646 			(void) strlcpy(ainfo->ia_sname, sname,
647 			    sizeof (ainfo->ia_sname));
648 			err = nvlist_lookup_string(nvladdr,
649 			    IPADM_NVP_IPDADDRHNAME, &dname);
650 			if (err == 0) {
651 				(void) strlcpy(ainfo->ia_dname, dname,
652 				    sizeof (ainfo->ia_dname));
653 			}
654 			break;
655 		case IPADM_ADDR_DHCP:
656 		case IPADM_ADDR_IPV6_ADDRCONF:
657 			/*
658 			 * dhcp and addrconf address objects are always
659 			 * marked up when re-enabled.
660 			 */
661 			ainfo->ia_pflags |= IA_UP;
662 			break;
663 		default:
664 			return (IPADM_FAILURE);
665 		}
666 	} else {
667 		/*
668 		 * We got an address property from `nvl'. Parse the
669 		 * name and the property value. Update the `ainfo->ia_pflags'
670 		 * for the flags.
671 		 */
672 		if (strcmp(name, "deprecated") == 0) {
673 			if (strcmp(propstr, IPADM_ONSTR) == 0)
674 				ainfo->ia_pflags |= IA_DEPRECATED;
675 		} else if (strcmp(name, "private") == 0) {
676 			if (strcmp(propstr, IPADM_ONSTR) == 0)
677 				ainfo->ia_pflags |= IA_PRIVATE;
678 		}
679 	}
680 
681 	return (IPADM_SUCCESS);
682 }
683 
684 /*
685  * Parses the given nvlist `nvl' for an address or an address property.
686  * The input nvlist must contain either an address or an address property.
687  * `ainfo' is an input as well as output parameter. When an address or an
688  * address property is found, `ainfo' is updated with the information found.
689  * Some of the fields may be already filled in by the calling function,
690  * because of previous calls to i_ipadm_nvl2ainfo_active().
691  *
692  * Since the address object in `nvl' is also in the active configuration, the
693  * fields that will be filled/updated by this function are `ia_pflags',
694  * `ia_sname' and `ia_dname'.
695  *
696  * If this function returns an error, the calling function will take
697  * care of freeing the fields in `ainfo'.
698  */
699 static ipadm_status_t
700 i_ipadm_nvl2ainfo_active(nvlist_t *nvl, ipadm_addr_info_t *ainfo)
701 {
702 	return (i_ipadm_nvl2ainfo_common(nvl, ainfo));
703 }
704 
705 /*
706  * Parses the given nvlist `nvl' for an address or an address property.
707  * The input nvlist must contain either an address or an address property.
708  * `ainfo' is an input as well as output parameter. When an address or an
709  * address property is found, `ainfo' is updated with the information found.
710  * Some of the fields may be already filled in by the calling function,
711  * because of previous calls to i_ipadm_nvl2ainfo_persist().
712  *
713  * All the relevant fields in `ainfo' will be filled by this function based
714  * on what we find in `nvl'.
715  *
716  * If this function returns an error, the calling function will take
717  * care of freeing the fields in `ainfo'.
718  */
719 static ipadm_status_t
720 i_ipadm_nvl2ainfo_persist(nvlist_t *nvl, ipadm_addr_info_t *ainfo)
721 {
722 	nvlist_t		*nvladdr;
723 	struct ifaddrs		*ifa;
724 	char			*name;
725 	char			*ifname = NULL;
726 	char			*aobjname = NULL;
727 	char			*propstr = NULL;
728 	nvpair_t		*nvp;
729 	sa_family_t		af;
730 	ipadm_addr_type_t	atype;
731 	boolean_t		is_addr = B_FALSE;
732 	size_t			size = sizeof (struct sockaddr_storage);
733 	uint32_t		plen = 0;
734 	int			err;
735 	ipadm_status_t		status;
736 
737 	status = i_ipadm_nvl2ainfo_common(nvl, ainfo);
738 	if (status != IPADM_SUCCESS)
739 		return (status);
740 
741 	for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL;
742 	    nvp = nvlist_next_nvpair(nvl, nvp)) {
743 		name = nvpair_name(nvp);
744 		if (strcmp(name, IPADM_NVP_IFNAME) == 0) {
745 			err = nvpair_value_string(nvp, &ifname);
746 		} else if (strcmp(name, IPADM_NVP_AOBJNAME) == 0) {
747 			err = nvpair_value_string(nvp, &aobjname);
748 		} else if (i_ipadm_name2atype(name, &af, &atype)) {
749 			err = nvpair_value_nvlist(nvp, &nvladdr);
750 			is_addr = B_TRUE;
751 		} else {
752 			err = nvpair_value_string(nvp, &propstr);
753 		}
754 		if (err != 0)
755 			return (ipadm_errno2status(err));
756 	}
757 
758 	ifa = &ainfo->ia_ifa;
759 	(void) strlcpy(ainfo->ia_aobjname, aobjname,
760 	    sizeof (ainfo->ia_aobjname));
761 	if (ifa->ifa_name == NULL && (ifa->ifa_name = strdup(ifname)) == NULL)
762 		return (IPADM_NO_MEMORY);
763 	if (is_addr) {
764 		struct sockaddr_in6 data;
765 
766 		/*
767 		 * We got an address from the nvlist `nvl'.
768 		 * Parse `nvladdr' and populate `ifa->ifa_addr'.
769 		 */
770 		ainfo->ia_atype = atype;
771 		if ((ifa->ifa_addr = calloc(1, size)) == NULL)
772 			return (IPADM_NO_MEMORY);
773 		switch (atype) {
774 		case IPADM_ADDR_STATIC:
775 			ifa->ifa_addr->sa_family = af;
776 			break;
777 		case IPADM_ADDR_DHCP:
778 			ifa->ifa_addr->sa_family = AF_INET;
779 			break;
780 		case IPADM_ADDR_IPV6_ADDRCONF:
781 			data.sin6_family = AF_INET6;
782 			if (i_ipadm_nvl2in6_addr(nvladdr, IPADM_NVP_IPNUMADDR,
783 			    &data.sin6_addr) != IPADM_SUCCESS)
784 				return (IPADM_NO_MEMORY);
785 			err = nvlist_lookup_uint32(nvladdr, IPADM_NVP_PREFIXLEN,
786 			    &plen);
787 			if (err != 0)
788 				return (ipadm_errno2status(err));
789 			if ((ifa->ifa_netmask = malloc(size)) == NULL)
790 				return (IPADM_NO_MEMORY);
791 			if ((err = plen2mask(plen, af, ifa->ifa_netmask)) != 0)
792 				return (ipadm_errno2status(err));
793 			(void) memcpy(ifa->ifa_addr, &data, sizeof (data));
794 			break;
795 		default:
796 			return (IPADM_FAILURE);
797 		}
798 	} else {
799 		if (strcmp(name, "prefixlen") == 0) {
800 			/*
801 			 * If a prefixlen was found, update the
802 			 * `ainfo->ia_ifa.ifa_netmask'.
803 			 */
804 
805 			if ((ifa->ifa_netmask = malloc(size)) == NULL)
806 				return (IPADM_NO_MEMORY);
807 			/*
808 			 * Address property lines always follow the address
809 			 * line itself in the persistent db. We must have
810 			 * found a valid `ainfo->ia_ifa.ifa_addr' by now.
811 			 */
812 			assert(ifa->ifa_addr != NULL);
813 			err = plen2mask(atoi(propstr), ifa->ifa_addr->sa_family,
814 			    ifa->ifa_netmask);
815 			if (err != 0)
816 				return (ipadm_errno2status(err));
817 		}
818 	}
819 
820 	return (IPADM_SUCCESS);
821 }
822 
823 /*
824  * Retrieves all addresses from active config and appends to it the
825  * addresses that are found only in persistent config. In addition,
826  * it updates the persistent fields for each address from information
827  * found in persistent config. The output parameter `addrinfo' contains
828  * complete information regarding all addresses in active as well as
829  * persistent config.
830  */
831 static ipadm_status_t
832 i_ipadm_get_all_addr_info(ipadm_handle_t iph, const char *ifname,
833     ipadm_addr_info_t **addrinfo, uint32_t ipadm_flags, int64_t lifc_flags)
834 {
835 	nvlist_t		*nvladdr = NULL;
836 	nvlist_t		*onvl = NULL;
837 	nvpair_t		*nvp;
838 	ipadm_status_t		status;
839 	ipadm_addr_info_t	*ainfo = NULL;
840 	ipadm_addr_info_t	*curr;
841 	ipadm_addr_info_t	*last = NULL;
842 	char			*aobjname;
843 
844 	/* Get all addresses from active config. */
845 	status = i_ipadm_active_addr_info(iph, ifname, &ainfo, ipadm_flags,
846 	    lifc_flags);
847 	if (status != IPADM_SUCCESS)
848 		goto fail;
849 
850 	/* Get all addresses from persistent config. */
851 	status = i_ipadm_get_db_addr(iph, ifname, NULL, &onvl);
852 	/*
853 	 * If no address was found in persistent config, just
854 	 * return what we found in active config.
855 	 */
856 	if (status == IPADM_NOTFOUND) {
857 		/*
858 		 * If nothing was found neither active nor persistent
859 		 * config, this means that the interface does not exist,
860 		 * if one was provided in `ifname'.
861 		 */
862 		if (ainfo == NULL && ifname != NULL)
863 			return (IPADM_ENXIO);
864 		*addrinfo = ainfo;
865 		return (IPADM_SUCCESS);
866 	}
867 	/* In case of any other error, cleanup and return. */
868 	if (status != IPADM_SUCCESS)
869 		goto fail;
870 	/* we append to make sure, loopback addresses are first */
871 	if (ainfo != NULL) {
872 		for (curr = ainfo; IA_NEXT(curr) != NULL; curr = IA_NEXT(curr))
873 			;
874 		last = curr;
875 	}
876 
877 	/*
878 	 * `onvl' will contain all the address lines from the db. Each line
879 	 * could contain the address itself or an address property. Addresses
880 	 * and address properties are found in separate lines.
881 	 *
882 	 * If an address A was found in active, we will already have `ainfo',
883 	 * and it is present in persistent configuration as well, we need to
884 	 * update `ainfo' with persistent information (`ia_pflags).
885 	 * For each address B found only in persistent configuration,
886 	 * append the address to the list with the address info for B from
887 	 * `onvl'.
888 	 */
889 	for (nvp = nvlist_next_nvpair(onvl, NULL); nvp != NULL;
890 	    nvp = nvlist_next_nvpair(onvl, nvp)) {
891 		if (nvpair_value_nvlist(nvp, &nvladdr) != 0)
892 			continue;
893 		if (nvlist_lookup_string(nvladdr, IPADM_NVP_AOBJNAME,
894 		    &aobjname) != 0)
895 			continue;
896 		for (curr = ainfo; curr != NULL; curr = IA_NEXT(curr)) {
897 			if (strcmp(curr->ia_aobjname, aobjname) == 0)
898 				break;
899 		}
900 		if (curr == NULL) {
901 			/*
902 			 * We did not find this address object in `ainfo'.
903 			 * This means that the address object exists only
904 			 * in the persistent configuration. Get its
905 			 * details and append to `ainfo'.
906 			 */
907 			curr = calloc(1, sizeof (ipadm_addr_info_t));
908 			if (curr == NULL)
909 				goto fail;
910 			curr->ia_state = IFA_DISABLED;
911 			if (last != NULL)
912 				last->ia_ifa.ifa_next = &curr->ia_ifa;
913 			else
914 				ainfo = curr;
915 			last = curr;
916 		}
917 		/*
918 		 * Fill relevant fields of `curr' from the persistent info
919 		 * in `nvladdr'. Call the appropriate function based on the
920 		 * `ia_state' value.
921 		 */
922 		if (curr->ia_state == IFA_DISABLED)
923 			status = i_ipadm_nvl2ainfo_persist(nvladdr, curr);
924 		else
925 			status = i_ipadm_nvl2ainfo_active(nvladdr, curr);
926 		if (status != IPADM_SUCCESS)
927 			goto fail;
928 	}
929 	*addrinfo = ainfo;
930 	nvlist_free(onvl);
931 	return (status);
932 fail:
933 	/* On error, cleanup and return. */
934 	nvlist_free(onvl);
935 	ipadm_free_addr_info(ainfo);
936 	*addrinfo = NULL;
937 	return (status);
938 }
939 
940 /*
941  * Callback function that sets the property `prefixlen' on the address
942  * object in `arg' to the value in `pval'.
943  */
944 /* ARGSUSED */
945 static ipadm_status_t
946 i_ipadm_set_prefixlen(ipadm_handle_t iph, const void *arg,
947     ipadm_prop_desc_t *pdp, const void *pval, uint_t af, uint_t flags)
948 {
949 	struct sockaddr_storage	netmask;
950 	struct lifreq		lifr;
951 	int			err, s;
952 	unsigned long		prefixlen, abits;
953 	char			*end;
954 	ipadm_addrobj_t		ipaddr = (ipadm_addrobj_t)arg;
955 
956 	if (ipaddr->ipadm_atype == IPADM_ADDR_DHCP)
957 		return (IPADM_NOTSUP);
958 
959 	errno = 0;
960 	prefixlen = strtoul(pval, &end, 10);
961 	if (errno != 0 || *end != '\0')
962 		return (IPADM_INVALID_ARG);
963 
964 	abits = (af == AF_INET ? IP_ABITS : IPV6_ABITS);
965 	if (prefixlen == 0 || prefixlen == (abits - 1))
966 		return (IPADM_INVALID_ARG);
967 
968 	if ((err = plen2mask(prefixlen, af, (struct sockaddr *)&netmask)) != 0)
969 		return (ipadm_errno2status(err));
970 
971 	s = (af == AF_INET ? iph->iph_sock : iph->iph_sock6);
972 
973 	bzero(&lifr, sizeof (lifr));
974 	i_ipadm_addrobj2lifname(ipaddr, lifr.lifr_name,
975 	    sizeof (lifr.lifr_name));
976 	(void) memcpy(&lifr.lifr_addr, &netmask, sizeof (netmask));
977 	if (ioctl(s, SIOCSLIFNETMASK, (caddr_t)&lifr) < 0)
978 		return (ipadm_errno2status(errno));
979 
980 	/* now, change the broadcast address to reflect the prefixlen */
981 	if (af == AF_INET) {
982 		/*
983 		 * get the interface address and set it, this should reset
984 		 * the broadcast address.
985 		 */
986 		(void) ioctl(s, SIOCGLIFADDR, (caddr_t)&lifr);
987 		(void) ioctl(s, SIOCSLIFADDR, (caddr_t)&lifr);
988 	}
989 
990 	return (IPADM_SUCCESS);
991 }
992 
993 
994 /*
995  * Callback function that sets the given value `pval' to one of the
996  * properties among `deprecated', `private', and `transmit' as defined in
997  * `pdp', on the address object in `arg'.
998  */
999 /* ARGSUSED */
1000 static ipadm_status_t
1001 i_ipadm_set_addr_flag(ipadm_handle_t iph, const void *arg,
1002     ipadm_prop_desc_t *pdp, const void *pval, uint_t af, uint_t flags)
1003 {
1004 	char		lifname[LIFNAMSIZ];
1005 	uint64_t	on_flags = 0, off_flags = 0;
1006 	boolean_t	on;
1007 	ipadm_addrobj_t	ipaddr = (ipadm_addrobj_t)arg;
1008 
1009 	if (ipaddr->ipadm_atype == IPADM_ADDR_DHCP &&
1010 	    strcmp(pdp->ipd_name, "deprecated") == 0)
1011 		return (IPADM_NOTSUP);
1012 
1013 	if (strcmp(pval, IPADM_ONSTR) == 0)
1014 		on = B_TRUE;
1015 	else if (strcmp(pval, IPADM_OFFSTR) == 0)
1016 		on = B_FALSE;
1017 	else
1018 		return (IPADM_INVALID_ARG);
1019 
1020 	if (strcmp(pdp->ipd_name, "private") == 0) {
1021 		if (on)
1022 			on_flags = IFF_PRIVATE;
1023 		else
1024 			off_flags = IFF_PRIVATE;
1025 	} else if (strcmp(pdp->ipd_name, "transmit") == 0) {
1026 		if (on)
1027 			off_flags = IFF_NOXMIT;
1028 		else
1029 			on_flags = IFF_NOXMIT;
1030 	} else if (strcmp(pdp->ipd_name, "deprecated") == 0) {
1031 		if (on)
1032 			on_flags = IFF_DEPRECATED;
1033 		else
1034 			off_flags = IFF_DEPRECATED;
1035 	} else {
1036 		return (IPADM_PROP_UNKNOWN);
1037 	}
1038 
1039 	i_ipadm_addrobj2lifname(ipaddr, lifname, sizeof (lifname));
1040 	return (i_ipadm_set_flags(iph, lifname, af, on_flags, off_flags));
1041 }
1042 
1043 /*
1044  * Callback function that sets the property `zone' on the address
1045  * object in `arg' to the value in `pval'.
1046  */
1047 /* ARGSUSED */
1048 static ipadm_status_t
1049 i_ipadm_set_zone(ipadm_handle_t iph, const void *arg,
1050     ipadm_prop_desc_t *pdp, const void *pval, uint_t af, uint_t flags)
1051 {
1052 	struct lifreq	lifr;
1053 	zoneid_t	zoneid;
1054 	int		s;
1055 
1056 	/*
1057 	 * To modify the zone assignment such that it persists across
1058 	 * reboots, zonecfg(8) must be used.
1059 	 */
1060 	if (flags & IPADM_OPT_PERSIST) {
1061 		return (IPADM_NOTSUP);
1062 	} else if (flags & IPADM_OPT_ACTIVE) {
1063 		/* put logical interface into all zones */
1064 		if (strcmp(pval, "all-zones") == 0) {
1065 			zoneid = ALL_ZONES;
1066 		} else {
1067 			/* zone must be ready or running */
1068 			if ((zoneid = getzoneidbyname(pval)) == -1)
1069 				return (ipadm_errno2status(errno));
1070 		}
1071 	} else {
1072 		return (IPADM_INVALID_ARG);
1073 	}
1074 
1075 	s = (af == AF_INET ? iph->iph_sock : iph->iph_sock6);
1076 	bzero(&lifr, sizeof (lifr));
1077 	i_ipadm_addrobj2lifname((ipadm_addrobj_t)arg, lifr.lifr_name,
1078 	    sizeof (lifr.lifr_name));
1079 	lifr.lifr_zoneid = zoneid;
1080 	if (ioctl(s, SIOCSLIFZONE, (caddr_t)&lifr) < 0)
1081 		return (ipadm_errno2status(errno));
1082 
1083 	return (IPADM_SUCCESS);
1084 }
1085 
1086 /*
1087  * Callback function that sets the property `reqhost' on the address
1088  * object in `arg' to the value in `pval'.
1089  */
1090 /* ARGSUSED */
1091 static ipadm_status_t
1092 i_ipadm_set_reqhost(ipadm_handle_t iph, const void *arg,
1093     ipadm_prop_desc_t *pdp, const void *pval, uint_t af, uint_t flags)
1094 {
1095 	ipadm_status_t		status;
1096 	ipadm_addrobj_t		ipaddr = (ipadm_addrobj_t)arg;
1097 
1098 	if (ipaddr->ipadm_atype != IPADM_ADDR_DHCP)
1099 		return (IPADM_NOTSUP);
1100 
1101 	/*
1102 	 * If requested to set reqhost just from active config but the
1103 	 * address is not in active config, return error.
1104 	 */
1105 	if (!(ipaddr->ipadm_flags & IPMGMT_ACTIVE) &&
1106 	    (flags & IPADM_OPT_ACTIVE) && !(flags & IPADM_OPT_PERSIST)) {
1107 		return (IPADM_NOTFOUND);
1108 	}
1109 
1110 	status = ipadm_set_reqhost(ipaddr, pval);
1111 	if (status != IPADM_SUCCESS)
1112 		return (status);
1113 
1114 	if (ipaddr->ipadm_flags & IPMGMT_ACTIVE) {
1115 		status = i_ipadm_refresh_dhcp(ipaddr);
1116 
1117 		/*
1118 		 * We do not report a problem for IPADM_DHCP_IPC_TIMEOUT since
1119 		 * it is only a soft error to indicate the caller that the
1120 		 * lease might be renewed after the function returns.
1121 		 */
1122 		if (status != IPADM_SUCCESS && status != IPADM_DHCP_IPC_TIMEOUT)
1123 			return (status);
1124 	}
1125 
1126 	status = i_ipadm_set_aobj_addrprop(iph, ipaddr, flags,
1127 	    IPADM_NVP_REQHOST);
1128 	return (status);
1129 }
1130 
1131 /*
1132  * Used by address object property callback functions that need to do a
1133  * two-stage update because the addrprop is cached on the address object.
1134  */
1135 static ipadm_status_t
1136 i_ipadm_set_aobj_addrprop(ipadm_handle_t iph, ipadm_addrobj_t ipaddr,
1137     uint_t flags, const char *propname)
1138 {
1139 	ipadm_status_t	status;
1140 	uint32_t	two_stage_flags;
1141 
1142 	/*
1143 	 * Send the updated address object information to ipmgmtd, since the
1144 	 * cached version of an addrprop resides on an aobjmap, but do
1145 	 * not change the ACTIVE/PERSIST state of the aobjmap. Instead, request
1146 	 * a two-stage, SET_PROPS update with ACTIVE/PERSIST as the first stage
1147 	 * per the existing aobjmap flags and a second stage encoded in
1148 	 * IPADM_OPT_PERSIST_PROPS.
1149 	 */
1150 	two_stage_flags = (flags | IPADM_OPT_SET_PROPS)
1151 	    & ~(IPADM_OPT_ACTIVE | IPADM_OPT_PERSIST);
1152 	if (ipaddr->ipadm_flags & IPMGMT_ACTIVE)
1153 		two_stage_flags |= IPADM_OPT_ACTIVE;
1154 	if (ipaddr->ipadm_flags & IPMGMT_PERSIST)
1155 		two_stage_flags |= IPADM_OPT_PERSIST;
1156 	if (flags & IPADM_OPT_PERSIST)
1157 		two_stage_flags |= IPADM_OPT_PERSIST_PROPS;
1158 
1159 	status = i_ipadm_addr_persist(iph, ipaddr, B_FALSE, two_stage_flags,
1160 	    propname);
1161 	return (status);
1162 }
1163 
1164 /*
1165  * Callback function that gets the property `broadcast' for the address
1166  * object in `arg'.
1167  */
1168 /* ARGSUSED */
1169 static ipadm_status_t
1170 i_ipadm_get_broadcast(ipadm_handle_t iph, const void *arg,
1171     ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t af,
1172     uint_t valtype)
1173 {
1174 	struct sockaddr_in	*sin;
1175 	struct lifreq		lifr;
1176 	char			lifname[LIFNAMSIZ];
1177 	ipadm_addrobj_t		ipaddr = (ipadm_addrobj_t)arg;
1178 	ipadm_status_t		status;
1179 	size_t			nbytes = 0;
1180 	uint64_t		ifflags = 0;
1181 
1182 	i_ipadm_addrobj2lifname(ipaddr, lifname, sizeof (lifname));
1183 	if (ipaddr->ipadm_flags & IPMGMT_ACTIVE) {
1184 		status = i_ipadm_get_flags(iph, lifname, af, &ifflags);
1185 		if (status != IPADM_SUCCESS)
1186 			return (status);
1187 		if (!(ifflags & IFF_BROADCAST)) {
1188 			buf[0] = '\0';
1189 			return (IPADM_SUCCESS);
1190 		}
1191 	}
1192 
1193 	switch (valtype) {
1194 	case MOD_PROP_DEFAULT: {
1195 		struct sockaddr_storage	mask;
1196 		struct in_addr		broadaddr;
1197 		uint_t			plen;
1198 		in_addr_t		addr, maddr;
1199 		char			val[MAXPROPVALLEN];
1200 		uint_t			valsz = MAXPROPVALLEN;
1201 		ipadm_status_t		status;
1202 		int			err;
1203 		struct sockaddr_in	*sin;
1204 
1205 		if (!(ipaddr->ipadm_flags & IPMGMT_ACTIVE)) {
1206 			/*
1207 			 * Since the address is unknown we cannot
1208 			 * obtain default prefixlen
1209 			 */
1210 			if (ipaddr->ipadm_atype == IPADM_ADDR_DHCP ||
1211 			    ipaddr->ipadm_af == AF_INET6) {
1212 				buf[0] = '\0';
1213 				return (IPADM_SUCCESS);
1214 			}
1215 			/*
1216 			 * For the static address, we get the address from the
1217 			 * persistent db.
1218 			 */
1219 			status = i_ipadm_get_static_addr_db(iph, ipaddr);
1220 			if (status != IPADM_SUCCESS)
1221 				return (status);
1222 			sin = SIN(&ipaddr->ipadm_static_addr);
1223 			addr = sin->sin_addr.s_addr;
1224 		} else {
1225 			/*
1226 			 * If the address object is active, we retrieve the
1227 			 * address from kernel.
1228 			 */
1229 			bzero(&lifr, sizeof (lifr));
1230 			(void) strlcpy(lifr.lifr_name, lifname,
1231 			    sizeof (lifr.lifr_name));
1232 			if (ioctl(iph->iph_sock, SIOCGLIFADDR,
1233 			    (caddr_t)&lifr) < 0)
1234 				return (ipadm_errno2status(errno));
1235 
1236 			addr = (SIN(&lifr.lifr_addr))->sin_addr.s_addr;
1237 		}
1238 		/*
1239 		 * For default broadcast address, get the address and the
1240 		 * default prefixlen for that address and then compute the
1241 		 * broadcast address.
1242 		 */
1243 		status = i_ipadm_get_prefixlen(iph, arg, NULL, val, &valsz, af,
1244 		    MOD_PROP_DEFAULT);
1245 		if (status != IPADM_SUCCESS)
1246 			return (status);
1247 
1248 		plen = atoi(val);
1249 		if ((err = plen2mask(plen, AF_INET,
1250 		    (struct sockaddr *)&mask)) != 0)
1251 			return (ipadm_errno2status(err));
1252 		maddr = (SIN(&mask))->sin_addr.s_addr;
1253 		broadaddr.s_addr = (addr & maddr) | ~maddr;
1254 		nbytes = snprintf(buf, *bufsize, "%s", inet_ntoa(broadaddr));
1255 		break;
1256 	}
1257 	case MOD_PROP_ACTIVE:
1258 		bzero(&lifr, sizeof (lifr));
1259 		(void) strlcpy(lifr.lifr_name, lifname,
1260 		    sizeof (lifr.lifr_name));
1261 		if (ioctl(iph->iph_sock, SIOCGLIFBRDADDR,
1262 		    (caddr_t)&lifr) < 0) {
1263 			return (ipadm_errno2status(errno));
1264 		} else {
1265 			sin = SIN(&lifr.lifr_addr);
1266 			nbytes = snprintf(buf, *bufsize, "%s",
1267 			    inet_ntoa(sin->sin_addr));
1268 		}
1269 		break;
1270 	default:
1271 		return (IPADM_INVALID_ARG);
1272 	}
1273 	if (nbytes >= *bufsize) {
1274 		/* insufficient buffer space */
1275 		*bufsize = nbytes + 1;
1276 		return (IPADM_NO_BUFS);
1277 	}
1278 	return (IPADM_SUCCESS);
1279 }
1280 
1281 /*
1282  * Callback function that retrieves the value of the property `prefixlen'
1283  * for the address object in `arg'.
1284  */
1285 /* ARGSUSED */
1286 static ipadm_status_t
1287 i_ipadm_get_prefixlen(ipadm_handle_t iph, const void *arg,
1288     ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t af,
1289     uint_t valtype)
1290 {
1291 	struct lifreq	lifr;
1292 	ipadm_addrobj_t	ipaddr = (ipadm_addrobj_t)arg;
1293 	char		lifname[LIFNAMSIZ];
1294 	int		s;
1295 	uint32_t	prefixlen;
1296 	size_t		nbytes;
1297 	ipadm_status_t	status;
1298 	uint64_t	lifflags;
1299 
1300 	i_ipadm_addrobj2lifname(ipaddr, lifname, sizeof (lifname));
1301 	if (ipaddr->ipadm_flags & IPMGMT_ACTIVE) {
1302 		status = i_ipadm_get_flags(iph, lifname, af, &lifflags);
1303 		if (status != IPADM_SUCCESS) {
1304 			return (status);
1305 		} else if (lifflags & IFF_POINTOPOINT) {
1306 			buf[0] = '\0';
1307 			return (status);
1308 		}
1309 	}
1310 
1311 	s = (af == AF_INET ? iph->iph_sock : iph->iph_sock6);
1312 	bzero(&lifr, sizeof (lifr));
1313 	(void) strlcpy(lifr.lifr_name, lifname, sizeof (lifr.lifr_name));
1314 	switch (valtype) {
1315 	case MOD_PROP_POSSIBLE:
1316 		if (af == AF_INET)
1317 			nbytes = snprintf(buf, *bufsize, "1-30,32");
1318 		else
1319 			nbytes = snprintf(buf, *bufsize, "1-126,128");
1320 		break;
1321 	case MOD_PROP_DEFAULT:
1322 		if (ipaddr->ipadm_flags & IPMGMT_ACTIVE) {
1323 			/*
1324 			 * For static addresses, we retrieve the address
1325 			 * from kernel if it is active.
1326 			 */
1327 			if (ioctl(s, SIOCGLIFADDR, (caddr_t)&lifr) < 0)
1328 				return (ipadm_errno2status(errno));
1329 			status = i_ipadm_get_default_prefixlen(
1330 			    &lifr.lifr_addr, &prefixlen);
1331 			if (status != IPADM_SUCCESS)
1332 				return (status);
1333 		} else if ((ipaddr->ipadm_flags & IPMGMT_PERSIST) &&
1334 		    ipaddr->ipadm_atype == IPADM_ADDR_DHCP) {
1335 			/*
1336 			 * Since the address is unknown we cannot
1337 			 * obtain default prefixlen
1338 			 */
1339 			buf[0] = '\0';
1340 			return (IPADM_SUCCESS);
1341 		} else {
1342 			/*
1343 			 * If not in active config, we use the address
1344 			 * from persistent store.
1345 			 */
1346 			status = i_ipadm_get_static_addr_db(iph, ipaddr);
1347 			if (status != IPADM_SUCCESS)
1348 				return (status);
1349 			status = i_ipadm_get_default_prefixlen(
1350 			    &ipaddr->ipadm_static_addr, &prefixlen);
1351 			if (status != IPADM_SUCCESS)
1352 				return (status);
1353 		}
1354 		nbytes = snprintf(buf, *bufsize, "%u", prefixlen);
1355 		break;
1356 	case MOD_PROP_ACTIVE:
1357 		if (ioctl(s, SIOCGLIFNETMASK, (caddr_t)&lifr) < 0)
1358 			return (ipadm_errno2status(errno));
1359 		prefixlen = lifr.lifr_addrlen;
1360 		nbytes = snprintf(buf, *bufsize, "%u", prefixlen);
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 	return (IPADM_SUCCESS);
1371 }
1372 
1373 /*
1374  * Callback function that retrieves the value of one of the properties
1375  * among `deprecated', `private', and `transmit' for the address object
1376  * in `arg'.
1377  */
1378 /* ARGSUSED */
1379 static ipadm_status_t
1380 i_ipadm_get_addr_flag(ipadm_handle_t iph, const void *arg,
1381     ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t af,
1382     uint_t valtype)
1383 {
1384 	boolean_t	on = B_FALSE;
1385 	char		lifname[LIFNAMSIZ];
1386 	ipadm_status_t	status = IPADM_SUCCESS;
1387 	uint64_t	ifflags;
1388 	size_t		nbytes;
1389 	ipadm_addrobj_t	ipaddr = (ipadm_addrobj_t)arg;
1390 
1391 	switch (valtype) {
1392 	case MOD_PROP_DEFAULT:
1393 		if (strcmp(pdp->ipd_name, "private") == 0 ||
1394 		    strcmp(pdp->ipd_name, "deprecated") == 0) {
1395 			on = B_FALSE;
1396 		} else if (strcmp(pdp->ipd_name, "transmit") == 0) {
1397 			on = B_TRUE;
1398 		} else {
1399 			return (IPADM_PROP_UNKNOWN);
1400 		}
1401 		break;
1402 	case MOD_PROP_ACTIVE:
1403 		/*
1404 		 * If the address is present in active configuration, we
1405 		 * retrieve it from kernel to get the property value.
1406 		 * Else, there is no value to return.
1407 		 */
1408 		i_ipadm_addrobj2lifname(ipaddr, lifname, sizeof (lifname));
1409 		status = i_ipadm_get_flags(iph, lifname, af, &ifflags);
1410 		if (status != IPADM_SUCCESS)
1411 			return (status);
1412 		if (strcmp(pdp->ipd_name, "private") == 0)
1413 			on = (ifflags & IFF_PRIVATE);
1414 		else if (strcmp(pdp->ipd_name, "transmit") == 0)
1415 			on = !(ifflags & IFF_NOXMIT);
1416 		else if (strcmp(pdp->ipd_name, "deprecated") == 0)
1417 			on = (ifflags & IFF_DEPRECATED);
1418 		break;
1419 	default:
1420 		return (IPADM_INVALID_ARG);
1421 	}
1422 	nbytes = snprintf(buf, *bufsize, "%s",
1423 	    (on ? IPADM_ONSTR : IPADM_OFFSTR));
1424 	if (nbytes >= *bufsize) {
1425 		/* insufficient buffer space */
1426 		*bufsize = nbytes + 1;
1427 		status = IPADM_NO_BUFS;
1428 	}
1429 
1430 	return (status);
1431 }
1432 
1433 /*
1434  * Callback function that retrieves the value of the property `zone'
1435  * for the address object in `arg'.
1436  */
1437 /* ARGSUSED */
1438 static ipadm_status_t
1439 i_ipadm_get_zone(ipadm_handle_t iph, const void *arg,
1440     ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t af,
1441     uint_t valtype)
1442 {
1443 	struct lifreq	lifr;
1444 	char		zone_name[ZONENAME_MAX];
1445 	int		s;
1446 	size_t		nbytes = 0;
1447 
1448 	if (iph->iph_zoneid != GLOBAL_ZONEID) {
1449 		buf[0] = '\0';
1450 		return (IPADM_SUCCESS);
1451 	}
1452 
1453 	/*
1454 	 * we are in global zone. See if the lifname is assigned to shared-ip
1455 	 * zone or global zone.
1456 	 */
1457 	switch (valtype) {
1458 	case MOD_PROP_DEFAULT:
1459 		if (getzonenamebyid(GLOBAL_ZONEID, zone_name,
1460 		    sizeof (zone_name)) > 0)
1461 			nbytes = snprintf(buf, *bufsize, "%s", zone_name);
1462 		else
1463 			return (ipadm_errno2status(errno));
1464 		break;
1465 	case MOD_PROP_ACTIVE:
1466 		bzero(&lifr, sizeof (lifr));
1467 		i_ipadm_addrobj2lifname((ipadm_addrobj_t)arg, lifr.lifr_name,
1468 		    sizeof (lifr.lifr_name));
1469 		s = (af == AF_INET ? iph->iph_sock : iph->iph_sock6);
1470 
1471 		if (ioctl(s, SIOCGLIFZONE, (caddr_t)&lifr) == -1)
1472 			return (ipadm_errno2status(errno));
1473 
1474 		if (lifr.lifr_zoneid == ALL_ZONES) {
1475 			nbytes = snprintf(buf, *bufsize, "%s", "all-zones");
1476 		} else if (getzonenamebyid(lifr.lifr_zoneid, zone_name,
1477 		    sizeof (zone_name)) < 0) {
1478 			return (ipadm_errno2status(errno));
1479 		} else {
1480 			nbytes = snprintf(buf, *bufsize, "%s", zone_name);
1481 		}
1482 		break;
1483 	default:
1484 		return (IPADM_INVALID_ARG);
1485 	}
1486 	if (nbytes >= *bufsize) {
1487 		/* insufficient buffer space */
1488 		*bufsize = nbytes + 1;
1489 		return (IPADM_NO_BUFS);
1490 	}
1491 
1492 	return (IPADM_SUCCESS);
1493 }
1494 
1495 /*
1496  * Callback function that retrieves the value of the property `primary'
1497  * for the address object in `arg'.
1498  */
1499 /* ARGSUSED */
1500 static ipadm_status_t
1501 i_ipadm_get_primary(ipadm_handle_t iph, const void *arg,
1502     ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t af,
1503     uint_t valtype)
1504 {
1505 	ipadm_addrobj_t	ipaddr = (ipadm_addrobj_t)arg;
1506 	const char		*onoff = "";
1507 	size_t			nbytes;
1508 
1509 	switch (valtype) {
1510 	case MOD_PROP_DEFAULT:
1511 		if (ipaddr->ipadm_atype == IPADM_ADDR_DHCP)
1512 			onoff = IPADM_OFFSTR;
1513 		break;
1514 	case MOD_PROP_ACTIVE:
1515 		if (ipaddr->ipadm_atype == IPADM_ADDR_DHCP) {
1516 			dhcp_status_t	dhcp_status;
1517 			ipadm_status_t	ipc_status;
1518 			int			error;
1519 
1520 			ipc_status = i_ipadm_dhcp_status(ipaddr, &dhcp_status,
1521 			    &error);
1522 			if (ipc_status != IPADM_SUCCESS &&
1523 			    ipc_status != IPADM_NOTFOUND)
1524 				return (ipc_status);
1525 
1526 			onoff = dhcp_status.if_dflags & DHCP_IF_PRIMARY ?
1527 			    IPADM_ONSTR : IPADM_OFFSTR;
1528 		}
1529 		break;
1530 	default:
1531 		return (IPADM_INVALID_ARG);
1532 	}
1533 
1534 	nbytes = strlcpy(buf, onoff, *bufsize);
1535 	if (nbytes >= *bufsize) {
1536 		/* insufficient buffer space */
1537 		*bufsize = nbytes + 1;
1538 		return (IPADM_NO_BUFS);
1539 	}
1540 
1541 	return (IPADM_SUCCESS);
1542 }
1543 
1544 /*
1545  * Callback function that retrieves the value of the property `reqhost'
1546  * for the address object in `arg'.
1547  */
1548 /* ARGSUSED */
1549 static ipadm_status_t
1550 i_ipadm_get_reqhost(ipadm_handle_t iph, const void *arg,
1551     ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t af,
1552     uint_t valtype)
1553 {
1554 	ipadm_addrobj_t	ipaddr = (ipadm_addrobj_t)arg;
1555 	const char	*reqhost = "";
1556 	size_t		nbytes;
1557 
1558 	switch (valtype) {
1559 	case MOD_PROP_DEFAULT:
1560 		break;
1561 	case MOD_PROP_ACTIVE:
1562 		if (ipaddr->ipadm_atype == IPADM_ADDR_DHCP)
1563 			reqhost = ipaddr->ipadm_reqhost;
1564 		break;
1565 	default:
1566 		return (IPADM_INVALID_ARG);
1567 	}
1568 
1569 	nbytes = strlcpy(buf, reqhost, *bufsize);
1570 	if (nbytes >= *bufsize) {
1571 		/* insufficient buffer space */
1572 		*bufsize = nbytes + 1;
1573 		return (IPADM_NO_BUFS);
1574 	}
1575 
1576 	return (IPADM_SUCCESS);
1577 }
1578 
1579 static ipadm_prop_desc_t *
1580 i_ipadm_get_addrprop_desc(const char *pname)
1581 {
1582 	int i;
1583 
1584 	for (i = 0; ipadm_addrprop_table[i].ipd_name != NULL; i++) {
1585 		if (strcmp(pname, ipadm_addrprop_table[i].ipd_name) == 0 ||
1586 		    (ipadm_addrprop_table[i].ipd_old_name != NULL &&
1587 		    strcmp(pname, ipadm_addrprop_table[i].ipd_old_name) == 0))
1588 			return (&ipadm_addrprop_table[i]);
1589 	}
1590 	return (NULL);
1591 }
1592 
1593 /*
1594  * Gets the value of the given address property `pname' for the address
1595  * object with name `aobjname'.
1596  */
1597 ipadm_status_t
1598 ipadm_get_addrprop(ipadm_handle_t iph, const char *pname, char *buf,
1599     uint_t *bufsize, const char *aobjname, uint_t valtype)
1600 {
1601 	struct ipadm_addrobj_s	ipaddr;
1602 	ipadm_status_t		status = IPADM_SUCCESS;
1603 	sa_family_t		af;
1604 	ipadm_prop_desc_t	*pdp = NULL;
1605 
1606 	if (iph == NULL || pname == NULL || buf == NULL ||
1607 	    bufsize == NULL || *bufsize == 0 || aobjname == NULL) {
1608 		return (IPADM_INVALID_ARG);
1609 	}
1610 
1611 	/* find the property in the property description table */
1612 	if ((pdp = i_ipadm_get_addrprop_desc(pname)) == NULL)
1613 		return (IPADM_PROP_UNKNOWN);
1614 
1615 	/*
1616 	 * For the given aobjname, get the addrobj it represents and
1617 	 * retrieve the property value for that object.
1618 	 */
1619 	i_ipadm_init_addr(&ipaddr, "", aobjname, IPADM_ADDR_NONE);
1620 	if ((status = i_ipadm_get_addrobj(iph, &ipaddr)) != IPADM_SUCCESS)
1621 		return (status);
1622 
1623 	if (ipaddr.ipadm_atype == IPADM_ADDR_IPV6_ADDRCONF)
1624 		return (IPADM_NOTSUP);
1625 	af = ipaddr.ipadm_af;
1626 
1627 	/*
1628 	 * Call the appropriate callback function to based on the field
1629 	 * that was asked for.
1630 	 */
1631 	switch (valtype) {
1632 	case IPADM_OPT_PERM:
1633 		status = i_ipadm_pd2permstr(pdp, buf, bufsize);
1634 		break;
1635 	case IPADM_OPT_ACTIVE:
1636 		if (!(ipaddr.ipadm_flags & IPMGMT_ACTIVE)) {
1637 			buf[0] = '\0';
1638 		} else {
1639 			status = pdp->ipd_get(iph, &ipaddr, pdp, buf, bufsize,
1640 			    af, MOD_PROP_ACTIVE);
1641 		}
1642 		break;
1643 	case IPADM_OPT_DEFAULT:
1644 		status = pdp->ipd_get(iph, &ipaddr, pdp, buf, bufsize,
1645 		    af, MOD_PROP_DEFAULT);
1646 		break;
1647 	case IPADM_OPT_POSSIBLE:
1648 		if (pdp->ipd_get_range != NULL) {
1649 			status = pdp->ipd_get_range(iph, &ipaddr, pdp, buf,
1650 			    bufsize, af, MOD_PROP_POSSIBLE);
1651 			break;
1652 		}
1653 		buf[0] = '\0';
1654 		break;
1655 	case IPADM_OPT_PERSIST:
1656 		status = i_ipadm_get_persist_propval(iph, pdp, buf, bufsize,
1657 		    &ipaddr);
1658 		break;
1659 	default:
1660 		status = IPADM_INVALID_ARG;
1661 		break;
1662 	}
1663 
1664 	return (status);
1665 }
1666 
1667 /*
1668  * Sets the value of the given address property `pname' to `pval' for the
1669  * address object with name `aobjname'.
1670  */
1671 ipadm_status_t
1672 ipadm_set_addrprop(ipadm_handle_t iph, const char *pname,
1673     const char *pval, const char *aobjname, uint_t pflags)
1674 {
1675 	struct ipadm_addrobj_s	ipaddr;
1676 	sa_family_t		af;
1677 	ipadm_prop_desc_t	*pdp = NULL;
1678 	char			defbuf[MAXPROPVALLEN];
1679 	uint_t			defbufsize = MAXPROPVALLEN;
1680 	boolean_t		reset = (pflags & IPADM_OPT_DEFAULT);
1681 	ipadm_status_t		status = IPADM_SUCCESS;
1682 
1683 	/* Check for solaris.network.interface.config authorization */
1684 	if (!ipadm_check_auth())
1685 		return (IPADM_EAUTH);
1686 
1687 	if (iph == NULL || pname == NULL || aobjname == NULL || pflags == 0 ||
1688 	    pflags == IPADM_OPT_PERSIST ||
1689 	    (pflags & ~(IPADM_COMMON_OPT_MASK|IPADM_OPT_DEFAULT)) ||
1690 	    (!reset && pval == NULL)) {
1691 		return (IPADM_INVALID_ARG);
1692 	}
1693 
1694 	/* find the property in the property description table */
1695 	if ((pdp = i_ipadm_get_addrprop_desc(pname)) == NULL)
1696 		return (IPADM_PROP_UNKNOWN);
1697 
1698 	if (pdp->ipd_set == NULL || (reset && pdp->ipd_get == NULL))
1699 		return (IPADM_NOTSUP);
1700 
1701 	if (!(pdp->ipd_flags & IPADMPROP_MULVAL) &&
1702 	    (pflags & (IPADM_OPT_APPEND|IPADM_OPT_REMOVE))) {
1703 		return (IPADM_INVALID_ARG);
1704 	}
1705 
1706 	/*
1707 	 * For the given aobjname, get the addrobj it represents and
1708 	 * set the property value for that object.
1709 	 */
1710 	i_ipadm_init_addr(&ipaddr, "", aobjname, IPADM_ADDR_NONE);
1711 	if ((status = i_ipadm_get_addrobj(iph, &ipaddr)) != IPADM_SUCCESS)
1712 		return (status);
1713 
1714 	if (!(ipaddr.ipadm_flags & IPMGMT_ACTIVE))
1715 		return (IPADM_OP_DISABLE_OBJ);
1716 
1717 	/* Persistent operation not allowed on a temporary object. */
1718 	if ((pflags & IPADM_OPT_PERSIST) &&
1719 	    !(ipaddr.ipadm_flags & IPMGMT_PERSIST))
1720 		return (IPADM_TEMPORARY_OBJ);
1721 	/*
1722 	 * Currently, setting an address property on an address object of type
1723 	 * IPADM_ADDR_IPV6_ADDRCONF is not supported. Supporting it involves
1724 	 * in.ndpd retrieving the address properties from ipmgmtd for given
1725 	 * address object and then setting them on auto-configured addresses,
1726 	 * whenever in.ndpd gets a new prefix. This will be supported in
1727 	 * future releases.
1728 	 */
1729 	if (ipaddr.ipadm_atype == IPADM_ADDR_IPV6_ADDRCONF)
1730 		return (IPADM_NOTSUP);
1731 
1732 	/*
1733 	 * Setting an address property on an address object that is
1734 	 * not present in active configuration is not supported.
1735 	 */
1736 	if (!(ipaddr.ipadm_flags & IPMGMT_ACTIVE))
1737 		return (IPADM_NOTSUP);
1738 
1739 	af = ipaddr.ipadm_af;
1740 	if (reset) {
1741 		/*
1742 		 * If we were asked to reset the value, we need to fetch
1743 		 * the default value and set the default value.
1744 		 */
1745 		status = pdp->ipd_get(iph, &ipaddr, pdp, defbuf, &defbufsize,
1746 		    af, MOD_PROP_DEFAULT);
1747 		if (status != IPADM_SUCCESS)
1748 			return (status);
1749 		pval = defbuf;
1750 	}
1751 	/* set the user provided or default property value */
1752 	status = pdp->ipd_set(iph, &ipaddr, pdp, pval, af, pflags);
1753 	if (status != IPADM_SUCCESS)
1754 		return (status);
1755 
1756 	/*
1757 	 * If IPADM_OPT_PERSIST was set in `flags', we need to store
1758 	 * property and its value in persistent DB.
1759 	 */
1760 	if (pflags & IPADM_OPT_PERSIST) {
1761 		status = i_ipadm_persist_propval(iph, pdp, pval, &ipaddr,
1762 		    pflags);
1763 	}
1764 
1765 	return (status);
1766 }
1767 
1768 /*
1769  * Remove the address specified by the address object in `addr'
1770  * from kernel. If the address is on a non-zero logical interface, we do a
1771  * SIOCLIFREMOVEIF, otherwise we set the address to INADDR_ANY for IPv4 or
1772  * :: for IPv6.
1773  */
1774 ipadm_status_t
1775 i_ipadm_delete_addr(ipadm_handle_t iph, ipadm_addrobj_t addr)
1776 {
1777 	struct lifreq	lifr;
1778 	int		sock;
1779 	ipadm_status_t	status;
1780 
1781 	bzero(&lifr, sizeof (lifr));
1782 	i_ipadm_addrobj2lifname(addr, lifr.lifr_name, sizeof (lifr.lifr_name));
1783 	sock = (addr->ipadm_af == AF_INET ? iph->iph_sock : iph->iph_sock6);
1784 	if (addr->ipadm_lifnum == 0) {
1785 		/*
1786 		 * Fake the deletion of the 0'th address by
1787 		 * clearing IFF_UP and setting it to as 0.0.0.0 or ::.
1788 		 */
1789 		status = i_ipadm_set_flags(iph, addr->ipadm_ifname,
1790 		    addr->ipadm_af, 0, IFF_UP);
1791 		if (status != IPADM_SUCCESS)
1792 			return (status);
1793 		bzero(&lifr.lifr_addr, sizeof (lifr.lifr_addr));
1794 		lifr.lifr_addr.ss_family = addr->ipadm_af;
1795 		if (ioctl(sock, SIOCSLIFADDR, (caddr_t)&lifr) < 0)
1796 			return (ipadm_errno2status(errno));
1797 		if (ioctl(sock, SIOCSLIFDSTADDR, (caddr_t)&lifr) < 0)
1798 			return (ipadm_errno2status(errno));
1799 	} else if (ioctl(sock, SIOCLIFREMOVEIF, (caddr_t)&lifr) < 0) {
1800 		return (ipadm_errno2status(errno));
1801 	}
1802 
1803 	return (IPADM_SUCCESS);
1804 }
1805 
1806 /*
1807  * Extracts the IPv6 address from the nvlist in `nvl'.
1808  */
1809 ipadm_status_t
1810 i_ipadm_nvl2in6_addr(nvlist_t *nvl, char *addr_type, in6_addr_t *in6_addr)
1811 {
1812 	uint8_t	*addr6;
1813 	uint_t	n;
1814 
1815 	if (nvlist_lookup_uint8_array(nvl, addr_type, &addr6, &n) != 0)
1816 		return (IPADM_NOTFOUND);
1817 	assert(n == 16);
1818 	bcopy(addr6, in6_addr->s6_addr, n);
1819 	return (IPADM_SUCCESS);
1820 }
1821 
1822 /*
1823  * Used to validate the given addrobj name string. Length of `aobjname'
1824  * cannot exceed IPADM_AOBJ_USTRSIZ. `aobjname' should start with an
1825  * alphabetic character and it can only contain alphanumeric characters.
1826  */
1827 static boolean_t
1828 i_ipadm_is_user_aobjname_valid(const char *aobjname)
1829 {
1830 	const char	*cp;
1831 
1832 	if (aobjname == NULL || strlen(aobjname) >= IPADM_AOBJ_USTRSIZ ||
1833 	    !isalpha(*aobjname)) {
1834 		return (B_FALSE);
1835 	}
1836 	for (cp = aobjname + 1; *cp && isalnum(*cp); cp++)
1837 		;
1838 	return (*cp == '\0');
1839 }
1840 
1841 /*
1842  * Computes the prefixlen for the given `addr' based on the netmask found using
1843  * the order specified in /etc/nsswitch.conf. If not found, then the
1844  * prefixlen is computed using the Classful subnetting semantics defined
1845  * in RFC 791 for IPv4 and RFC 4291 for IPv6.
1846  */
1847 static ipadm_status_t
1848 i_ipadm_get_default_prefixlen(struct sockaddr_storage *addr, uint32_t *plen)
1849 {
1850 	sa_family_t af = addr->ss_family;
1851 	struct sockaddr_storage mask;
1852 	struct sockaddr_in *m = (struct sockaddr_in *)&mask;
1853 	struct sockaddr_in6 *sin6;
1854 	struct sockaddr_in *sin;
1855 	struct in_addr ia;
1856 	uint32_t prefixlen = 0;
1857 
1858 	switch (af) {
1859 	case AF_INET:
1860 		sin = SIN(addr);
1861 		ia.s_addr = ntohl(sin->sin_addr.s_addr);
1862 		get_netmask4(&ia, &m->sin_addr);
1863 		m->sin_addr.s_addr = htonl(m->sin_addr.s_addr);
1864 		m->sin_family = AF_INET;
1865 		prefixlen = mask2plen((struct sockaddr *)&mask);
1866 		break;
1867 	case AF_INET6:
1868 		sin6 = SIN6(addr);
1869 		if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
1870 			prefixlen = 10;
1871 		else
1872 			prefixlen = 64;
1873 		break;
1874 	default:
1875 		return (IPADM_INVALID_ARG);
1876 	}
1877 	*plen = prefixlen;
1878 	return (IPADM_SUCCESS);
1879 }
1880 
1881 ipadm_status_t
1882 i_ipadm_resolve_addr(const char *name, sa_family_t af,
1883     struct sockaddr_storage *ss)
1884 {
1885 	struct addrinfo hints, *ai;
1886 	int rc;
1887 	struct sockaddr_in6 *sin6;
1888 	struct sockaddr_in *sin;
1889 	boolean_t is_mapped;
1890 
1891 	(void) memset(&hints, 0, sizeof (hints));
1892 	hints.ai_family = af;
1893 	hints.ai_flags = (AI_ALL | AI_V4MAPPED);
1894 	rc = getaddrinfo(name, NULL, &hints, &ai);
1895 	if (rc != 0) {
1896 		if (rc == EAI_NONAME)
1897 			return (IPADM_BAD_ADDR);
1898 		else
1899 			return (IPADM_FAILURE);
1900 	}
1901 	if (ai->ai_next != NULL) {
1902 		/* maps to more than one hostname */
1903 		freeaddrinfo(ai);
1904 		return (IPADM_BAD_HOSTNAME);
1905 	}
1906 	/* LINTED E_BAD_PTR_CAST_ALIGN */
1907 	is_mapped = IN6_IS_ADDR_V4MAPPED(&(SIN6(ai->ai_addr))->sin6_addr);
1908 	if (is_mapped) {
1909 		sin = SIN(ss);
1910 		sin->sin_family = AF_INET;
1911 		/* LINTED E_BAD_PTR_CAST_ALIGN */
1912 		IN6_V4MAPPED_TO_INADDR(&(SIN6(ai->ai_addr))->sin6_addr,
1913 		    &sin->sin_addr);
1914 	} else {
1915 		sin6 = SIN6(ss);
1916 		sin6->sin6_family = AF_INET6;
1917 		bcopy(ai->ai_addr, sin6, sizeof (*sin6));
1918 	}
1919 	freeaddrinfo(ai);
1920 	return (IPADM_SUCCESS);
1921 }
1922 
1923 /*
1924  * This takes a static address string <addr>[/<mask>] or a hostname
1925  * and maps it to a single numeric IP address, consulting DNS if
1926  * hostname was provided. If a specific address family was requested,
1927  * an error is returned if the given hostname does not map to an address
1928  * of the given family. Note that this function returns failure
1929  * if the name maps to more than one IP address.
1930  */
1931 ipadm_status_t
1932 ipadm_set_addr(ipadm_addrobj_t ipaddr, const char *astr, sa_family_t af)
1933 {
1934 	char		*prefixlenstr;
1935 	uint32_t	prefixlen = 0;
1936 	char		*endp;
1937 	/*
1938 	 * We use (NI_MAXHOST + 5) because the longest possible
1939 	 * astr will have (NI_MAXHOST + '/' + {a maximum of 32 for IPv4
1940 	 * or a maximum of 128 for IPv6 + '\0') chars
1941 	 */
1942 	char		addrstr[NI_MAXHOST + 5];
1943 	ipadm_status_t	status;
1944 
1945 	(void) snprintf(addrstr, sizeof (addrstr), "%s", astr);
1946 	if ((prefixlenstr = strchr(addrstr, '/')) != NULL) {
1947 		*prefixlenstr++ = '\0';
1948 		errno = 0;
1949 		prefixlen = strtoul(prefixlenstr, &endp, 10);
1950 		if (errno != 0 || *endp != '\0')
1951 			return (IPADM_INVALID_ARG);
1952 		if ((af == AF_INET && prefixlen > IP_ABITS) ||
1953 		    (af == AF_INET6 && prefixlen > IPV6_ABITS))
1954 			return (IPADM_INVALID_ARG);
1955 	}
1956 
1957 	status = i_ipadm_resolve_addr(addrstr, af, &ipaddr->ipadm_static_addr);
1958 	if (status == IPADM_SUCCESS) {
1959 		(void) strlcpy(ipaddr->ipadm_static_aname, addrstr,
1960 		    sizeof (ipaddr->ipadm_static_aname));
1961 		ipaddr->ipadm_af = ipaddr->ipadm_static_addr.ss_family;
1962 		ipaddr->ipadm_static_prefixlen = prefixlen;
1963 	}
1964 	return (status);
1965 }
1966 
1967 /*
1968  * Gets the static source address from the address object in `ipaddr'.
1969  * Memory for `addr' should be already allocated by the caller.
1970  */
1971 ipadm_status_t
1972 ipadm_get_addr(const ipadm_addrobj_t ipaddr, struct sockaddr_storage *addr)
1973 {
1974 	if (ipaddr == NULL || ipaddr->ipadm_atype != IPADM_ADDR_STATIC ||
1975 	    addr == NULL) {
1976 		return (IPADM_INVALID_ARG);
1977 	}
1978 	*addr = ipaddr->ipadm_static_addr;
1979 
1980 	return (IPADM_SUCCESS);
1981 }
1982 
1983 /*
1984  * Set up tunnel destination address in ipaddr by contacting DNS.
1985  * The function works similar to ipadm_set_addr().
1986  * The dst_addr must resolve to exactly one address. IPADM_BAD_ADDR is returned
1987  * if dst_addr resolves to more than one address. The caller has to verify
1988  * that ipadm_static_addr and ipadm_static_dst_addr have the same ss_family
1989  */
1990 ipadm_status_t
1991 ipadm_set_dst_addr(ipadm_addrobj_t ipaddr, const char *daddrstr, sa_family_t af)
1992 {
1993 	ipadm_status_t	status;
1994 
1995 	/* mask lengths are not meaningful for point-to-point interfaces. */
1996 	if (strchr(daddrstr, '/') != NULL)
1997 		return (IPADM_BAD_ADDR);
1998 
1999 	status = i_ipadm_resolve_addr(daddrstr, af,
2000 	    &ipaddr->ipadm_static_dst_addr);
2001 	if (status == IPADM_SUCCESS) {
2002 		(void) strlcpy(ipaddr->ipadm_static_dname, daddrstr,
2003 		    sizeof (ipaddr->ipadm_static_dname));
2004 	}
2005 	return (status);
2006 }
2007 
2008 /*
2009  * Sets the interface ID in the address object `ipaddr' with the address
2010  * in the string `interface_id'. This interface ID will be used when
2011  * ipadm_create_addr() is called with `ipaddr' with address type
2012  * set to IPADM_ADDR_IPV6_ADDRCONF.
2013  */
2014 ipadm_status_t
2015 ipadm_set_interface_id(ipadm_addrobj_t ipaddr, const char *interface_id)
2016 {
2017 	struct sockaddr_in6	*sin6;
2018 	char			*end;
2019 	char			*cp;
2020 	uint32_t		prefixlen;
2021 	char			addrstr[INET6_ADDRSTRLEN + 1];
2022 
2023 	if (ipaddr == NULL || interface_id == NULL ||
2024 	    ipaddr->ipadm_atype != IPADM_ADDR_IPV6_ADDRCONF)
2025 		return (IPADM_INVALID_ARG);
2026 
2027 	(void) strlcpy(addrstr, interface_id, sizeof (addrstr));
2028 	if ((cp = strchr(addrstr, '/')) == NULL)
2029 		return (IPADM_INVALID_ARG);
2030 	*cp++ = '\0';
2031 	sin6 = &ipaddr->ipadm_intfid;
2032 	if (inet_pton(AF_INET6, addrstr, &sin6->sin6_addr) == 1) {
2033 		errno = 0;
2034 		prefixlen = strtoul(cp, &end, 10);
2035 		if (errno != 0 || *end != '\0' || prefixlen > IPV6_ABITS)
2036 			return (IPADM_INVALID_ARG);
2037 		sin6->sin6_family = AF_INET6;
2038 		ipaddr->ipadm_intfidlen = prefixlen;
2039 		return (IPADM_SUCCESS);
2040 	}
2041 	return (IPADM_INVALID_ARG);
2042 }
2043 
2044 /*
2045  * Sets the value for the field `ipadm_stateless' in address object `ipaddr'.
2046  */
2047 ipadm_status_t
2048 ipadm_set_stateless(ipadm_addrobj_t ipaddr, boolean_t stateless)
2049 {
2050 	if (ipaddr == NULL ||
2051 	    ipaddr->ipadm_atype != IPADM_ADDR_IPV6_ADDRCONF)
2052 		return (IPADM_INVALID_ARG);
2053 	ipaddr->ipadm_stateless = stateless;
2054 
2055 	return (IPADM_SUCCESS);
2056 }
2057 
2058 /*
2059  * Sets the value for the field `ipadm_stateful' in address object `ipaddr'.
2060  */
2061 ipadm_status_t
2062 ipadm_set_stateful(ipadm_addrobj_t ipaddr, boolean_t stateful)
2063 {
2064 	if (ipaddr == NULL ||
2065 	    ipaddr->ipadm_atype != IPADM_ADDR_IPV6_ADDRCONF)
2066 		return (IPADM_INVALID_ARG);
2067 	ipaddr->ipadm_stateful = stateful;
2068 
2069 	return (IPADM_SUCCESS);
2070 }
2071 
2072 /*
2073  * Sets the dhcp parameter `ipadm_primary' in the address object `ipaddr'.
2074  * The field is used during the address creation with address
2075  * type IPADM_ADDR_DHCP. It specifies if the interface should be set
2076  * as a primary interface for getting dhcp global options from the DHCP server.
2077  */
2078 ipadm_status_t
2079 ipadm_set_primary(ipadm_addrobj_t ipaddr, boolean_t primary)
2080 {
2081 	if (ipaddr == NULL || ipaddr->ipadm_atype != IPADM_ADDR_DHCP)
2082 		return (IPADM_INVALID_ARG);
2083 	ipaddr->ipadm_primary = primary;
2084 
2085 	return (IPADM_SUCCESS);
2086 }
2087 
2088 /*
2089  * Sets the dhcp parameter `ipadm_wait' in the address object `ipaddr'.
2090  * This field is used during the address creation with address type
2091  * IPADM_ADDR_DHCP. It specifies how long the API ipadm_create_addr()
2092  * should wait before returning while the dhcp address is being acquired
2093  * by the dhcpagent.
2094  * Possible values:
2095  * - IPADM_DHCP_WAIT_FOREVER : Do not return until dhcpagent returns.
2096  * - IPADM_DHCP_WAIT_DEFAULT : Wait a default amount of time before returning.
2097  * - <integer>	   : Wait the specified number of seconds before returning.
2098  */
2099 ipadm_status_t
2100 ipadm_set_wait_time(ipadm_addrobj_t ipaddr, int32_t wait)
2101 {
2102 	if (ipaddr == NULL || ipaddr->ipadm_atype != IPADM_ADDR_DHCP)
2103 		return (IPADM_INVALID_ARG);
2104 	ipaddr->ipadm_wait = wait;
2105 	return (IPADM_SUCCESS);
2106 }
2107 
2108 /*
2109  * Sets the dhcp parameter `ipadm_reqhost' in the address object `ipaddr',
2110  * but validate any non-nil value using ipadm_is_valid_hostname() and also
2111  * check length.
2112  */
2113 ipadm_status_t
2114 ipadm_set_reqhost(ipadm_addrobj_t ipaddr, const char *reqhost)
2115 {
2116 	const size_t HNLEN = sizeof (ipaddr->ipadm_reqhost);
2117 
2118 	if (ipaddr == NULL || ipaddr->ipadm_atype != IPADM_ADDR_DHCP)
2119 		return (IPADM_INVALID_ARG);
2120 
2121 	if (ipadm_is_nil_hostname(reqhost))
2122 		*ipaddr->ipadm_reqhost = '\0';
2123 	else if (!ipadm_is_valid_hostname(reqhost))
2124 		return (IPADM_INVALID_ARG);
2125 	else if (strlcpy(ipaddr->ipadm_reqhost, reqhost, HNLEN) >= HNLEN)
2126 		return (IPADM_INVALID_ARG);
2127 	return (IPADM_SUCCESS);
2128 }
2129 
2130 /*
2131  * Creates a placeholder for the `ipadm_aobjname' in the ipmgmtd `aobjmap'.
2132  * If the `aobjname' already exists in the daemon's `aobjmap' then
2133  * IPADM_ADDROBJ_EXISTS will be returned.
2134  *
2135  * If the libipadm consumer set `ipaddr.ipadm_aobjname[0]' to `\0', then the
2136  * daemon will generate an `aobjname' for the given `ipaddr'.
2137  */
2138 ipadm_status_t
2139 i_ipadm_lookupadd_addrobj(ipadm_handle_t iph, ipadm_addrobj_t ipaddr)
2140 {
2141 	ipmgmt_aobjop_arg_t	larg;
2142 	ipmgmt_aobjop_rval_t	rval, *rvalp;
2143 	int			err;
2144 
2145 	bzero(&larg, sizeof (larg));
2146 	larg.ia_cmd = IPMGMT_CMD_ADDROBJ_LOOKUPADD;
2147 	(void) strlcpy(larg.ia_aobjname, ipaddr->ipadm_aobjname,
2148 	    sizeof (larg.ia_aobjname));
2149 	(void) strlcpy(larg.ia_ifname, ipaddr->ipadm_ifname,
2150 	    sizeof (larg.ia_ifname));
2151 	larg.ia_family = ipaddr->ipadm_af;
2152 	larg.ia_atype = ipaddr->ipadm_atype;
2153 
2154 	rvalp = &rval;
2155 	err = ipadm_door_call(iph, &larg, sizeof (larg), (void **)&rvalp,
2156 	    sizeof (rval), B_FALSE);
2157 	if (err == 0 && ipaddr->ipadm_aobjname[0] == '\0') {
2158 		/* copy the daemon generated `aobjname' into `ipadddr' */
2159 		(void) strlcpy(ipaddr->ipadm_aobjname, rval.ir_aobjname,
2160 		    sizeof (ipaddr->ipadm_aobjname));
2161 	}
2162 	if (err == EEXIST)
2163 		return (IPADM_ADDROBJ_EXISTS);
2164 	return (ipadm_errno2status(err));
2165 }
2166 
2167 /*
2168  * Sets the logical interface number in the ipmgmtd's memory map for the
2169  * address object `ipaddr'. If another address object has the same
2170  * logical interface number, IPADM_ADDROBJ_EXISTS is returned.
2171  */
2172 ipadm_status_t
2173 i_ipadm_setlifnum_addrobj(ipadm_handle_t iph, ipadm_addrobj_t ipaddr)
2174 {
2175 	ipmgmt_aobjop_arg_t	larg;
2176 	ipmgmt_retval_t		rval, *rvalp;
2177 	int			err;
2178 
2179 	if (iph->iph_flags & IPH_IPMGMTD)
2180 		return (IPADM_SUCCESS);
2181 
2182 	bzero(&larg, sizeof (larg));
2183 	larg.ia_cmd = IPMGMT_CMD_ADDROBJ_SETLIFNUM;
2184 	(void) strlcpy(larg.ia_aobjname, ipaddr->ipadm_aobjname,
2185 	    sizeof (larg.ia_aobjname));
2186 	larg.ia_lnum = ipaddr->ipadm_lifnum;
2187 	(void) strlcpy(larg.ia_ifname, ipaddr->ipadm_ifname,
2188 	    sizeof (larg.ia_ifname));
2189 	larg.ia_family = ipaddr->ipadm_af;
2190 
2191 	rvalp = &rval;
2192 	err = ipadm_door_call(iph, &larg, sizeof (larg), (void **)&rvalp,
2193 	    sizeof (rval), B_FALSE);
2194 	if (err == EEXIST)
2195 		return (IPADM_ADDROBJ_EXISTS);
2196 	return (ipadm_errno2status(err));
2197 }
2198 
2199 /*
2200  * Creates the IPv4 or IPv6 address in the nvlist `nvl' on the interface
2201  * `ifname'. If a hostname is present, it is resolved before the address
2202  * is created.
2203  */
2204 ipadm_status_t
2205 i_ipadm_enable_static(ipadm_handle_t iph, const char *ifname, nvlist_t *nvl,
2206     sa_family_t af)
2207 {
2208 	char			*prefixlenstr = NULL;
2209 	char			*upstr = NULL;
2210 	char			*sname = NULL, *dname = NULL;
2211 	struct ipadm_addrobj_s	ipaddr;
2212 	char			*aobjname = NULL;
2213 	nvlist_t		*nvaddr = NULL;
2214 	nvpair_t		*nvp;
2215 	char			*cidraddr;
2216 	char			*name;
2217 	ipadm_status_t		status;
2218 	int			err = 0;
2219 	uint32_t		flags = IPADM_OPT_ACTIVE;
2220 
2221 	/* retrieve the address information */
2222 	for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL;
2223 	    nvp = nvlist_next_nvpair(nvl, nvp)) {
2224 		name = nvpair_name(nvp);
2225 		if (strcmp(name, IPADM_NVP_IPV4ADDR) == 0 ||
2226 		    strcmp(name, IPADM_NVP_IPV6ADDR) == 0) {
2227 			err = nvpair_value_nvlist(nvp, &nvaddr);
2228 		} else if (strcmp(name, IPADM_NVP_AOBJNAME) == 0) {
2229 			err = nvpair_value_string(nvp, &aobjname);
2230 		} else if (strcmp(name, IPADM_NVP_PREFIXLEN) == 0) {
2231 			err = nvpair_value_string(nvp, &prefixlenstr);
2232 		} else if (strcmp(name, "up") == 0) {
2233 			err = nvpair_value_string(nvp, &upstr);
2234 		}
2235 		if (err != 0)
2236 			return (ipadm_errno2status(err));
2237 	}
2238 	for (nvp = nvlist_next_nvpair(nvaddr, NULL); nvp != NULL;
2239 	    nvp = nvlist_next_nvpair(nvaddr, nvp)) {
2240 		name = nvpair_name(nvp);
2241 		if (strcmp(name, IPADM_NVP_IPADDRHNAME) == 0)
2242 			err = nvpair_value_string(nvp, &sname);
2243 		else if (strcmp(name, IPADM_NVP_IPDADDRHNAME) == 0)
2244 			err = nvpair_value_string(nvp, &dname);
2245 		if (err != 0)
2246 			return (ipadm_errno2status(err));
2247 	}
2248 
2249 	if (strcmp(upstr, "yes") == 0)
2250 		flags |= IPADM_OPT_UP;
2251 
2252 	/* build the address object from the above information */
2253 	i_ipadm_init_addr(&ipaddr, ifname, aobjname, IPADM_ADDR_STATIC);
2254 	if (prefixlenstr != NULL && atoi(prefixlenstr) > 0) {
2255 		if (asprintf(&cidraddr, "%s/%s", sname, prefixlenstr) == -1)
2256 			return (IPADM_NO_MEMORY);
2257 		status = ipadm_set_addr(&ipaddr, cidraddr, af);
2258 		free(cidraddr);
2259 	} else {
2260 		status = ipadm_set_addr(&ipaddr, sname, af);
2261 	}
2262 	if (status != IPADM_SUCCESS)
2263 		return (status);
2264 
2265 	if (dname != NULL) {
2266 		status = ipadm_set_dst_addr(&ipaddr, dname, af);
2267 		if (status != IPADM_SUCCESS)
2268 			return (status);
2269 	}
2270 	return (i_ipadm_create_addr(iph, &ipaddr, flags));
2271 }
2272 
2273 /*
2274  * Creates a dhcp address on the interface `ifname' based on the
2275  * IPADM_ADDR_DHCP address object parameters from the nvlist `nvl'.
2276  */
2277 ipadm_status_t
2278 i_ipadm_enable_dhcp(ipadm_handle_t iph, const char *ifname, nvlist_t *nvl)
2279 {
2280 	int32_t			wait = IPADM_DHCP_WAIT_DEFAULT;
2281 	boolean_t		primary = B_FALSE;
2282 	nvlist_t		*nvdhcp = NULL;
2283 	nvpair_t		*nvp;
2284 	char			*name;
2285 	struct ipadm_addrobj_s	ipaddr;
2286 	char			*aobjname = NULL, *reqhost = NULL;
2287 	int			err = 0;
2288 	ipadm_status_t		ipadm_err = IPADM_SUCCESS;
2289 
2290 	/* Extract the dhcp parameters */
2291 	for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL;
2292 	    nvp = nvlist_next_nvpair(nvl, nvp)) {
2293 		name = nvpair_name(nvp);
2294 		if (strcmp(name, IPADM_NVP_DHCP) == 0)
2295 			err = nvpair_value_nvlist(nvp, &nvdhcp);
2296 		else if (strcmp(name, IPADM_NVP_AOBJNAME) == 0)
2297 			err = nvpair_value_string(nvp, &aobjname);
2298 		else if (strcmp(name, IPADM_NVP_REQHOST) == 0)
2299 			err = nvpair_value_string(nvp, &reqhost);
2300 		if (err != 0)
2301 			return (ipadm_errno2status(err));
2302 	}
2303 	for (nvp = nvlist_next_nvpair(nvdhcp, NULL); nvp != NULL;
2304 	    nvp = nvlist_next_nvpair(nvdhcp, nvp)) {
2305 		name = nvpair_name(nvp);
2306 		if (strcmp(name, IPADM_NVP_WAIT) == 0)
2307 			err = nvpair_value_int32(nvp, &wait);
2308 		else if (strcmp(name, IPADM_NVP_PRIMARY) == 0)
2309 			err = nvpair_value_boolean_value(nvp, &primary);
2310 		if (err != 0)
2311 			return (ipadm_errno2status(err));
2312 	}
2313 
2314 	/* Build the address object */
2315 	i_ipadm_init_addr(&ipaddr, ifname, aobjname, IPADM_ADDR_DHCP);
2316 	ipaddr.ipadm_primary = primary;
2317 	if (iph->iph_flags & IPH_INIT)
2318 		ipaddr.ipadm_wait = 0;
2319 	else
2320 		ipaddr.ipadm_wait = wait;
2321 	ipadm_err = ipadm_set_reqhost(&ipaddr, reqhost);
2322 	if (ipadm_err != IPADM_SUCCESS)
2323 		return (ipadm_err);
2324 	ipaddr.ipadm_af = AF_INET;
2325 	return (i_ipadm_create_dhcp(iph, &ipaddr, IPADM_OPT_ACTIVE));
2326 }
2327 
2328 /*
2329  * Creates auto-configured addresses on the interface `ifname' based on
2330  * the IPADM_ADDR_IPV6_ADDRCONF address object parameters from the nvlist `nvl'.
2331  */
2332 ipadm_status_t
2333 i_ipadm_enable_addrconf(ipadm_handle_t iph, const char *ifname, nvlist_t *nvl)
2334 {
2335 	struct ipadm_addrobj_s	ipaddr;
2336 	char		*stateful = NULL, *stateless = NULL;
2337 	uint_t		n;
2338 	uint8_t		*addr6 = NULL;
2339 	uint32_t	intfidlen = 0;
2340 	char		*aobjname;
2341 	nvlist_t	*nvaddr;
2342 	nvpair_t	*nvp;
2343 	char		*name;
2344 	int		err = 0;
2345 
2346 	/* Extract the parameters */
2347 	for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL;
2348 	    nvp = nvlist_next_nvpair(nvl, nvp)) {
2349 		name = nvpair_name(nvp);
2350 		if (strcmp(name, IPADM_NVP_INTFID) == 0)
2351 			err = nvpair_value_nvlist(nvp, &nvaddr);
2352 		else if (strcmp(name, IPADM_NVP_AOBJNAME) == 0)
2353 			err = nvpair_value_string(nvp, &aobjname);
2354 		if (err != 0)
2355 			return (ipadm_errno2status(err));
2356 	}
2357 	for (nvp = nvlist_next_nvpair(nvaddr, NULL); nvp != NULL;
2358 	    nvp = nvlist_next_nvpair(nvaddr, nvp)) {
2359 		name = nvpair_name(nvp);
2360 		if (strcmp(name, IPADM_NVP_IPNUMADDR) == 0)
2361 			err = nvpair_value_uint8_array(nvp, &addr6, &n);
2362 		if (strcmp(name, IPADM_NVP_PREFIXLEN) == 0)
2363 			err = nvpair_value_uint32(nvp, &intfidlen);
2364 		else if (strcmp(name, IPADM_NVP_STATELESS) == 0)
2365 			err = nvpair_value_string(nvp, &stateless);
2366 		else if (strcmp(name, IPADM_NVP_STATEFUL) == 0)
2367 			err = nvpair_value_string(nvp, &stateful);
2368 		if (err != 0)
2369 			return (ipadm_errno2status(err));
2370 	}
2371 	/* Build the address object. */
2372 	i_ipadm_init_addr(&ipaddr, ifname, aobjname, IPADM_ADDR_IPV6_ADDRCONF);
2373 	if (intfidlen > 0) {
2374 		ipaddr.ipadm_intfidlen = intfidlen;
2375 		bcopy(addr6, &ipaddr.ipadm_intfid.sin6_addr.s6_addr, n);
2376 	}
2377 	ipaddr.ipadm_stateless = (strcmp(stateless, "yes") == 0);
2378 	ipaddr.ipadm_stateful = (strcmp(stateful, "yes") == 0);
2379 	return (i_ipadm_create_ipv6addrs(iph, &ipaddr, IPADM_OPT_ACTIVE));
2380 }
2381 
2382 /*
2383  * Allocates `ipadm_addrobj_t' and populates the relevant member fields based on
2384  * the provided `type'. `aobjname' represents the address object name, which
2385  * is of the form `<ifname>/<addressname>'.
2386  *
2387  * The caller has to minimally provide <ifname>. If <addressname> is not
2388  * provided, then a default one will be generated by the API.
2389  */
2390 ipadm_status_t
2391 ipadm_create_addrobj(ipadm_addr_type_t type, const char *aobjname,
2392     ipadm_addrobj_t *ipaddr)
2393 {
2394 	ipadm_addrobj_t	newaddr;
2395 	ipadm_status_t	status;
2396 	char		*aname, *cp;
2397 	char		ifname[IPADM_AOBJSIZ];
2398 	ifspec_t	ifsp;
2399 
2400 	if (ipaddr == NULL)
2401 		return (IPADM_INVALID_ARG);
2402 	*ipaddr = NULL;
2403 
2404 	if (aobjname == NULL || aobjname[0] == '\0')
2405 		return (IPADM_INVALID_ARG);
2406 
2407 	if (strlcpy(ifname, aobjname, IPADM_AOBJSIZ) >= IPADM_AOBJSIZ)
2408 		return (IPADM_INVALID_ARG);
2409 
2410 	if ((aname = strchr(ifname, '/')) != NULL)
2411 		*aname++ = '\0';
2412 
2413 	/* Check if the interface name is valid. */
2414 	if (!ifparse_ifspec(ifname, &ifsp))
2415 		return (IPADM_INVALID_ARG);
2416 	/* Check if the given addrobj name is valid. */
2417 	if (aname != NULL && !i_ipadm_is_user_aobjname_valid(aname))
2418 		return (IPADM_INVALID_ARG);
2419 	if ((newaddr = calloc(1, sizeof (struct ipadm_addrobj_s))) == NULL)
2420 		return (IPADM_NO_MEMORY);
2421 
2422 	/*
2423 	 * If the ifname has logical interface number, extract it and assign
2424 	 * it to `ipadm_lifnum'. Only applications with IPH_LEGACY set will do
2425 	 * this today. We will check for the validity later in
2426 	 * i_ipadm_validate_create_addr().
2427 	 */
2428 	if (ifsp.ifsp_lunvalid) {
2429 		newaddr->ipadm_lifnum = ifsp.ifsp_lun;
2430 		cp = strchr(ifname, IPADM_LOGICAL_SEP);
2431 		*cp = '\0';
2432 	}
2433 	(void) strlcpy(newaddr->ipadm_ifname, ifname,
2434 	    sizeof (newaddr->ipadm_ifname));
2435 
2436 	if (aname != NULL) {
2437 		(void) snprintf(newaddr->ipadm_aobjname,
2438 		    sizeof (newaddr->ipadm_aobjname), "%s/%s", ifname, aname);
2439 	}
2440 
2441 	switch (type) {
2442 	case IPADM_ADDR_IPV6_ADDRCONF:
2443 		newaddr->ipadm_intfidlen = 0;
2444 		newaddr->ipadm_stateful = B_TRUE;
2445 		newaddr->ipadm_stateless = B_TRUE;
2446 		newaddr->ipadm_af = AF_INET6;
2447 		break;
2448 
2449 	case IPADM_ADDR_DHCP:
2450 		newaddr->ipadm_primary = B_FALSE;
2451 		newaddr->ipadm_wait = IPADM_DHCP_WAIT_DEFAULT;
2452 		newaddr->ipadm_af = AF_INET;
2453 		break;
2454 
2455 	case IPADM_ADDR_STATIC:
2456 		newaddr->ipadm_af = AF_UNSPEC;
2457 		newaddr->ipadm_static_prefixlen = 0;
2458 		break;
2459 
2460 	default:
2461 		status = IPADM_INVALID_ARG;
2462 		goto fail;
2463 	}
2464 	newaddr->ipadm_atype = type;
2465 	*ipaddr = newaddr;
2466 	return (IPADM_SUCCESS);
2467 fail:
2468 	free(newaddr);
2469 	return (status);
2470 }
2471 
2472 /*
2473  * Returns `aobjname' from the address object in `ipaddr'.
2474  */
2475 ipadm_status_t
2476 ipadm_get_aobjname(const ipadm_addrobj_t ipaddr, char *aobjname, size_t len)
2477 {
2478 	if (ipaddr == NULL || aobjname == NULL)
2479 		return (IPADM_INVALID_ARG);
2480 	if (strlcpy(aobjname, ipaddr->ipadm_aobjname, len) >= len)
2481 		return (IPADM_INVALID_ARG);
2482 
2483 	return (IPADM_SUCCESS);
2484 }
2485 
2486 /*
2487  * Frees the address object in `ipaddr'.
2488  */
2489 void
2490 ipadm_destroy_addrobj(ipadm_addrobj_t ipaddr)
2491 {
2492 	free(ipaddr);
2493 }
2494 
2495 /*
2496  * Retrieves the logical interface name from `ipaddr' and stores the
2497  * string in `lifname'.
2498  */
2499 void
2500 i_ipadm_addrobj2lifname(ipadm_addrobj_t ipaddr, char *lifname, int lifnamesize)
2501 {
2502 	if (ipaddr->ipadm_lifnum != 0) {
2503 		(void) snprintf(lifname, lifnamesize, "%s:%d",
2504 		    ipaddr->ipadm_ifname, ipaddr->ipadm_lifnum);
2505 	} else {
2506 		(void) snprintf(lifname, lifnamesize, "%s",
2507 		    ipaddr->ipadm_ifname);
2508 	}
2509 }
2510 
2511 /*
2512  * Checks if a non-zero static address is present on the 0th logical interface
2513  * of the given IPv4 or IPv6 physical interface. For an IPv4 interface, it
2514  * also checks if the interface is under DHCP control. If the condition is true,
2515  * the output argument `exists' will be set to B_TRUE. Otherwise, `exists'
2516  * is set to B_FALSE.
2517  *
2518  * Note that *exists will not be initialized if an error is encountered.
2519  */
2520 static ipadm_status_t
2521 i_ipadm_addr_exists_on_if(ipadm_handle_t iph, const char *ifname,
2522     sa_family_t af, boolean_t *exists)
2523 {
2524 	struct lifreq	lifr;
2525 	int		sock;
2526 
2527 	/* For IPH_LEGACY, a new logical interface will never be added. */
2528 	if (iph->iph_flags & IPH_LEGACY) {
2529 		*exists = B_FALSE;
2530 		return (IPADM_SUCCESS);
2531 	}
2532 	bzero(&lifr, sizeof (lifr));
2533 	(void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
2534 	if (af == AF_INET) {
2535 		sock = iph->iph_sock;
2536 		if (ioctl(sock, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0)
2537 			return (ipadm_errno2status(errno));
2538 		if (lifr.lifr_flags & IFF_DHCPRUNNING) {
2539 			*exists = B_TRUE;
2540 			return (IPADM_SUCCESS);
2541 		}
2542 	} else {
2543 		sock = iph->iph_sock6;
2544 	}
2545 	if (ioctl(sock, SIOCGLIFADDR, (caddr_t)&lifr) < 0)
2546 		return (ipadm_errno2status(errno));
2547 	*exists = !sockaddrunspec((struct sockaddr *)&lifr.lifr_addr);
2548 
2549 	return (IPADM_SUCCESS);
2550 }
2551 
2552 /*
2553  * Adds a new logical interface in the kernel for interface
2554  * `addr->ipadm_ifname', if there is a non-zero address on the 0th
2555  * logical interface or if the 0th logical interface is under DHCP
2556  * control. On success, it sets the lifnum in the address object `addr'.
2557  */
2558 ipadm_status_t
2559 i_ipadm_do_addif(ipadm_handle_t iph, ipadm_addrobj_t addr)
2560 {
2561 	ipadm_status_t	status;
2562 	boolean_t	addif;
2563 	struct lifreq	lifr;
2564 	int		sock;
2565 
2566 	addr->ipadm_lifnum = 0;
2567 	status = i_ipadm_addr_exists_on_if(iph, addr->ipadm_ifname,
2568 	    addr->ipadm_af, &addif);
2569 	if (status != IPADM_SUCCESS)
2570 		return (status);
2571 	if (addif) {
2572 		/*
2573 		 * If there is an address on 0th logical interface,
2574 		 * add a new logical interface.
2575 		 */
2576 		bzero(&lifr, sizeof (lifr));
2577 		(void) strlcpy(lifr.lifr_name, addr->ipadm_ifname,
2578 		    sizeof (lifr.lifr_name));
2579 		sock = (addr->ipadm_af == AF_INET ? iph->iph_sock :
2580 		    iph->iph_sock6);
2581 		if (ioctl(sock, SIOCLIFADDIF, (caddr_t)&lifr) < 0)
2582 			return (ipadm_errno2status(errno));
2583 		addr->ipadm_lifnum = i_ipadm_get_lnum(lifr.lifr_name);
2584 	}
2585 	return (IPADM_SUCCESS);
2586 }
2587 
2588 /*
2589  * Reads all the address lines from the persistent DB into the nvlist `onvl',
2590  * when both `ifname' and `aobjname' are NULL. If an `ifname' is provided,
2591  * it returns all the addresses for the given interface `ifname'.
2592  * If an `aobjname' is specified, then the address line corresponding to
2593  * that name will be returned.
2594  */
2595 static ipadm_status_t
2596 i_ipadm_get_db_addr(ipadm_handle_t iph, const char *ifname,
2597     const char *aobjname, nvlist_t **onvl)
2598 {
2599 	ipmgmt_getaddr_arg_t	garg;
2600 
2601 	/* Populate the door_call argument structure */
2602 	bzero(&garg, sizeof (garg));
2603 	garg.ia_cmd = IPMGMT_CMD_GETADDR;
2604 	if (aobjname != NULL)
2605 		(void) strlcpy(garg.ia_aobjname, aobjname,
2606 		    sizeof (garg.ia_aobjname));
2607 	if (ifname != NULL)
2608 		(void) strlcpy(garg.ia_ifname, ifname, sizeof (garg.ia_ifname));
2609 
2610 	return (i_ipadm_call_ipmgmtd(iph, (void *) &garg, sizeof (garg), onvl));
2611 }
2612 
2613 /*
2614  * Adds the IP address contained in the 'ipaddr' argument to the physical
2615  * interface represented by 'ifname' after doing the required validation.
2616  * If the interface does not exist, it is created before the address is
2617  * added.
2618  *
2619  * If IPH_LEGACY is set in iph_flags, flags has to be IPADM_OPT_ACTIVE
2620  * and a default addrobj name will be generated. Input `addr->ipadm_aobjname',
2621  * if provided, will be ignored and replaced with the newly generated name.
2622  * The interface name provided has to be a logical interface name that
2623  * already exists. No new logical interface will be added in this function.
2624  *
2625  * If IPADM_OPT_V46 is passed in the flags, then both IPv4 and IPv6 interfaces
2626  * are plumbed (if they haven't been already).  Otherwise, just the interface
2627  * specified in `addr' is plumbed.
2628  */
2629 ipadm_status_t
2630 ipadm_create_addr(ipadm_handle_t iph, ipadm_addrobj_t addr, uint32_t flags)
2631 {
2632 	ipadm_status_t		status;
2633 	sa_family_t		af;
2634 	sa_family_t		daf;
2635 	sa_family_t		other_af;
2636 	boolean_t		created_af = B_FALSE;
2637 	boolean_t		created_other_af = B_FALSE;
2638 	ipadm_addr_type_t	type;
2639 	char			*ifname = addr->ipadm_ifname;
2640 	boolean_t		legacy = (iph->iph_flags & IPH_LEGACY);
2641 	boolean_t		aobjfound;
2642 	boolean_t		is_6to4;
2643 	struct lifreq		lifr;
2644 	uint64_t		ifflags;
2645 	boolean_t		is_boot = (iph->iph_flags & IPH_IPMGMTD);
2646 	boolean_t		is_ipmp;
2647 	char			gifname[LIFGRNAMSIZ];
2648 
2649 	/* check for solaris.network.interface.config authorization */
2650 	if (!ipadm_check_auth())
2651 		return (IPADM_EAUTH);
2652 
2653 	/* Validate the addrobj. This also fills in addr->ipadm_ifname. */
2654 	status = i_ipadm_validate_create_addr(iph, addr, flags);
2655 	if (status != IPADM_SUCCESS)
2656 		return (status);
2657 	/*
2658 	 * For Legacy case, check if an addrobj already exists for the
2659 	 * given logical interface name. If one does not exist,
2660 	 * a default name will be generated and added to the daemon's
2661 	 * aobjmap.
2662 	 */
2663 	if (legacy) {
2664 		struct ipadm_addrobj_s	ipaddr;
2665 
2666 		ipaddr = *addr;
2667 		status = i_ipadm_get_lif2addrobj(iph, &ipaddr);
2668 		if (status == IPADM_SUCCESS) {
2669 			aobjfound = B_TRUE;
2670 			/*
2671 			 * With IPH_LEGACY, modifying an address that is not
2672 			 * a static address will return with an error.
2673 			 */
2674 			if (ipaddr.ipadm_atype != IPADM_ADDR_STATIC)
2675 				return (IPADM_NOTSUP);
2676 			/*
2677 			 * we found the addrobj in daemon, copy over the
2678 			 * aobjname to `addr'.
2679 			 */
2680 			(void) strlcpy(addr->ipadm_aobjname,
2681 			    ipaddr.ipadm_aobjname, IPADM_AOBJSIZ);
2682 		} else if (status == IPADM_NOTFOUND) {
2683 			aobjfound = B_FALSE;
2684 		} else {
2685 			return (status);
2686 		}
2687 	}
2688 
2689 	af = addr->ipadm_af;
2690 	/*
2691 	 * Create a placeholder for this address object in the daemon.
2692 	 * Skip this step if we are booting a zone (and therefore being called
2693 	 * from ipmgmtd itself), and, for IPH_LEGACY case if the
2694 	 * addrobj already exists.
2695 	 *
2696 	 * Note that the placeholder is not needed in the NGZ boot case,
2697 	 * when zoneadmd has itself applied the "allowed-ips" property to clamp
2698 	 * down any interface configuration, so the namespace for the interface
2699 	 * is fully controlled by the GZ.
2700 	 */
2701 	if (!is_boot && (!legacy || !aobjfound)) {
2702 		status = i_ipadm_lookupadd_addrobj(iph, addr);
2703 		if (status != IPADM_SUCCESS)
2704 			return (status);
2705 	}
2706 
2707 	is_6to4 = i_ipadm_is_6to4(iph, ifname);
2708 	/* Plumb the IP interfaces if necessary */
2709 	status = i_ipadm_create_if(iph, ifname, af, flags);
2710 	if (status != IPADM_SUCCESS && status != IPADM_IF_EXISTS) {
2711 		(void) i_ipadm_delete_addrobj(iph, addr, IPADM_OPT_ACTIVE);
2712 		return (status);
2713 	}
2714 	if (status == IPADM_SUCCESS)
2715 		created_af = B_TRUE;
2716 	if (!is_6to4 && !legacy && (flags & IPADM_OPT_V46)) {
2717 		other_af = (af == AF_INET ? AF_INET6 : AF_INET);
2718 		status = i_ipadm_create_if(iph, ifname, other_af, flags);
2719 		if (status != IPADM_SUCCESS && status != IPADM_IF_EXISTS) {
2720 			(void) i_ipadm_delete_if(iph, ifname, af, flags);
2721 			return (status);
2722 		}
2723 		if (status == IPADM_SUCCESS)
2724 			created_other_af = B_TRUE;
2725 	}
2726 
2727 	/*
2728 	 * Some input validation based on the interface flags:
2729 	 * 1. in non-global zones, make sure that we are not persistently
2730 	 *    creating addresses on interfaces that are acquiring
2731 	 *    address from the global zone.
2732 	 * 2. Validate static addresses for IFF_POINTOPOINT interfaces.
2733 	 */
2734 	if (addr->ipadm_atype == IPADM_ADDR_STATIC) {
2735 		status = i_ipadm_get_flags(iph, ifname, af, &ifflags);
2736 		if (status != IPADM_SUCCESS)
2737 			goto fail;
2738 
2739 		if (iph->iph_zoneid != GLOBAL_ZONEID &&
2740 		    (ifflags & IFF_L3PROTECT) && (flags & IPADM_OPT_PERSIST)) {
2741 			status = IPADM_GZ_PERM;
2742 			goto fail;
2743 		}
2744 		daf = addr->ipadm_static_dst_addr.ss_family;
2745 		if (ifflags & IFF_POINTOPOINT) {
2746 			if (is_6to4) {
2747 				if (af != AF_INET6 || daf != AF_UNSPEC) {
2748 					status = IPADM_INVALID_ARG;
2749 					goto fail;
2750 				}
2751 			} else {
2752 				if (daf != af) {
2753 					status = IPADM_INVALID_ARG;
2754 					goto fail;
2755 				}
2756 				/* Check for a valid dst address. */
2757 				if (!legacy && sockaddrunspec(
2758 				    (struct sockaddr *)
2759 				    &addr->ipadm_static_dst_addr)) {
2760 					status = IPADM_BAD_ADDR;
2761 					goto fail;
2762 				}
2763 			}
2764 		} else {
2765 			/*
2766 			 * Disallow setting of dstaddr when the link is not
2767 			 * a point-to-point link.
2768 			 */
2769 			if (daf != AF_UNSPEC)
2770 				return (IPADM_INVALID_ARG);
2771 		}
2772 	}
2773 
2774 	/*
2775 	 * For 6to4 interfaces, kernel configures a default link-local
2776 	 * address. We need to replace it, if the caller has provided
2777 	 * an address that is different from the default link-local.
2778 	 */
2779 	if (status == IPADM_SUCCESS && is_6to4) {
2780 		bzero(&lifr, sizeof (lifr));
2781 		(void) strlcpy(lifr.lifr_name, addr->ipadm_ifname,
2782 		    sizeof (lifr.lifr_name));
2783 		if (ioctl(iph->iph_sock6, SIOCGLIFADDR, &lifr) < 0) {
2784 			status = ipadm_errno2status(errno);
2785 			goto fail;
2786 		}
2787 		if (sockaddrcmp(&lifr.lifr_addr, &addr->ipadm_static_addr))
2788 			return (IPADM_SUCCESS);
2789 	}
2790 
2791 	/*
2792 	 * If interface is an IPMP group member, move it out of the group before
2793 	 * performing any operations on it.
2794 	 */
2795 	if ((is_ipmp = i_ipadm_is_under_ipmp(iph, addr->ipadm_ifname))) {
2796 		(void) i_ipadm_get_groupname_active(iph, addr->ipadm_ifname,
2797 		    gifname, sizeof (gifname));
2798 		(void) i_ipadm_set_groupname_active(iph, addr->ipadm_ifname,
2799 		    "");
2800 	}
2801 
2802 	/* Create the address. */
2803 	type = addr->ipadm_atype;
2804 	switch (type) {
2805 	case IPADM_ADDR_STATIC:
2806 		status = i_ipadm_create_addr(iph, addr, flags);
2807 		break;
2808 	case IPADM_ADDR_DHCP:
2809 		status = i_ipadm_create_dhcp(iph, addr, flags);
2810 		break;
2811 	case IPADM_ADDR_IPV6_ADDRCONF:
2812 		status = i_ipadm_create_ipv6addrs(iph, addr, flags);
2813 		break;
2814 	default:
2815 		status = IPADM_INVALID_ARG;
2816 		break;
2817 	}
2818 
2819 	/* Move the underlying IPMP interface back to the group */
2820 	if (is_ipmp) {
2821 		(void) i_ipadm_set_groupname_active(iph, addr->ipadm_ifname,
2822 		    gifname);
2823 	}
2824 
2825 	/*
2826 	 * If address was not created successfully, unplumb the interface
2827 	 * if it was plumbed implicitly in this function and remove the
2828 	 * addrobj created by the ipmgmtd daemon as a placeholder.
2829 	 * If IPH_LEGACY is set, then remove the addrobj only if it was
2830 	 * created in this function.
2831 	 */
2832 fail:
2833 	if (status != IPADM_DHCP_IPC_TIMEOUT &&
2834 	    status != IPADM_SUCCESS) {
2835 		if (!legacy) {
2836 			if (created_af || created_other_af) {
2837 				if (created_af) {
2838 					(void) i_ipadm_delete_if(iph, ifname,
2839 					    af, flags);
2840 				}
2841 				if (created_other_af) {
2842 					(void) i_ipadm_delete_if(iph, ifname,
2843 					    other_af, flags);
2844 				}
2845 			} else {
2846 				(void) i_ipadm_delete_addrobj(iph, addr, flags);
2847 			}
2848 		} else if (!aobjfound) {
2849 			(void) i_ipadm_delete_addrobj(iph, addr, flags);
2850 		}
2851 	}
2852 
2853 	return (status);
2854 }
2855 
2856 /*
2857  * Creates the static address in `ipaddr' in kernel. After successfully
2858  * creating it, it updates the ipmgmtd daemon's aobjmap with the logical
2859  * interface information.
2860  */
2861 static ipadm_status_t
2862 i_ipadm_create_addr(ipadm_handle_t iph, ipadm_addrobj_t ipaddr, uint32_t flags)
2863 {
2864 	struct lifreq			lifr;
2865 	ipadm_status_t			status = IPADM_SUCCESS;
2866 	int				sock;
2867 	struct sockaddr_storage		m, *mask = &m;
2868 	const struct sockaddr_storage	*addr = &ipaddr->ipadm_static_addr;
2869 	const struct sockaddr_storage	*daddr = &ipaddr->ipadm_static_dst_addr;
2870 	sa_family_t			af;
2871 	boolean_t			legacy = (iph->iph_flags & IPH_LEGACY);
2872 	struct ipadm_addrobj_s		legacy_addr;
2873 	boolean_t			default_prefixlen = B_FALSE;
2874 	boolean_t			is_boot;
2875 
2876 	is_boot = ((iph->iph_flags & IPH_IPMGMTD) != 0);
2877 	af = ipaddr->ipadm_af;
2878 	sock = (af == AF_INET ? iph->iph_sock : iph->iph_sock6);
2879 
2880 	/* If prefixlen was not provided, get default prefixlen */
2881 	if (ipaddr->ipadm_static_prefixlen == 0) {
2882 		/* prefixlen was not provided, get default prefixlen */
2883 		status = i_ipadm_get_default_prefixlen(
2884 		    &ipaddr->ipadm_static_addr,
2885 		    &ipaddr->ipadm_static_prefixlen);
2886 		if (status != IPADM_SUCCESS)
2887 			return (status);
2888 		default_prefixlen = B_TRUE;
2889 	}
2890 	(void) plen2mask(ipaddr->ipadm_static_prefixlen, af,
2891 	    (struct sockaddr *)mask);
2892 
2893 	/*
2894 	 * Create a new logical interface if needed; otherwise, just
2895 	 * use the 0th logical interface.
2896 	 */
2897 	if (!(iph->iph_flags & IPH_LEGACY)) {
2898 		status = i_ipadm_do_addif(iph, ipaddr);
2899 		if (status != IPADM_SUCCESS)
2900 			return (status);
2901 	}
2902 	i_ipadm_addrobj2lifname(ipaddr, lifr.lifr_name,
2903 	    sizeof (lifr.lifr_name));
2904 	lifr.lifr_addr = *mask;
2905 	if (ioctl(sock, SIOCSLIFNETMASK, (caddr_t)&lifr) < 0) {
2906 		status = ipadm_errno2status(errno);
2907 		goto ret;
2908 	}
2909 	lifr.lifr_addr = *addr;
2910 	if (ioctl(sock, SIOCSLIFADDR, (caddr_t)&lifr) < 0) {
2911 		status = ipadm_errno2status(errno);
2912 		goto ret;
2913 	}
2914 	/* Set the destination address, if one is given. */
2915 	if (daddr->ss_family != AF_UNSPEC) {
2916 		lifr.lifr_addr = *daddr;
2917 		if (ioctl(sock, SIOCSLIFDSTADDR, (caddr_t)&lifr) < 0) {
2918 			status = ipadm_errno2status(errno);
2919 			goto ret;
2920 		}
2921 	}
2922 
2923 	if (flags & IPADM_OPT_UP) {
2924 		uint32_t	iff_flags = IFF_UP;
2925 
2926 		/*
2927 		 * Set the NOFAILOVER flag only on underlying IPMP interface
2928 		 * and not the IPMP group interface itself.
2929 		 */
2930 		if (i_ipadm_is_under_ipmp(iph, lifr.lifr_name) &&
2931 		    !i_ipadm_is_ipmp(iph, lifr.lifr_name))
2932 			iff_flags |= IFF_NOFAILOVER;
2933 
2934 		status = i_ipadm_set_flags(iph, lifr.lifr_name,
2935 		    af, iff_flags, 0);
2936 
2937 		/*
2938 		 * IPADM_DAD_FOUND is a soft-error for create-addr.
2939 		 * No need to tear down the address.
2940 		 */
2941 		if (status == IPADM_DAD_FOUND)
2942 			status = IPADM_SUCCESS;
2943 	}
2944 
2945 	if (status == IPADM_SUCCESS && !is_boot) {
2946 		/*
2947 		 * For IPH_LEGACY, we might be modifying the address on
2948 		 * an address object that already exists e.g. by doing
2949 		 * "ifconfig bge0:1 <addr>; ifconfig bge0:1 <newaddr>"
2950 		 * So, we need to store the object only if it does not
2951 		 * already exist in ipmgmtd.
2952 		 */
2953 		if (legacy) {
2954 			bzero(&legacy_addr, sizeof (legacy_addr));
2955 			(void) strlcpy(legacy_addr.ipadm_aobjname,
2956 			    ipaddr->ipadm_aobjname,
2957 			    sizeof (legacy_addr.ipadm_aobjname));
2958 			status = i_ipadm_get_addrobj(iph, &legacy_addr);
2959 			if (status == IPADM_SUCCESS &&
2960 			    legacy_addr.ipadm_lifnum >= 0) {
2961 				return (status);
2962 			}
2963 		}
2964 		status = i_ipadm_addr_persist(iph, ipaddr, default_prefixlen,
2965 		    flags, NULL);
2966 	}
2967 ret:
2968 	if (status != IPADM_SUCCESS && !legacy)
2969 		(void) i_ipadm_delete_addr(iph, ipaddr);
2970 
2971 	return (status);
2972 }
2973 
2974 /*
2975  * Removes the address object identified by `aobjname' from both active and
2976  * persistent configuration. The address object will be removed from only
2977  * active configuration if IPH_LEGACY is set in `iph->iph_flags'.
2978  *
2979  * If the address type is IPADM_ADDR_STATIC or IPADM_ADDR_DHCP, the address
2980  * in the address object will be removed from the physical interface.
2981  * If the address type is IPADM_ADDR_DHCP, the flag IPADM_OPT_RELEASE specifies
2982  * whether the lease should be released. If IPADM_OPT_RELEASE is not
2983  * specified, the lease will be dropped. This option is not supported
2984  * for other address types.
2985  *
2986  * If the address type is IPADM_ADDR_IPV6_ADDRCONF, the link-local address and
2987  * all the autoconfigured addresses will be removed.
2988  * Finally, the address object is also removed from ipmgmtd's aobjmap and from
2989  * the persistent DB.
2990  */
2991 ipadm_status_t
2992 ipadm_delete_addr(ipadm_handle_t iph, const char *aobjname, uint32_t flags)
2993 {
2994 	ipadm_status_t		status;
2995 	struct ipadm_addrobj_s	ipaddr;
2996 	boolean_t		release = ((flags & IPADM_OPT_RELEASE) != 0);
2997 	boolean_t		is_ipmp = B_FALSE;
2998 	char			gifname[LIFGRNAMSIZ];
2999 
3000 	/* check for solaris.network.interface.config authorization */
3001 	if (!ipadm_check_auth())
3002 		return (IPADM_EAUTH);
3003 
3004 	/* validate input */
3005 	if (flags == 0 || ((flags & IPADM_OPT_PERSIST) &&
3006 	    !(flags & IPADM_OPT_ACTIVE)) ||
3007 	    (flags & ~(IPADM_COMMON_OPT_MASK|IPADM_OPT_RELEASE))) {
3008 		return (IPADM_INVALID_ARG);
3009 	}
3010 	bzero(&ipaddr, sizeof (ipaddr));
3011 	if (aobjname == NULL || strlcpy(ipaddr.ipadm_aobjname, aobjname,
3012 	    IPADM_AOBJSIZ) >= IPADM_AOBJSIZ) {
3013 		return (IPADM_INVALID_ARG);
3014 	}
3015 
3016 	/* Retrieve the address object information from ipmgmtd. */
3017 	status = i_ipadm_get_addrobj(iph, &ipaddr);
3018 	if (status != IPADM_SUCCESS)
3019 		return (status);
3020 
3021 	if (release && ipaddr.ipadm_atype != IPADM_ADDR_DHCP)
3022 		return (IPADM_NOTSUP);
3023 	/*
3024 	 * If requested to delete just from active config but the address
3025 	 * is not in active config, return error.
3026 	 */
3027 	if (!(ipaddr.ipadm_flags & IPMGMT_ACTIVE) &&
3028 	    (flags & IPADM_OPT_ACTIVE) && !(flags & IPADM_OPT_PERSIST)) {
3029 		return (IPADM_NOTFOUND);
3030 	}
3031 
3032 	/*
3033 	 * If address is present in active config, remove it from
3034 	 * kernel.
3035 	 */
3036 	if (ipaddr.ipadm_flags & IPMGMT_ACTIVE) {
3037 
3038 		/*
3039 		 * If interface is an IPMP group member, move it out of the
3040 		 * group before performing any operations on it.
3041 		 */
3042 		if ((is_ipmp = i_ipadm_is_under_ipmp(iph,
3043 		    ipaddr.ipadm_ifname))) {
3044 			(void) i_ipadm_get_groupname_active(iph,
3045 			    ipaddr.ipadm_ifname, gifname, sizeof (gifname));
3046 			(void) i_ipadm_set_groupname_active(iph,
3047 			    ipaddr.ipadm_ifname, "");
3048 		}
3049 
3050 		switch (ipaddr.ipadm_atype) {
3051 		case IPADM_ADDR_STATIC:
3052 			status = i_ipadm_delete_addr(iph, &ipaddr);
3053 			break;
3054 		case IPADM_ADDR_DHCP:
3055 			status = i_ipadm_delete_dhcp(iph, &ipaddr, release);
3056 			break;
3057 		case IPADM_ADDR_IPV6_ADDRCONF:
3058 			status = i_ipadm_delete_ipv6addrs(iph, &ipaddr);
3059 			break;
3060 		default:
3061 			/*
3062 			 * This is the case of address object name residing in
3063 			 * daemon's aobjmap (added by ADDROBJ_LOOKUPADD). Fall
3064 			 * through and delete that address object.
3065 			 */
3066 			break;
3067 		}
3068 
3069 		/*
3070 		 * If the address was previously deleted from the active
3071 		 * config, we will get a IPADM_ENXIO from kernel.
3072 		 * We will still proceed and purge the address information
3073 		 * in the DB.
3074 		 */
3075 		if (status == IPADM_ENXIO)
3076 			status = IPADM_SUCCESS;
3077 		else if (status != IPADM_SUCCESS)
3078 			goto out;
3079 	}
3080 
3081 	if (!(ipaddr.ipadm_flags & IPMGMT_PERSIST) &&
3082 	    (flags & IPADM_OPT_PERSIST)) {
3083 		flags &= ~IPADM_OPT_PERSIST;
3084 	}
3085 	status = i_ipadm_delete_addrobj(iph, &ipaddr, flags);
3086 
3087 	if (status != IPADM_NOTFOUND)
3088 		status = IPADM_SUCCESS;
3089 
3090 out:
3091 	/*
3092 	 * Move the underlying IPMP interface back to the group.
3093 	 * This cannot be done until the persistent configuration has been
3094 	 * deleted as it will otherwise cause the active configuration to be
3095 	 * restored.
3096 	 */
3097 	if (is_ipmp) {
3098 		(void) i_ipadm_set_groupname_active(iph,
3099 		    ipaddr.ipadm_ifname, gifname);
3100 	}
3101 	return (status);
3102 }
3103 
3104 /*
3105  * Starts the dhcpagent and sends it the message DHCP_START to start
3106  * configuring a dhcp address on the given interface in `addr'.
3107  * After making the dhcpagent request, it also updates the
3108  * address object information in ipmgmtd's aobjmap and creates an
3109  * entry in persistent DB if IPADM_OPT_PERSIST is set in `flags'.
3110  */
3111 static ipadm_status_t
3112 i_ipadm_create_dhcp(ipadm_handle_t iph, ipadm_addrobj_t addr, uint32_t flags)
3113 {
3114 	ipadm_status_t	status;
3115 	ipadm_status_t	dh_status;
3116 
3117 	if (dhcp_start_agent(DHCP_IPC_MAX_WAIT) == -1)
3118 		return (IPADM_DHCP_START_ERROR);
3119 	/*
3120 	 * Create a new logical interface if needed; otherwise, just
3121 	 * use the 0th logical interface.
3122 	 */
3123 retry:
3124 	status = i_ipadm_do_addif(iph, addr);
3125 	if (status != IPADM_SUCCESS)
3126 		return (status);
3127 	/*
3128 	 * We don't have to set the lifnum for IPH_INIT case, because
3129 	 * there is no placeholder created for the address object in this
3130 	 * case.
3131 	 */
3132 	if (!(iph->iph_flags & IPH_INIT)) {
3133 		status = i_ipadm_setlifnum_addrobj(iph, addr);
3134 		if (status == IPADM_ADDROBJ_EXISTS)
3135 			goto retry;
3136 		if (status != IPADM_SUCCESS)
3137 			return (status);
3138 	}
3139 	/* Send DHCP_START to the dhcpagent. */
3140 	status = i_ipadm_op_dhcp(addr, DHCP_START, NULL);
3141 	/*
3142 	 * We do not undo the create-addr operation for IPADM_DHCP_IPC_TIMEOUT
3143 	 * since it is only a soft error to indicate the caller that the lease
3144 	 * might be required after the function returns.
3145 	 */
3146 	if (status != IPADM_SUCCESS && status != IPADM_DHCP_IPC_TIMEOUT)
3147 		goto fail;
3148 	dh_status = status;
3149 
3150 	/* Persist the address object information in ipmgmtd. */
3151 	status = i_ipadm_addr_persist(iph, addr, B_FALSE, flags, NULL);
3152 	if (status != IPADM_SUCCESS)
3153 		goto fail;
3154 
3155 	return (dh_status);
3156 fail:
3157 	/* In case of error, delete the dhcp address */
3158 	(void) i_ipadm_delete_dhcp(iph, addr, B_TRUE);
3159 	return (status);
3160 }
3161 
3162 /*
3163  * Releases/drops the dhcp lease on the logical interface in the address
3164  * object `addr'. If `release' is set to B_FALSE, the lease will be dropped.
3165  */
3166 static ipadm_status_t
3167 i_ipadm_delete_dhcp(ipadm_handle_t iph, ipadm_addrobj_t addr, boolean_t release)
3168 {
3169 	ipadm_status_t	status;
3170 	int		dherr;
3171 
3172 	/* Send DHCP_RELEASE or DHCP_DROP to the dhcpagent */
3173 	if (release) {
3174 		status = i_ipadm_op_dhcp(addr, DHCP_RELEASE, &dherr);
3175 		/*
3176 		 * If no lease was obtained on the object, we should
3177 		 * drop the dhcp control on the interface.
3178 		 */
3179 		if (status != IPADM_SUCCESS && dherr == DHCP_IPC_E_OUTSTATE)
3180 			status = i_ipadm_op_dhcp(addr, DHCP_DROP, NULL);
3181 	} else {
3182 		status = i_ipadm_op_dhcp(addr, DHCP_DROP, NULL);
3183 	}
3184 	if (status != IPADM_SUCCESS)
3185 		return (status);
3186 
3187 	/* Delete the logical interface */
3188 	if (addr->ipadm_lifnum != 0) {
3189 		struct lifreq lifr;
3190 
3191 		bzero(&lifr, sizeof (lifr));
3192 		i_ipadm_addrobj2lifname(addr, lifr.lifr_name,
3193 		    sizeof (lifr.lifr_name));
3194 		if (ioctl(iph->iph_sock, SIOCLIFREMOVEIF, (caddr_t)&lifr) < 0)
3195 			return (ipadm_errno2status(errno));
3196 	}
3197 
3198 	return (IPADM_SUCCESS);
3199 }
3200 
3201 /*
3202  * Communicates with the dhcpagent to send a dhcp message of type `type'.
3203  * It returns the dhcp error in `dhcperror' if a non-null pointer is provided
3204  * in `dhcperror'.
3205  */
3206 static ipadm_status_t
3207 i_ipadm_op_dhcp(ipadm_addrobj_t addr, dhcp_ipc_type_t type, int *dhcperror)
3208 {
3209 	dhcp_ipc_request_t	*request;
3210 	dhcp_ipc_reply_t	*reply	= NULL;
3211 	dhcp_symbol_t		*entry = NULL;
3212 	dhcp_data_type_t	dtype = DHCP_TYPE_NONE;
3213 	void			*d4o = NULL;
3214 	uint16_t		d4olen = 0;
3215 	char			ifname[LIFNAMSIZ];
3216 	int			error;
3217 	int			dhcp_timeout;
3218 
3219 	/* Construct a message to the dhcpagent. */
3220 	bzero(&ifname, sizeof (ifname));
3221 	i_ipadm_addrobj2lifname(addr, ifname, sizeof (ifname));
3222 	if (addr->ipadm_primary)
3223 		type |= DHCP_PRIMARY;
3224 
3225 	/* Set up a CD_HOSTNAME option, if applicable, to send through IPC */
3226 	switch (DHCP_IPC_CMD(type)) {
3227 	case DHCP_START:
3228 	case DHCP_EXTEND:
3229 		if (addr->ipadm_af == AF_INET && addr->ipadm_reqhost != NULL &&
3230 		    *addr->ipadm_reqhost != '\0') {
3231 			entry = inittab_getbycode(ITAB_CAT_STANDARD,
3232 			    ITAB_CONS_INFO, CD_HOSTNAME);
3233 			if (entry == NULL) {
3234 				return (IPADM_FAILURE);
3235 			} else {
3236 				d4o = inittab_encode(entry, addr->ipadm_reqhost,
3237 				    &d4olen, B_FALSE);
3238 				free(entry);
3239 				entry = NULL;
3240 				if (d4o == NULL)
3241 					return (IPADM_FAILURE);
3242 				dtype = DHCP_TYPE_OPTION;
3243 			}
3244 		}
3245 		break;
3246 	default:
3247 		break;
3248 	}
3249 
3250 	request = dhcp_ipc_alloc_request(type, ifname, d4o, d4olen, dtype);
3251 	if (request == NULL) {
3252 		free(d4o);
3253 		return (IPADM_NO_MEMORY);
3254 	}
3255 
3256 	if (addr->ipadm_wait == IPADM_DHCP_WAIT_FOREVER)
3257 		dhcp_timeout = DHCP_IPC_WAIT_FOREVER;
3258 	else if (addr->ipadm_wait == IPADM_DHCP_WAIT_DEFAULT)
3259 		dhcp_timeout = DHCP_IPC_WAIT_DEFAULT;
3260 	else
3261 		dhcp_timeout = addr->ipadm_wait;
3262 	/* Send the message to dhcpagent. */
3263 	error = dhcp_ipc_make_request(request, &reply, dhcp_timeout);
3264 	free(request);
3265 	free(d4o);
3266 	if (error == 0) {
3267 		error = reply->return_code;
3268 		free(reply);
3269 	}
3270 	if (error != 0) {
3271 		if (dhcperror != NULL)
3272 			*dhcperror = error;
3273 		if (error != DHCP_IPC_E_TIMEOUT)
3274 			return (IPADM_DHCP_IPC_ERROR);
3275 		else if (dhcp_timeout != 0)
3276 			return (IPADM_DHCP_IPC_TIMEOUT);
3277 	}
3278 
3279 	return (IPADM_SUCCESS);
3280 }
3281 
3282 /*
3283  * Communicates with the dhcpagent to send a dhcp message of type
3284  * DHCP_STATUS, and copy on success into the `status' instance owned by the
3285  * caller. It returns any dhcp error in `dhcperror' if a non-null pointer
3286  * is provided.
3287  */
3288 static ipadm_status_t
3289 i_ipadm_dhcp_status(ipadm_addrobj_t addr, dhcp_status_t *status,
3290     int *dhcperror)
3291 {
3292 	dhcp_ipc_type_t		type = DHCP_STATUS;
3293 	dhcp_ipc_request_t	*request;
3294 	dhcp_ipc_reply_t	*reply;
3295 	dhcp_status_t		*private_status;
3296 	size_t			reply_size;
3297 	int			error;
3298 
3299 	if (addr->ipadm_af == AF_INET6)
3300 		type |= DHCP_V6;
3301 
3302 	request = dhcp_ipc_alloc_request(type, addr->ipadm_ifname, NULL, 0,
3303 	    DHCP_TYPE_NONE);
3304 	if (request == NULL)
3305 		return (IPADM_NO_MEMORY);
3306 
3307 	error = dhcp_ipc_make_request(request, &reply, DHCP_IPC_WAIT_DEFAULT);
3308 	free(request);
3309 	if (error != 0) {
3310 		if (dhcperror != NULL)
3311 			*dhcperror = error;
3312 		return (error != DHCP_IPC_E_TIMEOUT ? IPADM_DHCP_IPC_ERROR
3313 		    : IPADM_DHCP_IPC_TIMEOUT);
3314 	}
3315 
3316 	error = reply->return_code;
3317 	if (error == DHCP_IPC_E_UNKIF) {
3318 		free(reply);
3319 		bzero(status, sizeof (dhcp_status_t));
3320 		return (IPADM_NOTFOUND);
3321 	}
3322 
3323 	private_status = dhcp_ipc_get_data(reply, &reply_size, NULL);
3324 	if (reply_size < DHCP_STATUS_VER1_SIZE) {
3325 		free(reply);
3326 		return (IPADM_DHCP_IPC_ERROR);
3327 	}
3328 
3329 	/*
3330 	 * Copy the status out of the memory allocated by this function into
3331 	 * memory owned by the caller.
3332 	 */
3333 	*status = *private_status;
3334 	free(reply);
3335 	return (IPADM_SUCCESS);
3336 }
3337 
3338 /*
3339  * Returns the IP addresses of the specified interface in both the
3340  * active and the persistent configuration. If no
3341  * interface is specified, it returns all non-zero IP addresses
3342  * configured on all interfaces in active and persistent
3343  * configurations.
3344  * `addrinfo' will contain addresses that are
3345  * (1) in both active and persistent configuration (created persistently)
3346  * (2) only in active configuration (created temporarily)
3347  * (3) only in persistent configuration (disabled addresses)
3348  *
3349  * Address list that is returned by this function must be freed
3350  * using the ipadm_freeaddr_info() function.
3351  */
3352 ipadm_status_t
3353 ipadm_addr_info(ipadm_handle_t iph, const char *ifname,
3354     ipadm_addr_info_t **addrinfo, uint32_t flags, int64_t lifc_flags)
3355 {
3356 	ifspec_t	ifsp;
3357 
3358 	if (addrinfo == NULL || iph == NULL)
3359 		return (IPADM_INVALID_ARG);
3360 	if (ifname != NULL &&
3361 	    (!ifparse_ifspec(ifname, &ifsp) || ifsp.ifsp_lunvalid)) {
3362 		return (IPADM_INVALID_ARG);
3363 	}
3364 	return (i_ipadm_get_all_addr_info(iph, ifname, addrinfo,
3365 	    flags, lifc_flags));
3366 }
3367 
3368 /*
3369  * Frees the structure allocated by ipadm_addr_info().
3370  */
3371 void
3372 ipadm_free_addr_info(ipadm_addr_info_t *ainfo)
3373 {
3374 	freeifaddrs((struct ifaddrs *)ainfo);
3375 }
3376 
3377 /*
3378  * Makes a door call to ipmgmtd to update its `aobjmap' with the address
3379  * object in `ipaddr'. This door call also can update the persistent DB to
3380  * remember address object to be recreated on next reboot or on an
3381  * ipadm_enable_addr()/ipadm_enable_if() call.
3382  */
3383 ipadm_status_t
3384 i_ipadm_addr_persist(ipadm_handle_t iph, const ipadm_addrobj_t ipaddr,
3385     boolean_t default_prefixlen, uint32_t flags, const char *propname)
3386 {
3387 	char			*aname = ipaddr->ipadm_aobjname;
3388 	nvlist_t		*nvl;
3389 	int			err = 0;
3390 	ipadm_status_t		status;
3391 	uint_t			pflags = 0;
3392 
3393 	/*
3394 	 * Construct the nvl to send to the door.
3395 	 */
3396 	if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
3397 		return (IPADM_NO_MEMORY);
3398 	if ((err = nvlist_add_string(nvl, IPADM_NVP_IFNAME,
3399 	    ipaddr->ipadm_ifname)) != 0 ||
3400 	    (err = nvlist_add_string(nvl, IPADM_NVP_AOBJNAME, aname)) != 0 ||
3401 	    (err = nvlist_add_int32(nvl, IPADM_NVP_LIFNUM,
3402 	    ipaddr->ipadm_lifnum)) != 0) {
3403 		status = ipadm_errno2status(err);
3404 		goto ret;
3405 	}
3406 	switch (ipaddr->ipadm_atype) {
3407 	case IPADM_ADDR_STATIC:
3408 		status = i_ipadm_add_ipaddr2nvl(nvl, ipaddr);
3409 		if (status != IPADM_SUCCESS)
3410 			goto ret;
3411 		if (flags & IPADM_OPT_UP)
3412 			err = nvlist_add_string(nvl, "up", "yes");
3413 		else
3414 			err = nvlist_add_string(nvl, "up", "no");
3415 		status = ipadm_errno2status(err);
3416 		break;
3417 	case IPADM_ADDR_DHCP:
3418 		status = i_ipadm_add_dhcp2nvl(nvl, ipaddr->ipadm_primary,
3419 		    ipaddr->ipadm_wait);
3420 		if (status != IPADM_SUCCESS)
3421 			goto ret;
3422 
3423 		/*
3424 		 * For purposes of updating the ipmgmtd cached representation of
3425 		 * reqhost (ipmgmt_am_reqhost), include a value here in `nvl',
3426 		 * but the value is actually fully persisted as a separate
3427 		 * i_ipadm_persist_propval below.
3428 		 */
3429 		err = nvlist_add_string(nvl, IPADM_NVP_REQHOST,
3430 		    ipaddr->ipadm_reqhost);
3431 		status = ipadm_errno2status(err);
3432 		break;
3433 	case IPADM_ADDR_IPV6_ADDRCONF:
3434 		status = i_ipadm_add_intfid2nvl(nvl, ipaddr);
3435 		break;
3436 	}
3437 	if (status != IPADM_SUCCESS)
3438 		goto ret;
3439 
3440 	if (iph->iph_flags & IPH_INIT) {
3441 		/*
3442 		 * IPMGMT_INIT tells the ipmgmtd to set both IPMGMT_ACTIVE and
3443 		 * IPMGMT_PERSIST on the address object in its `aobjmap'.
3444 		 * For the callers ipadm_enable_if() and ipadm_enable_addr(),
3445 		 * IPADM_OPT_PERSIST is not set in their flags. They send
3446 		 * IPH_INIT in iph_flags, so that the address object will be
3447 		 * set as both IPMGMT_ACTIVE and IPMGMT_PERSIST.
3448 		 */
3449 		pflags |= IPMGMT_INIT;
3450 	} else {
3451 		if (flags & IPADM_OPT_ACTIVE)
3452 			pflags |= IPMGMT_ACTIVE;
3453 		if (flags & IPADM_OPT_PERSIST)
3454 			pflags |= IPMGMT_PERSIST;
3455 		if (flags & IPADM_OPT_SET_PROPS)
3456 			pflags |= IPMGMT_PROPS_ONLY;
3457 	}
3458 	status = i_ipadm_addr_persist_nvl(iph, nvl, pflags);
3459 
3460 	if (flags & IPADM_OPT_SET_PROPS) {
3461 		/*
3462 		 * Set PERSIST per IPADM_OPT_PROPS_PERSIST, and then un-set the
3463 		 * SET_PROPS bits.
3464 		 */
3465 		flags |= IPADM_OPT_ACTIVE;
3466 		if (flags & IPADM_OPT_PERSIST_PROPS)
3467 			flags |= IPADM_OPT_PERSIST;
3468 		else
3469 			flags &= ~IPADM_OPT_PERSIST;
3470 		flags &= ~(IPADM_OPT_SET_PROPS | IPADM_OPT_PERSIST_PROPS);
3471 	}
3472 
3473 	if (status == IPADM_SUCCESS && (flags & IPADM_OPT_PERSIST)) {
3474 		char		pbuf[MAXPROPVALLEN], *pval = NULL;
3475 		ipadm_prop_desc_t	*pdp = NULL;
3476 
3477 		/*
3478 		 * addprop properties are stored on separate lines in the DB and
3479 		 * not along with the address itself. Call the function that
3480 		 * persists address properties.
3481 		 */
3482 
3483 		switch (ipaddr->ipadm_atype) {
3484 		case IPADM_ADDR_STATIC:
3485 			if (!default_prefixlen && (propname == NULL ||
3486 			    strcmp(propname, IPADM_NVP_PREFIXLEN) == 0)) {
3487 				pdp = i_ipadm_get_addrprop_desc(
3488 				    IPADM_NVP_PREFIXLEN);
3489 				(void) snprintf(pbuf, sizeof (pbuf), "%u",
3490 				    ipaddr->ipadm_static_prefixlen);
3491 				pval = pbuf;
3492 			}
3493 			break;
3494 		case IPADM_ADDR_DHCP:
3495 			if (propname == NULL ||
3496 			    strcmp(propname, IPADM_NVP_REQHOST) == 0) {
3497 				pdp = i_ipadm_get_addrprop_desc(
3498 				    IPADM_NVP_REQHOST);
3499 				pval = ipaddr->ipadm_reqhost;
3500 			}
3501 			break;
3502 		default:
3503 			break;
3504 		}
3505 
3506 		if (pval != NULL) {
3507 			assert(pdp != NULL);
3508 			status = i_ipadm_persist_propval(iph, pdp, pval,
3509 			    ipaddr, flags);
3510 		}
3511 	}
3512 
3513 ret:
3514 	nvlist_free(nvl);
3515 	return (status);
3516 }
3517 
3518 /*
3519  * Makes the door call to ipmgmtd to store the address object in the
3520  * nvlist `nvl'.
3521  */
3522 static ipadm_status_t
3523 i_ipadm_addr_persist_nvl(ipadm_handle_t iph, nvlist_t *nvl, uint32_t flags)
3524 {
3525 	char			*buf = NULL, *nvlbuf = NULL;
3526 	size_t			nvlsize, bufsize;
3527 	ipmgmt_setaddr_arg_t	*sargp;
3528 	int			err;
3529 
3530 	err = nvlist_pack(nvl, &nvlbuf, &nvlsize, NV_ENCODE_NATIVE, 0);
3531 	if (err != 0)
3532 		return (ipadm_errno2status(err));
3533 	bufsize = sizeof (*sargp) + nvlsize;
3534 	buf = calloc(1, bufsize);
3535 	sargp = (void *)buf;
3536 	sargp->ia_cmd = IPMGMT_CMD_SETADDR;
3537 	sargp->ia_flags = flags;
3538 	sargp->ia_nvlsize = nvlsize;
3539 	(void) bcopy(nvlbuf, buf + sizeof (*sargp), nvlsize);
3540 	err = ipadm_door_call(iph, buf, bufsize, NULL, 0, B_FALSE);
3541 	free(buf);
3542 	free(nvlbuf);
3543 	return (ipadm_errno2status(err));
3544 }
3545 
3546 /*
3547  * Makes a door call to ipmgmtd to remove the address object in `ipaddr'
3548  * from its `aobjmap'. This door call also removes the address object and all
3549  * its properties from the persistent DB if IPADM_OPT_PERSIST is set in
3550  * `flags', so that the object will not be recreated on next reboot or on an
3551  * ipadm_enable_addr()/ipadm_enable_if() call.
3552  */
3553 ipadm_status_t
3554 i_ipadm_delete_addrobj(ipadm_handle_t iph, const ipadm_addrobj_t ipaddr,
3555     uint32_t flags)
3556 {
3557 	ipmgmt_addr_arg_t	arg;
3558 	int			err;
3559 
3560 	arg.ia_cmd = IPMGMT_CMD_RESETADDR;
3561 	arg.ia_flags = 0;
3562 	if (flags & IPADM_OPT_ACTIVE)
3563 		arg.ia_flags |= IPMGMT_ACTIVE;
3564 	if (flags & IPADM_OPT_PERSIST)
3565 		arg.ia_flags |= IPMGMT_PERSIST;
3566 	(void) strlcpy(arg.ia_aobjname, ipaddr->ipadm_aobjname,
3567 	    sizeof (arg.ia_aobjname));
3568 	arg.ia_lnum = ipaddr->ipadm_lifnum;
3569 	err = ipadm_door_call(iph, &arg, sizeof (arg), NULL, 0, B_FALSE);
3570 	return (ipadm_errno2status(err));
3571 }
3572 
3573 /*
3574  * Checks if the caller is authorized for the up/down operation.
3575  * Retrieves the address object corresponding to `aobjname' from ipmgmtd
3576  * and retrieves the address flags for that object from kernel.
3577  * The arguments `ipaddr' and `ifflags' must be allocated by the caller.
3578  */
3579 static ipadm_status_t
3580 i_ipadm_updown_common(ipadm_handle_t iph, const char *aobjname,
3581     ipadm_addrobj_t ipaddr, uint32_t ipadm_flags, uint64_t *ifflags)
3582 {
3583 	ipadm_status_t	status;
3584 	char		lifname[LIFNAMSIZ];
3585 
3586 	/* check for solaris.network.interface.config authorization */
3587 	if (!ipadm_check_auth())
3588 		return (IPADM_EAUTH);
3589 
3590 	/* validate input */
3591 	if (aobjname == NULL || strlcpy(ipaddr->ipadm_aobjname, aobjname,
3592 	    IPADM_AOBJSIZ) >= IPADM_AOBJSIZ) {
3593 		return (IPADM_INVALID_ARG);
3594 	}
3595 
3596 	/* Retrieve the address object information. */
3597 	status = i_ipadm_get_addrobj(iph, ipaddr);
3598 	if (status != IPADM_SUCCESS)
3599 		return (status);
3600 
3601 	if (!(ipaddr->ipadm_flags & IPMGMT_ACTIVE))
3602 		return (IPADM_OP_DISABLE_OBJ);
3603 
3604 	if ((ipadm_flags & IPADM_OPT_PERSIST) &&
3605 	    !(ipaddr->ipadm_flags & IPMGMT_PERSIST))
3606 		return (IPADM_TEMPORARY_OBJ);
3607 
3608 	if (ipaddr->ipadm_atype == IPADM_ADDR_IPV6_ADDRCONF ||
3609 	    (ipaddr->ipadm_atype == IPADM_ADDR_DHCP &&
3610 	    (ipadm_flags & IPADM_OPT_PERSIST)))
3611 		return (IPADM_NOTSUP);
3612 
3613 	i_ipadm_addrobj2lifname(ipaddr, lifname, sizeof (lifname));
3614 
3615 	return (i_ipadm_get_flags(iph, lifname, ipaddr->ipadm_af, ifflags));
3616 }
3617 
3618 /*
3619  * Marks the address in the address object `aobjname' up. This operation is
3620  * not supported for an address object of type IPADM_ADDR_IPV6_ADDRCONF.
3621  * For an address object of type IPADM_ADDR_DHCP, this operation can
3622  * only be temporary and no updates will be made to the persistent DB.
3623  */
3624 ipadm_status_t
3625 ipadm_up_addr(ipadm_handle_t iph, const char *aobjname, uint32_t ipadm_flags)
3626 {
3627 	struct ipadm_addrobj_s ipaddr;
3628 	ipadm_status_t	status;
3629 	uint64_t	flags;
3630 	char		lifname[LIFNAMSIZ];
3631 
3632 	status = i_ipadm_updown_common(iph, aobjname, &ipaddr, ipadm_flags,
3633 	    &flags);
3634 	if (status != IPADM_SUCCESS)
3635 		return (status);
3636 	if (flags & IFF_UP)
3637 		goto persist;
3638 	/*
3639 	 * If the address is already a duplicate, then refresh-addr
3640 	 * should be used to mark it up.
3641 	 */
3642 	if (flags & IFF_DUPLICATE)
3643 		return (IPADM_DAD_FOUND);
3644 
3645 	i_ipadm_addrobj2lifname(&ipaddr, lifname, sizeof (lifname));
3646 	status = i_ipadm_set_flags(iph, lifname, ipaddr.ipadm_af, IFF_UP, 0);
3647 	if (status != IPADM_SUCCESS)
3648 		return (status);
3649 
3650 persist:
3651 	/* Update persistent DB. */
3652 	if (ipadm_flags & IPADM_OPT_PERSIST) {
3653 		status = i_ipadm_persist_propval(iph, &up_addrprop,
3654 		    "yes", &ipaddr, 0);
3655 	}
3656 
3657 	return (status);
3658 }
3659 
3660 /*
3661  * Marks the address in the address object `aobjname' down. This operation is
3662  * not supported for an address object of type IPADM_ADDR_IPV6_ADDRCONF.
3663  * For an address object of type IPADM_ADDR_DHCP, this operation can
3664  * only be temporary and no updates will be made to the persistent DB.
3665  */
3666 ipadm_status_t
3667 ipadm_down_addr(ipadm_handle_t iph, const char *aobjname, uint32_t ipadm_flags)
3668 {
3669 	struct ipadm_addrobj_s ipaddr;
3670 	ipadm_status_t	status;
3671 	struct lifreq	lifr;
3672 	uint64_t	flags;
3673 
3674 	status = i_ipadm_updown_common(iph, aobjname, &ipaddr, ipadm_flags,
3675 	    &flags);
3676 	if (status != IPADM_SUCCESS)
3677 		return (status);
3678 	i_ipadm_addrobj2lifname(&ipaddr, lifr.lifr_name,
3679 	    sizeof (lifr.lifr_name));
3680 	if (flags & IFF_UP) {
3681 		status = i_ipadm_set_flags(iph, lifr.lifr_name,
3682 		    ipaddr.ipadm_af, 0, IFF_UP);
3683 		if (status != IPADM_SUCCESS)
3684 			return (status);
3685 	} else if (flags & IFF_DUPLICATE) {
3686 		/*
3687 		 * Clear the IFF_DUPLICATE flag.
3688 		 */
3689 		if (ioctl(iph->iph_sock, SIOCGLIFADDR, &lifr) < 0)
3690 			return (ipadm_errno2status(errno));
3691 		if (ioctl(iph->iph_sock, SIOCSLIFADDR, &lifr) < 0)
3692 			return (ipadm_errno2status(errno));
3693 	}
3694 
3695 	/* Update persistent DB */
3696 	if (ipadm_flags & IPADM_OPT_PERSIST) {
3697 		status = i_ipadm_persist_propval(iph, &up_addrprop,
3698 		    "no", &ipaddr, 0);
3699 	}
3700 
3701 	return (status);
3702 }
3703 
3704 /*
3705  * Refreshes the address in the address object `aobjname'. If the address object
3706  * is of type IPADM_ADDR_STATIC, DAD is re-initiated on the address. If
3707  * `ipadm_flags' has IPADM_OPT_INFORM set, a DHCP_INFORM message is sent to the
3708  * dhcpagent for this static address. If the address object is of type
3709  * IPADM_ADDR_DHCP, a DHCP_EXTEND message is sent to the dhcpagent.
3710  * If a dhcp address has not yet been acquired, a DHCP_START is sent to the
3711  * dhcpagent. This operation is not supported for an address object of
3712  * type IPADM_ADDR_IPV6_ADDRCONF.
3713  */
3714 ipadm_status_t
3715 ipadm_refresh_addr(ipadm_handle_t iph, const char *aobjname,
3716     uint32_t ipadm_flags)
3717 {
3718 	ipadm_status_t		status = IPADM_SUCCESS;
3719 	uint64_t		flags;
3720 	struct ipadm_addrobj_s	ipaddr;
3721 	sa_family_t		af;
3722 	char			lifname[LIFNAMSIZ];
3723 	boolean_t		inform =
3724 	    ((ipadm_flags & IPADM_OPT_INFORM) != 0);
3725 
3726 	/* check for solaris.network.interface.config authorization */
3727 	if (!ipadm_check_auth())
3728 		return (IPADM_EAUTH);
3729 
3730 	bzero(&ipaddr, sizeof (ipaddr));
3731 	/* validate input */
3732 	if (aobjname == NULL || strlcpy(ipaddr.ipadm_aobjname, aobjname,
3733 	    IPADM_AOBJSIZ) >= IPADM_AOBJSIZ) {
3734 		return (IPADM_INVALID_ARG);
3735 	}
3736 
3737 	/* Retrieve the address object information. */
3738 	status = i_ipadm_get_addrobj(iph, &ipaddr);
3739 	if (status != IPADM_SUCCESS)
3740 		return (status);
3741 
3742 	if (!(ipaddr.ipadm_flags & IPMGMT_ACTIVE))
3743 		return (IPADM_OP_DISABLE_OBJ);
3744 
3745 	if (i_ipadm_is_vni(ipaddr.ipadm_ifname))
3746 		return (IPADM_NOTSUP);
3747 	if (inform && ipaddr.ipadm_atype != IPADM_ADDR_STATIC)
3748 		return (IPADM_INVALID_ARG);
3749 	af = ipaddr.ipadm_af;
3750 	if (ipaddr.ipadm_atype == IPADM_ADDR_STATIC) {
3751 		i_ipadm_addrobj2lifname(&ipaddr, lifname, sizeof (lifname));
3752 		status = i_ipadm_get_flags(iph, lifname, af, &flags);
3753 		if (status != IPADM_SUCCESS)
3754 			return (status);
3755 		if (inform) {
3756 			if (dhcp_start_agent(DHCP_IPC_MAX_WAIT) == -1)
3757 				return (IPADM_DHCP_START_ERROR);
3758 
3759 			ipaddr.ipadm_wait = IPADM_DHCP_WAIT_DEFAULT;
3760 			return (i_ipadm_op_dhcp(&ipaddr, DHCP_INFORM, NULL));
3761 		}
3762 		if (!(flags & IFF_DUPLICATE))
3763 			return (IPADM_SUCCESS);
3764 		status = i_ipadm_set_flags(iph, lifname, af, IFF_UP, 0);
3765 	} else if (ipaddr.ipadm_atype == IPADM_ADDR_DHCP) {
3766 		status = i_ipadm_refresh_dhcp(&ipaddr);
3767 	} else {
3768 		status = IPADM_NOTSUP;
3769 	}
3770 	return (status);
3771 }
3772 
3773 /*
3774  * This is called from ipadm_refresh_addr() and i_ipadm_set_reqhost() to
3775  * send a DHCP_EXTEND message and possibly a DHCP_START message
3776  * to the dhcpagent.
3777  */
3778 static ipadm_status_t
3779 i_ipadm_refresh_dhcp(ipadm_addrobj_t ipaddr)
3780 {
3781 	ipadm_status_t		status;
3782 	int			dherr;
3783 
3784 	status = i_ipadm_op_dhcp(ipaddr, DHCP_EXTEND, &dherr);
3785 	/*
3786 	 * Restart the dhcp address negotiation with server if no
3787 	 * address has been acquired yet.
3788 	 */
3789 	if (status != IPADM_SUCCESS && dherr == DHCP_IPC_E_OUTSTATE) {
3790 		ipaddr->ipadm_wait = IPADM_DHCP_WAIT_DEFAULT;
3791 		status = i_ipadm_op_dhcp(ipaddr, DHCP_START, NULL);
3792 	}
3793 
3794 	return (status);
3795 }
3796 
3797 /*
3798  * This is called from ipadm_create_addr() to validate the address parameters.
3799  * It does the following steps:
3800  * 1. Validates the interface name.
3801  * 2. Verifies that the interface is not an IPMP meta-interface or an
3802  *	underlying interface.
3803  * 3. In case of a persistent operation, verifies that the interface
3804  *	is persistent. Returns error if interface is not enabled but
3805  *	is in persistent config.
3806  * 4. Verifies that the destination address is not set or the address type is
3807  *	not DHCP or ADDRCONF when the interface is a loopback interface.
3808  * 5. Verifies that the address type is not DHCP or ADDRCONF when the interface
3809  *	has IFF_VRRP interface flag set.
3810  */
3811 static ipadm_status_t
3812 i_ipadm_validate_create_addr(ipadm_handle_t iph, ipadm_addrobj_t ipaddr,
3813     uint32_t flags)
3814 {
3815 	sa_family_t		af;
3816 	sa_family_t		other_af;
3817 	char			*ifname;
3818 	ipadm_status_t		status;
3819 	boolean_t		legacy = (iph->iph_flags & IPH_LEGACY);
3820 	boolean_t		islo, isvni;
3821 	uint64_t		ifflags = 0;
3822 	boolean_t		p_exists;
3823 	boolean_t		af_exists, other_af_exists, a_exists;
3824 
3825 	if (ipaddr == NULL || flags == 0 || flags == IPADM_OPT_PERSIST ||
3826 	    (flags & ~(IPADM_COMMON_OPT_MASK|IPADM_OPT_UP|IPADM_OPT_V46))) {
3827 		return (IPADM_INVALID_ARG);
3828 	}
3829 
3830 	if (ipaddr->ipadm_af == AF_UNSPEC)
3831 		return (IPADM_BAD_ADDR);
3832 
3833 	if (!legacy && ipaddr->ipadm_lifnum != 0)
3834 		return (IPADM_INVALID_ARG);
3835 
3836 	if (legacy && ipaddr->ipadm_atype != IPADM_ADDR_STATIC)
3837 		return (IPADM_NOTSUP);
3838 
3839 	ifname = ipaddr->ipadm_ifname;
3840 
3841 	/*
3842 	 * Do not go further when we are under ipmp.
3843 	 * The interface is plumbed up and we are going to add
3844 	 * NOFAILOVER address to make in.mpathd happy.
3845 	 */
3846 	if (i_ipadm_is_under_ipmp(iph, ifname))
3847 		return (IPADM_SUCCESS);
3848 
3849 	af = ipaddr->ipadm_af;
3850 	af_exists = ipadm_if_enabled(iph, ifname, af);
3851 	/*
3852 	 * For legacy case, interfaces are not implicitly plumbed. We need to
3853 	 * check if the interface exists in the active configuration.
3854 	 */
3855 	if (legacy && !af_exists)
3856 		return (IPADM_ENXIO);
3857 
3858 	other_af = (af == AF_INET ? AF_INET6 : AF_INET);
3859 	other_af_exists = ipadm_if_enabled(iph, ifname, other_af);
3860 	/*
3861 	 * Check if one of the v4 or the v6 interfaces exists in the
3862 	 * active configuration. An interface is considered disabled only
3863 	 * if both v4 and v6 are not active.
3864 	 */
3865 	a_exists = (af_exists || other_af_exists);
3866 
3867 	/* Check if interface exists in the persistent configuration. */
3868 	status = i_ipadm_if_pexists(iph, ifname, af, &p_exists);
3869 	if (status != IPADM_SUCCESS)
3870 		return (status);
3871 
3872 	if (!a_exists && p_exists)
3873 		return (IPADM_OP_DISABLE_OBJ);
3874 
3875 	if (af_exists) {
3876 		status = i_ipadm_get_flags(iph, ifname, af, &ifflags);
3877 		if (status != IPADM_SUCCESS)
3878 			return (status);
3879 	}
3880 
3881 	/* Perform validation steps (4) and (5) */
3882 	islo = i_ipadm_is_loopback(ifname);
3883 	isvni = i_ipadm_is_vni(ifname);
3884 	switch (ipaddr->ipadm_atype) {
3885 	case IPADM_ADDR_STATIC:
3886 		if ((islo || isvni) && ipaddr->ipadm_static_dname[0] != '\0')
3887 			return (IPADM_INVALID_ARG);
3888 		/* Check for a valid src address */
3889 		if (!legacy && sockaddrunspec(
3890 		    (struct sockaddr *)&ipaddr->ipadm_static_addr))
3891 			return (IPADM_BAD_ADDR);
3892 		break;
3893 	case IPADM_ADDR_DHCP:
3894 		if (islo || (ifflags & IFF_VRRP))
3895 			return (IPADM_NOTSUP);
3896 		break;
3897 	case IPADM_ADDR_IPV6_ADDRCONF:
3898 		if (islo || (ifflags & IFF_VRRP) ||
3899 		    i_ipadm_is_6to4(iph, ifname)) {
3900 			return (IPADM_NOTSUP);
3901 		}
3902 		break;
3903 	default:
3904 		return (IPADM_INVALID_ARG);
3905 	}
3906 
3907 	return (IPADM_SUCCESS);
3908 }
3909 
3910 ipadm_status_t
3911 i_ipadm_merge_addrprops_from_nvl(nvlist_t *invl, nvlist_t *onvl,
3912     const char *aobjname)
3913 {
3914 	const char * const	ADDRPROPS[] =
3915 	    { IPADM_NVP_PREFIXLEN, IPADM_NVP_REQHOST };
3916 	const size_t		ADDRPROPSLEN =
3917 	    sizeof (ADDRPROPS) / sizeof (*ADDRPROPS);
3918 	nvpair_t	*nvp, *propnvp;
3919 	nvlist_t	*tnvl;
3920 	char		*aname;
3921 	const char	*propname;
3922 	size_t		i;
3923 	int		err;
3924 
3925 	for (i = 0; i < ADDRPROPSLEN; ++i) {
3926 		propname = ADDRPROPS[i];
3927 
3928 		for (nvp = nvlist_next_nvpair(invl, NULL); nvp != NULL;
3929 		    nvp = nvlist_next_nvpair(invl, nvp)) {
3930 			if (nvpair_value_nvlist(nvp, &tnvl) == 0 &&
3931 			    nvlist_exists(tnvl, propname) &&
3932 			    nvlist_lookup_string(tnvl, IPADM_NVP_AOBJNAME,
3933 			    &aname) == 0 && strcmp(aname, aobjname) == 0) {
3934 
3935 				/*
3936 				 * property named `propname' exists for given
3937 				 * aobj
3938 				 */
3939 				(void) nvlist_lookup_nvpair(tnvl, propname,
3940 				    &propnvp);
3941 				err = nvlist_add_nvpair(onvl, propnvp);
3942 				if (err == 0) {
3943 					err = nvlist_remove(invl,
3944 					    nvpair_name(nvp), nvpair_type(nvp));
3945 				}
3946 				if (err != 0)
3947 					return (ipadm_errno2status(err));
3948 				break;
3949 			}
3950 		}
3951 	}
3952 	return (IPADM_SUCCESS);
3953 }
3954 
3955 /*
3956  * Re-enables the address object `aobjname' based on the saved
3957  * configuration for `aobjname'.
3958  */
3959 ipadm_status_t
3960 ipadm_enable_addr(ipadm_handle_t iph, const char *aobjname, uint32_t flags)
3961 {
3962 	nvlist_t	*addrnvl, *nvl;
3963 	nvpair_t	*nvp;
3964 	ipadm_status_t	status;
3965 	struct ipadm_addrobj_s ipaddr;
3966 
3967 	/* check for solaris.network.interface.config authorization */
3968 	if (!ipadm_check_auth())
3969 		return (IPADM_EAUTH);
3970 
3971 	/* validate input */
3972 	if (flags & IPADM_OPT_PERSIST)
3973 		return (IPADM_NOTSUP);
3974 	if (aobjname == NULL || strlcpy(ipaddr.ipadm_aobjname, aobjname,
3975 	    IPADM_AOBJSIZ) >= IPADM_AOBJSIZ) {
3976 		return (IPADM_INVALID_ARG);
3977 	}
3978 
3979 	/* Retrieve the address object information. */
3980 	status = i_ipadm_get_addrobj(iph, &ipaddr);
3981 	if (status != IPADM_SUCCESS)
3982 		return (status);
3983 	if (ipaddr.ipadm_flags & IPMGMT_ACTIVE)
3984 		return (IPADM_ADDROBJ_EXISTS);
3985 
3986 	status = i_ipadm_get_db_addr(iph, NULL, aobjname, &addrnvl);
3987 	if (status != IPADM_SUCCESS)
3988 		return (status);
3989 
3990 	assert(addrnvl != NULL);
3991 
3992 	for (nvp = nvlist_next_nvpair(addrnvl, NULL); nvp != NULL;
3993 	    nvp = nvlist_next_nvpair(addrnvl, nvp)) {
3994 		boolean_t set_init = B_FALSE;
3995 
3996 		if (nvpair_value_nvlist(nvp, &nvl) != 0)
3997 			continue;
3998 
3999 		if (nvlist_exists(nvl, IPADM_NVP_IPV4ADDR) ||
4000 		    nvlist_exists(nvl, IPADM_NVP_IPV6ADDR) ||
4001 		    nvlist_exists(nvl, IPADM_NVP_DHCP)) {
4002 			status = i_ipadm_merge_addrprops_from_nvl(addrnvl, nvl,
4003 			    aobjname);
4004 			if (status != IPADM_SUCCESS)
4005 				continue;
4006 		}
4007 
4008 		/*
4009 		 * ipadm_enable_addr() is never a persistent operation. We need
4010 		 * to set IPH_INIT because ipmgmtd daemon does not have to write
4011 		 * the address to the persistent db. The address is already
4012 		 * available in the persistent db and we are here to re-enable
4013 		 * the persistent configuration.
4014 		 *
4015 		 * But we need to make sure we're not accidentally clearing an
4016 		 * IPH_INIT flag that was already set when we were called.
4017 		 */
4018 		if ((iph->iph_flags & IPH_INIT) == 0) {
4019 			iph->iph_flags |= IPH_INIT;
4020 			set_init = B_TRUE;
4021 		}
4022 
4023 		status = i_ipadm_init_addrobj(iph, nvl);
4024 
4025 		if (set_init)
4026 			iph->iph_flags &= ~IPH_INIT;
4027 
4028 		if (status != IPADM_SUCCESS)
4029 			break;
4030 	}
4031 
4032 	nvlist_free(addrnvl);
4033 	return (status);
4034 }
4035 
4036 /*
4037  * Disables the address object in `aobjname' from the active configuration.
4038  * Error code return values follow the model in ipadm_delete_addr().
4039  */
4040 ipadm_status_t
4041 ipadm_disable_addr(ipadm_handle_t iph, const char *aobjname, uint32_t flags)
4042 {
4043 	/* validate input */
4044 	if (flags & IPADM_OPT_PERSIST)
4045 		return (IPADM_NOTSUP);
4046 
4047 	return (ipadm_delete_addr(iph, aobjname, IPADM_OPT_ACTIVE));
4048 }
4049