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