14adb474b6b7e26e1318acab5e98864aa78f9b233David Kilroy/* Orinoco MIC helpers
24adb474b6b7e26e1318acab5e98864aa78f9b233David Kilroy *
34adb474b6b7e26e1318acab5e98864aa78f9b233David Kilroy * See copyright notice in main.c
44adb474b6b7e26e1318acab5e98864aa78f9b233David Kilroy */
54adb474b6b7e26e1318acab5e98864aa78f9b233David Kilroy#include <linux/kernel.h>
64adb474b6b7e26e1318acab5e98864aa78f9b233David Kilroy#include <linux/string.h>
74adb474b6b7e26e1318acab5e98864aa78f9b233David Kilroy#include <linux/if_ether.h>
84adb474b6b7e26e1318acab5e98864aa78f9b233David Kilroy#include <linux/scatterlist.h>
94adb474b6b7e26e1318acab5e98864aa78f9b233David Kilroy#include <linux/crypto.h>
104adb474b6b7e26e1318acab5e98864aa78f9b233David Kilroy
114adb474b6b7e26e1318acab5e98864aa78f9b233David Kilroy#include "orinoco.h"
124adb474b6b7e26e1318acab5e98864aa78f9b233David Kilroy#include "mic.h"
134adb474b6b7e26e1318acab5e98864aa78f9b233David Kilroy
144adb474b6b7e26e1318acab5e98864aa78f9b233David Kilroy/********************************************************************/
154adb474b6b7e26e1318acab5e98864aa78f9b233David Kilroy/* Michael MIC crypto setup                                         */
164adb474b6b7e26e1318acab5e98864aa78f9b233David Kilroy/********************************************************************/
174adb474b6b7e26e1318acab5e98864aa78f9b233David Kilroyint orinoco_mic_init(struct orinoco_private *priv)
184adb474b6b7e26e1318acab5e98864aa78f9b233David Kilroy{
194adb474b6b7e26e1318acab5e98864aa78f9b233David Kilroy	priv->tx_tfm_mic = crypto_alloc_hash("michael_mic", 0, 0);
204adb474b6b7e26e1318acab5e98864aa78f9b233David Kilroy	if (IS_ERR(priv->tx_tfm_mic)) {
214adb474b6b7e26e1318acab5e98864aa78f9b233David Kilroy		printk(KERN_DEBUG "orinoco_mic_init: could not allocate "
224adb474b6b7e26e1318acab5e98864aa78f9b233David Kilroy		       "crypto API michael_mic\n");
234adb474b6b7e26e1318acab5e98864aa78f9b233David Kilroy		priv->tx_tfm_mic = NULL;
244adb474b6b7e26e1318acab5e98864aa78f9b233David Kilroy		return -ENOMEM;
254adb474b6b7e26e1318acab5e98864aa78f9b233David Kilroy	}
264adb474b6b7e26e1318acab5e98864aa78f9b233David Kilroy
274adb474b6b7e26e1318acab5e98864aa78f9b233David Kilroy	priv->rx_tfm_mic = crypto_alloc_hash("michael_mic", 0, 0);
284adb474b6b7e26e1318acab5e98864aa78f9b233David Kilroy	if (IS_ERR(priv->rx_tfm_mic)) {
294adb474b6b7e26e1318acab5e98864aa78f9b233David Kilroy		printk(KERN_DEBUG "orinoco_mic_init: could not allocate "
304adb474b6b7e26e1318acab5e98864aa78f9b233David Kilroy		       "crypto API michael_mic\n");
314adb474b6b7e26e1318acab5e98864aa78f9b233David Kilroy		priv->rx_tfm_mic = NULL;
324adb474b6b7e26e1318acab5e98864aa78f9b233David Kilroy		return -ENOMEM;
334adb474b6b7e26e1318acab5e98864aa78f9b233David Kilroy	}
344adb474b6b7e26e1318acab5e98864aa78f9b233David Kilroy
354adb474b6b7e26e1318acab5e98864aa78f9b233David Kilroy	return 0;
364adb474b6b7e26e1318acab5e98864aa78f9b233David Kilroy}
374adb474b6b7e26e1318acab5e98864aa78f9b233David Kilroy
384adb474b6b7e26e1318acab5e98864aa78f9b233David Kilroyvoid orinoco_mic_free(struct orinoco_private *priv)
394adb474b6b7e26e1318acab5e98864aa78f9b233David Kilroy{
404adb474b6b7e26e1318acab5e98864aa78f9b233David Kilroy	if (priv->tx_tfm_mic)
414adb474b6b7e26e1318acab5e98864aa78f9b233David Kilroy		crypto_free_hash(priv->tx_tfm_mic);
424adb474b6b7e26e1318acab5e98864aa78f9b233David Kilroy	if (priv->rx_tfm_mic)
434adb474b6b7e26e1318acab5e98864aa78f9b233David Kilroy		crypto_free_hash(priv->rx_tfm_mic);
444adb474b6b7e26e1318acab5e98864aa78f9b233David Kilroy}
454adb474b6b7e26e1318acab5e98864aa78f9b233David Kilroy
464adb474b6b7e26e1318acab5e98864aa78f9b233David Kilroyint orinoco_mic(struct crypto_hash *tfm_michael, u8 *key,
474adb474b6b7e26e1318acab5e98864aa78f9b233David Kilroy		u8 *da, u8 *sa, u8 priority,
484adb474b6b7e26e1318acab5e98864aa78f9b233David Kilroy		u8 *data, size_t data_len, u8 *mic)
494adb474b6b7e26e1318acab5e98864aa78f9b233David Kilroy{
504adb474b6b7e26e1318acab5e98864aa78f9b233David Kilroy	struct hash_desc desc;
514adb474b6b7e26e1318acab5e98864aa78f9b233David Kilroy	struct scatterlist sg[2];
524adb474b6b7e26e1318acab5e98864aa78f9b233David Kilroy	u8 hdr[ETH_HLEN + 2]; /* size of header + padding */
534adb474b6b7e26e1318acab5e98864aa78f9b233David Kilroy
544adb474b6b7e26e1318acab5e98864aa78f9b233David Kilroy	if (tfm_michael == NULL) {
554adb474b6b7e26e1318acab5e98864aa78f9b233David Kilroy		printk(KERN_WARNING "orinoco_mic: tfm_michael == NULL\n");
564adb474b6b7e26e1318acab5e98864aa78f9b233David Kilroy		return -1;
574adb474b6b7e26e1318acab5e98864aa78f9b233David Kilroy	}
584adb474b6b7e26e1318acab5e98864aa78f9b233David Kilroy
594adb474b6b7e26e1318acab5e98864aa78f9b233David Kilroy	/* Copy header into buffer. We need the padding on the end zeroed */
604adb474b6b7e26e1318acab5e98864aa78f9b233David Kilroy	memcpy(&hdr[0], da, ETH_ALEN);
614adb474b6b7e26e1318acab5e98864aa78f9b233David Kilroy	memcpy(&hdr[ETH_ALEN], sa, ETH_ALEN);
62933d594313a5928ffc5325d7bbb6e2383d79622ePavel Roskin	hdr[ETH_ALEN * 2] = priority;
63933d594313a5928ffc5325d7bbb6e2383d79622ePavel Roskin	hdr[ETH_ALEN * 2 + 1] = 0;
64933d594313a5928ffc5325d7bbb6e2383d79622ePavel Roskin	hdr[ETH_ALEN * 2 + 2] = 0;
65933d594313a5928ffc5325d7bbb6e2383d79622ePavel Roskin	hdr[ETH_ALEN * 2 + 3] = 0;
664adb474b6b7e26e1318acab5e98864aa78f9b233David Kilroy
674adb474b6b7e26e1318acab5e98864aa78f9b233David Kilroy	/* Use scatter gather to MIC header and data in one go */
684adb474b6b7e26e1318acab5e98864aa78f9b233David Kilroy	sg_init_table(sg, 2);
694adb474b6b7e26e1318acab5e98864aa78f9b233David Kilroy	sg_set_buf(&sg[0], hdr, sizeof(hdr));
704adb474b6b7e26e1318acab5e98864aa78f9b233David Kilroy	sg_set_buf(&sg[1], data, data_len);
714adb474b6b7e26e1318acab5e98864aa78f9b233David Kilroy
724adb474b6b7e26e1318acab5e98864aa78f9b233David Kilroy	if (crypto_hash_setkey(tfm_michael, key, MIC_KEYLEN))
734adb474b6b7e26e1318acab5e98864aa78f9b233David Kilroy		return -1;
744adb474b6b7e26e1318acab5e98864aa78f9b233David Kilroy
754adb474b6b7e26e1318acab5e98864aa78f9b233David Kilroy	desc.tfm = tfm_michael;
764adb474b6b7e26e1318acab5e98864aa78f9b233David Kilroy	desc.flags = 0;
774adb474b6b7e26e1318acab5e98864aa78f9b233David Kilroy	return crypto_hash_digest(&desc, sg, data_len + sizeof(hdr),
784adb474b6b7e26e1318acab5e98864aa78f9b233David Kilroy				  mic);
794adb474b6b7e26e1318acab5e98864aa78f9b233David Kilroy}
80