1// SPDX-License-Identifier: GPL-3.0-or-later
2// io_t wrapper for IPC channels
3
4#include "mos/ipc/ipc_io.h"
5
6#include "mos/io/io.h"
7#include "mos/ipc/ipc.h"
8#include "mos/mm/slab_autoinit.h"
9#include "mos/platform/platform.h"
10
11#include <mos_stdlib.h>
12
13typedef struct _ipc_server_io
14{
15 io_t control_io;
16 ipc_server_t *server;
17} ipc_server_io_t;
18
19static slab_t *ipc_server_io_slab = NULL;
20SLAB_AUTOINIT("ipc_server_io", ipc_server_io_slab, ipc_server_io_t);
21
22static slab_t *ipc_conn_io_slab = NULL;
23SLAB_AUTOINIT("ipc_conn_io", ipc_conn_io_slab, ipc_conn_io_t);
24
25static void ipc_control_io_close(io_t *io)
26{
27 if (io->type != IO_IPC)
28 mos_panic("ipc_control_io_close: io->type != IO_IPC"); // handle error cases in io_close
29
30 // we only deannounce the server, we don't free it
31 ipc_server_io_t *server_io = container_of(io, ipc_server_io_t, control_io);
32 ipc_server_close(server: server_io->server);
33 kfree(ptr: server_io);
34}
35
36static const io_op_t ipc_control_io_op = {
37 .close = ipc_control_io_close,
38};
39
40static size_t ipc_client_io_write(io_t *io, const void *buf, size_t size)
41{
42 ipc_conn_io_t *conn = container_of(io, ipc_conn_io_t, io);
43 return ipc_client_write(ipc: conn->ipc, buffer: buf, size);
44}
45
46static size_t ipc_client_io_read(io_t *io, void *buf, size_t size)
47{
48 ipc_conn_io_t *conn = container_of(io, ipc_conn_io_t, io);
49 return ipc_client_read(ipc: conn->ipc, buffer: buf, size);
50}
51
52static void ipc_client_io_close(io_t *io)
53{
54 if (io->type != IO_IPC)
55 mos_panic("ipc_client_io_close: io->type != IO_IPC"); // handle error cases in io_close
56
57 ipc_conn_io_t *conn = container_of(io, ipc_conn_io_t, io);
58 ipc_client_close_channel(ipc: conn->ipc);
59 kfree(ptr: conn);
60}
61
62static size_t ipc_server_io_write(io_t *io, const void *buf, size_t size)
63{
64 ipc_conn_io_t *conn = container_of(io, ipc_conn_io_t, io);
65 return ipc_server_write(ipc: conn->ipc, buffer: buf, size);
66}
67
68static size_t ipc_server_io_read(io_t *io, void *buf, size_t size)
69{
70 ipc_conn_io_t *conn = container_of(io, ipc_conn_io_t, io);
71 return ipc_server_read(ipc: conn->ipc, buffer: buf, size);
72}
73
74static void ipc_server_io_close(io_t *io)
75{
76 if (io->type != IO_IPC)
77 mos_panic("ipc_server_io_close: io->type != IO_IPC"); // handle error cases in io_close
78
79 ipc_conn_io_t *conn = container_of(io, ipc_conn_io_t, io);
80 ipc_server_close_channel(ipc: conn->ipc);
81 kfree(ptr: conn);
82}
83
84static const io_op_t ipc_client_io_op = {
85 .read = ipc_client_io_read,
86 .write = ipc_client_io_write,
87 .close = ipc_client_io_close,
88};
89
90static const io_op_t ipc_server_io_op = {
91 .read = ipc_server_io_read,
92 .write = ipc_server_io_write,
93 .close = ipc_server_io_close,
94};
95
96ipc_conn_io_t *ipc_conn_io_create(ipc_t *ipc, bool is_server_side)
97{
98 ipc_conn_io_t *io = kmalloc(ipc_conn_io_slab);
99 if (IS_ERR(ptr: io))
100 return ERR(ptr: io);
101 io->ipc = ipc;
102 io_init(io: &io->io, type: IO_IPC, flags: IO_READABLE | IO_WRITABLE, ops: is_server_side ? &ipc_server_io_op : &ipc_client_io_op);
103 return io;
104}
105
106io_t *ipc_create(const char *name, size_t max_pending_connections)
107{
108 ipc_server_t *server = ipc_server_create(name, max_pending_connections);
109 if (IS_ERR(ptr: server))
110 return ERR(ptr: server);
111
112 ipc_server_io_t *io = kmalloc(ipc_server_io_slab);
113 if (IS_ERR(ptr: io))
114 return ERR(ptr: io);
115
116 io->server = server;
117 io_init(io: &io->control_io, type: IO_IPC, flags: IO_NONE, ops: &ipc_control_io_op);
118 return &io->control_io;
119}
120
121io_t *ipc_accept(io_t *server)
122{
123 if (server->type != IO_IPC)
124 return ERR_PTR(error: -EBADF); // not an ipc server
125
126 ipc_server_io_t *ipc_server = container_of(server, ipc_server_io_t, control_io);
127 ipc_t *ipc = ipc_server_accept(server: ipc_server->server);
128 if (IS_ERR(ptr: ipc))
129 return ERR(ptr: ipc);
130
131 ipc_conn_io_t *io = ipc_conn_io_create(ipc, is_server_side: true);
132 if (IS_ERR(ptr: io))
133 return ERR(ptr: io);
134
135 return &io->io;
136}
137
138io_t *ipc_connect(const char *name, size_t buffer_size)
139{
140 ipc_t *ipc = ipc_connect_to_server(name, buffer_size);
141 if (IS_ERR(ptr: ipc))
142 return ERR(ptr: ipc);
143
144 ipc_conn_io_t *connio = ipc_conn_io_create(ipc, is_server_side: false);
145 if (IS_ERR(ptr: connio))
146 return ERR(ptr: connio);
147
148 return &connio->io;
149}
150