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