X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/1c79356b52d46aa6b508fb032f5ae709b1f2897b..91447636331957f3d9b5ca5b508f07c526b0074d:/bsd/netinet6/ipcomp_core.c diff --git a/bsd/netinet6/ipcomp_core.c b/bsd/netinet6/ipcomp_core.c index 9ef5e3d14..38f70861c 100644 --- a/bsd/netinet6/ipcomp_core.c +++ b/bsd/netinet6/ipcomp_core.c @@ -1,4 +1,5 @@ -/* $KAME: ipcomp_core.c,v 1.10 2000/02/22 14:04:23 itojun Exp $ */ +/* $FreeBSD: src/sys/netinet6/ipcomp_core.c,v 1.1.2.2 2001/07/03 11:01:54 ume Exp $ */ +/* $KAME: ipcomp_core.c,v 1.24 2000/10/23 04:24:22 itojun Exp $ */ /* * Copyright (C) 1999 WIDE Project. @@ -33,10 +34,6 @@ * RFC2393 IP payload compression protocol (IPComp). */ -#define _IP_VHL -#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__NetBSD__) -#include "opt_inet.h" -#endif #include #include @@ -53,23 +50,25 @@ #include #include -#include #include #include -#include -#include -#include #include +#if INET6 +#include +#endif #include +#if INET6 +#include +#endif #include -static void *deflate_alloc __P((void *, u_int, u_int)); -static void deflate_free __P((void *, void *)); -static int deflate_common __P((struct mbuf *, struct mbuf *, size_t *, int)); -static int deflate_compress __P((struct mbuf *, struct mbuf *, size_t *)); -static int deflate_decompress __P((struct mbuf *, struct mbuf *, size_t *)); +static void *deflate_alloc(void *, u_int, u_int); +static void deflate_free(void *, void *); +static int deflate_common(struct mbuf *, struct mbuf *, size_t *, int); +static int deflate_compress(struct mbuf *, struct mbuf *, size_t *); +static int deflate_decompress(struct mbuf *, struct mbuf *, size_t *); /* * We need to use default window size (2^15 = 32Kbytes as of writing) for @@ -82,13 +81,57 @@ static int deflate_window_out = -12; static const int deflate_window_in = -1 * MAX_WBITS; /* don't change it */ static int deflate_memlevel = MAX_MEM_LEVEL; -struct ipcomp_algorithm ipcomp_algorithms[] = { - { NULL, NULL, -1 }, - { NULL, NULL, -1 }, +static z_stream deflate_stream; +static z_stream inflate_stream; + +static const struct ipcomp_algorithm ipcomp_algorithms[] = { { deflate_compress, deflate_decompress, 90 }, - { NULL, NULL, 90 }, }; +const struct ipcomp_algorithm * +ipcomp_algorithm_lookup(idx) + int idx; +{ + + if (idx == SADB_X_CALG_DEFLATE) { + /* + * Avert your gaze, ugly hack follows! + * We init here so our malloc can allocate using M_WAIT. + * We don't want to allocate if ipcomp isn't used, and we + * don't want to allocate on the input or output path. + * Allocation fails if we use M_NOWAIT because init allocates + * something like 256k (ouch). + */ + if (deflate_stream.zalloc == NULL) { + deflate_stream.zalloc = deflate_alloc; + deflate_stream.zfree = deflate_free; + if (deflateInit2(&deflate_stream, deflate_policy, Z_DEFLATED, + deflate_window_out, deflate_memlevel, Z_DEFAULT_STRATEGY)) { + /* Allocation failed */ + bzero(&deflate_stream, sizeof(deflate_stream)); +#if IPSEC_DEBUG + printf("ipcomp_algorithm_lookup: deflateInit2 failed.\n"); +#endif + } + } + + if (inflate_stream.zalloc == NULL) { + inflate_stream.zalloc = deflate_alloc; + inflate_stream.zfree = deflate_free; + if (inflateInit2(&inflate_stream, deflate_window_in)) { + /* Allocation failed */ + bzero(&inflate_stream, sizeof(inflate_stream)); +#if IPSEC_DEBUG + printf("ipcomp_algorithm_lookup: inflateInit2 failed.\n"); +#endif + } + } + + return &ipcomp_algorithms[0]; + } + return NULL; +} + static void * deflate_alloc(aux, items, siz) void *aux; @@ -96,7 +139,7 @@ deflate_alloc(aux, items, siz) u_int siz; { void *ptr; - MALLOC(ptr, void *, items * siz, M_TEMP, M_NOWAIT); + ptr = _MALLOC(items * siz, M_TEMP, M_WAIT); return ptr; } @@ -117,165 +160,210 @@ deflate_common(m, md, lenp, mode) { struct mbuf *mprev; struct mbuf *p; - struct mbuf *n, *n0 = NULL, **np; - z_stream zs; + struct mbuf *n = NULL, *n0 = NULL, **np; + z_stream *zs; int error = 0; int zerror; size_t offset; - int firsttime, final, flush; + +#define MOREBLOCK() \ +do { \ + /* keep the reply buffer into our chain */ \ + if (n) { \ + n->m_len = zs->total_out - offset; \ + offset = zs->total_out; \ + *np = n; \ + np = &n->m_next; \ + n = NULL; \ + } \ + \ + /* get a fresh reply buffer */ \ + MGET(n, M_DONTWAIT, MT_DATA); \ + if (n) { \ + MCLGET(n, M_DONTWAIT); \ + } \ + if (!n) { \ + error = ENOBUFS; \ + goto fail; \ + } \ + n->m_len = 0; \ + n->m_len = M_TRAILINGSPACE(n); \ + n->m_next = NULL; \ + /* \ + * if this is the first reply buffer, reserve \ + * region for ipcomp header. \ + */ \ + if (*np == NULL) { \ + n->m_len -= sizeof(struct ipcomp); \ + n->m_data += sizeof(struct ipcomp); \ + } \ + \ + zs->next_out = mtod(n, u_int8_t *); \ + zs->avail_out = n->m_len; \ +} while (0) for (mprev = m; mprev && mprev->m_next != md; mprev = mprev->m_next) ; if (!mprev) panic("md is not in m in deflate_common"); - bzero(&zs, sizeof(zs)); - zs.zalloc = deflate_alloc; - zs.zfree = deflate_free; - zerror = mode ? inflateInit2(&zs, deflate_window_in) - : deflateInit2(&zs, deflate_policy, Z_DEFLATED, - deflate_window_out, deflate_memlevel, - Z_DEFAULT_STRATEGY); - if (zerror != Z_OK) { + zs = mode ? &inflate_stream : &deflate_stream; + if (zs->zalloc == NULL) { + /* + * init is called in ipcomp_algorithm_lookup. + * if zs->zalloc is NULL, either init hasn't been called (unlikely) + * or init failed because of no memory. + */ error = ENOBUFS; goto fail; } + + zs->next_in = 0; + zs->avail_in = 0; + zs->next_out = 0; + zs->avail_out = 0; n0 = n = NULL; np = &n0; offset = 0; - firsttime = 1; - final = 0; - flush = Z_NO_FLUSH; zerror = 0; p = md; - while (1) { - /* - * first time, we need to setup the buffer before calling - * compression function. - */ - if (firsttime) - firsttime = 0; - else { - zerror = mode ? inflate(&zs, flush) - : deflate(&zs, flush); - } + while (p && p->m_len == 0) { + p = p->m_next; + } + /* input stream and output stream are available */ + while (p && zs->avail_in == 0) { /* get input buffer */ - if (p && zs.avail_in == 0) { - zs.next_in = mtod(p, u_int8_t *); - zs.avail_in = p->m_len; + if (p && zs->avail_in == 0) { + zs->next_in = mtod(p, u_int8_t *); + zs->avail_in = p->m_len; p = p->m_next; - if (!p) { - final = 1; - flush = Z_PARTIAL_FLUSH; + while (p && p->m_len == 0) { + p = p->m_next; } } /* get output buffer */ - if (zs.next_out == NULL || zs.avail_out == 0) { - /* keep the reply buffer into our chain */ - if (n) { - n->m_len = zs.total_out - offset; - offset = zs.total_out; - *np = n; - np = &n->m_next; - } + if (zs->next_out == NULL || zs->avail_out == 0) { + MOREBLOCK(); + } - /* get a fresh reply buffer */ - MGET(n, M_DONTWAIT, MT_DATA); - if (n) { - MCLGET(n, M_DONTWAIT); - } - if (!n) { - error = ENOBUFS; - goto fail; - } - n->m_len = 0; - n->m_len = M_TRAILINGSPACE(n); - n->m_next = NULL; - /* - * if this is the first reply buffer, reserve - * region for ipcomp header. - */ - if (*np == NULL) { - n->m_len -= sizeof(struct ipcomp); - n->m_data += sizeof(struct ipcomp); + zerror = mode ? inflate(zs, Z_NO_FLUSH) + : deflate(zs, Z_NO_FLUSH); + + if (zerror == Z_STREAM_END) + ; /*once more.*/ + else if (zerror == Z_OK) { + /* inflate: Z_OK can indicate the end of decode */ + if (mode && !p && zs->avail_out != 0) + goto terminate; + else + ; /*once more.*/ + } else { + if (zs->msg) { + ipseclog((LOG_ERR, "ipcomp_%scompress: " + "%sflate(Z_NO_FLUSH): %s\n", + mode ? "de" : "", mode ? "in" : "de", + zs->msg)); + } else { + ipseclog((LOG_ERR, "ipcomp_%scompress: " + "%sflate(Z_NO_FLUSH): unknown error (%d)\n", + mode ? "de" : "", mode ? "in" : "de", + zerror)); } + mode ? inflateReset(zs) : deflateReset(zs); +/* mode ? inflateEnd(zs) : deflateEnd(zs);*/ + error = EINVAL; + goto fail; + } + } - zs.next_out = mtod(n, u_int8_t *); - zs.avail_out = n->m_len; + if (zerror == Z_STREAM_END) + goto terminate; + + /* termination */ + while (1) { + /* get output buffer */ + if (zs->next_out == NULL || zs->avail_out == 0) { + MOREBLOCK(); } - if (zerror == Z_OK) { - /* - * to terminate deflate/inflate process, we need to - * call {in,de}flate() with different flushing methods. - * - * deflate() needs at least one Z_PARTIAL_FLUSH, - * then use Z_FINISH until we get to the end. - * (if we use Z_FLUSH without Z_PARTIAL_FLUSH, deflate() - * will assume contiguous single output buffer, and that - * is not what we want) - * inflate() does not care about flushing method, but - * needs output buffer until it gets to the end. - * - * the most outer loop will be terminated with - * Z_STREAM_END. - */ - if (final == 1) { - /* reached end of mbuf chain */ - if (mode == 0) - final = 2; - else - final = 3; - } else if (final == 2) { - /* terminate deflate case */ - flush = Z_FINISH; - } else if (final == 3) { - /* terminate inflate case */ - ; - } - } else if (zerror == Z_STREAM_END) + zerror = mode ? inflate(zs, Z_FINISH) + : deflate(zs, Z_FINISH); + + if (zerror == Z_STREAM_END) break; + else if (zerror == Z_OK) + ; /*once more.*/ else { - ipseclog((LOG_ERR, "ipcomp_%scompress: %sflate: %s\n", - mode ? "de" : "", mode ? "in" : "de", - zs.msg ? zs.msg : "unknown error")); + if (zs->msg) { + ipseclog((LOG_ERR, "ipcomp_%scompress: " + "%sflate(Z_FINISH): %s\n", + mode ? "de" : "", mode ? "in" : "de", + zs->msg)); + } else { + ipseclog((LOG_ERR, "ipcomp_%scompress: " + "%sflate(Z_FINISH): unknown error (%d)\n", + mode ? "de" : "", mode ? "in" : "de", + zerror)); + } + mode ? inflateReset(zs) : deflateReset(zs); +/* mode ? inflateEnd(zs) : deflateEnd(zs); */ error = EINVAL; goto fail; } } - zerror = mode ? inflateEnd(&zs) : deflateEnd(&zs); - if (zerror != Z_OK) { - ipseclog((LOG_ERR, "ipcomp_%scompress: %sflate: %s\n", - mode ? "de" : "", mode ? "in" : "de", - zs.msg ? zs.msg : "unknown error")); - error = EINVAL; - goto fail; - } + +terminate: /* keep the final reply buffer into our chain */ if (n) { - n->m_len = zs.total_out - offset; - offset = zs.total_out; + n->m_len = zs->total_out - offset; + offset = zs->total_out; *np = n; np = &n->m_next; + n = NULL; } /* switch the mbuf to the new one */ mprev->m_next = n0; m_freem(md); - *lenp = zs.total_out; + *lenp = zs->total_out; + + /* reset the inflate/deflate state */ + zerror = mode ? inflateReset(zs) : deflateReset(zs); + if (zerror != Z_OK) { + /* + * A failure here is uncommon. If this does + * fail, the packet can still be used but + * the z_stream will be messed up so subsequent + * inflates/deflates will probably fail. + */ + if (zs->msg) { + ipseclog((LOG_ERR, "ipcomp_%scompress: " + "%sflateEnd: %s\n", + mode ? "de" : "", mode ? "in" : "de", + zs->msg)); + } else { + ipseclog((LOG_ERR, "ipcomp_%scompress: " + "%sflateEnd: unknown error (%d)\n", + mode ? "de" : "", mode ? "in" : "de", + zerror)); + } + } return 0; fail: if (m) m_freem(m); + if (n) + m_freem(n); if (n0) m_freem(n0); return error; +#undef MOREBLOCK } static int