cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

lib80211.c (6717B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * lib80211 -- common bits for IEEE802.11 drivers
      4 *
      5 * Copyright(c) 2008 John W. Linville <linville@tuxdriver.com>
      6 *
      7 * Portions copied from old ieee80211 component, w/ original copyright
      8 * notices below:
      9 *
     10 * Host AP crypto routines
     11 *
     12 * Copyright (c) 2002-2003, Jouni Malinen <j@w1.fi>
     13 * Portions Copyright (C) 2004, Intel Corporation <jketreno@linux.intel.com>
     14 *
     15 */
     16
     17#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
     18
     19#include <linux/module.h>
     20#include <linux/ctype.h>
     21#include <linux/ieee80211.h>
     22#include <linux/errno.h>
     23#include <linux/init.h>
     24#include <linux/slab.h>
     25#include <linux/string.h>
     26
     27#include <net/lib80211.h>
     28
     29#define DRV_DESCRIPTION	"common routines for IEEE802.11 drivers"
     30
     31MODULE_DESCRIPTION(DRV_DESCRIPTION);
     32MODULE_AUTHOR("John W. Linville <linville@tuxdriver.com>");
     33MODULE_LICENSE("GPL");
     34
     35struct lib80211_crypto_alg {
     36	struct list_head list;
     37	struct lib80211_crypto_ops *ops;
     38};
     39
     40static LIST_HEAD(lib80211_crypto_algs);
     41static DEFINE_SPINLOCK(lib80211_crypto_lock);
     42
     43static void lib80211_crypt_deinit_entries(struct lib80211_crypt_info *info,
     44					  int force);
     45static void lib80211_crypt_quiescing(struct lib80211_crypt_info *info);
     46static void lib80211_crypt_deinit_handler(struct timer_list *t);
     47
     48int lib80211_crypt_info_init(struct lib80211_crypt_info *info, char *name,
     49				spinlock_t *lock)
     50{
     51	memset(info, 0, sizeof(*info));
     52
     53	info->name = name;
     54	info->lock = lock;
     55
     56	INIT_LIST_HEAD(&info->crypt_deinit_list);
     57	timer_setup(&info->crypt_deinit_timer, lib80211_crypt_deinit_handler,
     58		    0);
     59
     60	return 0;
     61}
     62EXPORT_SYMBOL(lib80211_crypt_info_init);
     63
     64void lib80211_crypt_info_free(struct lib80211_crypt_info *info)
     65{
     66	int i;
     67
     68        lib80211_crypt_quiescing(info);
     69        del_timer_sync(&info->crypt_deinit_timer);
     70        lib80211_crypt_deinit_entries(info, 1);
     71
     72        for (i = 0; i < NUM_WEP_KEYS; i++) {
     73                struct lib80211_crypt_data *crypt = info->crypt[i];
     74                if (crypt) {
     75                        if (crypt->ops) {
     76                                crypt->ops->deinit(crypt->priv);
     77                                module_put(crypt->ops->owner);
     78                        }
     79                        kfree(crypt);
     80                        info->crypt[i] = NULL;
     81                }
     82        }
     83}
     84EXPORT_SYMBOL(lib80211_crypt_info_free);
     85
     86static void lib80211_crypt_deinit_entries(struct lib80211_crypt_info *info,
     87					  int force)
     88{
     89	struct lib80211_crypt_data *entry, *next;
     90	unsigned long flags;
     91
     92	spin_lock_irqsave(info->lock, flags);
     93	list_for_each_entry_safe(entry, next, &info->crypt_deinit_list, list) {
     94		if (atomic_read(&entry->refcnt) != 0 && !force)
     95			continue;
     96
     97		list_del(&entry->list);
     98
     99		if (entry->ops) {
    100			entry->ops->deinit(entry->priv);
    101			module_put(entry->ops->owner);
    102		}
    103		kfree(entry);
    104	}
    105	spin_unlock_irqrestore(info->lock, flags);
    106}
    107
    108/* After this, crypt_deinit_list won't accept new members */
    109static void lib80211_crypt_quiescing(struct lib80211_crypt_info *info)
    110{
    111	unsigned long flags;
    112
    113	spin_lock_irqsave(info->lock, flags);
    114	info->crypt_quiesced = 1;
    115	spin_unlock_irqrestore(info->lock, flags);
    116}
    117
    118static void lib80211_crypt_deinit_handler(struct timer_list *t)
    119{
    120	struct lib80211_crypt_info *info = from_timer(info, t,
    121						      crypt_deinit_timer);
    122	unsigned long flags;
    123
    124	lib80211_crypt_deinit_entries(info, 0);
    125
    126	spin_lock_irqsave(info->lock, flags);
    127	if (!list_empty(&info->crypt_deinit_list) && !info->crypt_quiesced) {
    128		printk(KERN_DEBUG "%s: entries remaining in delayed crypt "
    129		       "deletion list\n", info->name);
    130		info->crypt_deinit_timer.expires = jiffies + HZ;
    131		add_timer(&info->crypt_deinit_timer);
    132	}
    133	spin_unlock_irqrestore(info->lock, flags);
    134}
    135
    136void lib80211_crypt_delayed_deinit(struct lib80211_crypt_info *info,
    137				    struct lib80211_crypt_data **crypt)
    138{
    139	struct lib80211_crypt_data *tmp;
    140	unsigned long flags;
    141
    142	if (*crypt == NULL)
    143		return;
    144
    145	tmp = *crypt;
    146	*crypt = NULL;
    147
    148	/* must not run ops->deinit() while there may be pending encrypt or
    149	 * decrypt operations. Use a list of delayed deinits to avoid needing
    150	 * locking. */
    151
    152	spin_lock_irqsave(info->lock, flags);
    153	if (!info->crypt_quiesced) {
    154		list_add(&tmp->list, &info->crypt_deinit_list);
    155		if (!timer_pending(&info->crypt_deinit_timer)) {
    156			info->crypt_deinit_timer.expires = jiffies + HZ;
    157			add_timer(&info->crypt_deinit_timer);
    158		}
    159	}
    160	spin_unlock_irqrestore(info->lock, flags);
    161}
    162EXPORT_SYMBOL(lib80211_crypt_delayed_deinit);
    163
    164int lib80211_register_crypto_ops(struct lib80211_crypto_ops *ops)
    165{
    166	unsigned long flags;
    167	struct lib80211_crypto_alg *alg;
    168
    169	alg = kzalloc(sizeof(*alg), GFP_KERNEL);
    170	if (alg == NULL)
    171		return -ENOMEM;
    172
    173	alg->ops = ops;
    174
    175	spin_lock_irqsave(&lib80211_crypto_lock, flags);
    176	list_add(&alg->list, &lib80211_crypto_algs);
    177	spin_unlock_irqrestore(&lib80211_crypto_lock, flags);
    178
    179	printk(KERN_DEBUG "lib80211_crypt: registered algorithm '%s'\n",
    180	       ops->name);
    181
    182	return 0;
    183}
    184EXPORT_SYMBOL(lib80211_register_crypto_ops);
    185
    186int lib80211_unregister_crypto_ops(struct lib80211_crypto_ops *ops)
    187{
    188	struct lib80211_crypto_alg *alg;
    189	unsigned long flags;
    190
    191	spin_lock_irqsave(&lib80211_crypto_lock, flags);
    192	list_for_each_entry(alg, &lib80211_crypto_algs, list) {
    193		if (alg->ops == ops)
    194			goto found;
    195	}
    196	spin_unlock_irqrestore(&lib80211_crypto_lock, flags);
    197	return -EINVAL;
    198
    199      found:
    200	printk(KERN_DEBUG "lib80211_crypt: unregistered algorithm '%s'\n",
    201	       ops->name);
    202	list_del(&alg->list);
    203	spin_unlock_irqrestore(&lib80211_crypto_lock, flags);
    204	kfree(alg);
    205	return 0;
    206}
    207EXPORT_SYMBOL(lib80211_unregister_crypto_ops);
    208
    209struct lib80211_crypto_ops *lib80211_get_crypto_ops(const char *name)
    210{
    211	struct lib80211_crypto_alg *alg;
    212	unsigned long flags;
    213
    214	spin_lock_irqsave(&lib80211_crypto_lock, flags);
    215	list_for_each_entry(alg, &lib80211_crypto_algs, list) {
    216		if (strcmp(alg->ops->name, name) == 0)
    217			goto found;
    218	}
    219	spin_unlock_irqrestore(&lib80211_crypto_lock, flags);
    220	return NULL;
    221
    222      found:
    223	spin_unlock_irqrestore(&lib80211_crypto_lock, flags);
    224	return alg->ops;
    225}
    226EXPORT_SYMBOL(lib80211_get_crypto_ops);
    227
    228static void *lib80211_crypt_null_init(int keyidx)
    229{
    230	return (void *)1;
    231}
    232
    233static void lib80211_crypt_null_deinit(void *priv)
    234{
    235}
    236
    237static struct lib80211_crypto_ops lib80211_crypt_null = {
    238	.name = "NULL",
    239	.init = lib80211_crypt_null_init,
    240	.deinit = lib80211_crypt_null_deinit,
    241	.owner = THIS_MODULE,
    242};
    243
    244static int __init lib80211_init(void)
    245{
    246	pr_info(DRV_DESCRIPTION "\n");
    247	return lib80211_register_crypto_ops(&lib80211_crypt_null);
    248}
    249
    250static void __exit lib80211_exit(void)
    251{
    252	lib80211_unregister_crypto_ops(&lib80211_crypt_null);
    253	BUG_ON(!list_empty(&lib80211_crypto_algs));
    254}
    255
    256module_init(lib80211_init);
    257module_exit(lib80211_exit);