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