1 /* $NetBSD: ppp-deflate.c,v 1.1 1996/03/15 02:28:09 paulus Exp $ */ 2 3 /* 4 * ppp_deflate.c - interface the zlib procedures for Deflate compression 5 * and decompression (as used by gzip) to the PPP code. 6 * This version is for use with mbufs on BSD-derived systems. 7 * 8 * Copyright (c) 1994 The Australian National University. 9 * All rights reserved. 10 * 11 * Permission to use, copy, modify, and distribute this software and its 12 * documentation is hereby granted, provided that the above copyright 13 * notice appears in all copies. This software is provided without any 14 * warranty, express or implied. The Australian National University 15 * makes no representations about the suitability of this software for 16 * any purpose. 17 * 18 * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY 19 * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 20 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF 21 * THE AUSTRALIAN NATIONAL UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY 22 * OF SUCH DAMAGE. 23 * 24 * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES, 25 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 26 * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 27 * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO 28 * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, 29 * OR MODIFICATIONS. 30 */ 31 32 #include <sys/param.h> 33 #include <sys/types.h> 34 #include <sys/systm.h> 35 #include <sys/mbuf.h> 36 #include <net/ppp_defs.h> 37 #include <net/zlib.h> 38 39 #define PACKETPTR struct mbuf * 40 #include <net/ppp-comp.h> 41 42 #if DO_DEFLATE 43 44 /* 45 * State for a Deflate (de)compressor. 46 */ 47 struct deflate_state { 48 int seqno; 49 int w_size; 50 int unit; 51 int hdrlen; 52 int mru; 53 int debug; 54 z_stream strm; 55 struct compstat stats; 56 }; 57 58 #define DEFLATE_OVHD 2 /* Deflate overhead/packet */ 59 60 static void *zalloc __P((void *, u_int items, u_int size)); 61 static void zfree __P((void *, void *ptr, u_int nb)); 62 static void *z_comp_alloc __P((u_char *options, int opt_len)); 63 static void *z_decomp_alloc __P((u_char *options, int opt_len)); 64 static void z_comp_free __P((void *state)); 65 static void z_decomp_free __P((void *state)); 66 static int z_comp_init __P((void *state, u_char *options, int opt_len, 67 int unit, int hdrlen, int debug)); 68 static int z_decomp_init __P((void *state, u_char *options, int opt_len, 69 int unit, int hdrlen, int mru, int debug)); 70 static int z_compress __P((void *state, struct mbuf **mret, 71 struct mbuf *mp, int slen, int maxolen)); 72 static void z_incomp __P((void *state, struct mbuf *dmsg)); 73 static int z_decompress __P((void *state, struct mbuf *cmp, 74 struct mbuf **dmpp)); 75 static void z_comp_reset __P((void *state)); 76 static void z_decomp_reset __P((void *state)); 77 static void z_comp_stats __P((void *state, struct compstat *stats)); 78 79 /* 80 * Procedures exported to if_ppp.c. 81 */ 82 struct compressor ppp_deflate = { 83 CI_DEFLATE, /* compress_proto */ 84 z_comp_alloc, /* comp_alloc */ 85 z_comp_free, /* comp_free */ 86 z_comp_init, /* comp_init */ 87 z_comp_reset, /* comp_reset */ 88 z_compress, /* compress */ 89 z_comp_stats, /* comp_stat */ 90 z_decomp_alloc, /* decomp_alloc */ 91 z_decomp_free, /* decomp_free */ 92 z_decomp_init, /* decomp_init */ 93 z_decomp_reset, /* decomp_reset */ 94 z_decompress, /* decompress */ 95 z_incomp, /* incomp */ 96 z_comp_stats, /* decomp_stat */ 97 }; 98 99 /* 100 * Space allocation and freeing routines for use by zlib routines. 101 */ 102 void * 103 zalloc(notused, items, size) 104 void *notused; 105 u_int items, size; 106 { 107 void *ptr; 108 109 MALLOC(ptr, void *, items * size, M_DEVBUF, M_NOWAIT); 110 return ptr; 111 } 112 113 void 114 zfree(notused, ptr, nbytes) 115 void *notused; 116 void *ptr; 117 u_int nbytes; 118 { 119 FREE(ptr, M_DEVBUF); 120 } 121 122 /* 123 * Allocate space for a compressor. 124 */ 125 static void * 126 z_comp_alloc(options, opt_len) 127 u_char *options; 128 int opt_len; 129 { 130 struct deflate_state *state; 131 int w_size; 132 133 if (opt_len != CILEN_DEFLATE || options[0] != CI_DEFLATE 134 || options[1] != CILEN_DEFLATE 135 || DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL 136 || options[3] != DEFLATE_CHK_SEQUENCE) 137 return NULL; 138 w_size = DEFLATE_SIZE(options[2]); 139 if (w_size < DEFLATE_MIN_SIZE || w_size > DEFLATE_MAX_SIZE) 140 return NULL; 141 142 MALLOC(state, struct deflate_state *, sizeof(struct deflate_state), 143 M_DEVBUF, M_NOWAIT); 144 if (state == NULL) 145 return NULL; 146 147 state->strm.next_in = NULL; 148 state->strm.zalloc = zalloc; 149 state->strm.zfree = zfree; 150 if (deflateInit2(&state->strm, Z_DEFAULT_COMPRESSION, DEFLATE_METHOD_VAL, 151 -w_size, 8, Z_DEFAULT_STRATEGY, DEFLATE_OVHD+2) != Z_OK) { 152 FREE(state, M_DEVBUF); 153 return NULL; 154 } 155 156 state->w_size = w_size; 157 bzero(&state->stats, sizeof(state->stats)); 158 return (void *) state; 159 } 160 161 static void 162 z_comp_free(arg) 163 void *arg; 164 { 165 struct deflate_state *state = (struct deflate_state *) arg; 166 167 deflateEnd(&state->strm); 168 FREE(state, M_DEVBUF); 169 } 170 171 static int 172 z_comp_init(arg, options, opt_len, unit, hdrlen, debug) 173 void *arg; 174 u_char *options; 175 int opt_len, unit, hdrlen, debug; 176 { 177 struct deflate_state *state = (struct deflate_state *) arg; 178 179 if (opt_len < CILEN_DEFLATE || options[0] != CI_DEFLATE 180 || options[1] != CILEN_DEFLATE 181 || DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL 182 || DEFLATE_SIZE(options[2]) != state->w_size 183 || options[3] != DEFLATE_CHK_SEQUENCE) 184 return 0; 185 186 state->seqno = 0; 187 state->unit = unit; 188 state->hdrlen = hdrlen; 189 state->debug = debug; 190 191 deflateReset(&state->strm); 192 193 return 1; 194 } 195 196 static void 197 z_comp_reset(arg) 198 void *arg; 199 { 200 struct deflate_state *state = (struct deflate_state *) arg; 201 202 state->seqno = 0; 203 deflateReset(&state->strm); 204 } 205 206 int 207 z_compress(arg, mret, mp, orig_len, maxolen) 208 void *arg; 209 struct mbuf **mret; /* compressed packet (out) */ 210 struct mbuf *mp; /* uncompressed packet (in) */ 211 int orig_len, maxolen; 212 { 213 struct deflate_state *state = (struct deflate_state *) arg; 214 u_char *rptr, *wptr; 215 int proto, olen, wspace, r, flush; 216 struct mbuf *m; 217 218 /* 219 * Check that the protocol is in the range we handle. 220 */ 221 rptr = mtod(mp, u_char *); 222 proto = PPP_PROTOCOL(rptr); 223 if (proto > 0x3fff || proto == 0xfd || proto == 0xfb) { 224 *mret = NULL; 225 return orig_len; 226 } 227 228 /* Allocate one mbuf initially. */ 229 if (maxolen > orig_len) 230 maxolen = orig_len; 231 MGET(m, M_DONTWAIT, MT_DATA); 232 *mret = m; 233 if (m != NULL) { 234 m->m_len = 0; 235 if (maxolen + state->hdrlen > MLEN) 236 MCLGET(m, M_DONTWAIT); 237 wspace = M_TRAILINGSPACE(m); 238 if (state->hdrlen + PPP_HDRLEN + 2 < wspace) { 239 m->m_data += state->hdrlen; 240 wspace -= state->hdrlen; 241 } 242 wptr = mtod(m, u_char *); 243 244 /* 245 * Copy over the PPP header and store the 2-byte sequence number. 246 */ 247 wptr[0] = PPP_ADDRESS(rptr); 248 wptr[1] = PPP_CONTROL(rptr); 249 wptr[2] = PPP_COMP >> 8; 250 wptr[3] = PPP_COMP; 251 wptr += PPP_HDRLEN; 252 wptr[0] = state->seqno >> 8; 253 wptr[1] = state->seqno; 254 wptr += 2; 255 state->strm.next_out = wptr; 256 state->strm.avail_out = wspace - (PPP_HDRLEN + 2); 257 } else { 258 state->strm.next_out = NULL; 259 state->strm.avail_out = 1000000; 260 wptr = NULL; 261 wspace = 0; 262 } 263 ++state->seqno; 264 265 rptr += (proto > 0xff)? 2: 3; /* skip 1st proto byte if 0 */ 266 state->strm.next_in = rptr; 267 state->strm.avail_in = mtod(mp, u_char *) + mp->m_len - rptr; 268 mp = mp->m_next; 269 flush = (mp == NULL)? Z_PACKET_FLUSH: Z_NO_FLUSH; 270 olen = 0; 271 for (;;) { 272 r = deflate(&state->strm, flush); 273 if (r != Z_OK) { 274 printf("z_compress: deflate returned %d (%s)\n", 275 r, (state->strm.msg? state->strm.msg: "")); 276 break; 277 } 278 if (flush != Z_NO_FLUSH && state->strm.avail_out != 0) 279 break; /* all done */ 280 if (state->strm.avail_in == 0 && mp != NULL) { 281 state->strm.next_in = mtod(mp, u_char *); 282 state->strm.avail_in = mp->m_len; 283 mp = mp->m_next; 284 if (mp == NULL) 285 flush = Z_PACKET_FLUSH; 286 } 287 if (state->strm.avail_out == 0) { 288 if (m != NULL) { 289 m->m_len = wspace; 290 olen += wspace; 291 MGET(m->m_next, M_DONTWAIT, MT_DATA); 292 m = m->m_next; 293 if (m != NULL) { 294 m->m_len = 0; 295 if (maxolen - olen > MLEN) 296 MCLGET(m, M_DONTWAIT); 297 state->strm.next_out = mtod(m, u_char *); 298 state->strm.avail_out = wspace = M_TRAILINGSPACE(m); 299 } 300 } 301 if (m == NULL) { 302 state->strm.next_out = NULL; 303 state->strm.avail_out = 1000000; 304 } 305 } 306 } 307 if (m != NULL) 308 olen += (m->m_len = wspace - state->strm.avail_out); 309 310 /* 311 * See if we managed to reduce the size of the packet. 312 * If the compressor just gave us a single zero byte, it means 313 * the packet was incompressible. 314 */ 315 if (m != NULL && olen < orig_len 316 && !(olen == PPP_HDRLEN + 3 && *wptr == 0)) { 317 state->stats.comp_bytes += olen; 318 state->stats.comp_packets++; 319 } else { 320 if (*mret != NULL) { 321 m_freem(*mret); 322 *mret = NULL; 323 } 324 state->stats.inc_bytes += orig_len; 325 state->stats.inc_packets++; 326 olen = orig_len; 327 } 328 state->stats.unc_bytes += orig_len; 329 state->stats.unc_packets++; 330 331 return olen; 332 } 333 334 static void 335 z_comp_stats(arg, stats) 336 void *arg; 337 struct compstat *stats; 338 { 339 struct deflate_state *state = (struct deflate_state *) arg; 340 u_int out; 341 342 *stats = state->stats; 343 stats->ratio = stats->unc_bytes; 344 out = stats->comp_bytes + stats->inc_bytes; 345 if (stats->ratio <= 0x7ffffff) 346 stats->ratio <<= 8; 347 else 348 out >>= 8; 349 if (out != 0) 350 stats->ratio /= out; 351 } 352 353 /* 354 * Allocate space for a decompressor. 355 */ 356 static void * 357 z_decomp_alloc(options, opt_len) 358 u_char *options; 359 int opt_len; 360 { 361 struct deflate_state *state; 362 int w_size; 363 364 if (opt_len != CILEN_DEFLATE || options[0] != CI_DEFLATE 365 || options[1] != CILEN_DEFLATE 366 || DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL 367 || options[3] != DEFLATE_CHK_SEQUENCE) 368 return NULL; 369 w_size = DEFLATE_SIZE(options[2]); 370 if (w_size < DEFLATE_MIN_SIZE || w_size > DEFLATE_MAX_SIZE) 371 return NULL; 372 373 MALLOC(state, struct deflate_state *, sizeof(struct deflate_state), 374 M_DEVBUF, M_NOWAIT); 375 if (state == NULL) 376 return NULL; 377 378 state->strm.next_out = NULL; 379 state->strm.zalloc = zalloc; 380 state->strm.zfree = zfree; 381 if (inflateInit2(&state->strm, -w_size) != Z_OK) { 382 FREE(state, M_DEVBUF); 383 return NULL; 384 } 385 386 state->w_size = w_size; 387 bzero(&state->stats, sizeof(state->stats)); 388 return (void *) state; 389 } 390 391 static void 392 z_decomp_free(arg) 393 void *arg; 394 { 395 struct deflate_state *state = (struct deflate_state *) arg; 396 397 inflateEnd(&state->strm); 398 FREE(state, M_DEVBUF); 399 } 400 401 static int 402 z_decomp_init(arg, options, opt_len, unit, hdrlen, mru, debug) 403 void *arg; 404 u_char *options; 405 int opt_len, unit, hdrlen, mru, debug; 406 { 407 struct deflate_state *state = (struct deflate_state *) arg; 408 409 if (opt_len < CILEN_DEFLATE || options[0] != CI_DEFLATE 410 || options[1] != CILEN_DEFLATE 411 || DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL 412 || DEFLATE_SIZE(options[2]) != state->w_size 413 || options[3] != DEFLATE_CHK_SEQUENCE) 414 return 0; 415 416 state->seqno = 0; 417 state->unit = unit; 418 state->hdrlen = hdrlen; 419 state->debug = debug; 420 state->mru = mru; 421 422 inflateReset(&state->strm); 423 424 return 1; 425 } 426 427 static void 428 z_decomp_reset(arg) 429 void *arg; 430 { 431 struct deflate_state *state = (struct deflate_state *) arg; 432 433 state->seqno = 0; 434 inflateReset(&state->strm); 435 } 436 437 /* 438 * Decompress a Deflate-compressed packet. 439 * 440 * Because of patent problems, we return DECOMP_ERROR for errors 441 * found by inspecting the input data and for system problems, but 442 * DECOMP_FATALERROR for any errors which could possibly be said to 443 * be being detected "after" decompression. For DECOMP_ERROR, 444 * we can issue a CCP reset-request; for DECOMP_FATALERROR, we may be 445 * infringing a patent of Motorola's if we do, so we take CCP down 446 * instead. 447 * 448 * Given that the frame has the correct sequence number and a good FCS, 449 * errors such as invalid codes in the input most likely indicate a 450 * bug, so we return DECOMP_FATALERROR for them in order to turn off 451 * compression, even though they are detected by inspecting the input. 452 */ 453 int 454 z_decompress(arg, mi, mop) 455 void *arg; 456 struct mbuf *mi, **mop; 457 { 458 struct deflate_state *state = (struct deflate_state *) arg; 459 struct mbuf *mo, *mo_head; 460 u_char *rptr, *wptr; 461 int rlen, olen, ospace; 462 int seq, i, flush, r, decode_proto; 463 u_char hdr[PPP_HDRLEN + DEFLATE_OVHD]; 464 465 *mop = NULL; 466 rptr = mtod(mi, u_char *); 467 rlen = mi->m_len; 468 for (i = 0; i < PPP_HDRLEN + DEFLATE_OVHD; ++i) { 469 while (rlen <= 0) { 470 mi = mi->m_next; 471 if (mi == NULL) 472 return DECOMP_ERROR; 473 rptr = mtod(mi, u_char *); 474 rlen = mi->m_len; 475 } 476 hdr[i] = *rptr++; 477 --rlen; 478 } 479 480 /* Check the sequence number. */ 481 seq = (hdr[PPP_HDRLEN] << 8) + hdr[PPP_HDRLEN+1]; 482 if (seq != state->seqno) { 483 if (state->debug) 484 printf("z_decompress%d: bad seq # %d, expected %d\n", 485 state->unit, seq, state->seqno); 486 return DECOMP_ERROR; 487 } 488 ++state->seqno; 489 490 /* Allocate an output mbuf. */ 491 MGETHDR(mo, M_DONTWAIT, MT_DATA); 492 if (mo == NULL) 493 return DECOMP_ERROR; 494 mo_head = mo; 495 mo->m_len = 0; 496 mo->m_next = NULL; 497 MCLGET(mo, M_DONTWAIT); 498 ospace = M_TRAILINGSPACE(mo); 499 if (state->hdrlen + PPP_HDRLEN < ospace) { 500 mo->m_data += state->hdrlen; 501 ospace -= state->hdrlen; 502 } 503 504 /* 505 * Fill in the first part of the PPP header. The protocol field 506 * comes from the decompressed data. 507 */ 508 wptr = mtod(mo, u_char *); 509 wptr[0] = PPP_ADDRESS(hdr); 510 wptr[1] = PPP_CONTROL(hdr); 511 wptr[2] = 0; 512 513 /* 514 * Set up to call inflate. We set avail_out to 1 initially so we can 515 * look at the first byte of the output and decide whether we have 516 * a 1-byte or 2-byte protocol field. 517 */ 518 state->strm.next_in = rptr; 519 state->strm.avail_in = rlen; 520 mi = mi->m_next; 521 flush = (mi == NULL)? Z_PACKET_FLUSH: Z_NO_FLUSH; 522 rlen += PPP_HDRLEN + DEFLATE_OVHD; 523 state->strm.next_out = wptr + 3; 524 state->strm.avail_out = 1; 525 decode_proto = 1; 526 olen = PPP_HDRLEN; 527 528 /* 529 * Call inflate, supplying more input or output as needed. 530 */ 531 for (;;) { 532 r = inflate(&state->strm, flush); 533 if (r != Z_OK) { 534 if (state->debug) 535 printf("z_decompress%d: inflate returned %d (%s)\n", 536 state->unit, r, (state->strm.msg? state->strm.msg: "")); 537 m_freem(mo_head); 538 return DECOMP_FATALERROR; 539 } 540 if (flush != Z_NO_FLUSH && state->strm.avail_out != 0) 541 break; /* all done */ 542 if (state->strm.avail_in == 0 && mi != NULL) { 543 state->strm.next_in = mtod(mi, u_char *); 544 state->strm.avail_in = mi->m_len; 545 rlen += mi->m_len; 546 mi = mi->m_next; 547 if (mi == NULL) 548 flush = Z_PACKET_FLUSH; 549 } 550 if (state->strm.avail_out == 0) { 551 if (decode_proto) { 552 state->strm.avail_out = ospace - PPP_HDRLEN; 553 if ((wptr[3] & 1) == 0) { 554 /* 2-byte protocol field */ 555 wptr[2] = wptr[3]; 556 --state->strm.next_out; 557 ++state->strm.avail_out; 558 --olen; 559 } 560 decode_proto = 0; 561 } else { 562 mo->m_len = ospace; 563 olen += ospace; 564 MGET(mo->m_next, M_DONTWAIT, MT_DATA); 565 mo = mo->m_next; 566 if (mo == NULL) { 567 m_freem(mo_head); 568 return DECOMP_ERROR; 569 } 570 MCLGET(mo, M_DONTWAIT); 571 state->strm.next_out = mtod(mo, u_char *); 572 state->strm.avail_out = ospace = M_TRAILINGSPACE(mo); 573 } 574 } 575 } 576 if (decode_proto) { 577 m_freem(mo_head); 578 return DECOMP_ERROR; 579 } 580 olen += (mo->m_len = ospace - state->strm.avail_out); 581 582 state->stats.unc_bytes += olen; 583 state->stats.unc_packets++; 584 state->stats.comp_bytes += rlen; 585 state->stats.comp_packets++; 586 587 *mop = mo_head; 588 return DECOMP_OK; 589 } 590 591 /* 592 * Incompressible data has arrived - add it to the history. 593 */ 594 static void 595 z_incomp(arg, mi) 596 void *arg; 597 struct mbuf *mi; 598 { 599 struct deflate_state *state = (struct deflate_state *) arg; 600 u_char *rptr; 601 int rlen, proto, r; 602 603 /* 604 * Check that the protocol is one we handle. 605 */ 606 rptr = mtod(mi, u_char *); 607 proto = PPP_PROTOCOL(rptr); 608 if (proto > 0x3fff || proto == 0xfd || proto == 0xfb) 609 return; 610 611 ++state->seqno; 612 613 /* 614 * Iterate through the mbufs, adding the characters in them 615 * to the decompressor's history. For the first mbuf, we start 616 * at the either the 1st or 2nd byte of the protocol field, 617 * depending on whether the protocol value is compressible. 618 */ 619 rlen = mi->m_len; 620 state->strm.next_in = rptr + 3; 621 state->strm.avail_in = rlen - 3; 622 if (proto > 0xff) { 623 --state->strm.next_in; 624 ++state->strm.avail_in; 625 } 626 for (;;) { 627 r = inflateIncomp(&state->strm); 628 if (r != Z_OK) { 629 /* gak! */ 630 if (state->debug) { 631 printf("z_incomp%d: inflateIncomp returned %d (%s)\n", 632 state->unit, r, (state->strm.msg? state->strm.msg: "")); 633 } 634 return; 635 } 636 mi = mi->m_next; 637 if (mi == NULL) 638 break; 639 state->strm.next_in = mtod(mi, u_char *); 640 state->strm.avail_in = mi->m_len; 641 rlen += mi->m_len; 642 } 643 644 /* 645 * Update stats. 646 */ 647 state->stats.inc_bytes += rlen; 648 state->stats.inc_packets++; 649 state->stats.unc_bytes += rlen; 650 state->stats.unc_packets++; 651 } 652 653 #endif /* DO_DEFLATE */ 654