static int tb_xdp_properties_request()

in xdomain.c [295:385]


static int tb_xdp_properties_request(struct tb_ctl *ctl, u64 route,
	const uuid_t *src_uuid, const uuid_t *dst_uuid, int retry,
	u32 **block, u32 *generation)
{
	struct tb_xdp_properties_response *res;
	struct tb_xdp_properties req;
	u16 data_len, len;
	size_t total_size;
	u32 *data = NULL;
	int ret;

	total_size = sizeof(*res) + TB_XDP_PROPERTIES_MAX_DATA_LENGTH * 4;
	res = kzalloc(total_size, GFP_KERNEL);
	if (!res)
		return -ENOMEM;

	memset(&req, 0, sizeof(req));
	tb_xdp_fill_header(&req.hdr, route, retry % 4, PROPERTIES_REQUEST,
			   sizeof(req));
	memcpy(&req.src_uuid, src_uuid, sizeof(*src_uuid));
	memcpy(&req.dst_uuid, dst_uuid, sizeof(*dst_uuid));

	len = 0;
	data_len = 0;

	do {
		ret = __tb_xdomain_request(ctl, &req, sizeof(req),
					   TB_CFG_PKG_XDOMAIN_REQ, res,
					   total_size, TB_CFG_PKG_XDOMAIN_RESP,
					   XDOMAIN_DEFAULT_TIMEOUT);
		if (ret)
			goto err;

		ret = tb_xdp_handle_error(&res->err);
		if (ret)
			goto err;

		/*
		 * Package length includes the whole payload without the
		 * XDomain header. Validate first that the package is at
		 * least size of the response structure.
		 */
		len = res->hdr.xd_hdr.length_sn & TB_XDOMAIN_LENGTH_MASK;
		if (len < sizeof(*res) / 4) {
			ret = -EINVAL;
			goto err;
		}

		len += sizeof(res->hdr.xd_hdr) / 4;
		len -= sizeof(*res) / 4;

		if (res->offset != req.offset) {
			ret = -EINVAL;
			goto err;
		}

		/*
		 * First time allocate block that has enough space for
		 * the whole properties block.
		 */
		if (!data) {
			data_len = res->data_length;
			if (data_len > TB_XDP_PROPERTIES_MAX_LENGTH) {
				ret = -E2BIG;
				goto err;
			}

			data = kcalloc(data_len, sizeof(u32), GFP_KERNEL);
			if (!data) {
				ret = -ENOMEM;
				goto err;
			}
		}

		memcpy(data + req.offset, res->data, len * 4);
		req.offset += len;
	} while (!data_len || req.offset < data_len);

	*block = data;
	*generation = res->generation;

	kfree(res);

	return data_len;

err:
	kfree(data);
	kfree(res);

	return ret;
}