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