]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - sys/netgraph/ng_deflate.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.git] / sys / netgraph / ng_deflate.c
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