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