diff --git a/sys/netinet/in_pcb.c b/sys/netinet/in_pcb.c --- a/sys/netinet/in_pcb.c +++ b/sys/netinet/in_pcb.c @@ -852,12 +852,14 @@ #ifdef INET6 if ((inp->inp_vflag & INP_IPV6) != 0) { tmpinp = in6_pcblookup_local(pcbinfo, - &inp->in6p_laddr, lport, lookupflags, cred); + &inp->in6p_laddr, lport, -1, lookupflags, + cred); #ifdef INET if (tmpinp == NULL && (inp->inp_vflag & INP_IPV4)) tmpinp = in_pcblookup_local(pcbinfo, - laddr, lport, lookupflags, cred); + laddr, lport, -1, lookupflags, + cred); #endif } #endif @@ -866,7 +868,7 @@ #endif #ifdef INET tmpinp = in_pcblookup_local(pcbinfo, laddr, - lport, lookupflags, cred); + lport, -1, lookupflags, cred); #endif } } while (tmpinp != NULL); @@ -965,14 +967,14 @@ * which has a unique 4-tuple. */ t = in_pcblookup_local(inp->inp_pcbinfo, laddr, lport, - INPLOOKUP_WILDCARD, cred); + -1, 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); } - t = in_pcblookup_local(inp->inp_pcbinfo, laddr, lport, + t = in_pcblookup_local(inp->inp_pcbinfo, laddr, lport, -1, lookupflags, cred); if (t != NULL && ((reuseport | reuseport_lb) & t->inp_socket->so_options) == 0) { @@ -2000,7 +2002,7 @@ #define INP_LOOKUP_MAPPED_PCB_COST 3 struct inpcb * in_pcblookup_local(struct inpcbinfo *pcbinfo, struct in_addr laddr, - u_short lport, int lookupflags, struct ucred *cred) + u_short lport, int fib, int lookupflags, struct ucred *cred) { struct inpcb *inp; #ifdef INET6 @@ -2012,6 +2014,9 @@ KASSERT((lookupflags & ~(INPLOOKUP_WILDCARD)) == 0, ("%s: invalid lookup flags %d", __func__, lookupflags)); + KASSERT(fib == -1 || (fib >= 0 && fib < V_rt_numfibs), + ("%s: invalid fib %d", __func__, fib)); + INP_HASH_LOCK_ASSERT(pcbinfo); if ((lookupflags & INPLOOKUP_WILDCARD) == 0) { @@ -2030,7 +2035,8 @@ #endif if (inp->inp_faddr.s_addr == INADDR_ANY && inp->inp_laddr.s_addr == laddr.s_addr && - inp->inp_lport == lport) { + inp->inp_lport == lport && + (fib == -1 || inp->inp_inc.inc_fibnum == fib)) { /* * Found? */ @@ -2069,6 +2075,8 @@ if (!prison_equal_ip4(inp->inp_cred->cr_prison, cred->cr_prison)) continue; + if (fib != -1 && inp->inp_inc.inc_fibnum != fib) + continue; #ifdef INET6 /* XXX inp locking */ if ((inp->inp_vflag & INP_IPV4) == 0) diff --git a/sys/netinet/in_pcb_var.h b/sys/netinet/in_pcb_var.h --- a/sys/netinet/in_pcb_var.h +++ b/sys/netinet/in_pcb_var.h @@ -53,8 +53,8 @@ int in_pcb_lport_dest(struct inpcb *inp, struct sockaddr *lsa, u_short *lportp, struct sockaddr *fsa, u_short fport, struct ucred *cred, int lookupflags); -struct inpcb * in_pcblookup_local(struct inpcbinfo *, struct in_addr, u_short, - int, struct ucred *); +struct inpcb *in_pcblookup_local(struct inpcbinfo *, struct in_addr, u_short, + int, int, struct ucred *); struct inpcbport { struct inpcbhead phd_pcblist; diff --git a/sys/netinet6/in6_pcb.h b/sys/netinet6/in6_pcb.h --- a/sys/netinet6/in6_pcb.h +++ b/sys/netinet6/in6_pcb.h @@ -75,7 +75,7 @@ bool); void in6_pcbdisconnect(struct inpcb *); struct inpcb *in6_pcblookup_local(struct inpcbinfo *, const struct in6_addr *, - u_short, int, struct ucred *); + u_short, int, int, struct ucred *); struct inpcb *in6_pcblookup_hash_locked(struct inpcbinfo *pcbinfo, const struct in6_addr *faddr, u_int fport_arg, const struct in6_addr *laddr, u_int lport_arg, diff --git a/sys/netinet6/in6_pcb.c b/sys/netinet6/in6_pcb.c --- a/sys/netinet6/in6_pcb.c +++ b/sys/netinet6/in6_pcb.c @@ -249,7 +249,7 @@ * which has a unique 4-tuple. */ t = in6_pcblookup_local(inp->inp_pcbinfo, laddr, lport, - INPLOOKUP_WILDCARD, cred); + -1, INPLOOKUP_WILDCARD, cred); if (t != NULL && (inp->inp_socket->so_type != SOCK_STREAM || IN6_IS_ADDR_UNSPECIFIED(&t->in6p_faddr)) && @@ -263,7 +263,7 @@ in6_sin6_2_sin(&sin, sin6); t = in_pcblookup_local(inp->inp_pcbinfo, - sin.sin_addr, lport, INPLOOKUP_WILDCARD, + sin.sin_addr, lport, -1, INPLOOKUP_WILDCARD, cred); if (t != NULL && (inp->inp_socket->so_type != SOCK_STREAM || @@ -275,7 +275,7 @@ #endif } t = in6_pcblookup_local(inp->inp_pcbinfo, laddr, lport, - lookupflags, cred); + -1, lookupflags, cred); if (t != NULL && ((reuseport | reuseport_lb) & t->inp_socket->so_options) == 0) return (EADDRINUSE); @@ -286,7 +286,7 @@ in6_sin6_2_sin(&sin, sin6); t = in_pcblookup_local(inp->inp_pcbinfo, sin.sin_addr, - lport, lookupflags, cred); + lport, -1, lookupflags, cred); if (t != NULL && ((reuseport | reuseport_lb) & t->inp_socket->so_options) == 0 && (!in_nullhost(t->inp_laddr) || @@ -720,13 +720,15 @@ */ struct inpcb * in6_pcblookup_local(struct inpcbinfo *pcbinfo, const struct in6_addr *laddr, - u_short lport, int lookupflags, struct ucred *cred) + u_short lport, int fib, int lookupflags, struct ucred *cred) { struct inpcb *inp; int matchwild = 3, wildcard; KASSERT((lookupflags & ~(INPLOOKUP_WILDCARD)) == 0, ("%s: invalid lookup flags %d", __func__, lookupflags)); + KASSERT(fib == -1 || (fib >= 0 && fib < V_rt_numfibs), + ("%s: invalid fib %d", __func__, fib)); INP_HASH_LOCK_ASSERT(pcbinfo); @@ -744,7 +746,8 @@ continue; if (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr) && IN6_ARE_ADDR_EQUAL(&inp->in6p_laddr, laddr) && - inp->inp_lport == lport) { + inp->inp_lport == lport && + (fib == -1 || inp->inp_inc.inc_fibnum == fib)) { /* Found. */ if (prison_equal_ip6(cred->cr_prison, inp->inp_cred->cr_prison)) @@ -784,6 +787,8 @@ /* XXX inp locking */ if ((inp->inp_vflag & INP_IPV6) == 0) continue; + if (fib != -1 && inp->inp_inc.inc_fibnum != fib) + continue; if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) wildcard++; if (!IN6_IS_ADDR_UNSPECIFIED(