No empty .Rs/.Re
[netbsd-mini2440.git] / sys / netinet6 / ipcomp_core.c
blobf1562ec714a95c190e827b174636eb60b2573cc4
1 /* $NetBSD: ipcomp_core.c,v 1.28 2008/05/05 13:41:30 ad Exp $ */
2 /* $KAME: ipcomp_core.c,v 1.25 2001/07/26 06:53:17 jinmei Exp $ */
4 /*
5 * Copyright (C) 1999 WIDE Project.
6 * All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following 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 * 3. Neither the name of the project nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
34 * RFC2393 IP payload compression protocol (IPComp).
37 #include <sys/cdefs.h>
38 __KERNEL_RCSID(0, "$NetBSD: ipcomp_core.c,v 1.28 2008/05/05 13:41:30 ad Exp $");
40 #include "opt_inet.h"
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/malloc.h>
45 #include <sys/mbuf.h>
46 #include <sys/domain.h>
47 #include <sys/protosw.h>
48 #include <sys/socket.h>
49 #include <sys/errno.h>
50 #include <sys/time.h>
51 #include <sys/kernel.h>
52 #include <sys/syslog.h>
53 #include <sys/queue.h>
55 #include <net/if.h>
56 #include <net/route.h>
57 #include <net/netisr.h>
58 #include <net/zlib.h>
59 #include <sys/cpu.h>
61 #include <netinet6/ipcomp.h>
62 #include <netinet6/ipsec.h>
64 #include <machine/stdarg.h>
66 #include <net/net_osdep.h>
68 static void *deflate_alloc(void *, u_int, u_int);
69 static void deflate_free(void *, void *);
70 static int deflate_common(struct mbuf *, struct mbuf *, size_t *, int);
71 static int deflate_compress(struct mbuf *, struct mbuf *, size_t *);
72 static int deflate_decompress(struct mbuf *, struct mbuf *, size_t *);
75 * We need to use default window size (2^15 = 32Kbytes as of writing) for
76 * inbound case. Otherwise we get interop problem.
77 * Use negative value to avoid Adler32 checksum. This is an undocumented
78 * feature in zlib (see ipsec wg mailing list archive in January 2000).
80 static int deflate_policy = Z_DEFAULT_COMPRESSION;
81 static int deflate_window_out = -12;
82 static const int deflate_window_in = -1 * MAX_WBITS; /* don't change it */
83 static int deflate_memlevel = MAX_MEM_LEVEL;
85 static const struct ipcomp_algorithm ipcomp_algorithms[] = {
86 { deflate_compress, deflate_decompress, 90 },
89 const struct ipcomp_algorithm *
90 ipcomp_algorithm_lookup(int idx)
93 if (idx == SADB_X_CALG_DEFLATE)
94 return &ipcomp_algorithms[0];
95 return NULL;
98 static void *
99 deflate_alloc(void *aux, u_int items, u_int siz)
101 void *ptr;
102 ptr = malloc(items * siz, M_TEMP, M_NOWAIT);
103 return ptr;
106 static void
107 deflate_free(void *aux, void *ptr)
109 free(ptr, M_TEMP);
113 * mode - 0: compress 1: decompress
116 static int
117 deflate_common(struct mbuf *m, struct mbuf *md, size_t *lenp, int mode)
119 struct mbuf *mprev;
120 struct mbuf *p;
121 struct mbuf *n = NULL, *n0 = NULL, **np;
122 z_stream zs;
123 int error = 0;
124 int zerror;
125 size_t offset;
127 #define MOREBLOCK() \
128 do { \
129 /* keep the reply buffer into our chain */ \
130 if (n) { \
131 n->m_len = zs.total_out - offset; \
132 offset = zs.total_out; \
133 *np = n; \
134 np = &n->m_next; \
135 n = NULL; \
138 /* get a fresh reply buffer */ \
139 MGET(n, M_DONTWAIT, MT_DATA); \
140 if (n) { \
141 MCLGET(n, M_DONTWAIT); \
143 if (!n) { \
144 error = ENOBUFS; \
145 goto fail; \
147 n->m_len = 0; \
148 n->m_len = M_TRAILINGSPACE(n); \
149 n->m_next = NULL; \
150 /* \
151 * if this is the first reply buffer, reserve \
152 * region for ipcomp header. \
153 */ \
154 if (*np == NULL) { \
155 n->m_len -= sizeof(struct ipcomp); \
156 n->m_data += sizeof(struct ipcomp); \
159 zs.next_out = mtod(n, u_int8_t *); \
160 zs.avail_out = n->m_len; \
161 } while (/*CONSTCOND*/ 0)
163 for (mprev = m; mprev && mprev->m_next != md; mprev = mprev->m_next)
165 if (!mprev)
166 panic("md is not in m in deflate_common");
168 memset(&zs, 0, sizeof(zs));
169 zs.zalloc = deflate_alloc;
170 zs.zfree = deflate_free;
172 zerror = mode ? inflateInit2(&zs, deflate_window_in)
173 : deflateInit2(&zs, deflate_policy, Z_DEFLATED,
174 deflate_window_out, deflate_memlevel,
175 Z_DEFAULT_STRATEGY);
176 if (zerror != Z_OK) {
177 error = ENOBUFS;
178 goto fail;
181 n0 = n = NULL;
182 np = &n0;
183 offset = 0;
184 zerror = 0;
185 p = md;
186 while (p && p->m_len == 0) {
187 p = p->m_next;
190 /* input stream and output stream are available */
191 while (p && zs.avail_in == 0) {
192 /* get input buffer */
193 if (p && zs.avail_in == 0) {
194 zs.next_in = mtod(p, u_int8_t *);
195 zs.avail_in = p->m_len;
196 p = p->m_next;
197 while (p && p->m_len == 0) {
198 p = p->m_next;
202 /* get output buffer */
203 if (zs.next_out == NULL || zs.avail_out == 0) {
204 MOREBLOCK();
207 zerror = mode ? inflate(&zs, Z_NO_FLUSH)
208 : deflate(&zs, Z_NO_FLUSH);
210 if (zerror == Z_STREAM_END)
211 ; /* once more. */
212 else if (zerror == Z_OK) {
213 /* inflate: Z_OK can indicate the end of decode */
214 if (mode && !p && zs.avail_out != 0)
215 goto terminate;
216 } else {
217 if (zs.msg) {
218 ipseclog((LOG_ERR, "ipcomp_%scompress: "
219 "%sflate(Z_NO_FLUSH): %s\n",
220 mode ? "de" : "", mode ? "in" : "de",
221 zs.msg));
222 } else {
223 ipseclog((LOG_ERR, "ipcomp_%scompress: "
224 "%sflate(Z_NO_FLUSH): unknown error (%d)\n",
225 mode ? "de" : "", mode ? "in" : "de",
226 zerror));
228 mode ? inflateEnd(&zs) : deflateEnd(&zs);
229 error = EINVAL;
230 goto fail;
234 if (zerror == Z_STREAM_END)
235 goto terminate;
237 /* termination */
238 while (1) {
239 /* get output buffer */
240 if (zs.next_out == NULL || zs.avail_out == 0) {
241 MOREBLOCK();
244 zerror = mode ? inflate(&zs, Z_SYNC_FLUSH)
245 : deflate(&zs, Z_FINISH);
247 if (zerror == Z_STREAM_END)
248 break;
249 else if (zerror == Z_OK) {
250 if (mode && zs.avail_out != 0)
251 goto terminate;
252 } else {
253 if (zs.msg) {
254 ipseclog((LOG_ERR, "ipcomp_%scompress: "
255 "%sflate(Z_FINISH): %s\n",
256 mode ? "de" : "", mode ? "in" : "de",
257 zs.msg));
258 } else {
259 ipseclog((LOG_ERR, "ipcomp_%scompress: "
260 "%sflate(Z_FINISH): unknown error (%d)\n",
261 mode ? "de" : "", mode ? "in" : "de",
262 zerror));
264 mode ? inflateEnd(&zs) : deflateEnd(&zs);
265 error = EINVAL;
266 goto fail;
270 terminate:
271 zerror = mode ? inflateEnd(&zs) : deflateEnd(&zs);
272 if (zerror != Z_OK) {
273 if (zs.msg) {
274 ipseclog((LOG_ERR, "ipcomp_%scompress: "
275 "%sflateEnd: %s\n",
276 mode ? "de" : "", mode ? "in" : "de",
277 zs.msg));
278 } else {
279 ipseclog((LOG_ERR, "ipcomp_%scompress: "
280 "%sflateEnd: unknown error (%d)\n",
281 mode ? "de" : "", mode ? "in" : "de",
282 zerror));
284 error = EINVAL;
285 goto fail;
287 /* keep the final reply buffer into our chain */
288 if (n) {
289 n->m_len = zs.total_out - offset;
290 offset = zs.total_out;
291 *np = n;
292 np = &n->m_next;
293 n = NULL;
296 /* switch the mbuf to the new one */
297 mprev->m_next = n0;
298 m_freem(md);
299 *lenp = zs.total_out;
301 return 0;
303 fail:
304 if (m)
305 m_freem(m);
306 if (n)
307 m_freem(n);
308 if (n0)
309 m_freem(n0);
310 return error;
311 #undef MOREBLOCK
314 static int
315 deflate_compress(struct mbuf *m, struct mbuf *md, size_t *lenp)
317 if (!m)
318 panic("m == NULL in deflate_compress");
319 if (!md)
320 panic("md == NULL in deflate_compress");
321 if (!lenp)
322 panic("lenp == NULL in deflate_compress");
324 return deflate_common(m, md, lenp, 0);
327 static int
328 deflate_decompress(struct mbuf *m, struct mbuf *md, size_t *lenp)
330 if (!m)
331 panic("m == NULL in deflate_decompress");
332 if (!md)
333 panic("md == NULL in deflate_decompress");
334 if (!lenp)
335 panic("lenp == NULL in deflate_decompress");
337 return deflate_common(m, md, lenp, 1);