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 | |
13 | typedef struct _ipc_server_io |
14 | { |
15 | io_t control_io; |
16 | ipc_server_t *server; |
17 | } ipc_server_io_t; |
18 | |
19 | static slab_t *ipc_server_io_slab = NULL; |
20 | SLAB_AUTOINIT("ipc_server_io" , ipc_server_io_slab, ipc_server_io_t); |
21 | |
22 | static slab_t *ipc_conn_io_slab = NULL; |
23 | SLAB_AUTOINIT("ipc_conn_io" , ipc_conn_io_slab, ipc_conn_io_t); |
24 | |
25 | static 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 | |
36 | static const io_op_t ipc_control_io_op = { |
37 | .close = ipc_control_io_close, |
38 | }; |
39 | |
40 | static 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 | |
46 | static 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 | |
52 | static 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 | |
62 | static 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 | |
68 | static 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 | |
74 | static 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 | |
84 | static 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 | |
90 | static 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 | |
96 | ipc_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 | |
106 | io_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 | |
121 | io_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 | |
138 | io_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 | |