brintos

brintos / linux-shallow public Read only

0
0
Text · 23.4 KiB · 2f27afb Raw
978 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 *   Copyright (C) 2018 Samsung Electronics Co., Ltd.4 */5 6#include <linux/jhash.h>7#include <linux/slab.h>8#include <linux/rwsem.h>9#include <linux/mutex.h>10#include <linux/wait.h>11#include <linux/hashtable.h>12#include <net/net_namespace.h>13#include <net/genetlink.h>14#include <linux/socket.h>15#include <linux/workqueue.h>16 17#include "vfs_cache.h"18#include "transport_ipc.h"19#include "server.h"20#include "smb_common.h"21 22#include "mgmt/user_config.h"23#include "mgmt/share_config.h"24#include "mgmt/user_session.h"25#include "mgmt/tree_connect.h"26#include "mgmt/ksmbd_ida.h"27#include "connection.h"28#include "transport_tcp.h"29#include "transport_rdma.h"30 31#define IPC_WAIT_TIMEOUT	(2 * HZ)32 33#define IPC_MSG_HASH_BITS	334static DEFINE_HASHTABLE(ipc_msg_table, IPC_MSG_HASH_BITS);35static DECLARE_RWSEM(ipc_msg_table_lock);36static DEFINE_MUTEX(startup_lock);37 38static DEFINE_IDA(ipc_ida);39 40static unsigned int ksmbd_tools_pid;41 42static bool ksmbd_ipc_validate_version(struct genl_info *m)43{44	if (m->genlhdr->version != KSMBD_GENL_VERSION) {45		pr_err("%s. ksmbd: %d, kernel module: %d. %s.\n",46		       "Daemon and kernel module version mismatch",47		       m->genlhdr->version,48		       KSMBD_GENL_VERSION,49		       "User-space ksmbd should terminate");50		return false;51	}52	return true;53}54 55struct ksmbd_ipc_msg {56	unsigned int		type;57	unsigned int		sz;58	unsigned char		payload[];59};60 61struct ipc_msg_table_entry {62	unsigned int		handle;63	unsigned int		type;64	wait_queue_head_t	wait;65	struct hlist_node	ipc_table_hlist;66 67	void			*response;68	unsigned int		msg_sz;69};70 71static struct delayed_work ipc_timer_work;72 73static int handle_startup_event(struct sk_buff *skb, struct genl_info *info);74static int handle_unsupported_event(struct sk_buff *skb, struct genl_info *info);75static int handle_generic_event(struct sk_buff *skb, struct genl_info *info);76static int ksmbd_ipc_heartbeat_request(void);77 78static const struct nla_policy ksmbd_nl_policy[KSMBD_EVENT_MAX + 1] = {79	[KSMBD_EVENT_UNSPEC] = {80		.len = 0,81	},82	[KSMBD_EVENT_HEARTBEAT_REQUEST] = {83		.len = sizeof(struct ksmbd_heartbeat),84	},85	[KSMBD_EVENT_STARTING_UP] = {86		.len = sizeof(struct ksmbd_startup_request),87	},88	[KSMBD_EVENT_SHUTTING_DOWN] = {89		.len = sizeof(struct ksmbd_shutdown_request),90	},91	[KSMBD_EVENT_LOGIN_REQUEST] = {92		.len = sizeof(struct ksmbd_login_request),93	},94	[KSMBD_EVENT_LOGIN_RESPONSE] = {95		.len = sizeof(struct ksmbd_login_response),96	},97	[KSMBD_EVENT_SHARE_CONFIG_REQUEST] = {98		.len = sizeof(struct ksmbd_share_config_request),99	},100	[KSMBD_EVENT_SHARE_CONFIG_RESPONSE] = {101		.len = sizeof(struct ksmbd_share_config_response),102	},103	[KSMBD_EVENT_TREE_CONNECT_REQUEST] = {104		.len = sizeof(struct ksmbd_tree_connect_request),105	},106	[KSMBD_EVENT_TREE_CONNECT_RESPONSE] = {107		.len = sizeof(struct ksmbd_tree_connect_response),108	},109	[KSMBD_EVENT_TREE_DISCONNECT_REQUEST] = {110		.len = sizeof(struct ksmbd_tree_disconnect_request),111	},112	[KSMBD_EVENT_LOGOUT_REQUEST] = {113		.len = sizeof(struct ksmbd_logout_request),114	},115	[KSMBD_EVENT_RPC_REQUEST] = {116	},117	[KSMBD_EVENT_RPC_RESPONSE] = {118	},119	[KSMBD_EVENT_SPNEGO_AUTHEN_REQUEST] = {120	},121	[KSMBD_EVENT_SPNEGO_AUTHEN_RESPONSE] = {122	},123	[KSMBD_EVENT_LOGIN_REQUEST_EXT] = {124		.len = sizeof(struct ksmbd_login_request),125	},126	[KSMBD_EVENT_LOGIN_RESPONSE_EXT] = {127		.len = sizeof(struct ksmbd_login_response_ext),128	},129};130 131static struct genl_ops ksmbd_genl_ops[] = {132	{133		.cmd	= KSMBD_EVENT_UNSPEC,134		.doit	= handle_unsupported_event,135	},136	{137		.cmd	= KSMBD_EVENT_HEARTBEAT_REQUEST,138		.doit	= handle_unsupported_event,139	},140	{141		.cmd	= KSMBD_EVENT_STARTING_UP,142		.doit	= handle_startup_event,143	},144	{145		.cmd	= KSMBD_EVENT_SHUTTING_DOWN,146		.doit	= handle_unsupported_event,147	},148	{149		.cmd	= KSMBD_EVENT_LOGIN_REQUEST,150		.doit	= handle_unsupported_event,151	},152	{153		.cmd	= KSMBD_EVENT_LOGIN_RESPONSE,154		.doit	= handle_generic_event,155	},156	{157		.cmd	= KSMBD_EVENT_SHARE_CONFIG_REQUEST,158		.doit	= handle_unsupported_event,159	},160	{161		.cmd	= KSMBD_EVENT_SHARE_CONFIG_RESPONSE,162		.doit	= handle_generic_event,163	},164	{165		.cmd	= KSMBD_EVENT_TREE_CONNECT_REQUEST,166		.doit	= handle_unsupported_event,167	},168	{169		.cmd	= KSMBD_EVENT_TREE_CONNECT_RESPONSE,170		.doit	= handle_generic_event,171	},172	{173		.cmd	= KSMBD_EVENT_TREE_DISCONNECT_REQUEST,174		.doit	= handle_unsupported_event,175	},176	{177		.cmd	= KSMBD_EVENT_LOGOUT_REQUEST,178		.doit	= handle_unsupported_event,179	},180	{181		.cmd	= KSMBD_EVENT_RPC_REQUEST,182		.doit	= handle_unsupported_event,183	},184	{185		.cmd	= KSMBD_EVENT_RPC_RESPONSE,186		.doit	= handle_generic_event,187	},188	{189		.cmd	= KSMBD_EVENT_SPNEGO_AUTHEN_REQUEST,190		.doit	= handle_unsupported_event,191	},192	{193		.cmd	= KSMBD_EVENT_SPNEGO_AUTHEN_RESPONSE,194		.doit	= handle_generic_event,195	},196	{197		.cmd	= KSMBD_EVENT_LOGIN_REQUEST_EXT,198		.doit	= handle_unsupported_event,199	},200	{201		.cmd	= KSMBD_EVENT_LOGIN_RESPONSE_EXT,202		.doit	= handle_generic_event,203	},204};205 206static struct genl_family ksmbd_genl_family = {207	.name		= KSMBD_GENL_NAME,208	.version	= KSMBD_GENL_VERSION,209	.hdrsize	= 0,210	.maxattr	= KSMBD_EVENT_MAX,211	.netnsok	= true,212	.module		= THIS_MODULE,213	.ops		= ksmbd_genl_ops,214	.n_ops		= ARRAY_SIZE(ksmbd_genl_ops),215	.resv_start_op	= KSMBD_EVENT_LOGIN_RESPONSE_EXT + 1,216};217 218static void ksmbd_nl_init_fixup(void)219{220	int i;221 222	for (i = 0; i < ARRAY_SIZE(ksmbd_genl_ops); i++)223		ksmbd_genl_ops[i].validate = GENL_DONT_VALIDATE_STRICT |224						GENL_DONT_VALIDATE_DUMP;225 226	ksmbd_genl_family.policy = ksmbd_nl_policy;227}228 229static int rpc_context_flags(struct ksmbd_session *sess)230{231	if (user_guest(sess->user))232		return KSMBD_RPC_RESTRICTED_CONTEXT;233	return 0;234}235 236static void ipc_update_last_active(void)237{238	if (server_conf.ipc_timeout)239		server_conf.ipc_last_active = jiffies;240}241 242static struct ksmbd_ipc_msg *ipc_msg_alloc(size_t sz)243{244	struct ksmbd_ipc_msg *msg;245	size_t msg_sz = sz + sizeof(struct ksmbd_ipc_msg);246 247	msg = kvzalloc(msg_sz, GFP_KERNEL);248	if (msg)249		msg->sz = sz;250	return msg;251}252 253static void ipc_msg_free(struct ksmbd_ipc_msg *msg)254{255	kvfree(msg);256}257 258static void ipc_msg_handle_free(int handle)259{260	if (handle >= 0)261		ksmbd_release_id(&ipc_ida, handle);262}263 264static int handle_response(int type, void *payload, size_t sz)265{266	unsigned int handle = *(unsigned int *)payload;267	struct ipc_msg_table_entry *entry;268	int ret = 0;269 270	ipc_update_last_active();271	down_read(&ipc_msg_table_lock);272	hash_for_each_possible(ipc_msg_table, entry, ipc_table_hlist, handle) {273		if (handle != entry->handle)274			continue;275 276		entry->response = NULL;277		/*278		 * Response message type value should be equal to279		 * request message type + 1.280		 */281		if (entry->type + 1 != type) {282			pr_err("Waiting for IPC type %d, got %d. Ignore.\n",283			       entry->type + 1, type);284		}285 286		entry->response = kvzalloc(sz, GFP_KERNEL);287		if (!entry->response) {288			ret = -ENOMEM;289			break;290		}291 292		memcpy(entry->response, payload, sz);293		entry->msg_sz = sz;294		wake_up_interruptible(&entry->wait);295		ret = 0;296		break;297	}298	up_read(&ipc_msg_table_lock);299 300	return ret;301}302 303static int ipc_server_config_on_startup(struct ksmbd_startup_request *req)304{305	int ret;306 307	ksmbd_set_fd_limit(req->file_max);308	server_conf.flags = req->flags;309	server_conf.signing = req->signing;310	server_conf.tcp_port = req->tcp_port;311	server_conf.ipc_timeout = req->ipc_timeout * HZ;312	server_conf.deadtime = req->deadtime * SMB_ECHO_INTERVAL;313	server_conf.share_fake_fscaps = req->share_fake_fscaps;314	ksmbd_init_domain(req->sub_auth);315 316	if (req->smb2_max_read)317		init_smb2_max_read_size(req->smb2_max_read);318	if (req->smb2_max_write)319		init_smb2_max_write_size(req->smb2_max_write);320	if (req->smb2_max_trans)321		init_smb2_max_trans_size(req->smb2_max_trans);322	if (req->smb2_max_credits)323		init_smb2_max_credits(req->smb2_max_credits);324	if (req->smbd_max_io_size)325		init_smbd_max_io_size(req->smbd_max_io_size);326 327	if (req->max_connections)328		server_conf.max_connections = req->max_connections;329 330	ret = ksmbd_set_netbios_name(req->netbios_name);331	ret |= ksmbd_set_server_string(req->server_string);332	ret |= ksmbd_set_work_group(req->work_group);333	ret |= ksmbd_tcp_set_interfaces(KSMBD_STARTUP_CONFIG_INTERFACES(req),334					req->ifc_list_sz);335	if (ret) {336		pr_err("Server configuration error: %s %s %s\n",337		       req->netbios_name, req->server_string,338		       req->work_group);339		return ret;340	}341 342	if (req->min_prot[0]) {343		ret = ksmbd_lookup_protocol_idx(req->min_prot);344		if (ret >= 0)345			server_conf.min_protocol = ret;346	}347	if (req->max_prot[0]) {348		ret = ksmbd_lookup_protocol_idx(req->max_prot);349		if (ret >= 0)350			server_conf.max_protocol = ret;351	}352 353	if (server_conf.ipc_timeout)354		schedule_delayed_work(&ipc_timer_work, server_conf.ipc_timeout);355	return 0;356}357 358static int handle_startup_event(struct sk_buff *skb, struct genl_info *info)359{360	int ret = 0;361 362#ifdef CONFIG_SMB_SERVER_CHECK_CAP_NET_ADMIN363	if (!netlink_capable(skb, CAP_NET_ADMIN))364		return -EPERM;365#endif366 367	if (!ksmbd_ipc_validate_version(info))368		return -EINVAL;369 370	if (!info->attrs[KSMBD_EVENT_STARTING_UP])371		return -EINVAL;372 373	mutex_lock(&startup_lock);374	if (!ksmbd_server_configurable()) {375		mutex_unlock(&startup_lock);376		pr_err("Server reset is in progress, can't start daemon\n");377		return -EINVAL;378	}379 380	if (ksmbd_tools_pid) {381		if (ksmbd_ipc_heartbeat_request() == 0) {382			ret = -EINVAL;383			goto out;384		}385 386		pr_err("Reconnect to a new user space daemon\n");387	} else {388		struct ksmbd_startup_request *req;389 390		req = nla_data(info->attrs[info->genlhdr->cmd]);391		ret = ipc_server_config_on_startup(req);392		if (ret)393			goto out;394		server_queue_ctrl_init_work();395	}396 397	ksmbd_tools_pid = info->snd_portid;398	ipc_update_last_active();399 400out:401	mutex_unlock(&startup_lock);402	return ret;403}404 405static int handle_unsupported_event(struct sk_buff *skb, struct genl_info *info)406{407	pr_err("Unknown IPC event: %d, ignore.\n", info->genlhdr->cmd);408	return -EINVAL;409}410 411static int handle_generic_event(struct sk_buff *skb, struct genl_info *info)412{413	void *payload;414	int sz;415	int type = info->genlhdr->cmd;416 417#ifdef CONFIG_SMB_SERVER_CHECK_CAP_NET_ADMIN418	if (!netlink_capable(skb, CAP_NET_ADMIN))419		return -EPERM;420#endif421 422	if (type > KSMBD_EVENT_MAX) {423		WARN_ON(1);424		return -EINVAL;425	}426 427	if (!ksmbd_ipc_validate_version(info))428		return -EINVAL;429 430	if (!info->attrs[type])431		return -EINVAL;432 433	payload = nla_data(info->attrs[info->genlhdr->cmd]);434	sz = nla_len(info->attrs[info->genlhdr->cmd]);435	return handle_response(type, payload, sz);436}437 438static int ipc_msg_send(struct ksmbd_ipc_msg *msg)439{440	struct genlmsghdr *nlh;441	struct sk_buff *skb;442	int ret = -EINVAL;443 444	if (!ksmbd_tools_pid)445		return ret;446 447	skb = genlmsg_new(msg->sz, GFP_KERNEL);448	if (!skb)449		return -ENOMEM;450 451	nlh = genlmsg_put(skb, 0, 0, &ksmbd_genl_family, 0, msg->type);452	if (!nlh)453		goto out;454 455	ret = nla_put(skb, msg->type, msg->sz, msg->payload);456	if (ret) {457		genlmsg_cancel(skb, nlh);458		goto out;459	}460 461	genlmsg_end(skb, nlh);462	ret = genlmsg_unicast(&init_net, skb, ksmbd_tools_pid);463	if (!ret)464		ipc_update_last_active();465	return ret;466 467out:468	nlmsg_free(skb);469	return ret;470}471 472static int ipc_validate_msg(struct ipc_msg_table_entry *entry)473{474	unsigned int msg_sz = entry->msg_sz;475 476	switch (entry->type) {477	case KSMBD_EVENT_RPC_REQUEST:478	{479		struct ksmbd_rpc_command *resp = entry->response;480 481		msg_sz = sizeof(struct ksmbd_rpc_command) + resp->payload_sz;482		break;483	}484	case KSMBD_EVENT_SPNEGO_AUTHEN_REQUEST:485	{486		struct ksmbd_spnego_authen_response *resp = entry->response;487 488		msg_sz = sizeof(struct ksmbd_spnego_authen_response) +489				resp->session_key_len + resp->spnego_blob_len;490		break;491	}492	case KSMBD_EVENT_SHARE_CONFIG_REQUEST:493	{494		struct ksmbd_share_config_response *resp = entry->response;495 496		if (resp->payload_sz) {497			if (resp->payload_sz < resp->veto_list_sz)498				return -EINVAL;499 500			msg_sz = sizeof(struct ksmbd_share_config_response) +501					resp->payload_sz;502		}503		break;504	}505	case KSMBD_EVENT_LOGIN_REQUEST_EXT:506	{507		struct ksmbd_login_response_ext *resp = entry->response;508 509		if (resp->ngroups) {510			msg_sz = sizeof(struct ksmbd_login_response_ext) +511					resp->ngroups * sizeof(gid_t);512		}513	}514	}515 516	return entry->msg_sz != msg_sz ? -EINVAL : 0;517}518 519static void *ipc_msg_send_request(struct ksmbd_ipc_msg *msg, unsigned int handle)520{521	struct ipc_msg_table_entry entry;522	int ret;523 524	if ((int)handle < 0)525		return NULL;526 527	entry.type = msg->type;528	entry.response = NULL;529	init_waitqueue_head(&entry.wait);530 531	down_write(&ipc_msg_table_lock);532	entry.handle = handle;533	hash_add(ipc_msg_table, &entry.ipc_table_hlist, entry.handle);534	up_write(&ipc_msg_table_lock);535 536	ret = ipc_msg_send(msg);537	if (ret)538		goto out;539 540	ret = wait_event_interruptible_timeout(entry.wait,541					       entry.response != NULL,542					       IPC_WAIT_TIMEOUT);543	if (entry.response) {544		ret = ipc_validate_msg(&entry);545		if (ret) {546			kvfree(entry.response);547			entry.response = NULL;548		}549	}550out:551	down_write(&ipc_msg_table_lock);552	hash_del(&entry.ipc_table_hlist);553	up_write(&ipc_msg_table_lock);554	return entry.response;555}556 557static int ksmbd_ipc_heartbeat_request(void)558{559	struct ksmbd_ipc_msg *msg;560	int ret;561 562	msg = ipc_msg_alloc(sizeof(struct ksmbd_heartbeat));563	if (!msg)564		return -EINVAL;565 566	msg->type = KSMBD_EVENT_HEARTBEAT_REQUEST;567	ret = ipc_msg_send(msg);568	ipc_msg_free(msg);569	return ret;570}571 572struct ksmbd_login_response *ksmbd_ipc_login_request(const char *account)573{574	struct ksmbd_ipc_msg *msg;575	struct ksmbd_login_request *req;576	struct ksmbd_login_response *resp;577 578	if (strlen(account) >= KSMBD_REQ_MAX_ACCOUNT_NAME_SZ)579		return NULL;580 581	msg = ipc_msg_alloc(sizeof(struct ksmbd_login_request));582	if (!msg)583		return NULL;584 585	msg->type = KSMBD_EVENT_LOGIN_REQUEST;586	req = (struct ksmbd_login_request *)msg->payload;587	req->handle = ksmbd_acquire_id(&ipc_ida);588	strscpy(req->account, account, KSMBD_REQ_MAX_ACCOUNT_NAME_SZ);589 590	resp = ipc_msg_send_request(msg, req->handle);591	ipc_msg_handle_free(req->handle);592	ipc_msg_free(msg);593	return resp;594}595 596struct ksmbd_login_response_ext *ksmbd_ipc_login_request_ext(const char *account)597{598	struct ksmbd_ipc_msg *msg;599	struct ksmbd_login_request *req;600	struct ksmbd_login_response_ext *resp;601 602	if (strlen(account) >= KSMBD_REQ_MAX_ACCOUNT_NAME_SZ)603		return NULL;604 605	msg = ipc_msg_alloc(sizeof(struct ksmbd_login_request));606	if (!msg)607		return NULL;608 609	msg->type = KSMBD_EVENT_LOGIN_REQUEST_EXT;610	req = (struct ksmbd_login_request *)msg->payload;611	req->handle = ksmbd_acquire_id(&ipc_ida);612	strscpy(req->account, account, KSMBD_REQ_MAX_ACCOUNT_NAME_SZ);613	resp = ipc_msg_send_request(msg, req->handle);614	ipc_msg_handle_free(req->handle);615	ipc_msg_free(msg);616	return resp;617}618 619struct ksmbd_spnego_authen_response *620ksmbd_ipc_spnego_authen_request(const char *spnego_blob, int blob_len)621{622	struct ksmbd_ipc_msg *msg;623	struct ksmbd_spnego_authen_request *req;624	struct ksmbd_spnego_authen_response *resp;625 626	msg = ipc_msg_alloc(sizeof(struct ksmbd_spnego_authen_request) +627			blob_len + 1);628	if (!msg)629		return NULL;630 631	msg->type = KSMBD_EVENT_SPNEGO_AUTHEN_REQUEST;632	req = (struct ksmbd_spnego_authen_request *)msg->payload;633	req->handle = ksmbd_acquire_id(&ipc_ida);634	req->spnego_blob_len = blob_len;635	memcpy(req->spnego_blob, spnego_blob, blob_len);636 637	resp = ipc_msg_send_request(msg, req->handle);638	ipc_msg_handle_free(req->handle);639	ipc_msg_free(msg);640	return resp;641}642 643struct ksmbd_tree_connect_response *644ksmbd_ipc_tree_connect_request(struct ksmbd_session *sess,645			       struct ksmbd_share_config *share,646			       struct ksmbd_tree_connect *tree_conn,647			       struct sockaddr *peer_addr)648{649	struct ksmbd_ipc_msg *msg;650	struct ksmbd_tree_connect_request *req;651	struct ksmbd_tree_connect_response *resp;652 653	if (strlen(user_name(sess->user)) >= KSMBD_REQ_MAX_ACCOUNT_NAME_SZ)654		return NULL;655 656	if (strlen(share->name) >= KSMBD_REQ_MAX_SHARE_NAME)657		return NULL;658 659	msg = ipc_msg_alloc(sizeof(struct ksmbd_tree_connect_request));660	if (!msg)661		return NULL;662 663	msg->type = KSMBD_EVENT_TREE_CONNECT_REQUEST;664	req = (struct ksmbd_tree_connect_request *)msg->payload;665 666	req->handle = ksmbd_acquire_id(&ipc_ida);667	req->account_flags = sess->user->flags;668	req->session_id = sess->id;669	req->connect_id = tree_conn->id;670	strscpy(req->account, user_name(sess->user), KSMBD_REQ_MAX_ACCOUNT_NAME_SZ);671	strscpy(req->share, share->name, KSMBD_REQ_MAX_SHARE_NAME);672	snprintf(req->peer_addr, sizeof(req->peer_addr), "%pIS", peer_addr);673 674	if (peer_addr->sa_family == AF_INET6)675		req->flags |= KSMBD_TREE_CONN_FLAG_REQUEST_IPV6;676	if (test_session_flag(sess, CIFDS_SESSION_FLAG_SMB2))677		req->flags |= KSMBD_TREE_CONN_FLAG_REQUEST_SMB2;678 679	resp = ipc_msg_send_request(msg, req->handle);680	ipc_msg_handle_free(req->handle);681	ipc_msg_free(msg);682	return resp;683}684 685int ksmbd_ipc_tree_disconnect_request(unsigned long long session_id,686				      unsigned long long connect_id)687{688	struct ksmbd_ipc_msg *msg;689	struct ksmbd_tree_disconnect_request *req;690	int ret;691 692	msg = ipc_msg_alloc(sizeof(struct ksmbd_tree_disconnect_request));693	if (!msg)694		return -ENOMEM;695 696	msg->type = KSMBD_EVENT_TREE_DISCONNECT_REQUEST;697	req = (struct ksmbd_tree_disconnect_request *)msg->payload;698	req->session_id = session_id;699	req->connect_id = connect_id;700 701	ret = ipc_msg_send(msg);702	ipc_msg_free(msg);703	return ret;704}705 706int ksmbd_ipc_logout_request(const char *account, int flags)707{708	struct ksmbd_ipc_msg *msg;709	struct ksmbd_logout_request *req;710	int ret;711 712	if (strlen(account) >= KSMBD_REQ_MAX_ACCOUNT_NAME_SZ)713		return -EINVAL;714 715	msg = ipc_msg_alloc(sizeof(struct ksmbd_logout_request));716	if (!msg)717		return -ENOMEM;718 719	msg->type = KSMBD_EVENT_LOGOUT_REQUEST;720	req = (struct ksmbd_logout_request *)msg->payload;721	req->account_flags = flags;722	strscpy(req->account, account, KSMBD_REQ_MAX_ACCOUNT_NAME_SZ);723 724	ret = ipc_msg_send(msg);725	ipc_msg_free(msg);726	return ret;727}728 729struct ksmbd_share_config_response *730ksmbd_ipc_share_config_request(const char *name)731{732	struct ksmbd_ipc_msg *msg;733	struct ksmbd_share_config_request *req;734	struct ksmbd_share_config_response *resp;735 736	if (strlen(name) >= KSMBD_REQ_MAX_SHARE_NAME)737		return NULL;738 739	msg = ipc_msg_alloc(sizeof(struct ksmbd_share_config_request));740	if (!msg)741		return NULL;742 743	msg->type = KSMBD_EVENT_SHARE_CONFIG_REQUEST;744	req = (struct ksmbd_share_config_request *)msg->payload;745	req->handle = ksmbd_acquire_id(&ipc_ida);746	strscpy(req->share_name, name, KSMBD_REQ_MAX_SHARE_NAME);747 748	resp = ipc_msg_send_request(msg, req->handle);749	ipc_msg_handle_free(req->handle);750	ipc_msg_free(msg);751	return resp;752}753 754struct ksmbd_rpc_command *ksmbd_rpc_open(struct ksmbd_session *sess, int handle)755{756	struct ksmbd_ipc_msg *msg;757	struct ksmbd_rpc_command *req;758	struct ksmbd_rpc_command *resp;759 760	msg = ipc_msg_alloc(sizeof(struct ksmbd_rpc_command));761	if (!msg)762		return NULL;763 764	msg->type = KSMBD_EVENT_RPC_REQUEST;765	req = (struct ksmbd_rpc_command *)msg->payload;766	req->handle = handle;767	req->flags = ksmbd_session_rpc_method(sess, handle);768	req->flags |= KSMBD_RPC_OPEN_METHOD;769	req->payload_sz = 0;770 771	resp = ipc_msg_send_request(msg, req->handle);772	ipc_msg_free(msg);773	return resp;774}775 776struct ksmbd_rpc_command *ksmbd_rpc_close(struct ksmbd_session *sess, int handle)777{778	struct ksmbd_ipc_msg *msg;779	struct ksmbd_rpc_command *req;780	struct ksmbd_rpc_command *resp;781 782	msg = ipc_msg_alloc(sizeof(struct ksmbd_rpc_command));783	if (!msg)784		return NULL;785 786	msg->type = KSMBD_EVENT_RPC_REQUEST;787	req = (struct ksmbd_rpc_command *)msg->payload;788	req->handle = handle;789	req->flags = ksmbd_session_rpc_method(sess, handle);790	req->flags |= KSMBD_RPC_CLOSE_METHOD;791	req->payload_sz = 0;792 793	resp = ipc_msg_send_request(msg, req->handle);794	ipc_msg_free(msg);795	return resp;796}797 798struct ksmbd_rpc_command *ksmbd_rpc_write(struct ksmbd_session *sess, int handle,799					  void *payload, size_t payload_sz)800{801	struct ksmbd_ipc_msg *msg;802	struct ksmbd_rpc_command *req;803	struct ksmbd_rpc_command *resp;804 805	msg = ipc_msg_alloc(sizeof(struct ksmbd_rpc_command) + payload_sz + 1);806	if (!msg)807		return NULL;808 809	msg->type = KSMBD_EVENT_RPC_REQUEST;810	req = (struct ksmbd_rpc_command *)msg->payload;811	req->handle = handle;812	req->flags = ksmbd_session_rpc_method(sess, handle);813	req->flags |= rpc_context_flags(sess);814	req->flags |= KSMBD_RPC_WRITE_METHOD;815	req->payload_sz = payload_sz;816	memcpy(req->payload, payload, payload_sz);817 818	resp = ipc_msg_send_request(msg, req->handle);819	ipc_msg_free(msg);820	return resp;821}822 823struct ksmbd_rpc_command *ksmbd_rpc_read(struct ksmbd_session *sess, int handle)824{825	struct ksmbd_ipc_msg *msg;826	struct ksmbd_rpc_command *req;827	struct ksmbd_rpc_command *resp;828 829	msg = ipc_msg_alloc(sizeof(struct ksmbd_rpc_command));830	if (!msg)831		return NULL;832 833	msg->type = KSMBD_EVENT_RPC_REQUEST;834	req = (struct ksmbd_rpc_command *)msg->payload;835	req->handle = handle;836	req->flags = ksmbd_session_rpc_method(sess, handle);837	req->flags |= rpc_context_flags(sess);838	req->flags |= KSMBD_RPC_READ_METHOD;839	req->payload_sz = 0;840 841	resp = ipc_msg_send_request(msg, req->handle);842	ipc_msg_free(msg);843	return resp;844}845 846struct ksmbd_rpc_command *ksmbd_rpc_ioctl(struct ksmbd_session *sess, int handle,847					  void *payload, size_t payload_sz)848{849	struct ksmbd_ipc_msg *msg;850	struct ksmbd_rpc_command *req;851	struct ksmbd_rpc_command *resp;852 853	msg = ipc_msg_alloc(sizeof(struct ksmbd_rpc_command) + payload_sz + 1);854	if (!msg)855		return NULL;856 857	msg->type = KSMBD_EVENT_RPC_REQUEST;858	req = (struct ksmbd_rpc_command *)msg->payload;859	req->handle = handle;860	req->flags = ksmbd_session_rpc_method(sess, handle);861	req->flags |= rpc_context_flags(sess);862	req->flags |= KSMBD_RPC_IOCTL_METHOD;863	req->payload_sz = payload_sz;864	memcpy(req->payload, payload, payload_sz);865 866	resp = ipc_msg_send_request(msg, req->handle);867	ipc_msg_free(msg);868	return resp;869}870 871struct ksmbd_rpc_command *ksmbd_rpc_rap(struct ksmbd_session *sess, void *payload,872					size_t payload_sz)873{874	struct ksmbd_ipc_msg *msg;875	struct ksmbd_rpc_command *req;876	struct ksmbd_rpc_command *resp;877 878	msg = ipc_msg_alloc(sizeof(struct ksmbd_rpc_command) + payload_sz + 1);879	if (!msg)880		return NULL;881 882	msg->type = KSMBD_EVENT_RPC_REQUEST;883	req = (struct ksmbd_rpc_command *)msg->payload;884	req->handle = ksmbd_acquire_id(&ipc_ida);885	req->flags = rpc_context_flags(sess);886	req->flags |= KSMBD_RPC_RAP_METHOD;887	req->payload_sz = payload_sz;888	memcpy(req->payload, payload, payload_sz);889 890	resp = ipc_msg_send_request(msg, req->handle);891	ipc_msg_handle_free(req->handle);892	ipc_msg_free(msg);893	return resp;894}895 896static int __ipc_heartbeat(void)897{898	unsigned long delta;899 900	if (!ksmbd_server_running())901		return 0;902 903	if (time_after(jiffies, server_conf.ipc_last_active)) {904		delta = (jiffies - server_conf.ipc_last_active);905	} else {906		ipc_update_last_active();907		schedule_delayed_work(&ipc_timer_work,908				      server_conf.ipc_timeout);909		return 0;910	}911 912	if (delta < server_conf.ipc_timeout) {913		schedule_delayed_work(&ipc_timer_work,914				      server_conf.ipc_timeout - delta);915		return 0;916	}917 918	if (ksmbd_ipc_heartbeat_request() == 0) {919		schedule_delayed_work(&ipc_timer_work,920				      server_conf.ipc_timeout);921		return 0;922	}923 924	mutex_lock(&startup_lock);925	WRITE_ONCE(server_conf.state, SERVER_STATE_RESETTING);926	server_conf.ipc_last_active = 0;927	ksmbd_tools_pid = 0;928	pr_err("No IPC daemon response for %lus\n", delta / HZ);929	mutex_unlock(&startup_lock);930	return -EINVAL;931}932 933static void ipc_timer_heartbeat(struct work_struct *w)934{935	if (__ipc_heartbeat())936		server_queue_ctrl_reset_work();937}938 939int ksmbd_ipc_id_alloc(void)940{941	return ksmbd_acquire_id(&ipc_ida);942}943 944void ksmbd_rpc_id_free(int handle)945{946	ksmbd_release_id(&ipc_ida, handle);947}948 949void ksmbd_ipc_release(void)950{951	cancel_delayed_work_sync(&ipc_timer_work);952	genl_unregister_family(&ksmbd_genl_family);953}954 955void ksmbd_ipc_soft_reset(void)956{957	mutex_lock(&startup_lock);958	ksmbd_tools_pid = 0;959	cancel_delayed_work_sync(&ipc_timer_work);960	mutex_unlock(&startup_lock);961}962 963int ksmbd_ipc_init(void)964{965	int ret = 0;966 967	ksmbd_nl_init_fixup();968	INIT_DELAYED_WORK(&ipc_timer_work, ipc_timer_heartbeat);969 970	ret = genl_register_family(&ksmbd_genl_family);971	if (ret) {972		pr_err("Failed to register KSMBD netlink interface %d\n", ret);973		cancel_delayed_work_sync(&ipc_timer_work);974	}975 976	return ret;977}978