Merge git://git.infradead.org/mtd-2.6
[linux-2.6] / drivers / net / wireless / orinoco / mic.c
1 /* Orinoco MIC helpers
2  *
3  * See copyright notice in main.c
4  */
5 #include <linux/kernel.h>
6 #include <linux/string.h>
7 #include <linux/if_ether.h>
8 #include <linux/scatterlist.h>
9 #include <linux/crypto.h>
10
11 #include "orinoco.h"
12 #include "mic.h"
13
14 /********************************************************************/
15 /* Michael MIC crypto setup                                         */
16 /********************************************************************/
17 int orinoco_mic_init(struct orinoco_private *priv)
18 {
19         priv->tx_tfm_mic = crypto_alloc_hash("michael_mic", 0, 0);
20         if (IS_ERR(priv->tx_tfm_mic)) {
21                 printk(KERN_DEBUG "orinoco_mic_init: could not allocate "
22                        "crypto API michael_mic\n");
23                 priv->tx_tfm_mic = NULL;
24                 return -ENOMEM;
25         }
26
27         priv->rx_tfm_mic = crypto_alloc_hash("michael_mic", 0, 0);
28         if (IS_ERR(priv->rx_tfm_mic)) {
29                 printk(KERN_DEBUG "orinoco_mic_init: could not allocate "
30                        "crypto API michael_mic\n");
31                 priv->rx_tfm_mic = NULL;
32                 return -ENOMEM;
33         }
34
35         return 0;
36 }
37
38 void orinoco_mic_free(struct orinoco_private *priv)
39 {
40         if (priv->tx_tfm_mic)
41                 crypto_free_hash(priv->tx_tfm_mic);
42         if (priv->rx_tfm_mic)
43                 crypto_free_hash(priv->rx_tfm_mic);
44 }
45
46 int orinoco_mic(struct crypto_hash *tfm_michael, u8 *key,
47                 u8 *da, u8 *sa, u8 priority,
48                 u8 *data, size_t data_len, u8 *mic)
49 {
50         struct hash_desc desc;
51         struct scatterlist sg[2];
52         u8 hdr[ETH_HLEN + 2]; /* size of header + padding */
53
54         if (tfm_michael == NULL) {
55                 printk(KERN_WARNING "orinoco_mic: tfm_michael == NULL\n");
56                 return -1;
57         }
58
59         /* Copy header into buffer. We need the padding on the end zeroed */
60         memcpy(&hdr[0], da, ETH_ALEN);
61         memcpy(&hdr[ETH_ALEN], sa, ETH_ALEN);
62         hdr[ETH_ALEN*2] = priority;
63         hdr[ETH_ALEN*2+1] = 0;
64         hdr[ETH_ALEN*2+2] = 0;
65         hdr[ETH_ALEN*2+3] = 0;
66
67         /* Use scatter gather to MIC header and data in one go */
68         sg_init_table(sg, 2);
69         sg_set_buf(&sg[0], hdr, sizeof(hdr));
70         sg_set_buf(&sg[1], data, data_len);
71
72         if (crypto_hash_setkey(tfm_michael, key, MIC_KEYLEN))
73                 return -1;
74
75         desc.tfm = tfm_michael;
76         desc.flags = 0;
77         return crypto_hash_digest(&desc, sg, data_len + sizeof(hdr),
78                                   mic);
79 }