summaryrefslogtreecommitdiffstats
path: root/net/ipv4/tcp_input.c
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1997-09-12 01:29:55 +0000
committerRalf Baechle <ralf@linux-mips.org>1997-09-12 01:29:55 +0000
commit545f435ebcfd94a1e7c20b46efe81b4d6ac4e698 (patch)
treee9ce4bc598d06374bda906f18365984bf22a526a /net/ipv4/tcp_input.c
parent4291a610eef89d0d5c69d9a10ee6560e1aa36c74 (diff)
Merge with Linux 2.1.55. More bugfixes and goodies from my private
CVS archive.
Diffstat (limited to 'net/ipv4/tcp_input.c')
-rw-r--r--net/ipv4/tcp_input.c110
1 files changed, 96 insertions, 14 deletions
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 7a6b8f55f..b60eed6f4 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -5,7 +5,7 @@
*
* Implementation of the Transmission Control Protocol(TCP).
*
- * Version: $Id: tcp_input.c,v 1.2 1997/06/17 13:31:29 ralf Exp $
+ * Version: $Id: tcp_input.c,v 1.3 1997/07/20 15:01:55 ralf Exp $
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -39,6 +39,8 @@
* David S. Miller : Don't allow zero congestion window.
* Eric Schenk : Fix retransmitter so that it sends
* next packet on ack of previous packet.
+ * Andi Kleen : Moved open_request checking here
+ * and process RSTs for open_requests.
*/
#include <linux/config.h>
@@ -1319,7 +1321,7 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
int queued = 0;
u32 flg;
-
+
/*
* Header prediction.
* The code follows the one in the famous
@@ -1388,7 +1390,6 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
tcp_send_delayed_ack(sk, HZ/2);
else
tcp_send_ack(sk);
-
return 0;
}
}
@@ -1402,21 +1403,20 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
}
tcp_send_ack(sk);
kfree_skb(skb, FREE_READ);
- return 0;
+ return 0;
}
}
if(th->syn && skb->seq != sk->syn_seq) {
- printk(KERN_DEBUG "syn in established state\n");
+ SOCK_DEBUG(sk, "syn in established state\n");
tcp_reset(sk, skb);
- kfree_skb(skb, FREE_READ);
return 1;
}
if(th->rst) {
tcp_reset(sk,skb);
kfree_skb(skb, FREE_READ);
- return 0;
+ return 0;
}
if(th->ack)
@@ -1443,9 +1443,88 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
if (!queued)
kfree_skb(skb, FREE_READ);
+
return 0;
}
+/* Shared between IPv4 and IPv6 now. */
+struct sock *
+tcp_check_req(struct sock *sk, struct sk_buff *skb, void *opt)
+{
+ struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+ struct open_request *dummy, *req;
+
+ /* assumption: the socket is not in use.
+ * as we checked the user count on tcp_rcv and we're
+ * running from a soft interrupt.
+ */
+ req = tp->af_specific->search_open_req(tp, (void *)skb->nh.raw, skb->h.th,
+ &dummy);
+ if (req) {
+ if (req->sk) {
+ /* socket already created but not
+ * yet accepted()...
+ */
+ sk = req->sk;
+ } else {
+ u32 flg;
+
+ /* Check for syn retransmission */
+ flg = *(((u32 *)skb->h.th) + 3);
+
+ flg &= __constant_htonl(0x00170000);
+ if ((flg == __constant_htonl(0x00020000)) &&
+ (!after(skb->seq, req->rcv_isn))) {
+ /* retransmited syn.
+ */
+ req->class->rtx_syn_ack(sk, req);
+ return NULL;
+ }
+
+ /* In theory the packet could be for a cookie, but
+ * TIME_WAIT should guard us against this.
+ * XXX: Nevertheless check for cookies?
+ */
+ if (skb->ack_seq != req->snt_isn+1) {
+ tp->af_specific->send_reset(skb);
+ return NULL;
+ }
+
+ sk = tp->af_specific->syn_recv_sock(sk, skb, req, NULL);
+ tcp_dec_slow_timer(TCP_SLT_SYNACK);
+ if (sk == NULL)
+ return NULL;
+
+ req->expires = 0UL;
+ req->sk = sk;
+ }
+ }
+#ifdef CONFIG_SYNCOOKIES
+ else {
+ sk = tp->af_specific->cookie_check(sk, skb, opt);
+ if (sk == NULL)
+ return NULL;
+ }
+#endif
+ skb_orphan(skb);
+ skb_set_owner_r(skb, sk);
+ return sk;
+}
+
+
+static void tcp_rst_req(struct tcp_opt *tp, struct sk_buff *skb)
+{
+ struct open_request *req, *prev;
+
+ req = tp->af_specific->search_open_req(tp,skb->nh.iph,skb->h.th,&prev);
+ if (!req)
+ return;
+ /* Sequence number check required by RFC793 */
+ if (before(skb->seq, req->snt_isn) || after(skb->seq, req->snt_isn+1))
+ return;
+ tcp_synq_unlink(tp, req, prev);
+}
+
/*
* This function implements the receiving procedure of RFC 793.
* It's called from both tcp_v4_rcv and tcp_v6_rcv and should be
@@ -1461,14 +1540,16 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
/* state == CLOSED, hash lookup always fails, so no worries. -DaveM */
switch (sk->state) {
case TCP_LISTEN:
- if (th->rst)
+ if (th->rst) {
+ tcp_rst_req(tp, skb);
goto discard;
+ }
/* These use the socket TOS..
* might want to be the received TOS
*/
if(th->ack)
- return 1; /* send reset */
+ return 1;
if(th->syn) {
if(tp->af_specific->conn_request(sk, skb, opt, 0) < 0)
@@ -1490,7 +1571,7 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
* against this problem. So, we drop the data
* in the interest of security over speed.
*/
- return 0;
+ goto discard;
}
goto discard;
@@ -1635,7 +1716,8 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
if(tp->af_specific->conn_request(sk, skb, opt, isn) < 0)
return 1;
- return 0;
+
+ goto discard;
}
break;
@@ -1794,10 +1876,10 @@ step6:
tcp_data_snd_check(sk);
tcp_ack_snd_check(sk);
- if (queued)
- return 0;
+ if (!queued) {
discard:
- kfree_skb(skb, FREE_READ);
+ kfree_skb(skb, FREE_READ);
+ }
return 0;
}