1 /*
2 * deflate.c - interface the zlib procedures for Deflate compression
3 * and decompression (as used by gzip) to the PPP code.
4 *
5 * This version is for use with STREAMS in Solaris 2
6 *
7 * Copyright (c) 2001 by Sun Microsystems, Inc.
8 * All rights reserved.
9 *
10 * Copyright (c) 1994 The Australian National University.
11 * All rights reserved.
12 *
13 * Permission to use, copy, modify, and distribute this software and its
14 * documentation is hereby granted, provided that the above copyright
15 * notice appears in all copies. This software is provided without any
16 * warranty, express or implied. The Australian National University
17 * makes no representations about the suitability of this software for
18 * any purpose.
19 *
20 * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
21 * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
22 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
23 * THE AUSTRALIAN NATIONAL UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY
24 * OF SUCH DAMAGE.
25 *
26 * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
27 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
28 * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
29 * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
30 * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
31 * OR MODIFICATIONS.
32 *
33 * $Id: deflate.c,v 1.9 1999/01/19 23:58:35 paulus Exp $
34 */
35
36 #define NO_DUMMY_DECL
37
38 #include <sys/param.h>
39 #include <sys/types.h>
40 #include <sys/kmem.h>
41 #include <sys/stream.h>
42 #include <sys/cmn_err.h>
43 #include <sys/ddi.h>
44 #include <sys/sunddi.h>
45 #include <sys/errno.h>
46 #include <net/ppp_defs.h>
47
48 /* Defined for platform-neutral include file */
49 #define PACKETPTR mblk_t *
50 #include <net/ppp-comp.h>
51 #include "s_common.h"
52 #include "zlib.h"
53
54 #if DO_DEFLATE
55
56 /*
57 * State for a Deflate (de)compressor.
58 */
59 struct deflate_state {
60 int seqno;
61 int w_size;
62 int unit;
63 int hdrlen;
64 int mru;
65 int flags;
66 z_stream strm;
67 struct compstat stats;
68 };
69
70 #define DEFLATE_OVHD 2 /* Deflate overhead/packet */
71
72 #define DS_DEBUG 0x0001
73 #define DS_TESTIN 0x0002
74 #define DS_TESTOUT 0x0004
75
76 static void *z_alloc(void *, uint_t items, uint_t size);
77 static void z_free(void *, void *ptr);
78 static void *z_comp_alloc(uchar_t *options, int opt_len);
79 static void *z_decomp_alloc(uchar_t *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, uchar_t *options, int opt_len,
83 int unit, int hdrlen, int debug);
84 static int z_decomp_init(void *state, uchar_t *options, int opt_len,
85 int unit, int hdrlen, int mru, int debug);
86 static int z_compress(void *state, mblk_t **mret,
87 mblk_t *mp, int slen, int maxolen);
88 static int z_incomp(void *state, mblk_t *dmsg);
89 static int z_decompress(void *state, mblk_t **dmpp);
90 static void z_comp_reset(void *state);
91 static void z_decomp_reset(void *state);
92 static void z_comp_stats(void *state, struct compstat *stats);
93 static int z_set_effort(void *xstate, void *rstate, int effortlevel);
94
95 /*
96 * Procedures exported to ppp_comp.c.
97 */
98 struct compressor ppp_deflate = {
99 CI_DEFLATE, /* compress_proto */
100 z_comp_alloc, /* comp_alloc */
101 z_comp_free, /* comp_free */
102 z_comp_init, /* comp_init */
103 z_comp_reset, /* comp_reset */
104 z_compress, /* compress */
105 z_comp_stats, /* comp_stat */
106 z_decomp_alloc, /* decomp_alloc */
107 z_decomp_free, /* decomp_free */
108 z_decomp_init, /* decomp_init */
109 z_decomp_reset, /* decomp_reset */
110 z_decompress, /* decompress */
111 z_incomp, /* incomp */
112 z_comp_stats, /* decomp_stat */
113 z_set_effort, /* set_effort */
114 };
115
116 struct compressor ppp_deflate_draft = {
117 CI_DEFLATE_DRAFT, /* compress_proto */
118 z_comp_alloc, /* comp_alloc */
119 z_comp_free, /* comp_free */
120 z_comp_init, /* comp_init */
121 z_comp_reset, /* comp_reset */
122 z_compress, /* compress */
123 z_comp_stats, /* comp_stat */
124 z_decomp_alloc, /* decomp_alloc */
125 z_decomp_free, /* decomp_free */
126 z_decomp_init, /* decomp_init */
127 z_decomp_reset, /* decomp_reset */
128 z_decompress, /* decompress */
129 z_incomp, /* incomp */
130 z_comp_stats, /* decomp_stat */
131 z_set_effort, /* set_effort */
132 };
133
134 #define DECOMP_CHUNK 512
135
136 /*
137 * Space allocation and freeing routines for use by zlib routines.
138 */
139 struct zchunk {
140 uint_t size;
141 uint_t guard;
142 };
143
144 #define GUARD_MAGIC 0x77a6011a
145
146 /*
147 * z_alloc()
148 */
149 /* ARGSUSED */
150 static void *
z_alloc(void * notused,uint_t items,uint_t size)151 z_alloc(void *notused, uint_t items, uint_t size)
152 {
153 struct zchunk *z;
154
155 size = items * size + sizeof (struct zchunk);
156
157 z = (struct zchunk *)kmem_alloc(size, KM_NOSLEEP);
158 if (z == NULL)
159 return (NULL);
160
161 z->size = size;
162 z->guard = GUARD_MAGIC;
163
164 return ((void *)(z + 1));
165 }
166
167 /*
168 * z_free()
169 */
170 /* ARGSUSED */
171 static void
z_free(void * notused,void * ptr)172 z_free(void *notused, void *ptr)
173 {
174 struct zchunk *z = ((struct zchunk *)ptr) - 1;
175
176 if (ptr == NULL)
177 return;
178
179 if (z->guard != GUARD_MAGIC) {
180 cmn_err(CE_CONT,
181 "deflate: z_free of corrupted chunk at 0x%p (%x, %x)\n",
182 (void *)z, z->size, z->guard);
183
184 return;
185 }
186
187 kmem_free(z, z->size);
188 }
189
190 /*
191 * Allocate space for a compressor.
192 */
193 static void *
z_comp_alloc(uchar_t * options,int opt_len)194 z_comp_alloc(uchar_t *options, int opt_len)
195 {
196 struct deflate_state *state;
197 int w_size;
198
199 if (opt_len != CILEN_DEFLATE ||
200 (options[0] != CI_DEFLATE && options[0] != CI_DEFLATE_DRAFT) ||
201 options[1] != CILEN_DEFLATE ||
202 DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL ||
203 options[3] != DEFLATE_CHK_SEQUENCE) {
204
205 return (NULL);
206 }
207
208 w_size = DEFLATE_SIZE(options[2]);
209 /*
210 * Check <= minimum size to avoid unfixable zlib bug -- window size
211 * 256 (w_size 8) is not supported.
212 */
213 if (w_size <= DEFLATE_MIN_SIZE || w_size > DEFLATE_MAX_SIZE) {
214 return (NULL);
215 }
216
217 state = (struct deflate_state *)kmem_zalloc(sizeof (*state), KM_SLEEP);
218 ASSERT(state != NULL);
219
220 state->strm.zalloc = (alloc_func)z_alloc;
221 state->strm.zfree = (free_func)z_free;
222
223 if (deflateInit2(&state->strm, Z_DEFAULT_COMPRESSION,
224 DEFLATE_METHOD_VAL, -w_size, 8, Z_DEFAULT_STRATEGY) != Z_OK) {
225
226 kmem_free(state, sizeof (*state));
227
228 return (NULL);
229 }
230
231 state->w_size = w_size;
232
233 bzero(&state->stats, sizeof (state->stats));
234
235 return ((void *)state);
236 }
237
238 /*
239 * z_comp_free()
240 */
241 static void
z_comp_free(void * arg)242 z_comp_free(void *arg)
243 {
244 struct deflate_state *state = (struct deflate_state *)arg;
245
246 (void) deflateEnd(&state->strm);
247
248 kmem_free(state, sizeof (*state));
249 }
250
251 /*
252 * z_comp_init()
253 */
254 static int
z_comp_init(void * arg,uchar_t * options,int opt_len,int unit,int hdrlen,int debug)255 z_comp_init(void *arg, uchar_t *options, int opt_len, int unit, int hdrlen,
256 int debug)
257 {
258 struct deflate_state *state = (struct deflate_state *)arg;
259
260 if (opt_len < CILEN_DEFLATE ||
261 (options[0] != CI_DEFLATE && options[0] != CI_DEFLATE_DRAFT) ||
262 options[1] != CILEN_DEFLATE ||
263 DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL ||
264 DEFLATE_SIZE(options[2]) != state->w_size ||
265 options[3] != DEFLATE_CHK_SEQUENCE) {
266
267 return (0);
268 }
269
270 state->seqno = 0;
271 state->unit = unit;
272 state->hdrlen = hdrlen;
273 if (debug)
274 state->flags |= DS_DEBUG;
275 else
276 state->flags &= ~DS_DEBUG;
277
278 (void) deflateReset(&state->strm);
279
280 return (1);
281 }
282
283 /*
284 * z_comp_reset()
285 */
286 static void
z_comp_reset(void * arg)287 z_comp_reset(void *arg)
288 {
289 struct deflate_state *state = (struct deflate_state *)arg;
290
291 state->seqno = 0;
292
293 (void) deflateReset(&state->strm);
294 }
295
296 /*
297 * z_compress()
298 */
299 static int
z_compress(void * arg,mblk_t ** mret,mblk_t * mp,int orig_len,int maxolen)300 z_compress(void *arg, mblk_t **mret, mblk_t *mp, int orig_len, int maxolen)
301 {
302 struct deflate_state *state = (struct deflate_state *)arg;
303 uchar_t *rptr, *rmax;
304 uchar_t *wptr;
305 int olen;
306 int wspace;
307 int r;
308 int flush;
309 mblk_t *m;
310 #if defined(lint) || defined(_lint)
311 uchar_t hdlcaddr, hdlcctrl;
312 #else
313 int hdlcaddr, hdlcctrl;
314 #endif
315
316 #define ADJRPTR() { \
317 if (rptr != NULL) { \
318 while (rptr >= rmax) { \
319 if ((mp = mp->b_cont) == NULL) { \
320 rptr = NULL; \
321 break; \
322 } \
323 rptr = mp->b_rptr; \
324 rmax = mp->b_wptr; \
325 } \
326 } \
327 }
328
329 #define GETBYTE(v) { \
330 if (rptr != NULL) { \
331 (v) = *rptr++; \
332 } \
333 }
334
335 /*
336 * Check that the protocol is one we handle. Pullup is *NOT*
337 * possible here.
338 */
339 *mret = NULL;
340 rptr = mp->b_rptr;
341 rmax = mp->b_wptr;
342 ADJRPTR();
343 GETBYTE(hdlcaddr);
344 ADJRPTR();
345 GETBYTE(hdlcctrl);
346 ADJRPTR();
347
348 /*
349 * Per RFC 1979, the protocol field must be compressed using a
350 * PFC-like procedure. Also, all protocols between 0000-3FFF
351 * except the two compression protocols must be LZ compressed.
352 */
353 if (rptr == NULL)
354 return (orig_len);
355 r = *rptr;
356 if (r == 0) {
357 rptr++;
358 ADJRPTR();
359 if (rptr == NULL || *rptr == PPP_COMP || *rptr == PPP_COMPFRAG)
360 return (orig_len);
361 } else {
362 if (r > 0x3F)
363 return (orig_len);
364 }
365
366 /*
367 * Allocate one mblk initially
368 */
369 if (maxolen > orig_len) {
370 maxolen = orig_len;
371 }
372
373 if (maxolen <= PPP_HDRLEN + 2) {
374 wspace = 0;
375 m = NULL;
376 } else {
377 wspace = maxolen + state->hdrlen;
378 if (wspace > 4096) {
379 wspace = 4096;
380 }
381
382 m = allocb(wspace, BPRI_MED);
383 }
384
385 if (m != NULL) {
386
387 wspace = m->b_datap->db_lim - m->b_wptr;
388
389 *mret = m;
390
391 if (state->hdrlen + PPP_HDRLEN + 2 < wspace) {
392 m->b_rptr += state->hdrlen;
393 m->b_wptr = m->b_rptr;
394 wspace -= state->hdrlen;
395 }
396
397 wptr = m->b_wptr;
398
399 /*
400 * Copy over the PPP header and store the 2-byte
401 * sequence number
402 */
403 wptr[0] = hdlcaddr;
404 wptr[1] = hdlcctrl;
405 wptr[2] = PPP_COMP >> 8;
406 wptr[3] = PPP_COMP;
407
408 wptr += PPP_HDRLEN;
409
410 wptr[0] = state->seqno >> 8;
411 wptr[1] = state->seqno;
412 wptr += 2;
413
414 #ifdef DEBUG
415 /*
416 * If testing output, just garbling the sequence here
417 * does the trick.
418 */
419 if ((state->flags & DS_TESTOUT) && (state->seqno % 100) == 50)
420 wptr[-1] ^= 0xAA;
421 #endif
422
423 state->strm.next_out = wptr;
424 state->strm.avail_out = wspace - (PPP_HDRLEN + 2);
425 } else {
426 state->strm.next_out = NULL;
427 state->strm.avail_out = 1000000;
428 }
429
430 ++state->seqno;
431
432 state->strm.next_in = rptr;
433 state->strm.avail_in = mp->b_wptr - rptr;
434
435 olen = 0;
436
437 for (;;) {
438 flush = (mp == NULL || mp->b_cont == NULL) ? Z_PACKET_FLUSH :
439 Z_NO_FLUSH;
440 r = deflate(&state->strm, flush);
441
442 if (r != Z_OK) {
443 cmn_err(CE_CONT,
444 "z_compress%d: deflate returned %d (%s)\n",
445 state->unit, r,
446 (state->strm.msg? state->strm.msg: ""));
447
448 break;
449 }
450
451 if (state->strm.avail_in == 0) {
452 if (mp != NULL)
453 mp = mp->b_cont;
454 if (mp == NULL) {
455 if (state->strm.avail_out != 0)
456 break; /* all done */
457 } else {
458 state->strm.next_in = mp->b_rptr;
459 state->strm.avail_in = mp->b_wptr - mp->b_rptr;
460 }
461 }
462
463 if (state->strm.avail_out == 0) {
464 if (m != NULL) {
465 m->b_wptr += wspace;
466 olen += wspace;
467 wspace = maxolen - olen;
468
469 if (wspace <= 0) {
470 wspace = 0;
471 m->b_cont = NULL;
472 } else {
473 if (wspace < 32) {
474 wspace = 32;
475 } else if (wspace > 4096) {
476 wspace = 4096;
477 }
478
479 m->b_cont = allocb(wspace, BPRI_MED);
480 }
481
482 m = m->b_cont;
483
484 if (m != NULL) {
485 state->strm.next_out = m->b_wptr;
486 wspace = m->b_datap->db_lim -
487 m->b_wptr;
488 state->strm.avail_out = wspace;
489 }
490 }
491
492 if (m == NULL) {
493 state->strm.next_out = NULL;
494 state->strm.avail_out = 1000000;
495 }
496 }
497 }
498
499 if (m != NULL) {
500 m->b_wptr += wspace - state->strm.avail_out;
501 olen += wspace - state->strm.avail_out;
502 }
503
504 /*
505 * See if we managed to reduce the size of the packet.
506 */
507 if (olen < orig_len && m != NULL) {
508 state->stats.comp_bytes += olen;
509 state->stats.comp_packets++;
510 } else {
511 if (*mret != NULL) {
512 freemsg(*mret);
513 *mret = NULL;
514 }
515
516 state->stats.inc_bytes += orig_len;
517 state->stats.inc_packets++;
518
519 olen = orig_len;
520 }
521
522 state->stats.unc_bytes += orig_len;
523 state->stats.unc_packets++;
524
525 return (olen);
526 }
527
528 /*
529 * z_incomp()
530 *
531 * Incompressible data has arrived - add it to the history.
532 */
533 static int
z_incomp(void * arg,mblk_t * mp)534 z_incomp(void *arg, mblk_t *mp)
535 {
536 struct deflate_state *state = (struct deflate_state *)arg;
537 uchar_t *rptr, *rmax;
538 int rlen;
539 int r;
540
541 /*
542 * Check that the protocol is one we handle. Pullup is *NOT*
543 * possible here.
544 */
545 rptr = mp->b_rptr;
546 rmax = mp->b_wptr;
547 ADJRPTR();
548 rptr++; /* skip address */
549 ADJRPTR();
550 rptr++; /* skip control */
551 ADJRPTR();
552
553 /*
554 * Per RFC 1979, the protocol field must be compressed using a
555 * PFC-like procedure. Also, all protocols between 0000-3FFF
556 * except the two compression protocols must be LZ compressed.
557 */
558 if (rptr == NULL)
559 return (0);
560 r = *rptr;
561 if (r == 0) {
562 rptr++;
563 ADJRPTR();
564 if (rptr == NULL || *rptr == PPP_COMP || *rptr == PPP_COMPFRAG)
565 return (0);
566 } else {
567 if (r > 0x3F)
568 return (0);
569 }
570
571 ++state->seqno;
572
573 /*
574 * Iterate through the message blocks, adding the characters
575 * in them to the decompressor's history.
576 */
577 rlen = mp->b_wptr - rptr;
578
579 state->strm.next_in = rptr;
580 state->strm.avail_in = rlen;
581
582 for (;;) {
583 r = inflateIncomp(&state->strm);
584
585 if (r != Z_OK) { /* gak! */
586 if (state->flags & DS_DEBUG) {
587 cmn_err(CE_CONT,
588 "z_incomp%d: inflateIncomp returned "
589 "%d (%s)\n", state->unit, r,
590 (state->strm.msg? state->strm.msg: ""));
591 }
592
593 return (-1);
594 }
595
596 mp = mp->b_cont;
597 if (mp == NULL) {
598 break;
599 }
600
601 state->strm.next_in = mp->b_rptr;
602 state->strm.avail_in = mp->b_wptr - mp->b_rptr;
603
604 rlen += state->strm.avail_in;
605 }
606
607 /*
608 * Update stats
609 */
610 state->stats.inc_bytes += rlen;
611 state->stats.inc_packets++;
612 state->stats.unc_bytes += rlen;
613 state->stats.unc_packets++;
614 return (0);
615 #undef ADJRPTR
616 }
617
618 /*
619 * z_comp_stats()
620 */
621 static void
z_comp_stats(void * arg,struct compstat * stats)622 z_comp_stats(void *arg, struct compstat *stats)
623 {
624 struct deflate_state *state = (struct deflate_state *)arg;
625 uint_t out;
626
627 *stats = state->stats;
628 stats->ratio = stats->unc_bytes;
629 out = stats->comp_bytes + stats->unc_bytes;
630
631 if (stats->ratio <= 0x7ffffff) {
632 stats->ratio <<= 8;
633 } else {
634 out >>= 8;
635 }
636
637 if (out != 0) {
638 stats->ratio /= out;
639 }
640 }
641
642 /*
643 * z_decomp_alloc()
644 *
645 * Allocate space for a decompressor.
646 */
647 static void *
z_decomp_alloc(uchar_t * options,int opt_len)648 z_decomp_alloc(uchar_t *options, int opt_len)
649 {
650 struct deflate_state *state;
651 int w_size;
652
653 if (opt_len != CILEN_DEFLATE ||
654 (options[0] != CI_DEFLATE && options[0] != CI_DEFLATE_DRAFT) ||
655 options[1] != CILEN_DEFLATE ||
656 DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL ||
657 options[3] != DEFLATE_CHK_SEQUENCE) {
658
659 return (NULL);
660 }
661
662 w_size = DEFLATE_SIZE(options[2]);
663 /*
664 * Check <= minimum size to avoid unfixable zlib bug -- window size
665 * 256 (w_size 8) is not supported.
666 */
667 if (w_size <= DEFLATE_MIN_SIZE || w_size > DEFLATE_MAX_SIZE) {
668 return (NULL);
669 }
670
671 state = (struct deflate_state *)kmem_zalloc(sizeof (*state), KM_SLEEP);
672 ASSERT(state != NULL);
673
674 state->strm.zalloc = (alloc_func)z_alloc;
675 state->strm.zfree = (free_func)z_free;
676
677 if (inflateInit2(&state->strm, -w_size) != Z_OK) {
678 kmem_free(state, sizeof (*state));
679 return (NULL);
680 }
681
682 state->w_size = w_size;
683
684 bzero(&state->stats, sizeof (state->stats));
685
686 return ((void *)state);
687 }
688
689 /*
690 * z_decomp_free()
691 */
692 static void
z_decomp_free(void * arg)693 z_decomp_free(void *arg)
694 {
695 struct deflate_state *state = (struct deflate_state *)arg;
696
697 (void) inflateEnd(&state->strm);
698
699 kmem_free(state, sizeof (*state));
700 }
701
702 /*
703 * z_decomp_init()
704 */
705 static int
z_decomp_init(void * arg,uchar_t * options,int opt_len,int unit,int hdrlen,int mru,int debug)706 z_decomp_init(void *arg, uchar_t *options, int opt_len, int unit, int hdrlen,
707 int mru, int debug)
708 {
709 struct deflate_state *state = (struct deflate_state *)arg;
710
711 if (opt_len < CILEN_DEFLATE ||
712 (options[0] != CI_DEFLATE && options[0] != CI_DEFLATE_DRAFT) ||
713 options[1] != CILEN_DEFLATE ||
714 DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL ||
715 DEFLATE_SIZE(options[2]) != state->w_size ||
716 options[3] != DEFLATE_CHK_SEQUENCE) {
717
718 return (0);
719 }
720
721 state->seqno = 0;
722 state->unit = unit;
723 state->hdrlen = hdrlen;
724 if (debug)
725 state->flags |= DS_DEBUG;
726 else
727 state->flags &= ~DS_DEBUG;
728 state->mru = mru;
729
730 (void) inflateReset(&state->strm);
731
732 return (1);
733 }
734
735 /*
736 * z_decomp_reset()
737 */
738 static void
z_decomp_reset(void * arg)739 z_decomp_reset(void *arg)
740 {
741 struct deflate_state *state = (struct deflate_state *)arg;
742
743 state->seqno = 0;
744
745 (void) inflateReset(&state->strm);
746 }
747
748 /*
749 * z_decompress()
750 *
751 * Decompress a Deflate-compressed packet.
752 *
753 * Because of patent problems, we return DECOMP_ERROR for errors
754 * found by inspecting the input data and for system problems, but
755 * DECOMP_FATALERROR for any errors which could possibly be said to
756 * be being detected "after" decompression. For DECOMP_ERROR,
757 * we can issue a CCP reset-request; for DECOMP_FATALERROR, we may be
758 * infringing a patent of Motorola's if we do, so we take CCP down
759 * instead.
760 *
761 * Given that the frame has the correct sequence number and a good FCS,
762 * errors such as invalid codes in the input most likely indicate a
763 * bug, so we return DECOMP_FATALERROR for them in order to turn off
764 * compression, even though they are detected by inspecting the input.
765 */
766 static int
z_decompress(void * arg,mblk_t ** mop)767 z_decompress(void *arg, mblk_t **mop)
768 {
769 struct deflate_state *state = (struct deflate_state *)arg;
770 mblk_t *mi = *mop, *mnext;
771 mblk_t *mo;
772 mblk_t *mo_head;
773 uchar_t *rptr, *rmax;
774 uchar_t *wptr;
775 int rlen;
776 int olen;
777 int ospace;
778 int seq;
779 int flush;
780 int r;
781 int decode_proto;
782 #if defined(lint) || defined(_lint)
783 uchar_t hdlcaddr, hdlcctrl;
784 #else
785 int hdlcaddr, hdlcctrl;
786 #endif
787
788 /* Note: spppcomp already did a pullup to fix the first buffer. */
789 *mop = NULL;
790 rptr = mi->b_rptr + PPP_HDRLEN;
791 rmax = mi->b_wptr;
792 if (rptr > rmax) {
793 if (state->flags & DS_DEBUG) {
794 cmn_err(CE_CONT, "z_decompress%d: bad buffer\n",
795 state->unit);
796 }
797 freemsg(mi);
798 return (DECOMP_ERROR);
799 }
800
801 hdlcaddr = rptr[-PPP_HDRLEN];
802 hdlcctrl = rptr[-PPP_HDRLEN+1];
803
804 /*
805 * Note that we free as we go. If we fail to decompress,
806 * there's nothing good that the caller can do.
807 */
808 #define ADJRPTR() { \
809 if (rptr != NULL) { \
810 while (rptr >= rmax) { \
811 mnext = mi->b_cont; \
812 freeb(mi); \
813 if ((mi = mnext) == NULL) { \
814 rptr = NULL; \
815 break; \
816 } \
817 rptr = mi->b_rptr; \
818 rmax = mi->b_wptr; \
819 } \
820 } \
821 }
822
823 /*
824 * Check the sequence number
825 */
826 ADJRPTR();
827 seq = rptr == NULL ? 0 : (*rptr++ << 8);
828 ADJRPTR();
829 if (rptr == NULL) {
830 if (state->flags & DS_DEBUG) {
831 cmn_err(CE_CONT, "z_decompress%d: bad buffer\n",
832 state->unit);
833 }
834 return (DECOMP_ERROR);
835 }
836
837 seq |= *rptr++;
838
839 #ifdef DEBUG
840 /*
841 * If testing input, just pretending the sequence is bad here
842 * does the trick.
843 */
844 if ((state->flags & DS_TESTIN) && (state->seqno % 300) == 101)
845 seq ^= 0x55;
846 #endif
847 if (seq != state->seqno++) {
848 freemsg(mi);
849 if (state->flags & DS_DEBUG) {
850 cmn_err(CE_CONT,
851 "z_decompress%d: bad seq # %d, expected %d\n",
852 state->unit, seq, state->seqno - 1);
853 }
854 return (DECOMP_ERROR);
855 }
856
857 /*
858 * Allocate an output message block
859 */
860 mo = allocb(DECOMP_CHUNK + state->hdrlen, BPRI_MED);
861 if (mo == NULL) {
862 freemsg(mi);
863 return (DECOMP_ERROR);
864 }
865
866 mo_head = mo;
867 mo->b_cont = NULL;
868 mo->b_rptr += state->hdrlen;
869 mo->b_wptr = wptr = mo->b_rptr;
870
871 ospace = DECOMP_CHUNK;
872 olen = 0;
873
874 /*
875 * Fill in the first part of the PPP header. The protocol field
876 * comes from the decompressed data.
877 */
878 *wptr++ = hdlcaddr;
879 *wptr++ = hdlcctrl;
880 *wptr++ = 0;
881
882 /*
883 * Set up to call inflate. We set avail_out to 1 initially so we can
884 * look at the first byte of the output and decide whether we have
885 * a 1-byte or 2-byte protocol field.
886 */
887 state->strm.next_in = rptr;
888 state->strm.avail_in = mi->b_wptr - rptr;
889
890 rlen = state->strm.avail_in + PPP_HDRLEN + DEFLATE_OVHD;
891
892 state->strm.next_out = wptr;
893 state->strm.avail_out = 1;
894
895 decode_proto = 1;
896
897 /*
898 * Call inflate, supplying more input or output as needed.
899 */
900 for (;;) {
901
902 flush = (mi == NULL || mi->b_cont == NULL) ?
903 Z_PACKET_FLUSH : Z_NO_FLUSH;
904 r = inflate(&state->strm, flush);
905
906 if (r != Z_OK) {
907
908 if (state->flags & DS_DEBUG) {
909 cmn_err(CE_CONT,
910 "z_decompress%d: inflate returned %d "
911 "(%s)\n", state->unit, r,
912 (state->strm.msg? state->strm.msg: ""));
913 }
914
915 if (mi != NULL)
916 freemsg(mi);
917 freemsg(mo_head);
918
919 return (DECOMP_FATALERROR);
920 }
921
922 if (state->strm.avail_in == 0) {
923 if (mi != NULL) {
924 mnext = mi->b_cont;
925 freeb(mi);
926 mi = mnext;
927 }
928 if (mi == NULL) {
929 if (state->strm.avail_out != 0)
930 break; /* all done */
931 } else {
932 state->strm.next_in = mi->b_rptr;
933 state->strm.avail_in = mi->b_wptr - mi->b_rptr;
934
935 rlen += state->strm.avail_in;
936 }
937 }
938
939 if (state->strm.avail_out == 0) {
940 if (decode_proto) {
941 state->strm.avail_out = ospace - PPP_HDRLEN;
942
943 if ((wptr[0] & 1) == 0) {
944 /*
945 * 2-byte protocol field
946 */
947 wptr[-1] = wptr[0];
948
949 --state->strm.next_out;
950 ++state->strm.avail_out;
951 }
952
953 decode_proto = 0;
954 } else {
955 mo->b_wptr += ospace;
956 olen += ospace;
957
958 mo->b_cont = allocb(DECOMP_CHUNK, BPRI_MED);
959
960 mo = mo->b_cont;
961 if (mo == NULL) {
962 if (mi != NULL)
963 freemsg(mi);
964 freemsg(mo_head);
965 return (DECOMP_ERROR);
966 }
967
968 state->strm.next_out = mo->b_rptr;
969 state->strm.avail_out = ospace = DECOMP_CHUNK;
970 }
971 }
972 }
973
974 if (decode_proto) {
975 freemsg(mo_head);
976 return (DECOMP_ERROR);
977 }
978
979 mo->b_wptr += ospace - state->strm.avail_out;
980 olen += ospace - state->strm.avail_out;
981
982 if ((olen > state->mru + PPP_HDRLEN) && (state->flags & DS_DEBUG)) {
983 cmn_err(CE_CONT, "z_decompress%d: exceeded mru (%d > %d)\n",
984 state->unit, olen, state->mru + PPP_HDRLEN);
985 }
986
987 state->stats.unc_bytes += olen;
988 state->stats.unc_packets++;
989 state->stats.comp_bytes += rlen;
990 state->stats.comp_packets++;
991
992 *mop = mo_head;
993
994 return (DECOMP_OK);
995 }
996
997 /* ARGSUSED */
998 static int
z_set_effort(void * xarg,void * rarg,int effortlevel)999 z_set_effort(void *xarg, void *rarg, int effortlevel)
1000 {
1001 struct deflate_state *xstate = (struct deflate_state *)xarg;
1002 #ifdef DEBUG
1003 struct deflate_state *rstate = (struct deflate_state *)rarg;
1004 #endif
1005 int retv;
1006
1007 #ifdef DEBUG
1008 if (effortlevel == 42 || effortlevel == 2112) {
1009 /* corrupt received data. */
1010 if (rstate != NULL) {
1011 rstate->flags |= DS_TESTIN;
1012 cmn_err(CE_CONT, "deflate: enabled input testing.");
1013 }
1014 if (effortlevel != 2112)
1015 return (0);
1016 }
1017 if (effortlevel == 2001 || effortlevel == 2112) {
1018 /* corrupt transmitted data. */
1019 if (xstate != NULL) {
1020 xstate->flags |= DS_TESTOUT;
1021 cmn_err(CE_CONT, "deflate: enabled output testing.");
1022 }
1023 return (0);
1024 }
1025 #endif
1026 if (effortlevel < -1 || effortlevel > 9)
1027 return (EINVAL);
1028 if (xstate == NULL)
1029 return (0);
1030 retv = deflateParams(&xstate->strm, effortlevel, Z_DEFAULT_STRATEGY);
1031 return (retv == Z_OK ? 0 : EINVAL);
1032 }
1033
1034 #endif /* DO_DEFLATE */
1035