]> git.ozlabs.org Git - ppp.git/blob - pppdump/deflate.c
More copyright updates. The new CMU copyright notice is from CMU and
[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.4 2002/12/06 09:49:16 paulus Exp $
37  */
38
39 #include <sys/types.h>
40 #include <stddef.h>
41 #include <stdlib.h>
42 #include "ppp_defs.h"
43 #include "ppp-comp.h"
44 #include "zlib.h"
45
46 #if DO_DEFLATE
47
48 #define DEFLATE_DEBUG   1
49
50 /*
51  * State for a Deflate (de)compressor.
52  */
53 struct deflate_state {
54     int         seqno;
55     int         w_size;
56     int         unit;
57     int         hdrlen;
58     int         mru;
59     int         debug;
60     z_stream    strm;
61     struct compstat stats;
62 };
63
64 #define DEFLATE_OVHD    2               /* Deflate overhead/packet */
65
66 static void     *z_alloc __P((void *, u_int items, u_int size));
67 static void     z_free __P((void *, void *ptr, u_int nb));
68 static void     *z_decomp_alloc __P((u_char *options, int opt_len));
69 static void     z_decomp_free __P((void *state));
70 static int      z_decomp_init __P((void *state, u_char *options, int opt_len,
71                                      int unit, int hdrlen, int mru, int debug));
72 static void     z_incomp __P((void *state, u_char *dmsg, int len));
73 static int      z_decompress __P((void *state, u_char *cmp, int inlen,
74                                     u_char *dmp, int *outlenp));
75 static void     z_decomp_reset __P((void *state));
76 static void     z_comp_stats __P((void *state, struct compstat *stats));
77
78 /*
79  * Procedures exported to if_ppp.c.
80  */
81 struct compressor ppp_deflate = {
82     CI_DEFLATE,                 /* compress_proto */
83     z_decomp_alloc,             /* decomp_alloc */
84     z_decomp_free,              /* decomp_free */
85     z_decomp_init,              /* decomp_init */
86     z_decomp_reset,             /* decomp_reset */
87     z_decompress,               /* decompress */
88     z_incomp,                   /* incomp */
89     z_comp_stats,               /* decomp_stat */
90 };
91
92 /*
93  * Space allocation and freeing routines for use by zlib routines.
94  */
95 static void *
96 z_alloc(notused, items, size)
97     void *notused;
98     u_int items, size;
99 {
100     return malloc(items * size);
101 }
102
103 static void
104 z_free(notused, ptr, nbytes)
105     void *notused;
106     void *ptr;
107     u_int nbytes;
108 {
109     free(ptr);
110 }
111
112 static void
113 z_comp_stats(arg, stats)
114     void *arg;
115     struct compstat *stats;
116 {
117     struct deflate_state *state = (struct deflate_state *) arg;
118     u_int out;
119
120     *stats = state->stats;
121     stats->ratio = stats->unc_bytes;
122     out = stats->comp_bytes + stats->unc_bytes;
123     if (stats->ratio <= 0x7ffffff)
124         stats->ratio <<= 8;
125     else
126         out >>= 8;
127     if (out != 0)
128         stats->ratio /= out;
129 }
130
131 /*
132  * Allocate space for a decompressor.
133  */
134 static void *
135 z_decomp_alloc(options, opt_len)
136     u_char *options;
137     int opt_len;
138 {
139     struct deflate_state *state;
140     int w_size;
141
142     if (opt_len != CILEN_DEFLATE || options[0] != CI_DEFLATE
143         || options[1] != CILEN_DEFLATE
144         || DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL
145         || options[3] != DEFLATE_CHK_SEQUENCE)
146         return NULL;
147     w_size = DEFLATE_SIZE(options[2]);
148     if (w_size < DEFLATE_MIN_SIZE || w_size > DEFLATE_MAX_SIZE)
149         return NULL;
150
151     state = (struct deflate_state *) malloc(sizeof(*state));
152     if (state == NULL)
153         return NULL;
154
155     state->strm.next_out = NULL;
156     state->strm.zalloc = (alloc_func) z_alloc;
157     state->strm.zfree = (free_func) z_free;
158     if (inflateInit2(&state->strm, -w_size) != Z_OK) {
159         free(state);
160         return NULL;
161     }
162
163     state->w_size = w_size;
164     memset(&state->stats, 0, sizeof(state->stats));
165     return (void *) state;
166 }
167
168 static void
169 z_decomp_free(arg)
170     void *arg;
171 {
172     struct deflate_state *state = (struct deflate_state *) arg;
173
174     inflateEnd(&state->strm);
175     free(state);
176 }
177
178 static int
179 z_decomp_init(arg, options, opt_len, unit, hdrlen, mru, debug)
180     void *arg;
181     u_char *options;
182     int opt_len, unit, hdrlen, mru, debug;
183 {
184     struct deflate_state *state = (struct deflate_state *) arg;
185
186     if (opt_len < CILEN_DEFLATE || options[0] != CI_DEFLATE
187         || options[1] != CILEN_DEFLATE
188         || DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL
189         || DEFLATE_SIZE(options[2]) != state->w_size
190         || options[3] != DEFLATE_CHK_SEQUENCE)
191         return 0;
192
193     state->seqno = 0;
194     state->unit = unit;
195     state->hdrlen = hdrlen;
196     state->debug = debug;
197     state->mru = mru;
198
199     inflateReset(&state->strm);
200
201     return 1;
202 }
203
204 static void
205 z_decomp_reset(arg)
206     void *arg;
207 {
208     struct deflate_state *state = (struct deflate_state *) arg;
209
210     state->seqno = 0;
211     inflateReset(&state->strm);
212 }
213
214 /*
215  * Decompress a Deflate-compressed packet.
216  *
217  * Because of patent problems, we return DECOMP_ERROR for errors
218  * found by inspecting the input data and for system problems, but
219  * DECOMP_FATALERROR for any errors which could possibly be said to
220  * be being detected "after" decompression.  For DECOMP_ERROR,
221  * we can issue a CCP reset-request; for DECOMP_FATALERROR, we may be
222  * infringing a patent of Motorola's if we do, so we take CCP down
223  * instead.
224  *
225  * Given that the frame has the correct sequence number and a good FCS,
226  * errors such as invalid codes in the input most likely indicate a
227  * bug, so we return DECOMP_FATALERROR for them in order to turn off
228  * compression, even though they are detected by inspecting the input.
229  */
230 static int
231 z_decompress(arg, mi, inlen, mo, outlenp)
232     void *arg;
233     u_char *mi, *mo;
234     int inlen, *outlenp;
235 {
236     struct deflate_state *state = (struct deflate_state *) arg;
237     u_char *rptr, *wptr;
238     int rlen, olen, ospace;
239     int seq, i, flush, r, decode_proto;
240
241     rptr = mi;
242     if (*rptr == 0)
243         ++rptr;
244     ++rptr;
245
246     /* Check the sequence number. */
247     seq = (rptr[0] << 8) + rptr[1];
248     rptr += 2;
249     if (seq != state->seqno) {
250 #if !DEFLATE_DEBUG
251         if (state->debug)
252 #endif
253             printf("z_decompress%d: bad seq # %d, expected %d\n",
254                    state->unit, seq, state->seqno);
255         return DECOMP_ERROR;
256     }
257     ++state->seqno;
258
259     /*
260      * Set up to call inflate.
261      */
262     wptr = mo;
263     state->strm.next_in = rptr;
264     state->strm.avail_in = mi + inlen - rptr;
265     rlen = state->strm.avail_in + PPP_HDRLEN + DEFLATE_OVHD;
266     state->strm.next_out = wptr;
267     state->strm.avail_out = state->mru + 2;
268
269     r = inflate(&state->strm, Z_PACKET_FLUSH);
270     if (r != Z_OK) {
271 #if !DEFLATE_DEBUG
272         if (state->debug)
273 #endif
274             printf("z_decompress%d: inflate returned %d (%s)\n",
275                    state->unit, r, (state->strm.msg? state->strm.msg: ""));
276         return DECOMP_FATALERROR;
277     }
278     olen = state->mru + 2 - state->strm.avail_out;
279     *outlenp = olen;
280
281     if ((wptr[0] & 1) != 0)
282         ++olen;                 /* for suppressed protocol high byte */
283     olen += 2;                  /* for address, control */
284
285 #if DEFLATE_DEBUG
286     if (olen > state->mru + PPP_HDRLEN)
287         printf("ppp_deflate%d: exceeded mru (%d > %d)\n",
288                state->unit, olen, state->mru + PPP_HDRLEN);
289 #endif
290
291     state->stats.unc_bytes += olen;
292     state->stats.unc_packets++;
293     state->stats.comp_bytes += rlen;
294     state->stats.comp_packets++;
295
296     return DECOMP_OK;
297 }
298
299 /*
300  * Incompressible data has arrived - add it to the history.
301  */
302 static void
303 z_incomp(arg, mi, mlen)
304     void *arg;
305     u_char *mi;
306     int mlen;
307 {
308     struct deflate_state *state = (struct deflate_state *) arg;
309     u_char *rptr;
310     int rlen, proto, r;
311
312     /*
313      * Check that the protocol is one we handle.
314      */
315     rptr = mi;
316     proto = rptr[0];
317     if ((proto & 1) == 0)
318         proto = (proto << 8) + rptr[1];
319     if (proto > 0x3fff || proto == 0xfd || proto == 0xfb)
320         return;
321
322     ++state->seqno;
323
324     if (rptr[0] == 0)
325         ++rptr;
326     rlen = mi + mlen - rptr;
327     state->strm.next_in = rptr;
328     state->strm.avail_in = rlen;
329     r = inflateIncomp(&state->strm);
330     if (r != Z_OK) {
331         /* gak! */
332 #if !DEFLATE_DEBUG
333         if (state->debug)
334 #endif
335             printf("z_incomp%d: inflateIncomp returned %d (%s)\n",
336                    state->unit, r, (state->strm.msg? state->strm.msg: ""));
337         return;
338     }
339
340     /*
341      * Update stats.
342      */
343     if (proto <= 0xff)
344         ++rlen;
345     rlen += 2;
346     state->stats.inc_bytes += rlen;
347     state->stats.inc_packets++;
348     state->stats.unc_bytes += rlen;
349     state->stats.unc_packets++;
350 }
351
352 #endif /* DO_DEFLATE */