patch-2.1.68 linux/net/ipv4/tcp_input.c
Next file: linux/net/ipv4/tcp_ipv4.c
Previous file: linux/net/ipv4/tcp.c
Back to the patch index
Back to the overall index
- Lines: 345
- Date:
Sun Nov 30 14:00:39 1997
- Orig file:
v2.1.67/linux/net/ipv4/tcp_input.c
- Orig date:
Thu Sep 4 17:07:32 1997
diff -u --recursive --new-file v2.1.67/linux/net/ipv4/tcp_input.c linux/net/ipv4/tcp_input.c
@@ -5,7 +5,7 @@
*
* Implementation of the Transmission Control Protocol(TCP).
*
- * Version: $Id: tcp_input.c,v 1.56 1997/08/31 08:24:54 freitag Exp $
+ * Version: $Id: tcp_input.c,v 1.64 1997/10/30 23:52:24 davem Exp $
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -64,6 +64,8 @@
#define SYNC_INIT 1
#endif
+extern int sysctl_tcp_fin_timeout;
+
int sysctl_tcp_cong_avoidance;
int sysctl_tcp_hoe_retransmits;
int sysctl_tcp_sack;
@@ -249,7 +251,7 @@
* really.
*/
-static int tcp_reset(struct sock *sk, struct sk_buff *skb)
+static void tcp_reset(struct sock *sk, struct sk_buff *skb)
{
sk->zapped = 1;
@@ -285,8 +287,6 @@
#endif
if (!sk->dead)
sk->state_change(sk);
-
- return(0);
}
/*
@@ -345,15 +345,16 @@
/* Cheaper to set again then to
* test syn. Optimize this?
*/
- if (sysctl_tcp_timestamps && !no_fancy)
+ if (sysctl_tcp_timestamps && !no_fancy) {
tp->tstamp_ok = 1;
- tp->saw_tstamp = 1;
- tp->rcv_tsval = ntohl(*(__u32 *)ptr);
- tp->rcv_tsecr = ntohl(*(__u32 *)(ptr+4));
+ tp->saw_tstamp = 1;
+ tp->rcv_tsval = ntohl(*(__u32 *)ptr);
+ tp->rcv_tsecr = ntohl(*(__u32 *)(ptr+4));
+ }
}
break;
case TCPOPT_SACK:
- if (no_fancy)
+ if (no_fancy || !sysctl_tcp_sack)
break;
tp->sacks = (opsize-2)>>3;
if (tp->sacks<<3 == opsize-2) {
@@ -486,8 +487,10 @@
#define FLAG_WIN_UPDATE 0x02
#define FLAG_DATA_ACKED 0x04
-static __inline__ void clear_fast_retransmit(struct sock *sk) {
+static __inline__ void clear_fast_retransmit(struct sock *sk)
+{
struct tcp_opt *tp=&(sk->tp_pinfo.af_tcp);
+
if (tp->dup_acks > 3) {
tp->retrans_head = NULL;
tp->snd_cwnd = max(tp->snd_ssthresh, 1);
@@ -857,8 +860,7 @@
tcp_ack_probe(sk, ack);
/* See if we can take anything off of the retransmit queue. */
- if (tcp_clean_rtx_queue(sk, ack, &seq, &seq_rtt))
- flag |= FLAG_DATA_ACKED;
+ flag |= tcp_clean_rtx_queue(sk, ack, &seq, &seq_rtt);
/* If we have a timestamp, we always do rtt estimates. */
if (tp->saw_tstamp) {
@@ -879,7 +881,7 @@
}
} else {
tcp_set_rto(tp);
- if (flag && FLAG_DATA_ACKED)
+ if (flag & FLAG_DATA_ACKED)
(*tcp_sys_cong_ctl_f)(sk, seq, ack, seq_rtt);
}
/* NOTE: safe here so long as cong_ctl doesn't use rto */
@@ -973,6 +975,11 @@
{
struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+ if(sk->state == TCP_SYN_SENT) {
+ /* RFC793 says to drop the segment and return. */
+ return 1;
+ }
+
/* XXX This fin_seq thing should disappear... -DaveM */
tp->fin_seq = skb->end_seq;
@@ -985,7 +992,6 @@
switch(sk->state) {
case TCP_SYN_RECV:
- case TCP_SYN_SENT:
case TCP_ESTABLISHED:
/* Move to CLOSE_WAIT */
tcp_set_state(sk, TCP_CLOSE_WAIT);
@@ -999,12 +1005,16 @@
* nothing.
*/
break;
+ case TCP_LAST_ACK:
+ /* RFC793: Remain in the LAST-ACK state. */
+ break;
case TCP_TIME_WAIT:
/* Received a retransmission of the FIN,
* restart the TIME_WAIT timer.
*/
tcp_reset_msl_timer(sk, TIME_CLOSE, TCP_TIMEWAIT_LEN);
- return(0);
+ break;
+
case TCP_FIN_WAIT1:
/* This case occurs when a simultaneous close
* happens, we must ack the received FIN and
@@ -1028,15 +1038,13 @@
/* Already in CLOSE. */
break;
default:
- /* FIXME: Document whats happening in this case. -DaveM */
- tcp_set_state(sk,TCP_LAST_ACK);
-
- /* Start the timers. */
- tcp_reset_msl_timer(sk, TIME_CLOSE, TCP_TIMEWAIT_LEN);
- return(0);
+ /* Only TCP_LISTEN is left, in that case we should never
+ * reach this piece of code.
+ */
+ printk("tcp_fin: Impossible, sk->state=%d\n", sk->state);
+ break;
};
-
- return(0);
+ return 0;
}
/* This one checks to see if we can put data from the
@@ -1337,8 +1345,6 @@
* We do checksum and copy also but from device to kernel.
*/
- tp = &(sk->tp_pinfo.af_tcp);
-
/*
* RFC1323: H1. Apply PAWS check first.
*/
@@ -1373,6 +1379,7 @@
tcp_data_snd_check(sk);
}
+ tcp_statistics.TcpInErrs++;
kfree_skb(skb, FREE_READ);
return 0;
} else if (skb->ack_seq == tp->snd_una) {
@@ -1409,6 +1416,7 @@
if(th->syn && skb->seq != sk->syn_seq) {
SOCK_DEBUG(sk, "syn in established state\n");
+ tcp_statistics.TcpInErrs++;
tcp_reset(sk, skb);
return 1;
}
@@ -1430,7 +1438,7 @@
/* step 8: check the FIN bit */
if (th->fin)
- tcp_fin(skb, sk, th);
+ (void) tcp_fin(skb, sk, th);
tcp_data_snd_check(sk);
tcp_ack_snd_check(sk);
@@ -1449,82 +1457,67 @@
/* Shared between IPv4 and IPv6 now. */
struct sock *
-tcp_check_req(struct sock *sk, struct sk_buff *skb, void *opt)
+tcp_check_req(struct sock *sk, struct sk_buff *skb, struct open_request *req)
{
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);
+ if (req->sk) {
+ /* socket already created but not
+ * yet accepted()...
+ */
+ sk = req->sk;
+ } else {
+ u32 flg;
- flg &= __constant_htonl(0x00170000);
- if ((flg == __constant_htonl(0x00020000)) &&
- (!after(skb->seq, req->rcv_isn))) {
+ /* Check for syn retransmission */
+ flg = *(((u32 *)skb->h.th) + 3);
+
+ flg &= __constant_htonl(0x00170000);
+ /* Only SYN set? */
+ if (flg == __constant_htonl(0x00020000)) {
+ if (!after(skb->seq, req->rcv_isn)) {
/* retransmited syn.
*/
req->class->rtx_syn_ack(sk, req);
return NULL;
+ } else {
+ return sk; /* New SYN */
}
-
- /* 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;
+ /* We know it's an ACK here */
+ /* In theory the packet could be for a cookie, but
+ * TIME_WAIT should guard us against this.
+ * XXX: Nevertheless check for cookies?
+ * This sequence number check is done again later,
+ * but we do it here to prevent syn flood attackers
+ * from creating big SYN_RECV sockets.
+ */
+ if (!between(skb->ack_seq, req->snt_isn, req->snt_isn+1) ||
+ !between(skb->seq, req->rcv_isn,
+ req->rcv_isn+1+req->rcv_wnd)) {
+ req->class->send_reset(skb);
+ return NULL;
}
- }
-#ifdef CONFIG_SYNCOOKIES
- else {
- sk = tp->af_specific->cookie_check(sk, skb, opt);
+
+ sk = tp->af_specific->syn_recv_sock(sk, skb, req, NULL);
+ tcp_dec_slow_timer(TCP_SLT_SYNACK);
if (sk == NULL)
- return NULL;
+ return NULL;
+
+ req->expires = 0UL;
+ req->sk = sk;
}
-#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
@@ -1540,16 +1533,11 @@
/* state == CLOSED, hash lookup always fails, so no worries. -DaveM */
switch (sk->state) {
case TCP_LISTEN:
- 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;
+ if(th->ack)
+ return 1;
if(th->syn) {
if(tp->af_specific->conn_request(sk, skb, opt, 0) < 0)
@@ -1812,6 +1800,8 @@
tcp_set_state(sk, TCP_FIN_WAIT2);
if (!sk->dead)
sk->state_change(sk);
+ else
+ tcp_reset_msl_timer(sk, TIME_CLOSE, sysctl_tcp_fin_timeout);
}
break;
@@ -1870,8 +1860,10 @@
}
/* step 8: check the FIN bit */
- if (th->fin)
- tcp_fin(skb, sk, th);
+ if (th->fin) {
+ if(tcp_fin(skb, sk, th) != 0)
+ goto discard;
+ }
tcp_data_snd_check(sk);
tcp_ack_snd_check(sk);
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov