aboutsummaryrefslogtreecommitdiff
path: root/sys/netatalk/ddp_pcb.c
diff options
context:
space:
mode:
authorRobert Watson <rwatson@FreeBSD.org>2009-06-22 10:23:54 +0000
committerRobert Watson <rwatson@FreeBSD.org>2009-06-22 10:23:54 +0000
commitcc18b1dbf067628f01e90d955afc2f56b4a5c9fd (patch)
tree8b6fd873a14e459bd3341eef4e3b417559fcfec3 /sys/netatalk/ddp_pcb.c
parent8af8ad68119d8bdd512fc7bbffda402dcb74e5fc (diff)
downloadsrc-cc18b1dbf067628f01e90d955afc2f56b4a5c9fd.tar.gz
src-cc18b1dbf067628f01e90d955afc2f56b4a5c9fd.zip
Add a global rwlock, at_ifaddr_rw, to protect the global netatalk
address lists, at_ifaddr_list. Acquire the lock, and use ifaddr refcounts where necessary, to close most known address-related races in netatalk. Annotate one potential race in at_control() where we acquire an ifaddr reference, drop the global lock, and scrub the address from the ifnet before re-acquiring the global lock, which could allow for a writer-writer race. MFC after: 3 weeks
Notes
Notes: svn path=/head/; revision=194619
Diffstat (limited to 'sys/netatalk/ddp_pcb.c')
-rw-r--r--sys/netatalk/ddp_pcb.c15
1 files changed, 13 insertions, 2 deletions
diff --git a/sys/netatalk/ddp_pcb.c b/sys/netatalk/ddp_pcb.c
index e40c84b6c1d0..a793a4f676f4 100644
--- a/sys/netatalk/ddp_pcb.c
+++ b/sys/netatalk/ddp_pcb.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2004-2005 Robert N. M. Watson
+ * Copyright (c) 2004-2009 Robert N. M. Watson
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -104,6 +104,7 @@ at_pcbsetaddr(struct ddpcb *ddp, struct sockaddr *addr, struct thread *td)
/*
* Validate passed address.
*/
+ aa = NULL;
if (addr != NULL) {
sat = (struct sockaddr_at *)addr;
if (sat->sat_family != AF_APPLETALK)
@@ -111,6 +112,7 @@ at_pcbsetaddr(struct ddpcb *ddp, struct sockaddr *addr, struct thread *td)
if (sat->sat_addr.s_node != ATADDR_ANYNODE ||
sat->sat_addr.s_net != ATADDR_ANYNET) {
+ AT_IFADDR_RLOCK();
for (aa = at_ifaddr_list; aa != NULL;
aa = aa->aa_next) {
if ((sat->sat_addr.s_net ==
@@ -119,6 +121,7 @@ at_pcbsetaddr(struct ddpcb *ddp, struct sockaddr *addr, struct thread *td)
AA_SAT(aa)->sat_addr.s_node))
break;
}
+ AT_IFADDR_RUNLOCK();
if (aa == NULL)
return (EADDRNOTAVAIL);
}
@@ -142,9 +145,13 @@ at_pcbsetaddr(struct ddpcb *ddp, struct sockaddr *addr, struct thread *td)
if (sat->sat_addr.s_node == ATADDR_ANYNODE &&
sat->sat_addr.s_net == ATADDR_ANYNET) {
- if (at_ifaddr_list == NULL)
+ AT_IFADDR_RLOCK();
+ if (at_ifaddr_list == NULL) {
+ AT_IFADDR_RUNLOCK();
return (EADDRNOTAVAIL);
+ }
sat->sat_addr = AA_SAT(at_ifaddr_list)->sat_addr;
+ AT_IFADDR_RUNLOCK();
}
ddp->ddp_lsat = *sat;
@@ -220,6 +227,7 @@ at_pcbconnect(struct ddpcb *ddp, struct sockaddr *addr, struct thread *td)
else
net = sat->sat_addr.s_net;
aa = NULL;
+ AT_IFADDR_RLOCK();
if ((ifp = ro->ro_rt->rt_ifp) != NULL) {
for (aa = at_ifaddr_list; aa != NULL;
aa = aa->aa_next) {
@@ -236,6 +244,7 @@ at_pcbconnect(struct ddpcb *ddp, struct sockaddr *addr, struct thread *td)
RTFREE(ro->ro_rt);
ro->ro_rt = NULL;
}
+ AT_IFADDR_RUNLOCK();
}
/*
@@ -258,10 +267,12 @@ at_pcbconnect(struct ddpcb *ddp, struct sockaddr *addr, struct thread *td)
*/
aa = NULL;
if (ro->ro_rt && (ifp = ro->ro_rt->rt_ifp)) {
+ AT_IFADDR_RLOCK();
for (aa = at_ifaddr_list; aa != NULL; aa = aa->aa_next) {
if (aa->aa_ifp == ifp)
break;
}
+ AT_IFADDR_RUNLOCK();
}
if (aa == NULL)
return (ENETUNREACH);