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