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