ipvs: Use kthread_run() instead of doing a double-fork via kernel_thread()
[safe/jmp/linux-2.6] / net / ipv4 / tcp.c
index 2cbfa6d..56a133c 100644 (file)
@@ -5,8 +5,6 @@
  *
  *             Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:    $Id: tcp.c,v 1.216 2002/02/01 22:01:04 davem Exp $
- *
  * Authors:    Ross Biro
  *             Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
  *             Mark Evans, <evansmp@uhura.aston.ac.uk>
 #include <linux/init.h>
 #include <linux/fs.h>
 #include <linux/skbuff.h>
+#include <linux/scatterlist.h>
 #include <linux/splice.h>
 #include <linux/net.h>
 #include <linux/socket.h>
 #include <linux/random.h>
 #include <linux/bootmem.h>
+#include <linux/highmem.h>
+#include <linux/swap.h>
 #include <linux/cache.h>
 #include <linux/err.h>
 #include <linux/crypto.h>
@@ -497,7 +498,6 @@ static inline void tcp_mark_urg(struct tcp_sock *tp, int flags,
        if (flags & MSG_OOB) {
                tp->urg_mode = 1;
                tp->snd_up = tp->write_seq;
-               TCP_SKB_CB(skb)->sacked |= TCPCB_URG;
        }
 }
 
@@ -736,7 +736,7 @@ new_segment:
                if (!(psize -= copy))
                        goto out;
 
-               if (skb->len < mss_now || (flags & MSG_OOB))
+               if (skb->len < size_goal || (flags & MSG_OOB))
                        continue;
 
                if (forced_push(tp)) {
@@ -982,7 +982,7 @@ new_segment:
                        if ((seglen -= copy) == 0 && iovlen == 0)
                                goto out;
 
-                       if (skb->len < mss_now || (flags & MSG_OOB))
+                       if (skb->len < size_goal || (flags & MSG_OOB))
                                continue;
 
                        if (forced_push(tp)) {
@@ -1207,7 +1207,8 @@ int tcp_read_sock(struct sock *sk, read_descriptor_t *desc,
                return -ENOTCONN;
        while ((skb = tcp_recv_skb(sk, seq, &offset)) != NULL) {
                if (offset < skb->len) {
-                       size_t used, len;
+                       int used;
+                       size_t len;
 
                        len = skb->len - offset;
                        /* Stop reading if we hit a patch of urgent data */
@@ -1228,7 +1229,14 @@ int tcp_read_sock(struct sock *sk, read_descriptor_t *desc,
                                copied += used;
                                offset += used;
                        }
-                       if (offset != skb->len)
+                       /*
+                        * If recv_actor drops the lock (e.g. TCP splice
+                        * receive) the skb pointer might be invalid when
+                        * getting here: tcp_collapse might have deleted it
+                        * while aggregating skbs from the socket queue.
+                        */
+                       skb = tcp_recv_skb(sk, seq-1, &offset);
+                       if (!skb || (offset+1 != skb->len))
                                break;
                }
                if (tcp_hdr(skb)->fin) {
@@ -1653,6 +1661,41 @@ recv_urg:
        goto out;
 }
 
+void tcp_set_state(struct sock *sk, int state)
+{
+       int oldstate = sk->sk_state;
+
+       switch (state) {
+       case TCP_ESTABLISHED:
+               if (oldstate != TCP_ESTABLISHED)
+                       TCP_INC_STATS(TCP_MIB_CURRESTAB);
+               break;
+
+       case TCP_CLOSE:
+               if (oldstate == TCP_CLOSE_WAIT || oldstate == TCP_ESTABLISHED)
+                       TCP_INC_STATS(TCP_MIB_ESTABRESETS);
+
+               sk->sk_prot->unhash(sk);
+               if (inet_csk(sk)->icsk_bind_hash &&
+                   !(sk->sk_userlocks & SOCK_BINDPORT_LOCK))
+                       inet_put_port(sk);
+               /* fall through */
+       default:
+               if (oldstate==TCP_ESTABLISHED)
+                       TCP_DEC_STATS(TCP_MIB_CURRESTAB);
+       }
+
+       /* Change state AFTER socket is unhashed to avoid closed
+        * socket sitting in hash tables.
+        */
+       sk->sk_state = state;
+
+#ifdef STATE_TRACE
+       SOCK_DEBUG(sk, "TCP sk=%p, State %s -> %s\n",sk, statename[oldstate],statename[state]);
+#endif
+}
+EXPORT_SYMBOL_GPL(tcp_set_state);
+
 /*
  *     State processing on a close. This implements the state shift for
  *     sending our FIN frame. Note that we only send a FIN for some
@@ -1688,7 +1731,7 @@ static int tcp_close_state(struct sock *sk)
 
 /*
  *     Shutdown the sending side of a connection. Much like close except
- *     that we don't receive shut down or set_sock_flag(sk, SOCK_DEAD).
+ *     that we don't receive shut down or sock_set_flag(sk, SOCK_DEAD).
  */
 
 void tcp_shutdown(struct sock *sk, int how)
@@ -2422,6 +2465,76 @@ static unsigned long tcp_md5sig_users;
 static struct tcp_md5sig_pool **tcp_md5sig_pool;
 static DEFINE_SPINLOCK(tcp_md5sig_pool_lock);
 
+int tcp_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key,
+                     int bplen,
+                     struct tcphdr *th, unsigned int tcplen,
+                     struct tcp_md5sig_pool *hp)
+{
+       struct scatterlist sg[4];
+       __u16 data_len;
+       int block = 0;
+       __sum16 cksum;
+       struct hash_desc *desc = &hp->md5_desc;
+       int err;
+       unsigned int nbytes = 0;
+
+       sg_init_table(sg, 4);
+
+       /* 1. The TCP pseudo-header */
+       sg_set_buf(&sg[block++], &hp->md5_blk, bplen);
+       nbytes += bplen;
+
+       /* 2. The TCP header, excluding options, and assuming a
+        * checksum of zero
+        */
+       cksum = th->check;
+       th->check = 0;
+       sg_set_buf(&sg[block++], th, sizeof(*th));
+       nbytes += sizeof(*th);
+
+       /* 3. The TCP segment data (if any) */
+       data_len = tcplen - (th->doff << 2);
+       if (data_len > 0) {
+               u8 *data = (u8 *)th + (th->doff << 2);
+               sg_set_buf(&sg[block++], data, data_len);
+               nbytes += data_len;
+       }
+
+       /* 4. an independently-specified key or password, known to both
+        * TCPs and presumably connection-specific
+        */
+       sg_set_buf(&sg[block++], key->key, key->keylen);
+       nbytes += key->keylen;
+
+       sg_mark_end(&sg[block - 1]);
+
+       /* Now store the hash into the packet */
+       err = crypto_hash_init(desc);
+       if (err) {
+               if (net_ratelimit())
+                       printk(KERN_WARNING "%s(): hash_init failed\n", __func__);
+               return -1;
+       }
+       err = crypto_hash_update(desc, sg, nbytes);
+       if (err) {
+               if (net_ratelimit())
+                       printk(KERN_WARNING "%s(): hash_update failed\n", __func__);
+               return -1;
+       }
+       err = crypto_hash_final(desc, md5_hash);
+       if (err) {
+               if (net_ratelimit())
+                       printk(KERN_WARNING "%s(): hash_final failed\n", __func__);
+               return -1;
+       }
+
+       /* Reset header */
+       th->check = cksum;
+
+       return 0;
+}
+EXPORT_SYMBOL(tcp_calc_md5_hash);
+
 static void __tcp_free_md5sig_pool(struct tcp_md5sig_pool **pool)
 {
        int cpu;
@@ -2579,7 +2692,7 @@ __setup("thash_entries=", set_thash_entries);
 void __init tcp_init(void)
 {
        struct sk_buff *skb = NULL;
-       unsigned long limit;
+       unsigned long nr_pages, limit;
        int order, i, max_share;
 
        BUILD_BUG_ON(sizeof(struct tcp_skb_cb) > sizeof(skb->cb));
@@ -2648,8 +2761,9 @@ void __init tcp_init(void)
         * is up to 1/2 at 256 MB, decreasing toward zero with the amount of
         * memory, with a floor of 128 pages.
         */
-       limit = min(nr_all_pages, 1UL<<(28-PAGE_SHIFT)) >> (20-PAGE_SHIFT);
-       limit = (limit * (nr_all_pages >> (20-PAGE_SHIFT))) >> (PAGE_SHIFT-11);
+       nr_pages = totalram_pages - totalhigh_pages;
+       limit = min(nr_pages, 1UL<<(28-PAGE_SHIFT)) >> (20-PAGE_SHIFT);
+       limit = (limit * (nr_pages >> (20-PAGE_SHIFT))) >> (PAGE_SHIFT-11);
        limit = max(limit, 128UL);
        sysctl_tcp_mem[0] = limit / 4 * 3;
        sysctl_tcp_mem[1] = limit;