Linux-libre 5.4.48-gnu
[librecmc/linux-libre.git] / drivers / staging / rtl8192u / ieee80211 / ieee80211_crypt.c
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
17 MODULE_AUTHOR("Jouni Malinen");
18 MODULE_DESCRIPTION("HostAP crypto");
19 MODULE_LICENSE("GPL");
20
21 struct ieee80211_crypto_alg {
22         struct list_head list;
23         struct ieee80211_crypto_ops *ops;
24 };
25
26
27 struct ieee80211_crypto {
28         struct list_head algs;
29         spinlock_t lock;
30 };
31
32 static struct ieee80211_crypto *hcrypt;
33
34 void 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
55 void 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
72 void 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
98 int 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
122 int 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
153 struct 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
179 static void *ieee80211_crypt_null_init(int keyidx) { return (void *)1; }
180 static void ieee80211_crypt_null_deinit(void *priv) {}
181
182 static 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
197 int __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         }
213 out:
214         return ret;
215 }
216
217 void __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 }