]> git.karo-electronics.de Git - mv-sheeva.git/blob - net/wireless/lib80211.c
lib80211: absorb crypto bits from net/ieee80211
[mv-sheeva.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 #include <linux/module.h>
17 #include <linux/ctype.h>
18 #include <linux/ieee80211.h>
19 #include <linux/errno.h>
20 #include <linux/init.h>
21 #include <linux/slab.h>
22 #include <linux/string.h>
23
24 #include <net/lib80211.h>
25
26 #define DRV_NAME        "lib80211"
27
28 #define DRV_DESCRIPTION "common routines for IEEE802.11 drivers"
29
30 MODULE_DESCRIPTION(DRV_DESCRIPTION);
31 MODULE_AUTHOR("John W. Linville <linville@tuxdriver.com>");
32 MODULE_LICENSE("GPL");
33
34 struct lib80211_crypto_alg {
35         struct list_head list;
36         struct lib80211_crypto_ops *ops;
37 };
38
39 static LIST_HEAD(lib80211_crypto_algs);
40 static DEFINE_SPINLOCK(lib80211_crypto_lock);
41
42 const char *print_ssid(char *buf, const char *ssid, u8 ssid_len)
43 {
44         const char *s = ssid;
45         char *d = buf;
46
47         ssid_len = min_t(u8, ssid_len, IEEE80211_MAX_SSID_LEN);
48         while (ssid_len--) {
49                 if (isprint(*s)) {
50                         *d++ = *s++;
51                         continue;
52                 }
53
54                 *d++ = '\\';
55                 if (*s == '\0')
56                         *d++ = '0';
57                 else if (*s == '\n')
58                         *d++ = 'n';
59                 else if (*s == '\r')
60                         *d++ = 'r';
61                 else if (*s == '\t')
62                         *d++ = 't';
63                 else if (*s == '\\')
64                         *d++ = '\\';
65                 else
66                         d += snprintf(d, 3, "%03o", *s);
67                 s++;
68         }
69         *d = '\0';
70         return buf;
71 }
72 EXPORT_SYMBOL(print_ssid);
73
74 void lib80211_crypt_deinit_entries(struct lib80211_crypt_info *info, int force)
75 {
76         struct lib80211_crypt_data *entry, *next;
77         unsigned long flags;
78
79         spin_lock_irqsave(info->lock, flags);
80         list_for_each_entry_safe(entry, next, &info->crypt_deinit_list, list) {
81                 if (atomic_read(&entry->refcnt) != 0 && !force)
82                         continue;
83
84                 list_del(&entry->list);
85
86                 if (entry->ops) {
87                         entry->ops->deinit(entry->priv);
88                         module_put(entry->ops->owner);
89                 }
90                 kfree(entry);
91         }
92         spin_unlock_irqrestore(info->lock, flags);
93 }
94 EXPORT_SYMBOL(lib80211_crypt_deinit_entries);
95
96 /* After this, crypt_deinit_list won't accept new members */
97 void lib80211_crypt_quiescing(struct lib80211_crypt_info *info)
98 {
99         unsigned long flags;
100
101         spin_lock_irqsave(info->lock, flags);
102         info->crypt_quiesced = 1;
103         spin_unlock_irqrestore(info->lock, flags);
104 }
105 EXPORT_SYMBOL(lib80211_crypt_quiescing);
106
107 void lib80211_crypt_deinit_handler(unsigned long data)
108 {
109         struct lib80211_crypt_info *info = (struct lib80211_crypt_info *)data;
110         unsigned long flags;
111
112         lib80211_crypt_deinit_entries(info, 0);
113
114         spin_lock_irqsave(info->lock, flags);
115         if (!list_empty(&info->crypt_deinit_list) && !info->crypt_quiesced) {
116                 printk(KERN_DEBUG "%s: entries remaining in delayed crypt "
117                        "deletion list\n", info->name);
118                 info->crypt_deinit_timer.expires = jiffies + HZ;
119                 add_timer(&info->crypt_deinit_timer);
120         }
121         spin_unlock_irqrestore(info->lock, flags);
122 }
123 EXPORT_SYMBOL(lib80211_crypt_deinit_handler);
124
125 void lib80211_crypt_delayed_deinit(struct lib80211_crypt_info *info,
126                                     struct lib80211_crypt_data **crypt)
127 {
128         struct lib80211_crypt_data *tmp;
129         unsigned long flags;
130
131         if (*crypt == NULL)
132                 return;
133
134         tmp = *crypt;
135         *crypt = NULL;
136
137         /* must not run ops->deinit() while there may be pending encrypt or
138          * decrypt operations. Use a list of delayed deinits to avoid needing
139          * locking. */
140
141         spin_lock_irqsave(info->lock, flags);
142         if (!info->crypt_quiesced) {
143                 list_add(&tmp->list, &info->crypt_deinit_list);
144                 if (!timer_pending(&info->crypt_deinit_timer)) {
145                         info->crypt_deinit_timer.expires = jiffies + HZ;
146                         add_timer(&info->crypt_deinit_timer);
147                 }
148         }
149         spin_unlock_irqrestore(info->lock, flags);
150 }
151 EXPORT_SYMBOL(lib80211_crypt_delayed_deinit);
152
153 int lib80211_register_crypto_ops(struct lib80211_crypto_ops *ops)
154 {
155         unsigned long flags;
156         struct lib80211_crypto_alg *alg;
157
158         alg = kzalloc(sizeof(*alg), GFP_KERNEL);
159         if (alg == NULL)
160                 return -ENOMEM;
161
162         alg->ops = ops;
163
164         spin_lock_irqsave(&lib80211_crypto_lock, flags);
165         list_add(&alg->list, &lib80211_crypto_algs);
166         spin_unlock_irqrestore(&lib80211_crypto_lock, flags);
167
168         printk(KERN_DEBUG "lib80211_crypt: registered algorithm '%s'\n",
169                ops->name);
170
171         return 0;
172 }
173 EXPORT_SYMBOL(lib80211_register_crypto_ops);
174
175 int lib80211_unregister_crypto_ops(struct lib80211_crypto_ops *ops)
176 {
177         struct lib80211_crypto_alg *alg;
178         unsigned long flags;
179
180         spin_lock_irqsave(&lib80211_crypto_lock, flags);
181         list_for_each_entry(alg, &lib80211_crypto_algs, list) {
182                 if (alg->ops == ops)
183                         goto found;
184         }
185         spin_unlock_irqrestore(&lib80211_crypto_lock, flags);
186         return -EINVAL;
187
188       found:
189         printk(KERN_DEBUG "lib80211_crypt: unregistered algorithm "
190                "'%s'\n", ops->name);
191         list_del(&alg->list);
192         spin_unlock_irqrestore(&lib80211_crypto_lock, flags);
193         kfree(alg);
194         return 0;
195 }
196 EXPORT_SYMBOL(lib80211_unregister_crypto_ops);
197
198 struct lib80211_crypto_ops *lib80211_get_crypto_ops(const char *name)
199 {
200         struct lib80211_crypto_alg *alg;
201         unsigned long flags;
202
203         spin_lock_irqsave(&lib80211_crypto_lock, flags);
204         list_for_each_entry(alg, &lib80211_crypto_algs, list) {
205                 if (strcmp(alg->ops->name, name) == 0)
206                         goto found;
207         }
208         spin_unlock_irqrestore(&lib80211_crypto_lock, flags);
209         return NULL;
210
211       found:
212         spin_unlock_irqrestore(&lib80211_crypto_lock, flags);
213         return alg->ops;
214 }
215 EXPORT_SYMBOL(lib80211_get_crypto_ops);
216
217 static void *lib80211_crypt_null_init(int keyidx)
218 {
219         return (void *)1;
220 }
221
222 static void lib80211_crypt_null_deinit(void *priv)
223 {
224 }
225
226 static struct lib80211_crypto_ops lib80211_crypt_null = {
227         .name = "NULL",
228         .init = lib80211_crypt_null_init,
229         .deinit = lib80211_crypt_null_deinit,
230         .owner = THIS_MODULE,
231 };
232
233 static int __init lib80211_init(void)
234 {
235         printk(KERN_INFO DRV_NAME ": " DRV_DESCRIPTION "\n");
236         return lib80211_register_crypto_ops(&lib80211_crypt_null);
237 }
238
239 static void __exit lib80211_exit(void)
240 {
241         lib80211_unregister_crypto_ops(&lib80211_crypt_null);
242         BUG_ON(!list_empty(&lib80211_crypto_algs));
243 }
244
245 module_init(lib80211_init);
246 module_exit(lib80211_exit);