dma: factor out mail handling code
[dragonfly.git] / sys / netinet6 / ipcomp_core.c
blob3f7040f604da3f2faedde12db01ad8caa4447504
1 /* $FreeBSD: src/sys/netinet6/ipcomp_core.c,v 1.1.2.5 2003/01/11 19:10:59 ume Exp $ */
2 /* $DragonFly: src/sys/netinet6/ipcomp_core.c,v 1.7 2006/09/29 03:37:04 hsu Exp $ */
3 /* $KAME: ipcomp_core.c,v 1.25 2001/07/26 06:53:17 jinmei Exp $ */
5 /*
6 * Copyright (C) 1999 WIDE Project.
7 * All rights reserved.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the project nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
35 * RFC2393 IP payload compression protocol (IPComp).
38 #include "opt_inet.h"
39 #include "opt_inet6.h"
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/malloc.h>
44 #include <sys/mbuf.h>
45 #include <sys/domain.h>
46 #include <sys/protosw.h>
47 #include <sys/socket.h>
48 #include <sys/errno.h>
49 #include <sys/time.h>
50 #include <sys/syslog.h>
51 #include <sys/queue.h>
53 #include <net/if.h>
54 #include <net/route.h>
55 #include <netinet/in.h>
56 #include <net/netisr.h>
57 #include <net/zlib.h>
58 #include <machine/cpu.h>
60 #include <netinet6/ipcomp.h>
61 #ifdef INET6
62 #include <netinet6/ipcomp6.h>
63 #endif
64 #include <netinet6/ipsec.h>
65 #ifdef INET6
66 #include <netinet6/ipsec6.h>
67 #endif
69 #include <machine/stdarg.h>
71 #include <net/net_osdep.h>
73 static void *deflate_alloc (void *, u_int, u_int);
74 static void deflate_free (void *, void *);
75 static int deflate_common (struct mbuf *, struct mbuf *, size_t *, int);
76 static int deflate_compress (struct mbuf *, struct mbuf *, size_t *);
77 static int deflate_decompress (struct mbuf *, struct mbuf *, size_t *);
80 * We need to use default window size (2^15 = 32Kbytes as of writing) for
81 * inbound case. Otherwise we get interop problem.
82 * Use negative value to avoid Adler32 checksum. This is an undocumented
83 * feature in zlib (see ipsec wg mailing list archive in January 2000).
85 static int deflate_policy = Z_DEFAULT_COMPRESSION;
86 static int deflate_window_out = -12;
87 static const int deflate_window_in = -1 * MAX_WBITS; /* don't change it */
88 static int deflate_memlevel = MAX_MEM_LEVEL;
90 static const struct ipcomp_algorithm ipcomp_algorithms[] = {
91 { deflate_compress, deflate_decompress, 90 },
94 const struct ipcomp_algorithm *
95 ipcomp_algorithm_lookup(int idx)
98 if (idx == SADB_X_CALG_DEFLATE)
99 return &ipcomp_algorithms[0];
100 return NULL;
103 static void *
104 deflate_alloc(void *aux, u_int items, u_int siz)
106 void *ptr;
107 ptr = kmalloc(items * siz, M_TEMP, M_NOWAIT);
108 return ptr;
111 static void
112 deflate_free(void *aux, void *ptr)
114 kfree(ptr, M_TEMP);
117 static int
118 deflate_common(struct mbuf *m, struct mbuf *md, size_t *lenp,
119 int mode) /* 0: compress 1: decompress */
121 struct mbuf *mprev;
122 struct mbuf *p;
123 struct mbuf *n = NULL, *n0 = NULL, **np;
124 z_stream zs;
125 int error = 0;
126 int zerror;
127 size_t offset;
129 #define MOREBLOCK() \
130 do { \
131 /* keep the reply buffer into our chain */ \
132 if (n) { \
133 n->m_len = zs.total_out - offset; \
134 offset = zs.total_out; \
135 *np = n; \
136 np = &n->m_next; \
137 n = NULL; \
140 /* get a fresh reply buffer */ \
141 n = m_getcl(MB_DONTWAIT, MT_DATA, 0); \
142 if (!n) { \
143 error = ENOBUFS; \
144 goto fail; \
146 n->m_len = 0; \
147 n->m_len = M_TRAILINGSPACE(n); \
148 n->m_next = NULL; \
149 /* \
150 * if this is the first reply buffer, reserve \
151 * region for ipcomp header. \
152 */ \
153 if (*np == NULL) { \
154 n->m_len -= sizeof(struct ipcomp); \
155 n->m_data += sizeof(struct ipcomp); \
158 zs.next_out = mtod(n, u_int8_t *); \
159 zs.avail_out = n->m_len; \
160 } while (0)
162 for (mprev = m; mprev && mprev->m_next != md; mprev = mprev->m_next)
164 if (!mprev)
165 panic("md is not in m in deflate_common");
167 bzero(&zs, sizeof(zs));
168 zs.zalloc = deflate_alloc;
169 zs.zfree = deflate_free;
171 zerror = mode ? inflateInit2(&zs, deflate_window_in)
172 : deflateInit2(&zs, deflate_policy, Z_DEFLATED,
173 deflate_window_out, deflate_memlevel,
174 Z_DEFAULT_STRATEGY);
175 if (zerror != Z_OK) {
176 error = ENOBUFS;
177 goto fail;
180 n0 = n = NULL;
181 np = &n0;
182 offset = 0;
183 zerror = 0;
184 p = md;
185 while (p && p->m_len == 0) {
186 p = p->m_next;
189 /* input stream and output stream are available */
190 while (p && zs.avail_in == 0) {
191 /* get input buffer */
192 if (p && zs.avail_in == 0) {
193 zs.next_in = mtod(p, u_int8_t *);
194 zs.avail_in = p->m_len;
195 p = p->m_next;
196 while (p && p->m_len == 0) {
197 p = p->m_next;
201 /* get output buffer */
202 if (zs.next_out == NULL || zs.avail_out == 0) {
203 MOREBLOCK();
206 zerror = mode ? inflate(&zs, Z_NO_FLUSH)
207 : deflate(&zs, Z_NO_FLUSH);
209 if (zerror == Z_STREAM_END)
210 ; /* once more. */
211 else if (zerror == Z_OK) {
212 /* inflate: Z_OK can indicate the end of decode */
213 if (mode && !p && zs.avail_out != 0)
214 goto terminate;
215 else
216 ; /* once more. */
217 } else {
218 if (zs.msg) {
219 ipseclog((LOG_ERR, "ipcomp_%scompress: "
220 "%sflate(Z_NO_FLUSH): %s\n",
221 mode ? "de" : "", mode ? "in" : "de",
222 zs.msg));
223 } else {
224 ipseclog((LOG_ERR, "ipcomp_%scompress: "
225 "%sflate(Z_NO_FLUSH): unknown error (%d)\n",
226 mode ? "de" : "", mode ? "in" : "de",
227 zerror));
229 mode ? inflateEnd(&zs) : deflateEnd(&zs);
230 error = EINVAL;
231 goto fail;
235 if (zerror == Z_STREAM_END)
236 goto terminate;
238 /* termination */
239 while (1) {
240 /* get output buffer */
241 if (zs.next_out == NULL || zs.avail_out == 0) {
242 MOREBLOCK();
245 zerror = mode ? inflate(&zs, Z_SYNC_FLUSH)
246 : deflate(&zs, Z_FINISH);
248 if (zerror == Z_STREAM_END)
249 break;
250 else if (zerror == Z_OK) {
251 if (mode && zs.avail_out != 0)
252 goto terminate;
253 else
254 ; /* once more. */
255 } else {
256 if (zs.msg) {
257 ipseclog((LOG_ERR, "ipcomp_%scompress: "
258 "%sflate(Z_FINISH): %s\n",
259 mode ? "de" : "", mode ? "in" : "de",
260 zs.msg));
261 } else {
262 ipseclog((LOG_ERR, "ipcomp_%scompress: "
263 "%sflate(Z_FINISH): unknown error (%d)\n",
264 mode ? "de" : "", mode ? "in" : "de",
265 zerror));
267 mode ? inflateEnd(&zs) : deflateEnd(&zs);
268 error = EINVAL;
269 goto fail;
273 terminate:
274 zerror = mode ? inflateEnd(&zs) : deflateEnd(&zs);
275 if (zerror != Z_OK) {
276 if (zs.msg) {
277 ipseclog((LOG_ERR, "ipcomp_%scompress: "
278 "%sflateEnd: %s\n",
279 mode ? "de" : "", mode ? "in" : "de",
280 zs.msg));
281 } else {
282 ipseclog((LOG_ERR, "ipcomp_%scompress: "
283 "%sflateEnd: unknown error (%d)\n",
284 mode ? "de" : "", mode ? "in" : "de",
285 zerror));
287 error = EINVAL;
288 goto fail;
290 /* keep the final reply buffer into our chain */
291 if (n) {
292 n->m_len = zs.total_out - offset;
293 offset = zs.total_out;
294 *np = n;
295 np = &n->m_next;
296 n = NULL;
299 /* switch the mbuf to the new one */
300 mprev->m_next = n0;
301 m_freem(md);
302 *lenp = zs.total_out;
304 return 0;
306 fail:
307 if (m)
308 m_freem(m);
309 if (n)
310 m_freem(n);
311 if (n0)
312 m_freem(n0);
313 return error;
314 #undef MOREBLOCK
317 static int
318 deflate_compress(struct mbuf *m, struct mbuf *md, size_t *lenp)
320 if (!m)
321 panic("m == NULL in deflate_compress");
322 if (!md)
323 panic("md == NULL in deflate_compress");
324 if (!lenp)
325 panic("lenp == NULL in deflate_compress");
327 return deflate_common(m, md, lenp, 0);
330 static int
331 deflate_decompress(struct mbuf *m, struct mbuf *md, size_t *lenp)
333 if (!m)
334 panic("m == NULL in deflate_decompress");
335 if (!md)
336 panic("md == NULL in deflate_decompress");
337 if (!lenp)
338 panic("lenp == NULL in deflate_decompress");
340 return deflate_common(m, md, lenp, 1);