Linux kernel & device driver programming

Cross-Referenced Linux and Device Driver Code

[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]
Version: [ 2.6.11.8 ] [ 2.6.25 ] [ 2.6.25.8 ] [ 2.6.31.13 ] Architecture: [ i386 ]
  1 /*
  2  * Host AP crypt: host-based WEP encryption implementation for Host AP driver
  3  *
  4  * Copyright (c) 2002-2004, Jouni Malinen <jkmaline@cc.hut.fi>
  5  *
  6  * This program is free software; you can redistribute it and/or modify
  7  * it under the terms of the GNU General Public License version 2 as
  8  * published by the Free Software Foundation. See README and COPYING for
  9  * more details.
 10  */
 11 
 12 //#include <linux/config.h>
 13 #include <linux/version.h>
 14 #include <linux/module.h>
 15 #include <linux/init.h>
 16 #include <linux/slab.h>
 17 #include <linux/random.h>
 18 #include <linux/skbuff.h>
 19 #include <asm/string.h>
 20 
 21 #include "ieee80211.h"
 22 
 23 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,20))
 24 //#include "crypto_compat.h"
 25 #endif
 26 
 27 
 28 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
 29 #include "rtl_crypto.h"
 30 #else
 31 #include <linux/crypto.h>
 32 #endif
 33 
 34 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
 35     #include <asm/scatterlist.h>
 36 #else
 37     #include <linux/scatterlist.h>
 38 #endif
 39 //#include <asm/scatterlist.h>
 40 #include <linux/crc32.h>
 41 //
 42 /*
 43 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
 44 #include "rtl_crypto.h"
 45 #else
 46 #include <linux/crypto.h>
 47 #endif
 48 
 49 #include <asm/scatterlist.h>
 50 #include <linux/crc32.h>
 51 */
 52 MODULE_AUTHOR("Jouni Malinen");
 53 MODULE_DESCRIPTION("Host AP crypt: WEP");
 54 MODULE_LICENSE("GPL");
 55 #ifndef OPENSUSE_SLED
 56 #define OPENSUSE_SLED 0
 57 #endif
 58 
 59 struct prism2_wep_data {
 60         u32 iv;
 61 #define WEP_KEY_LEN 13
 62         u8 key[WEP_KEY_LEN + 1];
 63         u8 key_len;
 64         u8 key_idx;
 65 #if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) && (!OPENSUSE_SLED))
 66         struct crypto_tfm *tfm;
 67         #else
 68         struct crypto_blkcipher *tx_tfm;
 69         struct crypto_blkcipher *rx_tfm;
 70         #endif
 71 };
 72 
 73 
 74 static void * prism2_wep_init(int keyidx)
 75 {
 76         struct prism2_wep_data *priv;
 77 
 78         priv = kmalloc(sizeof(*priv), GFP_ATOMIC);
 79         if (priv == NULL)
 80                 goto fail;
 81         memset(priv, 0, sizeof(*priv));
 82         priv->key_idx = keyidx;
 83 
 84 #if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) && (!OPENSUSE_SLED))
 85         priv->tfm = crypto_alloc_tfm("arc4", 0);
 86         if (priv->tfm == NULL) {
 87                 printk(KERN_DEBUG "ieee80211_crypt_wep: could not allocate "
 88                        "crypto API arc4\n");
 89                 goto fail;
 90         }
 91         #else
 92         priv->tx_tfm = crypto_alloc_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC);
 93         if (IS_ERR(priv->tx_tfm)) {
 94                 printk(KERN_DEBUG "ieee80211_crypt_wep: could not allocate "
 95                        "crypto API arc4\n");
 96                 priv->tx_tfm = NULL;
 97                 goto fail;
 98         }
 99         priv->rx_tfm = crypto_alloc_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC);
100         if (IS_ERR(priv->rx_tfm)) {
101                 printk(KERN_DEBUG "ieee80211_crypt_wep: could not allocate "
102                        "crypto API arc4\n");
103                 priv->rx_tfm = NULL;
104                 goto fail;
105         }
106         #endif
107 
108         /* start WEP IV from a random value */
109         get_random_bytes(&priv->iv, 4);
110 
111         return priv;
112 
113 fail:
114 #if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) && (!OPENSUSE_SLED))
115         if (priv) {
116                 if (priv->tfm)
117                         crypto_free_tfm(priv->tfm);
118                 kfree(priv);
119         }
120         #else
121         if (priv) {
122                 if (priv->tx_tfm)
123                         crypto_free_blkcipher(priv->tx_tfm);
124                 if (priv->rx_tfm)
125                         crypto_free_blkcipher(priv->rx_tfm);
126                 kfree(priv);
127         }
128         #endif
129         return NULL;
130 }
131 
132 
133 static void prism2_wep_deinit(void *priv)
134 {
135         struct prism2_wep_data *_priv = priv;
136 #if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) && (!OPENSUSE_SLED))
137         if (_priv && _priv->tfm)
138                 crypto_free_tfm(_priv->tfm);
139         #else
140         if (_priv) {
141                 if (_priv->tx_tfm)
142                         crypto_free_blkcipher(_priv->tx_tfm);
143                 if (_priv->rx_tfm)
144                         crypto_free_blkcipher(_priv->rx_tfm);
145         }
146         #endif
147         kfree(priv);
148 }
149 
150 /* Perform WEP encryption on given skb that has at least 4 bytes of headroom
151  * for IV and 4 bytes of tailroom for ICV. Both IV and ICV will be transmitted,
152  * so the payload length increases with 8 bytes.
153  *
154  * WEP frame payload: IV + TX key idx, RC4(data), ICV = RC4(CRC32(data))
155  */
156 static int prism2_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
157 {
158         struct prism2_wep_data *wep = priv;
159         u32 klen, len;
160         u8 key[WEP_KEY_LEN + 3];
161         u8 *pos;
162         cb_desc *tcb_desc = (cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE);
163         #if((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)) || (OPENSUSE_SLED))
164         struct blkcipher_desc desc = {.tfm = wep->tx_tfm};
165         #endif
166         u32 crc;
167         u8 *icv;
168         struct scatterlist sg;
169         if (skb_headroom(skb) < 4 || skb_tailroom(skb) < 4 ||
170             skb->len < hdr_len)
171                 return -1;
172 
173         len = skb->len - hdr_len;
174         pos = skb_push(skb, 4);
175         memmove(pos, pos + 4, hdr_len);
176         pos += hdr_len;
177 
178         klen = 3 + wep->key_len;
179 
180         wep->iv++;
181 
182         /* Fluhrer, Mantin, and Shamir have reported weaknesses in the key
183          * scheduling algorithm of RC4. At least IVs (KeyByte + 3, 0xff, N)
184          * can be used to speedup attacks, so avoid using them. */
185         if ((wep->iv & 0xff00) == 0xff00) {
186                 u8 B = (wep->iv >> 16) & 0xff;
187                 if (B >= 3 && B < klen)
188                         wep->iv += 0x0100;
189         }
190 
191         /* Prepend 24-bit IV to RC4 key and TX frame */
192         *pos++ = key[0] = (wep->iv >> 16) & 0xff;
193         *pos++ = key[1] = (wep->iv >> 8) & 0xff;
194         *pos++ = key[2] = wep->iv & 0xff;
195         *pos++ = wep->key_idx << 6;
196 
197         /* Copy rest of the WEP key (the secret part) */
198         memcpy(key + 3, wep->key, wep->key_len);
199 
200         if (!tcb_desc->bHwSec)
201         {
202 
203                 /* Append little-endian CRC32 and encrypt it to produce ICV */
204         #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
205                 crc = ~crc32_le(~0, pos, len);
206         #else
207                 crc = ~ether_crc_le(len, pos);
208         #endif
209                 icv = skb_put(skb, 4);
210                 icv[0] = crc;
211                 icv[1] = crc >> 8;
212                 icv[2] = crc >> 16;
213                 icv[3] = crc >> 24;
214 
215 #if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) && (!OPENSUSE_SLED))
216                 crypto_cipher_setkey(wep->tfm, key, klen);
217                 sg.page = virt_to_page(pos);
218                 sg.offset = offset_in_page(pos);
219                 sg.length = len + 4;
220                 crypto_cipher_encrypt(wep->tfm, &sg, &sg, len + 4);
221                 return 0;
222         #else
223                 crypto_blkcipher_setkey(wep->tx_tfm, key, klen);
224         #if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24))
225                 sg.page = virt_to_page(pos);
226                 sg.offset = offset_in_page(pos);
227                 sg.length = len + 4;
228         #else
229                 sg_init_one(&sg, pos, len+4);
230         #endif
231                 return crypto_blkcipher_encrypt(&desc, &sg, &sg, len + 4);
232         #endif
233         }
234 
235         return 0;
236 }
237 
238 
239 /* Perform WEP decryption on given buffer. Buffer includes whole WEP part of
240  * the frame: IV (4 bytes), encrypted payload (including SNAP header),
241  * ICV (4 bytes). len includes both IV and ICV.
242  *
243  * Returns 0 if frame was decrypted successfully and ICV was correct and -1 on
244  * failure. If frame is OK, IV and ICV will be removed.
245  */
246 static int prism2_wep_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
247 {
248         struct prism2_wep_data *wep = priv;
249         u32  klen, plen;
250         u8 key[WEP_KEY_LEN + 3];
251         u8 keyidx, *pos;
252         cb_desc *tcb_desc = (cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE);
253         #if((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)) || (OPENSUSE_SLED))
254         struct blkcipher_desc desc = {.tfm = wep->rx_tfm};
255         #endif
256         u32 crc;
257         u8 icv[4];
258         struct scatterlist sg;
259         if (skb->len < hdr_len + 8)
260                 return -1;
261 
262         pos = skb->data + hdr_len;
263         key[0] = *pos++;
264         key[1] = *pos++;
265         key[2] = *pos++;
266         keyidx = *pos++ >> 6;
267         if (keyidx != wep->key_idx)
268                 return -1;
269 
270         klen = 3 + wep->key_len;
271 
272         /* Copy rest of the WEP key (the secret part) */
273         memcpy(key + 3, wep->key, wep->key_len);
274 
275         /* Apply RC4 to data and compute CRC32 over decrypted data */
276         plen = skb->len - hdr_len - 8;
277 
278         if (!tcb_desc->bHwSec)
279         {
280 #if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) && (!OPENSUSE_SLED))
281                 crypto_cipher_setkey(wep->tfm, key, klen);
282                 sg.page = virt_to_page(pos);
283                 sg.offset = offset_in_page(pos);
284                 sg.length = plen + 4;
285                 crypto_cipher_decrypt(wep->tfm, &sg, &sg, plen + 4);
286         #else
287                 crypto_blkcipher_setkey(wep->rx_tfm, key, klen);
288         #if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24))
289                 sg.page = virt_to_page(pos);
290                 sg.offset = offset_in_page(pos);
291                 sg.length = plen + 4;
292         #else
293                 sg_init_one(&sg, pos, plen+4);
294         #endif
295                 if (crypto_blkcipher_decrypt(&desc, &sg, &sg, plen + 4))
296                         return -7;
297         #endif
298         #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
299                 crc = ~crc32_le(~0, pos, plen);
300         #else
301                 crc = ~ether_crc_le(plen, pos);
302         #endif
303                 icv[0] = crc;
304                 icv[1] = crc >> 8;
305                 icv[2] = crc >> 16;
306                 icv[3] = crc >> 24;
307                 if (memcmp(icv, pos + plen, 4) != 0) {
308                         /* ICV mismatch - drop frame */
309                         return -2;
310                 }
311         }
312         /* Remove IV and ICV */
313         memmove(skb->data + 4, skb->data, hdr_len);
314         skb_pull(skb, 4);
315         skb_trim(skb, skb->len - 4);
316 
317         return 0;
318 }
319 
320 
321 static int prism2_wep_set_key(void *key, int len, u8 *seq, void *priv)
322 {
323         struct prism2_wep_data *wep = priv;
324 
325         if (len < 0 || len > WEP_KEY_LEN)
326                 return -1;
327 
328         memcpy(wep->key, key, len);
329         wep->key_len = len;
330 
331         return 0;
332 }
333 
334 
335 static int prism2_wep_get_key(void *key, int len, u8 *seq, void *priv)
336 {
337         struct prism2_wep_data *wep = priv;
338 
339         if (len < wep->key_len)
340                 return -1;
341 
342         memcpy(key, wep->key, wep->key_len);
343 
344         return wep->key_len;
345 }
346 
347 
348 static char * prism2_wep_print_stats(char *p, void *priv)
349 {
350         struct prism2_wep_data *wep = priv;
351         p += sprintf(p, "key[%d] alg=WEP len=%d\n",
352                      wep->key_idx, wep->key_len);
353         return p;
354 }
355 
356 
357 static struct ieee80211_crypto_ops ieee80211_crypt_wep = {
358         .name                   = "WEP",
359         .init                   = prism2_wep_init,
360         .deinit                 = prism2_wep_deinit,
361         .encrypt_mpdu           = prism2_wep_encrypt,
362         .decrypt_mpdu           = prism2_wep_decrypt,
363         .encrypt_msdu           = NULL,
364         .decrypt_msdu           = NULL,
365         .set_key                = prism2_wep_set_key,
366         .get_key                = prism2_wep_get_key,
367         .print_stats            = prism2_wep_print_stats,
368         .extra_prefix_len       = 4, /* IV */
369         .extra_postfix_len      = 4, /* ICV */
370         .owner                  = THIS_MODULE,
371 };
372 
373 
374 static int __init ieee80211_crypto_wep_init(void)
375 {
376         return ieee80211_register_crypto_ops(&ieee80211_crypt_wep);
377 }
378 
379 
380 static void __exit ieee80211_crypto_wep_exit(void)
381 {
382         ieee80211_unregister_crypto_ops(&ieee80211_crypt_wep);
383 }
384 
385 void ieee80211_wep_null(void)
386 {
387 //      printk("============>%s()\n", __FUNCTION__);
388         return;
389 }
390 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
391 EXPORT_SYMBOL(ieee80211_wep_null);
392 #else
393 EXPORT_SYMBOL_NOVERS(ieee80211_wep_null);
394 #endif
395 
396 module_init(ieee80211_crypto_wep_init);
397 module_exit(ieee80211_crypto_wep_exit);
398 
  This page was automatically generated by the LXR engine.