xref: /linux/fs/smb/server/transport_ipc.c (revision 81a94b27847f7d2e499415db14dd9dc7c22b19b0)
138c8a9a5SSteve French // SPDX-License-Identifier: GPL-2.0-or-later
238c8a9a5SSteve French /*
338c8a9a5SSteve French  *   Copyright (C) 2018 Samsung Electronics Co., Ltd.
438c8a9a5SSteve French  */
538c8a9a5SSteve French 
638c8a9a5SSteve French #include <linux/jhash.h>
738c8a9a5SSteve French #include <linux/slab.h>
838c8a9a5SSteve French #include <linux/rwsem.h>
938c8a9a5SSteve French #include <linux/mutex.h>
1038c8a9a5SSteve French #include <linux/wait.h>
1138c8a9a5SSteve French #include <linux/hashtable.h>
1238c8a9a5SSteve French #include <net/net_namespace.h>
1338c8a9a5SSteve French #include <net/genetlink.h>
1438c8a9a5SSteve French #include <linux/socket.h>
1538c8a9a5SSteve French #include <linux/workqueue.h>
1638c8a9a5SSteve French 
1738c8a9a5SSteve French #include "vfs_cache.h"
1838c8a9a5SSteve French #include "transport_ipc.h"
1938c8a9a5SSteve French #include "server.h"
2038c8a9a5SSteve French #include "smb_common.h"
2138c8a9a5SSteve French 
2238c8a9a5SSteve French #include "mgmt/user_config.h"
2338c8a9a5SSteve French #include "mgmt/share_config.h"
2438c8a9a5SSteve French #include "mgmt/user_session.h"
2538c8a9a5SSteve French #include "mgmt/tree_connect.h"
2638c8a9a5SSteve French #include "mgmt/ksmbd_ida.h"
2738c8a9a5SSteve French #include "connection.h"
2838c8a9a5SSteve French #include "transport_tcp.h"
2938c8a9a5SSteve French #include "transport_rdma.h"
3038c8a9a5SSteve French 
3138c8a9a5SSteve French #define IPC_WAIT_TIMEOUT	(2 * HZ)
3238c8a9a5SSteve French 
3338c8a9a5SSteve French #define IPC_MSG_HASH_BITS	3
3438c8a9a5SSteve French static DEFINE_HASHTABLE(ipc_msg_table, IPC_MSG_HASH_BITS);
3538c8a9a5SSteve French static DECLARE_RWSEM(ipc_msg_table_lock);
3638c8a9a5SSteve French static DEFINE_MUTEX(startup_lock);
3738c8a9a5SSteve French 
3838c8a9a5SSteve French static DEFINE_IDA(ipc_ida);
3938c8a9a5SSteve French 
4038c8a9a5SSteve French static unsigned int ksmbd_tools_pid;
4138c8a9a5SSteve French 
4238c8a9a5SSteve French static bool ksmbd_ipc_validate_version(struct genl_info *m)
4338c8a9a5SSteve French {
4438c8a9a5SSteve French 	if (m->genlhdr->version != KSMBD_GENL_VERSION) {
4538c8a9a5SSteve French 		pr_err("%s. ksmbd: %d, kernel module: %d. %s.\n",
4638c8a9a5SSteve French 		       "Daemon and kernel module version mismatch",
4738c8a9a5SSteve French 		       m->genlhdr->version,
4838c8a9a5SSteve French 		       KSMBD_GENL_VERSION,
4938c8a9a5SSteve French 		       "User-space ksmbd should terminate");
5038c8a9a5SSteve French 		return false;
5138c8a9a5SSteve French 	}
5238c8a9a5SSteve French 	return true;
5338c8a9a5SSteve French }
5438c8a9a5SSteve French 
5538c8a9a5SSteve French struct ksmbd_ipc_msg {
5638c8a9a5SSteve French 	unsigned int		type;
5738c8a9a5SSteve French 	unsigned int		sz;
5838c8a9a5SSteve French 	unsigned char		payload[];
5938c8a9a5SSteve French };
6038c8a9a5SSteve French 
6138c8a9a5SSteve French struct ipc_msg_table_entry {
6238c8a9a5SSteve French 	unsigned int		handle;
6338c8a9a5SSteve French 	unsigned int		type;
6438c8a9a5SSteve French 	wait_queue_head_t	wait;
6538c8a9a5SSteve French 	struct hlist_node	ipc_table_hlist;
6638c8a9a5SSteve French 
6738c8a9a5SSteve French 	void			*response;
6838c8a9a5SSteve French };
6938c8a9a5SSteve French 
7038c8a9a5SSteve French static struct delayed_work ipc_timer_work;
7138c8a9a5SSteve French 
7238c8a9a5SSteve French static int handle_startup_event(struct sk_buff *skb, struct genl_info *info);
7338c8a9a5SSteve French static int handle_unsupported_event(struct sk_buff *skb, struct genl_info *info);
7438c8a9a5SSteve French static int handle_generic_event(struct sk_buff *skb, struct genl_info *info);
7538c8a9a5SSteve French static int ksmbd_ipc_heartbeat_request(void);
7638c8a9a5SSteve French 
7738c8a9a5SSteve French static const struct nla_policy ksmbd_nl_policy[KSMBD_EVENT_MAX] = {
7838c8a9a5SSteve French 	[KSMBD_EVENT_UNSPEC] = {
7938c8a9a5SSteve French 		.len = 0,
8038c8a9a5SSteve French 	},
8138c8a9a5SSteve French 	[KSMBD_EVENT_HEARTBEAT_REQUEST] = {
8238c8a9a5SSteve French 		.len = sizeof(struct ksmbd_heartbeat),
8338c8a9a5SSteve French 	},
8438c8a9a5SSteve French 	[KSMBD_EVENT_STARTING_UP] = {
8538c8a9a5SSteve French 		.len = sizeof(struct ksmbd_startup_request),
8638c8a9a5SSteve French 	},
8738c8a9a5SSteve French 	[KSMBD_EVENT_SHUTTING_DOWN] = {
8838c8a9a5SSteve French 		.len = sizeof(struct ksmbd_shutdown_request),
8938c8a9a5SSteve French 	},
9038c8a9a5SSteve French 	[KSMBD_EVENT_LOGIN_REQUEST] = {
9138c8a9a5SSteve French 		.len = sizeof(struct ksmbd_login_request),
9238c8a9a5SSteve French 	},
9338c8a9a5SSteve French 	[KSMBD_EVENT_LOGIN_RESPONSE] = {
9438c8a9a5SSteve French 		.len = sizeof(struct ksmbd_login_response),
9538c8a9a5SSteve French 	},
9638c8a9a5SSteve French 	[KSMBD_EVENT_SHARE_CONFIG_REQUEST] = {
9738c8a9a5SSteve French 		.len = sizeof(struct ksmbd_share_config_request),
9838c8a9a5SSteve French 	},
9938c8a9a5SSteve French 	[KSMBD_EVENT_SHARE_CONFIG_RESPONSE] = {
10038c8a9a5SSteve French 		.len = sizeof(struct ksmbd_share_config_response),
10138c8a9a5SSteve French 	},
10238c8a9a5SSteve French 	[KSMBD_EVENT_TREE_CONNECT_REQUEST] = {
10338c8a9a5SSteve French 		.len = sizeof(struct ksmbd_tree_connect_request),
10438c8a9a5SSteve French 	},
10538c8a9a5SSteve French 	[KSMBD_EVENT_TREE_CONNECT_RESPONSE] = {
10638c8a9a5SSteve French 		.len = sizeof(struct ksmbd_tree_connect_response),
10738c8a9a5SSteve French 	},
10838c8a9a5SSteve French 	[KSMBD_EVENT_TREE_DISCONNECT_REQUEST] = {
10938c8a9a5SSteve French 		.len = sizeof(struct ksmbd_tree_disconnect_request),
11038c8a9a5SSteve French 	},
11138c8a9a5SSteve French 	[KSMBD_EVENT_LOGOUT_REQUEST] = {
11238c8a9a5SSteve French 		.len = sizeof(struct ksmbd_logout_request),
11338c8a9a5SSteve French 	},
11438c8a9a5SSteve French 	[KSMBD_EVENT_RPC_REQUEST] = {
11538c8a9a5SSteve French 	},
11638c8a9a5SSteve French 	[KSMBD_EVENT_RPC_RESPONSE] = {
11738c8a9a5SSteve French 	},
11838c8a9a5SSteve French 	[KSMBD_EVENT_SPNEGO_AUTHEN_REQUEST] = {
11938c8a9a5SSteve French 	},
12038c8a9a5SSteve French 	[KSMBD_EVENT_SPNEGO_AUTHEN_RESPONSE] = {
12138c8a9a5SSteve French 	},
12238c8a9a5SSteve French };
12338c8a9a5SSteve French 
12438c8a9a5SSteve French static struct genl_ops ksmbd_genl_ops[] = {
12538c8a9a5SSteve French 	{
12638c8a9a5SSteve French 		.cmd	= KSMBD_EVENT_UNSPEC,
12738c8a9a5SSteve French 		.doit	= handle_unsupported_event,
12838c8a9a5SSteve French 	},
12938c8a9a5SSteve French 	{
13038c8a9a5SSteve French 		.cmd	= KSMBD_EVENT_HEARTBEAT_REQUEST,
13138c8a9a5SSteve French 		.doit	= handle_unsupported_event,
13238c8a9a5SSteve French 	},
13338c8a9a5SSteve French 	{
13438c8a9a5SSteve French 		.cmd	= KSMBD_EVENT_STARTING_UP,
13538c8a9a5SSteve French 		.doit	= handle_startup_event,
13638c8a9a5SSteve French 	},
13738c8a9a5SSteve French 	{
13838c8a9a5SSteve French 		.cmd	= KSMBD_EVENT_SHUTTING_DOWN,
13938c8a9a5SSteve French 		.doit	= handle_unsupported_event,
14038c8a9a5SSteve French 	},
14138c8a9a5SSteve French 	{
14238c8a9a5SSteve French 		.cmd	= KSMBD_EVENT_LOGIN_REQUEST,
14338c8a9a5SSteve French 		.doit	= handle_unsupported_event,
14438c8a9a5SSteve French 	},
14538c8a9a5SSteve French 	{
14638c8a9a5SSteve French 		.cmd	= KSMBD_EVENT_LOGIN_RESPONSE,
14738c8a9a5SSteve French 		.doit	= handle_generic_event,
14838c8a9a5SSteve French 	},
14938c8a9a5SSteve French 	{
15038c8a9a5SSteve French 		.cmd	= KSMBD_EVENT_SHARE_CONFIG_REQUEST,
15138c8a9a5SSteve French 		.doit	= handle_unsupported_event,
15238c8a9a5SSteve French 	},
15338c8a9a5SSteve French 	{
15438c8a9a5SSteve French 		.cmd	= KSMBD_EVENT_SHARE_CONFIG_RESPONSE,
15538c8a9a5SSteve French 		.doit	= handle_generic_event,
15638c8a9a5SSteve French 	},
15738c8a9a5SSteve French 	{
15838c8a9a5SSteve French 		.cmd	= KSMBD_EVENT_TREE_CONNECT_REQUEST,
15938c8a9a5SSteve French 		.doit	= handle_unsupported_event,
16038c8a9a5SSteve French 	},
16138c8a9a5SSteve French 	{
16238c8a9a5SSteve French 		.cmd	= KSMBD_EVENT_TREE_CONNECT_RESPONSE,
16338c8a9a5SSteve French 		.doit	= handle_generic_event,
16438c8a9a5SSteve French 	},
16538c8a9a5SSteve French 	{
16638c8a9a5SSteve French 		.cmd	= KSMBD_EVENT_TREE_DISCONNECT_REQUEST,
16738c8a9a5SSteve French 		.doit	= handle_unsupported_event,
16838c8a9a5SSteve French 	},
16938c8a9a5SSteve French 	{
17038c8a9a5SSteve French 		.cmd	= KSMBD_EVENT_LOGOUT_REQUEST,
17138c8a9a5SSteve French 		.doit	= handle_unsupported_event,
17238c8a9a5SSteve French 	},
17338c8a9a5SSteve French 	{
17438c8a9a5SSteve French 		.cmd	= KSMBD_EVENT_RPC_REQUEST,
17538c8a9a5SSteve French 		.doit	= handle_unsupported_event,
17638c8a9a5SSteve French 	},
17738c8a9a5SSteve French 	{
17838c8a9a5SSteve French 		.cmd	= KSMBD_EVENT_RPC_RESPONSE,
17938c8a9a5SSteve French 		.doit	= handle_generic_event,
18038c8a9a5SSteve French 	},
18138c8a9a5SSteve French 	{
18238c8a9a5SSteve French 		.cmd	= KSMBD_EVENT_SPNEGO_AUTHEN_REQUEST,
18338c8a9a5SSteve French 		.doit	= handle_unsupported_event,
18438c8a9a5SSteve French 	},
18538c8a9a5SSteve French 	{
18638c8a9a5SSteve French 		.cmd	= KSMBD_EVENT_SPNEGO_AUTHEN_RESPONSE,
18738c8a9a5SSteve French 		.doit	= handle_generic_event,
18838c8a9a5SSteve French 	},
18938c8a9a5SSteve French };
19038c8a9a5SSteve French 
19138c8a9a5SSteve French static struct genl_family ksmbd_genl_family = {
19238c8a9a5SSteve French 	.name		= KSMBD_GENL_NAME,
19338c8a9a5SSteve French 	.version	= KSMBD_GENL_VERSION,
19438c8a9a5SSteve French 	.hdrsize	= 0,
19538c8a9a5SSteve French 	.maxattr	= KSMBD_EVENT_MAX,
19638c8a9a5SSteve French 	.netnsok	= true,
19738c8a9a5SSteve French 	.module		= THIS_MODULE,
19838c8a9a5SSteve French 	.ops		= ksmbd_genl_ops,
19938c8a9a5SSteve French 	.n_ops		= ARRAY_SIZE(ksmbd_genl_ops),
20038c8a9a5SSteve French 	.resv_start_op	= KSMBD_EVENT_SPNEGO_AUTHEN_RESPONSE + 1,
20138c8a9a5SSteve French };
20238c8a9a5SSteve French 
20338c8a9a5SSteve French static void ksmbd_nl_init_fixup(void)
20438c8a9a5SSteve French {
20538c8a9a5SSteve French 	int i;
20638c8a9a5SSteve French 
20738c8a9a5SSteve French 	for (i = 0; i < ARRAY_SIZE(ksmbd_genl_ops); i++)
20838c8a9a5SSteve French 		ksmbd_genl_ops[i].validate = GENL_DONT_VALIDATE_STRICT |
20938c8a9a5SSteve French 						GENL_DONT_VALIDATE_DUMP;
21038c8a9a5SSteve French 
21138c8a9a5SSteve French 	ksmbd_genl_family.policy = ksmbd_nl_policy;
21238c8a9a5SSteve French }
21338c8a9a5SSteve French 
21438c8a9a5SSteve French static int rpc_context_flags(struct ksmbd_session *sess)
21538c8a9a5SSteve French {
21638c8a9a5SSteve French 	if (user_guest(sess->user))
21738c8a9a5SSteve French 		return KSMBD_RPC_RESTRICTED_CONTEXT;
21838c8a9a5SSteve French 	return 0;
21938c8a9a5SSteve French }
22038c8a9a5SSteve French 
22138c8a9a5SSteve French static void ipc_update_last_active(void)
22238c8a9a5SSteve French {
22338c8a9a5SSteve French 	if (server_conf.ipc_timeout)
22438c8a9a5SSteve French 		server_conf.ipc_last_active = jiffies;
22538c8a9a5SSteve French }
22638c8a9a5SSteve French 
22738c8a9a5SSteve French static struct ksmbd_ipc_msg *ipc_msg_alloc(size_t sz)
22838c8a9a5SSteve French {
22938c8a9a5SSteve French 	struct ksmbd_ipc_msg *msg;
23038c8a9a5SSteve French 	size_t msg_sz = sz + sizeof(struct ksmbd_ipc_msg);
23138c8a9a5SSteve French 
232*81a94b27SNamjae Jeon 	msg = kvzalloc(msg_sz, GFP_KERNEL);
23338c8a9a5SSteve French 	if (msg)
23438c8a9a5SSteve French 		msg->sz = sz;
23538c8a9a5SSteve French 	return msg;
23638c8a9a5SSteve French }
23738c8a9a5SSteve French 
23838c8a9a5SSteve French static void ipc_msg_free(struct ksmbd_ipc_msg *msg)
23938c8a9a5SSteve French {
24038c8a9a5SSteve French 	kvfree(msg);
24138c8a9a5SSteve French }
24238c8a9a5SSteve French 
24338c8a9a5SSteve French static void ipc_msg_handle_free(int handle)
24438c8a9a5SSteve French {
24538c8a9a5SSteve French 	if (handle >= 0)
24638c8a9a5SSteve French 		ksmbd_release_id(&ipc_ida, handle);
24738c8a9a5SSteve French }
24838c8a9a5SSteve French 
24938c8a9a5SSteve French static int handle_response(int type, void *payload, size_t sz)
25038c8a9a5SSteve French {
25138c8a9a5SSteve French 	unsigned int handle = *(unsigned int *)payload;
25238c8a9a5SSteve French 	struct ipc_msg_table_entry *entry;
25338c8a9a5SSteve French 	int ret = 0;
25438c8a9a5SSteve French 
25538c8a9a5SSteve French 	ipc_update_last_active();
25638c8a9a5SSteve French 	down_read(&ipc_msg_table_lock);
25738c8a9a5SSteve French 	hash_for_each_possible(ipc_msg_table, entry, ipc_table_hlist, handle) {
25838c8a9a5SSteve French 		if (handle != entry->handle)
25938c8a9a5SSteve French 			continue;
26038c8a9a5SSteve French 
26138c8a9a5SSteve French 		entry->response = NULL;
26238c8a9a5SSteve French 		/*
26338c8a9a5SSteve French 		 * Response message type value should be equal to
26438c8a9a5SSteve French 		 * request message type + 1.
26538c8a9a5SSteve French 		 */
26638c8a9a5SSteve French 		if (entry->type + 1 != type) {
26738c8a9a5SSteve French 			pr_err("Waiting for IPC type %d, got %d. Ignore.\n",
26838c8a9a5SSteve French 			       entry->type + 1, type);
26938c8a9a5SSteve French 		}
27038c8a9a5SSteve French 
271*81a94b27SNamjae Jeon 		entry->response = kvzalloc(sz, GFP_KERNEL);
27238c8a9a5SSteve French 		if (!entry->response) {
27338c8a9a5SSteve French 			ret = -ENOMEM;
27438c8a9a5SSteve French 			break;
27538c8a9a5SSteve French 		}
27638c8a9a5SSteve French 
27738c8a9a5SSteve French 		memcpy(entry->response, payload, sz);
27838c8a9a5SSteve French 		wake_up_interruptible(&entry->wait);
27938c8a9a5SSteve French 		ret = 0;
28038c8a9a5SSteve French 		break;
28138c8a9a5SSteve French 	}
28238c8a9a5SSteve French 	up_read(&ipc_msg_table_lock);
28338c8a9a5SSteve French 
28438c8a9a5SSteve French 	return ret;
28538c8a9a5SSteve French }
28638c8a9a5SSteve French 
28738c8a9a5SSteve French static int ipc_server_config_on_startup(struct ksmbd_startup_request *req)
28838c8a9a5SSteve French {
28938c8a9a5SSteve French 	int ret;
29038c8a9a5SSteve French 
29138c8a9a5SSteve French 	ksmbd_set_fd_limit(req->file_max);
29238c8a9a5SSteve French 	server_conf.flags = req->flags;
29338c8a9a5SSteve French 	server_conf.signing = req->signing;
29438c8a9a5SSteve French 	server_conf.tcp_port = req->tcp_port;
29538c8a9a5SSteve French 	server_conf.ipc_timeout = req->ipc_timeout * HZ;
29638c8a9a5SSteve French 	server_conf.deadtime = req->deadtime * SMB_ECHO_INTERVAL;
29738c8a9a5SSteve French 	server_conf.share_fake_fscaps = req->share_fake_fscaps;
29838c8a9a5SSteve French 	ksmbd_init_domain(req->sub_auth);
29938c8a9a5SSteve French 
30038c8a9a5SSteve French 	if (req->smb2_max_read)
30138c8a9a5SSteve French 		init_smb2_max_read_size(req->smb2_max_read);
30238c8a9a5SSteve French 	if (req->smb2_max_write)
30338c8a9a5SSteve French 		init_smb2_max_write_size(req->smb2_max_write);
30438c8a9a5SSteve French 	if (req->smb2_max_trans)
30538c8a9a5SSteve French 		init_smb2_max_trans_size(req->smb2_max_trans);
30638c8a9a5SSteve French 	if (req->smb2_max_credits)
30738c8a9a5SSteve French 		init_smb2_max_credits(req->smb2_max_credits);
30838c8a9a5SSteve French 	if (req->smbd_max_io_size)
30938c8a9a5SSteve French 		init_smbd_max_io_size(req->smbd_max_io_size);
31038c8a9a5SSteve French 
31138c8a9a5SSteve French 	if (req->max_connections)
31238c8a9a5SSteve French 		server_conf.max_connections = req->max_connections;
31338c8a9a5SSteve French 
31438c8a9a5SSteve French 	ret = ksmbd_set_netbios_name(req->netbios_name);
31538c8a9a5SSteve French 	ret |= ksmbd_set_server_string(req->server_string);
31638c8a9a5SSteve French 	ret |= ksmbd_set_work_group(req->work_group);
31738c8a9a5SSteve French 	ret |= ksmbd_tcp_set_interfaces(KSMBD_STARTUP_CONFIG_INTERFACES(req),
31838c8a9a5SSteve French 					req->ifc_list_sz);
31938c8a9a5SSteve French 	if (ret) {
32038c8a9a5SSteve French 		pr_err("Server configuration error: %s %s %s\n",
32138c8a9a5SSteve French 		       req->netbios_name, req->server_string,
32238c8a9a5SSteve French 		       req->work_group);
32338c8a9a5SSteve French 		return ret;
32438c8a9a5SSteve French 	}
32538c8a9a5SSteve French 
32638c8a9a5SSteve French 	if (req->min_prot[0]) {
32738c8a9a5SSteve French 		ret = ksmbd_lookup_protocol_idx(req->min_prot);
32838c8a9a5SSteve French 		if (ret >= 0)
32938c8a9a5SSteve French 			server_conf.min_protocol = ret;
33038c8a9a5SSteve French 	}
33138c8a9a5SSteve French 	if (req->max_prot[0]) {
33238c8a9a5SSteve French 		ret = ksmbd_lookup_protocol_idx(req->max_prot);
33338c8a9a5SSteve French 		if (ret >= 0)
33438c8a9a5SSteve French 			server_conf.max_protocol = ret;
33538c8a9a5SSteve French 	}
33638c8a9a5SSteve French 
33738c8a9a5SSteve French 	if (server_conf.ipc_timeout)
33838c8a9a5SSteve French 		schedule_delayed_work(&ipc_timer_work, server_conf.ipc_timeout);
33938c8a9a5SSteve French 	return 0;
34038c8a9a5SSteve French }
34138c8a9a5SSteve French 
34238c8a9a5SSteve French static int handle_startup_event(struct sk_buff *skb, struct genl_info *info)
34338c8a9a5SSteve French {
34438c8a9a5SSteve French 	int ret = 0;
34538c8a9a5SSteve French 
34638c8a9a5SSteve French #ifdef CONFIG_SMB_SERVER_CHECK_CAP_NET_ADMIN
34738c8a9a5SSteve French 	if (!netlink_capable(skb, CAP_NET_ADMIN))
34838c8a9a5SSteve French 		return -EPERM;
34938c8a9a5SSteve French #endif
35038c8a9a5SSteve French 
35138c8a9a5SSteve French 	if (!ksmbd_ipc_validate_version(info))
35238c8a9a5SSteve French 		return -EINVAL;
35338c8a9a5SSteve French 
35438c8a9a5SSteve French 	if (!info->attrs[KSMBD_EVENT_STARTING_UP])
35538c8a9a5SSteve French 		return -EINVAL;
35638c8a9a5SSteve French 
35738c8a9a5SSteve French 	mutex_lock(&startup_lock);
35838c8a9a5SSteve French 	if (!ksmbd_server_configurable()) {
35938c8a9a5SSteve French 		mutex_unlock(&startup_lock);
36038c8a9a5SSteve French 		pr_err("Server reset is in progress, can't start daemon\n");
36138c8a9a5SSteve French 		return -EINVAL;
36238c8a9a5SSteve French 	}
36338c8a9a5SSteve French 
36438c8a9a5SSteve French 	if (ksmbd_tools_pid) {
36538c8a9a5SSteve French 		if (ksmbd_ipc_heartbeat_request() == 0) {
36638c8a9a5SSteve French 			ret = -EINVAL;
36738c8a9a5SSteve French 			goto out;
36838c8a9a5SSteve French 		}
36938c8a9a5SSteve French 
37038c8a9a5SSteve French 		pr_err("Reconnect to a new user space daemon\n");
37138c8a9a5SSteve French 	} else {
37238c8a9a5SSteve French 		struct ksmbd_startup_request *req;
37338c8a9a5SSteve French 
37438c8a9a5SSteve French 		req = nla_data(info->attrs[info->genlhdr->cmd]);
37538c8a9a5SSteve French 		ret = ipc_server_config_on_startup(req);
37638c8a9a5SSteve French 		if (ret)
37738c8a9a5SSteve French 			goto out;
37838c8a9a5SSteve French 		server_queue_ctrl_init_work();
37938c8a9a5SSteve French 	}
38038c8a9a5SSteve French 
38138c8a9a5SSteve French 	ksmbd_tools_pid = info->snd_portid;
38238c8a9a5SSteve French 	ipc_update_last_active();
38338c8a9a5SSteve French 
38438c8a9a5SSteve French out:
38538c8a9a5SSteve French 	mutex_unlock(&startup_lock);
38638c8a9a5SSteve French 	return ret;
38738c8a9a5SSteve French }
38838c8a9a5SSteve French 
38938c8a9a5SSteve French static int handle_unsupported_event(struct sk_buff *skb, struct genl_info *info)
39038c8a9a5SSteve French {
39138c8a9a5SSteve French 	pr_err("Unknown IPC event: %d, ignore.\n", info->genlhdr->cmd);
39238c8a9a5SSteve French 	return -EINVAL;
39338c8a9a5SSteve French }
39438c8a9a5SSteve French 
39538c8a9a5SSteve French static int handle_generic_event(struct sk_buff *skb, struct genl_info *info)
39638c8a9a5SSteve French {
39738c8a9a5SSteve French 	void *payload;
39838c8a9a5SSteve French 	int sz;
39938c8a9a5SSteve French 	int type = info->genlhdr->cmd;
40038c8a9a5SSteve French 
40138c8a9a5SSteve French #ifdef CONFIG_SMB_SERVER_CHECK_CAP_NET_ADMIN
40238c8a9a5SSteve French 	if (!netlink_capable(skb, CAP_NET_ADMIN))
40338c8a9a5SSteve French 		return -EPERM;
40438c8a9a5SSteve French #endif
40538c8a9a5SSteve French 
40638c8a9a5SSteve French 	if (type >= KSMBD_EVENT_MAX) {
40738c8a9a5SSteve French 		WARN_ON(1);
40838c8a9a5SSteve French 		return -EINVAL;
40938c8a9a5SSteve French 	}
41038c8a9a5SSteve French 
41138c8a9a5SSteve French 	if (!ksmbd_ipc_validate_version(info))
41238c8a9a5SSteve French 		return -EINVAL;
41338c8a9a5SSteve French 
41438c8a9a5SSteve French 	if (!info->attrs[type])
41538c8a9a5SSteve French 		return -EINVAL;
41638c8a9a5SSteve French 
41738c8a9a5SSteve French 	payload = nla_data(info->attrs[info->genlhdr->cmd]);
41838c8a9a5SSteve French 	sz = nla_len(info->attrs[info->genlhdr->cmd]);
41938c8a9a5SSteve French 	return handle_response(type, payload, sz);
42038c8a9a5SSteve French }
42138c8a9a5SSteve French 
42238c8a9a5SSteve French static int ipc_msg_send(struct ksmbd_ipc_msg *msg)
42338c8a9a5SSteve French {
42438c8a9a5SSteve French 	struct genlmsghdr *nlh;
42538c8a9a5SSteve French 	struct sk_buff *skb;
42638c8a9a5SSteve French 	int ret = -EINVAL;
42738c8a9a5SSteve French 
42838c8a9a5SSteve French 	if (!ksmbd_tools_pid)
42938c8a9a5SSteve French 		return ret;
43038c8a9a5SSteve French 
43138c8a9a5SSteve French 	skb = genlmsg_new(msg->sz, GFP_KERNEL);
43238c8a9a5SSteve French 	if (!skb)
43338c8a9a5SSteve French 		return -ENOMEM;
43438c8a9a5SSteve French 
43538c8a9a5SSteve French 	nlh = genlmsg_put(skb, 0, 0, &ksmbd_genl_family, 0, msg->type);
43638c8a9a5SSteve French 	if (!nlh)
43738c8a9a5SSteve French 		goto out;
43838c8a9a5SSteve French 
43938c8a9a5SSteve French 	ret = nla_put(skb, msg->type, msg->sz, msg->payload);
44038c8a9a5SSteve French 	if (ret) {
44138c8a9a5SSteve French 		genlmsg_cancel(skb, nlh);
44238c8a9a5SSteve French 		goto out;
44338c8a9a5SSteve French 	}
44438c8a9a5SSteve French 
44538c8a9a5SSteve French 	genlmsg_end(skb, nlh);
44638c8a9a5SSteve French 	ret = genlmsg_unicast(&init_net, skb, ksmbd_tools_pid);
44738c8a9a5SSteve French 	if (!ret)
44838c8a9a5SSteve French 		ipc_update_last_active();
44938c8a9a5SSteve French 	return ret;
45038c8a9a5SSteve French 
45138c8a9a5SSteve French out:
45238c8a9a5SSteve French 	nlmsg_free(skb);
45338c8a9a5SSteve French 	return ret;
45438c8a9a5SSteve French }
45538c8a9a5SSteve French 
45638c8a9a5SSteve French static void *ipc_msg_send_request(struct ksmbd_ipc_msg *msg, unsigned int handle)
45738c8a9a5SSteve French {
45838c8a9a5SSteve French 	struct ipc_msg_table_entry entry;
45938c8a9a5SSteve French 	int ret;
46038c8a9a5SSteve French 
46138c8a9a5SSteve French 	if ((int)handle < 0)
46238c8a9a5SSteve French 		return NULL;
46338c8a9a5SSteve French 
46438c8a9a5SSteve French 	entry.type = msg->type;
46538c8a9a5SSteve French 	entry.response = NULL;
46638c8a9a5SSteve French 	init_waitqueue_head(&entry.wait);
46738c8a9a5SSteve French 
46838c8a9a5SSteve French 	down_write(&ipc_msg_table_lock);
46938c8a9a5SSteve French 	entry.handle = handle;
47038c8a9a5SSteve French 	hash_add(ipc_msg_table, &entry.ipc_table_hlist, entry.handle);
47138c8a9a5SSteve French 	up_write(&ipc_msg_table_lock);
47238c8a9a5SSteve French 
47338c8a9a5SSteve French 	ret = ipc_msg_send(msg);
47438c8a9a5SSteve French 	if (ret)
47538c8a9a5SSteve French 		goto out;
47638c8a9a5SSteve French 
47738c8a9a5SSteve French 	ret = wait_event_interruptible_timeout(entry.wait,
47838c8a9a5SSteve French 					       entry.response != NULL,
47938c8a9a5SSteve French 					       IPC_WAIT_TIMEOUT);
48038c8a9a5SSteve French out:
48138c8a9a5SSteve French 	down_write(&ipc_msg_table_lock);
48238c8a9a5SSteve French 	hash_del(&entry.ipc_table_hlist);
48338c8a9a5SSteve French 	up_write(&ipc_msg_table_lock);
48438c8a9a5SSteve French 	return entry.response;
48538c8a9a5SSteve French }
48638c8a9a5SSteve French 
48738c8a9a5SSteve French static int ksmbd_ipc_heartbeat_request(void)
48838c8a9a5SSteve French {
48938c8a9a5SSteve French 	struct ksmbd_ipc_msg *msg;
49038c8a9a5SSteve French 	int ret;
49138c8a9a5SSteve French 
49238c8a9a5SSteve French 	msg = ipc_msg_alloc(sizeof(struct ksmbd_heartbeat));
49338c8a9a5SSteve French 	if (!msg)
49438c8a9a5SSteve French 		return -EINVAL;
49538c8a9a5SSteve French 
49638c8a9a5SSteve French 	msg->type = KSMBD_EVENT_HEARTBEAT_REQUEST;
49738c8a9a5SSteve French 	ret = ipc_msg_send(msg);
49838c8a9a5SSteve French 	ipc_msg_free(msg);
49938c8a9a5SSteve French 	return ret;
50038c8a9a5SSteve French }
50138c8a9a5SSteve French 
50238c8a9a5SSteve French struct ksmbd_login_response *ksmbd_ipc_login_request(const char *account)
50338c8a9a5SSteve French {
50438c8a9a5SSteve French 	struct ksmbd_ipc_msg *msg;
50538c8a9a5SSteve French 	struct ksmbd_login_request *req;
50638c8a9a5SSteve French 	struct ksmbd_login_response *resp;
50738c8a9a5SSteve French 
50838c8a9a5SSteve French 	if (strlen(account) >= KSMBD_REQ_MAX_ACCOUNT_NAME_SZ)
50938c8a9a5SSteve French 		return NULL;
51038c8a9a5SSteve French 
51138c8a9a5SSteve French 	msg = ipc_msg_alloc(sizeof(struct ksmbd_login_request));
51238c8a9a5SSteve French 	if (!msg)
51338c8a9a5SSteve French 		return NULL;
51438c8a9a5SSteve French 
51538c8a9a5SSteve French 	msg->type = KSMBD_EVENT_LOGIN_REQUEST;
51638c8a9a5SSteve French 	req = (struct ksmbd_login_request *)msg->payload;
51738c8a9a5SSteve French 	req->handle = ksmbd_acquire_id(&ipc_ida);
51838c8a9a5SSteve French 	strscpy(req->account, account, KSMBD_REQ_MAX_ACCOUNT_NAME_SZ);
51938c8a9a5SSteve French 
52038c8a9a5SSteve French 	resp = ipc_msg_send_request(msg, req->handle);
52138c8a9a5SSteve French 	ipc_msg_handle_free(req->handle);
52238c8a9a5SSteve French 	ipc_msg_free(msg);
52338c8a9a5SSteve French 	return resp;
52438c8a9a5SSteve French }
52538c8a9a5SSteve French 
52638c8a9a5SSteve French struct ksmbd_spnego_authen_response *
52738c8a9a5SSteve French ksmbd_ipc_spnego_authen_request(const char *spnego_blob, int blob_len)
52838c8a9a5SSteve French {
52938c8a9a5SSteve French 	struct ksmbd_ipc_msg *msg;
53038c8a9a5SSteve French 	struct ksmbd_spnego_authen_request *req;
53138c8a9a5SSteve French 	struct ksmbd_spnego_authen_response *resp;
53238c8a9a5SSteve French 
53338c8a9a5SSteve French 	msg = ipc_msg_alloc(sizeof(struct ksmbd_spnego_authen_request) +
53438c8a9a5SSteve French 			blob_len + 1);
53538c8a9a5SSteve French 	if (!msg)
53638c8a9a5SSteve French 		return NULL;
53738c8a9a5SSteve French 
53838c8a9a5SSteve French 	msg->type = KSMBD_EVENT_SPNEGO_AUTHEN_REQUEST;
53938c8a9a5SSteve French 	req = (struct ksmbd_spnego_authen_request *)msg->payload;
54038c8a9a5SSteve French 	req->handle = ksmbd_acquire_id(&ipc_ida);
54138c8a9a5SSteve French 	req->spnego_blob_len = blob_len;
54238c8a9a5SSteve French 	memcpy(req->spnego_blob, spnego_blob, blob_len);
54338c8a9a5SSteve French 
54438c8a9a5SSteve French 	resp = ipc_msg_send_request(msg, req->handle);
54538c8a9a5SSteve French 	ipc_msg_handle_free(req->handle);
54638c8a9a5SSteve French 	ipc_msg_free(msg);
54738c8a9a5SSteve French 	return resp;
54838c8a9a5SSteve French }
54938c8a9a5SSteve French 
55038c8a9a5SSteve French struct ksmbd_tree_connect_response *
55138c8a9a5SSteve French ksmbd_ipc_tree_connect_request(struct ksmbd_session *sess,
55238c8a9a5SSteve French 			       struct ksmbd_share_config *share,
55338c8a9a5SSteve French 			       struct ksmbd_tree_connect *tree_conn,
55438c8a9a5SSteve French 			       struct sockaddr *peer_addr)
55538c8a9a5SSteve French {
55638c8a9a5SSteve French 	struct ksmbd_ipc_msg *msg;
55738c8a9a5SSteve French 	struct ksmbd_tree_connect_request *req;
55838c8a9a5SSteve French 	struct ksmbd_tree_connect_response *resp;
55938c8a9a5SSteve French 
56038c8a9a5SSteve French 	if (strlen(user_name(sess->user)) >= KSMBD_REQ_MAX_ACCOUNT_NAME_SZ)
56138c8a9a5SSteve French 		return NULL;
56238c8a9a5SSteve French 
56338c8a9a5SSteve French 	if (strlen(share->name) >= KSMBD_REQ_MAX_SHARE_NAME)
56438c8a9a5SSteve French 		return NULL;
56538c8a9a5SSteve French 
56638c8a9a5SSteve French 	msg = ipc_msg_alloc(sizeof(struct ksmbd_tree_connect_request));
56738c8a9a5SSteve French 	if (!msg)
56838c8a9a5SSteve French 		return NULL;
56938c8a9a5SSteve French 
57038c8a9a5SSteve French 	msg->type = KSMBD_EVENT_TREE_CONNECT_REQUEST;
57138c8a9a5SSteve French 	req = (struct ksmbd_tree_connect_request *)msg->payload;
57238c8a9a5SSteve French 
57338c8a9a5SSteve French 	req->handle = ksmbd_acquire_id(&ipc_ida);
57438c8a9a5SSteve French 	req->account_flags = sess->user->flags;
57538c8a9a5SSteve French 	req->session_id = sess->id;
57638c8a9a5SSteve French 	req->connect_id = tree_conn->id;
57738c8a9a5SSteve French 	strscpy(req->account, user_name(sess->user), KSMBD_REQ_MAX_ACCOUNT_NAME_SZ);
57838c8a9a5SSteve French 	strscpy(req->share, share->name, KSMBD_REQ_MAX_SHARE_NAME);
57938c8a9a5SSteve French 	snprintf(req->peer_addr, sizeof(req->peer_addr), "%pIS", peer_addr);
58038c8a9a5SSteve French 
58138c8a9a5SSteve French 	if (peer_addr->sa_family == AF_INET6)
58238c8a9a5SSteve French 		req->flags |= KSMBD_TREE_CONN_FLAG_REQUEST_IPV6;
58338c8a9a5SSteve French 	if (test_session_flag(sess, CIFDS_SESSION_FLAG_SMB2))
58438c8a9a5SSteve French 		req->flags |= KSMBD_TREE_CONN_FLAG_REQUEST_SMB2;
58538c8a9a5SSteve French 
58638c8a9a5SSteve French 	resp = ipc_msg_send_request(msg, req->handle);
58738c8a9a5SSteve French 	ipc_msg_handle_free(req->handle);
58838c8a9a5SSteve French 	ipc_msg_free(msg);
58938c8a9a5SSteve French 	return resp;
59038c8a9a5SSteve French }
59138c8a9a5SSteve French 
59238c8a9a5SSteve French int ksmbd_ipc_tree_disconnect_request(unsigned long long session_id,
59338c8a9a5SSteve French 				      unsigned long long connect_id)
59438c8a9a5SSteve French {
59538c8a9a5SSteve French 	struct ksmbd_ipc_msg *msg;
59638c8a9a5SSteve French 	struct ksmbd_tree_disconnect_request *req;
59738c8a9a5SSteve French 	int ret;
59838c8a9a5SSteve French 
59938c8a9a5SSteve French 	msg = ipc_msg_alloc(sizeof(struct ksmbd_tree_disconnect_request));
60038c8a9a5SSteve French 	if (!msg)
60138c8a9a5SSteve French 		return -ENOMEM;
60238c8a9a5SSteve French 
60338c8a9a5SSteve French 	msg->type = KSMBD_EVENT_TREE_DISCONNECT_REQUEST;
60438c8a9a5SSteve French 	req = (struct ksmbd_tree_disconnect_request *)msg->payload;
60538c8a9a5SSteve French 	req->session_id = session_id;
60638c8a9a5SSteve French 	req->connect_id = connect_id;
60738c8a9a5SSteve French 
60838c8a9a5SSteve French 	ret = ipc_msg_send(msg);
60938c8a9a5SSteve French 	ipc_msg_free(msg);
61038c8a9a5SSteve French 	return ret;
61138c8a9a5SSteve French }
61238c8a9a5SSteve French 
61338c8a9a5SSteve French int ksmbd_ipc_logout_request(const char *account, int flags)
61438c8a9a5SSteve French {
61538c8a9a5SSteve French 	struct ksmbd_ipc_msg *msg;
61638c8a9a5SSteve French 	struct ksmbd_logout_request *req;
61738c8a9a5SSteve French 	int ret;
61838c8a9a5SSteve French 
61938c8a9a5SSteve French 	if (strlen(account) >= KSMBD_REQ_MAX_ACCOUNT_NAME_SZ)
62038c8a9a5SSteve French 		return -EINVAL;
62138c8a9a5SSteve French 
62238c8a9a5SSteve French 	msg = ipc_msg_alloc(sizeof(struct ksmbd_logout_request));
62338c8a9a5SSteve French 	if (!msg)
62438c8a9a5SSteve French 		return -ENOMEM;
62538c8a9a5SSteve French 
62638c8a9a5SSteve French 	msg->type = KSMBD_EVENT_LOGOUT_REQUEST;
62738c8a9a5SSteve French 	req = (struct ksmbd_logout_request *)msg->payload;
62838c8a9a5SSteve French 	req->account_flags = flags;
62938c8a9a5SSteve French 	strscpy(req->account, account, KSMBD_REQ_MAX_ACCOUNT_NAME_SZ);
63038c8a9a5SSteve French 
63138c8a9a5SSteve French 	ret = ipc_msg_send(msg);
63238c8a9a5SSteve French 	ipc_msg_free(msg);
63338c8a9a5SSteve French 	return ret;
63438c8a9a5SSteve French }
63538c8a9a5SSteve French 
63638c8a9a5SSteve French struct ksmbd_share_config_response *
63738c8a9a5SSteve French ksmbd_ipc_share_config_request(const char *name)
63838c8a9a5SSteve French {
63938c8a9a5SSteve French 	struct ksmbd_ipc_msg *msg;
64038c8a9a5SSteve French 	struct ksmbd_share_config_request *req;
64138c8a9a5SSteve French 	struct ksmbd_share_config_response *resp;
64238c8a9a5SSteve French 
64338c8a9a5SSteve French 	if (strlen(name) >= KSMBD_REQ_MAX_SHARE_NAME)
64438c8a9a5SSteve French 		return NULL;
64538c8a9a5SSteve French 
64638c8a9a5SSteve French 	msg = ipc_msg_alloc(sizeof(struct ksmbd_share_config_request));
64738c8a9a5SSteve French 	if (!msg)
64838c8a9a5SSteve French 		return NULL;
64938c8a9a5SSteve French 
65038c8a9a5SSteve French 	msg->type = KSMBD_EVENT_SHARE_CONFIG_REQUEST;
65138c8a9a5SSteve French 	req = (struct ksmbd_share_config_request *)msg->payload;
65238c8a9a5SSteve French 	req->handle = ksmbd_acquire_id(&ipc_ida);
65338c8a9a5SSteve French 	strscpy(req->share_name, name, KSMBD_REQ_MAX_SHARE_NAME);
65438c8a9a5SSteve French 
65538c8a9a5SSteve French 	resp = ipc_msg_send_request(msg, req->handle);
65638c8a9a5SSteve French 	ipc_msg_handle_free(req->handle);
65738c8a9a5SSteve French 	ipc_msg_free(msg);
65838c8a9a5SSteve French 	return resp;
65938c8a9a5SSteve French }
66038c8a9a5SSteve French 
66138c8a9a5SSteve French struct ksmbd_rpc_command *ksmbd_rpc_open(struct ksmbd_session *sess, int handle)
66238c8a9a5SSteve French {
66338c8a9a5SSteve French 	struct ksmbd_ipc_msg *msg;
66438c8a9a5SSteve French 	struct ksmbd_rpc_command *req;
66538c8a9a5SSteve French 	struct ksmbd_rpc_command *resp;
66638c8a9a5SSteve French 
66738c8a9a5SSteve French 	msg = ipc_msg_alloc(sizeof(struct ksmbd_rpc_command));
66838c8a9a5SSteve French 	if (!msg)
66938c8a9a5SSteve French 		return NULL;
67038c8a9a5SSteve French 
67138c8a9a5SSteve French 	msg->type = KSMBD_EVENT_RPC_REQUEST;
67238c8a9a5SSteve French 	req = (struct ksmbd_rpc_command *)msg->payload;
67338c8a9a5SSteve French 	req->handle = handle;
67438c8a9a5SSteve French 	req->flags = ksmbd_session_rpc_method(sess, handle);
67538c8a9a5SSteve French 	req->flags |= KSMBD_RPC_OPEN_METHOD;
67638c8a9a5SSteve French 	req->payload_sz = 0;
67738c8a9a5SSteve French 
67838c8a9a5SSteve French 	resp = ipc_msg_send_request(msg, req->handle);
67938c8a9a5SSteve French 	ipc_msg_free(msg);
68038c8a9a5SSteve French 	return resp;
68138c8a9a5SSteve French }
68238c8a9a5SSteve French 
68338c8a9a5SSteve French struct ksmbd_rpc_command *ksmbd_rpc_close(struct ksmbd_session *sess, int handle)
68438c8a9a5SSteve French {
68538c8a9a5SSteve French 	struct ksmbd_ipc_msg *msg;
68638c8a9a5SSteve French 	struct ksmbd_rpc_command *req;
68738c8a9a5SSteve French 	struct ksmbd_rpc_command *resp;
68838c8a9a5SSteve French 
68938c8a9a5SSteve French 	msg = ipc_msg_alloc(sizeof(struct ksmbd_rpc_command));
69038c8a9a5SSteve French 	if (!msg)
69138c8a9a5SSteve French 		return NULL;
69238c8a9a5SSteve French 
69338c8a9a5SSteve French 	msg->type = KSMBD_EVENT_RPC_REQUEST;
69438c8a9a5SSteve French 	req = (struct ksmbd_rpc_command *)msg->payload;
69538c8a9a5SSteve French 	req->handle = handle;
69638c8a9a5SSteve French 	req->flags = ksmbd_session_rpc_method(sess, handle);
69738c8a9a5SSteve French 	req->flags |= KSMBD_RPC_CLOSE_METHOD;
69838c8a9a5SSteve French 	req->payload_sz = 0;
69938c8a9a5SSteve French 
70038c8a9a5SSteve French 	resp = ipc_msg_send_request(msg, req->handle);
70138c8a9a5SSteve French 	ipc_msg_free(msg);
70238c8a9a5SSteve French 	return resp;
70338c8a9a5SSteve French }
70438c8a9a5SSteve French 
70538c8a9a5SSteve French struct ksmbd_rpc_command *ksmbd_rpc_write(struct ksmbd_session *sess, int handle,
70638c8a9a5SSteve French 					  void *payload, size_t payload_sz)
70738c8a9a5SSteve French {
70838c8a9a5SSteve French 	struct ksmbd_ipc_msg *msg;
70938c8a9a5SSteve French 	struct ksmbd_rpc_command *req;
71038c8a9a5SSteve French 	struct ksmbd_rpc_command *resp;
71138c8a9a5SSteve French 
71238c8a9a5SSteve French 	msg = ipc_msg_alloc(sizeof(struct ksmbd_rpc_command) + payload_sz + 1);
71338c8a9a5SSteve French 	if (!msg)
71438c8a9a5SSteve French 		return NULL;
71538c8a9a5SSteve French 
71638c8a9a5SSteve French 	msg->type = KSMBD_EVENT_RPC_REQUEST;
71738c8a9a5SSteve French 	req = (struct ksmbd_rpc_command *)msg->payload;
71838c8a9a5SSteve French 	req->handle = handle;
71938c8a9a5SSteve French 	req->flags = ksmbd_session_rpc_method(sess, handle);
72038c8a9a5SSteve French 	req->flags |= rpc_context_flags(sess);
72138c8a9a5SSteve French 	req->flags |= KSMBD_RPC_WRITE_METHOD;
72238c8a9a5SSteve French 	req->payload_sz = payload_sz;
72338c8a9a5SSteve French 	memcpy(req->payload, payload, payload_sz);
72438c8a9a5SSteve French 
72538c8a9a5SSteve French 	resp = ipc_msg_send_request(msg, req->handle);
72638c8a9a5SSteve French 	ipc_msg_free(msg);
72738c8a9a5SSteve French 	return resp;
72838c8a9a5SSteve French }
72938c8a9a5SSteve French 
73038c8a9a5SSteve French struct ksmbd_rpc_command *ksmbd_rpc_read(struct ksmbd_session *sess, int handle)
73138c8a9a5SSteve French {
73238c8a9a5SSteve French 	struct ksmbd_ipc_msg *msg;
73338c8a9a5SSteve French 	struct ksmbd_rpc_command *req;
73438c8a9a5SSteve French 	struct ksmbd_rpc_command *resp;
73538c8a9a5SSteve French 
73638c8a9a5SSteve French 	msg = ipc_msg_alloc(sizeof(struct ksmbd_rpc_command));
73738c8a9a5SSteve French 	if (!msg)
73838c8a9a5SSteve French 		return NULL;
73938c8a9a5SSteve French 
74038c8a9a5SSteve French 	msg->type = KSMBD_EVENT_RPC_REQUEST;
74138c8a9a5SSteve French 	req = (struct ksmbd_rpc_command *)msg->payload;
74238c8a9a5SSteve French 	req->handle = handle;
74338c8a9a5SSteve French 	req->flags = ksmbd_session_rpc_method(sess, handle);
74438c8a9a5SSteve French 	req->flags |= rpc_context_flags(sess);
74538c8a9a5SSteve French 	req->flags |= KSMBD_RPC_READ_METHOD;
74638c8a9a5SSteve French 	req->payload_sz = 0;
74738c8a9a5SSteve French 
74838c8a9a5SSteve French 	resp = ipc_msg_send_request(msg, req->handle);
74938c8a9a5SSteve French 	ipc_msg_free(msg);
75038c8a9a5SSteve French 	return resp;
75138c8a9a5SSteve French }
75238c8a9a5SSteve French 
75338c8a9a5SSteve French struct ksmbd_rpc_command *ksmbd_rpc_ioctl(struct ksmbd_session *sess, int handle,
75438c8a9a5SSteve French 					  void *payload, size_t payload_sz)
75538c8a9a5SSteve French {
75638c8a9a5SSteve French 	struct ksmbd_ipc_msg *msg;
75738c8a9a5SSteve French 	struct ksmbd_rpc_command *req;
75838c8a9a5SSteve French 	struct ksmbd_rpc_command *resp;
75938c8a9a5SSteve French 
76038c8a9a5SSteve French 	msg = ipc_msg_alloc(sizeof(struct ksmbd_rpc_command) + payload_sz + 1);
76138c8a9a5SSteve French 	if (!msg)
76238c8a9a5SSteve French 		return NULL;
76338c8a9a5SSteve French 
76438c8a9a5SSteve French 	msg->type = KSMBD_EVENT_RPC_REQUEST;
76538c8a9a5SSteve French 	req = (struct ksmbd_rpc_command *)msg->payload;
76638c8a9a5SSteve French 	req->handle = handle;
76738c8a9a5SSteve French 	req->flags = ksmbd_session_rpc_method(sess, handle);
76838c8a9a5SSteve French 	req->flags |= rpc_context_flags(sess);
76938c8a9a5SSteve French 	req->flags |= KSMBD_RPC_IOCTL_METHOD;
77038c8a9a5SSteve French 	req->payload_sz = payload_sz;
77138c8a9a5SSteve French 	memcpy(req->payload, payload, payload_sz);
77238c8a9a5SSteve French 
77338c8a9a5SSteve French 	resp = ipc_msg_send_request(msg, req->handle);
77438c8a9a5SSteve French 	ipc_msg_free(msg);
77538c8a9a5SSteve French 	return resp;
77638c8a9a5SSteve French }
77738c8a9a5SSteve French 
77838c8a9a5SSteve French struct ksmbd_rpc_command *ksmbd_rpc_rap(struct ksmbd_session *sess, void *payload,
77938c8a9a5SSteve French 					size_t payload_sz)
78038c8a9a5SSteve French {
78138c8a9a5SSteve French 	struct ksmbd_ipc_msg *msg;
78238c8a9a5SSteve French 	struct ksmbd_rpc_command *req;
78338c8a9a5SSteve French 	struct ksmbd_rpc_command *resp;
78438c8a9a5SSteve French 
78538c8a9a5SSteve French 	msg = ipc_msg_alloc(sizeof(struct ksmbd_rpc_command) + payload_sz + 1);
78638c8a9a5SSteve French 	if (!msg)
78738c8a9a5SSteve French 		return NULL;
78838c8a9a5SSteve French 
78938c8a9a5SSteve French 	msg->type = KSMBD_EVENT_RPC_REQUEST;
79038c8a9a5SSteve French 	req = (struct ksmbd_rpc_command *)msg->payload;
79138c8a9a5SSteve French 	req->handle = ksmbd_acquire_id(&ipc_ida);
79238c8a9a5SSteve French 	req->flags = rpc_context_flags(sess);
79338c8a9a5SSteve French 	req->flags |= KSMBD_RPC_RAP_METHOD;
79438c8a9a5SSteve French 	req->payload_sz = payload_sz;
79538c8a9a5SSteve French 	memcpy(req->payload, payload, payload_sz);
79638c8a9a5SSteve French 
79738c8a9a5SSteve French 	resp = ipc_msg_send_request(msg, req->handle);
79838c8a9a5SSteve French 	ipc_msg_handle_free(req->handle);
79938c8a9a5SSteve French 	ipc_msg_free(msg);
80038c8a9a5SSteve French 	return resp;
80138c8a9a5SSteve French }
80238c8a9a5SSteve French 
80338c8a9a5SSteve French static int __ipc_heartbeat(void)
80438c8a9a5SSteve French {
80538c8a9a5SSteve French 	unsigned long delta;
80638c8a9a5SSteve French 
80738c8a9a5SSteve French 	if (!ksmbd_server_running())
80838c8a9a5SSteve French 		return 0;
80938c8a9a5SSteve French 
81038c8a9a5SSteve French 	if (time_after(jiffies, server_conf.ipc_last_active)) {
81138c8a9a5SSteve French 		delta = (jiffies - server_conf.ipc_last_active);
81238c8a9a5SSteve French 	} else {
81338c8a9a5SSteve French 		ipc_update_last_active();
81438c8a9a5SSteve French 		schedule_delayed_work(&ipc_timer_work,
81538c8a9a5SSteve French 				      server_conf.ipc_timeout);
81638c8a9a5SSteve French 		return 0;
81738c8a9a5SSteve French 	}
81838c8a9a5SSteve French 
81938c8a9a5SSteve French 	if (delta < server_conf.ipc_timeout) {
82038c8a9a5SSteve French 		schedule_delayed_work(&ipc_timer_work,
82138c8a9a5SSteve French 				      server_conf.ipc_timeout - delta);
82238c8a9a5SSteve French 		return 0;
82338c8a9a5SSteve French 	}
82438c8a9a5SSteve French 
82538c8a9a5SSteve French 	if (ksmbd_ipc_heartbeat_request() == 0) {
82638c8a9a5SSteve French 		schedule_delayed_work(&ipc_timer_work,
82738c8a9a5SSteve French 				      server_conf.ipc_timeout);
82838c8a9a5SSteve French 		return 0;
82938c8a9a5SSteve French 	}
83038c8a9a5SSteve French 
83138c8a9a5SSteve French 	mutex_lock(&startup_lock);
83238c8a9a5SSteve French 	WRITE_ONCE(server_conf.state, SERVER_STATE_RESETTING);
83338c8a9a5SSteve French 	server_conf.ipc_last_active = 0;
83438c8a9a5SSteve French 	ksmbd_tools_pid = 0;
83538c8a9a5SSteve French 	pr_err("No IPC daemon response for %lus\n", delta / HZ);
83638c8a9a5SSteve French 	mutex_unlock(&startup_lock);
83738c8a9a5SSteve French 	return -EINVAL;
83838c8a9a5SSteve French }
83938c8a9a5SSteve French 
84038c8a9a5SSteve French static void ipc_timer_heartbeat(struct work_struct *w)
84138c8a9a5SSteve French {
84238c8a9a5SSteve French 	if (__ipc_heartbeat())
84338c8a9a5SSteve French 		server_queue_ctrl_reset_work();
84438c8a9a5SSteve French }
84538c8a9a5SSteve French 
84638c8a9a5SSteve French int ksmbd_ipc_id_alloc(void)
84738c8a9a5SSteve French {
84838c8a9a5SSteve French 	return ksmbd_acquire_id(&ipc_ida);
84938c8a9a5SSteve French }
85038c8a9a5SSteve French 
85138c8a9a5SSteve French void ksmbd_rpc_id_free(int handle)
85238c8a9a5SSteve French {
85338c8a9a5SSteve French 	ksmbd_release_id(&ipc_ida, handle);
85438c8a9a5SSteve French }
85538c8a9a5SSteve French 
85638c8a9a5SSteve French void ksmbd_ipc_release(void)
85738c8a9a5SSteve French {
85838c8a9a5SSteve French 	cancel_delayed_work_sync(&ipc_timer_work);
85938c8a9a5SSteve French 	genl_unregister_family(&ksmbd_genl_family);
86038c8a9a5SSteve French }
86138c8a9a5SSteve French 
86238c8a9a5SSteve French void ksmbd_ipc_soft_reset(void)
86338c8a9a5SSteve French {
86438c8a9a5SSteve French 	mutex_lock(&startup_lock);
86538c8a9a5SSteve French 	ksmbd_tools_pid = 0;
86638c8a9a5SSteve French 	cancel_delayed_work_sync(&ipc_timer_work);
86738c8a9a5SSteve French 	mutex_unlock(&startup_lock);
86838c8a9a5SSteve French }
86938c8a9a5SSteve French 
87038c8a9a5SSteve French int ksmbd_ipc_init(void)
87138c8a9a5SSteve French {
87238c8a9a5SSteve French 	int ret = 0;
87338c8a9a5SSteve French 
87438c8a9a5SSteve French 	ksmbd_nl_init_fixup();
87538c8a9a5SSteve French 	INIT_DELAYED_WORK(&ipc_timer_work, ipc_timer_heartbeat);
87638c8a9a5SSteve French 
87738c8a9a5SSteve French 	ret = genl_register_family(&ksmbd_genl_family);
87838c8a9a5SSteve French 	if (ret) {
87938c8a9a5SSteve French 		pr_err("Failed to register KSMBD netlink interface %d\n", ret);
88038c8a9a5SSteve French 		cancel_delayed_work_sync(&ipc_timer_work);
88138c8a9a5SSteve French 	}
88238c8a9a5SSteve French 
88338c8a9a5SSteve French 	return ret;
88438c8a9a5SSteve French }
885