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