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
ieee80211_crypt_deinit_entries(struct ieee80211_device * ieee,int force)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
ieee80211_crypt_deinit_handler(struct timer_list * t)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
ieee80211_crypt_delayed_deinit(struct ieee80211_device * ieee,struct ieee80211_crypt_data ** crypt)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
ieee80211_register_crypto_ops(struct ieee80211_crypto_ops * ops)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
ieee80211_unregister_crypto_ops(struct ieee80211_crypto_ops * ops)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
ieee80211_get_crypto_ops(const char * name)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
ieee80211_crypt_null_init(int keyidx)179 static void *ieee80211_crypt_null_init(int keyidx) { return (void *)1; }
ieee80211_crypt_null_deinit(void * priv)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
ieee80211_crypto_init(void)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
ieee80211_crypto_deinit(void)217 void 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