in bcm/spu2.c [944:1110]
u32 spu2_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 SPU2_FMD *fmd;
u8 *ptr;
unsigned int buf_len;
int err;
enum spu2_cipher_type spu2_ciph_type = SPU2_CIPHER_TYPE_NONE;
enum spu2_cipher_mode spu2_ciph_mode;
enum spu2_hash_type spu2_auth_type = SPU2_HASH_TYPE_NONE;
enum spu2_hash_mode spu2_auth_mode;
bool return_md = true;
enum spu2_proto_sel proto = SPU2_PROTO_RESV;
/* size of the payload */
unsigned int payload_len =
hash_parms->prebuf_len + data_size + hash_parms->pad_len -
((req_opts->is_aead && req_opts->is_inbound) ?
hash_parms->digestsize : 0);
/* offset of prebuf or data from start of AAD2 */
unsigned int cipher_offset = aead_parms->assoc_size +
aead_parms->aad_pad_len + aead_parms->iv_len;
/* total size of the data following OMD (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 assoc_size = aead_parms->assoc_size;
if (req_opts->is_aead &&
(cipher_parms->alg == CIPHER_ALG_AES) &&
(cipher_parms->mode == CIPHER_MODE_GCM))
/*
* On SPU 2, aes gcm cipher first on encrypt, auth first on
* decrypt
*/
req_opts->auth_first = req_opts->is_inbound;
/* and do opposite for ccm (auth 1st on encrypt) */
if (req_opts->is_aead &&
(cipher_parms->alg == CIPHER_ALG_AES) &&
(cipher_parms->mode == CIPHER_MODE_CCM))
req_opts->auth_first = !req_opts->is_inbound;
flow_log("%s()\n", __func__);
flow_log(" in:%u authFirst:%u\n",
req_opts->is_inbound, req_opts->auth_first);
flow_log(" cipher alg:%u mode:%u type %u\n", cipher_parms->alg,
cipher_parms->mode, cipher_parms->type);
flow_log(" is_esp: %s\n", req_opts->is_esp ? "yes" : "no");
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", 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(" cipher_offset:%u payload_len:%u\n",
cipher_offset, payload_len);
flow_log(" aead_iv: %u\n", aead_parms->iv_len);
/* Convert to spu2 values for cipher alg, hash alg */
err = spu2_cipher_xlate(cipher_parms->alg, cipher_parms->mode,
cipher_parms->type,
&spu2_ciph_type, &spu2_ciph_mode);
/* If we are doing GCM hashing only - either via rfc4543 transform
* or because we happen to do GCM with AAD only and no payload - we
* need to configure hardware to use hash key rather than cipher key
* and put data into payload. This is because unlike SPU-M, running
* GCM cipher with 0 size payload is not permitted.
*/
if ((req_opts->is_rfc4543) ||
((spu2_ciph_mode == SPU2_CIPHER_MODE_GCM) &&
(payload_len == 0))) {
/* Use hashing (only) and set up hash key */
spu2_ciph_type = SPU2_CIPHER_TYPE_NONE;
hash_parms->key_len = cipher_parms->key_len;
memcpy(hash_parms->key_buf, cipher_parms->key_buf,
cipher_parms->key_len);
cipher_parms->key_len = 0;
if (req_opts->is_rfc4543)
payload_len += assoc_size;
else
payload_len = assoc_size;
cipher_offset = 0;
assoc_size = 0;
}
if (err)
return 0;
flow_log("spu2 cipher type %s, cipher mode %s\n",
spu2_ciph_type_name(spu2_ciph_type),
spu2_ciph_mode_name(spu2_ciph_mode));
err = spu2_hash_xlate(hash_parms->alg, hash_parms->mode,
hash_parms->type,
cipher_parms->type,
&spu2_auth_type, &spu2_auth_mode);
if (err)
return 0;
flow_log("spu2 hash type %s, hash mode %s\n",
spu2_hash_type_name(spu2_auth_type),
spu2_hash_mode_name(spu2_auth_mode));
fmd = (struct SPU2_FMD *)spu_hdr;
spu2_fmd_ctrl0_write(fmd, req_opts->is_inbound, req_opts->auth_first,
proto, spu2_ciph_type, spu2_ciph_mode,
spu2_auth_type, spu2_auth_mode);
spu2_fmd_ctrl1_write(fmd, req_opts->is_inbound, assoc_size,
hash_parms->key_len, cipher_parms->key_len,
false, false,
aead_parms->return_iv, aead_parms->ret_iv_len,
aead_parms->ret_iv_off,
cipher_parms->iv_len, hash_parms->digestsize,
!req_opts->bd_suppress, return_md);
spu2_fmd_ctrl2_write(fmd, cipher_offset, hash_parms->key_len, 0,
cipher_parms->key_len, cipher_parms->iv_len);
spu2_fmd_ctrl3_write(fmd, payload_len);
ptr = (u8 *)(fmd + 1);
buf_len = sizeof(struct SPU2_FMD);
/* Write OMD */
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;
}
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;
}
if (cipher_parms->iv_len) {
memcpy(ptr, cipher_parms->iv_buf, cipher_parms->iv_len);
ptr += cipher_parms->iv_len;
buf_len += cipher_parms->iv_len;
}
packet_dump(" SPU request header: ", spu_hdr, buf_len);
return buf_len;
}