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

Reply via email to