xref: /aosp_15_r20/trusty/kernel/lib/ktipc/ktipc.c (revision 344aa361028b423587d4ef3fa52a23d194628137)
1*344aa361SAndroid Build Coastguard Worker /*
2*344aa361SAndroid Build Coastguard Worker  * Copyright (c) 2020, Google Inc. All rights reserved
3*344aa361SAndroid Build Coastguard Worker  *
4*344aa361SAndroid Build Coastguard Worker  * Permission is hereby granted, free of charge, to any person obtaining
5*344aa361SAndroid Build Coastguard Worker  * a copy of this software and associated documentation files
6*344aa361SAndroid Build Coastguard Worker  * (the "Software"), to deal in the Software without restriction,
7*344aa361SAndroid Build Coastguard Worker  * including without limitation the rights to use, copy, modify, merge,
8*344aa361SAndroid Build Coastguard Worker  * publish, distribute, sublicense, and/or sell copies of the Software,
9*344aa361SAndroid Build Coastguard Worker  * and to permit persons to whom the Software is furnished to do so,
10*344aa361SAndroid Build Coastguard Worker  * subject to the following conditions:
11*344aa361SAndroid Build Coastguard Worker  *
12*344aa361SAndroid Build Coastguard Worker  * The above copyright notice and this permission notice shall be
13*344aa361SAndroid Build Coastguard Worker  * included in all copies or substantial portions of the Software.
14*344aa361SAndroid Build Coastguard Worker  *
15*344aa361SAndroid Build Coastguard Worker  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16*344aa361SAndroid Build Coastguard Worker  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17*344aa361SAndroid Build Coastguard Worker  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18*344aa361SAndroid Build Coastguard Worker  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19*344aa361SAndroid Build Coastguard Worker  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20*344aa361SAndroid Build Coastguard Worker  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21*344aa361SAndroid Build Coastguard Worker  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22*344aa361SAndroid Build Coastguard Worker  */
23*344aa361SAndroid Build Coastguard Worker #include <lib/ktipc/ktipc.h>
24*344aa361SAndroid Build Coastguard Worker 
25*344aa361SAndroid Build Coastguard Worker #include <assert.h>
26*344aa361SAndroid Build Coastguard Worker #include <err.h>
27*344aa361SAndroid Build Coastguard Worker #include <inttypes.h>
28*344aa361SAndroid Build Coastguard Worker #include <kernel/thread.h>
29*344aa361SAndroid Build Coastguard Worker #include <lib/trusty/handle_set.h>
30*344aa361SAndroid Build Coastguard Worker #include <lib/trusty/ipc.h>
31*344aa361SAndroid Build Coastguard Worker #include <lib/trusty/ipc_msg.h>
32*344aa361SAndroid Build Coastguard Worker #include <lk/init.h>
33*344aa361SAndroid Build Coastguard Worker #include <lk/list.h>
34*344aa361SAndroid Build Coastguard Worker #include <string.h>
35*344aa361SAndroid Build Coastguard Worker #include <trace.h>
36*344aa361SAndroid Build Coastguard Worker 
37*344aa361SAndroid Build Coastguard Worker #define LOCAL_TRACE 0
38*344aa361SAndroid Build Coastguard Worker 
39*344aa361SAndroid Build Coastguard Worker struct ksrv_event_handler {
40*344aa361SAndroid Build Coastguard Worker     void (*handler)(struct ktipc_server* ksrv,
41*344aa361SAndroid Build Coastguard Worker                     struct ksrv_event_handler* evth,
42*344aa361SAndroid Build Coastguard Worker                     uint32_t event);
43*344aa361SAndroid Build Coastguard Worker };
44*344aa361SAndroid Build Coastguard Worker 
45*344aa361SAndroid Build Coastguard Worker struct ksrv_port {
46*344aa361SAndroid Build Coastguard Worker     struct handle_ref href;
47*344aa361SAndroid Build Coastguard Worker     struct ksrv_event_handler evth;
48*344aa361SAndroid Build Coastguard Worker     const struct ktipc_srv_ops* ops;
49*344aa361SAndroid Build Coastguard Worker     const struct ktipc_port* port;
50*344aa361SAndroid Build Coastguard Worker };
51*344aa361SAndroid Build Coastguard Worker 
52*344aa361SAndroid Build Coastguard Worker struct ksrv_chan {
53*344aa361SAndroid Build Coastguard Worker     struct handle_ref href;
54*344aa361SAndroid Build Coastguard Worker     struct ksrv_event_handler evth;
55*344aa361SAndroid Build Coastguard Worker     const struct ktipc_srv_ops* ops;
56*344aa361SAndroid Build Coastguard Worker     const struct ktipc_port* port;
57*344aa361SAndroid Build Coastguard Worker     void* user_ctx;
58*344aa361SAndroid Build Coastguard Worker };
59*344aa361SAndroid Build Coastguard Worker 
60*344aa361SAndroid Build Coastguard Worker /*
61*344aa361SAndroid Build Coastguard Worker  * Helper to close channel
62*344aa361SAndroid Build Coastguard Worker  */
ktipc_chan_close(struct ksrv_chan * kchan)63*344aa361SAndroid Build Coastguard Worker static void ktipc_chan_close(struct ksrv_chan* kchan) {
64*344aa361SAndroid Build Coastguard Worker     void* user_ctx = kchan->user_ctx;
65*344aa361SAndroid Build Coastguard Worker     const struct ktipc_srv_ops* ops = kchan->ops;
66*344aa361SAndroid Build Coastguard Worker 
67*344aa361SAndroid Build Coastguard Worker     /* detach handle_ref */
68*344aa361SAndroid Build Coastguard Worker     handle_set_detach_ref(&kchan->href);
69*344aa361SAndroid Build Coastguard Worker 
70*344aa361SAndroid Build Coastguard Worker     /* close channel */
71*344aa361SAndroid Build Coastguard Worker     handle_decref(kchan->href.handle);
72*344aa361SAndroid Build Coastguard Worker 
73*344aa361SAndroid Build Coastguard Worker     /* free memory */
74*344aa361SAndroid Build Coastguard Worker     free(kchan);
75*344aa361SAndroid Build Coastguard Worker 
76*344aa361SAndroid Build Coastguard Worker     /*  cleanup user allocated state if any */
77*344aa361SAndroid Build Coastguard Worker     if (user_ctx) {
78*344aa361SAndroid Build Coastguard Worker         ops->on_channel_cleanup(user_ctx);
79*344aa361SAndroid Build Coastguard Worker     }
80*344aa361SAndroid Build Coastguard Worker }
81*344aa361SAndroid Build Coastguard Worker 
chan_event_handler(struct ktipc_server * ksrv,struct ksrv_event_handler * evth,uint32_t event)82*344aa361SAndroid Build Coastguard Worker static void chan_event_handler(struct ktipc_server* ksrv,
83*344aa361SAndroid Build Coastguard Worker                                struct ksrv_event_handler* evth,
84*344aa361SAndroid Build Coastguard Worker                                uint32_t event) {
85*344aa361SAndroid Build Coastguard Worker     int rc;
86*344aa361SAndroid Build Coastguard Worker 
87*344aa361SAndroid Build Coastguard Worker     struct ksrv_chan* kchan = containerof(evth, struct ksrv_chan, evth);
88*344aa361SAndroid Build Coastguard Worker 
89*344aa361SAndroid Build Coastguard Worker     if ((event & IPC_HANDLE_POLL_ERROR) || (event & IPC_HANDLE_POLL_READY)) {
90*344aa361SAndroid Build Coastguard Worker         /* should never happen for channel handles */
91*344aa361SAndroid Build Coastguard Worker         TRACEF("error event (0x%" PRIx32 ")\n", event);
92*344aa361SAndroid Build Coastguard Worker         ktipc_chan_close(kchan);
93*344aa361SAndroid Build Coastguard Worker         return;
94*344aa361SAndroid Build Coastguard Worker     }
95*344aa361SAndroid Build Coastguard Worker 
96*344aa361SAndroid Build Coastguard Worker     if (event & IPC_HANDLE_POLL_MSG) {
97*344aa361SAndroid Build Coastguard Worker         LTRACEF("got message\n");
98*344aa361SAndroid Build Coastguard Worker 
99*344aa361SAndroid Build Coastguard Worker         rc = kchan->ops->on_message(kchan->port, kchan->href.handle,
100*344aa361SAndroid Build Coastguard Worker                                     kchan->user_ctx);
101*344aa361SAndroid Build Coastguard Worker         if (rc < 0) {
102*344aa361SAndroid Build Coastguard Worker             /* report an error and close channel */
103*344aa361SAndroid Build Coastguard Worker             TRACEF("failed (%d) to handle event on channel %p\n", rc,
104*344aa361SAndroid Build Coastguard Worker                    kchan->href.handle);
105*344aa361SAndroid Build Coastguard Worker             ktipc_chan_close(kchan);
106*344aa361SAndroid Build Coastguard Worker             return;
107*344aa361SAndroid Build Coastguard Worker         }
108*344aa361SAndroid Build Coastguard Worker     }
109*344aa361SAndroid Build Coastguard Worker 
110*344aa361SAndroid Build Coastguard Worker     if (event & IPC_HANDLE_POLL_HUP) {
111*344aa361SAndroid Build Coastguard Worker         LTRACEF("connection closed by peer\n");
112*344aa361SAndroid Build Coastguard Worker 
113*344aa361SAndroid Build Coastguard Worker         /* closed by peer. */
114*344aa361SAndroid Build Coastguard Worker         if (kchan->ops->on_disconnect) {
115*344aa361SAndroid Build Coastguard Worker             kchan->ops->on_disconnect(kchan->port, kchan->href.handle,
116*344aa361SAndroid Build Coastguard Worker                                       kchan->user_ctx);
117*344aa361SAndroid Build Coastguard Worker         }
118*344aa361SAndroid Build Coastguard Worker         ktipc_chan_close(kchan);
119*344aa361SAndroid Build Coastguard Worker         return;
120*344aa361SAndroid Build Coastguard Worker     }
121*344aa361SAndroid Build Coastguard Worker 
122*344aa361SAndroid Build Coastguard Worker     if (event & IPC_HANDLE_POLL_SEND_UNBLOCKED) {
123*344aa361SAndroid Build Coastguard Worker         LTRACEF("unblocked for sending\n");
124*344aa361SAndroid Build Coastguard Worker 
125*344aa361SAndroid Build Coastguard Worker         if (kchan->ops->on_send_unblocked) {
126*344aa361SAndroid Build Coastguard Worker             rc = kchan->ops->on_send_unblocked(kchan->port, kchan->href.handle,
127*344aa361SAndroid Build Coastguard Worker                                                kchan->user_ctx);
128*344aa361SAndroid Build Coastguard Worker             if (rc < 0) {
129*344aa361SAndroid Build Coastguard Worker                 /* report an error and close channel */
130*344aa361SAndroid Build Coastguard Worker                 TRACEF("failed (%d) to handle event on channel %p\n", rc,
131*344aa361SAndroid Build Coastguard Worker                        kchan->href.handle);
132*344aa361SAndroid Build Coastguard Worker                 ktipc_chan_close(kchan);
133*344aa361SAndroid Build Coastguard Worker                 return;
134*344aa361SAndroid Build Coastguard Worker             }
135*344aa361SAndroid Build Coastguard Worker         } else {
136*344aa361SAndroid Build Coastguard Worker             LTRACEF("send-unblocking not handled for channel %p\n",
137*344aa361SAndroid Build Coastguard Worker                     kchan->href.handle);
138*344aa361SAndroid Build Coastguard Worker             ktipc_chan_close(kchan);
139*344aa361SAndroid Build Coastguard Worker             return;
140*344aa361SAndroid Build Coastguard Worker         }
141*344aa361SAndroid Build Coastguard Worker     }
142*344aa361SAndroid Build Coastguard Worker }
143*344aa361SAndroid Build Coastguard Worker 
144*344aa361SAndroid Build Coastguard Worker /*
145*344aa361SAndroid Build Coastguard Worker  *  Check if client is allowed to connect on specified port
146*344aa361SAndroid Build Coastguard Worker  */
client_is_allowed(const struct ktipc_port_acl * acl,const struct uuid * peer)147*344aa361SAndroid Build Coastguard Worker static bool client_is_allowed(const struct ktipc_port_acl* acl,
148*344aa361SAndroid Build Coastguard Worker                               const struct uuid* peer) {
149*344aa361SAndroid Build Coastguard Worker     uint32_t i;
150*344aa361SAndroid Build Coastguard Worker 
151*344aa361SAndroid Build Coastguard Worker     if (!acl->uuid_num)
152*344aa361SAndroid Build Coastguard Worker         return true;
153*344aa361SAndroid Build Coastguard Worker 
154*344aa361SAndroid Build Coastguard Worker     for (i = 0; i < acl->uuid_num; i++) {
155*344aa361SAndroid Build Coastguard Worker         if (memcmp(peer, acl->uuids[i], sizeof(*peer)) == 0) {
156*344aa361SAndroid Build Coastguard Worker             /* match */
157*344aa361SAndroid Build Coastguard Worker             return true;
158*344aa361SAndroid Build Coastguard Worker         }
159*344aa361SAndroid Build Coastguard Worker     }
160*344aa361SAndroid Build Coastguard Worker 
161*344aa361SAndroid Build Coastguard Worker     return false;
162*344aa361SAndroid Build Coastguard Worker }
163*344aa361SAndroid Build Coastguard Worker 
164*344aa361SAndroid Build Coastguard Worker /*
165*344aa361SAndroid Build Coastguard Worker  *  Handle incoming connection
166*344aa361SAndroid Build Coastguard Worker  */
handle_connect(struct ktipc_server * ksrv,struct ksrv_port * kport)167*344aa361SAndroid Build Coastguard Worker static void handle_connect(struct ktipc_server* ksrv, struct ksrv_port* kport) {
168*344aa361SAndroid Build Coastguard Worker     int rc;
169*344aa361SAndroid Build Coastguard Worker     struct handle* hchan;
170*344aa361SAndroid Build Coastguard Worker     const struct uuid* peer;
171*344aa361SAndroid Build Coastguard Worker     void* user_ctx = NULL;
172*344aa361SAndroid Build Coastguard Worker     struct ksrv_chan* kchan;
173*344aa361SAndroid Build Coastguard Worker 
174*344aa361SAndroid Build Coastguard Worker     /* incoming connection: accept it */
175*344aa361SAndroid Build Coastguard Worker     rc = ipc_port_accept(kport->href.handle, &hchan, &peer);
176*344aa361SAndroid Build Coastguard Worker     if (rc < 0) {
177*344aa361SAndroid Build Coastguard Worker         TRACEF("failed (%d) to accept on port %s\n", rc, kport->port->name);
178*344aa361SAndroid Build Coastguard Worker         return;
179*344aa361SAndroid Build Coastguard Worker     }
180*344aa361SAndroid Build Coastguard Worker 
181*344aa361SAndroid Build Coastguard Worker     /* do access control */
182*344aa361SAndroid Build Coastguard Worker     if (!client_is_allowed(kport->port->acl, peer)) {
183*344aa361SAndroid Build Coastguard Worker         TRACEF("access denied on port %s\n", kport->port->name);
184*344aa361SAndroid Build Coastguard Worker         goto err_access;
185*344aa361SAndroid Build Coastguard Worker     }
186*344aa361SAndroid Build Coastguard Worker 
187*344aa361SAndroid Build Coastguard Worker     kchan = calloc(1, sizeof(*kchan));
188*344aa361SAndroid Build Coastguard Worker     if (!kchan) {
189*344aa361SAndroid Build Coastguard Worker         TRACEF("oom handling connect on port %s\n", kport->port->name);
190*344aa361SAndroid Build Coastguard Worker         goto err_oom;
191*344aa361SAndroid Build Coastguard Worker     }
192*344aa361SAndroid Build Coastguard Worker 
193*344aa361SAndroid Build Coastguard Worker     /* setup channel structure */
194*344aa361SAndroid Build Coastguard Worker     kchan->evth.handler = chan_event_handler;
195*344aa361SAndroid Build Coastguard Worker     kchan->port = kport->port;
196*344aa361SAndroid Build Coastguard Worker     kchan->ops = kport->ops;
197*344aa361SAndroid Build Coastguard Worker 
198*344aa361SAndroid Build Coastguard Worker     /* add new channel to handle set */
199*344aa361SAndroid Build Coastguard Worker     kchan->href.emask = ~0U;
200*344aa361SAndroid Build Coastguard Worker     kchan->href.cookie = &kchan->evth;
201*344aa361SAndroid Build Coastguard Worker     kchan->href.handle = hchan;
202*344aa361SAndroid Build Coastguard Worker 
203*344aa361SAndroid Build Coastguard Worker     rc = handle_set_attach(ksrv->hset, &kchan->href);
204*344aa361SAndroid Build Coastguard Worker     if (rc != NO_ERROR) {
205*344aa361SAndroid Build Coastguard Worker         TRACEF("failed (%d) to add chan to hset\n", rc);
206*344aa361SAndroid Build Coastguard Worker         goto err_hset_add;
207*344aa361SAndroid Build Coastguard Worker     }
208*344aa361SAndroid Build Coastguard Worker 
209*344aa361SAndroid Build Coastguard Worker     /* invoke on_connect handler if any */
210*344aa361SAndroid Build Coastguard Worker     if (kport->ops->on_connect) {
211*344aa361SAndroid Build Coastguard Worker         rc = kport->ops->on_connect(kport->port, hchan, peer, &user_ctx);
212*344aa361SAndroid Build Coastguard Worker         if (rc < 0) {
213*344aa361SAndroid Build Coastguard Worker             TRACEF("on_connect failed (%d) on port %s\n", rc,
214*344aa361SAndroid Build Coastguard Worker                    kport->port->name);
215*344aa361SAndroid Build Coastguard Worker             goto err_on_connect;
216*344aa361SAndroid Build Coastguard Worker         }
217*344aa361SAndroid Build Coastguard Worker     }
218*344aa361SAndroid Build Coastguard Worker 
219*344aa361SAndroid Build Coastguard Worker     /* attach context provided by caller */
220*344aa361SAndroid Build Coastguard Worker     kchan->user_ctx = user_ctx;
221*344aa361SAndroid Build Coastguard Worker 
222*344aa361SAndroid Build Coastguard Worker     return;
223*344aa361SAndroid Build Coastguard Worker 
224*344aa361SAndroid Build Coastguard Worker err_on_connect:
225*344aa361SAndroid Build Coastguard Worker     handle_set_detach_ref(&kchan->href);
226*344aa361SAndroid Build Coastguard Worker err_hset_add:
227*344aa361SAndroid Build Coastguard Worker     free(kchan);
228*344aa361SAndroid Build Coastguard Worker err_oom:
229*344aa361SAndroid Build Coastguard Worker err_access:
230*344aa361SAndroid Build Coastguard Worker     handle_decref(hchan);
231*344aa361SAndroid Build Coastguard Worker }
232*344aa361SAndroid Build Coastguard Worker 
port_event_handler(struct ktipc_server * ksrv,struct ksrv_event_handler * evth,uint32_t event)233*344aa361SAndroid Build Coastguard Worker static void port_event_handler(struct ktipc_server* ksrv,
234*344aa361SAndroid Build Coastguard Worker                                struct ksrv_event_handler* evth,
235*344aa361SAndroid Build Coastguard Worker                                uint32_t event) {
236*344aa361SAndroid Build Coastguard Worker     struct ksrv_port* kport = containerof(evth, struct ksrv_port, evth);
237*344aa361SAndroid Build Coastguard Worker 
238*344aa361SAndroid Build Coastguard Worker     if ((event & IPC_HANDLE_POLL_ERROR) || (event & IPC_HANDLE_POLL_HUP) ||
239*344aa361SAndroid Build Coastguard Worker         (event & IPC_HANDLE_POLL_MSG) ||
240*344aa361SAndroid Build Coastguard Worker         (event & IPC_HANDLE_POLL_SEND_UNBLOCKED)) {
241*344aa361SAndroid Build Coastguard Worker         /* should never happen with port handles */
242*344aa361SAndroid Build Coastguard Worker         LTRACEF("error event (0x%" PRIx32 ") for port\n", event);
243*344aa361SAndroid Build Coastguard Worker         return;
244*344aa361SAndroid Build Coastguard Worker     }
245*344aa361SAndroid Build Coastguard Worker 
246*344aa361SAndroid Build Coastguard Worker     if (event & IPC_HANDLE_POLL_READY) {
247*344aa361SAndroid Build Coastguard Worker         handle_connect(ksrv, kport);
248*344aa361SAndroid Build Coastguard Worker     }
249*344aa361SAndroid Build Coastguard Worker }
250*344aa361SAndroid Build Coastguard Worker 
ktipc_server_add_port(struct ktipc_server * ksrv,const struct ktipc_port * port,const struct ktipc_srv_ops * ops)251*344aa361SAndroid Build Coastguard Worker int ktipc_server_add_port(struct ktipc_server* ksrv,
252*344aa361SAndroid Build Coastguard Worker                           const struct ktipc_port* port,
253*344aa361SAndroid Build Coastguard Worker                           const struct ktipc_srv_ops* ops) {
254*344aa361SAndroid Build Coastguard Worker     int rc;
255*344aa361SAndroid Build Coastguard Worker     struct ksrv_port* kport;
256*344aa361SAndroid Build Coastguard Worker 
257*344aa361SAndroid Build Coastguard Worker     if (!ksrv) {
258*344aa361SAndroid Build Coastguard Worker         rc = ERR_INVALID_ARGS;
259*344aa361SAndroid Build Coastguard Worker         goto err_null_ksrv;
260*344aa361SAndroid Build Coastguard Worker     }
261*344aa361SAndroid Build Coastguard Worker 
262*344aa361SAndroid Build Coastguard Worker     /* validate ops structure */
263*344aa361SAndroid Build Coastguard Worker     if (!ops) {
264*344aa361SAndroid Build Coastguard Worker         TRACEF("ktipc_srv_ops structure is NULL\n");
265*344aa361SAndroid Build Coastguard Worker         rc = ERR_INVALID_ARGS;
266*344aa361SAndroid Build Coastguard Worker         goto err_null_ops;
267*344aa361SAndroid Build Coastguard Worker     }
268*344aa361SAndroid Build Coastguard Worker     if (!ops->on_message) {
269*344aa361SAndroid Build Coastguard Worker         TRACEF("on_message handler is NULL\n");
270*344aa361SAndroid Build Coastguard Worker         rc = ERR_INVALID_ARGS;
271*344aa361SAndroid Build Coastguard Worker         goto err_null_on_message;
272*344aa361SAndroid Build Coastguard Worker     }
273*344aa361SAndroid Build Coastguard Worker     /* on_channel_cleanup is required if on_connect is present */
274*344aa361SAndroid Build Coastguard Worker     if (ops->on_connect && !ops->on_channel_cleanup) {
275*344aa361SAndroid Build Coastguard Worker         TRACEF("on_connect handler without on_channel_cleanup\n");
276*344aa361SAndroid Build Coastguard Worker         rc = ERR_INVALID_ARGS;
277*344aa361SAndroid Build Coastguard Worker         goto err_null_on_channel_cleanup;
278*344aa361SAndroid Build Coastguard Worker     }
279*344aa361SAndroid Build Coastguard Worker 
280*344aa361SAndroid Build Coastguard Worker     /* allocate port tracking structure */
281*344aa361SAndroid Build Coastguard Worker     kport = calloc(1, sizeof(*kport));
282*344aa361SAndroid Build Coastguard Worker     if (!kport) {
283*344aa361SAndroid Build Coastguard Worker         TRACEF("failed to allocate port\n");
284*344aa361SAndroid Build Coastguard Worker         rc = ERR_NO_MEMORY;
285*344aa361SAndroid Build Coastguard Worker         goto err_oom;
286*344aa361SAndroid Build Coastguard Worker     }
287*344aa361SAndroid Build Coastguard Worker 
288*344aa361SAndroid Build Coastguard Worker     /* create port */
289*344aa361SAndroid Build Coastguard Worker     rc = ipc_port_create(port->uuid, port->name, port->msg_queue_len,
290*344aa361SAndroid Build Coastguard Worker                          port->msg_max_size, port->acl->flags,
291*344aa361SAndroid Build Coastguard Worker                          &kport->href.handle);
292*344aa361SAndroid Build Coastguard Worker     if (rc) {
293*344aa361SAndroid Build Coastguard Worker         TRACEF("failed (%d) to create port %s\n", rc, port->name);
294*344aa361SAndroid Build Coastguard Worker         goto err_port_create;
295*344aa361SAndroid Build Coastguard Worker     }
296*344aa361SAndroid Build Coastguard Worker 
297*344aa361SAndroid Build Coastguard Worker     /* and publish it */
298*344aa361SAndroid Build Coastguard Worker     rc = ipc_port_publish(kport->href.handle);
299*344aa361SAndroid Build Coastguard Worker     if (rc) {
300*344aa361SAndroid Build Coastguard Worker         TRACEF("failed (%d) to publish port %s\n", rc, port->name);
301*344aa361SAndroid Build Coastguard Worker         goto err_port_publish;
302*344aa361SAndroid Build Coastguard Worker     }
303*344aa361SAndroid Build Coastguard Worker 
304*344aa361SAndroid Build Coastguard Worker     /* configure port event handler */
305*344aa361SAndroid Build Coastguard Worker     kport->evth.handler = port_event_handler;
306*344aa361SAndroid Build Coastguard Worker     kport->port = port;
307*344aa361SAndroid Build Coastguard Worker     kport->ops = ops;
308*344aa361SAndroid Build Coastguard Worker 
309*344aa361SAndroid Build Coastguard Worker     /* attach it to handle set */
310*344aa361SAndroid Build Coastguard Worker     kport->href.emask = ~0U;
311*344aa361SAndroid Build Coastguard Worker     kport->href.cookie = &kport->evth;
312*344aa361SAndroid Build Coastguard Worker 
313*344aa361SAndroid Build Coastguard Worker     rc = handle_set_attach(ksrv->hset, &kport->href);
314*344aa361SAndroid Build Coastguard Worker     if (rc < 0) {
315*344aa361SAndroid Build Coastguard Worker         TRACEF("failed (%d) to attach handle for port %s\n", rc, port->name);
316*344aa361SAndroid Build Coastguard Worker         goto err_hset_add_port;
317*344aa361SAndroid Build Coastguard Worker     }
318*344aa361SAndroid Build Coastguard Worker 
319*344aa361SAndroid Build Coastguard Worker     /* kick have handles event */
320*344aa361SAndroid Build Coastguard Worker     event_signal(&ksrv->have_handles_evt, false);
321*344aa361SAndroid Build Coastguard Worker 
322*344aa361SAndroid Build Coastguard Worker     return 0;
323*344aa361SAndroid Build Coastguard Worker 
324*344aa361SAndroid Build Coastguard Worker err_hset_add_port:
325*344aa361SAndroid Build Coastguard Worker err_port_publish:
326*344aa361SAndroid Build Coastguard Worker     handle_decref(kport->href.handle);
327*344aa361SAndroid Build Coastguard Worker err_port_create:
328*344aa361SAndroid Build Coastguard Worker     free(kport);
329*344aa361SAndroid Build Coastguard Worker err_oom:
330*344aa361SAndroid Build Coastguard Worker err_null_on_channel_cleanup:
331*344aa361SAndroid Build Coastguard Worker err_null_on_message:
332*344aa361SAndroid Build Coastguard Worker err_null_ops:
333*344aa361SAndroid Build Coastguard Worker err_null_ksrv:
334*344aa361SAndroid Build Coastguard Worker     return rc;
335*344aa361SAndroid Build Coastguard Worker }
336*344aa361SAndroid Build Coastguard Worker 
ksrv_event_loop(struct ktipc_server * ksrv)337*344aa361SAndroid Build Coastguard Worker static void ksrv_event_loop(struct ktipc_server* ksrv) {
338*344aa361SAndroid Build Coastguard Worker     int rc;
339*344aa361SAndroid Build Coastguard Worker     struct handle_ref evt_ref;
340*344aa361SAndroid Build Coastguard Worker 
341*344aa361SAndroid Build Coastguard Worker     while (true) {
342*344aa361SAndroid Build Coastguard Worker         /* wait here until we have handles */
343*344aa361SAndroid Build Coastguard Worker         event_wait(&ksrv->have_handles_evt);
344*344aa361SAndroid Build Coastguard Worker         while (true) {
345*344aa361SAndroid Build Coastguard Worker             rc = handle_set_wait(ksrv->hset, &evt_ref, INFINITE_TIME);
346*344aa361SAndroid Build Coastguard Worker             if (rc != NO_ERROR) {
347*344aa361SAndroid Build Coastguard Worker                 panic("handle_set_wait failed: %d\n", rc);
348*344aa361SAndroid Build Coastguard Worker             }
349*344aa361SAndroid Build Coastguard Worker 
350*344aa361SAndroid Build Coastguard Worker             /* get handler and invoke it */
351*344aa361SAndroid Build Coastguard Worker             struct ksrv_event_handler* evth = evt_ref.cookie;
352*344aa361SAndroid Build Coastguard Worker             DEBUG_ASSERT(evth && evth->handler);
353*344aa361SAndroid Build Coastguard Worker             evth->handler(ksrv, evth, evt_ref.emask);
354*344aa361SAndroid Build Coastguard Worker 
355*344aa361SAndroid Build Coastguard Worker             /* decrement ref obtained by handle_set_wait */
356*344aa361SAndroid Build Coastguard Worker             handle_decref(evt_ref.handle);
357*344aa361SAndroid Build Coastguard Worker         }
358*344aa361SAndroid Build Coastguard Worker     }
359*344aa361SAndroid Build Coastguard Worker }
360*344aa361SAndroid Build Coastguard Worker 
ksrv_thread(void * args)361*344aa361SAndroid Build Coastguard Worker static int ksrv_thread(void* args) {
362*344aa361SAndroid Build Coastguard Worker     struct ktipc_server* ksrv = args;
363*344aa361SAndroid Build Coastguard Worker 
364*344aa361SAndroid Build Coastguard Worker     LTRACEF("starting ktipc service: %s\n", ksrv->name);
365*344aa361SAndroid Build Coastguard Worker 
366*344aa361SAndroid Build Coastguard Worker     ksrv->hset = handle_set_create();
367*344aa361SAndroid Build Coastguard Worker     if (!ksrv->hset) {
368*344aa361SAndroid Build Coastguard Worker         TRACEF("failed to create handle set\n");
369*344aa361SAndroid Build Coastguard Worker         return ERR_NO_MEMORY;
370*344aa361SAndroid Build Coastguard Worker     }
371*344aa361SAndroid Build Coastguard Worker 
372*344aa361SAndroid Build Coastguard Worker     /* enter event loop */
373*344aa361SAndroid Build Coastguard Worker     ksrv_event_loop(ksrv);
374*344aa361SAndroid Build Coastguard Worker     LTRACEF("event loop returned\n");
375*344aa361SAndroid Build Coastguard Worker 
376*344aa361SAndroid Build Coastguard Worker     /* kill handle set */
377*344aa361SAndroid Build Coastguard Worker     handle_decref(ksrv->hset);
378*344aa361SAndroid Build Coastguard Worker     return 0;
379*344aa361SAndroid Build Coastguard Worker }
380*344aa361SAndroid Build Coastguard Worker 
ktipc_server_start(struct ktipc_server * ksrv)381*344aa361SAndroid Build Coastguard Worker int ktipc_server_start(struct ktipc_server* ksrv) {
382*344aa361SAndroid Build Coastguard Worker     DEBUG_ASSERT(ksrv);
383*344aa361SAndroid Build Coastguard Worker     DEBUG_ASSERT(!ksrv->thread);
384*344aa361SAndroid Build Coastguard Worker 
385*344aa361SAndroid Build Coastguard Worker     ksrv->thread = thread_create(ksrv->name, ksrv_thread, ksrv,
386*344aa361SAndroid Build Coastguard Worker                                  DEFAULT_PRIORITY, DEFAULT_STACK_SIZE);
387*344aa361SAndroid Build Coastguard Worker     if (!ksrv->thread) {
388*344aa361SAndroid Build Coastguard Worker         TRACEF("failed to create %s thread\n", ksrv->name);
389*344aa361SAndroid Build Coastguard Worker         return ERR_NO_MEMORY;
390*344aa361SAndroid Build Coastguard Worker     }
391*344aa361SAndroid Build Coastguard Worker     thread_resume(ksrv->thread);
392*344aa361SAndroid Build Coastguard Worker     return 0;
393*344aa361SAndroid Build Coastguard Worker }
394*344aa361SAndroid Build Coastguard Worker 
ktipc_recv_iov(struct handle * chan,size_t min_sz,struct iovec_kern * iov,uint32_t num_iov,struct handle ** handles,uint32_t num_handles)395*344aa361SAndroid Build Coastguard Worker int ktipc_recv_iov(struct handle* chan,
396*344aa361SAndroid Build Coastguard Worker                    size_t min_sz,
397*344aa361SAndroid Build Coastguard Worker                    struct iovec_kern* iov,
398*344aa361SAndroid Build Coastguard Worker                    uint32_t num_iov,
399*344aa361SAndroid Build Coastguard Worker                    struct handle** handles,
400*344aa361SAndroid Build Coastguard Worker                    uint32_t num_handles) {
401*344aa361SAndroid Build Coastguard Worker     int rc;
402*344aa361SAndroid Build Coastguard Worker     struct ipc_msg_info msg_inf;
403*344aa361SAndroid Build Coastguard Worker     size_t max_sz = 0;
404*344aa361SAndroid Build Coastguard Worker 
405*344aa361SAndroid Build Coastguard Worker     rc = ipc_get_msg(chan, &msg_inf);
406*344aa361SAndroid Build Coastguard Worker     if (rc) {
407*344aa361SAndroid Build Coastguard Worker         return rc;
408*344aa361SAndroid Build Coastguard Worker     }
409*344aa361SAndroid Build Coastguard Worker 
410*344aa361SAndroid Build Coastguard Worker     for (uint32_t i = 0; i < num_iov; i++) {
411*344aa361SAndroid Build Coastguard Worker         max_sz += iov[i].iov_len;
412*344aa361SAndroid Build Coastguard Worker     }
413*344aa361SAndroid Build Coastguard Worker 
414*344aa361SAndroid Build Coastguard Worker     if (msg_inf.len < min_sz || msg_inf.len > max_sz) {
415*344aa361SAndroid Build Coastguard Worker         /* unexpected msg size: buffer too small or too big */
416*344aa361SAndroid Build Coastguard Worker         rc = ERR_BAD_LEN;
417*344aa361SAndroid Build Coastguard Worker     } else {
418*344aa361SAndroid Build Coastguard Worker         struct ipc_msg_kern msg = {
419*344aa361SAndroid Build Coastguard Worker                 .iov = iov,
420*344aa361SAndroid Build Coastguard Worker                 .num_iov = num_iov,
421*344aa361SAndroid Build Coastguard Worker                 .handles = handles,
422*344aa361SAndroid Build Coastguard Worker                 .num_handles = num_handles,
423*344aa361SAndroid Build Coastguard Worker         };
424*344aa361SAndroid Build Coastguard Worker         rc = ipc_read_msg(chan, msg_inf.id, 0, &msg);
425*344aa361SAndroid Build Coastguard Worker     }
426*344aa361SAndroid Build Coastguard Worker 
427*344aa361SAndroid Build Coastguard Worker     ipc_put_msg(chan, msg_inf.id);
428*344aa361SAndroid Build Coastguard Worker     return rc;
429*344aa361SAndroid Build Coastguard Worker }
430