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