xref: /onnv-gate/usr/src/uts/common/io/ppp/spppcomp/bsd-comp.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * Copyright (c) 2000 by Sun Microsystems, Inc.
3*0Sstevel@tonic-gate  * All rights reserved.
4*0Sstevel@tonic-gate  *
5*0Sstevel@tonic-gate  * Because this code is derived from the 4.3BSD compress source:
6*0Sstevel@tonic-gate  *
7*0Sstevel@tonic-gate  * Copyright (c) 1985, 1986 The Regents of the University of California.
8*0Sstevel@tonic-gate  * All rights reserved.
9*0Sstevel@tonic-gate  *
10*0Sstevel@tonic-gate  * This code is derived from software contributed to Berkeley by
11*0Sstevel@tonic-gate  * James A. Woods, derived from original work by Spencer Thomas
12*0Sstevel@tonic-gate  * and Joseph Orost.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * Redistribution and use in source and binary forms, with or without
15*0Sstevel@tonic-gate  * modification, are permitted provided that the following conditions
16*0Sstevel@tonic-gate  * are met:
17*0Sstevel@tonic-gate  * 1. Redistributions of source code must retain the above copyright
18*0Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer.
19*0Sstevel@tonic-gate  * 2. Redistributions in binary form must reproduce the above copyright
20*0Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer in the
21*0Sstevel@tonic-gate  *    documentation and/or other materials provided with the distribution.
22*0Sstevel@tonic-gate  * 3. All advertising materials mentioning features or use of this software
23*0Sstevel@tonic-gate  *    must display the following acknowledgement:
24*0Sstevel@tonic-gate  *	This product includes software developed by the University of
25*0Sstevel@tonic-gate  *	California, Berkeley and its contributors.
26*0Sstevel@tonic-gate  * 4. Neither the name of the University nor the names of its contributors
27*0Sstevel@tonic-gate  *    may be used to endorse or promote products derived from this software
28*0Sstevel@tonic-gate  *    without specific prior written permission.
29*0Sstevel@tonic-gate  *
30*0Sstevel@tonic-gate  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
31*0Sstevel@tonic-gate  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
32*0Sstevel@tonic-gate  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33*0Sstevel@tonic-gate  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
34*0Sstevel@tonic-gate  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
35*0Sstevel@tonic-gate  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
36*0Sstevel@tonic-gate  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
37*0Sstevel@tonic-gate  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
38*0Sstevel@tonic-gate  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
39*0Sstevel@tonic-gate  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
40*0Sstevel@tonic-gate  * SUCH DAMAGE.
41*0Sstevel@tonic-gate  */
42*0Sstevel@tonic-gate 
43*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
44*0Sstevel@tonic-gate 
45*0Sstevel@tonic-gate /*
46*0Sstevel@tonic-gate  * This version is for use with STREAMS in Solaris 2
47*0Sstevel@tonic-gate  *
48*0Sstevel@tonic-gate  * $Id: bsd-comp.c,v 1.20 1996/08/28 06:31:57 paulus Exp $
49*0Sstevel@tonic-gate  */
50*0Sstevel@tonic-gate 
51*0Sstevel@tonic-gate #include <sys/param.h>
52*0Sstevel@tonic-gate #include <sys/types.h>
53*0Sstevel@tonic-gate #include <sys/kmem.h>
54*0Sstevel@tonic-gate #include <sys/stream.h>
55*0Sstevel@tonic-gate #include <sys/cmn_err.h>
56*0Sstevel@tonic-gate #include <sys/ddi.h>
57*0Sstevel@tonic-gate #include <sys/sunddi.h>
58*0Sstevel@tonic-gate #include <sys/byteorder.h>
59*0Sstevel@tonic-gate #include <net/ppp_defs.h>
60*0Sstevel@tonic-gate 
61*0Sstevel@tonic-gate /* Defined for platform-neutral include file */
62*0Sstevel@tonic-gate #define	PACKETPTR		mblk_t *
63*0Sstevel@tonic-gate #include <net/ppp-comp.h>
64*0Sstevel@tonic-gate #include "s_common.h"
65*0Sstevel@tonic-gate 
66*0Sstevel@tonic-gate #ifndef _BIG_ENDIAN
67*0Sstevel@tonic-gate #define	BSD_LITTLE_ENDIAN
68*0Sstevel@tonic-gate #endif
69*0Sstevel@tonic-gate 
70*0Sstevel@tonic-gate #if DO_BSD_COMPRESS
71*0Sstevel@tonic-gate 
72*0Sstevel@tonic-gate /*
73*0Sstevel@tonic-gate  * PPP "BSD compress" compression
74*0Sstevel@tonic-gate  *
75*0Sstevel@tonic-gate  *  The differences between this compression and the classic BSD LZW
76*0Sstevel@tonic-gate  *  source are obvious from the requirement that the classic code worked
77*0Sstevel@tonic-gate  *  with files while this handles arbitrarily long streams that
78*0Sstevel@tonic-gate  *  are broken into packets.  They are:
79*0Sstevel@tonic-gate  *
80*0Sstevel@tonic-gate  *	When the code size expands, a block of junk is not emitted by
81*0Sstevel@tonic-gate  *	    the compressor and not expected by the decompressor.
82*0Sstevel@tonic-gate  *
83*0Sstevel@tonic-gate  *	New codes are not necessarily assigned every time an old
84*0Sstevel@tonic-gate  *	    code is output by the compressor.  This is because a packet
85*0Sstevel@tonic-gate  *	    end forces a code to be emitted, but does not imply that a
86*0Sstevel@tonic-gate  *	    new sequence has been seen.
87*0Sstevel@tonic-gate  *
88*0Sstevel@tonic-gate  *	The compression ratio is checked at the first end of a packet
89*0Sstevel@tonic-gate  *	    after the appropriate gap.	Besides simplifying and speeding
90*0Sstevel@tonic-gate  *	    things up, this makes it more likely that the transmitter
91*0Sstevel@tonic-gate  *	    and receiver will agree when the dictionary is cleared when
92*0Sstevel@tonic-gate  *	    compression is not going well.
93*0Sstevel@tonic-gate  */
94*0Sstevel@tonic-gate 
95*0Sstevel@tonic-gate /*
96*0Sstevel@tonic-gate  * A dictionary for doing BSD compress.
97*0Sstevel@tonic-gate  */
98*0Sstevel@tonic-gate struct bsd_db {
99*0Sstevel@tonic-gate 	int		totlen;		/* length of this structure */
100*0Sstevel@tonic-gate 	uint_t		hsize;		/* size of the hash table */
101*0Sstevel@tonic-gate 	uint32_t	unit;
102*0Sstevel@tonic-gate 	uchar_t		hshift;		/* used in hash function */
103*0Sstevel@tonic-gate 	uchar_t		n_bits;		/* current bits/code */
104*0Sstevel@tonic-gate 	uchar_t		maxbits;
105*0Sstevel@tonic-gate 	uchar_t		flags;
106*0Sstevel@tonic-gate 	ushort_t	seqno;		/* sequence number of next packet */
107*0Sstevel@tonic-gate 	ushort_t	mru;
108*0Sstevel@tonic-gate 	uint_t		hdrlen;		/* header length to preallocate */
109*0Sstevel@tonic-gate 	uint_t		maxmaxcode;	/* largest valid code */
110*0Sstevel@tonic-gate 	uint_t		max_ent;	/* largest code in use */
111*0Sstevel@tonic-gate 	uint_t		in_count;	/* uncompressed bytes, aged */
112*0Sstevel@tonic-gate 	uint_t		bytes_out;	/* compressed bytes, aged */
113*0Sstevel@tonic-gate 	uint_t		ratio;		/* recent compression ratio */
114*0Sstevel@tonic-gate 	uint_t		checkpoint;	/* when to next check the ratio */
115*0Sstevel@tonic-gate 	uint_t		clear_count;	/* times dictionary cleared */
116*0Sstevel@tonic-gate 	uint_t		incomp_count;	/* incompressible packets */
117*0Sstevel@tonic-gate 	uint_t		incomp_bytes;	/* incompressible bytes */
118*0Sstevel@tonic-gate 	uint_t		uncomp_count;	/* uncompressed packets */
119*0Sstevel@tonic-gate 	uint_t		uncomp_bytes;	/* uncompressed bytes */
120*0Sstevel@tonic-gate 	uint_t		comp_count;	/* compressed packets */
121*0Sstevel@tonic-gate 	uint_t		comp_bytes;	/* compressed bytes */
122*0Sstevel@tonic-gate 	ushort_t	*lens;		/* array of lengths of codes */
123*0Sstevel@tonic-gate 	struct bsd_dict {
124*0Sstevel@tonic-gate 	union {				/* hash value */
125*0Sstevel@tonic-gate 		uint32_t	fcode;
126*0Sstevel@tonic-gate 		struct {
127*0Sstevel@tonic-gate #ifdef BSD_LITTLE_ENDIAN
128*0Sstevel@tonic-gate 			ushort_t	prefix;	/* preceding code */
129*0Sstevel@tonic-gate 			uchar_t		suffix;	/* last character of new code */
130*0Sstevel@tonic-gate 			uchar_t		pad;
131*0Sstevel@tonic-gate #else
132*0Sstevel@tonic-gate 			uchar_t		pad;
133*0Sstevel@tonic-gate 			uchar_t		suffix;	/* last character of new code */
134*0Sstevel@tonic-gate 			ushort_t	prefix;	/* preceding code */
135*0Sstevel@tonic-gate #endif
136*0Sstevel@tonic-gate 		} hs;
137*0Sstevel@tonic-gate 	} f;
138*0Sstevel@tonic-gate 		ushort_t	codem1;		/* output of hash table -1 */
139*0Sstevel@tonic-gate 		ushort_t	cptr;		/* map code to hash entry */
140*0Sstevel@tonic-gate 	} dict[1];
141*0Sstevel@tonic-gate };
142*0Sstevel@tonic-gate 
143*0Sstevel@tonic-gate #define	BSD_OVHD	2		/* BSD compress overhead/packet */
144*0Sstevel@tonic-gate #define	BSD_INIT_BITS	BSD_MIN_BITS
145*0Sstevel@tonic-gate 
146*0Sstevel@tonic-gate /* db->flags values */
147*0Sstevel@tonic-gate #define	DS_DEBUG	0x01
148*0Sstevel@tonic-gate #define	DS_TESTIN	0x02
149*0Sstevel@tonic-gate #define	DS_TESTOUT	0x04
150*0Sstevel@tonic-gate 
151*0Sstevel@tonic-gate static void	*bsd_comp_alloc(uchar_t *options, int opt_len);
152*0Sstevel@tonic-gate static void	*bsd_decomp_alloc(uchar_t *options, int opt_len);
153*0Sstevel@tonic-gate static void	bsd_free(void *state);
154*0Sstevel@tonic-gate static int	bsd_comp_init(void *state, uchar_t *options, int opt_len,
155*0Sstevel@tonic-gate 				int unit, int hdrlen, int debug);
156*0Sstevel@tonic-gate static int	bsd_decomp_init(void *state, uchar_t *options, int opt_len,
157*0Sstevel@tonic-gate 				int unit, int hdrlen, int mru, int debug);
158*0Sstevel@tonic-gate static int	bsd_compress(void *state, mblk_t **mret,
159*0Sstevel@tonic-gate 				mblk_t *mp, int slen, int maxolen);
160*0Sstevel@tonic-gate static int	bsd_incomp(void *state, mblk_t *dmsg);
161*0Sstevel@tonic-gate static int	bsd_decompress(void *state, mblk_t **dmpp);
162*0Sstevel@tonic-gate static void	bsd_reset(void *state);
163*0Sstevel@tonic-gate static void	bsd_comp_stats(void *state, struct compstat *stats);
164*0Sstevel@tonic-gate static int	bsd_set_effort(void *xarg, void *rarg, int effortlevel);
165*0Sstevel@tonic-gate 
166*0Sstevel@tonic-gate /*
167*0Sstevel@tonic-gate  * Procedures exported to ppp_comp.c.
168*0Sstevel@tonic-gate  */
169*0Sstevel@tonic-gate struct compressor ppp_bsd_compress = {
170*0Sstevel@tonic-gate 	CI_BSD_COMPRESS,		/* compress_proto */
171*0Sstevel@tonic-gate 	bsd_comp_alloc,			/* comp_alloc */
172*0Sstevel@tonic-gate 	bsd_free,			/* comp_free */
173*0Sstevel@tonic-gate 	bsd_comp_init,			/* comp_init */
174*0Sstevel@tonic-gate 	bsd_reset,			/* comp_reset */
175*0Sstevel@tonic-gate 	bsd_compress,			/* compress */
176*0Sstevel@tonic-gate 	bsd_comp_stats,			/* comp_stat */
177*0Sstevel@tonic-gate 	bsd_decomp_alloc,		/* decomp_alloc */
178*0Sstevel@tonic-gate 	bsd_free,			/* decomp_free */
179*0Sstevel@tonic-gate 	bsd_decomp_init,		/* decomp_init */
180*0Sstevel@tonic-gate 	bsd_reset,			/* decomp_reset */
181*0Sstevel@tonic-gate 	bsd_decompress,			/* decompress */
182*0Sstevel@tonic-gate 	bsd_incomp,			/* incomp */
183*0Sstevel@tonic-gate 	bsd_comp_stats,			/* decomp_stat */
184*0Sstevel@tonic-gate 	bsd_set_effort,			/* set_effort */
185*0Sstevel@tonic-gate };
186*0Sstevel@tonic-gate 
187*0Sstevel@tonic-gate /*
188*0Sstevel@tonic-gate  * the next two codes should not be changed lightly, as they must not
189*0Sstevel@tonic-gate  * lie within the contiguous general code space.
190*0Sstevel@tonic-gate  */
191*0Sstevel@tonic-gate #define	CLEAR		256		/* table clear output code */
192*0Sstevel@tonic-gate #define	FIRST		257		/* first free entry */
193*0Sstevel@tonic-gate #define	LAST		255
194*0Sstevel@tonic-gate 
195*0Sstevel@tonic-gate #define	MAXCODE(b)	((1 << (b)) - 1)
196*0Sstevel@tonic-gate #define	BADCODEM1	MAXCODE(BSD_MAX_BITS)
197*0Sstevel@tonic-gate 
198*0Sstevel@tonic-gate #define	BSD_HASH(prefix, suffix, hshift)	\
199*0Sstevel@tonic-gate 	((((uint32_t)(suffix)) << (hshift)) ^ (uint32_t)(prefix))
200*0Sstevel@tonic-gate 
201*0Sstevel@tonic-gate #define	BSD_KEY(prefix, suffix)		\
202*0Sstevel@tonic-gate 	((((uint32_t)(suffix)) << 16) + (uint32_t)(prefix))
203*0Sstevel@tonic-gate 
204*0Sstevel@tonic-gate #define	CHECK_GAP	10000		/* Ratio check interval */
205*0Sstevel@tonic-gate 
206*0Sstevel@tonic-gate #define	RATIO_SCALE_LOG	8
207*0Sstevel@tonic-gate #define	RATIO_SCALE	(1 << RATIO_SCALE_LOG)
208*0Sstevel@tonic-gate #define	RATIO_MAX	(0x7fffffff >> RATIO_SCALE_LOG)
209*0Sstevel@tonic-gate 
210*0Sstevel@tonic-gate #define	DECOMP_CHUNK	256
211*0Sstevel@tonic-gate 
212*0Sstevel@tonic-gate /*
213*0Sstevel@tonic-gate  * bsd_clear()
214*0Sstevel@tonic-gate  *
215*0Sstevel@tonic-gate  * clear the dictionary
216*0Sstevel@tonic-gate  */
217*0Sstevel@tonic-gate static void
218*0Sstevel@tonic-gate bsd_clear(struct bsd_db *db)
219*0Sstevel@tonic-gate {
220*0Sstevel@tonic-gate 	db->clear_count++;
221*0Sstevel@tonic-gate 	db->max_ent = FIRST-1;
222*0Sstevel@tonic-gate 	db->n_bits = BSD_INIT_BITS;
223*0Sstevel@tonic-gate 	db->ratio = 0;
224*0Sstevel@tonic-gate 	db->bytes_out = 0;
225*0Sstevel@tonic-gate 	db->in_count = 0;
226*0Sstevel@tonic-gate 	db->checkpoint = CHECK_GAP;
227*0Sstevel@tonic-gate }
228*0Sstevel@tonic-gate 
229*0Sstevel@tonic-gate /*
230*0Sstevel@tonic-gate  * bsd_check()
231*0Sstevel@tonic-gate  *
232*0Sstevel@tonic-gate  * If the dictionary is full, then see if it is time to reset it.
233*0Sstevel@tonic-gate  *
234*0Sstevel@tonic-gate  * Compute the compression ratio using fixed-point arithmetic
235*0Sstevel@tonic-gate  * with 8 fractional bits.
236*0Sstevel@tonic-gate  *
237*0Sstevel@tonic-gate  * Since we have an infinite stream instead of a single file,
238*0Sstevel@tonic-gate  * watch only the local compression ratio.
239*0Sstevel@tonic-gate  *
240*0Sstevel@tonic-gate  * Since both peers must reset the dictionary at the same time even in
241*0Sstevel@tonic-gate  * the absence of CLEAR codes (while packets are incompressible), they
242*0Sstevel@tonic-gate  * must compute the same ratio.
243*0Sstevel@tonic-gate  */
244*0Sstevel@tonic-gate static int				/* 1=output CLEAR */
245*0Sstevel@tonic-gate bsd_check(struct bsd_db *db)
246*0Sstevel@tonic-gate {
247*0Sstevel@tonic-gate 	uint_t	new_ratio;
248*0Sstevel@tonic-gate 
249*0Sstevel@tonic-gate 	if (db->in_count >= db->checkpoint) {
250*0Sstevel@tonic-gate 
251*0Sstevel@tonic-gate 		/*
252*0Sstevel@tonic-gate 		 * age the ratio by limiting the size of the counts
253*0Sstevel@tonic-gate 		 */
254*0Sstevel@tonic-gate 		if (db->in_count >= RATIO_MAX || db->bytes_out >= RATIO_MAX) {
255*0Sstevel@tonic-gate 			db->in_count -= db->in_count/4;
256*0Sstevel@tonic-gate 			db->bytes_out -= db->bytes_out/4;
257*0Sstevel@tonic-gate 		}
258*0Sstevel@tonic-gate 
259*0Sstevel@tonic-gate 		db->checkpoint = db->in_count + CHECK_GAP;
260*0Sstevel@tonic-gate 
261*0Sstevel@tonic-gate 		if (db->max_ent >= db->maxmaxcode) {
262*0Sstevel@tonic-gate 
263*0Sstevel@tonic-gate 			/*
264*0Sstevel@tonic-gate 			 * Reset the dictionary only if the ratio is worse,
265*0Sstevel@tonic-gate 			 * or if it looks as if it has been poisoned
266*0Sstevel@tonic-gate 			 * by incompressible data.
267*0Sstevel@tonic-gate 			 *
268*0Sstevel@tonic-gate 			 * This does not overflow, because
269*0Sstevel@tonic-gate 			 * db->in_count <= RATIO_MAX.
270*0Sstevel@tonic-gate 			 */
271*0Sstevel@tonic-gate 			new_ratio = db->in_count << RATIO_SCALE_LOG;
272*0Sstevel@tonic-gate 
273*0Sstevel@tonic-gate 			if (db->bytes_out != 0) {
274*0Sstevel@tonic-gate 				new_ratio /= db->bytes_out;
275*0Sstevel@tonic-gate 			}
276*0Sstevel@tonic-gate 
277*0Sstevel@tonic-gate 			if (new_ratio < db->ratio ||
278*0Sstevel@tonic-gate 						new_ratio < 1 * RATIO_SCALE) {
279*0Sstevel@tonic-gate 				bsd_clear(db);
280*0Sstevel@tonic-gate 				return (1);
281*0Sstevel@tonic-gate 			}
282*0Sstevel@tonic-gate 
283*0Sstevel@tonic-gate 			db->ratio = new_ratio;
284*0Sstevel@tonic-gate 		}
285*0Sstevel@tonic-gate 	}
286*0Sstevel@tonic-gate 
287*0Sstevel@tonic-gate 	return (0);
288*0Sstevel@tonic-gate }
289*0Sstevel@tonic-gate 
290*0Sstevel@tonic-gate /*
291*0Sstevel@tonic-gate  * bsd_comp_stats()
292*0Sstevel@tonic-gate  *
293*0Sstevel@tonic-gate  * Return statistics.
294*0Sstevel@tonic-gate  */
295*0Sstevel@tonic-gate static void
296*0Sstevel@tonic-gate bsd_comp_stats(void *state, struct compstat *stats)
297*0Sstevel@tonic-gate {
298*0Sstevel@tonic-gate 	struct bsd_db	*db = (struct bsd_db *)state;
299*0Sstevel@tonic-gate 	uint_t		out;
300*0Sstevel@tonic-gate 
301*0Sstevel@tonic-gate 	stats->unc_bytes = db->uncomp_bytes;
302*0Sstevel@tonic-gate 	stats->unc_packets = db->uncomp_count;
303*0Sstevel@tonic-gate 	stats->comp_bytes = db->comp_bytes;
304*0Sstevel@tonic-gate 	stats->comp_packets = db->comp_count;
305*0Sstevel@tonic-gate 	stats->inc_bytes = db->incomp_bytes;
306*0Sstevel@tonic-gate 	stats->inc_packets = db->incomp_count;
307*0Sstevel@tonic-gate 	stats->ratio = db->in_count;
308*0Sstevel@tonic-gate 
309*0Sstevel@tonic-gate 	out = db->bytes_out;
310*0Sstevel@tonic-gate 
311*0Sstevel@tonic-gate 	if (stats->ratio <= 0x7fffff) {
312*0Sstevel@tonic-gate 		stats->ratio <<= 8;
313*0Sstevel@tonic-gate 	} else {
314*0Sstevel@tonic-gate 		out >>= 8;
315*0Sstevel@tonic-gate 	}
316*0Sstevel@tonic-gate 
317*0Sstevel@tonic-gate 	if (out != 0) {
318*0Sstevel@tonic-gate 		stats->ratio /= out;
319*0Sstevel@tonic-gate 	}
320*0Sstevel@tonic-gate }
321*0Sstevel@tonic-gate 
322*0Sstevel@tonic-gate /*
323*0Sstevel@tonic-gate  * bsd_reset()
324*0Sstevel@tonic-gate  *
325*0Sstevel@tonic-gate  * Reset state, as on a CCP ResetReq.
326*0Sstevel@tonic-gate  */
327*0Sstevel@tonic-gate static void
328*0Sstevel@tonic-gate bsd_reset(void *state)
329*0Sstevel@tonic-gate {
330*0Sstevel@tonic-gate 	struct bsd_db	*db = (struct bsd_db *)state;
331*0Sstevel@tonic-gate 
332*0Sstevel@tonic-gate 	if (db->hsize != 0) {
333*0Sstevel@tonic-gate 		db->seqno = 0;
334*0Sstevel@tonic-gate 
335*0Sstevel@tonic-gate 		bsd_clear(db);
336*0Sstevel@tonic-gate 
337*0Sstevel@tonic-gate 		db->clear_count = 0;
338*0Sstevel@tonic-gate 	}
339*0Sstevel@tonic-gate }
340*0Sstevel@tonic-gate 
341*0Sstevel@tonic-gate /*
342*0Sstevel@tonic-gate  * bsd_alloc()
343*0Sstevel@tonic-gate  *
344*0Sstevel@tonic-gate  * Allocate space for a (de) compressor.
345*0Sstevel@tonic-gate  */
346*0Sstevel@tonic-gate static void *
347*0Sstevel@tonic-gate bsd_alloc(uchar_t *options, int opt_len, int decomp)
348*0Sstevel@tonic-gate {
349*0Sstevel@tonic-gate 	int		bits;
350*0Sstevel@tonic-gate 	uint_t		newlen;
351*0Sstevel@tonic-gate 	uint_t		hsize;
352*0Sstevel@tonic-gate 	uint_t		hshift;
353*0Sstevel@tonic-gate 	uint_t		maxmaxcode;
354*0Sstevel@tonic-gate 	uint_t		ilen;
355*0Sstevel@tonic-gate 	struct bsd_db	*db;
356*0Sstevel@tonic-gate 
357*0Sstevel@tonic-gate 	if (opt_len != 3 ||
358*0Sstevel@tonic-gate 		options[0] != CI_BSD_COMPRESS ||
359*0Sstevel@tonic-gate 		options[1] != 3 ||
360*0Sstevel@tonic-gate 		BSD_VERSION(options[2]) != BSD_CURRENT_VERSION) {
361*0Sstevel@tonic-gate 
362*0Sstevel@tonic-gate 		return (NULL);
363*0Sstevel@tonic-gate 	}
364*0Sstevel@tonic-gate 
365*0Sstevel@tonic-gate 	bits = BSD_NBITS(options[2]);
366*0Sstevel@tonic-gate 
367*0Sstevel@tonic-gate 	switch (bits) {
368*0Sstevel@tonic-gate 
369*0Sstevel@tonic-gate 	case 9:				/* needs 82152 for both directions */
370*0Sstevel@tonic-gate 	case 10:			/* needs 84144 */
371*0Sstevel@tonic-gate 	case 11:			/* needs 88240 */
372*0Sstevel@tonic-gate 	case 12:			/* needs 96432 */
373*0Sstevel@tonic-gate 
374*0Sstevel@tonic-gate 		hsize = 5003;
375*0Sstevel@tonic-gate 		hshift = 4;
376*0Sstevel@tonic-gate 
377*0Sstevel@tonic-gate 		break;
378*0Sstevel@tonic-gate 
379*0Sstevel@tonic-gate 	case 13:			/* needs 176784 */
380*0Sstevel@tonic-gate 
381*0Sstevel@tonic-gate 		hsize = 9001;
382*0Sstevel@tonic-gate 		hshift = 5;
383*0Sstevel@tonic-gate 
384*0Sstevel@tonic-gate 		break;
385*0Sstevel@tonic-gate 
386*0Sstevel@tonic-gate 	case 14:			/* needs 353744 */
387*0Sstevel@tonic-gate 
388*0Sstevel@tonic-gate 		hsize = 18013;
389*0Sstevel@tonic-gate 		hshift = 6;
390*0Sstevel@tonic-gate 
391*0Sstevel@tonic-gate 		break;
392*0Sstevel@tonic-gate 
393*0Sstevel@tonic-gate 	case 15:			/* needs 691440 */
394*0Sstevel@tonic-gate 
395*0Sstevel@tonic-gate 		hsize = 35023;
396*0Sstevel@tonic-gate 		hshift = 7;
397*0Sstevel@tonic-gate 
398*0Sstevel@tonic-gate 		break;
399*0Sstevel@tonic-gate 
400*0Sstevel@tonic-gate 	/* XXX: this falls thru - it was originally commented */
401*0Sstevel@tonic-gate 	case 16:			/* needs 1366160--far too much, */
402*0Sstevel@tonic-gate 		/* hsize = 69001; */	/* and 69001 is too big for cptr */
403*0Sstevel@tonic-gate 		/* hshift = 8; */	/* in struct bsd_db */
404*0Sstevel@tonic-gate 		/* break; */
405*0Sstevel@tonic-gate 
406*0Sstevel@tonic-gate 	default:
407*0Sstevel@tonic-gate 
408*0Sstevel@tonic-gate 		return (NULL);
409*0Sstevel@tonic-gate 	}
410*0Sstevel@tonic-gate 
411*0Sstevel@tonic-gate 	maxmaxcode = MAXCODE(bits);
412*0Sstevel@tonic-gate 	ilen = newlen = sizeof (*db) + (hsize-1) * sizeof (db->dict[0]);
413*0Sstevel@tonic-gate 	if (decomp)
414*0Sstevel@tonic-gate 		newlen += (maxmaxcode+1) * sizeof (db->lens[0]);
415*0Sstevel@tonic-gate 	db = (struct bsd_db *)kmem_alloc(newlen, KM_NOSLEEP);
416*0Sstevel@tonic-gate 	if (!db) {
417*0Sstevel@tonic-gate 		return (NULL);
418*0Sstevel@tonic-gate 	}
419*0Sstevel@tonic-gate 
420*0Sstevel@tonic-gate 	bzero(db, sizeof (*db) - sizeof (db->dict));
421*0Sstevel@tonic-gate 
422*0Sstevel@tonic-gate 	if (!decomp) {
423*0Sstevel@tonic-gate 		db->lens = NULL;
424*0Sstevel@tonic-gate 	} else {
425*0Sstevel@tonic-gate 		db->lens = (ushort_t *)((caddr_t)db + ilen);
426*0Sstevel@tonic-gate 	}
427*0Sstevel@tonic-gate 
428*0Sstevel@tonic-gate 	db->totlen = newlen;
429*0Sstevel@tonic-gate 	db->hsize = hsize;
430*0Sstevel@tonic-gate 	db->hshift = (uchar_t)hshift;
431*0Sstevel@tonic-gate 	db->maxmaxcode = maxmaxcode;
432*0Sstevel@tonic-gate 	db->maxbits = (uchar_t)bits;
433*0Sstevel@tonic-gate 
434*0Sstevel@tonic-gate 	return ((void *)db);
435*0Sstevel@tonic-gate }
436*0Sstevel@tonic-gate 
437*0Sstevel@tonic-gate /*
438*0Sstevel@tonic-gate  * bsd_free()
439*0Sstevel@tonic-gate  */
440*0Sstevel@tonic-gate static void
441*0Sstevel@tonic-gate bsd_free(void *state)
442*0Sstevel@tonic-gate {
443*0Sstevel@tonic-gate 	struct bsd_db	*db = (struct bsd_db *)state;
444*0Sstevel@tonic-gate 
445*0Sstevel@tonic-gate 	if (db->hsize != 0) {
446*0Sstevel@tonic-gate 		/* XXX feeble attempt to catch bad references. */
447*0Sstevel@tonic-gate 		db->hsize = 0;
448*0Sstevel@tonic-gate 
449*0Sstevel@tonic-gate 		kmem_free(db, db->totlen);
450*0Sstevel@tonic-gate 	}
451*0Sstevel@tonic-gate }
452*0Sstevel@tonic-gate 
453*0Sstevel@tonic-gate /*
454*0Sstevel@tonic-gate  * bsd_comp_alloc()
455*0Sstevel@tonic-gate  */
456*0Sstevel@tonic-gate static void *
457*0Sstevel@tonic-gate bsd_comp_alloc(uchar_t *options, int opt_len)
458*0Sstevel@tonic-gate {
459*0Sstevel@tonic-gate 	return (bsd_alloc(options, opt_len, 0));
460*0Sstevel@tonic-gate }
461*0Sstevel@tonic-gate 
462*0Sstevel@tonic-gate /*
463*0Sstevel@tonic-gate  * bsd_decomp_alloc()
464*0Sstevel@tonic-gate  */
465*0Sstevel@tonic-gate static void *
466*0Sstevel@tonic-gate bsd_decomp_alloc(uchar_t *options, int opt_len)
467*0Sstevel@tonic-gate {
468*0Sstevel@tonic-gate 	return (bsd_alloc(options, opt_len, 1));
469*0Sstevel@tonic-gate }
470*0Sstevel@tonic-gate 
471*0Sstevel@tonic-gate /*
472*0Sstevel@tonic-gate  * bsd_init()
473*0Sstevel@tonic-gate  *
474*0Sstevel@tonic-gate  * Initialize the database.
475*0Sstevel@tonic-gate  */
476*0Sstevel@tonic-gate static int
477*0Sstevel@tonic-gate bsd_init(struct bsd_db *db, uchar_t *options, int opt_len, int unit,
478*0Sstevel@tonic-gate 	int hdrlen, int mru, int debug, int decomp)
479*0Sstevel@tonic-gate {
480*0Sstevel@tonic-gate 	int	i;
481*0Sstevel@tonic-gate 
482*0Sstevel@tonic-gate 	if (db->hsize == 0 || opt_len < CILEN_BSD_COMPRESS ||
483*0Sstevel@tonic-gate 		options[0] != CI_BSD_COMPRESS ||
484*0Sstevel@tonic-gate 		options[1] != CILEN_BSD_COMPRESS ||
485*0Sstevel@tonic-gate 		BSD_VERSION(options[2]) != BSD_CURRENT_VERSION ||
486*0Sstevel@tonic-gate 		BSD_NBITS(options[2]) != db->maxbits ||
487*0Sstevel@tonic-gate 		decomp && db->lens == NULL) {
488*0Sstevel@tonic-gate 
489*0Sstevel@tonic-gate 		return (0);
490*0Sstevel@tonic-gate 	}
491*0Sstevel@tonic-gate 
492*0Sstevel@tonic-gate 	if (decomp) {
493*0Sstevel@tonic-gate 		i = LAST + 1;
494*0Sstevel@tonic-gate 
495*0Sstevel@tonic-gate 		while (i != 0) {
496*0Sstevel@tonic-gate 			db->lens[--i] = 1;
497*0Sstevel@tonic-gate 		}
498*0Sstevel@tonic-gate 	}
499*0Sstevel@tonic-gate 
500*0Sstevel@tonic-gate 	i = db->hsize;
501*0Sstevel@tonic-gate 
502*0Sstevel@tonic-gate 	while (i != 0) {
503*0Sstevel@tonic-gate 		db->dict[--i].codem1 = BADCODEM1;
504*0Sstevel@tonic-gate 		db->dict[i].cptr = 0;
505*0Sstevel@tonic-gate 	}
506*0Sstevel@tonic-gate 
507*0Sstevel@tonic-gate 	db->unit = unit;
508*0Sstevel@tonic-gate 	db->hdrlen = hdrlen;
509*0Sstevel@tonic-gate 	db->mru = (ushort_t)mru;
510*0Sstevel@tonic-gate 
511*0Sstevel@tonic-gate 	if (debug) {
512*0Sstevel@tonic-gate 		db->flags |= DS_DEBUG;
513*0Sstevel@tonic-gate 	}
514*0Sstevel@tonic-gate 
515*0Sstevel@tonic-gate 	bsd_reset(db);
516*0Sstevel@tonic-gate 
517*0Sstevel@tonic-gate 	return (1);
518*0Sstevel@tonic-gate }
519*0Sstevel@tonic-gate 
520*0Sstevel@tonic-gate /*
521*0Sstevel@tonic-gate  * bsd_comp_init()
522*0Sstevel@tonic-gate  */
523*0Sstevel@tonic-gate static int
524*0Sstevel@tonic-gate bsd_comp_init(void *state, uchar_t *options, int opt_len, int unit, int hdrlen,
525*0Sstevel@tonic-gate 	int debug)
526*0Sstevel@tonic-gate {
527*0Sstevel@tonic-gate 	return (bsd_init((struct bsd_db *)state, options, opt_len,
528*0Sstevel@tonic-gate 						unit, hdrlen, 0, debug, 0));
529*0Sstevel@tonic-gate }
530*0Sstevel@tonic-gate 
531*0Sstevel@tonic-gate /*
532*0Sstevel@tonic-gate  * bsd_decomp_init()
533*0Sstevel@tonic-gate  */
534*0Sstevel@tonic-gate static int
535*0Sstevel@tonic-gate bsd_decomp_init(void *state, uchar_t *options, int opt_len, int unit,
536*0Sstevel@tonic-gate 	int hdrlen, int mru, int debug)
537*0Sstevel@tonic-gate {
538*0Sstevel@tonic-gate 	return (bsd_init((struct bsd_db *)state, options, opt_len,
539*0Sstevel@tonic-gate 						unit, hdrlen, mru, debug, 1));
540*0Sstevel@tonic-gate }
541*0Sstevel@tonic-gate 
542*0Sstevel@tonic-gate 
543*0Sstevel@tonic-gate /*
544*0Sstevel@tonic-gate  * bsd_compress()
545*0Sstevel@tonic-gate  *
546*0Sstevel@tonic-gate  * compress a packet
547*0Sstevel@tonic-gate  *	One change from the BSD compress command is that when the
548*0Sstevel@tonic-gate  *	code size expands, we do not output a bunch of padding.
549*0Sstevel@tonic-gate  *
550*0Sstevel@tonic-gate  * N.B. at present, we ignore the hdrlen specified in the comp_init call.
551*0Sstevel@tonic-gate  */
552*0Sstevel@tonic-gate static int			/* new slen */
553*0Sstevel@tonic-gate bsd_compress(void *state, mblk_t **mretp, mblk_t *mp, int slen,	int maxolen)
554*0Sstevel@tonic-gate {
555*0Sstevel@tonic-gate 	struct bsd_db	*db = (struct bsd_db *)state;
556*0Sstevel@tonic-gate 	int		hshift = db->hshift;
557*0Sstevel@tonic-gate 	uint_t		max_ent = db->max_ent;
558*0Sstevel@tonic-gate 	uint_t		n_bits = db->n_bits;
559*0Sstevel@tonic-gate 	uint_t		bitno = 32;
560*0Sstevel@tonic-gate 	uint32_t	accm = 0;
561*0Sstevel@tonic-gate 	uint32_t	fcode;
562*0Sstevel@tonic-gate 	struct bsd_dict	*dictp;
563*0Sstevel@tonic-gate 	uchar_t		c;
564*0Sstevel@tonic-gate 	int		hval;
565*0Sstevel@tonic-gate 	int		disp;
566*0Sstevel@tonic-gate 	int		ent;
567*0Sstevel@tonic-gate 	int		ilen = slen - (PPP_HDRLEN-1);
568*0Sstevel@tonic-gate 	mblk_t		*mret;
569*0Sstevel@tonic-gate 	uchar_t		*rptr, *rmax;
570*0Sstevel@tonic-gate 	uchar_t		*wptr;
571*0Sstevel@tonic-gate 	uchar_t		*cp_end;
572*0Sstevel@tonic-gate 	int		olen;
573*0Sstevel@tonic-gate 	mblk_t		*m;
574*0Sstevel@tonic-gate 	mblk_t		**mnp;
575*0Sstevel@tonic-gate #if defined(lint) || defined(_lint)
576*0Sstevel@tonic-gate 	uchar_t		hdlcaddr, hdlcctl;
577*0Sstevel@tonic-gate #else
578*0Sstevel@tonic-gate 	int		hdlcaddr, hdlcctl;
579*0Sstevel@tonic-gate #endif
580*0Sstevel@tonic-gate 
581*0Sstevel@tonic-gate #define	PUTBYTE(v) {						\
582*0Sstevel@tonic-gate 	if (wptr) {						\
583*0Sstevel@tonic-gate 		*wptr++ = (v);					\
584*0Sstevel@tonic-gate 		if (wptr >= cp_end) {				\
585*0Sstevel@tonic-gate 			m->b_wptr = wptr;			\
586*0Sstevel@tonic-gate 			m = m->b_cont;				\
587*0Sstevel@tonic-gate 			if (m) {				\
588*0Sstevel@tonic-gate 				wptr = m->b_wptr;		\
589*0Sstevel@tonic-gate 				cp_end = m->b_datap->db_lim;	\
590*0Sstevel@tonic-gate 			} else {				\
591*0Sstevel@tonic-gate 				wptr = NULL;			\
592*0Sstevel@tonic-gate 			}					\
593*0Sstevel@tonic-gate 		}						\
594*0Sstevel@tonic-gate 	}							\
595*0Sstevel@tonic-gate 	++olen;							\
596*0Sstevel@tonic-gate }
597*0Sstevel@tonic-gate 
598*0Sstevel@tonic-gate #define	OUTPUT(ent) {						\
599*0Sstevel@tonic-gate 	bitno -= n_bits;					\
600*0Sstevel@tonic-gate 	accm |= ((ent) << bitno);				\
601*0Sstevel@tonic-gate 	do {							\
602*0Sstevel@tonic-gate 		PUTBYTE(accm >> 24);				\
603*0Sstevel@tonic-gate 		accm <<= 8;					\
604*0Sstevel@tonic-gate 		bitno += 8;					\
605*0Sstevel@tonic-gate 	} while (bitno <= 24);					\
606*0Sstevel@tonic-gate }
607*0Sstevel@tonic-gate 
608*0Sstevel@tonic-gate #define	ADJRPTR() {						\
609*0Sstevel@tonic-gate 	if (rptr != NULL) {					\
610*0Sstevel@tonic-gate 		while (rptr >= rmax) {				\
611*0Sstevel@tonic-gate 			if ((mp = mp->b_cont) == NULL) {	\
612*0Sstevel@tonic-gate 				rptr = NULL;			\
613*0Sstevel@tonic-gate 				break;				\
614*0Sstevel@tonic-gate 			}					\
615*0Sstevel@tonic-gate 			rptr = mp->b_rptr;			\
616*0Sstevel@tonic-gate 			rmax = mp->b_wptr;			\
617*0Sstevel@tonic-gate 		}						\
618*0Sstevel@tonic-gate 	}							\
619*0Sstevel@tonic-gate }
620*0Sstevel@tonic-gate 
621*0Sstevel@tonic-gate #define	GETBYTE(v) {						\
622*0Sstevel@tonic-gate 	if (rptr != NULL) {					\
623*0Sstevel@tonic-gate 		(v) = *rptr++;					\
624*0Sstevel@tonic-gate 	}							\
625*0Sstevel@tonic-gate }
626*0Sstevel@tonic-gate 
627*0Sstevel@tonic-gate 	if (db->hsize == 0)
628*0Sstevel@tonic-gate 		return (-1);
629*0Sstevel@tonic-gate 
630*0Sstevel@tonic-gate 	/*
631*0Sstevel@tonic-gate 	 * First get the protocol and check that we're
632*0Sstevel@tonic-gate 	 * interested in this packet.
633*0Sstevel@tonic-gate 	 */
634*0Sstevel@tonic-gate 	*mretp = NULL;
635*0Sstevel@tonic-gate 	rptr = mp->b_rptr;
636*0Sstevel@tonic-gate 	rmax = mp->b_wptr;
637*0Sstevel@tonic-gate 
638*0Sstevel@tonic-gate 	/* We CANNOT do a pullup here; it's not our buffer to toy with. */
639*0Sstevel@tonic-gate 	ADJRPTR();
640*0Sstevel@tonic-gate 	GETBYTE(hdlcaddr);
641*0Sstevel@tonic-gate 	ADJRPTR();
642*0Sstevel@tonic-gate 	GETBYTE(hdlcctl);
643*0Sstevel@tonic-gate 	ADJRPTR();
644*0Sstevel@tonic-gate 	GETBYTE(ent);
645*0Sstevel@tonic-gate 	ADJRPTR();
646*0Sstevel@tonic-gate 
647*0Sstevel@tonic-gate 	/*
648*0Sstevel@tonic-gate 	 * Per RFC 1977, the protocol field must be compressed using a
649*0Sstevel@tonic-gate 	 * PFC-like procedure.  Also, all protocols between 0000-3FFF
650*0Sstevel@tonic-gate 	 * except the two compression protocols must be LZ compressed.
651*0Sstevel@tonic-gate 	 */
652*0Sstevel@tonic-gate 	if (ent == 0) {
653*0Sstevel@tonic-gate 		GETBYTE(ent);
654*0Sstevel@tonic-gate 		if (rptr == NULL || ent == PPP_COMP || ent == PPP_COMPFRAG)
655*0Sstevel@tonic-gate 			return (0);
656*0Sstevel@tonic-gate 	} else {
657*0Sstevel@tonic-gate 		if (ent > 0x3F)
658*0Sstevel@tonic-gate 			return (0);
659*0Sstevel@tonic-gate 		ilen++;
660*0Sstevel@tonic-gate 	}
661*0Sstevel@tonic-gate 
662*0Sstevel@tonic-gate 	/*
663*0Sstevel@tonic-gate 	 * Don't generate compressed packets that are larger than the
664*0Sstevel@tonic-gate 	 * source (uncompressed) packet.
665*0Sstevel@tonic-gate 	 */
666*0Sstevel@tonic-gate 	if (maxolen > slen) {
667*0Sstevel@tonic-gate 		maxolen = slen;
668*0Sstevel@tonic-gate 	}
669*0Sstevel@tonic-gate 	if (maxolen < 6)
670*0Sstevel@tonic-gate 		maxolen = 6;
671*0Sstevel@tonic-gate 
672*0Sstevel@tonic-gate 	/*
673*0Sstevel@tonic-gate 	 * Allocate enough message blocks to give maxolen total space
674*0Sstevel@tonic-gate 	 */
675*0Sstevel@tonic-gate 	mnp = &mret;
676*0Sstevel@tonic-gate 	for (olen = maxolen; olen > 0; ) {
677*0Sstevel@tonic-gate 
678*0Sstevel@tonic-gate 		m = allocb((olen < 4096? olen: 4096), BPRI_MED);
679*0Sstevel@tonic-gate 
680*0Sstevel@tonic-gate 		*mnp = m;
681*0Sstevel@tonic-gate 		if (m == NULL) {
682*0Sstevel@tonic-gate 			if (mnp == &mret)
683*0Sstevel@tonic-gate 				return (0);
684*0Sstevel@tonic-gate 			/* We allocated some; hope for the best. */
685*0Sstevel@tonic-gate 			break;
686*0Sstevel@tonic-gate 		}
687*0Sstevel@tonic-gate 
688*0Sstevel@tonic-gate 		mnp = &m->b_cont;
689*0Sstevel@tonic-gate 		olen -= m->b_datap->db_lim - m->b_wptr;
690*0Sstevel@tonic-gate 	}
691*0Sstevel@tonic-gate 
692*0Sstevel@tonic-gate 	*mnp = NULL;
693*0Sstevel@tonic-gate 
694*0Sstevel@tonic-gate 	m = mret;
695*0Sstevel@tonic-gate 	wptr = m->b_wptr;
696*0Sstevel@tonic-gate 	cp_end = m->b_datap->db_lim;
697*0Sstevel@tonic-gate 
698*0Sstevel@tonic-gate 	olen = 0;
699*0Sstevel@tonic-gate 
700*0Sstevel@tonic-gate 	/*
701*0Sstevel@tonic-gate 	 * Copy the PPP header over, changing the protocol,
702*0Sstevel@tonic-gate 	 * and install the 2-byte sequence number
703*0Sstevel@tonic-gate 	 */
704*0Sstevel@tonic-gate 	*wptr++ = hdlcaddr;
705*0Sstevel@tonic-gate 	*wptr++ = hdlcctl;
706*0Sstevel@tonic-gate 	*wptr++ = PPP_COMP>>8;		/* change the protocol */
707*0Sstevel@tonic-gate 	*wptr++ = PPP_COMP;
708*0Sstevel@tonic-gate 	*wptr++ = db->seqno >> 8;
709*0Sstevel@tonic-gate 	*wptr++ = db->seqno;
710*0Sstevel@tonic-gate 
711*0Sstevel@tonic-gate #ifdef DEBUG
712*0Sstevel@tonic-gate 	/*
713*0Sstevel@tonic-gate 	 * If testing output, just garbling the sequence here does the
714*0Sstevel@tonic-gate 	 * trick.
715*0Sstevel@tonic-gate 	 */
716*0Sstevel@tonic-gate 	if ((db->flags & DS_TESTOUT) && (db->seqno % 100) == 50)
717*0Sstevel@tonic-gate 		wptr[-1] ^= 0xAA;
718*0Sstevel@tonic-gate #endif
719*0Sstevel@tonic-gate 
720*0Sstevel@tonic-gate 	++db->seqno;
721*0Sstevel@tonic-gate 
722*0Sstevel@tonic-gate 	for (;;) {
723*0Sstevel@tonic-gate 		ADJRPTR();
724*0Sstevel@tonic-gate 		if (rptr == NULL)
725*0Sstevel@tonic-gate 			break;
726*0Sstevel@tonic-gate 
727*0Sstevel@tonic-gate 		GETBYTE(c);
728*0Sstevel@tonic-gate 
729*0Sstevel@tonic-gate 		fcode = BSD_KEY(ent, c);
730*0Sstevel@tonic-gate 		hval = BSD_HASH(ent, c, hshift);
731*0Sstevel@tonic-gate 
732*0Sstevel@tonic-gate 		dictp = &db->dict[hval];
733*0Sstevel@tonic-gate 
734*0Sstevel@tonic-gate 		/*
735*0Sstevel@tonic-gate 		 * Validate and then check the entry
736*0Sstevel@tonic-gate 		 */
737*0Sstevel@tonic-gate 		if (dictp->codem1 >= max_ent) {
738*0Sstevel@tonic-gate 			goto nomatch;
739*0Sstevel@tonic-gate 		}
740*0Sstevel@tonic-gate 
741*0Sstevel@tonic-gate 		if (dictp->f.fcode == fcode) {
742*0Sstevel@tonic-gate 			ent = dictp->codem1+1;
743*0Sstevel@tonic-gate 
744*0Sstevel@tonic-gate 			/*
745*0Sstevel@tonic-gate 			 * found (prefix,suffix)
746*0Sstevel@tonic-gate 			 */
747*0Sstevel@tonic-gate 			continue;
748*0Sstevel@tonic-gate 		}
749*0Sstevel@tonic-gate 
750*0Sstevel@tonic-gate 		/*
751*0Sstevel@tonic-gate 		 * continue probing until a match or invalid entry
752*0Sstevel@tonic-gate 		 */
753*0Sstevel@tonic-gate 		disp = (hval == 0) ? 1 : hval;
754*0Sstevel@tonic-gate 
755*0Sstevel@tonic-gate 		do {
756*0Sstevel@tonic-gate 			hval += disp;
757*0Sstevel@tonic-gate 			if (hval >= db->hsize) {
758*0Sstevel@tonic-gate 				hval -= db->hsize;
759*0Sstevel@tonic-gate 				if (hval >= db->hsize) {
760*0Sstevel@tonic-gate 					if (db->flags & DS_DEBUG) {
761*0Sstevel@tonic-gate 						cmn_err(CE_CONT,
762*0Sstevel@tonic-gate 						    "bsd_comp%d: internal "
763*0Sstevel@tonic-gate 						    "error\n",
764*0Sstevel@tonic-gate 						    db->unit);
765*0Sstevel@tonic-gate 					}
766*0Sstevel@tonic-gate 					/* Caller will free it all */
767*0Sstevel@tonic-gate 					return (-1);
768*0Sstevel@tonic-gate 				}
769*0Sstevel@tonic-gate 			}
770*0Sstevel@tonic-gate 
771*0Sstevel@tonic-gate 			dictp = &db->dict[hval];
772*0Sstevel@tonic-gate 
773*0Sstevel@tonic-gate 			if (dictp->codem1 >= max_ent) {
774*0Sstevel@tonic-gate 				goto nomatch;
775*0Sstevel@tonic-gate 			}
776*0Sstevel@tonic-gate 		} while (dictp->f.fcode != fcode);
777*0Sstevel@tonic-gate 
778*0Sstevel@tonic-gate 		/*
779*0Sstevel@tonic-gate 		 * finally found (prefix,suffix)
780*0Sstevel@tonic-gate 		 */
781*0Sstevel@tonic-gate 		ent = dictp->codem1 + 1;
782*0Sstevel@tonic-gate 
783*0Sstevel@tonic-gate 		continue;
784*0Sstevel@tonic-gate 
785*0Sstevel@tonic-gate nomatch:
786*0Sstevel@tonic-gate 		/*
787*0Sstevel@tonic-gate 		 * output the prefix
788*0Sstevel@tonic-gate 		 */
789*0Sstevel@tonic-gate 		OUTPUT(ent);
790*0Sstevel@tonic-gate 
791*0Sstevel@tonic-gate 		/*
792*0Sstevel@tonic-gate 		 * code -> hashtable
793*0Sstevel@tonic-gate 		 */
794*0Sstevel@tonic-gate 		if (max_ent < db->maxmaxcode) {
795*0Sstevel@tonic-gate 			struct bsd_dict *dictp2;
796*0Sstevel@tonic-gate 
797*0Sstevel@tonic-gate 			/*
798*0Sstevel@tonic-gate 			 * expand code size if needed
799*0Sstevel@tonic-gate 			 */
800*0Sstevel@tonic-gate 			if (max_ent >= MAXCODE(n_bits)) {
801*0Sstevel@tonic-gate 				db->n_bits = ++n_bits;
802*0Sstevel@tonic-gate 			}
803*0Sstevel@tonic-gate 
804*0Sstevel@tonic-gate 			/*
805*0Sstevel@tonic-gate 			 * Invalidate old hash table entry using
806*0Sstevel@tonic-gate 			 * this code, and then take it over.
807*0Sstevel@tonic-gate 			 */
808*0Sstevel@tonic-gate 			dictp2 = &db->dict[max_ent+1];
809*0Sstevel@tonic-gate 
810*0Sstevel@tonic-gate 			if (db->dict[dictp2->cptr].codem1 == max_ent) {
811*0Sstevel@tonic-gate 				db->dict[dictp2->cptr].codem1 = BADCODEM1;
812*0Sstevel@tonic-gate 			}
813*0Sstevel@tonic-gate 
814*0Sstevel@tonic-gate 			dictp2->cptr = (ushort_t)hval;
815*0Sstevel@tonic-gate 			dictp->codem1 = max_ent;
816*0Sstevel@tonic-gate 			dictp->f.fcode = fcode;
817*0Sstevel@tonic-gate 
818*0Sstevel@tonic-gate 			db->max_ent = ++max_ent;
819*0Sstevel@tonic-gate 		}
820*0Sstevel@tonic-gate 
821*0Sstevel@tonic-gate 		ent = c;
822*0Sstevel@tonic-gate 	}
823*0Sstevel@tonic-gate 
824*0Sstevel@tonic-gate 	/*
825*0Sstevel@tonic-gate 	 * output the last code
826*0Sstevel@tonic-gate 	 */
827*0Sstevel@tonic-gate 	OUTPUT(ent);
828*0Sstevel@tonic-gate 
829*0Sstevel@tonic-gate 	olen += (32-bitno+7)/8;	/* count complete bytes */
830*0Sstevel@tonic-gate 
831*0Sstevel@tonic-gate 	db->bytes_out += olen;
832*0Sstevel@tonic-gate 	db->in_count += ilen;
833*0Sstevel@tonic-gate 
834*0Sstevel@tonic-gate 	if (bsd_check(db)) {
835*0Sstevel@tonic-gate 		OUTPUT(CLEAR);		/* do not count the CLEAR */
836*0Sstevel@tonic-gate 	}
837*0Sstevel@tonic-gate 
838*0Sstevel@tonic-gate 	/*
839*0Sstevel@tonic-gate 	 * Pad dribble bits of last code with ones.
840*0Sstevel@tonic-gate 	 * Do not emit a completely useless byte of ones.
841*0Sstevel@tonic-gate 	 */
842*0Sstevel@tonic-gate 	if (bitno != 32) {
843*0Sstevel@tonic-gate 		PUTBYTE((accm | (0xff << (bitno - 8))) >> 24);
844*0Sstevel@tonic-gate 	}
845*0Sstevel@tonic-gate 
846*0Sstevel@tonic-gate 	/*
847*0Sstevel@tonic-gate 	 * Increase code size if we would have without the packet
848*0Sstevel@tonic-gate 	 * boundary and as the decompressor will.
849*0Sstevel@tonic-gate 	 */
850*0Sstevel@tonic-gate 	if (max_ent >= MAXCODE(n_bits) && max_ent < db->maxmaxcode) {
851*0Sstevel@tonic-gate 		db->n_bits++;
852*0Sstevel@tonic-gate 	}
853*0Sstevel@tonic-gate 
854*0Sstevel@tonic-gate 	db->uncomp_bytes += ilen;
855*0Sstevel@tonic-gate 	++db->uncomp_count;
856*0Sstevel@tonic-gate 
857*0Sstevel@tonic-gate 	if (wptr == NULL || olen + PPP_HDRLEN + BSD_OVHD >= maxolen) {
858*0Sstevel@tonic-gate 		/*
859*0Sstevel@tonic-gate 		 * throw away the compressed stuff if it is longer
860*0Sstevel@tonic-gate 		 * than uncompressed
861*0Sstevel@tonic-gate 		 */
862*0Sstevel@tonic-gate 		freemsg(mret);
863*0Sstevel@tonic-gate 
864*0Sstevel@tonic-gate 		mret = NULL;
865*0Sstevel@tonic-gate 
866*0Sstevel@tonic-gate 		++db->incomp_count;
867*0Sstevel@tonic-gate 		db->incomp_bytes += ilen;
868*0Sstevel@tonic-gate 
869*0Sstevel@tonic-gate 	} else {
870*0Sstevel@tonic-gate 
871*0Sstevel@tonic-gate 		m->b_wptr = wptr;
872*0Sstevel@tonic-gate 		if (m->b_cont) {
873*0Sstevel@tonic-gate 			freemsg(m->b_cont);
874*0Sstevel@tonic-gate 			m->b_cont = NULL;
875*0Sstevel@tonic-gate 		}
876*0Sstevel@tonic-gate 
877*0Sstevel@tonic-gate 		++db->comp_count;
878*0Sstevel@tonic-gate 		db->comp_bytes += olen + BSD_OVHD;
879*0Sstevel@tonic-gate 	}
880*0Sstevel@tonic-gate 
881*0Sstevel@tonic-gate 	*mretp = mret;
882*0Sstevel@tonic-gate 
883*0Sstevel@tonic-gate 	return (olen + PPP_HDRLEN + BSD_OVHD);
884*0Sstevel@tonic-gate #undef OUTPUT
885*0Sstevel@tonic-gate #undef PUTBYTE
886*0Sstevel@tonic-gate }
887*0Sstevel@tonic-gate 
888*0Sstevel@tonic-gate 
889*0Sstevel@tonic-gate /*
890*0Sstevel@tonic-gate  * bsd_incomp()
891*0Sstevel@tonic-gate  *
892*0Sstevel@tonic-gate  * Update the "BSD Compress" dictionary on the receiver for
893*0Sstevel@tonic-gate  * incompressible data by pretending to compress the incoming data.
894*0Sstevel@tonic-gate  */
895*0Sstevel@tonic-gate static int
896*0Sstevel@tonic-gate bsd_incomp(void *state, mblk_t *mp)
897*0Sstevel@tonic-gate {
898*0Sstevel@tonic-gate 	struct bsd_db	*db = (struct bsd_db *)state;
899*0Sstevel@tonic-gate 	uint_t		hshift = db->hshift;
900*0Sstevel@tonic-gate 	uint_t		max_ent = db->max_ent;
901*0Sstevel@tonic-gate 	uint_t		n_bits = db->n_bits;
902*0Sstevel@tonic-gate 	struct bsd_dict	*dictp;
903*0Sstevel@tonic-gate 	uint32_t	fcode;
904*0Sstevel@tonic-gate 	uchar_t		c;
905*0Sstevel@tonic-gate 	long		hval;
906*0Sstevel@tonic-gate 	long		disp;
907*0Sstevel@tonic-gate 	int		slen;
908*0Sstevel@tonic-gate 	int		ilen;
909*0Sstevel@tonic-gate 	uint_t		bitno = 7;
910*0Sstevel@tonic-gate 	uchar_t		*rptr, *rmax;
911*0Sstevel@tonic-gate 	uint_t		ent;
912*0Sstevel@tonic-gate 
913*0Sstevel@tonic-gate 	if (db->hsize == 0)
914*0Sstevel@tonic-gate 		return (-1);
915*0Sstevel@tonic-gate 
916*0Sstevel@tonic-gate 	rptr = mp->b_rptr;
917*0Sstevel@tonic-gate 	rmax = mp->b_wptr;
918*0Sstevel@tonic-gate 	ADJRPTR();
919*0Sstevel@tonic-gate 	GETBYTE(ent);	/* address */
920*0Sstevel@tonic-gate 	ADJRPTR();
921*0Sstevel@tonic-gate 	GETBYTE(ent);	/* control */
922*0Sstevel@tonic-gate 	ADJRPTR();
923*0Sstevel@tonic-gate 	GETBYTE(ent);	/* protocol high */
924*0Sstevel@tonic-gate 	ADJRPTR();
925*0Sstevel@tonic-gate 
926*0Sstevel@tonic-gate 	/*
927*0Sstevel@tonic-gate 	 * Per RFC 1977, the protocol field must be compressed using a
928*0Sstevel@tonic-gate 	 * PFC-like procedure.  Also, all protocols between 0000-3FFF
929*0Sstevel@tonic-gate 	 * except the two compression protocols must be LZ compressed.
930*0Sstevel@tonic-gate 	 */
931*0Sstevel@tonic-gate 	ilen = 1;			/* count the protocol as 1 byte */
932*0Sstevel@tonic-gate 	if (ent == 0) {
933*0Sstevel@tonic-gate 		GETBYTE(ent);
934*0Sstevel@tonic-gate 		if (rptr == NULL || ent == PPP_COMP || ent == PPP_COMPFRAG)
935*0Sstevel@tonic-gate 			return (0);
936*0Sstevel@tonic-gate 	} else {
937*0Sstevel@tonic-gate 		if (ent > 0x3F)
938*0Sstevel@tonic-gate 			return (0);
939*0Sstevel@tonic-gate 		ilen++;
940*0Sstevel@tonic-gate 	}
941*0Sstevel@tonic-gate 
942*0Sstevel@tonic-gate 	db->seqno++;
943*0Sstevel@tonic-gate 
944*0Sstevel@tonic-gate 	for (;;) {
945*0Sstevel@tonic-gate 
946*0Sstevel@tonic-gate 		slen = mp->b_wptr - rptr;
947*0Sstevel@tonic-gate 		if (slen <= 0) {
948*0Sstevel@tonic-gate 			mp = mp->b_cont;
949*0Sstevel@tonic-gate 			if (!mp) {
950*0Sstevel@tonic-gate 				break;
951*0Sstevel@tonic-gate 			}
952*0Sstevel@tonic-gate 
953*0Sstevel@tonic-gate 			rptr = mp->b_rptr;
954*0Sstevel@tonic-gate 			continue;	/* skip zero-length buffers */
955*0Sstevel@tonic-gate 		}
956*0Sstevel@tonic-gate 
957*0Sstevel@tonic-gate 		ilen += slen;
958*0Sstevel@tonic-gate 
959*0Sstevel@tonic-gate 		do {
960*0Sstevel@tonic-gate 			c = *rptr++;
961*0Sstevel@tonic-gate 
962*0Sstevel@tonic-gate 			fcode = BSD_KEY(ent, c);
963*0Sstevel@tonic-gate 			hval = BSD_HASH(ent, c, hshift);
964*0Sstevel@tonic-gate 
965*0Sstevel@tonic-gate 			dictp = &db->dict[hval];
966*0Sstevel@tonic-gate 
967*0Sstevel@tonic-gate 			/*
968*0Sstevel@tonic-gate 			 * validate and then check the entry
969*0Sstevel@tonic-gate 			 */
970*0Sstevel@tonic-gate 			if (dictp->codem1 >= max_ent) {
971*0Sstevel@tonic-gate 				goto nomatch;
972*0Sstevel@tonic-gate 			}
973*0Sstevel@tonic-gate 
974*0Sstevel@tonic-gate 			if (dictp->f.fcode == fcode) {
975*0Sstevel@tonic-gate 				ent = dictp->codem1 + 1;
976*0Sstevel@tonic-gate 				continue;   /* found (prefix,suffix) */
977*0Sstevel@tonic-gate 			}
978*0Sstevel@tonic-gate 
979*0Sstevel@tonic-gate 			/*
980*0Sstevel@tonic-gate 			 * continue probing until a match or invalid entry
981*0Sstevel@tonic-gate 			 */
982*0Sstevel@tonic-gate 			disp = (hval == 0) ? 1 : hval;
983*0Sstevel@tonic-gate 			do {
984*0Sstevel@tonic-gate 				hval += disp;
985*0Sstevel@tonic-gate 				if (hval >= db->hsize) {
986*0Sstevel@tonic-gate 					hval -= db->hsize;
987*0Sstevel@tonic-gate 					if (hval >= db->hsize) {
988*0Sstevel@tonic-gate 						if (db->flags & DS_DEBUG) {
989*0Sstevel@tonic-gate 							cmn_err(CE_CONT,
990*0Sstevel@tonic-gate 							    "bsd_incomp%d: "
991*0Sstevel@tonic-gate 							    "internal error\n",
992*0Sstevel@tonic-gate 							    db->unit);
993*0Sstevel@tonic-gate 						}
994*0Sstevel@tonic-gate 						return (-1);
995*0Sstevel@tonic-gate 					}
996*0Sstevel@tonic-gate 				}
997*0Sstevel@tonic-gate 
998*0Sstevel@tonic-gate 				dictp = &db->dict[hval];
999*0Sstevel@tonic-gate 				if (dictp->codem1 >= max_ent) {
1000*0Sstevel@tonic-gate 					goto nomatch;
1001*0Sstevel@tonic-gate 				}
1002*0Sstevel@tonic-gate 			} while (dictp->f.fcode != fcode);
1003*0Sstevel@tonic-gate 
1004*0Sstevel@tonic-gate 			ent = dictp->codem1+1;
1005*0Sstevel@tonic-gate 			continue;	/* finally found (prefix,suffix) */
1006*0Sstevel@tonic-gate 
1007*0Sstevel@tonic-gate nomatch:				/* output (count) the prefix */
1008*0Sstevel@tonic-gate 			bitno += n_bits;
1009*0Sstevel@tonic-gate 
1010*0Sstevel@tonic-gate 			/*
1011*0Sstevel@tonic-gate 			 * code -> hashtable
1012*0Sstevel@tonic-gate 			 */
1013*0Sstevel@tonic-gate 			if (max_ent < db->maxmaxcode) {
1014*0Sstevel@tonic-gate 				struct bsd_dict *dictp2;
1015*0Sstevel@tonic-gate 
1016*0Sstevel@tonic-gate 				/*
1017*0Sstevel@tonic-gate 				 * expand code size if needed
1018*0Sstevel@tonic-gate 				 */
1019*0Sstevel@tonic-gate 				if (max_ent >= MAXCODE(n_bits)) {
1020*0Sstevel@tonic-gate 					db->n_bits = ++n_bits;
1021*0Sstevel@tonic-gate 				}
1022*0Sstevel@tonic-gate 
1023*0Sstevel@tonic-gate 				/*
1024*0Sstevel@tonic-gate 				 * Invalidate previous hash table entry
1025*0Sstevel@tonic-gate 				 * assigned this code, and then take it over.
1026*0Sstevel@tonic-gate 				 */
1027*0Sstevel@tonic-gate 				dictp2 = &db->dict[max_ent+1];
1028*0Sstevel@tonic-gate 				if (db->dict[dictp2->cptr].codem1 == max_ent) {
1029*0Sstevel@tonic-gate 					db->dict[dictp2->cptr].codem1 =
1030*0Sstevel@tonic-gate 								BADCODEM1;
1031*0Sstevel@tonic-gate 				}
1032*0Sstevel@tonic-gate 
1033*0Sstevel@tonic-gate 				dictp2->cptr = (ushort_t)hval;
1034*0Sstevel@tonic-gate 				dictp->codem1 = max_ent;
1035*0Sstevel@tonic-gate 				dictp->f.fcode = fcode;
1036*0Sstevel@tonic-gate 
1037*0Sstevel@tonic-gate 				db->max_ent = ++max_ent;
1038*0Sstevel@tonic-gate 				db->lens[max_ent] = db->lens[ent]+1;
1039*0Sstevel@tonic-gate 			}
1040*0Sstevel@tonic-gate 
1041*0Sstevel@tonic-gate 			ent = c;
1042*0Sstevel@tonic-gate 		} while (--slen != 0);
1043*0Sstevel@tonic-gate 	}
1044*0Sstevel@tonic-gate 
1045*0Sstevel@tonic-gate 	bitno += n_bits;		/* output (count) the last code */
1046*0Sstevel@tonic-gate 
1047*0Sstevel@tonic-gate 	db->bytes_out += bitno/8;
1048*0Sstevel@tonic-gate 	db->in_count += ilen;
1049*0Sstevel@tonic-gate 
1050*0Sstevel@tonic-gate 	(void) bsd_check(db);
1051*0Sstevel@tonic-gate 
1052*0Sstevel@tonic-gate 	++db->incomp_count;
1053*0Sstevel@tonic-gate 	db->incomp_bytes += ilen;
1054*0Sstevel@tonic-gate 	++db->uncomp_count;
1055*0Sstevel@tonic-gate 	db->uncomp_bytes += ilen;
1056*0Sstevel@tonic-gate 
1057*0Sstevel@tonic-gate 	/*
1058*0Sstevel@tonic-gate 	 * Increase code size if we would have without the packet
1059*0Sstevel@tonic-gate 	 * boundary and as the decompressor will.
1060*0Sstevel@tonic-gate 	 */
1061*0Sstevel@tonic-gate 	if (max_ent >= MAXCODE(n_bits) && max_ent < db->maxmaxcode) {
1062*0Sstevel@tonic-gate 		db->n_bits++;
1063*0Sstevel@tonic-gate 	}
1064*0Sstevel@tonic-gate 	return (0);
1065*0Sstevel@tonic-gate #undef ADJRPTR
1066*0Sstevel@tonic-gate }
1067*0Sstevel@tonic-gate 
1068*0Sstevel@tonic-gate 
1069*0Sstevel@tonic-gate /*
1070*0Sstevel@tonic-gate  * bsd_decompress()
1071*0Sstevel@tonic-gate  *
1072*0Sstevel@tonic-gate  * Decompress "BSD Compress"
1073*0Sstevel@tonic-gate  *
1074*0Sstevel@tonic-gate  * Because of patent problems, we return DECOMP_ERROR for errors
1075*0Sstevel@tonic-gate  * found by inspecting the input data and for system problems, but
1076*0Sstevel@tonic-gate  * DECOMP_FATALERROR for any errors which could possibly be said to
1077*0Sstevel@tonic-gate  * be being detected "after" decompression.  For DECOMP_ERROR,
1078*0Sstevel@tonic-gate  * we can issue a CCP reset-request; for DECOMP_FATALERROR, we may be
1079*0Sstevel@tonic-gate  * infringing a patent of Motorola's if we do, so we take CCP down
1080*0Sstevel@tonic-gate  * instead.
1081*0Sstevel@tonic-gate  *
1082*0Sstevel@tonic-gate  * Given that the frame has the correct sequence number and a good FCS,
1083*0Sstevel@tonic-gate  * errors such as invalid codes in the input most likely indicate a
1084*0Sstevel@tonic-gate  * bug, so we return DECOMP_FATALERROR for them in order to turn off
1085*0Sstevel@tonic-gate  * compression, even though they are detected by inspecting the input.
1086*0Sstevel@tonic-gate  */
1087*0Sstevel@tonic-gate static int
1088*0Sstevel@tonic-gate bsd_decompress(void *state, mblk_t **dmpp)
1089*0Sstevel@tonic-gate {
1090*0Sstevel@tonic-gate 	mblk_t		*cmsg = *dmpp, *mnext;
1091*0Sstevel@tonic-gate 	struct bsd_db	*db = (struct bsd_db *)state;
1092*0Sstevel@tonic-gate 	uint_t		max_ent = db->max_ent;
1093*0Sstevel@tonic-gate 	uint32_t	accm = 0;
1094*0Sstevel@tonic-gate 	uint_t		bitno = 32;		/* 1st valid bit in accm */
1095*0Sstevel@tonic-gate 	uint_t		n_bits = db->n_bits;
1096*0Sstevel@tonic-gate 	uint_t		tgtbitno = 32 - n_bits;	/* bitno when we have a code */
1097*0Sstevel@tonic-gate 	struct bsd_dict	*dictp;
1098*0Sstevel@tonic-gate 	int		explen;
1099*0Sstevel@tonic-gate 	int		seq;
1100*0Sstevel@tonic-gate 	uint_t		incode;
1101*0Sstevel@tonic-gate 	uint_t		oldcode;
1102*0Sstevel@tonic-gate 	uint_t		finchar = 0, ofinchar;
1103*0Sstevel@tonic-gate 	uchar_t		*p;
1104*0Sstevel@tonic-gate 	uchar_t		*rptr, *rmax;
1105*0Sstevel@tonic-gate 	uchar_t		*wptr, *prepos;
1106*0Sstevel@tonic-gate 	mblk_t		*dmsg;
1107*0Sstevel@tonic-gate 	mblk_t		*mret;
1108*0Sstevel@tonic-gate 	int		ilen;
1109*0Sstevel@tonic-gate 	int		dlen;
1110*0Sstevel@tonic-gate 	int		codelen;
1111*0Sstevel@tonic-gate 	int		extra;
1112*0Sstevel@tonic-gate 	int		decode_proto;
1113*0Sstevel@tonic-gate 	int		blockctr;
1114*0Sstevel@tonic-gate 	int		outlen;
1115*0Sstevel@tonic-gate #if defined(lint) || defined(_lint)
1116*0Sstevel@tonic-gate 	uchar_t		adrs, ctrl;
1117*0Sstevel@tonic-gate #else
1118*0Sstevel@tonic-gate 	int		adrs, ctrl;
1119*0Sstevel@tonic-gate #endif
1120*0Sstevel@tonic-gate 
1121*0Sstevel@tonic-gate 	/* Note: spppcomp already did a pullup to fix the first buffer. */
1122*0Sstevel@tonic-gate 	*dmpp = NULL;
1123*0Sstevel@tonic-gate 	rptr = cmsg->b_rptr;
1124*0Sstevel@tonic-gate 	rmax = cmsg->b_wptr;
1125*0Sstevel@tonic-gate 	ilen = 0;
1126*0Sstevel@tonic-gate 
1127*0Sstevel@tonic-gate 	/*
1128*0Sstevel@tonic-gate 	 * Note that we free as we go.  If we fail to decompress,
1129*0Sstevel@tonic-gate 	 * there's nothing good that the caller can do.
1130*0Sstevel@tonic-gate 	 */
1131*0Sstevel@tonic-gate #define	ADJRPTR()					\
1132*0Sstevel@tonic-gate 	while (rptr >= rmax) {				\
1133*0Sstevel@tonic-gate 		mnext = cmsg->b_cont;			\
1134*0Sstevel@tonic-gate 		freeb(cmsg);				\
1135*0Sstevel@tonic-gate 		if ((cmsg = mnext) == NULL) {		\
1136*0Sstevel@tonic-gate 			rptr = NULL;			\
1137*0Sstevel@tonic-gate 			break;				\
1138*0Sstevel@tonic-gate 		}					\
1139*0Sstevel@tonic-gate 		rptr = cmsg->b_rptr;			\
1140*0Sstevel@tonic-gate 		rmax = cmsg->b_wptr;			\
1141*0Sstevel@tonic-gate 		ilen += rmax-rptr;			\
1142*0Sstevel@tonic-gate 	}
1143*0Sstevel@tonic-gate 
1144*0Sstevel@tonic-gate 	/*
1145*0Sstevel@tonic-gate 	 * Save the address/control from the PPP header
1146*0Sstevel@tonic-gate 	 * and then get the sequence number.
1147*0Sstevel@tonic-gate 	 */
1148*0Sstevel@tonic-gate 	adrs = rptr[0];
1149*0Sstevel@tonic-gate 	ctrl = rptr[1];
1150*0Sstevel@tonic-gate 	rptr += 4;
1151*0Sstevel@tonic-gate 	ADJRPTR();
1152*0Sstevel@tonic-gate 	seq = rptr == NULL ? 0 : (*rptr++ << 8);
1153*0Sstevel@tonic-gate 	ADJRPTR();
1154*0Sstevel@tonic-gate 	if (rptr == NULL) {
1155*0Sstevel@tonic-gate 		if (db->flags & DS_DEBUG) {
1156*0Sstevel@tonic-gate 			cmn_err(CE_CONT, "bsd_decomp%d: bad buffer\n",
1157*0Sstevel@tonic-gate 			    db->unit);
1158*0Sstevel@tonic-gate 		}
1159*0Sstevel@tonic-gate 		return (DECOMP_ERROR);
1160*0Sstevel@tonic-gate 	}
1161*0Sstevel@tonic-gate 	seq |= *rptr++;
1162*0Sstevel@tonic-gate 
1163*0Sstevel@tonic-gate #ifdef DEBUG
1164*0Sstevel@tonic-gate 	/*
1165*0Sstevel@tonic-gate 	 * If testing input, just pretending the sequence is bad here
1166*0Sstevel@tonic-gate 	 * does the trick.
1167*0Sstevel@tonic-gate 	 */
1168*0Sstevel@tonic-gate 	if ((db->flags & DS_TESTIN) && (db->seqno % 300) == 101)
1169*0Sstevel@tonic-gate 		seq ^= 0x55;
1170*0Sstevel@tonic-gate #endif
1171*0Sstevel@tonic-gate 
1172*0Sstevel@tonic-gate 	/*
1173*0Sstevel@tonic-gate 	 * Check the sequence number and give up if it is not what we expect.
1174*0Sstevel@tonic-gate 	 */
1175*0Sstevel@tonic-gate 	if (db->hsize == 0 || seq != db->seqno++) {
1176*0Sstevel@tonic-gate 		freemsg(cmsg);
1177*0Sstevel@tonic-gate 		if (db->flags & DS_DEBUG) {
1178*0Sstevel@tonic-gate 			cmn_err(CE_CONT, "bsd_decomp%d: bad sequence # %d, "
1179*0Sstevel@tonic-gate 				"expected %d\n", db->unit, seq, db->seqno - 1);
1180*0Sstevel@tonic-gate 		}
1181*0Sstevel@tonic-gate 
1182*0Sstevel@tonic-gate 		return (DECOMP_ERROR);
1183*0Sstevel@tonic-gate 	}
1184*0Sstevel@tonic-gate 
1185*0Sstevel@tonic-gate 	/*
1186*0Sstevel@tonic-gate 	 * Allocate one message block to start with.
1187*0Sstevel@tonic-gate 	 */
1188*0Sstevel@tonic-gate 	if ((dmsg = allocb(DECOMP_CHUNK + db->hdrlen, BPRI_MED)) == NULL) {
1189*0Sstevel@tonic-gate 		freemsg(cmsg);
1190*0Sstevel@tonic-gate 		if (db->flags & DS_DEBUG) {
1191*0Sstevel@tonic-gate 			cmn_err(CE_CONT,
1192*0Sstevel@tonic-gate 			    "bsd_decomp%d: can't allocate first buffer\n",
1193*0Sstevel@tonic-gate 			    db->unit);
1194*0Sstevel@tonic-gate 		}
1195*0Sstevel@tonic-gate 		return (DECOMP_ERROR);
1196*0Sstevel@tonic-gate 	}
1197*0Sstevel@tonic-gate 
1198*0Sstevel@tonic-gate 	/*
1199*0Sstevel@tonic-gate 	 * Avoid an error that might cause us to allocate all available memory.
1200*0Sstevel@tonic-gate 	 * Enforce a maximum number of blocks to allocate for message. We add
1201*0Sstevel@tonic-gate 	 * a fudge factor of 5 extra blocks, in order to avoid unnecessary
1202*0Sstevel@tonic-gate 	 * DECOMP_ERROR when the code size is small (9).
1203*0Sstevel@tonic-gate 	 */
1204*0Sstevel@tonic-gate 	blockctr = ((db->mru + 32 + DECOMP_CHUNK - 1) / DECOMP_CHUNK) + 5;
1205*0Sstevel@tonic-gate 
1206*0Sstevel@tonic-gate 	mret = dmsg;
1207*0Sstevel@tonic-gate 	dmsg->b_wptr += db->hdrlen;
1208*0Sstevel@tonic-gate 	dmsg->b_rptr = wptr = dmsg->b_wptr;
1209*0Sstevel@tonic-gate 
1210*0Sstevel@tonic-gate 	/*
1211*0Sstevel@tonic-gate 	 * Insert PPP header.  This shouldn't be needed!
1212*0Sstevel@tonic-gate 	 */
1213*0Sstevel@tonic-gate 	*wptr++ = adrs;
1214*0Sstevel@tonic-gate 	*wptr++ = ctrl;
1215*0Sstevel@tonic-gate 	prepos = wptr;
1216*0Sstevel@tonic-gate 	*wptr++ = 0;
1217*0Sstevel@tonic-gate 	dmsg->b_wptr = wptr;
1218*0Sstevel@tonic-gate 
1219*0Sstevel@tonic-gate 	explen = dmsg->b_datap->db_lim - wptr;
1220*0Sstevel@tonic-gate 	oldcode = CLEAR;
1221*0Sstevel@tonic-gate 	ilen = rmax-rptr;
1222*0Sstevel@tonic-gate 
1223*0Sstevel@tonic-gate 	outlen = 0;
1224*0Sstevel@tonic-gate 	decode_proto = 1;
1225*0Sstevel@tonic-gate 	for (;;) {
1226*0Sstevel@tonic-gate 		ADJRPTR();
1227*0Sstevel@tonic-gate 		if (rptr == NULL)
1228*0Sstevel@tonic-gate 			break;
1229*0Sstevel@tonic-gate 
1230*0Sstevel@tonic-gate 		/*
1231*0Sstevel@tonic-gate 		 * Accumulate bytes until we have a complete code.
1232*0Sstevel@tonic-gate 		 * Then get the next code, relying on the 32-bit,
1233*0Sstevel@tonic-gate 		 * unsigned accm to mask the result.
1234*0Sstevel@tonic-gate 		 */
1235*0Sstevel@tonic-gate 		bitno -= 8;
1236*0Sstevel@tonic-gate 
1237*0Sstevel@tonic-gate 		accm |= *rptr++ << bitno;
1238*0Sstevel@tonic-gate 
1239*0Sstevel@tonic-gate 		if (tgtbitno < bitno) {
1240*0Sstevel@tonic-gate 			continue;
1241*0Sstevel@tonic-gate 		}
1242*0Sstevel@tonic-gate 
1243*0Sstevel@tonic-gate 		incode = accm >> tgtbitno;
1244*0Sstevel@tonic-gate 		accm <<= n_bits;
1245*0Sstevel@tonic-gate 		bitno += n_bits;
1246*0Sstevel@tonic-gate 
1247*0Sstevel@tonic-gate 		if (incode == CLEAR) {
1248*0Sstevel@tonic-gate 
1249*0Sstevel@tonic-gate 			/*
1250*0Sstevel@tonic-gate 			 * The dictionary must only be cleared at
1251*0Sstevel@tonic-gate 			 * the end of a packet.  But there could be an
1252*0Sstevel@tonic-gate 			 * empty message block at the end.
1253*0Sstevel@tonic-gate 			 */
1254*0Sstevel@tonic-gate 			ADJRPTR();
1255*0Sstevel@tonic-gate 			if (rptr != NULL) {
1256*0Sstevel@tonic-gate 				freemsg(mret);
1257*0Sstevel@tonic-gate 				freemsg(cmsg);
1258*0Sstevel@tonic-gate 				if (db->flags & DS_DEBUG) {
1259*0Sstevel@tonic-gate 					cmn_err(CE_CONT,
1260*0Sstevel@tonic-gate 					    "bsd_decomp%d: bad CLEAR\n",
1261*0Sstevel@tonic-gate 					    db->unit);
1262*0Sstevel@tonic-gate 				}
1263*0Sstevel@tonic-gate 
1264*0Sstevel@tonic-gate 				return (DECOMP_FATALERROR);
1265*0Sstevel@tonic-gate 			}
1266*0Sstevel@tonic-gate 
1267*0Sstevel@tonic-gate 			bsd_clear(db);
1268*0Sstevel@tonic-gate 			/* Have to keep cleared state variables! */
1269*0Sstevel@tonic-gate 			outlen += wptr-dmsg->b_wptr;
1270*0Sstevel@tonic-gate 			dmsg->b_wptr = wptr;
1271*0Sstevel@tonic-gate 			db->comp_bytes += ilen;
1272*0Sstevel@tonic-gate 			ilen = 0;
1273*0Sstevel@tonic-gate 			break;
1274*0Sstevel@tonic-gate 		}
1275*0Sstevel@tonic-gate 
1276*0Sstevel@tonic-gate 		/*
1277*0Sstevel@tonic-gate 		 * Special case for KwKwK string
1278*0Sstevel@tonic-gate 		 */
1279*0Sstevel@tonic-gate 		ofinchar = finchar;
1280*0Sstevel@tonic-gate 		if (incode > max_ent) {
1281*0Sstevel@tonic-gate 			if (incode > max_ent + 2 ||
1282*0Sstevel@tonic-gate 			    incode > db->maxmaxcode ||
1283*0Sstevel@tonic-gate 			    oldcode == CLEAR) {
1284*0Sstevel@tonic-gate 				freemsg(cmsg);
1285*0Sstevel@tonic-gate 				freemsg(mret);
1286*0Sstevel@tonic-gate 
1287*0Sstevel@tonic-gate 				/* probably a bug if we get here */
1288*0Sstevel@tonic-gate 				if (db->flags & DS_DEBUG) {
1289*0Sstevel@tonic-gate 					cmn_err(CE_CONT,
1290*0Sstevel@tonic-gate 					    "bsd_decomp%d: bad code 0x%x "
1291*0Sstevel@tonic-gate 					    "oldcode=0x%x ", db->unit, incode,
1292*0Sstevel@tonic-gate 					    oldcode);
1293*0Sstevel@tonic-gate 				}
1294*0Sstevel@tonic-gate 
1295*0Sstevel@tonic-gate 				return (DECOMP_FATALERROR);
1296*0Sstevel@tonic-gate 			}
1297*0Sstevel@tonic-gate 			finchar = oldcode;
1298*0Sstevel@tonic-gate 			extra = 1;
1299*0Sstevel@tonic-gate 		} else {
1300*0Sstevel@tonic-gate 			finchar = incode;
1301*0Sstevel@tonic-gate 			extra = 0;
1302*0Sstevel@tonic-gate 		}
1303*0Sstevel@tonic-gate 		codelen = db->lens[finchar];
1304*0Sstevel@tonic-gate 
1305*0Sstevel@tonic-gate 		/*
1306*0Sstevel@tonic-gate 		 * Decode this code and install it in the decompressed buffer
1307*0Sstevel@tonic-gate 		 */
1308*0Sstevel@tonic-gate 		explen -= codelen + extra;
1309*0Sstevel@tonic-gate 		if (explen < 0) {
1310*0Sstevel@tonic-gate 			/*
1311*0Sstevel@tonic-gate 			 * Allocate another message block
1312*0Sstevel@tonic-gate 			 */
1313*0Sstevel@tonic-gate 			dlen = wptr - dmsg->b_wptr;
1314*0Sstevel@tonic-gate 			outlen += dlen;
1315*0Sstevel@tonic-gate 			db->in_count += dlen;
1316*0Sstevel@tonic-gate 			dmsg->b_wptr = wptr;
1317*0Sstevel@tonic-gate 			dlen = codelen + extra;
1318*0Sstevel@tonic-gate 
1319*0Sstevel@tonic-gate 			if (dlen < DECOMP_CHUNK) {
1320*0Sstevel@tonic-gate 				dlen = DECOMP_CHUNK;
1321*0Sstevel@tonic-gate 			}
1322*0Sstevel@tonic-gate 
1323*0Sstevel@tonic-gate 			if ((--blockctr < 0) ||
1324*0Sstevel@tonic-gate 			    (dmsg->b_cont = allocb(dlen, BPRI_MED)) == NULL) {
1325*0Sstevel@tonic-gate 				freemsg(cmsg);
1326*0Sstevel@tonic-gate 				freemsg(mret);
1327*0Sstevel@tonic-gate 				if (db->flags & DS_DEBUG) {
1328*0Sstevel@tonic-gate 					cmn_err(CE_CONT,
1329*0Sstevel@tonic-gate 					    "bsd_decomp%d: %s output "
1330*0Sstevel@tonic-gate 					    "buffers; outlen %d+%d\n",
1331*0Sstevel@tonic-gate 					    db->unit,
1332*0Sstevel@tonic-gate 					    (blockctr < 0 ? "too many" :
1333*0Sstevel@tonic-gate 						"can't allocate"),
1334*0Sstevel@tonic-gate 					    outlen, dlen);
1335*0Sstevel@tonic-gate 				}
1336*0Sstevel@tonic-gate 				return (DECOMP_ERROR);
1337*0Sstevel@tonic-gate 			}
1338*0Sstevel@tonic-gate 
1339*0Sstevel@tonic-gate 			dmsg = dmsg->b_cont;
1340*0Sstevel@tonic-gate 			wptr = dmsg->b_wptr;
1341*0Sstevel@tonic-gate 			explen = dmsg->b_datap->db_lim - wptr - codelen -
1342*0Sstevel@tonic-gate 			    extra;
1343*0Sstevel@tonic-gate 		}
1344*0Sstevel@tonic-gate 
1345*0Sstevel@tonic-gate 		p = (wptr += codelen);
1346*0Sstevel@tonic-gate 
1347*0Sstevel@tonic-gate 		while (finchar > LAST) {
1348*0Sstevel@tonic-gate 			dictp = &db->dict[db->dict[finchar].cptr];
1349*0Sstevel@tonic-gate 			*--p = dictp->f.hs.suffix;
1350*0Sstevel@tonic-gate 			finchar = dictp->f.hs.prefix;
1351*0Sstevel@tonic-gate 		}
1352*0Sstevel@tonic-gate 
1353*0Sstevel@tonic-gate 		*--p = finchar;
1354*0Sstevel@tonic-gate 
1355*0Sstevel@tonic-gate 		if (decode_proto) {
1356*0Sstevel@tonic-gate 			decode_proto = 0;
1357*0Sstevel@tonic-gate 			/* Wow, is *this* ugly! */
1358*0Sstevel@tonic-gate 			if (!(finchar & 1)) {
1359*0Sstevel@tonic-gate 				if (p == prepos+1) {
1360*0Sstevel@tonic-gate 					bcopy(p, prepos, wptr-p);
1361*0Sstevel@tonic-gate 					wptr--;
1362*0Sstevel@tonic-gate 					explen++;
1363*0Sstevel@tonic-gate 					db->in_count++;
1364*0Sstevel@tonic-gate 				} else {
1365*0Sstevel@tonic-gate 					/* This is safe, but doesn't look it */
1366*0Sstevel@tonic-gate 					*prepos = *p++;
1367*0Sstevel@tonic-gate 					dmsg->b_rptr = p;
1368*0Sstevel@tonic-gate 				}
1369*0Sstevel@tonic-gate 			}
1370*0Sstevel@tonic-gate 		}
1371*0Sstevel@tonic-gate 
1372*0Sstevel@tonic-gate 		if (extra) {	/* the KwKwK case again */
1373*0Sstevel@tonic-gate 			*wptr++ = ofinchar;
1374*0Sstevel@tonic-gate 		}
1375*0Sstevel@tonic-gate 
1376*0Sstevel@tonic-gate 		/*
1377*0Sstevel@tonic-gate 		 * If not first code in a packet, and
1378*0Sstevel@tonic-gate 		 * if not out of code space, then allocate a new code.
1379*0Sstevel@tonic-gate 		 *
1380*0Sstevel@tonic-gate 		 * Keep the hash table correct so it can be used
1381*0Sstevel@tonic-gate 		 * with uncompressed packets.
1382*0Sstevel@tonic-gate 		 */
1383*0Sstevel@tonic-gate 		if (oldcode != CLEAR && max_ent < db->maxmaxcode) {
1384*0Sstevel@tonic-gate 			struct bsd_dict	*dictp2;
1385*0Sstevel@tonic-gate 			uint32_t	fcode;
1386*0Sstevel@tonic-gate 			int		hval;
1387*0Sstevel@tonic-gate 			int		disp;
1388*0Sstevel@tonic-gate 
1389*0Sstevel@tonic-gate 			fcode = BSD_KEY(oldcode, finchar);
1390*0Sstevel@tonic-gate 			hval = BSD_HASH(oldcode, finchar, db->hshift);
1391*0Sstevel@tonic-gate 
1392*0Sstevel@tonic-gate 			dictp = &db->dict[hval];
1393*0Sstevel@tonic-gate 
1394*0Sstevel@tonic-gate 			/*
1395*0Sstevel@tonic-gate 			 * look for a free hash table entry
1396*0Sstevel@tonic-gate 			 */
1397*0Sstevel@tonic-gate 			if (dictp->codem1 < max_ent) {
1398*0Sstevel@tonic-gate 				disp = (hval == 0) ? 1 : hval;
1399*0Sstevel@tonic-gate 
1400*0Sstevel@tonic-gate 				do {
1401*0Sstevel@tonic-gate 					hval += disp;
1402*0Sstevel@tonic-gate 
1403*0Sstevel@tonic-gate 					if (hval >= db->hsize) {
1404*0Sstevel@tonic-gate 						hval -= db->hsize;
1405*0Sstevel@tonic-gate 						if (hval >= db->hsize) {
1406*0Sstevel@tonic-gate 							freemsg(cmsg);
1407*0Sstevel@tonic-gate 							freemsg(mret);
1408*0Sstevel@tonic-gate 							if (db->flags &
1409*0Sstevel@tonic-gate 							    DS_DEBUG) {
1410*0Sstevel@tonic-gate 			cmn_err(CE_CONT, "bsd_decomp%d: internal error\n",
1411*0Sstevel@tonic-gate 			    db->unit);
1412*0Sstevel@tonic-gate 							}
1413*0Sstevel@tonic-gate 							return
1414*0Sstevel@tonic-gate 						    (DECOMP_FATALERROR);
1415*0Sstevel@tonic-gate 						}
1416*0Sstevel@tonic-gate 					}
1417*0Sstevel@tonic-gate 
1418*0Sstevel@tonic-gate 					dictp = &db->dict[hval];
1419*0Sstevel@tonic-gate 
1420*0Sstevel@tonic-gate 				} while (dictp->codem1 < max_ent);
1421*0Sstevel@tonic-gate 			}
1422*0Sstevel@tonic-gate 
1423*0Sstevel@tonic-gate 			/*
1424*0Sstevel@tonic-gate 			 * Invalidate previous hash table entry
1425*0Sstevel@tonic-gate 			 * assigned this code, and then take it over
1426*0Sstevel@tonic-gate 			 */
1427*0Sstevel@tonic-gate 			dictp2 = &db->dict[max_ent+1];
1428*0Sstevel@tonic-gate 
1429*0Sstevel@tonic-gate 			if (db->dict[dictp2->cptr].codem1 == max_ent) {
1430*0Sstevel@tonic-gate 				db->dict[dictp2->cptr].codem1 = BADCODEM1;
1431*0Sstevel@tonic-gate 			}
1432*0Sstevel@tonic-gate 
1433*0Sstevel@tonic-gate 			dictp2->cptr = (ushort_t)hval;
1434*0Sstevel@tonic-gate 			dictp->codem1 = max_ent;
1435*0Sstevel@tonic-gate 			dictp->f.fcode = fcode;
1436*0Sstevel@tonic-gate 
1437*0Sstevel@tonic-gate 			db->max_ent = ++max_ent;
1438*0Sstevel@tonic-gate 			db->lens[max_ent] = db->lens[oldcode]+1;
1439*0Sstevel@tonic-gate 
1440*0Sstevel@tonic-gate 			/*
1441*0Sstevel@tonic-gate 			 * Expand code size if needed
1442*0Sstevel@tonic-gate 			 */
1443*0Sstevel@tonic-gate 			if (max_ent >= MAXCODE(n_bits) &&
1444*0Sstevel@tonic-gate 						max_ent < db->maxmaxcode) {
1445*0Sstevel@tonic-gate 
1446*0Sstevel@tonic-gate 				db->n_bits = ++n_bits;
1447*0Sstevel@tonic-gate 				tgtbitno = 32-n_bits;
1448*0Sstevel@tonic-gate 			}
1449*0Sstevel@tonic-gate 		}
1450*0Sstevel@tonic-gate 
1451*0Sstevel@tonic-gate 		oldcode = incode;
1452*0Sstevel@tonic-gate 	}
1453*0Sstevel@tonic-gate 
1454*0Sstevel@tonic-gate 	dlen = wptr-dmsg->b_wptr;
1455*0Sstevel@tonic-gate 	outlen += dlen;
1456*0Sstevel@tonic-gate 	db->in_count += dlen;
1457*0Sstevel@tonic-gate 	dmsg->b_wptr = wptr;
1458*0Sstevel@tonic-gate 	db->bytes_out += ilen;
1459*0Sstevel@tonic-gate 
1460*0Sstevel@tonic-gate 	/*
1461*0Sstevel@tonic-gate 	 * Keep the checkpoint right so that incompressible packets
1462*0Sstevel@tonic-gate 	 * clear the dictionary at the right times.
1463*0Sstevel@tonic-gate 	 */
1464*0Sstevel@tonic-gate 	if (bsd_check(db) && (db->flags & DS_DEBUG)) {
1465*0Sstevel@tonic-gate 		cmn_err(CE_CONT,
1466*0Sstevel@tonic-gate 			"bsd_decomp%d: peer should have cleared dictionary\n",
1467*0Sstevel@tonic-gate 			db->unit);
1468*0Sstevel@tonic-gate 	}
1469*0Sstevel@tonic-gate 
1470*0Sstevel@tonic-gate 	++db->comp_count;
1471*0Sstevel@tonic-gate 	db->comp_bytes += ilen + BSD_OVHD;
1472*0Sstevel@tonic-gate 	++db->uncomp_count;
1473*0Sstevel@tonic-gate 	db->uncomp_bytes += outlen;
1474*0Sstevel@tonic-gate 
1475*0Sstevel@tonic-gate 	*dmpp = mret;
1476*0Sstevel@tonic-gate 
1477*0Sstevel@tonic-gate 	return (DECOMP_OK);
1478*0Sstevel@tonic-gate }
1479*0Sstevel@tonic-gate 
1480*0Sstevel@tonic-gate /* ARGSUSED */
1481*0Sstevel@tonic-gate static int
1482*0Sstevel@tonic-gate bsd_set_effort(void *xarg, void *rarg, int effortlevel)
1483*0Sstevel@tonic-gate {
1484*0Sstevel@tonic-gate #ifdef DEBUG
1485*0Sstevel@tonic-gate 	struct bsd_db *xdb = (struct bsd_db *)xarg;
1486*0Sstevel@tonic-gate 	struct bsd_db *rdb = (struct bsd_db *)rarg;
1487*0Sstevel@tonic-gate 
1488*0Sstevel@tonic-gate 	if (effortlevel == 42 || effortlevel == 2112) {
1489*0Sstevel@tonic-gate 		/* corrupt received data. */
1490*0Sstevel@tonic-gate 		if (rdb != NULL) {
1491*0Sstevel@tonic-gate 			rdb->flags |= DS_TESTIN;
1492*0Sstevel@tonic-gate 			cmn_err(CE_CONT, "bsd-comp: enabled input testing.");
1493*0Sstevel@tonic-gate 		}
1494*0Sstevel@tonic-gate 		if (effortlevel != 2112)
1495*0Sstevel@tonic-gate 			return (0);
1496*0Sstevel@tonic-gate 	}
1497*0Sstevel@tonic-gate 	if (effortlevel == 2001 || effortlevel == 2112) {
1498*0Sstevel@tonic-gate 		/* corrupt transmitted data. */
1499*0Sstevel@tonic-gate 		if (xdb != NULL) {
1500*0Sstevel@tonic-gate 			xdb->flags |= DS_TESTOUT;
1501*0Sstevel@tonic-gate 			cmn_err(CE_CONT, "bsd-comp: enabled output testing.");
1502*0Sstevel@tonic-gate 		}
1503*0Sstevel@tonic-gate 		return (0);
1504*0Sstevel@tonic-gate 	}
1505*0Sstevel@tonic-gate #endif
1506*0Sstevel@tonic-gate 	return (0);
1507*0Sstevel@tonic-gate }
1508*0Sstevel@tonic-gate #endif /* DO_BSD_COMPRESS */
1509