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 $ */
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).
37 #include <sys/cdefs.h>
38 __KERNEL_RCSID(0, "$NetBSD: ipcomp_core.c,v 1.28 2008/05/05 13:41:30 ad Exp $");
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/malloc.h>
46 #include <sys/domain.h>
47 #include <sys/protosw.h>
48 #include <sys/socket.h>
49 #include <sys/errno.h>
51 #include <sys/kernel.h>
52 #include <sys/syslog.h>
53 #include <sys/queue.h>
56 #include <net/route.h>
57 #include <net/netisr.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];
99 deflate_alloc(void *aux
, u_int items
, u_int siz
)
102 ptr
= malloc(items
* siz
, M_TEMP
, M_NOWAIT
);
107 deflate_free(void *aux
, void *ptr
)
113 * mode - 0: compress 1: decompress
117 deflate_common(struct mbuf
*m
, struct mbuf
*md
, size_t *lenp
, int mode
)
121 struct mbuf
*n
= NULL
, *n0
= NULL
, **np
;
127 #define MOREBLOCK() \
129 /* keep the reply buffer into our chain */ \
131 n->m_len = zs.total_out - offset; \
132 offset = zs.total_out; \
138 /* get a fresh reply buffer */ \
139 MGET(n, M_DONTWAIT, MT_DATA); \
141 MCLGET(n, M_DONTWAIT); \
148 n->m_len = M_TRAILINGSPACE(n); \
151 * if this is the first reply buffer, reserve \
152 * region for ipcomp header. \
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
)
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
,
176 if (zerror
!= Z_OK
) {
186 while (p
&& p
->m_len
== 0) {
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
;
197 while (p
&& p
->m_len
== 0) {
202 /* get output buffer */
203 if (zs
.next_out
== NULL
|| zs
.avail_out
== 0) {
207 zerror
= mode
? inflate(&zs
, Z_NO_FLUSH
)
208 : deflate(&zs
, Z_NO_FLUSH
);
210 if (zerror
== Z_STREAM_END
)
212 else if (zerror
== Z_OK
) {
213 /* inflate: Z_OK can indicate the end of decode */
214 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)
254 ipseclog((LOG_ERR
, "ipcomp_%scompress: "
255 "%sflate(Z_FINISH): %s\n",
256 mode
? "de" : "", mode
? "in" : "de",
259 ipseclog((LOG_ERR
, "ipcomp_%scompress: "
260 "%sflate(Z_FINISH): unknown error (%d)\n",
261 mode
? "de" : "", mode
? "in" : "de",
264 mode
? inflateEnd(&zs
) : deflateEnd(&zs
);
271 zerror
= mode
? inflateEnd(&zs
) : deflateEnd(&zs
);
272 if (zerror
!= Z_OK
) {
274 ipseclog((LOG_ERR
, "ipcomp_%scompress: "
276 mode
? "de" : "", mode
? "in" : "de",
279 ipseclog((LOG_ERR
, "ipcomp_%scompress: "
280 "%sflateEnd: unknown error (%d)\n",
281 mode
? "de" : "", mode
? "in" : "de",
287 /* keep the final reply buffer into our chain */
289 n
->m_len
= zs
.total_out
- offset
;
290 offset
= zs
.total_out
;
296 /* switch the mbuf to the new one */
299 *lenp
= zs
.total_out
;
315 deflate_compress(struct mbuf
*m
, struct mbuf
*md
, size_t *lenp
)
318 panic("m == NULL in deflate_compress");
320 panic("md == NULL in deflate_compress");
322 panic("lenp == NULL in deflate_compress");
324 return deflate_common(m
, md
, lenp
, 0);
328 deflate_decompress(struct mbuf
*m
, struct mbuf
*md
, size_t *lenp
)
331 panic("m == NULL in deflate_decompress");
333 panic("md == NULL in deflate_decompress");
335 panic("lenp == NULL in deflate_decompress");
337 return deflate_common(m
, md
, lenp
, 1);