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