|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.