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