1 /*-
2  * Copyright (c) 2006 Alexander Motin <mav@alkar.net>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice unmodified, this list of conditions, and the following
10  *    disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  *
27  * $FreeBSD: src/sys/netgraph/ng_deflate.c,v 1.3 2007/01/15 05:55:56 glebius Exp $
28  */
29 
30 /*
31  * Deflate PPP compression netgraph node type.
32  */
33 
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/kernel.h>
37 #include <sys/mbuf.h>
38 #include <sys/malloc.h>
39 #include <sys/errno.h>
40 #include <sys/syslog.h>
41 
42 #include <net/zlib.h>
43 
44 #include <netgraph7/ng_message.h>
45 #include <netgraph7/netgraph.h>
46 #include <netgraph7/ng_parse.h>
47 #include "ng_deflate.h"
48 
49 #include "opt_netgraph.h"
50 
51 MALLOC_DEFINE(M_NETGRAPH_DEFLATE, "netgraph_deflate", "netgraph deflate node ");
52 
53 /* DEFLATE header length */
54 #define DEFLATE_HDRLEN		2
55 
56 #define PROT_COMPD		0x00fd
57 
58 #define DEFLATE_BUF_SIZE	4096
59 
60 /* Node private data */
61 struct ng_deflate_private {
62 	struct ng_deflate_config cfg;		/* configuration */
63 	u_char		inbuf[DEFLATE_BUF_SIZE];	/* input buffer */
64 	u_char		outbuf[DEFLATE_BUF_SIZE];	/* output buffer */
65 	z_stream 	cx;			/* compression context */
66 	struct ng_deflate_stats stats;		/* statistics */
67 	ng_ID_t		ctrlnode;		/* path to controlling node */
68 	uint16_t	seqnum;			/* sequence number */
69 	u_char		compress;		/* compress/decompress flag */
70 };
71 typedef struct ng_deflate_private *priv_p;
72 
73 /* Netgraph node methods */
74 static ng_constructor_t	ng_deflate_constructor;
75 static ng_rcvmsg_t	ng_deflate_rcvmsg;
76 static ng_shutdown_t	ng_deflate_shutdown;
77 static ng_newhook_t	ng_deflate_newhook;
78 static ng_rcvdata_t	ng_deflate_rcvdata;
79 static ng_disconnect_t	ng_deflate_disconnect;
80 
81 /* Helper functions */
82 static void	*z_alloc(void *, u_int items, u_int size);
83 static void	z_free(void *, void *ptr);
84 static int	ng_deflate_compress(node_p node,
85 		    struct mbuf *m, struct mbuf **resultp);
86 static int	ng_deflate_decompress(node_p node,
87 		    struct mbuf *m, struct mbuf **resultp);
88 static void	ng_deflate_reset_req(node_p node);
89 
90 /* Parse type for struct ng_deflate_config. */
91 static const struct ng_parse_struct_field ng_deflate_config_type_fields[]
92 	= NG_DEFLATE_CONFIG_INFO;
93 static const struct ng_parse_type ng_deflate_config_type = {
94 	&ng_parse_struct_type,
95 	ng_deflate_config_type_fields
96 };
97 
98 /* Parse type for struct ng_deflate_stat. */
99 static const struct ng_parse_struct_field ng_deflate_stats_type_fields[]
100 	= NG_DEFLATE_STATS_INFO;
101 static const struct ng_parse_type ng_deflate_stat_type = {
102 	&ng_parse_struct_type,
103 	ng_deflate_stats_type_fields
104 };
105 
106 /* List of commands and how to convert arguments to/from ASCII. */
107 static const struct ng_cmdlist ng_deflate_cmds[] = {
108 	{
109 	  NGM_DEFLATE_COOKIE,
110 	  NGM_DEFLATE_CONFIG,
111 	  "config",
112 	  &ng_deflate_config_type,
113 	  NULL
114 	},
115 	{
116 	  NGM_DEFLATE_COOKIE,
117 	  NGM_DEFLATE_RESETREQ,
118 	  "resetreq",
119 	  NULL,
120 	  NULL
121 	},
122 	{
123 	  NGM_DEFLATE_COOKIE,
124 	  NGM_DEFLATE_GET_STATS,
125 	  "getstats",
126 	  NULL,
127 	  &ng_deflate_stat_type
128 	},
129 	{
130 	  NGM_DEFLATE_COOKIE,
131 	  NGM_DEFLATE_CLR_STATS,
132 	  "clrstats",
133 	  NULL,
134 	  NULL
135 	},
136 	{
137 	  NGM_DEFLATE_COOKIE,
138 	  NGM_DEFLATE_GETCLR_STATS,
139 	  "getclrstats",
140 	  NULL,
141 	  &ng_deflate_stat_type
142 	},
143 	{ 0 }
144 };
145 
146 /* Node type descriptor */
147 static struct ng_type ng_deflate_typestruct = {
148 	.version =	NG_ABI_VERSION,
149 	.name =		NG_DEFLATE_NODE_TYPE,
150 	.constructor =	ng_deflate_constructor,
151 	.rcvmsg =	ng_deflate_rcvmsg,
152 	.shutdown =	ng_deflate_shutdown,
153 	.newhook =	ng_deflate_newhook,
154 	.rcvdata =	ng_deflate_rcvdata,
155 	.disconnect =	ng_deflate_disconnect,
156 	.cmdlist =	ng_deflate_cmds,
157 };
158 NETGRAPH_INIT(deflate, &ng_deflate_typestruct);
159 
160 /* Depend on separate zlib module. */
161 MODULE_DEPEND(ng_deflate, zlib, 1, 1, 1);
162 
163 #define ERROUT(x)	do { error = (x); goto done; } while (0)
164 
165 /************************************************************************
166 			NETGRAPH NODE STUFF
167  ************************************************************************/
168 
169 /*
170  * Node type constructor
171  */
172 static int
173 ng_deflate_constructor(node_p node)
174 {
175 	priv_p priv;
176 
177 	/* Allocate private structure. */
178 	priv = kmalloc(sizeof(*priv), M_NETGRAPH_DEFLATE, M_WAITOK | M_ZERO);
179 
180 	NG_NODE_SET_PRIVATE(node, priv);
181 
182 	/* This node is not thread safe. */
183 	NG_NODE_FORCE_WRITER(node);
184 
185 	/* Done */
186 	return (0);
187 }
188 
189 /*
190  * Give our OK for a hook to be added.
191  */
192 static int
193 ng_deflate_newhook(node_p node, hook_p hook, const char *name)
194 {
195 	const priv_p priv = NG_NODE_PRIVATE(node);
196 
197 	if (NG_NODE_NUMHOOKS(node) > 0)
198 		return (EINVAL);
199 
200 	if (strcmp(name, NG_DEFLATE_HOOK_COMP) == 0)
201 		priv->compress = 1;
202 	else if (strcmp(name, NG_DEFLATE_HOOK_DECOMP) == 0)
203 		priv->compress = 0;
204 	else
205 		return (EINVAL);
206 
207 	return (0);
208 }
209 
210 /*
211  * Receive a control message
212  */
213 static int
214 ng_deflate_rcvmsg(node_p node, item_p item, hook_p lasthook)
215 {
216 	const priv_p priv = NG_NODE_PRIVATE(node);
217 	struct ng_mesg *resp = NULL;
218 	int error = 0;
219 	struct ng_mesg *msg;
220 
221 	NGI_GET_MSG(item, msg);
222 
223 	if (msg->header.typecookie != NGM_DEFLATE_COOKIE)
224 		ERROUT(EINVAL);
225 
226 	switch (msg->header.cmd) {
227 	case NGM_DEFLATE_CONFIG:
228 	    {
229 		struct ng_deflate_config *const cfg
230 		    = (struct ng_deflate_config *)msg->data;
231 
232 		/* Check configuration. */
233 		if (msg->header.arglen != sizeof(*cfg))
234 			ERROUT(EINVAL);
235 		if (cfg->enable) {
236 		    if (cfg->windowBits < 8 || cfg->windowBits > 15)
237 			ERROUT(EINVAL);
238 		} else
239 		    cfg->windowBits = 0;
240 
241 		/* Clear previous state. */
242 		if (priv->cfg.enable) {
243 			if (priv->compress)
244 				deflateEnd(&priv->cx);
245 			else
246 				inflateEnd(&priv->cx);
247 			priv->cfg.enable = 0;
248 		}
249 
250 		/* Configuration is OK, reset to it. */
251 		priv->cfg = *cfg;
252 
253 		if (priv->cfg.enable) {
254 			priv->cx.next_in = NULL;
255 			priv->cx.zalloc = z_alloc;
256 			priv->cx.zfree = z_free;
257 			int res;
258 			if (priv->compress) {
259 				if ((res = deflateInit2(&priv->cx,
260 				    Z_DEFAULT_COMPRESSION, Z_DEFLATED,
261 				    -cfg->windowBits, 8,
262 				    Z_DEFAULT_STRATEGY)) != Z_OK) {
263 					log(LOG_NOTICE,
264 					    "deflateInit2: error %d, %s\n",
265 					    res, priv->cx.msg);
266 					priv->cfg.enable = 0;
267 					ERROUT(ENOMEM);
268 				}
269 			} else {
270 				if ((res = inflateInit2(&priv->cx,
271 				    -cfg->windowBits)) != Z_OK) {
272 					log(LOG_NOTICE,
273 					    "inflateInit2: error %d, %s\n",
274 					    res, priv->cx.msg);
275 					priv->cfg.enable = 0;
276 					ERROUT(ENOMEM);
277 				}
278 			}
279 		}
280 
281 		/* Initialize other state. */
282 		priv->seqnum = 0;
283 
284 		/* Save return address so we can send reset-req's */
285 		priv->ctrlnode = NGI_RETADDR(item);
286 		break;
287 	    }
288 
289 	case NGM_DEFLATE_RESETREQ:
290 		ng_deflate_reset_req(node);
291 		break;
292 
293 	case NGM_DEFLATE_GET_STATS:
294 	case NGM_DEFLATE_CLR_STATS:
295 	case NGM_DEFLATE_GETCLR_STATS:
296 		/* Create response if requested. */
297 		if (msg->header.cmd != NGM_DEFLATE_CLR_STATS) {
298 			NG_MKRESPONSE(resp, msg,
299 			    sizeof(struct ng_deflate_stats), M_WAITOK | M_NULLOK);
300 			if (resp == NULL)
301 				ERROUT(ENOMEM);
302 			bcopy(&priv->stats, resp->data,
303 			    sizeof(struct ng_deflate_stats));
304 		}
305 
306 		/* Clear stats if requested. */
307 		if (msg->header.cmd != NGM_DEFLATE_GET_STATS)
308 			bzero(&priv->stats,
309 			    sizeof(struct ng_deflate_stats));
310 		break;
311 
312 	default:
313 		error = EINVAL;
314 		break;
315 	}
316 done:
317 	NG_RESPOND_MSG(error, node, item, resp);
318 	NG_FREE_MSG(msg);
319 	return (error);
320 }
321 
322 /*
323  * Receive incoming data on our hook.
324  */
325 static int
326 ng_deflate_rcvdata(hook_p hook, item_p item)
327 {
328 	const node_p node = NG_HOOK_NODE(hook);
329 	const priv_p priv = NG_NODE_PRIVATE(node);
330 	struct mbuf *m, *out;
331 	int error;
332 
333 	if (!priv->cfg.enable) {
334 		NG_FREE_ITEM(item);
335 		return (ENXIO);
336 	}
337 
338 	NGI_GET_M(item, m);
339 	/* Compress */
340 	if (priv->compress) {
341 		if ((error = ng_deflate_compress(node, m, &out)) != 0) {
342 			NG_FREE_ITEM(item);
343 			log(LOG_NOTICE, "%s: error: %d\n", __func__, error);
344 			return (error);
345 		}
346 
347 	} else { /* Decompress */
348 		if ((error = ng_deflate_decompress(node, m, &out)) != 0) {
349 			NG_FREE_ITEM(item);
350 			log(LOG_NOTICE, "%s: error: %d\n", __func__, error);
351 			if (priv->ctrlnode != 0) {
352 				struct ng_mesg *msg;
353 
354 				/* Need to send a reset-request. */
355 				NG_MKMESSAGE(msg, NGM_DEFLATE_COOKIE,
356 				    NGM_DEFLATE_RESETREQ, 0, M_WAITOK | M_NULLOK);
357 				if (msg == NULL)
358 					return (error);
359 				NG_SEND_MSG_ID(error, node, msg,
360 					priv->ctrlnode, 0);
361 			}
362 			return (error);
363 		}
364 	}
365 
366 	NG_FWD_NEW_DATA(error, item, hook, out);
367 	return (error);
368 }
369 
370 /*
371  * Destroy node.
372  */
373 static int
374 ng_deflate_shutdown(node_p node)
375 {
376 	const priv_p priv = NG_NODE_PRIVATE(node);
377 
378 	/* Take down netgraph node. */
379 	if (priv->cfg.enable) {
380 	    if (priv->compress)
381 		deflateEnd(&priv->cx);
382 	    else
383 		inflateEnd(&priv->cx);
384 	}
385 
386 	kfree(priv, M_NETGRAPH_DEFLATE);
387 	NG_NODE_SET_PRIVATE(node, NULL);
388 	NG_NODE_UNREF(node);		/* let the node escape */
389 	return (0);
390 }
391 
392 /*
393  * Hook disconnection
394  */
395 static int
396 ng_deflate_disconnect(hook_p hook)
397 {
398 	const node_p node = NG_HOOK_NODE(hook);
399 	const priv_p priv = NG_NODE_PRIVATE(node);
400 
401 	if (priv->cfg.enable) {
402 	    if (priv->compress)
403 		deflateEnd(&priv->cx);
404 	    else
405 		inflateEnd(&priv->cx);
406 	    priv->cfg.enable = 0;
407 	}
408 
409 	/* Go away if no longer connected. */
410 	if ((NG_NODE_NUMHOOKS(node) == 0) && NG_NODE_IS_VALID(node))
411 		ng_rmnode_self(node);
412 	return (0);
413 }
414 
415 /************************************************************************
416 			HELPER STUFF
417  ************************************************************************/
418 
419 /*
420  * Space allocation and freeing routines for use by zlib routines.
421  */
422 
423 static void *
424 z_alloc(void *notused, u_int items, u_int size)
425 {
426 
427 	return (kmalloc(items * size, M_NETGRAPH_DEFLATE, M_WAITOK | M_NULLOK));
428 }
429 
430 static void
431 z_free(void *notused, void *ptr)
432 {
433 
434 	kfree(ptr, M_NETGRAPH_DEFLATE);
435 }
436 
437 /*
438  * Compress/encrypt a packet and put the result in a new mbuf at *resultp.
439  * The original mbuf is not free'd.
440  */
441 static int
442 ng_deflate_compress(node_p node, struct mbuf *m, struct mbuf **resultp)
443 {
444 	const priv_p 	priv = NG_NODE_PRIVATE(node);
445 	int 		outlen, inlen;
446 	int 		rtn;
447 
448 	/* Initialize. */
449 	*resultp = NULL;
450 
451 	inlen = m->m_pkthdr.len;
452 
453 	priv->stats.FramesPlain++;
454 	priv->stats.InOctets+=inlen;
455 
456 	if (inlen > DEFLATE_BUF_SIZE) {
457 		priv->stats.Errors++;
458 		NG_FREE_M(m);
459 		return (ENOMEM);
460 	}
461 
462 	/* Work with contiguous regions of memory. */
463 	m_copydata(m, 0, inlen, priv->inbuf);
464 	outlen = DEFLATE_BUF_SIZE;
465 
466 	/* Compress "inbuf" into "outbuf". */
467 	/* Prepare to compress. */
468 	if (priv->inbuf[0] != 0) {
469 		priv->cx.next_in = priv->inbuf;
470 		priv->cx.avail_in = inlen;
471 	} else {
472 		priv->cx.next_in = priv->inbuf + 1; /* compress protocol */
473 		priv->cx.avail_in = inlen - 1;
474 	}
475 	priv->cx.next_out = priv->outbuf + 2 + DEFLATE_HDRLEN;
476 	priv->cx.avail_out = outlen - 2 - DEFLATE_HDRLEN;
477 
478 	/* Compress. */
479 	rtn = deflate(&priv->cx, Z_PACKET_FLUSH);
480 
481 	/* Check return value. */
482 	if (rtn != Z_OK) {
483 		priv->stats.Errors++;
484 		log(LOG_NOTICE, "ng_deflate: compression error: %d (%s)\n",
485 		    rtn, priv->cx.msg);
486 		NG_FREE_M(m);
487 		return (EINVAL);
488 	}
489 
490 	/* Calculate resulting size. */
491 	outlen -= priv->cx.avail_out;
492 
493 	/* If we can't compress this packet, send it as-is. */
494 	if (outlen > inlen) {
495 		/* Return original packet uncompressed. */
496 		*resultp = m;
497 		priv->stats.FramesUncomp++;
498 		priv->stats.OutOctets+=inlen;
499 	} else {
500 		NG_FREE_M(m);
501 
502 		/* Install header. */
503 		((u_int16_t *)priv->outbuf)[0] = htons(PROT_COMPD);
504 		((u_int16_t *)priv->outbuf)[1] = htons(priv->seqnum);
505 
506 		/* Return packet in an mbuf. */
507 		*resultp = m_devget(priv->outbuf, outlen, 0, NULL);
508 		if (*resultp == NULL) {
509 			priv->stats.Errors++;
510 			return (ENOMEM);
511 		}
512 		priv->stats.FramesComp++;
513 		priv->stats.OutOctets+=outlen;
514 	}
515 
516 	/* Update sequence number. */
517 	priv->seqnum++;
518 
519 	return (0);
520 }
521 
522 /*
523  * Decompress/decrypt packet and put the result in a new mbuf at *resultp.
524  * The original mbuf is not free'd.
525  */
526 static int
527 ng_deflate_decompress(node_p node, struct mbuf *m, struct mbuf **resultp)
528 {
529 	const priv_p 	priv = NG_NODE_PRIVATE(node);
530 	int 		outlen, inlen;
531 	int 		rtn;
532 	uint16_t	proto;
533 	int		offset;
534 	uint16_t	rseqnum;
535 
536 	/* Initialize. */
537 	*resultp = NULL;
538 
539 	inlen = m->m_pkthdr.len;
540 
541 	if (inlen > DEFLATE_BUF_SIZE) {
542 		priv->stats.Errors++;
543 		NG_FREE_M(m);
544 		priv->seqnum = 0;
545 		return (ENOMEM);
546 	}
547 
548 	/* Work with contiguous regions of memory. */
549 	m_copydata(m, 0, inlen, priv->inbuf);
550 
551 	/* Separate proto. */
552 	if ((priv->inbuf[0] & 0x01) != 0) {
553 		proto = priv->inbuf[0];
554 		offset = 1;
555 	} else {
556 		proto = ntohs(((uint16_t *)priv->inbuf)[0]);
557 		offset = 2;
558 	}
559 
560 	priv->stats.InOctets += inlen;
561 
562 	/* Packet is compressed, so decompress. */
563 	if (proto == PROT_COMPD) {
564 		priv->stats.FramesComp++;
565 
566 		/* Check sequence number. */
567 		rseqnum = ntohs(((uint16_t *)(priv->inbuf + offset))[0]);
568 		offset += 2;
569 		if (rseqnum != priv->seqnum) {
570 			priv->stats.Errors++;
571 			log(LOG_NOTICE, "ng_deflate: wrong sequence: %u "
572 			    "instead of %u\n", rseqnum, priv->seqnum);
573 			NG_FREE_M(m);
574 			priv->seqnum = 0;
575 			return (EPIPE);
576 		}
577 
578 		outlen = DEFLATE_BUF_SIZE;
579 
580     		/* Decompress "inbuf" into "outbuf". */
581 		/* Prepare to decompress. */
582 		priv->cx.next_in = priv->inbuf + offset;
583 		priv->cx.avail_in = inlen - offset;
584 		/* Reserve space for protocol decompression. */
585 		priv->cx.next_out = priv->outbuf + 1;
586 		priv->cx.avail_out = outlen - 1;
587 
588 		/* Decompress. */
589 		rtn = inflate(&priv->cx, Z_PACKET_FLUSH);
590 
591 		/* Check return value. */
592 		if (rtn != Z_OK && rtn != Z_STREAM_END) {
593 			priv->stats.Errors++;
594 			NG_FREE_M(m);
595 			priv->seqnum = 0;
596 			log(LOG_NOTICE, "%s: decompression error: %d (%s)\n",
597 			    __func__, rtn, priv->cx.msg);
598 
599 			switch (rtn) {
600 			case Z_MEM_ERROR:
601 				return (ENOMEM);
602 			case Z_DATA_ERROR:
603 				return (EIO);
604 			default:
605 				return (EINVAL);
606 			}
607 		}
608 
609 		/* Calculate resulting size. */
610 		outlen -= priv->cx.avail_out;
611 
612 		NG_FREE_M(m);
613 
614 		/* Decompress protocol. */
615 		if ((priv->outbuf[1] & 0x01) != 0) {
616 			priv->outbuf[0] = 0;
617 			/* Return packet in an mbuf. */
618 			*resultp = m_devget(priv->outbuf, outlen, 0, NULL);
619 		} else {
620 			outlen--;
621 			/* Return packet in an mbuf. */
622 			*resultp = m_devget(priv->outbuf + 1, outlen, 0, NULL);
623 		}
624 		if (*resultp == NULL) {
625 			priv->stats.Errors++;
626 			priv->seqnum = 0;
627 			return (ENOMEM);
628 		}
629 		priv->stats.FramesPlain++;
630 		priv->stats.OutOctets+=outlen;
631 
632 	} else { /* Packet is not compressed, just update dictionary. */
633 		priv->stats.FramesUncomp++;
634 		if (priv->inbuf[0] == 0) {
635 		    priv->cx.next_in = priv->inbuf + 1; /* compress protocol */
636 		    priv->cx.avail_in = inlen - 1;
637 		} else {
638 		    priv->cx.next_in = priv->inbuf;
639 		    priv->cx.avail_in = inlen;
640 		}
641 
642 		rtn = inflateIncomp(&priv->cx);
643 
644 		/* Check return value */
645 		if (rtn != Z_OK) {
646 			priv->stats.Errors++;
647 			log(LOG_NOTICE, "%s: inflateIncomp error: %d (%s)\n",
648 			    __func__, rtn, priv->cx.msg);
649 			NG_FREE_M(m);
650 			priv->seqnum = 0;
651 			return (EINVAL);
652 		}
653 
654 		*resultp = m;
655 		priv->stats.FramesPlain++;
656 		priv->stats.OutOctets += inlen;
657 	}
658 
659 	/* Update sequence number. */
660 	priv->seqnum++;
661 
662 	return (0);
663 }
664 
665 /*
666  * The peer has sent us a CCP ResetRequest, so reset our transmit state.
667  */
668 static void
669 ng_deflate_reset_req(node_p node)
670 {
671 	const priv_p priv = NG_NODE_PRIVATE(node);
672 
673 	priv->seqnum = 0;
674 	if (priv->cfg.enable) {
675 	    if (priv->compress)
676 		deflateReset(&priv->cx);
677 	    else
678 		inflateReset(&priv->cx);
679 	}
680 }
681 
682