]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - sys/netgraph/ng_deflate.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.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 MALLOC_DEFINE(M_NETGRAPH_DEFLATE, "netgraph_deflate", "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_DONTWAIT);
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_DONTWAIT);
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