1 /* 2 * deflate.c - interface the zlib procedures for Deflate compression 3 * and decompression (as used by gzip) to the PPP code. 4 * 5 * This version is for use with STREAMS in Solaris 2 6 * 7 * Copyright (c) 2001 by Sun Microsystems, Inc. 8 * All rights reserved. 9 * 10 * Copyright (c) 1994 The Australian National University. 11 * All rights reserved. 12 * 13 * Permission to use, copy, modify, and distribute this software and its 14 * documentation is hereby granted, provided that the above copyright 15 * notice appears in all copies. This software is provided without any 16 * warranty, express or implied. The Australian National University 17 * makes no representations about the suitability of this software for 18 * any purpose. 19 * 20 * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY 21 * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 22 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF 23 * THE AUSTRALIAN NATIONAL UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY 24 * OF SUCH DAMAGE. 25 * 26 * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES, 27 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 28 * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 29 * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO 30 * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, 31 * OR MODIFICATIONS. 32 * 33 * $Id: deflate.c,v 1.9 1999/01/19 23:58:35 paulus Exp $ 34 */ 35 36 #pragma ident "%Z%%M% %I% %E% SMI" 37 38 #include <sys/param.h> 39 #include <sys/types.h> 40 #include <sys/kmem.h> 41 #include <sys/stream.h> 42 #include <sys/cmn_err.h> 43 #include <sys/ddi.h> 44 #include <sys/sunddi.h> 45 #include <sys/errno.h> 46 #include <net/ppp_defs.h> 47 48 /* Defined for platform-neutral include file */ 49 #define PACKETPTR mblk_t * 50 #include <net/ppp-comp.h> 51 #include "s_common.h" 52 #include "zlib.h" 53 54 #if DO_DEFLATE 55 56 /* 57 * State for a Deflate (de)compressor. 58 */ 59 struct deflate_state { 60 int seqno; 61 int w_size; 62 int unit; 63 int hdrlen; 64 int mru; 65 int flags; 66 z_stream strm; 67 struct compstat stats; 68 }; 69 70 #define DEFLATE_OVHD 2 /* Deflate overhead/packet */ 71 72 #define DS_DEBUG 0x0001 73 #define DS_TESTIN 0x0002 74 #define DS_TESTOUT 0x0004 75 76 static void *z_alloc(void *, uint_t items, uint_t size); 77 static void z_free(void *, void *ptr); 78 static void *z_comp_alloc(uchar_t *options, int opt_len); 79 static void *z_decomp_alloc(uchar_t *options, int opt_len); 80 static void z_comp_free(void *state); 81 static void z_decomp_free(void *state); 82 static int z_comp_init(void *state, uchar_t *options, int opt_len, 83 int unit, int hdrlen, int debug); 84 static int z_decomp_init(void *state, uchar_t *options, int opt_len, 85 int unit, int hdrlen, int mru, int debug); 86 static int z_compress(void *state, mblk_t **mret, 87 mblk_t *mp, int slen, int maxolen); 88 static int z_incomp(void *state, mblk_t *dmsg); 89 static int z_decompress(void *state, mblk_t **dmpp); 90 static void z_comp_reset(void *state); 91 static void z_decomp_reset(void *state); 92 static void z_comp_stats(void *state, struct compstat *stats); 93 static int z_set_effort(void *xstate, void *rstate, int effortlevel); 94 95 /* 96 * Procedures exported to ppp_comp.c. 97 */ 98 struct compressor ppp_deflate = { 99 CI_DEFLATE, /* compress_proto */ 100 z_comp_alloc, /* comp_alloc */ 101 z_comp_free, /* comp_free */ 102 z_comp_init, /* comp_init */ 103 z_comp_reset, /* comp_reset */ 104 z_compress, /* compress */ 105 z_comp_stats, /* comp_stat */ 106 z_decomp_alloc, /* decomp_alloc */ 107 z_decomp_free, /* decomp_free */ 108 z_decomp_init, /* decomp_init */ 109 z_decomp_reset, /* decomp_reset */ 110 z_decompress, /* decompress */ 111 z_incomp, /* incomp */ 112 z_comp_stats, /* decomp_stat */ 113 z_set_effort, /* set_effort */ 114 }; 115 116 struct compressor ppp_deflate_draft = { 117 CI_DEFLATE_DRAFT, /* compress_proto */ 118 z_comp_alloc, /* comp_alloc */ 119 z_comp_free, /* comp_free */ 120 z_comp_init, /* comp_init */ 121 z_comp_reset, /* comp_reset */ 122 z_compress, /* compress */ 123 z_comp_stats, /* comp_stat */ 124 z_decomp_alloc, /* decomp_alloc */ 125 z_decomp_free, /* decomp_free */ 126 z_decomp_init, /* decomp_init */ 127 z_decomp_reset, /* decomp_reset */ 128 z_decompress, /* decompress */ 129 z_incomp, /* incomp */ 130 z_comp_stats, /* decomp_stat */ 131 z_set_effort, /* set_effort */ 132 }; 133 134 #define DECOMP_CHUNK 512 135 136 /* 137 * Space allocation and freeing routines for use by zlib routines. 138 */ 139 struct zchunk { 140 uint_t size; 141 uint_t guard; 142 }; 143 144 #define GUARD_MAGIC 0x77a6011a 145 146 /* 147 * z_alloc() 148 */ 149 /* ARGSUSED */ 150 static void * 151 z_alloc(void *notused, uint_t items, uint_t size) 152 { 153 struct zchunk *z; 154 155 size = items * size + sizeof (struct zchunk); 156 157 z = (struct zchunk *)kmem_alloc(size, KM_NOSLEEP); 158 if (z == NULL) 159 return (NULL); 160 161 z->size = size; 162 z->guard = GUARD_MAGIC; 163 164 return ((void *)(z + 1)); 165 } 166 167 /* 168 * z_free() 169 */ 170 /* ARGSUSED */ 171 static void 172 z_free(void *notused, void *ptr) 173 { 174 struct zchunk *z = ((struct zchunk *)ptr) - 1; 175 176 if (ptr == NULL) 177 return; 178 179 if (z->guard != GUARD_MAGIC) { 180 cmn_err(CE_CONT, 181 "deflate: z_free of corrupted chunk at 0x%p (%x, %x)\n", 182 (void *)z, z->size, z->guard); 183 184 return; 185 } 186 187 kmem_free(z, z->size); 188 } 189 190 /* 191 * Allocate space for a compressor. 192 */ 193 static void * 194 z_comp_alloc(uchar_t *options, int opt_len) 195 { 196 struct deflate_state *state; 197 int w_size; 198 199 if (opt_len != CILEN_DEFLATE || 200 (options[0] != CI_DEFLATE && options[0] != CI_DEFLATE_DRAFT) || 201 options[1] != CILEN_DEFLATE || 202 DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL || 203 options[3] != DEFLATE_CHK_SEQUENCE) { 204 205 return (NULL); 206 } 207 208 w_size = DEFLATE_SIZE(options[2]); 209 /* 210 * Check <= minimum size to avoid unfixable zlib bug -- window size 211 * 256 (w_size 8) is not supported. 212 */ 213 if (w_size <= DEFLATE_MIN_SIZE || w_size > DEFLATE_MAX_SIZE) { 214 return (NULL); 215 } 216 217 state = (struct deflate_state *)kmem_zalloc(sizeof (*state), KM_SLEEP); 218 ASSERT(state != NULL); 219 220 state->strm.zalloc = (alloc_func)z_alloc; 221 state->strm.zfree = (free_func)z_free; 222 223 if (deflateInit2(&state->strm, Z_DEFAULT_COMPRESSION, 224 DEFLATE_METHOD_VAL, -w_size, 8, Z_DEFAULT_STRATEGY) != Z_OK) { 225 226 kmem_free(state, sizeof (*state)); 227 228 return (NULL); 229 } 230 231 state->w_size = w_size; 232 233 bzero(&state->stats, sizeof (state->stats)); 234 235 return ((void *)state); 236 } 237 238 /* 239 * z_comp_free() 240 */ 241 static void 242 z_comp_free(void *arg) 243 { 244 struct deflate_state *state = (struct deflate_state *)arg; 245 246 (void) deflateEnd(&state->strm); 247 248 kmem_free(state, sizeof (*state)); 249 } 250 251 /* 252 * z_comp_init() 253 */ 254 static int 255 z_comp_init(void *arg, uchar_t *options, int opt_len, int unit, int hdrlen, 256 int debug) 257 { 258 struct deflate_state *state = (struct deflate_state *)arg; 259 260 if (opt_len < CILEN_DEFLATE || 261 (options[0] != CI_DEFLATE && options[0] != CI_DEFLATE_DRAFT) || 262 options[1] != CILEN_DEFLATE || 263 DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL || 264 DEFLATE_SIZE(options[2]) != state->w_size || 265 options[3] != DEFLATE_CHK_SEQUENCE) { 266 267 return (0); 268 } 269 270 state->seqno = 0; 271 state->unit = unit; 272 state->hdrlen = hdrlen; 273 if (debug) 274 state->flags |= DS_DEBUG; 275 else 276 state->flags &= ~DS_DEBUG; 277 278 (void) deflateReset(&state->strm); 279 280 return (1); 281 } 282 283 /* 284 * z_comp_reset() 285 */ 286 static void 287 z_comp_reset(void *arg) 288 { 289 struct deflate_state *state = (struct deflate_state *)arg; 290 291 state->seqno = 0; 292 293 (void) deflateReset(&state->strm); 294 } 295 296 /* 297 * z_compress() 298 */ 299 static int 300 z_compress(void *arg, mblk_t **mret, mblk_t *mp, int orig_len, int maxolen) 301 { 302 struct deflate_state *state = (struct deflate_state *)arg; 303 uchar_t *rptr, *rmax; 304 uchar_t *wptr; 305 int olen; 306 int wspace; 307 int r; 308 int flush; 309 mblk_t *m; 310 #if defined(lint) || defined(_lint) 311 uchar_t hdlcaddr, hdlcctrl; 312 #else 313 int hdlcaddr, hdlcctrl; 314 #endif 315 316 #define ADJRPTR() { \ 317 if (rptr != NULL) { \ 318 while (rptr >= rmax) { \ 319 if ((mp = mp->b_cont) == NULL) { \ 320 rptr = NULL; \ 321 break; \ 322 } \ 323 rptr = mp->b_rptr; \ 324 rmax = mp->b_wptr; \ 325 } \ 326 } \ 327 } 328 329 #define GETBYTE(v) { \ 330 if (rptr != NULL) { \ 331 (v) = *rptr++; \ 332 } \ 333 } 334 335 /* 336 * Check that the protocol is one we handle. Pullup is *NOT* 337 * possible here. 338 */ 339 *mret = NULL; 340 rptr = mp->b_rptr; 341 rmax = mp->b_wptr; 342 ADJRPTR(); 343 GETBYTE(hdlcaddr); 344 ADJRPTR(); 345 GETBYTE(hdlcctrl); 346 ADJRPTR(); 347 348 /* 349 * Per RFC 1979, the protocol field must be compressed using a 350 * PFC-like procedure. Also, all protocols between 0000-3FFF 351 * except the two compression protocols must be LZ compressed. 352 */ 353 if (rptr == NULL) 354 return (orig_len); 355 r = *rptr; 356 if (r == 0) { 357 rptr++; 358 ADJRPTR(); 359 if (rptr == NULL || *rptr == PPP_COMP || *rptr == PPP_COMPFRAG) 360 return (orig_len); 361 } else { 362 if (r > 0x3F) 363 return (orig_len); 364 } 365 366 /* 367 * Allocate one mblk initially 368 */ 369 if (maxolen > orig_len) { 370 maxolen = orig_len; 371 } 372 373 if (maxolen <= PPP_HDRLEN + 2) { 374 wspace = 0; 375 m = NULL; 376 } else { 377 wspace = maxolen + state->hdrlen; 378 if (wspace > 4096) { 379 wspace = 4096; 380 } 381 382 m = allocb(wspace, BPRI_MED); 383 } 384 385 if (m != NULL) { 386 387 wspace = m->b_datap->db_lim - m->b_wptr; 388 389 *mret = m; 390 391 if (state->hdrlen + PPP_HDRLEN + 2 < wspace) { 392 m->b_rptr += state->hdrlen; 393 m->b_wptr = m->b_rptr; 394 wspace -= state->hdrlen; 395 } 396 397 wptr = m->b_wptr; 398 399 /* 400 * Copy over the PPP header and store the 2-byte 401 * sequence number 402 */ 403 wptr[0] = hdlcaddr; 404 wptr[1] = hdlcctrl; 405 wptr[2] = PPP_COMP >> 8; 406 wptr[3] = PPP_COMP; 407 408 wptr += PPP_HDRLEN; 409 410 wptr[0] = state->seqno >> 8; 411 wptr[1] = state->seqno; 412 wptr += 2; 413 414 #ifdef DEBUG 415 /* 416 * If testing output, just garbling the sequence here 417 * does the trick. 418 */ 419 if ((state->flags & DS_TESTOUT) && (state->seqno % 100) == 50) 420 wptr[-1] ^= 0xAA; 421 #endif 422 423 state->strm.next_out = wptr; 424 state->strm.avail_out = wspace - (PPP_HDRLEN + 2); 425 } else { 426 state->strm.next_out = NULL; 427 state->strm.avail_out = 1000000; 428 } 429 430 ++state->seqno; 431 432 state->strm.next_in = rptr; 433 state->strm.avail_in = mp->b_wptr - rptr; 434 435 olen = 0; 436 437 for (;;) { 438 flush = (mp == NULL || mp->b_cont == NULL) ? Z_PACKET_FLUSH : 439 Z_NO_FLUSH; 440 r = deflate(&state->strm, flush); 441 442 if (r != Z_OK) { 443 cmn_err(CE_CONT, 444 "z_compress%d: deflate returned %d (%s)\n", 445 state->unit, r, 446 (state->strm.msg? state->strm.msg: "")); 447 448 break; 449 } 450 451 if (state->strm.avail_in == 0) { 452 if (mp != NULL) 453 mp = mp->b_cont; 454 if (mp == NULL) { 455 if (state->strm.avail_out != 0) 456 break; /* all done */ 457 } else { 458 state->strm.next_in = mp->b_rptr; 459 state->strm.avail_in = mp->b_wptr - mp->b_rptr; 460 } 461 } 462 463 if (state->strm.avail_out == 0) { 464 if (m != NULL) { 465 m->b_wptr += wspace; 466 olen += wspace; 467 wspace = maxolen - olen; 468 469 if (wspace <= 0) { 470 wspace = 0; 471 m->b_cont = NULL; 472 } else { 473 if (wspace < 32) { 474 wspace = 32; 475 } else if (wspace > 4096) { 476 wspace = 4096; 477 } 478 479 m->b_cont = allocb(wspace, BPRI_MED); 480 } 481 482 m = m->b_cont; 483 484 if (m != NULL) { 485 state->strm.next_out = m->b_wptr; 486 wspace = m->b_datap->db_lim - 487 m->b_wptr; 488 state->strm.avail_out = wspace; 489 } 490 } 491 492 if (m == NULL) { 493 state->strm.next_out = NULL; 494 state->strm.avail_out = 1000000; 495 } 496 } 497 } 498 499 if (m != NULL) { 500 m->b_wptr += wspace - state->strm.avail_out; 501 olen += wspace - state->strm.avail_out; 502 } 503 504 /* 505 * See if we managed to reduce the size of the packet. 506 */ 507 if (olen < orig_len && m != NULL) { 508 state->stats.comp_bytes += olen; 509 state->stats.comp_packets++; 510 } else { 511 if (*mret != NULL) { 512 freemsg(*mret); 513 *mret = NULL; 514 } 515 516 state->stats.inc_bytes += orig_len; 517 state->stats.inc_packets++; 518 519 olen = orig_len; 520 } 521 522 state->stats.unc_bytes += orig_len; 523 state->stats.unc_packets++; 524 525 return (olen); 526 } 527 528 /* 529 * z_incomp() 530 * 531 * Incompressible data has arrived - add it to the history. 532 */ 533 static int 534 z_incomp(void *arg, mblk_t *mp) 535 { 536 struct deflate_state *state = (struct deflate_state *)arg; 537 uchar_t *rptr, *rmax; 538 int rlen; 539 int r; 540 541 /* 542 * Check that the protocol is one we handle. Pullup is *NOT* 543 * possible here. 544 */ 545 rptr = mp->b_rptr; 546 rmax = mp->b_wptr; 547 ADJRPTR(); 548 rptr++; /* skip address */ 549 ADJRPTR(); 550 rptr++; /* skip control */ 551 ADJRPTR(); 552 553 /* 554 * Per RFC 1979, the protocol field must be compressed using a 555 * PFC-like procedure. Also, all protocols between 0000-3FFF 556 * except the two compression protocols must be LZ compressed. 557 */ 558 if (rptr == NULL) 559 return (0); 560 r = *rptr; 561 if (r == 0) { 562 rptr++; 563 ADJRPTR(); 564 if (rptr == NULL || *rptr == PPP_COMP || *rptr == PPP_COMPFRAG) 565 return (0); 566 } else { 567 if (r > 0x3F) 568 return (0); 569 } 570 571 ++state->seqno; 572 573 /* 574 * Iterate through the message blocks, adding the characters 575 * in them to the decompressor's history. 576 */ 577 rlen = mp->b_wptr - rptr; 578 579 state->strm.next_in = rptr; 580 state->strm.avail_in = rlen; 581 582 for (;;) { 583 r = inflateIncomp(&state->strm); 584 585 if (r != Z_OK) { /* gak! */ 586 if (state->flags & DS_DEBUG) { 587 cmn_err(CE_CONT, 588 "z_incomp%d: inflateIncomp returned " 589 "%d (%s)\n", state->unit, r, 590 (state->strm.msg? state->strm.msg: "")); 591 } 592 593 return (-1); 594 } 595 596 mp = mp->b_cont; 597 if (mp == NULL) { 598 break; 599 } 600 601 state->strm.next_in = mp->b_rptr; 602 state->strm.avail_in = mp->b_wptr - mp->b_rptr; 603 604 rlen += state->strm.avail_in; 605 } 606 607 /* 608 * Update stats 609 */ 610 state->stats.inc_bytes += rlen; 611 state->stats.inc_packets++; 612 state->stats.unc_bytes += rlen; 613 state->stats.unc_packets++; 614 return (0); 615 #undef ADJRPTR 616 } 617 618 /* 619 * z_comp_stats() 620 */ 621 static void 622 z_comp_stats(void *arg, struct compstat *stats) 623 { 624 struct deflate_state *state = (struct deflate_state *)arg; 625 uint_t out; 626 627 *stats = state->stats; 628 stats->ratio = stats->unc_bytes; 629 out = stats->comp_bytes + stats->unc_bytes; 630 631 if (stats->ratio <= 0x7ffffff) { 632 stats->ratio <<= 8; 633 } else { 634 out >>= 8; 635 } 636 637 if (out != 0) { 638 stats->ratio /= out; 639 } 640 } 641 642 /* 643 * z_decomp_alloc() 644 * 645 * Allocate space for a decompressor. 646 */ 647 static void * 648 z_decomp_alloc(uchar_t *options, int opt_len) 649 { 650 struct deflate_state *state; 651 int w_size; 652 653 if (opt_len != CILEN_DEFLATE || 654 (options[0] != CI_DEFLATE && options[0] != CI_DEFLATE_DRAFT) || 655 options[1] != CILEN_DEFLATE || 656 DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL || 657 options[3] != DEFLATE_CHK_SEQUENCE) { 658 659 return (NULL); 660 } 661 662 w_size = DEFLATE_SIZE(options[2]); 663 /* 664 * Check <= minimum size to avoid unfixable zlib bug -- window size 665 * 256 (w_size 8) is not supported. 666 */ 667 if (w_size <= DEFLATE_MIN_SIZE || w_size > DEFLATE_MAX_SIZE) { 668 return (NULL); 669 } 670 671 state = (struct deflate_state *)kmem_zalloc(sizeof (*state), KM_SLEEP); 672 ASSERT(state != NULL); 673 674 state->strm.zalloc = (alloc_func)z_alloc; 675 state->strm.zfree = (free_func)z_free; 676 677 if (inflateInit2(&state->strm, -w_size) != Z_OK) { 678 kmem_free(state, sizeof (*state)); 679 return (NULL); 680 } 681 682 state->w_size = w_size; 683 684 bzero(&state->stats, sizeof (state->stats)); 685 686 return ((void *)state); 687 } 688 689 /* 690 * z_decomp_free() 691 */ 692 static void 693 z_decomp_free(void *arg) 694 { 695 struct deflate_state *state = (struct deflate_state *)arg; 696 697 (void) inflateEnd(&state->strm); 698 699 kmem_free(state, sizeof (*state)); 700 } 701 702 /* 703 * z_decomp_init() 704 */ 705 static int 706 z_decomp_init(void *arg, uchar_t *options, int opt_len, int unit, int hdrlen, 707 int mru, int debug) 708 { 709 struct deflate_state *state = (struct deflate_state *)arg; 710 711 if (opt_len < CILEN_DEFLATE || 712 (options[0] != CI_DEFLATE && options[0] != CI_DEFLATE_DRAFT) || 713 options[1] != CILEN_DEFLATE || 714 DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL || 715 DEFLATE_SIZE(options[2]) != state->w_size || 716 options[3] != DEFLATE_CHK_SEQUENCE) { 717 718 return (0); 719 } 720 721 state->seqno = 0; 722 state->unit = unit; 723 state->hdrlen = hdrlen; 724 if (debug) 725 state->flags |= DS_DEBUG; 726 else 727 state->flags &= ~DS_DEBUG; 728 state->mru = mru; 729 730 (void) inflateReset(&state->strm); 731 732 return (1); 733 } 734 735 /* 736 * z_decomp_reset() 737 */ 738 static void 739 z_decomp_reset(void *arg) 740 { 741 struct deflate_state *state = (struct deflate_state *)arg; 742 743 state->seqno = 0; 744 745 (void) inflateReset(&state->strm); 746 } 747 748 /* 749 * z_decompress() 750 * 751 * Decompress a Deflate-compressed packet. 752 * 753 * Because of patent problems, we return DECOMP_ERROR for errors 754 * found by inspecting the input data and for system problems, but 755 * DECOMP_FATALERROR for any errors which could possibly be said to 756 * be being detected "after" decompression. For DECOMP_ERROR, 757 * we can issue a CCP reset-request; for DECOMP_FATALERROR, we may be 758 * infringing a patent of Motorola's if we do, so we take CCP down 759 * instead. 760 * 761 * Given that the frame has the correct sequence number and a good FCS, 762 * errors such as invalid codes in the input most likely indicate a 763 * bug, so we return DECOMP_FATALERROR for them in order to turn off 764 * compression, even though they are detected by inspecting the input. 765 */ 766 static int 767 z_decompress(void *arg, mblk_t **mop) 768 { 769 struct deflate_state *state = (struct deflate_state *)arg; 770 mblk_t *mi = *mop, *mnext; 771 mblk_t *mo; 772 mblk_t *mo_head; 773 uchar_t *rptr, *rmax; 774 uchar_t *wptr; 775 int rlen; 776 int olen; 777 int ospace; 778 int seq; 779 int flush; 780 int r; 781 int decode_proto; 782 #if defined(lint) || defined(_lint) 783 uchar_t hdlcaddr, hdlcctrl; 784 #else 785 int hdlcaddr, hdlcctrl; 786 #endif 787 788 /* Note: spppcomp already did a pullup to fix the first buffer. */ 789 *mop = NULL; 790 rptr = mi->b_rptr + PPP_HDRLEN; 791 rmax = mi->b_wptr; 792 if (rptr > rmax) { 793 if (state->flags & DS_DEBUG) { 794 cmn_err(CE_CONT, "z_decompress%d: bad buffer\n", 795 state->unit); 796 } 797 freemsg(mi); 798 return (DECOMP_ERROR); 799 } 800 801 hdlcaddr = rptr[-PPP_HDRLEN]; 802 hdlcctrl = rptr[-PPP_HDRLEN+1]; 803 804 /* 805 * Note that we free as we go. If we fail to decompress, 806 * there's nothing good that the caller can do. 807 */ 808 #define ADJRPTR() { \ 809 if (rptr != NULL) { \ 810 while (rptr >= rmax) { \ 811 mnext = mi->b_cont; \ 812 freeb(mi); \ 813 if ((mi = mnext) == NULL) { \ 814 rptr = NULL; \ 815 break; \ 816 } \ 817 rptr = mi->b_rptr; \ 818 rmax = mi->b_wptr; \ 819 } \ 820 } \ 821 } 822 823 /* 824 * Check the sequence number 825 */ 826 ADJRPTR(); 827 seq = rptr == NULL ? 0 : (*rptr++ << 8); 828 ADJRPTR(); 829 if (rptr == NULL) { 830 if (state->flags & DS_DEBUG) { 831 cmn_err(CE_CONT, "z_decompress%d: bad buffer\n", 832 state->unit); 833 } 834 return (DECOMP_ERROR); 835 } 836 837 seq |= *rptr++; 838 839 #ifdef DEBUG 840 /* 841 * If testing input, just pretending the sequence is bad here 842 * does the trick. 843 */ 844 if ((state->flags & DS_TESTIN) && (state->seqno % 300) == 101) 845 seq ^= 0x55; 846 #endif 847 if (seq != state->seqno++) { 848 freemsg(mi); 849 if (state->flags & DS_DEBUG) { 850 cmn_err(CE_CONT, 851 "z_decompress%d: bad seq # %d, expected %d\n", 852 state->unit, seq, state->seqno - 1); 853 } 854 return (DECOMP_ERROR); 855 } 856 857 /* 858 * Allocate an output message block 859 */ 860 mo = allocb(DECOMP_CHUNK + state->hdrlen, BPRI_MED); 861 if (mo == NULL) { 862 freemsg(mi); 863 return (DECOMP_ERROR); 864 } 865 866 mo_head = mo; 867 mo->b_cont = NULL; 868 mo->b_rptr += state->hdrlen; 869 mo->b_wptr = wptr = mo->b_rptr; 870 871 ospace = DECOMP_CHUNK; 872 olen = 0; 873 874 /* 875 * Fill in the first part of the PPP header. The protocol field 876 * comes from the decompressed data. 877 */ 878 *wptr++ = hdlcaddr; 879 *wptr++ = hdlcctrl; 880 *wptr++ = 0; 881 882 /* 883 * Set up to call inflate. We set avail_out to 1 initially so we can 884 * look at the first byte of the output and decide whether we have 885 * a 1-byte or 2-byte protocol field. 886 */ 887 state->strm.next_in = rptr; 888 state->strm.avail_in = mi->b_wptr - rptr; 889 890 rlen = state->strm.avail_in + PPP_HDRLEN + DEFLATE_OVHD; 891 892 state->strm.next_out = wptr; 893 state->strm.avail_out = 1; 894 895 decode_proto = 1; 896 897 /* 898 * Call inflate, supplying more input or output as needed. 899 */ 900 for (;;) { 901 902 flush = (mi == NULL || mi->b_cont == NULL) ? 903 Z_PACKET_FLUSH : Z_NO_FLUSH; 904 r = inflate(&state->strm, flush); 905 906 if (r != Z_OK) { 907 908 if (state->flags & DS_DEBUG) { 909 cmn_err(CE_CONT, 910 "z_decompress%d: inflate returned %d " 911 "(%s)\n", state->unit, r, 912 (state->strm.msg? state->strm.msg: "")); 913 } 914 915 if (mi != NULL) 916 freemsg(mi); 917 freemsg(mo_head); 918 919 return (DECOMP_FATALERROR); 920 } 921 922 if (state->strm.avail_in == 0) { 923 if (mi != NULL) { 924 mnext = mi->b_cont; 925 freeb(mi); 926 mi = mnext; 927 } 928 if (mi == NULL) { 929 if (state->strm.avail_out != 0) 930 break; /* all done */ 931 } else { 932 state->strm.next_in = mi->b_rptr; 933 state->strm.avail_in = mi->b_wptr - mi->b_rptr; 934 935 rlen += state->strm.avail_in; 936 } 937 } 938 939 if (state->strm.avail_out == 0) { 940 if (decode_proto) { 941 state->strm.avail_out = ospace - PPP_HDRLEN; 942 943 if ((wptr[0] & 1) == 0) { 944 /* 945 * 2-byte protocol field 946 */ 947 wptr[-1] = wptr[0]; 948 949 --state->strm.next_out; 950 ++state->strm.avail_out; 951 } 952 953 decode_proto = 0; 954 } else { 955 mo->b_wptr += ospace; 956 olen += ospace; 957 958 mo->b_cont = allocb(DECOMP_CHUNK, BPRI_MED); 959 960 mo = mo->b_cont; 961 if (mo == NULL) { 962 if (mi != NULL) 963 freemsg(mi); 964 freemsg(mo_head); 965 return (DECOMP_ERROR); 966 } 967 968 state->strm.next_out = mo->b_rptr; 969 state->strm.avail_out = ospace = DECOMP_CHUNK; 970 } 971 } 972 } 973 974 if (decode_proto) { 975 freemsg(mo_head); 976 return (DECOMP_ERROR); 977 } 978 979 mo->b_wptr += ospace - state->strm.avail_out; 980 olen += ospace - state->strm.avail_out; 981 982 if ((olen > state->mru + PPP_HDRLEN) && (state->flags & DS_DEBUG)) { 983 cmn_err(CE_CONT, "z_decompress%d: exceeded mru (%d > %d)\n", 984 state->unit, olen, state->mru + PPP_HDRLEN); 985 } 986 987 state->stats.unc_bytes += olen; 988 state->stats.unc_packets++; 989 state->stats.comp_bytes += rlen; 990 state->stats.comp_packets++; 991 992 *mop = mo_head; 993 994 return (DECOMP_OK); 995 } 996 997 /* ARGSUSED */ 998 static int 999 z_set_effort(void *xarg, void *rarg, int effortlevel) 1000 { 1001 struct deflate_state *xstate = (struct deflate_state *)xarg; 1002 #ifdef DEBUG 1003 struct deflate_state *rstate = (struct deflate_state *)rarg; 1004 #endif 1005 int retv; 1006 1007 #ifdef DEBUG 1008 if (effortlevel == 42 || effortlevel == 2112) { 1009 /* corrupt received data. */ 1010 if (rstate != NULL) { 1011 rstate->flags |= DS_TESTIN; 1012 cmn_err(CE_CONT, "deflate: enabled input testing."); 1013 } 1014 if (effortlevel != 2112) 1015 return (0); 1016 } 1017 if (effortlevel == 2001 || effortlevel == 2112) { 1018 /* corrupt transmitted data. */ 1019 if (xstate != NULL) { 1020 xstate->flags |= DS_TESTOUT; 1021 cmn_err(CE_CONT, "deflate: enabled output testing."); 1022 } 1023 return (0); 1024 } 1025 #endif 1026 if (effortlevel < -1 || effortlevel > 9) 1027 return (EINVAL); 1028 if (xstate == NULL) 1029 return (0); 1030 retv = deflateParams(&xstate->strm, effortlevel, Z_DEFAULT_STRATEGY); 1031 return (retv == Z_OK ? 0 : EINVAL); 1032 } 1033 1034 #endif /* DO_DEFLATE */ 1035