xref: /titanic_51/usr/src/lib/libipadm/common/ipadm_if.c (revision fcdeb91bbce674703e2d1423c81e7155f4f13089)
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 2010 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #include <errno.h>
27 #include <sys/sockio.h>
28 #include <string.h>
29 #include <assert.h>
30 #include <unistd.h>
31 #include <stropts.h>
32 #include <strings.h>
33 #include <libdlpi.h>
34 #include <libdllink.h>
35 #include <libinetutil.h>
36 #include <inet/ip.h>
37 #include <limits.h>
38 #include <zone.h>
39 #include <ipadm_ndpd.h>
40 #include "libipadm_impl.h"
41 
42 static ipadm_status_t	i_ipadm_slifname_arp(char *, uint64_t, int);
43 static ipadm_status_t	i_ipadm_slifname(ipadm_handle_t, char *, char *,
44 			    uint64_t, int, uint32_t);
45 static ipadm_status_t	i_ipadm_create_ipmp_peer(ipadm_handle_t, char *,
46 			    sa_family_t);
47 static ipadm_status_t	i_ipadm_persist_if(ipadm_handle_t, const char *,
48 			    sa_family_t);
49 
50 /*
51  * Returns B_FALSE if the interface in `ifname' has at least one address that is
52  * IFF_UP in the addresses in `ifa'.
53  */
54 static boolean_t
55 i_ipadm_is_if_down(char *ifname, struct ifaddrs *ifa)
56 {
57 	struct ifaddrs	*ifap;
58 	char		cifname[LIFNAMSIZ];
59 	char		*sep;
60 
61 	for (ifap = ifa; ifap != NULL; ifap = ifap->ifa_next) {
62 		(void) strlcpy(cifname, ifap->ifa_name, sizeof (cifname));
63 		if ((sep = strrchr(cifname, IPADM_LOGICAL_SEP)) != NULL)
64 			*sep = '\0';
65 		/*
66 		 * If this condition is true, there is at least one
67 		 * address that is IFF_UP. So, we need to return B_FALSE.
68 		 */
69 		if (strcmp(cifname, ifname) == 0 &&
70 		    (ifap->ifa_flags & IFF_UP)) {
71 			return (B_FALSE);
72 		}
73 	}
74 	/* We did not find any IFF_UP addresses. */
75 	return (B_TRUE);
76 }
77 
78 /*
79  * Retrieves the information for the interface `ifname' from active
80  * config if `ifname' is specified and returns the result in the list `if_info'.
81  * Otherwise, it retrieves the information for all the interfaces in
82  * the active config and returns the result in the list `if_info'.
83  */
84 static ipadm_status_t
85 i_ipadm_active_if_info(ipadm_handle_t iph, const char *ifname,
86     ipadm_if_info_t **if_info, int64_t lifc_flags)
87 {
88 	struct lifreq	*buf;
89 	struct lifreq	*lifrp;
90 	struct lifreq	lifrl;
91 	ipadm_if_info_t	*last = NULL;
92 	ipadm_if_info_t	*ifp;
93 	int		s;
94 	int		n;
95 	int		numifs;
96 	ipadm_status_t	status;
97 
98 	*if_info = NULL;
99 	/*
100 	 * Get information for all interfaces.
101 	 */
102 	if (getallifs(iph->iph_sock, 0, &buf, &numifs, lifc_flags) != 0)
103 		return (ipadm_errno2status(errno));
104 
105 	lifrp = buf;
106 	for (n = 0; n < numifs; n++, lifrp++) {
107 		/* Skip interfaces with logical num != 0 */
108 		if (i_ipadm_get_lnum(lifrp->lifr_name) != 0)
109 			continue;
110 		/*
111 		 * Skip the current interface if a specific `ifname' has
112 		 * been requested and current interface does not match
113 		 * `ifname'.
114 		 */
115 		if (ifname != NULL && strcmp(lifrp->lifr_name, ifname) != 0)
116 			continue;
117 		/*
118 		 * Check if the interface already exists in our list.
119 		 * If it already exists, we need to update its flags.
120 		 */
121 		for (ifp = *if_info; ifp != NULL; ifp = ifp->ifi_next) {
122 			if (strcmp(lifrp->lifr_name, ifp->ifi_name) == 0)
123 				break;
124 		}
125 		if (ifp == NULL) {
126 			ifp = calloc(1, sizeof (ipadm_if_info_t));
127 			if (ifp == NULL) {
128 				status = ipadm_errno2status(errno);
129 				goto fail;
130 			}
131 			(void) strlcpy(ifp->ifi_name, lifrp->lifr_name,
132 			    sizeof (ifp->ifi_name));
133 			/* Update the `ifi_next' pointer for this new node */
134 			if (*if_info == NULL)
135 				*if_info = ifp;
136 			else
137 				last->ifi_next = ifp;
138 			last = ifp;
139 		}
140 
141 		/*
142 		 * Retrieve the flags for the interface by doing a
143 		 * SIOCGLIFFLAGS to populate the `ifi_cflags' field.
144 		 */
145 		(void) strlcpy(lifrl.lifr_name,
146 		    lifrp->lifr_name, sizeof (lifrl.lifr_name));
147 		s = (lifrp->lifr_addr.ss_family == AF_INET) ?
148 		    iph->iph_sock : iph->iph_sock6;
149 		if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifrl) < 0)
150 			continue;
151 		if (lifrl.lifr_flags & IFF_BROADCAST)
152 			ifp->ifi_cflags |= IFIF_BROADCAST;
153 		if (lifrl.lifr_flags & IFF_MULTICAST)
154 			ifp->ifi_cflags |= IFIF_MULTICAST;
155 		if (lifrl.lifr_flags & IFF_POINTOPOINT)
156 			ifp->ifi_cflags |= IFIF_POINTOPOINT;
157 		if (lifrl.lifr_flags & IFF_VIRTUAL)
158 			ifp->ifi_cflags |= IFIF_VIRTUAL;
159 		if (lifrl.lifr_flags & IFF_IPMP)
160 			ifp->ifi_cflags |= IFIF_IPMP;
161 		if (lifrl.lifr_flags & IFF_STANDBY)
162 			ifp->ifi_cflags |= IFIF_STANDBY;
163 		if (lifrl.lifr_flags & IFF_INACTIVE)
164 			ifp->ifi_cflags |= IFIF_INACTIVE;
165 		if (lifrl.lifr_flags & IFF_VRRP)
166 			ifp->ifi_cflags |= IFIF_VRRP;
167 		if (lifrl.lifr_flags & IFF_NOACCEPT)
168 			ifp->ifi_cflags |= IFIF_NOACCEPT;
169 		if (lifrl.lifr_flags & IFF_IPV4)
170 			ifp->ifi_cflags |= IFIF_IPV4;
171 		if (lifrl.lifr_flags & IFF_IPV6)
172 			ifp->ifi_cflags |= IFIF_IPV6;
173 	}
174 	free(buf);
175 	return (IPADM_SUCCESS);
176 fail:
177 	free(buf);
178 	ipadm_free_if_info(*if_info);
179 	*if_info = NULL;
180 	return (status);
181 }
182 
183 /*
184  * Returns the interface information for `ifname' in `if_info' from persistent
185  * config if `ifname' is non-null. Otherwise, it returns all the interfaces
186  * from persistent config in `if_info'.
187  */
188 static ipadm_status_t
189 i_ipadm_persist_if_info(ipadm_handle_t iph, const char *ifname,
190     ipadm_if_info_t **if_info)
191 {
192 	ipadm_status_t		status = IPADM_SUCCESS;
193 	ipmgmt_getif_arg_t	getif;
194 	ipmgmt_getif_rval_t	*rvalp;
195 	ipadm_if_info_t		*ifp, *curr, *prev = NULL;
196 	int			i = 0, err = 0;
197 
198 	bzero(&getif, sizeof (getif));
199 	if (ifname != NULL)
200 		(void) strlcpy(getif.ia_ifname, ifname, LIFNAMSIZ);
201 	getif.ia_cmd = IPMGMT_CMD_GETIF;
202 
203 	*if_info = NULL;
204 
205 	if ((rvalp = malloc(sizeof (ipmgmt_getif_rval_t))) == NULL)
206 		return (ipadm_errno2status(errno));
207 	err = ipadm_door_call(iph, &getif, sizeof (getif), (void **)&rvalp,
208 	    sizeof (*rvalp), B_TRUE);
209 	if (err == ENOENT) {
210 		free(rvalp);
211 		if (ifname != NULL)
212 			return (ipadm_errno2status(err));
213 		return (IPADM_SUCCESS);
214 	} else if (err != 0) {
215 		free(rvalp);
216 		return (ipadm_errno2status(err));
217 	}
218 
219 	ifp = rvalp->ir_ifinfo;
220 	for (i = 0; i < rvalp->ir_ifcnt; i++) {
221 		ifp = rvalp->ir_ifinfo + i;
222 		if ((curr = malloc(sizeof (*curr))) == NULL) {
223 			status = ipadm_errno2status(errno);
224 			ipadm_free_if_info(prev);
225 			break;
226 		}
227 		(void) bcopy(ifp, curr, sizeof (*curr));
228 		curr->ifi_next = prev;
229 		prev = curr;
230 	}
231 	*if_info = curr;
232 	free(rvalp);
233 	return (status);
234 }
235 
236 /*
237  * Collects information for `ifname' if one is specified from both
238  * active and persistent config in `if_info'. If no `ifname' is specified,
239  * this returns all the interfaces in active and persistent config in
240  * `if_info'.
241  */
242 ipadm_status_t
243 i_ipadm_get_all_if_info(ipadm_handle_t iph, const char *ifname,
244     ipadm_if_info_t **if_info, int64_t lifc_flags)
245 {
246 	ipadm_status_t	status;
247 	ipadm_if_info_t	*aifinfo = NULL;
248 	ipadm_if_info_t	*pifinfo = NULL;
249 	ipadm_if_info_t	*aifp;
250 	ipadm_if_info_t	*pifp;
251 	ipadm_if_info_t	*last = NULL;
252 	struct ifaddrs	*ifa;
253 	struct ifaddrs	*ifap;
254 
255 	/*
256 	 * Retrive the information for the requested `ifname' or all
257 	 * interfaces from active configuration.
258 	 */
259 retry:
260 	status = i_ipadm_active_if_info(iph, ifname, &aifinfo, lifc_flags);
261 	if (status != IPADM_SUCCESS)
262 		return (status);
263 	/* Get the interface state for each interface in `aifinfo'. */
264 	if (aifinfo != NULL) {
265 		/* We need all addresses to get the interface state */
266 		if (getallifaddrs(AF_UNSPEC, &ifa, (LIFC_NOXMIT|LIFC_TEMPORARY|
267 		    LIFC_ALLZONES|LIFC_UNDER_IPMP)) != 0) {
268 			status = ipadm_errno2status(errno);
269 			goto fail;
270 		}
271 		for (aifp = aifinfo; aifp != NULL; aifp = aifp->ifi_next) {
272 			/*
273 			 * Find the `ifaddrs' structure from `ifa'
274 			 * for this interface. We need the IFF_* flags
275 			 * to find the interface state.
276 			 */
277 			for (ifap = ifa; ifap != NULL; ifap = ifap->ifa_next) {
278 				if (strcmp(ifap->ifa_name, aifp->ifi_name) == 0)
279 					break;
280 			}
281 			if (ifap == NULL) {
282 				/*
283 				 * The interface might have been removed
284 				 * from kernel. Retry getting all the active
285 				 * interfaces.
286 				 */
287 				freeifaddrs(ifa);
288 				ipadm_free_if_info(aifinfo);
289 				aifinfo = NULL;
290 				goto retry;
291 			}
292 			if (!(ifap->ifa_flags & IFF_RUNNING) ||
293 			    (ifap->ifa_flags & IFF_FAILED))
294 				aifp->ifi_state = IFIS_FAILED;
295 			else if (ifap->ifa_flags & IFF_OFFLINE)
296 				aifp->ifi_state = IFIS_OFFLINE;
297 			else if (i_ipadm_is_if_down(aifp->ifi_name, ifa))
298 				aifp->ifi_state = IFIS_DOWN;
299 			else
300 				aifp->ifi_state = IFIS_OK;
301 			if (aifp->ifi_next == NULL)
302 				last = aifp;
303 		}
304 		freeifaddrs(ifa);
305 	}
306 	/*
307 	 * Get the persistent interface information in `pifinfo'.
308 	 */
309 	status = i_ipadm_persist_if_info(iph, ifname, &pifinfo);
310 	if (status == IPADM_NOTFOUND) {
311 		*if_info = aifinfo;
312 		return (IPADM_SUCCESS);
313 	}
314 	if (status != IPADM_SUCCESS)
315 		goto fail;
316 	/*
317 	 * If a persistent interface is also found in `aifinfo', update
318 	 * its entry in `aifinfo' with the persistent information from
319 	 * `pifinfo'. If an interface is found in `pifinfo', but not in
320 	 * `aifinfo', it means that this interface was disabled. We should
321 	 * add this interface to `aifinfo' and set it state to IFIF_DISABLED.
322 	 */
323 	for (pifp = pifinfo; pifp != NULL; pifp = pifp->ifi_next) {
324 		for (aifp = aifinfo; aifp != NULL; aifp = aifp->ifi_next) {
325 			if (strcmp(aifp->ifi_name, pifp->ifi_name) == 0) {
326 				aifp->ifi_pflags = pifp->ifi_pflags;
327 				break;
328 			}
329 		}
330 		if (aifp == NULL) {
331 			aifp = malloc(sizeof (ipadm_if_info_t));
332 			if (aifp == NULL) {
333 				status = ipadm_errno2status(errno);
334 				goto fail;
335 			}
336 			*aifp = *pifp;
337 			aifp->ifi_next = NULL;
338 			aifp->ifi_state = IFIS_DISABLED;
339 			if (last != NULL)
340 				last->ifi_next = aifp;
341 			else
342 				aifinfo = aifp;
343 			last = aifp;
344 		}
345 	}
346 	*if_info = aifinfo;
347 	ipadm_free_if_info(pifinfo);
348 	return (IPADM_SUCCESS);
349 fail:
350 	*if_info = NULL;
351 	ipadm_free_if_info(aifinfo);
352 	ipadm_free_if_info(pifinfo);
353 	return (status);
354 }
355 
356 int
357 i_ipadm_get_lnum(const char *ifname)
358 {
359 	char *num = strrchr(ifname, IPADM_LOGICAL_SEP);
360 
361 	if (num == NULL)
362 		return (0);
363 
364 	return (atoi(++num));
365 }
366 
367 /*
368  * Sets the output argument `exists' to true or false based on whether
369  * any persistent configuration is available for `ifname' and returns
370  * IPADM_SUCCESS as status. If the persistent information cannot be retrieved,
371  * `exists' is unmodified and an error status is returned.
372  */
373 ipadm_status_t
374 i_ipadm_if_pexists(ipadm_handle_t iph, const char *ifname, sa_family_t af,
375     boolean_t *exists)
376 {
377 	ipadm_if_info_t	*ifinfo;
378 	ipadm_status_t	status;
379 
380 	status = i_ipadm_persist_if_info(iph, ifname, &ifinfo);
381 	if (status == IPADM_SUCCESS) {
382 		*exists = ((af == AF_INET &&
383 		    (ifinfo->ifi_pflags & IFIF_IPV4)) ||
384 		    (af == AF_INET6 &&
385 		    (ifinfo->ifi_pflags & IFIF_IPV6)));
386 		free(ifinfo);
387 	} else if (status == IPADM_NOTFOUND) {
388 		status = IPADM_SUCCESS;
389 		*exists = B_FALSE;
390 	}
391 	return (status);
392 }
393 
394 /*
395  * Open "/dev/udp{,6}" for use as a multiplexor to PLINK the interface stream
396  * under. We use "/dev/udp" instead of "/dev/ip" since STREAMS will not let
397  * you PLINK a driver under itself, and "/dev/ip" is typically the driver at
398  * the bottom of the stream for tunneling interfaces.
399  */
400 ipadm_status_t
401 ipadm_open_arp_on_udp(const char *udp_dev_name, int *fd)
402 {
403 	int err;
404 
405 	if ((*fd = open(udp_dev_name, O_RDWR)) == -1)
406 		return (ipadm_errno2status(errno));
407 
408 	/*
409 	 * Pop off all undesired modules (note that the user may have
410 	 * configured autopush to add modules above udp), and push the
411 	 * arp module onto the resulting stream. This is used to make
412 	 * IP+ARP be able to atomically track the muxid for the I_PLINKed
413 	 * STREAMS, thus it isn't related to ARP running the ARP protocol.
414 	 */
415 	while (ioctl(*fd, I_POP, 0) != -1)
416 		;
417 	if (errno == EINVAL && ioctl(*fd, I_PUSH, ARP_MOD_NAME) != -1)
418 		return (IPADM_SUCCESS);
419 	err = errno;
420 	(void) close(*fd);
421 
422 	return (ipadm_errno2status(err));
423 }
424 
425 /*
426  * i_ipadm_create_ipmp() is called from i_ipadm_create_ipmp_peer() when an
427  * underlying interface in an ipmp group G is plumbed for an address family,
428  * but the meta-interface for the other address family `af' does not exist
429  * yet for the group G. If `af' is IPv6, we need to bring up the
430  * link-local address.
431  */
432 static ipadm_status_t
433 i_ipadm_create_ipmp(ipadm_handle_t iph, char *ifname, sa_family_t af,
434     const char *grname, uint32_t ipadm_flags)
435 {
436 	ipadm_status_t	status;
437 	struct lifreq	lifr;
438 	int		sock;
439 	int		err;
440 
441 	assert(ipadm_flags & IPADM_OPT_IPMP);
442 
443 	/* Create the ipmp underlying interface */
444 	status = i_ipadm_create_if(iph, ifname, af, ipadm_flags);
445 	if (status != IPADM_SUCCESS && status != IPADM_IF_EXISTS)
446 		return (status);
447 
448 	/*
449 	 * To preserve backward-compatibility, always bring up the link-local
450 	 * address for implicitly-created IPv6 IPMP interfaces.
451 	 */
452 	if (af == AF_INET6)
453 		(void) i_ipadm_set_flags(iph, ifname, AF_INET6, IFF_UP, 0);
454 
455 	sock = (af == AF_INET ? iph->iph_sock : iph->iph_sock6);
456 	/*
457 	 * If the caller requested a different group name, issue a
458 	 * SIOCSLIFGROUPNAME on the new IPMP interface.
459 	 */
460 	bzero(&lifr, sizeof (lifr));
461 	(void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
462 	if (strcmp(lifr.lifr_name, grname) != 0) {
463 		(void) strlcpy(lifr.lifr_groupname, grname, LIFGRNAMSIZ);
464 		if (ioctl(sock, SIOCSLIFGROUPNAME, &lifr) == -1) {
465 			err = errno;
466 			/* Remove the interface we created. */
467 			if (status == IPADM_SUCCESS) {
468 				(void) i_ipadm_delete_if(iph, ifname, af,
469 				    ipadm_flags);
470 			}
471 			return (ipadm_errno2status(err));
472 		}
473 	}
474 
475 	return (IPADM_SUCCESS);
476 }
477 
478 /*
479  * Checks if `ifname' is plumbed and in an IPMP group on its "other" address
480  * family.  If so, create a matching IPMP group for address family `af'.
481  */
482 static ipadm_status_t
483 i_ipadm_create_ipmp_peer(ipadm_handle_t iph, char *ifname, sa_family_t af)
484 {
485 	lifgroupinfo_t	lifgr;
486 	ipadm_status_t	status = IPADM_SUCCESS;
487 	struct lifreq	lifr;
488 	int 		other_af_sock;
489 
490 	assert(af == AF_INET || af == AF_INET6);
491 
492 	other_af_sock = (af == AF_INET ? iph->iph_sock6 : iph->iph_sock);
493 
494 	/*
495 	 * iph is the handle for the interface that we are trying to plumb.
496 	 * other_af_sock is the socket for the "other" address family.
497 	 */
498 	bzero(&lifr, sizeof (lifr));
499 	(void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
500 	if (ioctl(other_af_sock, SIOCGLIFGROUPNAME, &lifr) != 0)
501 		return (IPADM_SUCCESS);
502 
503 	(void) strlcpy(lifgr.gi_grname, lifr.lifr_groupname, LIFGRNAMSIZ);
504 	if (ioctl(other_af_sock, SIOCGLIFGROUPINFO, &lifgr) != 0)
505 		return (IPADM_SUCCESS);
506 
507 	/*
508 	 * If `ifname' *is* the IPMP group interface, or if the relevant
509 	 * address family is already configured, then there's nothing to do.
510 	 */
511 	if (strcmp(lifgr.gi_grifname, ifname) == 0 ||
512 	    (af == AF_INET && lifgr.gi_v4) || (af == AF_INET6 && lifgr.gi_v6)) {
513 		return (IPADM_SUCCESS);
514 	}
515 
516 	status = i_ipadm_create_ipmp(iph, lifgr.gi_grifname, af,
517 	    lifgr.gi_grname, IPADM_OPT_ACTIVE|IPADM_OPT_IPMP);
518 	return (status);
519 }
520 
521 /*
522  * Issues the ioctl SIOCSLIFNAME to kernel on the given ARP stream fd.
523  */
524 static ipadm_status_t
525 i_ipadm_slifname_arp(char *ifname, uint64_t flags, int fd)
526 {
527 	struct lifreq	lifr;
528 	ifspec_t	ifsp;
529 
530 	bzero(&lifr, sizeof (lifr));
531 	(void) ifparse_ifspec(ifname, &ifsp);
532 	lifr.lifr_ppa = ifsp.ifsp_ppa;
533 	lifr.lifr_flags = flags;
534 	(void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
535 	/*
536 	 * Tell ARP the name and unit number for this interface.
537 	 * Note that arp has no support for transparent ioctls.
538 	 */
539 	if (i_ipadm_strioctl(fd, SIOCSLIFNAME, (char *)&lifr,
540 	    sizeof (lifr)) == -1) {
541 		return (ipadm_errno2status(errno));
542 	}
543 	return (IPADM_SUCCESS);
544 }
545 
546 /*
547  * Issues the ioctl SIOCSLIFNAME to kernel. If IPADM_OPT_GENPPA is set in
548  * `ipadm_flags', then a ppa will be generated. `newif' will be updated
549  * with the generated ppa.
550  */
551 static ipadm_status_t
552 i_ipadm_slifname(ipadm_handle_t iph, char *ifname, char *newif, uint64_t flags,
553     int fd, uint32_t ipadm_flags)
554 {
555 	struct lifreq	lifr;
556 	ipadm_status_t	status = IPADM_SUCCESS;
557 	int		err = 0;
558 	sa_family_t	af;
559 	int		ppa;
560 	ifspec_t	ifsp;
561 	boolean_t	valid_if;
562 
563 	bzero(&lifr, sizeof (lifr));
564 	if (ipadm_flags & IPADM_OPT_GENPPA) {
565 		/*
566 		 * We'd like to just set lifr_ppa to UINT_MAX and have the
567 		 * kernel pick a PPA.  Unfortunately, that would mishandle
568 		 * two cases:
569 		 *
570 		 *	1. If the PPA is available but the groupname is taken
571 		 *	   (e.g., the "ipmp2" IP interface name is available
572 		 *	   but the "ipmp2" groupname is taken) then the
573 		 *	   auto-assignment by the kernel will fail.
574 		 *
575 		 *	2. If we're creating (e.g.) an IPv6-only IPMP
576 		 *	   interface, and there's already an IPv4-only IPMP
577 		 *	   interface, the kernel will allow us to accidentally
578 		 *	   reuse the IPv6 IPMP interface name (since
579 		 *	   SIOCSLIFNAME uniqueness is per-interface-type).
580 		 *	   This will cause administrative confusion.
581 		 *
582 		 * Thus, we instead take a brute-force approach of checking
583 		 * whether the IPv4 or IPv6 name is already in-use before
584 		 * attempting the SIOCSLIFNAME.  As per (1) above, the
585 		 * SIOCSLIFNAME may still fail, in which case we just proceed
586 		 * to the next one.  If this approach becomes too slow, we
587 		 * can add a new SIOC* to handle this case in the kernel.
588 		 */
589 		for (ppa = 0; ppa < UINT_MAX; ppa++) {
590 			(void) snprintf(lifr.lifr_name, LIFNAMSIZ, "%s%d",
591 			    ifname, ppa);
592 
593 			if (ioctl(iph->iph_sock, SIOCGLIFFLAGS, &lifr) != -1 ||
594 			    errno != ENXIO)
595 				continue;
596 
597 			if (ioctl(iph->iph_sock6, SIOCGLIFFLAGS, &lifr) != -1 ||
598 			    errno != ENXIO)
599 				continue;
600 
601 			lifr.lifr_ppa = ppa;
602 			lifr.lifr_flags = flags;
603 
604 			err = ioctl(fd, SIOCSLIFNAME, &lifr);
605 			if (err != -1 || errno != EEXIST)
606 				break;
607 		}
608 		if (err == -1) {
609 			status = ipadm_errno2status(errno);
610 		} else {
611 			/*
612 			 * PPA has been successfully established.
613 			 * Update `newif' with the ppa.
614 			 */
615 			assert(newif != NULL);
616 			if (snprintf(newif, LIFNAMSIZ, "%s%d", ifname,
617 			    ppa) >= LIFNAMSIZ)
618 				return (IPADM_INVALID_ARG);
619 		}
620 	} else {
621 		/* We should have already validated the interface name. */
622 		valid_if = ifparse_ifspec(ifname, &ifsp);
623 		assert(valid_if);
624 
625 		/*
626 		 * Before we call SIOCSLIFNAME, ensure that the IPMP group
627 		 * interface for this address family exists.  Otherwise, the
628 		 * kernel will kick the interface out of the group when we do
629 		 * the SIOCSLIFNAME.
630 		 *
631 		 * Example: suppose bge0 is plumbed for IPv4 and in group "a".
632 		 * If we're now plumbing bge0 for IPv6, but the IPMP group
633 		 * interface for "a" is not plumbed for IPv6, the SIOCSLIFNAME
634 		 * will kick bge0 out of group "a", which is undesired.
635 		 */
636 		if (flags & IFF_IPV4)
637 			af = AF_INET;
638 		else
639 			af = AF_INET6;
640 		status = i_ipadm_create_ipmp_peer(iph, ifname, af);
641 		if (status != IPADM_SUCCESS)
642 			return (status);
643 		lifr.lifr_ppa = ifsp.ifsp_ppa;
644 		lifr.lifr_flags = flags;
645 		(void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
646 		if (ioctl(fd, SIOCSLIFNAME, &lifr) == -1)
647 			status = ipadm_errno2status(errno);
648 	}
649 
650 	return (status);
651 }
652 
653 /*
654  * Plumbs the interface `ifname' for the address family `af'. It also persists
655  * the interface for `af' if IPADM_OPT_PERSIST is set in `ipadm_flags'.
656  */
657 ipadm_status_t
658 i_ipadm_plumb_if(ipadm_handle_t iph, char *ifname, sa_family_t af,
659     uint32_t ipadm_flags)
660 {
661 	int		ip_muxid;
662 	int		mux_fd = -1, ip_fd, arp_fd;
663 	char		*udp_dev_name;
664 	dlpi_handle_t	dh_arp = NULL, dh_ip;
665 	uint64_t	ifflags;
666 	struct lifreq	lifr;
667 	uint_t		dlpi_flags;
668 	ipadm_status_t	status = IPADM_SUCCESS;
669 	char		*linkname;
670 	boolean_t	legacy = (iph->iph_flags & IPH_LEGACY);
671 	zoneid_t	zoneid;
672 	char		newif[LIFNAMSIZ];
673 	char		lifname[LIFNAMSIZ];
674 	datalink_id_t	linkid;
675 	int		sock;
676 	boolean_t	islo;
677 	boolean_t	is_persistent =
678 	    ((ipadm_flags & IPADM_OPT_PERSIST) != 0);
679 	uint32_t	dlflags;
680 	dladm_status_t	dlstatus;
681 
682 	if (iph->iph_dlh != NULL) {
683 		dlstatus = dladm_name2info(iph->iph_dlh, ifname, &linkid,
684 		    &dlflags, NULL, NULL);
685 	}
686 	/*
687 	 * If we're in the global zone and we're plumbing a datalink, make
688 	 * sure that the datalink is not assigned to a non-global zone.  Note
689 	 * that the non-global zones don't need this check, because zoneadm
690 	 * has taken care of this when the zones boot.
691 	 */
692 	if (getzoneid() == GLOBAL_ZONEID && dlstatus == DLADM_STATUS_OK) {
693 		zoneid = ALL_ZONES;
694 		if (zone_check_datalink(&zoneid, linkid) == 0) {
695 			/* interface is in use by a non-global zone. */
696 			return (IPADM_IF_INUSE);
697 		}
698 	}
699 
700 	/* loopback interfaces are just added as logical interface */
701 	bzero(&lifr, sizeof (lifr));
702 	islo = i_ipadm_is_loopback(ifname);
703 	if (islo || i_ipadm_get_lnum(ifname) != 0) {
704 		(void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
705 		if (af == AF_INET)
706 			sock = iph->iph_sock;
707 		else
708 			sock = iph->iph_sock6;
709 		if (islo && ioctl(sock, SIOCGLIFADDR, (caddr_t)&lifr) >= 0)
710 			return (IPADM_IF_EXISTS);
711 		if (ioctl(sock, SIOCLIFADDIF, (caddr_t)&lifr) < 0)
712 			return (ipadm_errno2status(errno));
713 
714 		/*
715 		 * By default, kernel configures 127.0.0.1 on the loopback
716 		 * interface. Replace this with 0.0.0.0 to be consistent
717 		 * with interface creation on other physical interfaces.
718 		 */
719 		if (islo && !legacy) {
720 			bzero(&lifr.lifr_addr, sizeof (lifr.lifr_addr));
721 			lifr.lifr_addr.ss_family = af;
722 			if (ioctl(sock, SIOCSLIFADDR, (caddr_t)&lifr) < 0)
723 				return (ipadm_errno2status(errno));
724 			if (is_persistent) {
725 				status = i_ipadm_persist_if(iph, ifname, af);
726 				if (status != IPADM_SUCCESS) {
727 					(void) i_ipadm_delete_if(iph, ifname,
728 					    af, IPADM_OPT_ACTIVE);
729 				}
730 			}
731 		}
732 		return (status);
733 	}
734 
735 	dlpi_flags = DLPI_NOATTACH;
736 
737 	/*
738 	 * If IPADM_OPT_IPMP is specified, then this is a request
739 	 * to create an IPMP interface atop /dev/ipmpstub0.  (We can't simply
740 	 * pass "ipmpstub0" as devname since an admin *could* have a normal
741 	 * vanity-named link named "ipmpstub0" that they'd like to plumb.)
742 	 */
743 	if (ipadm_flags & IPADM_OPT_IPMP) {
744 		dlpi_flags |= DLPI_DEVONLY;
745 		linkname = "ipmpstub0";
746 	} else {
747 		/*
748 		 * Verify that the user is not creating a persistent
749 		 * IP interface on a non-persistent data-link.
750 		 */
751 		if (!i_ipadm_is_vni(ifname) && dlstatus == DLADM_STATUS_OK &&
752 		    is_persistent && !(dlflags & DLADM_OPT_PERSIST)) {
753 				return (IPADM_TEMPORARY_OBJ);
754 		}
755 		linkname = ifname;
756 	}
757 
758 	/*
759 	 * We use DLPI_NOATTACH because the ip module will do the attach
760 	 * itself for DLPI style-2 devices.
761 	 */
762 	if (dlpi_open(linkname, &dh_ip, dlpi_flags) != DLPI_SUCCESS)
763 		return (IPADM_DLPI_FAILURE);
764 	ip_fd = dlpi_fd(dh_ip);
765 	if (ioctl(ip_fd, I_PUSH, IP_MOD_NAME) == -1) {
766 		status = ipadm_errno2status(errno);
767 		goto done;
768 	}
769 
770 	/*
771 	 * Set IFF_IPV4/IFF_IPV6 flags. The kernel only allows modifications
772 	 * to IFF_IPv4, IFF_IPV6, IFF_BROADCAST, IFF_XRESOLV, IFF_NOLINKLOCAL.
773 	 */
774 	ifflags = 0;
775 
776 	/* Set the name string and the IFF_IPV* flag */
777 	if (af == AF_INET) {
778 		ifflags = IFF_IPV4;
779 	} else {
780 		ifflags = IFF_IPV6;
781 		/*
782 		 * With the legacy method, the link-local address should be
783 		 * configured as part of the interface plumb, using the default
784 		 * token. If IPH_LEGACY is not specified, we want to set :: as
785 		 * the address and require the admin to explicitly call
786 		 * ipadm_create_addr() with the address object type set to
787 		 * IPADM_ADDR_IPV6_ADDRCONF to create the link-local address
788 		 * as well as the autoconfigured addresses.
789 		 */
790 		if (!legacy && !i_ipadm_is_6to4(iph, ifname))
791 			ifflags |= IFF_NOLINKLOCAL;
792 	}
793 	(void) strlcpy(newif, ifname, sizeof (newif));
794 	status = i_ipadm_slifname(iph, ifname, newif, ifflags, ip_fd,
795 	    ipadm_flags);
796 	if (status != IPADM_SUCCESS)
797 		goto done;
798 
799 	/* Get the full set of existing flags for this stream */
800 	status = i_ipadm_get_flags(iph, newif, af, &ifflags);
801 	if (status != IPADM_SUCCESS)
802 		goto done;
803 
804 	udp_dev_name = (af == AF_INET6 ? UDP6_DEV_NAME : UDP_DEV_NAME);
805 	status = ipadm_open_arp_on_udp(udp_dev_name, &mux_fd);
806 	if (status != IPADM_SUCCESS)
807 		goto done;
808 
809 	/* Check if arp is not needed */
810 	if (ifflags & (IFF_NOARP|IFF_IPV6)) {
811 		/*
812 		 * PLINK the interface stream so that the application can exit
813 		 * without tearing down the stream.
814 		 */
815 		if ((ip_muxid = ioctl(mux_fd, I_PLINK, ip_fd)) == -1)
816 			status = ipadm_errno2status(errno);
817 		goto done;
818 	}
819 
820 	/*
821 	 * This interface does use ARP, so set up a separate stream
822 	 * from the interface to ARP.
823 	 *
824 	 * We use DLPI_NOATTACH because the arp module will do the attach
825 	 * itself for DLPI style-2 devices.
826 	 */
827 	if (dlpi_open(linkname, &dh_arp, dlpi_flags) != DLPI_SUCCESS) {
828 		status = IPADM_DLPI_FAILURE;
829 		goto done;
830 	}
831 
832 	arp_fd = dlpi_fd(dh_arp);
833 	if (ioctl(arp_fd, I_PUSH, ARP_MOD_NAME) == -1) {
834 		status = ipadm_errno2status(errno);
835 		goto done;
836 	}
837 
838 	status = i_ipadm_slifname_arp(newif, ifflags, arp_fd);
839 	if (status != IPADM_SUCCESS)
840 		goto done;
841 	/*
842 	 * PLINK the IP and ARP streams so that ifconfig can exit
843 	 * without tearing down the stream.
844 	 */
845 	if ((ip_muxid = ioctl(mux_fd, I_PLINK, ip_fd)) == -1) {
846 		status = ipadm_errno2status(errno);
847 		goto done;
848 	}
849 
850 	if (ioctl(mux_fd, I_PLINK, arp_fd) < 0) {
851 		status = ipadm_errno2status(errno);
852 		(void) ioctl(mux_fd, I_PUNLINK, ip_muxid);
853 	}
854 
855 done:
856 	dlpi_close(dh_ip);
857 	if (dh_arp != NULL)
858 		dlpi_close(dh_arp);
859 
860 	if (mux_fd != -1)
861 		(void) close(mux_fd);
862 
863 	if (status == IPADM_SUCCESS) {
864 		/* copy back new ifname */
865 		(void) strlcpy(ifname, newif, LIFNAMSIZ);
866 		/*
867 		 * If it is a 6to4 tunnel, create a default
868 		 * addrobj name for the default address on the 0'th
869 		 * logical interface and set IFF_UP in the interface flags.
870 		 */
871 		if (i_ipadm_is_6to4(iph, ifname)) {
872 			struct ipadm_addrobj_s addr;
873 
874 			i_ipadm_init_addr(&addr, ifname, "", IPADM_ADDR_STATIC);
875 			addr.ipadm_af = af;
876 			status = i_ipadm_lookupadd_addrobj(iph, &addr);
877 			if (status != IPADM_SUCCESS)
878 				return (status);
879 			status = ipadm_add_aobjname(iph, ifname,
880 			    af, addr.ipadm_aobjname, IPADM_ADDR_STATIC, 0);
881 			if (status != IPADM_SUCCESS)
882 				return (status);
883 			addr.ipadm_lifnum = 0;
884 			i_ipadm_addrobj2lifname(&addr, lifname,
885 			    sizeof (lifname));
886 			status = i_ipadm_set_flags(iph, lifname, af,
887 			    IFF_UP, 0);
888 			if (status != IPADM_SUCCESS)
889 				return (status);
890 		} else {
891 			/*
892 			 * Prevent static IPv6 addresses from triggering
893 			 * autoconf. This does not have to be done for
894 			 * 6to4 tunnel interfaces, since in.ndpd will
895 			 * not autoconfigure those interfaces.
896 			 */
897 			if (af == AF_INET6 && !legacy)
898 				(void) i_ipadm_disable_autoconf(newif);
899 		}
900 
901 		/*
902 		 * If IPADM_OPT_PERSIST was set in flags, store the
903 		 * interface in persistent DB.
904 		 */
905 		if (is_persistent) {
906 			status = i_ipadm_persist_if(iph, newif, af);
907 			if (status != IPADM_SUCCESS) {
908 				(void) i_ipadm_delete_if(iph, newif, af,
909 				    IPADM_OPT_ACTIVE);
910 			}
911 		}
912 	}
913 	if (status == IPADM_EXISTS)
914 		status = IPADM_IF_EXISTS;
915 	return (status);
916 }
917 
918 /*
919  * Unplumbs the interface in `ifname' of family `af'.
920  */
921 ipadm_status_t
922 i_ipadm_unplumb_if(ipadm_handle_t iph, const char *ifname, sa_family_t af)
923 {
924 	int		ip_muxid, arp_muxid;
925 	int		mux_fd = -1;
926 	int		muxid_fd = -1;
927 	char		*udp_dev_name;
928 	uint64_t	flags;
929 	boolean_t	changed_arp_muxid = B_FALSE;
930 	int		save_errno;
931 	struct lifreq	lifr;
932 	ipadm_status_t	ret = IPADM_SUCCESS;
933 	int		sock;
934 	lifgroupinfo_t	lifgr;
935 	ifaddrlistx_t	*ifaddrs, *ifaddrp;
936 	boolean_t	v6 = (af == AF_INET6);
937 
938 	/* Just do SIOCLIFREMOVEIF on loopback interfaces */
939 	bzero(&lifr, sizeof (lifr));
940 	if (i_ipadm_is_loopback(ifname) ||
941 	    (i_ipadm_get_lnum(ifname) != 0 && (iph->iph_flags & IPH_LEGACY))) {
942 		(void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
943 		if (ioctl((af == AF_INET) ? iph->iph_sock : iph->iph_sock6,
944 		    SIOCLIFREMOVEIF, (caddr_t)&lifr) < 0) {
945 			return (ipadm_errno2status(errno));
946 		}
947 		return (IPADM_SUCCESS);
948 	}
949 
950 	/*
951 	 * We used /dev/udp or udp6 to set up the mux. So we have to use
952 	 * the same now for PUNLINK also.
953 	 */
954 	if (v6) {
955 		udp_dev_name = UDP6_DEV_NAME;
956 		sock = iph->iph_sock6;
957 	} else {
958 		udp_dev_name = UDP_DEV_NAME;
959 		sock = iph->iph_sock;
960 	}
961 	if ((muxid_fd = open(udp_dev_name, O_RDWR)) == -1) {
962 		ret = ipadm_errno2status(errno);
963 		goto done;
964 	}
965 	ret = ipadm_open_arp_on_udp(udp_dev_name, &mux_fd);
966 	if (ret != IPADM_SUCCESS)
967 		goto done;
968 	(void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
969 	if (ioctl(muxid_fd, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) {
970 		ret = ipadm_errno2status(errno);
971 		goto done;
972 	}
973 	flags = lifr.lifr_flags;
974 again:
975 	if (flags & IFF_IPMP) {
976 		/*
977 		 * There are two reasons the I_PUNLINK can fail with EBUSY:
978 		 * (1) if IP interfaces are in the group, or (2) if IPMP data
979 		 * addresses are administratively up.  For case (1), we fail
980 		 * here with a specific error message.  For case (2), we bring
981 		 * down the addresses prior to doing the I_PUNLINK.  If the
982 		 * I_PUNLINK still fails with EBUSY then the configuration
983 		 * must have changed after our checks, in which case we branch
984 		 * back up to `again' and rerun this logic.  The net effect is
985 		 * that unplumbing an IPMP interface will only fail with EBUSY
986 		 * if IP interfaces are in the group.
987 		 */
988 		if (ioctl(sock, SIOCGLIFGROUPNAME, &lifr) == -1) {
989 			ret = ipadm_errno2status(errno);
990 			goto done;
991 		}
992 		(void) strlcpy(lifgr.gi_grname, lifr.lifr_groupname,
993 		    LIFGRNAMSIZ);
994 		if (ioctl(sock, SIOCGLIFGROUPINFO, &lifgr) == -1) {
995 			ret = ipadm_errno2status(errno);
996 			goto done;
997 		}
998 		if ((v6 && lifgr.gi_nv6 != 0) || (!v6 && lifgr.gi_nv4 != 0)) {
999 			ret = IPADM_GRP_NOTEMPTY;
1000 			goto done;
1001 		}
1002 
1003 		/*
1004 		 * The kernel will fail the I_PUNLINK if the IPMP interface
1005 		 * has administratively up addresses; bring them down.
1006 		 */
1007 		if (ifaddrlistx(ifname, IFF_UP|IFF_DUPLICATE,
1008 		    0, &ifaddrs) == -1) {
1009 			ret = ipadm_errno2status(errno);
1010 			goto done;
1011 		}
1012 		ifaddrp = ifaddrs;
1013 		for (; ifaddrp != NULL; ifaddrp = ifaddrp->ia_next) {
1014 			int sock = (ifaddrp->ia_flags & IFF_IPV4) ?
1015 			    iph->iph_sock : iph->iph_sock6;
1016 			struct lifreq lifrl;
1017 
1018 			if (((ifaddrp->ia_flags & IFF_IPV6) && !v6) ||
1019 			    (!(ifaddrp->ia_flags & IFF_IPV6) && v6))
1020 				continue;
1021 
1022 			bzero(&lifrl, sizeof (lifrl));
1023 			(void) strlcpy(lifrl.lifr_name, ifaddrp->ia_name,
1024 			    sizeof (lifrl.lifr_name));
1025 			if (ioctl(sock, SIOCGLIFFLAGS, &lifrl) < 0) {
1026 				ret = ipadm_errno2status(errno);
1027 				ifaddrlistx_free(ifaddrs);
1028 				goto done;
1029 			}
1030 			if (lifrl.lifr_flags & IFF_UP) {
1031 				ret = i_ipadm_set_flags(iph, lifrl.lifr_name,
1032 				    ((lifrl.lifr_flags & IFF_IPV4) ? AF_INET :
1033 				    AF_INET6), 0, IFF_UP);
1034 				if (ret != IPADM_SUCCESS) {
1035 					ifaddrlistx_free(ifaddrs);
1036 					goto done;
1037 				}
1038 			} else if (lifrl.lifr_flags & IFF_DUPLICATE) {
1039 				if (ioctl(sock, SIOCGLIFADDR, &lifrl) < 0 ||
1040 				    ioctl(sock, SIOCSLIFADDR, &lifrl) < 0) {
1041 					ret = ipadm_errno2status(errno);
1042 					ifaddrlistx_free(ifaddrs);
1043 					goto done;
1044 				}
1045 			}
1046 		}
1047 		ifaddrlistx_free(ifaddrs);
1048 	}
1049 
1050 	if (ioctl(muxid_fd, SIOCGLIFMUXID, (caddr_t)&lifr) < 0) {
1051 		ret = ipadm_errno2status(errno);
1052 		goto done;
1053 	}
1054 	arp_muxid = lifr.lifr_arp_muxid;
1055 	ip_muxid = lifr.lifr_ip_muxid;
1056 
1057 	/*
1058 	 * We don't have a good way of knowing whether the arp stream is
1059 	 * plumbed. We can't rely on IFF_NOARP because someone could
1060 	 * have turned it off later using "ifconfig xxx -arp".
1061 	 */
1062 	if (arp_muxid != 0) {
1063 		if (ioctl(mux_fd, I_PUNLINK, arp_muxid) < 0) {
1064 			/*
1065 			 * See the comment before the SIOCGLIFGROUPNAME call.
1066 			 */
1067 			if (errno == EBUSY && (flags & IFF_IPMP))
1068 				goto again;
1069 
1070 			if ((errno == EINVAL) &&
1071 			    (flags & (IFF_NOARP | IFF_IPV6))) {
1072 				/*
1073 				 * Some plumbing utilities set the muxid to
1074 				 * -1 or some invalid value to signify that
1075 				 * there is no arp stream. Set the muxid to 0
1076 				 * before trying to unplumb the IP stream.
1077 				 * IP does not allow the IP stream to be
1078 				 * unplumbed if it sees a non-null arp muxid,
1079 				 * for consistency of IP-ARP streams.
1080 				 */
1081 				lifr.lifr_arp_muxid = 0;
1082 				(void) ioctl(muxid_fd, SIOCSLIFMUXID,
1083 				    (caddr_t)&lifr);
1084 				changed_arp_muxid = B_TRUE;
1085 			}
1086 			/*
1087 			 * In case of any other error, we continue with
1088 			 * the unplumb.
1089 			 */
1090 		}
1091 	}
1092 
1093 	if (ioctl(mux_fd, I_PUNLINK, ip_muxid) < 0) {
1094 		if (changed_arp_muxid) {
1095 			/*
1096 			 * Some error occurred, and we need to restore
1097 			 * everything back to what it was.
1098 			 */
1099 			save_errno = errno;
1100 			lifr.lifr_arp_muxid = arp_muxid;
1101 			lifr.lifr_ip_muxid = ip_muxid;
1102 			(void) ioctl(muxid_fd, SIOCSLIFMUXID, (caddr_t)&lifr);
1103 			errno = save_errno;
1104 		}
1105 		/*
1106 		 * See the comment before the SIOCGLIFGROUPNAME call.
1107 		 */
1108 		if (errno == EBUSY && (flags & IFF_IPMP))
1109 			goto again;
1110 
1111 		ret = ipadm_errno2status(errno);
1112 	}
1113 done:
1114 	if (muxid_fd != -1)
1115 		(void) close(muxid_fd);
1116 	if (mux_fd != -1)
1117 		(void) close(mux_fd);
1118 
1119 	if (af == AF_INET6 && ret == IPADM_SUCCESS) {
1120 		/*
1121 		 * in.ndpd maintains the phyints in its memory even after
1122 		 * the interface is plumbed, so that it can be reused when
1123 		 * the interface gets plumbed again. The default behavior
1124 		 * of in.ndpd is to start autoconfiguration for an interface
1125 		 * that gets plumbed. We need to send the
1126 		 * message IPADM_ENABLE_AUTOCONF to in.ndpd to restore this
1127 		 * default behavior on replumb.
1128 		 */
1129 		(void) i_ipadm_enable_autoconf(ifname);
1130 	}
1131 	return (ret);
1132 }
1133 
1134 /*
1135  * Saves the given interface name `ifname' with address family `af' in
1136  * persistent DB.
1137  */
1138 static ipadm_status_t
1139 i_ipadm_persist_if(ipadm_handle_t iph, const char *ifname, sa_family_t af)
1140 {
1141 	ipmgmt_if_arg_t		ifarg;
1142 	int			err;
1143 
1144 	(void) strlcpy(ifarg.ia_ifname, ifname, sizeof (ifarg.ia_ifname));
1145 	ifarg.ia_family = af;
1146 	ifarg.ia_cmd = IPMGMT_CMD_SETIF;
1147 	ifarg.ia_flags = IPMGMT_PERSIST;
1148 	err = ipadm_door_call(iph, &ifarg, sizeof (ifarg), NULL, 0, B_FALSE);
1149 	return (ipadm_errno2status(err));
1150 }
1151 
1152 /*
1153  * Remove the IP interface from active configuration. If IPADM_OPT_PERSIST
1154  * is set in `ipadm_flags', it is also removed from persistent configuration.
1155  */
1156 ipadm_status_t
1157 i_ipadm_delete_if(ipadm_handle_t iph, const char *ifname, sa_family_t af,
1158     uint32_t ipadm_flags)
1159 {
1160 	ipadm_status_t		ret = IPADM_SUCCESS;
1161 	ipadm_status_t		db_status;
1162 	char			tmp_ifname[LIFNAMSIZ];
1163 	char			*cp;
1164 	struct ipadm_addrobj_s	ipaddr;
1165 	boolean_t		is_persistent =
1166 	    (ipadm_flags & IPADM_OPT_PERSIST);
1167 
1168 	ret = i_ipadm_unplumb_if(iph, ifname, af);
1169 	if (ret != IPADM_SUCCESS)
1170 		goto done;
1171 
1172 	cp = strrchr(ifname, IPADM_LOGICAL_SEP);
1173 	if (cp != NULL) {
1174 		assert(iph->iph_flags & IPH_LEGACY);
1175 		/*
1176 		 * This is a non-zero logical interface.
1177 		 * Find the addrobj and remove it from the daemon's memory.
1178 		 */
1179 		(void) strlcpy(tmp_ifname, ifname, sizeof (tmp_ifname));
1180 		tmp_ifname[cp - ifname] = '\0';
1181 		*cp++ = '\0';
1182 		ipaddr.ipadm_lifnum = atoi(cp);
1183 		(void) strlcpy(ipaddr.ipadm_ifname, tmp_ifname,
1184 		    sizeof (ipaddr.ipadm_ifname));
1185 		ipaddr.ipadm_af = af;
1186 		ret = i_ipadm_get_lif2addrobj(iph, &ipaddr);
1187 		if (ret == IPADM_SUCCESS) {
1188 			ret = i_ipadm_delete_addrobj(iph, &ipaddr,
1189 			    IPADM_OPT_ACTIVE);
1190 		} else if (ret == IPADM_NOTFOUND) {
1191 			ret = IPADM_SUCCESS;
1192 		}
1193 		return (ret);
1194 	}
1195 done:
1196 	/*
1197 	 * Even if interface does not exist, remove all its addresses and
1198 	 * properties from the persistent store. If interface does not
1199 	 * exist both in kernel and the persistent store, return IPADM_ENXIO.
1200 	 */
1201 	if ((ret == IPADM_ENXIO && is_persistent) || ret == IPADM_SUCCESS) {
1202 		db_status = i_ipadm_delete_ifobj(iph, ifname, af,
1203 		    is_persistent);
1204 		if (db_status == IPADM_SUCCESS)
1205 			ret = IPADM_SUCCESS;
1206 	}
1207 
1208 	return (ret);
1209 }
1210 
1211 /*
1212  * Resets all addresses on interface `ifname' with address family `af'
1213  * from ipmgmtd daemon. If is_persistent = B_TRUE, all interface properties
1214  * and address objects of `ifname' for `af' are also removed from the
1215  * persistent DB.
1216  */
1217 ipadm_status_t
1218 i_ipadm_delete_ifobj(ipadm_handle_t iph, const char *ifname, sa_family_t af,
1219     boolean_t is_persistent)
1220 {
1221 	ipmgmt_if_arg_t		ifarg;
1222 	int			err;
1223 
1224 	ifarg.ia_cmd = IPMGMT_CMD_RESETIF;
1225 	ifarg.ia_flags = IPMGMT_ACTIVE;
1226 	if (is_persistent)
1227 		ifarg.ia_flags |= IPMGMT_PERSIST;
1228 	ifarg.ia_family = af;
1229 	(void) strlcpy(ifarg.ia_ifname, ifname, LIFNAMSIZ);
1230 
1231 	err = ipadm_door_call(iph, &ifarg, sizeof (ifarg), NULL, 0, B_FALSE);
1232 	return (ipadm_errno2status(err));
1233 }
1234 
1235 /*
1236  * Create the interface by plumbing it for IP.
1237  * This function will check if there is saved configuration information
1238  * for `ifname' and return IPADM_OP_DISABLE_OBJ if the name-space
1239  * for `ifname' is taken.
1240  */
1241 ipadm_status_t
1242 i_ipadm_create_if(ipadm_handle_t iph, char *ifname, sa_family_t af,
1243     uint32_t ipadm_flags)
1244 {
1245 	ipadm_status_t	status;
1246 	boolean_t	p_exists;
1247 	sa_family_t	other_af;
1248 
1249 	/*
1250 	 * Return error, if the interface already exists in either the active
1251 	 * or the persistent configuration.
1252 	 */
1253 	if (ipadm_if_enabled(iph, ifname, af))
1254 		return (IPADM_IF_EXISTS);
1255 
1256 	status = i_ipadm_if_pexists(iph, ifname, af, &p_exists);
1257 	if (status != IPADM_SUCCESS)
1258 		return (status);
1259 	other_af = (af == AF_INET ? AF_INET6 : AF_INET);
1260 	if (p_exists) {
1261 		if (!ipadm_if_enabled(iph, ifname, other_af))
1262 			return (IPADM_OP_DISABLE_OBJ);
1263 		else
1264 			ipadm_flags &= ~IPADM_OPT_PERSIST;
1265 	}
1266 
1267 	return (i_ipadm_plumb_if(iph, ifname, af, ipadm_flags));
1268 }
1269 
1270 /*
1271  * Plumbs an interface. Creates both IPv4 and IPv6 interfaces by
1272  * default, unless a value in `af' is specified. The interface may be plumbed
1273  * only if there is no previously saved persistent configuration information
1274  * for the interface (in which case the ipadm_enable_if() function must
1275  * be used to enable the interface).
1276  *
1277  * Returns: IPADM_SUCCESS, IPADM_FAILURE, IPADM_IF_EXISTS,
1278  * IPADM_IF_PERSIST_EXISTS, IPADM_DLPI_FAILURE,
1279  * or appropriate ipadm_status_t corresponding to the errno.
1280  *
1281  * `ifname' must point to memory that can hold upto LIFNAMSIZ chars. It may
1282  * be over-written with the actual interface name when a PPA has to be
1283  * internally generated by the library.
1284  */
1285 ipadm_status_t
1286 ipadm_create_if(ipadm_handle_t iph, char *ifname, sa_family_t af,
1287     uint32_t flags)
1288 {
1289 	ipadm_status_t	status;
1290 	boolean_t	created_v4 = B_FALSE;
1291 	char		newifname[LIFNAMSIZ];
1292 
1293 	/* Check for the required authorization */
1294 	if (!ipadm_check_auth())
1295 		return (IPADM_EAUTH);
1296 
1297 	if (flags == 0 || ((flags & IPADM_OPT_PERSIST) &&
1298 	    !(flags & IPADM_OPT_ACTIVE)) ||
1299 	    (flags & ~(IPADM_COMMON_OPT_MASK | IPADM_OPT_IPMP |
1300 	    IPADM_OPT_GENPPA))) {
1301 		return (IPADM_INVALID_ARG);
1302 	}
1303 	if (flags & IPADM_OPT_GENPPA) {
1304 		if (snprintf(newifname, LIFNAMSIZ, "%s0", ifname) >=
1305 		    LIFNAMSIZ)
1306 			return (IPADM_INVALID_ARG);
1307 	} else {
1308 		if (strlcpy(newifname, ifname, LIFNAMSIZ) >= LIFNAMSIZ)
1309 			return (IPADM_INVALID_ARG);
1310 	}
1311 
1312 	if (!i_ipadm_validate_ifname(iph, newifname))
1313 		return (IPADM_INVALID_ARG);
1314 
1315 	if ((af == AF_INET || af == AF_UNSPEC) &&
1316 	    !i_ipadm_is_6to4(iph, ifname)) {
1317 		status = i_ipadm_create_if(iph, ifname, AF_INET, flags);
1318 		if (status != IPADM_SUCCESS)
1319 			return (status);
1320 		created_v4 = B_TRUE;
1321 	}
1322 	if (af == AF_INET6 || af == AF_UNSPEC) {
1323 		status = i_ipadm_create_if(iph, ifname, AF_INET6, flags);
1324 		if (status != IPADM_SUCCESS) {
1325 			if (created_v4) {
1326 				(void) i_ipadm_delete_if(iph, ifname, AF_INET,
1327 				    IPADM_OPT_ACTIVE);
1328 			}
1329 			return (status);
1330 		}
1331 	}
1332 
1333 	return (IPADM_SUCCESS);
1334 }
1335 
1336 /*
1337  * Deletes the interface in `ifname'. Removes both IPv4 and IPv6 interfaces
1338  * when `af' = AF_UNSPEC.
1339  */
1340 ipadm_status_t
1341 ipadm_delete_if(ipadm_handle_t iph, const char *ifname, sa_family_t af,
1342     uint32_t flags)
1343 {
1344 	ipadm_status_t status1 = IPADM_SUCCESS;
1345 	ipadm_status_t status2 = IPADM_SUCCESS;
1346 	ipadm_status_t other;
1347 
1348 	/* Check for the required authorization */
1349 	if (!ipadm_check_auth())
1350 		return (IPADM_EAUTH);
1351 
1352 	/* Validate the `ifname' for any logical interface. */
1353 	if (flags == 0 || (flags & ~(IPADM_COMMON_OPT_MASK)) ||
1354 	    !i_ipadm_validate_ifname(iph, ifname))
1355 		return (IPADM_INVALID_ARG);
1356 
1357 	if (af == AF_INET || af == AF_UNSPEC)
1358 		status1 = i_ipadm_delete_if(iph, ifname, AF_INET, flags);
1359 	if (af == AF_INET6 || af == AF_UNSPEC)
1360 		status2 = i_ipadm_delete_if(iph, ifname, AF_INET6, flags);
1361 	/*
1362 	 * If the family has been uniquely identified, we return the
1363 	 * associated status, even if that is ENXIO. Calls from ifconfig
1364 	 * which can only unplumb one of IPv4/IPv6 at any time fall under
1365 	 * this category.
1366 	 */
1367 	if (af == AF_INET)
1368 		return (status1);
1369 	else if (af == AF_INET6)
1370 		return (status2);
1371 	else if (af != AF_UNSPEC)
1372 		return (IPADM_INVALID_ARG);
1373 
1374 	/*
1375 	 * If af is AF_UNSPEC, then we return the following:
1376 	 * status1,		if status1 == status2
1377 	 * IPADM_SUCCESS,	if either of status1 or status2 is SUCCESS
1378 	 * 			and the other status is ENXIO
1379 	 * IPADM_ENXIO,		if both status1 and status2 are ENXIO
1380 	 * IPADM_FAILURE	otherwise.
1381 	 */
1382 	if (status1 == status2) {
1383 		/* covers the case when both status1 and status2 are ENXIO */
1384 		return (status1);
1385 	} else if (status1 == IPADM_SUCCESS || status2 == IPADM_SUCCESS) {
1386 		if (status1 == IPADM_SUCCESS)
1387 			other = status2;
1388 		else
1389 			other = status1;
1390 		return (other == IPADM_ENXIO ? IPADM_SUCCESS : IPADM_FAILURE);
1391 	} else {
1392 		return (IPADM_FAILURE);
1393 	}
1394 }
1395 
1396 /*
1397  * Returns information about all interfaces in both active and persistent
1398  * configuration. If `ifname' is not NULL, it returns only the interface
1399  * identified by `ifname'.
1400  *
1401  * Return values:
1402  * 	On success: IPADM_SUCCESS.
1403  * 	On error  : IPADM_INVALID_ARG, IPADM_ENXIO or IPADM_FAILURE.
1404  */
1405 ipadm_status_t
1406 ipadm_if_info(ipadm_handle_t iph, const char *ifname,
1407     ipadm_if_info_t **if_info, uint32_t flags, int64_t lifc_flags)
1408 {
1409 	ipadm_status_t	status;
1410 	ifspec_t	ifsp;
1411 
1412 	if (if_info == NULL || iph == NULL || flags != 0)
1413 		return (IPADM_INVALID_ARG);
1414 
1415 	if (ifname != NULL &&
1416 	    (!ifparse_ifspec(ifname, &ifsp) || ifsp.ifsp_lunvalid)) {
1417 		return (IPADM_INVALID_ARG);
1418 	}
1419 
1420 	status = i_ipadm_get_all_if_info(iph, ifname, if_info, lifc_flags);
1421 	if (status != IPADM_SUCCESS)
1422 		return (status);
1423 	if (ifname != NULL && *if_info == NULL)
1424 		return (IPADM_ENXIO);
1425 
1426 	return (IPADM_SUCCESS);
1427 }
1428 
1429 /*
1430  * Frees the linked list allocated by ipadm_if_info().
1431  */
1432 void
1433 ipadm_free_if_info(ipadm_if_info_t *ifinfo)
1434 {
1435 	ipadm_if_info_t	*ifinfo_next;
1436 
1437 	for (; ifinfo != NULL; ifinfo = ifinfo_next) {
1438 		ifinfo_next = ifinfo->ifi_next;
1439 		free(ifinfo);
1440 	}
1441 }
1442 
1443 /*
1444  * Re-enable the interface `ifname' based on the saved configuration
1445  * for `ifname'.
1446  */
1447 ipadm_status_t
1448 ipadm_enable_if(ipadm_handle_t iph, const char *ifname, uint32_t flags)
1449 {
1450 	nvlist_t	*ifnvl;
1451 	ipadm_status_t	status;
1452 	ifspec_t	ifsp;
1453 
1454 	/* Check for the required authorization */
1455 	if (!ipadm_check_auth())
1456 		return (IPADM_EAUTH);
1457 
1458 	/* Check for logical interfaces. */
1459 	if (!ifparse_ifspec(ifname, &ifsp) || ifsp.ifsp_lunvalid)
1460 		return (IPADM_INVALID_ARG);
1461 
1462 	/* Enabling an interface persistently is not supported. */
1463 	if (flags & IPADM_OPT_PERSIST)
1464 		return (IPADM_NOTSUP);
1465 
1466 	/*
1467 	 * Return early by checking if the interface is already enabled.
1468 	 */
1469 	if (ipadm_if_enabled(iph, ifname, AF_INET) &&
1470 	    ipadm_if_enabled(iph, ifname, AF_INET6)) {
1471 		return (IPADM_IF_EXISTS);
1472 	}
1473 	/*
1474 	 * Enable the interface and restore all its interface properties
1475 	 * and address objects.
1476 	 */
1477 	status = i_ipadm_init_ifs(iph, ifname, &ifnvl);
1478 	if (status != IPADM_SUCCESS)
1479 		return (status);
1480 
1481 	assert(ifnvl != NULL);
1482 	/*
1483 	 * ipadm_enable_if() does exactly what ipadm_init_ifs() does,
1484 	 * but only for one interface. We need to set IPH_INIT because
1485 	 * ipmgmtd daemon does not have to write the interface to persistent
1486 	 * db. The interface is already available in persistent db
1487 	 * and we are here to re-enable the persistent configuration.
1488 	 */
1489 	iph->iph_flags |= IPH_INIT;
1490 	status = i_ipadm_init_ifobj(iph, ifname, ifnvl);
1491 	iph->iph_flags &= ~IPH_INIT;
1492 	return (status);
1493 }
1494 
1495 /*
1496  * Disable the interface `ifname' by removing it from the active configuration.
1497  * Error code return values follow the model in ipadm_delete_if()
1498  */
1499 ipadm_status_t
1500 ipadm_disable_if(ipadm_handle_t iph, const char *ifname, uint32_t flags)
1501 {
1502 	ipadm_status_t	status1, status2, other;
1503 	ifspec_t	ifsp;
1504 
1505 	/* Check for the required authorization */
1506 	if (!ipadm_check_auth())
1507 		return (IPADM_EAUTH);
1508 
1509 	/* Check for logical interfaces. */
1510 	if (!ifparse_ifspec(ifname, &ifsp) || ifsp.ifsp_lunvalid)
1511 		return (IPADM_INVALID_ARG);
1512 
1513 	/* Disabling an interface persistently is not supported. */
1514 	if (flags & IPADM_OPT_PERSIST)
1515 		return (IPADM_NOTSUP);
1516 
1517 	status1 = i_ipadm_unplumb_if(iph, ifname, AF_INET6);
1518 	if (status1 == IPADM_SUCCESS)
1519 		status1 = i_ipadm_delete_ifobj(iph, ifname, AF_INET6, B_FALSE);
1520 	status2 = i_ipadm_unplumb_if(iph, ifname, AF_INET);
1521 	if (status2 == IPADM_SUCCESS)
1522 		status2 = i_ipadm_delete_ifobj(iph, ifname, AF_INET, B_FALSE);
1523 	if (status1 == status2) {
1524 		return (status2);
1525 	} else if (status1 == IPADM_SUCCESS || status2 == IPADM_SUCCESS) {
1526 		if (status1 == IPADM_SUCCESS)
1527 			other = status2;
1528 		else
1529 			other = status1;
1530 		return (other == IPADM_ENXIO ? IPADM_SUCCESS : IPADM_FAILURE);
1531 	} else {
1532 		return (IPADM_FAILURE);
1533 	}
1534 }
1535