| // Copyright 2018 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <string.h> |
| |
| #include <ldmsg/ldmsg.h> |
| |
| static_assert(sizeof(ldmsg_req_t) == 1024, "Loader service requests can be at most 1024 bytes."); |
| |
| static uint64_t FidlAlign(uint32_t offset) { |
| const uint64_t alignment_mask = FIDL_ALIGNMENT - 1; |
| return (offset + alignment_mask) & ~alignment_mask; |
| } |
| |
| zx_status_t ldmsg_req_encode(ldmsg_req_t* req, size_t* req_len_out, const char* data, size_t len) { |
| size_t offset = 0; |
| switch (req->header.ordinal) { |
| case LDMSG_OP_DONE: |
| *req_len_out = sizeof(fidl_message_header_t); |
| return ZX_OK; |
| case LDMSG_OP_CLONE: |
| *req_len_out = sizeof(fidl_message_header_t) + sizeof(ldmsg_clone_t); |
| req->clone.object = FIDL_HANDLE_PRESENT; |
| return ZX_OK; |
| case LDMSG_OP_LOAD_OBJECT: |
| case LDMSG_OP_CONFIG: |
| offset = sizeof(fidl_string_t); |
| break; |
| default: |
| return ZX_ERR_INVALID_ARGS; |
| } |
| |
| // Reserve one byte for the null terminator on the receiving side. |
| if (LDMSG_MAX_PAYLOAD - offset - 1 < len) |
| return ZX_ERR_OUT_OF_RANGE; |
| |
| req->common.string.size = len; |
| req->common.string.data = (char*)FIDL_ALLOC_PRESENT; |
| memcpy(req->data + offset, data, len); |
| |
| // Make sure to zero out the extra bytes required by alignment constraints. |
| size_t req_len_unaligned = sizeof(fidl_message_header_t) + offset + len; |
| *req_len_out = FidlAlign(req_len_unaligned); |
| memset((char*)req + req_len_unaligned, 0, *req_len_out - req_len_unaligned); |
| return ZX_OK; |
| } |
| |
| zx_status_t ldmsg_req_decode(ldmsg_req_t* req, size_t req_len, const char** data_out, |
| size_t* len_out) { |
| size_t offset = 0; |
| switch (req->header.ordinal) { |
| case LDMSG_OP_DONE: |
| if (req_len != sizeof(fidl_message_header_t)) |
| return ZX_ERR_INVALID_ARGS; |
| *data_out = 0; |
| *len_out = 0; |
| return ZX_OK; |
| case LDMSG_OP_CLONE: |
| if (req_len != sizeof(fidl_message_header_t) + sizeof(ldmsg_clone_t) || |
| req->clone.object != FIDL_HANDLE_PRESENT) |
| return ZX_ERR_INVALID_ARGS; |
| *data_out = 0; |
| *len_out = 0; |
| return ZX_OK; |
| case LDMSG_OP_LOAD_OBJECT: |
| case LDMSG_OP_CONFIG: |
| if ((uintptr_t)req->common.string.data != FIDL_ALLOC_PRESENT) |
| return ZX_ERR_INVALID_ARGS; |
| offset = sizeof(fidl_string_t); |
| break; |
| default: |
| return ZX_ERR_INVALID_ARGS; |
| } |
| |
| size_t size = req->common.string.size; |
| if (LDMSG_MAX_PAYLOAD - offset - 1 < size || |
| req_len != FidlAlign(sizeof(fidl_message_header_t) + offset + size)) |
| return ZX_ERR_INVALID_ARGS; |
| |
| // Null terminate the string. The message isn't required to have a null |
| // terminated string, but we have enough space in our buffer for the null |
| // terminator and adding it makes life easier for our caller. |
| req->data[offset + size] = '\0'; |
| |
| *data_out = req->data + offset; |
| *len_out = size; |
| return ZX_OK; |
| } |
| |
| size_t ldmsg_rsp_get_size(ldmsg_rsp_t* rsp) { |
| switch (rsp->header.ordinal) { |
| case LDMSG_OP_LOAD_OBJECT: |
| case LDMSG_OP_CONFIG: |
| case LDMSG_OP_CLONE: |
| return sizeof(ldmsg_rsp_t); |
| case LDMSG_OP_DONE: |
| default: |
| return 0; |
| } |
| } |