linux/drivers/staging/rtl8187se/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#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  15
  16//#include <linux/config.h>
  17#include <linux/module.h>
  18#include <linux/slab.h>
  19#include <linux/string.h>
  20#include <linux/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, 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                pr_debug("entries remaining in delayed crypt deletion list\n");
  70                ieee->crypt_deinit_timer.expires = jiffies + HZ;
  71                add_timer(&ieee->crypt_deinit_timer);
  72        }
  73        spin_unlock_irqrestore(&ieee->lock, flags);
  74
  75}
  76
  77void ieee80211_crypt_delayed_deinit(struct ieee80211_device *ieee,
  78                                    struct ieee80211_crypt_data **crypt)
  79{
  80        struct ieee80211_crypt_data *tmp;
  81        unsigned long flags;
  82
  83        if (*crypt == NULL)
  84                return;
  85
  86        tmp = *crypt;
  87        *crypt = NULL;
  88
  89        /* must not run ops->deinit() while there may be pending encrypt or
  90         * decrypt operations. Use a list of delayed deinits to avoid needing
  91         * locking. */
  92
  93        spin_lock_irqsave(&ieee->lock, flags);
  94        list_add(&tmp->list, &ieee->crypt_deinit_list);
  95        if (!timer_pending(&ieee->crypt_deinit_timer)) {
  96                ieee->crypt_deinit_timer.expires = jiffies + HZ;
  97                add_timer(&ieee->crypt_deinit_timer);
  98        }
  99        spin_unlock_irqrestore(&ieee->lock, flags);
 100}
 101
 102int ieee80211_register_crypto_ops(struct ieee80211_crypto_ops *ops)
 103{
 104        unsigned long flags;
 105        struct ieee80211_crypto_alg *alg;
 106
 107        if (hcrypt == NULL)
 108                return -1;
 109
 110        alg = kzalloc(sizeof(*alg), GFP_KERNEL);
 111        if (alg == NULL)
 112                return -ENOMEM;
 113
 114        alg->ops = ops;
 115
 116        spin_lock_irqsave(&hcrypt->lock, flags);
 117        list_add(&alg->list, &hcrypt->algs);
 118        spin_unlock_irqrestore(&hcrypt->lock, flags);
 119
 120        pr_debug("registered algorithm '%s'\n", ops->name);
 121
 122        return 0;
 123}
 124
 125int ieee80211_unregister_crypto_ops(struct ieee80211_crypto_ops *ops)
 126{
 127        unsigned long flags;
 128        struct list_head *ptr;
 129        struct ieee80211_crypto_alg *del_alg = NULL;
 130
 131        if (hcrypt == NULL)
 132                return -1;
 133
 134        spin_lock_irqsave(&hcrypt->lock, flags);
 135        for (ptr = hcrypt->algs.next; ptr != &hcrypt->algs; ptr = ptr->next) {
 136                struct ieee80211_crypto_alg *alg =
 137                        (struct ieee80211_crypto_alg *) ptr;
 138                if (alg->ops == ops) {
 139                        list_del(&alg->list);
 140                        del_alg = alg;
 141                        break;
 142                }
 143        }
 144        spin_unlock_irqrestore(&hcrypt->lock, flags);
 145
 146        if (del_alg) {
 147                pr_debug("unregistered algorithm '%s'\n", ops->name);
 148                kfree(del_alg);
 149        }
 150
 151        return del_alg ? 0 : -1;
 152}
 153
 154
 155struct ieee80211_crypto_ops *ieee80211_get_crypto_ops(const char *name)
 156{
 157        unsigned long flags;
 158        struct list_head *ptr;
 159        struct ieee80211_crypto_alg *found_alg = NULL;
 160
 161        if (hcrypt == NULL)
 162                return NULL;
 163
 164        spin_lock_irqsave(&hcrypt->lock, flags);
 165        for (ptr = hcrypt->algs.next; ptr != &hcrypt->algs; ptr = ptr->next) {
 166                struct ieee80211_crypto_alg *alg =
 167                        (struct ieee80211_crypto_alg *) ptr;
 168                if (strcmp(alg->ops->name, name) == 0) {
 169                        found_alg = alg;
 170                        break;
 171                }
 172        }
 173        spin_unlock_irqrestore(&hcrypt->lock, flags);
 174
 175        if (found_alg)
 176                return found_alg->ops;
 177        else
 178                return NULL;
 179}
 180
 181
 182static void *ieee80211_crypt_null_init(int keyidx) { return (void *) 1; }
 183static void ieee80211_crypt_null_deinit(void *priv) {}
 184
 185static struct ieee80211_crypto_ops ieee80211_crypt_null = {
 186        .name                   = "NULL",
 187        .init                   = ieee80211_crypt_null_init,
 188        .deinit                 = ieee80211_crypt_null_deinit,
 189        .encrypt_mpdu           = NULL,
 190        .decrypt_mpdu           = NULL,
 191        .encrypt_msdu           = NULL,
 192        .decrypt_msdu           = NULL,
 193        .set_key                = NULL,
 194        .get_key                = NULL,
 195        .extra_prefix_len       = 0,
 196        .extra_postfix_len      = 0,
 197        .owner                  = THIS_MODULE,
 198};
 199
 200
 201int ieee80211_crypto_init(void)
 202{
 203        int ret = -ENOMEM;
 204
 205        hcrypt = kzalloc(sizeof(*hcrypt), GFP_KERNEL);
 206        if (!hcrypt)
 207                goto out;
 208
 209        INIT_LIST_HEAD(&hcrypt->algs);
 210        spin_lock_init(&hcrypt->lock);
 211
 212        ret = ieee80211_register_crypto_ops(&ieee80211_crypt_null);
 213        if (ret < 0) {
 214                kfree(hcrypt);
 215                hcrypt = NULL;
 216        }
 217out:
 218        return ret;
 219}
 220
 221
 222void ieee80211_crypto_deinit(void)
 223{
 224        struct list_head *ptr, *n;
 225        struct ieee80211_crypto_alg *alg = NULL;
 226
 227        if (hcrypt == NULL)
 228                return;
 229
 230        list_for_each_safe(ptr, n, &hcrypt->algs) {
 231                alg = list_entry(ptr, struct ieee80211_crypto_alg, list);
 232                if (alg) {
 233                        list_del(ptr);
 234                        pr_debug("unregistered algorithm '%s' (deinit)\n",
 235                                 alg->ops->name);
 236                        kfree(alg);
 237                }
 238        }
 239        kfree(hcrypt);
 240}
 241