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.h"
6#include "mos/filesystem/vfs_types.h"
7#include "mos/ipc/ipc.h"
8#include "mos/ipc/ipc_io.h"
9#include "mos/mm/slab_autoinit.h"
10#include "mos/platform/platform.h"
11#include "mos/tasks/process.h"
12
13#include <mos_stdlib.h>
14#include <mos_string.h>
15
16typedef struct
17{
18 bool server_control_file;
19 ipc_server_t *server;
20 ipc_t *client_ipc;
21} ipc_vfs_private_t;
22
23slab_t *ipc_vfs_private_slab = NULL;
24SLAB_AUTOINIT("ipc_vfs_private", ipc_vfs_private_slab, ipc_vfs_private_t);
25
26static bool vfs_open_ipc(inode_t *ino, file_t *file, bool created)
27{
28 MOS_UNUSED(ino);
29
30 ipc_t *ipc = NULL;
31 ipc_server_t *server = NULL;
32
33 if (created)
34 {
35 server = ipc_get_server(name: file->dentry->name);
36 MOS_ASSERT(server);
37 }
38 else
39 {
40 ipc = ipc_connect_to_server(name: file->dentry->name, MOS_PAGE_SIZE);
41 if (IS_ERR(ptr: ipc))
42 return false;
43 }
44
45 ipc_vfs_private_t *private = kmalloc(ipc_vfs_private_slab);
46 private->server_control_file = created;
47 private->client_ipc = ipc;
48 private->server = server;
49
50 file->private_data = private;
51 return true;
52}
53
54static ssize_t vfs_ipc_file_read(const file_t *file, void *buf, size_t size, off_t offset)
55{
56 MOS_UNUSED(offset);
57
58 ipc_vfs_private_t *private = file->private_data;
59 if (private->server_control_file)
60 {
61 // reading from the server's control file accepts and returns a new connection, as a fd
62 if (size < sizeof(fd_t))
63 return -EINVAL;
64
65 ipc_t *ipc = ipc_server_accept(server: private->server);
66 if (IS_ERR(ptr: ipc))
67 return PTR_ERR(ptr: ipc);
68
69 ipc_conn_io_t *connio = ipc_conn_io_create(ipc, is_server_side: true);
70 if (IS_ERR(ptr: connio))
71 return PTR_ERR(ptr: connio);
72
73 const fd_t fd = process_attach_ref_fd(current_process, file: &connio->io, flags: FD_FLAGS_NONE);
74 if (IS_ERR_VALUE(fd))
75 return fd;
76
77 // return the fd to the client
78 memcpy(dest: buf, src: &fd, n: sizeof(fd_t));
79 return sizeof(fd_t);
80 }
81 else
82 {
83 return ipc_client_read(ipc: private->client_ipc, buffer: buf, size);
84 }
85}
86
87static ssize_t vfs_ipc_file_write(const file_t *file, const void *buf, size_t size, off_t offset)
88{
89 MOS_UNUSED(offset);
90 ipc_vfs_private_t *private = file->private_data;
91 if (private->server_control_file)
92 return -EBADF; // writing to the server's control file is not supported
93
94 return ipc_client_write(ipc: private->client_ipc, buffer: buf, size);
95}
96
97static void vfs_ipc_file_release(file_t *file)
98{
99 ipc_vfs_private_t *private = file->private_data;
100 if (private->server_control_file)
101 {
102 ipc_server_close(server: private->server);
103 dentry_detach(dentry: file->dentry);
104 }
105 else
106 ipc_client_close_channel(ipc: private->client_ipc);
107 kfree(ptr: private);
108}
109
110const file_ops_t ipc_sysfs_file_ops = {
111 .open = vfs_open_ipc,
112 .read = vfs_ipc_file_read,
113 .write = vfs_ipc_file_write,
114 .release = vfs_ipc_file_release,
115};
116