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/deflate.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  * 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 #include <linux/slab.h>
   36 
   37 #define DEFLATE_DEF_LEVEL               Z_DEFAULT_COMPRESSION
   38 #define DEFLATE_DEF_WINBITS             11
   39 #define DEFLATE_DEF_MEMLEVEL            MAX_MEM_LEVEL
   40 
   41 struct deflate_ctx {
   42         int comp_initialized;
   43         int decomp_initialized;
   44         struct z_stream_s comp_stream;
   45         struct z_stream_s decomp_stream;
   46 };
   47 
   48 static inline int deflate_gfp(void)
   49 {
   50         return in_softirq() ? GFP_ATOMIC : GFP_KERNEL;
   51 }
   52 
   53 static int deflate_init(void *ctx)
   54 {
   55         return 0;
   56 }
   57 
   58 static void deflate_exit(void *ctx)
   59 {
   60         struct deflate_ctx *dctx = ctx;
   61 
   62         if (dctx->comp_initialized)
   63                 vfree(dctx->comp_stream.workspace);
   64         if (dctx->decomp_initialized)
   65                 kfree(dctx->decomp_stream.workspace);
   66 }
   67 
   68 /*
   69  * Lazy initialization to make interface simple without allocating
   70  * un-needed workspaces.  Thus can be called in softirq context.
   71  */
   72 static int deflate_comp_init(struct deflate_ctx *ctx)
   73 {
   74         int ret = 0;
   75         struct z_stream_s *stream = &ctx->comp_stream;
   76 
   77         stream->workspace = __vmalloc(zlib_deflate_workspacesize(),
   78                                       deflate_gfp()|__GFP_HIGHMEM,
   79                                       PAGE_KERNEL);
   80         if (!stream->workspace ) {
   81                 ret = -ENOMEM;
   82                 goto out;
   83         }
   84         memset(stream->workspace, 0, zlib_deflate_workspacesize());
   85         ret = zlib_deflateInit2(stream, DEFLATE_DEF_LEVEL, Z_DEFLATED,
   86                                 -DEFLATE_DEF_WINBITS, DEFLATE_DEF_MEMLEVEL,
   87                                 Z_DEFAULT_STRATEGY);
   88         if (ret != Z_OK) {
   89                 ret = -EINVAL;
   90                 goto out_free;
   91         }
   92         ctx->comp_initialized = 1;
   93 out:    
   94         return ret;
   95 out_free:
   96         vfree(stream->workspace);
   97         goto out;
   98 }
   99 
  100 static int deflate_decomp_init(struct deflate_ctx *ctx)
  101 {
  102         int ret = 0;
  103         struct z_stream_s *stream = &ctx->decomp_stream;
  104 
  105         stream->workspace = kmalloc(zlib_inflate_workspacesize(),
  106                                     deflate_gfp());
  107         if (!stream->workspace ) {
  108                 ret = -ENOMEM;
  109                 goto out;
  110         }
  111         memset(stream->workspace, 0, zlib_inflate_workspacesize());
  112         ret = zlib_inflateInit2(stream, -DEFLATE_DEF_WINBITS);
  113         if (ret != Z_OK) {
  114                 ret = -EINVAL;
  115                 goto out_free;
  116         }
  117         ctx->decomp_initialized = 1;
  118 out:
  119         return ret;
  120 out_free:
  121         kfree(stream->workspace);
  122         goto out;
  123 }
  124 
  125 static int deflate_compress(void *ctx, const u8 *src, unsigned int slen,
  126                             u8 *dst, unsigned int *dlen)
  127 {
  128         int ret = 0;
  129         struct deflate_ctx *dctx = ctx;
  130         struct z_stream_s *stream = &dctx->comp_stream;
  131 
  132         if (!dctx->comp_initialized) {
  133                 ret = deflate_comp_init(dctx);
  134                 if (ret)
  135                         goto out;
  136         }
  137 
  138         ret = zlib_deflateReset(stream);
  139         if (ret != Z_OK) {
  140                 ret = -EINVAL;
  141                 goto out;
  142         }
  143 
  144         stream->next_in = (u8 *)src;
  145         stream->avail_in = slen;
  146         stream->next_out = (u8 *)dst;
  147         stream->avail_out = *dlen;
  148 
  149         ret = zlib_deflate(stream, Z_FINISH);
  150         if (ret != Z_STREAM_END) {
  151                 ret = -EINVAL;
  152                 goto out;
  153         }
  154         ret = 0;
  155         *dlen = stream->total_out;
  156 out:
  157         return ret;
  158 }
  159  
  160 static int deflate_decompress(void *ctx, const u8 *src, unsigned int slen,
  161                               u8 *dst, unsigned int *dlen)
  162 {
  163         
  164         int ret = 0;
  165         struct deflate_ctx *dctx = ctx;
  166         struct z_stream_s *stream = &dctx->decomp_stream;
  167 
  168         if (!dctx->decomp_initialized) {
  169                 ret = deflate_decomp_init(dctx);
  170                 if (ret)
  171                         goto out;
  172         }
  173 
  174         ret = zlib_inflateReset(stream);
  175         if (ret != Z_OK) {
  176                 ret = -EINVAL;
  177                 goto out;
  178         }
  179 
  180         stream->next_in = (u8 *)src;
  181         stream->avail_in = slen;
  182         stream->next_out = (u8 *)dst;
  183         stream->avail_out = *dlen;
  184 
  185         ret = zlib_inflate(stream, Z_SYNC_FLUSH);
  186         /*
  187          * Work around a bug in zlib, which sometimes wants to taste an extra
  188          * byte when being used in the (undocumented) raw deflate mode.
  189          * (From USAGI).
  190          */
  191         if (ret == Z_OK && !stream->avail_in && stream->avail_out) {
  192                 u8 zerostuff = 0;
  193                 stream->next_in = &zerostuff;
  194                 stream->avail_in = 1; 
  195                 ret = zlib_inflate(stream, Z_FINISH);
  196         }
  197         if (ret != Z_STREAM_END) {
  198                 ret = -EINVAL;
  199                 goto out;
  200         }
  201         ret = 0;
  202         *dlen = stream->total_out;
  203 out:
  204         return ret;
  205 }
  206 
  207 static struct crypto_alg alg = {
  208         .cra_name               = "deflate",
  209         .cra_flags              = CRYPTO_ALG_TYPE_COMPRESS,
  210         .cra_ctxsize            = sizeof(struct deflate_ctx),
  211         .cra_module             = THIS_MODULE,
  212         .cra_list               = LIST_HEAD_INIT(alg.cra_list),
  213         .cra_u                  = { .compress = {
  214         .coa_init               = deflate_init,
  215         .coa_exit               = deflate_exit,
  216         .coa_compress           = deflate_compress,
  217         .coa_decompress         = deflate_decompress } }
  218 };
  219 
  220 static int __init init(void)
  221 {
  222         return crypto_register_alg(&alg);
  223 }
  224 
  225 static void __exit fini(void)
  226 {
  227         crypto_unregister_alg(&alg);
  228 }
  229 
  230 module_init(init);
  231 module_exit(fini);
  232 
  233 MODULE_LICENSE("GPL");
  234 MODULE_DESCRIPTION("Deflate Compression Algorithm for IPCOMP");
  235 MODULE_AUTHOR("James Morris <jmorris@intercode.com.au>");
  236 

Cache object: 3b26f2c9ad0015b88b64924c93389144


[ 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.