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