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