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