xref: /titanic_50/usr/src/uts/common/io/ppp/spppcomp/deflate.c (revision 3c112a2b34403220c06c3e2fcac403358cfba168)
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 *
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
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 *
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
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
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
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
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
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
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 *
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
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
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
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
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
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