#include <sys/param.h>
#include <sys/types.h>
#include <sys/kmem.h>
#include <sys/stream.h>
#include <sys/cmn_err.h>
#include <sys/ddi.h>
#include <sys/sunddi.h>
#include <sys/byteorder.h>
#include <net/ppp_defs.h>
#define PACKETPTR mblk_t *
#include <net/ppp-comp.h>
#ifndef _BIG_ENDIAN
#define BSD_LITTLE_ENDIAN
#endif
#if DO_BSD_COMPRESS
struct bsd_db {
int totlen;
uint_t hsize;
uint32_t unit;
uchar_t hshift;
uchar_t n_bits;
uchar_t maxbits;
uchar_t flags;
ushort_t seqno;
ushort_t mru;
uint_t hdrlen;
uint_t maxmaxcode;
uint_t max_ent;
uint_t in_count;
uint_t bytes_out;
uint_t ratio;
uint_t checkpoint;
uint_t clear_count;
uint_t incomp_count;
uint_t incomp_bytes;
uint_t uncomp_count;
uint_t uncomp_bytes;
uint_t comp_count;
uint_t comp_bytes;
ushort_t *lens;
struct bsd_dict {
union {
uint32_t fcode;
struct {
#ifdef BSD_LITTLE_ENDIAN
ushort_t prefix;
uchar_t suffix;
uchar_t pad;
#else
uchar_t pad;
uchar_t suffix;
ushort_t prefix;
#endif
} hs;
} f;
ushort_t codem1;
ushort_t cptr;
} dict[1];
};
#define BSD_OVHD 2
#define BSD_INIT_BITS BSD_MIN_BITS
#define DS_DEBUG 0x01
#define DS_TESTIN 0x02
#define DS_TESTOUT 0x04
#define DS_INITDONE 0x08
static void *bsd_comp_alloc(uchar_t *options, int opt_len);
static void *bsd_decomp_alloc(uchar_t *options, int opt_len);
static void bsd_free(void *state);
static int bsd_comp_init(void *state, uchar_t *options, int opt_len,
int unit, int hdrlen, int debug);
static int bsd_decomp_init(void *state, uchar_t *options, int opt_len,
int unit, int hdrlen, int mru, int debug);
static int bsd_compress(void *state, mblk_t **mret,
mblk_t *mp, int slen, int maxolen);
static int bsd_incomp(void *state, mblk_t *dmsg);
static int bsd_decompress(void *state, mblk_t **dmpp);
static void bsd_reset(void *state);
static void bsd_comp_stats(void *state, struct compstat *stats);
static int bsd_set_effort(void *xarg, void *rarg, int effortlevel);
struct compressor ppp_bsd_compress = {
CI_BSD_COMPRESS,
bsd_comp_alloc,
bsd_free,
bsd_comp_init,
bsd_reset,
bsd_compress,
bsd_comp_stats,
bsd_decomp_alloc,
bsd_free,
bsd_decomp_init,
bsd_reset,
bsd_decompress,
bsd_incomp,
bsd_comp_stats,
bsd_set_effort,
};
#define CLEAR 256
#define FIRST 257
#define LAST 255
#define MAXCODE(b) ((1 << (b)) - 1)
#define BADCODEM1 MAXCODE(BSD_MAX_BITS)
#define BSD_HASH(prefix, suffix, hshift) \
((((uint32_t)(suffix)) << (hshift)) ^ (uint32_t)(prefix))
#define BSD_KEY(prefix, suffix) \
((((uint32_t)(suffix)) << 16) + (uint32_t)(prefix))
#define CHECK_GAP 10000
#define RATIO_SCALE_LOG 8
#define RATIO_SCALE (1 << RATIO_SCALE_LOG)
#define RATIO_MAX (0x7fffffff >> RATIO_SCALE_LOG)
#define DECOMP_CHUNK 256
static void
bsd_clear(struct bsd_db *db)
{
db->clear_count++;
db->max_ent = FIRST-1;
db->n_bits = BSD_INIT_BITS;
db->ratio = 0;
db->bytes_out = 0;
db->in_count = 0;
db->checkpoint = CHECK_GAP;
}
static int
bsd_check(struct bsd_db *db)
{
uint_t new_ratio;
if (db->in_count >= db->checkpoint) {
if (db->in_count >= RATIO_MAX || db->bytes_out >= RATIO_MAX) {
db->in_count -= db->in_count/4;
db->bytes_out -= db->bytes_out/4;
}
db->checkpoint = db->in_count + CHECK_GAP;
if (db->max_ent >= db->maxmaxcode) {
new_ratio = db->in_count << RATIO_SCALE_LOG;
if (db->bytes_out != 0) {
new_ratio /= db->bytes_out;
}
if (new_ratio < db->ratio ||
new_ratio < 1 * RATIO_SCALE) {
bsd_clear(db);
return (1);
}
db->ratio = new_ratio;
}
}
return (0);
}
static void
bsd_comp_stats(void *state, struct compstat *stats)
{
struct bsd_db *db = (struct bsd_db *)state;
uint_t out;
stats->unc_bytes = db->uncomp_bytes;
stats->unc_packets = db->uncomp_count;
stats->comp_bytes = db->comp_bytes;
stats->comp_packets = db->comp_count;
stats->inc_bytes = db->incomp_bytes;
stats->inc_packets = db->incomp_count;
stats->ratio = db->in_count;
out = db->bytes_out;
if (stats->ratio <= 0x7fffff) {
stats->ratio <<= 8;
} else {
out >>= 8;
}
if (out != 0) {
stats->ratio /= out;
}
}
static void
bsd_reset(void *state)
{
struct bsd_db *db = (struct bsd_db *)state;
if (db->hsize != 0) {
db->seqno = 0;
bsd_clear(db);
db->clear_count = 0;
}
}
static void *
bsd_alloc(uchar_t *options, int opt_len, int decomp)
{
int bits;
uint_t newlen;
uint_t hsize;
uint_t hshift;
uint_t maxmaxcode;
uint_t ilen;
struct bsd_db *db;
if (opt_len != 3 ||
options[0] != CI_BSD_COMPRESS ||
options[1] != 3 ||
BSD_VERSION(options[2]) != BSD_CURRENT_VERSION) {
return (NULL);
}
bits = BSD_NBITS(options[2]);
switch (bits) {
case 9:
case 10:
case 11:
case 12:
hsize = 5003;
hshift = 4;
break;
case 13:
hsize = 9001;
hshift = 5;
break;
case 14:
hsize = 18013;
hshift = 6;
break;
case 15:
hsize = 35023;
hshift = 7;
break;
case 16:
default:
return (NULL);
}
maxmaxcode = MAXCODE(bits);
ilen = newlen = sizeof (*db) + (hsize-1) * sizeof (db->dict[0]);
if (decomp)
newlen += (maxmaxcode+1) * sizeof (db->lens[0]);
db = (struct bsd_db *)kmem_alloc(newlen, KM_NOSLEEP);
if (!db) {
return (NULL);
}
bzero(db, sizeof (*db) - sizeof (db->dict));
if (!decomp) {
db->lens = NULL;
} else {
db->lens = (ushort_t *)((caddr_t)db + ilen);
}
db->totlen = newlen;
db->hsize = hsize;
db->hshift = (uchar_t)hshift;
db->maxmaxcode = maxmaxcode;
db->maxbits = (uchar_t)bits;
return ((void *)db);
}
static void
bsd_free(void *state)
{
struct bsd_db *db = (struct bsd_db *)state;
if (db->hsize != 0) {
db->hsize = 0;
kmem_free(db, db->totlen);
}
}
static void *
bsd_comp_alloc(uchar_t *options, int opt_len)
{
return (bsd_alloc(options, opt_len, 0));
}
static void *
bsd_decomp_alloc(uchar_t *options, int opt_len)
{
return (bsd_alloc(options, opt_len, 1));
}
static int
bsd_init(struct bsd_db *db, uchar_t *options, int opt_len, int unit,
int hdrlen, int mru, int debug, int decomp)
{
int i;
if (db->hsize == 0 || opt_len < CILEN_BSD_COMPRESS ||
options[0] != CI_BSD_COMPRESS ||
options[1] != CILEN_BSD_COMPRESS ||
BSD_VERSION(options[2]) != BSD_CURRENT_VERSION ||
BSD_NBITS(options[2]) != db->maxbits ||
decomp && db->lens == NULL) {
return (0);
}
if (decomp) {
i = LAST + 1;
while (i != 0) {
db->lens[--i] = 1;
}
}
i = db->hsize;
while (i != 0) {
db->dict[--i].codem1 = BADCODEM1;
db->dict[i].cptr = 0;
}
db->unit = unit;
db->hdrlen = hdrlen;
db->mru = (ushort_t)mru;
if (debug) {
db->flags |= DS_DEBUG;
}
bsd_reset(db);
db->flags |= DS_INITDONE;
return (1);
}
static int
bsd_comp_init(void *state, uchar_t *options, int opt_len, int unit, int hdrlen,
int debug)
{
return (bsd_init((struct bsd_db *)state, options, opt_len,
unit, hdrlen, 0, debug, 0));
}
static int
bsd_decomp_init(void *state, uchar_t *options, int opt_len, int unit,
int hdrlen, int mru, int debug)
{
return (bsd_init((struct bsd_db *)state, options, opt_len,
unit, hdrlen, mru, debug, 1));
}
static int
bsd_compress(void *state, mblk_t **mretp, mblk_t *mp, int slen, int maxolen)
{
struct bsd_db *db = (struct bsd_db *)state;
int hshift = db->hshift;
uint_t max_ent = db->max_ent;
uint_t n_bits = db->n_bits;
uint_t bitno = 32;
uint32_t accm = 0;
uint32_t fcode;
struct bsd_dict *dictp;
uchar_t c;
int hval;
int disp;
int ent;
int ilen = slen - (PPP_HDRLEN-1);
mblk_t *mret;
uchar_t *rptr, *rmax;
uchar_t *wptr;
uchar_t *cp_end;
int olen;
mblk_t *m;
mblk_t **mnp;
#if defined(lint) || defined(_lint)
uchar_t hdlcaddr, hdlcctl;
#else
int hdlcaddr, hdlcctl;
#endif
ASSERT(db->flags & DS_INITDONE);
#define PUTBYTE(v) { \
if (wptr) { \
*wptr++ = (v); \
if (wptr >= cp_end) { \
m->b_wptr = wptr; \
m = m->b_cont; \
if (m) { \
wptr = m->b_wptr; \
cp_end = m->b_datap->db_lim; \
} else { \
wptr = NULL; \
} \
} \
} \
++olen; \
}
#define OUTPUT(ent) { \
bitno -= n_bits; \
accm |= ((ent) << bitno); \
do { \
PUTBYTE(accm >> 24); \
accm <<= 8; \
bitno += 8; \
} while (bitno <= 24); \
}
#define ADJRPTR() { \
if (rptr != NULL) { \
while (rptr >= rmax) { \
if ((mp = mp->b_cont) == NULL) { \
rptr = NULL; \
break; \
} \
rptr = mp->b_rptr; \
rmax = mp->b_wptr; \
} \
} \
}
#define GETBYTE(v) { \
if (rptr != NULL) { \
(v) = *rptr++; \
} \
}
if (db->hsize == 0)
return (-1);
*mretp = NULL;
rptr = mp->b_rptr;
rmax = mp->b_wptr;
ADJRPTR();
GETBYTE(hdlcaddr);
ADJRPTR();
GETBYTE(hdlcctl);
ADJRPTR();
GETBYTE(ent);
ADJRPTR();
if (ent == 0) {
GETBYTE(ent);
if (rptr == NULL || ent == PPP_COMP || ent == PPP_COMPFRAG)
return (0);
} else {
if (ent > 0x3F)
return (0);
ilen++;
}
if (maxolen > slen) {
maxolen = slen;
}
if (maxolen < 6)
maxolen = 6;
mnp = &mret;
for (olen = maxolen; olen > 0; ) {
m = allocb((olen < 4096? olen: 4096), BPRI_MED);
*mnp = m;
if (m == NULL) {
if (mnp == &mret)
return (0);
break;
}
mnp = &m->b_cont;
olen -= m->b_datap->db_lim - m->b_wptr;
}
*mnp = NULL;
m = mret;
wptr = m->b_wptr;
cp_end = m->b_datap->db_lim;
olen = 0;
*wptr++ = hdlcaddr;
*wptr++ = hdlcctl;
*wptr++ = PPP_COMP>>8;
*wptr++ = PPP_COMP;
*wptr++ = db->seqno >> 8;
*wptr++ = db->seqno;
#ifdef DEBUG
if ((db->flags & DS_TESTOUT) && (db->seqno % 100) == 50)
wptr[-1] ^= 0xAA;
#endif
++db->seqno;
for (;;) {
ADJRPTR();
if (rptr == NULL)
break;
GETBYTE(c);
fcode = BSD_KEY(ent, c);
hval = BSD_HASH(ent, c, hshift);
dictp = &db->dict[hval];
if (dictp->codem1 >= max_ent) {
goto nomatch;
}
if (dictp->f.fcode == fcode) {
ent = dictp->codem1+1;
continue;
}
disp = (hval == 0) ? 1 : hval;
do {
hval += disp;
if (hval >= db->hsize) {
hval -= db->hsize;
if (hval >= db->hsize) {
if (db->flags & DS_DEBUG) {
cmn_err(CE_CONT,
"bsd_comp%d: internal "
"error\n",
db->unit);
}
return (-1);
}
}
dictp = &db->dict[hval];
if (dictp->codem1 >= max_ent) {
goto nomatch;
}
} while (dictp->f.fcode != fcode);
ent = dictp->codem1 + 1;
continue;
nomatch:
OUTPUT(ent);
if (max_ent < db->maxmaxcode) {
struct bsd_dict *dictp2;
if (max_ent >= MAXCODE(n_bits)) {
db->n_bits = ++n_bits;
}
dictp2 = &db->dict[max_ent+1];
if (db->dict[dictp2->cptr].codem1 == max_ent) {
db->dict[dictp2->cptr].codem1 = BADCODEM1;
}
dictp2->cptr = (ushort_t)hval;
dictp->codem1 = max_ent;
dictp->f.fcode = fcode;
db->max_ent = ++max_ent;
}
ent = c;
}
OUTPUT(ent);
olen += (32-bitno+7)/8;
db->bytes_out += olen;
db->in_count += ilen;
if (bsd_check(db)) {
OUTPUT(CLEAR);
}
if (bitno != 32) {
PUTBYTE((accm | (0xff << (bitno - 8))) >> 24);
}
if (max_ent >= MAXCODE(n_bits) && max_ent < db->maxmaxcode) {
db->n_bits++;
}
db->uncomp_bytes += ilen;
++db->uncomp_count;
if (wptr == NULL || olen + PPP_HDRLEN + BSD_OVHD >= maxolen) {
freemsg(mret);
mret = NULL;
++db->incomp_count;
db->incomp_bytes += ilen;
} else {
m->b_wptr = wptr;
if (m->b_cont) {
freemsg(m->b_cont);
m->b_cont = NULL;
}
++db->comp_count;
db->comp_bytes += olen + BSD_OVHD;
}
*mretp = mret;
return (olen + PPP_HDRLEN + BSD_OVHD);
#undef OUTPUT
#undef PUTBYTE
}
static int
bsd_incomp(void *state, mblk_t *mp)
{
struct bsd_db *db = (struct bsd_db *)state;
uint_t hshift = db->hshift;
uint_t max_ent = db->max_ent;
uint_t n_bits = db->n_bits;
struct bsd_dict *dictp;
uint32_t fcode;
uchar_t c;
long hval;
long disp;
int slen;
int ilen;
uint_t bitno = 7;
uchar_t *rptr, *rmax;
uint_t ent;
ASSERT(db->flags & DS_INITDONE);
if (db->hsize == 0)
return (-1);
rptr = mp->b_rptr;
rmax = mp->b_wptr;
ADJRPTR();
GETBYTE(ent);
ADJRPTR();
GETBYTE(ent);
ADJRPTR();
GETBYTE(ent);
ADJRPTR();
ilen = 1;
if (ent == 0) {
GETBYTE(ent);
if (rptr == NULL || ent == PPP_COMP || ent == PPP_COMPFRAG)
return (0);
} else {
if (ent > 0x3F)
return (0);
ilen++;
}
db->seqno++;
for (;;) {
slen = mp->b_wptr - rptr;
if (slen <= 0) {
mp = mp->b_cont;
if (!mp) {
break;
}
rptr = mp->b_rptr;
continue;
}
ilen += slen;
do {
c = *rptr++;
fcode = BSD_KEY(ent, c);
hval = BSD_HASH(ent, c, hshift);
dictp = &db->dict[hval];
if (dictp->codem1 >= max_ent) {
goto nomatch;
}
if (dictp->f.fcode == fcode) {
ent = dictp->codem1 + 1;
continue;
}
disp = (hval == 0) ? 1 : hval;
do {
hval += disp;
if (hval >= db->hsize) {
hval -= db->hsize;
if (hval >= db->hsize) {
if (db->flags & DS_DEBUG) {
cmn_err(CE_CONT,
"bsd_incomp%d: "
"internal error\n",
db->unit);
}
return (-1);
}
}
dictp = &db->dict[hval];
if (dictp->codem1 >= max_ent) {
goto nomatch;
}
} while (dictp->f.fcode != fcode);
ent = dictp->codem1+1;
continue;
nomatch:
bitno += n_bits;
if (max_ent < db->maxmaxcode) {
struct bsd_dict *dictp2;
if (max_ent >= MAXCODE(n_bits)) {
db->n_bits = ++n_bits;
}
dictp2 = &db->dict[max_ent+1];
if (db->dict[dictp2->cptr].codem1 == max_ent) {
db->dict[dictp2->cptr].codem1 =
BADCODEM1;
}
dictp2->cptr = (ushort_t)hval;
dictp->codem1 = max_ent;
dictp->f.fcode = fcode;
db->max_ent = ++max_ent;
db->lens[max_ent] = db->lens[ent]+1;
}
ent = c;
} while (--slen != 0);
}
bitno += n_bits;
db->bytes_out += bitno/8;
db->in_count += ilen;
(void) bsd_check(db);
++db->incomp_count;
db->incomp_bytes += ilen;
++db->uncomp_count;
db->uncomp_bytes += ilen;
if (max_ent >= MAXCODE(n_bits) && max_ent < db->maxmaxcode) {
db->n_bits++;
}
return (0);
#undef ADJRPTR
}
static int
bsd_decompress(void *state, mblk_t **dmpp)
{
mblk_t *cmsg = *dmpp, *mnext;
struct bsd_db *db = (struct bsd_db *)state;
uint_t max_ent = db->max_ent;
uint32_t accm = 0;
uint_t bitno = 32;
uint_t n_bits = db->n_bits;
uint_t tgtbitno = 32 - n_bits;
struct bsd_dict *dictp;
int explen;
int seq;
uint_t incode;
uint_t oldcode;
uint_t finchar = 0, ofinchar;
uchar_t *p;
uchar_t *rptr, *rmax;
uchar_t *wptr, *prepos;
mblk_t *dmsg;
mblk_t *mret;
int ilen;
int dlen;
int codelen;
int extra;
int decode_proto;
int blockctr;
int outlen;
#if defined(lint) || defined(_lint)
uchar_t adrs, ctrl;
#else
int adrs, ctrl;
#endif
ASSERT(db->flags & DS_INITDONE);
*dmpp = NULL;
rptr = cmsg->b_rptr;
rmax = cmsg->b_wptr;
ilen = 0;
#define ADJRPTR() \
while (rptr >= rmax) { \
mnext = cmsg->b_cont; \
freeb(cmsg); \
if ((cmsg = mnext) == NULL) { \
rptr = NULL; \
break; \
} \
rptr = cmsg->b_rptr; \
rmax = cmsg->b_wptr; \
ilen += rmax-rptr; \
}
adrs = rptr[0];
ctrl = rptr[1];
rptr += 4;
ADJRPTR();
seq = rptr == NULL ? 0 : (*rptr++ << 8);
ADJRPTR();
if (rptr == NULL) {
if (db->flags & DS_DEBUG) {
cmn_err(CE_CONT, "bsd_decomp%d: bad buffer\n",
db->unit);
}
return (DECOMP_ERROR);
}
seq |= *rptr++;
#ifdef DEBUG
if ((db->flags & DS_TESTIN) && (db->seqno % 300) == 101)
seq ^= 0x55;
#endif
if (db->hsize == 0 || seq != db->seqno++) {
freemsg(cmsg);
if (db->flags & DS_DEBUG) {
cmn_err(CE_CONT, "bsd_decomp%d: bad sequence # %d, "
"expected %d\n", db->unit, seq, db->seqno - 1);
}
return (DECOMP_ERROR);
}
if ((dmsg = allocb(DECOMP_CHUNK + db->hdrlen, BPRI_MED)) == NULL) {
freemsg(cmsg);
if (db->flags & DS_DEBUG) {
cmn_err(CE_CONT,
"bsd_decomp%d: can't allocate first buffer\n",
db->unit);
}
return (DECOMP_ERROR);
}
blockctr = ((db->mru + 32 + DECOMP_CHUNK - 1) / DECOMP_CHUNK) + 5;
mret = dmsg;
dmsg->b_wptr += db->hdrlen;
dmsg->b_rptr = wptr = dmsg->b_wptr;
*wptr++ = adrs;
*wptr++ = ctrl;
prepos = wptr;
*wptr++ = 0;
dmsg->b_wptr = wptr;
explen = dmsg->b_datap->db_lim - wptr;
oldcode = CLEAR;
ilen = rmax-rptr;
outlen = 0;
decode_proto = 1;
for (;;) {
ADJRPTR();
if (rptr == NULL)
break;
bitno -= 8;
accm |= *rptr++ << bitno;
if (tgtbitno < bitno) {
continue;
}
incode = accm >> tgtbitno;
accm <<= n_bits;
bitno += n_bits;
if (incode == CLEAR) {
ADJRPTR();
if (rptr != NULL) {
freemsg(mret);
freemsg(cmsg);
if (db->flags & DS_DEBUG) {
cmn_err(CE_CONT,
"bsd_decomp%d: bad CLEAR\n",
db->unit);
}
return (DECOMP_FATALERROR);
}
bsd_clear(db);
outlen += wptr-dmsg->b_wptr;
dmsg->b_wptr = wptr;
db->comp_bytes += ilen;
ilen = 0;
break;
}
ofinchar = finchar;
if (incode > max_ent) {
if (incode > max_ent + 2 ||
incode > db->maxmaxcode ||
oldcode == CLEAR) {
freemsg(cmsg);
freemsg(mret);
if (db->flags & DS_DEBUG) {
cmn_err(CE_CONT,
"bsd_decomp%d: bad code 0x%x "
"oldcode=0x%x ", db->unit, incode,
oldcode);
}
return (DECOMP_FATALERROR);
}
finchar = oldcode;
extra = 1;
} else {
finchar = incode;
extra = 0;
}
codelen = db->lens[finchar];
explen -= codelen + extra;
if (explen < 0) {
dlen = wptr - dmsg->b_wptr;
outlen += dlen;
db->in_count += dlen;
dmsg->b_wptr = wptr;
dlen = codelen + extra;
if (dlen < DECOMP_CHUNK) {
dlen = DECOMP_CHUNK;
}
if ((--blockctr < 0) ||
(dmsg->b_cont = allocb(dlen, BPRI_MED)) == NULL) {
freemsg(cmsg);
freemsg(mret);
if (db->flags & DS_DEBUG) {
cmn_err(CE_CONT,
"bsd_decomp%d: %s output "
"buffers; outlen %d+%d\n",
db->unit,
(blockctr < 0 ? "too many" :
"can't allocate"),
outlen, dlen);
}
return (DECOMP_ERROR);
}
dmsg = dmsg->b_cont;
wptr = dmsg->b_wptr;
explen = dmsg->b_datap->db_lim - wptr - codelen -
extra;
}
p = (wptr += codelen);
while (finchar > LAST) {
dictp = &db->dict[db->dict[finchar].cptr];
*--p = dictp->f.hs.suffix;
finchar = dictp->f.hs.prefix;
}
*--p = finchar;
if (decode_proto) {
decode_proto = 0;
if (!(finchar & 1)) {
if (p == prepos+1) {
bcopy(p, prepos, wptr-p);
wptr--;
explen++;
db->in_count++;
} else {
*prepos = *p++;
dmsg->b_rptr = p;
}
}
}
if (extra) {
*wptr++ = ofinchar;
}
if (oldcode != CLEAR && max_ent < db->maxmaxcode) {
struct bsd_dict *dictp2;
uint32_t fcode;
int hval;
int disp;
fcode = BSD_KEY(oldcode, finchar);
hval = BSD_HASH(oldcode, finchar, db->hshift);
dictp = &db->dict[hval];
if (dictp->codem1 < max_ent) {
disp = (hval == 0) ? 1 : hval;
do {
hval += disp;
if (hval >= db->hsize) {
hval -= db->hsize;
if (hval >= db->hsize) {
freemsg(cmsg);
freemsg(mret);
if (db->flags &
DS_DEBUG) {
cmn_err(CE_CONT, "bsd_decomp%d: internal error\n",
db->unit);
}
return
(DECOMP_FATALERROR);
}
}
dictp = &db->dict[hval];
} while (dictp->codem1 < max_ent);
}
dictp2 = &db->dict[max_ent+1];
if (db->dict[dictp2->cptr].codem1 == max_ent) {
db->dict[dictp2->cptr].codem1 = BADCODEM1;
}
dictp2->cptr = (ushort_t)hval;
dictp->codem1 = max_ent;
dictp->f.fcode = fcode;
db->max_ent = ++max_ent;
db->lens[max_ent] = db->lens[oldcode]+1;
if (max_ent >= MAXCODE(n_bits) &&
max_ent < db->maxmaxcode) {
db->n_bits = ++n_bits;
tgtbitno = 32-n_bits;
}
}
oldcode = incode;
}
dlen = wptr-dmsg->b_wptr;
outlen += dlen;
db->in_count += dlen;
dmsg->b_wptr = wptr;
db->bytes_out += ilen;
if (bsd_check(db) && (db->flags & DS_DEBUG)) {
cmn_err(CE_CONT,
"bsd_decomp%d: peer should have cleared dictionary\n",
db->unit);
}
++db->comp_count;
db->comp_bytes += ilen + BSD_OVHD;
++db->uncomp_count;
db->uncomp_bytes += outlen;
*dmpp = mret;
return (DECOMP_OK);
}
static int
bsd_set_effort(void *xarg, void *rarg, int effortlevel)
{
#ifdef DEBUG
struct bsd_db *xdb = (struct bsd_db *)xarg;
struct bsd_db *rdb = (struct bsd_db *)rarg;
if (effortlevel == 42 || effortlevel == 2112) {
if (rdb != NULL) {
rdb->flags |= DS_TESTIN;
cmn_err(CE_CONT, "bsd-comp: enabled input testing.");
}
if (effortlevel != 2112)
return (0);
}
if (effortlevel == 2001 || effortlevel == 2112) {
if (xdb != NULL) {
xdb->flags |= DS_TESTOUT;
cmn_err(CE_CONT, "bsd-comp: enabled output testing.");
}
return (0);
}
#endif
return (0);
}
#endif