u-isdn/ksupport/proto.c

1249 lines
26 KiB
C

/* Streams protocol mangling module */
#include "f_module.h"
#include "primitives.h"
#include "f_malloc.h"
#include "kernel.h"
#include "f_signal.h"
#include "stropts.h"
#include "f_user.h"
#include "f_termio.h"
#ifndef linux
#include <sys/tty.h>
#endif
#include "streams.h"
#include "smallq.h"
#include "streamlib.h"
#include "isdn_limits.h"
#include "proto.h"
#include "isdn_proto.h"
static struct module_info proto_minfo =
{
0, PROTO_NAME, 0, INFPSZ, 200,100
};
static qf_open proto_open;
static qf_close proto_close;
static qf_put proto_wput,proto_rput;
static qf_srv proto_wsrv,proto_rsrv;
static struct qinit proto_rinit =
{
proto_rput, proto_rsrv, proto_open, proto_close, NULL, &proto_minfo, NULL
};
static struct qinit proto_winit =
{
proto_wput, proto_wsrv, NULL, NULL, NULL, &proto_minfo, NULL
};
struct streamtab protoinfo =
{&proto_rinit, &proto_winit, NULL, NULL};
#define CMDLEN 128
enum Pmode {
P_UNKNOWN, P_CMD, P_NONE, P_LISTEN, P_CONN
};
struct _proto {
queue_t *qptr;
mblk_t *keep;
enum Pmode mode;
struct _smallq write_delay;
struct termios tty;
short reppos;
uchar_t sCR, sLF, sBS, sBR; /* CR,LF,Backspace,Break (^C) */
char nr;
unsigned int cCarrier:2; /* Disconnect generates hangup? */
unsigned int cBreak:1; /* Break switches to command mode? */
unsigned int cSig:1; /* Send signals up when conn/disc */
unsigned int talker:1;
unsigned int binmode:1;
char cmdline[CMDLEN];
char repline[CMDLEN + 20];
streamchar prefix[PREFIX_MAX];
};
static void setmode(struct _proto *proto, enum Pmode mode)
{
char *x;
switch(mode) {
default : x = "???" ; break;
case P_UNKNOWN: x = "unknown"; break;
case P_CMD : x = "command"; break;
case P_NONE : x = "none" ; break;
case P_LISTEN : x = "listen" ; break;
case P_CONN : x = "connect"; break;
}
if(proto->mode != mode) printf("%sSwitch mode to %s, talk %d\n",KERN_DEBUG,x,proto->talker);
proto->mode = mode;
}
static int
proto_open (queue_t * q, dev_t dev, int flag, int sflag ERR_DECL)
{
struct _proto *proto;
if (q->q_ptr) {
if (0)
printf ("%sProtocol: already open?\n",KERN_DEBUG);
return 0;
}
proto = malloc(sizeof(*proto));
if(proto == NULL)
ERR_RETURN(-ENOMEM);
bzero ((caddr_t) proto, sizeof (struct _proto));
proto->tty.c_iflag = IGNBRK | IGNPAR;
proto->tty.c_cflag = B38400 | CS8 | CREAD | HUPCL;
proto->sCR = 0x0D;
proto->sLF = 0x0A;
proto->sBS = 0x08;
proto->sBR = 0x03;
proto->cCarrier = 2;
proto->cBreak = 1;
proto->cSig = 0;
proto->talker = 0;
proto->mode = P_UNKNOWN;
proto->reppos = 0;
WR (q)->q_ptr = (char *) proto;
q->q_ptr = (char *) proto;
proto->qptr = q;
MORE_USE;
return 0;
}
static void mm_reply (struct _proto *proto, queue_t * q, mblk_t * mp, int err)
{
if(q == proto->qptr || proto->prefix[0] == proto->prefix[1]) {
m_reply(q,mp,err);
return;
}
{
mblk_t *mq = allocb (err ? 17 : 9, BPRI_HI);
if (mq == NULL) {
printf("%s* NoMem m_reply %d\n",KERN_DEBUG,err);
freemsg (mq);
return;
}
*mq->b_wptr++ = proto->prefix[PREFIX_LOCALPROTO];
if (err == 0) {
m_putid (mq, PROTO_NOERROR);
} else {
m_putid (mq, PROTO_ERROR);
m_putsx (mq, PROTO_ERROR);
m_puti (mq, err);
}
m_putdelim (mq);
linkb (mq, mp);
DATA_TYPE(mp) = MSG_DATA;
DATA_TYPE(mq) = MSG_DATA;
putnext (OTHERQ (q), mq);
}
}
static void
proto_prot (queue_t * q, mblk_t * mp)
{
struct _proto *proto = (struct _proto *) q->q_ptr;
ushort_t id;
streamchar *origmp = mp->b_rptr;
int error = 0;
if (m_getid (mp, &id) != 0) {
mp->b_rptr = origmp;
mm_reply(proto,q,mp,ENXIO);
return;
}
switch (id) {
default:
mp->b_rptr = origmp;
break;
case PROTO_DATA_IN:
case PROTO_DATA_OUT:
freemsg(mp);
mp = NULL;
break;
case PROTO_TICK:
case PROTO_TELLME: /* TODO send OK to the monitor, if any */
freemsg(mp);
mp = NULL;
break;
case PROTO_OFFSET:
{
long z;
if ((error = m_geti (mp, &z)) != 0)
goto err;
if (z < 0 || z >= 1024) {
error = -EINVAL;
goto err;
}
freemsg(mp);
if((mp = allocb(8,BPRI_MED)) != NULL) {
m_putid(mp,PROTO_OFFSET);
m_puti(mp,proto->prefix[0] != proto->prefix[1]);
DATA_TYPE(mp) = M_EXPROTO;
qreply(q,mp);
mp = NULL;
}
}
break;
case PROTO_AT:
switch (proto->mode) {
case P_NONE:
case P_LISTEN:
case P_CONN:
if(!proto->talker) {
int ms;
ms = splstr ();
mp->b_rptr = origmp;
if (proto->keep != NULL)
freemsg (proto->keep);
proto->keep = mp;
splx (ms);
mp = NULL;
break;
}
/* FALL THRU */
default:
DATA_TYPE(mp) = M_DATA;
m_getskip (mp);
if(!proto->binmode) {
for(origmp = mp->b_rptr; origmp < mp->b_wptr; origmp++) {
if(*origmp == '\r')
*origmp = proto->sCR;
else if (*origmp == '\n')
*origmp = proto->sLF;
}
if (mp->b_wptr + 2 <= DATA_END(mp)) {
*mp->b_wptr++ = proto->sCR;
*mp->b_wptr++ = proto->sLF;
} else {
mblk_t *mz = allocb (2, BPRI_MED);
if (mz != NULL) {
*mz->b_wptr++ = proto->sCR;
*mz->b_wptr++ = proto->sLF;
linkb (mp, mz);
}
}
}
putnext (q, mp);
mp = NULL;
break;
}
break;
case PROTO_INTERRUPT:
mp->b_rptr = origmp;
*(ushort_t *) (mp->b_rptr) = PROTO_HAS_INTERRUPT;
#if 0
goto conn_intr;
#else
qreply(q,mp);
mp = NULL;
break;
#endif
case PROTO_CONNECTED:
mp->b_rptr = origmp;
*(ushort_t *) (mp->b_rptr) = PROTO_HAS_CONNECTED;
qreply (q, mp);
mp = NULL;
if(proto->mode != P_CONN) {
if (proto->cSig)
putctlx1 (q, M_SIG, SIGUSR1);
setmode(proto, P_CONN);
qenable (WR (q));
}
if (proto->cCarrier == 2)
proto->cCarrier |= 1;
break;
case PROTO_SETUP:
mp->b_rptr = origmp;
*(ushort_t *) (mp->b_rptr) = PROTO_HAS_SETUP;
qreply (q, mp);
setmode(proto, P_NONE);
mp = NULL;
break;
case PROTO_LISTEN:
mp->b_rptr = origmp;
*(ushort_t *) (mp->b_rptr) = PROTO_HAS_LISTEN;
qreply (q, mp);
setmode(proto, P_LISTEN);
mp = NULL;
break;
case PROTO_MODLIST:
mp->b_rptr = origmp;
mm_reply(proto,q,mp,0);
mp = NULL;
break;
case PROTO_INCOMING:
case PROTO_OUTGOING:
case PROTO_ENABLE: /* FIXME -- this should not get sent, but... */
mp->b_rptr = origmp;
mm_reply(proto,q,mp,0);
mp = NULL;
break;
case PROTO_DISCONNECT:
mp->b_rptr = origmp;
if (proto->cSig)
putctlx1 (q, M_SIG, SIGUSR2);
*(ushort_t *) (mp->b_rptr) = PROTO_HAS_DISCONNECT;
qreply (q, mp);
mp = NULL;
{
int ms = splstr ();
if (proto->keep != NULL) {
putbq (proto->qptr, proto->keep);
proto->keep = NULL;
qenable (proto->qptr);
}
splx (ms);
}
#if 0
putctlx1 (q, M_FLUSH, FLUSHW); /* To prevent data confusion */
#endif
if ((proto->mode >= P_NONE) && (proto->cCarrier & 1)) {
putctlx (q, M_HANGUP);
}
setmode(proto, (proto->talker ? P_CMD : P_NONE));
break;
case PROTO_WILL_DISCONNECT:
mp->b_rptr = origmp;
if (proto->cSig)
putctlx1 (q, M_SIG, SIGPWR);
*(ushort_t *) (mp->b_rptr) = PROTO_DISCONNECT;
qreply (q, mp);
mp = NULL;
setmode(proto, P_NONE);
{
int ms = splstr ();
if (proto->keep != NULL) {
putbq (proto->qptr, proto->keep);
proto->keep = NULL;
qenable (proto->qptr);
}
splx (ms);
}
break;
case PROTO_WILL_INTERRUPT:
mp->b_rptr = origmp;
*(ushort_t *) (mp->b_rptr) = PROTO_INTERRUPT;
qreply (q, mp);
mp = NULL;
break;
case PROTO_MODULE:
if (strnamecmp (q, mp)) { /* Config information for me. */
long z;
while ((mp != NULL) && ((error = m_getsx (mp, &id)) == 0)) {
switch (id) {
default:
error = -EINVAL;
goto err;
case PROTO_MODULE:
break;
case PROTO_PREFIX:
if ((error = m_getstr (mp,proto->prefix,PREFIX_MAX)) != 0)
goto err;
break;
case PROTO_CR:
if ((error = m_geti (mp, &z)) != 0)
goto err;
if (z < 0 || z >= 255) {
goto err;
}
proto->sCR = z;
break;
case PROTO_LF:
if ((error = m_geti (mp, &z)) != 0)
goto err;
if (z < 0 || z >= 255) {
goto err;
}
proto->sLF = z;
break;
case PROTO_BACKSPACE:
if ((error = m_geti (mp, &z)) != 0)
goto err;
if (z < 0 || z >= 255) {
goto err;
}
proto->sBS = z;
break;
case PROTO_ABORT:
if ((error = m_geti (mp, &z)) != 0)
goto err;
if (z < 0 || z >= 255) {
goto err;
}
proto->sBR = z;
break;
case PROTO_BINCMD:
proto->binmode = 1;
break;
case PROTO_ASCIICMD:
proto->binmode = 0;
break;
case PROTO_CARRIER:
if ((error = m_geti (mp, &z)) != 0)
goto err;
if (z < 0 || z > 2) {
goto err;
}
proto->cCarrier = z;
break;
case PROTO_BREAK:
if ((error = m_geti (mp, &z)) != 0)
goto err;
if (z < 0 || z > 1) {
goto err;
}
proto->cBreak = z;
break;
case PROTO_SIGNALS:
if ((error = m_geti (mp, &z)) != 0)
goto err;
if (z < 0 || z > 1) {
goto err;
}
proto->cSig = z;
break;
case PROTO_ONLINE:
proto->talker = 0;
if (proto->mode == P_CMD)
setmode(proto, P_UNKNOWN);
break;
case PROTO_OFFLINE:
proto->talker = 1;
if(proto->cCarrier & 2)
proto->cCarrier &=~ 1;
if (proto->mode == P_UNKNOWN || proto->mode == P_NONE)
setmode(proto, P_CMD);
qenable (WR (proto->qptr));
if (proto->keep != NULL) {
putbq (proto->qptr, proto->keep);
proto->keep = NULL;
qenable (proto->qptr);
}
break;
}
}
mp->b_rptr = origmp;
mm_reply (proto,q,mp,0);
mp = NULL;
} else {
mp->b_rptr = origmp;
mm_reply (proto,q,mp,ENXIO);
mp = NULL;
}
break;
}
err:
if (mp != NULL) {
if (origmp != NULL)
mp->b_rptr = origmp;
mm_reply(proto,q,mp,error ? error : -EINVAL);
}
return;
}
/*
* Flush replies
*/
static void
proto_reply_send (struct _proto *ch, short flush)
{
if ((flush || ch->reppos >= sizeof (ch->repline)) && (ch->reppos > 0)) {
mblk_t *rep = allocb (ch->reppos, BPRI_LO);
if (rep == NULL) {
ch->reppos = -1;
} else {
bcopy (ch->repline, rep->b_wptr, ch->reppos);
rep->b_wptr += ch->reppos;
putnext (ch->qptr, rep);
ch->reppos = 0;
}
}
if (ch->reppos == -1 && putctlx (ch->qptr, M_HANGUP) == 0)
ch->reppos = -2;
}
/*
* Send a reply
*/
static void
proto_reply (struct _proto *ch, uchar_t c)
{
proto_reply_send (ch, 0);
if (ch->reppos >= 0)
ch->repline[ch->reppos++] = c;
}
/*
* Low-level processing of incoming characters.
*
* Essentially a very stupid line editor. Setting up the "line" Stremas module
* would be too much work; besides, "line" usually works in the other
* direction, thus it might be dangerous too.
*/
static void
proto_cmdproc (struct _proto *ch, uchar_t c)
{
int cmdlen;
short cc;
for (cmdlen = 0; cmdlen < CMDLEN; cmdlen++)
if (ch->cmdline[cmdlen] == 0)
break;
if (c == ch->sCR)
cc = 0x10D;
else if (c == ch->sLF)
cc = 0x10A;
else if (c == ch->sBS)
cc = 0x108;
else if (c == ch->sBR)
cc = 0x103;
else
cc = c;
switch (cc) {
default:
if (cmdlen >= CMDLEN - 1) {
/* putctlx1 (ch->qptr, M_DATA, ch->sBS); */
return;
}
ch->cmdline[cmdlen++] = c;
ch->cmdline[cmdlen] = '\0';
proto_reply (ch, c);
break;
case 0x103:
ch->cmdline[0] = 0;
proto_reply (ch, ch->sCR);
proto_reply (ch, ch->sLF);
break;
case 0x108:
if (cmdlen > 0) {
proto_reply (ch, ch->sBS);
proto_reply (ch, ' ');
proto_reply (ch, ch->sBS);
}
ch->cmdline[--cmdlen] = '\0';
break;
case 0x10D:
case 0x10A:
if (cmdlen == 0) {
proto_reply (ch, ch->sCR);
proto_reply (ch, ch->sLF);
return /* 0 */ ;
} else {
mblk_t *mb = allocb (8 + cmdlen, BPRI_MED);
if (mb == NULL) {
putctlx (ch->qptr, M_HANGUP);
return /* EAGAIN */ ;
}
/* Endianness alert */
*((ushort_t *) mb->b_wptr)++ = PROTO_AT;
*mb->b_wptr++ = ' ';
for (cmdlen = 0; ch->cmdline[cmdlen] != 0; cmdlen++)
*mb->b_wptr++ = ch->cmdline[cmdlen];
DATA_TYPE(mb) = MSG_PROTO;
putnext (WR (ch->qptr), mb);
proto_reply (ch, ch->sCR);
proto_reply (ch, ch->sLF);
}
ch->cmdline[0] = 0;
break;
}
return /* 0 */ ;
}
static void
proto_rput (queue_t * q, mblk_t * mp)
{
switch (DATA_TYPE(mp)) {
case M_FLUSH:
if (*mp->b_rptr & FLUSHR)
flushq (q, 0);
putnext (q, mp);
break;
default:
putq (q, mp);
break;
}
return;
}
static void
proto_rsrv (queue_t * q)
{
struct _proto *proto = (struct _proto *) q->q_ptr;
mblk_t *mp;
while ((mp = getq (q)) != NULL) {
switch (DATA_TYPE(mp)) {
case MSG_PROTO:
if(proto->prefix[0] == proto->prefix[1] || proto->mode <= P_NONE) {
proto_prot (q, mp);
break;
}
if(mp->b_rptr <= DATA_START(mp)) {
mblk_t *mq = allocb(1,BPRI_HI);
if(mq == NULL) {
putbqf(q,mp);
return;
}
linkb(mq,mp);
mp = mq;
}
*--mp->b_rptr = proto->prefix[PREFIX_PROTO];
goto def;
case CASE_DATA:
DATA_TYPE(mp) = M_DATA;
switch (proto->mode) {
case P_NONE:
case P_CMD:
freemsg (mp);
continue;
case P_UNKNOWN:
putbqf (q, mp);
return;
default:
if ((proto->talker && proto->prefix[0] == proto->prefix[1]) || !canput (q->q_next)) {
putbq (q, mp);
return;
}
if(proto->prefix[0] != proto->prefix[1]) {
if(mp->b_rptr <= DATA_START(mp)) {
int i;
for(i=0;i<PREFIX_MAX;i++) {
if(*mp->b_rptr == proto->prefix[i]) {
mblk_t *mq = allocb(1,BPRI_HI);
if(mq == NULL) {
putbqf(q,mp);
return;
}
*--mp->b_rptr = proto->prefix[PREFIX_DATA];
linkb(mq,mp);
mp = mq;
break;
}
}
} else
*--mp->b_rptr = proto->prefix[PREFIX_DATA];
}
def:
DATA_TYPE(mp) = M_DATA;
#ifndef linux
if (proto->tty.c_iflag & (ICRNL | INLCR | ISTRIP | IGNCR)) {
unsigned char c;
unsigned short flag = proto->tty.c_iflag;
mblk_t *mm;
for (mm = mp; mm != NULL; mm = mm->b_cont) {
streamchar *endp = mm->b_wptr;
streamchar *src = mm->b_rptr;
uchar_t *dest = mm->b_rptr;
while (src < endp) {
c = *src++;
if (flag & ISTRIP)
c &= 0x7F;
switch (c) {
case '\r':
if (flag & IGNCR)
continue;
else if (flag & ICRNL)
c = '\n';
break;
case '\n':
if (flag & INLCR)
c = '\r';
break;
default:;
}
*dest++ = c;
}
mm->b_wptr = dest;
}
}
#endif
putnext (q, mp);
break;
}
continue;
default:
if (DATA_TYPE(mp) > QPCTL || canput (q->q_next)) {
putnext (q, mp);
continue;
} else {
putbq (q, mp);
return;
}
}
}
return;
}
static void
proto_wput (queue_t * q, mblk_t * mp)
{
struct _proto *proto = (struct _proto *) q->q_ptr;
switch (DATA_TYPE(mp)) {
case M_FLUSH:
if (*mp->b_rptr & FLUSHW) {
flushq (q, 0);
S_flush(&proto->write_delay);
}
putnext (q, mp);
break;
default:
putq (q, mp);
break;
}
return;
}
static void
proto_wsrv (queue_t * q)
{
struct _proto *proto = (struct _proto *) q->q_ptr;
mblk_t *mp;
int realq = 1;
while ((mp = getq (q)) != NULL || (realq = 0) || (mp = S_dequeue(&proto->write_delay)) != NULL) {
if(!realq)printf("%sFromDel %p\n",KERN_DEBUG, &proto->write_delay);
switch (DATA_TYPE(mp)) {
case MSG_PROTO:
freemsg (mp);
break;
case CASE_DATA:
switch (proto->mode) {
case P_CMD: DoCmd:
if(proto->binmode) {
mblk_t *mb = allocb (4, BPRI_MED);
if (mb == NULL) {
putctlx (RD(q), M_HANGUP);
freemsg(mp);
return /* EAGAIN */ ;
}
/* Endianness alert */
*((ushort_t *) mb->b_wptr)++ = PROTO_AT;
*mb->b_wptr++ = ' ';
DATA_TYPE(mb) = MSG_PROTO;
linkb(mb,mp);
putnext(q,mb);
} else {
while ((mp = pullupm (mp, 0)) != NULL)
proto_cmdproc (proto, *mp->b_rptr++);
proto_reply_send (proto, 1);
}
continue;
case P_UNKNOWN:
case P_NONE:
case P_LISTEN:
#if 0
if(realq) {
if(proto->write_delay.nblocks > 20)
freemsg(mp);
else
S_enqueue(&proto->write_delay, mp);
} else {
S_requeue(&proto->write_delay, mp);
return;
}
goto nextone;
#else
putbq(q,mp);
return;
#endif
default:
{
streamchar ch = *mp->b_rptr;
if(proto->prefix[0] != proto->prefix[1]) {
if(ch == proto->prefix[PREFIX_DATA]) {
mp->b_rptr++;
}
else if(ch == proto->prefix[PREFIX_PROTO]) {
mp->b_rptr++;
DATA_TYPE(mp) = MSG_PROTO;
}
else if(ch == proto->prefix[PREFIX_LOCALPROTO]) {
mp->b_rptr++;
proto_prot(q,mp);
continue;
}
else {
ch = 0;
}
} else if(proto->talker)
goto DoCmd;
if (!canput (q->q_next)) {
if(proto->prefix[0] != proto->prefix[1]) {
if(ch != 0)
*--mp->b_rptr = ch;
}
DATA_TYPE(mp) = MSG_DATA;
putbq (q, mp);
return;
}
}
}
#ifndef linux
if (proto->tty.c_oflag & (ONLCR | OCRNL)) {
short flag = proto->tty.c_oflag;
mblk_t *mm, *mm2;
for (mm2 = mm = mp; mm != NULL; mm2 = mm = mm2->b_cont) {
unsigned char *endp = (uchar_t *) mm->b_wptr;
unsigned char *src = (uchar_t *) mm->b_rptr;
unsigned char *lim = (uchar_t *) DATA_END(mm);
unsigned char *dest = (uchar_t *) mm->b_wptr;
if (flag & ONLCR) { /* Possible expansion. */
short addlen = 0;
while (src < dest) {
if (*src++ == '\n')
addlen++;
}
dest += addlen;
}
src = endp;
endp = mm->b_rptr;
if (dest <= (uchar_t *) DATA_END(mm))
(uchar_t *) mm->b_wptr = dest;
else { /* Too much expansion. (Happens with any
* three-characters-plus-Newline data block.)
* Allocate another mblk, link it in, start
* expanding into it. */
uchar_t *lim2;
mm->b_wptr = DATA_END(mm);
mm2 = allocb (dest - (uchar_t *) DATA_END(mm), BPRI_MED);
if (mm2 == NULL)
continue;
mm2->b_cont = mm->b_cont;
mm->b_cont = mm2;
lim2 = (uchar_t *) mm2->b_rptr;
dest = (uchar_t *) mm2->b_wptr = lim2 + (dest - (uchar_t *) DATA_END(mm));
while (src > endp) {
char c = *--src;
switch (c) {
case '\n':
if (flag & ONLCR) {
*--dest = '\n';
if (dest == lim2) {
dest = (uchar_t *) mm->b_wptr;
*--dest = '\r';
goto norm;
}
c = '\r';
}
break;
case '\r':
if (flag & OCRNL)
c = '\n';
break;
default:;
}
*--dest = c;
if (dest == lim2) {
dest = (uchar_t *) mm->b_wptr;
goto norm;
}
}
}
norm:
while (src > endp) {
char c = *--src;
switch (c) {
case '\n':
if (flag & ONLCR) {
*--dest = '\n';
c = '\r';
}
break;
case '\r':
if (flag & OCRNL)
c = '\n';
break;
default:;
}
*--dest = c;
}
(uchar_t *) mm->b_rptr = dest;
}
}
#endif
putnext (q, mp);
break;
case M_IOCTL:
{
struct iocblk *iocb;
int error = -EINVAL;
iocb = (struct iocblk *) mp->b_rptr;
if(0)printf("%sProto IOC %x\n",KERN_DEBUG,iocb->ioc_cmd);
switch (iocb->ioc_cmd) {
#ifdef TCGETA
case TCGETA:
{
struct termio *tty;
mblk_t *m0 = allocb (sizeof (struct termio), BPRI_MED);
if (m0 == NULL) {
error = -ENOMEM;
goto iocnak;
}
m0->b_cont = mp->b_cont;
mp->b_cont = m0;
tty = ((struct termio *) m0->b_wptr)++;
bzero(tty,sizeof(*tty));
tty->c_cflag = proto->tty.c_cflag;
tty->c_iflag = proto->tty.c_iflag;
tty->c_lflag = proto->tty.c_lflag;
tty->c_oflag = proto->tty.c_oflag;
tty->c_line = proto->tty.c_line ;
#if NCC <= NCCS
memcpy(tty->c_cc,proto->tty.c_cc,NCC);
#else
memcpy(tty->c_cc,proto->tty.c_cc,NCCS);
#endif
goto iocackn;
}
#endif
#ifdef TCFLSH
case TCFLSH:
{
goto iocackn; /* We don't flush */
}
#endif
#ifdef TCGETS
case TCGETS:
{
mblk_t *m0 = allocb (sizeof (struct termios), BPRI_MED);
if (m0 == NULL) {
error = -ENOMEM;
goto iocnak;
}
m0->b_cont = mp->b_cont;
mp->b_cont = m0;
*((struct termios *) m0->b_wptr)++ = proto->tty;
goto iocackn;
}
#endif
#ifdef UIOCTTSTAT
case UIOCTTSTAT:
{
mblk_t *m0 = allocb (3, BPRI_MED);
if (m0 == NULL) {
error = -ENOMEM;
goto iocnak;
}
m0->b_cont = mp->b_cont;
mp->b_cont = m0;
*m0->b_wptr++ = 0;
*m0->b_wptr++ = 0;
*m0->b_wptr++ = 1;
goto iocack;
}
#endif
#ifdef TCSETA
case TCSETA:
case TCSETAW:
case TCSETAF:
{
int ms;
struct termio *tty;
if (mp->b_cont == NULL || iocb->ioc_count != sizeof (struct termio)) {
goto iocnak;
}
ms = splstr ();
tty = (struct termio *) mp->b_cont->b_rptr;
if (proto->cBreak && !(tty->c_cflag & CBAUD)) {
mblk_t *mb;
if (proto->keep != NULL) {
putbq (proto->qptr, proto->keep);
proto->keep = NULL;
qenable (proto->qptr);
}
if (proto->mode >= P_NONE) {
setmode(proto, P_CMD);
mb = allocb (3, BPRI_MED);
if (mb != NULL) {
*((ushort_t *) mb->b_wptr)++ = PROTO_AT;
DATA_TYPE(mb) = MSG_PROTO;
putnext (q, mb);
}
}
}
proto->tty.c_cflag = tty->c_cflag;
proto->tty.c_iflag = tty->c_iflag;
proto->tty.c_lflag = tty->c_lflag;
proto->tty.c_oflag = tty->c_oflag;
proto->tty.c_line = tty->c_line ;
#if NCC <= NCCS
memcpy(proto->tty.c_cc,tty->c_cc,NCC);
#else
memcpy(proto->tty.c_cc,tty->c_cc,NCCS);
#endif
#if NCC < NCCS
memset(proto->tty.c_cc+NCC,0,NCCS-NCC);
#endif
#if 0
proto->tty.c_iflag |= IGNBRK | IGNPAR;
proto->tty.c_iflag &= ~(BRKINT | INPCK | IUCLC | IXON | IXANY | IXOFF);
proto->tty.c_oflag &= ~(ONOCR | OLCUC | NLDLY | OFILL | OFDEL | CRDLY | TABDLY | BSDLY | VTDLY | FFDLY);
proto->tty.c_cflag &= ~(CBAUD | CSIZE | CSTOPB | PARENB | PARODD | CLOCAL);
proto->tty.c_cflag |= B38400 | CS8 | HUPCL;
/* bzero(proto->tty.c_cc,NCC); */
#endif
splx (ms);
goto iocackn;
}
#endif
#ifdef TCSETS
case TCSETS:
case TCSETSW:
case TCSETSF:
#if 0 /* defined(TIOCSETA) && (TIOCSETA != TCSETS) */
case TIOCSETA:
case TIOCSETAW:
case TIOCSETAF:
#endif
{
int ms;
if (mp->b_cont == NULL || iocb->ioc_count != sizeof (struct termios)) {
printf("%stermios: want %d, got %d\n",KERN_DEBUG,sizeof(struct termios),iocb->ioc_count);
goto iocnak;
}
ms = splstr ();
proto->tty = *(struct termios *) mp->b_cont->b_rptr;
if (proto->cBreak && !(proto->tty.c_cflag & CBAUD)) {
mblk_t *mb;
if (proto->keep != NULL) {
putbq (proto->qptr, proto->keep);
proto->keep = NULL;
qenable (proto->qptr);
}
if (proto->mode >= P_NONE) {
setmode(proto, P_CMD);
mb = allocb (3, BPRI_MED);
if (mb != NULL) {
*((ushort_t *) mb->b_wptr)++ = PROTO_AT;
DATA_TYPE(mb) = MSG_PROTO;
putnext (q, mb);
}
}
}
#if 0
proto->tty.c_iflag |= IGNBRK | IGNPAR;
proto->tty.c_iflag &= ~(BRKINT | INPCK | IUCLC | IXON | IXANY | IXOFF);
proto->tty.c_oflag &= ~(ONOCR | OLCUC | NLDLY | OFILL | OFDEL | CRDLY | TABDLY | BSDLY | VTDLY | FFDLY);
proto->tty.c_cflag &= ~(CBAUD | CSIZE | CSTOPB | PARENB | PARODD | CLOCAL);
proto->tty.c_cflag |= B38400 | CS8 | HUPCL;
/* bzero(proto->tty.c_cc,NCC); */
#endif
splx (ms);
goto iocackn;
}
#endif
#ifdef TCSBRK
case TCSBRK:
#endif
#ifdef TCSBRKM
case TCSBRKM:
#endif
#ifdef TCRESET
case TCRESET:
#endif
#if defined(TCRESET) || defined(TCSBRKM) || defined(TCSBRK)
{
if (proto->cBreak) {
int ms;
if (proto->mode >= P_NONE) {
mblk_t *mz;
setmode(proto, P_CMD);
mz = allocb (3, BPRI_MED);
if (mz != NULL) {
*((ushort_t *) mz->b_wptr)++ = PROTO_AT;
DATA_TYPE(mz) = MSG_PROTO;
putnext (q, mz);
}
}
ms = splstr ();
if (proto->keep != NULL) {
putbq (proto->qptr, proto->keep);
proto->keep = NULL;
qenable (proto->qptr);
}
splx (ms);
}
}
goto iocack;
#endif
case TCXONC:
#ifdef TIOCMGET
case TIOCMGET:
#endif
#ifdef TIOCMBIS
case TIOCMBIS:
#endif
#ifdef TIOCMBIC
case TIOCMBIC:
#endif
#ifdef TIOCMSET
case TIOCMSET:
#endif
#ifdef TCCBRKM
case TCCBRKM:
#endif
#ifdef TCSETDTR
case TCSETDTR:
#endif
#ifdef TCCLRDTR
case TCCLRDTR:
#endif
#ifdef TIOCSDTR
case TIOCSDTR:
#endif
#ifdef TIOCCDTR
case TIOCCDTR:
#endif
#ifdef TIOCSBRK
case TIOCSBRK:
#endif
#ifdef TIOCCBRK
case TIOCCBRK:
#endif
#ifdef LDSETT
case LDSETT:
#endif
#ifdef UIOCMODEM
case UIOCMODEM:
#endif
#ifdef UIOCNOMODEM
case UIOCNOMODEM:
#endif
#ifdef UIOCEMODEM
case UIOCEMODEM:
#endif
#ifdef UIOCDTRFLOW
case UIOCDTRFLOW:
#endif
#ifdef UIOCFLOW
case UIOCFLOW:
#endif
#ifdef UIOCNOFLOW
case UIOCNOFLOW:
#endif
iocack:
DATA_TYPE(mp) = M_IOCACK;
qreply (q, mp);
break;
default:
putnext (q, mp);
break;
#ifdef linux /* This is handled by the line discipline. */
iocackn:
error = -ENOIOCTLCMD; /* special code */
#endif
iocnak:
DATA_TYPE(mp) = M_IOCNAK;
iocb->ioc_error = (error < 0) ? -error : error;
qreply (q, mp);
}
break;
}
default:
if (DATA_TYPE(mp) > QPCTL || canput (q->q_next)) {
putnext (q, mp);
continue;
} else {
putbqf (q, mp);
return;
}
}
}
return;
}
static void
proto_close (queue_t * q, int dummy)
{
struct _proto *proto;
int ms;
proto = (struct _proto *) q->q_ptr;
flushq (q, FLUSHALL);
flushq (WR (q), FLUSHALL);
if(0)printf("%sFlushDel %p\n",KERN_DEBUG, &proto->write_delay);
S_flush (&proto->write_delay);
proto->qptr = NULL;
ms = splstr ();
if (proto->keep != NULL) {
freemsg (proto->keep);
proto->keep = NULL;
}
free(proto);
splx (ms);
LESS_USE;
return;
}
#ifdef MODULE
static int do_init_module(void)
{
return register_strmod(&protoinfo);
}
static int do_exit_module(void)
{
return unregister_strmod(&protoinfo);
}
#endif