xref: /aosp_15_r20/trusty/kernel/lib/ktipc/test/srv/srv.c (revision 344aa361028b423587d4ef3fa52a23d194628137)
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