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
51 static 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 */
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 int ng_deflate_compress(node_p, struct mbuf *, struct mbuf **);
84 static int ng_deflate_decompress(node_p, struct mbuf *, struct mbuf **);
85 static void ng_deflate_reset_req(node_p);
86
87 /* Parse type for struct ng_deflate_config. */
88 static const struct ng_parse_struct_field ng_deflate_config_type_fields[]
89 = NG_DEFLATE_CONFIG_INFO;
90 static 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. */
96 static const struct ng_parse_struct_field ng_deflate_stats_type_fields[]
97 = NG_DEFLATE_STATS_INFO;
98 static 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. */
104 static 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 */
144 static 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 };
155 NETGRAPH_INIT(deflate, &ng_deflate_typestruct);
156
157 /* Depend on separate zlib module. */
158 MODULE_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 */
169 static int
ng_deflate_constructor(node_p node)170 ng_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 */
189 static int
ng_deflate_newhook(node_p node,hook_p hook,const char * name)190 ng_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 */
210 static int
ng_deflate_rcvmsg(node_p node,item_p item,hook_p lasthook)211 ng_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 }
311 done:
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 */
320 static int
ng_deflate_rcvdata(hook_p hook,item_p item)321 ng_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 */
367 static int
ng_deflate_shutdown(node_p node)368 ng_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 */
389 static int
ng_deflate_disconnect(hook_p hook)390 ng_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 */
417 static int
ng_deflate_compress(node_p node,struct mbuf * m,struct mbuf ** resultp)418 ng_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 */
523 static int
ng_deflate_decompress(node_p node,struct mbuf * m,struct mbuf ** resultp)524 ng_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 */
704 static void
ng_deflate_reset_req(node_p node)705 ng_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