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