19739f5f9SChristian Marangi // SPDX-License-Identifier: GPL-2.0 29739f5f9SChristian Marangi /* 39739f5f9SChristian Marangi * Copyright (C) 2019 - 2021 49739f5f9SChristian Marangi * 59739f5f9SChristian Marangi * Richard van Schagen <vschagen@icloud.com> 69739f5f9SChristian Marangi * Christian Marangi <ansuelsmth@gmail.com 79739f5f9SChristian Marangi */ 89739f5f9SChristian Marangi 99739f5f9SChristian Marangi #include <crypto/aes.h> 109739f5f9SChristian Marangi #include <crypto/ctr.h> 119739f5f9SChristian Marangi #include <crypto/hmac.h> 129739f5f9SChristian Marangi #include <crypto/sha1.h> 139739f5f9SChristian Marangi #include <crypto/sha2.h> 149739f5f9SChristian Marangi #include <linux/kernel.h> 159739f5f9SChristian Marangi #include <linux/delay.h> 169739f5f9SChristian Marangi #include <linux/dma-mapping.h> 179739f5f9SChristian Marangi #include <linux/scatterlist.h> 189739f5f9SChristian Marangi 199739f5f9SChristian Marangi #include "eip93-cipher.h" 209739f5f9SChristian Marangi #include "eip93-hash.h" 219739f5f9SChristian Marangi #include "eip93-common.h" 229739f5f9SChristian Marangi #include "eip93-main.h" 239739f5f9SChristian Marangi #include "eip93-regs.h" 249739f5f9SChristian Marangi 259739f5f9SChristian Marangi int eip93_parse_ctrl_stat_err(struct eip93_device *eip93, int err) 269739f5f9SChristian Marangi { 279739f5f9SChristian Marangi u32 ext_err; 289739f5f9SChristian Marangi 299739f5f9SChristian Marangi if (!err) 309739f5f9SChristian Marangi return 0; 319739f5f9SChristian Marangi 329739f5f9SChristian Marangi switch (err & ~EIP93_PE_CTRL_PE_EXT_ERR_CODE) { 339739f5f9SChristian Marangi case EIP93_PE_CTRL_PE_AUTH_ERR: 349739f5f9SChristian Marangi case EIP93_PE_CTRL_PE_PAD_ERR: 359739f5f9SChristian Marangi return -EBADMSG; 369739f5f9SChristian Marangi /* let software handle anti-replay errors */ 379739f5f9SChristian Marangi case EIP93_PE_CTRL_PE_SEQNUM_ERR: 389739f5f9SChristian Marangi return 0; 399739f5f9SChristian Marangi case EIP93_PE_CTRL_PE_EXT_ERR: 409739f5f9SChristian Marangi break; 419739f5f9SChristian Marangi default: 429739f5f9SChristian Marangi dev_err(eip93->dev, "Unhandled error 0x%08x\n", err); 439739f5f9SChristian Marangi return -EINVAL; 449739f5f9SChristian Marangi } 459739f5f9SChristian Marangi 469739f5f9SChristian Marangi /* Parse additional ext errors */ 479739f5f9SChristian Marangi ext_err = FIELD_GET(EIP93_PE_CTRL_PE_EXT_ERR_CODE, err); 489739f5f9SChristian Marangi switch (ext_err) { 499739f5f9SChristian Marangi case EIP93_PE_CTRL_PE_EXT_ERR_BUS: 509739f5f9SChristian Marangi case EIP93_PE_CTRL_PE_EXT_ERR_PROCESSING: 519739f5f9SChristian Marangi return -EIO; 529739f5f9SChristian Marangi case EIP93_PE_CTRL_PE_EXT_ERR_DESC_OWNER: 539739f5f9SChristian Marangi return -EACCES; 549739f5f9SChristian Marangi case EIP93_PE_CTRL_PE_EXT_ERR_INVALID_CRYPTO_OP: 559739f5f9SChristian Marangi case EIP93_PE_CTRL_PE_EXT_ERR_INVALID_CRYPTO_ALGO: 569739f5f9SChristian Marangi case EIP93_PE_CTRL_PE_EXT_ERR_SPI: 579739f5f9SChristian Marangi return -EINVAL; 589739f5f9SChristian Marangi case EIP93_PE_CTRL_PE_EXT_ERR_ZERO_LENGTH: 599739f5f9SChristian Marangi case EIP93_PE_CTRL_PE_EXT_ERR_INVALID_PK_LENGTH: 609739f5f9SChristian Marangi case EIP93_PE_CTRL_PE_EXT_ERR_BLOCK_SIZE_ERR: 619739f5f9SChristian Marangi return -EBADMSG; 629739f5f9SChristian Marangi default: 639739f5f9SChristian Marangi dev_err(eip93->dev, "Unhandled ext error 0x%08x\n", ext_err); 649739f5f9SChristian Marangi return -EINVAL; 659739f5f9SChristian Marangi } 669739f5f9SChristian Marangi } 679739f5f9SChristian Marangi 689739f5f9SChristian Marangi static void *eip93_ring_next_wptr(struct eip93_device *eip93, 699739f5f9SChristian Marangi struct eip93_desc_ring *ring) 709739f5f9SChristian Marangi { 719739f5f9SChristian Marangi void *ptr = ring->write; 729739f5f9SChristian Marangi 739739f5f9SChristian Marangi if ((ring->write == ring->read - ring->offset) || 749739f5f9SChristian Marangi (ring->read == ring->base && ring->write == ring->base_end)) 759739f5f9SChristian Marangi return ERR_PTR(-ENOMEM); 769739f5f9SChristian Marangi 779739f5f9SChristian Marangi if (ring->write == ring->base_end) 789739f5f9SChristian Marangi ring->write = ring->base; 799739f5f9SChristian Marangi else 809739f5f9SChristian Marangi ring->write += ring->offset; 819739f5f9SChristian Marangi 829739f5f9SChristian Marangi return ptr; 839739f5f9SChristian Marangi } 849739f5f9SChristian Marangi 859739f5f9SChristian Marangi static void *eip93_ring_next_rptr(struct eip93_device *eip93, 869739f5f9SChristian Marangi struct eip93_desc_ring *ring) 879739f5f9SChristian Marangi { 889739f5f9SChristian Marangi void *ptr = ring->read; 899739f5f9SChristian Marangi 909739f5f9SChristian Marangi if (ring->write == ring->read) 919739f5f9SChristian Marangi return ERR_PTR(-ENOENT); 929739f5f9SChristian Marangi 939739f5f9SChristian Marangi if (ring->read == ring->base_end) 949739f5f9SChristian Marangi ring->read = ring->base; 959739f5f9SChristian Marangi else 969739f5f9SChristian Marangi ring->read += ring->offset; 979739f5f9SChristian Marangi 989739f5f9SChristian Marangi return ptr; 999739f5f9SChristian Marangi } 1009739f5f9SChristian Marangi 1019739f5f9SChristian Marangi int eip93_put_descriptor(struct eip93_device *eip93, 1029739f5f9SChristian Marangi struct eip93_descriptor *desc) 1039739f5f9SChristian Marangi { 1049739f5f9SChristian Marangi struct eip93_descriptor *cdesc; 1059739f5f9SChristian Marangi struct eip93_descriptor *rdesc; 1069739f5f9SChristian Marangi 1079739f5f9SChristian Marangi rdesc = eip93_ring_next_wptr(eip93, &eip93->ring->rdr); 1089739f5f9SChristian Marangi if (IS_ERR(rdesc)) 1099739f5f9SChristian Marangi return -ENOENT; 1109739f5f9SChristian Marangi 1119739f5f9SChristian Marangi cdesc = eip93_ring_next_wptr(eip93, &eip93->ring->cdr); 1129739f5f9SChristian Marangi if (IS_ERR(cdesc)) 1139739f5f9SChristian Marangi return -ENOENT; 1149739f5f9SChristian Marangi 1159739f5f9SChristian Marangi memset(rdesc, 0, sizeof(struct eip93_descriptor)); 1169739f5f9SChristian Marangi 1179739f5f9SChristian Marangi memcpy(cdesc, desc, sizeof(struct eip93_descriptor)); 1189739f5f9SChristian Marangi 1199739f5f9SChristian Marangi return 0; 1209739f5f9SChristian Marangi } 1219739f5f9SChristian Marangi 1229739f5f9SChristian Marangi void *eip93_get_descriptor(struct eip93_device *eip93) 1239739f5f9SChristian Marangi { 1249739f5f9SChristian Marangi struct eip93_descriptor *cdesc; 1259739f5f9SChristian Marangi void *ptr; 1269739f5f9SChristian Marangi 1279739f5f9SChristian Marangi cdesc = eip93_ring_next_rptr(eip93, &eip93->ring->cdr); 1289739f5f9SChristian Marangi if (IS_ERR(cdesc)) 1299739f5f9SChristian Marangi return ERR_PTR(-ENOENT); 1309739f5f9SChristian Marangi 1319739f5f9SChristian Marangi memset(cdesc, 0, sizeof(struct eip93_descriptor)); 1329739f5f9SChristian Marangi 1339739f5f9SChristian Marangi ptr = eip93_ring_next_rptr(eip93, &eip93->ring->rdr); 1349739f5f9SChristian Marangi if (IS_ERR(ptr)) 1359739f5f9SChristian Marangi return ERR_PTR(-ENOENT); 1369739f5f9SChristian Marangi 1379739f5f9SChristian Marangi return ptr; 1389739f5f9SChristian Marangi } 1399739f5f9SChristian Marangi 1409739f5f9SChristian Marangi static void eip93_free_sg_copy(const int len, struct scatterlist **sg) 1419739f5f9SChristian Marangi { 1429739f5f9SChristian Marangi if (!*sg || !len) 1439739f5f9SChristian Marangi return; 1449739f5f9SChristian Marangi 1459739f5f9SChristian Marangi free_pages((unsigned long)sg_virt(*sg), get_order(len)); 1469739f5f9SChristian Marangi kfree(*sg); 1479739f5f9SChristian Marangi *sg = NULL; 1489739f5f9SChristian Marangi } 1499739f5f9SChristian Marangi 1509739f5f9SChristian Marangi static int eip93_make_sg_copy(struct scatterlist *src, struct scatterlist **dst, 1519739f5f9SChristian Marangi const u32 len, const bool copy) 1529739f5f9SChristian Marangi { 1539739f5f9SChristian Marangi void *pages; 1549739f5f9SChristian Marangi 1559739f5f9SChristian Marangi *dst = kmalloc(sizeof(**dst), GFP_KERNEL); 1569739f5f9SChristian Marangi if (!*dst) 1579739f5f9SChristian Marangi return -ENOMEM; 1589739f5f9SChristian Marangi 1599739f5f9SChristian Marangi pages = (void *)__get_free_pages(GFP_KERNEL | GFP_DMA, 1609739f5f9SChristian Marangi get_order(len)); 1619739f5f9SChristian Marangi if (!pages) { 1629739f5f9SChristian Marangi kfree(*dst); 1639739f5f9SChristian Marangi *dst = NULL; 1649739f5f9SChristian Marangi return -ENOMEM; 1659739f5f9SChristian Marangi } 1669739f5f9SChristian Marangi 1679739f5f9SChristian Marangi sg_init_table(*dst, 1); 1689739f5f9SChristian Marangi sg_set_buf(*dst, pages, len); 1699739f5f9SChristian Marangi 1709739f5f9SChristian Marangi /* copy only as requested */ 1719739f5f9SChristian Marangi if (copy) 1729739f5f9SChristian Marangi sg_copy_to_buffer(src, sg_nents(src), pages, len); 1739739f5f9SChristian Marangi 1749739f5f9SChristian Marangi return 0; 1759739f5f9SChristian Marangi } 1769739f5f9SChristian Marangi 1779739f5f9SChristian Marangi static bool eip93_is_sg_aligned(struct scatterlist *sg, u32 len, 1789739f5f9SChristian Marangi const int blksize) 1799739f5f9SChristian Marangi { 1809739f5f9SChristian Marangi int nents; 1819739f5f9SChristian Marangi 1829739f5f9SChristian Marangi for (nents = 0; sg; sg = sg_next(sg), ++nents) { 1839739f5f9SChristian Marangi if (!IS_ALIGNED(sg->offset, 4)) 1849739f5f9SChristian Marangi return false; 1859739f5f9SChristian Marangi 1869739f5f9SChristian Marangi if (len <= sg->length) { 1879739f5f9SChristian Marangi if (!IS_ALIGNED(len, blksize)) 1889739f5f9SChristian Marangi return false; 1899739f5f9SChristian Marangi 1909739f5f9SChristian Marangi return true; 1919739f5f9SChristian Marangi } 1929739f5f9SChristian Marangi 1939739f5f9SChristian Marangi if (!IS_ALIGNED(sg->length, blksize)) 1949739f5f9SChristian Marangi return false; 1959739f5f9SChristian Marangi 1969739f5f9SChristian Marangi len -= sg->length; 1979739f5f9SChristian Marangi } 1989739f5f9SChristian Marangi return false; 1999739f5f9SChristian Marangi } 2009739f5f9SChristian Marangi 2019739f5f9SChristian Marangi int check_valid_request(struct eip93_cipher_reqctx *rctx) 2029739f5f9SChristian Marangi { 2039739f5f9SChristian Marangi struct scatterlist *src = rctx->sg_src; 2049739f5f9SChristian Marangi struct scatterlist *dst = rctx->sg_dst; 2059739f5f9SChristian Marangi u32 textsize = rctx->textsize; 2069739f5f9SChristian Marangi u32 authsize = rctx->authsize; 2079739f5f9SChristian Marangi u32 blksize = rctx->blksize; 2089739f5f9SChristian Marangi u32 totlen_src = rctx->assoclen + rctx->textsize; 2099739f5f9SChristian Marangi u32 totlen_dst = rctx->assoclen + rctx->textsize; 2109739f5f9SChristian Marangi u32 copy_len; 2119739f5f9SChristian Marangi bool src_align, dst_align; 212*21746054SChristian Marangi int src_nents, dst_nents; 2139739f5f9SChristian Marangi int err = -EINVAL; 2149739f5f9SChristian Marangi 2159739f5f9SChristian Marangi if (!IS_CTR(rctx->flags)) { 2169739f5f9SChristian Marangi if (!IS_ALIGNED(textsize, blksize)) 2179739f5f9SChristian Marangi return err; 2189739f5f9SChristian Marangi } 2199739f5f9SChristian Marangi 2209739f5f9SChristian Marangi if (authsize) { 2219739f5f9SChristian Marangi if (IS_ENCRYPT(rctx->flags)) 2229739f5f9SChristian Marangi totlen_dst += authsize; 2239739f5f9SChristian Marangi else 2249739f5f9SChristian Marangi totlen_src += authsize; 2259739f5f9SChristian Marangi } 2269739f5f9SChristian Marangi 2279739f5f9SChristian Marangi src_nents = sg_nents_for_len(src, totlen_src); 228*21746054SChristian Marangi if (src_nents < 0) 229*21746054SChristian Marangi return src_nents; 230*21746054SChristian Marangi 2319739f5f9SChristian Marangi dst_nents = sg_nents_for_len(dst, totlen_dst); 232*21746054SChristian Marangi if (dst_nents < 0) 233*21746054SChristian Marangi return dst_nents; 2349739f5f9SChristian Marangi 2359739f5f9SChristian Marangi if (src == dst) { 2369739f5f9SChristian Marangi src_nents = max(src_nents, dst_nents); 2379739f5f9SChristian Marangi dst_nents = src_nents; 238*21746054SChristian Marangi if (unlikely((totlen_src || totlen_dst) && !src_nents)) 2399739f5f9SChristian Marangi return err; 2409739f5f9SChristian Marangi 2419739f5f9SChristian Marangi } else { 242*21746054SChristian Marangi if (unlikely(totlen_src && !src_nents)) 2439739f5f9SChristian Marangi return err; 2449739f5f9SChristian Marangi 245*21746054SChristian Marangi if (unlikely(totlen_dst && !dst_nents)) 2469739f5f9SChristian Marangi return err; 2479739f5f9SChristian Marangi } 2489739f5f9SChristian Marangi 2499739f5f9SChristian Marangi if (authsize) { 2509739f5f9SChristian Marangi if (dst_nents == 1 && src_nents == 1) { 2519739f5f9SChristian Marangi src_align = eip93_is_sg_aligned(src, totlen_src, blksize); 2529739f5f9SChristian Marangi if (src == dst) 2539739f5f9SChristian Marangi dst_align = src_align; 2549739f5f9SChristian Marangi else 2559739f5f9SChristian Marangi dst_align = eip93_is_sg_aligned(dst, totlen_dst, blksize); 2569739f5f9SChristian Marangi } else { 2579739f5f9SChristian Marangi src_align = false; 2589739f5f9SChristian Marangi dst_align = false; 2599739f5f9SChristian Marangi } 2609739f5f9SChristian Marangi } else { 2619739f5f9SChristian Marangi src_align = eip93_is_sg_aligned(src, totlen_src, blksize); 2629739f5f9SChristian Marangi if (src == dst) 2639739f5f9SChristian Marangi dst_align = src_align; 2649739f5f9SChristian Marangi else 2659739f5f9SChristian Marangi dst_align = eip93_is_sg_aligned(dst, totlen_dst, blksize); 2669739f5f9SChristian Marangi } 2679739f5f9SChristian Marangi 2689739f5f9SChristian Marangi copy_len = max(totlen_src, totlen_dst); 2699739f5f9SChristian Marangi if (!src_align) { 2709739f5f9SChristian Marangi err = eip93_make_sg_copy(src, &rctx->sg_src, copy_len, true); 2719739f5f9SChristian Marangi if (err) 2729739f5f9SChristian Marangi return err; 2739739f5f9SChristian Marangi } 2749739f5f9SChristian Marangi 2759739f5f9SChristian Marangi if (!dst_align) { 2769739f5f9SChristian Marangi err = eip93_make_sg_copy(dst, &rctx->sg_dst, copy_len, false); 2779739f5f9SChristian Marangi if (err) 2789739f5f9SChristian Marangi return err; 2799739f5f9SChristian Marangi } 2809739f5f9SChristian Marangi 281*21746054SChristian Marangi src_nents = sg_nents_for_len(rctx->sg_src, totlen_src); 282*21746054SChristian Marangi if (src_nents < 0) 283*21746054SChristian Marangi return src_nents; 284*21746054SChristian Marangi 285*21746054SChristian Marangi dst_nents = sg_nents_for_len(rctx->sg_dst, totlen_dst); 286*21746054SChristian Marangi if (dst_nents < 0) 287*21746054SChristian Marangi return dst_nents; 288*21746054SChristian Marangi 289*21746054SChristian Marangi rctx->src_nents = src_nents; 290*21746054SChristian Marangi rctx->dst_nents = dst_nents; 2919739f5f9SChristian Marangi 2929739f5f9SChristian Marangi return 0; 2939739f5f9SChristian Marangi } 2949739f5f9SChristian Marangi 2959739f5f9SChristian Marangi /* 2969739f5f9SChristian Marangi * Set sa_record function: 2979739f5f9SChristian Marangi * Even sa_record is set to "0", keep " = 0" for readability. 2989739f5f9SChristian Marangi */ 2999739f5f9SChristian Marangi void eip93_set_sa_record(struct sa_record *sa_record, const unsigned int keylen, 3009739f5f9SChristian Marangi const u32 flags) 3019739f5f9SChristian Marangi { 3029739f5f9SChristian Marangi /* Reset cmd word */ 3039739f5f9SChristian Marangi sa_record->sa_cmd0_word = 0; 3049739f5f9SChristian Marangi sa_record->sa_cmd1_word = 0; 3059739f5f9SChristian Marangi 3069739f5f9SChristian Marangi sa_record->sa_cmd0_word |= EIP93_SA_CMD_IV_FROM_STATE; 3079739f5f9SChristian Marangi if (!IS_ECB(flags)) 3089739f5f9SChristian Marangi sa_record->sa_cmd0_word |= EIP93_SA_CMD_SAVE_IV; 3099739f5f9SChristian Marangi 3109739f5f9SChristian Marangi sa_record->sa_cmd0_word |= EIP93_SA_CMD_OP_BASIC; 3119739f5f9SChristian Marangi 3129739f5f9SChristian Marangi switch ((flags & EIP93_ALG_MASK)) { 3139739f5f9SChristian Marangi case EIP93_ALG_AES: 3149739f5f9SChristian Marangi sa_record->sa_cmd0_word |= EIP93_SA_CMD_CIPHER_AES; 3159739f5f9SChristian Marangi sa_record->sa_cmd1_word |= FIELD_PREP(EIP93_SA_CMD_AES_KEY_LENGTH, 3169739f5f9SChristian Marangi keylen >> 3); 3179739f5f9SChristian Marangi break; 3189739f5f9SChristian Marangi case EIP93_ALG_3DES: 3199739f5f9SChristian Marangi sa_record->sa_cmd0_word |= EIP93_SA_CMD_CIPHER_3DES; 3209739f5f9SChristian Marangi break; 3219739f5f9SChristian Marangi case EIP93_ALG_DES: 3229739f5f9SChristian Marangi sa_record->sa_cmd0_word |= EIP93_SA_CMD_CIPHER_DES; 3239739f5f9SChristian Marangi break; 3249739f5f9SChristian Marangi default: 3259739f5f9SChristian Marangi sa_record->sa_cmd0_word |= EIP93_SA_CMD_CIPHER_NULL; 3269739f5f9SChristian Marangi } 3279739f5f9SChristian Marangi 3289739f5f9SChristian Marangi switch ((flags & EIP93_HASH_MASK)) { 3299739f5f9SChristian Marangi case EIP93_HASH_SHA256: 3309739f5f9SChristian Marangi sa_record->sa_cmd0_word |= EIP93_SA_CMD_HASH_SHA256; 3319739f5f9SChristian Marangi break; 3329739f5f9SChristian Marangi case EIP93_HASH_SHA224: 3339739f5f9SChristian Marangi sa_record->sa_cmd0_word |= EIP93_SA_CMD_HASH_SHA224; 3349739f5f9SChristian Marangi break; 3359739f5f9SChristian Marangi case EIP93_HASH_SHA1: 3369739f5f9SChristian Marangi sa_record->sa_cmd0_word |= EIP93_SA_CMD_HASH_SHA1; 3379739f5f9SChristian Marangi break; 3389739f5f9SChristian Marangi case EIP93_HASH_MD5: 3399739f5f9SChristian Marangi sa_record->sa_cmd0_word |= EIP93_SA_CMD_HASH_MD5; 3409739f5f9SChristian Marangi break; 3419739f5f9SChristian Marangi default: 3429739f5f9SChristian Marangi sa_record->sa_cmd0_word |= EIP93_SA_CMD_HASH_NULL; 3439739f5f9SChristian Marangi } 3449739f5f9SChristian Marangi 3459739f5f9SChristian Marangi sa_record->sa_cmd0_word |= EIP93_SA_CMD_PAD_ZERO; 3469739f5f9SChristian Marangi 3479739f5f9SChristian Marangi switch ((flags & EIP93_MODE_MASK)) { 3489739f5f9SChristian Marangi case EIP93_MODE_CBC: 3499739f5f9SChristian Marangi sa_record->sa_cmd1_word |= EIP93_SA_CMD_CHIPER_MODE_CBC; 3509739f5f9SChristian Marangi break; 3519739f5f9SChristian Marangi case EIP93_MODE_CTR: 3529739f5f9SChristian Marangi sa_record->sa_cmd1_word |= EIP93_SA_CMD_CHIPER_MODE_CTR; 3539739f5f9SChristian Marangi break; 3549739f5f9SChristian Marangi case EIP93_MODE_ECB: 3559739f5f9SChristian Marangi sa_record->sa_cmd1_word |= EIP93_SA_CMD_CHIPER_MODE_ECB; 3569739f5f9SChristian Marangi break; 3579739f5f9SChristian Marangi } 3589739f5f9SChristian Marangi 3599739f5f9SChristian Marangi sa_record->sa_cmd0_word |= EIP93_SA_CMD_DIGEST_3WORD; 3609739f5f9SChristian Marangi if (IS_HASH(flags)) { 3619739f5f9SChristian Marangi sa_record->sa_cmd1_word |= EIP93_SA_CMD_COPY_PAD; 3629739f5f9SChristian Marangi sa_record->sa_cmd1_word |= EIP93_SA_CMD_COPY_DIGEST; 3639739f5f9SChristian Marangi } 3649739f5f9SChristian Marangi 3659739f5f9SChristian Marangi if (IS_HMAC(flags)) { 3669739f5f9SChristian Marangi sa_record->sa_cmd1_word |= EIP93_SA_CMD_HMAC; 3679739f5f9SChristian Marangi sa_record->sa_cmd1_word |= EIP93_SA_CMD_COPY_HEADER; 3689739f5f9SChristian Marangi } 3699739f5f9SChristian Marangi 3709739f5f9SChristian Marangi sa_record->sa_spi = 0x0; 3719739f5f9SChristian Marangi sa_record->sa_seqmum_mask[0] = 0xFFFFFFFF; 3729739f5f9SChristian Marangi sa_record->sa_seqmum_mask[1] = 0x0; 3739739f5f9SChristian Marangi } 3749739f5f9SChristian Marangi 3759739f5f9SChristian Marangi /* 3769739f5f9SChristian Marangi * Poor mans Scatter/gather function: 3779739f5f9SChristian Marangi * Create a Descriptor for every segment to avoid copying buffers. 3789739f5f9SChristian Marangi * For performance better to wait for hardware to perform multiple DMA 3799739f5f9SChristian Marangi */ 3809739f5f9SChristian Marangi static int eip93_scatter_combine(struct eip93_device *eip93, 3819739f5f9SChristian Marangi struct eip93_cipher_reqctx *rctx, 3829739f5f9SChristian Marangi u32 datalen, u32 split, int offsetin) 3839739f5f9SChristian Marangi { 3849739f5f9SChristian Marangi struct eip93_descriptor *cdesc = rctx->cdesc; 3859739f5f9SChristian Marangi struct scatterlist *sgsrc = rctx->sg_src; 3869739f5f9SChristian Marangi struct scatterlist *sgdst = rctx->sg_dst; 3879739f5f9SChristian Marangi unsigned int remainin = sg_dma_len(sgsrc); 3889739f5f9SChristian Marangi unsigned int remainout = sg_dma_len(sgdst); 3899739f5f9SChristian Marangi dma_addr_t saddr = sg_dma_address(sgsrc); 3909739f5f9SChristian Marangi dma_addr_t daddr = sg_dma_address(sgdst); 3919739f5f9SChristian Marangi dma_addr_t state_addr; 3929739f5f9SChristian Marangi u32 src_addr, dst_addr, len, n; 3939739f5f9SChristian Marangi bool nextin = false; 3949739f5f9SChristian Marangi bool nextout = false; 3959739f5f9SChristian Marangi int offsetout = 0; 3969739f5f9SChristian Marangi int err; 3979739f5f9SChristian Marangi 3989739f5f9SChristian Marangi if (IS_ECB(rctx->flags)) 3999739f5f9SChristian Marangi rctx->sa_state_base = 0; 4009739f5f9SChristian Marangi 4019739f5f9SChristian Marangi if (split < datalen) { 4029739f5f9SChristian Marangi state_addr = rctx->sa_state_ctr_base; 4039739f5f9SChristian Marangi n = split; 4049739f5f9SChristian Marangi } else { 4059739f5f9SChristian Marangi state_addr = rctx->sa_state_base; 4069739f5f9SChristian Marangi n = datalen; 4079739f5f9SChristian Marangi } 4089739f5f9SChristian Marangi 4099739f5f9SChristian Marangi do { 4109739f5f9SChristian Marangi if (nextin) { 4119739f5f9SChristian Marangi sgsrc = sg_next(sgsrc); 4129739f5f9SChristian Marangi remainin = sg_dma_len(sgsrc); 4139739f5f9SChristian Marangi if (remainin == 0) 4149739f5f9SChristian Marangi continue; 4159739f5f9SChristian Marangi 4169739f5f9SChristian Marangi saddr = sg_dma_address(sgsrc); 4179739f5f9SChristian Marangi offsetin = 0; 4189739f5f9SChristian Marangi nextin = false; 4199739f5f9SChristian Marangi } 4209739f5f9SChristian Marangi 4219739f5f9SChristian Marangi if (nextout) { 4229739f5f9SChristian Marangi sgdst = sg_next(sgdst); 4239739f5f9SChristian Marangi remainout = sg_dma_len(sgdst); 4249739f5f9SChristian Marangi if (remainout == 0) 4259739f5f9SChristian Marangi continue; 4269739f5f9SChristian Marangi 4279739f5f9SChristian Marangi daddr = sg_dma_address(sgdst); 4289739f5f9SChristian Marangi offsetout = 0; 4299739f5f9SChristian Marangi nextout = false; 4309739f5f9SChristian Marangi } 4319739f5f9SChristian Marangi src_addr = saddr + offsetin; 4329739f5f9SChristian Marangi dst_addr = daddr + offsetout; 4339739f5f9SChristian Marangi 4349739f5f9SChristian Marangi if (remainin == remainout) { 4359739f5f9SChristian Marangi len = remainin; 4369739f5f9SChristian Marangi if (len > n) { 4379739f5f9SChristian Marangi len = n; 4389739f5f9SChristian Marangi remainin -= n; 4399739f5f9SChristian Marangi remainout -= n; 4409739f5f9SChristian Marangi offsetin += n; 4419739f5f9SChristian Marangi offsetout += n; 4429739f5f9SChristian Marangi } else { 4439739f5f9SChristian Marangi nextin = true; 4449739f5f9SChristian Marangi nextout = true; 4459739f5f9SChristian Marangi } 4469739f5f9SChristian Marangi } else if (remainin < remainout) { 4479739f5f9SChristian Marangi len = remainin; 4489739f5f9SChristian Marangi if (len > n) { 4499739f5f9SChristian Marangi len = n; 4509739f5f9SChristian Marangi remainin -= n; 4519739f5f9SChristian Marangi remainout -= n; 4529739f5f9SChristian Marangi offsetin += n; 4539739f5f9SChristian Marangi offsetout += n; 4549739f5f9SChristian Marangi } else { 4559739f5f9SChristian Marangi offsetout += len; 4569739f5f9SChristian Marangi remainout -= len; 4579739f5f9SChristian Marangi nextin = true; 4589739f5f9SChristian Marangi } 4599739f5f9SChristian Marangi } else { 4609739f5f9SChristian Marangi len = remainout; 4619739f5f9SChristian Marangi if (len > n) { 4629739f5f9SChristian Marangi len = n; 4639739f5f9SChristian Marangi remainin -= n; 4649739f5f9SChristian Marangi remainout -= n; 4659739f5f9SChristian Marangi offsetin += n; 4669739f5f9SChristian Marangi offsetout += n; 4679739f5f9SChristian Marangi } else { 4689739f5f9SChristian Marangi offsetin += len; 4699739f5f9SChristian Marangi remainin -= len; 4709739f5f9SChristian Marangi nextout = true; 4719739f5f9SChristian Marangi } 4729739f5f9SChristian Marangi } 4739739f5f9SChristian Marangi n -= len; 4749739f5f9SChristian Marangi 4759739f5f9SChristian Marangi cdesc->src_addr = src_addr; 4769739f5f9SChristian Marangi cdesc->dst_addr = dst_addr; 4779739f5f9SChristian Marangi cdesc->state_addr = state_addr; 4789739f5f9SChristian Marangi cdesc->pe_length_word = FIELD_PREP(EIP93_PE_LENGTH_HOST_PE_READY, 4799739f5f9SChristian Marangi EIP93_PE_LENGTH_HOST_READY); 4809739f5f9SChristian Marangi cdesc->pe_length_word |= FIELD_PREP(EIP93_PE_LENGTH_LENGTH, len); 4819739f5f9SChristian Marangi 4829739f5f9SChristian Marangi if (n == 0) { 4839739f5f9SChristian Marangi n = datalen - split; 4849739f5f9SChristian Marangi split = datalen; 4859739f5f9SChristian Marangi state_addr = rctx->sa_state_base; 4869739f5f9SChristian Marangi } 4879739f5f9SChristian Marangi 4889739f5f9SChristian Marangi if (n == 0) 4899739f5f9SChristian Marangi cdesc->user_id |= FIELD_PREP(EIP93_PE_USER_ID_DESC_FLAGS, 4909739f5f9SChristian Marangi EIP93_DESC_LAST); 4919739f5f9SChristian Marangi 4929739f5f9SChristian Marangi /* 4939739f5f9SChristian Marangi * Loop - Delay - No need to rollback 4949739f5f9SChristian Marangi * Maybe refine by slowing down at EIP93_RING_BUSY 4959739f5f9SChristian Marangi */ 4969739f5f9SChristian Marangi again: 4979739f5f9SChristian Marangi scoped_guard(spinlock_irqsave, &eip93->ring->write_lock) 4989739f5f9SChristian Marangi err = eip93_put_descriptor(eip93, cdesc); 4999739f5f9SChristian Marangi if (err) { 5009739f5f9SChristian Marangi usleep_range(EIP93_RING_BUSY_DELAY, 5019739f5f9SChristian Marangi EIP93_RING_BUSY_DELAY * 2); 5029739f5f9SChristian Marangi goto again; 5039739f5f9SChristian Marangi } 5049739f5f9SChristian Marangi /* Writing new descriptor count starts DMA action */ 5059739f5f9SChristian Marangi writel(1, eip93->base + EIP93_REG_PE_CD_COUNT); 5069739f5f9SChristian Marangi } while (n); 5079739f5f9SChristian Marangi 5089739f5f9SChristian Marangi return -EINPROGRESS; 5099739f5f9SChristian Marangi } 5109739f5f9SChristian Marangi 5119739f5f9SChristian Marangi int eip93_send_req(struct crypto_async_request *async, 5129739f5f9SChristian Marangi const u8 *reqiv, struct eip93_cipher_reqctx *rctx) 5139739f5f9SChristian Marangi { 5149739f5f9SChristian Marangi struct eip93_crypto_ctx *ctx = crypto_tfm_ctx(async->tfm); 5159739f5f9SChristian Marangi struct eip93_device *eip93 = ctx->eip93; 5169739f5f9SChristian Marangi struct scatterlist *src = rctx->sg_src; 5179739f5f9SChristian Marangi struct scatterlist *dst = rctx->sg_dst; 5189739f5f9SChristian Marangi struct sa_state *sa_state; 5199739f5f9SChristian Marangi struct eip93_descriptor cdesc; 5209739f5f9SChristian Marangi u32 flags = rctx->flags; 5219739f5f9SChristian Marangi int offsetin = 0, err; 5229739f5f9SChristian Marangi u32 datalen = rctx->assoclen + rctx->textsize; 5239739f5f9SChristian Marangi u32 split = datalen; 5249739f5f9SChristian Marangi u32 start, end, ctr, blocks; 5259739f5f9SChristian Marangi u32 iv[AES_BLOCK_SIZE / sizeof(u32)]; 5269739f5f9SChristian Marangi int crypto_async_idr; 5279739f5f9SChristian Marangi 5289739f5f9SChristian Marangi rctx->sa_state_ctr = NULL; 5299739f5f9SChristian Marangi rctx->sa_state = NULL; 5309739f5f9SChristian Marangi 5319739f5f9SChristian Marangi if (IS_ECB(flags)) 5329739f5f9SChristian Marangi goto skip_iv; 5339739f5f9SChristian Marangi 5349739f5f9SChristian Marangi memcpy(iv, reqiv, rctx->ivsize); 5359739f5f9SChristian Marangi 5369739f5f9SChristian Marangi rctx->sa_state = kzalloc(sizeof(*rctx->sa_state), GFP_KERNEL); 5379739f5f9SChristian Marangi if (!rctx->sa_state) 5389739f5f9SChristian Marangi return -ENOMEM; 5399739f5f9SChristian Marangi 5409739f5f9SChristian Marangi sa_state = rctx->sa_state; 5419739f5f9SChristian Marangi 5429739f5f9SChristian Marangi memcpy(sa_state->state_iv, iv, rctx->ivsize); 5439739f5f9SChristian Marangi if (IS_RFC3686(flags)) { 5449739f5f9SChristian Marangi sa_state->state_iv[0] = ctx->sa_nonce; 5459739f5f9SChristian Marangi sa_state->state_iv[1] = iv[0]; 5469739f5f9SChristian Marangi sa_state->state_iv[2] = iv[1]; 5479739f5f9SChristian Marangi sa_state->state_iv[3] = (u32 __force)cpu_to_be32(0x1); 5489739f5f9SChristian Marangi } else if (!IS_HMAC(flags) && IS_CTR(flags)) { 5499739f5f9SChristian Marangi /* Compute data length. */ 5509739f5f9SChristian Marangi blocks = DIV_ROUND_UP(rctx->textsize, AES_BLOCK_SIZE); 5519739f5f9SChristian Marangi ctr = be32_to_cpu((__be32 __force)iv[3]); 5529739f5f9SChristian Marangi /* Check 32bit counter overflow. */ 5539739f5f9SChristian Marangi start = ctr; 5549739f5f9SChristian Marangi end = start + blocks - 1; 5559739f5f9SChristian Marangi if (end < start) { 5569739f5f9SChristian Marangi split = AES_BLOCK_SIZE * -start; 5579739f5f9SChristian Marangi /* 5589739f5f9SChristian Marangi * Increment the counter manually to cope with 5599739f5f9SChristian Marangi * the hardware counter overflow. 5609739f5f9SChristian Marangi */ 5619739f5f9SChristian Marangi iv[3] = 0xffffffff; 5629739f5f9SChristian Marangi crypto_inc((u8 *)iv, AES_BLOCK_SIZE); 5639739f5f9SChristian Marangi 5649739f5f9SChristian Marangi rctx->sa_state_ctr = kzalloc(sizeof(*rctx->sa_state_ctr), 5659739f5f9SChristian Marangi GFP_KERNEL); 5669739f5f9SChristian Marangi if (!rctx->sa_state_ctr) { 5679739f5f9SChristian Marangi err = -ENOMEM; 5689739f5f9SChristian Marangi goto free_sa_state; 5699739f5f9SChristian Marangi } 5709739f5f9SChristian Marangi 5719739f5f9SChristian Marangi memcpy(rctx->sa_state_ctr->state_iv, reqiv, rctx->ivsize); 5729739f5f9SChristian Marangi memcpy(sa_state->state_iv, iv, rctx->ivsize); 5739739f5f9SChristian Marangi 5749739f5f9SChristian Marangi rctx->sa_state_ctr_base = dma_map_single(eip93->dev, rctx->sa_state_ctr, 5759739f5f9SChristian Marangi sizeof(*rctx->sa_state_ctr), 5769739f5f9SChristian Marangi DMA_TO_DEVICE); 5779739f5f9SChristian Marangi err = dma_mapping_error(eip93->dev, rctx->sa_state_ctr_base); 5789739f5f9SChristian Marangi if (err) 5799739f5f9SChristian Marangi goto free_sa_state_ctr; 5809739f5f9SChristian Marangi } 5819739f5f9SChristian Marangi } 5829739f5f9SChristian Marangi 5839739f5f9SChristian Marangi rctx->sa_state_base = dma_map_single(eip93->dev, rctx->sa_state, 5849739f5f9SChristian Marangi sizeof(*rctx->sa_state), DMA_TO_DEVICE); 5859739f5f9SChristian Marangi err = dma_mapping_error(eip93->dev, rctx->sa_state_base); 5869739f5f9SChristian Marangi if (err) 5879739f5f9SChristian Marangi goto free_sa_state_ctr_dma; 5889739f5f9SChristian Marangi 5899739f5f9SChristian Marangi skip_iv: 5909739f5f9SChristian Marangi 5919739f5f9SChristian Marangi cdesc.pe_ctrl_stat_word = FIELD_PREP(EIP93_PE_CTRL_PE_READY_DES_TRING_OWN, 5929739f5f9SChristian Marangi EIP93_PE_CTRL_HOST_READY); 5939739f5f9SChristian Marangi cdesc.sa_addr = rctx->sa_record_base; 5949739f5f9SChristian Marangi cdesc.arc4_addr = 0; 5959739f5f9SChristian Marangi 5969739f5f9SChristian Marangi scoped_guard(spinlock_bh, &eip93->ring->idr_lock) 5979739f5f9SChristian Marangi crypto_async_idr = idr_alloc(&eip93->ring->crypto_async_idr, async, 0, 5989739f5f9SChristian Marangi EIP93_RING_NUM - 1, GFP_ATOMIC); 5999739f5f9SChristian Marangi 6009739f5f9SChristian Marangi cdesc.user_id = FIELD_PREP(EIP93_PE_USER_ID_CRYPTO_IDR, (u16)crypto_async_idr) | 6019739f5f9SChristian Marangi FIELD_PREP(EIP93_PE_USER_ID_DESC_FLAGS, rctx->desc_flags); 6029739f5f9SChristian Marangi 6039739f5f9SChristian Marangi rctx->cdesc = &cdesc; 6049739f5f9SChristian Marangi 6059739f5f9SChristian Marangi /* map DMA_BIDIRECTIONAL to invalidate cache on destination 6069739f5f9SChristian Marangi * implies __dma_cache_wback_inv 6079739f5f9SChristian Marangi */ 6089739f5f9SChristian Marangi if (!dma_map_sg(eip93->dev, dst, rctx->dst_nents, DMA_BIDIRECTIONAL)) { 6099739f5f9SChristian Marangi err = -ENOMEM; 6109739f5f9SChristian Marangi goto free_sa_state_ctr_dma; 6119739f5f9SChristian Marangi } 6129739f5f9SChristian Marangi 6139739f5f9SChristian Marangi if (src != dst && 6149739f5f9SChristian Marangi !dma_map_sg(eip93->dev, src, rctx->src_nents, DMA_TO_DEVICE)) { 6159739f5f9SChristian Marangi err = -ENOMEM; 6169739f5f9SChristian Marangi goto free_sg_dma; 6179739f5f9SChristian Marangi } 6189739f5f9SChristian Marangi 6199739f5f9SChristian Marangi return eip93_scatter_combine(eip93, rctx, datalen, split, offsetin); 6209739f5f9SChristian Marangi 6219739f5f9SChristian Marangi free_sg_dma: 6229739f5f9SChristian Marangi dma_unmap_sg(eip93->dev, dst, rctx->dst_nents, DMA_BIDIRECTIONAL); 6239739f5f9SChristian Marangi free_sa_state_ctr_dma: 6249739f5f9SChristian Marangi if (rctx->sa_state_ctr) 6259739f5f9SChristian Marangi dma_unmap_single(eip93->dev, rctx->sa_state_ctr_base, 6269739f5f9SChristian Marangi sizeof(*rctx->sa_state_ctr), 6279739f5f9SChristian Marangi DMA_TO_DEVICE); 6289739f5f9SChristian Marangi free_sa_state_ctr: 6299739f5f9SChristian Marangi kfree(rctx->sa_state_ctr); 6309739f5f9SChristian Marangi if (rctx->sa_state) 6319739f5f9SChristian Marangi dma_unmap_single(eip93->dev, rctx->sa_state_base, 6329739f5f9SChristian Marangi sizeof(*rctx->sa_state), 6339739f5f9SChristian Marangi DMA_TO_DEVICE); 6349739f5f9SChristian Marangi free_sa_state: 6359739f5f9SChristian Marangi kfree(rctx->sa_state); 6369739f5f9SChristian Marangi 6379739f5f9SChristian Marangi return err; 6389739f5f9SChristian Marangi } 6399739f5f9SChristian Marangi 6409739f5f9SChristian Marangi void eip93_unmap_dma(struct eip93_device *eip93, struct eip93_cipher_reqctx *rctx, 6419739f5f9SChristian Marangi struct scatterlist *reqsrc, struct scatterlist *reqdst) 6429739f5f9SChristian Marangi { 6439739f5f9SChristian Marangi u32 len = rctx->assoclen + rctx->textsize; 6449739f5f9SChristian Marangi u32 authsize = rctx->authsize; 6459739f5f9SChristian Marangi u32 flags = rctx->flags; 6469739f5f9SChristian Marangi u32 *otag; 6479739f5f9SChristian Marangi int i; 6489739f5f9SChristian Marangi 6499739f5f9SChristian Marangi if (rctx->sg_src == rctx->sg_dst) { 6509739f5f9SChristian Marangi dma_unmap_sg(eip93->dev, rctx->sg_dst, rctx->dst_nents, 6519739f5f9SChristian Marangi DMA_BIDIRECTIONAL); 6529739f5f9SChristian Marangi goto process_tag; 6539739f5f9SChristian Marangi } 6549739f5f9SChristian Marangi 6559739f5f9SChristian Marangi dma_unmap_sg(eip93->dev, rctx->sg_src, rctx->src_nents, 6569739f5f9SChristian Marangi DMA_TO_DEVICE); 6579739f5f9SChristian Marangi 6589739f5f9SChristian Marangi if (rctx->sg_src != reqsrc) 6599739f5f9SChristian Marangi eip93_free_sg_copy(len + rctx->authsize, &rctx->sg_src); 6609739f5f9SChristian Marangi 6619739f5f9SChristian Marangi dma_unmap_sg(eip93->dev, rctx->sg_dst, rctx->dst_nents, 6629739f5f9SChristian Marangi DMA_BIDIRECTIONAL); 6639739f5f9SChristian Marangi 6649739f5f9SChristian Marangi /* SHA tags need conversion from net-to-host */ 6659739f5f9SChristian Marangi process_tag: 6669739f5f9SChristian Marangi if (IS_DECRYPT(flags)) 6679739f5f9SChristian Marangi authsize = 0; 6689739f5f9SChristian Marangi 6699739f5f9SChristian Marangi if (authsize) { 6709739f5f9SChristian Marangi if (!IS_HASH_MD5(flags)) { 6719739f5f9SChristian Marangi otag = sg_virt(rctx->sg_dst) + len; 6729739f5f9SChristian Marangi for (i = 0; i < (authsize / 4); i++) 6739739f5f9SChristian Marangi otag[i] = be32_to_cpu((__be32 __force)otag[i]); 6749739f5f9SChristian Marangi } 6759739f5f9SChristian Marangi } 6769739f5f9SChristian Marangi 6779739f5f9SChristian Marangi if (rctx->sg_dst != reqdst) { 6789739f5f9SChristian Marangi sg_copy_from_buffer(reqdst, sg_nents(reqdst), 6799739f5f9SChristian Marangi sg_virt(rctx->sg_dst), len + authsize); 6809739f5f9SChristian Marangi eip93_free_sg_copy(len + rctx->authsize, &rctx->sg_dst); 6819739f5f9SChristian Marangi } 6829739f5f9SChristian Marangi } 6839739f5f9SChristian Marangi 6849739f5f9SChristian Marangi void eip93_handle_result(struct eip93_device *eip93, struct eip93_cipher_reqctx *rctx, 6859739f5f9SChristian Marangi u8 *reqiv) 6869739f5f9SChristian Marangi { 6879739f5f9SChristian Marangi if (rctx->sa_state_ctr) 6889739f5f9SChristian Marangi dma_unmap_single(eip93->dev, rctx->sa_state_ctr_base, 6899739f5f9SChristian Marangi sizeof(*rctx->sa_state_ctr), 6909739f5f9SChristian Marangi DMA_FROM_DEVICE); 6919739f5f9SChristian Marangi 6929739f5f9SChristian Marangi if (rctx->sa_state) 6939739f5f9SChristian Marangi dma_unmap_single(eip93->dev, rctx->sa_state_base, 6949739f5f9SChristian Marangi sizeof(*rctx->sa_state), 6959739f5f9SChristian Marangi DMA_FROM_DEVICE); 6969739f5f9SChristian Marangi 6979739f5f9SChristian Marangi if (!IS_ECB(rctx->flags)) 6989739f5f9SChristian Marangi memcpy(reqiv, rctx->sa_state->state_iv, rctx->ivsize); 6999739f5f9SChristian Marangi 7009739f5f9SChristian Marangi kfree(rctx->sa_state_ctr); 7019739f5f9SChristian Marangi kfree(rctx->sa_state); 7029739f5f9SChristian Marangi } 7039739f5f9SChristian Marangi 7049739f5f9SChristian Marangi int eip93_hmac_setkey(u32 ctx_flags, const u8 *key, unsigned int keylen, 7059739f5f9SChristian Marangi unsigned int hashlen, u8 *dest_ipad, u8 *dest_opad, 7069739f5f9SChristian Marangi bool skip_ipad) 7079739f5f9SChristian Marangi { 7089739f5f9SChristian Marangi u8 ipad[SHA256_BLOCK_SIZE], opad[SHA256_BLOCK_SIZE]; 7099739f5f9SChristian Marangi struct crypto_ahash *ahash_tfm; 7109739f5f9SChristian Marangi struct eip93_hash_reqctx *rctx; 7119739f5f9SChristian Marangi struct ahash_request *req; 7129739f5f9SChristian Marangi DECLARE_CRYPTO_WAIT(wait); 7139739f5f9SChristian Marangi struct scatterlist sg[1]; 7149739f5f9SChristian Marangi const char *alg_name; 7159739f5f9SChristian Marangi int i, ret; 7169739f5f9SChristian Marangi 7179739f5f9SChristian Marangi switch (ctx_flags & EIP93_HASH_MASK) { 7189739f5f9SChristian Marangi case EIP93_HASH_SHA256: 7199739f5f9SChristian Marangi alg_name = "sha256-eip93"; 7209739f5f9SChristian Marangi break; 7219739f5f9SChristian Marangi case EIP93_HASH_SHA224: 7229739f5f9SChristian Marangi alg_name = "sha224-eip93"; 7239739f5f9SChristian Marangi break; 7249739f5f9SChristian Marangi case EIP93_HASH_SHA1: 7259739f5f9SChristian Marangi alg_name = "sha1-eip93"; 7269739f5f9SChristian Marangi break; 7279739f5f9SChristian Marangi case EIP93_HASH_MD5: 7289739f5f9SChristian Marangi alg_name = "md5-eip93"; 7299739f5f9SChristian Marangi break; 7309739f5f9SChristian Marangi default: /* Impossible */ 7319739f5f9SChristian Marangi return -EINVAL; 7329739f5f9SChristian Marangi } 7339739f5f9SChristian Marangi 7349739f5f9SChristian Marangi ahash_tfm = crypto_alloc_ahash(alg_name, 0, CRYPTO_ALG_ASYNC); 7359739f5f9SChristian Marangi if (IS_ERR(ahash_tfm)) 7369739f5f9SChristian Marangi return PTR_ERR(ahash_tfm); 7379739f5f9SChristian Marangi 7389739f5f9SChristian Marangi req = ahash_request_alloc(ahash_tfm, GFP_ATOMIC); 7399739f5f9SChristian Marangi if (!req) { 7409739f5f9SChristian Marangi ret = -ENOMEM; 7419739f5f9SChristian Marangi goto err_ahash; 7429739f5f9SChristian Marangi } 7439739f5f9SChristian Marangi 7449739f5f9SChristian Marangi rctx = ahash_request_ctx_dma(req); 7459739f5f9SChristian Marangi crypto_init_wait(&wait); 7469739f5f9SChristian Marangi ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, 7479739f5f9SChristian Marangi crypto_req_done, &wait); 7489739f5f9SChristian Marangi 7499739f5f9SChristian Marangi /* Hash the key if > SHA256_BLOCK_SIZE */ 7509739f5f9SChristian Marangi if (keylen > SHA256_BLOCK_SIZE) { 7519739f5f9SChristian Marangi sg_init_one(&sg[0], key, keylen); 7529739f5f9SChristian Marangi 7539739f5f9SChristian Marangi ahash_request_set_crypt(req, sg, ipad, keylen); 7549739f5f9SChristian Marangi ret = crypto_wait_req(crypto_ahash_digest(req), &wait); 7559739f5f9SChristian Marangi if (ret) 7569739f5f9SChristian Marangi goto err_req; 7579739f5f9SChristian Marangi 7589739f5f9SChristian Marangi keylen = hashlen; 7599739f5f9SChristian Marangi } else { 7609739f5f9SChristian Marangi memcpy(ipad, key, keylen); 7619739f5f9SChristian Marangi } 7629739f5f9SChristian Marangi 7639739f5f9SChristian Marangi /* Copy to opad */ 7649739f5f9SChristian Marangi memset(ipad + keylen, 0, SHA256_BLOCK_SIZE - keylen); 7659739f5f9SChristian Marangi memcpy(opad, ipad, SHA256_BLOCK_SIZE); 7669739f5f9SChristian Marangi 7679739f5f9SChristian Marangi /* Pad with HMAC constants */ 7689739f5f9SChristian Marangi for (i = 0; i < SHA256_BLOCK_SIZE; i++) { 7699739f5f9SChristian Marangi ipad[i] ^= HMAC_IPAD_VALUE; 7709739f5f9SChristian Marangi opad[i] ^= HMAC_OPAD_VALUE; 7719739f5f9SChristian Marangi } 7729739f5f9SChristian Marangi 7739739f5f9SChristian Marangi if (skip_ipad) { 7749739f5f9SChristian Marangi memcpy(dest_ipad, ipad, SHA256_BLOCK_SIZE); 7759739f5f9SChristian Marangi } else { 7769739f5f9SChristian Marangi /* Hash ipad */ 7779739f5f9SChristian Marangi sg_init_one(&sg[0], ipad, SHA256_BLOCK_SIZE); 7789739f5f9SChristian Marangi ahash_request_set_crypt(req, sg, dest_ipad, SHA256_BLOCK_SIZE); 7799739f5f9SChristian Marangi ret = crypto_ahash_init(req); 7809739f5f9SChristian Marangi if (ret) 7819739f5f9SChristian Marangi goto err_req; 7829739f5f9SChristian Marangi 7839739f5f9SChristian Marangi /* Disable HASH_FINALIZE for ipad hash */ 7849739f5f9SChristian Marangi rctx->partial_hash = true; 7859739f5f9SChristian Marangi 7869739f5f9SChristian Marangi ret = crypto_wait_req(crypto_ahash_finup(req), &wait); 7879739f5f9SChristian Marangi if (ret) 7889739f5f9SChristian Marangi goto err_req; 7899739f5f9SChristian Marangi } 7909739f5f9SChristian Marangi 7919739f5f9SChristian Marangi /* Hash opad */ 7929739f5f9SChristian Marangi sg_init_one(&sg[0], opad, SHA256_BLOCK_SIZE); 7939739f5f9SChristian Marangi ahash_request_set_crypt(req, sg, dest_opad, SHA256_BLOCK_SIZE); 7949739f5f9SChristian Marangi ret = crypto_ahash_init(req); 7959739f5f9SChristian Marangi if (ret) 7969739f5f9SChristian Marangi goto err_req; 7979739f5f9SChristian Marangi 7989739f5f9SChristian Marangi /* Disable HASH_FINALIZE for opad hash */ 7999739f5f9SChristian Marangi rctx->partial_hash = true; 8009739f5f9SChristian Marangi 8019739f5f9SChristian Marangi ret = crypto_wait_req(crypto_ahash_finup(req), &wait); 8029739f5f9SChristian Marangi if (ret) 8039739f5f9SChristian Marangi goto err_req; 8049739f5f9SChristian Marangi 8059739f5f9SChristian Marangi if (!IS_HASH_MD5(ctx_flags)) { 8069739f5f9SChristian Marangi for (i = 0; i < SHA256_DIGEST_SIZE / sizeof(u32); i++) { 8079739f5f9SChristian Marangi u32 *ipad_hash = (u32 *)dest_ipad; 8089739f5f9SChristian Marangi u32 *opad_hash = (u32 *)dest_opad; 8099739f5f9SChristian Marangi 8109739f5f9SChristian Marangi if (!skip_ipad) 8119739f5f9SChristian Marangi ipad_hash[i] = (u32 __force)cpu_to_be32(ipad_hash[i]); 8129739f5f9SChristian Marangi opad_hash[i] = (u32 __force)cpu_to_be32(opad_hash[i]); 8139739f5f9SChristian Marangi } 8149739f5f9SChristian Marangi } 8159739f5f9SChristian Marangi 8169739f5f9SChristian Marangi err_req: 8179739f5f9SChristian Marangi ahash_request_free(req); 8189739f5f9SChristian Marangi err_ahash: 8199739f5f9SChristian Marangi crypto_free_ahash(ahash_tfm); 8209739f5f9SChristian Marangi 8219739f5f9SChristian Marangi return ret; 8229739f5f9SChristian Marangi } 823