xref: /openbmc/linux/net/wireless/lib80211.c (revision 274bfb8dc5ffa16cb073801bebe76ab7f4e2e73d)
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