162306a36Sopenharmony_ci/* Orinoco MIC helpers
262306a36Sopenharmony_ci *
362306a36Sopenharmony_ci * See copyright notice in main.c
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci#include <linux/kernel.h>
662306a36Sopenharmony_ci#include <linux/string.h>
762306a36Sopenharmony_ci#include <linux/if_ether.h>
862306a36Sopenharmony_ci#include <linux/scatterlist.h>
962306a36Sopenharmony_ci#include <crypto/hash.h>
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include "orinoco.h"
1262306a36Sopenharmony_ci#include "mic.h"
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci/********************************************************************/
1562306a36Sopenharmony_ci/* Michael MIC crypto setup                                         */
1662306a36Sopenharmony_ci/********************************************************************/
1762306a36Sopenharmony_ciint orinoco_mic_init(struct orinoco_private *priv)
1862306a36Sopenharmony_ci{
1962306a36Sopenharmony_ci	priv->tx_tfm_mic = crypto_alloc_shash("michael_mic", 0, 0);
2062306a36Sopenharmony_ci	if (IS_ERR(priv->tx_tfm_mic)) {
2162306a36Sopenharmony_ci		printk(KERN_DEBUG "%s: could not allocate "
2262306a36Sopenharmony_ci		       "crypto API michael_mic\n", __func__);
2362306a36Sopenharmony_ci		priv->tx_tfm_mic = NULL;
2462306a36Sopenharmony_ci		return -ENOMEM;
2562306a36Sopenharmony_ci	}
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci	priv->rx_tfm_mic = crypto_alloc_shash("michael_mic", 0, 0);
2862306a36Sopenharmony_ci	if (IS_ERR(priv->rx_tfm_mic)) {
2962306a36Sopenharmony_ci		printk(KERN_DEBUG "%s: could not allocate "
3062306a36Sopenharmony_ci		       "crypto API michael_mic\n", __func__);
3162306a36Sopenharmony_ci		priv->rx_tfm_mic = NULL;
3262306a36Sopenharmony_ci		return -ENOMEM;
3362306a36Sopenharmony_ci	}
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci	return 0;
3662306a36Sopenharmony_ci}
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_civoid orinoco_mic_free(struct orinoco_private *priv)
3962306a36Sopenharmony_ci{
4062306a36Sopenharmony_ci	if (priv->tx_tfm_mic)
4162306a36Sopenharmony_ci		crypto_free_shash(priv->tx_tfm_mic);
4262306a36Sopenharmony_ci	if (priv->rx_tfm_mic)
4362306a36Sopenharmony_ci		crypto_free_shash(priv->rx_tfm_mic);
4462306a36Sopenharmony_ci}
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ciint orinoco_mic(struct crypto_shash *tfm_michael, u8 *key,
4762306a36Sopenharmony_ci		u8 *da, u8 *sa, u8 priority,
4862306a36Sopenharmony_ci		u8 *data, size_t data_len, u8 *mic)
4962306a36Sopenharmony_ci{
5062306a36Sopenharmony_ci	SHASH_DESC_ON_STACK(desc, tfm_michael);
5162306a36Sopenharmony_ci	u8 hdr[ETH_HLEN + 2]; /* size of header + padding */
5262306a36Sopenharmony_ci	int err;
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	if (tfm_michael == NULL) {
5562306a36Sopenharmony_ci		printk(KERN_WARNING "%s: tfm_michael == NULL\n", __func__);
5662306a36Sopenharmony_ci		return -1;
5762306a36Sopenharmony_ci	}
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	/* Copy header into buffer. We need the padding on the end zeroed */
6062306a36Sopenharmony_ci	memcpy(&hdr[0], da, ETH_ALEN);
6162306a36Sopenharmony_ci	memcpy(&hdr[ETH_ALEN], sa, ETH_ALEN);
6262306a36Sopenharmony_ci	hdr[ETH_ALEN * 2] = priority;
6362306a36Sopenharmony_ci	hdr[ETH_ALEN * 2 + 1] = 0;
6462306a36Sopenharmony_ci	hdr[ETH_ALEN * 2 + 2] = 0;
6562306a36Sopenharmony_ci	hdr[ETH_ALEN * 2 + 3] = 0;
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	desc->tfm = tfm_michael;
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	err = crypto_shash_setkey(tfm_michael, key, MIC_KEYLEN);
7062306a36Sopenharmony_ci	if (err)
7162306a36Sopenharmony_ci		return err;
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	err = crypto_shash_init(desc);
7462306a36Sopenharmony_ci	if (err)
7562306a36Sopenharmony_ci		return err;
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	err = crypto_shash_update(desc, hdr, sizeof(hdr));
7862306a36Sopenharmony_ci	if (err)
7962306a36Sopenharmony_ci		return err;
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	err = crypto_shash_update(desc, data, data_len);
8262306a36Sopenharmony_ci	if (err)
8362306a36Sopenharmony_ci		return err;
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	err = crypto_shash_final(desc, mic);
8662306a36Sopenharmony_ci	shash_desc_zero(desc);
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	return err;
8962306a36Sopenharmony_ci}
90