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