|
|
researchv10 Norman
/*
* Raw line discipline and listener stuff for talking to controller
*/
#include "sys/param.h"
#include "sys/stream.h"
#include "sys/dkio.h"
#include "sys/conf.h"
#include "sys/dkstat.h"
#include "sys/dkmod.h"
/*
* CMC/Listener message structure
*/
struct dialin {
char type;
char srv;
short param0;
short param1;
short param2;
short param3;
short param4;
short param5;
};
struct dialout {
short chan;
struct dialin d;
};
/*
* Message codes
*/
#define T_LSTNR 4
#define T_CHG 3
#define T_REPLY 10
#define D_CLOSE 1
#define D_ISCLOSED 2
#define D_ENQ 3
#define D_ENQANS 4
/*
* Raw-mode line discipline for DK (only)
*/
long rdkopen();
int rdkclose(), rdkiput(), rdkoput(), rdkosrv();
static struct qinit rdkrinit = { rdkiput, NULL, rdkopen, rdkclose, 72, 36};
static struct qinit rdkwinit = { rdkoput, rdkosrv, rdkopen, nulldev, 72, 36};
struct streamtab rdkstream = { &rdkrinit, &rdkwinit };
extern struct dkstat dkstat;
extern struct dkmodule dkmod[];
extern int dkmodcnt;
#define NDKRAW 32
struct rdk {
struct queue *q;
struct dkmodule *module;
short chan;
} rdk[NDKRAW];
long
rdkopen(q, dev)
register struct queue *q;
{
static timer_on = 0;
register struct rdk *dkp, *edkp;
register struct dkmodule *dkm;
if ((dkm = getdkmod(dev)) == NULL)
return (0);
edkp = NULL;
for (dkp=rdk; dkp < &rdk[NDKRAW]; dkp++) {
if (dkp->q == q) {
if (dkp->chan != minor(dev) - dkm->lo || WR(q)->ptr==NULL) {
printf("q %x dkp %x\n", q, dkp);
panic("rdkopen");
}
return(1);
}
if (dkp->q == NULL && edkp==NULL)
edkp = dkp;
}
if (edkp==NULL)
return(0);
edkp->q = q;
edkp->module = dkm;
edkp->chan = minor(dev) - dkm->lo;
q->flag |= QDELIM;
q->ptr = 0;
WR(q)->ptr = (caddr_t)edkp;
if (timer_on==0) {
dktimer();
timer_on = 1;
}
return(1);
}
rdkclose(q)
register struct queue *q;
{
register struct block *bp;
register struct rdk *dkp = (struct rdk *)WR(q)->ptr;
if (WR(q)==dkp->module->listnrq) {
dkp->module->listnrq = NULL;
dkp->module->type = 0;
}
while (bp = getq(q))
(*q->next->qinfo->putp)(q->next, bp);
dkp->q = NULL;
dkp->module = NULL;
}
/*
* output put procedure.
*/
rdkoput(q, bp)
register struct queue *q;
register struct block *bp;
{
register struct rdk *dkp = (struct rdk *)q->ptr;
register struct dkmodule *modp = dkp->module;
register i;
switch (bp->type) {
case M_IOCTL:
switch (stiocom(bp)) {
/* hang everybody up */
case DIOCHUP:
/* must be on listener chan */
if (q == modp->listnrq) {
dkmesg(modp, T_LSTNR, 0, 0, 0, 1);
bp->type = M_IOCACK;
bp->rptr = bp->wptr;
qreply(q, bp);
return;
}
break;
/* announce listener channel */
case DIOCLHN:
if (modp->listnrq == NULL) {
modp->listnrq = q;
modp->type = CMCLD;
dkmesg(modp, T_LSTNR, 0, 0, 0, 0);
bp->type = M_IOCACK;
bp->rptr = bp->wptr;
qreply(q, bp);
return;
}
break;
/* delay input */
case DIOCSTOP:
RD(q)->ptr = (caddr_t)1;
bp->type = M_IOCACK;
bp->rptr = bp->wptr;
qreply(q, bp);
return;
/* suggest a free outgoing channel */
case DIOCCHAN:
for (i=modp->lo + 3; i<modp->hi; i+=2) {
if (modp->dkstate[i]==DKCLOSED) {
stiodata(bp)[0] = i;
for (i = 1; i < sizeof(int); i++)
stiodata(bp)[i] = 0; /* silly */
bp->wptr = bp->rptr+STIOCHDR+sizeof(int);
bp->type = M_IOCACK;
break;
}
}
qreply(q, bp);
return;
default:
(*q->next->qinfo->putp)(q->next, bp);
return;
}
bp->type = M_IOCNAK;
bp->wptr = bp->rptr;
qreply(q, bp);
return;
}
putq(q, bp);
}
rdkosrv(q)
register struct queue *q;
{
register struct block *bp;
while ((q->next->flag&QFULL)==0 && (bp = getq(q)))
(*q->next->qinfo->putp)(q->next, bp);
}
/*
* input put procedure
* -- ignores all control bytes
*/
rdkiput(q, bp)
register struct queue *q;
register struct block *bp;
{
register struct rdk *dkp = (struct rdk *)WR(q)->ptr;
switch (bp->type) {
case M_DATA:
if (WR(q)==dkp->module->listnrq && dklstnr(dkp->module, bp))
return;
if (q->next->flag&QFULL) { /* you lose */
freeb(bp);
return;
}
bp->class |= S_DELIM; /* always push through */
if (q->ptr) { /* input delayed */
putq(q, bp);
return;
}
(*q->next->qinfo->putp)(q->next, bp);
return;
case M_IOCACK:
case M_IOCNAK:
case M_HANGUP:
(*q->next->qinfo->putp)(q->next, bp);
return;
case M_PRICTL:
switch (*bp->rptr) {
case DKMCLOSE:
if (dkp->module->dkstate[bp->rptr[1]] == DKRCLOSE)
dkmesg(dkp->module, T_CHG, D_ISCLOSED, 0, bp->rptr[1], 0);
else
dkmesg(dkp->module, T_CHG, D_CLOSE, 0, bp->rptr[1], 0);
freeb(bp);
return;
default:
freeb(bp);
return;
}
default:
freeb(bp);
}
}
/*
* listener sends a message to CMC
*/
dkmesg(modp, type, srv, p0, p1, p2)
register struct dkmodule *modp;
{
register struct dialout *dp;
register struct block *bp;
if (modp->listnrq==NULL || modp->listnrq->next->flag&QFULL)
return;
if ((bp = allocb(sizeof(struct dialout))) == NULL)
return; /* hope it will be retried later */
dp = (struct dialout *)bp->wptr;
dp->chan = ((struct rdk *)modp->listnrq->ptr)->chan;
dp->d.type = type;
dp->d.srv = srv;
dp->d.param0 = p0;
dp->d.param1 = p1;
dp->d.param2 = p2;
bp->wptr += sizeof(struct dialout);
bp->class |= S_DELIM;
(*modp->listnrq->next->qinfo->putp)(modp->listnrq->next, bp);
}
/*
* Receive message for listener
*/
dklstnr(modp, bp)
register struct block *bp;
struct dkmodule *modp;
{
register struct dialin *dialp;
register i;
register struct queue *listnrq = modp->listnrq;
register struct rdk *dkp;
dialp = (struct dialin *)bp->rptr;
switch (dialp->type) {
case T_CHG:
i = dialp->param1;
if (i <= 0 || i >= modp->hi - modp->lo) {
dkstat.chgstrange++;
if (dialp->srv)
dkmesg(modp, T_CHG, D_ISCLOSED, 0, i, 0);
freeb(bp);
return(1);
}
switch (dialp->srv) {
case D_CLOSE: /* remote shutdown */
switch (modp->dkstate[i]) {
case DKRCLOSE:
dkstat.notclosed++;
case DKOPEN:
putctl2(listnrq->next, M_PRICTL, DKMCLOSE, i);
break;
case DKLCLOSE:
case DKCLOSED:
dkmesg(modp, T_CHG, D_ISCLOSED, 0, i, 0);
putctl2(listnrq->next, M_PRICTL, DKMCLOSE, i);
break;
}
break;
case D_ISCLOSED:
switch (modp->dkstate[i]) {
case DKLCLOSE:
case DKCLOSED:
putctl2(listnrq->next, M_PRICTL, DKMCLOSE, i);
break;
case DKOPEN:
case DKRCLOSE:
dkstat.isclosed++;
break;
}
break;
case D_ENQ:
dkmesg(modp, T_CHG, D_ENQANS, 0, i, modp->dkstate[i]);
break;
}
freeb(bp);
return(1);
case T_REPLY: /* CMC sends reply; find, and hand to process */
i = dialp->param0;
if (i < 0 || i >= modp->hi - modp->lo)
return(0);
for (dkp=rdk; dkp<&rdk[NDKRAW]; dkp++) {
if (dkp->module==modp && dkp->chan==i) {
bp->class |= S_DELIM;
(*dkp->q->next->qinfo->putp)(dkp->q->next, bp);
return(1);
}
}
return(0);
default:
return(0);
}
}
/*
* 15-second timer
* -- should look at dkmod->type, so different
* listeners can coexist
*/
dktimer()
{
register i;
register struct dkmodule *dkp;
for (dkp = dkmod; dkp < &dkmod[dkmodcnt]; dkp++) {
if (dkp->listnrq && dkp->type == CMCLD) {
dkmesg(dkp, T_LSTNR, 0, 0, 0, 0);
for (i=dkp->hi - dkp->lo - 1; i >= 0; --i)
if (dkp->dkstate[i] == DKLCLOSE)
dkmesg(dkp, T_CHG, D_CLOSE, 0, i, 0);
}
}
timeout(dktimer, (caddr_t)NULL, 15*HZ);
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.