Annotation of researchv10no/sys/io/devnonet.c, revision 1.1

1.1     ! root        1: #include       "u.h"
        !             2: #include       "lib.h"
        !             3: #include       "mem.h"
        !             4: #include       "dat.h"
        !             5: #include       "fns.h"
        !             6: #include       "io.h"
        !             7: #include       "errno.h"
        !             8: 
        !             9: #define NOW (MACHP(0)->ticks*MS2HZ)
        !            10: 
        !            11: enum {
        !            12:        /*
        !            13:         *  configuration parameters
        !            14:         */
        !            15:        Nconv = 32,             /* total number of active circuits */
        !            16:        Nifc = 2,               /* number of interfaces */
        !            17:        MSrexmit = 300,         /* retranmission interval in ms */
        !            18:        MSack = 50,             /* ms to sit on an ack */
        !            19: 
        !            20:        /*
        !            21:         *  relative or immutable
        !            22:         */
        !            23:        Ndir = Nconv + 1,       /* entries in the nonet directory */
        !            24:        Nsubdir = 2,            /* entries in the nonet directory */
        !            25:        Nmsg = 128,             /* max number of outstanding messages */
        !            26:        Nmask = Nmsg - 1,       /* mask for log(Nmsg) bits */
        !            27: };
        !            28: 
        !            29: typedef struct Hdr             Hdr;
        !            30: typedef struct Msg             Msg;
        !            31: typedef struct Conversation    Conversation;
        !            32: typedef struct Interface       Interface;
        !            33: typedef struct Etherhdr                Etherhdr;
        !            34: 
        !            35: /*
        !            36:  *  generic nonet header
        !            37:  */
        !            38: struct Hdr {
        !            39:        uchar   circuit[3];     /* circuit number */
        !            40:        uchar   flag;
        !            41:        uchar   mid;            /* message id */
        !            42:        uchar   ack;            /* piggy back ack */
        !            43:        uchar   remain[2];      /* count of remaing bytes of data */
        !            44:        uchar   sum[2];         /* checksum (0 means none) */
        !            45: };
        !            46: #define HDRSIZE 10
        !            47: #define NEWCALL        0x1             /* flag bit marking a new circuit */
        !            48: #define HANGUP 0x2             /* flag bit requesting hangup */
        !            49: #define ACKME 0x4              /* acknowledge this message */
        !            50: 
        !            51: /*
        !            52:  *  a buffer describing a nonet message
        !            53:  */
        !            54: struct Msg {
        !            55:        QLock;
        !            56:        Blist;
        !            57:        int     mid;            /* sequence number */
        !            58:        int     rem;            /* remaining */
        !            59:        long    time;
        !            60:        int     acked;
        !            61: };
        !            62: 
        !            63: /*
        !            64:  *  Nonet conversation states (for Conversation.state)
        !            65:  */
        !            66: enum {
        !            67:        Cclosed,
        !            68:        Copen,
        !            69:        Clistening,
        !            70:        Cconnected,
        !            71:        Cconnecting,
        !            72:        Chungup,
        !            73:        Cclosing,
        !            74: };
        !            75: 
        !            76: /*
        !            77:  *  one exists for each Nonet conversation.
        !            78:  */
        !            79: struct Conversation {
        !            80:        QLock;
        !            81: 
        !            82:        Queue   *rq;            /* input queue */
        !            83:        int     version;        /* incremented each time struct is changed */
        !            84:        int     state;          /* true if listening */
        !            85: 
        !            86:        Msg     in[Nmsg];       /* messages being received */
        !            87:        int     rcvcircuit;     /* circuit number of incoming packets */
        !            88: 
        !            89:        uchar   ack[Nmsg];      /* acknowledgements waiting to be sent */
        !            90:        long    atime[Nmsg];
        !            91:        int     afirst;
        !            92:        int     anext;
        !            93: 
        !            94:        QLock   xlock;          /* one trasmitter at a time */
        !            95:        Rendez  r;              /* process waiting for an output mid */
        !            96:        Msg     ctl;            /* for control messages */
        !            97:        Msg     out[Nmsg];      /* messages being sent */
        !            98:        int     first;          /* first unacknowledged message */
        !            99:        int     next;           /* next message buffer to use */
        !           100:        int     lastacked;      /* last message acked */                
        !           101:        Block   *media;         /* prototype media output header */
        !           102:        Hdr     *hdr;           /* nonet header inside of media header */
        !           103: 
        !           104:        Interface *ifc;
        !           105:        int     kstarted;
        !           106:        char    raddr[64];      /* remote address */
        !           107:        int     rexmit;         /* statistics */
        !           108:        int     retry;
        !           109:        int     bad;
        !           110:        int     sent;
        !           111:        int     rcvd;
        !           112: };
        !           113: 
        !           114: /*
        !           115:  *  a nonet interface.  one exists for every stream that a 
        !           116:  *  nonet multiplexor is pushed onto.
        !           117:  */
        !           118: struct Interface {
        !           119:        QLock;
        !           120:        int     ref;
        !           121:        char    name[64];       /* interface name */            
        !           122:        int     maxtu;          /* maximum transfer unit */
        !           123:        int     mintu;          /* minimum transfer unit */
        !           124:        int     hsize;          /* media header size */
        !           125:        Queue   *wq;            /* interface output queue */
        !           126:        void    (*connect)(Conversation *, char *);
        !           127:        Conversation conv[Nconv];
        !           128: };
        !           129: static Interface interface[Nifc];
        !           130: 
        !           131: void nonetkproc(void *);
        !           132: int cksum(Block*, int);
        !           133: extern Qinfo noetherinfo;
        !           134: 
        !           135: /*
        !           136:  *  start a new conversation.  start an ack/retransmit process if
        !           137:  *  none already exists for this circuit.
        !           138:  */
        !           139: static void
        !           140: startconv(Conversation *cp, int circuit, int state)
        !           141: {
        !           142:        int i;
        !           143:        char name[32];
        !           144:        Interface *ifc;
        !           145: 
        !           146:        ifc = cp->ifc;
        !           147: 
        !           148:        /*
        !           149:         *  allocate the prototype header
        !           150:         */
        !           151:        cp->media = allocb(ifc->hsize + HDRSIZE);
        !           152:        cp->media->wptr += ifc->hsize + HDRSIZE;
        !           153:        cp->hdr = (Hdr *)(cp->media->rptr + ifc->hsize);
        !           154: 
        !           155:        /*
        !           156:         *  fill in the circuit number
        !           157:         */
        !           158:        cp->hdr->flag = NEWCALL|ACKME;
        !           159:        cp->hdr->circuit[2] = circuit>>16;
        !           160:        cp->hdr->circuit[1] = circuit>>8;
        !           161:        cp->hdr->circuit[0] = circuit;
        !           162: 
        !           163:        /*
        !           164:         *  set the state variables
        !           165:         */
        !           166:        cp->state = state;
        !           167:        cp->retry = 0;
        !           168:        for(i = 1; i < Nmsg; i++){
        !           169:                cp->in[i].mid = i;
        !           170:                cp->in[i].acked = 0;
        !           171:                cp->in[i].rem = 0;
        !           172:                cp->out[i].mid = i | Nmsg;
        !           173:                cp->out[i].acked = 1;
        !           174:                cp->out[i].rem = 0;
        !           175:        }
        !           176:        cp->in[0].mid = Nmsg;
        !           177:        cp->in[0].acked = 0;
        !           178:        cp->in[0].rem = 0;
        !           179:        cp->out[0].mid = 0;
        !           180:        cp->out[0].acked = 1;
        !           181:        cp->out[0].rem = 0;
        !           182:        cp->first = cp->next = 1;
        !           183:        cp->rexmit = cp->bad = cp->sent = cp->rcvd = cp->lastacked = 0;
        !           184: 
        !           185:        /*
        !           186:         *  used for demultiplexing
        !           187:         */
        !           188:        cp->rcvcircuit = circuit ^ 1;
        !           189: 
        !           190:        /*
        !           191:         *  start the ack/rexmit process
        !           192:         */
        !           193:        if(cp->kstarted == 0){
        !           194:                cp->kstarted = 1;
        !           195:                sprint(name, "**nonet%d**", cp - ifc->conv);
        !           196:                kproc(name, nonetkproc, cp);
        !           197:        }
        !           198: }
        !           199: 
        !           200: /*
        !           201:  *  connect to the destination whose name is pointed to by bp->rptr.
        !           202:  */
        !           203: void
        !           204: connect(Conversation *cp, Block *bp)
        !           205: {
        !           206:        Interface *ifc;
        !           207:        char *iname;
        !           208:        int len;
        !           209:        int circuit;
        !           210: 
        !           211:        ifc = cp->ifc;
        !           212:        qlock(ifc);
        !           213:        if(waserror()){
        !           214:                qunlock(ifc);
        !           215:                if(cp->media){
        !           216:                        freeb(cp->media);
        !           217:                        cp->media = 0;
        !           218:                }
        !           219:                freeb(bp);
        !           220:                nexterror();
        !           221:        }
        !           222: 
        !           223:        /*
        !           224:         *  init
        !           225:         */
        !           226:        startconv(cp, (++(cp->version) * Nconv) + 2*(cp - ifc->conv), Cconnecting);
        !           227:        (*ifc->connect)(cp, (char *)bp->rptr);
        !           228:        strncpy(cp->raddr, (char *)bp->rptr, sizeof(cp->raddr));
        !           229: 
        !           230:        qunlock(ifc);
        !           231:        freeb(bp);
        !           232:        poperror();
        !           233: }
        !           234: 
        !           235: /*
        !           236:  *  listen for calls from any interface
        !           237:  */
        !           238: static int
        !           239: listendone(void *a)
        !           240: {
        !           241:        Conversation *cp;
        !           242: 
        !           243:        cp = (Conversation *)a;
        !           244:        return cp->state != Clistening;
        !           245: }
        !           246: static void
        !           247: listen(Conversation *cp, Block *bp)
        !           248: {
        !           249:        freeb(bp);
        !           250:        if(cp->state >= Clistening){
        !           251:                print("listen in use %d %ux %ux\n", cp->state, cp->ifc, interface);
        !           252:                error(0, Einuse);
        !           253:        }
        !           254:        cp->state = Clistening;
        !           255:        sleep(&cp->r, listendone, cp);
        !           256: }
        !           257: 
        !           258: /*
        !           259:  *  send a hangup signal up the stream to get all line disciplines
        !           260:  *  to cease and desist
        !           261:  */
        !           262: static void
        !           263: hangup(Conversation *cp)
        !           264: {
        !           265:        Block *bp;
        !           266:        Queue *q;
        !           267: 
        !           268:        cp->state = Chungup;
        !           269:        bp = allocb(0);
        !           270:        bp->type = M_HANGUP;
        !           271:        q = cp->rq;
        !           272:        PUTNEXT(q, bp);
        !           273:        wakeup(&cp->r);
        !           274: }
        !           275: 
        !           276: /*
        !           277:  *  process a message acknowledgement.  if the message
        !           278:  *  has any xmit buffers queued, free them.
        !           279:  */
        !           280: static void
        !           281: rcvack(Conversation *cp, int mid)
        !           282: {
        !           283:        Msg *mp;
        !           284:        Block *bp;
        !           285:        int i;
        !           286: 
        !           287:        mp = &cp->out[mid & Nmask];
        !           288: 
        !           289:        /*
        !           290:         *  if already acked, ignore
        !           291:         */
        !           292:        if(mp->acked || mp->mid != mid)
        !           293:                return;
        !           294:        mp->acked = 1;
        !           295:        cp->lastacked = mid;
        !           296: 
        !           297:        /*
        !           298:         *  free buffers
        !           299:         */
        !           300:        qlock(mp);
        !           301:        while(bp = getb(mp))
        !           302:                freeb(bp);
        !           303:        qunlock(mp);
        !           304: 
        !           305:        /*
        !           306:         *  advance the first pointer and wakeup any processes waiting for a mid
        !           307:         */
        !           308:        if((mid&Nmask) == cp->first){
        !           309:                cp->retry = 0;
        !           310:                for(i = cp->first; i!=cp->next && cp->out[i].acked; i = (i+1)&Nmask)
        !           311:                        ;
        !           312:                cp->first = i;
        !           313:                wakeup(&cp->r);
        !           314:        }
        !           315: }
        !           316: 
        !           317: /*
        !           318:  *  queue an acknowledgement to be sent.  ignore it if we already have Nmsg
        !           319:  *  acknowledgements queued.
        !           320:  */
        !           321: static void
        !           322: queueack(Conversation *cp, int mid)
        !           323: {
        !           324:        int next;
        !           325:        ulong now;
        !           326: 
        !           327:        now = NOW;
        !           328:        next = (cp->anext + 1)&Nmask;
        !           329:        if(next != cp->afirst){
        !           330:                cp->ack[cp->anext] = mid;
        !           331:                cp->atime[cp->anext] = now + MSack;
        !           332:                cp->anext = next;
        !           333:        }
        !           334:        if(now > cp->atime[cp->afirst])
        !           335:                wakeup(&cp->rq->r);
        !           336: }
        !           337: 
        !           338: /*
        !           339:  *  make a packet header
        !           340:  */
        !           341: Block *
        !           342: mkhdr(Conversation *cp, int rem)
        !           343: {
        !           344:        Block *bp;
        !           345:        Hdr *hp;
        !           346: 
        !           347:        bp = allocb(cp->ifc->hsize + HDRSIZE + cp->ifc->mintu);
        !           348:        memcpy(bp->wptr, cp->media->rptr, cp->ifc->hsize + HDRSIZE);
        !           349:        bp->wptr += cp->ifc->hsize + HDRSIZE;
        !           350:        hp = (Hdr *)(bp->rptr + cp->ifc->hsize);
        !           351:        hp->remain[1] = rem>>8;
        !           352:        hp->remain[0] = rem;
        !           353:        hp->sum[0] = hp->sum[1] = 0;
        !           354:        return bp;
        !           355: }
        !           356: 
        !           357: /*
        !           358:  *  transmit a message.  this involves breaking a possibly multi-block message into
        !           359:  *  a train of packets on the media.
        !           360:  *
        !           361:  *  called by nonetoput() and nonetkproc().  the qlock(mp) synchronizes these two
        !           362:  *  processes.
        !           363:  */
        !           364: static void
        !           365: sendmsg(Conversation *cp, Msg *mp)
        !           366: {
        !           367:        Interface *ifc;
        !           368:        Queue *wq;
        !           369:        int msgrem;
        !           370:        int pktrem;
        !           371:        int n;
        !           372:        Block *bp, *pkt, *last;
        !           373:        uchar *rptr;
        !           374: 
        !           375:        ifc = cp->ifc;
        !           376:        if(ifc == 0)
        !           377:                return;
        !           378:        wq = ifc->wq->next;
        !           379: 
        !           380:        /*
        !           381:         *  one transmitter at a time
        !           382:         */
        !           383:        qlock(&cp->xlock);
        !           384: 
        !           385:        /*
        !           386:         *  synchronize with rcvack, don't want to send while the
        !           387:         *  message is being freed.
        !           388:         */
        !           389:        qlock(mp);
        !           390: 
        !           391:        if(waserror() || mp->acked){
        !           392:                qunlock(&cp->xlock);
        !           393:                qunlock(mp);
        !           394:                return;
        !           395:        }
        !           396: 
        !           397:        /*
        !           398:         *  get the next acknowledge to use if the next queue up
        !           399:         *  is not full.
        !           400:         */
        !           401:        if(cp->afirst != cp->anext && cp->rq->next->len < 16*1024){
        !           402:                cp->hdr->ack = cp->ack[cp->afirst];
        !           403:                cp->afirst = (cp->afirst+1)&Nmask;
        !           404:        }
        !           405:        cp->hdr->mid = mp->mid;
        !           406: 
        !           407:        if(ifc->mintu > mp->len) {
        !           408:                /*
        !           409:                 *  short message:
        !           410:                 *  copy the whole message into the header block
        !           411:                 */
        !           412:                last = pkt = mkhdr(cp, mp->len);
        !           413:                for(bp = mp->first; bp; bp = bp->next){
        !           414:                        memcpy(pkt->wptr, bp->rptr, n = BLEN(bp));
        !           415:                        pkt->wptr += n;
        !           416:                }
        !           417:                memset(pkt->wptr, 0, n = ifc->mintu - mp->len);
        !           418:                pkt->wptr += n;
        !           419:        } else {
        !           420:                /*
        !           421:                 *  long message:
        !           422:                 *  break up the message into interface packets and send them.
        !           423:                 *  once around this loop for each non-header block generated.
        !           424:                 */
        !           425:                msgrem = mp->len;
        !           426:                pktrem = msgrem > ifc->maxtu ? ifc->maxtu : msgrem;
        !           427:                bp = mp->first;
        !           428:                if(bp)
        !           429:                        rptr = bp->rptr;
        !           430:                last = pkt = mkhdr(cp, msgrem);
        !           431:                while(bp){
        !           432:                        /*
        !           433:                         *  if pkt full, send and create new header block
        !           434:                         */
        !           435:                        if(pktrem == 0){
        !           436:                                cksum(pkt, ifc->hsize);
        !           437:                                last->flags |= S_DELIM;
        !           438:                                (*wq->put)(wq, pkt);
        !           439:                                last = pkt = mkhdr(cp, -msgrem);
        !           440:                                pktrem = msgrem > ifc->maxtu ? ifc->maxtu : msgrem;
        !           441:                        }
        !           442:                        n = bp->wptr - rptr;
        !           443:                        if(n > pktrem)
        !           444:                                n = pktrem;
        !           445:                        last = last->next = allocb(0);
        !           446:                        last->rptr = rptr;
        !           447:                        last->wptr = rptr = rptr + n;
        !           448:                        msgrem -= n;
        !           449:                        pktrem -= n;
        !           450:                        if(rptr >= bp->wptr){
        !           451:                                bp = bp->next;
        !           452:                                if(bp)
        !           453:                                        rptr = bp->rptr;
        !           454:                        }
        !           455:                }
        !           456:        }
        !           457:        cksum(pkt, ifc->hsize);
        !           458:        last->flags |= S_DELIM;
        !           459:        (*wq->put)(wq, pkt);
        !           460:        mp->time = NOW + MSrexmit;
        !           461:        qunlock(mp);
        !           462:        qunlock(&cp->xlock);
        !           463:        poperror();
        !           464: }
        !           465: 
        !           466: /*
        !           467:  *  send a control message (hangup or acknowledgement).
        !           468:  */
        !           469: sendctlmsg(Conversation *cp, int flag, int new)
        !           470: {
        !           471:        cp->ctl.len = 0;
        !           472:        cp->ctl.first = 0;
        !           473:        cp->ctl.acked = 0;
        !           474:        if(new)
        !           475:                cp->ctl.mid = Nmsg^cp->out[cp->next].mid;
        !           476:        else
        !           477:                cp->ctl.mid = cp->lastacked;
        !           478:        cp->hdr->flag |= flag;
        !           479:        sendmsg(cp, &cp->ctl);
        !           480: }
        !           481: 
        !           482: /*
        !           483:  *  receive a message (called by the multiplexor; noetheriput, nofddiiput, ...)
        !           484:  */
        !           485: static void
        !           486: rcvmsg(Conversation *cp, Block *bp)
        !           487: {
        !           488:        Block *nbp;
        !           489:        Hdr *h;
        !           490:        short r;
        !           491:        int c;
        !           492:        Msg *mp;
        !           493:        int f;
        !           494:        Queue *q;
        !           495: 
        !           496:        q = cp->rq;
        !           497: 
        !           498:        /*
        !           499:         *  grab the packet header, push the pointer past the nonet header
        !           500:         */
        !           501:        h = (Hdr *)bp->rptr;
        !           502:        bp->rptr += HDRSIZE;
        !           503:        mp = &cp->in[h->mid & Nmask];
        !           504:        r = (h->remain[1]<<8) | h->remain[0];
        !           505:        f = h->flag;
        !           506: 
        !           507:        /*
        !           508:         *  if a new call request comes in on a connected channel, hang up the call
        !           509:         */
        !           510:        if(h->mid==0 && (f & NEWCALL) && cp->state==Cconnected){
        !           511:                freeb(bp);
        !           512:                hangup(cp);
        !           513:                return;
        !           514:        }
        !           515: 
        !           516:        /*
        !           517:         *  ignore old messages and process the acknowledgement
        !           518:         */
        !           519:        if(h->mid != mp->mid){
        !           520:                if(r == 0){
        !           521:                        rcvack(cp, h->ack);
        !           522:                        if(f & HANGUP)
        !           523:                                hangup(cp);
        !           524:                } else {
        !           525:                        if(r>0)
        !           526:                                queueack(cp, h->mid);
        !           527:                        cp->bad++;
        !           528:                }
        !           529:                freeb(bp);
        !           530:                return;
        !           531:        }
        !           532: 
        !           533:        if(r>=0){
        !           534:                /*
        !           535:                 *  start of message packet
        !           536:                 */
        !           537:                if(mp->first){
        !           538:                        cp->bad++;
        !           539:                        freeb(bp);
        !           540:                        return;
        !           541:                }
        !           542:                mp->rem = r;
        !           543:        } else {
        !           544:                /*
        !           545:                 *  a continuation
        !           546:                 */
        !           547:                if(-r != mp->rem) {
        !           548:                        cp->bad++;
        !           549:                        freeb(bp);
        !           550:                        return;
        !           551:                }
        !           552:        }
        !           553: 
        !           554:        /*
        !           555:         *  take care of packets that were padded up
        !           556:         */
        !           557:        mp->rem -= BLEN(bp);
        !           558:        if(mp->rem < 0){
        !           559:                if(-mp->rem <= BLEN(bp)){
        !           560:                        bp->wptr += mp->rem;
        !           561:                        mp->rem = 0;
        !           562:                } else
        !           563:                        panic("rcvmsg: short packet");
        !           564:        }
        !           565:        putb(mp, bp);
        !           566: 
        !           567:        /*
        !           568:         *  if the last chunk - pass it up the stream and wake any
        !           569:         *  waiting process.
        !           570:         *
        !           571:         *  if not, strip off the delimiter.
        !           572:         */
        !           573:        if(mp->rem == 0){
        !           574:                rcvack(cp, h->ack);
        !           575:                if(f & ACKME)
        !           576:                        queueack(cp, h->mid);
        !           577:                mp->last->flags |= S_DELIM;
        !           578:                PUTNEXT(q, mp->first);
        !           579:                mp->first = mp->last = 0;
        !           580:                mp->len = 0;
        !           581:                cp->rcvd++;
        !           582: 
        !           583:                /*
        !           584:                 *  cycle bufffer to next expected mid
        !           585:                 */
        !           586:                mp->mid ^= Nmsg;
        !           587: 
        !           588:                /*
        !           589:                 *  stop xmitting the NEWCALL flag
        !           590:                 */
        !           591:                if(cp->state==Cconnecting && !(f & NEWCALL))
        !           592:                        cp->state = Cconnected;
        !           593:        } else
        !           594:                mp->last->flags &= ~S_DELIM;
        !           595: 
        !           596: }
        !           597: 
        !           598: /*
        !           599:  *  the device stream module definition
        !           600:  */
        !           601: static void nonetstopen(Queue *, Stream *);
        !           602: static void nonetstclose(Queue *);
        !           603: static void nonetoput(Queue *, Block *);
        !           604: static void nonetiput(Queue *, Block *);
        !           605: Qinfo nonetinfo = { nonetiput, nonetoput, nonetstopen, nonetstclose, "nonet" } ;
        !           606: 
        !           607: /*
        !           608:  *  store the device end of the stream so that the multiplexor can
        !           609:  *  send blocks upstream.  this is called by streamopen() when a
        !           610:  *  nonet device steam is created.
        !           611:  */
        !           612: static void
        !           613: nonetstopen(Queue *q, Stream *s)
        !           614: {
        !           615:        Interface *ifc;
        !           616:        Conversation *cp;
        !           617: 
        !           618:        ifc = &interface[s->dev];
        !           619:        cp = &ifc->conv[s->id];
        !           620:        cp->ifc = ifc;
        !           621:        cp->rq = RD(q);
        !           622:        cp->state = Copen;
        !           623:        RD(q)->ptr = WR(q)->ptr = (void *)cp;
        !           624: }
        !           625: 
        !           626: /*
        !           627:  *  wait until all output has drained or a hangup is received.
        !           628:  *  then send a hangup message (until one is received).
        !           629:  */
        !           630: static int
        !           631: isflushed(void *a)
        !           632: {
        !           633:        Conversation *cp;
        !           634: 
        !           635:        cp = (Conversation *)a;
        !           636:        return cp->first == cp->next || cp->state == Chungup;
        !           637: }
        !           638: static int
        !           639: ishungup(void *a)
        !           640: {
        !           641:        Conversation *cp;
        !           642: 
        !           643:        cp = (Conversation *)a;
        !           644:        return cp->state == Chungup;
        !           645: }
        !           646: static int
        !           647: isdead(void *a)
        !           648: {
        !           649:        Conversation *cp;
        !           650: 
        !           651:        cp = (Conversation *)a;
        !           652:        return cp->kstarted == 0;
        !           653: }
        !           654: static void
        !           655: nonetstclose(Queue *q)
        !           656: {
        !           657:        Conversation *cp;
        !           658:        Msg *mp;
        !           659:        int i;
        !           660: 
        !           661:        cp = (Conversation *)q->ptr;
        !           662: 
        !           663:        /*
        !           664:         *  wait for all messages to drain
        !           665:         */
        !           666:        while(!isflushed(cp))
        !           667:                sleep(&cp->r, isflushed, cp);
        !           668: 
        !           669:        /*
        !           670:         *  ack all outstanding messages
        !           671:         */
        !           672:        for(; cp->first != cp->next; cp->first = (cp->first+1)&Nmask) {
        !           673:                mp = &cp->out[cp->first];
        !           674:                if(!mp->acked)
        !           675:                        rcvack(cp, mp->mid);
        !           676:        }
        !           677:        cp->first = cp->next;
        !           678: 
        !           679:        /*
        !           680:         *  send hangup messages to the other side
        !           681:         *  until it hangs up.
        !           682:         */
        !           683:        if(cp->state >= Cconnected){
        !           684:                sendctlmsg(cp, HANGUP, 1);
        !           685:                for(i=0; i<10 && !ishungup(cp); i++){
        !           686:                        sendctlmsg(cp, HANGUP, 1);
        !           687:                        tsleep(&cp->r, ishungup, cp, MSrexmit);
        !           688:                }
        !           689:        }
        !           690: 
        !           691:        /*
        !           692:         *  kill off the nonetkproc
        !           693:         */
        !           694:        cp->state = Cclosed;
        !           695:        wakeup(&cp->rq->r);
        !           696:        sleep(&cp->r, isdead, cp);
        !           697: 
        !           698:        /*
        !           699:         *  close down, synchronizing with interface
        !           700:         */
        !           701:        qlock(cp);
        !           702:        cp->ifc = 0;
        !           703:        qunlock(cp);
        !           704: }
        !           705: 
        !           706: /*
        !           707:  *  send all messages up stream.  this should only be control messages
        !           708:  */
        !           709: static void
        !           710: nonetiput(Queue *q, Block *bp)
        !           711: {
        !           712:        Conversation *cp;
        !           713: 
        !           714:        if(bp->type == M_HANGUP){
        !           715:                cp = (Conversation *)q->ptr;
        !           716:                cp->state = Chungup;
        !           717:        }
        !           718:        PUTNEXT(q, bp);
        !           719: }
        !           720: 
        !           721: /*
        !           722:  *  queue a block
        !           723:  */
        !           724: static int
        !           725: windowopen(void *a)
        !           726: {
        !           727:        Conversation *cp;
        !           728: 
        !           729:        cp = (Conversation *)a;
        !           730:        return (cp->next + 1)&Nmask != cp->first;       
        !           731: }
        !           732: static void
        !           733: nonetoput(Queue *q, Block *bp)
        !           734: {
        !           735:        Conversation *cp;
        !           736:        int next;
        !           737:        Msg *mp;
        !           738: 
        !           739:        cp = (Conversation *)(q->ptr);
        !           740: 
        !           741:        /*
        !           742:         *  do all control functions
        !           743:         */
        !           744:        if(bp->type != M_DATA){
        !           745:                if(streamparse("connect", bp))
        !           746:                        connect(cp, bp);
        !           747:                else if(streamparse("listen", bp))
        !           748:                        listen(cp, bp);
        !           749:                else
        !           750:                        freeb(bp);
        !           751:                return;
        !           752:        }
        !           753: 
        !           754:        /*
        !           755:         *  collect till we see a delim
        !           756:         */
        !           757:        if(!putb(q, bp))
        !           758:                return;
        !           759: 
        !           760:        /*
        !           761:         *  block if we don't have any free mid's
        !           762:         */
        !           763:        while((next = (cp->next + 1)&Nmask) == cp->first)
        !           764:                sleep(&cp->r, windowopen, cp);
        !           765: 
        !           766:        /*
        !           767:         *  stick the message in a Msg structure
        !           768:         */
        !           769:        mp = &cp->out[cp->next];
        !           770:        mp->time = NOW + MSrexmit;
        !           771:        mp->first = q->first;
        !           772:        mp->last = q->last;
        !           773:        mp->len = q->len;
        !           774:        mp->mid ^= Nmsg;
        !           775:        mp->acked = 0;
        !           776: 
        !           777:        /*
        !           778:         *  init the queue for new messages
        !           779:         */
        !           780:        q->len = 0;
        !           781:        q->first = q->last = 0;
        !           782: 
        !           783:        /*
        !           784:         *  send it
        !           785:         */
        !           786:        cp->next = next;
        !           787:        sendmsg(cp, mp);
        !           788:        cp->sent++;
        !           789: }
        !           790: 
        !           791: /*
        !           792:  *  wake up every 250 ms to send and ack or resend a message
        !           793:  */
        !           794: static int
        !           795: always(void *a)
        !           796: {
        !           797:        return 0;
        !           798: }
        !           799: void
        !           800: nonetkproc(void *arg)
        !           801: {
        !           802:        Conversation *cp;
        !           803:        Interface *ifc;
        !           804:        Queue *wq;
        !           805:        Msg *mp;
        !           806:        int i;
        !           807: 
        !           808:        cp = (Conversation *)arg;
        !           809: 
        !           810:        for(;;){
        !           811:                /*
        !           812:                 *  die on request
        !           813:                 */
        !           814:                if(cp->state == Cclosed){
        !           815:                        cp->kstarted = 0;
        !           816:                        wakeup(&cp->r);
        !           817:                        return;
        !           818:                }
        !           819: 
        !           820:                /*
        !           821:                 *  retransmit first message
        !           822:                 */
        !           823:                if(cp->first != cp->next){
        !           824:                        mp = &cp->out[cp->first];
        !           825:                        if(!mp->acked && NOW >= mp->time){
        !           826:                                if(cp->retry++ > 400)
        !           827:                                        hangup(cp);
        !           828:                                else {
        !           829:                                        cp->rexmit++;
        !           830:                                        sendmsg(cp, mp);
        !           831:                                }
        !           832:                        }
        !           833:                }
        !           834: 
        !           835:                /*
        !           836:                 *  send any ack whose time is come
        !           837:                 */
        !           838:                while(cp->afirst != cp->anext && NOW >= cp->atime[cp->anext]
        !           839:                      && cp->rq->next->len < Streamhi)
        !           840:                        sendctlmsg(cp, 0, 0);
        !           841:                tsleep(&cp->rq->r, always, 0, MSrexmit/2);
        !           842:        }
        !           843: }
        !           844: 
        !           845: /*
        !           846:  *  nonet directory and subdirectory
        !           847:  */
        !           848: enum {
        !           849:        Nraddrqid,
        !           850:        Nstatsqid,
        !           851:        Nchanqid,
        !           852:        Ncloneqid,
        !           853: };
        !           854: Dirtab nonetdir[Ndir];
        !           855: Dirtab nosubdir[]={
        !           856:        "raddr",        Nraddrqid,      0,      0600,
        !           857:        "stats",        Nstatsqid,      0,      0600,
        !           858: };
        !           859: 
        !           860: /*
        !           861:  *  nonet file system.  most of the calls use dev.c to access the nonet
        !           862:  *  directory and stream.c to access the nonet devices.
        !           863:  */
        !           864: void
        !           865: nonetreset(void)
        !           866: {
        !           867:        newqinfo(&noetherinfo);
        !           868: }
        !           869: 
        !           870: /*
        !           871:  *  create the nonet directory.  the files are `clone' and stream
        !           872:  * directories '1' to '32' (or whatever Nconv is in decimal)
        !           873:  */
        !           874: void
        !           875: nonetinit(void)
        !           876: {
        !           877:        int i;
        !           878: 
        !           879:        /*
        !           880:         *  create the directory.
        !           881:         */
        !           882:        /*
        !           883:         *  the circuits
        !           884:         */
        !           885:        for(i = 0; i < Nconv; i++) {
        !           886:                sprint(nonetdir[i].name, "%d", i);
        !           887:                nonetdir[i].qid = CHDIR|STREAMQID(i, Nchanqid);
        !           888:                nonetdir[i].length = 0;
        !           889:                nonetdir[i].perm = 0600;
        !           890:        }
        !           891: 
        !           892:        /*
        !           893:         *  the clone device
        !           894:         */
        !           895:        strcpy(nonetdir[i].name, "clone");
        !           896:        nonetdir[i].qid = Ncloneqid;
        !           897:        nonetdir[i].length = 0;
        !           898:        nonetdir[i].perm = 0600;
        !           899: 
        !           900: }
        !           901: 
        !           902: Chan*
        !           903: nonetattach(char *spec)
        !           904: {
        !           905:        Interface *ifc;
        !           906:        Chan *c;
        !           907: 
        !           908:        /*
        !           909:         *  find an interface with the same name
        !           910:         */
        !           911:        for(ifc = interface; ifc < &interface[Nifc]; ifc++){
        !           912:                qlock(ifc);
        !           913:                if(strcmp(spec, ifc->name)==0 && ifc->wq) {
        !           914:                        ifc->ref++;
        !           915:                        qunlock(ifc);
        !           916:                        break;
        !           917:                }
        !           918:                qunlock(ifc);
        !           919:        }
        !           920:        if(ifc == &interface[Nifc])
        !           921:                error(0, Enoifc);
        !           922:        c = devattach('n', spec);
        !           923:        c->dev = 0;
        !           924:        return c;
        !           925: }
        !           926: 
        !           927: Chan*
        !           928: nonetclone(Chan *c, Chan *nc)
        !           929: {
        !           930:        Interface *ifc;
        !           931: 
        !           932:        c = devclone(c, nc);
        !           933:        ifc = &interface[c->dev];
        !           934:        qlock(ifc);
        !           935:        ifc->ref++;
        !           936:        qunlock(ifc);
        !           937:        return c;
        !           938: }
        !           939: 
        !           940: int     
        !           941: nonetwalk(Chan *c, char *name)
        !           942: {
        !           943:        if(c->qid == CHDIR)
        !           944:                return devwalk(c, name, nonetdir, Ndir, devgen);
        !           945:        else
        !           946:                return devwalk(c, name, nosubdir, Nsubdir, streamgen);
        !           947: }
        !           948: 
        !           949: void    
        !           950: nonetstat(Chan *c, char *dp)
        !           951: {
        !           952:        if(c->qid == CHDIR)
        !           953:                devstat(c, dp, nonetdir, Ndir, devgen);
        !           954:        else
        !           955:                devstat(c, dp, nosubdir, Nsubdir, streamgen);
        !           956: }
        !           957: 
        !           958: /*
        !           959:  *  opening a nonet device allocates a Conversation.  Opening the `clone'
        !           960:  *  device is a ``macro'' for finding a free Conversation and opening
        !           961:  *  it's ctl file.
        !           962:  */
        !           963: Chan*
        !           964: nonetopen(Chan *c, int omode)
        !           965: {
        !           966:        extern Qinfo nonetinfo;
        !           967:        Stream *s;
        !           968:        Conversation *cp;
        !           969:        Interface *ifc;
        !           970: 
        !           971:        if(c->qid == Ncloneqid){
        !           972:                ifc = &interface[c->dev];
        !           973:                for(cp = &ifc->conv[0]; cp < &ifc->conv[Nconv]; cp++){
        !           974:                        if(cp->state == Cclosed && canqlock(cp)){
        !           975:                                if(cp->state != Cclosed){
        !           976:                                        qunlock(cp);
        !           977:                                        continue;
        !           978:                                }
        !           979:                                c->qid = CHDIR|STREAMQID(cp-ifc->conv, Nchanqid);
        !           980:                                devwalk(c, "ctl", 0, 0, streamgen);
        !           981:                                streamopen(c, &nonetinfo);
        !           982:                                qunlock(cp);
        !           983:                                break;
        !           984:                        }
        !           985:                }
        !           986:                if(cp == &ifc->conv[Nconv])
        !           987:                        error(0, Enodev);
        !           988:        } else if(c->qid != CHDIR)
        !           989:                streamopen(c, &nonetinfo);
        !           990: 
        !           991:        c->mode = openmode(omode);
        !           992:        c->flag |= COPEN;
        !           993:        c->offset = 0;
        !           994:        return c;
        !           995: }
        !           996: 
        !           997: void    
        !           998: nonetcreate(Chan *c, char *name, int omode, ulong perm)
        !           999: {
        !          1000:        error(0, Eperm);
        !          1001: }
        !          1002: 
        !          1003: void    
        !          1004: nonetclose(Chan *c)
        !          1005: {
        !          1006:        Interface *ifc;
        !          1007: 
        !          1008:        /* real closing happens in lancestclose */
        !          1009:        if(c->qid != CHDIR)
        !          1010:                streamclose(c);
        !          1011: 
        !          1012:        ifc = &interface[c->dev];
        !          1013:        qlock(ifc);
        !          1014:        ifc->ref--;
        !          1015:        qunlock(ifc);
        !          1016: }
        !          1017: 
        !          1018: long    
        !          1019: nonetread(Chan *c, void *a, long n)
        !          1020: {
        !          1021:        int t;
        !          1022:        Conversation *cp;
        !          1023:        char stats[256];
        !          1024: 
        !          1025:        t = STREAMTYPE(c->qid);
        !          1026:        if(t >= Slowqid)
        !          1027:                return streamread(c, a, n);
        !          1028: 
        !          1029:        if(c->qid == CHDIR)
        !          1030:                return devdirread(c, a, n, nonetdir, Ndir, devgen);
        !          1031:        if(c->qid & CHDIR)
        !          1032:                return devdirread(c, a, n, nosubdir, Nsubdir, streamgen);
        !          1033: 
        !          1034:        cp = &interface[c->dev].conv[STREAMID(c->qid)];
        !          1035:        switch(t){
        !          1036:        case Nraddrqid:
        !          1037:                return stringread(c, a, n, cp->raddr);
        !          1038:        case Nstatsqid:
        !          1039:                sprint(stats, "sent: %d\nrcved: %d\nrexmit: %d\nbad: %d\n",
        !          1040:                        cp->sent, cp->rcvd, cp->rexmit, cp->bad);
        !          1041:                return stringread(c, a, n, stats);
        !          1042:        }
        !          1043:        error(0, Eperm);
        !          1044: }
        !          1045: 
        !          1046: long    
        !          1047: nonetwrite(Chan *c, void *a, long n)
        !          1048: {
        !          1049:        int t;
        !          1050: 
        !          1051:        t = STREAMTYPE(c->qid);
        !          1052:        if(t >= Slowqid)
        !          1053:                return streamwrite(c, a, n, 0);
        !          1054:        
        !          1055:        error(0, Eperm);
        !          1056: }
        !          1057: 
        !          1058: void    
        !          1059: nonetremove(Chan *c)
        !          1060: {
        !          1061:        error(0, Eperm);
        !          1062: }
        !          1063: 
        !          1064: void    
        !          1065: nonetwstat(Chan *c, char *dp)
        !          1066: {
        !          1067:        error(0, Eperm);
        !          1068: }
        !          1069: 
        !          1070: void    
        !          1071: noneterrstr(Error *e, char *buf)
        !          1072: {
        !          1073:        rooterrstr(e, buf);
        !          1074: }
        !          1075: 
        !          1076: void    
        !          1077: nonetuserstr(Error *e, char *buf)
        !          1078: {
        !          1079:        extern consuserstr(Error *, char *);
        !          1080: 
        !          1081:        consuserstr(e, buf);
        !          1082: }
        !          1083: 
        !          1084: /*
        !          1085:  *  interface
        !          1086:  */
        !          1087: /*
        !          1088:  *  Create an interface.  The qlock on ifc prevents a circuit
        !          1089:  *  from connecting to (nonetconnect) or outputting on (nonetoput)
        !          1090:  *  the interface while it is being created.
        !          1091:  */
        !          1092: Interface *
        !          1093: newifc(Queue *q, Stream *s, int maxtu, int mintu, int hsize,
        !          1094:        void (*connect)(Conversation *, char *))
        !          1095: {
        !          1096:        Interface *ifc;
        !          1097: 
        !          1098:        for(ifc = interface; ifc < &interface[Nifc]; ifc++){
        !          1099:                if(ifc->wq == 0){
        !          1100:                        qlock(ifc);
        !          1101:                        if(ifc->wq) {
        !          1102:                                /* someone was faster than us */
        !          1103:                                qunlock(ifc);
        !          1104:                                continue;
        !          1105:                        }
        !          1106:                        RD(q)->ptr = WR(q)->ptr = (void *)ifc;
        !          1107:                        ifc->maxtu = maxtu - hsize - HDRSIZE;
        !          1108:                        ifc->mintu = mintu - hsize - HDRSIZE;
        !          1109:                        ifc->hsize = hsize;
        !          1110:                        ifc->connect = connect;
        !          1111:                        ifc->wq = WR(q);
        !          1112:                        ifc->name[0] = 0;
        !          1113:                        qunlock(ifc);
        !          1114:                        return ifc;
        !          1115:                }
        !          1116:        }
        !          1117:        error(0, Enoifc);
        !          1118: }
        !          1119: 
        !          1120: /*
        !          1121:  *  Free an interface.
        !          1122:  */
        !          1123: void
        !          1124: freeifc(Interface *ifc)
        !          1125: {
        !          1126:        qlock(ifc);
        !          1127:        if(ifc->ref){
        !          1128:                qunlock(ifc);
        !          1129:                print("freeifc in use\n");
        !          1130:                error(0, Einuse);
        !          1131:        }
        !          1132:        ifc->wq = 0;
        !          1133:        qunlock(ifc);
        !          1134: }
        !          1135: /*
        !          1136:  *  ethernet specific multiplexor
        !          1137:  */
        !          1138: /*
        !          1139:  *  ethernet header of a packet
        !          1140:  */
        !          1141: struct Etherhdr {
        !          1142:        uchar   d[6];
        !          1143:        uchar   s[6];
        !          1144:        uchar   type[2];
        !          1145:        uchar   circuit[3];     /* circuit number */
        !          1146:        uchar   flag;
        !          1147:        uchar   mid;            /* message id */
        !          1148:        uchar   ack;            /* piggy back ack */
        !          1149:        uchar   remain[2];      /* count of remaing bytes of data */
        !          1150:        uchar   sum[2];         /* checksum (0 means none) */
        !          1151: };
        !          1152: #define EHDRSIZE 24
        !          1153: #define EMAXBODY       (1514-HDRSIZE)  /* maximum ethernet packet body */
        !          1154: #define ETHER_TYPE     0x900   /* most significant byte last */
        !          1155: 
        !          1156: /*
        !          1157:  *  the ethernet multiplexor stream module definition
        !          1158:  */
        !          1159: static void noetheropen(Queue *, Stream *);
        !          1160: static void noetherclose(Queue *);
        !          1161: static void noetheroput(Queue *, Block *);
        !          1162: static void noetheriput(Queue *, Block *);
        !          1163: Qinfo noetherinfo = { noetheriput, nullput, noetheropen, noetherclose, "noether" };
        !          1164: 
        !          1165: /*
        !          1166:  *  parse an ethernet address (assumed to be 12 ascii hex digits)
        !          1167:  */
        !          1168: void
        !          1169: etherparse(uchar *to, char *from)
        !          1170: {
        !          1171:        int tdig;
        !          1172:        int fdig;
        !          1173:        int i;
        !          1174: 
        !          1175:        if(strlen(from) != 12)
        !          1176:                error(0, Ebadnet);
        !          1177: 
        !          1178:        for(i = 0; i < 6; i++){
        !          1179:                fdig = *from++;
        !          1180:                tdig = fdig > 'a' ? (fdig - 'a' + 10)
        !          1181:                                : (fdig > 'A' ? (fdig - 'A' + 10) : (fdig - '0'));
        !          1182:                fdig = *from++;
        !          1183:                tdig <<= 4;
        !          1184:                tdig |= fdig > 'a' ? (fdig - 'a' + 10)
        !          1185:                                : (fdig > 'A' ? (fdig - 'A' + 10) : (fdig - '0'));
        !          1186:                *to++ = tdig;
        !          1187:        }
        !          1188: }
        !          1189: 
        !          1190: /*
        !          1191:  *  perfrorm the ether specific part of nonetconnect.  just stick
        !          1192:  *  the address into the prototype header.
        !          1193:  */
        !          1194: void
        !          1195: noetherconnect(Conversation *cp, char *ea)
        !          1196: {
        !          1197:        Etherhdr *eh;
        !          1198: 
        !          1199:        /*
        !          1200:         *  special hack for ross
        !          1201:         */
        !          1202:        if(strcmp(ea, "020701005eff")==0)
        !          1203:                cp->hdr->flag &= ~ACKME;
        !          1204: 
        !          1205:        eh = (Etherhdr *)cp->media->rptr;
        !          1206:        etherparse(eh->d, ea);
        !          1207:        eh->type[0] = ETHER_TYPE>>8;
        !          1208:        eh->type[1] = ETHER_TYPE;
        !          1209: }
        !          1210: 
        !          1211: /*
        !          1212:  *  set up an ether interface
        !          1213:  */
        !          1214: static void
        !          1215: noetheropen(Queue *q, Stream *s)
        !          1216: {
        !          1217:        newifc(q, s, 1514, 60, 14, noetherconnect);
        !          1218: }
        !          1219: 
        !          1220: /*
        !          1221:  *  tear down an ether interface
        !          1222:  */
        !          1223: static void
        !          1224: noetherclose(Queue *q)
        !          1225: {
        !          1226:        Interface *ifc;
        !          1227: 
        !          1228:        ifc = (Interface *)(q->ptr);
        !          1229:        freeifc(ifc);
        !          1230: }
        !          1231: 
        !          1232: /*
        !          1233:  *  Input a packet and use the ether address to select the correct
        !          1234:  *  nonet device to pass it to.
        !          1235:  *
        !          1236:  *  Simplifying assumption:  one put == one packet && the complete header
        !          1237:  *     is in the first block.  If this isn't true, demultiplexing will not work.
        !          1238:  */
        !          1239: static void
        !          1240: noetheriput(Queue *q, Block *bp)
        !          1241: {
        !          1242:        Interface *ifc;
        !          1243:        int circuit;
        !          1244:        Conversation *cp;
        !          1245:        Etherhdr *h;
        !          1246:        Etherhdr *ph;
        !          1247:        ulong s;
        !          1248:        Block *end;
        !          1249: 
        !          1250:        if(bp->type != M_DATA){
        !          1251:                PUTNEXT(q, bp);
        !          1252:                return;
        !          1253:        }
        !          1254: 
        !          1255:        ifc = (Interface *)(q->ptr);
        !          1256:        h = (Etherhdr *)(bp->rptr);
        !          1257:        circuit = (h->circuit[2]<<16) | (h->circuit[1]<<8) | h->circuit[0];
        !          1258:        s = (h->sum[1]<<8) | h->sum[0];
        !          1259:        if(s && s != cksum(bp, 14)){
        !          1260:                print("checksum error %ux %ux\n", s, (h->sum[1]<<8) | h->sum[0]);
        !          1261:                freeb(bp);
        !          1262:                return;
        !          1263:        }
        !          1264: 
        !          1265:        /*
        !          1266:         *  look for an existing circuit.
        !          1267:         */
        !          1268:        for(cp = &ifc->conv[0]; cp < &ifc->conv[Nconv]; cp++){
        !          1269:                if(cp->state > Clistening && circuit == cp->rcvcircuit && canqlock(cp)){
        !          1270:                        ph = (Etherhdr *)(cp->media->rptr);
        !          1271:                        if(ifc == cp->ifc
        !          1272:                        && circuit == cp->rcvcircuit
        !          1273:                        && cp->state > Clistening
        !          1274:                        && memcmp(ph->d, h->s, sizeof(h->s)) == 0){
        !          1275:                                cp->hdr->flag &= ~NEWCALL;
        !          1276:                                bp->rptr += ifc->hsize;
        !          1277:                                rcvmsg(cp, bp);
        !          1278:                                qunlock(cp);
        !          1279:                                return;
        !          1280:                        }
        !          1281:                        qunlock(cp);
        !          1282:                }
        !          1283:        }
        !          1284: 
        !          1285:        /*
        !          1286:         *  ... or one just listening
        !          1287:         */
        !          1288:        if((h->flag & NEWCALL) == 0) {
        !          1289:                freeb(bp);
        !          1290:                return;
        !          1291:        }
        !          1292:        for(cp = &ifc->conv[0]; cp < &ifc->conv[Nconv]; cp++){
        !          1293:                if(cp->state == Clistening && canqlock(cp)) {
        !          1294:                        /*
        !          1295:                         *  initialize the conversation
        !          1296:                         */
        !          1297:                        startconv(cp, circuit^1, Cconnecting);
        !          1298:                        wakeup(&cp->r);
        !          1299:                        sprint(cp->raddr, "%.2ux%.2ux%.2ux%.2ux%.2ux%.2ux", h->s[0],
        !          1300:                                h->s[1], h->s[2], h->s[3], h->s[4], h->s[5]);
        !          1301: 
        !          1302:                        /*
        !          1303:                         *  fill in media dependent prototype header
        !          1304:                         */
        !          1305:                        ph = (Etherhdr *)(cp->media->rptr);
        !          1306:                        memcpy(ph->d, h->s, sizeof(h->s));
        !          1307:                        ph->type[0] = ETHER_TYPE>>8;
        !          1308:                        ph->type[1] = ETHER_TYPE;
        !          1309: 
        !          1310:                        /*
        !          1311:                         *  pass on the packet
        !          1312:                         */
        !          1313:                        bp->rptr += ifc->hsize;
        !          1314:                        rcvmsg(cp, bp);
        !          1315:                        qunlock(cp);
        !          1316:                        return;
        !          1317:                }
        !          1318:        }
        !          1319: 
        !          1320:        /*
        !          1321:         *  not found 
        !          1322:         */
        !          1323:        freeb(bp);
        !          1324: }
        !          1325: 
        !          1326: /*
        !          1327:  *  calculate the checksum of a list of blocks.  ignore the first `offset' bytes.
        !          1328:  */
        !          1329: int
        !          1330: cksum(Block *bp, int offset)
        !          1331: {
        !          1332:        Block *nbp = bp;
        !          1333:        uchar *ep, *p;
        !          1334:        int n;
        !          1335:        ulong s;
        !          1336:        Hdr *hp;
        !          1337: 
        !          1338:        s = 0;
        !          1339:        p = bp->rptr + offset;
        !          1340:        n = bp->wptr - p;
        !          1341:        hp = (Hdr *)p;
        !          1342:        hp->sum[0] = hp->sum[1] = 0;
        !          1343:        for(;;){
        !          1344:                ep = p+(n&~0x7);
        !          1345:                while(p < ep) {
        !          1346:                        s = s + s + p[0];
        !          1347:                        s = s + s + p[1];
        !          1348:                        s = s + s + p[2];
        !          1349:                        s = s + s + p[3];
        !          1350:                        s = s + s + p[4];
        !          1351:                        s = s + s + p[5];
        !          1352:                        s = s + s + p[6];
        !          1353:                        s = s + s + p[7];
        !          1354:                        s = (s&0xffff) + (s>>16);
        !          1355:                        p += 8;
        !          1356:                }
        !          1357:                ep = p+(n&0x7);
        !          1358:                while(p < ep) {
        !          1359:                        s = s + s + *p;
        !          1360:                        p++;
        !          1361:                }
        !          1362:                s = (s&0xffff) + (s>>16);
        !          1363:                bp = bp->next;
        !          1364:                if(bp == 0)
        !          1365:                        break;
        !          1366:                p = bp->rptr;
        !          1367:                n = BLEN(bp);
        !          1368:        }
        !          1369:        s = (s&0xffff) + (s>>16);
        !          1370:        hp->sum[1] = s>>8;
        !          1371:        hp->sum[0] = s;
        !          1372:        return s & 0xffff;
        !          1373: }

unix.superglobalmegacorp.com

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