Lock up ifaddr reference counts.

This commit is contained in:
Jeffrey Hsu 2002-12-18 11:46:59 +00:00
parent 9a26e46eb4
commit 19fc74fb60
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=108033
8 changed files with 56 additions and 58 deletions

View File

@ -425,6 +425,7 @@ if_attach(ifp)
ifasize = sizeof(*ifa) + 2 * socksize;
ifa = (struct ifaddr *)malloc(ifasize, M_IFADDR, M_WAITOK | M_ZERO);
if (ifa) {
IFA_LOCK_INIT(ifa);
sdl = (struct sockaddr_dl *)(ifa + 1);
sdl->sdl_len = socksize;
sdl->sdl_family = AF_LINK;
@ -441,6 +442,7 @@ if_attach(ifp)
sdl->sdl_len = masklen;
while (namelen != 0)
sdl->sdl_data[--namelen] = 0xff;
ifa->ifa_refcnt = 1;
TAILQ_INSERT_HEAD(&ifp->if_addrhead, ifa, ifa_link);
}
ifp->if_broadcastaddr = 0; /* reliably crash if used uninitialized */
@ -830,6 +832,9 @@ if_clone_list(ifcr)
return (error);
}
#define equal(a1, a2) \
(bcmp((caddr_t)(a1), (caddr_t)(a2), ((struct sockaddr *)(a1))->sa_len) == 0)
/*
* Locate an interface based on a complete address.
*/
@ -841,8 +846,6 @@ ifa_ifwithaddr(addr)
struct ifnet *ifp;
struct ifaddr *ifa;
#define equal(a1, a2) \
(bcmp((caddr_t)(a1), (caddr_t)(a2), ((struct sockaddr *)(a1))->sa_len) == 0)
TAILQ_FOREACH(ifp, &ifnet, if_link)
TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
if (ifa->ifa_addr->sa_family != addr->sa_family)
@ -1051,8 +1054,8 @@ link_rtrequest(cmd, rt, info)
ifa = ifaof_ifpforaddr(dst, ifp);
if (ifa) {
IFAFREE(rt->rt_ifa);
IFAREF(ifa); /* XXX */
rt->rt_ifa = ifa;
ifa->ifa_refcnt++;
if (ifa->ifa_rtrequest && ifa->ifa_rtrequest != link_rtrequest)
ifa->ifa_rtrequest(cmd, rt, info);
}

View File

@ -348,13 +348,19 @@ struct ifaddr {
#endif
int (*ifa_claim_addr) /* check if an addr goes to this if */
(struct ifaddr *, struct sockaddr *);
struct mtx ifa_mtx;
};
#define IFA_ROUTE RTF_UP /* route installed */
/* for compatibility with other BSDs */
#define ifa_list ifa_link
#define IFA_LOCK_INIT(ifa) \
mtx_init(&(ifa)->ifa_mtx, "ifaddr", NULL, MTX_DEF)
#define IFA_LOCK(ifa) mtx_lock(&(ifa)->ifa_mtx)
#define IFA_UNLOCK(ifa) mtx_unlock(&(ifa)->ifa_mtx)
#define IFA_DESTROY(ifa) mtx_destroy(&(ifa)->ifa_mtx)
/*
* The prefix structure contains information about one prefix
* of an interface. They are maintained by the different address families,
@ -385,12 +391,23 @@ struct ifmultiaddr {
};
#ifdef _KERNEL
#define IFAFREE(ifa) \
do { \
if ((ifa)->ifa_refcnt <= 0) \
ifafree(ifa); \
else \
(ifa)->ifa_refcnt--; \
#define IFAFREE(ifa) \
do { \
IFA_LOCK(ifa); \
if ((ifa)->ifa_refcnt == 0) { \
IFA_DESTROY(ifa); \
free(ifa, M_IFADDR); \
} else { \
--(ifa)->ifa_refcnt; \
IFA_UNLOCK(ifa); \
} \
} while (0)
#define IFAREF(ifa) \
do { \
IFA_LOCK(ifa); \
++(ifa)->ifa_refcnt; \
IFA_UNLOCK(ifa); \
} while (0)
struct ifindex_entry {
@ -438,7 +455,6 @@ struct ifaddr *ifa_ifwithdstaddr(struct sockaddr *);
struct ifaddr *ifa_ifwithnet(struct sockaddr *);
struct ifaddr *ifa_ifwithroute(int, struct sockaddr *, struct sockaddr *);
struct ifaddr *ifaof_ifpforaddr(struct sockaddr *, struct ifnet *);
void ifafree(struct ifaddr *);
struct ifmultiaddr *ifmaof_ifpforaddr(struct sockaddr *, struct ifnet *);
int if_simloop(struct ifnet *ifp, struct mbuf *m, int af, int hlen);

View File

@ -304,9 +304,6 @@ extern const char *if_name(struct ifnet *);
#define if_addrlist if_addrhead
#define if_list if_link
/* sys/net/if.h */
#define IFAREF(ifa) do { ++(ifa)->ifa_refcnt; } while (0)
#define WITH_CONVERT_AND_STRIP_IP_LEN
#if 1 /* at this moment, all OSes do this */

View File

@ -213,7 +213,6 @@ rtfree(rt)
*/
register struct radix_node_head *rnh =
rt_tables[rt_key(rt)->sa_family];
register struct ifaddr *ifa;
if (rt == 0 || rnh == 0)
panic("rtfree");
@ -252,11 +251,10 @@ rtfree(rt)
* release references on items we hold them on..
* e.g other routes and ifaddrs.
*/
if((ifa = rt->rt_ifa))
IFAFREE(ifa);
if (rt->rt_parent) {
if (rt->rt_ifa)
IFAFREE(rt->rt_ifa);
if (rt->rt_parent)
RTFREE(rt->rt_parent);
}
/*
* The key is separatly alloc'd so free it (see rt_setgate()).
@ -272,17 +270,7 @@ rtfree(rt)
}
}
void
ifafree(ifa)
register struct ifaddr *ifa;
{
if (ifa == NULL)
panic("ifafree");
if (ifa->ifa_refcnt == 0)
free(ifa, M_IFADDR);
else
ifa->ifa_refcnt--;
}
#define equal(a1, a2) (bcmp((caddr_t)(a1), (caddr_t)(a2), (a1)->sa_len) == 0)
/*
* Force a routing table entry to the specified
@ -317,7 +305,6 @@ rtredirect(dst, gateway, netmask, flags, src, rtp)
* we have a routing loop, perhaps as a result of an interface
* going down recently.
*/
#define equal(a1, a2) (bcmp((caddr_t)(a1), (caddr_t)(a2), (a1)->sa_len) == 0)
if (!(flags & RTF_DONE) && rt &&
(!equal(src, rt->rt_gateway) || rt->rt_ifa != ifa))
error = EINVAL;
@ -394,8 +381,8 @@ out:
}
/*
* Routing table ioctl interface.
*/
* Routing table ioctl interface.
*/
int
rtioctl(req, data)
u_long req;
@ -443,7 +430,7 @@ ifa_ifwithroute(flags, dst, gateway)
struct rtentry *rt = rtalloc1(gateway, 0, 0UL);
if (rt == 0)
return (0);
rt->rt_refcnt--;
--rt->rt_refcnt;
if ((ifa = rt->rt_ifa) == 0)
return (0);
}
@ -679,7 +666,7 @@ rtrequest1(req, info, ret_nrt)
* This moved from below so that rnh->rnh_addaddr() can
* examine the ifa and ifa->ifa_ifp if it so desires.
*/
ifa->ifa_refcnt++;
IFAREF(ifa);
rt->rt_ifa = ifa;
rt->rt_ifp = ifa->ifa_ifp;
/* XXX mtu manipulation will be done in rnh_addaddr -- itojun */

View File

@ -428,12 +428,14 @@ route_output(m, so)
if ((ifa = info.rti_ifa) != NULL) {
register struct ifaddr *oifa = rt->rt_ifa;
if (oifa != ifa) {
if (oifa && oifa->ifa_rtrequest)
oifa->ifa_rtrequest(RTM_DELETE, rt,
&info);
IFAFREE(rt->rt_ifa);
if (oifa) {
IFAFREE(oifa);
if (oifa->ifa_rtrequest)
oifa->ifa_rtrequest(RTM_DELETE, rt,
&info);
}
IFAREF(ifa);
rt->rt_ifa = ifa;
ifa->ifa_refcnt++;
rt->rt_ifp = info.rti_ifp;
}
}

View File

@ -159,12 +159,6 @@ at_control(struct socket *so, u_long cmd, caddr_t data,
} else {
at_ifaddr = aa0;
}
/*
* Don't Add a reference for the aa itself!
* I fell into this trap. IFAFREE tests for <=0
* not <= 1 like RTFREE
*/
/* aa->aa_ifa.ifa_refcnt++; DON'T DO THIS!! */
aa = aa0;
/*
@ -172,13 +166,10 @@ at_control(struct socket *so, u_long cmd, caddr_t data,
* and link our new one on the end
*/
ifa = (struct ifaddr *)aa;
IFA_LOCK_INIT(ifa);
ifa->ifa_refcnt = 1;
TAILQ_INSERT_TAIL(&ifp->if_addrhead, ifa, ifa_link);
/*
* Add a reference for the linking into the ifp_if_addrlist.
*/
ifa->ifa_refcnt++;
/*
* As the at_ifaddr contains the actual sockaddrs,
* and the ifaddr itself, link them al together correctly.

View File

@ -276,14 +276,16 @@ in_control(so, cmd, data, ifp, td)
* while we're modifying it.
*/
s = splnet();
TAILQ_INSERT_TAIL(&in_ifaddrhead, ia, ia_link);
ifa = &ia->ia_ifa;
TAILQ_INSERT_TAIL(&ifp->if_addrhead, ifa, ifa_link);
ifa = &ia->ia_ifa;
IFA_LOCK_INIT(ifa);
ifa->ifa_addr = (struct sockaddr *)&ia->ia_addr;
ifa->ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr;
ifa->ifa_netmask = (struct sockaddr *)&ia->ia_sockmask;
ifa->ifa_refcnt = 1;
TAILQ_INSERT_TAIL(&ifp->if_addrhead, ifa, ifa_link);
ia->ia_sockmask.sin_len = 8;
ia->ia_sockmask.sin_family = AF_INET;
if (ifp->if_flags & IFF_BROADCAST) {

View File

@ -908,6 +908,7 @@ in6_update_ifa(ifp, ifra, ia)
return (ENOBUFS);
bzero((caddr_t)ia, sizeof(*ia));
/* Initialize the address and masks */
IFA_LOCK_INIT(&ia->ia_ifa);
ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
ia->ia_addr.sin6_family = AF_INET6;
ia->ia_addr.sin6_len = sizeof(ia->ia_addr);
@ -921,8 +922,7 @@ in6_update_ifa(ifp, ifra, ia)
} else {
ia->ia_ifa.ifa_dstaddr = NULL;
}
ia->ia_ifa.ifa_netmask
= (struct sockaddr *)&ia->ia_prefixmask;
ia->ia_ifa.ifa_netmask = (struct sockaddr *)&ia->ia_prefixmask;
ia->ia_ifp = ifp;
if ((oia = in6_ifaddr) != NULL) {
@ -932,8 +932,8 @@ in6_update_ifa(ifp, ifra, ia)
} else
in6_ifaddr = ia;
TAILQ_INSERT_TAIL(&ifp->if_addrlist, &ia->ia_ifa,
ifa_list);
ia->ia_ifa.ifa_refcnt = 1;
TAILQ_INSERT_TAIL(&ifp->if_addrlist, &ia->ia_ifa, ifa_list);
}
/* set prefix mask */