tcp: Add tcp_validate_incoming & put duplicated code there
authorIlpo Järvinen <ilpo.jarvinen@helsinki.fi>
Sat, 23 Aug 2008 12:10:12 +0000 (05:10 -0700)
committerDavid S. Miller <davem@davemloft.net>
Sat, 23 Aug 2008 12:10:12 +0000 (05:10 -0700)
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>
net/ipv4/tcp_input.c

index 67ccce2..e1b15d4 100644 (file)
@@ -4691,6 +4691,67 @@ out:
 }
 #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 @@ slow_path:
        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) {