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