Separate out address-detaching part of if_detach into if_purgeaddrs,

so if_tap doesn't need to rely on locally-rolled code to do same.

The observable symptom of if_tap's bzero'ing the address details
was a crash in "ifconfig tap0" after an if_tap device was closed.

Reported By: Matti Saarinen (mjsaarin at cc dot helsinki dot fi)
This commit is contained in:
Peter Edwards 2005-05-25 13:52:03 +00:00
parent 08a94fbcf9
commit 45778b37b2
3 changed files with 45 additions and 46 deletions

View File

@ -529,6 +529,45 @@ if_attachdomain1(struct ifnet *ifp)
splx(s);
}
/*
* Remove any network addresses from an interface.
*/
void
if_purgeaddrs(struct ifnet *ifp)
{
struct ifaddr *ifa, *next;
TAILQ_FOREACH_SAFE(ifa, &ifp->if_addrhead, ifa_link, next) {
if (ifa->ifa_addr->sa_family == AF_LINK)
continue;
#ifdef INET
/* XXX: Ugly!! ad hoc just for INET */
if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET) {
struct ifaliasreq ifr;
bzero(&ifr, sizeof(ifr));
ifr.ifra_addr = *ifa->ifa_addr;
if (ifa->ifa_dstaddr)
ifr.ifra_broadaddr = *ifa->ifa_dstaddr;
if (in_control(NULL, SIOCDIFADDR, (caddr_t)&ifr, ifp,
NULL) == 0)
continue;
}
#endif /* INET */
#ifdef INET6
if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET6) {
in6_purgeaddr(ifa);
/* ifp_addrhead is already updated */
continue;
}
#endif /* INET6 */
TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link);
IFAFREE(ifa);
}
}
/*
* Detach an interface, removing it from the
* list of "active" interfaces.
@ -536,7 +575,7 @@ if_attachdomain1(struct ifnet *ifp)
void
if_detach(struct ifnet *ifp)
{
struct ifaddr *ifa, *next;
struct ifaddr *ifa;
struct radix_node_head *rnh;
int s;
int i;
@ -568,35 +607,7 @@ if_detach(struct ifnet *ifp)
altq_detach(&ifp->if_snd);
#endif
for (ifa = TAILQ_FIRST(&ifp->if_addrhead); ifa; ifa = next) {
next = TAILQ_NEXT(ifa, ifa_link);
if (ifa->ifa_addr->sa_family == AF_LINK)
continue;
#ifdef INET
/* XXX: Ugly!! ad hoc just for INET */
if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET) {
struct ifaliasreq ifr;
bzero(&ifr, sizeof(ifr));
ifr.ifra_addr = *ifa->ifa_addr;
if (ifa->ifa_dstaddr)
ifr.ifra_broadaddr = *ifa->ifa_dstaddr;
if (in_control(NULL, SIOCDIFADDR, (caddr_t)&ifr, ifp,
NULL) == 0)
continue;
}
#endif /* INET */
#ifdef INET6
if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET6) {
in6_purgeaddr(ifa);
/* ifp_addrhead is already updated */
continue;
}
#endif /* INET6 */
TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link);
IFAFREE(ifa);
}
if_purgeaddrs(ifp);
#ifdef INET6
/*

View File

@ -408,6 +408,7 @@ tapclose(dev, foo, bar, td)
int bar;
struct thread *td;
{
struct ifaddr *ifa;
struct tap_softc *tp = dev->si_drv1;
struct ifnet *ifp = &tp->tap_if;
int s;
@ -426,24 +427,10 @@ tapclose(dev, foo, bar, td)
s = splimp();
if_down(ifp);
if (ifp->if_flags & IFF_RUNNING) {
/* find internet addresses and delete routes */
struct ifaddr *ifa = NULL;
/* In desparate need of ifaddr locking. */
TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
if (ifa->ifa_addr->sa_family == AF_INET) {
rtinit(ifa, (int)RTM_DELETE, 0);
/* remove address from interface */
bzero(ifa->ifa_addr,
sizeof(*(ifa->ifa_addr)));
bzero(ifa->ifa_dstaddr,
sizeof(*(ifa->ifa_dstaddr)));
bzero(ifa->ifa_netmask,
sizeof(*(ifa->ifa_netmask)));
}
rtinit(ifa, (int)RTM_DELETE, 0);
}
if_purgeaddrs(ifp);
ifp->if_flags &= ~IFF_RUNNING;
}
splx(s);

View File

@ -629,6 +629,7 @@ int if_allmulti(struct ifnet *, int);
void if_attach(struct ifnet *);
int if_delmulti(struct ifnet *, struct sockaddr *);
void if_detach(struct ifnet *);
void if_purgeaddrs(struct ifnet *);
void if_down(struct ifnet *);
void if_initname(struct ifnet *, const char *, int);
void if_link_state_change(struct ifnet *, int);