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