Home | History | Annotate | Download | only in spppcomp
      1 /*
      2  * deflate.c - interface the zlib procedures for Deflate compression
      3  * and decompression (as used by gzip) to the PPP code.
      4  *
      5  * This version is for use with STREAMS in Solaris 2
      6  *
      7  * Copyright (c) 2001 by Sun Microsystems, Inc.
      8  * All rights reserved.
      9  *
     10  * Copyright (c) 1994 The Australian National University.
     11  * All rights reserved.
     12  *
     13  * Permission to use, copy, modify, and distribute this software and its
     14  * documentation is hereby granted, provided that the above copyright
     15  * notice appears in all copies.  This software is provided without any
     16  * warranty, express or implied. The Australian National University
     17  * makes no representations about the suitability of this software for
     18  * any purpose.
     19  *
     20  * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
     21  * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
     22  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
     23  * THE AUSTRALIAN NATIONAL UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY
     24  * OF SUCH DAMAGE.
     25  *
     26  * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
     27  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
     28  * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
     29  * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
     30  * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
     31  * OR MODIFICATIONS.
     32  *
     33  * $Id: deflate.c,v 1.9 1999/01/19 23:58:35 paulus Exp $
     34  */
     35 
     36 #define	NO_DUMMY_DECL
     37 
     38 #include <sys/param.h>
     39 #include <sys/types.h>
     40 #include <sys/kmem.h>
     41 #include <sys/stream.h>
     42 #include <sys/cmn_err.h>
     43 #include <sys/ddi.h>
     44 #include <sys/sunddi.h>
     45 #include <sys/errno.h>
     46 #include <net/ppp_defs.h>
     47 
     48 /* Defined for platform-neutral include file */
     49 #define	PACKETPTR	mblk_t *
     50 #include <net/ppp-comp.h>
     51 #include "s_common.h"
     52 #include "zlib.h"
     53 
     54 #if DO_DEFLATE
     55 
     56 /*
     57  * State for a Deflate (de)compressor.
     58  */
     59 struct deflate_state {
     60 	int		seqno;
     61 	int		w_size;
     62 	int		unit;
     63 	int		hdrlen;
     64 	int		mru;
     65 	int		flags;
     66 	z_stream	strm;
     67 	struct compstat	stats;
     68 };
     69 
     70 #define	DEFLATE_OVHD	2		/* Deflate overhead/packet */
     71 
     72 #define	DS_DEBUG	0x0001
     73 #define	DS_TESTIN	0x0002
     74 #define	DS_TESTOUT	0x0004
     75 
     76 static void	*z_alloc(void *, uint_t items, uint_t size);
     77 static void	z_free(void *, void *ptr);
     78 static void	*z_comp_alloc(uchar_t *options, int opt_len);
     79 static void	*z_decomp_alloc(uchar_t *options, int opt_len);
     80 static void	z_comp_free(void *state);
     81 static void	z_decomp_free(void *state);
     82 static int	z_comp_init(void *state, uchar_t *options, int opt_len,
     83 			int unit, int hdrlen, int debug);
     84 static int	z_decomp_init(void *state, uchar_t *options, int opt_len,
     85 			int unit, int hdrlen, int mru, int debug);
     86 static int	z_compress(void *state, mblk_t **mret,
     87 			mblk_t *mp, int slen, int maxolen);
     88 static int	z_incomp(void *state, mblk_t *dmsg);
     89 static int	z_decompress(void *state, mblk_t **dmpp);
     90 static void	z_comp_reset(void *state);
     91 static void	z_decomp_reset(void *state);
     92 static void	z_comp_stats(void *state, struct compstat *stats);
     93 static int	z_set_effort(void *xstate, void *rstate, int effortlevel);
     94 
     95 /*
     96  * Procedures exported to ppp_comp.c.
     97  */
     98 struct compressor ppp_deflate = {
     99 	CI_DEFLATE,		/* compress_proto */
    100 	z_comp_alloc,		/* comp_alloc */
    101 	z_comp_free,		/* comp_free */
    102 	z_comp_init,		/* comp_init */
    103 	z_comp_reset,		/* comp_reset */
    104 	z_compress,		/* compress */
    105 	z_comp_stats,		/* comp_stat */
    106 	z_decomp_alloc,		/* decomp_alloc */
    107 	z_decomp_free,		/* decomp_free */
    108 	z_decomp_init,		/* decomp_init */
    109 	z_decomp_reset,		/* decomp_reset */
    110 	z_decompress,		/* decompress */
    111 	z_incomp,		/* incomp */
    112 	z_comp_stats,		/* decomp_stat */
    113 	z_set_effort,		/* set_effort */
    114 };
    115 
    116 struct compressor ppp_deflate_draft = {
    117 	CI_DEFLATE_DRAFT,	/* compress_proto */
    118 	z_comp_alloc,		/* comp_alloc */
    119 	z_comp_free,		/* comp_free */
    120 	z_comp_init,		/* comp_init */
    121 	z_comp_reset,		/* comp_reset */
    122 	z_compress,		/* compress */
    123 	z_comp_stats,		/* comp_stat */
    124 	z_decomp_alloc,		/* decomp_alloc */
    125 	z_decomp_free,		/* decomp_free */
    126 	z_decomp_init,		/* decomp_init */
    127 	z_decomp_reset,		/* decomp_reset */
    128 	z_decompress,		/* decompress */
    129 	z_incomp,		/* incomp */
    130 	z_comp_stats,		/* decomp_stat */
    131 	z_set_effort,		/* set_effort */
    132 };
    133 
    134 #define	DECOMP_CHUNK	512
    135 
    136 /*
    137  * Space allocation and freeing routines for use by zlib routines.
    138  */
    139 struct zchunk {
    140 	uint_t		size;
    141 	uint_t		guard;
    142 };
    143 
    144 #define	GUARD_MAGIC	0x77a6011a
    145 
    146 /*
    147  * z_alloc()
    148  */
    149 /* ARGSUSED */
    150 static void *
    151 z_alloc(void *notused, uint_t items, uint_t size)
    152 {
    153 	struct zchunk	*z;
    154 
    155 	size = items * size + sizeof (struct zchunk);
    156 
    157 	z = (struct zchunk *)kmem_alloc(size, KM_NOSLEEP);
    158 	if (z == NULL)
    159 		return (NULL);
    160 
    161 	z->size = size;
    162 	z->guard = GUARD_MAGIC;
    163 
    164 	return ((void *)(z + 1));
    165 }
    166 
    167 /*
    168  * z_free()
    169  */
    170 /* ARGSUSED */
    171 static void
    172 z_free(void *notused, void *ptr)
    173 {
    174 	struct zchunk	*z = ((struct zchunk *)ptr) - 1;
    175 
    176 	if (ptr == NULL)
    177 		return;
    178 
    179 	if (z->guard != GUARD_MAGIC) {
    180 		cmn_err(CE_CONT,
    181 		    "deflate: z_free of corrupted chunk at 0x%p (%x, %x)\n",
    182 		    (void *)z, z->size, z->guard);
    183 
    184 		return;
    185 	}
    186 
    187 	kmem_free(z, z->size);
    188 }
    189 
    190 /*
    191  * Allocate space for a compressor.
    192  */
    193 static void *
    194 z_comp_alloc(uchar_t *options, int opt_len)
    195 {
    196 	struct deflate_state	*state;
    197 	int			w_size;
    198 
    199 	if (opt_len != CILEN_DEFLATE ||
    200 		(options[0] != CI_DEFLATE && options[0] != CI_DEFLATE_DRAFT) ||
    201 		options[1] != CILEN_DEFLATE ||
    202 		DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL ||
    203 		options[3] != DEFLATE_CHK_SEQUENCE) {
    204 
    205 		return (NULL);
    206 	}
    207 
    208 	w_size = DEFLATE_SIZE(options[2]);
    209 	/*
    210 	 * Check <= minimum size to avoid unfixable zlib bug -- window size
    211 	 * 256 (w_size 8) is not supported.
    212 	 */
    213 	if (w_size <= DEFLATE_MIN_SIZE || w_size > DEFLATE_MAX_SIZE) {
    214 		return (NULL);
    215 	}
    216 
    217 	state = (struct deflate_state *)kmem_zalloc(sizeof (*state), KM_SLEEP);
    218 	ASSERT(state != NULL);
    219 
    220 	state->strm.zalloc = (alloc_func)z_alloc;
    221 	state->strm.zfree = (free_func)z_free;
    222 
    223 	if (deflateInit2(&state->strm, Z_DEFAULT_COMPRESSION,
    224 		DEFLATE_METHOD_VAL, -w_size, 8, Z_DEFAULT_STRATEGY) != Z_OK) {
    225 
    226 		kmem_free(state, sizeof (*state));
    227 
    228 		return (NULL);
    229 	}
    230 
    231 	state->w_size = w_size;
    232 
    233 	bzero(&state->stats, sizeof (state->stats));
    234 
    235 	return ((void *)state);
    236 }
    237 
    238 /*
    239  * z_comp_free()
    240  */
    241 static void
    242 z_comp_free(void *arg)
    243 {
    244 	struct deflate_state	*state = (struct deflate_state *)arg;
    245 
    246 	(void) deflateEnd(&state->strm);
    247 
    248 	kmem_free(state, sizeof (*state));
    249 }
    250 
    251 /*
    252  * z_comp_init()
    253  */
    254 static int
    255 z_comp_init(void *arg, uchar_t *options, int opt_len, int unit, int hdrlen,
    256 	int debug)
    257 {
    258 	struct deflate_state *state = (struct deflate_state *)arg;
    259 
    260 	if (opt_len < CILEN_DEFLATE ||
    261 		(options[0] != CI_DEFLATE && options[0] != CI_DEFLATE_DRAFT) ||
    262 		options[1] != CILEN_DEFLATE ||
    263 		DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL ||
    264 		DEFLATE_SIZE(options[2]) != state->w_size ||
    265 		options[3] != DEFLATE_CHK_SEQUENCE) {
    266 
    267 		return (0);
    268 	}
    269 
    270 	state->seqno = 0;
    271 	state->unit = unit;
    272 	state->hdrlen = hdrlen;
    273 	if (debug)
    274 		state->flags |= DS_DEBUG;
    275 	else
    276 		state->flags &= ~DS_DEBUG;
    277 
    278 	(void) deflateReset(&state->strm);
    279 
    280 	return (1);
    281 }
    282 
    283 /*
    284  * z_comp_reset()
    285  */
    286 static void
    287 z_comp_reset(void *arg)
    288 {
    289 	struct deflate_state	*state = (struct deflate_state *)arg;
    290 
    291 	state->seqno = 0;
    292 
    293 	(void) deflateReset(&state->strm);
    294 }
    295 
    296 /*
    297  * z_compress()
    298  */
    299 static int
    300 z_compress(void *arg, mblk_t **mret, mblk_t *mp, int orig_len, int maxolen)
    301 {
    302 	struct deflate_state	*state = (struct deflate_state *)arg;
    303 	uchar_t			*rptr, *rmax;
    304 	uchar_t			*wptr;
    305 	int			olen;
    306 	int			wspace;
    307 	int			r;
    308 	int			flush;
    309 	mblk_t			*m;
    310 #if defined(lint) || defined(_lint)
    311 	uchar_t			hdlcaddr, hdlcctrl;
    312 #else
    313 	int			hdlcaddr, hdlcctrl;
    314 #endif
    315 
    316 #define	ADJRPTR() {						\
    317 	if (rptr != NULL) {					\
    318 		while (rptr >= rmax) {				\
    319 			if ((mp = mp->b_cont) == NULL) {	\
    320 				rptr = NULL;			\
    321 				break;				\
    322 			}					\
    323 			rptr = mp->b_rptr;			\
    324 			rmax = mp->b_wptr;			\
    325 		}						\
    326 	}							\
    327 }
    328 
    329 #define	GETBYTE(v) {						\
    330 	if (rptr != NULL) {					\
    331 		(v) = *rptr++;					\
    332 	}							\
    333 }
    334 
    335 	/*
    336 	 * Check that the protocol is one we handle.  Pullup is *NOT*
    337 	 * possible here.
    338 	 */
    339 	*mret = NULL;
    340 	rptr = mp->b_rptr;
    341 	rmax = mp->b_wptr;
    342 	ADJRPTR();
    343 	GETBYTE(hdlcaddr);
    344 	ADJRPTR();
    345 	GETBYTE(hdlcctrl);
    346 	ADJRPTR();
    347 
    348 	/*
    349 	 * Per RFC 1979, the protocol field must be compressed using a
    350 	 * PFC-like procedure.  Also, all protocols between 0000-3FFF
    351 	 * except the two compression protocols must be LZ compressed.
    352 	 */
    353 	if (rptr == NULL)
    354 		return (orig_len);
    355 	r = *rptr;
    356 	if (r == 0) {
    357 		rptr++;
    358 		ADJRPTR();
    359 		if (rptr == NULL || *rptr == PPP_COMP || *rptr == PPP_COMPFRAG)
    360 			return (orig_len);
    361 	} else {
    362 		if (r > 0x3F)
    363 			return (orig_len);
    364 	}
    365 
    366 	/*
    367 	 * Allocate one mblk initially
    368 	 */
    369 	if (maxolen > orig_len) {
    370 		maxolen = orig_len;
    371 	}
    372 
    373 	if (maxolen <= PPP_HDRLEN + 2) {
    374 		wspace = 0;
    375 		m = NULL;
    376 	} else {
    377 		wspace = maxolen + state->hdrlen;
    378 		if (wspace > 4096) {
    379 			wspace = 4096;
    380 		}
    381 
    382 		m = allocb(wspace, BPRI_MED);
    383 	}
    384 
    385 	if (m != NULL) {
    386 
    387 		wspace = m->b_datap->db_lim - m->b_wptr;
    388 
    389 		*mret = m;
    390 
    391 		if (state->hdrlen + PPP_HDRLEN + 2 < wspace) {
    392 			m->b_rptr += state->hdrlen;
    393 			m->b_wptr = m->b_rptr;
    394 			wspace -= state->hdrlen;
    395 		}
    396 
    397 		wptr = m->b_wptr;
    398 
    399 		/*
    400 		 * Copy over the PPP header and store the 2-byte
    401 		 * sequence number
    402 		 */
    403 		wptr[0] = hdlcaddr;
    404 		wptr[1] = hdlcctrl;
    405 		wptr[2] = PPP_COMP >> 8;
    406 		wptr[3] = PPP_COMP;
    407 
    408 		wptr += PPP_HDRLEN;
    409 
    410 		wptr[0] = state->seqno >> 8;
    411 		wptr[1] = state->seqno;
    412 		wptr += 2;
    413 
    414 #ifdef DEBUG
    415 		/*
    416 		 * If testing output, just garbling the sequence here
    417 		 * does the trick.
    418 		 */
    419 		if ((state->flags & DS_TESTOUT) && (state->seqno % 100) == 50)
    420 			wptr[-1] ^= 0xAA;
    421 #endif
    422 
    423 		state->strm.next_out = wptr;
    424 		state->strm.avail_out = wspace - (PPP_HDRLEN + 2);
    425 	} else {
    426 		state->strm.next_out = NULL;
    427 		state->strm.avail_out = 1000000;
    428 	}
    429 
    430 	++state->seqno;
    431 
    432 	state->strm.next_in = rptr;
    433 	state->strm.avail_in = mp->b_wptr - rptr;
    434 
    435 	olen = 0;
    436 
    437 	for (;;) {
    438 		flush = (mp == NULL || mp->b_cont == NULL) ? Z_PACKET_FLUSH :
    439 		    Z_NO_FLUSH;
    440 		r = deflate(&state->strm, flush);
    441 
    442 		if (r != Z_OK) {
    443 			cmn_err(CE_CONT,
    444 			    "z_compress%d: deflate returned %d (%s)\n",
    445 			    state->unit, r,
    446 			    (state->strm.msg? state->strm.msg: ""));
    447 
    448 			break;
    449 		}
    450 
    451 		if (state->strm.avail_in == 0) {
    452 			if (mp != NULL)
    453 				mp = mp->b_cont;
    454 			if (mp == NULL) {
    455 				if (state->strm.avail_out != 0)
    456 					break;	/* all done */
    457 			} else {
    458 				state->strm.next_in = mp->b_rptr;
    459 				state->strm.avail_in = mp->b_wptr - mp->b_rptr;
    460 			}
    461 		}
    462 
    463 		if (state->strm.avail_out == 0) {
    464 			if (m != NULL) {
    465 				m->b_wptr += wspace;
    466 				olen += wspace;
    467 				wspace = maxolen - olen;
    468 
    469 				if (wspace <= 0) {
    470 					wspace = 0;
    471 					m->b_cont = NULL;
    472 				} else {
    473 					if (wspace < 32) {
    474 						wspace = 32;
    475 					} else if (wspace > 4096) {
    476 						wspace = 4096;
    477 					}
    478 
    479 					m->b_cont = allocb(wspace, BPRI_MED);
    480 				}
    481 
    482 				m = m->b_cont;
    483 
    484 				if (m != NULL) {
    485 					state->strm.next_out = m->b_wptr;
    486 					wspace = m->b_datap->db_lim -
    487 					    m->b_wptr;
    488 					state->strm.avail_out = wspace;
    489 				}
    490 			}
    491 
    492 			if (m == NULL) {
    493 				state->strm.next_out = NULL;
    494 				state->strm.avail_out = 1000000;
    495 			}
    496 		}
    497 	}
    498 
    499 	if (m != NULL) {
    500 		m->b_wptr += wspace - state->strm.avail_out;
    501 		olen += wspace - state->strm.avail_out;
    502 	}
    503 
    504 	/*
    505 	 * See if we managed to reduce the size of the packet.
    506 	 */
    507 	if (olen < orig_len && m != NULL) {
    508 		state->stats.comp_bytes += olen;
    509 		state->stats.comp_packets++;
    510 	} else {
    511 		if (*mret != NULL) {
    512 			freemsg(*mret);
    513 			*mret = NULL;
    514 		}
    515 
    516 		state->stats.inc_bytes += orig_len;
    517 		state->stats.inc_packets++;
    518 
    519 		olen = orig_len;
    520 	}
    521 
    522 	state->stats.unc_bytes += orig_len;
    523 	state->stats.unc_packets++;
    524 
    525 	return (olen);
    526 }
    527 
    528 /*
    529  * z_incomp()
    530  *
    531  * Incompressible data has arrived - add it to the history.
    532  */
    533 static int
    534 z_incomp(void *arg, mblk_t *mp)
    535 {
    536 	struct deflate_state	*state = (struct deflate_state *)arg;
    537 	uchar_t			*rptr, *rmax;
    538 	int			rlen;
    539 	int			r;
    540 
    541 	/*
    542 	 * Check that the protocol is one we handle.  Pullup is *NOT*
    543 	 * possible here.
    544 	 */
    545 	rptr = mp->b_rptr;
    546 	rmax = mp->b_wptr;
    547 	ADJRPTR();
    548 	rptr++;		/* skip address */
    549 	ADJRPTR();
    550 	rptr++;		/* skip control */
    551 	ADJRPTR();
    552 
    553 	/*
    554 	 * Per RFC 1979, the protocol field must be compressed using a
    555 	 * PFC-like procedure.  Also, all protocols between 0000-3FFF
    556 	 * except the two compression protocols must be LZ compressed.
    557 	 */
    558 	if (rptr == NULL)
    559 		return (0);
    560 	r = *rptr;
    561 	if (r == 0) {
    562 		rptr++;
    563 		ADJRPTR();
    564 		if (rptr == NULL || *rptr == PPP_COMP || *rptr == PPP_COMPFRAG)
    565 			return (0);
    566 	} else {
    567 		if (r > 0x3F)
    568 			return (0);
    569 	}
    570 
    571 	++state->seqno;
    572 
    573 	/*
    574 	 * Iterate through the message blocks, adding the characters
    575 	 * in them to the decompressor's history.
    576 	 */
    577 	rlen = mp->b_wptr - rptr;
    578 
    579 	state->strm.next_in = rptr;
    580 	state->strm.avail_in = rlen;
    581 
    582 	for (;;) {
    583 		r = inflateIncomp(&state->strm);
    584 
    585 		if (r != Z_OK) {	/* gak! */
    586 			if (state->flags & DS_DEBUG) {
    587 				cmn_err(CE_CONT,
    588 				    "z_incomp%d: inflateIncomp returned "
    589 				    "%d (%s)\n", state->unit, r,
    590 				    (state->strm.msg? state->strm.msg: ""));
    591 			}
    592 
    593 			return (-1);
    594 		}
    595 
    596 		mp = mp->b_cont;
    597 		if (mp == NULL) {
    598 			break;
    599 		}
    600 
    601 		state->strm.next_in = mp->b_rptr;
    602 		state->strm.avail_in = mp->b_wptr - mp->b_rptr;
    603 
    604 		rlen += state->strm.avail_in;
    605 	}
    606 
    607 	/*
    608 	 * Update stats
    609 	 */
    610 	state->stats.inc_bytes += rlen;
    611 	state->stats.inc_packets++;
    612 	state->stats.unc_bytes += rlen;
    613 	state->stats.unc_packets++;
    614 	return (0);
    615 #undef ADJRPTR
    616 }
    617 
    618 /*
    619  * z_comp_stats()
    620  */
    621 static void
    622 z_comp_stats(void *arg, struct compstat *stats)
    623 {
    624 	struct deflate_state	*state = (struct deflate_state *)arg;
    625 	uint_t			out;
    626 
    627 	*stats = state->stats;
    628 	stats->ratio = stats->unc_bytes;
    629 	out = stats->comp_bytes + stats->unc_bytes;
    630 
    631 	if (stats->ratio <= 0x7ffffff) {
    632 		stats->ratio <<= 8;
    633 	} else {
    634 		out >>= 8;
    635 	}
    636 
    637 	if (out != 0) {
    638 		stats->ratio /= out;
    639 	}
    640 }
    641 
    642 /*
    643  * z_decomp_alloc()
    644  *
    645  * Allocate space for a decompressor.
    646  */
    647 static void *
    648 z_decomp_alloc(uchar_t *options, int opt_len)
    649 {
    650 	struct deflate_state	*state;
    651 	int			w_size;
    652 
    653 	if (opt_len != CILEN_DEFLATE ||
    654 		(options[0] != CI_DEFLATE && options[0] != CI_DEFLATE_DRAFT) ||
    655 		options[1] != CILEN_DEFLATE ||
    656 		DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL ||
    657 		options[3] != DEFLATE_CHK_SEQUENCE) {
    658 
    659 		return (NULL);
    660 	}
    661 
    662 	w_size = DEFLATE_SIZE(options[2]);
    663 	/*
    664 	 * Check <= minimum size to avoid unfixable zlib bug -- window size
    665 	 * 256 (w_size 8) is not supported.
    666 	 */
    667 	if (w_size <= DEFLATE_MIN_SIZE || w_size > DEFLATE_MAX_SIZE) {
    668 		return (NULL);
    669 	}
    670 
    671 	state = (struct deflate_state *)kmem_zalloc(sizeof (*state), KM_SLEEP);
    672 	ASSERT(state != NULL);
    673 
    674 	state->strm.zalloc = (alloc_func)z_alloc;
    675 	state->strm.zfree = (free_func)z_free;
    676 
    677 	if (inflateInit2(&state->strm, -w_size) != Z_OK) {
    678 		kmem_free(state, sizeof (*state));
    679 		return (NULL);
    680 	}
    681 
    682 	state->w_size = w_size;
    683 
    684 	bzero(&state->stats, sizeof (state->stats));
    685 
    686 	return ((void *)state);
    687 }
    688 
    689 /*
    690  * z_decomp_free()
    691  */
    692 static void
    693 z_decomp_free(void *arg)
    694 {
    695 	struct deflate_state	*state = (struct deflate_state *)arg;
    696 
    697 	(void) inflateEnd(&state->strm);
    698 
    699 	kmem_free(state, sizeof (*state));
    700 }
    701 
    702 /*
    703  * z_decomp_init()
    704  */
    705 static int
    706 z_decomp_init(void *arg, uchar_t *options, int opt_len, int unit, int hdrlen,
    707 	int mru, int debug)
    708 {
    709 	struct deflate_state *state = (struct deflate_state *)arg;
    710 
    711 	if (opt_len < CILEN_DEFLATE ||
    712 		(options[0] != CI_DEFLATE && options[0] != CI_DEFLATE_DRAFT) ||
    713 		options[1] != CILEN_DEFLATE ||
    714 		DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL ||
    715 		DEFLATE_SIZE(options[2]) != state->w_size ||
    716 		options[3] != DEFLATE_CHK_SEQUENCE) {
    717 
    718 		return (0);
    719 	}
    720 
    721 	state->seqno = 0;
    722 	state->unit = unit;
    723 	state->hdrlen = hdrlen;
    724 	if (debug)
    725 		state->flags |= DS_DEBUG;
    726 	else
    727 		state->flags &= ~DS_DEBUG;
    728 	state->mru = mru;
    729 
    730 	(void) inflateReset(&state->strm);
    731 
    732 	return (1);
    733 }
    734 
    735 /*
    736  * z_decomp_reset()
    737  */
    738 static void
    739 z_decomp_reset(void *arg)
    740 {
    741 	struct deflate_state	*state = (struct deflate_state *)arg;
    742 
    743 	state->seqno = 0;
    744 
    745 	(void) inflateReset(&state->strm);
    746 }
    747 
    748 /*
    749  * z_decompress()
    750  *
    751  * Decompress a Deflate-compressed packet.
    752  *
    753  * Because of patent problems, we return DECOMP_ERROR for errors
    754  * found by inspecting the input data and for system problems, but
    755  * DECOMP_FATALERROR for any errors which could possibly be said to
    756  * be being detected "after" decompression.  For DECOMP_ERROR,
    757  * we can issue a CCP reset-request; for DECOMP_FATALERROR, we may be
    758  * infringing a patent of Motorola's if we do, so we take CCP down
    759  * instead.
    760  *
    761  * Given that the frame has the correct sequence number and a good FCS,
    762  * errors such as invalid codes in the input most likely indicate a
    763  * bug, so we return DECOMP_FATALERROR for them in order to turn off
    764  * compression, even though they are detected by inspecting the input.
    765  */
    766 static int
    767 z_decompress(void *arg, mblk_t **mop)
    768 {
    769 	struct deflate_state	*state = (struct deflate_state *)arg;
    770 	mblk_t			*mi = *mop, *mnext;
    771 	mblk_t			*mo;
    772 	mblk_t			*mo_head;
    773 	uchar_t			*rptr, *rmax;
    774 	uchar_t			*wptr;
    775 	int			rlen;
    776 	int			olen;
    777 	int			ospace;
    778 	int			seq;
    779 	int			flush;
    780 	int			r;
    781 	int			decode_proto;
    782 #if defined(lint) || defined(_lint)
    783 	uchar_t			hdlcaddr, hdlcctrl;
    784 #else
    785 	int			hdlcaddr, hdlcctrl;
    786 #endif
    787 
    788 	/* Note: spppcomp already did a pullup to fix the first buffer. */
    789 	*mop = NULL;
    790 	rptr = mi->b_rptr + PPP_HDRLEN;
    791 	rmax = mi->b_wptr;
    792 	if (rptr > rmax) {
    793 		if (state->flags & DS_DEBUG) {
    794 			cmn_err(CE_CONT, "z_decompress%d: bad buffer\n",
    795 			    state->unit);
    796 		}
    797 		freemsg(mi);
    798 		return (DECOMP_ERROR);
    799 	}
    800 
    801 	hdlcaddr = rptr[-PPP_HDRLEN];
    802 	hdlcctrl = rptr[-PPP_HDRLEN+1];
    803 
    804 	/*
    805 	 * Note that we free as we go.  If we fail to decompress,
    806 	 * there's nothing good that the caller can do.
    807 	 */
    808 #define	ADJRPTR() {						\
    809 	if (rptr != NULL) {					\
    810 		while (rptr >= rmax) {				\
    811 			mnext = mi->b_cont;			\
    812 			freeb(mi);				\
    813 			if ((mi = mnext) == NULL) {		\
    814 				rptr = NULL;			\
    815 				break;				\
    816 			}					\
    817 			rptr = mi->b_rptr;			\
    818 			rmax = mi->b_wptr;			\
    819 		}						\
    820 	}							\
    821 }
    822 
    823 	/*
    824 	 * Check the sequence number
    825 	 */
    826 	ADJRPTR();
    827 	seq = rptr == NULL ? 0 : (*rptr++ << 8);
    828 	ADJRPTR();
    829 	if (rptr == NULL) {
    830 		if (state->flags & DS_DEBUG) {
    831 			cmn_err(CE_CONT, "z_decompress%d: bad buffer\n",
    832 			    state->unit);
    833 		}
    834 		return (DECOMP_ERROR);
    835 	}
    836 
    837 	seq |= *rptr++;
    838 
    839 #ifdef DEBUG
    840 	/*
    841 	 * If testing input, just pretending the sequence is bad here
    842 	 * does the trick.
    843 	 */
    844 	if ((state->flags & DS_TESTIN) && (state->seqno % 300) == 101)
    845 		seq ^= 0x55;
    846 #endif
    847 	if (seq != state->seqno++) {
    848 		freemsg(mi);
    849 		if (state->flags & DS_DEBUG) {
    850 			cmn_err(CE_CONT,
    851 				"z_decompress%d: bad seq # %d, expected %d\n",
    852 				state->unit, seq, state->seqno - 1);
    853 		}
    854 		return (DECOMP_ERROR);
    855 	}
    856 
    857 	/*
    858 	 * Allocate an output message block
    859 	 */
    860 	mo = allocb(DECOMP_CHUNK + state->hdrlen, BPRI_MED);
    861 	if (mo == NULL) {
    862 		freemsg(mi);
    863 		return (DECOMP_ERROR);
    864 	}
    865 
    866 	mo_head = mo;
    867 	mo->b_cont = NULL;
    868 	mo->b_rptr += state->hdrlen;
    869 	mo->b_wptr = wptr = mo->b_rptr;
    870 
    871 	ospace = DECOMP_CHUNK;
    872 	olen = 0;
    873 
    874 	/*
    875 	 * Fill in the first part of the PPP header.  The protocol field
    876 	 * comes from the decompressed data.
    877 	 */
    878 	*wptr++ = hdlcaddr;
    879 	*wptr++ = hdlcctrl;
    880 	*wptr++ = 0;
    881 
    882 	/*
    883 	 * Set up to call inflate.  We set avail_out to 1 initially so we can
    884 	 * look at the first byte of the output and decide whether we have
    885 	 * a 1-byte or 2-byte protocol field.
    886 	 */
    887 	state->strm.next_in = rptr;
    888 	state->strm.avail_in = mi->b_wptr - rptr;
    889 
    890 	rlen = state->strm.avail_in + PPP_HDRLEN + DEFLATE_OVHD;
    891 
    892 	state->strm.next_out = wptr;
    893 	state->strm.avail_out = 1;
    894 
    895 	decode_proto = 1;
    896 
    897 	/*
    898 	 * Call inflate, supplying more input or output as needed.
    899 	 */
    900 	for (;;) {
    901 
    902 		flush = (mi == NULL || mi->b_cont == NULL) ?
    903 		    Z_PACKET_FLUSH : Z_NO_FLUSH;
    904 		r = inflate(&state->strm, flush);
    905 
    906 		if (r != Z_OK) {
    907 
    908 			if (state->flags & DS_DEBUG) {
    909 				cmn_err(CE_CONT,
    910 				    "z_decompress%d: inflate returned %d "
    911 				    "(%s)\n", state->unit, r,
    912 				    (state->strm.msg? state->strm.msg: ""));
    913 			}
    914 
    915 			if (mi != NULL)
    916 				freemsg(mi);
    917 			freemsg(mo_head);
    918 
    919 			return (DECOMP_FATALERROR);
    920 		}
    921 
    922 		if (state->strm.avail_in == 0) {
    923 			if (mi != NULL) {
    924 				mnext = mi->b_cont;
    925 				freeb(mi);
    926 				mi = mnext;
    927 			}
    928 			if (mi == NULL) {
    929 				if (state->strm.avail_out != 0)
    930 					break;	/* all done */
    931 			} else {
    932 				state->strm.next_in = mi->b_rptr;
    933 				state->strm.avail_in = mi->b_wptr - mi->b_rptr;
    934 
    935 				rlen += state->strm.avail_in;
    936 			}
    937 		}
    938 
    939 		if (state->strm.avail_out == 0) {
    940 			if (decode_proto) {
    941 				state->strm.avail_out = ospace - PPP_HDRLEN;
    942 
    943 				if ((wptr[0] & 1) == 0) {
    944 					/*
    945 					 * 2-byte protocol field
    946 					 */
    947 					wptr[-1] = wptr[0];
    948 
    949 					--state->strm.next_out;
    950 					++state->strm.avail_out;
    951 				}
    952 
    953 				decode_proto = 0;
    954 			} else {
    955 				mo->b_wptr += ospace;
    956 				olen += ospace;
    957 
    958 				mo->b_cont = allocb(DECOMP_CHUNK, BPRI_MED);
    959 
    960 				mo = mo->b_cont;
    961 				if (mo == NULL) {
    962 					if (mi != NULL)
    963 						freemsg(mi);
    964 					freemsg(mo_head);
    965 					return (DECOMP_ERROR);
    966 				}
    967 
    968 				state->strm.next_out = mo->b_rptr;
    969 				state->strm.avail_out = ospace = DECOMP_CHUNK;
    970 			}
    971 		}
    972 	}
    973 
    974 	if (decode_proto) {
    975 		freemsg(mo_head);
    976 		return (DECOMP_ERROR);
    977 	}
    978 
    979 	mo->b_wptr += ospace - state->strm.avail_out;
    980 	olen += ospace - state->strm.avail_out;
    981 
    982 	if ((olen > state->mru + PPP_HDRLEN) && (state->flags & DS_DEBUG)) {
    983 		cmn_err(CE_CONT, "z_decompress%d: exceeded mru (%d > %d)\n",
    984 		    state->unit, olen, state->mru + PPP_HDRLEN);
    985 	}
    986 
    987 	state->stats.unc_bytes += olen;
    988 	state->stats.unc_packets++;
    989 	state->stats.comp_bytes += rlen;
    990 	state->stats.comp_packets++;
    991 
    992 	*mop = mo_head;
    993 
    994 	return (DECOMP_OK);
    995 }
    996 
    997 /* ARGSUSED */
    998 static int
    999 z_set_effort(void *xarg, void *rarg, int effortlevel)
   1000 {
   1001 	struct deflate_state *xstate = (struct deflate_state *)xarg;
   1002 #ifdef DEBUG
   1003 	struct deflate_state *rstate = (struct deflate_state *)rarg;
   1004 #endif
   1005 	int retv;
   1006 
   1007 #ifdef DEBUG
   1008 	if (effortlevel == 42 || effortlevel == 2112) {
   1009 		/* corrupt received data. */
   1010 		if (rstate != NULL) {
   1011 			rstate->flags |= DS_TESTIN;
   1012 			cmn_err(CE_CONT, "deflate: enabled input testing.");
   1013 		}
   1014 		if (effortlevel != 2112)
   1015 			return (0);
   1016 	}
   1017 	if (effortlevel == 2001 || effortlevel == 2112) {
   1018 		/* corrupt transmitted data. */
   1019 		if (xstate != NULL) {
   1020 			xstate->flags |= DS_TESTOUT;
   1021 			cmn_err(CE_CONT, "deflate: enabled output testing.");
   1022 		}
   1023 		return (0);
   1024 	}
   1025 #endif
   1026 	if (effortlevel < -1 || effortlevel > 9)
   1027 		return (EINVAL);
   1028 	if (xstate == NULL)
   1029 		return (0);
   1030 	retv = deflateParams(&xstate->strm, effortlevel, Z_DEFAULT_STRATEGY);
   1031 	return (retv == Z_OK ? 0 : EINVAL);
   1032 }
   1033 
   1034 #endif /* DO_DEFLATE */
   1035