X-Git-Url: https://git.ozlabs.org/?p=ppp.git;a=blobdiff_plain;f=modules%2Fbsd-comp.c;h=d30e0d25f69da08dc4781cdfc6e1b58e85f0e9c0;hp=a9852789534174d546c269920ce6d856689403f8;hb=eab0d24f3ee832231aa5ba844775e84084c392c3;hpb=7aa1222ea5fe1d3459c9cb31c2dc41d2f3826554 diff --git a/modules/bsd-comp.c b/modules/bsd-comp.c index a985278..d30e0d2 100644 --- a/modules/bsd-comp.c +++ b/modules/bsd-comp.c @@ -38,16 +38,41 @@ */ /* - * This version is for use with STREAMS under SunOS 4.x. + * This version is for use with STREAMS under SunOS 4.x, + * DEC Alpha OSF/1, and AIX 4.x. + * + * $Id: bsd-comp.c,v 1.8 1994/12/08 00:35:33 paulus Exp $ */ +#ifdef __aix4__ +#include +#endif #include #include #include -#include +#include +#include +#include #include -#define PACKET mblk_t +#ifdef sun +#include +#define ALLOCATE(n) kmem_alloc((n), KMEM_NOSLEEP) +#define FREE(p, n) kmem_free((p), (n)) +#endif + +#ifdef __osf__ +#include +#define ALLOCATE(n) kalloc((n)) +#define FREE(p, n) kfree((p), (n)) +#endif + +#ifdef __aix4__ +#define ALLOCATE(n) xmalloc((n), 0, pinned_heap) +#define FREE(p, n) xmfree((p), pinned_heap) +#endif + +#define PACKETPTR mblk_t * #include /* @@ -72,6 +97,15 @@ * compression is not going well. */ +/* + * Macros to extract protocol version and number of bits + * from the third byte of the BSD Compress CCP configuration option. + */ +#define BSD_VERSION(x) ((x) >> 5) +#define BSD_NBITS(x) ((x) & 0x1F) + +#define BSD_CURRENT_VERSION 1 + /* * A dictionary for doing BSD compress. */ @@ -80,22 +114,29 @@ struct bsd_db { u_int hsize; /* size of the hash table */ u_char hshift; /* used in hash function */ u_char n_bits; /* current bits/code */ - char debug; + u_char maxbits; + u_char debug; u_char unit; - u_short mru; + u_short seqno; /* sequence number of next packet */ + u_int hdrlen; /* header length to preallocate */ + u_int mru; u_int maxmaxcode; /* largest valid code */ u_int max_ent; /* largest code in use */ - u_long seqno; /* # of last byte of packet */ - u_long in_count; /* uncompressed bytes */ - u_long bytes_out; /* compressed bytes */ - u_long ratio; /* recent compression ratio */ - u_long checkpoint; /* when to next check the ratio */ - int clear_count; /* times dictionary cleared */ - int incomp_count; /* incompressible packets */ + u_int in_count; /* uncompressed bytes, aged */ + u_int bytes_out; /* compressed bytes, aged */ + u_int ratio; /* recent compression ratio */ + u_int checkpoint; /* when to next check the ratio */ + u_int clear_count; /* times dictionary cleared */ + u_int incomp_count; /* incompressible packets */ + u_int incomp_bytes; /* incompressible bytes */ + u_int uncomp_count; /* uncompressed packets */ + u_int uncomp_bytes; /* uncompressed bytes */ + u_int comp_count; /* compressed packets */ + u_int comp_bytes; /* compressed bytes */ u_short *lens; /* array of lengths of codes */ struct bsd_dict { union { /* hash value */ - u_long fcode; + u_int32_t fcode; struct { #ifdef BSD_LITTLE_ENDIAN u_short prefix; /* preceding code */ @@ -113,7 +154,7 @@ struct bsd_db { } dict[1]; }; -#define BSD_OVHD 3 /* BSD compress overhead/packet */ +#define BSD_OVHD 2 /* BSD compress overhead/packet */ #define MIN_BSD_BITS 9 #define BSD_INIT_BITS MIN_BSD_BITS #define MAX_BSD_BITS 15 @@ -124,12 +165,13 @@ static void bsd_free __P((void *state)); static int bsd_comp_init __P((void *state, u_char *options, int opt_len, int unit, int debug)); static int bsd_decomp_init __P((void *state, u_char *options, int opt_len, - int unit, int mru, int debug)); + int unit, int hdrlen, int mru, int debug)); static int bsd_compress __P((void *state, mblk_t **mret, mblk_t *mp, int slen, int maxolen)); static void bsd_incomp __P((void *state, mblk_t *dmsg)); -static mblk_t *bsd_decompress __P((void *state, mblk_t *cmp, int hdroff)); +static int bsd_decompress __P((void *state, mblk_t *cmp, mblk_t **dmpp)); static void bsd_reset __P((void *state)); +static void bsd_comp_stats __P((void *state, struct compstat *stats)); /* * Procedures exported to ppp_comp.c. @@ -141,12 +183,14 @@ struct compressor ppp_bsd_compress = { bsd_comp_init, /* comp_init */ bsd_reset, /* comp_reset */ bsd_compress, /* compress */ + bsd_comp_stats, /* comp_stat */ bsd_decomp_alloc, /* decomp_alloc */ bsd_free, /* decomp_free */ bsd_decomp_init, /* decomp_init */ bsd_reset, /* decomp_reset */ bsd_decompress, /* decompress */ bsd_incomp, /* incomp */ + bsd_comp_stats, /* decomp_stat */ }; /* @@ -160,12 +204,18 @@ struct compressor ppp_bsd_compress = { #define MAXCODE(b) ((1 << (b)) - 1) #define BADCODEM1 MAXCODE(MAX_BSD_BITS); -#define BSD_HASH(prefix,suffix,hshift) ((((u_long)(suffix)) << (hshift)) \ - ^ (u_long)(prefix)) -#define BSD_KEY(prefix,suffix) ((((u_long)(suffix)) << 16) + (u_long)(prefix)) +#define BSD_HASH(prefix,suffix,hshift) ((((u_int32_t)(suffix)) << (hshift)) \ + ^ (u_int32_t)(prefix)) +#define BSD_KEY(prefix,suffix) ((((u_int32_t)(suffix)) << 16) \ + + (u_int32_t)(prefix)) #define CHECK_GAP 10000 /* Ratio check interval */ +#define RATIO_SCALE_LOG 8 +#define RATIO_SCALE (1<>RATIO_SCALE_LOG) + +#define DECOMP_CHUNK 256 /* * clear the dictionary @@ -201,12 +251,12 @@ static int /* 1=output CLEAR */ bsd_check(db) struct bsd_db *db; { - u_long new_ratio; + u_int new_ratio; if (db->in_count >= db->checkpoint) { /* age the ratio by limiting the size of the counts */ - if (db->in_count >= 0x7fffff - || db->bytes_out >= 0x7fffff) { + 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; } @@ -219,13 +269,13 @@ bsd_check(db) * by incompressible data. * * This does not overflow, because - * db->in_count <= 0x7fffff. + * db->in_count <= RATIO_MAX. */ - new_ratio = db->in_count<<8; + 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 < 256) { + if (new_ratio < db->ratio || new_ratio < 1 * RATIO_SCALE) { bsd_clear(db); return 1; } @@ -235,6 +285,33 @@ bsd_check(db) return 0; } +/* + * Return statistics. + */ +static void +bsd_comp_stats(state, stats) + void *state; + struct compstat *stats; +{ + struct bsd_db *db = (struct bsd_db *) state; + u_int 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; +} + /* * Reset state, as on a CCP ResetReq. */ @@ -261,9 +338,10 @@ bsd_alloc(options, opt_len, decomp) u_int newlen, hsize, hshift, maxmaxcode; struct bsd_db *db; - if (opt_len != 3 || options[0] != 0x21 || options[1] != 3) + if (opt_len != 3 || options[0] != 0x21 || options[1] != 3 + || BSD_VERSION(options[2]) != BSD_CURRENT_VERSION) return NULL; - bits = options[2]; + bits = BSD_NBITS(options[2]); switch (bits) { case 9: /* needs 82152 for both directions */ case 10: /* needs 84144 */ @@ -294,7 +372,7 @@ bsd_alloc(options, opt_len, decomp) maxmaxcode = MAXCODE(bits); newlen = sizeof(*db) + (hsize-1) * (sizeof(db->dict[0])); - db = (struct bsd_db *) kmem_alloc(newlen, KMEM_NOSLEEP); + db = (struct bsd_db *) ALLOCATE(newlen); if (!db) return NULL; bzero(db, sizeof(*db) - sizeof(db->dict)); @@ -302,10 +380,9 @@ bsd_alloc(options, opt_len, decomp) if (!decomp) { db->lens = NULL; } else { - db->lens = (u_short *) kmem_alloc((maxmaxcode+1) * sizeof(db->lens[0]), - KMEM_NOSLEEP); + db->lens = (u_short *) ALLOCATE((maxmaxcode+1) * sizeof(db->lens[0])); if (!db->lens) { - kmem_free(db, newlen); + FREE(db, newlen); return NULL; } } @@ -314,6 +391,7 @@ bsd_alloc(options, opt_len, decomp) db->hsize = hsize; db->hshift = hshift; db->maxmaxcode = maxmaxcode; + db->maxbits = bits; return (void *) db; } @@ -325,8 +403,8 @@ bsd_free(state) struct bsd_db *db = (struct bsd_db *) state; if (db->lens) - kmem_free(db->lens, (db->maxmaxcode+1) * sizeof(db->lens[0])); - kmem_free(db, db->totlen); + FREE(db->lens, (db->maxmaxcode+1) * sizeof(db->lens[0])); + FREE(db, db->totlen); } static void * @@ -349,15 +427,16 @@ bsd_decomp_alloc(options, opt_len) * Initialize the database. */ static int -bsd_init(db, options, opt_len, unit, mru, debug, decomp) +bsd_init(db, options, opt_len, unit, hdrlen, mru, debug, decomp) struct bsd_db *db; u_char *options; - int opt_len, unit, mru, debug, decomp; + int opt_len, unit, hdrlen, mru, debug, decomp; { int i; if (opt_len != 3 || options[0] != 0x21 || options[1] != 3 - || MAXCODE(options[2]) != db->maxmaxcode + || BSD_VERSION(options[2]) != BSD_CURRENT_VERSION + || BSD_NBITS(options[2]) != db->maxbits || decomp && db->lens == NULL) return 0; @@ -373,12 +452,12 @@ bsd_init(db, options, opt_len, unit, mru, debug, decomp) } db->unit = unit; + db->hdrlen = hdrlen; db->mru = mru; - db->clear_count = -1; if (debug) db->debug = 1; - bsd_clear(db); + bsd_reset(db); return 1; } @@ -390,31 +469,29 @@ bsd_comp_init(state, options, opt_len, unit, debug) int opt_len, unit, debug; { return bsd_init((struct bsd_db *) state, options, opt_len, - unit, 0, debug, 0); + unit, 0, 0, debug, 0); } static int -bsd_decomp_init(state, options, opt_len, unit, mru, debug) +bsd_decomp_init(state, options, opt_len, unit, hdrlen, mru, debug) void *state; u_char *options; - int opt_len, unit, mru, debug; + int opt_len, unit, hdrlen, mru, debug; { return bsd_init((struct bsd_db *) state, options, opt_len, - unit, mru, debug, 1); + unit, hdrlen, mru, debug, 1); } - /* * compress a packet - * Assume the protocol is known to be >= 0x21 and < 0xff. * One change from the BSD compress command is that when the * code size expands, we do not output a bunch of padding. */ static int /* new slen */ -bsd_compress(state, mret, mp, slen, maxolen) +bsd_compress(state, mretp, mp, slen, maxolen) void *state; - mblk_t **mret; /* return compressed mbuf chain here */ + mblk_t **mretp; /* return compressed mbuf chain here */ mblk_t *mp; /* from here */ int slen; /* uncompressed length */ int maxolen; /* max compressed length */ @@ -424,17 +501,15 @@ bsd_compress(state, mret, mp, slen, maxolen) u_int max_ent = db->max_ent; u_int n_bits = db->n_bits; u_int bitno = 32; - u_long accm = 0; + u_int32_t accm = 0, fcode; struct bsd_dict *dictp; - u_long fcode; u_char c; - long hval, disp, ent; - mblk_t *np; + int hval, disp, ent, ilen; + mblk_t *np, *mret; u_char *rptr, *wptr; u_char *cp_end; int olen; mblk_t *m, **mnp; - int proto; #define PUTBYTE(v) { \ if (wptr) { \ @@ -462,20 +537,35 @@ bsd_compress(state, mret, mp, slen, maxolen) } while (bitno <= 24); \ } + /* + * First get the protocol and check that we're + * interested in this packet. + */ + *mretp = NULL; + rptr = mp->b_rptr; + if (rptr + PPP_HDRLEN > mp->b_wptr) { + if (!pullupmsg(mp, PPP_HDRLEN)) + return 0; + rptr = mp->b_rptr; + } + ent = PPP_PROTOCOL(rptr); /* get the protocol */ + if (ent < 0x21 || ent > 0xf9) + return 0; + /* Don't generate compressed packets which are larger than the uncompressed packet. */ if (maxolen > slen) maxolen = slen; /* Allocate enough message blocks to give maxolen total space. */ - mnp = mret; + mnp = &mret; for (olen = maxolen; olen > 0; ) { m = allocb((olen < 4096? olen: 4096), BPRI_MED); *mnp = m; if (m == NULL) { - if (*mret != NULL) { - freemsg(*mret); - mnp = mret; + if (mret != NULL) { + freemsg(mret); + mnp = &mret; } break; } @@ -484,34 +574,31 @@ bsd_compress(state, mret, mp, slen, maxolen) } *mnp = NULL; - rptr = mp->b_rptr; - if ((m = *mret) != NULL) { + if ((m = mret) != NULL) { wptr = m->b_wptr; cp_end = m->b_datap->db_lim; } else wptr = cp_end = NULL; olen = 0; - /* Copy the PPP header over, changing the protocol */ + /* + * Copy the PPP header over, changing the protocol, + * and install the 2-byte sequence number. + */ if (wptr) { - *wptr++ = rptr[0]; /* assumes the ppp header is */ - *wptr++ = rptr[1]; /* all in one mblk */ - *wptr++ = 0; /* change the protocol */ - *wptr++ = PPP_COMP; + wptr[0] = PPP_ADDRESS(rptr); + wptr[1] = PPP_CONTROL(rptr); + wptr[2] = 0; /* change the protocol */ + wptr[3] = PPP_COMP; + wptr[4] = db->seqno >> 8; + wptr[5] = db->seqno; + wptr += PPP_HDRLEN + BSD_OVHD; } - - /* install the 3-byte sequence number */ - slen += db->seqno - PPP_HDRLEN + 1; - db->seqno = slen; - *wptr++ = slen>>16; - *wptr++ = slen>>8; - *wptr++ = slen; - - /* start with the protocol byte */ - ent = rptr[3]; + ++db->seqno; rptr += PPP_HDRLEN; + slen = mp->b_wptr - rptr; - db->in_count += slen + 1; + ilen = slen + 1; np = mp->b_cont; for (;;) { if (slen <= 0) { @@ -522,7 +609,7 @@ bsd_compress(state, mret, mp, slen, maxolen) np = np->b_cont; if (!slen) continue; /* handle 0-length buffers */ - db->in_count += slen; + ilen += slen; } slen--; @@ -549,7 +636,7 @@ bsd_compress(state, mret, mp, slen, maxolen) if (dictp->codem1 >= max_ent) goto nomatch; } while (dictp->f.fcode != fcode); - ent = dictp->codem1+1; /* finally found (prefix,suffix) */ + ent = dictp->codem1 + 1; /* finally found (prefix,suffix) */ continue; nomatch: @@ -577,36 +664,48 @@ bsd_compress(state, mret, mp, slen, maxolen) ent = c; } - OUTPUT(ent); /* output the last code */ + OUTPUT(ent); /* output the last code */ db->bytes_out += olen; + db->in_count += ilen; + if (bitno < 32) + ++db->bytes_out; /* count complete bytes */ if (bsd_check(db)) - OUTPUT(CLEAR); /* do not count the CLEAR */ + OUTPUT(CLEAR); /* do not count the CLEAR */ - /* Pad dribble bits of last code with ones. + /* + * Pad dribble bits of last code with ones. * Do not emit a completely useless byte of ones. */ if (bitno != 32) PUTBYTE((accm | (0xff << (bitno-8))) >> 24); - /* Increase code size if we would have without the packet + /* + * Increase code size if we would have without the packet * boundary and as the decompressor will. */ if (max_ent >= MAXCODE(n_bits) && max_ent < db->maxmaxcode) db->n_bits++; - if (olen + PPP_HDRLEN + BSD_OVHD > maxolen && *mret != NULL) { + db->uncomp_bytes += ilen; + ++db->uncomp_count; + if (olen + PPP_HDRLEN + BSD_OVHD > maxolen && mret != NULL) { /* throw away the compressed stuff if it is longer than uncompressed */ - freemsg(*mret); - *mret = NULL; + freemsg(mret); + mret = NULL; + ++db->incomp_count; + db->incomp_bytes += ilen; } else if (wptr != NULL) { 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 @@ -616,7 +715,6 @@ bsd_compress(state, mret, mp, slen, maxolen) /* * Update the "BSD Compress" dictionary on the receiver for * incompressible data by pretending to compress the incoming data. - * The protocol is assumed to be < 0x100. */ static void bsd_incomp(state, dmsg) @@ -628,20 +726,27 @@ bsd_incomp(state, dmsg) u_int max_ent = db->max_ent; u_int n_bits = db->n_bits; struct bsd_dict *dictp; - u_long fcode; + u_int32_t fcode; u_char c; long hval, disp; - int slen; + int slen, ilen; u_int bitno = 7; u_char *rptr; u_int ent; - db->incomp_count++; + rptr = dmsg->b_rptr; + if (rptr + PPP_HDRLEN > dmsg->b_wptr) { + if (!pullupmsg(dmsg, PPP_HDRLEN)) + return; + rptr = dmsg->b_rptr; + } + ent = PPP_PROTOCOL(rptr); /* get the protocol */ + if (ent < 0x21 || ent > 0xf9) + return; + db->incomp_count++; db->seqno++; - db->in_count++; /* count the protocol as 1 byte */ - rptr = dmsg->b_rptr; - ent = rptr[3]; /* get the protocol */ + ilen = 1; /* count the protocol as 1 byte */ rptr += PPP_HDRLEN; for (;;) { slen = dmsg->b_wptr - rptr; @@ -652,8 +757,7 @@ bsd_incomp(state, dmsg) rptr = dmsg->b_rptr; continue; /* skip zero-length buffers */ } - db->in_count += slen; - db->seqno += slen; + ilen += slen; do { c = *rptr++; @@ -710,8 +814,14 @@ bsd_incomp(state, dmsg) } bitno += n_bits; /* output (count) the last code */ 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; + /* Increase code size if we would have without the packet * boundary and as the decompressor will. */ @@ -722,16 +832,28 @@ bsd_incomp(state, dmsg) /* * Decompress "BSD Compress" + * + * Because of patent problems, we return DECOMP_ERROR for errors + * found by inspecting the input data and for system problems, but + * DECOMP_FATALERROR for any errors which could possibly be said to + * be being detected "after" decompression. For DECOMP_ERROR, + * we can issue a CCP reset-request; for DECOMP_FATALERROR, we may be + * infringing a patent of Motorola's if we do, so we take CCP down + * instead. + * + * Given that the frame has the correct sequence number and a good FCS, + * errors such as invalid codes in the input most likely indicate a + * bug, so we return DECOMP_FATALERROR for them in order to turn off + * compression, even though they are detected by inspecting the input. */ -static mblk_t * /* 0=failed, so zap CCP */ -bsd_decompress(state, cmsg, hdroff) +static int +bsd_decompress(state, cmsg, dmpp) void *state; - mblk_t *cmsg; - int hdroff; + mblk_t *cmsg, **dmpp; { struct bsd_db *db = (struct bsd_db *) state; u_int max_ent = db->max_ent; - u_long accm = 0; + u_int32_t accm = 0; u_int bitno = 32; /* 1st valid bit in accm */ u_int n_bits = db->n_bits; u_int tgtbitno = 32-n_bits; /* bitno when we have a code */ @@ -739,19 +861,19 @@ bsd_decompress(state, cmsg, hdroff) int explen, i, seq, len; u_int incode, oldcode, finchar; u_char *p, *rptr, *wptr; - mblk_t *dmsg; - int adrs, ctrl; - int dlen, space, codelen; + mblk_t *dmsg, *mret; + int adrs, ctrl, ilen; + int dlen, space, codelen, extra; /* * Get at least the BSD Compress header in the first buffer */ rptr = cmsg->b_rptr; - if (rptr + PPP_HDRLEN + BSD_OVHD <= cmsg->b_wptr) { + if (rptr + PPP_HDRLEN + BSD_OVHD >= cmsg->b_wptr) { if (!pullupmsg(cmsg, PPP_HDRLEN + BSD_OVHD + 1)) { if (db->debug) printf("bsd_decomp%d: failed to pullup\n", db->unit); - return 0; + return DECOMP_ERROR; } rptr = cmsg->b_rptr; } @@ -763,28 +885,28 @@ bsd_decompress(state, cmsg, hdroff) adrs = PPP_ADDRESS(rptr); ctrl = PPP_CONTROL(rptr); rptr += PPP_HDRLEN; - seq = (rptr[0] << 16) + (rptr[1] << 8) + rptr[2]; - rptr += 3; - len = cmsg->b_wptr - rptr; - - /* check the sequence number and give up if the length is nonsense */ - explen = (seq - db->seqno) & 0xffffff; - db->seqno = seq; - if (explen > db->mru || explen < 1) { + seq = (rptr[0] << 8) + rptr[1]; + rptr += BSD_OVHD; + ilen = len = cmsg->b_wptr - rptr; + + /* + * Check the sequence number and give up if it is not what we expect. + */ + if (seq != db->seqno++) { if (db->debug) - printf("bsd_decomp%d: bad length 0x%x\n", db->unit, explen); - return 0; + printf("bsd_decomp%d: bad sequence # %d, expected %d\n", + db->unit, seq, db->seqno - 1); + return DECOMP_ERROR; } - /* allocate enough message blocks for the decompressed message */ - dlen = explen + PPP_HDRLEN - 1 + hdroff; - /* XXX assume decompressed packet fits in a single block */ - dmsg = allocb(dlen, BPRI_HI); - if (!dmsg) { - /* give up if cannot get an uncompressed buffer */ - return 0; - } - wptr = dmsg->b_wptr; + /* + * Allocate one message block to start with. + */ + if ((dmsg = allocb(DECOMP_CHUNK + db->hdrlen, BPRI_MED)) == NULL) + return DECOMP_ERROR; + mret = dmsg; + dmsg->b_wptr += db->hdrlen; + dmsg->b_rptr = wptr = dmsg->b_wptr; /* Fill in the ppp header, but not the last byte of the protocol (that comes from the decompressed data). */ @@ -794,29 +916,21 @@ bsd_decompress(state, cmsg, hdroff) wptr += PPP_HDRLEN - 1; space = dmsg->b_datap->db_lim - wptr; - db->bytes_out += len; - dlen = explen; oldcode = CLEAR; + explen = 0; for (;;) { if (len == 0) { cmsg = cmsg->b_cont; - if (!cmsg) { /* quit at end of message */ - if (dlen != 0) { - freemsg(dmsg); - if (db->debug) - printf("bsd_decomp%d: lost %d bytes\n", - db->unit, explen); - return 0; - } + if (!cmsg) /* quit at end of message */ break; - } rptr = cmsg->b_rptr; len = cmsg->b_wptr - rptr; - db->bytes_out += len; + ilen += len; continue; /* handle 0-length buffers */ } - /* Accumulate bytes until we have a complete code. + /* + * Accumulate bytes until we have a complete code. * Then get the next code, relying on the 32-bit, * unsigned accm to mask the result. */ @@ -830,7 +944,8 @@ bsd_decompress(state, cmsg, hdroff) bitno += n_bits; if (incode == CLEAR) { - /* The dictionary must only be cleared at + /* + * The dictionary must only be cleared at * the end of a packet. But there could be an * empty message block at the end. */ @@ -841,52 +956,61 @@ bsd_decompress(state, cmsg, hdroff) freemsg(dmsg); if (db->debug) printf("bsd_decomp%d: bad CLEAR\n", db->unit); - return 0; + return DECOMP_FATALERROR; } } bsd_clear(db); - explen = 0; + explen = ilen = 0; break; } + if (incode > max_ent + 2 || incode > db->maxmaxcode + || incode > max_ent && oldcode == CLEAR) { + freemsg(dmsg); + if (db->debug) { + printf("bsd_decomp%d: bad code 0x%x oldcode=0x%x ", + db->unit, incode, oldcode); + printf("max_ent=0x%x dlen=%d seqno=%d\n", + max_ent, dlen, db->seqno); + } + return DECOMP_FATALERROR; /* probably a bug */ + } + /* Special case for KwKwK string. */ if (incode > max_ent) { - if (incode > max_ent+2 || incode > db->maxmaxcode - || oldcode == CLEAR) { - freemsg(dmsg); - if (db->debug) { - printf("bsd_decomp%d: bad code 0x%x oldcode=0x%x ", - db->unit, incode, oldcode); - printf("max_ent=0x%x dlen=%d seqno=%d\n", - max_ent, dlen, db->seqno); - } - return 0; - } finchar = oldcode; - --dlen; - } else + extra = 1; + } else { finchar = incode; + extra = 0; + } codelen = db->lens[finchar]; - dlen -= codelen; - if (dlen < 0) { + explen += codelen + extra; + if (explen > db->mru + 1) { freemsg(dmsg); if (db->debug) - printf("bsd_decomp%d: ran out of buffer\n", db->unit); - return 0; + printf("bsd_decomp%d: ran out of mru\n", db->unit); + return DECOMP_FATALERROR; } - /* decode code and install in decompressed buffer */ - space -= codelen; + /* + * Decode this code and install it in the decompressed buffer. + */ + space -= codelen + extra; if (space < 0) { -#ifdef DEBUG - if (cmsg->b_cont) - len += msgdsize(cmsg->b_cont); - printf("bsd_decomp%d: overran output by %d with %d bytes left\n", - db->unit, -space, len); -#endif - freemsg(dmsg); - return 0; + /* Allocate another message block. */ + dmsg->b_wptr = wptr; + dlen = codelen + extra; + if (dlen < DECOMP_CHUNK) + dlen = DECOMP_CHUNK; + if ((dmsg->b_cont = allocb(dlen, BPRI_MED)) == NULL) { + freemsg(dmsg); + return DECOMP_ERROR; + } + dmsg = dmsg->b_cont; + wptr = dmsg->b_wptr; + space = dmsg->b_datap->db_lim - wptr - codelen - extra; } p = (wptr += codelen); while (finchar > LAST) { @@ -898,7 +1022,7 @@ bsd_decompress(state, cmsg, hdroff) printf("bsd_decomp%d: fell off end of chain ", db->unit); printf("0x%x at 0x%x by 0x%x, max_ent=0x%x\n", incode, finchar, db->dict[finchar].cptr, max_ent); - return 0; + return DECOMP_FATALERROR; } if (dictp->codem1 != finchar-1) { freemsg(dmsg); @@ -906,7 +1030,7 @@ bsd_decompress(state, cmsg, hdroff) db->unit, incode, finchar); printf("oldcode=0x%x cptr=0x%x codem1=0x%x\n", oldcode, db->dict[finchar].cptr, dictp->codem1); - return 0; + return DECOMP_FATALERROR; } #endif *--p = dictp->f.hs.suffix; @@ -920,10 +1044,8 @@ bsd_decompress(state, cmsg, hdroff) db->unit, codelen, incode, max_ent); #endif - if (incode > max_ent) { /* the KwKwK case again */ + if (extra) /* the KwKwK case again */ *wptr++ = finchar; - --space; - } /* * If not first code in a packet, and @@ -934,8 +1056,8 @@ bsd_decompress(state, cmsg, hdroff) */ if (oldcode != CLEAR && max_ent < db->maxmaxcode) { struct bsd_dict *dictp2; - u_long fcode; - long hval, disp; + u_int32_t fcode; + int hval, disp; fcode = BSD_KEY(oldcode,finchar); hval = BSD_HASH(oldcode,finchar,db->hshift); @@ -952,7 +1074,8 @@ bsd_decompress(state, cmsg, hdroff) } while (dictp->codem1 < max_ent); } - /* Invalidate previous hash table entry + /* + * Invalidate previous hash table entry * assigned this code, and then take it over */ dictp2 = &db->dict[max_ent+1]; @@ -976,20 +1099,22 @@ bsd_decompress(state, cmsg, hdroff) } dmsg->b_wptr = wptr; - /* fail on packets with bad lengths/sequence numbers */ - if (dlen != 0) { - freemsg(dmsg); - return 0; - } - - /* Keep the checkpoint right so that incompressible packets + /* + * Keep the checkpoint right so that incompressible packets * clear the dictionary at the right times. */ + db->bytes_out += ilen; db->in_count += explen; if (bsd_check(db) && db->debug) { printf("bsd_decomp%d: peer should have cleared dictionary\n", db->unit); } - return dmsg; + ++db->comp_count; + db->comp_bytes += ilen + BSD_OVHD; + ++db->uncomp_count; + db->uncomp_bytes += explen; + + *dmpp = mret; + return DECOMP_OK; }