svn commit: r230932 - projects/multi-fibv6/head/sys/netinet6

Bjoern A. Zeeb bz at FreeBSD.org
Fri Feb 3 08:50:19 UTC 2012


Author: bz
Date: Fri Feb  3 08:50:19 2012
New Revision: 230932
URL: http://svn.freebsd.org/changeset/base/230932

Log:
  In preparation for multi-FIB IPv6 support, factor the code for joining
  and leaving multicast groups out from in6_update_ifa() and in6_purgeaddr().
  
  Sponsored by:	Cisco Systems, Inc.

Modified:
  projects/multi-fibv6/head/sys/netinet6/in6.c

Modified: projects/multi-fibv6/head/sys/netinet6/in6.c
==============================================================================
--- projects/multi-fibv6/head/sys/netinet6/in6.c	Fri Feb  3 05:00:43 2012	(r230931)
+++ projects/multi-fibv6/head/sys/netinet6/in6.c	Fri Feb  3 08:50:19 2012	(r230932)
@@ -821,6 +821,169 @@ out:
 }
 
 /*
+ * Join necessary multicast groups.  Factored out from in6_update_ifa().
+ * This entire work should only be done once, for the default FIB.
+ */
+static int
+in6_update_ifa_join_mc(struct ifnet *ifp, struct in6_aliasreq *ifra,
+    struct in6_ifaddr *ia, int flags, struct in6_multi **in6m_sol)
+{
+	char ip6buf[INET6_ADDRSTRLEN];
+	struct sockaddr_in6 mltaddr, mltmask;
+	struct in6_addr llsol;
+	struct in6_multi_mship *imm;
+	struct rtentry *rt;
+	int delay, error;
+
+	KASSERT(in6m_sol != NULL, ("%s: in6m_sol is NULL", __func__));
+
+	/* Join solicited multicast addr for new host id. */
+	bzero(&llsol, sizeof(struct in6_addr));
+	llsol.s6_addr32[0] = IPV6_ADDR_INT32_MLL;
+	llsol.s6_addr32[1] = 0;
+	llsol.s6_addr32[2] = htonl(1);
+	llsol.s6_addr32[3] = ifra->ifra_addr.sin6_addr.s6_addr32[3];
+	llsol.s6_addr8[12] = 0xff;
+	if ((error = in6_setscope(&llsol, ifp, NULL)) != 0) {
+		/* XXX: should not happen */
+		log(LOG_ERR, "%s: in6_setscope failed\n", __func__);
+		goto cleanup;
+	}
+	delay = 0;
+	if ((flags & IN6_IFAUPDATE_DADDELAY)) {
+		/*
+		 * We need a random delay for DAD on the address being
+		 * configured.  It also means delaying transmission of the
+		 * corresponding MLD report to avoid report collision.
+		 * [RFC 4861, Section 6.3.7]
+		 */
+		delay = arc4random() % (MAX_RTR_SOLICITATION_DELAY * hz);
+	}
+	imm = in6_joingroup(ifp, &llsol, &error, delay);
+	if (imm == NULL) {
+		nd6log((LOG_WARNING, "%s: addmulti failed for %s on %s "
+		    "(errno=%d)\n", __func__, ip6_sprintf(ip6buf, &llsol),
+		    if_name(ifp), error));
+		goto cleanup;
+	}
+	LIST_INSERT_HEAD(&ia->ia6_memberships, imm, i6mm_chain);
+	*in6m_sol = imm->i6mm_maddr;
+
+	bzero(&mltmask, sizeof(mltmask));
+	mltmask.sin6_len = sizeof(struct sockaddr_in6);
+	mltmask.sin6_family = AF_INET6;
+	mltmask.sin6_addr = in6mask32;
+#define	MLTMASK_LEN  4	/* mltmask's masklen (=32bit=4octet) */
+
+	/*
+	 * Join link-local all-nodes address.
+	 */
+	bzero(&mltaddr, sizeof(mltaddr));
+	mltaddr.sin6_len = sizeof(struct sockaddr_in6);
+	mltaddr.sin6_family = AF_INET6;
+	mltaddr.sin6_addr = in6addr_linklocal_allnodes;
+	if ((error = in6_setscope(&mltaddr.sin6_addr, ifp, NULL)) != 0)
+		goto cleanup; /* XXX: should not fail */
+
+	/*
+	 * XXX: do we really need this automatic routes?  We should probably
+	 * reconsider this stuff.  Most applications actually do not need the
+	 * routes, since they usually specify the outgoing interface.
+	 */
+	rt = rtalloc1((struct sockaddr *)&mltaddr, 0, 0UL);
+	if (rt != NULL) {
+		/* XXX: only works in !SCOPEDROUTING case. */
+		if (memcmp(&mltaddr.sin6_addr,
+		    &((struct sockaddr_in6 *)rt_key(rt))->sin6_addr,
+		    MLTMASK_LEN)) {
+			RTFREE_LOCKED(rt);
+			rt = NULL;
+		}
+	}
+	if (rt == NULL) {
+		error = rtrequest(RTM_ADD, (struct sockaddr *)&mltaddr,
+		    (struct sockaddr *)&ia->ia_addr,
+		    (struct sockaddr *)&mltmask, RTF_UP,
+		    (struct rtentry **)0);
+		if (error)
+			goto cleanup;
+	} else
+		RTFREE_LOCKED(rt);
+
+	imm = in6_joingroup(ifp, &mltaddr.sin6_addr, &error, 0);
+	if (imm == NULL) {
+		nd6log((LOG_WARNING, "%s: addmulti failed for %s on %s "
+		    "(errno=%d)\n", __func__, ip6_sprintf(ip6buf,
+		    &mltaddr.sin6_addr), if_name(ifp), error));
+		goto cleanup;
+	}
+	LIST_INSERT_HEAD(&ia->ia6_memberships, imm, i6mm_chain);
+
+	/*
+	 * Join node information group address.
+	 */
+	delay = 0;
+	if ((flags & IN6_IFAUPDATE_DADDELAY)) {
+		/*
+		 * The spec does not say anything about delay for this group,
+		 * but the same logic should apply.
+		 */
+		delay = arc4random() % (MAX_RTR_SOLICITATION_DELAY * hz);
+	}
+	if (in6_nigroup(ifp, NULL, -1, &mltaddr.sin6_addr) == 0) {
+		/* XXX jinmei */
+		imm = in6_joingroup(ifp, &mltaddr.sin6_addr, &error, delay);
+		if (imm == NULL)
+			nd6log((LOG_WARNING, "%s: addmulti failed for %s on %s "
+			    "(errno=%d)\n", __func__, ip6_sprintf(ip6buf,
+			    &mltaddr.sin6_addr), if_name(ifp), error));
+			/* XXX not very fatal, go on... */
+		else
+			LIST_INSERT_HEAD(&ia->ia6_memberships, imm, i6mm_chain);
+	}
+
+	/*
+	 * Join interface-local all-nodes address.
+	 * (ff01::1%ifN, and ff01::%ifN/32)
+	 */
+	mltaddr.sin6_addr = in6addr_nodelocal_allnodes;
+	if ((error = in6_setscope(&mltaddr.sin6_addr, ifp, NULL)) != 0)
+		goto cleanup; /* XXX: should not fail */
+	/* XXX: again, do we really need the route? */
+	rt = rtalloc1((struct sockaddr *)&mltaddr, 0, 0UL);
+	if (rt != NULL) {
+		if (memcmp(&mltaddr.sin6_addr,
+		    &((struct sockaddr_in6 *)rt_key(rt))->sin6_addr,
+		    MLTMASK_LEN)) {
+			RTFREE_LOCKED(rt);
+			rt = NULL;
+		}
+	}
+	if (rt == NULL) {
+		error = rtrequest(RTM_ADD, (struct sockaddr *)&mltaddr,
+		    (struct sockaddr *)&ia->ia_addr,
+		    (struct sockaddr *)&mltmask, RTF_UP,
+		    (struct rtentry **)0);
+		if (error)
+			goto cleanup;
+	} else
+		RTFREE_LOCKED(rt);
+
+	imm = in6_joingroup(ifp, &mltaddr.sin6_addr, &error, 0);
+	if (imm == NULL) {
+		nd6log((LOG_WARNING, "%s: addmulti failed for %s on %s "
+		    "(errno=%d)\n", __func__, ip6_sprintf(ip6buf,
+		    &mltaddr.sin6_addr), if_name(ifp), error));
+		goto cleanup;
+	}
+	LIST_INSERT_HEAD(&ia->ia6_memberships, imm, i6mm_chain);
+#undef	MLTMASK_LEN
+
+cleanup:
+	return (error);
+}
+
+/*
  * Update parameters of an IPv6 interface address.
  * If necessary, a new entry is created and linked into address chains.
  * This function is separated from in6_control().
@@ -833,9 +996,7 @@ in6_update_ifa(struct ifnet *ifp, struct
 	int error = 0, hostIsNew = 0, plen = -1;
 	struct sockaddr_in6 dst6;
 	struct in6_addrlifetime *lt;
-	struct in6_multi_mship *imm;
 	struct in6_multi *in6m_sol;
-	struct rtentry *rt;
 	int delay;
 	char ip6buf[INET6_ADDRSTRLEN];
 
@@ -1083,172 +1244,12 @@ in6_update_ifa(struct ifnet *ifp, struct
 	 * not just go to unlink.
 	 */
 
-	/* Join necessary multicast groups */
+	/* Join necessary multicast groups. */
 	in6m_sol = NULL;
 	if ((ifp->if_flags & IFF_MULTICAST) != 0) {
-		struct sockaddr_in6 mltaddr, mltmask;
-		struct in6_addr llsol;
-
-		/* join solicited multicast addr for new host id */
-		bzero(&llsol, sizeof(struct in6_addr));
-		llsol.s6_addr32[0] = IPV6_ADDR_INT32_MLL;
-		llsol.s6_addr32[1] = 0;
-		llsol.s6_addr32[2] = htonl(1);
-		llsol.s6_addr32[3] = ifra->ifra_addr.sin6_addr.s6_addr32[3];
-		llsol.s6_addr8[12] = 0xff;
-		if ((error = in6_setscope(&llsol, ifp, NULL)) != 0) {
-			/* XXX: should not happen */
-			log(LOG_ERR, "in6_update_ifa: "
-			    "in6_setscope failed\n");
-			goto cleanup;
-		}
-		delay = 0;
-		if ((flags & IN6_IFAUPDATE_DADDELAY)) {
-			/*
-			 * We need a random delay for DAD on the address
-			 * being configured.  It also means delaying
-			 * transmission of the corresponding MLD report to
-			 * avoid report collision.
-			 * [RFC 4861, Section 6.3.7]
-			 */
-			delay = arc4random() %
-			    (MAX_RTR_SOLICITATION_DELAY * hz);
-		}
-		imm = in6_joingroup(ifp, &llsol, &error, delay);
-		if (imm == NULL) {
-			nd6log((LOG_WARNING,
-			    "in6_update_ifa: addmulti failed for "
-			    "%s on %s (errno=%d)\n",
-			    ip6_sprintf(ip6buf, &llsol), if_name(ifp),
-			    error));
-			goto cleanup;
-		}
-		LIST_INSERT_HEAD(&ia->ia6_memberships,
-		    imm, i6mm_chain);
-		in6m_sol = imm->i6mm_maddr;
-
-		bzero(&mltmask, sizeof(mltmask));
-		mltmask.sin6_len = sizeof(struct sockaddr_in6);
-		mltmask.sin6_family = AF_INET6;
-		mltmask.sin6_addr = in6mask32;
-#define	MLTMASK_LEN  4	/* mltmask's masklen (=32bit=4octet) */
-
-		/*
-		 * join link-local all-nodes address
-		 */
-		bzero(&mltaddr, sizeof(mltaddr));
-		mltaddr.sin6_len = sizeof(struct sockaddr_in6);
-		mltaddr.sin6_family = AF_INET6;
-		mltaddr.sin6_addr = in6addr_linklocal_allnodes;
-		if ((error = in6_setscope(&mltaddr.sin6_addr, ifp, NULL)) !=
-		    0)
-			goto cleanup; /* XXX: should not fail */
-
-		/*
-		 * XXX: do we really need this automatic routes?
-		 * We should probably reconsider this stuff.  Most applications
-		 * actually do not need the routes, since they usually specify
-		 * the outgoing interface.
-		 */
-		rt = rtalloc1((struct sockaddr *)&mltaddr, 0, 0UL);
-		if (rt) {
-			/* XXX: only works in !SCOPEDROUTING case. */
-			if (memcmp(&mltaddr.sin6_addr,
-			    &((struct sockaddr_in6 *)rt_key(rt))->sin6_addr,
-			    MLTMASK_LEN)) {
-				RTFREE_LOCKED(rt);
-				rt = NULL;
-			}
-		}
-		if (!rt) {
-			error = rtrequest(RTM_ADD, (struct sockaddr *)&mltaddr,
-			    (struct sockaddr *)&ia->ia_addr,
-			    (struct sockaddr *)&mltmask, RTF_UP,
-			    (struct rtentry **)0);
-			if (error)
-				goto cleanup;
-		} else {
-			RTFREE_LOCKED(rt);
-		}
-
-		imm = in6_joingroup(ifp, &mltaddr.sin6_addr, &error, 0);
-		if (!imm) {
-			nd6log((LOG_WARNING,
-			    "in6_update_ifa: addmulti failed for "
-			    "%s on %s (errno=%d)\n",
-			    ip6_sprintf(ip6buf, &mltaddr.sin6_addr),
-			    if_name(ifp), error));
-			goto cleanup;
-		}
-		LIST_INSERT_HEAD(&ia->ia6_memberships, imm, i6mm_chain);
-
-		/*
-		 * join node information group address
-		 */
-		delay = 0;
-		if ((flags & IN6_IFAUPDATE_DADDELAY)) {
-			/*
-			 * The spec doesn't say anything about delay for this
-			 * group, but the same logic should apply.
-			 */
-			delay = arc4random() %
-			    (MAX_RTR_SOLICITATION_DELAY * hz);
-		}
-		if (in6_nigroup(ifp, NULL, -1, &mltaddr.sin6_addr) == 0) {
-			imm = in6_joingroup(ifp, &mltaddr.sin6_addr, &error,
-			    delay); /* XXX jinmei */
-			if (!imm) {
-				nd6log((LOG_WARNING, "in6_update_ifa: "
-				    "addmulti failed for %s on %s "
-				    "(errno=%d)\n",
-				    ip6_sprintf(ip6buf, &mltaddr.sin6_addr),
-				    if_name(ifp), error));
-				/* XXX not very fatal, go on... */
-			} else {
-				LIST_INSERT_HEAD(&ia->ia6_memberships,
-				    imm, i6mm_chain);
-			}
-		}
-
-		/*
-		 * join interface-local all-nodes address.
-		 * (ff01::1%ifN, and ff01::%ifN/32)
-		 */
-		mltaddr.sin6_addr = in6addr_nodelocal_allnodes;
-		if ((error = in6_setscope(&mltaddr.sin6_addr, ifp, NULL))
-		    != 0)
-			goto cleanup; /* XXX: should not fail */
-		/* XXX: again, do we really need the route? */
-		rt = rtalloc1((struct sockaddr *)&mltaddr, 0, 0UL);
-		if (rt) {
-			if (memcmp(&mltaddr.sin6_addr,
-			    &((struct sockaddr_in6 *)rt_key(rt))->sin6_addr,
-			    MLTMASK_LEN)) {
-				RTFREE_LOCKED(rt);
-				rt = NULL;
-			}
-		}
-		if (!rt) {
-			error = rtrequest(RTM_ADD, (struct sockaddr *)&mltaddr,
-			    (struct sockaddr *)&ia->ia_addr,
-			    (struct sockaddr *)&mltmask, RTF_UP,
-			    (struct rtentry **)0);
-			if (error)
-				goto cleanup;
-		} else
-			RTFREE_LOCKED(rt);
-
-		imm = in6_joingroup(ifp, &mltaddr.sin6_addr, &error, 0);
-		if (!imm) {
-			nd6log((LOG_WARNING, "in6_update_ifa: "
-			    "addmulti failed for %s on %s "
-			    "(errno=%d)\n",
-			    ip6_sprintf(ip6buf, &mltaddr.sin6_addr),
-			    if_name(ifp), error));
+		error = in6_update_ifa_join_mc(ifp, ifra, ia, flags, &in6m_sol);
+		if (error)
 			goto cleanup;
-		}
-		LIST_INSERT_HEAD(&ia->ia6_memberships, imm, i6mm_chain);
-#undef	MLTMASK_LEN
 	}
 
 	/*
@@ -1312,58 +1313,20 @@ in6_update_ifa(struct ifnet *ifp, struct
 	return error;
 }
 
-void
-in6_purgeaddr(struct ifaddr *ifa)
+/*
+ * Leave multicast groups.  Factored out from in6_purgeaddr().
+ * This entire work should only be done once, for the default FIB.
+ */
+static int
+in6_purgeaddr_mc(struct ifnet *ifp, struct in6_ifaddr *ia, struct ifaddr *ifa0)
 {
-	struct ifnet *ifp = ifa->ifa_ifp;
-	struct in6_ifaddr *ia = (struct in6_ifaddr *) ifa;
-	struct in6_multi_mship *imm;
 	struct sockaddr_in6 mltaddr, mltmask;
-	int plen, error;
+	struct in6_multi_mship *imm;
 	struct rtentry *rt;
-	struct ifaddr *ifa0;
-
-	if (ifa->ifa_carp)
-		(*carp_detach_p)(ifa);
+	int error;
 
 	/*
-	 * find another IPv6 address as the gateway for the
-	 * link-local and node-local all-nodes multicast
-	 * address routes
-	 */
-	IF_ADDR_RLOCK(ifp);
-	TAILQ_FOREACH(ifa0, &ifp->if_addrhead, ifa_link) {
-		if ((ifa0->ifa_addr->sa_family != AF_INET6) ||
-		    memcmp(&satosin6(ifa0->ifa_addr)->sin6_addr,
-			   &ia->ia_addr.sin6_addr, 
-			   sizeof(struct in6_addr)) == 0)
-			continue;
-		else
-			break;
-	}
-	if (ifa0 != NULL)
-		ifa_ref(ifa0);
-	IF_ADDR_RUNLOCK(ifp);
-
-	/*
-	 * Remove the loopback route to the interface address.
-	 * The check for the current setting of "nd6_useloopback" 
-	 * is not needed.
-	 */
-	if (ia->ia_flags & IFA_RTSELF) {
-		error = ifa_del_loopback_route((struct ifaddr *)ia,
-				       (struct sockaddr *)&ia->ia_addr);
-		if (error == 0)
-			ia->ia_flags &= ~IFA_RTSELF;
-	}
-
-	/* stop DAD processing */
-	nd6_dad_stop(ifa);
-
-	in6_ifremloop(ifa);
-
-	/*
-	 * leave from multicast groups we have joined for the interface
+	 * Leave from multicast groups we have joined for the interface.
 	 */
 	while ((imm = LIST_FIRST(&ia->ia6_memberships)) != NULL) {
 		LIST_REMOVE(imm, i6mm_chain);
@@ -1371,7 +1334,7 @@ in6_purgeaddr(struct ifaddr *ifa)
 	}
 
 	/*
-	 * remove the link-local all-nodes address
+	 * Remove the link-local all-nodes address.
 	 */
 	bzero(&mltmask, sizeof(mltmask));
 	mltmask.sin6_len = sizeof(struct sockaddr_in6);
@@ -1384,7 +1347,7 @@ in6_purgeaddr(struct ifaddr *ifa)
 	mltaddr.sin6_addr = in6addr_linklocal_allnodes;
 
 	if ((error = in6_setscope(&mltaddr.sin6_addr, ifp, NULL)) != 0)
-		goto cleanup; 
+		return (error);
 
 	rt = rtalloc1((struct sockaddr *)&mltaddr, 0, 0UL);
 	if (rt != NULL && rt->rt_gateway != NULL &&
@@ -1392,23 +1355,25 @@ in6_purgeaddr(struct ifaddr *ifa)
 		    &ia->ia_addr.sin6_addr,
 		    sizeof(ia->ia_addr.sin6_addr)) == 0)) {
 		/* 
-		 * if no more IPv6 address exists on this interface
-		 * then remove the multicast address route
+		 * If no more IPv6 address exists on this interface then
+		 * remove the multicast address route.
 		 */
 		if (ifa0 == NULL) {
 			memcpy(&mltaddr.sin6_addr, &satosin6(rt_key(rt))->sin6_addr, 
 			       sizeof(mltaddr.sin6_addr));
 			RTFREE_LOCKED(rt);
-			error = rtrequest(RTM_DELETE, (struct sockaddr *)&mltaddr,
-					  (struct sockaddr *)&ia->ia_addr,
-					  (struct sockaddr *)&mltmask, RTF_UP,
-					  (struct rtentry **)0);
+			error = rtrequest(RTM_DELETE,
+			    (struct sockaddr *)&mltaddr,
+			    (struct sockaddr *)&ia->ia_addr,
+			    (struct sockaddr *)&mltmask, RTF_UP,
+			    (struct rtentry **)0);
 			if (error)
-				log(LOG_INFO, "in6_purgeaddr: link-local all-nodes"
-				    "multicast address deletion error\n");
+				log(LOG_INFO, "%s: link-local all-nodes "
+				    "multicast address deletion error\n",
+				    __func__);
 		} else {
 			/*
-			 * replace the gateway of the route
+			 * Replace the gateway of the route.
 			 */
 			struct sockaddr_in6 sa;
 
@@ -1427,12 +1392,11 @@ in6_purgeaddr(struct ifaddr *ifa)
 	}
 
 	/*
-	 * remove the node-local all-nodes address
+	 * Remove the node-local all-nodes address.
 	 */
 	mltaddr.sin6_addr = in6addr_nodelocal_allnodes;
-	if ((error = in6_setscope(&mltaddr.sin6_addr, ifp, NULL)) !=
-	    0)
-		goto cleanup;
+	if ((error = in6_setscope(&mltaddr.sin6_addr, ifp, NULL)) != 0)
+		return (error);
 
 	rt = rtalloc1((struct sockaddr *)&mltaddr, 0, 0UL);
 	if (rt != NULL && rt->rt_gateway != NULL &&
@@ -1440,25 +1404,26 @@ in6_purgeaddr(struct ifaddr *ifa)
 		    &ia->ia_addr.sin6_addr,
 		    sizeof(ia->ia_addr.sin6_addr)) == 0)) {
 		/* 
-		 * if no more IPv6 address exists on this interface
-		 * then remove the multicast address route
+		 * If no more IPv6 address exists on this interface then
+		 * remove the multicast address route.
 		 */
 		if (ifa0 == NULL) {
 			memcpy(&mltaddr.sin6_addr, &satosin6(rt_key(rt))->sin6_addr, 
 			       sizeof(mltaddr.sin6_addr));
 
 			RTFREE_LOCKED(rt);
-			error = rtrequest(RTM_DELETE, (struct sockaddr *)&mltaddr,
-					  (struct sockaddr *)&ia->ia_addr,
-					  (struct sockaddr *)&mltmask, RTF_UP,
-					  (struct rtentry **)0);
-
+			error = rtrequest(RTM_DELETE,
+			    (struct sockaddr *)&mltaddr,
+			    (struct sockaddr *)&ia->ia_addr,
+			    (struct sockaddr *)&mltmask, RTF_UP,
+			    (struct rtentry **)0);
 			if (error)
-				log(LOG_INFO, "in6_purgeaddr: node-local all-nodes"
-				    "multicast address deletion error\n");
+				log(LOG_INFO, "%s: node-local all-nodes"
+				    "multicast address deletion error\n",
+				    __func__);
 		} else {
 			/*
-			 * replace the gateway of the route
+			 * Replace the gateway of the route.
 			 */
 			struct sockaddr_in6 sa;
 
@@ -1476,7 +1441,59 @@ in6_purgeaddr(struct ifaddr *ifa)
 			RTFREE_LOCKED(rt);
 	}
 
-cleanup:
+	return (0);
+}
+
+void
+in6_purgeaddr(struct ifaddr *ifa)
+{
+	struct ifnet *ifp = ifa->ifa_ifp;
+	struct in6_ifaddr *ia = (struct in6_ifaddr *) ifa;
+	int plen, error;
+	struct ifaddr *ifa0;
+
+	if (ifa->ifa_carp)
+		(*carp_detach_p)(ifa);
+
+	/*
+	 * find another IPv6 address as the gateway for the
+	 * link-local and node-local all-nodes multicast
+	 * address routes
+	 */
+	IF_ADDR_RLOCK(ifp);
+	TAILQ_FOREACH(ifa0, &ifp->if_addrhead, ifa_link) {
+		if ((ifa0->ifa_addr->sa_family != AF_INET6) ||
+		    memcmp(&satosin6(ifa0->ifa_addr)->sin6_addr,
+			   &ia->ia_addr.sin6_addr, 
+			   sizeof(struct in6_addr)) == 0)
+			continue;
+		else
+			break;
+	}
+	if (ifa0 != NULL)
+		ifa_ref(ifa0);
+	IF_ADDR_RUNLOCK(ifp);
+
+	/*
+	 * Remove the loopback route to the interface address.
+	 * The check for the current setting of "nd6_useloopback" 
+	 * is not needed.
+	 */
+	if (ia->ia_flags & IFA_RTSELF) {
+		error = ifa_del_loopback_route((struct ifaddr *)ia,
+				       (struct sockaddr *)&ia->ia_addr);
+		if (error == 0)
+			ia->ia_flags &= ~IFA_RTSELF;
+	}
+
+	/* stop DAD processing */
+	nd6_dad_stop(ifa);
+
+	in6_ifremloop(ifa);
+
+	/* Leave multicast groups. */
+	error = in6_purgeaddr_mc(ifp, ia, ifa0);
+
 	if (ifa0 != NULL)
 		ifa_free(ifa0);
 


More information about the svn-src-projects mailing list