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