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