summaryrefslogtreecommitdiffstats
path: root/sys/netatalk
diff options
context:
space:
mode:
authorrwatson <rwatson@FreeBSD.org>2004-07-12 18:39:59 +0000
committerrwatson <rwatson@FreeBSD.org>2004-07-12 18:39:59 +0000
commit9183ed533a6a59e2febbded3d383cd619c86b214 (patch)
tree9b431220526cb46ffec785cb7faee8827c5c49fc /sys/netatalk
parentd0f3949724322ee8bfcd3f3026b6911ef764e498 (diff)
downloadFreeBSD-src-9183ed533a6a59e2febbded3d383cd619c86b214.zip
FreeBSD-src-9183ed533a6a59e2febbded3d383cd619c86b214.tar.gz
Procotol control block locking for netatalk DDP.
Diffstat (limited to 'sys/netatalk')
-rw-r--r--sys/netatalk/ddp_input.c18
-rw-r--r--sys/netatalk/ddp_pcb.c50
-rw-r--r--sys/netatalk/ddp_pcb.h20
-rw-r--r--sys/netatalk/ddp_usrreq.c79
-rw-r--r--sys/netatalk/ddp_var.h2
5 files changed, 134 insertions, 35 deletions
diff --git a/sys/netatalk/ddp_input.c b/sys/netatalk/ddp_input.c
index 679f943..58d4ad8 100644
--- a/sys/netatalk/ddp_input.c
+++ b/sys/netatalk/ddp_input.c
@@ -1,4 +1,5 @@
/*
+ * Copyright (c) 2004 Robert N. M. Watson
* Copyright (c) 1990,1994 Regents of The University of Michigan.
* All Rights Reserved. See COPYRIGHT.
*
@@ -24,11 +25,13 @@
#include <netatalk/at_var.h>
#include <netatalk/ddp.h>
#include <netatalk/ddp_var.h>
+#include <netatalk/ddp_pcb.h>
#include <netatalk/at_extern.h>
static volatile int ddp_forward = 1;
static volatile int ddp_firewall = 0;
static struct ddpstat ddpstat;
+
static struct route forwro;
static void ddp_input(struct mbuf *, struct ifnet *, struct elaphdr *, int);
@@ -360,17 +363,16 @@ ddp_input(m, ifp, elh, phase)
* Search for ddp protocol control blocks that match these
* addresses.
*/
+ DDP_LIST_SLOCK();
if ((ddp = ddp_search(&from, &to, aa)) == NULL) {
- m_freem(m);
- return;
+ goto out;
}
#ifdef MAC
SOCK_LOCK(ddp->ddp_socket);
if (mac_check_socket_deliver(ddp->ddp_socket, m) != 0) {
SOCK_UNLOCK(ddp->ddp_socket);
- m_freem(m);
- return;
+ goto out;
}
SOCK_UNLOCK(ddp->ddp_socket);
#endif
@@ -384,13 +386,17 @@ ddp_input(m, ifp, elh, phase)
* If the socket is full (or similar error) dump the packet.
*/
ddpstat.ddps_nosockspace++;
- m_freem(m);
- return;
+ goto out;
}
/*
* And wake up whatever might be waiting for it
*/
sorwakeup(ddp->ddp_socket);
+ m = NULL;
+out:
+ DDP_LIST_SUNLOCK();
+ if (m != NULL)
+ m_freem(m);
}
#if 0
diff --git a/sys/netatalk/ddp_pcb.c b/sys/netatalk/ddp_pcb.c
index e6dc5fb..8073d55 100644
--- a/sys/netatalk/ddp_pcb.c
+++ b/sys/netatalk/ddp_pcb.c
@@ -1,4 +1,5 @@
/*
+ * Copyright (c) 2004 Robert N. M. Watson
* Copyright (c) 1990,1994 Regents of The University of Michigan.
* All Rights Reserved. See COPYRIGHT.
*
@@ -22,12 +23,18 @@
#include <netatalk/ddp_pcb.h>
#include <netatalk/at_extern.h>
+struct mtx ddp_list_mtx;
static struct ddpcb *ddp_ports[ ATPORT_LAST ];
-struct ddpcb *ddpcb_list = NULL;
+struct ddpcb *ddpcb_list = NULL;
void
at_sockaddr(struct ddpcb *ddp, struct sockaddr **addr)
{
+
+ /*
+ * Prevent modification of ddp during copy of addr.
+ */
+ DDP_LOCK_ASSERT(ddp);
*addr = sodupsockaddr((struct sockaddr *)&ddp->ddp_lsat, M_NOWAIT);
}
@@ -38,6 +45,12 @@ at_pcbsetaddr(struct ddpcb *ddp, struct sockaddr *addr, struct thread *td)
struct at_ifaddr *aa;
struct ddpcb *ddpp;
+ /*
+ * We read and write both the ddp passed in, and also ddp_ports.
+ */
+ DDP_LIST_XLOCK_ASSERT();
+ DDP_LOCK_ASSERT(ddp);
+
if (ddp->ddp_lsat.sat_port != ATADDR_ANYPORT) { /* shouldn't be bound */
return (EINVAL);
}
@@ -134,6 +147,9 @@ at_pcbconnect(struct ddpcb *ddp, struct sockaddr *addr, struct thread *td)
struct ifnet *ifp;
u_short hintnet = 0, net;
+ DDP_LIST_XLOCK_ASSERT();
+ DDP_LOCK_ASSERT(ddp);
+
if (sat->sat_family != AF_APPLETALK) {
return (EAFNOSUPPORT);
}
@@ -222,6 +238,9 @@ at_pcbconnect(struct ddpcb *ddp, struct sockaddr *addr, struct thread *td)
void
at_pcbdisconnect(struct ddpcb *ddp)
{
+
+ DDP_LOCK_ASSERT(ddp);
+
ddp->ddp_fsat.sat_addr.s_net = ATADDR_ANYNET;
ddp->ddp_fsat.sat_addr.s_node = ATADDR_ANYNODE;
ddp->ddp_fsat.sat_port = ATADDR_ANYPORT;
@@ -232,9 +251,15 @@ at_pcballoc(struct socket *so)
{
struct ddpcb *ddp;
- MALLOC(ddp, struct ddpcb *, sizeof *ddp, M_PCB, M_WAITOK | M_ZERO);
+ DDP_LIST_XLOCK_ASSERT();
+
+ MALLOC(ddp, struct ddpcb *, sizeof *ddp, M_PCB, M_NOWAIT | M_ZERO);
+ DDP_LOCK_INIT(ddp);
ddp->ddp_lsat.sat_port = ATADDR_ANYPORT;
+ ddp->ddp_socket = so;
+ so->so_pcb = (caddr_t)ddp;
+
ddp->ddp_next = ddpcb_list;
ddp->ddp_prev = NULL;
ddp->ddp_pprev = NULL;
@@ -243,15 +268,19 @@ at_pcballoc(struct socket *so)
ddpcb_list->ddp_prev = ddp;
}
ddpcb_list = ddp;
-
- ddp->ddp_socket = so;
- so->so_pcb = (caddr_t)ddp;
- return (0);
+ return(0);
}
void
at_pcbdetach(struct socket *so, struct ddpcb *ddp)
{
+
+ /*
+ * We modify ddp, ddp_ports, and the global list.
+ */
+ DDP_LIST_XLOCK_ASSERT();
+ DDP_LOCK_ASSERT(ddp);
+
soisdisconnected(so);
SOCK_LOCK(so);
so->so_pcb = NULL;
@@ -282,6 +311,8 @@ at_pcbdetach(struct socket *so, struct ddpcb *ddp)
if (ddp->ddp_next) {
ddp->ddp_next->ddp_prev = ddp->ddp_prev;
}
+ DDP_UNLOCK(ddp);
+ DDP_LOCK_DESTROY(ddp);
FREE(ddp, M_PCB);
}
@@ -297,6 +328,8 @@ ddp_search(struct sockaddr_at *from, struct sockaddr_at *to,
{
struct ddpcb *ddp;
+ DDP_LIST_SLOCK_ASSERT();
+
/*
* Check for bad ports.
*/
@@ -309,11 +342,13 @@ ddp_search(struct sockaddr_at *from, struct sockaddr_at *to,
* the interface?
*/
for (ddp = ddp_ports[ to->sat_port - 1 ]; ddp; ddp = ddp->ddp_pnext) {
+ DDP_LOCK(ddp);
/* XXX should we handle 0.YY? */
/* XXXX.YY to socket on destination interface */
if (to->sat_addr.s_net == ddp->ddp_lsat.sat_addr.s_net &&
to->sat_addr.s_node == ddp->ddp_lsat.sat_addr.s_node) {
+ DDP_UNLOCK(ddp);
break;
}
@@ -321,6 +356,7 @@ ddp_search(struct sockaddr_at *from, struct sockaddr_at *to,
if (to->sat_addr.s_node == ATADDR_BCAST && (to->sat_addr.s_net == 0 ||
to->sat_addr.s_net == ddp->ddp_lsat.sat_addr.s_net) &&
ddp->ddp_lsat.sat_addr.s_net == AA_SAT(aa)->sat_addr.s_net) {
+ DDP_UNLOCK(ddp);
break;
}
@@ -331,8 +367,10 @@ ddp_search(struct sockaddr_at *from, struct sockaddr_at *to,
ntohs(aa->aa_firstnet) &&
ntohs(ddp->ddp_lsat.sat_addr.s_net) <=
ntohs(aa->aa_lastnet)) {
+ DDP_UNLOCK(ddp);
break;
}
+ DDP_UNLOCK(ddp);
}
return (ddp);
}
diff --git a/sys/netatalk/ddp_pcb.h b/sys/netatalk/ddp_pcb.h
index 819d674..85ec0cc 100644
--- a/sys/netatalk/ddp_pcb.h
+++ b/sys/netatalk/ddp_pcb.h
@@ -1,4 +1,5 @@
/*
+ * Copyright (c) 2004 Robert N. M. Watson
* Copyright (c) 1990,1994 Regents of The University of Michigan.
* All Rights Reserved. See COPYRIGHT.
*
@@ -17,4 +18,23 @@ int at_pcbsetaddr(struct ddpcb *ddp, struct sockaddr *addr,
struct thread *td);
void at_sockaddr(struct ddpcb *ddp, struct sockaddr **addr);
+/* Lock macros for per-pcb locks. */
+#define DDP_LOCK_INIT(ddp) mtx_init(&(ddp)->ddp_mtx, "ddp_mtx", \
+ NULL, MTX_DEF)
+#define DDP_LOCK_DESTROY(ddp) mtx_destroy(&(ddp)->ddp_mtx)
+#define DDP_LOCK(ddp) mtx_lock(&(ddp)->ddp_mtx)
+#define DDP_UNLOCK(ddp) mtx_unlock(&(ddp)->ddp_mtx)
+#define DDP_LOCK_ASSERT(ddp) mtx_assert(&(ddp)->ddp_mtx, MA_OWNED)
+
+/* Lock macros for global pcb list lock. */
+#define DDP_LIST_LOCK_INIT() mtx_init(&ddp_list_mtx, "ddp_list_mtx", \
+ NULL, MTX_DEF)
+#define DDP_LIST_LOCK_DESTROY() mtx_destroy(&ddp_list_mtx)
+#define DDP_LIST_XLOCK() mtx_lock(&ddp_list_mtx)
+#define DDP_LIST_XUNLOCK() mtx_unlock(&ddp_list_mtx)
+#define DDP_LIST_XLOCK_ASSERT() mtx_assert(&ddp_list_mtx, MA_OWNED)
+#define DDP_LIST_SLOCK() mtx_lock(&ddp_list_mtx)
+#define DDP_LIST_SUNLOCK() mtx_unlock(&ddp_list_mtx)
+#define DDP_LIST_SLOCK_ASSERT() mtx_assert(&ddp_list_mtx, MA_OWNED)
+
#endif
diff --git a/sys/netatalk/ddp_usrreq.c b/sys/netatalk/ddp_usrreq.c
index e33da4a..1621f1f 100644
--- a/sys/netatalk/ddp_usrreq.c
+++ b/sys/netatalk/ddp_usrreq.c
@@ -1,4 +1,5 @@
/*
+ * Copyright (c) 2004 Robert N. M. Watson
* Copyright (c) 1990,1994 Regents of The University of Michigan.
* All Rights Reserved. See COPYRIGHT.
*
@@ -33,17 +34,22 @@ ddp_attach(struct socket *so, int proto, struct thread *td)
struct ddpcb *ddp;
int error = 0;
-
ddp = sotoddpcb(so);
- if (ddp != NULL) {
- return (EINVAL);
- }
+ if (ddp != NULL)
+ return (EINVAL);
+ /*
+ * Allocate socket buffer space first so that it's present
+ * before first use.
+ */
+ error = soreserve(so, ddp_sendspace, ddp_recvspace);
+ if (error)
+ return (error);
+
+ DDP_LIST_XLOCK();
error = at_pcballoc(so);
- if (error) {
- return (error);
- }
- return (soreserve(so, ddp_sendspace, ddp_recvspace));
+ DDP_LIST_XUNLOCK();
+ return (error);
}
static int
@@ -52,10 +58,13 @@ ddp_detach(struct socket *so)
struct ddpcb *ddp;
ddp = sotoddpcb(so);
- if (ddp == NULL) {
+ if (ddp == NULL)
return (EINVAL);
- }
+
+ DDP_LIST_XLOCK();
+ DDP_LOCK(ddp);
at_pcbdetach(so, ddp);
+ DDP_LIST_XUNLOCK();
return (0);
}
@@ -69,7 +78,11 @@ ddp_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
if (ddp == NULL) {
return (EINVAL);
}
+ DDP_LIST_XLOCK();
+ DDP_LOCK(ddp);
error = at_pcbsetaddr(ddp, nam, td);
+ DDP_UNLOCK(ddp);
+ DDP_LIST_XUNLOCK();
return (error);
}
@@ -84,11 +97,17 @@ ddp_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
return (EINVAL);
}
+ DDP_LIST_XLOCK();
+ DDP_LOCK(ddp);
if (ddp->ddp_fsat.sat_port != ATADDR_ANYPORT) {
+ DDP_UNLOCK(ddp);
+ DDP_LIST_XUNLOCK();
return (EISCONN);
}
- error = at_pcbconnect(ddp, nam, td);
+ error = at_pcbconnect( ddp, nam, td );
+ DDP_UNLOCK(ddp);
+ DDP_LIST_XUNLOCK();
if (error == 0)
soisconnected(so);
return (error);
@@ -104,12 +123,15 @@ ddp_disconnect(struct socket *so)
if (ddp == NULL) {
return (EINVAL);
}
+ DDP_LOCK(ddp);
if (ddp->ddp_fsat.sat_addr.s_node == ATADDR_ANYNODE) {
+ DDP_UNLOCK(ddp);
return (ENOTCONN);
}
at_pcbdisconnect(ddp);
ddp->ddp_fsat.sat_addr.s_node = ATADDR_ANYNODE;
+ DDP_UNLOCK(ddp);
soisdisconnected(so);
return (0);
}
@@ -144,23 +166,28 @@ ddp_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
}
if (addr != NULL) {
+ DDP_LIST_XLOCK();
+ DDP_LOCK(ddp);
if (ddp->ddp_fsat.sat_port != ATADDR_ANYPORT) {
- return (EISCONN);
+ error = EISCONN;
+ goto out;
}
error = at_pcbconnect(ddp, addr, td);
- if (error) {
- return (error);
+ if (error == 0) {
+ error = ddp_output(m, so);
+ at_pcbdisconnect(ddp);
}
+out:
+ DDP_UNLOCK(ddp);
+ DDP_LIST_XUNLOCK();
} else {
- if (ddp->ddp_fsat.sat_port == ATADDR_ANYPORT) {
- return (ENOTCONN);
- }
- }
-
- error = ddp_output(m, so);
- if (addr != NULL) {
- at_pcbdisconnect(ddp);
+ DDP_LOCK(ddp);
+ if (ddp->ddp_fsat.sat_port == ATADDR_ANYPORT)
+ error = ENOTCONN;
+ else
+ error = ddp_output(m, so);
+ DDP_UNLOCK(ddp);
}
return (error);
}
@@ -174,20 +201,23 @@ ddp_abort(struct socket *so)
if (ddp == NULL) {
return (EINVAL);
}
+ DDP_LIST_XLOCK();
+ DDP_LOCK(ddp);
at_pcbdetach(so, ddp);
+ DDP_LIST_XUNLOCK();
return (0);
}
void
ddp_init(void)
{
-
atintrq1.ifq_maxlen = IFQ_MAXLEN;
atintrq2.ifq_maxlen = IFQ_MAXLEN;
aarpintrq.ifq_maxlen = IFQ_MAXLEN;
mtx_init(&atintrq1.ifq_mtx, "at1_inq", NULL, MTX_DEF);
mtx_init(&atintrq2.ifq_mtx, "at2_inq", NULL, MTX_DEF);
mtx_init(&aarpintrq.ifq_mtx, "aarp_inq", NULL, MTX_DEF);
+ DDP_LIST_LOCK_INIT();
netisr_register(NETISR_ATALK1, at1intr, &atintrq1, 0);
netisr_register(NETISR_ATALK2, at2intr, &atintrq2, 0);
netisr_register(NETISR_AARP, aarpintr, &aarpintrq, 0);
@@ -202,6 +232,7 @@ ddp_clean(void)
for (ddp = ddpcb_list; ddp != NULL; ddp = ddp->ddp_next) {
at_pcbdetach(ddp->ddp_socket, ddp);
}
+ DDP_LIST_LOCK_DESTROY();
}
#endif
@@ -220,7 +251,9 @@ at_setsockaddr(struct socket *so, struct sockaddr **nam)
if (ddp == NULL) {
return (EINVAL);
}
+ DDP_LOCK(ddp);
at_sockaddr(ddp, nam);
+ DDP_UNLOCK(ddp);
return (0);
}
diff --git a/sys/netatalk/ddp_var.h b/sys/netatalk/ddp_var.h
index 1e74381..6fb3aed 100644
--- a/sys/netatalk/ddp_var.h
+++ b/sys/netatalk/ddp_var.h
@@ -13,6 +13,7 @@ struct ddpcb {
struct socket *ddp_socket;
struct ddpcb *ddp_prev, *ddp_next;
struct ddpcb *ddp_pprev, *ddp_pnext;
+ struct mtx ddp_mtx;
};
#define sotoddpcb(so) ((struct ddpcb *)(so)->so_pcb)
@@ -34,5 +35,6 @@ struct ddpstat {
extern int ddp_cksum;
extern struct ddpcb *ddpcb_list;
extern struct pr_usrreqs ddp_usrreqs;
+extern struct mtx ddp_list_mtx;
#endif
#endif /* _NETATALK_DDP_VAR_H_ */
OpenPOWER on IntegriCloud