1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * ppp_deflate.c - interface the zlib procedures for Deflate compression
4*4882a593Smuzhiyun * and decompression (as used by gzip) to the PPP code.
5*4882a593Smuzhiyun *
6*4882a593Smuzhiyun * Copyright 1994-1998 Paul Mackerras.
7*4882a593Smuzhiyun */
8*4882a593Smuzhiyun
9*4882a593Smuzhiyun #include <linux/module.h>
10*4882a593Smuzhiyun #include <linux/slab.h>
11*4882a593Smuzhiyun #include <linux/vmalloc.h>
12*4882a593Smuzhiyun #include <linux/init.h>
13*4882a593Smuzhiyun #include <linux/string.h>
14*4882a593Smuzhiyun
15*4882a593Smuzhiyun #include <linux/ppp_defs.h>
16*4882a593Smuzhiyun #include <linux/ppp-comp.h>
17*4882a593Smuzhiyun
18*4882a593Smuzhiyun #include <linux/zlib.h>
19*4882a593Smuzhiyun #include <asm/unaligned.h>
20*4882a593Smuzhiyun
21*4882a593Smuzhiyun /*
22*4882a593Smuzhiyun * State for a Deflate (de)compressor.
23*4882a593Smuzhiyun */
24*4882a593Smuzhiyun struct ppp_deflate_state {
25*4882a593Smuzhiyun int seqno;
26*4882a593Smuzhiyun int w_size;
27*4882a593Smuzhiyun int unit;
28*4882a593Smuzhiyun int mru;
29*4882a593Smuzhiyun int debug;
30*4882a593Smuzhiyun z_stream strm;
31*4882a593Smuzhiyun struct compstat stats;
32*4882a593Smuzhiyun };
33*4882a593Smuzhiyun
34*4882a593Smuzhiyun #define DEFLATE_OVHD 2 /* Deflate overhead/packet */
35*4882a593Smuzhiyun
36*4882a593Smuzhiyun static void *z_comp_alloc(unsigned char *options, int opt_len);
37*4882a593Smuzhiyun static void *z_decomp_alloc(unsigned char *options, int opt_len);
38*4882a593Smuzhiyun static void z_comp_free(void *state);
39*4882a593Smuzhiyun static void z_decomp_free(void *state);
40*4882a593Smuzhiyun static int z_comp_init(void *state, unsigned char *options,
41*4882a593Smuzhiyun int opt_len,
42*4882a593Smuzhiyun int unit, int hdrlen, int debug);
43*4882a593Smuzhiyun static int z_decomp_init(void *state, unsigned char *options,
44*4882a593Smuzhiyun int opt_len,
45*4882a593Smuzhiyun int unit, int hdrlen, int mru, int debug);
46*4882a593Smuzhiyun static int z_compress(void *state, unsigned char *rptr,
47*4882a593Smuzhiyun unsigned char *obuf,
48*4882a593Smuzhiyun int isize, int osize);
49*4882a593Smuzhiyun static void z_incomp(void *state, unsigned char *ibuf, int icnt);
50*4882a593Smuzhiyun static int z_decompress(void *state, unsigned char *ibuf,
51*4882a593Smuzhiyun int isize, unsigned char *obuf, int osize);
52*4882a593Smuzhiyun static void z_comp_reset(void *state);
53*4882a593Smuzhiyun static void z_decomp_reset(void *state);
54*4882a593Smuzhiyun static void z_comp_stats(void *state, struct compstat *stats);
55*4882a593Smuzhiyun
56*4882a593Smuzhiyun /**
57*4882a593Smuzhiyun * z_comp_free - free the memory used by a compressor
58*4882a593Smuzhiyun * @arg: pointer to the private state for the compressor.
59*4882a593Smuzhiyun */
z_comp_free(void * arg)60*4882a593Smuzhiyun static void z_comp_free(void *arg)
61*4882a593Smuzhiyun {
62*4882a593Smuzhiyun struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg;
63*4882a593Smuzhiyun
64*4882a593Smuzhiyun if (state) {
65*4882a593Smuzhiyun zlib_deflateEnd(&state->strm);
66*4882a593Smuzhiyun vfree(state->strm.workspace);
67*4882a593Smuzhiyun kfree(state);
68*4882a593Smuzhiyun }
69*4882a593Smuzhiyun }
70*4882a593Smuzhiyun
71*4882a593Smuzhiyun /**
72*4882a593Smuzhiyun * z_comp_alloc - allocate space for a compressor.
73*4882a593Smuzhiyun * @options: pointer to CCP option data
74*4882a593Smuzhiyun * @opt_len: length of the CCP option at @options.
75*4882a593Smuzhiyun *
76*4882a593Smuzhiyun * The @options pointer points to the a buffer containing the
77*4882a593Smuzhiyun * CCP option data for the compression being negotiated. It is
78*4882a593Smuzhiyun * formatted according to RFC1979, and describes the window
79*4882a593Smuzhiyun * size that the peer is requesting that we use in compressing
80*4882a593Smuzhiyun * data to be sent to it.
81*4882a593Smuzhiyun *
82*4882a593Smuzhiyun * Returns the pointer to the private state for the compressor,
83*4882a593Smuzhiyun * or NULL if we could not allocate enough memory.
84*4882a593Smuzhiyun */
z_comp_alloc(unsigned char * options,int opt_len)85*4882a593Smuzhiyun static void *z_comp_alloc(unsigned char *options, int opt_len)
86*4882a593Smuzhiyun {
87*4882a593Smuzhiyun struct ppp_deflate_state *state;
88*4882a593Smuzhiyun int w_size;
89*4882a593Smuzhiyun
90*4882a593Smuzhiyun if (opt_len != CILEN_DEFLATE ||
91*4882a593Smuzhiyun (options[0] != CI_DEFLATE && options[0] != CI_DEFLATE_DRAFT) ||
92*4882a593Smuzhiyun options[1] != CILEN_DEFLATE ||
93*4882a593Smuzhiyun DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL ||
94*4882a593Smuzhiyun options[3] != DEFLATE_CHK_SEQUENCE)
95*4882a593Smuzhiyun return NULL;
96*4882a593Smuzhiyun w_size = DEFLATE_SIZE(options[2]);
97*4882a593Smuzhiyun if (w_size < DEFLATE_MIN_SIZE || w_size > DEFLATE_MAX_SIZE)
98*4882a593Smuzhiyun return NULL;
99*4882a593Smuzhiyun
100*4882a593Smuzhiyun state = kzalloc(sizeof(*state),
101*4882a593Smuzhiyun GFP_KERNEL);
102*4882a593Smuzhiyun if (state == NULL)
103*4882a593Smuzhiyun return NULL;
104*4882a593Smuzhiyun
105*4882a593Smuzhiyun state->strm.next_in = NULL;
106*4882a593Smuzhiyun state->w_size = w_size;
107*4882a593Smuzhiyun state->strm.workspace = vmalloc(zlib_deflate_workspacesize(-w_size, 8));
108*4882a593Smuzhiyun if (state->strm.workspace == NULL)
109*4882a593Smuzhiyun goto out_free;
110*4882a593Smuzhiyun
111*4882a593Smuzhiyun if (zlib_deflateInit2(&state->strm, Z_DEFAULT_COMPRESSION,
112*4882a593Smuzhiyun DEFLATE_METHOD_VAL, -w_size, 8, Z_DEFAULT_STRATEGY)
113*4882a593Smuzhiyun != Z_OK)
114*4882a593Smuzhiyun goto out_free;
115*4882a593Smuzhiyun return (void *) state;
116*4882a593Smuzhiyun
117*4882a593Smuzhiyun out_free:
118*4882a593Smuzhiyun z_comp_free(state);
119*4882a593Smuzhiyun return NULL;
120*4882a593Smuzhiyun }
121*4882a593Smuzhiyun
122*4882a593Smuzhiyun /**
123*4882a593Smuzhiyun * z_comp_init - initialize a previously-allocated compressor.
124*4882a593Smuzhiyun * @arg: pointer to the private state for the compressor
125*4882a593Smuzhiyun * @options: pointer to the CCP option data describing the
126*4882a593Smuzhiyun * compression that was negotiated with the peer
127*4882a593Smuzhiyun * @opt_len: length of the CCP option data at @options
128*4882a593Smuzhiyun * @unit: PPP unit number for diagnostic messages
129*4882a593Smuzhiyun * @hdrlen: ignored (present for backwards compatibility)
130*4882a593Smuzhiyun * @debug: debug flag; if non-zero, debug messages are printed.
131*4882a593Smuzhiyun *
132*4882a593Smuzhiyun * The CCP options described by @options must match the options
133*4882a593Smuzhiyun * specified when the compressor was allocated. The compressor
134*4882a593Smuzhiyun * history is reset. Returns 0 for failure (CCP options don't
135*4882a593Smuzhiyun * match) or 1 for success.
136*4882a593Smuzhiyun */
z_comp_init(void * arg,unsigned char * options,int opt_len,int unit,int hdrlen,int debug)137*4882a593Smuzhiyun static int z_comp_init(void *arg, unsigned char *options, int opt_len,
138*4882a593Smuzhiyun int unit, int hdrlen, int debug)
139*4882a593Smuzhiyun {
140*4882a593Smuzhiyun struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg;
141*4882a593Smuzhiyun
142*4882a593Smuzhiyun if (opt_len < CILEN_DEFLATE ||
143*4882a593Smuzhiyun (options[0] != CI_DEFLATE && options[0] != CI_DEFLATE_DRAFT) ||
144*4882a593Smuzhiyun options[1] != CILEN_DEFLATE ||
145*4882a593Smuzhiyun DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL ||
146*4882a593Smuzhiyun DEFLATE_SIZE(options[2]) != state->w_size ||
147*4882a593Smuzhiyun options[3] != DEFLATE_CHK_SEQUENCE)
148*4882a593Smuzhiyun return 0;
149*4882a593Smuzhiyun
150*4882a593Smuzhiyun state->seqno = 0;
151*4882a593Smuzhiyun state->unit = unit;
152*4882a593Smuzhiyun state->debug = debug;
153*4882a593Smuzhiyun
154*4882a593Smuzhiyun zlib_deflateReset(&state->strm);
155*4882a593Smuzhiyun
156*4882a593Smuzhiyun return 1;
157*4882a593Smuzhiyun }
158*4882a593Smuzhiyun
159*4882a593Smuzhiyun /**
160*4882a593Smuzhiyun * z_comp_reset - reset a previously-allocated compressor.
161*4882a593Smuzhiyun * @arg: pointer to private state for the compressor.
162*4882a593Smuzhiyun *
163*4882a593Smuzhiyun * This clears the history for the compressor and makes it
164*4882a593Smuzhiyun * ready to start emitting a new compressed stream.
165*4882a593Smuzhiyun */
z_comp_reset(void * arg)166*4882a593Smuzhiyun static void z_comp_reset(void *arg)
167*4882a593Smuzhiyun {
168*4882a593Smuzhiyun struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg;
169*4882a593Smuzhiyun
170*4882a593Smuzhiyun state->seqno = 0;
171*4882a593Smuzhiyun zlib_deflateReset(&state->strm);
172*4882a593Smuzhiyun }
173*4882a593Smuzhiyun
174*4882a593Smuzhiyun /**
175*4882a593Smuzhiyun * z_compress - compress a PPP packet with Deflate compression.
176*4882a593Smuzhiyun * @arg: pointer to private state for the compressor
177*4882a593Smuzhiyun * @rptr: uncompressed packet (input)
178*4882a593Smuzhiyun * @obuf: compressed packet (output)
179*4882a593Smuzhiyun * @isize: size of uncompressed packet
180*4882a593Smuzhiyun * @osize: space available at @obuf
181*4882a593Smuzhiyun *
182*4882a593Smuzhiyun * Returns the length of the compressed packet, or 0 if the
183*4882a593Smuzhiyun * packet is incompressible.
184*4882a593Smuzhiyun */
z_compress(void * arg,unsigned char * rptr,unsigned char * obuf,int isize,int osize)185*4882a593Smuzhiyun static int z_compress(void *arg, unsigned char *rptr, unsigned char *obuf,
186*4882a593Smuzhiyun int isize, int osize)
187*4882a593Smuzhiyun {
188*4882a593Smuzhiyun struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg;
189*4882a593Smuzhiyun int r, proto, off, olen, oavail;
190*4882a593Smuzhiyun unsigned char *wptr;
191*4882a593Smuzhiyun
192*4882a593Smuzhiyun /*
193*4882a593Smuzhiyun * Check that the protocol is in the range we handle.
194*4882a593Smuzhiyun */
195*4882a593Smuzhiyun proto = PPP_PROTOCOL(rptr);
196*4882a593Smuzhiyun if (proto > 0x3fff || proto == 0xfd || proto == 0xfb)
197*4882a593Smuzhiyun return 0;
198*4882a593Smuzhiyun
199*4882a593Smuzhiyun /* Don't generate compressed packets which are larger than
200*4882a593Smuzhiyun the uncompressed packet. */
201*4882a593Smuzhiyun if (osize > isize)
202*4882a593Smuzhiyun osize = isize;
203*4882a593Smuzhiyun
204*4882a593Smuzhiyun wptr = obuf;
205*4882a593Smuzhiyun
206*4882a593Smuzhiyun /*
207*4882a593Smuzhiyun * Copy over the PPP header and store the 2-byte sequence number.
208*4882a593Smuzhiyun */
209*4882a593Smuzhiyun wptr[0] = PPP_ADDRESS(rptr);
210*4882a593Smuzhiyun wptr[1] = PPP_CONTROL(rptr);
211*4882a593Smuzhiyun put_unaligned_be16(PPP_COMP, wptr + 2);
212*4882a593Smuzhiyun wptr += PPP_HDRLEN;
213*4882a593Smuzhiyun put_unaligned_be16(state->seqno, wptr);
214*4882a593Smuzhiyun wptr += DEFLATE_OVHD;
215*4882a593Smuzhiyun olen = PPP_HDRLEN + DEFLATE_OVHD;
216*4882a593Smuzhiyun state->strm.next_out = wptr;
217*4882a593Smuzhiyun state->strm.avail_out = oavail = osize - olen;
218*4882a593Smuzhiyun ++state->seqno;
219*4882a593Smuzhiyun
220*4882a593Smuzhiyun off = (proto > 0xff) ? 2 : 3; /* skip 1st proto byte if 0 */
221*4882a593Smuzhiyun rptr += off;
222*4882a593Smuzhiyun state->strm.next_in = rptr;
223*4882a593Smuzhiyun state->strm.avail_in = (isize - off);
224*4882a593Smuzhiyun
225*4882a593Smuzhiyun for (;;) {
226*4882a593Smuzhiyun r = zlib_deflate(&state->strm, Z_PACKET_FLUSH);
227*4882a593Smuzhiyun if (r != Z_OK) {
228*4882a593Smuzhiyun if (state->debug)
229*4882a593Smuzhiyun printk(KERN_ERR
230*4882a593Smuzhiyun "z_compress: deflate returned %d\n", r);
231*4882a593Smuzhiyun break;
232*4882a593Smuzhiyun }
233*4882a593Smuzhiyun if (state->strm.avail_out == 0) {
234*4882a593Smuzhiyun olen += oavail;
235*4882a593Smuzhiyun state->strm.next_out = NULL;
236*4882a593Smuzhiyun state->strm.avail_out = oavail = 1000000;
237*4882a593Smuzhiyun } else {
238*4882a593Smuzhiyun break; /* all done */
239*4882a593Smuzhiyun }
240*4882a593Smuzhiyun }
241*4882a593Smuzhiyun olen += oavail - state->strm.avail_out;
242*4882a593Smuzhiyun
243*4882a593Smuzhiyun /*
244*4882a593Smuzhiyun * See if we managed to reduce the size of the packet.
245*4882a593Smuzhiyun */
246*4882a593Smuzhiyun if (olen < isize && olen <= osize) {
247*4882a593Smuzhiyun state->stats.comp_bytes += olen;
248*4882a593Smuzhiyun state->stats.comp_packets++;
249*4882a593Smuzhiyun } else {
250*4882a593Smuzhiyun state->stats.inc_bytes += isize;
251*4882a593Smuzhiyun state->stats.inc_packets++;
252*4882a593Smuzhiyun olen = 0;
253*4882a593Smuzhiyun }
254*4882a593Smuzhiyun state->stats.unc_bytes += isize;
255*4882a593Smuzhiyun state->stats.unc_packets++;
256*4882a593Smuzhiyun
257*4882a593Smuzhiyun return olen;
258*4882a593Smuzhiyun }
259*4882a593Smuzhiyun
260*4882a593Smuzhiyun /**
261*4882a593Smuzhiyun * z_comp_stats - return compression statistics for a compressor
262*4882a593Smuzhiyun * or decompressor.
263*4882a593Smuzhiyun * @arg: pointer to private space for the (de)compressor
264*4882a593Smuzhiyun * @stats: pointer to a struct compstat to receive the result.
265*4882a593Smuzhiyun */
z_comp_stats(void * arg,struct compstat * stats)266*4882a593Smuzhiyun static void z_comp_stats(void *arg, struct compstat *stats)
267*4882a593Smuzhiyun {
268*4882a593Smuzhiyun struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg;
269*4882a593Smuzhiyun
270*4882a593Smuzhiyun *stats = state->stats;
271*4882a593Smuzhiyun }
272*4882a593Smuzhiyun
273*4882a593Smuzhiyun /**
274*4882a593Smuzhiyun * z_decomp_free - Free the memory used by a decompressor.
275*4882a593Smuzhiyun * @arg: pointer to private space for the decompressor.
276*4882a593Smuzhiyun */
z_decomp_free(void * arg)277*4882a593Smuzhiyun static void z_decomp_free(void *arg)
278*4882a593Smuzhiyun {
279*4882a593Smuzhiyun struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg;
280*4882a593Smuzhiyun
281*4882a593Smuzhiyun if (state) {
282*4882a593Smuzhiyun zlib_inflateEnd(&state->strm);
283*4882a593Smuzhiyun vfree(state->strm.workspace);
284*4882a593Smuzhiyun kfree(state);
285*4882a593Smuzhiyun }
286*4882a593Smuzhiyun }
287*4882a593Smuzhiyun
288*4882a593Smuzhiyun /**
289*4882a593Smuzhiyun * z_decomp_alloc - allocate space for a decompressor.
290*4882a593Smuzhiyun * @options: pointer to CCP option data
291*4882a593Smuzhiyun * @opt_len: length of the CCP option at @options.
292*4882a593Smuzhiyun *
293*4882a593Smuzhiyun * The @options pointer points to the a buffer containing the
294*4882a593Smuzhiyun * CCP option data for the compression being negotiated. It is
295*4882a593Smuzhiyun * formatted according to RFC1979, and describes the window
296*4882a593Smuzhiyun * size that we are requesting the peer to use in compressing
297*4882a593Smuzhiyun * data to be sent to us.
298*4882a593Smuzhiyun *
299*4882a593Smuzhiyun * Returns the pointer to the private state for the decompressor,
300*4882a593Smuzhiyun * or NULL if we could not allocate enough memory.
301*4882a593Smuzhiyun */
z_decomp_alloc(unsigned char * options,int opt_len)302*4882a593Smuzhiyun static void *z_decomp_alloc(unsigned char *options, int opt_len)
303*4882a593Smuzhiyun {
304*4882a593Smuzhiyun struct ppp_deflate_state *state;
305*4882a593Smuzhiyun int w_size;
306*4882a593Smuzhiyun
307*4882a593Smuzhiyun if (opt_len != CILEN_DEFLATE ||
308*4882a593Smuzhiyun (options[0] != CI_DEFLATE && options[0] != CI_DEFLATE_DRAFT) ||
309*4882a593Smuzhiyun options[1] != CILEN_DEFLATE ||
310*4882a593Smuzhiyun DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL ||
311*4882a593Smuzhiyun options[3] != DEFLATE_CHK_SEQUENCE)
312*4882a593Smuzhiyun return NULL;
313*4882a593Smuzhiyun w_size = DEFLATE_SIZE(options[2]);
314*4882a593Smuzhiyun if (w_size < DEFLATE_MIN_SIZE || w_size > DEFLATE_MAX_SIZE)
315*4882a593Smuzhiyun return NULL;
316*4882a593Smuzhiyun
317*4882a593Smuzhiyun state = kzalloc(sizeof(*state), GFP_KERNEL);
318*4882a593Smuzhiyun if (state == NULL)
319*4882a593Smuzhiyun return NULL;
320*4882a593Smuzhiyun
321*4882a593Smuzhiyun state->w_size = w_size;
322*4882a593Smuzhiyun state->strm.next_out = NULL;
323*4882a593Smuzhiyun state->strm.workspace = vmalloc(zlib_inflate_workspacesize());
324*4882a593Smuzhiyun if (state->strm.workspace == NULL)
325*4882a593Smuzhiyun goto out_free;
326*4882a593Smuzhiyun
327*4882a593Smuzhiyun if (zlib_inflateInit2(&state->strm, -w_size) != Z_OK)
328*4882a593Smuzhiyun goto out_free;
329*4882a593Smuzhiyun return (void *) state;
330*4882a593Smuzhiyun
331*4882a593Smuzhiyun out_free:
332*4882a593Smuzhiyun z_decomp_free(state);
333*4882a593Smuzhiyun return NULL;
334*4882a593Smuzhiyun }
335*4882a593Smuzhiyun
336*4882a593Smuzhiyun /**
337*4882a593Smuzhiyun * z_decomp_init - initialize a previously-allocated decompressor.
338*4882a593Smuzhiyun * @arg: pointer to the private state for the decompressor
339*4882a593Smuzhiyun * @options: pointer to the CCP option data describing the
340*4882a593Smuzhiyun * compression that was negotiated with the peer
341*4882a593Smuzhiyun * @opt_len: length of the CCP option data at @options
342*4882a593Smuzhiyun * @unit: PPP unit number for diagnostic messages
343*4882a593Smuzhiyun * @hdrlen: ignored (present for backwards compatibility)
344*4882a593Smuzhiyun * @mru: maximum length of decompressed packets
345*4882a593Smuzhiyun * @debug: debug flag; if non-zero, debug messages are printed.
346*4882a593Smuzhiyun *
347*4882a593Smuzhiyun * The CCP options described by @options must match the options
348*4882a593Smuzhiyun * specified when the decompressor was allocated. The decompressor
349*4882a593Smuzhiyun * history is reset. Returns 0 for failure (CCP options don't
350*4882a593Smuzhiyun * match) or 1 for success.
351*4882a593Smuzhiyun */
z_decomp_init(void * arg,unsigned char * options,int opt_len,int unit,int hdrlen,int mru,int debug)352*4882a593Smuzhiyun static int z_decomp_init(void *arg, unsigned char *options, int opt_len,
353*4882a593Smuzhiyun int unit, int hdrlen, int mru, int debug)
354*4882a593Smuzhiyun {
355*4882a593Smuzhiyun struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg;
356*4882a593Smuzhiyun
357*4882a593Smuzhiyun if (opt_len < CILEN_DEFLATE ||
358*4882a593Smuzhiyun (options[0] != CI_DEFLATE && options[0] != CI_DEFLATE_DRAFT) ||
359*4882a593Smuzhiyun options[1] != CILEN_DEFLATE ||
360*4882a593Smuzhiyun DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL ||
361*4882a593Smuzhiyun DEFLATE_SIZE(options[2]) != state->w_size ||
362*4882a593Smuzhiyun options[3] != DEFLATE_CHK_SEQUENCE)
363*4882a593Smuzhiyun return 0;
364*4882a593Smuzhiyun
365*4882a593Smuzhiyun state->seqno = 0;
366*4882a593Smuzhiyun state->unit = unit;
367*4882a593Smuzhiyun state->debug = debug;
368*4882a593Smuzhiyun state->mru = mru;
369*4882a593Smuzhiyun
370*4882a593Smuzhiyun zlib_inflateReset(&state->strm);
371*4882a593Smuzhiyun
372*4882a593Smuzhiyun return 1;
373*4882a593Smuzhiyun }
374*4882a593Smuzhiyun
375*4882a593Smuzhiyun /**
376*4882a593Smuzhiyun * z_decomp_reset - reset a previously-allocated decompressor.
377*4882a593Smuzhiyun * @arg: pointer to private state for the decompressor.
378*4882a593Smuzhiyun *
379*4882a593Smuzhiyun * This clears the history for the decompressor and makes it
380*4882a593Smuzhiyun * ready to receive a new compressed stream.
381*4882a593Smuzhiyun */
z_decomp_reset(void * arg)382*4882a593Smuzhiyun static void z_decomp_reset(void *arg)
383*4882a593Smuzhiyun {
384*4882a593Smuzhiyun struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg;
385*4882a593Smuzhiyun
386*4882a593Smuzhiyun state->seqno = 0;
387*4882a593Smuzhiyun zlib_inflateReset(&state->strm);
388*4882a593Smuzhiyun }
389*4882a593Smuzhiyun
390*4882a593Smuzhiyun /**
391*4882a593Smuzhiyun * z_decompress - decompress a Deflate-compressed packet.
392*4882a593Smuzhiyun * @arg: pointer to private state for the decompressor
393*4882a593Smuzhiyun * @ibuf: pointer to input (compressed) packet data
394*4882a593Smuzhiyun * @isize: length of input packet
395*4882a593Smuzhiyun * @obuf: pointer to space for output (decompressed) packet
396*4882a593Smuzhiyun * @osize: amount of space available at @obuf
397*4882a593Smuzhiyun *
398*4882a593Smuzhiyun * Because of patent problems, we return DECOMP_ERROR for errors
399*4882a593Smuzhiyun * found by inspecting the input data and for system problems, but
400*4882a593Smuzhiyun * DECOMP_FATALERROR for any errors which could possibly be said to
401*4882a593Smuzhiyun * be being detected "after" decompression. For DECOMP_ERROR,
402*4882a593Smuzhiyun * we can issue a CCP reset-request; for DECOMP_FATALERROR, we may be
403*4882a593Smuzhiyun * infringing a patent of Motorola's if we do, so we take CCP down
404*4882a593Smuzhiyun * instead.
405*4882a593Smuzhiyun *
406*4882a593Smuzhiyun * Given that the frame has the correct sequence number and a good FCS,
407*4882a593Smuzhiyun * errors such as invalid codes in the input most likely indicate a
408*4882a593Smuzhiyun * bug, so we return DECOMP_FATALERROR for them in order to turn off
409*4882a593Smuzhiyun * compression, even though they are detected by inspecting the input.
410*4882a593Smuzhiyun */
z_decompress(void * arg,unsigned char * ibuf,int isize,unsigned char * obuf,int osize)411*4882a593Smuzhiyun static int z_decompress(void *arg, unsigned char *ibuf, int isize,
412*4882a593Smuzhiyun unsigned char *obuf, int osize)
413*4882a593Smuzhiyun {
414*4882a593Smuzhiyun struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg;
415*4882a593Smuzhiyun int olen, seq, r;
416*4882a593Smuzhiyun int decode_proto, overflow;
417*4882a593Smuzhiyun unsigned char overflow_buf[1];
418*4882a593Smuzhiyun
419*4882a593Smuzhiyun if (isize <= PPP_HDRLEN + DEFLATE_OVHD) {
420*4882a593Smuzhiyun if (state->debug)
421*4882a593Smuzhiyun printk(KERN_DEBUG "z_decompress%d: short pkt (%d)\n",
422*4882a593Smuzhiyun state->unit, isize);
423*4882a593Smuzhiyun return DECOMP_ERROR;
424*4882a593Smuzhiyun }
425*4882a593Smuzhiyun
426*4882a593Smuzhiyun /* Check the sequence number. */
427*4882a593Smuzhiyun seq = get_unaligned_be16(ibuf + PPP_HDRLEN);
428*4882a593Smuzhiyun if (seq != (state->seqno & 0xffff)) {
429*4882a593Smuzhiyun if (state->debug)
430*4882a593Smuzhiyun printk(KERN_DEBUG "z_decompress%d: bad seq # %d, expected %d\n",
431*4882a593Smuzhiyun state->unit, seq, state->seqno & 0xffff);
432*4882a593Smuzhiyun return DECOMP_ERROR;
433*4882a593Smuzhiyun }
434*4882a593Smuzhiyun ++state->seqno;
435*4882a593Smuzhiyun
436*4882a593Smuzhiyun /*
437*4882a593Smuzhiyun * Fill in the first part of the PPP header. The protocol field
438*4882a593Smuzhiyun * comes from the decompressed data.
439*4882a593Smuzhiyun */
440*4882a593Smuzhiyun obuf[0] = PPP_ADDRESS(ibuf);
441*4882a593Smuzhiyun obuf[1] = PPP_CONTROL(ibuf);
442*4882a593Smuzhiyun obuf[2] = 0;
443*4882a593Smuzhiyun
444*4882a593Smuzhiyun /*
445*4882a593Smuzhiyun * Set up to call inflate. We set avail_out to 1 initially so we can
446*4882a593Smuzhiyun * look at the first byte of the output and decide whether we have
447*4882a593Smuzhiyun * a 1-byte or 2-byte protocol field.
448*4882a593Smuzhiyun */
449*4882a593Smuzhiyun state->strm.next_in = ibuf + PPP_HDRLEN + DEFLATE_OVHD;
450*4882a593Smuzhiyun state->strm.avail_in = isize - (PPP_HDRLEN + DEFLATE_OVHD);
451*4882a593Smuzhiyun state->strm.next_out = obuf + 3;
452*4882a593Smuzhiyun state->strm.avail_out = 1;
453*4882a593Smuzhiyun decode_proto = 1;
454*4882a593Smuzhiyun overflow = 0;
455*4882a593Smuzhiyun
456*4882a593Smuzhiyun /*
457*4882a593Smuzhiyun * Call inflate, supplying more input or output as needed.
458*4882a593Smuzhiyun */
459*4882a593Smuzhiyun for (;;) {
460*4882a593Smuzhiyun r = zlib_inflate(&state->strm, Z_PACKET_FLUSH);
461*4882a593Smuzhiyun if (r != Z_OK) {
462*4882a593Smuzhiyun if (state->debug)
463*4882a593Smuzhiyun printk(KERN_DEBUG "z_decompress%d: inflate returned %d (%s)\n",
464*4882a593Smuzhiyun state->unit, r, (state->strm.msg? state->strm.msg: ""));
465*4882a593Smuzhiyun return DECOMP_FATALERROR;
466*4882a593Smuzhiyun }
467*4882a593Smuzhiyun if (state->strm.avail_out != 0)
468*4882a593Smuzhiyun break; /* all done */
469*4882a593Smuzhiyun if (decode_proto) {
470*4882a593Smuzhiyun state->strm.avail_out = osize - PPP_HDRLEN;
471*4882a593Smuzhiyun if ((obuf[3] & 1) == 0) {
472*4882a593Smuzhiyun /* 2-byte protocol field */
473*4882a593Smuzhiyun obuf[2] = obuf[3];
474*4882a593Smuzhiyun --state->strm.next_out;
475*4882a593Smuzhiyun ++state->strm.avail_out;
476*4882a593Smuzhiyun }
477*4882a593Smuzhiyun decode_proto = 0;
478*4882a593Smuzhiyun } else if (!overflow) {
479*4882a593Smuzhiyun /*
480*4882a593Smuzhiyun * We've filled up the output buffer; the only way to
481*4882a593Smuzhiyun * find out whether inflate has any more characters
482*4882a593Smuzhiyun * left is to give it another byte of output space.
483*4882a593Smuzhiyun */
484*4882a593Smuzhiyun state->strm.next_out = overflow_buf;
485*4882a593Smuzhiyun state->strm.avail_out = 1;
486*4882a593Smuzhiyun overflow = 1;
487*4882a593Smuzhiyun } else {
488*4882a593Smuzhiyun if (state->debug)
489*4882a593Smuzhiyun printk(KERN_DEBUG "z_decompress%d: ran out of mru\n",
490*4882a593Smuzhiyun state->unit);
491*4882a593Smuzhiyun return DECOMP_FATALERROR;
492*4882a593Smuzhiyun }
493*4882a593Smuzhiyun }
494*4882a593Smuzhiyun
495*4882a593Smuzhiyun if (decode_proto) {
496*4882a593Smuzhiyun if (state->debug)
497*4882a593Smuzhiyun printk(KERN_DEBUG "z_decompress%d: didn't get proto\n",
498*4882a593Smuzhiyun state->unit);
499*4882a593Smuzhiyun return DECOMP_ERROR;
500*4882a593Smuzhiyun }
501*4882a593Smuzhiyun
502*4882a593Smuzhiyun olen = osize + overflow - state->strm.avail_out;
503*4882a593Smuzhiyun state->stats.unc_bytes += olen;
504*4882a593Smuzhiyun state->stats.unc_packets++;
505*4882a593Smuzhiyun state->stats.comp_bytes += isize;
506*4882a593Smuzhiyun state->stats.comp_packets++;
507*4882a593Smuzhiyun
508*4882a593Smuzhiyun return olen;
509*4882a593Smuzhiyun }
510*4882a593Smuzhiyun
511*4882a593Smuzhiyun /**
512*4882a593Smuzhiyun * z_incomp - add incompressible input data to the history.
513*4882a593Smuzhiyun * @arg: pointer to private state for the decompressor
514*4882a593Smuzhiyun * @ibuf: pointer to input packet data
515*4882a593Smuzhiyun * @icnt: length of input data.
516*4882a593Smuzhiyun */
z_incomp(void * arg,unsigned char * ibuf,int icnt)517*4882a593Smuzhiyun static void z_incomp(void *arg, unsigned char *ibuf, int icnt)
518*4882a593Smuzhiyun {
519*4882a593Smuzhiyun struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg;
520*4882a593Smuzhiyun int proto, r;
521*4882a593Smuzhiyun
522*4882a593Smuzhiyun /*
523*4882a593Smuzhiyun * Check that the protocol is one we handle.
524*4882a593Smuzhiyun */
525*4882a593Smuzhiyun proto = PPP_PROTOCOL(ibuf);
526*4882a593Smuzhiyun if (proto > 0x3fff || proto == 0xfd || proto == 0xfb)
527*4882a593Smuzhiyun return;
528*4882a593Smuzhiyun
529*4882a593Smuzhiyun ++state->seqno;
530*4882a593Smuzhiyun
531*4882a593Smuzhiyun /*
532*4882a593Smuzhiyun * We start at the either the 1st or 2nd byte of the protocol field,
533*4882a593Smuzhiyun * depending on whether the protocol value is compressible.
534*4882a593Smuzhiyun */
535*4882a593Smuzhiyun state->strm.next_in = ibuf + 3;
536*4882a593Smuzhiyun state->strm.avail_in = icnt - 3;
537*4882a593Smuzhiyun if (proto > 0xff) {
538*4882a593Smuzhiyun --state->strm.next_in;
539*4882a593Smuzhiyun ++state->strm.avail_in;
540*4882a593Smuzhiyun }
541*4882a593Smuzhiyun
542*4882a593Smuzhiyun r = zlib_inflateIncomp(&state->strm);
543*4882a593Smuzhiyun if (r != Z_OK) {
544*4882a593Smuzhiyun /* gak! */
545*4882a593Smuzhiyun if (state->debug) {
546*4882a593Smuzhiyun printk(KERN_DEBUG "z_incomp%d: inflateIncomp returned %d (%s)\n",
547*4882a593Smuzhiyun state->unit, r, (state->strm.msg? state->strm.msg: ""));
548*4882a593Smuzhiyun }
549*4882a593Smuzhiyun return;
550*4882a593Smuzhiyun }
551*4882a593Smuzhiyun
552*4882a593Smuzhiyun /*
553*4882a593Smuzhiyun * Update stats.
554*4882a593Smuzhiyun */
555*4882a593Smuzhiyun state->stats.inc_bytes += icnt;
556*4882a593Smuzhiyun state->stats.inc_packets++;
557*4882a593Smuzhiyun state->stats.unc_bytes += icnt;
558*4882a593Smuzhiyun state->stats.unc_packets++;
559*4882a593Smuzhiyun }
560*4882a593Smuzhiyun
561*4882a593Smuzhiyun /*************************************************************
562*4882a593Smuzhiyun * Module interface table
563*4882a593Smuzhiyun *************************************************************/
564*4882a593Smuzhiyun
565*4882a593Smuzhiyun /* These are in ppp_generic.c */
566*4882a593Smuzhiyun extern int ppp_register_compressor (struct compressor *cp);
567*4882a593Smuzhiyun extern void ppp_unregister_compressor (struct compressor *cp);
568*4882a593Smuzhiyun
569*4882a593Smuzhiyun /*
570*4882a593Smuzhiyun * Procedures exported to if_ppp.c.
571*4882a593Smuzhiyun */
572*4882a593Smuzhiyun static struct compressor ppp_deflate = {
573*4882a593Smuzhiyun .compress_proto = CI_DEFLATE,
574*4882a593Smuzhiyun .comp_alloc = z_comp_alloc,
575*4882a593Smuzhiyun .comp_free = z_comp_free,
576*4882a593Smuzhiyun .comp_init = z_comp_init,
577*4882a593Smuzhiyun .comp_reset = z_comp_reset,
578*4882a593Smuzhiyun .compress = z_compress,
579*4882a593Smuzhiyun .comp_stat = z_comp_stats,
580*4882a593Smuzhiyun .decomp_alloc = z_decomp_alloc,
581*4882a593Smuzhiyun .decomp_free = z_decomp_free,
582*4882a593Smuzhiyun .decomp_init = z_decomp_init,
583*4882a593Smuzhiyun .decomp_reset = z_decomp_reset,
584*4882a593Smuzhiyun .decompress = z_decompress,
585*4882a593Smuzhiyun .incomp = z_incomp,
586*4882a593Smuzhiyun .decomp_stat = z_comp_stats,
587*4882a593Smuzhiyun .owner = THIS_MODULE
588*4882a593Smuzhiyun };
589*4882a593Smuzhiyun
590*4882a593Smuzhiyun static struct compressor ppp_deflate_draft = {
591*4882a593Smuzhiyun .compress_proto = CI_DEFLATE_DRAFT,
592*4882a593Smuzhiyun .comp_alloc = z_comp_alloc,
593*4882a593Smuzhiyun .comp_free = z_comp_free,
594*4882a593Smuzhiyun .comp_init = z_comp_init,
595*4882a593Smuzhiyun .comp_reset = z_comp_reset,
596*4882a593Smuzhiyun .compress = z_compress,
597*4882a593Smuzhiyun .comp_stat = z_comp_stats,
598*4882a593Smuzhiyun .decomp_alloc = z_decomp_alloc,
599*4882a593Smuzhiyun .decomp_free = z_decomp_free,
600*4882a593Smuzhiyun .decomp_init = z_decomp_init,
601*4882a593Smuzhiyun .decomp_reset = z_decomp_reset,
602*4882a593Smuzhiyun .decompress = z_decompress,
603*4882a593Smuzhiyun .incomp = z_incomp,
604*4882a593Smuzhiyun .decomp_stat = z_comp_stats,
605*4882a593Smuzhiyun .owner = THIS_MODULE
606*4882a593Smuzhiyun };
607*4882a593Smuzhiyun
deflate_init(void)608*4882a593Smuzhiyun static int __init deflate_init(void)
609*4882a593Smuzhiyun {
610*4882a593Smuzhiyun int rc;
611*4882a593Smuzhiyun
612*4882a593Smuzhiyun rc = ppp_register_compressor(&ppp_deflate);
613*4882a593Smuzhiyun if (rc)
614*4882a593Smuzhiyun return rc;
615*4882a593Smuzhiyun
616*4882a593Smuzhiyun rc = ppp_register_compressor(&ppp_deflate_draft);
617*4882a593Smuzhiyun if (rc) {
618*4882a593Smuzhiyun ppp_unregister_compressor(&ppp_deflate);
619*4882a593Smuzhiyun return rc;
620*4882a593Smuzhiyun }
621*4882a593Smuzhiyun
622*4882a593Smuzhiyun pr_info("PPP Deflate Compression module registered\n");
623*4882a593Smuzhiyun return 0;
624*4882a593Smuzhiyun }
625*4882a593Smuzhiyun
deflate_cleanup(void)626*4882a593Smuzhiyun static void __exit deflate_cleanup(void)
627*4882a593Smuzhiyun {
628*4882a593Smuzhiyun ppp_unregister_compressor(&ppp_deflate);
629*4882a593Smuzhiyun ppp_unregister_compressor(&ppp_deflate_draft);
630*4882a593Smuzhiyun }
631*4882a593Smuzhiyun
632*4882a593Smuzhiyun module_init(deflate_init);
633*4882a593Smuzhiyun module_exit(deflate_cleanup);
634*4882a593Smuzhiyun MODULE_LICENSE("Dual BSD/GPL");
635*4882a593Smuzhiyun MODULE_ALIAS("ppp-compress-" __stringify(CI_DEFLATE));
636*4882a593Smuzhiyun MODULE_ALIAS("ppp-compress-" __stringify(CI_DEFLATE_DRAFT));
637