1// SPDX-License-Identifier: GPL-3.0-or-later
2
3// ! /sys/ipc/<server_name> operations to connect to an IPC server
4
5#include "mos/filesystem/dentry.hpp"
6#include "mos/filesystem/vfs_types.hpp"
7#include "mos/ipc/ipc.hpp"
8#include "mos/ipc/ipc_io.hpp"
9#include "mos/platform/platform.hpp"
10#include "mos/tasks/process.hpp"
11
12#include <mos/allocator.hpp>
13#include <mos_stdlib.hpp>
14#include <mos_string.hpp>
15
16struct ipc_vfs_private_t : mos::NamedType<"IPC_VFS_Private">
17{
18 bool server_control_file;
19 IPCServer *server;
20 IpcDescriptor *client_ipc;
21};
22
23static bool vfs_open_ipc(inode_t *ino, FsBaseFile *file, bool created)
24{
25 MOS_UNUSED(ino);
26
27 IpcDescriptor *ipc = NULL;
28 IPCServer *server = NULL;
29
30 if (created)
31 {
32 const auto result = ipc_get_server(name: file->dentry->name);
33 if (result.isErr())
34 return false;
35 server = result.get();
36 MOS_ASSERT(server);
37 }
38 else
39 {
40 const auto result = ipc_connect_to_server(name: file->dentry->name, MOS_PAGE_SIZE);
41 if (result.isErr())
42 return false;
43 ipc = result.get();
44 MOS_ASSERT(ipc);
45 }
46
47 ipc_vfs_private_t *priv = mos::create<ipc_vfs_private_t>();
48 priv->server_control_file = created;
49 priv->client_ipc = ipc;
50 priv->server = server;
51
52 file->private_data = priv;
53 return true;
54}
55
56static ssize_t vfs_ipc_file_read(const FsBaseFile *file, void *buf, size_t size, off_t offset)
57{
58 MOS_UNUSED(offset);
59
60 ipc_vfs_private_t *priv = (ipc_vfs_private_t *) file->private_data;
61 if (priv->server_control_file)
62 {
63 // reading from the server's control file accepts and returns a new connection, as a fd
64 if (size < sizeof(fd_t))
65 return -EINVAL;
66
67 const auto ipc = ipc_server_accept(server: priv->server);
68 if (ipc.isErr())
69 return ipc.getErr();
70
71 const auto connio = ipc_conn_io_create(ipc: ipc.get(), is_server_side: true);
72 if (connio.isErr())
73 return connio.getErr();
74
75 const fd_t fd = process_attach_ref_fd(current_process, file: connio.get(), flags: FD_FLAGS_NONE);
76 if (IS_ERR_VALUE(fd))
77 return fd;
78
79 // return the fd to the client
80 memcpy(dest: buf, src: &fd, n: sizeof(fd_t));
81 return sizeof(fd_t);
82 }
83 else
84 {
85 return ipc_client_read(ipc: priv->client_ipc, buffer: buf, size);
86 }
87}
88
89static ssize_t vfs_ipc_file_write(const FsBaseFile *file, const void *buf, size_t size, off_t offset)
90{
91 MOS_UNUSED(offset);
92 ipc_vfs_private_t *priv = (ipc_vfs_private_t *) file->private_data;
93 if (priv->server_control_file)
94 return -EBADF; // writing to the server's control file is not supported
95
96 return ipc_client_write(ipc: priv->client_ipc, buffer: buf, size);
97}
98
99static void vfs_ipc_file_release(FsBaseFile *file)
100{
101 ipc_vfs_private_t *priv = (ipc_vfs_private_t *) file->private_data;
102 if (priv->server_control_file)
103 {
104 ipc_server_close(server: priv->server);
105 dentry_detach(dentry: file->dentry);
106 }
107 else
108 ipc_client_close_channel(ipc: priv->client_ipc);
109 delete priv;
110}
111
112const file_ops_t ipc_sysfs_file_ops = {
113 .open = vfs_open_ipc,
114 .read = vfs_ipc_file_read,
115 .write = vfs_ipc_file_write,
116 .release = vfs_ipc_file_release,
117};
118