static int nsm_rng_read()

in nsm-driver/nsm.c [563:658]


static int nsm_rng_read(struct hwrng *rng, void *data, size_t max, bool wait)
{
	int rc = 0;
	uint8_t *resp_ptr = NULL;
	uint64_t resp_len = 0;
	uint8_t *rand_data = NULL;

	struct nsm_kernel_message message;

	/*
	 * 69                          # text(9)
	 *     47657452616E646F6D      # "GetRandom"
	 */
	const uint8_t request[] = { 0x69, 0x47, 0x65, 0x74, 0x52, 0x61, 0x6E, 0x64, 0x6F, 0x6D };

	/*
	 * A1                          # map(1)
	 *     69                      # text(9) - Name of field
	 *         47657452616E646F6D  # "GetRandom"
	 * A1                          # map(1) - The field itself
	 *     66                      # text(6)
	 *         72616E646F6D        # "random"
	 *	# The rest of the response should be a byte array
	 */
	const uint8_t response[] = { 0xA1, 0x69, 0x47, 0x65, 0x74, 0x52, 0x61, 0x6E, 0x64,
		0x6F, 0x6D, 0xA1, 0x66, 0x72, 0x61, 0x6E, 0x64, 0x6F, 0x6D };

	if (wait == true) {
		mutex_lock(&nsm_lock);
	} else {
		if (mutex_trylock(&nsm_lock) == 0)
			return -EBUSY;
	}

	/* The kernel message structure must be cleared */
	memset(&message, 0, sizeof(message));

	/* Set request message */
	message.request.iov_len = sizeof(request);
	message.request.iov_base = kmalloc(message.request.iov_len, GFP_KERNEL);
	if (message.request.iov_base == NULL)
		goto out;
	memcpy(message.request.iov_base, request, sizeof(request));

	/* Allocate space for response */
	message.response.iov_len = NSM_RESPONSE_MAX_SIZE;
	message.response.iov_base = kmalloc(message.response.iov_len, GFP_KERNEL);
	if (message.response.iov_base == NULL)
		goto out;

	/* Send/receive message */
	rc = nsm_communicate_with_device(&message);
	if (rc != 0)
		goto out;

	resp_ptr = (uint8_t *) message.response.iov_base;
	resp_len = message.response.iov_len;

	if (resp_len < sizeof(response) + 1) {
		pr_err("NSM RNG: Received short response from NSM: Possible error message or invalid response");
		rc = -EFAULT;
		goto out;
	}

	if (memcmp(resp_ptr, response, sizeof(response)) != 0) {
		pr_err("NSM RNG: Invalid response header: Possible error message or invalid response");
		rc = -EFAULT;
		goto out;
	}

	resp_ptr += sizeof(response);
	resp_len -= sizeof(response);

	if (!cbor_object_is_array(resp_ptr, resp_len)) {
		/* not a byte array */
		pr_err("NSM RNG: Invalid response type: Expecting a byte array response");
		rc = -EFAULT;
		goto out;
	}

	rc = cbor_object_get_array(resp_ptr, resp_len, &rand_data);
	if (rc < 0) {
		pr_err("NSM RNG: Invalid CBOR encoding\n");
		goto out;
	}

	max = max > INT_MAX ? INT_MAX : max;
	rc = rc > max ? max : rc;
	memcpy(data, rand_data, rc);

	pr_info("NSM RNG: returning rand bytes = %d\n", rc);
out:
	message_delete(&message);
	mutex_unlock(&nsm_lock);
	return rc;
}