summaryrefslogtreecommitdiffstats
path: root/sys/netipx
diff options
context:
space:
mode:
authorrwatson <rwatson@FreeBSD.org>2009-06-23 20:19:09 +0000
committerrwatson <rwatson@FreeBSD.org>2009-06-23 20:19:09 +0000
commitc9ef486fe1d7da6a2212a337eacc5ed5b40f85d9 (patch)
tree5ce1a7dad67026f119a839b3325454ebafa72c51 /sys/netipx
parentf75c2385c686d82292982283b5f0a9c9988beda8 (diff)
downloadFreeBSD-src-c9ef486fe1d7da6a2212a337eacc5ed5b40f85d9.zip
FreeBSD-src-c9ef486fe1d7da6a2212a337eacc5ed5b40f85d9.tar.gz
Modify most routines returning 'struct ifaddr *' to return references
rather than pointers, requiring callers to properly dispose of those references. The following routines now return references: ifaddr_byindex ifa_ifwithaddr ifa_ifwithbroadaddr ifa_ifwithdstaddr ifa_ifwithnet ifaof_ifpforaddr ifa_ifwithroute ifa_ifwithroute_fib rt_getifa rt_getifa_fib IFP_TO_IA ip_rtaddr in6_ifawithifp in6ifa_ifpforlinklocal in6ifa_ifpwithaddr in6_ifadd carp_iamatch6 ip6_getdstifaddr Remove unused macro which didn't have required referencing: IFP_TO_IA6 This closes many small races in which changes to interface or address lists while an ifaddr was in use could lead to use of freed memory (etc). In a few cases, add missing if_addr_list locking required to safely acquire references. Because of a lack of deep copying support, we accept a race in which an in6_ifaddr pointed to by mbuf tags and extracted with ip6_getdstifaddr() doesn't hold a reference while in transmit. Once we have mbuf tag deep copy support, this can be fixed. Reviewed by: bz Obtained from: Apple, Inc. (portions) MFC after: 6 weeks (portions)
Diffstat (limited to 'sys/netipx')
-rw-r--r--sys/netipx/ipx_pcb.c34
1 files changed, 27 insertions, 7 deletions
diff --git a/sys/netipx/ipx_pcb.c b/sys/netipx/ipx_pcb.c
index 4c8eba0..77fbfe8 100644
--- a/sys/netipx/ipx_pcb.c
+++ b/sys/netipx/ipx_pcb.c
@@ -158,7 +158,6 @@ noname:
int
ipx_pcbconnect(struct ipxpcb *ipxp, struct sockaddr *nam, struct thread *td)
{
- struct ipx_ifaddr *ia;
struct sockaddr_ipx *sipx = (struct sockaddr_ipx *)nam;
struct ipx_addr *dst;
struct route *ro;
@@ -167,8 +166,6 @@ ipx_pcbconnect(struct ipxpcb *ipxp, struct sockaddr *nam, struct thread *td)
IPX_LIST_LOCK_ASSERT();
IPX_LOCK_ASSERT(ipxp);
- ia = NULL;
-
if (sipx->sipx_family != AF_IPX)
return (EAFNOSUPPORT);
if (sipx->sipx_port == 0 || ipx_nullhost(sipx->sipx_addr))
@@ -213,6 +210,8 @@ ipx_pcbconnect(struct ipxpcb *ipxp, struct sockaddr *nam, struct thread *td)
rtalloc_ign(ro, 0);
}
if (ipx_neteqnn(ipxp->ipxp_laddr.x_net, ipx_zeronet)) {
+ struct ipx_ifaddr *ia = NULL;
+
/*
* If route is known or can be allocated now,
* our src addr is taken from the i/f, else punt.
@@ -225,8 +224,10 @@ ipx_pcbconnect(struct ipxpcb *ipxp, struct sockaddr *nam, struct thread *td)
if (ro->ro_rt != NULL && (ifp = ro->ro_rt->rt_ifp) != NULL) {
IPX_IFADDR_RLOCK();
for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next)
- if (ia->ia_ifp == ifp)
+ if (ia->ia_ifp == ifp) {
+ ifa_ref(&ia->ia_ifa);
break;
+ }
IPX_IFADDR_RUNLOCK();
}
if (ia == NULL) {
@@ -235,16 +236,28 @@ ipx_pcbconnect(struct ipxpcb *ipxp, struct sockaddr *nam, struct thread *td)
ia = (struct ipx_ifaddr *)
ifa_ifwithdstaddr((struct sockaddr *)sipx);
sipx->sipx_addr.x_port = fport;
- if (ia == NULL)
+ if (ia == NULL) {
+ IPX_IFADDR_RLOCK();
ia = ipx_iaonnetof(&sipx->sipx_addr);
- if (ia == NULL)
+ if (ia != NULL)
+ ifa_ref(&ia->ia_ifa);
+ IPX_IFADDR_RUNLOCK();
+ }
+ if (ia == NULL) {
+ IPX_IFADDR_RLOCK();
ia = ipx_ifaddr;
+ if (ia != NULL)
+ ifa_ref(&ia->ia_ifa);
+ IPX_IFADDR_RUNLOCK();
+ }
if (ia == NULL)
return (EADDRNOTAVAIL);
}
ipxp->ipxp_laddr.x_net = satoipx_addr(ia->ia_addr).x_net;
+ ifa_free(&ia->ia_ifa);
}
if (ipx_nullhost(ipxp->ipxp_laddr)) {
+ struct ipx_ifaddr *ia = NULL;
/*
* If route is known or can be allocated now,
* our src addr is taken from the i/f, else punt.
@@ -257,8 +270,10 @@ ipx_pcbconnect(struct ipxpcb *ipxp, struct sockaddr *nam, struct thread *td)
if (ro->ro_rt != NULL && (ifp = ro->ro_rt->rt_ifp) != NULL) {
IPX_IFADDR_RLOCK();
for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next)
- if (ia->ia_ifp == ifp)
+ if (ia->ia_ifp == ifp) {
+ ifa_ref(&ia->ia_ifa);
break;
+ }
IPX_IFADDR_RUNLOCK();
}
if (ia == NULL) {
@@ -270,17 +285,22 @@ ipx_pcbconnect(struct ipxpcb *ipxp, struct sockaddr *nam, struct thread *td)
if (ia == NULL) {
IPX_IFADDR_RLOCK();
ia = ipx_iaonnetof(&sipx->sipx_addr);
+ if (ia != NULL)
+ ifa_ref(&ia->ia_ifa);
IPX_IFADDR_RUNLOCK();
}
if (ia == NULL) {
IPX_IFADDR_RLOCK();
ia = ipx_ifaddr;
+ if (ia != NULL)
+ ifa_ref(&ia->ia_ifa);
IPX_IFADDR_RUNLOCK();
}
if (ia == NULL)
return (EADDRNOTAVAIL);
}
ipxp->ipxp_laddr.x_host = satoipx_addr(ia->ia_addr).x_host;
+ ifa_free(&ia->ia_ifa);
}
if (ipx_pcblookup(&sipx->sipx_addr, ipxp->ipxp_lport, 0))
return (EADDRINUSE);
OpenPOWER on IntegriCloud