xref: /onnv-gate/usr/src/uts/common/io/ppp/spppcomp/bsd-comp.c (revision 5640:6cbb4c17a378)
10Sstevel@tonic-gate /*
2*5640Scarlsonj  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
3*5640Scarlsonj  * Use is subject to license terms.
40Sstevel@tonic-gate  *
50Sstevel@tonic-gate  * Because this code is derived from the 4.3BSD compress source:
60Sstevel@tonic-gate  *
70Sstevel@tonic-gate  * Copyright (c) 1985, 1986 The Regents of the University of California.
80Sstevel@tonic-gate  * All rights reserved.
90Sstevel@tonic-gate  *
100Sstevel@tonic-gate  * This code is derived from software contributed to Berkeley by
110Sstevel@tonic-gate  * James A. Woods, derived from original work by Spencer Thomas
120Sstevel@tonic-gate  * and Joseph Orost.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * Redistribution and use in source and binary forms, with or without
150Sstevel@tonic-gate  * modification, are permitted provided that the following conditions
160Sstevel@tonic-gate  * are met:
170Sstevel@tonic-gate  * 1. Redistributions of source code must retain the above copyright
180Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer.
190Sstevel@tonic-gate  * 2. Redistributions in binary form must reproduce the above copyright
200Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer in the
210Sstevel@tonic-gate  *    documentation and/or other materials provided with the distribution.
220Sstevel@tonic-gate  * 3. All advertising materials mentioning features or use of this software
230Sstevel@tonic-gate  *    must display the following acknowledgement:
240Sstevel@tonic-gate  *	This product includes software developed by the University of
250Sstevel@tonic-gate  *	California, Berkeley and its contributors.
260Sstevel@tonic-gate  * 4. Neither the name of the University nor the names of its contributors
270Sstevel@tonic-gate  *    may be used to endorse or promote products derived from this software
280Sstevel@tonic-gate  *    without specific prior written permission.
290Sstevel@tonic-gate  *
300Sstevel@tonic-gate  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
310Sstevel@tonic-gate  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
320Sstevel@tonic-gate  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
330Sstevel@tonic-gate  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
340Sstevel@tonic-gate  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
350Sstevel@tonic-gate  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
360Sstevel@tonic-gate  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
370Sstevel@tonic-gate  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
380Sstevel@tonic-gate  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
390Sstevel@tonic-gate  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
400Sstevel@tonic-gate  * SUCH DAMAGE.
410Sstevel@tonic-gate  */
420Sstevel@tonic-gate 
430Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
440Sstevel@tonic-gate 
450Sstevel@tonic-gate /*
460Sstevel@tonic-gate  * This version is for use with STREAMS in Solaris 2
470Sstevel@tonic-gate  *
480Sstevel@tonic-gate  * $Id: bsd-comp.c,v 1.20 1996/08/28 06:31:57 paulus Exp $
490Sstevel@tonic-gate  */
500Sstevel@tonic-gate 
510Sstevel@tonic-gate #include <sys/param.h>
520Sstevel@tonic-gate #include <sys/types.h>
530Sstevel@tonic-gate #include <sys/kmem.h>
540Sstevel@tonic-gate #include <sys/stream.h>
550Sstevel@tonic-gate #include <sys/cmn_err.h>
560Sstevel@tonic-gate #include <sys/ddi.h>
570Sstevel@tonic-gate #include <sys/sunddi.h>
580Sstevel@tonic-gate #include <sys/byteorder.h>
590Sstevel@tonic-gate #include <net/ppp_defs.h>
600Sstevel@tonic-gate 
610Sstevel@tonic-gate /* Defined for platform-neutral include file */
620Sstevel@tonic-gate #define	PACKETPTR		mblk_t *
630Sstevel@tonic-gate #include <net/ppp-comp.h>
640Sstevel@tonic-gate 
650Sstevel@tonic-gate #ifndef _BIG_ENDIAN
660Sstevel@tonic-gate #define	BSD_LITTLE_ENDIAN
670Sstevel@tonic-gate #endif
680Sstevel@tonic-gate 
690Sstevel@tonic-gate #if DO_BSD_COMPRESS
700Sstevel@tonic-gate 
710Sstevel@tonic-gate /*
720Sstevel@tonic-gate  * PPP "BSD compress" compression
730Sstevel@tonic-gate  *
740Sstevel@tonic-gate  *  The differences between this compression and the classic BSD LZW
750Sstevel@tonic-gate  *  source are obvious from the requirement that the classic code worked
760Sstevel@tonic-gate  *  with files while this handles arbitrarily long streams that
770Sstevel@tonic-gate  *  are broken into packets.  They are:
780Sstevel@tonic-gate  *
790Sstevel@tonic-gate  *	When the code size expands, a block of junk is not emitted by
800Sstevel@tonic-gate  *	    the compressor and not expected by the decompressor.
810Sstevel@tonic-gate  *
820Sstevel@tonic-gate  *	New codes are not necessarily assigned every time an old
830Sstevel@tonic-gate  *	    code is output by the compressor.  This is because a packet
840Sstevel@tonic-gate  *	    end forces a code to be emitted, but does not imply that a
850Sstevel@tonic-gate  *	    new sequence has been seen.
860Sstevel@tonic-gate  *
870Sstevel@tonic-gate  *	The compression ratio is checked at the first end of a packet
880Sstevel@tonic-gate  *	    after the appropriate gap.	Besides simplifying and speeding
890Sstevel@tonic-gate  *	    things up, this makes it more likely that the transmitter
900Sstevel@tonic-gate  *	    and receiver will agree when the dictionary is cleared when
910Sstevel@tonic-gate  *	    compression is not going well.
920Sstevel@tonic-gate  */
930Sstevel@tonic-gate 
940Sstevel@tonic-gate /*
950Sstevel@tonic-gate  * A dictionary for doing BSD compress.
960Sstevel@tonic-gate  */
970Sstevel@tonic-gate struct bsd_db {
980Sstevel@tonic-gate 	int		totlen;		/* length of this structure */
990Sstevel@tonic-gate 	uint_t		hsize;		/* size of the hash table */
1000Sstevel@tonic-gate 	uint32_t	unit;
1010Sstevel@tonic-gate 	uchar_t		hshift;		/* used in hash function */
1020Sstevel@tonic-gate 	uchar_t		n_bits;		/* current bits/code */
1030Sstevel@tonic-gate 	uchar_t		maxbits;
1040Sstevel@tonic-gate 	uchar_t		flags;
1050Sstevel@tonic-gate 	ushort_t	seqno;		/* sequence number of next packet */
1060Sstevel@tonic-gate 	ushort_t	mru;
1070Sstevel@tonic-gate 	uint_t		hdrlen;		/* header length to preallocate */
1080Sstevel@tonic-gate 	uint_t		maxmaxcode;	/* largest valid code */
1090Sstevel@tonic-gate 	uint_t		max_ent;	/* largest code in use */
1100Sstevel@tonic-gate 	uint_t		in_count;	/* uncompressed bytes, aged */
1110Sstevel@tonic-gate 	uint_t		bytes_out;	/* compressed bytes, aged */
1120Sstevel@tonic-gate 	uint_t		ratio;		/* recent compression ratio */
1130Sstevel@tonic-gate 	uint_t		checkpoint;	/* when to next check the ratio */
1140Sstevel@tonic-gate 	uint_t		clear_count;	/* times dictionary cleared */
1150Sstevel@tonic-gate 	uint_t		incomp_count;	/* incompressible packets */
1160Sstevel@tonic-gate 	uint_t		incomp_bytes;	/* incompressible bytes */
1170Sstevel@tonic-gate 	uint_t		uncomp_count;	/* uncompressed packets */
1180Sstevel@tonic-gate 	uint_t		uncomp_bytes;	/* uncompressed bytes */
1190Sstevel@tonic-gate 	uint_t		comp_count;	/* compressed packets */
1200Sstevel@tonic-gate 	uint_t		comp_bytes;	/* compressed bytes */
1210Sstevel@tonic-gate 	ushort_t	*lens;		/* array of lengths of codes */
1220Sstevel@tonic-gate 	struct bsd_dict {
1230Sstevel@tonic-gate 	union {				/* hash value */
1240Sstevel@tonic-gate 		uint32_t	fcode;
1250Sstevel@tonic-gate 		struct {
1260Sstevel@tonic-gate #ifdef BSD_LITTLE_ENDIAN
1270Sstevel@tonic-gate 			ushort_t	prefix;	/* preceding code */
1280Sstevel@tonic-gate 			uchar_t		suffix;	/* last character of new code */
1290Sstevel@tonic-gate 			uchar_t		pad;
1300Sstevel@tonic-gate #else
1310Sstevel@tonic-gate 			uchar_t		pad;
1320Sstevel@tonic-gate 			uchar_t		suffix;	/* last character of new code */
1330Sstevel@tonic-gate 			ushort_t	prefix;	/* preceding code */
1340Sstevel@tonic-gate #endif
1350Sstevel@tonic-gate 		} hs;
1360Sstevel@tonic-gate 	} f;
1370Sstevel@tonic-gate 		ushort_t	codem1;		/* output of hash table -1 */
1380Sstevel@tonic-gate 		ushort_t	cptr;		/* map code to hash entry */
1390Sstevel@tonic-gate 	} dict[1];
1400Sstevel@tonic-gate };
1410Sstevel@tonic-gate 
1420Sstevel@tonic-gate #define	BSD_OVHD	2		/* BSD compress overhead/packet */
1430Sstevel@tonic-gate #define	BSD_INIT_BITS	BSD_MIN_BITS
1440Sstevel@tonic-gate 
1450Sstevel@tonic-gate /* db->flags values */
1460Sstevel@tonic-gate #define	DS_DEBUG	0x01
1470Sstevel@tonic-gate #define	DS_TESTIN	0x02
1480Sstevel@tonic-gate #define	DS_TESTOUT	0x04
149*5640Scarlsonj #define	DS_INITDONE	0x08
1500Sstevel@tonic-gate 
1510Sstevel@tonic-gate static void	*bsd_comp_alloc(uchar_t *options, int opt_len);
1520Sstevel@tonic-gate static void	*bsd_decomp_alloc(uchar_t *options, int opt_len);
1530Sstevel@tonic-gate static void	bsd_free(void *state);
1540Sstevel@tonic-gate static int	bsd_comp_init(void *state, uchar_t *options, int opt_len,
1550Sstevel@tonic-gate 				int unit, int hdrlen, int debug);
1560Sstevel@tonic-gate static int	bsd_decomp_init(void *state, uchar_t *options, int opt_len,
1570Sstevel@tonic-gate 				int unit, int hdrlen, int mru, int debug);
1580Sstevel@tonic-gate static int	bsd_compress(void *state, mblk_t **mret,
1590Sstevel@tonic-gate 				mblk_t *mp, int slen, int maxolen);
1600Sstevel@tonic-gate static int	bsd_incomp(void *state, mblk_t *dmsg);
1610Sstevel@tonic-gate static int	bsd_decompress(void *state, mblk_t **dmpp);
1620Sstevel@tonic-gate static void	bsd_reset(void *state);
1630Sstevel@tonic-gate static void	bsd_comp_stats(void *state, struct compstat *stats);
1640Sstevel@tonic-gate static int	bsd_set_effort(void *xarg, void *rarg, int effortlevel);
1650Sstevel@tonic-gate 
1660Sstevel@tonic-gate /*
1670Sstevel@tonic-gate  * Procedures exported to ppp_comp.c.
1680Sstevel@tonic-gate  */
1690Sstevel@tonic-gate struct compressor ppp_bsd_compress = {
1700Sstevel@tonic-gate 	CI_BSD_COMPRESS,		/* compress_proto */
1710Sstevel@tonic-gate 	bsd_comp_alloc,			/* comp_alloc */
1720Sstevel@tonic-gate 	bsd_free,			/* comp_free */
1730Sstevel@tonic-gate 	bsd_comp_init,			/* comp_init */
1740Sstevel@tonic-gate 	bsd_reset,			/* comp_reset */
1750Sstevel@tonic-gate 	bsd_compress,			/* compress */
1760Sstevel@tonic-gate 	bsd_comp_stats,			/* comp_stat */
1770Sstevel@tonic-gate 	bsd_decomp_alloc,		/* decomp_alloc */
1780Sstevel@tonic-gate 	bsd_free,			/* decomp_free */
1790Sstevel@tonic-gate 	bsd_decomp_init,		/* decomp_init */
1800Sstevel@tonic-gate 	bsd_reset,			/* decomp_reset */
1810Sstevel@tonic-gate 	bsd_decompress,			/* decompress */
1820Sstevel@tonic-gate 	bsd_incomp,			/* incomp */
1830Sstevel@tonic-gate 	bsd_comp_stats,			/* decomp_stat */
1840Sstevel@tonic-gate 	bsd_set_effort,			/* set_effort */
1850Sstevel@tonic-gate };
1860Sstevel@tonic-gate 
1870Sstevel@tonic-gate /*
1880Sstevel@tonic-gate  * the next two codes should not be changed lightly, as they must not
1890Sstevel@tonic-gate  * lie within the contiguous general code space.
1900Sstevel@tonic-gate  */
1910Sstevel@tonic-gate #define	CLEAR		256		/* table clear output code */
1920Sstevel@tonic-gate #define	FIRST		257		/* first free entry */
1930Sstevel@tonic-gate #define	LAST		255
1940Sstevel@tonic-gate 
1950Sstevel@tonic-gate #define	MAXCODE(b)	((1 << (b)) - 1)
1960Sstevel@tonic-gate #define	BADCODEM1	MAXCODE(BSD_MAX_BITS)
1970Sstevel@tonic-gate 
1980Sstevel@tonic-gate #define	BSD_HASH(prefix, suffix, hshift)	\
1990Sstevel@tonic-gate 	((((uint32_t)(suffix)) << (hshift)) ^ (uint32_t)(prefix))
2000Sstevel@tonic-gate 
2010Sstevel@tonic-gate #define	BSD_KEY(prefix, suffix)		\
2020Sstevel@tonic-gate 	((((uint32_t)(suffix)) << 16) + (uint32_t)(prefix))
2030Sstevel@tonic-gate 
2040Sstevel@tonic-gate #define	CHECK_GAP	10000		/* Ratio check interval */
2050Sstevel@tonic-gate 
2060Sstevel@tonic-gate #define	RATIO_SCALE_LOG	8
2070Sstevel@tonic-gate #define	RATIO_SCALE	(1 << RATIO_SCALE_LOG)
2080Sstevel@tonic-gate #define	RATIO_MAX	(0x7fffffff >> RATIO_SCALE_LOG)
2090Sstevel@tonic-gate 
2100Sstevel@tonic-gate #define	DECOMP_CHUNK	256
2110Sstevel@tonic-gate 
2120Sstevel@tonic-gate /*
2130Sstevel@tonic-gate  * bsd_clear()
2140Sstevel@tonic-gate  *
2150Sstevel@tonic-gate  * clear the dictionary
2160Sstevel@tonic-gate  */
2170Sstevel@tonic-gate static void
bsd_clear(struct bsd_db * db)2180Sstevel@tonic-gate bsd_clear(struct bsd_db *db)
2190Sstevel@tonic-gate {
2200Sstevel@tonic-gate 	db->clear_count++;
2210Sstevel@tonic-gate 	db->max_ent = FIRST-1;
2220Sstevel@tonic-gate 	db->n_bits = BSD_INIT_BITS;
2230Sstevel@tonic-gate 	db->ratio = 0;
2240Sstevel@tonic-gate 	db->bytes_out = 0;
2250Sstevel@tonic-gate 	db->in_count = 0;
2260Sstevel@tonic-gate 	db->checkpoint = CHECK_GAP;
2270Sstevel@tonic-gate }
2280Sstevel@tonic-gate 
2290Sstevel@tonic-gate /*
2300Sstevel@tonic-gate  * bsd_check()
2310Sstevel@tonic-gate  *
2320Sstevel@tonic-gate  * If the dictionary is full, then see if it is time to reset it.
2330Sstevel@tonic-gate  *
2340Sstevel@tonic-gate  * Compute the compression ratio using fixed-point arithmetic
2350Sstevel@tonic-gate  * with 8 fractional bits.
2360Sstevel@tonic-gate  *
2370Sstevel@tonic-gate  * Since we have an infinite stream instead of a single file,
2380Sstevel@tonic-gate  * watch only the local compression ratio.
2390Sstevel@tonic-gate  *
2400Sstevel@tonic-gate  * Since both peers must reset the dictionary at the same time even in
2410Sstevel@tonic-gate  * the absence of CLEAR codes (while packets are incompressible), they
2420Sstevel@tonic-gate  * must compute the same ratio.
2430Sstevel@tonic-gate  */
2440Sstevel@tonic-gate static int				/* 1=output CLEAR */
bsd_check(struct bsd_db * db)2450Sstevel@tonic-gate bsd_check(struct bsd_db *db)
2460Sstevel@tonic-gate {
2470Sstevel@tonic-gate 	uint_t	new_ratio;
2480Sstevel@tonic-gate 
2490Sstevel@tonic-gate 	if (db->in_count >= db->checkpoint) {
2500Sstevel@tonic-gate 
2510Sstevel@tonic-gate 		/*
2520Sstevel@tonic-gate 		 * age the ratio by limiting the size of the counts
2530Sstevel@tonic-gate 		 */
2540Sstevel@tonic-gate 		if (db->in_count >= RATIO_MAX || db->bytes_out >= RATIO_MAX) {
2550Sstevel@tonic-gate 			db->in_count -= db->in_count/4;
2560Sstevel@tonic-gate 			db->bytes_out -= db->bytes_out/4;
2570Sstevel@tonic-gate 		}
2580Sstevel@tonic-gate 
2590Sstevel@tonic-gate 		db->checkpoint = db->in_count + CHECK_GAP;
2600Sstevel@tonic-gate 
2610Sstevel@tonic-gate 		if (db->max_ent >= db->maxmaxcode) {
2620Sstevel@tonic-gate 
2630Sstevel@tonic-gate 			/*
2640Sstevel@tonic-gate 			 * Reset the dictionary only if the ratio is worse,
2650Sstevel@tonic-gate 			 * or if it looks as if it has been poisoned
2660Sstevel@tonic-gate 			 * by incompressible data.
2670Sstevel@tonic-gate 			 *
2680Sstevel@tonic-gate 			 * This does not overflow, because
2690Sstevel@tonic-gate 			 * db->in_count <= RATIO_MAX.
2700Sstevel@tonic-gate 			 */
2710Sstevel@tonic-gate 			new_ratio = db->in_count << RATIO_SCALE_LOG;
2720Sstevel@tonic-gate 
2730Sstevel@tonic-gate 			if (db->bytes_out != 0) {
2740Sstevel@tonic-gate 				new_ratio /= db->bytes_out;
2750Sstevel@tonic-gate 			}
2760Sstevel@tonic-gate 
2770Sstevel@tonic-gate 			if (new_ratio < db->ratio ||
278*5640Scarlsonj 			    new_ratio < 1 * RATIO_SCALE) {
2790Sstevel@tonic-gate 				bsd_clear(db);
2800Sstevel@tonic-gate 				return (1);
2810Sstevel@tonic-gate 			}
2820Sstevel@tonic-gate 
2830Sstevel@tonic-gate 			db->ratio = new_ratio;
2840Sstevel@tonic-gate 		}
2850Sstevel@tonic-gate 	}
2860Sstevel@tonic-gate 
2870Sstevel@tonic-gate 	return (0);
2880Sstevel@tonic-gate }
2890Sstevel@tonic-gate 
2900Sstevel@tonic-gate /*
2910Sstevel@tonic-gate  * bsd_comp_stats()
2920Sstevel@tonic-gate  *
2930Sstevel@tonic-gate  * Return statistics.
2940Sstevel@tonic-gate  */
2950Sstevel@tonic-gate static void
bsd_comp_stats(void * state,struct compstat * stats)2960Sstevel@tonic-gate bsd_comp_stats(void *state, struct compstat *stats)
2970Sstevel@tonic-gate {
2980Sstevel@tonic-gate 	struct bsd_db	*db = (struct bsd_db *)state;
2990Sstevel@tonic-gate 	uint_t		out;
3000Sstevel@tonic-gate 
3010Sstevel@tonic-gate 	stats->unc_bytes = db->uncomp_bytes;
3020Sstevel@tonic-gate 	stats->unc_packets = db->uncomp_count;
3030Sstevel@tonic-gate 	stats->comp_bytes = db->comp_bytes;
3040Sstevel@tonic-gate 	stats->comp_packets = db->comp_count;
3050Sstevel@tonic-gate 	stats->inc_bytes = db->incomp_bytes;
3060Sstevel@tonic-gate 	stats->inc_packets = db->incomp_count;
3070Sstevel@tonic-gate 	stats->ratio = db->in_count;
3080Sstevel@tonic-gate 
3090Sstevel@tonic-gate 	out = db->bytes_out;
3100Sstevel@tonic-gate 
3110Sstevel@tonic-gate 	if (stats->ratio <= 0x7fffff) {
3120Sstevel@tonic-gate 		stats->ratio <<= 8;
3130Sstevel@tonic-gate 	} else {
3140Sstevel@tonic-gate 		out >>= 8;
3150Sstevel@tonic-gate 	}
3160Sstevel@tonic-gate 
3170Sstevel@tonic-gate 	if (out != 0) {
3180Sstevel@tonic-gate 		stats->ratio /= out;
3190Sstevel@tonic-gate 	}
3200Sstevel@tonic-gate }
3210Sstevel@tonic-gate 
3220Sstevel@tonic-gate /*
3230Sstevel@tonic-gate  * bsd_reset()
3240Sstevel@tonic-gate  *
3250Sstevel@tonic-gate  * Reset state, as on a CCP ResetReq.
3260Sstevel@tonic-gate  */
3270Sstevel@tonic-gate static void
bsd_reset(void * state)3280Sstevel@tonic-gate bsd_reset(void *state)
3290Sstevel@tonic-gate {
3300Sstevel@tonic-gate 	struct bsd_db	*db = (struct bsd_db *)state;
3310Sstevel@tonic-gate 
3320Sstevel@tonic-gate 	if (db->hsize != 0) {
3330Sstevel@tonic-gate 		db->seqno = 0;
3340Sstevel@tonic-gate 
3350Sstevel@tonic-gate 		bsd_clear(db);
3360Sstevel@tonic-gate 
3370Sstevel@tonic-gate 		db->clear_count = 0;
3380Sstevel@tonic-gate 	}
3390Sstevel@tonic-gate }
3400Sstevel@tonic-gate 
3410Sstevel@tonic-gate /*
3420Sstevel@tonic-gate  * bsd_alloc()
3430Sstevel@tonic-gate  *
3440Sstevel@tonic-gate  * Allocate space for a (de) compressor.
3450Sstevel@tonic-gate  */
3460Sstevel@tonic-gate static void *
bsd_alloc(uchar_t * options,int opt_len,int decomp)3470Sstevel@tonic-gate bsd_alloc(uchar_t *options, int opt_len, int decomp)
3480Sstevel@tonic-gate {
3490Sstevel@tonic-gate 	int		bits;
3500Sstevel@tonic-gate 	uint_t		newlen;
3510Sstevel@tonic-gate 	uint_t		hsize;
3520Sstevel@tonic-gate 	uint_t		hshift;
3530Sstevel@tonic-gate 	uint_t		maxmaxcode;
3540Sstevel@tonic-gate 	uint_t		ilen;
3550Sstevel@tonic-gate 	struct bsd_db	*db;
3560Sstevel@tonic-gate 
3570Sstevel@tonic-gate 	if (opt_len != 3 ||
358*5640Scarlsonj 	    options[0] != CI_BSD_COMPRESS ||
359*5640Scarlsonj 	    options[1] != 3 ||
360*5640Scarlsonj 	    BSD_VERSION(options[2]) != BSD_CURRENT_VERSION) {
3610Sstevel@tonic-gate 
3620Sstevel@tonic-gate 		return (NULL);
3630Sstevel@tonic-gate 	}
3640Sstevel@tonic-gate 
3650Sstevel@tonic-gate 	bits = BSD_NBITS(options[2]);
3660Sstevel@tonic-gate 
3670Sstevel@tonic-gate 	switch (bits) {
3680Sstevel@tonic-gate 
3690Sstevel@tonic-gate 	case 9:				/* needs 82152 for both directions */
3700Sstevel@tonic-gate 	case 10:			/* needs 84144 */
3710Sstevel@tonic-gate 	case 11:			/* needs 88240 */
3720Sstevel@tonic-gate 	case 12:			/* needs 96432 */
3730Sstevel@tonic-gate 
3740Sstevel@tonic-gate 		hsize = 5003;
3750Sstevel@tonic-gate 		hshift = 4;
3760Sstevel@tonic-gate 
3770Sstevel@tonic-gate 		break;
3780Sstevel@tonic-gate 
3790Sstevel@tonic-gate 	case 13:			/* needs 176784 */
3800Sstevel@tonic-gate 
3810Sstevel@tonic-gate 		hsize = 9001;
3820Sstevel@tonic-gate 		hshift = 5;
3830Sstevel@tonic-gate 
3840Sstevel@tonic-gate 		break;
3850Sstevel@tonic-gate 
3860Sstevel@tonic-gate 	case 14:			/* needs 353744 */
3870Sstevel@tonic-gate 
3880Sstevel@tonic-gate 		hsize = 18013;
3890Sstevel@tonic-gate 		hshift = 6;
3900Sstevel@tonic-gate 
3910Sstevel@tonic-gate 		break;
3920Sstevel@tonic-gate 
3930Sstevel@tonic-gate 	case 15:			/* needs 691440 */
3940Sstevel@tonic-gate 
3950Sstevel@tonic-gate 		hsize = 35023;
3960Sstevel@tonic-gate 		hshift = 7;
3970Sstevel@tonic-gate 
3980Sstevel@tonic-gate 		break;
3990Sstevel@tonic-gate 
4000Sstevel@tonic-gate 	/* XXX: this falls thru - it was originally commented */
4010Sstevel@tonic-gate 	case 16:			/* needs 1366160--far too much, */
4020Sstevel@tonic-gate 		/* hsize = 69001; */	/* and 69001 is too big for cptr */
4030Sstevel@tonic-gate 		/* hshift = 8; */	/* in struct bsd_db */
4040Sstevel@tonic-gate 		/* break; */
4050Sstevel@tonic-gate 
4060Sstevel@tonic-gate 	default:
4070Sstevel@tonic-gate 
4080Sstevel@tonic-gate 		return (NULL);
4090Sstevel@tonic-gate 	}
4100Sstevel@tonic-gate 
4110Sstevel@tonic-gate 	maxmaxcode = MAXCODE(bits);
4120Sstevel@tonic-gate 	ilen = newlen = sizeof (*db) + (hsize-1) * sizeof (db->dict[0]);
4130Sstevel@tonic-gate 	if (decomp)
4140Sstevel@tonic-gate 		newlen += (maxmaxcode+1) * sizeof (db->lens[0]);
4150Sstevel@tonic-gate 	db = (struct bsd_db *)kmem_alloc(newlen, KM_NOSLEEP);
4160Sstevel@tonic-gate 	if (!db) {
4170Sstevel@tonic-gate 		return (NULL);
4180Sstevel@tonic-gate 	}
4190Sstevel@tonic-gate 
4200Sstevel@tonic-gate 	bzero(db, sizeof (*db) - sizeof (db->dict));
4210Sstevel@tonic-gate 
4220Sstevel@tonic-gate 	if (!decomp) {
4230Sstevel@tonic-gate 		db->lens = NULL;
4240Sstevel@tonic-gate 	} else {
4250Sstevel@tonic-gate 		db->lens = (ushort_t *)((caddr_t)db + ilen);
4260Sstevel@tonic-gate 	}
4270Sstevel@tonic-gate 
4280Sstevel@tonic-gate 	db->totlen = newlen;
4290Sstevel@tonic-gate 	db->hsize = hsize;
4300Sstevel@tonic-gate 	db->hshift = (uchar_t)hshift;
4310Sstevel@tonic-gate 	db->maxmaxcode = maxmaxcode;
4320Sstevel@tonic-gate 	db->maxbits = (uchar_t)bits;
4330Sstevel@tonic-gate 
4340Sstevel@tonic-gate 	return ((void *)db);
4350Sstevel@tonic-gate }
4360Sstevel@tonic-gate 
4370Sstevel@tonic-gate /*
4380Sstevel@tonic-gate  * bsd_free()
4390Sstevel@tonic-gate  */
4400Sstevel@tonic-gate static void
bsd_free(void * state)4410Sstevel@tonic-gate bsd_free(void *state)
4420Sstevel@tonic-gate {
4430Sstevel@tonic-gate 	struct bsd_db	*db = (struct bsd_db *)state;
4440Sstevel@tonic-gate 
4450Sstevel@tonic-gate 	if (db->hsize != 0) {
4460Sstevel@tonic-gate 		/* XXX feeble attempt to catch bad references. */
4470Sstevel@tonic-gate 		db->hsize = 0;
4480Sstevel@tonic-gate 
4490Sstevel@tonic-gate 		kmem_free(db, db->totlen);
4500Sstevel@tonic-gate 	}
4510Sstevel@tonic-gate }
4520Sstevel@tonic-gate 
4530Sstevel@tonic-gate /*
4540Sstevel@tonic-gate  * bsd_comp_alloc()
4550Sstevel@tonic-gate  */
4560Sstevel@tonic-gate static void *
bsd_comp_alloc(uchar_t * options,int opt_len)4570Sstevel@tonic-gate bsd_comp_alloc(uchar_t *options, int opt_len)
4580Sstevel@tonic-gate {
4590Sstevel@tonic-gate 	return (bsd_alloc(options, opt_len, 0));
4600Sstevel@tonic-gate }
4610Sstevel@tonic-gate 
4620Sstevel@tonic-gate /*
4630Sstevel@tonic-gate  * bsd_decomp_alloc()
4640Sstevel@tonic-gate  */
4650Sstevel@tonic-gate static void *
bsd_decomp_alloc(uchar_t * options,int opt_len)4660Sstevel@tonic-gate bsd_decomp_alloc(uchar_t *options, int opt_len)
4670Sstevel@tonic-gate {
4680Sstevel@tonic-gate 	return (bsd_alloc(options, opt_len, 1));
4690Sstevel@tonic-gate }
4700Sstevel@tonic-gate 
4710Sstevel@tonic-gate /*
4720Sstevel@tonic-gate  * bsd_init()
4730Sstevel@tonic-gate  *
4740Sstevel@tonic-gate  * Initialize the database.
4750Sstevel@tonic-gate  */
4760Sstevel@tonic-gate static int
bsd_init(struct bsd_db * db,uchar_t * options,int opt_len,int unit,int hdrlen,int mru,int debug,int decomp)4770Sstevel@tonic-gate bsd_init(struct bsd_db *db, uchar_t *options, int opt_len, int unit,
4780Sstevel@tonic-gate 	int hdrlen, int mru, int debug, int decomp)
4790Sstevel@tonic-gate {
4800Sstevel@tonic-gate 	int	i;
4810Sstevel@tonic-gate 
4820Sstevel@tonic-gate 	if (db->hsize == 0 || opt_len < CILEN_BSD_COMPRESS ||
483*5640Scarlsonj 	    options[0] != CI_BSD_COMPRESS ||
484*5640Scarlsonj 	    options[1] != CILEN_BSD_COMPRESS ||
485*5640Scarlsonj 	    BSD_VERSION(options[2]) != BSD_CURRENT_VERSION ||
486*5640Scarlsonj 	    BSD_NBITS(options[2]) != db->maxbits ||
487*5640Scarlsonj 	    decomp && db->lens == NULL) {
4880Sstevel@tonic-gate 
4890Sstevel@tonic-gate 		return (0);
4900Sstevel@tonic-gate 	}
4910Sstevel@tonic-gate 
4920Sstevel@tonic-gate 	if (decomp) {
4930Sstevel@tonic-gate 		i = LAST + 1;
4940Sstevel@tonic-gate 
4950Sstevel@tonic-gate 		while (i != 0) {
4960Sstevel@tonic-gate 			db->lens[--i] = 1;
4970Sstevel@tonic-gate 		}
4980Sstevel@tonic-gate 	}
4990Sstevel@tonic-gate 
5000Sstevel@tonic-gate 	i = db->hsize;
5010Sstevel@tonic-gate 
5020Sstevel@tonic-gate 	while (i != 0) {
5030Sstevel@tonic-gate 		db->dict[--i].codem1 = BADCODEM1;
5040Sstevel@tonic-gate 		db->dict[i].cptr = 0;
5050Sstevel@tonic-gate 	}
5060Sstevel@tonic-gate 
5070Sstevel@tonic-gate 	db->unit = unit;
5080Sstevel@tonic-gate 	db->hdrlen = hdrlen;
5090Sstevel@tonic-gate 	db->mru = (ushort_t)mru;
5100Sstevel@tonic-gate 
5110Sstevel@tonic-gate 	if (debug) {
5120Sstevel@tonic-gate 		db->flags |= DS_DEBUG;
5130Sstevel@tonic-gate 	}
5140Sstevel@tonic-gate 
5150Sstevel@tonic-gate 	bsd_reset(db);
5160Sstevel@tonic-gate 
517*5640Scarlsonj 	db->flags |= DS_INITDONE;
518*5640Scarlsonj 
5190Sstevel@tonic-gate 	return (1);
5200Sstevel@tonic-gate }
5210Sstevel@tonic-gate 
5220Sstevel@tonic-gate /*
5230Sstevel@tonic-gate  * bsd_comp_init()
5240Sstevel@tonic-gate  */
5250Sstevel@tonic-gate static int
bsd_comp_init(void * state,uchar_t * options,int opt_len,int unit,int hdrlen,int debug)5260Sstevel@tonic-gate bsd_comp_init(void *state, uchar_t *options, int opt_len, int unit, int hdrlen,
5270Sstevel@tonic-gate 	int debug)
5280Sstevel@tonic-gate {
5290Sstevel@tonic-gate 	return (bsd_init((struct bsd_db *)state, options, opt_len,
530*5640Scarlsonj 	    unit, hdrlen, 0, debug, 0));
5310Sstevel@tonic-gate }
5320Sstevel@tonic-gate 
5330Sstevel@tonic-gate /*
5340Sstevel@tonic-gate  * bsd_decomp_init()
5350Sstevel@tonic-gate  */
5360Sstevel@tonic-gate static int
bsd_decomp_init(void * state,uchar_t * options,int opt_len,int unit,int hdrlen,int mru,int debug)5370Sstevel@tonic-gate bsd_decomp_init(void *state, uchar_t *options, int opt_len, int unit,
5380Sstevel@tonic-gate 	int hdrlen, int mru, int debug)
5390Sstevel@tonic-gate {
5400Sstevel@tonic-gate 	return (bsd_init((struct bsd_db *)state, options, opt_len,
541*5640Scarlsonj 	    unit, hdrlen, mru, debug, 1));
5420Sstevel@tonic-gate }
5430Sstevel@tonic-gate 
5440Sstevel@tonic-gate 
5450Sstevel@tonic-gate /*
5460Sstevel@tonic-gate  * bsd_compress()
5470Sstevel@tonic-gate  *
5480Sstevel@tonic-gate  * compress a packet
5490Sstevel@tonic-gate  *	One change from the BSD compress command is that when the
5500Sstevel@tonic-gate  *	code size expands, we do not output a bunch of padding.
5510Sstevel@tonic-gate  *
5520Sstevel@tonic-gate  * N.B. at present, we ignore the hdrlen specified in the comp_init call.
5530Sstevel@tonic-gate  */
5540Sstevel@tonic-gate static int			/* new slen */
bsd_compress(void * state,mblk_t ** mretp,mblk_t * mp,int slen,int maxolen)5550Sstevel@tonic-gate bsd_compress(void *state, mblk_t **mretp, mblk_t *mp, int slen,	int maxolen)
5560Sstevel@tonic-gate {
5570Sstevel@tonic-gate 	struct bsd_db	*db = (struct bsd_db *)state;
5580Sstevel@tonic-gate 	int		hshift = db->hshift;
5590Sstevel@tonic-gate 	uint_t		max_ent = db->max_ent;
5600Sstevel@tonic-gate 	uint_t		n_bits = db->n_bits;
5610Sstevel@tonic-gate 	uint_t		bitno = 32;
5620Sstevel@tonic-gate 	uint32_t	accm = 0;
5630Sstevel@tonic-gate 	uint32_t	fcode;
5640Sstevel@tonic-gate 	struct bsd_dict	*dictp;
5650Sstevel@tonic-gate 	uchar_t		c;
5660Sstevel@tonic-gate 	int		hval;
5670Sstevel@tonic-gate 	int		disp;
5680Sstevel@tonic-gate 	int		ent;
5690Sstevel@tonic-gate 	int		ilen = slen - (PPP_HDRLEN-1);
5700Sstevel@tonic-gate 	mblk_t		*mret;
5710Sstevel@tonic-gate 	uchar_t		*rptr, *rmax;
5720Sstevel@tonic-gate 	uchar_t		*wptr;
5730Sstevel@tonic-gate 	uchar_t		*cp_end;
5740Sstevel@tonic-gate 	int		olen;
5750Sstevel@tonic-gate 	mblk_t		*m;
5760Sstevel@tonic-gate 	mblk_t		**mnp;
5770Sstevel@tonic-gate #if defined(lint) || defined(_lint)
5780Sstevel@tonic-gate 	uchar_t		hdlcaddr, hdlcctl;
5790Sstevel@tonic-gate #else
5800Sstevel@tonic-gate 	int		hdlcaddr, hdlcctl;
5810Sstevel@tonic-gate #endif
5820Sstevel@tonic-gate 
583*5640Scarlsonj 	ASSERT(db->flags & DS_INITDONE);
584*5640Scarlsonj 
5850Sstevel@tonic-gate #define	PUTBYTE(v) {						\
5860Sstevel@tonic-gate 	if (wptr) {						\
5870Sstevel@tonic-gate 		*wptr++ = (v);					\
5880Sstevel@tonic-gate 		if (wptr >= cp_end) {				\
5890Sstevel@tonic-gate 			m->b_wptr = wptr;			\
5900Sstevel@tonic-gate 			m = m->b_cont;				\
5910Sstevel@tonic-gate 			if (m) {				\
5920Sstevel@tonic-gate 				wptr = m->b_wptr;		\
5930Sstevel@tonic-gate 				cp_end = m->b_datap->db_lim;	\
5940Sstevel@tonic-gate 			} else {				\
5950Sstevel@tonic-gate 				wptr = NULL;			\
5960Sstevel@tonic-gate 			}					\
5970Sstevel@tonic-gate 		}						\
5980Sstevel@tonic-gate 	}							\
5990Sstevel@tonic-gate 	++olen;							\
6000Sstevel@tonic-gate }
6010Sstevel@tonic-gate 
6020Sstevel@tonic-gate #define	OUTPUT(ent) {						\
6030Sstevel@tonic-gate 	bitno -= n_bits;					\
6040Sstevel@tonic-gate 	accm |= ((ent) << bitno);				\
6050Sstevel@tonic-gate 	do {							\
6060Sstevel@tonic-gate 		PUTBYTE(accm >> 24);				\
6070Sstevel@tonic-gate 		accm <<= 8;					\
6080Sstevel@tonic-gate 		bitno += 8;					\
6090Sstevel@tonic-gate 	} while (bitno <= 24);					\
6100Sstevel@tonic-gate }
6110Sstevel@tonic-gate 
6120Sstevel@tonic-gate #define	ADJRPTR() {						\
6130Sstevel@tonic-gate 	if (rptr != NULL) {					\
6140Sstevel@tonic-gate 		while (rptr >= rmax) {				\
6150Sstevel@tonic-gate 			if ((mp = mp->b_cont) == NULL) {	\
6160Sstevel@tonic-gate 				rptr = NULL;			\
6170Sstevel@tonic-gate 				break;				\
6180Sstevel@tonic-gate 			}					\
6190Sstevel@tonic-gate 			rptr = mp->b_rptr;			\
6200Sstevel@tonic-gate 			rmax = mp->b_wptr;			\
6210Sstevel@tonic-gate 		}						\
6220Sstevel@tonic-gate 	}							\
6230Sstevel@tonic-gate }
6240Sstevel@tonic-gate 
6250Sstevel@tonic-gate #define	GETBYTE(v) {						\
6260Sstevel@tonic-gate 	if (rptr != NULL) {					\
6270Sstevel@tonic-gate 		(v) = *rptr++;					\
6280Sstevel@tonic-gate 	}							\
6290Sstevel@tonic-gate }
6300Sstevel@tonic-gate 
6310Sstevel@tonic-gate 	if (db->hsize == 0)
6320Sstevel@tonic-gate 		return (-1);
6330Sstevel@tonic-gate 
6340Sstevel@tonic-gate 	/*
6350Sstevel@tonic-gate 	 * First get the protocol and check that we're
6360Sstevel@tonic-gate 	 * interested in this packet.
6370Sstevel@tonic-gate 	 */
6380Sstevel@tonic-gate 	*mretp = NULL;
6390Sstevel@tonic-gate 	rptr = mp->b_rptr;
6400Sstevel@tonic-gate 	rmax = mp->b_wptr;
6410Sstevel@tonic-gate 
6420Sstevel@tonic-gate 	/* We CANNOT do a pullup here; it's not our buffer to toy with. */
6430Sstevel@tonic-gate 	ADJRPTR();
6440Sstevel@tonic-gate 	GETBYTE(hdlcaddr);
6450Sstevel@tonic-gate 	ADJRPTR();
6460Sstevel@tonic-gate 	GETBYTE(hdlcctl);
6470Sstevel@tonic-gate 	ADJRPTR();
6480Sstevel@tonic-gate 	GETBYTE(ent);
6490Sstevel@tonic-gate 	ADJRPTR();
6500Sstevel@tonic-gate 
6510Sstevel@tonic-gate 	/*
6520Sstevel@tonic-gate 	 * Per RFC 1977, the protocol field must be compressed using a
6530Sstevel@tonic-gate 	 * PFC-like procedure.  Also, all protocols between 0000-3FFF
6540Sstevel@tonic-gate 	 * except the two compression protocols must be LZ compressed.
6550Sstevel@tonic-gate 	 */
6560Sstevel@tonic-gate 	if (ent == 0) {
6570Sstevel@tonic-gate 		GETBYTE(ent);
6580Sstevel@tonic-gate 		if (rptr == NULL || ent == PPP_COMP || ent == PPP_COMPFRAG)
6590Sstevel@tonic-gate 			return (0);
6600Sstevel@tonic-gate 	} else {
6610Sstevel@tonic-gate 		if (ent > 0x3F)
6620Sstevel@tonic-gate 			return (0);
6630Sstevel@tonic-gate 		ilen++;
6640Sstevel@tonic-gate 	}
6650Sstevel@tonic-gate 
6660Sstevel@tonic-gate 	/*
6670Sstevel@tonic-gate 	 * Don't generate compressed packets that are larger than the
6680Sstevel@tonic-gate 	 * source (uncompressed) packet.
6690Sstevel@tonic-gate 	 */
6700Sstevel@tonic-gate 	if (maxolen > slen) {
6710Sstevel@tonic-gate 		maxolen = slen;
6720Sstevel@tonic-gate 	}
6730Sstevel@tonic-gate 	if (maxolen < 6)
6740Sstevel@tonic-gate 		maxolen = 6;
6750Sstevel@tonic-gate 
6760Sstevel@tonic-gate 	/*
6770Sstevel@tonic-gate 	 * Allocate enough message blocks to give maxolen total space
6780Sstevel@tonic-gate 	 */
6790Sstevel@tonic-gate 	mnp = &mret;
6800Sstevel@tonic-gate 	for (olen = maxolen; olen > 0; ) {
6810Sstevel@tonic-gate 
6820Sstevel@tonic-gate 		m = allocb((olen < 4096? olen: 4096), BPRI_MED);
6830Sstevel@tonic-gate 
6840Sstevel@tonic-gate 		*mnp = m;
6850Sstevel@tonic-gate 		if (m == NULL) {
6860Sstevel@tonic-gate 			if (mnp == &mret)
6870Sstevel@tonic-gate 				return (0);
6880Sstevel@tonic-gate 			/* We allocated some; hope for the best. */
6890Sstevel@tonic-gate 			break;
6900Sstevel@tonic-gate 		}
6910Sstevel@tonic-gate 
6920Sstevel@tonic-gate 		mnp = &m->b_cont;
6930Sstevel@tonic-gate 		olen -= m->b_datap->db_lim - m->b_wptr;
6940Sstevel@tonic-gate 	}
6950Sstevel@tonic-gate 
6960Sstevel@tonic-gate 	*mnp = NULL;
6970Sstevel@tonic-gate 
6980Sstevel@tonic-gate 	m = mret;
6990Sstevel@tonic-gate 	wptr = m->b_wptr;
7000Sstevel@tonic-gate 	cp_end = m->b_datap->db_lim;
7010Sstevel@tonic-gate 
7020Sstevel@tonic-gate 	olen = 0;
7030Sstevel@tonic-gate 
7040Sstevel@tonic-gate 	/*
7050Sstevel@tonic-gate 	 * Copy the PPP header over, changing the protocol,
7060Sstevel@tonic-gate 	 * and install the 2-byte sequence number
7070Sstevel@tonic-gate 	 */
7080Sstevel@tonic-gate 	*wptr++ = hdlcaddr;
7090Sstevel@tonic-gate 	*wptr++ = hdlcctl;
7100Sstevel@tonic-gate 	*wptr++ = PPP_COMP>>8;		/* change the protocol */
7110Sstevel@tonic-gate 	*wptr++ = PPP_COMP;
7120Sstevel@tonic-gate 	*wptr++ = db->seqno >> 8;
7130Sstevel@tonic-gate 	*wptr++ = db->seqno;
7140Sstevel@tonic-gate 
7150Sstevel@tonic-gate #ifdef DEBUG
7160Sstevel@tonic-gate 	/*
7170Sstevel@tonic-gate 	 * If testing output, just garbling the sequence here does the
7180Sstevel@tonic-gate 	 * trick.
7190Sstevel@tonic-gate 	 */
7200Sstevel@tonic-gate 	if ((db->flags & DS_TESTOUT) && (db->seqno % 100) == 50)
7210Sstevel@tonic-gate 		wptr[-1] ^= 0xAA;
7220Sstevel@tonic-gate #endif
7230Sstevel@tonic-gate 
7240Sstevel@tonic-gate 	++db->seqno;
7250Sstevel@tonic-gate 
7260Sstevel@tonic-gate 	for (;;) {
7270Sstevel@tonic-gate 		ADJRPTR();
7280Sstevel@tonic-gate 		if (rptr == NULL)
7290Sstevel@tonic-gate 			break;
7300Sstevel@tonic-gate 
7310Sstevel@tonic-gate 		GETBYTE(c);
7320Sstevel@tonic-gate 
7330Sstevel@tonic-gate 		fcode = BSD_KEY(ent, c);
7340Sstevel@tonic-gate 		hval = BSD_HASH(ent, c, hshift);
7350Sstevel@tonic-gate 
7360Sstevel@tonic-gate 		dictp = &db->dict[hval];
7370Sstevel@tonic-gate 
7380Sstevel@tonic-gate 		/*
7390Sstevel@tonic-gate 		 * Validate and then check the entry
7400Sstevel@tonic-gate 		 */
7410Sstevel@tonic-gate 		if (dictp->codem1 >= max_ent) {
7420Sstevel@tonic-gate 			goto nomatch;
7430Sstevel@tonic-gate 		}
7440Sstevel@tonic-gate 
7450Sstevel@tonic-gate 		if (dictp->f.fcode == fcode) {
7460Sstevel@tonic-gate 			ent = dictp->codem1+1;
7470Sstevel@tonic-gate 
7480Sstevel@tonic-gate 			/*
7490Sstevel@tonic-gate 			 * found (prefix,suffix)
7500Sstevel@tonic-gate 			 */
7510Sstevel@tonic-gate 			continue;
7520Sstevel@tonic-gate 		}
7530Sstevel@tonic-gate 
7540Sstevel@tonic-gate 		/*
7550Sstevel@tonic-gate 		 * continue probing until a match or invalid entry
7560Sstevel@tonic-gate 		 */
7570Sstevel@tonic-gate 		disp = (hval == 0) ? 1 : hval;
7580Sstevel@tonic-gate 
7590Sstevel@tonic-gate 		do {
7600Sstevel@tonic-gate 			hval += disp;
7610Sstevel@tonic-gate 			if (hval >= db->hsize) {
7620Sstevel@tonic-gate 				hval -= db->hsize;
7630Sstevel@tonic-gate 				if (hval >= db->hsize) {
7640Sstevel@tonic-gate 					if (db->flags & DS_DEBUG) {
7650Sstevel@tonic-gate 						cmn_err(CE_CONT,
7660Sstevel@tonic-gate 						    "bsd_comp%d: internal "
7670Sstevel@tonic-gate 						    "error\n",
7680Sstevel@tonic-gate 						    db->unit);
7690Sstevel@tonic-gate 					}
7700Sstevel@tonic-gate 					/* Caller will free it all */
7710Sstevel@tonic-gate 					return (-1);
7720Sstevel@tonic-gate 				}
7730Sstevel@tonic-gate 			}
7740Sstevel@tonic-gate 
7750Sstevel@tonic-gate 			dictp = &db->dict[hval];
7760Sstevel@tonic-gate 
7770Sstevel@tonic-gate 			if (dictp->codem1 >= max_ent) {
7780Sstevel@tonic-gate 				goto nomatch;
7790Sstevel@tonic-gate 			}
7800Sstevel@tonic-gate 		} while (dictp->f.fcode != fcode);
7810Sstevel@tonic-gate 
7820Sstevel@tonic-gate 		/*
7830Sstevel@tonic-gate 		 * finally found (prefix,suffix)
7840Sstevel@tonic-gate 		 */
7850Sstevel@tonic-gate 		ent = dictp->codem1 + 1;
7860Sstevel@tonic-gate 
7870Sstevel@tonic-gate 		continue;
7880Sstevel@tonic-gate 
7890Sstevel@tonic-gate nomatch:
7900Sstevel@tonic-gate 		/*
7910Sstevel@tonic-gate 		 * output the prefix
7920Sstevel@tonic-gate 		 */
7930Sstevel@tonic-gate 		OUTPUT(ent);
7940Sstevel@tonic-gate 
7950Sstevel@tonic-gate 		/*
7960Sstevel@tonic-gate 		 * code -> hashtable
7970Sstevel@tonic-gate 		 */
7980Sstevel@tonic-gate 		if (max_ent < db->maxmaxcode) {
7990Sstevel@tonic-gate 			struct bsd_dict *dictp2;
8000Sstevel@tonic-gate 
8010Sstevel@tonic-gate 			/*
8020Sstevel@tonic-gate 			 * expand code size if needed
8030Sstevel@tonic-gate 			 */
8040Sstevel@tonic-gate 			if (max_ent >= MAXCODE(n_bits)) {
8050Sstevel@tonic-gate 				db->n_bits = ++n_bits;
8060Sstevel@tonic-gate 			}
8070Sstevel@tonic-gate 
8080Sstevel@tonic-gate 			/*
8090Sstevel@tonic-gate 			 * Invalidate old hash table entry using
8100Sstevel@tonic-gate 			 * this code, and then take it over.
8110Sstevel@tonic-gate 			 */
8120Sstevel@tonic-gate 			dictp2 = &db->dict[max_ent+1];
8130Sstevel@tonic-gate 
8140Sstevel@tonic-gate 			if (db->dict[dictp2->cptr].codem1 == max_ent) {
8150Sstevel@tonic-gate 				db->dict[dictp2->cptr].codem1 = BADCODEM1;
8160Sstevel@tonic-gate 			}
8170Sstevel@tonic-gate 
8180Sstevel@tonic-gate 			dictp2->cptr = (ushort_t)hval;
8190Sstevel@tonic-gate 			dictp->codem1 = max_ent;
8200Sstevel@tonic-gate 			dictp->f.fcode = fcode;
8210Sstevel@tonic-gate 
8220Sstevel@tonic-gate 			db->max_ent = ++max_ent;
8230Sstevel@tonic-gate 		}
8240Sstevel@tonic-gate 
8250Sstevel@tonic-gate 		ent = c;
8260Sstevel@tonic-gate 	}
8270Sstevel@tonic-gate 
8280Sstevel@tonic-gate 	/*
8290Sstevel@tonic-gate 	 * output the last code
8300Sstevel@tonic-gate 	 */
8310Sstevel@tonic-gate 	OUTPUT(ent);
8320Sstevel@tonic-gate 
8330Sstevel@tonic-gate 	olen += (32-bitno+7)/8;	/* count complete bytes */
8340Sstevel@tonic-gate 
8350Sstevel@tonic-gate 	db->bytes_out += olen;
8360Sstevel@tonic-gate 	db->in_count += ilen;
8370Sstevel@tonic-gate 
8380Sstevel@tonic-gate 	if (bsd_check(db)) {
8390Sstevel@tonic-gate 		OUTPUT(CLEAR);		/* do not count the CLEAR */
8400Sstevel@tonic-gate 	}
8410Sstevel@tonic-gate 
8420Sstevel@tonic-gate 	/*
8430Sstevel@tonic-gate 	 * Pad dribble bits of last code with ones.
8440Sstevel@tonic-gate 	 * Do not emit a completely useless byte of ones.
8450Sstevel@tonic-gate 	 */
8460Sstevel@tonic-gate 	if (bitno != 32) {
8470Sstevel@tonic-gate 		PUTBYTE((accm | (0xff << (bitno - 8))) >> 24);
8480Sstevel@tonic-gate 	}
8490Sstevel@tonic-gate 
8500Sstevel@tonic-gate 	/*
8510Sstevel@tonic-gate 	 * Increase code size if we would have without the packet
8520Sstevel@tonic-gate 	 * boundary and as the decompressor will.
8530Sstevel@tonic-gate 	 */
8540Sstevel@tonic-gate 	if (max_ent >= MAXCODE(n_bits) && max_ent < db->maxmaxcode) {
8550Sstevel@tonic-gate 		db->n_bits++;
8560Sstevel@tonic-gate 	}
8570Sstevel@tonic-gate 
8580Sstevel@tonic-gate 	db->uncomp_bytes += ilen;
8590Sstevel@tonic-gate 	++db->uncomp_count;
8600Sstevel@tonic-gate 
8610Sstevel@tonic-gate 	if (wptr == NULL || olen + PPP_HDRLEN + BSD_OVHD >= maxolen) {
8620Sstevel@tonic-gate 		/*
8630Sstevel@tonic-gate 		 * throw away the compressed stuff if it is longer
8640Sstevel@tonic-gate 		 * than uncompressed
8650Sstevel@tonic-gate 		 */
8660Sstevel@tonic-gate 		freemsg(mret);
8670Sstevel@tonic-gate 
8680Sstevel@tonic-gate 		mret = NULL;
8690Sstevel@tonic-gate 
8700Sstevel@tonic-gate 		++db->incomp_count;
8710Sstevel@tonic-gate 		db->incomp_bytes += ilen;
8720Sstevel@tonic-gate 
8730Sstevel@tonic-gate 	} else {
8740Sstevel@tonic-gate 
8750Sstevel@tonic-gate 		m->b_wptr = wptr;
8760Sstevel@tonic-gate 		if (m->b_cont) {
8770Sstevel@tonic-gate 			freemsg(m->b_cont);
8780Sstevel@tonic-gate 			m->b_cont = NULL;
8790Sstevel@tonic-gate 		}
8800Sstevel@tonic-gate 
8810Sstevel@tonic-gate 		++db->comp_count;
8820Sstevel@tonic-gate 		db->comp_bytes += olen + BSD_OVHD;
8830Sstevel@tonic-gate 	}
8840Sstevel@tonic-gate 
8850Sstevel@tonic-gate 	*mretp = mret;
8860Sstevel@tonic-gate 
8870Sstevel@tonic-gate 	return (olen + PPP_HDRLEN + BSD_OVHD);
8880Sstevel@tonic-gate #undef OUTPUT
8890Sstevel@tonic-gate #undef PUTBYTE
8900Sstevel@tonic-gate }
8910Sstevel@tonic-gate 
8920Sstevel@tonic-gate 
8930Sstevel@tonic-gate /*
8940Sstevel@tonic-gate  * bsd_incomp()
8950Sstevel@tonic-gate  *
8960Sstevel@tonic-gate  * Update the "BSD Compress" dictionary on the receiver for
8970Sstevel@tonic-gate  * incompressible data by pretending to compress the incoming data.
8980Sstevel@tonic-gate  */
8990Sstevel@tonic-gate static int
bsd_incomp(void * state,mblk_t * mp)9000Sstevel@tonic-gate bsd_incomp(void *state, mblk_t *mp)
9010Sstevel@tonic-gate {
9020Sstevel@tonic-gate 	struct bsd_db	*db = (struct bsd_db *)state;
9030Sstevel@tonic-gate 	uint_t		hshift = db->hshift;
9040Sstevel@tonic-gate 	uint_t		max_ent = db->max_ent;
9050Sstevel@tonic-gate 	uint_t		n_bits = db->n_bits;
9060Sstevel@tonic-gate 	struct bsd_dict	*dictp;
9070Sstevel@tonic-gate 	uint32_t	fcode;
9080Sstevel@tonic-gate 	uchar_t		c;
9090Sstevel@tonic-gate 	long		hval;
9100Sstevel@tonic-gate 	long		disp;
9110Sstevel@tonic-gate 	int		slen;
9120Sstevel@tonic-gate 	int		ilen;
9130Sstevel@tonic-gate 	uint_t		bitno = 7;
9140Sstevel@tonic-gate 	uchar_t		*rptr, *rmax;
9150Sstevel@tonic-gate 	uint_t		ent;
9160Sstevel@tonic-gate 
917*5640Scarlsonj 	ASSERT(db->flags & DS_INITDONE);
918*5640Scarlsonj 
9190Sstevel@tonic-gate 	if (db->hsize == 0)
9200Sstevel@tonic-gate 		return (-1);
9210Sstevel@tonic-gate 
9220Sstevel@tonic-gate 	rptr = mp->b_rptr;
9230Sstevel@tonic-gate 	rmax = mp->b_wptr;
9240Sstevel@tonic-gate 	ADJRPTR();
9250Sstevel@tonic-gate 	GETBYTE(ent);	/* address */
9260Sstevel@tonic-gate 	ADJRPTR();
9270Sstevel@tonic-gate 	GETBYTE(ent);	/* control */
9280Sstevel@tonic-gate 	ADJRPTR();
9290Sstevel@tonic-gate 	GETBYTE(ent);	/* protocol high */
9300Sstevel@tonic-gate 	ADJRPTR();
9310Sstevel@tonic-gate 
9320Sstevel@tonic-gate 	/*
9330Sstevel@tonic-gate 	 * Per RFC 1977, the protocol field must be compressed using a
9340Sstevel@tonic-gate 	 * PFC-like procedure.  Also, all protocols between 0000-3FFF
9350Sstevel@tonic-gate 	 * except the two compression protocols must be LZ compressed.
9360Sstevel@tonic-gate 	 */
9370Sstevel@tonic-gate 	ilen = 1;			/* count the protocol as 1 byte */
9380Sstevel@tonic-gate 	if (ent == 0) {
9390Sstevel@tonic-gate 		GETBYTE(ent);
9400Sstevel@tonic-gate 		if (rptr == NULL || ent == PPP_COMP || ent == PPP_COMPFRAG)
9410Sstevel@tonic-gate 			return (0);
9420Sstevel@tonic-gate 	} else {
9430Sstevel@tonic-gate 		if (ent > 0x3F)
9440Sstevel@tonic-gate 			return (0);
9450Sstevel@tonic-gate 		ilen++;
9460Sstevel@tonic-gate 	}
9470Sstevel@tonic-gate 
9480Sstevel@tonic-gate 	db->seqno++;
9490Sstevel@tonic-gate 
9500Sstevel@tonic-gate 	for (;;) {
9510Sstevel@tonic-gate 
9520Sstevel@tonic-gate 		slen = mp->b_wptr - rptr;
9530Sstevel@tonic-gate 		if (slen <= 0) {
9540Sstevel@tonic-gate 			mp = mp->b_cont;
9550Sstevel@tonic-gate 			if (!mp) {
9560Sstevel@tonic-gate 				break;
9570Sstevel@tonic-gate 			}
9580Sstevel@tonic-gate 
9590Sstevel@tonic-gate 			rptr = mp->b_rptr;
9600Sstevel@tonic-gate 			continue;	/* skip zero-length buffers */
9610Sstevel@tonic-gate 		}
9620Sstevel@tonic-gate 
9630Sstevel@tonic-gate 		ilen += slen;
9640Sstevel@tonic-gate 
9650Sstevel@tonic-gate 		do {
9660Sstevel@tonic-gate 			c = *rptr++;
9670Sstevel@tonic-gate 
9680Sstevel@tonic-gate 			fcode = BSD_KEY(ent, c);
9690Sstevel@tonic-gate 			hval = BSD_HASH(ent, c, hshift);
9700Sstevel@tonic-gate 
9710Sstevel@tonic-gate 			dictp = &db->dict[hval];
9720Sstevel@tonic-gate 
9730Sstevel@tonic-gate 			/*
9740Sstevel@tonic-gate 			 * validate and then check the entry
9750Sstevel@tonic-gate 			 */
9760Sstevel@tonic-gate 			if (dictp->codem1 >= max_ent) {
9770Sstevel@tonic-gate 				goto nomatch;
9780Sstevel@tonic-gate 			}
9790Sstevel@tonic-gate 
9800Sstevel@tonic-gate 			if (dictp->f.fcode == fcode) {
9810Sstevel@tonic-gate 				ent = dictp->codem1 + 1;
9820Sstevel@tonic-gate 				continue;   /* found (prefix,suffix) */
9830Sstevel@tonic-gate 			}
9840Sstevel@tonic-gate 
9850Sstevel@tonic-gate 			/*
9860Sstevel@tonic-gate 			 * continue probing until a match or invalid entry
9870Sstevel@tonic-gate 			 */
9880Sstevel@tonic-gate 			disp = (hval == 0) ? 1 : hval;
9890Sstevel@tonic-gate 			do {
9900Sstevel@tonic-gate 				hval += disp;
9910Sstevel@tonic-gate 				if (hval >= db->hsize) {
9920Sstevel@tonic-gate 					hval -= db->hsize;
9930Sstevel@tonic-gate 					if (hval >= db->hsize) {
9940Sstevel@tonic-gate 						if (db->flags & DS_DEBUG) {
9950Sstevel@tonic-gate 							cmn_err(CE_CONT,
9960Sstevel@tonic-gate 							    "bsd_incomp%d: "
9970Sstevel@tonic-gate 							    "internal error\n",
9980Sstevel@tonic-gate 							    db->unit);
9990Sstevel@tonic-gate 						}
10000Sstevel@tonic-gate 						return (-1);
10010Sstevel@tonic-gate 					}
10020Sstevel@tonic-gate 				}
10030Sstevel@tonic-gate 
10040Sstevel@tonic-gate 				dictp = &db->dict[hval];
10050Sstevel@tonic-gate 				if (dictp->codem1 >= max_ent) {
10060Sstevel@tonic-gate 					goto nomatch;
10070Sstevel@tonic-gate 				}
10080Sstevel@tonic-gate 			} while (dictp->f.fcode != fcode);
10090Sstevel@tonic-gate 
10100Sstevel@tonic-gate 			ent = dictp->codem1+1;
10110Sstevel@tonic-gate 			continue;	/* finally found (prefix,suffix) */
10120Sstevel@tonic-gate 
10130Sstevel@tonic-gate nomatch:				/* output (count) the prefix */
10140Sstevel@tonic-gate 			bitno += n_bits;
10150Sstevel@tonic-gate 
10160Sstevel@tonic-gate 			/*
10170Sstevel@tonic-gate 			 * code -> hashtable
10180Sstevel@tonic-gate 			 */
10190Sstevel@tonic-gate 			if (max_ent < db->maxmaxcode) {
10200Sstevel@tonic-gate 				struct bsd_dict *dictp2;
10210Sstevel@tonic-gate 
10220Sstevel@tonic-gate 				/*
10230Sstevel@tonic-gate 				 * expand code size if needed
10240Sstevel@tonic-gate 				 */
10250Sstevel@tonic-gate 				if (max_ent >= MAXCODE(n_bits)) {
10260Sstevel@tonic-gate 					db->n_bits = ++n_bits;
10270Sstevel@tonic-gate 				}
10280Sstevel@tonic-gate 
10290Sstevel@tonic-gate 				/*
10300Sstevel@tonic-gate 				 * Invalidate previous hash table entry
10310Sstevel@tonic-gate 				 * assigned this code, and then take it over.
10320Sstevel@tonic-gate 				 */
10330Sstevel@tonic-gate 				dictp2 = &db->dict[max_ent+1];
10340Sstevel@tonic-gate 				if (db->dict[dictp2->cptr].codem1 == max_ent) {
10350Sstevel@tonic-gate 					db->dict[dictp2->cptr].codem1 =
1036*5640Scarlsonj 					    BADCODEM1;
10370Sstevel@tonic-gate 				}
10380Sstevel@tonic-gate 
10390Sstevel@tonic-gate 				dictp2->cptr = (ushort_t)hval;
10400Sstevel@tonic-gate 				dictp->codem1 = max_ent;
10410Sstevel@tonic-gate 				dictp->f.fcode = fcode;
10420Sstevel@tonic-gate 
10430Sstevel@tonic-gate 				db->max_ent = ++max_ent;
10440Sstevel@tonic-gate 				db->lens[max_ent] = db->lens[ent]+1;
10450Sstevel@tonic-gate 			}
10460Sstevel@tonic-gate 
10470Sstevel@tonic-gate 			ent = c;
10480Sstevel@tonic-gate 		} while (--slen != 0);
10490Sstevel@tonic-gate 	}
10500Sstevel@tonic-gate 
10510Sstevel@tonic-gate 	bitno += n_bits;		/* output (count) the last code */
10520Sstevel@tonic-gate 
10530Sstevel@tonic-gate 	db->bytes_out += bitno/8;
10540Sstevel@tonic-gate 	db->in_count += ilen;
10550Sstevel@tonic-gate 
10560Sstevel@tonic-gate 	(void) bsd_check(db);
10570Sstevel@tonic-gate 
10580Sstevel@tonic-gate 	++db->incomp_count;
10590Sstevel@tonic-gate 	db->incomp_bytes += ilen;
10600Sstevel@tonic-gate 	++db->uncomp_count;
10610Sstevel@tonic-gate 	db->uncomp_bytes += ilen;
10620Sstevel@tonic-gate 
10630Sstevel@tonic-gate 	/*
10640Sstevel@tonic-gate 	 * Increase code size if we would have without the packet
10650Sstevel@tonic-gate 	 * boundary and as the decompressor will.
10660Sstevel@tonic-gate 	 */
10670Sstevel@tonic-gate 	if (max_ent >= MAXCODE(n_bits) && max_ent < db->maxmaxcode) {
10680Sstevel@tonic-gate 		db->n_bits++;
10690Sstevel@tonic-gate 	}
10700Sstevel@tonic-gate 	return (0);
10710Sstevel@tonic-gate #undef ADJRPTR
10720Sstevel@tonic-gate }
10730Sstevel@tonic-gate 
10740Sstevel@tonic-gate 
10750Sstevel@tonic-gate /*
10760Sstevel@tonic-gate  * bsd_decompress()
10770Sstevel@tonic-gate  *
10780Sstevel@tonic-gate  * Decompress "BSD Compress"
10790Sstevel@tonic-gate  *
10800Sstevel@tonic-gate  * Because of patent problems, we return DECOMP_ERROR for errors
10810Sstevel@tonic-gate  * found by inspecting the input data and for system problems, but
10820Sstevel@tonic-gate  * DECOMP_FATALERROR for any errors which could possibly be said to
10830Sstevel@tonic-gate  * be being detected "after" decompression.  For DECOMP_ERROR,
10840Sstevel@tonic-gate  * we can issue a CCP reset-request; for DECOMP_FATALERROR, we may be
10850Sstevel@tonic-gate  * infringing a patent of Motorola's if we do, so we take CCP down
10860Sstevel@tonic-gate  * instead.
10870Sstevel@tonic-gate  *
10880Sstevel@tonic-gate  * Given that the frame has the correct sequence number and a good FCS,
10890Sstevel@tonic-gate  * errors such as invalid codes in the input most likely indicate a
10900Sstevel@tonic-gate  * bug, so we return DECOMP_FATALERROR for them in order to turn off
10910Sstevel@tonic-gate  * compression, even though they are detected by inspecting the input.
10920Sstevel@tonic-gate  */
10930Sstevel@tonic-gate static int
bsd_decompress(void * state,mblk_t ** dmpp)10940Sstevel@tonic-gate bsd_decompress(void *state, mblk_t **dmpp)
10950Sstevel@tonic-gate {
10960Sstevel@tonic-gate 	mblk_t		*cmsg = *dmpp, *mnext;
10970Sstevel@tonic-gate 	struct bsd_db	*db = (struct bsd_db *)state;
10980Sstevel@tonic-gate 	uint_t		max_ent = db->max_ent;
10990Sstevel@tonic-gate 	uint32_t	accm = 0;
11000Sstevel@tonic-gate 	uint_t		bitno = 32;		/* 1st valid bit in accm */
11010Sstevel@tonic-gate 	uint_t		n_bits = db->n_bits;
11020Sstevel@tonic-gate 	uint_t		tgtbitno = 32 - n_bits;	/* bitno when we have a code */
11030Sstevel@tonic-gate 	struct bsd_dict	*dictp;
11040Sstevel@tonic-gate 	int		explen;
11050Sstevel@tonic-gate 	int		seq;
11060Sstevel@tonic-gate 	uint_t		incode;
11070Sstevel@tonic-gate 	uint_t		oldcode;
11080Sstevel@tonic-gate 	uint_t		finchar = 0, ofinchar;
11090Sstevel@tonic-gate 	uchar_t		*p;
11100Sstevel@tonic-gate 	uchar_t		*rptr, *rmax;
11110Sstevel@tonic-gate 	uchar_t		*wptr, *prepos;
11120Sstevel@tonic-gate 	mblk_t		*dmsg;
11130Sstevel@tonic-gate 	mblk_t		*mret;
11140Sstevel@tonic-gate 	int		ilen;
11150Sstevel@tonic-gate 	int		dlen;
11160Sstevel@tonic-gate 	int		codelen;
11170Sstevel@tonic-gate 	int		extra;
11180Sstevel@tonic-gate 	int		decode_proto;
11190Sstevel@tonic-gate 	int		blockctr;
11200Sstevel@tonic-gate 	int		outlen;
11210Sstevel@tonic-gate #if defined(lint) || defined(_lint)
11220Sstevel@tonic-gate 	uchar_t		adrs, ctrl;
11230Sstevel@tonic-gate #else
11240Sstevel@tonic-gate 	int		adrs, ctrl;
11250Sstevel@tonic-gate #endif
11260Sstevel@tonic-gate 
1127*5640Scarlsonj 	ASSERT(db->flags & DS_INITDONE);
1128*5640Scarlsonj 
11290Sstevel@tonic-gate 	/* Note: spppcomp already did a pullup to fix the first buffer. */
11300Sstevel@tonic-gate 	*dmpp = NULL;
11310Sstevel@tonic-gate 	rptr = cmsg->b_rptr;
11320Sstevel@tonic-gate 	rmax = cmsg->b_wptr;
11330Sstevel@tonic-gate 	ilen = 0;
11340Sstevel@tonic-gate 
11350Sstevel@tonic-gate 	/*
11360Sstevel@tonic-gate 	 * Note that we free as we go.  If we fail to decompress,
11370Sstevel@tonic-gate 	 * there's nothing good that the caller can do.
11380Sstevel@tonic-gate 	 */
11390Sstevel@tonic-gate #define	ADJRPTR()					\
11400Sstevel@tonic-gate 	while (rptr >= rmax) {				\
11410Sstevel@tonic-gate 		mnext = cmsg->b_cont;			\
11420Sstevel@tonic-gate 		freeb(cmsg);				\
11430Sstevel@tonic-gate 		if ((cmsg = mnext) == NULL) {		\
11440Sstevel@tonic-gate 			rptr = NULL;			\
11450Sstevel@tonic-gate 			break;				\
11460Sstevel@tonic-gate 		}					\
11470Sstevel@tonic-gate 		rptr = cmsg->b_rptr;			\
11480Sstevel@tonic-gate 		rmax = cmsg->b_wptr;			\
11490Sstevel@tonic-gate 		ilen += rmax-rptr;			\
11500Sstevel@tonic-gate 	}
11510Sstevel@tonic-gate 
11520Sstevel@tonic-gate 	/*
11530Sstevel@tonic-gate 	 * Save the address/control from the PPP header
11540Sstevel@tonic-gate 	 * and then get the sequence number.
11550Sstevel@tonic-gate 	 */
11560Sstevel@tonic-gate 	adrs = rptr[0];
11570Sstevel@tonic-gate 	ctrl = rptr[1];
11580Sstevel@tonic-gate 	rptr += 4;
11590Sstevel@tonic-gate 	ADJRPTR();
11600Sstevel@tonic-gate 	seq = rptr == NULL ? 0 : (*rptr++ << 8);
11610Sstevel@tonic-gate 	ADJRPTR();
11620Sstevel@tonic-gate 	if (rptr == NULL) {
11630Sstevel@tonic-gate 		if (db->flags & DS_DEBUG) {
11640Sstevel@tonic-gate 			cmn_err(CE_CONT, "bsd_decomp%d: bad buffer\n",
11650Sstevel@tonic-gate 			    db->unit);
11660Sstevel@tonic-gate 		}
11670Sstevel@tonic-gate 		return (DECOMP_ERROR);
11680Sstevel@tonic-gate 	}
11690Sstevel@tonic-gate 	seq |= *rptr++;
11700Sstevel@tonic-gate 
11710Sstevel@tonic-gate #ifdef DEBUG
11720Sstevel@tonic-gate 	/*
11730Sstevel@tonic-gate 	 * If testing input, just pretending the sequence is bad here
11740Sstevel@tonic-gate 	 * does the trick.
11750Sstevel@tonic-gate 	 */
11760Sstevel@tonic-gate 	if ((db->flags & DS_TESTIN) && (db->seqno % 300) == 101)
11770Sstevel@tonic-gate 		seq ^= 0x55;
11780Sstevel@tonic-gate #endif
11790Sstevel@tonic-gate 
11800Sstevel@tonic-gate 	/*
11810Sstevel@tonic-gate 	 * Check the sequence number and give up if it is not what we expect.
11820Sstevel@tonic-gate 	 */
11830Sstevel@tonic-gate 	if (db->hsize == 0 || seq != db->seqno++) {
11840Sstevel@tonic-gate 		freemsg(cmsg);
11850Sstevel@tonic-gate 		if (db->flags & DS_DEBUG) {
11860Sstevel@tonic-gate 			cmn_err(CE_CONT, "bsd_decomp%d: bad sequence # %d, "
1187*5640Scarlsonj 			    "expected %d\n", db->unit, seq, db->seqno - 1);
11880Sstevel@tonic-gate 		}
11890Sstevel@tonic-gate 
11900Sstevel@tonic-gate 		return (DECOMP_ERROR);
11910Sstevel@tonic-gate 	}
11920Sstevel@tonic-gate 
11930Sstevel@tonic-gate 	/*
11940Sstevel@tonic-gate 	 * Allocate one message block to start with.
11950Sstevel@tonic-gate 	 */
11960Sstevel@tonic-gate 	if ((dmsg = allocb(DECOMP_CHUNK + db->hdrlen, BPRI_MED)) == NULL) {
11970Sstevel@tonic-gate 		freemsg(cmsg);
11980Sstevel@tonic-gate 		if (db->flags & DS_DEBUG) {
11990Sstevel@tonic-gate 			cmn_err(CE_CONT,
12000Sstevel@tonic-gate 			    "bsd_decomp%d: can't allocate first buffer\n",
12010Sstevel@tonic-gate 			    db->unit);
12020Sstevel@tonic-gate 		}
12030Sstevel@tonic-gate 		return (DECOMP_ERROR);
12040Sstevel@tonic-gate 	}
12050Sstevel@tonic-gate 
12060Sstevel@tonic-gate 	/*
12070Sstevel@tonic-gate 	 * Avoid an error that might cause us to allocate all available memory.
12080Sstevel@tonic-gate 	 * Enforce a maximum number of blocks to allocate for message. We add
12090Sstevel@tonic-gate 	 * a fudge factor of 5 extra blocks, in order to avoid unnecessary
12100Sstevel@tonic-gate 	 * DECOMP_ERROR when the code size is small (9).
12110Sstevel@tonic-gate 	 */
12120Sstevel@tonic-gate 	blockctr = ((db->mru + 32 + DECOMP_CHUNK - 1) / DECOMP_CHUNK) + 5;
12130Sstevel@tonic-gate 
12140Sstevel@tonic-gate 	mret = dmsg;
12150Sstevel@tonic-gate 	dmsg->b_wptr += db->hdrlen;
12160Sstevel@tonic-gate 	dmsg->b_rptr = wptr = dmsg->b_wptr;
12170Sstevel@tonic-gate 
12180Sstevel@tonic-gate 	/*
12190Sstevel@tonic-gate 	 * Insert PPP header.  This shouldn't be needed!
12200Sstevel@tonic-gate 	 */
12210Sstevel@tonic-gate 	*wptr++ = adrs;
12220Sstevel@tonic-gate 	*wptr++ = ctrl;
12230Sstevel@tonic-gate 	prepos = wptr;
12240Sstevel@tonic-gate 	*wptr++ = 0;
12250Sstevel@tonic-gate 	dmsg->b_wptr = wptr;
12260Sstevel@tonic-gate 
12270Sstevel@tonic-gate 	explen = dmsg->b_datap->db_lim - wptr;
12280Sstevel@tonic-gate 	oldcode = CLEAR;
12290Sstevel@tonic-gate 	ilen = rmax-rptr;
12300Sstevel@tonic-gate 
12310Sstevel@tonic-gate 	outlen = 0;
12320Sstevel@tonic-gate 	decode_proto = 1;
12330Sstevel@tonic-gate 	for (;;) {
12340Sstevel@tonic-gate 		ADJRPTR();
12350Sstevel@tonic-gate 		if (rptr == NULL)
12360Sstevel@tonic-gate 			break;
12370Sstevel@tonic-gate 
12380Sstevel@tonic-gate 		/*
12390Sstevel@tonic-gate 		 * Accumulate bytes until we have a complete code.
12400Sstevel@tonic-gate 		 * Then get the next code, relying on the 32-bit,
12410Sstevel@tonic-gate 		 * unsigned accm to mask the result.
12420Sstevel@tonic-gate 		 */
12430Sstevel@tonic-gate 		bitno -= 8;
12440Sstevel@tonic-gate 
12450Sstevel@tonic-gate 		accm |= *rptr++ << bitno;
12460Sstevel@tonic-gate 
12470Sstevel@tonic-gate 		if (tgtbitno < bitno) {
12480Sstevel@tonic-gate 			continue;
12490Sstevel@tonic-gate 		}
12500Sstevel@tonic-gate 
12510Sstevel@tonic-gate 		incode = accm >> tgtbitno;
12520Sstevel@tonic-gate 		accm <<= n_bits;
12530Sstevel@tonic-gate 		bitno += n_bits;
12540Sstevel@tonic-gate 
12550Sstevel@tonic-gate 		if (incode == CLEAR) {
12560Sstevel@tonic-gate 
12570Sstevel@tonic-gate 			/*
12580Sstevel@tonic-gate 			 * The dictionary must only be cleared at
12590Sstevel@tonic-gate 			 * the end of a packet.  But there could be an
12600Sstevel@tonic-gate 			 * empty message block at the end.
12610Sstevel@tonic-gate 			 */
12620Sstevel@tonic-gate 			ADJRPTR();
12630Sstevel@tonic-gate 			if (rptr != NULL) {
12640Sstevel@tonic-gate 				freemsg(mret);
12650Sstevel@tonic-gate 				freemsg(cmsg);
12660Sstevel@tonic-gate 				if (db->flags & DS_DEBUG) {
12670Sstevel@tonic-gate 					cmn_err(CE_CONT,
12680Sstevel@tonic-gate 					    "bsd_decomp%d: bad CLEAR\n",
12690Sstevel@tonic-gate 					    db->unit);
12700Sstevel@tonic-gate 				}
12710Sstevel@tonic-gate 
12720Sstevel@tonic-gate 				return (DECOMP_FATALERROR);
12730Sstevel@tonic-gate 			}
12740Sstevel@tonic-gate 
12750Sstevel@tonic-gate 			bsd_clear(db);
12760Sstevel@tonic-gate 			/* Have to keep cleared state variables! */
12770Sstevel@tonic-gate 			outlen += wptr-dmsg->b_wptr;
12780Sstevel@tonic-gate 			dmsg->b_wptr = wptr;
12790Sstevel@tonic-gate 			db->comp_bytes += ilen;
12800Sstevel@tonic-gate 			ilen = 0;
12810Sstevel@tonic-gate 			break;
12820Sstevel@tonic-gate 		}
12830Sstevel@tonic-gate 
12840Sstevel@tonic-gate 		/*
12850Sstevel@tonic-gate 		 * Special case for KwKwK string
12860Sstevel@tonic-gate 		 */
12870Sstevel@tonic-gate 		ofinchar = finchar;
12880Sstevel@tonic-gate 		if (incode > max_ent) {
12890Sstevel@tonic-gate 			if (incode > max_ent + 2 ||
12900Sstevel@tonic-gate 			    incode > db->maxmaxcode ||
12910Sstevel@tonic-gate 			    oldcode == CLEAR) {
12920Sstevel@tonic-gate 				freemsg(cmsg);
12930Sstevel@tonic-gate 				freemsg(mret);
12940Sstevel@tonic-gate 
12950Sstevel@tonic-gate 				/* probably a bug if we get here */
12960Sstevel@tonic-gate 				if (db->flags & DS_DEBUG) {
12970Sstevel@tonic-gate 					cmn_err(CE_CONT,
12980Sstevel@tonic-gate 					    "bsd_decomp%d: bad code 0x%x "
12990Sstevel@tonic-gate 					    "oldcode=0x%x ", db->unit, incode,
13000Sstevel@tonic-gate 					    oldcode);
13010Sstevel@tonic-gate 				}
13020Sstevel@tonic-gate 
13030Sstevel@tonic-gate 				return (DECOMP_FATALERROR);
13040Sstevel@tonic-gate 			}
13050Sstevel@tonic-gate 			finchar = oldcode;
13060Sstevel@tonic-gate 			extra = 1;
13070Sstevel@tonic-gate 		} else {
13080Sstevel@tonic-gate 			finchar = incode;
13090Sstevel@tonic-gate 			extra = 0;
13100Sstevel@tonic-gate 		}
13110Sstevel@tonic-gate 		codelen = db->lens[finchar];
13120Sstevel@tonic-gate 
13130Sstevel@tonic-gate 		/*
13140Sstevel@tonic-gate 		 * Decode this code and install it in the decompressed buffer
13150Sstevel@tonic-gate 		 */
13160Sstevel@tonic-gate 		explen -= codelen + extra;
13170Sstevel@tonic-gate 		if (explen < 0) {
13180Sstevel@tonic-gate 			/*
13190Sstevel@tonic-gate 			 * Allocate another message block
13200Sstevel@tonic-gate 			 */
13210Sstevel@tonic-gate 			dlen = wptr - dmsg->b_wptr;
13220Sstevel@tonic-gate 			outlen += dlen;
13230Sstevel@tonic-gate 			db->in_count += dlen;
13240Sstevel@tonic-gate 			dmsg->b_wptr = wptr;
13250Sstevel@tonic-gate 			dlen = codelen + extra;
13260Sstevel@tonic-gate 
13270Sstevel@tonic-gate 			if (dlen < DECOMP_CHUNK) {
13280Sstevel@tonic-gate 				dlen = DECOMP_CHUNK;
13290Sstevel@tonic-gate 			}
13300Sstevel@tonic-gate 
13310Sstevel@tonic-gate 			if ((--blockctr < 0) ||
13320Sstevel@tonic-gate 			    (dmsg->b_cont = allocb(dlen, BPRI_MED)) == NULL) {
13330Sstevel@tonic-gate 				freemsg(cmsg);
13340Sstevel@tonic-gate 				freemsg(mret);
13350Sstevel@tonic-gate 				if (db->flags & DS_DEBUG) {
13360Sstevel@tonic-gate 					cmn_err(CE_CONT,
13370Sstevel@tonic-gate 					    "bsd_decomp%d: %s output "
13380Sstevel@tonic-gate 					    "buffers; outlen %d+%d\n",
13390Sstevel@tonic-gate 					    db->unit,
13400Sstevel@tonic-gate 					    (blockctr < 0 ? "too many" :
1341*5640Scarlsonj 					    "can't allocate"),
13420Sstevel@tonic-gate 					    outlen, dlen);
13430Sstevel@tonic-gate 				}
13440Sstevel@tonic-gate 				return (DECOMP_ERROR);
13450Sstevel@tonic-gate 			}
13460Sstevel@tonic-gate 
13470Sstevel@tonic-gate 			dmsg = dmsg->b_cont;
13480Sstevel@tonic-gate 			wptr = dmsg->b_wptr;
13490Sstevel@tonic-gate 			explen = dmsg->b_datap->db_lim - wptr - codelen -
13500Sstevel@tonic-gate 			    extra;
13510Sstevel@tonic-gate 		}
13520Sstevel@tonic-gate 
13530Sstevel@tonic-gate 		p = (wptr += codelen);
13540Sstevel@tonic-gate 
13550Sstevel@tonic-gate 		while (finchar > LAST) {
13560Sstevel@tonic-gate 			dictp = &db->dict[db->dict[finchar].cptr];
13570Sstevel@tonic-gate 			*--p = dictp->f.hs.suffix;
13580Sstevel@tonic-gate 			finchar = dictp->f.hs.prefix;
13590Sstevel@tonic-gate 		}
13600Sstevel@tonic-gate 
13610Sstevel@tonic-gate 		*--p = finchar;
13620Sstevel@tonic-gate 
13630Sstevel@tonic-gate 		if (decode_proto) {
13640Sstevel@tonic-gate 			decode_proto = 0;
13650Sstevel@tonic-gate 			/* Wow, is *this* ugly! */
13660Sstevel@tonic-gate 			if (!(finchar & 1)) {
13670Sstevel@tonic-gate 				if (p == prepos+1) {
13680Sstevel@tonic-gate 					bcopy(p, prepos, wptr-p);
13690Sstevel@tonic-gate 					wptr--;
13700Sstevel@tonic-gate 					explen++;
13710Sstevel@tonic-gate 					db->in_count++;
13720Sstevel@tonic-gate 				} else {
13730Sstevel@tonic-gate 					/* This is safe, but doesn't look it */
13740Sstevel@tonic-gate 					*prepos = *p++;
13750Sstevel@tonic-gate 					dmsg->b_rptr = p;
13760Sstevel@tonic-gate 				}
13770Sstevel@tonic-gate 			}
13780Sstevel@tonic-gate 		}
13790Sstevel@tonic-gate 
13800Sstevel@tonic-gate 		if (extra) {	/* the KwKwK case again */
13810Sstevel@tonic-gate 			*wptr++ = ofinchar;
13820Sstevel@tonic-gate 		}
13830Sstevel@tonic-gate 
13840Sstevel@tonic-gate 		/*
13850Sstevel@tonic-gate 		 * If not first code in a packet, and
13860Sstevel@tonic-gate 		 * if not out of code space, then allocate a new code.
13870Sstevel@tonic-gate 		 *
13880Sstevel@tonic-gate 		 * Keep the hash table correct so it can be used
13890Sstevel@tonic-gate 		 * with uncompressed packets.
13900Sstevel@tonic-gate 		 */
13910Sstevel@tonic-gate 		if (oldcode != CLEAR && max_ent < db->maxmaxcode) {
13920Sstevel@tonic-gate 			struct bsd_dict	*dictp2;
13930Sstevel@tonic-gate 			uint32_t	fcode;
13940Sstevel@tonic-gate 			int		hval;
13950Sstevel@tonic-gate 			int		disp;
13960Sstevel@tonic-gate 
13970Sstevel@tonic-gate 			fcode = BSD_KEY(oldcode, finchar);
13980Sstevel@tonic-gate 			hval = BSD_HASH(oldcode, finchar, db->hshift);
13990Sstevel@tonic-gate 
14000Sstevel@tonic-gate 			dictp = &db->dict[hval];
14010Sstevel@tonic-gate 
14020Sstevel@tonic-gate 			/*
14030Sstevel@tonic-gate 			 * look for a free hash table entry
14040Sstevel@tonic-gate 			 */
14050Sstevel@tonic-gate 			if (dictp->codem1 < max_ent) {
14060Sstevel@tonic-gate 				disp = (hval == 0) ? 1 : hval;
14070Sstevel@tonic-gate 
14080Sstevel@tonic-gate 				do {
14090Sstevel@tonic-gate 					hval += disp;
14100Sstevel@tonic-gate 
14110Sstevel@tonic-gate 					if (hval >= db->hsize) {
14120Sstevel@tonic-gate 						hval -= db->hsize;
14130Sstevel@tonic-gate 						if (hval >= db->hsize) {
14140Sstevel@tonic-gate 							freemsg(cmsg);
14150Sstevel@tonic-gate 							freemsg(mret);
14160Sstevel@tonic-gate 							if (db->flags &
14170Sstevel@tonic-gate 							    DS_DEBUG) {
14180Sstevel@tonic-gate 			cmn_err(CE_CONT, "bsd_decomp%d: internal error\n",
14190Sstevel@tonic-gate 			    db->unit);
14200Sstevel@tonic-gate 							}
14210Sstevel@tonic-gate 							return
1422*5640Scarlsonj 							    (DECOMP_FATALERROR);
14230Sstevel@tonic-gate 						}
14240Sstevel@tonic-gate 					}
14250Sstevel@tonic-gate 
14260Sstevel@tonic-gate 					dictp = &db->dict[hval];
14270Sstevel@tonic-gate 
14280Sstevel@tonic-gate 				} while (dictp->codem1 < max_ent);
14290Sstevel@tonic-gate 			}
14300Sstevel@tonic-gate 
14310Sstevel@tonic-gate 			/*
14320Sstevel@tonic-gate 			 * Invalidate previous hash table entry
14330Sstevel@tonic-gate 			 * assigned this code, and then take it over
14340Sstevel@tonic-gate 			 */
14350Sstevel@tonic-gate 			dictp2 = &db->dict[max_ent+1];
14360Sstevel@tonic-gate 
14370Sstevel@tonic-gate 			if (db->dict[dictp2->cptr].codem1 == max_ent) {
14380Sstevel@tonic-gate 				db->dict[dictp2->cptr].codem1 = BADCODEM1;
14390Sstevel@tonic-gate 			}
14400Sstevel@tonic-gate 
14410Sstevel@tonic-gate 			dictp2->cptr = (ushort_t)hval;
14420Sstevel@tonic-gate 			dictp->codem1 = max_ent;
14430Sstevel@tonic-gate 			dictp->f.fcode = fcode;
14440Sstevel@tonic-gate 
14450Sstevel@tonic-gate 			db->max_ent = ++max_ent;
14460Sstevel@tonic-gate 			db->lens[max_ent] = db->lens[oldcode]+1;
14470Sstevel@tonic-gate 
14480Sstevel@tonic-gate 			/*
14490Sstevel@tonic-gate 			 * Expand code size if needed
14500Sstevel@tonic-gate 			 */
14510Sstevel@tonic-gate 			if (max_ent >= MAXCODE(n_bits) &&
1452*5640Scarlsonj 			    max_ent < db->maxmaxcode) {
14530Sstevel@tonic-gate 
14540Sstevel@tonic-gate 				db->n_bits = ++n_bits;
14550Sstevel@tonic-gate 				tgtbitno = 32-n_bits;
14560Sstevel@tonic-gate 			}
14570Sstevel@tonic-gate 		}
14580Sstevel@tonic-gate 
14590Sstevel@tonic-gate 		oldcode = incode;
14600Sstevel@tonic-gate 	}
14610Sstevel@tonic-gate 
14620Sstevel@tonic-gate 	dlen = wptr-dmsg->b_wptr;
14630Sstevel@tonic-gate 	outlen += dlen;
14640Sstevel@tonic-gate 	db->in_count += dlen;
14650Sstevel@tonic-gate 	dmsg->b_wptr = wptr;
14660Sstevel@tonic-gate 	db->bytes_out += ilen;
14670Sstevel@tonic-gate 
14680Sstevel@tonic-gate 	/*
14690Sstevel@tonic-gate 	 * Keep the checkpoint right so that incompressible packets
14700Sstevel@tonic-gate 	 * clear the dictionary at the right times.
14710Sstevel@tonic-gate 	 */
14720Sstevel@tonic-gate 	if (bsd_check(db) && (db->flags & DS_DEBUG)) {
14730Sstevel@tonic-gate 		cmn_err(CE_CONT,
1474*5640Scarlsonj 		    "bsd_decomp%d: peer should have cleared dictionary\n",
1475*5640Scarlsonj 		    db->unit);
14760Sstevel@tonic-gate 	}
14770Sstevel@tonic-gate 
14780Sstevel@tonic-gate 	++db->comp_count;
14790Sstevel@tonic-gate 	db->comp_bytes += ilen + BSD_OVHD;
14800Sstevel@tonic-gate 	++db->uncomp_count;
14810Sstevel@tonic-gate 	db->uncomp_bytes += outlen;
14820Sstevel@tonic-gate 
14830Sstevel@tonic-gate 	*dmpp = mret;
14840Sstevel@tonic-gate 
14850Sstevel@tonic-gate 	return (DECOMP_OK);
14860Sstevel@tonic-gate }
14870Sstevel@tonic-gate 
14880Sstevel@tonic-gate /* ARGSUSED */
14890Sstevel@tonic-gate static int
bsd_set_effort(void * xarg,void * rarg,int effortlevel)14900Sstevel@tonic-gate bsd_set_effort(void *xarg, void *rarg, int effortlevel)
14910Sstevel@tonic-gate {
14920Sstevel@tonic-gate #ifdef DEBUG
14930Sstevel@tonic-gate 	struct bsd_db *xdb = (struct bsd_db *)xarg;
14940Sstevel@tonic-gate 	struct bsd_db *rdb = (struct bsd_db *)rarg;
14950Sstevel@tonic-gate 
14960Sstevel@tonic-gate 	if (effortlevel == 42 || effortlevel == 2112) {
14970Sstevel@tonic-gate 		/* corrupt received data. */
14980Sstevel@tonic-gate 		if (rdb != NULL) {
14990Sstevel@tonic-gate 			rdb->flags |= DS_TESTIN;
15000Sstevel@tonic-gate 			cmn_err(CE_CONT, "bsd-comp: enabled input testing.");
15010Sstevel@tonic-gate 		}
15020Sstevel@tonic-gate 		if (effortlevel != 2112)
15030Sstevel@tonic-gate 			return (0);
15040Sstevel@tonic-gate 	}
15050Sstevel@tonic-gate 	if (effortlevel == 2001 || effortlevel == 2112) {
15060Sstevel@tonic-gate 		/* corrupt transmitted data. */
15070Sstevel@tonic-gate 		if (xdb != NULL) {
15080Sstevel@tonic-gate 			xdb->flags |= DS_TESTOUT;
15090Sstevel@tonic-gate 			cmn_err(CE_CONT, "bsd-comp: enabled output testing.");
15100Sstevel@tonic-gate 		}
15110Sstevel@tonic-gate 		return (0);
15120Sstevel@tonic-gate 	}
15130Sstevel@tonic-gate #endif
15140Sstevel@tonic-gate 	return (0);
15150Sstevel@tonic-gate }
15160Sstevel@tonic-gate #endif /* DO_BSD_COMPRESS */
1517