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