summaryrefslogtreecommitdiffstats
path: root/sys/net
diff options
context:
space:
mode:
authorhsu <hsu@FreeBSD.org>2002-12-18 11:46:59 +0000
committerhsu <hsu@FreeBSD.org>2002-12-18 11:46:59 +0000
commitc3153934cb24d911042c92eedf9e5dd6d7be07e1 (patch)
tree079e82ffd683b796c6432b8bcf3ff23f996d4e04 /sys/net
parent2d0e93bb2eab2533104a92a432361a0d75aae7da (diff)
downloadFreeBSD-src-c3153934cb24d911042c92eedf9e5dd6d7be07e1.zip
FreeBSD-src-c3153934cb24d911042c92eedf9e5dd6d7be07e1.tar.gz
Lock up ifaddr reference counts.
Diffstat (limited to 'sys/net')
-rw-r--r--sys/net/if.c9
-rw-r--r--sys/net/if_var.h32
-rw-r--r--sys/net/net_osdep.h3
-rw-r--r--sys/net/route.c29
-rw-r--r--sys/net/rtsock.c12
5 files changed, 45 insertions, 40 deletions
diff --git a/sys/net/if.c b/sys/net/if.c
index 699278b..10c6c10 100644
--- a/sys/net/if.c
+++ b/sys/net/if.c
@@ -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);
}
diff --git a/sys/net/if_var.h b/sys/net/if_var.h
index 4f943bb..bf9ee0c 100644
--- a/sys/net/if_var.h
+++ b/sys/net/if_var.h
@@ -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);
diff --git a/sys/net/net_osdep.h b/sys/net/net_osdep.h
index 5669275..62b7dc0 100644
--- a/sys/net/net_osdep.h
+++ b/sys/net/net_osdep.h
@@ -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 */
diff --git a/sys/net/route.c b/sys/net/route.c
index adf0b3b..bb07949 100644
--- a/sys/net/route.c
+++ b/sys/net/route.c
@@ -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 */
diff --git a/sys/net/rtsock.c b/sys/net/rtsock.c
index 16d5c03..e7fad28 100644
--- a/sys/net/rtsock.c
+++ b/sys/net/rtsock.c
@@ -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;
}
}
OpenPOWER on IntegriCloud