-/* $OpenBSD: in_pcb.c,v 1.271 2022/08/21 11:44:53 bluhm Exp $ */
+/* $OpenBSD: in_pcb.c,v 1.272 2022/08/22 10:37:27 bluhm Exp $ */
/* $NetBSD: in_pcb.c,v 1.25 1996/02/13 23:41:53 christos Exp $ */
/*
in_pcbinit(struct inpcbtable *table, int hashsize)
{
mtx_init(&table->inpt_mtx, IPL_SOFTNET);
+ rw_init(&table->inpt_notify, "inpnotify");
TAILQ_INIT(&table->inpt_queue);
table->inpt_hashtbl = hashinit(hashsize, M_PCB, M_WAITOK,
&table->inpt_mask);
struct in_addr faddr;
u_int rdomain;
- NET_ASSERT_LOCKED_EXCLUSIVE();
-
if (dst->sa_family != AF_INET)
return;
faddr = satosin(dst)->sin_addr;
if (notify == NULL)
return;
+ /*
+ * Use a temporary notify list protected by rwlock to run over
+ * selected PCB. This is necessary as the list of all PCB is
+ * protected by a mutex. Notify may call ip_output() eventually
+ * which may sleep as pf lock is a rwlock. Also the SRP
+ * implementation of the routing table might sleep.
+ * The same inp_notify list entry and inpt_notify rwlock are
+ * used for UDP multicast and raw IP delivery.
+ */
SIMPLEQ_INIT(&inpcblist);
rdomain = rtable_l2(rtable);
+ rw_enter_write(&table->inpt_notify);
mtx_enter(&table->inpt_mtx);
TAILQ_FOREACH(inp, &table->inpt_queue, inp_queue) {
#ifdef INET6
(*notify)(inp, errno);
in_pcbunref(inp);
}
+ rw_exit_write(&table->inpt_notify);
}
/*
-/* $OpenBSD: in_pcb.h,v 1.130 2022/08/21 11:44:53 bluhm Exp $ */
+/* $OpenBSD: in_pcb.h,v 1.131 2022/08/22 10:37:27 bluhm Exp $ */
/* $NetBSD: in_pcb.h,v 1.14 1996/02/13 23:42:00 christos Exp $ */
/*
#include <sys/queue.h>
#include <sys/mutex.h>
+#include <sys/rwlock.h>
#include <sys/refcnt.h>
#include <netinet/ip6.h>
#include <netinet6/ip6_var.h>
* I immutable after creation
* N net lock
* t inpt_mtx pcb table mutex
+ * y inpt_notify pcb table rwlock for notify
* p inpcb_mtx pcb mutex
*/
LIST_ENTRY(inpcb) inp_hash; /* [t] local and foreign hash */
LIST_ENTRY(inpcb) inp_lhash; /* [t] local port hash */
TAILQ_ENTRY(inpcb) inp_queue; /* [t] inet PCB queue */
- SIMPLEQ_ENTRY(inpcb) inp_notify; /* [N] notify or udp append */
+ SIMPLEQ_ENTRY(inpcb) inp_notify; /* [y] notify or udp append */
struct inpcbtable *inp_table; /* [I] inet queue/hash table */
union inpaddru inp_faddru; /* Foreign address. */
union inpaddru inp_laddru; /* Local address. */
struct inpcbtable {
struct mutex inpt_mtx; /* protect queue and hash */
+ struct rwlock inpt_notify; /* protect inp_notify list */
TAILQ_HEAD(inpthead, inpcb) inpt_queue; /* [t] inet PCB queue */
struct inpcbhead *inpt_hashtbl; /* [t] local and foreign hash */
struct inpcbhead *inpt_lhashtbl; /* [t] local port hash */
-/* $OpenBSD: raw_ip.c,v 1.134 2022/08/22 08:08:46 mvs Exp $ */
+/* $OpenBSD: raw_ip.c,v 1.135 2022/08/22 10:37:27 bluhm Exp $ */
/* $NetBSD: raw_ip.c,v 1.25 1996/02/18 18:58:33 christos Exp $ */
/*
}
}
#endif
- NET_ASSERT_LOCKED_EXCLUSIVE();
SIMPLEQ_INIT(&inpcblist);
+ rw_enter_write(&rawcbtable.inpt_notify);
mtx_enter(&rawcbtable.inpt_mtx);
TAILQ_FOREACH(inp, &rawcbtable.inpt_queue, inp_queue) {
if (inp->inp_socket->so_state & SS_CANTRCVMORE)
mtx_leave(&rawcbtable.inpt_mtx);
if (SIMPLEQ_EMPTY(&inpcblist)) {
+ rw_exit_write(&rawcbtable.inpt_notify);
+
if (ip->ip_p != IPPROTO_ICMP)
icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PROTOCOL,
0, 0);
counters[ips_noproto]++;
counters[ips_delivered]--;
counters_leave(&ref, ipcounters);
+
+ return IPPROTO_DONE;
}
while ((inp = SIMPLEQ_FIRST(&inpcblist)) != NULL) {
}
in_pcbunref(inp);
}
+ rw_exit_write(&rawcbtable.inpt_notify);
+
return IPPROTO_DONE;
}
-/* $OpenBSD: udp_usrreq.c,v 1.286 2022/08/22 08:08:46 mvs Exp $ */
+/* $OpenBSD: udp_usrreq.c,v 1.287 2022/08/22 10:37:27 bluhm Exp $ */
/* $NetBSD: udp_usrreq.c,v 1.28 1996/03/16 23:54:03 christos Exp $ */
/*
* Locate pcb(s) for datagram.
* (Algorithm copied from raw_intr().)
*/
- NET_ASSERT_LOCKED_EXCLUSIVE();
SIMPLEQ_INIT(&inpcblist);
+ rw_enter_write(&udbtable.inpt_notify);
mtx_enter(&udbtable.inpt_mtx);
TAILQ_FOREACH(inp, &udbtable.inpt_queue, inp_queue) {
if (inp->inp_socket->so_state & SS_CANTRCVMORE)
mtx_leave(&udbtable.inpt_mtx);
if (SIMPLEQ_EMPTY(&inpcblist)) {
+ rw_exit_write(&udbtable.inpt_notify);
+
/*
* No matching pcb found; discard datagram.
* (No need to send an ICMP Port Unreachable
}
in_pcbunref(inp);
}
+ rw_exit_write(&udbtable.inpt_notify);
+
return IPPROTO_DONE;
}
/*
-/* $OpenBSD: in6_pcb.c,v 1.119 2022/08/08 12:06:31 bluhm Exp $ */
+/* $OpenBSD: in6_pcb.c,v 1.120 2022/08/22 10:37:27 bluhm Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
u_int32_t flowinfo;
u_int rdomain;
- NET_ASSERT_LOCKED_EXCLUSIVE();
-
if ((unsigned)cmd >= PRC_NCMDS)
return;
SIMPLEQ_INIT(&inpcblist);
rdomain = rtable_l2(rtable);
+ rw_enter_write(&table->inpt_notify);
mtx_enter(&table->inpt_mtx);
TAILQ_FOREACH(inp, &table->inpt_queue, inp_queue) {
if ((inp->inp_flags & INP_IPV6) == 0)
(*notify)(inp, errno);
in_pcbunref(inp);
}
+ rw_exit_write(&table->inpt_notify);
}
struct inpcb *
-/* $OpenBSD: raw_ip6.c,v 1.154 2022/08/22 08:08:46 mvs Exp $ */
+/* $OpenBSD: raw_ip6.c,v 1.155 2022/08/22 10:37:27 bluhm Exp $ */
/* $KAME: raw_ip6.c,v 1.69 2001/03/04 15:55:44 itojun Exp $ */
/*
}
}
#endif
- NET_ASSERT_LOCKED_EXCLUSIVE();
SIMPLEQ_INIT(&inpcblist);
+ rw_enter_write(&rawin6pcbtable.inpt_notify);
mtx_enter(&rawin6pcbtable.inpt_mtx);
TAILQ_FOREACH(in6p, &rawin6pcbtable.inpt_queue, inp_queue) {
if (in6p->inp_socket->so_state & SS_CANTRCVMORE)
struct counters_ref ref;
uint64_t *counters;
+ rw_exit_write(&rawin6pcbtable.inpt_notify);
+
if (proto != IPPROTO_ICMPV6) {
rip6stat_inc(rip6s_nosock);
if (m->m_flags & M_MCAST)
counters = counters_enter(&ref, ip6counters);
counters[ip6s_delivered]--;
counters_leave(&ref, ip6counters);
+
+ return IPPROTO_DONE;
}
while ((in6p = SIMPLEQ_FIRST(&inpcblist)) != NULL) {
}
in_pcbunref(in6p);
}
+ rw_exit_write(&rawin6pcbtable.inpt_notify);
+
return IPPROTO_DONE;
}