The branch main has been updated by markj:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=457abbb85794ad8b28d11a7cd44260eabdf3114d

commit 457abbb85794ad8b28d11a7cd44260eabdf3114d
Author:     Mark Johnston <ma...@freebsd.org>
AuthorDate: 2021-09-01 14:04:47 +0000
Commit:     Mark Johnston <ma...@freebsd.org>
CommitDate: 2021-09-01 14:06:18 +0000

    sctp: Implement sctp_inpcb_bind_locked()
    
    This will be used by sctp_listen() to avoid dropping locks when
    performing an implicit bind.  No functional change intended.
    
    Reviewed by:    tuexen
    MFC after:      1 week
    Sponsored by:   The FreeBSD Foundation
    Differential Revision:  https://reviews.freebsd.org/D31757
---
 sys/netinet/sctp_pcb.c | 53 +++++++++++++++++++++++++++++++++-----------------
 sys/netinet/sctp_pcb.h |  3 +++
 2 files changed, 38 insertions(+), 18 deletions(-)

diff --git a/sys/netinet/sctp_pcb.c b/sys/netinet/sctp_pcb.c
index 12f2d5d7fb76..7aa20b5e14b9 100644
--- a/sys/netinet/sctp_pcb.c
+++ b/sys/netinet/sctp_pcb.c
@@ -2801,14 +2801,19 @@ sctp_remove_laddr(struct sctp_laddr *laddr)
        SCTP_DECR_LADDR_COUNT();
 }
 
-/* sctp_ifap is used to bypass normal local address validation checks */
+/*
+ * Bind the socket, with the PCB and global info locks held.  Note, if a
+ * socket address is specified, the PCB lock may be dropped and re-acquired.
+ *
+ * sctp_ifap is used to bypass normal local address validation checks.
+ */
 int
-sctp_inpcb_bind(struct socket *so, struct sockaddr *addr,
+sctp_inpcb_bind_locked(struct sctp_inpcb *inp, struct sockaddr *addr,
     struct sctp_ifa *sctp_ifap, struct thread *td)
 {
        /* bind a ep to a socket address */
        struct sctppcbhead *head;
-       struct sctp_inpcb *inp, *inp_tmp;
+       struct sctp_inpcb *inp_tmp;
        struct inpcb *ip_inp;
        int port_reuse_active = 0;
        int bindall;
@@ -2821,8 +2826,11 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr,
        error = 0;
        lport = 0;
        bindall = 1;
-       inp = (struct sctp_inpcb *)so->so_pcb;
-       ip_inp = (struct inpcb *)so->so_pcb;
+       ip_inp = &inp->ip_inp.inp;
+
+       SCTP_INP_INFO_WLOCK_ASSERT();
+       SCTP_INP_WLOCK_ASSERT(inp);
+
 #ifdef SCTP_DEBUG
        if (addr) {
                SCTPDBG(SCTP_DEBUG_PCB1, "Bind called port: %d\n",
@@ -2831,8 +2839,6 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr,
                SCTPDBG_ADDR(SCTP_DEBUG_PCB1, addr);
        }
 #endif
-       SCTP_INP_INFO_WLOCK();
-       SCTP_INP_WLOCK(inp);
        if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) == 0) {
                error = EINVAL;
                /* already did a bind, subsequent binds NOT allowed ! */
@@ -2925,20 +2931,16 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr 
*addr,
        vrf_id = inp->def_vrf_id;
 
        if (lport) {
-               /* increase our count due to the unlock we do */
-               SCTP_INP_INCR_REF(inp);
-
                /*
                 * Did the caller specify a port? if so we must see if an ep
                 * already has this one bound.
                 */
                /* got to be root to get at low ports */
-               if (ntohs(lport) < IPPORT_RESERVED) {
-                       if ((error = priv_check(td, PRIV_NETINET_RESERVEDPORT)) 
!= 0) {
-                               SCTP_INP_DECR_REF(inp);
-                               goto out;
-                       }
+               if (ntohs(lport) < IPPORT_RESERVED &&
+                   (error = priv_check(td, PRIV_NETINET_RESERVEDPORT)) != 0) {
+                       goto out;
                }
+               SCTP_INP_INCR_REF(inp);
                SCTP_INP_WUNLOCK(inp);
                if (bindall) {
                        vrf_id = inp->def_vrf_id;
@@ -2962,10 +2964,11 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr 
*addr,
                                        port_reuse_active = 1;
                                        goto continue_anyway;
                                }
+                               SCTP_INP_WLOCK(inp);
                                SCTP_INP_DECR_REF(inp);
                                error = EADDRINUSE;
                                SCTP_LTRACE_ERR_RET(inp, NULL, NULL, 
SCTP_FROM_SCTP_PCB, error);
-                               goto out_inp_unlocked;
+                               goto out;
                        }
                } else {
                        inp_tmp = sctp_pcb_findep(addr, 0, 1, vrf_id);
@@ -2988,10 +2991,11 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr 
*addr,
                                        port_reuse_active = 1;
                                        goto continue_anyway;
                                }
+                               SCTP_INP_WLOCK(inp);
                                SCTP_INP_DECR_REF(inp);
                                error = EADDRINUSE;
                                SCTP_LTRACE_ERR_RET(inp, NULL, NULL, 
SCTP_FROM_SCTP_PCB, error);
-                               goto out_inp_unlocked;
+                               goto out;
                        }
                }
 continue_anyway:
@@ -3201,8 +3205,21 @@ continue_anyway:
            ("%s: inp %p is already bound", __func__, inp));
        inp->sctp_flags &= ~SCTP_PCB_FLAGS_UNBOUND;
 out:
+       return (error);
+}
+
+int
+sctp_inpcb_bind(struct socket *so, struct sockaddr *addr,
+    struct sctp_ifa *sctp_ifap, struct thread *td)
+{
+       struct sctp_inpcb *inp;
+       int error;
+
+       inp = so->so_pcb;
+       SCTP_INP_INFO_WLOCK();
+       SCTP_INP_WLOCK(inp);
+       error = sctp_inpcb_bind_locked(inp, addr, sctp_ifap, td);
        SCTP_INP_WUNLOCK(inp);
-out_inp_unlocked:
        SCTP_INP_INFO_WUNLOCK();
        return (error);
 }
diff --git a/sys/netinet/sctp_pcb.h b/sys/netinet/sctp_pcb.h
index c978e8c72b42..e14c9f39356c 100644
--- a/sys/netinet/sctp_pcb.h
+++ b/sys/netinet/sctp_pcb.h
@@ -526,6 +526,9 @@ struct sctp_inpcb *sctp_pcb_findep(struct sockaddr *, int, 
int, uint32_t);
 int
 sctp_inpcb_bind(struct socket *, struct sockaddr *,
     struct sctp_ifa *, struct thread *);
+int
+sctp_inpcb_bind_locked(struct sctp_inpcb *, struct sockaddr *,
+    struct sctp_ifa *, struct thread *);
 
 struct sctp_tcb *
 sctp_findassociation_addr(struct mbuf *, int,
_______________________________________________
dev-commits-src-main@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/dev-commits-src-main
To unsubscribe, send any mail to "dev-commits-src-main-unsubscr...@freebsd.org"

Reply via email to