1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <lib/system_state/system_state.h>
18 
19 #include <lib/tipc/tipc.h>
20 #include <stdbool.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <trusty_ipc.h>
25 #include <trusty_log.h>
26 #include <uapi/err.h>
27 
28 #define TLOG_TAG "lib_system_state"
29 
30 /**
31  * long system_state_send_req() - sends request to system_state server
32  * @req:          the request header to send to the system_state server
33  * @req_buf:      the request payload to send to the system_state server
34  * @req_buf_len:  the length of the request payload @req_buf
35  * @resp:         buffer in which to store the response header
36  * @resp_buf:     buffer in which to store the response payload
37  * @resp_buf_len: the size of the response buffer. Inout param, set
38  *                to the actual response payload length.
39  *
40  * Returns: NO_ERROR on success, negative error code on failure
41  */
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)42 static long system_state_send_req(struct system_state_req* req,
43                                   void* req_buf,
44                                   size_t req_buf_len,
45                                   struct system_state_resp* resp,
46                                   void* resp_buf,
47                                   size_t* resp_buf_len) {
48     int ret;
49 
50     handle_t session = connect(SYSTEM_STATE_PORT, IPC_CONNECT_WAIT_FOR_PORT);
51     if (session == INVALID_IPC_HANDLE) {
52         TLOGE("%s: failed to connect\n", __func__);
53         return ERR_IO;
54     }
55 
56     ret = tipc_send2(session, req, sizeof(*req), req_buf, req_buf_len);
57     if (ret < 0) {
58         goto err_io;
59     }
60 
61     if (((size_t)ret) != sizeof(*req) + req_buf_len) {
62         ret = ERR_IO;
63         goto err_io;
64     }
65 
66     uevent_t uevt;
67     ret = wait(session, &uevt, INFINITE_TIME);
68     if (ret != NO_ERROR) {
69         goto err_io;
70     }
71 
72     ret = tipc_recv2(session, sizeof(*resp), resp, sizeof(*resp), resp_buf,
73                      *resp_buf_len);
74     if (ret < 0) {
75         goto err_io;
76     }
77 
78     size_t read_len = (size_t)ret;
79     if (read_len < sizeof(*resp)) {
80         TLOGE("%s: short read (%zu)\n", __func__, read_len);
81         ret = ERR_IO;
82         goto err_io;
83     }
84 
85     if (resp->cmd != (req->cmd | SYSTEM_STATE_CMD_RESP_BIT)) {
86         TLOGE("%s: invalid response id (0x%x) for cmd (0x%x)\n", __func__,
87               resp->cmd, req->cmd);
88         ret = ERR_NOT_VALID;
89         goto err_io;
90     }
91 
92     close(session);
93 
94     *resp_buf_len = read_len - sizeof(*resp);
95     return resp->result;
96 
97 err_io:
98     close(session);
99     TLOGE("%s: failed read_msg (%d)\n", __func__, ret);
100     return ret;
101 }
102 
system_state_get_flag(enum system_state_flag flag,uint64_t * valuep)103 int system_state_get_flag(enum system_state_flag flag, uint64_t* valuep) {
104     int ret;
105     struct system_state_req req = {
106             .cmd = SYSTEM_STATE_CMD_GET_FLAG,
107     };
108     struct system_state_get_flag_req get_flag_req = {
109             .flag = flag,
110     };
111     struct system_state_resp resp;
112     struct system_state_get_flag_resp get_flag_resp;
113     size_t get_flag_resp_size = sizeof(get_flag_resp);
114 
115     ret = system_state_send_req(&req, &get_flag_req, sizeof(get_flag_req),
116                                 &resp, &get_flag_resp, &get_flag_resp_size);
117     if (ret) {
118         TLOGE("%s: request failed (%d)\n", __func__, ret);
119         return ret;
120     }
121 
122     if (get_flag_resp_size != sizeof(get_flag_resp)) {
123         TLOGE("%s: bad response size (%zd)\n", __func__, get_flag_resp_size);
124         return ERR_IO;
125     }
126 
127     if (get_flag_resp.flag != flag) {
128         TLOGE("%s: bad response flag (%d)\n", __func__, get_flag_resp.flag);
129         return ERR_IO;
130     }
131 
132     *valuep = get_flag_resp.value;
133 
134     return 0;
135 }
136