diff options
Diffstat (limited to 'target/linux/generic-2.6/files/crypto/ocf/ep80579')
7 files changed, 4262 insertions, 0 deletions
diff --git a/target/linux/generic-2.6/files/crypto/ocf/ep80579/Makefile b/target/linux/generic-2.6/files/crypto/ocf/ep80579/Makefile new file mode 100644 index 0000000000..19ff6eb054 --- /dev/null +++ b/target/linux/generic-2.6/files/crypto/ocf/ep80579/Makefile @@ -0,0 +1,107 @@ +######################################################################### +# +# Targets supported +# all - builds everything and installs +# install - identical to all +# depend - build dependencies +# clean - clears derived objects except the .depend files +# distclean- clears all derived objects and the .depend file +# +# @par +# This file is provided under a dual BSD/GPLv2 license. When using or +# redistributing this file, you may do so under either license. +# +# GPL LICENSE SUMMARY +# +# Copyright(c) 2007,2008 Intel Corporation. All rights reserved. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. +# The full GNU General Public License is included in this distribution +# in the file called LICENSE.GPL. +# +# Contact Information: +# Intel Corporation +# +# BSD LICENSE +# +# Copyright(c) 2007,2008 Intel Corporation. All rights reserved. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Intel Corporation nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# +# version: Security.L.1.0.130 +############################################################################ + + +####################Common variables and definitions######################## + +# Ensure The ENV_DIR environmental var is defined. +ifndef ICP_ENV_DIR +$(error ICP_ENV_DIR is undefined. Please set the path to your environment makefile \ + "-> setenv ICP_ENV_DIR <path>") +endif + +#Add your project environment Makefile +include $(ICP_ENV_DIR)/environment.mk + +#include the makefile with all the default and common Make variable definitions +include $(ICP_BUILDSYSTEM_PATH)/build_files/common.mk + +#Add the name for the executable, Library or Module output definitions +OUTPUT_NAME= icp_ocf + +# List of Source Files to be compiled +SOURCES= icp_common.c icp_sym.c icp_asym.c + +#common includes between all supported OSes +INCLUDES= -I $(ICP_API_DIR) -I$(ICP_LAC_API) \ +-I$(ICP_OCF_SRC_DIR) + +# The location of the os level makefile needs to be changed. +include $(ICP_ENV_DIR)/$(ICP_OS)_$(ICP_OS_LEVEL).mk + +# On the line directly below list the outputs you wish to build for, +# e.g "lib_static lib_shared exe module" as show below +install: module + +###################Include rules makefiles######################## +include $(ICP_BUILDSYSTEM_PATH)/build_files/rules.mk +###################End of Rules inclusion######################### + + diff --git a/target/linux/generic-2.6/files/crypto/ocf/ep80579/environment.mk b/target/linux/generic-2.6/files/crypto/ocf/ep80579/environment.mk new file mode 100644 index 0000000000..a674b4589f --- /dev/null +++ b/target/linux/generic-2.6/files/crypto/ocf/ep80579/environment.mk @@ -0,0 +1,75 @@ + ########################################################################### + # +# This file is provided under a dual BSD/GPLv2 license. When using or +# redistributing this file, you may do so under either license. +# +# GPL LICENSE SUMMARY +# +# Copyright(c) 2007,2008 Intel Corporation. All rights reserved. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. +# The full GNU General Public License is included in this distribution +# in the file called LICENSE.GPL. +# +# Contact Information: +# Intel Corporation +# +# BSD LICENSE +# +# Copyright(c) 2007,2008 Intel Corporation. All rights reserved. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Intel Corporation nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# +# version: Security.L.1.0.130 + # + ########################################################################### + + +ICP_LAC_API=$(ICP_ROOT)/Acceleration/include/lac +ICP_BTR_API=$(ICP_ROOT)/Acceleration/include/btr +ICP_API_DIR=$(ICP_ROOT)/Acceleration/include +ICP_OCF_SHIM_DIR?=$(KERNEL_SOURCE_ROOT)/crypto/ocf/ + +ICP_OS_LEVEL?=kernel_space + +ICP_OS?=linux_2.6 + +ICP_CORE?=ia + diff --git a/target/linux/generic-2.6/files/crypto/ocf/ep80579/icp_asym.c b/target/linux/generic-2.6/files/crypto/ocf/ep80579/icp_asym.c new file mode 100644 index 0000000000..1a9bd28bf4 --- /dev/null +++ b/target/linux/generic-2.6/files/crypto/ocf/ep80579/icp_asym.c @@ -0,0 +1,1375 @@ +/*************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2007,2008 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * The full GNU General Public License is included in this distribution + * in the file called LICENSE.GPL. + * + * Contact Information: + * Intel Corporation + * + * BSD LICENSE + * + * Copyright(c) 2007,2008 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + * version: Security.L.1.0.130 + * + ***************************************************************************/ + +#include "icp_ocf.h" + +/*The following define values (containing the word 'INDEX') are used to find +the index of each input buffer of the crypto_kop struct (see OCF cryptodev.h). +These values were found through analysis of the OCF OpenSSL patch. If the +calling program uses different input buffer positions, these defines will have +to be changed.*/ + +/*DIFFIE HELLMAN buffer index values*/ +#define ICP_DH_KRP_PARAM_PRIME_INDEX (0) +#define ICP_DH_KRP_PARAM_BASE_INDEX (1) +#define ICP_DH_KRP_PARAM_PRIVATE_VALUE_INDEX (2) +#define ICP_DH_KRP_PARAM_RESULT_INDEX (3) + +/*MOD EXP buffer index values*/ +#define ICP_MOD_EXP_KRP_PARAM_BASE_INDEX (0) +#define ICP_MOD_EXP_KRP_PARAM_EXPONENT_INDEX (1) +#define ICP_MOD_EXP_KRP_PARAM_MODULUS_INDEX (2) +#define ICP_MOD_EXP_KRP_PARAM_RESULT_INDEX (3) + +#define SINGLE_BYTE_VALUE (4) + +/*MOD EXP CRT buffer index values*/ +#define ICP_MOD_EXP_CRT_KRP_PARAM_PRIME_P_INDEX (0) +#define ICP_MOD_EXP_CRT_KRP_PARAM_PRIME_Q_INDEX (1) +#define ICP_MOD_EXP_CRT_KRP_PARAM_I_INDEX (2) +#define ICP_MOD_EXP_CRT_KRP_PARAM_EXPONENT_DP_INDEX (3) +#define ICP_MOD_EXP_CRT_KRP_PARAM_EXPONENT_DQ_INDEX (4) +#define ICP_MOD_EXP_CRT_KRP_PARAM_COEFF_QINV_INDEX (5) +#define ICP_MOD_EXP_CRT_KRP_PARAM_RESULT_INDEX (6) + +/*DSA sign buffer index values*/ +#define ICP_DSA_SIGN_KRP_PARAM_DGST_INDEX (0) +#define ICP_DSA_SIGN_KRP_PARAM_PRIME_P_INDEX (1) +#define ICP_DSA_SIGN_KRP_PARAM_PRIME_Q_INDEX (2) +#define ICP_DSA_SIGN_KRP_PARAM_G_INDEX (3) +#define ICP_DSA_SIGN_KRP_PARAM_X_INDEX (4) +#define ICP_DSA_SIGN_KRP_PARAM_R_RESULT_INDEX (5) +#define ICP_DSA_SIGN_KRP_PARAM_S_RESULT_INDEX (6) + +/*DSA verify buffer index values*/ +#define ICP_DSA_VERIFY_KRP_PARAM_DGST_INDEX (0) +#define ICP_DSA_VERIFY_KRP_PARAM_PRIME_P_INDEX (1) +#define ICP_DSA_VERIFY_KRP_PARAM_PRIME_Q_INDEX (2) +#define ICP_DSA_VERIFY_KRP_PARAM_G_INDEX (3) +#define ICP_DSA_VERIFY_KRP_PARAM_PUBKEY_INDEX (4) +#define ICP_DSA_VERIFY_KRP_PARAM_SIG_R_INDEX (5) +#define ICP_DSA_VERIFY_KRP_PARAM_SIG_S_INDEX (6) + +/*DSA sign prime Q vs random number K size check values*/ +#define DONT_RUN_LESS_THAN_CHECK (0) +#define FAIL_A_IS_GREATER_THAN_B (1) +#define FAIL_A_IS_EQUAL_TO_B (1) +#define SUCCESS_A_IS_LESS_THAN_B (0) +#define DSA_SIGN_RAND_GEN_VAL_CHECK_MAX_ITERATIONS (500) + +/* We need to set a cryptokp success value just in case it is set or allocated + and not set to zero outside of this module */ +#define CRYPTO_OP_SUCCESS (0) + +static int icp_ocfDrvDHComputeKey(struct cryptkop *krp); + +static int icp_ocfDrvModExp(struct cryptkop *krp); + +static int icp_ocfDrvModExpCRT(struct cryptkop *krp); + +static int +icp_ocfDrvCheckALessThanB(CpaFlatBuffer * pK, CpaFlatBuffer * pQ, int *doCheck); + +static int icp_ocfDrvDsaSign(struct cryptkop *krp); + +static int icp_ocfDrvDsaVerify(struct cryptkop *krp); + +static void +icp_ocfDrvDhP1CallBack(void *callbackTag, + CpaStatus status, + void *pOpData, CpaFlatBuffer * pLocalOctetStringPV); + +static void +icp_ocfDrvModExpCallBack(void *callbackTag, + CpaStatus status, + void *pOpData, CpaFlatBuffer * pResult); + +static void +icp_ocfDrvModExpCRTCallBack(void *callbackTag, + CpaStatus status, + void *pOpData, CpaFlatBuffer * pOutputData); + +static void +icp_ocfDrvDsaVerifyCallBack(void *callbackTag, + CpaStatus status, + void *pOpData, CpaBoolean verifyStatus); + +static void +icp_ocfDrvDsaRSSignCallBack(void *callbackTag, + CpaStatus status, + void *pOpData, + CpaBoolean protocolStatus, + CpaFlatBuffer * pR, CpaFlatBuffer * pS); + +/* Name : icp_ocfDrvPkeProcess + * + * Description : This function will choose which PKE process to follow + * based on the input arguments + */ +int icp_ocfDrvPkeProcess(device_t dev, struct cryptkop *krp, int hint) +{ + CpaStatus lacStatus = CPA_STATUS_SUCCESS; + + if (NULL == krp) { + DPRINTK("%s(): Invalid input parameters, cryptkop = %p\n", + __FUNCTION__, krp); + return EINVAL; + } + + if (CPA_TRUE == atomic_read(&icp_ocfDrvIsExiting)) { + krp->krp_status = ECANCELED; + return ECANCELED; + } + + switch (krp->krp_op) { + case CRK_DH_COMPUTE_KEY: + DPRINTK("%s() doing DH_COMPUTE_KEY\n", __FUNCTION__); + lacStatus = icp_ocfDrvDHComputeKey(krp); + if (CPA_STATUS_SUCCESS != lacStatus) { + EPRINTK("%s(): icp_ocfDrvDHComputeKey failed " + "(%d).\n", __FUNCTION__, lacStatus); + krp->krp_status = ECANCELED; + return ECANCELED; + } + + break; + + case CRK_MOD_EXP: + DPRINTK("%s() doing MOD_EXP \n", __FUNCTION__); + lacStatus = icp_ocfDrvModExp(krp); + if (CPA_STATUS_SUCCESS != lacStatus) { + EPRINTK("%s(): icp_ocfDrvModExp failed (%d).\n", + __FUNCTION__, lacStatus); + krp->krp_status = ECANCELED; + return ECANCELED; + } + + break; + + case CRK_MOD_EXP_CRT: + DPRINTK("%s() doing MOD_EXP_CRT \n", __FUNCTION__); + lacStatus = icp_ocfDrvModExpCRT(krp); + if (CPA_STATUS_SUCCESS != lacStatus) { + EPRINTK("%s(): icp_ocfDrvModExpCRT " + "failed (%d).\n", __FUNCTION__, lacStatus); + krp->krp_status = ECANCELED; + return ECANCELED; + } + + break; + + case CRK_DSA_SIGN: + DPRINTK("%s() doing DSA_SIGN \n", __FUNCTION__); + lacStatus = icp_ocfDrvDsaSign(krp); + if (CPA_STATUS_SUCCESS != lacStatus) { + EPRINTK("%s(): icp_ocfDrvDsaSign " + "failed (%d).\n", __FUNCTION__, lacStatus); + krp->krp_status = ECANCELED; + return ECANCELED; + } + + break; + + case CRK_DSA_VERIFY: + DPRINTK("%s() doing DSA_VERIFY \n", __FUNCTION__); + lacStatus = icp_ocfDrvDsaVerify(krp); + if (CPA_STATUS_SUCCESS != lacStatus) { + EPRINTK("%s(): icp_ocfDrvDsaVerify " + "failed (%d).\n", __FUNCTION__, lacStatus); + krp->krp_status = ECANCELED; + return ECANCELED; + } + + break; + + default: + EPRINTK("%s(): Asymettric function not " + "supported (%d).\n", __FUNCTION__, krp->krp_op); + krp->krp_status = EOPNOTSUPP; + return EOPNOTSUPP; + } + + return ICP_OCF_DRV_STATUS_SUCCESS; +} + +/* Name : icp_ocfDrvSwapBytes + * + * Description : This function is used to swap the byte order of a buffer. + * It has been seen that in general we are passed little endian byte order + * buffers, but LAC only accepts big endian byte order buffers. + */ +static void inline +icp_ocfDrvSwapBytes(u_int8_t * num, u_int32_t buff_len_bytes) +{ + + int i; + u_int8_t *end_ptr; + u_int8_t hold_val; + + end_ptr = num + (buff_len_bytes - 1); + buff_len_bytes = buff_len_bytes >> 1; + for (i = 0; i < buff_len_bytes; i++) { + hold_val = *num; + *num = *end_ptr; + num++; + *end_ptr = hold_val; + end_ptr--; + } +} + +/* Name : icp_ocfDrvDHComputeKey + * + * Description : This function will map Diffie Hellman calls from OCF + * to the LAC API. OCF uses this function for Diffie Hellman Phase1 and + * Phase2. LAC has a separate Diffie Hellman Phase2 call, however both phases + * break down to a modular exponentiation. + */ +static int icp_ocfDrvDHComputeKey(struct cryptkop *krp) +{ + CpaStatus lacStatus = CPA_STATUS_SUCCESS; + void *callbackTag = NULL; + CpaCyDhPhase1KeyGenOpData *pPhase1OpData = NULL; + CpaFlatBuffer *pLocalOctetStringPV = NULL; + uint32_t dh_prime_len_bytes = 0, dh_prime_len_bits = 0; + + /* Input checks - check prime is a multiple of 8 bits to allow for + allocation later */ + dh_prime_len_bits = + (krp->krp_param[ICP_DH_KRP_PARAM_PRIME_INDEX].crp_nbits); + + /* LAC can reject prime lengths based on prime key sizes, we just + need to make sure we can allocate space for the base and + exponent buffers correctly */ + if ((dh_prime_len_bits % NUM_BITS_IN_BYTE) != 0) { + APRINTK("%s(): Warning Prime number buffer size is not a " + "multiple of 8 bits\n", __FUNCTION__); + } + + /* Result storage space should be the same size as the prime as this + value can take up the same amount of storage space */ + if (dh_prime_len_bits != + krp->krp_param[ICP_DH_KRP_PARAM_RESULT_INDEX].crp_nbits) { + DPRINTK("%s(): Return Buffer must be the same size " + "as the Prime buffer\n", __FUNCTION__); + krp->krp_status = EINVAL; + return EINVAL; + } + /* Switch to size in bytes */ + BITS_TO_BYTES(dh_prime_len_bytes, dh_prime_len_bits); + + callbackTag = krp; + + pPhase1OpData = kmem_cache_zalloc(drvDH_zone, GFP_KERNEL); + if (NULL == pPhase1OpData) { + APRINTK("%s():Failed to get memory for key gen data\n", + __FUNCTION__); + krp->krp_status = ENOMEM; + return ENOMEM; + } + + pLocalOctetStringPV = kmem_cache_zalloc(drvFlatBuffer_zone, GFP_KERNEL); + if (NULL == pLocalOctetStringPV) { + APRINTK("%s():Failed to get memory for pLocalOctetStringPV\n", + __FUNCTION__); + kmem_cache_free(drvDH_zone, pPhase1OpData); + krp->krp_status = ENOMEM; + return ENOMEM; + } + + /* Link parameters */ + pPhase1OpData->primeP.pData = + krp->krp_param[ICP_DH_KRP_PARAM_PRIME_INDEX].crp_p; + + pPhase1OpData->primeP.dataLenInBytes = dh_prime_len_bytes; + + icp_ocfDrvSwapBytes(pPhase1OpData->primeP.pData, dh_prime_len_bytes); + + pPhase1OpData->baseG.pData = + krp->krp_param[ICP_DH_KRP_PARAM_BASE_INDEX].crp_p; + + BITS_TO_BYTES(pPhase1OpData->baseG.dataLenInBytes, + krp->krp_param[ICP_DH_KRP_PARAM_BASE_INDEX].crp_nbits); + + icp_ocfDrvSwapBytes(pPhase1OpData->baseG.pData, + pPhase1OpData->baseG.dataLenInBytes); + + pPhase1OpData->privateValueX.pData = + krp->krp_param[ICP_DH_KRP_PARAM_PRIVATE_VALUE_INDEX].crp_p; + + BITS_TO_BYTES(pPhase1OpData->privateValueX.dataLenInBytes, + krp->krp_param[ICP_DH_KRP_PARAM_PRIVATE_VALUE_INDEX]. + crp_nbits); + + icp_ocfDrvSwapBytes(pPhase1OpData->privateValueX.pData, + pPhase1OpData->privateValueX.dataLenInBytes); + + /* Output parameters */ + pLocalOctetStringPV->pData = + krp->krp_param[ICP_DH_KRP_PARAM_RESULT_INDEX].crp_p; + + BITS_TO_BYTES(pLocalOctetStringPV->dataLenInBytes, + krp->krp_param[ICP_DH_KRP_PARAM_RESULT_INDEX].crp_nbits); + + lacStatus = cpaCyDhKeyGenPhase1(CPA_INSTANCE_HANDLE_SINGLE, + icp_ocfDrvDhP1CallBack, + callbackTag, pPhase1OpData, + pLocalOctetStringPV); + + if (CPA_STATUS_SUCCESS != lacStatus) { + EPRINTK("%s(): DH Phase 1 Key Gen failed (%d).\n", + __FUNCTION__, lacStatus); + icp_ocfDrvFreeFlatBuffer(pLocalOctetStringPV); + kmem_cache_free(drvDH_zone, pPhase1OpData); + } + + return lacStatus; +} + +/* Name : icp_ocfDrvModExp + * + * Description : This function will map ordinary Modular Exponentiation calls + * from OCF to the LAC API. + * + */ +static int icp_ocfDrvModExp(struct cryptkop *krp) +{ + CpaStatus lacStatus = CPA_STATUS_SUCCESS; + void *callbackTag = NULL; + CpaCyLnModExpOpData *pModExpOpData = NULL; + CpaFlatBuffer *pResult = NULL; + + if ((krp->krp_param[ICP_MOD_EXP_KRP_PARAM_MODULUS_INDEX].crp_nbits % + NUM_BITS_IN_BYTE) != 0) { + DPRINTK("%s(): Warning - modulus buffer size (%d) is not a " + "multiple of 8 bits\n", __FUNCTION__, + krp->krp_param[ICP_MOD_EXP_KRP_PARAM_MODULUS_INDEX]. + crp_nbits); + } + + /* Result storage space should be the same size as the prime as this + value can take up the same amount of storage space */ + if (krp->krp_param[ICP_MOD_EXP_KRP_PARAM_MODULUS_INDEX].crp_nbits > + krp->krp_param[ICP_MOD_EXP_KRP_PARAM_RESULT_INDEX].crp_nbits) { + APRINTK("%s(): Return Buffer size must be the same or" + " greater than the Modulus buffer\n", __FUNCTION__); + krp->krp_status = EINVAL; + return EINVAL; + } + + callbackTag = krp; + + pModExpOpData = kmem_cache_zalloc(drvLnModExp_zone, GFP_KERNEL); + if (NULL == pModExpOpData) { + APRINTK("%s():Failed to get memory for key gen data\n", + __FUNCTION__); + krp->krp_status = ENOMEM; + return ENOMEM; + } + + pResult = kmem_cache_zalloc(drvFlatBuffer_zone, GFP_KERNEL); + if (NULL == pResult) { + APRINTK("%s():Failed to get memory for ModExp result\n", + __FUNCTION__); + kmem_cache_free(drvLnModExp_zone, pModExpOpData); + krp->krp_status = ENOMEM; + return ENOMEM; + } + + /* Link parameters */ + pModExpOpData->modulus.pData = + krp->krp_param[ICP_MOD_EXP_KRP_PARAM_MODULUS_INDEX].crp_p; + BITS_TO_BYTES(pModExpOpData->modulus.dataLenInBytes, + krp->krp_param[ICP_MOD_EXP_KRP_PARAM_MODULUS_INDEX]. + crp_nbits); + + icp_ocfDrvSwapBytes(pModExpOpData->modulus.pData, + pModExpOpData->modulus.dataLenInBytes); + + /*OCF patch to Openswan Pluto regularly sends the base value as 2 + bits in size. In this case, it has been found it is better to + use the base size memory space as the input buffer (if the number + is in bits is less than a byte, the number of bits is the input + value) */ + if (krp->krp_param[ICP_MOD_EXP_KRP_PARAM_BASE_INDEX].crp_nbits < + NUM_BITS_IN_BYTE) { + DPRINTK("%s : base is small (%d)\n", __FUNCTION__, krp-> + krp_param[ICP_MOD_EXP_KRP_PARAM_BASE_INDEX].crp_nbits); + pModExpOpData->base.dataLenInBytes = SINGLE_BYTE_VALUE; + pModExpOpData->base.pData = + (uint8_t *) & (krp-> + krp_param[ICP_MOD_EXP_KRP_PARAM_BASE_INDEX]. + crp_nbits); + *((uint32_t *) pModExpOpData->base.pData) = + htonl(*((uint32_t *) pModExpOpData->base.pData)); + + } else { + + DPRINTK("%s : base is big (%d)\n", __FUNCTION__, krp-> + krp_param[ICP_MOD_EXP_KRP_PARAM_BASE_INDEX].crp_nbits); + pModExpOpData->base.pData = + krp->krp_param[ICP_MOD_EXP_KRP_PARAM_BASE_INDEX].crp_p; + BITS_TO_BYTES(pModExpOpData->base.dataLenInBytes, + krp->krp_param[ICP_MOD_EXP_KRP_PARAM_BASE_INDEX]. + crp_nbits); + icp_ocfDrvSwapBytes(pModExpOpData->base.pData, + pModExpOpData->base.dataLenInBytes); + } + + pModExpOpData->exponent.pData = + krp->krp_param[ICP_MOD_EXP_KRP_PARAM_EXPONENT_INDEX].crp_p; + BITS_TO_BYTES(pModExpOpData->exponent.dataLenInBytes, + krp->krp_param[ICP_MOD_EXP_KRP_PARAM_EXPONENT_INDEX]. + crp_nbits); + + icp_ocfDrvSwapBytes(pModExpOpData->exponent.pData, + pModExpOpData->exponent.dataLenInBytes); + /* Output parameters */ + pResult->pData = + krp->krp_param[ICP_MOD_EXP_KRP_PARAM_RESULT_INDEX].crp_p, + BITS_TO_BYTES(pResult->dataLenInBytes, + krp->krp_param[ICP_MOD_EXP_KRP_PARAM_RESULT_INDEX]. + crp_nbits); + + lacStatus = cpaCyLnModExp(CPA_INSTANCE_HANDLE_SINGLE, + icp_ocfDrvModExpCallBack, + callbackTag, pModExpOpData, pResult); + + if (CPA_STATUS_SUCCESS != lacStatus) { + EPRINTK("%s(): Mod Exp Operation failed (%d).\n", + __FUNCTION__, lacStatus); + krp->krp_status = ECANCELED; + icp_ocfDrvFreeFlatBuffer(pResult); + kmem_cache_free(drvLnModExp_zone, pModExpOpData); + } + + return lacStatus; +} + +/* Name : icp_ocfDrvModExpCRT + * + * Description : This function will map ordinary Modular Exponentiation Chinese + * Remainder Theorem implementaion calls from OCF to the LAC API. + * + * Note : Mod Exp CRT for this driver is accelerated through LAC RSA type 2 + * decrypt operation. Therefore P and Q input values must always be prime + * numbers. Although basic primality checks are done in LAC, it is up to the + * user to do any correct prime number checking before passing the inputs. + */ + +static int icp_ocfDrvModExpCRT(struct cryptkop *krp) +{ + CpaStatus lacStatus = CPA_STATUS_SUCCESS; + CpaCyRsaDecryptOpData *rsaDecryptOpData = NULL; + void *callbackTag = NULL; + CpaFlatBuffer *pOutputData = NULL; + + /*Parameter input checks are all done by LAC, no need to repeat + them here. */ + callbackTag = krp; + + rsaDecryptOpData = kmem_cache_zalloc(drvRSADecrypt_zone, GFP_KERNEL); + if (NULL == rsaDecryptOpData) { + APRINTK("%s():Failed to get memory" + " for MOD EXP CRT Op data struct\n", __FUNCTION__); + krp->krp_status = ENOMEM; + return ENOMEM; + } + + rsaDecryptOpData->pRecipientPrivateKey + = kmem_cache_zalloc(drvRSAPrivateKey_zone, GFP_KERNEL); + if (NULL == rsaDecryptOpData->pRecipientPrivateKey) { + APRINTK("%s():Failed to get memory for MOD EXP CRT" + " private key values struct\n", __FUNCTION__); + kmem_cache_free(drvRSADecrypt_zone, rsaDecryptOpData); + krp->krp_status = ENOMEM; + return ENOMEM; + } + + rsaDecryptOpData->pRecipientPrivateKey-> + version = CPA_CY_RSA_VERSION_TWO_PRIME; + rsaDecryptOpData->pRecipientPrivateKey-> + privateKeyRepType = CPA_CY_RSA_PRIVATE_KEY_REP_TYPE_2; + + pOutputData = kmem_cache_zalloc(drvFlatBuffer_zone, GFP_KERNEL); + if (NULL == pOutputData) { + APRINTK("%s():Failed to get memory" + " for MOD EXP CRT output data\n", __FUNCTION__); + kmem_cache_free(drvRSAPrivateKey_zone, + rsaDecryptOpData->pRecipientPrivateKey); + kmem_cache_free(drvRSADecrypt_zone, rsaDecryptOpData); + krp->krp_status = ENOMEM; + return ENOMEM; + } + + rsaDecryptOpData->pRecipientPrivateKey-> + version = CPA_CY_RSA_VERSION_TWO_PRIME; + rsaDecryptOpData->pRecipientPrivateKey-> + privateKeyRepType = CPA_CY_RSA_PRIVATE_KEY_REP_TYPE_2; + + /* Link parameters */ + rsaDecryptOpData->inputData.pData = + krp->krp_param[ICP_MOD_EXP_CRT_KRP_PARAM_I_INDEX].crp_p; + BITS_TO_BYTES(rsaDecryptOpData->inputData.dataLenInBytes, + krp->krp_param[ICP_MOD_EXP_CRT_KRP_PARAM_I_INDEX]. + crp_nbits); + + icp_ocfDrvSwapBytes(rsaDecryptOpData->inputData.pData, + rsaDecryptOpData->inputData.dataLenInBytes); + + rsaDecryptOpData->pRecipientPrivateKey->privateKeyRep2.prime1P.pData = + krp->krp_param[ICP_MOD_EXP_CRT_KRP_PARAM_PRIME_P_INDEX].crp_p; + BITS_TO_BYTES(rsaDecryptOpData->pRecipientPrivateKey->privateKeyRep2. + prime1P.dataLenInBytes, + krp->krp_param[ICP_MOD_EXP_CRT_KRP_PARAM_PRIME_P_INDEX]. + crp_nbits); + + icp_ocfDrvSwapBytes(rsaDecryptOpData->pRecipientPrivateKey-> + privateKeyRep2.prime1P.pData, + rsaDecryptOpData->pRecipientPrivateKey-> + privateKeyRep2.prime1P.dataLenInBytes); + + rsaDecryptOpData->pRecipientPrivateKey->privateKeyRep2.prime2Q.pData = + krp->krp_param[ICP_MOD_EXP_CRT_KRP_PARAM_PRIME_Q_INDEX].crp_p; + BITS_TO_BYTES(rsaDecryptOpData->pRecipientPrivateKey->privateKeyRep2. + prime2Q.dataLenInBytes, + krp->krp_param[ICP_MOD_EXP_CRT_KRP_PARAM_PRIME_Q_INDEX]. + crp_nbits); + + icp_ocfDrvSwapBytes(rsaDecryptOpData->pRecipientPrivateKey-> + privateKeyRep2.prime2Q.pData, + rsaDecryptOpData->pRecipientPrivateKey-> + privateKeyRep2.prime2Q.dataLenInBytes); + + rsaDecryptOpData->pRecipientPrivateKey-> + privateKeyRep2.exponent1Dp.pData = + krp->krp_param[ICP_MOD_EXP_CRT_KRP_PARAM_EXPONENT_DP_INDEX].crp_p; + BITS_TO_BYTES(rsaDecryptOpData->pRecipientPrivateKey->privateKeyRep2. + exponent1Dp.dataLenInBytes, + krp-> + krp_param[ICP_MOD_EXP_CRT_KRP_PARAM_EXPONENT_DP_INDEX]. + crp_nbits); + + icp_ocfDrvSwapBytes(rsaDecryptOpData->pRecipientPrivateKey-> + privateKeyRep2.exponent1Dp.pData, + rsaDecryptOpData->pRecipientPrivateKey-> + privateKeyRep2.exponent1Dp.dataLenInBytes); + + rsaDecryptOpData->pRecipientPrivateKey-> + privateKeyRep2.exponent2Dq.pData = + krp->krp_param[ICP_MOD_EXP_CRT_KRP_PARAM_EXPONENT_DQ_INDEX].crp_p; + BITS_TO_BYTES(rsaDecryptOpData->pRecipientPrivateKey-> + privateKeyRep2.exponent2Dq.dataLenInBytes, + krp-> + krp_param[ICP_MOD_EXP_CRT_KRP_PARAM_EXPONENT_DQ_INDEX]. + crp_nbits); + + icp_ocfDrvSwapBytes(rsaDecryptOpData->pRecipientPrivateKey-> + privateKeyRep2.exponent2Dq.pData, + rsaDecryptOpData->pRecipientPrivateKey-> + privateKeyRep2.exponent2Dq.dataLenInBytes); + + rsaDecryptOpData->pRecipientPrivateKey-> + privateKeyRep2.coefficientQInv.pData = + krp->krp_param[ICP_MOD_EXP_CRT_KRP_PARAM_COEFF_QINV_INDEX].crp_p; + BITS_TO_BYTES(rsaDecryptOpData->pRecipientPrivateKey-> + privateKeyRep2.coefficientQInv.dataLenInBytes, + krp-> + krp_param[ICP_MOD_EXP_CRT_KRP_PARAM_COEFF_QINV_INDEX]. + crp_nbits); + + icp_ocfDrvSwapBytes(rsaDecryptOpData->pRecipientPrivateKey-> + privateKeyRep2.coefficientQInv.pData, + rsaDecryptOpData->pRecipientPrivateKey-> + privateKeyRep2.coefficientQInv.dataLenInBytes); + + /* Output Parameter */ + pOutputData->pData = + krp->krp_param[ICP_MOD_EXP_CRT_KRP_PARAM_RESULT_INDEX].crp_p; + BITS_TO_BYTES(pOutputData->dataLenInBytes, + krp->krp_param[ICP_MOD_EXP_CRT_KRP_PARAM_RESULT_INDEX]. + crp_nbits); + + lacStatus = cpaCyRsaDecrypt(CPA_INSTANCE_HANDLE_SINGLE, + icp_ocfDrvModExpCRTCallBack, + callbackTag, rsaDecryptOpData, pOutputData); + + if (CPA_STATUS_SUCCESS != lacStatus) { + EPRINTK("%s(): Mod Exp CRT Operation failed (%d).\n", + __FUNCTION__, lacStatus); + krp->krp_status = ECANCELED; + icp_ocfDrvFreeFlatBuffer(pOutputData); + kmem_cache_free(drvRSAPrivateKey_zone, + rsaDecryptOpData->pRecipientPrivateKey); + kmem_cache_free(drvRSADecrypt_zone, rsaDecryptOpData); + } + + return lacStatus; +} + +/* Name : icp_ocfDrvCheckALessThanB + * + * Description : This function will check whether the first argument is less + * than the second. It is used to check whether the DSA RS sign Random K + * value is less than the Prime Q value (as defined in the specification) + * + */ +static int +icp_ocfDrvCheckALessThanB(CpaFlatBuffer * pK, CpaFlatBuffer * pQ, int *doCheck) +{ + + uint8_t *MSB_K = pK->pData; + uint8_t *MSB_Q = pQ->pData; + uint32_t buffer_lengths_in_bytes = pQ->dataLenInBytes; + + if (DONT_RUN_LESS_THAN_CHECK == *doCheck) { + return FAIL_A_IS_GREATER_THAN_B; + } + +/*Check MSBs +if A == B, check next MSB +if A > B, return A_IS_GREATER_THAN_B +if A < B, return A_IS_LESS_THAN_B (success) +*/ + while (*MSB_K == *MSB_Q) { + MSB_K++; + MSB_Q++; + + buffer_lengths_in_bytes--; + if (0 == buffer_lengths_in_bytes) { + DPRINTK("%s() Buffers have equal value!!\n", + __FUNCTION__); + return FAIL_A_IS_EQUAL_TO_B; + } + + } + + if (*MSB_K < *MSB_Q) { + return SUCCESS_A_IS_LESS_THAN_B; + } else { + return FAIL_A_IS_GREATER_THAN_B; + } + +} + +/* Name : icp_ocfDrvDsaSign + * + * Description : This function will map DSA RS Sign from OCF to the LAC API. + * + * NOTE: From looking at OCF patch to OpenSSL and even the number of input + * parameters, OCF expects us to generate the random seed value. This value + * is generated and passed to LAC, however the number is discared in the + * callback and not returned to the user. + */ +static int icp_ocfDrvDsaSign(struct cryptkop *krp) +{ + CpaStatus lacStatus = CPA_STATUS_SUCCESS; + CpaCyDsaRSSignOpData *dsaRsSignOpData = NULL; + void *callbackTag = NULL; + CpaCyRandGenOpData randGenOpData; + int primeQSizeInBytes = 0; + int doCheck = 0; + CpaFlatBuffer randData; + CpaBoolean protocolStatus = CPA_FALSE; + CpaFlatBuffer *pR = NULL; + CpaFlatBuffer *pS = NULL; + + callbackTag = krp; + + BITS_TO_BYTES(primeQSizeInBytes, + krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_PRIME_Q_INDEX]. + crp_nbits); + + if (DSA_RS_SIGN_PRIMEQ_SIZE_IN_BYTES != primeQSizeInBytes) { + APRINTK("%s(): DSA PRIME Q size not equal to the " + "FIPS defined 20bytes, = %d\n", + __FUNCTION__, primeQSizeInBytes); + krp->krp_status = EDOM; + return EDOM; + } + + dsaRsSignOpData = kmem_cache_zalloc(drvDSARSSign_zone, GFP_KERNEL); + if (NULL == dsaRsSignOpData) { + APRINTK("%s():Failed to get memory" + " for DSA RS Sign Op data struct\n", __FUNCTION__); + krp->krp_status = ENOMEM; + return ENOMEM; + } + + dsaRsSignOpData->K.pData = + kmem_cache_alloc(drvDSARSSignKValue_zone, GFP_ATOMIC); + + if (NULL == dsaRsSignOpData->K.pData) { + APRINTK("%s():Failed to get memory" + " for DSA RS Sign Op Random value\n", __FUNCTION__); + kmem_cache_free(drvDSARSSign_zone, dsaRsSignOpData); + krp->krp_status = ENOMEM; + return ENOMEM; + } + + pR = kmem_cache_zalloc(drvFlatBuffer_zone, GFP_KERNEL); + if (NULL == pR) { + APRINTK("%s():Failed to get memory" + " for DSA signature R\n", __FUNCTION__); + kmem_cache_free(drvDSARSSignKValue_zone, + dsaRsSignOpData->K.pData); + kmem_cache_free(drvDSARSSign_zone, dsaRsSignOpData); + krp->krp_status = ENOMEM; + return ENOMEM; + } + + pS = kmem_cache_zalloc(drvFlatBuffer_zone, GFP_KERNEL); + if (NULL == pS) { + APRINTK("%s():Failed to get memory" + " for DSA signature S\n", __FUNCTION__); + icp_ocfDrvFreeFlatBuffer(pR); + kmem_cache_free(drvDSARSSignKValue_zone, + dsaRsSignOpData->K.pData); + kmem_cache_free(drvDSARSSign_zone, dsaRsSignOpData); + krp->krp_status = ENOMEM; + return ENOMEM; + } + + /*link prime number parameter for ease of processing */ + dsaRsSignOpData->P.pData = + krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_PRIME_P_INDEX].crp_p; + BITS_TO_BYTES(dsaRsSignOpData->P.dataLenInBytes, + krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_PRIME_P_INDEX]. + crp_nbits); + + icp_ocfDrvSwapBytes(dsaRsSignOpData->P.pData, + dsaRsSignOpData->P.dataLenInBytes); + + dsaRsSignOpData->Q.pData = + krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_PRIME_Q_INDEX].crp_p; + BITS_TO_BYTES(dsaRsSignOpData->Q.dataLenInBytes, + krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_PRIME_Q_INDEX]. + crp_nbits); + + icp_ocfDrvSwapBytes(dsaRsSignOpData->Q.pData, + dsaRsSignOpData->Q.dataLenInBytes); + + /*generate random number with equal buffer size to Prime value Q, + but value less than Q */ + dsaRsSignOpData->K.dataLenInBytes = dsaRsSignOpData->Q.dataLenInBytes; + + randGenOpData.generateBits = CPA_TRUE; + randGenOpData.lenInBytes = dsaRsSignOpData->K.dataLenInBytes; + + icp_ocfDrvPtrAndLenToFlatBuffer(dsaRsSignOpData->K.pData, + dsaRsSignOpData->K.dataLenInBytes, + &randData); + + doCheck = 0; + while (icp_ocfDrvCheckALessThanB(&(dsaRsSignOpData->K), + &(dsaRsSignOpData->Q), &doCheck)) { + + if (CPA_STATUS_SUCCESS + != cpaCyRandGen(CPA_INSTANCE_HANDLE_SINGLE, + NULL, NULL, &randGenOpData, &randData)) { + APRINTK("%s(): ERROR - Failed to generate DSA RS Sign K" + "value\n", __FUNCTION__); + icp_ocfDrvFreeFlatBuffer(pS); + icp_ocfDrvFreeFlatBuffer(pR); + kmem_cache_free(drvDSARSSignKValue_zone, + dsaRsSignOpData->K.pData); + kmem_cache_free(drvDSARSSign_zone, dsaRsSignOpData); + krp->krp_status = EAGAIN; + return EAGAIN; + } + + doCheck++; + if (DSA_SIGN_RAND_GEN_VAL_CHECK_MAX_ITERATIONS == doCheck) { + APRINTK("%s(): ERROR - Failed to find DSA RS Sign K " + "value less than Q value\n", __FUNCTION__); + icp_ocfDrvFreeFlatBuffer(pS); + icp_ocfDrvFreeFlatBuffer(pR); + kmem_cache_free(drvDSARSSignKValue_zone, + dsaRsSignOpData->K.pData); + kmem_cache_free(drvDSARSSign_zone, dsaRsSignOpData); + krp->krp_status = EAGAIN; + return EAGAIN; + } + + } + /*Rand Data - no need to swap bytes for pK */ + + /* Link parameters */ + dsaRsSignOpData->G.pData = + krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_G_INDEX].crp_p; + BITS_TO_BYTES(dsaRsSignOpData->G.dataLenInBytes, + krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_G_INDEX].crp_nbits); + + icp_ocfDrvSwapBytes(dsaRsSignOpData->G.pData, + dsaRsSignOpData->G.dataLenInBytes); + + dsaRsSignOpData->X.pData = + krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_X_INDEX].crp_p; + BITS_TO_BYTES(dsaRsSignOpData->X.dataLenInBytes, + krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_X_INDEX].crp_nbits); + icp_ocfDrvSwapBytes(dsaRsSignOpData->X.pData, + dsaRsSignOpData->X.dataLenInBytes); + + dsaRsSignOpData->M.pData = + krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_DGST_INDEX].crp_p; + BITS_TO_BYTES(dsaRsSignOpData->M.dataLenInBytes, + krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_DGST_INDEX]. + crp_nbits); + icp_ocfDrvSwapBytes(dsaRsSignOpData->M.pData, + dsaRsSignOpData->M.dataLenInBytes); + + /* Output Parameters */ + pS->pData = krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_S_RESULT_INDEX].crp_p; + BITS_TO_BYTES(pS->dataLenInBytes, + krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_S_RESULT_INDEX]. + crp_nbits); + + pR->pData = krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_R_RESULT_INDEX].crp_p; + BITS_TO_BYTES(pR->dataLenInBytes, + krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_R_RESULT_INDEX]. + crp_nbits); + + lacStatus = cpaCyDsaSignRS(CPA_INSTANCE_HANDLE_SINGLE, + icp_ocfDrvDsaRSSignCallBack, + callbackTag, dsaRsSignOpData, + &protocolStatus, pR, pS); + + if (CPA_STATUS_SUCCESS != lacStatus) { + EPRINTK("%s(): DSA RS Sign Operation failed (%d).\n", + __FUNCTION__, lacStatus); + krp->krp_status = ECANCELED; + icp_ocfDrvFreeFlatBuffer(pS); + icp_ocfDrvFreeFlatBuffer(pR); + kmem_cache_free(drvDSARSSignKValue_zone, + dsaRsSignOpData->K.pData); + kmem_cache_free(drvDSARSSign_zone, dsaRsSignOpData); + } + + return lacStatus; +} + +/* Name : icp_ocfDrvDsaVerify + * + * Description : This function will map DSA RS Verify from OCF to the LAC API. + * + */ +static int icp_ocfDrvDsaVerify(struct cryptkop *krp) +{ + CpaStatus lacStatus = CPA_STATUS_SUCCESS; + CpaCyDsaVerifyOpData *dsaVerifyOpData = NULL; + void *callbackTag = NULL; + CpaBoolean verifyStatus = CPA_FALSE; + + callbackTag = krp; + + dsaVerifyOpData = kmem_cache_zalloc(drvDSAVerify_zone, GFP_KERNEL); + if (NULL == dsaVerifyOpData) { + APRINTK("%s():Failed to get memory" + " for DSA Verify Op data struct\n", __FUNCTION__); + krp->krp_status = ENOMEM; + return ENOMEM; + } + + /* Link parameters */ + dsaVerifyOpData->P.pData = + krp->krp_param[ICP_DSA_VERIFY_KRP_PARAM_PRIME_P_INDEX].crp_p; + BITS_TO_BYTES(dsaVerifyOpData->P.dataLenInBytes, + krp->krp_param[ICP_DSA_VERIFY_KRP_PARAM_PRIME_P_INDEX]. + crp_nbits); + icp_ocfDrvSwapBytes(dsaVerifyOpData->P.pData, + dsaVerifyOpData->P.dataLenInBytes); + + dsaVerifyOpData->Q.pData = + krp->krp_param[ICP_DSA_VERIFY_KRP_PARAM_PRIME_Q_INDEX].crp_p; + BITS_TO_BYTES(dsaVerifyOpData->Q.dataLenInBytes, + krp->krp_param[ICP_DSA_VERIFY_KRP_PARAM_PRIME_Q_INDEX]. + crp_nbits); + icp_ocfDrvSwapBytes(dsaVerifyOpData->Q.pData, + dsaVerifyOpData->Q.dataLenInBytes); + + dsaVerifyOpData->G.pData = + krp->krp_param[ICP_DSA_VERIFY_KRP_PARAM_G_INDEX].crp_p; + BITS_TO_BYTES(dsaVerifyOpData->G.dataLenInBytes, + krp->krp_param[ICP_DSA_VERIFY_KRP_PARAM_G_INDEX]. + crp_nbits); + icp_ocfDrvSwapBytes(dsaVerifyOpData->G.pData, + dsaVerifyOpData->G.dataLenInBytes); + + dsaVerifyOpData->Y.pData = + krp->krp_param[ICP_DSA_VERIFY_KRP_PARAM_PUBKEY_INDEX].crp_p; + BITS_TO_BYTES(dsaVerifyOpData->Y.dataLenInBytes, + krp->krp_param[ICP_DSA_VERIFY_KRP_PARAM_PUBKEY_INDEX]. + crp_nbits); + icp_ocfDrvSwapBytes(dsaVerifyOpData->Y.pData, + dsaVerifyOpData->Y.dataLenInBytes); + + dsaVerifyOpData->M.pData = + krp->krp_param[ICP_DSA_VERIFY_KRP_PARAM_DGST_INDEX].crp_p; + BITS_TO_BYTES(dsaVerifyOpData->M.dataLenInBytes, + krp->krp_param[ICP_DSA_VERIFY_KRP_PARAM_DGST_INDEX]. + crp_nbits); + icp_ocfDrvSwapBytes(dsaVerifyOpData->M.pData, + dsaVerifyOpData->M.dataLenInBytes); + + dsaVerifyOpData->R.pData = + krp->krp_param[ICP_DSA_VERIFY_KRP_PARAM_SIG_R_INDEX].crp_p; + BITS_TO_BYTES(dsaVerifyOpData->R.dataLenInBytes, + krp->krp_param[ICP_DSA_VERIFY_KRP_PARAM_SIG_R_INDEX]. + crp_nbits); + icp_ocfDrvSwapBytes(dsaVerifyOpData->R.pData, + dsaVerifyOpData->R.dataLenInBytes); + + dsaVerifyOpData->S.pData = + krp->krp_param[ICP_DSA_VERIFY_KRP_PARAM_SIG_S_INDEX].crp_p; + BITS_TO_BYTES(dsaVerifyOpData->S.dataLenInBytes, + krp->krp_param[ICP_DSA_VERIFY_KRP_PARAM_SIG_S_INDEX]. + crp_nbits); + icp_ocfDrvSwapBytes(dsaVerifyOpData->S.pData, + dsaVerifyOpData->S.dataLenInBytes); + + lacStatus = cpaCyDsaVerify(CPA_INSTANCE_HANDLE_SINGLE, + icp_ocfDrvDsaVerifyCallBack, + callbackTag, dsaVerifyOpData, &verifyStatus); + + if (CPA_STATUS_SUCCESS != lacStatus) { + EPRINTK("%s(): DSA Verify Operation failed (%d).\n", + __FUNCTION__, lacStatus); + kmem_cache_free(drvDSAVerify_zone, dsaVerifyOpData); + krp->krp_status = ECANCELED; + } + + return lacStatus; +} + +/* Name : icp_ocfDrvReadRandom + * + * Description : This function will map RNG functionality calls from OCF + * to the LAC API. + */ +int icp_ocfDrvReadRandom(void *arg, uint32_t * buf, int maxwords) +{ + CpaStatus lacStatus = CPA_STATUS_SUCCESS; + CpaCyRandGenOpData randGenOpData; + CpaFlatBuffer randData; + + if (NULL == buf) { + APRINTK("%s(): Invalid input parameters\n", __FUNCTION__); + return EINVAL; + } + + /* maxwords here is number of integers to generate data for */ + randGenOpData.generateBits = CPA_TRUE; + + randGenOpData.lenInBytes = maxwords * sizeof(uint32_t); + + icp_ocfDrvPtrAndLenToFlatBuffer((Cpa8U *) buf, + randGenOpData.lenInBytes, &randData); + + lacStatus = cpaCyRandGen(CPA_INSTANCE_HANDLE_SINGLE, + NULL, NULL, &randGenOpData, &randData); + if (CPA_STATUS_SUCCESS != lacStatus) { + EPRINTK("%s(): icp_LacSymRandGen failed (%d). \n", + __FUNCTION__, lacStatus); + return RETURN_RAND_NUM_GEN_FAILED; + } + + return randGenOpData.lenInBytes / sizeof(uint32_t); +} + +/* Name : icp_ocfDrvDhP1Callback + * + * Description : When this function returns it signifies that the LAC + * component has completed the DH operation. + */ +static void +icp_ocfDrvDhP1CallBack(void *callbackTag, + CpaStatus status, + void *pOpData, CpaFlatBuffer * pLocalOctetStringPV) +{ + struct cryptkop *krp = NULL; + CpaCyDhPhase1KeyGenOpData *pPhase1OpData = NULL; + + if (NULL == callbackTag) { + DPRINTK("%s(): Invalid input parameters - " + "callbackTag data is NULL\n", __FUNCTION__); + return; + } + krp = (struct cryptkop *)callbackTag; + + if (NULL == pOpData) { + DPRINTK("%s(): Invalid input parameters - " + "Operation Data is NULL\n", __FUNCTION__); + krp->krp_status = ECANCELED; + crypto_kdone(krp); + return; + } + pPhase1OpData = (CpaCyDhPhase1KeyGenOpData *) pOpData; + + if (NULL == pLocalOctetStringPV) { + DPRINTK("%s(): Invalid input parameters - " + "pLocalOctetStringPV Data is NULL\n", __FUNCTION__); + memset(pPhase1OpData, 0, sizeof(CpaCyDhPhase1KeyGenOpData)); + kmem_cache_free(drvDH_zone, pPhase1OpData); + krp->krp_status = ECANCELED; + crypto_kdone(krp); + return; + } + + if (CPA_STATUS_SUCCESS == status) { + krp->krp_status = CRYPTO_OP_SUCCESS; + } else { + APRINTK("%s(): Diffie Hellman Phase1 Key Gen failed - " + "Operation Status = %d\n", __FUNCTION__, status); + krp->krp_status = ECANCELED; + } + + icp_ocfDrvSwapBytes(pLocalOctetStringPV->pData, + pLocalOctetStringPV->dataLenInBytes); + + icp_ocfDrvFreeFlatBuffer(pLocalOctetStringPV); + memset(pPhase1OpData, 0, sizeof(CpaCyDhPhase1KeyGenOpData)); + kmem_cache_free(drvDH_zone, pPhase1OpData); + + crypto_kdone(krp); + + return; +} + +/* Name : icp_ocfDrvModExpCallBack + * + * Description : When this function returns it signifies that the LAC + * component has completed the Mod Exp operation. + */ +static void +icp_ocfDrvModExpCallBack(void *callbackTag, + CpaStatus status, + void *pOpdata, CpaFlatBuffer * pResult) +{ + struct cryptkop *krp = NULL; + CpaCyLnModExpOpData *pLnModExpOpData = NULL; + + if (NULL == callbackTag) { + DPRINTK("%s(): Invalid input parameters - " + "callbackTag data is NULL\n", __FUNCTION__); + return; + } + krp = (struct cryptkop *)callbackTag; + + if (NULL == pOpdata) { + DPRINTK("%s(): Invalid Mod Exp input parameters - " + "Operation Data is NULL\n", __FUNCTION__); + krp->krp_status = ECANCELED; + crypto_kdone(krp); + return; + } + pLnModExpOpData = (CpaCyLnModExpOpData *) pOpdata; + + if (NULL == pResult) { + DPRINTK("%s(): Invalid input parameters - " + "pResult data is NULL\n", __FUNCTION__); + krp->krp_status = ECANCELED; + memset(pLnModExpOpData, 0, sizeof(CpaCyLnModExpOpData)); + kmem_cache_free(drvLnModExp_zone, pLnModExpOpData); + crypto_kdone(krp); + return; + } + + if (CPA_STATUS_SUCCESS == status) { + krp->krp_status = CRYPTO_OP_SUCCESS; + } else { + APRINTK("%s(): LAC Mod Exp Operation failed - " + "Operation Status = %d\n", __FUNCTION__, status); + krp->krp_status = ECANCELED; + } + + icp_ocfDrvSwapBytes(pResult->pData, pResult->dataLenInBytes); + + /*switch base size value back to original */ + if (pLnModExpOpData->base.pData == + (uint8_t *) & (krp-> + krp_param[ICP_MOD_EXP_KRP_PARAM_BASE_INDEX]. + crp_nbits)) { + *((uint32_t *) pLnModExpOpData->base.pData) = + ntohl(*((uint32_t *) pLnModExpOpData->base.pData)); + } + icp_ocfDrvFreeFlatBuffer(pResult); + memset(pLnModExpOpData, 0, sizeof(CpaCyLnModExpOpData)); + kmem_cache_free(drvLnModExp_zone, pLnModExpOpData); + + crypto_kdone(krp); + + return; + +} + +/* Name : icp_ocfDrvModExpCRTCallBack + * + * Description : When this function returns it signifies that the LAC + * component has completed the Mod Exp CRT operation. + */ +static void +icp_ocfDrvModExpCRTCallBack(void *callbackTag, + CpaStatus status, + void *pOpData, CpaFlatBuffer * pOutputData) +{ + struct cryptkop *krp = NULL; + CpaCyRsaDecryptOpData *pDecryptData = NULL; + + if (NULL == callbackTag) { + DPRINTK("%s(): Invalid input parameters - " + "callbackTag data is NULL\n", __FUNCTION__); + return; + } + + krp = (struct cryptkop *)callbackTag; + + if (NULL == pOpData) { + DPRINTK("%s(): Invalid input parameters - " + "Operation Data is NULL\n", __FUNCTION__); + krp->krp_status = ECANCELED; + crypto_kdone(krp); + return; + } + pDecryptData = (CpaCyRsaDecryptOpData *) pOpData; + + if (NULL == pOutputData) { + DPRINTK("%s(): Invalid input parameter - " + "pOutputData is NULL\n", __FUNCTION__); + memset(pDecryptData->pRecipientPrivateKey, 0, + sizeof(CpaCyRsaPrivateKey)); + kmem_cache_free(drvRSAPrivateKey_zone, + pDecryptData->pRecipientPrivateKey); + memset(pDecryptData, 0, sizeof(CpaCyRsaDecryptOpData)); + kmem_cache_free(drvRSADecrypt_zone, pDecryptData); + krp->krp_status = ECANCELED; + crypto_kdone(krp); + return; + } + + if (CPA_STATUS_SUCCESS == status) { + krp->krp_status = CRYPTO_OP_SUCCESS; + } else { + APRINTK("%s(): LAC Mod Exp CRT operation failed - " + "Operation Status = %d\n", __FUNCTION__, status); + krp->krp_status = ECANCELED; + } + + icp_ocfDrvSwapBytes(pOutputData->pData, pOutputData->dataLenInBytes); + + icp_ocfDrvFreeFlatBuffer(pOutputData); + memset(pDecryptData->pRecipientPrivateKey, 0, + sizeof(CpaCyRsaPrivateKey)); + kmem_cache_free(drvRSAPrivateKey_zone, + pDecryptData->pRecipientPrivateKey); + memset(pDecryptData, 0, sizeof(CpaCyRsaDecryptOpData)); + kmem_cache_free(drvRSADecrypt_zone, pDecryptData); + + crypto_kdone(krp); + + return; +} + +/* Name : icp_ocfDrvDsaRSSignCallBack + * + * Description : When this function returns it signifies that the LAC + * component has completed the DSA RS sign operation. + */ +static void +icp_ocfDrvDsaRSSignCallBack(void *callbackTag, + CpaStatus status, + void *pOpData, + CpaBoolean protocolStatus, + CpaFlatBuffer * pR, CpaFlatBuffer * pS) +{ + struct cryptkop *krp = NULL; + CpaCyDsaRSSignOpData *pSignData = NULL; + + if (NULL == callbackTag) { + DPRINTK("%s(): Invalid input parameters - " + "callbackTag data is NULL\n", __FUNCTION__); + return; + } + + krp = (struct cryptkop *)callbackTag; + + if (NULL == pOpData) { + DPRINTK("%s(): Invalid input parameters - " + "Operation Data is NULL\n", __FUNCTION__); + krp->krp_status = ECANCELED; + crypto_kdone(krp); + return; + } + pSignData = (CpaCyDsaRSSignOpData *) pOpData; + + if (NULL == pR) { + DPRINTK("%s(): Invalid input parameter - " + "pR sign is NULL\n", __FUNCTION__); + icp_ocfDrvFreeFlatBuffer(pS); + kmem_cache_free(drvDSARSSign_zone, pSignData); + krp->krp_status = ECANCELED; + crypto_kdone(krp); + return; + } + + if (NULL == pS) { + DPRINTK("%s(): Invalid input parameter - " + "pS sign is NULL\n", __FUNCTION__); + icp_ocfDrvFreeFlatBuffer(pR); + kmem_cache_free(drvDSARSSign_zone, pSignData); + krp->krp_status = ECANCELED; + crypto_kdone(krp); + return; + } + + if (CPA_STATUS_SUCCESS != status) { + APRINTK("%s(): LAC DSA RS Sign operation failed - " + "Operation Status = %d\n", __FUNCTION__, status); + krp->krp_status = ECANCELED; + } else { + krp->krp_status = CRYPTO_OP_SUCCESS; + + if (CPA_TRUE != protocolStatus) { + DPRINTK("%s(): LAC DSA RS Sign operation failed due " + "to protocol error\n", __FUNCTION__); + krp->krp_status = EIO; + } + } + + /* Swap bytes only when the callback status is successful and + protocolStatus is set to true */ + if (CPA_STATUS_SUCCESS == status && CPA_TRUE == protocolStatus) { + icp_ocfDrvSwapBytes(pR->pData, pR->dataLenInBytes); + icp_ocfDrvSwapBytes(pS->pData, pS->dataLenInBytes); + } + + icp_ocfDrvFreeFlatBuffer(pR); + icp_ocfDrvFreeFlatBuffer(pS); + memset(pSignData->K.pData, 0, pSignData->K.dataLenInBytes); + kmem_cache_free(drvDSARSSignKValue_zone, pSignData->K.pData); + memset(pSignData, 0, sizeof(CpaCyDsaRSSignOpData)); + kmem_cache_free(drvDSARSSign_zone, pSignData); + crypto_kdone(krp); + + return; +} + +/* Name : icp_ocfDrvDsaVerifyCallback + * + * Description : When this function returns it signifies that the LAC + * component has completed the DSA Verify operation. + */ +static void +icp_ocfDrvDsaVerifyCallBack(void *callbackTag, + CpaStatus status, + void *pOpData, CpaBoolean verifyStatus) +{ + + struct cryptkop *krp = NULL; + CpaCyDsaVerifyOpData *pVerData = NULL; + + if (NULL == callbackTag) { + DPRINTK("%s(): Invalid input parameters - " + "callbackTag data is NULL\n", __FUNCTION__); + return; + } + + krp = (struct cryptkop *)callbackTag; + + if (NULL == pOpData) { + DPRINTK("%s(): Invalid input parameters - " + "Operation Data is NULL\n", __FUNCTION__); + krp->krp_status = ECANCELED; + crypto_kdone(krp); + return; + } + pVerData = (CpaCyDsaVerifyOpData *) pOpData; + + if (CPA_STATUS_SUCCESS != status) { + APRINTK("%s(): LAC DSA Verify operation failed - " + "Operation Status = %d\n", __FUNCTION__, status); + krp->krp_status = ECANCELED; + } else { + krp->krp_status = CRYPTO_OP_SUCCESS; + + if (CPA_TRUE != verifyStatus) { + DPRINTK("%s(): DSA signature invalid\n", __FUNCTION__); + krp->krp_status = EIO; + } + } + + /* Swap bytes only when the callback status is successful and + verifyStatus is set to true */ + /*Just swapping back the key values for now. Possibly all + swapped buffers need to be reverted */ + if (CPA_STATUS_SUCCESS == status && CPA_TRUE == verifyStatus) { + icp_ocfDrvSwapBytes(pVerData->R.pData, + pVerData->R.dataLenInBytes); + icp_ocfDrvSwapBytes(pVerData->S.pData, + pVerData->S.dataLenInBytes); + } + + memset(pVerData, 0, sizeof(CpaCyDsaVerifyOpData)); + kmem_cache_free(drvDSAVerify_zone, pVerData); + crypto_kdone(krp); + + return; +} diff --git a/target/linux/generic-2.6/files/crypto/ocf/ep80579/icp_common.c b/target/linux/generic-2.6/files/crypto/ocf/ep80579/icp_common.c new file mode 100644 index 0000000000..461370c2c7 --- /dev/null +++ b/target/linux/generic-2.6/files/crypto/ocf/ep80579/icp_common.c @@ -0,0 +1,891 @@ +/*************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2007,2008 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * The full GNU General Public License is included in this distribution + * in the file called LICENSE.GPL. + * + * Contact Information: + * Intel Corporation + * + * BSD LICENSE + * + * Copyright(c) 2007,2008 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + * version: Security.L.1.0.130 + * + ***************************************************************************/ + +/* + * An OCF module that uses Intel® QuickAssist Integrated Accelerator to do the + * crypto. + * + * This driver requires the ICP Access Library that is available from Intel in + * order to operate. + */ + +#include "icp_ocf.h" + +#define ICP_OCF_COMP_NAME "ICP_OCF" +#define ICP_OCF_VER_MAIN (2) +#define ICP_OCF_VER_MJR (0) +#define ICP_OCF_VER_MNR (0) + +#define MAX_DEREG_RETRIES (100) +#define DEFAULT_DEREG_RETRIES (10) +#define DEFAULT_DEREG_DELAY_IN_JIFFIES (10) + +/* This defines the maximum number of sessions possible between OCF + and the OCF Tolapai Driver. If set to zero, there is no limit. */ +#define DEFAULT_OCF_TO_DRV_MAX_SESSION_COUNT (0) +#define NUM_SUPPORTED_CAPABILITIES (21) + +/*Slabs zones*/ +struct kmem_cache *drvSessionData_zone = NULL; +struct kmem_cache *drvOpData_zone = NULL; +struct kmem_cache *drvDH_zone = NULL; +struct kmem_cache *drvLnModExp_zone = NULL; +struct kmem_cache *drvRSADecrypt_zone = NULL; +struct kmem_cache *drvRSAPrivateKey_zone = NULL; +struct kmem_cache *drvDSARSSign_zone = NULL; +struct kmem_cache *drvDSARSSignKValue_zone = NULL; +struct kmem_cache *drvDSAVerify_zone = NULL; + +/*Slab zones for flatbuffers and bufferlist*/ +struct kmem_cache *drvFlatBuffer_zone = NULL; + +static int icp_ocfDrvInit(void); +static void icp_ocfDrvExit(void); +static void icp_ocfDrvFreeCaches(void); +static void icp_ocfDrvDeferedFreeLacSessionProcess(void *arg); + +int32_t icp_ocfDrvDriverId = INVALID_DRIVER_ID; + +/* Module parameter - gives the number of times LAC deregistration shall be + re-tried */ +int num_dereg_retries = DEFAULT_DEREG_RETRIES; + +/* Module parameter - gives the delay time in jiffies before a LAC session + shall be attempted to be deregistered again */ +int dereg_retry_delay_in_jiffies = DEFAULT_DEREG_DELAY_IN_JIFFIES; + +/* Module parameter - gives the maximum number of sessions possible between + OCF and the OCF Tolapai Driver. If set to zero, there is no limit.*/ +int max_sessions = DEFAULT_OCF_TO_DRV_MAX_SESSION_COUNT; + +/* This is set when the module is removed from the system, no further + processing can take place if this is set */ +atomic_t icp_ocfDrvIsExiting = ATOMIC_INIT(0); + +/* This is used to show how many lac sessions were not deregistered*/ +atomic_t lac_session_failed_dereg_count = ATOMIC_INIT(0); + +/* This is used to track the number of registered sessions between OCF and + * and the OCF Tolapai driver, when max_session is set to value other than + * zero. This ensures that the max_session set for the OCF and the driver + * is equal to the LAC registered sessions */ +atomic_t num_ocf_to_drv_registered_sessions = ATOMIC_INIT(0); + +/* Head of linked list used to store session data */ +struct list_head icp_ocfDrvGlobalSymListHead; +struct list_head icp_ocfDrvGlobalSymListHead_FreeMemList; + +spinlock_t icp_ocfDrvSymSessInfoListSpinlock = SPIN_LOCK_UNLOCKED; +rwlock_t icp_kmem_cache_destroy_alloc_lock = RW_LOCK_UNLOCKED; + +struct workqueue_struct *icp_ocfDrvFreeLacSessionWorkQ; + +struct icp_drvBuffListInfo defBuffListInfo; + +static struct { + softc_device_decl sc_dev; +} icpDev; + +static device_method_t icp_methods = { + /* crypto device methods */ + DEVMETHOD(cryptodev_newsession, icp_ocfDrvNewSession), + DEVMETHOD(cryptodev_freesession, icp_ocfDrvFreeLACSession), + DEVMETHOD(cryptodev_process, icp_ocfDrvSymProcess), + DEVMETHOD(cryptodev_kprocess, icp_ocfDrvPkeProcess), +}; + +module_param(num_dereg_retries, int, S_IRUGO); +module_param(dereg_retry_delay_in_jiffies, int, S_IRUGO); +module_param(max_sessions, int, S_IRUGO); + +MODULE_PARM_DESC(num_dereg_retries, + "Number of times to retry LAC Sym Session Deregistration. " + "Default 10, Max 100"); +MODULE_PARM_DESC(dereg_retry_delay_in_jiffies, "Delay in jiffies " + "(added to a schedule() function call) before a LAC Sym " + "Session Dereg is retried. Default 10"); +MODULE_PARM_DESC(max_sessions, "This sets the maximum number of sessions " + "between OCF and this driver. If this value is set to zero, " + "max session count checking is disabled. Default is zero(0)"); + +/* Name : icp_ocfDrvInit + * + * Description : This function will register all the symmetric and asymmetric + * functionality that will be accelerated by the hardware. It will also + * get a unique driver ID from the OCF and initialise all slab caches + */ +static int __init icp_ocfDrvInit(void) +{ + int ocfStatus = 0; + + IPRINTK("=== %s ver %d.%d.%d ===\n", ICP_OCF_COMP_NAME, + ICP_OCF_VER_MAIN, ICP_OCF_VER_MJR, ICP_OCF_VER_MNR); + + if (MAX_DEREG_RETRIES < num_dereg_retries) { + EPRINTK("Session deregistration retry count set to greater " + "than %d", MAX_DEREG_RETRIES); + return -1; + } + + /* Initialize and Start the Cryptographic component */ + if (CPA_STATUS_SUCCESS != + cpaCyStartInstance(CPA_INSTANCE_HANDLE_SINGLE)) { + EPRINTK("Failed to initialize and start the instance " + "of the Cryptographic component.\n"); + return -1; + } + + /* Set the default size of BufferList to allocate */ + memset(&defBuffListInfo, 0, sizeof(struct icp_drvBuffListInfo)); + if (ICP_OCF_DRV_STATUS_SUCCESS != + icp_ocfDrvBufferListMemInfo(ICP_OCF_DRV_DEFAULT_BUFFLIST_ARRAYS, + &defBuffListInfo)) { + EPRINTK("Failed to get bufferlist memory info.\n"); + return -1; + } + + /*Register OCF Tolapai Driver with OCF */ + memset(&icpDev, 0, sizeof(icpDev)); + softc_device_init(&icpDev, "icp", 0, icp_methods); + + icp_ocfDrvDriverId = crypto_get_driverid(softc_get_device(&icpDev), + CRYPTOCAP_F_HARDWARE); + + if (icp_ocfDrvDriverId < 0) { + EPRINTK("%s : ICP driver failed to register with OCF!\n", + __FUNCTION__); + return -ENODEV; + } + + /*Create all the slab caches used by the OCF Tolapai Driver */ + drvSessionData_zone = + ICP_CACHE_CREATE("ICP Session Data", struct icp_drvSessionData); + ICP_CACHE_NULL_CHECK(drvSessionData_zone); + + /* + * Allocation of the OpData includes the allocation space for meta data. + * The memory after the opData structure is reserved for this meta data. + */ + drvOpData_zone = + kmem_cache_create("ICP Op Data", sizeof(struct icp_drvOpData) + + defBuffListInfo.metaSize ,0, SLAB_HWCACHE_ALIGN, NULL, NULL); + + + ICP_CACHE_NULL_CHECK(drvOpData_zone); + + drvDH_zone = ICP_CACHE_CREATE("ICP DH data", CpaCyDhPhase1KeyGenOpData); + ICP_CACHE_NULL_CHECK(drvDH_zone); + + drvLnModExp_zone = + ICP_CACHE_CREATE("ICP ModExp data", CpaCyLnModExpOpData); + ICP_CACHE_NULL_CHECK(drvLnModExp_zone); + + drvRSADecrypt_zone = + ICP_CACHE_CREATE("ICP RSA decrypt data", CpaCyRsaDecryptOpData); + ICP_CACHE_NULL_CHECK(drvRSADecrypt_zone); + + drvRSAPrivateKey_zone = + ICP_CACHE_CREATE("ICP RSA private key data", CpaCyRsaPrivateKey); + ICP_CACHE_NULL_CHECK(drvRSAPrivateKey_zone); + + drvDSARSSign_zone = + ICP_CACHE_CREATE("ICP DSA Sign", CpaCyDsaRSSignOpData); + ICP_CACHE_NULL_CHECK(drvDSARSSign_zone); + + /*too awkward to use a macro here */ + drvDSARSSignKValue_zone = + kmem_cache_create("ICP DSA Sign Rand Val", + DSA_RS_SIGN_PRIMEQ_SIZE_IN_BYTES, 0, + SLAB_HWCACHE_ALIGN, NULL, NULL); + ICP_CACHE_NULL_CHECK(drvDSARSSignKValue_zone); + + drvDSAVerify_zone = + ICP_CACHE_CREATE("ICP DSA Verify", CpaCyDsaVerifyOpData); + ICP_CACHE_NULL_CHECK(drvDSAVerify_zone); + + drvFlatBuffer_zone = + ICP_CACHE_CREATE("ICP Flat Buffers", CpaFlatBuffer); + ICP_CACHE_NULL_CHECK(drvFlatBuffer_zone); + + /* Register the ICP symmetric crypto support. */ + ICP_REGISTER_SYM_FUNCTIONALITY_WITH_OCF(CRYPTO_NULL_CBC); + ICP_REGISTER_SYM_FUNCTIONALITY_WITH_OCF(CRYPTO_DES_CBC); + ICP_REGISTER_SYM_FUNCTIONALITY_WITH_OCF(CRYPTO_3DES_CBC); + ICP_REGISTER_SYM_FUNCTIONALITY_WITH_OCF(CRYPTO_AES_CBC); + ICP_REGISTER_SYM_FUNCTIONALITY_WITH_OCF(CRYPTO_ARC4); + ICP_REGISTER_SYM_FUNCTIONALITY_WITH_OCF(CRYPTO_MD5); + ICP_REGISTER_SYM_FUNCTIONALITY_WITH_OCF(CRYPTO_MD5_HMAC); + ICP_REGISTER_SYM_FUNCTIONALITY_WITH_OCF(CRYPTO_SHA1); + ICP_REGISTER_SYM_FUNCTIONALITY_WITH_OCF(CRYPTO_SHA1_HMAC); + ICP_REGISTER_SYM_FUNCTIONALITY_WITH_OCF(CRYPTO_SHA2_256); + ICP_REGISTER_SYM_FUNCTIONALITY_WITH_OCF(CRYPTO_SHA2_256_HMAC); + ICP_REGISTER_SYM_FUNCTIONALITY_WITH_OCF(CRYPTO_SHA2_384); + ICP_REGISTER_SYM_FUNCTIONALITY_WITH_OCF(CRYPTO_SHA2_384_HMAC); + ICP_REGISTER_SYM_FUNCTIONALITY_WITH_OCF(CRYPTO_SHA2_512); + ICP_REGISTER_SYM_FUNCTIONALITY_WITH_OCF(CRYPTO_SHA2_512_HMAC); + + /* Register the ICP asymmetric algorithm support */ + ICP_REGISTER_ASYM_FUNCTIONALITY_WITH_OCF(CRK_DH_COMPUTE_KEY); + ICP_REGISTER_ASYM_FUNCTIONALITY_WITH_OCF(CRK_MOD_EXP); + ICP_REGISTER_ASYM_FUNCTIONALITY_WITH_OCF(CRK_MOD_EXP_CRT); + ICP_REGISTER_ASYM_FUNCTIONALITY_WITH_OCF(CRK_DSA_SIGN); + ICP_REGISTER_ASYM_FUNCTIONALITY_WITH_OCF(CRK_DSA_VERIFY); + + /* Register the ICP random number generator support */ + if (OCF_REGISTRATION_STATUS_SUCCESS == + crypto_rregister(icp_ocfDrvDriverId, icp_ocfDrvReadRandom, NULL)) { + ocfStatus++; + } + + if (OCF_ZERO_FUNCTIONALITY_REGISTERED == ocfStatus) { + DPRINTK("%s: Failed to register any device capabilities\n", + __FUNCTION__); + icp_ocfDrvFreeCaches(); + icp_ocfDrvDriverId = INVALID_DRIVER_ID; + return -ECANCELED; + } + + DPRINTK("%s: Registered %d of %d device capabilities\n", + __FUNCTION__, ocfStatus, NUM_SUPPORTED_CAPABILITIES); + +/*Session data linked list used during module exit*/ + INIT_LIST_HEAD(&icp_ocfDrvGlobalSymListHead); + INIT_LIST_HEAD(&icp_ocfDrvGlobalSymListHead_FreeMemList); + + icp_ocfDrvFreeLacSessionWorkQ = + create_singlethread_workqueue("ocfLacDeregWorkQueue"); + + return 0; +} + +/* Name : icp_ocfDrvExit + * + * Description : This function will deregister all the symmetric sessions + * registered with the LAC component. It will also deregister all symmetric + * and asymmetric functionality that can be accelerated by the hardware via OCF + * and random number generation if it is enabled. + */ +static void icp_ocfDrvExit(void) +{ + CpaStatus lacStatus = CPA_STATUS_SUCCESS; + struct icp_drvSessionData *sessionData = NULL; + struct icp_drvSessionData *tempSessionData = NULL; + int i, remaining_delay_time_in_jiffies = 0; + /* There is a possibility of a process or new session command being */ + /* sent before this variable is incremented. The aim of this variable */ + /* is to stop a loop of calls creating a deadlock situation which */ + /* would prevent the driver from exiting. */ + + atomic_inc(&icp_ocfDrvIsExiting); + + /*Existing sessions will be routed to another driver after these calls */ + crypto_unregister_all(icp_ocfDrvDriverId); + crypto_runregister_all(icp_ocfDrvDriverId); + + /*If any sessions are waiting to be deregistered, do that. This also + flushes the work queue */ + destroy_workqueue(icp_ocfDrvFreeLacSessionWorkQ); + + /*ENTER CRITICAL SECTION */ + spin_lock_bh(&icp_ocfDrvSymSessInfoListSpinlock); + list_for_each_entry_safe(tempSessionData, sessionData, + &icp_ocfDrvGlobalSymListHead, listNode) { + for (i = 0; i < num_dereg_retries; i++) { + /*No harm if bad input - LAC will handle error cases */ + if (ICP_SESSION_RUNNING == tempSessionData->inUse) { + lacStatus = + cpaCySymRemoveSession + (CPA_INSTANCE_HANDLE_SINGLE, + tempSessionData->sessHandle); + if (CPA_STATUS_SUCCESS == lacStatus) { + /* Succesfully deregistered */ + break; + } else if (CPA_STATUS_RETRY != lacStatus) { + atomic_inc + (&lac_session_failed_dereg_count); + break; + } + + /*schedule_timout returns the time left for completion if + * this task is set to TASK_INTERRUPTIBLE */ + remaining_delay_time_in_jiffies = + dereg_retry_delay_in_jiffies; + while (0 > remaining_delay_time_in_jiffies) { + remaining_delay_time_in_jiffies = + schedule_timeout + (remaining_delay_time_in_jiffies); + } + + DPRINTK + ("%s(): Retry %d to deregistrate the session\n", + __FUNCTION__, i); + } + } + + /*remove from current list */ + list_del(&(tempSessionData->listNode)); + /*add to free mem linked list */ + list_add(&(tempSessionData->listNode), + &icp_ocfDrvGlobalSymListHead_FreeMemList); + + } + + /*EXIT CRITICAL SECTION */ + spin_unlock_bh(&icp_ocfDrvSymSessInfoListSpinlock); + + /*set back to initial values */ + sessionData = NULL; + /*still have a reference in our list! */ + tempSessionData = NULL; + /*free memory */ + list_for_each_entry_safe(tempSessionData, sessionData, + &icp_ocfDrvGlobalSymListHead_FreeMemList, + listNode) { + + list_del(&(tempSessionData->listNode)); + /* Free allocated CpaCySymSessionCtx */ + if (NULL != tempSessionData->sessHandle) { + kfree(tempSessionData->sessHandle); + } + memset(tempSessionData, 0, sizeof(struct icp_drvSessionData)); + kmem_cache_free(drvSessionData_zone, tempSessionData); + } + + if (0 != atomic_read(&lac_session_failed_dereg_count)) { + DPRINTK("%s(): %d LAC sessions were not deregistered " + "correctly. This is not a clean exit! \n", + __FUNCTION__, + atomic_read(&lac_session_failed_dereg_count)); + } + + icp_ocfDrvFreeCaches(); + icp_ocfDrvDriverId = INVALID_DRIVER_ID; + + /* Shutdown the Cryptographic component */ + lacStatus = cpaCyStopInstance(CPA_INSTANCE_HANDLE_SINGLE); + if (CPA_STATUS_SUCCESS != lacStatus) { + DPRINTK("%s(): Failed to stop instance of the " + "Cryptographic component.(status == %d)\n", + __FUNCTION__, lacStatus); + } + +} + +/* Name : icp_ocfDrvFreeCaches + * + * Description : This function deregisters all slab caches + */ +static void icp_ocfDrvFreeCaches(void) +{ + if (atomic_read(&icp_ocfDrvIsExiting) != CPA_TRUE) { + atomic_set(&icp_ocfDrvIsExiting, 1); + } + + /*Sym Zones */ + ICP_CACHE_DESTROY(drvSessionData_zone); + ICP_CACHE_DESTROY(drvOpData_zone); + + /*Asym zones */ + ICP_CACHE_DESTROY(drvDH_zone); + ICP_CACHE_DESTROY(drvLnModExp_zone); + ICP_CACHE_DESTROY(drvRSADecrypt_zone); + ICP_CACHE_DESTROY(drvRSAPrivateKey_zone); + ICP_CACHE_DESTROY(drvDSARSSignKValue_zone); + ICP_CACHE_DESTROY(drvDSARSSign_zone); + ICP_CACHE_DESTROY(drvDSAVerify_zone); + + /*FlatBuffer and BufferList Zones */ + ICP_CACHE_DESTROY(drvFlatBuffer_zone); + +} + +/* Name : icp_ocfDrvDeregRetry + * + * Description : This function will try to farm the session deregistration + * off to a work queue. If it fails, nothing more can be done and it + * returns an error + */ + +int icp_ocfDrvDeregRetry(CpaCySymSessionCtx sessionToDeregister) +{ + struct icp_ocfDrvFreeLacSession *workstore = NULL; + + DPRINTK("%s(): Retry - Deregistering session (%p)\n", + __FUNCTION__, sessionToDeregister); + + /*make sure the session is not available to be allocated during this + process */ + atomic_inc(&lac_session_failed_dereg_count); + + /*Farm off to work queue */ + workstore = + kmalloc(sizeof(struct icp_ocfDrvFreeLacSession), GFP_ATOMIC); + if (NULL == workstore) { + DPRINTK("%s(): unable to free session - no memory available " + "for work queue\n", __FUNCTION__); + return ENOMEM; + } + + workstore->sessionToDeregister = sessionToDeregister; + + INIT_WORK(&(workstore->work), icp_ocfDrvDeferedFreeLacSessionProcess, + workstore); + queue_work(icp_ocfDrvFreeLacSessionWorkQ, &(workstore->work)); + + return ICP_OCF_DRV_STATUS_SUCCESS; + +} + +/* Name : icp_ocfDrvDeferedFreeLacSessionProcess + * + * Description : This function will retry (module input parameter) + * 'num_dereg_retries' times to deregister any symmetric session that recieves a + * CPA_STATUS_RETRY message from the LAC component. This function is run in + * Thread context because it is called from a worker thread + */ +static void icp_ocfDrvDeferedFreeLacSessionProcess(void *arg) +{ + struct icp_ocfDrvFreeLacSession *workstore = NULL; + CpaCySymSessionCtx sessionToDeregister = NULL; + int i = 0; + int remaining_delay_time_in_jiffies = 0; + CpaStatus lacStatus = CPA_STATUS_SUCCESS; + + workstore = (struct icp_ocfDrvFreeLacSession *)arg; + if (NULL == workstore) { + DPRINTK("%s() function called with null parameter \n", + __FUNCTION__); + return; + } + + sessionToDeregister = workstore->sessionToDeregister; + kfree(workstore); + + /*if exiting, give deregistration one more blast only */ + if (atomic_read(&icp_ocfDrvIsExiting) == CPA_TRUE) { + lacStatus = cpaCySymRemoveSession(CPA_INSTANCE_HANDLE_SINGLE, + sessionToDeregister); + + if (lacStatus != CPA_STATUS_SUCCESS) { + DPRINTK("%s() Failed to Dereg LAC session %p " + "during module exit\n", __FUNCTION__, + sessionToDeregister); + return; + } + + atomic_dec(&lac_session_failed_dereg_count); + return; + } + + for (i = 0; i <= num_dereg_retries; i++) { + lacStatus = cpaCySymRemoveSession(CPA_INSTANCE_HANDLE_SINGLE, + sessionToDeregister); + + if (lacStatus == CPA_STATUS_SUCCESS) { + atomic_dec(&lac_session_failed_dereg_count); + return; + } + if (lacStatus != CPA_STATUS_RETRY) { + DPRINTK("%s() Failed to deregister session - lacStatus " + " = %d", __FUNCTION__, lacStatus); + break; + } + + /*schedule_timout returns the time left for completion if this + task is set to TASK_INTERRUPTIBLE */ + remaining_delay_time_in_jiffies = dereg_retry_delay_in_jiffies; + while (0 > remaining_delay_time_in_jiffies) { + remaining_delay_time_in_jiffies = + schedule_timeout(remaining_delay_time_in_jiffies); + } + + } + + DPRINTK("%s(): Unable to deregister session\n", __FUNCTION__); + DPRINTK("%s(): Number of unavailable LAC sessions = %d\n", __FUNCTION__, + atomic_read(&lac_session_failed_dereg_count)); +} + +/* Name : icp_ocfDrvPtrAndLenToFlatBuffer + * + * Description : This function converts a "pointer and length" buffer + * structure to Fredericksburg Flat Buffer (CpaFlatBuffer) format. + * + * This function assumes that the data passed in are valid. + */ +inline void +icp_ocfDrvPtrAndLenToFlatBuffer(void *pData, uint32_t len, + CpaFlatBuffer * pFlatBuffer) +{ + pFlatBuffer->pData = pData; + pFlatBuffer->dataLenInBytes = len; +} + +/* Name : icp_ocfDrvSingleSkBuffToFlatBuffer + * + * Description : This function converts a single socket buffer (sk_buff) + * structure to a Fredericksburg Flat Buffer (CpaFlatBuffer) format. + * + * This function assumes that the data passed in are valid. + */ +static inline void +icp_ocfDrvSingleSkBuffToFlatBuffer(struct sk_buff *pSkb, + CpaFlatBuffer * pFlatBuffer) +{ + pFlatBuffer->pData = pSkb->data; + pFlatBuffer->dataLenInBytes = skb_headlen(pSkb); +} + +/* Name : icp_ocfDrvSkBuffToBufferList + * + * Description : This function converts a socket buffer (sk_buff) structure to + * Fredericksburg Scatter/Gather (CpaBufferList) buffer format. + * + * This function assumes that the bufferlist has been allocated with the correct + * number of buffer arrays. + * + */ +inline int +icp_ocfDrvSkBuffToBufferList(struct sk_buff *pSkb, CpaBufferList * bufferList) +{ + CpaFlatBuffer *curFlatBuffer = NULL; + char *skbuffPageAddr = NULL; + struct sk_buff *pCurFrag = NULL; + struct skb_shared_info *pShInfo = NULL; + uint32_t page_offset = 0, i = 0; + + DPRINTK("%s(): Entry Point\n", __FUNCTION__); + + /* + * In all cases, the first skb needs to be translated to FlatBuffer. + * Perform a buffer translation for the first skbuff + */ + curFlatBuffer = bufferList->pBuffers; + icp_ocfDrvSingleSkBuffToFlatBuffer(pSkb, curFlatBuffer); + + /* Set the userData to point to the original sk_buff */ + bufferList->pUserData = (void *)pSkb; + + /* We now know we'll have at least one element in the SGL */ + bufferList->numBuffers = 1; + + if (0 == skb_is_nonlinear(pSkb)) { + /* Is a linear buffer - therefore it's a single skbuff */ + DPRINTK("%s(): Exit Point\n", __FUNCTION__); + return ICP_OCF_DRV_STATUS_SUCCESS; + } + + curFlatBuffer++; + pShInfo = skb_shinfo(pSkb); + if (pShInfo->frag_list != NULL && pShInfo->nr_frags != 0) { + EPRINTK("%s():" + "Translation for a combination of frag_list " + "and frags[] array not supported!\n", __FUNCTION__); + return ICP_OCF_DRV_STATUS_FAIL; + } else if (pShInfo->frag_list != NULL) { + /* + * Non linear skbuff supported through frag_list + * Perform translation for each fragment (sk_buff) + * in the frag_list of the first sk_buff. + */ + for (pCurFrag = pShInfo->frag_list; + pCurFrag != NULL; pCurFrag = pCurFrag->next) { + icp_ocfDrvSingleSkBuffToFlatBuffer(pCurFrag, + curFlatBuffer); + curFlatBuffer++; + bufferList->numBuffers++; + } + } else if (pShInfo->nr_frags != 0) { + /* + * Perform translation for each fragment in frags array + * and add to the BufferList + */ + for (i = 0; i < pShInfo->nr_frags; i++) { + /* Get the page address and offset of this frag */ + skbuffPageAddr = (char *)pShInfo->frags[i].page; + page_offset = pShInfo->frags[i].page_offset; + + /* Convert a pointer and length to a flat buffer */ + icp_ocfDrvPtrAndLenToFlatBuffer(skbuffPageAddr + + page_offset, + pShInfo->frags[i].size, + curFlatBuffer); + curFlatBuffer++; + bufferList->numBuffers++; + } + } else { + EPRINTK("%s():" "Could not recognize skbuff fragments!\n", + __FUNCTION__); + return ICP_OCF_DRV_STATUS_FAIL; + } + + DPRINTK("%s(): Exit Point\n", __FUNCTION__); + return ICP_OCF_DRV_STATUS_SUCCESS; +} + +/* Name : icp_ocfDrvBufferListToSkBuff + * + * Description : This function converts a Fredericksburg Scatter/Gather + * (CpaBufferList) buffer format to socket buffer structure. + */ +inline int +icp_ocfDrvBufferListToSkBuff(CpaBufferList * bufferList, struct sk_buff **skb) +{ + DPRINTK("%s(): Entry Point\n", __FUNCTION__); + + /* Retrieve the orignal skbuff */ + *skb = (struct sk_buff *)bufferList->pUserData; + if (NULL == *skb) { + EPRINTK("%s():" + "Error on converting from a BufferList. " + "The BufferList does not contain an sk_buff.\n", + __FUNCTION__); + return ICP_OCF_DRV_STATUS_FAIL; + } + DPRINTK("%s(): Exit Point\n", __FUNCTION__); + return ICP_OCF_DRV_STATUS_SUCCESS; +} + +/* Name : icp_ocfDrvPtrAndLenToBufferList + * + * Description : This function converts a "pointer and length" buffer + * structure to Fredericksburg Scatter/Gather Buffer (CpaBufferList) format. + * + * This function assumes that the data passed in are valid. + */ +inline void +icp_ocfDrvPtrAndLenToBufferList(void *pDataIn, uint32_t length, + CpaBufferList * pBufferList) +{ + pBufferList->numBuffers = 1; + pBufferList->pBuffers->pData = pDataIn; + pBufferList->pBuffers->dataLenInBytes = length; +} + +/* Name : icp_ocfDrvBufferListToPtrAndLen + * + * Description : This function converts Fredericksburg Scatter/Gather Buffer + * (CpaBufferList) format to a "pointer and length" buffer structure. + * + * This function assumes that the data passed in are valid. + */ +inline void +icp_ocfDrvBufferListToPtrAndLen(CpaBufferList * pBufferList, + void **ppDataOut, uint32_t * pLength) +{ + *ppDataOut = pBufferList->pBuffers->pData; + *pLength = pBufferList->pBuffers->dataLenInBytes; +} + +/* Name : icp_ocfDrvBufferListMemInfo + * + * Description : This function will set the number of flat buffers in + * bufferlist, the size of memory to allocate for the pPrivateMetaData + * member of the CpaBufferList. + */ +int +icp_ocfDrvBufferListMemInfo(uint16_t numBuffers, + struct icp_drvBuffListInfo *buffListInfo) +{ + buffListInfo->numBuffers = numBuffers; + + if (CPA_STATUS_SUCCESS != + cpaCyBufferListGetMetaSize(CPA_INSTANCE_HANDLE_SINGLE, + buffListInfo->numBuffers, + &(buffListInfo->metaSize))) { + EPRINTK("%s() Failed to get buffer list meta size.\n", + __FUNCTION__); + return ICP_OCF_DRV_STATUS_FAIL; + } + + return ICP_OCF_DRV_STATUS_SUCCESS; +} + +/* Name : icp_ocfDrvGetSkBuffFrags + * + * Description : This function will determine the number of + * fragments in a socket buffer(sk_buff). + */ +inline uint16_t icp_ocfDrvGetSkBuffFrags(struct sk_buff * pSkb) +{ + uint16_t numFrags = 0; + struct sk_buff *pCurFrag = NULL; + struct skb_shared_info *pShInfo = NULL; + + if (NULL == pSkb) + return 0; + + numFrags = 1; + if (0 == skb_is_nonlinear(pSkb)) { + /* Linear buffer - it's a single skbuff */ + return numFrags; + } + + pShInfo = skb_shinfo(pSkb); + if (NULL != pShInfo->frag_list && 0 != pShInfo->nr_frags) { + EPRINTK("%s(): Combination of frag_list " + "and frags[] array not supported!\n", __FUNCTION__); + return 0; + } else if (0 != pShInfo->nr_frags) { + numFrags += pShInfo->nr_frags; + return numFrags; + } else if (NULL != pShInfo->frag_list) { + for (pCurFrag = pShInfo->frag_list; + pCurFrag != NULL; pCurFrag = pCurFrag->next) { + numFrags++; + } + return numFrags; + } else { + return 0; + } +} + +/* Name : icp_ocfDrvFreeFlatBuffer + * + * Description : This function will deallocate flat buffer. + */ +inline void icp_ocfDrvFreeFlatBuffer(CpaFlatBuffer * pFlatBuffer) +{ + if (pFlatBuffer != NULL) { + memset(pFlatBuffer, 0, sizeof(CpaFlatBuffer)); + kmem_cache_free(drvFlatBuffer_zone, pFlatBuffer); + } +} + +/* Name : icp_ocfDrvAllocMetaData + * + * Description : This function will allocate memory for the + * pPrivateMetaData member of CpaBufferList. + */ +inline int +icp_ocfDrvAllocMetaData(CpaBufferList * pBufferList, + const struct icp_drvOpData *pOpData) +{ + Cpa32U metaSize = 0; + + if (pBufferList->numBuffers <= ICP_OCF_DRV_DEFAULT_BUFFLIST_ARRAYS){ + void *pOpDataStartAddr = (void *)pOpData; + + if (0 == defBuffListInfo.metaSize) { + pBufferList->pPrivateMetaData = NULL; + return ICP_OCF_DRV_STATUS_SUCCESS; + } + /* + * The meta data allocation has been included as part of the + * op data. It has been pre-allocated in memory just after the + * icp_drvOpData structure. + */ + pBufferList->pPrivateMetaData = pOpDataStartAddr + + sizeof(struct icp_drvOpData); + } else { + if (CPA_STATUS_SUCCESS != + cpaCyBufferListGetMetaSize(CPA_INSTANCE_HANDLE_SINGLE, + pBufferList->numBuffers, + &metaSize)) { + EPRINTK("%s() Failed to get buffer list meta size.\n", + __FUNCTION__); + return ICP_OCF_DRV_STATUS_FAIL; + } + + if (0 == metaSize) { + pBufferList->pPrivateMetaData = NULL; + return ICP_OCF_DRV_STATUS_SUCCESS; + } + + pBufferList->pPrivateMetaData = kmalloc(metaSize, GFP_ATOMIC); + } + if (NULL == pBufferList->pPrivateMetaData) { + EPRINTK("%s() Failed to allocate pPrivateMetaData.\n", + __FUNCTION__); + return ICP_OCF_DRV_STATUS_FAIL; + } + + return ICP_OCF_DRV_STATUS_SUCCESS; +} + +/* Name : icp_ocfDrvFreeMetaData + * + * Description : This function will deallocate pPrivateMetaData memory. + */ +inline void icp_ocfDrvFreeMetaData(CpaBufferList * pBufferList) +{ + if (NULL == pBufferList->pPrivateMetaData) { + return; + } + + /* + * Only free the meta data if the BufferList has more than + * ICP_OCF_DRV_DEFAULT_BUFFLIST_ARRAYS number of buffers. + * Otherwise, the meta data shall be freed when the icp_drvOpData is + * freed. + */ + if (ICP_OCF_DRV_DEFAULT_BUFFLIST_ARRAYS < pBufferList->numBuffers){ + kfree(pBufferList->pPrivateMetaData); + } +} + +module_init(icp_ocfDrvInit); +module_exit(icp_ocfDrvExit); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_AUTHOR("Intel"); +MODULE_DESCRIPTION("OCF Driver for Intel Quick Assist crypto acceleration"); diff --git a/target/linux/generic-2.6/files/crypto/ocf/ep80579/icp_ocf.h b/target/linux/generic-2.6/files/crypto/ocf/ep80579/icp_ocf.h new file mode 100644 index 0000000000..dff0a8b7d4 --- /dev/null +++ b/target/linux/generic-2.6/files/crypto/ocf/ep80579/icp_ocf.h @@ -0,0 +1,363 @@ +/*************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2007,2008 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * The full GNU General Public License is included in this distribution + * in the file called LICENSE.GPL. + * + * Contact Information: + * Intel Corporation + * + * BSD LICENSE + * + * Copyright(c) 2007,2008 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + * version: Security.L.1.0.130 + * + ***************************************************************************/ + +/* + * OCF drv driver header file for the Intel ICP processor. + */ + +#ifndef ICP_OCF_H +#define ICP_OCF_H + +#include <linux/crypto.h> +#include <linux/delay.h> +#include <linux/skbuff.h> + +#include "cryptodev.h" +#include "uio.h" + +#include "cpa.h" +#include "cpa_cy_im.h" +#include "cpa_cy_sym.h" +#include "cpa_cy_rand.h" +#include "cpa_cy_dh.h" +#include "cpa_cy_rsa.h" +#include "cpa_cy_ln.h" +#include "cpa_cy_common.h" +#include "cpa_cy_dsa.h" + +#define NUM_BITS_IN_BYTE (8) +#define NUM_BITS_IN_BYTE_MINUS_ONE (NUM_BITS_IN_BYTE -1) +#define INVALID_DRIVER_ID (-1) +#define RETURN_RAND_NUM_GEN_FAILED (-1) + +/*This is define means only one operation can be chained to another +(resulting in one chain of two operations)*/ +#define MAX_NUM_OF_CHAINED_OPS (1) +/*This is the max block cipher initialisation vector*/ +#define MAX_IV_LEN_IN_BYTES (20) +/*This is used to check whether the OCF to this driver session limit has + been disabled*/ +#define NO_OCF_TO_DRV_MAX_SESSIONS (0) + +/*OCF values mapped here*/ +#define ICP_SHA1_DIGEST_SIZE_IN_BYTES (SHA1_HASH_LEN) +#define ICP_SHA256_DIGEST_SIZE_IN_BYTES (SHA2_256_HASH_LEN) +#define ICP_SHA384_DIGEST_SIZE_IN_BYTES (SHA2_384_HASH_LEN) +#define ICP_SHA512_DIGEST_SIZE_IN_BYTES (SHA2_512_HASH_LEN) +#define ICP_MD5_DIGEST_SIZE_IN_BYTES (MD5_HASH_LEN) +#define ARC4_COUNTER_LEN (ARC4_BLOCK_LEN) + +#define OCF_REGISTRATION_STATUS_SUCCESS (0) +#define OCF_ZERO_FUNCTIONALITY_REGISTERED (0) +#define ICP_OCF_DRV_NO_CRYPTO_PROCESS_ERROR (0) +#define ICP_OCF_DRV_STATUS_SUCCESS (0) +#define ICP_OCF_DRV_STATUS_FAIL (1) + +/*Turn on/off debug options*/ +#define ICP_OCF_PRINT_DEBUG_MESSAGES (0) +#define ICP_OCF_PRINT_KERN_ALERT (1) +#define ICP_OCF_PRINT_KERN_ERRS (1) + +/*DSA Prime Q size in bytes (as defined in the standard) */ +#define DSA_RS_SIGN_PRIMEQ_SIZE_IN_BYTES (20) + +/*MACRO DEFINITIONS*/ + +#define BITS_TO_BYTES(bytes, bits) \ + bytes = (bits + NUM_BITS_IN_BYTE_MINUS_ONE) / NUM_BITS_IN_BYTE + +#define ICP_CACHE_CREATE(cache_ID, cache_name) \ + kmem_cache_create(cache_ID, sizeof(cache_name),0, \ + SLAB_HWCACHE_ALIGN, NULL, NULL); + +#define ICP_CACHE_NULL_CHECK(slab_zone) \ +{ \ + if(NULL == slab_zone){ \ + icp_ocfDrvFreeCaches(); \ + EPRINTK("%s() line %d: Not enough memory!\n", \ + __FUNCTION__, __LINE__); \ + return ENOMEM; \ + } \ +} + +#define ICP_CACHE_DESTROY(slab_zone) \ +{ \ + if(NULL != slab_zone){ \ + kmem_cache_destroy(slab_zone); \ + slab_zone = NULL; \ + } \ +} + +#define ICP_REGISTER_SYM_FUNCTIONALITY_WITH_OCF(alg) \ +{ \ + if(OCF_REGISTRATION_STATUS_SUCCESS == \ + crypto_register(icp_ocfDrvDriverId, \ + alg, \ + 0, \ + 0)) { \ + ocfStatus++; \ + } \ +} + +#define ICP_REGISTER_ASYM_FUNCTIONALITY_WITH_OCF(alg) \ +{ \ + if(OCF_REGISTRATION_STATUS_SUCCESS == \ + crypto_kregister(icp_ocfDrvDriverId, \ + alg, \ + 0)){ \ + ocfStatus++; \ + } \ +} + +#if ICP_OCF_PRINT_DEBUG_MESSAGES == 1 +#define DPRINTK(args...) \ +{ \ + printk(args); \ +} + +#else //ICP_OCF_PRINT_DEBUG_MESSAGES == 1 + +#define DPRINTK(args...) + +#endif //ICP_OCF_PRINT_DEBUG_MESSAGES == 1 + +#if ICP_OCF_PRINT_KERN_ALERT == 1 +#define APRINTK(args...) \ +{ \ + printk(KERN_ALERT args); \ +} + +#else //ICP_OCF_PRINT_KERN_ALERT == 1 + +#define APRINTK(args...) + +#endif //ICP_OCF_PRINT_KERN_ALERT == 1 + +#if ICP_OCF_PRINT_KERN_ERRS == 1 +#define EPRINTK(args...) \ +{ \ + printk(KERN_ERR args); \ +} + +#else //ICP_OCF_PRINT_KERN_ERRS == 1 + +#define EPRINTK(args...) + +#endif //ICP_OCF_PRINT_KERN_ERRS == 1 + +#define IPRINTK(args...) \ +{ \ + printk(KERN_INFO args); \ +} + +/*END OF MACRO DEFINITIONS*/ + +typedef enum { + ICP_OCF_DRV_ALG_CIPHER = 0, + ICP_OCF_DRV_ALG_HASH +} icp_ocf_drv_alg_type_t; + +/* These are all defined in icp_common.c */ +extern atomic_t lac_session_failed_dereg_count; +extern atomic_t icp_ocfDrvIsExiting; +extern atomic_t num_ocf_to_drv_registered_sessions; + +/*These are use inputs used in icp_sym.c and icp_common.c + They are instantiated in icp_common.c*/ +extern int max_sessions; + +extern int32_t icp_ocfDrvDriverId; +extern struct list_head icp_ocfDrvGlobalSymListHead; +extern struct list_head icp_ocfDrvGlobalSymListHead_FreeMemList; +extern struct workqueue_struct *icp_ocfDrvFreeLacSessionWorkQ; +extern spinlock_t icp_ocfDrvSymSessInfoListSpinlock; +extern rwlock_t icp_kmem_cache_destroy_alloc_lock; + +/*Slab zones for symettric functionality, instantiated in icp_common.c*/ +extern struct kmem_cache *drvSessionData_zone; +extern struct kmem_cache *drvOpData_zone; + +/*Slabs zones for asymettric functionality, instantiated in icp_common.c*/ +extern struct kmem_cache *drvDH_zone; +extern struct kmem_cache *drvLnModExp_zone; +extern struct kmem_cache *drvRSADecrypt_zone; +extern struct kmem_cache *drvRSAPrivateKey_zone; +extern struct kmem_cache *drvDSARSSign_zone; +extern struct kmem_cache *drvDSARSSignKValue_zone; +extern struct kmem_cache *drvDSAVerify_zone; + +/*Slab zones for flatbuffers and bufferlist*/ +extern struct kmem_cache *drvFlatBuffer_zone; + +#define ICP_OCF_DRV_DEFAULT_BUFFLIST_ARRAYS (16) + +struct icp_drvBuffListInfo { + Cpa16U numBuffers; + Cpa32U metaSize; + Cpa32U metaOffset; + Cpa32U buffListSize; +}; +extern struct icp_drvBuffListInfo defBuffListInfo; + +/* +* This struct is used to keep a reference to the relevant node in the list +* of sessionData structs, to the buffer type required by OCF and to the OCF +* provided crp struct that needs to be returned. All this info is needed in +* the callback function. +* +* IV can sometimes be stored in non-contiguous memory (e.g. skbuff +* linked/frag list, therefore a contiguous memory space for the IV data must be +* created and passed to LAC +* +*/ +struct icp_drvOpData { + CpaCySymOpData lacOpData; + uint32_t digestSizeInBytes; + struct cryptop *crp; + uint8_t bufferType; + uint8_t ivData[MAX_IV_LEN_IN_BYTES]; + uint16_t numBufferListArray; + CpaBufferList srcBuffer; + CpaFlatBuffer bufferListArray[ICP_OCF_DRV_DEFAULT_BUFFLIST_ARRAYS]; + CpaBoolean verifyResult; +}; +/*Values used to derisk chances of performs being called against +deregistered sessions (for which the slab page has been reclaimed) +This is not a fix - since page frames are reclaimed from a slab, one cannot +rely on that memory not being re-used by another app.*/ +typedef enum { + ICP_SESSION_INITIALISED = 0x5C5C5C, + ICP_SESSION_RUNNING = 0x005C00, + ICP_SESSION_DEREGISTERED = 0xC5C5C5 +} usage_derisk; + +/* +This is the OCF<->OCF_DRV session object: + +1.The first member is a listNode. These session objects are added to a linked + list in order to make it easier to remove them all at session exit time. +2.The second member is used to give the session object state and derisk the + possibility of OCF batch calls executing against a deregistered session (as + described above). +3.The third member is a LAC<->OCF_DRV session handle (initialised with the first + perform request for that session). +4.The fourth is the LAC session context. All the parameters for this structure + are only known when the first perform request for this session occurs. That is + why the OCF Tolapai Driver only registers a new LAC session at perform time +*/ +struct icp_drvSessionData { + struct list_head listNode; + usage_derisk inUse; + CpaCySymSessionCtx sessHandle; + CpaCySymSessionSetupData lacSessCtx; +}; + +/* This struct is required for deferred session + deregistration as a work queue function can + only have one argument*/ +struct icp_ocfDrvFreeLacSession { + CpaCySymSessionCtx sessionToDeregister; + struct work_struct work; +}; + +int icp_ocfDrvNewSession(device_t dev, uint32_t * sild, struct cryptoini *cri); + +int icp_ocfDrvFreeLACSession(device_t dev, uint64_t sid); + +int icp_ocfDrvSymProcess(device_t dev, struct cryptop *crp, int hint); + +int icp_ocfDrvPkeProcess(device_t dev, struct cryptkop *krp, int hint); + +int icp_ocfDrvReadRandom(void *arg, uint32_t * buf, int maxwords); + +int icp_ocfDrvDeregRetry(CpaCySymSessionCtx sessionToDeregister); + +int icp_ocfDrvSkBuffToBufferList(struct sk_buff *skb, + CpaBufferList * bufferList); + +int icp_ocfDrvBufferListToSkBuff(CpaBufferList * bufferList, + struct sk_buff **skb); + +void icp_ocfDrvPtrAndLenToFlatBuffer(void *pData, uint32_t len, + CpaFlatBuffer * pFlatBuffer); + +void icp_ocfDrvPtrAndLenToBufferList(void *pDataIn, uint32_t length, + CpaBufferList * pBufferList); + +void icp_ocfDrvBufferListToPtrAndLen(CpaBufferList * pBufferList, + void **ppDataOut, uint32_t * pLength); + +int icp_ocfDrvBufferListMemInfo(uint16_t numBuffers, + struct icp_drvBuffListInfo *buffListInfo); + +uint16_t icp_ocfDrvGetSkBuffFrags(struct sk_buff *pSkb); + +void icp_ocfDrvFreeFlatBuffer(CpaFlatBuffer * pFlatBuffer); + +int icp_ocfDrvAllocMetaData(CpaBufferList * pBufferList, + const struct icp_drvOpData *pOpData); + +void icp_ocfDrvFreeMetaData(CpaBufferList * pBufferList); + +#endif +/* ICP_OCF_H */ diff --git a/target/linux/generic-2.6/files/crypto/ocf/ep80579/icp_sym.c b/target/linux/generic-2.6/files/crypto/ocf/ep80579/icp_sym.c new file mode 100644 index 0000000000..d632970165 --- /dev/null +++ b/target/linux/generic-2.6/files/crypto/ocf/ep80579/icp_sym.c @@ -0,0 +1,1382 @@ +/*************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2007,2008 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * The full GNU General Public License is included in this distribution + * in the file called LICENSE.GPL. + * + * Contact Information: + * Intel Corporation + * + * BSD LICENSE + * + * Copyright(c) 2007,2008 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + * version: Security.L.1.0.130 + * + ***************************************************************************/ +/* + * An OCF module that uses the API for Intel® QuickAssist Technology to do the + * cryptography. + * + * This driver requires the ICP Access Library that is available from Intel in + * order to operate. + */ + +#include "icp_ocf.h" + +/*This is the call back function for all symmetric cryptographic processes. + Its main functionality is to free driver crypto operation structure and to + call back to OCF*/ +static void +icp_ocfDrvSymCallBack(void *callbackTag, + CpaStatus status, + const CpaCySymOp operationType, + void *pOpData, + CpaBufferList * pDstBuffer, CpaBoolean verifyResult); + +/*This function is used to extract crypto processing information from the OCF + inputs, so as that it may be passed onto LAC*/ +static int +icp_ocfDrvProcessDataSetup(struct icp_drvOpData *drvOpData, + struct cryptodesc *crp_desc); + +/*This function checks whether the crp_desc argument pertains to a digest or a + cipher operation*/ +static int icp_ocfDrvAlgCheck(struct cryptodesc *crp_desc); + +/*This function copies all the passed in session context information and stores + it in a LAC context structure*/ +static int +icp_ocfDrvAlgorithmSetup(struct cryptoini *cri, + CpaCySymSessionSetupData * lacSessCtx); + +/*This top level function is used to find a pointer to where a digest is + stored/needs to be inserted. */ +static uint8_t *icp_ocfDrvDigestPointerFind(struct icp_drvOpData *drvOpData, + struct cryptodesc *crp_desc); + +/*This function is called when a digest pointer has to be found within a + SKBUFF.*/ +static inline uint8_t *icp_ocfDrvSkbuffDigestPointerFind(struct icp_drvOpData + *drvOpData, + int offsetInBytes, + uint32_t + digestSizeInBytes); + +/*The following two functions are called if the SKBUFF digest pointer is not + positioned in the linear portion of the buffer (i.e. it is in a linked SKBUFF + or page fragment).*/ +/*This function takes care of the page fragment case.*/ +static inline uint8_t *icp_ocfDrvDigestSkbNRFragsCheck(struct sk_buff *skb, + struct skb_shared_info + *skb_shared, + int offsetInBytes, + uint32_t + digestSizeInBytes); + +/*This function takes care of the linked list case.*/ +static inline uint8_t *icp_ocfDrvDigestSkbFragListCheck(struct sk_buff *skb, + struct skb_shared_info + *skb_shared, + int offsetInBytes, + uint32_t + digestSizeInBytes); + +/*This function is used to free an OCF->OCF_DRV session object*/ +static void icp_ocfDrvFreeOCFSession(struct icp_drvSessionData *sessionData); + +/*max IOV buffs supported in a UIO structure*/ +#define NUM_IOV_SUPPORTED (1) + +/* Name : icp_ocfDrvSymCallBack + * + * Description : When this function returns it signifies that the LAC + * component has completed the relevant symmetric operation. + * + * Notes : The callbackTag is a pointer to an icp_drvOpData. This memory + * object was passed to LAC for the cryptographic processing and contains all + * the relevant information for cleaning up buffer handles etc. so that the + * OCF Tolapai Driver portion of this crypto operation can be fully completed. + */ +static void +icp_ocfDrvSymCallBack(void *callbackTag, + CpaStatus status, + const CpaCySymOp operationType, + void *pOpData, + CpaBufferList * pDstBuffer, CpaBoolean verifyResult) +{ + struct cryptop *crp = NULL; + struct icp_drvOpData *temp_drvOpData = + (struct icp_drvOpData *)callbackTag; + uint64_t *tempBasePtr = NULL; + uint32_t tempLen = 0; + + if (NULL == temp_drvOpData) { + DPRINTK("%s(): The callback from the LAC component" + " has failed due to Null userOpaque data" + "(status == %d).\n", __FUNCTION__, status); + DPRINTK("%s(): Unable to call OCF back! \n", __FUNCTION__); + return; + } + + crp = temp_drvOpData->crp; + crp->crp_etype = ICP_OCF_DRV_NO_CRYPTO_PROCESS_ERROR; + + if (NULL == pOpData) { + DPRINTK("%s(): The callback from the LAC component" + " has failed due to Null Symmetric Op data" + "(status == %d).\n", __FUNCTION__, status); + crp->crp_etype = ECANCELED; + crypto_done(crp); + return; + } + + if (NULL == pDstBuffer) { + DPRINTK("%s(): The callback from the LAC component" + " has failed due to Null Dst Bufferlist data" + "(status == %d).\n", __FUNCTION__, status); + crp->crp_etype = ECANCELED; + crypto_done(crp); + return; + } + + if (CPA_STATUS_SUCCESS == status) { + + if (temp_drvOpData->bufferType == CRYPTO_F_SKBUF) { + if (ICP_OCF_DRV_STATUS_SUCCESS != + icp_ocfDrvBufferListToSkBuff(pDstBuffer, + (struct sk_buff **) + &(crp->crp_buf))) { + EPRINTK("%s(): BufferList to SkBuff " + "conversion error.\n", __FUNCTION__); + crp->crp_etype = EPERM; + } + } else { + icp_ocfDrvBufferListToPtrAndLen(pDstBuffer, + (void **)&tempBasePtr, + &tempLen); + crp->crp_olen = (int)tempLen; + } + + } else { + DPRINTK("%s(): The callback from the LAC component has failed" + "(status == %d).\n", __FUNCTION__, status); + + crp->crp_etype = ECANCELED; + } + + if (temp_drvOpData->numBufferListArray > + ICP_OCF_DRV_DEFAULT_BUFFLIST_ARRAYS) { + kfree(pDstBuffer->pBuffers); + } + icp_ocfDrvFreeMetaData(pDstBuffer); + kmem_cache_free(drvOpData_zone, temp_drvOpData); + + /* Invoke the OCF callback function */ + crypto_done(crp); + + return; +} + +/* Name : icp_ocfDrvNewSession + * + * Description : This function will create a new Driver<->OCF session + * + * Notes : LAC session registration happens during the first perform call. + * That is the first time we know all information about a given session. + */ +int icp_ocfDrvNewSession(device_t dev, uint32_t * sid, struct cryptoini *cri) +{ + struct icp_drvSessionData *sessionData = NULL; + uint32_t delete_session = 0; + + /* The SID passed in should be our driver ID. We can return the */ + /* local ID (LID) which is a unique identifier which we can use */ + /* to differentiate between the encrypt/decrypt LAC session handles */ + if (NULL == sid) { + EPRINTK("%s(): Invalid input parameters - NULL sid.\n", + __FUNCTION__); + return EINVAL; + } + + if (NULL == cri) { + EPRINTK("%s(): Invalid input parameters - NULL cryptoini.\n", + __FUNCTION__); + return EINVAL; + } + + if (icp_ocfDrvDriverId != *sid) { + EPRINTK("%s(): Invalid input parameters - bad driver ID\n", + __FUNCTION__); + EPRINTK("\t sid = 0x08%p \n \t cri = 0x08%p \n", sid, cri); + return EINVAL; + } + + sessionData = kmem_cache_zalloc(drvSessionData_zone, GFP_ATOMIC); + if (NULL == sessionData) { + DPRINTK("%s():No memory for Session Data\n", __FUNCTION__); + return ENOMEM; + } + + /*ENTER CRITICAL SECTION */ + spin_lock_bh(&icp_ocfDrvSymSessInfoListSpinlock); + /*put this check in the spinlock so no new sessions can be added to the + linked list when we are exiting */ + if (CPA_TRUE == atomic_read(&icp_ocfDrvIsExiting)) { + delete_session++; + + } else if (NO_OCF_TO_DRV_MAX_SESSIONS != max_sessions) { + if (atomic_read(&num_ocf_to_drv_registered_sessions) >= + (max_sessions - + atomic_read(&lac_session_failed_dereg_count))) { + delete_session++; + } else { + atomic_inc(&num_ocf_to_drv_registered_sessions); + /* Add to session data linked list */ + list_add(&(sessionData->listNode), + &icp_ocfDrvGlobalSymListHead); + } + + } else if (NO_OCF_TO_DRV_MAX_SESSIONS == max_sessions) { + list_add(&(sessionData->listNode), + &icp_ocfDrvGlobalSymListHead); + } + + sessionData->inUse = ICP_SESSION_INITIALISED; + + /*EXIT CRITICAL SECTION */ + spin_unlock_bh(&icp_ocfDrvSymSessInfoListSpinlock); + + if (delete_session) { + DPRINTK("%s():No Session handles available\n", __FUNCTION__); + kmem_cache_free(drvSessionData_zone, sessionData); + return EPERM; + } + + if (ICP_OCF_DRV_STATUS_SUCCESS != + icp_ocfDrvAlgorithmSetup(cri, &(sessionData->lacSessCtx))) { + DPRINTK("%s():algorithm not supported\n", __FUNCTION__); + icp_ocfDrvFreeOCFSession(sessionData); + return EINVAL; + } + + if (cri->cri_next) { + if (cri->cri_next->cri_next != NULL) { + DPRINTK("%s():only two chained algorithms supported\n", + __FUNCTION__); + icp_ocfDrvFreeOCFSession(sessionData); + return EPERM; + } + + if (ICP_OCF_DRV_STATUS_SUCCESS != + icp_ocfDrvAlgorithmSetup(cri->cri_next, + &(sessionData->lacSessCtx))) { + DPRINTK("%s():second algorithm not supported\n", + __FUNCTION__); + icp_ocfDrvFreeOCFSession(sessionData); + return EINVAL; + } + + sessionData->lacSessCtx.symOperation = + CPA_CY_SYM_OP_ALGORITHM_CHAINING; + } + + *sid = (uint32_t) sessionData; + + return ICP_OCF_DRV_STATUS_SUCCESS; +} + +/* Name : icp_ocfDrvAlgorithmSetup + * + * Description : This function builds the session context data from the + * information supplied through OCF. Algorithm chain order and whether the + * session is Encrypt/Decrypt can only be found out at perform time however, so + * the session is registered with LAC at that time. + */ +static int +icp_ocfDrvAlgorithmSetup(struct cryptoini *cri, + CpaCySymSessionSetupData * lacSessCtx) +{ + + lacSessCtx->sessionPriority = CPA_CY_PRIORITY_NORMAL; + + switch (cri->cri_alg) { + + case CRYPTO_NULL_CBC: + DPRINTK("%s(): NULL CBC\n", __FUNCTION__); + lacSessCtx->symOperation = CPA_CY_SYM_OP_CIPHER; + lacSessCtx->cipherSetupData.cipherAlgorithm = + CPA_CY_SYM_CIPHER_NULL; + lacSessCtx->cipherSetupData.cipherKeyLenInBytes = + cri->cri_klen / NUM_BITS_IN_BYTE; + lacSessCtx->cipherSetupData.pCipherKey = cri->cri_key; + break; + + case CRYPTO_DES_CBC: + DPRINTK("%s(): DES CBC\n", __FUNCTION__); + lacSessCtx->symOperation = CPA_CY_SYM_OP_CIPHER; + lacSessCtx->cipherSetupData.cipherAlgorithm = + CPA_CY_SYM_CIPHER_DES_CBC; + lacSessCtx->cipherSetupData.cipherKeyLenInBytes = + cri->cri_klen / NUM_BITS_IN_BYTE; + lacSessCtx->cipherSetupData.pCipherKey = cri->cri_key; + break; + + case CRYPTO_3DES_CBC: + DPRINTK("%s(): 3DES CBC\n", __FUNCTION__); + lacSessCtx->symOperation = CPA_CY_SYM_OP_CIPHER; + lacSessCtx->cipherSetupData.cipherAlgorithm = + CPA_CY_SYM_CIPHER_3DES_CBC; + lacSessCtx->cipherSetupData.cipherKeyLenInBytes = + cri->cri_klen / NUM_BITS_IN_BYTE; + lacSessCtx->cipherSetupData.pCipherKey = cri->cri_key; + break; + + case CRYPTO_AES_CBC: + DPRINTK("%s(): AES CBC\n", __FUNCTION__); + lacSessCtx->symOperation = CPA_CY_SYM_OP_CIPHER; + lacSessCtx->cipherSetupData.cipherAlgorithm = + CPA_CY_SYM_CIPHER_AES_CBC; + lacSessCtx->cipherSetupData.cipherKeyLenInBytes = + cri->cri_klen / NUM_BITS_IN_BYTE; + lacSessCtx->cipherSetupData.pCipherKey = cri->cri_key; + break; + + case CRYPTO_ARC4: + DPRINTK("%s(): ARC4\n", __FUNCTION__); + lacSessCtx->symOperation = CPA_CY_SYM_OP_CIPHER; + lacSessCtx->cipherSetupData.cipherAlgorithm = + CPA_CY_SYM_CIPHER_ARC4; + lacSessCtx->cipherSetupData.cipherKeyLenInBytes = + cri->cri_klen / NUM_BITS_IN_BYTE; + lacSessCtx->cipherSetupData.pCipherKey = cri->cri_key; + break; + + case CRYPTO_SHA1: + DPRINTK("%s(): SHA1\n", __FUNCTION__); + lacSessCtx->symOperation = CPA_CY_SYM_OP_HASH; + lacSessCtx->hashSetupData.hashAlgorithm = CPA_CY_SYM_HASH_SHA1; + lacSessCtx->hashSetupData.hashMode = CPA_CY_SYM_HASH_MODE_PLAIN; + lacSessCtx->hashSetupData.digestResultLenInBytes = + (cri->cri_mlen ? + cri->cri_mlen : ICP_SHA1_DIGEST_SIZE_IN_BYTES); + + break; + + case CRYPTO_SHA1_HMAC: + DPRINTK("%s(): SHA1_HMAC\n", __FUNCTION__); + lacSessCtx->symOperation = CPA_CY_SYM_OP_HASH; + lacSessCtx->hashSetupData.hashAlgorithm = CPA_CY_SYM_HASH_SHA1; + lacSessCtx->hashSetupData.hashMode = CPA_CY_SYM_HASH_MODE_AUTH; + lacSessCtx->hashSetupData.digestResultLenInBytes = + (cri->cri_mlen ? + cri->cri_mlen : ICP_SHA1_DIGEST_SIZE_IN_BYTES); + lacSessCtx->hashSetupData.authModeSetupData.authKey = + cri->cri_key; + lacSessCtx->hashSetupData.authModeSetupData.authKeyLenInBytes = + cri->cri_klen / NUM_BITS_IN_BYTE; + lacSessCtx->hashSetupData.authModeSetupData.aadLenInBytes = 0; + + break; + + case CRYPTO_SHA2_256: + DPRINTK("%s(): SHA256\n", __FUNCTION__); + lacSessCtx->symOperation = CPA_CY_SYM_OP_HASH; + lacSessCtx->hashSetupData.hashAlgorithm = + CPA_CY_SYM_HASH_SHA256; + lacSessCtx->hashSetupData.hashMode = CPA_CY_SYM_HASH_MODE_PLAIN; + lacSessCtx->hashSetupData.digestResultLenInBytes = + (cri->cri_mlen ? + cri->cri_mlen : ICP_SHA256_DIGEST_SIZE_IN_BYTES); + + break; + + case CRYPTO_SHA2_256_HMAC: + DPRINTK("%s(): SHA256_HMAC\n", __FUNCTION__); + lacSessCtx->symOperation = CPA_CY_SYM_OP_HASH; + lacSessCtx->hashSetupData.hashAlgorithm = + CPA_CY_SYM_HASH_SHA256; + lacSessCtx->hashSetupData.hashMode = CPA_CY_SYM_HASH_MODE_AUTH; + lacSessCtx->hashSetupData.digestResultLenInBytes = + (cri->cri_mlen ? + cri->cri_mlen : ICP_SHA256_DIGEST_SIZE_IN_BYTES); + lacSessCtx->hashSetupData.authModeSetupData.authKey = + cri->cri_key; + lacSessCtx->hashSetupData.authModeSetupData.authKeyLenInBytes = + cri->cri_klen / NUM_BITS_IN_BYTE; + lacSessCtx->hashSetupData.authModeSetupData.aadLenInBytes = 0; + + break; + + case CRYPTO_SHA2_384: + DPRINTK("%s(): SHA384\n", __FUNCTION__); + lacSessCtx->symOperation = CPA_CY_SYM_OP_HASH; + lacSessCtx->hashSetupData.hashAlgorithm = + CPA_CY_SYM_HASH_SHA384; + lacSessCtx->hashSetupData.hashMode = CPA_CY_SYM_HASH_MODE_PLAIN; + lacSessCtx->hashSetupData.digestResultLenInBytes = + (cri->cri_mlen ? + cri->cri_mlen : ICP_SHA384_DIGEST_SIZE_IN_BYTES); + + break; + + case CRYPTO_SHA2_384_HMAC: + DPRINTK("%s(): SHA384_HMAC\n", __FUNCTION__); + lacSessCtx->symOperation = CPA_CY_SYM_OP_HASH; + lacSessCtx->hashSetupData.hashAlgorithm = + CPA_CY_SYM_HASH_SHA384; + lacSessCtx->hashSetupData.hashMode = CPA_CY_SYM_HASH_MODE_AUTH; + lacSessCtx->hashSetupData.digestResultLenInBytes = + (cri->cri_mlen ? + cri->cri_mlen : ICP_SHA384_DIGEST_SIZE_IN_BYTES); + lacSessCtx->hashSetupData.authModeSetupData.authKey = + cri->cri_key; + lacSessCtx->hashSetupData.authModeSetupData.authKeyLenInBytes = + cri->cri_klen / NUM_BITS_IN_BYTE; + lacSessCtx->hashSetupData.authModeSetupData.aadLenInBytes = 0; + + break; + + case CRYPTO_SHA2_512: + DPRINTK("%s(): SHA512\n", __FUNCTION__); + lacSessCtx->symOperation = CPA_CY_SYM_OP_HASH; + lacSessCtx->hashSetupData.hashAlgorithm = + CPA_CY_SYM_HASH_SHA512; + lacSessCtx->hashSetupData.hashMode = CPA_CY_SYM_HASH_MODE_PLAIN; + lacSessCtx->hashSetupData.digestResultLenInBytes = + (cri->cri_mlen ? + cri->cri_mlen : ICP_SHA512_DIGEST_SIZE_IN_BYTES); + + break; + + case CRYPTO_SHA2_512_HMAC: + DPRINTK("%s(): SHA512_HMAC\n", __FUNCTION__); + lacSessCtx->symOperation = CPA_CY_SYM_OP_HASH; + lacSessCtx->hashSetupData.hashAlgorithm = + CPA_CY_SYM_HASH_SHA512; + lacSessCtx->hashSetupData.hashMode = CPA_CY_SYM_HASH_MODE_AUTH; + lacSessCtx->hashSetupData.digestResultLenInBytes = + (cri->cri_mlen ? + cri->cri_mlen : ICP_SHA512_DIGEST_SIZE_IN_BYTES); + lacSessCtx->hashSetupData.authModeSetupData.authKey = + cri->cri_key; + lacSessCtx->hashSetupData.authModeSetupData.authKeyLenInBytes = + cri->cri_klen / NUM_BITS_IN_BYTE; + lacSessCtx->hashSetupData.authModeSetupData.aadLenInBytes = 0; + + break; + + case CRYPTO_MD5: + DPRINTK("%s(): MD5\n", __FUNCTION__); + lacSessCtx->symOperation = CPA_CY_SYM_OP_HASH; + lacSessCtx->hashSetupData.hashAlgorithm = CPA_CY_SYM_HASH_MD5; + lacSessCtx->hashSetupData.hashMode = CPA_CY_SYM_HASH_MODE_PLAIN; + lacSessCtx->hashSetupData.digestResultLenInBytes = + (cri->cri_mlen ? + cri->cri_mlen : ICP_MD5_DIGEST_SIZE_IN_BYTES); + + break; + + case CRYPTO_MD5_HMAC: + DPRINTK("%s(): MD5_HMAC\n", __FUNCTION__); + lacSessCtx->symOperation = CPA_CY_SYM_OP_HASH; + lacSessCtx->hashSetupData.hashAlgorithm = CPA_CY_SYM_HASH_MD5; + lacSessCtx->hashSetupData.hashMode = CPA_CY_SYM_HASH_MODE_AUTH; + lacSessCtx->hashSetupData.digestResultLenInBytes = + (cri->cri_mlen ? + cri->cri_mlen : ICP_MD5_DIGEST_SIZE_IN_BYTES); + lacSessCtx->hashSetupData.authModeSetupData.authKey = + cri->cri_key; + lacSessCtx->hashSetupData.authModeSetupData.authKeyLenInBytes = + cri->cri_klen / NUM_BITS_IN_BYTE; + lacSessCtx->hashSetupData.authModeSetupData.aadLenInBytes = 0; + + break; + + default: + DPRINTK("%s(): ALG Setup FAIL\n", __FUNCTION__); + return ICP_OCF_DRV_STATUS_FAIL; + } + + return ICP_OCF_DRV_STATUS_SUCCESS; +} + +/* Name : icp_ocfDrvFreeOCFSession + * + * Description : This function deletes all existing Session data representing + * the Cryptographic session established between OCF and this driver. This + * also includes freeing the memory allocated for the session context. The + * session object is also removed from the session linked list. + */ +static void icp_ocfDrvFreeOCFSession(struct icp_drvSessionData *sessionData) +{ + + sessionData->inUse = ICP_SESSION_DEREGISTERED; + + /*ENTER CRITICAL SECTION */ + spin_lock_bh(&icp_ocfDrvSymSessInfoListSpinlock); + + if (CPA_TRUE == atomic_read(&icp_ocfDrvIsExiting)) { + /*If the Driver is exiting, allow that process to + handle any deletions */ + /*EXIT CRITICAL SECTION */ + spin_unlock_bh(&icp_ocfDrvSymSessInfoListSpinlock); + return; + } + + atomic_dec(&num_ocf_to_drv_registered_sessions); + + list_del(&(sessionData->listNode)); + + /*EXIT CRITICAL SECTION */ + spin_unlock_bh(&icp_ocfDrvSymSessInfoListSpinlock); + + if (NULL != sessionData->sessHandle) { + kfree(sessionData->sessHandle); + } + kmem_cache_free(drvSessionData_zone, sessionData); +} + +/* Name : icp_ocfDrvFreeLACSession + * + * Description : This attempts to deregister a LAC session. If it fails, the + * deregistation retry function is called. + */ +int icp_ocfDrvFreeLACSession(device_t dev, uint64_t sid) +{ + CpaCySymSessionCtx sessionToDeregister = NULL; + struct icp_drvSessionData *sessionData = NULL; + CpaStatus lacStatus = CPA_STATUS_SUCCESS; + int retval = 0; + + sessionData = (struct icp_drvSessionData *)CRYPTO_SESID2LID(sid); + if (NULL == sessionData) { + EPRINTK("%s(): OCF Free session called with Null Session ID.\n", + __FUNCTION__); + return EINVAL; + } + + sessionToDeregister = sessionData->sessHandle; + + if (ICP_SESSION_INITIALISED == sessionData->inUse) { + DPRINTK("%s() Session not registered with LAC\n", __FUNCTION__); + } else if (NULL == sessionData->sessHandle) { + EPRINTK + ("%s(): OCF Free session called with Null Session Handle.\n", + __FUNCTION__); + return EINVAL; + } else { + lacStatus = cpaCySymRemoveSession(CPA_INSTANCE_HANDLE_SINGLE, + sessionToDeregister); + if (CPA_STATUS_RETRY == lacStatus) { + if (ICP_OCF_DRV_STATUS_SUCCESS != + icp_ocfDrvDeregRetry(&sessionToDeregister)) { + /* the retry function increments the + dereg failed count */ + DPRINTK("%s(): LAC failed to deregister the " + "session. (localSessionId= %p)\n", + __FUNCTION__, sessionToDeregister); + retval = EPERM; + } + + } else if (CPA_STATUS_SUCCESS != lacStatus) { + DPRINTK("%s(): LAC failed to deregister the session. " + "localSessionId= %p, lacStatus = %d\n", + __FUNCTION__, sessionToDeregister, lacStatus); + atomic_inc(&lac_session_failed_dereg_count); + retval = EPERM; + } + } + + icp_ocfDrvFreeOCFSession(sessionData); + return retval; + +} + +/* Name : icp_ocfDrvAlgCheck + * + * Description : This function checks whether the cryptodesc argument pertains + * to a sym or hash function + */ +static int icp_ocfDrvAlgCheck(struct cryptodesc *crp_desc) +{ + + if (crp_desc->crd_alg == CRYPTO_3DES_CBC || + crp_desc->crd_alg == CRYPTO_AES_CBC || + crp_desc->crd_alg == CRYPTO_DES_CBC || + crp_desc->crd_alg == CRYPTO_NULL_CBC || + crp_desc->crd_alg == CRYPTO_ARC4) { + return ICP_OCF_DRV_ALG_CIPHER; + } + + return ICP_OCF_DRV_ALG_HASH; +} + +/* Name : icp_ocfDrvSymProcess + * + * Description : This function will map symmetric functionality calls from OCF + * to the LAC API. It will also allocate memory to store the session context. + * + * Notes: If it is the first perform call for a given session, then a LAC + * session is registered. After the session is registered, no checks as + * to whether session paramaters have changed (e.g. alg chain order) are + * done. + */ +int icp_ocfDrvSymProcess(device_t dev, struct cryptop *crp, int hint) +{ + struct icp_drvSessionData *sessionData = NULL; + struct icp_drvOpData *drvOpData = NULL; + CpaStatus lacStatus = CPA_STATUS_SUCCESS; + Cpa32U sessionCtxSizeInBytes = 0; + uint16_t numBufferListArray = 0; + + if (NULL == crp) { + DPRINTK("%s(): Invalid input parameters, cryptop is NULL\n", + __FUNCTION__); + return EINVAL; + } + + if (NULL == crp->crp_desc) { + DPRINTK("%s(): Invalid input parameters, no crp_desc attached " + "to crp\n", __FUNCTION__); + crp->crp_etype = EINVAL; + return EINVAL; + } + + if (NULL == crp->crp_buf) { + DPRINTK("%s(): Invalid input parameters, no buffer attached " + "to crp\n", __FUNCTION__); + crp->crp_etype = EINVAL; + return EINVAL; + } + + if (CPA_TRUE == atomic_read(&icp_ocfDrvIsExiting)) { + crp->crp_etype = EFAULT; + return EFAULT; + } + + sessionData = (struct icp_drvSessionData *) + (CRYPTO_SESID2LID(crp->crp_sid)); + if (NULL == sessionData) { + DPRINTK("%s(): Invalid input parameters, Null Session ID \n", + __FUNCTION__); + crp->crp_etype = EINVAL; + return EINVAL; + } + +/*If we get a request against a deregisted session, cancel operation*/ + if (ICP_SESSION_DEREGISTERED == sessionData->inUse) { + DPRINTK("%s(): Session ID %d was deregistered \n", + __FUNCTION__, (int)(CRYPTO_SESID2LID(crp->crp_sid))); + crp->crp_etype = EFAULT; + return EFAULT; + } + +/*If none of the session states are set, then the session structure was either + not initialised properly or we are reading from a freed memory area (possible + due to OCF batch mode not removing queued requests against deregistered + sessions*/ + if (ICP_SESSION_INITIALISED != sessionData->inUse && + ICP_SESSION_RUNNING != sessionData->inUse) { + DPRINTK("%s(): Session - ID %d - not properly initialised or " + "memory freed back to the kernel \n", + __FUNCTION__, (int)(CRYPTO_SESID2LID(crp->crp_sid))); + crp->crp_etype = EINVAL; + return EINVAL; + } + + /*For the below checks, remember error checking is already done in LAC. + We're not validating inputs subsequent to registration */ + if (sessionData->inUse == ICP_SESSION_INITIALISED) { + DPRINTK("%s(): Initialising session\n", __FUNCTION__); + + if (NULL != crp->crp_desc->crd_next) { + if (ICP_OCF_DRV_ALG_CIPHER == + icp_ocfDrvAlgCheck(crp->crp_desc)) { + + sessionData->lacSessCtx.algChainOrder = + CPA_CY_SYM_ALG_CHAIN_ORDER_CIPHER_THEN_HASH; + + if (crp->crp_desc->crd_flags & CRD_F_ENCRYPT) { + sessionData->lacSessCtx.cipherSetupData. + cipherDirection = + CPA_CY_SYM_CIPHER_DIRECTION_ENCRYPT; + } else { + sessionData->lacSessCtx.cipherSetupData. + cipherDirection = + CPA_CY_SYM_CIPHER_DIRECTION_DECRYPT; + } + } else { + sessionData->lacSessCtx.algChainOrder = + CPA_CY_SYM_ALG_CHAIN_ORDER_HASH_THEN_CIPHER; + + if (crp->crp_desc->crd_next->crd_flags & + CRD_F_ENCRYPT) { + sessionData->lacSessCtx.cipherSetupData. + cipherDirection = + CPA_CY_SYM_CIPHER_DIRECTION_ENCRYPT; + } else { + sessionData->lacSessCtx.cipherSetupData. + cipherDirection = + CPA_CY_SYM_CIPHER_DIRECTION_DECRYPT; + } + + } + + } else if (ICP_OCF_DRV_ALG_CIPHER == + icp_ocfDrvAlgCheck(crp->crp_desc)) { + if (crp->crp_desc->crd_flags & CRD_F_ENCRYPT) { + sessionData->lacSessCtx.cipherSetupData. + cipherDirection = + CPA_CY_SYM_CIPHER_DIRECTION_ENCRYPT; + } else { + sessionData->lacSessCtx.cipherSetupData. + cipherDirection = + CPA_CY_SYM_CIPHER_DIRECTION_DECRYPT; + } + + } + + /*No action required for standalone Auth here */ + + /* Allocate memory for SymSessionCtx before the Session Registration */ + lacStatus = + cpaCySymSessionCtxGetSize(CPA_INSTANCE_HANDLE_SINGLE, + &(sessionData->lacSessCtx), + &sessionCtxSizeInBytes); + if (CPA_STATUS_SUCCESS != lacStatus) { + EPRINTK("%s(): cpaCySymSessionCtxGetSize failed - %d\n", + __FUNCTION__, lacStatus); + return EINVAL; + } + sessionData->sessHandle = + kmalloc(sessionCtxSizeInBytes, GFP_ATOMIC); + if (NULL == sessionData->sessHandle) { + EPRINTK + ("%s(): Failed to get memory for SymSessionCtx\n", + __FUNCTION__); + return ENOMEM; + } + + lacStatus = cpaCySymInitSession(CPA_INSTANCE_HANDLE_SINGLE, + icp_ocfDrvSymCallBack, + &(sessionData->lacSessCtx), + sessionData->sessHandle); + + if (CPA_STATUS_SUCCESS != lacStatus) { + EPRINTK("%s(): cpaCySymInitSession failed -%d \n", + __FUNCTION__, lacStatus); + return EFAULT; + } + + sessionData->inUse = ICP_SESSION_RUNNING; + } + + drvOpData = kmem_cache_zalloc(drvOpData_zone, GFP_ATOMIC); + if (NULL == drvOpData) { + EPRINTK("%s():Failed to get memory for drvOpData\n", + __FUNCTION__); + crp->crp_etype = ENOMEM; + return ENOMEM; + } + + drvOpData->lacOpData.pSessionCtx = sessionData->sessHandle; + drvOpData->digestSizeInBytes = sessionData->lacSessCtx.hashSetupData. + digestResultLenInBytes; + drvOpData->crp = crp; + + /* Set the default buffer list array memory allocation */ + drvOpData->srcBuffer.pBuffers = drvOpData->bufferListArray; + drvOpData->numBufferListArray = ICP_OCF_DRV_DEFAULT_BUFFLIST_ARRAYS; + + /* + * Allocate buffer list array memory allocation if the + * data fragment is more than the default allocation + */ + if (crp->crp_flags & CRYPTO_F_SKBUF) { + numBufferListArray = icp_ocfDrvGetSkBuffFrags((struct sk_buff *) + crp->crp_buf); + if (ICP_OCF_DRV_DEFAULT_BUFFLIST_ARRAYS < numBufferListArray) { + DPRINTK("%s() numBufferListArray more than default\n", + __FUNCTION__); + drvOpData->srcBuffer.pBuffers = NULL; + drvOpData->srcBuffer.pBuffers = + kmalloc(numBufferListArray * + sizeof(CpaFlatBuffer), GFP_ATOMIC); + if (NULL == drvOpData->srcBuffer.pBuffers) { + EPRINTK("%s() Failed to get memory for " + "pBuffers\n", __FUNCTION__); + kmem_cache_free(drvOpData_zone, drvOpData); + crp->crp_etype = ENOMEM; + return ENOMEM; + } + drvOpData->numBufferListArray = numBufferListArray; + } + } + + /* + * Check the type of buffer structure we got and convert it into + * CpaBufferList format. + */ + if (crp->crp_flags & CRYPTO_F_SKBUF) { + if (ICP_OCF_DRV_STATUS_SUCCESS != + icp_ocfDrvSkBuffToBufferList((struct sk_buff *)crp->crp_buf, + &(drvOpData->srcBuffer))) { + EPRINTK("%s():Failed to translate from SK_BUF " + "to bufferlist\n", __FUNCTION__); + crp->crp_etype = EINVAL; + goto err; + } + + drvOpData->bufferType = CRYPTO_F_SKBUF; + } else if (crp->crp_flags & CRYPTO_F_IOV) { + /* OCF only supports IOV of one entry. */ + if (NUM_IOV_SUPPORTED == + ((struct uio *)(crp->crp_buf))->uio_iovcnt) { + + icp_ocfDrvPtrAndLenToBufferList(((struct uio *)(crp-> + crp_buf))-> + uio_iov[0].iov_base, + ((struct uio *)(crp-> + crp_buf))-> + uio_iov[0].iov_len, + &(drvOpData-> + srcBuffer)); + + drvOpData->bufferType = CRYPTO_F_IOV; + + } else { + DPRINTK("%s():Unable to handle IOVs with lengths of " + "greater than one!\n", __FUNCTION__); + crp->crp_etype = EINVAL; + goto err; + } + + } else { + icp_ocfDrvPtrAndLenToBufferList(crp->crp_buf, + crp->crp_ilen, + &(drvOpData->srcBuffer)); + + drvOpData->bufferType = CRYPTO_BUF_CONTIG; + } + + if (ICP_OCF_DRV_STATUS_SUCCESS != + icp_ocfDrvProcessDataSetup(drvOpData, drvOpData->crp->crp_desc)) { + crp->crp_etype = EINVAL; + goto err; + } + + if (drvOpData->crp->crp_desc->crd_next != NULL) { + if (icp_ocfDrvProcessDataSetup(drvOpData, drvOpData->crp-> + crp_desc->crd_next)) { + crp->crp_etype = EINVAL; + goto err; + } + + } + + /* Allocate srcBuffer's private meta data */ + if (ICP_OCF_DRV_STATUS_SUCCESS != + icp_ocfDrvAllocMetaData(&(drvOpData->srcBuffer), drvOpData)) { + EPRINTK("%s() icp_ocfDrvAllocMetaData failed\n", __FUNCTION__); + memset(&(drvOpData->lacOpData), 0, sizeof(CpaCySymOpData)); + crp->crp_etype = EINVAL; + goto err; + } + + /* Perform "in-place" crypto operation */ + lacStatus = cpaCySymPerformOp(CPA_INSTANCE_HANDLE_SINGLE, + (void *)drvOpData, + &(drvOpData->lacOpData), + &(drvOpData->srcBuffer), + &(drvOpData->srcBuffer), + &(drvOpData->verifyResult)); + if (CPA_STATUS_RETRY == lacStatus) { + DPRINTK("%s(): cpaCySymPerformOp retry, lacStatus = %d\n", + __FUNCTION__, lacStatus); + memset(&(drvOpData->lacOpData), 0, sizeof(CpaCySymOpData)); + crp->crp_etype = EINVAL; + goto err; + } + if (CPA_STATUS_SUCCESS != lacStatus) { + EPRINTK("%s(): cpaCySymPerformOp failed, lacStatus = %d\n", + __FUNCTION__, lacStatus); + memset(&(drvOpData->lacOpData), 0, sizeof(CpaCySymOpData)); + crp->crp_etype = EINVAL; + goto err; + } + + return 0; //OCF success status value + + err: + if (drvOpData->numBufferListArray > ICP_OCF_DRV_DEFAULT_BUFFLIST_ARRAYS) { + kfree(drvOpData->srcBuffer.pBuffers); + } + icp_ocfDrvFreeMetaData(&(drvOpData->srcBuffer)); + kmem_cache_free(drvOpData_zone, drvOpData); + + return crp->crp_etype; +} + +/* Name : icp_ocfDrvProcessDataSetup + * + * Description : This function will setup all the cryptographic operation data + * that is required by LAC to execute the operation. + */ +static int icp_ocfDrvProcessDataSetup(struct icp_drvOpData *drvOpData, + struct cryptodesc *crp_desc) +{ + CpaCyRandGenOpData randGenOpData; + CpaFlatBuffer randData; + + drvOpData->lacOpData.packetType = CPA_CY_SYM_PACKET_TYPE_FULL; + + /* Convert from the cryptop to the ICP LAC crypto parameters */ + switch (crp_desc->crd_alg) { + case CRYPTO_NULL_CBC: + drvOpData->lacOpData. + cryptoStartSrcOffsetInBytes = crp_desc->crd_skip; + drvOpData->lacOpData. + messageLenToCipherInBytes = crp_desc->crd_len; + drvOpData->verifyResult = CPA_FALSE; + drvOpData->lacOpData.ivLenInBytes = NULL_BLOCK_LEN; + break; + case CRYPTO_DES_CBC: + drvOpData->lacOpData. + cryptoStartSrcOffsetInBytes = crp_desc->crd_skip; + drvOpData->lacOpData. + messageLenToCipherInBytes = crp_desc->crd_len; + drvOpData->verifyResult = CPA_FALSE; + drvOpData->lacOpData.ivLenInBytes = DES_BLOCK_LEN; + break; + case CRYPTO_3DES_CBC: + drvOpData->lacOpData. + cryptoStartSrcOffsetInBytes = crp_desc->crd_skip; + drvOpData->lacOpData. + messageLenToCipherInBytes = crp_desc->crd_len; + drvOpData->verifyResult = CPA_FALSE; + drvOpData->lacOpData.ivLenInBytes = DES3_BLOCK_LEN; + break; + case CRYPTO_ARC4: + drvOpData->lacOpData. + cryptoStartSrcOffsetInBytes = crp_desc->crd_skip; + drvOpData->lacOpData. + messageLenToCipherInBytes = crp_desc->crd_len; + drvOpData->verifyResult = CPA_FALSE; + drvOpData->lacOpData.ivLenInBytes = ARC4_COUNTER_LEN; + break; + case CRYPTO_AES_CBC: + drvOpData->lacOpData. + cryptoStartSrcOffsetInBytes = crp_desc->crd_skip; + drvOpData->lacOpData. + messageLenToCipherInBytes = crp_desc->crd_len; + drvOpData->verifyResult = CPA_FALSE; + drvOpData->lacOpData.ivLenInBytes = RIJNDAEL128_BLOCK_LEN; + break; + case CRYPTO_SHA1: + case CRYPTO_SHA1_HMAC: + case CRYPTO_SHA2_256: + case CRYPTO_SHA2_256_HMAC: + case CRYPTO_SHA2_384: + case CRYPTO_SHA2_384_HMAC: + case CRYPTO_SHA2_512: + case CRYPTO_SHA2_512_HMAC: + case CRYPTO_MD5: + case CRYPTO_MD5_HMAC: + drvOpData->lacOpData. + hashStartSrcOffsetInBytes = crp_desc->crd_skip; + drvOpData->lacOpData. + messageLenToHashInBytes = crp_desc->crd_len; + drvOpData->lacOpData. + pDigestResult = + icp_ocfDrvDigestPointerFind(drvOpData, crp_desc); + + if (NULL == drvOpData->lacOpData.pDigestResult) { + DPRINTK("%s(): ERROR - could not calculate " + "Digest Result memory address\n", __FUNCTION__); + return ICP_OCF_DRV_STATUS_FAIL; + } + + drvOpData->lacOpData.digestVerify = CPA_FALSE; + break; + default: + DPRINTK("%s(): Crypto process error - algorithm not " + "found \n", __FUNCTION__); + return ICP_OCF_DRV_STATUS_FAIL; + } + + /* Figure out what the IV is supposed to be */ + if ((crp_desc->crd_alg == CRYPTO_DES_CBC) || + (crp_desc->crd_alg == CRYPTO_3DES_CBC) || + (crp_desc->crd_alg == CRYPTO_AES_CBC)) { + /*ARC4 doesn't use an IV */ + if (crp_desc->crd_flags & CRD_F_IV_EXPLICIT) { + /* Explicit IV provided to OCF */ + drvOpData->lacOpData.pIv = crp_desc->crd_iv; + } else { + /* IV is not explicitly provided to OCF */ + + /* Point the LAC OP Data IV pointer to our allocated + storage location for this session. */ + drvOpData->lacOpData.pIv = drvOpData->ivData; + + if ((crp_desc->crd_flags & CRD_F_ENCRYPT) && + ((crp_desc->crd_flags & CRD_F_IV_PRESENT) == 0)) { + + /* Encrypting - need to create IV */ + randGenOpData.generateBits = CPA_TRUE; + randGenOpData.lenInBytes = MAX_IV_LEN_IN_BYTES; + + icp_ocfDrvPtrAndLenToFlatBuffer((Cpa8U *) + drvOpData-> + ivData, + MAX_IV_LEN_IN_BYTES, + &randData); + + if (CPA_STATUS_SUCCESS != + cpaCyRandGen(CPA_INSTANCE_HANDLE_SINGLE, + NULL, NULL, + &randGenOpData, &randData)) { + DPRINTK("%s(): ERROR - Failed to" + " generate" + " Initialisation Vector\n", + __FUNCTION__); + return ICP_OCF_DRV_STATUS_FAIL; + } + + crypto_copyback(drvOpData->crp-> + crp_flags, + drvOpData->crp->crp_buf, + crp_desc->crd_inject, + drvOpData->lacOpData. + ivLenInBytes, + (caddr_t) (drvOpData->lacOpData. + pIv)); + } else { + /* Reading IV from buffer */ + crypto_copydata(drvOpData->crp-> + crp_flags, + drvOpData->crp->crp_buf, + crp_desc->crd_inject, + drvOpData->lacOpData. + ivLenInBytes, + (caddr_t) (drvOpData->lacOpData. + pIv)); + } + + } + + } + + return ICP_OCF_DRV_STATUS_SUCCESS; +} + +/* Name : icp_ocfDrvDigestPointerFind + * + * Description : This function is used to find the memory address of where the + * digest information shall be stored in. Input buffer types are an skbuff, iov + * or flat buffer. The address is found using the buffer data start address and + * an offset. + * + * Note: In the case of a linux skbuff, the digest address may exist within + * a memory space linked to from the start buffer. These linked memory spaces + * must be traversed by the data length offset in order to find the digest start + * address. Whether there is enough space for the digest must also be checked. + */ + +static uint8_t *icp_ocfDrvDigestPointerFind(struct icp_drvOpData *drvOpData, + struct cryptodesc *crp_desc) +{ + + int offsetInBytes = crp_desc->crd_inject; + uint32_t digestSizeInBytes = drvOpData->digestSizeInBytes; + uint8_t *flat_buffer_base = NULL; + int flat_buffer_length = 0; + struct sk_buff *skb; + + if (drvOpData->crp->crp_flags & CRYPTO_F_SKBUF) { + /*check if enough overall space to store hash */ + skb = (struct sk_buff *)(drvOpData->crp->crp_buf); + + if (skb->len < (offsetInBytes + digestSizeInBytes)) { + DPRINTK("%s() Not enough space for Digest" + " payload after the offset (%d), " + "digest size (%d) \n", __FUNCTION__, + offsetInBytes, digestSizeInBytes); + return NULL; + } + + return icp_ocfDrvSkbuffDigestPointerFind(drvOpData, + offsetInBytes, + digestSizeInBytes); + + } else { + /* IOV or flat buffer */ + if (drvOpData->crp->crp_flags & CRYPTO_F_IOV) { + /*single IOV check has already been done */ + flat_buffer_base = ((struct uio *) + (drvOpData->crp->crp_buf))-> + uio_iov[0].iov_base; + flat_buffer_length = ((struct uio *) + (drvOpData->crp->crp_buf))-> + uio_iov[0].iov_len; + } else { + flat_buffer_base = (uint8_t *) drvOpData->crp->crp_buf; + flat_buffer_length = drvOpData->crp->crp_ilen; + } + + if (flat_buffer_length < (offsetInBytes + digestSizeInBytes)) { + DPRINTK("%s() Not enough space for Digest " + "(IOV/Flat Buffer) \n", __FUNCTION__); + return NULL; + } else { + return (uint8_t *) (flat_buffer_base + offsetInBytes); + } + } + DPRINTK("%s() Should not reach this point\n", __FUNCTION__); + return NULL; +} + +/* Name : icp_ocfDrvSkbuffDigestPointerFind + * + * Description : This function is used by icp_ocfDrvDigestPointerFind to process + * the non-linear portion of the skbuff if the fragmentation type is a linked + * list (frag_list is not NULL in the skb_shared_info structure) + */ +static inline uint8_t *icp_ocfDrvSkbuffDigestPointerFind(struct icp_drvOpData + *drvOpData, + int offsetInBytes, + uint32_t + digestSizeInBytes) +{ + + struct sk_buff *skb = NULL; + struct skb_shared_info *skb_shared = NULL; + + uint32_t skbuffisnonlinear = 0; + + uint32_t skbheadlen = 0; + + skb = (struct sk_buff *)(drvOpData->crp->crp_buf); + skbuffisnonlinear = skb_is_nonlinear(skb); + + skbheadlen = skb_headlen(skb); + + /*Linear skb checks */ + if (skbheadlen > offsetInBytes) { + + if (skbheadlen >= (offsetInBytes + digestSizeInBytes)) { + return (uint8_t *) (skb->data + offsetInBytes); + } else { + DPRINTK("%s() Auth payload stretches " + "accross contiguous memory\n", __FUNCTION__); + return NULL; + } + } else { + if (skbuffisnonlinear) { + offsetInBytes -= skbheadlen; + } else { + DPRINTK("%s() Offset outside of buffer boundaries\n", + __FUNCTION__); + return NULL; + } + } + + /*Non Linear checks */ + skb_shared = (struct skb_shared_info *)(skb->end); + if (unlikely(NULL == skb_shared)) { + DPRINTK("%s() skbuff shared info stucture is NULL! \n", + __FUNCTION__); + return NULL; + } else if ((0 != skb_shared->nr_frags) && + (skb_shared->frag_list != NULL)) { + DPRINTK("%s() skbuff nr_frags AND " + "frag_list not supported \n", __FUNCTION__); + return NULL; + } + + /*TCP segmentation more likely than IP fragmentation */ + if (likely(0 != skb_shared->nr_frags)) { + return icp_ocfDrvDigestSkbNRFragsCheck(skb, skb_shared, + offsetInBytes, + digestSizeInBytes); + } else if (skb_shared->frag_list != NULL) { + return icp_ocfDrvDigestSkbFragListCheck(skb, skb_shared, + offsetInBytes, + digestSizeInBytes); + } else { + DPRINTK("%s() skbuff is non-linear but does not show any " + "linked data\n", __FUNCTION__); + return NULL; + } + +} + +/* Name : icp_ocfDrvDigestSkbNRFragsCheck + * + * Description : This function is used by icp_ocfDrvSkbuffDigestPointerFind to + * process the non-linear portion of the skbuff, if the fragmentation type is + * page fragments + */ +static inline uint8_t *icp_ocfDrvDigestSkbNRFragsCheck(struct sk_buff *skb, + struct skb_shared_info + *skb_shared, + int offsetInBytes, + uint32_t + digestSizeInBytes) +{ + int i = 0; + /*nr_frags starts from 1 */ + if (MAX_SKB_FRAGS < skb_shared->nr_frags) { + DPRINTK("%s error processing skbuff " + "page frame -- MAX FRAGS exceeded \n", __FUNCTION__); + return NULL; + } + + for (i = 0; i < skb_shared->nr_frags; i++) { + + if (offsetInBytes >= skb_shared->frags[i].size) { + /*offset still greater than data position */ + offsetInBytes -= skb_shared->frags[i].size; + } else { + /* found the page containing start of hash */ + + if (NULL == skb_shared->frags[i].page) { + DPRINTK("%s() Linked page is NULL!\n", + __FUNCTION__); + return NULL; + } + + if (offsetInBytes + digestSizeInBytes > + skb_shared->frags[i].size) { + DPRINTK("%s() Auth payload stretches accross " + "contiguous memory\n", __FUNCTION__); + return NULL; + } else { + return (uint8_t *) (skb_shared->frags[i].page + + skb_shared->frags[i]. + page_offset + + offsetInBytes); + } + } + /*only possible if internal page sizes are set wrong */ + if (offsetInBytes < 0) { + DPRINTK("%s error processing skbuff page frame " + "-- offset calculation \n", __FUNCTION__); + return NULL; + } + } + /*only possible if internal page sizes are set wrong */ + DPRINTK("%s error processing skbuff page frame " + "-- ran out of page fragments, remaining offset = %d \n", + __FUNCTION__, offsetInBytes); + return NULL; + +} + +/* Name : icp_ocfDrvDigestSkbFragListCheck + * + * Description : This function is used by icp_ocfDrvSkbuffDigestPointerFind to + * process the non-linear portion of the skbuff, if the fragmentation type is + * a linked list + * + */ +static inline uint8_t *icp_ocfDrvDigestSkbFragListCheck(struct sk_buff *skb, + struct skb_shared_info + *skb_shared, + int offsetInBytes, + uint32_t + digestSizeInBytes) +{ + + struct sk_buff *skb_list = skb_shared->frag_list; + /*check added for readability */ + if (NULL == skb_list) { + DPRINTK("%s error processing skbuff " + "-- no more list! \n", __FUNCTION__); + return NULL; + } + + for (; skb_list; skb_list = skb_list->next) { + if (NULL == skb_list) { + DPRINTK("%s error processing skbuff " + "-- no more list! \n", __FUNCTION__); + return NULL; + } + + if (offsetInBytes >= skb_list->len) { + offsetInBytes -= skb_list->len; + + } else { + if (offsetInBytes + digestSizeInBytes > skb_list->len) { + DPRINTK("%s() Auth payload stretches accross " + "contiguous memory\n", __FUNCTION__); + return NULL; + } else { + return (uint8_t *) + (skb_list->data + offsetInBytes); + } + + } + + /*This check is only needed if internal skb_list length values + are set wrong. */ + if (0 > offsetInBytes) { + DPRINTK("%s() error processing skbuff object -- offset " + "calculation \n", __FUNCTION__); + return NULL; + } + + } + + /*catch all for unusual for-loop exit. + This code should never be reached */ + DPRINTK("%s() Catch-All hit! Process error.\n", __FUNCTION__); + return NULL; +} diff --git a/target/linux/generic-2.6/files/crypto/ocf/ep80579/linux_2.6_kernel_space.mk b/target/linux/generic-2.6/files/crypto/ocf/ep80579/linux_2.6_kernel_space.mk new file mode 100644 index 0000000000..96afa9a453 --- /dev/null +++ b/target/linux/generic-2.6/files/crypto/ocf/ep80579/linux_2.6_kernel_space.mk @@ -0,0 +1,69 @@ +################### +# @par +# This file is provided under a dual BSD/GPLv2 license. When using or +# redistributing this file, you may do so under either license. +# +# GPL LICENSE SUMMARY +# +# Copyright(c) 2007,2008 Intel Corporation. All rights reserved. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. +# The full GNU General Public License is included in this distribution +# in the file called LICENSE.GPL. +# +# Contact Information: +# Intel Corporation +# +# BSD LICENSE +# +# Copyright(c) 2007,2008 Intel Corporation. All rights reserved. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Intel Corporation nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# +# version: Security.L.1.0.130 +################### + +#specific include directories in kernel space +INCLUDES+=#e.g. -I$(OSAL_DIR)/include \ + +#Extra Flags Specific in kernel space e.g. include path or debug flags etc. e.g to add an include path EXTRA_CFLAGS += -I$(src)/../include +EXTRA_CFLAGS += $(INCLUDES) -O2 -Wall +EXTRA_LDFLAGS +=-whole-archive + |