1 /* $FreeBSD: src/sys/netinet6/ipcomp_core.c,v 1.1.2.5 2003/01/11 19:10:59 ume Exp $ */
2 /* $KAME: ipcomp_core.c,v 1.25 2001/07/26 06:53:17 jinmei Exp $ */
5 * Copyright (C) 1999 WIDE Project.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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
34 * RFC2393 IP payload compression protocol (IPComp).
38 #include "opt_inet6.h"
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/malloc.h>
44 #include <sys/domain.h>
45 #include <sys/protosw.h>
46 #include <sys/socket.h>
47 #include <sys/errno.h>
49 #include <sys/syslog.h>
50 #include <sys/queue.h>
53 #include <net/route.h>
54 #include <netinet/in.h>
55 #include <net/netisr.h>
57 #include <machine/cpu.h>
59 #include <netinet6/ipcomp.h>
61 #include <netinet6/ipcomp6.h>
63 #include <netinet6/ipsec.h>
65 #include <netinet6/ipsec6.h>
68 #include <machine/stdarg.h>
70 #include <net/net_osdep.h>
72 static void *deflate_alloc (void *, u_int, u_int);
73 static void deflate_free (void *, void *);
74 static int deflate_common (struct mbuf *, struct mbuf *, size_t *, int);
75 static int deflate_compress (struct mbuf *, struct mbuf *, size_t *);
76 static int deflate_decompress (struct mbuf *, struct mbuf *, size_t *);
79 * We need to use default window size (2^15 = 32Kbytes as of writing) for
80 * inbound case. Otherwise we get interop problem.
81 * Use negative value to avoid Adler32 checksum. This is an undocumented
82 * feature in zlib (see ipsec wg mailing list archive in January 2000).
84 static int deflate_policy = Z_DEFAULT_COMPRESSION;
85 static int deflate_window_out = -12;
86 static const int deflate_window_in = -1 * MAX_WBITS; /* don't change it */
87 static int deflate_memlevel = MAX_MEM_LEVEL;
89 static const struct ipcomp_algorithm ipcomp_algorithms[] = {
90 { deflate_compress, deflate_decompress, 90 },
93 const struct ipcomp_algorithm *
94 ipcomp_algorithm_lookup(int idx)
97 if (idx == SADB_X_CALG_DEFLATE)
98 return &ipcomp_algorithms[0];
103 deflate_alloc(void *aux, u_int items, u_int siz)
106 ptr = kmalloc(items * siz, M_TEMP, M_NOWAIT);
111 deflate_free(void *aux, void *ptr)
117 deflate_common(struct mbuf *m, struct mbuf *md, size_t *lenp,
118 int mode) /* 0: compress 1: decompress */
122 struct mbuf *n = NULL, *n0 = NULL, **np;
128 #define MOREBLOCK() \
130 /* keep the reply buffer into our chain */ \
132 n->m_len = zs.total_out - offset; \
133 offset = zs.total_out; \
139 /* get a fresh reply buffer */ \
140 n = m_getcl(M_NOWAIT, MT_DATA, 0); \
146 n->m_len = M_TRAILINGSPACE(n); \
149 * if this is the first reply buffer, reserve \
150 * region for ipcomp header. \
153 n->m_len -= sizeof(struct ipcomp); \
154 n->m_data += sizeof(struct ipcomp); \
157 zs.next_out = mtod(n, u_int8_t *); \
158 zs.avail_out = n->m_len; \
161 for (mprev = m; mprev && mprev->m_next != md; mprev = mprev->m_next)
164 panic("md is not in m in deflate_common");
166 bzero(&zs, sizeof(zs));
167 zs.zalloc = deflate_alloc;
168 zs.zfree = deflate_free;
170 zerror = mode ? inflateInit2(&zs, deflate_window_in)
171 : deflateInit2(&zs, deflate_policy, Z_DEFLATED,
172 deflate_window_out, deflate_memlevel,
174 if (zerror != Z_OK) {
184 while (p && p->m_len == 0) {
188 /* input stream and output stream are available */
189 while (p && zs.avail_in == 0) {
190 /* get input buffer */
191 if (p && zs.avail_in == 0) {
192 zs.next_in = mtod(p, u_int8_t *);
193 zs.avail_in = p->m_len;
195 while (p && p->m_len == 0) {
200 /* get output buffer */
201 if (zs.next_out == NULL || zs.avail_out == 0) {
205 zerror = mode ? inflate(&zs, Z_NO_FLUSH)
206 : deflate(&zs, Z_NO_FLUSH);
208 if (zerror == Z_STREAM_END)
210 else if (zerror == Z_OK) {
211 /* inflate: Z_OK can indicate the end of decode */
212 if (mode && !p && zs.avail_out != 0)
218 ipseclog((LOG_ERR, "ipcomp_%scompress: "
219 "%sflate(Z_NO_FLUSH): %s\n",
220 mode ? "de" : "", mode ? "in" : "de",
223 ipseclog((LOG_ERR, "ipcomp_%scompress: "
224 "%sflate(Z_NO_FLUSH): unknown error (%d)\n",
225 mode ? "de" : "", mode ? "in" : "de",
228 mode ? inflateEnd(&zs) : deflateEnd(&zs);
234 if (zerror == Z_STREAM_END)
239 /* get output buffer */
240 if (zs.next_out == NULL || zs.avail_out == 0) {
244 zerror = mode ? inflate(&zs, Z_SYNC_FLUSH)
245 : deflate(&zs, Z_FINISH);
247 if (zerror == Z_STREAM_END)
249 else if (zerror == Z_OK) {
250 if (mode && zs.avail_out != 0)
256 ipseclog((LOG_ERR, "ipcomp_%scompress: "
257 "%sflate(Z_FINISH): %s\n",
258 mode ? "de" : "", mode ? "in" : "de",
261 ipseclog((LOG_ERR, "ipcomp_%scompress: "
262 "%sflate(Z_FINISH): unknown error (%d)\n",
263 mode ? "de" : "", mode ? "in" : "de",
266 mode ? inflateEnd(&zs) : deflateEnd(&zs);
273 zerror = mode ? inflateEnd(&zs) : deflateEnd(&zs);
274 if (zerror != Z_OK) {
276 ipseclog((LOG_ERR, "ipcomp_%scompress: "
278 mode ? "de" : "", mode ? "in" : "de",
281 ipseclog((LOG_ERR, "ipcomp_%scompress: "
282 "%sflateEnd: unknown error (%d)\n",
283 mode ? "de" : "", mode ? "in" : "de",
289 /* keep the final reply buffer into our chain */
291 n->m_len = zs.total_out - offset;
292 offset = zs.total_out;
298 /* switch the mbuf to the new one */
301 *lenp = zs.total_out;
317 deflate_compress(struct mbuf *m, struct mbuf *md, size_t *lenp)
320 panic("m == NULL in deflate_compress");
322 panic("md == NULL in deflate_compress");
324 panic("lenp == NULL in deflate_compress");
326 return deflate_common(m, md, lenp, 0);
330 deflate_decompress(struct mbuf *m, struct mbuf *md, size_t *lenp)
333 panic("m == NULL in deflate_decompress");
335 panic("md == NULL in deflate_decompress");
337 panic("lenp == NULL in deflate_decompress");
339 return deflate_common(m, md, lenp, 1);