Changeset View
Changeset View
Standalone View
Standalone View
sys/netinet/tcp_timewait.c
Show First 20 Lines • Show All 87 Lines • ▼ Show 20 Lines | |||||
#include <netinet/tcpip.h> | #include <netinet/tcpip.h> | ||||
#ifdef TCPDEBUG | #ifdef TCPDEBUG | ||||
#include <netinet/tcp_debug.h> | #include <netinet/tcp_debug.h> | ||||
#endif | #endif | ||||
#ifdef INET6 | #ifdef INET6 | ||||
#include <netinet6/ip6protosw.h> | #include <netinet6/ip6protosw.h> | ||||
#endif | #endif | ||||
#include <netinet/udp.h> | |||||
#include <netinet/udp_var.h> | |||||
#include <machine/in_cksum.h> | #include <machine/in_cksum.h> | ||||
#include <security/mac/mac_framework.h> | #include <security/mac/mac_framework.h> | ||||
VNET_DEFINE_STATIC(uma_zone_t, tcptw_zone); | VNET_DEFINE_STATIC(uma_zone_t, tcptw_zone); | ||||
#define V_tcptw_zone VNET(tcptw_zone) | #define V_tcptw_zone VNET(tcptw_zone) | ||||
static int maxtcptw; | static int maxtcptw; | ||||
▲ Show 20 Lines • Show All 209 Lines • ▼ Show 20 Lines | if ((tp->t_flags & (TF_REQ_TSTMP|TF_RCVD_TSTMP|TF_NOOPT)) == | ||||
tw->t_recent = tp->ts_recent; | tw->t_recent = tp->ts_recent; | ||||
tw->ts_offset = tp->ts_offset; | tw->ts_offset = tp->ts_offset; | ||||
} else { | } else { | ||||
tw->t_recent = 0; | tw->t_recent = 0; | ||||
tw->ts_offset = 0; | tw->ts_offset = 0; | ||||
} | } | ||||
tw->snd_nxt = tp->snd_nxt; | tw->snd_nxt = tp->snd_nxt; | ||||
tw->t_port = tp->t_port; | |||||
tw->rcv_nxt = tp->rcv_nxt; | tw->rcv_nxt = tp->rcv_nxt; | ||||
tw->iss = tp->iss; | tw->iss = tp->iss; | ||||
tw->irs = tp->irs; | tw->irs = tp->irs; | ||||
tw->t_starttime = tp->t_starttime; | tw->t_starttime = tp->t_starttime; | ||||
tw->tw_time = 0; | tw->tw_time = 0; | ||||
/* XXX | /* XXX | ||||
* If this code will | * If this code will | ||||
▲ Show 20 Lines • Show All 102 Lines • ▼ Show 20 Lines | /* PAWS not needed at the moment */ | ||||
*/ | */ | ||||
#endif | #endif | ||||
/* | /* | ||||
* If a new connection request is received | * If a new connection request is received | ||||
* while in TIME_WAIT, drop the old connection | * while in TIME_WAIT, drop the old connection | ||||
* and start over if the sequence numbers | * and start over if the sequence numbers | ||||
* are above the previous ones. | * are above the previous ones. | ||||
* Allow UDP port number changes in this case. | |||||
*/ | */ | ||||
if ((thflags & TH_SYN) && SEQ_GT(th->th_seq, tw->rcv_nxt)) { | if ((thflags & TH_SYN) && SEQ_GT(th->th_seq, tw->rcv_nxt)) { | ||||
tcp_twclose(tw, 0); | tcp_twclose(tw, 0); | ||||
return (1); | return (1); | ||||
} | } | ||||
/* | /* | ||||
* Send RST if UDP port numbers don't match | |||||
*/ | |||||
if (tw->t_port != m->m_pkthdr.tcp_tun_port) { | |||||
if (th->th_flags & TH_ACK) { | |||||
tcp_respond(NULL, mtod(m, void *), th, m, | |||||
(tcp_seq)0, th->th_ack, TH_RST); | |||||
} else { | |||||
if (th->th_flags & TH_SYN) | |||||
tlen++; | |||||
if (th->th_flags & TH_FIN) | |||||
tlen++; | |||||
tcp_respond(NULL, mtod(m, void *), th, m, | |||||
th->th_seq+tlen, (tcp_seq)0, TH_RST|TH_ACK); | |||||
} | |||||
INP_WUNLOCK(inp); | |||||
return (0); | |||||
} | |||||
/* | |||||
* Drop the segment if it does not contain an ACK. | * Drop the segment if it does not contain an ACK. | ||||
*/ | */ | ||||
if ((thflags & TH_ACK) == 0) | if ((thflags & TH_ACK) == 0) | ||||
goto drop; | goto drop; | ||||
/* | /* | ||||
* If timestamps were negotiated during SYN/ACK and a | * If timestamps were negotiated during SYN/ACK and a | ||||
* segment without a timestamp is received, silently drop | * segment without a timestamp is received, silently drop | ||||
▲ Show 20 Lines • Show All 96 Lines • ▼ Show 20 Lines | tcp_twrespond(struct tcptw *tw, int flags) | ||||
struct inpcb *inp = tw->tw_inpcb; | struct inpcb *inp = tw->tw_inpcb; | ||||
#if defined(INET6) || defined(INET) | #if defined(INET6) || defined(INET) | ||||
struct tcphdr *th = NULL; | struct tcphdr *th = NULL; | ||||
#endif | #endif | ||||
struct mbuf *m; | struct mbuf *m; | ||||
#ifdef INET | #ifdef INET | ||||
struct ip *ip = NULL; | struct ip *ip = NULL; | ||||
#endif | #endif | ||||
u_int hdrlen, optlen; | u_int hdrlen, optlen, ulen; | ||||
int error = 0; /* Keep compiler happy */ | int error = 0; /* Keep compiler happy */ | ||||
struct tcpopt to; | struct tcpopt to; | ||||
#ifdef INET6 | #ifdef INET6 | ||||
struct ip6_hdr *ip6 = NULL; | struct ip6_hdr *ip6 = NULL; | ||||
int isipv6 = inp->inp_inc.inc_flags & INC_ISIPV6; | int isipv6 = inp->inp_inc.inc_flags & INC_ISIPV6; | ||||
#endif | #endif | ||||
struct udphdr *udp = NULL; | |||||
hdrlen = 0; /* Keep compiler happy */ | hdrlen = 0; /* Keep compiler happy */ | ||||
INP_WLOCK_ASSERT(inp); | INP_WLOCK_ASSERT(inp); | ||||
m = m_gethdr(M_NOWAIT, MT_DATA); | m = m_gethdr(M_NOWAIT, MT_DATA); | ||||
if (m == NULL) | if (m == NULL) | ||||
return (ENOBUFS); | return (ENOBUFS); | ||||
m->m_data += max_linkhdr; | m->m_data += max_linkhdr; | ||||
#ifdef MAC | #ifdef MAC | ||||
mac_inpcb_create_mbuf(inp, m); | mac_inpcb_create_mbuf(inp, m); | ||||
#endif | #endif | ||||
#ifdef INET6 | #ifdef INET6 | ||||
if (isipv6) { | if (isipv6) { | ||||
hdrlen = sizeof(struct ip6_hdr) + sizeof(struct tcphdr); | hdrlen = sizeof(struct ip6_hdr) + sizeof(struct tcphdr); | ||||
ip6 = mtod(m, struct ip6_hdr *); | ip6 = mtod(m, struct ip6_hdr *); | ||||
if (tw->t_port) { | |||||
udp = (struct udphdr *)(ip6 + 1); | |||||
hdrlen += sizeof(struct udphdr); | |||||
udp->uh_sport = htons(V_tcp_udp_tunneling_port); | |||||
udp->uh_dport = tw->t_port; | |||||
ulen = (hdrlen - sizeof(struct ip6_hdr)); | |||||
th = (struct tcphdr *)(udp + 1); | |||||
} else | |||||
th = (struct tcphdr *)(ip6 + 1); | th = (struct tcphdr *)(ip6 + 1); | ||||
tcpip_fillheaders(inp, ip6, th); | tcpip_fillheaders(inp, tw->t_port, ip6, th); | ||||
} | } | ||||
#endif | #endif | ||||
#if defined(INET6) && defined(INET) | #if defined(INET6) && defined(INET) | ||||
else | else | ||||
#endif | #endif | ||||
#ifdef INET | #ifdef INET | ||||
{ | { | ||||
hdrlen = sizeof(struct tcpiphdr); | hdrlen = sizeof(struct tcpiphdr); | ||||
ip = mtod(m, struct ip *); | ip = mtod(m, struct ip *); | ||||
if (tw->t_port) { | |||||
udp = (struct udphdr *)(ip + 1); | |||||
hdrlen += sizeof(struct udphdr); | |||||
udp->uh_sport = htons(V_tcp_udp_tunneling_port); | |||||
udp->uh_dport = tw->t_port; | |||||
ulen = (hdrlen - sizeof(struct ip)); | |||||
th = (struct tcphdr *)(udp + 1); | |||||
} else | |||||
th = (struct tcphdr *)(ip + 1); | th = (struct tcphdr *)(ip + 1); | ||||
tcpip_fillheaders(inp, ip, th); | tcpip_fillheaders(inp, tw->t_port, ip, th); | ||||
} | } | ||||
#endif | #endif | ||||
to.to_flags = 0; | to.to_flags = 0; | ||||
/* | /* | ||||
* Send a timestamp and echo-reply if both our side and our peer | * Send a timestamp and echo-reply if both our side and our peer | ||||
* have sent timestamps in our SYN's and this is not a RST. | * have sent timestamps in our SYN's and this is not a RST. | ||||
*/ | */ | ||||
if (tw->t_recent && flags == TH_ACK) { | if (tw->t_recent && flags == TH_ACK) { | ||||
to.to_flags |= TOF_TS; | to.to_flags |= TOF_TS; | ||||
to.to_tsval = tcp_ts_getticks() + tw->ts_offset; | to.to_tsval = tcp_ts_getticks() + tw->ts_offset; | ||||
to.to_tsecr = tw->t_recent; | to.to_tsecr = tw->t_recent; | ||||
} | } | ||||
optlen = tcp_addoptions(&to, (u_char *)(th + 1)); | optlen = tcp_addoptions(&to, (u_char *)(th + 1)); | ||||
if (udp) { | |||||
ulen += optlen; | |||||
udp->uh_ulen = htons(ulen); | |||||
} | |||||
m->m_len = hdrlen + optlen; | m->m_len = hdrlen + optlen; | ||||
m->m_pkthdr.len = m->m_len; | m->m_pkthdr.len = m->m_len; | ||||
KASSERT(max_linkhdr + m->m_len <= MHLEN, ("tcptw: mbuf too small")); | KASSERT(max_linkhdr + m->m_len <= MHLEN, ("tcptw: mbuf too small")); | ||||
th->th_seq = htonl(tw->snd_nxt); | th->th_seq = htonl(tw->snd_nxt); | ||||
th->th_ack = htonl(tw->rcv_nxt); | th->th_ack = htonl(tw->rcv_nxt); | ||||
th->th_off = (sizeof(struct tcphdr) + optlen) >> 2; | th->th_off = (sizeof(struct tcphdr) + optlen) >> 2; | ||||
th->th_flags = flags; | th->th_flags = flags; | ||||
th->th_win = htons(tw->last_win); | th->th_win = htons(tw->last_win); | ||||
m->m_pkthdr.csum_data = offsetof(struct tcphdr, th_sum); | |||||
#ifdef INET6 | #ifdef INET6 | ||||
if (isipv6) { | if (isipv6) { | ||||
if (tw->t_port) { | |||||
m->m_pkthdr.csum_flags = CSUM_UDP_IPV6; | |||||
m->m_pkthdr.csum_data = offsetof(struct udphdr, uh_sum); | |||||
udp->uh_sum = in6_cksum_pseudo(ip6, ulen, IPPROTO_UDP, 0); | |||||
th->th_sum = htons(0); | |||||
} else { | |||||
m->m_pkthdr.csum_flags = CSUM_TCP_IPV6; | m->m_pkthdr.csum_flags = CSUM_TCP_IPV6; | ||||
m->m_pkthdr.csum_data = offsetof(struct tcphdr, th_sum); | |||||
th->th_sum = in6_cksum_pseudo(ip6, | th->th_sum = in6_cksum_pseudo(ip6, | ||||
sizeof(struct tcphdr) + optlen, IPPROTO_TCP, 0); | sizeof(struct tcphdr) + optlen, IPPROTO_TCP, 0); | ||||
} | |||||
ip6->ip6_hlim = in6_selecthlim(inp, NULL); | ip6->ip6_hlim = in6_selecthlim(inp, NULL); | ||||
TCP_PROBE5(send, NULL, NULL, ip6, NULL, th); | TCP_PROBE5(send, NULL, NULL, ip6, NULL, th); | ||||
error = ip6_output(m, inp->in6p_outputopts, NULL, | error = ip6_output(m, inp->in6p_outputopts, NULL, | ||||
(tw->tw_so_options & SO_DONTROUTE), NULL, NULL, inp); | (tw->tw_so_options & SO_DONTROUTE), NULL, NULL, inp); | ||||
} | } | ||||
#endif | #endif | ||||
#if defined(INET6) && defined(INET) | #if defined(INET6) && defined(INET) | ||||
else | else | ||||
#endif | #endif | ||||
#ifdef INET | #ifdef INET | ||||
{ | { | ||||
if (tw->t_port) { | |||||
m->m_pkthdr.csum_flags = CSUM_UDP; | |||||
m->m_pkthdr.csum_data = offsetof(struct udphdr, uh_sum); | |||||
udp->uh_sum = in_pseudo(ip->ip_src.s_addr, | |||||
ip->ip_dst.s_addr, htons(ulen + IPPROTO_UDP)); | |||||
th->th_sum = htons(0); | |||||
} else { | |||||
m->m_pkthdr.csum_flags = CSUM_TCP; | m->m_pkthdr.csum_flags = CSUM_TCP; | ||||
m->m_pkthdr.csum_data = offsetof(struct tcphdr, th_sum); | |||||
th->th_sum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr, | th->th_sum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr, | ||||
htons(sizeof(struct tcphdr) + optlen + IPPROTO_TCP)); | htons(sizeof(struct tcphdr) + optlen + IPPROTO_TCP)); | ||||
} | |||||
ip->ip_len = htons(m->m_pkthdr.len); | ip->ip_len = htons(m->m_pkthdr.len); | ||||
if (V_path_mtu_discovery) | if (V_path_mtu_discovery) | ||||
ip->ip_off |= htons(IP_DF); | ip->ip_off |= htons(IP_DF); | ||||
TCP_PROBE5(send, NULL, NULL, ip, NULL, th); | TCP_PROBE5(send, NULL, NULL, ip, NULL, th); | ||||
error = ip_output(m, inp->inp_options, NULL, | error = ip_output(m, inp->inp_options, NULL, | ||||
((tw->tw_so_options & SO_DONTROUTE) ? IP_ROUTETOIF : 0), | ((tw->tw_so_options & SO_DONTROUTE) ? IP_ROUTETOIF : 0), | ||||
NULL, inp); | NULL, inp); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 114 Lines • Show Last 20 Lines |