1130803Smarcel// SPDX-License-Identifier: GPL-2.0-only
298944Sobrien/*
3130803Smarcel * lib80211 -- common bits for IEEE802.11 drivers
4130803Smarcel *
598944Sobrien * Copyright(c) 2008 John W. Linville <linville@tuxdriver.com>
698944Sobrien *
798944Sobrien * Portions copied from old ieee80211 component, w/ original copyright
898944Sobrien * notices below:
998944Sobrien *
1098944Sobrien * Host AP crypto routines
1198944Sobrien *
1298944Sobrien * Copyright (c) 2002-2003, Jouni Malinen <j@w1.fi>
1398944Sobrien * Portions Copyright (C) 2004, Intel Corporation <jketreno@linux.intel.com>
1498944Sobrien *
1598944Sobrien */
1698944Sobrien
1798944Sobrien#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
1898944Sobrien
1998944Sobrien#include <linux/module.h>
2098944Sobrien#include <linux/ctype.h>
2198944Sobrien#include <linux/ieee80211.h>
2298944Sobrien#include <linux/errno.h>
2398944Sobrien#include <linux/init.h>
24130803Smarcel#include <linux/slab.h>
2598944Sobrien#include <linux/string.h>
2698944Sobrien
27130803Smarcel#include <net/lib80211.h>
2898944Sobrien
29130803Smarcel#define DRV_DESCRIPTION	"common routines for IEEE802.11 drivers"
3098944Sobrien
31130803SmarcelMODULE_DESCRIPTION(DRV_DESCRIPTION);
32130803SmarcelMODULE_AUTHOR("John W. Linville <linville@tuxdriver.com>");
3398944SobrienMODULE_LICENSE("GPL");
3498944Sobrien
3598944Sobrienstruct lib80211_crypto_alg {
36130803Smarcel	struct list_head list;
37130803Smarcel	struct lib80211_crypto_ops *ops;
3898944Sobrien};
39130803Smarcel
40130803Smarcelstatic LIST_HEAD(lib80211_crypto_algs);
41130803Smarcelstatic DEFINE_SPINLOCK(lib80211_crypto_lock);
4298944Sobrien
43130803Smarcelstatic void lib80211_crypt_deinit_entries(struct lib80211_crypt_info *info,
44130803Smarcel					  int force);
45130803Smarcelstatic void lib80211_crypt_quiescing(struct lib80211_crypt_info *info);
46130803Smarcelstatic void lib80211_crypt_deinit_handler(struct timer_list *t);
47130803Smarcel
48130803Smarcelint lib80211_crypt_info_init(struct lib80211_crypt_info *info, char *name,
49130803Smarcel				spinlock_t *lock)
50130803Smarcel{
51130803Smarcel	memset(info, 0, sizeof(*info));
52130803Smarcel
53130803Smarcel	info->name = name;
5498944Sobrien	info->lock = lock;
55130803Smarcel
56130803Smarcel	INIT_LIST_HEAD(&info->crypt_deinit_list);
57130803Smarcel	timer_setup(&info->crypt_deinit_timer, lib80211_crypt_deinit_handler,
58130803Smarcel		    0);
59130803Smarcel
60130803Smarcel	return 0;
61130803Smarcel}
62130803SmarcelEXPORT_SYMBOL(lib80211_crypt_info_init);
63130803Smarcel
64130803Smarcelvoid lib80211_crypt_info_free(struct lib80211_crypt_info *info)
65130803Smarcel{
66130803Smarcel	int i;
67130803Smarcel
68130803Smarcel        lib80211_crypt_quiescing(info);
69130803Smarcel        del_timer_sync(&info->crypt_deinit_timer);
70130803Smarcel        lib80211_crypt_deinit_entries(info, 1);
71130803Smarcel
72130803Smarcel        for (i = 0; i < NUM_WEP_KEYS; i++) {
73130803Smarcel                struct lib80211_crypt_data *crypt = info->crypt[i];
74130803Smarcel                if (crypt) {
75130803Smarcel                        if (crypt->ops) {
76130803Smarcel                                crypt->ops->deinit(crypt->priv);
77130803Smarcel                                module_put(crypt->ops->owner);
78130803Smarcel                        }
79130803Smarcel                        kfree(crypt);
80130803Smarcel                        info->crypt[i] = NULL;
81130803Smarcel                }
82130803Smarcel        }
83130803Smarcel}
84130803SmarcelEXPORT_SYMBOL(lib80211_crypt_info_free);
85130803Smarcel
86130803Smarcelstatic void lib80211_crypt_deinit_entries(struct lib80211_crypt_info *info,
87130803Smarcel					  int force)
88130803Smarcel{
89130803Smarcel	struct lib80211_crypt_data *entry, *next;
90130803Smarcel	unsigned long flags;
91130803Smarcel
92130803Smarcel	spin_lock_irqsave(info->lock, flags);
93130803Smarcel	list_for_each_entry_safe(entry, next, &info->crypt_deinit_list, list) {
94130803Smarcel		if (atomic_read(&entry->refcnt) != 0 && !force)
95130803Smarcel			continue;
96130803Smarcel
97130803Smarcel		list_del(&entry->list);
98130803Smarcel
9998944Sobrien		if (entry->ops) {
100130803Smarcel			entry->ops->deinit(entry->priv);
101130803Smarcel			module_put(entry->ops->owner);
102130803Smarcel		}
103130803Smarcel		kfree(entry);
104130803Smarcel	}
105130803Smarcel	spin_unlock_irqrestore(info->lock, flags);
10698944Sobrien}
107130803Smarcel
108130803Smarcel/* After this, crypt_deinit_list won't accept new members */
109130803Smarcelstatic void lib80211_crypt_quiescing(struct lib80211_crypt_info *info)
110130803Smarcel{
111130803Smarcel	unsigned long flags;
112130803Smarcel
11398944Sobrien	spin_lock_irqsave(info->lock, flags);
114130803Smarcel	info->crypt_quiesced = 1;
115130803Smarcel	spin_unlock_irqrestore(info->lock, flags);
11698944Sobrien}
117130803Smarcel
11898944Sobrienstatic void lib80211_crypt_deinit_handler(struct timer_list *t)
119130803Smarcel{
120130803Smarcel	struct lib80211_crypt_info *info = from_timer(info, t,
121130803Smarcel						      crypt_deinit_timer);
122130803Smarcel	unsigned long flags;
123130803Smarcel
124130803Smarcel	lib80211_crypt_deinit_entries(info, 0);
12598944Sobrien
126130803Smarcel	spin_lock_irqsave(info->lock, flags);
127130803Smarcel	if (!list_empty(&info->crypt_deinit_list) && !info->crypt_quiesced) {
128130803Smarcel		printk(KERN_DEBUG "%s: entries remaining in delayed crypt "
12998944Sobrien		       "deletion list\n", info->name);
130130803Smarcel		info->crypt_deinit_timer.expires = jiffies + HZ;
131130803Smarcel		add_timer(&info->crypt_deinit_timer);
132130803Smarcel	}
133130803Smarcel	spin_unlock_irqrestore(info->lock, flags);
134130803Smarcel}
135130803Smarcel
136130803Smarcelvoid lib80211_crypt_delayed_deinit(struct lib80211_crypt_info *info,
137130803Smarcel				    struct lib80211_crypt_data **crypt)
138130803Smarcel{
139130803Smarcel	struct lib80211_crypt_data *tmp;
140130803Smarcel	unsigned long flags;
141130803Smarcel
142130803Smarcel	if (*crypt == NULL)
143130803Smarcel		return;
144130803Smarcel
145130803Smarcel	tmp = *crypt;
146130803Smarcel	*crypt = NULL;
147130803Smarcel
148130803Smarcel	/* must not run ops->deinit() while there may be pending encrypt or
149130803Smarcel	 * decrypt operations. Use a list of delayed deinits to avoid needing
150130803Smarcel	 * locking. */
151130803Smarcel
152130803Smarcel	spin_lock_irqsave(info->lock, flags);
153130803Smarcel	if (!info->crypt_quiesced) {
154130803Smarcel		list_add(&tmp->list, &info->crypt_deinit_list);
155130803Smarcel		if (!timer_pending(&info->crypt_deinit_timer)) {
156130803Smarcel			info->crypt_deinit_timer.expires = jiffies + HZ;
157130803Smarcel			add_timer(&info->crypt_deinit_timer);
158130803Smarcel		}
159130803Smarcel	}
16098944Sobrien	spin_unlock_irqrestore(info->lock, flags);
161130803Smarcel}
162130803SmarcelEXPORT_SYMBOL(lib80211_crypt_delayed_deinit);
16398944Sobrien
16498944Sobrienint lib80211_register_crypto_ops(struct lib80211_crypto_ops *ops)
165130803Smarcel{
16698944Sobrien	unsigned long flags;
167130803Smarcel	struct lib80211_crypto_alg *alg;
168130803Smarcel
169130803Smarcel	alg = kzalloc(sizeof(*alg), GFP_KERNEL);
170130803Smarcel	if (alg == NULL)
171130803Smarcel		return -ENOMEM;
172130803Smarcel
173130803Smarcel	alg->ops = ops;
174130803Smarcel
17598944Sobrien	spin_lock_irqsave(&lib80211_crypto_lock, flags);
176130803Smarcel	list_add(&alg->list, &lib80211_crypto_algs);
177130803Smarcel	spin_unlock_irqrestore(&lib80211_crypto_lock, flags);
17898944Sobrien
179130803Smarcel	printk(KERN_DEBUG "lib80211_crypt: registered algorithm '%s'\n",
180130803Smarcel	       ops->name);
181130803Smarcel
182130803Smarcel	return 0;
183130803Smarcel}
184130803SmarcelEXPORT_SYMBOL(lib80211_register_crypto_ops);
18598944Sobrien
18698944Sobrienint lib80211_unregister_crypto_ops(struct lib80211_crypto_ops *ops)
18798944Sobrien{
18898944Sobrien	struct lib80211_crypto_alg *alg;
189130803Smarcel	unsigned long flags;
19098944Sobrien
191130803Smarcel	spin_lock_irqsave(&lib80211_crypto_lock, flags);
192130803Smarcel	list_for_each_entry(alg, &lib80211_crypto_algs, list) {
19398944Sobrien		if (alg->ops == ops)
194130803Smarcel			goto found;
195130803Smarcel	}
196130803Smarcel	spin_unlock_irqrestore(&lib80211_crypto_lock, flags);
197130803Smarcel	return -EINVAL;
198130803Smarcel
19998944Sobrien      found:
200130803Smarcel	printk(KERN_DEBUG "lib80211_crypt: unregistered algorithm '%s'\n",
20198944Sobrien	       ops->name);
202130803Smarcel	list_del(&alg->list);
20398944Sobrien	spin_unlock_irqrestore(&lib80211_crypto_lock, flags);
204130803Smarcel	kfree(alg);
205130803Smarcel	return 0;
20698944Sobrien}
207130803SmarcelEXPORT_SYMBOL(lib80211_unregister_crypto_ops);
208130803Smarcel
209130803Smarcelstruct lib80211_crypto_ops *lib80211_get_crypto_ops(const char *name)
210130803Smarcel{
211130803Smarcel	struct lib80211_crypto_alg *alg;
212130803Smarcel	unsigned long flags;
213130803Smarcel
214130803Smarcel	spin_lock_irqsave(&lib80211_crypto_lock, flags);
21598944Sobrien	list_for_each_entry(alg, &lib80211_crypto_algs, list) {
216130803Smarcel		if (strcmp(alg->ops->name, name) == 0)
217130803Smarcel			goto found;
218130803Smarcel	}
219130803Smarcel	spin_unlock_irqrestore(&lib80211_crypto_lock, flags);
22098944Sobrien	return NULL;
22198944Sobrien
222130803Smarcel      found:
223130803Smarcel	spin_unlock_irqrestore(&lib80211_crypto_lock, flags);
22498944Sobrien	return alg->ops;
22598944Sobrien}
226130803SmarcelEXPORT_SYMBOL(lib80211_get_crypto_ops);
22798944Sobrien
228130803Smarcelstatic void *lib80211_crypt_null_init(int keyidx)
22998944Sobrien{
230130803Smarcel	return (void *)1;
231130803Smarcel}
23298944Sobrien
233130803Smarcelstatic void lib80211_crypt_null_deinit(void *priv)
234130803Smarcel{
23598944Sobrien}
236130803Smarcel
237130803Smarcelstatic struct lib80211_crypto_ops lib80211_crypt_null = {
238130803Smarcel	.name = "NULL",
239130803Smarcel	.init = lib80211_crypt_null_init,
240130803Smarcel	.deinit = lib80211_crypt_null_deinit,
241130803Smarcel	.owner = THIS_MODULE,
242130803Smarcel};
243130803Smarcel
244130803Smarcelstatic int __init lib80211_init(void)
245130803Smarcel{
24698944Sobrien	pr_info(DRV_DESCRIPTION "\n");
247130803Smarcel	return lib80211_register_crypto_ops(&lib80211_crypt_null);
248130803Smarcel}
24998944Sobrien
25098944Sobrienstatic void __exit lib80211_exit(void)
25198944Sobrien{
252130803Smarcel	lib80211_unregister_crypto_ops(&lib80211_crypt_null);
253130803Smarcel	BUG_ON(!list_empty(&lib80211_crypto_algs));
25498944Sobrien}
255130803Smarcel
256130803Smarcelmodule_init(lib80211_init);
257130803Smarcelmodule_exit(lib80211_exit);
258130803Smarcel