17e272fcfSJohn W. Linville /* 27e272fcfSJohn W. Linville * lib80211 -- common bits for IEEE802.11 drivers 37e272fcfSJohn W. Linville * 47e272fcfSJohn W. Linville * Copyright(c) 2008 John W. Linville <linville@tuxdriver.com> 57e272fcfSJohn W. Linville * 6*274bfb8dSJohn W. Linville * Portions copied from old ieee80211 component, w/ original copyright 7*274bfb8dSJohn W. Linville * notices below: 8*274bfb8dSJohn W. Linville * 9*274bfb8dSJohn W. Linville * Host AP crypto routines 10*274bfb8dSJohn W. Linville * 11*274bfb8dSJohn W. Linville * Copyright (c) 2002-2003, Jouni Malinen <j@w1.fi> 12*274bfb8dSJohn W. Linville * Portions Copyright (C) 2004, Intel Corporation <jketreno@linux.intel.com> 13*274bfb8dSJohn W. Linville * 147e272fcfSJohn W. Linville */ 157e272fcfSJohn W. Linville 167e272fcfSJohn W. Linville #include <linux/module.h> 172819f8adSJohn W. Linville #include <linux/ctype.h> 187e272fcfSJohn W. Linville #include <linux/ieee80211.h> 19*274bfb8dSJohn W. Linville #include <linux/errno.h> 20*274bfb8dSJohn W. Linville #include <linux/init.h> 21*274bfb8dSJohn W. Linville #include <linux/slab.h> 22*274bfb8dSJohn W. Linville #include <linux/string.h> 237e272fcfSJohn W. Linville 247e272fcfSJohn W. Linville #include <net/lib80211.h> 257e272fcfSJohn W. Linville 267e272fcfSJohn W. Linville #define DRV_NAME "lib80211" 277e272fcfSJohn W. Linville 287e272fcfSJohn W. Linville #define DRV_DESCRIPTION "common routines for IEEE802.11 drivers" 297e272fcfSJohn W. Linville 307e272fcfSJohn W. Linville MODULE_DESCRIPTION(DRV_DESCRIPTION); 317e272fcfSJohn W. Linville MODULE_AUTHOR("John W. Linville <linville@tuxdriver.com>"); 327e272fcfSJohn W. Linville MODULE_LICENSE("GPL"); 337e272fcfSJohn W. Linville 34*274bfb8dSJohn W. Linville struct lib80211_crypto_alg { 35*274bfb8dSJohn W. Linville struct list_head list; 36*274bfb8dSJohn W. Linville struct lib80211_crypto_ops *ops; 37*274bfb8dSJohn W. Linville }; 38*274bfb8dSJohn W. Linville 39*274bfb8dSJohn W. Linville static LIST_HEAD(lib80211_crypto_algs); 40*274bfb8dSJohn W. Linville static DEFINE_SPINLOCK(lib80211_crypto_lock); 41*274bfb8dSJohn W. Linville 429387b7caSJohn W. Linville const char *print_ssid(char *buf, const char *ssid, u8 ssid_len) 437e272fcfSJohn W. Linville { 447e272fcfSJohn W. Linville const char *s = ssid; 459387b7caSJohn W. Linville char *d = buf; 467e272fcfSJohn W. Linville 477e272fcfSJohn W. Linville ssid_len = min_t(u8, ssid_len, IEEE80211_MAX_SSID_LEN); 487e272fcfSJohn W. Linville while (ssid_len--) { 492819f8adSJohn W. Linville if (isprint(*s)) { 507e272fcfSJohn W. Linville *d++ = *s++; 512819f8adSJohn W. Linville continue; 527e272fcfSJohn W. Linville } 532819f8adSJohn W. Linville 542819f8adSJohn W. Linville *d++ = '\\'; 552819f8adSJohn W. Linville if (*s == '\0') 562819f8adSJohn W. Linville *d++ = '0'; 572819f8adSJohn W. Linville else if (*s == '\n') 582819f8adSJohn W. Linville *d++ = 'n'; 592819f8adSJohn W. Linville else if (*s == '\r') 602819f8adSJohn W. Linville *d++ = 'r'; 612819f8adSJohn W. Linville else if (*s == '\t') 622819f8adSJohn W. Linville *d++ = 't'; 632819f8adSJohn W. Linville else if (*s == '\\') 642819f8adSJohn W. Linville *d++ = '\\'; 652819f8adSJohn W. Linville else 662819f8adSJohn W. Linville d += snprintf(d, 3, "%03o", *s); 672819f8adSJohn W. Linville s++; 687e272fcfSJohn W. Linville } 697e272fcfSJohn W. Linville *d = '\0'; 709387b7caSJohn W. Linville return buf; 717e272fcfSJohn W. Linville } 729387b7caSJohn W. Linville EXPORT_SYMBOL(print_ssid); 737e272fcfSJohn W. Linville 74*274bfb8dSJohn W. Linville void lib80211_crypt_deinit_entries(struct lib80211_crypt_info *info, int force) 757e272fcfSJohn W. Linville { 76*274bfb8dSJohn W. Linville struct lib80211_crypt_data *entry, *next; 77*274bfb8dSJohn W. Linville unsigned long flags; 78*274bfb8dSJohn W. Linville 79*274bfb8dSJohn W. Linville spin_lock_irqsave(info->lock, flags); 80*274bfb8dSJohn W. Linville list_for_each_entry_safe(entry, next, &info->crypt_deinit_list, list) { 81*274bfb8dSJohn W. Linville if (atomic_read(&entry->refcnt) != 0 && !force) 82*274bfb8dSJohn W. Linville continue; 83*274bfb8dSJohn W. Linville 84*274bfb8dSJohn W. Linville list_del(&entry->list); 85*274bfb8dSJohn W. Linville 86*274bfb8dSJohn W. Linville if (entry->ops) { 87*274bfb8dSJohn W. Linville entry->ops->deinit(entry->priv); 88*274bfb8dSJohn W. Linville module_put(entry->ops->owner); 89*274bfb8dSJohn W. Linville } 90*274bfb8dSJohn W. Linville kfree(entry); 91*274bfb8dSJohn W. Linville } 92*274bfb8dSJohn W. Linville spin_unlock_irqrestore(info->lock, flags); 93*274bfb8dSJohn W. Linville } 94*274bfb8dSJohn W. Linville EXPORT_SYMBOL(lib80211_crypt_deinit_entries); 95*274bfb8dSJohn W. Linville 96*274bfb8dSJohn W. Linville /* After this, crypt_deinit_list won't accept new members */ 97*274bfb8dSJohn W. Linville void lib80211_crypt_quiescing(struct lib80211_crypt_info *info) 98*274bfb8dSJohn W. Linville { 99*274bfb8dSJohn W. Linville unsigned long flags; 100*274bfb8dSJohn W. Linville 101*274bfb8dSJohn W. Linville spin_lock_irqsave(info->lock, flags); 102*274bfb8dSJohn W. Linville info->crypt_quiesced = 1; 103*274bfb8dSJohn W. Linville spin_unlock_irqrestore(info->lock, flags); 104*274bfb8dSJohn W. Linville } 105*274bfb8dSJohn W. Linville EXPORT_SYMBOL(lib80211_crypt_quiescing); 106*274bfb8dSJohn W. Linville 107*274bfb8dSJohn W. Linville void lib80211_crypt_deinit_handler(unsigned long data) 108*274bfb8dSJohn W. Linville { 109*274bfb8dSJohn W. Linville struct lib80211_crypt_info *info = (struct lib80211_crypt_info *)data; 110*274bfb8dSJohn W. Linville unsigned long flags; 111*274bfb8dSJohn W. Linville 112*274bfb8dSJohn W. Linville lib80211_crypt_deinit_entries(info, 0); 113*274bfb8dSJohn W. Linville 114*274bfb8dSJohn W. Linville spin_lock_irqsave(info->lock, flags); 115*274bfb8dSJohn W. Linville if (!list_empty(&info->crypt_deinit_list) && !info->crypt_quiesced) { 116*274bfb8dSJohn W. Linville printk(KERN_DEBUG "%s: entries remaining in delayed crypt " 117*274bfb8dSJohn W. Linville "deletion list\n", info->name); 118*274bfb8dSJohn W. Linville info->crypt_deinit_timer.expires = jiffies + HZ; 119*274bfb8dSJohn W. Linville add_timer(&info->crypt_deinit_timer); 120*274bfb8dSJohn W. Linville } 121*274bfb8dSJohn W. Linville spin_unlock_irqrestore(info->lock, flags); 122*274bfb8dSJohn W. Linville } 123*274bfb8dSJohn W. Linville EXPORT_SYMBOL(lib80211_crypt_deinit_handler); 124*274bfb8dSJohn W. Linville 125*274bfb8dSJohn W. Linville void lib80211_crypt_delayed_deinit(struct lib80211_crypt_info *info, 126*274bfb8dSJohn W. Linville struct lib80211_crypt_data **crypt) 127*274bfb8dSJohn W. Linville { 128*274bfb8dSJohn W. Linville struct lib80211_crypt_data *tmp; 129*274bfb8dSJohn W. Linville unsigned long flags; 130*274bfb8dSJohn W. Linville 131*274bfb8dSJohn W. Linville if (*crypt == NULL) 132*274bfb8dSJohn W. Linville return; 133*274bfb8dSJohn W. Linville 134*274bfb8dSJohn W. Linville tmp = *crypt; 135*274bfb8dSJohn W. Linville *crypt = NULL; 136*274bfb8dSJohn W. Linville 137*274bfb8dSJohn W. Linville /* must not run ops->deinit() while there may be pending encrypt or 138*274bfb8dSJohn W. Linville * decrypt operations. Use a list of delayed deinits to avoid needing 139*274bfb8dSJohn W. Linville * locking. */ 140*274bfb8dSJohn W. Linville 141*274bfb8dSJohn W. Linville spin_lock_irqsave(info->lock, flags); 142*274bfb8dSJohn W. Linville if (!info->crypt_quiesced) { 143*274bfb8dSJohn W. Linville list_add(&tmp->list, &info->crypt_deinit_list); 144*274bfb8dSJohn W. Linville if (!timer_pending(&info->crypt_deinit_timer)) { 145*274bfb8dSJohn W. Linville info->crypt_deinit_timer.expires = jiffies + HZ; 146*274bfb8dSJohn W. Linville add_timer(&info->crypt_deinit_timer); 147*274bfb8dSJohn W. Linville } 148*274bfb8dSJohn W. Linville } 149*274bfb8dSJohn W. Linville spin_unlock_irqrestore(info->lock, flags); 150*274bfb8dSJohn W. Linville } 151*274bfb8dSJohn W. Linville EXPORT_SYMBOL(lib80211_crypt_delayed_deinit); 152*274bfb8dSJohn W. Linville 153*274bfb8dSJohn W. Linville int lib80211_register_crypto_ops(struct lib80211_crypto_ops *ops) 154*274bfb8dSJohn W. Linville { 155*274bfb8dSJohn W. Linville unsigned long flags; 156*274bfb8dSJohn W. Linville struct lib80211_crypto_alg *alg; 157*274bfb8dSJohn W. Linville 158*274bfb8dSJohn W. Linville alg = kzalloc(sizeof(*alg), GFP_KERNEL); 159*274bfb8dSJohn W. Linville if (alg == NULL) 160*274bfb8dSJohn W. Linville return -ENOMEM; 161*274bfb8dSJohn W. Linville 162*274bfb8dSJohn W. Linville alg->ops = ops; 163*274bfb8dSJohn W. Linville 164*274bfb8dSJohn W. Linville spin_lock_irqsave(&lib80211_crypto_lock, flags); 165*274bfb8dSJohn W. Linville list_add(&alg->list, &lib80211_crypto_algs); 166*274bfb8dSJohn W. Linville spin_unlock_irqrestore(&lib80211_crypto_lock, flags); 167*274bfb8dSJohn W. Linville 168*274bfb8dSJohn W. Linville printk(KERN_DEBUG "lib80211_crypt: registered algorithm '%s'\n", 169*274bfb8dSJohn W. Linville ops->name); 170*274bfb8dSJohn W. Linville 1717e272fcfSJohn W. Linville return 0; 1727e272fcfSJohn W. Linville } 173*274bfb8dSJohn W. Linville EXPORT_SYMBOL(lib80211_register_crypto_ops); 1747e272fcfSJohn W. Linville 175*274bfb8dSJohn W. Linville int lib80211_unregister_crypto_ops(struct lib80211_crypto_ops *ops) 176*274bfb8dSJohn W. Linville { 177*274bfb8dSJohn W. Linville struct lib80211_crypto_alg *alg; 178*274bfb8dSJohn W. Linville unsigned long flags; 179*274bfb8dSJohn W. Linville 180*274bfb8dSJohn W. Linville spin_lock_irqsave(&lib80211_crypto_lock, flags); 181*274bfb8dSJohn W. Linville list_for_each_entry(alg, &lib80211_crypto_algs, list) { 182*274bfb8dSJohn W. Linville if (alg->ops == ops) 183*274bfb8dSJohn W. Linville goto found; 184*274bfb8dSJohn W. Linville } 185*274bfb8dSJohn W. Linville spin_unlock_irqrestore(&lib80211_crypto_lock, flags); 186*274bfb8dSJohn W. Linville return -EINVAL; 187*274bfb8dSJohn W. Linville 188*274bfb8dSJohn W. Linville found: 189*274bfb8dSJohn W. Linville printk(KERN_DEBUG "lib80211_crypt: unregistered algorithm " 190*274bfb8dSJohn W. Linville "'%s'\n", ops->name); 191*274bfb8dSJohn W. Linville list_del(&alg->list); 192*274bfb8dSJohn W. Linville spin_unlock_irqrestore(&lib80211_crypto_lock, flags); 193*274bfb8dSJohn W. Linville kfree(alg); 194*274bfb8dSJohn W. Linville return 0; 195*274bfb8dSJohn W. Linville } 196*274bfb8dSJohn W. Linville EXPORT_SYMBOL(lib80211_unregister_crypto_ops); 197*274bfb8dSJohn W. Linville 198*274bfb8dSJohn W. Linville struct lib80211_crypto_ops *lib80211_get_crypto_ops(const char *name) 199*274bfb8dSJohn W. Linville { 200*274bfb8dSJohn W. Linville struct lib80211_crypto_alg *alg; 201*274bfb8dSJohn W. Linville unsigned long flags; 202*274bfb8dSJohn W. Linville 203*274bfb8dSJohn W. Linville spin_lock_irqsave(&lib80211_crypto_lock, flags); 204*274bfb8dSJohn W. Linville list_for_each_entry(alg, &lib80211_crypto_algs, list) { 205*274bfb8dSJohn W. Linville if (strcmp(alg->ops->name, name) == 0) 206*274bfb8dSJohn W. Linville goto found; 207*274bfb8dSJohn W. Linville } 208*274bfb8dSJohn W. Linville spin_unlock_irqrestore(&lib80211_crypto_lock, flags); 209*274bfb8dSJohn W. Linville return NULL; 210*274bfb8dSJohn W. Linville 211*274bfb8dSJohn W. Linville found: 212*274bfb8dSJohn W. Linville spin_unlock_irqrestore(&lib80211_crypto_lock, flags); 213*274bfb8dSJohn W. Linville return alg->ops; 214*274bfb8dSJohn W. Linville } 215*274bfb8dSJohn W. Linville EXPORT_SYMBOL(lib80211_get_crypto_ops); 216*274bfb8dSJohn W. Linville 217*274bfb8dSJohn W. Linville static void *lib80211_crypt_null_init(int keyidx) 218*274bfb8dSJohn W. Linville { 219*274bfb8dSJohn W. Linville return (void *)1; 220*274bfb8dSJohn W. Linville } 221*274bfb8dSJohn W. Linville 222*274bfb8dSJohn W. Linville static void lib80211_crypt_null_deinit(void *priv) 2237e272fcfSJohn W. Linville { 2247e272fcfSJohn W. Linville } 2257e272fcfSJohn W. Linville 226*274bfb8dSJohn W. Linville static struct lib80211_crypto_ops lib80211_crypt_null = { 227*274bfb8dSJohn W. Linville .name = "NULL", 228*274bfb8dSJohn W. Linville .init = lib80211_crypt_null_init, 229*274bfb8dSJohn W. Linville .deinit = lib80211_crypt_null_deinit, 230*274bfb8dSJohn W. Linville .owner = THIS_MODULE, 231*274bfb8dSJohn W. Linville }; 232*274bfb8dSJohn W. Linville 233*274bfb8dSJohn W. Linville static int __init lib80211_init(void) 234*274bfb8dSJohn W. Linville { 235*274bfb8dSJohn W. Linville printk(KERN_INFO DRV_NAME ": " DRV_DESCRIPTION "\n"); 236*274bfb8dSJohn W. Linville return lib80211_register_crypto_ops(&lib80211_crypt_null); 237*274bfb8dSJohn W. Linville } 238*274bfb8dSJohn W. Linville 239*274bfb8dSJohn W. Linville static void __exit lib80211_exit(void) 240*274bfb8dSJohn W. Linville { 241*274bfb8dSJohn W. Linville lib80211_unregister_crypto_ops(&lib80211_crypt_null); 242*274bfb8dSJohn W. Linville BUG_ON(!list_empty(&lib80211_crypto_algs)); 243*274bfb8dSJohn W. Linville } 244*274bfb8dSJohn W. Linville 245*274bfb8dSJohn W. Linville module_init(lib80211_init); 246*274bfb8dSJohn W. Linville module_exit(lib80211_exit); 247