Changeset View
Changeset View
Standalone View
Standalone View
sys/netinet/tcp_reass.c
Show First 20 Lines • Show All 326 Lines • ▼ Show 20 Lines | |||||
{ | { | ||||
#ifdef TCP_REASS_LOGGING | #ifdef TCP_REASS_LOGGING | ||||
tcp_log_reassm(tp, last, NULL, th->th_seq, tlen, TCP_R_LOG_APPEND, 0); | tcp_log_reassm(tp, last, NULL, th->th_seq, tlen, TCP_R_LOG_APPEND, 0); | ||||
#endif | #endif | ||||
last->tqe_len += tlen; | last->tqe_len += tlen; | ||||
last->tqe_m->m_pkthdr.len += tlen; | last->tqe_m->m_pkthdr.len += tlen; | ||||
/* Preserve the FIN bit if its there */ | /* Preserve the FIN bit if its there */ | ||||
last->tqe_flags |= (th->th_flags & TH_FIN); | last->tqe_flags |= (tcp_get_flags(th) & TH_FIN); | ||||
last->tqe_last->m_next = m; | last->tqe_last->m_next = m; | ||||
last->tqe_last = mlast; | last->tqe_last = mlast; | ||||
last->tqe_mbuf_cnt += lenofoh; | last->tqe_mbuf_cnt += lenofoh; | ||||
tp->t_rcvoopack++; | tp->t_rcvoopack++; | ||||
TCPSTAT_INC(tcps_rcvoopack); | TCPSTAT_INC(tcps_rcvoopack); | ||||
TCPSTAT_ADD(tcps_rcvoobyte, tlen); | TCPSTAT_ADD(tcps_rcvoobyte, tlen); | ||||
#ifdef TCP_REASS_LOGGING | #ifdef TCP_REASS_LOGGING | ||||
tcp_reass_log_new_in(tp, last->tqe_start, lenofoh, last->tqe_m, | tcp_reass_log_new_in(tp, last->tqe_start, lenofoh, last->tqe_m, | ||||
Show All 35 Lines | #ifdef TCP_REASS_LOGGING | ||||
tcp_reass_log_new_in(tp, first->tqe_start, lenofoh, first->tqe_m, | tcp_reass_log_new_in(tp, first->tqe_start, lenofoh, first->tqe_m, | ||||
TCP_R_LOG_PREPEND, | TCP_R_LOG_PREPEND, | ||||
first); | first); | ||||
#endif | #endif | ||||
} | } | ||||
static void | static void | ||||
tcp_reass_replace(struct tcpcb *tp, struct tseg_qent *q, struct mbuf *m, | tcp_reass_replace(struct tcpcb *tp, struct tseg_qent *q, struct mbuf *m, | ||||
tcp_seq seq, int len, struct mbuf *mlast, int mbufoh, uint8_t flags) | tcp_seq seq, int len, struct mbuf *mlast, int mbufoh, uint16_t flags) | ||||
{ | { | ||||
/* | /* | ||||
* Free the data in q, and replace | * Free the data in q, and replace | ||||
* it with the new segment. | * it with the new segment. | ||||
*/ | */ | ||||
int len_dif; | int len_dif; | ||||
#ifdef TCP_REASS_LOGGING | #ifdef TCP_REASS_LOGGING | ||||
▲ Show 20 Lines • Show All 163 Lines • ▼ Show 20 Lines | #ifdef TCP_REASS_LOGGING | ||||
tcp_reass_log_new_in(tp, th->th_seq, *tlenp, m, TCP_R_LOG_ADD, NULL); | tcp_reass_log_new_in(tp, th->th_seq, *tlenp, m, TCP_R_LOG_ADD, NULL); | ||||
#endif | #endif | ||||
#ifdef TCP_REASS_COUNTERS | #ifdef TCP_REASS_COUNTERS | ||||
counter_u64_add(reass_entry, 1); | counter_u64_add(reass_entry, 1); | ||||
#endif | #endif | ||||
/* | /* | ||||
* Check for zero length data. | * Check for zero length data. | ||||
*/ | */ | ||||
if ((*tlenp == 0) && ((th->th_flags & TH_FIN) == 0)) { | if ((*tlenp == 0) && ((tcp_get_flags(th) & TH_FIN) == 0)) { | ||||
/* | /* | ||||
* A zero length segment does no | * A zero length segment does no | ||||
* one any good. We could check | * one any good. We could check | ||||
* the rcv_nxt <-> rcv_wnd but thats | * the rcv_nxt <-> rcv_wnd but thats | ||||
* already done for us by the caller. | * already done for us by the caller. | ||||
*/ | */ | ||||
strip_fin: | strip_fin: | ||||
#ifdef TCP_REASS_COUNTERS | #ifdef TCP_REASS_COUNTERS | ||||
counter_u64_add(tcp_zero_input, 1); | counter_u64_add(tcp_zero_input, 1); | ||||
#endif | #endif | ||||
m_freem(m); | m_freem(m); | ||||
#ifdef TCP_REASS_LOGGING | #ifdef TCP_REASS_LOGGING | ||||
tcp_reass_log_dump(tp); | tcp_reass_log_dump(tp); | ||||
#endif | #endif | ||||
return (0); | return (0); | ||||
} else if ((*tlenp == 0) && | } else if ((*tlenp == 0) && | ||||
(th->th_flags & TH_FIN) && | (tcp_get_flags(th) & TH_FIN) && | ||||
!TCPS_HAVEESTABLISHED(tp->t_state)) { | !TCPS_HAVEESTABLISHED(tp->t_state)) { | ||||
/* | /* | ||||
* We have not established, and we | * We have not established, and we | ||||
* have a FIN and no data. Lets treat | * have a FIN and no data. Lets treat | ||||
* this as the same as if the FIN were | * this as the same as if the FIN were | ||||
* not present. We don't want to save | * not present. We don't want to save | ||||
* the FIN bit in a reassembly buffer | * the FIN bit in a reassembly buffer | ||||
* we want to get established first before | * we want to get established first before | ||||
Show All 30 Lines | #endif | ||||
} | } | ||||
/* | /* | ||||
* First lets deal with two common cases, the | * First lets deal with two common cases, the | ||||
* segment appends to the back of our collected | * segment appends to the back of our collected | ||||
* segments. Or the segment is the next in line. | * segments. Or the segment is the next in line. | ||||
*/ | */ | ||||
last = TAILQ_LAST_FAST(&tp->t_segq, tseg_qent, tqe_q); | last = TAILQ_LAST_FAST(&tp->t_segq, tseg_qent, tqe_q); | ||||
if (last != NULL) { | if (last != NULL) { | ||||
if ((th->th_flags & TH_FIN) && | if ((tcp_get_flags(th) & TH_FIN) && | ||||
SEQ_LT((th->th_seq + *tlenp), (last->tqe_start + last->tqe_len))) { | SEQ_LT((th->th_seq + *tlenp), (last->tqe_start + last->tqe_len))) { | ||||
/* | /* | ||||
* Someone is trying to game us, dump | * Someone is trying to game us, dump | ||||
* the segment. | * the segment. | ||||
*/ | */ | ||||
*tlenp = 0; | *tlenp = 0; | ||||
m_freem(m); | m_freem(m); | ||||
return (0); | return (0); | ||||
▲ Show 20 Lines • Show All 270 Lines • ▼ Show 20 Lines | if (SEQ_GEQ((th->th_seq + *tlenp), (q->tqe_start + q->tqe_len))) { | ||||
* next seg---->+ | * next seg---->+ | ||||
* v | * v | ||||
* reassembly buffer |--| |---| | * reassembly buffer |--| |---| | ||||
* new segment |----------| | * new segment |----------| | ||||
*/ | */ | ||||
#ifdef TCP_REASS_COUNTERS | #ifdef TCP_REASS_COUNTERS | ||||
counter_u64_add(reass_path7, 1); | counter_u64_add(reass_path7, 1); | ||||
#endif | #endif | ||||
tcp_reass_replace(tp, q, m, th->th_seq, *tlenp, mlast, lenofoh, th->th_flags); | tcp_reass_replace(tp, q, m, th->th_seq, *tlenp, mlast, lenofoh, tcp_get_flags(th)); | ||||
} else { | } else { | ||||
/* | /* | ||||
* We just need to prepend the data | * We just need to prepend the data | ||||
* to this. It does not overrun | * to this. It does not overrun | ||||
* the end. | * the end. | ||||
*/ | */ | ||||
/** | /** | ||||
* next seg---->+ | * next seg---->+ | ||||
Show All 32 Lines | #endif | ||||
* XXXLAS: Using sbspace(so->so_rcv) instead of so->so_rcv.sb_hiwat | * XXXLAS: Using sbspace(so->so_rcv) instead of so->so_rcv.sb_hiwat | ||||
* should work but causes packets to be dropped when they shouldn't. | * should work but causes packets to be dropped when they shouldn't. | ||||
* Investigate why and re-evaluate the below limit after the behaviour | * Investigate why and re-evaluate the below limit after the behaviour | ||||
* is understood. | * is understood. | ||||
*/ | */ | ||||
new_entry: | new_entry: | ||||
if (th->th_seq == tp->rcv_nxt && TCPS_HAVEESTABLISHED(tp->t_state)) { | if (th->th_seq == tp->rcv_nxt && TCPS_HAVEESTABLISHED(tp->t_state)) { | ||||
tp->rcv_nxt += *tlenp; | tp->rcv_nxt += *tlenp; | ||||
flags = th->th_flags & TH_FIN; | flags = tcp_get_flags(th) & TH_FIN; | ||||
TCPSTAT_INC(tcps_rcvoopack); | TCPSTAT_INC(tcps_rcvoopack); | ||||
TCPSTAT_ADD(tcps_rcvoobyte, *tlenp); | TCPSTAT_ADD(tcps_rcvoobyte, *tlenp); | ||||
SOCKBUF_LOCK(&so->so_rcv); | SOCKBUF_LOCK(&so->so_rcv); | ||||
if (so->so_rcv.sb_state & SBS_CANTRCVMORE) { | if (so->so_rcv.sb_state & SBS_CANTRCVMORE) { | ||||
m_freem(m); | m_freem(m); | ||||
} else { | } else { | ||||
sbappendstream_locked(&so->so_rcv, m, 0); | sbappendstream_locked(&so->so_rcv, m, 0); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 58 Lines • ▼ Show 20 Lines | if (te == NULL) { | ||||
return (0); | return (0); | ||||
} | } | ||||
tp->t_segqlen++; | tp->t_segqlen++; | ||||
tp->t_rcvoopack++; | tp->t_rcvoopack++; | ||||
TCPSTAT_INC(tcps_rcvoopack); | TCPSTAT_INC(tcps_rcvoopack); | ||||
TCPSTAT_ADD(tcps_rcvoobyte, *tlenp); | TCPSTAT_ADD(tcps_rcvoobyte, *tlenp); | ||||
/* Insert the new segment queue entry into place. */ | /* Insert the new segment queue entry into place. */ | ||||
te->tqe_m = m; | te->tqe_m = m; | ||||
te->tqe_flags = th->th_flags; | te->tqe_flags = tcp_get_flags(th); | ||||
te->tqe_len = *tlenp; | te->tqe_len = *tlenp; | ||||
te->tqe_start = th->th_seq; | te->tqe_start = th->th_seq; | ||||
te->tqe_last = mlast; | te->tqe_last = mlast; | ||||
te->tqe_mbuf_cnt = lenofoh; | te->tqe_mbuf_cnt = lenofoh; | ||||
tp->t_segqmbuflen += te->tqe_mbuf_cnt; | tp->t_segqmbuflen += te->tqe_mbuf_cnt; | ||||
if (p == NULL) { | if (p == NULL) { | ||||
TAILQ_INSERT_HEAD(&tp->t_segq, te, tqe_q); | TAILQ_INSERT_HEAD(&tp->t_segq, te, tqe_q); | ||||
} else { | } else { | ||||
▲ Show 20 Lines • Show All 76 Lines • Show Last 20 Lines |