Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/bouyer-socketcan]: src/sys/netcan Add locking and refcounting to canpcb.
details: https://anonhg.NetBSD.org/src/rev/22307e9d6b6e
branches: bouyer-socketcan
changeset: 820902:22307e9d6b6e
user: bouyer <bouyer%NetBSD.org@localhost>
date: Sun Apr 23 21:05:09 2017 +0000
description:
Add locking and refcounting to canpcb.
Store the canpcb in the in the mbuf tag on send instead of the socket's address.
This should protect against a race where the socket cloud be closed before
we get back the mbuf from the adapter's driver.
diffstat:
sys/netcan/can.c | 41 ++++++++++++++++++++++++++---------
sys/netcan/can_pcb.c | 58 +++++++++++++++++++++++++++++++++++++++++----------
sys/netcan/can_pcb.h | 16 ++++++++++---
3 files changed, 88 insertions(+), 27 deletions(-)
diffs (truncated from 329 to 300 lines):
diff -r d23335a39927 -r 22307e9d6b6e sys/netcan/can.c
--- a/sys/netcan/can.c Sun Apr 23 11:17:25 2017 +0000
+++ b/sys/netcan/can.c Sun Apr 23 21:05:09 2017 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: can.c,v 1.1.2.12 2017/04/20 17:29:10 bouyer Exp $ */
+/* $NetBSD: can.c,v 1.1.2.13 2017/04/23 21:05:09 bouyer Exp $ */
/*-
* Copyright (c) 2003, 2017 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: can.c,v 1.1.2.12 2017/04/20 17:29:10 bouyer Exp $");
+__KERNEL_RCSID(0, "$NetBSD: can.c,v 1.1.2.13 2017/04/23 21:05:09 bouyer Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -235,7 +235,10 @@
ifp->if_oerrors++;
return ENOMEM;
}
- *(struct socket **)(sotag + 1) = canp->canp_socket;
+ mutex_enter(&canp->canp_mtx);
+ canp_ref(canp);
+ mutex_exit(&canp->canp_mtx);
+ *(struct canpcb **)(sotag + 1) = canp;
m_tag_prepend(m, sotag);
if (m->m_len <= ifp->if_mtu) {
@@ -302,7 +305,6 @@
struct sockaddr_can from;
struct canpcb *canp;
struct m_tag *sotag;
- struct socket *so;
struct canpcb *sender_canp;
mutex_enter(softnet_lock);
@@ -319,13 +321,13 @@
#endif
sotag = m_tag_find(m, PACKET_TAG_SO, NULL);
if (sotag) {
- so = *(struct socket **)(sotag + 1);
- sender_canp = sotocanpcb(so);
+ sender_canp = *(struct canpcb **)(sotag + 1);
m_tag_delete(m, sotag);
+ KASSERT(sender_canp != NULL);
/* if the sender doesn't want loopback, don't do it */
- if (sender_canp &&
- (sender_canp->canp_flags & CANP_NO_LOOPBACK) != 0) {
+ if ((sender_canp->canp_flags & CANP_NO_LOOPBACK) != 0) {
m_freem(m);
+ canp_unref(sender_canp);
continue;
}
} else {
@@ -340,19 +342,31 @@
TAILQ_FOREACH(canp, &cbtable.canpt_queue, canp_queue) {
struct mbuf *mc;
+ mutex_enter(&canp->canp_mtx);
+ /* skip if we're detached */
+ if (canp->canp_state == CANP_DETACHED) {
+ mutex_exit(&canp->canp_mtx);
+ continue;
+ }
+
/* don't loop back to sockets on other interfaces */
if (canp->canp_ifp != NULL &&
canp->canp_ifp->if_index != rcv_ifindex) {
+ mutex_exit(&canp->canp_mtx);
continue;
}
/* don't loop back to myself if I don't want it */
if (canp == sender_canp &&
- (canp->canp_flags & CANP_RECEIVE_OWN) == 0)
+ (canp->canp_flags & CANP_RECEIVE_OWN) == 0) {
+ mutex_exit(&canp->canp_mtx);
continue;
+ }
/* skip if the accept filter doen't match this pkt */
- if (!can_pcbfilter(canp, m))
+ if (!can_pcbfilter(canp, m)) {
+ mutex_exit(&canp->canp_mtx);
continue;
+ }
if (TAILQ_NEXT(canp, canp_queue) != NULL) {
/*
@@ -375,9 +389,13 @@
m_freem(mc);
} else
sorwakeup(canp->canp_socket);
+ mutex_exit(&canp->canp_mtx);
if (m == NULL)
break;
}
+ if (sender_canp) {
+ canp_unref(sender_canp);
+ }
/* If it didn't go anywhere just delete it */
if (m) {
m_freem(m);
@@ -492,7 +510,6 @@
/*soisdisconnected(so);*/
so->so_state &= ~SS_ISCONNECTED; /* XXX */
can_pcbdisconnect(canp);
- can_pcbstate(canp, CANP_BOUND); /* XXX */
return 0;
}
@@ -877,7 +894,9 @@
int nfilters = sopt->sopt_size / sizeof(struct can_filter);
if (sopt->sopt_size % sizeof(struct can_filter) != 0)
return EINVAL;
+ mutex_enter(&canp->canp_mtx);
error = can_pcbsetfilter(canp, sopt->sopt_data, nfilters);
+ mutex_exit(&canp->canp_mtx);
break;
}
default:
diff -r d23335a39927 -r 22307e9d6b6e sys/netcan/can_pcb.c
--- a/sys/netcan/can_pcb.c Sun Apr 23 11:17:25 2017 +0000
+++ b/sys/netcan/can_pcb.c Sun Apr 23 21:05:09 2017 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: can_pcb.c,v 1.1.2.3 2017/02/05 19:44:53 bouyer Exp $ */
+/* $NetBSD: can_pcb.c,v 1.1.2.4 2017/04/23 21:05:09 bouyer Exp $ */
/*-
* Copyright (c) 2003, 2017 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: can_pcb.c,v 1.1.2.3 2017/02/05 19:44:53 bouyer Exp $");
+__KERNEL_RCSID(0, "$NetBSD: can_pcb.c,v 1.1.2.4 2017/04/23 21:05:09 bouyer Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -106,12 +106,14 @@
canp->canp_socket = so;
canp->canp_filters = can_init_filter;
canp->canp_nfilters = 1;
+ mutex_init(&canp->canp_mtx, MUTEX_DEFAULT, IPL_NET);
+ canp->canp_refcount = 1;
so->so_pcb = canp;
- s = splnet();
+ mutex_enter(&canp->canp_mtx);
TAILQ_INSERT_HEAD(&table->canpt_queue, canp, canp_queue);
can_pcbstate(canp, CANP_ATTACHED);
- splx(s);
+ mutex_exit(&canp->canp_mtx);
return (0);
}
@@ -122,6 +124,7 @@
if (scan->can_family != AF_CAN)
return (EAFNOSUPPORT);
+ mutex_enter(&canp->canp_mtx);
if (scan->can_ifindex != 0) {
canp->canp_ifp = if_byindex(scan->can_ifindex);
if (canp->canp_ifp == NULL)
@@ -132,6 +135,7 @@
canp->canp_socket->so_state &= ~SS_ISCONNECTED; /* XXX */
}
can_pcbstate(canp, CANP_BOUND);
+ mutex_exit(&canp->canp_mtx);
return 0;
}
@@ -150,8 +154,10 @@
if (scan->can_family != AF_CAN)
return (EAFNOSUPPORT);
#if 0
+ mutex_enter(&canp->canp_mtx);
memcpy(&canp->canp_dst, scan, sizeof(struct sockaddr_can));
can_pcbstate(canp, CANP_CONNECTED);
+ mutex_exit(&canp->canp_mtx);
return 0;
#endif
return EOPNOTSUPP;
@@ -162,7 +168,9 @@
{
struct canpcb *canp = v;
- can_pcbstate(canp, CANP_BOUND);
+ mutex_enter(&canp->canp_mtx);
+ can_pcbstate(canp, CANP_DETACHED);
+ mutex_exit(&canp->canp_mtx);
if (canp->canp_socket->so_state & SS_NOFDREF)
can_pcbdetach(canp);
}
@@ -172,28 +180,51 @@
{
struct canpcb *canp = v;
struct socket *so = canp->canp_socket;
- int s;
KASSERT(mutex_owned(softnet_lock));
so->so_pcb = NULL;
- s = splnet();
- can_pcbstate(canp, CANP_ATTACHED);
+ mutex_enter(&canp->canp_mtx);
+ can_pcbstate(canp, CANP_DETACHED);
+ can_pcbsetfilter(canp, NULL, 0);
+ mutex_exit(&canp->canp_mtx);
TAILQ_REMOVE(&canp->canp_table->canpt_queue, canp, canp_queue);
- splx(s);
- sofree(so); /* sofree drops the lock */
- can_pcbsetfilter(canp, NULL, 0);
+ sofree(so); /* sofree drops the softnet_lock */
+ canp_unref(canp);
+ mutex_enter(softnet_lock);
+}
+
+void
+canp_ref(struct canpcb *canp)
+{
+ KASSERT(mutex_owned(&canp->canp_mtx));
+ canp->canp_refcount++;
+}
+
+void
+canp_unref(struct canpcb *canp)
+{
+ mutex_enter(&canp->canp_mtx);
+ canp->canp_refcount--;
+ KASSERT(canp->canp_refcount >= 0);
+ if (canp->canp_refcount > 0) {
+ mutex_exit(&canp->canp_mtx);
+ return;
+ }
+ mutex_exit(&canp->canp_mtx);
+ mutex_destroy(&canp->canp_mtx);
pool_put(&canpcb_pool, canp);
- mutex_enter(softnet_lock);
}
void
can_setsockaddr(struct canpcb *canp, struct sockaddr_can *scan)
{
+ mutex_enter(&canp->canp_mtx);
memset(scan, 0, sizeof (*scan));
scan->can_family = AF_CAN;
scan->can_len = sizeof(*scan);
scan->can_ifindex = canp->canp_ifp->if_index;
+ mutex_exit(&canp->canp_mtx);
}
int
@@ -201,6 +232,7 @@
{
struct can_filter *newf;
+ KASSERT(mutex_owned(&canp->canp_mtx));
if (nfilters > 0) {
newf =
@@ -303,6 +335,7 @@
can_pcbstate(struct canpcb *canp, int state)
{
int ifindex = canp->canp_ifp ? canp->canp_ifp->if_index : 0;
+ KASSERT(mutex_owned(&canp->canp_mtx));
if (canp->canp_state > CANP_ATTACHED)
LIST_REMOVE(canp, canp_hash);
@@ -332,6 +365,7 @@
struct can_frame *fmp;
struct can_filter *fip;
+ KASSERT(mutex_owned(&canp->canp_mtx));
KASSERT((m->m_flags & M_PKTHDR) != 0);
KASSERT(m->m_len == m->m_pkthdr.len);
diff -r d23335a39927 -r 22307e9d6b6e sys/netcan/can_pcb.h
--- a/sys/netcan/can_pcb.h Sun Apr 23 11:17:25 2017 +0000
+++ b/sys/netcan/can_pcb.h Sun Apr 23 21:05:09 2017 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: can_pcb.h,v 1.1.2.3 2017/02/05 10:56:12 bouyer Exp $ */
+/* $NetBSD: can_pcb.h,v 1.1.2.4 2017/04/23 21:05:09 bouyer Exp $ */
/*-
* Copyright (c) 2003, 2017 The NetBSD Foundation, Inc.
@@ -48,6 +48,7 @@
LIST_ENTRY(canpcb) canp_hash;
LIST_ENTRY(canpcb) canp_lhash;
TAILQ_ENTRY(canpcb) canp_queue;
+ kmutex_t canp_mtx; /* protect states and refcount */
int canp_state;
int canp_flags;
struct socket *canp_socket; /* back pointer to socket */
@@ -56,6 +57,8 @@
struct canpcbtable *canp_table;
struct can_filter *canp_filters; /* filter array */
int canp_nfilters; /* size of canp_filters */
+
Home |
Main Index |
Thread Index |
Old Index