162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2018 Samsung Electronics Co., Ltd. 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <linux/jhash.h> 762306a36Sopenharmony_ci#include <linux/slab.h> 862306a36Sopenharmony_ci#include <linux/rwsem.h> 962306a36Sopenharmony_ci#include <linux/mutex.h> 1062306a36Sopenharmony_ci#include <linux/wait.h> 1162306a36Sopenharmony_ci#include <linux/hashtable.h> 1262306a36Sopenharmony_ci#include <net/net_namespace.h> 1362306a36Sopenharmony_ci#include <net/genetlink.h> 1462306a36Sopenharmony_ci#include <linux/socket.h> 1562306a36Sopenharmony_ci#include <linux/workqueue.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include "vfs_cache.h" 1862306a36Sopenharmony_ci#include "transport_ipc.h" 1962306a36Sopenharmony_ci#include "server.h" 2062306a36Sopenharmony_ci#include "smb_common.h" 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#include "mgmt/user_config.h" 2362306a36Sopenharmony_ci#include "mgmt/share_config.h" 2462306a36Sopenharmony_ci#include "mgmt/user_session.h" 2562306a36Sopenharmony_ci#include "mgmt/tree_connect.h" 2662306a36Sopenharmony_ci#include "mgmt/ksmbd_ida.h" 2762306a36Sopenharmony_ci#include "connection.h" 2862306a36Sopenharmony_ci#include "transport_tcp.h" 2962306a36Sopenharmony_ci#include "transport_rdma.h" 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci#define IPC_WAIT_TIMEOUT (2 * HZ) 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci#define IPC_MSG_HASH_BITS 3 3462306a36Sopenharmony_cistatic DEFINE_HASHTABLE(ipc_msg_table, IPC_MSG_HASH_BITS); 3562306a36Sopenharmony_cistatic DECLARE_RWSEM(ipc_msg_table_lock); 3662306a36Sopenharmony_cistatic DEFINE_MUTEX(startup_lock); 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_cistatic DEFINE_IDA(ipc_ida); 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_cistatic unsigned int ksmbd_tools_pid; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_cistatic bool ksmbd_ipc_validate_version(struct genl_info *m) 4362306a36Sopenharmony_ci{ 4462306a36Sopenharmony_ci if (m->genlhdr->version != KSMBD_GENL_VERSION) { 4562306a36Sopenharmony_ci pr_err("%s. ksmbd: %d, kernel module: %d. %s.\n", 4662306a36Sopenharmony_ci "Daemon and kernel module version mismatch", 4762306a36Sopenharmony_ci m->genlhdr->version, 4862306a36Sopenharmony_ci KSMBD_GENL_VERSION, 4962306a36Sopenharmony_ci "User-space ksmbd should terminate"); 5062306a36Sopenharmony_ci return false; 5162306a36Sopenharmony_ci } 5262306a36Sopenharmony_ci return true; 5362306a36Sopenharmony_ci} 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_cistruct ksmbd_ipc_msg { 5662306a36Sopenharmony_ci unsigned int type; 5762306a36Sopenharmony_ci unsigned int sz; 5862306a36Sopenharmony_ci unsigned char payload[]; 5962306a36Sopenharmony_ci}; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_cistruct ipc_msg_table_entry { 6262306a36Sopenharmony_ci unsigned int handle; 6362306a36Sopenharmony_ci unsigned int type; 6462306a36Sopenharmony_ci wait_queue_head_t wait; 6562306a36Sopenharmony_ci struct hlist_node ipc_table_hlist; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci void *response; 6862306a36Sopenharmony_ci}; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_cistatic struct delayed_work ipc_timer_work; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_cistatic int handle_startup_event(struct sk_buff *skb, struct genl_info *info); 7362306a36Sopenharmony_cistatic int handle_unsupported_event(struct sk_buff *skb, struct genl_info *info); 7462306a36Sopenharmony_cistatic int handle_generic_event(struct sk_buff *skb, struct genl_info *info); 7562306a36Sopenharmony_cistatic int ksmbd_ipc_heartbeat_request(void); 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_cistatic const struct nla_policy ksmbd_nl_policy[KSMBD_EVENT_MAX + 1] = { 7862306a36Sopenharmony_ci [KSMBD_EVENT_UNSPEC] = { 7962306a36Sopenharmony_ci .len = 0, 8062306a36Sopenharmony_ci }, 8162306a36Sopenharmony_ci [KSMBD_EVENT_HEARTBEAT_REQUEST] = { 8262306a36Sopenharmony_ci .len = sizeof(struct ksmbd_heartbeat), 8362306a36Sopenharmony_ci }, 8462306a36Sopenharmony_ci [KSMBD_EVENT_STARTING_UP] = { 8562306a36Sopenharmony_ci .len = sizeof(struct ksmbd_startup_request), 8662306a36Sopenharmony_ci }, 8762306a36Sopenharmony_ci [KSMBD_EVENT_SHUTTING_DOWN] = { 8862306a36Sopenharmony_ci .len = sizeof(struct ksmbd_shutdown_request), 8962306a36Sopenharmony_ci }, 9062306a36Sopenharmony_ci [KSMBD_EVENT_LOGIN_REQUEST] = { 9162306a36Sopenharmony_ci .len = sizeof(struct ksmbd_login_request), 9262306a36Sopenharmony_ci }, 9362306a36Sopenharmony_ci [KSMBD_EVENT_LOGIN_RESPONSE] = { 9462306a36Sopenharmony_ci .len = sizeof(struct ksmbd_login_response), 9562306a36Sopenharmony_ci }, 9662306a36Sopenharmony_ci [KSMBD_EVENT_SHARE_CONFIG_REQUEST] = { 9762306a36Sopenharmony_ci .len = sizeof(struct ksmbd_share_config_request), 9862306a36Sopenharmony_ci }, 9962306a36Sopenharmony_ci [KSMBD_EVENT_SHARE_CONFIG_RESPONSE] = { 10062306a36Sopenharmony_ci .len = sizeof(struct ksmbd_share_config_response), 10162306a36Sopenharmony_ci }, 10262306a36Sopenharmony_ci [KSMBD_EVENT_TREE_CONNECT_REQUEST] = { 10362306a36Sopenharmony_ci .len = sizeof(struct ksmbd_tree_connect_request), 10462306a36Sopenharmony_ci }, 10562306a36Sopenharmony_ci [KSMBD_EVENT_TREE_CONNECT_RESPONSE] = { 10662306a36Sopenharmony_ci .len = sizeof(struct ksmbd_tree_connect_response), 10762306a36Sopenharmony_ci }, 10862306a36Sopenharmony_ci [KSMBD_EVENT_TREE_DISCONNECT_REQUEST] = { 10962306a36Sopenharmony_ci .len = sizeof(struct ksmbd_tree_disconnect_request), 11062306a36Sopenharmony_ci }, 11162306a36Sopenharmony_ci [KSMBD_EVENT_LOGOUT_REQUEST] = { 11262306a36Sopenharmony_ci .len = sizeof(struct ksmbd_logout_request), 11362306a36Sopenharmony_ci }, 11462306a36Sopenharmony_ci [KSMBD_EVENT_RPC_REQUEST] = { 11562306a36Sopenharmony_ci }, 11662306a36Sopenharmony_ci [KSMBD_EVENT_RPC_RESPONSE] = { 11762306a36Sopenharmony_ci }, 11862306a36Sopenharmony_ci [KSMBD_EVENT_SPNEGO_AUTHEN_REQUEST] = { 11962306a36Sopenharmony_ci }, 12062306a36Sopenharmony_ci [KSMBD_EVENT_SPNEGO_AUTHEN_RESPONSE] = { 12162306a36Sopenharmony_ci }, 12262306a36Sopenharmony_ci}; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_cistatic struct genl_ops ksmbd_genl_ops[] = { 12562306a36Sopenharmony_ci { 12662306a36Sopenharmony_ci .cmd = KSMBD_EVENT_UNSPEC, 12762306a36Sopenharmony_ci .doit = handle_unsupported_event, 12862306a36Sopenharmony_ci }, 12962306a36Sopenharmony_ci { 13062306a36Sopenharmony_ci .cmd = KSMBD_EVENT_HEARTBEAT_REQUEST, 13162306a36Sopenharmony_ci .doit = handle_unsupported_event, 13262306a36Sopenharmony_ci }, 13362306a36Sopenharmony_ci { 13462306a36Sopenharmony_ci .cmd = KSMBD_EVENT_STARTING_UP, 13562306a36Sopenharmony_ci .doit = handle_startup_event, 13662306a36Sopenharmony_ci }, 13762306a36Sopenharmony_ci { 13862306a36Sopenharmony_ci .cmd = KSMBD_EVENT_SHUTTING_DOWN, 13962306a36Sopenharmony_ci .doit = handle_unsupported_event, 14062306a36Sopenharmony_ci }, 14162306a36Sopenharmony_ci { 14262306a36Sopenharmony_ci .cmd = KSMBD_EVENT_LOGIN_REQUEST, 14362306a36Sopenharmony_ci .doit = handle_unsupported_event, 14462306a36Sopenharmony_ci }, 14562306a36Sopenharmony_ci { 14662306a36Sopenharmony_ci .cmd = KSMBD_EVENT_LOGIN_RESPONSE, 14762306a36Sopenharmony_ci .doit = handle_generic_event, 14862306a36Sopenharmony_ci }, 14962306a36Sopenharmony_ci { 15062306a36Sopenharmony_ci .cmd = KSMBD_EVENT_SHARE_CONFIG_REQUEST, 15162306a36Sopenharmony_ci .doit = handle_unsupported_event, 15262306a36Sopenharmony_ci }, 15362306a36Sopenharmony_ci { 15462306a36Sopenharmony_ci .cmd = KSMBD_EVENT_SHARE_CONFIG_RESPONSE, 15562306a36Sopenharmony_ci .doit = handle_generic_event, 15662306a36Sopenharmony_ci }, 15762306a36Sopenharmony_ci { 15862306a36Sopenharmony_ci .cmd = KSMBD_EVENT_TREE_CONNECT_REQUEST, 15962306a36Sopenharmony_ci .doit = handle_unsupported_event, 16062306a36Sopenharmony_ci }, 16162306a36Sopenharmony_ci { 16262306a36Sopenharmony_ci .cmd = KSMBD_EVENT_TREE_CONNECT_RESPONSE, 16362306a36Sopenharmony_ci .doit = handle_generic_event, 16462306a36Sopenharmony_ci }, 16562306a36Sopenharmony_ci { 16662306a36Sopenharmony_ci .cmd = KSMBD_EVENT_TREE_DISCONNECT_REQUEST, 16762306a36Sopenharmony_ci .doit = handle_unsupported_event, 16862306a36Sopenharmony_ci }, 16962306a36Sopenharmony_ci { 17062306a36Sopenharmony_ci .cmd = KSMBD_EVENT_LOGOUT_REQUEST, 17162306a36Sopenharmony_ci .doit = handle_unsupported_event, 17262306a36Sopenharmony_ci }, 17362306a36Sopenharmony_ci { 17462306a36Sopenharmony_ci .cmd = KSMBD_EVENT_RPC_REQUEST, 17562306a36Sopenharmony_ci .doit = handle_unsupported_event, 17662306a36Sopenharmony_ci }, 17762306a36Sopenharmony_ci { 17862306a36Sopenharmony_ci .cmd = KSMBD_EVENT_RPC_RESPONSE, 17962306a36Sopenharmony_ci .doit = handle_generic_event, 18062306a36Sopenharmony_ci }, 18162306a36Sopenharmony_ci { 18262306a36Sopenharmony_ci .cmd = KSMBD_EVENT_SPNEGO_AUTHEN_REQUEST, 18362306a36Sopenharmony_ci .doit = handle_unsupported_event, 18462306a36Sopenharmony_ci }, 18562306a36Sopenharmony_ci { 18662306a36Sopenharmony_ci .cmd = KSMBD_EVENT_SPNEGO_AUTHEN_RESPONSE, 18762306a36Sopenharmony_ci .doit = handle_generic_event, 18862306a36Sopenharmony_ci }, 18962306a36Sopenharmony_ci}; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_cistatic struct genl_family ksmbd_genl_family = { 19262306a36Sopenharmony_ci .name = KSMBD_GENL_NAME, 19362306a36Sopenharmony_ci .version = KSMBD_GENL_VERSION, 19462306a36Sopenharmony_ci .hdrsize = 0, 19562306a36Sopenharmony_ci .maxattr = KSMBD_EVENT_MAX, 19662306a36Sopenharmony_ci .netnsok = true, 19762306a36Sopenharmony_ci .module = THIS_MODULE, 19862306a36Sopenharmony_ci .ops = ksmbd_genl_ops, 19962306a36Sopenharmony_ci .n_ops = ARRAY_SIZE(ksmbd_genl_ops), 20062306a36Sopenharmony_ci .resv_start_op = KSMBD_EVENT_SPNEGO_AUTHEN_RESPONSE + 1, 20162306a36Sopenharmony_ci}; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_cistatic void ksmbd_nl_init_fixup(void) 20462306a36Sopenharmony_ci{ 20562306a36Sopenharmony_ci int i; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(ksmbd_genl_ops); i++) 20862306a36Sopenharmony_ci ksmbd_genl_ops[i].validate = GENL_DONT_VALIDATE_STRICT | 20962306a36Sopenharmony_ci GENL_DONT_VALIDATE_DUMP; 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci ksmbd_genl_family.policy = ksmbd_nl_policy; 21262306a36Sopenharmony_ci} 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_cistatic int rpc_context_flags(struct ksmbd_session *sess) 21562306a36Sopenharmony_ci{ 21662306a36Sopenharmony_ci if (user_guest(sess->user)) 21762306a36Sopenharmony_ci return KSMBD_RPC_RESTRICTED_CONTEXT; 21862306a36Sopenharmony_ci return 0; 21962306a36Sopenharmony_ci} 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_cistatic void ipc_update_last_active(void) 22262306a36Sopenharmony_ci{ 22362306a36Sopenharmony_ci if (server_conf.ipc_timeout) 22462306a36Sopenharmony_ci server_conf.ipc_last_active = jiffies; 22562306a36Sopenharmony_ci} 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_cistatic struct ksmbd_ipc_msg *ipc_msg_alloc(size_t sz) 22862306a36Sopenharmony_ci{ 22962306a36Sopenharmony_ci struct ksmbd_ipc_msg *msg; 23062306a36Sopenharmony_ci size_t msg_sz = sz + sizeof(struct ksmbd_ipc_msg); 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci msg = kvzalloc(msg_sz, GFP_KERNEL); 23362306a36Sopenharmony_ci if (msg) 23462306a36Sopenharmony_ci msg->sz = sz; 23562306a36Sopenharmony_ci return msg; 23662306a36Sopenharmony_ci} 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_cistatic void ipc_msg_free(struct ksmbd_ipc_msg *msg) 23962306a36Sopenharmony_ci{ 24062306a36Sopenharmony_ci kvfree(msg); 24162306a36Sopenharmony_ci} 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_cistatic void ipc_msg_handle_free(int handle) 24462306a36Sopenharmony_ci{ 24562306a36Sopenharmony_ci if (handle >= 0) 24662306a36Sopenharmony_ci ksmbd_release_id(&ipc_ida, handle); 24762306a36Sopenharmony_ci} 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_cistatic int handle_response(int type, void *payload, size_t sz) 25062306a36Sopenharmony_ci{ 25162306a36Sopenharmony_ci unsigned int handle = *(unsigned int *)payload; 25262306a36Sopenharmony_ci struct ipc_msg_table_entry *entry; 25362306a36Sopenharmony_ci int ret = 0; 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci ipc_update_last_active(); 25662306a36Sopenharmony_ci down_read(&ipc_msg_table_lock); 25762306a36Sopenharmony_ci hash_for_each_possible(ipc_msg_table, entry, ipc_table_hlist, handle) { 25862306a36Sopenharmony_ci if (handle != entry->handle) 25962306a36Sopenharmony_ci continue; 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci entry->response = NULL; 26262306a36Sopenharmony_ci /* 26362306a36Sopenharmony_ci * Response message type value should be equal to 26462306a36Sopenharmony_ci * request message type + 1. 26562306a36Sopenharmony_ci */ 26662306a36Sopenharmony_ci if (entry->type + 1 != type) { 26762306a36Sopenharmony_ci pr_err("Waiting for IPC type %d, got %d. Ignore.\n", 26862306a36Sopenharmony_ci entry->type + 1, type); 26962306a36Sopenharmony_ci } 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci entry->response = kvzalloc(sz, GFP_KERNEL); 27262306a36Sopenharmony_ci if (!entry->response) { 27362306a36Sopenharmony_ci ret = -ENOMEM; 27462306a36Sopenharmony_ci break; 27562306a36Sopenharmony_ci } 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci memcpy(entry->response, payload, sz); 27862306a36Sopenharmony_ci wake_up_interruptible(&entry->wait); 27962306a36Sopenharmony_ci ret = 0; 28062306a36Sopenharmony_ci break; 28162306a36Sopenharmony_ci } 28262306a36Sopenharmony_ci up_read(&ipc_msg_table_lock); 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci return ret; 28562306a36Sopenharmony_ci} 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_cistatic int ipc_server_config_on_startup(struct ksmbd_startup_request *req) 28862306a36Sopenharmony_ci{ 28962306a36Sopenharmony_ci int ret; 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci ksmbd_set_fd_limit(req->file_max); 29262306a36Sopenharmony_ci server_conf.flags = req->flags; 29362306a36Sopenharmony_ci server_conf.signing = req->signing; 29462306a36Sopenharmony_ci server_conf.tcp_port = req->tcp_port; 29562306a36Sopenharmony_ci server_conf.ipc_timeout = req->ipc_timeout * HZ; 29662306a36Sopenharmony_ci server_conf.deadtime = req->deadtime * SMB_ECHO_INTERVAL; 29762306a36Sopenharmony_ci server_conf.share_fake_fscaps = req->share_fake_fscaps; 29862306a36Sopenharmony_ci ksmbd_init_domain(req->sub_auth); 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci if (req->smb2_max_read) 30162306a36Sopenharmony_ci init_smb2_max_read_size(req->smb2_max_read); 30262306a36Sopenharmony_ci if (req->smb2_max_write) 30362306a36Sopenharmony_ci init_smb2_max_write_size(req->smb2_max_write); 30462306a36Sopenharmony_ci if (req->smb2_max_trans) 30562306a36Sopenharmony_ci init_smb2_max_trans_size(req->smb2_max_trans); 30662306a36Sopenharmony_ci if (req->smb2_max_credits) 30762306a36Sopenharmony_ci init_smb2_max_credits(req->smb2_max_credits); 30862306a36Sopenharmony_ci if (req->smbd_max_io_size) 30962306a36Sopenharmony_ci init_smbd_max_io_size(req->smbd_max_io_size); 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci if (req->max_connections) 31262306a36Sopenharmony_ci server_conf.max_connections = req->max_connections; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci ret = ksmbd_set_netbios_name(req->netbios_name); 31562306a36Sopenharmony_ci ret |= ksmbd_set_server_string(req->server_string); 31662306a36Sopenharmony_ci ret |= ksmbd_set_work_group(req->work_group); 31762306a36Sopenharmony_ci ret |= ksmbd_tcp_set_interfaces(KSMBD_STARTUP_CONFIG_INTERFACES(req), 31862306a36Sopenharmony_ci req->ifc_list_sz); 31962306a36Sopenharmony_ci if (ret) { 32062306a36Sopenharmony_ci pr_err("Server configuration error: %s %s %s\n", 32162306a36Sopenharmony_ci req->netbios_name, req->server_string, 32262306a36Sopenharmony_ci req->work_group); 32362306a36Sopenharmony_ci return ret; 32462306a36Sopenharmony_ci } 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci if (req->min_prot[0]) { 32762306a36Sopenharmony_ci ret = ksmbd_lookup_protocol_idx(req->min_prot); 32862306a36Sopenharmony_ci if (ret >= 0) 32962306a36Sopenharmony_ci server_conf.min_protocol = ret; 33062306a36Sopenharmony_ci } 33162306a36Sopenharmony_ci if (req->max_prot[0]) { 33262306a36Sopenharmony_ci ret = ksmbd_lookup_protocol_idx(req->max_prot); 33362306a36Sopenharmony_ci if (ret >= 0) 33462306a36Sopenharmony_ci server_conf.max_protocol = ret; 33562306a36Sopenharmony_ci } 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci if (server_conf.ipc_timeout) 33862306a36Sopenharmony_ci schedule_delayed_work(&ipc_timer_work, server_conf.ipc_timeout); 33962306a36Sopenharmony_ci return 0; 34062306a36Sopenharmony_ci} 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_cistatic int handle_startup_event(struct sk_buff *skb, struct genl_info *info) 34362306a36Sopenharmony_ci{ 34462306a36Sopenharmony_ci int ret = 0; 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci#ifdef CONFIG_SMB_SERVER_CHECK_CAP_NET_ADMIN 34762306a36Sopenharmony_ci if (!netlink_capable(skb, CAP_NET_ADMIN)) 34862306a36Sopenharmony_ci return -EPERM; 34962306a36Sopenharmony_ci#endif 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci if (!ksmbd_ipc_validate_version(info)) 35262306a36Sopenharmony_ci return -EINVAL; 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci if (!info->attrs[KSMBD_EVENT_STARTING_UP]) 35562306a36Sopenharmony_ci return -EINVAL; 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci mutex_lock(&startup_lock); 35862306a36Sopenharmony_ci if (!ksmbd_server_configurable()) { 35962306a36Sopenharmony_ci mutex_unlock(&startup_lock); 36062306a36Sopenharmony_ci pr_err("Server reset is in progress, can't start daemon\n"); 36162306a36Sopenharmony_ci return -EINVAL; 36262306a36Sopenharmony_ci } 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci if (ksmbd_tools_pid) { 36562306a36Sopenharmony_ci if (ksmbd_ipc_heartbeat_request() == 0) { 36662306a36Sopenharmony_ci ret = -EINVAL; 36762306a36Sopenharmony_ci goto out; 36862306a36Sopenharmony_ci } 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci pr_err("Reconnect to a new user space daemon\n"); 37162306a36Sopenharmony_ci } else { 37262306a36Sopenharmony_ci struct ksmbd_startup_request *req; 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci req = nla_data(info->attrs[info->genlhdr->cmd]); 37562306a36Sopenharmony_ci ret = ipc_server_config_on_startup(req); 37662306a36Sopenharmony_ci if (ret) 37762306a36Sopenharmony_ci goto out; 37862306a36Sopenharmony_ci server_queue_ctrl_init_work(); 37962306a36Sopenharmony_ci } 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci ksmbd_tools_pid = info->snd_portid; 38262306a36Sopenharmony_ci ipc_update_last_active(); 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ciout: 38562306a36Sopenharmony_ci mutex_unlock(&startup_lock); 38662306a36Sopenharmony_ci return ret; 38762306a36Sopenharmony_ci} 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_cistatic int handle_unsupported_event(struct sk_buff *skb, struct genl_info *info) 39062306a36Sopenharmony_ci{ 39162306a36Sopenharmony_ci pr_err("Unknown IPC event: %d, ignore.\n", info->genlhdr->cmd); 39262306a36Sopenharmony_ci return -EINVAL; 39362306a36Sopenharmony_ci} 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_cistatic int handle_generic_event(struct sk_buff *skb, struct genl_info *info) 39662306a36Sopenharmony_ci{ 39762306a36Sopenharmony_ci void *payload; 39862306a36Sopenharmony_ci int sz; 39962306a36Sopenharmony_ci int type = info->genlhdr->cmd; 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci#ifdef CONFIG_SMB_SERVER_CHECK_CAP_NET_ADMIN 40262306a36Sopenharmony_ci if (!netlink_capable(skb, CAP_NET_ADMIN)) 40362306a36Sopenharmony_ci return -EPERM; 40462306a36Sopenharmony_ci#endif 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci if (type > KSMBD_EVENT_MAX) { 40762306a36Sopenharmony_ci WARN_ON(1); 40862306a36Sopenharmony_ci return -EINVAL; 40962306a36Sopenharmony_ci } 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci if (!ksmbd_ipc_validate_version(info)) 41262306a36Sopenharmony_ci return -EINVAL; 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci if (!info->attrs[type]) 41562306a36Sopenharmony_ci return -EINVAL; 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci payload = nla_data(info->attrs[info->genlhdr->cmd]); 41862306a36Sopenharmony_ci sz = nla_len(info->attrs[info->genlhdr->cmd]); 41962306a36Sopenharmony_ci return handle_response(type, payload, sz); 42062306a36Sopenharmony_ci} 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_cistatic int ipc_msg_send(struct ksmbd_ipc_msg *msg) 42362306a36Sopenharmony_ci{ 42462306a36Sopenharmony_ci struct genlmsghdr *nlh; 42562306a36Sopenharmony_ci struct sk_buff *skb; 42662306a36Sopenharmony_ci int ret = -EINVAL; 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci if (!ksmbd_tools_pid) 42962306a36Sopenharmony_ci return ret; 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci skb = genlmsg_new(msg->sz, GFP_KERNEL); 43262306a36Sopenharmony_ci if (!skb) 43362306a36Sopenharmony_ci return -ENOMEM; 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci nlh = genlmsg_put(skb, 0, 0, &ksmbd_genl_family, 0, msg->type); 43662306a36Sopenharmony_ci if (!nlh) 43762306a36Sopenharmony_ci goto out; 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci ret = nla_put(skb, msg->type, msg->sz, msg->payload); 44062306a36Sopenharmony_ci if (ret) { 44162306a36Sopenharmony_ci genlmsg_cancel(skb, nlh); 44262306a36Sopenharmony_ci goto out; 44362306a36Sopenharmony_ci } 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci genlmsg_end(skb, nlh); 44662306a36Sopenharmony_ci ret = genlmsg_unicast(&init_net, skb, ksmbd_tools_pid); 44762306a36Sopenharmony_ci if (!ret) 44862306a36Sopenharmony_ci ipc_update_last_active(); 44962306a36Sopenharmony_ci return ret; 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ciout: 45262306a36Sopenharmony_ci nlmsg_free(skb); 45362306a36Sopenharmony_ci return ret; 45462306a36Sopenharmony_ci} 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_cistatic void *ipc_msg_send_request(struct ksmbd_ipc_msg *msg, unsigned int handle) 45762306a36Sopenharmony_ci{ 45862306a36Sopenharmony_ci struct ipc_msg_table_entry entry; 45962306a36Sopenharmony_ci int ret; 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci if ((int)handle < 0) 46262306a36Sopenharmony_ci return NULL; 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci entry.type = msg->type; 46562306a36Sopenharmony_ci entry.response = NULL; 46662306a36Sopenharmony_ci init_waitqueue_head(&entry.wait); 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci down_write(&ipc_msg_table_lock); 46962306a36Sopenharmony_ci entry.handle = handle; 47062306a36Sopenharmony_ci hash_add(ipc_msg_table, &entry.ipc_table_hlist, entry.handle); 47162306a36Sopenharmony_ci up_write(&ipc_msg_table_lock); 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci ret = ipc_msg_send(msg); 47462306a36Sopenharmony_ci if (ret) 47562306a36Sopenharmony_ci goto out; 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci ret = wait_event_interruptible_timeout(entry.wait, 47862306a36Sopenharmony_ci entry.response != NULL, 47962306a36Sopenharmony_ci IPC_WAIT_TIMEOUT); 48062306a36Sopenharmony_ciout: 48162306a36Sopenharmony_ci down_write(&ipc_msg_table_lock); 48262306a36Sopenharmony_ci hash_del(&entry.ipc_table_hlist); 48362306a36Sopenharmony_ci up_write(&ipc_msg_table_lock); 48462306a36Sopenharmony_ci return entry.response; 48562306a36Sopenharmony_ci} 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_cistatic int ksmbd_ipc_heartbeat_request(void) 48862306a36Sopenharmony_ci{ 48962306a36Sopenharmony_ci struct ksmbd_ipc_msg *msg; 49062306a36Sopenharmony_ci int ret; 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci msg = ipc_msg_alloc(sizeof(struct ksmbd_heartbeat)); 49362306a36Sopenharmony_ci if (!msg) 49462306a36Sopenharmony_ci return -EINVAL; 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci msg->type = KSMBD_EVENT_HEARTBEAT_REQUEST; 49762306a36Sopenharmony_ci ret = ipc_msg_send(msg); 49862306a36Sopenharmony_ci ipc_msg_free(msg); 49962306a36Sopenharmony_ci return ret; 50062306a36Sopenharmony_ci} 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_cistruct ksmbd_login_response *ksmbd_ipc_login_request(const char *account) 50362306a36Sopenharmony_ci{ 50462306a36Sopenharmony_ci struct ksmbd_ipc_msg *msg; 50562306a36Sopenharmony_ci struct ksmbd_login_request *req; 50662306a36Sopenharmony_ci struct ksmbd_login_response *resp; 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci if (strlen(account) >= KSMBD_REQ_MAX_ACCOUNT_NAME_SZ) 50962306a36Sopenharmony_ci return NULL; 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci msg = ipc_msg_alloc(sizeof(struct ksmbd_login_request)); 51262306a36Sopenharmony_ci if (!msg) 51362306a36Sopenharmony_ci return NULL; 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci msg->type = KSMBD_EVENT_LOGIN_REQUEST; 51662306a36Sopenharmony_ci req = (struct ksmbd_login_request *)msg->payload; 51762306a36Sopenharmony_ci req->handle = ksmbd_acquire_id(&ipc_ida); 51862306a36Sopenharmony_ci strscpy(req->account, account, KSMBD_REQ_MAX_ACCOUNT_NAME_SZ); 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci resp = ipc_msg_send_request(msg, req->handle); 52162306a36Sopenharmony_ci ipc_msg_handle_free(req->handle); 52262306a36Sopenharmony_ci ipc_msg_free(msg); 52362306a36Sopenharmony_ci return resp; 52462306a36Sopenharmony_ci} 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_cistruct ksmbd_spnego_authen_response * 52762306a36Sopenharmony_ciksmbd_ipc_spnego_authen_request(const char *spnego_blob, int blob_len) 52862306a36Sopenharmony_ci{ 52962306a36Sopenharmony_ci struct ksmbd_ipc_msg *msg; 53062306a36Sopenharmony_ci struct ksmbd_spnego_authen_request *req; 53162306a36Sopenharmony_ci struct ksmbd_spnego_authen_response *resp; 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci msg = ipc_msg_alloc(sizeof(struct ksmbd_spnego_authen_request) + 53462306a36Sopenharmony_ci blob_len + 1); 53562306a36Sopenharmony_ci if (!msg) 53662306a36Sopenharmony_ci return NULL; 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci msg->type = KSMBD_EVENT_SPNEGO_AUTHEN_REQUEST; 53962306a36Sopenharmony_ci req = (struct ksmbd_spnego_authen_request *)msg->payload; 54062306a36Sopenharmony_ci req->handle = ksmbd_acquire_id(&ipc_ida); 54162306a36Sopenharmony_ci req->spnego_blob_len = blob_len; 54262306a36Sopenharmony_ci memcpy(req->spnego_blob, spnego_blob, blob_len); 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci resp = ipc_msg_send_request(msg, req->handle); 54562306a36Sopenharmony_ci ipc_msg_handle_free(req->handle); 54662306a36Sopenharmony_ci ipc_msg_free(msg); 54762306a36Sopenharmony_ci return resp; 54862306a36Sopenharmony_ci} 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_cistruct ksmbd_tree_connect_response * 55162306a36Sopenharmony_ciksmbd_ipc_tree_connect_request(struct ksmbd_session *sess, 55262306a36Sopenharmony_ci struct ksmbd_share_config *share, 55362306a36Sopenharmony_ci struct ksmbd_tree_connect *tree_conn, 55462306a36Sopenharmony_ci struct sockaddr *peer_addr) 55562306a36Sopenharmony_ci{ 55662306a36Sopenharmony_ci struct ksmbd_ipc_msg *msg; 55762306a36Sopenharmony_ci struct ksmbd_tree_connect_request *req; 55862306a36Sopenharmony_ci struct ksmbd_tree_connect_response *resp; 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci if (strlen(user_name(sess->user)) >= KSMBD_REQ_MAX_ACCOUNT_NAME_SZ) 56162306a36Sopenharmony_ci return NULL; 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci if (strlen(share->name) >= KSMBD_REQ_MAX_SHARE_NAME) 56462306a36Sopenharmony_ci return NULL; 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci msg = ipc_msg_alloc(sizeof(struct ksmbd_tree_connect_request)); 56762306a36Sopenharmony_ci if (!msg) 56862306a36Sopenharmony_ci return NULL; 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci msg->type = KSMBD_EVENT_TREE_CONNECT_REQUEST; 57162306a36Sopenharmony_ci req = (struct ksmbd_tree_connect_request *)msg->payload; 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci req->handle = ksmbd_acquire_id(&ipc_ida); 57462306a36Sopenharmony_ci req->account_flags = sess->user->flags; 57562306a36Sopenharmony_ci req->session_id = sess->id; 57662306a36Sopenharmony_ci req->connect_id = tree_conn->id; 57762306a36Sopenharmony_ci strscpy(req->account, user_name(sess->user), KSMBD_REQ_MAX_ACCOUNT_NAME_SZ); 57862306a36Sopenharmony_ci strscpy(req->share, share->name, KSMBD_REQ_MAX_SHARE_NAME); 57962306a36Sopenharmony_ci snprintf(req->peer_addr, sizeof(req->peer_addr), "%pIS", peer_addr); 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci if (peer_addr->sa_family == AF_INET6) 58262306a36Sopenharmony_ci req->flags |= KSMBD_TREE_CONN_FLAG_REQUEST_IPV6; 58362306a36Sopenharmony_ci if (test_session_flag(sess, CIFDS_SESSION_FLAG_SMB2)) 58462306a36Sopenharmony_ci req->flags |= KSMBD_TREE_CONN_FLAG_REQUEST_SMB2; 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci resp = ipc_msg_send_request(msg, req->handle); 58762306a36Sopenharmony_ci ipc_msg_handle_free(req->handle); 58862306a36Sopenharmony_ci ipc_msg_free(msg); 58962306a36Sopenharmony_ci return resp; 59062306a36Sopenharmony_ci} 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ciint ksmbd_ipc_tree_disconnect_request(unsigned long long session_id, 59362306a36Sopenharmony_ci unsigned long long connect_id) 59462306a36Sopenharmony_ci{ 59562306a36Sopenharmony_ci struct ksmbd_ipc_msg *msg; 59662306a36Sopenharmony_ci struct ksmbd_tree_disconnect_request *req; 59762306a36Sopenharmony_ci int ret; 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci msg = ipc_msg_alloc(sizeof(struct ksmbd_tree_disconnect_request)); 60062306a36Sopenharmony_ci if (!msg) 60162306a36Sopenharmony_ci return -ENOMEM; 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci msg->type = KSMBD_EVENT_TREE_DISCONNECT_REQUEST; 60462306a36Sopenharmony_ci req = (struct ksmbd_tree_disconnect_request *)msg->payload; 60562306a36Sopenharmony_ci req->session_id = session_id; 60662306a36Sopenharmony_ci req->connect_id = connect_id; 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci ret = ipc_msg_send(msg); 60962306a36Sopenharmony_ci ipc_msg_free(msg); 61062306a36Sopenharmony_ci return ret; 61162306a36Sopenharmony_ci} 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ciint ksmbd_ipc_logout_request(const char *account, int flags) 61462306a36Sopenharmony_ci{ 61562306a36Sopenharmony_ci struct ksmbd_ipc_msg *msg; 61662306a36Sopenharmony_ci struct ksmbd_logout_request *req; 61762306a36Sopenharmony_ci int ret; 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci if (strlen(account) >= KSMBD_REQ_MAX_ACCOUNT_NAME_SZ) 62062306a36Sopenharmony_ci return -EINVAL; 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci msg = ipc_msg_alloc(sizeof(struct ksmbd_logout_request)); 62362306a36Sopenharmony_ci if (!msg) 62462306a36Sopenharmony_ci return -ENOMEM; 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci msg->type = KSMBD_EVENT_LOGOUT_REQUEST; 62762306a36Sopenharmony_ci req = (struct ksmbd_logout_request *)msg->payload; 62862306a36Sopenharmony_ci req->account_flags = flags; 62962306a36Sopenharmony_ci strscpy(req->account, account, KSMBD_REQ_MAX_ACCOUNT_NAME_SZ); 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci ret = ipc_msg_send(msg); 63262306a36Sopenharmony_ci ipc_msg_free(msg); 63362306a36Sopenharmony_ci return ret; 63462306a36Sopenharmony_ci} 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_cistruct ksmbd_share_config_response * 63762306a36Sopenharmony_ciksmbd_ipc_share_config_request(const char *name) 63862306a36Sopenharmony_ci{ 63962306a36Sopenharmony_ci struct ksmbd_ipc_msg *msg; 64062306a36Sopenharmony_ci struct ksmbd_share_config_request *req; 64162306a36Sopenharmony_ci struct ksmbd_share_config_response *resp; 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci if (strlen(name) >= KSMBD_REQ_MAX_SHARE_NAME) 64462306a36Sopenharmony_ci return NULL; 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci msg = ipc_msg_alloc(sizeof(struct ksmbd_share_config_request)); 64762306a36Sopenharmony_ci if (!msg) 64862306a36Sopenharmony_ci return NULL; 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci msg->type = KSMBD_EVENT_SHARE_CONFIG_REQUEST; 65162306a36Sopenharmony_ci req = (struct ksmbd_share_config_request *)msg->payload; 65262306a36Sopenharmony_ci req->handle = ksmbd_acquire_id(&ipc_ida); 65362306a36Sopenharmony_ci strscpy(req->share_name, name, KSMBD_REQ_MAX_SHARE_NAME); 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci resp = ipc_msg_send_request(msg, req->handle); 65662306a36Sopenharmony_ci ipc_msg_handle_free(req->handle); 65762306a36Sopenharmony_ci ipc_msg_free(msg); 65862306a36Sopenharmony_ci return resp; 65962306a36Sopenharmony_ci} 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_cistruct ksmbd_rpc_command *ksmbd_rpc_open(struct ksmbd_session *sess, int handle) 66262306a36Sopenharmony_ci{ 66362306a36Sopenharmony_ci struct ksmbd_ipc_msg *msg; 66462306a36Sopenharmony_ci struct ksmbd_rpc_command *req; 66562306a36Sopenharmony_ci struct ksmbd_rpc_command *resp; 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci msg = ipc_msg_alloc(sizeof(struct ksmbd_rpc_command)); 66862306a36Sopenharmony_ci if (!msg) 66962306a36Sopenharmony_ci return NULL; 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci msg->type = KSMBD_EVENT_RPC_REQUEST; 67262306a36Sopenharmony_ci req = (struct ksmbd_rpc_command *)msg->payload; 67362306a36Sopenharmony_ci req->handle = handle; 67462306a36Sopenharmony_ci req->flags = ksmbd_session_rpc_method(sess, handle); 67562306a36Sopenharmony_ci req->flags |= KSMBD_RPC_OPEN_METHOD; 67662306a36Sopenharmony_ci req->payload_sz = 0; 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci resp = ipc_msg_send_request(msg, req->handle); 67962306a36Sopenharmony_ci ipc_msg_free(msg); 68062306a36Sopenharmony_ci return resp; 68162306a36Sopenharmony_ci} 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_cistruct ksmbd_rpc_command *ksmbd_rpc_close(struct ksmbd_session *sess, int handle) 68462306a36Sopenharmony_ci{ 68562306a36Sopenharmony_ci struct ksmbd_ipc_msg *msg; 68662306a36Sopenharmony_ci struct ksmbd_rpc_command *req; 68762306a36Sopenharmony_ci struct ksmbd_rpc_command *resp; 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci msg = ipc_msg_alloc(sizeof(struct ksmbd_rpc_command)); 69062306a36Sopenharmony_ci if (!msg) 69162306a36Sopenharmony_ci return NULL; 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci msg->type = KSMBD_EVENT_RPC_REQUEST; 69462306a36Sopenharmony_ci req = (struct ksmbd_rpc_command *)msg->payload; 69562306a36Sopenharmony_ci req->handle = handle; 69662306a36Sopenharmony_ci req->flags = ksmbd_session_rpc_method(sess, handle); 69762306a36Sopenharmony_ci req->flags |= KSMBD_RPC_CLOSE_METHOD; 69862306a36Sopenharmony_ci req->payload_sz = 0; 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci resp = ipc_msg_send_request(msg, req->handle); 70162306a36Sopenharmony_ci ipc_msg_free(msg); 70262306a36Sopenharmony_ci return resp; 70362306a36Sopenharmony_ci} 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_cistruct ksmbd_rpc_command *ksmbd_rpc_write(struct ksmbd_session *sess, int handle, 70662306a36Sopenharmony_ci void *payload, size_t payload_sz) 70762306a36Sopenharmony_ci{ 70862306a36Sopenharmony_ci struct ksmbd_ipc_msg *msg; 70962306a36Sopenharmony_ci struct ksmbd_rpc_command *req; 71062306a36Sopenharmony_ci struct ksmbd_rpc_command *resp; 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci msg = ipc_msg_alloc(sizeof(struct ksmbd_rpc_command) + payload_sz + 1); 71362306a36Sopenharmony_ci if (!msg) 71462306a36Sopenharmony_ci return NULL; 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci msg->type = KSMBD_EVENT_RPC_REQUEST; 71762306a36Sopenharmony_ci req = (struct ksmbd_rpc_command *)msg->payload; 71862306a36Sopenharmony_ci req->handle = handle; 71962306a36Sopenharmony_ci req->flags = ksmbd_session_rpc_method(sess, handle); 72062306a36Sopenharmony_ci req->flags |= rpc_context_flags(sess); 72162306a36Sopenharmony_ci req->flags |= KSMBD_RPC_WRITE_METHOD; 72262306a36Sopenharmony_ci req->payload_sz = payload_sz; 72362306a36Sopenharmony_ci memcpy(req->payload, payload, payload_sz); 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci resp = ipc_msg_send_request(msg, req->handle); 72662306a36Sopenharmony_ci ipc_msg_free(msg); 72762306a36Sopenharmony_ci return resp; 72862306a36Sopenharmony_ci} 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_cistruct ksmbd_rpc_command *ksmbd_rpc_read(struct ksmbd_session *sess, int handle) 73162306a36Sopenharmony_ci{ 73262306a36Sopenharmony_ci struct ksmbd_ipc_msg *msg; 73362306a36Sopenharmony_ci struct ksmbd_rpc_command *req; 73462306a36Sopenharmony_ci struct ksmbd_rpc_command *resp; 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci msg = ipc_msg_alloc(sizeof(struct ksmbd_rpc_command)); 73762306a36Sopenharmony_ci if (!msg) 73862306a36Sopenharmony_ci return NULL; 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci msg->type = KSMBD_EVENT_RPC_REQUEST; 74162306a36Sopenharmony_ci req = (struct ksmbd_rpc_command *)msg->payload; 74262306a36Sopenharmony_ci req->handle = handle; 74362306a36Sopenharmony_ci req->flags = ksmbd_session_rpc_method(sess, handle); 74462306a36Sopenharmony_ci req->flags |= rpc_context_flags(sess); 74562306a36Sopenharmony_ci req->flags |= KSMBD_RPC_READ_METHOD; 74662306a36Sopenharmony_ci req->payload_sz = 0; 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci resp = ipc_msg_send_request(msg, req->handle); 74962306a36Sopenharmony_ci ipc_msg_free(msg); 75062306a36Sopenharmony_ci return resp; 75162306a36Sopenharmony_ci} 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_cistruct ksmbd_rpc_command *ksmbd_rpc_ioctl(struct ksmbd_session *sess, int handle, 75462306a36Sopenharmony_ci void *payload, size_t payload_sz) 75562306a36Sopenharmony_ci{ 75662306a36Sopenharmony_ci struct ksmbd_ipc_msg *msg; 75762306a36Sopenharmony_ci struct ksmbd_rpc_command *req; 75862306a36Sopenharmony_ci struct ksmbd_rpc_command *resp; 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci msg = ipc_msg_alloc(sizeof(struct ksmbd_rpc_command) + payload_sz + 1); 76162306a36Sopenharmony_ci if (!msg) 76262306a36Sopenharmony_ci return NULL; 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci msg->type = KSMBD_EVENT_RPC_REQUEST; 76562306a36Sopenharmony_ci req = (struct ksmbd_rpc_command *)msg->payload; 76662306a36Sopenharmony_ci req->handle = handle; 76762306a36Sopenharmony_ci req->flags = ksmbd_session_rpc_method(sess, handle); 76862306a36Sopenharmony_ci req->flags |= rpc_context_flags(sess); 76962306a36Sopenharmony_ci req->flags |= KSMBD_RPC_IOCTL_METHOD; 77062306a36Sopenharmony_ci req->payload_sz = payload_sz; 77162306a36Sopenharmony_ci memcpy(req->payload, payload, payload_sz); 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci resp = ipc_msg_send_request(msg, req->handle); 77462306a36Sopenharmony_ci ipc_msg_free(msg); 77562306a36Sopenharmony_ci return resp; 77662306a36Sopenharmony_ci} 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_cistruct ksmbd_rpc_command *ksmbd_rpc_rap(struct ksmbd_session *sess, void *payload, 77962306a36Sopenharmony_ci size_t payload_sz) 78062306a36Sopenharmony_ci{ 78162306a36Sopenharmony_ci struct ksmbd_ipc_msg *msg; 78262306a36Sopenharmony_ci struct ksmbd_rpc_command *req; 78362306a36Sopenharmony_ci struct ksmbd_rpc_command *resp; 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci msg = ipc_msg_alloc(sizeof(struct ksmbd_rpc_command) + payload_sz + 1); 78662306a36Sopenharmony_ci if (!msg) 78762306a36Sopenharmony_ci return NULL; 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci msg->type = KSMBD_EVENT_RPC_REQUEST; 79062306a36Sopenharmony_ci req = (struct ksmbd_rpc_command *)msg->payload; 79162306a36Sopenharmony_ci req->handle = ksmbd_acquire_id(&ipc_ida); 79262306a36Sopenharmony_ci req->flags = rpc_context_flags(sess); 79362306a36Sopenharmony_ci req->flags |= KSMBD_RPC_RAP_METHOD; 79462306a36Sopenharmony_ci req->payload_sz = payload_sz; 79562306a36Sopenharmony_ci memcpy(req->payload, payload, payload_sz); 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ci resp = ipc_msg_send_request(msg, req->handle); 79862306a36Sopenharmony_ci ipc_msg_handle_free(req->handle); 79962306a36Sopenharmony_ci ipc_msg_free(msg); 80062306a36Sopenharmony_ci return resp; 80162306a36Sopenharmony_ci} 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_cistatic int __ipc_heartbeat(void) 80462306a36Sopenharmony_ci{ 80562306a36Sopenharmony_ci unsigned long delta; 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_ci if (!ksmbd_server_running()) 80862306a36Sopenharmony_ci return 0; 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_ci if (time_after(jiffies, server_conf.ipc_last_active)) { 81162306a36Sopenharmony_ci delta = (jiffies - server_conf.ipc_last_active); 81262306a36Sopenharmony_ci } else { 81362306a36Sopenharmony_ci ipc_update_last_active(); 81462306a36Sopenharmony_ci schedule_delayed_work(&ipc_timer_work, 81562306a36Sopenharmony_ci server_conf.ipc_timeout); 81662306a36Sopenharmony_ci return 0; 81762306a36Sopenharmony_ci } 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci if (delta < server_conf.ipc_timeout) { 82062306a36Sopenharmony_ci schedule_delayed_work(&ipc_timer_work, 82162306a36Sopenharmony_ci server_conf.ipc_timeout - delta); 82262306a36Sopenharmony_ci return 0; 82362306a36Sopenharmony_ci } 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_ci if (ksmbd_ipc_heartbeat_request() == 0) { 82662306a36Sopenharmony_ci schedule_delayed_work(&ipc_timer_work, 82762306a36Sopenharmony_ci server_conf.ipc_timeout); 82862306a36Sopenharmony_ci return 0; 82962306a36Sopenharmony_ci } 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci mutex_lock(&startup_lock); 83262306a36Sopenharmony_ci WRITE_ONCE(server_conf.state, SERVER_STATE_RESETTING); 83362306a36Sopenharmony_ci server_conf.ipc_last_active = 0; 83462306a36Sopenharmony_ci ksmbd_tools_pid = 0; 83562306a36Sopenharmony_ci pr_err("No IPC daemon response for %lus\n", delta / HZ); 83662306a36Sopenharmony_ci mutex_unlock(&startup_lock); 83762306a36Sopenharmony_ci return -EINVAL; 83862306a36Sopenharmony_ci} 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_cistatic void ipc_timer_heartbeat(struct work_struct *w) 84162306a36Sopenharmony_ci{ 84262306a36Sopenharmony_ci if (__ipc_heartbeat()) 84362306a36Sopenharmony_ci server_queue_ctrl_reset_work(); 84462306a36Sopenharmony_ci} 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ciint ksmbd_ipc_id_alloc(void) 84762306a36Sopenharmony_ci{ 84862306a36Sopenharmony_ci return ksmbd_acquire_id(&ipc_ida); 84962306a36Sopenharmony_ci} 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_civoid ksmbd_rpc_id_free(int handle) 85262306a36Sopenharmony_ci{ 85362306a36Sopenharmony_ci ksmbd_release_id(&ipc_ida, handle); 85462306a36Sopenharmony_ci} 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_civoid ksmbd_ipc_release(void) 85762306a36Sopenharmony_ci{ 85862306a36Sopenharmony_ci cancel_delayed_work_sync(&ipc_timer_work); 85962306a36Sopenharmony_ci genl_unregister_family(&ksmbd_genl_family); 86062306a36Sopenharmony_ci} 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_civoid ksmbd_ipc_soft_reset(void) 86362306a36Sopenharmony_ci{ 86462306a36Sopenharmony_ci mutex_lock(&startup_lock); 86562306a36Sopenharmony_ci ksmbd_tools_pid = 0; 86662306a36Sopenharmony_ci cancel_delayed_work_sync(&ipc_timer_work); 86762306a36Sopenharmony_ci mutex_unlock(&startup_lock); 86862306a36Sopenharmony_ci} 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_ciint ksmbd_ipc_init(void) 87162306a36Sopenharmony_ci{ 87262306a36Sopenharmony_ci int ret = 0; 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_ci ksmbd_nl_init_fixup(); 87562306a36Sopenharmony_ci INIT_DELAYED_WORK(&ipc_timer_work, ipc_timer_heartbeat); 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci ret = genl_register_family(&ksmbd_genl_family); 87862306a36Sopenharmony_ci if (ret) { 87962306a36Sopenharmony_ci pr_err("Failed to register KSMBD netlink interface %d\n", ret); 88062306a36Sopenharmony_ci cancel_delayed_work_sync(&ipc_timer_work); 88162306a36Sopenharmony_ci } 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_ci return ret; 88462306a36Sopenharmony_ci} 885