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