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