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