2021-03-16 07:07:11 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright ( C ) 2016 Namjae Jeon < namjae . jeon @ protocolfreedom . org >
* Copyright ( C ) 2018 Samsung Electronics Co . , Ltd .
*/
# include <linux/mutex.h>
# include <linux/freezer.h>
# include <linux/module.h>
# include "server.h"
# include "smb_common.h"
# include "mgmt/ksmbd_ida.h"
# include "connection.h"
# include "transport_tcp.h"
# include "transport_rdma.h"
static DEFINE_MUTEX ( init_lock ) ;
static struct ksmbd_conn_ops default_conn_ops ;
2021-07-10 10:22:41 +03:00
LIST_HEAD ( conn_list ) ;
DEFINE_RWLOCK ( conn_list_lock ) ;
2021-03-16 07:07:11 +03:00
/**
* ksmbd_conn_free ( ) - free resources of the connection instance
*
* @ conn : connection instance to be cleand up
*
* During the thread termination , the corresponding conn instance
* resources ( sock / memory ) are released and finally the conn object is freed .
*/
void ksmbd_conn_free ( struct ksmbd_conn * conn )
{
write_lock ( & conn_list_lock ) ;
list_del ( & conn - > conns_list ) ;
write_unlock ( & conn_list_lock ) ;
2022-07-22 04:15:10 +03:00
xa_destroy ( & conn - > sessions ) ;
2021-04-02 06:47:14 +03:00
kvfree ( conn - > request_buf ) ;
2021-03-16 07:07:11 +03:00
kfree ( conn - > preauth_info ) ;
kfree ( conn ) ;
}
/**
* ksmbd_conn_alloc ( ) - initialize a new connection instance
*
* Return : ksmbd_conn struct on success , otherwise NULL
*/
struct ksmbd_conn * ksmbd_conn_alloc ( void )
{
struct ksmbd_conn * conn ;
conn = kzalloc ( sizeof ( struct ksmbd_conn ) , GFP_KERNEL ) ;
if ( ! conn )
return NULL ;
conn - > need_neg = true ;
conn - > status = KSMBD_SESS_NEW ;
conn - > local_nls = load_nls ( " utf8 " ) ;
if ( ! conn - > local_nls )
conn - > local_nls = load_nls_default ( ) ;
2022-09-15 16:49:11 +03:00
if ( IS_ENABLED ( CONFIG_UNICODE ) )
conn - > um = utf8_load ( UNICODE_AGE ( 12 , 1 , 0 ) ) ;
else
conn - > um = ERR_PTR ( - EOPNOTSUPP ) ;
if ( IS_ERR ( conn - > um ) )
conn - > um = NULL ;
2021-03-16 07:07:11 +03:00
atomic_set ( & conn - > req_running , 0 ) ;
atomic_set ( & conn - > r_count , 0 ) ;
2021-10-07 10:26:58 +03:00
conn - > total_credits = 1 ;
2022-05-20 08:35:47 +03:00
conn - > outstanding_credits = 0 ;
2021-10-07 10:26:58 +03:00
2021-03-16 07:07:11 +03:00
init_waitqueue_head ( & conn - > req_running_q ) ;
2022-07-28 17:35:18 +03:00
init_waitqueue_head ( & conn - > r_count_q ) ;
2021-03-16 07:07:11 +03:00
INIT_LIST_HEAD ( & conn - > conns_list ) ;
INIT_LIST_HEAD ( & conn - > requests ) ;
INIT_LIST_HEAD ( & conn - > async_requests ) ;
spin_lock_init ( & conn - > request_lock ) ;
spin_lock_init ( & conn - > credits_lock ) ;
2021-04-13 07:06:30 +03:00
ida_init ( & conn - > async_ida ) ;
2022-07-22 04:15:10 +03:00
xa_init ( & conn - > sessions ) ;
2021-03-16 07:07:11 +03:00
2021-07-10 10:22:41 +03:00
spin_lock_init ( & conn - > llist_lock ) ;
INIT_LIST_HEAD ( & conn - > lock_list ) ;
2021-03-16 07:07:11 +03:00
write_lock ( & conn_list_lock ) ;
list_add ( & conn - > conns_list , & conn_list ) ;
write_unlock ( & conn_list_lock ) ;
return conn ;
}
bool ksmbd_conn_lookup_dialect ( struct ksmbd_conn * c )
{
struct ksmbd_conn * t ;
bool ret = false ;
read_lock ( & conn_list_lock ) ;
list_for_each_entry ( t , & conn_list , conns_list ) {
if ( memcmp ( t - > ClientGUID , c - > ClientGUID , SMB2_CLIENT_GUID_SIZE ) )
continue ;
ret = true ;
break ;
}
read_unlock ( & conn_list_lock ) ;
return ret ;
}
void ksmbd_conn_enqueue_request ( struct ksmbd_work * work )
{
struct ksmbd_conn * conn = work - > conn ;
struct list_head * requests_queue = NULL ;
2023-03-31 02:42:12 +03:00
if ( conn - > ops - > get_cmd_val ( work ) ! = SMB2_CANCEL_HE )
2021-03-16 07:07:11 +03:00
requests_queue = & conn - > requests ;
if ( requests_queue ) {
atomic_inc ( & conn - > req_running ) ;
spin_lock ( & conn - > request_lock ) ;
list_add_tail ( & work - > request_entry , requests_queue ) ;
spin_unlock ( & conn - > request_lock ) ;
}
}
int ksmbd_conn_try_dequeue_request ( struct ksmbd_work * work )
{
struct ksmbd_conn * conn = work - > conn ;
int ret = 1 ;
if ( list_empty ( & work - > request_entry ) & &
2021-03-30 08:25:35 +03:00
list_empty ( & work - > async_request_entry ) )
2021-03-16 07:07:11 +03:00
return 0 ;
2021-07-10 03:31:08 +03:00
if ( ! work - > multiRsp )
atomic_dec ( & conn - > req_running ) ;
2021-03-16 07:07:11 +03:00
if ( ! work - > multiRsp ) {
2023-03-31 02:42:12 +03:00
spin_lock ( & conn - > request_lock ) ;
2021-03-16 07:07:11 +03:00
list_del_init ( & work - > request_entry ) ;
2023-03-31 02:42:12 +03:00
spin_unlock ( & conn - > request_lock ) ;
if ( work - > asynchronous )
release_async_work ( work ) ;
2021-03-16 07:07:11 +03:00
ret = 0 ;
}
wake_up_all ( & conn - > req_running_q ) ;
return ret ;
}
static void ksmbd_conn_lock ( struct ksmbd_conn * conn )
{
mutex_lock ( & conn - > srv_mutex ) ;
}
static void ksmbd_conn_unlock ( struct ksmbd_conn * conn )
{
mutex_unlock ( & conn - > srv_mutex ) ;
}
void ksmbd_conn_wait_idle ( struct ksmbd_conn * conn )
{
wait_event ( conn - > req_running_q , atomic_read ( & conn - > req_running ) < 2 ) ;
}
int ksmbd_conn_write ( struct ksmbd_work * work )
{
struct ksmbd_conn * conn = work - > conn ;
size_t len = 0 ;
int sent ;
struct kvec iov [ 3 ] ;
int iov_idx = 0 ;
2021-11-03 02:08:44 +03:00
if ( ! work - > response_buf ) {
2021-06-28 09:23:19 +03:00
pr_err ( " NULL response header \n " ) ;
2021-03-16 07:07:11 +03:00
return - EINVAL ;
}
2021-03-30 06:35:23 +03:00
if ( work - > tr_buf ) {
2021-03-16 07:07:11 +03:00
iov [ iov_idx ] = ( struct kvec ) { work - > tr_buf ,
2021-11-03 02:25:54 +03:00
sizeof ( struct smb2_transform_hdr ) + 4 } ;
2021-03-16 07:07:11 +03:00
len + = iov [ iov_idx + + ] . iov_len ;
}
2021-03-30 06:35:23 +03:00
if ( work - > aux_payload_sz ) {
2021-11-03 02:08:44 +03:00
iov [ iov_idx ] = ( struct kvec ) { work - > response_buf , work - > resp_hdr_sz } ;
2021-03-16 07:07:11 +03:00
len + = iov [ iov_idx + + ] . iov_len ;
2021-03-30 06:35:23 +03:00
iov [ iov_idx ] = ( struct kvec ) { work - > aux_payload_buf , work - > aux_payload_sz } ;
2021-03-16 07:07:11 +03:00
len + = iov [ iov_idx + + ] . iov_len ;
} else {
2021-03-30 06:35:23 +03:00
if ( work - > tr_buf )
iov [ iov_idx ] . iov_len = work - > resp_hdr_sz ;
2021-03-16 07:07:11 +03:00
else
2021-11-03 02:08:44 +03:00
iov [ iov_idx ] . iov_len = get_rfc1002_len ( work - > response_buf ) + 4 ;
iov [ iov_idx ] . iov_base = work - > response_buf ;
2021-03-16 07:07:11 +03:00
len + = iov [ iov_idx + + ] . iov_len ;
}
ksmbd_conn_lock ( conn ) ;
sent = conn - > transport - > ops - > writev ( conn - > transport , & iov [ 0 ] ,
iov_idx , len ,
work - > need_invalidate_rkey ,
work - > remote_key ) ;
ksmbd_conn_unlock ( conn ) ;
if ( sent < 0 ) {
2021-06-28 09:23:19 +03:00
pr_err ( " Failed to send message: %d \n " , sent ) ;
2021-03-16 07:07:11 +03:00
return sent ;
}
return 0 ;
}
2022-04-30 02:30:25 +03:00
int ksmbd_conn_rdma_read ( struct ksmbd_conn * conn ,
void * buf , unsigned int buflen ,
struct smb2_buffer_desc_v1 * desc ,
unsigned int desc_len )
2021-03-16 07:07:11 +03:00
{
int ret = - EINVAL ;
if ( conn - > transport - > ops - > rdma_read )
ret = conn - > transport - > ops - > rdma_read ( conn - > transport ,
2021-05-26 11:57:12 +03:00
buf , buflen ,
2022-04-30 02:30:25 +03:00
desc , desc_len ) ;
2021-03-16 07:07:11 +03:00
return ret ;
}
2022-04-30 02:30:25 +03:00
int ksmbd_conn_rdma_write ( struct ksmbd_conn * conn ,
void * buf , unsigned int buflen ,
struct smb2_buffer_desc_v1 * desc ,
unsigned int desc_len )
2021-03-16 07:07:11 +03:00
{
int ret = - EINVAL ;
if ( conn - > transport - > ops - > rdma_write )
ret = conn - > transport - > ops - > rdma_write ( conn - > transport ,
2021-05-26 11:57:12 +03:00
buf , buflen ,
2022-04-30 02:30:25 +03:00
desc , desc_len ) ;
2021-03-16 07:07:11 +03:00
return ret ;
}
bool ksmbd_conn_alive ( struct ksmbd_conn * conn )
{
if ( ! ksmbd_server_running ( ) )
return false ;
if ( conn - > status = = KSMBD_SESS_EXITING )
return false ;
if ( kthread_should_stop ( ) )
return false ;
if ( atomic_read ( & conn - > stats . open_files_count ) > 0 )
return true ;
/*
* Stop current session if the time that get last request from client
2021-07-15 04:22:20 +03:00
* is bigger than deadtime user configured and opening file count is
2021-03-16 07:07:11 +03:00
* zero .
*/
if ( server_conf . deadtime > 0 & &
2021-03-30 08:25:35 +03:00
time_after ( jiffies , conn - > last_active + server_conf . deadtime ) ) {
2021-03-16 07:07:11 +03:00
ksmbd_debug ( CONN , " No response from client in %lu minutes \n " ,
2021-05-26 11:57:12 +03:00
server_conf . deadtime / SMB_ECHO_INTERVAL ) ;
2021-03-16 07:07:11 +03:00
return false ;
}
return true ;
}
/**
* ksmbd_conn_handler_loop ( ) - session thread to listen on new smb requests
* @ p : connection instance
*
* One thread each per connection
*
* Return : 0 on success
*/
int ksmbd_conn_handler_loop ( void * p )
{
struct ksmbd_conn * conn = ( struct ksmbd_conn * ) p ;
struct ksmbd_transport * t = conn - > transport ;
2023-01-24 18:13:20 +03:00
unsigned int pdu_size , max_allowed_pdu_size ;
2021-03-16 07:07:11 +03:00
char hdr_buf [ 4 ] = { 0 , } ;
int size ;
mutex_init ( & conn - > srv_mutex ) ;
__module_get ( THIS_MODULE ) ;
if ( t - > ops - > prepare & & t - > ops - > prepare ( t ) )
goto out ;
conn - > last_active = jiffies ;
while ( ksmbd_conn_alive ( conn ) ) {
if ( try_to_freeze ( ) )
continue ;
2021-04-02 06:47:14 +03:00
kvfree ( conn - > request_buf ) ;
2021-03-16 07:07:11 +03:00
conn - > request_buf = NULL ;
2023-03-21 09:25:34 +03:00
size = t - > ops - > read ( t , hdr_buf , sizeof ( hdr_buf ) , - 1 ) ;
2021-03-16 07:07:11 +03:00
if ( size ! = sizeof ( hdr_buf ) )
break ;
pdu_size = get_rfc1002_len ( hdr_buf ) ;
ksmbd_debug ( CONN , " RFC1002 header %u bytes \n " , pdu_size ) ;
2023-01-24 18:13:20 +03:00
if ( conn - > status = = KSMBD_SESS_GOOD )
max_allowed_pdu_size =
SMB3_MAX_MSGSIZE + conn - > vals - > max_write_size ;
else
max_allowed_pdu_size = SMB3_MAX_MSGSIZE ;
if ( pdu_size > max_allowed_pdu_size ) {
2023-01-30 12:23:57 +03:00
pr_err_ratelimited ( " PDU length(%u) exceeded maximum allowed pdu size(%u) on connection(%d) \n " ,
2023-01-24 18:13:20 +03:00
pdu_size , max_allowed_pdu_size ,
conn - > status ) ;
break ;
}
2021-09-24 03:17:30 +03:00
/*
2023-03-23 15:15:52 +03:00
* Check maximum pdu size ( 0x00FFFFFF ) .
2021-09-24 03:17:30 +03:00
*/
2023-03-23 15:15:52 +03:00
if ( pdu_size > MAX_STREAM_PROT_LEN )
2023-01-24 18:13:20 +03:00
break ;
2021-03-16 07:07:11 +03:00
/* 4 for rfc1002 length field */
size = pdu_size + 4 ;
2023-03-16 16:40:43 +03:00
conn - > request_buf = kvmalloc ( size , GFP_KERNEL ) ;
2021-03-16 07:07:11 +03:00
if ( ! conn - > request_buf )
2022-12-31 11:32:31 +03:00
break ;
2021-03-16 07:07:11 +03:00
memcpy ( conn - > request_buf , hdr_buf , sizeof ( hdr_buf ) ) ;
if ( ! ksmbd_smb_request ( conn ) )
break ;
/*
* We already read 4 bytes to find out PDU size , now
* read in PDU
*/
2023-03-21 09:25:34 +03:00
size = t - > ops - > read ( t , conn - > request_buf + 4 , pdu_size , 2 ) ;
2021-03-16 07:07:11 +03:00
if ( size < 0 ) {
2021-06-28 09:23:19 +03:00
pr_err ( " sock_read failed: %d \n " , size ) ;
2021-03-16 07:07:11 +03:00
break ;
}
if ( size ! = pdu_size ) {
2021-06-28 09:23:19 +03:00
pr_err ( " PDU error. Read: %d, Expected: %d \n " ,
size , pdu_size ) ;
2021-03-16 07:07:11 +03:00
continue ;
}
if ( ! default_conn_ops . process_fn ) {
2021-06-28 09:23:19 +03:00
pr_err ( " No connection request callback \n " ) ;
2021-03-16 07:07:11 +03:00
break ;
}
if ( default_conn_ops . process_fn ( conn ) ) {
2021-06-28 09:23:19 +03:00
pr_err ( " Cannot handle request \n " ) ;
2021-03-16 07:07:11 +03:00
break ;
}
}
out :
/* Wait till all reference dropped to the Server object*/
2022-07-28 17:35:18 +03:00
wait_event ( conn - > r_count_q , atomic_read ( & conn - > r_count ) = = 0 ) ;
2021-03-16 07:07:11 +03:00
2022-09-15 16:49:11 +03:00
if ( IS_ENABLED ( CONFIG_UNICODE ) )
utf8_unload ( conn - > um ) ;
2021-03-16 07:07:11 +03:00
unload_nls ( conn - > local_nls ) ;
if ( default_conn_ops . terminate_fn )
default_conn_ops . terminate_fn ( conn ) ;
t - > ops - > disconnect ( t ) ;
module_put ( THIS_MODULE ) ;
return 0 ;
}
void ksmbd_conn_init_server_callbacks ( struct ksmbd_conn_ops * ops )
{
default_conn_ops . process_fn = ops - > process_fn ;
default_conn_ops . terminate_fn = ops - > terminate_fn ;
}
int ksmbd_conn_transport_init ( void )
{
int ret ;
mutex_lock ( & init_lock ) ;
ret = ksmbd_tcp_init ( ) ;
if ( ret ) {
pr_err ( " Failed to init TCP subsystem: %d \n " , ret ) ;
goto out ;
}
ret = ksmbd_rdma_init ( ) ;
if ( ret ) {
2021-07-13 09:38:30 +03:00
pr_err ( " Failed to init RDMA subsystem: %d \n " , ret ) ;
2021-03-16 07:07:11 +03:00
goto out ;
}
out :
mutex_unlock ( & init_lock ) ;
return ret ;
}
static void stop_sessions ( void )
{
struct ksmbd_conn * conn ;
2022-01-09 05:34:16 +03:00
struct ksmbd_transport * t ;
2021-03-16 07:07:11 +03:00
again :
read_lock ( & conn_list_lock ) ;
list_for_each_entry ( conn , & conn_list , conns_list ) {
struct task_struct * task ;
2022-01-09 05:34:16 +03:00
t = conn - > transport ;
task = t - > handler ;
2021-03-16 07:07:11 +03:00
if ( task )
ksmbd_debug ( CONN , " Stop session handler %s/%d \n " ,
2021-05-26 11:57:12 +03:00
task - > comm , task_pid_nr ( task ) ) ;
2021-03-16 07:07:11 +03:00
conn - > status = KSMBD_SESS_EXITING ;
2022-01-09 05:34:16 +03:00
if ( t - > ops - > shutdown ) {
read_unlock ( & conn_list_lock ) ;
t - > ops - > shutdown ( t ) ;
read_lock ( & conn_list_lock ) ;
}
2021-03-16 07:07:11 +03:00
}
read_unlock ( & conn_list_lock ) ;
if ( ! list_empty ( & conn_list ) ) {
2021-03-30 08:25:35 +03:00
schedule_timeout_interruptible ( HZ / 10 ) ; /* 100ms */
2021-03-16 07:07:11 +03:00
goto again ;
}
}
void ksmbd_conn_transport_destroy ( void )
{
mutex_lock ( & init_lock ) ;
ksmbd_tcp_destroy ( ) ;
ksmbd_rdma_destroy ( ) ;
stop_sessions ( ) ;
mutex_unlock ( & init_lock ) ;
}