1130803Smarcel// SPDX-License-Identifier: GPL-2.0-only 298944Sobrien/* 3130803Smarcel * lib80211 -- common bits for IEEE802.11 drivers 4130803Smarcel * 598944Sobrien * Copyright(c) 2008 John W. Linville <linville@tuxdriver.com> 698944Sobrien * 798944Sobrien * Portions copied from old ieee80211 component, w/ original copyright 898944Sobrien * notices below: 998944Sobrien * 1098944Sobrien * Host AP crypto routines 1198944Sobrien * 1298944Sobrien * Copyright (c) 2002-2003, Jouni Malinen <j@w1.fi> 1398944Sobrien * Portions Copyright (C) 2004, Intel Corporation <jketreno@linux.intel.com> 1498944Sobrien * 1598944Sobrien */ 1698944Sobrien 1798944Sobrien#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 1898944Sobrien 1998944Sobrien#include <linux/module.h> 2098944Sobrien#include <linux/ctype.h> 2198944Sobrien#include <linux/ieee80211.h> 2298944Sobrien#include <linux/errno.h> 2398944Sobrien#include <linux/init.h> 24130803Smarcel#include <linux/slab.h> 2598944Sobrien#include <linux/string.h> 2698944Sobrien 27130803Smarcel#include <net/lib80211.h> 2898944Sobrien 29130803Smarcel#define DRV_DESCRIPTION "common routines for IEEE802.11 drivers" 3098944Sobrien 31130803SmarcelMODULE_DESCRIPTION(DRV_DESCRIPTION); 32130803SmarcelMODULE_AUTHOR("John W. Linville <linville@tuxdriver.com>"); 3398944SobrienMODULE_LICENSE("GPL"); 3498944Sobrien 3598944Sobrienstruct lib80211_crypto_alg { 36130803Smarcel struct list_head list; 37130803Smarcel struct lib80211_crypto_ops *ops; 3898944Sobrien}; 39130803Smarcel 40130803Smarcelstatic LIST_HEAD(lib80211_crypto_algs); 41130803Smarcelstatic DEFINE_SPINLOCK(lib80211_crypto_lock); 4298944Sobrien 43130803Smarcelstatic void lib80211_crypt_deinit_entries(struct lib80211_crypt_info *info, 44130803Smarcel int force); 45130803Smarcelstatic void lib80211_crypt_quiescing(struct lib80211_crypt_info *info); 46130803Smarcelstatic void lib80211_crypt_deinit_handler(struct timer_list *t); 47130803Smarcel 48130803Smarcelint lib80211_crypt_info_init(struct lib80211_crypt_info *info, char *name, 49130803Smarcel spinlock_t *lock) 50130803Smarcel{ 51130803Smarcel memset(info, 0, sizeof(*info)); 52130803Smarcel 53130803Smarcel info->name = name; 5498944Sobrien info->lock = lock; 55130803Smarcel 56130803Smarcel INIT_LIST_HEAD(&info->crypt_deinit_list); 57130803Smarcel timer_setup(&info->crypt_deinit_timer, lib80211_crypt_deinit_handler, 58130803Smarcel 0); 59130803Smarcel 60130803Smarcel return 0; 61130803Smarcel} 62130803SmarcelEXPORT_SYMBOL(lib80211_crypt_info_init); 63130803Smarcel 64130803Smarcelvoid lib80211_crypt_info_free(struct lib80211_crypt_info *info) 65130803Smarcel{ 66130803Smarcel int i; 67130803Smarcel 68130803Smarcel lib80211_crypt_quiescing(info); 69130803Smarcel del_timer_sync(&info->crypt_deinit_timer); 70130803Smarcel lib80211_crypt_deinit_entries(info, 1); 71130803Smarcel 72130803Smarcel for (i = 0; i < NUM_WEP_KEYS; i++) { 73130803Smarcel struct lib80211_crypt_data *crypt = info->crypt[i]; 74130803Smarcel if (crypt) { 75130803Smarcel if (crypt->ops) { 76130803Smarcel crypt->ops->deinit(crypt->priv); 77130803Smarcel module_put(crypt->ops->owner); 78130803Smarcel } 79130803Smarcel kfree(crypt); 80130803Smarcel info->crypt[i] = NULL; 81130803Smarcel } 82130803Smarcel } 83130803Smarcel} 84130803SmarcelEXPORT_SYMBOL(lib80211_crypt_info_free); 85130803Smarcel 86130803Smarcelstatic void lib80211_crypt_deinit_entries(struct lib80211_crypt_info *info, 87130803Smarcel int force) 88130803Smarcel{ 89130803Smarcel struct lib80211_crypt_data *entry, *next; 90130803Smarcel unsigned long flags; 91130803Smarcel 92130803Smarcel spin_lock_irqsave(info->lock, flags); 93130803Smarcel list_for_each_entry_safe(entry, next, &info->crypt_deinit_list, list) { 94130803Smarcel if (atomic_read(&entry->refcnt) != 0 && !force) 95130803Smarcel continue; 96130803Smarcel 97130803Smarcel list_del(&entry->list); 98130803Smarcel 9998944Sobrien if (entry->ops) { 100130803Smarcel entry->ops->deinit(entry->priv); 101130803Smarcel module_put(entry->ops->owner); 102130803Smarcel } 103130803Smarcel kfree(entry); 104130803Smarcel } 105130803Smarcel spin_unlock_irqrestore(info->lock, flags); 10698944Sobrien} 107130803Smarcel 108130803Smarcel/* After this, crypt_deinit_list won't accept new members */ 109130803Smarcelstatic void lib80211_crypt_quiescing(struct lib80211_crypt_info *info) 110130803Smarcel{ 111130803Smarcel unsigned long flags; 112130803Smarcel 11398944Sobrien spin_lock_irqsave(info->lock, flags); 114130803Smarcel info->crypt_quiesced = 1; 115130803Smarcel spin_unlock_irqrestore(info->lock, flags); 11698944Sobrien} 117130803Smarcel 11898944Sobrienstatic void lib80211_crypt_deinit_handler(struct timer_list *t) 119130803Smarcel{ 120130803Smarcel struct lib80211_crypt_info *info = from_timer(info, t, 121130803Smarcel crypt_deinit_timer); 122130803Smarcel unsigned long flags; 123130803Smarcel 124130803Smarcel lib80211_crypt_deinit_entries(info, 0); 12598944Sobrien 126130803Smarcel spin_lock_irqsave(info->lock, flags); 127130803Smarcel if (!list_empty(&info->crypt_deinit_list) && !info->crypt_quiesced) { 128130803Smarcel printk(KERN_DEBUG "%s: entries remaining in delayed crypt " 12998944Sobrien "deletion list\n", info->name); 130130803Smarcel info->crypt_deinit_timer.expires = jiffies + HZ; 131130803Smarcel add_timer(&info->crypt_deinit_timer); 132130803Smarcel } 133130803Smarcel spin_unlock_irqrestore(info->lock, flags); 134130803Smarcel} 135130803Smarcel 136130803Smarcelvoid lib80211_crypt_delayed_deinit(struct lib80211_crypt_info *info, 137130803Smarcel struct lib80211_crypt_data **crypt) 138130803Smarcel{ 139130803Smarcel struct lib80211_crypt_data *tmp; 140130803Smarcel unsigned long flags; 141130803Smarcel 142130803Smarcel if (*crypt == NULL) 143130803Smarcel return; 144130803Smarcel 145130803Smarcel tmp = *crypt; 146130803Smarcel *crypt = NULL; 147130803Smarcel 148130803Smarcel /* must not run ops->deinit() while there may be pending encrypt or 149130803Smarcel * decrypt operations. Use a list of delayed deinits to avoid needing 150130803Smarcel * locking. */ 151130803Smarcel 152130803Smarcel spin_lock_irqsave(info->lock, flags); 153130803Smarcel if (!info->crypt_quiesced) { 154130803Smarcel list_add(&tmp->list, &info->crypt_deinit_list); 155130803Smarcel if (!timer_pending(&info->crypt_deinit_timer)) { 156130803Smarcel info->crypt_deinit_timer.expires = jiffies + HZ; 157130803Smarcel add_timer(&info->crypt_deinit_timer); 158130803Smarcel } 159130803Smarcel } 16098944Sobrien spin_unlock_irqrestore(info->lock, flags); 161130803Smarcel} 162130803SmarcelEXPORT_SYMBOL(lib80211_crypt_delayed_deinit); 16398944Sobrien 16498944Sobrienint lib80211_register_crypto_ops(struct lib80211_crypto_ops *ops) 165130803Smarcel{ 16698944Sobrien unsigned long flags; 167130803Smarcel struct lib80211_crypto_alg *alg; 168130803Smarcel 169130803Smarcel alg = kzalloc(sizeof(*alg), GFP_KERNEL); 170130803Smarcel if (alg == NULL) 171130803Smarcel return -ENOMEM; 172130803Smarcel 173130803Smarcel alg->ops = ops; 174130803Smarcel 17598944Sobrien spin_lock_irqsave(&lib80211_crypto_lock, flags); 176130803Smarcel list_add(&alg->list, &lib80211_crypto_algs); 177130803Smarcel spin_unlock_irqrestore(&lib80211_crypto_lock, flags); 17898944Sobrien 179130803Smarcel printk(KERN_DEBUG "lib80211_crypt: registered algorithm '%s'\n", 180130803Smarcel ops->name); 181130803Smarcel 182130803Smarcel return 0; 183130803Smarcel} 184130803SmarcelEXPORT_SYMBOL(lib80211_register_crypto_ops); 18598944Sobrien 18698944Sobrienint lib80211_unregister_crypto_ops(struct lib80211_crypto_ops *ops) 18798944Sobrien{ 18898944Sobrien struct lib80211_crypto_alg *alg; 189130803Smarcel unsigned long flags; 19098944Sobrien 191130803Smarcel spin_lock_irqsave(&lib80211_crypto_lock, flags); 192130803Smarcel list_for_each_entry(alg, &lib80211_crypto_algs, list) { 19398944Sobrien if (alg->ops == ops) 194130803Smarcel goto found; 195130803Smarcel } 196130803Smarcel spin_unlock_irqrestore(&lib80211_crypto_lock, flags); 197130803Smarcel return -EINVAL; 198130803Smarcel 19998944Sobrien found: 200130803Smarcel printk(KERN_DEBUG "lib80211_crypt: unregistered algorithm '%s'\n", 20198944Sobrien ops->name); 202130803Smarcel list_del(&alg->list); 20398944Sobrien spin_unlock_irqrestore(&lib80211_crypto_lock, flags); 204130803Smarcel kfree(alg); 205130803Smarcel return 0; 20698944Sobrien} 207130803SmarcelEXPORT_SYMBOL(lib80211_unregister_crypto_ops); 208130803Smarcel 209130803Smarcelstruct lib80211_crypto_ops *lib80211_get_crypto_ops(const char *name) 210130803Smarcel{ 211130803Smarcel struct lib80211_crypto_alg *alg; 212130803Smarcel unsigned long flags; 213130803Smarcel 214130803Smarcel spin_lock_irqsave(&lib80211_crypto_lock, flags); 21598944Sobrien list_for_each_entry(alg, &lib80211_crypto_algs, list) { 216130803Smarcel if (strcmp(alg->ops->name, name) == 0) 217130803Smarcel goto found; 218130803Smarcel } 219130803Smarcel spin_unlock_irqrestore(&lib80211_crypto_lock, flags); 22098944Sobrien return NULL; 22198944Sobrien 222130803Smarcel found: 223130803Smarcel spin_unlock_irqrestore(&lib80211_crypto_lock, flags); 22498944Sobrien return alg->ops; 22598944Sobrien} 226130803SmarcelEXPORT_SYMBOL(lib80211_get_crypto_ops); 22798944Sobrien 228130803Smarcelstatic void *lib80211_crypt_null_init(int keyidx) 22998944Sobrien{ 230130803Smarcel return (void *)1; 231130803Smarcel} 23298944Sobrien 233130803Smarcelstatic void lib80211_crypt_null_deinit(void *priv) 234130803Smarcel{ 23598944Sobrien} 236130803Smarcel 237130803Smarcelstatic struct lib80211_crypto_ops lib80211_crypt_null = { 238130803Smarcel .name = "NULL", 239130803Smarcel .init = lib80211_crypt_null_init, 240130803Smarcel .deinit = lib80211_crypt_null_deinit, 241130803Smarcel .owner = THIS_MODULE, 242130803Smarcel}; 243130803Smarcel 244130803Smarcelstatic int __init lib80211_init(void) 245130803Smarcel{ 24698944Sobrien pr_info(DRV_DESCRIPTION "\n"); 247130803Smarcel return lib80211_register_crypto_ops(&lib80211_crypt_null); 248130803Smarcel} 24998944Sobrien 25098944Sobrienstatic void __exit lib80211_exit(void) 25198944Sobrien{ 252130803Smarcel lib80211_unregister_crypto_ops(&lib80211_crypt_null); 253130803Smarcel BUG_ON(!list_empty(&lib80211_crypto_algs)); 25498944Sobrien} 255130803Smarcel 256130803Smarcelmodule_init(lib80211_init); 257130803Smarcelmodule_exit(lib80211_exit); 258130803Smarcel