1df747d8aSNuno Antunes /*-
2df747d8aSNuno Antunes * Copyright (c) 2006 Alexander Motin <mav@alkar.net>
3df747d8aSNuno Antunes * All rights reserved.
4df747d8aSNuno Antunes *
5df747d8aSNuno Antunes * Redistribution and use in source and binary forms, with or without
6df747d8aSNuno Antunes * modification, are permitted provided that the following conditions
7df747d8aSNuno Antunes * are met:
8df747d8aSNuno Antunes * 1. Redistributions of source code must retain the above copyright
9df747d8aSNuno Antunes * notice unmodified, this list of conditions, and the following
10df747d8aSNuno Antunes * disclaimer.
11df747d8aSNuno Antunes * 2. Redistributions in binary form must reproduce the above copyright
12df747d8aSNuno Antunes * notice, this list of conditions and the following disclaimer in the
13df747d8aSNuno Antunes * documentation and/or other materials provided with the distribution.
14df747d8aSNuno Antunes *
15df747d8aSNuno Antunes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16df747d8aSNuno Antunes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17df747d8aSNuno Antunes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18df747d8aSNuno Antunes * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19df747d8aSNuno Antunes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20df747d8aSNuno Antunes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21df747d8aSNuno Antunes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22df747d8aSNuno Antunes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23df747d8aSNuno Antunes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24df747d8aSNuno Antunes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25df747d8aSNuno Antunes * SUCH DAMAGE.
26df747d8aSNuno Antunes *
27df747d8aSNuno Antunes * $FreeBSD: src/sys/netgraph/ng_deflate.c,v 1.3 2007/01/15 05:55:56 glebius Exp $
28df747d8aSNuno Antunes */
29df747d8aSNuno Antunes
30df747d8aSNuno Antunes /*
31df747d8aSNuno Antunes * Deflate PPP compression netgraph node type.
32df747d8aSNuno Antunes */
33df747d8aSNuno Antunes
34df747d8aSNuno Antunes #include <sys/param.h>
35df747d8aSNuno Antunes #include <sys/systm.h>
36df747d8aSNuno Antunes #include <sys/kernel.h>
37df747d8aSNuno Antunes #include <sys/mbuf.h>
38df747d8aSNuno Antunes #include <sys/malloc.h>
39df747d8aSNuno Antunes #include <sys/errno.h>
40df747d8aSNuno Antunes #include <sys/syslog.h>
41df747d8aSNuno Antunes
42df747d8aSNuno Antunes #include <net/zlib.h>
43df747d8aSNuno Antunes
44df747d8aSNuno Antunes #include <netgraph7/ng_message.h>
45df747d8aSNuno Antunes #include <netgraph7/netgraph.h>
46df747d8aSNuno Antunes #include <netgraph7/ng_parse.h>
47df747d8aSNuno Antunes #include "ng_deflate.h"
48df747d8aSNuno Antunes
49df747d8aSNuno Antunes #include "opt_netgraph.h"
50df747d8aSNuno Antunes
51df747d8aSNuno Antunes MALLOC_DEFINE(M_NETGRAPH_DEFLATE, "netgraph_deflate", "netgraph deflate node ");
52df747d8aSNuno Antunes
53df747d8aSNuno Antunes /* DEFLATE header length */
54df747d8aSNuno Antunes #define DEFLATE_HDRLEN 2
55df747d8aSNuno Antunes
56df747d8aSNuno Antunes #define PROT_COMPD 0x00fd
57df747d8aSNuno Antunes
58df747d8aSNuno Antunes #define DEFLATE_BUF_SIZE 4096
59df747d8aSNuno Antunes
60df747d8aSNuno Antunes /* Node private data */
61df747d8aSNuno Antunes struct ng_deflate_private {
62df747d8aSNuno Antunes struct ng_deflate_config cfg; /* configuration */
63df747d8aSNuno Antunes u_char inbuf[DEFLATE_BUF_SIZE]; /* input buffer */
64df747d8aSNuno Antunes u_char outbuf[DEFLATE_BUF_SIZE]; /* output buffer */
65df747d8aSNuno Antunes z_stream cx; /* compression context */
66df747d8aSNuno Antunes struct ng_deflate_stats stats; /* statistics */
67df747d8aSNuno Antunes ng_ID_t ctrlnode; /* path to controlling node */
68df747d8aSNuno Antunes uint16_t seqnum; /* sequence number */
69df747d8aSNuno Antunes u_char compress; /* compress/decompress flag */
70df747d8aSNuno Antunes };
71df747d8aSNuno Antunes typedef struct ng_deflate_private *priv_p;
72df747d8aSNuno Antunes
73df747d8aSNuno Antunes /* Netgraph node methods */
74df747d8aSNuno Antunes static ng_constructor_t ng_deflate_constructor;
75df747d8aSNuno Antunes static ng_rcvmsg_t ng_deflate_rcvmsg;
76df747d8aSNuno Antunes static ng_shutdown_t ng_deflate_shutdown;
77df747d8aSNuno Antunes static ng_newhook_t ng_deflate_newhook;
78df747d8aSNuno Antunes static ng_rcvdata_t ng_deflate_rcvdata;
79df747d8aSNuno Antunes static ng_disconnect_t ng_deflate_disconnect;
80df747d8aSNuno Antunes
81df747d8aSNuno Antunes /* Helper functions */
82df747d8aSNuno Antunes static void *z_alloc(void *, u_int items, u_int size);
83df747d8aSNuno Antunes static void z_free(void *, void *ptr);
84df747d8aSNuno Antunes static int ng_deflate_compress(node_p node,
85df747d8aSNuno Antunes struct mbuf *m, struct mbuf **resultp);
86df747d8aSNuno Antunes static int ng_deflate_decompress(node_p node,
87df747d8aSNuno Antunes struct mbuf *m, struct mbuf **resultp);
88df747d8aSNuno Antunes static void ng_deflate_reset_req(node_p node);
89df747d8aSNuno Antunes
90df747d8aSNuno Antunes /* Parse type for struct ng_deflate_config. */
91df747d8aSNuno Antunes static const struct ng_parse_struct_field ng_deflate_config_type_fields[]
92df747d8aSNuno Antunes = NG_DEFLATE_CONFIG_INFO;
93df747d8aSNuno Antunes static const struct ng_parse_type ng_deflate_config_type = {
94df747d8aSNuno Antunes &ng_parse_struct_type,
95df747d8aSNuno Antunes ng_deflate_config_type_fields
96df747d8aSNuno Antunes };
97df747d8aSNuno Antunes
98df747d8aSNuno Antunes /* Parse type for struct ng_deflate_stat. */
99df747d8aSNuno Antunes static const struct ng_parse_struct_field ng_deflate_stats_type_fields[]
100df747d8aSNuno Antunes = NG_DEFLATE_STATS_INFO;
101df747d8aSNuno Antunes static const struct ng_parse_type ng_deflate_stat_type = {
102df747d8aSNuno Antunes &ng_parse_struct_type,
103df747d8aSNuno Antunes ng_deflate_stats_type_fields
104df747d8aSNuno Antunes };
105df747d8aSNuno Antunes
106df747d8aSNuno Antunes /* List of commands and how to convert arguments to/from ASCII. */
107df747d8aSNuno Antunes static const struct ng_cmdlist ng_deflate_cmds[] = {
108df747d8aSNuno Antunes {
109df747d8aSNuno Antunes NGM_DEFLATE_COOKIE,
110df747d8aSNuno Antunes NGM_DEFLATE_CONFIG,
111df747d8aSNuno Antunes "config",
112df747d8aSNuno Antunes &ng_deflate_config_type,
113df747d8aSNuno Antunes NULL
114df747d8aSNuno Antunes },
115df747d8aSNuno Antunes {
116df747d8aSNuno Antunes NGM_DEFLATE_COOKIE,
117df747d8aSNuno Antunes NGM_DEFLATE_RESETREQ,
118df747d8aSNuno Antunes "resetreq",
119df747d8aSNuno Antunes NULL,
120df747d8aSNuno Antunes NULL
121df747d8aSNuno Antunes },
122df747d8aSNuno Antunes {
123df747d8aSNuno Antunes NGM_DEFLATE_COOKIE,
124df747d8aSNuno Antunes NGM_DEFLATE_GET_STATS,
125df747d8aSNuno Antunes "getstats",
126df747d8aSNuno Antunes NULL,
127df747d8aSNuno Antunes &ng_deflate_stat_type
128df747d8aSNuno Antunes },
129df747d8aSNuno Antunes {
130df747d8aSNuno Antunes NGM_DEFLATE_COOKIE,
131df747d8aSNuno Antunes NGM_DEFLATE_CLR_STATS,
132df747d8aSNuno Antunes "clrstats",
133df747d8aSNuno Antunes NULL,
134df747d8aSNuno Antunes NULL
135df747d8aSNuno Antunes },
136df747d8aSNuno Antunes {
137df747d8aSNuno Antunes NGM_DEFLATE_COOKIE,
138df747d8aSNuno Antunes NGM_DEFLATE_GETCLR_STATS,
139df747d8aSNuno Antunes "getclrstats",
140df747d8aSNuno Antunes NULL,
141df747d8aSNuno Antunes &ng_deflate_stat_type
142df747d8aSNuno Antunes },
143df747d8aSNuno Antunes { 0 }
144df747d8aSNuno Antunes };
145df747d8aSNuno Antunes
146df747d8aSNuno Antunes /* Node type descriptor */
147df747d8aSNuno Antunes static struct ng_type ng_deflate_typestruct = {
148df747d8aSNuno Antunes .version = NG_ABI_VERSION,
149df747d8aSNuno Antunes .name = NG_DEFLATE_NODE_TYPE,
150df747d8aSNuno Antunes .constructor = ng_deflate_constructor,
151df747d8aSNuno Antunes .rcvmsg = ng_deflate_rcvmsg,
152df747d8aSNuno Antunes .shutdown = ng_deflate_shutdown,
153df747d8aSNuno Antunes .newhook = ng_deflate_newhook,
154df747d8aSNuno Antunes .rcvdata = ng_deflate_rcvdata,
155df747d8aSNuno Antunes .disconnect = ng_deflate_disconnect,
156df747d8aSNuno Antunes .cmdlist = ng_deflate_cmds,
157df747d8aSNuno Antunes };
158df747d8aSNuno Antunes NETGRAPH_INIT(deflate, &ng_deflate_typestruct);
159df747d8aSNuno Antunes
160df747d8aSNuno Antunes /* Depend on separate zlib module. */
161df747d8aSNuno Antunes MODULE_DEPEND(ng_deflate, zlib, 1, 1, 1);
162df747d8aSNuno Antunes
163df747d8aSNuno Antunes #define ERROUT(x) do { error = (x); goto done; } while (0)
164df747d8aSNuno Antunes
165df747d8aSNuno Antunes /************************************************************************
166df747d8aSNuno Antunes NETGRAPH NODE STUFF
167df747d8aSNuno Antunes ************************************************************************/
168df747d8aSNuno Antunes
169df747d8aSNuno Antunes /*
170df747d8aSNuno Antunes * Node type constructor
171df747d8aSNuno Antunes */
172df747d8aSNuno Antunes static int
ng_deflate_constructor(node_p node)173df747d8aSNuno Antunes ng_deflate_constructor(node_p node)
174df747d8aSNuno Antunes {
175df747d8aSNuno Antunes priv_p priv;
176df747d8aSNuno Antunes
177df747d8aSNuno Antunes /* Allocate private structure. */
178df747d8aSNuno Antunes priv = kmalloc(sizeof(*priv), M_NETGRAPH_DEFLATE, M_WAITOK | M_ZERO);
179df747d8aSNuno Antunes
180df747d8aSNuno Antunes NG_NODE_SET_PRIVATE(node, priv);
181df747d8aSNuno Antunes
182df747d8aSNuno Antunes /* This node is not thread safe. */
183df747d8aSNuno Antunes NG_NODE_FORCE_WRITER(node);
184df747d8aSNuno Antunes
185df747d8aSNuno Antunes /* Done */
186df747d8aSNuno Antunes return (0);
187df747d8aSNuno Antunes }
188df747d8aSNuno Antunes
189df747d8aSNuno Antunes /*
190df747d8aSNuno Antunes * Give our OK for a hook to be added.
191df747d8aSNuno Antunes */
192df747d8aSNuno Antunes static int
ng_deflate_newhook(node_p node,hook_p hook,const char * name)193df747d8aSNuno Antunes ng_deflate_newhook(node_p node, hook_p hook, const char *name)
194df747d8aSNuno Antunes {
195df747d8aSNuno Antunes const priv_p priv = NG_NODE_PRIVATE(node);
196df747d8aSNuno Antunes
197df747d8aSNuno Antunes if (NG_NODE_NUMHOOKS(node) > 0)
198df747d8aSNuno Antunes return (EINVAL);
199df747d8aSNuno Antunes
200df747d8aSNuno Antunes if (strcmp(name, NG_DEFLATE_HOOK_COMP) == 0)
201df747d8aSNuno Antunes priv->compress = 1;
202df747d8aSNuno Antunes else if (strcmp(name, NG_DEFLATE_HOOK_DECOMP) == 0)
203df747d8aSNuno Antunes priv->compress = 0;
204df747d8aSNuno Antunes else
205df747d8aSNuno Antunes return (EINVAL);
206df747d8aSNuno Antunes
207df747d8aSNuno Antunes return (0);
208df747d8aSNuno Antunes }
209df747d8aSNuno Antunes
210df747d8aSNuno Antunes /*
211df747d8aSNuno Antunes * Receive a control message
212df747d8aSNuno Antunes */
213df747d8aSNuno Antunes static int
ng_deflate_rcvmsg(node_p node,item_p item,hook_p lasthook)214df747d8aSNuno Antunes ng_deflate_rcvmsg(node_p node, item_p item, hook_p lasthook)
215df747d8aSNuno Antunes {
216df747d8aSNuno Antunes const priv_p priv = NG_NODE_PRIVATE(node);
217df747d8aSNuno Antunes struct ng_mesg *resp = NULL;
218df747d8aSNuno Antunes int error = 0;
219df747d8aSNuno Antunes struct ng_mesg *msg;
220df747d8aSNuno Antunes
221df747d8aSNuno Antunes NGI_GET_MSG(item, msg);
222df747d8aSNuno Antunes
223df747d8aSNuno Antunes if (msg->header.typecookie != NGM_DEFLATE_COOKIE)
224df747d8aSNuno Antunes ERROUT(EINVAL);
225df747d8aSNuno Antunes
226df747d8aSNuno Antunes switch (msg->header.cmd) {
227df747d8aSNuno Antunes case NGM_DEFLATE_CONFIG:
228df747d8aSNuno Antunes {
229df747d8aSNuno Antunes struct ng_deflate_config *const cfg
230df747d8aSNuno Antunes = (struct ng_deflate_config *)msg->data;
231df747d8aSNuno Antunes
232df747d8aSNuno Antunes /* Check configuration. */
233df747d8aSNuno Antunes if (msg->header.arglen != sizeof(*cfg))
234df747d8aSNuno Antunes ERROUT(EINVAL);
235df747d8aSNuno Antunes if (cfg->enable) {
236df747d8aSNuno Antunes if (cfg->windowBits < 8 || cfg->windowBits > 15)
237df747d8aSNuno Antunes ERROUT(EINVAL);
238df747d8aSNuno Antunes } else
239df747d8aSNuno Antunes cfg->windowBits = 0;
240df747d8aSNuno Antunes
241df747d8aSNuno Antunes /* Clear previous state. */
242df747d8aSNuno Antunes if (priv->cfg.enable) {
243df747d8aSNuno Antunes if (priv->compress)
244df747d8aSNuno Antunes deflateEnd(&priv->cx);
245df747d8aSNuno Antunes else
246df747d8aSNuno Antunes inflateEnd(&priv->cx);
247df747d8aSNuno Antunes priv->cfg.enable = 0;
248df747d8aSNuno Antunes }
249df747d8aSNuno Antunes
250df747d8aSNuno Antunes /* Configuration is OK, reset to it. */
251df747d8aSNuno Antunes priv->cfg = *cfg;
252df747d8aSNuno Antunes
253df747d8aSNuno Antunes if (priv->cfg.enable) {
254df747d8aSNuno Antunes priv->cx.next_in = NULL;
255df747d8aSNuno Antunes priv->cx.zalloc = z_alloc;
256df747d8aSNuno Antunes priv->cx.zfree = z_free;
257df747d8aSNuno Antunes int res;
258df747d8aSNuno Antunes if (priv->compress) {
259df747d8aSNuno Antunes if ((res = deflateInit2(&priv->cx,
260df747d8aSNuno Antunes Z_DEFAULT_COMPRESSION, Z_DEFLATED,
261df747d8aSNuno Antunes -cfg->windowBits, 8,
262df747d8aSNuno Antunes Z_DEFAULT_STRATEGY)) != Z_OK) {
263df747d8aSNuno Antunes log(LOG_NOTICE,
264df747d8aSNuno Antunes "deflateInit2: error %d, %s\n",
265df747d8aSNuno Antunes res, priv->cx.msg);
266df747d8aSNuno Antunes priv->cfg.enable = 0;
267df747d8aSNuno Antunes ERROUT(ENOMEM);
268df747d8aSNuno Antunes }
269df747d8aSNuno Antunes } else {
270df747d8aSNuno Antunes if ((res = inflateInit2(&priv->cx,
271df747d8aSNuno Antunes -cfg->windowBits)) != Z_OK) {
272df747d8aSNuno Antunes log(LOG_NOTICE,
273df747d8aSNuno Antunes "inflateInit2: error %d, %s\n",
274df747d8aSNuno Antunes res, priv->cx.msg);
275df747d8aSNuno Antunes priv->cfg.enable = 0;
276df747d8aSNuno Antunes ERROUT(ENOMEM);
277df747d8aSNuno Antunes }
278df747d8aSNuno Antunes }
279df747d8aSNuno Antunes }
280df747d8aSNuno Antunes
281df747d8aSNuno Antunes /* Initialize other state. */
282df747d8aSNuno Antunes priv->seqnum = 0;
283df747d8aSNuno Antunes
284df747d8aSNuno Antunes /* Save return address so we can send reset-req's */
285df747d8aSNuno Antunes priv->ctrlnode = NGI_RETADDR(item);
286df747d8aSNuno Antunes break;
287df747d8aSNuno Antunes }
288df747d8aSNuno Antunes
289df747d8aSNuno Antunes case NGM_DEFLATE_RESETREQ:
290df747d8aSNuno Antunes ng_deflate_reset_req(node);
291df747d8aSNuno Antunes break;
292df747d8aSNuno Antunes
293df747d8aSNuno Antunes case NGM_DEFLATE_GET_STATS:
294df747d8aSNuno Antunes case NGM_DEFLATE_CLR_STATS:
295df747d8aSNuno Antunes case NGM_DEFLATE_GETCLR_STATS:
296df747d8aSNuno Antunes /* Create response if requested. */
297df747d8aSNuno Antunes if (msg->header.cmd != NGM_DEFLATE_CLR_STATS) {
298df747d8aSNuno Antunes NG_MKRESPONSE(resp, msg,
299df747d8aSNuno Antunes sizeof(struct ng_deflate_stats), M_WAITOK | M_NULLOK);
300df747d8aSNuno Antunes if (resp == NULL)
301df747d8aSNuno Antunes ERROUT(ENOMEM);
302df747d8aSNuno Antunes bcopy(&priv->stats, resp->data,
303df747d8aSNuno Antunes sizeof(struct ng_deflate_stats));
304df747d8aSNuno Antunes }
305df747d8aSNuno Antunes
306df747d8aSNuno Antunes /* Clear stats if requested. */
307df747d8aSNuno Antunes if (msg->header.cmd != NGM_DEFLATE_GET_STATS)
308df747d8aSNuno Antunes bzero(&priv->stats,
309df747d8aSNuno Antunes sizeof(struct ng_deflate_stats));
310df747d8aSNuno Antunes break;
311df747d8aSNuno Antunes
312df747d8aSNuno Antunes default:
313df747d8aSNuno Antunes error = EINVAL;
314df747d8aSNuno Antunes break;
315df747d8aSNuno Antunes }
316df747d8aSNuno Antunes done:
317df747d8aSNuno Antunes NG_RESPOND_MSG(error, node, item, resp);
318df747d8aSNuno Antunes NG_FREE_MSG(msg);
319df747d8aSNuno Antunes return (error);
320df747d8aSNuno Antunes }
321df747d8aSNuno Antunes
322df747d8aSNuno Antunes /*
323df747d8aSNuno Antunes * Receive incoming data on our hook.
324df747d8aSNuno Antunes */
325df747d8aSNuno Antunes static int
ng_deflate_rcvdata(hook_p hook,item_p item)326df747d8aSNuno Antunes ng_deflate_rcvdata(hook_p hook, item_p item)
327df747d8aSNuno Antunes {
328df747d8aSNuno Antunes const node_p node = NG_HOOK_NODE(hook);
329df747d8aSNuno Antunes const priv_p priv = NG_NODE_PRIVATE(node);
330df747d8aSNuno Antunes struct mbuf *m, *out;
331df747d8aSNuno Antunes int error;
332df747d8aSNuno Antunes
333df747d8aSNuno Antunes if (!priv->cfg.enable) {
334df747d8aSNuno Antunes NG_FREE_ITEM(item);
335df747d8aSNuno Antunes return (ENXIO);
336df747d8aSNuno Antunes }
337df747d8aSNuno Antunes
338df747d8aSNuno Antunes NGI_GET_M(item, m);
339df747d8aSNuno Antunes /* Compress */
340df747d8aSNuno Antunes if (priv->compress) {
341df747d8aSNuno Antunes if ((error = ng_deflate_compress(node, m, &out)) != 0) {
342df747d8aSNuno Antunes NG_FREE_ITEM(item);
343df747d8aSNuno Antunes log(LOG_NOTICE, "%s: error: %d\n", __func__, error);
344df747d8aSNuno Antunes return (error);
345df747d8aSNuno Antunes }
346df747d8aSNuno Antunes
347df747d8aSNuno Antunes } else { /* Decompress */
348df747d8aSNuno Antunes if ((error = ng_deflate_decompress(node, m, &out)) != 0) {
349df747d8aSNuno Antunes NG_FREE_ITEM(item);
350df747d8aSNuno Antunes log(LOG_NOTICE, "%s: error: %d\n", __func__, error);
351df747d8aSNuno Antunes if (priv->ctrlnode != 0) {
352df747d8aSNuno Antunes struct ng_mesg *msg;
353df747d8aSNuno Antunes
354df747d8aSNuno Antunes /* Need to send a reset-request. */
355df747d8aSNuno Antunes NG_MKMESSAGE(msg, NGM_DEFLATE_COOKIE,
356df747d8aSNuno Antunes NGM_DEFLATE_RESETREQ, 0, M_WAITOK | M_NULLOK);
357df747d8aSNuno Antunes if (msg == NULL)
358df747d8aSNuno Antunes return (error);
359df747d8aSNuno Antunes NG_SEND_MSG_ID(error, node, msg,
360df747d8aSNuno Antunes priv->ctrlnode, 0);
361df747d8aSNuno Antunes }
362df747d8aSNuno Antunes return (error);
363df747d8aSNuno Antunes }
364df747d8aSNuno Antunes }
365df747d8aSNuno Antunes
366df747d8aSNuno Antunes NG_FWD_NEW_DATA(error, item, hook, out);
367df747d8aSNuno Antunes return (error);
368df747d8aSNuno Antunes }
369df747d8aSNuno Antunes
370df747d8aSNuno Antunes /*
371df747d8aSNuno Antunes * Destroy node.
372df747d8aSNuno Antunes */
373df747d8aSNuno Antunes static int
ng_deflate_shutdown(node_p node)374df747d8aSNuno Antunes ng_deflate_shutdown(node_p node)
375df747d8aSNuno Antunes {
376df747d8aSNuno Antunes const priv_p priv = NG_NODE_PRIVATE(node);
377df747d8aSNuno Antunes
378df747d8aSNuno Antunes /* Take down netgraph node. */
379df747d8aSNuno Antunes if (priv->cfg.enable) {
380df747d8aSNuno Antunes if (priv->compress)
381df747d8aSNuno Antunes deflateEnd(&priv->cx);
382df747d8aSNuno Antunes else
383df747d8aSNuno Antunes inflateEnd(&priv->cx);
384df747d8aSNuno Antunes }
385df747d8aSNuno Antunes
386df747d8aSNuno Antunes kfree(priv, M_NETGRAPH_DEFLATE);
387df747d8aSNuno Antunes NG_NODE_SET_PRIVATE(node, NULL);
388df747d8aSNuno Antunes NG_NODE_UNREF(node); /* let the node escape */
389df747d8aSNuno Antunes return (0);
390df747d8aSNuno Antunes }
391df747d8aSNuno Antunes
392df747d8aSNuno Antunes /*
393df747d8aSNuno Antunes * Hook disconnection
394df747d8aSNuno Antunes */
395df747d8aSNuno Antunes static int
ng_deflate_disconnect(hook_p hook)396df747d8aSNuno Antunes ng_deflate_disconnect(hook_p hook)
397df747d8aSNuno Antunes {
398df747d8aSNuno Antunes const node_p node = NG_HOOK_NODE(hook);
399df747d8aSNuno Antunes const priv_p priv = NG_NODE_PRIVATE(node);
400df747d8aSNuno Antunes
401df747d8aSNuno Antunes if (priv->cfg.enable) {
402df747d8aSNuno Antunes if (priv->compress)
403df747d8aSNuno Antunes deflateEnd(&priv->cx);
404df747d8aSNuno Antunes else
405df747d8aSNuno Antunes inflateEnd(&priv->cx);
406df747d8aSNuno Antunes priv->cfg.enable = 0;
407df747d8aSNuno Antunes }
408df747d8aSNuno Antunes
409df747d8aSNuno Antunes /* Go away if no longer connected. */
410df747d8aSNuno Antunes if ((NG_NODE_NUMHOOKS(node) == 0) && NG_NODE_IS_VALID(node))
411df747d8aSNuno Antunes ng_rmnode_self(node);
412df747d8aSNuno Antunes return (0);
413df747d8aSNuno Antunes }
414df747d8aSNuno Antunes
415df747d8aSNuno Antunes /************************************************************************
416df747d8aSNuno Antunes HELPER STUFF
417df747d8aSNuno Antunes ************************************************************************/
418df747d8aSNuno Antunes
419df747d8aSNuno Antunes /*
420df747d8aSNuno Antunes * Space allocation and freeing routines for use by zlib routines.
421df747d8aSNuno Antunes */
422df747d8aSNuno Antunes
423df747d8aSNuno Antunes static void *
z_alloc(void * notused,u_int items,u_int size)424df747d8aSNuno Antunes z_alloc(void *notused, u_int items, u_int size)
425df747d8aSNuno Antunes {
426df747d8aSNuno Antunes
427df747d8aSNuno Antunes return (kmalloc(items * size, M_NETGRAPH_DEFLATE, M_WAITOK | M_NULLOK));
428df747d8aSNuno Antunes }
429df747d8aSNuno Antunes
430df747d8aSNuno Antunes static void
z_free(void * notused,void * ptr)431df747d8aSNuno Antunes z_free(void *notused, void *ptr)
432df747d8aSNuno Antunes {
433df747d8aSNuno Antunes
434df747d8aSNuno Antunes kfree(ptr, M_NETGRAPH_DEFLATE);
435df747d8aSNuno Antunes }
436df747d8aSNuno Antunes
437df747d8aSNuno Antunes /*
438df747d8aSNuno Antunes * Compress/encrypt a packet and put the result in a new mbuf at *resultp.
439df747d8aSNuno Antunes * The original mbuf is not free'd.
440df747d8aSNuno Antunes */
441df747d8aSNuno Antunes static int
ng_deflate_compress(node_p node,struct mbuf * m,struct mbuf ** resultp)442df747d8aSNuno Antunes ng_deflate_compress(node_p node, struct mbuf *m, struct mbuf **resultp)
443df747d8aSNuno Antunes {
444df747d8aSNuno Antunes const priv_p priv = NG_NODE_PRIVATE(node);
445df747d8aSNuno Antunes int outlen, inlen;
446df747d8aSNuno Antunes int rtn;
447df747d8aSNuno Antunes
448df747d8aSNuno Antunes /* Initialize. */
449df747d8aSNuno Antunes *resultp = NULL;
450df747d8aSNuno Antunes
451df747d8aSNuno Antunes inlen = m->m_pkthdr.len;
452df747d8aSNuno Antunes
453df747d8aSNuno Antunes priv->stats.FramesPlain++;
454df747d8aSNuno Antunes priv->stats.InOctets+=inlen;
455df747d8aSNuno Antunes
456df747d8aSNuno Antunes if (inlen > DEFLATE_BUF_SIZE) {
457df747d8aSNuno Antunes priv->stats.Errors++;
458df747d8aSNuno Antunes NG_FREE_M(m);
459df747d8aSNuno Antunes return (ENOMEM);
460df747d8aSNuno Antunes }
461df747d8aSNuno Antunes
462df747d8aSNuno Antunes /* Work with contiguous regions of memory. */
463*05d02a38SAaron LI m_copydata(m, 0, inlen, priv->inbuf);
464df747d8aSNuno Antunes outlen = DEFLATE_BUF_SIZE;
465df747d8aSNuno Antunes
466df747d8aSNuno Antunes /* Compress "inbuf" into "outbuf". */
467df747d8aSNuno Antunes /* Prepare to compress. */
468df747d8aSNuno Antunes if (priv->inbuf[0] != 0) {
469df747d8aSNuno Antunes priv->cx.next_in = priv->inbuf;
470df747d8aSNuno Antunes priv->cx.avail_in = inlen;
471df747d8aSNuno Antunes } else {
472df747d8aSNuno Antunes priv->cx.next_in = priv->inbuf + 1; /* compress protocol */
473df747d8aSNuno Antunes priv->cx.avail_in = inlen - 1;
474df747d8aSNuno Antunes }
475df747d8aSNuno Antunes priv->cx.next_out = priv->outbuf + 2 + DEFLATE_HDRLEN;
476df747d8aSNuno Antunes priv->cx.avail_out = outlen - 2 - DEFLATE_HDRLEN;
477df747d8aSNuno Antunes
478df747d8aSNuno Antunes /* Compress. */
479df747d8aSNuno Antunes rtn = deflate(&priv->cx, Z_PACKET_FLUSH);
480df747d8aSNuno Antunes
481df747d8aSNuno Antunes /* Check return value. */
482df747d8aSNuno Antunes if (rtn != Z_OK) {
483df747d8aSNuno Antunes priv->stats.Errors++;
484df747d8aSNuno Antunes log(LOG_NOTICE, "ng_deflate: compression error: %d (%s)\n",
485df747d8aSNuno Antunes rtn, priv->cx.msg);
486df747d8aSNuno Antunes NG_FREE_M(m);
487df747d8aSNuno Antunes return (EINVAL);
488df747d8aSNuno Antunes }
489df747d8aSNuno Antunes
490df747d8aSNuno Antunes /* Calculate resulting size. */
491df747d8aSNuno Antunes outlen -= priv->cx.avail_out;
492df747d8aSNuno Antunes
493df747d8aSNuno Antunes /* If we can't compress this packet, send it as-is. */
494df747d8aSNuno Antunes if (outlen > inlen) {
495df747d8aSNuno Antunes /* Return original packet uncompressed. */
496df747d8aSNuno Antunes *resultp = m;
497df747d8aSNuno Antunes priv->stats.FramesUncomp++;
498df747d8aSNuno Antunes priv->stats.OutOctets+=inlen;
499df747d8aSNuno Antunes } else {
500df747d8aSNuno Antunes NG_FREE_M(m);
501df747d8aSNuno Antunes
502df747d8aSNuno Antunes /* Install header. */
503df747d8aSNuno Antunes ((u_int16_t *)priv->outbuf)[0] = htons(PROT_COMPD);
504df747d8aSNuno Antunes ((u_int16_t *)priv->outbuf)[1] = htons(priv->seqnum);
505df747d8aSNuno Antunes
506df747d8aSNuno Antunes /* Return packet in an mbuf. */
507*05d02a38SAaron LI *resultp = m_devget(priv->outbuf, outlen, 0, NULL);
508df747d8aSNuno Antunes if (*resultp == NULL) {
509df747d8aSNuno Antunes priv->stats.Errors++;
510df747d8aSNuno Antunes return (ENOMEM);
5110fdb7d01SSascha Wildner }
512df747d8aSNuno Antunes priv->stats.FramesComp++;
513df747d8aSNuno Antunes priv->stats.OutOctets+=outlen;
514df747d8aSNuno Antunes }
515df747d8aSNuno Antunes
516df747d8aSNuno Antunes /* Update sequence number. */
517df747d8aSNuno Antunes priv->seqnum++;
518df747d8aSNuno Antunes
519df747d8aSNuno Antunes return (0);
520df747d8aSNuno Antunes }
521df747d8aSNuno Antunes
522df747d8aSNuno Antunes /*
523df747d8aSNuno Antunes * Decompress/decrypt packet and put the result in a new mbuf at *resultp.
524df747d8aSNuno Antunes * The original mbuf is not free'd.
525df747d8aSNuno Antunes */
526df747d8aSNuno Antunes static int
ng_deflate_decompress(node_p node,struct mbuf * m,struct mbuf ** resultp)527df747d8aSNuno Antunes ng_deflate_decompress(node_p node, struct mbuf *m, struct mbuf **resultp)
528df747d8aSNuno Antunes {
529df747d8aSNuno Antunes const priv_p priv = NG_NODE_PRIVATE(node);
530df747d8aSNuno Antunes int outlen, inlen;
531df747d8aSNuno Antunes int rtn;
532df747d8aSNuno Antunes uint16_t proto;
533df747d8aSNuno Antunes int offset;
534df747d8aSNuno Antunes uint16_t rseqnum;
535df747d8aSNuno Antunes
536df747d8aSNuno Antunes /* Initialize. */
537df747d8aSNuno Antunes *resultp = NULL;
538df747d8aSNuno Antunes
539df747d8aSNuno Antunes inlen = m->m_pkthdr.len;
540df747d8aSNuno Antunes
541df747d8aSNuno Antunes if (inlen > DEFLATE_BUF_SIZE) {
542df747d8aSNuno Antunes priv->stats.Errors++;
543df747d8aSNuno Antunes NG_FREE_M(m);
544df747d8aSNuno Antunes priv->seqnum = 0;
545df747d8aSNuno Antunes return (ENOMEM);
546df747d8aSNuno Antunes }
547df747d8aSNuno Antunes
548df747d8aSNuno Antunes /* Work with contiguous regions of memory. */
549*05d02a38SAaron LI m_copydata(m, 0, inlen, priv->inbuf);
550df747d8aSNuno Antunes
551df747d8aSNuno Antunes /* Separate proto. */
552df747d8aSNuno Antunes if ((priv->inbuf[0] & 0x01) != 0) {
553df747d8aSNuno Antunes proto = priv->inbuf[0];
554df747d8aSNuno Antunes offset = 1;
555df747d8aSNuno Antunes } else {
556df747d8aSNuno Antunes proto = ntohs(((uint16_t *)priv->inbuf)[0]);
557df747d8aSNuno Antunes offset = 2;
558df747d8aSNuno Antunes }
559df747d8aSNuno Antunes
560df747d8aSNuno Antunes priv->stats.InOctets += inlen;
561df747d8aSNuno Antunes
562df747d8aSNuno Antunes /* Packet is compressed, so decompress. */
563df747d8aSNuno Antunes if (proto == PROT_COMPD) {
564df747d8aSNuno Antunes priv->stats.FramesComp++;
565df747d8aSNuno Antunes
566df747d8aSNuno Antunes /* Check sequence number. */
567df747d8aSNuno Antunes rseqnum = ntohs(((uint16_t *)(priv->inbuf + offset))[0]);
568df747d8aSNuno Antunes offset += 2;
569df747d8aSNuno Antunes if (rseqnum != priv->seqnum) {
570df747d8aSNuno Antunes priv->stats.Errors++;
571df747d8aSNuno Antunes log(LOG_NOTICE, "ng_deflate: wrong sequence: %u "
572df747d8aSNuno Antunes "instead of %u\n", rseqnum, priv->seqnum);
573df747d8aSNuno Antunes NG_FREE_M(m);
574df747d8aSNuno Antunes priv->seqnum = 0;
575df747d8aSNuno Antunes return (EPIPE);
576df747d8aSNuno Antunes }
577df747d8aSNuno Antunes
578df747d8aSNuno Antunes outlen = DEFLATE_BUF_SIZE;
579df747d8aSNuno Antunes
580df747d8aSNuno Antunes /* Decompress "inbuf" into "outbuf". */
581df747d8aSNuno Antunes /* Prepare to decompress. */
582df747d8aSNuno Antunes priv->cx.next_in = priv->inbuf + offset;
583df747d8aSNuno Antunes priv->cx.avail_in = inlen - offset;
584df747d8aSNuno Antunes /* Reserve space for protocol decompression. */
585df747d8aSNuno Antunes priv->cx.next_out = priv->outbuf + 1;
586df747d8aSNuno Antunes priv->cx.avail_out = outlen - 1;
587df747d8aSNuno Antunes
588df747d8aSNuno Antunes /* Decompress. */
589df747d8aSNuno Antunes rtn = inflate(&priv->cx, Z_PACKET_FLUSH);
590df747d8aSNuno Antunes
591df747d8aSNuno Antunes /* Check return value. */
592df747d8aSNuno Antunes if (rtn != Z_OK && rtn != Z_STREAM_END) {
593df747d8aSNuno Antunes priv->stats.Errors++;
594df747d8aSNuno Antunes NG_FREE_M(m);
595df747d8aSNuno Antunes priv->seqnum = 0;
596df747d8aSNuno Antunes log(LOG_NOTICE, "%s: decompression error: %d (%s)\n",
597df747d8aSNuno Antunes __func__, rtn, priv->cx.msg);
598df747d8aSNuno Antunes
599df747d8aSNuno Antunes switch (rtn) {
600df747d8aSNuno Antunes case Z_MEM_ERROR:
601df747d8aSNuno Antunes return (ENOMEM);
602df747d8aSNuno Antunes case Z_DATA_ERROR:
603df747d8aSNuno Antunes return (EIO);
604df747d8aSNuno Antunes default:
605df747d8aSNuno Antunes return (EINVAL);
606df747d8aSNuno Antunes }
607df747d8aSNuno Antunes }
608df747d8aSNuno Antunes
609df747d8aSNuno Antunes /* Calculate resulting size. */
610df747d8aSNuno Antunes outlen -= priv->cx.avail_out;
611df747d8aSNuno Antunes
612df747d8aSNuno Antunes NG_FREE_M(m);
613df747d8aSNuno Antunes
614df747d8aSNuno Antunes /* Decompress protocol. */
615df747d8aSNuno Antunes if ((priv->outbuf[1] & 0x01) != 0) {
616df747d8aSNuno Antunes priv->outbuf[0] = 0;
617df747d8aSNuno Antunes /* Return packet in an mbuf. */
618*05d02a38SAaron LI *resultp = m_devget(priv->outbuf, outlen, 0, NULL);
619df747d8aSNuno Antunes } else {
620df747d8aSNuno Antunes outlen--;
621df747d8aSNuno Antunes /* Return packet in an mbuf. */
622*05d02a38SAaron LI *resultp = m_devget(priv->outbuf + 1, outlen, 0, NULL);
623df747d8aSNuno Antunes }
624df747d8aSNuno Antunes if (*resultp == NULL) {
625df747d8aSNuno Antunes priv->stats.Errors++;
626df747d8aSNuno Antunes priv->seqnum = 0;
627df747d8aSNuno Antunes return (ENOMEM);
6280fdb7d01SSascha Wildner }
629df747d8aSNuno Antunes priv->stats.FramesPlain++;
630df747d8aSNuno Antunes priv->stats.OutOctets+=outlen;
631df747d8aSNuno Antunes
632df747d8aSNuno Antunes } else { /* Packet is not compressed, just update dictionary. */
633df747d8aSNuno Antunes priv->stats.FramesUncomp++;
634df747d8aSNuno Antunes if (priv->inbuf[0] == 0) {
635df747d8aSNuno Antunes priv->cx.next_in = priv->inbuf + 1; /* compress protocol */
636df747d8aSNuno Antunes priv->cx.avail_in = inlen - 1;
637df747d8aSNuno Antunes } else {
638df747d8aSNuno Antunes priv->cx.next_in = priv->inbuf;
639df747d8aSNuno Antunes priv->cx.avail_in = inlen;
640df747d8aSNuno Antunes }
641df747d8aSNuno Antunes
642df747d8aSNuno Antunes rtn = inflateIncomp(&priv->cx);
643df747d8aSNuno Antunes
644df747d8aSNuno Antunes /* Check return value */
645df747d8aSNuno Antunes if (rtn != Z_OK) {
646df747d8aSNuno Antunes priv->stats.Errors++;
647df747d8aSNuno Antunes log(LOG_NOTICE, "%s: inflateIncomp error: %d (%s)\n",
648df747d8aSNuno Antunes __func__, rtn, priv->cx.msg);
649df747d8aSNuno Antunes NG_FREE_M(m);
650df747d8aSNuno Antunes priv->seqnum = 0;
651df747d8aSNuno Antunes return (EINVAL);
652df747d8aSNuno Antunes }
653df747d8aSNuno Antunes
654df747d8aSNuno Antunes *resultp = m;
655df747d8aSNuno Antunes priv->stats.FramesPlain++;
656df747d8aSNuno Antunes priv->stats.OutOctets += inlen;
657df747d8aSNuno Antunes }
658df747d8aSNuno Antunes
659df747d8aSNuno Antunes /* Update sequence number. */
660df747d8aSNuno Antunes priv->seqnum++;
661df747d8aSNuno Antunes
662df747d8aSNuno Antunes return (0);
663df747d8aSNuno Antunes }
664df747d8aSNuno Antunes
665df747d8aSNuno Antunes /*
666df747d8aSNuno Antunes * The peer has sent us a CCP ResetRequest, so reset our transmit state.
667df747d8aSNuno Antunes */
668df747d8aSNuno Antunes static void
ng_deflate_reset_req(node_p node)669df747d8aSNuno Antunes ng_deflate_reset_req(node_p node)
670df747d8aSNuno Antunes {
671df747d8aSNuno Antunes const priv_p priv = NG_NODE_PRIVATE(node);
672df747d8aSNuno Antunes
673df747d8aSNuno Antunes priv->seqnum = 0;
674df747d8aSNuno Antunes if (priv->cfg.enable) {
675df747d8aSNuno Antunes if (priv->compress)
676df747d8aSNuno Antunes deflateReset(&priv->cx);
677df747d8aSNuno Antunes else
678df747d8aSNuno Antunes inflateReset(&priv->cx);
679df747d8aSNuno Antunes }
680df747d8aSNuno Antunes }
681df747d8aSNuno Antunes
682