patch-1.3.63 linux/net/ipv4/tcp.c
Next file: linux/net/ipv4/tcp_input.c
Previous file: linux/net/ipv4/af_inet.c
Back to the patch index
Back to the overall index
- Lines: 397
- Date:
Wed Feb 14 09:26:25 1996
- Orig file:
v1.3.62/linux/net/ipv4/tcp.c
- Orig date:
Sun Feb 11 15:32:48 1996
diff -u --recursive --new-file v1.3.62/linux/net/ipv4/tcp.c linux/net/ipv4/tcp.c
@@ -802,14 +802,31 @@
* Modified January 1995 from a go-faster DOS routine by
* Jorge Cwik <jorge@laser.satlink.net>
*/
-
+#undef DEBUG_TCP_CHECK
void tcp_send_check(struct tcphdr *th, unsigned long saddr,
- unsigned long daddr, int len, struct sock *sk)
+ unsigned long daddr, int len, struct sk_buff *skb)
{
+#ifdef DEBUG_TCP_CHECK
+ u16 check;
+#endif
+ th->check = 0;
+ th->check = tcp_check(th, len, saddr, daddr,
+ csum_partial((char *)th,sizeof(*th),skb->csum));
+
+#ifdef DEBUG_TCP_CHECK
+ check = th->check;
th->check = 0;
th->check = tcp_check(th, len, saddr, daddr,
csum_partial((char *)th,len,0));
- return;
+ if (check != th->check) {
+ static int count = 0;
+ if (++count < 10) {
+ printk("Checksum %x (%x) from %p\n", th->check, check,
+ (&th)[-1]);
+ printk("TCP=<off:%d a:%d s:%d f:%d>\n", th->doff*4, th->ack, th->syn, th->fin);
+ }
+ }
+#endif
}
@@ -823,9 +840,6 @@
memcpy(th,(void *) &(sk->dummy_th), sizeof(*th));
th->seq = htonl(sk->write_seq);
th->psh =(push == 0) ? 1 : 0;
- th->doff = sizeof(*th)/4;
- th->ack = 1;
- th->fin = 0;
sk->ack_backlog = 0;
sk->bytes_rcv = 0;
sk->ack_timed = 0;
@@ -1003,30 +1017,29 @@
if ((skb = tcp_dequeue_partial(sk)) != NULL)
{
- int hdrlen;
+ int tcp_size;
- /* IP header + TCP header */
- hdrlen = ((unsigned long)skb->h.th - (unsigned long)skb->data)
- + sizeof(struct tcphdr);
+ tcp_size = skb->tail - (unsigned char *)(skb->h.th + 1);
/* Add more stuff to the end of skb->len */
if (!(flags & MSG_OOB))
{
- copy = min(sk->mss - (skb->len - hdrlen), seglen);
+ copy = min(sk->mss - tcp_size, seglen);
if (copy <= 0)
{
printk("TCP: **bug**: \"copy\" <= 0\n");
return -EFAULT;
- }
+ }
+ tcp_size += copy;
memcpy_fromfs(skb_put(skb,copy), from, copy);
+ skb->csum = csum_partial(skb->tail - tcp_size, tcp_size, 0);
from += copy;
copied += copy;
len -= copy;
sk->write_seq += copy;
seglen -= copy;
}
- if ((skb->len - hdrlen) >= sk->mss ||
- (flags & MSG_OOB) || !sk->packets_out)
+ if (tcp_size >= sk->mss || (flags & MSG_OOB) || !sk->packets_out)
tcp_send_skb(sk, skb);
else
tcp_enqueue_partial(skb, sk);
@@ -1058,6 +1071,11 @@
send_tmp = NULL;
if (copy < sk->mss && !(flags & MSG_OOB) && sk->packets_out)
{
+#if EXTRA_RELEASE
+/*
+ * we don't really need to release even if we sleep: our packets
+ * will be backlogged for us, and that's just fine.
+ */
/*
* We will release the socket in case we sleep here.
*/
@@ -1066,16 +1084,19 @@
* NB: following must be mtu, because mss can be increased.
* mss is always <= mtu
*/
+#endif
skb = sock_wmalloc(sk, sk->mtu + 128 + prot->max_header + 15, 0, GFP_KERNEL);
sk->inuse = 1;
send_tmp = skb;
}
else
{
+#if EXTRA_RELEASE
/*
* We will release the socket in case we sleep here.
*/
release_sock(sk);
+#endif
skb = sock_wmalloc(sk, copy + prot->max_header + 15 , 0, GFP_KERNEL);
sk->inuse = 1;
}
@@ -1156,7 +1177,8 @@
skb->h.th->urg_ptr = ntohs(copy);
}
- memcpy_fromfs(skb_put(skb,copy), from, copy);
+ skb->csum = csum_partial_copy_fromuser(from,
+ skb_put(skb,copy), copy, 0);
from += copy;
copied += copy;
@@ -1240,6 +1262,7 @@
buff->sk = sk;
buff->localroute = sk->localroute;
+ buff->csum = 0;
/*
* Put in the IP header and routing stuff.
@@ -1258,14 +1281,6 @@
memcpy(t1,(void *) &sk->dummy_th, sizeof(*t1));
t1->seq = htonl(sk->sent_seq);
- t1->ack = 1;
- t1->res1 = 0;
- t1->res2 = 0;
- t1->rst = 0;
- t1->urg = 0;
- t1->syn = 0;
- t1->psh = 0;
-
sk->ack_backlog = 0;
sk->bytes_rcv = 0;
@@ -1274,13 +1289,90 @@
t1->window = htons(sk->window);
t1->ack_seq = htonl(sk->acked_seq);
t1->doff = sizeof(*t1)/4;
- tcp_send_check(t1, sk->saddr, sk->daddr, sizeof(*t1), sk);
+ tcp_send_check(t1, sk->saddr, sk->daddr, sizeof(*t1), buff);
sk->prot->queue_xmit(sk, dev, buff, 1);
tcp_statistics.TcpOutSegs++;
}
/*
+ * Handle reading urgent data. BSD has very simple semantics for
+ * this, no blocking and very strange errors 8)
+ */
+
+static int tcp_recv_urg(struct sock * sk, int nonblock,
+ struct msghdr *msg, int len, int flags, int *addr_len)
+{
+ /*
+ * No URG data to read
+ */
+ if (sk->urginline || !sk->urg_data || sk->urg_data == URG_READ)
+ return -EINVAL; /* Yes this is right ! */
+
+ if (sk->err)
+ return sock_error(sk);
+
+ if (sk->state == TCP_CLOSE || sk->done)
+ {
+ if (!sk->done)
+ {
+ sk->done = 1;
+ return 0;
+ }
+ return -ENOTCONN;
+ }
+
+ if (sk->shutdown & RCV_SHUTDOWN)
+ {
+ sk->done = 1;
+ return 0;
+ }
+ sk->inuse = 1;
+ if (sk->urg_data & URG_VALID)
+ {
+ char c = sk->urg_data;
+ if (!(flags & MSG_PEEK))
+ sk->urg_data = URG_READ;
+ memcpy_toiovec(msg->msg_iov, &c, 1);
+ if(msg->msg_name)
+ {
+ struct sockaddr_in *sin=(struct sockaddr_in *)msg->msg_name;
+ sin->sin_family=AF_INET;
+ sin->sin_addr.s_addr=sk->daddr;
+ sin->sin_port=sk->dummy_th.dest;
+ }
+ if(addr_len)
+ *addr_len=sizeof(struct sockaddr_in);
+ release_sock(sk);
+ return 1;
+ }
+ release_sock(sk);
+
+ /*
+ * Fixed the recv(..., MSG_OOB) behaviour. BSD docs and
+ * the available implementations agree in this case:
+ * this call should never block, independent of the
+ * blocking state of the socket.
+ * Mike <pall@rz.uni-karlsruhe.de>
+ */
+ return -EAGAIN;
+}
+
+/*
+ * Release a skb if it is no longer needed. This routine
+ * must be called with interrupts disabled or "sk->inuse = 1"
+ * so that the sk_buff queue operation is ok.
+ */
+
+static inline void tcp_eat_skb(struct sock *sk, struct sk_buff * skb)
+{
+ sk->ack_backlog++;
+ skb->sk = sk;
+ __skb_unlink(skb, &sk->receive_queue);
+ kfree_skb(skb, FREE_READ);
+}
+
+/*
* FIXME:
* This routine frees used buffers.
* It should consider sending an ACK to let the
@@ -1289,37 +1381,20 @@
static void cleanup_rbuf(struct sock *sk)
{
- unsigned long flags;
struct sk_buff *skb;
unsigned long rspace;
- save_flags(flags);
- cli();
-
/*
- * See if we have anything to free up?
+ * NOTE! 'sk->inuse' must be set, so that we don't get
+ * a messed-up receive queue.
*/
-
- skb = skb_peek(&sk->receive_queue);
- if (!skb || !skb->used || skb->users) {
- restore_flags(flags);
- return;
+ while ((skb=skb_peek(&sk->receive_queue)) != NULL) {
+ if (!skb->used || skb->users)
+ break;
+ tcp_eat_skb(sk, skb);
}
/*
- * We have to loop through all the buffer headers,
- * and try to free up all the space we can.
- */
-
- do {
- skb_unlink(skb);
- skb->sk = sk;
- kfree_skb(skb, FREE_READ);
- skb = skb_peek(&sk->receive_queue);
- } while (skb && skb->used && !skb->users);
- restore_flags(flags);
-
- /*
* FIXME:
* At this point we should send an ack if the difference
* in the window, and the amount of space is bigger than
@@ -1339,7 +1414,6 @@
* immediately. Otherwise we will wait up to .5 seconds in case
* the user reads some more.
*/
- sk->ack_backlog++;
/*
* It's unclear whether to use sk->mtu or sk->mss here. They differ only
@@ -1370,70 +1444,6 @@
/*
- * Handle reading urgent data. BSD has very simple semantics for
- * this, no blocking and very strange errors 8)
- */
-
-static int tcp_recv_urg(struct sock * sk, int nonblock,
- struct msghdr *msg, int len, int flags, int *addr_len)
-{
- /*
- * No URG data to read
- */
- if (sk->urginline || !sk->urg_data || sk->urg_data == URG_READ)
- return -EINVAL; /* Yes this is right ! */
-
- if (sk->err)
- return sock_error(sk);
-
- if (sk->state == TCP_CLOSE || sk->done)
- {
- if (!sk->done)
- {
- sk->done = 1;
- return 0;
- }
- return -ENOTCONN;
- }
-
- if (sk->shutdown & RCV_SHUTDOWN)
- {
- sk->done = 1;
- return 0;
- }
- sk->inuse = 1;
- if (sk->urg_data & URG_VALID)
- {
- char c = sk->urg_data;
- if (!(flags & MSG_PEEK))
- sk->urg_data = URG_READ;
- memcpy_toiovec(msg->msg_iov, &c, 1);
- if(msg->msg_name)
- {
- struct sockaddr_in *sin=(struct sockaddr_in *)msg->msg_name;
- sin->sin_family=AF_INET;
- sin->sin_addr.s_addr=sk->daddr;
- sin->sin_port=sk->dummy_th.dest;
- }
- if(addr_len)
- *addr_len=sizeof(struct sockaddr_in);
- release_sock(sk);
- return 1;
- }
- release_sock(sk);
-
- /*
- * Fixed the recv(..., MSG_OOB) behaviour. BSD docs and
- * the available implementations agree in this case:
- * this call should never block, independent of the
- * blocking state of the socket.
- * Mike <pall@rz.uni-karlsruhe.de>
- */
- return -EAGAIN;
-}
-
-
-/*
* This routine copies from a sock struct into the user buffer.
*/
@@ -1637,6 +1647,8 @@
if (flags & MSG_PEEK)
continue;
skb->used = 1;
+ if (!skb->users)
+ tcp_eat_skb(sk, skb);
continue;
found_fin_ok:
@@ -2001,13 +2013,7 @@
buff->end_seq = sk->write_seq;
t1->ack = 0;
t1->window = 2;
- t1->res1=0;
- t1->res2=0;
- t1->rst = 0;
- t1->urg = 0;
- t1->psh = 0;
t1->syn = 1;
- t1->urg_ptr = 0;
t1->doff = 6;
/* use 512 or whatever user asked for */
@@ -2056,8 +2062,9 @@
ptr[1] = 4;
ptr[2] = (sk->mtu) >> 8;
ptr[3] = (sk->mtu) & 0xff;
+ buff->csum = csum_partial(ptr, 4, 0);
tcp_send_check(t1, sk->saddr, sk->daddr,
- sizeof(struct tcphdr) + 4, sk);
+ sizeof(struct tcphdr) + 4, buff);
/*
* This must go first otherwise a really quick response will get reset.
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov
with Sam's (original) version of this