## diffname port/tcpinput.c 1991/0424
## diff -e /dev/null /n/bootesdump/1991/0424/sys/src/9/port/tcpinput.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"
int tcpdbg = 0;
#define DPRINT if(tcpdbg) print
#define LPRINT print
extern Queue *Tcpoutput;
QLock reseqlock;
Reseq *reseqfree;
char *tcpstate[] = {
"Closed", "Listen", "Syn_sent", "Syn_received",
"Established", "Finwait1", "Finwait2", "Close_wait",
"Closing", "Last_ack", "Time_wait" };
void
tcp_input(Ipconv *ipc, Block *bp)
{
Ipconv *s, *new, *etab;
Tcpctl *tcb;
Tcphdr *h;
Tcp seg;
int hdrlen;
Block *oobbp;
Ipaddr source, dest;
char tos;
ushort length;
DPRINT("tcp_input.\n");
h = (Tcphdr *)(bp->rptr);
dest = nhgetl(h->tcpdst);
source = nhgetl(h->tcpsrc);
tos = h->tos;
length = nhgets(h->length);
if (dest == source) {
if (!(bp = copyb(bp, blen(bp)))) {
print("tcpin: allocb failure.");
return;
}
DPRINT("tcpin: Duplicate packet %lux\n", bp);
}
h->Unused = 0;
hnputs(h->tcplen, length - (TCP_IPLEN+TCP_PHDRSIZE));
if(ptcl_csum(bp, TCP_EHSIZE+TCP_IPLEN, length - TCP_IPLEN)) {
DPRINT("tcpin: Bad checksum.\n");
freeb(bp);
return;
}
if((hdrlen = ntohtcp(&seg, &bp)) < 0)
return;
/* Adjust the data length */
length -= (hdrlen+TCP_IPLEN+TCP_PHDRSIZE);
DPRINT("tcpin: lport = %d, rport = %d hdrlen %d",
seg.dest, seg.source, hdrlen);
DPRINT(" flags = 0x%lux, seqo = %d, seqi = %d len %d\n",
seg.flags, seg.seq, seg.ack, length);
/* Trim the packet down to just the data */
bp = btrim(bp, hdrlen+TCP_PKT, length);
if(bp == 0)
return;
if (!(s = ip_conn(ipc, seg.dest, seg.source, source, IP_TCPPROTO))) {
LPRINT("tcpin: look for listen on %d\n", seg.dest);
if(!(seg.flags & SYN)) {
LPRINT("tcpin: No SYN\n");
clear:
LPRINT("tcpin: call cleared\n");
freeb(bp);
reset(source, dest, tos, length, &seg);
return;
}
if(!(s = ip_conn(ipc, seg.dest, 0, 0, IP_TCPPROTO))) {
LPRINT("tcpin: No socket dest on %d\n", seg.dest);
goto clear;
}
if(s->curlog >= s->backlog) {
LPRINT("too many pending\n");
goto clear;
}
/* Find a conversation to clone onto */
etab = &ipc[conf.ip];
for(new = ipc; new < etab; new++) {
if(new->ref == 0 && canqlock(new)) {
if(new->ref || new->tcpctl.state != CLOSED) {
qunlock(new);
continue;
}
new->ref++;
qunlock(new);
break;
}
}
if(new == etab)
goto clear;
s->curlog++;
LPRINT("tcpin: cloning socket\n");
new->psrc = s->psrc;
new->pdst = seg.source;
new->dst = source;
memmove(&new->tcpctl, &s->tcpctl, sizeof(Tcpctl));
new->tcpctl.flags &= ~CLONE;
new->tcpctl.timer.arg = new;
new->tcpctl.timer.state = TIMER_STOP;
new->tcpctl.acktimer.arg = new;
new->tcpctl.acktimer.state = TIMER_STOP;
new->ipinterface = s->ipinterface;
s->ipinterface->ref++;
/* Wake the sleeping dodo */
wakeup(&s->listenr);
s = new;
}
tcb = &s->tcpctl;
qlock(tcb);
switch(tcb->state) {
case CLOSED:
freeb(bp);
reset(source, dest, tos, length, &seg);
goto done;
case LISTEN:
if(seg.flags & RST) {
freeb(bp);
goto done;
}
if(seg.flags & ACK) {
freeb(bp);
reset(source, dest, tos, length, &seg);
goto done;
}
if(seg.flags & SYN) {
proc_syn(s, tos, &seg);
send_syn(tcb);
setstate(s, SYN_RECEIVED);
if(length != 0 || (seg.flags & FIN))
break;
freeb(bp);
goto output;
}
freeb(bp);
goto done;
case SYN_SENT:
if(seg.flags & ACK) {
if(!seq_within(seg.ack, tcb->iss+1, tcb->snd.nxt)) {
freeb(bp);
reset(source, dest, tos, length, &seg);
goto done;
}
}
if(seg.flags & RST) {
if(seg.flags & ACK)
close_self(s, Econrefused);
freeb(bp);
goto done;
}
if((seg.flags & ACK) && PREC(tos) != PREC(tcb->tos)){
freeb(bp);
reset(source, dest, tos, length, &seg);
goto done;
}
if(seg.flags & SYN) {
proc_syn(s, tos, &seg);
if(seg.flags & ACK){
update(s, &seg);
setstate(s, ESTABLISHED);
}
else
setstate(s, SYN_RECEIVED);
if(length != 0 || (seg.flags & FIN))
break;
freeb(bp);
goto output;
}
else
freeb(bp);
goto done;
}
/* Trim segment to fit receive window. */
if(trim(tcb, &seg, &bp, &length) == -1) {
if(!(seg.flags & RST)) {
tcb->flags |= FORCE;
goto output;
}
goto done;
}
/* If we have no opens and the other end is sending data then
* reply with a reset
*/
if(s->readq == 0 && length) {
freeb(bp);
reset(source, dest, tos, length, &seg);
goto done;
}
if(seg.seq != tcb->rcv.nxt
&& (length != 0 || (seg.flags & (SYN|FIN)) )) {
add_reseq(tcb, tos, &seg, bp, length);
tcb->flags |= FORCE;
goto output;
}
for(;;) {
if(seg.flags & RST) {
if(tcb->state == SYN_RECEIVED
&& !(tcb->flags & (CLONE|ACTIVE)))
setstate(s, LISTEN);
else
close_self(s, Econrefused);
freeb(bp);
goto done;
}
if(PREC(tos) != PREC(tcb->tos) || (seg.flags & SYN)){
freeb(bp);
reset(source, dest, tos, length, &seg);
goto done;
}
if(!(seg.flags & ACK)) {
freeb(bp);
goto done;
}
switch(tcb->state) {
case SYN_RECEIVED:
if(seq_within(seg.ack, tcb->snd.una+1, tcb->snd.nxt)){
update(s, &seg);
setstate(s, ESTABLISHED);
}
else {
freeb(bp);
reset(source, dest, tos, length, &seg);
goto done;
}
break;
case ESTABLISHED:
case CLOSE_WAIT:
update(s, &seg);
break;
case FINWAIT1:
update(s, &seg);
if(tcb->sndcnt == 0)
setstate(s, FINWAIT2);
break;
case FINWAIT2:
update(s, &seg);
break;
case CLOSING:
update(s, &seg);
if(tcb->sndcnt == 0){
setstate(s, TIME_WAIT);
tcb->timer.start = MSL2 * (1000 / MSPTICK);
start_timer(&tcb->timer);
}
break;
case LAST_ACK:
update(s, &seg);
if(tcb->sndcnt == 0) {
close_self(s, 0);
goto done;
}
case TIME_WAIT:
tcb->flags |= FORCE;
start_timer(&tcb->timer);
}
if ((seg.flags&URG) && seg.up) {
DPRINT("tcpin: oob: up = %u seq = %u rcv.up = %u\n",
seg.up, seg.seq, tcb->rcv.up);
if (seq_gt(seg.up + seg.seq, tcb->rcv.up)) {
tcb->rcv.up = seg.up + seg.seq;
tcb->oobflags &= ~(TCPOOB_HAVEDATA|TCPOOB_HADDATA);
extract_oob(&bp, &oobbp, &seg);
if (oobbp) {
DPRINT("tcpin: oob delivered\n");
appendb(&tcb->rcvoobq, oobbp);
tcb->rcvoobcnt += blen(oobbp);
tcb->oobmark = tcb->rcvcnt;
tcb->oobflags |= TCPOOB_HAVEDATA;
#ifdef NOTIFY
urg_signal(s);
#endif
}
}
}
else if (seq_gt(tcb->rcv.nxt, tcb->rcv.up))
tcb->rcv.up = tcb->rcv.nxt;
DPRINT("tcpin: Append pkt len=%d state=%s\n",
length, tcpstate[tcb->state]);
if(length != 0){
switch(tcb->state){
case SYN_RECEIVED:
case ESTABLISHED:
case FINWAIT1:
case FINWAIT2:
/* Place on receive queue */
tcb->rcvcnt += blen(bp);
if(s->readq && bp) {
PUTNEXT(s->readq, bp);
bp = 0;
}
tcb->rcv.nxt += length;
tcprcvwin(s);
start_timer(&tcb->acktimer);
if (tcb->max_snd <= tcb->rcv.nxt-tcb->last_ack)
tcb->flags |= FORCE;
break;
default:
/* Ignore segment text */
freeb(bp);
break;
}
}
if(seg.flags & FIN) {
tcb->flags |= FORCE;
switch(tcb->state) {
case SYN_RECEIVED:
case ESTABLISHED:
tcb->rcv.nxt++;
setstate(s, CLOSE_WAIT);
break;
case FINWAIT1:
tcb->rcv.nxt++;
if(tcb->sndcnt == 0) {
setstate(s, TIME_WAIT);
tcb->timer.start = MSL2 * (1000/MSPTICK);
start_timer(&tcb->timer);
}
else
setstate(s, CLOSING);
break;
case FINWAIT2:
tcb->rcv.nxt++;
setstate(s, TIME_WAIT);
tcb->timer.start = MSL2 * (1000/MSPTICK);
start_timer(&tcb->timer);
break;
case CLOSE_WAIT:
case CLOSING:
case LAST_ACK:
break;
case TIME_WAIT:
start_timer(&tcb->timer);
break;
}
}
while(tcb->reseq != 0 &&
seq_ge(tcb->rcv.nxt, tcb->reseq->seg.seq)){
get_reseq(tcb, &tos, &seg, &bp, &length);
if(trim(tcb, &seg, &bp, &length) == 0)
goto gotone;
}
break;
gotone:;
}
output:
tcp_output(s);
done:
qunlock(tcb);
}
void
tcp_icmp(Ipconv *ipc, Ipaddr source, Ipaddr dest, char type, char code, Block **bpp)
{
Tcp seg;
Tcpctl *tcb;
Ipconv *s;
ntohtcp(&seg, bpp);
if(!(s = ip_conn(ipc, seg.source, seg.dest, dest, IP_TCPPROTO)))
return;
tcb = &s->tcpctl;
if(!seq_within(seg.seq, tcb->snd.una, tcb->snd.nxt))
return;
switch((uchar)type) {
case ICMP_UNREACH:
tcb->type = type;
tcb->code = code;
if(tcb->state == SYN_SENT || tcb->state == SYN_RECEIVED)
close_self(s, Enetunreach);
break;
case ICMP_TIMXCEED:
tcb->type = type;
tcb->code = code;
if(tcb->state == SYN_SENT || tcb->state == SYN_RECEIVED)
close_self(s, Etimedout);
break;
case ICMP_SOURCEQUENCH:
tcb->cwind /= 2;
tcb->cwind = MAX(tcb->mss,tcb->cwind);
break;
}
}
void
reset(Ipaddr source, Ipaddr dest, char tos, ushort length, Tcp *seg)
{
Block *hbp;
Port tmp;
char rflags;
Tcphdr ph;
if(seg->flags & RST)
return;
hnputl(ph.tcpsrc, dest);
hnputl(ph.tcpdst, source);
ph.proto = IP_TCPPROTO;
hnputs(ph.tcplen, TCP_HDRSIZE);
/* Swap port numbers */
tmp = seg->dest;
seg->dest = seg->source;
seg->source = tmp;
rflags = RST;
if(seg->flags & ACK) {
/* This reset is being sent to clear a half-open connection.
* Set the sequence number of the RST to the incoming ACK
* so it will be acceptable.
*/
seg->seq = seg->ack;
seg->ack = 0;
}
else {
/* We're rejecting a connect request (SYN) from LISTEN state
* so we have to "acknowledge" their SYN.
*/
rflags |= ACK;
seg->ack = seg->seq;
seg->seq = 0;
if(seg->flags & SYN)
seg->ack++;
seg->ack += length;
if(seg->flags & FIN)
seg->ack++;
}
seg->flags = rflags;
seg->wnd = 0;
seg->up = 0;
seg->mss = 0;
if((hbp = htontcp(seg, 0, &ph)) == 0)
return;
DPRINT("Reset: seq = %lux ack = %d flags = %lux\n",
seg->seq, seg->ack, seg->flags);
PUTNEXT(Tcpoutput, hbp);
}
void
update(Ipconv *s, Tcp *seg)
{
ushort acked;
ushort oobacked;
ushort expand;
Tcpctl *tcb = &s->tcpctl;
if(seq_gt(seg->ack, tcb->snd.nxt)) {
tcb->flags |= FORCE;
return;
}
if(seq_gt(seg->seq,tcb->snd.wl1) || ((seg->seq == tcb->snd.wl1)
&& seq_ge(seg->ack,tcb->snd.wl2))) {
if(tcb->snd.wnd == 0 && seg->wnd != 0)
tcb->snd.ptr = tcb->snd.una;
tcb->snd.wnd = seg->wnd;
tcb->snd.wl1 = seg->seq;
tcb->snd.wl2 = seg->ack;
}
if(!seq_gt(seg->ack, tcb->snd.una))
return;
acked = seg->ack - tcb->snd.una;
if(tcb->cwind < tcb->snd.wnd) {
if(tcb->cwind < tcb->ssthresh)
expand = MIN(acked,tcb->mss);
else
expand = ((long)tcb->mss * tcb->mss) / tcb->cwind;
if(tcb->cwind + expand < tcb->cwind)
expand = 65535 - tcb->cwind;
if(tcb->cwind + expand > tcb->snd.wnd)
expand = tcb->snd.wnd - tcb->cwind;
if(expand != 0)
tcb->cwind += expand;
}
/* Round trip time estimation */
if(run_timer(&tcb->rtt_timer) && seq_ge(seg->ack, tcb->rttseq)) {
stop_timer(&tcb->rtt_timer);
if(!(tcb->flags & RETRAN)) {
int rtt; /* measured round trip time */
int abserr; /* abs(rtt - srtt) */
rtt = tcb->rtt_timer.start - tcb->rtt_timer.count;
rtt *= MSPTICK;
if(rtt > tcb->srtt &&
(tcb->state == SYN_SENT || tcb->state == SYN_RECEIVED))
tcb->srtt = rtt;
else {
abserr = (rtt > tcb->srtt) ? rtt - tcb->srtt : tcb->srtt - rtt;
tcb->srtt = ((AGAIN-1)*tcb->srtt + rtt) / AGAIN;
tcb->mdev = ((DGAIN-1)*tcb->mdev + abserr) / DGAIN;
DPRINT("tcpout: rtt %d, srtt %d, mdev %d\n",
rtt, tcb->srtt, tcb->mdev);
}
tcb->backoff = 0;
}
}
/* If we're waiting for an ack of our SYN, note it and adjust count */
if(!(tcb->flags & SYNACK)){
tcb->flags |= SYNACK;
acked--;
tcb->sndcnt--;
}
/* Acking some oob data if relevant */
if(tcb->sndoobq && seq_ge(tcb->snd.up,tcb->snd.una) &&
seq_gt(seg->ack, tcb->snd.up)) {
oobacked = seg->ack - tcb->snd.up;
acked -= oobacked;
copyupb(&tcb->sndoobq, 0, oobacked);
tcb->sndoobcnt -= oobacked;
DPRINT("update: oobacked = %d\n", oobacked);
}
copyupb(&tcb->sndq, 0, acked);
/* This will include the FIN if there is one */
tcb->sndcnt -= acked;
tcb->snd.una = seg->ack;
/* If ack includes some out-of-band data then update urgent pointer */
if (seq_gt(seg->ack, tcb->snd.up))
tcb->snd.up = seg->ack;
/* Stop retransmission timer, but restart it if there is still
* unacknowledged data.
*/
stop_timer(&tcb->timer);
if(tcb->snd.una != tcb->snd.nxt)
start_timer(&tcb->timer);
/* If retransmissions have been occurring, make sure the
* send pointer doesn't repeat ancient history
*/
if(seq_lt(tcb->snd.ptr, tcb->snd.una))
tcb->snd.ptr = tcb->snd.una;
/* Clear the retransmission flag since the oldest
* unacknowledged segment (the only one that is ever retransmitted)
* has now been acked.
*/
tcb->flags &= ~RETRAN;
tcb->backoff = 0;
}
int
in_window(Tcpctl *tcb, int seq)
{
return seq_within(seq, tcb->rcv.nxt,
(int)(tcb->rcv.nxt+tcb->rcv.wnd-1));
}
void
proc_syn(Ipconv *s, char tos, Tcp *seg)
{
Tcpctl *tcb = &s->tcpctl;
ushort mtu;
tcb->flags |= FORCE;
if(PREC(tos) > PREC(tcb->tos))
tcb->tos = tos;
tcb->rcv.up = tcb->rcv.nxt = seg->seq + 1; /* p 68 */
tcb->snd.wl1 = tcb->irs = seg->seq;
tcb->snd.wnd = seg->wnd;
if(seg->mss != 0)
tcb->mss = seg->mss;
tcb->max_snd = seg->wnd;
if((mtu = s->ipinterface->maxmtu) != 0) {
mtu -= TCP_HDRSIZE + TCP_EHSIZE + TCP_PHDRSIZE;
tcb->cwind = tcb->mss = MIN(mtu, tcb->mss);
}
}
/* Generate an initial sequence number and put a SYN on the send queue */
void
send_syn(Tcpctl *tcb)
{
tcb->iss = iss();
tcb->rttseq = tcb->snd.wl2 = tcb->snd.una = tcb->iss;
tcb->snd.ptr = tcb->snd.nxt = tcb->rttseq;
tcb->sndcnt++;
tcb->flags |= FORCE;
}
void
add_reseq(Tcpctl *tcb, char tos, Tcp *seg, Block *bp, ushort length)
{
Reseq *rp, *rp1;
qlock(&reseqlock);
if(!reseqfree) {
qunlock(&reseqlock);
print("tcp: no resequence descriptors\n");
freeb(bp);
return;
}
rp = reseqfree;
reseqfree = rp->next;
qunlock(&reseqlock);
rp->seg = *seg;
rp->tos = tos;
rp->bp = bp;
rp->length = length;
/* Place on reassembly list sorting by starting seq number */
rp1 = tcb->reseq;
if(rp1 == 0 || seq_lt(seg->seq, rp1->seg.seq)) {
rp->next = rp1;
tcb->reseq = rp;
}
else {
for(;;){
if(rp1->next == 0 ||
seq_lt(seg->seq, rp1->next->seg.seq)) {
rp->next = rp1->next;
rp1->next = rp;
break;
}
rp1 = rp1->next;
}
}
}
void
get_reseq(Tcpctl *tcb, char *tos, Tcp *seg, Block **bp, ushort *length)
{
Reseq *rp;
if((rp = tcb->reseq) == 0)
return;
tcb->reseq = rp->next;
*tos = rp->tos;
*seg = rp->seg;
*bp = rp->bp;
*length = rp->length;
qlock(&reseqlock);
rp->next = reseqfree;
reseqfree = rp;
qunlock(&reseqlock);
}
int
trim(Tcpctl *tcb, Tcp *seg, Block **bp, ushort *length)
{
Block *nbp;
long dupcnt,excess;
ushort len; /* Segment length including flags */
char accept;
accept = 0;
len = *length;
if(seg->flags & SYN)
len++;
if(seg->flags & FIN)
len++;
/* Acceptability tests */
if(tcb->rcv.wnd == 0) {
if(seg->seq == tcb->rcv.nxt && len == 0)
return 0;
} else {
/* Some part of the segment must be in the window */
if(in_window(tcb,seg->seq)) {
accept++;
}
else if(len != 0) {
if(in_window(tcb, (int)(seg->seq+len-1)) ||
seq_within(tcb->rcv.nxt, seg->seq,(int)(seg->seq+len-1)))
accept++;
}
}
if(!accept) {
freeb(*bp);
return -1;
}
dupcnt = tcb->rcv.nxt - seg->seq;
if(dupcnt > 0){
tcb->rerecv += dupcnt;
if(seg->flags & SYN){
seg->flags &= ~SYN;
seg->seq++;
if (seg->up > 1)
seg->up--;
else
seg->flags &= ~URG;
dupcnt--;
}
if(dupcnt > 0){
copyupb(bp, 0, (ushort)dupcnt);
seg->seq += dupcnt;
*length -= dupcnt;
if (seg->up > dupcnt)
seg->up -= dupcnt;
else {
seg->flags &= ~URG;
seg->up = 0;
}
}
}
excess = seg->seq + *length - (tcb->rcv.nxt + tcb->rcv.wnd);
if(excess > 0){
tcb->rerecv += excess;
*length -= excess;
nbp = copyb(*bp, *length);
freeb(*bp);
*bp = nbp;
seg->flags &= ~FIN;
}
return 0;
}
void
extract_oob(Block **bp, Block **oobbp, Tcp *seg)
{
DPRINT("extract_oob: size = %u\n", seg->up);
if (*oobbp = allocb(seg->up))
(*oobbp)->wptr = (*oobbp)->wptr +
copyupb(bp, (*oobbp)->rptr, seg->up);
else
copyupb(bp, 0, seg->up);
}
int
copyupb(Block **bph, uchar *data, int count)
{
int n, bytes;
Block *bp;
bytes = 0;
if(bph == 0)
return 0;
while(*bph && count != 0) {
bp = *bph;
n = MIN(count, BLEN(bp));
if(data && n) {
memmove(data, bp->rptr, n);
data += n;
}
bytes += n;
count -= n;
bp->rptr += n;
if(BLEN(bp) == 0) {
*bph = bp->next;
bp->next = 0;
freeb(bp);
}
}
return bytes;
}
void
appendb(Block **list, Block *bp)
{
Block *f;
if(f = *list) {
while(f->next)
f = f->next;
f->next = bp;
}
else
*list = bp;
bp->next = 0;
}
int
dupb(Block **hp, Block *bp, int offset, int count)
{
int i, blen, bytes = 0;
uchar *addr;
*hp = allocb(count);
if(*hp == 0)
return 0;
/* Correct to front of data area */
while(bp && offset && offset >= BLEN(bp)) {
offset -= BLEN(bp);
bp = bp->next;
}
if(bp == 0)
return 0;
addr = bp->rptr + offset;
blen = BLEN(bp) - offset;
while(count) {
i = MIN(count, blen);
memmove((*hp)->wptr, addr, i);
(*hp)->wptr += i;
bytes += i;
count -= i;
bp = bp->next;
if(!bp)
break;
blen = BLEN(bp);
addr = bp->rptr;
}
return bytes;
}
Block *
copyb(Block *bp, int count)
{
Block *nbp;
int i;
nbp = allocb(count);
if(nbp == 0)
return 0;
while(bp && count) {
i = MIN(count, BLEN(bp));
memmove(nbp->wptr, bp->rptr, i);
nbp->wptr += i;
count -= i;
bp = bp->next;
}
return nbp;
}
ushort tcp_mss = DEF_MSS; /* Maximum segment size to be sent with SYN */
int tcp_irtt = DEF_RTT; /* Initial guess at round trip time */
void
init_tcpctl(Ipconv *s)
{
Tcpctl *tcb = &s->tcpctl;
memset(tcb, 0, sizeof(Tcpctl));
tcb->cwind = tcb->mss = tcp_mss;
tcb->ssthresh = 65535;
tcb->srtt = tcp_irtt;
/* Initialize timer intervals */
tcb->timer.start = tcb->srtt / MSPTICK;
tcb->timer.func = (void(*)(void*))tcp_timeout;
tcb->timer.arg = (void *)s;
tcb->rtt_timer.start = MAX_TIME;
/* Initialise ack timer */
tcb->acktimer.start = TCP_ACK / MSPTICK;
tcb->acktimer.func = (void(*)(void*))tcp_acktimer;
tcb->acktimer.arg = (void *)s;
}
void
close_self(Ipconv *s, int reason)
{
Reseq *rp,*rp1;
Tcpctl *tcb = &s->tcpctl;
stop_timer(&tcb->timer);
stop_timer(&tcb->rtt_timer);
s->err = reason;
/* Flush reassembly queue; nothing more can arrive */
for(rp = tcb->reseq;rp != 0;rp = rp1){
rp1 = rp->next;
freeb(rp->bp);
qlock(&reseqlock);
rp->next = reseqfree;
reseqfree = rp;
qunlock(&reseqlock);
}
tcb->reseq = 0;
s->err = reason;
setstate(s, CLOSED);
}
int
iss(void)
{
static int seq;
seq += 250000;
return seq;
}
int
seq_within(int x, int low, int high)
{
if(low <= high){
if(low <= x && x <= high)
return 1;
} else {
if(low >= x && x >= high)
return 1;
}
return 0;
}
int
seq_lt(int x, int y)
{
return (long)(x-y) < 0;
}
int
seq_le(int x, int y)
{
return (long)(x-y) <= 0;
}
int
seq_gt(int x, int y)
{
return (long)(x-y) > 0;
}
int
seq_ge(int x, int y)
{
return (long)(x-y) >= 0;
}
void
setstate(Ipconv *s, char newstate)
{
char oldstate;
Tcpctl *tcb = &s->tcpctl;
oldstate = tcb->state;
tcb->state = newstate;
state_upcall(s, oldstate, newstate);
}
Block *
htontcp(Tcp *tcph, Block *data, Tcphdr *ph)
{
ushort hdrlen;
int dlen;
ushort csum;
Tcphdr *h;
Block *bp;
hdrlen = TCP_HDRSIZE;
if(tcph->mss)
hdrlen += MSS_LENGTH;
if(data) {
dlen = blen(data);
if((data = padb(data, hdrlen + TCP_PKT)) == 0)
return 0;
/* If we collected blocks delimit the end of the chain */
for(bp = data; bp->next; bp = bp->next)
bp->flags &= ~S_DELIM;
bp->flags |= S_DELIM;
}
else {
dlen = 0;
data = allocb(hdrlen + TCP_PKT);
if(data == 0)
return 0;
data->wptr += hdrlen + TCP_PKT;
data->flags |= S_DELIM;
}
memmove(data->rptr, ph, TCP_PKT);
h = (Tcphdr *)(data->rptr);
h->proto = IP_TCPPROTO;
hnputs(h->tcplen, hdrlen + dlen);
hnputs(h->tcpsport, tcph->source);
hnputs(h->tcpdport, tcph->dest);
hnputl(h->tcpseq, tcph->seq);
hnputl(h->tcpack, tcph->ack);
hnputs(h->tcpflag, (hdrlen<<10) | tcph->flags);
hnputs(h->tcpwin, tcph->wnd);
h->tcpcksum[0] = 0;
h->tcpcksum[1] = 0;
h->Unused = 0;
hnputs(h->tcpurg, tcph->up);
if(tcph->mss != 0){
h->tcpopt[0] = MSS_KIND;
h->tcpopt[1] = MSS_LENGTH;
hnputs(h->tcpmss, tcph->mss);
}
csum = ptcl_csum(data, TCP_EHSIZE+TCP_IPLEN, hdrlen+dlen+TCP_PHDRSIZE);
hnputs(h->tcpcksum, csum);
return data;
}
int
ntohtcp(Tcp *tcph, Block **bpp)
{
ushort hdrlen;
ushort i, optlen;
Block *nbp;
Tcphdr *h;
uchar *optr;
*bpp = pullup(*bpp, TCP_PKT+TCP_HDRSIZE);
if(*bpp == 0)
return -1;
h = (Tcphdr *)((*bpp)->rptr);
tcph->source = nhgets(h->tcpsport);
tcph->dest = nhgets(h->tcpdport);
tcph->seq = nhgetl(h->tcpseq);
tcph->ack = nhgetl(h->tcpack);
hdrlen = (h->tcpflag[0] & 0xf0) >> 2;
if(hdrlen < TCP_HDRSIZE) {
freeb(*bpp);
return -1;
}
tcph->flags = h->tcpflag[1];
tcph->wnd = nhgets(h->tcpwin);
tcph->up = nhgets(h->tcpurg);
tcph->mss = 0;
*bpp = pullup(*bpp, hdrlen+TCP_PKT);
if(!*bpp)
return -1;
for(optr = h->tcpopt, i = TCP_HDRSIZE; i < hdrlen;) {
switch(*optr++){
case EOL_KIND:
goto eol;
case NOOP_KIND:
i++;
break;
case MSS_KIND:
optlen = *optr++;
if(optlen == MSS_LENGTH)
tcph->mss = nhgets(optr);
i += optlen;
break;
}
}
eol:
return hdrlen;
}
.
## diffname port/tcpinput.c 1991/0625
## diff -e /n/bootesdump/1991/0424/sys/src/9/port/tcpinput.c /n/bootesdump/1991/0625/sys/src/9/port/tcpinput.c
660d
## diffname port/tcpinput.c 1991/0705
## diff -e /n/bootesdump/1991/0625/sys/src/9/port/tcpinput.c /n/bootesdump/1991/0705/sys/src/9/port/tcpinput.c
659a
print("tcp: no resequence descriptors\n");
.
23a
tcpinit(void)
{
Reseq *r;
reseqfree = ialloc(sizeof(Reseq)*Nreseq, 0);
for(r = reseqfree; r < &reseqfree[Nreseq-1]; r++)
r->next = r+1;
r->next = 0;
}
void
.
## diffname port/tcpinput.c 1991/0727
## diff -e /n/bootesdump/1991/0705/sys/src/9/port/tcpinput.c /n/bootesdump/1991/0727/sys/src/9/port/tcpinput.c
12c
#define LPRINT if(tcpdbg) print
.
## diffname port/tcpinput.c 1991/0926
## diff -e /n/bootesdump/1991/0727/sys/src/9/port/tcpinput.c /n/bootesdump/1991/0926/sys/src/9/port/tcpinput.c
441c
tcb->cwind = tcb->cwind/2;
.
## diffname port/tcpinput.c 1991/1019
## diff -e /n/bootesdump/1991/0926/sys/src/9/port/tcpinput.c /n/bootesdump/1991/1019/sys/src/9/port/tcpinput.c
500c
PUTNEXT(Ipoutput, hbp);
.
14d
## diffname port/tcpinput.c 1991/1023
## diff -e /n/bootesdump/1991/1019/sys/src/9/port/tcpinput.c /n/bootesdump/1991/1023/sys/src/9/port/tcpinput.c
144a
.
142,143d
139a
new->newcon = 1;
.
111,125c
new = ipincoming(ipc);
if(new == 0)
.
37c
Ipconv *s, *new;
.
## diffname port/tcpinput.c 1991/1030
## diff -e /n/bootesdump/1991/1023/sys/src/9/port/tcpinput.c /n/bootesdump/1991/1030/sys/src/9/port/tcpinput.c
1122d
1110c
return hdrlen;
.
1010d
971c
}
else {
.
952d
824d
785,797d
774c
if(excess > 0) {
.
732c
}
else {
.
691d
680,681c
if(rp1->next == 0 || seq_lt(seg->seq, rp1->next->seg.seq)) {
.
632d
608,609c
return seq_within(seq, tcb->rcv.nxt, (int)(tcb->rcv.nxt+tcb->rcv.wnd-1));
.
591,593d
580d
577d
565,574d
559c
if((tcb->flags & SYNACK) == 0){
.
542d
537,538d
530d
527d
524d
515d
495a
int rtt;
int abserr;
.
493d
389c
gotone:;
.
300,311c
copyupb(&bp, 0, seg.up);
.
296,297d
42d
## diffname port/tcpinput.c 1991/1102
## diff -e /n/bootesdump/1991/1030/sys/src/9/port/tcpinput.c /n/bootesdump/1991/1102/sys/src/9/port/tcpinput.c
133c
process:
.
131c
s = new;
goto process;
}
}
clear:
LPRINT("tcpin: call cleared\n");
freeb(bp);
reset(source, dest, tos, length, &seg);
return;
.
126,129c
new->newcon = 1;
new->ipinterface = s->ipinterface;
s->ipinterface->ref++;
wakeup(&s->listenr);
.
114,124c
s->curlog++;
LPRINT("tcpin: cloning socket\n");
new->psrc = seg.dest;
new->pdst = seg.source;
new->dst = source;
memmove(&new->tcpctl, &s->tcpctl, sizeof(Tcpctl));
new->tcpctl.flags &= ~CLONE;
new->tcpctl.timer.arg = new;
new->tcpctl.timer.state = TIMER_STOP;
new->tcpctl.acktimer.arg = new;
new->tcpctl.acktimer.state = TIMER_STOP;
.
110,112c
new = ipincoming(ipc);
if(new == 0)
goto clear;
.
105,108c
e = &ipc[conf.ip];
for(s = ipc; s < e; s++) {
if(s->tcpctl.state == LISTEN)
if(s->pdst == 0)
if(s->dst == 0) {
if(s->curlog >= s->backlog)
goto clear;
.
103d
91,101c
if((seg.flags & SYN) == 0)
.
88c
s = ip_conn(ipc, seg.dest, seg.source, source, IP_TCPPROTO);
if (s == 0) {
.
37c
Ipconv *s, *e, *new;
.
## diffname port/tcpinput.c 1991/1104
## diff -e /n/bootesdump/1991/1102/sys/src/9/port/tcpinput.c /n/bootesdump/1991/1104/sys/src/9/port/tcpinput.c
469,471d
369,370c
while(tcb->reseq != 0 && seq_ge(tcb->rcv.nxt, tcb->reseq->seg.seq)) {
.
304,306d
222,223c
if(seg.seq != tcb->rcv.nxt && (length != 0 || (seg.flags & (SYN|FIN)) )) {
.
129d
123d
120a
.
118d
108d
90,91d
77,83d
67d
65d
60d
## diffname port/tcpinput.c 1991/1106
## diff -e /n/bootesdump/1991/1104/sys/src/9/port/tcpinput.c /n/bootesdump/1991/1106/sys/src/9/port/tcpinput.c
55,61d
## diffname port/tcpinput.c 1991/1115
## diff -e /n/bootesdump/1991/1106/sys/src/9/port/tcpinput.c /n/bootesdump/1991/1115/sys/src/9/port/tcpinput.c
84c
new = ipincoming(ipc, s);
.
## diffname port/tcpinput.c 1991/1122
## diff -e /n/bootesdump/1991/1115/sys/src/9/port/tcpinput.c /n/bootesdump/1991/1122/sys/src/9/port/tcpinput.c
818c
return head;
.
814a
if(head == 0)
head = nbp;
else
tail->next = nbp;
tail = nbp;
.
811c
i = BLEN(bp);
nbp = allocb(i);
if(i > nbp->lim-nbp->wptr) {
if(head)
freeb(head);
return 0;
}
.
806,809c
head = 0;
.
803c
Block *nbp, *head, *tail;
.
## diffname port/tcpinput.c 1991/1126
## diff -e /n/bootesdump/1991/1122/sys/src/9/port/tcpinput.c /n/bootesdump/1991/1126/sys/src/9/port/tcpinput.c
806c
head = tail = 0;
.
747,762d
## diffname port/tcpinput.c 1991/12171
## diff -e /n/bootesdump/1991/1126/sys/src/9/port/tcpinput.c /n/bootesdump/1991/12171/sys/src/9/port/tcpinput.c
864c
setstate(s, Closed);
.
495c
(tcb->state == Syn_sent || tcb->state == Syn_received))
.
383c
if(tcb->state == Syn_sent || tcb->state == Syn_received)
.
377c
if(tcb->state == Syn_sent || tcb->state == Syn_received)
.
338c
case Time_wait:
.
334,336c
case Close_wait:
case Closing:
case Last_ack:
.
330c
setstate(s, Time_wait);
.
328c
case Finwait2:
.
326c
setstate(s, Closing);
.
321c
setstate(s, Time_wait);
.
318c
case Finwait1:
.
316c
setstate(s, Close_wait);
.
313,314c
case Syn_received:
case Established:
.
283,286c
case Syn_received:
case Established:
case Finwait1:
case Finwait2:
.
267c
case Time_wait:
.
261c
case Last_ack:
.
256c
setstate(s, Time_wait);
.
253c
case Closing:
.
250c
case Finwait2:
.
248c
setstate(s, Finwait2);
.
245c
case Finwait1:
.
241,242c
case Established:
case Close_wait:
.
233c
setstate(s, Established);
.
230c
case Syn_received:
.
210c
setstate(s, Listen);
.
208c
if(tcb->state == Syn_received
.
169c
setstate(s, Syn_received);
.
166c
setstate(s, Established);
.
142c
case Syn_sent:
.
134c
setstate(s, Syn_received);
.
121c
case Listen:
.
117c
case Closed:
.
78c
if(s->tcpctl.state == Listen)
.
## diffname port/tcpinput.c 1992/0105
## diff -e /n/bootesdump/1991/12171/sys/src/9/port/tcpinput.c /n/bootesdump/1992/0105/sys/src/9/port/tcpinput.c
810,811c
if(count) {
nb = allocb(count);
if(nb == 0)
panic("copyb.2");
memset(nb->wptr, 0, count);
nb->wptr += count;
*p = nb;
}
if(blen(head) == 0)
print("copyb: zero length\n");
return head;
.
808a
if(bp == 0)
break;
.
790,807c
p = &head;
while(count) {
l = BLEN(bp);
if(count < l)
l = count;
nb = allocb(l);
if(nb == 0)
panic("copyb.1");
memmove(nb->wptr, bp->rptr, l);
nb->wptr += l;
count -= l;
*p = nb;
p = &nb->next;
.
787,788c
Block *nb, *head, **p;
int l;
.
## diffname port/tcpinput.c 1992/0106
## diff -e /n/bootesdump/1992/0105/sys/src/9/port/tcpinput.c /n/bootesdump/1992/0106/sys/src/9/port/tcpinput.c
966a
h->frag[0] = 0;
h->frag[1] = 0;
.
816a
.
812a
nb->flags |= S_DELIM;
.
800a
if(bp->flags & S_DELIM)
nb->flags |= S_DELIM;
.
## diffname port/tcpinput.c 1992/0111
## diff -e /n/bootesdump/1992/0106/sys/src/9/port/tcpinput.c /n/bootesdump/1992/0111/sys/src/9/port/tcpinput.c
852c
close_self(Ipconv *s, char reason[])
.
264c
close_self(s, Enoerror);
.
6c
#include "../port/error.h"
.
## diffname port/tcpinput.c 1992/0128
## diff -e /n/bootesdump/1992/0111/sys/src/9/port/tcpinput.c /n/bootesdump/1992/0128/sys/src/9/port/tcpinput.c
833c
cleartcp(tcb);
.
826a
static void
cleartcp(struct Tctl *a)
{
memset(a, 0, sizeof(struct Tctl));
}
.
## diffname port/tcpinput.c 1992/0306
## diff -e /n/bootesdump/1992/0128/sys/src/9/port/tcpinput.c /n/bootesdump/1992/0306/sys/src/9/port/tcpinput.c
88a
qunlock(s);
.
87a
qlock(s);
.
## diffname port/tcpinput.c 1992/0310
## diff -e /n/bootesdump/1992/0306/sys/src/9/port/tcpinput.c /n/bootesdump/1992/0310/sys/src/9/port/tcpinput.c
662d
651,652c
long dupcnt;
long excess;
ushort len;
.
561c
tcb->rcv.up = tcb->rcv.nxt = seg->seq + 1;
.
535,538c
/* All data is acked now */
.
426,428d
418,421d
416a
/* convince the other end that this reset is in band */
.
304,307d
301c
if(tcb->max_snd <= tcb->rcv.nxt-tcb->last_ack)
.
284a
default:
/* Ignore segment text */
freeb(bp);
break;
.
283c
if(length != 0) {
.
280c
else if(seq_gt(tcb->rcv.nxt, tcb->rcv.up))
.
274,275c
if((seg.flags&URG) && seg.up) {
if(seq_gt(seg.up + seg.seq, tcb->rcv.up)) {
.
257c
if(tcb->sndcnt == 0) {
.
202c
if(seg.seq != tcb->rcv.nxt)
if(length != 0 || (seg.flags & (SYN|FIN))) {
.
## diffname port/tcpinput.c 1992/0313
## diff -e /n/bootesdump/1992/0310/sys/src/9/port/tcpinput.c /n/bootesdump/1992/0313/sys/src/9/port/tcpinput.c
657c
if(len == 0)
if(seg->seq == tcb->rcv.nxt)
.
489a
if(!(tcb->flags & RETRAN)) {
.
488d
486c
if(run_timer(&tcb->rtt_timer))
if(seq_ge(seg->ack, tcb->rttseq)) {
.
461a
.
458,460c
if(seq_ge(seg->ack,tcb->snd.wl2))
if(seq_gt(seg->seq,tcb->snd.wl1) || (seg->seq == tcb->snd.wl1)) {
if(seg->wnd != 0)
if(tcb->snd.wnd == 0)
.
361,396d
296c
if(bp)
if(s->readq) {
.
196c
if(length)
if(s->readq == 0) {
.
163a
.
159c
if(seg.flags & ACK)
if(PREC(tos) != PREC(tcb->tos)){
.
## diffname port/tcpinput.c 1992/0318
## diff -e /n/bootesdump/1992/0313/sys/src/9/port/tcpinput.c /n/bootesdump/1992/0318/sys/src/9/port/tcpinput.c
751,790d
## diffname port/tcpinput.c 1992/0319
## diff -e /n/bootesdump/1992/0318/sys/src/9/port/tcpinput.c /n/bootesdump/1992/0319/sys/src/9/port/tcpinput.c
978a
}
void
tcpdumpconv(Ipconv *c)
{
if(c->tcpctl.state == Closed)
return;
print("%s %d -> %d.%d.%d.%d/%d snd %d recv %d una %d nxt %d ptr %d wnd %d\n",
tcpstate[c->tcpctl.state],
c->psrc,
fmtaddr(c->dst),
c->pdst,
c->tcpctl.sndcnt,
c->tcpctl.rcvcnt,
c->tcpctl.snd.una,
c->tcpctl.snd.nxt,
c->tcpctl.snd.ptr,
c->tcpctl.snd.wnd);
}
void
tcpdump(void)
{
Ipifc *ep, *ifp;
Ipconv *cp, *ecp;
extern Ipifc *ipifc;
ep = &ipifc[conf.ipif];
for(ifp = ipifc; ifp < ep; ifp++)
if(strcmp(ifp->name, "TCP") == 0) {
ecp = &ifp->connections[conf.ip];
for(cp = ifp->connections; cp < ecp; cp++)
tcpdumpconv(cp);
break;
}
.
883c
data = padb(data, hdrlen + TCP_PKT);
if(data == 0)
.
350c
while(tcb->reseq != 0) {
if(seq_ge(tcb->rcv.nxt, tcb->reseq->seg.seq) == 0)
break;
.
300a
print("bl %d ty %d\n", blen(bp), bp->rptr[0]);
for(f = bp; bp->next; f = f->next)
;
if((f->flags&S_DELIM) == 0) {
print("No delim upstream rcp");
f->flags |= S_DELIM;
}
.
292a
.
44a
Block *f;
.
## diffname port/tcpinput.c 1992/0320
## diff -e /n/bootesdump/1992/0319/sys/src/9/port/tcpinput.c /n/bootesdump/1992/0320/sys/src/9/port/tcpinput.c
991,1026d
484d
478c
if(rtt > tcb->srtt)
abserr = rtt - tcb->srtt;
else
abserr = tcb->srtt - rtt;
.
470,471c
if((tcb->flags&RETRAN) == 0) {
.
303,309d
47,48d
45d
## diffname port/tcpinput.c 1992/0321
## diff -e /n/bootesdump/1992/0320/sys/src/9/port/tcpinput.c /n/bootesdump/1992/0321/sys/src/9/port/tcpinput.c
2c
#include "../port/lib.h"
.
## diffname port/tcpinput.c 1992/0325
## diff -e /n/bootesdump/1992/0321/sys/src/9/port/tcpinput.c /n/bootesdump/1992/0325/sys/src/9/port/tcpinput.c
810,818d
700,703d
688c
pullb(Block **bph, int count)
.
663c
pullb(bp, (ushort)dupcnt);
.
545,546c
static int start;
start += 250000;
tcb->iss = start;
tcb->rttseq = tcb->iss;
tcb->snd.wl2 = tcb->iss;
tcb->snd.una = tcb->iss;
.
487c
pullb(&tcb->sndq, acked);
.
366,413d
279c
pullb(&bp, seg.up);
.
193,195c
/* If we dont understand answer with a rst */
.
112c
process:
/* The rest of the input state machine is run with the control block
* locked
*/
.
68c
/* Look for a connection, failing that attempt to establish a listen */
.
34a
reset(Ipaddr source, Ipaddr dest, char tos, ushort length, Tcp *seg)
{
Block *hbp;
Port tmp;
char rflags;
Tcphdr ph;
if(seg->flags & RST)
return;
hnputl(ph.tcpsrc, dest);
hnputl(ph.tcpdst, source);
ph.proto = IP_TCPPROTO;
hnputs(ph.tcplen, TCP_HDRSIZE);
/* Swap port numbers */
tmp = seg->dest;
seg->dest = seg->source;
seg->source = tmp;
rflags = RST;
/* convince the other end that this reset is in band */
if(seg->flags & ACK) {
seg->seq = seg->ack;
seg->ack = 0;
}
else {
rflags |= ACK;
seg->ack = seg->seq;
seg->seq = 0;
if(seg->flags & SYN)
seg->ack++;
seg->ack += length;
if(seg->flags & FIN)
seg->ack++;
}
seg->flags = rflags;
seg->wnd = 0;
seg->up = 0;
seg->mss = 0;
if((hbp = htontcp(seg, 0, &ph)) == 0)
return;
PUTNEXT(Ipoutput, hbp);
}
void
.
## diffname port/tcpinput.c 1992/0406
## diff -e /n/bootesdump/1992/0325/sys/src/9/port/tcpinput.c /n/bootesdump/1992/0406/sys/src/9/port/tcpinput.c
161c
.
156,159c
if(s == 0){
freeb(bp);
reset(source, dest, tos, length, &seg);
return;
}
.
154a
if(spec)
s = tcpincoming(ipc, spec, &seg, source);
else if(gen)
s = tcpincoming(ipc, gen, &seg, source);
else
s = 0;
.
120,153c
if(seg.flags & SYN){
/*
* find a listener specific to this port (spec) or,
* failing that, a general one (gen)
*/
spec = 0;
gen = 0;
e = &ipc[conf.ip];
for(s = ipc; s < e; s++) {
if(s->tcpctl.state == Listen)
if(s->pdst == 0)
if(s->dst == 0) {
if(s->psrc == seg.dest){
spec = s;
break;
}
if(s->psrc == 0)
gen = s;
}
.
85c
Ipconv *s, *e;
Ipconv *spec, *gen;
.
81a
Ipconv*
tcpincoming(Ipconv *ipc, Ipconv *s, Tcp *segp, Ipaddr source)
{
Ipconv *new;
if(s->curlog >= s->backlog)
return 0;
new = ipincoming(ipc, s);
if(new == 0)
return 0;
qlock(s);
s->curlog++;
qunlock(s);
new->psrc = segp->dest;
new->pdst = segp->source;
new->dst = source;
memmove(&new->tcpctl, &s->tcpctl, sizeof(Tcpctl));
new->tcpctl.flags &= ~CLONE;
new->tcpctl.timer.arg = new;
new->tcpctl.timer.state = TIMER_STOP;
new->tcpctl.acktimer.arg = new;
new->tcpctl.acktimer.state = TIMER_STOP;
new->newcon = 1;
new->ipinterface = s->ipinterface;
s->ipinterface->ref++;
wakeup(&s->listenr);
return new;
}
.
## diffname port/tcpinput.c 1992/0414
## diff -e /n/bootesdump/1992/0406/sys/src/9/port/tcpinput.c /n/bootesdump/1992/0414/sys/src/9/port/tcpinput.c
106c
new->newcon = s;
.
## diffname port/tcpinput.c 1992/0416
## diff -e /n/bootesdump/1992/0414/sys/src/9/port/tcpinput.c /n/bootesdump/1992/0416/sys/src/9/port/tcpinput.c
822a
/* flush receive queue */
while(bp = getb(&tcb->rcvq))
freeb(bp);
.
818a
Block *bp;
.
813a
/*
* called with tcb locked
*/
.
373,375c
if(bp){
if(s->readq)
PUTNEXT(s->readq, bp);
else
putb(&tcb->rcvq, bp);
.
272c
if(s->readq == 0)
if(tcb->state == Closed) {
.
100c
tcpmove(&new->tcpctl, &s->tcpctl);
.
94d
92a
}
.
91c
if(new == 0){
qunlock(s);
.
88a
}
.
87c
qlock(s);
if(s->curlog >= s->backlog){
qunlock(s);
.
81a
/*
* flush an incoming call; send a reset to the remote side and close the
* conversation
*/
void
tcpflushincoming(Ipconv *s)
{
Tcp seg;
Tcpctl *tcb;
tcb = &s->tcpctl;
seg.source = s->pdst;
seg.dest = s->psrc;
seg.flags = ACK;
seg.seq = tcb->snd.ptr;
seg.ack = tcb->last_ack = tcb->rcv.nxt;
reset(s->dst, Myip[Myself], 0, 0, &seg);
close_self(s, 0);
}
static void
tcpmove(struct Tctl *to, struct Tctl *from)
{
memmove(to, from, sizeof(struct Tctl));
}
.
## diffname port/tcpinput.c 1992/0512
## diff -e /n/bootesdump/1992/0416/sys/src/9/port/tcpinput.c /n/bootesdump/1992/0512/sys/src/9/port/tcpinput.c
392c
if(length == 0)
freeb(bp);
else {
.
374a
freeb(bp);
.
## diffname port/tcpinput.c 1992/0527
## diff -e /n/bootesdump/1992/0512/sys/src/9/port/tcpinput.c /n/bootesdump/1992/0527/sys/src/9/port/tcpinput.c
399c
if(bp)
freeb(bp);
.
393,395c
if(length == 0){
if(bp)
freeb(bp);
} else {
.
## diffname port/tcpinput.c 1992/0606
## diff -e /n/bootesdump/1992/0527/sys/src/9/port/tcpinput.c /n/bootesdump/1992/0606/sys/src/9/port/tcpinput.c
631c
if((dropped++%256) == 0)
print("tcp: no resequence descriptors\n");
.
626a
static int dropped;
.
## diffname port/tcpinput.c 1992/0619
## diff -e /n/bootesdump/1992/0606/sys/src/9/port/tcpinput.c /n/bootesdump/1992/0619/sys/src/9/port/tcpinput.c
877,881c
free(rp);
.
680,683c
free(rp);
.
638,641d
636d
629,634c
rp = malloc(sizeof(Reseq));
if(rp == 0)
.
627d
23,34d
14,16d
## diffname port/tcpinput.c 1992/0626
## diff -e /n/bootesdump/1992/0619/sys/src/9/port/tcpinput.c /n/bootesdump/1992/0626/sys/src/9/port/tcpinput.c
586c
if((mtu = s->ifc->maxmtu) != 0) {
.
192c
s = tcpincoming(ifc, gen, &seg, source);
.
190c
s = tcpincoming(ifc, spec, &seg, source);
.
176,177c
etab = &ifc->conv[Nipconv];
for(p = ifc->conv; p < etab && *p; p++) {
s = *p;
.
167c
s = ip_conn(ifc, seg.dest, seg.source, source, IP_TCPPROTO);
.
133c
Ipconv *s, **p, **etab;
.
131c
tcp_input(Ipifc *ifc, Block *bp)
.
125d
123d
105c
new = ipincoming(ifc, s);
.
95c
tcpincoming(Ipifc *ifc, Ipconv *s, Tcp *segp, Ipaddr source)
.
## diffname port/tcpinput.c 1992/0711
## diff -e /n/bootesdump/1992/0626/sys/src/9/port/tcpinput.c /n/bootesdump/1992/0711/sys/src/9/port/tcpinput.c
972d
165c
s = ip_conn(ifc, seg.dest, seg.source, source);
.
26a
USED(tos); /* is this right??? */
.
## diffname port/tcpinput.c 1992/0724
## diff -e /n/bootesdump/1992/0711/sys/src/9/port/tcpinput.c /n/bootesdump/1992/0724/sys/src/9/port/tcpinput.c
616a
}
.
615c
if(rp == 0){
freeb(bp); /* bp always consumed by add_reseq */
.
411a
case Finwait2:
/* no process to read the data, send a reset */
if(bp)
freeb(bp);
reset(source, dest, tos, length, &seg);
goto done;
.
393d
166c
/* Look for a connection. failing that look for a listener. */
.
## diffname port/tcpinput.c 1992/0807
## diff -e /n/bootesdump/1992/0724/sys/src/9/port/tcpinput.c /n/bootesdump/1992/0807/sys/src/9/port/tcpinput.c
382c
}
else {
.
17c
"Closing", "Last_ack", "Time_wait"
};
.
14c
char *tcpstate[] =
{
.
## diffname port/tcpinput.c 1992/0826
## diff -e /n/bootesdump/1992/0807/sys/src/9/port/tcpinput.c /n/bootesdump/1992/0826/sys/src/9/port/tcpinput.c
842c
localclose(Ipconv *s, char reason[])
.
691c
/* Some part of the segment should be in the window */
.
564d
554,556d
551c
if(seq_gt(seg->ack, tcb->snd.up))
.
540d
536d
532,534c
rtt = abs(rtt - tcb->srtt);
tcb->mdev = ((DGAIN-1)*tcb->mdev + rtt) / DGAIN;
.
527,530d
522c
rtt *= MSPTICK;
.
520a
tcb->backoff = 0;
.
516c
/* Adjust the timers acorrding to the round trip time */
.
500a
/* Compute the new send window size */
.
479,480d
475a
int rtt;
.
465d
462c
break;
.
460a
.
459a
.
456a
.
418c
sndrst(source, dest, tos, length, &seg);
.
396c
/* If we still have some data place on receive queue */
.
364c
localclose(s, Enoerror);
.
336c
sndrst(source, dest, tos, length, &seg);
.
319c
sndrst(source, dest, tos, length, &seg);
.
311c
localclose(s, Econrefused);
.
297a
/* The segment is beyond the current receive pointer so
* queue the data in the resequence queue
*/
.
294c
sndrst(source, dest, tos, length, &seg);
.
289c
/* Cannot accept so answer with a rst */
.
280c
/* Cut the data to fit the receive window */
.
256c
sndrst(source, dest, tos, length, &seg);
.
248c
localclose(s, Econrefused);
.
242c
sndrst(source, dest, tos, length, &seg);
.
224c
sndrst(source, dest, tos, length, &seg);
.
215c
sndrst(source, dest, tos, length, &seg);
.
201c
sndrst(source, dest, tos, length, &seg);
.
162c
/* trim the packet to the size claimed by the datagram */
.
88,89c
sndrst(s->dst, Myip[Myself], 0, 0, &seg);
localclose(s, 0);
.
22c
sndrst(Ipaddr source, Ipaddr dest, char tos, ushort length, Tcp *seg)
.
## diffname port/tcpinput.c 1992/0903
## diff -e /n/bootesdump/1992/0826/sys/src/9/port/tcpinput.c /n/bootesdump/1992/0903/sys/src/9/port/tcpinput.c
1007c
optr = h->tcpopt;
for(i = TCP_HDRSIZE; i < hdrlen;) {
.
909c
tcpxstate(s, oldstate, newstate);
.
902c
tcpsetstate(Ipconv *s, char newstate)
.
860c
tcpsetstate(s, Closed);
.
843,844c
tcphalt(&tcb->timer);
tcphalt(&tcb->rtt_timer);
.
829,830c
tcb->acktimer.func = tcpacktimer;
tcb->acktimer.arg = s;
.
826,827d
823,824c
tcb->timer.func = tcptimeout;
tcb->timer.arg = s;
.
821d
651c
rp = tcb->reseq;
if(rp == 0)
.
642a
rp1 = rp1->next;
.
633,641c
return;
}
for(;;) {
if(rp1->next == 0 || seq_lt(seg->seq, rp1->next->seg.seq)) {
rp->next = rp1->next;
rp1->next = rp;
break;
.
598c
tcpsndsyn(Tcpctl *tcb)
.
555c
tcpgo(&tcb->timer);
.
553c
tcphalt(&tcb->timer);
.
524c
tcphalt(&tcb->rtt_timer);
.
473c
tcpoutput(s);
.
461c
while(tcb->reseq) {
.
456c
tcpgo(&tcb->timer);
.
449c
tcpgo(&tcb->timer);
.
447c
tcpsetstate(s, Time_wait);
.
443c
tcpsetstate(s, Closing);
.
440c
tcpgo(&tcb->timer);
.
438c
tcpsetstate(s, Time_wait);
.
433c
tcpsetstate(s, Close_wait);
.
421c
sndrst(source, dest, length, &seg);
.
412c
tcpgo(&tcb->acktimer);
.
372c
tcpgo(&tcb->timer);
.
360c
tcpgo(&tcb->timer);
.
358c
tcpsetstate(s, Time_wait);
.
350c
tcpsetstate(s, Finwait2);
.
342c
update(s, &seg);
tcpsetstate(s, Established);
.
339c
sndrst(source, dest, length, &seg);
.
333,337c
if(!seq_within(seg.ack, tcb->snd.una+1, tcb->snd.nxt)){
.
322c
sndrst(source, dest, length, &seg);
.
319a
/* This tos stuff should be removed */
.
312c
tcpsetstate(s, Listen);
.
294c
sndrst(source, dest, length, &seg);
.
267c
tcpsetstate(s, Syn_received);
.
264c
tcpsetstate(s, Established);
.
256c
sndrst(source, dest, length, &seg);
.
242c
sndrst(source, dest, length, &seg);
.
229,230c
tcpsndsyn(tcb);
tcpsetstate(s, Syn_received);
.
224c
sndrst(source, dest, length, &seg);
.
215c
sndrst(source, dest, length, &seg);
.
201c
sndrst(source, dest, length, &seg);
.
133c
tcpinput(Ipifc *ifc, Block *bp)
.
88c
sndrst(s->dst, Myip[Myself], 0, &seg);
.
29,30d
22c
sndrst(Ipaddr source, Ipaddr dest, ushort length, Tcp *seg)
.
## diffname port/tcpinput.c 1992/0906
## diff -e /n/bootesdump/1992/0903/sys/src/9/port/tcpinput.c /n/bootesdump/1992/0906/sys/src/9/port/tcpinput.c
913a
ushort csum;
ushort hdrlen;
.
911d
909d
900a
tcb = &s->tcpctl;
.
899d
897a
Tcpctl *tcb;
.
797,799d
686,687c
else
if(len != 0) {
.
684c
if(in_window(tcb,seg->seq))
.
205c
* locked and implements the state machine directly out of the RFC
* Out-of-band data is ignored - it was always a bad idea.
.
141a
Ipconv *spec, *gen;
Ipaddr source, dest;
Ipconv *s, **p, **etab;
.
140a
Tcphdr *h;
int hdrlen;
Tcpctl *tcb;
.
138,139d
133,136d
123c
new->tcpctl.acktimer.state = TimerOFF;
.
121c
new->tcpctl.timer.state = TimerOFF;
.
10c
int tcpdbg = 0;
ushort tcp_mss = DEF_MSS; /* Maximum segment size to be sent with SYN */
int tcp_irtt = DEF_RTT; /* Initial guess at round trip time */
.
## diffname port/tcpinput.c 1992/1221
## diff -e /n/bootesdump/1992/0906/sys/src/9/port/tcpinput.c /n/bootesdump/1992/1221/sys/src/9/port/tcpinput.c
561a
if(tcb->sndfull && tcb->sndcnt < Streamhi/2){
wakeup(&tcb->sndr);
tcb->sndfull = 0;
}
.
## diffname port/tcpinput.c 1993/0218
## diff -e /n/bootesdump/1992/1221/sys/src/9/port/tcpinput.c /n/bootesdump/1993/0218/sys/src/9/port/tcpinput.c
415a
.
414c
if(tcb->rcv.nxt-tcb->last_ack > Streamhi/2)
.
412c
if(tcb->acktimer.state != TimerON)
tcpgo(&tcb->acktimer);
.
87c
tcb->last_ack = tcb->rcv.nxt;
seg.ack = tcb->rcv.nxt;
.
## diffname port/tcpinput.c 1993/0220
## diff -e /n/bootesdump/1993/0218/sys/src/9/port/tcpinput.c /n/bootesdump/1993/0220/sys/src/9/port/tcpinput.c
901c
return x >= y;
.
899c
seq_ge(ulong x, ulong y)
.
895c
return x > y;
.
893c
seq_gt(ulong x, ulong y)
.
889c
return x <= y;
.
887c
seq_le(ulong x, ulong y)
.
883c
return x < y;
.
881c
seq_lt(ulong x, ulong y)
.
867c
seq_within(ulong x, ulong low, ulong high)
.
700,701c
if(in_window(tcb, seg->seq+len-1) ||
seq_within(tcb->rcv.nxt, seg->seq,seg->seq+len-1))
.
575c
return seq_within(seq, tcb->rcv.nxt, tcb->rcv.nxt+tcb->rcv.wnd-1);
.
473d
466c
goto output;
.
464c
/*
* get next adjacent segment from the requence queue.
* dump/trim any overlapping segments
*/
for(;;) {
if(tcb->reseq == 0)
goto output;
.
310a
/*
* keep looping till we've processed this packet plus any
* adjacent packets in the resequence queue
*/
.
## diffname port/tcpinput.c 1993/0501
## diff -e /n/bootesdump/1993/0220/sys/src/9/port/tcpinput.c /n/fornaxdump/1993/0501/sys/src/brazil/port/tcpinput.c
911c
return (long)(x-y) >= 0;
.
909c
seq_ge(int x, int y)
.
905c
return (long)(x-y) > 0;
.
903c
seq_gt(int x, int y)
.
899c
return (long)(x-y) <= 0;
.
897c
seq_le(int x, int y)
.
893c
return (long)(x-y) < 0;
.
891c
seq_lt(int x, int y)
.
877c
seq_within(int x, int low, int high)
.
710,711c
if(in_window(tcb, (int)(seg->seq+len-1)) ||
seq_within(tcb->rcv.nxt, seg->seq,(int)(seg->seq+len-1)))
.
585c
return seq_within(seq, tcb->rcv.nxt, (int)(tcb->rcv.nxt+tcb->rcv.wnd-1));
.
483a
break;
.
477c
break;
.
468,475c
while(tcb->reseq) {
.
422d
420c
if(tcb->max_snd <= tcb->rcv.nxt-tcb->last_ack)
.
417,418c
tcpgo(&tcb->acktimer);
.
311,314d
87,88c
seg.ack = tcb->last_ack = tcb->rcv.nxt;
.
## diffname port/tcpinput.c 1993/0804 # deleted
## diff -e /n/fornaxdump/1993/0501/sys/src/brazil/port/tcpinput.c /n/fornaxdump/1993/0804/sys/src/brazil/port/tcpinput.c
1,1026d
|