|
|
1.1 ! root 1: /* ! 2: * C H A O S _ D E V I C E ! 3: * ! 4: * Chaosnet pseudo-device. This is the multiplexer/demultiplexer ! 5: * used in conjunction with the Chaosnet line discipline. ! 6: * ! 7: * ! 8: * (c) Copyright 1985 Nirvonics, Inc. ! 9: * ! 10: * Written by Kurt Gollhardt ! 11: * Last update Thu Mar 14 16:03:34 1985 ! 12: * ! 13: * This software is the property of Nirvonics, Inc. ! 14: * All rights reserved. ! 15: * ! 16: */ ! 17: ! 18: #include "ch.h" ! 19: #if NCH > 0 ! 20: #include "../h/param.h" ! 21: #include "../h/systm.h" ! 22: #include "../h/stream.h" ! 23: #include "../h/ioctl.h" ! 24: #include "../h/ttyld.h" ! 25: #include "../h/buf.h" ! 26: #include "../h/conf.h" ! 27: #include "../h/dir.h" ! 28: #include "../h/user.h" ! 29: #include "../chaosld/types.h" ! 30: #include "../chaosld/constants.h" ! 31: #include "../chaosld/globals.h" ! 32: ! 33: #define CHIOPRIO (PZERO+1) /* Just interruptible */ ! 34: ! 35: int NCh = NCH; /* For peeking */ ! 36: int NChopen; ! 37: ! 38: int nodev(), chdopen(), chdclose(), chdput(), chdosrv(); ! 39: static struct qinit chdrinit = { nodev, NULL, chdopen, chdclose, 0, 0 }, ! 40: chdwinit = { chdput, chdosrv, chdopen, chdclose, 1024, 129 }; ! 41: struct streamtab chdinfo = { &chdrinit, &chdwinit }; ! 42: ! 43: ! 44: chdopen(q, dev) ! 45: register struct queue *q; ! 46: dev_t dev; ! 47: { ! 48: dev = minor(dev); ! 49: ! 50: if (ChaosQ == (struct queue *)0) /* Make sure line-discipline is on */ ! 51: return 0; ! 52: if (dev > NCH || Chconn[dev] != NOCONN) ! 53: return 0; ! 54: if ((Chconn[dev] = new_conn(dev)) == NOCONN) ! 55: return 0; ! 56: ! 57: NChopen++; ! 58: Chconn[dev]->cn_rdq = q; ! 59: Chconn[dev]->cn_state |= CSSTARTING; ! 60: q->ptr = WR(q)->ptr = (caddr_t)Chconn[dev]; ! 61: q->flag |= QDELIM; ! 62: WR(q)->flag |= QNOENB|QBIGB; ! 63: ! 64: if (!Chtimer) ! 65: ch_timer(); ! 66: ! 67: return 1; ! 68: } ! 69: ! 70: chdclose(q) ! 71: struct queue *q; ! 72: { ! 73: register struct connection *conn; ! 74: register struct packet *pkt; ! 75: int ps; ! 76: ! 77: if ((conn = (struct connection *)q->ptr) == NOCONN) ! 78: return; ! 79: conn->cn_time = Chclock; ! 80: ! 81: switch (conn->cn_mode) { ! 82: case CHSTREAM: ! 83: ps = spl6(); ! 84: if (setjmp(u.u_qsav)) { ! 85: if ((pkt = new_packet()) != NOPKT) { ! 86: pkt->pk_op = CLSOP; ! 87: append_packet(pkt, "User interrupted", 16); ! 88: } ! 89: chld_close(conn, pkt); ! 90: goto shut; ! 91: } ! 92: if (conn->cn_flags & CHWRITER) { ! 93: /* ! 94: * We set this flag telling the interrupt time ! 95: * receiver to abort the connection if any new packets ! 96: * arrive. ! 97: */ ! 98: conn->cn_sflags |= CHCLOSING; ! 99: /* ! 100: * Closing a stream transmitter involves flushing ! 101: * the last packet, sending an EOF and waiting for ! 102: * it to be acknowledged. If the connection was ! 103: * bidirectional, the reader should have already ! 104: * read until EOF if everything is to be closed ! 105: * cleanly. ! 106: */ ! 107: if (conn->cn_state == CSOPEN || ! 108: conn->cn_state == CSRFCRCVD) { ! 109: if (conn->cn_toutput) { ! 110: chld_write(conn, conn->cn_toutput); ! 111: conn->cn_toutput = NULL; ! 112: } ! 113: if (conn->cn_state == CSOPEN) ! 114: chld_eof(conn); ! 115: } ! 116: while (!chtempty(conn)) { ! 117: conn->cn_sflags |= CHOWAIT; ! 118: sleep((caddr_t)&conn->cn_thead, CHIOPRIO); ! 119: } ! 120: if (conn->cn_flags & CHREADER) { ! 121: if (conn->cn_flags & CHSERVER) ! 122: chld_eof(conn); ! 123: else ! 124: goto close_wait; ! 125: } ! 126: } else if (conn->cn_state == CSOPEN) { ! 127: /* ! 128: * If we are only reading then we should read the EOF ! 129: * before closing and wait for the other end to close. ! 130: */ ! 131: close_wait: ! 132: if (conn->cn_flags & CHEOFSEEN) ! 133: while (conn->cn_state == CSOPEN) ! 134: sleep((caddr_t)conn, CHIOPRIO); ! 135: } ! 136: splx(ps); ! 137: /* Fall into... */ ! 138: case CHRECORD: /* Record oriented close is just sending a CLOSE */ ! 139: if (conn->cn_state == CSOPEN) { ! 140: if ((pkt = new_packet()) != NOPKT) ! 141: pkt->pk_op = CLSOP; ! 142: chld_close(conn, pkt); ! 143: } ! 144: } ! 145: shut: ! 146: chld_close(conn, NOPKT); ! 147: ! 148: free_conn(conn); ! 149: q->ptr = (caddr_t)0; ! 150: --NChopen; ! 151: } ! 152: ! 153: chdstart(q, conn) ! 154: register struct queue *q; ! 155: register struct connection *conn; ! 156: { ! 157: register struct packet *pkt; ! 158: register struct block *bp; ! 159: register struct chopen *c; ! 160: int len, rwsize, err, ps; ! 161: ! 162: err = 0; ! 163: conn->cn_sflags |= CHOPNWAIT; ! 164: if (block_pullup(q, sizeof(struct chopen)) == 0) { ! 165: err = EINVAL; ! 166: goto flush; ! 167: } ! 168: c = (struct chopen *)q->first->rptr; ! 169: ! 170: len = c->co_clength + c->co_length + (c->co_length? 1 : 0); ! 171: if (len > CHMAXPKT || c->co_clength <= 0) { ! 172: err = E2BIG; ! 173: flush: ! 174: flush_packet(q); ! 175: goto out; ! 176: } ! 177: if (block_pullup(q, len + sizeof(struct chopen)) == 0) { ! 178: err = EINVAL; ! 179: goto flush; ! 180: } ! 181: bp = getq(q); ! 182: flush_packet(q); ! 183: c = (struct chopen *)bp->rptr; ! 184: ! 185: if ((pkt = new_packet()) == NOPKT) { ! 186: err = ENOMEM; ! 187: goto out; ! 188: } ! 189: append_packet(pkt, bp->rptr += sizeof(struct chopen), c->co_clength); ! 190: if (c->co_length) { ! 191: append_packet(pkt, " ", 1); ! 192: append_packet(pkt, bp->rptr += c->co_clength, c->co_length); ! 193: } ! 194: ! 195: conn->cn_mode = c->co_mode; ! 196: if (c->co_mode == CHSTREAM) ! 197: RD(q)->flag &= ~QDELIM; ! 198: rwsize = (c->co_rwsize ? c->co_rwsize : CHDRWSIZE); ! 199: if (c->co_host) ! 200: chld_open(conn, c->co_host, rwsize, pkt); ! 201: else ! 202: chld_listen(conn, rwsize, pkt); ! 203: ! 204: out: ! 205: ps = spl6(); ! 206: if (conn->cn_sflags & CHOPNWAIT) { ! 207: if (c->co_async || err) ! 208: chdoreply(conn, err, NOPKT, c->co_async); ! 209: } ! 210: splx(ps); ! 211: } ! 212: ! 213: chdoreply(conn, err, pkt, async) ! 214: struct connection *conn; ! 215: struct packet *pkt; ! 216: { ! 217: struct choreply c; ! 218: struct queue *q; ! 219: ! 220: conn->cn_sflags &= ~CHOPNWAIT; ! 221: q = conn->cn_rdq; ! 222: ! 223: if (err == 0 && !async) { ! 224: if (conn->cn_flags & CHSERVER) { ! 225: if (conn->cn_state != CSRFCRCVD) ! 226: err = EIO; ! 227: } else { ! 228: if (conn->cn_state != CSOPEN && ! 229: (conn->cn_state != CSCLOSED || ! 230: pkt == NOPKT || pkt->pk_op != ANSOP)) ! 231: err = EIO; ! 232: } ! 233: } ! 234: c.errno = err; ! 235: putcpy(q->next, &c, sizeof(c)); ! 236: putctl(q->next, M_DELIM); ! 237: } ! 238: ! 239: chdput(q, bp) ! 240: register struct queue *q; ! 241: register struct block *bp; ! 242: { ! 243: switch(bp->type){ ! 244: case M_IOCTL: ! 245: chdioctl(q, bp); ! 246: break; ! 247: case M_DATA: ! 248: putq(q, bp); ! 249: break; ! 250: case M_DELIM: ! 251: putq(q, bp); ! 252: if (!(((struct connection *)q->ptr)->cn_sflags & CHOQWAIT)) ! 253: qenable(q); ! 254: break; ! 255: default: ! 256: freeb(bp); ! 257: break; ! 258: } ! 259: } ! 260: ! 261: chdioctl(q, bp) ! 262: register struct queue *q; ! 263: register struct block *bp; ! 264: { ! 265: register struct connection *conn; ! 266: register struct packet *pkt; ! 267: union stmsg *sp; ! 268: int ps, len; ! 269: ! 270: sp = (union stmsg *)(bp->rptr); ! 271: if ((conn = (struct connection *)q->ptr) == NOCONN) ! 272: goto bad; ! 273: bp->type = M_IOCACK; ! 274: ! 275: switch(sp->ioc0.com){ ! 276: case CHIOCRPKT: ! 277: /* Read a packet that would normally be discarded. ! 278: * This is typically used to read the error message ! 279: * given with a CLS packet, or to look at the contact ! 280: * string for a listener. ! 281: * The ioctl returns 2 bytes for the opcode, 2 bytes for ! 282: * the (data) length, and the bytes of data. ! 283: */ ! 284: ps = spl6(); ! 285: if ((pkt = conn->cn_expkt) == NOPKT || flatten(pkt)) ! 286: break; ! 287: conn->cn_expkt = NULL; ! 288: splx(ps); ! 289: len = pkt->pk_len + 4 + sizeof(sp->ioc0.com); ! 290: if (bp->lim - bp->base < len) { ! 291: freeb(bp); ! 292: if ((bp = allocb(len)) == NOBLOCK ! 293: || bp->lim - bp->base < len) ! 294: break; ! 295: bp->type = M_IOCACK; ! 296: } ! 297: sp = (union stmsg *)(bp->rptr = bp->base); ! 298: bp->wptr = bp->rptr + len; ! 299: sp->ioc0.com = CHIOCRPKT; ! 300: *(short *)(&sp->iocx.xxx[0]) = pkt->pk_op; ! 301: *(short *)(&sp->iocx.xxx[2]) = pkt->pk_len; ! 302: bcopy(pkt->data->rptr, &sp->iocx.xxx[4], pkt->pk_len); ! 303: free_packet(pkt); ! 304: goto reply; ! 305: case CHIOCFLUSH: ! 306: /* Flush the current output packet if there is one. ! 307: * Applicable in stream mode only. ! 308: */ ! 309: if (conn->cn_toutput != NOPKT) { ! 310: chld_write(conn, conn->cn_toutput); ! 311: conn->cn_toutput = NULL; ! 312: } ! 313: goto noreply; ! 314: case CHIOCOWAIT: ! 315: /* Wait for all output to be acknowledged. ! 316: * If in stream mode, any pending output is flushed first. ! 317: * If *addr is non-zero, an EOF is also sent before waiting. ! 318: */ ! 319: if (conn->cn_toutput != NOPKT) { ! 320: chld_write(conn, conn->cn_toutput); ! 321: conn->cn_toutput = NULL; ! 322: } ! 323: if (sp->iocx.xxx[0]) ! 324: chld_eof(conn); ! 325: ps = spl6(); ! 326: if (chtempty(conn)) { ! 327: /* already empty */ ! 328: splx(ps); ! 329: goto noreply; ! 330: } ! 331: conn->cn_sflags |= CHEMPWAIT; ! 332: conn->cn_wait = bp; ! 333: splx(ps); ! 334: return; ! 335: case CHIOCGSTAT: ! 336: /* Return the status of the connection */ ! 337: ps = spl6(); ! 338: { ! 339: register struct chstatus *chst; ! 340: ! 341: chst = (struct chstatus *)sp->iocx.xxx; ! 342: chst->st_fhost = conn->cn_faddr.ch_addr; ! 343: chst->st_cnum = conn->cn_lidx.ci_tidx; ! 344: chst->st_rwsize = conn->cn_rwsize; ! 345: chst->st_twsize = conn->cn_twsize; ! 346: chst->st_state = conn->cn_state; ! 347: chst->st_cmode = conn->cn_mode; ! 348: chst->st_oroom = conn->cn_twsize - ! 349: (conn->cn_tlast - conn->cn_tacked); ! 350: chst->st_ptype = chst->st_plength = 0; ! 351: bp->wptr = (u_char *)(chst + 1); ! 352: } ! 353: splx(ps); ! 354: goto reply; ! 355: case CHIOCSWAIT: ! 356: /* Wait for the state of the connection to be different ! 357: * from the given state. ! 358: */ ! 359: ps = spl6(); ! 360: if (conn->cn_state != *(int *)sp->iocx.xxx) { ! 361: /* already out of the given state */ ! 362: splx(ps); ! 363: goto noreply; ! 364: } ! 365: conn->cn_sflags |= CHSWAIT; ! 366: conn->cn_wait = bp; ! 367: splx(ps); ! 368: return; ! 369: case CHIOCANSWER: ! 370: /* Answer an RFC. This sets a bit saying the next write ! 371: * call should send an ANS packet and close the connection. ! 372: */ ! 373: if (conn->cn_state == CSRFCRCVD) { ! 374: conn->cn_flags |= CHANSWER; ! 375: goto noreply; ! 376: } ! 377: break; ! 378: case CHIOCREJECT: ! 379: /* Reject an RFC. This closes the connection with a CLS ! 380: * packet containing an error message string. The user ! 381: * passes in a structure containing a pointer to the error ! 382: * message (reason) and its length. ! 383: */ ! 384: { ! 385: register struct chreject *cr; ! 386: int flag, c; ! 387: ! 388: cr = (struct chreject *)sp->iocx.xxx; ! 389: pkt = NOPKT; ! 390: flag = 0; ! 391: if (cr->cr_length > 0 && cr->cr_length <= CHMAXPKT) { ! 392: if ((pkt = new_packet()) == NOPKT) ! 393: ++flag; ! 394: else { ! 395: pkt->pk_op = CLSOP; ! 396: while (cr->cr_length-- > 0) { ! 397: if ((c = fubyte(cr->cr_reason++)) < 0) ! 398: break; ! 399: append_packet(pkt, &c, 1); ! 400: } ! 401: } ! 402: } ! 403: chld_close(conn, pkt); ! 404: if (flag == 0) ! 405: goto noreply; ! 406: } ! 407: break; ! 408: case CHIOCACCEPT: ! 409: /* Accept an RFC causing the OPN packet to be sent */ ! 410: ps = spl6(); ! 411: if (conn->cn_state == CSRFCRCVD) { ! 412: chld_accept(conn); ! 413: splx(ps); ! 414: goto noreply; ! 415: } ! 416: splx(ps); ! 417: break; ! 418: } ! 419: ! 420: bad: ! 421: bp->type = M_IOCNAK; ! 422: noreply: ! 423: bp->wptr = bp->rptr; ! 424: reply: ! 425: qreply(q, bp); ! 426: } ! 427: ! 428: chdosrv(q) ! 429: struct queue *q; ! 430: { ! 431: register struct block *bp; ! 432: ! 433: if (chdwrite(q)) ! 434: return; ! 435: ! 436: /* See if there's another packet on the queue */ ! 437: for (bp = q->first; bp != NOBLOCK; bp = bp->next) ! 438: if (bp->type == M_DELIM) { ! 439: qenable(q); /* re-enable queue for the next packet */ ! 440: break; ! 441: } ! 442: } ! 443: ! 444: chdwrite(q) ! 445: register struct queue *q; ! 446: { ! 447: register struct packet *pkt; ! 448: register struct block *bp, *tail; ! 449: register struct connection *conn; ! 450: int n, ps; ! 451: ! 452: if ((conn = (struct connection *)q->ptr) == NOCONN) { ! 453: flush_packet(q); ! 454: return 1; ! 455: } ! 456: if (conn->cn_state == CSSTARTING) { ! 457: chdstart(q, conn); ! 458: return 0; ! 459: } ! 460: conn->cn_flags |= CHWRITER; ! 461: ! 462: ps = spl6(); ! 463: if (chtfull(conn)) { ! 464: conn->cn_sflags |= CHOQWAIT; ! 465: splx(ps); ! 466: return 1; ! 467: } ! 468: splx(ps); ! 469: ! 470: switch (conn->cn_mode) { ! 471: case CHSTREAM: ! 472: while ((bp = getq(q)) != NOBLOCK) { ! 473: if (bp->rptr >= bp->wptr) { ! 474: freeb(bp); ! 475: continue; ! 476: } ! 477: if (conn->cn_state != CSOPEN && ! 478: (conn->cn_state != CSRFCRCVD || ! 479: (conn->cn_flags & CHANSWER) == 0)) { ! 480: freeb(bp); ! 481: flush_packet(q); ! 482: return 1; ! 483: } ! 484: if ((pkt = conn->cn_toutput) == NOPKT) { ! 485: if ((pkt = new_packet()) == NOPKT) { ! 486: printf("chodsrv: can't allocate packet\n"); ! 487: return 0; ! 488: } ! 489: setconn(conn, pkt); ! 490: pkt->pk_op = (conn->cn_flags & CHANSWER ? ! 491: ANSOP : DATOP); ! 492: conn->cn_toutput = pkt; ! 493: } ! 494: n = CHMAXDATA - pkt->pk_len; ! 495: if (bp->wptr - bp->rptr >= n) { ! 496: append_packet(pkt, bp->rptr, n); ! 497: bp->rptr += n; ! 498: conn->cn_toutput = NOPKT; ! 499: if (bp->rptr < bp->wptr) ! 500: putbq(q, bp); ! 501: chld_write(conn, pkt); ! 502: } else { ! 503: bp->next = NOBLOCK; ! 504: if (pkt->data == NOBLOCK) ! 505: pkt->data = bp; ! 506: else { ! 507: for (tail = pkt->data; tail->next != NOBLOCK;) ! 508: tail = tail->next; ! 509: tail->next = bp; ! 510: } ! 511: pkt->pk_lenword += bp->wptr - bp->rptr; ! 512: } ! 513: } ! 514: break; ! 515: case CHRECORD: ! 516: if ((pkt = get_packet(q, 1)) == NOPKT) { ! 517: printf("chdosrv: can't allocate packet\n"); ! 518: return 0; ! 519: } ! 520: setconn(conn, pkt); ! 521: chld_write(conn, pkt); ! 522: break; ! 523: } ! 524: ! 525: return 0; ! 526: } ! 527: ! 528: chdrint(conn, pkt) ! 529: register struct connection *conn; ! 530: register struct packet *pkt; ! 531: { ! 532: register struct queue *q; ! 533: ! 534: if (conn->cn_sflags & CHOPNWAIT) ! 535: chdoreply(conn, 0, pkt, 0); ! 536: if (ISDATA(pkt) || pkt->pk_op == EOFOP) ! 537: conn->cn_flags |= CHREADER; ! 538: ! 539: q = conn->cn_rdq; ! 540: if (q) { ! 541: if (conn->cn_mode == CHSTREAM) { ! 542: if (pkt->pk_op == EOFOP) ! 543: conn->cn_flags |= CHEOFSEEN; ! 544: else ! 545: conn->cn_flags &= ~CHEOFSEEN; ! 546: if (!READABLE(pkt)) { ! 547: conn->cn_expkt = pkt; ! 548: return; ! 549: } ! 550: } ! 551: if (q->next->flag & QFULL) { ! 552: free_packet(pkt); ! 553: debug(DABNOR,printf("chdrint: QFULL\n")); ! 554: return; ! 555: } ! 556: ch_busy++; ! 557: if (conn->cn_mode == CHRECORD) /* Check for RECORD mode */ ! 558: putcpy(q->next, &pkt->pk_op, 1); ! 559: put_pkdata(q, pkt); ! 560: --ch_busy; ! 561: } else ! 562: free_packet(pkt); ! 563: } ! 564: ! 565: ! 566: chd_newstate(conn) ! 567: register struct connection *conn; ! 568: { ! 569: register struct queue *qnext = conn->cn_rdq->next; ! 570: int ps = spl6(); ! 571: ! 572: if (conn->cn_sflags & CHOPNWAIT) ! 573: chdoreply(conn, 0, NOPKT); ! 574: ! 575: if (conn->cn_sflags & CHSWAIT) { ! 576: register union stmsg *sp = (union stmsg *)conn->cn_wait->rptr; ! 577: ! 578: if (conn->cn_state != *(int *)sp->iocx.xxx) { ! 579: conn->cn_wait->wptr = (u_char *)sp; ! 580: (*qnext->qinfo->putp) (qnext, conn->cn_wait); ! 581: conn->cn_sflags &= ~CHSWAIT; ! 582: conn->cn_wait = NOBLOCK; ! 583: } ! 584: } ! 585: ! 586: if (chdead(conn)) { /* send an end-of-file */ ! 587: putctl(qnext, M_DELIM); ! 588: putctl(qnext, M_DELIM); ! 589: } ! 590: ! 591: splx(ps); ! 592: } ! 593: ! 594: chd_newout(conn) ! 595: register struct connection *conn; ! 596: { ! 597: int ps = spl6(); ! 598: ! 599: if (conn->cn_sflags & CHOWAIT) ! 600: wakeup((caddr_t)&conn->cn_thead); ! 601: ! 602: if (conn->cn_sflags & CHEMPWAIT) { ! 603: register union stmsg *sp = (union stmsg *)conn->cn_wait->rptr; ! 604: ! 605: if (chtempty(conn)) { ! 606: conn->cn_wait->wptr = (u_char *)sp; ! 607: qreply(conn->cn_rdq, conn->cn_wait); ! 608: conn->cn_sflags &= ~CHEMPWAIT; ! 609: conn->cn_wait = NOBLOCK; ! 610: } ! 611: } ! 612: ! 613: if (conn->cn_sflags & CHOQWAIT) { ! 614: conn->cn_sflags &= ~CHOQWAIT; ! 615: qenable(WR(conn->cn_rdq)); ! 616: } ! 617: ! 618: splx(ps); ! 619: } ! 620: ! 621: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.