Annotation of lucent/sys/src/9/port/devdk.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       "io.h"
        !             7: #include       "../port/error.h"
        !             8: 
        !             9: #define        DPRINT  if(0) print
        !            10: 
        !            11: #define        NOW     (MACHP(0)->ticks)
        !            12: 
        !            13: typedef struct Dkmsg   Dkmsg;
        !            14: typedef struct Line    Line;
        !            15: typedef struct Dk      Dk;
        !            16: 
        !            17: enum {
        !            18:        Maxdk = 4,
        !            19: };
        !            20: 
        !            21: /*
        !            22:  *  types of possible dkcalls
        !            23:  */
        !            24: enum {
        !            25:        Dial,
        !            26:        Announce,
        !            27:        Redial
        !            28: };
        !            29: 
        !            30: /*
        !            31:  *  format of messages to/from the datakit controller on the common
        !            32:  *  signalling line
        !            33:  */
        !            34: struct Dkmsg {
        !            35:        uchar   type;
        !            36:        uchar   srv;
        !            37:        uchar   param0l;
        !            38:        uchar   param0h;
        !            39:        uchar   param1l;
        !            40:        uchar   param1h;
        !            41:        uchar   param2l;
        !            42:        uchar   param2h;
        !            43:        uchar   param3l;
        !            44:        uchar   param3h;
        !            45:        uchar   param4l;
        !            46:        uchar   param4h;
        !            47: };
        !            48: 
        !            49: /*
        !            50:  *  message codes (T_xxx == dialin.type, D_xxx == dialin.srv)
        !            51:  */
        !            52: #define        T_SRV   1               /* service request */
        !            53: #define   D_SERV       1               /* (host to dkmux) announce a service */
        !            54: #define   D_DIAL       2               /* (host to dkmux) connect to a service */
        !            55: #define   D_XINIT      7               /* (dkmux to host) line has been spliced */
        !            56: #define        T_REPLY 2               /* reply to T_SRV/D_SERV or T_SRV/D_DIAL */
        !            57: #define          D_OK          1               /* not used */
        !            58: #define          D_OPEN        2               /* (dkmux to host) connection established */
        !            59: #define          D_FAIL        3               /* (dkmux to host) connection failed */
        !            60: #define        T_CHG   3               /* change the status of a connection */
        !            61: #define          D_CLOSE       1               /* close the connection */
        !            62: #define          D_ISCLOSED    2               /* (dkmux to host) confirm a close */
        !            63: #define          D_CLOSEALL    3               /* (dkmux to host) close all connections */
        !            64: #define          D_REDIAL      6               /* (host to dkmux) redial a call */
        !            65: #define        T_ALIVE 4               /* (host to dkmux) keep alive message */
        !            66: #define          D_CONTINUE    0               /* host has not died since last msg */
        !            67: #define          D_RESTART     1               /* host has restarted */
        !            68: #define   D_MAXCHAN    2               /* request maximum line number */
        !            69: #define        T_RESTART 8             /* (dkmux to host) datakit restarted */
        !            70: 
        !            71: /*
        !            72:  *  macros for cracking/forming the window negotiation parameter
        !            73:  */
        !            74: #define MIN(x,y)  (x < y ? x : y)
        !            75: #define W_WINDOW(o,d,t)  ((o<<8) | (d<<4) | t | 0100000)
        !            76: #define W_VALID(x)  ((x) & 0100000)
        !            77: #define W_ORIG(x)  (((x)>>8) & 017)
        !            78: #define W_DEST(x)  (((x)>>4) & 017)
        !            79: #define W_TRAF(x)  ((x) & 017)
        !            80: #define W_DESTMAX(x,y)  (W_WINDOW(W_ORIG(x),MIN(W_DEST(x),y),W_TRAF(x)))
        !            81: #define W_LIMIT(x,y)  (W_WINDOW(MIN(W_ORIG(x),y),MIN(W_DEST(x),y),W_TRAF(x)))
        !            82: #define        W_VALUE(x)      (1<<((x)+4))
        !            83: 
        !            84: struct Line {
        !            85:        QLock;
        !            86:        Netprot;                /* stat info */
        !            87:        int     lineno;
        !            88:        Rendez  r;              /* wait here for dial */
        !            89:        int     state;          /* dial state */
        !            90:        int     err;            /* dialing error (if non zero) */
        !            91:        int     window;         /* negotiated window */
        !            92:        int     timestamp;      /* timestamp of last call received on this line */
        !            93:        int     calltolive;     /* multiple of 15 seconds for dialing state to last */
        !            94:        Queue   *rq;
        !            95:        char    addr[64];
        !            96:        char    raddr[64];
        !            97:        char    ruser[32];
        !            98:        Dk *dp;                 /* interface contianing this line */
        !            99: };
        !           100: 
        !           101: /*
        !           102:  *  a dkmux dk.  one exists for every stream that a 
        !           103:  *  dkmux line discipline is pushed onto.
        !           104:  */
        !           105: struct Dk
        !           106: {
        !           107:        QLock   netlock;
        !           108:        Network net;            /* stat info */
        !           109:        Line    **linep;        /* array of line structures */
        !           110: 
        !           111:        QLock   csclock;
        !           112:        Chan    *csc;
        !           113: 
        !           114:        char    name[64];       /* dk name */
        !           115:        Queue   *wq;            /* dk output queue */
        !           116:        int     ncsc;           /* csc line number */
        !           117:        int     lines;          /* number of lines */
        !           118:        int     restart;
        !           119:        int     urpwindow;
        !           120:        Rendez  timer;
        !           121:        int     closeall;       /* set when we receive a closeall message */
        !           122:        Rendez  closeallr;      /* wait here for a closeall */
        !           123: };
        !           124: Lock   dklock;
        !           125: Dk     *dk[Maxdk];
        !           126: 
        !           127: /*
        !           128:  *  conversation states (for Line.state)
        !           129:  */
        !           130: typedef enum {
        !           131:        Lclosed=0,
        !           132:        Lopened,                /* opened but no call out */
        !           133:        Lconnected,             /* opened and a call set up on htis line */
        !           134:        Lrclose,                /* remote end has closed down */
        !           135:        Llclose,                /* local end has closed down */
        !           136:        Ldialing,               /* dialing a new call */
        !           137:        Llistening,             /* this line listening for calls */
        !           138:        Lackwait,               /* incoming call waiting for ack/nak */
        !           139:        Laccepting,             /* waiting for user to accept or reject the call */
        !           140: } Lstate;
        !           141: char *dkstate[] =
        !           142: {
        !           143:        [Lclosed]       "Closed",
        !           144:        [Lopened]       "Opened",
        !           145:        [Lconnected]    "Established",
        !           146:        [Lrclose]       "Rclose",
        !           147:        [Llclose]       "Lclose",
        !           148:        [Ldialing]      "Dialing",
        !           149:        [Llistening]    "Listen",
        !           150:        [Lackwait]      "Ackwait",
        !           151:        [Laccepting]    "Accepting",
        !           152: };
        !           153: 
        !           154: /*
        !           155:  *  map datakit error to errno 
        !           156:  */
        !           157: enum {
        !           158:        DKok,
        !           159:        DKbusy,
        !           160:        DKnetotl,
        !           161:        DKdestotl,
        !           162:        DKbadnet,
        !           163:        DKnetbusy,
        !           164:        DKinuse,
        !           165:        DKreject,
        !           166: };
        !           167: char* dkerr[]={
        !           168:        [DKok]          "",
        !           169:        [DKbusy]        "devdk: destination busy",
        !           170:        [DKnetotl]      "devdk: network not answering",
        !           171:        [DKdestotl]     "devdk: destination not answering",
        !           172:        [DKbadnet]      "devdk: unknown address",
        !           173:        [DKnetbusy]     "devdk: network busy",
        !           174:        [DKinuse]       "devdk: service in use",
        !           175:        [DKreject]      "devdk: connection refused", 
        !           176: };
        !           177: #define DKERRS sizeof(dkerr)/sizeof(char*)
        !           178: 
        !           179: /*
        !           180:  *  imported
        !           181:  */
        !           182: extern Qinfo urpinfo;
        !           183: 
        !           184: /*
        !           185:  *  predeclared
        !           186:  */
        !           187: Chan*          dkattach(char*);
        !           188: static void    dkmuxconfig(Queue*, Block*);
        !           189: static Chan*   dkopenline(Dk*, int);
        !           190: static Chan*   dkopencsc(Dk*);
        !           191: static int     dkmesg(Chan*, int, int, int, int);
        !           192: static void    dkcsckproc(void*);
        !           193: static void    dkanswer(Chan*, int, int);
        !           194: static void    dkwindow(Chan*);
        !           195: static void    dkcall(int, Chan*, char*, char*, char*);
        !           196: static void    dktimer(void*);
        !           197: static void    dkchgmesg(Chan*, Dk*, Dkmsg*, int);
        !           198: static void    dkreplymesg(Dk*, Dkmsg*, int);
        !           199: Chan*          dkopen(Chan*, int);
        !           200: static void    dkhangup(Line*);
        !           201: 
        !           202: /*
        !           203:  *  for standard network interface (net.c)
        !           204:  */
        !           205: static int     dkcloneline(Chan*);
        !           206: static int     dklisten(Chan*);
        !           207: static void    dkfilladdr(Chan*, char*, int);
        !           208: static void    dkfillraddr(Chan*, char*, int);
        !           209: static void    dkfillruser(Chan*, char*, int);
        !           210: static void    dkfillstatus(Chan*, char*, int);
        !           211: 
        !           212: extern Qinfo dkinfo;
        !           213: 
        !           214: /*
        !           215:  *  the datakit multiplexor stream module definition
        !           216:  */
        !           217: static Streamopen dkmuxopen;
        !           218: static Streamput dkmuxoput;
        !           219: static Streamput dkmuxiput;
        !           220: Qinfo dkmuxinfo =
        !           221: {
        !           222:        dkmuxiput,
        !           223:        dkmuxoput,
        !           224:        dkmuxopen,
        !           225:        0,
        !           226:        "dkmux"
        !           227: };
        !           228: 
        !           229: /*
        !           230:  *  allocate a line if it doesn't exist
        !           231:  */
        !           232: static Line*
        !           233: linealloc(Dk *dp, int lineno, int dolock)
        !           234: {
        !           235:        Line *lp;
        !           236: 
        !           237:        if(dolock)
        !           238:                qlock(&dp->netlock);
        !           239:        if(lineno > dp->lines)
        !           240:                panic("linealloc");
        !           241:        lp = dp->linep[lineno];
        !           242:        if(lp == 0){
        !           243:                lp = smalloc(sizeof(Line));
        !           244:                lp->lineno = lineno;
        !           245:                netadd(&dp->net, lp, lineno);
        !           246:                dp->linep[lineno] = lp;
        !           247:        }
        !           248:        if(dolock)
        !           249:                qunlock(&dp->netlock);
        !           250:        return lp;
        !           251: }
        !           252: 
        !           253: /*
        !           254:  *  a new dkmux.  hold the stream in place so it can never be closed down.
        !           255:  */
        !           256: static void
        !           257: dkmuxopen(Queue *q, Stream *s)
        !           258: {
        !           259:        RD(q)->ptr = 0;
        !           260:        WR(q)->ptr = 0;
        !           261: 
        !           262:        naildownstream(s);
        !           263: }
        !           264: 
        !           265: /*
        !           266:  *  handle configuration
        !           267:  */
        !           268: static void
        !           269: dkmuxoput(Queue *q, Block *bp)
        !           270: {
        !           271:        if(bp->type != M_DATA){
        !           272:                if(streamparse("config", bp))
        !           273:                        dkmuxconfig(q, bp);
        !           274:                else
        !           275:                        PUTNEXT(q, bp);
        !           276:                return;
        !           277:        }
        !           278:        PUTNEXT(q, bp);
        !           279: }
        !           280: 
        !           281: /*
        !           282:  *  gather a message and send it up the appropriate stream
        !           283:  *
        !           284:  *  The first two bytes of each message contains the channel
        !           285:  *  number, low order byte first.
        !           286:  *
        !           287:  *  Simplifying assumption:  one put == one message && the channel number
        !           288:  *     is in the first block.  If this isn't true, demultiplexing will not
        !           289:  *     work.
        !           290:  */
        !           291: static void
        !           292: dkmuxiput(Queue *q, Block *bp)
        !           293: {
        !           294:        Dk *dp;
        !           295:        Line *lp;
        !           296:        int line;
        !           297: 
        !           298:        /*
        !           299:         *  not configured yet
        !           300:         */
        !           301:        if(q->other->ptr == 0){
        !           302:                freeb(bp);
        !           303:                return;
        !           304:        }
        !           305: 
        !           306:        dp = (Dk *)q->ptr;
        !           307:        if(bp->type != M_DATA){
        !           308:                PUTNEXT(q, bp);
        !           309:                return;
        !           310:        }
        !           311: 
        !           312:        line = bp->rptr[0] | (bp->rptr[1]<<8);
        !           313:        bp->rptr += 2;
        !           314:        if(line<0 || line>=dp->lines){
        !           315:                DPRINT("dkmuxiput bad line %d\n", line);
        !           316:                freeb(bp);
        !           317:                return;
        !           318:        }
        !           319: 
        !           320:        lp = linealloc(dp, line, 1);
        !           321:        if(lp && canqlock(lp)){
        !           322:                if(lp->rq)
        !           323:                        PUTNEXT(lp->rq, bp);
        !           324:                else{
        !           325:                        DPRINT("dkmuxiput unopened line %d\n", line);
        !           326:                        freeb(bp);
        !           327:                }
        !           328:                qunlock(lp);
        !           329:        } else {
        !           330:                DPRINT("dkmuxiput unopened line %d\n", line);
        !           331:                freeb(bp);
        !           332:        }
        !           333: }
        !           334: 
        !           335: /*
        !           336:  *  the datakit line stream module definition
        !           337:  */
        !           338: static Streamopen dkstopen;
        !           339: static Streamclose dkstclose;
        !           340: static Streamput dkoput, dkiput;
        !           341: Qinfo dkinfo =
        !           342: {
        !           343:        dkiput,
        !           344:        dkoput,
        !           345:        dkstopen,
        !           346:        dkstclose,
        !           347:        "dk"
        !           348: };
        !           349: 
        !           350: /*
        !           351:  *  open and save a pointer to the conversation
        !           352:  */
        !           353: static void
        !           354: dkstopen(Queue *q, Stream *s)
        !           355: {
        !           356:        Dk *dp;
        !           357:        Line *lp;
        !           358: 
        !           359:        dp = dk[s->dev];
        !           360:        q->other->ptr = q->ptr = lp = dp->linep[s->id];
        !           361:        lp->dp = dp;
        !           362:        lp->rq = q;
        !           363:        if(lp->state==Lclosed)
        !           364:                lp->state = Lopened;
        !           365: }
        !           366: 
        !           367: /*
        !           368:  *  close down a datakit conversation
        !           369:  */
        !           370: static void
        !           371: dkstclose(Queue *q)
        !           372: {
        !           373:        Dk *dp;
        !           374:        Line *lp;
        !           375:        Chan *c;
        !           376: 
        !           377:        lp = (Line *)q->ptr;
        !           378:        dp = lp->dp;
        !           379: 
        !           380:        /*
        !           381:         *  if we never got going, we're done
        !           382:         */
        !           383:        if(lp->rq == 0){
        !           384:                lp->state = Lclosed; 
        !           385:                return;
        !           386:        }
        !           387: 
        !           388:        /*
        !           389:         *  these states don't need the datakit
        !           390:         */
        !           391:        switch(lp->state){
        !           392:        case Lclosed:
        !           393:        case Llclose:
        !           394:        case Lopened:
        !           395:                lp->state = Lclosed;
        !           396:                goto out;
        !           397:        }
        !           398: 
        !           399:        c = 0;
        !           400:        if(waserror()){
        !           401:                lp->state = Lclosed;
        !           402:                if(c)
        !           403:                        close(c);
        !           404:                goto out;
        !           405:        }       
        !           406:        c = dkopencsc(dp);
        !           407: 
        !           408:        /*
        !           409:         *  shake hands with dk
        !           410:         */
        !           411:        switch(lp->state){
        !           412:        case Lrclose:
        !           413:                dkmesg(c, T_CHG, D_CLOSE, lp->lineno, 0);
        !           414:                lp->state = Lclosed;
        !           415:                break;
        !           416: 
        !           417:        case Lackwait:
        !           418:                dkmesg(c, T_CHG, D_CLOSE, lp->lineno, 0);
        !           419:                lp->state = Llclose;
        !           420:                break;
        !           421: 
        !           422:        case Llistening:
        !           423:                dkmesg(c, T_CHG, D_CLOSE, lp->lineno, 0);
        !           424:                lp->state = Llclose;
        !           425:                break;
        !           426: 
        !           427:        case Lconnected:
        !           428:                dkmesg(c, T_CHG, D_CLOSE, lp->lineno, 0);
        !           429:                lp->state = Llclose;
        !           430:                break;
        !           431:        }
        !           432:        poperror();
        !           433:        close(c);
        !           434: 
        !           435: out:
        !           436:        qlock(lp);
        !           437:        lp->rq = 0;
        !           438:        qunlock(lp);
        !           439: 
        !           440:        netdisown(lp);
        !           441:        lp->window = 0;
        !           442: }
        !           443: 
        !           444: /*
        !           445:  *  this is only called by hangup
        !           446:  */
        !           447: static void
        !           448: dkiput(Queue *q, Block *bp)
        !           449: {
        !           450:        PUTNEXT(q, bp);
        !           451: }
        !           452: 
        !           453: /*
        !           454:  *  we assume that each put is a message.
        !           455:  *
        !           456:  *  add a 2 byte channel number to the start of each message,
        !           457:  *  low order byte first.  Make sure the first block contains
        !           458:  *  both the 2 channel bytes and the control byte.
        !           459:  */
        !           460: static void
        !           461: dkoput(Queue *q, Block *bp)
        !           462: {
        !           463:        Line *lp;
        !           464:        Dk *dp;
        !           465:        int line;
        !           466: 
        !           467:        if(bp->type != M_DATA){
        !           468:                freeb(bp);
        !           469:                error(Ebadarg);
        !           470:        }
        !           471: 
        !           472:        lp = (Line *)q->ptr;
        !           473:        dp = lp->dp;
        !           474:        line = lp->lineno;
        !           475: 
        !           476:        bp = padb(bp, 2);
        !           477:        bp->rptr[0] = line;
        !           478:        bp->rptr[1] = line>>8;
        !           479: 
        !           480:        FLOWCTL(dp->wq, bp);
        !           481: }
        !           482: 
        !           483: /*
        !           484:  *  configure a datakit multiplexor.  this takes 5 arguments separated
        !           485:  *  by spaces:
        !           486:  *     the line number of the common signalling channel (must be > 0)
        !           487:  *     the number of lines in the device (optional)
        !           488:  *     the word `restart' or `norestart' (optional/default==restart)
        !           489:  *     the name of the dk (default==dk)
        !           490:  *     the urp window size (default==2048)
        !           491:  *
        !           492:  *  we can configure only once
        !           493:  */
        !           494: static int
        !           495: haveca(void *arg)
        !           496: {
        !           497:        Dk *dp;
        !           498: 
        !           499:        dp = arg;
        !           500:        return dp->closeall;
        !           501: }
        !           502: static void
        !           503: dkmuxconfig(Queue *q, Block *bp)
        !           504: {
        !           505:        Dk *dp;
        !           506:        char *fields[5];
        !           507:        int n;
        !           508:        char buf[64];
        !           509:        char name[NAMELEN];
        !           510:        int lines;
        !           511:        int ncsc;
        !           512:        int restart;
        !           513:        int window;
        !           514: 
        !           515:        if(WR(q)->ptr){
        !           516:                freeb(bp);
        !           517:                error(Egreg);
        !           518:        }
        !           519: 
        !           520:        /*
        !           521:         *  defaults
        !           522:         */
        !           523:        ncsc = 1;
        !           524:        restart = 1;
        !           525:        lines = 16;
        !           526:        window = 2048;
        !           527:        strcpy(name, "dk");
        !           528: 
        !           529:        /*
        !           530:         *  parse
        !           531:         */
        !           532:        n = getfields((char *)bp->rptr, fields, 5, " ");
        !           533:        switch(n){
        !           534:        case 5:
        !           535:                window = strtoul(fields[4], 0, 0);
        !           536:                if(window < 16)
        !           537:                        window = 1<<(window+4);
        !           538:        case 4:
        !           539:                strncpy(name, fields[3], sizeof(name));
        !           540:                name[sizeof(name)-1] = 0;
        !           541:        case 3:
        !           542:                if(strcmp(fields[2], "restart")!=0)
        !           543:                        restart = 0;
        !           544:        case 2:
        !           545:                lines = strtoul(fields[1], 0, 0);
        !           546:        case 1:
        !           547:                ncsc = strtoul(fields[0], 0, 0);
        !           548:                break;
        !           549:        default:
        !           550:                freeb(bp);
        !           551:                error(Ebadarg);
        !           552:        }
        !           553:        freeb(bp);
        !           554:        if(ncsc <= 0 || lines <= ncsc)
        !           555:                error(Ebadarg);
        !           556: 
        !           557:        /*
        !           558:         *  find a free dk slot.  it name is already configured
        !           559:         *  or no slots are left, error.
        !           560:         */
        !           561:        lock(&dklock);
        !           562:        if(waserror()){
        !           563:                unlock(&dklock);
        !           564:                nexterror();
        !           565:        }
        !           566:        for(n = 0; n < Maxdk; n++){
        !           567:                dp = dk[n];
        !           568:                if(dp == 0)
        !           569:                        break;
        !           570:                if(strcmp(name, dp->name) == 0)
        !           571:                        error(Einuse);
        !           572:        }
        !           573:        if(n == Maxdk)
        !           574:                error(Enoifc);
        !           575: 
        !           576:        /*
        !           577:         *  allocate both a dk structure and an array of pointers to line
        !           578:         *  structures
        !           579:         */
        !           580:        dp = smalloc(sizeof(Dk));
        !           581:        dp->ncsc = ncsc;
        !           582:        dp->lines = lines;
        !           583:        dp->linep = smalloc(sizeof(Line*) * dp->lines);
        !           584:        strcpy(dp->name, name);
        !           585:        dp->net.name = dp->name;
        !           586:        dp->net.nconv = dp->lines;
        !           587:        dp->net.devp = &dkinfo;
        !           588:        dp->net.protop = &urpinfo;
        !           589:        dp->net.listen = dklisten;
        !           590:        dp->net.clone = dkcloneline;
        !           591:        dp->net.ninfo = 5;
        !           592:        dp->net.info[0].name = "local";
        !           593:        dp->net.info[0].fill = dkfilladdr;
        !           594:        dp->net.info[1].name = "remote";
        !           595:        dp->net.info[1].fill = dkfillraddr;
        !           596:        dp->net.info[2].name = "ruser";
        !           597:        dp->net.info[2].fill = dkfillruser;
        !           598:        dp->net.info[3].name = "urpstats";
        !           599:        dp->net.info[3].fill = urpfillstats;
        !           600:        dp->net.info[4].name = "status";
        !           601:        dp->net.info[4].fill = dkfillstatus;
        !           602:        dp->restart = restart;
        !           603:        dp->urpwindow = window;
        !           604:        dp->wq = WR(q);
        !           605:        q->ptr = q->other->ptr = dp;
        !           606:        dk[n] = dp;
        !           607:        unlock(&dklock);
        !           608:        poperror();
        !           609: 
        !           610:        /*
        !           611:         *  open csc here so that boot, dktimer, and dkcsckproc aren't
        !           612:         *  all fighting for it at once.
        !           613:         */
        !           614:        dkopencsc(dp);
        !           615: 
        !           616:        /*
        !           617:         *  start a process to listen to csc messages
        !           618:         */
        !           619:        sprint(buf, "csc.%s.%d", dp->name, dp->ncsc);
        !           620:        kproc(buf, dkcsckproc, dp);
        !           621: 
        !           622:        /*
        !           623:         *  tell datakit we've rebooted. It should close all channels.
        !           624:         *  do this here to get it done before trying to open a channel.
        !           625:         */
        !           626:        if(dp->restart) {
        !           627:                DPRINT("dktimer: restart %s\n", dp->name);
        !           628:                dp->closeall = 0;
        !           629:                dkmesg(dp->csc, T_ALIVE, D_RESTART, 0, 0);
        !           630:        }
        !           631:        tsleep(&dp->closeallr, haveca, dp, 15000);
        !           632: 
        !           633:        /*
        !           634:         *  start a keepalive process
        !           635:         */
        !           636:        sprint(buf, "timer.%s.%d", dp->name, dp->ncsc);
        !           637:        kproc(buf, dktimer, dp);
        !           638: }
        !           639: 
        !           640: void
        !           641: dkreset(void)
        !           642: {
        !           643:        newqinfo(&dkmuxinfo);
        !           644: }
        !           645: 
        !           646: void
        !           647: dkinit(void)
        !           648: {
        !           649: }
        !           650: 
        !           651: Chan*
        !           652: dkattach(char *spec)
        !           653: {
        !           654:        Chan *c;
        !           655:        Dk *dp;
        !           656:        int dev;
        !           657: 
        !           658:        /*
        !           659:         *  find a multiplexor with the same name (default dk)
        !           660:         */
        !           661:        if(*spec == 0)
        !           662:                spec = "dk";
        !           663:        for(dev = 0; dev < Maxdk; dev++){
        !           664:                dp = dk[dev];
        !           665:                if(dp && strcmp(dp->name, spec) == 0)
        !           666:                        break;
        !           667:        }
        !           668:        if(dev == Maxdk)
        !           669:                error(Enoifc);
        !           670: 
        !           671:        /*
        !           672:         *  return the new channel
        !           673:         */
        !           674:        c = devattach('k', spec);
        !           675:        c->dev = dev;
        !           676:        return c;
        !           677: }
        !           678: 
        !           679: Chan*
        !           680: dkclone(Chan *c, Chan *nc)
        !           681: {
        !           682:        return devclone(c, nc);
        !           683: }
        !           684: 
        !           685: int     
        !           686: dkwalk(Chan *c, char *name)
        !           687: {
        !           688:        return netwalk(c, name, &dk[c->dev]->net);
        !           689: }
        !           690: 
        !           691: void    
        !           692: dkstat(Chan *c, char *dp)
        !           693: {
        !           694:        netstat(c, dp, &dk[c->dev]->net);
        !           695: }
        !           696: 
        !           697: Chan*
        !           698: dkopen(Chan *c, int omode)
        !           699: {
        !           700:        Dk *dp;
        !           701: 
        !           702:        dp = dk[c->dev];
        !           703:        linealloc(dp, STREAMID(c->qid.path), 1);
        !           704:        return netopen(c, omode, &dp->net);
        !           705: }
        !           706: 
        !           707: void    
        !           708: dkcreate(Chan *c, char *name, int omode, ulong perm)
        !           709: {
        !           710:        USED(c);
        !           711:        USED(name);
        !           712:        USED(omode);
        !           713:        USED(perm);
        !           714:        error(Eperm);
        !           715: }
        !           716: 
        !           717: void    
        !           718: dkclose(Chan *c)
        !           719: {
        !           720:        if(c->stream)
        !           721:                streamclose(c);
        !           722: }
        !           723: 
        !           724: long    
        !           725: dkread(Chan *c, void *a, long n, ulong offset)
        !           726: {
        !           727:        return netread(c, a, n, offset, &dk[c->dev]->net);
        !           728: }
        !           729: 
        !           730: long    
        !           731: dkwrite(Chan *c, void *a, long n, ulong offset)
        !           732: {
        !           733:        int t;
        !           734:        char buf[256];
        !           735:        char *field[5];
        !           736:        int m;
        !           737: 
        !           738:        USED(offset);
        !           739:        t = STREAMTYPE(c->qid.path);
        !           740: 
        !           741:        /*
        !           742:         *  get data dispatched as quickly as possible
        !           743:         */
        !           744:        if(t == Sdataqid)
        !           745:                return streamwrite(c, a, n, 0);
        !           746: 
        !           747:        /*
        !           748:         *  easier to do here than in dkoput
        !           749:         */
        !           750:        if(t == Sctlqid){
        !           751:                if(n > sizeof buf - 1)
        !           752:                        n = sizeof buf - 1;
        !           753:                strncpy(buf, a, n);
        !           754:                buf[n] = '\0';
        !           755:                m = getfields(buf, field, 5, " ");
        !           756:                if(strncmp(field[0], "connect", 7)==0){
        !           757:                        if(m < 2)
        !           758:                                error(Ebadarg);
        !           759:                        dkcall(Dial, c, field[1], 0, 0);
        !           760:                } else if(strncmp(field[0], "announce", 8)==0){
        !           761:                        if(m < 2)
        !           762:                                error(Ebadarg);
        !           763:                        dkcall(Announce, c, field[1], 0, 0);
        !           764:                } else if(strncmp(field[0], "redial", 6)==0){
        !           765:                        if(m < 4)
        !           766:                                error(Ebadarg);
        !           767:                        dkcall(Redial, c, field[1], field[2], field[3]);
        !           768:                } else if(strncmp(field[0], "accept", 6)==0){
        !           769:                        if(m < 2)
        !           770:                                error(Ebadarg);
        !           771:                        dkanswer(c, strtoul(field[1], 0, 0), 0);
        !           772:                } else if(strncmp(field[0], "reject", 6)==0){
        !           773:                        if(m < 3)
        !           774:                                error(Ebadarg);
        !           775:                        for(m = 0; m < DKERRS-1; m++)
        !           776:                                if(strcmp(field[2], dkerr[m]) == 0)
        !           777:                                        break;
        !           778:                        dkanswer(c, strtoul(field[1], 0, 0), m);
        !           779:                } else
        !           780:                        return streamwrite(c, a, n, 0);
        !           781:                return n;
        !           782:        }
        !           783: 
        !           784:        error(Eperm);
        !           785:        return -1;              /* never reached */
        !           786: }
        !           787: 
        !           788: void    
        !           789: dkremove(Chan *c)
        !           790: {
        !           791:        USED(c);
        !           792:        error(Eperm);
        !           793: }
        !           794: 
        !           795: void    
        !           796: dkwstat(Chan *c, char *dp)
        !           797: {
        !           798:        netwstat(c, dp, &dk[c->dev]->net);
        !           799: }
        !           800: 
        !           801: /*
        !           802:  *  return the number of an unused line (reserve it)
        !           803:  */
        !           804: static int
        !           805: dkcloneline(Chan *c)
        !           806: {
        !           807:        Line *lp;
        !           808:        Dk *dp;
        !           809:        int line;
        !           810: 
        !           811:        dp = dk[c->dev];
        !           812:        /*
        !           813:         *  get an unused device and open its control file
        !           814:         */
        !           815:        qlock(&dp->netlock);
        !           816:        for(line = dp->ncsc+1; line < dp->lines; line++){
        !           817:                lp = dp->linep[line];
        !           818:                if(lp == 0 || lp->state == Lclosed){
        !           819:                        lp = linealloc(dp, line, 0);
        !           820:                        lp->state = Lopened;
        !           821: 
        !           822:                        /* current user becomes owner */
        !           823:                        netown(lp, u->p->user, 0);
        !           824: 
        !           825:                        qunlock(&dp->netlock);
        !           826:                        return lp->lineno;
        !           827:                }
        !           828:        }
        !           829:        qunlock(&dp->netlock);
        !           830:        error(Enodev);
        !           831:        return -1;              /* never reached */
        !           832: }
        !           833: 
        !           834: static Chan*
        !           835: dkopenline(Dk *dp, int line)
        !           836: {
        !           837:        Chan *c;
        !           838: 
        !           839:        c = 0;
        !           840:        if(waserror()){
        !           841:                if(c)
        !           842:                        close(c);
        !           843:                nexterror();
        !           844:        }
        !           845:        c = dkattach(dp->name);
        !           846:        c->qid.path = STREAMQID(line, Sdataqid);
        !           847:        dkopen(c, ORDWR);
        !           848:        poperror();
        !           849: 
        !           850:        return c;
        !           851: }
        !           852: 
        !           853: /*
        !           854:  *  open the common signalling channel (dp->csc's reference count never goes below 1)
        !           855:  */
        !           856: static Chan*
        !           857: dkopencsc(Dk *dp)
        !           858: {
        !           859:        qlock(&dp->csclock);
        !           860:        if(dp->csc == 0)
        !           861:                dp->csc = dkopenline(dp, dp->ncsc);
        !           862:        incref(dp->csc);
        !           863:        qunlock(&dp->csclock);
        !           864:        return dp->csc;
        !           865: }
        !           866: 
        !           867: /*
        !           868:  *  return the contents of the info files
        !           869:  */
        !           870: void
        !           871: dkfilladdr(Chan *c, char *buf, int len)
        !           872: {
        !           873:        if(len < sizeof(dk[0]->linep[0]->addr)+2)
        !           874:                error(Ebadarg);
        !           875:        sprint(buf, "%s\n", dk[c->dev]->linep[STREAMID(c->qid.path)]->addr);
        !           876: }
        !           877: void
        !           878: dkfillraddr(Chan *c, char *buf, int len)
        !           879: {
        !           880:        if(len < sizeof(dk[0]->linep[0]->raddr)+2)
        !           881:                error(Ebadarg);
        !           882:        sprint(buf, "%s\n", dk[c->dev]->linep[STREAMID(c->qid.path)]->raddr);
        !           883: }
        !           884: void
        !           885: dkfillruser(Chan *c, char *buf, int len)
        !           886: {
        !           887:        if(len < sizeof(dk[0]->linep[0]->ruser)+2)
        !           888:                error(Ebadarg);
        !           889:        sprint(buf, "%s\n", dk[c->dev]->linep[STREAMID(c->qid.path)]->ruser);
        !           890: }
        !           891: void
        !           892: dkfillstatus(Chan *c, char *buf, int len)
        !           893: {
        !           894:        Dk *dp;
        !           895:        Line *lp;
        !           896:        int line;
        !           897:        char lbuf[65];
        !           898: 
        !           899:        line = STREAMID(c->qid.path);
        !           900:        dp = dk[c->dev];
        !           901:        lp = linealloc(dp, line, 1);
        !           902:        sprint(lbuf, "%s/%d %d %s window %d\n", dp->name, line,
        !           903:                lp->state != Lclosed ? 1 : 0, dkstate[lp->state], lp->window);
        !           904:        strncpy(buf, lbuf, len);
        !           905: }
        !           906: 
        !           907: /*
        !           908:  *  send a message to the datakit on the common signaling line
        !           909:  */
        !           910: static int
        !           911: dkmesg(Chan *c, int type, int srv, int p0, int p1)
        !           912: {
        !           913:        Dkmsg d;
        !           914: 
        !           915:        if(waserror()){
        !           916:                print("dkmesg: error\n");
        !           917:                return -1;
        !           918:        }
        !           919:        d.type = type;
        !           920:        d.srv = srv;
        !           921:        d.param0l = p0;
        !           922:        d.param0h = p0>>8;
        !           923:        d.param1l = p1;
        !           924:        d.param1h = p1>>8;
        !           925:        d.param2l = 0;
        !           926:        d.param2h = 0;
        !           927:        d.param3l = 0;
        !           928:        d.param3h = 0;
        !           929:        d.param4l = 0;
        !           930:        d.param4h = 0;
        !           931:        streamwrite(c, (char *)&d, sizeof(Dkmsg), 1);
        !           932:        poperror();
        !           933:        return 0;
        !           934: }
        !           935: 
        !           936: /*
        !           937:  *  call out on a datakit
        !           938:  */
        !           939: static int
        !           940: calldone(void *a)
        !           941: {
        !           942:        Line *lp;
        !           943: 
        !           944:        lp = (Line *)a;
        !           945:        return lp->state != Ldialing;
        !           946: }
        !           947: static void
        !           948: dkcall(int type, Chan *c, char *addr, char *nuser, char *machine)
        !           949: {
        !           950:        char dialstr[66];
        !           951:        int line, win;
        !           952:        char dialtone;
        !           953:        int t_val, d_val;
        !           954:        Dk *dp;
        !           955:        Line *lp;
        !           956:        Chan *dc;
        !           957:        Chan *csc;
        !           958:        char *bang, *dot;
        !           959:        
        !           960:        line = STREAMID(c->qid.path);
        !           961:        dp = dk[c->dev];
        !           962:        lp = linealloc(dp, line, 1);
        !           963: 
        !           964:        /*
        !           965:         *  only dial on virgin lines
        !           966:         */
        !           967:        if(lp->state != Lopened)
        !           968:                error(Ebadarg);
        !           969: 
        !           970:        DPRINT("dkcall(line=%d, type=%d, dest=%s)\n", line, type, addr);
        !           971: 
        !           972:        /*
        !           973:         *  build dial string
        !           974:         *      - guard against new lines
        !           975:         *      - change ! into . to delimit service
        !           976:         */
        !           977:        if(strchr(addr, '\n'))
        !           978:                error(Ebadarg);
        !           979:        if(strlen(addr)+strlen(u->p->user)+2 >= sizeof(dialstr))
        !           980:                error(Ebadarg);
        !           981:        strcpy(dialstr, addr);
        !           982:        bang = strchr(dialstr, '!');
        !           983:        if(bang){
        !           984:                dot = strchr(dialstr, '.');
        !           985:                if(dot==0 || dot > bang)
        !           986:                        *bang = '.';
        !           987:        }
        !           988:        switch(type){
        !           989:        case Dial:
        !           990:                t_val = T_SRV;
        !           991:                d_val = D_DIAL;
        !           992:                strcat(dialstr, "\n");
        !           993:                strcat(dialstr, u->p->user);
        !           994:                strcat(dialstr, "\n");
        !           995:                break;
        !           996:        case Announce:
        !           997:                t_val = T_SRV;
        !           998:                d_val = D_SERV;
        !           999:                break;
        !          1000:        case Redial:
        !          1001:                t_val = T_CHG;
        !          1002:                d_val = D_REDIAL;
        !          1003:                strcat(dialstr, "\n");
        !          1004:                strcat(dialstr, nuser);
        !          1005:                strcat(dialstr, "\n");
        !          1006:                strcat(dialstr, machine);
        !          1007:                strcat(dialstr, "\n");
        !          1008:                break;
        !          1009:        default:
        !          1010:                t_val = 0;
        !          1011:                d_val = 0;
        !          1012:                panic("bad dial type");
        !          1013:        }
        !          1014: 
        !          1015:        /*
        !          1016:         *  open the data file
        !          1017:         */
        !          1018:        dc = dkopenline(dp, line);
        !          1019:        if(waserror()){
        !          1020:                close(dc);
        !          1021:                nexterror();
        !          1022:        }
        !          1023:        lp->calltolive = 4;
        !          1024:        lp->state = Ldialing;
        !          1025: 
        !          1026:        /*
        !          1027:         *  tell the controller we want to make a call
        !          1028:         */
        !          1029:        DPRINT("dialout\n");
        !          1030:        csc = dkopencsc(dp);
        !          1031:        if(waserror()){
        !          1032:                close(csc);
        !          1033:                nexterror();
        !          1034:        }
        !          1035:        for(win = 0; ; win++)
        !          1036:                if(W_VALUE(win) >= dp->urpwindow || win == 15)
        !          1037:                        break;
        !          1038:        dkmesg(csc, t_val, d_val, line, W_WINDOW(win, win, 2));
        !          1039:        poperror();
        !          1040:        close(csc);
        !          1041: 
        !          1042:        /*
        !          1043:         *  if redial, wait for a dial tone (otherwise we might send
        !          1044:         *  the dialstr to the previous other end and not the controller)
        !          1045:         */
        !          1046:        if(type==Redial){
        !          1047:                if(streamread(dc, &dialtone, 1L) != 1L){
        !          1048:                        lp->state = Lconnected;
        !          1049:                        error(Ebadarg);
        !          1050:                }
        !          1051:        }
        !          1052: 
        !          1053:        /*
        !          1054:         *  make the call
        !          1055:         */
        !          1056:        DPRINT("dialstr %s\n", dialstr);
        !          1057:        streamwrite(dc, dialstr, (long)strlen(dialstr), 1);
        !          1058:        close(dc);
        !          1059:        poperror();
        !          1060: 
        !          1061:        /*
        !          1062:         *  redial's never get a reply, assume it worked
        !          1063:         */
        !          1064:        if(type == Redial) {
        !          1065:                lp->state = Lconnected;
        !          1066:                return;
        !          1067:        }
        !          1068: 
        !          1069:        /*
        !          1070:         *  wait for a reply
        !          1071:         */
        !          1072:        DPRINT("reply wait\n");
        !          1073:        sleep(&lp->r, calldone, lp);
        !          1074: 
        !          1075:        /*
        !          1076:         *  if there was an error, translate it to a plan 9
        !          1077:         *  errno and report it to the user.
        !          1078:         */
        !          1079:        DPRINT("got reply %d\n", lp->state);
        !          1080:        if(lp->state != Lconnected) {
        !          1081:                if(lp->err >= DKERRS)
        !          1082:                        error(dkerr[0]);
        !          1083:                else
        !          1084:                        error(dkerr[lp->err]);
        !          1085:        }
        !          1086: 
        !          1087:        /*
        !          1088:         *  change state if serving
        !          1089:         */
        !          1090:        if(type == D_SERV){
        !          1091:                lp->state = Llistening;
        !          1092:        }
        !          1093:        DPRINT("connected!\n");
        !          1094: 
        !          1095:        /*
        !          1096:         *  decode the window size
        !          1097:         */
        !          1098:        if (W_VALID(lp->window)){
        !          1099:                /*
        !          1100:                 *  a 1127 window negotiation
        !          1101:                 */
        !          1102:                lp->window = W_VALUE(W_DEST(lp->window));
        !          1103:        } else if(lp->window>2 && lp->window<31){
        !          1104:                /*
        !          1105:                 *  a generic window negotiation
        !          1106:                 */
        !          1107:                lp->window = 1<<lp->window;
        !          1108:        } else
        !          1109:                lp->window = 0;
        !          1110: 
        !          1111:        /*
        !          1112:         *  tag the connection
        !          1113:         */
        !          1114:        strncpy(lp->addr, addr, sizeof(lp->addr)-1);
        !          1115:        strncpy(lp->raddr, addr, sizeof(lp->raddr)-1);
        !          1116: 
        !          1117:        /*
        !          1118:         *  reset the protocol
        !          1119:         */
        !          1120:        dkwindow(c);
        !          1121: }
        !          1122: 
        !          1123: /*
        !          1124:  *  listen for a call, reflavor the 
        !          1125:  */
        !          1126: static int
        !          1127: dklisten(Chan *c)
        !          1128: {
        !          1129:        char dialstr[512];
        !          1130:        char *line[12];
        !          1131:        char *field[8];
        !          1132:        Line *lp;
        !          1133:        Dk *dp;
        !          1134:        int n, lineno, ts, window;
        !          1135:        int from;
        !          1136:        Chan *dc;
        !          1137:        static int dts;
        !          1138:        char *cp;
        !          1139: 
        !          1140:        dp = dk[c->dev];
        !          1141:        from = STREAMID(c->qid.path);
        !          1142: 
        !          1143:        /*
        !          1144:         *  open the data file
        !          1145:         */
        !          1146:        dc = dkopenline(dp, STREAMID(c->qid.path));
        !          1147:        if(waserror()){
        !          1148:                close(dc);
        !          1149:                nexterror();
        !          1150:        }
        !          1151: 
        !          1152:        /*
        !          1153:         *  wait for a call in
        !          1154:         */
        !          1155:        for(;;){
        !          1156:                /*
        !          1157:                 *  read the dialstring and null terminate it
        !          1158:                 */
        !          1159:                n = streamread(dc, dialstr, sizeof(dialstr)-1);
        !          1160:                DPRINT("returns %d\n", n);
        !          1161:                if(n <= 0)
        !          1162:                        error(Eio);
        !          1163:                dialstr[n] = 0;
        !          1164:                DPRINT("dialstr = %s\n", dialstr);
        !          1165: 
        !          1166:                /*
        !          1167:                 *  break the dial string into lines
        !          1168:                 */
        !          1169:                n = getfields(dialstr, line, 12, "\n");
        !          1170:                if (n < 2) {
        !          1171:                        DPRINT("bad dialstr from dk (1 line)\n");
        !          1172:                        error(Eio);
        !          1173:                }
        !          1174: 
        !          1175:                /*
        !          1176:                 * line 0 is `line.tstamp.traffic[.urpparms.window]'
        !          1177:                 */
        !          1178:                window = 0;
        !          1179:                switch(getfields(line[0], field, 5, ".")){
        !          1180:                case 5:
        !          1181:                        /*
        !          1182:                         *  generic way of passing window
        !          1183:                         */
        !          1184:                        window = strtoul(field[4], 0, 0);
        !          1185:                        if(window > 0 && window <31)
        !          1186:                                window = 1<<window;
        !          1187:                        else
        !          1188:                                window = 0;
        !          1189:                        /*
        !          1190:                         *  intentional fall through
        !          1191:                         */
        !          1192:                case 3:
        !          1193:                        /*
        !          1194:                         *  1127 way of passing window
        !          1195:                         */
        !          1196:                        if(window == 0){
        !          1197:                                window = strtoul(field[2], 0, 0);
        !          1198:                                if(W_VALID(window))
        !          1199:                                        window = W_VALUE(W_ORIG(window));
        !          1200:                                else
        !          1201:                                        window = 0;
        !          1202:                        }
        !          1203:                        break;
        !          1204:                default:
        !          1205:                        print("bad message from dk(bad first line)\n");
        !          1206:                        continue;
        !          1207:                }
        !          1208:                lineno = strtoul(field[0], 0, 0);
        !          1209:                if(lineno >= dp->lines){
        !          1210:                        print("dklisten: illegal line %d\n", lineno);
        !          1211:                        continue;
        !          1212:                }
        !          1213:                lp = linealloc(dp, lineno, 1);
        !          1214:                ts = strtoul(field[1], 0, 0);
        !          1215: 
        !          1216:                /*
        !          1217:                 *  this could be a duplicate request
        !          1218:                 */
        !          1219:                if(ts == lp->timestamp){
        !          1220:                        if((dts++ % 1000) == 0)
        !          1221:                                print("dklisten: repeat timestamp %d\n", lineno);
        !          1222:                        if(lp->state != Lconnected)
        !          1223:                                dkanswer(c, lineno, DKbusy);
        !          1224:                        continue;
        !          1225:                }
        !          1226:        
        !          1227:                /*
        !          1228:                 *  take care of glare (datakit picked an inuse channel
        !          1229:                 *  for the call to come in on).
        !          1230:                 */
        !          1231:                if(!canqlock(lp)){
        !          1232:                        DPRINT("DKbusy1\n");
        !          1233:                        dkanswer(c, lineno, DKbusy);
        !          1234:                        continue;
        !          1235:                } else {
        !          1236:                        if(lp->state != Lclosed){
        !          1237:                                qunlock(lp);
        !          1238:                                DPRINT("DKbusy2 %ux\n", lp->state);
        !          1239:                                dkanswer(c, lineno, DKbusy);
        !          1240:                                continue;
        !          1241:                        }
        !          1242:                }
        !          1243:                lp->window = window;
        !          1244: 
        !          1245:                /*
        !          1246:                 *  Line 1 is `my-dk-name.service[.more-things]'.
        !          1247:                 *  Special characters are escaped by '\'s.  Convert to
        !          1248:                 *  a plan 9 address, i.e. system!service.
        !          1249:                 */
        !          1250:                strncpy(lp->addr, line[1], sizeof(lp->addr)-1);
        !          1251:                if(cp = strchr(lp->addr, '.')){
        !          1252:                        *cp = '!';
        !          1253:                        if(cp = strchr(cp, '.'))
        !          1254:                                *cp = 0;
        !          1255:                }
        !          1256:        
        !          1257:                /*
        !          1258:                 *  the rest is variable length
        !          1259:                 */
        !          1260:                switch(n) {
        !          1261:                case 2:
        !          1262:                        /* no more lines */
        !          1263:                        lp->ruser[0] = 0;
        !          1264:                        lp->raddr[0] = 0;
        !          1265:                        break;
        !          1266:                case 3:
        !          1267:                        /* line 2 is `source.user.param1.param2' */
        !          1268:                        getfields(line[2], field, 3, ".");
        !          1269:                        strncpy(lp->raddr, field[0], sizeof(lp->raddr)-1);
        !          1270:                        strncpy(lp->ruser, field[1], sizeof(lp->ruser)-1);
        !          1271:                        break;
        !          1272:                case 4:
        !          1273:                        /* line 2 is `user.param1.param2' */
        !          1274:                        getfields(line[2], field, 2, ".");
        !          1275:                        strncpy(lp->ruser, field[0], sizeof(lp->ruser)-1);
        !          1276:        
        !          1277:                        /* line 3 is `source.node.mod.line' */
        !          1278:                        strncpy(lp->raddr, line[3], sizeof(lp->raddr)-1);
        !          1279:                        break;
        !          1280:                default:
        !          1281:                        print("bad message from dk(>4 line)\n");
        !          1282:                        qunlock(lp);
        !          1283:                        error(Ebadarg);
        !          1284:                }
        !          1285: 
        !          1286:                DPRINT("src(%s)user(%s)dest(%s)w(%d)\n", lp->raddr, lp->ruser,
        !          1287:                        lp->addr, W_TRAF(lp->window));
        !          1288: 
        !          1289:                lp->timestamp = ts;
        !          1290:                lp->state = Lconnected;
        !          1291: 
        !          1292:                /* listener becomes owner */
        !          1293:                netown(lp, dp->linep[from]->owner, 0);
        !          1294: 
        !          1295:                qunlock(lp);
        !          1296:                close(dc);
        !          1297:                poperror();
        !          1298:                DPRINT("dklisten returns %d\n", lineno);
        !          1299:                return lineno;
        !          1300:        }
        !          1301:        panic("dklisten terminates strangely\n");
        !          1302:        return -1;              /* never reached */
        !          1303: }
        !          1304: 
        !          1305: /*
        !          1306:  *  answer a call
        !          1307:  */
        !          1308: static void
        !          1309: dkanswer(Chan *c, int line, int code)
        !          1310: {
        !          1311:        char reply[64];
        !          1312:        Chan *dc;
        !          1313:        Line *lp;
        !          1314:        Dk *dp;
        !          1315: 
        !          1316:        dp = dk[c->dev];
        !          1317:        lp = linealloc(dp, line, 1);
        !          1318: 
        !          1319:        /*
        !          1320:         *  open the data file (c is a control file)
        !          1321:         */
        !          1322:        dc = dkattach(dp->name);
        !          1323:        if(waserror()){
        !          1324:                close(dc);
        !          1325:                nexterror();
        !          1326:        }
        !          1327:        dc->qid.path = STREAMQID(STREAMID(c->qid.path), Sdataqid);
        !          1328:        dkopen(dc, ORDWR);
        !          1329: 
        !          1330:        /*
        !          1331:         *  send the reply
        !          1332:         */
        !          1333:        sprint(reply, "%ud.%ud.%ud", line, lp->timestamp, code);
        !          1334:        DPRINT("dkanswer %s\n", reply);
        !          1335:        streamwrite(dc, reply, strlen(reply), 1);
        !          1336:        close(dc);
        !          1337:        poperror();
        !          1338: 
        !          1339:        /*
        !          1340:         *  set window size
        !          1341:         */
        !          1342:        if(code == 0){
        !          1343:                if(waserror()){
        !          1344:                        close(dc);
        !          1345:                        nexterror();
        !          1346:                }
        !          1347:                sprint(reply, "init %d %d", lp->window, Streamhi);
        !          1348:                dc = dkopenline(dp, line);
        !          1349:                dc->qid.path = STREAMQID(line, Sctlqid);
        !          1350:                streamwrite(dc, reply, strlen(reply), 1);
        !          1351:                close(dc);
        !          1352:                poperror();
        !          1353:        }
        !          1354: }
        !          1355: 
        !          1356: /*
        !          1357:  *  set the window size and reset the protocol
        !          1358:  */
        !          1359: static void
        !          1360: dkwindow(Chan *c)
        !          1361: {
        !          1362:        char buf[64];
        !          1363:        Line *lp;
        !          1364: 
        !          1365:        lp = linealloc(dk[c->dev], STREAMID(c->qid.path), 1);
        !          1366:        if(lp->window == 0)
        !          1367:                lp->window = 64;
        !          1368:        sprint(buf, "init %d %d", lp->window, Streamhi);
        !          1369:        streamwrite(c, buf, strlen(buf), 1);
        !          1370: }
        !          1371: 
        !          1372: /*
        !          1373:  *  hangup a datakit connection
        !          1374:  */
        !          1375: static void
        !          1376: dkhangup(Line *lp)
        !          1377: {
        !          1378:        Block *bp;
        !          1379: 
        !          1380:        qlock(lp);
        !          1381:        if(lp->rq){
        !          1382:                bp = allocb(0);
        !          1383:                bp->type = M_HANGUP;
        !          1384:                PUTNEXT(lp->rq, bp);
        !          1385:        }
        !          1386:        qunlock(lp);
        !          1387: }
        !          1388: 
        !          1389: /*
        !          1390:  *  A process which listens to all input on a csc line
        !          1391:  */
        !          1392: static void
        !          1393: dkcsckproc(void *a)
        !          1394: {
        !          1395:        long n;
        !          1396:        Dk *dp;
        !          1397:        Dkmsg d;
        !          1398:        int line;
        !          1399: 
        !          1400:        dp = a;
        !          1401: 
        !          1402:        if(waserror()){
        !          1403:                close(dp->csc);
        !          1404:                return;
        !          1405:        }
        !          1406:        DPRINT("dkcsckproc: %d\n", dp->ncsc);
        !          1407: 
        !          1408:        /*
        !          1409:         *  loop forever listening
        !          1410:         */
        !          1411:        for(;;){
        !          1412:                n = streamread(dp->csc, (char *)&d, (long)sizeof(d));
        !          1413:                if(n != sizeof(d)){
        !          1414:                        if(n == 0)
        !          1415:                                error(Ehungup);
        !          1416:                        print("strange csc message %d\n", n);
        !          1417:                        continue;
        !          1418:                }
        !          1419:                line = (d.param0h<<8) + d.param0l;
        !          1420:                DPRINT("t(%d)s(%d)l(%d)\n", d.type, d.srv, line);
        !          1421:                switch (d.type) {
        !          1422: 
        !          1423:                case T_CHG:     /* controller wants to close a line */
        !          1424:                        dkchgmesg(dp->csc, dp, &d, line);
        !          1425:                        break;
        !          1426:                
        !          1427:                case T_REPLY:   /* reply to a dial request */
        !          1428:                        dkreplymesg(dp, &d, line);
        !          1429:                        break;
        !          1430:                
        !          1431:                case T_SRV:     /* ignore it, it's useless */
        !          1432: /*                     print("dksrvmesg(%d)\n", line);         /**/
        !          1433:                        break;
        !          1434:                
        !          1435:                case T_RESTART: /* datakit reboot */
        !          1436:                        if(line >=0 && line<dp->lines)
        !          1437:                                dp->lines = line+1;
        !          1438:                        break;
        !          1439:                
        !          1440:                default:
        !          1441:                        print("unrecognized csc message %o.%o(%o)\n",
        !          1442:                                d.type, d.srv, line);
        !          1443:                        break;
        !          1444:                }
        !          1445:        }
        !          1446: }
        !          1447: 
        !          1448: /*
        !          1449:  *  datakit requests or confirms closing a line
        !          1450:  */
        !          1451: static void
        !          1452: dkchgmesg(Chan *c, Dk *dp, Dkmsg *dialp, int line)
        !          1453: {
        !          1454:        Line *lp;
        !          1455: 
        !          1456:        switch (dialp->srv) {
        !          1457: 
        !          1458:        case D_CLOSE:           /* remote shutdown */
        !          1459:                if (line <= 0 || line >= dp->lines || (lp = dp->linep[line]) == 0) {
        !          1460:                        /* tell controller this line is not in use */
        !          1461:                        dkmesg(c, T_CHG, D_CLOSE, line, 0);
        !          1462:                        return;
        !          1463:                }
        !          1464:                switch (lp->state) {
        !          1465: 
        !          1466:                case Ldialing:
        !          1467:                        /* simulate a failed connection */
        !          1468:                        dkreplymesg(dp, (Dkmsg *)0, line);
        !          1469:                        lp->state = Lrclose;
        !          1470:                        break;
        !          1471: 
        !          1472:                case Lrclose:
        !          1473:                case Lconnected:
        !          1474:                case Llistening:
        !          1475:                case Lackwait:
        !          1476:                        dkhangup(lp);
        !          1477:                        lp->state = Lrclose;
        !          1478:                        break;
        !          1479: 
        !          1480:                case Lopened:
        !          1481:                        dkmesg(c, T_CHG, D_CLOSE, line, 0);
        !          1482:                        break;
        !          1483: 
        !          1484:                case Llclose:
        !          1485:                case Lclosed:
        !          1486:                        dkhangup(lp);
        !          1487:                        dkmesg(c, T_CHG, D_CLOSE, line, 0);
        !          1488:                        lp->state = Lclosed;
        !          1489:                        break;
        !          1490:                }
        !          1491:                break;
        !          1492:        
        !          1493:        case D_ISCLOSED:        /* acknowledging a local shutdown */
        !          1494:                if (line <= 0 || line >= dp->lines || (lp = dp->linep[line]) == 0)
        !          1495:                        return;
        !          1496:                switch (lp->state) {
        !          1497:                case Llclose:
        !          1498:                case Lclosed:
        !          1499:                        lp->state = Lclosed;
        !          1500:                        break;
        !          1501: 
        !          1502:                case Lrclose:
        !          1503:                case Lconnected:
        !          1504:                case Llistening:
        !          1505:                case Lackwait:
        !          1506:                        break;
        !          1507:                }
        !          1508:                break;
        !          1509: 
        !          1510:        case D_CLOSEALL:
        !          1511:                /*
        !          1512:                 *  datakit wants us to close all lines
        !          1513:                 */
        !          1514:                for(line = dp->ncsc+1; line < dp->lines; line++){
        !          1515:                        lp = dp->linep[line];
        !          1516:                        if(lp == 0)
        !          1517:                                continue;
        !          1518:                        switch (lp->state) {
        !          1519:        
        !          1520:                        case Ldialing:
        !          1521:                                /* simulate a failed connection */
        !          1522:                                dkreplymesg(dp, (Dkmsg *)0, line);
        !          1523:                                lp->state = Lrclose;
        !          1524:                                break;
        !          1525:        
        !          1526:                        case Lrclose:
        !          1527:                        case Lconnected:
        !          1528:                        case Llistening:
        !          1529:                        case Lackwait:
        !          1530:                                lp->state = Lrclose;
        !          1531:                                dkhangup(lp);
        !          1532:                                break;
        !          1533:        
        !          1534:                        case Lopened:
        !          1535:                                break;
        !          1536:        
        !          1537:                        case Llclose:
        !          1538:                        case Lclosed:
        !          1539:                                lp->state = Lclosed;
        !          1540:                                break;
        !          1541:                        }
        !          1542:                }
        !          1543:                dp->closeall = 1;
        !          1544:                wakeup(&dp->closeallr);
        !          1545:                break;
        !          1546: 
        !          1547:        default:
        !          1548:                print("unrecognized T_CHG\n");
        !          1549:        }
        !          1550: }
        !          1551: 
        !          1552: /*
        !          1553:  *  datakit replies to a dialout.  capture reply code and traffic parameters
        !          1554:  */
        !          1555: static void
        !          1556: dkreplymesg(Dk *dp, Dkmsg *dialp, int line)
        !          1557: {
        !          1558:        Line *lp;
        !          1559: 
        !          1560:        DPRINT("dkreplymesg(%d)\n", line);
        !          1561: 
        !          1562:        if(line < 0 || line >= dp->lines || (lp = dp->linep[line]) == 0)
        !          1563:                return;
        !          1564: 
        !          1565:        if(lp->state != Ldialing)
        !          1566:                return;
        !          1567: 
        !          1568:        if(dialp){
        !          1569:                /*
        !          1570:                 *  a reply from the dk
        !          1571:                 */
        !          1572:                lp->state = (dialp->srv==D_OPEN) ? Lconnected : Lrclose;
        !          1573:                lp->err = (dialp->param1h<<8) + dialp->param1l;
        !          1574:                lp->window = lp->err;
        !          1575:                DPRINT("dkreplymesg: %d\n", lp->state);
        !          1576:        } else {
        !          1577:                /*
        !          1578:                 *  a local abort
        !          1579:                 */
        !          1580:                lp->state = Lrclose;
        !          1581:                lp->err = 0;
        !          1582:        }
        !          1583: 
        !          1584:        if(lp->state==Lrclose){
        !          1585:                dkhangup(lp);
        !          1586:        }
        !          1587:        wakeup(&lp->r);
        !          1588: }
        !          1589: 
        !          1590: /*
        !          1591:  *  send a I'm alive message every 7.5 seconds and remind the dk of
        !          1592:  *  any closed channels it hasn't acknowledged.
        !          1593:  */
        !          1594: static void
        !          1595: dktimer(void *a)
        !          1596: {
        !          1597:        int i;
        !          1598:        Dk *dp;
        !          1599:        Line *lp;
        !          1600:        Chan *c;
        !          1601: 
        !          1602:        dp = (Dk *)a;
        !          1603:        c = dkopencsc(dp);
        !          1604: 
        !          1605:        while(waserror());
        !          1606: 
        !          1607:        for(;;){
        !          1608:                /*
        !          1609:                 * send keep alive
        !          1610:                 */
        !          1611:                DPRINT("keep alive\n");
        !          1612:                dkmesg(c, T_ALIVE, D_CONTINUE, 0, 0);
        !          1613: 
        !          1614:                /*
        !          1615:                 *  remind controller of dead lines and
        !          1616:                 *  timeout calls that take to long
        !          1617:                 */
        !          1618:                for (i=dp->ncsc+1; i<dp->lines; i++){
        !          1619:                        lp = dp->linep[i];
        !          1620:                        if(lp == 0)
        !          1621:                                continue;
        !          1622:                        switch(lp->state){
        !          1623:                        case Llclose:
        !          1624:                                dkmesg(c, T_CHG, D_CLOSE, i, 0);
        !          1625:                                break;
        !          1626: 
        !          1627:                        case Ldialing:
        !          1628:                                if(lp->calltolive==0 || --lp->calltolive!=0)
        !          1629:                                        break;
        !          1630:                                dkreplymesg(dp, (Dkmsg *)0, i);
        !          1631:                                break;
        !          1632:                        }
        !          1633:                }
        !          1634:                tsleep(&dp->timer, return0, 0, 7500);
        !          1635:        }
        !          1636: }

unix.superglobalmegacorp.com

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