1 /* $FreeBSD: src/sys/netinet6/ipcomp_core.c,v 1.1.2.2 2001/07/03 11:01:54 ume Exp $ */
2 /* $KAME: ipcomp_core.c,v 1.24 2000/10/23 04:24:22 itojun 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 <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/malloc.h>
42 #include <sys/domain.h>
43 #include <sys/protosw.h>
44 #include <sys/socket.h>
45 #include <sys/errno.h>
47 #include <sys/kernel.h>
48 #include <sys/syslog.h>
49 #include <sys/queue.h>
52 #include <net/route.h>
54 #include <libkern/zlib.h>
56 #include <kern/cpu_number.h>
58 #include <netinet6/ipcomp.h>
60 #include <netinet6/ipcomp6.h>
62 #include <netinet6/ipsec.h>
64 #include <netinet6/ipsec6.h>
67 #include <net/net_osdep.h>
70 static void *deflate_alloc(void *, u_int
, u_int
);
71 static void deflate_free(void *, void *);
72 static int deflate_common(struct mbuf
*, struct mbuf
*, size_t *, int);
73 static int deflate_compress(struct mbuf
*, struct mbuf
*, size_t *);
74 static int deflate_decompress(struct mbuf
*, struct mbuf
*, size_t *);
77 * We need to use default window size (2^15 = 32Kbytes as of writing) for
78 * inbound case. Otherwise we get interop problem.
79 * Use negative value to avoid Adler32 checksum. This is an undocumented
80 * feature in zlib (see ipsec wg mailing list archive in January 2000).
82 static int deflate_policy
= Z_DEFAULT_COMPRESSION
;
83 static int deflate_window_out
= -12;
84 static const int deflate_window_in
= -1 * MAX_WBITS
; /* don't change it */
85 static int deflate_memlevel
= MAX_MEM_LEVEL
;
87 static z_stream deflate_stream
;
88 static z_stream inflate_stream
;
91 static const struct ipcomp_algorithm ipcomp_algorithms
[] = {
93 { deflate_compress
, deflate_decompress
, 90 },
97 const struct ipcomp_algorithm
*
98 ipcomp_algorithm_lookup(
107 if (idx
== SADB_X_CALG_DEFLATE
) {
109 * Avert your gaze, ugly hack follows!
110 * We init here so our malloc can allocate using M_WAIT.
111 * We don't want to allocate if ipcomp isn't used, and we
112 * don't want to allocate on the input or output path.
113 * Allocation fails if we use M_NOWAIT because init allocates
114 * something like 256k (ouch).
116 if (deflate_stream
.zalloc
== NULL
) {
117 deflate_stream
.zalloc
= deflate_alloc
;
118 deflate_stream
.zfree
= deflate_free
;
119 if (deflateInit2(&deflate_stream
, deflate_policy
, Z_DEFLATED
,
120 deflate_window_out
, deflate_memlevel
, Z_DEFAULT_STRATEGY
)) {
121 /* Allocation failed */
122 bzero(&deflate_stream
, sizeof(deflate_stream
));
124 printf("ipcomp_algorithm_lookup: deflateInit2 failed.\n");
129 if (inflate_stream
.zalloc
== NULL
) {
130 inflate_stream
.zalloc
= deflate_alloc
;
131 inflate_stream
.zfree
= deflate_free
;
132 if (inflateInit2(&inflate_stream
, deflate_window_in
)) {
133 /* Allocation failed */
134 bzero(&inflate_stream
, sizeof(inflate_stream
));
136 printf("ipcomp_algorithm_lookup: inflateInit2 failed.\n");
141 return &ipcomp_algorithms
[0];
155 ptr
= _MALLOC(items
* siz
, M_TEMP
, M_NOWAIT
);
168 deflate_common(m
, md
, lenp
, mode
)
172 int mode
; /* 0: compress 1: decompress */
176 struct mbuf
*n
= NULL
, *n0
= NULL
, **np
;
182 #define MOREBLOCK() \
184 /* keep the reply buffer into our chain */ \
186 n->m_len = zs->total_out - offset; \
187 offset = zs->total_out; \
193 /* get a fresh reply buffer */ \
194 MGET(n, M_DONTWAIT, MT_DATA); \
196 MCLGET(n, M_DONTWAIT); \
203 n->m_len = M_TRAILINGSPACE(n); \
206 * if this is the first reply buffer, reserve \
207 * region for ipcomp header. \
210 n->m_len -= sizeof(struct ipcomp); \
211 n->m_data += sizeof(struct ipcomp); \
214 zs->next_out = mtod(n, u_int8_t *); \
215 zs->avail_out = n->m_len; \
218 for (mprev
= m
; mprev
&& mprev
->m_next
!= md
; mprev
= mprev
->m_next
)
221 panic("md is not in m in deflate_common");
224 zs
= mode
? &inflate_stream
: &deflate_stream
;
225 if (zs
->zalloc
== NULL
) {
227 * init is called in ipcomp_algorithm_lookup.
228 * if zs->zalloc is NULL, either init hasn't been called (unlikely)
229 * or init failed because of no memory.
245 while (p
&& p
->m_len
== 0) {
249 /* input stream and output stream are available */
250 while (p
&& zs
->avail_in
== 0) {
251 /* get input buffer */
252 if (p
&& zs
->avail_in
== 0) {
253 zs
->next_in
= mtod(p
, u_int8_t
*);
254 zs
->avail_in
= p
->m_len
;
256 while (p
&& p
->m_len
== 0) {
261 /* get output buffer */
262 if (zs
->next_out
== NULL
|| zs
->avail_out
== 0) {
266 zerror
= mode
? inflate(zs
, Z_NO_FLUSH
)
267 : deflate(zs
, Z_NO_FLUSH
);
269 if (zerror
== Z_STREAM_END
)
271 else if (zerror
== Z_OK
) {
272 /* inflate: Z_OK can indicate the end of decode */
273 if (mode
&& !p
&& zs
->avail_out
!= 0)
279 ipseclog((LOG_ERR
, "ipcomp_%scompress: "
280 "%sflate(Z_NO_FLUSH): %s\n",
281 mode
? "de" : "", mode
? "in" : "de",
284 ipseclog((LOG_ERR
, "ipcomp_%scompress: "
285 "%sflate(Z_NO_FLUSH): unknown error (%d)\n",
286 mode
? "de" : "", mode
? "in" : "de",
289 mode
? inflateReset(zs
) : deflateReset(zs
);
290 /* mode ? inflateEnd(zs) : deflateEnd(zs);*/
296 if (zerror
== Z_STREAM_END
)
301 /* get output buffer */
302 if (zs
->next_out
== NULL
|| zs
->avail_out
== 0) {
306 zerror
= mode
? inflate(zs
, Z_FINISH
)
307 : deflate(zs
, Z_FINISH
);
309 if (zerror
== Z_STREAM_END
)
311 else if (zerror
== Z_OK
)
315 ipseclog((LOG_ERR
, "ipcomp_%scompress: "
316 "%sflate(Z_FINISH): %s\n",
317 mode
? "de" : "", mode
? "in" : "de",
320 ipseclog((LOG_ERR
, "ipcomp_%scompress: "
321 "%sflate(Z_FINISH): unknown error (%d)\n",
322 mode
? "de" : "", mode
? "in" : "de",
325 mode
? inflateReset(zs
) : deflateReset(zs
);
326 /* mode ? inflateEnd(zs) : deflateEnd(zs); */
333 /* keep the final reply buffer into our chain */
335 n
->m_len
= zs
->total_out
- offset
;
336 offset
= zs
->total_out
;
342 /* switch the mbuf to the new one */
345 *lenp
= zs
->total_out
;
347 /* reset the inflate/deflate state */
348 zerror
= mode
? inflateReset(zs
) : deflateReset(zs
);
349 if (zerror
!= Z_OK
) {
351 * A failure here is uncommon. If this does
352 * fail, the packet can still be used but
353 * the z_stream will be messed up so subsequent
354 * inflates/deflates will probably fail.
357 ipseclog((LOG_ERR
, "ipcomp_%scompress: "
359 mode
? "de" : "", mode
? "in" : "de",
362 ipseclog((LOG_ERR
, "ipcomp_%scompress: "
363 "%sflateEnd: unknown error (%d)\n",
364 mode
? "de" : "", mode
? "in" : "de",
383 deflate_compress(m
, md
, lenp
)
389 panic("m == NULL in deflate_compress");
391 panic("md == NULL in deflate_compress");
393 panic("lenp == NULL in deflate_compress");
395 return deflate_common(m
, md
, lenp
, 0);
399 deflate_decompress(m
, md
, lenp
)
405 panic("m == NULL in deflate_decompress");
407 panic("md == NULL in deflate_decompress");
409 panic("lenp == NULL in deflate_decompress");
411 return deflate_common(m
, md
, lenp
, 1);