The patch implements asynchronous out-of-place ODP crypto operations:
results are stored in a new buffer.

Implementation based on NWAL library.

Signed-off-by: Taras Kondratiuk <[email protected]>
Signed-off-by: Taras Kondratiuk <[email protected]>
---
 platform/linux-keystone2/Makefile.am               |    2 +
 platform/linux-keystone2/README                    |    2 +-
 platform/linux-keystone2/include/api/odp_crypto.h  |  375 +++++++++++++++
 .../linux-keystone2/include/odp_crypto_internal.h  |   84 ++++
 platform/linux-keystone2/include/odp_internal.h    |    2 +
 platform/linux-keystone2/odp_crypto.c              |  490 ++++++++++++++++++++
 platform/linux-keystone2/odp_init.c                |    5 +
 7 files changed, 959 insertions(+), 1 deletion(-)
 create mode 100644 platform/linux-keystone2/include/api/odp_crypto.h
 create mode 100644 platform/linux-keystone2/include/odp_crypto_internal.h
 create mode 100644 platform/linux-keystone2/odp_crypto.c

diff --git a/platform/linux-keystone2/Makefile.am 
b/platform/linux-keystone2/Makefile.am
index c94edf2..61b58b7 100644
--- a/platform/linux-keystone2/Makefile.am
+++ b/platform/linux-keystone2/Makefile.am
@@ -19,6 +19,7 @@ LIBS += $(KS2_LIBS)
 include_HEADERS = \
                  $(srcdir)/include/api/odp_buffer.h \
                  $(srcdir)/include/api/odp_buffer_pool.h \
+                 $(srcdir)/include/api/odp_crypto.h \
                  $(srcdir)/include/api/odp_packet.h \
                  $(srcdir)/include/api/odp_packet_io.h \
                  $(srcdir)/include/api/odp_debug.h \
@@ -63,6 +64,7 @@ subdirheaders_HEADERS = \
 __LIB__libodp_la_SOURCES = \
                           odp_buffer.c \
                           odp_buffer_pool.c \
+                          odp_crypto.c \
                           odp_init.c \
                           odp_packet.c \
                           odp_packet_io.c \
diff --git a/platform/linux-keystone2/README b/platform/linux-keystone2/README
index 207acf2..9a7e807 100644
--- a/platform/linux-keystone2/README
+++ b/platform/linux-keystone2/README
@@ -7,7 +7,7 @@ SPDX-License-Identifier:     BSD-3-Clause
 1. Intro
 
 OpenDataPlane implementation for TI Keystone2 SoC's. Current version supports
-HW buffer, queues and Packet IO management. This drop does not target high
+HW buffer, queues, Packet IO and Crypto APIs. This drop does not target high
 performance. It is rather proof of ODP API functionality. It still uses
 linux-generic's SW scheduler.
 
diff --git a/platform/linux-keystone2/include/api/odp_crypto.h 
b/platform/linux-keystone2/include/api/odp_crypto.h
new file mode 100644
index 0000000..9082f9b
--- /dev/null
+++ b/platform/linux-keystone2/include/api/odp_crypto.h
@@ -0,0 +1,375 @@
+/*
+ * Copyright (c) 2014, Linaro Limited
+ * Copyright (c) 2014, Texas Instruments Incorporated
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ */
+
+/**
+ * @file
+ *
+ * ODP crypto
+ */
+
+#ifndef ODP_CRYPTO_H_
+#define ODP_CRYPTO_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <odp_std_types.h>
+#include <odp_buffer.h>
+#include <odp_buffer_pool.h>
+#include <odp_queue.h>
+#include <odp_packet.h>
+#include <ti/drv/nwal/nwal.h>
+
+/** Invalid session handle */
+#define ODP_CRYPTO_SESSION_INVALID NULL
+
+/**
+ * Crypto API opaque session handle
+ */
+typedef struct odp_crypto_session_s *odp_crypto_session_t;
+
+/**
+ * Crypto API operation mode
+ */
+enum odp_crypto_op_mode {
+       ODP_CRYPTO_SYNC,    /**< Synchronous, return results immediately */
+       ODP_CRYPTO_ASYNC,   /**< Aynchronous, return results via posted event */
+};
+
+/**
+ * Crypto API operation type
+ */
+enum odp_crypto_op {
+       ODP_CRYPTO_OP_ENCODE, /**< Encrypt and/or compute authentication ICV */
+       ODP_CRYPTO_OP_DECODE  /**< Decrypt and/or verify authentication ICV */
+};
+
+/**
+ * Crypto API cipher algorithm
+ */
+enum  odp_cipher_alg {
+       ODP_CIPHER_ALG_NULL = NWAL_SA_EALG_NULL,         /**< No cipher 
algorithm specified */
+       ODP_CIPHER_ALG_DES = NWAL_SA_EALG_DES_CBC,       /**< DES */
+       ODP_CIPHER_ALG_3DES_CBC = NWAL_SA_EALG_3DES_CBC, /**< Triple DES with 
cipher block chaining */
+       ODP_CIPHER_ALG_AES_CBC = NWAL_SA_EALG_AES_CBC,
+       ODP_CIPHER_ALG_AES_CTR = NWAL_SA_EALG_AES_CTR,
+       ODP_CIPHER_ALG_AES_GCM = NWAL_SA_EALG_AES_GCM,
+       ODP_CIPHER_ALG_AES_CCM = NWAL_SA_EALG_AES_CCM,
+};
+
+/**
+ * Crypto API authentication algorithm
+ */
+enum odp_auth_alg {
+       ODP_AUTH_ALG_NULL = NWAL_SA_AALG_NULL,           /**< No authentication 
algorithm specified */
+       ODP_AUTH_ALG_MD5_96 = NWAL_SA_AALG_HMAC_MD5,     /**< HMAC-MD5 with 96 
bit key */
+       ODP_AUTH_ALG_HMAC_SHA1 = NWAL_SA_AALG_HMAC_SHA1,
+};
+
+/**
+ * Crypto API key structure
+ */
+typedef struct odp_crypto_key {
+       uint8_t *data;       /**< Key data */
+       uint32_t length;     /**< Key length in bytes */
+} odp_crypto_key_t;
+
+/**
+ * Crypto API IV structure
+ */
+typedef struct odp_crypto_iv {
+       uint8_t *data;      /**< IV data */
+       uint32_t length;    /**< IV length in bytes */
+} odp_crypto_iv_t;
+
+/**
+ * Crypto API data range specifier
+ */
+typedef struct odp_crypto_data_range {
+       uint32_t offset;  /**< Offset from beginning of buffer (chain) */
+       uint32_t length;  /**< Length of data to operate on */
+} odp_crypto_data_range_t;
+
+/**
+ * Crypto API session creation paramters
+ *
+ * @todo Add "odp_session_proc_info_t"
+ */
+typedef struct odp_crypto_session_params {
+       enum odp_crypto_op op;             /**< Encode versus decode */
+       bool auth_cipher_text;             /**< Authenticate/cipher ordering */
+       enum odp_crypto_op_mode pref_mode; /**< Preferred sync vs async */
+       enum odp_cipher_alg cipher_alg;    /**< Cipher algorithm */
+       odp_crypto_key_t cipher_key;       /**< Cipher key */
+       odp_crypto_iv_t  iv;               /**< Cipher Initialization Vector 
(IV) */
+       enum odp_auth_alg auth_alg;        /**< Authentication algorithm */
+       odp_crypto_key_t auth_key;         /**< Authentication key */
+       odp_queue_t compl_queue;           /**< Async mode completion event 
queue */
+       odp_buffer_pool_t output_pool;     /**< Output buffer pool */
+} odp_crypto_session_params_t;
+
+/**
+ * @var odp_crypto_session_params_t::auth_cipher_text
+ *
+ *   Controls ordering of authentication and cipher operations,
+ *   and is relative to the operation (encode vs decode).
+ *   When encoding, @c TRUE indicates the authentication operation
+ *   should be peformed @b after the cipher operation else before.
+ *   When decoding, @c TRUE indicates the reverse order of operation.
+ *
+ * @var odp_crypto_session_params_t::compl_queue
+ *
+ *   When the API operates asynchronously, the completion queue is
+ *   used to return the completion status of the operation to the
+ *   application.
+ *
+ * @var odp_crypto_session_params_t::output_pool
+ *
+ *   When the output packet is not specified during the call to
+ *   odp_crypto_operation, the output packet buffer will be allocated
+ *   from this pool.
+ */
+
+/**
+ * Crypto API per packet operation parameters
+ *
+ * @todo Clarify who zero's ICV and how this relates to "hash_result_offset"
+ */
+typedef struct odp_crypto_op_params {
+       odp_crypto_session_t session;   /**< Session handle from creation */
+       odp_packet_t pkt;               /**< Input packet buffer */
+       odp_packet_t out_pkt;           /**< Output packet buffer */
+       uint8_t *override_iv_ptr;       /**< Override session IV pointer */
+       uint32_t hash_result_offset;    /**< Offset from start of packet buffer 
for hash result */
+       odp_crypto_data_range_t cipher_range;   /**< Data range to apply cipher 
*/
+       odp_crypto_data_range_t auth_range;     /**< Data range to authenticate 
*/
+} odp_crypto_op_params_t;
+
+/**
+ * @var odp_crypto_op_params_t::pkt
+ *   Specifies the input packet buffer for the crypto operation.  When the
+ *   @c out_pkt variable is set to @c ODP_PACKET_INVALID (indicating a new
+ *   buffer should be allocated for the resulting packet), the #define TBD
+ *   indicates whether the implementation will free the input packet buffer
+ *   or if it becomes the responsibility of the caller.
+ *
+ * @var odp_crypto_op_params_t::out_pkt
+ *
+ *   The API supports both "in place" (the original packet "pkt" is
+ *   modified) and "copy" (the packet is replicated to a new buffer
+ *   which contains the modified data).
+ *
+ *   The "in place" mode of operation is indicated by setting @c out_pkt
+ *   equal to @c pkt.  For the copy mode of operation, setting @c out_pkt
+ *   to a valid packet buffer value indicates the caller wishes to specify
+ *   the destination buffer.  Setting @c out_pkt to @c ODP_PACKET_INVALID
+ *   indicates the caller wishes the destination packet buffer be allocated
+ *   from the output pool specified during session creation.
+ *
+ *   @sa odp_crypto_session_params_t::output_pool.
+ */
+
+/**
+ * Crypto API session creation return code
+ */
+enum odp_crypto_ses_create_err {
+       ODP_CRYPTO_SES_CREATE_ERR_NONE,       /**< Session created */
+       ODP_CRYPTO_SES_CREATE_ERR_ENOMEM,     /**< Creation failed, no 
resources */
+       ODP_CRYPTO_SES_CREATE_ERR_INV_CIPHER, /**< Creation failed, bad cipher 
params */
+       ODP_CRYPTO_SES_CREATE_ERR_INV_AUTH,   /**< Creation failed, bad auth 
params */
+};
+
+/**
+ * Crypto API algorithm return code
+ */
+enum crypto_alg_err {
+       ODP_CRYPTO_ALG_ERR_NONE,      /**< Algorithm successful */
+       ODP_CRYPTO_ALG_ERR_DATA_SIZE, /**< Invalid data block size */
+       ODP_CRYPTO_ALG_ERR_KEY_SIZE,  /**< Key size invalid for algorithm */
+       ODP_CRYPTO_ALG_ERR_ICV_CHECK, /**< Computed ICV value mismatch */
+};
+
+/**
+ * Crypto API hardware centric return code
+ */
+enum crypto_hw_err {
+       ODP_CRYPTO_HW_ERR_NONE,         /**< Operation completed successfully */
+       ODP_CRYPTO_HW_ERR_DMA,          /**< Error detected during DMA of data 
*/
+       ODP_CRYPTO_HW_ERR_BP_DEPLETED,  /**< Operation failed due to buffer 
pool depletion */
+};
+
+/**
+ * Cryto API per packet operation completion status
+ */
+typedef struct odp_crypto_compl_status {
+       enum crypto_alg_err alg_err;  /**< Algorithm specific return code */
+       enum crypto_hw_err  hw_err;   /**< Hardware specific return code */
+} odp_crypto_compl_status_t;
+
+
+/**
+ * Crypto session creation (synchronouse)
+ *
+ * @param params            Session parameters
+ * @param session           Created session else ODP_CRYPTO_SESSION_INVALID
+ * @param status            Failure code if unsuccessful
+ *
+ * @return 0 if successful else -1
+ */
+int
+odp_crypto_session_create(odp_crypto_session_params_t *params,
+                         odp_crypto_session_t *session,
+                         enum odp_crypto_ses_create_err *status);
+
+int odp_crypto_session_destroy(odp_crypto_session_t ses);
+
+/**
+ * Crypto session creation (asynchronous)
+ *
+ * Initiate crypto session creation.  Results are delivered using
+ * the completion event via the completion queue.
+ *
+ * @param params            Session parameters
+ * @param completion_event  Event by which the session creation results are
+ *                          delivered.
+ * @param completion_queue  Queue by which the completion event will be
+ *                          delivered.
+ *
+ * @return 0 if successful else -1
+ *
+ */
+int
+odp_crypto_session_create_async(odp_crypto_session_params_t *params,
+                               odp_buffer_t completion_event,
+                               odp_queue_t completion_queue);
+
+
+/**
+ * Crypto session creation completion status
+ *
+ * Accessor function for obtaining creation status from the completion event.
+ *
+ * @param completion_event  Event containing operation results
+ * @param status            Pointer to store creation return code
+ */
+void
+odp_crypto_get_ses_create_compl_status(odp_buffer_t completion_event,
+                                      enum odp_crypto_ses_create_err *status);
+
+/**
+ * Crypto session creation completion return value
+ *
+ * Accessor function for obtaining handle for newly created session.
+ *
+ * @param completion_event  Event containing operation results
+ * @param session           Pointer to store session handle
+ */
+void
+odp_crypto_get_ses_create_compl_session(odp_buffer_t completion_event,
+                                       odp_crypto_session_t *session);
+
+/**
+ * Crypto per packet operation
+ *
+ * Performs the cryptographic operations specified during session creation
+ * on the packet.  If the operation is performed synchronously, "posted"
+ * will return FALSE and the result of the operation is immediately available
+ * in the completion event.  If "posted" returns TRUE the result will be
+ * delivered via the completion queue specified when the session was created.
+ *
+ * @todo Resolve if completion_event is necessary, can/should the output
+ *       packet buffer always be used instead.
+ *
+ * @param params            Operation parameters
+ * @param posted            Pointer to return posted, TRUE for async operation
+ * @param completion_event  Event by which the operation results are delivered.
+ *
+ * @return 0 if successful else -1
+ */
+int
+odp_crypto_operation(odp_crypto_op_params_t *params,
+                    bool *posted,
+                    odp_buffer_t completion_event);
+
+/**
+ * Crypto per packet operation set user context in completion event
+ *
+ * @param completion_event  Event containing operation results
+ * @param ctx               User data
+ */
+void
+odp_crypto_set_operation_compl_ctx(odp_buffer_t completion_event,
+                                  void *ctx);
+
+/**
+ * Crypto per packet operation completion status
+ *
+ * Accessor function for obtaining operation status from the completion event.
+ *
+ * @param completion_event  Event containing operation results
+ * @param auth              Pointer to store authentication results
+ * @param cipher            Pointer to store cipher results
+ */
+void
+odp_crypto_get_operation_compl_status(odp_buffer_t completion_event,
+                                     odp_crypto_compl_status_t *auth,
+                                     odp_crypto_compl_status_t *cipher);
+
+/**
+ * Crypto per packet operation query completed operation packet
+ *
+ * Accessor function for obtaining current packet buffer, can be
+ * different from input packet buffer on some systems
+ *
+ * @param completion_event  Event containing operation results
+ *
+ * @return Packet structure where data now resides
+ */
+odp_packet_t
+odp_crypto_get_operation_compl_packet(odp_buffer_t completion_event);
+
+/**
+ * Crypto per packet operation query user context in completion event
+ *
+ * @param completion_event  Event containing operation results
+ *
+ * @return User data
+ */
+void *
+odp_crypto_get_operation_compl_ctx(odp_buffer_t completion_event);
+
+/**
+ * Generate random byte string
+ *
+ * @param buf          Pointer to store result
+ * @param len          Pointer to input length value as well as return value
+ * @param use_entropy  Use entropy
+ *
+ * @todo Define the implication of the use_entropy parameter
+ *
+ * @return 0 if succesful
+ */
+int
+odp_hw_random_get(uint8_t *buf, size_t *len, bool use_entropy);
+
+/**
+ * Initialize the crypto subsystem, called once from main thread
+ *
+ * @param max_sessions  Maximum number of sessions to support
+ *
+ * @return 0 if succesful
+ */
+int
+odp_crypto_init(uint32_t max_sessions);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/platform/linux-keystone2/include/odp_crypto_internal.h 
b/platform/linux-keystone2/include/odp_crypto_internal.h
new file mode 100644
index 0000000..17756fd
--- /dev/null
+++ b/platform/linux-keystone2/include/odp_crypto_internal.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2014, Linaro Limited
+ * Copyright (c) 2014, Texas Instruments Incorporated
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ */
+
+#ifndef ODP_CRYPTO_INTERNAL_H_
+#define ODP_CRYPTO_INTERNAL_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <ti/drv/nwal/nwal.h>
+#include <ti/drv/nwal/nwal_util.h>
+
+#define OP_RESULT_MAGIC 0x91919191
+
+/** Forward declaration of session structure */
+struct odp_crypto_session_s;
+
+/**
+ * Algorithm handler function prototype
+ */
+typedef
+enum crypto_alg_err (*crypto_func_t)(struct odp_crypto_op_params *params,
+                                    struct odp_crypto_session_s *session);
+
+#define ODP_CRYPTO_MAX_IV_LENGTH 32
+
+struct iv_full {
+       uint8_t data[ODP_CRYPTO_MAX_IV_LENGTH];
+       size_t  length;
+};
+
+
+/**
+ * Per crypto session data structure
+ */
+struct odp_crypto_session_s {
+       nwal_Handle         dm_handle;
+       nwalTxDmPSCmdInfo_t dm_ps_cmdinfo;
+       odp_buffer_pool_t   out_pool;
+       uint32_t            out_flow_id;
+       odp_queue_t         compl_queue;
+       struct {
+               enum odp_cipher_alg alg;
+               struct iv_full      iv;
+       } cipher;
+
+       struct {
+               enum odp_auth_alg   alg;
+               struct iv_full      iv;
+               uint32_t            tag_len;
+       } auth;
+
+       uint32_t            index;
+       enum odp_crypto_op  op;
+};
+
+/**
+ * Per packet operation result
+ */
+struct odp_operation_result_s {
+       uint32_t magic;
+       struct odp_crypto_compl_status cipher;
+       struct odp_crypto_compl_status auth;
+};
+
+/**
+ * Per session creation operation result
+ */
+struct odp_session_result_s {
+       enum odp_crypto_ses_create_err rc;
+       odp_crypto_session_t           session;
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/platform/linux-keystone2/include/odp_internal.h 
b/platform/linux-keystone2/include/odp_internal.h
index d043770..bccd14a 100644
--- a/platform/linux-keystone2/include/odp_internal.h
+++ b/platform/linux-keystone2/include/odp_internal.h
@@ -34,6 +34,8 @@ int odp_pktio_init_global(void);
 
 int odp_queue_init_global(void);
 
+int odp_crypto_init_global(void);
+
 int odp_schedule_init_global(void);
 int odp_schedule_init_local(void);
 
diff --git a/platform/linux-keystone2/odp_crypto.c 
b/platform/linux-keystone2/odp_crypto.c
new file mode 100644
index 0000000..33a2813
--- /dev/null
+++ b/platform/linux-keystone2/odp_crypto.c
@@ -0,0 +1,490 @@
+/*
+ * Copyright (c) 2014, Linaro Limited
+ * Copyright (c) 2014, Texas Instruments Incorporated
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ */
+
+#include <odp_crypto.h>
+#include <odp_internal.h>
+#include <odp_atomic.h>
+#include <odp_spinlock.h>
+#include <odp_sync.h>
+#include <odp_debug.h>
+#include <odp_align.h>
+#include <odp_hints.h>
+#include <odp_shared_memory.h>
+#include <odp_crypto_internal.h>
+#include <odp_packet_internal.h>
+#include <odp_queue_internal.h>
+#include <odp_byteorder.h>
+
+#include <string.h>
+#include <odp_ti_mcsdk.h>
+
+#define MAX_SESSIONS 32
+
+typedef struct {
+       odp_atomic_u32_t next;
+       uint32_t         max;
+       struct odp_crypto_session_s sessions[0];
+} odp_crypto_global_t;
+
+static odp_crypto_global_t *global;
+
+static struct odp_crypto_session_s *alloc_session(void)
+{
+       uint32_t idx;
+       struct odp_crypto_session_s *session = NULL;
+
+       idx = odp_atomic_fetch_inc_u32(&global->next);
+       if (idx < global->max) {
+               session = &global->sessions[idx];
+               session->index = idx;
+       }
+       return session;
+}
+
+static void _print_nwalCreateDmSAParams(nwalCreateDmSAParams_t *dmSaParam)
+{
+       odp_pr_dbg("dmSaParam.dmChnType = %u\n",
+                  dmSaParam->dmSaParam.dmChnType);
+       odp_pr_dbg("dmSaParam.authMode = %u\n", dmSaParam->dmSaParam.authMode);
+       odp_pr_dbg("dmSaParam.cipherMode = %u\n",
+                  dmSaParam->dmSaParam.cipherMode);
+       odp_pr_dbg("dmSaParam.enc1st = %u\n", dmSaParam->dmSaParam.enc1st);
+       odp_pr_dbg("dmSaParam.macSize = %u\n", dmSaParam->dmSaParam.macSize);
+       odp_pr_dbg("dmSaParam.aadSize = %u\n", dmSaParam->dmSaParam.aadSize);
+       odp_pr_dbg("dmSaParam.replayWindow = %u\n",
+                  dmSaParam->dmSaParam.replayWindow);
+
+       if (dmSaParam->dmSaParam.cipherMode != NWAL_SA_EALG_NULL)
+               odp_pr_dbg_mem(dmSaParam->keyParam.pEncKey,
+                              dmSaParam->keyParam.encKeySize,
+                              "keyParam.pEncKey");
+       if (dmSaParam->dmSaParam.authMode != NWAL_SA_AALG_NULL)
+               odp_pr_dbg_mem(dmSaParam->keyParam.pAuthKey,
+                              dmSaParam->keyParam.macKeySize,
+                              "keyParam.pAuthKey");
+}
+
+int odp_crypto_session_create(odp_crypto_session_params_t *params,
+                             odp_crypto_session_t *session_out,
+                             enum odp_crypto_ses_create_err *status)
+{
+       nwal_RetValue nwal_ret;
+       nwalCreateDmSAParams_t sa_params;
+       nwalMbufPool_t rx_pool;
+       Cppi_FlowHnd out_flow;
+       struct odp_crypto_session_s *session;
+
+       ODP_ASSERT((params->cipher_alg != ODP_CIPHER_ALG_NULL ||
+                   params->auth_alg != ODP_AUTH_ALG_NULL),
+                  "Both algorithms are NULL");
+
+       if (params->cipher_alg == ODP_CIPHER_ALG_NULL) {
+               params->cipher_key.data   = NULL;
+               params->cipher_key.length = 0;
+       }
+
+       if (params->auth_alg == ODP_AUTH_ALG_NULL &&
+           params->cipher_alg != ODP_CIPHER_ALG_AES_GCM &&
+           params->cipher_alg != ODP_CIPHER_ALG_AES_CCM) {
+               params->auth_key.data   = NULL;
+               params->auth_key.length = 0;
+       }
+
+       /* Default to failure result */
+       *status  = ODP_CRYPTO_SES_CREATE_ERR_NONE;
+       *session_out = ODP_CRYPTO_SESSION_INVALID;
+
+
+       /* Allocate memory for this session */
+       session = alloc_session();
+       if (!session) {
+               *status = ODP_CRYPTO_SES_CREATE_ERR_ENOMEM;
+               return -1;
+       }
+
+       /* Copy stuff over */
+       session->op = params->op;
+       session->cipher.alg = params->cipher_alg;
+       session->auth.alg = params->auth_alg;
+       if (sizeof(session->cipher.iv.data) < params->iv.length) {
+               *status = ODP_CRYPTO_SES_CREATE_ERR_INV_CIPHER;
+               return -1;
+       }
+       memcpy(session->cipher.iv.data, params->iv.data, params->iv.length);
+       /** @todo: need separate IV for Auth */
+       memcpy(session->auth.iv.data, params->iv.data, params->iv.length);
+
+       session->compl_queue = params->compl_queue;
+       session->out_pool = params->output_pool;
+
+       rx_pool.numBufPools = 1;
+       rx_pool.bufPool[0].heapHandle = session->out_pool;
+       rx_pool.bufPool[0].bufSize =
+                       Pktlib_getMaxBufferSize(session->out_pool);
+       rx_pool.bufPool[0].descSize = TUNE_NETAPI_DESC_SIZE;
+
+       nwal_ret = nwal_SetupFlow(odp_global->nwal.handle,
+                       &rx_pool,
+                       0, /* buffer header travels via SA, so no offset */
+                       odp_local.nwal.cfg.rxPktTailRoomSz,
+                       &out_flow,
+                       nwal_FALSE);
+
+       if (nwal_ret != nwal_OK) {
+               *status = ODP_CRYPTO_SES_CREATE_ERR_ENOMEM;
+               return -1;
+       }
+
+       session->out_flow_id = Cppi_getFlowId(out_flow);
+
+       memset(&sa_params, 0, sizeof(nwalCreateDmSAParams_t));
+       sa_params.dmSaParam.dmChnType =
+                       (params->op == ODP_CRYPTO_OP_DECODE) ?
+                                       NWAL_DM_CHAN_DECRYPT :
+                                       NWAL_DM_CHAN_ENCRYPT;
+       sa_params.dmSaParam.replayWindow = 64; /** @todo: always 64? */
+       sa_params.dmSaParam.authMode = params->auth_alg;
+       sa_params.dmSaParam.cipherMode = params->cipher_alg;
+
+       sa_params.dmSaParam.enc1st = (params->op == ODP_CRYPTO_OP_ENCODE) ?
+                       params->auth_cipher_text : !params->auth_cipher_text;
+
+       if ((sa_params.dmSaParam.cipherMode == NWAL_SA_EALG_AES_GCM) ||
+           (sa_params.dmSaParam.cipherMode     == NWAL_SA_EALG_AES_CCM) ||
+           (sa_params.dmSaParam.authMode == NWAL_SA_AALG_GMAC)) {
+               sa_params.dmSaParam.macSize = 16;
+               sa_params.dmSaParam.aadSize = 8;
+               /* Enc1st needs to always be true for combined algorithms */
+               sa_params.dmSaParam.enc1st = nwal_TRUE;
+       } else if (sa_params.dmSaParam.authMode != NWAL_SA_AALG_NULL) {
+               sa_params.dmSaParam.macSize = 12;
+               sa_params.dmSaParam.aadSize = 0;
+       } else {
+               sa_params.dmSaParam.enc1st = nwal_TRUE;
+               sa_params.dmSaParam.macSize = 0;
+       }
+
+       sa_params.keyParam.pEncKey = params->cipher_key.data;
+       sa_params.keyParam.encKeySize = params->cipher_key.length;
+       sa_params.keyParam.pAuthKey = params->auth_key.data;
+       sa_params.keyParam.macKeySize = params->auth_key.length;
+
+       session->auth.tag_len = sa_params.dmSaParam.macSize;
+
+       ODP_ASSERT(session->auth.tag_len <=
+                  ODP_FIELD_SIZEOF(struct odp_pkthdr, crypto.dec.hash_tag),
+                  "Auth tag length is bigger than hash_tag array");
+
+       _print_nwalCreateDmSAParams(&sa_params);
+       odp_pr_dbg("Session addr: %p\n", session);
+       nwal_ret = nwal_setDMSecAssoc(odp_global->nwal.handle,
+                                       (nwal_AppId) session,
+                                       &sa_params,
+                                       &session->dm_handle);
+       if (nwal_ret != nwal_OK) {
+               odp_pr_err("nwal_setDMSecAssoc() returned Error Code %d\n",
+                          nwal_ret);
+               *status = ODP_CRYPTO_SES_CREATE_ERR_ENOMEM;
+               return -1;
+       }
+
+       nwal_ret = nwal_initDMPSCmdInfo(odp_global->nwal.handle,
+                       session->dm_handle,
+                       &session->dm_ps_cmdinfo);
+
+       *status = ODP_CRYPTO_SES_CREATE_ERR_NONE;
+       *session_out = session;
+
+       return 0;
+}
+
+int odp_crypto_session_destroy(odp_crypto_session_t ses)
+{
+       struct odp_crypto_session_s *session = ses;
+       nwal_RetValue nwal_ret;
+       nwal_ret = nwal_delDMSecAssoc(odp_global->nwal.handle,
+                                     session->dm_handle);
+       return (nwal_ret == nwal_OK) ? 0 : 1;
+}
+
+#define ODP_CRYPTO_BUFFER_PROCESSED_OFFSET (-1)
+
+static inline void hash_copy_be32(uint8_t *dest, const uint32be_t *sa, size_t 
n)
+{
+       union hash_u {
+               uint32_t hash32;
+               uint8_t hash[4];
+       } hash;
+
+       n /= 4;
+       while (n--) {
+               unsigned int i;
+               hash.hash32 = odp_be_to_cpu_32(*sa++);
+               for (i = 0; i < sizeof(hash.hash); i++)
+                       *dest++ = hash.hash[i];
+       };
+}
+
+static inline int hash_compare_be32(const uint32_t *orig, const uint32be_t *sa,
+                                   size_t n)
+{
+       n /= 4;
+       while (n--) {
+               if (*orig++ != odp_be_to_cpu_32(*sa++))
+                       return 1;
+       };
+       return 0;
+}
+
+/**
+ *  Set bufPtr to origBuffPtr to pass buffer header via SA
+ *
+ *  @return offset value
+ */
+static inline int16_t odp_crypto_buffer_preprocess(odp_buffer_t buf)
+{
+       struct odp_pkthdr *hdr;
+       int16_t offset;
+       Cppi_HostDesc *desc;
+       uint32_t packet_length;
+
+       desc = _odp_buf_to_cppi_desc(buf);
+       hdr = odp_packet_hdr(odp_packet_from_buffer(buf));
+       offset = desc->buffPtr - desc->origBuffPtr;
+       hdr->crypto.saved_buf_offset = offset;
+       odp_pr_dbg("buffPtr: 0x%08x, buffLen: 0x%x, offset: %x\n",
+                  desc->buffPtr, desc->buffLen, offset);
+       desc->buffPtr -= offset;
+       desc->buffLen += offset;
+       packet_length = odp_packet_get_len(odp_packet_from_buffer(buf));
+       odp_packet_set_len(odp_packet_from_buffer(buf),
+                          packet_length + offset);
+       odp_pr_vdbg_packet(odp_packet_from_buffer(buf));
+       return offset;
+}
+
+/**
+ *  Restore bufPtr after SA operation
+ *
+ *  @return offset value
+ */
+static inline void odp_crypto_buffer_postprocess(odp_buffer_t buf,
+                                                enum crypto_alg_err *alg_err)
+{
+       Cppi_HostDesc *desc;
+       int16_t offset;
+       uint8_t *auth_tag = NULL;
+       uint32_t auth_tag_len = 0;
+       struct odp_pkthdr *hdr;
+       struct odp_crypto_session_s *session;
+       Ti_Pkt *pkt;
+       uint32_t packet_length;
+       nwal_Bool_t result;
+       enum crypto_alg_err auth_err = ODP_CRYPTO_ALG_ERR_NONE;
+
+       odp_pr_vdbg_packet(odp_packet_from_buffer(buf));
+       hdr  = odp_packet_hdr(odp_packet_from_buffer(buf));
+       offset = hdr->crypto.saved_buf_offset;
+       if (offset == ODP_CRYPTO_BUFFER_PROCESSED_OFFSET) {
+               /* Buffer already post-processed */
+               return;
+       }
+       ODP_ASSERT(offset >= 0, "Wrong saved buffer offset\n");
+
+       hdr->crypto.saved_buf_offset = ODP_CRYPTO_BUFFER_PROCESSED_OFFSET;
+       pkt  = _odp_buf_to_ti_pkt(buf);
+       desc = _odp_buf_to_cppi_desc(buf);
+
+       odp_pr_dbg("buffPtr: 0x%08x, buffLen: 0x%x, offset: %x\n",
+                  desc->buffPtr, desc->buffLen, offset);
+       desc->buffPtr += offset;
+       desc->buffLen -= offset;
+       packet_length = odp_packet_get_len(odp_packet_from_buffer(buf));
+       odp_packet_set_len(odp_packet_from_buffer(buf),
+                          packet_length - offset);
+
+       result = nwal_mGetAppidFmPkt(pkt, (nwal_AppId *)&session);
+       ODP_ASSERT(result == nwal_TRUE, "Can't get crypto session context\n");
+       odp_pr_dbg("Session addr: %p\n", session);
+
+       nwal_mmGetDmAuthTag(pkt, &auth_tag, &auth_tag_len);
+
+       ODP_ASSERT(session->auth.tag_len <= auth_tag_len,
+                  "Auth tag length from SA is bigger than ICV length");
+       ODP_ASSERT(!((uintptr_t)auth_tag & 0x3),
+                  "Auth tag is not 4 bytes aligned");
+
+       if (session->op == ODP_CRYPTO_OP_ENCODE) {
+               /* Copy hash to packet */
+               uint8_t *data = odp_buffer_addr(buf);
+               data += hdr->crypto.hash_offset;
+               hash_copy_be32(data, (uint32be_t *)(void *)auth_tag,
+                              session->auth.tag_len);
+       } else if (hash_compare_be32(hdr->crypto.dec.hash_tag,
+                                    (uint32be_t *)(void *)auth_tag,
+                                    session->auth.tag_len)) {
+               odp_pr_dbg("ICV is wrong\n");
+               odp_pr_dbg_mem(hdr->crypto.dec.hash_tag, session->auth.tag_len,
+                              "Saved auth tag");
+               odp_pr_dbg_mem(auth_tag, session->auth.tag_len,
+                              "Decoded auth tag");
+               auth_err = ODP_CRYPTO_ALG_ERR_ICV_CHECK;
+       }
+
+       if (alg_err)
+               *alg_err = auth_err;
+       return;
+}
+
+int odp_crypto_operation(odp_crypto_op_params_t *params,
+                        bool *posted,
+                        odp_buffer_t completion_event ODP_UNUSED)
+{
+       nwalTxDmPSCmdInfo_t *dm_cmd_info;
+       Cppi_HostDesc       *desc;
+       struct odp_crypto_session_s *session;
+       odp_buffer_t buf = odp_buffer_from_packet(params->pkt);
+       struct odp_pkthdr *hdr = odp_packet_hdr(params->pkt);
+       uint32_t offset;
+       uint8_t *data;
+
+       session = (struct odp_crypto_session_s *)(intptr_t)params->session;
+
+       /* Out packet is allocated from out poll and can't be specified */
+       if (params->out_pkt != ODP_PACKET_INVALID)
+               return -1;
+
+       dm_cmd_info = &session->dm_ps_cmdinfo;
+       dm_cmd_info->rxSbSaQ = _odp_queue_to_qmss_queue(session->compl_queue);
+       dm_cmd_info->rxPktFlowId = session->out_flow_id;
+
+       /* Save hash tag for decode operation and fill hash result with 0's*/
+       data  = odp_packet_buf_addr(params->pkt);
+       data += params->hash_result_offset;
+       hdr->crypto.hash_offset = params->hash_result_offset;
+       if (session->op == ODP_CRYPTO_OP_DECODE)
+               memcpy(hdr->crypto.dec.hash_tag, data, session->auth.tag_len);
+       memset(data, 0, session->auth.tag_len);
+
+       offset = odp_crypto_buffer_preprocess(buf);
+
+       nwal_mCmdDMUpdate(_odp_buf_to_ti_pkt(buf),
+                         dm_cmd_info,
+                         nwal_HANDLE_INVALID,
+                         params->cipher_range.offset + offset,
+                         params->cipher_range.length,
+                         (params->override_iv_ptr) ?
+                                       params->override_iv_ptr :
+                                       session->cipher.iv.data,
+                         params->auth_range.offset + offset,
+                         params->auth_range.length,
+                         NULL,
+                         0, /** @todo: Should be aadSize from session? */
+                         NULL);
+
+       desc = _odp_buf_to_cppi_desc(buf);
+       desc = Osal_qmssConvertDescVirtToPhy(0, desc);
+
+       Qmss_queuePushDescSizeRaw(dm_cmd_info->txQueue,
+                                 desc,
+                                 NWAL_DESC_SIZE);
+
+       *posted = 1;
+       return 0;
+}
+
+
+int odp_crypto_init_global(void)
+{
+       size_t mem_size;
+
+       /* Calculate the memory size we need */
+       mem_size  = sizeof(*global);
+       mem_size += (MAX_SESSIONS * sizeof(struct odp_crypto_session_s));
+
+       /* Allocate our globally shared memory */
+       global = odp_shm_reserve("crypto_pool", mem_size, ODP_CACHE_LINE_SIZE);
+
+       /* Clear it out */
+       memset(global, 0, mem_size);
+
+       /* Initialize it */
+       global->max = MAX_SESSIONS;
+
+       return 0;
+}
+
+int odp_hw_random_get(uint8_t *buf, uint32_t *len, bool use_entropy ODP_UNUSED)
+{
+       Sa_RngData_t random;
+       uint8_t *random_buf;
+       uint32_t length = *len;
+       uint32_t i;
+       nwal_RetValue ret;
+
+       ret = nwal_getSARandomNum(odp_global->nwal.handle, &random);
+       if (ret != nwal_OK) {
+               *len = 0;
+               return -1;
+       }
+       random_buf = (uint8_t *)&random;
+       if (length > sizeof(Sa_RngData_t))
+               length = sizeof(Sa_RngData_t);
+
+       for (i = 0; i < length; i++)
+               *buf++ = *random_buf++;
+       *len = length;
+
+       return 0;
+}
+void
+odp_crypto_get_operation_compl_status(odp_buffer_t completion_event,
+                                     struct odp_crypto_compl_status *auth,
+                                     struct odp_crypto_compl_status *cipher)
+{
+       auth->hw_err = ODP_CRYPTO_HW_ERR_NONE;
+       auth->alg_err = ODP_CRYPTO_ALG_ERR_NONE;
+       cipher->hw_err = ODP_CRYPTO_HW_ERR_NONE;
+       cipher->alg_err = ODP_CRYPTO_ALG_ERR_NONE;
+
+       odp_crypto_buffer_postprocess(completion_event, &auth->alg_err);
+
+       return;
+}
+
+odp_packet_t
+odp_crypto_get_operation_compl_packet(odp_buffer_t completion_event)
+{
+       odp_crypto_buffer_postprocess(completion_event, NULL);
+       return odp_packet_from_buffer(completion_event);
+}
+
+
+void *odp_crypto_get_operation_compl_ctx(odp_buffer_t completion ODP_UNUSED)
+{
+       /* Not supported */
+       return NULL;
+}
+
+void odp_crypto_get_ses_create_compl_status(odp_buffer_t completion_event,
+                                      enum odp_crypto_ses_create_err *status)
+{
+       struct odp_session_result_s *result;
+
+       result = odp_buffer_addr(completion_event);
+       *status = result->rc;
+}
+
+void odp_crypto_get_ses_create_compl_session(odp_buffer_t completion_event,
+                                       odp_crypto_session_t *session)
+{
+       struct odp_session_result_s *result;
+
+       result = odp_buffer_addr(completion_event);
+       *session = result->session;
+}
diff --git a/platform/linux-keystone2/odp_init.c 
b/platform/linux-keystone2/odp_init.c
index 3161f75..12c9ff2 100644
--- a/platform/linux-keystone2/odp_init.c
+++ b/platform/linux-keystone2/odp_init.c
@@ -66,6 +66,11 @@ int odp_init_global(void)
                return -1;
        }
 
+       if (odp_crypto_init_global()) {
+               odp_pr_err("ODP crypto init failed.\n");
+               return -1;
+       }
+
        if (odp_timer_init_global()) {
                odp_pr_err("ODP timer init failed.\n");
                return -1;
-- 
1.7.9.5


_______________________________________________
lng-odp mailing list
[email protected]
http://lists.linaro.org/mailman/listinfo/lng-odp

Reply via email to