## diffname port/tcpoutput.c 1991/0424
## diff -e /dev/null /n/bootesdump/1991/0424/sys/src/9/port/tcpoutput.c
0a
#include "u.h"
#include "lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "errno.h"
#include "arp.h"
#include "ipdat.h"
extern int tcpdbg;
extern ushort tcp_mss;
extern Queue *Tcpoutput;
#define DPRINT if(tcpdbg) print
void
tcp_output(Ipconv *s)
{
Block *hbp,*dbp, *sndq;
ushort ssize, dsize, usable, sent, oobsent;
int qlen;
char doing_oob;
Tcphdr ph;
Tcp seg;
Tcpctl *tcb;
tcb = &s->tcpctl;
switch(tcb->state) {
case LISTEN:
case CLOSED:
return;
}
for(;;){
if (tcb->sndoobq) {
/* We have pending out-of-band data - use it */
qlen = tcb->sndoobcnt;
oobsent = tcb->snd.ptr - tcb->snd.up;
if (oobsent >= qlen) {
oobsent = qlen;
goto normal;
}
sndq = tcb->sndoobq;
sent = oobsent;
doing_oob = 1;
DPRINT("tcp_out: oob: qlen = %lux sent = %lux\n",
qlen, sent);
} else {
oobsent = 0;
normal:
qlen = tcb->sndcnt;
sent = tcb->snd.ptr - tcb->snd.una - oobsent;
sndq = tcb->sndq;
doing_oob = 0;
DPRINT("tcp_out: norm: qlen = %lux sent = %lux\n", qlen, sent);
}
/* Don't send anything else until our SYN has been acked */
if(sent != 0 && !(tcb->flags & SYNACK))
break;
if(tcb->snd.wnd == 0){
/* Allow only one closed-window probe at a time */
if(sent != 0)
break;
/* Force a closed-window probe */
usable = 1;
} else {
/* usable window = offered window - unacked bytes in transit
* limited by the congestion window
*/
usable = MIN(tcb->snd.wnd,tcb->cwind) - sent;
if(sent != 0 && qlen - sent < tcb->mss)
usable = 0;
}
ssize = MIN(qlen - sent, usable);
ssize = MIN(ssize, tcb->mss);
dsize = ssize;
if (!doing_oob)
seg.up = 0;
else {
seg.up = ssize;
DPRINT("tcp_out: oob seg.up = %d\n", seg.up);
}
DPRINT("tcp_out: ssize = %lux\n", ssize);
if(ssize == 0 && !(tcb->flags & FORCE))
break;
/* Stop ack timer if one will be piggy backed on data */
stop_timer(&tcb->acktimer);
tcb->flags &= ~FORCE;
seg.source = s->psrc;
seg.dest = s->pdst;
/* Every state except SYN_SENT */
seg.flags = ACK;
seg.mss = 0;
switch(tcb->state){
case SYN_SENT:
seg.flags = 0;
/* No break */
case SYN_RECEIVED:
if(tcb->snd.ptr == tcb->iss){
seg.flags |= SYN;
dsize--;
/* Also send MSS */
seg.mss = tcp_mss;
}
break;
}
seg.seq = tcb->snd.ptr;
seg.ack = tcb->last_ack = tcb->rcv.nxt;
seg.wnd = tcb->rcv.wnd;
if (doing_oob) {
DPRINT("tcp_out: Setting URG (up = %u)\n", seg.up);
seg.flags |= URG;
}
/* Now try to extract some data from the send queue.
* Since SYN and FIN occupy sequence space and are reflected
* in sndcnt but don't actually sit in the send queue,
* dupb will return one less than dsize if a FIN needs to be sent.
*/
if(dsize != 0){
if(dupb(&dbp, sndq, sent, dsize) != dsize) {
seg.flags |= FIN;
dsize--;
}
DPRINT("dupb: 1st char = %c\n", dbp->rptr[0]);
} else
dbp = 0;
/* If the entire send queue will now be in the pipe, set the
* push flag
*/
if((dsize != 0) &&
((sent + ssize) == (tcb->rcvcnt + tcb->rcvoobcnt)))
seg.flags |= PSH;
/* If this transmission includes previously transmitted data,
* snd.nxt will already be past snd.ptr. In this case,
* compute the amount of retransmitted data and keep score
*/
if(tcb->snd.ptr < tcb->snd.nxt)
tcb->resent += MIN((int)tcb->snd.nxt - (int)tcb->snd.ptr,(int)ssize);
tcb->snd.ptr += ssize;
/* If this is the first transmission of a range of sequence
* numbers, record it so we'll accept acknowledgments
* for it later
*/
if(seq_gt(tcb->snd.ptr,tcb->snd.nxt))
tcb->snd.nxt = tcb->snd.ptr;
/* Fill in fields of pseudo IP header */
hnputl(ph.tcpdst, s->dst);
hnputl(ph.tcpsrc, Myip);
hnputs(ph.tcpsport, s->psrc);
hnputs(ph.tcpdport, s->pdst);
/* Build header, link data and compute cksum */
if((hbp = htontcp(&seg, dbp, &ph)) == 0) {
freeb(dbp);
return;
}
/* If we're sending some data or flags, start retransmission
* and round trip timers if they aren't already running.
*/
if(ssize != 0){
tcb->timer.start = backoff(tcb->backoff) *
(2 * tcb->mdev + tcb->srtt + MSPTICK) / MSPTICK;
if(!run_timer(&tcb->timer))
start_timer(&tcb->timer);
/* If round trip timer isn't running, start it */
if(!run_timer(&tcb->rtt_timer)){
start_timer(&tcb->rtt_timer);
tcb->rttseq = tcb->snd.ptr;
}
}
DPRINT("tcp_output: ip_send s%lux a%lux w%lux u%lux\n",
seg.seq, seg.ack, seg.wnd, seg.up);
PUTNEXT(Tcpoutput, hbp);
}
}
int tcptimertype = 0;
void
tcp_timeout(void *arg)
{
Tcpctl *tcb;
Ipconv *s;
s = (Ipconv *)arg;
tcb = &s->tcpctl;
DPRINT("Timer %lux state = %d\n", s, tcb->state);
switch(tcb->state){
case CLOSED:
panic("tcptimeout");
case TIME_WAIT:
close_self(s, 0);
break;
case ESTABLISHED:
if(tcb->backoff < MAXBACKOFF)
tcb->backoff++;
goto retran;
default:
tcb->backoff++;
DPRINT("tcp_timeout: retransmit %d %x\n", tcb->backoff, s);
if (tcb->backoff >= MAXBACKOFF) {
DPRINT("tcp_timeout: timeout\n");
close_self(s, Etimedout);
}
else {
retran:
qlock(tcb);
tcb->flags |= RETRAN|FORCE;
tcb->snd.ptr = tcb->snd.una;
/* Reduce slowstart threshold to half current window */
tcb->ssthresh = tcb->cwind / 2;
tcb->ssthresh = MAX(tcb->ssthresh,tcb->mss);
/* Shrink congestion window to 1 packet */
tcb->cwind = tcb->mss;
tcp_output(s);
qunlock(tcb);
}
}
}
int
backoff(int n)
{
if(tcptimertype == 1)
return n+1;
else {
if(n <= 4)
return 1 << n;
else
return n * n;
}
}
void
tcp_acktimer(Ipconv *s)
{
Tcpctl *tcb = &s->tcpctl;
qlock(tcb);
tcb->flags |= FORCE;
tcprcvwin(s);
tcp_output(s);
qunlock(tcb);
}
void
tcprcvwin(Ipconv *s)
{
Tcpctl *tcb = &s->tcpctl;
/* Calculate new window */
if(s->readq) {
tcb->rcv.wnd = Streamhi - s->readq->next->len;
if(tcb->rcv.wnd < 0)
tcb->rcv.wnd = 0;
}
else
tcb->rcv.wnd = Streamhi;
}
.
## diffname port/tcpoutput.c 1991/0425
## diff -e /n/bootesdump/1991/0424/sys/src/9/port/tcpoutput.c /n/bootesdump/1991/0425/sys/src/9/port/tcpoutput.c
95a
tcprcvwin(s);
.
## diffname port/tcpoutput.c 1991/0723
## diff -e /n/bootesdump/1991/0425/sys/src/9/port/tcpoutput.c /n/bootesdump/1991/0723/sys/src/9/port/tcpoutput.c
284a
/*
* Network byte order functions
*/
void
hnputs(uchar *ptr, ushort val)
{
ptr[0] = val>>8;
ptr[1] = val;
}
void
hnputl(uchar *ptr, ulong val)
{
ptr[0] = val>>24;
ptr[1] = val>>16;
ptr[2] = val>>8;
ptr[3] = val;
}
ulong
nhgetl(uchar *ptr)
{
return ((ptr[0]<<24) | (ptr[1]<<16) | (ptr[2]<<8) | ptr[3]);
}
ushort
nhgets(uchar *ptr)
{
return ((ptr[0]<<8) | ptr[1]);
}
.
## diffname port/tcpoutput.c 1991/1019
## diff -e /n/bootesdump/1991/0723/sys/src/9/port/tcpoutput.c /n/bootesdump/1991/1019/sys/src/9/port/tcpoutput.c
196,197d
193c
PUTNEXT(Ipoutput, hbp);
.
13a
.
12c
int tcptimertype = 0;
.
## diffname port/tcpoutput.c 1991/1030
## diff -e /n/bootesdump/1991/1019/sys/src/9/port/tcpoutput.c /n/bootesdump/1991/1030/sys/src/9/port/tcpoutput.c
262c
print("Acktimer!\n");
.
122,126d
113d
90c
if(ssize == 0 && (tcb->flags & FORCE) == 0)
.
82,88d
80a
seg.up = 0;
.
36,57c
qlen = tcb->sndcnt;
sent = tcb->snd.ptr - tcb->snd.una;
sndq = tcb->sndq;
.
34a
.
23d
21c
ushort ssize, dsize, usable, sent;
.
14,16d
10a
#define DPRINT if(tcpdbg) print
.
## diffname port/tcpoutput.c 1991/1101
## diff -e /n/bootesdump/1991/1030/sys/src/9/port/tcpoutput.c /n/bootesdump/1991/1101/sys/src/9/port/tcpoutput.c
229c
.
## diffname port/tcpoutput.c 1991/1126
## diff -e /n/bootesdump/1991/1101/sys/src/9/port/tcpoutput.c /n/bootesdump/1991/1126/sys/src/9/port/tcpoutput.c
111,112c
if(sent+dsize == qlen)
.
## diffname port/tcpoutput.c 1991/12171
## diff -e /n/bootesdump/1991/1126/sys/src/9/port/tcpoutput.c /n/bootesdump/1991/12171/sys/src/9/port/tcpoutput.c
181c
case Established:
.
178c
case Time_wait:
.
176c
case Closed:
.
82c
case Syn_received:
.
79c
case Syn_sent:
.
28,29c
case Listen:
case Closed:
.
## diffname port/tcpoutput.c 1992/0111
## diff -e /n/bootesdump/1991/12171/sys/src/9/port/tcpoutput.c /n/bootesdump/1992/0111/sys/src/9/port/tcpoutput.c
6c
#include "../port/error.h"
.
## diffname port/tcpoutput.c 1992/0213
## diff -e /n/bootesdump/1992/0111/sys/src/9/port/tcpoutput.c /n/bootesdump/1992/0213/sys/src/9/port/tcpoutput.c
132c
hnputl(ph.tcpsrc, Myip[Myself]);
.
## diffname port/tcpoutput.c 1992/0223
## diff -e /n/bootesdump/1992/0213/sys/src/9/port/tcpoutput.c /n/bootesdump/1992/0223/sys/src/9/port/tcpoutput.c
248a
qunlock(s);
.
241a
qlock(s);
.
## diffname port/tcpoutput.c 1992/0313
## diff -e /n/bootesdump/1992/0223/sys/src/9/port/tcpoutput.c /n/bootesdump/1992/0313/sys/src/9/port/tcpoutput.c
180a
.
177a
.
63c
if(ssize == 0)
if((tcb->flags & FORCE) == 0)
.
53c
if(sent != 0)
if(qlen - sent < tcb->mss)
.
39c
if(sent != 0)
if((tcb->flags & SYNACK) == 0)
.
## diffname port/tcpoutput.c 1992/0319
## diff -e /n/bootesdump/1992/0313/sys/src/9/port/tcpoutput.c /n/bootesdump/1992/0319/sys/src/9/port/tcpoutput.c
242c
tcprcvwin(Ipconv *s) /* Call with tcb locked */
.
189,212c
tcprxmit(s);
break;
.
179,180c
default:
tcb->backoff++;
DPRINT("tcp_timeout: retransmit %d %x\n", tcb->backoff, s);
if (tcb->backoff >= MAXBACKOFF)
close_self(s, Etimedout);
else
tcprxmit(s);
break;
.
176c
print("Timer %lux state = %d\n", s, tcb->state);
.
167a
tcprxmit(Ipconv *s)
{
Tcpctl *tcb;
print("tcp! rexmit\n");
tcb = &s->tcpctl;
qlock(tcb);
tcb->flags |= RETRAN|FORCE;
tcb->snd.ptr = tcb->snd.una;
/* Reduce slowstart threshold to half current window */
tcb->ssthresh = tcb->cwind / 2;
tcb->ssthresh = MAX(tcb->ssthresh,tcb->mss);
/* Shrink congestion window to 1 packet */
tcb->cwind = tcb->mss;
tcp_output(s);
qunlock(tcb);
}
void
.
160,162c
print("snd: %d %x\n", blen(hbp), seg.seq);
.
111,113d
107,109c
print("dupb: %d\n", dbp->rptr[0]);
}
.
101a
dbp = 0;
.
## diffname port/tcpoutput.c 1992/0320
## diff -e /n/bootesdump/1992/0319/sys/src/9/port/tcpoutput.c /n/bootesdump/1992/0320/sys/src/9/port/tcpoutput.c
206,211d
197d
192,193d
167d
157d
108c
DPRINT("dupb: %d\n", dbp->rptr[0]);
.
66c
if((tcb->flags&FORCE) == 0)
.
## diffname port/tcpoutput.c 1992/0321
## diff -e /n/bootesdump/1992/0320/sys/src/9/port/tcpoutput.c /n/bootesdump/1992/0321/sys/src/9/port/tcpoutput.c
2c
#include "../port/lib.h"
.
## diffname port/tcpoutput.c 1992/0724
## diff -e /n/bootesdump/1992/0321/sys/src/9/port/tcpoutput.c /n/bootesdump/1992/0724/sys/src/9/port/tcpoutput.c
240a
else
tcb->rcv.wnd = w;
.
238,239c
/* use w because rcv.wnd is unsigned */
w = Streamhi - s->readq->next->len;
if(w < 0)
.
233a
int w;
.
## diffname port/tcpoutput.c 1992/0822
## diff -e /n/bootesdump/1992/0724/sys/src/9/port/tcpoutput.c /n/bootesdump/1992/0822/sys/src/9/port/tcpoutput.c
142,143c
/* Start the transmission timers if there is new data and we
* expect acknowledges
.
123,126c
/* Pull up the send pointer so we can accept acks for this window */
.
114,117c
/*
* keep track of balance of resent data */
.
97,101c
/* Pull out data to send */
.
## diffname port/tcpoutput.c 1992/0826
## diff -e /n/bootesdump/1992/0822/sys/src/9/port/tcpoutput.c /n/bootesdump/1992/0826/sys/src/9/port/tcpoutput.c
191c
localclose(s, 0);
.
185c
localclose(s, Etimedout);
.
## diffname port/tcpoutput.c 1992/0903
## diff -e /n/bootesdump/1992/0826/sys/src/9/port/tcpoutput.c /n/bootesdump/1992/0903/sys/src/9/port/tcpoutput.c
217c
tcpoutput(s);
.
210c
tcpacktimer(Ipconv *s)
.
186,187c
break;
}
tcprxmit(s);
.
184c
if (tcb->backoff >= MAXBACKOFF) {
.
173c
tcptimeout(void *arg)
.
168c
tcpoutput(s);
.
144c
tcpgo(&tcb->rtt_timer);
.
140c
tcpgo(&tcb->timer);
.
77d
74a
/* By default we will generate an ack */
.
69,70c
tcphalt(&tcb->acktimer);
.
64d
49,52c
}
else {
.
47d
44d
42a
/* Compute usable segment based on offered window and limit
* window probes to one
*/
.
33c
for(;;) {
.
16c
tcpoutput(Ipconv *s)
.
14a
extern int tcpdbg;
extern ushort tcp_mss;
int tcptimertype;
.
12,13d
10d
## diffname port/tcpoutput.c 1992/0906
## diff -e /n/bootesdump/1992/0903/sys/src/9/port/tcpoutput.c /n/bootesdump/1992/0906/sys/src/9/port/tcpoutput.c
229d
226c
tcb = &s->tcpctl;
.
224a
Tcpctl *tcb;
.
223d
200,205c
if(n <= 4)
return 1 << n;
return n*n;
.
164d
162c
tcb->ssthresh = MAX(tcb->ssthresh, tcb->mss);
.
160c
/* Pull window down to a single packet and halve the slow
* start threshold
*/
.
24a
Block *hbp,*dbp, *sndq;
ushort ssize, dsize, usable, sent;
.
23d
19,20c
Tcp seg;
.
## diffname port/tcpoutput.c 1992/1019
## diff -e /n/bootesdump/1992/0906/sys/src/9/port/tcpoutput.c /n/bootesdump/1992/1019/sys/src/9/port/tcpoutput.c
183c
if (tcb->backoff >= MAXBACKOFF && tcb->snd.wnd > 0) {
.
179d
48,49c
if(sent != 0) {
if (tcb->flags&FORCE)
tcb->snd.ptr = tcb->snd.una;
else
break;
}
.
## diffname port/tcpoutput.c 1993/0218
## diff -e /n/bootesdump/1992/1019/sys/src/9/port/tcpoutput.c /n/bootesdump/1993/0218/sys/src/9/port/tcpoutput.c
96c
seg.ack = tcb->rcv.nxt;
.
94a
tcb->last_ack = tcb->rcv.nxt;
.
52a
tcb->snd.ptr = tcb->snd.una;
.
49,51c
if ((tcb->flags&FORCE) == 0)
.
## diffname port/tcpoutput.c 1993/0220
## diff -e /n/bootesdump/1993/0218/sys/src/9/port/tcpoutput.c /n/bootesdump/1993/0220/sys/src/9/port/tcpoutput.c
115c
tcb->resent += MIN(tcb->snd.nxt - tcb->snd.ptr,(int)ssize);
.
## diffname port/tcpoutput.c 1993/0427
## diff -e /n/bootesdump/1993/0220/sys/src/9/port/tcpoutput.c /n/bootesdump/1993/0427/sys/src/9/port/tcpoutput.c
186a
print("tcp connection timed out\n");
.
## diffname port/tcpoutput.c 1993/0501
## diff -e /n/bootesdump/1993/0427/sys/src/9/port/tcpoutput.c /n/fornaxdump/1993/0501/sys/src/brazil/port/tcpoutput.c
187d
115c
tcb->resent += MIN((int)tcb->snd.nxt - (int)tcb->snd.ptr,(int)ssize);
.
96c
seg.ack = tcb->last_ack = tcb->rcv.nxt;
.
94d
51d
49c
if (tcb->flags&FORCE)
tcb->snd.ptr = tcb->snd.una;
else
.
## diffname port/tcpoutput.c 1993/0804 # deleted
## diff -e /n/fornaxdump/1993/0501/sys/src/brazil/port/tcpoutput.c /n/fornaxdump/1993/0804/sys/src/brazil/port/tcpoutput.c
1,273d
|