Hi Herbert,
Thank you for your answer. I forgot to mention that the version of the kernel I
am using is 2.6.28.10; I can't use the latest one because of the hardware I am
using.
The code is below; it registers the 3 algorithms needed for IPSec. The actual
implementations of the algorithms are in other files. They basically call a
dedicated hardware and for that reason need to be asynchronous. I can send them
if you wish.
----------------------------
/*
* icp_netkey.c
*
* This is an implementation of Linux Kernel Crypto API shim that uses
* the Intel's Quick Assist API. The focus here is IPsec, (Netkey stack).
*
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/crypto.h>
#include <linux/scatterlist.h>
#include <linux/rwsem.h>
#include <crypto/aead.h>
#include <crypto/algapi.h>
#include "icp_sym_chaining.h"
#include "icp_aes_gcm.h"
#include "icp_netkey.h"
#include "cpa.h"
#include "cpa_cy_sym.h"
#include "cpa_cy_im.h"
static icp_aead_tfm_desc_t *g_pTfm_desc_list = NULL;
static icp_aead_tfm_desc_t *g_pTfm_desc_list_head = NULL;
static struct kmem_cache *pOpDataCache = NULL;
static struct kmem_cache *pMetaCache = NULL;
static struct rw_semaphore tfm_desc_semaphore;
/* delete the tfm descriptor associated with this aead */
static void del_tfm_desc(const struct crypto_aead* const pAead)
{
icp_aead_tfm_desc_t *pCurr = NULL;
CpaStatus status = CPA_STATUS_SUCCESS;
for (pCurr = g_pTfm_desc_list_head; pCurr != NULL; pCurr = pCurr->pNext)
{
if (pCurr->pAead == pAead)
{
down_write(&tfm_desc_semaphore);
ICP_REMOVE_ELEMENT_FROM_LIST(pCurr, g_pTfm_desc_list,
g_pTfm_desc_list_head);
up_write(&tfm_desc_semaphore);
if (pCurr->pEncrypt_session_ctx != NULL)
{
status =
cpaCySymRemoveSession(CPA_INSTANCE_HANDLE_SINGLE, pCurr->pEncrypt_session_ctx);
if (CPA_STATUS_SUCCESS != status)
{
printk("cpaCySymRemoveSession failed.
(status = %d)\n", status);
/* the session could not be removed,
its memory can't be freed */
}
else
{
icp_kfree(pCurr->pEncrypt_session_ctx);
dprintk("cpaCySymRemoveSession for
Encryption was successful. (status = %d)\n", status);
}
}
if (pCurr->pDecrypt_session_ctx != NULL)
{
status =
cpaCySymRemoveSession(CPA_INSTANCE_HANDLE_SINGLE, pCurr->pDecrypt_session_ctx);
if (CPA_STATUS_SUCCESS != status)
{
/* the session could not be removed, its memory
can't be freed */
printk("cpaCySymRemoveSession failed.
(status = %d)\n", status);
}
else
{
icp_kfree(pCurr->pDecrypt_session_ctx);
dprintk("cpaCySymRemoveSession for
Decryption was successful. (status = %d)\n", status);
}
}
icp_kfree(pCurr);
dprintk("%s: tfm_desc deleted\n", __FUNCTION__);
break;
}
}
}
static void aead_auth_exit(struct crypto_tfm *pTfm)
{
del_tfm_desc((struct crypto_aead *)(pTfm));
}
inline icp_aead_tfm_desc_t *find_tfm_desc(const struct crypto_aead* const pAead)
{
icp_aead_tfm_desc_t *pCurr = NULL;
down_read(&tfm_desc_semaphore);
for (pCurr = g_pTfm_desc_list_head; pCurr != NULL; pCurr = pCurr->pNext)
{
if (pCurr->pAead == pAead)
{
dprintk("%s: found tfm_desc = %p\n", __FUNCTION__, pCurr);
up_read(&tfm_desc_semaphore);
return pCurr;
}
}
up_read(&tfm_desc_semaphore);
return NULL;
}
icp_aead_tfm_desc_t *add_tfm_desc(struct crypto_aead* const pAead)
{
icp_aead_tfm_desc_t *pCurr = NULL;
pCurr = find_tfm_desc(pAead);
if (NULL != pCurr)
{
dprintk("%s: tfm_desc already exist for this aead\n", __FUNCTION__);
return pCurr;
}
pCurr = kzalloc(sizeof(icp_aead_tfm_desc_t), GFP_ATOMIC);
if (NULL == pCurr)
{
printk("%s: unable to allocate memory\n", __FUNCTION__);
return NULL;
}
pCurr->pAead = pAead;
down_write(&tfm_desc_semaphore);
ICP_ADD_ELEMENT_TO_END_OF_LIST(pCurr, g_pTfm_desc_list,
g_pTfm_desc_list_head);
up_write(&tfm_desc_semaphore);
dprintk("%s: new tfm_desc added %p\n", __FUNCTION__, pCurr);
return pCurr;
}
static struct crypto_alg aead_authenc_3des_hmac_sha1 = {
.cra_name = "authenc(hmac(sha1),cbc(des3_ede))",
.cra_driver_name = "icp_aead",
.cra_priority = ICP_AES_ASYNC_PRIORITY,
.cra_flags =
CRYPTO_ALG_TYPE_AEAD|CRYPTO_ALG_GENIV|CRYPTO_ALG_ASYNC,
.cra_blocksize = DES3_BLOCK_SIZE /*8*/,
.cra_ctxsize = 0,
.cra_type = &crypto_aead_type,
.cra_module = THIS_MODULE,
.cra_list =
LIST_HEAD_INIT(aead_authenc_3des_hmac_sha1.cra_list),
.cra_exit = aead_auth_exit,
.cra_u = {
.aead = {
.ivsize = DES3_BLOCK_SIZE /*8*/,
.maxauthsize = SHA1_DIGEST_SIZE /*20*/,
.setkey = setkey_3des_hmac_sha1,
.setauthsize = qat_setauthsize,
.encrypt = encrypt_3des_hmac_sha1,
.decrypt = decrypt_3des_hmac_sha1,
.givencrypt = geniv_encrypt_3des_hmac_sha1,
.givdecrypt = geniv_decrypt_3des_hmac_sha1,
}
}
};
static struct crypto_alg aead_authenc_aes_cbc_hmac_sha1 = {
.cra_name = "authenc(hmac(sha1),cbc(aes))",
.cra_driver_name = "icp_aead",
.cra_priority = ICP_AES_ASYNC_PRIORITY,
.cra_flags =
CRYPTO_ALG_TYPE_AEAD|CRYPTO_ALG_GENIV|CRYPTO_ALG_ASYNC,
.cra_blocksize = AES_BLOCK_SIZE /*16*/,
.cra_ctxsize = 0,
.cra_type = &crypto_aead_type,
.cra_module = THIS_MODULE,
.cra_list =
LIST_HEAD_INIT(aead_authenc_aes_cbc_hmac_sha1.cra_list),
.cra_exit = aead_auth_exit,
.cra_u = {
.aead = {
.ivsize = AES_BLOCK_SIZE /*16*/,
.maxauthsize = SHA1_DIGEST_SIZE /*20*/,
.setkey = setkey_aes_cbc_hmac_sha1,
.setauthsize = qat_setauthsize,
.encrypt = encrypt_aes_cbc_hmac_sha1,
.decrypt = decrypt_aes_cbc_hmac_sha1,
.givencrypt = geniv_encrypt_aes_cbc_hmac_sha1,
.givdecrypt = geniv_decrypt_aes_cbc_hmac_sha1,
}
}
};
static struct crypto_alg aead_authenc_aes_gcm = {
.cra_name = "rfc4106(gcm(aes))",
.cra_driver_name = "icp_aead",
.cra_priority = ICP_AES_ASYNC_PRIORITY,
.cra_flags =
CRYPTO_ALG_TYPE_AEAD|CRYPTO_ALG_GENIV|CRYPTO_ALG_ASYNC,
.cra_blocksize = AES_BLOCK_SIZE /*16*/,
.cra_ctxsize = 0,
.cra_type = &crypto_aead_type,
.cra_module = THIS_MODULE,
.cra_list =
LIST_HEAD_INIT(aead_authenc_aes_gcm.cra_list),
.cra_exit = aead_auth_exit,
.cra_u = {
.aead = {
.ivsize = AES_GCM_IV_SIZE, /*8*/
.maxauthsize = AES_GCM_AUTH_TAG_LEN, /*16*/
.setkey = setkey_aes_gcm,
.setauthsize = qat_setauthsize,
.encrypt = encrypt_aes_gcm,
.decrypt = decrypt_aes_gcm,
.givencrypt = geniv_encrypt_aes_gcm,
.givdecrypt = geniv_decrypt_aes_gcm,
}
}
};
static int __init netkey_init(void)
{
CpaStatus status = CPA_STATUS_SUCCESS;
Cpa32U bufferListMetaSize = 0;
int registerStatus =0;
init_rwsem(&tfm_desc_semaphore);
status = cpaCyStartInstance(CPA_INSTANCE_HANDLE_SINGLE);
if (CPA_STATUS_SUCCESS != status) {
printk("cpaCyStartInstance failed. (status = %d)\n", status);
return -EPERM;
}
/* Determine the size of bufferlist pPrivateMetaData */
status = cpaCyBufferListGetMetaSize(CPA_INSTANCE_HANDLE_SINGLE,
ICP_MAX_NUM_BUFFERS,
&bufferListMetaSize);
if (CPA_STATUS_SUCCESS != status)
{
printk("cpaCyBufferListGetMetaSize failed. (status = %d)\n", status);
status = cpaCyStopInstance(CPA_INSTANCE_HANDLE_SINGLE);
if (CPA_STATUS_SUCCESS != status)
{
printk("cpaCyStopInstance failed. (status = %d)\n", status);
}
return -EPERM;
}
dprintk("%s: cpaCyBufferListGetMetaSize = %u\n", __FUNCTION__,
bufferListMetaSize);
/*
* Allocation of the OpData includes the allocation space for meta data.
* The memory after the opData structure is reserved for this meta data.
*/
pOpDataCache = kmem_cache_create("icp_opdata",
sizeof(icp_aead_op_data_t),
0, SLAB_HWCACHE_ALIGN, NULL);
if (NULL == pOpDataCache) {
printk("%s: unable to allocate OpData cache\n", __FUNCTION__);
status = cpaCyStopInstance(CPA_INSTANCE_HANDLE_SINGLE);
if (CPA_STATUS_SUCCESS != status)
{
printk("cpaCyStopInstance failed. (status = %d)\n", status);
}
return -ENOMEM;
}
pMetaCache = kmem_cache_create("icp_meta",
bufferListMetaSize,
0, SLAB_HWCACHE_ALIGN, NULL);
if (NULL == pMetaCache) {
printk("%s: unable to allocate OpData cache\n", __FUNCTION__);
kmem_cache_destroy(pOpDataCache);
pOpDataCache = NULL;
status = cpaCyStopInstance(CPA_INSTANCE_HANDLE_SINGLE);
if (CPA_STATUS_SUCCESS != status)
{
printk("cpaCyStopInstance failed. (status = %d)\n", status);
}
return -ENOMEM;
}
registerStatus = crypto_register_alg(&aead_authenc_3des_hmac_sha1);
if (registerStatus != 0)
{
printk("Register alg failed for 3DES-HMAC_SHA1\n");
kmem_cache_destroy(pOpDataCache);
kmem_cache_destroy(pMetaCache);
pOpDataCache = NULL;
pMetaCache = NULL;
return registerStatus;
}
printk("3DES-HMAC_SHA1 loaded\n");
registerStatus = crypto_register_alg(&aead_authenc_aes_cbc_hmac_sha1);
if (registerStatus != 0)
{
printk("Register alg failed for AES-CBC-HMAC_SHA1\n");
kmem_cache_destroy(pOpDataCache);
kmem_cache_destroy(pMetaCache);
pOpDataCache = NULL;
pMetaCache = NULL;
return registerStatus;
}
printk("AES-CBC-HMAC_SHA1 loaded\n");
registerStatus = crypto_register_alg(&aead_authenc_aes_gcm);
if (registerStatus !=0)
{
printk("Register alg failed for AES_GCM\n");
kmem_cache_destroy(pOpDataCache);
kmem_cache_destroy(pMetaCache);
pOpDataCache = NULL;
pMetaCache = NULL;
return registerStatus;
}
printk("AES_GCM loaded\n");
printk("%s: Intel ICP NetKey Loaded.\n", __FUNCTION__);
return 0;
}
static void __exit netkey_exit(void)
{
CpaStatus status = CPA_STATUS_SUCCESS;
printk("%s: crypto_unregister_alg()\n", __FUNCTION__);
if (crypto_unregister_alg(&aead_authenc_3des_hmac_sha1) != 0)
{
printk("Unable to unload 3DES-HMAC_SHA1\n");
}
if (crypto_unregister_alg(&aead_authenc_aes_cbc_hmac_sha1) != 0)
{
printk("Unable to unload AES-CBC-HMAC_SHA1\n");
}
if (crypto_unregister_alg(&aead_authenc_aes_gcm) != 0)
{
printk("Unable to unload AES_GCM\n");
}
status = cpaCyStopInstance(CPA_INSTANCE_HANDLE_SINGLE);
if (CPA_STATUS_SUCCESS != status)
{
printk("cpaCyStopInstance failed. (status = %d)\n", status);
}
if (NULL != pOpDataCache)
{
kmem_cache_destroy(pOpDataCache);
pOpDataCache = NULL;
}
if (NULL != pMetaCache) {
kmem_cache_destroy(pMetaCache);
pMetaCache = NULL;
}
/* delete all the tfm descriptors */
while (NULL != g_pTfm_desc_list_head) {
del_tfm_desc(g_pTfm_desc_list_head->pAead);
}
printk("%s: Intel ICP NetKey Unloaded.\n", __FUNCTION__);
}
module_init(netkey_init);
module_exit(netkey_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("QAT ICP NETKEY");
MODULE_AUTHOR("Intel");
---------------------------------------
Thank you very much.
Best regards,
Mario
-----Original Message-----
From: Herbert Xu [mailto:[email protected]]
Sent: 01 April 2010 09:55
To: Nicolas, Mario
Cc: [email protected]
Subject: Re: cra_priority usage
Nicolas, Mario <[email protected]> wrote:
> So my questions are:
> -What is this variable used for?
> -If there are multiple implementations of the same algorithm, how is one
> version chosen as opposed to another one?
The one with the numerically higher priority will be used. If
there are multiple implementations with the same priority, the
one registered last will be used.
> I guess that the reason is that an asynchronous version always has a higher
> priority than a synchronous one. Is that correct?
Actually this is probably a bug. I'll have a look to see why this
is the case. Can you please post your complete source?
Thanks,
--
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <[email protected]>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
--------------------------------------------------------------
Intel Shannon Limited
Registered in Ireland
Registered Office: Collinstown Industrial Park, Leixlip, County Kildare
Registered Number: 308263
Business address: Dromore House, East Park, Shannon, Co. Clare
This e-mail and any attachments may contain confidential material for the sole
use of the intended recipient(s). Any review or distribution by others is
strictly prohibited. If you are not the intended recipient, please contact the
sender and delete all copies.
--
To unsubscribe from this list: send the line "unsubscribe linux-crypto" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html