blob: dce749ba9beacbf3216de1ae36731b7fc09c2a99 [file] [log] [blame]
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <lib/system_state/system_state.h>
#include <lib/tipc/tipc.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <trusty_ipc.h>
#include <trusty_log.h>
#include <uapi/err.h>
#define TLOG_TAG "lib_system_state"
/**
* long system_state_send_req() - sends request to system_state server
* @req: the request header to send to the system_state server
* @req_buf: the request payload to send to the system_state server
* @req_buf_len: the length of the request payload @req_buf
* @resp: buffer in which to store the response header
* @resp_buf: buffer in which to store the response payload
* @resp_buf_len: the size of the response buffer. Inout param, set
* to the actual response payload length.
*
* Returns: NO_ERROR on success, negative error code on failure
*/
static long system_state_send_req(struct system_state_req* req,
void* req_buf,
size_t req_buf_len,
struct system_state_resp* resp,
void* resp_buf,
size_t* resp_buf_len) {
int ret;
handle_t session = connect(SYSTEM_STATE_PORT, IPC_CONNECT_WAIT_FOR_PORT);
if (session == INVALID_IPC_HANDLE) {
TLOGE("%s: failed to connect\n", __func__);
return ERR_IO;
}
ret = tipc_send2(session, req, sizeof(*req), req_buf, req_buf_len);
if (ret < 0) {
goto err_io;
}
if (((size_t)ret) != sizeof(*req) + req_buf_len) {
ret = ERR_IO;
goto err_io;
}
uevent_t uevt;
ret = wait(session, &uevt, INFINITE_TIME);
if (ret != NO_ERROR) {
goto err_io;
}
ret = tipc_recv2(session, sizeof(*resp), resp, sizeof(*resp), resp_buf,
*resp_buf_len);
if (ret < 0) {
goto err_io;
}
size_t read_len = (size_t)ret;
if (read_len < sizeof(*resp)) {
TLOGE("%s: short read (%zu)\n", __func__, read_len);
ret = ERR_IO;
goto err_io;
}
if (resp->cmd != (req->cmd | SYSTEM_STATE_CMD_RESP_BIT)) {
TLOGE("%s: invalid response id (0x%x) for cmd (0x%x)\n", __func__,
resp->cmd, req->cmd);
ret = ERR_NOT_VALID;
goto err_io;
}
close(session);
*resp_buf_len = read_len - sizeof(*resp);
return resp->result;
err_io:
close(session);
TLOGE("%s: failed read_msg (%d)\n", __func__, ret);
return ret;
}
int system_state_get_flag(enum system_state_flag flag, uint64_t* valuep) {
int ret;
struct system_state_req req = {
.cmd = SYSTEM_STATE_CMD_GET_FLAG,
};
struct system_state_get_flag_req get_flag_req = {
.flag = flag,
};
struct system_state_resp resp;
struct system_state_get_flag_resp get_flag_resp;
size_t get_flag_resp_size = sizeof(get_flag_resp);
ret = system_state_send_req(&req, &get_flag_req, sizeof(get_flag_req),
&resp, &get_flag_resp, &get_flag_resp_size);
if (ret) {
TLOGE("%s: request failed (%d)\n", __func__, ret);
return ret;
}
if (get_flag_resp_size != sizeof(get_flag_resp)) {
TLOGE("%s: bad response size (%zd)\n", __func__, get_flag_resp_size);
return ERR_IO;
}
if (get_flag_resp.flag != flag) {
TLOGE("%s: bad response flag (%d)\n", __func__, get_flag_resp.flag);
return ERR_IO;
}
*valuep = get_flag_resp.value;
return 0;
}