The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/crypto/zlib.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 80ff3d5803f3a8307c8635a275254b31


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.