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