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