TCP/buffering changes

Alan Cox (alan@lxorguk.ukuu.org.uk)
Sun, 4 Aug 96 00:32 BST


*
* Ok Linus this looks like the working diff.
*
* 1. sock_wmalloc/rmalloc allow an allocation to succeed if no
* memory is allocated. Its up to the protocol to handle limits
* gracefully beyond this. At worst we can slightly overcommit
* socket resources beyond those requested.
*
* 2. TCP sleep for memory is fixed
*
* 3. Pedro's eth_copy_csum fix
*
* 4. POSIX 1003.1g compliance oddities while Im fixing tcp
* MSG_PEEK prevents errors being reported (so you can peek
* when there is an error to see whats next, without upsetting
* the error state)
* EINVAL and ECONNABORTED error return fixes.
*
* 5. Fixed the sk->mss == 0 bug reports. sk->mss can be 0 if the
* remote offers us a zero window and we send before the first
* ack opening the window. We don't chop our mss to fit their
* largest window until we see one offered now.
*
* Alan
*
*
diff --unified --new-file --recursive --exclude-from exclude linux.vanilla/net/core/sock.c linux/net/core/sock.c
--- linux.vanilla/net/core/sock.c Sun Jul 28 13:33:17 1996
+++ linux/net/core/sock.c Sat Aug 3 23:23:04 1996
@@ -348,7 +363,7 @@
struct sk_buff *sock_wmalloc(struct sock *sk, unsigned long size, int force, int priority)
{
if (sk) {
- if (force || sk->wmem_alloc + size < sk->sndbuf) {
+ if (force || !sk->wmem_alloc || sk->wmem_alloc + size < sk->sndbuf) {
struct sk_buff * skb = alloc_skb(size, priority);
if (skb)
atomic_add(skb->truesize, &sk->wmem_alloc);
@@ -362,7 +377,7 @@
struct sk_buff *sock_rmalloc(struct sock *sk, unsigned long size, int force, int priority)
{
if (sk) {
- if (force || sk->rmem_alloc + size < sk->rcvbuf) {
+ if (force || !sk->rmem_alloc || sk->rmem_alloc + size < sk->rcvbuf) {
struct sk_buff *skb = alloc_skb(size, priority);
if (skb)
atomic_add(skb->truesize, &sk->rmem_alloc);
diff --unified --new-file --recursive --exclude-from exclude linux.vanilla/net/ethernet/eth.c linux/net/ethernet/eth.c
--- linux.vanilla/net/ethernet/eth.c Sun Jul 28 13:33:18 1996
+++ linux/net/ethernet/eth.c Sat Aug 3 19:18:34 1996
@@ -273,7 +273,7 @@
int ip_length;

IS_SKB(dest);
- eth=(struct ethhdr *)dest->data;
+ eth=(struct ethhdr *)src;
if(eth->h_proto!=htons(ETH_P_IP))
{
memcpy(dest->data,src,length);
diff --unified --new-file --recursive --exclude-from exclude linux.vanilla/net/ipv4/af_inet.c linux/net/ipv4/af_inet.c
--- linux.vanilla/net/ipv4/af_inet.c Sun Jul 28 13:33:18 1996
+++ linux/net/ipv4/af_inet.c Wed Jul 31 18:25:36 1996
@@ -814,7 +814,7 @@

/* check this error. */
if (sk->state != TCP_CLOSE)
- return(-EIO);
+ return(-EINVAL);
if(addr_len<sizeof(struct sockaddr_in))
return -EINVAL;

@@ -1104,6 +1104,12 @@
destroy_sock(sk2);
newsock->data = NULL;
return err;
+ }
+ if (sk2->state == TCP_CLOSE)
+ {
+ destroy_sock(sk2);
+ newsock->data=NULL;
+ return -ECONNABORTED;
}
newsock->state = SS_CONNECTED;
return(0);
diff --unified --new-file --recursive --exclude-from exclude linux.vanilla/net/ipv4/tcp.c linux/net/ipv4/tcp.c
--- linux.vanilla/net/ipv4/tcp.c Sun Jul 28 13:33:19 1996
+++ linux/net/ipv4/tcp.c Sat Aug 3 23:16:42 1996
@@ -856,16 +856,24 @@
lock_sock(sk);
}

+extern __inline int tcp_memory_free(struct sock *sk, int umem)
+{
+ if(!sk->wmem_alloc || sk->wmem_alloc+umem>=sk->sndbuf)
+ return 0;
+ return 1;
+}
+
/*
* Wait for more memory for a socket
*/
-static void wait_for_tcp_memory(struct sock * sk)
+static void wait_for_tcp_memory(struct sock * sk, int umem)
{
release_sock(sk);
cli();
- if (sk->wmem_alloc*2 > sk->sndbuf &&
+ /* THIS LINE HAS TO BE CORRECT AND MATCH SOCK_WMALLOC OR KERBOOM */
+ if ( !tcp_memory_free(sk,umem) &&
(sk->state == TCP_ESTABLISHED||sk->state == TCP_CLOSE_WAIT)
- && sk->err == 0)
+ && sk->err == 0 /* && check shutdown ?? */)
{
sk->socket->flags &= ~SO_NOSPACE;
interruptible_sleep_on(sk->sleep);
@@ -964,16 +972,20 @@
*/
#ifndef CONFIG_NO_PATH_MTU_DISCOVERY
/*
- * FIXME: I'm almost sure that this fragment is BUG,
- * but it works... I do not know why 8) --ANK
- *
* Really, we should rebuild all the queues...
* It's difficult. Temporary hack is to send all
* queued segments with allowed fragmentation.
*/
{
+ /*
+ * new_mss may be zero. That indicates
+ * we don't have a window estimate for
+ * the remote box yet.
+ * -- AC
+ */
+
int new_mss = min(sk->mtu, sk->max_window);
- if (new_mss < sk->mss)
+ if (new_mss && new_mss < sk->mss)
{
tcp_send_partial(sk);
sk->mss = new_mss;
@@ -1095,7 +1107,7 @@
return -ERESTARTSYS;
}

- wait_for_tcp_memory(sk);
+ wait_for_tcp_memory(sk, tmp);
continue;
}

@@ -1428,7 +1440,7 @@
if (copied)
break;

- if (sk->err)
+ if (sk->err && !(flags&MSG_PEEK))
{
copied = sock_error(sk);
break;