bridge: add notification over netlink when STP changes state
[platform/adaptation/renesas_rcar/renesas_kernel.git] / crypto / deflate.c
1 /*
2  * Cryptographic API.
3  *
4  * Deflate algorithm (RFC 1951), implemented here primarily for use
5  * by IPCOMP (RFC 3173 & RFC 2394).
6  *
7  * Copyright (c) 2003 James Morris <jmorris@intercode.com.au>
8  *
9  * This program is free software; you can redistribute it and/or modify it
10  * under the terms of the GNU General Public License as published by the Free
11  * Software Foundation; either version 2 of the License, or (at your option)
12  * any later version.
13  *
14  * FIXME: deflate transforms will require up to a total of about 436k of kernel
15  * memory on i386 (390k for compression, the rest for decompression), as the
16  * current zlib kernel code uses a worst case pre-allocation system by default.
17  * This needs to be fixed so that the amount of memory required is properly
18  * related to the  winbits and memlevel parameters.
19  *
20  * The default winbits of 11 should suit most packets, and it may be something
21  * to configure on a per-tfm basis in the future.
22  *
23  * Currently, compression history is not maintained between tfm calls, as
24  * it is not needed for IPCOMP and keeps the code simpler.  It can be
25  * implemented if someone wants it.
26  */
27 #include <linux/init.h>
28 #include <linux/module.h>
29 #include <linux/crypto.h>
30 #include <linux/zlib.h>
31 #include <linux/vmalloc.h>
32 #include <linux/interrupt.h>
33 #include <linux/mm.h>
34 #include <linux/net.h>
35
36 #define DEFLATE_DEF_LEVEL               Z_DEFAULT_COMPRESSION
37 #define DEFLATE_DEF_WINBITS             11
38 #define DEFLATE_DEF_MEMLEVEL            MAX_MEM_LEVEL
39
40 struct deflate_ctx {
41         struct z_stream_s comp_stream;
42         struct z_stream_s decomp_stream;
43 };
44
45 static int deflate_comp_init(struct deflate_ctx *ctx)
46 {
47         int ret = 0;
48         struct z_stream_s *stream = &ctx->comp_stream;
49
50         stream->workspace = vzalloc(zlib_deflate_workspacesize(
51                                 -DEFLATE_DEF_WINBITS, DEFLATE_DEF_MEMLEVEL));
52         if (!stream->workspace) {
53                 ret = -ENOMEM;
54                 goto out;
55         }
56         ret = zlib_deflateInit2(stream, DEFLATE_DEF_LEVEL, Z_DEFLATED,
57                                 -DEFLATE_DEF_WINBITS, DEFLATE_DEF_MEMLEVEL,
58                                 Z_DEFAULT_STRATEGY);
59         if (ret != Z_OK) {
60                 ret = -EINVAL;
61                 goto out_free;
62         }
63 out:
64         return ret;
65 out_free:
66         vfree(stream->workspace);
67         goto out;
68 }
69
70 static int deflate_decomp_init(struct deflate_ctx *ctx)
71 {
72         int ret = 0;
73         struct z_stream_s *stream = &ctx->decomp_stream;
74
75         stream->workspace = vzalloc(zlib_inflate_workspacesize());
76         if (!stream->workspace) {
77                 ret = -ENOMEM;
78                 goto out;
79         }
80         ret = zlib_inflateInit2(stream, -DEFLATE_DEF_WINBITS);
81         if (ret != Z_OK) {
82                 ret = -EINVAL;
83                 goto out_free;
84         }
85 out:
86         return ret;
87 out_free:
88         vfree(stream->workspace);
89         goto out;
90 }
91
92 static void deflate_comp_exit(struct deflate_ctx *ctx)
93 {
94         zlib_deflateEnd(&ctx->comp_stream);
95         vfree(ctx->comp_stream.workspace);
96 }
97
98 static void deflate_decomp_exit(struct deflate_ctx *ctx)
99 {
100         zlib_inflateEnd(&ctx->decomp_stream);
101         vfree(ctx->decomp_stream.workspace);
102 }
103
104 static int deflate_init(struct crypto_tfm *tfm)
105 {
106         struct deflate_ctx *ctx = crypto_tfm_ctx(tfm);
107         int ret;
108
109         ret = deflate_comp_init(ctx);
110         if (ret)
111                 goto out;
112         ret = deflate_decomp_init(ctx);
113         if (ret)
114                 deflate_comp_exit(ctx);
115 out:
116         return ret;
117 }
118
119 static void deflate_exit(struct crypto_tfm *tfm)
120 {
121         struct deflate_ctx *ctx = crypto_tfm_ctx(tfm);
122
123         deflate_comp_exit(ctx);
124         deflate_decomp_exit(ctx);
125 }
126
127 static int deflate_compress(struct crypto_tfm *tfm, const u8 *src,
128                             unsigned int slen, u8 *dst, unsigned int *dlen)
129 {
130         int ret = 0;
131         struct deflate_ctx *dctx = crypto_tfm_ctx(tfm);
132         struct z_stream_s *stream = &dctx->comp_stream;
133
134         ret = zlib_deflateReset(stream);
135         if (ret != Z_OK) {
136                 ret = -EINVAL;
137                 goto out;
138         }
139
140         stream->next_in = (u8 *)src;
141         stream->avail_in = slen;
142         stream->next_out = (u8 *)dst;
143         stream->avail_out = *dlen;
144
145         ret = zlib_deflate(stream, Z_FINISH);
146         if (ret != Z_STREAM_END) {
147                 ret = -EINVAL;
148                 goto out;
149         }
150         ret = 0;
151         *dlen = stream->total_out;
152 out:
153         return ret;
154 }
155
156 static int deflate_decompress(struct crypto_tfm *tfm, const u8 *src,
157                               unsigned int slen, u8 *dst, unsigned int *dlen)
158 {
159
160         int ret = 0;
161         struct deflate_ctx *dctx = crypto_tfm_ctx(tfm);
162         struct z_stream_s *stream = &dctx->decomp_stream;
163
164         ret = zlib_inflateReset(stream);
165         if (ret != Z_OK) {
166                 ret = -EINVAL;
167                 goto out;
168         }
169
170         stream->next_in = (u8 *)src;
171         stream->avail_in = slen;
172         stream->next_out = (u8 *)dst;
173         stream->avail_out = *dlen;
174
175         ret = zlib_inflate(stream, Z_SYNC_FLUSH);
176         /*
177          * Work around a bug in zlib, which sometimes wants to taste an extra
178          * byte when being used in the (undocumented) raw deflate mode.
179          * (From USAGI).
180          */
181         if (ret == Z_OK && !stream->avail_in && stream->avail_out) {
182                 u8 zerostuff = 0;
183                 stream->next_in = &zerostuff;
184                 stream->avail_in = 1;
185                 ret = zlib_inflate(stream, Z_FINISH);
186         }
187         if (ret != Z_STREAM_END) {
188                 ret = -EINVAL;
189                 goto out;
190         }
191         ret = 0;
192         *dlen = stream->total_out;
193 out:
194         return ret;
195 }
196
197 static struct crypto_alg alg = {
198         .cra_name               = "deflate",
199         .cra_flags              = CRYPTO_ALG_TYPE_COMPRESS,
200         .cra_ctxsize            = sizeof(struct deflate_ctx),
201         .cra_module             = THIS_MODULE,
202         .cra_list               = LIST_HEAD_INIT(alg.cra_list),
203         .cra_init               = deflate_init,
204         .cra_exit               = deflate_exit,
205         .cra_u                  = { .compress = {
206         .coa_compress           = deflate_compress,
207         .coa_decompress         = deflate_decompress } }
208 };
209
210 static int __init deflate_mod_init(void)
211 {
212         return crypto_register_alg(&alg);
213 }
214
215 static void __exit deflate_mod_fini(void)
216 {
217         crypto_unregister_alg(&alg);
218 }
219
220 module_init(deflate_mod_init);
221 module_exit(deflate_mod_fini);
222
223 MODULE_LICENSE("GPL");
224 MODULE_DESCRIPTION("Deflate Compression Algorithm for IPCOMP");
225 MODULE_AUTHOR("James Morris <jmorris@intercode.com.au>");
226