X-Git-Url: http://git.ozlabs.org/?p=ppp.git;a=blobdiff_plain;f=svr4%2Fppp_comp.c;h=4a33591503f6e484df04f70ee5eaf311acd3ed14;hp=254a9358890fb00279cc2448ef62199786ecc8d1;hb=f8d05a1667af0c81e7c517466d870686afff0a54;hpb=eeeeae4502021b0dac85d3212f1b25a94496ee94 diff --git a/svr4/ppp_comp.c b/svr4/ppp_comp.c index 254a935..4a33591 100644 --- a/svr4/ppp_comp.c +++ b/svr4/ppp_comp.c @@ -1,5 +1,5 @@ /* - * ppp_comp.c - STREAMS module for kernel-level CCP support. + * ppp_comp.c - STREAMS module for kernel-level compression and CCP support. * * Copyright (c) 1994 The Australian National University. * All rights reserved. @@ -24,32 +24,31 @@ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, * OR MODIFICATIONS. * - * $Id: ppp_comp.c,v 1.1 1995/05/10 01:38:47 paulus Exp $ + * $Id: ppp_comp.c,v 1.3 1995/05/29 06:43:50 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. + * This file is used under Solaris 2. */ #include #include #include #include -#include #include #include +#include #include +#ifdef sun +#include #include +#endif #include -#include - -#define ALLOCATE(n) kmem_zalloc((n), KM_NOSLEEP) -#define FREE(p, n) kmem_free((p), (n)) +#include +#include +#include +#include +#include #define PACKETPTR mblk_t * #include @@ -57,26 +56,29 @@ 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_rsrv __P((queue_t *)); static int ppp_comp_wput __P((queue_t *, mblk_t *)); +static int ppp_comp_wsrv __P((queue_t *)); static void ppp_comp_ccp __P((queue_t *, mblk_t *, int)); static struct module_info minfo = { - 0xbadf, "ppp_compress", 0, INFPSZ, 16384, 4096, + 0xbadf, "ppp_comp", 0, INFPSZ, 16384, 4096, }; static struct qinit r_init = { - ppp_comp_rput, NULL, ppp_comp_open, ppp_comp_close, + ppp_comp_rput, ppp_comp_rsrv, ppp_comp_open, ppp_comp_close, NULL, &minfo, NULL }; static struct qinit w_init = { - ppp_comp_wput, NULL, NULL, NULL, NULL, &minfo, NULL + ppp_comp_wput, ppp_comp_wsrv, NULL, NULL, NULL, &minfo, NULL }; static struct streamtab ppp_compinfo = { &r_init, &w_init, NULL, NULL }; +#ifdef sun static struct fmodsw fsw = { "ppp_comp", &ppp_compinfo, @@ -96,24 +98,32 @@ static struct modlinkage modlinkage = { (void *) &modlstrmod, NULL }; +#endif -struct ppp_comp_state { +typedef struct comp_state { int flags; int mru; int mtu; + int unit; struct compressor *xcomp; void *xstate; struct compressor *rcomp; void *rstate; struct vjcompress vj_comp; -}; + int vj_last_ierrors; + struct pppstat stats; +} comp_state_t; /* Bits in flags are as defined in pppio.h. */ #define CCP_ERR (CCP_ERROR | CCP_FATALERROR) +#define LAST_MOD 0x1000000 /* no ppp modules below us */ #define MAX_IPHDR 128 /* max TCP/IP header size */ #define MAX_VJHDR 20 /* max VJ compressed header size (?) */ +#undef MIN /* just in case */ +#define MIN(a, b) ((a) < (b)? (a): (b)) + /* * List of compressors we know about. */ @@ -127,6 +137,7 @@ struct compressor *ppp_compressors[] = { NULL }; +#ifdef sun /* * Entry points for modloading. */ @@ -148,45 +159,57 @@ _info(mip) { return mod_info(&modlinkage, mip); } +#endif + +#ifndef sun +# define qprocson(q) +# define qprocsoff(q) +#endif /* * STREAMS module entry points. */ static int -ppp_comp_open(q, dev, flag, sflag, credp) +ppp_comp_open(q, devp, flag, sflag, credp) queue_t *q; - dev_t dev; + dev_t *devp; int flag, sflag; cred_t *credp; { - struct ppp_comp_state *cp; + comp_state_t *cp; if (q->q_ptr == NULL) { - cp = (struct ppp_comp_state *) ALLOCATE(sizeof(struct ppp_comp_state)); + cp = (comp_state_t *) kmem_zalloc(sizeof(comp_state_t), KM_SLEEP); if (cp == NULL) return ENOSR; - OTHERQ(q)->q_ptr = q->q_ptr = cp; - cp->flags = 0; + WR(q)->q_ptr = q->q_ptr = cp; + bzero((caddr_t)cp, sizeof(comp_state_t)); cp->mru = PPP_MRU; + cp->mtu = PPP_MRU; cp->xstate = NULL; cp->rstate = NULL; + vj_compress_init(&cp->vj_comp, -1); + qprocson(q); } return 0; } static int -ppp_comp_close(q) +ppp_comp_close(q, flag, credp) queue_t *q; + int flag; + cred_t *credp; { - struct ppp_comp_state *cp; + comp_state_t *cp; - cp = (struct ppp_comp_state *) q->q_ptr; + qprocsoff(q); + cp = (comp_state_t *) 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)); + kmem_free(cp, sizeof(comp_state_t)); q->q_ptr = NULL; OTHERQ(q)->q_ptr = NULL; } @@ -199,101 +222,36 @@ ppp_comp_wput(q, mp) mblk_t *mp; { struct iocblk *iop; - struct ppp_comp_state *cp; - mblk_t *cmp; - int error, len, proto, state; - struct ppp_option_data *odp; + comp_state_t *cp; + int error, len; + int flags, mask; + mblk_t *np; struct compressor **comp; - struct ppp_comp_stats *pcp; + struct ppp_stats *psp; + struct ppp_comp_stats *csp; + unsigned char *opt_data; + int nxslots, nrslots; - cp = (struct ppp_comp_state *) q->q_ptr; + cp = (comp_state_t *) 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); + putq(q, mp); break; case M_IOCTL: iop = (struct iocblk *) mp->b_rptr; - error = -1; + error = EINVAL; switch (iop->ioc_cmd) { case PPPIO_CFLAGS: - /* set CCP state */ - if (iop->ioc_count != sizeof(int)) { - error = EINVAL; + /* set/get CCP state */ + if (iop->ioc_count != 2 * sizeof(int)) break; - } - state = (*(int *) mp->b_cont->b_rptr) & (CCP_ISUP | CCP_ISOPEN); - if ((state & CCP_ISOPEN) == 0) { + flags = ((int *) mp->b_cont->b_rptr)[0]; + mask = ((int *) mp->b_cont->b_rptr)[1]; + cp->flags = (cp->flags & ~mask) | (flags & mask); + if ((mask & CCP_ISOPEN) && (flags & CCP_ISOPEN) == 0) { if (cp->xstate != NULL) { (*cp->xcomp->comp_free)(cp->xstate); cp->xstate = NULL; @@ -302,49 +260,56 @@ ppp_comp_wput(q, mp) (*cp->rcomp->decomp_free)(cp->rstate); cp->rstate = NULL; } - cp->flags = 0; - } else { - cp->flags = (cp->flags & ~CCP_ISUP) | state; + cp->flags &= ~CCP_ISUP; } error = 0; - iop->ioc_count = 0; + iop->ioc_count = sizeof(int); + ((int *) mp->b_cont->b_rptr)[0] = cp->flags; + mp->b_cont->b_wptr = mp->b_cont->b_rptr + sizeof(int); break; - case SIOCGIFCOMP: - if ((mp->b_cont = allocb(sizeof(int), BPRI_MED)) == NULL) { - error = ENOSR; + case PPPIO_VJINIT: + /* + * Initialize VJ compressor/decompressor + */ + if (iop->ioc_count != 2) break; - } - *(int *)mp->b_cont->b_wptr = cp->flags; - mp->b_cont->b_wptr += iop->ioc_count = sizeof(int); + nxslots = mp->b_cont->b_rptr[0] + 1; + nrslots = mp->b_cont->b_rptr[1] + 1; + if (nxslots > MAX_STATES || nrslots > MAX_STATES) + break; + vj_compress_init(&cp->vj_comp, nxslots); + cp->vj_last_ierrors = cp->stats.ppp_ierrors; + error = 0; + iop->ioc_count = 0; break; - case PPPIO_COMPRESS: - error = EINVAL; - if (iop->ioc_count != sizeof(struct ppp_option_data)) + case PPPIO_XCOMP: + case PPPIO_RCOMP: + if (iop->ioc_count <= 0) 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) + opt_data = mp->b_cont->b_rptr; + len = mp->b_cont->b_wptr - opt_data; + if (len > iop->ioc_count) + len = iop->ioc_count; + if (opt_data[1] < 2 || opt_data[1] > len) break; for (comp = ppp_compressors; *comp != NULL; ++comp) - if ((*comp)->compress_proto == odp->opt_data[0]) { + if ((*comp)->compress_proto == opt_data[0]) { /* here's the handler! */ error = 0; - if (odp->transmit) { + if (iop->ioc_cmd == PPPIO_XCOMP) { if (cp->xstate != NULL) (*cp->xcomp->comp_free)(cp->xstate); cp->xcomp = *comp; - cp->xstate = (*comp)->comp_alloc(odp->opt_data, len); + cp->xstate = (*comp)->comp_alloc(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); + cp->rstate = (*comp)->decomp_alloc(opt_data, len); if (cp->rstate == NULL) error = ENOSR; } @@ -353,13 +318,55 @@ ppp_comp_wput(q, mp) 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; + case PPPIO_GETSTAT: + if ((cp->flags & LAST_MOD) == 0) { + error = -1; /* let the ppp_ahdl module handle it */ + break; + } + np = allocb(sizeof(struct ppp_stats), BPRI_HI); + if (np == 0) { + error = ENOSR; + break; + } + if (mp->b_cont != 0) + freemsg(mp->b_cont); + mp->b_cont = np; + psp = (struct ppp_stats *) np->b_wptr; + np->b_wptr += sizeof(struct ppp_stats); + iop->ioc_count = sizeof(struct ppp_stats); + psp->p = cp->stats; + psp->vj = cp->vj_comp.stats; + error = 0; + break; + + case PPPIO_GETCSTAT: + np = allocb(sizeof(struct ppp_comp_stats), BPRI_HI); + if (np == 0) { + error = ENOSR; + break; } + if (mp->b_cont != 0) + freemsg(mp->b_cont); + mp->b_cont = np; + csp = (struct ppp_comp_stats *) np->b_wptr; + np->b_wptr += sizeof(struct ppp_comp_stats); + iop->ioc_count = sizeof(struct ppp_comp_stats); + bzero((caddr_t)csp, sizeof(struct ppp_comp_stats)); + if (cp->xstate != 0) + (*cp->xcomp->comp_stat)(cp->xstate, &csp->c); + if (cp->rstate != 0) + (*cp->rcomp->decomp_stat)(cp->rstate, &csp->d); + error = 0; break; + case PPPIO_LASTMOD: + cp->flags |= LAST_MOD; + error = 0; + break; + + default: + error = -1; + break; } if (error < 0) @@ -369,69 +376,261 @@ ppp_comp_wput(q, mp) qreply(q, mp); } else { mp->b_datap->db_type = M_IOCNAK; + iop->ioc_error = error; iop->ioc_count = 0; qreply(q, mp); } break; + case M_CTL: + switch (*mp->b_rptr) { + case PPPCTL_MTU: + cp->mtu = ((unsigned short *)mp->b_rptr)[1]; + break; + case PPPCTL_MRU: + cp->mru = ((unsigned short *)mp->b_rptr)[1]; + break; + case PPPCTL_UNIT: + cp->unit = mp->b_rptr[1]; + break; + } + putnext(q, mp); + break; + default: putnext(q, mp); } } +static int +ppp_comp_wsrv(q) + queue_t *q; +{ + mblk_t *mp, *cmp, *np; + comp_state_t *cp; + int len, proto, type; + struct ip *ip; + unsigned char *vjhdr, *dp; + + cp = (comp_state_t *) q->q_ptr; + while ((mp = getq(q)) != 0) { + /* assert(mp->b_datap->db_type == M_DATA) */ + if (!canputnext(q)) { + putbq(q, mp); + return; + } + + /* + * Make sure we've got a reasonable amount in the first + * mblk and that we are its only user. + * Then find out what the protocol is. + */ + len = msgdsize(mp); + if (len > PPP_HDRLEN + MAX_IPHDR) + len = PPP_HDRLEN + MAX_IPHDR; + if (mp->b_wptr < mp->b_rptr + len || mp->b_datap->db_ref > 1) { + np = msgpullup(mp, len); + freemsg(mp); + if (np == 0) { +#if DEBUG + cmn_err(CE_CONT, "ppp_comp_wsrv: msgpullup failed\n"); +#endif + cp->stats.ppp_oerrors++; + putctl1(RD(q)->q_next, M_CTL, PPPCTL_OERROR); + continue; + } + mp = np; + } + proto = PPP_PROTOCOL(mp->b_rptr); + + /* + * Do VJ compression if requested. + */ + if (proto == PPP_IP && (cp->flags & COMP_VJC)) { + 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; + } + + cp->stats.ppp_opackets++; + cp->stats.ppp_obytes += msgdsize(mp); + 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; + comp_state_t *cp; + struct iocblk *iop; + struct ppp_stats *psp; - cp = (struct ppp_comp_state *) q->q_ptr; + cp = (comp_state_t *) q->q_ptr; switch (mp->b_datap->db_type) { case M_DATA: + putq(q, mp); + break; + + case M_IOCACK: + iop = (struct iocblk *) mp->b_rptr; + switch (iop->ioc_cmd) { + case PPPIO_GETSTAT: + /* + * Catch this on the way back from the ppp_ahdl module + * so we can fill in the VJ stats. + */ + if (mp->b_cont == 0 || iop->ioc_count != sizeof(struct ppp_stats)) + break; + psp = (struct ppp_stats *) mp->b_cont->b_rptr; + psp->vj = cp->vj_comp.stats; + break; + } + putnext(q, mp); + break; + + case M_CTL: + switch (mp->b_rptr[0]) { + case PPPCTL_IERROR: + ++cp->stats.ppp_ierrors; + break; + case PPPCTL_OERROR: + ++cp->stats.ppp_oerrors; + break; + } + putnext(q, mp); + break; + + default: + putnext(q, mp); + } +} + +static int +ppp_comp_rsrv(q) + queue_t *q; +{ + int proto, rv, i; + mblk_t *mp, *dmp, *np; + uchar_t *dp, *iphdr; + comp_state_t *cp; + int len, hlen, vjlen, iphlen; + + cp = (comp_state_t *) q->q_ptr; + while ((mp = getq(q)) != 0) { + /* assert(mp->b_datap->db_type == M_DATA) */ + if (!canputnext(q)) { + putbq(q, mp); + return; + } + + len = msgdsize(mp); + cp->stats.ppp_ibytes += len; + cp->stats.ppp_ipackets++; + /* * 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 */ + hlen = MIN(len, PPP_HDRLEN); + if (mp->b_wptr < mp->b_rptr + hlen) { + np = msgpullup(mp, hlen); + if (np == 0) + goto bad; freemsg(mp); - break; + mp = np; } dp = mp->b_rptr; - if (PPP_ADDRESS(dp) == PPP_ALLSTATIONS && PPP_CONTROL(dp) == PPP_UI) + if (PPP_ADDRESS(dp) == PPP_ALLSTATIONS + && PPP_CONTROL(dp) == PPP_UI) dp += 2; /* skip address/control */ + else if ((cp->flags & DECOMP_AC) == 0) { + /* count these? */ + goto bad; + } proto = 0; - if ((dp[0] & 1) == 0) + if ((*dp & 1) == 0) proto = *dp++ << 8; /* grab high byte of protocol */ + else if ((cp->flags & DECOMP_PROT) == 0) { + /* count these? */ + goto bad; + } proto += *dp++; /* grab low byte of protocol */ - if (dp > mp->b_wptr) { - freemsg(mp); /* short/bogus packet */ - break; + if (dp > mp->b_wptr) + goto bad; /* short/bogus packet */ + dp -= PPP_HDRLEN; + if (dp != mp->b_rptr) { + /* + * We need to put some bytes on the front of the packet + * to make a full-length PPP header. + * If we can put them in *mp, we do, otherwise we + * tack another mblk on the front. + * XXX we really shouldn't need to carry around + * the address and control at this stage. + */ + if (dp < mp->b_datap->db_base || mp->b_datap->db_ref > 1) { + np = allocb(PPP_HDRLEN, BPRI_MED); + if (np == 0) + goto bad; + np->b_cont = mp; + mp->b_rptr = dp + PPP_HDRLEN; + mp = np; + dp = mp->b_wptr; + mp->b_wptr += PPP_HDRLEN; + } else + mp->b_rptr = dp; + + dp[0] = PPP_ALLSTATIONS; + dp[1] = PPP_UI; + dp[2] = proto >> 8; + dp[3] = proto; } - 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, @@ -453,13 +652,16 @@ ppp_comp_rput(q, mp) case DECOMP_OK: /* no error, but no packet returned */ freemsg(mp); - mp = NULL; - break; + continue; case DECOMP_ERROR: cp->flags |= CCP_ERROR; + ++cp->stats.ppp_ierrors; + putctl1(q->q_next, M_CTL, PPPCTL_IERROR); break; case DECOMP_FATALERROR: cp->flags |= CCP_FATALERROR; + ++cp->stats.ppp_ierrors; + putctl1(q->q_next, M_CTL, PPPCTL_IERROR); break; } } @@ -471,13 +673,104 @@ ppp_comp_rput(q, mp) /* * Now do VJ decompression. */ + proto = PPP_PROTOCOL(mp->b_rptr); + if (proto == PPP_VJC_COMP || proto == PPP_VJC_UNCOMP) { + len = msgdsize(mp) - PPP_HDRLEN; + if ((cp->flags & DECOMP_VJC) == 0 || len <= 0) + goto bad; + + /* + * Advance past the ppp header. + * Here we assume that the whole PPP header is in the first mblk. + */ + np = mp; + dp = np->b_rptr + PPP_HDRLEN; + if (dp >= mp->b_wptr) { + np = np->b_cont; + dp = np->b_rptr; + } - if (mp != NULL) - putnext(q, mp); - break; + if (proto == PPP_VJC_COMP) { + hlen = MIN(len, MAX_VJHDR); + if (np->b_wptr < dp + hlen) { + np = msgpullup(mp, hlen + PPP_HDRLEN); + if (np == 0) + goto bad; + freemsg(mp); + mp = np; + dp = np->b_rptr + PPP_HDRLEN; + } + + if (cp->stats.ppp_ierrors != cp->vj_last_ierrors) { + vj_uncompress_err(&cp->vj_comp); + cp->vj_last_ierrors = cp->stats.ppp_ierrors; + } + + vjlen = vj_uncompress_tcp(dp, np->b_wptr - dp, len, + &cp->vj_comp, &iphdr, &iphlen); + if (vjlen < 0) + goto bad; + + /* drop ppp and vj headers off */ + if (mp != np) { + freeb(mp); + mp = np; + } + mp->b_rptr = dp + vjlen; + + /* allocate a new mblk for the ppp and ip headers */ + if ((np = allocb(iphlen + PPP_HDRLEN + 4, BPRI_MED)) == 0) + goto bad; + dp = np->b_rptr; /* prepend mblk with TCP/IP hdr */ + dp[0] = PPP_ALLSTATIONS; /* reconstruct PPP header */ + dp[1] = PPP_UI; + dp[2] = PPP_IP >> 8; + dp[3] = PPP_IP; + bcopy(iphdr, dp + PPP_HDRLEN, iphlen); + np->b_wptr = dp + iphlen + PPP_HDRLEN; + np->b_cont = mp; + + /* XXX there seems to be a bug which causes panics in strread + if we make an mbuf with only the IP header in it :-( */ + if (mp->b_wptr - mp->b_rptr > 4) { + bcopy(mp->b_rptr, np->b_wptr, 4); + mp->b_rptr += 4; + np->b_wptr += 4; + } else { + bcopy(mp->b_rptr, np->b_wptr, mp->b_wptr - mp->b_rptr); + np->b_wptr += mp->b_wptr - mp->b_rptr; + np->b_cont = mp->b_cont; + freeb(mp); + } + + mp = np; + + } else { + hlen = MIN(len, MAX_IPHDR); + if (np->b_wptr < dp + hlen || np->b_datap->db_ref > 1 + || mp->b_datap->db_ref > 1) { + np = msgpullup(mp, hlen + PPP_HDRLEN); + if (np == 0) + goto bad; + freemsg(mp); + mp = np; + dp = np->b_rptr + PPP_HDRLEN; + } + + if (!vj_uncompress_uncomp(dp, &cp->vj_comp)) + goto bad; + mp->b_rptr[3] = PPP_IP; /* fix up the PPP protocol field */ + } + } - default: putnext(q, mp); + continue; + + bad: + if (mp != 0) + freemsg(mp); + cp->stats.ppp_ierrors++; + putctl1(q->q_next, M_CTL, PPPCTL_IERROR); } } @@ -491,18 +784,28 @@ ppp_comp_ccp(q, mp, rcvd) int rcvd; { int len, clen; - struct ppp_comp_state *cp; + comp_state_t *cp; unsigned char *dp; + mblk_t *np; len = msgdsize(mp); - if (len < PPP_HDRLEN + CCP_HDRLEN || !pullupmsg(mp, len)) + if (len < PPP_HDRLEN + CCP_HDRLEN) return; - cp = (struct ppp_comp_state *) q->q_ptr; + if (mp->b_wptr < mp->b_rptr + len) { + np = msgpullup(mp, len); + if (np == 0) { + cmn_err(CE_CONT, "ppp_comp_ccp: msgpullup failed\n"); + return; + } + } else + np = mp; + + cp = (comp_state_t *) q->q_ptr; dp = mp->b_rptr + PPP_HDRLEN; len -= PPP_HDRLEN; clen = CCP_LENGTH(dp); if (clen > len) - return; + goto bad; switch (CCP_CODE(dp)) { case CCP_CONFREQ: @@ -519,13 +822,13 @@ ppp_comp_ccp(q, mp, 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->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->unit, 0, cp->mru, 0)) cp->flags = (cp->flags & ~CCP_ERR) | CCP_DECOMP_RUN; } @@ -547,4 +850,25 @@ ppp_comp_ccp(q, mp, rcvd) break; } + bad: + if (np != mp) + freemsg(np); } + +#if DEBUG +dump_msg(mp) + mblk_t *mp; +{ + dblk_t *db; + + while (mp != 0) { + db = mp->b_datap; + cmn_err(CE_CONT, "mp=%x cont=%x rptr=%x wptr=%x datap=%x\n", + mp, mp->b_cont, mp->b_rptr, mp->b_wptr, db); + cmn_err(CE_CONT, " base=%x lim=%x ref=%d type=%d struioflag=%d\n", + db->db_base, db->db_lim, db->db_ref, db->db_type, + db->db_struioflag); + mp = mp->b_cont; + } +} +#endif