1 /*
2 * Copyright (c) 2022, Google Inc. All rights reserved
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files
6 * (the "Software"), to deal in the Software without restriction,
7 * including without limitation the rights to use, copy, modify, merge,
8 * publish, distribute, sublicense, and/or sell copies of the Software,
9 * and to permit persons to whom the Software is furnished to do so,
10 * subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 */
23
24 #include <err.h>
25 #include <inttypes.h>
26 #include <ktipc_test.h>
27 #include <lib/ktipc/ktipc.h>
28 #include <lib/trusty/ipc.h>
29 #include <lib/trusty/uuid.h>
30 #include <lk/init.h>
31 #include <lk/list.h>
32 #include <lk/trace.h>
33 #include <string.h>
34
35 struct chan_ctx {
36 struct list_node queued_msgs;
37 };
38
39 struct queued_msg {
40 struct list_node node;
41 size_t len;
42 char buf[KTIPC_TEST_MAX_MSG_SIZE];
43 };
44
45 static uint8_t echo_buf[KTIPC_TEST_MAX_MSG_SIZE];
46 static uint32_t close_counter = 0;
47
queue_buffer(struct chan_ctx * ctx,const uint8_t * buf,size_t len)48 static int queue_buffer(struct chan_ctx* ctx, const uint8_t* buf, size_t len) {
49 struct queued_msg* qmsg;
50
51 qmsg = calloc(1, sizeof(struct queued_msg));
52 if (!qmsg) {
53 TRACEF("%s: failed to allocate queued message\n", __func__);
54 return ERR_NO_MEMORY;
55 }
56
57 qmsg->len = len;
58 memcpy(qmsg->buf, buf, len);
59 list_add_tail(&ctx->queued_msgs, &qmsg->node);
60
61 return NO_ERROR;
62 }
63
test_handle_msg(const struct ktipc_port * port,struct handle * chan,void * ctx_v)64 static int test_handle_msg(const struct ktipc_port* port,
65 struct handle* chan,
66 void* ctx_v) {
67 int rc;
68 struct chan_ctx* ctx = ctx_v;
69 struct ktipc_test_req* req = (struct ktipc_test_req*)echo_buf;
70
71 rc = ktipc_recv(chan, sizeof(*req), req, KTIPC_TEST_MAX_MSG_SIZE);
72 if (rc < 0) {
73 TRACEF("%s: failed (%d) to read message\n", __func__, rc);
74 return rc;
75 }
76
77 switch (req->cmd) {
78 case KTIPC_TEST_CMD_NOP:
79 break;
80
81 case KTIPC_TEST_CMD_ECHO: {
82 size_t len = rc - sizeof(*req);
83 if (list_is_empty(&ctx->queued_msgs)) {
84 /* Queue is empty, we can send this message directly */
85 rc = ktipc_send(chan, req->payload, len);
86 } else {
87 /* There are other messages in the queue, add this one to the end */
88 rc = ERR_NOT_ENOUGH_BUFFER;
89 }
90
91 if (rc < 0) {
92 if (rc == ERR_NOT_ENOUGH_BUFFER) {
93 TRACEF("%s: queuing message %zd\n", __func__, len);
94 return queue_buffer(ctx, req->payload, len);
95 } else {
96 TRACEF("%s: failed (%d) to send echo\n", __func__, rc);
97 return rc;
98 }
99 }
100 break;
101 }
102
103 case KTIPC_TEST_CMD_CLOSE:
104 /* We want to close our end of the connection, and this does it */
105 return ERR_INVALID_ARGS;
106
107 case KTIPC_TEST_CMD_READ_CLOSE_COUNTER:
108 rc = ktipc_send(chan, &close_counter, sizeof(close_counter));
109 if (rc < 0) {
110 TRACEF("%s: failed (%d) to send close counter\n", __func__, rc);
111 return rc;
112 }
113 break;
114
115 default:
116 TRACEF("%s: unknown test command: %" PRIu32 "\n", __func__, req->cmd);
117 return ERR_CMD_UNKNOWN;
118 }
119
120 return NO_ERROR;
121 }
122
test_handle_connect(const struct ktipc_port * port,struct handle * chan,const struct uuid * peer,void ** ctx_p)123 static int test_handle_connect(const struct ktipc_port* port,
124 struct handle* chan,
125 const struct uuid* peer,
126 void** ctx_p) {
127 struct chan_ctx* ctx = calloc(1, sizeof(*ctx));
128 if (!ctx) {
129 TRACEF("%s: failed to allocate context\n", __func__);
130 return ERR_NO_MEMORY;
131 }
132
133 list_initialize(&ctx->queued_msgs);
134 *ctx_p = ctx;
135
136 return NO_ERROR;
137 }
138
test_handle_channel_cleanup(void * ctx_v)139 static void test_handle_channel_cleanup(void* ctx_v) {
140 struct chan_ctx* ctx = ctx_v;
141 struct queued_msg* qmsg;
142 struct queued_msg* temp;
143
144 close_counter++;
145
146 list_for_every_entry_safe(&ctx->queued_msgs, qmsg, temp, struct queued_msg,
147 node) {
148 free(qmsg);
149 }
150
151 free(ctx);
152 }
153
test_handle_send_unblocked(const struct ktipc_port * port,struct handle * chan,void * ctx_v)154 static int test_handle_send_unblocked(const struct ktipc_port* port,
155 struct handle* chan,
156 void* ctx_v) {
157 int rc;
158 struct chan_ctx* ctx = ctx_v;
159 struct queued_msg* qmsg;
160 struct queued_msg* temp;
161
162 list_for_every_entry_safe(&ctx->queued_msgs, qmsg, temp, struct queued_msg,
163 node) {
164 TRACEF("%s: sending queued message %zd\n", __func__, qmsg->len);
165 rc = ktipc_send(chan, qmsg->buf, qmsg->len);
166 if (rc < 0) {
167 if (rc == ERR_NOT_ENOUGH_BUFFER) {
168 break;
169 } else {
170 TRACEF("%s: failed (%d) to send echo\n", __func__, rc);
171 return rc;
172 }
173 }
174
175 list_delete(&qmsg->node);
176 free(qmsg);
177 }
178
179 return NO_ERROR;
180 }
181
connecterr_handle_connect(const struct ktipc_port * port,struct handle * chan,const struct uuid * peer,void ** ctx_p)182 static int connecterr_handle_connect(const struct ktipc_port* port,
183 struct handle* chan,
184 const struct uuid* peer,
185 void** ctx_p) {
186 TRACEF("%s: closing channel\n", __func__);
187 return ERR_INVALID_ARGS;
188 }
189
nop_handle_msg(const struct ktipc_port * port,struct handle * chan,void * ctx_v)190 static int nop_handle_msg(const struct ktipc_port* port,
191 struct handle* chan,
192 void* ctx_v) {
193 return NO_ERROR;
194 }
195
nop_handle_channel_cleanup(void * ctx_v)196 static void nop_handle_channel_cleanup(void* ctx_v) {}
197
198 /* Operation structures for this server */
199 const static struct ktipc_srv_ops test_srv_ops = {
200 .on_connect = test_handle_connect,
201 .on_message = test_handle_msg,
202 .on_channel_cleanup = test_handle_channel_cleanup,
203 .on_send_unblocked = test_handle_send_unblocked,
204 };
205
206 const static struct ktipc_srv_ops connecterr_srv_ops = {
207 .on_connect = connecterr_handle_connect,
208 .on_message = nop_handle_msg,
209 .on_channel_cleanup = nop_handle_channel_cleanup,
210 };
211
212 /* UUID structures for this server */
213 const static struct uuid* valid_uuids[] = {
214 &kernel_uuid,
215 };
216
217 const static struct uuid* bad_uuids[] = {
218 &zero_uuid,
219 };
220
221 /* Ports for this server */
222 const static struct ktipc_port_acl test_srv_port_acl = {
223 .flags = IPC_PORT_ALLOW_TA_CONNECT,
224 .uuids = valid_uuids,
225 .uuid_num = countof(valid_uuids),
226 .extra_data = NULL,
227 };
228
229 const static struct ktipc_port test_srv_port = {
230 .name = KTIPC_TEST_SRV_PORT,
231 .uuid = &kernel_uuid,
232 .msg_max_size = KTIPC_TEST_MAX_MSG_SIZE,
233 .msg_queue_len = 1,
234 .acl = &test_srv_port_acl,
235 .priv = NULL,
236 };
237
238 const static struct ktipc_port_acl blocked_srv_port_acl = {
239 .flags = IPC_PORT_ALLOW_TA_CONNECT,
240 .uuids = bad_uuids,
241 .uuid_num = countof(bad_uuids),
242 .extra_data = NULL,
243 };
244
245 const static struct ktipc_port blocked_srv_port = {
246 .name = KTIPC_TEST_SRV_PORT ".blocked",
247 .uuid = &kernel_uuid,
248 .msg_max_size = KTIPC_TEST_MAX_MSG_SIZE,
249 .msg_queue_len = 1,
250 .acl = &blocked_srv_port_acl,
251 .priv = NULL,
252 };
253
254 const static struct ktipc_port_acl connecterr_srv_port_acl = {
255 .flags = IPC_PORT_ALLOW_TA_CONNECT,
256 .uuids = valid_uuids,
257 .uuid_num = countof(valid_uuids),
258 .extra_data = NULL,
259 };
260
261 const static struct ktipc_port connecterr_srv_port = {
262 .name = KTIPC_TEST_SRV_PORT ".connecterr",
263 .uuid = &kernel_uuid,
264 .msg_max_size = KTIPC_TEST_MAX_MSG_SIZE,
265 .msg_queue_len = 1,
266 .acl = &connecterr_srv_port_acl,
267 .priv = NULL,
268 };
269
270 static struct ktipc_server ktipc_test_server =
271 KTIPC_SERVER_INITIAL_VALUE(ktipc_test_server, "ktipc_test_server");
272
ktipc_test_server_init(uint lvl)273 static void ktipc_test_server_init(uint lvl) {
274 int rc;
275
276 rc = ktipc_server_start(&ktipc_test_server);
277 if (rc < 0) {
278 TRACEF("Failed (%d) to start ktipc_test_srv server\n", rc);
279 return;
280 }
281
282 rc = ktipc_server_add_port(&ktipc_test_server, &test_srv_port,
283 &test_srv_ops);
284 if (rc < 0) {
285 TRACEF("Failed (%d) to create echo service port\n", rc);
286 }
287
288 rc = ktipc_server_add_port(&ktipc_test_server, &blocked_srv_port,
289 &test_srv_ops);
290 if (rc < 0) {
291 TRACEF("Failed (%d) to create blocked service port\n", rc);
292 }
293
294 rc = ktipc_server_add_port(&ktipc_test_server, &connecterr_srv_port,
295 &connecterr_srv_ops);
296 if (rc < 0) {
297 TRACEF("Failed (%d) to create connecterr service port\n", rc);
298 }
299 }
300
301 LK_INIT_HOOK(ktipc_test_server_init,
302 ktipc_test_server_init,
303 LK_INIT_LEVEL_APPS - 1)
304