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