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 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