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