1 /*
2 * Copyright (C) 2018 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 #include <assert.h>
17 #include <lk/err_ptr.h>
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <uapi/err.h>
21
22 #define TLOG_TAG "libtipc"
23 #include <trusty_log.h>
24
25 #include <lib/tipc/tipc.h>
26
27 #include "tipc_priv.h"
28
tipc_connect(handle_t * handle_p,const char * port)29 int tipc_connect(handle_t* handle_p, const char* port) {
30 int rc;
31
32 assert(handle_p);
33
34 rc = connect(port, IPC_CONNECT_WAIT_FOR_PORT);
35 if (rc < 0)
36 return rc;
37
38 *handle_p = (handle_t)rc;
39 return 0;
40 }
41
42 /*
43 * Send single buf message
44 */
tipc_send1(handle_t chan,const void * buf,size_t len)45 int tipc_send1(handle_t chan, const void* buf, size_t len) {
46 struct iovec iov = {
47 .iov_base = (void*)buf,
48 .iov_len = len,
49 };
50 ipc_msg_t msg = {
51 .iov = &iov,
52 .num_iov = 1,
53 .handles = NULL,
54 .num_handles = 0,
55 };
56 return send_msg(chan, &msg);
57 }
58
59 /*
60 * Receive single buf message
61 */
tipc_recv1(handle_t chan,size_t min_sz,void * buf,size_t buf_sz)62 int tipc_recv1(handle_t chan, size_t min_sz, void* buf, size_t buf_sz) {
63 int rc;
64 ipc_msg_info_t msg_inf;
65
66 rc = get_msg(chan, &msg_inf);
67 if (rc)
68 return rc;
69
70 if (msg_inf.len < min_sz || msg_inf.len > buf_sz) {
71 /* unexpected msg size: buffer too small or too big */
72 rc = ERR_BAD_LEN;
73 } else {
74 struct iovec iov = {
75 .iov_base = buf,
76 .iov_len = buf_sz,
77 };
78 ipc_msg_t msg = {
79 .iov = &iov,
80 .num_iov = 1,
81 .handles = NULL,
82 .num_handles = 0,
83 };
84 rc = read_msg(chan, msg_inf.id, 0, &msg);
85 }
86
87 put_msg(chan, msg_inf.id);
88 return rc;
89 }
90
91 /*
92 * Send message consisting of two segments (header and payload)
93 */
tipc_send2(handle_t chan,const void * hdr,size_t hdr_len,const void * payload,size_t payload_len)94 int tipc_send2(handle_t chan,
95 const void* hdr,
96 size_t hdr_len,
97 const void* payload,
98 size_t payload_len) {
99 struct iovec iovs[2] = {
100 {
101 .iov_base = (void*)hdr,
102 .iov_len = hdr_len,
103 },
104 {
105 .iov_base = (void*)payload,
106 .iov_len = payload_len,
107 },
108 };
109 ipc_msg_t msg = {
110 .iov = iovs,
111 .num_iov = countof(iovs),
112 .handles = NULL,
113 .num_handles = 0,
114 };
115 return send_msg(chan, &msg);
116 }
117
118 /*
119 * Receive message consisting of two segments.
120 */
tipc_recv2(handle_t chan,size_t min_sz,void * buf1,size_t buf1_sz,void * buf2,size_t buf2_sz)121 int tipc_recv2(handle_t chan,
122 size_t min_sz,
123 void* buf1,
124 size_t buf1_sz,
125 void* buf2,
126 size_t buf2_sz) {
127 int rc;
128 ipc_msg_info_t msg_inf;
129
130 rc = get_msg(chan, &msg_inf);
131 if (rc)
132 return rc;
133
134 if (msg_inf.len < min_sz || (msg_inf.len > (buf1_sz + buf2_sz))) {
135 /* unexpected msg size: buffer too small or too big */
136 rc = ERR_BAD_LEN;
137 } else {
138 struct iovec iovs[2] = {
139 {
140 .iov_base = buf1,
141 .iov_len = buf1_sz,
142 },
143 {
144 .iov_base = buf2,
145 .iov_len = buf2_sz,
146 },
147 };
148 ipc_msg_t msg = {
149 .iov = iovs,
150 .num_iov = countof(iovs),
151 .handles = NULL,
152 .num_handles = 0,
153 };
154 rc = read_msg(chan, msg_inf.id, 0, &msg);
155 }
156
157 put_msg(chan, msg_inf.id);
158 return rc;
159 }
160
161 /*
162 * Handle common unexpected port events
163 */
tipc_handle_port_errors(const struct uevent * ev)164 void tipc_handle_port_errors(const struct uevent* ev) {
165 if ((ev->event & IPC_HANDLE_POLL_ERROR) ||
166 (ev->event & IPC_HANDLE_POLL_HUP) ||
167 (ev->event & IPC_HANDLE_POLL_MSG) ||
168 (ev->event & IPC_HANDLE_POLL_SEND_UNBLOCKED)) {
169 /* should never happen with port handles */
170 TLOGE("error event (0x%x) for port (%d)\n", ev->event, ev->handle);
171 abort();
172 }
173 }
174
175 /*
176 * Handle common unexpected channel events
177 */
tipc_handle_chan_errors(const struct uevent * ev)178 void tipc_handle_chan_errors(const struct uevent* ev) {
179 if ((ev->event & IPC_HANDLE_POLL_ERROR) ||
180 (ev->event & IPC_HANDLE_POLL_READY)) {
181 /* should never happen for channel handles */
182 TLOGE("error event (0x%x) for chan (%d)\n", ev->event, ev->handle);
183 abort();
184 }
185 }
186
187 /*
188 * Initialize an existing tipc_hset
189 */
tipc_hset_init(struct tipc_hset * hset)190 int tipc_hset_init(struct tipc_hset* hset) {
191 int rc;
192
193 assert(!IS_ERR(hset) && hset);
194
195 hset->handle = INVALID_IPC_HANDLE;
196
197 rc = handle_set_create();
198 if (rc < 0)
199 return rc;
200
201 hset->handle = (handle_t)rc;
202 return 0;
203 }
204
205 /*
206 * Allocate and initialize new handle set structure
207 */
tipc_hset_create(void)208 struct tipc_hset* tipc_hset_create(void) {
209 struct tipc_hset* hset;
210
211 hset = malloc(sizeof(struct tipc_hset));
212 if (!hset)
213 return (void*)(uintptr_t)(ERR_NO_MEMORY);
214
215 int rc = tipc_hset_init(hset);
216 if (rc < 0) {
217 free(hset);
218 return (void*)(uintptr_t)(rc);
219 }
220
221 return hset;
222 }
223
224 /*
225 * Add handle to handle set
226 */
tipc_hset_add_entry(struct tipc_hset * hset,handle_t handle,uint32_t evt_mask,struct tipc_event_handler * evt_handler)227 int tipc_hset_add_entry(struct tipc_hset* hset,
228 handle_t handle,
229 uint32_t evt_mask,
230 struct tipc_event_handler* evt_handler) {
231 struct uevent uevt = {
232 .handle = handle,
233 .event = evt_mask,
234 .cookie = (void*)evt_handler,
235 };
236
237 if (IS_ERR(hset) || !hset || !evt_handler)
238 return ERR_INVALID_ARGS;
239
240 assert(evt_handler->proc);
241
242 /* attach new entry */
243 return handle_set_ctrl(hset->handle, HSET_ADD, &uevt);
244 }
245
246 /*
247 * Modify handle set entry
248 */
tipc_hset_mod_entry(struct tipc_hset * hset,handle_t handle,uint32_t evt_mask,struct tipc_event_handler * evt_handler)249 int tipc_hset_mod_entry(struct tipc_hset* hset,
250 handle_t handle,
251 uint32_t evt_mask,
252 struct tipc_event_handler* evt_handler) {
253 struct uevent uevt = {
254 .handle = handle,
255 .event = evt_mask,
256 .cookie = (void*)evt_handler,
257 };
258
259 if (IS_ERR(hset) || !hset || !evt_handler)
260 return ERR_INVALID_ARGS;
261
262 assert(evt_handler->proc);
263
264 /* modify entry */
265 return handle_set_ctrl(hset->handle, HSET_MOD, &uevt);
266 }
267
268 /*
269 * Remove handle from handle set
270 */
tipc_hset_remove_entry(struct tipc_hset * hset,handle_t h)271 int tipc_hset_remove_entry(struct tipc_hset* hset, handle_t h) {
272 struct uevent uevt = {
273 .handle = h,
274 .event = 0,
275 .cookie = NULL,
276 };
277
278 if (IS_ERR(hset) || !hset)
279 return ERR_INVALID_ARGS;
280
281 /* detach entry */
282 return handle_set_ctrl(hset->handle, HSET_DEL, &uevt);
283 }
284
tipc_handle_event(struct tipc_hset * hset,uint32_t timeout)285 int tipc_handle_event(struct tipc_hset* hset, uint32_t timeout) {
286 int rc;
287 struct uevent evt = UEVENT_INITIAL_VALUE(evt);
288
289 if (IS_ERR(hset) || !hset)
290 return ERR_INVALID_ARGS;
291
292 /* wait for next event up to specified time */
293 rc = wait(hset->handle, &evt, timeout);
294 if (rc < 0)
295 return rc;
296
297 /* get handler */
298 struct tipc_event_handler* handler = evt.cookie;
299
300 /* invoke it */
301 handler->proc(&evt, handler->priv);
302
303 return 0;
304 }
305
tipc_run_event_loop(struct tipc_hset * hset)306 int tipc_run_event_loop(struct tipc_hset* hset) {
307 int rc;
308
309 do {
310 rc = tipc_handle_event(hset, INFINITE_TIME);
311 } while (rc == 0);
312
313 return rc;
314 }
315