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