linux/drivers/staging/rtl8192e/rtllib_crypt.c
<<
>>
Prefs
   1/*
   2 * Host AP crypto routines
   3 *
   4 * Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
   5 * Portions Copyright (C) 2004, Intel Corporation <jketreno@linux.intel.com>
   6 *
   7 * This program is free software; you can redistribute it and/or modify
   8 * it under the terms of the GNU General Public License version 2 as
   9 * published by the Free Software Foundation. See README and COPYING for
  10 * more details.
  11 *
  12 */
  13
  14#include <linux/module.h>
  15#include <linux/init.h>
  16#include <linux/slab.h>
  17#include <linux/string.h>
  18#include <linux/errno.h>
  19
  20#include "rtllib.h"
  21
  22struct rtllib_crypto_alg {
  23        struct list_head list;
  24        struct lib80211_crypto_ops *ops;
  25};
  26
  27
  28struct rtllib_crypto {
  29        struct list_head algs;
  30        spinlock_t lock;
  31};
  32
  33static struct rtllib_crypto *hcrypt;
  34
  35void rtllib_crypt_deinit_entries(struct lib80211_crypt_info *info,
  36                                           int force)
  37{
  38        struct list_head *ptr, *n;
  39        struct lib80211_crypt_data *entry;
  40
  41        for (ptr = info->crypt_deinit_list.next, n = ptr->next;
  42             ptr != &info->crypt_deinit_list; ptr = n, n = ptr->next) {
  43                entry = list_entry(ptr, struct lib80211_crypt_data, list);
  44
  45                if (atomic_read(&entry->refcnt) != 0 && !force)
  46                        continue;
  47
  48                list_del(ptr);
  49
  50                if (entry->ops)
  51                        entry->ops->deinit(entry->priv);
  52                kfree(entry);
  53        }
  54}
  55EXPORT_SYMBOL(rtllib_crypt_deinit_entries);
  56
  57void rtllib_crypt_deinit_handler(unsigned long data)
  58{
  59        struct lib80211_crypt_info *info = (struct lib80211_crypt_info *)data;
  60        unsigned long flags;
  61
  62        spin_lock_irqsave(info->lock, flags);
  63        rtllib_crypt_deinit_entries(info, 0);
  64        if (!list_empty(&info->crypt_deinit_list)) {
  65                printk(KERN_DEBUG "%s: entries remaining in delayed crypt "
  66                       "deletion list\n", info->name);
  67                info->crypt_deinit_timer.expires = jiffies + HZ;
  68                add_timer(&info->crypt_deinit_timer);
  69        }
  70        spin_unlock_irqrestore(info->lock, flags);
  71
  72}
  73EXPORT_SYMBOL(rtllib_crypt_deinit_handler);
  74
  75void rtllib_crypt_delayed_deinit(struct lib80211_crypt_info *info,
  76                                 struct lib80211_crypt_data **crypt)
  77{
  78        struct lib80211_crypt_data *tmp;
  79        unsigned long flags;
  80
  81        if (*crypt == NULL)
  82                return;
  83
  84        tmp = *crypt;
  85        *crypt = NULL;
  86
  87        /* must not run ops->deinit() while there may be pending encrypt or
  88         * decrypt operations. Use a list of delayed deinits to avoid needing
  89         * locking. */
  90
  91        spin_lock_irqsave(info->lock, flags);
  92        list_add(&tmp->list, &info->crypt_deinit_list);
  93        if (!timer_pending(&info->crypt_deinit_timer)) {
  94                info->crypt_deinit_timer.expires = jiffies + HZ;
  95                add_timer(&info->crypt_deinit_timer);
  96        }
  97        spin_unlock_irqrestore(info->lock, flags);
  98}
  99EXPORT_SYMBOL(rtllib_crypt_delayed_deinit);
 100
 101int rtllib_register_crypto_ops(struct lib80211_crypto_ops *ops)
 102{
 103        unsigned long flags;
 104        struct rtllib_crypto_alg *alg;
 105
 106        if (hcrypt == NULL)
 107                return -1;
 108
 109        alg = kzalloc(sizeof(*alg), GFP_KERNEL);
 110        if (alg == NULL)
 111                return -ENOMEM;
 112
 113        alg->ops = ops;
 114
 115        spin_lock_irqsave(&hcrypt->lock, flags);
 116        list_add(&alg->list, &hcrypt->algs);
 117        spin_unlock_irqrestore(&hcrypt->lock, flags);
 118
 119        printk(KERN_DEBUG "rtllib_crypt: registered algorithm '%s'\n",
 120               ops->name);
 121
 122        return 0;
 123}
 124EXPORT_SYMBOL(rtllib_register_crypto_ops);
 125
 126int rtllib_unregister_crypto_ops(struct lib80211_crypto_ops *ops)
 127{
 128        unsigned long flags;
 129        struct list_head *ptr;
 130        struct rtllib_crypto_alg *del_alg = NULL;
 131
 132        if (hcrypt == NULL)
 133                return -1;
 134
 135        spin_lock_irqsave(&hcrypt->lock, flags);
 136        for (ptr = hcrypt->algs.next; ptr != &hcrypt->algs; ptr = ptr->next) {
 137                struct rtllib_crypto_alg *alg =
 138                        (struct rtllib_crypto_alg *) ptr;
 139                if (alg->ops == ops) {
 140                        list_del(&alg->list);
 141                        del_alg = alg;
 142                        break;
 143                }
 144        }
 145        spin_unlock_irqrestore(&hcrypt->lock, flags);
 146
 147        if (del_alg) {
 148                printk(KERN_DEBUG "rtllib_crypt: unregistered algorithm "
 149                       "'%s'\n", ops->name);
 150                kfree(del_alg);
 151        }
 152
 153        return del_alg ? 0 : -1;
 154}
 155EXPORT_SYMBOL(rtllib_unregister_crypto_ops);
 156
 157
 158struct lib80211_crypto_ops *rtllib_get_crypto_ops(const char *name)
 159{
 160        unsigned long flags;
 161        struct list_head *ptr;
 162        struct rtllib_crypto_alg *found_alg = NULL;
 163
 164        if (hcrypt == NULL)
 165                return NULL;
 166
 167        spin_lock_irqsave(&hcrypt->lock, flags);
 168        for (ptr = hcrypt->algs.next; ptr != &hcrypt->algs; ptr = ptr->next) {
 169                struct rtllib_crypto_alg *alg =
 170                        (struct rtllib_crypto_alg *) ptr;
 171                if (strcmp(alg->ops->name, name) == 0) {
 172                        found_alg = alg;
 173                        break;
 174                }
 175        }
 176        spin_unlock_irqrestore(&hcrypt->lock, flags);
 177
 178        if (found_alg)
 179                return found_alg->ops;
 180        else
 181                return NULL;
 182}
 183EXPORT_SYMBOL(rtllib_get_crypto_ops);
 184
 185
 186static void * rtllib_crypt_null_init(int keyidx) { return (void *) 1; }
 187static void rtllib_crypt_null_deinit(void *priv) {}
 188
 189static struct lib80211_crypto_ops rtllib_crypt_null = {
 190        .name                   = "NULL",
 191        .init                   = rtllib_crypt_null_init,
 192        .deinit                 = rtllib_crypt_null_deinit,
 193        .encrypt_mpdu           = NULL,
 194        .decrypt_mpdu           = NULL,
 195        .encrypt_msdu           = NULL,
 196        .decrypt_msdu           = NULL,
 197        .set_key                = NULL,
 198        .get_key                = NULL,
 199        .extra_mpdu_prefix_len  = 0,
 200        .extra_mpdu_postfix_len = 0,
 201        .extra_msdu_prefix_len  = 0,
 202        .extra_msdu_postfix_len = 0,
 203        .owner                  = THIS_MODULE,
 204};
 205
 206
 207int __init rtllib_crypto_init(void)
 208{
 209        int ret = -ENOMEM;
 210
 211        hcrypt = kzalloc(sizeof(*hcrypt), GFP_KERNEL);
 212        if (!hcrypt)
 213                goto out;
 214
 215        INIT_LIST_HEAD(&hcrypt->algs);
 216        spin_lock_init(&hcrypt->lock);
 217
 218        ret = lib80211_register_crypto_ops(&rtllib_crypt_null);
 219        if (ret < 0) {
 220                kfree(hcrypt);
 221                hcrypt = NULL;
 222        }
 223out:
 224        return ret;
 225}
 226
 227
 228void __exit rtllib_crypto_deinit(void)
 229{
 230        struct list_head *ptr, *n;
 231
 232        if (hcrypt == NULL)
 233                return;
 234
 235        for (ptr = hcrypt->algs.next, n = ptr->next; ptr != &hcrypt->algs;
 236             ptr = n, n = ptr->next) {
 237                struct rtllib_crypto_alg *alg =
 238                        (struct rtllib_crypto_alg *) ptr;
 239                list_del(ptr);
 240                printk(KERN_DEBUG "rtllib_crypt: unregistered algorithm "
 241                       "'%s' (deinit)\n", alg->ops->name);
 242                kfree(alg);
 243        }
 244
 245        kfree(hcrypt);
 246}
 247
 248module_init(rtllib_crypto_init);
 249module_exit(rtllib_crypto_deinit);
 250
 251MODULE_LICENSE("GPL");
 252