ACPI: thinkpad-acpi: add development version tag
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / crypto / zlib.c
blobd11d761a5e418191c29a987f923ac3e2be0f20a6
1 /*
2 * Cryptographic API.
4 * Zlib algorithm
6 * Copyright 2008 Sony Corporation
8 * Based on deflate.c, which is
9 * Copyright (c) 2003 James Morris <jmorris@intercode.com.au>
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.
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.
23 #define pr_fmt(fmt) "%s: " fmt, __func__
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 #include <linux/slab.h>
34 #include <crypto/internal/compress.h>
36 #include <net/netlink.h>
39 struct zlib_ctx {
40 struct z_stream_s comp_stream;
41 struct z_stream_s decomp_stream;
42 int decomp_windowBits;
46 static void zlib_comp_exit(struct zlib_ctx *ctx)
48 struct z_stream_s *stream = &ctx->comp_stream;
50 if (stream->workspace) {
51 zlib_deflateEnd(stream);
52 vfree(stream->workspace);
53 stream->workspace = NULL;
57 static void zlib_decomp_exit(struct zlib_ctx *ctx)
59 struct z_stream_s *stream = &ctx->decomp_stream;
61 if (stream->workspace) {
62 zlib_inflateEnd(stream);
63 kfree(stream->workspace);
64 stream->workspace = NULL;
68 static int zlib_init(struct crypto_tfm *tfm)
70 return 0;
73 static void zlib_exit(struct crypto_tfm *tfm)
75 struct zlib_ctx *ctx = crypto_tfm_ctx(tfm);
77 zlib_comp_exit(ctx);
78 zlib_decomp_exit(ctx);
82 static int zlib_compress_setup(struct crypto_pcomp *tfm, void *params,
83 unsigned int len)
85 struct zlib_ctx *ctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
86 struct z_stream_s *stream = &ctx->comp_stream;
87 struct nlattr *tb[ZLIB_COMP_MAX + 1];
88 int window_bits, mem_level;
89 size_t workspacesize;
90 int ret;
92 ret = nla_parse(tb, ZLIB_COMP_MAX, params, len, NULL);
93 if (ret)
94 return ret;
96 zlib_comp_exit(ctx);
98 window_bits = tb[ZLIB_COMP_WINDOWBITS]
99 ? nla_get_u32(tb[ZLIB_COMP_WINDOWBITS])
100 : MAX_WBITS;
101 mem_level = tb[ZLIB_COMP_MEMLEVEL]
102 ? nla_get_u32(tb[ZLIB_COMP_MEMLEVEL])
103 : DEF_MEM_LEVEL;
105 workspacesize = zlib_deflate_workspacesize(window_bits, mem_level);
106 stream->workspace = vzalloc(workspacesize);
107 if (!stream->workspace)
108 return -ENOMEM;
110 ret = zlib_deflateInit2(stream,
111 tb[ZLIB_COMP_LEVEL]
112 ? nla_get_u32(tb[ZLIB_COMP_LEVEL])
113 : Z_DEFAULT_COMPRESSION,
114 tb[ZLIB_COMP_METHOD]
115 ? nla_get_u32(tb[ZLIB_COMP_METHOD])
116 : Z_DEFLATED,
117 window_bits,
118 mem_level,
119 tb[ZLIB_COMP_STRATEGY]
120 ? nla_get_u32(tb[ZLIB_COMP_STRATEGY])
121 : Z_DEFAULT_STRATEGY);
122 if (ret != Z_OK) {
123 vfree(stream->workspace);
124 stream->workspace = NULL;
125 return -EINVAL;
128 return 0;
131 static int zlib_compress_init(struct crypto_pcomp *tfm)
133 int ret;
134 struct zlib_ctx *dctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
135 struct z_stream_s *stream = &dctx->comp_stream;
137 ret = zlib_deflateReset(stream);
138 if (ret != Z_OK)
139 return -EINVAL;
141 return 0;
144 static int zlib_compress_update(struct crypto_pcomp *tfm,
145 struct comp_request *req)
147 int ret;
148 struct zlib_ctx *dctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
149 struct z_stream_s *stream = &dctx->comp_stream;
151 pr_debug("avail_in %u, avail_out %u\n", req->avail_in, req->avail_out);
152 stream->next_in = req->next_in;
153 stream->avail_in = req->avail_in;
154 stream->next_out = req->next_out;
155 stream->avail_out = req->avail_out;
157 ret = zlib_deflate(stream, Z_NO_FLUSH);
158 switch (ret) {
159 case Z_OK:
160 break;
162 case Z_BUF_ERROR:
163 pr_debug("zlib_deflate could not make progress\n");
164 return -EAGAIN;
166 default:
167 pr_debug("zlib_deflate failed %d\n", ret);
168 return -EINVAL;
171 ret = req->avail_out - stream->avail_out;
172 pr_debug("avail_in %u, avail_out %u (consumed %u, produced %u)\n",
173 stream->avail_in, stream->avail_out,
174 req->avail_in - stream->avail_in, ret);
175 req->next_in = stream->next_in;
176 req->avail_in = stream->avail_in;
177 req->next_out = stream->next_out;
178 req->avail_out = stream->avail_out;
179 return ret;
182 static int zlib_compress_final(struct crypto_pcomp *tfm,
183 struct comp_request *req)
185 int ret;
186 struct zlib_ctx *dctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
187 struct z_stream_s *stream = &dctx->comp_stream;
189 pr_debug("avail_in %u, avail_out %u\n", req->avail_in, req->avail_out);
190 stream->next_in = req->next_in;
191 stream->avail_in = req->avail_in;
192 stream->next_out = req->next_out;
193 stream->avail_out = req->avail_out;
195 ret = zlib_deflate(stream, Z_FINISH);
196 if (ret != Z_STREAM_END) {
197 pr_debug("zlib_deflate failed %d\n", ret);
198 return -EINVAL;
201 ret = req->avail_out - stream->avail_out;
202 pr_debug("avail_in %u, avail_out %u (consumed %u, produced %u)\n",
203 stream->avail_in, stream->avail_out,
204 req->avail_in - stream->avail_in, ret);
205 req->next_in = stream->next_in;
206 req->avail_in = stream->avail_in;
207 req->next_out = stream->next_out;
208 req->avail_out = stream->avail_out;
209 return ret;
213 static int zlib_decompress_setup(struct crypto_pcomp *tfm, void *params,
214 unsigned int len)
216 struct zlib_ctx *ctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
217 struct z_stream_s *stream = &ctx->decomp_stream;
218 struct nlattr *tb[ZLIB_DECOMP_MAX + 1];
219 int ret = 0;
221 ret = nla_parse(tb, ZLIB_DECOMP_MAX, params, len, NULL);
222 if (ret)
223 return ret;
225 zlib_decomp_exit(ctx);
227 ctx->decomp_windowBits = tb[ZLIB_DECOMP_WINDOWBITS]
228 ? nla_get_u32(tb[ZLIB_DECOMP_WINDOWBITS])
229 : DEF_WBITS;
231 stream->workspace = kzalloc(zlib_inflate_workspacesize(), GFP_KERNEL);
232 if (!stream->workspace)
233 return -ENOMEM;
235 ret = zlib_inflateInit2(stream, ctx->decomp_windowBits);
236 if (ret != Z_OK) {
237 kfree(stream->workspace);
238 stream->workspace = NULL;
239 return -EINVAL;
242 return 0;
245 static int zlib_decompress_init(struct crypto_pcomp *tfm)
247 int ret;
248 struct zlib_ctx *dctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
249 struct z_stream_s *stream = &dctx->decomp_stream;
251 ret = zlib_inflateReset(stream);
252 if (ret != Z_OK)
253 return -EINVAL;
255 return 0;
258 static int zlib_decompress_update(struct crypto_pcomp *tfm,
259 struct comp_request *req)
261 int ret;
262 struct zlib_ctx *dctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
263 struct z_stream_s *stream = &dctx->decomp_stream;
265 pr_debug("avail_in %u, avail_out %u\n", req->avail_in, req->avail_out);
266 stream->next_in = req->next_in;
267 stream->avail_in = req->avail_in;
268 stream->next_out = req->next_out;
269 stream->avail_out = req->avail_out;
271 ret = zlib_inflate(stream, Z_SYNC_FLUSH);
272 switch (ret) {
273 case Z_OK:
274 case Z_STREAM_END:
275 break;
277 case Z_BUF_ERROR:
278 pr_debug("zlib_inflate could not make progress\n");
279 return -EAGAIN;
281 default:
282 pr_debug("zlib_inflate failed %d\n", ret);
283 return -EINVAL;
286 ret = req->avail_out - stream->avail_out;
287 pr_debug("avail_in %u, avail_out %u (consumed %u, produced %u)\n",
288 stream->avail_in, stream->avail_out,
289 req->avail_in - stream->avail_in, ret);
290 req->next_in = stream->next_in;
291 req->avail_in = stream->avail_in;
292 req->next_out = stream->next_out;
293 req->avail_out = stream->avail_out;
294 return ret;
297 static int zlib_decompress_final(struct crypto_pcomp *tfm,
298 struct comp_request *req)
300 int ret;
301 struct zlib_ctx *dctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
302 struct z_stream_s *stream = &dctx->decomp_stream;
304 pr_debug("avail_in %u, avail_out %u\n", req->avail_in, req->avail_out);
305 stream->next_in = req->next_in;
306 stream->avail_in = req->avail_in;
307 stream->next_out = req->next_out;
308 stream->avail_out = req->avail_out;
310 if (dctx->decomp_windowBits < 0) {
311 ret = zlib_inflate(stream, Z_SYNC_FLUSH);
313 * Work around a bug in zlib, which sometimes wants to taste an
314 * extra byte when being used in the (undocumented) raw deflate
315 * mode. (From USAGI).
317 if (ret == Z_OK && !stream->avail_in && stream->avail_out) {
318 const void *saved_next_in = stream->next_in;
319 u8 zerostuff = 0;
321 stream->next_in = &zerostuff;
322 stream->avail_in = 1;
323 ret = zlib_inflate(stream, Z_FINISH);
324 stream->next_in = saved_next_in;
325 stream->avail_in = 0;
327 } else
328 ret = zlib_inflate(stream, Z_FINISH);
329 if (ret != Z_STREAM_END) {
330 pr_debug("zlib_inflate failed %d\n", ret);
331 return -EINVAL;
334 ret = req->avail_out - stream->avail_out;
335 pr_debug("avail_in %u, avail_out %u (consumed %u, produced %u)\n",
336 stream->avail_in, stream->avail_out,
337 req->avail_in - stream->avail_in, ret);
338 req->next_in = stream->next_in;
339 req->avail_in = stream->avail_in;
340 req->next_out = stream->next_out;
341 req->avail_out = stream->avail_out;
342 return ret;
346 static struct pcomp_alg zlib_alg = {
347 .compress_setup = zlib_compress_setup,
348 .compress_init = zlib_compress_init,
349 .compress_update = zlib_compress_update,
350 .compress_final = zlib_compress_final,
351 .decompress_setup = zlib_decompress_setup,
352 .decompress_init = zlib_decompress_init,
353 .decompress_update = zlib_decompress_update,
354 .decompress_final = zlib_decompress_final,
356 .base = {
357 .cra_name = "zlib",
358 .cra_flags = CRYPTO_ALG_TYPE_PCOMPRESS,
359 .cra_ctxsize = sizeof(struct zlib_ctx),
360 .cra_module = THIS_MODULE,
361 .cra_init = zlib_init,
362 .cra_exit = zlib_exit,
366 static int __init zlib_mod_init(void)
368 return crypto_register_pcomp(&zlib_alg);
371 static void __exit zlib_mod_fini(void)
373 crypto_unregister_pcomp(&zlib_alg);
376 module_init(zlib_mod_init);
377 module_exit(zlib_mod_fini);
379 MODULE_LICENSE("GPL");
380 MODULE_DESCRIPTION("Zlib Compression Algorithm");
381 MODULE_AUTHOR("Sony Corporation");