GNU Linux-libre 4.9.283-gnu1
[releases.git] / drivers / net / wireless / intersil / 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 <crypto/hash.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_shash("michael_mic", 0,
20                                               CRYPTO_ALG_ASYNC);
21         if (IS_ERR(priv->tx_tfm_mic)) {
22                 printk(KERN_DEBUG "orinoco_mic_init: could not allocate "
23                        "crypto API michael_mic\n");
24                 priv->tx_tfm_mic = NULL;
25                 return -ENOMEM;
26         }
27
28         priv->rx_tfm_mic = crypto_alloc_shash("michael_mic", 0,
29                                               CRYPTO_ALG_ASYNC);
30         if (IS_ERR(priv->rx_tfm_mic)) {
31                 printk(KERN_DEBUG "orinoco_mic_init: could not allocate "
32                        "crypto API michael_mic\n");
33                 priv->rx_tfm_mic = NULL;
34                 return -ENOMEM;
35         }
36
37         return 0;
38 }
39
40 void orinoco_mic_free(struct orinoco_private *priv)
41 {
42         if (priv->tx_tfm_mic)
43                 crypto_free_shash(priv->tx_tfm_mic);
44         if (priv->rx_tfm_mic)
45                 crypto_free_shash(priv->rx_tfm_mic);
46 }
47
48 int orinoco_mic(struct crypto_shash *tfm_michael, u8 *key,
49                 u8 *da, u8 *sa, u8 priority,
50                 u8 *data, size_t data_len, u8 *mic)
51 {
52         SHASH_DESC_ON_STACK(desc, tfm_michael);
53         u8 hdr[ETH_HLEN + 2]; /* size of header + padding */
54         int err;
55
56         if (tfm_michael == NULL) {
57                 printk(KERN_WARNING "orinoco_mic: tfm_michael == NULL\n");
58                 return -1;
59         }
60
61         /* Copy header into buffer. We need the padding on the end zeroed */
62         memcpy(&hdr[0], da, ETH_ALEN);
63         memcpy(&hdr[ETH_ALEN], sa, ETH_ALEN);
64         hdr[ETH_ALEN * 2] = priority;
65         hdr[ETH_ALEN * 2 + 1] = 0;
66         hdr[ETH_ALEN * 2 + 2] = 0;
67         hdr[ETH_ALEN * 2 + 3] = 0;
68
69         desc->tfm = tfm_michael;
70         desc->flags = 0;
71
72         err = crypto_shash_setkey(tfm_michael, key, MIC_KEYLEN);
73         if (err)
74                 return err;
75
76         err = crypto_shash_init(desc);
77         if (err)
78                 return err;
79
80         err = crypto_shash_update(desc, hdr, sizeof(hdr));
81         if (err)
82                 return err;
83
84         err = crypto_shash_update(desc, data, data_len);
85         if (err)
86                 return err;
87
88         err = crypto_shash_final(desc, mic);
89         shash_desc_zero(desc);
90
91         return err;
92 }