]> git.saurik.com Git - apple/xnu.git/blob - bsd/netinet6/ipcomp_core.c
xnu-1699.22.81.tar.gz
[apple/xnu.git] / bsd / netinet6 / ipcomp_core.c
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 $ */
3
4 /*
5 * Copyright (C) 1999 WIDE Project.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
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.
19 *
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
30 * SUCH DAMAGE.
31 */
32
33 /*
34 * RFC2393 IP payload compression protocol (IPComp).
35 */
36
37
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/malloc.h>
41 #include <sys/mbuf.h>
42 #include <sys/domain.h>
43 #include <sys/protosw.h>
44 #include <sys/socket.h>
45 #include <sys/errno.h>
46 #include <sys/time.h>
47 #include <sys/kernel.h>
48 #include <sys/syslog.h>
49 #include <sys/queue.h>
50
51 #include <net/if.h>
52 #include <net/route.h>
53 #if ZLIB
54 #include <libkern/zlib.h>
55 #endif
56 #include <kern/cpu_number.h>
57
58 #include <netinet6/ipcomp.h>
59 #if INET6
60 #include <netinet6/ipcomp6.h>
61 #endif
62 #include <netinet6/ipsec.h>
63 #if INET6
64 #include <netinet6/ipsec6.h>
65 #endif
66
67 #include <net/net_osdep.h>
68
69 #if ZLIB
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 *);
75
76 /*
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).
81 */
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;
86
87 static z_stream deflate_stream;
88 static z_stream inflate_stream;
89 #endif /* ZLIB */
90
91 static const struct ipcomp_algorithm ipcomp_algorithms[] = {
92 #if ZLIB
93 { deflate_compress, deflate_decompress, 90 },
94 #endif /* ZLIB */
95 };
96
97 const struct ipcomp_algorithm *
98 ipcomp_algorithm_lookup(
99 #if ZLIB
100 int idx
101 #else
102 __unused int idx
103 #endif
104 )
105 {
106 #if ZLIB
107 if (idx == SADB_X_CALG_DEFLATE) {
108 /*
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).
115 */
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));
123 #if IPSEC_DEBUG
124 printf("ipcomp_algorithm_lookup: deflateInit2 failed.\n");
125 #endif
126 }
127 }
128
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));
135 #if IPSEC_DEBUG
136 printf("ipcomp_algorithm_lookup: inflateInit2 failed.\n");
137 #endif
138 }
139 }
140
141 return &ipcomp_algorithms[0];
142 }
143 #endif /* ZLIB */
144 return NULL;
145 }
146
147 #if ZLIB
148 static void *
149 deflate_alloc(
150 __unused void *aux,
151 u_int items,
152 u_int siz)
153 {
154 void *ptr;
155 ptr = _MALLOC(items * siz, M_TEMP, M_NOWAIT);
156 return ptr;
157 }
158
159 static void
160 deflate_free(
161 __unused void *aux,
162 void *ptr)
163 {
164 FREE(ptr, M_TEMP);
165 }
166
167 static int
168 deflate_common(m, md, lenp, mode)
169 struct mbuf *m;
170 struct mbuf *md;
171 size_t *lenp;
172 int mode; /* 0: compress 1: decompress */
173 {
174 struct mbuf *mprev;
175 struct mbuf *p;
176 struct mbuf *n = NULL, *n0 = NULL, **np;
177 z_stream *zs;
178 int error = 0;
179 int zerror;
180 size_t offset;
181
182 #define MOREBLOCK() \
183 do { \
184 /* keep the reply buffer into our chain */ \
185 if (n) { \
186 n->m_len = zs->total_out - offset; \
187 offset = zs->total_out; \
188 *np = n; \
189 np = &n->m_next; \
190 n = NULL; \
191 } \
192 \
193 /* get a fresh reply buffer */ \
194 MGET(n, M_DONTWAIT, MT_DATA); \
195 if (n) { \
196 MCLGET(n, M_DONTWAIT); \
197 } \
198 if (!n) { \
199 error = ENOBUFS; \
200 goto fail; \
201 } \
202 n->m_len = 0; \
203 n->m_len = M_TRAILINGSPACE(n); \
204 n->m_next = NULL; \
205 /* \
206 * if this is the first reply buffer, reserve \
207 * region for ipcomp header. \
208 */ \
209 if (*np == NULL) { \
210 n->m_len -= sizeof(struct ipcomp); \
211 n->m_data += sizeof(struct ipcomp); \
212 } \
213 \
214 zs->next_out = mtod(n, u_int8_t *); \
215 zs->avail_out = n->m_len; \
216 } while (0)
217
218 for (mprev = m; mprev && mprev->m_next != md; mprev = mprev->m_next)
219 ;
220 if (!mprev)
221 panic("md is not in m in deflate_common");
222
223
224 zs = mode ? &inflate_stream : &deflate_stream;
225 if (zs->zalloc == NULL) {
226 /*
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.
230 */
231 error = ENOBUFS;
232 goto fail;
233 }
234
235 zs->next_in = 0;
236 zs->avail_in = 0;
237 zs->next_out = 0;
238 zs->avail_out = 0;
239
240 n0 = n = NULL;
241 np = &n0;
242 offset = 0;
243 zerror = 0;
244 p = md;
245 while (p && p->m_len == 0) {
246 p = p->m_next;
247 }
248
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;
255 p = p->m_next;
256 while (p && p->m_len == 0) {
257 p = p->m_next;
258 }
259 }
260
261 /* get output buffer */
262 if (zs->next_out == NULL || zs->avail_out == 0) {
263 MOREBLOCK();
264 }
265
266 zerror = mode ? inflate(zs, Z_NO_FLUSH)
267 : deflate(zs, Z_NO_FLUSH);
268
269 if (zerror == Z_STREAM_END)
270 ; /*once more.*/
271 else if (zerror == Z_OK) {
272 /* inflate: Z_OK can indicate the end of decode */
273 if (mode && !p && zs->avail_out != 0)
274 goto terminate;
275
276 /* else once more.*/
277 } else {
278 if (zs->msg) {
279 ipseclog((LOG_ERR, "ipcomp_%scompress: "
280 "%sflate(Z_NO_FLUSH): %s\n",
281 mode ? "de" : "", mode ? "in" : "de",
282 zs->msg));
283 } else {
284 ipseclog((LOG_ERR, "ipcomp_%scompress: "
285 "%sflate(Z_NO_FLUSH): unknown error (%d)\n",
286 mode ? "de" : "", mode ? "in" : "de",
287 zerror));
288 }
289 mode ? inflateReset(zs) : deflateReset(zs);
290 /* mode ? inflateEnd(zs) : deflateEnd(zs);*/
291 error = EINVAL;
292 goto fail;
293 }
294 }
295
296 if (zerror == Z_STREAM_END)
297 goto terminate;
298
299 /* termination */
300 while (1) {
301 /* get output buffer */
302 if (zs->next_out == NULL || zs->avail_out == 0) {
303 MOREBLOCK();
304 }
305
306 zerror = mode ? inflate(zs, Z_FINISH)
307 : deflate(zs, Z_FINISH);
308
309 if (zerror == Z_STREAM_END)
310 break;
311 else if (zerror == Z_OK)
312 ; /*once more.*/
313 else {
314 if (zs->msg) {
315 ipseclog((LOG_ERR, "ipcomp_%scompress: "
316 "%sflate(Z_FINISH): %s\n",
317 mode ? "de" : "", mode ? "in" : "de",
318 zs->msg));
319 } else {
320 ipseclog((LOG_ERR, "ipcomp_%scompress: "
321 "%sflate(Z_FINISH): unknown error (%d)\n",
322 mode ? "de" : "", mode ? "in" : "de",
323 zerror));
324 }
325 mode ? inflateReset(zs) : deflateReset(zs);
326 /* mode ? inflateEnd(zs) : deflateEnd(zs); */
327 error = EINVAL;
328 goto fail;
329 }
330 }
331
332 terminate:
333 /* keep the final reply buffer into our chain */
334 if (n) {
335 n->m_len = zs->total_out - offset;
336 offset = zs->total_out;
337 *np = n;
338 np = &n->m_next;
339 n = NULL;
340 }
341
342 /* switch the mbuf to the new one */
343 mprev->m_next = n0;
344 m_freem(md);
345 *lenp = zs->total_out;
346
347 /* reset the inflate/deflate state */
348 zerror = mode ? inflateReset(zs) : deflateReset(zs);
349 if (zerror != Z_OK) {
350 /*
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.
355 */
356 if (zs->msg) {
357 ipseclog((LOG_ERR, "ipcomp_%scompress: "
358 "%sflateEnd: %s\n",
359 mode ? "de" : "", mode ? "in" : "de",
360 zs->msg));
361 } else {
362 ipseclog((LOG_ERR, "ipcomp_%scompress: "
363 "%sflateEnd: unknown error (%d)\n",
364 mode ? "de" : "", mode ? "in" : "de",
365 zerror));
366 }
367 }
368
369 return 0;
370
371 fail:
372 if (m)
373 m_freem(m);
374 if (n)
375 m_freem(n);
376 if (n0)
377 m_freem(n0);
378 return error;
379 #undef MOREBLOCK
380 }
381
382 static int
383 deflate_compress(m, md, lenp)
384 struct mbuf *m;
385 struct mbuf *md;
386 size_t *lenp;
387 {
388 if (!m)
389 panic("m == NULL in deflate_compress");
390 if (!md)
391 panic("md == NULL in deflate_compress");
392 if (!lenp)
393 panic("lenp == NULL in deflate_compress");
394
395 return deflate_common(m, md, lenp, 0);
396 }
397
398 static int
399 deflate_decompress(m, md, lenp)
400 struct mbuf *m;
401 struct mbuf *md;
402 size_t *lenp;
403 {
404 if (!m)
405 panic("m == NULL in deflate_decompress");
406 if (!md)
407 panic("md == NULL in deflate_decompress");
408 if (!lenp)
409 panic("lenp == NULL in deflate_decompress");
410
411 return deflate_common(m, md, lenp, 1);
412 }
413 #endif /* ZLIB */