Merge branch 'tty-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh...
[pandora-kernel.git] / net / wireless / lib80211.c
1 /*
2  * lib80211 -- common bits for IEEE802.11 drivers
3  *
4  * Copyright(c) 2008 John W. Linville <linville@tuxdriver.com>
5  *
6  * Portions copied from old ieee80211 component, w/ original copyright
7  * notices below:
8  *
9  * Host AP crypto routines
10  *
11  * Copyright (c) 2002-2003, Jouni Malinen <j@w1.fi>
12  * Portions Copyright (C) 2004, Intel Corporation <jketreno@linux.intel.com>
13  *
14  */
15
16 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
17
18 #include <linux/module.h>
19 #include <linux/ctype.h>
20 #include <linux/ieee80211.h>
21 #include <linux/errno.h>
22 #include <linux/init.h>
23 #include <linux/slab.h>
24 #include <linux/string.h>
25
26 #include <net/lib80211.h>
27
28 #define DRV_NAME        "lib80211"
29
30 #define DRV_DESCRIPTION "common routines for IEEE802.11 drivers"
31
32 MODULE_DESCRIPTION(DRV_DESCRIPTION);
33 MODULE_AUTHOR("John W. Linville <linville@tuxdriver.com>");
34 MODULE_LICENSE("GPL");
35
36 struct lib80211_crypto_alg {
37         struct list_head list;
38         struct lib80211_crypto_ops *ops;
39 };
40
41 static LIST_HEAD(lib80211_crypto_algs);
42 static DEFINE_SPINLOCK(lib80211_crypto_lock);
43
44 const char *print_ssid(char *buf, const char *ssid, u8 ssid_len)
45 {
46         const char *s = ssid;
47         char *d = buf;
48
49         ssid_len = min_t(u8, ssid_len, IEEE80211_MAX_SSID_LEN);
50         while (ssid_len--) {
51                 if (isprint(*s)) {
52                         *d++ = *s++;
53                         continue;
54                 }
55
56                 *d++ = '\\';
57                 if (*s == '\0')
58                         *d++ = '0';
59                 else if (*s == '\n')
60                         *d++ = 'n';
61                 else if (*s == '\r')
62                         *d++ = 'r';
63                 else if (*s == '\t')
64                         *d++ = 't';
65                 else if (*s == '\\')
66                         *d++ = '\\';
67                 else
68                         d += snprintf(d, 3, "%03o", *s);
69                 s++;
70         }
71         *d = '\0';
72         return buf;
73 }
74 EXPORT_SYMBOL(print_ssid);
75
76 int lib80211_crypt_info_init(struct lib80211_crypt_info *info, char *name,
77                                 spinlock_t *lock)
78 {
79         memset(info, 0, sizeof(*info));
80
81         info->name = name;
82         info->lock = lock;
83
84         INIT_LIST_HEAD(&info->crypt_deinit_list);
85         setup_timer(&info->crypt_deinit_timer, lib80211_crypt_deinit_handler,
86                         (unsigned long)info);
87
88         return 0;
89 }
90 EXPORT_SYMBOL(lib80211_crypt_info_init);
91
92 void lib80211_crypt_info_free(struct lib80211_crypt_info *info)
93 {
94         int i;
95
96         lib80211_crypt_quiescing(info);
97         del_timer_sync(&info->crypt_deinit_timer);
98         lib80211_crypt_deinit_entries(info, 1);
99
100         for (i = 0; i < NUM_WEP_KEYS; i++) {
101                 struct lib80211_crypt_data *crypt = info->crypt[i];
102                 if (crypt) {
103                         if (crypt->ops) {
104                                 crypt->ops->deinit(crypt->priv);
105                                 module_put(crypt->ops->owner);
106                         }
107                         kfree(crypt);
108                         info->crypt[i] = NULL;
109                 }
110         }
111 }
112 EXPORT_SYMBOL(lib80211_crypt_info_free);
113
114 void lib80211_crypt_deinit_entries(struct lib80211_crypt_info *info, int force)
115 {
116         struct lib80211_crypt_data *entry, *next;
117         unsigned long flags;
118
119         spin_lock_irqsave(info->lock, flags);
120         list_for_each_entry_safe(entry, next, &info->crypt_deinit_list, list) {
121                 if (atomic_read(&entry->refcnt) != 0 && !force)
122                         continue;
123
124                 list_del(&entry->list);
125
126                 if (entry->ops) {
127                         entry->ops->deinit(entry->priv);
128                         module_put(entry->ops->owner);
129                 }
130                 kfree(entry);
131         }
132         spin_unlock_irqrestore(info->lock, flags);
133 }
134 EXPORT_SYMBOL(lib80211_crypt_deinit_entries);
135
136 /* After this, crypt_deinit_list won't accept new members */
137 void lib80211_crypt_quiescing(struct lib80211_crypt_info *info)
138 {
139         unsigned long flags;
140
141         spin_lock_irqsave(info->lock, flags);
142         info->crypt_quiesced = 1;
143         spin_unlock_irqrestore(info->lock, flags);
144 }
145 EXPORT_SYMBOL(lib80211_crypt_quiescing);
146
147 void lib80211_crypt_deinit_handler(unsigned long data)
148 {
149         struct lib80211_crypt_info *info = (struct lib80211_crypt_info *)data;
150         unsigned long flags;
151
152         lib80211_crypt_deinit_entries(info, 0);
153
154         spin_lock_irqsave(info->lock, flags);
155         if (!list_empty(&info->crypt_deinit_list) && !info->crypt_quiesced) {
156                 printk(KERN_DEBUG "%s: entries remaining in delayed crypt "
157                        "deletion list\n", info->name);
158                 info->crypt_deinit_timer.expires = jiffies + HZ;
159                 add_timer(&info->crypt_deinit_timer);
160         }
161         spin_unlock_irqrestore(info->lock, flags);
162 }
163 EXPORT_SYMBOL(lib80211_crypt_deinit_handler);
164
165 void lib80211_crypt_delayed_deinit(struct lib80211_crypt_info *info,
166                                     struct lib80211_crypt_data **crypt)
167 {
168         struct lib80211_crypt_data *tmp;
169         unsigned long flags;
170
171         if (*crypt == NULL)
172                 return;
173
174         tmp = *crypt;
175         *crypt = NULL;
176
177         /* must not run ops->deinit() while there may be pending encrypt or
178          * decrypt operations. Use a list of delayed deinits to avoid needing
179          * locking. */
180
181         spin_lock_irqsave(info->lock, flags);
182         if (!info->crypt_quiesced) {
183                 list_add(&tmp->list, &info->crypt_deinit_list);
184                 if (!timer_pending(&info->crypt_deinit_timer)) {
185                         info->crypt_deinit_timer.expires = jiffies + HZ;
186                         add_timer(&info->crypt_deinit_timer);
187                 }
188         }
189         spin_unlock_irqrestore(info->lock, flags);
190 }
191 EXPORT_SYMBOL(lib80211_crypt_delayed_deinit);
192
193 int lib80211_register_crypto_ops(struct lib80211_crypto_ops *ops)
194 {
195         unsigned long flags;
196         struct lib80211_crypto_alg *alg;
197
198         alg = kzalloc(sizeof(*alg), GFP_KERNEL);
199         if (alg == NULL)
200                 return -ENOMEM;
201
202         alg->ops = ops;
203
204         spin_lock_irqsave(&lib80211_crypto_lock, flags);
205         list_add(&alg->list, &lib80211_crypto_algs);
206         spin_unlock_irqrestore(&lib80211_crypto_lock, flags);
207
208         printk(KERN_DEBUG "lib80211_crypt: registered algorithm '%s'\n",
209                ops->name);
210
211         return 0;
212 }
213 EXPORT_SYMBOL(lib80211_register_crypto_ops);
214
215 int lib80211_unregister_crypto_ops(struct lib80211_crypto_ops *ops)
216 {
217         struct lib80211_crypto_alg *alg;
218         unsigned long flags;
219
220         spin_lock_irqsave(&lib80211_crypto_lock, flags);
221         list_for_each_entry(alg, &lib80211_crypto_algs, list) {
222                 if (alg->ops == ops)
223                         goto found;
224         }
225         spin_unlock_irqrestore(&lib80211_crypto_lock, flags);
226         return -EINVAL;
227
228       found:
229         printk(KERN_DEBUG "lib80211_crypt: unregistered algorithm '%s'\n",
230                ops->name);
231         list_del(&alg->list);
232         spin_unlock_irqrestore(&lib80211_crypto_lock, flags);
233         kfree(alg);
234         return 0;
235 }
236 EXPORT_SYMBOL(lib80211_unregister_crypto_ops);
237
238 struct lib80211_crypto_ops *lib80211_get_crypto_ops(const char *name)
239 {
240         struct lib80211_crypto_alg *alg;
241         unsigned long flags;
242
243         spin_lock_irqsave(&lib80211_crypto_lock, flags);
244         list_for_each_entry(alg, &lib80211_crypto_algs, list) {
245                 if (strcmp(alg->ops->name, name) == 0)
246                         goto found;
247         }
248         spin_unlock_irqrestore(&lib80211_crypto_lock, flags);
249         return NULL;
250
251       found:
252         spin_unlock_irqrestore(&lib80211_crypto_lock, flags);
253         return alg->ops;
254 }
255 EXPORT_SYMBOL(lib80211_get_crypto_ops);
256
257 static void *lib80211_crypt_null_init(int keyidx)
258 {
259         return (void *)1;
260 }
261
262 static void lib80211_crypt_null_deinit(void *priv)
263 {
264 }
265
266 static struct lib80211_crypto_ops lib80211_crypt_null = {
267         .name = "NULL",
268         .init = lib80211_crypt_null_init,
269         .deinit = lib80211_crypt_null_deinit,
270         .owner = THIS_MODULE,
271 };
272
273 static int __init lib80211_init(void)
274 {
275         pr_info(DRV_DESCRIPTION "\n");
276         return lib80211_register_crypto_ops(&lib80211_crypt_null);
277 }
278
279 static void __exit lib80211_exit(void)
280 {
281         lib80211_unregister_crypto_ops(&lib80211_crypt_null);
282         BUG_ON(!list_empty(&lib80211_crypto_algs));
283 }
284
285 module_init(lib80211_init);
286 module_exit(lib80211_exit);