1 /* 2 * Host AP crypto routines 3 * 4 * Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi> 5 * Portions Copyright (C) 2004, Intel Corporation <jketreno@linux.intel.com> 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License version 2 as 9 * published by the Free Software Foundation. See README and COPYING for 10 * more details. 11 * 12 */ 13 14 #include <linux/module.h> 15 #include <linux/init.h> 16 #include <linux/slab.h> 17 #include <linux/string.h> 18 #include <linux/errno.h> 19 20 #include "ieee80211.h" 21 22 MODULE_AUTHOR("Jouni Malinen"); 23 MODULE_DESCRIPTION("HostAP crypto"); 24 MODULE_LICENSE("GPL"); 25 26 struct ieee80211_crypto_alg { 27 struct list_head list; 28 struct ieee80211_crypto_ops *ops; 29 }; 30 31 32 struct ieee80211_crypto { 33 struct list_head algs; 34 spinlock_t lock; 35 }; 36 37 static struct ieee80211_crypto *hcrypt; 38 39 void ieee80211_crypt_deinit_entries(struct ieee80211_device *ieee, 40 int force) 41 { 42 struct list_head *ptr, *n; 43 struct ieee80211_crypt_data *entry; 44 45 for (ptr = ieee->crypt_deinit_list.next, n = ptr->next; 46 ptr != &ieee->crypt_deinit_list; ptr = n, n = ptr->next) { 47 entry = list_entry(ptr, struct ieee80211_crypt_data, list); 48 49 if (atomic_read(&entry->refcnt) != 0 && !force) 50 continue; 51 52 list_del(ptr); 53 54 if (entry->ops) 55 entry->ops->deinit(entry->priv); 56 kfree(entry); 57 } 58 } 59 60 void ieee80211_crypt_deinit_handler(unsigned long data) 61 { 62 struct ieee80211_device *ieee = (struct ieee80211_device *)data; 63 unsigned long flags; 64 65 spin_lock_irqsave(&ieee->lock, flags); 66 ieee80211_crypt_deinit_entries(ieee, 0); 67 if (!list_empty(&ieee->crypt_deinit_list)) { 68 netdev_dbg(ieee->dev, "%s: entries remaining in delayed crypt deletion list\n", 69 ieee->dev->name); 70 ieee->crypt_deinit_timer.expires = jiffies + HZ; 71 add_timer(&ieee->crypt_deinit_timer); 72 } 73 spin_unlock_irqrestore(&ieee->lock, flags); 74 75 } 76 77 void ieee80211_crypt_delayed_deinit(struct ieee80211_device *ieee, 78 struct ieee80211_crypt_data **crypt) 79 { 80 struct ieee80211_crypt_data *tmp; 81 unsigned long flags; 82 83 if (*crypt == NULL) 84 return; 85 86 tmp = *crypt; 87 *crypt = NULL; 88 89 /* must not run ops->deinit() while there may be pending encrypt or 90 * decrypt operations. Use a list of delayed deinits to avoid needing 91 * locking. */ 92 93 spin_lock_irqsave(&ieee->lock, flags); 94 list_add(&tmp->list, &ieee->crypt_deinit_list); 95 if (!timer_pending(&ieee->crypt_deinit_timer)) { 96 ieee->crypt_deinit_timer.expires = jiffies + HZ; 97 add_timer(&ieee->crypt_deinit_timer); 98 } 99 spin_unlock_irqrestore(&ieee->lock, flags); 100 } 101 102 int ieee80211_register_crypto_ops(struct ieee80211_crypto_ops *ops) 103 { 104 unsigned long flags; 105 struct ieee80211_crypto_alg *alg; 106 107 if (hcrypt == NULL) 108 return -1; 109 110 alg = kzalloc(sizeof(*alg), GFP_KERNEL); 111 if (alg == NULL) 112 return -ENOMEM; 113 114 alg->ops = ops; 115 116 spin_lock_irqsave(&hcrypt->lock, flags); 117 list_add(&alg->list, &hcrypt->algs); 118 spin_unlock_irqrestore(&hcrypt->lock, flags); 119 120 pr_debug("ieee80211_crypt: registered algorithm '%s'\n", 121 ops->name); 122 123 return 0; 124 } 125 126 int ieee80211_unregister_crypto_ops(struct ieee80211_crypto_ops *ops) 127 { 128 unsigned long flags; 129 struct list_head *ptr; 130 struct ieee80211_crypto_alg *del_alg = NULL; 131 132 if (hcrypt == NULL) 133 return -1; 134 135 spin_lock_irqsave(&hcrypt->lock, flags); 136 for (ptr = hcrypt->algs.next; ptr != &hcrypt->algs; ptr = ptr->next) { 137 struct ieee80211_crypto_alg *alg = 138 (struct ieee80211_crypto_alg *) ptr; 139 if (alg->ops == ops) { 140 list_del(&alg->list); 141 del_alg = alg; 142 break; 143 } 144 } 145 spin_unlock_irqrestore(&hcrypt->lock, flags); 146 147 if (del_alg) { 148 pr_debug("ieee80211_crypt: unregistered algorithm '%s'\n", 149 ops->name); 150 kfree(del_alg); 151 } 152 153 return del_alg ? 0 : -1; 154 } 155 156 157 struct ieee80211_crypto_ops *ieee80211_get_crypto_ops(const char *name) 158 { 159 unsigned long flags; 160 struct list_head *ptr; 161 struct ieee80211_crypto_alg *found_alg = NULL; 162 163 if (hcrypt == NULL) 164 return NULL; 165 166 spin_lock_irqsave(&hcrypt->lock, flags); 167 for (ptr = hcrypt->algs.next; ptr != &hcrypt->algs; ptr = ptr->next) { 168 struct ieee80211_crypto_alg *alg = 169 (struct ieee80211_crypto_alg *) ptr; 170 if (strcmp(alg->ops->name, name) == 0) { 171 found_alg = alg; 172 break; 173 } 174 } 175 spin_unlock_irqrestore(&hcrypt->lock, flags); 176 177 if (found_alg) 178 return found_alg->ops; 179 return NULL; 180 } 181 182 183 static void *ieee80211_crypt_null_init(int keyidx) { return (void *) 1; } 184 static void ieee80211_crypt_null_deinit(void *priv) {} 185 186 static struct ieee80211_crypto_ops ieee80211_crypt_null = { 187 .name = "NULL", 188 .init = ieee80211_crypt_null_init, 189 .deinit = ieee80211_crypt_null_deinit, 190 .encrypt_mpdu = NULL, 191 .decrypt_mpdu = NULL, 192 .encrypt_msdu = NULL, 193 .decrypt_msdu = NULL, 194 .set_key = NULL, 195 .get_key = NULL, 196 .extra_prefix_len = 0, 197 .extra_postfix_len = 0, 198 .owner = THIS_MODULE, 199 }; 200 201 int __init ieee80211_crypto_init(void) 202 { 203 int ret = -ENOMEM; 204 205 hcrypt = kzalloc(sizeof(*hcrypt), GFP_KERNEL); 206 if (!hcrypt) 207 goto out; 208 209 INIT_LIST_HEAD(&hcrypt->algs); 210 spin_lock_init(&hcrypt->lock); 211 212 ret = ieee80211_register_crypto_ops(&ieee80211_crypt_null); 213 if (ret < 0) { 214 kfree(hcrypt); 215 hcrypt = NULL; 216 } 217 out: 218 return ret; 219 } 220 221 void __exit ieee80211_crypto_deinit(void) 222 { 223 struct list_head *ptr, *n; 224 225 if (hcrypt == NULL) 226 return; 227 228 for (ptr = hcrypt->algs.next, n = ptr->next; ptr != &hcrypt->algs; 229 ptr = n, n = ptr->next) { 230 struct ieee80211_crypto_alg *alg = 231 (struct ieee80211_crypto_alg *) ptr; 232 list_del(ptr); 233 pr_debug("ieee80211_crypt: unregistered algorithm '%s' (deinit)\n", 234 alg->ops->name); 235 kfree(alg); 236 } 237 238 kfree(hcrypt); 239 } 240