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