linux/drivers/staging/rtl8192su/ieee80211/ieee80211_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/config.h>
  15#include <linux/version.h>
  16#include <linux/module.h>
  17#include <linux/init.h>
  18#include <linux/slab.h>
  19#include <asm/string.h>
  20#include <asm/errno.h>
  21
  22#include "ieee80211.h"
  23
  24MODULE_AUTHOR("Jouni Malinen");
  25MODULE_DESCRIPTION("HostAP crypto");
  26MODULE_LICENSE("GPL");
  27
  28struct ieee80211_crypto_alg {
  29        struct list_head list;
  30        struct ieee80211_crypto_ops *ops;
  31};
  32
  33
  34struct ieee80211_crypto {
  35        struct list_head algs;
  36        spinlock_t lock;
  37};
  38
  39static struct ieee80211_crypto *hcrypt;
  40
  41void ieee80211_crypt_deinit_entries(struct ieee80211_device *ieee,
  42                                           int force)
  43{
  44        struct list_head *ptr, *n;
  45        struct ieee80211_crypt_data *entry;
  46
  47        for (ptr = ieee->crypt_deinit_list.next, n = ptr->next;
  48             ptr != &ieee->crypt_deinit_list; ptr = n, n = ptr->next) {
  49                entry = list_entry(ptr, struct ieee80211_crypt_data, list);
  50
  51                if (atomic_read(&entry->refcnt) != 0 && !force)
  52                        continue;
  53
  54                list_del(ptr);
  55
  56                if (entry->ops)
  57                        entry->ops->deinit(entry->priv);
  58                kfree(entry);
  59        }
  60}
  61
  62void ieee80211_crypt_deinit_handler(unsigned long data)
  63{
  64        struct ieee80211_device *ieee = (struct ieee80211_device *)data;
  65        unsigned long flags;
  66
  67        spin_lock_irqsave(&ieee->lock, flags);
  68        ieee80211_crypt_deinit_entries(ieee, 0);
  69        if (!list_empty(&ieee->crypt_deinit_list)) {
  70                printk(KERN_DEBUG "%s: entries remaining in delayed crypt "
  71                       "deletion list\n", ieee->dev->name);
  72                ieee->crypt_deinit_timer.expires = jiffies + HZ;
  73                add_timer(&ieee->crypt_deinit_timer);
  74        }
  75        spin_unlock_irqrestore(&ieee->lock, flags);
  76
  77}
  78
  79void ieee80211_crypt_delayed_deinit(struct ieee80211_device *ieee,
  80                                    struct ieee80211_crypt_data **crypt)
  81{
  82        struct ieee80211_crypt_data *tmp;
  83        unsigned long flags;
  84
  85        if (*crypt == NULL)
  86                return;
  87
  88        tmp = *crypt;
  89        *crypt = NULL;
  90
  91        /* must not run ops->deinit() while there may be pending encrypt or
  92         * decrypt operations. Use a list of delayed deinits to avoid needing
  93         * locking. */
  94
  95        spin_lock_irqsave(&ieee->lock, flags);
  96        list_add(&tmp->list, &ieee->crypt_deinit_list);
  97        if (!timer_pending(&ieee->crypt_deinit_timer)) {
  98                ieee->crypt_deinit_timer.expires = jiffies + HZ;
  99                add_timer(&ieee->crypt_deinit_timer);
 100        }
 101        spin_unlock_irqrestore(&ieee->lock, flags);
 102}
 103
 104int ieee80211_register_crypto_ops(struct ieee80211_crypto_ops *ops)
 105{
 106        unsigned long flags;
 107        struct ieee80211_crypto_alg *alg;
 108
 109        if (hcrypt == NULL)
 110                return -1;
 111
 112        alg = kmalloc(sizeof(*alg), GFP_KERNEL);
 113        if (alg == NULL)
 114                return -ENOMEM;
 115
 116        memset(alg, 0, sizeof(*alg));
 117        alg->ops = ops;
 118
 119        spin_lock_irqsave(&hcrypt->lock, flags);
 120        list_add(&alg->list, &hcrypt->algs);
 121        spin_unlock_irqrestore(&hcrypt->lock, flags);
 122
 123        printk(KERN_DEBUG "ieee80211_crypt: registered algorithm '%s'\n",
 124               ops->name);
 125
 126        return 0;
 127}
 128
 129int ieee80211_unregister_crypto_ops(struct ieee80211_crypto_ops *ops)
 130{
 131        unsigned long flags;
 132        struct list_head *ptr;
 133        struct ieee80211_crypto_alg *del_alg = NULL;
 134
 135        if (hcrypt == NULL)
 136                return -1;
 137
 138        spin_lock_irqsave(&hcrypt->lock, flags);
 139        for (ptr = hcrypt->algs.next; ptr != &hcrypt->algs; ptr = ptr->next) {
 140                struct ieee80211_crypto_alg *alg =
 141                        (struct ieee80211_crypto_alg *) ptr;
 142                if (alg->ops == ops) {
 143                        list_del(&alg->list);
 144                        del_alg = alg;
 145                        break;
 146                }
 147        }
 148        spin_unlock_irqrestore(&hcrypt->lock, flags);
 149
 150        if (del_alg) {
 151                printk(KERN_DEBUG "ieee80211_crypt: unregistered algorithm "
 152                       "'%s'\n", ops->name);
 153                kfree(del_alg);
 154        }
 155
 156        return del_alg ? 0 : -1;
 157}
 158
 159
 160struct ieee80211_crypto_ops * ieee80211_get_crypto_ops(const char *name)
 161{
 162        unsigned long flags;
 163        struct list_head *ptr;
 164        struct ieee80211_crypto_alg *found_alg = NULL;
 165
 166        if (hcrypt == NULL)
 167                return NULL;
 168
 169        spin_lock_irqsave(&hcrypt->lock, flags);
 170        for (ptr = hcrypt->algs.next; ptr != &hcrypt->algs; ptr = ptr->next) {
 171                struct ieee80211_crypto_alg *alg =
 172                        (struct ieee80211_crypto_alg *) ptr;
 173                if (strcmp(alg->ops->name, name) == 0) {
 174                        found_alg = alg;
 175                        break;
 176                }
 177        }
 178        spin_unlock_irqrestore(&hcrypt->lock, flags);
 179
 180        if (found_alg)
 181                return found_alg->ops;
 182        else
 183                return NULL;
 184}
 185
 186
 187static void * ieee80211_crypt_null_init(int keyidx) { return (void *) 1; }
 188static void ieee80211_crypt_null_deinit(void *priv) {}
 189
 190static struct ieee80211_crypto_ops ieee80211_crypt_null = {
 191        .name                   = "NULL",
 192        .init                   = ieee80211_crypt_null_init,
 193        .deinit                 = ieee80211_crypt_null_deinit,
 194        .encrypt_mpdu           = NULL,
 195        .decrypt_mpdu           = NULL,
 196        .encrypt_msdu           = NULL,
 197        .decrypt_msdu           = NULL,
 198        .set_key                = NULL,
 199        .get_key                = NULL,
 200        .extra_prefix_len       = 0,
 201        .extra_postfix_len      = 0,
 202        .owner                  = THIS_MODULE,
 203};
 204
 205int __init ieee80211_crypto_init(void)
 206{
 207        int ret = -ENOMEM;
 208
 209        hcrypt = kmalloc(sizeof(*hcrypt), GFP_KERNEL);
 210        if (!hcrypt)
 211                goto out;
 212
 213        memset(hcrypt, 0, sizeof(*hcrypt));
 214        INIT_LIST_HEAD(&hcrypt->algs);
 215        spin_lock_init(&hcrypt->lock);
 216
 217        ret = ieee80211_register_crypto_ops(&ieee80211_crypt_null);
 218        if (ret < 0) {
 219                kfree(hcrypt);
 220                hcrypt = NULL;
 221        }
 222out:
 223        return ret;
 224}
 225
 226void __exit ieee80211_crypto_deinit(void)
 227{
 228        struct list_head *ptr, *n;
 229
 230        if (hcrypt == NULL)
 231                return;
 232
 233        for (ptr = hcrypt->algs.next, n = ptr->next; ptr != &hcrypt->algs;
 234             ptr = n, n = ptr->next) {
 235                struct ieee80211_crypto_alg *alg =
 236                        (struct ieee80211_crypto_alg *) ptr;
 237                list_del(ptr);
 238                printk(KERN_DEBUG "ieee80211_crypt: unregistered algorithm "
 239                       "'%s' (deinit)\n", alg->ops->name);
 240                kfree(alg);
 241        }
 242
 243        kfree(hcrypt);
 244}
 245