Contributors: 1
Author Tokens Token Proportion Commits Commit Proportion
Ansuel Smith 3875 100.00% 2 100.00%
Total 3875 2


// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright (C) 2019 - 2021
 *
 * Richard van Schagen <vschagen@icloud.com>
 * Christian Marangi <ansuelsmth@gmail.com
 */

#include <crypto/aes.h>
#include <crypto/ctr.h>
#include <crypto/hmac.h>
#include <crypto/sha1.h>
#include <crypto/sha2.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/scatterlist.h>

#include "eip93-cipher.h"
#include "eip93-hash.h"
#include "eip93-common.h"
#include "eip93-main.h"
#include "eip93-regs.h"

int eip93_parse_ctrl_stat_err(struct eip93_device *eip93, int err)
{
	u32 ext_err;

	if (!err)
		return 0;

	switch (err & ~EIP93_PE_CTRL_PE_EXT_ERR_CODE) {
	case EIP93_PE_CTRL_PE_AUTH_ERR:
	case EIP93_PE_CTRL_PE_PAD_ERR:
		return -EBADMSG;
	/* let software handle anti-replay errors */
	case EIP93_PE_CTRL_PE_SEQNUM_ERR:
		return 0;
	case EIP93_PE_CTRL_PE_EXT_ERR:
		break;
	default:
		dev_err(eip93->dev, "Unhandled error 0x%08x\n", err);
		return -EINVAL;
	}

	/* Parse additional ext errors */
	ext_err = FIELD_GET(EIP93_PE_CTRL_PE_EXT_ERR_CODE, err);
	switch (ext_err) {
	case EIP93_PE_CTRL_PE_EXT_ERR_BUS:
	case EIP93_PE_CTRL_PE_EXT_ERR_PROCESSING:
		return -EIO;
	case EIP93_PE_CTRL_PE_EXT_ERR_DESC_OWNER:
		return -EACCES;
	case EIP93_PE_CTRL_PE_EXT_ERR_INVALID_CRYPTO_OP:
	case EIP93_PE_CTRL_PE_EXT_ERR_INVALID_CRYPTO_ALGO:
	case EIP93_PE_CTRL_PE_EXT_ERR_SPI:
		return -EINVAL;
	case EIP93_PE_CTRL_PE_EXT_ERR_ZERO_LENGTH:
	case EIP93_PE_CTRL_PE_EXT_ERR_INVALID_PK_LENGTH:
	case EIP93_PE_CTRL_PE_EXT_ERR_BLOCK_SIZE_ERR:
		return -EBADMSG;
	default:
		dev_err(eip93->dev, "Unhandled ext error 0x%08x\n", ext_err);
		return -EINVAL;
	}
}

static void *eip93_ring_next_wptr(struct eip93_device *eip93,
				  struct eip93_desc_ring *ring)
{
	void *ptr = ring->write;

	if ((ring->write == ring->read - ring->offset) ||
	    (ring->read == ring->base && ring->write == ring->base_end))
		return ERR_PTR(-ENOMEM);

	if (ring->write == ring->base_end)
		ring->write = ring->base;
	else
		ring->write += ring->offset;

	return ptr;
}

static void *eip93_ring_next_rptr(struct eip93_device *eip93,
				  struct eip93_desc_ring *ring)
{
	void *ptr = ring->read;

	if (ring->write == ring->read)
		return ERR_PTR(-ENOENT);

	if (ring->read == ring->base_end)
		ring->read = ring->base;
	else
		ring->read += ring->offset;

	return ptr;
}

int eip93_put_descriptor(struct eip93_device *eip93,
			 struct eip93_descriptor *desc)
{
	struct eip93_descriptor *cdesc;
	struct eip93_descriptor *rdesc;

	rdesc = eip93_ring_next_wptr(eip93, &eip93->ring->rdr);
	if (IS_ERR(rdesc))
		return -ENOENT;

	cdesc = eip93_ring_next_wptr(eip93, &eip93->ring->cdr);
	if (IS_ERR(cdesc))
		return -ENOENT;

	memset(rdesc, 0, sizeof(struct eip93_descriptor));

	memcpy(cdesc, desc, sizeof(struct eip93_descriptor));

	return 0;
}

void *eip93_get_descriptor(struct eip93_device *eip93)
{
	struct eip93_descriptor *cdesc;
	void *ptr;

	cdesc = eip93_ring_next_rptr(eip93, &eip93->ring->cdr);
	if (IS_ERR(cdesc))
		return ERR_PTR(-ENOENT);

	memset(cdesc, 0, sizeof(struct eip93_descriptor));

	ptr = eip93_ring_next_rptr(eip93, &eip93->ring->rdr);
	if (IS_ERR(ptr))
		return ERR_PTR(-ENOENT);

	return ptr;
}

static void eip93_free_sg_copy(const int len, struct scatterlist **sg)
{
	if (!*sg || !len)
		return;

	free_pages((unsigned long)sg_virt(*sg), get_order(len));
	kfree(*sg);
	*sg = NULL;
}

static int eip93_make_sg_copy(struct scatterlist *src, struct scatterlist **dst,
			      const u32 len, const bool copy)
{
	void *pages;

	*dst = kmalloc(sizeof(**dst), GFP_KERNEL);
	if (!*dst)
		return -ENOMEM;

	pages = (void *)__get_free_pages(GFP_KERNEL | GFP_DMA,
					 get_order(len));
	if (!pages) {
		kfree(*dst);
		*dst = NULL;
		return -ENOMEM;
	}

	sg_init_table(*dst, 1);
	sg_set_buf(*dst, pages, len);

	/* copy only as requested */
	if (copy)
		sg_copy_to_buffer(src, sg_nents(src), pages, len);

	return 0;
}

static bool eip93_is_sg_aligned(struct scatterlist *sg, u32 len,
				const int blksize)
{
	int nents;

	for (nents = 0; sg; sg = sg_next(sg), ++nents) {
		if (!IS_ALIGNED(sg->offset, 4))
			return false;

		if (len <= sg->length) {
			if (!IS_ALIGNED(len, blksize))
				return false;

			return true;
		}

		if (!IS_ALIGNED(sg->length, blksize))
			return false;

		len -= sg->length;
	}
	return false;
}

int check_valid_request(struct eip93_cipher_reqctx *rctx)
{
	struct scatterlist *src = rctx->sg_src;
	struct scatterlist *dst = rctx->sg_dst;
	u32 textsize = rctx->textsize;
	u32 authsize = rctx->authsize;
	u32 blksize = rctx->blksize;
	u32 totlen_src = rctx->assoclen + rctx->textsize;
	u32 totlen_dst = rctx->assoclen + rctx->textsize;
	u32 copy_len;
	bool src_align, dst_align;
	int src_nents, dst_nents;
	int err = -EINVAL;

	if (!IS_CTR(rctx->flags)) {
		if (!IS_ALIGNED(textsize, blksize))
			return err;
	}

	if (authsize) {
		if (IS_ENCRYPT(rctx->flags))
			totlen_dst += authsize;
		else
			totlen_src += authsize;
	}

	src_nents = sg_nents_for_len(src, totlen_src);
	if (src_nents < 0)
		return src_nents;

	dst_nents = sg_nents_for_len(dst, totlen_dst);
	if (dst_nents < 0)
		return dst_nents;

	if (src == dst) {
		src_nents = max(src_nents, dst_nents);
		dst_nents = src_nents;
		if (unlikely((totlen_src || totlen_dst) && !src_nents))
			return err;

	} else {
		if (unlikely(totlen_src && !src_nents))
			return err;

		if (unlikely(totlen_dst && !dst_nents))
			return err;
	}

	if (authsize) {
		if (dst_nents == 1 && src_nents == 1) {
			src_align = eip93_is_sg_aligned(src, totlen_src, blksize);
			if (src ==  dst)
				dst_align = src_align;
			else
				dst_align = eip93_is_sg_aligned(dst, totlen_dst, blksize);
		} else {
			src_align = false;
			dst_align = false;
		}
	} else {
		src_align = eip93_is_sg_aligned(src, totlen_src, blksize);
		if (src == dst)
			dst_align = src_align;
		else
			dst_align = eip93_is_sg_aligned(dst, totlen_dst, blksize);
	}

	copy_len = max(totlen_src, totlen_dst);
	if (!src_align) {
		err = eip93_make_sg_copy(src, &rctx->sg_src, copy_len, true);
		if (err)
			return err;
	}

	if (!dst_align) {
		err = eip93_make_sg_copy(dst, &rctx->sg_dst, copy_len, false);
		if (err)
			return err;
	}

	src_nents = sg_nents_for_len(rctx->sg_src, totlen_src);
	if (src_nents < 0)
		return src_nents;

	dst_nents = sg_nents_for_len(rctx->sg_dst, totlen_dst);
	if (dst_nents < 0)
		return dst_nents;

	rctx->src_nents = src_nents;
	rctx->dst_nents = dst_nents;

	return 0;
}

/*
 * Set sa_record function:
 * Even sa_record is set to "0", keep " = 0" for readability.
 */
void eip93_set_sa_record(struct sa_record *sa_record, const unsigned int keylen,
			 const u32 flags)
{
	/* Reset cmd word */
	sa_record->sa_cmd0_word = 0;
	sa_record->sa_cmd1_word = 0;

	sa_record->sa_cmd0_word |= EIP93_SA_CMD_IV_FROM_STATE;
	if (!IS_ECB(flags))
		sa_record->sa_cmd0_word |= EIP93_SA_CMD_SAVE_IV;

	sa_record->sa_cmd0_word |= EIP93_SA_CMD_OP_BASIC;

	switch ((flags & EIP93_ALG_MASK)) {
	case EIP93_ALG_AES:
		sa_record->sa_cmd0_word |= EIP93_SA_CMD_CIPHER_AES;
		sa_record->sa_cmd1_word |= FIELD_PREP(EIP93_SA_CMD_AES_KEY_LENGTH,
						      keylen >> 3);
		break;
	case EIP93_ALG_3DES:
		sa_record->sa_cmd0_word |= EIP93_SA_CMD_CIPHER_3DES;
		break;
	case EIP93_ALG_DES:
		sa_record->sa_cmd0_word |= EIP93_SA_CMD_CIPHER_DES;
		break;
	default:
		sa_record->sa_cmd0_word |= EIP93_SA_CMD_CIPHER_NULL;
	}

	switch ((flags & EIP93_HASH_MASK)) {
	case EIP93_HASH_SHA256:
		sa_record->sa_cmd0_word |= EIP93_SA_CMD_HASH_SHA256;
		break;
	case EIP93_HASH_SHA224:
		sa_record->sa_cmd0_word |= EIP93_SA_CMD_HASH_SHA224;
		break;
	case EIP93_HASH_SHA1:
		sa_record->sa_cmd0_word |= EIP93_SA_CMD_HASH_SHA1;
		break;
	case EIP93_HASH_MD5:
		sa_record->sa_cmd0_word |= EIP93_SA_CMD_HASH_MD5;
		break;
	default:
		sa_record->sa_cmd0_word |= EIP93_SA_CMD_HASH_NULL;
	}

	sa_record->sa_cmd0_word |= EIP93_SA_CMD_PAD_ZERO;

	switch ((flags & EIP93_MODE_MASK)) {
	case EIP93_MODE_CBC:
		sa_record->sa_cmd1_word |= EIP93_SA_CMD_CHIPER_MODE_CBC;
		break;
	case EIP93_MODE_CTR:
		sa_record->sa_cmd1_word |= EIP93_SA_CMD_CHIPER_MODE_CTR;
		break;
	case EIP93_MODE_ECB:
		sa_record->sa_cmd1_word |= EIP93_SA_CMD_CHIPER_MODE_ECB;
		break;
	}

	sa_record->sa_cmd0_word |= EIP93_SA_CMD_DIGEST_3WORD;
	if (IS_HASH(flags)) {
		sa_record->sa_cmd1_word |= EIP93_SA_CMD_COPY_PAD;
		sa_record->sa_cmd1_word |= EIP93_SA_CMD_COPY_DIGEST;
	}

	if (IS_HMAC(flags)) {
		sa_record->sa_cmd1_word |= EIP93_SA_CMD_HMAC;
		sa_record->sa_cmd1_word |= EIP93_SA_CMD_COPY_HEADER;
	}

	sa_record->sa_spi = 0x0;
	sa_record->sa_seqmum_mask[0] = 0xFFFFFFFF;
	sa_record->sa_seqmum_mask[1] = 0x0;
}

/*
 * Poor mans Scatter/gather function:
 * Create a Descriptor for every segment to avoid copying buffers.
 * For performance better to wait for hardware to perform multiple DMA
 */
static int eip93_scatter_combine(struct eip93_device *eip93,
				 struct eip93_cipher_reqctx *rctx,
				 u32 datalen, u32 split, int offsetin)
{
	struct eip93_descriptor *cdesc = rctx->cdesc;
	struct scatterlist *sgsrc = rctx->sg_src;
	struct scatterlist *sgdst = rctx->sg_dst;
	unsigned int remainin = sg_dma_len(sgsrc);
	unsigned int remainout = sg_dma_len(sgdst);
	dma_addr_t saddr = sg_dma_address(sgsrc);
	dma_addr_t daddr = sg_dma_address(sgdst);
	dma_addr_t state_addr;
	u32 src_addr, dst_addr, len, n;
	bool nextin = false;
	bool nextout = false;
	int offsetout = 0;
	int err;

	if (IS_ECB(rctx->flags))
		rctx->sa_state_base = 0;

	if (split < datalen) {
		state_addr = rctx->sa_state_ctr_base;
		n = split;
	} else {
		state_addr = rctx->sa_state_base;
		n = datalen;
	}

	do {
		if (nextin) {
			sgsrc = sg_next(sgsrc);
			remainin = sg_dma_len(sgsrc);
			if (remainin == 0)
				continue;

			saddr = sg_dma_address(sgsrc);
			offsetin = 0;
			nextin = false;
		}

		if (nextout) {
			sgdst = sg_next(sgdst);
			remainout = sg_dma_len(sgdst);
			if (remainout == 0)
				continue;

			daddr = sg_dma_address(sgdst);
			offsetout = 0;
			nextout = false;
		}
		src_addr = saddr + offsetin;
		dst_addr = daddr + offsetout;

		if (remainin == remainout) {
			len = remainin;
			if (len > n) {
				len = n;
				remainin -= n;
				remainout -= n;
				offsetin += n;
				offsetout += n;
			} else {
				nextin = true;
				nextout = true;
			}
		} else if (remainin < remainout) {
			len = remainin;
			if (len > n) {
				len = n;
				remainin -= n;
				remainout -= n;
				offsetin += n;
				offsetout += n;
			} else {
				offsetout += len;
				remainout -= len;
				nextin = true;
			}
		} else {
			len = remainout;
			if (len > n) {
				len = n;
				remainin -= n;
				remainout -= n;
				offsetin += n;
				offsetout += n;
			} else {
				offsetin += len;
				remainin -= len;
				nextout = true;
			}
		}
		n -= len;

		cdesc->src_addr = src_addr;
		cdesc->dst_addr = dst_addr;
		cdesc->state_addr = state_addr;
		cdesc->pe_length_word = FIELD_PREP(EIP93_PE_LENGTH_HOST_PE_READY,
						   EIP93_PE_LENGTH_HOST_READY);
		cdesc->pe_length_word |= FIELD_PREP(EIP93_PE_LENGTH_LENGTH, len);

		if (n == 0) {
			n = datalen - split;
			split = datalen;
			state_addr = rctx->sa_state_base;
		}

		if (n == 0)
			cdesc->user_id |= FIELD_PREP(EIP93_PE_USER_ID_DESC_FLAGS,
						     EIP93_DESC_LAST);

		/*
		 * Loop - Delay - No need to rollback
		 * Maybe refine by slowing down at EIP93_RING_BUSY
		 */
again:
		scoped_guard(spinlock_irqsave, &eip93->ring->write_lock)
			err = eip93_put_descriptor(eip93, cdesc);
		if (err) {
			usleep_range(EIP93_RING_BUSY_DELAY,
				     EIP93_RING_BUSY_DELAY * 2);
			goto again;
		}
		/* Writing new descriptor count starts DMA action */
		writel(1, eip93->base + EIP93_REG_PE_CD_COUNT);
	} while (n);

	return -EINPROGRESS;
}

int eip93_send_req(struct crypto_async_request *async,
		   const u8 *reqiv, struct eip93_cipher_reqctx *rctx)
{
	struct eip93_crypto_ctx *ctx = crypto_tfm_ctx(async->tfm);
	struct eip93_device *eip93 = ctx->eip93;
	struct scatterlist *src = rctx->sg_src;
	struct scatterlist *dst = rctx->sg_dst;
	struct sa_state *sa_state;
	struct eip93_descriptor cdesc;
	u32 flags = rctx->flags;
	int offsetin = 0, err;
	u32 datalen = rctx->assoclen + rctx->textsize;
	u32 split = datalen;
	u32 start, end, ctr, blocks;
	u32 iv[AES_BLOCK_SIZE / sizeof(u32)];
	int crypto_async_idr;

	rctx->sa_state_ctr = NULL;
	rctx->sa_state = NULL;

	if (IS_ECB(flags))
		goto skip_iv;

	memcpy(iv, reqiv, rctx->ivsize);

	rctx->sa_state = kzalloc(sizeof(*rctx->sa_state), GFP_KERNEL);
	if (!rctx->sa_state)
		return -ENOMEM;

	sa_state = rctx->sa_state;

	memcpy(sa_state->state_iv, iv, rctx->ivsize);
	if (IS_RFC3686(flags)) {
		sa_state->state_iv[0] = ctx->sa_nonce;
		sa_state->state_iv[1] = iv[0];
		sa_state->state_iv[2] = iv[1];
		sa_state->state_iv[3] = (u32 __force)cpu_to_be32(0x1);
	} else if (!IS_HMAC(flags) && IS_CTR(flags)) {
		/* Compute data length. */
		blocks = DIV_ROUND_UP(rctx->textsize, AES_BLOCK_SIZE);
		ctr = be32_to_cpu((__be32 __force)iv[3]);
		/* Check 32bit counter overflow. */
		start = ctr;
		end = start + blocks - 1;
		if (end < start) {
			split = AES_BLOCK_SIZE * -start;
			/*
			 * Increment the counter manually to cope with
			 * the hardware counter overflow.
			 */
			iv[3] = 0xffffffff;
			crypto_inc((u8 *)iv, AES_BLOCK_SIZE);

			rctx->sa_state_ctr = kzalloc(sizeof(*rctx->sa_state_ctr),
						     GFP_KERNEL);
			if (!rctx->sa_state_ctr) {
				err = -ENOMEM;
				goto free_sa_state;
			}

			memcpy(rctx->sa_state_ctr->state_iv, reqiv, rctx->ivsize);
			memcpy(sa_state->state_iv, iv, rctx->ivsize);

			rctx->sa_state_ctr_base = dma_map_single(eip93->dev, rctx->sa_state_ctr,
								 sizeof(*rctx->sa_state_ctr),
								 DMA_TO_DEVICE);
			err = dma_mapping_error(eip93->dev, rctx->sa_state_ctr_base);
			if (err)
				goto free_sa_state_ctr;
		}
	}

	rctx->sa_state_base = dma_map_single(eip93->dev, rctx->sa_state,
					     sizeof(*rctx->sa_state), DMA_TO_DEVICE);
	err = dma_mapping_error(eip93->dev, rctx->sa_state_base);
	if (err)
		goto free_sa_state_ctr_dma;

skip_iv:

	cdesc.pe_ctrl_stat_word = FIELD_PREP(EIP93_PE_CTRL_PE_READY_DES_TRING_OWN,
					     EIP93_PE_CTRL_HOST_READY);
	cdesc.sa_addr = rctx->sa_record_base;
	cdesc.arc4_addr = 0;

	scoped_guard(spinlock_bh, &eip93->ring->idr_lock)
		crypto_async_idr = idr_alloc(&eip93->ring->crypto_async_idr, async, 0,
					     EIP93_RING_NUM - 1, GFP_ATOMIC);

	cdesc.user_id = FIELD_PREP(EIP93_PE_USER_ID_CRYPTO_IDR, (u16)crypto_async_idr) |
			FIELD_PREP(EIP93_PE_USER_ID_DESC_FLAGS, rctx->desc_flags);

	rctx->cdesc = &cdesc;

	/* map DMA_BIDIRECTIONAL to invalidate cache on destination
	 * implies __dma_cache_wback_inv
	 */
	if (!dma_map_sg(eip93->dev, dst, rctx->dst_nents, DMA_BIDIRECTIONAL)) {
		err = -ENOMEM;
		goto free_sa_state_ctr_dma;
	}

	if (src != dst &&
	    !dma_map_sg(eip93->dev, src, rctx->src_nents, DMA_TO_DEVICE)) {
		err = -ENOMEM;
		goto free_sg_dma;
	}

	return eip93_scatter_combine(eip93, rctx, datalen, split, offsetin);

free_sg_dma:
	dma_unmap_sg(eip93->dev, dst, rctx->dst_nents, DMA_BIDIRECTIONAL);
free_sa_state_ctr_dma:
	if (rctx->sa_state_ctr)
		dma_unmap_single(eip93->dev, rctx->sa_state_ctr_base,
				 sizeof(*rctx->sa_state_ctr),
				 DMA_TO_DEVICE);
free_sa_state_ctr:
	kfree(rctx->sa_state_ctr);
	if (rctx->sa_state)
		dma_unmap_single(eip93->dev, rctx->sa_state_base,
				 sizeof(*rctx->sa_state),
				 DMA_TO_DEVICE);
free_sa_state:
	kfree(rctx->sa_state);

	return err;
}

void eip93_unmap_dma(struct eip93_device *eip93, struct eip93_cipher_reqctx *rctx,
		     struct scatterlist *reqsrc, struct scatterlist *reqdst)
{
	u32 len = rctx->assoclen + rctx->textsize;
	u32 authsize = rctx->authsize;
	u32 flags = rctx->flags;
	u32 *otag;
	int i;

	if (rctx->sg_src == rctx->sg_dst) {
		dma_unmap_sg(eip93->dev, rctx->sg_dst, rctx->dst_nents,
			     DMA_BIDIRECTIONAL);
		goto process_tag;
	}

	dma_unmap_sg(eip93->dev, rctx->sg_src, rctx->src_nents,
		     DMA_TO_DEVICE);

	if (rctx->sg_src != reqsrc)
		eip93_free_sg_copy(len +  rctx->authsize, &rctx->sg_src);

	dma_unmap_sg(eip93->dev, rctx->sg_dst, rctx->dst_nents,
		     DMA_BIDIRECTIONAL);

	/* SHA tags need conversion from net-to-host */
process_tag:
	if (IS_DECRYPT(flags))
		authsize = 0;

	if (authsize) {
		if (!IS_HASH_MD5(flags)) {
			otag = sg_virt(rctx->sg_dst) + len;
			for (i = 0; i < (authsize / 4); i++)
				otag[i] = be32_to_cpu((__be32 __force)otag[i]);
		}
	}

	if (rctx->sg_dst != reqdst) {
		sg_copy_from_buffer(reqdst, sg_nents(reqdst),
				    sg_virt(rctx->sg_dst), len + authsize);
		eip93_free_sg_copy(len + rctx->authsize, &rctx->sg_dst);
	}
}

void eip93_handle_result(struct eip93_device *eip93, struct eip93_cipher_reqctx *rctx,
			 u8 *reqiv)
{
	if (rctx->sa_state_ctr)
		dma_unmap_single(eip93->dev, rctx->sa_state_ctr_base,
				 sizeof(*rctx->sa_state_ctr),
				 DMA_FROM_DEVICE);

	if (rctx->sa_state)
		dma_unmap_single(eip93->dev, rctx->sa_state_base,
				 sizeof(*rctx->sa_state),
				 DMA_FROM_DEVICE);

	if (!IS_ECB(rctx->flags))
		memcpy(reqiv, rctx->sa_state->state_iv, rctx->ivsize);

	kfree(rctx->sa_state_ctr);
	kfree(rctx->sa_state);
}

int eip93_hmac_setkey(u32 ctx_flags, const u8 *key, unsigned int keylen,
		      unsigned int hashlen, u8 *dest_ipad, u8 *dest_opad,
		      bool skip_ipad)
{
	u8 ipad[SHA256_BLOCK_SIZE], opad[SHA256_BLOCK_SIZE];
	struct crypto_ahash *ahash_tfm;
	struct eip93_hash_reqctx *rctx;
	struct ahash_request *req;
	DECLARE_CRYPTO_WAIT(wait);
	struct scatterlist sg[1];
	const char *alg_name;
	int i, ret;

	switch (ctx_flags & EIP93_HASH_MASK) {
	case EIP93_HASH_SHA256:
		alg_name = "sha256-eip93";
		break;
	case EIP93_HASH_SHA224:
		alg_name = "sha224-eip93";
		break;
	case EIP93_HASH_SHA1:
		alg_name = "sha1-eip93";
		break;
	case EIP93_HASH_MD5:
		alg_name = "md5-eip93";
		break;
	default: /* Impossible */
		return -EINVAL;
	}

	ahash_tfm = crypto_alloc_ahash(alg_name, 0, CRYPTO_ALG_ASYNC);
	if (IS_ERR(ahash_tfm))
		return PTR_ERR(ahash_tfm);

	req = ahash_request_alloc(ahash_tfm, GFP_ATOMIC);
	if (!req) {
		ret = -ENOMEM;
		goto err_ahash;
	}

	rctx = ahash_request_ctx_dma(req);
	crypto_init_wait(&wait);
	ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
				   crypto_req_done, &wait);

	/* Hash the key if > SHA256_BLOCK_SIZE */
	if (keylen > SHA256_BLOCK_SIZE) {
		sg_init_one(&sg[0], key, keylen);

		ahash_request_set_crypt(req, sg, ipad, keylen);
		ret = crypto_wait_req(crypto_ahash_digest(req), &wait);
		if (ret)
			goto err_req;

		keylen = hashlen;
	} else {
		memcpy(ipad, key, keylen);
	}

	/* Copy to opad */
	memset(ipad + keylen, 0, SHA256_BLOCK_SIZE - keylen);
	memcpy(opad, ipad, SHA256_BLOCK_SIZE);

	/* Pad with HMAC constants */
	for (i = 0; i < SHA256_BLOCK_SIZE; i++) {
		ipad[i] ^= HMAC_IPAD_VALUE;
		opad[i] ^= HMAC_OPAD_VALUE;
	}

	if (skip_ipad) {
		memcpy(dest_ipad, ipad, SHA256_BLOCK_SIZE);
	} else {
		/* Hash ipad */
		sg_init_one(&sg[0], ipad, SHA256_BLOCK_SIZE);
		ahash_request_set_crypt(req, sg, dest_ipad, SHA256_BLOCK_SIZE);
		ret = crypto_ahash_init(req);
		if (ret)
			goto err_req;

		/* Disable HASH_FINALIZE for ipad hash */
		rctx->partial_hash = true;

		ret = crypto_wait_req(crypto_ahash_finup(req), &wait);
		if (ret)
			goto err_req;
	}

	/* Hash opad */
	sg_init_one(&sg[0], opad, SHA256_BLOCK_SIZE);
	ahash_request_set_crypt(req, sg, dest_opad, SHA256_BLOCK_SIZE);
	ret = crypto_ahash_init(req);
	if (ret)
		goto err_req;

	/* Disable HASH_FINALIZE for opad hash */
	rctx->partial_hash = true;

	ret = crypto_wait_req(crypto_ahash_finup(req), &wait);
	if (ret)
		goto err_req;

	if (!IS_HASH_MD5(ctx_flags)) {
		for (i = 0; i < SHA256_DIGEST_SIZE / sizeof(u32); i++) {
			u32 *ipad_hash = (u32 *)dest_ipad;
			u32 *opad_hash = (u32 *)dest_opad;

			if (!skip_ipad)
				ipad_hash[i] = (u32 __force)cpu_to_be32(ipad_hash[i]);
			opad_hash[i] = (u32 __force)cpu_to_be32(opad_hash[i]);
		}
	}

err_req:
	ahash_request_free(req);
err_ahash:
	crypto_free_ahash(ahash_tfm);

	return ret;
}