+++ /dev/null
-/*
- * 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);
-}