From nobody Thu Dec 05 16:35:23 2024 X-Original-To: dev-commits-src-main@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4Y40PG1cdSz5dlPL; Thu, 05 Dec 2024 16:35:30 +0000 (UTC) (envelope-from freebsd@walstatt-de.de) Received: from smtp6.goneo.de (smtp6.goneo.de [85.220.129.31]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 4Y40PF5mH6z44WL; Thu, 5 Dec 2024 16:35:29 +0000 (UTC) (envelope-from freebsd@walstatt-de.de) Authentication-Results: mx1.freebsd.org; none Received: from hub1.goneo.de (hub1.goneo.de [85.220.129.52]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by smtp6.goneo.de (Postfix) with ESMTPS id 724D5240D59; Thu, 5 Dec 2024 17:35:26 +0100 (CET) Received: from hub1.goneo.de (localhost [127.0.0.1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by hub1.goneo.de (Postfix) with ESMTPS id A05D02402D8; Thu, 5 Dec 2024 17:35:24 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=walstatt-de.de; s=DKIM001; t=1733416524; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=6x1fuvbH9fLvyvUd0bUv1+ErhS521J4gzU3bjIYRznc=; b=Hbvh/+o43RjFauqo8UDLEmd/FoHGe+bJfYXMlnBqIVtC76JMcm2FjAuv3xrRFQekQkEW9Q SeKCvT4yJN8x+mzo/4+dM1dNCG0T64awepAvMs5W0sN3alhRMAr+p9rconJdY5f0w0aBWe fmfijbZbCeyU6EPLfmUsg4ObB4tAk4r9kJVNL9u4lNHYPfCEGUVs7Jg0Vx/IHeF3JxbaIf gfvb4kGfe1WqViHkcxXVLhH+W0ScL5TfqFsRvMnilFLpjq2fmOoAf8ImjSYombrIPb1qGP PA7qHscN7VVfMOBmlR+DbIicuARyKokQpOsrMqraOw9vq5RJZwX3Mat8ikXU9w== Received: from hermann.intern.walstatt.dynvpn.de (dynamic-077-183-116-031.77.183.pool.telefonica.de [77.183.116.31]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange ECDHE (prime256v1) server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by hub1.goneo.de (Postfix) with ESMTPSA id 55C812402D6; Thu, 5 Dec 2024 17:35:24 +0100 (CET) Date: Thu, 5 Dec 2024 17:35:23 +0100 From: FreeBSD User To: Mark Johnston Cc: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org Subject: Re: git: 01f8ce83242d - main - inpcb: Factor out parts of in6_pcbbind() and in_pcbbind_setup() Message-ID: <20241205173523.7d4ddf02@hermann.intern.walstatt.dynvpn.de> In-Reply-To: <202412051520.4B5FKmT0099691@gitrepo.freebsd.org> References: <202412051520.4B5FKmT0099691@gitrepo.freebsd.org> List-Id: Commit messages for the main branch of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-main List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-main@freebsd.org Sender: owner-dev-commits-src-main@FreeBSD.org MIME-Version: 1.0 Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: 7bit X-Rspamd-UID: 3b7a15 X-Rspamd-UID: 9e0e9b X-Rspamd-Pre-Result: action=no action; module=replies; Message is reply to one we originated X-Spamd-Result: default: False [-4.00 / 15.00]; REPLY(-4.00)[]; ASN(0.00)[asn:25394, ipnet:85.220.128.0/17, country:DE] X-Rspamd-Queue-Id: 4Y40PF5mH6z44WL X-Spamd-Bar: ---- On Thu, 5 Dec 2024 15:20:48 GMT Mark Johnston wrote: This commit breaks buildkernel: [...] --- in6_pcb.o --- /usr/src/sys/netinet6/in6_pcb.c:301:20: error: unused variable 'pcbinfo' [-Werror,-Wunused-variable] 301 | struct inpcbinfo *pcbinfo = inp->inp_pcbinfo; > The branch main has been updated by markj: > > URL: https://cgit.FreeBSD.org/src/commit/?id=01f8ce83242d7a8e599cf6a78b6277161d79edd4 > > commit 01f8ce83242d7a8e599cf6a78b6277161d79edd4 > Author: Mark Johnston > AuthorDate: 2024-12-05 15:00:13 +0000 > Commit: Mark Johnston > CommitDate: 2024-12-05 15:19:57 +0000 > > inpcb: Factor out parts of in6_pcbbind() and in_pcbbind_setup() > > A large portion of these functions just determines whether the inpcb can > bind to the address/port. This portion has no side effects, so is a > good candidate to move into its own helper function. This patch does > so, making the callers less complicated and reducing indentation. > > While moving this code, also make some changes: > - Load socket options (SO_REUSEADDR etc.) only once. There is nothing > preventing another thread from toggling the socket options, so make > this function easier to reason about by avoiding races. > - When checking whether the bind address is an interface address, make a > separate sockaddr rather than temporarily modifying the one passed to > in_pcbbind(). > > Reviewed by: ae, glebius > MFC after: 1 month > Sponsored by: Klara, Inc. > Sponsored by: Stormshield > Differential Revision: https://reviews.freebsd.org/D47590 > --- > sys/netinet/in_pcb.c | 172 ++++++++++++++++++-------------- > sys/netinet6/in6_pcb.c | 262 +++++++++++++++++++++++++++---------------------- > 2 files changed, 242 insertions(+), 192 deletions(-) > > diff --git a/sys/netinet/in_pcb.c b/sys/netinet/in_pcb.c > index 7c881817ac6e..94fb406bcd2b 100644 > --- a/sys/netinet/in_pcb.c > +++ b/sys/netinet/in_pcb.c > @@ -861,6 +861,93 @@ in_pcb_lport(struct inpcb *inp, struct in_addr *laddrp, u_short > *lportp, #endif /* INET || INET6 */ > > #ifdef INET > +/* > + * Determine whether the inpcb can be bound to the specified address/port tuple. > + */ > +static int > +in_pcbbind_avail(struct inpcb *inp, const struct in_addr laddr, > + const u_short lport, int sooptions, int lookupflags, struct ucred *cred) > +{ > + int reuseport, reuseport_lb; > + > + INP_LOCK_ASSERT(inp); > + INP_HASH_LOCK_ASSERT(inp->inp_pcbinfo); > + > + reuseport = (sooptions & SO_REUSEPORT); > + reuseport_lb = (sooptions & SO_REUSEPORT_LB); > + > + if (IN_MULTICAST(ntohl(laddr.s_addr))) { > + /* > + * Treat SO_REUSEADDR as SO_REUSEPORT for multicast; > + * allow complete duplication of binding if > + * SO_REUSEPORT is set, or if SO_REUSEADDR is set > + * and a multicast address is bound on both > + * new and duplicated sockets. > + */ > + if ((sooptions & (SO_REUSEADDR | SO_REUSEPORT)) != 0) > + reuseport = SO_REUSEADDR | SO_REUSEPORT; > + /* > + * XXX: How to deal with SO_REUSEPORT_LB here? > + * Treat same as SO_REUSEPORT for now. > + */ > + if ((sooptions & (SO_REUSEADDR | SO_REUSEPORT_LB)) != 0) > + reuseport_lb = SO_REUSEADDR | SO_REUSEPORT_LB; > + } else if (!in_nullhost(laddr)) { > + struct sockaddr_in sin; > + > + memset(&sin, 0, sizeof(sin)); > + sin.sin_family = AF_INET; > + sin.sin_len = sizeof(sin); > + sin.sin_addr = laddr; > + > + /* > + * Is the address a local IP address? > + * If INP_BINDANY is set, then the socket may be bound > + * to any endpoint address, local or not. > + */ > + if ((inp->inp_flags & INP_BINDANY) == 0 && > + ifa_ifwithaddr_check((const struct sockaddr *)&sin) == 0) > + return (EADDRNOTAVAIL); > + } > + > + if (lport != 0) { > + struct inpcb *t; > + > + if (ntohs(lport) <= V_ipport_reservedhigh && > + ntohs(lport) >= V_ipport_reservedlow && > + priv_check_cred(cred, PRIV_NETINET_RESERVEDPORT)) > + return (EACCES); > + > + if (!IN_MULTICAST(ntohl(laddr.s_addr)) && > + priv_check_cred(inp->inp_cred, PRIV_NETINET_REUSEPORT) != 0) { > + t = in_pcblookup_local(inp->inp_pcbinfo, laddr, lport, > + INPLOOKUP_WILDCARD, cred); > + if (t != NULL && > + (inp->inp_socket->so_type != SOCK_STREAM || > + in_nullhost(t->inp_faddr)) && > + (!in_nullhost(laddr) || > + !in_nullhost(t->inp_laddr) || > + (t->inp_socket->so_options & SO_REUSEPORT) || > + (t->inp_socket->so_options & SO_REUSEPORT_LB) == 0) && > + (inp->inp_cred->cr_uid != t->inp_cred->cr_uid)) > + return (EADDRINUSE); > + } > + t = in_pcblookup_local(inp->inp_pcbinfo, laddr, lport, > + lookupflags, cred); > + if (t != NULL && ((reuseport | reuseport_lb) & > + t->inp_socket->so_options) == 0) { > +#ifdef INET6 > + if (!in_nullhost(laddr) || > + !in_nullhost(t->inp_laddr) || > + (inp->inp_vflag & INP_IPV6PROTO) == 0 || > + (t->inp_vflag & INP_IPV6PROTO) == 0) > +#endif > + return (EADDRINUSE); > + } > + } > + return (0); > +} > + > /* > * Set up a bind operation on a PCB, performing port allocation > * as required, but do not actually modify the PCB. Callers can > @@ -878,15 +965,9 @@ in_pcbbind_setup(struct inpcb *inp, struct sockaddr_in *sin, > in_addr_t *laddrp, struct inpcbinfo *pcbinfo = inp->inp_pcbinfo; > struct in_addr laddr; > u_short lport = 0; > - int lookupflags = 0, reuseport = (so->so_options & SO_REUSEPORT); > + int lookupflags, sooptions; > int error; > > - /* > - * XXX: Maybe we could let SO_REUSEPORT_LB set SO_REUSEPORT bit here > - * so that we don't have to add to the (already messy) code below. > - */ > - int reuseport_lb = (so->so_options & SO_REUSEPORT_LB); > - > /* > * No state changes, so read locks are sufficient here. > */ > @@ -896,7 +977,10 @@ in_pcbbind_setup(struct inpcb *inp, struct sockaddr_in *sin, > in_addr_t *laddrp, laddr.s_addr = *laddrp; > if (sin != NULL && laddr.s_addr != INADDR_ANY) > return (EINVAL); > - if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT|SO_REUSEPORT_LB)) == 0) > + > + lookupflags = 0; > + sooptions = atomic_load_int(&so->so_options); > + if ((sooptions & (SO_REUSEADDR | SO_REUSEPORT | SO_REUSEPORT_LB)) == 0) > lookupflags = INPLOOKUP_WILDCARD; > if (sin == NULL) { > if ((error = prison_local_ip4(cred, &laddr)) != 0) > @@ -918,73 +1002,11 @@ in_pcbbind_setup(struct inpcb *inp, struct sockaddr_in *sin, > in_addr_t *laddrp, } > laddr = sin->sin_addr; > > - /* NB: lport is left as 0 if the port isn't being changed. */ > - if (IN_MULTICAST(ntohl(laddr.s_addr))) { > - /* > - * Treat SO_REUSEADDR as SO_REUSEPORT for multicast; > - * allow complete duplication of binding if > - * SO_REUSEPORT is set, or if SO_REUSEADDR is set > - * and a multicast address is bound on both > - * new and duplicated sockets. > - */ > - if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) != 0) > - reuseport = SO_REUSEADDR|SO_REUSEPORT; > - /* > - * XXX: How to deal with SO_REUSEPORT_LB here? > - * Treat same as SO_REUSEPORT for now. > - */ > - if ((so->so_options & > - (SO_REUSEADDR|SO_REUSEPORT_LB)) != 0) > - reuseport_lb = SO_REUSEADDR|SO_REUSEPORT_LB; > - } else if (!in_nullhost(laddr)) { > - sin->sin_port = 0; /* yech... */ > - bzero(&sin->sin_zero, sizeof(sin->sin_zero)); > - /* > - * Is the address a local IP address? > - * If INP_BINDANY is set, then the socket may be bound > - * to any endpoint address, local or not. > - */ > - if ((inp->inp_flags & INP_BINDANY) == 0 && > - ifa_ifwithaddr_check( > - (const struct sockaddr *)sin) == 0) > - return (EADDRNOTAVAIL); > - } > - if (lport) { > - struct inpcb *t; > - > - if (ntohs(lport) <= V_ipport_reservedhigh && > - ntohs(lport) >= V_ipport_reservedlow && > - priv_check_cred(cred, PRIV_NETINET_RESERVEDPORT)) > - return (EACCES); > - > - if (!IN_MULTICAST(ntohl(laddr.s_addr)) && > - priv_check_cred(inp->inp_cred, PRIV_NETINET_REUSEPORT) != > 0) { > - t = in_pcblookup_local(pcbinfo, laddr, lport, > - INPLOOKUP_WILDCARD, cred); > - if (t != NULL && > - (so->so_type != SOCK_STREAM || > - in_nullhost(t->inp_faddr)) && > - (!in_nullhost(laddr) || > - !in_nullhost(t->inp_laddr) || > - (t->inp_socket->so_options & SO_REUSEPORT) || > - (t->inp_socket->so_options & SO_REUSEPORT_LB) == > 0) && > - (inp->inp_cred->cr_uid != > - t->inp_cred->cr_uid)) > - return (EADDRINUSE); > - } > - t = in_pcblookup_local(pcbinfo, laddr, lport, > - lookupflags, cred); > - if (t != NULL && ((reuseport | reuseport_lb) & > - t->inp_socket->so_options) == 0) { > -#ifdef INET6 > - if (!in_nullhost(laddr) || > - !in_nullhost(t->inp_laddr) || > - (inp->inp_vflag & INP_IPV6PROTO) == 0 || > - (t->inp_vflag & INP_IPV6PROTO) == 0) > -#endif > - return (EADDRINUSE); > - } > - } > + /* See if this address/port combo is available. */ > + error = in_pcbbind_avail(inp, laddr, lport, sooptions, > + lookupflags, cred); > + if (error != 0) > + return (error); > } > if (*lportp != 0) > lport = *lportp; > diff --git a/sys/netinet6/in6_pcb.c b/sys/netinet6/in6_pcb.c > index 639ec68e19e2..6b5a9d3706be 100644 > --- a/sys/netinet6/in6_pcb.c > +++ b/sys/netinet6/in6_pcb.c > @@ -160,27 +160,157 @@ in6_pcbsetport(struct in6_addr *laddr, struct inpcb *inp, struct > ucred *cred) return (0); > } > > +/* > + * Determine whether the inpcb can be bound to the specified address/port tuple. > + */ > +static int > +in6_pcbbind_avail(struct inpcb *inp, const struct sockaddr_in6 *sin6, > + int sooptions, int lookupflags, struct ucred *cred) > +{ > + const struct in6_addr *laddr; > + int reuseport, reuseport_lb; > + u_short lport; > + > + INP_LOCK_ASSERT(inp); > + INP_HASH_LOCK_ASSERT(inp->inp_pcbinfo); > + > + laddr = &sin6->sin6_addr; > + lport = sin6->sin6_port; > + > + reuseport = (sooptions & SO_REUSEPORT); > + reuseport_lb = (sooptions & SO_REUSEPORT_LB); > + > + if (IN6_IS_ADDR_MULTICAST(laddr)) { > + /* > + * Treat SO_REUSEADDR as SO_REUSEPORT for multicast; > + * allow compepte duplication of binding if > + * SO_REUSEPORT is set, or if SO_REUSEADDR is set > + * and a multicast address is bound on both > + * new and duplicated sockets. > + */ > + if ((sooptions & (SO_REUSEADDR | SO_REUSEPORT)) != 0) > + reuseport = SO_REUSEADDR | SO_REUSEPORT; > + /* > + * XXX: How to deal with SO_REUSEPORT_LB here? > + * Treat same as SO_REUSEPORT for now. > + */ > + if ((sooptions & (SO_REUSEADDR | SO_REUSEPORT_LB)) != 0) > + reuseport_lb = SO_REUSEADDR | SO_REUSEPORT_LB; > + } else if (!IN6_IS_ADDR_UNSPECIFIED(laddr)) { > + struct sockaddr_in6 sin6; > + struct epoch_tracker et; > + struct ifaddr *ifa; > + > + memset(&sin6, 0, sizeof(sin6)); > + sin6.sin6_family = AF_INET6; > + sin6.sin6_len = sizeof(sin6); > + sin6.sin6_addr = *laddr; > + > + NET_EPOCH_ENTER(et); > + if ((ifa = ifa_ifwithaddr((const struct sockaddr *)&sin6)) == > + NULL && (inp->inp_flags & INP_BINDANY) == 0) { > + NET_EPOCH_EXIT(et); > + return (EADDRNOTAVAIL); > + } > + > + /* > + * XXX: bind to an anycast address might accidentally > + * cause sending a packet with anycast source address. > + * We should allow to bind to a deprecated address, since > + * the application dares to use it. > + */ > + if (ifa != NULL && > + ((struct in6_ifaddr *)ifa)->ia6_flags & > + (IN6_IFF_ANYCAST | IN6_IFF_NOTREADY | IN6_IFF_DETACHED)) { > + NET_EPOCH_EXIT(et); > + return (EADDRNOTAVAIL); > + } > + NET_EPOCH_EXIT(et); > + } > + > + if (lport != 0) { > + struct inpcb *t; > + > + if (ntohs(lport) <= V_ipport_reservedhigh && > + ntohs(lport) >= V_ipport_reservedlow && > + priv_check_cred(cred, PRIV_NETINET_RESERVEDPORT)) > + return (EACCES); > + > + if (!IN6_IS_ADDR_MULTICAST(laddr) && > + priv_check_cred(inp->inp_cred, PRIV_NETINET_REUSEPORT) != > + 0) { > + t = in6_pcblookup_local(inp->inp_pcbinfo, laddr, lport, > + INPLOOKUP_WILDCARD, cred); > + if (t != NULL && > + (inp->inp_socket->so_type != SOCK_STREAM || > + IN6_IS_ADDR_UNSPECIFIED(&t->in6p_faddr)) && > + (!IN6_IS_ADDR_UNSPECIFIED(laddr) || > + !IN6_IS_ADDR_UNSPECIFIED(&t->in6p_laddr) || > + (t->inp_socket->so_options & SO_REUSEPORT) || > + (t->inp_socket->so_options & SO_REUSEPORT_LB) == 0) && > + (inp->inp_cred->cr_uid != t->inp_cred->cr_uid)) > + return (EADDRINUSE); > + > +#ifdef INET > + if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0 && > + IN6_IS_ADDR_UNSPECIFIED(laddr)) { > + struct sockaddr_in sin; > + > + in6_sin6_2_sin(&sin, sin6); > + t = in_pcblookup_local(inp->inp_pcbinfo, > + sin.sin_addr, lport, INPLOOKUP_WILDCARD, > + cred); > + if (t != NULL && > + (inp->inp_socket->so_type != SOCK_STREAM || > + in_nullhost(t->inp_faddr)) && > + (inp->inp_cred->cr_uid != > + t->inp_cred->cr_uid)) > + return (EADDRINUSE); > + } > +#endif > + } > + t = in6_pcblookup_local(inp->inp_pcbinfo, laddr, lport, > + lookupflags, cred); > + if (t != NULL && ((reuseport | reuseport_lb) & > + t->inp_socket->so_options) == 0) > + return (EADDRINUSE); > +#ifdef INET > + if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0 && > + IN6_IS_ADDR_UNSPECIFIED(laddr)) { > + struct sockaddr_in sin; > + > + in6_sin6_2_sin(&sin, sin6); > + t = in_pcblookup_local(inp->inp_pcbinfo, sin.sin_addr, > + lport, lookupflags, cred); > + if (t != NULL && ((reuseport | reuseport_lb) & > + t->inp_socket->so_options) == 0 && > + (!in_nullhost(t->inp_laddr) || > + (t->inp_vflag & INP_IPV6PROTO) != 0)) { > + return (EADDRINUSE); > + } > + } > +#endif > + } > + return (0); > +} > + > int > in6_pcbbind(struct inpcb *inp, struct sockaddr_in6 *sin6, struct ucred *cred) > { > struct socket *so = inp->inp_socket; > struct inpcbinfo *pcbinfo = inp->inp_pcbinfo; > u_short lport = 0; > - int error, lookupflags = 0; > - int reuseport = (so->so_options & SO_REUSEPORT); > - > - /* > - * XXX: Maybe we could let SO_REUSEPORT_LB set SO_REUSEPORT bit here > - * so that we don't have to add to the (already messy) code below. > - */ > - int reuseport_lb = (so->so_options & SO_REUSEPORT_LB); > + int error, lookupflags, sooptions; > > INP_WLOCK_ASSERT(inp); > INP_HASH_WLOCK_ASSERT(pcbinfo); > > if (inp->inp_lport || !IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr)) > return (EINVAL); > - if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT|SO_REUSEPORT_LB)) == 0) > + > + lookupflags = 0; > + sooptions = atomic_load_int(&so->so_options); > + if ((sooptions & (SO_REUSEADDR | SO_REUSEPORT | SO_REUSEPORT_LB)) == 0) > lookupflags = INPLOOKUP_WILDCARD; > if (sin6 == NULL) { > if ((error = prison_local_ip6(cred, &inp->in6p_laddr, > @@ -199,115 +329,13 @@ in6_pcbbind(struct inpcb *inp, struct sockaddr_in6 *sin6, struct > ucred *cred) ((inp->inp_flags & IN6P_IPV6_V6ONLY) != 0))) != 0) > return (error); > > - lport = sin6->sin6_port; > - if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) { > - /* > - * Treat SO_REUSEADDR as SO_REUSEPORT for multicast; > - * allow compepte duplication of binding if > - * SO_REUSEPORT is set, or if SO_REUSEADDR is set > - * and a multicast address is bound on both > - * new and duplicated sockets. > - */ > - if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) != 0) > - reuseport = SO_REUSEADDR|SO_REUSEPORT; > - /* > - * XXX: How to deal with SO_REUSEPORT_LB here? > - * Treat same as SO_REUSEPORT for now. > - */ > - if ((so->so_options & > - (SO_REUSEADDR|SO_REUSEPORT_LB)) != 0) > - reuseport_lb = SO_REUSEADDR|SO_REUSEPORT_LB; > - } else if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { > - struct epoch_tracker et; > - struct ifaddr *ifa; > - > - sin6->sin6_port = 0; /* yech... */ > - NET_EPOCH_ENTER(et); > - if ((ifa = ifa_ifwithaddr((struct sockaddr *)sin6)) == > - NULL && > - (inp->inp_flags & INP_BINDANY) == 0) { > - NET_EPOCH_EXIT(et); > - return (EADDRNOTAVAIL); > - } > - > - /* > - * XXX: bind to an anycast address might accidentally > - * cause sending a packet with anycast source address. > - * We should allow to bind to a deprecated address, since > - * the application dares to use it. > - */ > - if (ifa != NULL && > - ((struct in6_ifaddr *)ifa)->ia6_flags & > - (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY|IN6_IFF_DETACHED)) { > - NET_EPOCH_EXIT(et); > - return (EADDRNOTAVAIL); > - } > - NET_EPOCH_EXIT(et); > - } > - if (lport) { > - struct inpcb *t; > - > - if (ntohs(lport) <= V_ipport_reservedhigh && > - ntohs(lport) >= V_ipport_reservedlow && > - priv_check_cred(cred, PRIV_NETINET_RESERVEDPORT)) > - return (EACCES); > - > - if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr) && > - priv_check_cred(inp->inp_cred, PRIV_NETINET_REUSEPORT) != > 0) { > - t = in6_pcblookup_local(pcbinfo, > - &sin6->sin6_addr, lport, > - INPLOOKUP_WILDCARD, cred); > - if (t != NULL && > - (so->so_type != SOCK_STREAM || > - IN6_IS_ADDR_UNSPECIFIED(&t->in6p_faddr)) && > - (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) || > - !IN6_IS_ADDR_UNSPECIFIED(&t->in6p_laddr) || > - (t->inp_socket->so_options & SO_REUSEPORT) || > - (t->inp_socket->so_options & SO_REUSEPORT_LB) == > 0) && > - (inp->inp_cred->cr_uid != > - t->inp_cred->cr_uid)) > - return (EADDRINUSE); > - > -#ifdef INET > - if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0 && > - IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { > - struct sockaddr_in sin; > - > - in6_sin6_2_sin(&sin, sin6); > - t = in_pcblookup_local(pcbinfo, > - sin.sin_addr, lport, > - INPLOOKUP_WILDCARD, cred); > - if (t != NULL && > - (so->so_type != SOCK_STREAM || > - in_nullhost(t->inp_faddr)) && > - (inp->inp_cred->cr_uid != > - t->inp_cred->cr_uid)) > - return (EADDRINUSE); > - } > -#endif > - } > - t = in6_pcblookup_local(pcbinfo, &sin6->sin6_addr, > - lport, lookupflags, cred); > - if (t != NULL && ((reuseport | reuseport_lb) & > - t->inp_socket->so_options) == 0) > - return (EADDRINUSE); > -#ifdef INET > - if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0 && > - IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { > - struct sockaddr_in sin; > + /* See if this address/port combo is available. */ > + error = in6_pcbbind_avail(inp, sin6, sooptions, lookupflags, > + cred); > + if (error != 0) > + return (error); > > - in6_sin6_2_sin(&sin, sin6); > - t = in_pcblookup_local(pcbinfo, sin.sin_addr, > - lport, lookupflags, cred); > - if (t != NULL && ((reuseport | reuseport_lb) & > - t->inp_socket->so_options) == 0 && > - (!in_nullhost(t->inp_laddr) || > - (t->inp_vflag & INP_IPV6PROTO) != 0)) { > - return (EADDRINUSE); > - } > - } > -#endif > - } > + lport = sin6->sin6_port; > inp->in6p_laddr = sin6->sin6_addr; > } > if (lport == 0) { >