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