Merge remote-tracking branch 'origin/master'
[unleashed/lotheac.git] / usr / src / uts / common / io / ppp / spppcomp / bsd-comp.c
blob46c3c19707765e0d746671d8e2fe58cfb7865e4f
1 /*
2 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
5 * Because this code is derived from the 4.3BSD compress source:
7 * Copyright (c) 1985, 1986 The Regents of the University of California.
8 * All rights reserved.
10 * This code is derived from software contributed to Berkeley by
11 * James A. Woods, derived from original work by Spencer Thomas
12 * and Joseph Orost.
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions
16 * are met:
17 * 1. Redistributions of source code must retain the above copyright
18 * notice, this list of conditions and the following disclaimer.
19 * 2. Redistributions in binary form must reproduce the above copyright
20 * notice, this list of conditions and the following disclaimer in the
21 * documentation and/or other materials provided with the distribution.
22 * 3. All advertising materials mentioning features or use of this software
23 * must display the following acknowledgement:
24 * This product includes software developed by the University of
25 * California, Berkeley and its contributors.
26 * 4. Neither the name of the University nor the names of its contributors
27 * may be used to endorse or promote products derived from this software
28 * without specific prior written permission.
30 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
31 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
32 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
34 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
35 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
36 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
37 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
38 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
39 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
40 * SUCH DAMAGE.
43 #pragma ident "%Z%%M% %I% %E% SMI"
46 * This version is for use with STREAMS in Solaris 2
48 * $Id: bsd-comp.c,v 1.20 1996/08/28 06:31:57 paulus Exp $
51 #include <sys/param.h>
52 #include <sys/types.h>
53 #include <sys/kmem.h>
54 #include <sys/stream.h>
55 #include <sys/cmn_err.h>
56 #include <sys/ddi.h>
57 #include <sys/sunddi.h>
58 #include <sys/byteorder.h>
59 #include <net/ppp_defs.h>
61 /* Defined for platform-neutral include file */
62 #define PACKETPTR mblk_t *
63 #include <net/ppp-comp.h>
65 #ifndef _BIG_ENDIAN
66 #define BSD_LITTLE_ENDIAN
67 #endif
69 #if DO_BSD_COMPRESS
72 * PPP "BSD compress" compression
74 * The differences between this compression and the classic BSD LZW
75 * source are obvious from the requirement that the classic code worked
76 * with files while this handles arbitrarily long streams that
77 * are broken into packets. They are:
79 * When the code size expands, a block of junk is not emitted by
80 * the compressor and not expected by the decompressor.
82 * New codes are not necessarily assigned every time an old
83 * code is output by the compressor. This is because a packet
84 * end forces a code to be emitted, but does not imply that a
85 * new sequence has been seen.
87 * The compression ratio is checked at the first end of a packet
88 * after the appropriate gap. Besides simplifying and speeding
89 * things up, this makes it more likely that the transmitter
90 * and receiver will agree when the dictionary is cleared when
91 * compression is not going well.
95 * A dictionary for doing BSD compress.
97 struct bsd_db {
98 int totlen; /* length of this structure */
99 uint_t hsize; /* size of the hash table */
100 uint32_t unit;
101 uchar_t hshift; /* used in hash function */
102 uchar_t n_bits; /* current bits/code */
103 uchar_t maxbits;
104 uchar_t flags;
105 ushort_t seqno; /* sequence number of next packet */
106 ushort_t mru;
107 uint_t hdrlen; /* header length to preallocate */
108 uint_t maxmaxcode; /* largest valid code */
109 uint_t max_ent; /* largest code in use */
110 uint_t in_count; /* uncompressed bytes, aged */
111 uint_t bytes_out; /* compressed bytes, aged */
112 uint_t ratio; /* recent compression ratio */
113 uint_t checkpoint; /* when to next check the ratio */
114 uint_t clear_count; /* times dictionary cleared */
115 uint_t incomp_count; /* incompressible packets */
116 uint_t incomp_bytes; /* incompressible bytes */
117 uint_t uncomp_count; /* uncompressed packets */
118 uint_t uncomp_bytes; /* uncompressed bytes */
119 uint_t comp_count; /* compressed packets */
120 uint_t comp_bytes; /* compressed bytes */
121 ushort_t *lens; /* array of lengths of codes */
122 struct bsd_dict {
123 union { /* hash value */
124 uint32_t fcode;
125 struct {
126 #ifdef BSD_LITTLE_ENDIAN
127 ushort_t prefix; /* preceding code */
128 uchar_t suffix; /* last character of new code */
129 uchar_t pad;
130 #else
131 uchar_t pad;
132 uchar_t suffix; /* last character of new code */
133 ushort_t prefix; /* preceding code */
134 #endif
135 } hs;
136 } f;
137 ushort_t codem1; /* output of hash table -1 */
138 ushort_t cptr; /* map code to hash entry */
139 } dict[1];
142 #define BSD_OVHD 2 /* BSD compress overhead/packet */
143 #define BSD_INIT_BITS BSD_MIN_BITS
145 /* db->flags values */
146 #define DS_DEBUG 0x01
147 #define DS_TESTIN 0x02
148 #define DS_TESTOUT 0x04
149 #define DS_INITDONE 0x08
151 static void *bsd_comp_alloc(uchar_t *options, int opt_len);
152 static void *bsd_decomp_alloc(uchar_t *options, int opt_len);
153 static void bsd_free(void *state);
154 static int bsd_comp_init(void *state, uchar_t *options, int opt_len,
155 int unit, int hdrlen, int debug);
156 static int bsd_decomp_init(void *state, uchar_t *options, int opt_len,
157 int unit, int hdrlen, int mru, int debug);
158 static int bsd_compress(void *state, mblk_t **mret,
159 mblk_t *mp, int slen, int maxolen);
160 static int bsd_incomp(void *state, mblk_t *dmsg);
161 static int bsd_decompress(void *state, mblk_t **dmpp);
162 static void bsd_reset(void *state);
163 static void bsd_comp_stats(void *state, struct compstat *stats);
164 static int bsd_set_effort(void *xarg, void *rarg, int effortlevel);
167 * Procedures exported to ppp_comp.c.
169 struct compressor ppp_bsd_compress = {
170 CI_BSD_COMPRESS, /* compress_proto */
171 bsd_comp_alloc, /* comp_alloc */
172 bsd_free, /* comp_free */
173 bsd_comp_init, /* comp_init */
174 bsd_reset, /* comp_reset */
175 bsd_compress, /* compress */
176 bsd_comp_stats, /* comp_stat */
177 bsd_decomp_alloc, /* decomp_alloc */
178 bsd_free, /* decomp_free */
179 bsd_decomp_init, /* decomp_init */
180 bsd_reset, /* decomp_reset */
181 bsd_decompress, /* decompress */
182 bsd_incomp, /* incomp */
183 bsd_comp_stats, /* decomp_stat */
184 bsd_set_effort, /* set_effort */
188 * the next two codes should not be changed lightly, as they must not
189 * lie within the contiguous general code space.
191 #define CLEAR 256 /* table clear output code */
192 #define FIRST 257 /* first free entry */
193 #define LAST 255
195 #define MAXCODE(b) ((1 << (b)) - 1)
196 #define BADCODEM1 MAXCODE(BSD_MAX_BITS)
198 #define BSD_HASH(prefix, suffix, hshift) \
199 ((((uint32_t)(suffix)) << (hshift)) ^ (uint32_t)(prefix))
201 #define BSD_KEY(prefix, suffix) \
202 ((((uint32_t)(suffix)) << 16) + (uint32_t)(prefix))
204 #define CHECK_GAP 10000 /* Ratio check interval */
206 #define RATIO_SCALE_LOG 8
207 #define RATIO_SCALE (1 << RATIO_SCALE_LOG)
208 #define RATIO_MAX (0x7fffffff >> RATIO_SCALE_LOG)
210 #define DECOMP_CHUNK 256
213 * bsd_clear()
215 * clear the dictionary
217 static void
218 bsd_clear(struct bsd_db *db)
220 db->clear_count++;
221 db->max_ent = FIRST-1;
222 db->n_bits = BSD_INIT_BITS;
223 db->ratio = 0;
224 db->bytes_out = 0;
225 db->in_count = 0;
226 db->checkpoint = CHECK_GAP;
230 * bsd_check()
232 * If the dictionary is full, then see if it is time to reset it.
234 * Compute the compression ratio using fixed-point arithmetic
235 * with 8 fractional bits.
237 * Since we have an infinite stream instead of a single file,
238 * watch only the local compression ratio.
240 * Since both peers must reset the dictionary at the same time even in
241 * the absence of CLEAR codes (while packets are incompressible), they
242 * must compute the same ratio.
244 static int /* 1=output CLEAR */
245 bsd_check(struct bsd_db *db)
247 uint_t new_ratio;
249 if (db->in_count >= db->checkpoint) {
252 * age the ratio by limiting the size of the counts
254 if (db->in_count >= RATIO_MAX || db->bytes_out >= RATIO_MAX) {
255 db->in_count -= db->in_count/4;
256 db->bytes_out -= db->bytes_out/4;
259 db->checkpoint = db->in_count + CHECK_GAP;
261 if (db->max_ent >= db->maxmaxcode) {
264 * Reset the dictionary only if the ratio is worse,
265 * or if it looks as if it has been poisoned
266 * by incompressible data.
268 * This does not overflow, because
269 * db->in_count <= RATIO_MAX.
271 new_ratio = db->in_count << RATIO_SCALE_LOG;
273 if (db->bytes_out != 0) {
274 new_ratio /= db->bytes_out;
277 if (new_ratio < db->ratio ||
278 new_ratio < 1 * RATIO_SCALE) {
279 bsd_clear(db);
280 return (1);
283 db->ratio = new_ratio;
287 return (0);
291 * bsd_comp_stats()
293 * Return statistics.
295 static void
296 bsd_comp_stats(void *state, struct compstat *stats)
298 struct bsd_db *db = (struct bsd_db *)state;
299 uint_t out;
301 stats->unc_bytes = db->uncomp_bytes;
302 stats->unc_packets = db->uncomp_count;
303 stats->comp_bytes = db->comp_bytes;
304 stats->comp_packets = db->comp_count;
305 stats->inc_bytes = db->incomp_bytes;
306 stats->inc_packets = db->incomp_count;
307 stats->ratio = db->in_count;
309 out = db->bytes_out;
311 if (stats->ratio <= 0x7fffff) {
312 stats->ratio <<= 8;
313 } else {
314 out >>= 8;
317 if (out != 0) {
318 stats->ratio /= out;
323 * bsd_reset()
325 * Reset state, as on a CCP ResetReq.
327 static void
328 bsd_reset(void *state)
330 struct bsd_db *db = (struct bsd_db *)state;
332 if (db->hsize != 0) {
333 db->seqno = 0;
335 bsd_clear(db);
337 db->clear_count = 0;
342 * bsd_alloc()
344 * Allocate space for a (de) compressor.
346 static void *
347 bsd_alloc(uchar_t *options, int opt_len, int decomp)
349 int bits;
350 uint_t newlen;
351 uint_t hsize;
352 uint_t hshift;
353 uint_t maxmaxcode;
354 uint_t ilen;
355 struct bsd_db *db;
357 if (opt_len != 3 ||
358 options[0] != CI_BSD_COMPRESS ||
359 options[1] != 3 ||
360 BSD_VERSION(options[2]) != BSD_CURRENT_VERSION) {
362 return (NULL);
365 bits = BSD_NBITS(options[2]);
367 switch (bits) {
369 case 9: /* needs 82152 for both directions */
370 case 10: /* needs 84144 */
371 case 11: /* needs 88240 */
372 case 12: /* needs 96432 */
374 hsize = 5003;
375 hshift = 4;
377 break;
379 case 13: /* needs 176784 */
381 hsize = 9001;
382 hshift = 5;
384 break;
386 case 14: /* needs 353744 */
388 hsize = 18013;
389 hshift = 6;
391 break;
393 case 15: /* needs 691440 */
395 hsize = 35023;
396 hshift = 7;
398 break;
400 /* XXX: this falls thru - it was originally commented */
401 case 16: /* needs 1366160--far too much, */
402 /* hsize = 69001; */ /* and 69001 is too big for cptr */
403 /* hshift = 8; */ /* in struct bsd_db */
404 /* break; */
406 default:
408 return (NULL);
411 maxmaxcode = MAXCODE(bits);
412 ilen = newlen = sizeof (*db) + (hsize-1) * sizeof (db->dict[0]);
413 if (decomp)
414 newlen += (maxmaxcode+1) * sizeof (db->lens[0]);
415 db = kmem_alloc(newlen, KM_NOSLEEP);
416 if (!db) {
417 return (NULL);
420 bzero(db, sizeof (*db) - sizeof (db->dict));
422 if (!decomp) {
423 db->lens = NULL;
424 } else {
425 db->lens = (ushort_t *)((caddr_t)db + ilen);
428 db->totlen = newlen;
429 db->hsize = hsize;
430 db->hshift = (uchar_t)hshift;
431 db->maxmaxcode = maxmaxcode;
432 db->maxbits = (uchar_t)bits;
434 return ((void *)db);
438 * bsd_free()
440 static void
441 bsd_free(void *state)
443 struct bsd_db *db = (struct bsd_db *)state;
445 if (db->hsize != 0) {
446 /* XXX feeble attempt to catch bad references. */
447 db->hsize = 0;
449 kmem_free(db, db->totlen);
454 * bsd_comp_alloc()
456 static void *
457 bsd_comp_alloc(uchar_t *options, int opt_len)
459 return (bsd_alloc(options, opt_len, 0));
463 * bsd_decomp_alloc()
465 static void *
466 bsd_decomp_alloc(uchar_t *options, int opt_len)
468 return (bsd_alloc(options, opt_len, 1));
472 * bsd_init()
474 * Initialize the database.
476 static int
477 bsd_init(struct bsd_db *db, uchar_t *options, int opt_len, int unit,
478 int hdrlen, int mru, int debug, int decomp)
480 int i;
482 if (db->hsize == 0 || opt_len < CILEN_BSD_COMPRESS ||
483 options[0] != CI_BSD_COMPRESS ||
484 options[1] != CILEN_BSD_COMPRESS ||
485 BSD_VERSION(options[2]) != BSD_CURRENT_VERSION ||
486 BSD_NBITS(options[2]) != db->maxbits ||
487 decomp && db->lens == NULL) {
489 return (0);
492 if (decomp) {
493 i = LAST + 1;
495 while (i != 0) {
496 db->lens[--i] = 1;
500 i = db->hsize;
502 while (i != 0) {
503 db->dict[--i].codem1 = BADCODEM1;
504 db->dict[i].cptr = 0;
507 db->unit = unit;
508 db->hdrlen = hdrlen;
509 db->mru = (ushort_t)mru;
511 if (debug) {
512 db->flags |= DS_DEBUG;
515 bsd_reset(db);
517 db->flags |= DS_INITDONE;
519 return (1);
523 * bsd_comp_init()
525 static int
526 bsd_comp_init(void *state, uchar_t *options, int opt_len, int unit, int hdrlen,
527 int debug)
529 return (bsd_init((struct bsd_db *)state, options, opt_len,
530 unit, hdrlen, 0, debug, 0));
534 * bsd_decomp_init()
536 static int
537 bsd_decomp_init(void *state, uchar_t *options, int opt_len, int unit,
538 int hdrlen, int mru, int debug)
540 return (bsd_init((struct bsd_db *)state, options, opt_len,
541 unit, hdrlen, mru, debug, 1));
546 * bsd_compress()
548 * compress a packet
549 * One change from the BSD compress command is that when the
550 * code size expands, we do not output a bunch of padding.
552 * N.B. at present, we ignore the hdrlen specified in the comp_init call.
554 static int /* new slen */
555 bsd_compress(void *state, mblk_t **mretp, mblk_t *mp, int slen, int maxolen)
557 struct bsd_db *db = (struct bsd_db *)state;
558 int hshift = db->hshift;
559 uint_t max_ent = db->max_ent;
560 uint_t n_bits = db->n_bits;
561 uint_t bitno = 32;
562 uint32_t accm = 0;
563 uint32_t fcode;
564 struct bsd_dict *dictp;
565 uchar_t c;
566 int hval;
567 int disp;
568 int ent;
569 int ilen = slen - (PPP_HDRLEN-1);
570 mblk_t *mret;
571 uchar_t *rptr, *rmax;
572 uchar_t *wptr;
573 uchar_t *cp_end;
574 int olen;
575 mblk_t *m;
576 mblk_t **mnp;
577 int hdlcaddr, hdlcctl;
579 ASSERT(db->flags & DS_INITDONE);
581 #define PUTBYTE(v) { \
582 if (wptr) { \
583 *wptr++ = (v); \
584 if (wptr >= cp_end) { \
585 m->b_wptr = wptr; \
586 m = m->b_cont; \
587 if (m) { \
588 wptr = m->b_wptr; \
589 cp_end = m->b_datap->db_lim; \
590 } else { \
591 wptr = NULL; \
595 ++olen; \
598 #define OUTPUT(ent) { \
599 bitno -= n_bits; \
600 accm |= ((ent) << bitno); \
601 do { \
602 PUTBYTE(accm >> 24); \
603 accm <<= 8; \
604 bitno += 8; \
605 } while (bitno <= 24); \
608 #define ADJRPTR() { \
609 if (rptr != NULL) { \
610 while (rptr >= rmax) { \
611 if ((mp = mp->b_cont) == NULL) { \
612 rptr = NULL; \
613 break; \
615 rptr = mp->b_rptr; \
616 rmax = mp->b_wptr; \
621 #define GETBYTE(v) { \
622 if (rptr != NULL) { \
623 (v) = *rptr++; \
627 if (db->hsize == 0)
628 return (-1);
631 * First get the protocol and check that we're
632 * interested in this packet.
634 *mretp = NULL;
635 rptr = mp->b_rptr;
636 rmax = mp->b_wptr;
638 /* We CANNOT do a pullup here; it's not our buffer to toy with. */
639 ADJRPTR();
640 GETBYTE(hdlcaddr);
641 ADJRPTR();
642 GETBYTE(hdlcctl);
643 ADJRPTR();
644 GETBYTE(ent);
645 ADJRPTR();
648 * Per RFC 1977, the protocol field must be compressed using a
649 * PFC-like procedure. Also, all protocols between 0000-3FFF
650 * except the two compression protocols must be LZ compressed.
652 if (ent == 0) {
653 GETBYTE(ent);
654 if (rptr == NULL || ent == PPP_COMP || ent == PPP_COMPFRAG)
655 return (0);
656 } else {
657 if (ent > 0x3F)
658 return (0);
659 ilen++;
663 * Don't generate compressed packets that are larger than the
664 * source (uncompressed) packet.
666 if (maxolen > slen) {
667 maxolen = slen;
669 if (maxolen < 6)
670 maxolen = 6;
673 * Allocate enough message blocks to give maxolen total space
675 mnp = &mret;
676 for (olen = maxolen; olen > 0; ) {
678 m = allocb((olen < 4096? olen: 4096), BPRI_MED);
680 *mnp = m;
681 if (m == NULL) {
682 if (mnp == &mret)
683 return (0);
684 /* We allocated some; hope for the best. */
685 break;
688 mnp = &m->b_cont;
689 olen -= m->b_datap->db_lim - m->b_wptr;
692 *mnp = NULL;
694 m = mret;
695 wptr = m->b_wptr;
696 cp_end = m->b_datap->db_lim;
698 olen = 0;
701 * Copy the PPP header over, changing the protocol,
702 * and install the 2-byte sequence number
704 *wptr++ = hdlcaddr;
705 *wptr++ = hdlcctl;
706 *wptr++ = PPP_COMP>>8; /* change the protocol */
707 *wptr++ = PPP_COMP;
708 *wptr++ = db->seqno >> 8;
709 *wptr++ = db->seqno;
711 #ifdef DEBUG
713 * If testing output, just garbling the sequence here does the
714 * trick.
716 if ((db->flags & DS_TESTOUT) && (db->seqno % 100) == 50)
717 wptr[-1] ^= 0xAA;
718 #endif
720 ++db->seqno;
722 for (;;) {
723 ADJRPTR();
724 if (rptr == NULL)
725 break;
727 GETBYTE(c);
729 fcode = BSD_KEY(ent, c);
730 hval = BSD_HASH(ent, c, hshift);
732 dictp = &db->dict[hval];
735 * Validate and then check the entry
737 if (dictp->codem1 >= max_ent) {
738 goto nomatch;
741 if (dictp->f.fcode == fcode) {
742 ent = dictp->codem1+1;
745 * found (prefix,suffix)
747 continue;
751 * continue probing until a match or invalid entry
753 disp = (hval == 0) ? 1 : hval;
755 do {
756 hval += disp;
757 if (hval >= db->hsize) {
758 hval -= db->hsize;
759 if (hval >= db->hsize) {
760 if (db->flags & DS_DEBUG) {
761 cmn_err(CE_CONT,
762 "bsd_comp%d: internal "
763 "error\n",
764 db->unit);
766 /* Caller will free it all */
767 return (-1);
771 dictp = &db->dict[hval];
773 if (dictp->codem1 >= max_ent) {
774 goto nomatch;
776 } while (dictp->f.fcode != fcode);
779 * finally found (prefix,suffix)
781 ent = dictp->codem1 + 1;
783 continue;
785 nomatch:
787 * output the prefix
789 OUTPUT(ent);
792 * code -> hashtable
794 if (max_ent < db->maxmaxcode) {
795 struct bsd_dict *dictp2;
798 * expand code size if needed
800 if (max_ent >= MAXCODE(n_bits)) {
801 db->n_bits = ++n_bits;
805 * Invalidate old hash table entry using
806 * this code, and then take it over.
808 dictp2 = &db->dict[max_ent+1];
810 if (db->dict[dictp2->cptr].codem1 == max_ent) {
811 db->dict[dictp2->cptr].codem1 = BADCODEM1;
814 dictp2->cptr = (ushort_t)hval;
815 dictp->codem1 = max_ent;
816 dictp->f.fcode = fcode;
818 db->max_ent = ++max_ent;
821 ent = c;
825 * output the last code
827 OUTPUT(ent);
829 olen += (32-bitno+7)/8; /* count complete bytes */
831 db->bytes_out += olen;
832 db->in_count += ilen;
834 if (bsd_check(db)) {
835 OUTPUT(CLEAR); /* do not count the CLEAR */
839 * Pad dribble bits of last code with ones.
840 * Do not emit a completely useless byte of ones.
842 if (bitno != 32) {
843 PUTBYTE((accm | (0xff << (bitno - 8))) >> 24);
847 * Increase code size if we would have without the packet
848 * boundary and as the decompressor will.
850 if (max_ent >= MAXCODE(n_bits) && max_ent < db->maxmaxcode) {
851 db->n_bits++;
854 db->uncomp_bytes += ilen;
855 ++db->uncomp_count;
857 if (wptr == NULL || olen + PPP_HDRLEN + BSD_OVHD >= maxolen) {
859 * throw away the compressed stuff if it is longer
860 * than uncompressed
862 freemsg(mret);
864 mret = NULL;
866 ++db->incomp_count;
867 db->incomp_bytes += ilen;
869 } else {
871 m->b_wptr = wptr;
872 if (m->b_cont) {
873 freemsg(m->b_cont);
874 m->b_cont = NULL;
877 ++db->comp_count;
878 db->comp_bytes += olen + BSD_OVHD;
881 *mretp = mret;
883 return (olen + PPP_HDRLEN + BSD_OVHD);
884 #undef OUTPUT
885 #undef PUTBYTE
890 * bsd_incomp()
892 * Update the "BSD Compress" dictionary on the receiver for
893 * incompressible data by pretending to compress the incoming data.
895 static int
896 bsd_incomp(void *state, mblk_t *mp)
898 struct bsd_db *db = (struct bsd_db *)state;
899 uint_t hshift = db->hshift;
900 uint_t max_ent = db->max_ent;
901 uint_t n_bits = db->n_bits;
902 struct bsd_dict *dictp;
903 uint32_t fcode;
904 uchar_t c;
905 long hval;
906 long disp;
907 int slen;
908 int ilen;
909 uint_t bitno = 7;
910 uchar_t *rptr, *rmax;
911 uint_t ent;
913 ASSERT(db->flags & DS_INITDONE);
915 if (db->hsize == 0)
916 return (-1);
918 rptr = mp->b_rptr;
919 rmax = mp->b_wptr;
920 ADJRPTR();
921 GETBYTE(ent); /* address */
922 ADJRPTR();
923 GETBYTE(ent); /* control */
924 ADJRPTR();
925 GETBYTE(ent); /* protocol high */
926 ADJRPTR();
929 * Per RFC 1977, the protocol field must be compressed using a
930 * PFC-like procedure. Also, all protocols between 0000-3FFF
931 * except the two compression protocols must be LZ compressed.
933 ilen = 1; /* count the protocol as 1 byte */
934 if (ent == 0) {
935 GETBYTE(ent);
936 if (rptr == NULL || ent == PPP_COMP || ent == PPP_COMPFRAG)
937 return (0);
938 } else {
939 if (ent > 0x3F)
940 return (0);
941 ilen++;
944 db->seqno++;
946 for (;;) {
948 slen = mp->b_wptr - rptr;
949 if (slen <= 0) {
950 mp = mp->b_cont;
951 if (!mp) {
952 break;
955 rptr = mp->b_rptr;
956 continue; /* skip zero-length buffers */
959 ilen += slen;
961 do {
962 c = *rptr++;
964 fcode = BSD_KEY(ent, c);
965 hval = BSD_HASH(ent, c, hshift);
967 dictp = &db->dict[hval];
970 * validate and then check the entry
972 if (dictp->codem1 >= max_ent) {
973 goto nomatch;
976 if (dictp->f.fcode == fcode) {
977 ent = dictp->codem1 + 1;
978 continue; /* found (prefix,suffix) */
982 * continue probing until a match or invalid entry
984 disp = (hval == 0) ? 1 : hval;
985 do {
986 hval += disp;
987 if (hval >= db->hsize) {
988 hval -= db->hsize;
989 if (hval >= db->hsize) {
990 if (db->flags & DS_DEBUG) {
991 cmn_err(CE_CONT,
992 "bsd_incomp%d: "
993 "internal error\n",
994 db->unit);
996 return (-1);
1000 dictp = &db->dict[hval];
1001 if (dictp->codem1 >= max_ent) {
1002 goto nomatch;
1004 } while (dictp->f.fcode != fcode);
1006 ent = dictp->codem1+1;
1007 continue; /* finally found (prefix,suffix) */
1009 nomatch: /* output (count) the prefix */
1010 bitno += n_bits;
1013 * code -> hashtable
1015 if (max_ent < db->maxmaxcode) {
1016 struct bsd_dict *dictp2;
1019 * expand code size if needed
1021 if (max_ent >= MAXCODE(n_bits)) {
1022 db->n_bits = ++n_bits;
1026 * Invalidate previous hash table entry
1027 * assigned this code, and then take it over.
1029 dictp2 = &db->dict[max_ent+1];
1030 if (db->dict[dictp2->cptr].codem1 == max_ent) {
1031 db->dict[dictp2->cptr].codem1 =
1032 BADCODEM1;
1035 dictp2->cptr = (ushort_t)hval;
1036 dictp->codem1 = max_ent;
1037 dictp->f.fcode = fcode;
1039 db->max_ent = ++max_ent;
1040 db->lens[max_ent] = db->lens[ent]+1;
1043 ent = c;
1044 } while (--slen != 0);
1047 bitno += n_bits; /* output (count) the last code */
1049 db->bytes_out += bitno/8;
1050 db->in_count += ilen;
1052 (void) bsd_check(db);
1054 ++db->incomp_count;
1055 db->incomp_bytes += ilen;
1056 ++db->uncomp_count;
1057 db->uncomp_bytes += ilen;
1060 * Increase code size if we would have without the packet
1061 * boundary and as the decompressor will.
1063 if (max_ent >= MAXCODE(n_bits) && max_ent < db->maxmaxcode) {
1064 db->n_bits++;
1066 return (0);
1067 #undef ADJRPTR
1072 * bsd_decompress()
1074 * Decompress "BSD Compress"
1076 * Because of patent problems, we return DECOMP_ERROR for errors
1077 * found by inspecting the input data and for system problems, but
1078 * DECOMP_FATALERROR for any errors which could possibly be said to
1079 * be being detected "after" decompression. For DECOMP_ERROR,
1080 * we can issue a CCP reset-request; for DECOMP_FATALERROR, we may be
1081 * infringing a patent of Motorola's if we do, so we take CCP down
1082 * instead.
1084 * Given that the frame has the correct sequence number and a good FCS,
1085 * errors such as invalid codes in the input most likely indicate a
1086 * bug, so we return DECOMP_FATALERROR for them in order to turn off
1087 * compression, even though they are detected by inspecting the input.
1089 static int
1090 bsd_decompress(void *state, mblk_t **dmpp)
1092 mblk_t *cmsg = *dmpp, *mnext;
1093 struct bsd_db *db = (struct bsd_db *)state;
1094 uint_t max_ent = db->max_ent;
1095 uint32_t accm = 0;
1096 uint_t bitno = 32; /* 1st valid bit in accm */
1097 uint_t n_bits = db->n_bits;
1098 uint_t tgtbitno = 32 - n_bits; /* bitno when we have a code */
1099 struct bsd_dict *dictp;
1100 int explen;
1101 int seq;
1102 uint_t incode;
1103 uint_t oldcode;
1104 uint_t finchar = 0, ofinchar;
1105 uchar_t *p;
1106 uchar_t *rptr, *rmax;
1107 uchar_t *wptr, *prepos;
1108 mblk_t *dmsg;
1109 mblk_t *mret;
1110 int ilen;
1111 int dlen;
1112 int codelen;
1113 int extra;
1114 int decode_proto;
1115 int blockctr;
1116 int outlen;
1117 int adrs, ctrl;
1119 ASSERT(db->flags & DS_INITDONE);
1121 /* Note: spppcomp already did a pullup to fix the first buffer. */
1122 *dmpp = NULL;
1123 rptr = cmsg->b_rptr;
1124 rmax = cmsg->b_wptr;
1125 ilen = 0;
1128 * Note that we free as we go. If we fail to decompress,
1129 * there's nothing good that the caller can do.
1131 #define ADJRPTR() \
1132 while (rptr >= rmax) { \
1133 mnext = cmsg->b_cont; \
1134 freeb(cmsg); \
1135 if ((cmsg = mnext) == NULL) { \
1136 rptr = NULL; \
1137 break; \
1139 rptr = cmsg->b_rptr; \
1140 rmax = cmsg->b_wptr; \
1141 ilen += rmax-rptr; \
1145 * Save the address/control from the PPP header
1146 * and then get the sequence number.
1148 adrs = rptr[0];
1149 ctrl = rptr[1];
1150 rptr += 4;
1151 ADJRPTR();
1152 seq = rptr == NULL ? 0 : (*rptr++ << 8);
1153 ADJRPTR();
1154 if (rptr == NULL) {
1155 if (db->flags & DS_DEBUG) {
1156 cmn_err(CE_CONT, "bsd_decomp%d: bad buffer\n",
1157 db->unit);
1159 return (DECOMP_ERROR);
1161 seq |= *rptr++;
1163 #ifdef DEBUG
1165 * If testing input, just pretending the sequence is bad here
1166 * does the trick.
1168 if ((db->flags & DS_TESTIN) && (db->seqno % 300) == 101)
1169 seq ^= 0x55;
1170 #endif
1173 * Check the sequence number and give up if it is not what we expect.
1175 if (db->hsize == 0 || seq != db->seqno++) {
1176 freemsg(cmsg);
1177 if (db->flags & DS_DEBUG) {
1178 cmn_err(CE_CONT, "bsd_decomp%d: bad sequence # %d, "
1179 "expected %d\n", db->unit, seq, db->seqno - 1);
1182 return (DECOMP_ERROR);
1186 * Allocate one message block to start with.
1188 if ((dmsg = allocb(DECOMP_CHUNK + db->hdrlen, BPRI_MED)) == NULL) {
1189 freemsg(cmsg);
1190 if (db->flags & DS_DEBUG) {
1191 cmn_err(CE_CONT,
1192 "bsd_decomp%d: can't allocate first buffer\n",
1193 db->unit);
1195 return (DECOMP_ERROR);
1199 * Avoid an error that might cause us to allocate all available memory.
1200 * Enforce a maximum number of blocks to allocate for message. We add
1201 * a fudge factor of 5 extra blocks, in order to avoid unnecessary
1202 * DECOMP_ERROR when the code size is small (9).
1204 blockctr = ((db->mru + 32 + DECOMP_CHUNK - 1) / DECOMP_CHUNK) + 5;
1206 mret = dmsg;
1207 dmsg->b_wptr += db->hdrlen;
1208 dmsg->b_rptr = wptr = dmsg->b_wptr;
1211 * Insert PPP header. This shouldn't be needed!
1213 *wptr++ = adrs;
1214 *wptr++ = ctrl;
1215 prepos = wptr;
1216 *wptr++ = 0;
1217 dmsg->b_wptr = wptr;
1219 explen = dmsg->b_datap->db_lim - wptr;
1220 oldcode = CLEAR;
1221 ilen = rmax-rptr;
1223 outlen = 0;
1224 decode_proto = 1;
1225 for (;;) {
1226 ADJRPTR();
1227 if (rptr == NULL)
1228 break;
1231 * Accumulate bytes until we have a complete code.
1232 * Then get the next code, relying on the 32-bit,
1233 * unsigned accm to mask the result.
1235 bitno -= 8;
1237 accm |= *rptr++ << bitno;
1239 if (tgtbitno < bitno) {
1240 continue;
1243 incode = accm >> tgtbitno;
1244 accm <<= n_bits;
1245 bitno += n_bits;
1247 if (incode == CLEAR) {
1250 * The dictionary must only be cleared at
1251 * the end of a packet. But there could be an
1252 * empty message block at the end.
1254 ADJRPTR();
1255 if (rptr != NULL) {
1256 freemsg(mret);
1257 freemsg(cmsg);
1258 if (db->flags & DS_DEBUG) {
1259 cmn_err(CE_CONT,
1260 "bsd_decomp%d: bad CLEAR\n",
1261 db->unit);
1264 return (DECOMP_FATALERROR);
1267 bsd_clear(db);
1268 /* Have to keep cleared state variables! */
1269 outlen += wptr-dmsg->b_wptr;
1270 dmsg->b_wptr = wptr;
1271 db->comp_bytes += ilen;
1272 ilen = 0;
1273 break;
1277 * Special case for KwKwK string
1279 ofinchar = finchar;
1280 if (incode > max_ent) {
1281 if (incode > max_ent + 2 ||
1282 incode > db->maxmaxcode ||
1283 oldcode == CLEAR) {
1284 freemsg(cmsg);
1285 freemsg(mret);
1287 /* probably a bug if we get here */
1288 if (db->flags & DS_DEBUG) {
1289 cmn_err(CE_CONT,
1290 "bsd_decomp%d: bad code 0x%x "
1291 "oldcode=0x%x ", db->unit, incode,
1292 oldcode);
1295 return (DECOMP_FATALERROR);
1297 finchar = oldcode;
1298 extra = 1;
1299 } else {
1300 finchar = incode;
1301 extra = 0;
1303 codelen = db->lens[finchar];
1306 * Decode this code and install it in the decompressed buffer
1308 explen -= codelen + extra;
1309 if (explen < 0) {
1311 * Allocate another message block
1313 dlen = wptr - dmsg->b_wptr;
1314 outlen += dlen;
1315 db->in_count += dlen;
1316 dmsg->b_wptr = wptr;
1317 dlen = codelen + extra;
1319 if (dlen < DECOMP_CHUNK) {
1320 dlen = DECOMP_CHUNK;
1323 if ((--blockctr < 0) ||
1324 (dmsg->b_cont = allocb(dlen, BPRI_MED)) == NULL) {
1325 freemsg(cmsg);
1326 freemsg(mret);
1327 if (db->flags & DS_DEBUG) {
1328 cmn_err(CE_CONT,
1329 "bsd_decomp%d: %s output "
1330 "buffers; outlen %d+%d\n",
1331 db->unit,
1332 (blockctr < 0 ? "too many" :
1333 "can't allocate"),
1334 outlen, dlen);
1336 return (DECOMP_ERROR);
1339 dmsg = dmsg->b_cont;
1340 wptr = dmsg->b_wptr;
1341 explen = dmsg->b_datap->db_lim - wptr - codelen -
1342 extra;
1345 p = (wptr += codelen);
1347 while (finchar > LAST) {
1348 dictp = &db->dict[db->dict[finchar].cptr];
1349 *--p = dictp->f.hs.suffix;
1350 finchar = dictp->f.hs.prefix;
1353 *--p = finchar;
1355 if (decode_proto) {
1356 decode_proto = 0;
1357 /* Wow, is *this* ugly! */
1358 if (!(finchar & 1)) {
1359 if (p == prepos+1) {
1360 bcopy(p, prepos, wptr-p);
1361 wptr--;
1362 explen++;
1363 db->in_count++;
1364 } else {
1365 /* This is safe, but doesn't look it */
1366 *prepos = *p++;
1367 dmsg->b_rptr = p;
1372 if (extra) { /* the KwKwK case again */
1373 *wptr++ = ofinchar;
1377 * If not first code in a packet, and
1378 * if not out of code space, then allocate a new code.
1380 * Keep the hash table correct so it can be used
1381 * with uncompressed packets.
1383 if (oldcode != CLEAR && max_ent < db->maxmaxcode) {
1384 struct bsd_dict *dictp2;
1385 uint32_t fcode;
1386 int hval;
1387 int disp;
1389 fcode = BSD_KEY(oldcode, finchar);
1390 hval = BSD_HASH(oldcode, finchar, db->hshift);
1392 dictp = &db->dict[hval];
1395 * look for a free hash table entry
1397 if (dictp->codem1 < max_ent) {
1398 disp = (hval == 0) ? 1 : hval;
1400 do {
1401 hval += disp;
1403 if (hval >= db->hsize) {
1404 hval -= db->hsize;
1405 if (hval >= db->hsize) {
1406 freemsg(cmsg);
1407 freemsg(mret);
1408 if (db->flags &
1409 DS_DEBUG) {
1410 cmn_err(CE_CONT, "bsd_decomp%d: internal error\n",
1411 db->unit);
1413 return
1414 (DECOMP_FATALERROR);
1418 dictp = &db->dict[hval];
1420 } while (dictp->codem1 < max_ent);
1424 * Invalidate previous hash table entry
1425 * assigned this code, and then take it over
1427 dictp2 = &db->dict[max_ent+1];
1429 if (db->dict[dictp2->cptr].codem1 == max_ent) {
1430 db->dict[dictp2->cptr].codem1 = BADCODEM1;
1433 dictp2->cptr = (ushort_t)hval;
1434 dictp->codem1 = max_ent;
1435 dictp->f.fcode = fcode;
1437 db->max_ent = ++max_ent;
1438 db->lens[max_ent] = db->lens[oldcode]+1;
1441 * Expand code size if needed
1443 if (max_ent >= MAXCODE(n_bits) &&
1444 max_ent < db->maxmaxcode) {
1446 db->n_bits = ++n_bits;
1447 tgtbitno = 32-n_bits;
1451 oldcode = incode;
1454 dlen = wptr-dmsg->b_wptr;
1455 outlen += dlen;
1456 db->in_count += dlen;
1457 dmsg->b_wptr = wptr;
1458 db->bytes_out += ilen;
1461 * Keep the checkpoint right so that incompressible packets
1462 * clear the dictionary at the right times.
1464 if (bsd_check(db) && (db->flags & DS_DEBUG)) {
1465 cmn_err(CE_CONT,
1466 "bsd_decomp%d: peer should have cleared dictionary\n",
1467 db->unit);
1470 ++db->comp_count;
1471 db->comp_bytes += ilen + BSD_OVHD;
1472 ++db->uncomp_count;
1473 db->uncomp_bytes += outlen;
1475 *dmpp = mret;
1477 return (DECOMP_OK);
1480 /* ARGSUSED */
1481 static int
1482 bsd_set_effort(void *xarg, void *rarg, int effortlevel)
1484 #ifdef DEBUG
1485 struct bsd_db *xdb = (struct bsd_db *)xarg;
1486 struct bsd_db *rdb = (struct bsd_db *)rarg;
1488 if (effortlevel == 42 || effortlevel == 2112) {
1489 /* corrupt received data. */
1490 if (rdb != NULL) {
1491 rdb->flags |= DS_TESTIN;
1492 cmn_err(CE_CONT, "bsd-comp: enabled input testing.");
1494 if (effortlevel != 2112)
1495 return (0);
1497 if (effortlevel == 2001 || effortlevel == 2112) {
1498 /* corrupt transmitted data. */
1499 if (xdb != NULL) {
1500 xdb->flags |= DS_TESTOUT;
1501 cmn_err(CE_CONT, "bsd-comp: enabled output testing.");
1503 return (0);
1505 #endif
1506 return (0);
1508 #endif /* DO_BSD_COMPRESS */