]> git.saurik.com Git - apple/xnu.git/blame_incremental - bsd/net/bsd_comp.c
xnu-792.6.56.tar.gz
[apple/xnu.git] / bsd / net / bsd_comp.c
... / ...
CommitLineData
1/*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23/* Because this code is derived from the 4.3BSD compress source:
24 *
25 *
26 * Copyright (c) 1985, 1986 The Regents of the University of California.
27 * All rights reserved.
28 *
29 * This code is derived from software contributed to Berkeley by
30 * James A. Woods, derived from original work by Spencer Thomas
31 * and Joseph Orost.
32 *
33 * Redistribution and use in source and binary forms, with or without
34 * modification, are permitted provided that the following conditions
35 * are met:
36 * 1. Redistributions of source code must retain the above copyright
37 * notice, this list of conditions and the following disclaimer.
38 * 2. Redistributions in binary form must reproduce the above copyright
39 * notice, this list of conditions and the following disclaimer in the
40 * documentation and/or other materials provided with the distribution.
41 * 3. All advertising materials mentioning features or use of this software
42 * must display the following acknowledgement:
43 * This product includes software developed by the University of
44 * California, Berkeley and its contributors.
45 * 4. Neither the name of the University nor the names of its contributors
46 * may be used to endorse or promote products derived from this software
47 * without specific prior written permission.
48 *
49 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
50 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
51 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
52 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
53 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
54 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
55 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
56 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
57 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
58 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
59 * SUCH DAMAGE.
60 */
61
62/*
63 * This version is for use with mbufs on BSD-derived systems.
64 *
65 */
66
67#include <sys/param.h>
68#include <sys/systm.h>
69#include <sys/malloc.h>
70#include <sys/mbuf.h>
71#include <net/ppp_defs.h>
72
73#define PACKETPTR struct mbuf *
74#include <net/ppp_comp.h>
75
76#if DO_BSD_COMPRESS
77/*
78 * PPP "BSD compress" compression
79 * The differences between this compression and the classic BSD LZW
80 * source are obvious from the requirement that the classic code worked
81 * with files while this handles arbitrarily long streams that
82 * are broken into packets. They are:
83 *
84 * When the code size expands, a block of junk is not emitted by
85 * the compressor and not expected by the decompressor.
86 *
87 * New codes are not necessarily assigned every time an old
88 * code is output by the compressor. This is because a packet
89 * end forces a code to be emitted, but does not imply that a
90 * new sequence has been seen.
91 *
92 * The compression ratio is checked at the first end of a packet
93 * after the appropriate gap. Besides simplifying and speeding
94 * things up, this makes it more likely that the transmitter
95 * and receiver will agree when the dictionary is cleared when
96 * compression is not going well.
97 */
98
99/*
100 * A dictionary for doing BSD compress.
101 */
102struct bsd_db {
103 int totlen; /* length of this structure */
104 u_int hsize; /* size of the hash table */
105 u_char hshift; /* used in hash function */
106 u_char n_bits; /* current bits/code */
107 u_char maxbits;
108 u_char debug;
109 u_char unit;
110 u_int16_t seqno; /* sequence # of next packet */
111 u_int hdrlen; /* header length to preallocate */
112 u_int mru;
113 u_int maxmaxcode; /* largest valid code */
114 u_int max_ent; /* largest code in use */
115 u_int in_count; /* uncompressed bytes, aged */
116 u_int bytes_out; /* compressed bytes, aged */
117 u_int ratio; /* recent compression ratio */
118 u_int checkpoint; /* when to next check the ratio */
119 u_int clear_count; /* times dictionary cleared */
120 u_int incomp_count; /* incompressible packets */
121 u_int incomp_bytes; /* incompressible bytes */
122 u_int uncomp_count; /* uncompressed packets */
123 u_int uncomp_bytes; /* uncompressed bytes */
124 u_int comp_count; /* compressed packets */
125 u_int comp_bytes; /* compressed bytes */
126 u_int16_t *lens; /* array of lengths of codes */
127 struct bsd_dict {
128 union { /* hash value */
129 u_int32_t fcode;
130 struct {
131#if BYTE_ORDER == LITTLE_ENDIAN
132 u_int16_t prefix; /* preceding code */
133 u_char suffix; /* last character of new code */
134 u_char pad;
135#else
136 u_char pad;
137 u_char suffix; /* last character of new code */
138 u_int16_t prefix; /* preceding code */
139#endif
140 } hs;
141 } f;
142 u_int16_t codem1; /* output of hash table -1 */
143 u_int16_t cptr; /* map code to hash table entry */
144 } dict[1];
145};
146
147#define BSD_OVHD 2 /* BSD compress overhead/packet */
148#define BSD_INIT_BITS BSD_MIN_BITS
149
150static void bsd_clear(struct bsd_db *db);
151static int bsd_check(struct bsd_db *db);
152static void *bsd_alloc(u_char *options, int opt_len, int decomp);
153static int bsd_init_comp_db(struct bsd_db *db, u_char *options,
154 int opt_len,
155 int unit, int hdrlen, int mru, int debug,
156 int decomp);
157static void *bsd_comp_alloc(u_char *options, int opt_len);
158static void *bsd_decomp_alloc(u_char *options, int opt_len);
159static void bsd_free(void *state);
160static int bsd_comp_init(void *state, u_char *options, int opt_len,
161 int unit, int hdrlen, int debug);
162static int bsd_decomp_init(void *state, u_char *options, int opt_len,
163 int unit, int hdrlen, int mru, int debug);
164static int bsd_compress(void *state, struct mbuf **mret,
165 struct mbuf *mp, int slen, int maxolen);
166static void bsd_incomp(void *state, struct mbuf *dmsg);
167static int bsd_decompress(void *state, struct mbuf *cmp,
168 struct mbuf **dmpp);
169static void bsd_reset(void *state);
170static void bsd_comp_stats(void *state, struct compstat *stats);
171
172/*
173 * Procedures exported to if_ppp.c.
174 */
175struct compressor ppp_bsd_compress = {
176 CI_BSD_COMPRESS, /* compress_proto */
177 bsd_comp_alloc, /* comp_alloc */
178 bsd_free, /* comp_free */
179 bsd_comp_init, /* comp_init */
180 bsd_reset, /* comp_reset */
181 bsd_compress, /* compress */
182 bsd_comp_stats, /* comp_stat */
183 bsd_decomp_alloc, /* decomp_alloc */
184 bsd_free, /* decomp_free */
185 bsd_decomp_init, /* decomp_init */
186 bsd_reset, /* decomp_reset */
187 bsd_decompress, /* decompress */
188 bsd_incomp, /* incomp */
189 bsd_comp_stats, /* decomp_stat */
190};
191
192/*
193 * the next two codes should not be changed lightly, as they must not
194 * lie within the contiguous general code space.
195 */
196#define CLEAR 256 /* table clear output code */
197#define FIRST 257 /* first free entry */
198#define LAST 255
199
200#define MAXCODE(b) ((1 << (b)) - 1)
201#define BADCODEM1 MAXCODE(BSD_MAX_BITS)
202
203#define BSD_HASH(prefix,suffix,hshift) ((((u_int32_t)(suffix)) << (hshift)) \
204 ^ (u_int32_t)(prefix))
205#define BSD_KEY(prefix,suffix) ((((u_int32_t)(suffix)) << 16) \
206 + (u_int32_t)(prefix))
207
208#define CHECK_GAP 10000 /* Ratio check interval */
209
210#define RATIO_SCALE_LOG 8
211#define RATIO_SCALE (1<<RATIO_SCALE_LOG)
212#define RATIO_MAX (0x7fffffff>>RATIO_SCALE_LOG)
213
214/*
215 * clear the dictionary
216 */
217static void
218bsd_clear(db)
219 struct bsd_db *db;
220{
221 db->clear_count++;
222 db->max_ent = FIRST-1;
223 db->n_bits = BSD_INIT_BITS;
224 db->ratio = 0;
225 db->bytes_out = 0;
226 db->in_count = 0;
227 db->checkpoint = CHECK_GAP;
228}
229
230/*
231 * If the dictionary is full, then see if it is time to reset it.
232 *
233 * Compute the compression ratio using fixed-point arithmetic
234 * with 8 fractional bits.
235 *
236 * Since we have an infinite stream instead of a single file,
237 * watch only the local compression ratio.
238 *
239 * Since both peers must reset the dictionary at the same time even in
240 * the absence of CLEAR codes (while packets are incompressible), they
241 * must compute the same ratio.
242 */
243static int /* 1=output CLEAR */
244bsd_check(db)
245 struct bsd_db *db;
246{
247 u_int new_ratio;
248
249 if (db->in_count >= db->checkpoint) {
250 /* age the ratio by limiting the size of the counts */
251 if (db->in_count >= RATIO_MAX
252 || db->bytes_out >= RATIO_MAX) {
253 db->in_count -= db->in_count/4;
254 db->bytes_out -= db->bytes_out/4;
255 }
256
257 db->checkpoint = db->in_count + CHECK_GAP;
258
259 if (db->max_ent >= db->maxmaxcode) {
260 /* Reset the dictionary only if the ratio is worse,
261 * or if it looks as if it has been poisoned
262 * by incompressible data.
263 *
264 * This does not overflow, because
265 * db->in_count <= RATIO_MAX.
266 */
267 new_ratio = db->in_count << RATIO_SCALE_LOG;
268 if (db->bytes_out != 0)
269 new_ratio /= db->bytes_out;
270
271 if (new_ratio < db->ratio || new_ratio < 1 * RATIO_SCALE) {
272 bsd_clear(db);
273 return 1;
274 }
275 db->ratio = new_ratio;
276 }
277 }
278 return 0;
279}
280
281/*
282 * Return statistics.
283 */
284static void
285bsd_comp_stats(state, stats)
286 void *state;
287 struct compstat *stats;
288{
289 struct bsd_db *db = (struct bsd_db *) state;
290 u_int out;
291
292 stats->unc_bytes = db->uncomp_bytes;
293 stats->unc_packets = db->uncomp_count;
294 stats->comp_bytes = db->comp_bytes;
295 stats->comp_packets = db->comp_count;
296 stats->inc_bytes = db->incomp_bytes;
297 stats->inc_packets = db->incomp_count;
298 stats->ratio = db->in_count;
299 out = db->bytes_out;
300 if (stats->ratio <= 0x7fffff)
301 stats->ratio <<= 8;
302 else
303 out >>= 8;
304 if (out != 0)
305 stats->ratio /= out;
306}
307
308/*
309 * Reset state, as on a CCP ResetReq.
310 */
311static void
312bsd_reset(state)
313 void *state;
314{
315 struct bsd_db *db = (struct bsd_db *) state;
316
317 db->seqno = 0;
318 bsd_clear(db);
319 db->clear_count = 0;
320}
321
322/*
323 * Allocate space for a (de) compressor.
324 */
325static void *
326bsd_alloc(options, opt_len, decomp)
327 u_char *options;
328 int opt_len, decomp;
329{
330 int bits;
331 u_int newlen, hsize, hshift, maxmaxcode;
332 struct bsd_db *db;
333
334 if (opt_len < CILEN_BSD_COMPRESS || options[0] != CI_BSD_COMPRESS
335 || options[1] != CILEN_BSD_COMPRESS
336 || BSD_VERSION(options[2]) != BSD_CURRENT_VERSION)
337 return NULL;
338 bits = BSD_NBITS(options[2]);
339 switch (bits) {
340 case 9: /* needs 82152 for both directions */
341 case 10: /* needs 84144 */
342 case 11: /* needs 88240 */
343 case 12: /* needs 96432 */
344 hsize = 5003;
345 hshift = 4;
346 break;
347 case 13: /* needs 176784 */
348 hsize = 9001;
349 hshift = 5;
350 break;
351 case 14: /* needs 353744 */
352 hsize = 18013;
353 hshift = 6;
354 break;
355 case 15: /* needs 691440 */
356 hsize = 35023;
357 hshift = 7;
358 break;
359 case 16: /* needs 1366160--far too much, */
360 /* hsize = 69001; */ /* and 69001 is too big for cptr */
361 /* hshift = 8; */ /* in struct bsd_db */
362 /* break; */
363 default:
364 return NULL;
365 }
366
367 maxmaxcode = MAXCODE(bits);
368 newlen = sizeof(*db) + (hsize-1) * (sizeof(db->dict[0]));
369 MALLOC(db, struct bsd_db *, newlen, M_DEVBUF, M_NOWAIT);
370 if (!db)
371 return NULL;
372 bzero(db, sizeof(*db) - sizeof(db->dict));
373
374 if (!decomp) {
375 db->lens = NULL;
376 } else {
377 MALLOC(db->lens, u_int16_t *, (maxmaxcode+1) * sizeof(db->lens[0]),
378 M_DEVBUF, M_NOWAIT);
379 if (!db->lens) {
380 FREE(db, M_DEVBUF);
381 return NULL;
382 }
383 }
384
385 db->totlen = newlen;
386 db->hsize = hsize;
387 db->hshift = hshift;
388 db->maxmaxcode = maxmaxcode;
389 db->maxbits = bits;
390
391 return (void *) db;
392}
393
394static void
395bsd_free(state)
396 void *state;
397{
398 struct bsd_db *db = (struct bsd_db *) state;
399
400 if (db->lens)
401 FREE(db->lens, M_DEVBUF);
402 FREE(db, M_DEVBUF);
403}
404
405static void *
406bsd_comp_alloc(options, opt_len)
407 u_char *options;
408 int opt_len;
409{
410 return bsd_alloc(options, opt_len, 0);
411}
412
413static void *
414bsd_decomp_alloc(options, opt_len)
415 u_char *options;
416 int opt_len;
417{
418 return bsd_alloc(options, opt_len, 1);
419}
420
421/*
422 * Initialize the database.
423 */
424static int
425bsd_init_comp_db(db, options, opt_len, unit, hdrlen, mru, debug, decomp)
426 struct bsd_db *db;
427 u_char *options;
428 int opt_len, unit, hdrlen, mru, debug, decomp;
429{
430 int i;
431
432 if (opt_len < CILEN_BSD_COMPRESS || options[0] != CI_BSD_COMPRESS
433 || options[1] != CILEN_BSD_COMPRESS
434 || BSD_VERSION(options[2]) != BSD_CURRENT_VERSION
435 || BSD_NBITS(options[2]) != db->maxbits
436 || (decomp && db->lens == NULL))
437 return 0;
438
439 if (decomp) {
440 i = LAST+1;
441 while (i != 0)
442 db->lens[--i] = 1;
443 }
444 i = db->hsize;
445 while (i != 0) {
446 db->dict[--i].codem1 = BADCODEM1;
447 db->dict[i].cptr = 0;
448 }
449
450 db->unit = unit;
451 db->hdrlen = hdrlen;
452 db->mru = mru;
453#ifndef DEBUG
454 if (debug)
455#endif
456 db->debug = 1;
457
458 bsd_reset(db);
459
460 return 1;
461}
462
463static int
464bsd_comp_init(state, options, opt_len, unit, hdrlen, debug)
465 void *state;
466 u_char *options;
467 int opt_len, unit, hdrlen, debug;
468{
469 return bsd_init_comp_db((struct bsd_db *) state, options, opt_len,
470 unit, hdrlen, 0, debug, 0);
471}
472
473static int
474bsd_decomp_init(state, options, opt_len, unit, hdrlen, mru, debug)
475 void *state;
476 u_char *options;
477 int opt_len, unit, hdrlen, mru, debug;
478{
479 return bsd_init_comp_db((struct bsd_db *) state, options, opt_len,
480 unit, hdrlen, mru, debug, 1);
481}
482
483
484/*
485 * compress a packet
486 * One change from the BSD compress command is that when the
487 * code size expands, we do not output a bunch of padding.
488 */
489int /* new slen */
490bsd_compress(state, mret, mp, slen, maxolen)
491 void *state;
492 struct mbuf **mret; /* return compressed mbuf chain here */
493 struct mbuf *mp; /* from here */
494 int slen; /* uncompressed length */
495 int maxolen; /* max compressed length */
496{
497 struct bsd_db *db = (struct bsd_db *) state;
498 int hshift = db->hshift;
499 u_int max_ent = db->max_ent;
500 u_int n_bits = db->n_bits;
501 u_int bitno = 32;
502 u_int32_t accm = 0, fcode;
503 struct bsd_dict *dictp;
504 u_char c;
505 int hval, disp, ent, ilen;
506 u_char *rptr, *wptr;
507 u_char *cp_end;
508 int olen;
509 struct mbuf *m;
510
511#define PUTBYTE(v) { \
512 ++olen; \
513 if (wptr) { \
514 *wptr++ = (v); \
515 if (wptr >= cp_end) { \
516 m->m_len = wptr - mtod(m, u_char *); \
517 MGET(m->m_next, M_DONTWAIT, MT_DATA); \
518 m = m->m_next; \
519 if (m) { \
520 m->m_len = 0; \
521 if (maxolen - olen > MLEN) \
522 MCLGET(m, M_DONTWAIT); \
523 wptr = mtod(m, u_char *); \
524 cp_end = wptr + M_TRAILINGSPACE(m); \
525 } else \
526 wptr = NULL; \
527 } \
528 } \
529}
530
531#define OUTPUT(ent) { \
532 bitno -= n_bits; \
533 accm |= ((ent) << bitno); \
534 do { \
535 PUTBYTE(accm >> 24); \
536 accm <<= 8; \
537 bitno += 8; \
538 } while (bitno <= 24); \
539}
540
541 /*
542 * If the protocol is not in the range we're interested in,
543 * just return without compressing the packet. If it is,
544 * the protocol becomes the first byte to compress.
545 */
546 rptr = mtod(mp, u_char *);
547 ent = PPP_PROTOCOL(rptr);
548 if (ent < 0x21 || ent > 0xf9) {
549 *mret = NULL;
550 return slen;
551 }
552
553 /* Don't generate compressed packets which are larger than
554 the uncompressed packet. */
555 if (maxolen > slen)
556 maxolen = slen;
557
558 /* Allocate one mbuf to start with. */
559 MGET(m, M_DONTWAIT, MT_DATA);
560 *mret = m;
561 if (m != NULL) {
562 m->m_len = 0;
563 if (maxolen + db->hdrlen > MLEN)
564 MCLGET(m, M_DONTWAIT);
565 m->m_data += db->hdrlen;
566 wptr = mtod(m, u_char *);
567 cp_end = wptr + M_TRAILINGSPACE(m);
568 } else
569 wptr = cp_end = NULL;
570
571 /*
572 * Copy the PPP header over, changing the protocol,
573 * and install the 2-byte packet sequence number.
574 */
575 if (wptr) {
576 *wptr++ = PPP_ADDRESS(rptr); /* assumes the ppp header is */
577 *wptr++ = PPP_CONTROL(rptr); /* all in one mbuf */
578 *wptr++ = 0; /* change the protocol */
579 *wptr++ = PPP_COMP;
580 *wptr++ = db->seqno >> 8;
581 *wptr++ = db->seqno;
582 }
583 ++db->seqno;
584
585 olen = 0;
586 rptr += PPP_HDRLEN;
587 slen = mp->m_len - PPP_HDRLEN;
588 ilen = slen + 1;
589 for (;;) {
590 if (slen <= 0) {
591 mp = mp->m_next;
592 if (!mp)
593 break;
594 rptr = mtod(mp, u_char *);
595 slen = mp->m_len;
596 if (!slen)
597 continue; /* handle 0-length buffers */
598 ilen += slen;
599 }
600
601 slen--;
602 c = *rptr++;
603 fcode = BSD_KEY(ent, c);
604 hval = BSD_HASH(ent, c, hshift);
605 dictp = &db->dict[hval];
606
607 /* Validate and then check the entry. */
608 if (dictp->codem1 >= max_ent)
609 goto nomatch;
610 if (dictp->f.fcode == fcode) {
611 ent = dictp->codem1+1;
612 continue; /* found (prefix,suffix) */
613 }
614
615 /* continue probing until a match or invalid entry */
616 disp = (hval == 0) ? 1 : hval;
617 do {
618 hval += disp;
619 if (hval >= db->hsize)
620 hval -= db->hsize;
621 dictp = &db->dict[hval];
622 if (dictp->codem1 >= max_ent)
623 goto nomatch;
624 } while (dictp->f.fcode != fcode);
625 ent = dictp->codem1 + 1; /* finally found (prefix,suffix) */
626 continue;
627
628 nomatch:
629 OUTPUT(ent); /* output the prefix */
630
631 /* code -> hashtable */
632 if (max_ent < db->maxmaxcode) {
633 struct bsd_dict *dictp2;
634 /* expand code size if needed */
635 if (max_ent >= MAXCODE(n_bits))
636 db->n_bits = ++n_bits;
637
638 /* Invalidate old hash table entry using
639 * this code, and then take it over.
640 */
641 dictp2 = &db->dict[max_ent+1];
642 if (db->dict[dictp2->cptr].codem1 == max_ent)
643 db->dict[dictp2->cptr].codem1 = BADCODEM1;
644 dictp2->cptr = hval;
645 dictp->codem1 = max_ent;
646 dictp->f.fcode = fcode;
647
648 db->max_ent = ++max_ent;
649 }
650 ent = c;
651 }
652
653 OUTPUT(ent); /* output the last code */
654 db->bytes_out += olen;
655 db->in_count += ilen;
656 if (bitno < 32)
657 ++db->bytes_out; /* count complete bytes */
658
659 if (bsd_check(db))
660 OUTPUT(CLEAR); /* do not count the CLEAR */
661
662 /*
663 * Pad dribble bits of last code with ones.
664 * Do not emit a completely useless byte of ones.
665 */
666 if (bitno != 32)
667 PUTBYTE((accm | (0xff << (bitno-8))) >> 24);
668
669 if (m != NULL) {
670 m->m_len = wptr - mtod(m, u_char *);
671 m->m_next = NULL;
672 }
673
674 /*
675 * Increase code size if we would have without the packet
676 * boundary and as the decompressor will.
677 */
678 if (max_ent >= MAXCODE(n_bits) && max_ent < db->maxmaxcode)
679 db->n_bits++;
680
681 db->uncomp_bytes += ilen;
682 ++db->uncomp_count;
683 if (olen + PPP_HDRLEN + BSD_OVHD > maxolen) {
684 /* throw away the compressed stuff if it is longer than uncompressed */
685 if (*mret != NULL) {
686 m_freem(*mret);
687 *mret = NULL;
688 }
689 ++db->incomp_count;
690 db->incomp_bytes += ilen;
691 } else {
692 ++db->comp_count;
693 db->comp_bytes += olen + BSD_OVHD;
694 }
695
696 return olen + PPP_HDRLEN + BSD_OVHD;
697#undef OUTPUT
698#undef PUTBYTE
699}
700
701
702/*
703 * Update the "BSD Compress" dictionary on the receiver for
704 * incompressible data by pretending to compress the incoming data.
705 */
706static void
707bsd_incomp(state, dmsg)
708 void *state;
709 struct mbuf *dmsg;
710{
711 struct bsd_db *db = (struct bsd_db *) state;
712 u_int hshift = db->hshift;
713 u_int max_ent = db->max_ent;
714 u_int n_bits = db->n_bits;
715 struct bsd_dict *dictp;
716 u_int32_t fcode;
717 u_char c;
718 u_int32_t hval, disp;
719 int slen, ilen;
720 u_int bitno = 7;
721 u_char *rptr;
722 u_int ent;
723
724 /*
725 * If the protocol is not in the range we're interested in,
726 * just return without looking at the packet. If it is,
727 * the protocol becomes the first byte to "compress".
728 */
729 rptr = mtod(dmsg, u_char *);
730 ent = PPP_PROTOCOL(rptr);
731 if (ent < 0x21 || ent > 0xf9)
732 return;
733
734 db->seqno++;
735 ilen = 1; /* count the protocol as 1 byte */
736 rptr += PPP_HDRLEN;
737 slen = dmsg->m_len - PPP_HDRLEN;
738 for (;;) {
739 if (slen <= 0) {
740 dmsg = dmsg->m_next;
741 if (!dmsg)
742 break;
743 rptr = mtod(dmsg, u_char *);
744 slen = dmsg->m_len;
745 continue;
746 }
747 ilen += slen;
748
749 do {
750 c = *rptr++;
751 fcode = BSD_KEY(ent, c);
752 hval = BSD_HASH(ent, c, hshift);
753 dictp = &db->dict[hval];
754
755 /* validate and then check the entry */
756 if (dictp->codem1 >= max_ent)
757 goto nomatch;
758 if (dictp->f.fcode == fcode) {
759 ent = dictp->codem1+1;
760 continue; /* found (prefix,suffix) */
761 }
762
763 /* continue probing until a match or invalid entry */
764 disp = (hval == 0) ? 1 : hval;
765 do {
766 hval += disp;
767 if (hval >= db->hsize)
768 hval -= db->hsize;
769 dictp = &db->dict[hval];
770 if (dictp->codem1 >= max_ent)
771 goto nomatch;
772 } while (dictp->f.fcode != fcode);
773 ent = dictp->codem1+1;
774 continue; /* finally found (prefix,suffix) */
775
776 nomatch: /* output (count) the prefix */
777 bitno += n_bits;
778
779 /* code -> hashtable */
780 if (max_ent < db->maxmaxcode) {
781 struct bsd_dict *dictp2;
782 /* expand code size if needed */
783 if (max_ent >= MAXCODE(n_bits))
784 db->n_bits = ++n_bits;
785
786 /* Invalidate previous hash table entry
787 * assigned this code, and then take it over.
788 */
789 dictp2 = &db->dict[max_ent+1];
790 if (db->dict[dictp2->cptr].codem1 == max_ent)
791 db->dict[dictp2->cptr].codem1 = BADCODEM1;
792 dictp2->cptr = hval;
793 dictp->codem1 = max_ent;
794 dictp->f.fcode = fcode;
795
796 db->max_ent = ++max_ent;
797 db->lens[max_ent] = db->lens[ent]+1;
798 }
799 ent = c;
800 } while (--slen != 0);
801 }
802 bitno += n_bits; /* output (count) the last code */
803 db->bytes_out += bitno/8;
804 db->in_count += ilen;
805 (void)bsd_check(db);
806
807 ++db->incomp_count;
808 db->incomp_bytes += ilen;
809 ++db->uncomp_count;
810 db->uncomp_bytes += ilen;
811
812 /* Increase code size if we would have without the packet
813 * boundary and as the decompressor will.
814 */
815 if (max_ent >= MAXCODE(n_bits) && max_ent < db->maxmaxcode)
816 db->n_bits++;
817}
818
819
820/*
821 * Decompress "BSD Compress".
822 *
823 * Because of patent problems, we return DECOMP_ERROR for errors
824 * found by inspecting the input data and for system problems, but
825 * DECOMP_FATALERROR for any errors which could possibly be said to
826 * be being detected "after" decompression. For DECOMP_ERROR,
827 * we can issue a CCP reset-request; for DECOMP_FATALERROR, we may be
828 * infringing a patent of Motorola's if we do, so we take CCP down
829 * instead.
830 *
831 * Given that the frame has the correct sequence number and a good FCS,
832 * errors such as invalid codes in the input most likely indicate a
833 * bug, so we return DECOMP_FATALERROR for them in order to turn off
834 * compression, even though they are detected by inspecting the input.
835 */
836int
837bsd_decompress(state, cmp, dmpp)
838 void *state;
839 struct mbuf *cmp, **dmpp;
840{
841 struct bsd_db *db = (struct bsd_db *) state;
842 u_int max_ent = db->max_ent;
843 u_int32_t accm = 0;
844 u_int bitno = 32; /* 1st valid bit in accm */
845 u_int n_bits = db->n_bits;
846 u_int tgtbitno = 32-n_bits; /* bitno when we have a code */
847 struct bsd_dict *dictp;
848 int explen, i, seq, len;
849 u_int incode, oldcode, finchar;
850 u_char *p, *rptr, *wptr;
851 struct mbuf *m, *dmp, *mret;
852 int adrs, ctrl, ilen;
853 int space, codelen, extra;
854
855 /*
856 * Save the address/control from the PPP header
857 * and then get the sequence number.
858 */
859 *dmpp = NULL;
860 rptr = mtod(cmp, u_char *);
861 adrs = PPP_ADDRESS(rptr);
862 ctrl = PPP_CONTROL(rptr);
863 rptr += PPP_HDRLEN;
864 len = cmp->m_len - PPP_HDRLEN;
865 seq = 0;
866 for (i = 0; i < 2; ++i) {
867 while (len <= 0) {
868 cmp = cmp->m_next;
869 if (cmp == NULL)
870 return DECOMP_ERROR;
871 rptr = mtod(cmp, u_char *);
872 len = cmp->m_len;
873 }
874 seq = (seq << 8) + *rptr++;
875 --len;
876 }
877
878 /*
879 * Check the sequence number and give up if it differs from
880 * the value we're expecting.
881 */
882 if (seq != db->seqno) {
883 if (db->debug)
884 printf("bsd_decomp%d: bad sequence # %d, expected %d\n",
885 db->unit, seq, db->seqno - 1);
886 return DECOMP_ERROR;
887 }
888 ++db->seqno;
889
890 /*
891 * Allocate one mbuf to start with.
892 */
893 MGETHDR(dmp, M_DONTWAIT, MT_DATA);
894 if (dmp == NULL)
895 return DECOMP_ERROR;
896 mret = dmp;
897 dmp->m_len = 0;
898 dmp->m_next = NULL;
899 MCLGET(dmp, M_DONTWAIT);
900 dmp->m_data += db->hdrlen;
901 wptr = mtod(dmp, u_char *);
902 space = M_TRAILINGSPACE(dmp) - PPP_HDRLEN + 1;
903
904 /*
905 * Fill in the ppp header, but not the last byte of the protocol
906 * (that comes from the decompressed data).
907 */
908 wptr[0] = adrs;
909 wptr[1] = ctrl;
910 wptr[2] = 0;
911 wptr += PPP_HDRLEN - 1;
912
913 ilen = len;
914 oldcode = CLEAR;
915 explen = 0;
916 for (;;) {
917 if (len == 0) {
918 cmp = cmp->m_next;
919 if (!cmp) /* quit at end of message */
920 break;
921 rptr = mtod(cmp, u_char *);
922 len = cmp->m_len;
923 ilen += len;
924 continue; /* handle 0-length buffers */
925 }
926
927 /*
928 * Accumulate bytes until we have a complete code.
929 * Then get the next code, relying on the 32-bit,
930 * unsigned accm to mask the result.
931 */
932 bitno -= 8;
933 accm |= *rptr++ << bitno;
934 --len;
935 if (tgtbitno < bitno)
936 continue;
937 incode = accm >> tgtbitno;
938 accm <<= n_bits;
939 bitno += n_bits;
940
941 if (incode == CLEAR) {
942 /*
943 * The dictionary must only be cleared at
944 * the end of a packet. But there could be an
945 * empty mbuf at the end.
946 */
947 if (len > 0 || cmp->m_next != NULL) {
948 while ((cmp = cmp->m_next) != NULL)
949 len += cmp->m_len;
950 if (len > 0) {
951 m_freem(mret);
952 if (db->debug)
953 printf("bsd_decomp%d: bad CLEAR\n", db->unit);
954 return DECOMP_FATALERROR; /* probably a bug */
955 }
956 }
957 bsd_clear(db);
958 explen = ilen = 0;
959 break;
960 }
961
962 if (incode > max_ent + 2 || incode > db->maxmaxcode
963 || (incode > max_ent && oldcode == CLEAR)) {
964 m_freem(mret);
965 if (db->debug) {
966 printf("bsd_decomp%d: bad code 0x%x oldcode=0x%x ",
967 db->unit, incode, oldcode);
968 printf("max_ent=0x%x explen=%d seqno=%d\n",
969 max_ent, explen, db->seqno);
970 }
971 return DECOMP_FATALERROR; /* probably a bug */
972 }
973
974 /* Special case for KwKwK string. */
975 if (incode > max_ent) {
976 finchar = oldcode;
977 extra = 1;
978 } else {
979 finchar = incode;
980 extra = 0;
981 }
982
983 codelen = db->lens[finchar];
984 explen += codelen + extra;
985 if (explen > db->mru + 1) {
986 m_freem(mret);
987 if (db->debug) {
988 printf("bsd_decomp%d: ran out of mru\n", db->unit);
989#ifdef DEBUG
990 while ((cmp = cmp->m_next) != NULL)
991 len += cmp->m_len;
992 printf(" len=%d, finchar=0x%x, codelen=%d, explen=%d\n",
993 len, finchar, codelen, explen);
994#endif
995 }
996 return DECOMP_FATALERROR;
997 }
998
999 /*
1000 * For simplicity, the decoded characters go in a single mbuf,
1001 * so we allocate a single extra cluster mbuf if necessary.
1002 */
1003 if ((space -= codelen + extra) < 0) {
1004 dmp->m_len = wptr - mtod(dmp, u_char *);
1005 MGET(m, M_DONTWAIT, MT_DATA);
1006 if (m == NULL) {
1007 m_freem(mret);
1008 return DECOMP_ERROR;
1009 }
1010 m->m_len = 0;
1011 m->m_next = NULL;
1012 dmp->m_next = m;
1013 MCLGET(m, M_DONTWAIT);
1014 space = M_TRAILINGSPACE(m) - (codelen + extra);
1015 if (space < 0) {
1016 /* now that's what I call *compression*. */
1017 m_freem(mret);
1018 return DECOMP_ERROR;
1019 }
1020 dmp = m;
1021 wptr = mtod(dmp, u_char *);
1022 }
1023
1024 /*
1025 * Decode this code and install it in the decompressed buffer.
1026 */
1027 p = (wptr += codelen);
1028 while (finchar > LAST) {
1029 dictp = &db->dict[db->dict[finchar].cptr];
1030#ifdef DEBUG
1031 if (--codelen <= 0 || dictp->codem1 != finchar-1)
1032 goto bad;
1033#endif
1034 *--p = dictp->f.hs.suffix;
1035 finchar = dictp->f.hs.prefix;
1036 }
1037 *--p = finchar;
1038
1039#ifdef DEBUG
1040 if (--codelen != 0)
1041 printf("bsd_decomp%d: short by %d after code 0x%x, max_ent=0x%x\n",
1042 db->unit, codelen, incode, max_ent);
1043#endif
1044
1045 if (extra) /* the KwKwK case again */
1046 *wptr++ = finchar;
1047
1048 /*
1049 * If not first code in a packet, and
1050 * if not out of code space, then allocate a new code.
1051 *
1052 * Keep the hash table correct so it can be used
1053 * with uncompressed packets.
1054 */
1055 if (oldcode != CLEAR && max_ent < db->maxmaxcode) {
1056 struct bsd_dict *dictp2;
1057 u_int32_t fcode;
1058 u_int32_t hval, disp;
1059
1060 fcode = BSD_KEY(oldcode,finchar);
1061 hval = BSD_HASH(oldcode,finchar,db->hshift);
1062 dictp = &db->dict[hval];
1063
1064 /* look for a free hash table entry */
1065 if (dictp->codem1 < max_ent) {
1066 disp = (hval == 0) ? 1 : hval;
1067 do {
1068 hval += disp;
1069 if (hval >= db->hsize)
1070 hval -= db->hsize;
1071 dictp = &db->dict[hval];
1072 } while (dictp->codem1 < max_ent);
1073 }
1074
1075 /*
1076 * Invalidate previous hash table entry
1077 * assigned this code, and then take it over
1078 */
1079 dictp2 = &db->dict[max_ent+1];
1080 if (db->dict[dictp2->cptr].codem1 == max_ent) {
1081 db->dict[dictp2->cptr].codem1 = BADCODEM1;
1082 }
1083 dictp2->cptr = hval;
1084 dictp->codem1 = max_ent;
1085 dictp->f.fcode = fcode;
1086
1087 db->max_ent = ++max_ent;
1088 db->lens[max_ent] = db->lens[oldcode]+1;
1089
1090 /* Expand code size if needed. */
1091 if (max_ent >= MAXCODE(n_bits) && max_ent < db->maxmaxcode) {
1092 db->n_bits = ++n_bits;
1093 tgtbitno = 32-n_bits;
1094 }
1095 }
1096 oldcode = incode;
1097 }
1098 dmp->m_len = wptr - mtod(dmp, u_char *);
1099
1100 /*
1101 * Keep the checkpoint right so that incompressible packets
1102 * clear the dictionary at the right times.
1103 */
1104 db->bytes_out += ilen;
1105 db->in_count += explen;
1106 if (bsd_check(db) && db->debug) {
1107 printf("bsd_decomp%d: peer should have cleared dictionary\n",
1108 db->unit);
1109 }
1110
1111 ++db->comp_count;
1112 db->comp_bytes += ilen + BSD_OVHD;
1113 ++db->uncomp_count;
1114 db->uncomp_bytes += explen;
1115
1116 *dmpp = mret;
1117 return DECOMP_OK;
1118
1119#ifdef DEBUG
1120 bad:
1121 if (codelen <= 0) {
1122 printf("bsd_decomp%d: fell off end of chain ", db->unit);
1123 printf("0x%x at 0x%x by 0x%x, max_ent=0x%x\n",
1124 incode, finchar, db->dict[finchar].cptr, max_ent);
1125 } else if (dictp->codem1 != finchar-1) {
1126 printf("bsd_decomp%d: bad code chain 0x%x finchar=0x%x ",
1127 db->unit, incode, finchar);
1128 printf("oldcode=0x%x cptr=0x%x codem1=0x%x\n", oldcode,
1129 db->dict[finchar].cptr, dictp->codem1);
1130 }
1131 m_freem(mret);
1132 return DECOMP_FATALERROR;
1133#endif /* DEBUG */
1134}
1135#endif /* DO_BSD_COMPRESS */