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