Annotation of lucent/sys/src/9/port/devdk.c, revision 1.1.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.