patch-2.0.34 linux/net/ipv4/tcp_output.c
Next file: linux/net/ipx/af_ipx.c
Previous file: linux/net/ipv4/tcp_input.c
Back to the patch index
Back to the overall index
- Lines: 88
- Date:
Wed Jun 3 15:17:50 1998
- Orig file:
v2.0.33/linux/net/ipv4/tcp_output.c
- Orig date:
Wed Oct 15 14:47:56 1997
diff -u --recursive --new-file v2.0.33/linux/net/ipv4/tcp_output.c linux/net/ipv4/tcp_output.c
@@ -370,7 +370,7 @@
* a packet that contains both old and new data. (Feh!)
* Soooo, we have this uglyness here.
*/
- if (after(sk->rcv_ack_seq,skb->seq+th->syn+th->fin))
+ if (after(sk->rcv_ack_seq,skb->seq+th->syn))
tcp_shrink_skb(sk,skb,sk->rcv_ack_seq);
size = skb->len - (((unsigned char *) th) - skb->data);
@@ -487,6 +487,21 @@
iph = (struct iphdr *)skb->data;
th = (struct tcphdr *)(((char *)iph) + (iph->ihl << 2));
+
+ /* See if we need to shrink the leading packet on
+ * the retransmit queue. Strictly speaking, we
+ * should never need to do this, but some buggy TCP
+ * implementations get confused if you send them
+ * a packet that contains both old and new data. (Feh!)
+ * Soooo, we have this uglyness here.
+ *
+ * Is the && test needed here? If so, then it implies that
+ * we might be retransmitting an acked packet. This code is
+ * needed here to talk to Solaris 2.6 stack.
+ */
+ if (after(sk->rcv_ack_seq,skb->seq+th->syn) && before(sk->rcv_ack_seq, skb->end_seq))
+ tcp_shrink_skb(sk,skb,sk->rcv_ack_seq);
+
size = ntohs(iph->tot_len) - (iph->ihl<<2);
/*
@@ -546,7 +561,7 @@
struct sk_buff *skb2 = sk->write_queue.next;
while (skb2 && skb2->dev == skb->dev) {
skb2->raddr=rt->rt_gateway;
- if (sk->state == TCP_SYN_SENT && sysctl_ip_dynaddr)
+ if (sysctl_ip_dynaddr & 4 || (sk->state == TCP_SYN_SENT && sysctl_ip_dynaddr & 3))
ip_rewrite_addrs (sk, skb2, dev);
skb_pull(skb2,((unsigned char *)skb2->ip_hdr)-skb2->data);
skb2->dev = dev;
@@ -572,7 +587,7 @@
}
}
skb->raddr=rt->rt_gateway;
- if (skb->dev !=dev && sk->state == TCP_SYN_SENT && sysctl_ip_dynaddr)
+ if ((skb->dev !=dev || skb->dev->pa_addr != skb->ip_hdr->saddr) && (sysctl_ip_dynaddr & 4 || (sk->state == TCP_SYN_SENT && sysctl_ip_dynaddr & 3)))
ip_rewrite_addrs(sk, skb, dev);
skb->dev=dev;
skb->arp=1;
@@ -820,6 +835,7 @@
t1->urg = 0;
t1->rst = 0;
t1->psh = 0;
+ t1->fin = 0; /* In case someone sent us a SYN|FIN frame! */
t1->doff = sizeof(*t1)/4;
tcp_send_check(t1, saddr, daddr, sizeof(*t1), buff);
@@ -1398,6 +1414,10 @@
* Needed to deal with buggy TCP implementations that can't deal
* with seeing a packet that contains some data that has already
* been received.
+ *
+ * Note that the SYN sequence number is at the start of the packet
+ * while the FIN is at the end. This means that we always clear out
+ * the SYN bit, and never clear out the FIN bit.
*/
void tcp_shrink_skb(struct sock *sk, struct sk_buff *skb, u32 ack)
{
@@ -1415,9 +1435,9 @@
th = (struct tcphdr *)(((char *)iph) +(iph->ihl << 2));
/* how much data are we droping from the tcp frame */
- diff = ack - skb->seq;
+ diff = ack - (skb->seq + th->syn);
/* how much data are we keeping in the tcp frame */
- len = (skb->end_seq - (th->fin + th->syn)) - ack;
+ len = (skb->end_seq - th->fin) - ack;
/* pointers to new start of remaining data, and old start */
new = (unsigned char *)th + th->doff*4;
@@ -1426,6 +1446,7 @@
/* Update our starting seq number */
skb->seq = ack;
th->seq = htonl(ack);
+ th->syn = 0; /* Turn SYN off as it is logically at the start of the packet */
iph->tot_len = htons(ntohs(iph->tot_len)-diff);
ip_send_check(iph);
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov