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