]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - net/ipv4/tcp_input.c
tcp: accept RST if SEQ matches right edge of right-most SACK block
[karo-tx-linux.git] / net / ipv4 / tcp_input.c
index d6c8f4cd080001a527f7c137021cc6a3f3604344..89dd8d82826f6e16de784d350d53a636990188f3 100644 (file)
@@ -5159,6 +5159,7 @@ static bool tcp_validate_incoming(struct sock *sk, struct sk_buff *skb,
                                  const struct tcphdr *th, int syn_inerr)
 {
        struct tcp_sock *tp = tcp_sk(sk);
+       bool rst_seq_match = false;
 
        /* RFC1323: H1. Apply PAWS check first. */
        if (tcp_fast_parse_options(skb, th, tp) && tp->rx_opt.saw_tstamp &&
@@ -5195,13 +5196,32 @@ static bool tcp_validate_incoming(struct sock *sk, struct sk_buff *skb,
 
        /* Step 2: check RST bit */
        if (th->rst) {
-               /* RFC 5961 3.2 :
-                * If sequence number exactly matches RCV.NXT, then
+               /* RFC 5961 3.2 (extend to match against SACK too if available):
+                * If seq num matches RCV.NXT or the right-most SACK block,
+                * then
                 *     RESET the connection
                 * else
                 *     Send a challenge ACK
                 */
-               if (TCP_SKB_CB(skb)->seq == tp->rcv_nxt)
+               if (TCP_SKB_CB(skb)->seq == tp->rcv_nxt) {
+                       rst_seq_match = true;
+               } else if (tcp_is_sack(tp) && tp->rx_opt.num_sacks > 0) {
+                       struct tcp_sack_block *sp = &tp->selective_acks[0];
+                       int max_sack = sp[0].end_seq;
+                       int this_sack;
+
+                       for (this_sack = 1; this_sack < tp->rx_opt.num_sacks;
+                            ++this_sack) {
+                               max_sack = after(sp[this_sack].end_seq,
+                                                max_sack) ?
+                                       sp[this_sack].end_seq : max_sack;
+                       }
+
+                       if (TCP_SKB_CB(skb)->seq == max_sack)
+                               rst_seq_match = true;
+               }
+
+               if (rst_seq_match)
                        tcp_reset(sk);
                else
                        tcp_send_challenge_ack(sk, skb);