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