1/*
2 * Cryptographic API.
3 *
4 * Zlib algorithm
5 *
6 * Copyright 2008 Sony Corporation
7 *
8 * Based on deflate.c, which is
9 * Copyright (c) 2003 James Morris <jmorris@intercode.com.au>
10 *
11 * This program is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU General Public License as published by the Free
13 * Software Foundation; either version 2 of the License, or (at your option)
14 * any later version.
15 *
16 * FIXME: deflate transforms will require up to a total of about 436k of kernel
17 * memory on i386 (390k for compression, the rest for decompression), as the
18 * current zlib kernel code uses a worst case pre-allocation system by default.
19 * This needs to be fixed so that the amount of memory required is properly
20 * related to the winbits and memlevel parameters.
21 */
22
23#define pr_fmt(fmt)	"%s: " fmt, __func__
24
25#include <linux/init.h>
26#include <linux/module.h>
27#include <linux/zlib.h>
28#include <linux/vmalloc.h>
29#include <linux/interrupt.h>
30#include <linux/mm.h>
31#include <linux/net.h>
32
33#include <crypto/internal/compress.h>
34
35#include <net/netlink.h>
36
37
38struct zlib_ctx {
39	struct z_stream_s comp_stream;
40	struct z_stream_s decomp_stream;
41	int decomp_windowBits;
42};
43
44
45static void zlib_comp_exit(struct zlib_ctx *ctx)
46{
47	struct z_stream_s *stream = &ctx->comp_stream;
48
49	if (stream->workspace) {
50		zlib_deflateEnd(stream);
51		vfree(stream->workspace);
52		stream->workspace = NULL;
53	}
54}
55
56static void zlib_decomp_exit(struct zlib_ctx *ctx)
57{
58	struct z_stream_s *stream = &ctx->decomp_stream;
59
60	if (stream->workspace) {
61		zlib_inflateEnd(stream);
62		vfree(stream->workspace);
63		stream->workspace = NULL;
64	}
65}
66
67static int zlib_init(struct crypto_tfm *tfm)
68{
69	return 0;
70}
71
72static void zlib_exit(struct crypto_tfm *tfm)
73{
74	struct zlib_ctx *ctx = crypto_tfm_ctx(tfm);
75
76	zlib_comp_exit(ctx);
77	zlib_decomp_exit(ctx);
78}
79
80
81static int zlib_compress_setup(struct crypto_pcomp *tfm, const void *params,
82			       unsigned int len)
83{
84	struct zlib_ctx *ctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
85	struct z_stream_s *stream = &ctx->comp_stream;
86	struct nlattr *tb[ZLIB_COMP_MAX + 1];
87	int window_bits, mem_level;
88	size_t workspacesize;
89	int ret;
90
91	ret = nla_parse(tb, ZLIB_COMP_MAX, params, len, NULL);
92	if (ret)
93		return ret;
94
95	zlib_comp_exit(ctx);
96
97	window_bits = tb[ZLIB_COMP_WINDOWBITS]
98					? nla_get_u32(tb[ZLIB_COMP_WINDOWBITS])
99					: MAX_WBITS;
100	mem_level = tb[ZLIB_COMP_MEMLEVEL]
101					? nla_get_u32(tb[ZLIB_COMP_MEMLEVEL])
102					: DEF_MEM_LEVEL;
103
104	workspacesize = zlib_deflate_workspacesize(window_bits, mem_level);
105	stream->workspace = vzalloc(workspacesize);
106	if (!stream->workspace)
107		return -ENOMEM;
108
109	ret = zlib_deflateInit2(stream,
110				tb[ZLIB_COMP_LEVEL]
111					? nla_get_u32(tb[ZLIB_COMP_LEVEL])
112					: Z_DEFAULT_COMPRESSION,
113				tb[ZLIB_COMP_METHOD]
114					? nla_get_u32(tb[ZLIB_COMP_METHOD])
115					: Z_DEFLATED,
116				window_bits,
117				mem_level,
118				tb[ZLIB_COMP_STRATEGY]
119					? nla_get_u32(tb[ZLIB_COMP_STRATEGY])
120					: Z_DEFAULT_STRATEGY);
121	if (ret != Z_OK) {
122		vfree(stream->workspace);
123		stream->workspace = NULL;
124		return -EINVAL;
125	}
126
127	return 0;
128}
129
130static int zlib_compress_init(struct crypto_pcomp *tfm)
131{
132	int ret;
133	struct zlib_ctx *dctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
134	struct z_stream_s *stream = &dctx->comp_stream;
135
136	ret = zlib_deflateReset(stream);
137	if (ret != Z_OK)
138		return -EINVAL;
139
140	return 0;
141}
142
143static int zlib_compress_update(struct crypto_pcomp *tfm,
144				struct comp_request *req)
145{
146	int ret;
147	struct zlib_ctx *dctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
148	struct z_stream_s *stream = &dctx->comp_stream;
149
150	pr_debug("avail_in %u, avail_out %u\n", req->avail_in, req->avail_out);
151	stream->next_in = req->next_in;
152	stream->avail_in = req->avail_in;
153	stream->next_out = req->next_out;
154	stream->avail_out = req->avail_out;
155
156	ret = zlib_deflate(stream, Z_NO_FLUSH);
157	switch (ret) {
158	case Z_OK:
159		break;
160
161	case Z_BUF_ERROR:
162		pr_debug("zlib_deflate could not make progress\n");
163		return -EAGAIN;
164
165	default:
166		pr_debug("zlib_deflate failed %d\n", ret);
167		return -EINVAL;
168	}
169
170	ret = req->avail_out - stream->avail_out;
171	pr_debug("avail_in %lu, avail_out %lu (consumed %lu, produced %u)\n",
172		 stream->avail_in, stream->avail_out,
173		 req->avail_in - stream->avail_in, ret);
174	req->next_in = stream->next_in;
175	req->avail_in = stream->avail_in;
176	req->next_out = stream->next_out;
177	req->avail_out = stream->avail_out;
178	return ret;
179}
180
181static int zlib_compress_final(struct crypto_pcomp *tfm,
182			       struct comp_request *req)
183{
184	int ret;
185	struct zlib_ctx *dctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
186	struct z_stream_s *stream = &dctx->comp_stream;
187
188	pr_debug("avail_in %u, avail_out %u\n", req->avail_in, req->avail_out);
189	stream->next_in = req->next_in;
190	stream->avail_in = req->avail_in;
191	stream->next_out = req->next_out;
192	stream->avail_out = req->avail_out;
193
194	ret = zlib_deflate(stream, Z_FINISH);
195	if (ret != Z_STREAM_END) {
196		pr_debug("zlib_deflate failed %d\n", ret);
197		return -EINVAL;
198	}
199
200	ret = req->avail_out - stream->avail_out;
201	pr_debug("avail_in %lu, avail_out %lu (consumed %lu, produced %u)\n",
202		 stream->avail_in, stream->avail_out,
203		 req->avail_in - stream->avail_in, ret);
204	req->next_in = stream->next_in;
205	req->avail_in = stream->avail_in;
206	req->next_out = stream->next_out;
207	req->avail_out = stream->avail_out;
208	return ret;
209}
210
211
212static int zlib_decompress_setup(struct crypto_pcomp *tfm, const void *params,
213				 unsigned int len)
214{
215	struct zlib_ctx *ctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
216	struct z_stream_s *stream = &ctx->decomp_stream;
217	struct nlattr *tb[ZLIB_DECOMP_MAX + 1];
218	int ret = 0;
219
220	ret = nla_parse(tb, ZLIB_DECOMP_MAX, params, len, NULL);
221	if (ret)
222		return ret;
223
224	zlib_decomp_exit(ctx);
225
226	ctx->decomp_windowBits = tb[ZLIB_DECOMP_WINDOWBITS]
227				 ? nla_get_u32(tb[ZLIB_DECOMP_WINDOWBITS])
228				 : DEF_WBITS;
229
230	stream->workspace = vzalloc(zlib_inflate_workspacesize());
231	if (!stream->workspace)
232		return -ENOMEM;
233
234	ret = zlib_inflateInit2(stream, ctx->decomp_windowBits);
235	if (ret != Z_OK) {
236		vfree(stream->workspace);
237		stream->workspace = NULL;
238		return -EINVAL;
239	}
240
241	return 0;
242}
243
244static int zlib_decompress_init(struct crypto_pcomp *tfm)
245{
246	int ret;
247	struct zlib_ctx *dctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
248	struct z_stream_s *stream = &dctx->decomp_stream;
249
250	ret = zlib_inflateReset(stream);
251	if (ret != Z_OK)
252		return -EINVAL;
253
254	return 0;
255}
256
257static int zlib_decompress_update(struct crypto_pcomp *tfm,
258				  struct comp_request *req)
259{
260	int ret;
261	struct zlib_ctx *dctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
262	struct z_stream_s *stream = &dctx->decomp_stream;
263
264	pr_debug("avail_in %u, avail_out %u\n", req->avail_in, req->avail_out);
265	stream->next_in = req->next_in;
266	stream->avail_in = req->avail_in;
267	stream->next_out = req->next_out;
268	stream->avail_out = req->avail_out;
269
270	ret = zlib_inflate(stream, Z_SYNC_FLUSH);
271	switch (ret) {
272	case Z_OK:
273	case Z_STREAM_END:
274		break;
275
276	case Z_BUF_ERROR:
277		pr_debug("zlib_inflate could not make progress\n");
278		return -EAGAIN;
279
280	default:
281		pr_debug("zlib_inflate failed %d\n", ret);
282		return -EINVAL;
283	}
284
285	ret = req->avail_out - stream->avail_out;
286	pr_debug("avail_in %lu, avail_out %lu (consumed %lu, produced %u)\n",
287		 stream->avail_in, stream->avail_out,
288		 req->avail_in - stream->avail_in, ret);
289	req->next_in = stream->next_in;
290	req->avail_in = stream->avail_in;
291	req->next_out = stream->next_out;
292	req->avail_out = stream->avail_out;
293	return ret;
294}
295
296static int zlib_decompress_final(struct crypto_pcomp *tfm,
297				 struct comp_request *req)
298{
299	int ret;
300	struct zlib_ctx *dctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
301	struct z_stream_s *stream = &dctx->decomp_stream;
302
303	pr_debug("avail_in %u, avail_out %u\n", req->avail_in, req->avail_out);
304	stream->next_in = req->next_in;
305	stream->avail_in = req->avail_in;
306	stream->next_out = req->next_out;
307	stream->avail_out = req->avail_out;
308
309	if (dctx->decomp_windowBits < 0) {
310		ret = zlib_inflate(stream, Z_SYNC_FLUSH);
311		/*
312		 * Work around a bug in zlib, which sometimes wants to taste an
313		 * extra byte when being used in the (undocumented) raw deflate
314		 * mode. (From USAGI).
315		 */
316		if (ret == Z_OK && !stream->avail_in && stream->avail_out) {
317			const void *saved_next_in = stream->next_in;
318			u8 zerostuff = 0;
319
320			stream->next_in = &zerostuff;
321			stream->avail_in = 1;
322			ret = zlib_inflate(stream, Z_FINISH);
323			stream->next_in = saved_next_in;
324			stream->avail_in = 0;
325		}
326	} else
327		ret = zlib_inflate(stream, Z_FINISH);
328	if (ret != Z_STREAM_END) {
329		pr_debug("zlib_inflate failed %d\n", ret);
330		return -EINVAL;
331	}
332
333	ret = req->avail_out - stream->avail_out;
334	pr_debug("avail_in %lu, avail_out %lu (consumed %lu, produced %u)\n",
335		 stream->avail_in, stream->avail_out,
336		 req->avail_in - stream->avail_in, ret);
337	req->next_in = stream->next_in;
338	req->avail_in = stream->avail_in;
339	req->next_out = stream->next_out;
340	req->avail_out = stream->avail_out;
341	return ret;
342}
343
344
345static struct pcomp_alg zlib_alg = {
346	.compress_setup		= zlib_compress_setup,
347	.compress_init		= zlib_compress_init,
348	.compress_update	= zlib_compress_update,
349	.compress_final		= zlib_compress_final,
350	.decompress_setup	= zlib_decompress_setup,
351	.decompress_init	= zlib_decompress_init,
352	.decompress_update	= zlib_decompress_update,
353	.decompress_final	= zlib_decompress_final,
354
355	.base			= {
356		.cra_name	= "zlib",
357		.cra_flags	= CRYPTO_ALG_TYPE_PCOMPRESS,
358		.cra_ctxsize	= sizeof(struct zlib_ctx),
359		.cra_module	= THIS_MODULE,
360		.cra_init	= zlib_init,
361		.cra_exit	= zlib_exit,
362	}
363};
364
365static int __init zlib_mod_init(void)
366{
367	return crypto_register_pcomp(&zlib_alg);
368}
369
370static void __exit zlib_mod_fini(void)
371{
372	crypto_unregister_pcomp(&zlib_alg);
373}
374
375module_init(zlib_mod_init);
376module_exit(zlib_mod_fini);
377
378MODULE_LICENSE("GPL");
379MODULE_DESCRIPTION("Zlib Compression Algorithm");
380MODULE_AUTHOR("Sony Corporation");
381MODULE_ALIAS_CRYPTO("zlib");
382