/*
* deflate.c - interface the zlib procedures for Deflate compression
* and decompression (as used by gzip) to the PPP code.
*
* This version is for use with STREAMS in Solaris 2
*
* Copyright (c) 2001 by Sun Microsystems, Inc.
* All rights reserved.
*
* 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 HAS 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: deflate.c,v 1.9 1999/01/19 23:58:35 paulus Exp $
*/
#define NO_DUMMY_DECL
#include <sys/param.h>
#include <sys/types.h>
#include <sys/kmem.h>
#include <sys/stream.h>
#include <sys/cmn_err.h>
#include <sys/ddi.h>
#include <sys/sunddi.h>
#include <sys/errno.h>
#include <net/ppp_defs.h>
/* Defined for platform-neutral include file */
#define PACKETPTR mblk_t *
#include <net/ppp-comp.h>
#include "s_common.h"
#include "zlib.h"
#if DO_DEFLATE
/*
* State for a Deflate (de)compressor.
*/
struct deflate_state {
int seqno;
int w_size;
int unit;
int hdrlen;
int mru;
int flags;
z_stream strm;
struct compstat stats;
};
#define DEFLATE_OVHD 2 /* Deflate overhead/packet */
#define DS_DEBUG 0x0001
#define DS_TESTIN 0x0002
#define DS_TESTOUT 0x0004
static void *z_alloc(void *, uint_t items, uint_t size);
static void z_free(void *, void *ptr);
static void *z_comp_alloc(uchar_t *options, int opt_len);
static void *z_decomp_alloc(uchar_t *options, int opt_len);
static void z_comp_free(void *state);
static void z_decomp_free(void *state);
static int z_comp_init(void *state, uchar_t *options, int opt_len,
int unit, int hdrlen, int debug);
static int z_decomp_init(void *state, uchar_t *options, int opt_len,
int unit, int hdrlen, int mru, int debug);
static int z_compress(void *state, mblk_t **mret,
mblk_t *mp, int slen, int maxolen);
static int z_incomp(void *state, mblk_t *dmsg);
static int z_decompress(void *state, mblk_t **dmpp);
static void z_comp_reset(void *state);
static void z_decomp_reset(void *state);
static void z_comp_stats(void *state, struct compstat *stats);
static int z_set_effort(void *xstate, void *rstate, int effortlevel);
/*
* Procedures exported to ppp_comp.c.
*/
struct compressor ppp_deflate = {
CI_DEFLATE, /* compress_proto */
z_comp_alloc, /* comp_alloc */
z_comp_free, /* comp_free */
z_comp_init, /* comp_init */
z_comp_reset, /* comp_reset */
z_compress, /* compress */
z_comp_stats, /* comp_stat */
z_decomp_alloc, /* decomp_alloc */
z_decomp_free, /* decomp_free */
z_decomp_init, /* decomp_init */
z_decomp_reset, /* decomp_reset */
z_decompress, /* decompress */
z_incomp, /* incomp */
z_comp_stats, /* decomp_stat */
z_set_effort, /* set_effort */
};
struct compressor ppp_deflate_draft = {
CI_DEFLATE_DRAFT, /* compress_proto */
z_comp_alloc, /* comp_alloc */
z_comp_free, /* comp_free */
z_comp_init, /* comp_init */
z_comp_reset, /* comp_reset */
z_compress, /* compress */
z_comp_stats, /* comp_stat */
z_decomp_alloc, /* decomp_alloc */
z_decomp_free, /* decomp_free */
z_decomp_init, /* decomp_init */
z_decomp_reset, /* decomp_reset */
z_decompress, /* decompress */
z_incomp, /* incomp */
z_comp_stats, /* decomp_stat */
z_set_effort, /* set_effort */
};
#define DECOMP_CHUNK 512
/*
* Space allocation and freeing routines for use by zlib routines.
*/
struct zchunk {
uint_t size;
uint_t guard;
};
#define GUARD_MAGIC 0x77a6011a
/*
* z_alloc()
*/
/* ARGSUSED */
static void *
z_alloc(void *notused, uint_t items, uint_t size)
{
struct zchunk *z;
size = items * size + sizeof (struct zchunk);
z = (struct zchunk *)kmem_alloc(size, KM_NOSLEEP);
if (z == NULL)
return (NULL);
z->size = size;
z->guard = GUARD_MAGIC;
return ((void *)(z + 1));
}
/*
* z_free()
*/
/* ARGSUSED */
static void
z_free(void *notused, void *ptr)
{
struct zchunk *z = ((struct zchunk *)ptr) - 1;
if (ptr == NULL)
return;
if (z->guard != GUARD_MAGIC) {
cmn_err(CE_CONT,
"deflate: z_free of corrupted chunk at 0x%p (%x, %x)\n",
(void *)z, z->size, z->guard);
return;
}
kmem_free(z, z->size);
}
/*
* Allocate space for a compressor.
*/
static void *
z_comp_alloc(uchar_t *options, int opt_len)
{
struct deflate_state *state;
int w_size;
if (opt_len != CILEN_DEFLATE ||
(options[0] != CI_DEFLATE && options[0] != CI_DEFLATE_DRAFT) ||
options[1] != CILEN_DEFLATE ||
DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL ||
options[3] != DEFLATE_CHK_SEQUENCE) {
return (NULL);
}
w_size = DEFLATE_SIZE(options[2]);
/*
* Check <= minimum size to avoid unfixable zlib bug -- window size
* 256 (w_size 8) is not supported.
*/
if (w_size <= DEFLATE_MIN_SIZE || w_size > DEFLATE_MAX_SIZE) {
return (NULL);
}
state = (struct deflate_state *)kmem_zalloc(sizeof (*state), KM_SLEEP);
ASSERT(state != NULL);
state->strm.zalloc = (alloc_func)z_alloc;
state->strm.zfree = (free_func)z_free;
if (deflateInit2(&state->strm, Z_DEFAULT_COMPRESSION,
DEFLATE_METHOD_VAL, -w_size, 8, Z_DEFAULT_STRATEGY) != Z_OK) {
kmem_free(state, sizeof (*state));
return (NULL);
}
state->w_size = w_size;
bzero(&state->stats, sizeof (state->stats));
return ((void *)state);
}
/*
* z_comp_free()
*/
static void
z_comp_free(void *arg)
{
struct deflate_state *state = (struct deflate_state *)arg;
(void) deflateEnd(&state->strm);
kmem_free(state, sizeof (*state));
}
/*
* z_comp_init()
*/
static int
z_comp_init(void *arg, uchar_t *options, int opt_len, int unit, int hdrlen,
int debug)
{
struct deflate_state *state = (struct deflate_state *)arg;
if (opt_len < CILEN_DEFLATE ||
(options[0] != CI_DEFLATE && options[0] != CI_DEFLATE_DRAFT) ||
options[1] != CILEN_DEFLATE ||
DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL ||
DEFLATE_SIZE(options[2]) != state->w_size ||
options[3] != DEFLATE_CHK_SEQUENCE) {
return (0);
}
state->seqno = 0;
state->unit = unit;
state->hdrlen = hdrlen;
if (debug)
state->flags |= DS_DEBUG;
else
state->flags &= ~DS_DEBUG;
(void) deflateReset(&state->strm);
return (1);
}
/*
* z_comp_reset()
*/
static void
z_comp_reset(void *arg)
{
struct deflate_state *state = (struct deflate_state *)arg;
state->seqno = 0;
(void) deflateReset(&state->strm);
}
/*
* z_compress()
*/
static int
z_compress(void *arg, mblk_t **mret, mblk_t *mp, int orig_len, int maxolen)
{
struct deflate_state *state = (struct deflate_state *)arg;
uchar_t *rptr, *rmax;
uchar_t *wptr;
int olen;
int wspace;
int r;
int flush;
mblk_t *m;
#if defined(lint) || defined(_lint)
uchar_t hdlcaddr, hdlcctrl;
#else
int hdlcaddr, hdlcctrl;
#endif
#define ADJRPTR() { \
if (rptr != NULL) { \
while (rptr >= rmax) { \
if ((mp = mp->b_cont) == NULL) { \
rptr = NULL; \
break; \
} \
rptr = mp->b_rptr; \
rmax = mp->b_wptr; \
} \
} \
}
#define GETBYTE(v) { \
if (rptr != NULL) { \
(v) = *rptr++; \
} \
}
/*
* Check that the protocol is one we handle. Pullup is *NOT*
* possible here.
*/
*mret = NULL;
rptr = mp->b_rptr;
rmax = mp->b_wptr;
ADJRPTR();
GETBYTE(hdlcaddr);
ADJRPTR();
GETBYTE(hdlcctrl);
ADJRPTR();
/*
* Per RFC 1979, the protocol field must be compressed using a
* PFC-like procedure. Also, all protocols between 0000-3FFF
* except the two compression protocols must be LZ compressed.
*/
if (rptr == NULL)
return (orig_len);
r = *rptr;
if (r == 0) {
rptr++;
ADJRPTR();
if (rptr == NULL || *rptr == PPP_COMP || *rptr == PPP_COMPFRAG)
return (orig_len);
} else {
if (r > 0x3F)
return (orig_len);
}
/*
* Allocate one mblk initially
*/
if (maxolen > orig_len) {
maxolen = orig_len;
}
if (maxolen <= PPP_HDRLEN + 2) {
wspace = 0;
m = NULL;
} else {
wspace = maxolen + state->hdrlen;
if (wspace > 4096) {
wspace = 4096;
}
m = allocb(wspace, BPRI_MED);
}
if (m != NULL) {
wspace = m->b_datap->db_lim - m->b_wptr;
*mret = m;
if (state->hdrlen + PPP_HDRLEN + 2 < wspace) {
m->b_rptr += state->hdrlen;
m->b_wptr = m->b_rptr;
wspace -= state->hdrlen;
}
wptr = m->b_wptr;
/*
* Copy over the PPP header and store the 2-byte
* sequence number
*/
wptr[0] = hdlcaddr;
wptr[1] = hdlcctrl;
wptr[2] = PPP_COMP >> 8;
wptr[3] = PPP_COMP;
wptr += PPP_HDRLEN;
wptr[0] = state->seqno >> 8;
wptr[1] = state->seqno;
wptr += 2;
#ifdef DEBUG
/*
* If testing output, just garbling the sequence here
* does the trick.
*/
if ((state->flags & DS_TESTOUT) && (state->seqno % 100) == 50)
wptr[-1] ^= 0xAA;
#endif
state->strm.next_out = wptr;
state->strm.avail_out = wspace - (PPP_HDRLEN + 2);
} else {
state->strm.next_out = NULL;
state->strm.avail_out = 1000000;
}
++state->seqno;
state->strm.next_in = rptr;
state->strm.avail_in = mp->b_wptr - rptr;
olen = 0;
for (;;) {
flush = (mp == NULL || mp->b_cont == NULL) ? Z_PACKET_FLUSH :
Z_NO_FLUSH;
r = deflate(&state->strm, flush);
if (r != Z_OK) {
cmn_err(CE_CONT,
"z_compress%d: deflate returned %d (%s)\n",
state->unit, r,
(state->strm.msg? state->strm.msg: ""));
break;
}
if (state->strm.avail_in == 0) {
if (mp != NULL)
mp = mp->b_cont;
if (mp == NULL) {
if (state->strm.avail_out != 0)
break; /* all done */
} else {
state->strm.next_in = mp->b_rptr;
state->strm.avail_in = mp->b_wptr - mp->b_rptr;
}
}
if (state->strm.avail_out == 0) {
if (m != NULL) {
m->b_wptr += wspace;
olen += wspace;
wspace = maxolen - olen;
if (wspace <= 0) {
wspace = 0;
m->b_cont = NULL;
} else {
if (wspace < 32) {
wspace = 32;
} else if (wspace > 4096) {
wspace = 4096;
}
m->b_cont = allocb(wspace, BPRI_MED);
}
m = m->b_cont;
if (m != NULL) {
state->strm.next_out = m->b_wptr;
wspace = m->b_datap->db_lim -
m->b_wptr;
state->strm.avail_out = wspace;
}
}
if (m == NULL) {
state->strm.next_out = NULL;
state->strm.avail_out = 1000000;
}
}
}
if (m != NULL) {
m->b_wptr += wspace - state->strm.avail_out;
olen += wspace - state->strm.avail_out;
}
/*
* See if we managed to reduce the size of the packet.
*/
if (olen < orig_len && m != NULL) {
state->stats.comp_bytes += olen;
state->stats.comp_packets++;
} else {
if (*mret != NULL) {
freemsg(*mret);
*mret = NULL;
}
state->stats.inc_bytes += orig_len;
state->stats.inc_packets++;
olen = orig_len;
}
state->stats.unc_bytes += orig_len;
state->stats.unc_packets++;
return (olen);
}
/*
* z_incomp()
*
* Incompressible data has arrived - add it to the history.
*/
static int
z_incomp(void *arg, mblk_t *mp)
{
struct deflate_state *state = (struct deflate_state *)arg;
uchar_t *rptr, *rmax;
int rlen;
int r;
/*
* Check that the protocol is one we handle. Pullup is *NOT*
* possible here.
*/
rptr = mp->b_rptr;
rmax = mp->b_wptr;
ADJRPTR();
rptr++; /* skip address */
ADJRPTR();
rptr++; /* skip control */
ADJRPTR();
/*
* Per RFC 1979, the protocol field must be compressed using a
* PFC-like procedure. Also, all protocols between 0000-3FFF
* except the two compression protocols must be LZ compressed.
*/
if (rptr == NULL)
return (0);
r = *rptr;
if (r == 0) {
rptr++;
ADJRPTR();
if (rptr == NULL || *rptr == PPP_COMP || *rptr == PPP_COMPFRAG)
return (0);
} else {
if (r > 0x3F)
return (0);
}
++state->seqno;
/*
* Iterate through the message blocks, adding the characters
* in them to the decompressor's history.
*/
rlen = mp->b_wptr - rptr;
state->strm.next_in = rptr;
state->strm.avail_in = rlen;
for (;;) {
r = inflateIncomp(&state->strm);
if (r != Z_OK) { /* gak! */
if (state->flags & DS_DEBUG) {
cmn_err(CE_CONT,
"z_incomp%d: inflateIncomp returned "
"%d (%s)\n", state->unit, r,
(state->strm.msg? state->strm.msg: ""));
}
return (-1);
}
mp = mp->b_cont;
if (mp == NULL) {
break;
}
state->strm.next_in = mp->b_rptr;
state->strm.avail_in = mp->b_wptr - mp->b_rptr;
rlen += state->strm.avail_in;
}
/*
* Update stats
*/
state->stats.inc_bytes += rlen;
state->stats.inc_packets++;
state->stats.unc_bytes += rlen;
state->stats.unc_packets++;
return (0);
#undef ADJRPTR
}
/*
* z_comp_stats()
*/
static void
z_comp_stats(void *arg, struct compstat *stats)
{
struct deflate_state *state = (struct deflate_state *)arg;
uint_t out;
*stats = state->stats;
stats->ratio = stats->unc_bytes;
out = stats->comp_bytes + stats->unc_bytes;
if (stats->ratio <= 0x7ffffff) {
stats->ratio <<= 8;
} else {
out >>= 8;
}
if (out != 0) {
stats->ratio /= out;
}
}
/*
* z_decomp_alloc()
*
* Allocate space for a decompressor.
*/
static void *
z_decomp_alloc(uchar_t *options, int opt_len)
{
struct deflate_state *state;
int w_size;
if (opt_len != CILEN_DEFLATE ||
(options[0] != CI_DEFLATE && options[0] != CI_DEFLATE_DRAFT) ||
options[1] != CILEN_DEFLATE ||
DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL ||
options[3] != DEFLATE_CHK_SEQUENCE) {
return (NULL);
}
w_size = DEFLATE_SIZE(options[2]);
/*
* Check <= minimum size to avoid unfixable zlib bug -- window size
* 256 (w_size 8) is not supported.
*/
if (w_size <= DEFLATE_MIN_SIZE || w_size > DEFLATE_MAX_SIZE) {
return (NULL);
}
state = (struct deflate_state *)kmem_zalloc(sizeof (*state), KM_SLEEP);
ASSERT(state != NULL);
state->strm.zalloc = (alloc_func)z_alloc;
state->strm.zfree = (free_func)z_free;
if (inflateInit2(&state->strm, -w_size) != Z_OK) {
kmem_free(state, sizeof (*state));
return (NULL);
}
state->w_size = w_size;
bzero(&state->stats, sizeof (state->stats));
return ((void *)state);
}
/*
* z_decomp_free()
*/
static void
z_decomp_free(void *arg)
{
struct deflate_state *state = (struct deflate_state *)arg;
(void) inflateEnd(&state->strm);
kmem_free(state, sizeof (*state));
}
/*
* z_decomp_init()
*/
static int
z_decomp_init(void *arg, uchar_t *options, int opt_len, int unit, int hdrlen,
int mru, int debug)
{
struct deflate_state *state = (struct deflate_state *)arg;
if (opt_len < CILEN_DEFLATE ||
(options[0] != CI_DEFLATE && options[0] != CI_DEFLATE_DRAFT) ||
options[1] != CILEN_DEFLATE ||
DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL ||
DEFLATE_SIZE(options[2]) != state->w_size ||
options[3] != DEFLATE_CHK_SEQUENCE) {
return (0);
}
state->seqno = 0;
state->unit = unit;
state->hdrlen = hdrlen;
if (debug)
state->flags |= DS_DEBUG;
else
state->flags &= ~DS_DEBUG;
state->mru = mru;
(void) inflateReset(&state->strm);
return (1);
}
/*
* z_decomp_reset()
*/
static void
z_decomp_reset(void *arg)
{
struct deflate_state *state = (struct deflate_state *)arg;
state->seqno = 0;
(void) inflateReset(&state->strm);
}
/*
* z_decompress()
*
* Decompress a Deflate-compressed packet.
*
* Because of patent problems, we return DECOMP_ERROR for errors
* found by inspecting the input data and for system problems, but
* DECOMP_FATALERROR for any errors which could possibly be said to
* be being detected "after" decompression. For DECOMP_ERROR,
* we can issue a CCP reset-request; for DECOMP_FATALERROR, we may be
* infringing a patent of Motorola's if we do, so we take CCP down
* instead.
*
* Given that the frame has the correct sequence number and a good FCS,
* errors such as invalid codes in the input most likely indicate a
* bug, so we return DECOMP_FATALERROR for them in order to turn off
* compression, even though they are detected by inspecting the input.
*/
static int
z_decompress(void *arg, mblk_t **mop)
{
struct deflate_state *state = (struct deflate_state *)arg;
mblk_t *mi = *mop, *mnext;
mblk_t *mo;
mblk_t *mo_head;
uchar_t *rptr, *rmax;
uchar_t *wptr;
int rlen;
int olen;
int ospace;
int seq;
int flush;
int r;
int decode_proto;
#if defined(lint) || defined(_lint)
uchar_t hdlcaddr, hdlcctrl;
#else
int hdlcaddr, hdlcctrl;
#endif
/* Note: spppcomp already did a pullup to fix the first buffer. */
*mop = NULL;
rptr = mi->b_rptr + PPP_HDRLEN;
rmax = mi->b_wptr;
if (rptr > rmax) {
if (state->flags & DS_DEBUG) {
cmn_err(CE_CONT, "z_decompress%d: bad buffer\n",
state->unit);
}
freemsg(mi);
return (DECOMP_ERROR);
}
hdlcaddr = rptr[-PPP_HDRLEN];
hdlcctrl = rptr[-PPP_HDRLEN+1];
/*
* Note that we free as we go. If we fail to decompress,
* there's nothing good that the caller can do.
*/
#define ADJRPTR() { \
if (rptr != NULL) { \
while (rptr >= rmax) { \
mnext = mi->b_cont; \
freeb(mi); \
if ((mi = mnext) == NULL) { \
rptr = NULL; \
break; \
} \
rptr = mi->b_rptr; \
rmax = mi->b_wptr; \
} \
} \
}
/*
* Check the sequence number
*/
ADJRPTR();
seq = rptr == NULL ? 0 : (*rptr++ << 8);
ADJRPTR();
if (rptr == NULL) {
if (state->flags & DS_DEBUG) {
cmn_err(CE_CONT, "z_decompress%d: bad buffer\n",
state->unit);
}
return (DECOMP_ERROR);
}
seq |= *rptr++;
#ifdef DEBUG
/*
* If testing input, just pretending the sequence is bad here
* does the trick.
*/
if ((state->flags & DS_TESTIN) && (state->seqno % 300) == 101)
seq ^= 0x55;
#endif
if (seq != state->seqno++) {
freemsg(mi);
if (state->flags & DS_DEBUG) {
cmn_err(CE_CONT,
"z_decompress%d: bad seq # %d, expected %d\n",
state->unit, seq, state->seqno - 1);
}
return (DECOMP_ERROR);
}
/*
* Allocate an output message block
*/
mo = allocb(DECOMP_CHUNK + state->hdrlen, BPRI_MED);
if (mo == NULL) {
freemsg(mi);
return (DECOMP_ERROR);
}
mo_head = mo;
mo->b_cont = NULL;
mo->b_rptr += state->hdrlen;
mo->b_wptr = wptr = mo->b_rptr;
ospace = DECOMP_CHUNK;
olen = 0;
/*
* Fill in the first part of the PPP header. The protocol field
* comes from the decompressed data.
*/
*wptr++ = hdlcaddr;
*wptr++ = hdlcctrl;
*wptr++ = 0;
/*
* Set up to call inflate. We set avail_out to 1 initially so we can
* look at the first byte of the output and decide whether we have
* a 1-byte or 2-byte protocol field.
*/
state->strm.next_in = rptr;
state->strm.avail_in = mi->b_wptr - rptr;
rlen = state->strm.avail_in + PPP_HDRLEN + DEFLATE_OVHD;
state->strm.next_out = wptr;
state->strm.avail_out = 1;
decode_proto = 1;
/*
* Call inflate, supplying more input or output as needed.
*/
for (;;) {
flush = (mi == NULL || mi->b_cont == NULL) ?
Z_PACKET_FLUSH : Z_NO_FLUSH;
r = inflate(&state->strm, flush);
if (r != Z_OK) {
if (state->flags & DS_DEBUG) {
cmn_err(CE_CONT,
"z_decompress%d: inflate returned %d "
"(%s)\n", state->unit, r,
(state->strm.msg? state->strm.msg: ""));
}
if (mi != NULL)
freemsg(mi);
freemsg(mo_head);
return (DECOMP_FATALERROR);
}
if (state->strm.avail_in == 0) {
if (mi != NULL) {
mnext = mi->b_cont;
freeb(mi);
mi = mnext;
}
if (mi == NULL) {
if (state->strm.avail_out != 0)
break; /* all done */
} else {
state->strm.next_in = mi->b_rptr;
state->strm.avail_in = mi->b_wptr - mi->b_rptr;
rlen += state->strm.avail_in;
}
}
if (state->strm.avail_out == 0) {
if (decode_proto) {
state->strm.avail_out = ospace - PPP_HDRLEN;
if ((wptr[0] & 1) == 0) {
/*
* 2-byte protocol field
*/
wptr[-1] = wptr[0];
--state->strm.next_out;
++state->strm.avail_out;
}
decode_proto = 0;
} else {
mo->b_wptr += ospace;
olen += ospace;
mo->b_cont = allocb(DECOMP_CHUNK, BPRI_MED);
mo = mo->b_cont;
if (mo == NULL) {
if (mi != NULL)
freemsg(mi);
freemsg(mo_head);
return (DECOMP_ERROR);
}
state->strm.next_out = mo->b_rptr;
state->strm.avail_out = ospace = DECOMP_CHUNK;
}
}
}
if (decode_proto) {
freemsg(mo_head);
return (DECOMP_ERROR);
}
mo->b_wptr += ospace - state->strm.avail_out;
olen += ospace - state->strm.avail_out;
if ((olen > state->mru + PPP_HDRLEN) && (state->flags & DS_DEBUG)) {
cmn_err(CE_CONT, "z_decompress%d: exceeded mru (%d > %d)\n",
state->unit, olen, state->mru + PPP_HDRLEN);
}
state->stats.unc_bytes += olen;
state->stats.unc_packets++;
state->stats.comp_bytes += rlen;
state->stats.comp_packets++;
*mop = mo_head;
return (DECOMP_OK);
}
/* ARGSUSED */
static int
z_set_effort(void *xarg, void *rarg, int effortlevel)
{
struct deflate_state *xstate = (struct deflate_state *)xarg;
#ifdef DEBUG
struct deflate_state *rstate = (struct deflate_state *)rarg;
#endif
int retv;
#ifdef DEBUG
if (effortlevel == 42 || effortlevel == 2112) {
/* corrupt received data. */
if (rstate != NULL) {
rstate->flags |= DS_TESTIN;
cmn_err(CE_CONT, "deflate: enabled input testing.");
}
if (effortlevel != 2112)
return (0);
}
if (effortlevel == 2001 || effortlevel == 2112) {
/* corrupt transmitted data. */
if (xstate != NULL) {
xstate->flags |= DS_TESTOUT;
cmn_err(CE_CONT, "deflate: enabled output testing.");
}
return (0);
}
#endif
if (effortlevel < -1 || effortlevel > 9)
return (EINVAL);
if (xstate == NULL)
return (0);
retv = deflateParams(&xstate->strm, effortlevel, Z_DEFAULT_STRATEGY);
return (retv == Z_OK ? 0 : EINVAL);
}
#endif /* DO_DEFLATE */