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