Date: Wed, 1 Sep 2021 14:07:18 GMT From: Mark Johnston <markj@FreeBSD.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org Subject: git: 457abbb85794 - main - sctp: Implement sctp_inpcb_bind_locked() Message-ID: <202109011407.181E7IIl001394@gitrepo.freebsd.org>
next in thread | raw e-mail | index | archive | help
The branch main has been updated by markj: URL: https://cgit.FreeBSD.org/src/commit/?id=457abbb85794ad8b28d11a7cd44260eabdf3114d commit 457abbb85794ad8b28d11a7cd44260eabdf3114d Author: Mark Johnston <markj@FreeBSD.org> AuthorDate: 2021-09-01 14:04:47 +0000 Commit: Mark Johnston <markj@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,
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202109011407.181E7IIl001394>