OMAP4: hwmod: Naming of address space
[pandora-kernel.git] / crypto / zlib.c
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 #include <linux/slab.h>
33
34 #include <crypto/internal/compress.h>
35
36 #include <net/netlink.h>
37
38
39 struct zlib_ctx {
40         struct z_stream_s comp_stream;
41         struct z_stream_s decomp_stream;
42         int decomp_windowBits;
43 };
44
45
46 static void zlib_comp_exit(struct zlib_ctx *ctx)
47 {
48         struct z_stream_s *stream = &ctx->comp_stream;
49
50         if (stream->workspace) {
51                 zlib_deflateEnd(stream);
52                 vfree(stream->workspace);
53                 stream->workspace = NULL;
54         }
55 }
56
57 static void zlib_decomp_exit(struct zlib_ctx *ctx)
58 {
59         struct z_stream_s *stream = &ctx->decomp_stream;
60
61         if (stream->workspace) {
62                 zlib_inflateEnd(stream);
63                 kfree(stream->workspace);
64                 stream->workspace = NULL;
65         }
66 }
67
68 static int zlib_init(struct crypto_tfm *tfm)
69 {
70         return 0;
71 }
72
73 static void zlib_exit(struct crypto_tfm *tfm)
74 {
75         struct zlib_ctx *ctx = crypto_tfm_ctx(tfm);
76
77         zlib_comp_exit(ctx);
78         zlib_decomp_exit(ctx);
79 }
80
81
82 static int zlib_compress_setup(struct crypto_pcomp *tfm, void *params,
83                                unsigned int len)
84 {
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         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         workspacesize = zlib_deflate_workspacesize();
98         stream->workspace = vzalloc(workspacesize);
99         if (!stream->workspace)
100                 return -ENOMEM;
101
102         ret = zlib_deflateInit2(stream,
103                                 tb[ZLIB_COMP_LEVEL]
104                                         ? nla_get_u32(tb[ZLIB_COMP_LEVEL])
105                                         : Z_DEFAULT_COMPRESSION,
106                                 tb[ZLIB_COMP_METHOD]
107                                         ? nla_get_u32(tb[ZLIB_COMP_METHOD])
108                                         : Z_DEFLATED,
109                                 tb[ZLIB_COMP_WINDOWBITS]
110                                         ? nla_get_u32(tb[ZLIB_COMP_WINDOWBITS])
111                                         : MAX_WBITS,
112                                 tb[ZLIB_COMP_MEMLEVEL]
113                                         ? nla_get_u32(tb[ZLIB_COMP_MEMLEVEL])
114                                         : DEF_MEM_LEVEL,
115                                 tb[ZLIB_COMP_STRATEGY]
116                                         ? nla_get_u32(tb[ZLIB_COMP_STRATEGY])
117                                         : Z_DEFAULT_STRATEGY);
118         if (ret != Z_OK) {
119                 vfree(stream->workspace);
120                 stream->workspace = NULL;
121                 return -EINVAL;
122         }
123
124         return 0;
125 }
126
127 static int zlib_compress_init(struct crypto_pcomp *tfm)
128 {
129         int ret;
130         struct zlib_ctx *dctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
131         struct z_stream_s *stream = &dctx->comp_stream;
132
133         ret = zlib_deflateReset(stream);
134         if (ret != Z_OK)
135                 return -EINVAL;
136
137         return 0;
138 }
139
140 static int zlib_compress_update(struct crypto_pcomp *tfm,
141                                 struct comp_request *req)
142 {
143         int ret;
144         struct zlib_ctx *dctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
145         struct z_stream_s *stream = &dctx->comp_stream;
146
147         pr_debug("avail_in %u, avail_out %u\n", req->avail_in, req->avail_out);
148         stream->next_in = req->next_in;
149         stream->avail_in = req->avail_in;
150         stream->next_out = req->next_out;
151         stream->avail_out = req->avail_out;
152
153         ret = zlib_deflate(stream, Z_NO_FLUSH);
154         switch (ret) {
155         case Z_OK:
156                 break;
157
158         case Z_BUF_ERROR:
159                 pr_debug("zlib_deflate could not make progress\n");
160                 return -EAGAIN;
161
162         default:
163                 pr_debug("zlib_deflate failed %d\n", ret);
164                 return -EINVAL;
165         }
166
167         ret = req->avail_out - stream->avail_out;
168         pr_debug("avail_in %u, avail_out %u (consumed %u, produced %u)\n",
169                  stream->avail_in, stream->avail_out,
170                  req->avail_in - stream->avail_in, ret);
171         req->next_in = stream->next_in;
172         req->avail_in = stream->avail_in;
173         req->next_out = stream->next_out;
174         req->avail_out = stream->avail_out;
175         return ret;
176 }
177
178 static int zlib_compress_final(struct crypto_pcomp *tfm,
179                                struct comp_request *req)
180 {
181         int ret;
182         struct zlib_ctx *dctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
183         struct z_stream_s *stream = &dctx->comp_stream;
184
185         pr_debug("avail_in %u, avail_out %u\n", req->avail_in, req->avail_out);
186         stream->next_in = req->next_in;
187         stream->avail_in = req->avail_in;
188         stream->next_out = req->next_out;
189         stream->avail_out = req->avail_out;
190
191         ret = zlib_deflate(stream, Z_FINISH);
192         if (ret != Z_STREAM_END) {
193                 pr_debug("zlib_deflate failed %d\n", ret);
194                 return -EINVAL;
195         }
196
197         ret = req->avail_out - stream->avail_out;
198         pr_debug("avail_in %u, avail_out %u (consumed %u, produced %u)\n",
199                  stream->avail_in, stream->avail_out,
200                  req->avail_in - stream->avail_in, ret);
201         req->next_in = stream->next_in;
202         req->avail_in = stream->avail_in;
203         req->next_out = stream->next_out;
204         req->avail_out = stream->avail_out;
205         return ret;
206 }
207
208
209 static int zlib_decompress_setup(struct crypto_pcomp *tfm, void *params,
210                                  unsigned int len)
211 {
212         struct zlib_ctx *ctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
213         struct z_stream_s *stream = &ctx->decomp_stream;
214         struct nlattr *tb[ZLIB_DECOMP_MAX + 1];
215         int ret = 0;
216
217         ret = nla_parse(tb, ZLIB_DECOMP_MAX, params, len, NULL);
218         if (ret)
219                 return ret;
220
221         zlib_decomp_exit(ctx);
222
223         ctx->decomp_windowBits = tb[ZLIB_DECOMP_WINDOWBITS]
224                                  ? nla_get_u32(tb[ZLIB_DECOMP_WINDOWBITS])
225                                  : DEF_WBITS;
226
227         stream->workspace = kzalloc(zlib_inflate_workspacesize(), GFP_KERNEL);
228         if (!stream->workspace)
229                 return -ENOMEM;
230
231         ret = zlib_inflateInit2(stream, ctx->decomp_windowBits);
232         if (ret != Z_OK) {
233                 kfree(stream->workspace);
234                 stream->workspace = NULL;
235                 return -EINVAL;
236         }
237
238         return 0;
239 }
240
241 static int zlib_decompress_init(struct crypto_pcomp *tfm)
242 {
243         int ret;
244         struct zlib_ctx *dctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
245         struct z_stream_s *stream = &dctx->decomp_stream;
246
247         ret = zlib_inflateReset(stream);
248         if (ret != Z_OK)
249                 return -EINVAL;
250
251         return 0;
252 }
253
254 static int zlib_decompress_update(struct crypto_pcomp *tfm,
255                                   struct comp_request *req)
256 {
257         int ret;
258         struct zlib_ctx *dctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
259         struct z_stream_s *stream = &dctx->decomp_stream;
260
261         pr_debug("avail_in %u, avail_out %u\n", req->avail_in, req->avail_out);
262         stream->next_in = req->next_in;
263         stream->avail_in = req->avail_in;
264         stream->next_out = req->next_out;
265         stream->avail_out = req->avail_out;
266
267         ret = zlib_inflate(stream, Z_SYNC_FLUSH);
268         switch (ret) {
269         case Z_OK:
270         case Z_STREAM_END:
271                 break;
272
273         case Z_BUF_ERROR:
274                 pr_debug("zlib_inflate could not make progress\n");
275                 return -EAGAIN;
276
277         default:
278                 pr_debug("zlib_inflate failed %d\n", ret);
279                 return -EINVAL;
280         }
281
282         ret = req->avail_out - stream->avail_out;
283         pr_debug("avail_in %u, avail_out %u (consumed %u, produced %u)\n",
284                  stream->avail_in, stream->avail_out,
285                  req->avail_in - stream->avail_in, ret);
286         req->next_in = stream->next_in;
287         req->avail_in = stream->avail_in;
288         req->next_out = stream->next_out;
289         req->avail_out = stream->avail_out;
290         return ret;
291 }
292
293 static int zlib_decompress_final(struct crypto_pcomp *tfm,
294                                  struct comp_request *req)
295 {
296         int ret;
297         struct zlib_ctx *dctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
298         struct z_stream_s *stream = &dctx->decomp_stream;
299
300         pr_debug("avail_in %u, avail_out %u\n", req->avail_in, req->avail_out);
301         stream->next_in = req->next_in;
302         stream->avail_in = req->avail_in;
303         stream->next_out = req->next_out;
304         stream->avail_out = req->avail_out;
305
306         if (dctx->decomp_windowBits < 0) {
307                 ret = zlib_inflate(stream, Z_SYNC_FLUSH);
308                 /*
309                  * Work around a bug in zlib, which sometimes wants to taste an
310                  * extra byte when being used in the (undocumented) raw deflate
311                  * mode. (From USAGI).
312                  */
313                 if (ret == Z_OK && !stream->avail_in && stream->avail_out) {
314                         const void *saved_next_in = stream->next_in;
315                         u8 zerostuff = 0;
316
317                         stream->next_in = &zerostuff;
318                         stream->avail_in = 1;
319                         ret = zlib_inflate(stream, Z_FINISH);
320                         stream->next_in = saved_next_in;
321                         stream->avail_in = 0;
322                 }
323         } else
324                 ret = zlib_inflate(stream, Z_FINISH);
325         if (ret != Z_STREAM_END) {
326                 pr_debug("zlib_inflate failed %d\n", ret);
327                 return -EINVAL;
328         }
329
330         ret = req->avail_out - stream->avail_out;
331         pr_debug("avail_in %u, avail_out %u (consumed %u, produced %u)\n",
332                  stream->avail_in, stream->avail_out,
333                  req->avail_in - stream->avail_in, ret);
334         req->next_in = stream->next_in;
335         req->avail_in = stream->avail_in;
336         req->next_out = stream->next_out;
337         req->avail_out = stream->avail_out;
338         return ret;
339 }
340
341
342 static struct pcomp_alg zlib_alg = {
343         .compress_setup         = zlib_compress_setup,
344         .compress_init          = zlib_compress_init,
345         .compress_update        = zlib_compress_update,
346         .compress_final         = zlib_compress_final,
347         .decompress_setup       = zlib_decompress_setup,
348         .decompress_init        = zlib_decompress_init,
349         .decompress_update      = zlib_decompress_update,
350         .decompress_final       = zlib_decompress_final,
351
352         .base                   = {
353                 .cra_name       = "zlib",
354                 .cra_flags      = CRYPTO_ALG_TYPE_PCOMPRESS,
355                 .cra_ctxsize    = sizeof(struct zlib_ctx),
356                 .cra_module     = THIS_MODULE,
357                 .cra_init       = zlib_init,
358                 .cra_exit       = zlib_exit,
359         }
360 };
361
362 static int __init zlib_mod_init(void)
363 {
364         return crypto_register_pcomp(&zlib_alg);
365 }
366
367 static void __exit zlib_mod_fini(void)
368 {
369         crypto_unregister_pcomp(&zlib_alg);
370 }
371
372 module_init(zlib_mod_init);
373 module_exit(zlib_mod_fini);
374
375 MODULE_LICENSE("GPL");
376 MODULE_DESCRIPTION("Zlib Compression Algorithm");
377 MODULE_AUTHOR("Sony Corporation");