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