xref: /OK3568_Linux_fs/kernel/drivers/net/ppp/ppp_deflate.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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