copies from sunos for osf1

This commit is contained in:
Paul Mackerras 1995-12-18 23:45:11 +00:00
parent cf60450944
commit 252d98000b
3 changed files with 2517 additions and 0 deletions

896
osf1/ppp_async.c Normal file
View File

@ -0,0 +1,896 @@
/*
ppp_async.c - Streams async functions Also does FCS
Copyright (C) 1990 Brad K. Clements, All Rights Reserved
fcstab and some ideas nicked from if_ppp.c from cmu.
See copyright notice in if_ppp.h and NOTES
$Id: ppp_async.c,v 1.1 1995/12/18 23:45:07 paulus Exp $
*/
/*
* This file is used under SunOS 4.x, and OSF/1 on DEC Alpha.
*
* Beware that under OSF/1, the ioctl constants (SIOC*) end up
* as 64-bit (long) values, so an ioctl constant should be cast to
* int (32 bits) before being compared with the ioc_cmd field of
* an iocblk structure.
*/
#include <sys/types.h>
#ifndef PPP_VD
#include "ppp.h"
#endif
#if NPPP > 0
#define STREAMS 1
#define DEBUGS 1
#include <sys/param.h>
#include <sys/stream.h>
#include <sys/stropts.h>
#include <sys/dir.h>
#include <sys/signal.h>
#include <sys/user.h>
#include <sys/mbuf.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netinet/in.h>
#ifdef __osf__
#include <sys/proc.h>
#define NOTSUSER (suser(u.u_procp->p_rcred, &u.u_acflag))
#else
#define NOTSUSER (!suser())
#endif
#include <net/ppp_defs.h>
#include <net/ppp_str.h>
/* how big of a buffer block to allocate for each chunk of the input chain */
#define ALLOCBSIZE 64
#ifdef DEBUGS
#include <sys/syslog.h>
#define DLOG(s,a) if (p->pai_flags&PAI_FLAGS_DEBUG) log(LOG_DEBUG, s, a)
int ppp_async_max_dump_bytes = 28;
#define MAX_DUMP_BYTES 1504
static void ppp_dump_frame();
#else
#define DLOG(s) {}
#endif
static int ppp_async_open(), ppp_async_close(), ppp_async_rput(),
ppp_async_wput(), ppp_async_wsrv(), ppp_async_rsrv();
static struct module_info minfo ={
0xabcd,"ppp_async",0, INFPSZ, 16384, 4096
};
static struct qinit r_init = {
ppp_async_rput, ppp_async_rsrv, ppp_async_open, ppp_async_close,
NULL, &minfo, NULL
};
static struct qinit w_init = {
ppp_async_wput, ppp_async_wsrv, ppp_async_open, ppp_async_close,
NULL, &minfo, NULL
};
struct streamtab ppp_asyncinfo = {
&r_init, &w_init, NULL, NULL,
};
/*
* FCS lookup table as calculated by genfcstab.
*/
static u_short fcstab[256] = {
0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
};
struct ppp_async_info {
u_int pai_flags;
int pai_buffsize; /* how big of an input buffer to alloc */
int pai_buffcount; /* how many chars currently in input buffer */
u_short pai_fcs; /* the current fcs */
mblk_t *pai_buffer; /* pointer to the current buffer list */
mblk_t *pai_bufftail; /* pointer to the current input block */
ext_accm pai_asyncmap; /* current outgoing asyncmap */
u_int32_t pai_rasyncmap; /* current receive asyncmap */
};
/* Values for pai_flags */
#define PAI_FLAGS_INUSE 0x1
#define PAI_FLAGS_FLUSH 0x2
#define PAI_FLAGS_ESCAPED 0x4
#define PAI_FLAGS_COMPPROT 0x8
#define PAI_FLAGS_COMPAC 0x10
#define PAI_FLAGS_RCV_COMPPROT 0x20
#define PAI_FLAGS_RCV_COMPAC 0x40
#define PAI_FLAGS_DEBUG 0x1000
#define PAI_FLAGS_LOG_INPKT 0x2000
#define PAI_FLAGS_LOG_OUTPKT 0x4000
#define PAI_FLAGS_ALL_DEBUG 0x7000
typedef struct ppp_async_info PAI;
static PAI pai[NPPP*2]; /* our private cache of async ctrl structs */
/* open might fail if we don't have any more pai elements left free */
static int
ppp_async_open(q, dev, flag, sflag)
queue_t *q;
dev_t dev;
int flag;
int sflag;
{
register PAI *p;
register int x;
int s;
/* only let the superuser or setuid root ppl open this module */
if (NOTSUSER) {
u.u_error = EPERM;
return (OPENFAIL);
}
s = splstr();
if (!q->q_ptr) {
for (x=0; x < NPPP; x++) /* search for an empty PAI */
if (!(pai[x].pai_flags & PAI_FLAGS_INUSE))
break;
if (x == NPPP) { /* all buffers in use */
splx(s); /* restore processor state */
u.u_error = ENOBUFS;
return (OPENFAIL);
}
p = &pai[x];
DLOG("ppp_async%d: opening\n",x);
/* initialize the unit to default values */
WR(q)->q_ptr = q->q_ptr = (caddr_t) p;
bzero(p, sizeof(*p));
p->pai_flags = PAI_FLAGS_INUSE | PAI_FLAGS_RCV_COMPAC
| PAI_FLAGS_RCV_COMPPROT;
p->pai_asyncmap[0] = 0xffffffff; /* default async map */
p->pai_asyncmap[3] = 0x60000000; /* escape 7d, 7e */
p->pai_buffsize = PPP_MTU + PPP_HDRLEN + PPP_FCSLEN;
}
else {
p = (PAI *) q->q_ptr;
DLOG("ppp_async%d: reopen\n", p - pai);
}
splx(s);
return(0);
}
static int
ppp_async_close(q)
queue_t *q; /* queue info */
{
int s;
register PAI *p;
s = splstr();
if ((p = (PAI *) q->q_ptr) != NULL) {
p->pai_flags = 0; /* clear all flags */
if (p->pai_buffer) {
/* currently receiving some chars, discard the buffer */
freemsg(p->pai_buffer);
p->pai_buffer = NULL;
}
DLOG("ppp_async%d: closing\n", p - pai);
}
splx(s);
return(0);
}
/* M_IOCTL processing is performed at this level. There is some
weirdness here, but I couldn't think of an easier way to handle it.
SIOC{G,S}IF{,R,X}ASYNCMAP are handled here.
SIOCSIFCOMPAC and SIOCSIFCOMPPROT are both handled here.
SIOCSIFMRU and SIOCGIFMRU (Max Receive Unit) are both handled here.
Rather than using the MTU to set the MRU, we have a seperate IOCTL for it.
*/
static int
ppp_async_wput(q, mp)
queue_t *q;
register mblk_t *mp;
{
register struct iocblk *i;
register PAI *p;
int x, flags;
switch (mp->b_datap->db_type) {
case M_CTL:
switch (*(u_char *)mp->b_rptr) {
case IF_GET_CSTATS:
/* trap this and remove it */
freemsg(mp);
break;
default:
putnext(q, mp);
}
break;
case M_FLUSH :
if (*mp->b_rptr & FLUSHW)
flushq(q, FLUSHDATA);
putnext(q, mp); /* send it along too */
break;
case M_DATA :
putq(q, mp); /* queue it for my service routine */
break;
case M_IOCTL :
i = (struct iocblk *) mp->b_rptr;
p = (PAI *) q->q_ptr;
switch (i->ioc_cmd) {
case SIOCSIFCOMPAC : /* enable or disable AC compression */
if (i->ioc_count != sizeof(u_char)) {
i->ioc_error = EINVAL;
goto iocnak;
}
x = *(u_char *) mp->b_cont->b_rptr;
DLOG("ppp_async: SIFCOMPAC %d\n", x);
flags = (x & 2)? PAI_FLAGS_RCV_COMPAC: PAI_FLAGS_COMPAC;
if (x & 1)
p->pai_flags |= flags;
else
p->pai_flags &= ~flags;
i->ioc_count = 0;
goto iocack;
case SIOCSIFCOMPPROT: /* enable or disable PROT compression */
if (i->ioc_count != sizeof(u_char)) {
i->ioc_error = EINVAL;
goto iocnak;
}
x = *(u_char *) mp->b_cont->b_rptr;
DLOG("ppp_async: SIFCOMPPROT %d\n", x);
flags = (x & 2)? PAI_FLAGS_RCV_COMPPROT: PAI_FLAGS_COMPPROT;
if (x & 1)
p->pai_flags |= flags;
else
p->pai_flags &= ~flags;
i->ioc_count = 0;
goto iocack;
case SIOCSIFMRU :
if (i->ioc_count != sizeof(int)) {
i->ioc_error = EINVAL;
goto iocnak;
}
x = *(int *) mp->b_cont->b_rptr;
if (x < PPP_MTU)
x = PPP_MTU;
x += PPP_HDRLEN + PPP_FCSLEN;
if (x > 4096) { /* couldn't allocb something this big */
i->ioc_error = EINVAL;
goto iocnak;
}
p->pai_buffsize = x;
i->ioc_count = 0;
goto iocack;
case SIOCGIFMRU :
if ((mp->b_cont = allocb(sizeof(int), BPRI_MED)) != NULL) {
*(int *) mp->b_cont->b_wptr =
p->pai_buffsize - (PPP_HDRLEN + PPP_FCSLEN);
mp->b_cont->b_wptr += i->ioc_count = sizeof(int);
goto iocack;
}
i->ioc_error = ENOSR;
goto iocnak;
case SIOCGIFASYNCMAP :
if ((mp->b_cont = allocb(sizeof(u_int32_t), BPRI_MED)) != NULL) {
*(u_int32_t *) mp->b_cont->b_wptr = p->pai_asyncmap[0];
mp->b_cont->b_wptr += i->ioc_count = sizeof(u_int32_t);
goto iocack;
}
i->ioc_error = ENOSR;
goto iocnak;
case SIOCSIFASYNCMAP :
if (i->ioc_count != sizeof(u_int32_t)) {
i->ioc_error = EINVAL;
goto iocnak; /* ugh, goto */
}
p->pai_asyncmap[0] = *(u_int32_t *) mp->b_cont->b_rptr;
DLOG("ppp_async: SIFASYNCMAP %lx\n", p->pai_asyncmap[0]);
i->ioc_count = 0;
goto iocack;
case SIOCGIFRASYNCMAP :
if ((mp->b_cont = allocb(sizeof(u_int32_t), BPRI_MED)) != NULL) {
*(u_int32_t *) mp->b_cont->b_wptr = p->pai_rasyncmap;
mp->b_cont->b_wptr += i->ioc_count = sizeof(u_int32_t);
goto iocack;
}
i->ioc_error = ENOSR;
goto iocnak;
case SIOCSIFRASYNCMAP :
if (i->ioc_count != sizeof(u_int32_t)) {
i->ioc_error = EINVAL;
goto iocnak; /* ugh, goto */
}
p->pai_rasyncmap = *(u_int32_t *) mp->b_cont->b_rptr;
DLOG("ppp_async: SIFRASYNCMAP %lx\n", p->pai_rasyncmap);
i->ioc_count = 0;
goto iocack;
case SIOCGIFXASYNCMAP :
if ((mp->b_cont = allocb(sizeof(ext_accm), BPRI_MED)) != NULL) {
bcopy(p->pai_asyncmap, mp->b_cont->b_wptr, sizeof(ext_accm));
mp->b_cont->b_wptr += i->ioc_count = sizeof(ext_accm);
goto iocack;
}
i->ioc_error = ENOSR;
goto iocnak;
case SIOCSIFXASYNCMAP :
if (i->ioc_count != sizeof(ext_accm)) {
i->ioc_error = EINVAL;
goto iocnak; /* ugh, goto */
}
bcopy(mp->b_cont->b_rptr, p->pai_asyncmap, sizeof(ext_accm));
p->pai_asyncmap[1] = 0; /* can't escape 20-3f */
p->pai_asyncmap[2] &= ~0x40000000; /* can't escape 5e */
p->pai_asyncmap[3] |= 0x60000000; /* must escape 7d, 7e */
i->ioc_count = 0;
goto iocack;
case SIOCGIFDEBUG :
if ((mp->b_cont = allocb(sizeof(int), BPRI_MED)) != NULL) {
*(int *)mp->b_cont->b_wptr =
(unsigned)(p->pai_flags & PAI_FLAGS_ALL_DEBUG)
/ PAI_FLAGS_DEBUG |
(p->pai_flags & PAI_FLAGS_HIBITS);
mp->b_cont->b_wptr += i->ioc_count = sizeof(int);
goto iocack;
}
i->ioc_error = ENOSR;
goto iocnak;
case SIOCSIFDEBUG :
if(i->ioc_count != sizeof(int)) {
i->ioc_error = EINVAL;
goto iocnak; /* ugh, goto */
}
flags = *(int *)mp->b_cont->b_rptr;
DLOG("ppp_async: SIFIFDEBUG %x\n", flags);
p->pai_flags &= ~PAI_FLAGS_ALL_DEBUG | PAI_FLAGS_HIBITS;
p->pai_flags |= ((unsigned) flags * PAI_FLAGS_DEBUG)
& PAI_FLAGS_ALL_DEBUG;
i->ioc_count = 0;
goto iocack;
iocack:;
mp->b_datap->db_type = M_IOCACK;
qreply(q,mp);
break;
iocnak:;
i->ioc_count = 0;
mp->b_datap->db_type = M_IOCNAK;
qreply(q, mp);
break;
default: /* unknown IOCTL call */
putnext(q,mp); /* pass it along */
}
break;
default:
putnext(q, mp); /* don't know what to do with this, so send it along*/
}
}
static int
ppp_async_wsrv(q)
queue_t *q;
{
register u_char *cp, *wp;
register PAI *p;
register u_short fcs;
register mblk_t *mp, *m0;
mblk_t *cop, *outgoing;
int proto, len, olen, c;
p = (PAI *) q->q_ptr;
while ((mp = getq(q)) != NULL) {
/*
* we can only get M_DATA types into our Queue,
* due to our Put function
*/
if (!canput(q->q_next)) {
putbq(q, mp);
return;
}
/* at least a header required */
len = msgdsize(mp);
if (len < PPP_HDRLEN
|| (mp->b_wptr - mp->b_rptr < PPP_HDRLEN
&& !pullupmsg(mp, PPP_HDRLEN))) {
freemsg(mp); /* discard the message */
DLOG("ppp_async: short message (%d)\n", len);
/* indicate output err */
putctl1(OTHERQ(q), M_CTL, IF_OUTPUT_ERROR);
continue;
}
/* Do address/control and protocol compression */
proto = (mp->b_rptr[2] << 8) + mp->b_rptr[3];
if (p->pai_flags & PAI_FLAGS_COMPAC && proto != PPP_LCP
&& mp->b_rptr[0] == PPP_ALLSTATIONS && mp->b_rptr[1] == PPP_UI) {
mp->b_rptr += 2;
if (p->pai_flags & PAI_FLAGS_COMPPROT && proto < 0xff)
++mp->b_rptr;
} else if (p->pai_flags & PAI_FLAGS_COMPPROT && proto < 0xff) {
mp->b_rptr[2] = mp->b_rptr[1];
mp->b_rptr[1] = mp->b_rptr[0];
++mp->b_rptr;
}
m0 = mp; /* remember first message block */
fcs = PPP_INITFCS;
/*
* Estimate the required buffer length as 1.25 * message length
* to allow for escaped characters. If this isn't enough, we
* allocate another buffer later.
*/
olen = len + (len >> 2) + 5;
if (olen < 32)
olen = 32;
else if (olen > 2048)
olen = 2048;
outgoing = cop = allocb(olen, BPRI_MED);
if (outgoing == NULL) {
DLOG("allocb(%d) failed!\n", olen);
/* should do something tricky here */
goto nobuffs;
}
wp = cop->b_wptr;
/* Put the initial flag in (we'll take it out later if we don't
need it). */
*wp++ = PPP_FLAG;
--olen;
#define SPECIAL(p, c) (p->pai_asyncmap[(c) >> 5] & (1 << ((c) & 0x1F)))
/*
* Copy the message to the output block, escaping characters
* as needed.
*/
while (mp) {
for (cp = mp->b_rptr; cp < mp->b_wptr; ) {
c = *cp++;
if (olen < 2) {
/* grab another message block and put it on the end */
cop->b_wptr = wp;
olen = 256;
cop = allocb(olen, BPRI_MED);
if (cop == NULL)
goto nobuffs;
linkb(outgoing, cop);
wp = cop->b_wptr;
}
if (SPECIAL(p, c)) {
*wp++ = PPP_ESCAPE;
*wp++ = c ^ PPP_TRANS;
olen -= 2;
} else {
*wp++ = c;
--olen;
}
fcs = PPP_FCS(fcs, c);
}
mp = mp->b_cont; /* look at the next block */
} /* end while(mp) */
/*
* Add the FCS and the trailing flag.
*/
if (olen < 5) {
/* grab another message block for FCS and trailing flag */
cop->b_wptr = wp;
cop = allocb(5, BPRI_MED);
if (cop == NULL)
goto nobuffs;
linkb(outgoing, cop);
wp = cop->b_wptr;
}
fcs ^= 0xffff; /* XOR the resulting FCS */
c = fcs & 0xff;
if (SPECIAL(p, c)) {
*wp++ = PPP_ESCAPE;
*wp++ = c ^ PPP_TRANS;
} else
*wp++ = c;
c = fcs >> 8;
if (SPECIAL(p, c)) {
*wp++ = PPP_ESCAPE;
*wp++ = c ^ PPP_TRANS;
} else
*wp++ = c;
*wp++ = PPP_FLAG; /* add trailing PPP_FLAG */
cop->b_wptr = wp;
freemsg(m0);
/*
* now we check to see if the lower queue has entries, if so,
* we assume that we don't need a leading PPP_FLAG because
* these packets will be sent back to back.
*/
if (qsize(q->q_next) > 0) {
/* entries in next queue, remove the leading PPP_FLAG */
++outgoing->b_rptr;
}
#if DEBUGS
if (p->pai_flags & PAI_FLAGS_LOG_OUTPKT)
ppp_dump_frame(p, outgoing, " sent output");
#endif
putnext(q, outgoing);
continue;
nobuffs: /* well, we ran out of memory somewhere */
if (outgoing)
freemsg(outgoing); /* throw away what we have already */
putbq(q, m0); /* put back the original message */
putctl1(OTHERQ(q), M_CTL, IF_OUTPUT_ERROR);
qenable(q); /* reschedule ourselves for later */
return;
} /* end while(getq()) */
} /* end function */
static int
ppp_async_rput(q, mp)
queue_t *q;
register mblk_t *mp;
{
switch (mp->b_datap->db_type) {
case M_FLUSH:
if(*mp->b_rptr & FLUSHR)
flushq(q, FLUSHDATA);
putnext(q, mp); /* send it along too */
break;
case M_DATA:
putq(q, mp); /* queue it for my service routine */
break;
default:
putnext(q,mp); /* don't know what to do with this, so send it along */
}
}
static u_int32_t paritytab[8] = {
0x96696996, 0x69969669, 0x69969669, 0x96696996,
0x69969669, 0x96696996, 0x96696996, 0x69969669,
};
static int
ppp_async_rsrv(q)
queue_t *q;
{
register mblk_t *mp, *bp;
register PAI *p;
register u_char *cp,c;
mblk_t *m0;
register u_char *wptr;
int bcount;
p = (PAI *) q->q_ptr;
#define INPUT_ERROR(q) putctl1(q, M_CTL, IF_INPUT_ERROR)
#define STUFF_CHAR(p,c) (*wptr++ = (c), (p)->pai_buffcount++)
#define FLUSHEM(q, p) (INPUT_ERROR(q), (p)->pai_flags |= PAI_FLAGS_FLUSH)
while ((mp = getq(q)) != NULL) {
/* we can only get M_DATA types into our Queue,
due to our Put function */
if (!canput(q->q_next)) {
putbq(q, mp);
return;
}
m0 = mp; /* remember first message block */
for (; mp != NULL; mp = mp->b_cont) { /* for each message block */
cp = mp->b_rptr;
while (cp < mp->b_wptr) {
c = *cp++;
/* Accumulate info to help with detecting
non 8-bit clean links. */
if (c & 0x80)
p->pai_flags |= PAI_FLAGS_B7_1;
else
p->pai_flags |= PAI_FLAGS_B7_0;
if (paritytab[c >> 5] & (1 << (c & 0x1F)))
p->pai_flags |= PAI_FLAGS_PAR_ODD;
else
p->pai_flags |= PAI_FLAGS_PAR_EVEN;
/* Throw out chars in the receive asyncmap. */
if (c < 0x20 && (p->pai_rasyncmap & (1 << c)))
continue;
/* A flag marks the end of a frame. */
if (c == PPP_FLAG) {
bp = p->pai_buffer;
bcount = p->pai_buffcount;
p->pai_buffer = NULL;
p->pai_buffcount = 0;
/* if the escape indicator is set, then we have
seen the packet abort sequence "}~". */
if (p->pai_flags & (PAI_FLAGS_ESCAPED | PAI_FLAGS_FLUSH)) {
if ((p->pai_flags & PAI_FLAGS_FLUSH) == 0)
DLOG("ppp_async: packet abort\n", 0);
p->pai_flags &= ~(PAI_FLAGS_ESCAPED | PAI_FLAGS_FLUSH);
if (bp)
freemsg(bp);
continue;
}
if (bcount > PPP_FCSLEN) { /* discard FCS */
adjmsg(bp, -PPP_FCSLEN);
bcount -= PPP_FCSLEN;
}
if (bcount < PPP_HDRLEN) {
if (bcount) {
INPUT_ERROR(q);
DLOG("ppp_async: short input packet (%d)\n",
bcount);
}
if (bp)
freemsg(bp);
continue;
}
if (bp) {
if (p->pai_fcs == PPP_GOODFCS) {
#if DEBUGS
if (p->pai_flags & PAI_FLAGS_LOG_INPKT)
ppp_dump_frame(p, bp, " got input");
#endif /*DEBUGS*/
putnext(q, bp);
}
else {
INPUT_ERROR(q);
freemsg(bp);
DLOG("ppp_async: FCS Error\n", 0);
}
}
continue;
}
/* here c != PPP_FLAG */
if (p->pai_flags & PAI_FLAGS_FLUSH) {
while (cp < mp->b_wptr && *cp != PPP_FLAG)
++cp;
continue;
}
if (p->pai_flags & PAI_FLAGS_ESCAPED) {
p->pai_flags &= ~PAI_FLAGS_ESCAPED; /* clear esc flag */
c ^= PPP_TRANS;
} else if (c == PPP_ESCAPE) {
if (cp >= mp->b_wptr || (c = *cp) == PPP_FLAG
|| c < 0x20 && (p->pai_rasyncmap & (1 << c))) {
p->pai_flags |= PAI_FLAGS_ESCAPED;
continue;
}
c ^= PPP_TRANS;
++cp;
}
/* here we check to see if we have a buffer.
If we don't, we assume that this is the first char
for the buffer, and we allocb one */
if (!p->pai_buffer) {
/* we allocate buffer chains in blocks of ALLOCBSIZE */
if (!(p->pai_buffer = allocb(ALLOCBSIZE, BPRI_MED))) {
FLUSHEM(q, p);
continue;
/* if we don't get a buffer, is there some way
to recover and requeue later? rather than flushing
the current packet... ? */
}
p->pai_bufftail = p->pai_buffer;
}
wptr = p->pai_bufftail->b_wptr;
if (!p->pai_buffcount) {
p->pai_fcs = PPP_INITFCS;
if (c != PPP_ALLSTATIONS) {
if (p->pai_flags & PAI_FLAGS_RCV_COMPAC) {
STUFF_CHAR(p, PPP_ALLSTATIONS);
STUFF_CHAR(p, PPP_UI);
}
else {
DLOG("ppp_async: missed ALLSTATIONS (0xff), got 0x%x\n", c);
FLUSHEM(q, p);
continue;
}
}
} /* end if !p->pai_buffcount */
if (p->pai_buffcount == 1 && c != PPP_UI) {
DLOG("ppp_async: missed UI (0x3), got 0x%x\n", c);
FLUSHEM(q,p);
continue;
}
if (p->pai_buffcount == 2 && (c & 1) == 1) {
if (p->pai_flags & PAI_FLAGS_RCV_COMPPROT)
STUFF_CHAR(p, 0);
else {
DLOG("ppp_async: bad protocol high byte %x\n", c);
FLUSHEM(q, p);
continue;
}
}
if (p->pai_buffcount == 3 && (c & 1) == 0) {
DLOG("ppp_async: bad protocol low byte %x\n", c);
FLUSHEM(q, p);
continue;
}
if (p->pai_buffcount >= p->pai_buffsize) { /* overrun */
DLOG("ppp_async: too many chars in input buffer %d\n",
p->pai_buffcount);
FLUSHEM(q, p);
continue;
}
/* determine if we have enough space in the buffer */
if (wptr >= p->pai_bufftail->b_datap->db_lim) {
p->pai_bufftail->b_wptr = wptr;
if (!(p->pai_bufftail = allocb(ALLOCBSIZE, BPRI_MED))) {
DLOG("ppp_async: couldn't get buffer for tail\n", 0);
FLUSHEM(q, p); /* discard all of it */
continue;
}
linkb(p->pai_buffer, p->pai_bufftail);
wptr = p->pai_bufftail->b_wptr;
}
STUFF_CHAR(p, c);
p->pai_fcs = PPP_FCS(p->pai_fcs, c);
if (p->pai_buffcount >= PPP_HDRLEN) {
while (cp < mp->b_wptr
&& wptr < p->pai_bufftail->b_datap->db_lim
&& (c = *cp) != PPP_FLAG && c != PPP_ESCAPE) {
if (c >= 0x20 || (p->pai_rasyncmap & (1 << c)) == 0) {
STUFF_CHAR(p, c);
p->pai_fcs = PPP_FCS(p->pai_fcs, c);
}
++cp;
}
}
p->pai_bufftail->b_wptr = wptr;
} /* end while cp < wptr */
} /* end for each block */
/* discard this message now */
freemsg(m0);
} /* end while getq */
}
#if DEBUGS
/*
* here is where we will dump out a frame in hex using the log()
* function if ppp_async_input_debug is non-zero. As this function is
* a pig, we only print up to the number of bytes specified by the value of
* the ppp_async_max_dump_bytes variable so as to not cause too many
* timeouts. <gmc@quotron.com>
*/
static void
ppp_dump_frame(p, mptr, msg)
register PAI *p;
register mblk_t *mptr;
char *msg;
{
register u_char *rptr;
register u_int i, mlen, frame_length;
char buf[2*MAX_DUMP_BYTES+4]; /* tmp buffer */
char *bp = buf;
static char digits[] = "0123456789abcdef";
frame_length = i = msgdsize(mptr);
log(LOG_INFO, "ppp_async%d:%s frame of %d bytes\n", p - pai,
msg, frame_length);
rptr = mptr->b_rptr; /* get pointer to beginning */
mlen = mptr->b_wptr - rptr; /* get length of this dblock */
/* only dump up to MAX_DUMP_BYTES */
if (i > ppp_async_max_dump_bytes)
i = ppp_async_max_dump_bytes;
while (i--) { /* convert to ascii hex */
while (mlen == 0) { /* get next dblock */
mptr = mptr->b_cont;
if (mptr) { /* are we done? */
rptr = mptr->b_rptr; /* nope, get next dblock */
mlen = mptr->b_wptr - rptr;
}
else { /* no more dblocks */
if (i != 0)
log(LOG_ERR, "ppp_async: ran out of data! (this shouldn't happen\n");
break;
}
}
--mlen;
*bp++ = digits[*rptr >> 4]; /* convert byte to ascii hex */
*bp++ = digits[*rptr++ & 0xf];
}
/* add a '>' to show that frame was truncated*/
if (ppp_async_max_dump_bytes < frame_length)
*bp++ = '>';
*bp = 0;
log(LOG_INFO,"ppp_async: %s\n", buf);
}
#endif /* DEBUGS */
#endif /* NPPP > 0 */

457
osf1/ppp_comp.c Normal file
View File

@ -0,0 +1,457 @@
/*
* ppp_comp.c - STREAMS module for kernel-level CCP support.
*
* Copyright (c) 1994 The Australian National University.
* All rights reserved.
*
* Permission to use, copy, modify, and distribute this software and its
* documentation is hereby granted, provided that the above copyright
* notice appears in all copies. This software is provided without any
* warranty, express or implied. The Australian National University
* makes no representations about the suitability of this software for
* any purpose.
*
* IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
* PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
* THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
* OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
* OR MODIFICATIONS.
*
* $Id: ppp_comp.c,v 1.1 1995/12/18 23:45:09 paulus Exp $
*/
/*
* This file is used under SunOS 4.x, and OSF/1 on DEC Alpha.
*
* Beware that under OSF/1, the ioctl constants (SIOC*) end up
* as 64-bit (long) values, so an ioctl constant should be cast to
* int (32 bits) before being compared with the ioc_cmd field of
* an iocblk structure.
*/
#include <sys/types.h>
#include <sys/param.h>
#include <sys/errno.h>
#include <sys/user.h>
#include <sys/stream.h>
#include <sys/stropts.h>
#include <sys/syslog.h>
#include <sys/socket.h>
#include <net/if.h>
#include <net/ppp_defs.h>
#include <net/ppp_str.h>
#ifdef __osf__
#include <kern/kalloc.h>
#ifdef FREE
#undef FREE
#endif
#define ALLOCATE(n) kalloc((n))
#define FREE(p, n) kfree((p), (n))
#endif
#ifdef sun
#include <sys/kmem_alloc.h>
#define ALLOCATE(n) kmem_alloc((n), KMEM_NOSLEEP)
#define FREE(p, n) kmem_free((p), (n))
#endif
#define PACKETPTR mblk_t *
#include <net/ppp-comp.h>
static int ppp_comp_open(), ppp_comp_close();
static int ppp_comp_rput(), ppp_comp_wput();
static void ppp_comp_ccp();
static struct module_info minfo = {
0xbadf, "ppp_compress", 0, INFPSZ, 16384, 4096,
};
static struct qinit r_init = {
ppp_comp_rput, NULL, ppp_comp_open, ppp_comp_close,
NULL, &minfo, NULL
};
static struct qinit w_init = {
ppp_comp_wput, NULL, NULL, NULL, NULL, &minfo, NULL
};
struct streamtab ppp_compinfo = {
&r_init, &w_init, NULL, NULL
};
struct ppp_comp_state {
int ccp_state;
int debug;
int mru;
struct compressor *xcomp;
void *xstate;
struct compressor *rcomp;
void *rstate;
};
/* Bits in ccp_state are as defined in ppp_str.h. */
#define CCP_ERR (CCP_ERROR | CCP_FATALERROR)
/*
* List of compressors we know about.
*/
extern struct compressor ppp_bsd_compress;
struct compressor *ppp_compressors[] = {
#if DO_BSD_COMPRESS
&ppp_bsd_compress,
#endif
NULL
};
static int
ppp_comp_open(q, dev, flag, sflag)
queue_t *q;
dev_t dev;
int flag;
int sflag;
{
struct ppp_comp_state *cp;
if (q->q_ptr == NULL) {
cp = (struct ppp_comp_state *) ALLOCATE(sizeof(struct ppp_comp_state));
if (cp == NULL) {
u.u_error = ENOSR;
return OPENFAIL;
}
OTHERQ(q)->q_ptr = q->q_ptr = (caddr_t) cp;
cp->ccp_state = 0;
cp->debug = 0;
cp->mru = PPP_MRU;
cp->xstate = NULL;
cp->rstate = NULL;
}
return 0;
}
static int
ppp_comp_close(q)
queue_t *q;
{
struct ppp_comp_state *cp;
cp = (struct ppp_comp_state *) q->q_ptr;
if (cp != NULL) {
if (cp->xstate != NULL)
(*cp->xcomp->comp_free)(cp->xstate);
if (cp->rstate != NULL)
(*cp->rcomp->decomp_free)(cp->rstate);
FREE(cp, sizeof(struct ppp_comp_state));
q->q_ptr = NULL;
OTHERQ(q)->q_ptr = NULL;
}
return 0;
}
static int
ppp_comp_wput(q, mp)
queue_t *q;
mblk_t *mp;
{
struct iocblk *iop;
struct ppp_comp_state *cp;
mblk_t *cmp = NULL;
int error, len, proto, state;
struct ppp_option_data *odp;
struct compressor **comp;
struct ppp_comp_stats *pcp;
cp = (struct ppp_comp_state *) q->q_ptr;
switch (mp->b_datap->db_type) {
case M_CTL:
switch (*(u_char *) mp->b_rptr) {
case IF_GET_CSTATS:
freemsg(mp);
mp = allocb(sizeof(struct ppp_comp_stats) + sizeof(u_long),
BPRI_HI);
if (mp != NULL) {
mp->b_datap->db_type = M_CTL;
*(u_char *) mp->b_wptr = IF_CSTATS;
mp->b_wptr += sizeof(u_long); /* should be enough alignment */
pcp = (struct ppp_comp_stats *) mp->b_wptr;
mp->b_wptr += sizeof(struct ppp_comp_stats);
bzero(pcp, sizeof(struct ppp_comp_stats));
if (cp->xstate != NULL)
(*cp->xcomp->comp_stat)(cp->xstate, &pcp->c);
if (cp->rstate != NULL)
(*cp->rcomp->decomp_stat)(cp->rstate, &pcp->d);
qreply(q, mp);
}
break;
default:
putnext(q, mp);
}
break;
case M_DATA:
/* first find out what the protocol is */
if (mp->b_wptr - mp->b_rptr >= PPP_HDRLEN
|| pullupmsg(mp, PPP_HDRLEN)) {
proto = PPP_PROTOCOL(mp->b_rptr);
if (proto == PPP_CCP)
ppp_comp_ccp(q, mp, 0);
else if (proto != PPP_LCP && (cp->ccp_state & CCP_COMP_RUN)
&& cp->xstate != NULL) {
len = msgdsize(mp);
(*cp->xcomp->compress)(cp->xstate, &cmp, mp, len,
(cp->ccp_state & CCP_ISUP? len: 0));
/* XXX we really want the MTU here, not len */
if (cmp != NULL) {
freemsg(mp);
mp = cmp;
}
}
}
putnext(q, mp);
break;
case M_IOCTL:
iop = (struct iocblk *) mp->b_rptr;
error = -1;
switch (iop->ioc_cmd) {
case SIOCSIFCOMP:
/* set CCP state */
if (iop->ioc_count != sizeof(int)) {
error = EINVAL;
break;
}
state = (*(int *) mp->b_cont->b_rptr) & (CCP_ISUP | CCP_ISOPEN);
if ((state & CCP_ISOPEN) == 0) {
if (cp->xstate != NULL) {
(*cp->xcomp->comp_free)(cp->xstate);
cp->xstate = NULL;
}
if (cp->rstate != NULL) {
(*cp->rcomp->decomp_free)(cp->rstate);
cp->rstate = NULL;
}
cp->ccp_state = 0;
} else {
cp->ccp_state = (cp->ccp_state & ~CCP_ISUP) | state;
}
if (cp->debug)
log(LOG_DEBUG, "SIOCSIFCOMP %x, state = %x\n",
*(int *) mp->b_cont->b_rptr, cp->ccp_state);
error = 0;
iop->ioc_count = 0;
break;
case SIOCGIFCOMP:
if ((mp->b_cont = allocb(sizeof(int), BPRI_MED)) == NULL) {
error = ENOSR;
break;
}
*(int *)mp->b_cont->b_wptr = cp->ccp_state;
mp->b_cont->b_wptr += iop->ioc_count = sizeof(int);
error = 0;
break;
case SIOCSCOMPRESS:
error = EINVAL;
if (iop->ioc_count != sizeof(struct ppp_option_data))
break;
odp = (struct ppp_option_data *) mp->b_cont->b_rptr;
len = mp->b_cont->b_wptr - (unsigned char *) odp->opt_data;
if (len > odp->length)
len = odp->length;
if (odp->opt_data[1] < 2 || odp->opt_data[1] > len)
break;
for (comp = ppp_compressors; *comp != NULL; ++comp)
if ((*comp)->compress_proto == odp->opt_data[0]) {
/* here's the handler! */
error = 0;
if (odp->transmit) {
if (cp->xstate != NULL)
(*cp->xcomp->comp_free)(cp->xstate);
cp->xcomp = *comp;
cp->xstate = (*comp)->comp_alloc(odp->opt_data, len);
if (cp->xstate == NULL)
error = ENOSR;
} else {
if (cp->rstate != NULL)
(*cp->rcomp->decomp_free)(cp->rstate);
cp->rcomp = *comp;
cp->rstate = (*comp)->decomp_alloc(odp->opt_data, len);
if (cp->rstate == NULL)
error = ENOSR;
}
if (cp->debug)
log(LOG_DEBUG, "SIOCSCOMPRESS %s len=%d\n",
odp->transmit? "xmit": "recv", len);
break;
}
iop->ioc_count = 0;
break;
case SIOCSIFDEBUG:
/* set our debug flag from this */
if (iop->ioc_count == sizeof(int)) {
cp->debug = *(int *) mp->b_cont->b_rptr & 1;
}
break;
case SIOCSIFMRU:
/* remember this value */
if (iop->ioc_count == sizeof(int)) {
cp->mru = *(int *) mp->b_cont->b_rptr;
}
break;
}
if (error < 0)
putnext(q, mp);
else if (error == 0) {
mp->b_datap->db_type = M_IOCACK;
qreply(q, mp);
} else {
mp->b_datap->db_type = M_IOCNAK;
iop->ioc_count = 0;
qreply(q, mp);
}
break;
default:
putnext(q, mp);
}
}
static int
ppp_comp_rput(q, mp)
queue_t *q;
mblk_t *mp;
{
int proto, rv;
mblk_t *dmp = NULL;
struct ppp_comp_state *cp;
cp = (struct ppp_comp_state *) q->q_ptr;
switch (mp->b_datap->db_type) {
case M_DATA:
/* possibly a compressed packet to decompress,
or a CCP packet to take notice of. */
if (mp->b_wptr - mp->b_rptr >= PPP_HDRLEN
|| pullupmsg(mp, PPP_HDRLEN)) {
proto = PPP_PROTOCOL(mp->b_rptr);
if (proto == PPP_CCP)
ppp_comp_ccp(q, mp, 1);
else if (proto == PPP_COMP) {
if ((cp->ccp_state & CCP_ISUP)
&& (cp->ccp_state & CCP_DECOMP_RUN) && cp->rstate
&& (cp->ccp_state & CCP_ERR) == 0) {
rv = (*cp->rcomp->decompress)(cp->rstate, mp, &dmp);
switch (rv) {
case DECOMP_OK:
freemsg(mp);
mp = dmp;
/* if mp is now NULL, then there was no error,
but no packet returned either. */
break;
case DECOMP_ERROR:
cp->ccp_state |= CCP_ERROR;
break;
case DECOMP_FATALERROR:
cp->ccp_state |= CCP_FATALERROR;
break;
}
}
} else if (cp->rstate && (cp->ccp_state & CCP_DECOMP_RUN)) {
(*cp->rcomp->incomp)(cp->rstate, mp);
}
}
if (mp != NULL)
putnext(q, mp);
break;
default:
putnext(q, mp);
}
}
static void
ppp_comp_ccp(q, mp, rcvd)
queue_t *q;
mblk_t *mp;
int rcvd;
{
int len, clen;
struct ppp_comp_state *cp;
unsigned char *dp;
len = msgdsize(mp);
if (len < PPP_HDRLEN + CCP_HDRLEN || !pullupmsg(mp, len))
return;
cp = (struct ppp_comp_state *) q->q_ptr;
dp = mp->b_rptr + PPP_HDRLEN;
len -= PPP_HDRLEN;
clen = CCP_LENGTH(dp);
if (clen > len)
return;
if (cp->debug)
log(LOG_DEBUG, "CCP %s: code=%x len=%d\n", rcvd? "rcvd": "sent",
CCP_CODE(dp), clen);
switch (CCP_CODE(dp)) {
case CCP_CONFREQ:
case CCP_TERMREQ:
case CCP_TERMACK:
cp->ccp_state &= ~CCP_ISUP;
break;
case CCP_CONFACK:
if ((cp->ccp_state & (CCP_ISOPEN | CCP_ISUP)) == CCP_ISOPEN
&& clen >= CCP_HDRLEN + CCP_OPT_MINLEN
&& clen >= CCP_HDRLEN + CCP_OPT_LENGTH(dp + CCP_HDRLEN)) {
if (!rcvd) {
if (cp->xstate != NULL
&& (*cp->xcomp->comp_init)
(cp->xstate, dp + CCP_HDRLEN, clen - CCP_HDRLEN,
0, /* XXX: should be unit */ 0,
cp->debug))
cp->ccp_state |= CCP_COMP_RUN;
} else {
if (cp->rstate != NULL
&& (*cp->rcomp->decomp_init)
(cp->rstate, dp + CCP_HDRLEN, clen - CCP_HDRLEN,
0/* unit */, 0, cp->mru, cp->debug))
cp->ccp_state = (cp->ccp_state & ~CCP_ERR)
| CCP_DECOMP_RUN;
}
}
break;
case CCP_RESETACK:
if (cp->ccp_state & CCP_ISUP) {
if (!rcvd) {
if (cp->xstate && (cp->ccp_state & CCP_COMP_RUN))
(*cp->xcomp->comp_reset)(cp->xstate);
} else {
if (cp->rstate && (cp->ccp_state & CCP_DECOMP_RUN)) {
(*cp->rcomp->decomp_reset)(cp->rstate);
cp->ccp_state &= ~CCP_ERROR;
}
}
}
break;
}
if (cp->debug)
log(LOG_DEBUG, "ccp_state = %x\n", cp->ccp_state);
}

1164
osf1/ppp_if.c Normal file

File diff suppressed because it is too large Load Diff