patch-1.3.73 linux/net/ipv4/tcp_input.c
Next file: linux/net/ipv4/tcp_output.c
Previous file: linux/net/ipv4/tcp.c
Back to the patch index
Back to the overall index
- Lines: 295
- Date:
Tue Mar 12 16:39:31 1996
- Orig file:
v1.3.72/linux/net/ipv4/tcp_input.c
- Orig date:
Tue Mar 5 10:11:15 1996
diff -u --recursive --new-file v1.3.72/linux/net/ipv4/tcp_input.c linux/net/ipv4/tcp_input.c
@@ -396,6 +396,7 @@
newsk->send_tail = NULL;
skb_queue_head_init(&newsk->back_log);
newsk->rtt = 0; /*TCP_CONNECT_TIME<<3*/
+ newsk->ato = HZ/3;
newsk->rto = TCP_TIMEOUT_INIT;
newsk->mdev = 0;
newsk->max_window = 0;
@@ -1181,6 +1182,95 @@
return(0);
}
+/*
+ * Called for each packet when we find a new ACK endpoint sequence in it
+ */
+static inline u32 tcp_queue_ack(struct sk_buff * skb, struct sock * sk)
+{
+ /*
+ * When we ack the fin, we do the FIN
+ * processing.
+ */
+ skb->acked = 1;
+ if (skb->h.th->fin)
+ tcp_fin(skb,sk,skb->h.th);
+ return skb->end_seq;
+}
+
+
+/*
+ * Add a sk_buff to the TCP receive queue, calculating
+ * the ACK sequence as we go..
+ */
+static void tcp_queue(struct sk_buff * skb, struct sock * sk,
+ struct tcphdr *th, unsigned long saddr)
+{
+ struct sk_buff_head * list = &sk->receive_queue;
+ struct sk_buff * next;
+ u32 ack_seq;
+
+ /*
+ * Find where the new skb goes.. (This goes backwards,
+ * on the assumption that we get the packets in order)
+ */
+ next = list->prev;
+ while (next != (struct sk_buff *) list) {
+ if (!after(next->seq, skb->seq))
+ break;
+ next = next->prev;
+ }
+ /*
+ * put it after the packet we found (which
+ * may be the list-head, but that's fine).
+ */
+ __skb_append(next, skb, list);
+ next = skb->next;
+
+ /*
+ * Did we get anything new to ack?
+ */
+ ack_seq = sk->acked_seq;
+ if (!after(skb->seq, ack_seq) && after(skb->end_seq, ack_seq)) {
+ ack_seq = tcp_queue_ack(skb, sk);
+
+ /*
+ * Do we have any old packets to ack that the above
+ * made visible? (Go forward from skb)
+ */
+ while (next != (struct sk_buff *) list) {
+ if (after(next->seq, ack_seq))
+ break;
+ if (after(next->end_seq, ack_seq))
+ ack_seq = tcp_queue_ack(next, sk);
+ next = next->next;
+ }
+
+ /*
+ * Ok, we found new data, update acked_seq as
+ * necessary (and possibly send the actual
+ * ACK packet).
+ *
+ * rules for delaying an ack:
+ * - delay time <= 0.5 HZ
+ * - we don't have a window update to send
+ * - must send at least every 2 full sized packets
+ */
+ sk->acked_seq = ack_seq;
+ if (!sk->delay_acks ||
+ /* sk->ack_backlog >= sk->max_ack_backlog || */
+ sk->bytes_rcv > sk->max_unacked || th->fin ||
+ sk->ato > HZ/2) {
+ tcp_send_ack(sk->sent_seq, sk->acked_seq, sk, th, saddr);
+ }
+ else
+ {
+ sk->ack_backlog++;
+ if(sk->debug)
+ printk("Ack queued.\n");
+ tcp_reset_xmit_timer(sk, TIME_WRITE, sk->ato);
+ }
+ }
+}
/*
@@ -1192,9 +1282,7 @@
static int tcp_data(struct sk_buff *skb, struct sock *sk,
unsigned long saddr, unsigned short len)
{
- struct sk_buff *skb1, *skb2;
struct tcphdr *th;
- int dup_dumped=0;
u32 new_seq, shut_seq;
th = skb->h.th;
@@ -1277,170 +1365,7 @@
#endif
- /*
- * Now we have to walk the chain, and figure out where this one
- * goes into it. This is set up so that the last packet we received
- * will be the first one we look at, that way if everything comes
- * in order, there will be no performance loss, and if they come
- * out of order we will be able to fit things in nicely.
- *
- * [AC: This is wrong. We should assume in order first and then walk
- * forwards from the first hole based upon real traffic patterns.]
- *
- */
-
- if (skb_peek(&sk->receive_queue) == NULL) /* Empty queue is easy case */
- {
- skb_queue_head(&sk->receive_queue,skb);
- skb1= NULL;
- }
- else
- {
- for(skb1=sk->receive_queue.prev; ; skb1 = skb1->prev)
- {
- if(sk->debug)
- {
- printk("skb1=%p :", skb1);
- printk("skb1->seq = %d: ", skb1->seq);
- printk("skb->seq = %d\n",skb->seq);
- printk("copied_seq = %d acked_seq = %d\n", sk->copied_seq,
- sk->acked_seq);
- }
-
- /*
- * Optimisation: Duplicate frame or extension of previous frame from
- * same sequence point (lost ack case).
- * The frame contains duplicate data or replaces a previous frame
- * discard the previous frame (safe as sk->users is set) and put
- * the new one in its place.
- */
-
- if (skb->seq==skb1->seq && skb->len>=skb1->len)
- {
- skb_append(skb1,skb);
- skb_unlink(skb1);
- kfree_skb(skb1,FREE_READ);
- dup_dumped=1;
- skb1=NULL;
- break;
- }
-
- /*
- * Found where it fits
- */
-
- if (after(skb->seq+1, skb1->seq))
- {
- skb_append(skb1,skb);
- break;
- }
-
- /*
- * See if we've hit the start. If so insert.
- */
- if (skb1 == skb_peek(&sk->receive_queue))
- {
- skb_queue_head(&sk->receive_queue, skb);
- break;
- }
- }
- }
-
- /*
- * Figure out what the ack value for this frame is
- */
-
- if (before(sk->acked_seq, sk->copied_seq))
- {
- printk("*** tcp.c:tcp_data bug acked < copied\n");
- sk->acked_seq = sk->copied_seq;
- }
-
- /*
- * Now figure out if we can ack anything. This is very messy because we really want two
- * receive queues, a completed and an assembly queue. We also want only one transmit
- * queue.
- */
-
- if ((!dup_dumped && (skb1 == NULL || skb1->acked)) || before(skb->seq, sk->acked_seq+1))
- {
- if (before(skb->seq, sk->acked_seq+1))
- {
-
- if (after(skb->end_seq, sk->acked_seq))
- sk->acked_seq = skb->end_seq;
-
- skb->acked = 1;
-
- /*
- * When we ack the fin, we do the FIN
- * processing.
- */
-
- if (skb->h.th->fin)
- {
- tcp_fin(skb,sk,skb->h.th);
- }
-
- for(skb2 = skb->next;
- skb2 != (struct sk_buff *)&sk->receive_queue;
- skb2 = skb2->next)
- {
- if (before(skb2->seq, sk->acked_seq+1))
- {
- if (after(skb2->end_seq, sk->acked_seq))
- sk->acked_seq = skb2->end_seq;
-
- skb2->acked = 1;
- /*
- * When we ack the fin, we do
- * the fin handling.
- */
- if (skb2->h.th->fin)
- {
- tcp_fin(skb,sk,skb->h.th);
- }
-
- /*
- * Force an immediate ack.
- */
-
- sk->ack_backlog = sk->max_ack_backlog;
- }
- else
- {
- break;
- }
- }
-
- /*
- * This also takes care of updating the window.
- * This if statement needs to be simplified.
- *
- * rules for delaying an ack:
- * - delay time <= 0.5 HZ
- * - we don't have a window update to send
- * - must send at least every 2 full sized packets
- */
- if (!sk->delay_acks ||
- /* sk->ack_backlog >= sk->max_ack_backlog || */
- sk->bytes_rcv > sk->max_unacked || th->fin ||
- sk->ato > HZ/2 ||
- tcp_raise_window(sk)) {
- tcp_send_ack(sk->sent_seq, sk->acked_seq,sk,th, saddr);
- }
- else
- {
- sk->ack_backlog++;
-
- if(sk->debug)
- printk("Ack queued.\n");
-
- tcp_reset_xmit_timer(sk, TIME_WRITE, sk->ato);
-
- }
- }
- }
+ tcp_queue(skb, sk, th, saddr);
/*
* If we've missed a packet, send an ack.
@@ -1459,7 +1384,7 @@
while (sock_rspace(sk) < sk->mtu)
{
- skb1 = skb_peek(&sk->receive_queue);
+ struct sk_buff * skb1 = skb_peek(&sk->receive_queue);
if (skb1 == NULL)
{
printk("INET: tcp.c:tcp_data memory leak detected.\n");
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