/* * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include "fwu_provider.h" #include #include "common/uuid/uuid.h" #include "protocols/rpc/common/packed-c/status.h" #include "protocols/service/fwu/packed-c/opcodes.h" #include "service/fwu/agent/update_agent.h" #include "service/fwu/provider/serializer/fwu_provider_serializer.h" #include "fwu_uuid.h" /* Service request handlers */ static rpc_status_t begin_staging_handler(void *context, struct rpc_request *req); static rpc_status_t end_staging_handler(void *context, struct rpc_request *req); static rpc_status_t cancel_staging_handler(void *context, struct rpc_request *req); static rpc_status_t open_handler(void *context, struct rpc_request *req); static rpc_status_t write_stream_handler(void *context, struct rpc_request *req); static rpc_status_t read_stream_handler(void *context, struct rpc_request *req); static rpc_status_t commit_handler(void *context, struct rpc_request *req); static rpc_status_t accept_image_handler(void *context, struct rpc_request *req); static rpc_status_t select_previous_handler(void *context, struct rpc_request *req); /* Handler mapping table for service */ static const struct service_handler handler_table[] = { { TS_FWU_OPCODE_BEGIN_STAGING, begin_staging_handler }, { TS_FWU_OPCODE_END_STAGING, end_staging_handler }, { TS_FWU_OPCODE_CANCEL_STAGING, cancel_staging_handler }, { TS_FWU_OPCODE_OPEN, open_handler }, { TS_FWU_OPCODE_WRITE_STREAM, write_stream_handler }, { TS_FWU_OPCODE_READ_STREAM, read_stream_handler }, { TS_FWU_OPCODE_COMMIT, commit_handler }, { TS_FWU_OPCODE_ACCEPT_IMAGE, accept_image_handler }, { TS_FWU_OPCODE_SELECT_PREVIOUS, select_previous_handler } }; struct rpc_service_interface *fwu_provider_init(struct fwu_provider *context, struct update_agent *update_agent) { const struct rpc_uuid service_uuid = { .uuid = TS_FWU_SERVICE_UUID }; /* Initialise the fwu_provider */ context->update_agent = update_agent; for (size_t encoding = 0; encoding < TS_RPC_ENCODING_LIMIT; ++encoding) context->serializers[encoding] = NULL; service_provider_init(&context->base_provider, context, &service_uuid, handler_table, sizeof(handler_table) / sizeof(struct service_handler)); return service_provider_get_rpc_interface(&context->base_provider); } void fwu_provider_deinit(struct fwu_provider *context) { (void)context; } void fwu_provider_register_serializer(struct fwu_provider *context, unsigned int encoding, const struct fwu_provider_serializer *serializer) { if (encoding < TS_RPC_ENCODING_LIMIT) { context->serializers[encoding] = serializer; } } static const struct fwu_provider_serializer *get_fwu_serializer(struct fwu_provider *this_instance, const struct rpc_request *req) { const struct fwu_provider_serializer *serializer = NULL; unsigned int encoding = 0; if (encoding < TS_RPC_ENCODING_LIMIT) serializer = this_instance->serializers[encoding]; return serializer; } static rpc_status_t begin_staging_handler(void *context, struct rpc_request *req) { struct fwu_provider *this_instance = (struct fwu_provider *)context; req->service_status = update_agent_begin_staging(this_instance->update_agent); return RPC_SUCCESS; } static rpc_status_t end_staging_handler(void *context, struct rpc_request *req) { struct fwu_provider *this_instance = (struct fwu_provider *)context; req->service_status = update_agent_end_staging(this_instance->update_agent); return RPC_SUCCESS; } static rpc_status_t cancel_staging_handler(void *context, struct rpc_request *req) { struct fwu_provider *this_instance = (struct fwu_provider *)context; req->service_status = update_agent_cancel_staging(this_instance->update_agent); return RPC_SUCCESS; } static rpc_status_t open_handler(void *context, struct rpc_request *req) { rpc_status_t rpc_status = RPC_ERROR_INTERNAL; struct rpc_buffer *req_buf = &req->request; struct fwu_provider *this_instance = (struct fwu_provider *)context; const struct fwu_provider_serializer *serializer = get_fwu_serializer(this_instance, req); struct uuid_octets image_type_uuid; if (serializer) rpc_status = serializer->deserialize_open_req(req_buf, &image_type_uuid); if (rpc_status == RPC_SUCCESS) { uint32_t handle = 0; req->service_status = update_agent_open(this_instance->update_agent, &image_type_uuid, &handle); if (!req->service_status) { struct rpc_buffer *resp_buf = &req->response; rpc_status = serializer->serialize_open_resp(resp_buf, handle); } } return rpc_status; } static rpc_status_t write_stream_handler(void *context, struct rpc_request *req) { rpc_status_t rpc_status = RPC_ERROR_INTERNAL; struct rpc_buffer *req_buf = &req->request; struct fwu_provider *this_instance = (struct fwu_provider *)context; const struct fwu_provider_serializer *serializer = get_fwu_serializer(this_instance, req); uint32_t handle = 0; size_t data_len = 0; const uint8_t *data = NULL; if (serializer) rpc_status = serializer->deserialize_write_stream_req(req_buf, &handle, &data_len, &data); if (rpc_status == RPC_SUCCESS) { req->service_status = update_agent_write_stream(this_instance->update_agent, handle, data, data_len); } return rpc_status; } static rpc_status_t read_stream_handler(void *context, struct rpc_request *req) { rpc_status_t rpc_status = RPC_ERROR_INTERNAL; struct rpc_buffer *req_buf = &req->request; struct fwu_provider *this_instance = (struct fwu_provider *)context; const struct fwu_provider_serializer *serializer = get_fwu_serializer(this_instance, req); uint32_t handle = 0; if (serializer) rpc_status = serializer->deserialize_read_stream_req(req_buf, &handle); if (rpc_status == RPC_SUCCESS) { struct rpc_buffer *resp_buf = &req->response; uint8_t *payload_buf; size_t max_payload; size_t read_len = 0; size_t total_len = 0; serializer->read_stream_resp_payload(resp_buf, &payload_buf, &max_payload); req->service_status = update_agent_read_stream(this_instance->update_agent, handle, payload_buf, max_payload, &read_len, &total_len); if (!req->service_status) rpc_status = serializer->serialize_read_stream_resp(resp_buf, read_len, total_len); } return rpc_status; } static rpc_status_t commit_handler(void *context, struct rpc_request *req) { rpc_status_t rpc_status = RPC_ERROR_INTERNAL; struct rpc_buffer *req_buf = &req->request; struct fwu_provider *this_instance = (struct fwu_provider *)context; const struct fwu_provider_serializer *serializer = get_fwu_serializer(this_instance, req); uint32_t handle = 0; bool accepted = false; size_t max_atomic_len = 0; if (serializer) rpc_status = serializer->deserialize_commit_req(req_buf, &handle, &accepted, &max_atomic_len); if (rpc_status == RPC_SUCCESS) { req->service_status = update_agent_commit(this_instance->update_agent, handle, accepted); if (!req->service_status) { struct rpc_buffer *resp_buf = &req->response; rpc_status = serializer->serialize_commit_resp(resp_buf, 0, 0); } } return rpc_status; } static rpc_status_t accept_image_handler(void *context, struct rpc_request *req) { rpc_status_t rpc_status = RPC_ERROR_INTERNAL; struct rpc_buffer *req_buf = &req->request; struct fwu_provider *this_instance = (struct fwu_provider *)context; const struct fwu_provider_serializer *serializer = get_fwu_serializer(this_instance, req); struct uuid_octets image_type_uuid; if (serializer) rpc_status = serializer->deserialize_accept_req(req_buf, &image_type_uuid); if (rpc_status == RPC_SUCCESS) req->service_status = update_agent_accept(this_instance->update_agent, &image_type_uuid); return rpc_status; } static rpc_status_t select_previous_handler(void *context, struct rpc_request *req) { struct fwu_provider *this_instance = (struct fwu_provider *)context; req->service_status = update_agent_select_previous(this_instance->update_agent); return RPC_SUCCESS; }