]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - sys/netgraph/ng_deflate.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.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/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_DONTWAIT);
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_DONTWAIT);
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