Changeset View
Changeset View
Standalone View
Standalone View
sys/netinet/tcp_input.c
Show First 20 Lines • Show All 620 Lines • ▼ Show 20 Lines | |||||
#ifdef INET | #ifdef INET | ||||
int len; | int len; | ||||
uint8_t ipttl; | uint8_t ipttl; | ||||
#endif | #endif | ||||
int tlen = 0, off; | int tlen = 0, off; | ||||
int drop_hdrlen; | int drop_hdrlen; | ||||
int thflags; | int thflags; | ||||
int rstreason = 0; /* For badport_bandlim accounting purposes */ | int rstreason = 0; /* For badport_bandlim accounting purposes */ | ||||
int lookupflag; | |||||
uint8_t iptos; | uint8_t iptos; | ||||
struct m_tag *fwd_tag = NULL; | struct m_tag *fwd_tag = NULL; | ||||
#ifdef INET6 | #ifdef INET6 | ||||
struct ip6_hdr *ip6 = NULL; | struct ip6_hdr *ip6 = NULL; | ||||
int isipv6; | int isipv6; | ||||
#else | #else | ||||
const void *ip6 = NULL; | const void *ip6 = NULL; | ||||
#endif /* INET6 */ | #endif /* INET6 */ | ||||
▲ Show 20 Lines • Show All 183 Lines • ▼ Show 20 Lines | |||||
#endif | #endif | ||||
#endif | #endif | ||||
#if defined(INET) && !defined(INET6) | #if defined(INET) && !defined(INET6) | ||||
(m->m_flags & M_IP_NEXTHOP) | (m->m_flags & M_IP_NEXTHOP) | ||||
#endif | #endif | ||||
) | ) | ||||
fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL); | fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL); | ||||
/* | |||||
* For initial SYN packets arriving on listening socket, | |||||
* we don't need write lock. | |||||
*/ | |||||
lookupflag = (thflags & (TH_ACK|TH_SYN)) == TH_SYN ? | |||||
INPLOOKUP_RLOCKLISTEN : INPLOOKUP_WLOCKPCB; | |||||
findpcb: | findpcb: | ||||
#ifdef INET6 | #ifdef INET6 | ||||
if (isipv6 && fwd_tag != NULL) { | if (isipv6 && fwd_tag != NULL) { | ||||
struct sockaddr_in6 *next_hop6; | struct sockaddr_in6 *next_hop6; | ||||
next_hop6 = (struct sockaddr_in6 *)(fwd_tag + 1); | next_hop6 = (struct sockaddr_in6 *)(fwd_tag + 1); | ||||
/* | /* | ||||
* Transparently forwarded. Pretend to be the destination. | * Transparently forwarded. Pretend to be the destination. | ||||
* Already got one like this? | * Already got one like this? | ||||
*/ | */ | ||||
inp = in6_pcblookup_mbuf(&V_tcbinfo, | inp = in6_pcblookup_mbuf(&V_tcbinfo, | ||||
&ip6->ip6_src, th->th_sport, &ip6->ip6_dst, th->th_dport, | &ip6->ip6_src, th->th_sport, &ip6->ip6_dst, th->th_dport, | ||||
INPLOOKUP_WLOCKPCB, m->m_pkthdr.rcvif, m); | lookupflag, m->m_pkthdr.rcvif, m); | ||||
if (!inp) { | if (!inp) { | ||||
/* | /* | ||||
* It's new. Try to find the ambushing socket. | * It's new. Try to find the ambushing socket. | ||||
* Because we've rewritten the destination address, | * Because we've rewritten the destination address, | ||||
* any hardware-generated hash is ignored. | * any hardware-generated hash is ignored. | ||||
*/ | */ | ||||
inp = in6_pcblookup(&V_tcbinfo, &ip6->ip6_src, | inp = in6_pcblookup(&V_tcbinfo, &ip6->ip6_src, | ||||
th->th_sport, &next_hop6->sin6_addr, | th->th_sport, &next_hop6->sin6_addr, | ||||
next_hop6->sin6_port ? ntohs(next_hop6->sin6_port) : | next_hop6->sin6_port ? ntohs(next_hop6->sin6_port) : | ||||
th->th_dport, INPLOOKUP_WILDCARD | | th->th_dport, INPLOOKUP_WILDCARD | lookupflag, | ||||
INPLOOKUP_WLOCKPCB, m->m_pkthdr.rcvif); | m->m_pkthdr.rcvif); | ||||
} | } | ||||
} else if (isipv6) { | } else if (isipv6) { | ||||
inp = in6_pcblookup_mbuf(&V_tcbinfo, &ip6->ip6_src, | inp = in6_pcblookup_mbuf(&V_tcbinfo, &ip6->ip6_src, | ||||
th->th_sport, &ip6->ip6_dst, th->th_dport, | th->th_sport, &ip6->ip6_dst, th->th_dport, | ||||
INPLOOKUP_WILDCARD | INPLOOKUP_WLOCKPCB, | INPLOOKUP_WILDCARD | lookupflag, m->m_pkthdr.rcvif, m); | ||||
m->m_pkthdr.rcvif, m); | |||||
} | } | ||||
#endif /* INET6 */ | #endif /* INET6 */ | ||||
#if defined(INET6) && defined(INET) | #if defined(INET6) && defined(INET) | ||||
else | else | ||||
#endif | #endif | ||||
#ifdef INET | #ifdef INET | ||||
if (fwd_tag != NULL) { | if (fwd_tag != NULL) { | ||||
struct sockaddr_in *next_hop; | struct sockaddr_in *next_hop; | ||||
next_hop = (struct sockaddr_in *)(fwd_tag+1); | next_hop = (struct sockaddr_in *)(fwd_tag+1); | ||||
/* | /* | ||||
* Transparently forwarded. Pretend to be the destination. | * Transparently forwarded. Pretend to be the destination. | ||||
* already got one like this? | * already got one like this? | ||||
*/ | */ | ||||
inp = in_pcblookup_mbuf(&V_tcbinfo, ip->ip_src, th->th_sport, | inp = in_pcblookup_mbuf(&V_tcbinfo, ip->ip_src, th->th_sport, | ||||
ip->ip_dst, th->th_dport, INPLOOKUP_WLOCKPCB, | ip->ip_dst, th->th_dport, lookupflag, m->m_pkthdr.rcvif, m); | ||||
m->m_pkthdr.rcvif, m); | |||||
if (!inp) { | if (!inp) { | ||||
/* | /* | ||||
* It's new. Try to find the ambushing socket. | * It's new. Try to find the ambushing socket. | ||||
* Because we've rewritten the destination address, | * Because we've rewritten the destination address, | ||||
* any hardware-generated hash is ignored. | * any hardware-generated hash is ignored. | ||||
*/ | */ | ||||
inp = in_pcblookup(&V_tcbinfo, ip->ip_src, | inp = in_pcblookup(&V_tcbinfo, ip->ip_src, | ||||
th->th_sport, next_hop->sin_addr, | th->th_sport, next_hop->sin_addr, | ||||
next_hop->sin_port ? ntohs(next_hop->sin_port) : | next_hop->sin_port ? ntohs(next_hop->sin_port) : | ||||
th->th_dport, INPLOOKUP_WILDCARD | | th->th_dport, INPLOOKUP_WILDCARD | lookupflag, | ||||
INPLOOKUP_WLOCKPCB, m->m_pkthdr.rcvif); | m->m_pkthdr.rcvif); | ||||
} | } | ||||
} else | } else | ||||
inp = in_pcblookup_mbuf(&V_tcbinfo, ip->ip_src, | inp = in_pcblookup_mbuf(&V_tcbinfo, ip->ip_src, | ||||
th->th_sport, ip->ip_dst, th->th_dport, | th->th_sport, ip->ip_dst, th->th_dport, | ||||
INPLOOKUP_WILDCARD | INPLOOKUP_WLOCKPCB, | INPLOOKUP_WILDCARD | lookupflag, m->m_pkthdr.rcvif, m); | ||||
m->m_pkthdr.rcvif, m); | |||||
#endif /* INET */ | #endif /* INET */ | ||||
/* | /* | ||||
* If the INPCB does not exist then all data in the incoming | * If the INPCB does not exist then all data in the incoming | ||||
* segment is discarded and an appropriate RST is sent back. | * segment is discarded and an appropriate RST is sent back. | ||||
* XXX MRT Send RST using which routing table? | * XXX MRT Send RST using which routing table? | ||||
*/ | */ | ||||
if (inp == NULL) { | if (inp == NULL) { | ||||
Show All 13 Lines | if (inp == NULL) { | ||||
*/ | */ | ||||
if ((V_blackhole == 1 && (thflags & TH_SYN)) || | if ((V_blackhole == 1 && (thflags & TH_SYN)) || | ||||
V_blackhole == 2) | V_blackhole == 2) | ||||
goto dropunlock; | goto dropunlock; | ||||
rstreason = BANDLIM_RST_CLOSEDPORT; | rstreason = BANDLIM_RST_CLOSEDPORT; | ||||
goto dropwithreset; | goto dropwithreset; | ||||
} | } | ||||
INP_WLOCK_ASSERT(inp); | INP_LOCK_ASSERT(inp); | ||||
/* | /* | ||||
* While waiting for inp lock during the lookup, another thread | * While waiting for inp lock during the lookup, another thread | ||||
* can have dropped the inpcb, in which case we need to loop back | * can have dropped the inpcb, in which case we need to loop back | ||||
* and try to find a new inpcb to deliver to. | * and try to find a new inpcb to deliver to. | ||||
*/ | */ | ||||
if (inp->inp_flags & INP_DROPPED) { | if (inp->inp_flags & INP_DROPPED) { | ||||
INP_WUNLOCK(inp); | INP_UNLOCK(inp); | ||||
inp = NULL; | inp = NULL; | ||||
goto findpcb; | goto findpcb; | ||||
} | } | ||||
if ((inp->inp_flowtype == M_HASHTYPE_NONE) && | if ((inp->inp_flowtype == M_HASHTYPE_NONE) && | ||||
(M_HASHTYPE_GET(m) != M_HASHTYPE_NONE) && | (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE) && | ||||
((inp->inp_socket == NULL) || | ((inp->inp_socket == NULL) || | ||||
(inp->inp_socket->so_options & SO_ACCEPTCONN) == 0)) { | (inp->inp_socket->so_options & SO_ACCEPTCONN) == 0)) { | ||||
inp->inp_flowid = m->m_pkthdr.flowid; | inp->inp_flowid = m->m_pkthdr.flowid; | ||||
▲ Show 20 Lines • Show All 72 Lines • ▼ Show 20 Lines | #ifdef TCP_OFFLOAD | ||||
if (tp->t_flags & TF_TOE) { | if (tp->t_flags & TF_TOE) { | ||||
tcp_offload_input(tp, m); | tcp_offload_input(tp, m); | ||||
m = NULL; /* consumed by the TOE driver */ | m = NULL; /* consumed by the TOE driver */ | ||||
goto dropunlock; | goto dropunlock; | ||||
} | } | ||||
#endif | #endif | ||||
#ifdef MAC | #ifdef MAC | ||||
INP_WLOCK_ASSERT(inp); | |||||
if (mac_inpcb_check_deliver(inp, m)) | if (mac_inpcb_check_deliver(inp, m)) | ||||
goto dropunlock; | goto dropunlock; | ||||
#endif | #endif | ||||
so = inp->inp_socket; | so = inp->inp_socket; | ||||
KASSERT(so != NULL, ("%s: so == NULL", __func__)); | KASSERT(so != NULL, ("%s: so == NULL", __func__)); | ||||
#ifdef TCPDEBUG | #ifdef TCPDEBUG | ||||
if (so->so_options & SO_DEBUG) { | if (so->so_options & SO_DEBUG) { | ||||
ostate = tp->t_state; | ostate = tp->t_state; | ||||
▲ Show 20 Lines • Show All 93 Lines • ▼ Show 20 Lines | tfo_socket_result: | ||||
goto dropwithreset; | goto dropwithreset; | ||||
} else | } else | ||||
goto dropunlock; | goto dropunlock; | ||||
} | } | ||||
/* | /* | ||||
* Socket is created in state SYN_RECEIVED. | * Socket is created in state SYN_RECEIVED. | ||||
* Unlock the listen socket, lock the newly | * Unlock the listen socket, lock the newly | ||||
* created socket and update the tp variable. | * created socket and update the tp variable. | ||||
* If we came here via jump to tfo_socket_result, | |||||
* then listening socket is read-locked. | |||||
*/ | */ | ||||
INP_WUNLOCK(inp); /* listen socket */ | INP_UNLOCK(inp); /* listen socket */ | ||||
inp = sotoinpcb(so); | inp = sotoinpcb(so); | ||||
/* | /* | ||||
* New connection inpcb is already locked by | * New connection inpcb is already locked by | ||||
* syncache_expand(). | * syncache_expand(). | ||||
*/ | */ | ||||
INP_WLOCK_ASSERT(inp); | INP_WLOCK_ASSERT(inp); | ||||
tp = intotcpcb(inp); | tp = intotcpcb(inp); | ||||
KASSERT(tp->t_state == TCPS_SYN_RECEIVED, | KASSERT(tp->t_state == TCPS_SYN_RECEIVED, | ||||
▲ Show 20 Lines • Show All 71 Lines • ▼ Show 20 Lines | tfo_socket_result: | ||||
* TH_PUSH, TH_URG, TH_ECE, TH_CWR are ignored | * TH_PUSH, TH_URG, TH_ECE, TH_CWR are ignored | ||||
* as they do not affect the state of the TCP FSM. | * as they do not affect the state of the TCP FSM. | ||||
* The data pointed to by TH_URG and th_urp is ignored. | * The data pointed to by TH_URG and th_urp is ignored. | ||||
*/ | */ | ||||
KASSERT((thflags & (TH_RST|TH_ACK)) == 0, | KASSERT((thflags & (TH_RST|TH_ACK)) == 0, | ||||
("%s: Listen socket: TH_RST or TH_ACK set", __func__)); | ("%s: Listen socket: TH_RST or TH_ACK set", __func__)); | ||||
KASSERT(thflags & (TH_SYN), | KASSERT(thflags & (TH_SYN), | ||||
("%s: Listen socket: TH_SYN not set", __func__)); | ("%s: Listen socket: TH_SYN not set", __func__)); | ||||
INP_RLOCK_ASSERT(inp); | |||||
#ifdef INET6 | #ifdef INET6 | ||||
/* | /* | ||||
* If deprecated address is forbidden, | * If deprecated address is forbidden, | ||||
* we do not accept SYN to deprecated interface | * we do not accept SYN to deprecated interface | ||||
* address to prevent any new inbound connection from | * address to prevent any new inbound connection from | ||||
* getting established. | * getting established. | ||||
* When we do not accept SYN, we send a TCP RST, | * When we do not accept SYN, we send a TCP RST, | ||||
* with deprecated source address (instead of dropping | * with deprecated source address (instead of dropping | ||||
▲ Show 20 Lines • Show All 152 Lines • ▼ Show 20 Lines | #endif | ||||
tp->t_fb->tfb_tcp_do_segment(m, th, so, tp, drop_hdrlen, tlen, iptos); | tp->t_fb->tfb_tcp_do_segment(m, th, so, tp, drop_hdrlen, tlen, iptos); | ||||
return (IPPROTO_DONE); | return (IPPROTO_DONE); | ||||
dropwithreset: | dropwithreset: | ||||
TCP_PROBE5(receive, NULL, tp, m, tp, th); | TCP_PROBE5(receive, NULL, tp, m, tp, th); | ||||
if (inp != NULL) { | if (inp != NULL) { | ||||
tcp_dropwithreset(m, th, tp, tlen, rstreason); | tcp_dropwithreset(m, th, tp, tlen, rstreason); | ||||
INP_WUNLOCK(inp); | INP_UNLOCK(inp); | ||||
} else | } else | ||||
tcp_dropwithreset(m, th, NULL, tlen, rstreason); | tcp_dropwithreset(m, th, NULL, tlen, rstreason); | ||||
m = NULL; /* mbuf chain got consumed. */ | m = NULL; /* mbuf chain got consumed. */ | ||||
goto drop; | goto drop; | ||||
dropunlock: | dropunlock: | ||||
if (m != NULL) | if (m != NULL) | ||||
TCP_PROBE5(receive, NULL, tp, m, tp, th); | TCP_PROBE5(receive, NULL, tp, m, tp, th); | ||||
if (inp != NULL) | if (inp != NULL) | ||||
INP_WUNLOCK(inp); | INP_UNLOCK(inp); | ||||
drop: | drop: | ||||
INP_INFO_WUNLOCK_ASSERT(&V_tcbinfo); | INP_INFO_WUNLOCK_ASSERT(&V_tcbinfo); | ||||
if (s != NULL) | if (s != NULL) | ||||
free(s, M_TCPLOG); | free(s, M_TCPLOG); | ||||
if (m != NULL) | if (m != NULL) | ||||
m_freem(m); | m_freem(m); | ||||
return (IPPROTO_DONE); | return (IPPROTO_DONE); | ||||
▲ Show 20 Lines • Show All 1,951 Lines • ▼ Show 20 Lines | |||||
#ifdef INET | #ifdef INET | ||||
struct ip *ip; | struct ip *ip; | ||||
#endif | #endif | ||||
#ifdef INET6 | #ifdef INET6 | ||||
struct ip6_hdr *ip6; | struct ip6_hdr *ip6; | ||||
#endif | #endif | ||||
if (tp != NULL) { | if (tp != NULL) { | ||||
INP_WLOCK_ASSERT(tp->t_inpcb); | INP_LOCK_ASSERT(tp->t_inpcb); | ||||
} | } | ||||
/* Don't bother if destination was broadcast/multicast. */ | /* Don't bother if destination was broadcast/multicast. */ | ||||
if ((th->th_flags & TH_RST) || m->m_flags & (M_BCAST|M_MCAST)) | if ((th->th_flags & TH_RST) || m->m_flags & (M_BCAST|M_MCAST)) | ||||
goto drop; | goto drop; | ||||
#ifdef INET6 | #ifdef INET6 | ||||
if (mtod(m, struct ip *)->ip_v == 6) { | if (mtod(m, struct ip *)->ip_v == 6) { | ||||
ip6 = mtod(m, struct ip6_hdr *); | ip6 = mtod(m, struct ip6_hdr *); | ||||
▲ Show 20 Lines • Show All 676 Lines • Show Last 20 Lines |