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