1 /*
2 * ==FILEVERSION 980319==
3 *
4 * ppp_deflate.c - interface the zlib procedures for Deflate compression
5 * and decompression (as used by gzip) to the PPP code.
6 * This version is for use with Linux kernel 1.3.X.
7 *
8 * Copyright (c) 1994 The Australian National University.
9 * All rights reserved.
10 *
11 * Permission to use, copy, modify, and distribute this software and its
12 * documentation is hereby granted, provided that the above copyright
13 * notice appears in all copies. This software is provided without any
14 * warranty, express or implied. The Australian National University
15 * makes no representations about the suitability of this software for
16 * any purpose.
17 *
18 * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
19 * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
20 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
21 * THE AUSTRALIAN NATIONAL UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY
22 * OF SUCH DAMAGE.
23 *
24 * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
25 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
26 * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
27 * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
28 * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
29 * OR MODIFICATIONS.
30 *
31 * From: deflate.c,v 1.1 1996/01/18 03:17:48 paulus Exp
32 */
33
34 #include <linux/module.h>
35 #include <linux/slab.h>
36 #include <linux/vmalloc.h>
37 #include <linux/init.h>
38
39 #include <linux/ppp_defs.h>
40 #include <linux/ppp-comp.h>
41
42 #include <linux/zlib.h>
43
44 /*
45 * State for a Deflate (de)compressor.
46 */
47 struct ppp_deflate_state {
48 int seqno;
49 int w_size;
50 int unit;
51 int mru;
52 int debug;
53 z_stream strm;
54 struct compstat stats;
55 };
56
57 #define DEFLATE_OVHD 2 /* Deflate overhead/packet */
58
59 static void *z_comp_alloc __P((unsigned char *options, int opt_len));
60 static void *z_decomp_alloc __P((unsigned char *options, int opt_len));
61 static void z_comp_free __P((void *state));
62 static void z_decomp_free __P((void *state));
63 static int z_comp_init __P((void *state, unsigned char *options,
64 int opt_len,
65 int unit, int hdrlen, int debug));
66 static int z_decomp_init __P((void *state, unsigned char *options,
67 int opt_len,
68 int unit, int hdrlen, int mru, int debug));
69 static int z_compress __P((void *state, unsigned char *rptr,
70 unsigned char *obuf,
71 int isize, int osize));
72 static void z_incomp __P((void *state, unsigned char *ibuf, int icnt));
73 static int z_decompress __P((void *state, unsigned char *ibuf,
74 int isize, unsigned char *obuf, int osize));
75 static void z_comp_reset __P((void *state));
76 static void z_decomp_reset __P((void *state));
77 static void z_comp_stats __P((void *state, struct compstat *stats));
78
79 static void
z_comp_free(arg)80 z_comp_free(arg)
81 void *arg;
82 {
83 struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg;
84
85 if (state) {
86 zlib_deflateEnd(&state->strm);
87 if (state->strm.workspace)
88 vfree(state->strm.workspace);
89 kfree(state);
90 MOD_DEC_USE_COUNT;
91 }
92 }
93
94 /*
95 * Allocate space for a compressor.
96 */
97 static void *
z_comp_alloc(options,opt_len)98 z_comp_alloc(options, opt_len)
99 unsigned char *options;
100 int opt_len;
101 {
102 struct ppp_deflate_state *state;
103 int w_size;
104
105 if (opt_len != CILEN_DEFLATE
106 || (options[0] != CI_DEFLATE && options[0] != CI_DEFLATE_DRAFT)
107 || options[1] != CILEN_DEFLATE
108 || DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL
109 || options[3] != DEFLATE_CHK_SEQUENCE)
110 return NULL;
111 w_size = DEFLATE_SIZE(options[2]);
112 if (w_size < DEFLATE_MIN_SIZE || w_size > DEFLATE_MAX_SIZE)
113 return NULL;
114
115 state = (struct ppp_deflate_state *) kmalloc(sizeof(*state),
116 GFP_KERNEL);
117 if (state == NULL)
118 return NULL;
119
120 MOD_INC_USE_COUNT;
121 memset (state, 0, sizeof (struct ppp_deflate_state));
122 state->strm.next_in = NULL;
123 state->w_size = w_size;
124 state->strm.workspace = vmalloc(zlib_deflate_workspacesize());
125 if (state->strm.workspace == NULL)
126 goto out_free;
127
128 if (zlib_deflateInit2(&state->strm, Z_DEFAULT_COMPRESSION,
129 DEFLATE_METHOD_VAL, -w_size, 8, Z_DEFAULT_STRATEGY)
130 != Z_OK)
131 goto out_free;
132 return (void *) state;
133
134 out_free:
135 z_comp_free(state);
136 return NULL;
137 }
138
139 static int
z_comp_init(arg,options,opt_len,unit,hdrlen,debug)140 z_comp_init(arg, options, opt_len, unit, hdrlen, debug)
141 void *arg;
142 unsigned char *options;
143 int opt_len, unit, hdrlen, debug;
144 {
145 struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg;
146
147 if (opt_len < CILEN_DEFLATE
148 || (options[0] != CI_DEFLATE && options[0] != CI_DEFLATE_DRAFT)
149 || options[1] != CILEN_DEFLATE
150 || DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL
151 || DEFLATE_SIZE(options[2]) != state->w_size
152 || options[3] != DEFLATE_CHK_SEQUENCE)
153 return 0;
154
155 state->seqno = 0;
156 state->unit = unit;
157 state->debug = debug;
158
159 zlib_deflateReset(&state->strm);
160
161 return 1;
162 }
163
164 static void
z_comp_reset(arg)165 z_comp_reset(arg)
166 void *arg;
167 {
168 struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg;
169
170 state->seqno = 0;
171 zlib_deflateReset(&state->strm);
172 }
173
174 int
z_compress(arg,rptr,obuf,isize,osize)175 z_compress(arg, rptr, obuf, isize, osize)
176 void *arg;
177 unsigned char *rptr; /* uncompressed packet (in) */
178 unsigned char *obuf; /* compressed packet (out) */
179 int isize, osize;
180 {
181 struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg;
182 int r, proto, off, olen, oavail;
183 unsigned char *wptr;
184
185 /*
186 * Check that the protocol is in the range we handle.
187 */
188 proto = PPP_PROTOCOL(rptr);
189 if (proto > 0x3fff || proto == 0xfd || proto == 0xfb)
190 return 0;
191
192 /* Don't generate compressed packets which are larger than
193 the uncompressed packet. */
194 if (osize > isize)
195 osize = isize;
196
197 wptr = obuf;
198
199 /*
200 * Copy over the PPP header and store the 2-byte sequence number.
201 */
202 wptr[0] = PPP_ADDRESS(rptr);
203 wptr[1] = PPP_CONTROL(rptr);
204 wptr[2] = PPP_COMP >> 8;
205 wptr[3] = PPP_COMP;
206 wptr += PPP_HDRLEN;
207 wptr[0] = state->seqno >> 8;
208 wptr[1] = state->seqno;
209 wptr += DEFLATE_OVHD;
210 olen = PPP_HDRLEN + DEFLATE_OVHD;
211 state->strm.next_out = wptr;
212 state->strm.avail_out = oavail = osize - olen;
213 ++state->seqno;
214
215 off = (proto > 0xff) ? 2 : 3; /* skip 1st proto byte if 0 */
216 rptr += off;
217 state->strm.next_in = rptr;
218 state->strm.avail_in = (isize - off);
219
220 for (;;) {
221 r = zlib_deflate(&state->strm, Z_PACKET_FLUSH);
222 if (r != Z_OK) {
223 if (state->debug)
224 printk(KERN_ERR
225 "z_compress: deflate returned %d\n", r);
226 break;
227 }
228 if (state->strm.avail_out == 0) {
229 olen += oavail;
230 state->strm.next_out = NULL;
231 state->strm.avail_out = oavail = 1000000;
232 } else {
233 break; /* all done */
234 }
235 }
236 olen += oavail - state->strm.avail_out;
237
238 /*
239 * See if we managed to reduce the size of the packet.
240 */
241 if (olen < isize) {
242 state->stats.comp_bytes += olen;
243 state->stats.comp_packets++;
244 } else {
245 state->stats.inc_bytes += isize;
246 state->stats.inc_packets++;
247 olen = 0;
248 }
249 state->stats.unc_bytes += isize;
250 state->stats.unc_packets++;
251
252 return olen;
253 }
254
255 static void
z_comp_stats(arg,stats)256 z_comp_stats(arg, stats)
257 void *arg;
258 struct compstat *stats;
259 {
260 struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg;
261
262 *stats = state->stats;
263 }
264
265 static void
z_decomp_free(arg)266 z_decomp_free(arg)
267 void *arg;
268 {
269 struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg;
270
271 if (state) {
272 zlib_inflateEnd(&state->strm);
273 if (state->strm.workspace)
274 kfree(state->strm.workspace);
275 kfree(state);
276 MOD_DEC_USE_COUNT;
277 }
278 }
279
280 /*
281 * Allocate space for a decompressor.
282 */
283 static void *
z_decomp_alloc(options,opt_len)284 z_decomp_alloc(options, opt_len)
285 unsigned char *options;
286 int opt_len;
287 {
288 struct ppp_deflate_state *state;
289 int w_size;
290
291 if (opt_len != CILEN_DEFLATE
292 || (options[0] != CI_DEFLATE && options[0] != CI_DEFLATE_DRAFT)
293 || options[1] != CILEN_DEFLATE
294 || DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL
295 || options[3] != DEFLATE_CHK_SEQUENCE)
296 return NULL;
297 w_size = DEFLATE_SIZE(options[2]);
298 if (w_size < DEFLATE_MIN_SIZE || w_size > DEFLATE_MAX_SIZE)
299 return NULL;
300
301 state = (struct ppp_deflate_state *) kmalloc(sizeof(*state), GFP_KERNEL);
302 if (state == NULL)
303 return NULL;
304
305 MOD_INC_USE_COUNT;
306 memset (state, 0, sizeof (struct ppp_deflate_state));
307 state->w_size = w_size;
308 state->strm.next_out = NULL;
309 state->strm.workspace = kmalloc(zlib_inflate_workspacesize(),
310 GFP_KERNEL);
311 if (state->strm.workspace == NULL)
312 goto out_free;
313
314 if (zlib_inflateInit2(&state->strm, -w_size) != Z_OK)
315 goto out_free;
316 return (void *) state;
317
318 out_free:
319 z_decomp_free(state);
320 return NULL;
321 }
322
323 static int
z_decomp_init(arg,options,opt_len,unit,hdrlen,mru,debug)324 z_decomp_init(arg, options, opt_len, unit, hdrlen, mru, debug)
325 void *arg;
326 unsigned char *options;
327 int opt_len, unit, hdrlen, mru, debug;
328 {
329 struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg;
330
331 if (opt_len < CILEN_DEFLATE
332 || (options[0] != CI_DEFLATE && options[0] != CI_DEFLATE_DRAFT)
333 || options[1] != CILEN_DEFLATE
334 || DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL
335 || DEFLATE_SIZE(options[2]) != state->w_size
336 || options[3] != DEFLATE_CHK_SEQUENCE)
337 return 0;
338
339 state->seqno = 0;
340 state->unit = unit;
341 state->debug = debug;
342 state->mru = mru;
343
344 zlib_inflateReset(&state->strm);
345
346 return 1;
347 }
348
349 static void
z_decomp_reset(arg)350 z_decomp_reset(arg)
351 void *arg;
352 {
353 struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg;
354
355 state->seqno = 0;
356 zlib_inflateReset(&state->strm);
357 }
358
359 /*
360 * Decompress a Deflate-compressed packet.
361 *
362 * Because of patent problems, we return DECOMP_ERROR for errors
363 * found by inspecting the input data and for system problems, but
364 * DECOMP_FATALERROR for any errors which could possibly be said to
365 * be being detected "after" decompression. For DECOMP_ERROR,
366 * we can issue a CCP reset-request; for DECOMP_FATALERROR, we may be
367 * infringing a patent of Motorola's if we do, so we take CCP down
368 * instead.
369 *
370 * Given that the frame has the correct sequence number and a good FCS,
371 * errors such as invalid codes in the input most likely indicate a
372 * bug, so we return DECOMP_FATALERROR for them in order to turn off
373 * compression, even though they are detected by inspecting the input.
374 */
375 int
z_decompress(arg,ibuf,isize,obuf,osize)376 z_decompress(arg, ibuf, isize, obuf, osize)
377 void *arg;
378 unsigned char *ibuf;
379 int isize;
380 unsigned char *obuf;
381 int osize;
382 {
383 struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg;
384 int olen, seq, r;
385 int decode_proto, overflow;
386 unsigned char overflow_buf[1];
387
388 if (isize <= PPP_HDRLEN + DEFLATE_OVHD) {
389 if (state->debug)
390 printk(KERN_DEBUG "z_decompress%d: short pkt (%d)\n",
391 state->unit, isize);
392 return DECOMP_ERROR;
393 }
394
395 /* Check the sequence number. */
396 seq = (ibuf[PPP_HDRLEN] << 8) + ibuf[PPP_HDRLEN+1];
397 if (seq != (state->seqno & 0xffff)) {
398 if (state->debug)
399 printk(KERN_DEBUG "z_decompress%d: bad seq # %d, expected %d\n",
400 state->unit, seq, state->seqno & 0xffff);
401 return DECOMP_ERROR;
402 }
403 ++state->seqno;
404
405 /*
406 * Fill in the first part of the PPP header. The protocol field
407 * comes from the decompressed data.
408 */
409 obuf[0] = PPP_ADDRESS(ibuf);
410 obuf[1] = PPP_CONTROL(ibuf);
411 obuf[2] = 0;
412
413 /*
414 * Set up to call inflate. We set avail_out to 1 initially so we can
415 * look at the first byte of the output and decide whether we have
416 * a 1-byte or 2-byte protocol field.
417 */
418 state->strm.next_in = ibuf + PPP_HDRLEN + DEFLATE_OVHD;
419 state->strm.avail_in = isize - (PPP_HDRLEN + DEFLATE_OVHD);
420 state->strm.next_out = obuf + 3;
421 state->strm.avail_out = 1;
422 decode_proto = 1;
423 overflow = 0;
424
425 /*
426 * Call inflate, supplying more input or output as needed.
427 */
428 for (;;) {
429 r = zlib_inflate(&state->strm, Z_PACKET_FLUSH);
430 if (r != Z_OK) {
431 if (state->debug)
432 printk(KERN_DEBUG "z_decompress%d: inflate returned %d (%s)\n",
433 state->unit, r, (state->strm.msg? state->strm.msg: ""));
434 return DECOMP_FATALERROR;
435 }
436 if (state->strm.avail_out != 0)
437 break; /* all done */
438 if (decode_proto) {
439 state->strm.avail_out = osize - PPP_HDRLEN;
440 if ((obuf[3] & 1) == 0) {
441 /* 2-byte protocol field */
442 obuf[2] = obuf[3];
443 --state->strm.next_out;
444 ++state->strm.avail_out;
445 }
446 decode_proto = 0;
447 } else if (!overflow) {
448 /*
449 * We've filled up the output buffer; the only way to
450 * find out whether inflate has any more characters
451 * left is to give it another byte of output space.
452 */
453 state->strm.next_out = overflow_buf;
454 state->strm.avail_out = 1;
455 overflow = 1;
456 } else {
457 if (state->debug)
458 printk(KERN_DEBUG "z_decompress%d: ran out of mru\n",
459 state->unit);
460 return DECOMP_FATALERROR;
461 }
462 }
463
464 if (decode_proto) {
465 if (state->debug)
466 printk(KERN_DEBUG "z_decompress%d: didn't get proto\n",
467 state->unit);
468 return DECOMP_ERROR;
469 }
470
471 olen = osize + overflow - state->strm.avail_out;
472 state->stats.unc_bytes += olen;
473 state->stats.unc_packets++;
474 state->stats.comp_bytes += isize;
475 state->stats.comp_packets++;
476
477 return olen;
478 }
479
480 /*
481 * Incompressible data has arrived - add it to the history.
482 */
483 static void
z_incomp(arg,ibuf,icnt)484 z_incomp(arg, ibuf, icnt)
485 void *arg;
486 unsigned char *ibuf;
487 int icnt;
488 {
489 struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg;
490 int proto, r;
491
492 /*
493 * Check that the protocol is one we handle.
494 */
495 proto = PPP_PROTOCOL(ibuf);
496 if (proto > 0x3fff || proto == 0xfd || proto == 0xfb)
497 return;
498
499 ++state->seqno;
500
501 /*
502 * We start at the either the 1st or 2nd byte of the protocol field,
503 * depending on whether the protocol value is compressible.
504 */
505 state->strm.next_in = ibuf + 3;
506 state->strm.avail_in = icnt - 3;
507 if (proto > 0xff) {
508 --state->strm.next_in;
509 ++state->strm.avail_in;
510 }
511
512 r = zlib_inflateIncomp(&state->strm);
513 if (r != Z_OK) {
514 /* gak! */
515 if (state->debug) {
516 printk(KERN_DEBUG "z_incomp%d: inflateIncomp returned %d (%s)\n",
517 state->unit, r, (state->strm.msg? state->strm.msg: ""));
518 }
519 return;
520 }
521
522 /*
523 * Update stats.
524 */
525 state->stats.inc_bytes += icnt;
526 state->stats.inc_packets++;
527 state->stats.unc_bytes += icnt;
528 state->stats.unc_packets++;
529 }
530
531 /*************************************************************
532 * Module interface table
533 *************************************************************/
534
535 /* These are in ppp_generic.c */
536 extern int ppp_register_compressor (struct compressor *cp);
537 extern void ppp_unregister_compressor (struct compressor *cp);
538
539 /*
540 * Procedures exported to if_ppp.c.
541 */
542 struct compressor ppp_deflate = {
543 CI_DEFLATE, /* compress_proto */
544 z_comp_alloc, /* comp_alloc */
545 z_comp_free, /* comp_free */
546 z_comp_init, /* comp_init */
547 z_comp_reset, /* comp_reset */
548 z_compress, /* compress */
549 z_comp_stats, /* comp_stat */
550 z_decomp_alloc, /* decomp_alloc */
551 z_decomp_free, /* decomp_free */
552 z_decomp_init, /* decomp_init */
553 z_decomp_reset, /* decomp_reset */
554 z_decompress, /* decompress */
555 z_incomp, /* incomp */
556 z_comp_stats, /* decomp_stat */
557 };
558
559 struct compressor ppp_deflate_draft = {
560 CI_DEFLATE_DRAFT, /* compress_proto */
561 z_comp_alloc, /* comp_alloc */
562 z_comp_free, /* comp_free */
563 z_comp_init, /* comp_init */
564 z_comp_reset, /* comp_reset */
565 z_compress, /* compress */
566 z_comp_stats, /* comp_stat */
567 z_decomp_alloc, /* decomp_alloc */
568 z_decomp_free, /* decomp_free */
569 z_decomp_init, /* decomp_init */
570 z_decomp_reset, /* decomp_reset */
571 z_decompress, /* decompress */
572 z_incomp, /* incomp */
573 z_comp_stats, /* decomp_stat */
574 };
575
deflate_init(void)576 int __init deflate_init(void)
577 {
578 int answer = ppp_register_compressor(&ppp_deflate);
579 if (answer == 0)
580 printk(KERN_INFO
581 "PPP Deflate Compression module registered\n");
582 ppp_register_compressor(&ppp_deflate_draft);
583 return answer;
584 }
585
deflate_cleanup(void)586 void __exit deflate_cleanup(void)
587 {
588 ppp_unregister_compressor(&ppp_deflate);
589 ppp_unregister_compressor(&ppp_deflate_draft);
590 }
591
592 module_init(deflate_init);
593 module_exit(deflate_cleanup);
594 MODULE_LICENSE("Dual BSD/GPL");
595