Annotation of lucent/sys/src/9/port/tcpinput.c, revision 1.1

1.1     ! root        1: #include       "u.h"
        !             2: #include       "../port/lib.h"
        !             3: #include       "mem.h"
        !             4: #include       "dat.h"
        !             5: #include       "fns.h"
        !             6: #include       "../port/error.h"
        !             7: #include       "arp.h"
        !             8: #include       "../port/ipdat.h"
        !             9: 
        !            10: int    tcpdbg = 0;
        !            11: ushort tcp_mss = DEF_MSS;      /* Maximum segment size to be sent with SYN */
        !            12: int    tcp_irtt = DEF_RTT;     /* Initial guess at round trip time */
        !            13: 
        !            14: #define DPRINT if(tcpdbg) print
        !            15: #define LPRINT  if(tcpdbg) print
        !            16: 
        !            17: char *tcpstate[] =
        !            18: {
        !            19:        "Closed",       "Listen",       "Syn_sent", "Syn_received",
        !            20:        "Established",  "Finwait1",     "Finwait2", "Close_wait",
        !            21:        "Closing",      "Last_ack",     "Time_wait"
        !            22: };
        !            23: 
        !            24: void
        !            25: sndrst(Ipaddr source, Ipaddr dest, ushort length, Tcp *seg)
        !            26: {
        !            27:        Block *hbp;
        !            28:        Port tmp;
        !            29:        char rflags;
        !            30:        Tcphdr ph;
        !            31: 
        !            32:        if(seg->flags & RST)
        !            33:                return;
        !            34: 
        !            35:        hnputl(ph.tcpsrc, dest);
        !            36:        hnputl(ph.tcpdst, source);
        !            37:        ph.proto = IP_TCPPROTO;
        !            38:        hnputs(ph.tcplen, TCP_HDRSIZE);
        !            39: 
        !            40:        /* Swap port numbers */
        !            41:        tmp = seg->dest;
        !            42:        seg->dest = seg->source;
        !            43:        seg->source = tmp;
        !            44: 
        !            45:        rflags = RST;
        !            46: 
        !            47:        /* convince the other end that this reset is in band */
        !            48:        if(seg->flags & ACK) {
        !            49:                seg->seq = seg->ack;
        !            50:                seg->ack = 0;
        !            51:        }
        !            52:        else {
        !            53:                rflags |= ACK;
        !            54:                seg->ack = seg->seq;
        !            55:                seg->seq = 0;
        !            56:                if(seg->flags & SYN)
        !            57:                        seg->ack++;
        !            58:                seg->ack += length;
        !            59:                if(seg->flags & FIN)
        !            60:                        seg->ack++;
        !            61:        }
        !            62:        seg->flags = rflags;
        !            63:        seg->wnd = 0;
        !            64:        seg->up = 0;
        !            65:        seg->mss = 0;
        !            66:        if((hbp = htontcp(seg, 0, &ph)) == 0)
        !            67:                return;
        !            68: 
        !            69:        ipmuxoput(0, hbp);
        !            70: }
        !            71: 
        !            72: /*
        !            73:  *  flush an incoming call; send a reset to the remote side and close the
        !            74:  *  conversation
        !            75:  */
        !            76: void
        !            77: tcpflushincoming(Ipconv *s)
        !            78: {
        !            79:        Tcp seg;
        !            80:        Tcpctl *tcb;
        !            81:        uchar dst[4];           
        !            82: 
        !            83:        tcb = &s->tcpctl;
        !            84:        seg.source = s->pdst;
        !            85:        seg.dest = s->psrc;
        !            86:        seg.flags = ACK;        
        !            87:        seg.seq = tcb->snd.ptr;
        !            88:        tcb->last_ack = tcb->rcv.nxt;
        !            89:        seg.ack = tcb->rcv.nxt;
        !            90: 
        !            91:        if(s->src == 0){
        !            92:                hnputl(dst, s->dst);
        !            93:                s->src = ipgetsrc(dst);
        !            94:        }
        !            95:        sndrst(s->dst, s->src, 0, &seg);
        !            96:        localclose(s, 0);
        !            97: }
        !            98: 
        !            99: static void
        !           100: tcpmove(struct Tctl *to, struct Tctl *from)
        !           101: {
        !           102:        memmove(to, from, sizeof(struct Tctl));
        !           103: }
        !           104: 
        !           105: Ipconv*
        !           106: tcpincoming(Ipifc *ifc, Ipconv *s, Tcp *segp, Ipaddr source, Ipaddr dest)
        !           107: {
        !           108:        Ipconv *new;
        !           109: 
        !           110:        qlock(s);
        !           111:        if(s->curlog >= s->backlog){
        !           112:                qunlock(s);
        !           113:                return 0;
        !           114:        }
        !           115: 
        !           116:        new = ipincoming(ifc, s);
        !           117:        if(new == 0){
        !           118:                qunlock(s);
        !           119:                return 0;
        !           120:        }
        !           121: 
        !           122:        s->curlog++;
        !           123:        qunlock(s);
        !           124:        new->psrc = segp->dest;
        !           125:        new->pdst = segp->source;
        !           126:        new->dst = source;
        !           127:        new->src = dest;
        !           128:        tcpmove(&new->tcpctl, &s->tcpctl);
        !           129:        new->tcpctl.flags &= ~CLONE;
        !           130:        new->tcpctl.timer.arg = new;
        !           131:        new->tcpctl.timer.state = TimerOFF;
        !           132:        new->tcpctl.acktimer.arg = new;
        !           133:        new->tcpctl.acktimer.state = TimerOFF;
        !           134:        new->newcon = s;
        !           135: 
        !           136:        wakeup(&s->listenr);
        !           137:        return new;
        !           138: }
        !           139: 
        !           140: void
        !           141: tcpinput(Ipifc *ifc, Block *bp)
        !           142: {
        !           143:        Tcp seg;
        !           144:        char tos;
        !           145:        Tcphdr *h;
        !           146:        int hdrlen;     
        !           147:        Tcpctl *tcb;            
        !           148:        ushort length;
        !           149:        Ipconv *spec, *gen;
        !           150:        Ipaddr source, dest;
        !           151:        Ipconv *s, **p, **etab;
        !           152: 
        !           153:        h = (Tcphdr *)(bp->rptr);
        !           154:        dest = nhgetl(h->tcpdst);
        !           155:        source = nhgetl(h->tcpsrc);
        !           156: 
        !           157:        tos = h->tos;
        !           158:        length = nhgets(h->length);
        !           159: 
        !           160:        h->Unused = 0;
        !           161:        hnputs(h->tcplen, length - (TCP_IPLEN+TCP_PHDRSIZE));
        !           162:        if(ptcl_csum(bp, TCP_EHSIZE+TCP_IPLEN, length - TCP_IPLEN)) {
        !           163:                freeb(bp);
        !           164:                return;
        !           165:        }
        !           166: 
        !           167:        if((hdrlen = ntohtcp(&seg, &bp)) < 0)
        !           168:                return;
        !           169: 
        !           170:        /* trim the packet to the size claimed by the datagram */
        !           171:        length -= (hdrlen+TCP_IPLEN+TCP_PHDRSIZE);
        !           172:        bp = btrim(bp, hdrlen+TCP_PKT, length);
        !           173:        if(bp == 0)
        !           174:                return;
        !           175:        
        !           176:        /* Look for a connection. failing that look for a listener. */
        !           177:        s = ip_conn(ifc, seg.dest, seg.source, source);
        !           178:        if(s && s->tcpctl.state == Listen)
        !           179:                s = 0;  /* can't talk directly to a listener */
        !           180: 
        !           181:        if (s == 0) {
        !           182:                if(seg.flags & SYN){
        !           183:                        /*
        !           184:                         *  dump packets with bogus flags
        !           185:                         */
        !           186:                        if(seg.flags & RST){
        !           187:                                freeb(bp);
        !           188:                                return;
        !           189:                        }
        !           190:                        if(seg.flags & ACK) {
        !           191:                                freeb(bp);
        !           192:                                sndrst(source, dest, length, &seg);
        !           193:                                return;
        !           194:                        }
        !           195: 
        !           196:                        /*
        !           197:                         *  find a listener specific to this port (spec) or,
        !           198:                         *  failing that, a general one (gen)
        !           199:                         */
        !           200:                        spec = 0;
        !           201:                        gen = 0;
        !           202:                        etab = &ifc->conv[Nipconv];
        !           203:                        for(p = ifc->conv; p < etab && *p; p++) {
        !           204:                                s = *p;
        !           205:                                if(s->tcpctl.state == Listen)
        !           206:                                if(s->pdst == 0)
        !           207:                                if(s->dst == 0) {
        !           208:                                        if(s->psrc == seg.dest){
        !           209:                                                spec = s;
        !           210:                                                break;
        !           211:                                        }
        !           212:                                        if(s->psrc == 0)
        !           213:                                                gen = s;
        !           214:                                }
        !           215:                        }
        !           216:                        if(spec)
        !           217:                                s = tcpincoming(ifc, spec, &seg, source, dest);
        !           218:                        else if(gen)
        !           219:                                s = tcpincoming(ifc, gen, &seg, source, dest);
        !           220:                        else
        !           221:                                s = 0;
        !           222:                }
        !           223:                if(s == 0){
        !           224:                        freeb(bp);   
        !           225:                        sndrst(source, dest, length, &seg);
        !           226:                        return;
        !           227:                }
        !           228:        }
        !           229: 
        !           230:        /* The rest of the input state machine is run with the control block
        !           231:         * locked and implements the state machine directly out of the RFC
        !           232:         * Out-of-band data is ignored - it was always a bad idea.
        !           233:         */
        !           234:        tcb = &s->tcpctl;
        !           235:        qlock(tcb);
        !           236: 
        !           237:        switch(tcb->state) {
        !           238:        case Closed:
        !           239:                freeb(bp);
        !           240:                sndrst(source, dest, length, &seg);
        !           241:                goto done;
        !           242:        case Listen:
        !           243:                if((seg.flags & (SYN|RST|ACK)) != SYN) {
        !           244:                        /* ignore bogus packets */
        !           245: print("packet to channel in listen state %d <- %d\n", s->psrc, s->pdst);
        !           246:                        freeb(bp);
        !           247:                        goto done;
        !           248:                }
        !           249: 
        !           250:                proc_syn(s, tos, &seg);
        !           251:                tcpsndsyn(tcb);
        !           252:                tcpsetstate(s, Syn_received);           
        !           253:                if(length != 0 || (seg.flags & FIN)) 
        !           254:                        break;
        !           255:                freeb(bp);
        !           256:                goto output;
        !           257:        case Syn_sent:
        !           258:                if(seg.flags & ACK) {
        !           259:                        if(!seq_within(seg.ack, tcb->iss+1, tcb->snd.nxt)) {
        !           260:                                freeb(bp);
        !           261:                                sndrst(source, dest, length, &seg);
        !           262:                                goto done;
        !           263:                        }
        !           264:                }
        !           265:                if(seg.flags & RST) {
        !           266:                        if(seg.flags & ACK)
        !           267:                                localclose(s, Econrefused);
        !           268:                        freeb(bp);
        !           269:                        goto done;
        !           270:                }
        !           271: 
        !           272:                if(seg.flags & ACK)
        !           273:                if(PREC(tos) != PREC(tcb->tos)){
        !           274:                        freeb(bp);
        !           275:                        sndrst(source, dest, length, &seg);
        !           276:                        goto done;
        !           277:                }
        !           278: 
        !           279:                if(seg.flags & SYN) {
        !           280:                        proc_syn(s, tos, &seg);
        !           281:                        if(seg.flags & ACK){
        !           282:                                update(s, &seg);
        !           283:                                tcpsetstate(s, Established);
        !           284:                        }
        !           285:                        else 
        !           286:                                tcpsetstate(s, Syn_received);
        !           287: 
        !           288:                        if(length != 0 || (seg.flags & FIN))
        !           289:                                break;
        !           290: 
        !           291:                        freeb(bp);
        !           292:                        goto output;
        !           293:                }
        !           294:                else 
        !           295:                        freeb(bp);
        !           296:                goto done;
        !           297:        }
        !           298: 
        !           299:        /* Cut the data to fit the receive window */
        !           300:        if(trim(tcb, &seg, &bp, &length) == -1) {
        !           301:                if(!(seg.flags & RST)) {
        !           302:                        tcb->flags |= FORCE;
        !           303:                        goto output;
        !           304:                }
        !           305:                goto done;
        !           306:        }
        !           307: 
        !           308:        /* Cannot accept so answer with a rst */
        !           309:        if(length)
        !           310:        if(s->readq == 0)
        !           311:        if(tcb->state == Closed) {
        !           312:                freeb(bp);
        !           313:                sndrst(source, dest, length, &seg);
        !           314:                goto done;
        !           315:        }
        !           316: 
        !           317:        /* The segment is beyond the current receive pointer so
        !           318:         * queue the data in the resequence queue
        !           319:         */
        !           320:        if(seg.seq != tcb->rcv.nxt)
        !           321:        if(length != 0 || (seg.flags & (SYN|FIN))) {
        !           322:                add_reseq(tcb, tos, &seg, bp, length);
        !           323:                tcb->flags |= FORCE;
        !           324:                goto output;
        !           325:        }
        !           326: 
        !           327:        /*
        !           328:         *  keep looping till we've processed this packet plus any
        !           329:         *  adjacent packets in the resequence queue
        !           330:         */
        !           331:        for(;;) {
        !           332:                if(seg.flags & RST) {
        !           333:                        localclose(s, Econrefused);
        !           334: 
        !           335:                        freeb(bp);
        !           336:                        goto done;
        !           337:                }
        !           338: 
        !           339:                /* This tos stuff should be removed */
        !           340:                if(PREC(tos) != PREC(tcb->tos) || (seg.flags & SYN)){
        !           341:                        freeb(bp);
        !           342:                        sndrst(source, dest, length, &seg);
        !           343:                        goto done;
        !           344:                }
        !           345: 
        !           346:                if(!(seg.flags & ACK)) {
        !           347:                        freeb(bp);      
        !           348:                        goto done;
        !           349:                }
        !           350: 
        !           351:                switch(tcb->state) {
        !           352:                case Syn_received:
        !           353:                        if(!seq_within(seg.ack, tcb->snd.una+1, tcb->snd.nxt)){
        !           354:                                freeb(bp);
        !           355:                                sndrst(source, dest, length, &seg);
        !           356:                                goto done;
        !           357:                        }
        !           358:                        update(s, &seg);
        !           359:                        tcpsetstate(s, Established);
        !           360:                case Established:
        !           361:                case Close_wait:
        !           362:                        update(s, &seg);
        !           363:                        break;
        !           364:                case Finwait1:
        !           365:                        update(s, &seg);
        !           366:                        if(tcb->sndcnt == 0){
        !           367:                                tcb->kacounter = MAXBACKOFF;
        !           368:                                tcpsetstate(s, Finwait2);
        !           369:                                tcb->timer.start = MSL2 * (1000 / MSPTICK);
        !           370:                                tcpgo(&tcb->timer);
        !           371:                        }
        !           372:                        break;
        !           373:                case Finwait2:
        !           374:                        update(s, &seg);
        !           375:                        break;
        !           376:                case Closing:
        !           377:                        update(s, &seg);
        !           378:                        if(tcb->sndcnt == 0) {
        !           379:                                tcpsetstate(s, Time_wait);
        !           380:                                tcb->timer.start = MSL2 * (1000 / MSPTICK);
        !           381:                                tcpgo(&tcb->timer);
        !           382:                        }
        !           383:                        break;
        !           384:                case Last_ack:
        !           385:                        update(s, &seg);
        !           386:                        if(tcb->sndcnt == 0) {
        !           387:                                freeb(bp);
        !           388:                                localclose(s, 0);
        !           389:                                goto done;
        !           390:                        }                       
        !           391:                case Time_wait:
        !           392:                        tcb->flags |= FORCE;
        !           393:                        tcpgo(&tcb->timer);
        !           394:                }
        !           395: 
        !           396:                if((seg.flags&URG) && seg.up) {
        !           397:                        if(seq_gt(seg.up + seg.seq, tcb->rcv.up)) {
        !           398:                                tcb->rcv.up = seg.up + seg.seq;
        !           399:                                pullb(&bp, seg.up);
        !           400:                        }
        !           401:                } 
        !           402:                else if(seq_gt(tcb->rcv.nxt, tcb->rcv.up))
        !           403:                        tcb->rcv.up = tcb->rcv.nxt;
        !           404: 
        !           405:                if(length == 0){
        !           406:                        if(bp)
        !           407:                                freeb(bp);
        !           408:                }
        !           409:                else {
        !           410:                        switch(tcb->state){
        !           411:                        default:
        !           412:                                /* Ignore segment text */
        !           413:                                if(bp)
        !           414:                                        freeb(bp);
        !           415:                                break;
        !           416: 
        !           417:                        case Syn_received:
        !           418:                        case Established:
        !           419:                        case Finwait1:
        !           420:                                /* If we still have some data place on receive queue */
        !           421:                                tcb->rcvcnt += blen(bp);
        !           422:                                if(bp){
        !           423:                                        if(s->readq)
        !           424:                                                PUTNEXT(s->readq, bp);
        !           425:                                        else
        !           426:                                                putb(&tcb->rcvq, bp);
        !           427:                                        bp = 0;
        !           428:                                }
        !           429:                                tcb->rcv.nxt += length;
        !           430: 
        !           431:                                tcprcvwin(s);
        !           432:        
        !           433:                                if(tcb->acktimer.state != TimerON)
        !           434:                                        tcpgo(&tcb->acktimer);
        !           435: 
        !           436:                                if(tcb->rcv.nxt-tcb->last_ack > Streamhi/2)
        !           437:                                        tcb->flags |= FORCE;
        !           438: 
        !           439:                                break;
        !           440:                        case Finwait2:
        !           441:                                /* no process to read the data, send a reset */
        !           442:                                if(bp)
        !           443:                                        freeb(bp);
        !           444:                                sndrst(source, dest, length, &seg);
        !           445:                                goto done;
        !           446:                        }
        !           447:                }
        !           448: 
        !           449:                if(seg.flags & FIN) {
        !           450:                        tcb->flags |= FORCE;
        !           451: 
        !           452:                        switch(tcb->state) {
        !           453:                        case Syn_received:
        !           454:                        case Established:
        !           455:                                tcb->rcv.nxt++;
        !           456:                                tcpsetstate(s, Close_wait);
        !           457:                                break;
        !           458:                        case Finwait1:
        !           459:                                tcb->rcv.nxt++;
        !           460:                                if(tcb->sndcnt == 0) {
        !           461:                                        tcpsetstate(s, Time_wait);
        !           462:                                        tcb->timer.start = MSL2 * (1000/MSPTICK);
        !           463:                                        tcpgo(&tcb->timer);
        !           464:                                }
        !           465:                                else 
        !           466:                                        tcpsetstate(s, Closing);
        !           467:                                break;
        !           468:                        case Finwait2:
        !           469:                                tcb->rcv.nxt++;
        !           470:                                tcpsetstate(s, Time_wait);
        !           471:                                tcb->timer.start = MSL2 * (1000/MSPTICK);
        !           472:                                tcpgo(&tcb->timer);
        !           473:                                break;
        !           474:                        case Close_wait:
        !           475:                        case Closing:
        !           476:                        case Last_ack:
        !           477:                                break;
        !           478:                        case Time_wait:
        !           479:                                tcpgo(&tcb->timer);
        !           480:                                break;
        !           481:                        }
        !           482:                }
        !           483: 
        !           484:                /*
        !           485:                 *  get next adjacent segment from the requence queue.
        !           486:                 *  dump/trim any overlapping segments
        !           487:                 */
        !           488:                for(;;) {
        !           489:                        if(tcb->reseq == 0)
        !           490:                                goto output;
        !           491: 
        !           492:                        if(seq_ge(tcb->rcv.nxt, tcb->reseq->seg.seq) == 0)
        !           493:                                goto output;
        !           494: 
        !           495:                        get_reseq(tcb, &tos, &seg, &bp, &length);
        !           496: 
        !           497:                        if(trim(tcb, &seg, &bp, &length) == 0)
        !           498:                                break;
        !           499:                }
        !           500:        }
        !           501: output:
        !           502:        tcpoutput(s);
        !           503: done:
        !           504:        qunlock(tcb);
        !           505: }
        !           506: 
        !           507: void
        !           508: update(Ipconv *s, Tcp *seg)
        !           509: {
        !           510:        int rtt;
        !           511:        ushort acked;
        !           512:        ushort expand;
        !           513:        Tcpctl *tcb = &s->tcpctl;
        !           514: 
        !           515:        tcb->kacounter = MAXBACKOFF;    /* keep alive count down */
        !           516: 
        !           517:        if(seq_gt(seg->ack, tcb->snd.nxt)) {
        !           518:                tcb->flags |= FORCE;
        !           519:                return;
        !           520:        }
        !           521: 
        !           522:        if(seq_ge(seg->ack,tcb->snd.wl2))
        !           523:        if(seq_gt(seg->seq,tcb->snd.wl1) || (seg->seq == tcb->snd.wl1)) {
        !           524:                if(seg->wnd != 0)
        !           525:                if(tcb->snd.wnd == 0)
        !           526:                        tcb->snd.ptr = tcb->snd.una;
        !           527: 
        !           528:                tcb->snd.wnd = seg->wnd;
        !           529:                tcb->snd.wl1 = seg->seq;
        !           530:                tcb->snd.wl2 = seg->ack;
        !           531:        }
        !           532: 
        !           533:        if(!seq_gt(seg->ack, tcb->snd.una))
        !           534:                return; 
        !           535: 
        !           536:        /* Compute the new send window size */
        !           537:        acked = seg->ack - tcb->snd.una;
        !           538:        if(tcb->cwind < tcb->snd.wnd) {
        !           539:                if(tcb->cwind < tcb->ssthresh)
        !           540:                        expand = MIN(acked,tcb->mss);
        !           541:                else
        !           542:                        expand = ((long)tcb->mss * tcb->mss) / tcb->cwind;
        !           543: 
        !           544:                if(tcb->cwind + expand < tcb->cwind)
        !           545:                        expand = 65535 - tcb->cwind;
        !           546:                if(tcb->cwind + expand > tcb->snd.wnd)
        !           547:                        expand = tcb->snd.wnd - tcb->cwind;
        !           548:                if(expand != 0)
        !           549:                        tcb->cwind += expand;
        !           550:        }
        !           551: 
        !           552:        /* Adjust the timers acorrding to the round trip time */
        !           553:        if(run_timer(&tcb->rtt_timer))
        !           554:        if(seq_ge(seg->ack, tcb->rttseq)) {
        !           555:                tcphalt(&tcb->rtt_timer);
        !           556:                if((tcb->flags&RETRAN) == 0) {
        !           557:                        tcb->backoff = 0;
        !           558:                        rtt = tcb->rtt_timer.start - tcb->rtt_timer.count;
        !           559:                        rtt *= MSPTICK;
        !           560:                        if(rtt > tcb->srtt &&
        !           561:                          (tcb->state == Syn_sent || tcb->state == Syn_received))
        !           562:                                tcb->srtt = rtt;
        !           563:                        else {
        !           564:                                tcb->srtt = ((AGAIN-1)*tcb->srtt + rtt) / AGAIN;
        !           565:                                rtt = abs(rtt - tcb->srtt);
        !           566:                                tcb->mdev = ((DGAIN-1)*tcb->mdev + rtt) / DGAIN;
        !           567:                        }
        !           568:                }
        !           569:        }
        !           570: 
        !           571:        if((tcb->flags & SYNACK) == 0){
        !           572:                tcb->flags |= SYNACK;
        !           573:                acked--;
        !           574:                tcb->sndcnt--;
        !           575:        }
        !           576: 
        !           577:        pullb(&tcb->sndq, acked);
        !           578: 
        !           579:        tcb->sndcnt -= acked;
        !           580:        tcb->snd.una = seg->ack;
        !           581:        if(seq_gt(seg->ack, tcb->snd.up))
        !           582:                tcb->snd.up = seg->ack;
        !           583: 
        !           584:        tcphalt(&tcb->timer);
        !           585:        if(tcb->snd.una != tcb->snd.nxt)
        !           586:                tcpgo(&tcb->timer);
        !           587: 
        !           588:        if(seq_lt(tcb->snd.ptr, tcb->snd.una))
        !           589:                tcb->snd.ptr = tcb->snd.una;
        !           590: 
        !           591:        tcb->flags &= ~RETRAN;
        !           592:        tcb->backoff = 0;
        !           593: 
        !           594:        if(tcb->sndfull && tcb->sndcnt < Streamhi/2){
        !           595:                wakeup(&tcb->sndr);
        !           596:                tcb->sndfull = 0;
        !           597:        }
        !           598: }
        !           599: 
        !           600: int
        !           601: in_window(Tcpctl *tcb, int seq)
        !           602: {
        !           603:        return seq_within(seq, tcb->rcv.nxt, tcb->rcv.nxt+tcb->rcv.wnd-1);
        !           604: }
        !           605: 
        !           606: void
        !           607: proc_syn(Ipconv *s, char tos, Tcp *seg)
        !           608: {
        !           609:        Tcpctl *tcb = &s->tcpctl;
        !           610:        ushort mtu;
        !           611: 
        !           612: 
        !           613:        tcb->flags |= FORCE;
        !           614: 
        !           615:        if(PREC(tos) > PREC(tcb->tos))
        !           616:                tcb->tos = tos;
        !           617: 
        !           618:        tcb->rcv.up = tcb->rcv.nxt = seg->seq + 1;
        !           619:        tcb->snd.wl1 = tcb->irs = seg->seq;
        !           620:        tcb->snd.wnd = seg->wnd;
        !           621: 
        !           622:        if(seg->mss != 0)
        !           623:                tcb->mss = seg->mss;
        !           624: 
        !           625:        tcb->max_snd = seg->wnd;
        !           626: /* FIX MTU!!! */
        !           627:        if((mtu = 1500) != 0) {
        !           628:                mtu -= TCP_HDRSIZE + TCP_EHSIZE + TCP_PHDRSIZE; 
        !           629:                tcb->cwind = tcb->mss = MIN(mtu, tcb->mss);
        !           630:        }
        !           631: }
        !           632: 
        !           633: /* Generate an initial sequence number and put a SYN on the send queue */
        !           634: void
        !           635: tcpsndsyn(Tcpctl *tcb)
        !           636: {
        !           637:        static int start;
        !           638: 
        !           639:        if(start == 0)
        !           640:                start = rtctime();
        !           641:        else
        !           642:                start += 250000;
        !           643:        tcb->iss = start;
        !           644:        tcb->rttseq = tcb->iss;
        !           645:        tcb->snd.wl2 = tcb->iss;
        !           646:        tcb->snd.una = tcb->iss;
        !           647:        tcb->snd.ptr = tcb->snd.nxt = tcb->rttseq;
        !           648:        tcb->sndcnt++;
        !           649:        tcb->flags |= FORCE;
        !           650: }
        !           651: 
        !           652: void
        !           653: add_reseq(Tcpctl *tcb, char tos, Tcp *seg, Block *bp, ushort length)
        !           654: {
        !           655:        Reseq *rp, *rp1;
        !           656: 
        !           657:        rp = malloc(sizeof(Reseq));
        !           658:        if(rp == 0){
        !           659:                freeb(bp);      /* bp always consumed by add_reseq */
        !           660:                return;
        !           661:        }
        !           662: 
        !           663:        rp->seg = *seg;
        !           664:        rp->tos = tos;
        !           665:        rp->bp = bp;
        !           666:        rp->length = length;
        !           667: 
        !           668:        /* Place on reassembly list sorting by starting seq number */
        !           669:        rp1 = tcb->reseq;
        !           670:        if(rp1 == 0 || seq_lt(seg->seq, rp1->seg.seq)) {
        !           671:                rp->next = rp1;
        !           672:                tcb->reseq = rp;
        !           673:                return;
        !           674:        }
        !           675: 
        !           676:        for(;;) {
        !           677:                if(rp1->next == 0 || seq_lt(seg->seq, rp1->next->seg.seq)) {
        !           678:                        rp->next = rp1->next;
        !           679:                        rp1->next = rp;
        !           680:                        break;
        !           681:                }
        !           682:                rp1 = rp1->next;
        !           683:        }
        !           684: }
        !           685: 
        !           686: void
        !           687: get_reseq(Tcpctl *tcb, char *tos, Tcp *seg, Block **bp, ushort *length)
        !           688: {
        !           689:        Reseq *rp;
        !           690: 
        !           691:        rp = tcb->reseq;
        !           692:        if(rp == 0)
        !           693:                return;
        !           694: 
        !           695:        tcb->reseq = rp->next;
        !           696: 
        !           697:        *tos = rp->tos;
        !           698:        *seg = rp->seg;
        !           699:        *bp = rp->bp;
        !           700:        *length = rp->length;
        !           701: 
        !           702:        free(rp);
        !           703: }
        !           704: 
        !           705: int
        !           706: trim(Tcpctl *tcb, Tcp *seg, Block **bp, ushort *length)
        !           707: {
        !           708:        Block *nbp;
        !           709:        long dupcnt;
        !           710:        long excess;
        !           711:        ushort len;
        !           712:        char accept;
        !           713: 
        !           714:        accept = 0;
        !           715:        len = *length;
        !           716:        if(seg->flags & SYN)
        !           717:                len++;
        !           718:        if(seg->flags & FIN)
        !           719:                len++;
        !           720: 
        !           721:        if(tcb->rcv.wnd == 0) {
        !           722:                if(len == 0)
        !           723:                if(seg->seq == tcb->rcv.nxt)
        !           724:                        return 0;
        !           725:        }
        !           726:        else {
        !           727:                /* Some part of the segment should be in the window */
        !           728:                if(in_window(tcb,seg->seq))
        !           729:                        accept++;
        !           730:                else
        !           731:                if(len != 0) {
        !           732:                        if(in_window(tcb, seg->seq+len-1) || 
        !           733:                        seq_within(tcb->rcv.nxt, seg->seq,seg->seq+len-1))
        !           734:                                accept++;
        !           735:                }
        !           736:        }
        !           737:        if(!accept) {
        !           738:                freeb(*bp);
        !           739:                return -1;
        !           740:        }
        !           741:        dupcnt = tcb->rcv.nxt - seg->seq;
        !           742:        if(dupcnt > 0){
        !           743:                tcb->rerecv += dupcnt;
        !           744:                if(seg->flags & SYN){
        !           745:                        seg->flags &= ~SYN;
        !           746:                        seg->seq++;
        !           747: 
        !           748:                        if (seg->up > 1)
        !           749:                                seg->up--;
        !           750:                        else
        !           751:                                seg->flags &= ~URG;
        !           752:                        dupcnt--;
        !           753:                }
        !           754:                if(dupcnt > 0){
        !           755:                        pullb(bp, (ushort)dupcnt);
        !           756:                        seg->seq += dupcnt;
        !           757:                        *length -= dupcnt;
        !           758: 
        !           759:                        if (seg->up > dupcnt)
        !           760:                                seg->up -= dupcnt;
        !           761:                        else {
        !           762:                                seg->flags &= ~URG;
        !           763:                                seg->up = 0;
        !           764:                        }
        !           765:                }
        !           766:        }
        !           767:        excess = seg->seq + *length - (tcb->rcv.nxt + tcb->rcv.wnd);
        !           768:        if(excess > 0) {
        !           769:                tcb->rerecv += excess;
        !           770:                *length -= excess;
        !           771:                nbp = copyb(*bp, *length);
        !           772:                freeb(*bp);
        !           773:                *bp = nbp;
        !           774:                seg->flags &= ~FIN;
        !           775:        }
        !           776:        return 0;
        !           777: }
        !           778: 
        !           779: int
        !           780: pullb(Block **bph, int count)
        !           781: {
        !           782:        int n, bytes;
        !           783:        Block *bp;
        !           784: 
        !           785:        bytes = 0;
        !           786:        if(bph == 0)
        !           787:                return 0;
        !           788: 
        !           789:        while(*bph && count != 0) {
        !           790:                bp = *bph;
        !           791:                n = MIN(count, BLEN(bp));
        !           792:                bytes += n;
        !           793:                count -= n;
        !           794:                bp->rptr += n;
        !           795:                if(BLEN(bp) == 0) {
        !           796:                        *bph = bp->next;
        !           797:                        bp->next = 0;
        !           798:                        freeb(bp);
        !           799:                }
        !           800:        }
        !           801:        return bytes;
        !           802: }
        !           803: 
        !           804: int
        !           805: dupb(Block **hp, Block *bp, int offset, int count)
        !           806: {
        !           807:        int i, blen, bytes = 0;
        !           808:        uchar *addr;
        !           809:        
        !           810:        *hp = allocb(count);
        !           811:        if(*hp == 0)
        !           812:                return 0;
        !           813: 
        !           814:        /* Correct to front of data area */
        !           815:        while(bp && offset && offset >= BLEN(bp)) {
        !           816:                offset -= BLEN(bp);
        !           817:                bp = bp->next;
        !           818:        }
        !           819:        if(bp == 0)
        !           820:                return 0;
        !           821: 
        !           822:        addr = bp->rptr + offset;
        !           823:        blen = BLEN(bp) - offset;
        !           824: 
        !           825:        while(count) {
        !           826:                i = MIN(count, blen);
        !           827:                memmove((*hp)->wptr, addr, i);
        !           828:                (*hp)->wptr += i;
        !           829:                bytes += i;
        !           830:                count -= i;
        !           831:                bp = bp->next;
        !           832:                if(!bp)
        !           833:                        break;
        !           834:                blen = BLEN(bp);
        !           835:                addr = bp->rptr;
        !           836:        }
        !           837: 
        !           838:        return bytes;
        !           839: }
        !           840: 
        !           841: static void
        !           842: cleartcp(struct Tctl *a)
        !           843: {
        !           844:        memset(a, 0, sizeof(struct Tctl));
        !           845: }
        !           846: 
        !           847: void
        !           848: init_tcpctl(Ipconv *s)
        !           849: {
        !           850: 
        !           851:        Tcpctl *tcb = &s->tcpctl;
        !           852: 
        !           853:        cleartcp(tcb);
        !           854: 
        !           855:        tcb->cwind = tcb->mss = tcp_mss;
        !           856:        tcb->ssthresh = 65535;
        !           857:        tcb->srtt = tcp_irtt;
        !           858: 
        !           859:        tcb->timer.start = tcb->srtt / MSPTICK;
        !           860:        tcb->timer.func = tcptimeout;
        !           861:        tcb->timer.arg = s;
        !           862:        tcb->rtt_timer.start = MAX_TIME; 
        !           863:        tcb->acktimer.start = TCP_ACK / MSPTICK;
        !           864:        tcb->acktimer.func = tcpacktimer;
        !           865:        tcb->acktimer.arg = s;
        !           866: }
        !           867: 
        !           868: /*
        !           869:  *  called with tcb locked
        !           870:  */
        !           871: void
        !           872: localclose(Ipconv *s, char *reason)
        !           873: {
        !           874:        Reseq *rp,*rp1;
        !           875:        Tcpctl *tcb = &s->tcpctl;
        !           876:        Block *bp;
        !           877: 
        !           878:        tcphalt(&tcb->timer);
        !           879:        tcphalt(&tcb->rtt_timer);
        !           880:        s->err = reason;
        !           881: 
        !           882:        /* flush receive queue */
        !           883:        while(bp = getb(&tcb->rcvq))
        !           884:                freeb(bp);
        !           885: 
        !           886:        /* Flush reassembly queue; nothing more can arrive */
        !           887:        for(rp = tcb->reseq;rp != 0;rp = rp1){
        !           888:                rp1 = rp->next;
        !           889:                freeb(rp->bp);
        !           890:                free(rp);
        !           891:        }
        !           892: 
        !           893:        tcb->reseq = 0;
        !           894:        s->err = reason;
        !           895:        if(tcb->sndq != 0){
        !           896:                freeb(tcb->sndq);
        !           897:                tcb->sndq = 0;
        !           898:        }
        !           899:        tcpsetstate(s, Closed);
        !           900: }
        !           901: 
        !           902: int
        !           903: seq_within(ulong x, ulong low, ulong high)
        !           904: {
        !           905:        if(low <= high){
        !           906:                if(low <= x && x <= high)
        !           907:                        return 1;
        !           908:        }
        !           909:        else {
        !           910:                if(low >= x && x >= high)
        !           911:                        return 1;
        !           912:        }
        !           913:        return 0;
        !           914: }
        !           915: 
        !           916: int
        !           917: seq_lt(ulong x, ulong y)
        !           918: {
        !           919:        return x < y;
        !           920: }
        !           921: 
        !           922: int
        !           923: seq_le(ulong x, ulong y)
        !           924: {
        !           925:        return x <= y;
        !           926: }
        !           927: 
        !           928: int
        !           929: seq_gt(ulong x, ulong y)
        !           930: {
        !           931:        return x > y;
        !           932: }
        !           933: 
        !           934: int
        !           935: seq_ge(ulong x, ulong y)
        !           936: {
        !           937:        return x >= y;
        !           938: }
        !           939: 
        !           940: void
        !           941: tcpsetstate(Ipconv *s, char newstate)
        !           942: {
        !           943:        Tcpctl *tcb;
        !           944:        char oldstate;
        !           945: 
        !           946:        tcb = &s->tcpctl;
        !           947: 
        !           948:        oldstate = tcb->state;
        !           949:        tcb->state = newstate;
        !           950:        tcpxstate(s, oldstate, newstate);
        !           951: }
        !           952: 
        !           953: Block *
        !           954: htontcp(Tcp *tcph, Block *data, Tcphdr *ph)
        !           955: {
        !           956:        int dlen;
        !           957:        Tcphdr *h;
        !           958:        Block *bp;
        !           959:        ushort csum;
        !           960:        ushort hdrlen;
        !           961: 
        !           962:        hdrlen = TCP_HDRSIZE;
        !           963:        if(tcph->mss)
        !           964:                hdrlen += MSS_LENGTH;
        !           965: 
        !           966:        if(data) {
        !           967:                dlen = blen(data);      
        !           968:                data = padb(data, hdrlen + TCP_PKT);
        !           969:                if(data == 0)
        !           970:                        return 0;
        !           971:                /* If we collected blocks delimit the end of the chain */
        !           972:                for(bp = data; bp->next; bp = bp->next)
        !           973:                        bp->flags &= ~S_DELIM;
        !           974:                bp->flags |= S_DELIM;
        !           975:        }
        !           976:        else {
        !           977:                dlen = 0;
        !           978:                data = allocb(hdrlen + TCP_PKT);
        !           979:                if(data == 0)
        !           980:                        return 0;
        !           981:                data->wptr += hdrlen + TCP_PKT;
        !           982:                data->flags |= S_DELIM;
        !           983:        }
        !           984: 
        !           985: 
        !           986:        memmove(data->rptr, ph, TCP_PKT);
        !           987:        
        !           988:        h = (Tcphdr *)(data->rptr);
        !           989:        h->proto = IP_TCPPROTO;
        !           990:        h->frag[0] = 0;
        !           991:        h->frag[1] = 0;
        !           992:        hnputs(h->tcplen, hdrlen + dlen);
        !           993:        hnputs(h->tcpsport, tcph->source);
        !           994:        hnputs(h->tcpdport, tcph->dest);
        !           995:        hnputl(h->tcpseq, tcph->seq);
        !           996:        hnputl(h->tcpack, tcph->ack);
        !           997:        hnputs(h->tcpflag, (hdrlen<<10) | tcph->flags);
        !           998:        hnputs(h->tcpwin, tcph->wnd);
        !           999:        h->tcpcksum[0] = 0;
        !          1000:        h->tcpcksum[1] = 0;
        !          1001:        h->Unused = 0;
        !          1002:        hnputs(h->tcpurg, tcph->up);
        !          1003: 
        !          1004:        if(tcph->mss != 0){
        !          1005:                h->tcpopt[0] = MSS_KIND;
        !          1006:                h->tcpopt[1] = MSS_LENGTH;
        !          1007:                hnputs(h->tcpmss, tcph->mss);
        !          1008:        }
        !          1009:        csum = ptcl_csum(data, TCP_EHSIZE+TCP_IPLEN, hdrlen+dlen+TCP_PHDRSIZE);
        !          1010:        hnputs(h->tcpcksum, csum);
        !          1011: 
        !          1012:        return data;
        !          1013: }
        !          1014: 
        !          1015: int
        !          1016: ntohtcp(Tcp *tcph, Block **bpp)
        !          1017: {
        !          1018:        ushort hdrlen;
        !          1019:        ushort i, optlen;
        !          1020:        Tcphdr *h;
        !          1021:        uchar *optr;
        !          1022: 
        !          1023:        *bpp = pullup(*bpp, TCP_PKT+TCP_HDRSIZE);
        !          1024:        if(*bpp == 0)
        !          1025:                return -1;
        !          1026: 
        !          1027:        h = (Tcphdr *)((*bpp)->rptr);
        !          1028:        tcph->source = nhgets(h->tcpsport);
        !          1029:        tcph->dest = nhgets(h->tcpdport);
        !          1030:        tcph->seq = nhgetl(h->tcpseq);
        !          1031:        tcph->ack = nhgetl(h->tcpack);
        !          1032: 
        !          1033:        hdrlen = (h->tcpflag[0] & 0xf0) >> 2;
        !          1034:        if(hdrlen < TCP_HDRSIZE) {
        !          1035:                freeb(*bpp);
        !          1036:                return -1;
        !          1037:        }
        !          1038: 
        !          1039:        tcph->flags = h->tcpflag[1];
        !          1040:        tcph->wnd = nhgets(h->tcpwin);
        !          1041:        tcph->up = nhgets(h->tcpurg);
        !          1042:        tcph->mss = 0;
        !          1043: 
        !          1044:        *bpp = pullup(*bpp, hdrlen+TCP_PKT);
        !          1045:        if(!*bpp)
        !          1046:                return -1;
        !          1047: 
        !          1048:        optr = h->tcpopt;
        !          1049:        for(i = TCP_HDRSIZE; i < hdrlen;) {
        !          1050:                switch(*optr++){
        !          1051:                case EOL_KIND:
        !          1052:                        return hdrlen;
        !          1053:                case NOOP_KIND:
        !          1054:                        i++;
        !          1055:                        break;
        !          1056:                case MSS_KIND:
        !          1057:                        optlen = *optr++;
        !          1058:                        if(optlen == MSS_LENGTH)
        !          1059:                                tcph->mss = nhgets(optr);
        !          1060:                        i += optlen;
        !          1061:                        break;
        !          1062:                }
        !          1063:        }
        !          1064:        return hdrlen;
        !          1065: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.