blob: 847eec15aa858e70f6e4f3023562b189eeeeddd7 [file] [log] [blame]
/*
* Copyright (c) 2023, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "rpmb_provider.h"
#include "components/service/rpmb/backend/rpmb_backend.h"
#include "protocols/service/rpmb/packed-c/rpmb_proto.h"
#include "util.h"
#include <string.h>
static rpc_status_t get_dev_info_handler(void *context, struct rpc_request *req)
{
struct rpmb_provider *this_context = (struct rpmb_provider *)context;
struct rpmb_request_get_dev_info *request_desc = NULL;
struct rpmb_response_get_dev_info *response_desc = NULL;
if (req->request.data_length < sizeof(*request_desc))
return RPC_ERROR_INVALID_REQUEST_BODY;
if (req->response.size < sizeof(*response_desc))
return RPC_ERROR_INVALID_RESPONSE_BODY;
request_desc = (struct rpmb_request_get_dev_info *)(req->request.data);
response_desc = (struct rpmb_response_get_dev_info *)(req->response.data);
req->service_status = rpmb_backend_get_dev_info(this_context->backend, request_desc->dev_id,
&response_desc->dev_info);
if (!req->service_status)
req->response.data_length = sizeof(*response_desc);
return RPC_SUCCESS;
}
static bool validate_size(size_t header_size, uint32_t frame_count, size_t available_length,
size_t *total_size)
{
/*
* Checking if [data frame count] * [data frame size] + [header size] fits into the RPC
* buffer.
*/
if (MUL_OVERFLOW(frame_count, sizeof(struct rpmb_data_frame), total_size))
return false;
if (ADD_OVERFLOW(*total_size, header_size, total_size))
return false;
if (*total_size > available_length)
return false;
return true;
}
static rpc_status_t data_request_handler(void *context, struct rpc_request *req)
{
struct rpmb_provider *this_context = (struct rpmb_provider *)context;
struct rpmb_request_data_request *request_desc = NULL;
struct rpmb_response_data_request *response_desc = NULL;
size_t response_frame_count = 0;
size_t total_size = 0;
if (req->request.data_length < sizeof(*request_desc))
return RPC_ERROR_INVALID_REQUEST_BODY;
request_desc = (struct rpmb_request_data_request *)(req->request.data);
if (!validate_size(sizeof(*request_desc), request_desc->request_frame_count,
req->request.data_length, &total_size))
return RPC_ERROR_INVALID_REQUEST_BODY;
if (!validate_size(sizeof(*response_desc), request_desc->max_response_frame_count,
req->response.size, &total_size))
return RPC_ERROR_INVALID_RESPONSE_BODY;
response_desc = (struct rpmb_response_data_request *)(req->response.data);
response_frame_count = request_desc->max_response_frame_count;
req->service_status = rpmb_backend_data_request(
this_context->backend,
request_desc->dev_id,
request_desc->request_frames,
request_desc->request_frame_count,
response_desc->response_frames,
&response_frame_count);
if (!req->service_status) {
if (!validate_size(sizeof(*response_desc), response_frame_count,
req->response.size, &total_size))
return RPC_ERROR_INVALID_RESPONSE_BODY;
response_desc->response_frame_count = response_frame_count;
req->response.data_length = total_size;
}
return RPC_SUCCESS;
}
static const struct service_handler handler_table[] = {
{TS_RPMB_OPCODE_GET_DEV_INFO, get_dev_info_handler},
{TS_RPMB_OPCODE_DATA_REQUEST, data_request_handler},
};
struct rpc_service_interface *rpmb_provider_init(struct rpmb_provider *context,
struct rpmb_backend *backend,
const struct rpc_uuid *service_uuid)
{
struct rpc_service_interface *rpc_interface = NULL;
if (!context || !backend || !service_uuid)
return NULL;
service_provider_init(&context->base_provider, context, service_uuid, handler_table,
ARRAY_SIZE(handler_table));
rpc_interface = service_provider_get_rpc_interface(&context->base_provider);
context->backend = backend;
return rpc_interface;
}
void rpmb_provider_deinit(struct rpmb_provider *context)
{
(void)context;
}