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);