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