2 * Copyright (c) 2016 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 /* $FreeBSD: src/sys/netinet6/ipcomp_core.c,v 1.1.2.2 2001/07/03 11:01:54 ume Exp $ */
30 /* $KAME: ipcomp_core.c,v 1.24 2000/10/23 04:24:22 itojun Exp $ */
33 * Copyright (C) 1999 WIDE Project.
34 * All rights reserved.
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
39 * 1. Redistributions of source code must retain the above copyright
40 * notice, this list of conditions and the following disclaimer.
41 * 2. Redistributions in binary form must reproduce the above copyright
42 * notice, this list of conditions and the following disclaimer in the
43 * documentation and/or other materials provided with the distribution.
44 * 3. Neither the name of the project nor the names of its contributors
45 * may be used to endorse or promote products derived from this software
46 * without specific prior written permission.
48 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
62 * RFC2393 IP payload compression protocol (IPComp).
66 #include <sys/param.h>
67 #include <sys/systm.h>
68 #include <sys/malloc.h>
70 #include <sys/domain.h>
71 #include <sys/protosw.h>
72 #include <sys/socket.h>
73 #include <sys/errno.h>
75 #include <sys/kernel.h>
76 #include <sys/syslog.h>
77 #include <sys/queue.h>
80 #include <net/route.h>
82 #include <libkern/zlib.h>
84 #include <kern/cpu_number.h>
86 #include <netinet6/ipcomp.h>
88 #include <netinet6/ipcomp6.h>
90 #include <netinet6/ipsec.h>
92 #include <netinet6/ipsec6.h>
95 #include <net/net_osdep.h>
98 static void *deflate_alloc(void *, u_int
, u_int
);
99 static void deflate_free(void *, void *);
100 static int deflate_common(struct mbuf
*, struct mbuf
*, size_t *, int);
101 static int deflate_compress(struct mbuf
*, struct mbuf
*, size_t *);
102 static int deflate_decompress(struct mbuf
*, struct mbuf
*, size_t *);
105 * We need to use default window size (2^15 = 32Kbytes as of writing) for
106 * inbound case. Otherwise we get interop problem.
107 * Use negative value to avoid Adler32 checksum. This is an undocumented
108 * feature in zlib (see ipsec wg mailing list archive in January 2000).
110 static int deflate_policy
= Z_DEFAULT_COMPRESSION
;
111 static int deflate_window_out
= -12;
112 static const int deflate_window_in
= -1 * MAX_WBITS
; /* don't change it */
113 static int deflate_memlevel
= MAX_MEM_LEVEL
;
115 static z_stream deflate_stream
;
116 static z_stream inflate_stream
;
117 #endif /* IPCOMP_ZLIB */
120 static const struct ipcomp_algorithm ipcomp_algorithms
[] = {
121 { deflate_compress
, deflate_decompress
, 90 },
124 static const struct ipcomp_algorithm ipcomp_algorithms
[] __unused
= {};
127 const struct ipcomp_algorithm
*
128 ipcomp_algorithm_lookup(
137 if (idx
== SADB_X_CALG_DEFLATE
) {
139 * Avert your gaze, ugly hack follows!
140 * We init here so our malloc can allocate using M_WAIT.
141 * We don't want to allocate if ipcomp isn't used, and we
142 * don't want to allocate on the input or output path.
143 * Allocation fails if we use M_NOWAIT because init allocates
144 * something like 256k (ouch).
146 if (deflate_stream
.zalloc
== NULL
) {
147 deflate_stream
.zalloc
= deflate_alloc
;
148 deflate_stream
.zfree
= deflate_free
;
149 if (deflateInit2(&deflate_stream
, deflate_policy
, Z_DEFLATED
,
150 deflate_window_out
, deflate_memlevel
, Z_DEFAULT_STRATEGY
)) {
151 /* Allocation failed */
152 bzero(&deflate_stream
, sizeof(deflate_stream
));
154 printf("ipcomp_algorithm_lookup: deflateInit2 failed.\n");
159 if (inflate_stream
.zalloc
== NULL
) {
160 inflate_stream
.zalloc
= deflate_alloc
;
161 inflate_stream
.zfree
= deflate_free
;
162 if (inflateInit2(&inflate_stream
, deflate_window_in
)) {
163 /* Allocation failed */
164 bzero(&inflate_stream
, sizeof(inflate_stream
));
166 printf("ipcomp_algorithm_lookup: inflateInit2 failed.\n");
171 return &ipcomp_algorithms
[0];
173 #endif /* IPCOMP_ZLIB */
185 ptr
= _MALLOC(items
* siz
, M_TEMP
, M_NOWAIT
);
197 /* @param mode 0: compress 1: decompress */
199 deflate_common(struct mbuf
*m
, struct mbuf
*md
, size_t *lenp
, int mode
)
203 struct mbuf
*n
= NULL
, *n0
= NULL
, **np
;
209 #define MOREBLOCK() \
211 /* keep the reply buffer into our chain */ \
213 n->m_len = zs->total_out - offset; \
214 offset = zs->total_out; \
220 /* get a fresh reply buffer */ \
221 MGET(n, M_DONTWAIT, MT_DATA); \
223 MCLGET(n, M_DONTWAIT); \
230 n->m_len = M_TRAILINGSPACE(n); \
233 * if this is the first reply buffer, reserve \
234 * region for ipcomp header. \
237 n->m_len -= sizeof(struct ipcomp); \
238 n->m_data += sizeof(struct ipcomp); \
241 zs->next_out = mtod(n, u_int8_t *); \
242 zs->avail_out = n->m_len; \
245 for (mprev
= m
; mprev
&& mprev
->m_next
!= md
; mprev
= mprev
->m_next
)
248 panic("md is not in m in deflate_common");
251 zs
= mode
? &inflate_stream
: &deflate_stream
;
252 if (zs
->zalloc
== NULL
) {
254 * init is called in ipcomp_algorithm_lookup.
255 * if zs->zalloc is NULL, either init hasn't been called (unlikely)
256 * or init failed because of no memory.
272 while (p
&& p
->m_len
== 0) {
276 /* input stream and output stream are available */
277 while (p
&& zs
->avail_in
== 0) {
278 /* get input buffer */
279 if (p
&& zs
->avail_in
== 0) {
280 zs
->next_in
= mtod(p
, u_int8_t
*);
281 zs
->avail_in
= p
->m_len
;
283 while (p
&& p
->m_len
== 0) {
288 /* get output buffer */
289 if (zs
->next_out
== NULL
|| zs
->avail_out
== 0) {
293 zerror
= mode
? inflate(zs
, Z_NO_FLUSH
)
294 : deflate(zs
, Z_NO_FLUSH
);
296 if (zerror
== Z_STREAM_END
)
298 else if (zerror
== Z_OK
) {
299 /* inflate: Z_OK can indicate the end of decode */
300 if (mode
&& !p
&& zs
->avail_out
!= 0)
306 ipseclog((LOG_ERR
, "ipcomp_%scompress: "
307 "%sflate(Z_NO_FLUSH): %s\n",
308 mode
? "de" : "", mode
? "in" : "de",
311 ipseclog((LOG_ERR
, "ipcomp_%scompress: "
312 "%sflate(Z_NO_FLUSH): unknown error (%d)\n",
313 mode
? "de" : "", mode
? "in" : "de",
316 mode
? inflateReset(zs
) : deflateReset(zs
);
317 /* mode ? inflateEnd(zs) : deflateEnd(zs);*/
323 if (zerror
== Z_STREAM_END
)
328 /* get output buffer */
329 if (zs
->next_out
== NULL
|| zs
->avail_out
== 0) {
333 zerror
= mode
? inflate(zs
, Z_FINISH
)
334 : deflate(zs
, Z_FINISH
);
336 if (zerror
== Z_STREAM_END
)
338 else if (zerror
== Z_OK
)
342 ipseclog((LOG_ERR
, "ipcomp_%scompress: "
343 "%sflate(Z_FINISH): %s\n",
344 mode
? "de" : "", mode
? "in" : "de",
347 ipseclog((LOG_ERR
, "ipcomp_%scompress: "
348 "%sflate(Z_FINISH): unknown error (%d)\n",
349 mode
? "de" : "", mode
? "in" : "de",
352 mode
? inflateReset(zs
) : deflateReset(zs
);
353 /* mode ? inflateEnd(zs) : deflateEnd(zs); */
360 /* keep the final reply buffer into our chain */
362 n
->m_len
= zs
->total_out
- offset
;
363 offset
= zs
->total_out
;
369 /* switch the mbuf to the new one */
372 *lenp
= zs
->total_out
;
374 /* reset the inflate/deflate state */
375 zerror
= mode
? inflateReset(zs
) : deflateReset(zs
);
376 if (zerror
!= Z_OK
) {
378 * A failure here is uncommon. If this does
379 * fail, the packet can still be used but
380 * the z_stream will be messed up so subsequent
381 * inflates/deflates will probably fail.
384 ipseclog((LOG_ERR
, "ipcomp_%scompress: "
386 mode
? "de" : "", mode
? "in" : "de",
389 ipseclog((LOG_ERR
, "ipcomp_%scompress: "
390 "%sflateEnd: unknown error (%d)\n",
391 mode
? "de" : "", mode
? "in" : "de",
410 deflate_compress(struct mbuf
*m
, struct mbuf
*md
, size_t *lenp
)
413 panic("m == NULL in deflate_compress");
415 panic("md == NULL in deflate_compress");
417 panic("lenp == NULL in deflate_compress");
419 return deflate_common(m
, md
, lenp
, 0);
423 deflate_decompress(struct mbuf
*m
, struct mbuf
*md
, size_t *lenp
)
426 panic("m == NULL in deflate_decompress");
428 panic("md == NULL in deflate_decompress");
430 panic("lenp == NULL in deflate_decompress");
432 return deflate_common(m
, md
, lenp
, 1);
434 #endif /* IPCOMP_ZLIB */