## 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<<lp->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<<window;
else
window = 0;
/*
* intentional fall through
*/
case 3:
/*
* 1127 way of passing window
*/
if(window == 0){
window = strtoul(field[2], 0, 0);
if(W_VALID(window))
window = W_VALUE(W_ORIG(window));
else
window = 0;
}
break;
default:
print("bad message from dk(bad first line)\n");
continue;
}
lineno = strtoul(field[0], 0, 0);
if(lineno >= 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 && line<dp->lines){
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; dki<Ndk; dki++){
dp = &dk[dki];
if(dp->csc==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; i<dp->lines; 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; i<dp->lines; 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; i<dp->lines; 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; i<dp->lines; 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 && line<dp->lines)
.
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
|