xref: /onnv-gate/usr/src/uts/common/io/ppp/spppcomp/deflate.c (revision 7767:905db6a104b6)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * deflate.c - interface the zlib procedures for Deflate compression
30Sstevel@tonic-gate  * and decompression (as used by gzip) to the PPP code.
40Sstevel@tonic-gate  *
50Sstevel@tonic-gate  * This version is for use with STREAMS in Solaris 2
60Sstevel@tonic-gate  *
70Sstevel@tonic-gate  * Copyright (c) 2001 by Sun Microsystems, Inc.
80Sstevel@tonic-gate  * All rights reserved.
90Sstevel@tonic-gate  *
100Sstevel@tonic-gate  * Copyright (c) 1994 The Australian National University.
110Sstevel@tonic-gate  * All rights reserved.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * Permission to use, copy, modify, and distribute this software and its
140Sstevel@tonic-gate  * documentation is hereby granted, provided that the above copyright
150Sstevel@tonic-gate  * notice appears in all copies.  This software is provided without any
160Sstevel@tonic-gate  * warranty, express or implied. The Australian National University
170Sstevel@tonic-gate  * makes no representations about the suitability of this software for
180Sstevel@tonic-gate  * any purpose.
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
210Sstevel@tonic-gate  * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
220Sstevel@tonic-gate  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
230Sstevel@tonic-gate  * THE AUSTRALIAN NATIONAL UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY
240Sstevel@tonic-gate  * OF SUCH DAMAGE.
250Sstevel@tonic-gate  *
260Sstevel@tonic-gate  * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
270Sstevel@tonic-gate  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
280Sstevel@tonic-gate  * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
290Sstevel@tonic-gate  * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
300Sstevel@tonic-gate  * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
310Sstevel@tonic-gate  * OR MODIFICATIONS.
320Sstevel@tonic-gate  *
330Sstevel@tonic-gate  * $Id: deflate.c,v 1.9 1999/01/19 23:58:35 paulus Exp $
340Sstevel@tonic-gate  */
350Sstevel@tonic-gate 
36*7767SJohn.Beck@Sun.COM #define	NO_DUMMY_DECL
370Sstevel@tonic-gate 
380Sstevel@tonic-gate #include <sys/param.h>
390Sstevel@tonic-gate #include <sys/types.h>
400Sstevel@tonic-gate #include <sys/kmem.h>
410Sstevel@tonic-gate #include <sys/stream.h>
420Sstevel@tonic-gate #include <sys/cmn_err.h>
430Sstevel@tonic-gate #include <sys/ddi.h>
440Sstevel@tonic-gate #include <sys/sunddi.h>
450Sstevel@tonic-gate #include <sys/errno.h>
460Sstevel@tonic-gate #include <net/ppp_defs.h>
470Sstevel@tonic-gate 
480Sstevel@tonic-gate /* Defined for platform-neutral include file */
490Sstevel@tonic-gate #define	PACKETPTR	mblk_t *
500Sstevel@tonic-gate #include <net/ppp-comp.h>
510Sstevel@tonic-gate #include "s_common.h"
520Sstevel@tonic-gate #include "zlib.h"
530Sstevel@tonic-gate 
540Sstevel@tonic-gate #if DO_DEFLATE
550Sstevel@tonic-gate 
560Sstevel@tonic-gate /*
570Sstevel@tonic-gate  * State for a Deflate (de)compressor.
580Sstevel@tonic-gate  */
590Sstevel@tonic-gate struct deflate_state {
600Sstevel@tonic-gate 	int		seqno;
610Sstevel@tonic-gate 	int		w_size;
620Sstevel@tonic-gate 	int		unit;
630Sstevel@tonic-gate 	int		hdrlen;
640Sstevel@tonic-gate 	int		mru;
650Sstevel@tonic-gate 	int		flags;
660Sstevel@tonic-gate 	z_stream	strm;
670Sstevel@tonic-gate 	struct compstat	stats;
680Sstevel@tonic-gate };
690Sstevel@tonic-gate 
700Sstevel@tonic-gate #define	DEFLATE_OVHD	2		/* Deflate overhead/packet */
710Sstevel@tonic-gate 
720Sstevel@tonic-gate #define	DS_DEBUG	0x0001
730Sstevel@tonic-gate #define	DS_TESTIN	0x0002
740Sstevel@tonic-gate #define	DS_TESTOUT	0x0004
750Sstevel@tonic-gate 
760Sstevel@tonic-gate static void	*z_alloc(void *, uint_t items, uint_t size);
770Sstevel@tonic-gate static void	z_free(void *, void *ptr);
780Sstevel@tonic-gate static void	*z_comp_alloc(uchar_t *options, int opt_len);
790Sstevel@tonic-gate static void	*z_decomp_alloc(uchar_t *options, int opt_len);
800Sstevel@tonic-gate static void	z_comp_free(void *state);
810Sstevel@tonic-gate static void	z_decomp_free(void *state);
820Sstevel@tonic-gate static int	z_comp_init(void *state, uchar_t *options, int opt_len,
830Sstevel@tonic-gate 			int unit, int hdrlen, int debug);
840Sstevel@tonic-gate static int	z_decomp_init(void *state, uchar_t *options, int opt_len,
850Sstevel@tonic-gate 			int unit, int hdrlen, int mru, int debug);
860Sstevel@tonic-gate static int	z_compress(void *state, mblk_t **mret,
870Sstevel@tonic-gate 			mblk_t *mp, int slen, int maxolen);
880Sstevel@tonic-gate static int	z_incomp(void *state, mblk_t *dmsg);
890Sstevel@tonic-gate static int	z_decompress(void *state, mblk_t **dmpp);
900Sstevel@tonic-gate static void	z_comp_reset(void *state);
910Sstevel@tonic-gate static void	z_decomp_reset(void *state);
920Sstevel@tonic-gate static void	z_comp_stats(void *state, struct compstat *stats);
930Sstevel@tonic-gate static int	z_set_effort(void *xstate, void *rstate, int effortlevel);
940Sstevel@tonic-gate 
950Sstevel@tonic-gate /*
960Sstevel@tonic-gate  * Procedures exported to ppp_comp.c.
970Sstevel@tonic-gate  */
980Sstevel@tonic-gate struct compressor ppp_deflate = {
990Sstevel@tonic-gate 	CI_DEFLATE,		/* compress_proto */
1000Sstevel@tonic-gate 	z_comp_alloc,		/* comp_alloc */
1010Sstevel@tonic-gate 	z_comp_free,		/* comp_free */
1020Sstevel@tonic-gate 	z_comp_init,		/* comp_init */
1030Sstevel@tonic-gate 	z_comp_reset,		/* comp_reset */
1040Sstevel@tonic-gate 	z_compress,		/* compress */
1050Sstevel@tonic-gate 	z_comp_stats,		/* comp_stat */
1060Sstevel@tonic-gate 	z_decomp_alloc,		/* decomp_alloc */
1070Sstevel@tonic-gate 	z_decomp_free,		/* decomp_free */
1080Sstevel@tonic-gate 	z_decomp_init,		/* decomp_init */
1090Sstevel@tonic-gate 	z_decomp_reset,		/* decomp_reset */
1100Sstevel@tonic-gate 	z_decompress,		/* decompress */
1110Sstevel@tonic-gate 	z_incomp,		/* incomp */
1120Sstevel@tonic-gate 	z_comp_stats,		/* decomp_stat */
1130Sstevel@tonic-gate 	z_set_effort,		/* set_effort */
1140Sstevel@tonic-gate };
1150Sstevel@tonic-gate 
1160Sstevel@tonic-gate struct compressor ppp_deflate_draft = {
1170Sstevel@tonic-gate 	CI_DEFLATE_DRAFT,	/* compress_proto */
1180Sstevel@tonic-gate 	z_comp_alloc,		/* comp_alloc */
1190Sstevel@tonic-gate 	z_comp_free,		/* comp_free */
1200Sstevel@tonic-gate 	z_comp_init,		/* comp_init */
1210Sstevel@tonic-gate 	z_comp_reset,		/* comp_reset */
1220Sstevel@tonic-gate 	z_compress,		/* compress */
1230Sstevel@tonic-gate 	z_comp_stats,		/* comp_stat */
1240Sstevel@tonic-gate 	z_decomp_alloc,		/* decomp_alloc */
1250Sstevel@tonic-gate 	z_decomp_free,		/* decomp_free */
1260Sstevel@tonic-gate 	z_decomp_init,		/* decomp_init */
1270Sstevel@tonic-gate 	z_decomp_reset,		/* decomp_reset */
1280Sstevel@tonic-gate 	z_decompress,		/* decompress */
1290Sstevel@tonic-gate 	z_incomp,		/* incomp */
1300Sstevel@tonic-gate 	z_comp_stats,		/* decomp_stat */
1310Sstevel@tonic-gate 	z_set_effort,		/* set_effort */
1320Sstevel@tonic-gate };
1330Sstevel@tonic-gate 
1340Sstevel@tonic-gate #define	DECOMP_CHUNK	512
1350Sstevel@tonic-gate 
1360Sstevel@tonic-gate /*
1370Sstevel@tonic-gate  * Space allocation and freeing routines for use by zlib routines.
1380Sstevel@tonic-gate  */
1390Sstevel@tonic-gate struct zchunk {
1400Sstevel@tonic-gate 	uint_t		size;
1410Sstevel@tonic-gate 	uint_t		guard;
1420Sstevel@tonic-gate };
1430Sstevel@tonic-gate 
1440Sstevel@tonic-gate #define	GUARD_MAGIC	0x77a6011a
1450Sstevel@tonic-gate 
1460Sstevel@tonic-gate /*
1470Sstevel@tonic-gate  * z_alloc()
1480Sstevel@tonic-gate  */
1490Sstevel@tonic-gate /* ARGSUSED */
1500Sstevel@tonic-gate static void *
z_alloc(void * notused,uint_t items,uint_t size)1510Sstevel@tonic-gate z_alloc(void *notused, uint_t items, uint_t size)
1520Sstevel@tonic-gate {
1530Sstevel@tonic-gate 	struct zchunk	*z;
1540Sstevel@tonic-gate 
1550Sstevel@tonic-gate 	size = items * size + sizeof (struct zchunk);
1560Sstevel@tonic-gate 
1570Sstevel@tonic-gate 	z = (struct zchunk *)kmem_alloc(size, KM_NOSLEEP);
1580Sstevel@tonic-gate 	if (z == NULL)
1590Sstevel@tonic-gate 		return (NULL);
1600Sstevel@tonic-gate 
1610Sstevel@tonic-gate 	z->size = size;
1620Sstevel@tonic-gate 	z->guard = GUARD_MAGIC;
1630Sstevel@tonic-gate 
1640Sstevel@tonic-gate 	return ((void *)(z + 1));
1650Sstevel@tonic-gate }
1660Sstevel@tonic-gate 
1670Sstevel@tonic-gate /*
1680Sstevel@tonic-gate  * z_free()
1690Sstevel@tonic-gate  */
1700Sstevel@tonic-gate /* ARGSUSED */
1710Sstevel@tonic-gate static void
z_free(void * notused,void * ptr)1720Sstevel@tonic-gate z_free(void *notused, void *ptr)
1730Sstevel@tonic-gate {
1740Sstevel@tonic-gate 	struct zchunk	*z = ((struct zchunk *)ptr) - 1;
1750Sstevel@tonic-gate 
1760Sstevel@tonic-gate 	if (ptr == NULL)
1770Sstevel@tonic-gate 		return;
1780Sstevel@tonic-gate 
1790Sstevel@tonic-gate 	if (z->guard != GUARD_MAGIC) {
1800Sstevel@tonic-gate 		cmn_err(CE_CONT,
1810Sstevel@tonic-gate 		    "deflate: z_free of corrupted chunk at 0x%p (%x, %x)\n",
1820Sstevel@tonic-gate 		    (void *)z, z->size, z->guard);
1830Sstevel@tonic-gate 
1840Sstevel@tonic-gate 		return;
1850Sstevel@tonic-gate 	}
1860Sstevel@tonic-gate 
1870Sstevel@tonic-gate 	kmem_free(z, z->size);
1880Sstevel@tonic-gate }
1890Sstevel@tonic-gate 
1900Sstevel@tonic-gate /*
1910Sstevel@tonic-gate  * Allocate space for a compressor.
1920Sstevel@tonic-gate  */
1930Sstevel@tonic-gate static void *
z_comp_alloc(uchar_t * options,int opt_len)1940Sstevel@tonic-gate z_comp_alloc(uchar_t *options, int opt_len)
1950Sstevel@tonic-gate {
1960Sstevel@tonic-gate 	struct deflate_state	*state;
1970Sstevel@tonic-gate 	int			w_size;
1980Sstevel@tonic-gate 
1990Sstevel@tonic-gate 	if (opt_len != CILEN_DEFLATE ||
2000Sstevel@tonic-gate 		(options[0] != CI_DEFLATE && options[0] != CI_DEFLATE_DRAFT) ||
2010Sstevel@tonic-gate 		options[1] != CILEN_DEFLATE ||
2020Sstevel@tonic-gate 		DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL ||
2030Sstevel@tonic-gate 		options[3] != DEFLATE_CHK_SEQUENCE) {
2040Sstevel@tonic-gate 
2050Sstevel@tonic-gate 		return (NULL);
2060Sstevel@tonic-gate 	}
2070Sstevel@tonic-gate 
2080Sstevel@tonic-gate 	w_size = DEFLATE_SIZE(options[2]);
2090Sstevel@tonic-gate 	/*
2100Sstevel@tonic-gate 	 * Check <= minimum size to avoid unfixable zlib bug -- window size
2110Sstevel@tonic-gate 	 * 256 (w_size 8) is not supported.
2120Sstevel@tonic-gate 	 */
2130Sstevel@tonic-gate 	if (w_size <= DEFLATE_MIN_SIZE || w_size > DEFLATE_MAX_SIZE) {
2140Sstevel@tonic-gate 		return (NULL);
2150Sstevel@tonic-gate 	}
2160Sstevel@tonic-gate 
2170Sstevel@tonic-gate 	state = (struct deflate_state *)kmem_zalloc(sizeof (*state), KM_SLEEP);
2180Sstevel@tonic-gate 	ASSERT(state != NULL);
2190Sstevel@tonic-gate 
2200Sstevel@tonic-gate 	state->strm.zalloc = (alloc_func)z_alloc;
2210Sstevel@tonic-gate 	state->strm.zfree = (free_func)z_free;
2220Sstevel@tonic-gate 
2230Sstevel@tonic-gate 	if (deflateInit2(&state->strm, Z_DEFAULT_COMPRESSION,
2240Sstevel@tonic-gate 		DEFLATE_METHOD_VAL, -w_size, 8, Z_DEFAULT_STRATEGY) != Z_OK) {
2250Sstevel@tonic-gate 
2260Sstevel@tonic-gate 		kmem_free(state, sizeof (*state));
2270Sstevel@tonic-gate 
2280Sstevel@tonic-gate 		return (NULL);
2290Sstevel@tonic-gate 	}
2300Sstevel@tonic-gate 
2310Sstevel@tonic-gate 	state->w_size = w_size;
2320Sstevel@tonic-gate 
2330Sstevel@tonic-gate 	bzero(&state->stats, sizeof (state->stats));
2340Sstevel@tonic-gate 
2350Sstevel@tonic-gate 	return ((void *)state);
2360Sstevel@tonic-gate }
2370Sstevel@tonic-gate 
2380Sstevel@tonic-gate /*
2390Sstevel@tonic-gate  * z_comp_free()
2400Sstevel@tonic-gate  */
2410Sstevel@tonic-gate static void
z_comp_free(void * arg)2420Sstevel@tonic-gate z_comp_free(void *arg)
2430Sstevel@tonic-gate {
2440Sstevel@tonic-gate 	struct deflate_state	*state = (struct deflate_state *)arg;
2450Sstevel@tonic-gate 
2460Sstevel@tonic-gate 	(void) deflateEnd(&state->strm);
2470Sstevel@tonic-gate 
2480Sstevel@tonic-gate 	kmem_free(state, sizeof (*state));
2490Sstevel@tonic-gate }
2500Sstevel@tonic-gate 
2510Sstevel@tonic-gate /*
2520Sstevel@tonic-gate  * z_comp_init()
2530Sstevel@tonic-gate  */
2540Sstevel@tonic-gate static int
z_comp_init(void * arg,uchar_t * options,int opt_len,int unit,int hdrlen,int debug)2550Sstevel@tonic-gate z_comp_init(void *arg, uchar_t *options, int opt_len, int unit, int hdrlen,
2560Sstevel@tonic-gate 	int debug)
2570Sstevel@tonic-gate {
2580Sstevel@tonic-gate 	struct deflate_state *state = (struct deflate_state *)arg;
2590Sstevel@tonic-gate 
2600Sstevel@tonic-gate 	if (opt_len < CILEN_DEFLATE ||
2610Sstevel@tonic-gate 		(options[0] != CI_DEFLATE && options[0] != CI_DEFLATE_DRAFT) ||
2620Sstevel@tonic-gate 		options[1] != CILEN_DEFLATE ||
2630Sstevel@tonic-gate 		DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL ||
2640Sstevel@tonic-gate 		DEFLATE_SIZE(options[2]) != state->w_size ||
2650Sstevel@tonic-gate 		options[3] != DEFLATE_CHK_SEQUENCE) {
2660Sstevel@tonic-gate 
2670Sstevel@tonic-gate 		return (0);
2680Sstevel@tonic-gate 	}
2690Sstevel@tonic-gate 
2700Sstevel@tonic-gate 	state->seqno = 0;
2710Sstevel@tonic-gate 	state->unit = unit;
2720Sstevel@tonic-gate 	state->hdrlen = hdrlen;
2730Sstevel@tonic-gate 	if (debug)
2740Sstevel@tonic-gate 		state->flags |= DS_DEBUG;
2750Sstevel@tonic-gate 	else
2760Sstevel@tonic-gate 		state->flags &= ~DS_DEBUG;
2770Sstevel@tonic-gate 
2780Sstevel@tonic-gate 	(void) deflateReset(&state->strm);
2790Sstevel@tonic-gate 
2800Sstevel@tonic-gate 	return (1);
2810Sstevel@tonic-gate }
2820Sstevel@tonic-gate 
2830Sstevel@tonic-gate /*
2840Sstevel@tonic-gate  * z_comp_reset()
2850Sstevel@tonic-gate  */
2860Sstevel@tonic-gate static void
z_comp_reset(void * arg)2870Sstevel@tonic-gate z_comp_reset(void *arg)
2880Sstevel@tonic-gate {
2890Sstevel@tonic-gate 	struct deflate_state	*state = (struct deflate_state *)arg;
2900Sstevel@tonic-gate 
2910Sstevel@tonic-gate 	state->seqno = 0;
2920Sstevel@tonic-gate 
2930Sstevel@tonic-gate 	(void) deflateReset(&state->strm);
2940Sstevel@tonic-gate }
2950Sstevel@tonic-gate 
2960Sstevel@tonic-gate /*
2970Sstevel@tonic-gate  * z_compress()
2980Sstevel@tonic-gate  */
2990Sstevel@tonic-gate static int
z_compress(void * arg,mblk_t ** mret,mblk_t * mp,int orig_len,int maxolen)3000Sstevel@tonic-gate z_compress(void *arg, mblk_t **mret, mblk_t *mp, int orig_len, int maxolen)
3010Sstevel@tonic-gate {
3020Sstevel@tonic-gate 	struct deflate_state	*state = (struct deflate_state *)arg;
3030Sstevel@tonic-gate 	uchar_t			*rptr, *rmax;
3040Sstevel@tonic-gate 	uchar_t			*wptr;
3050Sstevel@tonic-gate 	int			olen;
3060Sstevel@tonic-gate 	int			wspace;
3070Sstevel@tonic-gate 	int			r;
3080Sstevel@tonic-gate 	int			flush;
3090Sstevel@tonic-gate 	mblk_t			*m;
3100Sstevel@tonic-gate #if defined(lint) || defined(_lint)
3110Sstevel@tonic-gate 	uchar_t			hdlcaddr, hdlcctrl;
3120Sstevel@tonic-gate #else
3130Sstevel@tonic-gate 	int			hdlcaddr, hdlcctrl;
3140Sstevel@tonic-gate #endif
3150Sstevel@tonic-gate 
3160Sstevel@tonic-gate #define	ADJRPTR() {						\
3170Sstevel@tonic-gate 	if (rptr != NULL) {					\
3180Sstevel@tonic-gate 		while (rptr >= rmax) {				\
3190Sstevel@tonic-gate 			if ((mp = mp->b_cont) == NULL) {	\
3200Sstevel@tonic-gate 				rptr = NULL;			\
3210Sstevel@tonic-gate 				break;				\
3220Sstevel@tonic-gate 			}					\
3230Sstevel@tonic-gate 			rptr = mp->b_rptr;			\
3240Sstevel@tonic-gate 			rmax = mp->b_wptr;			\
3250Sstevel@tonic-gate 		}						\
3260Sstevel@tonic-gate 	}							\
3270Sstevel@tonic-gate }
3280Sstevel@tonic-gate 
3290Sstevel@tonic-gate #define	GETBYTE(v) {						\
3300Sstevel@tonic-gate 	if (rptr != NULL) {					\
3310Sstevel@tonic-gate 		(v) = *rptr++;					\
3320Sstevel@tonic-gate 	}							\
3330Sstevel@tonic-gate }
3340Sstevel@tonic-gate 
3350Sstevel@tonic-gate 	/*
3360Sstevel@tonic-gate 	 * Check that the protocol is one we handle.  Pullup is *NOT*
3370Sstevel@tonic-gate 	 * possible here.
3380Sstevel@tonic-gate 	 */
3390Sstevel@tonic-gate 	*mret = NULL;
3400Sstevel@tonic-gate 	rptr = mp->b_rptr;
3410Sstevel@tonic-gate 	rmax = mp->b_wptr;
3420Sstevel@tonic-gate 	ADJRPTR();
3430Sstevel@tonic-gate 	GETBYTE(hdlcaddr);
3440Sstevel@tonic-gate 	ADJRPTR();
3450Sstevel@tonic-gate 	GETBYTE(hdlcctrl);
3460Sstevel@tonic-gate 	ADJRPTR();
3470Sstevel@tonic-gate 
3480Sstevel@tonic-gate 	/*
3490Sstevel@tonic-gate 	 * Per RFC 1979, the protocol field must be compressed using a
3500Sstevel@tonic-gate 	 * PFC-like procedure.  Also, all protocols between 0000-3FFF
3510Sstevel@tonic-gate 	 * except the two compression protocols must be LZ compressed.
3520Sstevel@tonic-gate 	 */
3530Sstevel@tonic-gate 	if (rptr == NULL)
3540Sstevel@tonic-gate 		return (orig_len);
3550Sstevel@tonic-gate 	r = *rptr;
3560Sstevel@tonic-gate 	if (r == 0) {
3570Sstevel@tonic-gate 		rptr++;
3580Sstevel@tonic-gate 		ADJRPTR();
3590Sstevel@tonic-gate 		if (rptr == NULL || *rptr == PPP_COMP || *rptr == PPP_COMPFRAG)
3600Sstevel@tonic-gate 			return (orig_len);
3610Sstevel@tonic-gate 	} else {
3620Sstevel@tonic-gate 		if (r > 0x3F)
3630Sstevel@tonic-gate 			return (orig_len);
3640Sstevel@tonic-gate 	}
3650Sstevel@tonic-gate 
3660Sstevel@tonic-gate 	/*
3670Sstevel@tonic-gate 	 * Allocate one mblk initially
3680Sstevel@tonic-gate 	 */
3690Sstevel@tonic-gate 	if (maxolen > orig_len) {
3700Sstevel@tonic-gate 		maxolen = orig_len;
3710Sstevel@tonic-gate 	}
3720Sstevel@tonic-gate 
3730Sstevel@tonic-gate 	if (maxolen <= PPP_HDRLEN + 2) {
3740Sstevel@tonic-gate 		wspace = 0;
3750Sstevel@tonic-gate 		m = NULL;
3760Sstevel@tonic-gate 	} else {
3770Sstevel@tonic-gate 		wspace = maxolen + state->hdrlen;
3780Sstevel@tonic-gate 		if (wspace > 4096) {
3790Sstevel@tonic-gate 			wspace = 4096;
3800Sstevel@tonic-gate 		}
3810Sstevel@tonic-gate 
3820Sstevel@tonic-gate 		m = allocb(wspace, BPRI_MED);
3830Sstevel@tonic-gate 	}
3840Sstevel@tonic-gate 
3850Sstevel@tonic-gate 	if (m != NULL) {
3860Sstevel@tonic-gate 
3870Sstevel@tonic-gate 		wspace = m->b_datap->db_lim - m->b_wptr;
3880Sstevel@tonic-gate 
3890Sstevel@tonic-gate 		*mret = m;
3900Sstevel@tonic-gate 
3910Sstevel@tonic-gate 		if (state->hdrlen + PPP_HDRLEN + 2 < wspace) {
3920Sstevel@tonic-gate 			m->b_rptr += state->hdrlen;
3930Sstevel@tonic-gate 			m->b_wptr = m->b_rptr;
3940Sstevel@tonic-gate 			wspace -= state->hdrlen;
3950Sstevel@tonic-gate 		}
3960Sstevel@tonic-gate 
3970Sstevel@tonic-gate 		wptr = m->b_wptr;
3980Sstevel@tonic-gate 
3990Sstevel@tonic-gate 		/*
4000Sstevel@tonic-gate 		 * Copy over the PPP header and store the 2-byte
4010Sstevel@tonic-gate 		 * sequence number
4020Sstevel@tonic-gate 		 */
4030Sstevel@tonic-gate 		wptr[0] = hdlcaddr;
4040Sstevel@tonic-gate 		wptr[1] = hdlcctrl;
4050Sstevel@tonic-gate 		wptr[2] = PPP_COMP >> 8;
4060Sstevel@tonic-gate 		wptr[3] = PPP_COMP;
4070Sstevel@tonic-gate 
4080Sstevel@tonic-gate 		wptr += PPP_HDRLEN;
4090Sstevel@tonic-gate 
4100Sstevel@tonic-gate 		wptr[0] = state->seqno >> 8;
4110Sstevel@tonic-gate 		wptr[1] = state->seqno;
4120Sstevel@tonic-gate 		wptr += 2;
4130Sstevel@tonic-gate 
4140Sstevel@tonic-gate #ifdef DEBUG
4150Sstevel@tonic-gate 		/*
4160Sstevel@tonic-gate 		 * If testing output, just garbling the sequence here
4170Sstevel@tonic-gate 		 * does the trick.
4180Sstevel@tonic-gate 		 */
4190Sstevel@tonic-gate 		if ((state->flags & DS_TESTOUT) && (state->seqno % 100) == 50)
4200Sstevel@tonic-gate 			wptr[-1] ^= 0xAA;
4210Sstevel@tonic-gate #endif
4220Sstevel@tonic-gate 
4230Sstevel@tonic-gate 		state->strm.next_out = wptr;
4240Sstevel@tonic-gate 		state->strm.avail_out = wspace - (PPP_HDRLEN + 2);
4250Sstevel@tonic-gate 	} else {
4260Sstevel@tonic-gate 		state->strm.next_out = NULL;
4270Sstevel@tonic-gate 		state->strm.avail_out = 1000000;
4280Sstevel@tonic-gate 	}
4290Sstevel@tonic-gate 
4300Sstevel@tonic-gate 	++state->seqno;
4310Sstevel@tonic-gate 
4320Sstevel@tonic-gate 	state->strm.next_in = rptr;
4330Sstevel@tonic-gate 	state->strm.avail_in = mp->b_wptr - rptr;
4340Sstevel@tonic-gate 
4350Sstevel@tonic-gate 	olen = 0;
4360Sstevel@tonic-gate 
4370Sstevel@tonic-gate 	for (;;) {
4380Sstevel@tonic-gate 		flush = (mp == NULL || mp->b_cont == NULL) ? Z_PACKET_FLUSH :
4390Sstevel@tonic-gate 		    Z_NO_FLUSH;
4400Sstevel@tonic-gate 		r = deflate(&state->strm, flush);
4410Sstevel@tonic-gate 
4420Sstevel@tonic-gate 		if (r != Z_OK) {
4430Sstevel@tonic-gate 			cmn_err(CE_CONT,
4440Sstevel@tonic-gate 			    "z_compress%d: deflate returned %d (%s)\n",
4450Sstevel@tonic-gate 			    state->unit, r,
4460Sstevel@tonic-gate 			    (state->strm.msg? state->strm.msg: ""));
4470Sstevel@tonic-gate 
4480Sstevel@tonic-gate 			break;
4490Sstevel@tonic-gate 		}
4500Sstevel@tonic-gate 
4510Sstevel@tonic-gate 		if (state->strm.avail_in == 0) {
4520Sstevel@tonic-gate 			if (mp != NULL)
4530Sstevel@tonic-gate 				mp = mp->b_cont;
4540Sstevel@tonic-gate 			if (mp == NULL) {
4550Sstevel@tonic-gate 				if (state->strm.avail_out != 0)
4560Sstevel@tonic-gate 					break;	/* all done */
4570Sstevel@tonic-gate 			} else {
4580Sstevel@tonic-gate 				state->strm.next_in = mp->b_rptr;
4590Sstevel@tonic-gate 				state->strm.avail_in = mp->b_wptr - mp->b_rptr;
4600Sstevel@tonic-gate 			}
4610Sstevel@tonic-gate 		}
4620Sstevel@tonic-gate 
4630Sstevel@tonic-gate 		if (state->strm.avail_out == 0) {
4640Sstevel@tonic-gate 			if (m != NULL) {
4650Sstevel@tonic-gate 				m->b_wptr += wspace;
4660Sstevel@tonic-gate 				olen += wspace;
4670Sstevel@tonic-gate 				wspace = maxolen - olen;
4680Sstevel@tonic-gate 
4690Sstevel@tonic-gate 				if (wspace <= 0) {
4700Sstevel@tonic-gate 					wspace = 0;
4710Sstevel@tonic-gate 					m->b_cont = NULL;
4720Sstevel@tonic-gate 				} else {
4730Sstevel@tonic-gate 					if (wspace < 32) {
4740Sstevel@tonic-gate 						wspace = 32;
4750Sstevel@tonic-gate 					} else if (wspace > 4096) {
4760Sstevel@tonic-gate 						wspace = 4096;
4770Sstevel@tonic-gate 					}
4780Sstevel@tonic-gate 
4790Sstevel@tonic-gate 					m->b_cont = allocb(wspace, BPRI_MED);
4800Sstevel@tonic-gate 				}
4810Sstevel@tonic-gate 
4820Sstevel@tonic-gate 				m = m->b_cont;
4830Sstevel@tonic-gate 
4840Sstevel@tonic-gate 				if (m != NULL) {
4850Sstevel@tonic-gate 					state->strm.next_out = m->b_wptr;
4860Sstevel@tonic-gate 					wspace = m->b_datap->db_lim -
4870Sstevel@tonic-gate 					    m->b_wptr;
4880Sstevel@tonic-gate 					state->strm.avail_out = wspace;
4890Sstevel@tonic-gate 				}
4900Sstevel@tonic-gate 			}
4910Sstevel@tonic-gate 
4920Sstevel@tonic-gate 			if (m == NULL) {
4930Sstevel@tonic-gate 				state->strm.next_out = NULL;
4940Sstevel@tonic-gate 				state->strm.avail_out = 1000000;
4950Sstevel@tonic-gate 			}
4960Sstevel@tonic-gate 		}
4970Sstevel@tonic-gate 	}
4980Sstevel@tonic-gate 
4990Sstevel@tonic-gate 	if (m != NULL) {
5000Sstevel@tonic-gate 		m->b_wptr += wspace - state->strm.avail_out;
5010Sstevel@tonic-gate 		olen += wspace - state->strm.avail_out;
5020Sstevel@tonic-gate 	}
5030Sstevel@tonic-gate 
5040Sstevel@tonic-gate 	/*
5050Sstevel@tonic-gate 	 * See if we managed to reduce the size of the packet.
5060Sstevel@tonic-gate 	 */
5070Sstevel@tonic-gate 	if (olen < orig_len && m != NULL) {
5080Sstevel@tonic-gate 		state->stats.comp_bytes += olen;
5090Sstevel@tonic-gate 		state->stats.comp_packets++;
5100Sstevel@tonic-gate 	} else {
5110Sstevel@tonic-gate 		if (*mret != NULL) {
5120Sstevel@tonic-gate 			freemsg(*mret);
5130Sstevel@tonic-gate 			*mret = NULL;
5140Sstevel@tonic-gate 		}
5150Sstevel@tonic-gate 
5160Sstevel@tonic-gate 		state->stats.inc_bytes += orig_len;
5170Sstevel@tonic-gate 		state->stats.inc_packets++;
5180Sstevel@tonic-gate 
5190Sstevel@tonic-gate 		olen = orig_len;
5200Sstevel@tonic-gate 	}
5210Sstevel@tonic-gate 
5220Sstevel@tonic-gate 	state->stats.unc_bytes += orig_len;
5230Sstevel@tonic-gate 	state->stats.unc_packets++;
5240Sstevel@tonic-gate 
5250Sstevel@tonic-gate 	return (olen);
5260Sstevel@tonic-gate }
5270Sstevel@tonic-gate 
5280Sstevel@tonic-gate /*
5290Sstevel@tonic-gate  * z_incomp()
5300Sstevel@tonic-gate  *
5310Sstevel@tonic-gate  * Incompressible data has arrived - add it to the history.
5320Sstevel@tonic-gate  */
5330Sstevel@tonic-gate static int
z_incomp(void * arg,mblk_t * mp)5340Sstevel@tonic-gate z_incomp(void *arg, mblk_t *mp)
5350Sstevel@tonic-gate {
5360Sstevel@tonic-gate 	struct deflate_state	*state = (struct deflate_state *)arg;
5370Sstevel@tonic-gate 	uchar_t			*rptr, *rmax;
5380Sstevel@tonic-gate 	int			rlen;
5390Sstevel@tonic-gate 	int			r;
5400Sstevel@tonic-gate 
5410Sstevel@tonic-gate 	/*
5420Sstevel@tonic-gate 	 * Check that the protocol is one we handle.  Pullup is *NOT*
5430Sstevel@tonic-gate 	 * possible here.
5440Sstevel@tonic-gate 	 */
5450Sstevel@tonic-gate 	rptr = mp->b_rptr;
5460Sstevel@tonic-gate 	rmax = mp->b_wptr;
5470Sstevel@tonic-gate 	ADJRPTR();
5480Sstevel@tonic-gate 	rptr++;		/* skip address */
5490Sstevel@tonic-gate 	ADJRPTR();
5500Sstevel@tonic-gate 	rptr++;		/* skip control */
5510Sstevel@tonic-gate 	ADJRPTR();
5520Sstevel@tonic-gate 
5530Sstevel@tonic-gate 	/*
5540Sstevel@tonic-gate 	 * Per RFC 1979, the protocol field must be compressed using a
5550Sstevel@tonic-gate 	 * PFC-like procedure.  Also, all protocols between 0000-3FFF
5560Sstevel@tonic-gate 	 * except the two compression protocols must be LZ compressed.
5570Sstevel@tonic-gate 	 */
5580Sstevel@tonic-gate 	if (rptr == NULL)
5590Sstevel@tonic-gate 		return (0);
5600Sstevel@tonic-gate 	r = *rptr;
5610Sstevel@tonic-gate 	if (r == 0) {
5620Sstevel@tonic-gate 		rptr++;
5630Sstevel@tonic-gate 		ADJRPTR();
5640Sstevel@tonic-gate 		if (rptr == NULL || *rptr == PPP_COMP || *rptr == PPP_COMPFRAG)
5650Sstevel@tonic-gate 			return (0);
5660Sstevel@tonic-gate 	} else {
5670Sstevel@tonic-gate 		if (r > 0x3F)
5680Sstevel@tonic-gate 			return (0);
5690Sstevel@tonic-gate 	}
5700Sstevel@tonic-gate 
5710Sstevel@tonic-gate 	++state->seqno;
5720Sstevel@tonic-gate 
5730Sstevel@tonic-gate 	/*
5740Sstevel@tonic-gate 	 * Iterate through the message blocks, adding the characters
5750Sstevel@tonic-gate 	 * in them to the decompressor's history.
5760Sstevel@tonic-gate 	 */
5770Sstevel@tonic-gate 	rlen = mp->b_wptr - rptr;
5780Sstevel@tonic-gate 
5790Sstevel@tonic-gate 	state->strm.next_in = rptr;
5800Sstevel@tonic-gate 	state->strm.avail_in = rlen;
5810Sstevel@tonic-gate 
5820Sstevel@tonic-gate 	for (;;) {
5830Sstevel@tonic-gate 		r = inflateIncomp(&state->strm);
5840Sstevel@tonic-gate 
5850Sstevel@tonic-gate 		if (r != Z_OK) {	/* gak! */
5860Sstevel@tonic-gate 			if (state->flags & DS_DEBUG) {
5870Sstevel@tonic-gate 				cmn_err(CE_CONT,
5880Sstevel@tonic-gate 				    "z_incomp%d: inflateIncomp returned "
5890Sstevel@tonic-gate 				    "%d (%s)\n", state->unit, r,
5900Sstevel@tonic-gate 				    (state->strm.msg? state->strm.msg: ""));
5910Sstevel@tonic-gate 			}
5920Sstevel@tonic-gate 
5930Sstevel@tonic-gate 			return (-1);
5940Sstevel@tonic-gate 		}
5950Sstevel@tonic-gate 
5960Sstevel@tonic-gate 		mp = mp->b_cont;
5970Sstevel@tonic-gate 		if (mp == NULL) {
5980Sstevel@tonic-gate 			break;
5990Sstevel@tonic-gate 		}
6000Sstevel@tonic-gate 
6010Sstevel@tonic-gate 		state->strm.next_in = mp->b_rptr;
6020Sstevel@tonic-gate 		state->strm.avail_in = mp->b_wptr - mp->b_rptr;
6030Sstevel@tonic-gate 
6040Sstevel@tonic-gate 		rlen += state->strm.avail_in;
6050Sstevel@tonic-gate 	}
6060Sstevel@tonic-gate 
6070Sstevel@tonic-gate 	/*
6080Sstevel@tonic-gate 	 * Update stats
6090Sstevel@tonic-gate 	 */
6100Sstevel@tonic-gate 	state->stats.inc_bytes += rlen;
6110Sstevel@tonic-gate 	state->stats.inc_packets++;
6120Sstevel@tonic-gate 	state->stats.unc_bytes += rlen;
6130Sstevel@tonic-gate 	state->stats.unc_packets++;
6140Sstevel@tonic-gate 	return (0);
6150Sstevel@tonic-gate #undef ADJRPTR
6160Sstevel@tonic-gate }
6170Sstevel@tonic-gate 
6180Sstevel@tonic-gate /*
6190Sstevel@tonic-gate  * z_comp_stats()
6200Sstevel@tonic-gate  */
6210Sstevel@tonic-gate static void
z_comp_stats(void * arg,struct compstat * stats)6220Sstevel@tonic-gate z_comp_stats(void *arg, struct compstat *stats)
6230Sstevel@tonic-gate {
6240Sstevel@tonic-gate 	struct deflate_state	*state = (struct deflate_state *)arg;
6250Sstevel@tonic-gate 	uint_t			out;
6260Sstevel@tonic-gate 
6270Sstevel@tonic-gate 	*stats = state->stats;
6280Sstevel@tonic-gate 	stats->ratio = stats->unc_bytes;
6290Sstevel@tonic-gate 	out = stats->comp_bytes + stats->unc_bytes;
6300Sstevel@tonic-gate 
6310Sstevel@tonic-gate 	if (stats->ratio <= 0x7ffffff) {
6320Sstevel@tonic-gate 		stats->ratio <<= 8;
6330Sstevel@tonic-gate 	} else {
6340Sstevel@tonic-gate 		out >>= 8;
6350Sstevel@tonic-gate 	}
6360Sstevel@tonic-gate 
6370Sstevel@tonic-gate 	if (out != 0) {
6380Sstevel@tonic-gate 		stats->ratio /= out;
6390Sstevel@tonic-gate 	}
6400Sstevel@tonic-gate }
6410Sstevel@tonic-gate 
6420Sstevel@tonic-gate /*
6430Sstevel@tonic-gate  * z_decomp_alloc()
6440Sstevel@tonic-gate  *
6450Sstevel@tonic-gate  * Allocate space for a decompressor.
6460Sstevel@tonic-gate  */
6470Sstevel@tonic-gate static void *
z_decomp_alloc(uchar_t * options,int opt_len)6480Sstevel@tonic-gate z_decomp_alloc(uchar_t *options, int opt_len)
6490Sstevel@tonic-gate {
6500Sstevel@tonic-gate 	struct deflate_state	*state;
6510Sstevel@tonic-gate 	int			w_size;
6520Sstevel@tonic-gate 
6530Sstevel@tonic-gate 	if (opt_len != CILEN_DEFLATE ||
6540Sstevel@tonic-gate 		(options[0] != CI_DEFLATE && options[0] != CI_DEFLATE_DRAFT) ||
6550Sstevel@tonic-gate 		options[1] != CILEN_DEFLATE ||
6560Sstevel@tonic-gate 		DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL ||
6570Sstevel@tonic-gate 		options[3] != DEFLATE_CHK_SEQUENCE) {
6580Sstevel@tonic-gate 
6590Sstevel@tonic-gate 		return (NULL);
6600Sstevel@tonic-gate 	}
6610Sstevel@tonic-gate 
6620Sstevel@tonic-gate 	w_size = DEFLATE_SIZE(options[2]);
6630Sstevel@tonic-gate 	/*
6640Sstevel@tonic-gate 	 * Check <= minimum size to avoid unfixable zlib bug -- window size
6650Sstevel@tonic-gate 	 * 256 (w_size 8) is not supported.
6660Sstevel@tonic-gate 	 */
6670Sstevel@tonic-gate 	if (w_size <= DEFLATE_MIN_SIZE || w_size > DEFLATE_MAX_SIZE) {
6680Sstevel@tonic-gate 		return (NULL);
6690Sstevel@tonic-gate 	}
6700Sstevel@tonic-gate 
6710Sstevel@tonic-gate 	state = (struct deflate_state *)kmem_zalloc(sizeof (*state), KM_SLEEP);
6720Sstevel@tonic-gate 	ASSERT(state != NULL);
6730Sstevel@tonic-gate 
6740Sstevel@tonic-gate 	state->strm.zalloc = (alloc_func)z_alloc;
6750Sstevel@tonic-gate 	state->strm.zfree = (free_func)z_free;
6760Sstevel@tonic-gate 
6770Sstevel@tonic-gate 	if (inflateInit2(&state->strm, -w_size) != Z_OK) {
6780Sstevel@tonic-gate 		kmem_free(state, sizeof (*state));
6790Sstevel@tonic-gate 		return (NULL);
6800Sstevel@tonic-gate 	}
6810Sstevel@tonic-gate 
6820Sstevel@tonic-gate 	state->w_size = w_size;
6830Sstevel@tonic-gate 
6840Sstevel@tonic-gate 	bzero(&state->stats, sizeof (state->stats));
6850Sstevel@tonic-gate 
6860Sstevel@tonic-gate 	return ((void *)state);
6870Sstevel@tonic-gate }
6880Sstevel@tonic-gate 
6890Sstevel@tonic-gate /*
6900Sstevel@tonic-gate  * z_decomp_free()
6910Sstevel@tonic-gate  */
6920Sstevel@tonic-gate static void
z_decomp_free(void * arg)6930Sstevel@tonic-gate z_decomp_free(void *arg)
6940Sstevel@tonic-gate {
6950Sstevel@tonic-gate 	struct deflate_state	*state = (struct deflate_state *)arg;
6960Sstevel@tonic-gate 
6970Sstevel@tonic-gate 	(void) inflateEnd(&state->strm);
6980Sstevel@tonic-gate 
6990Sstevel@tonic-gate 	kmem_free(state, sizeof (*state));
7000Sstevel@tonic-gate }
7010Sstevel@tonic-gate 
7020Sstevel@tonic-gate /*
7030Sstevel@tonic-gate  * z_decomp_init()
7040Sstevel@tonic-gate  */
7050Sstevel@tonic-gate static int
z_decomp_init(void * arg,uchar_t * options,int opt_len,int unit,int hdrlen,int mru,int debug)7060Sstevel@tonic-gate z_decomp_init(void *arg, uchar_t *options, int opt_len, int unit, int hdrlen,
7070Sstevel@tonic-gate 	int mru, int debug)
7080Sstevel@tonic-gate {
7090Sstevel@tonic-gate 	struct deflate_state *state = (struct deflate_state *)arg;
7100Sstevel@tonic-gate 
7110Sstevel@tonic-gate 	if (opt_len < CILEN_DEFLATE ||
7120Sstevel@tonic-gate 		(options[0] != CI_DEFLATE && options[0] != CI_DEFLATE_DRAFT) ||
7130Sstevel@tonic-gate 		options[1] != CILEN_DEFLATE ||
7140Sstevel@tonic-gate 		DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL ||
7150Sstevel@tonic-gate 		DEFLATE_SIZE(options[2]) != state->w_size ||
7160Sstevel@tonic-gate 		options[3] != DEFLATE_CHK_SEQUENCE) {
7170Sstevel@tonic-gate 
7180Sstevel@tonic-gate 		return (0);
7190Sstevel@tonic-gate 	}
7200Sstevel@tonic-gate 
7210Sstevel@tonic-gate 	state->seqno = 0;
7220Sstevel@tonic-gate 	state->unit = unit;
7230Sstevel@tonic-gate 	state->hdrlen = hdrlen;
7240Sstevel@tonic-gate 	if (debug)
7250Sstevel@tonic-gate 		state->flags |= DS_DEBUG;
7260Sstevel@tonic-gate 	else
7270Sstevel@tonic-gate 		state->flags &= ~DS_DEBUG;
7280Sstevel@tonic-gate 	state->mru = mru;
7290Sstevel@tonic-gate 
7300Sstevel@tonic-gate 	(void) inflateReset(&state->strm);
7310Sstevel@tonic-gate 
7320Sstevel@tonic-gate 	return (1);
7330Sstevel@tonic-gate }
7340Sstevel@tonic-gate 
7350Sstevel@tonic-gate /*
7360Sstevel@tonic-gate  * z_decomp_reset()
7370Sstevel@tonic-gate  */
7380Sstevel@tonic-gate static void
z_decomp_reset(void * arg)7390Sstevel@tonic-gate z_decomp_reset(void *arg)
7400Sstevel@tonic-gate {
7410Sstevel@tonic-gate 	struct deflate_state	*state = (struct deflate_state *)arg;
7420Sstevel@tonic-gate 
7430Sstevel@tonic-gate 	state->seqno = 0;
7440Sstevel@tonic-gate 
7450Sstevel@tonic-gate 	(void) inflateReset(&state->strm);
7460Sstevel@tonic-gate }
7470Sstevel@tonic-gate 
7480Sstevel@tonic-gate /*
7490Sstevel@tonic-gate  * z_decompress()
7500Sstevel@tonic-gate  *
7510Sstevel@tonic-gate  * Decompress a Deflate-compressed packet.
7520Sstevel@tonic-gate  *
7530Sstevel@tonic-gate  * Because of patent problems, we return DECOMP_ERROR for errors
7540Sstevel@tonic-gate  * found by inspecting the input data and for system problems, but
7550Sstevel@tonic-gate  * DECOMP_FATALERROR for any errors which could possibly be said to
7560Sstevel@tonic-gate  * be being detected "after" decompression.  For DECOMP_ERROR,
7570Sstevel@tonic-gate  * we can issue a CCP reset-request; for DECOMP_FATALERROR, we may be
7580Sstevel@tonic-gate  * infringing a patent of Motorola's if we do, so we take CCP down
7590Sstevel@tonic-gate  * instead.
7600Sstevel@tonic-gate  *
7610Sstevel@tonic-gate  * Given that the frame has the correct sequence number and a good FCS,
7620Sstevel@tonic-gate  * errors such as invalid codes in the input most likely indicate a
7630Sstevel@tonic-gate  * bug, so we return DECOMP_FATALERROR for them in order to turn off
7640Sstevel@tonic-gate  * compression, even though they are detected by inspecting the input.
7650Sstevel@tonic-gate  */
7660Sstevel@tonic-gate static int
z_decompress(void * arg,mblk_t ** mop)7670Sstevel@tonic-gate z_decompress(void *arg, mblk_t **mop)
7680Sstevel@tonic-gate {
7690Sstevel@tonic-gate 	struct deflate_state	*state = (struct deflate_state *)arg;
7700Sstevel@tonic-gate 	mblk_t			*mi = *mop, *mnext;
7710Sstevel@tonic-gate 	mblk_t			*mo;
7720Sstevel@tonic-gate 	mblk_t			*mo_head;
7730Sstevel@tonic-gate 	uchar_t			*rptr, *rmax;
7740Sstevel@tonic-gate 	uchar_t			*wptr;
7750Sstevel@tonic-gate 	int			rlen;
7760Sstevel@tonic-gate 	int			olen;
7770Sstevel@tonic-gate 	int			ospace;
7780Sstevel@tonic-gate 	int			seq;
7790Sstevel@tonic-gate 	int			flush;
7800Sstevel@tonic-gate 	int			r;
7810Sstevel@tonic-gate 	int			decode_proto;
7820Sstevel@tonic-gate #if defined(lint) || defined(_lint)
7830Sstevel@tonic-gate 	uchar_t			hdlcaddr, hdlcctrl;
7840Sstevel@tonic-gate #else
7850Sstevel@tonic-gate 	int			hdlcaddr, hdlcctrl;
7860Sstevel@tonic-gate #endif
7870Sstevel@tonic-gate 
7880Sstevel@tonic-gate 	/* Note: spppcomp already did a pullup to fix the first buffer. */
7890Sstevel@tonic-gate 	*mop = NULL;
7900Sstevel@tonic-gate 	rptr = mi->b_rptr + PPP_HDRLEN;
7910Sstevel@tonic-gate 	rmax = mi->b_wptr;
7920Sstevel@tonic-gate 	if (rptr > rmax) {
7930Sstevel@tonic-gate 		if (state->flags & DS_DEBUG) {
7940Sstevel@tonic-gate 			cmn_err(CE_CONT, "z_decompress%d: bad buffer\n",
7950Sstevel@tonic-gate 			    state->unit);
7960Sstevel@tonic-gate 		}
7970Sstevel@tonic-gate 		freemsg(mi);
7980Sstevel@tonic-gate 		return (DECOMP_ERROR);
7990Sstevel@tonic-gate 	}
8000Sstevel@tonic-gate 
8010Sstevel@tonic-gate 	hdlcaddr = rptr[-PPP_HDRLEN];
8020Sstevel@tonic-gate 	hdlcctrl = rptr[-PPP_HDRLEN+1];
8030Sstevel@tonic-gate 
8040Sstevel@tonic-gate 	/*
8050Sstevel@tonic-gate 	 * Note that we free as we go.  If we fail to decompress,
8060Sstevel@tonic-gate 	 * there's nothing good that the caller can do.
8070Sstevel@tonic-gate 	 */
8080Sstevel@tonic-gate #define	ADJRPTR() {						\
8090Sstevel@tonic-gate 	if (rptr != NULL) {					\
8100Sstevel@tonic-gate 		while (rptr >= rmax) {				\
8110Sstevel@tonic-gate 			mnext = mi->b_cont;			\
8120Sstevel@tonic-gate 			freeb(mi);				\
8130Sstevel@tonic-gate 			if ((mi = mnext) == NULL) {		\
8140Sstevel@tonic-gate 				rptr = NULL;			\
8150Sstevel@tonic-gate 				break;				\
8160Sstevel@tonic-gate 			}					\
8170Sstevel@tonic-gate 			rptr = mi->b_rptr;			\
8180Sstevel@tonic-gate 			rmax = mi->b_wptr;			\
8190Sstevel@tonic-gate 		}						\
8200Sstevel@tonic-gate 	}							\
8210Sstevel@tonic-gate }
8220Sstevel@tonic-gate 
8230Sstevel@tonic-gate 	/*
8240Sstevel@tonic-gate 	 * Check the sequence number
8250Sstevel@tonic-gate 	 */
8260Sstevel@tonic-gate 	ADJRPTR();
8270Sstevel@tonic-gate 	seq = rptr == NULL ? 0 : (*rptr++ << 8);
8280Sstevel@tonic-gate 	ADJRPTR();
8290Sstevel@tonic-gate 	if (rptr == NULL) {
8300Sstevel@tonic-gate 		if (state->flags & DS_DEBUG) {
8310Sstevel@tonic-gate 			cmn_err(CE_CONT, "z_decompress%d: bad buffer\n",
8320Sstevel@tonic-gate 			    state->unit);
8330Sstevel@tonic-gate 		}
8340Sstevel@tonic-gate 		return (DECOMP_ERROR);
8350Sstevel@tonic-gate 	}
8360Sstevel@tonic-gate 
8370Sstevel@tonic-gate 	seq |= *rptr++;
8380Sstevel@tonic-gate 
8390Sstevel@tonic-gate #ifdef DEBUG
8400Sstevel@tonic-gate 	/*
8410Sstevel@tonic-gate 	 * If testing input, just pretending the sequence is bad here
8420Sstevel@tonic-gate 	 * does the trick.
8430Sstevel@tonic-gate 	 */
8440Sstevel@tonic-gate 	if ((state->flags & DS_TESTIN) && (state->seqno % 300) == 101)
8450Sstevel@tonic-gate 		seq ^= 0x55;
8460Sstevel@tonic-gate #endif
8470Sstevel@tonic-gate 	if (seq != state->seqno++) {
8480Sstevel@tonic-gate 		freemsg(mi);
8490Sstevel@tonic-gate 		if (state->flags & DS_DEBUG) {
8500Sstevel@tonic-gate 			cmn_err(CE_CONT,
8510Sstevel@tonic-gate 				"z_decompress%d: bad seq # %d, expected %d\n",
8520Sstevel@tonic-gate 				state->unit, seq, state->seqno - 1);
8530Sstevel@tonic-gate 		}
8540Sstevel@tonic-gate 		return (DECOMP_ERROR);
8550Sstevel@tonic-gate 	}
8560Sstevel@tonic-gate 
8570Sstevel@tonic-gate 	/*
8580Sstevel@tonic-gate 	 * Allocate an output message block
8590Sstevel@tonic-gate 	 */
8600Sstevel@tonic-gate 	mo = allocb(DECOMP_CHUNK + state->hdrlen, BPRI_MED);
8610Sstevel@tonic-gate 	if (mo == NULL) {
8620Sstevel@tonic-gate 		freemsg(mi);
8630Sstevel@tonic-gate 		return (DECOMP_ERROR);
8640Sstevel@tonic-gate 	}
8650Sstevel@tonic-gate 
8660Sstevel@tonic-gate 	mo_head = mo;
8670Sstevel@tonic-gate 	mo->b_cont = NULL;
8680Sstevel@tonic-gate 	mo->b_rptr += state->hdrlen;
8690Sstevel@tonic-gate 	mo->b_wptr = wptr = mo->b_rptr;
8700Sstevel@tonic-gate 
8710Sstevel@tonic-gate 	ospace = DECOMP_CHUNK;
8720Sstevel@tonic-gate 	olen = 0;
8730Sstevel@tonic-gate 
8740Sstevel@tonic-gate 	/*
8750Sstevel@tonic-gate 	 * Fill in the first part of the PPP header.  The protocol field
8760Sstevel@tonic-gate 	 * comes from the decompressed data.
8770Sstevel@tonic-gate 	 */
8780Sstevel@tonic-gate 	*wptr++ = hdlcaddr;
8790Sstevel@tonic-gate 	*wptr++ = hdlcctrl;
8800Sstevel@tonic-gate 	*wptr++ = 0;
8810Sstevel@tonic-gate 
8820Sstevel@tonic-gate 	/*
8830Sstevel@tonic-gate 	 * Set up to call inflate.  We set avail_out to 1 initially so we can
8840Sstevel@tonic-gate 	 * look at the first byte of the output and decide whether we have
8850Sstevel@tonic-gate 	 * a 1-byte or 2-byte protocol field.
8860Sstevel@tonic-gate 	 */
8870Sstevel@tonic-gate 	state->strm.next_in = rptr;
8880Sstevel@tonic-gate 	state->strm.avail_in = mi->b_wptr - rptr;
8890Sstevel@tonic-gate 
8900Sstevel@tonic-gate 	rlen = state->strm.avail_in + PPP_HDRLEN + DEFLATE_OVHD;
8910Sstevel@tonic-gate 
8920Sstevel@tonic-gate 	state->strm.next_out = wptr;
8930Sstevel@tonic-gate 	state->strm.avail_out = 1;
8940Sstevel@tonic-gate 
8950Sstevel@tonic-gate 	decode_proto = 1;
8960Sstevel@tonic-gate 
8970Sstevel@tonic-gate 	/*
8980Sstevel@tonic-gate 	 * Call inflate, supplying more input or output as needed.
8990Sstevel@tonic-gate 	 */
9000Sstevel@tonic-gate 	for (;;) {
9010Sstevel@tonic-gate 
9020Sstevel@tonic-gate 		flush = (mi == NULL || mi->b_cont == NULL) ?
9030Sstevel@tonic-gate 		    Z_PACKET_FLUSH : Z_NO_FLUSH;
9040Sstevel@tonic-gate 		r = inflate(&state->strm, flush);
9050Sstevel@tonic-gate 
9060Sstevel@tonic-gate 		if (r != Z_OK) {
9070Sstevel@tonic-gate 
9080Sstevel@tonic-gate 			if (state->flags & DS_DEBUG) {
9090Sstevel@tonic-gate 				cmn_err(CE_CONT,
9100Sstevel@tonic-gate 				    "z_decompress%d: inflate returned %d "
9110Sstevel@tonic-gate 				    "(%s)\n", state->unit, r,
9120Sstevel@tonic-gate 				    (state->strm.msg? state->strm.msg: ""));
9130Sstevel@tonic-gate 			}
9140Sstevel@tonic-gate 
9150Sstevel@tonic-gate 			if (mi != NULL)
9160Sstevel@tonic-gate 				freemsg(mi);
9170Sstevel@tonic-gate 			freemsg(mo_head);
9180Sstevel@tonic-gate 
9190Sstevel@tonic-gate 			return (DECOMP_FATALERROR);
9200Sstevel@tonic-gate 		}
9210Sstevel@tonic-gate 
9220Sstevel@tonic-gate 		if (state->strm.avail_in == 0) {
9230Sstevel@tonic-gate 			if (mi != NULL) {
9240Sstevel@tonic-gate 				mnext = mi->b_cont;
9250Sstevel@tonic-gate 				freeb(mi);
9260Sstevel@tonic-gate 				mi = mnext;
9270Sstevel@tonic-gate 			}
9280Sstevel@tonic-gate 			if (mi == NULL) {
9290Sstevel@tonic-gate 				if (state->strm.avail_out != 0)
9300Sstevel@tonic-gate 					break;	/* all done */
9310Sstevel@tonic-gate 			} else {
9320Sstevel@tonic-gate 				state->strm.next_in = mi->b_rptr;
9330Sstevel@tonic-gate 				state->strm.avail_in = mi->b_wptr - mi->b_rptr;
9340Sstevel@tonic-gate 
9350Sstevel@tonic-gate 				rlen += state->strm.avail_in;
9360Sstevel@tonic-gate 			}
9370Sstevel@tonic-gate 		}
9380Sstevel@tonic-gate 
9390Sstevel@tonic-gate 		if (state->strm.avail_out == 0) {
9400Sstevel@tonic-gate 			if (decode_proto) {
9410Sstevel@tonic-gate 				state->strm.avail_out = ospace - PPP_HDRLEN;
9420Sstevel@tonic-gate 
9430Sstevel@tonic-gate 				if ((wptr[0] & 1) == 0) {
9440Sstevel@tonic-gate 					/*
9450Sstevel@tonic-gate 					 * 2-byte protocol field
9460Sstevel@tonic-gate 					 */
9470Sstevel@tonic-gate 					wptr[-1] = wptr[0];
9480Sstevel@tonic-gate 
9490Sstevel@tonic-gate 					--state->strm.next_out;
9500Sstevel@tonic-gate 					++state->strm.avail_out;
9510Sstevel@tonic-gate 				}
9520Sstevel@tonic-gate 
9530Sstevel@tonic-gate 				decode_proto = 0;
9540Sstevel@tonic-gate 			} else {
9550Sstevel@tonic-gate 				mo->b_wptr += ospace;
9560Sstevel@tonic-gate 				olen += ospace;
9570Sstevel@tonic-gate 
9580Sstevel@tonic-gate 				mo->b_cont = allocb(DECOMP_CHUNK, BPRI_MED);
9590Sstevel@tonic-gate 
9600Sstevel@tonic-gate 				mo = mo->b_cont;
9610Sstevel@tonic-gate 				if (mo == NULL) {
9620Sstevel@tonic-gate 					if (mi != NULL)
9630Sstevel@tonic-gate 						freemsg(mi);
9640Sstevel@tonic-gate 					freemsg(mo_head);
9650Sstevel@tonic-gate 					return (DECOMP_ERROR);
9660Sstevel@tonic-gate 				}
9670Sstevel@tonic-gate 
9680Sstevel@tonic-gate 				state->strm.next_out = mo->b_rptr;
9690Sstevel@tonic-gate 				state->strm.avail_out = ospace = DECOMP_CHUNK;
9700Sstevel@tonic-gate 			}
9710Sstevel@tonic-gate 		}
9720Sstevel@tonic-gate 	}
9730Sstevel@tonic-gate 
9740Sstevel@tonic-gate 	if (decode_proto) {
9750Sstevel@tonic-gate 		freemsg(mo_head);
9760Sstevel@tonic-gate 		return (DECOMP_ERROR);
9770Sstevel@tonic-gate 	}
9780Sstevel@tonic-gate 
9790Sstevel@tonic-gate 	mo->b_wptr += ospace - state->strm.avail_out;
9800Sstevel@tonic-gate 	olen += ospace - state->strm.avail_out;
9810Sstevel@tonic-gate 
9820Sstevel@tonic-gate 	if ((olen > state->mru + PPP_HDRLEN) && (state->flags & DS_DEBUG)) {
9830Sstevel@tonic-gate 		cmn_err(CE_CONT, "z_decompress%d: exceeded mru (%d > %d)\n",
9840Sstevel@tonic-gate 		    state->unit, olen, state->mru + PPP_HDRLEN);
9850Sstevel@tonic-gate 	}
9860Sstevel@tonic-gate 
9870Sstevel@tonic-gate 	state->stats.unc_bytes += olen;
9880Sstevel@tonic-gate 	state->stats.unc_packets++;
9890Sstevel@tonic-gate 	state->stats.comp_bytes += rlen;
9900Sstevel@tonic-gate 	state->stats.comp_packets++;
9910Sstevel@tonic-gate 
9920Sstevel@tonic-gate 	*mop = mo_head;
9930Sstevel@tonic-gate 
9940Sstevel@tonic-gate 	return (DECOMP_OK);
9950Sstevel@tonic-gate }
9960Sstevel@tonic-gate 
9970Sstevel@tonic-gate /* ARGSUSED */
9980Sstevel@tonic-gate static int
z_set_effort(void * xarg,void * rarg,int effortlevel)9990Sstevel@tonic-gate z_set_effort(void *xarg, void *rarg, int effortlevel)
10000Sstevel@tonic-gate {
10010Sstevel@tonic-gate 	struct deflate_state *xstate = (struct deflate_state *)xarg;
10020Sstevel@tonic-gate #ifdef DEBUG
10030Sstevel@tonic-gate 	struct deflate_state *rstate = (struct deflate_state *)rarg;
10040Sstevel@tonic-gate #endif
10050Sstevel@tonic-gate 	int retv;
10060Sstevel@tonic-gate 
10070Sstevel@tonic-gate #ifdef DEBUG
10080Sstevel@tonic-gate 	if (effortlevel == 42 || effortlevel == 2112) {
10090Sstevel@tonic-gate 		/* corrupt received data. */
10100Sstevel@tonic-gate 		if (rstate != NULL) {
10110Sstevel@tonic-gate 			rstate->flags |= DS_TESTIN;
10120Sstevel@tonic-gate 			cmn_err(CE_CONT, "deflate: enabled input testing.");
10130Sstevel@tonic-gate 		}
10140Sstevel@tonic-gate 		if (effortlevel != 2112)
10150Sstevel@tonic-gate 			return (0);
10160Sstevel@tonic-gate 	}
10170Sstevel@tonic-gate 	if (effortlevel == 2001 || effortlevel == 2112) {
10180Sstevel@tonic-gate 		/* corrupt transmitted data. */
10190Sstevel@tonic-gate 		if (xstate != NULL) {
10200Sstevel@tonic-gate 			xstate->flags |= DS_TESTOUT;
10210Sstevel@tonic-gate 			cmn_err(CE_CONT, "deflate: enabled output testing.");
10220Sstevel@tonic-gate 		}
10230Sstevel@tonic-gate 		return (0);
10240Sstevel@tonic-gate 	}
10250Sstevel@tonic-gate #endif
10260Sstevel@tonic-gate 	if (effortlevel < -1 || effortlevel > 9)
10270Sstevel@tonic-gate 		return (EINVAL);
10280Sstevel@tonic-gate 	if (xstate == NULL)
10290Sstevel@tonic-gate 		return (0);
10300Sstevel@tonic-gate 	retv = deflateParams(&xstate->strm, effortlevel, Z_DEFAULT_STRATEGY);
10310Sstevel@tonic-gate 	return (retv == Z_OK ? 0 : EINVAL);
10320Sstevel@tonic-gate }
10330Sstevel@tonic-gate 
10340Sstevel@tonic-gate #endif /* DO_DEFLATE */
1035