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