Re: git: 01f8ce83242d - main - inpcb: Factor out parts of in6_pcbbind() and in_pcbbind_setup()
- Reply: Mark Johnston : "Re: git: 01f8ce83242d - main - inpcb: Factor out parts of in6_pcbbind() and in_pcbbind_setup()"
- In reply to: Mark Johnston : "git: 01f8ce83242d - main - inpcb: Factor out parts of in6_pcbbind() and in_pcbbind_setup()"
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Thu, 05 Dec 2024 16:35:23 UTC
On Thu, 5 Dec 2024 15:20:48 GMT
Mark Johnston <markj@FreeBSD.org> 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 <markj@FreeBSD.org>
> AuthorDate: 2024-12-05 15:00:13 +0000
> Commit: Mark Johnston <markj@FreeBSD.org>
> 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) {
>