in bcm/spu.c [586:819]
u32 spum_create_request(u8 *spu_hdr,
struct spu_request_opts *req_opts,
struct spu_cipher_parms *cipher_parms,
struct spu_hash_parms *hash_parms,
struct spu_aead_parms *aead_parms,
unsigned int data_size)
{
struct SPUHEADER *spuh;
struct BDESC_HEADER *bdesc;
struct BD_HEADER *bd;
u8 *ptr;
u32 protocol_bits = 0;
u32 cipher_bits = 0;
u32 ecf_bits = 0;
u8 sctx_words = 0;
unsigned int buf_len = 0;
/* size of the cipher payload */
unsigned int cipher_len = hash_parms->prebuf_len + data_size +
hash_parms->pad_len;
/* offset of prebuf or data from end of BD header */
unsigned int cipher_offset = aead_parms->assoc_size +
aead_parms->iv_len + aead_parms->aad_pad_len;
/* total size of the DB data (without STAT word padding) */
unsigned int real_db_size = spu_real_db_size(aead_parms->assoc_size,
aead_parms->iv_len,
hash_parms->prebuf_len,
data_size,
aead_parms->aad_pad_len,
aead_parms->data_pad_len,
hash_parms->pad_len);
unsigned int auth_offset = 0;
unsigned int offset_iv = 0;
/* size/offset of the auth payload */
unsigned int auth_len;
auth_len = real_db_size;
if (req_opts->is_aead && req_opts->is_inbound)
cipher_len -= hash_parms->digestsize;
if (req_opts->is_aead && req_opts->is_inbound)
auth_len -= hash_parms->digestsize;
if ((hash_parms->alg == HASH_ALG_AES) &&
(hash_parms->mode == HASH_MODE_XCBC)) {
auth_len -= hash_parms->pad_len;
cipher_len -= hash_parms->pad_len;
}
flow_log("%s()\n", __func__);
flow_log(" in:%u authFirst:%u\n",
req_opts->is_inbound, req_opts->auth_first);
flow_log(" %s. cipher alg:%u mode:%u type %u\n",
spu_alg_name(cipher_parms->alg, cipher_parms->mode),
cipher_parms->alg, cipher_parms->mode, cipher_parms->type);
flow_log(" key: %d\n", cipher_parms->key_len);
flow_dump(" key: ", cipher_parms->key_buf, cipher_parms->key_len);
flow_log(" iv: %d\n", cipher_parms->iv_len);
flow_dump(" iv: ", cipher_parms->iv_buf, cipher_parms->iv_len);
flow_log(" auth alg:%u mode:%u type %u\n",
hash_parms->alg, hash_parms->mode, hash_parms->type);
flow_log(" digestsize: %u\n", hash_parms->digestsize);
flow_log(" authkey: %d\n", hash_parms->key_len);
flow_dump(" authkey: ", hash_parms->key_buf, hash_parms->key_len);
flow_log(" assoc_size:%u\n", aead_parms->assoc_size);
flow_log(" prebuf_len:%u\n", hash_parms->prebuf_len);
flow_log(" data_size:%u\n", data_size);
flow_log(" hash_pad_len:%u\n", hash_parms->pad_len);
flow_log(" real_db_size:%u\n", real_db_size);
flow_log(" auth_offset:%u auth_len:%u cipher_offset:%u cipher_len:%u\n",
auth_offset, auth_len, cipher_offset, cipher_len);
flow_log(" aead_iv: %u\n", aead_parms->iv_len);
/* starting out: zero the header (plus some) */
ptr = spu_hdr;
memset(ptr, 0, sizeof(struct SPUHEADER));
/* format master header word */
/* Do not set the next bit even though the datasheet says to */
spuh = (struct SPUHEADER *)ptr;
ptr += sizeof(struct SPUHEADER);
buf_len += sizeof(struct SPUHEADER);
spuh->mh.op_code = SPU_CRYPTO_OPERATION_GENERIC;
spuh->mh.flags |= (MH_SCTX_PRES | MH_BDESC_PRES | MH_BD_PRES);
/* Format sctx word 0 (protocol_bits) */
sctx_words = 3; /* size in words */
/* Format sctx word 1 (cipher_bits) */
if (req_opts->is_inbound)
cipher_bits |= CIPHER_INBOUND;
if (req_opts->auth_first)
cipher_bits |= CIPHER_ORDER;
/* Set the crypto parameters in the cipher.flags */
cipher_bits |= cipher_parms->alg << CIPHER_ALG_SHIFT;
cipher_bits |= cipher_parms->mode << CIPHER_MODE_SHIFT;
cipher_bits |= cipher_parms->type << CIPHER_TYPE_SHIFT;
/* Set the auth parameters in the cipher.flags */
cipher_bits |= hash_parms->alg << HASH_ALG_SHIFT;
cipher_bits |= hash_parms->mode << HASH_MODE_SHIFT;
cipher_bits |= hash_parms->type << HASH_TYPE_SHIFT;
/*
* Format sctx extensions if required, and update main fields if
* required)
*/
if (hash_parms->alg) {
/* Write the authentication key material if present */
if (hash_parms->key_len) {
memcpy(ptr, hash_parms->key_buf, hash_parms->key_len);
ptr += hash_parms->key_len;
buf_len += hash_parms->key_len;
sctx_words += hash_parms->key_len / 4;
}
if ((cipher_parms->mode == CIPHER_MODE_GCM) ||
(cipher_parms->mode == CIPHER_MODE_CCM))
/* unpadded length */
offset_iv = aead_parms->assoc_size;
/* if GCM/CCM we need to write ICV into the payload */
if (!req_opts->is_inbound) {
if ((cipher_parms->mode == CIPHER_MODE_GCM) ||
(cipher_parms->mode == CIPHER_MODE_CCM))
ecf_bits |= 1 << INSERT_ICV_SHIFT;
} else {
ecf_bits |= CHECK_ICV;
}
/* Inform the SPU of the ICV size (in words) */
if (hash_parms->digestsize == 64)
cipher_bits |= ICV_IS_512;
else
ecf_bits |=
(hash_parms->digestsize / 4) << ICV_SIZE_SHIFT;
}
if (req_opts->bd_suppress)
ecf_bits |= BD_SUPPRESS;
/* copy the encryption keys in the SAD entry */
if (cipher_parms->alg) {
if (cipher_parms->key_len) {
memcpy(ptr, cipher_parms->key_buf,
cipher_parms->key_len);
ptr += cipher_parms->key_len;
buf_len += cipher_parms->key_len;
sctx_words += cipher_parms->key_len / 4;
}
/*
* if encrypting then set IV size, use SCTX IV unless no IV
* given here
*/
if (cipher_parms->iv_buf && cipher_parms->iv_len) {
/* Use SCTX IV */
ecf_bits |= SCTX_IV;
/* cipher iv provided so put it in here */
memcpy(ptr, cipher_parms->iv_buf, cipher_parms->iv_len);
ptr += cipher_parms->iv_len;
buf_len += cipher_parms->iv_len;
sctx_words += cipher_parms->iv_len / 4;
}
}
/*
* RFC4543 (GMAC/ESP) requires data to be sent as part of AAD
* so we need to override the BDESC parameters.
*/
if (req_opts->is_rfc4543) {
if (req_opts->is_inbound)
data_size -= hash_parms->digestsize;
offset_iv = aead_parms->assoc_size + data_size;
cipher_len = 0;
cipher_offset = offset_iv;
auth_len = cipher_offset + aead_parms->data_pad_len;
}
/* write in the total sctx length now that we know it */
protocol_bits |= sctx_words;
/* Endian adjust the SCTX */
spuh->sa.proto_flags = cpu_to_be32(protocol_bits);
spuh->sa.cipher_flags = cpu_to_be32(cipher_bits);
spuh->sa.ecf = cpu_to_be32(ecf_bits);
/* === create the BDESC section === */
bdesc = (struct BDESC_HEADER *)ptr;
bdesc->offset_mac = cpu_to_be16(auth_offset);
bdesc->length_mac = cpu_to_be16(auth_len);
bdesc->offset_crypto = cpu_to_be16(cipher_offset);
bdesc->length_crypto = cpu_to_be16(cipher_len);
/*
* CCM in SPU-M requires that ICV not be in same 32-bit word as data or
* padding. So account for padding as necessary.
*/
if (cipher_parms->mode == CIPHER_MODE_CCM)
auth_len += spum_wordalign_padlen(auth_len);
bdesc->offset_icv = cpu_to_be16(auth_len);
bdesc->offset_iv = cpu_to_be16(offset_iv);
ptr += sizeof(struct BDESC_HEADER);
buf_len += sizeof(struct BDESC_HEADER);
/* === no MFM section === */
/* === create the BD section === */
/* add the BD header */
bd = (struct BD_HEADER *)ptr;
bd->size = cpu_to_be16(real_db_size);
bd->prev_length = 0;
ptr += sizeof(struct BD_HEADER);
buf_len += sizeof(struct BD_HEADER);
packet_dump(" SPU request header: ", spu_hdr, buf_len);
return buf_len;
}