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