]> git.saurik.com Git - apple/xnu.git/blame - bsd/netinet6/ipcomp_core.c
xnu-2782.30.5.tar.gz
[apple/xnu.git] / bsd / netinet6 / ipcomp_core.c
CommitLineData
9bccf70c
A
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 $ */
1c79356b
A
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
1c79356b
A
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>
fe8ab488 53#if IPCOMP_ZLIB
2d21ac55
A
54#include <libkern/zlib.h>
55#endif
1c79356b
A
56#include <kern/cpu_number.h>
57
1c79356b 58#include <netinet6/ipcomp.h>
9bccf70c
A
59#if INET6
60#include <netinet6/ipcomp6.h>
61#endif
1c79356b 62#include <netinet6/ipsec.h>
9bccf70c
A
63#if INET6
64#include <netinet6/ipsec6.h>
65#endif
1c79356b
A
66
67#include <net/net_osdep.h>
68
fe8ab488 69#if IPCOMP_ZLIB
91447636
A
70static void *deflate_alloc(void *, u_int, u_int);
71static void deflate_free(void *, void *);
72static int deflate_common(struct mbuf *, struct mbuf *, size_t *, int);
73static int deflate_compress(struct mbuf *, struct mbuf *, size_t *);
74static int deflate_decompress(struct mbuf *, struct mbuf *, size_t *);
1c79356b
A
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 */
82static int deflate_policy = Z_DEFAULT_COMPRESSION;
83static int deflate_window_out = -12;
84static const int deflate_window_in = -1 * MAX_WBITS; /* don't change it */
85static int deflate_memlevel = MAX_MEM_LEVEL;
86
9bccf70c
A
87static z_stream deflate_stream;
88static z_stream inflate_stream;
fe8ab488 89#endif /* IPCOMP_ZLIB */
9bccf70c 90
fe8ab488 91#if IPCOMP_ZLIB
9bccf70c 92static const struct ipcomp_algorithm ipcomp_algorithms[] = {
1c79356b 93 { deflate_compress, deflate_decompress, 90 },
1c79356b 94};
fe8ab488
A
95#else
96static const struct ipcomp_algorithm ipcomp_algorithms[] __unused = {};
97#endif
1c79356b 98
9bccf70c 99const struct ipcomp_algorithm *
2d21ac55 100ipcomp_algorithm_lookup(
fe8ab488 101#if IPCOMP_ZLIB
2d21ac55
A
102 int idx
103#else
104 __unused int idx
105#endif
106 )
9bccf70c 107{
fe8ab488 108#if IPCOMP_ZLIB
9bccf70c
A
109 if (idx == SADB_X_CALG_DEFLATE) {
110 /*
111 * Avert your gaze, ugly hack follows!
112 * We init here so our malloc can allocate using M_WAIT.
113 * We don't want to allocate if ipcomp isn't used, and we
114 * don't want to allocate on the input or output path.
115 * Allocation fails if we use M_NOWAIT because init allocates
116 * something like 256k (ouch).
117 */
118 if (deflate_stream.zalloc == NULL) {
119 deflate_stream.zalloc = deflate_alloc;
120 deflate_stream.zfree = deflate_free;
121 if (deflateInit2(&deflate_stream, deflate_policy, Z_DEFLATED,
122 deflate_window_out, deflate_memlevel, Z_DEFAULT_STRATEGY)) {
123 /* Allocation failed */
124 bzero(&deflate_stream, sizeof(deflate_stream));
125#if IPSEC_DEBUG
126 printf("ipcomp_algorithm_lookup: deflateInit2 failed.\n");
127#endif
128 }
129 }
130
131 if (inflate_stream.zalloc == NULL) {
132 inflate_stream.zalloc = deflate_alloc;
133 inflate_stream.zfree = deflate_free;
134 if (inflateInit2(&inflate_stream, deflate_window_in)) {
135 /* Allocation failed */
136 bzero(&inflate_stream, sizeof(inflate_stream));
137#if IPSEC_DEBUG
138 printf("ipcomp_algorithm_lookup: inflateInit2 failed.\n");
139#endif
140 }
141 }
142
143 return &ipcomp_algorithms[0];
144 }
fe8ab488 145#endif /* IPCOMP_ZLIB */
9bccf70c
A
146 return NULL;
147}
148
fe8ab488 149#if IPCOMP_ZLIB
1c79356b 150static void *
2d21ac55
A
151deflate_alloc(
152 __unused void *aux,
153 u_int items,
154 u_int siz)
1c79356b
A
155{
156 void *ptr;
2d21ac55 157 ptr = _MALLOC(items * siz, M_TEMP, M_NOWAIT);
1c79356b
A
158 return ptr;
159}
160
161static void
2d21ac55
A
162deflate_free(
163 __unused void *aux,
164 void *ptr)
1c79356b
A
165{
166 FREE(ptr, M_TEMP);
167}
168
169static int
170deflate_common(m, md, lenp, mode)
171 struct mbuf *m;
172 struct mbuf *md;
173 size_t *lenp;
174 int mode; /* 0: compress 1: decompress */
175{
176 struct mbuf *mprev;
177 struct mbuf *p;
9bccf70c
A
178 struct mbuf *n = NULL, *n0 = NULL, **np;
179 z_stream *zs;
1c79356b
A
180 int error = 0;
181 int zerror;
182 size_t offset;
9bccf70c
A
183
184#define MOREBLOCK() \
185do { \
186 /* keep the reply buffer into our chain */ \
187 if (n) { \
188 n->m_len = zs->total_out - offset; \
189 offset = zs->total_out; \
190 *np = n; \
191 np = &n->m_next; \
192 n = NULL; \
193 } \
194 \
195 /* get a fresh reply buffer */ \
196 MGET(n, M_DONTWAIT, MT_DATA); \
197 if (n) { \
198 MCLGET(n, M_DONTWAIT); \
199 } \
200 if (!n) { \
201 error = ENOBUFS; \
202 goto fail; \
203 } \
204 n->m_len = 0; \
205 n->m_len = M_TRAILINGSPACE(n); \
206 n->m_next = NULL; \
207 /* \
208 * if this is the first reply buffer, reserve \
209 * region for ipcomp header. \
210 */ \
211 if (*np == NULL) { \
212 n->m_len -= sizeof(struct ipcomp); \
213 n->m_data += sizeof(struct ipcomp); \
214 } \
215 \
216 zs->next_out = mtod(n, u_int8_t *); \
217 zs->avail_out = n->m_len; \
218} while (0)
1c79356b
A
219
220 for (mprev = m; mprev && mprev->m_next != md; mprev = mprev->m_next)
221 ;
222 if (!mprev)
223 panic("md is not in m in deflate_common");
224
1c79356b 225
9bccf70c
A
226 zs = mode ? &inflate_stream : &deflate_stream;
227 if (zs->zalloc == NULL) {
228 /*
229 * init is called in ipcomp_algorithm_lookup.
230 * if zs->zalloc is NULL, either init hasn't been called (unlikely)
231 * or init failed because of no memory.
232 */
1c79356b
A
233 error = ENOBUFS;
234 goto fail;
235 }
9bccf70c
A
236
237 zs->next_in = 0;
238 zs->avail_in = 0;
239 zs->next_out = 0;
240 zs->avail_out = 0;
1c79356b
A
241
242 n0 = n = NULL;
243 np = &n0;
244 offset = 0;
1c79356b
A
245 zerror = 0;
246 p = md;
9bccf70c
A
247 while (p && p->m_len == 0) {
248 p = p->m_next;
249 }
1c79356b 250
9bccf70c
A
251 /* input stream and output stream are available */
252 while (p && zs->avail_in == 0) {
1c79356b 253 /* get input buffer */
9bccf70c
A
254 if (p && zs->avail_in == 0) {
255 zs->next_in = mtod(p, u_int8_t *);
256 zs->avail_in = p->m_len;
1c79356b 257 p = p->m_next;
9bccf70c
A
258 while (p && p->m_len == 0) {
259 p = p->m_next;
1c79356b
A
260 }
261 }
262
263 /* get output buffer */
9bccf70c
A
264 if (zs->next_out == NULL || zs->avail_out == 0) {
265 MOREBLOCK();
266 }
1c79356b 267
9bccf70c
A
268 zerror = mode ? inflate(zs, Z_NO_FLUSH)
269 : deflate(zs, Z_NO_FLUSH);
270
271 if (zerror == Z_STREAM_END)
272 ; /*once more.*/
273 else if (zerror == Z_OK) {
274 /* inflate: Z_OK can indicate the end of decode */
275 if (mode && !p && zs->avail_out != 0)
276 goto terminate;
2d21ac55
A
277
278 /* else once more.*/
9bccf70c
A
279 } else {
280 if (zs->msg) {
281 ipseclog((LOG_ERR, "ipcomp_%scompress: "
282 "%sflate(Z_NO_FLUSH): %s\n",
283 mode ? "de" : "", mode ? "in" : "de",
284 zs->msg));
285 } else {
286 ipseclog((LOG_ERR, "ipcomp_%scompress: "
287 "%sflate(Z_NO_FLUSH): unknown error (%d)\n",
288 mode ? "de" : "", mode ? "in" : "de",
289 zerror));
1c79356b 290 }
9bccf70c
A
291 mode ? inflateReset(zs) : deflateReset(zs);
292/* mode ? inflateEnd(zs) : deflateEnd(zs);*/
293 error = EINVAL;
294 goto fail;
295 }
296 }
1c79356b 297
9bccf70c
A
298 if (zerror == Z_STREAM_END)
299 goto terminate;
300
301 /* termination */
302 while (1) {
303 /* get output buffer */
304 if (zs->next_out == NULL || zs->avail_out == 0) {
305 MOREBLOCK();
1c79356b
A
306 }
307
9bccf70c
A
308 zerror = mode ? inflate(zs, Z_FINISH)
309 : deflate(zs, Z_FINISH);
310
311 if (zerror == Z_STREAM_END)
1c79356b 312 break;
9bccf70c
A
313 else if (zerror == Z_OK)
314 ; /*once more.*/
1c79356b 315 else {
9bccf70c
A
316 if (zs->msg) {
317 ipseclog((LOG_ERR, "ipcomp_%scompress: "
318 "%sflate(Z_FINISH): %s\n",
319 mode ? "de" : "", mode ? "in" : "de",
320 zs->msg));
321 } else {
322 ipseclog((LOG_ERR, "ipcomp_%scompress: "
323 "%sflate(Z_FINISH): unknown error (%d)\n",
324 mode ? "de" : "", mode ? "in" : "de",
325 zerror));
326 }
327 mode ? inflateReset(zs) : deflateReset(zs);
328/* mode ? inflateEnd(zs) : deflateEnd(zs); */
1c79356b
A
329 error = EINVAL;
330 goto fail;
331 }
332 }
9bccf70c
A
333
334terminate:
1c79356b
A
335 /* keep the final reply buffer into our chain */
336 if (n) {
9bccf70c
A
337 n->m_len = zs->total_out - offset;
338 offset = zs->total_out;
1c79356b
A
339 *np = n;
340 np = &n->m_next;
9bccf70c 341 n = NULL;
1c79356b
A
342 }
343
344 /* switch the mbuf to the new one */
345 mprev->m_next = n0;
346 m_freem(md);
9bccf70c
A
347 *lenp = zs->total_out;
348
349 /* reset the inflate/deflate state */
350 zerror = mode ? inflateReset(zs) : deflateReset(zs);
351 if (zerror != Z_OK) {
352 /*
353 * A failure here is uncommon. If this does
354 * fail, the packet can still be used but
355 * the z_stream will be messed up so subsequent
356 * inflates/deflates will probably fail.
357 */
358 if (zs->msg) {
359 ipseclog((LOG_ERR, "ipcomp_%scompress: "
360 "%sflateEnd: %s\n",
361 mode ? "de" : "", mode ? "in" : "de",
362 zs->msg));
363 } else {
364 ipseclog((LOG_ERR, "ipcomp_%scompress: "
365 "%sflateEnd: unknown error (%d)\n",
366 mode ? "de" : "", mode ? "in" : "de",
367 zerror));
368 }
369 }
1c79356b
A
370
371 return 0;
372
373fail:
374 if (m)
375 m_freem(m);
9bccf70c
A
376 if (n)
377 m_freem(n);
1c79356b
A
378 if (n0)
379 m_freem(n0);
380 return error;
9bccf70c 381#undef MOREBLOCK
1c79356b
A
382}
383
384static int
385deflate_compress(m, md, lenp)
386 struct mbuf *m;
387 struct mbuf *md;
388 size_t *lenp;
389{
390 if (!m)
391 panic("m == NULL in deflate_compress");
392 if (!md)
393 panic("md == NULL in deflate_compress");
394 if (!lenp)
395 panic("lenp == NULL in deflate_compress");
396
397 return deflate_common(m, md, lenp, 0);
398}
399
400static int
401deflate_decompress(m, md, lenp)
402 struct mbuf *m;
403 struct mbuf *md;
404 size_t *lenp;
405{
406 if (!m)
407 panic("m == NULL in deflate_decompress");
408 if (!md)
409 panic("md == NULL in deflate_decompress");
410 if (!lenp)
411 panic("lenp == NULL in deflate_decompress");
412
413 return deflate_common(m, md, lenp, 1);
414}
fe8ab488 415#endif /* IPCOMP_ZLIB */