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