0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/module.h>
0010 #include <linux/slab.h>
0011 #include <linux/vmalloc.h>
0012 #include <linux/init.h>
0013 #include <linux/string.h>
0014
0015 #include <linux/ppp_defs.h>
0016 #include <linux/ppp-comp.h>
0017
0018 #include <linux/zlib.h>
0019 #include <asm/unaligned.h>
0020
0021
0022
0023
0024 struct ppp_deflate_state {
0025 int seqno;
0026 int w_size;
0027 int unit;
0028 int mru;
0029 int debug;
0030 z_stream strm;
0031 struct compstat stats;
0032 };
0033
0034 #define DEFLATE_OVHD 2
0035
0036 static void *z_comp_alloc(unsigned char *options, int opt_len);
0037 static void *z_decomp_alloc(unsigned char *options, int opt_len);
0038 static void z_comp_free(void *state);
0039 static void z_decomp_free(void *state);
0040 static int z_comp_init(void *state, unsigned char *options,
0041 int opt_len,
0042 int unit, int hdrlen, int debug);
0043 static int z_decomp_init(void *state, unsigned char *options,
0044 int opt_len,
0045 int unit, int hdrlen, int mru, int debug);
0046 static int z_compress(void *state, unsigned char *rptr,
0047 unsigned char *obuf,
0048 int isize, int osize);
0049 static void z_incomp(void *state, unsigned char *ibuf, int icnt);
0050 static int z_decompress(void *state, unsigned char *ibuf,
0051 int isize, unsigned char *obuf, int osize);
0052 static void z_comp_reset(void *state);
0053 static void z_decomp_reset(void *state);
0054 static void z_comp_stats(void *state, struct compstat *stats);
0055
0056
0057
0058
0059
0060 static void z_comp_free(void *arg)
0061 {
0062 struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg;
0063
0064 if (state) {
0065 zlib_deflateEnd(&state->strm);
0066 vfree(state->strm.workspace);
0067 kfree(state);
0068 }
0069 }
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082
0083
0084
0085 static void *z_comp_alloc(unsigned char *options, int opt_len)
0086 {
0087 struct ppp_deflate_state *state;
0088 int w_size;
0089
0090 if (opt_len != CILEN_DEFLATE ||
0091 (options[0] != CI_DEFLATE && options[0] != CI_DEFLATE_DRAFT) ||
0092 options[1] != CILEN_DEFLATE ||
0093 DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL ||
0094 options[3] != DEFLATE_CHK_SEQUENCE)
0095 return NULL;
0096 w_size = DEFLATE_SIZE(options[2]);
0097 if (w_size < DEFLATE_MIN_SIZE || w_size > DEFLATE_MAX_SIZE)
0098 return NULL;
0099
0100 state = kzalloc(sizeof(*state),
0101 GFP_KERNEL);
0102 if (state == NULL)
0103 return NULL;
0104
0105 state->strm.next_in = NULL;
0106 state->w_size = w_size;
0107 state->strm.workspace = vmalloc(zlib_deflate_workspacesize(-w_size, 8));
0108 if (state->strm.workspace == NULL)
0109 goto out_free;
0110
0111 if (zlib_deflateInit2(&state->strm, Z_DEFAULT_COMPRESSION,
0112 DEFLATE_METHOD_VAL, -w_size, 8, Z_DEFAULT_STRATEGY)
0113 != Z_OK)
0114 goto out_free;
0115 return (void *) state;
0116
0117 out_free:
0118 z_comp_free(state);
0119 return NULL;
0120 }
0121
0122
0123
0124
0125
0126
0127
0128
0129
0130
0131
0132
0133
0134
0135
0136
0137 static int z_comp_init(void *arg, unsigned char *options, int opt_len,
0138 int unit, int hdrlen, int debug)
0139 {
0140 struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg;
0141
0142 if (opt_len < CILEN_DEFLATE ||
0143 (options[0] != CI_DEFLATE && options[0] != CI_DEFLATE_DRAFT) ||
0144 options[1] != CILEN_DEFLATE ||
0145 DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL ||
0146 DEFLATE_SIZE(options[2]) != state->w_size ||
0147 options[3] != DEFLATE_CHK_SEQUENCE)
0148 return 0;
0149
0150 state->seqno = 0;
0151 state->unit = unit;
0152 state->debug = debug;
0153
0154 zlib_deflateReset(&state->strm);
0155
0156 return 1;
0157 }
0158
0159
0160
0161
0162
0163
0164
0165
0166 static void z_comp_reset(void *arg)
0167 {
0168 struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg;
0169
0170 state->seqno = 0;
0171 zlib_deflateReset(&state->strm);
0172 }
0173
0174
0175
0176
0177
0178
0179
0180
0181
0182
0183
0184
0185 static int z_compress(void *arg, unsigned char *rptr, unsigned char *obuf,
0186 int isize, int osize)
0187 {
0188 struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg;
0189 int r, proto, off, olen, oavail;
0190 unsigned char *wptr;
0191
0192
0193
0194
0195 proto = PPP_PROTOCOL(rptr);
0196 if (proto > 0x3fff || proto == 0xfd || proto == 0xfb)
0197 return 0;
0198
0199
0200
0201 if (osize > isize)
0202 osize = isize;
0203
0204 wptr = obuf;
0205
0206
0207
0208
0209 wptr[0] = PPP_ADDRESS(rptr);
0210 wptr[1] = PPP_CONTROL(rptr);
0211 put_unaligned_be16(PPP_COMP, wptr + 2);
0212 wptr += PPP_HDRLEN;
0213 put_unaligned_be16(state->seqno, wptr);
0214 wptr += DEFLATE_OVHD;
0215 olen = PPP_HDRLEN + DEFLATE_OVHD;
0216 state->strm.next_out = wptr;
0217 state->strm.avail_out = oavail = osize - olen;
0218 ++state->seqno;
0219
0220 off = (proto > 0xff) ? 2 : 3;
0221 rptr += off;
0222 state->strm.next_in = rptr;
0223 state->strm.avail_in = (isize - off);
0224
0225 for (;;) {
0226 r = zlib_deflate(&state->strm, Z_PACKET_FLUSH);
0227 if (r != Z_OK) {
0228 if (state->debug)
0229 printk(KERN_ERR
0230 "z_compress: deflate returned %d\n", r);
0231 break;
0232 }
0233 if (state->strm.avail_out == 0) {
0234 olen += oavail;
0235 state->strm.next_out = NULL;
0236 state->strm.avail_out = oavail = 1000000;
0237 } else {
0238 break;
0239 }
0240 }
0241 olen += oavail - state->strm.avail_out;
0242
0243
0244
0245
0246 if (olen < isize && olen <= osize) {
0247 state->stats.comp_bytes += olen;
0248 state->stats.comp_packets++;
0249 } else {
0250 state->stats.inc_bytes += isize;
0251 state->stats.inc_packets++;
0252 olen = 0;
0253 }
0254 state->stats.unc_bytes += isize;
0255 state->stats.unc_packets++;
0256
0257 return olen;
0258 }
0259
0260
0261
0262
0263
0264
0265
0266 static void z_comp_stats(void *arg, struct compstat *stats)
0267 {
0268 struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg;
0269
0270 *stats = state->stats;
0271 }
0272
0273
0274
0275
0276
0277 static void z_decomp_free(void *arg)
0278 {
0279 struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg;
0280
0281 if (state) {
0282 vfree(state->strm.workspace);
0283 kfree(state);
0284 }
0285 }
0286
0287
0288
0289
0290
0291
0292
0293
0294
0295
0296
0297
0298
0299
0300
0301 static void *z_decomp_alloc(unsigned char *options, int opt_len)
0302 {
0303 struct ppp_deflate_state *state;
0304 int w_size;
0305
0306 if (opt_len != CILEN_DEFLATE ||
0307 (options[0] != CI_DEFLATE && options[0] != CI_DEFLATE_DRAFT) ||
0308 options[1] != CILEN_DEFLATE ||
0309 DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL ||
0310 options[3] != DEFLATE_CHK_SEQUENCE)
0311 return NULL;
0312 w_size = DEFLATE_SIZE(options[2]);
0313 if (w_size < DEFLATE_MIN_SIZE || w_size > DEFLATE_MAX_SIZE)
0314 return NULL;
0315
0316 state = kzalloc(sizeof(*state), GFP_KERNEL);
0317 if (state == NULL)
0318 return NULL;
0319
0320 state->w_size = w_size;
0321 state->strm.next_out = NULL;
0322 state->strm.workspace = vmalloc(zlib_inflate_workspacesize());
0323 if (state->strm.workspace == NULL)
0324 goto out_free;
0325
0326 if (zlib_inflateInit2(&state->strm, -w_size) != Z_OK)
0327 goto out_free;
0328 return (void *) state;
0329
0330 out_free:
0331 z_decomp_free(state);
0332 return NULL;
0333 }
0334
0335
0336
0337
0338
0339
0340
0341
0342
0343
0344
0345
0346
0347
0348
0349
0350
0351 static int z_decomp_init(void *arg, unsigned char *options, int opt_len,
0352 int unit, int hdrlen, int mru, int debug)
0353 {
0354 struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg;
0355
0356 if (opt_len < CILEN_DEFLATE ||
0357 (options[0] != CI_DEFLATE && options[0] != CI_DEFLATE_DRAFT) ||
0358 options[1] != CILEN_DEFLATE ||
0359 DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL ||
0360 DEFLATE_SIZE(options[2]) != state->w_size ||
0361 options[3] != DEFLATE_CHK_SEQUENCE)
0362 return 0;
0363
0364 state->seqno = 0;
0365 state->unit = unit;
0366 state->debug = debug;
0367 state->mru = mru;
0368
0369 zlib_inflateReset(&state->strm);
0370
0371 return 1;
0372 }
0373
0374
0375
0376
0377
0378
0379
0380
0381 static void z_decomp_reset(void *arg)
0382 {
0383 struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg;
0384
0385 state->seqno = 0;
0386 zlib_inflateReset(&state->strm);
0387 }
0388
0389
0390
0391
0392
0393
0394
0395
0396
0397
0398
0399
0400
0401
0402
0403
0404
0405
0406
0407
0408
0409
0410 static int z_decompress(void *arg, unsigned char *ibuf, int isize,
0411 unsigned char *obuf, int osize)
0412 {
0413 struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg;
0414 int olen, seq, r;
0415 int decode_proto, overflow;
0416 unsigned char overflow_buf[1];
0417
0418 if (isize <= PPP_HDRLEN + DEFLATE_OVHD) {
0419 if (state->debug)
0420 printk(KERN_DEBUG "z_decompress%d: short pkt (%d)\n",
0421 state->unit, isize);
0422 return DECOMP_ERROR;
0423 }
0424
0425
0426 seq = get_unaligned_be16(ibuf + PPP_HDRLEN);
0427 if (seq != (state->seqno & 0xffff)) {
0428 if (state->debug)
0429 printk(KERN_DEBUG "z_decompress%d: bad seq # %d, expected %d\n",
0430 state->unit, seq, state->seqno & 0xffff);
0431 return DECOMP_ERROR;
0432 }
0433 ++state->seqno;
0434
0435
0436
0437
0438
0439 obuf[0] = PPP_ADDRESS(ibuf);
0440 obuf[1] = PPP_CONTROL(ibuf);
0441 obuf[2] = 0;
0442
0443
0444
0445
0446
0447
0448 state->strm.next_in = ibuf + PPP_HDRLEN + DEFLATE_OVHD;
0449 state->strm.avail_in = isize - (PPP_HDRLEN + DEFLATE_OVHD);
0450 state->strm.next_out = obuf + 3;
0451 state->strm.avail_out = 1;
0452 decode_proto = 1;
0453 overflow = 0;
0454
0455
0456
0457
0458 for (;;) {
0459 r = zlib_inflate(&state->strm, Z_PACKET_FLUSH);
0460 if (r != Z_OK) {
0461 if (state->debug)
0462 printk(KERN_DEBUG "z_decompress%d: inflate returned %d (%s)\n",
0463 state->unit, r, (state->strm.msg? state->strm.msg: ""));
0464 return DECOMP_FATALERROR;
0465 }
0466 if (state->strm.avail_out != 0)
0467 break;
0468 if (decode_proto) {
0469 state->strm.avail_out = osize - PPP_HDRLEN;
0470 if ((obuf[3] & 1) == 0) {
0471
0472 obuf[2] = obuf[3];
0473 --state->strm.next_out;
0474 ++state->strm.avail_out;
0475 }
0476 decode_proto = 0;
0477 } else if (!overflow) {
0478
0479
0480
0481
0482
0483 state->strm.next_out = overflow_buf;
0484 state->strm.avail_out = 1;
0485 overflow = 1;
0486 } else {
0487 if (state->debug)
0488 printk(KERN_DEBUG "z_decompress%d: ran out of mru\n",
0489 state->unit);
0490 return DECOMP_FATALERROR;
0491 }
0492 }
0493
0494 if (decode_proto) {
0495 if (state->debug)
0496 printk(KERN_DEBUG "z_decompress%d: didn't get proto\n",
0497 state->unit);
0498 return DECOMP_ERROR;
0499 }
0500
0501 olen = osize + overflow - state->strm.avail_out;
0502 state->stats.unc_bytes += olen;
0503 state->stats.unc_packets++;
0504 state->stats.comp_bytes += isize;
0505 state->stats.comp_packets++;
0506
0507 return olen;
0508 }
0509
0510
0511
0512
0513
0514
0515
0516 static void z_incomp(void *arg, unsigned char *ibuf, int icnt)
0517 {
0518 struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg;
0519 int proto, r;
0520
0521
0522
0523
0524 proto = PPP_PROTOCOL(ibuf);
0525 if (proto > 0x3fff || proto == 0xfd || proto == 0xfb)
0526 return;
0527
0528 ++state->seqno;
0529
0530
0531
0532
0533
0534 state->strm.next_in = ibuf + 3;
0535 state->strm.avail_in = icnt - 3;
0536 if (proto > 0xff) {
0537 --state->strm.next_in;
0538 ++state->strm.avail_in;
0539 }
0540
0541 r = zlib_inflateIncomp(&state->strm);
0542 if (r != Z_OK) {
0543
0544 if (state->debug) {
0545 printk(KERN_DEBUG "z_incomp%d: inflateIncomp returned %d (%s)\n",
0546 state->unit, r, (state->strm.msg? state->strm.msg: ""));
0547 }
0548 return;
0549 }
0550
0551
0552
0553
0554 state->stats.inc_bytes += icnt;
0555 state->stats.inc_packets++;
0556 state->stats.unc_bytes += icnt;
0557 state->stats.unc_packets++;
0558 }
0559
0560
0561
0562
0563
0564
0565 extern int ppp_register_compressor (struct compressor *cp);
0566 extern void ppp_unregister_compressor (struct compressor *cp);
0567
0568
0569
0570
0571 static struct compressor ppp_deflate = {
0572 .compress_proto = CI_DEFLATE,
0573 .comp_alloc = z_comp_alloc,
0574 .comp_free = z_comp_free,
0575 .comp_init = z_comp_init,
0576 .comp_reset = z_comp_reset,
0577 .compress = z_compress,
0578 .comp_stat = z_comp_stats,
0579 .decomp_alloc = z_decomp_alloc,
0580 .decomp_free = z_decomp_free,
0581 .decomp_init = z_decomp_init,
0582 .decomp_reset = z_decomp_reset,
0583 .decompress = z_decompress,
0584 .incomp = z_incomp,
0585 .decomp_stat = z_comp_stats,
0586 .owner = THIS_MODULE
0587 };
0588
0589 static struct compressor ppp_deflate_draft = {
0590 .compress_proto = CI_DEFLATE_DRAFT,
0591 .comp_alloc = z_comp_alloc,
0592 .comp_free = z_comp_free,
0593 .comp_init = z_comp_init,
0594 .comp_reset = z_comp_reset,
0595 .compress = z_compress,
0596 .comp_stat = z_comp_stats,
0597 .decomp_alloc = z_decomp_alloc,
0598 .decomp_free = z_decomp_free,
0599 .decomp_init = z_decomp_init,
0600 .decomp_reset = z_decomp_reset,
0601 .decompress = z_decompress,
0602 .incomp = z_incomp,
0603 .decomp_stat = z_comp_stats,
0604 .owner = THIS_MODULE
0605 };
0606
0607 static int __init deflate_init(void)
0608 {
0609 int rc;
0610
0611 rc = ppp_register_compressor(&ppp_deflate);
0612 if (rc)
0613 return rc;
0614
0615 rc = ppp_register_compressor(&ppp_deflate_draft);
0616 if (rc) {
0617 ppp_unregister_compressor(&ppp_deflate);
0618 return rc;
0619 }
0620
0621 pr_info("PPP Deflate Compression module registered\n");
0622 return 0;
0623 }
0624
0625 static void __exit deflate_cleanup(void)
0626 {
0627 ppp_unregister_compressor(&ppp_deflate);
0628 ppp_unregister_compressor(&ppp_deflate_draft);
0629 }
0630
0631 module_init(deflate_init);
0632 module_exit(deflate_cleanup);
0633 MODULE_LICENSE("Dual BSD/GPL");
0634 MODULE_ALIAS("ppp-compress-" __stringify(CI_DEFLATE));
0635 MODULE_ALIAS("ppp-compress-" __stringify(CI_DEFLATE_DRAFT));