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