2021-03-16 07:07:11 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright ( C ) 2018 Samsung Electronics Co . , Ltd .
*/
# include <linux/jhash.h>
# include <linux/slab.h>
# include <linux/rwsem.h>
# include <linux/mutex.h>
# include <linux/wait.h>
# include <linux/hashtable.h>
# include <net/net_namespace.h>
# include <net/genetlink.h>
# include <linux/socket.h>
# include <linux/workqueue.h>
# include "vfs_cache.h"
# include "transport_ipc.h"
# include "server.h"
# include "smb_common.h"
# include "mgmt/user_config.h"
# include "mgmt/share_config.h"
# include "mgmt/user_session.h"
# include "mgmt/tree_connect.h"
# include "mgmt/ksmbd_ida.h"
# include "connection.h"
# include "transport_tcp.h"
# define IPC_WAIT_TIMEOUT (2 * HZ)
# define IPC_MSG_HASH_BITS 3
static DEFINE_HASHTABLE ( ipc_msg_table , IPC_MSG_HASH_BITS ) ;
static DECLARE_RWSEM ( ipc_msg_table_lock ) ;
static DEFINE_MUTEX ( startup_lock ) ;
2021-04-13 07:06:30 +03:00
static DEFINE_IDA ( ipc_ida ) ;
2021-03-16 07:07:11 +03:00
static unsigned int ksmbd_tools_pid ;
static bool ksmbd_ipc_validate_version ( struct genl_info * m )
{
if ( m - > genlhdr - > version ! = KSMBD_GENL_VERSION ) {
2021-06-28 09:23:19 +03:00
pr_err ( " %s. ksmbd: %d, kernel module: %d. %s. \n " ,
" Daemon and kernel module version mismatch " ,
m - > genlhdr - > version ,
KSMBD_GENL_VERSION ,
" User-space ksmbd should terminate " ) ;
2021-03-16 07:07:11 +03:00
return false ;
}
return true ;
}
struct ksmbd_ipc_msg {
unsigned int type ;
unsigned int sz ;
2021-06-25 01:02:06 +03:00
unsigned char payload [ ] ;
2021-03-16 07:07:11 +03:00
} ;
struct ipc_msg_table_entry {
unsigned int handle ;
unsigned int type ;
wait_queue_head_t wait ;
struct hlist_node ipc_table_hlist ;
void * response ;
} ;
static struct delayed_work ipc_timer_work ;
static int handle_startup_event ( struct sk_buff * skb , struct genl_info * info ) ;
2021-03-30 08:25:35 +03:00
static int handle_unsupported_event ( struct sk_buff * skb , struct genl_info * info ) ;
2021-03-16 07:07:11 +03:00
static int handle_generic_event ( struct sk_buff * skb , struct genl_info * info ) ;
static int ksmbd_ipc_heartbeat_request ( void ) ;
static const struct nla_policy ksmbd_nl_policy [ KSMBD_EVENT_MAX ] = {
[ KSMBD_EVENT_UNSPEC ] = {
. len = 0 ,
} ,
[ KSMBD_EVENT_HEARTBEAT_REQUEST ] = {
. len = sizeof ( struct ksmbd_heartbeat ) ,
} ,
[ KSMBD_EVENT_STARTING_UP ] = {
. len = sizeof ( struct ksmbd_startup_request ) ,
} ,
[ KSMBD_EVENT_SHUTTING_DOWN ] = {
. len = sizeof ( struct ksmbd_shutdown_request ) ,
} ,
[ KSMBD_EVENT_LOGIN_REQUEST ] = {
. len = sizeof ( struct ksmbd_login_request ) ,
} ,
[ KSMBD_EVENT_LOGIN_RESPONSE ] = {
. len = sizeof ( struct ksmbd_login_response ) ,
} ,
[ KSMBD_EVENT_SHARE_CONFIG_REQUEST ] = {
. len = sizeof ( struct ksmbd_share_config_request ) ,
} ,
[ KSMBD_EVENT_SHARE_CONFIG_RESPONSE ] = {
. len = sizeof ( struct ksmbd_share_config_response ) ,
} ,
[ KSMBD_EVENT_TREE_CONNECT_REQUEST ] = {
. len = sizeof ( struct ksmbd_tree_connect_request ) ,
} ,
[ KSMBD_EVENT_TREE_CONNECT_RESPONSE ] = {
. len = sizeof ( struct ksmbd_tree_connect_response ) ,
} ,
[ KSMBD_EVENT_TREE_DISCONNECT_REQUEST ] = {
. len = sizeof ( struct ksmbd_tree_disconnect_request ) ,
} ,
[ KSMBD_EVENT_LOGOUT_REQUEST ] = {
. len = sizeof ( struct ksmbd_logout_request ) ,
} ,
[ KSMBD_EVENT_RPC_REQUEST ] = {
} ,
[ KSMBD_EVENT_RPC_RESPONSE ] = {
} ,
[ KSMBD_EVENT_SPNEGO_AUTHEN_REQUEST ] = {
} ,
[ KSMBD_EVENT_SPNEGO_AUTHEN_RESPONSE ] = {
} ,
} ;
static struct genl_ops ksmbd_genl_ops [ ] = {
{
. cmd = KSMBD_EVENT_UNSPEC ,
. doit = handle_unsupported_event ,
} ,
{
. cmd = KSMBD_EVENT_HEARTBEAT_REQUEST ,
. doit = handle_unsupported_event ,
} ,
{
. cmd = KSMBD_EVENT_STARTING_UP ,
. doit = handle_startup_event ,
} ,
{
. cmd = KSMBD_EVENT_SHUTTING_DOWN ,
. doit = handle_unsupported_event ,
} ,
{
. cmd = KSMBD_EVENT_LOGIN_REQUEST ,
. doit = handle_unsupported_event ,
} ,
{
. cmd = KSMBD_EVENT_LOGIN_RESPONSE ,
. doit = handle_generic_event ,
} ,
{
. cmd = KSMBD_EVENT_SHARE_CONFIG_REQUEST ,
. doit = handle_unsupported_event ,
} ,
{
. cmd = KSMBD_EVENT_SHARE_CONFIG_RESPONSE ,
. doit = handle_generic_event ,
} ,
{
. cmd = KSMBD_EVENT_TREE_CONNECT_REQUEST ,
. doit = handle_unsupported_event ,
} ,
{
. cmd = KSMBD_EVENT_TREE_CONNECT_RESPONSE ,
. doit = handle_generic_event ,
} ,
{
. cmd = KSMBD_EVENT_TREE_DISCONNECT_REQUEST ,
. doit = handle_unsupported_event ,
} ,
{
. cmd = KSMBD_EVENT_LOGOUT_REQUEST ,
. doit = handle_unsupported_event ,
} ,
{
. cmd = KSMBD_EVENT_RPC_REQUEST ,
. doit = handle_unsupported_event ,
} ,
{
. cmd = KSMBD_EVENT_RPC_RESPONSE ,
. doit = handle_generic_event ,
} ,
{
. cmd = KSMBD_EVENT_SPNEGO_AUTHEN_REQUEST ,
. doit = handle_unsupported_event ,
} ,
{
. cmd = KSMBD_EVENT_SPNEGO_AUTHEN_RESPONSE ,
. doit = handle_generic_event ,
} ,
} ;
static struct genl_family ksmbd_genl_family = {
. name = KSMBD_GENL_NAME ,
. version = KSMBD_GENL_VERSION ,
. hdrsize = 0 ,
. maxattr = KSMBD_EVENT_MAX ,
. netnsok = true ,
. module = THIS_MODULE ,
. ops = ksmbd_genl_ops ,
. n_ops = ARRAY_SIZE ( ksmbd_genl_ops ) ,
} ;
static void ksmbd_nl_init_fixup ( void )
{
int i ;
for ( i = 0 ; i < ARRAY_SIZE ( ksmbd_genl_ops ) ; i + + )
ksmbd_genl_ops [ i ] . validate = GENL_DONT_VALIDATE_STRICT |
GENL_DONT_VALIDATE_DUMP ;
ksmbd_genl_family . policy = ksmbd_nl_policy ;
}
static int rpc_context_flags ( struct ksmbd_session * sess )
{
if ( user_guest ( sess - > user ) )
return KSMBD_RPC_RESTRICTED_CONTEXT ;
return 0 ;
}
static void ipc_update_last_active ( void )
{
if ( server_conf . ipc_timeout )
server_conf . ipc_last_active = jiffies ;
}
static struct ksmbd_ipc_msg * ipc_msg_alloc ( size_t sz )
{
struct ksmbd_ipc_msg * msg ;
size_t msg_sz = sz + sizeof ( struct ksmbd_ipc_msg ) ;
2021-04-02 06:47:14 +03:00
msg = kvmalloc ( msg_sz , GFP_KERNEL | __GFP_ZERO ) ;
2021-03-16 07:07:11 +03:00
if ( msg )
msg - > sz = sz ;
return msg ;
}
static void ipc_msg_free ( struct ksmbd_ipc_msg * msg )
{
2021-04-02 06:47:14 +03:00
kvfree ( msg ) ;
2021-03-16 07:07:11 +03:00
}
static void ipc_msg_handle_free ( int handle )
{
if ( handle > = 0 )
2021-04-13 07:06:30 +03:00
ksmbd_release_id ( & ipc_ida , handle ) ;
2021-03-16 07:07:11 +03:00
}
static int handle_response ( int type , void * payload , size_t sz )
{
2021-06-25 01:02:06 +03:00
unsigned int handle = * ( unsigned int * ) payload ;
2021-03-16 07:07:11 +03:00
struct ipc_msg_table_entry * entry ;
int ret = 0 ;
ipc_update_last_active ( ) ;
down_read ( & ipc_msg_table_lock ) ;
hash_for_each_possible ( ipc_msg_table , entry , ipc_table_hlist , handle ) {
if ( handle ! = entry - > handle )
continue ;
entry - > response = NULL ;
/*
* Response message type value should be equal to
* request message type + 1.
*/
if ( entry - > type + 1 ! = type ) {
2021-06-28 09:23:19 +03:00
pr_err ( " Waiting for IPC type %d, got %d. Ignore. \n " ,
entry - > type + 1 , type ) ;
2021-03-16 07:07:11 +03:00
}
2021-04-02 06:47:14 +03:00
entry - > response = kvmalloc ( sz , GFP_KERNEL | __GFP_ZERO ) ;
2021-03-16 07:07:11 +03:00
if ( ! entry - > response ) {
ret = - ENOMEM ;
break ;
}
memcpy ( entry - > response , payload , sz ) ;
wake_up_interruptible ( & entry - > wait ) ;
ret = 0 ;
break ;
}
up_read ( & ipc_msg_table_lock ) ;
return ret ;
}
static int ipc_server_config_on_startup ( struct ksmbd_startup_request * req )
{
int ret ;
ksmbd_set_fd_limit ( req - > file_max ) ;
server_conf . flags = req - > flags ;
server_conf . signing = req - > signing ;
server_conf . tcp_port = req - > tcp_port ;
server_conf . ipc_timeout = req - > ipc_timeout * HZ ;
server_conf . deadtime = req - > deadtime * SMB_ECHO_INTERVAL ;
server_conf . share_fake_fscaps = req - > share_fake_fscaps ;
ksmbd_init_domain ( req - > sub_auth ) ;
if ( req - > smb2_max_read )
init_smb2_max_read_size ( req - > smb2_max_read ) ;
if ( req - > smb2_max_write )
init_smb2_max_write_size ( req - > smb2_max_write ) ;
if ( req - > smb2_max_trans )
init_smb2_max_trans_size ( req - > smb2_max_trans ) ;
ret = ksmbd_set_netbios_name ( req - > netbios_name ) ;
ret | = ksmbd_set_server_string ( req - > server_string ) ;
ret | = ksmbd_set_work_group ( req - > work_group ) ;
ret | = ksmbd_tcp_set_interfaces ( KSMBD_STARTUP_CONFIG_INTERFACES ( req ) ,
req - > ifc_list_sz ) ;
if ( ret ) {
2021-06-28 09:23:19 +03:00
pr_err ( " Server configuration error: %s %s %s \n " ,
req - > netbios_name , req - > server_string ,
req - > work_group ) ;
2021-03-16 07:07:11 +03:00
return ret ;
}
if ( req - > min_prot [ 0 ] ) {
ret = ksmbd_lookup_protocol_idx ( req - > min_prot ) ;
if ( ret > = 0 )
server_conf . min_protocol = ret ;
}
if ( req - > max_prot [ 0 ] ) {
ret = ksmbd_lookup_protocol_idx ( req - > max_prot ) ;
if ( ret > = 0 )
server_conf . max_protocol = ret ;
}
if ( server_conf . ipc_timeout )
schedule_delayed_work ( & ipc_timer_work , server_conf . ipc_timeout ) ;
return 0 ;
}
static int handle_startup_event ( struct sk_buff * skb , struct genl_info * info )
{
int ret = 0 ;
# ifdef CONFIG_SMB_SERVER_CHECK_CAP_NET_ADMIN
if ( ! netlink_capable ( skb , CAP_NET_ADMIN ) )
return - EPERM ;
# endif
if ( ! ksmbd_ipc_validate_version ( info ) )
return - EINVAL ;
if ( ! info - > attrs [ KSMBD_EVENT_STARTING_UP ] )
return - EINVAL ;
mutex_lock ( & startup_lock ) ;
if ( ! ksmbd_server_configurable ( ) ) {
mutex_unlock ( & startup_lock ) ;
2021-06-28 09:23:19 +03:00
pr_err ( " Server reset is in progress, can't start daemon \n " ) ;
2021-03-16 07:07:11 +03:00
return - EINVAL ;
}
if ( ksmbd_tools_pid ) {
if ( ksmbd_ipc_heartbeat_request ( ) = = 0 ) {
ret = - EINVAL ;
goto out ;
}
2021-06-28 09:23:19 +03:00
pr_err ( " Reconnect to a new user space daemon \n " ) ;
2021-03-16 07:07:11 +03:00
} else {
struct ksmbd_startup_request * req ;
req = nla_data ( info - > attrs [ info - > genlhdr - > cmd ] ) ;
ret = ipc_server_config_on_startup ( req ) ;
if ( ret )
goto out ;
server_queue_ctrl_init_work ( ) ;
}
ksmbd_tools_pid = info - > snd_portid ;
ipc_update_last_active ( ) ;
out :
mutex_unlock ( & startup_lock ) ;
return ret ;
}
2021-03-30 08:25:35 +03:00
static int handle_unsupported_event ( struct sk_buff * skb , struct genl_info * info )
2021-03-16 07:07:11 +03:00
{
2021-06-28 09:23:19 +03:00
pr_err ( " Unknown IPC event: %d, ignore. \n " , info - > genlhdr - > cmd ) ;
2021-03-16 07:07:11 +03:00
return - EINVAL ;
}
static int handle_generic_event ( struct sk_buff * skb , struct genl_info * info )
{
void * payload ;
int sz ;
int type = info - > genlhdr - > cmd ;
# ifdef CONFIG_SMB_SERVER_CHECK_CAP_NET_ADMIN
if ( ! netlink_capable ( skb , CAP_NET_ADMIN ) )
return - EPERM ;
# endif
if ( type > = KSMBD_EVENT_MAX ) {
WARN_ON ( 1 ) ;
return - EINVAL ;
}
if ( ! ksmbd_ipc_validate_version ( info ) )
return - EINVAL ;
if ( ! info - > attrs [ type ] )
return - EINVAL ;
payload = nla_data ( info - > attrs [ info - > genlhdr - > cmd ] ) ;
sz = nla_len ( info - > attrs [ info - > genlhdr - > cmd ] ) ;
return handle_response ( type , payload , sz ) ;
}
static int ipc_msg_send ( struct ksmbd_ipc_msg * msg )
{
struct genlmsghdr * nlh ;
struct sk_buff * skb ;
int ret = - EINVAL ;
if ( ! ksmbd_tools_pid )
return ret ;
skb = genlmsg_new ( msg - > sz , GFP_KERNEL ) ;
if ( ! skb )
return - ENOMEM ;
nlh = genlmsg_put ( skb , 0 , 0 , & ksmbd_genl_family , 0 , msg - > type ) ;
if ( ! nlh )
goto out ;
2021-06-25 01:02:06 +03:00
ret = nla_put ( skb , msg - > type , msg - > sz , msg - > payload ) ;
2021-03-16 07:07:11 +03:00
if ( ret ) {
genlmsg_cancel ( skb , nlh ) ;
goto out ;
}
genlmsg_end ( skb , nlh ) ;
ret = genlmsg_unicast ( & init_net , skb , ksmbd_tools_pid ) ;
if ( ! ret )
ipc_update_last_active ( ) ;
return ret ;
out :
nlmsg_free ( skb ) ;
return ret ;
}
2021-03-30 08:25:35 +03:00
static void * ipc_msg_send_request ( struct ksmbd_ipc_msg * msg , unsigned int handle )
2021-03-16 07:07:11 +03:00
{
struct ipc_msg_table_entry entry ;
int ret ;
if ( ( int ) handle < 0 )
return NULL ;
entry . type = msg - > type ;
entry . response = NULL ;
init_waitqueue_head ( & entry . wait ) ;
down_write ( & ipc_msg_table_lock ) ;
entry . handle = handle ;
hash_add ( ipc_msg_table , & entry . ipc_table_hlist , entry . handle ) ;
up_write ( & ipc_msg_table_lock ) ;
ret = ipc_msg_send ( msg ) ;
if ( ret )
goto out ;
ret = wait_event_interruptible_timeout ( entry . wait ,
entry . response ! = NULL ,
IPC_WAIT_TIMEOUT ) ;
out :
down_write ( & ipc_msg_table_lock ) ;
hash_del ( & entry . ipc_table_hlist ) ;
up_write ( & ipc_msg_table_lock ) ;
return entry . response ;
}
static int ksmbd_ipc_heartbeat_request ( void )
{
struct ksmbd_ipc_msg * msg ;
int ret ;
msg = ipc_msg_alloc ( sizeof ( struct ksmbd_heartbeat ) ) ;
if ( ! msg )
return - EINVAL ;
msg - > type = KSMBD_EVENT_HEARTBEAT_REQUEST ;
ret = ipc_msg_send ( msg ) ;
ipc_msg_free ( msg ) ;
return ret ;
}
struct ksmbd_login_response * ksmbd_ipc_login_request ( const char * account )
{
struct ksmbd_ipc_msg * msg ;
struct ksmbd_login_request * req ;
struct ksmbd_login_response * resp ;
if ( strlen ( account ) > = KSMBD_REQ_MAX_ACCOUNT_NAME_SZ )
return NULL ;
msg = ipc_msg_alloc ( sizeof ( struct ksmbd_login_request ) ) ;
if ( ! msg )
return NULL ;
msg - > type = KSMBD_EVENT_LOGIN_REQUEST ;
2021-06-25 01:02:06 +03:00
req = ( struct ksmbd_login_request * ) msg - > payload ;
2021-04-13 07:06:30 +03:00
req - > handle = ksmbd_acquire_id ( & ipc_ida ) ;
2021-03-16 07:07:11 +03:00
strscpy ( req - > account , account , KSMBD_REQ_MAX_ACCOUNT_NAME_SZ ) ;
resp = ipc_msg_send_request ( msg , req - > handle ) ;
ipc_msg_handle_free ( req - > handle ) ;
ipc_msg_free ( msg ) ;
return resp ;
}
struct ksmbd_spnego_authen_response *
ksmbd_ipc_spnego_authen_request ( const char * spnego_blob , int blob_len )
{
struct ksmbd_ipc_msg * msg ;
struct ksmbd_spnego_authen_request * req ;
struct ksmbd_spnego_authen_response * resp ;
msg = ipc_msg_alloc ( sizeof ( struct ksmbd_spnego_authen_request ) +
blob_len + 1 ) ;
if ( ! msg )
return NULL ;
msg - > type = KSMBD_EVENT_SPNEGO_AUTHEN_REQUEST ;
2021-06-25 01:02:06 +03:00
req = ( struct ksmbd_spnego_authen_request * ) msg - > payload ;
2021-04-13 07:06:30 +03:00
req - > handle = ksmbd_acquire_id ( & ipc_ida ) ;
2021-03-16 07:07:11 +03:00
req - > spnego_blob_len = blob_len ;
memcpy ( req - > spnego_blob , spnego_blob , blob_len ) ;
resp = ipc_msg_send_request ( msg , req - > handle ) ;
ipc_msg_handle_free ( req - > handle ) ;
ipc_msg_free ( msg ) ;
return resp ;
}
struct ksmbd_tree_connect_response *
ksmbd_ipc_tree_connect_request ( struct ksmbd_session * sess ,
2021-05-26 11:57:12 +03:00
struct ksmbd_share_config * share ,
struct ksmbd_tree_connect * tree_conn ,
struct sockaddr * peer_addr )
2021-03-16 07:07:11 +03:00
{
struct ksmbd_ipc_msg * msg ;
struct ksmbd_tree_connect_request * req ;
struct ksmbd_tree_connect_response * resp ;
if ( strlen ( user_name ( sess - > user ) ) > = KSMBD_REQ_MAX_ACCOUNT_NAME_SZ )
return NULL ;
if ( strlen ( share - > name ) > = KSMBD_REQ_MAX_SHARE_NAME )
return NULL ;
msg = ipc_msg_alloc ( sizeof ( struct ksmbd_tree_connect_request ) ) ;
if ( ! msg )
return NULL ;
msg - > type = KSMBD_EVENT_TREE_CONNECT_REQUEST ;
2021-06-25 01:02:06 +03:00
req = ( struct ksmbd_tree_connect_request * ) msg - > payload ;
2021-03-16 07:07:11 +03:00
2021-04-13 07:06:30 +03:00
req - > handle = ksmbd_acquire_id ( & ipc_ida ) ;
2021-03-16 07:07:11 +03:00
req - > account_flags = sess - > user - > flags ;
req - > session_id = sess - > id ;
req - > connect_id = tree_conn - > id ;
strscpy ( req - > account , user_name ( sess - > user ) , KSMBD_REQ_MAX_ACCOUNT_NAME_SZ ) ;
strscpy ( req - > share , share - > name , KSMBD_REQ_MAX_SHARE_NAME ) ;
snprintf ( req - > peer_addr , sizeof ( req - > peer_addr ) , " %pIS " , peer_addr ) ;
if ( peer_addr - > sa_family = = AF_INET6 )
req - > flags | = KSMBD_TREE_CONN_FLAG_REQUEST_IPV6 ;
if ( test_session_flag ( sess , CIFDS_SESSION_FLAG_SMB2 ) )
req - > flags | = KSMBD_TREE_CONN_FLAG_REQUEST_SMB2 ;
resp = ipc_msg_send_request ( msg , req - > handle ) ;
ipc_msg_handle_free ( req - > handle ) ;
ipc_msg_free ( msg ) ;
return resp ;
}
int ksmbd_ipc_tree_disconnect_request ( unsigned long long session_id ,
2021-05-26 11:57:12 +03:00
unsigned long long connect_id )
2021-03-16 07:07:11 +03:00
{
struct ksmbd_ipc_msg * msg ;
struct ksmbd_tree_disconnect_request * req ;
int ret ;
msg = ipc_msg_alloc ( sizeof ( struct ksmbd_tree_disconnect_request ) ) ;
if ( ! msg )
return - ENOMEM ;
msg - > type = KSMBD_EVENT_TREE_DISCONNECT_REQUEST ;
2021-06-25 01:02:06 +03:00
req = ( struct ksmbd_tree_disconnect_request * ) msg - > payload ;
2021-03-16 07:07:11 +03:00
req - > session_id = session_id ;
req - > connect_id = connect_id ;
ret = ipc_msg_send ( msg ) ;
ipc_msg_free ( msg ) ;
return ret ;
}
int ksmbd_ipc_logout_request ( const char * account )
{
struct ksmbd_ipc_msg * msg ;
struct ksmbd_logout_request * req ;
int ret ;
if ( strlen ( account ) > = KSMBD_REQ_MAX_ACCOUNT_NAME_SZ )
return - EINVAL ;
msg = ipc_msg_alloc ( sizeof ( struct ksmbd_logout_request ) ) ;
if ( ! msg )
return - ENOMEM ;
msg - > type = KSMBD_EVENT_LOGOUT_REQUEST ;
2021-06-25 01:02:06 +03:00
req = ( struct ksmbd_logout_request * ) msg - > payload ;
2021-03-16 07:07:11 +03:00
strscpy ( req - > account , account , KSMBD_REQ_MAX_ACCOUNT_NAME_SZ ) ;
ret = ipc_msg_send ( msg ) ;
ipc_msg_free ( msg ) ;
return ret ;
}
struct ksmbd_share_config_response *
ksmbd_ipc_share_config_request ( const char * name )
{
struct ksmbd_ipc_msg * msg ;
struct ksmbd_share_config_request * req ;
struct ksmbd_share_config_response * resp ;
if ( strlen ( name ) > = KSMBD_REQ_MAX_SHARE_NAME )
return NULL ;
msg = ipc_msg_alloc ( sizeof ( struct ksmbd_share_config_request ) ) ;
if ( ! msg )
return NULL ;
msg - > type = KSMBD_EVENT_SHARE_CONFIG_REQUEST ;
2021-06-25 01:02:06 +03:00
req = ( struct ksmbd_share_config_request * ) msg - > payload ;
2021-04-13 07:06:30 +03:00
req - > handle = ksmbd_acquire_id ( & ipc_ida ) ;
2021-03-16 07:07:11 +03:00
strscpy ( req - > share_name , name , KSMBD_REQ_MAX_SHARE_NAME ) ;
resp = ipc_msg_send_request ( msg , req - > handle ) ;
ipc_msg_handle_free ( req - > handle ) ;
ipc_msg_free ( msg ) ;
return resp ;
}
2021-03-30 08:25:35 +03:00
struct ksmbd_rpc_command * ksmbd_rpc_open ( struct ksmbd_session * sess , int handle )
2021-03-16 07:07:11 +03:00
{
struct ksmbd_ipc_msg * msg ;
struct ksmbd_rpc_command * req ;
struct ksmbd_rpc_command * resp ;
msg = ipc_msg_alloc ( sizeof ( struct ksmbd_rpc_command ) ) ;
if ( ! msg )
return NULL ;
msg - > type = KSMBD_EVENT_RPC_REQUEST ;
2021-06-25 01:02:06 +03:00
req = ( struct ksmbd_rpc_command * ) msg - > payload ;
2021-03-16 07:07:11 +03:00
req - > handle = handle ;
req - > flags = ksmbd_session_rpc_method ( sess , handle ) ;
req - > flags | = KSMBD_RPC_OPEN_METHOD ;
req - > payload_sz = 0 ;
resp = ipc_msg_send_request ( msg , req - > handle ) ;
ipc_msg_free ( msg ) ;
return resp ;
}
2021-03-30 08:25:35 +03:00
struct ksmbd_rpc_command * ksmbd_rpc_close ( struct ksmbd_session * sess , int handle )
2021-03-16 07:07:11 +03:00
{
struct ksmbd_ipc_msg * msg ;
struct ksmbd_rpc_command * req ;
struct ksmbd_rpc_command * resp ;
msg = ipc_msg_alloc ( sizeof ( struct ksmbd_rpc_command ) ) ;
if ( ! msg )
return NULL ;
msg - > type = KSMBD_EVENT_RPC_REQUEST ;
2021-06-25 01:02:06 +03:00
req = ( struct ksmbd_rpc_command * ) msg - > payload ;
2021-03-16 07:07:11 +03:00
req - > handle = handle ;
req - > flags = ksmbd_session_rpc_method ( sess , handle ) ;
req - > flags | = KSMBD_RPC_CLOSE_METHOD ;
req - > payload_sz = 0 ;
resp = ipc_msg_send_request ( msg , req - > handle ) ;
ipc_msg_free ( msg ) ;
return resp ;
}
2021-03-30 08:25:35 +03:00
struct ksmbd_rpc_command * ksmbd_rpc_write ( struct ksmbd_session * sess , int handle ,
2021-05-26 11:57:12 +03:00
void * payload , size_t payload_sz )
2021-03-16 07:07:11 +03:00
{
struct ksmbd_ipc_msg * msg ;
struct ksmbd_rpc_command * req ;
struct ksmbd_rpc_command * resp ;
msg = ipc_msg_alloc ( sizeof ( struct ksmbd_rpc_command ) + payload_sz + 1 ) ;
if ( ! msg )
return NULL ;
msg - > type = KSMBD_EVENT_RPC_REQUEST ;
2021-06-25 01:02:06 +03:00
req = ( struct ksmbd_rpc_command * ) msg - > payload ;
2021-03-16 07:07:11 +03:00
req - > handle = handle ;
req - > flags = ksmbd_session_rpc_method ( sess , handle ) ;
req - > flags | = rpc_context_flags ( sess ) ;
req - > flags | = KSMBD_RPC_WRITE_METHOD ;
req - > payload_sz = payload_sz ;
memcpy ( req - > payload , payload , payload_sz ) ;
resp = ipc_msg_send_request ( msg , req - > handle ) ;
ipc_msg_free ( msg ) ;
return resp ;
}
2021-03-30 08:25:35 +03:00
struct ksmbd_rpc_command * ksmbd_rpc_read ( struct ksmbd_session * sess , int handle )
2021-03-16 07:07:11 +03:00
{
struct ksmbd_ipc_msg * msg ;
struct ksmbd_rpc_command * req ;
struct ksmbd_rpc_command * resp ;
msg = ipc_msg_alloc ( sizeof ( struct ksmbd_rpc_command ) ) ;
if ( ! msg )
return NULL ;
msg - > type = KSMBD_EVENT_RPC_REQUEST ;
2021-06-25 01:02:06 +03:00
req = ( struct ksmbd_rpc_command * ) msg - > payload ;
2021-03-16 07:07:11 +03:00
req - > handle = handle ;
req - > flags = ksmbd_session_rpc_method ( sess , handle ) ;
req - > flags | = rpc_context_flags ( sess ) ;
req - > flags | = KSMBD_RPC_READ_METHOD ;
req - > payload_sz = 0 ;
resp = ipc_msg_send_request ( msg , req - > handle ) ;
ipc_msg_free ( msg ) ;
return resp ;
}
2021-03-30 08:25:35 +03:00
struct ksmbd_rpc_command * ksmbd_rpc_ioctl ( struct ksmbd_session * sess , int handle ,
2021-05-26 11:57:12 +03:00
void * payload , size_t payload_sz )
2021-03-16 07:07:11 +03:00
{
struct ksmbd_ipc_msg * msg ;
struct ksmbd_rpc_command * req ;
struct ksmbd_rpc_command * resp ;
msg = ipc_msg_alloc ( sizeof ( struct ksmbd_rpc_command ) + payload_sz + 1 ) ;
if ( ! msg )
return NULL ;
msg - > type = KSMBD_EVENT_RPC_REQUEST ;
2021-07-03 02:00:06 +03:00
req = ( struct ksmbd_rpc_command * ) msg - > payload ;
2021-03-16 07:07:11 +03:00
req - > handle = handle ;
req - > flags = ksmbd_session_rpc_method ( sess , handle ) ;
req - > flags | = rpc_context_flags ( sess ) ;
req - > flags | = KSMBD_RPC_IOCTL_METHOD ;
req - > payload_sz = payload_sz ;
memcpy ( req - > payload , payload , payload_sz ) ;
resp = ipc_msg_send_request ( msg , req - > handle ) ;
ipc_msg_free ( msg ) ;
return resp ;
}
2021-03-30 08:25:35 +03:00
struct ksmbd_rpc_command * ksmbd_rpc_rap ( struct ksmbd_session * sess , void * payload ,
2021-05-26 11:57:12 +03:00
size_t payload_sz )
2021-03-16 07:07:11 +03:00
{
struct ksmbd_ipc_msg * msg ;
struct ksmbd_rpc_command * req ;
struct ksmbd_rpc_command * resp ;
msg = ipc_msg_alloc ( sizeof ( struct ksmbd_rpc_command ) + payload_sz + 1 ) ;
if ( ! msg )
return NULL ;
msg - > type = KSMBD_EVENT_RPC_REQUEST ;
2021-07-03 02:00:06 +03:00
req = ( struct ksmbd_rpc_command * ) msg - > payload ;
2021-04-13 07:06:30 +03:00
req - > handle = ksmbd_acquire_id ( & ipc_ida ) ;
2021-03-16 07:07:11 +03:00
req - > flags = rpc_context_flags ( sess ) ;
req - > flags | = KSMBD_RPC_RAP_METHOD ;
req - > payload_sz = payload_sz ;
memcpy ( req - > payload , payload , payload_sz ) ;
resp = ipc_msg_send_request ( msg , req - > handle ) ;
ipc_msg_handle_free ( req - > handle ) ;
ipc_msg_free ( msg ) ;
return resp ;
}
static int __ipc_heartbeat ( void )
{
unsigned long delta ;
if ( ! ksmbd_server_running ( ) )
return 0 ;
if ( time_after ( jiffies , server_conf . ipc_last_active ) ) {
delta = ( jiffies - server_conf . ipc_last_active ) ;
} else {
ipc_update_last_active ( ) ;
schedule_delayed_work ( & ipc_timer_work ,
server_conf . ipc_timeout ) ;
return 0 ;
}
if ( delta < server_conf . ipc_timeout ) {
schedule_delayed_work ( & ipc_timer_work ,
server_conf . ipc_timeout - delta ) ;
return 0 ;
}
if ( ksmbd_ipc_heartbeat_request ( ) = = 0 ) {
schedule_delayed_work ( & ipc_timer_work ,
server_conf . ipc_timeout ) ;
return 0 ;
}
mutex_lock ( & startup_lock ) ;
WRITE_ONCE ( server_conf . state , SERVER_STATE_RESETTING ) ;
server_conf . ipc_last_active = 0 ;
ksmbd_tools_pid = 0 ;
2021-06-28 09:23:19 +03:00
pr_err ( " No IPC daemon response for %lus \n " , delta / HZ ) ;
2021-03-16 07:07:11 +03:00
mutex_unlock ( & startup_lock ) ;
return - EINVAL ;
}
static void ipc_timer_heartbeat ( struct work_struct * w )
{
if ( __ipc_heartbeat ( ) )
server_queue_ctrl_reset_work ( ) ;
}
int ksmbd_ipc_id_alloc ( void )
{
2021-04-13 07:06:30 +03:00
return ksmbd_acquire_id ( & ipc_ida ) ;
2021-03-16 07:07:11 +03:00
}
void ksmbd_rpc_id_free ( int handle )
{
2021-04-13 07:06:30 +03:00
ksmbd_release_id ( & ipc_ida , handle ) ;
2021-03-16 07:07:11 +03:00
}
void ksmbd_ipc_release ( void )
{
cancel_delayed_work_sync ( & ipc_timer_work ) ;
genl_unregister_family ( & ksmbd_genl_family ) ;
}
void ksmbd_ipc_soft_reset ( void )
{
mutex_lock ( & startup_lock ) ;
ksmbd_tools_pid = 0 ;
cancel_delayed_work_sync ( & ipc_timer_work ) ;
mutex_unlock ( & startup_lock ) ;
}
int ksmbd_ipc_init ( void )
{
2021-04-13 07:06:30 +03:00
int ret = 0 ;
2021-03-16 07:07:11 +03:00
ksmbd_nl_init_fixup ( ) ;
INIT_DELAYED_WORK ( & ipc_timer_work , ipc_timer_heartbeat ) ;
ret = genl_register_family ( & ksmbd_genl_family ) ;
if ( ret ) {
2021-06-28 09:23:19 +03:00
pr_err ( " Failed to register KSMBD netlink interface %d \n " , ret ) ;
2021-04-13 07:06:30 +03:00
cancel_delayed_work_sync ( & ipc_timer_work ) ;
2021-03-16 07:07:11 +03:00
}
2021-03-23 16:27:04 +03:00
return ret ;
2021-03-16 07:07:11 +03:00
}