## 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