Update READMEs etc. for the forthcoming ppp-2.4.5 release
[ppp.git] / pppdump / deflate.c
1 /*
2  * ppp_deflate.c - interface the zlib procedures for Deflate compression
3  * and decompression (as used by gzip) to the PPP code.
4  *
5  * Copyright (c) 1994 Paul Mackerras. All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  *
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in
16  *    the documentation and/or other materials provided with the
17  *    distribution.
18  *
19  * 3. The name(s) of the authors of this software must not be used to
20  *    endorse or promote products derived from this software without
21  *    prior written permission.
22  *
23  * 4. Redistributions of any form whatsoever must retain the following
24  *    acknowledgment:
25  *    "This product includes software developed by Paul Mackerras
26  *     <paulus@samba.org>".
27  *
28  * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO
29  * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
30  * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
31  * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
32  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
33  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
34  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
35  *
36  * $Id: deflate.c,v 1.5 2004/01/17 05:47:55 carlsonj Exp $
37  */
38
39 #include <sys/types.h>
40 #include <stdio.h>
41 #include <stddef.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include "ppp_defs.h"
45 #include "ppp-comp.h"
46 #include "zlib.h"
47
48 #if DO_DEFLATE
49
50 #define DEFLATE_DEBUG   1
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     *z_alloc __P((void *, u_int items, u_int size));
69 static void     z_free __P((void *, void *ptr, u_int nb));
70 static void     *z_decomp_alloc __P((u_char *options, int opt_len));
71 static void     z_decomp_free __P((void *state));
72 static int      z_decomp_init __P((void *state, u_char *options, int opt_len,
73                                      int unit, int hdrlen, int mru, int debug));
74 static void     z_incomp __P((void *state, u_char *dmsg, int len));
75 static int      z_decompress __P((void *state, u_char *cmp, int inlen,
76                                     u_char *dmp, int *outlenp));
77 static void     z_decomp_reset __P((void *state));
78 static void     z_comp_stats __P((void *state, struct compstat *stats));
79
80 /*
81  * Procedures exported to if_ppp.c.
82  */
83 struct compressor ppp_deflate = {
84     CI_DEFLATE,                 /* compress_proto */
85     z_decomp_alloc,             /* decomp_alloc */
86     z_decomp_free,              /* decomp_free */
87     z_decomp_init,              /* decomp_init */
88     z_decomp_reset,             /* decomp_reset */
89     z_decompress,               /* decompress */
90     z_incomp,                   /* incomp */
91     z_comp_stats,               /* decomp_stat */
92 };
93
94 /*
95  * Space allocation and freeing routines for use by zlib routines.
96  */
97 static void *
98 z_alloc(notused, items, size)
99     void *notused;
100     u_int items, size;
101 {
102     return malloc(items * size);
103 }
104
105 static void
106 z_free(notused, ptr, nbytes)
107     void *notused;
108     void *ptr;
109     u_int nbytes;
110 {
111     free(ptr);
112 }
113
114 static void
115 z_comp_stats(arg, stats)
116     void *arg;
117     struct compstat *stats;
118 {
119     struct deflate_state *state = (struct deflate_state *) arg;
120     u_int out;
121
122     *stats = state->stats;
123     stats->ratio = stats->unc_bytes;
124     out = stats->comp_bytes + stats->unc_bytes;
125     if (stats->ratio <= 0x7ffffff)
126         stats->ratio <<= 8;
127     else
128         out >>= 8;
129     if (out != 0)
130         stats->ratio /= out;
131 }
132
133 /*
134  * Allocate space for a decompressor.
135  */
136 static void *
137 z_decomp_alloc(options, opt_len)
138     u_char *options;
139     int opt_len;
140 {
141     struct deflate_state *state;
142     int w_size;
143
144     if (opt_len != CILEN_DEFLATE || options[0] != CI_DEFLATE
145         || options[1] != CILEN_DEFLATE
146         || DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL
147         || options[3] != DEFLATE_CHK_SEQUENCE)
148         return NULL;
149     w_size = DEFLATE_SIZE(options[2]);
150     if (w_size < DEFLATE_MIN_SIZE || w_size > DEFLATE_MAX_SIZE)
151         return NULL;
152
153     state = (struct deflate_state *) malloc(sizeof(*state));
154     if (state == NULL)
155         return NULL;
156
157     state->strm.next_out = NULL;
158     state->strm.zalloc = (alloc_func) z_alloc;
159     state->strm.zfree = (free_func) z_free;
160     if (inflateInit2(&state->strm, -w_size) != Z_OK) {
161         free(state);
162         return NULL;
163     }
164
165     state->w_size = w_size;
166     memset(&state->stats, 0, sizeof(state->stats));
167     return (void *) state;
168 }
169
170 static void
171 z_decomp_free(arg)
172     void *arg;
173 {
174     struct deflate_state *state = (struct deflate_state *) arg;
175
176     inflateEnd(&state->strm);
177     free(state);
178 }
179
180 static int
181 z_decomp_init(arg, options, opt_len, unit, hdrlen, mru, debug)
182     void *arg;
183     u_char *options;
184     int opt_len, unit, hdrlen, mru, debug;
185 {
186     struct deflate_state *state = (struct deflate_state *) arg;
187
188     if (opt_len < CILEN_DEFLATE || options[0] != CI_DEFLATE
189         || options[1] != CILEN_DEFLATE
190         || DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL
191         || DEFLATE_SIZE(options[2]) != state->w_size
192         || options[3] != DEFLATE_CHK_SEQUENCE)
193         return 0;
194
195     state->seqno = 0;
196     state->unit = unit;
197     state->hdrlen = hdrlen;
198     state->debug = debug;
199     state->mru = mru;
200
201     inflateReset(&state->strm);
202
203     return 1;
204 }
205
206 static void
207 z_decomp_reset(arg)
208     void *arg;
209 {
210     struct deflate_state *state = (struct deflate_state *) arg;
211
212     state->seqno = 0;
213     inflateReset(&state->strm);
214 }
215
216 /*
217  * Decompress a Deflate-compressed packet.
218  *
219  * Because of patent problems, we return DECOMP_ERROR for errors
220  * found by inspecting the input data and for system problems, but
221  * DECOMP_FATALERROR for any errors which could possibly be said to
222  * be being detected "after" decompression.  For DECOMP_ERROR,
223  * we can issue a CCP reset-request; for DECOMP_FATALERROR, we may be
224  * infringing a patent of Motorola's if we do, so we take CCP down
225  * instead.
226  *
227  * Given that the frame has the correct sequence number and a good FCS,
228  * errors such as invalid codes in the input most likely indicate a
229  * bug, so we return DECOMP_FATALERROR for them in order to turn off
230  * compression, even though they are detected by inspecting the input.
231  */
232 static int
233 z_decompress(arg, mi, inlen, mo, outlenp)
234     void *arg;
235     u_char *mi, *mo;
236     int inlen, *outlenp;
237 {
238     struct deflate_state *state = (struct deflate_state *) arg;
239     u_char *rptr, *wptr;
240     int rlen, olen, ospace;
241     int seq, i, flush, r, decode_proto;
242
243     rptr = mi;
244     if (*rptr == 0)
245         ++rptr;
246     ++rptr;
247
248     /* Check the sequence number. */
249     seq = (rptr[0] << 8) + rptr[1];
250     rptr += 2;
251     if (seq != state->seqno) {
252 #if !DEFLATE_DEBUG
253         if (state->debug)
254 #endif
255             printf("z_decompress%d: bad seq # %d, expected %d\n",
256                    state->unit, seq, state->seqno);
257         return DECOMP_ERROR;
258     }
259     ++state->seqno;
260
261     /*
262      * Set up to call inflate.
263      */
264     wptr = mo;
265     state->strm.next_in = rptr;
266     state->strm.avail_in = mi + inlen - rptr;
267     rlen = state->strm.avail_in + PPP_HDRLEN + DEFLATE_OVHD;
268     state->strm.next_out = wptr;
269     state->strm.avail_out = state->mru + 2;
270
271     r = inflate(&state->strm, Z_PACKET_FLUSH);
272     if (r != Z_OK) {
273 #if !DEFLATE_DEBUG
274         if (state->debug)
275 #endif
276             printf("z_decompress%d: inflate returned %d (%s)\n",
277                    state->unit, r, (state->strm.msg? state->strm.msg: ""));
278         return DECOMP_FATALERROR;
279     }
280     olen = state->mru + 2 - state->strm.avail_out;
281     *outlenp = olen;
282
283     if ((wptr[0] & 1) != 0)
284         ++olen;                 /* for suppressed protocol high byte */
285     olen += 2;                  /* for address, control */
286
287 #if DEFLATE_DEBUG
288     if (olen > state->mru + PPP_HDRLEN)
289         printf("ppp_deflate%d: exceeded mru (%d > %d)\n",
290                state->unit, olen, state->mru + PPP_HDRLEN);
291 #endif
292
293     state->stats.unc_bytes += olen;
294     state->stats.unc_packets++;
295     state->stats.comp_bytes += rlen;
296     state->stats.comp_packets++;
297
298     return DECOMP_OK;
299 }
300
301 /*
302  * Incompressible data has arrived - add it to the history.
303  */
304 static void
305 z_incomp(arg, mi, mlen)
306     void *arg;
307     u_char *mi;
308     int mlen;
309 {
310     struct deflate_state *state = (struct deflate_state *) arg;
311     u_char *rptr;
312     int rlen, proto, r;
313
314     /*
315      * Check that the protocol is one we handle.
316      */
317     rptr = mi;
318     proto = rptr[0];
319     if ((proto & 1) == 0)
320         proto = (proto << 8) + rptr[1];
321     if (proto > 0x3fff || proto == 0xfd || proto == 0xfb)
322         return;
323
324     ++state->seqno;
325
326     if (rptr[0] == 0)
327         ++rptr;
328     rlen = mi + mlen - rptr;
329     state->strm.next_in = rptr;
330     state->strm.avail_in = rlen;
331     r = inflateIncomp(&state->strm);
332     if (r != Z_OK) {
333         /* gak! */
334 #if !DEFLATE_DEBUG
335         if (state->debug)
336 #endif
337             printf("z_incomp%d: inflateIncomp returned %d (%s)\n",
338                    state->unit, r, (state->strm.msg? state->strm.msg: ""));
339         return;
340     }
341
342     /*
343      * Update stats.
344      */
345     if (proto <= 0xff)
346         ++rlen;
347     rlen += 2;
348     state->stats.inc_bytes += rlen;
349     state->stats.inc_packets++;
350     state->stats.unc_bytes += rlen;
351     state->stats.unc_packets++;
352 }
353
354 #endif /* DO_DEFLATE */