Changeset View
Changeset View
Standalone View
Standalone View
sys/netinet6/in6_pcb.c
| Show First 20 Lines • Show All 479 Lines • ▼ Show 20 Lines | in6_pcbconnect(struct inpcb *inp, struct sockaddr_in6 *sin6, struct ucred *cred, | ||||
| */ | */ | ||||
| INP_HASH_WLOCK(pcbinfo); | INP_HASH_WLOCK(pcbinfo); | ||||
| if ((error = in6_pcbladdr(inp, sin6, &laddr6.sin6_addr, | if ((error = in6_pcbladdr(inp, sin6, &laddr6.sin6_addr, | ||||
| sas_required)) != 0) { | sas_required)) != 0) { | ||||
| INP_HASH_WUNLOCK(pcbinfo); | INP_HASH_WUNLOCK(pcbinfo); | ||||
| return (error); | return (error); | ||||
| } | } | ||||
| if (in6_pcblookup_hash_locked(pcbinfo, &sin6->sin6_addr, | if (in6_pcblookup_internal(pcbinfo, &sin6->sin6_addr, sin6->sin6_port, | ||||
| sin6->sin6_port, IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr) ? | IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr) ? | ||||
| &laddr6.sin6_addr : &inp->in6p_laddr, inp->inp_lport, 0, | &laddr6.sin6_addr : &inp->in6p_laddr, inp->inp_lport, 0, | ||||
| M_NODOM, RT_ALL_FIBS) != NULL) { | M_NODOM, RT_ALL_FIBS) != NULL) { | ||||
| INP_HASH_WUNLOCK(pcbinfo); | INP_HASH_WUNLOCK(pcbinfo); | ||||
| return (EADDRINUSE); | return (EADDRINUSE); | ||||
| } | } | ||||
| if (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr)) { | if (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr)) { | ||||
| if (inp->inp_lport == 0) { | if (inp->inp_lport == 0) { | ||||
| error = in_pcb_lport_dest(inp, | error = in_pcb_lport_dest(inp, | ||||
| ▲ Show 20 Lines • Show All 489 Lines • ▼ Show 20 Lines | in6_pcblookup_exact_match(const struct inpcb *inp, const struct in6_addr *faddr, | ||||
| if (IN6_ARE_ADDR_EQUAL(&inp->in6p_faddr, faddr) && | if (IN6_ARE_ADDR_EQUAL(&inp->in6p_faddr, faddr) && | ||||
| IN6_ARE_ADDR_EQUAL(&inp->in6p_laddr, laddr) && | IN6_ARE_ADDR_EQUAL(&inp->in6p_laddr, laddr) && | ||||
| inp->inp_fport == fport && inp->inp_lport == lport) | inp->inp_fport == fport && inp->inp_lport == lport) | ||||
| return (true); | return (true); | ||||
| return (false); | return (false); | ||||
| } | } | ||||
| static struct inpcb * | static struct inpcb * | ||||
| in6_pcblookup_hash_exact(struct inpcbinfo *pcbinfo, | in6_pcblookup_exact(struct inpcbinfo *pcbinfo, const struct in6_addr *faddr, | ||||
| const struct in6_addr *faddr, u_short fport, | u_short fport, const struct in6_addr *laddr, u_short lport) | ||||
| const struct in6_addr *laddr, u_short lport) | |||||
| { | { | ||||
| struct inpcbhead *head; | struct inpcbhead *head; | ||||
| struct inpcb *inp; | struct inpcb *inp; | ||||
| INP_HASH_LOCK_ASSERT(pcbinfo); | INP_HASH_LOCK_ASSERT(pcbinfo); | ||||
| /* | /* | ||||
| * First look for an exact match. | * First look for an exact match. | ||||
| Show All 30 Lines | in6_pcblookup_wild_match(const struct inpcb *inp, const struct in6_addr *laddr, | ||||
| if (IN6_ARE_ADDR_EQUAL(&inp->in6p_laddr, laddr)) | if (IN6_ARE_ADDR_EQUAL(&inp->in6p_laddr, laddr)) | ||||
| return (INPLOOKUP_MATCH_LADDR); | return (INPLOOKUP_MATCH_LADDR); | ||||
| return (INPLOOKUP_MATCH_NONE); | return (INPLOOKUP_MATCH_NONE); | ||||
| } | } | ||||
| #define INP_LOOKUP_AGAIN ((struct inpcb *)(uintptr_t)-1) | #define INP_LOOKUP_AGAIN ((struct inpcb *)(uintptr_t)-1) | ||||
| static struct inpcb * | static struct inpcb * | ||||
| in6_pcblookup_hash_wild_smr(struct inpcbinfo *pcbinfo, | in6_pcblookup_wild_smr(struct inpcbinfo *pcbinfo, | ||||
| const struct in6_addr *laddr, u_short lport, int fib, | const struct in6_addr *laddr, u_short lport, int fib, | ||||
| const inp_lookup_t lockflags) | const inp_lookup_t lockflags) | ||||
| { | { | ||||
| struct inpcbhead *head; | struct inpcbhead *head; | ||||
| struct inpcb *inp; | struct inpcb *inp; | ||||
| KASSERT(SMR_ENTERED(pcbinfo->ipi_smr), | KASSERT(SMR_ENTERED(pcbinfo->ipi_smr), | ||||
| ("%s: not in SMR read section", __func__)); | ("%s: not in SMR read section", __func__)); | ||||
| Show All 22 Lines | CK_LIST_FOREACH(inp, head, inp_hash_wild) { | ||||
| * to a serialized lookup. | * to a serialized lookup. | ||||
| */ | */ | ||||
| return (INP_LOOKUP_AGAIN); | return (INP_LOOKUP_AGAIN); | ||||
| } | } | ||||
| return (NULL); | return (NULL); | ||||
| } | } | ||||
| static struct inpcb * | static struct inpcb * | ||||
| in6_pcblookup_hash_wild_locked(struct inpcbinfo *pcbinfo, | in6_pcblookup_wild_locked(struct inpcbinfo *pcbinfo, | ||||
| const struct in6_addr *laddr, u_short lport, int fib) | const struct in6_addr *laddr, u_short lport, int fib) | ||||
| { | { | ||||
| struct inpcbhead *head; | struct inpcbhead *head; | ||||
| struct inpcb *inp, *jail_wild, *local_exact, *local_wild; | struct inpcb *inp, *jail_wild, *local_exact, *local_wild; | ||||
| INP_HASH_LOCK_ASSERT(pcbinfo); | INP_HASH_LOCK_ASSERT(pcbinfo); | ||||
| /* | /* | ||||
| ▲ Show 20 Lines • Show All 42 Lines • ▼ Show 20 Lines | in6_pcblookup_wild_locked(struct inpcbinfo *pcbinfo, | ||||
| if (local_exact != NULL) | if (local_exact != NULL) | ||||
| return (local_exact); | return (local_exact); | ||||
| if (local_wild != NULL) | if (local_wild != NULL) | ||||
| return (local_wild); | return (local_wild); | ||||
| return (NULL); | return (NULL); | ||||
| } | } | ||||
| struct inpcb * | struct inpcb * | ||||
| in6_pcblookup_hash_locked(struct inpcbinfo *pcbinfo, | in6_pcblookup_internal(struct inpcbinfo *pcbinfo, const struct in6_addr *faddr, | ||||
| const struct in6_addr *faddr, u_int fport_arg, | u_int fport_arg, const struct in6_addr *laddr, u_int lport_arg, | ||||
| const struct in6_addr *laddr, u_int lport_arg, | |||||
| int lookupflags, uint8_t numa_domain, int fib) | int lookupflags, uint8_t numa_domain, int fib) | ||||
| { | { | ||||
| struct inpcb *inp; | struct inpcb *inp; | ||||
| u_short fport = fport_arg, lport = lport_arg; | u_short fport = fport_arg, lport = lport_arg; | ||||
| KASSERT((lookupflags & ~(INPLOOKUP_WILDCARD | INPLOOKUP_FIB)) == 0, | KASSERT((lookupflags & ~(INPLOOKUP_WILDCARD | INPLOOKUP_FIB)) == 0, | ||||
| ("%s: invalid lookup flags %d", __func__, lookupflags)); | ("%s: invalid lookup flags %d", __func__, lookupflags)); | ||||
| KASSERT(!IN6_IS_ADDR_UNSPECIFIED(faddr), | KASSERT(!IN6_IS_ADDR_UNSPECIFIED(faddr), | ||||
| ("%s: invalid foreign address", __func__)); | ("%s: invalid foreign address", __func__)); | ||||
| KASSERT(!IN6_IS_ADDR_UNSPECIFIED(laddr), | KASSERT(!IN6_IS_ADDR_UNSPECIFIED(laddr), | ||||
| ("%s: invalid local address", __func__)); | ("%s: invalid local address", __func__)); | ||||
| INP_HASH_LOCK_ASSERT(pcbinfo); | INP_HASH_LOCK_ASSERT(pcbinfo); | ||||
| inp = in6_pcblookup_hash_exact(pcbinfo, faddr, fport, laddr, lport); | inp = in6_pcblookup_exact(pcbinfo, faddr, fport, laddr, lport); | ||||
| if (inp != NULL) | if (inp != NULL) | ||||
| return (inp); | return (inp); | ||||
| if ((lookupflags & INPLOOKUP_WILDCARD) != 0) { | if ((lookupflags & INPLOOKUP_WILDCARD) != 0) { | ||||
| inp = in6_pcblookup_lbgroup(pcbinfo, faddr, fport, laddr, | inp = in6_pcblookup_lbgroup(pcbinfo, faddr, fport, laddr, | ||||
| lport, numa_domain, fib); | lport, numa_domain, fib); | ||||
| if (inp == NULL) { | if (inp == NULL) { | ||||
| inp = in6_pcblookup_hash_wild_locked(pcbinfo, | inp = in6_pcblookup_wild_locked(pcbinfo, laddr, lport, | ||||
| laddr, lport, fib); | fib); | ||||
| } | } | ||||
| } | } | ||||
| return (inp); | return (inp); | ||||
| } | } | ||||
| static struct inpcb * | static struct inpcb * | ||||
| in6_pcblookup_hash(struct inpcbinfo *pcbinfo, const struct in6_addr *faddr, | in6_pcblookup_with_lock(struct inpcbinfo *pcbinfo, const struct in6_addr *faddr, | ||||
| u_int fport, const struct in6_addr *laddr, u_int lport, int lookupflags, | u_int fport, const struct in6_addr *laddr, u_int lport, int lookupflags, | ||||
| uint8_t numa_domain, int fib) | uint8_t numa_domain, int fib) | ||||
| { | { | ||||
| struct inpcb *inp; | struct inpcb *inp; | ||||
| const inp_lookup_t lockflags = lookupflags & INPLOOKUP_LOCKMASK; | const inp_lookup_t lockflags = lookupflags & INPLOOKUP_LOCKMASK; | ||||
| KASSERT((lookupflags & (INPLOOKUP_RLOCKPCB | INPLOOKUP_WLOCKPCB)) != 0, | KASSERT((lookupflags & (INPLOOKUP_RLOCKPCB | INPLOOKUP_WLOCKPCB)) != 0, | ||||
| ("%s: LOCKPCB not set", __func__)); | ("%s: LOCKPCB not set", __func__)); | ||||
| INP_HASH_WLOCK(pcbinfo); | INP_HASH_WLOCK(pcbinfo); | ||||
| inp = in6_pcblookup_hash_locked(pcbinfo, faddr, fport, laddr, lport, | inp = in6_pcblookup_internal(pcbinfo, faddr, fport, laddr, lport, | ||||
| lookupflags & ~INPLOOKUP_LOCKMASK, numa_domain, fib); | lookupflags & ~INPLOOKUP_LOCKMASK, numa_domain, fib); | ||||
| if (inp != NULL && !inp_trylock(inp, lockflags)) { | if (inp != NULL && !inp_trylock(inp, lockflags)) { | ||||
| in_pcbref(inp); | in_pcbref(inp); | ||||
| INP_HASH_WUNLOCK(pcbinfo); | INP_HASH_WUNLOCK(pcbinfo); | ||||
| inp_lock(inp, lockflags); | inp_lock(inp, lockflags); | ||||
| if (in_pcbrele(inp, lockflags)) | if (in_pcbrele(inp, lockflags)) | ||||
| /* XXX-MJ or retry until we get a negative match? */ | /* XXX-MJ or retry until we get a negative match? */ | ||||
| inp = NULL; | inp = NULL; | ||||
| } else { | } else { | ||||
| INP_HASH_WUNLOCK(pcbinfo); | INP_HASH_WUNLOCK(pcbinfo); | ||||
| } | } | ||||
| return (inp); | return (inp); | ||||
| } | } | ||||
| static struct inpcb * | static struct inpcb * | ||||
| in6_pcblookup_hash_smr(struct inpcbinfo *pcbinfo, const struct in6_addr *faddr, | in6_pcblookup_smr(struct inpcbinfo *pcbinfo, const struct in6_addr *faddr, | ||||
| u_int fport_arg, const struct in6_addr *laddr, u_int lport_arg, | u_int fport_arg, const struct in6_addr *laddr, u_int lport_arg, | ||||
| int lookupflags, uint8_t numa_domain, int fib) | int lookupflags, uint8_t numa_domain, int fib) | ||||
| { | { | ||||
| struct inpcb *inp; | struct inpcb *inp; | ||||
| const inp_lookup_t lockflags = lookupflags & INPLOOKUP_LOCKMASK; | const inp_lookup_t lockflags = lookupflags & INPLOOKUP_LOCKMASK; | ||||
| const u_short fport = fport_arg, lport = lport_arg; | const u_short fport = fport_arg, lport = lport_arg; | ||||
| KASSERT((lookupflags & ~INPLOOKUP_MASK) == 0, | KASSERT((lookupflags & ~INPLOOKUP_MASK) == 0, | ||||
| ("%s: invalid lookup flags %d", __func__, lookupflags)); | ("%s: invalid lookup flags %d", __func__, lookupflags)); | ||||
| KASSERT((lookupflags & (INPLOOKUP_RLOCKPCB | INPLOOKUP_WLOCKPCB)) != 0, | KASSERT((lookupflags & (INPLOOKUP_RLOCKPCB | INPLOOKUP_WLOCKPCB)) != 0, | ||||
| ("%s: LOCKPCB not set", __func__)); | ("%s: LOCKPCB not set", __func__)); | ||||
| smr_enter(pcbinfo->ipi_smr); | smr_enter(pcbinfo->ipi_smr); | ||||
| inp = in6_pcblookup_hash_exact(pcbinfo, faddr, fport, laddr, lport); | inp = in6_pcblookup_exact(pcbinfo, faddr, fport, laddr, lport); | ||||
| if (inp != NULL) { | if (inp != NULL) { | ||||
| if (__predict_true(inp_smr_lock(inp, lockflags))) { | if (__predict_true(inp_smr_lock(inp, lockflags))) { | ||||
| if (__predict_true(in6_pcblookup_exact_match(inp, | if (__predict_true(in6_pcblookup_exact_match(inp, | ||||
| faddr, fport, laddr, lport))) | faddr, fport, laddr, lport))) | ||||
| return (inp); | return (inp); | ||||
| inp_unlock(inp, lockflags); | inp_unlock(inp, lockflags); | ||||
| } | } | ||||
| /* | /* | ||||
| * We failed to lock the inpcb, or its connection state changed | * We failed to lock the inpcb, or its connection state changed | ||||
| * out from under us. Fall back to a precise search. | * out from under us. Fall back to a precise search. | ||||
| */ | */ | ||||
| return (in6_pcblookup_hash(pcbinfo, faddr, fport, laddr, lport, | return (in6_pcblookup_with_lock(pcbinfo, faddr, fport, laddr, | ||||
| lookupflags, numa_domain, fib)); | lport, lookupflags, numa_domain, fib)); | ||||
| } | } | ||||
| if ((lookupflags & INPLOOKUP_WILDCARD) != 0) { | if ((lookupflags & INPLOOKUP_WILDCARD) != 0) { | ||||
| inp = in6_pcblookup_lbgroup(pcbinfo, faddr, fport, | inp = in6_pcblookup_lbgroup(pcbinfo, faddr, fport, | ||||
| laddr, lport, numa_domain, fib); | laddr, lport, numa_domain, fib); | ||||
| if (inp != NULL) { | if (inp != NULL) { | ||||
| if (__predict_true(inp_smr_lock(inp, lockflags))) { | if (__predict_true(inp_smr_lock(inp, lockflags))) { | ||||
| if (__predict_true(in6_pcblookup_wild_match(inp, | if (__predict_true(in6_pcblookup_wild_match(inp, | ||||
| laddr, lport, fib) != INPLOOKUP_MATCH_NONE)) | laddr, lport, fib) != INPLOOKUP_MATCH_NONE)) | ||||
| return (inp); | return (inp); | ||||
| inp_unlock(inp, lockflags); | inp_unlock(inp, lockflags); | ||||
| } | } | ||||
| inp = INP_LOOKUP_AGAIN; | inp = INP_LOOKUP_AGAIN; | ||||
| } else { | } else { | ||||
| inp = in6_pcblookup_hash_wild_smr(pcbinfo, laddr, lport, | inp = in6_pcblookup_wild_smr(pcbinfo, laddr, lport, | ||||
| fib, lockflags); | fib, lockflags); | ||||
| } | } | ||||
| if (inp == INP_LOOKUP_AGAIN) { | if (inp == INP_LOOKUP_AGAIN) { | ||||
| return (in6_pcblookup_hash(pcbinfo, faddr, fport, laddr, | return (in6_pcblookup_with_lock(pcbinfo, faddr, fport, | ||||
| lport, lookupflags, numa_domain, fib)); | laddr, lport, lookupflags, numa_domain, fib)); | ||||
| } | } | ||||
| } | } | ||||
| if (inp == NULL) | if (inp == NULL) | ||||
| smr_exit(pcbinfo->ipi_smr); | smr_exit(pcbinfo->ipi_smr); | ||||
| return (inp); | return (inp); | ||||
| } | } | ||||
| /* | /* | ||||
| * Public inpcb lookup routines, accepting a 4-tuple, and optionally, an mbuf | * Public inpcb lookup routines, accepting a 4-tuple, and optionally, an mbuf | ||||
| * from which a pre-calculated hash value may be extracted. | * from which a pre-calculated hash value may be extracted. | ||||
| */ | */ | ||||
| struct inpcb * | struct inpcb * | ||||
| in6_pcblookup(struct inpcbinfo *pcbinfo, const struct in6_addr *faddr, | in6_pcblookup(struct inpcbinfo *pcbinfo, const struct in6_addr *faddr, | ||||
| u_int fport, const struct in6_addr *laddr, u_int lport, int lookupflags, | u_int fport, const struct in6_addr *laddr, u_int lport, int lookupflags, | ||||
| struct ifnet *ifp) | struct ifnet *ifp) | ||||
| { | { | ||||
| int fib; | int fib; | ||||
| fib = (lookupflags & INPLOOKUP_FIB) ? if_getfib(ifp) : RT_ALL_FIBS; | fib = (lookupflags & INPLOOKUP_FIB) ? if_getfib(ifp) : RT_ALL_FIBS; | ||||
| return (in6_pcblookup_hash_smr(pcbinfo, faddr, fport, laddr, lport, | return (in6_pcblookup_smr(pcbinfo, faddr, fport, laddr, lport, | ||||
| lookupflags, M_NODOM, fib)); | lookupflags, M_NODOM, fib)); | ||||
| } | } | ||||
| struct inpcb * | struct inpcb * | ||||
| in6_pcblookup_mbuf(struct inpcbinfo *pcbinfo, const struct in6_addr *faddr, | in6_pcblookup_mbuf(struct inpcbinfo *pcbinfo, const struct in6_addr *faddr, | ||||
| u_int fport, const struct in6_addr *laddr, u_int lport, int lookupflags, | u_int fport, const struct in6_addr *laddr, u_int lport, int lookupflags, | ||||
| struct ifnet *ifp __unused, struct mbuf *m) | struct ifnet *ifp __unused, struct mbuf *m) | ||||
| { | { | ||||
| int fib; | int fib; | ||||
| M_ASSERTPKTHDR(m); | M_ASSERTPKTHDR(m); | ||||
| fib = (lookupflags & INPLOOKUP_FIB) ? M_GETFIB(m) : RT_ALL_FIBS; | fib = (lookupflags & INPLOOKUP_FIB) ? M_GETFIB(m) : RT_ALL_FIBS; | ||||
| return (in6_pcblookup_hash_smr(pcbinfo, faddr, fport, laddr, lport, | return (in6_pcblookup_smr(pcbinfo, faddr, fport, laddr, lport, | ||||
| lookupflags, m->m_pkthdr.numa_domain, fib)); | lookupflags, m->m_pkthdr.numa_domain, fib)); | ||||
| } | } | ||||
| void | void | ||||
| init_sin6(struct sockaddr_in6 *sin6, struct mbuf *m, int srcordst) | init_sin6(struct sockaddr_in6 *sin6, struct mbuf *m, int srcordst) | ||||
| { | { | ||||
| struct ip6_hdr *ip; | struct ip6_hdr *ip; | ||||
| Show All 10 Lines | |||||