xref: /freebsd/sys/netgraph/ng_deflate.c (revision 82431678fce5c893ef9c7418ad6d998ad4187de6)
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$
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 <netgraph/ng_message.h>
45 #include <netgraph/netgraph.h>
46 #include <netgraph/ng_parse.h>
47 #include <netgraph/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 = malloc(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_NOWAIT);
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_NOWAIT);
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 	free(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 (malloc(items * size, M_NETGRAPH_DEFLATE, M_NOWAIT));
428 }
429 
430 static void
431 z_free(void *notused, void *ptr)
432 {
433 
434 	free(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 	/* We must own the mbuf chain exclusively to modify it. */
463 	m = m_unshare(m, M_DONTWAIT);
464 	if (m == NULL) {
465 		priv->stats.Errors++;
466 		return (ENOMEM);
467 	}
468 
469 	/* Work with contiguous regions of memory. */
470 	m_copydata(m, 0, inlen, (caddr_t)priv->inbuf);
471 	outlen = DEFLATE_BUF_SIZE;
472 
473 	/* Compress "inbuf" into "outbuf". */
474 	/* Prepare to compress. */
475 	if (priv->inbuf[0] != 0) {
476 		priv->cx.next_in = priv->inbuf;
477 		priv->cx.avail_in = inlen;
478 	} else {
479 		priv->cx.next_in = priv->inbuf + 1; /* compress protocol */
480 		priv->cx.avail_in = inlen - 1;
481 	}
482 	priv->cx.next_out = priv->outbuf + 2 + DEFLATE_HDRLEN;
483 	priv->cx.avail_out = outlen - 2 - DEFLATE_HDRLEN;
484 
485 	/* Compress. */
486 	rtn = deflate(&priv->cx, Z_PACKET_FLUSH);
487 
488 	/* Check return value. */
489 	if (rtn != Z_OK) {
490 		priv->stats.Errors++;
491 		log(LOG_NOTICE, "ng_deflate: compression error: %d (%s)\n",
492 		    rtn, priv->cx.msg);
493 		NG_FREE_M(m);
494 		return (EINVAL);
495 	}
496 
497 	/* Calculate resulting size. */
498 	outlen -= priv->cx.avail_out;
499 
500 	/* If we can't compress this packet, send it as-is. */
501 	if (outlen > inlen) {
502 		/* Return original packet uncompressed. */
503 		*resultp = m;
504 		priv->stats.FramesUncomp++;
505 		priv->stats.OutOctets+=inlen;
506 	} else {
507 		/* Install header. */
508 		((u_int16_t *)priv->outbuf)[0] = htons(PROT_COMPD);
509 		((u_int16_t *)priv->outbuf)[1] = htons(priv->seqnum);
510 
511 		/* Return packet in an mbuf. */
512 		m_copyback(m, 0, outlen, (caddr_t)priv->outbuf);
513 		if (m->m_pkthdr.len < outlen) {
514 			m_freem(m);
515 			priv->stats.Errors++;
516 			return (ENOMEM);
517 		} else if (outlen < m->m_pkthdr.len)
518 			m_adj(m, outlen - m->m_pkthdr.len);
519 		*resultp = m;
520 		priv->stats.FramesComp++;
521 		priv->stats.OutOctets+=outlen;
522 	}
523 
524 	/* Update sequence number. */
525 	priv->seqnum++;
526 
527 	return (0);
528 }
529 
530 /*
531  * Decompress/decrypt packet and put the result in a new mbuf at *resultp.
532  * The original mbuf is not free'd.
533  */
534 static int
535 ng_deflate_decompress(node_p node, struct mbuf *m, struct mbuf **resultp)
536 {
537 	const priv_p 	priv = NG_NODE_PRIVATE(node);
538 	int 		outlen, inlen;
539 	int 		rtn;
540 	uint16_t	proto;
541 	int		offset;
542 	uint16_t	rseqnum;
543 
544 	/* Initialize. */
545 	*resultp = NULL;
546 
547 	inlen = m->m_pkthdr.len;
548 
549 	if (inlen > DEFLATE_BUF_SIZE) {
550 		priv->stats.Errors++;
551 		NG_FREE_M(m);
552 		priv->seqnum = 0;
553 		return (ENOMEM);
554 	}
555 
556 	/* We must own the mbuf chain exclusively to modify it. */
557 	m = m_unshare(m, M_DONTWAIT);
558 	if (m == NULL) {
559 		priv->stats.Errors++;
560 		return (ENOMEM);
561 	}
562 
563 	/* Work with contiguous regions of memory. */
564 	m_copydata(m, 0, inlen, (caddr_t)priv->inbuf);
565 
566 	/* Separate proto. */
567 	if ((priv->inbuf[0] & 0x01) != 0) {
568 		proto = priv->inbuf[0];
569 		offset = 1;
570 	} else {
571 		proto = ntohs(((uint16_t *)priv->inbuf)[0]);
572 		offset = 2;
573 	}
574 
575 	priv->stats.InOctets += inlen;
576 
577 	/* Packet is compressed, so decompress. */
578 	if (proto == PROT_COMPD) {
579 		priv->stats.FramesComp++;
580 
581 		/* Check sequence number. */
582 		rseqnum = ntohs(((uint16_t *)(priv->inbuf + offset))[0]);
583 		offset += 2;
584 		if (rseqnum != priv->seqnum) {
585 			priv->stats.Errors++;
586 			log(LOG_NOTICE, "ng_deflate: wrong sequence: %u "
587 			    "instead of %u\n", rseqnum, priv->seqnum);
588 			NG_FREE_M(m);
589 			priv->seqnum = 0;
590 			return (EPIPE);
591 		}
592 
593 		outlen = DEFLATE_BUF_SIZE;
594 
595     		/* Decompress "inbuf" into "outbuf". */
596 		/* Prepare to decompress. */
597 		priv->cx.next_in = priv->inbuf + offset;
598 		priv->cx.avail_in = inlen - offset;
599 		/* Reserve space for protocol decompression. */
600 		priv->cx.next_out = priv->outbuf + 1;
601 		priv->cx.avail_out = outlen - 1;
602 
603 		/* Decompress. */
604 		rtn = inflate(&priv->cx, Z_PACKET_FLUSH);
605 
606 		/* Check return value. */
607 		if (rtn != Z_OK && rtn != Z_STREAM_END) {
608 			priv->stats.Errors++;
609 			NG_FREE_M(m);
610 			priv->seqnum = 0;
611 			log(LOG_NOTICE, "%s: decompression error: %d (%s)\n",
612 			    __func__, rtn, priv->cx.msg);
613 
614 			switch (rtn) {
615 			case Z_MEM_ERROR:
616 				return (ENOMEM);
617 			case Z_DATA_ERROR:
618 				return (EIO);
619 			default:
620 				return (EINVAL);
621 			}
622 		}
623 
624 		/* Calculate resulting size. */
625 		outlen -= priv->cx.avail_out;
626 
627 		/* Decompress protocol. */
628 		if ((priv->outbuf[1] & 0x01) != 0) {
629 			priv->outbuf[0] = 0;
630 			/* Return packet in an mbuf. */
631 			m_copyback(m, 0, outlen, (caddr_t)priv->outbuf);
632 		} else {
633 			outlen--;
634 			/* Return packet in an mbuf. */
635 			m_copyback(m, 0, outlen, (caddr_t)(priv->outbuf + 1));
636 		}
637 		if (m->m_pkthdr.len < outlen) {
638 			m_freem(m);
639 			priv->stats.Errors++;
640 			priv->seqnum = 0;
641 			return (ENOMEM);
642 		} else if (outlen < m->m_pkthdr.len)
643 			m_adj(m, outlen - m->m_pkthdr.len);
644 		*resultp = m;
645 		priv->stats.FramesPlain++;
646 		priv->stats.OutOctets+=outlen;
647 
648 	} else { /* Packet is not compressed, just update dictionary. */
649 		priv->stats.FramesUncomp++;
650 		if (priv->inbuf[0] == 0) {
651 		    priv->cx.next_in = priv->inbuf + 1; /* compress protocol */
652 		    priv->cx.avail_in = inlen - 1;
653 		} else {
654 		    priv->cx.next_in = priv->inbuf;
655 		    priv->cx.avail_in = inlen;
656 		}
657 
658 		rtn = inflateIncomp(&priv->cx);
659 
660 		/* Check return value */
661 		if (rtn != Z_OK) {
662 			priv->stats.Errors++;
663 			log(LOG_NOTICE, "%s: inflateIncomp error: %d (%s)\n",
664 			    __func__, rtn, priv->cx.msg);
665 			NG_FREE_M(m);
666 			priv->seqnum = 0;
667 			return (EINVAL);
668 		}
669 
670 		*resultp = m;
671 		priv->stats.FramesPlain++;
672 		priv->stats.OutOctets += inlen;
673 	}
674 
675 	/* Update sequence number. */
676 	priv->seqnum++;
677 
678 	return (0);
679 }
680 
681 /*
682  * The peer has sent us a CCP ResetRequest, so reset our transmit state.
683  */
684 static void
685 ng_deflate_reset_req(node_p node)
686 {
687 	const priv_p priv = NG_NODE_PRIVATE(node);
688 
689 	priv->seqnum = 0;
690 	if (priv->cfg.enable) {
691 	    if (priv->compress)
692 		deflateReset(&priv->cx);
693 	    else
694 		inflateReset(&priv->cx);
695 	}
696 }
697 
698