## diffname gnot/devdk.c 1990/0312 ## diff -e /dev/null /n/bootesdump/1990/0312/sys/src/9/68020/devdk.c 0a #include "u.h" #include "lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "io.h" #include "errno.h" #define NOW (MACHP(0)->ticks) #define DPRINT if(0) enum { /* * configuration parameters */ Ndk = 2, /* max dks */ /* * relative or immutable */ Nline = 256, /* max lines per dk */ Ndir = Nline + 1, /* entries in the dk directory */ Nsubdir = 5, /* entries in the sub directory */ }; typedef struct Dkmsg Dkmsg; typedef struct Line Line; typedef struct Dk Dk; /* * types of possible dkcalls */ enum { Dial, Announce, Redial }; /* * format of messages to/from the datakit controller on the common * signalling line */ struct Dkmsg { uchar type; uchar srv; uchar param0l; uchar param0h; uchar param1l; uchar param1h; uchar param2l; uchar param2h; uchar param3l; uchar param3h; uchar param4l; uchar param4h; }; /* * message codes (T_xxx == dialin.type, D_xxx == dialin.srv) */ #define T_SRV 1 /* service request */ #define D_SERV 1 /* (host to dkmux) announce a service */ #define D_DIAL 2 /* (host to dkmux) connect to a service */ #define D_XINIT 7 /* (dkmux to host) line has been spliced */ #define T_REPLY 2 /* reply to T_SRV/D_SERV or T_SRV/D_DIAL */ #define D_OK 1 /* not used */ #define D_OPEN 2 /* (dkmux to host) connection established */ #define D_FAIL 3 /* (dkmux to host) connection failed */ #define T_CHG 3 /* linege the status of a connection */ #define D_CLOSE 1 /* close the connection */ #define D_ISCLOSED 2 /* (dkmux to host) confirm a close */ #define D_CLOSEALL 3 /* (dkmux to host) close all connections */ #define D_REDIAL 6 /* (host to dkmux) redial a call */ #define T_ALIVE 4 /* (host to dkmux) keep alive message */ #define D_CONTINUE 0 /* host has not died since last msg */ #define D_RESTART 1 /* host has restarted */ #define D_MAXCHAN 2 /* request maximum line number */ #define T_RESTART 8 /* (dkmux to host) datakit restarted */ /* * macros for cracking/forming the window negotiation parameter */ #define MIN(x,y) (x < y ? x : y) #define W_WINDOW(o,d,t) ((o<<8) | (d<<4) | t | 0100000) #define W_VALID(x) ((x) & 0100000) #define W_ORIG(x) (((x)>>8) & 017) #define W_DEST(x) (((x)>>4) & 017) #define W_TRAF(x) ((x) & 017) #define W_DESTMAX(x,y) (W_WINDOW(W_ORIG(x),MIN(W_DEST(x),y),W_TRAF(x))) #define W_LIMIT(x,y) (W_WINDOW(MIN(W_ORIG(x),y),MIN(W_DEST(x),y),W_TRAF(x))) #define W_VALUE(x) (1<<((x)+4)) #define WS_2K 7 /* * one per datakit line */ struct Line { QLock; Rendez r; /* wait here for dial */ int state; /* dial state */ int err; /* dialing error (if non zero) */ int window; /* negotiated window */ int timestamp; /* timestamp of last call received on this line */ int calltolive; /* multiple of 15 seconds for dialing state to last */ Queue *rq; char addr[64]; char raddr[64]; char ruser[32]; char other[64]; Dk *dp; /* interface contianing this line */ }; /* * a dkmux dk. one exists for every stream that a * dkmux line discipline is pushed onto. */ struct Dk { QLock; int ref; char name[64]; /* dk name */ Queue *wq; /* dk output queue */ int lines; /* number of lines */ int ncsc; /* csc line number */ Chan *csc; /* common signalling line */ Line line[Nline]; }; static Dk dk[Ndk]; /* * conversation states (for Line.state) */ typedef enum { Lclosed=0, Lopened, /* opened but no call out */ Lconnected, /* opened and a call set up on htis line */ Lrclose, /* remote end has closed down */ Llclose, /* local end has closed down */ Ldialing, /* dialing a new call */ Llistening, /* this line listening for calls */ Lackwait, /* incoming call waiting for ack/nak */ Laccepting, /* waiting for user to accept or reject the call */ } Lstate; /* * datakit error to errno */ enum { DKok, DKbusy, DKnetotl, DKdestotl, DKbadnet, DKnetbusy, DKinuse, DKreject, }; int dkerr[]={ [DKok]Egreg, [DKbusy]Einuse, /* destination busy */ [DKnetotl]Enetotl, /* network not answering */ [DKdestotl]Edestotl, /* destination not answering */ [DKbadnet]Ebadnet, /* unassigned destination */ [DKnetbusy]Enetbusy, /* network overload */ [DKinuse]Einuse, /* server already exists */ [DKreject]Erejected /* call rejected by destination */ }; #define DKERRS sizeof(dkerr)/sizeof(int) /* * imported */ extern Qinfo urpinfo; /* * predeclared */ Chan* dkattach(char*); static void dkmuxconfig(Dk*, Block*); static int dkmesg(Dk*, int, int, int, int); static void dkcsckproc(void*); static int dklisten(Chan*); static void dkanswer(Chan*, int, int); static void dkwindow(Chan*); static void dkcall(int, Chan*, char*, char*, char*); static void dktimer(void*); static void dkchgmesg(Dk*, Dkmsg*, int); static void dkreplymesg(Dk*, Dkmsg*, int); Chan* dkopen(Chan*, int); /* * the datakit multiplexor stream module definition */ static void dkmuxopen(Queue *, Stream *); static void dkmuxclose(Queue *); static void dkmuxoput(Queue *, Block *); static void dkmuxiput(Queue *, Block *); Qinfo dkmuxinfo = { dkmuxiput, dkmuxoput, dkmuxopen, dkmuxclose, "dkmux" }; /* * a new dkmux. find a free dk structure and assign it to this queue. */ static void dkmuxopen(Queue *q, Stream *s) { Dk *dp; int i; for(dp = dk; dp < &dk[Ndk]; dp++){ if(dp->wq == 0){ qlock(dp); if(dp->wq) { /* someone was faster than us */ qunlock(dp); continue; } q->ptr = q->other->ptr = (void *)dp; dp->csc = 0; dp->ncsc = 4; dp->lines = 16; dp->name[0] = 0; dp->wq = WR(q); qunlock(dp); return; } } error(0, Enoifc); } /* * close down a dkmux */ static void dkmuxclose(Queue *q) { Dk *dp; dp = (Dk *)q->ptr; qlock(dp); if(dp->csc) close(dp->csc); dp->wq = 0; qunlock(dp); } /* * handle configuration */ static void dkmuxoput(Queue *q, Block *bp) { Dk *dp; dp = (Dk *)q->ptr; if(bp->type != M_DATA){ if(streamparse("config", bp)) dkmuxconfig(dp, bp); else PUTNEXT(q, bp); return; } PUTNEXT(q, bp); } /* * gather a message and send it up the appropriate stream * * The first two bytes of each message contains the channel * number, low order byte first. * * Simplifying assumption: one put == one message && the channel number * is in the first block. If this isn't true, demultiplexing will not * work. */ static void dkmuxiput(Queue *q, Block *bp) { Dk *dp; Line *lp; int line; dp = (Dk *)q->ptr; if(bp->type != M_DATA){ PUTNEXT(q, bp); return; } line = bp->rptr[0] | (bp->rptr[1]<<8); bp->rptr += 2; if(line<0 || line>=dp->lines){ print("dkmuxiput bad line %d\n", line); freeb(bp); return; } lp = &dp->line[line]; if(canqlock(lp)){ if(lp->rq) PUTNEXT(lp->rq, bp); else{ print("dkmuxiput unopened line %d\n", line); freeb(bp); } qunlock(lp); } else { print("dkmuxiput unopened line %d\n", line); freeb(bp); } } /* * the datakit line stream module definition */ static void dkstopen(Queue *, Stream *); static void dkstclose(Queue *); static void dkoput(Queue *, Block *); static void dkiput(Queue *, Block *); Qinfo dkinfo = { dkiput, dkoput, dkstopen, dkstclose, "dk" }; /* * open and save a pointer to the conversation */ static void dkstopen(Queue *q, Stream *s) { Dk *dp; Line *lp; dp = &dk[s->dev]; q->other->ptr = q->ptr = lp = &dp->line[s->id]; lp->dp = dp; lp->rq = q; } /* * close down a datakit conversation */ static void dkstclose(Queue *q) { Dk *dp; Line *lp; lp = (Line *)q->ptr; dp = lp->dp; /* * shake hands with dk */ switch(lp->state){ case Lclosed: case Llclose: break; case Lrclose: dkmesg(dp, T_CHG, D_CLOSE, lp - dp->line, 0); lp->state = Lclosed; break; case Lackwait: dkmesg(dp, T_CHG, D_CLOSE, lp - dp->line, 0); lp->state = Llclose; break; case Llistening: dkmesg(dp, T_CHG, D_CLOSE, lp - dp->line, 0); lp->state = Llclose; break; case Lconnected: dkmesg(dp, T_CHG, D_CLOSE, lp - dp->line, 0); lp->state = Llclose; break; case Lopened: lp->state = Lclosed; } qlock(lp); lp->rq = 0; qunlock(lp); } /* * this is only called by hangup */ static void dkiput(Queue *q, Block *bp) { PUTNEXT(q, bp); } /* * we assume that each put is a message. * * add a 2 byte channel number to the start of each message */ static void dkoput(Queue *q, Block *bp) { Line *lp; Dk *dp; int line; if(bp->type != M_DATA){ freeb(bp); error(0, Ebadarg); } lp = (Line *)q->ptr; dp = lp->dp; line = lp - dp->line; if(bp->base && bp->rptr - bp->base >= 2) bp->rptr -= 2; bp->rptr[0] = line; bp->rptr[1] = line>>8; PUTNEXT(dp->wq, bp); } /* * configure a datakit multiplexor. this takes 3 arguments separated * by spaces: * the line number of the common signalling channel (must be > 0) * the number of lines in the device (optional) * the name of the dk (optional) * * we can configure only once */ static void dkmuxconfig(Dk *dp, Block *bp) { Chan *c; char *fields[3]; int n; char buf[64]; static int dktimeron; if(dp->csc != 0){ freeb(bp); error(0, Ebadarg); } /* * parse */ n = getfields((char *)bp->rptr, fields, 3, ' '); switch(n){ case 3: strncpy(dp->name, fields[2], sizeof(dp->name)); case 2: dp->lines = strtoul(fields[1], 0, 0); case 1: dp->ncsc = strtoul(fields[0], 0, 0); break; default: freeb(bp); error(0, Ebadarg); } freeb(bp); if(dp->ncsc <= 0 || dp->lines <= dp->ncsc){ dp->lines = 16; error(0, Ebadarg); } /* * open a stream for the csc and push urp onto it */ c = 0; if(waserror()){ if(c) close(c); nexterror(); } c = dkattach(dp->name); c->qid = STREAMQID(dp->ncsc, Sdataqid); dkopen(c, ORDWR); dp->csc = c; /* * start a process to deal with it */ sprint(buf, "**csckproc%d**", dp->ncsc); kproc(buf, dkcsckproc, dp); poperror(); /* * start a keepalive process if one doesn't exist */ if(dktimeron == 0){ dktimeron = 1; kproc("**dktimer**", dktimer, 0); } } /* * qid's */ enum { /* * per line */ Daddrqid, Dlistenqid, Draddrqid, Duserqid, Dotherqid, Dlineqid, /* * per device */ Dcloneqid, }; /* * the dk directory */ Dirtab dkdir[Ndir]; /* * the per stream directory structure */ Dirtab dksubdir[]={ "addr", Daddrqid, 0, 0600, "listen", Dlistenqid, 0, 0600, "other", Dotherqid, 0, 0600, "raddr", Draddrqid, 0, 0600, "ruser", Duserqid, 0, 0600, }; /* * dk file system. most of the calls use dev.c to access the dk * directory and stream.c to access the dk devices. */ void dkreset(void) { } /* * create the dk directory. the files are `clone' and stream * directories '1' to '32' (or whatever Nline is in decimal) */ void dkinit(void) { int i; /* * create the directory. */ /* * the circuits */ for(i = 1; i < Nline; i++) { sprint(dkdir[i].name, "%d", i); dkdir[i].qid = CHDIR|STREAMQID(i, Dlineqid); dkdir[i].length = 0; dkdir[i].perm = 0600; } /* * the clone device */ strcpy(dkdir[0].name, "clone"); dkdir[0].qid = Dcloneqid; dkdir[0].length = 0; dkdir[0].perm = 0600; } Chan* dkattach(char *spec) { Chan *c; Dk *dp; print("attach\n"); /* * find a multiplexor with the same name */ for(dp = dk; dp < &dk[Ndk]; dp++){ qlock(dp); print("name %s %lux\n", dp->name, dp->wq); if(dp->wq && strcmp(spec, dp->name)==0) { dp->ref++; qunlock(dp); break; } qunlock(dp); } if(dp == &dk[Ndk]) error(0, Enoifc); c = devattach('k', spec); c->dev = dp - dk; print("attach done\n"); return c; } Chan* dkclone(Chan *c, Chan *nc) { Dk *dp; dp = &dk[c->dev]; qlock(dp); dp->ref++; qunlock(dp); return devclone(c, nc); } int dkwalk(Chan *c, char *name) { if(c->qid == CHDIR) return devwalk(c, name, dkdir, dk[c->dev].lines, devgen); else return devwalk(c, name, dksubdir, Nsubdir, streamgen); } void dkstat(Chan *c, char *dp) { if(c->qid == CHDIR) devstat(c, dp, dkdir, dk[c->dev].lines, devgen); else devstat(c, dp, dksubdir, Nsubdir, streamgen); } /* * opening a dk device allocates a Line. Opening the `clone' * device is a ``macro'' for finding a free Line and opening * it's ctl file. * * opening the `listen' sub device is a macro for listening for * a new call. Lile `clone' the ctl file of the new channel is * returned. */ Chan* dkopen(Chan *c, int omode) { extern Qinfo dkinfo; Stream *s; Line *lp, *end; Dk *dp; int line; if(c->qid == Dcloneqid){ /* * get an unused device and open it's control file */ dp = &dk[c->dev]; end = &dp->line[dp->lines]; for(lp = &dp->line[dp->ncsc+1]; lp < end; lp++){ if(lp->state == Lclosed && canqlock(lp)){ if(lp->state != Lclosed){ qunlock(lp); continue; } c->qid = STREAMQID(lp-dp->line, Sctlqid); qunlock(lp); break; } } if(lp == end) error(0, Enodev); streamopen(c, &dkinfo); pushq(c->stream, &urpinfo); } else if(STREAMTYPE(c->qid) == Dlistenqid){ /* * listen for a call and open the control file for the * channel on which the call arrived. */ line = dklisten(c); c->qid = STREAMQID(line, Sctlqid); streamopen(c, &dkinfo); pushq(c->stream, &urpinfo); dkwindow(c); } else if(c->qid != CHDIR){ /* * open whatever c points to, make sure it has an urp */ streamopen(c, &dkinfo); if(strcmp(c->stream->procq->next->info->name, "urp")!=0) pushq(c->stream, &urpinfo); } c->mode = openmode(omode); c->flag |= COPEN; c->offset = 0; return c; } void dkcreate(Chan *c, char *name, int omode, ulong perm) { error(0, Eperm); } void dkclose(Chan *c) { Dk *dp; /* real closing happens in lancestclose */ if(c->qid != CHDIR) streamclose(c); dp = &dk[c->dev]; qlock(dp); dp->ref--; qunlock(dp); } long dkread(Chan *c, void *a, long n) { int t; Line *lp; t = STREAMTYPE(c->qid); if(t>=Slowqid || t==Dlineqid) return streamread(c, a, n); if(c->qid == CHDIR) return devdirread(c, a, n, dkdir, dk[c->dev].lines, devgen); lp = &dk[c->dev].line[STREAMID(c->qid)]; switch(t){ case Daddrqid: return stringread(c, a, n, lp->addr); case Draddrqid: return stringread(c, a, n, lp->raddr); case Duserqid: return stringread(c, a, n, lp->ruser); } error(0, Eperm); } long dkwrite(Chan *c, void *a, long n) { int t; char buf[256]; char *field[5]; int m; t = STREAMTYPE(c->qid); /* * get data dispatched as quickly as possible */ if(t == Sdataqid) return streamwrite(c, a, n, 0); /* * easier to do here than in dkoput */ if(t == Sctlqid){ strncpy(buf, a, sizeof buf); m = getfields(buf, field, 5, ' '); if(strcmp(field[0], "connect")==0){ if(m < 2) error(0, Ebadarg); dkcall(Dial, c, field[1], 0, 0); } else if(strcmp(field[0], "announce")==0){ if(m < 2) error(0, Ebadarg); dkcall(Announce, c, field[1], 0, 0); } else if(strcmp(field[0], "redial")==0){ if(m < 4) error(0, Ebadarg); dkcall(Redial, c, field[1], field[2], field[3]); } else if(strcmp(field[0], "accept")==0){ if(m < 2) error(0, Ebadarg); dkanswer(c, strtoul(field[1], 0, 0), 0); } else if(strcmp(field[0], "reject")==0){ if(m < 3) error(0, Ebadarg); dkanswer(c, strtoul(field[1], 0, 0), strtoul(field[2], 0, 0)); } else return streamwrite(c, a, n, 0); return n; } if(t >= Slowqid) return streamwrite(c, a, n, 0); error(0, Eperm); } void dkremove(Chan *c) { error(0, Eperm); } void dkwstat(Chan *c, char *dp) { error(0, Eperm); } void dkerrstr(Error *e, char *buf) { rooterrstr(e, buf); } void dkuserstr(Error *e, char *buf) { extern consuserstr(Error *, char *); consuserstr(e, buf); } /* * send a message to the datakit on the common signaling line */ static int dkmesg(Dk *dp, int type, int srv, int p0, int p1) { Dkmsg d; Block *bp; if(dp->csc == 0) return -1; if(waserror()) return -1; d.type = type; d.srv = srv; d.param0l = p0; d.param0h = p0>>8; d.param1l = p1; d.param1h = p1>>8; d.param2l = 0; d.param2h = 0; d.param3l = 0; d.param3h = 0; d.param4l = 0; d.param4h = 0; streamwrite(dp->csc, (char *)&d, sizeof(Dkmsg), 1); poperror(); return 0; } /* * call out on a datakit */ static int calldone(void *a) { Line *lp; lp = (Line *)a; return lp->state != Ldialing; } static void dkcall(int type, Chan *c, char *addr, char *nuser, char *machine) { char dialstr[66]; int line; char dialtone; int t_val, d_val; Dk *dp; Line *lp; Chan *dc; line = STREAMID(c->qid); dp = &dk[c->dev]; lp = &dp->line[line]; /* * only dial on virgin lines */ if(lp->state != Lclosed) error(0, Ebadarg); DPRINT("dkcall(line=%d, type=%d, dest=%s)\n", line, type, addr); /* * build dial string (guard against new lines) */ if(strchr(addr, '\n')) error(0, Ebadarg); if(strlen(addr)+strlen(u->p->pgrp->user)+2 >= sizeof(dialstr)) error(0, Ebadarg); strcpy(dialstr, addr); switch(type){ case Dial: t_val = T_SRV; d_val = D_DIAL; strcat(dialstr, "\n"); strcat(dialstr, u->p->pgrp->user); strcat(dialstr, "\n"); break; case Announce: t_val = T_SRV; d_val = D_SERV; break; case Redial: t_val = T_CHG; d_val = D_REDIAL; strcat(dialstr, "\n"); strcat(dialstr, nuser); strcat(dialstr, "\n"); strcat(dialstr, machine); strcat(dialstr, "\n"); break; } /* * open the data file */ dc = dkattach(dp->name); if(waserror()){ close(dc); nexterror(); } dc->qid = STREAMQID(line, Sdataqid); dkopen(dc, ORDWR); lp->calltolive = 4; lp->state = Ldialing; /* * tell the controller we want to make a call */ DPRINT("dialout\n"); dkmesg(dp, t_val, d_val, line, W_WINDOW(WS_2K,WS_2K,2)); /* * if redial, wait for a dial tone (otherwise we might send * the dialstr to the previous other end and not the controller) */ if(type==Redial){ if(streamread(dc, &dialtone, 1L) != 1L){ lp->state = Lconnected; error(0, Ebadarg); } } /* * make the call */ DPRINT("dialstr %s\n", dialstr); streamwrite(dc, dialstr, (long)strlen(dialstr), 1); close(dc); poperror(); /* * redial's never get a reply, assume it worked */ if(type == Redial) { lp->state = Lconnected; return; } /* * wait for a reply */ DPRINT("reply wait\n"); sleep(&lp->r, calldone, lp); /* * if there was an error, translate it to a plan 9 * errno and report it to the user. */ DPRINT("got reply %d\n", lp->state); if(lp->state != Lconnected) { if(lp->err >= DKERRS) error(0, dkerr[0]); else error(0, dkerr[lp->err]); } /* * linege state if serving */ if(type == D_SERV){ lp->state = Llistening; } DPRINT("connected!\n"); /* * decode the window size */ if (W_VALID(lp->window)){ /* * a 1127 window negotiation */ lp->window = W_VALUE(W_DEST(lp->window)); } else if(lp->window>2 && lp->window<31){ /* * a generic window negotiation */ lp->window = 1<window; } else lp->window = 0; /* * tag the connection */ strncpy(lp->addr, addr, sizeof(lp->addr)-1); strncpy(lp->raddr, addr, sizeof(lp->raddr)-1); /* * reset the protocol */ dkwindow(c); } /* * listen for a call, reflavor the */ static int dklisten(Chan *c) { char dialstr[512]; char *line[12]; char *field[8]; Line *lp; Dk *dp; int n, lineno, ts, window; Chan *dc; dp = &dk[c->dev]; /* * open the data file */ dc = dkattach(dp->name); if(waserror()){ close(dc); nexterror(); } dc->qid = STREAMQID(STREAMID(c->qid), Sdataqid); dkopen(dc, ORDWR); /* * wait for a call in */ for(;;){ /* * read the dialstring and null terminate it */ n = streamread(dc, dialstr, sizeof(dialstr)-1); DPRINT("returns %d\n", n); if(n <= 0) error(0, Eio); dialstr[n] = 0; DPRINT("dialstr = %s\n", dialstr); /* * break the dial string into lines */ n = getfields(dialstr, line, 12, '\n'); if (n < 2) { DPRINT("bad dialstr from dk (1 line)\n"); error(0, Eio); } /* * line 0 is `line.tstamp.traffic[.urpparms.window]' */ window = 0; switch(getfields(line[0], field, 5, '.')){ case 5: /* * generic way of passing window */ window = strtoul(field[4], 0, 0); if(window > 0 && window <31) window = 1<= dp->lines){ print("dklisten: illegal line %d\n", lineno); continue; } lp = &dp->line[lineno]; ts = strtoul(field[1], 0, 0); /* * this could be a duplicate request */ if(ts == lp->timestamp){ print("dklisten: repeat timestamp %d\n", lineno); continue; } /* * take care of glare (datakit picked an inuse channel * for the call to come in on). */ if(!canqlock(lp)){ print("DKbusy1\n"); dkanswer(c, lineno, DKbusy); continue; } else { if(lp->state != Lclosed){ qunlock(lp); print("DKbusy2 %ux\n", lp->state); dkanswer(c, lineno, DKbusy); continue; } } lp->window = window; /* * Line 1 is `my-dk-name.service[.more-things]'. * Special characters are escaped by '\'s. */ strncpy(lp->addr, line[1], sizeof(lp->addr)-1); /* * the rest is variable length */ switch(n) { case 2: /* no more lines */ lp->ruser[0] = 0; lp->raddr[0] = 0; break; case 3: /* line 2 is `source.user.param1.param2' */ getfields(line[2], field, 3, '.'); strncpy(lp->raddr, field[0], sizeof(lp->raddr)-1); strncpy(lp->ruser, field[1], sizeof(lp->ruser)-1); break; case 4: /* line 2 is `user.param1.param2' */ getfields(line[2], field, 2, '.'); strncpy(lp->ruser, field[0], sizeof(lp->ruser)-1); /* line 3 is `source.node.mod.line' */ strncpy(lp->raddr, line[3], sizeof(lp->raddr)-1); break; default: print("bad message from dk(>4 line)\n"); qunlock(lp); error(0, Ebadarg); } sprint(lp->other, "w(%d)", W_TRAF(lp->window)); DPRINT("src(%s)user(%s)dest(%s)other(%s)\n", lp->raddr, lp->ruser, lp->addr, lp->other); lp->timestamp = ts; lp->state = Lconnected; qunlock(lp); close(dc); poperror(); DPRINT("dklisten returns %d\n", lineno); return lineno; } } /* * answer a call */ static void dkanswer(Chan *c, int line, int code) { char reply[64]; Dk *dp; Chan *dc; Line *lp; dp = &dk[c->dev]; lp = &dp->line[line]; /* * open the data file (c is a control file) */ dc = dkattach(dp->name); if(waserror()){ close(dc); nexterror(); } dc->qid = STREAMQID(STREAMID(c->qid), Sdataqid); dkopen(dc, ORDWR); /* * send the reply */ sprint(reply, "%ud.%ud.%ud", line, lp->timestamp, code); DPRINT("dkanswer %s\n", reply); streamwrite(dc, reply, strlen(reply), 1); close(dc); poperror(); } /* * set the window size and reset the protocol */ static void dkwindow(Chan *c) { char buf[64]; long wins; Line *lp; lp = &dk[c->dev].line[STREAMID(c->qid)]; if(lp->window == 0) lp->window = 64; sprint(buf, "init %d %d", lp->window, Streamhi); streamwrite(c, buf, strlen(buf), 1); } /* * hangup a datakit connection */ static void dkhangup(Line *lp) { Block *bp; qlock(lp); if(lp->rq){ bp = allocb(0); bp->type = M_HANGUP; PUTNEXT(lp->rq, bp); } qunlock(lp); } /* * A process which listens to all input on a csc line */ static void dkcsckproc(void *a) { long n; Dk *dp; Dkmsg d; int line; int i; dp = (Dk *)a; /* * loop forever listening */ for(;;){ n = streamread(dp->csc, (char *)&d, (long)sizeof(d)); if(n != sizeof(d)){ print("strange csc message %d\n", n); continue; } line = (d.param0h<<8) + d.param0l; /* print("t(%d)s(%d)l(%d)\n", d.type, d.srv, line); /**/ switch (d.type) { case T_CHG: /* controller wants to close a line */ dkchgmesg(dp, &d, line); break; case T_REPLY: /* reply to a dial request */ dkreplymesg(dp, &d, line); break; case T_SRV: /* ignore it, it's useless */ print("dksrvmesg(%d)\n", line); break; case T_RESTART: /* datakit reboot */ print("dk restart\n"); if(line >=0 && linelines){ print("maxlines=%d\n", line+1); dp->lines=line+1; } break; default: DPRINT("unrecognized csc message %o(%o)\n", d.type, line); break; } } } /* * datakit requests or confirms closing a line */ static void dkchgmesg(Dk *dp, Dkmsg *dialp, int line) { Line *lp; if (line <= 0 || line >= dp->lines) { /* tell controller this line is not in use */ dkmesg(dp, T_CHG, D_CLOSE, line, 0); return; } lp = &dp->line[line]; switch (dialp->srv) { case D_CLOSE: /* remote shutdown */ switch (lp->state) { case Ldialing: /* simulate a failed connection */ dkreplymesg(dp, (Dkmsg *)0, line); lp->state = Lrclose; break; case Lrclose: case Lconnected: case Llistening: case Lackwait: dkhangup(lp); lp->state = Lrclose; break; case Lopened: dkmesg(dp, T_CHG, D_CLOSE, line, 0); break; case Llclose: case Lclosed: dkhangup(lp); dkmesg(dp, T_CHG, D_CLOSE, line, 0); lp->state = Lclosed; break; } break; case D_ISCLOSED: /* acknowledging a local shutdown */ switch (lp->state) { case Llclose: case Lclosed: lp->state = Lclosed; break; case Lrclose: case Lconnected: case Llistening: case Lackwait: break; } break; default: print("unrecognized T_CHG\n"); } } /* * datakit replies to a dialout. capture reply code and traffic parameters */ static void dkreplymesg(Dk *dp, Dkmsg *dialp, int line) { Proc *p; Line *lp; DPRINT("dkreplymesg(%d)\n", line); if(line < 0 || line >= dp->lines) return; lp=&dp->line[line]; if(lp->state != Ldialing) return; if(dialp){ /* * a reply from the dk */ lp->state = (dialp->srv==D_OPEN) ? Lconnected : Lrclose; lp->err = (dialp->param1h<<8) + dialp->param1l; lp->window = lp->err; DPRINT("dkreplymesg: %d\n", lp->state); } else { /* * a local abort */ lp->state = Lrclose; lp->err = 0; } if(lp->state==Lrclose){ dkhangup(lp); } wakeup(&lp->r); } /* * 15-second timer for all interfaces */ static Rendez dkt; static int fuckit(void *a) { return 0; } static void dktimer(void *a) { int dki, i; Dk *dp; Line *lp; waserror(); for(;;){ /* * loop through the active dks */ for(dki=0; dkicsc==0) continue; /* * send keep alive */ dkmesg(dp, T_ALIVE, D_CONTINUE, 0, 0); /* * remind controller of dead lines and * timeout calls that take to long */ for (i=0; ilines; i++){ lp = &dp->line[i]; switch(lp->state){ case Llclose: dkmesg(dp, T_CHG, D_CLOSE, i, 0); break; case Ldialing: if(lp->calltolive==0 || --lp->calltolive!=0) break; dkreplymesg(dp, (Dkmsg *)0, i); break; } } } tsleep(&dkt, fuckit, 0, 7500); } } . ## diffname gnot/devdk.c 1990/0315 ## diff -e /n/bootesdump/1990/0312/sys/src/9/68020/devdk.c /n/bootesdump/1990/0315/sys/src/9/68020/devdk.c 1124c DPRINT("DKbusy2 %ux\n", lp->state); . 1118c DPRINT("DKbusy1\n"); . 596d 584d 577d 414a else panic("dkoput"); . 305c DPRINT("dkmuxiput unopened line %d\n", line); . 300c DPRINT("dkmuxiput unopened line %d\n", line); . 290c DPRINT("dkmuxiput bad line %d\n", line); . ## diffname gnot/devdk.c 1990/0319 ## diff -e /n/bootesdump/1990/0315/sys/src/9/68020/devdk.c /n/bootesdump/1990/0319/sys/src/9/68020/devdk.c 784,786d 727c switch(STREAMTYPE(c->qid)){ . 725a if(c->qid & CHDIR){ if(c->qid == CHDIR) return devdirread(c, a, n, dkdir, dk[c->dev].lines, devgen); else return devdirread(c, a, n, dksubdir, Nsubdir, streamgen); } . 723,724d 720,721c if(c->stream) . 717d 705c if(c->stream) . 684a break; . 679a * read only files */ if(omode != OREAD) error(0, Ebadarg); break; default: /* . 678c break; case Daddrqid: case Draddrqid: case Duserqid: case Dotherqid: . 668c break; case Dlistenqid: . 648a * directories are read only */ if(omode != OREAD) error(0, Ebadarg); } else switch(STREAMTYPE(c->qid)){ case Dcloneqid: /* . 647c if(c->qid & CHDIR){ . ## diffname gnot/devdk.c 1990/0321 ## diff -e /n/bootesdump/1990/0319/sys/src/9/68020/devdk.c /n/bootesdump/1990/0321/sys/src/9/68020/devdk.c 540a newqinfo(&dkmuxinfo); newqinfo(&urpinfo); . ## diffname gnot/devdk.c 1990/0331 ## diff -e /n/bootesdump/1990/0321/sys/src/9/68020/devdk.c /n/bootesdump/1990/0331/sys/src/9/68020/devdk.c 420c if(dp->wq->len >= Streamhi){ print("dkoput free\n"); freeb(bp); } else PUTNEXT(dp->wq, bp); . ## diffname gnot/devdk.c 1990/0403 ## diff -e /n/bootesdump/1990/0331/sys/src/9/68020/devdk.c /n/bootesdump/1990/0403/sys/src/9/68020/devdk.c 1134a if(lp->state != Lconnected) dkanswer(c, lineno, DKbusy); . 420,424c PUTNEXT(dp->wq, bp); . ## diffname gnot/devdk.c 1990/05313 ## diff -e /n/bootesdump/1990/0403/sys/src/9/68020/devdk.c /n/bootesdump/1990/05313/sys/src/9/68020/devdk.c 1200a panic("dklisten terminates strangely\n"); . 898c if(lp->state != Lopened) . 726c /* real closing happens in dkstclose */ . 676a qunlock(lp); . 669d 420c if(QFULL(dp->wq->next)){ print("dk wq full\n"); freeb(bp); } else PUTNEXT(dp->wq, bp); . 331a if(lp->state == Lclosed) lp->state = Lopened; . ## diffname gnot/devdk.c 1990/0617 ## diff -e /n/bootesdump/1990/05313/sys/src/9/68020/devdk.c /n/bootesdump/1990/0617/sys/src/9/68020/devdk.c 1291a /* * tell datakit we've rebooted. It should close all channels. */ dkmesg(dp, T_CHG, D_CLOSEALL, 0, 0); . 1087a print("bad dialstr %d '%s'\n", n, dialstr); . 1078a } . 1077a {print("bad n\n"); . 1006c * change state if serving . 69c #define T_CHG 3 /* change the status of a connection */ . ## diffname gnot/devdk.c 1990/0707 ## diff -e /n/bootesdump/1990/0617/sys/src/9/68020/devdk.c /n/bootesdump/1990/0707/sys/src/9/68020/devdk.c 1298a if(dp->restart) dkmesg(dp, T_ALIVE, D_RESTART, 0, 0); . 916a bang = strchr(dialstr, '!'); if(bang){ dot = strchr(dialstr, '.'); if(dot==0 || dot > bang) *bang = '.'; } . 910c * build dial string * - guard against new lines * - change ! into . to delimit service . 895a char *bang, *dot; . 458c if(strcmp(fields[2], "restart")!=0) dp->restart = 0; . 456a case 4: strncpy(dp->name, fields[3], sizeof(dp->name)); . 455c dp->restart = 1; n = getfields((char *)bp->rptr, fields, 4, ' '); . 442c char *fields[4]; . 433a * the word `restart' or `norestart' (optional/default==restart) . 430c * configure a datakit multiplexor. this takes 4 arguments separated . 125a int restart; . ## diffname gnot/devdk.c 1990/0717 ## diff -e /n/bootesdump/1990/0707/sys/src/9/68020/devdk.c /n/bootesdump/1990/0717/sys/src/9/68020/devdk.c 554c urpreset(); . ## diffname gnot/devdk.c 1990/0725 ## diff -e /n/bootesdump/1990/0717/sys/src/9/68020/devdk.c /n/bootesdump/1990/0725/sys/src/9/68020/devdk.c 596a if(*spec == 0) spec = "dk"; . 595c * find a multiplexor with the same name (default dk) . 506c kproc("dktimer", dktimer, 0); . 497c sprint(buf, "csckproc%d", dp->ncsc); . 458a strcpy(dp->name, "dk"); . ## diffname gnot/devdk.c 1990/0726 ## diff -e /n/bootesdump/1990/0725/sys/src/9/68020/devdk.c /n/bootesdump/1990/0726/sys/src/9/68020/devdk.c 598,599d 596c * find a multiplexor with the same name . 507c kproc("**dktimer**", dktimer, 0); . 498c sprint(buf, "**csckproc%d**", dp->ncsc); . 459d ## diffname gnot/devdk.c 1990/0728 ## diff -e /n/bootesdump/1990/0726/sys/src/9/68020/devdk.c /n/bootesdump/1990/0728/sys/src/9/68020/devdk.c 1480c while(waserror()) print("dktimer: error\n"); . 863a } . 862c if(waserror()){ print("dkmesg: error\n"); . 596a if(*spec == 0) spec = "dk"; . 595c * find a multiplexor with the same name (default dk) . 506c kproc("dktimer", dktimer, 0); . 497c sprint(buf, "csckproc%d", dp->ncsc); . 458a strcpy(dp->name, "dk"); . ## diffname gnot/devdk.c 1990/08101 ## diff -e /n/bootesdump/1990/0728/sys/src/9/68020/devdk.c /n/bootesdump/1990/08101/sys/src/9/68020/devdk.c 1320a } DPRINT("dkcsckproc: closeall %s\n", dp->name); . 1319c if(dp->restart) { DPRINT("dkcsckproc: restart %s\n", dp->name); . 498c sprint(buf, "csc.%s.%d", dp->name, dp->ncsc); . 479a DPRINT("dkmuxconfig: ncsc=%d, lines=%d, restart=%d, name=\"%s\"\n", dp->ncsc, dp->lines, dp->restart, dp->name); . 11a #define NOW (MACHP(0)->ticks) . 9,10c #define DPRINT if(0) /*kprint*/ . ## diffname gnot/devdk.c 1990/08163 ## diff -e /n/bootesdump/1990/08101/sys/src/9/68020/devdk.c /n/bootesdump/1990/08163/sys/src/9/68020/devdk.c 981c dkmesg(dp, t_val, d_val, line, W_WINDOW(dp->urpwindow,dp->urpwindow,2)); . 461a case 5: dp->urpwindow = strtoul(fields[4], 0, 0); . 460a dp->urpwindow = WS_2K; . 459c n = getfields((char *)bp->rptr, fields, 5, ' '); . 445c char *fields[5]; . 437c * the name of the dk (default==dk) * the urp window size (default==WS_2K) . 432c * configure a datakit multiplexor. this takes 5 arguments separated . 127a int urpwindow; . ## diffname gnot/devdk.c 1990/0905 ## diff -e /n/bootesdump/1990/08163/sys/src/9/68020/devdk.c /n/bootesdump/1990/0905/sys/src/9/68020/devdk.c 418,421c bp = padb(bp, 2); . 400c * add a 2 byte channel number to the start of each message, * low order byte first. . ## diffname gnot/devdk.c 1990/0911 ## diff -e /n/bootesdump/1990/0905/sys/src/9/68020/devdk.c /n/bootesdump/1990/0911/sys/src/9/68020/devdk.c 561d ## diffname gnot/devdk.c 1990/1004 ## diff -e /n/bootesdump/1990/0911/sys/src/9/68020/devdk.c /n/bootesdump/1990/1004/sys/src/9/68020/devdk.c 1320,1329d 1115d 1105d 1103d 501a * tell datakit we've rebooted. It should close all channels. */ if(dp->restart) { DPRINT("dkmuxconfig: restart %s\n", dp->name); dkmesg(dp, T_ALIVE, D_RESTART, 0, 0); } /* . ## diffname gnot/devdk.c 1990/1018 ## diff -e /n/bootesdump/1990/1004/sys/src/9/68020/devdk.c /n/bootesdump/1990/1018/sys/src/9/68020/devdk.c 423,427c FLOWCTL(dp->wq); PUTNEXT(dp->wq, bp); . 121c char name[64]; /* dk name */ . ## diffname gnot/devdk.c 1990/1020 ## diff -e /n/bootesdump/1990/1018/sys/src/9/68020/devdk.c /n/bootesdump/1990/1020/sys/src/9/68020/devdk.c 1506c for (i=dp->ncsc+1; ilines; i++){ . 1423a case D_CLOSEALL: for(line = dp->ncsc+1; line < dp->lines; line++){ lp = &dp->line[line]; switch (lp->state) { case Ldialing: /* simulate a failed connection */ dkreplymesg(dp, (Dkmsg *)0, line); lp->state = Lrclose; break; case Lrclose: case Lconnected: case Llistening: case Lackwait: dkhangup(lp); lp->state = Lrclose; break; case Lopened: break; case Llclose: case Lclosed: lp->state = Lclosed; break; } } break; . 1409a if (line <= 0 || line >= dp->lines) { /* tell controller this line is not in use */ dkmesg(dp, T_CHG, D_CLOSE, line, 0); return; } lp = &dp->line[line]; . 1379a if (line <= 0 || line >= dp->lines) { /* tell controller this line is not in use */ dkmesg(dp, T_CHG, D_CLOSE, line, 0); return; } lp = &dp->line[line]; . 1371,1376d 224a for(lp = dp->line; lp < &dp->line[Nline]; lp++) if(lp->state != 0) panic("dkmuxopen l %d s %lux", lp-dp->line, lp->state); . 208a Line *lp; . ## diffname gnot/devdk.c 1990/1022 ## diff -e /n/bootesdump/1990/1020/sys/src/9/68020/devdk.c /n/bootesdump/1990/1022/sys/src/9/68020/devdk.c 226,228d 209d ## diffname gnot/devdk.c 1990/1024 ## diff -e /n/bootesdump/1990/1022/sys/src/9/68020/devdk.c /n/bootesdump/1990/1024/sys/src/9/68020/devdk.c 1555a unlock(dp); . 1531a if(dp->csc==0){ unlock(dp); continue; } . 1530c if(!canlock(dp)) . 1328a if(n == 0) error(0, Ehungup); . 1322a if(waserror()){ Chan *csc; csc = dp->csc; lock(dp); dp->csc = 0; unlock(dp); close(csc); return; } . 756,758c if(streamexit(dp->s, 0) == 0) dp->name[0] = 0; . 754a /* * Let go of the mulitplexed stream. If we're the last out, * free dp. */ . 685d 681a dp = &dk[c->dev]; . 632,634c if(streamenter(dp->s) < 0) error(0, Ehungup); . 625a /* * clone as long as the multiplexed channel is not closing * down */ . 622a unlock(dp); poperror(); . 620a /* * don't let the multiplexed stream disappear under us */ if(streamenter(dp->s) < 0){ /* * it's closing down, forget it */ unlock(dp); error(0, Ehungup); } /* * return the new channel */ if(waserror()){ if(streamexit(dp->s, 0) == 0) dp->name[0] = 0; unlock(dp); nexterror(); } . 616,617c unlock(dp); . 611,614c lock(dp); if(strcmp(spec, dp->name)==0) . 275c * work. . 241,245c /* * if we're the last user of the stream, * free the Dk structure */ if(dp->s->inuse == 1) dp->name[0] = 0; /* * hang up all datakit connections */ for(i=dp->ncsc; i < dp->lines; i++) dkhangup(&dp->line[i]); . 238a int i; . 225c dp->s = s; unlock(dp); . 223c strcpy(dp->name, "/"); . 216c unlock(dp); . 212,214c if(dp->name[0]==0){ lock(dp); if(dp->name[0]){ . 203a * when we get though here dp->s is meaningful and the name is set to "/". . 191a static void dkhangup(Line*); . 122a Stream *s; . 119,120c Lock; . ## diffname gnot/devdk.c 1990/1026 ## diff -e /n/bootesdump/1990/1024/sys/src/9/68020/devdk.c /n/bootesdump/1990/1026/sys/src/9/68020/devdk.c 1613c tsleep(&dp->timer, return0, 0, 7500); . 1611d 1603,1609c dkreplymesg(dp, (Dkmsg *)0, i); break; . 1593,1601c case Ldialing: if(lp->calltolive==0 || --lp->calltolive!=0) . 1588,1591c /* * remind controller of dead lines and * timeout calls that take to long */ for (i=dp->ncsc+1; ilines; i++){ lp = &dp->line[i]; switch(lp->state){ case Llclose: dkmesg(c, T_CHG, D_CLOSE, i, 0); break; . 1579,1586c dkmesg(c, T_ALIVE, D_CONTINUE, 0, 0); . 1577c * send keep alive . 1575a if(dp->opened==0) error(0, Ehungup); . 1574a /* * open csc */ dp = (Dk *)a; c = dkopenline(dp, dp->ncsc); . 1572,1573c c = 0; if(waserror()){ if(c) close(c); return; } . 1570a Chan *c; . 1559,1564d 1557c * send a I'm alive message every 7.5 seconds and remind the dk of * any closed channels it hasn't acknowledged. . 1463c dkmesg(c, T_CHG, D_CLOSE, line, 0); . 1454c dkmesg(c, T_CHG, D_CLOSE, line, 0); . 1448c dkmesg(c, T_CHG, D_CLOSE, line, 0); . 1427c dkmesg(c, T_CHG, D_CLOSE, line, 0); . 1418c dkchgmesg(Chan *c, Dk *dp, Dkmsg *dialp, int line) . 1388c dkchgmesg(dp->csc, dp, &d, line); . 1362,1368c close(dp->csc); . 1359c dp = a; . 1357d 1026c csc = dkopenline(dp, dp->ncsc); dkmesg(csc, t_val, d_val, line, W_WINDOW(dp->urpwindow,dp->urpwindow,2)); close(csc); csc = 0; . 1018a /* * open the data file */ dc = dkopenline(dp, line); . 1016,1017d 1013c if(csc) close(csc); if(dc) close(dc); . 1011c dc = 0; csc = 0; . 1009c * close temporary channels on error . 956c . 954a Chan *csc; . 929c streamwrite(c, (char *)&d, sizeof(Dkmsg), 1); . 911,912d 909d 906c dkmesg(Chan *c, int type, int srv, int p0, int p1) . 902a * open the common signalling channel */ static Chan* dkopenline(Dk *dp, int line) { Chan *c; c = 0; if(waserror()){ if(c) close(c); nexterror(); } c = dkattach(dp->name); c->qid = STREAMQID(line, Sdataqid); dkopen(c, ORDWR); poperror(); return c; } /* . 789,796d 786d 665,669d 658,661d 653,654d 645,650d 632,642d 622,629c dp = dkalloc(spec); . 528,531c sprint(buf, "timer.%s.%d", dp->name, dp->ncsc); kproc(buf, dktimer, dp); . 526c * start a keepalive process . 523d 519c * start a process to listen to csc messages . 514,515c DPRINT("dktimer: restart %s\n", dp->name); dkmesg(dp->csc, T_ALIVE, D_RESTART, 0, 0); . 511a * do this here to get it done before trying to open a channel. . 510a * open csc here so that boot, dktimer, and dkcsckproc aren't * all fighting for it at once. */ dp->csc = dkopenline(dp, dp->ncsc); /* . 505,508c dp->ncsc = ncsc; dp->lines = lines; dp->restart = restart; dp->urpwindow = window; dp->s = RD(q)->ptr; q->ptr = q->other->ptr = dp; dp->opened = 1; dp->wq = WR(q); unlock(dp); . 499,503c dp = dkalloc(name); lock(dp); if(dp->opened){ unlock(dp); error(0, Ebadarg); . 497c * set up . 492,494d 489,490c if(ncsc <= 0 || lines <= ncsc) . 482c ncsc = strtoul(fields[0], 0, 0); . 480c lines = strtoul(fields[1], 0, 0); . 478c restart = 0; . 475c strncpy(name, fields[3], sizeof(name)); . 473c window = strtoul(fields[4], 0, 0); . 469,470d 467d 464a * defaults */ ncsc = 1; restart = 1; lines = 16; window = WS_2K; strcpy(name, "dk"); /* . 461c error(0, Egreg); . 459c if(WR(q)->ptr){ . 457c char name[NAMELEN]; int lines; int ncsc; int restart; int window; . 453c Dk *dp; . 451c dkmuxconfig(Queue *q, Block *bp) . 394a out: . 393a poperror(); close(c); . 387c dkmesg(c, T_CHG, D_CLOSE, lp - dp->line, 0); . 382c dkmesg(c, T_CHG, D_CLOSE, lp - dp->line, 0); . 377c dkmesg(c, T_CHG, D_CLOSE, lp - dp->line, 0); . 372c dkmesg(c, T_CHG, D_CLOSE, lp - dp->line, 0); . 363a * decrement ref count on mux'd line */ streamexit(dp->s, 0); /* * don't tell controller about closing down the csc */ if(lp - dp->line == dp->ncsc) goto out; c = 0; if(waserror()){ if(c) close(c); lp->state = Lclosed; goto out; } c = dkopenline(dp, dp->ncsc); /* . 358a Chan *c; . 343a lock(dp); if(dp->opened==0 || streamenter(dp->s)<0){ unlock(dp); error(0, Ehungup); } unlock(dp); . 295a /* * not configured yet */ if(q->other->ptr == 0){ freeb(bp); return; } . 271c dkmuxconfig(q, bp); . 266,268d 257a /* * wakeup the timer so it can die */ wakeup(&dp->timer); . 250,251c lock(dp); dp->opened = 0; unlock(dp); . 247,248c * disallow new dkstopens() on this line. * the lock syncs with dkstopen(). . 244c dp = WR(q)->ptr; if(dp == 0) return; . 235a * a new dkmux. find a free dk structure and assign it to this queue. * when we get though here dp->s is meaningful and the name is set to "/". */ static void dkmuxopen(Queue *q, Stream *s) { RD(q)->ptr = s; WR(q)->ptr = 0; } /* . 232c if(freep == 0){ unlock(&dklock); error(0, Enoifc); } dp = freep; dp->opened = 0; dp->s = 0; dp->ncsc = 1; strncpy(dp->name, name, sizeof(freep->name)); unlock(&dklock); return dp; . 230a if(dp->name[0] == 0) freep = dp; . 214,229c if(strcmp(name, dp->name) == 0){ unlock(&dklock); return dp; . 212a lock(&dklock); freep = 0; . 211c Dk *freep; . 204,208c * Look for a dk struct with a name. If none exists, create one. */ static Dk * dkalloc(char *name) . 189c static void dkchgmesg(Chan*, Dk*, Dkmsg*, int); . 181,182c static void dkmuxconfig(Queue*, Block*); static Chan* dkopenline(Dk*, int); static int dkmesg(Chan*, int, int, int, int); . 130a static Lock dklock; . 128a Rendez timer; . 125c Chan *csc; . 119a int opened; . ## diffname gnot/devdk.c 1990/1101 ## diff -e /n/bootesdump/1990/1026/sys/src/9/68020/devdk.c /n/bootesdump/1990/1101/sys/src/9/68020/devdk.c 1620a /* * hang up any calls waiting for the dk */ for (i=dp->ncsc+1; ilines; i++){ lp = &dp->line[i]; switch(lp->state){ case Llclose: lp->state = Lclosed; break; case Ldialing: dkreplymesg(dp, (Dkmsg *)0, i); break; } } . 1548a dkhangup(lp); . 1547d 1532a /* * datakit wants us to close all lines */ . 1455d 1451,1453c if(line >=0 && linelines) . 1191,1192d 1186c dc = dkopenline(dp, STREAMID(c->qid)); . 822,823d 774d 771a lp->state = Lopened; qunlock(lp); . 445,447d 422,425d 413d 410a lp->state = Lclosed; . 407a } . 406c switch(lp->state){ case Lclosed: case Llclose: case Lopened: lp->state = Lclosed; . 404c * these states don't need the datakit . 398a * if we never got going, we're done */ if(lp->rq == 0){ lp->state = Lclosed; return; } /* . 382a lp->rq = q; . 378,381c if(lp->state==Lclosed) . 371a q->other->ptr = q->ptr = lp = &dp->line[s->id]; lp->dp = dp; . ## diffname gnot/devdk.c 1990/1104 ## diff -e /n/bootesdump/1990/1101/sys/src/9/68020/devdk.c /n/bootesdump/1990/1104/sys/src/9/68020/devdk.c 382d 379a lp->rq = q; . ## diffname gnot/devdk.c 1990/11151 ## diff -e /n/bootesdump/1990/1104/sys/src/9/68020/devdk.c /n/bootesdump/1990/11151/sys/src/9/68020/devdk.c 360c Qinfo dkinfo = { dkiput, dkoput, dkstopen, dkstclose, "dk" }; . 205c Qinfo dkmuxinfo = { dkmuxiput, dkmuxoput, dkmuxopen, dkmuxclose, "dkmux" }; . ## diffname gnot/devdk.c 1990/11211 ## diff -e /n/bootesdump/1990/11151/sys/src/9/68020/devdk.c /n/bootesdump/1990/11211/sys/src/9/68020/devdk.c 1670a DPRINT("keep alive\n"); . 1666c error(Ehungup); . 1447c error(Ehungup); . 1398c lp = &dk[c->dev].line[STREAMID(c->qid.path)]; . 1375c dc->qid.path = STREAMQID(STREAMID(c->qid.path), Sdataqid); . 1335c error(Ebadarg); . 1231c error(Eio); . 1221c error(Eio); . 1205c dc = dkopenline(dp, STREAMID(c->qid.path)); . 1147c error(dkerr[lp->err]); . 1145c error(dkerr[0]); . 1112c error(Ebadarg); . 1045c error(Ebadarg); . 1043c error(Ebadarg); . 1033c error(Ebadarg); . 1025c line = STREAMID(c->qid.path); . 965c c->qid.path = STREAMQID(line, Sdataqid); . 936,949d 933c error(Eperm); . 927c error(Eperm); . 921c error(Eperm); . 914c error(Ebadarg); . 910c error(Ebadarg); . 906c error(Ebadarg); . 902c error(Ebadarg); . 898c error(Ebadarg); . 882c t = STREAMTYPE(c->qid.path); . 871c error(Eperm); . 862,863c lp = &dk[c->dev].line[STREAMID(c->qid.path)]; switch(STREAMTYPE(c->qid.path)){ . 855,856c if(c->qid.path & CHDIR){ if(c->qid.path == CHDIR) . 837c error(Eperm); . 816c error(Ebadarg); . 803c c->qid.path = STREAMQID(line, Sctlqid); . 791c error(Enodev); . 786c c->qid.path = STREAMQID(lp-dp->line, Sctlqid); . 772,773c error(Ebadarg); } else switch(STREAMTYPE(c->qid.path)){ . 767c if(c->qid.path & CHDIR){ . 743c if(c->qid.path == CHDIR) . 734c if(c->qid.path == CHDIR) . 699c dkdir[0].qid.path = Dcloneqid; dkdir[0].qid.vers = 0; . 690c dkdir[i].qid.path = CHDIR|STREAMQID(i, Dlineqid); dkdir[i].qid.vers = 0; . 656,660c "addr", {Daddrqid}, 0, 0600, "listen", {Dlistenqid}, 0, 0600, "other", {Dotherqid}, 0, 0600, "raddr", {Draddrqid}, 0, 0600, "ruser", {Duserqid}, 0, 0600, . 587c error(Ebadarg); . 578c error(Ebadarg); . 574c error(Ebadarg); . 543c error(Egreg); . 502c error(Ebadarg); . 391c error(Ehungup); . 235c error(Enoifc); . 9c #define DPRINT if(0) print . ## diffname gnot/devdk.c 1990/1126 ## diff -e /n/bootesdump/1990/11211/sys/src/9/68020/devdk.c /n/bootesdump/1990/1126/sys/src/9/68020/devdk.c 779c * get an unused device and open its control file . 746a else if(c->qid.path == Dcloneqid) devstat(c, dp, dkdir, 1, devgen); . ## diffname gnot/devdk.c 1990/1210 # deleted ## diff -e /n/bootesdump/1990/1126/sys/src/9/68020/devdk.c /n/bootesdump/1990/1210/sys/src/9/68020/devdk.c 1,1684d