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