1104476Ssam/* $OpenBSD: deflate.c,v 1.3 2001/08/20 02:45:22 hugh Exp $ */ 2104476Ssam 3139825Simp/*- 4104476Ssam * Copyright (c) 2001 Jean-Jacques Bernard-Gundol (jj@wabbitt.org) 5104476Ssam * 6104476Ssam * Redistribution and use in source and binary forms, with or without 7104476Ssam * modification, are permitted provided that the following conditions 8104476Ssam * are met: 9104476Ssam * 10104476Ssam * 1. Redistributions of source code must retain the above copyright 11104476Ssam * notice, this list of conditions and the following disclaimer. 12104476Ssam * 2. Redistributions in binary form must reproduce the above copyright 13104476Ssam * notice, this list of conditions and the following disclaimer in the 14104476Ssam * documentation and/or other materials provided with the distribution. 15104476Ssam * 3. The name of the author may not be used to endorse or promote products 16104476Ssam * derived from this software without specific prior written permission. 17104476Ssam * 18104476Ssam * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19104476Ssam * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20104476Ssam * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21104476Ssam * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22104476Ssam * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23104476Ssam * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24104476Ssam * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25104476Ssam * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26104476Ssam * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27104476Ssam * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28104476Ssam */ 29104476Ssam 30104476Ssam/* 31104476Ssam * This file contains a wrapper around the deflate algo compression 32104476Ssam * functions using the zlib library (see net/zlib.{c,h}) 33104476Ssam */ 34104476Ssam 35116191Sobrien#include <sys/cdefs.h> 36116191Sobrien__FBSDID("$FreeBSD$"); 37116191Sobrien 38199885Sbz#include "opt_kdtrace.h" 39199885Sbz 40104476Ssam#include <sys/types.h> 41146797Sscottl#include <sys/param.h> 42104476Ssam#include <sys/malloc.h> 43104476Ssam#include <sys/param.h> 44199885Sbz#include <sys/kernel.h> 45199885Sbz#include <sys/sdt.h> 46104476Ssam#include <sys/systm.h> 47104476Ssam#include <net/zlib.h> 48104476Ssam 49104476Ssam#include <opencrypto/cryptodev.h> 50104476Ssam#include <opencrypto/deflate.h> 51104476Ssam 52199885SbzSDT_PROVIDER_DECLARE(opencrypto); 53260817SavgSDT_PROBE_DEFINE2(opencrypto, deflate, deflate_global, entry, 54199885Sbz "int", "u_int32_t"); 55260817SavgSDT_PROBE_DEFINE5(opencrypto, deflate, deflate_global, bad, 56199885Sbz "int", "int", "int", "int", "int"); 57260817SavgSDT_PROBE_DEFINE5(opencrypto, deflate, deflate_global, iter, 58199885Sbz "int", "int", "int", "int", "int"); 59260817SavgSDT_PROBE_DEFINE2(opencrypto, deflate, deflate_global, return, 60199885Sbz "int", "u_int32_t"); 61199885Sbz 62104476Ssamint window_inflate = -1 * MAX_WBITS; 63104476Ssamint window_deflate = -12; 64104476Ssam 65104476Ssam/* 66104476Ssam * This function takes a block of data and (de)compress it using the deflate 67104476Ssam * algorithm 68104476Ssam */ 69104476Ssam 70104476Ssamu_int32_t 71104476Ssamdeflate_global(data, size, decomp, out) 72104476Ssam u_int8_t *data; 73104476Ssam u_int32_t size; 74104476Ssam int decomp; 75104476Ssam u_int8_t **out; 76104476Ssam{ 77104476Ssam /* decomp indicates whether we compress (0) or decompress (1) */ 78104476Ssam 79104476Ssam z_stream zbuf; 80104476Ssam u_int8_t *output; 81104476Ssam u_int32_t count, result; 82199895Sbz int error, i; 83199895Sbz struct deflate_buf *bufh, *bufp; 84104476Ssam 85199885Sbz SDT_PROBE2(opencrypto, deflate, deflate_global, entry, decomp, size); 86199885Sbz 87199895Sbz bufh = bufp = NULL; 88104476Ssam if (!decomp) { 89199895Sbz i = 1; 90104476Ssam } else { 91104476Ssam /* 92104476Ssam * Choose a buffer with 4x the size of the input buffer 93104476Ssam * for the size of the output buffer in the case of 94104476Ssam * decompression. If it's not sufficient, it will need to be 95199895Sbz * updated while the decompression is going on. 96104476Ssam */ 97199895Sbz i = 4; 98199895Sbz } 99199895Sbz /* 100199895Sbz * Make sure we do have enough output space. Repeated calls to 101199895Sbz * deflate need at least 6 bytes of output buffer space to avoid 102199895Sbz * repeated markers. We will always provide at least 16 bytes. 103199895Sbz */ 104199895Sbz while ((size * i) < 16) 105199895Sbz i++; 106104476Ssam 107199895Sbz bufh = bufp = malloc(sizeof(*bufp) + (size_t)(size * i), 108199895Sbz M_CRYPTO_DATA, M_NOWAIT); 109199895Sbz if (bufp == NULL) { 110199895Sbz SDT_PROBE3(opencrypto, deflate, deflate_global, bad, 111199895Sbz decomp, 0, __LINE__); 112199895Sbz goto bad2; 113104476Ssam } 114199895Sbz bufp->next = NULL; 115199895Sbz bufp->size = size * i; 116104476Ssam 117199895Sbz bzero(&zbuf, sizeof(z_stream)); 118199895Sbz zbuf.zalloc = z_alloc; 119199895Sbz zbuf.zfree = z_free; 120199895Sbz zbuf.opaque = Z_NULL; 121199895Sbz zbuf.next_in = data; /* Data that is going to be processed. */ 122199895Sbz zbuf.avail_in = size; /* Total length of data to be processed. */ 123199895Sbz zbuf.next_out = bufp->data; 124199895Sbz zbuf.avail_out = bufp->size; 125104476Ssam 126104476Ssam error = decomp ? inflateInit2(&zbuf, window_inflate) : 127104476Ssam deflateInit2(&zbuf, Z_DEFAULT_COMPRESSION, Z_METHOD, 128104476Ssam window_deflate, Z_MEMLEVEL, Z_DEFAULT_STRATEGY); 129199885Sbz if (error != Z_OK) { 130199885Sbz SDT_PROBE3(opencrypto, deflate, deflate_global, bad, 131199885Sbz decomp, error, __LINE__); 132104476Ssam goto bad; 133199885Sbz } 134199895Sbz 135104476Ssam for (;;) { 136199887Sbz error = decomp ? inflate(&zbuf, Z_SYNC_FLUSH) : 137199887Sbz deflate(&zbuf, Z_FINISH); 138199885Sbz if (error != Z_OK && error != Z_STREAM_END) { 139199885Sbz /* 140199885Sbz * Unfortunately we are limited to 5 arguments, 141199885Sbz * thus use two probes. 142199885Sbz */ 143199885Sbz SDT_PROBE5(opencrypto, deflate, deflate_global, bad, 144199885Sbz decomp, error, __LINE__, 145199885Sbz zbuf.avail_in, zbuf.avail_out); 146199885Sbz SDT_PROBE5(opencrypto, deflate, deflate_global, bad, 147199885Sbz decomp, error, __LINE__, 148199885Sbz zbuf.state->dummy, zbuf.total_out); 149104476Ssam goto bad; 150199885Sbz } 151199904Sbz SDT_PROBE5(opencrypto, deflate, deflate_global, iter, 152199904Sbz decomp, error, __LINE__, 153199904Sbz zbuf.avail_in, zbuf.avail_out); 154199904Sbz SDT_PROBE5(opencrypto, deflate, deflate_global, iter, 155199904Sbz decomp, error, __LINE__, 156199904Sbz zbuf.state->dummy, zbuf.total_out); 157199887Sbz if (decomp && zbuf.avail_in == 0 && error == Z_STREAM_END) { 158199887Sbz /* Done. */ 159199887Sbz break; 160199887Sbz } else if (!decomp && error == Z_STREAM_END) { 161199887Sbz /* Done. */ 162199887Sbz break; 163199887Sbz } else if (zbuf.avail_out == 0) { 164199895Sbz struct deflate_buf *p; 165199895Sbz 166199895Sbz /* We need more output space for another iteration. */ 167199895Sbz p = malloc(sizeof(*p) + (size_t)(size * i), 168104476Ssam M_CRYPTO_DATA, M_NOWAIT); 169199895Sbz if (p == NULL) { 170199885Sbz SDT_PROBE3(opencrypto, deflate, deflate_global, 171199885Sbz bad, decomp, 0, __LINE__); 172104476Ssam goto bad; 173199885Sbz } 174199895Sbz p->next = NULL; 175199895Sbz p->size = size * i; 176199895Sbz bufp->next = p; 177199895Sbz bufp = p; 178199895Sbz zbuf.next_out = bufp->data; 179199895Sbz zbuf.avail_out = bufp->size; 180199885Sbz } else { 181199887Sbz /* Unexpect result. */ 182199885Sbz /* 183199885Sbz * Unfortunately we are limited to 5 arguments, 184199885Sbz * thus, again, use two probes. 185199885Sbz */ 186199885Sbz SDT_PROBE5(opencrypto, deflate, deflate_global, bad, 187199885Sbz decomp, error, __LINE__, 188199885Sbz zbuf.avail_in, zbuf.avail_out); 189199885Sbz SDT_PROBE5(opencrypto, deflate, deflate_global, bad, 190199885Sbz decomp, error, __LINE__, 191199885Sbz zbuf.state->dummy, zbuf.total_out); 192104476Ssam goto bad; 193199885Sbz } 194104476Ssam } 195104476Ssam 196104476Ssam result = count = zbuf.total_out; 197104476Ssam 198199895Sbz *out = malloc(result, M_CRYPTO_DATA, M_NOWAIT); 199199885Sbz if (*out == NULL) { 200199885Sbz SDT_PROBE3(opencrypto, deflate, deflate_global, bad, 201199885Sbz decomp, 0, __LINE__); 202104476Ssam goto bad; 203199885Sbz } 204104476Ssam if (decomp) 205104476Ssam inflateEnd(&zbuf); 206104476Ssam else 207104476Ssam deflateEnd(&zbuf); 208104476Ssam output = *out; 209199895Sbz for (bufp = bufh; bufp != NULL; ) { 210199895Sbz if (count > bufp->size) { 211199895Sbz struct deflate_buf *p; 212199895Sbz 213199895Sbz bcopy(bufp->data, *out, bufp->size); 214199895Sbz *out += bufp->size; 215199895Sbz count -= bufp->size; 216199895Sbz p = bufp; 217199895Sbz bufp = bufp->next; 218199895Sbz free(p, M_CRYPTO_DATA); 219104476Ssam } else { 220199895Sbz /* It should be the last buffer. */ 221199895Sbz bcopy(bufp->data, *out, count); 222104476Ssam *out += count; 223199895Sbz free(bufp, M_CRYPTO_DATA); 224199895Sbz bufp = NULL; 225104476Ssam count = 0; 226104476Ssam } 227104476Ssam } 228104476Ssam *out = output; 229199885Sbz SDT_PROBE2(opencrypto, deflate, deflate_global, return, decomp, result); 230104476Ssam return result; 231104476Ssam 232104476Ssambad: 233104476Ssam if (decomp) 234104476Ssam inflateEnd(&zbuf); 235104476Ssam else 236104476Ssam deflateEnd(&zbuf); 237199895Sbz for (bufp = bufh; bufp != NULL; ) { 238199895Sbz struct deflate_buf *p; 239199895Sbz 240199895Sbz p = bufp; 241199895Sbz bufp = bufp->next; 242199895Sbz free(p, M_CRYPTO_DATA); 243199895Sbz } 244199895Sbzbad2: 245199895Sbz *out = NULL; 246104476Ssam return 0; 247104476Ssam} 248104476Ssam 249104476Ssamvoid * 250104476Ssamz_alloc(nil, type, size) 251104476Ssam void *nil; 252104476Ssam u_int type, size; 253104476Ssam{ 254104476Ssam void *ptr; 255104476Ssam 256104476Ssam ptr = malloc(type *size, M_CRYPTO_DATA, M_NOWAIT); 257104476Ssam return ptr; 258104476Ssam} 259104476Ssam 260104476Ssamvoid 261104476Ssamz_free(nil, ptr) 262104476Ssam void *nil, *ptr; 263104476Ssam{ 264104476Ssam free(ptr, M_CRYPTO_DATA); 265104476Ssam} 266