mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-23 17:30:02 +00:00
tcp: Add tcp_validate_incoming & put duplicated code there
Large block of code duplication removed. Sadly, the return value thing is a bit tricky here but it seems the most sensible way to return positive from validator on success rather than negative. Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@helsinki.fi> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
23edcc4147
commit
cbe2d128a0
1 changed files with 69 additions and 78 deletions
|
@ -4691,6 +4691,67 @@ static int tcp_dma_try_early_copy(struct sock *sk, struct sk_buff *skb,
|
|||
}
|
||||
#endif /* CONFIG_NET_DMA */
|
||||
|
||||
/* Does PAWS and seqno based validation of an incoming segment, flags will
|
||||
* play significant role here.
|
||||
*/
|
||||
static int tcp_validate_incoming(struct sock *sk, struct sk_buff *skb,
|
||||
struct tcphdr *th, int syn_inerr)
|
||||
{
|
||||
struct tcp_sock *tp = tcp_sk(sk);
|
||||
|
||||
/* RFC1323: H1. Apply PAWS check first. */
|
||||
if (tcp_fast_parse_options(skb, th, tp) && tp->rx_opt.saw_tstamp &&
|
||||
tcp_paws_discard(sk, skb)) {
|
||||
if (!th->rst) {
|
||||
NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_PAWSESTABREJECTED);
|
||||
tcp_send_dupack(sk, skb);
|
||||
goto discard;
|
||||
}
|
||||
/* Reset is accepted even if it did not pass PAWS. */
|
||||
}
|
||||
|
||||
/* Step 1: check sequence number */
|
||||
if (!tcp_sequence(tp, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq)) {
|
||||
/* RFC793, page 37: "In all states except SYN-SENT, all reset
|
||||
* (RST) segments are validated by checking their SEQ-fields."
|
||||
* And page 69: "If an incoming segment is not acceptable,
|
||||
* an acknowledgment should be sent in reply (unless the RST
|
||||
* bit is set, if so drop the segment and return)".
|
||||
*/
|
||||
if (!th->rst)
|
||||
tcp_send_dupack(sk, skb);
|
||||
goto discard;
|
||||
}
|
||||
|
||||
/* Step 2: check RST bit */
|
||||
if (th->rst) {
|
||||
tcp_reset(sk);
|
||||
goto discard;
|
||||
}
|
||||
|
||||
/* ts_recent update must be made after we are sure that the packet
|
||||
* is in window.
|
||||
*/
|
||||
tcp_replace_ts_recent(tp, TCP_SKB_CB(skb)->seq);
|
||||
|
||||
/* step 3: check security and precedence [ignored] */
|
||||
|
||||
/* step 4: Check for a SYN in window. */
|
||||
if (th->syn && !before(TCP_SKB_CB(skb)->seq, tp->rcv_nxt)) {
|
||||
if (syn_inerr)
|
||||
TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_INERRS);
|
||||
NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPABORTONSYN);
|
||||
tcp_reset(sk);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
discard:
|
||||
__kfree_skb(skb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* TCP receive function for the ESTABLISHED state.
|
||||
*
|
||||
|
@ -4718,6 +4779,7 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
|
|||
struct tcphdr *th, unsigned len)
|
||||
{
|
||||
struct tcp_sock *tp = tcp_sk(sk);
|
||||
int res;
|
||||
|
||||
/*
|
||||
* Header prediction.
|
||||
|
@ -4898,52 +4960,13 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
|
|||
if (len < (th->doff << 2) || tcp_checksum_complete_user(sk, skb))
|
||||
goto csum_error;
|
||||
|
||||
/*
|
||||
* RFC1323: H1. Apply PAWS check first.
|
||||
*/
|
||||
if (tcp_fast_parse_options(skb, th, tp) && tp->rx_opt.saw_tstamp &&
|
||||
tcp_paws_discard(sk, skb)) {
|
||||
if (!th->rst) {
|
||||
NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_PAWSESTABREJECTED);
|
||||
tcp_send_dupack(sk, skb);
|
||||
goto discard;
|
||||
}
|
||||
/* Resets are accepted even if PAWS failed.
|
||||
|
||||
ts_recent update must be made after we are sure
|
||||
that the packet is in window.
|
||||
*/
|
||||
}
|
||||
|
||||
/*
|
||||
* Standard slow path.
|
||||
*/
|
||||
|
||||
if (!tcp_sequence(tp, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq)) {
|
||||
/* RFC793, page 37: "In all states except SYN-SENT, all reset
|
||||
* (RST) segments are validated by checking their SEQ-fields."
|
||||
* And page 69: "If an incoming segment is not acceptable,
|
||||
* an acknowledgment should be sent in reply (unless the RST bit
|
||||
* is set, if so drop the segment and return)".
|
||||
*/
|
||||
if (!th->rst)
|
||||
tcp_send_dupack(sk, skb);
|
||||
goto discard;
|
||||
}
|
||||
|
||||
if (th->rst) {
|
||||
tcp_reset(sk);
|
||||
goto discard;
|
||||
}
|
||||
|
||||
tcp_replace_ts_recent(tp, TCP_SKB_CB(skb)->seq);
|
||||
|
||||
if (th->syn && !before(TCP_SKB_CB(skb)->seq, tp->rcv_nxt)) {
|
||||
TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_INERRS);
|
||||
NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPABORTONSYN);
|
||||
tcp_reset(sk);
|
||||
return 1;
|
||||
}
|
||||
res = tcp_validate_incoming(sk, skb, th, 1);
|
||||
if (res <= 0)
|
||||
return -res;
|
||||
|
||||
step5:
|
||||
if (th->ack)
|
||||
|
@ -5225,6 +5248,7 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
|
|||
struct tcp_sock *tp = tcp_sk(sk);
|
||||
struct inet_connection_sock *icsk = inet_csk(sk);
|
||||
int queued = 0;
|
||||
int res;
|
||||
|
||||
tp->rx_opt.saw_tstamp = 0;
|
||||
|
||||
|
@ -5277,42 +5301,9 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (tcp_fast_parse_options(skb, th, tp) && tp->rx_opt.saw_tstamp &&
|
||||
tcp_paws_discard(sk, skb)) {
|
||||
if (!th->rst) {
|
||||
NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_PAWSESTABREJECTED);
|
||||
tcp_send_dupack(sk, skb);
|
||||
goto discard;
|
||||
}
|
||||
/* Reset is accepted even if it did not pass PAWS. */
|
||||
}
|
||||
|
||||
/* step 1: check sequence number */
|
||||
if (!tcp_sequence(tp, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq)) {
|
||||
if (!th->rst)
|
||||
tcp_send_dupack(sk, skb);
|
||||
goto discard;
|
||||
}
|
||||
|
||||
/* step 2: check RST bit */
|
||||
if (th->rst) {
|
||||
tcp_reset(sk);
|
||||
goto discard;
|
||||
}
|
||||
|
||||
tcp_replace_ts_recent(tp, TCP_SKB_CB(skb)->seq);
|
||||
|
||||
/* step 3: check security and precedence [ignored] */
|
||||
|
||||
/* step 4:
|
||||
*
|
||||
* Check for a SYN in window.
|
||||
*/
|
||||
if (th->syn && !before(TCP_SKB_CB(skb)->seq, tp->rcv_nxt)) {
|
||||
NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPABORTONSYN);
|
||||
tcp_reset(sk);
|
||||
return 1;
|
||||
}
|
||||
res = tcp_validate_incoming(sk, skb, th, 0);
|
||||
if (res <= 0)
|
||||
return -res;
|
||||
|
||||
/* step 5: check the ACK field */
|
||||
if (th->ack) {
|
||||
|
|
Loading…
Reference in a new issue