|
|
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.