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