1 /* $KAME: ipcomp_core.c,v 1.10 2000/02/22 14:04:23 itojun Exp $ */
4 * Copyright (C) 1999 WIDE Project.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the project nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * RFC2393 IP payload compression protocol (IPComp).
37 #if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__NetBSD__)
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/malloc.h>
45 #include <sys/domain.h>
46 #include <sys/protosw.h>
47 #include <sys/socket.h>
48 #include <sys/errno.h>
50 #include <sys/kernel.h>
51 #include <sys/syslog.h>
52 #include <sys/queue.h>
55 #include <net/route.h>
56 #include <net/netisr.h>
58 #include <kern/cpu_number.h>
60 #include <netinet/in.h>
61 #include <netinet/in_systm.h>
62 #include <netinet/ip.h>
63 #include <netinet6/ipcomp.h>
64 #include <netinet6/ipsec.h>
66 #include <net/net_osdep.h>
68 static void *deflate_alloc
__P((void *, u_int
, u_int
));
69 static void deflate_free
__P((void *, void *));
70 static int deflate_common
__P((struct mbuf
*, struct mbuf
*, size_t *, int));
71 static int deflate_compress
__P((struct mbuf
*, struct mbuf
*, size_t *));
72 static int deflate_decompress
__P((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 struct ipcomp_algorithm ipcomp_algorithms
[] = {
88 { deflate_compress
, deflate_decompress
, 90 },
93 deflate_alloc(aux
, items
, siz
)
99 MALLOC(ptr
, void *, items
* siz
, M_TEMP
, M_NOWAIT
);
104 deflate_free(aux
, ptr
)
112 deflate_common(m
, md
, lenp
, mode
)
116 int mode
; /* 0: compress 1: decompress */
120 struct mbuf
*n
, *n0
= NULL
, **np
;
125 int firsttime
, final
, flush
;
127 for (mprev
= m
; mprev
&& mprev
->m_next
!= md
; mprev
= mprev
->m_next
)
130 panic("md is not in m in deflate_common");
132 bzero(&zs
, sizeof(zs
));
133 zs
.zalloc
= deflate_alloc
;
134 zs
.zfree
= deflate_free
;
136 zerror
= mode
? inflateInit2(&zs
, deflate_window_in
)
137 : deflateInit2(&zs
, deflate_policy
, Z_DEFLATED
,
138 deflate_window_out
, deflate_memlevel
,
140 if (zerror
!= Z_OK
) {
155 * first time, we need to setup the buffer before calling
156 * compression function.
161 zerror
= mode
? inflate(&zs
, flush
)
162 : deflate(&zs
, flush
);
165 /* get input buffer */
166 if (p
&& zs
.avail_in
== 0) {
167 zs
.next_in
= mtod(p
, u_int8_t
*);
168 zs
.avail_in
= p
->m_len
;
172 flush
= Z_PARTIAL_FLUSH
;
176 /* get output buffer */
177 if (zs
.next_out
== NULL
|| zs
.avail_out
== 0) {
178 /* keep the reply buffer into our chain */
180 n
->m_len
= zs
.total_out
- offset
;
181 offset
= zs
.total_out
;
186 /* get a fresh reply buffer */
187 MGET(n
, M_DONTWAIT
, MT_DATA
);
189 MCLGET(n
, M_DONTWAIT
);
196 n
->m_len
= M_TRAILINGSPACE(n
);
199 * if this is the first reply buffer, reserve
200 * region for ipcomp header.
203 n
->m_len
-= sizeof(struct ipcomp
);
204 n
->m_data
+= sizeof(struct ipcomp
);
207 zs
.next_out
= mtod(n
, u_int8_t
*);
208 zs
.avail_out
= n
->m_len
;
211 if (zerror
== Z_OK
) {
213 * to terminate deflate/inflate process, we need to
214 * call {in,de}flate() with different flushing methods.
216 * deflate() needs at least one Z_PARTIAL_FLUSH,
217 * then use Z_FINISH until we get to the end.
218 * (if we use Z_FLUSH without Z_PARTIAL_FLUSH, deflate()
219 * will assume contiguous single output buffer, and that
220 * is not what we want)
221 * inflate() does not care about flushing method, but
222 * needs output buffer until it gets to the end.
224 * the most outer loop will be terminated with
228 /* reached end of mbuf chain */
233 } else if (final
== 2) {
234 /* terminate deflate case */
236 } else if (final
== 3) {
237 /* terminate inflate case */
240 } else if (zerror
== Z_STREAM_END
)
243 ipseclog((LOG_ERR
, "ipcomp_%scompress: %sflate: %s\n",
244 mode
? "de" : "", mode
? "in" : "de",
245 zs
.msg
? zs
.msg
: "unknown error"));
250 zerror
= mode
? inflateEnd(&zs
) : deflateEnd(&zs
);
251 if (zerror
!= Z_OK
) {
252 ipseclog((LOG_ERR
, "ipcomp_%scompress: %sflate: %s\n",
253 mode
? "de" : "", mode
? "in" : "de",
254 zs
.msg
? zs
.msg
: "unknown error"));
258 /* keep the final reply buffer into our chain */
260 n
->m_len
= zs
.total_out
- offset
;
261 offset
= zs
.total_out
;
266 /* switch the mbuf to the new one */
269 *lenp
= zs
.total_out
;
282 deflate_compress(m
, md
, lenp
)
288 panic("m == NULL in deflate_compress");
290 panic("md == NULL in deflate_compress");
292 panic("lenp == NULL in deflate_compress");
294 return deflate_common(m
, md
, lenp
, 0);
298 deflate_decompress(m
, md
, lenp
)
304 panic("m == NULL in deflate_decompress");
306 panic("md == NULL in deflate_decompress");
308 panic("lenp == NULL in deflate_decompress");
310 return deflate_common(m
, md
, lenp
, 1);