|
|
1.1 ! root 1: /* ! 2: * UNIX device driver interface to the Chaos N.C.P. ! 3: */ ! 4: #include "../chunix/chsys.h" ! 5: #include "../chunix/chconf.h" ! 6: #include "../chaos/chaos.h" ! 7: #include "../chaos/user.h" ! 8: #include "../chaos/dev.h" ! 9: #include "../h/inode.h" ! 10: #include "../h/file.h" ! 11: #include "../h/dir.h" ! 12: #include "../h/user.h" ! 13: #include "../h/conf.h" ! 14: #include "../h/ioctl.h" ! 15: #include "../h/buf.h" ! 16: #include "../h/systm.h" ! 17: #include "../h/tty.h" ! 18: ! 19: #ifdef VMUNIX ! 20: #include "cht.h" ! 21: #endif ! 22: ! 23: static int initted; /* NCP initialization flag */ ! 24: int Rfcwaiting; /* Someone waiting on unmatched RFC */ ! 25: static char *chnames[][3] = { ! 26: /* reading writing read/write */ ! 27: { "uread", "ucreate", "ureadwrite", }, ! 28: }; ! 29: ! 30: #define CHFCONN(fp) ((fp)->f_conn) ! 31: #define CHIOPRIO (PZERO+1) /* Just interruptible */ ! 32: #ifndef VMUNIX ! 33: #define setjmp save ! 34: #endif ! 35: static struct packet *fillpacket(); ! 36: /* ! 37: * Open a chaos channel. ! 38: * Special case devices are indicated if CHHOST(dev) == CHHSPEC. ! 39: * See <chaos/dev.h> for the definitions. ! 40: * Non-special device opens imply a request to create a new connection ! 41: * via an RFC to a specified host, with a specified contact name string. ! 42: * The host number is specified one of three ways (CHHOST(dev)): ! 43: * CHHREAD Read an ascii host number from the remainder ! 44: * of the pathname (after the component that ! 45: * matched this device). ! 46: * CHHUSE Use the component that matched itself ! 47: * as an ascii number. ! 48: * else Use the CHHOST(dev) as an index into an ! 49: * internal host table where frequently used ! 50: * host numbers should reside. ! 51: * The contact name can also be specified in three ways (CHNAME(dev)): ! 52: * CHNREAD Read the contact string from the rest of the ! 53: * path name (possibly after host number). ! 54: * CHNUSE Read the contact string from the path ! 55: * component that matched (possibly after host ! 56: * number). ! 57: * else Use the CHNAME(dev) as an index into an ! 58: * internal array of contact names, also ! 59: * indexed by the type of open (read, write, rw). ! 60: */ ! 61: chropen(dev, flag) ! 62: dev_t dev; ! 63: { ! 64: register struct connection *conn; ! 65: register struct packet *pkt; ! 66: int host, name, wstate; ! 67: ! 68: ch_bufalloc(); ! 69: /* initialize the NCP somewhere else? */ ! 70: if (!initted) { ! 71: chrreset(); /* Reset drivers */ ! 72: chtimeout(); /* Start clock "process" */ ! 73: initted++; ! 74: } ! 75: conn = NOCONN; ! 76: name = CHNAME(dev); ! 77: host = CHHOST(dev); ! 78: wstate = 0; ! 79: if (host == CHHSPEC) ! 80: switch (name) { ! 81: case CHUNMATCHED: ! 82: if(Chrfcrcv == 0) { ! 83: Chrfcrcv++; ! 84: return; ! 85: } ! 86: break; ! 87: /* ! 88: * Listens create a connection waiting for RFC's containing ! 89: * the given contact name. The returned file descriptor ! 90: * corresponds to a connection that may not be open yet. ! 91: * Use ioctls (CHIOCGSTAT, CHIOCSWAIT), to check or ! 92: * hang on the state of the connection. ! 93: */ ! 94: case CHLISTEN: ! 95: if ((pkt = fillpacket("", 0)) != NOPKT) ! 96: conn = ch_listen(pkt); ! 97: break; ! 98: } ! 99: else { ! 100: register int len = DIRSIZ; ! 101: char *namp = u.u_dbuf; ! 102: ! 103: switch(host) { ! 104: case CHHREAD: ! 105: host = uatoi((char **)0); ! 106: break; ! 107: case CHHUSE: ! 108: host = uatoi(&namp); /* stuffs namp */ ! 109: break; ! 110: default: ! 111: host = chhosts[host]; ! 112: } ! 113: if (u.u_error) ! 114: host = 0; ! 115: switch(name) { ! 116: case CHNREAD: ! 117: namp = ""; ! 118: len = 0; ! 119: break; ! 120: case CHNUSE: ! 121: len = DIRSIZ - (namp - u.u_dbuf); ! 122: break; ! 123: default: ! 124: len = CHMAXRFC; ! 125: if ((namp = chnames[name][flag-1]) == NONAME) ! 126: host = 0; ! 127: } ! 128: if (host != 0 && (pkt = fillpacket(namp, len)) != NOPKT && ! 129: (conn = ch_open(host, CHDRWSIZE, pkt)) != NOCONN && ! 130: CHHANGDEV(dev)) ! 131: wstate = CSRFCSENT; /* Wait until OPEN/CLOSED */ ! 132: } ! 133: if (conn == NOCONN) { ! 134: u.u_error = ENXIO; ! 135: ch_buffree(); ! 136: } else { ! 137: register struct file *fp; ! 138: ! 139: fp = u.u_ofile[u.u_r.r_val1]; /* Yick. (see mx2.c) */ ! 140: CHFCONN(fp) = (caddr_t)conn; ! 141: if (wstate) { ! 142: /* ! 143: * We should hang until the connection changes from ! 144: * its initial state. ! 145: * If interrupted, flush the connection. ! 146: */ ! 147: #ifdef VMUNIX ! 148: if (setjmp(u.u_qsav) == 0) { ! 149: #else ! 150: if (save(u.u_qsav) == 0) { ! 151: #endif ! 152: spl6(); ! 153: while (conn->cn_state == wstate) ! 154: sleep((caddr_t)conn, CHIOPRIO); ! 155: spl0(); ! 156: #ifdef DEBUG ! 157: if (ch_badaddr((char *)conn)) ! 158: panic("chopen"); ! 159: #endif DEBUG ! 160: } ! 161: /* ! 162: * If the connection is not open, the open failed. ! 163: * Unless is got an ANS back. ! 164: */ ! 165: if (conn->cn_state != CSOPEN && ! 166: (conn->cn_state != CSCLOSED || ! 167: (pkt = conn->cn_rhead) == NOPKT || ! 168: pkt->pk_op != ANSOP)) { ! 169: rlsconn(conn); ! 170: u.u_error = ENXIO; ! 171: return; ! 172: } ! 173: } ! 174: conn->cn_sflags |= CHRAW; ! 175: conn->cn_mode = CHSTREAM; ! 176: } ! 177: } ! 178: ! 179: /* ARGSUSED */ ! 180: chrclose(dev, flag, cp) ! 181: dev_t dev; ! 182: struct chan *cp; ! 183: { ! 184: register struct connection *conn = (struct connection *)cp; ! 185: ! 186: if (minor(dev) == CHURFCMIN) { ! 187: Chrfcrcv = 0; ! 188: freelist(Chrfclist); ! 189: Chrfclist = NOPKT; ! 190: return; ! 191: } ! 192: /* ! 193: * If this connection has been turned into a tty, then the ! 194: * tty owns it and we don't do anything. ! 195: */ ! 196: if (conn->cn_mode != CHTTY) ! 197: chclose(conn, flag); ! 198: } ! 199: chclose(conn, flag) ! 200: register struct connection *conn; ! 201: { ! 202: register struct packet *pkt; ! 203: ! 204: switch (conn->cn_mode) { ! 205: case CHTTY: ! 206: panic("chclose on tty"); ! 207: case CHSTREAM: ! 208: spl6(); ! 209: if (setjmp(u.u_qsav)) { ! 210: pkt = pktstr(NOPKT, "User interrupted", 16); ! 211: if (pkt != NOPKT) ! 212: pkt->pk_op = CLSOP; ! 213: ch_close(conn, pkt, 0); ! 214: goto shut; ! 215: } ! 216: if (flag & FWRITE) { ! 217: /* ! 218: * If any input packets other than the RFC are around ! 219: * something is wrong and we just abort the connection ! 220: */ ! 221: while ((pkt = conn->cn_rhead) != NOPKT) { ! 222: ch_read(conn); ! 223: if (pkt->pk_op != RFCOP) ! 224: goto recclose; ! 225: } ! 226: /* ! 227: * We set this flag telling the interrupt time ! 228: * receiver to abort the connection if any new packets ! 229: * arrive. ! 230: */ ! 231: conn->cn_sflags |= CHCLOSING; ! 232: /* ! 233: * Closing a stream transmitter involves flushing ! 234: * the last packet, sending an EOF and waiting for ! 235: * it to be acknowledged. If the connection was ! 236: * bidirectional, the reader should have already ! 237: * read until EOF if everything is to be closed ! 238: * cleanly. ! 239: */ ! 240: checkfull: ! 241: while (chtfull(conn)) { ! 242: conn->cn_sflags |= CHOWAIT; ! 243: sleep((caddr_t)&conn->cn_thead, CHIOPRIO); ! 244: } ! 245: if (conn->cn_state == CSOPEN || ! 246: conn->cn_state == CSRFCRCVD) { ! 247: if (conn->cn_toutput) { ! 248: ch_sflush(conn); ! 249: goto checkfull; ! 250: } ! 251: if (conn->cn_state == CSOPEN) ! 252: (void)ch_eof(conn); ! 253: } ! 254: while (!chtempty(conn)) { ! 255: conn->cn_sflags |= CHOWAIT; ! 256: sleep((caddr_t)&conn->cn_thead, CHIOPRIO); ! 257: } ! 258: } else if (conn->cn_state == CSOPEN) { ! 259: /* ! 260: * If we are only reading then we should read the EOF ! 261: * before closing and wiat for the other end to close. ! 262: */ ! 263: if (conn->cn_flags & CHEOFSEEN) ! 264: while (conn->cn_state == CSOPEN) ! 265: sleep((caddr_t)conn, CHIOPRIO); ! 266: } ! 267: recclose: ! 268: spl0(); ! 269: /* Fall into... */ ! 270: case CHRECORD: /* Record oriented close is just sending a CLOSE */ ! 271: if (conn->cn_state == CSOPEN) { ! 272: pkt = pkalloc(0, 0); ! 273: if (pkt != NOPKT) { ! 274: pkt->pk_op = CLSOP; ! 275: pkt->pk_len = 0; ! 276: } ! 277: ch_close(conn, pkt, 0); ! 278: } ! 279: } ! 280: shut: ! 281: spl0(); ! 282: ch_close(conn, NOPKT, 1); ! 283: ch_buffree(); ! 284: } ! 285: /* ! 286: * Raw read routine. ! 287: */ ! 288: chrread(dev) ! 289: dev_t dev; ! 290: { ! 291: register struct connection *conn; ! 292: register struct packet *pkt; ! 293: register int count, n; ! 294: ! 295: if(minor(dev) == CHURFCMIN) { ! 296: spl6(); ! 297: while ((pkt = ch_rnext()) == NOPKT) { ! 298: Rfcwaiting++; ! 299: sleep((caddr_t)&Chrfclist, CHIOPRIO); ! 300: } ! 301: spl0(); ! 302: if (u.u_count < pkt->pk_len) ! 303: u.u_error = EIO; ! 304: else ! 305: iomove((caddr_t)pkt->pk_cdata, pkt->pk_len, B_READ); ! 306: return; ! 307: } ! 308: conn = (struct connection *)CHFCONN(getf(u.u_arg[0])); ! 309: ! 310: switch (conn->cn_mode) { ! 311: case CHTTY: ! 312: panic("chread on tty"); ! 313: break; ! 314: case CHSTREAM: ! 315: for (count = u.u_count; u.u_count != 0; ) ! 316: switch (n = ch_sread(conn, (char*)0, u.u_count)) { ! 317: case 0: /* No data to read */ ! 318: if (count != u.u_count) ! 319: return; ! 320: spl6(); ! 321: while (chrempty(conn)) { ! 322: conn->cn_sflags |= CHIWAIT; ! 323: sleep((char *)&conn->cn_rhead, ! 324: CHIOPRIO); ! 325: } ! 326: spl0(); ! 327: break; ! 328: case CHEOF: ! 329: return; ! 330: default: ! 331: if (n < 0) { ! 332: u.u_error = EIO; ! 333: return; ! 334: } ! 335: } ! 336: break; ! 337: /* ! 338: * Record oriented mode gives a one byte packet opcode ! 339: * followed by the data in the packet. The buffer must ! 340: * be large enough to fit the data and the opcode, otherwise an ! 341: * i/o error results. ! 342: */ ! 343: case CHRECORD: ! 344: spl6(); ! 345: while (chrempty(conn)) { ! 346: conn->cn_sflags |= CHIWAIT; ! 347: sleep((char *)&conn->cn_rhead, ! 348: CHIOPRIO); ! 349: } ! 350: spl0(); ! 351: if ((pkt = conn->cn_rhead) == NOPKT || ! 352: pkt->pk_len + 1 > u.u_count) /* + 1 for opcode */ ! 353: u.u_error = EIO; ! 354: else { ! 355: iomove((caddr_t)&pkt->pk_op, 1, B_READ); ! 356: iomove((caddr_t)pkt->pk_cdata, pkt->pk_len, B_READ); ! 357: spl6(); ! 358: ch_read(conn); ! 359: spl0(); ! 360: } ! 361: } ! 362: } ! 363: /* ! 364: * Raw write routine ! 365: * Note that user programs can write to a connection ! 366: * that has been CHIOCANSWER"'d, implying transmission of an ANS packet ! 367: * rather than a normal packet. This is illegal for TTY mode connections, ! 368: * is handled in the system independent stream code for STREAM mode, and ! 369: * is handled here for RECORD mode. ! 370: */ ! 371: chrwrite(dev) ! 372: dev_t dev; ! 373: { ! 374: register struct connection *conn; ! 375: ! 376: if(minor(dev) == CHURFCMIN) { ! 377: u.u_error = EIO; ! 378: return; ! 379: } ! 380: conn = (struct connection *)CHFCONN(getf(u.u_arg[0])); ! 381: chwrite(conn); ! 382: } ! 383: chwrite(conn) ! 384: register struct connection *conn; ! 385: { ! 386: register struct packet *pkt; ! 387: register int n; ! 388: ! 389: if (conn->cn_rhead != NOPKT && conn->cn_rhead->pk_op == RFCOP) { ! 390: spl6(); ! 391: ch_read(conn); ! 392: spl0(); ! 393: } ! 394: switch (conn->cn_mode) { ! 395: case CHTTY: ! 396: /* Fall into (on RAW mode only) */ ! 397: case CHSTREAM: ! 398: while (u.u_count != 0) ! 399: switch (n = ch_swrite(conn, (char *)0, u.u_count)) { ! 400: case 0: ! 401: spl6(); ! 402: while (chtfull(conn)) { ! 403: conn->cn_sflags |= CHOWAIT; ! 404: sleep((caddr_t)&conn->cn_thead, ! 405: CHIOPRIO); ! 406: } ! 407: spl0(); ! 408: break; ! 409: case CHTEMP: ! 410: sleep((caddr_t)&lbolt, CHIOPRIO); ! 411: break; ! 412: default: ! 413: if (n < 0) { ! 414: u.u_error = EIO; ! 415: return; ! 416: } ! 417: } ! 418: break; ! 419: case CHRECORD: /* one write call -> one packet */ ! 420: if (u.u_count < 1 || u.u_count - 1 > CHMAXDATA) { ! 421: u.u_error = EIO; ! 422: return; ! 423: } ! 424: loop: ! 425: spl6(); ! 426: while (chtfull(conn)) { ! 427: conn->cn_sflags |= CHOWAIT; ! 428: sleep((caddr_t)&conn->cn_thead, CHIOPRIO); ! 429: } ! 430: spl0(); ! 431: if ((pkt = pkalloc((int)(u.u_count - 1), 0)) == NOPKT) { ! 432: sleep((caddr_t)&lbolt, CHIOPRIO); ! 433: goto loop; ! 434: } ! 435: iomove(&pkt->pk_op, 1, B_WRITE); ! 436: pkt->pk_len = u.u_count; ! 437: if (u.u_count) ! 438: iomove(pkt->pk_cdata, u.u_count, B_WRITE); ! 439: if (u.u_error == 0) { ! 440: spl6(); ! 441: if (ch_write(conn, pkt)) ! 442: u.u_error = EIO; ! 443: spl0(); ! 444: } ! 445: } ! 446: } ! 447: ! 448: /* ! 449: * This routine allocates a packet and fills it with data from pointer in ! 450: * user space until null or CHMAXDATA characters ! 451: */ ! 452: static struct packet * ! 453: fillpacket(str, len) ! 454: register char *str; ! 455: int len; /* assumed <= CHMAXDATA */ ! 456: { ! 457: register char *ptr; ! 458: register struct packet *pkt; ! 459: int c; ! 460: extern uchar(); ! 461: ! 462: if ((pkt = pkalloc(CHMAXDATA, 0)) != NOPKT) { ! 463: ptr = pkt->pk_cdata; ! 464: for (pkt->pk_len = 0; *str != '\0' && pkt->pk_len < len; pkt->pk_len++) ! 465: *ptr++ = *str++; ! 466: while ((c = uchar()) > 0 && pkt->pk_len < CHMAXDATA) { ! 467: *ptr++ = c; ! 468: pkt->pk_len++; ! 469: } ! 470: if (c > 0) { ! 471: debug(DABNOR, ! 472: printf("Fillpacket too long: %s\n", ! 473: pkt->pk_cdata)); ! 474: ch_free((char *)pkt); ! 475: } else ! 476: return(pkt); ! 477: } ! 478: u.u_error = ENXIO; ! 479: return(NOPKT); ! 480: } ! 481: /* ! 482: * This is atoi from users space terminates on / or null. ! 483: * If cpp is not NULL then get the number from *cpp (u.u_dbuf). ! 484: * *cpp is stuffed where the scan stopped, enabling further usage of the ! 485: * contents of u.u_dbuf. ! 486: */ ! 487: static ! 488: uatoi(cpp) ! 489: char **cpp; ! 490: { ! 491: register char *p = cpp ? *cpp - 1 : (char *)0; ! 492: register int i = 0, chr; ! 493: extern uchar(); ! 494: ! 495: for (;;) { ! 496: if (p) ! 497: if (++p >= &u.u_dbuf[DIRSIZ]) ! 498: break; ! 499: else ! 500: chr = *p; ! 501: else if ((chr = uchar()) == '/') ! 502: break; ! 503: if ((chr -= '0') < 0 || chr > 9) ! 504: break; ! 505: i *= 10; ! 506: i += chr; ! 507: } ! 508: if (cpp) ! 509: *cpp = p; ! 510: return(i); ! 511: } ! 512: ! 513: /* ! 514: * Raw ioctl routine - perform non-connection functions, otherwise call down ! 515: */ ! 516: chrioctl(dev, cmd, addr, flag) ! 517: register int cmd; ! 518: caddr_t addr; ! 519: { ! 520: register char *cp; ! 521: register int c; ! 522: ! 523: switch (cmd) { ! 524: /* ! 525: * Skip the first unmatched RFC at the head of the queue ! 526: * and mark it so that ch_rnext will never pick it up again. ! 527: */ ! 528: case CHIOCRSKIP: ! 529: if (minor(dev) != CHURFCMIN) ! 530: break; ! 531: spl6(); ! 532: ch_rskip(); ! 533: spl0(); ! 534: return; ! 535: /* ! 536: * Specify the chaosnet address of an interlan ethernet interface. ! 537: */ ! 538: case CHIOCILADDR: ! 539: if (minor(dev) != CHURFCMIN) ! 540: break; ! 541: #if NCHIL > 0 ! 542: { ! 543: struct chiladdr ca; ! 544: ! 545: if (addr == 0 || copyin(addr, (caddr_t)&ca, sizeof(ca))) ! 546: break; ! 547: if (chilseta(ca.cil_device, ca.cil_address)) ! 548: break; ! 549: return; ! 550: } ! 551: #else ! 552: break; ! 553: #endif ! 554: case CHIOCNAME: ! 555: if (minor(dev) != CHURFCMIN) ! 556: break; ! 557: for (cp = Chmyname; c = fubyte(addr); *cp++ = c, addr++) ! 558: if (c < 0) { ! 559: cp = Chmyname; ! 560: u.u_error = EFAULT; ! 561: break; ! 562: } else if(cp >= &Chmyname[CHSTATNAME]) ! 563: break; ! 564: while (cp < &Chmyname[CHSTATNAME]) ! 565: *cp++ = '\0'; ! 566: if (c >= 0) ! 567: return; ! 568: break; ! 569: /* ! 570: * Specify my own network number. ! 571: */ ! 572: case CHIOCADDR: ! 573: if (minor(dev) != CHURFCMIN) ! 574: break; ! 575: Chmyaddr = (int)addr; ! 576: return; ! 577: default: ! 578: if (minor(dev) == CHURFCMIN) ! 579: break; ! 580: chioctl(CHFCONN(getf(u.u_arg[0])), dev, cmd, addr, flag); ! 581: return; ! 582: } ! 583: u.u_error = ENXIO; ! 584: } ! 585: /* ARGSUSED */ ! 586: chioctl(conn, dev, cmd, addr, flag) ! 587: register struct connection *conn; ! 588: dev_t dev; ! 589: caddr_t addr; ! 590: { ! 591: register struct packet *pkt; ! 592: struct chstatus chst; ! 593: ! 594: switch(cmd) { ! 595: /* ! 596: * Read the first packet in the read queue for a connection. ! 597: * This call is primarily intended for those who want to read ! 598: * non-data packets (which are normally ignored) like RFC ! 599: * (for arguments in the contact string), CLS (for error string) etc. ! 600: * The reader's buffer is assumed to be CHMAXDATA long. When ioctl's ! 601: * change on the VAX to have data length arguments, this will be done ! 602: * right. An error results if there is no packet to read. ! 603: * No hanging is currently provided for. ! 604: * The normal mode of operation for reading such packets is to ! 605: * first do a CHIOCGSTAT call to find out whether there is a packet ! 606: * to read (and what kind) and then make this call - except for ! 607: * RFC's when you know it must be there. ! 608: */ ! 609: case CHIOCPREAD: ! 610: if ((pkt = conn->cn_rhead) == NULL) ! 611: break; ! 612: if (copyout((caddr_t)pkt->pk_cdata, addr, pkt->pk_len)) ! 613: break; ! 614: spl6(); ! 615: ch_read(conn); ! 616: spl0(); ! 617: return; ! 618: /* ! 619: * Change the mode of the connection. ! 620: * The default mode is CHSTREAM. ! 621: */ ! 622: case CHIOCSMODE: ! 623: switch ((int)addr) { ! 624: case CHTTY: ! 625: #if NCHT > 0 ! 626: if (conn->cn_state == CSOPEN && ! 627: conn->cn_mode != CHTTY) { ! 628: register struct tty *tp; ! 629: extern struct tty cht_tty[]; ! 630: extern int cht_cnt; ! 631: /* ! 632: * To turn a connection into a tty, ! 633: * we need to find a tty that is waiting to ! 634: * be opened and connect ourselves to it. ! 635: */ ! 636: for (tp = cht_tty; tp < &cht_tty[cht_cnt]; tp++) ! 637: if (tp->t_addr == 0 && ! 638: tp->t_state & WOPEN) { ! 639: tp->t_addr = (caddr_t)conn; ! 640: tp->t_state |= CARR_ON; ! 641: conn->cn_ttyp = tp; ! 642: conn->cn_mode = CHTTY; ! 643: wakeup((caddr_t)&tp->t_rawq); ! 644: return; ! 645: } ! 646: ! 647: } ! 648: #endif ! 649: break; ! 650: case CHSTREAM: ! 651: case CHRECORD: ! 652: if (conn->cn_mode == CHTTY) ! 653: break; ! 654: conn->cn_mode = (int)addr; ! 655: return; ! 656: } ! 657: break; ! 658: /* ! 659: * Flush the current output packet if there is one. ! 660: * This is only valid in stream mode. ! 661: * If the argument is non-zero an error is returned if the ! 662: * transmit window is full, otherwise we hang. ! 663: */ ! 664: case CHIOCFLUSH: ! 665: if (conn->cn_mode == CHSTREAM) { ! 666: spl6(); ! 667: while ((flag = ch_sflush(conn)) == CHTEMP) ! 668: if (addr) ! 669: break; ! 670: else { ! 671: conn->cn_sflags |= CHOWAIT; ! 672: sleep((caddr_t)&conn->cn_thead, ! 673: CHIOPRIO); ! 674: } ! 675: if (flag) ! 676: u.u_error = EIO; ! 677: spl0(); ! 678: return; ! 679: } ! 680: break; ! 681: /* ! 682: * Wait for all output to be acknowledged. If addr is non-zero ! 683: * an EOF packet is also sent before waiting. ! 684: * If in stream mode, output is flushed first. ! 685: */ ! 686: case CHIOCOWAIT: ! 687: if (conn->cn_mode == CHSTREAM) { ! 688: spl6(); ! 689: while ((flag = ch_sflush(conn)) == CHTEMP) { ! 690: conn->cn_sflags |= CHOWAIT; ! 691: sleep((caddr_t)&conn->cn_thead, CHIOPRIO); ! 692: } ! 693: spl0(); ! 694: if (flag) { ! 695: u.u_error = EIO; ! 696: return; ! 697: } ! 698: } ! 699: if (addr) { ! 700: spl6(); ! 701: while (chtfull(conn)) { ! 702: conn->cn_sflags |= CHOWAIT; ! 703: sleep((caddr_t)&conn->cn_thead, CHIOPRIO); ! 704: } ! 705: flag = ch_eof(conn); ! 706: spl0(); ! 707: if (flag) { ! 708: u.u_error = EIO; ! 709: return; ! 710: } ! 711: } ! 712: spl6(); ! 713: while (!chtempty(conn)) { ! 714: conn->cn_sflags |= CHOWAIT; ! 715: sleep((caddr_t)&conn->cn_thead, CHIOPRIO); ! 716: } ! 717: spl0(); ! 718: if (conn->cn_state != CSOPEN) ! 719: u.u_error = EIO; ! 720: return; ! 721: /* ! 722: * Return the status of the connection in a structure supplied ! 723: * by the user program. ! 724: */ ! 725: case CHIOCGSTAT: ! 726: chst.st_fhost = conn->cn_faddr; ! 727: chst.st_cnum = conn->cn_ltidx; ! 728: chst.st_rwsize = conn->cn_rwsize; ! 729: chst.st_twsize = conn->cn_twsize; ! 730: chst.st_state = conn->cn_state; ! 731: chst.st_cmode = conn->cn_mode; ! 732: chst.st_oroom = conn->cn_twsize - (conn->cn_tlast - conn->cn_tacked); ! 733: if ((pkt = conn->cn_rhead) != NOPKT) { ! 734: chst.st_ptype = pkt->pk_op; ! 735: chst.st_plength = pkt->pk_len; ! 736: } else { ! 737: chst.st_ptype = 0; ! 738: chst.st_plength = 0; ! 739: } ! 740: if (copyout((caddr_t)&chst, addr, sizeof(chst))) ! 741: break; ! 742: return; ! 743: /* ! 744: * Wait for the state of the connection to be different from ! 745: * the given state. ! 746: */ ! 747: case CHIOCSWAIT: ! 748: spl6(); ! 749: while (conn->cn_state == (int)addr) ! 750: sleep((caddr_t)conn, CHIOPRIO); ! 751: spl0(); ! 752: return; ! 753: /* ! 754: * Answer an RFC. Basically this call does nothing except ! 755: * setting a bit that says this connection should be of the ! 756: * datagram variety so that the connection automatically gets ! 757: * closed after the first write, whose data is immediately sent ! 758: * in an ANS packet. ! 759: */ ! 760: case CHIOCANSWER: ! 761: spl6(); ! 762: if (conn->cn_state == CSRFCRCVD && conn->cn_mode != CHTTY) ! 763: conn->cn_flags |= CHANSWER; ! 764: else ! 765: u.u_error = EIO; ! 766: spl0(); ! 767: return; ! 768: /* ! 769: * Reject a RFC, giving a string (null terminated), to put in the ! 770: * close packet. This call can also be used to shut down a connection ! 771: * prematurely giving an ascii close reason. ! 772: */ ! 773: case CHIOCREJECT: ! 774: spl6(); ! 775: if (conn->cn_state == CSRFCRCVD || conn->cn_state == CSOPEN) { ! 776: u.u_dirp = addr; /* a kludge for fillpacket */ ! 777: pkt = fillpacket("", 0); ! 778: pkt->pk_op = CLSOP; ! 779: ch_close(conn, pkt, 0); ! 780: } else ! 781: u.u_error = EIO; ! 782: spl0(); ! 783: return; ! 784: /* ! 785: * Accept an RFC causing the OPEN packet to be sent ! 786: */ ! 787: case CHIOCACCEPT: ! 788: spl6(); ! 789: if (conn->cn_state == CSRFCRCVD) ! 790: ch_accept(conn); ! 791: else ! 792: u.u_error = EIO; ! 793: spl0(); ! 794: return; ! 795: /* ! 796: * Count how many bytes can be immediately read. ! 797: */ ! 798: case FIONREAD: ! 799: if (conn->cn_mode != CHTTY) { ! 800: off_t nread = 0; ! 801: ! 802: for (pkt = conn->cn_rhead; pkt != NOPKT; pkt = pkt->pk_next) ! 803: if (ISDATOP(pkt)) ! 804: nread += pkt->pk_len; ! 805: if (conn->cn_rhead != NOPKT) ! 806: nread -= conn->cn_roffset; ! 807: if (copyout((caddr_t)&nread, addr, sizeof(off_t))) ! 808: u.u_error = EFAULT; ! 809: return; ! 810: } ! 811: default: ! 812: break; ! 813: } ! 814: u.u_error = ENXIO; ! 815: } ! 816: /* ! 817: * Timeout routine that implements the chaosnet clock process. ! 818: */ ! 819: chtimeout() ! 820: { ! 821: register int s = spl6(); ! 822: ch_clock(); ! 823: timeout(chtimeout, 0, 1); ! 824: splx(s); ! 825: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.