void in6_pcbpurgeif0(struct inpcbtable *table, struct ifnet *ifp) { struct in6pcb *in6p, *nin6p; struct ip6_moptions *im6o; struct in6_multi_mship *imm, *nimm; for (in6p = (struct in6pcb *)CIRCLEQ_FIRST(&table->inpt_queue); in6p != (void *)&table->inpt_queue; in6p = nin6p) { nin6p = (struct in6pcb *)CIRCLEQ_NEXT(in6p, in6p_queue); if (in6p->in6p_af != AF_INET6) continue; im6o = in6p->in6p_moptions; if (im6o) { /* * Unselect the outgoing interface if it is being * detached. */ if (im6o->im6o_multicast_ifp == ifp) im6o->im6o_multicast_ifp = NULL; /* * Drop multicast group membership if we joined * through the interface being detached. * XXX controversial - is it really legal for kernel * to force this? */ for (imm = im6o->im6o_memberships.lh_first; imm != NULL; imm = nimm) { nimm = imm->i6mm_chain.le_next; if (imm->i6mm_maddr->in6m_ifp == ifp) { LIST_REMOVE(imm, i6mm_chain); in6_leavegroup(imm); } } } } }
/* * NOTE: in6_ifdetach() does not support loopback if at this moment. * We don't need this function in bsdi, because interfaces are never removed * from the ifnet list in bsdi. */ void in6_ifdetach(struct ifnet *ifp) { struct in6_ifaddr *ia, *oia; struct ifaddr *ifa, *next; struct rtentry *rt; short rtflags; struct in6_multi_mship *imm; /* remove ip6_mrouter stuff */ ip6_mrouter_detach(ifp); /* remove neighbor management table */ nd6_purge(ifp); /* XXX this code is duplicated in in6_purgeif() --dyoung */ /* nuke any of IPv6 addresses we have */ if_purgeaddrs(ifp, AF_INET6, in6_purgeaddr); /* XXX isn't this code is redundant, given the above? --dyoung */ /* XXX doesn't this code replicate code in in6_purgeaddr() ? --dyoung */ /* undo everything done by in6_ifattach(), just in case */ for (ifa = IFADDR_FIRST(ifp); ifa != NULL; ifa = next) { next = IFADDR_NEXT(ifa); if (ifa->ifa_addr->sa_family != AF_INET6 || !IN6_IS_ADDR_LINKLOCAL(&satosin6(&ifa->ifa_addr)->sin6_addr)) { continue; } ia = (struct in6_ifaddr *)ifa; /* * leave from multicast groups we have joined for the interface */ while ((imm = LIST_FIRST(&ia->ia6_memberships)) != NULL) { LIST_REMOVE(imm, i6mm_chain); in6_leavegroup(imm); } /* remove from the routing table */ if ((ia->ia_flags & IFA_ROUTE) && (rt = rtalloc1((struct sockaddr *)&ia->ia_addr, 0))) { rtflags = rt->rt_flags; rtfree(rt); rtrequest(RTM_DELETE, (struct sockaddr *)&ia->ia_addr, (struct sockaddr *)&ia->ia_addr, (struct sockaddr *)&ia->ia_prefixmask, rtflags, NULL); } /* remove from the linked list */ ifa_remove(ifp, &ia->ia_ifa); /* also remove from the IPv6 address chain(itojun&jinmei) */ oia = ia; if (oia == (ia = in6_ifaddr)) in6_ifaddr = ia->ia_next; else { while (ia->ia_next && (ia->ia_next != oia)) ia = ia->ia_next; if (ia->ia_next) ia->ia_next = oia->ia_next; else { nd6log((LOG_ERR, "%s: didn't unlink in6ifaddr from list\n", if_name(ifp))); } } ifafree(&oia->ia_ifa); } /* cleanup multicast address kludge table, if there is any */ in6_purgemkludge(ifp); /* * remove neighbor management table. we call it twice just to make * sure we nuke everything. maybe we need just one call. * XXX: since the first call did not release addresses, some prefixes * might remain. We should call nd6_purge() again to release the * prefixes after removing all addresses above. * (Or can we just delay calling nd6_purge until at this point?) */ nd6_purge(ifp); }