xref: /titanic_51/usr/src/lib/libipadm/common/ipadm_if.c (revision 550b6e4083768ca350e9e7c3a1ebbf720b23dcad)
16e91bba0SGirish Moodalbail /*
26e91bba0SGirish Moodalbail  * CDDL HEADER START
36e91bba0SGirish Moodalbail  *
46e91bba0SGirish Moodalbail  * The contents of this file are subject to the terms of the
56e91bba0SGirish Moodalbail  * Common Development and Distribution License (the "License").
66e91bba0SGirish Moodalbail  * You may not use this file except in compliance with the License.
76e91bba0SGirish Moodalbail  *
86e91bba0SGirish Moodalbail  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
96e91bba0SGirish Moodalbail  * or http://www.opensolaris.org/os/licensing.
106e91bba0SGirish Moodalbail  * See the License for the specific language governing permissions
116e91bba0SGirish Moodalbail  * and limitations under the License.
126e91bba0SGirish Moodalbail  *
136e91bba0SGirish Moodalbail  * When distributing Covered Code, include this CDDL HEADER in each
146e91bba0SGirish Moodalbail  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
156e91bba0SGirish Moodalbail  * If applicable, add the following below this CDDL HEADER, with the
166e91bba0SGirish Moodalbail  * fields enclosed by brackets "[]" replaced with your own identifying
176e91bba0SGirish Moodalbail  * information: Portions Copyright [yyyy] [name of copyright owner]
186e91bba0SGirish Moodalbail  *
196e91bba0SGirish Moodalbail  * CDDL HEADER END
206e91bba0SGirish Moodalbail  */
216e91bba0SGirish Moodalbail /*
2236b41818SGirish Moodalbail  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
236e91bba0SGirish Moodalbail  */
246e91bba0SGirish Moodalbail 
256e91bba0SGirish Moodalbail #include <errno.h>
266e91bba0SGirish Moodalbail #include <sys/sockio.h>
276e91bba0SGirish Moodalbail #include <string.h>
286e91bba0SGirish Moodalbail #include <assert.h>
296e91bba0SGirish Moodalbail #include <unistd.h>
306e91bba0SGirish Moodalbail #include <stropts.h>
316e91bba0SGirish Moodalbail #include <strings.h>
326e91bba0SGirish Moodalbail #include <libdlpi.h>
336e91bba0SGirish Moodalbail #include <libdllink.h>
346e91bba0SGirish Moodalbail #include <libinetutil.h>
356e91bba0SGirish Moodalbail #include <inet/ip.h>
366e91bba0SGirish Moodalbail #include <limits.h>
376e91bba0SGirish Moodalbail #include <zone.h>
386e91bba0SGirish Moodalbail #include <ipadm_ndpd.h>
396e91bba0SGirish Moodalbail #include "libipadm_impl.h"
406e91bba0SGirish Moodalbail 
416e91bba0SGirish Moodalbail static ipadm_status_t	i_ipadm_slifname_arp(char *, uint64_t, int);
426e91bba0SGirish Moodalbail static ipadm_status_t	i_ipadm_slifname(ipadm_handle_t, char *, char *,
436e91bba0SGirish Moodalbail 			    uint64_t, int, uint32_t);
446e91bba0SGirish Moodalbail static ipadm_status_t	i_ipadm_create_ipmp_peer(ipadm_handle_t, char *,
456e91bba0SGirish Moodalbail 			    sa_family_t);
466e91bba0SGirish Moodalbail static ipadm_status_t	i_ipadm_persist_if(ipadm_handle_t, const char *,
476e91bba0SGirish Moodalbail 			    sa_family_t);
486e91bba0SGirish Moodalbail 
496e91bba0SGirish Moodalbail /*
506e91bba0SGirish Moodalbail  * Returns B_FALSE if the interface in `ifname' has at least one address that is
516e91bba0SGirish Moodalbail  * IFF_UP in the addresses in `ifa'.
526e91bba0SGirish Moodalbail  */
536e91bba0SGirish Moodalbail static boolean_t
546e91bba0SGirish Moodalbail i_ipadm_is_if_down(char *ifname, struct ifaddrs *ifa)
556e91bba0SGirish Moodalbail {
566e91bba0SGirish Moodalbail 	struct ifaddrs	*ifap;
576e91bba0SGirish Moodalbail 	char		cifname[LIFNAMSIZ];
586e91bba0SGirish Moodalbail 	char		*sep;
596e91bba0SGirish Moodalbail 
606e91bba0SGirish Moodalbail 	for (ifap = ifa; ifap != NULL; ifap = ifap->ifa_next) {
616e91bba0SGirish Moodalbail 		(void) strlcpy(cifname, ifap->ifa_name, sizeof (cifname));
626e91bba0SGirish Moodalbail 		if ((sep = strrchr(cifname, IPADM_LOGICAL_SEP)) != NULL)
636e91bba0SGirish Moodalbail 			*sep = '\0';
646e91bba0SGirish Moodalbail 		/*
656e91bba0SGirish Moodalbail 		 * If this condition is true, there is at least one
666e91bba0SGirish Moodalbail 		 * address that is IFF_UP. So, we need to return B_FALSE.
676e91bba0SGirish Moodalbail 		 */
686e91bba0SGirish Moodalbail 		if (strcmp(cifname, ifname) == 0 &&
696e91bba0SGirish Moodalbail 		    (ifap->ifa_flags & IFF_UP)) {
706e91bba0SGirish Moodalbail 			return (B_FALSE);
716e91bba0SGirish Moodalbail 		}
726e91bba0SGirish Moodalbail 	}
736e91bba0SGirish Moodalbail 	/* We did not find any IFF_UP addresses. */
746e91bba0SGirish Moodalbail 	return (B_TRUE);
756e91bba0SGirish Moodalbail }
766e91bba0SGirish Moodalbail 
776e91bba0SGirish Moodalbail /*
786e91bba0SGirish Moodalbail  * Retrieves the information for the interface `ifname' from active
796e91bba0SGirish Moodalbail  * config if `ifname' is specified and returns the result in the list `if_info'.
806e91bba0SGirish Moodalbail  * Otherwise, it retrieves the information for all the interfaces in
816e91bba0SGirish Moodalbail  * the active config and returns the result in the list `if_info'.
826e91bba0SGirish Moodalbail  */
836e91bba0SGirish Moodalbail static ipadm_status_t
846e91bba0SGirish Moodalbail i_ipadm_active_if_info(ipadm_handle_t iph, const char *ifname,
856e91bba0SGirish Moodalbail     ipadm_if_info_t **if_info, int64_t lifc_flags)
866e91bba0SGirish Moodalbail {
876e91bba0SGirish Moodalbail 	struct lifreq	*buf;
886e91bba0SGirish Moodalbail 	struct lifreq	*lifrp;
896e91bba0SGirish Moodalbail 	struct lifreq	lifrl;
906e91bba0SGirish Moodalbail 	ipadm_if_info_t	*last = NULL;
916e91bba0SGirish Moodalbail 	ipadm_if_info_t	*ifp;
926e91bba0SGirish Moodalbail 	int		s;
936e91bba0SGirish Moodalbail 	int		n;
946e91bba0SGirish Moodalbail 	int		numifs;
956e91bba0SGirish Moodalbail 	ipadm_status_t	status;
966e91bba0SGirish Moodalbail 
976e91bba0SGirish Moodalbail 	*if_info = NULL;
986e91bba0SGirish Moodalbail 	/*
996e91bba0SGirish Moodalbail 	 * Get information for all interfaces.
1006e91bba0SGirish Moodalbail 	 */
1016e91bba0SGirish Moodalbail 	if (getallifs(iph->iph_sock, 0, &buf, &numifs, lifc_flags) != 0)
1026e91bba0SGirish Moodalbail 		return (ipadm_errno2status(errno));
1036e91bba0SGirish Moodalbail 
1046e91bba0SGirish Moodalbail 	lifrp = buf;
1056e91bba0SGirish Moodalbail 	for (n = 0; n < numifs; n++, lifrp++) {
1066e91bba0SGirish Moodalbail 		/* Skip interfaces with logical num != 0 */
1076e91bba0SGirish Moodalbail 		if (i_ipadm_get_lnum(lifrp->lifr_name) != 0)
1086e91bba0SGirish Moodalbail 			continue;
1096e91bba0SGirish Moodalbail 		/*
1106e91bba0SGirish Moodalbail 		 * Skip the current interface if a specific `ifname' has
1116e91bba0SGirish Moodalbail 		 * been requested and current interface does not match
1126e91bba0SGirish Moodalbail 		 * `ifname'.
1136e91bba0SGirish Moodalbail 		 */
1146e91bba0SGirish Moodalbail 		if (ifname != NULL && strcmp(lifrp->lifr_name, ifname) != 0)
1156e91bba0SGirish Moodalbail 			continue;
1166e91bba0SGirish Moodalbail 		/*
1176e91bba0SGirish Moodalbail 		 * Check if the interface already exists in our list.
1186e91bba0SGirish Moodalbail 		 * If it already exists, we need to update its flags.
1196e91bba0SGirish Moodalbail 		 */
1206e91bba0SGirish Moodalbail 		for (ifp = *if_info; ifp != NULL; ifp = ifp->ifi_next) {
1216e91bba0SGirish Moodalbail 			if (strcmp(lifrp->lifr_name, ifp->ifi_name) == 0)
1226e91bba0SGirish Moodalbail 				break;
1236e91bba0SGirish Moodalbail 		}
1246e91bba0SGirish Moodalbail 		if (ifp == NULL) {
1256e91bba0SGirish Moodalbail 			ifp = calloc(1, sizeof (ipadm_if_info_t));
1266e91bba0SGirish Moodalbail 			if (ifp == NULL) {
1276e91bba0SGirish Moodalbail 				status = ipadm_errno2status(errno);
1286e91bba0SGirish Moodalbail 				goto fail;
1296e91bba0SGirish Moodalbail 			}
1306e91bba0SGirish Moodalbail 			(void) strlcpy(ifp->ifi_name, lifrp->lifr_name,
1316e91bba0SGirish Moodalbail 			    sizeof (ifp->ifi_name));
1326e91bba0SGirish Moodalbail 			/* Update the `ifi_next' pointer for this new node */
1336e91bba0SGirish Moodalbail 			if (*if_info == NULL)
1346e91bba0SGirish Moodalbail 				*if_info = ifp;
1356e91bba0SGirish Moodalbail 			else
1366e91bba0SGirish Moodalbail 				last->ifi_next = ifp;
1376e91bba0SGirish Moodalbail 			last = ifp;
1386e91bba0SGirish Moodalbail 		}
1396e91bba0SGirish Moodalbail 
1406e91bba0SGirish Moodalbail 		/*
1416e91bba0SGirish Moodalbail 		 * Retrieve the flags for the interface by doing a
1426e91bba0SGirish Moodalbail 		 * SIOCGLIFFLAGS to populate the `ifi_cflags' field.
1436e91bba0SGirish Moodalbail 		 */
1446e91bba0SGirish Moodalbail 		(void) strlcpy(lifrl.lifr_name,
1456e91bba0SGirish Moodalbail 		    lifrp->lifr_name, sizeof (lifrl.lifr_name));
1466e91bba0SGirish Moodalbail 		s = (lifrp->lifr_addr.ss_family == AF_INET) ?
1476e91bba0SGirish Moodalbail 		    iph->iph_sock : iph->iph_sock6;
1486e91bba0SGirish Moodalbail 		if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifrl) < 0)
1496e91bba0SGirish Moodalbail 			continue;
1506e91bba0SGirish Moodalbail 		if (lifrl.lifr_flags & IFF_BROADCAST)
1516e91bba0SGirish Moodalbail 			ifp->ifi_cflags |= IFIF_BROADCAST;
1526e91bba0SGirish Moodalbail 		if (lifrl.lifr_flags & IFF_MULTICAST)
1536e91bba0SGirish Moodalbail 			ifp->ifi_cflags |= IFIF_MULTICAST;
1546e91bba0SGirish Moodalbail 		if (lifrl.lifr_flags & IFF_POINTOPOINT)
1556e91bba0SGirish Moodalbail 			ifp->ifi_cflags |= IFIF_POINTOPOINT;
1566e91bba0SGirish Moodalbail 		if (lifrl.lifr_flags & IFF_VIRTUAL)
1576e91bba0SGirish Moodalbail 			ifp->ifi_cflags |= IFIF_VIRTUAL;
1586e91bba0SGirish Moodalbail 		if (lifrl.lifr_flags & IFF_IPMP)
1596e91bba0SGirish Moodalbail 			ifp->ifi_cflags |= IFIF_IPMP;
1606e91bba0SGirish Moodalbail 		if (lifrl.lifr_flags & IFF_STANDBY)
1616e91bba0SGirish Moodalbail 			ifp->ifi_cflags |= IFIF_STANDBY;
1626e91bba0SGirish Moodalbail 		if (lifrl.lifr_flags & IFF_INACTIVE)
1636e91bba0SGirish Moodalbail 			ifp->ifi_cflags |= IFIF_INACTIVE;
1646e91bba0SGirish Moodalbail 		if (lifrl.lifr_flags & IFF_VRRP)
1656e91bba0SGirish Moodalbail 			ifp->ifi_cflags |= IFIF_VRRP;
1666e91bba0SGirish Moodalbail 		if (lifrl.lifr_flags & IFF_NOACCEPT)
1676e91bba0SGirish Moodalbail 			ifp->ifi_cflags |= IFIF_NOACCEPT;
1686e91bba0SGirish Moodalbail 		if (lifrl.lifr_flags & IFF_IPV4)
1696e91bba0SGirish Moodalbail 			ifp->ifi_cflags |= IFIF_IPV4;
1706e91bba0SGirish Moodalbail 		if (lifrl.lifr_flags & IFF_IPV6)
1716e91bba0SGirish Moodalbail 			ifp->ifi_cflags |= IFIF_IPV6;
172*550b6e40SSowmini Varadhan 		if (lifrl.lifr_flags & IFF_L3PROTECT)
173*550b6e40SSowmini Varadhan 			ifp->ifi_cflags |= IFIF_L3PROTECT;
1746e91bba0SGirish Moodalbail 	}
1756e91bba0SGirish Moodalbail 	free(buf);
1766e91bba0SGirish Moodalbail 	return (IPADM_SUCCESS);
1776e91bba0SGirish Moodalbail fail:
1786e91bba0SGirish Moodalbail 	free(buf);
1796e91bba0SGirish Moodalbail 	ipadm_free_if_info(*if_info);
1806e91bba0SGirish Moodalbail 	*if_info = NULL;
1816e91bba0SGirish Moodalbail 	return (status);
1826e91bba0SGirish Moodalbail }
1836e91bba0SGirish Moodalbail 
1846e91bba0SGirish Moodalbail /*
1856e91bba0SGirish Moodalbail  * Returns the interface information for `ifname' in `if_info' from persistent
1866e91bba0SGirish Moodalbail  * config if `ifname' is non-null. Otherwise, it returns all the interfaces
1876e91bba0SGirish Moodalbail  * from persistent config in `if_info'.
1886e91bba0SGirish Moodalbail  */
1896e91bba0SGirish Moodalbail static ipadm_status_t
1906e91bba0SGirish Moodalbail i_ipadm_persist_if_info(ipadm_handle_t iph, const char *ifname,
1916e91bba0SGirish Moodalbail     ipadm_if_info_t **if_info)
1926e91bba0SGirish Moodalbail {
1936e91bba0SGirish Moodalbail 	ipadm_status_t		status = IPADM_SUCCESS;
1946e91bba0SGirish Moodalbail 	ipmgmt_getif_arg_t	getif;
1956e91bba0SGirish Moodalbail 	ipmgmt_getif_rval_t	*rvalp;
1966e91bba0SGirish Moodalbail 	ipadm_if_info_t		*ifp, *curr, *prev = NULL;
1976e91bba0SGirish Moodalbail 	int			i = 0, err = 0;
1986e91bba0SGirish Moodalbail 
1996e91bba0SGirish Moodalbail 	bzero(&getif, sizeof (getif));
2006e91bba0SGirish Moodalbail 	if (ifname != NULL)
2016e91bba0SGirish Moodalbail 		(void) strlcpy(getif.ia_ifname, ifname, LIFNAMSIZ);
2026e91bba0SGirish Moodalbail 	getif.ia_cmd = IPMGMT_CMD_GETIF;
2036e91bba0SGirish Moodalbail 
2046e91bba0SGirish Moodalbail 	*if_info = NULL;
2056e91bba0SGirish Moodalbail 
2066e91bba0SGirish Moodalbail 	if ((rvalp = malloc(sizeof (ipmgmt_getif_rval_t))) == NULL)
2076e91bba0SGirish Moodalbail 		return (ipadm_errno2status(errno));
2086e91bba0SGirish Moodalbail 	err = ipadm_door_call(iph, &getif, sizeof (getif), (void **)&rvalp,
2096e91bba0SGirish Moodalbail 	    sizeof (*rvalp), B_TRUE);
2106e91bba0SGirish Moodalbail 	if (err == ENOENT) {
2116e91bba0SGirish Moodalbail 		free(rvalp);
2126e91bba0SGirish Moodalbail 		if (ifname != NULL)
2136e91bba0SGirish Moodalbail 			return (ipadm_errno2status(err));
2146e91bba0SGirish Moodalbail 		return (IPADM_SUCCESS);
2156e91bba0SGirish Moodalbail 	} else if (err != 0) {
2166e91bba0SGirish Moodalbail 		free(rvalp);
2176e91bba0SGirish Moodalbail 		return (ipadm_errno2status(err));
2186e91bba0SGirish Moodalbail 	}
2196e91bba0SGirish Moodalbail 
2206e91bba0SGirish Moodalbail 	ifp = rvalp->ir_ifinfo;
2216e91bba0SGirish Moodalbail 	for (i = 0; i < rvalp->ir_ifcnt; i++) {
2226e91bba0SGirish Moodalbail 		ifp = rvalp->ir_ifinfo + i;
2236e91bba0SGirish Moodalbail 		if ((curr = malloc(sizeof (*curr))) == NULL) {
2246e91bba0SGirish Moodalbail 			status = ipadm_errno2status(errno);
2256e91bba0SGirish Moodalbail 			ipadm_free_if_info(prev);
2266e91bba0SGirish Moodalbail 			break;
2276e91bba0SGirish Moodalbail 		}
2286e91bba0SGirish Moodalbail 		(void) bcopy(ifp, curr, sizeof (*curr));
2296e91bba0SGirish Moodalbail 		curr->ifi_next = prev;
2306e91bba0SGirish Moodalbail 		prev = curr;
2316e91bba0SGirish Moodalbail 	}
2326e91bba0SGirish Moodalbail 	*if_info = curr;
2336e91bba0SGirish Moodalbail 	free(rvalp);
2346e91bba0SGirish Moodalbail 	return (status);
2356e91bba0SGirish Moodalbail }
2366e91bba0SGirish Moodalbail 
2376e91bba0SGirish Moodalbail /*
2386e91bba0SGirish Moodalbail  * Collects information for `ifname' if one is specified from both
2396e91bba0SGirish Moodalbail  * active and persistent config in `if_info'. If no `ifname' is specified,
2406e91bba0SGirish Moodalbail  * this returns all the interfaces in active and persistent config in
2416e91bba0SGirish Moodalbail  * `if_info'.
2426e91bba0SGirish Moodalbail  */
2436e91bba0SGirish Moodalbail ipadm_status_t
2446e91bba0SGirish Moodalbail i_ipadm_get_all_if_info(ipadm_handle_t iph, const char *ifname,
2456e91bba0SGirish Moodalbail     ipadm_if_info_t **if_info, int64_t lifc_flags)
2466e91bba0SGirish Moodalbail {
2476e91bba0SGirish Moodalbail 	ipadm_status_t	status;
2486e91bba0SGirish Moodalbail 	ipadm_if_info_t	*aifinfo = NULL;
2496e91bba0SGirish Moodalbail 	ipadm_if_info_t	*pifinfo = NULL;
2506e91bba0SGirish Moodalbail 	ipadm_if_info_t	*aifp;
2516e91bba0SGirish Moodalbail 	ipadm_if_info_t	*pifp;
2526e91bba0SGirish Moodalbail 	ipadm_if_info_t	*last = NULL;
2536e91bba0SGirish Moodalbail 	struct ifaddrs	*ifa;
2546e91bba0SGirish Moodalbail 	struct ifaddrs	*ifap;
2556e91bba0SGirish Moodalbail 
2566e91bba0SGirish Moodalbail 	/*
2576e91bba0SGirish Moodalbail 	 * Retrive the information for the requested `ifname' or all
2586e91bba0SGirish Moodalbail 	 * interfaces from active configuration.
2596e91bba0SGirish Moodalbail 	 */
2606e91bba0SGirish Moodalbail retry:
2616e91bba0SGirish Moodalbail 	status = i_ipadm_active_if_info(iph, ifname, &aifinfo, lifc_flags);
2626e91bba0SGirish Moodalbail 	if (status != IPADM_SUCCESS)
2636e91bba0SGirish Moodalbail 		return (status);
2646e91bba0SGirish Moodalbail 	/* Get the interface state for each interface in `aifinfo'. */
2656e91bba0SGirish Moodalbail 	if (aifinfo != NULL) {
2666e91bba0SGirish Moodalbail 		/* We need all addresses to get the interface state */
2676e91bba0SGirish Moodalbail 		if (getallifaddrs(AF_UNSPEC, &ifa, (LIFC_NOXMIT|LIFC_TEMPORARY|
2686e91bba0SGirish Moodalbail 		    LIFC_ALLZONES|LIFC_UNDER_IPMP)) != 0) {
2696e91bba0SGirish Moodalbail 			status = ipadm_errno2status(errno);
2706e91bba0SGirish Moodalbail 			goto fail;
2716e91bba0SGirish Moodalbail 		}
2726e91bba0SGirish Moodalbail 		for (aifp = aifinfo; aifp != NULL; aifp = aifp->ifi_next) {
2736e91bba0SGirish Moodalbail 			/*
2746e91bba0SGirish Moodalbail 			 * Find the `ifaddrs' structure from `ifa'
2756e91bba0SGirish Moodalbail 			 * for this interface. We need the IFF_* flags
2766e91bba0SGirish Moodalbail 			 * to find the interface state.
2776e91bba0SGirish Moodalbail 			 */
2786e91bba0SGirish Moodalbail 			for (ifap = ifa; ifap != NULL; ifap = ifap->ifa_next) {
2796e91bba0SGirish Moodalbail 				if (strcmp(ifap->ifa_name, aifp->ifi_name) == 0)
2806e91bba0SGirish Moodalbail 					break;
2816e91bba0SGirish Moodalbail 			}
2826e91bba0SGirish Moodalbail 			if (ifap == NULL) {
2836e91bba0SGirish Moodalbail 				/*
2846e91bba0SGirish Moodalbail 				 * The interface might have been removed
2856e91bba0SGirish Moodalbail 				 * from kernel. Retry getting all the active
2866e91bba0SGirish Moodalbail 				 * interfaces.
2876e91bba0SGirish Moodalbail 				 */
2886e91bba0SGirish Moodalbail 				freeifaddrs(ifa);
2896e91bba0SGirish Moodalbail 				ipadm_free_if_info(aifinfo);
2906e91bba0SGirish Moodalbail 				aifinfo = NULL;
2916e91bba0SGirish Moodalbail 				goto retry;
2926e91bba0SGirish Moodalbail 			}
2936e91bba0SGirish Moodalbail 			if (!(ifap->ifa_flags & IFF_RUNNING) ||
2946e91bba0SGirish Moodalbail 			    (ifap->ifa_flags & IFF_FAILED))
2956e91bba0SGirish Moodalbail 				aifp->ifi_state = IFIS_FAILED;
2966e91bba0SGirish Moodalbail 			else if (ifap->ifa_flags & IFF_OFFLINE)
2976e91bba0SGirish Moodalbail 				aifp->ifi_state = IFIS_OFFLINE;
2986e91bba0SGirish Moodalbail 			else if (i_ipadm_is_if_down(aifp->ifi_name, ifa))
2996e91bba0SGirish Moodalbail 				aifp->ifi_state = IFIS_DOWN;
3006e91bba0SGirish Moodalbail 			else
3016e91bba0SGirish Moodalbail 				aifp->ifi_state = IFIS_OK;
3026e91bba0SGirish Moodalbail 			if (aifp->ifi_next == NULL)
3036e91bba0SGirish Moodalbail 				last = aifp;
3046e91bba0SGirish Moodalbail 		}
3056e91bba0SGirish Moodalbail 		freeifaddrs(ifa);
3066e91bba0SGirish Moodalbail 	}
3076e91bba0SGirish Moodalbail 	/*
3086e91bba0SGirish Moodalbail 	 * Get the persistent interface information in `pifinfo'.
3096e91bba0SGirish Moodalbail 	 */
3106e91bba0SGirish Moodalbail 	status = i_ipadm_persist_if_info(iph, ifname, &pifinfo);
3116e91bba0SGirish Moodalbail 	if (status == IPADM_NOTFOUND) {
3126e91bba0SGirish Moodalbail 		*if_info = aifinfo;
3136e91bba0SGirish Moodalbail 		return (IPADM_SUCCESS);
3146e91bba0SGirish Moodalbail 	}
3156e91bba0SGirish Moodalbail 	if (status != IPADM_SUCCESS)
3166e91bba0SGirish Moodalbail 		goto fail;
3176e91bba0SGirish Moodalbail 	/*
3186e91bba0SGirish Moodalbail 	 * If a persistent interface is also found in `aifinfo', update
3196e91bba0SGirish Moodalbail 	 * its entry in `aifinfo' with the persistent information from
3206e91bba0SGirish Moodalbail 	 * `pifinfo'. If an interface is found in `pifinfo', but not in
3216e91bba0SGirish Moodalbail 	 * `aifinfo', it means that this interface was disabled. We should
3226e91bba0SGirish Moodalbail 	 * add this interface to `aifinfo' and set it state to IFIF_DISABLED.
3236e91bba0SGirish Moodalbail 	 */
3246e91bba0SGirish Moodalbail 	for (pifp = pifinfo; pifp != NULL; pifp = pifp->ifi_next) {
3256e91bba0SGirish Moodalbail 		for (aifp = aifinfo; aifp != NULL; aifp = aifp->ifi_next) {
3266e91bba0SGirish Moodalbail 			if (strcmp(aifp->ifi_name, pifp->ifi_name) == 0) {
3276e91bba0SGirish Moodalbail 				aifp->ifi_pflags = pifp->ifi_pflags;
3286e91bba0SGirish Moodalbail 				break;
3296e91bba0SGirish Moodalbail 			}
3306e91bba0SGirish Moodalbail 		}
3316e91bba0SGirish Moodalbail 		if (aifp == NULL) {
3326e91bba0SGirish Moodalbail 			aifp = malloc(sizeof (ipadm_if_info_t));
3336e91bba0SGirish Moodalbail 			if (aifp == NULL) {
3346e91bba0SGirish Moodalbail 				status = ipadm_errno2status(errno);
3356e91bba0SGirish Moodalbail 				goto fail;
3366e91bba0SGirish Moodalbail 			}
3376e91bba0SGirish Moodalbail 			*aifp = *pifp;
3386e91bba0SGirish Moodalbail 			aifp->ifi_next = NULL;
3396e91bba0SGirish Moodalbail 			aifp->ifi_state = IFIS_DISABLED;
3406e91bba0SGirish Moodalbail 			if (last != NULL)
3416e91bba0SGirish Moodalbail 				last->ifi_next = aifp;
3426e91bba0SGirish Moodalbail 			else
3436e91bba0SGirish Moodalbail 				aifinfo = aifp;
3446e91bba0SGirish Moodalbail 			last = aifp;
3456e91bba0SGirish Moodalbail 		}
3466e91bba0SGirish Moodalbail 	}
3476e91bba0SGirish Moodalbail 	*if_info = aifinfo;
3486e91bba0SGirish Moodalbail 	ipadm_free_if_info(pifinfo);
3496e91bba0SGirish Moodalbail 	return (IPADM_SUCCESS);
3506e91bba0SGirish Moodalbail fail:
3516e91bba0SGirish Moodalbail 	*if_info = NULL;
3526e91bba0SGirish Moodalbail 	ipadm_free_if_info(aifinfo);
3536e91bba0SGirish Moodalbail 	ipadm_free_if_info(pifinfo);
3546e91bba0SGirish Moodalbail 	return (status);
3556e91bba0SGirish Moodalbail }
3566e91bba0SGirish Moodalbail 
3576e91bba0SGirish Moodalbail int
3586e91bba0SGirish Moodalbail i_ipadm_get_lnum(const char *ifname)
3596e91bba0SGirish Moodalbail {
3606e91bba0SGirish Moodalbail 	char *num = strrchr(ifname, IPADM_LOGICAL_SEP);
3616e91bba0SGirish Moodalbail 
3626e91bba0SGirish Moodalbail 	if (num == NULL)
3636e91bba0SGirish Moodalbail 		return (0);
3646e91bba0SGirish Moodalbail 
3656e91bba0SGirish Moodalbail 	return (atoi(++num));
3666e91bba0SGirish Moodalbail }
3676e91bba0SGirish Moodalbail 
3686e91bba0SGirish Moodalbail /*
3696e91bba0SGirish Moodalbail  * Sets the output argument `exists' to true or false based on whether
3706e91bba0SGirish Moodalbail  * any persistent configuration is available for `ifname' and returns
3716e91bba0SGirish Moodalbail  * IPADM_SUCCESS as status. If the persistent information cannot be retrieved,
3726e91bba0SGirish Moodalbail  * `exists' is unmodified and an error status is returned.
3736e91bba0SGirish Moodalbail  */
3746e91bba0SGirish Moodalbail ipadm_status_t
3756e91bba0SGirish Moodalbail i_ipadm_if_pexists(ipadm_handle_t iph, const char *ifname, sa_family_t af,
3766e91bba0SGirish Moodalbail     boolean_t *exists)
3776e91bba0SGirish Moodalbail {
3786e91bba0SGirish Moodalbail 	ipadm_if_info_t	*ifinfo;
3796e91bba0SGirish Moodalbail 	ipadm_status_t	status;
3806e91bba0SGirish Moodalbail 
381*550b6e40SSowmini Varadhan 	/*
382*550b6e40SSowmini Varadhan 	 * if IPH_IPMGMTD is set, we know that the caller (ipmgmtd) already
383*550b6e40SSowmini Varadhan 	 * knows about persistent configuration in the first place, so we
384*550b6e40SSowmini Varadhan 	 * just return success.
385*550b6e40SSowmini Varadhan 	 */
386*550b6e40SSowmini Varadhan 	if (iph->iph_flags & IPH_IPMGMTD) {
387*550b6e40SSowmini Varadhan 		*exists = B_FALSE;
388*550b6e40SSowmini Varadhan 		return (IPADM_SUCCESS);
389*550b6e40SSowmini Varadhan 	}
3906e91bba0SGirish Moodalbail 	status = i_ipadm_persist_if_info(iph, ifname, &ifinfo);
3916e91bba0SGirish Moodalbail 	if (status == IPADM_SUCCESS) {
3926e91bba0SGirish Moodalbail 		*exists = ((af == AF_INET &&
3936e91bba0SGirish Moodalbail 		    (ifinfo->ifi_pflags & IFIF_IPV4)) ||
3946e91bba0SGirish Moodalbail 		    (af == AF_INET6 &&
3956e91bba0SGirish Moodalbail 		    (ifinfo->ifi_pflags & IFIF_IPV6)));
3966e91bba0SGirish Moodalbail 		free(ifinfo);
3976e91bba0SGirish Moodalbail 	} else if (status == IPADM_NOTFOUND) {
3986e91bba0SGirish Moodalbail 		status = IPADM_SUCCESS;
3996e91bba0SGirish Moodalbail 		*exists = B_FALSE;
4006e91bba0SGirish Moodalbail 	}
4016e91bba0SGirish Moodalbail 	return (status);
4026e91bba0SGirish Moodalbail }
4036e91bba0SGirish Moodalbail 
4046e91bba0SGirish Moodalbail /*
4056e91bba0SGirish Moodalbail  * Open "/dev/udp{,6}" for use as a multiplexor to PLINK the interface stream
4066e91bba0SGirish Moodalbail  * under. We use "/dev/udp" instead of "/dev/ip" since STREAMS will not let
4076e91bba0SGirish Moodalbail  * you PLINK a driver under itself, and "/dev/ip" is typically the driver at
4086e91bba0SGirish Moodalbail  * the bottom of the stream for tunneling interfaces.
4096e91bba0SGirish Moodalbail  */
4106e91bba0SGirish Moodalbail ipadm_status_t
4116e91bba0SGirish Moodalbail ipadm_open_arp_on_udp(const char *udp_dev_name, int *fd)
4126e91bba0SGirish Moodalbail {
4136e91bba0SGirish Moodalbail 	int err;
4146e91bba0SGirish Moodalbail 
4156e91bba0SGirish Moodalbail 	if ((*fd = open(udp_dev_name, O_RDWR)) == -1)
4166e91bba0SGirish Moodalbail 		return (ipadm_errno2status(errno));
4176e91bba0SGirish Moodalbail 
4186e91bba0SGirish Moodalbail 	/*
4196e91bba0SGirish Moodalbail 	 * Pop off all undesired modules (note that the user may have
4206e91bba0SGirish Moodalbail 	 * configured autopush to add modules above udp), and push the
4216e91bba0SGirish Moodalbail 	 * arp module onto the resulting stream. This is used to make
4226e91bba0SGirish Moodalbail 	 * IP+ARP be able to atomically track the muxid for the I_PLINKed
4236e91bba0SGirish Moodalbail 	 * STREAMS, thus it isn't related to ARP running the ARP protocol.
4246e91bba0SGirish Moodalbail 	 */
4256e91bba0SGirish Moodalbail 	while (ioctl(*fd, I_POP, 0) != -1)
4266e91bba0SGirish Moodalbail 		;
4276e91bba0SGirish Moodalbail 	if (errno == EINVAL && ioctl(*fd, I_PUSH, ARP_MOD_NAME) != -1)
4286e91bba0SGirish Moodalbail 		return (IPADM_SUCCESS);
4296e91bba0SGirish Moodalbail 	err = errno;
4306e91bba0SGirish Moodalbail 	(void) close(*fd);
4316e91bba0SGirish Moodalbail 
4326e91bba0SGirish Moodalbail 	return (ipadm_errno2status(err));
4336e91bba0SGirish Moodalbail }
4346e91bba0SGirish Moodalbail 
4356e91bba0SGirish Moodalbail /*
4366e91bba0SGirish Moodalbail  * i_ipadm_create_ipmp() is called from i_ipadm_create_ipmp_peer() when an
4376e91bba0SGirish Moodalbail  * underlying interface in an ipmp group G is plumbed for an address family,
4386e91bba0SGirish Moodalbail  * but the meta-interface for the other address family `af' does not exist
4396e91bba0SGirish Moodalbail  * yet for the group G. If `af' is IPv6, we need to bring up the
4406e91bba0SGirish Moodalbail  * link-local address.
4416e91bba0SGirish Moodalbail  */
4426e91bba0SGirish Moodalbail static ipadm_status_t
4436e91bba0SGirish Moodalbail i_ipadm_create_ipmp(ipadm_handle_t iph, char *ifname, sa_family_t af,
4446e91bba0SGirish Moodalbail     const char *grname, uint32_t ipadm_flags)
4456e91bba0SGirish Moodalbail {
4466e91bba0SGirish Moodalbail 	ipadm_status_t	status;
4476e91bba0SGirish Moodalbail 	struct lifreq	lifr;
4486e91bba0SGirish Moodalbail 	int		sock;
4496e91bba0SGirish Moodalbail 	int		err;
4506e91bba0SGirish Moodalbail 
4516e91bba0SGirish Moodalbail 	assert(ipadm_flags & IPADM_OPT_IPMP);
4526e91bba0SGirish Moodalbail 
4536e91bba0SGirish Moodalbail 	/* Create the ipmp underlying interface */
4546e91bba0SGirish Moodalbail 	status = i_ipadm_create_if(iph, ifname, af, ipadm_flags);
4556e91bba0SGirish Moodalbail 	if (status != IPADM_SUCCESS && status != IPADM_IF_EXISTS)
4566e91bba0SGirish Moodalbail 		return (status);
4576e91bba0SGirish Moodalbail 
4586e91bba0SGirish Moodalbail 	/*
4596e91bba0SGirish Moodalbail 	 * To preserve backward-compatibility, always bring up the link-local
4606e91bba0SGirish Moodalbail 	 * address for implicitly-created IPv6 IPMP interfaces.
4616e91bba0SGirish Moodalbail 	 */
4626e91bba0SGirish Moodalbail 	if (af == AF_INET6)
4636e91bba0SGirish Moodalbail 		(void) i_ipadm_set_flags(iph, ifname, AF_INET6, IFF_UP, 0);
4646e91bba0SGirish Moodalbail 
4656e91bba0SGirish Moodalbail 	sock = (af == AF_INET ? iph->iph_sock : iph->iph_sock6);
4666e91bba0SGirish Moodalbail 	/*
4676e91bba0SGirish Moodalbail 	 * If the caller requested a different group name, issue a
4686e91bba0SGirish Moodalbail 	 * SIOCSLIFGROUPNAME on the new IPMP interface.
4696e91bba0SGirish Moodalbail 	 */
4706e91bba0SGirish Moodalbail 	bzero(&lifr, sizeof (lifr));
4716e91bba0SGirish Moodalbail 	(void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
4726e91bba0SGirish Moodalbail 	if (strcmp(lifr.lifr_name, grname) != 0) {
4736e91bba0SGirish Moodalbail 		(void) strlcpy(lifr.lifr_groupname, grname, LIFGRNAMSIZ);
4746e91bba0SGirish Moodalbail 		if (ioctl(sock, SIOCSLIFGROUPNAME, &lifr) == -1) {
4756e91bba0SGirish Moodalbail 			err = errno;
4766e91bba0SGirish Moodalbail 			/* Remove the interface we created. */
4776e91bba0SGirish Moodalbail 			if (status == IPADM_SUCCESS) {
4786e91bba0SGirish Moodalbail 				(void) i_ipadm_delete_if(iph, ifname, af,
4796e91bba0SGirish Moodalbail 				    ipadm_flags);
4806e91bba0SGirish Moodalbail 			}
4816e91bba0SGirish Moodalbail 			return (ipadm_errno2status(err));
4826e91bba0SGirish Moodalbail 		}
4836e91bba0SGirish Moodalbail 	}
4846e91bba0SGirish Moodalbail 
4856e91bba0SGirish Moodalbail 	return (IPADM_SUCCESS);
4866e91bba0SGirish Moodalbail }
4876e91bba0SGirish Moodalbail 
4886e91bba0SGirish Moodalbail /*
4896e91bba0SGirish Moodalbail  * Checks if `ifname' is plumbed and in an IPMP group on its "other" address
4906e91bba0SGirish Moodalbail  * family.  If so, create a matching IPMP group for address family `af'.
4916e91bba0SGirish Moodalbail  */
4926e91bba0SGirish Moodalbail static ipadm_status_t
4936e91bba0SGirish Moodalbail i_ipadm_create_ipmp_peer(ipadm_handle_t iph, char *ifname, sa_family_t af)
4946e91bba0SGirish Moodalbail {
4956e91bba0SGirish Moodalbail 	lifgroupinfo_t	lifgr;
4966e91bba0SGirish Moodalbail 	ipadm_status_t	status = IPADM_SUCCESS;
4976e91bba0SGirish Moodalbail 	struct lifreq	lifr;
4986e91bba0SGirish Moodalbail 	int 		other_af_sock;
4996e91bba0SGirish Moodalbail 
5006e91bba0SGirish Moodalbail 	assert(af == AF_INET || af == AF_INET6);
5016e91bba0SGirish Moodalbail 
5026e91bba0SGirish Moodalbail 	other_af_sock = (af == AF_INET ? iph->iph_sock6 : iph->iph_sock);
5036e91bba0SGirish Moodalbail 
5046e91bba0SGirish Moodalbail 	/*
5056e91bba0SGirish Moodalbail 	 * iph is the handle for the interface that we are trying to plumb.
5066e91bba0SGirish Moodalbail 	 * other_af_sock is the socket for the "other" address family.
5076e91bba0SGirish Moodalbail 	 */
5086e91bba0SGirish Moodalbail 	bzero(&lifr, sizeof (lifr));
5096e91bba0SGirish Moodalbail 	(void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
5106e91bba0SGirish Moodalbail 	if (ioctl(other_af_sock, SIOCGLIFGROUPNAME, &lifr) != 0)
5116e91bba0SGirish Moodalbail 		return (IPADM_SUCCESS);
5126e91bba0SGirish Moodalbail 
5136e91bba0SGirish Moodalbail 	(void) strlcpy(lifgr.gi_grname, lifr.lifr_groupname, LIFGRNAMSIZ);
5146e91bba0SGirish Moodalbail 	if (ioctl(other_af_sock, SIOCGLIFGROUPINFO, &lifgr) != 0)
5156e91bba0SGirish Moodalbail 		return (IPADM_SUCCESS);
5166e91bba0SGirish Moodalbail 
5176e91bba0SGirish Moodalbail 	/*
5186e91bba0SGirish Moodalbail 	 * If `ifname' *is* the IPMP group interface, or if the relevant
5196e91bba0SGirish Moodalbail 	 * address family is already configured, then there's nothing to do.
5206e91bba0SGirish Moodalbail 	 */
5216e91bba0SGirish Moodalbail 	if (strcmp(lifgr.gi_grifname, ifname) == 0 ||
5226e91bba0SGirish Moodalbail 	    (af == AF_INET && lifgr.gi_v4) || (af == AF_INET6 && lifgr.gi_v6)) {
5236e91bba0SGirish Moodalbail 		return (IPADM_SUCCESS);
5246e91bba0SGirish Moodalbail 	}
5256e91bba0SGirish Moodalbail 
5266e91bba0SGirish Moodalbail 	status = i_ipadm_create_ipmp(iph, lifgr.gi_grifname, af,
5276e91bba0SGirish Moodalbail 	    lifgr.gi_grname, IPADM_OPT_ACTIVE|IPADM_OPT_IPMP);
5286e91bba0SGirish Moodalbail 	return (status);
5296e91bba0SGirish Moodalbail }
5306e91bba0SGirish Moodalbail 
5316e91bba0SGirish Moodalbail /*
5326e91bba0SGirish Moodalbail  * Issues the ioctl SIOCSLIFNAME to kernel on the given ARP stream fd.
5336e91bba0SGirish Moodalbail  */
5346e91bba0SGirish Moodalbail static ipadm_status_t
5356e91bba0SGirish Moodalbail i_ipadm_slifname_arp(char *ifname, uint64_t flags, int fd)
5366e91bba0SGirish Moodalbail {
5376e91bba0SGirish Moodalbail 	struct lifreq	lifr;
5386e91bba0SGirish Moodalbail 	ifspec_t	ifsp;
5396e91bba0SGirish Moodalbail 
5406e91bba0SGirish Moodalbail 	bzero(&lifr, sizeof (lifr));
5416e91bba0SGirish Moodalbail 	(void) ifparse_ifspec(ifname, &ifsp);
5426e91bba0SGirish Moodalbail 	lifr.lifr_ppa = ifsp.ifsp_ppa;
5436e91bba0SGirish Moodalbail 	lifr.lifr_flags = flags;
5446e91bba0SGirish Moodalbail 	(void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
5456e91bba0SGirish Moodalbail 	/*
5466e91bba0SGirish Moodalbail 	 * Tell ARP the name and unit number for this interface.
5476e91bba0SGirish Moodalbail 	 * Note that arp has no support for transparent ioctls.
5486e91bba0SGirish Moodalbail 	 */
5496e91bba0SGirish Moodalbail 	if (i_ipadm_strioctl(fd, SIOCSLIFNAME, (char *)&lifr,
5506e91bba0SGirish Moodalbail 	    sizeof (lifr)) == -1) {
5516e91bba0SGirish Moodalbail 		return (ipadm_errno2status(errno));
5526e91bba0SGirish Moodalbail 	}
5536e91bba0SGirish Moodalbail 	return (IPADM_SUCCESS);
5546e91bba0SGirish Moodalbail }
5556e91bba0SGirish Moodalbail 
5566e91bba0SGirish Moodalbail /*
5576e91bba0SGirish Moodalbail  * Issues the ioctl SIOCSLIFNAME to kernel. If IPADM_OPT_GENPPA is set in
5586e91bba0SGirish Moodalbail  * `ipadm_flags', then a ppa will be generated. `newif' will be updated
5596e91bba0SGirish Moodalbail  * with the generated ppa.
5606e91bba0SGirish Moodalbail  */
5616e91bba0SGirish Moodalbail static ipadm_status_t
5626e91bba0SGirish Moodalbail i_ipadm_slifname(ipadm_handle_t iph, char *ifname, char *newif, uint64_t flags,
5636e91bba0SGirish Moodalbail     int fd, uint32_t ipadm_flags)
5646e91bba0SGirish Moodalbail {
5656e91bba0SGirish Moodalbail 	struct lifreq	lifr;
5666e91bba0SGirish Moodalbail 	ipadm_status_t	status = IPADM_SUCCESS;
5676e91bba0SGirish Moodalbail 	int		err = 0;
5686e91bba0SGirish Moodalbail 	sa_family_t	af;
5696e91bba0SGirish Moodalbail 	int		ppa;
5706e91bba0SGirish Moodalbail 	ifspec_t	ifsp;
5716e91bba0SGirish Moodalbail 	boolean_t	valid_if;
5726e91bba0SGirish Moodalbail 
5736e91bba0SGirish Moodalbail 	bzero(&lifr, sizeof (lifr));
5746e91bba0SGirish Moodalbail 	if (ipadm_flags & IPADM_OPT_GENPPA) {
5756e91bba0SGirish Moodalbail 		/*
5766e91bba0SGirish Moodalbail 		 * We'd like to just set lifr_ppa to UINT_MAX and have the
5776e91bba0SGirish Moodalbail 		 * kernel pick a PPA.  Unfortunately, that would mishandle
5786e91bba0SGirish Moodalbail 		 * two cases:
5796e91bba0SGirish Moodalbail 		 *
5806e91bba0SGirish Moodalbail 		 *	1. If the PPA is available but the groupname is taken
5816e91bba0SGirish Moodalbail 		 *	   (e.g., the "ipmp2" IP interface name is available
5826e91bba0SGirish Moodalbail 		 *	   but the "ipmp2" groupname is taken) then the
5836e91bba0SGirish Moodalbail 		 *	   auto-assignment by the kernel will fail.
5846e91bba0SGirish Moodalbail 		 *
5856e91bba0SGirish Moodalbail 		 *	2. If we're creating (e.g.) an IPv6-only IPMP
5866e91bba0SGirish Moodalbail 		 *	   interface, and there's already an IPv4-only IPMP
5876e91bba0SGirish Moodalbail 		 *	   interface, the kernel will allow us to accidentally
5886e91bba0SGirish Moodalbail 		 *	   reuse the IPv6 IPMP interface name (since
5896e91bba0SGirish Moodalbail 		 *	   SIOCSLIFNAME uniqueness is per-interface-type).
5906e91bba0SGirish Moodalbail 		 *	   This will cause administrative confusion.
5916e91bba0SGirish Moodalbail 		 *
5926e91bba0SGirish Moodalbail 		 * Thus, we instead take a brute-force approach of checking
5936e91bba0SGirish Moodalbail 		 * whether the IPv4 or IPv6 name is already in-use before
5946e91bba0SGirish Moodalbail 		 * attempting the SIOCSLIFNAME.  As per (1) above, the
5956e91bba0SGirish Moodalbail 		 * SIOCSLIFNAME may still fail, in which case we just proceed
5966e91bba0SGirish Moodalbail 		 * to the next one.  If this approach becomes too slow, we
5976e91bba0SGirish Moodalbail 		 * can add a new SIOC* to handle this case in the kernel.
5986e91bba0SGirish Moodalbail 		 */
5996e91bba0SGirish Moodalbail 		for (ppa = 0; ppa < UINT_MAX; ppa++) {
6006e91bba0SGirish Moodalbail 			(void) snprintf(lifr.lifr_name, LIFNAMSIZ, "%s%d",
6016e91bba0SGirish Moodalbail 			    ifname, ppa);
6026e91bba0SGirish Moodalbail 
6036e91bba0SGirish Moodalbail 			if (ioctl(iph->iph_sock, SIOCGLIFFLAGS, &lifr) != -1 ||
6046e91bba0SGirish Moodalbail 			    errno != ENXIO)
6056e91bba0SGirish Moodalbail 				continue;
6066e91bba0SGirish Moodalbail 
6076e91bba0SGirish Moodalbail 			if (ioctl(iph->iph_sock6, SIOCGLIFFLAGS, &lifr) != -1 ||
6086e91bba0SGirish Moodalbail 			    errno != ENXIO)
6096e91bba0SGirish Moodalbail 				continue;
6106e91bba0SGirish Moodalbail 
6116e91bba0SGirish Moodalbail 			lifr.lifr_ppa = ppa;
6126e91bba0SGirish Moodalbail 			lifr.lifr_flags = flags;
6136e91bba0SGirish Moodalbail 
6146e91bba0SGirish Moodalbail 			err = ioctl(fd, SIOCSLIFNAME, &lifr);
6156e91bba0SGirish Moodalbail 			if (err != -1 || errno != EEXIST)
6166e91bba0SGirish Moodalbail 				break;
6176e91bba0SGirish Moodalbail 		}
6186e91bba0SGirish Moodalbail 		if (err == -1) {
6196e91bba0SGirish Moodalbail 			status = ipadm_errno2status(errno);
6206e91bba0SGirish Moodalbail 		} else {
6216e91bba0SGirish Moodalbail 			/*
6226e91bba0SGirish Moodalbail 			 * PPA has been successfully established.
6236e91bba0SGirish Moodalbail 			 * Update `newif' with the ppa.
6246e91bba0SGirish Moodalbail 			 */
6256e91bba0SGirish Moodalbail 			assert(newif != NULL);
6266e91bba0SGirish Moodalbail 			if (snprintf(newif, LIFNAMSIZ, "%s%d", ifname,
6276e91bba0SGirish Moodalbail 			    ppa) >= LIFNAMSIZ)
6286e91bba0SGirish Moodalbail 				return (IPADM_INVALID_ARG);
6296e91bba0SGirish Moodalbail 		}
6306e91bba0SGirish Moodalbail 	} else {
6316e91bba0SGirish Moodalbail 		/* We should have already validated the interface name. */
6326e91bba0SGirish Moodalbail 		valid_if = ifparse_ifspec(ifname, &ifsp);
6336e91bba0SGirish Moodalbail 		assert(valid_if);
6346e91bba0SGirish Moodalbail 
6356e91bba0SGirish Moodalbail 		/*
6366e91bba0SGirish Moodalbail 		 * Before we call SIOCSLIFNAME, ensure that the IPMP group
6376e91bba0SGirish Moodalbail 		 * interface for this address family exists.  Otherwise, the
6386e91bba0SGirish Moodalbail 		 * kernel will kick the interface out of the group when we do
6396e91bba0SGirish Moodalbail 		 * the SIOCSLIFNAME.
6406e91bba0SGirish Moodalbail 		 *
6416e91bba0SGirish Moodalbail 		 * Example: suppose bge0 is plumbed for IPv4 and in group "a".
6426e91bba0SGirish Moodalbail 		 * If we're now plumbing bge0 for IPv6, but the IPMP group
6436e91bba0SGirish Moodalbail 		 * interface for "a" is not plumbed for IPv6, the SIOCSLIFNAME
6446e91bba0SGirish Moodalbail 		 * will kick bge0 out of group "a", which is undesired.
6456e91bba0SGirish Moodalbail 		 */
6466e91bba0SGirish Moodalbail 		if (flags & IFF_IPV4)
6476e91bba0SGirish Moodalbail 			af = AF_INET;
6486e91bba0SGirish Moodalbail 		else
6496e91bba0SGirish Moodalbail 			af = AF_INET6;
6506e91bba0SGirish Moodalbail 		status = i_ipadm_create_ipmp_peer(iph, ifname, af);
6516e91bba0SGirish Moodalbail 		if (status != IPADM_SUCCESS)
6526e91bba0SGirish Moodalbail 			return (status);
6536e91bba0SGirish Moodalbail 		lifr.lifr_ppa = ifsp.ifsp_ppa;
6546e91bba0SGirish Moodalbail 		lifr.lifr_flags = flags;
6556e91bba0SGirish Moodalbail 		(void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
6566e91bba0SGirish Moodalbail 		if (ioctl(fd, SIOCSLIFNAME, &lifr) == -1)
6576e91bba0SGirish Moodalbail 			status = ipadm_errno2status(errno);
6586e91bba0SGirish Moodalbail 	}
6596e91bba0SGirish Moodalbail 
6606e91bba0SGirish Moodalbail 	return (status);
6616e91bba0SGirish Moodalbail }
6626e91bba0SGirish Moodalbail 
6636e91bba0SGirish Moodalbail /*
6646e91bba0SGirish Moodalbail  * Plumbs the interface `ifname' for the address family `af'. It also persists
6656e91bba0SGirish Moodalbail  * the interface for `af' if IPADM_OPT_PERSIST is set in `ipadm_flags'.
6666e91bba0SGirish Moodalbail  */
6676e91bba0SGirish Moodalbail ipadm_status_t
6686e91bba0SGirish Moodalbail i_ipadm_plumb_if(ipadm_handle_t iph, char *ifname, sa_family_t af,
6696e91bba0SGirish Moodalbail     uint32_t ipadm_flags)
6706e91bba0SGirish Moodalbail {
6716e91bba0SGirish Moodalbail 	int		ip_muxid;
6726e91bba0SGirish Moodalbail 	int		mux_fd = -1, ip_fd, arp_fd;
6736e91bba0SGirish Moodalbail 	char		*udp_dev_name;
6746e91bba0SGirish Moodalbail 	dlpi_handle_t	dh_arp = NULL, dh_ip;
6756e91bba0SGirish Moodalbail 	uint64_t	ifflags;
6766e91bba0SGirish Moodalbail 	struct lifreq	lifr;
6776e91bba0SGirish Moodalbail 	uint_t		dlpi_flags;
6786e91bba0SGirish Moodalbail 	ipadm_status_t	status = IPADM_SUCCESS;
6796e91bba0SGirish Moodalbail 	char		*linkname;
6806e91bba0SGirish Moodalbail 	boolean_t	legacy = (iph->iph_flags & IPH_LEGACY);
6816e91bba0SGirish Moodalbail 	zoneid_t	zoneid;
6826e91bba0SGirish Moodalbail 	char		newif[LIFNAMSIZ];
6836e91bba0SGirish Moodalbail 	char		lifname[LIFNAMSIZ];
6846e91bba0SGirish Moodalbail 	datalink_id_t	linkid;
6856e91bba0SGirish Moodalbail 	int		sock;
6866e91bba0SGirish Moodalbail 	boolean_t	islo;
6876e91bba0SGirish Moodalbail 	boolean_t	is_persistent =
6886e91bba0SGirish Moodalbail 	    ((ipadm_flags & IPADM_OPT_PERSIST) != 0);
6896e91bba0SGirish Moodalbail 	uint32_t	dlflags;
6906e91bba0SGirish Moodalbail 	dladm_status_t	dlstatus;
6916e91bba0SGirish Moodalbail 
6926e91bba0SGirish Moodalbail 	if (iph->iph_dlh != NULL) {
6936e91bba0SGirish Moodalbail 		dlstatus = dladm_name2info(iph->iph_dlh, ifname, &linkid,
6946e91bba0SGirish Moodalbail 		    &dlflags, NULL, NULL);
6956e91bba0SGirish Moodalbail 	}
6966e91bba0SGirish Moodalbail 	/*
6976e91bba0SGirish Moodalbail 	 * If we're in the global zone and we're plumbing a datalink, make
6986e91bba0SGirish Moodalbail 	 * sure that the datalink is not assigned to a non-global zone.  Note
6996e91bba0SGirish Moodalbail 	 * that the non-global zones don't need this check, because zoneadm
7006e91bba0SGirish Moodalbail 	 * has taken care of this when the zones boot.
7016e91bba0SGirish Moodalbail 	 */
702*550b6e40SSowmini Varadhan 	if (iph->iph_zoneid == GLOBAL_ZONEID && dlstatus == DLADM_STATUS_OK) {
7036e91bba0SGirish Moodalbail 		zoneid = ALL_ZONES;
7046e91bba0SGirish Moodalbail 		if (zone_check_datalink(&zoneid, linkid) == 0) {
7056e91bba0SGirish Moodalbail 			/* interface is in use by a non-global zone. */
7066e91bba0SGirish Moodalbail 			return (IPADM_IF_INUSE);
7076e91bba0SGirish Moodalbail 		}
7086e91bba0SGirish Moodalbail 	}
7096e91bba0SGirish Moodalbail 
7106e91bba0SGirish Moodalbail 	/* loopback interfaces are just added as logical interface */
7116e91bba0SGirish Moodalbail 	bzero(&lifr, sizeof (lifr));
7126e91bba0SGirish Moodalbail 	islo = i_ipadm_is_loopback(ifname);
7136e91bba0SGirish Moodalbail 	if (islo || i_ipadm_get_lnum(ifname) != 0) {
7146e91bba0SGirish Moodalbail 		(void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
7156e91bba0SGirish Moodalbail 		if (af == AF_INET)
7166e91bba0SGirish Moodalbail 			sock = iph->iph_sock;
7176e91bba0SGirish Moodalbail 		else
7186e91bba0SGirish Moodalbail 			sock = iph->iph_sock6;
7196e91bba0SGirish Moodalbail 		if (islo && ioctl(sock, SIOCGLIFADDR, (caddr_t)&lifr) >= 0)
7206e91bba0SGirish Moodalbail 			return (IPADM_IF_EXISTS);
7216e91bba0SGirish Moodalbail 		if (ioctl(sock, SIOCLIFADDIF, (caddr_t)&lifr) < 0)
7226e91bba0SGirish Moodalbail 			return (ipadm_errno2status(errno));
7236e91bba0SGirish Moodalbail 
7246e91bba0SGirish Moodalbail 		/*
7256e91bba0SGirish Moodalbail 		 * By default, kernel configures 127.0.0.1 on the loopback
7266e91bba0SGirish Moodalbail 		 * interface. Replace this with 0.0.0.0 to be consistent
7276e91bba0SGirish Moodalbail 		 * with interface creation on other physical interfaces.
7286e91bba0SGirish Moodalbail 		 */
7296e91bba0SGirish Moodalbail 		if (islo && !legacy) {
7306e91bba0SGirish Moodalbail 			bzero(&lifr.lifr_addr, sizeof (lifr.lifr_addr));
7316e91bba0SGirish Moodalbail 			lifr.lifr_addr.ss_family = af;
7326e91bba0SGirish Moodalbail 			if (ioctl(sock, SIOCSLIFADDR, (caddr_t)&lifr) < 0)
7336e91bba0SGirish Moodalbail 				return (ipadm_errno2status(errno));
7346e91bba0SGirish Moodalbail 			if (is_persistent) {
7356e91bba0SGirish Moodalbail 				status = i_ipadm_persist_if(iph, ifname, af);
7366e91bba0SGirish Moodalbail 				if (status != IPADM_SUCCESS) {
7376e91bba0SGirish Moodalbail 					(void) i_ipadm_delete_if(iph, ifname,
7386e91bba0SGirish Moodalbail 					    af, IPADM_OPT_ACTIVE);
7396e91bba0SGirish Moodalbail 				}
7406e91bba0SGirish Moodalbail 			}
7416e91bba0SGirish Moodalbail 		}
7426e91bba0SGirish Moodalbail 		return (status);
7436e91bba0SGirish Moodalbail 	}
7446e91bba0SGirish Moodalbail 
7456e91bba0SGirish Moodalbail 	dlpi_flags = DLPI_NOATTACH;
7466e91bba0SGirish Moodalbail 
7476e91bba0SGirish Moodalbail 	/*
7486e91bba0SGirish Moodalbail 	 * If IPADM_OPT_IPMP is specified, then this is a request
7496e91bba0SGirish Moodalbail 	 * to create an IPMP interface atop /dev/ipmpstub0.  (We can't simply
7506e91bba0SGirish Moodalbail 	 * pass "ipmpstub0" as devname since an admin *could* have a normal
7516e91bba0SGirish Moodalbail 	 * vanity-named link named "ipmpstub0" that they'd like to plumb.)
7526e91bba0SGirish Moodalbail 	 */
7536e91bba0SGirish Moodalbail 	if (ipadm_flags & IPADM_OPT_IPMP) {
7546e91bba0SGirish Moodalbail 		dlpi_flags |= DLPI_DEVONLY;
7556e91bba0SGirish Moodalbail 		linkname = "ipmpstub0";
7566e91bba0SGirish Moodalbail 	} else {
7576e91bba0SGirish Moodalbail 		/*
7586e91bba0SGirish Moodalbail 		 * Verify that the user is not creating a persistent
7596e91bba0SGirish Moodalbail 		 * IP interface on a non-persistent data-link.
7606e91bba0SGirish Moodalbail 		 */
7616e91bba0SGirish Moodalbail 		if (!i_ipadm_is_vni(ifname) && dlstatus == DLADM_STATUS_OK &&
7626e91bba0SGirish Moodalbail 		    is_persistent && !(dlflags & DLADM_OPT_PERSIST)) {
7636e91bba0SGirish Moodalbail 				return (IPADM_TEMPORARY_OBJ);
7646e91bba0SGirish Moodalbail 		}
7656e91bba0SGirish Moodalbail 		linkname = ifname;
7666e91bba0SGirish Moodalbail 	}
7676e91bba0SGirish Moodalbail 
7686e91bba0SGirish Moodalbail 	/*
7696e91bba0SGirish Moodalbail 	 * We use DLPI_NOATTACH because the ip module will do the attach
7706e91bba0SGirish Moodalbail 	 * itself for DLPI style-2 devices.
7716e91bba0SGirish Moodalbail 	 */
7726e91bba0SGirish Moodalbail 	if (dlpi_open(linkname, &dh_ip, dlpi_flags) != DLPI_SUCCESS)
7736e91bba0SGirish Moodalbail 		return (IPADM_DLPI_FAILURE);
7746e91bba0SGirish Moodalbail 	ip_fd = dlpi_fd(dh_ip);
7756e91bba0SGirish Moodalbail 	if (ioctl(ip_fd, I_PUSH, IP_MOD_NAME) == -1) {
7766e91bba0SGirish Moodalbail 		status = ipadm_errno2status(errno);
7776e91bba0SGirish Moodalbail 		goto done;
7786e91bba0SGirish Moodalbail 	}
7796e91bba0SGirish Moodalbail 
7806e91bba0SGirish Moodalbail 	/*
7816e91bba0SGirish Moodalbail 	 * Set IFF_IPV4/IFF_IPV6 flags. The kernel only allows modifications
7826e91bba0SGirish Moodalbail 	 * to IFF_IPv4, IFF_IPV6, IFF_BROADCAST, IFF_XRESOLV, IFF_NOLINKLOCAL.
7836e91bba0SGirish Moodalbail 	 */
7846e91bba0SGirish Moodalbail 	ifflags = 0;
7856e91bba0SGirish Moodalbail 
7866e91bba0SGirish Moodalbail 	/* Set the name string and the IFF_IPV* flag */
7876e91bba0SGirish Moodalbail 	if (af == AF_INET) {
7886e91bba0SGirish Moodalbail 		ifflags = IFF_IPV4;
7896e91bba0SGirish Moodalbail 	} else {
7906e91bba0SGirish Moodalbail 		ifflags = IFF_IPV6;
7916e91bba0SGirish Moodalbail 		/*
7926e91bba0SGirish Moodalbail 		 * With the legacy method, the link-local address should be
7936e91bba0SGirish Moodalbail 		 * configured as part of the interface plumb, using the default
7946e91bba0SGirish Moodalbail 		 * token. If IPH_LEGACY is not specified, we want to set :: as
7956e91bba0SGirish Moodalbail 		 * the address and require the admin to explicitly call
7966e91bba0SGirish Moodalbail 		 * ipadm_create_addr() with the address object type set to
7976e91bba0SGirish Moodalbail 		 * IPADM_ADDR_IPV6_ADDRCONF to create the link-local address
7986e91bba0SGirish Moodalbail 		 * as well as the autoconfigured addresses.
7996e91bba0SGirish Moodalbail 		 */
8006e91bba0SGirish Moodalbail 		if (!legacy && !i_ipadm_is_6to4(iph, ifname))
8016e91bba0SGirish Moodalbail 			ifflags |= IFF_NOLINKLOCAL;
8026e91bba0SGirish Moodalbail 	}
8036e91bba0SGirish Moodalbail 	(void) strlcpy(newif, ifname, sizeof (newif));
8046e91bba0SGirish Moodalbail 	status = i_ipadm_slifname(iph, ifname, newif, ifflags, ip_fd,
8056e91bba0SGirish Moodalbail 	    ipadm_flags);
8066e91bba0SGirish Moodalbail 	if (status != IPADM_SUCCESS)
8076e91bba0SGirish Moodalbail 		goto done;
8086e91bba0SGirish Moodalbail 
8096e91bba0SGirish Moodalbail 	/* Get the full set of existing flags for this stream */
8106e91bba0SGirish Moodalbail 	status = i_ipadm_get_flags(iph, newif, af, &ifflags);
8116e91bba0SGirish Moodalbail 	if (status != IPADM_SUCCESS)
8126e91bba0SGirish Moodalbail 		goto done;
8136e91bba0SGirish Moodalbail 
8146e91bba0SGirish Moodalbail 	udp_dev_name = (af == AF_INET6 ? UDP6_DEV_NAME : UDP_DEV_NAME);
8156e91bba0SGirish Moodalbail 	status = ipadm_open_arp_on_udp(udp_dev_name, &mux_fd);
8166e91bba0SGirish Moodalbail 	if (status != IPADM_SUCCESS)
8176e91bba0SGirish Moodalbail 		goto done;
8186e91bba0SGirish Moodalbail 
8196e91bba0SGirish Moodalbail 	/* Check if arp is not needed */
8206e91bba0SGirish Moodalbail 	if (ifflags & (IFF_NOARP|IFF_IPV6)) {
8216e91bba0SGirish Moodalbail 		/*
8226e91bba0SGirish Moodalbail 		 * PLINK the interface stream so that the application can exit
8236e91bba0SGirish Moodalbail 		 * without tearing down the stream.
8246e91bba0SGirish Moodalbail 		 */
8256e91bba0SGirish Moodalbail 		if ((ip_muxid = ioctl(mux_fd, I_PLINK, ip_fd)) == -1)
8266e91bba0SGirish Moodalbail 			status = ipadm_errno2status(errno);
8276e91bba0SGirish Moodalbail 		goto done;
8286e91bba0SGirish Moodalbail 	}
8296e91bba0SGirish Moodalbail 
8306e91bba0SGirish Moodalbail 	/*
8316e91bba0SGirish Moodalbail 	 * This interface does use ARP, so set up a separate stream
8326e91bba0SGirish Moodalbail 	 * from the interface to ARP.
8336e91bba0SGirish Moodalbail 	 *
8346e91bba0SGirish Moodalbail 	 * We use DLPI_NOATTACH because the arp module will do the attach
8356e91bba0SGirish Moodalbail 	 * itself for DLPI style-2 devices.
8366e91bba0SGirish Moodalbail 	 */
8376e91bba0SGirish Moodalbail 	if (dlpi_open(linkname, &dh_arp, dlpi_flags) != DLPI_SUCCESS) {
8386e91bba0SGirish Moodalbail 		status = IPADM_DLPI_FAILURE;
8396e91bba0SGirish Moodalbail 		goto done;
8406e91bba0SGirish Moodalbail 	}
8416e91bba0SGirish Moodalbail 
8426e91bba0SGirish Moodalbail 	arp_fd = dlpi_fd(dh_arp);
8436e91bba0SGirish Moodalbail 	if (ioctl(arp_fd, I_PUSH, ARP_MOD_NAME) == -1) {
8446e91bba0SGirish Moodalbail 		status = ipadm_errno2status(errno);
8456e91bba0SGirish Moodalbail 		goto done;
8466e91bba0SGirish Moodalbail 	}
8476e91bba0SGirish Moodalbail 
8486e91bba0SGirish Moodalbail 	status = i_ipadm_slifname_arp(newif, ifflags, arp_fd);
8496e91bba0SGirish Moodalbail 	if (status != IPADM_SUCCESS)
8506e91bba0SGirish Moodalbail 		goto done;
8516e91bba0SGirish Moodalbail 	/*
8526e91bba0SGirish Moodalbail 	 * PLINK the IP and ARP streams so that ifconfig can exit
8536e91bba0SGirish Moodalbail 	 * without tearing down the stream.
8546e91bba0SGirish Moodalbail 	 */
8556e91bba0SGirish Moodalbail 	if ((ip_muxid = ioctl(mux_fd, I_PLINK, ip_fd)) == -1) {
8566e91bba0SGirish Moodalbail 		status = ipadm_errno2status(errno);
8576e91bba0SGirish Moodalbail 		goto done;
8586e91bba0SGirish Moodalbail 	}
8596e91bba0SGirish Moodalbail 
8606e91bba0SGirish Moodalbail 	if (ioctl(mux_fd, I_PLINK, arp_fd) < 0) {
8616e91bba0SGirish Moodalbail 		status = ipadm_errno2status(errno);
8626e91bba0SGirish Moodalbail 		(void) ioctl(mux_fd, I_PUNLINK, ip_muxid);
8636e91bba0SGirish Moodalbail 	}
8646e91bba0SGirish Moodalbail 
8656e91bba0SGirish Moodalbail done:
8666e91bba0SGirish Moodalbail 	dlpi_close(dh_ip);
8676e91bba0SGirish Moodalbail 	if (dh_arp != NULL)
8686e91bba0SGirish Moodalbail 		dlpi_close(dh_arp);
8696e91bba0SGirish Moodalbail 
8706e91bba0SGirish Moodalbail 	if (mux_fd != -1)
8716e91bba0SGirish Moodalbail 		(void) close(mux_fd);
8726e91bba0SGirish Moodalbail 
8736e91bba0SGirish Moodalbail 	if (status == IPADM_SUCCESS) {
8746e91bba0SGirish Moodalbail 		/* copy back new ifname */
8756e91bba0SGirish Moodalbail 		(void) strlcpy(ifname, newif, LIFNAMSIZ);
8766e91bba0SGirish Moodalbail 		/*
8776e91bba0SGirish Moodalbail 		 * If it is a 6to4 tunnel, create a default
8786e91bba0SGirish Moodalbail 		 * addrobj name for the default address on the 0'th
8796e91bba0SGirish Moodalbail 		 * logical interface and set IFF_UP in the interface flags.
8806e91bba0SGirish Moodalbail 		 */
8816e91bba0SGirish Moodalbail 		if (i_ipadm_is_6to4(iph, ifname)) {
8826e91bba0SGirish Moodalbail 			struct ipadm_addrobj_s addr;
8836e91bba0SGirish Moodalbail 
8846e91bba0SGirish Moodalbail 			i_ipadm_init_addr(&addr, ifname, "", IPADM_ADDR_STATIC);
8856e91bba0SGirish Moodalbail 			addr.ipadm_af = af;
8866e91bba0SGirish Moodalbail 			status = i_ipadm_lookupadd_addrobj(iph, &addr);
8876e91bba0SGirish Moodalbail 			if (status != IPADM_SUCCESS)
8886e91bba0SGirish Moodalbail 				return (status);
8896e91bba0SGirish Moodalbail 			status = ipadm_add_aobjname(iph, ifname,
8906e91bba0SGirish Moodalbail 			    af, addr.ipadm_aobjname, IPADM_ADDR_STATIC, 0);
8916e91bba0SGirish Moodalbail 			if (status != IPADM_SUCCESS)
8926e91bba0SGirish Moodalbail 				return (status);
8936e91bba0SGirish Moodalbail 			addr.ipadm_lifnum = 0;
8946e91bba0SGirish Moodalbail 			i_ipadm_addrobj2lifname(&addr, lifname,
8956e91bba0SGirish Moodalbail 			    sizeof (lifname));
8966e91bba0SGirish Moodalbail 			status = i_ipadm_set_flags(iph, lifname, af,
8976e91bba0SGirish Moodalbail 			    IFF_UP, 0);
8986e91bba0SGirish Moodalbail 			if (status != IPADM_SUCCESS)
8996e91bba0SGirish Moodalbail 				return (status);
9006e91bba0SGirish Moodalbail 		} else {
9016e91bba0SGirish Moodalbail 			/*
9026e91bba0SGirish Moodalbail 			 * Prevent static IPv6 addresses from triggering
9036e91bba0SGirish Moodalbail 			 * autoconf. This does not have to be done for
9046e91bba0SGirish Moodalbail 			 * 6to4 tunnel interfaces, since in.ndpd will
9056e91bba0SGirish Moodalbail 			 * not autoconfigure those interfaces.
9066e91bba0SGirish Moodalbail 			 */
9076e91bba0SGirish Moodalbail 			if (af == AF_INET6 && !legacy)
9086e91bba0SGirish Moodalbail 				(void) i_ipadm_disable_autoconf(newif);
9096e91bba0SGirish Moodalbail 		}
9106e91bba0SGirish Moodalbail 
9116e91bba0SGirish Moodalbail 		/*
9126e91bba0SGirish Moodalbail 		 * If IPADM_OPT_PERSIST was set in flags, store the
9136e91bba0SGirish Moodalbail 		 * interface in persistent DB.
9146e91bba0SGirish Moodalbail 		 */
9156e91bba0SGirish Moodalbail 		if (is_persistent) {
9166e91bba0SGirish Moodalbail 			status = i_ipadm_persist_if(iph, newif, af);
9176e91bba0SGirish Moodalbail 			if (status != IPADM_SUCCESS) {
9186e91bba0SGirish Moodalbail 				(void) i_ipadm_delete_if(iph, newif, af,
9196e91bba0SGirish Moodalbail 				    IPADM_OPT_ACTIVE);
9206e91bba0SGirish Moodalbail 			}
9216e91bba0SGirish Moodalbail 		}
9226e91bba0SGirish Moodalbail 	}
9236e91bba0SGirish Moodalbail 	if (status == IPADM_EXISTS)
9246e91bba0SGirish Moodalbail 		status = IPADM_IF_EXISTS;
9256e91bba0SGirish Moodalbail 	return (status);
9266e91bba0SGirish Moodalbail }
9276e91bba0SGirish Moodalbail 
9286e91bba0SGirish Moodalbail /*
9296e91bba0SGirish Moodalbail  * Unplumbs the interface in `ifname' of family `af'.
9306e91bba0SGirish Moodalbail  */
9316e91bba0SGirish Moodalbail ipadm_status_t
9326e91bba0SGirish Moodalbail i_ipadm_unplumb_if(ipadm_handle_t iph, const char *ifname, sa_family_t af)
9336e91bba0SGirish Moodalbail {
9346e91bba0SGirish Moodalbail 	int		ip_muxid, arp_muxid;
9356e91bba0SGirish Moodalbail 	int		mux_fd = -1;
9366e91bba0SGirish Moodalbail 	int		muxid_fd = -1;
9376e91bba0SGirish Moodalbail 	char		*udp_dev_name;
9386e91bba0SGirish Moodalbail 	uint64_t	flags;
9396e91bba0SGirish Moodalbail 	boolean_t	changed_arp_muxid = B_FALSE;
9406e91bba0SGirish Moodalbail 	int		save_errno;
9416e91bba0SGirish Moodalbail 	struct lifreq	lifr;
9426e91bba0SGirish Moodalbail 	ipadm_status_t	ret = IPADM_SUCCESS;
9436e91bba0SGirish Moodalbail 	int		sock;
9446e91bba0SGirish Moodalbail 	lifgroupinfo_t	lifgr;
9456e91bba0SGirish Moodalbail 	ifaddrlistx_t	*ifaddrs, *ifaddrp;
9466e91bba0SGirish Moodalbail 	boolean_t	v6 = (af == AF_INET6);
9476e91bba0SGirish Moodalbail 
9486e91bba0SGirish Moodalbail 	/* Just do SIOCLIFREMOVEIF on loopback interfaces */
9496e91bba0SGirish Moodalbail 	bzero(&lifr, sizeof (lifr));
9506e91bba0SGirish Moodalbail 	if (i_ipadm_is_loopback(ifname) ||
9516e91bba0SGirish Moodalbail 	    (i_ipadm_get_lnum(ifname) != 0 && (iph->iph_flags & IPH_LEGACY))) {
9526e91bba0SGirish Moodalbail 		(void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
9536e91bba0SGirish Moodalbail 		if (ioctl((af == AF_INET) ? iph->iph_sock : iph->iph_sock6,
9546e91bba0SGirish Moodalbail 		    SIOCLIFREMOVEIF, (caddr_t)&lifr) < 0) {
9556e91bba0SGirish Moodalbail 			return (ipadm_errno2status(errno));
9566e91bba0SGirish Moodalbail 		}
9576e91bba0SGirish Moodalbail 		return (IPADM_SUCCESS);
9586e91bba0SGirish Moodalbail 	}
9596e91bba0SGirish Moodalbail 
9606e91bba0SGirish Moodalbail 	/*
9616e91bba0SGirish Moodalbail 	 * We used /dev/udp or udp6 to set up the mux. So we have to use
9626e91bba0SGirish Moodalbail 	 * the same now for PUNLINK also.
9636e91bba0SGirish Moodalbail 	 */
9646e91bba0SGirish Moodalbail 	if (v6) {
9656e91bba0SGirish Moodalbail 		udp_dev_name = UDP6_DEV_NAME;
9666e91bba0SGirish Moodalbail 		sock = iph->iph_sock6;
9676e91bba0SGirish Moodalbail 	} else {
9686e91bba0SGirish Moodalbail 		udp_dev_name = UDP_DEV_NAME;
9696e91bba0SGirish Moodalbail 		sock = iph->iph_sock;
9706e91bba0SGirish Moodalbail 	}
9716e91bba0SGirish Moodalbail 	if ((muxid_fd = open(udp_dev_name, O_RDWR)) == -1) {
9726e91bba0SGirish Moodalbail 		ret = ipadm_errno2status(errno);
9736e91bba0SGirish Moodalbail 		goto done;
9746e91bba0SGirish Moodalbail 	}
9756e91bba0SGirish Moodalbail 	ret = ipadm_open_arp_on_udp(udp_dev_name, &mux_fd);
9766e91bba0SGirish Moodalbail 	if (ret != IPADM_SUCCESS)
9776e91bba0SGirish Moodalbail 		goto done;
9786e91bba0SGirish Moodalbail 	(void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
9796e91bba0SGirish Moodalbail 	if (ioctl(muxid_fd, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) {
9806e91bba0SGirish Moodalbail 		ret = ipadm_errno2status(errno);
9816e91bba0SGirish Moodalbail 		goto done;
9826e91bba0SGirish Moodalbail 	}
9836e91bba0SGirish Moodalbail 	flags = lifr.lifr_flags;
9846e91bba0SGirish Moodalbail again:
9856e91bba0SGirish Moodalbail 	if (flags & IFF_IPMP) {
9866e91bba0SGirish Moodalbail 		/*
9876e91bba0SGirish Moodalbail 		 * There are two reasons the I_PUNLINK can fail with EBUSY:
9886e91bba0SGirish Moodalbail 		 * (1) if IP interfaces are in the group, or (2) if IPMP data
9896e91bba0SGirish Moodalbail 		 * addresses are administratively up.  For case (1), we fail
9906e91bba0SGirish Moodalbail 		 * here with a specific error message.  For case (2), we bring
9916e91bba0SGirish Moodalbail 		 * down the addresses prior to doing the I_PUNLINK.  If the
9926e91bba0SGirish Moodalbail 		 * I_PUNLINK still fails with EBUSY then the configuration
9936e91bba0SGirish Moodalbail 		 * must have changed after our checks, in which case we branch
9946e91bba0SGirish Moodalbail 		 * back up to `again' and rerun this logic.  The net effect is
9956e91bba0SGirish Moodalbail 		 * that unplumbing an IPMP interface will only fail with EBUSY
9966e91bba0SGirish Moodalbail 		 * if IP interfaces are in the group.
9976e91bba0SGirish Moodalbail 		 */
9986e91bba0SGirish Moodalbail 		if (ioctl(sock, SIOCGLIFGROUPNAME, &lifr) == -1) {
9996e91bba0SGirish Moodalbail 			ret = ipadm_errno2status(errno);
10006e91bba0SGirish Moodalbail 			goto done;
10016e91bba0SGirish Moodalbail 		}
10026e91bba0SGirish Moodalbail 		(void) strlcpy(lifgr.gi_grname, lifr.lifr_groupname,
10036e91bba0SGirish Moodalbail 		    LIFGRNAMSIZ);
10046e91bba0SGirish Moodalbail 		if (ioctl(sock, SIOCGLIFGROUPINFO, &lifgr) == -1) {
10056e91bba0SGirish Moodalbail 			ret = ipadm_errno2status(errno);
10066e91bba0SGirish Moodalbail 			goto done;
10076e91bba0SGirish Moodalbail 		}
10086e91bba0SGirish Moodalbail 		if ((v6 && lifgr.gi_nv6 != 0) || (!v6 && lifgr.gi_nv4 != 0)) {
10096e91bba0SGirish Moodalbail 			ret = IPADM_GRP_NOTEMPTY;
10106e91bba0SGirish Moodalbail 			goto done;
10116e91bba0SGirish Moodalbail 		}
10126e91bba0SGirish Moodalbail 
10136e91bba0SGirish Moodalbail 		/*
10146e91bba0SGirish Moodalbail 		 * The kernel will fail the I_PUNLINK if the IPMP interface
10156e91bba0SGirish Moodalbail 		 * has administratively up addresses; bring them down.
10166e91bba0SGirish Moodalbail 		 */
10176e91bba0SGirish Moodalbail 		if (ifaddrlistx(ifname, IFF_UP|IFF_DUPLICATE,
10186e91bba0SGirish Moodalbail 		    0, &ifaddrs) == -1) {
10196e91bba0SGirish Moodalbail 			ret = ipadm_errno2status(errno);
10206e91bba0SGirish Moodalbail 			goto done;
10216e91bba0SGirish Moodalbail 		}
10226e91bba0SGirish Moodalbail 		ifaddrp = ifaddrs;
10236e91bba0SGirish Moodalbail 		for (; ifaddrp != NULL; ifaddrp = ifaddrp->ia_next) {
10246e91bba0SGirish Moodalbail 			int sock = (ifaddrp->ia_flags & IFF_IPV4) ?
10256e91bba0SGirish Moodalbail 			    iph->iph_sock : iph->iph_sock6;
10266e91bba0SGirish Moodalbail 			struct lifreq lifrl;
10276e91bba0SGirish Moodalbail 
10286e91bba0SGirish Moodalbail 			if (((ifaddrp->ia_flags & IFF_IPV6) && !v6) ||
10296e91bba0SGirish Moodalbail 			    (!(ifaddrp->ia_flags & IFF_IPV6) && v6))
10306e91bba0SGirish Moodalbail 				continue;
10316e91bba0SGirish Moodalbail 
10326e91bba0SGirish Moodalbail 			bzero(&lifrl, sizeof (lifrl));
10336e91bba0SGirish Moodalbail 			(void) strlcpy(lifrl.lifr_name, ifaddrp->ia_name,
10346e91bba0SGirish Moodalbail 			    sizeof (lifrl.lifr_name));
10356e91bba0SGirish Moodalbail 			if (ioctl(sock, SIOCGLIFFLAGS, &lifrl) < 0) {
10366e91bba0SGirish Moodalbail 				ret = ipadm_errno2status(errno);
10376e91bba0SGirish Moodalbail 				ifaddrlistx_free(ifaddrs);
10386e91bba0SGirish Moodalbail 				goto done;
10396e91bba0SGirish Moodalbail 			}
10406e91bba0SGirish Moodalbail 			if (lifrl.lifr_flags & IFF_UP) {
10416e91bba0SGirish Moodalbail 				ret = i_ipadm_set_flags(iph, lifrl.lifr_name,
10426e91bba0SGirish Moodalbail 				    ((lifrl.lifr_flags & IFF_IPV4) ? AF_INET :
10436e91bba0SGirish Moodalbail 				    AF_INET6), 0, IFF_UP);
10446e91bba0SGirish Moodalbail 				if (ret != IPADM_SUCCESS) {
10456e91bba0SGirish Moodalbail 					ifaddrlistx_free(ifaddrs);
10466e91bba0SGirish Moodalbail 					goto done;
10476e91bba0SGirish Moodalbail 				}
10486e91bba0SGirish Moodalbail 			} else if (lifrl.lifr_flags & IFF_DUPLICATE) {
10496e91bba0SGirish Moodalbail 				if (ioctl(sock, SIOCGLIFADDR, &lifrl) < 0 ||
10506e91bba0SGirish Moodalbail 				    ioctl(sock, SIOCSLIFADDR, &lifrl) < 0) {
10516e91bba0SGirish Moodalbail 					ret = ipadm_errno2status(errno);
10526e91bba0SGirish Moodalbail 					ifaddrlistx_free(ifaddrs);
10536e91bba0SGirish Moodalbail 					goto done;
10546e91bba0SGirish Moodalbail 				}
10556e91bba0SGirish Moodalbail 			}
10566e91bba0SGirish Moodalbail 		}
10576e91bba0SGirish Moodalbail 		ifaddrlistx_free(ifaddrs);
10586e91bba0SGirish Moodalbail 	}
10596e91bba0SGirish Moodalbail 
10606e91bba0SGirish Moodalbail 	if (ioctl(muxid_fd, SIOCGLIFMUXID, (caddr_t)&lifr) < 0) {
10616e91bba0SGirish Moodalbail 		ret = ipadm_errno2status(errno);
10626e91bba0SGirish Moodalbail 		goto done;
10636e91bba0SGirish Moodalbail 	}
10646e91bba0SGirish Moodalbail 	arp_muxid = lifr.lifr_arp_muxid;
10656e91bba0SGirish Moodalbail 	ip_muxid = lifr.lifr_ip_muxid;
10666e91bba0SGirish Moodalbail 
10676e91bba0SGirish Moodalbail 	/*
10686e91bba0SGirish Moodalbail 	 * We don't have a good way of knowing whether the arp stream is
10696e91bba0SGirish Moodalbail 	 * plumbed. We can't rely on IFF_NOARP because someone could
10706e91bba0SGirish Moodalbail 	 * have turned it off later using "ifconfig xxx -arp".
10716e91bba0SGirish Moodalbail 	 */
10726e91bba0SGirish Moodalbail 	if (arp_muxid != 0) {
10736e91bba0SGirish Moodalbail 		if (ioctl(mux_fd, I_PUNLINK, arp_muxid) < 0) {
10746e91bba0SGirish Moodalbail 			/*
10756e91bba0SGirish Moodalbail 			 * See the comment before the SIOCGLIFGROUPNAME call.
10766e91bba0SGirish Moodalbail 			 */
10776e91bba0SGirish Moodalbail 			if (errno == EBUSY && (flags & IFF_IPMP))
10786e91bba0SGirish Moodalbail 				goto again;
10796e91bba0SGirish Moodalbail 
10806e91bba0SGirish Moodalbail 			if ((errno == EINVAL) &&
10816e91bba0SGirish Moodalbail 			    (flags & (IFF_NOARP | IFF_IPV6))) {
10826e91bba0SGirish Moodalbail 				/*
10836e91bba0SGirish Moodalbail 				 * Some plumbing utilities set the muxid to
10846e91bba0SGirish Moodalbail 				 * -1 or some invalid value to signify that
10856e91bba0SGirish Moodalbail 				 * there is no arp stream. Set the muxid to 0
10866e91bba0SGirish Moodalbail 				 * before trying to unplumb the IP stream.
10876e91bba0SGirish Moodalbail 				 * IP does not allow the IP stream to be
10886e91bba0SGirish Moodalbail 				 * unplumbed if it sees a non-null arp muxid,
10896e91bba0SGirish Moodalbail 				 * for consistency of IP-ARP streams.
10906e91bba0SGirish Moodalbail 				 */
10916e91bba0SGirish Moodalbail 				lifr.lifr_arp_muxid = 0;
10926e91bba0SGirish Moodalbail 				(void) ioctl(muxid_fd, SIOCSLIFMUXID,
10936e91bba0SGirish Moodalbail 				    (caddr_t)&lifr);
10946e91bba0SGirish Moodalbail 				changed_arp_muxid = B_TRUE;
10956e91bba0SGirish Moodalbail 			}
10966e91bba0SGirish Moodalbail 			/*
10976e91bba0SGirish Moodalbail 			 * In case of any other error, we continue with
10986e91bba0SGirish Moodalbail 			 * the unplumb.
10996e91bba0SGirish Moodalbail 			 */
11006e91bba0SGirish Moodalbail 		}
11016e91bba0SGirish Moodalbail 	}
11026e91bba0SGirish Moodalbail 
11036e91bba0SGirish Moodalbail 	if (ioctl(mux_fd, I_PUNLINK, ip_muxid) < 0) {
11046e91bba0SGirish Moodalbail 		if (changed_arp_muxid) {
11056e91bba0SGirish Moodalbail 			/*
11066e91bba0SGirish Moodalbail 			 * Some error occurred, and we need to restore
11076e91bba0SGirish Moodalbail 			 * everything back to what it was.
11086e91bba0SGirish Moodalbail 			 */
11096e91bba0SGirish Moodalbail 			save_errno = errno;
11106e91bba0SGirish Moodalbail 			lifr.lifr_arp_muxid = arp_muxid;
11116e91bba0SGirish Moodalbail 			lifr.lifr_ip_muxid = ip_muxid;
11126e91bba0SGirish Moodalbail 			(void) ioctl(muxid_fd, SIOCSLIFMUXID, (caddr_t)&lifr);
11136e91bba0SGirish Moodalbail 			errno = save_errno;
11146e91bba0SGirish Moodalbail 		}
11156e91bba0SGirish Moodalbail 		/*
11166e91bba0SGirish Moodalbail 		 * See the comment before the SIOCGLIFGROUPNAME call.
11176e91bba0SGirish Moodalbail 		 */
11186e91bba0SGirish Moodalbail 		if (errno == EBUSY && (flags & IFF_IPMP))
11196e91bba0SGirish Moodalbail 			goto again;
11206e91bba0SGirish Moodalbail 
11216e91bba0SGirish Moodalbail 		ret = ipadm_errno2status(errno);
11226e91bba0SGirish Moodalbail 	}
11236e91bba0SGirish Moodalbail done:
11246e91bba0SGirish Moodalbail 	if (muxid_fd != -1)
11256e91bba0SGirish Moodalbail 		(void) close(muxid_fd);
11266e91bba0SGirish Moodalbail 	if (mux_fd != -1)
11276e91bba0SGirish Moodalbail 		(void) close(mux_fd);
11286e91bba0SGirish Moodalbail 
11296e91bba0SGirish Moodalbail 	if (af == AF_INET6 && ret == IPADM_SUCCESS) {
11306e91bba0SGirish Moodalbail 		/*
11316e91bba0SGirish Moodalbail 		 * in.ndpd maintains the phyints in its memory even after
11326e91bba0SGirish Moodalbail 		 * the interface is plumbed, so that it can be reused when
11336e91bba0SGirish Moodalbail 		 * the interface gets plumbed again. The default behavior
11346e91bba0SGirish Moodalbail 		 * of in.ndpd is to start autoconfiguration for an interface
11356e91bba0SGirish Moodalbail 		 * that gets plumbed. We need to send the
11366e91bba0SGirish Moodalbail 		 * message IPADM_ENABLE_AUTOCONF to in.ndpd to restore this
11376e91bba0SGirish Moodalbail 		 * default behavior on replumb.
11386e91bba0SGirish Moodalbail 		 */
11396e91bba0SGirish Moodalbail 		(void) i_ipadm_enable_autoconf(ifname);
11406e91bba0SGirish Moodalbail 	}
11416e91bba0SGirish Moodalbail 	return (ret);
11426e91bba0SGirish Moodalbail }
11436e91bba0SGirish Moodalbail 
11446e91bba0SGirish Moodalbail /*
11456e91bba0SGirish Moodalbail  * Saves the given interface name `ifname' with address family `af' in
11466e91bba0SGirish Moodalbail  * persistent DB.
11476e91bba0SGirish Moodalbail  */
11486e91bba0SGirish Moodalbail static ipadm_status_t
11496e91bba0SGirish Moodalbail i_ipadm_persist_if(ipadm_handle_t iph, const char *ifname, sa_family_t af)
11506e91bba0SGirish Moodalbail {
11516e91bba0SGirish Moodalbail 	ipmgmt_if_arg_t		ifarg;
11526e91bba0SGirish Moodalbail 	int			err;
11536e91bba0SGirish Moodalbail 
11546e91bba0SGirish Moodalbail 	(void) strlcpy(ifarg.ia_ifname, ifname, sizeof (ifarg.ia_ifname));
11556e91bba0SGirish Moodalbail 	ifarg.ia_family = af;
11566e91bba0SGirish Moodalbail 	ifarg.ia_cmd = IPMGMT_CMD_SETIF;
11576e91bba0SGirish Moodalbail 	ifarg.ia_flags = IPMGMT_PERSIST;
11586e91bba0SGirish Moodalbail 	err = ipadm_door_call(iph, &ifarg, sizeof (ifarg), NULL, 0, B_FALSE);
11596e91bba0SGirish Moodalbail 	return (ipadm_errno2status(err));
11606e91bba0SGirish Moodalbail }
11616e91bba0SGirish Moodalbail 
11626e91bba0SGirish Moodalbail /*
11636e91bba0SGirish Moodalbail  * Remove the IP interface from active configuration. If IPADM_OPT_PERSIST
11646e91bba0SGirish Moodalbail  * is set in `ipadm_flags', it is also removed from persistent configuration.
11656e91bba0SGirish Moodalbail  */
11666e91bba0SGirish Moodalbail ipadm_status_t
11676e91bba0SGirish Moodalbail i_ipadm_delete_if(ipadm_handle_t iph, const char *ifname, sa_family_t af,
11686e91bba0SGirish Moodalbail     uint32_t ipadm_flags)
11696e91bba0SGirish Moodalbail {
11706e91bba0SGirish Moodalbail 	ipadm_status_t		ret = IPADM_SUCCESS;
11716e91bba0SGirish Moodalbail 	ipadm_status_t		db_status;
11726e91bba0SGirish Moodalbail 	char			tmp_ifname[LIFNAMSIZ];
11736e91bba0SGirish Moodalbail 	char			*cp;
11746e91bba0SGirish Moodalbail 	struct ipadm_addrobj_s	ipaddr;
11756e91bba0SGirish Moodalbail 	boolean_t		is_persistent =
11766e91bba0SGirish Moodalbail 	    (ipadm_flags & IPADM_OPT_PERSIST);
11776e91bba0SGirish Moodalbail 
11786e91bba0SGirish Moodalbail 	ret = i_ipadm_unplumb_if(iph, ifname, af);
11796e91bba0SGirish Moodalbail 	if (ret != IPADM_SUCCESS)
11806e91bba0SGirish Moodalbail 		goto done;
11816e91bba0SGirish Moodalbail 
11826e91bba0SGirish Moodalbail 	cp = strrchr(ifname, IPADM_LOGICAL_SEP);
11836e91bba0SGirish Moodalbail 	if (cp != NULL) {
11846e91bba0SGirish Moodalbail 		assert(iph->iph_flags & IPH_LEGACY);
11856e91bba0SGirish Moodalbail 		/*
11866e91bba0SGirish Moodalbail 		 * This is a non-zero logical interface.
11876e91bba0SGirish Moodalbail 		 * Find the addrobj and remove it from the daemon's memory.
11886e91bba0SGirish Moodalbail 		 */
11896e91bba0SGirish Moodalbail 		(void) strlcpy(tmp_ifname, ifname, sizeof (tmp_ifname));
11906e91bba0SGirish Moodalbail 		tmp_ifname[cp - ifname] = '\0';
11916e91bba0SGirish Moodalbail 		*cp++ = '\0';
11926e91bba0SGirish Moodalbail 		ipaddr.ipadm_lifnum = atoi(cp);
11936e91bba0SGirish Moodalbail 		(void) strlcpy(ipaddr.ipadm_ifname, tmp_ifname,
11946e91bba0SGirish Moodalbail 		    sizeof (ipaddr.ipadm_ifname));
11956e91bba0SGirish Moodalbail 		ipaddr.ipadm_af = af;
11966e91bba0SGirish Moodalbail 		ret = i_ipadm_get_lif2addrobj(iph, &ipaddr);
11976e91bba0SGirish Moodalbail 		if (ret == IPADM_SUCCESS) {
11986e91bba0SGirish Moodalbail 			ret = i_ipadm_delete_addrobj(iph, &ipaddr,
11996e91bba0SGirish Moodalbail 			    IPADM_OPT_ACTIVE);
12006e91bba0SGirish Moodalbail 		} else if (ret == IPADM_NOTFOUND) {
12016e91bba0SGirish Moodalbail 			ret = IPADM_SUCCESS;
12026e91bba0SGirish Moodalbail 		}
12036e91bba0SGirish Moodalbail 		return (ret);
12046e91bba0SGirish Moodalbail 	}
12056e91bba0SGirish Moodalbail done:
12066e91bba0SGirish Moodalbail 	/*
12076e91bba0SGirish Moodalbail 	 * Even if interface does not exist, remove all its addresses and
12086e91bba0SGirish Moodalbail 	 * properties from the persistent store. If interface does not
12096e91bba0SGirish Moodalbail 	 * exist both in kernel and the persistent store, return IPADM_ENXIO.
12106e91bba0SGirish Moodalbail 	 */
12116e91bba0SGirish Moodalbail 	if ((ret == IPADM_ENXIO && is_persistent) || ret == IPADM_SUCCESS) {
12126e91bba0SGirish Moodalbail 		db_status = i_ipadm_delete_ifobj(iph, ifname, af,
12136e91bba0SGirish Moodalbail 		    is_persistent);
12146e91bba0SGirish Moodalbail 		if (db_status == IPADM_SUCCESS)
12156e91bba0SGirish Moodalbail 			ret = IPADM_SUCCESS;
12166e91bba0SGirish Moodalbail 	}
12176e91bba0SGirish Moodalbail 
12186e91bba0SGirish Moodalbail 	return (ret);
12196e91bba0SGirish Moodalbail }
12206e91bba0SGirish Moodalbail 
12216e91bba0SGirish Moodalbail /*
12226e91bba0SGirish Moodalbail  * Resets all addresses on interface `ifname' with address family `af'
12236e91bba0SGirish Moodalbail  * from ipmgmtd daemon. If is_persistent = B_TRUE, all interface properties
12246e91bba0SGirish Moodalbail  * and address objects of `ifname' for `af' are also removed from the
12256e91bba0SGirish Moodalbail  * persistent DB.
12266e91bba0SGirish Moodalbail  */
12276e91bba0SGirish Moodalbail ipadm_status_t
12286e91bba0SGirish Moodalbail i_ipadm_delete_ifobj(ipadm_handle_t iph, const char *ifname, sa_family_t af,
12296e91bba0SGirish Moodalbail     boolean_t is_persistent)
12306e91bba0SGirish Moodalbail {
12316e91bba0SGirish Moodalbail 	ipmgmt_if_arg_t		ifarg;
12326e91bba0SGirish Moodalbail 	int			err;
12336e91bba0SGirish Moodalbail 
12346e91bba0SGirish Moodalbail 	ifarg.ia_cmd = IPMGMT_CMD_RESETIF;
12356e91bba0SGirish Moodalbail 	ifarg.ia_flags = IPMGMT_ACTIVE;
12366e91bba0SGirish Moodalbail 	if (is_persistent)
12376e91bba0SGirish Moodalbail 		ifarg.ia_flags |= IPMGMT_PERSIST;
12386e91bba0SGirish Moodalbail 	ifarg.ia_family = af;
12396e91bba0SGirish Moodalbail 	(void) strlcpy(ifarg.ia_ifname, ifname, LIFNAMSIZ);
12406e91bba0SGirish Moodalbail 
12416e91bba0SGirish Moodalbail 	err = ipadm_door_call(iph, &ifarg, sizeof (ifarg), NULL, 0, B_FALSE);
12426e91bba0SGirish Moodalbail 	return (ipadm_errno2status(err));
12436e91bba0SGirish Moodalbail }
12446e91bba0SGirish Moodalbail 
12456e91bba0SGirish Moodalbail /*
12466e91bba0SGirish Moodalbail  * Create the interface by plumbing it for IP.
12476e91bba0SGirish Moodalbail  * This function will check if there is saved configuration information
12486e91bba0SGirish Moodalbail  * for `ifname' and return IPADM_OP_DISABLE_OBJ if the name-space
12496e91bba0SGirish Moodalbail  * for `ifname' is taken.
12506e91bba0SGirish Moodalbail  */
12516e91bba0SGirish Moodalbail ipadm_status_t
12526e91bba0SGirish Moodalbail i_ipadm_create_if(ipadm_handle_t iph, char *ifname, sa_family_t af,
12536e91bba0SGirish Moodalbail     uint32_t ipadm_flags)
12546e91bba0SGirish Moodalbail {
12556e91bba0SGirish Moodalbail 	ipadm_status_t	status;
12566e91bba0SGirish Moodalbail 	boolean_t	p_exists;
12576e91bba0SGirish Moodalbail 	sa_family_t	other_af;
12586e91bba0SGirish Moodalbail 
12596e91bba0SGirish Moodalbail 	/*
12606e91bba0SGirish Moodalbail 	 * Return error, if the interface already exists in either the active
12616e91bba0SGirish Moodalbail 	 * or the persistent configuration.
12626e91bba0SGirish Moodalbail 	 */
12636e91bba0SGirish Moodalbail 	if (ipadm_if_enabled(iph, ifname, af))
12646e91bba0SGirish Moodalbail 		return (IPADM_IF_EXISTS);
12656e91bba0SGirish Moodalbail 
1266913a9028SVasumathi Sundaram 	if (!(iph->iph_flags & IPH_LEGACY)) {
12676e91bba0SGirish Moodalbail 		status = i_ipadm_if_pexists(iph, ifname, af, &p_exists);
12686e91bba0SGirish Moodalbail 		if (status != IPADM_SUCCESS)
12696e91bba0SGirish Moodalbail 			return (status);
12706e91bba0SGirish Moodalbail 		other_af = (af == AF_INET ? AF_INET6 : AF_INET);
12716e91bba0SGirish Moodalbail 		if (p_exists) {
12726e91bba0SGirish Moodalbail 			if (!ipadm_if_enabled(iph, ifname, other_af))
12736e91bba0SGirish Moodalbail 				return (IPADM_OP_DISABLE_OBJ);
12746e91bba0SGirish Moodalbail 			else
12756e91bba0SGirish Moodalbail 				ipadm_flags &= ~IPADM_OPT_PERSIST;
12766e91bba0SGirish Moodalbail 		}
1277913a9028SVasumathi Sundaram 	}
12786e91bba0SGirish Moodalbail 
12796e91bba0SGirish Moodalbail 	return (i_ipadm_plumb_if(iph, ifname, af, ipadm_flags));
12806e91bba0SGirish Moodalbail }
12816e91bba0SGirish Moodalbail 
12826e91bba0SGirish Moodalbail /*
12836e91bba0SGirish Moodalbail  * Plumbs an interface. Creates both IPv4 and IPv6 interfaces by
12846e91bba0SGirish Moodalbail  * default, unless a value in `af' is specified. The interface may be plumbed
12856e91bba0SGirish Moodalbail  * only if there is no previously saved persistent configuration information
12866e91bba0SGirish Moodalbail  * for the interface (in which case the ipadm_enable_if() function must
12876e91bba0SGirish Moodalbail  * be used to enable the interface).
12886e91bba0SGirish Moodalbail  *
12896e91bba0SGirish Moodalbail  * Returns: IPADM_SUCCESS, IPADM_FAILURE, IPADM_IF_EXISTS,
12906e91bba0SGirish Moodalbail  * IPADM_IF_PERSIST_EXISTS, IPADM_DLPI_FAILURE,
12916e91bba0SGirish Moodalbail  * or appropriate ipadm_status_t corresponding to the errno.
12926e91bba0SGirish Moodalbail  *
12936e91bba0SGirish Moodalbail  * `ifname' must point to memory that can hold upto LIFNAMSIZ chars. It may
12946e91bba0SGirish Moodalbail  * be over-written with the actual interface name when a PPA has to be
12956e91bba0SGirish Moodalbail  * internally generated by the library.
12966e91bba0SGirish Moodalbail  */
12976e91bba0SGirish Moodalbail ipadm_status_t
12986e91bba0SGirish Moodalbail ipadm_create_if(ipadm_handle_t iph, char *ifname, sa_family_t af,
12996e91bba0SGirish Moodalbail     uint32_t flags)
13006e91bba0SGirish Moodalbail {
13016e91bba0SGirish Moodalbail 	ipadm_status_t	status;
13026e91bba0SGirish Moodalbail 	boolean_t	created_v4 = B_FALSE;
13036e91bba0SGirish Moodalbail 	char		newifname[LIFNAMSIZ];
13046e91bba0SGirish Moodalbail 
13056e91bba0SGirish Moodalbail 	/* Check for the required authorization */
13066e91bba0SGirish Moodalbail 	if (!ipadm_check_auth())
13076e91bba0SGirish Moodalbail 		return (IPADM_EAUTH);
13086e91bba0SGirish Moodalbail 
13096e91bba0SGirish Moodalbail 	if (flags == 0 || ((flags & IPADM_OPT_PERSIST) &&
13106e91bba0SGirish Moodalbail 	    !(flags & IPADM_OPT_ACTIVE)) ||
13116e91bba0SGirish Moodalbail 	    (flags & ~(IPADM_COMMON_OPT_MASK | IPADM_OPT_IPMP |
13126e91bba0SGirish Moodalbail 	    IPADM_OPT_GENPPA))) {
13136e91bba0SGirish Moodalbail 		return (IPADM_INVALID_ARG);
13146e91bba0SGirish Moodalbail 	}
13156e91bba0SGirish Moodalbail 	if (flags & IPADM_OPT_GENPPA) {
13166e91bba0SGirish Moodalbail 		if (snprintf(newifname, LIFNAMSIZ, "%s0", ifname) >=
13176e91bba0SGirish Moodalbail 		    LIFNAMSIZ)
13186e91bba0SGirish Moodalbail 			return (IPADM_INVALID_ARG);
13196e91bba0SGirish Moodalbail 	} else {
13206e91bba0SGirish Moodalbail 		if (strlcpy(newifname, ifname, LIFNAMSIZ) >= LIFNAMSIZ)
13216e91bba0SGirish Moodalbail 			return (IPADM_INVALID_ARG);
13226e91bba0SGirish Moodalbail 	}
13236e91bba0SGirish Moodalbail 
13246e91bba0SGirish Moodalbail 	if (!i_ipadm_validate_ifname(iph, newifname))
13256e91bba0SGirish Moodalbail 		return (IPADM_INVALID_ARG);
13266e91bba0SGirish Moodalbail 
13276e91bba0SGirish Moodalbail 	if ((af == AF_INET || af == AF_UNSPEC) &&
13286e91bba0SGirish Moodalbail 	    !i_ipadm_is_6to4(iph, ifname)) {
13296e91bba0SGirish Moodalbail 		status = i_ipadm_create_if(iph, ifname, AF_INET, flags);
13306e91bba0SGirish Moodalbail 		if (status != IPADM_SUCCESS)
13316e91bba0SGirish Moodalbail 			return (status);
13326e91bba0SGirish Moodalbail 		created_v4 = B_TRUE;
13336e91bba0SGirish Moodalbail 	}
13346e91bba0SGirish Moodalbail 	if (af == AF_INET6 || af == AF_UNSPEC) {
13356e91bba0SGirish Moodalbail 		status = i_ipadm_create_if(iph, ifname, AF_INET6, flags);
13366e91bba0SGirish Moodalbail 		if (status != IPADM_SUCCESS) {
13376e91bba0SGirish Moodalbail 			if (created_v4) {
13386e91bba0SGirish Moodalbail 				(void) i_ipadm_delete_if(iph, ifname, AF_INET,
13396e91bba0SGirish Moodalbail 				    IPADM_OPT_ACTIVE);
13406e91bba0SGirish Moodalbail 			}
13416e91bba0SGirish Moodalbail 			return (status);
13426e91bba0SGirish Moodalbail 		}
13436e91bba0SGirish Moodalbail 	}
13446e91bba0SGirish Moodalbail 
13456e91bba0SGirish Moodalbail 	return (IPADM_SUCCESS);
13466e91bba0SGirish Moodalbail }
13476e91bba0SGirish Moodalbail 
13486e91bba0SGirish Moodalbail /*
13496e91bba0SGirish Moodalbail  * Deletes the interface in `ifname'. Removes both IPv4 and IPv6 interfaces
13506e91bba0SGirish Moodalbail  * when `af' = AF_UNSPEC.
13516e91bba0SGirish Moodalbail  */
13526e91bba0SGirish Moodalbail ipadm_status_t
13536e91bba0SGirish Moodalbail ipadm_delete_if(ipadm_handle_t iph, const char *ifname, sa_family_t af,
13546e91bba0SGirish Moodalbail     uint32_t flags)
13556e91bba0SGirish Moodalbail {
13566e91bba0SGirish Moodalbail 	ipadm_status_t status1 = IPADM_SUCCESS;
13576e91bba0SGirish Moodalbail 	ipadm_status_t status2 = IPADM_SUCCESS;
13586e91bba0SGirish Moodalbail 	ipadm_status_t other;
13596e91bba0SGirish Moodalbail 
13606e91bba0SGirish Moodalbail 	/* Check for the required authorization */
13616e91bba0SGirish Moodalbail 	if (!ipadm_check_auth())
13626e91bba0SGirish Moodalbail 		return (IPADM_EAUTH);
13636e91bba0SGirish Moodalbail 
13646e91bba0SGirish Moodalbail 	/* Validate the `ifname' for any logical interface. */
13656e91bba0SGirish Moodalbail 	if (flags == 0 || (flags & ~(IPADM_COMMON_OPT_MASK)) ||
13666e91bba0SGirish Moodalbail 	    !i_ipadm_validate_ifname(iph, ifname))
13676e91bba0SGirish Moodalbail 		return (IPADM_INVALID_ARG);
13686e91bba0SGirish Moodalbail 
13696e91bba0SGirish Moodalbail 	if (af == AF_INET || af == AF_UNSPEC)
13706e91bba0SGirish Moodalbail 		status1 = i_ipadm_delete_if(iph, ifname, AF_INET, flags);
13716e91bba0SGirish Moodalbail 	if (af == AF_INET6 || af == AF_UNSPEC)
13726e91bba0SGirish Moodalbail 		status2 = i_ipadm_delete_if(iph, ifname, AF_INET6, flags);
13736e91bba0SGirish Moodalbail 	/*
13746e91bba0SGirish Moodalbail 	 * If the family has been uniquely identified, we return the
13756e91bba0SGirish Moodalbail 	 * associated status, even if that is ENXIO. Calls from ifconfig
13766e91bba0SGirish Moodalbail 	 * which can only unplumb one of IPv4/IPv6 at any time fall under
13776e91bba0SGirish Moodalbail 	 * this category.
13786e91bba0SGirish Moodalbail 	 */
13796e91bba0SGirish Moodalbail 	if (af == AF_INET)
13806e91bba0SGirish Moodalbail 		return (status1);
13816e91bba0SGirish Moodalbail 	else if (af == AF_INET6)
13826e91bba0SGirish Moodalbail 		return (status2);
13836e91bba0SGirish Moodalbail 	else if (af != AF_UNSPEC)
13846e91bba0SGirish Moodalbail 		return (IPADM_INVALID_ARG);
13856e91bba0SGirish Moodalbail 
13866e91bba0SGirish Moodalbail 	/*
13876e91bba0SGirish Moodalbail 	 * If af is AF_UNSPEC, then we return the following:
13886e91bba0SGirish Moodalbail 	 * status1,		if status1 == status2
13896e91bba0SGirish Moodalbail 	 * IPADM_SUCCESS,	if either of status1 or status2 is SUCCESS
13906e91bba0SGirish Moodalbail 	 * 			and the other status is ENXIO
13916e91bba0SGirish Moodalbail 	 * IPADM_ENXIO,		if both status1 and status2 are ENXIO
13926e91bba0SGirish Moodalbail 	 * IPADM_FAILURE	otherwise.
13936e91bba0SGirish Moodalbail 	 */
13946e91bba0SGirish Moodalbail 	if (status1 == status2) {
13956e91bba0SGirish Moodalbail 		/* covers the case when both status1 and status2 are ENXIO */
13966e91bba0SGirish Moodalbail 		return (status1);
13976e91bba0SGirish Moodalbail 	} else if (status1 == IPADM_SUCCESS || status2 == IPADM_SUCCESS) {
13986e91bba0SGirish Moodalbail 		if (status1 == IPADM_SUCCESS)
13996e91bba0SGirish Moodalbail 			other = status2;
14006e91bba0SGirish Moodalbail 		else
14016e91bba0SGirish Moodalbail 			other = status1;
14026e91bba0SGirish Moodalbail 		return (other == IPADM_ENXIO ? IPADM_SUCCESS : IPADM_FAILURE);
14036e91bba0SGirish Moodalbail 	} else {
14046e91bba0SGirish Moodalbail 		return (IPADM_FAILURE);
14056e91bba0SGirish Moodalbail 	}
14066e91bba0SGirish Moodalbail }
14076e91bba0SGirish Moodalbail 
14086e91bba0SGirish Moodalbail /*
14096e91bba0SGirish Moodalbail  * Returns information about all interfaces in both active and persistent
14106e91bba0SGirish Moodalbail  * configuration. If `ifname' is not NULL, it returns only the interface
14116e91bba0SGirish Moodalbail  * identified by `ifname'.
14126e91bba0SGirish Moodalbail  *
14136e91bba0SGirish Moodalbail  * Return values:
14146e91bba0SGirish Moodalbail  * 	On success: IPADM_SUCCESS.
14156e91bba0SGirish Moodalbail  * 	On error  : IPADM_INVALID_ARG, IPADM_ENXIO or IPADM_FAILURE.
14166e91bba0SGirish Moodalbail  */
14176e91bba0SGirish Moodalbail ipadm_status_t
14186e91bba0SGirish Moodalbail ipadm_if_info(ipadm_handle_t iph, const char *ifname,
14196e91bba0SGirish Moodalbail     ipadm_if_info_t **if_info, uint32_t flags, int64_t lifc_flags)
14206e91bba0SGirish Moodalbail {
14216e91bba0SGirish Moodalbail 	ipadm_status_t	status;
14226e91bba0SGirish Moodalbail 	ifspec_t	ifsp;
14236e91bba0SGirish Moodalbail 
14246e91bba0SGirish Moodalbail 	if (if_info == NULL || iph == NULL || flags != 0)
14256e91bba0SGirish Moodalbail 		return (IPADM_INVALID_ARG);
14266e91bba0SGirish Moodalbail 
14276e91bba0SGirish Moodalbail 	if (ifname != NULL &&
14286e91bba0SGirish Moodalbail 	    (!ifparse_ifspec(ifname, &ifsp) || ifsp.ifsp_lunvalid)) {
14296e91bba0SGirish Moodalbail 		return (IPADM_INVALID_ARG);
14306e91bba0SGirish Moodalbail 	}
14316e91bba0SGirish Moodalbail 
14326e91bba0SGirish Moodalbail 	status = i_ipadm_get_all_if_info(iph, ifname, if_info, lifc_flags);
14336e91bba0SGirish Moodalbail 	if (status != IPADM_SUCCESS)
14346e91bba0SGirish Moodalbail 		return (status);
14356e91bba0SGirish Moodalbail 	if (ifname != NULL && *if_info == NULL)
14366e91bba0SGirish Moodalbail 		return (IPADM_ENXIO);
14376e91bba0SGirish Moodalbail 
14386e91bba0SGirish Moodalbail 	return (IPADM_SUCCESS);
14396e91bba0SGirish Moodalbail }
14406e91bba0SGirish Moodalbail 
14416e91bba0SGirish Moodalbail /*
14426e91bba0SGirish Moodalbail  * Frees the linked list allocated by ipadm_if_info().
14436e91bba0SGirish Moodalbail  */
14446e91bba0SGirish Moodalbail void
14456e91bba0SGirish Moodalbail ipadm_free_if_info(ipadm_if_info_t *ifinfo)
14466e91bba0SGirish Moodalbail {
14476e91bba0SGirish Moodalbail 	ipadm_if_info_t	*ifinfo_next;
14486e91bba0SGirish Moodalbail 
14496e91bba0SGirish Moodalbail 	for (; ifinfo != NULL; ifinfo = ifinfo_next) {
14506e91bba0SGirish Moodalbail 		ifinfo_next = ifinfo->ifi_next;
14516e91bba0SGirish Moodalbail 		free(ifinfo);
14526e91bba0SGirish Moodalbail 	}
14536e91bba0SGirish Moodalbail }
14546e91bba0SGirish Moodalbail 
14556e91bba0SGirish Moodalbail /*
14566e91bba0SGirish Moodalbail  * Re-enable the interface `ifname' based on the saved configuration
14576e91bba0SGirish Moodalbail  * for `ifname'.
14586e91bba0SGirish Moodalbail  */
14596e91bba0SGirish Moodalbail ipadm_status_t
14606e91bba0SGirish Moodalbail ipadm_enable_if(ipadm_handle_t iph, const char *ifname, uint32_t flags)
14616e91bba0SGirish Moodalbail {
14626e91bba0SGirish Moodalbail 	nvlist_t	*ifnvl;
14636e91bba0SGirish Moodalbail 	ipadm_status_t	status;
14646e91bba0SGirish Moodalbail 	ifspec_t	ifsp;
14656e91bba0SGirish Moodalbail 
14666e91bba0SGirish Moodalbail 	/* Check for the required authorization */
14676e91bba0SGirish Moodalbail 	if (!ipadm_check_auth())
14686e91bba0SGirish Moodalbail 		return (IPADM_EAUTH);
14696e91bba0SGirish Moodalbail 
14706e91bba0SGirish Moodalbail 	/* Check for logical interfaces. */
14716e91bba0SGirish Moodalbail 	if (!ifparse_ifspec(ifname, &ifsp) || ifsp.ifsp_lunvalid)
14726e91bba0SGirish Moodalbail 		return (IPADM_INVALID_ARG);
14736e91bba0SGirish Moodalbail 
14746e91bba0SGirish Moodalbail 	/* Enabling an interface persistently is not supported. */
14756e91bba0SGirish Moodalbail 	if (flags & IPADM_OPT_PERSIST)
14766e91bba0SGirish Moodalbail 		return (IPADM_NOTSUP);
14776e91bba0SGirish Moodalbail 
14786e91bba0SGirish Moodalbail 	/*
14796e91bba0SGirish Moodalbail 	 * Return early by checking if the interface is already enabled.
14806e91bba0SGirish Moodalbail 	 */
14816e91bba0SGirish Moodalbail 	if (ipadm_if_enabled(iph, ifname, AF_INET) &&
14826e91bba0SGirish Moodalbail 	    ipadm_if_enabled(iph, ifname, AF_INET6)) {
14836e91bba0SGirish Moodalbail 		return (IPADM_IF_EXISTS);
14846e91bba0SGirish Moodalbail 	}
14856e91bba0SGirish Moodalbail 	/*
14866e91bba0SGirish Moodalbail 	 * Enable the interface and restore all its interface properties
14876e91bba0SGirish Moodalbail 	 * and address objects.
14886e91bba0SGirish Moodalbail 	 */
14896e91bba0SGirish Moodalbail 	status = i_ipadm_init_ifs(iph, ifname, &ifnvl);
14906e91bba0SGirish Moodalbail 	if (status != IPADM_SUCCESS)
14916e91bba0SGirish Moodalbail 		return (status);
14926e91bba0SGirish Moodalbail 
14936e91bba0SGirish Moodalbail 	assert(ifnvl != NULL);
14946e91bba0SGirish Moodalbail 	/*
14956e91bba0SGirish Moodalbail 	 * ipadm_enable_if() does exactly what ipadm_init_ifs() does,
14966e91bba0SGirish Moodalbail 	 * but only for one interface. We need to set IPH_INIT because
14976e91bba0SGirish Moodalbail 	 * ipmgmtd daemon does not have to write the interface to persistent
14986e91bba0SGirish Moodalbail 	 * db. The interface is already available in persistent db
14996e91bba0SGirish Moodalbail 	 * and we are here to re-enable the persistent configuration.
15006e91bba0SGirish Moodalbail 	 */
15016e91bba0SGirish Moodalbail 	iph->iph_flags |= IPH_INIT;
15026e91bba0SGirish Moodalbail 	status = i_ipadm_init_ifobj(iph, ifname, ifnvl);
15036e91bba0SGirish Moodalbail 	iph->iph_flags &= ~IPH_INIT;
15046e91bba0SGirish Moodalbail 	return (status);
15056e91bba0SGirish Moodalbail }
15066e91bba0SGirish Moodalbail 
15076e91bba0SGirish Moodalbail /*
15086e91bba0SGirish Moodalbail  * Disable the interface `ifname' by removing it from the active configuration.
15096e91bba0SGirish Moodalbail  * Error code return values follow the model in ipadm_delete_if()
15106e91bba0SGirish Moodalbail  */
15116e91bba0SGirish Moodalbail ipadm_status_t
15126e91bba0SGirish Moodalbail ipadm_disable_if(ipadm_handle_t iph, const char *ifname, uint32_t flags)
15136e91bba0SGirish Moodalbail {
15146e91bba0SGirish Moodalbail 	ipadm_status_t	status1, status2, other;
15156e91bba0SGirish Moodalbail 	ifspec_t	ifsp;
15166e91bba0SGirish Moodalbail 
15176e91bba0SGirish Moodalbail 	/* Check for the required authorization */
15186e91bba0SGirish Moodalbail 	if (!ipadm_check_auth())
15196e91bba0SGirish Moodalbail 		return (IPADM_EAUTH);
15206e91bba0SGirish Moodalbail 
15216e91bba0SGirish Moodalbail 	/* Check for logical interfaces. */
15226e91bba0SGirish Moodalbail 	if (!ifparse_ifspec(ifname, &ifsp) || ifsp.ifsp_lunvalid)
15236e91bba0SGirish Moodalbail 		return (IPADM_INVALID_ARG);
15246e91bba0SGirish Moodalbail 
15256e91bba0SGirish Moodalbail 	/* Disabling an interface persistently is not supported. */
15266e91bba0SGirish Moodalbail 	if (flags & IPADM_OPT_PERSIST)
15276e91bba0SGirish Moodalbail 		return (IPADM_NOTSUP);
15286e91bba0SGirish Moodalbail 
15296e91bba0SGirish Moodalbail 	status1 = i_ipadm_unplumb_if(iph, ifname, AF_INET6);
15306e91bba0SGirish Moodalbail 	if (status1 == IPADM_SUCCESS)
15316e91bba0SGirish Moodalbail 		status1 = i_ipadm_delete_ifobj(iph, ifname, AF_INET6, B_FALSE);
15326e91bba0SGirish Moodalbail 	status2 = i_ipadm_unplumb_if(iph, ifname, AF_INET);
15336e91bba0SGirish Moodalbail 	if (status2 == IPADM_SUCCESS)
15346e91bba0SGirish Moodalbail 		status2 = i_ipadm_delete_ifobj(iph, ifname, AF_INET, B_FALSE);
15356e91bba0SGirish Moodalbail 	if (status1 == status2) {
15366e91bba0SGirish Moodalbail 		return (status2);
15376e91bba0SGirish Moodalbail 	} else if (status1 == IPADM_SUCCESS || status2 == IPADM_SUCCESS) {
15386e91bba0SGirish Moodalbail 		if (status1 == IPADM_SUCCESS)
15396e91bba0SGirish Moodalbail 			other = status2;
15406e91bba0SGirish Moodalbail 		else
15416e91bba0SGirish Moodalbail 			other = status1;
15426e91bba0SGirish Moodalbail 		return (other == IPADM_ENXIO ? IPADM_SUCCESS : IPADM_FAILURE);
15436e91bba0SGirish Moodalbail 	} else {
15446e91bba0SGirish Moodalbail 		return (IPADM_FAILURE);
15456e91bba0SGirish Moodalbail 	}
15466e91bba0SGirish Moodalbail }
154736b41818SGirish Moodalbail 
154836b41818SGirish Moodalbail /*
154936b41818SGirish Moodalbail  * This workaround is until libipadm supports IPMP and is required whenever an
155036b41818SGirish Moodalbail  * interface is moved into an IPMP group. Since libipadm doesn't support IPMP
155136b41818SGirish Moodalbail  * yet, we will have to update the daemon's in-memory mapping of
155236b41818SGirish Moodalbail  * `aobjname' to 'lifnum'.
155336b41818SGirish Moodalbail  *
155436b41818SGirish Moodalbail  * For `IPMGMT_ACTIVE' case, i_ipadm_delete_ifobj() would only fail if
155536b41818SGirish Moodalbail  * door_call(3C) fails. Also, there is no use in returning error because
155636b41818SGirish Moodalbail  * `ifname' would have been successfuly moved into IPMP group, by this time.
155736b41818SGirish Moodalbail  */
155836b41818SGirish Moodalbail void
155936b41818SGirish Moodalbail ipadm_if_move(ipadm_handle_t iph, const char *ifname)
156036b41818SGirish Moodalbail {
156136b41818SGirish Moodalbail 	(void) i_ipadm_delete_ifobj(iph, ifname, AF_INET, B_FALSE);
156236b41818SGirish Moodalbail 	(void) i_ipadm_delete_ifobj(iph, ifname, AF_INET6, B_FALSE);
156336b41818SGirish Moodalbail }
1564