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;
68a637fabaSNamjae 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
789863a531SLin 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);
270*76861630SNamjae Jeon continue;
27138c8a9a5SSteve French }
27238c8a9a5SSteve French
27381a94b27SNamjae Jeon entry->response = kvzalloc(sz, GFP_KERNEL);
27438c8a9a5SSteve French if (!entry->response) {
27538c8a9a5SSteve French ret = -ENOMEM;
27638c8a9a5SSteve French break;
27738c8a9a5SSteve French }
27838c8a9a5SSteve French
27938c8a9a5SSteve French memcpy(entry->response, payload, sz);
280a637fabaSNamjae Jeon entry->msg_sz = sz;
28138c8a9a5SSteve French wake_up_interruptible(&entry->wait);
28238c8a9a5SSteve French ret = 0;
28338c8a9a5SSteve French break;
28438c8a9a5SSteve French }
28538c8a9a5SSteve French up_read(&ipc_msg_table_lock);
28638c8a9a5SSteve French
28738c8a9a5SSteve French return ret;
28838c8a9a5SSteve French }
28938c8a9a5SSteve French
ipc_server_config_on_startup(struct ksmbd_startup_request * req)29038c8a9a5SSteve French static int ipc_server_config_on_startup(struct ksmbd_startup_request *req)
29138c8a9a5SSteve French {
29238c8a9a5SSteve French int ret;
29338c8a9a5SSteve French
29438c8a9a5SSteve French ksmbd_set_fd_limit(req->file_max);
29538c8a9a5SSteve French server_conf.flags = req->flags;
29638c8a9a5SSteve French server_conf.signing = req->signing;
29738c8a9a5SSteve French server_conf.tcp_port = req->tcp_port;
29838c8a9a5SSteve French server_conf.ipc_timeout = req->ipc_timeout * HZ;
29938c8a9a5SSteve French server_conf.deadtime = req->deadtime * SMB_ECHO_INTERVAL;
30038c8a9a5SSteve French server_conf.share_fake_fscaps = req->share_fake_fscaps;
30138c8a9a5SSteve French ksmbd_init_domain(req->sub_auth);
30238c8a9a5SSteve French
30338c8a9a5SSteve French if (req->smb2_max_read)
30438c8a9a5SSteve French init_smb2_max_read_size(req->smb2_max_read);
30538c8a9a5SSteve French if (req->smb2_max_write)
30638c8a9a5SSteve French init_smb2_max_write_size(req->smb2_max_write);
30738c8a9a5SSteve French if (req->smb2_max_trans)
30838c8a9a5SSteve French init_smb2_max_trans_size(req->smb2_max_trans);
30955a81dcfSMarios Makassikis if (req->smb2_max_credits) {
31038c8a9a5SSteve French init_smb2_max_credits(req->smb2_max_credits);
31155a81dcfSMarios Makassikis server_conf.max_inflight_req =
31255a81dcfSMarios Makassikis req->smb2_max_credits;
31355a81dcfSMarios Makassikis }
31438c8a9a5SSteve French if (req->smbd_max_io_size)
31538c8a9a5SSteve French init_smbd_max_io_size(req->smbd_max_io_size);
31638c8a9a5SSteve French
31738c8a9a5SSteve French if (req->max_connections)
31838c8a9a5SSteve French server_conf.max_connections = req->max_connections;
31938c8a9a5SSteve French
32038c8a9a5SSteve French ret = ksmbd_set_netbios_name(req->netbios_name);
32138c8a9a5SSteve French ret |= ksmbd_set_server_string(req->server_string);
32238c8a9a5SSteve French ret |= ksmbd_set_work_group(req->work_group);
32338c8a9a5SSteve French ret |= ksmbd_tcp_set_interfaces(KSMBD_STARTUP_CONFIG_INTERFACES(req),
32438c8a9a5SSteve French req->ifc_list_sz);
32538c8a9a5SSteve French if (ret) {
32638c8a9a5SSteve French pr_err("Server configuration error: %s %s %s\n",
32738c8a9a5SSteve French req->netbios_name, req->server_string,
32838c8a9a5SSteve French req->work_group);
32938c8a9a5SSteve French return ret;
33038c8a9a5SSteve French }
33138c8a9a5SSteve French
33238c8a9a5SSteve French if (req->min_prot[0]) {
33338c8a9a5SSteve French ret = ksmbd_lookup_protocol_idx(req->min_prot);
33438c8a9a5SSteve French if (ret >= 0)
33538c8a9a5SSteve French server_conf.min_protocol = ret;
33638c8a9a5SSteve French }
33738c8a9a5SSteve French if (req->max_prot[0]) {
33838c8a9a5SSteve French ret = ksmbd_lookup_protocol_idx(req->max_prot);
33938c8a9a5SSteve French if (ret >= 0)
34038c8a9a5SSteve French server_conf.max_protocol = ret;
34138c8a9a5SSteve French }
34238c8a9a5SSteve French
34338c8a9a5SSteve French if (server_conf.ipc_timeout)
34438c8a9a5SSteve French schedule_delayed_work(&ipc_timer_work, server_conf.ipc_timeout);
34538c8a9a5SSteve French return 0;
34638c8a9a5SSteve French }
34738c8a9a5SSteve French
handle_startup_event(struct sk_buff * skb,struct genl_info * info)34838c8a9a5SSteve French static int handle_startup_event(struct sk_buff *skb, struct genl_info *info)
34938c8a9a5SSteve French {
35038c8a9a5SSteve French int ret = 0;
35138c8a9a5SSteve French
35238c8a9a5SSteve French #ifdef CONFIG_SMB_SERVER_CHECK_CAP_NET_ADMIN
35338c8a9a5SSteve French if (!netlink_capable(skb, CAP_NET_ADMIN))
35438c8a9a5SSteve French return -EPERM;
35538c8a9a5SSteve French #endif
35638c8a9a5SSteve French
35738c8a9a5SSteve French if (!ksmbd_ipc_validate_version(info))
35838c8a9a5SSteve French return -EINVAL;
35938c8a9a5SSteve French
36038c8a9a5SSteve French if (!info->attrs[KSMBD_EVENT_STARTING_UP])
36138c8a9a5SSteve French return -EINVAL;
36238c8a9a5SSteve French
36338c8a9a5SSteve French mutex_lock(&startup_lock);
36438c8a9a5SSteve French if (!ksmbd_server_configurable()) {
36538c8a9a5SSteve French mutex_unlock(&startup_lock);
36638c8a9a5SSteve French pr_err("Server reset is in progress, can't start daemon\n");
36738c8a9a5SSteve French return -EINVAL;
36838c8a9a5SSteve French }
36938c8a9a5SSteve French
37038c8a9a5SSteve French if (ksmbd_tools_pid) {
37138c8a9a5SSteve French if (ksmbd_ipc_heartbeat_request() == 0) {
37238c8a9a5SSteve French ret = -EINVAL;
37338c8a9a5SSteve French goto out;
37438c8a9a5SSteve French }
37538c8a9a5SSteve French
37638c8a9a5SSteve French pr_err("Reconnect to a new user space daemon\n");
37738c8a9a5SSteve French } else {
37838c8a9a5SSteve French struct ksmbd_startup_request *req;
37938c8a9a5SSteve French
38038c8a9a5SSteve French req = nla_data(info->attrs[info->genlhdr->cmd]);
38138c8a9a5SSteve French ret = ipc_server_config_on_startup(req);
38238c8a9a5SSteve French if (ret)
38338c8a9a5SSteve French goto out;
38438c8a9a5SSteve French server_queue_ctrl_init_work();
38538c8a9a5SSteve French }
38638c8a9a5SSteve French
38738c8a9a5SSteve French ksmbd_tools_pid = info->snd_portid;
38838c8a9a5SSteve French ipc_update_last_active();
38938c8a9a5SSteve French
39038c8a9a5SSteve French out:
39138c8a9a5SSteve French mutex_unlock(&startup_lock);
39238c8a9a5SSteve French return ret;
39338c8a9a5SSteve French }
39438c8a9a5SSteve French
handle_unsupported_event(struct sk_buff * skb,struct genl_info * info)39538c8a9a5SSteve French static int handle_unsupported_event(struct sk_buff *skb, struct genl_info *info)
39638c8a9a5SSteve French {
39738c8a9a5SSteve French pr_err("Unknown IPC event: %d, ignore.\n", info->genlhdr->cmd);
39838c8a9a5SSteve French return -EINVAL;
39938c8a9a5SSteve French }
40038c8a9a5SSteve French
handle_generic_event(struct sk_buff * skb,struct genl_info * info)40138c8a9a5SSteve French static int handle_generic_event(struct sk_buff *skb, struct genl_info *info)
40238c8a9a5SSteve French {
40338c8a9a5SSteve French void *payload;
40438c8a9a5SSteve French int sz;
40538c8a9a5SSteve French int type = info->genlhdr->cmd;
40638c8a9a5SSteve French
40738c8a9a5SSteve French #ifdef CONFIG_SMB_SERVER_CHECK_CAP_NET_ADMIN
40838c8a9a5SSteve French if (!netlink_capable(skb, CAP_NET_ADMIN))
40938c8a9a5SSteve French return -EPERM;
41038c8a9a5SSteve French #endif
41138c8a9a5SSteve French
4129863a531SLin Ma if (type > KSMBD_EVENT_MAX) {
41338c8a9a5SSteve French WARN_ON(1);
41438c8a9a5SSteve French return -EINVAL;
41538c8a9a5SSteve French }
41638c8a9a5SSteve French
41738c8a9a5SSteve French if (!ksmbd_ipc_validate_version(info))
41838c8a9a5SSteve French return -EINVAL;
41938c8a9a5SSteve French
42038c8a9a5SSteve French if (!info->attrs[type])
42138c8a9a5SSteve French return -EINVAL;
42238c8a9a5SSteve French
42338c8a9a5SSteve French payload = nla_data(info->attrs[info->genlhdr->cmd]);
42438c8a9a5SSteve French sz = nla_len(info->attrs[info->genlhdr->cmd]);
42538c8a9a5SSteve French return handle_response(type, payload, sz);
42638c8a9a5SSteve French }
42738c8a9a5SSteve French
ipc_msg_send(struct ksmbd_ipc_msg * msg)42838c8a9a5SSteve French static int ipc_msg_send(struct ksmbd_ipc_msg *msg)
42938c8a9a5SSteve French {
43038c8a9a5SSteve French struct genlmsghdr *nlh;
43138c8a9a5SSteve French struct sk_buff *skb;
43238c8a9a5SSteve French int ret = -EINVAL;
43338c8a9a5SSteve French
43438c8a9a5SSteve French if (!ksmbd_tools_pid)
43538c8a9a5SSteve French return ret;
43638c8a9a5SSteve French
43738c8a9a5SSteve French skb = genlmsg_new(msg->sz, GFP_KERNEL);
43838c8a9a5SSteve French if (!skb)
43938c8a9a5SSteve French return -ENOMEM;
44038c8a9a5SSteve French
44138c8a9a5SSteve French nlh = genlmsg_put(skb, 0, 0, &ksmbd_genl_family, 0, msg->type);
44238c8a9a5SSteve French if (!nlh)
44338c8a9a5SSteve French goto out;
44438c8a9a5SSteve French
44538c8a9a5SSteve French ret = nla_put(skb, msg->type, msg->sz, msg->payload);
44638c8a9a5SSteve French if (ret) {
44738c8a9a5SSteve French genlmsg_cancel(skb, nlh);
44838c8a9a5SSteve French goto out;
44938c8a9a5SSteve French }
45038c8a9a5SSteve French
45138c8a9a5SSteve French genlmsg_end(skb, nlh);
45238c8a9a5SSteve French ret = genlmsg_unicast(&init_net, skb, ksmbd_tools_pid);
45338c8a9a5SSteve French if (!ret)
45438c8a9a5SSteve French ipc_update_last_active();
45538c8a9a5SSteve French return ret;
45638c8a9a5SSteve French
45738c8a9a5SSteve French out:
45838c8a9a5SSteve French nlmsg_free(skb);
45938c8a9a5SSteve French return ret;
46038c8a9a5SSteve French }
46138c8a9a5SSteve French
ipc_validate_msg(struct ipc_msg_table_entry * entry)462a637fabaSNamjae Jeon static int ipc_validate_msg(struct ipc_msg_table_entry *entry)
463a637fabaSNamjae Jeon {
464a637fabaSNamjae Jeon unsigned int msg_sz = entry->msg_sz;
465a637fabaSNamjae Jeon
466a637fabaSNamjae Jeon if (entry->type == KSMBD_EVENT_RPC_REQUEST) {
467a637fabaSNamjae Jeon struct ksmbd_rpc_command *resp = entry->response;
468a637fabaSNamjae Jeon
469a637fabaSNamjae Jeon msg_sz = sizeof(struct ksmbd_rpc_command) + resp->payload_sz;
470a637fabaSNamjae Jeon } else if (entry->type == KSMBD_EVENT_SPNEGO_AUTHEN_REQUEST) {
471a637fabaSNamjae Jeon struct ksmbd_spnego_authen_response *resp = entry->response;
472a637fabaSNamjae Jeon
473a637fabaSNamjae Jeon msg_sz = sizeof(struct ksmbd_spnego_authen_response) +
474a637fabaSNamjae Jeon resp->session_key_len + resp->spnego_blob_len;
475a637fabaSNamjae Jeon } else if (entry->type == KSMBD_EVENT_SHARE_CONFIG_REQUEST) {
476a637fabaSNamjae Jeon struct ksmbd_share_config_response *resp = entry->response;
477a637fabaSNamjae Jeon
478a637fabaSNamjae Jeon if (resp->payload_sz) {
479a637fabaSNamjae Jeon if (resp->payload_sz < resp->veto_list_sz)
480a637fabaSNamjae Jeon return -EINVAL;
481a637fabaSNamjae Jeon
482a637fabaSNamjae Jeon msg_sz = sizeof(struct ksmbd_share_config_response) +
483a637fabaSNamjae Jeon resp->payload_sz;
484a637fabaSNamjae Jeon }
485a637fabaSNamjae Jeon }
486a637fabaSNamjae Jeon
487a637fabaSNamjae Jeon return entry->msg_sz != msg_sz ? -EINVAL : 0;
488a637fabaSNamjae Jeon }
489a637fabaSNamjae Jeon
ipc_msg_send_request(struct ksmbd_ipc_msg * msg,unsigned int handle)49038c8a9a5SSteve French static void *ipc_msg_send_request(struct ksmbd_ipc_msg *msg, unsigned int handle)
49138c8a9a5SSteve French {
49238c8a9a5SSteve French struct ipc_msg_table_entry entry;
49338c8a9a5SSteve French int ret;
49438c8a9a5SSteve French
49538c8a9a5SSteve French if ((int)handle < 0)
49638c8a9a5SSteve French return NULL;
49738c8a9a5SSteve French
49838c8a9a5SSteve French entry.type = msg->type;
49938c8a9a5SSteve French entry.response = NULL;
50038c8a9a5SSteve French init_waitqueue_head(&entry.wait);
50138c8a9a5SSteve French
50238c8a9a5SSteve French down_write(&ipc_msg_table_lock);
50338c8a9a5SSteve French entry.handle = handle;
50438c8a9a5SSteve French hash_add(ipc_msg_table, &entry.ipc_table_hlist, entry.handle);
50538c8a9a5SSteve French up_write(&ipc_msg_table_lock);
50638c8a9a5SSteve French
50738c8a9a5SSteve French ret = ipc_msg_send(msg);
50838c8a9a5SSteve French if (ret)
50938c8a9a5SSteve French goto out;
51038c8a9a5SSteve French
51138c8a9a5SSteve French ret = wait_event_interruptible_timeout(entry.wait,
51238c8a9a5SSteve French entry.response != NULL,
51338c8a9a5SSteve French IPC_WAIT_TIMEOUT);
514a637fabaSNamjae Jeon if (entry.response) {
515a637fabaSNamjae Jeon ret = ipc_validate_msg(&entry);
516a637fabaSNamjae Jeon if (ret) {
517a637fabaSNamjae Jeon kvfree(entry.response);
518a637fabaSNamjae Jeon entry.response = NULL;
519a637fabaSNamjae Jeon }
520a637fabaSNamjae Jeon }
52138c8a9a5SSteve French out:
52238c8a9a5SSteve French down_write(&ipc_msg_table_lock);
52338c8a9a5SSteve French hash_del(&entry.ipc_table_hlist);
52438c8a9a5SSteve French up_write(&ipc_msg_table_lock);
52538c8a9a5SSteve French return entry.response;
52638c8a9a5SSteve French }
52738c8a9a5SSteve French
ksmbd_ipc_heartbeat_request(void)52838c8a9a5SSteve French static int ksmbd_ipc_heartbeat_request(void)
52938c8a9a5SSteve French {
53038c8a9a5SSteve French struct ksmbd_ipc_msg *msg;
53138c8a9a5SSteve French int ret;
53238c8a9a5SSteve French
53338c8a9a5SSteve French msg = ipc_msg_alloc(sizeof(struct ksmbd_heartbeat));
53438c8a9a5SSteve French if (!msg)
53538c8a9a5SSteve French return -EINVAL;
53638c8a9a5SSteve French
53738c8a9a5SSteve French msg->type = KSMBD_EVENT_HEARTBEAT_REQUEST;
53838c8a9a5SSteve French ret = ipc_msg_send(msg);
53938c8a9a5SSteve French ipc_msg_free(msg);
54038c8a9a5SSteve French return ret;
54138c8a9a5SSteve French }
54238c8a9a5SSteve French
ksmbd_ipc_login_request(const char * account)54338c8a9a5SSteve French struct ksmbd_login_response *ksmbd_ipc_login_request(const char *account)
54438c8a9a5SSteve French {
54538c8a9a5SSteve French struct ksmbd_ipc_msg *msg;
54638c8a9a5SSteve French struct ksmbd_login_request *req;
54738c8a9a5SSteve French struct ksmbd_login_response *resp;
54838c8a9a5SSteve French
54938c8a9a5SSteve French if (strlen(account) >= KSMBD_REQ_MAX_ACCOUNT_NAME_SZ)
55038c8a9a5SSteve French return NULL;
55138c8a9a5SSteve French
55238c8a9a5SSteve French msg = ipc_msg_alloc(sizeof(struct ksmbd_login_request));
55338c8a9a5SSteve French if (!msg)
55438c8a9a5SSteve French return NULL;
55538c8a9a5SSteve French
55638c8a9a5SSteve French msg->type = KSMBD_EVENT_LOGIN_REQUEST;
55738c8a9a5SSteve French req = (struct ksmbd_login_request *)msg->payload;
55838c8a9a5SSteve French req->handle = ksmbd_acquire_id(&ipc_ida);
55938c8a9a5SSteve French strscpy(req->account, account, KSMBD_REQ_MAX_ACCOUNT_NAME_SZ);
56038c8a9a5SSteve French
56138c8a9a5SSteve French resp = ipc_msg_send_request(msg, req->handle);
56238c8a9a5SSteve French ipc_msg_handle_free(req->handle);
56338c8a9a5SSteve French ipc_msg_free(msg);
56438c8a9a5SSteve French return resp;
56538c8a9a5SSteve French }
56638c8a9a5SSteve French
56738c8a9a5SSteve French struct ksmbd_spnego_authen_response *
ksmbd_ipc_spnego_authen_request(const char * spnego_blob,int blob_len)56838c8a9a5SSteve French ksmbd_ipc_spnego_authen_request(const char *spnego_blob, int blob_len)
56938c8a9a5SSteve French {
57038c8a9a5SSteve French struct ksmbd_ipc_msg *msg;
57138c8a9a5SSteve French struct ksmbd_spnego_authen_request *req;
57238c8a9a5SSteve French struct ksmbd_spnego_authen_response *resp;
57338c8a9a5SSteve French
57482f59d64SDan Carpenter if (blob_len > KSMBD_IPC_MAX_PAYLOAD)
57582f59d64SDan Carpenter return NULL;
57682f59d64SDan Carpenter
57738c8a9a5SSteve French msg = ipc_msg_alloc(sizeof(struct ksmbd_spnego_authen_request) +
57838c8a9a5SSteve French blob_len + 1);
57938c8a9a5SSteve French if (!msg)
58038c8a9a5SSteve French return NULL;
58138c8a9a5SSteve French
58238c8a9a5SSteve French msg->type = KSMBD_EVENT_SPNEGO_AUTHEN_REQUEST;
58338c8a9a5SSteve French req = (struct ksmbd_spnego_authen_request *)msg->payload;
58438c8a9a5SSteve French req->handle = ksmbd_acquire_id(&ipc_ida);
58538c8a9a5SSteve French req->spnego_blob_len = blob_len;
58638c8a9a5SSteve French memcpy(req->spnego_blob, spnego_blob, blob_len);
58738c8a9a5SSteve French
58838c8a9a5SSteve French resp = ipc_msg_send_request(msg, req->handle);
58938c8a9a5SSteve French ipc_msg_handle_free(req->handle);
59038c8a9a5SSteve French ipc_msg_free(msg);
59138c8a9a5SSteve French return resp;
59238c8a9a5SSteve French }
59338c8a9a5SSteve French
59438c8a9a5SSteve 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)59538c8a9a5SSteve French ksmbd_ipc_tree_connect_request(struct ksmbd_session *sess,
59638c8a9a5SSteve French struct ksmbd_share_config *share,
59738c8a9a5SSteve French struct ksmbd_tree_connect *tree_conn,
59838c8a9a5SSteve French struct sockaddr *peer_addr)
59938c8a9a5SSteve French {
60038c8a9a5SSteve French struct ksmbd_ipc_msg *msg;
60138c8a9a5SSteve French struct ksmbd_tree_connect_request *req;
60238c8a9a5SSteve French struct ksmbd_tree_connect_response *resp;
60338c8a9a5SSteve French
60438c8a9a5SSteve French if (strlen(user_name(sess->user)) >= KSMBD_REQ_MAX_ACCOUNT_NAME_SZ)
60538c8a9a5SSteve French return NULL;
60638c8a9a5SSteve French
60738c8a9a5SSteve French if (strlen(share->name) >= KSMBD_REQ_MAX_SHARE_NAME)
60838c8a9a5SSteve French return NULL;
60938c8a9a5SSteve French
61038c8a9a5SSteve French msg = ipc_msg_alloc(sizeof(struct ksmbd_tree_connect_request));
61138c8a9a5SSteve French if (!msg)
61238c8a9a5SSteve French return NULL;
61338c8a9a5SSteve French
61438c8a9a5SSteve French msg->type = KSMBD_EVENT_TREE_CONNECT_REQUEST;
61538c8a9a5SSteve French req = (struct ksmbd_tree_connect_request *)msg->payload;
61638c8a9a5SSteve French
61738c8a9a5SSteve French req->handle = ksmbd_acquire_id(&ipc_ida);
61838c8a9a5SSteve French req->account_flags = sess->user->flags;
61938c8a9a5SSteve French req->session_id = sess->id;
62038c8a9a5SSteve French req->connect_id = tree_conn->id;
62138c8a9a5SSteve French strscpy(req->account, user_name(sess->user), KSMBD_REQ_MAX_ACCOUNT_NAME_SZ);
62238c8a9a5SSteve French strscpy(req->share, share->name, KSMBD_REQ_MAX_SHARE_NAME);
62338c8a9a5SSteve French snprintf(req->peer_addr, sizeof(req->peer_addr), "%pIS", peer_addr);
62438c8a9a5SSteve French
62538c8a9a5SSteve French if (peer_addr->sa_family == AF_INET6)
62638c8a9a5SSteve French req->flags |= KSMBD_TREE_CONN_FLAG_REQUEST_IPV6;
62738c8a9a5SSteve French if (test_session_flag(sess, CIFDS_SESSION_FLAG_SMB2))
62838c8a9a5SSteve French req->flags |= KSMBD_TREE_CONN_FLAG_REQUEST_SMB2;
62938c8a9a5SSteve French
63038c8a9a5SSteve French resp = ipc_msg_send_request(msg, req->handle);
63138c8a9a5SSteve French ipc_msg_handle_free(req->handle);
63238c8a9a5SSteve French ipc_msg_free(msg);
63338c8a9a5SSteve French return resp;
63438c8a9a5SSteve French }
63538c8a9a5SSteve French
ksmbd_ipc_tree_disconnect_request(unsigned long long session_id,unsigned long long connect_id)63638c8a9a5SSteve French int ksmbd_ipc_tree_disconnect_request(unsigned long long session_id,
63738c8a9a5SSteve French unsigned long long connect_id)
63838c8a9a5SSteve French {
63938c8a9a5SSteve French struct ksmbd_ipc_msg *msg;
64038c8a9a5SSteve French struct ksmbd_tree_disconnect_request *req;
64138c8a9a5SSteve French int ret;
64238c8a9a5SSteve French
64338c8a9a5SSteve French msg = ipc_msg_alloc(sizeof(struct ksmbd_tree_disconnect_request));
64438c8a9a5SSteve French if (!msg)
64538c8a9a5SSteve French return -ENOMEM;
64638c8a9a5SSteve French
64738c8a9a5SSteve French msg->type = KSMBD_EVENT_TREE_DISCONNECT_REQUEST;
64838c8a9a5SSteve French req = (struct ksmbd_tree_disconnect_request *)msg->payload;
64938c8a9a5SSteve French req->session_id = session_id;
65038c8a9a5SSteve French req->connect_id = connect_id;
65138c8a9a5SSteve French
65238c8a9a5SSteve French ret = ipc_msg_send(msg);
65338c8a9a5SSteve French ipc_msg_free(msg);
65438c8a9a5SSteve French return ret;
65538c8a9a5SSteve French }
65638c8a9a5SSteve French
ksmbd_ipc_logout_request(const char * account,int flags)65738c8a9a5SSteve French int ksmbd_ipc_logout_request(const char *account, int flags)
65838c8a9a5SSteve French {
65938c8a9a5SSteve French struct ksmbd_ipc_msg *msg;
66038c8a9a5SSteve French struct ksmbd_logout_request *req;
66138c8a9a5SSteve French int ret;
66238c8a9a5SSteve French
66338c8a9a5SSteve French if (strlen(account) >= KSMBD_REQ_MAX_ACCOUNT_NAME_SZ)
66438c8a9a5SSteve French return -EINVAL;
66538c8a9a5SSteve French
66638c8a9a5SSteve French msg = ipc_msg_alloc(sizeof(struct ksmbd_logout_request));
66738c8a9a5SSteve French if (!msg)
66838c8a9a5SSteve French return -ENOMEM;
66938c8a9a5SSteve French
67038c8a9a5SSteve French msg->type = KSMBD_EVENT_LOGOUT_REQUEST;
67138c8a9a5SSteve French req = (struct ksmbd_logout_request *)msg->payload;
67238c8a9a5SSteve French req->account_flags = flags;
67338c8a9a5SSteve French strscpy(req->account, account, KSMBD_REQ_MAX_ACCOUNT_NAME_SZ);
67438c8a9a5SSteve French
67538c8a9a5SSteve French ret = ipc_msg_send(msg);
67638c8a9a5SSteve French ipc_msg_free(msg);
67738c8a9a5SSteve French return ret;
67838c8a9a5SSteve French }
67938c8a9a5SSteve French
68038c8a9a5SSteve French struct ksmbd_share_config_response *
ksmbd_ipc_share_config_request(const char * name)68138c8a9a5SSteve French ksmbd_ipc_share_config_request(const char *name)
68238c8a9a5SSteve French {
68338c8a9a5SSteve French struct ksmbd_ipc_msg *msg;
68438c8a9a5SSteve French struct ksmbd_share_config_request *req;
68538c8a9a5SSteve French struct ksmbd_share_config_response *resp;
68638c8a9a5SSteve French
68738c8a9a5SSteve French if (strlen(name) >= KSMBD_REQ_MAX_SHARE_NAME)
68838c8a9a5SSteve French return NULL;
68938c8a9a5SSteve French
69038c8a9a5SSteve French msg = ipc_msg_alloc(sizeof(struct ksmbd_share_config_request));
69138c8a9a5SSteve French if (!msg)
69238c8a9a5SSteve French return NULL;
69338c8a9a5SSteve French
69438c8a9a5SSteve French msg->type = KSMBD_EVENT_SHARE_CONFIG_REQUEST;
69538c8a9a5SSteve French req = (struct ksmbd_share_config_request *)msg->payload;
69638c8a9a5SSteve French req->handle = ksmbd_acquire_id(&ipc_ida);
69738c8a9a5SSteve French strscpy(req->share_name, name, KSMBD_REQ_MAX_SHARE_NAME);
69838c8a9a5SSteve French
69938c8a9a5SSteve French resp = ipc_msg_send_request(msg, req->handle);
70038c8a9a5SSteve French ipc_msg_handle_free(req->handle);
70138c8a9a5SSteve French ipc_msg_free(msg);
70238c8a9a5SSteve French return resp;
70338c8a9a5SSteve French }
70438c8a9a5SSteve French
ksmbd_rpc_open(struct ksmbd_session * sess,int handle)70538c8a9a5SSteve French struct ksmbd_rpc_command *ksmbd_rpc_open(struct ksmbd_session *sess, int handle)
70638c8a9a5SSteve French {
70738c8a9a5SSteve French struct ksmbd_ipc_msg *msg;
70838c8a9a5SSteve French struct ksmbd_rpc_command *req;
70938c8a9a5SSteve French struct ksmbd_rpc_command *resp;
71038c8a9a5SSteve French
71138c8a9a5SSteve French msg = ipc_msg_alloc(sizeof(struct ksmbd_rpc_command));
71238c8a9a5SSteve French if (!msg)
71338c8a9a5SSteve French return NULL;
71438c8a9a5SSteve French
71538c8a9a5SSteve French msg->type = KSMBD_EVENT_RPC_REQUEST;
71638c8a9a5SSteve French req = (struct ksmbd_rpc_command *)msg->payload;
71738c8a9a5SSteve French req->handle = handle;
71838c8a9a5SSteve French req->flags = ksmbd_session_rpc_method(sess, handle);
71938c8a9a5SSteve French req->flags |= KSMBD_RPC_OPEN_METHOD;
72038c8a9a5SSteve French req->payload_sz = 0;
72138c8a9a5SSteve French
72238c8a9a5SSteve French resp = ipc_msg_send_request(msg, req->handle);
72338c8a9a5SSteve French ipc_msg_free(msg);
72438c8a9a5SSteve French return resp;
72538c8a9a5SSteve French }
72638c8a9a5SSteve French
ksmbd_rpc_close(struct ksmbd_session * sess,int handle)72738c8a9a5SSteve French struct ksmbd_rpc_command *ksmbd_rpc_close(struct ksmbd_session *sess, int handle)
72838c8a9a5SSteve French {
72938c8a9a5SSteve French struct ksmbd_ipc_msg *msg;
73038c8a9a5SSteve French struct ksmbd_rpc_command *req;
73138c8a9a5SSteve French struct ksmbd_rpc_command *resp;
73238c8a9a5SSteve French
73338c8a9a5SSteve French msg = ipc_msg_alloc(sizeof(struct ksmbd_rpc_command));
73438c8a9a5SSteve French if (!msg)
73538c8a9a5SSteve French return NULL;
73638c8a9a5SSteve French
73738c8a9a5SSteve French msg->type = KSMBD_EVENT_RPC_REQUEST;
73838c8a9a5SSteve French req = (struct ksmbd_rpc_command *)msg->payload;
73938c8a9a5SSteve French req->handle = handle;
74038c8a9a5SSteve French req->flags = ksmbd_session_rpc_method(sess, handle);
74138c8a9a5SSteve French req->flags |= KSMBD_RPC_CLOSE_METHOD;
74238c8a9a5SSteve French req->payload_sz = 0;
74338c8a9a5SSteve French
74438c8a9a5SSteve French resp = ipc_msg_send_request(msg, req->handle);
74538c8a9a5SSteve French ipc_msg_free(msg);
74638c8a9a5SSteve French return resp;
74738c8a9a5SSteve French }
74838c8a9a5SSteve French
ksmbd_rpc_write(struct ksmbd_session * sess,int handle,void * payload,size_t payload_sz)74938c8a9a5SSteve French struct ksmbd_rpc_command *ksmbd_rpc_write(struct ksmbd_session *sess, int handle,
75038c8a9a5SSteve French void *payload, size_t payload_sz)
75138c8a9a5SSteve French {
75238c8a9a5SSteve French struct ksmbd_ipc_msg *msg;
75338c8a9a5SSteve French struct ksmbd_rpc_command *req;
75438c8a9a5SSteve French struct ksmbd_rpc_command *resp;
75538c8a9a5SSteve French
75682f59d64SDan Carpenter if (payload_sz > KSMBD_IPC_MAX_PAYLOAD)
75782f59d64SDan Carpenter return NULL;
75882f59d64SDan Carpenter
75938c8a9a5SSteve French msg = ipc_msg_alloc(sizeof(struct ksmbd_rpc_command) + payload_sz + 1);
76038c8a9a5SSteve French if (!msg)
76138c8a9a5SSteve French return NULL;
76238c8a9a5SSteve French
76338c8a9a5SSteve French msg->type = KSMBD_EVENT_RPC_REQUEST;
76438c8a9a5SSteve French req = (struct ksmbd_rpc_command *)msg->payload;
76538c8a9a5SSteve French req->handle = handle;
76638c8a9a5SSteve French req->flags = ksmbd_session_rpc_method(sess, handle);
76738c8a9a5SSteve French req->flags |= rpc_context_flags(sess);
76838c8a9a5SSteve French req->flags |= KSMBD_RPC_WRITE_METHOD;
76938c8a9a5SSteve French req->payload_sz = payload_sz;
77038c8a9a5SSteve French memcpy(req->payload, payload, payload_sz);
77138c8a9a5SSteve French
77238c8a9a5SSteve French resp = ipc_msg_send_request(msg, req->handle);
77338c8a9a5SSteve French ipc_msg_free(msg);
77438c8a9a5SSteve French return resp;
77538c8a9a5SSteve French }
77638c8a9a5SSteve French
ksmbd_rpc_read(struct ksmbd_session * sess,int handle)77738c8a9a5SSteve French struct ksmbd_rpc_command *ksmbd_rpc_read(struct ksmbd_session *sess, int handle)
77838c8a9a5SSteve French {
77938c8a9a5SSteve French struct ksmbd_ipc_msg *msg;
78038c8a9a5SSteve French struct ksmbd_rpc_command *req;
78138c8a9a5SSteve French struct ksmbd_rpc_command *resp;
78238c8a9a5SSteve French
78338c8a9a5SSteve French msg = ipc_msg_alloc(sizeof(struct ksmbd_rpc_command));
78438c8a9a5SSteve French if (!msg)
78538c8a9a5SSteve French return NULL;
78638c8a9a5SSteve French
78738c8a9a5SSteve French msg->type = KSMBD_EVENT_RPC_REQUEST;
78838c8a9a5SSteve French req = (struct ksmbd_rpc_command *)msg->payload;
78938c8a9a5SSteve French req->handle = handle;
79038c8a9a5SSteve French req->flags = ksmbd_session_rpc_method(sess, handle);
79138c8a9a5SSteve French req->flags |= rpc_context_flags(sess);
79238c8a9a5SSteve French req->flags |= KSMBD_RPC_READ_METHOD;
79338c8a9a5SSteve French req->payload_sz = 0;
79438c8a9a5SSteve French
79538c8a9a5SSteve French resp = ipc_msg_send_request(msg, req->handle);
79638c8a9a5SSteve French ipc_msg_free(msg);
79738c8a9a5SSteve French return resp;
79838c8a9a5SSteve French }
79938c8a9a5SSteve French
ksmbd_rpc_ioctl(struct ksmbd_session * sess,int handle,void * payload,size_t payload_sz)80038c8a9a5SSteve French struct ksmbd_rpc_command *ksmbd_rpc_ioctl(struct ksmbd_session *sess, int handle,
80138c8a9a5SSteve French void *payload, size_t payload_sz)
80238c8a9a5SSteve French {
80338c8a9a5SSteve French struct ksmbd_ipc_msg *msg;
80438c8a9a5SSteve French struct ksmbd_rpc_command *req;
80538c8a9a5SSteve French struct ksmbd_rpc_command *resp;
80638c8a9a5SSteve French
80782f59d64SDan Carpenter if (payload_sz > KSMBD_IPC_MAX_PAYLOAD)
80882f59d64SDan Carpenter return NULL;
80982f59d64SDan Carpenter
81038c8a9a5SSteve French msg = ipc_msg_alloc(sizeof(struct ksmbd_rpc_command) + payload_sz + 1);
81138c8a9a5SSteve French if (!msg)
81238c8a9a5SSteve French return NULL;
81338c8a9a5SSteve French
81438c8a9a5SSteve French msg->type = KSMBD_EVENT_RPC_REQUEST;
81538c8a9a5SSteve French req = (struct ksmbd_rpc_command *)msg->payload;
81638c8a9a5SSteve French req->handle = handle;
81738c8a9a5SSteve French req->flags = ksmbd_session_rpc_method(sess, handle);
81838c8a9a5SSteve French req->flags |= rpc_context_flags(sess);
81938c8a9a5SSteve French req->flags |= KSMBD_RPC_IOCTL_METHOD;
82038c8a9a5SSteve French req->payload_sz = payload_sz;
82138c8a9a5SSteve French memcpy(req->payload, payload, payload_sz);
82238c8a9a5SSteve French
82338c8a9a5SSteve French resp = ipc_msg_send_request(msg, req->handle);
82438c8a9a5SSteve French ipc_msg_free(msg);
82538c8a9a5SSteve French return resp;
82638c8a9a5SSteve French }
82738c8a9a5SSteve French
ksmbd_rpc_rap(struct ksmbd_session * sess,void * payload,size_t payload_sz)82838c8a9a5SSteve French struct ksmbd_rpc_command *ksmbd_rpc_rap(struct ksmbd_session *sess, void *payload,
82938c8a9a5SSteve French size_t payload_sz)
83038c8a9a5SSteve French {
83138c8a9a5SSteve French struct ksmbd_ipc_msg *msg;
83238c8a9a5SSteve French struct ksmbd_rpc_command *req;
83338c8a9a5SSteve French struct ksmbd_rpc_command *resp;
83438c8a9a5SSteve French
83538c8a9a5SSteve French msg = ipc_msg_alloc(sizeof(struct ksmbd_rpc_command) + payload_sz + 1);
83638c8a9a5SSteve French if (!msg)
83738c8a9a5SSteve French return NULL;
83838c8a9a5SSteve French
83938c8a9a5SSteve French msg->type = KSMBD_EVENT_RPC_REQUEST;
84038c8a9a5SSteve French req = (struct ksmbd_rpc_command *)msg->payload;
84138c8a9a5SSteve French req->handle = ksmbd_acquire_id(&ipc_ida);
84238c8a9a5SSteve French req->flags = rpc_context_flags(sess);
84338c8a9a5SSteve French req->flags |= KSMBD_RPC_RAP_METHOD;
84438c8a9a5SSteve French req->payload_sz = payload_sz;
84538c8a9a5SSteve French memcpy(req->payload, payload, payload_sz);
84638c8a9a5SSteve French
84738c8a9a5SSteve French resp = ipc_msg_send_request(msg, req->handle);
84838c8a9a5SSteve French ipc_msg_handle_free(req->handle);
84938c8a9a5SSteve French ipc_msg_free(msg);
85038c8a9a5SSteve French return resp;
85138c8a9a5SSteve French }
85238c8a9a5SSteve French
__ipc_heartbeat(void)85338c8a9a5SSteve French static int __ipc_heartbeat(void)
85438c8a9a5SSteve French {
85538c8a9a5SSteve French unsigned long delta;
85638c8a9a5SSteve French
85738c8a9a5SSteve French if (!ksmbd_server_running())
85838c8a9a5SSteve French return 0;
85938c8a9a5SSteve French
86038c8a9a5SSteve French if (time_after(jiffies, server_conf.ipc_last_active)) {
86138c8a9a5SSteve French delta = (jiffies - server_conf.ipc_last_active);
86238c8a9a5SSteve French } else {
86338c8a9a5SSteve French ipc_update_last_active();
86438c8a9a5SSteve French schedule_delayed_work(&ipc_timer_work,
86538c8a9a5SSteve French server_conf.ipc_timeout);
86638c8a9a5SSteve French return 0;
86738c8a9a5SSteve French }
86838c8a9a5SSteve French
86938c8a9a5SSteve French if (delta < server_conf.ipc_timeout) {
87038c8a9a5SSteve French schedule_delayed_work(&ipc_timer_work,
87138c8a9a5SSteve French server_conf.ipc_timeout - delta);
87238c8a9a5SSteve French return 0;
87338c8a9a5SSteve French }
87438c8a9a5SSteve French
87538c8a9a5SSteve French if (ksmbd_ipc_heartbeat_request() == 0) {
87638c8a9a5SSteve French schedule_delayed_work(&ipc_timer_work,
87738c8a9a5SSteve French server_conf.ipc_timeout);
87838c8a9a5SSteve French return 0;
87938c8a9a5SSteve French }
88038c8a9a5SSteve French
88138c8a9a5SSteve French mutex_lock(&startup_lock);
88238c8a9a5SSteve French WRITE_ONCE(server_conf.state, SERVER_STATE_RESETTING);
88338c8a9a5SSteve French server_conf.ipc_last_active = 0;
88438c8a9a5SSteve French ksmbd_tools_pid = 0;
88538c8a9a5SSteve French pr_err("No IPC daemon response for %lus\n", delta / HZ);
88638c8a9a5SSteve French mutex_unlock(&startup_lock);
88738c8a9a5SSteve French return -EINVAL;
88838c8a9a5SSteve French }
88938c8a9a5SSteve French
ipc_timer_heartbeat(struct work_struct * w)89038c8a9a5SSteve French static void ipc_timer_heartbeat(struct work_struct *w)
89138c8a9a5SSteve French {
89238c8a9a5SSteve French if (__ipc_heartbeat())
89338c8a9a5SSteve French server_queue_ctrl_reset_work();
89438c8a9a5SSteve French }
89538c8a9a5SSteve French
ksmbd_ipc_id_alloc(void)89638c8a9a5SSteve French int ksmbd_ipc_id_alloc(void)
89738c8a9a5SSteve French {
89838c8a9a5SSteve French return ksmbd_acquire_id(&ipc_ida);
89938c8a9a5SSteve French }
90038c8a9a5SSteve French
ksmbd_rpc_id_free(int handle)90138c8a9a5SSteve French void ksmbd_rpc_id_free(int handle)
90238c8a9a5SSteve French {
90338c8a9a5SSteve French ksmbd_release_id(&ipc_ida, handle);
90438c8a9a5SSteve French }
90538c8a9a5SSteve French
ksmbd_ipc_release(void)90638c8a9a5SSteve French void ksmbd_ipc_release(void)
90738c8a9a5SSteve French {
90838c8a9a5SSteve French cancel_delayed_work_sync(&ipc_timer_work);
90938c8a9a5SSteve French genl_unregister_family(&ksmbd_genl_family);
91038c8a9a5SSteve French }
91138c8a9a5SSteve French
ksmbd_ipc_soft_reset(void)91238c8a9a5SSteve French void ksmbd_ipc_soft_reset(void)
91338c8a9a5SSteve French {
91438c8a9a5SSteve French mutex_lock(&startup_lock);
91538c8a9a5SSteve French ksmbd_tools_pid = 0;
91638c8a9a5SSteve French cancel_delayed_work_sync(&ipc_timer_work);
91738c8a9a5SSteve French mutex_unlock(&startup_lock);
91838c8a9a5SSteve French }
91938c8a9a5SSteve French
ksmbd_ipc_init(void)92038c8a9a5SSteve French int ksmbd_ipc_init(void)
92138c8a9a5SSteve French {
92238c8a9a5SSteve French int ret = 0;
92338c8a9a5SSteve French
92438c8a9a5SSteve French ksmbd_nl_init_fixup();
92538c8a9a5SSteve French INIT_DELAYED_WORK(&ipc_timer_work, ipc_timer_heartbeat);
92638c8a9a5SSteve French
92738c8a9a5SSteve French ret = genl_register_family(&ksmbd_genl_family);
92838c8a9a5SSteve French if (ret) {
92938c8a9a5SSteve French pr_err("Failed to register KSMBD netlink interface %d\n", ret);
93038c8a9a5SSteve French cancel_delayed_work_sync(&ipc_timer_work);
93138c8a9a5SSteve French }
93238c8a9a5SSteve French
93338c8a9a5SSteve French return ret;
93438c8a9a5SSteve French }
935