linux/crypto/842.c
<<
>>
Prefs
   1/*
   2 * Cryptographic API for the 842 compression algorithm.
   3 *
   4 * This program is free software; you can redistribute it and/or modify
   5 * it under the terms of the GNU General Public License as published by
   6 * the Free Software Foundation; either version 2 of the License, or
   7 * (at your option) any later version.
   8 *
   9 * This program is distributed in the hope that it will be useful,
  10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12 * GNU General Public License for more details.
  13 *
  14 * You should have received a copy of the GNU General Public License
  15 * along with this program; if not, write to the Free Software
  16 * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  17 *
  18 * Copyright (C) IBM Corporation, 2011
  19 *
  20 * Authors: Robert Jennings <rcj@linux.vnet.ibm.com>
  21 *          Seth Jennings <sjenning@linux.vnet.ibm.com>
  22 */
  23
  24#include <linux/init.h>
  25#include <linux/module.h>
  26#include <linux/crypto.h>
  27#include <linux/vmalloc.h>
  28#include <linux/nx842.h>
  29#include <linux/lzo.h>
  30#include <linux/timer.h>
  31
  32static int nx842_uselzo;
  33
  34struct nx842_ctx {
  35        void *nx842_wmem; /* working memory for 842/lzo */
  36};
  37
  38enum nx842_crypto_type {
  39        NX842_CRYPTO_TYPE_842,
  40        NX842_CRYPTO_TYPE_LZO
  41};
  42
  43#define NX842_SENTINEL 0xdeadbeef
  44
  45struct nx842_crypto_header {
  46        unsigned int sentinel; /* debug */
  47        enum nx842_crypto_type type;
  48};
  49
  50static int nx842_init(struct crypto_tfm *tfm)
  51{
  52        struct nx842_ctx *ctx = crypto_tfm_ctx(tfm);
  53        int wmemsize;
  54
  55        wmemsize = max_t(int, nx842_get_workmem_size(), LZO1X_MEM_COMPRESS);
  56        ctx->nx842_wmem = kmalloc(wmemsize, GFP_NOFS);
  57        if (!ctx->nx842_wmem)
  58                return -ENOMEM;
  59
  60        return 0;
  61}
  62
  63static void nx842_exit(struct crypto_tfm *tfm)
  64{
  65        struct nx842_ctx *ctx = crypto_tfm_ctx(tfm);
  66
  67        kfree(ctx->nx842_wmem);
  68}
  69
  70static void nx842_reset_uselzo(unsigned long data)
  71{
  72        nx842_uselzo = 0;
  73}
  74
  75static DEFINE_TIMER(failover_timer, nx842_reset_uselzo, 0, 0);
  76
  77static int nx842_crypto_compress(struct crypto_tfm *tfm, const u8 *src,
  78                            unsigned int slen, u8 *dst, unsigned int *dlen)
  79{
  80        struct nx842_ctx *ctx = crypto_tfm_ctx(tfm);
  81        struct nx842_crypto_header *hdr;
  82        unsigned int tmp_len = *dlen;
  83        size_t lzodlen; /* needed for lzo */
  84        int err;
  85
  86        *dlen = 0;
  87        hdr = (struct nx842_crypto_header *)dst;
  88        hdr->sentinel = NX842_SENTINEL; /* debug */
  89        dst += sizeof(struct nx842_crypto_header);
  90        tmp_len -= sizeof(struct nx842_crypto_header);
  91        lzodlen = tmp_len;
  92
  93        if (likely(!nx842_uselzo)) {
  94                err = nx842_compress(src, slen, dst, &tmp_len, ctx->nx842_wmem);
  95
  96                if (likely(!err)) {
  97                        hdr->type = NX842_CRYPTO_TYPE_842;
  98                        *dlen = tmp_len + sizeof(struct nx842_crypto_header);
  99                        return 0;
 100                }
 101
 102                /* hardware failed */
 103                nx842_uselzo = 1;
 104
 105                /* set timer to check for hardware again in 1 second */
 106                mod_timer(&failover_timer, jiffies + msecs_to_jiffies(1000));
 107        }
 108
 109        /* no hardware, use lzo */
 110        err = lzo1x_1_compress(src, slen, dst, &lzodlen, ctx->nx842_wmem);
 111        if (err != LZO_E_OK)
 112                return -EINVAL;
 113
 114        hdr->type = NX842_CRYPTO_TYPE_LZO;
 115        *dlen = lzodlen + sizeof(struct nx842_crypto_header);
 116        return 0;
 117}
 118
 119static int nx842_crypto_decompress(struct crypto_tfm *tfm, const u8 *src,
 120                              unsigned int slen, u8 *dst, unsigned int *dlen)
 121{
 122        struct nx842_ctx *ctx = crypto_tfm_ctx(tfm);
 123        struct nx842_crypto_header *hdr;
 124        unsigned int tmp_len = *dlen;
 125        size_t lzodlen; /* needed for lzo */
 126        int err;
 127
 128        *dlen = 0;
 129        hdr = (struct nx842_crypto_header *)src;
 130
 131        if (unlikely(hdr->sentinel != NX842_SENTINEL))
 132                return -EINVAL;
 133
 134        src += sizeof(struct nx842_crypto_header);
 135        slen -= sizeof(struct nx842_crypto_header);
 136
 137        if (likely(hdr->type == NX842_CRYPTO_TYPE_842)) {
 138                err = nx842_decompress(src, slen, dst, &tmp_len,
 139                        ctx->nx842_wmem);
 140                if (err)
 141                        return -EINVAL;
 142                *dlen = tmp_len;
 143        } else if (hdr->type == NX842_CRYPTO_TYPE_LZO) {
 144                lzodlen = tmp_len;
 145                err = lzo1x_decompress_safe(src, slen, dst, &lzodlen);
 146                if (err != LZO_E_OK)
 147                        return -EINVAL;
 148                *dlen = lzodlen;
 149        } else
 150                return -EINVAL;
 151
 152        return 0;
 153}
 154
 155static struct crypto_alg alg = {
 156        .cra_name               = "842",
 157        .cra_flags              = CRYPTO_ALG_TYPE_COMPRESS,
 158        .cra_ctxsize            = sizeof(struct nx842_ctx),
 159        .cra_module             = THIS_MODULE,
 160        .cra_init               = nx842_init,
 161        .cra_exit               = nx842_exit,
 162        .cra_u                  = { .compress = {
 163        .coa_compress           = nx842_crypto_compress,
 164        .coa_decompress         = nx842_crypto_decompress } }
 165};
 166
 167static int __init nx842_mod_init(void)
 168{
 169        del_timer(&failover_timer);
 170        return crypto_register_alg(&alg);
 171}
 172
 173static void __exit nx842_mod_exit(void)
 174{
 175        crypto_unregister_alg(&alg);
 176}
 177
 178module_init(nx842_mod_init);
 179module_exit(nx842_mod_exit);
 180
 181MODULE_LICENSE("GPL");
 182MODULE_DESCRIPTION("842 Compression Algorithm");
 183