X-Git-Url: https://git.ozlabs.org/?a=blobdiff_plain;f=svr4%2Fppp_comp.c;fp=svr4%2Fppp_comp.c;h=254a9358890fb00279cc2448ef62199786ecc8d1;hb=eeeeae4502021b0dac85d3212f1b25a94496ee94;hp=0000000000000000000000000000000000000000;hpb=35f06b7c87653ff6e12b6ec95d046d70fc165b5c;p=ppp.git diff --git a/svr4/ppp_comp.c b/svr4/ppp_comp.c new file mode 100644 index 0000000..254a935 --- /dev/null +++ b/svr4/ppp_comp.c @@ -0,0 +1,550 @@ +/* + * 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/05/10 01:38:47 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ALLOCATE(n) kmem_zalloc((n), KM_NOSLEEP) +#define FREE(p, n) kmem_free((p), (n)) + +#define PACKETPTR mblk_t * +#include + +static int ppp_comp_open __P((queue_t *, dev_t *, int, int, cred_t *)); +static int ppp_comp_close __P((queue_t *, int, cred_t *)); +static int ppp_comp_rput __P((queue_t *, mblk_t *)); +static int ppp_comp_wput __P((queue_t *, mblk_t *)); +static void ppp_comp_ccp __P((queue_t *, mblk_t *, int)); + +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 +}; + +static struct streamtab ppp_compinfo = { + &r_init, &w_init, NULL, NULL +}; + +static struct fmodsw fsw = { + "ppp_comp", + &ppp_compinfo, + D_NEW | D_MP | D_MTQPAIR +}; + +extern struct mod_ops mod_strmodops; + +static struct modlstrmod modlstrmod = { + &mod_strmodops, + "PPP compression module", + &fsw +}; + +static struct modlinkage modlinkage = { + MODREV_1, + (void *) &modlstrmod, + NULL +}; + +struct ppp_comp_state { + int flags; + int mru; + int mtu; + struct compressor *xcomp; + void *xstate; + struct compressor *rcomp; + void *rstate; + struct vjcompress vj_comp; +}; + +/* Bits in flags are as defined in pppio.h. */ +#define CCP_ERR (CCP_ERROR | CCP_FATALERROR) + +#define MAX_IPHDR 128 /* max TCP/IP header size */ +#define MAX_VJHDR 20 /* max VJ compressed header size (?) */ + +/* + * 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 +}; + +/* + * Entry points for modloading. + */ +int +_init(void) +{ + return mod_install(&modlinkage); +} + +int +_fini(void) +{ + return mod_remove(&modlinkage); +} + +int +_info(mip) + struct modinfo *mip; +{ + return mod_info(&modlinkage, mip); +} + +/* + * STREAMS module entry points. + */ +static int +ppp_comp_open(q, dev, flag, sflag, credp) + queue_t *q; + dev_t dev; + int flag, sflag; + cred_t *credp; +{ + struct ppp_comp_state *cp; + + if (q->q_ptr == NULL) { + cp = (struct ppp_comp_state *) ALLOCATE(sizeof(struct ppp_comp_state)); + if (cp == NULL) + return ENOSR; + OTHERQ(q)->q_ptr = q->q_ptr = cp; + cp->flags = 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; + 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_DATA: + /* first find out what the protocol is */ + if (mp->b_wptr - mp->b_rptr < PPP_HDRLEN + && !pullupmsg(mp, PPP_HDRLEN)) { + freemsg(mp); /* give up on it */ + break; + } + proto = PPP_PROTOCOL(mp->b_rptr); + + /* + * Do VJ compression if requested. + */ + if (proto == PPP_IP && (cp->flags & COMP_VJC)) { + len = msgdsize(mp); + if (len > MAX_IPHDR + PPP_HDRLEN) + len = MAX_IPHDR + PPP_HDRLEN; + if (mp->b_wptr - mp->b_rptr >= len || pullupmsg(mp, len)) { + ip = (struct ip *) (mp->b_rptr + PPP_HDRLEN); + if (ip->ip_p == IPPROTO_TCP) { + type = vj_compress_tcp(ip, len - PPP_HDRLEN, + cp->vj_comp, (cp->flags & COMP_VJCCID), + &vjhdr); + switch (type) { + case TYPE_UNCOMPRESSED_TCP: + mp->b_rptr[3] = proto = PPP_VJC_UNCOMP; + break; + case TYPE_COMPRESSED_TCP: + dp = vjhdr - PPP_HDRLEN; + dp[1] = mp->b_rptr[1]; /* copy control field */ + dp[0] = mp->b_rptr[0]; /* copy address field */ + dp[2] = 0; /* set protocol field */ + dp[3] = proto = PPP_VJC_COMP; + mp->b_rptr = dp; + break; + } + } + } + } + + /* + * Do packet compression if enabled. + */ + if (proto == PPP_CCP) + ppp_comp_ccp(q, mp, 0); + else if (proto != PPP_LCP && (cp->flags & CCP_COMP_RUN) + && cp->xstate != NULL) { + len = msgdsize(mp); + (*cp->xcomp->compress)(cp->xstate, &cmp, mp, len, + (cp->flags & CCP_ISUP? cp->mtu: 0)); + if (cmp != NULL) { + freemsg(mp); + mp = cmp; + } + } + + /* + * Do address/control and protocol compression if enabled. + */ + if (proto != PPP_LCP && (cp->flags & COMP_AC)) { + mp->b_rptr += 2; /* drop the address & ctrl fields */ + if (proto < 0x100 && (cp->flags & COMP_PROT)) + ++mp->b_rptr; /* drop the high protocol byte */ + } else if (proto < 0x100 && (cp->flags & COMP_PROT)) { + /* shuffle up the address & ctrl fields */ + mp->b_rptr[2] = mp->b_rptr[1]; + mp->b_rptr[1] = mp->b_rptr[0]; + ++mp->b_rptr; + } + + putnext(q, mp); + break; + + case M_IOCTL: + iop = (struct iocblk *) mp->b_rptr; + error = -1; + switch (iop->ioc_cmd) { + + case PPPIO_CFLAGS: + /* 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->flags = 0; + } else { + cp->flags = (cp->flags & ~CCP_ISUP) | 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->flags; + mp->b_cont->b_wptr += iop->ioc_count = sizeof(int); + break; + + case PPPIO_COMPRESS: + 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; + } + break; + } + iop->ioc_count = 0; + break; + + case PPPIO_MRU: + /* 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; + struct ppp_comp_state *cp; + + cp = (struct ppp_comp_state *) q->q_ptr; + switch (mp->b_datap->db_type) { + + case M_DATA: + /* + * First do address/control and protocol "decompression". + */ + len = msgdsize(mp); + if (len > PPP_HDRLEN) + len = PPP_HDRLEN; + if (mp->b_wptr - mp->b_rptr < len && !pullupmsg(mp, len)) { + /* XXX reset VJ */ + freemsg(mp); + break; + } + dp = mp->b_rptr; + if (PPP_ADDRESS(dp) == PPP_ALLSTATIONS && PPP_CONTROL(dp) == PPP_UI) + dp += 2; /* skip address/control */ + proto = 0; + if ((dp[0] & 1) == 0) + proto = *dp++ << 8; /* grab high byte of protocol */ + proto += *dp++; /* grab low byte of protocol */ + if (dp > mp->b_wptr) { + freemsg(mp); /* short/bogus packet */ + break; + } + if ((dp -= PPP_HDRLEN) < mp->b_datap->db_base) { + /* yucko, need a new message block */ + mp->b_rptr = dp; + np = allocb(PPP_HDRLEN, BPRI_MED); + if (np == 0) { + freemsg(mp); + break; + } + linkb(np, mp); + mp = np; + dp = mp->b_rptr; + mp->b_wptr = dp + PPP_HDRLEN; + } else + mp->b_rptr = dp; + dp[0] = PPP_ALLSTATIONS; + dp[1] = PPP_UI; + dp[2] = proto >> 8; + dp[3] = proto; + + /* + * Now see if we have a compressed packet to decompress, + * or a CCP packet to take notice of. + */ + proto = PPP_PROTOCOL(mp->b_rptr); + if (proto == PPP_CCP) + ppp_comp_ccp(q, mp, 1); + else if (proto == PPP_COMP) { + if ((cp->flags & CCP_ISUP) + && (cp->flags & CCP_DECOMP_RUN) && cp->rstate + && (cp->flags & CCP_ERR) == 0) { + rv = (*cp->rcomp->decompress)(cp->rstate, mp, &dmp); + if (dmp != NULL) { + freemsg(mp); + mp = dmp; + } else { + switch (rv) { + case DECOMP_OK: + /* no error, but no packet returned */ + freemsg(mp); + mp = NULL; + break; + case DECOMP_ERROR: + cp->flags |= CCP_ERROR; + break; + case DECOMP_FATALERROR: + cp->flags |= CCP_FATALERROR; + break; + } + } + } + } else if (cp->rstate && (cp->flags & CCP_DECOMP_RUN)) { + (*cp->rcomp->incomp)(cp->rstate, mp); + } + + /* + * Now do VJ decompression. + */ + + if (mp != NULL) + putnext(q, mp); + break; + + default: + putnext(q, mp); + } +} + +/* + * Handle a CCP packet being sent or received. + */ +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; + + switch (CCP_CODE(dp)) { + case CCP_CONFREQ: + case CCP_TERMREQ: + case CCP_TERMACK: + cp->flags &= ~CCP_ISUP; + break; + + case CCP_CONFACK: + if ((cp->flags & (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, 0)) + cp->flags |= 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, 0)) + cp->flags = (cp->flags & ~CCP_ERR) + | CCP_DECOMP_RUN; + } + } + break; + + case CCP_RESETACK: + if (cp->flags & CCP_ISUP) { + if (!rcvd) { + if (cp->xstate && (cp->flags & CCP_COMP_RUN)) + (*cp->xcomp->comp_reset)(cp->xstate); + } else { + if (cp->rstate && (cp->flags & CCP_DECOMP_RUN)) { + (*cp->rcomp->decomp_reset)(cp->rstate); + cp->flags &= ~CCP_ERROR; + } + } + } + break; + } + +}