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