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