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