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