u32 spu2_create_request()

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;
}