Instead of grabbing the KERNEL_LOCK() in pfkey_sendup(), assert the
corresponding socket lock is held.
It's currently the same since the kernel lock is still the socket lock
for pfkey sockets. However this prepare the terrain for using a
different lock. This reuse the same pattern already used by routing
sockets: SRPL iteration, solock(), enqueue mbuf, sounlock().
ok?
Index: net/pfkeyv2.c
===================================================================
RCS file: /cvs/src/sys/net/pfkeyv2.c,v
retrieving revision 1.184
diff -u -p -r1.184 pfkeyv2.c
--- net/pfkeyv2.c 11 Jun 2018 09:05:05 -0000 1.184
+++ net/pfkeyv2.c 18 Jun 2018 12:24:45 -0000
@@ -146,7 +146,9 @@ struct pkpcb {
uint32_t kcb_registration; /* Inc. if SATYPE_MAX > 31 */
unsigned int kcb_rdomain;
};
-#define sotokeycb(so) ((struct pkpcb *)(so)->so_pcb)
+#define sotokeycb(so) ((struct pkpcb *)(so)->so_pcb)
+#define keylock(kp) solock((kp)->kcb_socket)
+#define keyunlock(kp, s) sounlock((kp)->kcb_socket, s)
struct dump_state {
@@ -373,21 +375,20 @@ pfkey_sendup(struct pkpcb *kp, struct mb
struct socket *so = kp->kcb_socket;
struct mbuf *m;
+ soassertlocked(so);
+
if (more) {
if (!(m = m_dup_pkt(m0, 0, M_DONTWAIT)))
return (ENOMEM);
} else
m = m0;
- KERNEL_LOCK();
if (!sbappendaddr(so, &so->so_rcv, &pfkey_addr, m, NULL)) {
m_freem(m);
- KERNEL_UNLOCK();
return (ENOBUFS);
}
sorwakeup(so);
- KERNEL_UNLOCK();
return (0);
}
@@ -400,10 +401,10 @@ int
pfkeyv2_sendmessage(void **headers, int mode, struct socket *so,
u_int8_t satype, int count, u_int rdomain)
{
- int i, j, rval;
+ int i, j, rval, s;
void *p, *buffer = NULL;
struct mbuf *packet;
- struct pkpcb *s;
+ struct pkpcb *kp;
struct sadb_msg *smsg;
struct srp_ref sr;
@@ -445,7 +446,9 @@ pfkeyv2_sendmessage(void **headers, int
* Send message to the specified socket, plus all
* promiscuous listeners.
*/
+ s = solock(so);
pfkey_sendup(sotokeycb(so), packet, 0);
+ sounlock(so, s);
/*
* Promiscuous messages contain the original message
@@ -468,11 +471,13 @@ pfkeyv2_sendmessage(void **headers, int
* Search for promiscuous listeners, skipping the
* original destination.
*/
- SRPL_FOREACH(s, &sr, &pkptable.pkp_list, kcb_list) {
- if ((s->kcb_flags & PFKEYV2_SOCKETFLAGS_PROMISC) &&
- (s->kcb_socket != so) &&
- (s->kcb_rdomain == rdomain))
- pfkey_sendup(s, packet, 1);
+ SRPL_FOREACH(kp, &sr, &pkptable.pkp_list, kcb_list) {
+ s = keylock(kp);
+ if ((kp->kcb_flags & PFKEYV2_SOCKETFLAGS_PROMISC) &&
+ (kp->kcb_socket != so) &&
+ (kp->kcb_rdomain == rdomain))
+ pfkey_sendup(kp, packet, 1);
+ keyunlock(kp, s);
}
SRPL_LEAVE(&sr);
m_freem(packet);
@@ -483,17 +488,20 @@ pfkeyv2_sendmessage(void **headers, int
* Send the message to all registered sockets that match
* the specified satype (e.g., all IPSEC-ESP negotiators)
*/
- SRPL_FOREACH(s, &sr, &pkptable.pkp_list, kcb_list) {
- if ((s->kcb_flags & PFKEYV2_SOCKETFLAGS_REGISTERED) &&
- (s->kcb_rdomain == rdomain)) {
- if (!satype) /* Just send to everyone
registered */
- pfkey_sendup(s, packet, 1);
- else {
+ SRPL_FOREACH(kp, &sr, &pkptable.pkp_list, kcb_list) {
+ s = keylock(kp);
+ if ((kp->kcb_flags & PFKEYV2_SOCKETFLAGS_REGISTERED) &&
+ (kp->kcb_rdomain == rdomain)) {
+ if (!satype) {
+ /* Just send to everyone registered */
+ pfkey_sendup(kp, packet, 1);
+ } else {
/* Check for specified satype */
- if ((1 << satype) & s->kcb_registration)
- pfkey_sendup(s, packet, 1);
+ if ((1 << satype) &
kp->kcb_registration)
+ pfkey_sendup(kp, packet, 1);
}
}
+ keyunlock(kp, s);
}
SRPL_LEAVE(&sr);
/* Free last/original copy of the packet */
@@ -514,11 +522,13 @@ pfkeyv2_sendmessage(void **headers, int
goto ret;
/* Send to all registered promiscuous listeners */
- SRPL_FOREACH(s, &sr, &pkptable.pkp_list, kcb_list) {
- if ((s->kcb_flags & PFKEYV2_SOCKETFLAGS_PROMISC) &&
- !(s->kcb_flags & PFKEYV2_SOCKETFLAGS_REGISTERED) &&
- (s->kcb_rdomain == rdomain))
- pfkey_sendup(s, packet, 1);
+ SRPL_FOREACH(kp, &sr, &pkptable.pkp_list, kcb_list) {
+ s = keylock(kp);
+ if ((kp->kcb_flags & PFKEYV2_SOCKETFLAGS_PROMISC) &&
+ !(kp->kcb_flags & PFKEYV2_SOCKETFLAGS_REGISTERED) &&
+ (kp->kcb_rdomain == rdomain))
+ pfkey_sendup(kp, packet, 1);
+ keyunlock(kp, s);
}
SRPL_LEAVE(&sr);
m_freem(packet);
@@ -526,9 +536,11 @@ pfkeyv2_sendmessage(void **headers, int
case PFKEYV2_SENDMESSAGE_BROADCAST:
/* Send message to all sockets */
- SRPL_FOREACH(s, &sr, &pkptable.pkp_list, kcb_list) {
- if (s->kcb_rdomain == rdomain)
- pfkey_sendup(s, packet, 1);
+ SRPL_FOREACH(kp, &sr, &pkptable.pkp_list, kcb_list) {
+ s = keylock(kp);
+ if (kp->kcb_rdomain == rdomain)
+ pfkey_sendup(kp, packet, 1);
+ keyunlock(kp, s);
}
SRPL_LEAVE(&sr);
m_freem(packet);
@@ -1009,7 +1021,7 @@ pfkeyv2_send(struct socket *so, void *me
struct sadb_ident *sid, *did;
struct srp_ref sr;
u_int rdomain;
- int promisc;
+ int promisc, s;
mtx_enter(&pfkeyv2_mtx);
promisc = npromisc;
@@ -1056,9 +1068,11 @@ pfkeyv2_send(struct socket *so, void *me
/* Send to all promiscuous listeners */
SRPL_FOREACH(bkp, &sr, &pkptable.pkp_list, kcb_list) {
+ s = keylock(bkp);
if ((bkp->kcb_flags & PFKEYV2_SOCKETFLAGS_PROMISC) &&
(bkp->kcb_rdomain == rdomain))
pfkey_sendup(bkp, packet, 1);
+ keyunlock(bkp, s);
}
SRPL_LEAVE(&sr);
@@ -1831,11 +1845,15 @@ pfkeyv2_send(struct socket *so, void *me
goto ret;
SRPL_FOREACH(bkp, &sr, &pkptable.pkp_list, kcb_list) {
- if ((bkp != kp) &&
- (bkp->kcb_rdomain == rdomain) &&
+ if (bkp == kp)
+ continue;
+
+ s = keylock(bkp);
+ if ((bkp->kcb_rdomain == rdomain) &&
(!smsg->sadb_msg_seq ||
(smsg->sadb_msg_seq == kp->kcb_pid)))
pfkey_sendup(bkp, packet, 1);
+ keyunlock(bkp, s);
}
SRPL_LEAVE(&sr);