/*
* INET An implementation of the TCP/IP protocol suite for the LINUX
* operating system. INET is implemented using the BSD Socket
* interface as the means of communication with the user level.
*
* Implementation of the Transmission Control Protocol(TCP).
*
* Version: @(#)tcp.c 1.0.16 05/25/93
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
* Mark Evans, <evansmp@uhura.aston.ac.uk>
* Corey Minyard <wf-rch!minyard@relay.EU.net>
* Florian La Roche, <flla@stud.uni-sb.de>
*
* Fixes:
* Alan Cox : Numerous verify_area() calls
* Alan Cox : Set the ACK bit on a reset
* Alan Cox : Stopped it crashing if it closed while sk->inuse=1
* and was trying to connect (tcp_err()).
* Alan Cox : All icmp error handling was broken
* pointers passed where wrong and the
* socket was looked up backwards. Nobody
* tested any icmp error code obviously.
* Alan Cox : tcp_err() now handled properly. It wakes people
* on errors. select behaves and the icmp error race
* has gone by moving it into sock.c
* Alan Cox : tcp_reset() fixed to work for everything not just
* packets for unknown sockets.
* Alan Cox : tcp option processing.
* Alan Cox : Reset tweaked (still not 100%) [Had syn rule wrong]
* Herp Rosmanith : More reset fixes
* Alan Cox : No longer acks invalid rst frames. Acking
* any kind of RST is right out.
* Alan Cox : Sets an ignore me flag on an rst receive
* otherwise odd bits of prattle escape still
* Alan Cox : Fixed another acking RST frame bug. Should stop
* LAN workplace lockups.
* Alan Cox : Some tidyups using the new skb list facilities
* Alan Cox : sk->keepopen now seems to work
* Alan Cox : Pulls options out correctly on accepts
* Alan Cox : Fixed assorted sk->rqueue->next errors
* Alan Cox : PSH doesn't end a TCP read. Switched a bit to skb ops.
* Alan Cox : Tidied tcp_data to avoid a potential nasty.
* Alan Cox : Added some beter commenting, as the tcp is hard to follow
* Alan Cox : Removed incorrect check for 20 * psh
* Michael O'Reilly : ack < copied bug fix.
* Johannes Stille : Misc tcp fixes (not all in yet).
* Alan Cox : FIN with no memory -> CRASH
* Alan Cox : Added socket option proto entries. Also added awareness of them to accept.
* Alan Cox : Added TCP options (SOL_TCP)
* Alan Cox : Switched wakeup calls to callbacks, so the kernel can layer network sockets.
* Alan Cox : Use ip_tos/ip_ttl settings.
* Alan Cox : Handle FIN (more) properly (we hope).
* Alan Cox : RST frames sent on unsynchronised state ack error/
* Alan Cox : Put in missing check for SYN bit.
* Alan Cox : Added tcp_select_window() aka NET2E
* window non shrink trick.
* Alan Cox : Added a couple of small NET2E timer fixes
* Charles Hedrick : TCP fixes
* Toomas Tamm : TCP window fixes
* Alan Cox : Small URG fix to rlogin ^C ack fight
* Charles Hedrick : Window fix
* Linus : Rewrote tcp_read() and URG handling
* completely
*
*
* To Fix:
* Possibly a problem with accept(). BSD accept never fails after
* it causes a select. Linux can - given the official select semantics I
* feel that _really_ its the BSD network programs that are bust (notably
* inetd, which hangs occasionally because of this).
* Add VJ Fastrecovery algorithm ?
* Protocol closedown badly messed up.
* Incompatiblity with spider ports (tcp hangs on that
* socket occasionally).
* MSG_PEEK and read on same socket at once can cause crashes.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or(at your option) any later version.
*/
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/string.h>
#include <linux/socket.h>
#include <linux/sockios.h>
#include <linux/termios.h>
#include <linux/in.h>
#include <linux/fcntl.h>
#include "inet.h"
#include "dev.h"
#include "ip.h"
#include "protocol.h"
#include "icmp.h"
#include "tcp.h"
#include "skbuff.h"
#include "sock.h"
#include "arp.h"
#include <linux/errno.h>
#include <linux/timer.h>
#include <asm/system.h>
#include <asm/segment.h>
#include <linux/mm.h>
#define SEQ_TICK 3
unsigned long seq_offset;
#define SUBNETSARELOCAL
static __inline__ int
min(unsigned int a, unsigned int b)
{
if (a < b) return(a);
return(b);
}
static void __print_th(struct tcphdr *th)
{
unsigned char *ptr;
printk("TCP header:\n");
printk(" source=%d, dest=%d, seq =%ld, ack_seq = %ld\n",
ntohs(th->source), ntohs(th->dest),
ntohl(th->seq), ntohl(th->ack_seq));
printk(" fin=%d, syn=%d, rst=%d, psh=%d, ack=%d, urg=%d res1=%d res2=%d\n",
th->fin, th->syn, th->rst, th->psh, th->ack,
th->urg, th->res1, th->res2);
printk(" window = %d, check = %d urg_ptr = %d\n",
ntohs(th->window), ntohs(th->check), ntohs(th->urg_ptr));
printk(" doff = %d\n", th->doff);
ptr =(unsigned char *)(th + 1);
printk(" options = %d %d %d %d\n", ptr[0], ptr[1], ptr[2], ptr[3]);
}
static inline void print_th(struct tcphdr *th)
{
if (inet_debug == DBG_TCP)
__print_th(th);
}
/* This routine grabs the first thing off of a rcv queue. */
static struct sk_buff *
get_firstr(struct sock *sk)
{
return skb_dequeue(&sk->rqueue);
}
/*
* Difference between two values in tcp ack terms.
*/
static long
diff(unsigned long seq1, unsigned long seq2)
{
long d;
d = seq1 - seq2;
if (d > 0) return(d);
/* I hope this returns what I want. */
return(~d+1);
}
/* This routine picks a TCP windows for a socket based on
the following constraints
1. The window can never be shrunk once it is offered (RFC 793)
2. We limit memory per socket
For now we use NET2E3's heuristic of offering half the memory
we have handy. All is not as bad as this seems however because
of two things. Firstly we will bin packets even within the window
in order to get the data we are waiting for into the memory limit.
Secondly we bin common duplicate forms at receive time
Better heuristics welcome
*/
static int tcp_select_window(struct sock *sk)
{
int new_window = sk->prot->rspace(sk);
/*
* two things are going on here. First, we don't ever offer a
* window less than min(sk->mss, MAX_WINDOW/2). This is the
* receiver side of SWS as specified in RFC1122.
* Second, we always give them at least the window they
* had before, in order to avoid retracting window. This
* is technically allowed, but RFC1122 advises against it and
* in practice it causes trouble.
*/
if (new_window < min(sk->mss, MAX_WINDOW/2) ||
new_window < sk->window)
return(sk->window);
return(new_window);
}
/* Enter the time wait state. */
static void tcp_time_wait(struct sock *sk)
{
sk->state = TCP_TIME_WAIT;
sk->shutdown = SHUTDOWN_MASK;
if (!sk->dead)
sk->state_change(sk);
reset_timer(sk, TIME_CLOSE, TCP_TIMEWAIT_LEN);
}
/*
* A timer event has trigger a tcp retransmit timeout. The
* socket xmit queue is ready and set up to send. Because
* the ack receive code keeps the queue straight we do
* nothing clever here.
*/
static void
tcp_retransmit(struct sock *sk, int all)
{
if (all) {
ip_retransmit(sk, all);
return;
}
sk->ssthresh = sk->cong_window >> 1; /* remember window where we lost */
/* sk->ssthresh in theory can be zero. I guess that's OK */
sk->cong_count = 0;
sk->cong_window = 1;
/* Do the actual retransmit. */
ip_retransmit(sk, all);
}
/*
* This routine is called by the ICMP module when it gets some
* sort of error condition. If err < 0 then the socket should
* be closed and the error returned to the user. If err > 0
* it's just the icmp type << 8 | icmp code. After adjustment
* header points to the first 8 bytes of the tcp header. We need
* to find the appropriate port.
*/
void
tcp_err(int err, unsigned char *header