ppp-deflate.c revision 1.11 1 /* $NetBSD: ppp-deflate.c,v 1.11 2002/03/13 04:04:00 fvdl Exp $ */
2 /* Id: ppp-deflate.c,v 1.5 1997/03/04 03:33:28 paulus Exp */
3
4 /*
5 * ppp_deflate.c - interface the zlib procedures for Deflate compression
6 * and decompression (as used by gzip) to the PPP code.
7 * This version is for use with mbufs on BSD-derived systems.
8 *
9 * Copyright (c) 1994 The Australian National University.
10 * All rights reserved.
11 *
12 * Permission to use, copy, modify, and distribute this software and its
13 * documentation is hereby granted, provided that the above copyright
14 * notice appears in all copies. This software is provided without any
15 * warranty, express or implied. The Australian National University
16 * makes no representations about the suitability of this software for
17 * any purpose.
18 *
19 * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
20 * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
21 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
22 * THE AUSTRALIAN NATIONAL UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY
23 * OF SUCH DAMAGE.
24 *
25 * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
26 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
27 * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
28 * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
29 * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
30 * OR MODIFICATIONS.
31 */
32
33 #include <sys/cdefs.h>
34 __KERNEL_RCSID(0, "$NetBSD: ppp-deflate.c,v 1.11 2002/03/13 04:04:00 fvdl Exp $");
35
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/mbuf.h>
39 #include <net/ppp_defs.h>
40 #include <net/zlib.h>
41
42 #define PACKETPTR struct mbuf *
43 #include <net/ppp-comp.h>
44
45 #if DO_DEFLATE
46
47 #define DEFLATE_DEBUG 1
48
49 /*
50 * State for a Deflate (de)compressor.
51 */
52 struct deflate_state {
53 int seqno;
54 int w_size;
55 int unit;
56 int hdrlen;
57 int mru;
58 int debug;
59 z_stream strm;
60 struct compstat stats;
61 };
62
63 #define DEFLATE_OVHD 2 /* Deflate overhead/packet */
64
65 static void *zalloc __P((void *, u_int items, u_int size));
66 static void zfree __P((void *, void *ptr));
67 static void *z_comp_alloc __P((u_char *options, int opt_len));
68 static void *z_decomp_alloc __P((u_char *options, int opt_len));
69 static void z_comp_free __P((void *state));
70 static void z_decomp_free __P((void *state));
71 static int z_comp_init __P((void *state, u_char *options, int opt_len,
72 int unit, int hdrlen, int debug));
73 static int z_decomp_init __P((void *state, u_char *options, int opt_len,
74 int unit, int hdrlen, int mru, int debug));
75 static int z_compress __P((void *state, struct mbuf **mret,
76 struct mbuf *mp, int slen, int maxolen));
77 static void z_incomp __P((void *state, struct mbuf *dmsg));
78 static int z_decompress __P((void *state, struct mbuf *cmp,
79 struct mbuf **dmpp));
80 static void z_comp_reset __P((void *state));
81 static void z_decomp_reset __P((void *state));
82 static void z_comp_stats __P((void *state, struct compstat *stats));
83
84 /*
85 * Procedures exported to if_ppp.c.
86 */
87 struct compressor ppp_deflate = {
88 CI_DEFLATE, /* compress_proto */
89 z_comp_alloc, /* comp_alloc */
90 z_comp_free, /* comp_free */
91 z_comp_init, /* comp_init */
92 z_comp_reset, /* comp_reset */
93 z_compress, /* compress */
94 z_comp_stats, /* comp_stat */
95 z_decomp_alloc, /* decomp_alloc */
96 z_decomp_free, /* decomp_free */
97 z_decomp_init, /* decomp_init */
98 z_decomp_reset, /* decomp_reset */
99 z_decompress, /* decompress */
100 z_incomp, /* incomp */
101 z_comp_stats, /* decomp_stat */
102 };
103
104 struct compressor ppp_deflate_draft = {
105 CI_DEFLATE_DRAFT, /* compress_proto */
106 z_comp_alloc, /* comp_alloc */
107 z_comp_free, /* comp_free */
108 z_comp_init, /* comp_init */
109 z_comp_reset, /* comp_reset */
110 z_compress, /* compress */
111 z_comp_stats, /* comp_stat */
112 z_decomp_alloc, /* decomp_alloc */
113 z_decomp_free, /* decomp_free */
114 z_decomp_init, /* decomp_init */
115 z_decomp_reset, /* decomp_reset */
116 z_decompress, /* decompress */
117 z_incomp, /* incomp */
118 z_comp_stats, /* decomp_stat */
119 };
120 /*
121 * Space allocation and freeing routines for use by zlib routines.
122 */
123 void *
124 zalloc(notused, items, size)
125 void *notused;
126 u_int items, size;
127 {
128 void *ptr;
129
130 ptr = malloc(items * size, M_DEVBUF, M_NOWAIT);
131 return ptr;
132 }
133
134 void
135 zfree(notused, ptr)
136 void *notused;
137 void *ptr;
138 {
139 free(ptr, M_DEVBUF);
140 }
141
142 /*
143 * Allocate space for a compressor.
144 */
145 static void *
146 z_comp_alloc(options, opt_len)
147 u_char *options;
148 int opt_len;
149 {
150 struct deflate_state *state;
151 int w_size;
152
153 if (opt_len != CILEN_DEFLATE
154 || (options[0] != CI_DEFLATE && options[0] != CI_DEFLATE_DRAFT)
155 || options[1] != CILEN_DEFLATE
156 || DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL
157 || options[3] != DEFLATE_CHK_SEQUENCE)
158 return NULL;
159 w_size = DEFLATE_SIZE(options[2]);
160 if (w_size < DEFLATE_MIN_SIZE || w_size > DEFLATE_MAX_SIZE)
161 return NULL;
162
163 MALLOC(state, struct deflate_state *, sizeof(struct deflate_state),
164 M_DEVBUF, M_NOWAIT);
165 if (state == NULL)
166 return NULL;
167
168 state->strm.next_in = NULL;
169 state->strm.zalloc = zalloc;
170 state->strm.zfree = zfree;
171 if (deflateInit2(&state->strm, Z_DEFAULT_COMPRESSION, DEFLATE_METHOD_VAL,
172 -w_size, 8, Z_DEFAULT_STRATEGY) != Z_OK) {
173 FREE(state, M_DEVBUF);
174 return NULL;
175 }
176
177 state->w_size = w_size;
178 memset(&state->stats, 0, sizeof(state->stats));
179 return (void *) state;
180 }
181
182 static void
183 z_comp_free(arg)
184 void *arg;
185 {
186 struct deflate_state *state = (struct deflate_state *) arg;
187
188 deflateEnd(&state->strm);
189 FREE(state, M_DEVBUF);
190 }
191
192 static int
193 z_comp_init(arg, options, opt_len, unit, hdrlen, debug)
194 void *arg;
195 u_char *options;
196 int opt_len, unit, hdrlen, debug;
197 {
198 struct deflate_state *state = (struct deflate_state *) arg;
199
200 if (opt_len < CILEN_DEFLATE
201 || (options[0] != CI_DEFLATE && options[0] != CI_DEFLATE_DRAFT)
202 || options[1] != CILEN_DEFLATE
203 || DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL
204 || DEFLATE_SIZE(options[2]) != state->w_size
205 || options[3] != DEFLATE_CHK_SEQUENCE)
206 return 0;
207
208 state->seqno = 0;
209 state->unit = unit;
210 state->hdrlen = hdrlen;
211 state->debug = debug;
212
213 deflateReset(&state->strm);
214
215 return 1;
216 }
217
218 static void
219 z_comp_reset(arg)
220 void *arg;
221 {
222 struct deflate_state *state = (struct deflate_state *) arg;
223
224 state->seqno = 0;
225 deflateReset(&state->strm);
226 }
227
228 int
229 z_compress(arg, mret, mp, orig_len, maxolen)
230 void *arg;
231 struct mbuf **mret; /* compressed packet (out) */
232 struct mbuf *mp; /* uncompressed packet (in) */
233 int orig_len, maxolen;
234 {
235 struct deflate_state *state = (struct deflate_state *) arg;
236 u_char *rptr, *wptr;
237 int proto, olen, wspace, r, flush;
238 struct mbuf *m;
239
240 /*
241 * Check that the protocol is in the range we handle.
242 */
243 rptr = mtod(mp, u_char *);
244 proto = PPP_PROTOCOL(rptr);
245 if (proto > 0x3fff || proto == 0xfd || proto == 0xfb) {
246 *mret = NULL;
247 return orig_len;
248 }
249
250 /* Allocate one mbuf initially. */
251 if (maxolen > orig_len)
252 maxolen = orig_len;
253 MGET(m, M_DONTWAIT, MT_DATA);
254 *mret = m;
255 if (m != NULL) {
256 m->m_len = 0;
257 if (maxolen + state->hdrlen > MLEN)
258 MCLGET(m, M_DONTWAIT);
259 wspace = M_TRAILINGSPACE(m);
260 if (state->hdrlen + PPP_HDRLEN + 2 < wspace) {
261 m->m_data += state->hdrlen;
262 wspace -= state->hdrlen;
263 }
264 wptr = mtod(m, u_char *);
265
266 /*
267 * Copy over the PPP header and store the 2-byte sequence number.
268 */
269 wptr[0] = PPP_ADDRESS(rptr);
270 wptr[1] = PPP_CONTROL(rptr);
271 wptr[2] = PPP_COMP >> 8;
272 wptr[3] = PPP_COMP;
273 wptr += PPP_HDRLEN;
274 wptr[0] = state->seqno >> 8;
275 wptr[1] = state->seqno;
276 wptr += 2;
277 state->strm.next_out = wptr;
278 state->strm.avail_out = wspace - (PPP_HDRLEN + 2);
279 } else {
280 state->strm.next_out = NULL;
281 state->strm.avail_out = 1000000;
282 wptr = NULL;
283 wspace = 0;
284 }
285 ++state->seqno;
286
287 rptr += (proto > 0xff)? 2: 3; /* skip 1st proto byte if 0 */
288 state->strm.next_in = rptr;
289 state->strm.avail_in = mtod(mp, u_char *) + mp->m_len - rptr;
290 mp = mp->m_next;
291 flush = (mp == NULL)? Z_PACKET_FLUSH: Z_NO_FLUSH;
292 olen = 0;
293 for (;;) {
294 r = deflate(&state->strm, flush);
295 if (r != Z_OK) {
296 printf("z_compress: deflate returned %d (%s)\n",
297 r, (state->strm.msg? state->strm.msg: ""));
298 break;
299 }
300 if (flush != Z_NO_FLUSH && state->strm.avail_out != 0)
301 break; /* all done */
302 if (state->strm.avail_in == 0 && mp != NULL) {
303 state->strm.next_in = mtod(mp, u_char *);
304 state->strm.avail_in = mp->m_len;
305 mp = mp->m_next;
306 if (mp == NULL)
307 flush = Z_PACKET_FLUSH;
308 }
309 if (state->strm.avail_out == 0) {
310 if (m != NULL) {
311 m->m_len = wspace;
312 olen += wspace;
313 MGET(m->m_next, M_DONTWAIT, MT_DATA);
314 m = m->m_next;
315 if (m != NULL) {
316 m->m_len = 0;
317 if (maxolen - olen > MLEN)
318 MCLGET(m, M_DONTWAIT);
319 state->strm.next_out = mtod(m, u_char *);
320 state->strm.avail_out = wspace = M_TRAILINGSPACE(m);
321 }
322 }
323 if (m == NULL) {
324 state->strm.next_out = NULL;
325 state->strm.avail_out = 1000000;
326 }
327 }
328 }
329 if (m != NULL)
330 olen += (m->m_len = wspace - state->strm.avail_out);
331
332 /*
333 * See if we managed to reduce the size of the packet.
334 */
335 if (m != NULL && olen < orig_len) {
336 state->stats.comp_bytes += olen;
337 state->stats.comp_packets++;
338 } else {
339 if (*mret != NULL) {
340 m_freem(*mret);
341 *mret = NULL;
342 }
343 state->stats.inc_bytes += orig_len;
344 state->stats.inc_packets++;
345 olen = orig_len;
346 }
347 state->stats.unc_bytes += orig_len;
348 state->stats.unc_packets++;
349
350 return olen;
351 }
352
353 static void
354 z_comp_stats(arg, stats)
355 void *arg;
356 struct compstat *stats;
357 {
358 struct deflate_state *state = (struct deflate_state *) arg;
359 u_int out;
360
361 *stats = state->stats;
362 stats->ratio = stats->unc_bytes;
363 out = stats->comp_bytes + stats->inc_bytes;
364 if (stats->ratio <= 0x7ffffff)
365 stats->ratio <<= 8;
366 else
367 out >>= 8;
368 if (out != 0)
369 stats->ratio /= out;
370 }
371
372 /*
373 * Allocate space for a decompressor.
374 */
375 static void *
376 z_decomp_alloc(options, opt_len)
377 u_char *options;
378 int opt_len;
379 {
380 struct deflate_state *state;
381 int w_size;
382
383 if (opt_len != CILEN_DEFLATE
384 || (options[0] != CI_DEFLATE && options[0] != CI_DEFLATE_DRAFT)
385 || options[1] != CILEN_DEFLATE
386 || DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL
387 || options[3] != DEFLATE_CHK_SEQUENCE)
388 return NULL;
389 w_size = DEFLATE_SIZE(options[2]);
390 if (w_size < DEFLATE_MIN_SIZE || w_size > DEFLATE_MAX_SIZE)
391 return NULL;
392
393 MALLOC(state, struct deflate_state *, sizeof(struct deflate_state),
394 M_DEVBUF, M_NOWAIT);
395 if (state == NULL)
396 return NULL;
397
398 state->strm.next_out = NULL;
399 state->strm.zalloc = zalloc;
400 state->strm.zfree = zfree;
401 if (inflateInit2(&state->strm, -w_size) != Z_OK) {
402 FREE(state, M_DEVBUF);
403 return NULL;
404 }
405
406 state->w_size = w_size;
407 memset(&state->stats, 0, sizeof(state->stats));
408 return (void *) state;
409 }
410
411 static void
412 z_decomp_free(arg)
413 void *arg;
414 {
415 struct deflate_state *state = (struct deflate_state *) arg;
416
417 inflateEnd(&state->strm);
418 FREE(state, M_DEVBUF);
419 }
420
421 static int
422 z_decomp_init(arg, options, opt_len, unit, hdrlen, mru, debug)
423 void *arg;
424 u_char *options;
425 int opt_len, unit, hdrlen, mru, debug;
426 {
427 struct deflate_state *state = (struct deflate_state *) arg;
428
429 if (opt_len < CILEN_DEFLATE
430 || (options[0] != CI_DEFLATE && options[0] != CI_DEFLATE_DRAFT)
431 || options[1] != CILEN_DEFLATE
432 || DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL
433 || DEFLATE_SIZE(options[2]) != state->w_size
434 || options[3] != DEFLATE_CHK_SEQUENCE)
435 return 0;
436
437 state->seqno = 0;
438 state->unit = unit;
439 state->hdrlen = hdrlen;
440 state->debug = debug;
441 state->mru = mru;
442
443 inflateReset(&state->strm);
444
445 return 1;
446 }
447
448 static void
449 z_decomp_reset(arg)
450 void *arg;
451 {
452 struct deflate_state *state = (struct deflate_state *) arg;
453
454 state->seqno = 0;
455 inflateReset(&state->strm);
456 }
457
458 /*
459 * Decompress a Deflate-compressed packet.
460 *
461 * Because of patent problems, we return DECOMP_ERROR for errors
462 * found by inspecting the input data and for system problems, but
463 * DECOMP_FATALERROR for any errors which could possibly be said to
464 * be being detected "after" decompression. For DECOMP_ERROR,
465 * we can issue a CCP reset-request; for DECOMP_FATALERROR, we may be
466 * infringing a patent of Motorola's if we do, so we take CCP down
467 * instead.
468 *
469 * Given that the frame has the correct sequence number and a good FCS,
470 * errors such as invalid codes in the input most likely indicate a
471 * bug, so we return DECOMP_FATALERROR for them in order to turn off
472 * compression, even though they are detected by inspecting the input.
473 */
474 int
475 z_decompress(arg, mi, mop)
476 void *arg;
477 struct mbuf *mi, **mop;
478 {
479 struct deflate_state *state = (struct deflate_state *) arg;
480 struct mbuf *mo, *mo_head;
481 u_char *rptr, *wptr;
482 int rlen, olen, ospace;
483 int seq, i, flush, r, decode_proto;
484 u_char hdr[PPP_HDRLEN + DEFLATE_OVHD];
485
486 *mop = NULL;
487 rptr = mtod(mi, u_char *);
488 rlen = mi->m_len;
489 for (i = 0; i < PPP_HDRLEN + DEFLATE_OVHD; ++i) {
490 while (rlen <= 0) {
491 mi = mi->m_next;
492 if (mi == NULL)
493 return DECOMP_ERROR;
494 rptr = mtod(mi, u_char *);
495 rlen = mi->m_len;
496 }
497 hdr[i] = *rptr++;
498 --rlen;
499 }
500
501 /* Check the sequence number. */
502 seq = (hdr[PPP_HDRLEN] << 8) + hdr[PPP_HDRLEN+1];
503 if (seq != state->seqno) {
504 if (state->debug)
505 printf("z_decompress%d: bad seq # %d, expected %d\n",
506 state->unit, seq, state->seqno);
507 return DECOMP_ERROR;
508 }
509 ++state->seqno;
510
511 /* Allocate an output mbuf. */
512 MGETHDR(mo, M_DONTWAIT, MT_DATA);
513 if (mo == NULL)
514 return DECOMP_ERROR;
515 mo_head = mo;
516 mo->m_len = 0;
517 mo->m_next = NULL;
518 MCLGET(mo, M_DONTWAIT);
519 ospace = M_TRAILINGSPACE(mo);
520 if (state->hdrlen + PPP_HDRLEN < ospace) {
521 mo->m_data += state->hdrlen;
522 ospace -= state->hdrlen;
523 }
524
525 /*
526 * Fill in the first part of the PPP header. The protocol field
527 * comes from the decompressed data.
528 */
529 wptr = mtod(mo, u_char *);
530 wptr[0] = PPP_ADDRESS(hdr);
531 wptr[1] = PPP_CONTROL(hdr);
532 wptr[2] = 0;
533
534 /*
535 * Set up to call inflate. We set avail_out to 1 initially so we can
536 * look at the first byte of the output and decide whether we have
537 * a 1-byte or 2-byte protocol field.
538 */
539 state->strm.next_in = rptr;
540 state->strm.avail_in = rlen;
541 mi = mi->m_next;
542 flush = (mi == NULL)? Z_PACKET_FLUSH: Z_NO_FLUSH;
543 rlen += PPP_HDRLEN + DEFLATE_OVHD;
544 state->strm.next_out = wptr + 3;
545 state->strm.avail_out = 1;
546 decode_proto = 1;
547 olen = 0;
548
549 /*
550 * Call inflate, supplying more input or output as needed.
551 */
552 for (;;) {
553 r = inflate(&state->strm, flush);
554 if (r != Z_OK) {
555 #if !DEFLATE_DEBUG
556 if (state->debug)
557 #endif
558 printf("z_decompress%d: inflate returned %d (%s)\n",
559 state->unit, r, (state->strm.msg? state->strm.msg: ""));
560 m_freem(mo_head);
561 return DECOMP_FATALERROR;
562 }
563 if (flush != Z_NO_FLUSH && state->strm.avail_out != 0)
564 break; /* all done */
565 if (state->strm.avail_in == 0 && mi != NULL) {
566 state->strm.next_in = mtod(mi, u_char *);
567 state->strm.avail_in = mi->m_len;
568 rlen += mi->m_len;
569 mi = mi->m_next;
570 if (mi == NULL)
571 flush = Z_PACKET_FLUSH;
572 }
573 if (state->strm.avail_out == 0) {
574 if (decode_proto) {
575 state->strm.avail_out = ospace - PPP_HDRLEN;
576 if ((wptr[3] & 1) == 0) {
577 /* 2-byte protocol field */
578 wptr[2] = wptr[3];
579 --state->strm.next_out;
580 ++state->strm.avail_out;
581 --olen;
582 }
583 decode_proto = 0;
584 } else {
585 mo->m_len = ospace;
586 olen += ospace;
587 MGET(mo->m_next, M_DONTWAIT, MT_DATA);
588 mo = mo->m_next;
589 if (mo == NULL) {
590 m_freem(mo_head);
591 return DECOMP_ERROR;
592 }
593 MCLGET(mo, M_DONTWAIT);
594 state->strm.next_out = mtod(mo, u_char *);
595 state->strm.avail_out = ospace = M_TRAILINGSPACE(mo);
596 }
597 }
598 }
599 if (decode_proto) {
600 m_freem(mo_head);
601 return DECOMP_ERROR;
602 }
603 olen += (mo->m_len = ospace - state->strm.avail_out);
604 #if DEFLATE_DEBUG
605 if (olen > state->mru + PPP_HDRLEN)
606 printf("ppp_deflate%d: exceeded mru (%d > %d)\n",
607 state->unit, olen, state->mru + PPP_HDRLEN);
608 #endif
609
610 state->stats.unc_bytes += olen;
611 state->stats.unc_packets++;
612 state->stats.comp_bytes += rlen;
613 state->stats.comp_packets++;
614
615 *mop = mo_head;
616 return DECOMP_OK;
617 }
618
619 /*
620 * Incompressible data has arrived - add it to the history.
621 */
622 static void
623 z_incomp(arg, mi)
624 void *arg;
625 struct mbuf *mi;
626 {
627 struct deflate_state *state = (struct deflate_state *) arg;
628 u_char *rptr;
629 int rlen, proto, r;
630
631 /*
632 * Check that the protocol is one we handle.
633 */
634 rptr = mtod(mi, u_char *);
635 proto = PPP_PROTOCOL(rptr);
636 if (proto > 0x3fff || proto == 0xfd || proto == 0xfb)
637 return;
638
639 ++state->seqno;
640
641 /*
642 * Iterate through the mbufs, adding the characters in them
643 * to the decompressor's history. For the first mbuf, we start
644 * at the either the 1st or 2nd byte of the protocol field,
645 * depending on whether the protocol value is compressible.
646 */
647 rlen = mi->m_len;
648 state->strm.next_in = rptr + 3;
649 state->strm.avail_in = rlen - 3;
650 if (proto > 0xff) {
651 --state->strm.next_in;
652 ++state->strm.avail_in;
653 }
654 for (;;) {
655 r = inflateIncomp(&state->strm);
656 if (r != Z_OK) {
657 /* gak! */
658 #if !DEFLATE_DEBUG
659 if (state->debug)
660 #endif
661 printf("z_incomp%d: inflateIncomp returned %d (%s)\n",
662 state->unit, r, (state->strm.msg? state->strm.msg: ""));
663 return;
664 }
665 mi = mi->m_next;
666 if (mi == NULL)
667 break;
668 state->strm.next_in = mtod(mi, u_char *);
669 state->strm.avail_in = mi->m_len;
670 rlen += mi->m_len;
671 }
672
673 /*
674 * Update stats.
675 */
676 state->stats.inc_bytes += rlen;
677 state->stats.inc_packets++;
678 state->stats.unc_bytes += rlen;
679 state->stats.unc_packets++;
680 }
681
682 #endif /* DO_DEFLATE */
683