You've already forked linux-rockchip
mirror of
https://github.com/armbian/linux-rockchip.git
synced 2026-01-06 11:08:10 -08:00
cifsd: add server handler for central processing and tranport layers
This adds server handler for central processing, transport layers(tcp, rdma, ipc) and a document describing cifsd architecture. Signed-off-by: Namjae Jeon <namjae.jeon@samsung.com> Signed-off-by: Sergey Senozhatsky <sergey.senozhatsky@gmail.com> Signed-off-by: Hyunchul Lee <hyc.lee@gmail.com> Acked-by: Ronnie Sahlberg <lsahlber@redhat.com> Signed-off-by: Steve French <stfrench@microsoft.com>
This commit is contained in:
committed by
Steve French
parent
6efb943b86
commit
0626e6641f
136
Documentation/filesystems/cifs/cifsd.rst
Normal file
136
Documentation/filesystems/cifs/cifsd.rst
Normal file
@@ -0,0 +1,136 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
=========================
|
||||
CIFSD - SMB3 Kernel Server
|
||||
=========================
|
||||
|
||||
CIFSD is a linux kernel server which implements SMB3 protocol in kernel space
|
||||
for sharing files over network.
|
||||
|
||||
CIFSD architecture
|
||||
==================
|
||||
|
||||
The subset of performance related operations belong in kernelspace and
|
||||
the other subset which belong to operations which are not really related with
|
||||
performance in userspace. So, DCE/RPC management that has historically resulted
|
||||
into number of buffer overflow issues and dangerous security bugs and user
|
||||
account management are implemented in user space as ksmbd.mountd.
|
||||
File operations that are related with performance (open/read/write/close etc.)
|
||||
in kernel space (ksmbd). This also allows for easier integration with VFS
|
||||
interface for all file operations.
|
||||
|
||||
ksmbd (kernel daemon)
|
||||
---------------------
|
||||
|
||||
When the server daemon is started, It starts up a forker thread
|
||||
(ksmbd/interface name) at initialization time and open a dedicated port 445
|
||||
for listening to SMB requests. Whenever new clients make request, Forker
|
||||
thread will accept the client connection and fork a new thread for dedicated
|
||||
communication channel between the client and the server. It allows for parallel
|
||||
processing of SMB requests(commands) from clients as well as allowing for new
|
||||
clients to make new connections. Each instance is named ksmbd/1~n(port number)
|
||||
to indicate connected clients. Depending on the SMB request types, each new
|
||||
thread can decide to pass through the commands to the user space (ksmbd.mountd),
|
||||
currently DCE/RPC commands are identified to be handled through the user space.
|
||||
To further utilize the linux kernel, it has been chosen to process the commands
|
||||
as workitems and to be executed in the handlers of the ksmbd-io kworker threads.
|
||||
It allows for multiplexing of the handlers as the kernel take care of initiating
|
||||
extra worker threads if the load is increased and vice versa, if the load is
|
||||
decreased it destroys the extra worker threads. So, after connection is
|
||||
established with client. Dedicated ksmbd/1..n(port number) takes complete
|
||||
ownership of receiving/parsing of SMB commands. Each received command is worked
|
||||
in parallel i.e., There can be multiple clients commands which are worked in
|
||||
parallel. After receiving each command a separated kernel workitem is prepared
|
||||
for each command which is further queued to be handled by ksmbd-io kworkers.
|
||||
So, each SMB workitem is queued to the kworkers. This allows the benefit of load
|
||||
sharing to be managed optimally by the default kernel and optimizing client
|
||||
performance by handling client commands in parallel.
|
||||
|
||||
ksmbd.mountd (user space daemon)
|
||||
--------------------------------
|
||||
|
||||
ksmbd.mountd is userspace process to, transfer user account and password that
|
||||
are registered using ksmbd.adduser(part of utils for user space). Further it
|
||||
allows sharing information parameters that parsed from smb.conf to ksmbd in
|
||||
kernel. For the execution part it has a daemon which is continuously running
|
||||
and connected to the kernel interface using netlink socket, it waits for the
|
||||
requests(dcerpc and share/user info). It handles RPC calls (at a minimum few
|
||||
dozen) that are most important for file server from NetShareEnum and
|
||||
NetServerGetInfo. Complete DCE/RPC response is prepared from the user space
|
||||
and passed over to the associated kernel thread for the client.
|
||||
|
||||
Key Features
|
||||
============
|
||||
|
||||
The supported features are:
|
||||
* SMB3 protocols for basic file sharing
|
||||
* Auto negotiation
|
||||
* Compound requests
|
||||
* Oplock/Lease
|
||||
* Large MTU
|
||||
* NTLM/NTLMv2
|
||||
* HMAC-SHA256 Signing
|
||||
* Secure negotiate
|
||||
* Signing Update
|
||||
* Pre-authentication integrity(SMB 3.1.1)
|
||||
* SMB3 encryption(CCM, GCM)
|
||||
* SMB direct(RDMA)
|
||||
* SMB3.1.1 POSIX extension support
|
||||
* ACLs
|
||||
* Kerberos
|
||||
|
||||
The features that are planned or not supported:
|
||||
* SMB3 Multi-channel
|
||||
* Durable handle v1,v2
|
||||
* Persistent handles
|
||||
* Directory lease
|
||||
* SMB2 notify
|
||||
|
||||
How to run
|
||||
==========
|
||||
|
||||
1. Download ksmbd-tools and compile them.
|
||||
- https://github.com/cifsd-team/ksmbd-tools
|
||||
|
||||
2. Create user/password for SMB share.
|
||||
|
||||
# mkdir /etc/ksmbd/
|
||||
# ksmbd.adduser -a <Enter USERNAME for SMB share access>
|
||||
|
||||
3. Create /etc/ksmbd/smb.conf file, add SMB share in smb.conf file
|
||||
- Refer smb.conf.example and Documentation/configuration.txt
|
||||
in ksmbd-tools
|
||||
|
||||
4. Insert ksmbd.ko module
|
||||
|
||||
# insmod ksmbd.ko
|
||||
|
||||
5. Start ksmbd user space daemon
|
||||
# ksmbd.mountd
|
||||
|
||||
6. Access share from Windows or Linux using CIFS
|
||||
|
||||
Shutdown CIFSD
|
||||
==============
|
||||
|
||||
1. kill user and kernel space daemon
|
||||
# sudo ksmbd.control -s
|
||||
|
||||
How to turn debug print on
|
||||
==========================
|
||||
|
||||
Each layer
|
||||
/sys/class/ksmbd-control/debug
|
||||
|
||||
1. Enable all component prints
|
||||
# sudo ksmbd.control -d "all"
|
||||
|
||||
2. Enable one of components(smb, auth, vfs, oplock, ipc, conn, rdma)
|
||||
# sudo ksmbd.control -d "smb"
|
||||
|
||||
3. Show what prints are enable.
|
||||
# cat/sys/class/ksmbd-control/debug
|
||||
[smb] auth vfs oplock ipc conn [rdma]
|
||||
|
||||
4. Disable prints:
|
||||
If you try the selected component once more, It is disabled without brackets.
|
||||
416
fs/cifsd/connection.c
Normal file
416
fs/cifsd/connection.c
Normal file
@@ -0,0 +1,416 @@
|
||||
// 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 "buffer_pool.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;
|
||||
|
||||
static LIST_HEAD(conn_list);
|
||||
static DEFINE_RWLOCK(conn_list_lock);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
ksmbd_free_request(conn->request_buf);
|
||||
ksmbd_ida_free(conn->async_ida);
|
||||
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();
|
||||
atomic_set(&conn->req_running, 0);
|
||||
atomic_set(&conn->r_count, 0);
|
||||
init_waitqueue_head(&conn->req_running_q);
|
||||
INIT_LIST_HEAD(&conn->conns_list);
|
||||
INIT_LIST_HEAD(&conn->sessions);
|
||||
INIT_LIST_HEAD(&conn->requests);
|
||||
INIT_LIST_HEAD(&conn->async_requests);
|
||||
spin_lock_init(&conn->request_lock);
|
||||
spin_lock_init(&conn->credits_lock);
|
||||
conn->async_ida = ksmbd_ida_alloc();
|
||||
|
||||
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;
|
||||
|
||||
if (conn->ops->get_cmd_val(work) != SMB2_CANCEL_HE) {
|
||||
requests_queue = &conn->requests;
|
||||
work->syncronous = true;
|
||||
}
|
||||
|
||||
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) &&
|
||||
list_empty(&work->async_request_entry))
|
||||
return 0;
|
||||
|
||||
atomic_dec(&conn->req_running);
|
||||
spin_lock(&conn->request_lock);
|
||||
if (!work->multiRsp) {
|
||||
list_del_init(&work->request_entry);
|
||||
if (work->syncronous == false)
|
||||
list_del_init(&work->async_request_entry);
|
||||
ret = 0;
|
||||
}
|
||||
spin_unlock(&conn->request_lock);
|
||||
|
||||
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;
|
||||
struct smb_hdr *rsp_hdr = RESPONSE_BUF(work);
|
||||
size_t len = 0;
|
||||
int sent;
|
||||
struct kvec iov[3];
|
||||
int iov_idx = 0;
|
||||
|
||||
ksmbd_conn_try_dequeue_request(work);
|
||||
if (!rsp_hdr) {
|
||||
ksmbd_err("NULL response header\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (HAS_TRANSFORM_BUF(work)) {
|
||||
iov[iov_idx] = (struct kvec) { work->tr_buf,
|
||||
sizeof(struct smb2_transform_hdr) };
|
||||
len += iov[iov_idx++].iov_len;
|
||||
}
|
||||
|
||||
if (HAS_AUX_PAYLOAD(work)) {
|
||||
iov[iov_idx] = (struct kvec) { rsp_hdr, RESP_HDR_SIZE(work) };
|
||||
len += iov[iov_idx++].iov_len;
|
||||
iov[iov_idx] = (struct kvec) { AUX_PAYLOAD(work),
|
||||
AUX_PAYLOAD_SIZE(work) };
|
||||
len += iov[iov_idx++].iov_len;
|
||||
} else {
|
||||
if (HAS_TRANSFORM_BUF(work))
|
||||
iov[iov_idx].iov_len = RESP_HDR_SIZE(work);
|
||||
else
|
||||
iov[iov_idx].iov_len = get_rfc1002_len(rsp_hdr) + 4;
|
||||
iov[iov_idx].iov_base = rsp_hdr;
|
||||
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) {
|
||||
ksmbd_err("Failed to send message: %d\n", sent);
|
||||
return sent;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ksmbd_conn_rdma_read(struct ksmbd_conn *conn,
|
||||
void *buf, unsigned int buflen,
|
||||
u32 remote_key, u64 remote_offset,
|
||||
u32 remote_len)
|
||||
{
|
||||
int ret = -EINVAL;
|
||||
|
||||
if (conn->transport->ops->rdma_read)
|
||||
ret = conn->transport->ops->rdma_read(conn->transport,
|
||||
buf, buflen,
|
||||
remote_key, remote_offset,
|
||||
remote_len);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ksmbd_conn_rdma_write(struct ksmbd_conn *conn,
|
||||
void *buf, unsigned int buflen,
|
||||
u32 remote_key, u64 remote_offset,
|
||||
u32 remote_len)
|
||||
{
|
||||
int ret = -EINVAL;
|
||||
|
||||
if (conn->transport->ops->rdma_write)
|
||||
ret = conn->transport->ops->rdma_write(conn->transport,
|
||||
buf, buflen,
|
||||
remote_key, remote_offset,
|
||||
remote_len);
|
||||
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
|
||||
* is bigger than deadtime user configured and openning file count is
|
||||
* zero.
|
||||
*/
|
||||
if (server_conf.deadtime > 0 &&
|
||||
time_after(jiffies, conn->last_active + server_conf.deadtime)) {
|
||||
ksmbd_debug(CONN, "No response from client in %lu minutes\n",
|
||||
server_conf.deadtime / SMB_ECHO_INTERVAL);
|
||||
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;
|
||||
unsigned int pdu_size;
|
||||
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;
|
||||
|
||||
ksmbd_free_request(conn->request_buf);
|
||||
conn->request_buf = NULL;
|
||||
|
||||
size = t->ops->read(t, hdr_buf, sizeof(hdr_buf));
|
||||
if (size != sizeof(hdr_buf))
|
||||
break;
|
||||
|
||||
pdu_size = get_rfc1002_len(hdr_buf);
|
||||
ksmbd_debug(CONN, "RFC1002 header %u bytes\n", pdu_size);
|
||||
|
||||
/* make sure we have enough to get to SMB header end */
|
||||
if (!ksmbd_pdu_size_has_room(pdu_size)) {
|
||||
ksmbd_debug(CONN, "SMB request too short (%u bytes)\n",
|
||||
pdu_size);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* 4 for rfc1002 length field */
|
||||
size = pdu_size + 4;
|
||||
conn->request_buf = ksmbd_alloc_request(size);
|
||||
if (!conn->request_buf)
|
||||
continue;
|
||||
|
||||
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
|
||||
*/
|
||||
size = t->ops->read(t, conn->request_buf + 4, pdu_size);
|
||||
if (size < 0) {
|
||||
ksmbd_err("sock_read failed: %d\n", size);
|
||||
break;
|
||||
}
|
||||
|
||||
if (size != pdu_size) {
|
||||
ksmbd_err("PDU error. Read: %d, Expected: %d\n",
|
||||
size,
|
||||
pdu_size);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!default_conn_ops.process_fn) {
|
||||
ksmbd_err("No connection request callback\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (default_conn_ops.process_fn(conn)) {
|
||||
ksmbd_err("Cannot handle request\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
/* Wait till all reference dropped to the Server object*/
|
||||
while (atomic_read(&conn->r_count) > 0)
|
||||
schedule_timeout(HZ);
|
||||
|
||||
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) {
|
||||
pr_err("Failed to init KSMBD subsystem: %d\n", ret);
|
||||
goto out;
|
||||
}
|
||||
out:
|
||||
mutex_unlock(&init_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void stop_sessions(void)
|
||||
{
|
||||
struct ksmbd_conn *conn;
|
||||
|
||||
again:
|
||||
read_lock(&conn_list_lock);
|
||||
list_for_each_entry(conn, &conn_list, conns_list) {
|
||||
struct task_struct *task;
|
||||
|
||||
task = conn->transport->handler;
|
||||
if (task)
|
||||
ksmbd_debug(CONN, "Stop session handler %s/%d\n",
|
||||
task->comm,
|
||||
task_pid_nr(task));
|
||||
conn->status = KSMBD_SESS_EXITING;
|
||||
}
|
||||
read_unlock(&conn_list_lock);
|
||||
|
||||
if (!list_empty(&conn_list)) {
|
||||
schedule_timeout_interruptible(HZ/10); /* 100ms */
|
||||
goto again;
|
||||
}
|
||||
}
|
||||
|
||||
void ksmbd_conn_transport_destroy(void)
|
||||
{
|
||||
mutex_lock(&init_lock);
|
||||
ksmbd_tcp_destroy();
|
||||
ksmbd_rdma_destroy();
|
||||
stop_sessions();
|
||||
mutex_unlock(&init_lock);
|
||||
}
|
||||
212
fs/cifsd/connection.h
Normal file
212
fs/cifsd/connection.h
Normal file
@@ -0,0 +1,212 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Copyright (C) 2018 Samsung Electronics Co., Ltd.
|
||||
*/
|
||||
|
||||
#ifndef __KSMBD_CONNECTION_H__
|
||||
#define __KSMBD_CONNECTION_H__
|
||||
|
||||
#include <linux/list.h>
|
||||
#include <linux/ip.h>
|
||||
#include <net/sock.h>
|
||||
#include <net/tcp.h>
|
||||
#include <net/inet_connection_sock.h>
|
||||
#include <net/request_sock.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/nls.h>
|
||||
|
||||
#include "smb_common.h"
|
||||
#include "ksmbd_work.h"
|
||||
|
||||
#define KSMBD_SOCKET_BACKLOG 16
|
||||
|
||||
/*
|
||||
* WARNING
|
||||
*
|
||||
* This is nothing but a HACK. Session status should move to channel
|
||||
* or to session. As of now we have 1 tcp_conn : 1 ksmbd_session, but
|
||||
* we need to change it to 1 tcp_conn : N ksmbd_sessions.
|
||||
*/
|
||||
enum {
|
||||
KSMBD_SESS_NEW = 0,
|
||||
KSMBD_SESS_GOOD,
|
||||
KSMBD_SESS_EXITING,
|
||||
KSMBD_SESS_NEED_RECONNECT,
|
||||
KSMBD_SESS_NEED_NEGOTIATE
|
||||
};
|
||||
|
||||
struct ksmbd_stats {
|
||||
atomic_t open_files_count;
|
||||
atomic64_t request_served;
|
||||
};
|
||||
|
||||
struct ksmbd_transport;
|
||||
|
||||
struct ksmbd_conn {
|
||||
struct smb_version_values *vals;
|
||||
struct smb_version_ops *ops;
|
||||
struct smb_version_cmds *cmds;
|
||||
unsigned int max_cmds;
|
||||
struct mutex srv_mutex;
|
||||
int status;
|
||||
unsigned int cli_cap;
|
||||
char *request_buf;
|
||||
struct ksmbd_transport *transport;
|
||||
struct nls_table *local_nls;
|
||||
struct list_head conns_list;
|
||||
/* smb session 1 per user */
|
||||
struct list_head sessions;
|
||||
unsigned long last_active;
|
||||
/* How many request are running currently */
|
||||
atomic_t req_running;
|
||||
/* References which are made for this Server object*/
|
||||
atomic_t r_count;
|
||||
unsigned short total_credits;
|
||||
unsigned short max_credits;
|
||||
spinlock_t credits_lock;
|
||||
wait_queue_head_t req_running_q;
|
||||
/* Lock to protect requests list*/
|
||||
spinlock_t request_lock;
|
||||
struct list_head requests;
|
||||
struct list_head async_requests;
|
||||
int connection_type;
|
||||
struct ksmbd_stats stats;
|
||||
char ClientGUID[SMB2_CLIENT_GUID_SIZE];
|
||||
union {
|
||||
/* pending trans request table */
|
||||
struct trans_state *recent_trans;
|
||||
/* Used by ntlmssp */
|
||||
char *ntlmssp_cryptkey;
|
||||
};
|
||||
|
||||
struct preauth_integrity_info *preauth_info;
|
||||
|
||||
bool need_neg;
|
||||
unsigned int auth_mechs;
|
||||
unsigned int preferred_auth_mech;
|
||||
bool sign;
|
||||
bool use_spnego:1;
|
||||
__u16 cli_sec_mode;
|
||||
__u16 srv_sec_mode;
|
||||
/* dialect index that server chose */
|
||||
__u16 dialect;
|
||||
|
||||
char *mechToken;
|
||||
|
||||
struct ksmbd_conn_ops *conn_ops;
|
||||
|
||||
/* Preauth Session Table */
|
||||
struct list_head preauth_sess_table;
|
||||
|
||||
struct sockaddr_storage peer_addr;
|
||||
|
||||
/* Identifier for async message */
|
||||
struct ksmbd_ida *async_ida;
|
||||
|
||||
__le16 cipher_type;
|
||||
__le16 compress_algorithm;
|
||||
bool posix_ext_supported;
|
||||
};
|
||||
|
||||
struct ksmbd_conn_ops {
|
||||
int (*process_fn)(struct ksmbd_conn *conn);
|
||||
int (*terminate_fn)(struct ksmbd_conn *conn);
|
||||
};
|
||||
|
||||
struct ksmbd_transport_ops {
|
||||
int (*prepare)(struct ksmbd_transport *t);
|
||||
void (*disconnect)(struct ksmbd_transport *t);
|
||||
int (*read)(struct ksmbd_transport *t,
|
||||
char *buf, unsigned int size);
|
||||
int (*writev)(struct ksmbd_transport *t,
|
||||
struct kvec *iovs, int niov, int size,
|
||||
bool need_invalidate_rkey, unsigned int remote_key);
|
||||
int (*rdma_read)(struct ksmbd_transport *t,
|
||||
void *buf, unsigned int len, u32 remote_key,
|
||||
u64 remote_offset, u32 remote_len);
|
||||
int (*rdma_write)(struct ksmbd_transport *t,
|
||||
void *buf, unsigned int len, u32 remote_key,
|
||||
u64 remote_offset, u32 remote_len);
|
||||
};
|
||||
|
||||
struct ksmbd_transport {
|
||||
struct ksmbd_conn *conn;
|
||||
struct ksmbd_transport_ops *ops;
|
||||
struct task_struct *handler;
|
||||
};
|
||||
|
||||
#define KSMBD_TCP_RECV_TIMEOUT (7 * HZ)
|
||||
#define KSMBD_TCP_SEND_TIMEOUT (5 * HZ)
|
||||
#define KSMBD_TCP_PEER_SOCKADDR(c) ((struct sockaddr *)&((c)->peer_addr))
|
||||
|
||||
bool ksmbd_conn_alive(struct ksmbd_conn *conn);
|
||||
void ksmbd_conn_wait_idle(struct ksmbd_conn *conn);
|
||||
|
||||
struct ksmbd_conn *ksmbd_conn_alloc(void);
|
||||
void ksmbd_conn_free(struct ksmbd_conn *conn);
|
||||
bool ksmbd_conn_lookup_dialect(struct ksmbd_conn *c);
|
||||
int ksmbd_conn_write(struct ksmbd_work *work);
|
||||
int ksmbd_conn_rdma_read(struct ksmbd_conn *conn,
|
||||
void *buf, unsigned int buflen,
|
||||
u32 remote_key, u64 remote_offset,
|
||||
u32 remote_len);
|
||||
int ksmbd_conn_rdma_write(struct ksmbd_conn *conn,
|
||||
void *buf, unsigned int buflen,
|
||||
u32 remote_key, u64 remote_offset,
|
||||
u32 remote_len);
|
||||
|
||||
void ksmbd_conn_enqueue_request(struct ksmbd_work *work);
|
||||
int ksmbd_conn_try_dequeue_request(struct ksmbd_work *work);
|
||||
void ksmbd_conn_init_server_callbacks(struct ksmbd_conn_ops *ops);
|
||||
|
||||
int ksmbd_conn_handler_loop(void *p);
|
||||
|
||||
int ksmbd_conn_transport_init(void);
|
||||
void ksmbd_conn_transport_destroy(void);
|
||||
|
||||
/*
|
||||
* WARNING
|
||||
*
|
||||
* This is a hack. We will move status to a proper place once we land
|
||||
* a multi-sessions support.
|
||||
*/
|
||||
static inline bool ksmbd_conn_good(struct ksmbd_work *work)
|
||||
{
|
||||
return work->conn->status == KSMBD_SESS_GOOD;
|
||||
}
|
||||
|
||||
static inline bool ksmbd_conn_need_negotiate(struct ksmbd_work *work)
|
||||
{
|
||||
return work->conn->status == KSMBD_SESS_NEED_NEGOTIATE;
|
||||
}
|
||||
|
||||
static inline bool ksmbd_conn_need_reconnect(struct ksmbd_work *work)
|
||||
{
|
||||
return work->conn->status == KSMBD_SESS_NEED_RECONNECT;
|
||||
}
|
||||
|
||||
static inline bool ksmbd_conn_exiting(struct ksmbd_work *work)
|
||||
{
|
||||
return work->conn->status == KSMBD_SESS_EXITING;
|
||||
}
|
||||
|
||||
static inline void ksmbd_conn_set_good(struct ksmbd_work *work)
|
||||
{
|
||||
work->conn->status = KSMBD_SESS_GOOD;
|
||||
}
|
||||
|
||||
static inline void ksmbd_conn_set_need_negotiate(struct ksmbd_work *work)
|
||||
{
|
||||
work->conn->status = KSMBD_SESS_NEED_NEGOTIATE;
|
||||
}
|
||||
|
||||
static inline void ksmbd_conn_set_need_reconnect(struct ksmbd_work *work)
|
||||
{
|
||||
work->conn->status = KSMBD_SESS_NEED_RECONNECT;
|
||||
}
|
||||
|
||||
static inline void ksmbd_conn_set_exiting(struct ksmbd_work *work)
|
||||
{
|
||||
work->conn->status = KSMBD_SESS_EXITING;
|
||||
}
|
||||
#endif /* __CONNECTION_H__ */
|
||||
67
fs/cifsd/glob.h
Normal file
67
fs/cifsd/glob.h
Normal file
@@ -0,0 +1,67 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Copyright (C) 2016 Namjae Jeon <linkinjeon@kernel.org>
|
||||
* Copyright (C) 2018 Samsung Electronics Co., Ltd.
|
||||
*/
|
||||
|
||||
#ifndef __KSMBD_GLOB_H
|
||||
#define __KSMBD_GLOB_H
|
||||
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/version.h>
|
||||
|
||||
#include "unicode.h"
|
||||
#include "vfs_cache.h"
|
||||
#include "smberr.h"
|
||||
|
||||
#define KSMBD_VERSION "3.1.9"
|
||||
|
||||
/* @FIXME clean up this code */
|
||||
|
||||
extern int ksmbd_debug_types;
|
||||
extern int ksmbd_caseless_search;
|
||||
|
||||
#define DATA_STREAM 1
|
||||
#define DIR_STREAM 2
|
||||
|
||||
#define KSMBD_DEBUG_SMB (1 << 0)
|
||||
#define KSMBD_DEBUG_AUTH (1 << 1)
|
||||
#define KSMBD_DEBUG_VFS (1 << 2)
|
||||
#define KSMBD_DEBUG_OPLOCK (1 << 3)
|
||||
#define KSMBD_DEBUG_IPC (1 << 4)
|
||||
#define KSMBD_DEBUG_CONN (1 << 5)
|
||||
#define KSMBD_DEBUG_RDMA (1 << 6)
|
||||
#define KSMBD_DEBUG_ALL (KSMBD_DEBUG_SMB | KSMBD_DEBUG_AUTH | \
|
||||
KSMBD_DEBUG_VFS | KSMBD_DEBUG_OPLOCK | \
|
||||
KSMBD_DEBUG_IPC | KSMBD_DEBUG_CONN | \
|
||||
KSMBD_DEBUG_RDMA)
|
||||
|
||||
#ifndef ksmbd_pr_fmt
|
||||
#ifdef SUBMOD_NAME
|
||||
#define ksmbd_pr_fmt(fmt) "ksmbd: " SUBMOD_NAME ": " fmt
|
||||
#else
|
||||
#define ksmbd_pr_fmt(fmt) "ksmbd: " fmt
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define ksmbd_debug(type, fmt, ...) \
|
||||
do { \
|
||||
if (ksmbd_debug_types & KSMBD_DEBUG_##type) \
|
||||
pr_info(ksmbd_pr_fmt("%s:%d: " fmt), \
|
||||
__func__, \
|
||||
__LINE__, \
|
||||
##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define ksmbd_info(fmt, ...) \
|
||||
pr_info(ksmbd_pr_fmt(fmt), ##__VA_ARGS__)
|
||||
|
||||
#define ksmbd_err(fmt, ...) \
|
||||
pr_err(ksmbd_pr_fmt("%s:%d: " fmt), \
|
||||
__func__, \
|
||||
__LINE__, \
|
||||
##__VA_ARGS__)
|
||||
|
||||
#define UNICODE_LEN(x) ((x) * 2)
|
||||
|
||||
#endif /* __KSMBD_GLOB_H */
|
||||
285
fs/cifsd/ksmbd_server.h
Normal file
285
fs/cifsd/ksmbd_server.h
Normal file
@@ -0,0 +1,285 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Copyright (C) 2018 Samsung Electronics Co., Ltd.
|
||||
*
|
||||
* linux-ksmbd-devel@lists.sourceforge.net
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_KSMBD_SERVER_H
|
||||
#define _LINUX_KSMBD_SERVER_H
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
#define KSMBD_GENL_NAME "SMBD_GENL"
|
||||
#define KSMBD_GENL_VERSION 0x01
|
||||
|
||||
#ifndef ____ksmbd_align
|
||||
#define ____ksmbd_align __aligned(4)
|
||||
#endif
|
||||
|
||||
#define KSMBD_REQ_MAX_ACCOUNT_NAME_SZ 48
|
||||
#define KSMBD_REQ_MAX_HASH_SZ 18
|
||||
#define KSMBD_REQ_MAX_SHARE_NAME 64
|
||||
|
||||
struct ksmbd_heartbeat {
|
||||
__u32 handle;
|
||||
};
|
||||
|
||||
/*
|
||||
* Global config flags.
|
||||
*/
|
||||
#define KSMBD_GLOBAL_FLAG_INVALID (0)
|
||||
#define KSMBD_GLOBAL_FLAG_SMB2_LEASES (1 << 0)
|
||||
#define KSMBD_GLOBAL_FLAG_CACHE_TBUF (1 << 1)
|
||||
#define KSMBD_GLOBAL_FLAG_CACHE_RBUF (1 << 2)
|
||||
#define KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION (1 << 3)
|
||||
#define KSMBD_GLOBAL_FLAG_DURABLE_HANDLE (1 << 4)
|
||||
|
||||
struct ksmbd_startup_request {
|
||||
__u32 flags;
|
||||
__s32 signing;
|
||||
__s8 min_prot[16];
|
||||
__s8 max_prot[16];
|
||||
__s8 netbios_name[16];
|
||||
__s8 work_group[64];
|
||||
__s8 server_string[64];
|
||||
__u16 tcp_port;
|
||||
__u16 ipc_timeout;
|
||||
__u32 deadtime;
|
||||
__u32 file_max;
|
||||
__u32 smb2_max_write;
|
||||
__u32 smb2_max_read;
|
||||
__u32 smb2_max_trans;
|
||||
__u32 share_fake_fscaps;
|
||||
__u32 sub_auth[3];
|
||||
__u32 ifc_list_sz;
|
||||
__s8 ____payload[0];
|
||||
} ____ksmbd_align;
|
||||
|
||||
#define KSMBD_STARTUP_CONFIG_INTERFACES(s) ((s)->____payload)
|
||||
|
||||
struct ksmbd_shutdown_request {
|
||||
__s32 reserved;
|
||||
} ____ksmbd_align;
|
||||
|
||||
struct ksmbd_login_request {
|
||||
__u32 handle;
|
||||
__s8 account[KSMBD_REQ_MAX_ACCOUNT_NAME_SZ];
|
||||
} ____ksmbd_align;
|
||||
|
||||
struct ksmbd_login_response {
|
||||
__u32 handle;
|
||||
__u32 gid;
|
||||
__u32 uid;
|
||||
__s8 account[KSMBD_REQ_MAX_ACCOUNT_NAME_SZ];
|
||||
__u16 status;
|
||||
__u16 hash_sz;
|
||||
__s8 hash[KSMBD_REQ_MAX_HASH_SZ];
|
||||
} ____ksmbd_align;
|
||||
|
||||
struct ksmbd_share_config_request {
|
||||
__u32 handle;
|
||||
__s8 share_name[KSMBD_REQ_MAX_SHARE_NAME];
|
||||
} ____ksmbd_align;
|
||||
|
||||
struct ksmbd_share_config_response {
|
||||
__u32 handle;
|
||||
__u32 flags;
|
||||
__u16 create_mask;
|
||||
__u16 directory_mask;
|
||||
__u16 force_create_mode;
|
||||
__u16 force_directory_mode;
|
||||
__u16 force_uid;
|
||||
__u16 force_gid;
|
||||
__u32 veto_list_sz;
|
||||
__s8 ____payload[0];
|
||||
} ____ksmbd_align;
|
||||
|
||||
#define KSMBD_SHARE_CONFIG_VETO_LIST(s) ((s)->____payload)
|
||||
#define KSMBD_SHARE_CONFIG_PATH(s) \
|
||||
({ \
|
||||
char *p = (s)->____payload; \
|
||||
if ((s)->veto_list_sz) \
|
||||
p += (s)->veto_list_sz + 1; \
|
||||
p; \
|
||||
})
|
||||
|
||||
struct ksmbd_tree_connect_request {
|
||||
__u32 handle;
|
||||
__u16 account_flags;
|
||||
__u16 flags;
|
||||
__u64 session_id;
|
||||
__u64 connect_id;
|
||||
__s8 account[KSMBD_REQ_MAX_ACCOUNT_NAME_SZ];
|
||||
__s8 share[KSMBD_REQ_MAX_SHARE_NAME];
|
||||
__s8 peer_addr[64];
|
||||
} ____ksmbd_align;
|
||||
|
||||
struct ksmbd_tree_connect_response {
|
||||
__u32 handle;
|
||||
__u16 status;
|
||||
__u16 connection_flags;
|
||||
} ____ksmbd_align;
|
||||
|
||||
struct ksmbd_tree_disconnect_request {
|
||||
__u64 session_id;
|
||||
__u64 connect_id;
|
||||
} ____ksmbd_align;
|
||||
|
||||
struct ksmbd_logout_request {
|
||||
__s8 account[KSMBD_REQ_MAX_ACCOUNT_NAME_SZ];
|
||||
} ____ksmbd_align;
|
||||
|
||||
struct ksmbd_rpc_command {
|
||||
__u32 handle;
|
||||
__u32 flags;
|
||||
__u32 payload_sz;
|
||||
__u8 payload[0];
|
||||
} ____ksmbd_align;
|
||||
|
||||
struct ksmbd_spnego_authen_request {
|
||||
__u32 handle;
|
||||
__u16 spnego_blob_len;
|
||||
__u8 spnego_blob[0];
|
||||
} ____ksmbd_align;
|
||||
|
||||
struct ksmbd_spnego_authen_response {
|
||||
__u32 handle;
|
||||
struct ksmbd_login_response login_response;
|
||||
__u16 session_key_len;
|
||||
__u16 spnego_blob_len;
|
||||
__u8 payload[0]; /* session key + AP_REP */
|
||||
} ____ksmbd_align;
|
||||
|
||||
/*
|
||||
* This also used as NETLINK attribute type value.
|
||||
*
|
||||
* NOTE:
|
||||
* Response message type value should be equal to
|
||||
* request message type value + 1.
|
||||
*/
|
||||
enum ksmbd_event {
|
||||
KSMBD_EVENT_UNSPEC = 0,
|
||||
KSMBD_EVENT_HEARTBEAT_REQUEST,
|
||||
|
||||
KSMBD_EVENT_STARTING_UP,
|
||||
KSMBD_EVENT_SHUTTING_DOWN,
|
||||
|
||||
KSMBD_EVENT_LOGIN_REQUEST,
|
||||
KSMBD_EVENT_LOGIN_RESPONSE = 5,
|
||||
|
||||
KSMBD_EVENT_SHARE_CONFIG_REQUEST,
|
||||
KSMBD_EVENT_SHARE_CONFIG_RESPONSE,
|
||||
|
||||
KSMBD_EVENT_TREE_CONNECT_REQUEST,
|
||||
KSMBD_EVENT_TREE_CONNECT_RESPONSE,
|
||||
|
||||
KSMBD_EVENT_TREE_DISCONNECT_REQUEST = 10,
|
||||
|
||||
KSMBD_EVENT_LOGOUT_REQUEST,
|
||||
|
||||
KSMBD_EVENT_RPC_REQUEST,
|
||||
KSMBD_EVENT_RPC_RESPONSE,
|
||||
|
||||
KSMBD_EVENT_SPNEGO_AUTHEN_REQUEST,
|
||||
KSMBD_EVENT_SPNEGO_AUTHEN_RESPONSE = 15,
|
||||
|
||||
KSMBD_EVENT_MAX
|
||||
};
|
||||
|
||||
enum KSMBD_TREE_CONN_STATUS {
|
||||
KSMBD_TREE_CONN_STATUS_OK = 0,
|
||||
KSMBD_TREE_CONN_STATUS_NOMEM,
|
||||
KSMBD_TREE_CONN_STATUS_NO_SHARE,
|
||||
KSMBD_TREE_CONN_STATUS_NO_USER,
|
||||
KSMBD_TREE_CONN_STATUS_INVALID_USER,
|
||||
KSMBD_TREE_CONN_STATUS_HOST_DENIED = 5,
|
||||
KSMBD_TREE_CONN_STATUS_CONN_EXIST,
|
||||
KSMBD_TREE_CONN_STATUS_TOO_MANY_CONNS,
|
||||
KSMBD_TREE_CONN_STATUS_TOO_MANY_SESSIONS,
|
||||
KSMBD_TREE_CONN_STATUS_ERROR,
|
||||
};
|
||||
|
||||
/*
|
||||
* User config flags.
|
||||
*/
|
||||
#define KSMBD_USER_FLAG_INVALID (0)
|
||||
#define KSMBD_USER_FLAG_OK (1 << 0)
|
||||
#define KSMBD_USER_FLAG_BAD_PASSWORD (1 << 1)
|
||||
#define KSMBD_USER_FLAG_BAD_UID (1 << 2)
|
||||
#define KSMBD_USER_FLAG_BAD_USER (1 << 3)
|
||||
#define KSMBD_USER_FLAG_GUEST_ACCOUNT (1 << 4)
|
||||
|
||||
/*
|
||||
* Share config flags.
|
||||
*/
|
||||
#define KSMBD_SHARE_FLAG_INVALID (0)
|
||||
#define KSMBD_SHARE_FLAG_AVAILABLE (1 << 0)
|
||||
#define KSMBD_SHARE_FLAG_BROWSEABLE (1 << 1)
|
||||
#define KSMBD_SHARE_FLAG_WRITEABLE (1 << 2)
|
||||
#define KSMBD_SHARE_FLAG_READONLY (1 << 3)
|
||||
#define KSMBD_SHARE_FLAG_GUEST_OK (1 << 4)
|
||||
#define KSMBD_SHARE_FLAG_GUEST_ONLY (1 << 5)
|
||||
#define KSMBD_SHARE_FLAG_STORE_DOS_ATTRS (1 << 6)
|
||||
#define KSMBD_SHARE_FLAG_OPLOCKS (1 << 7)
|
||||
#define KSMBD_SHARE_FLAG_PIPE (1 << 8)
|
||||
#define KSMBD_SHARE_FLAG_HIDE_DOT_FILES (1 << 9)
|
||||
#define KSMBD_SHARE_FLAG_INHERIT_SMACK (1 << 10)
|
||||
#define KSMBD_SHARE_FLAG_INHERIT_OWNER (1 << 11)
|
||||
#define KSMBD_SHARE_FLAG_STREAMS (1 << 12)
|
||||
#define KSMBD_SHARE_FLAG_FOLLOW_SYMLINKS (1 << 13)
|
||||
#define KSMBD_SHARE_FLAG_ACL_XATTR (1 << 14)
|
||||
|
||||
/*
|
||||
* Tree connect request flags.
|
||||
*/
|
||||
#define KSMBD_TREE_CONN_FLAG_REQUEST_SMB1 (0)
|
||||
#define KSMBD_TREE_CONN_FLAG_REQUEST_IPV6 (1 << 0)
|
||||
#define KSMBD_TREE_CONN_FLAG_REQUEST_SMB2 (1 << 1)
|
||||
|
||||
/*
|
||||
* Tree connect flags.
|
||||
*/
|
||||
#define KSMBD_TREE_CONN_FLAG_GUEST_ACCOUNT (1 << 0)
|
||||
#define KSMBD_TREE_CONN_FLAG_READ_ONLY (1 << 1)
|
||||
#define KSMBD_TREE_CONN_FLAG_WRITABLE (1 << 2)
|
||||
#define KSMBD_TREE_CONN_FLAG_ADMIN_ACCOUNT (1 << 3)
|
||||
|
||||
/*
|
||||
* RPC over IPC.
|
||||
*/
|
||||
#define KSMBD_RPC_METHOD_RETURN (1 << 0)
|
||||
#define KSMBD_RPC_SRVSVC_METHOD_INVOKE (1 << 1)
|
||||
#define KSMBD_RPC_SRVSVC_METHOD_RETURN ((1 << 1) | KSMBD_RPC_METHOD_RETURN)
|
||||
#define KSMBD_RPC_WKSSVC_METHOD_INVOKE (1 << 2)
|
||||
#define KSMBD_RPC_WKSSVC_METHOD_RETURN ((1 << 2) | KSMBD_RPC_METHOD_RETURN)
|
||||
#define KSMBD_RPC_IOCTL_METHOD ((1 << 3) | KSMBD_RPC_METHOD_RETURN)
|
||||
#define KSMBD_RPC_OPEN_METHOD (1 << 4)
|
||||
#define KSMBD_RPC_WRITE_METHOD (1 << 5)
|
||||
#define KSMBD_RPC_READ_METHOD ((1 << 6) | KSMBD_RPC_METHOD_RETURN)
|
||||
#define KSMBD_RPC_CLOSE_METHOD (1 << 7)
|
||||
#define KSMBD_RPC_RAP_METHOD ((1 << 8) | KSMBD_RPC_METHOD_RETURN)
|
||||
#define KSMBD_RPC_RESTRICTED_CONTEXT (1 << 9)
|
||||
#define KSMBD_RPC_SAMR_METHOD_INVOKE (1 << 10)
|
||||
#define KSMBD_RPC_SAMR_METHOD_RETURN ((1 << 10) | KSMBD_RPC_METHOD_RETURN)
|
||||
#define KSMBD_RPC_LSARPC_METHOD_INVOKE (1 << 11)
|
||||
#define KSMBD_RPC_LSARPC_METHOD_RETURN ((1 << 11) | KSMBD_RPC_METHOD_RETURN)
|
||||
|
||||
#define KSMBD_RPC_OK 0
|
||||
#define KSMBD_RPC_EBAD_FUNC 0x00000001
|
||||
#define KSMBD_RPC_EACCESS_DENIED 0x00000005
|
||||
#define KSMBD_RPC_EBAD_FID 0x00000006
|
||||
#define KSMBD_RPC_ENOMEM 0x00000008
|
||||
#define KSMBD_RPC_EBAD_DATA 0x0000000D
|
||||
#define KSMBD_RPC_ENOTIMPLEMENTED 0x00000040
|
||||
#define KSMBD_RPC_EINVALID_PARAMETER 0x00000057
|
||||
#define KSMBD_RPC_EMORE_DATA 0x000000EA
|
||||
#define KSMBD_RPC_EINVALID_LEVEL 0x0000007C
|
||||
#define KSMBD_RPC_SOME_NOT_MAPPED 0x00000107
|
||||
|
||||
#define KSMBD_CONFIG_OPT_DISABLED 0
|
||||
#define KSMBD_CONFIG_OPT_ENABLED 1
|
||||
#define KSMBD_CONFIG_OPT_AUTO 2
|
||||
#define KSMBD_CONFIG_OPT_MANDATORY 3
|
||||
|
||||
#endif /* _LINUX_KSMBD_SERVER_H */
|
||||
93
fs/cifsd/ksmbd_work.c
Normal file
93
fs/cifsd/ksmbd_work.c
Normal file
@@ -0,0 +1,93 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (C) 2019 Samsung Electronics Co., Ltd.
|
||||
*/
|
||||
|
||||
#include <linux/list.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
#include "server.h"
|
||||
#include "connection.h"
|
||||
#include "ksmbd_work.h"
|
||||
#include "buffer_pool.h"
|
||||
#include "mgmt/ksmbd_ida.h"
|
||||
|
||||
/* @FIXME */
|
||||
#include "ksmbd_server.h"
|
||||
|
||||
static struct kmem_cache *work_cache;
|
||||
static struct workqueue_struct *ksmbd_wq;
|
||||
|
||||
struct ksmbd_work *ksmbd_alloc_work_struct(void)
|
||||
{
|
||||
struct ksmbd_work *work = kmem_cache_zalloc(work_cache, GFP_KERNEL);
|
||||
|
||||
if (work) {
|
||||
work->compound_fid = KSMBD_NO_FID;
|
||||
work->compound_pfid = KSMBD_NO_FID;
|
||||
INIT_LIST_HEAD(&work->request_entry);
|
||||
INIT_LIST_HEAD(&work->async_request_entry);
|
||||
INIT_LIST_HEAD(&work->fp_entry);
|
||||
INIT_LIST_HEAD(&work->interim_entry);
|
||||
}
|
||||
return work;
|
||||
}
|
||||
|
||||
void ksmbd_free_work_struct(struct ksmbd_work *work)
|
||||
{
|
||||
WARN_ON(work->saved_cred != NULL);
|
||||
if (server_conf.flags & KSMBD_GLOBAL_FLAG_CACHE_TBUF &&
|
||||
work->set_trans_buf)
|
||||
ksmbd_release_buffer(RESPONSE_BUF(work));
|
||||
else
|
||||
ksmbd_free_response(RESPONSE_BUF(work));
|
||||
|
||||
if (server_conf.flags & KSMBD_GLOBAL_FLAG_CACHE_RBUF &&
|
||||
work->set_read_buf)
|
||||
ksmbd_release_buffer(AUX_PAYLOAD(work));
|
||||
else
|
||||
ksmbd_free_response(AUX_PAYLOAD(work));
|
||||
|
||||
ksmbd_free_response(TRANSFORM_BUF(work));
|
||||
ksmbd_free_request(REQUEST_BUF(work));
|
||||
if (work->async_id)
|
||||
ksmbd_release_id(work->conn->async_ida, work->async_id);
|
||||
kmem_cache_free(work_cache, work);
|
||||
}
|
||||
|
||||
void ksmbd_work_pool_destroy(void)
|
||||
{
|
||||
kmem_cache_destroy(work_cache);
|
||||
}
|
||||
|
||||
int ksmbd_work_pool_init(void)
|
||||
{
|
||||
work_cache = kmem_cache_create("ksmbd_work_cache",
|
||||
sizeof(struct ksmbd_work), 0,
|
||||
SLAB_HWCACHE_ALIGN, NULL);
|
||||
if (!work_cache)
|
||||
return -ENOMEM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ksmbd_workqueue_init(void)
|
||||
{
|
||||
ksmbd_wq = alloc_workqueue("ksmbd-io", 0, 0);
|
||||
if (!ksmbd_wq)
|
||||
return -ENOMEM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ksmbd_workqueue_destroy(void)
|
||||
{
|
||||
flush_workqueue(ksmbd_wq);
|
||||
destroy_workqueue(ksmbd_wq);
|
||||
ksmbd_wq = NULL;
|
||||
}
|
||||
|
||||
bool ksmbd_queue_work(struct ksmbd_work *work)
|
||||
{
|
||||
return queue_work(ksmbd_wq, &work->work);
|
||||
}
|
||||
124
fs/cifsd/ksmbd_work.h
Normal file
124
fs/cifsd/ksmbd_work.h
Normal file
@@ -0,0 +1,124 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Copyright (C) 2019 Samsung Electronics Co., Ltd.
|
||||
*/
|
||||
|
||||
#ifndef __KSMBD_WORK_H__
|
||||
#define __KSMBD_WORK_H__
|
||||
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
struct ksmbd_conn;
|
||||
struct ksmbd_session;
|
||||
struct ksmbd_tree_connect;
|
||||
|
||||
enum {
|
||||
KSMBD_WORK_ACTIVE = 0,
|
||||
KSMBD_WORK_CANCELLED,
|
||||
KSMBD_WORK_CLOSED,
|
||||
};
|
||||
|
||||
/* one of these for every pending CIFS request at the connection */
|
||||
struct ksmbd_work {
|
||||
/* Server corresponding to this mid */
|
||||
struct ksmbd_conn *conn;
|
||||
struct ksmbd_session *sess;
|
||||
struct ksmbd_tree_connect *tcon;
|
||||
|
||||
/* Pointer to received SMB header */
|
||||
char *request_buf;
|
||||
/* Response buffer */
|
||||
char *response_buf;
|
||||
|
||||
/* Read data buffer */
|
||||
char *aux_payload_buf;
|
||||
|
||||
/* Next cmd hdr in compound req buf*/
|
||||
int next_smb2_rcv_hdr_off;
|
||||
/* Next cmd hdr in compound rsp buf*/
|
||||
int next_smb2_rsp_hdr_off;
|
||||
|
||||
/*
|
||||
* Current Local FID assigned compound response if SMB2 CREATE
|
||||
* command is present in compound request
|
||||
*/
|
||||
unsigned int compound_fid;
|
||||
unsigned int compound_pfid;
|
||||
unsigned int compound_sid;
|
||||
|
||||
const struct cred *saved_cred;
|
||||
|
||||
/* Number of granted credits */
|
||||
unsigned int credits_granted;
|
||||
|
||||
/* response smb header size */
|
||||
unsigned int resp_hdr_sz;
|
||||
unsigned int response_sz;
|
||||
/* Read data count */
|
||||
unsigned int aux_payload_sz;
|
||||
|
||||
void *tr_buf;
|
||||
|
||||
unsigned char state;
|
||||
/* Multiple responses for one request e.g. SMB ECHO */
|
||||
bool multiRsp:1;
|
||||
/* No response for cancelled request */
|
||||
bool send_no_response:1;
|
||||
/* Request is encrypted */
|
||||
bool encrypted:1;
|
||||
/* Is this SYNC or ASYNC ksmbd_work */
|
||||
bool syncronous:1;
|
||||
bool need_invalidate_rkey:1;
|
||||
bool set_trans_buf:1;
|
||||
bool set_read_buf:1;
|
||||
|
||||
unsigned int remote_key;
|
||||
/* cancel works */
|
||||
int async_id;
|
||||
void **cancel_argv;
|
||||
void (*cancel_fn)(void **argv);
|
||||
|
||||
struct work_struct work;
|
||||
/* List head at conn->requests */
|
||||
struct list_head request_entry;
|
||||
/* List head at conn->async_requests */
|
||||
struct list_head async_request_entry;
|
||||
struct list_head fp_entry;
|
||||
struct list_head interim_entry;
|
||||
};
|
||||
|
||||
#define WORK_CANCELLED(w) ((w)->state == KSMBD_WORK_CANCELLED)
|
||||
#define WORK_CLOSED(w) ((w)->state == KSMBD_WORK_CLOSED)
|
||||
#define WORK_ACTIVE(w) ((w)->state == KSMBD_WORK_ACTIVE)
|
||||
|
||||
#define RESPONSE_BUF(w) ((void *)(w)->response_buf)
|
||||
#define REQUEST_BUF(w) ((void *)(w)->request_buf)
|
||||
|
||||
#define RESPONSE_BUF_NEXT(w) \
|
||||
((void *)((w)->response_buf + (w)->next_smb2_rsp_hdr_off))
|
||||
#define REQUEST_BUF_NEXT(w) \
|
||||
((void *)((w)->request_buf + (w)->next_smb2_rcv_hdr_off))
|
||||
|
||||
#define RESPONSE_SZ(w) ((w)->response_sz)
|
||||
|
||||
#define INIT_AUX_PAYLOAD(w) ((w)->aux_payload_buf = NULL)
|
||||
#define HAS_AUX_PAYLOAD(w) ((w)->aux_payload_sz != 0)
|
||||
#define AUX_PAYLOAD(w) ((void *)((w)->aux_payload_buf))
|
||||
#define AUX_PAYLOAD_SIZE(w) ((w)->aux_payload_sz)
|
||||
#define RESP_HDR_SIZE(w) ((w)->resp_hdr_sz)
|
||||
|
||||
#define HAS_TRANSFORM_BUF(w) ((w)->tr_buf != NULL)
|
||||
#define TRANSFORM_BUF(w) ((void *)((w)->tr_buf))
|
||||
|
||||
struct ksmbd_work *ksmbd_alloc_work_struct(void);
|
||||
void ksmbd_free_work_struct(struct ksmbd_work *work);
|
||||
|
||||
void ksmbd_work_pool_destroy(void);
|
||||
int ksmbd_work_pool_init(void);
|
||||
|
||||
int ksmbd_workqueue_init(void);
|
||||
void ksmbd_workqueue_destroy(void);
|
||||
bool ksmbd_queue_work(struct ksmbd_work *work);
|
||||
|
||||
#endif /* __KSMBD_WORK_H__ */
|
||||
635
fs/cifsd/server.c
Normal file
635
fs/cifsd/server.c
Normal file
File diff suppressed because it is too large
Load Diff
62
fs/cifsd/server.h
Normal file
62
fs/cifsd/server.h
Normal file
@@ -0,0 +1,62 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Copyright (C) 2018 Samsung Electronics Co., Ltd.
|
||||
*/
|
||||
|
||||
#ifndef __SERVER_H__
|
||||
#define __SERVER_H__
|
||||
|
||||
#include "smbacl.h"
|
||||
|
||||
#define SERVER_STATE_STARTING_UP 0
|
||||
#define SERVER_STATE_RUNNING 1
|
||||
#define SERVER_STATE_RESETTING 2
|
||||
#define SERVER_STATE_SHUTTING_DOWN 3
|
||||
|
||||
#define SERVER_CONF_NETBIOS_NAME 0
|
||||
#define SERVER_CONF_SERVER_STRING 1
|
||||
#define SERVER_CONF_WORK_GROUP 2
|
||||
|
||||
extern int ksmbd_debugging;
|
||||
|
||||
struct ksmbd_server_config {
|
||||
unsigned int flags;
|
||||
unsigned int state;
|
||||
short signing;
|
||||
short enforced_signing;
|
||||
short min_protocol;
|
||||
short max_protocol;
|
||||
unsigned short tcp_port;
|
||||
unsigned short ipc_timeout;
|
||||
unsigned long ipc_last_active;
|
||||
unsigned long deadtime;
|
||||
unsigned int share_fake_fscaps;
|
||||
struct smb_sid domain_sid;
|
||||
unsigned int auth_mechs;
|
||||
|
||||
char *conf[SERVER_CONF_WORK_GROUP + 1];
|
||||
};
|
||||
|
||||
extern struct ksmbd_server_config server_conf;
|
||||
|
||||
int ksmbd_set_netbios_name(char *v);
|
||||
int ksmbd_set_server_string(char *v);
|
||||
int ksmbd_set_work_group(char *v);
|
||||
|
||||
char *ksmbd_netbios_name(void);
|
||||
char *ksmbd_server_string(void);
|
||||
char *ksmbd_work_group(void);
|
||||
|
||||
static inline int ksmbd_server_running(void)
|
||||
{
|
||||
return READ_ONCE(server_conf.state) == SERVER_STATE_RUNNING;
|
||||
}
|
||||
|
||||
static inline int ksmbd_server_configurable(void)
|
||||
{
|
||||
return READ_ONCE(server_conf.state) < SERVER_STATE_RESETTING;
|
||||
}
|
||||
|
||||
int server_queue_ctrl_init_work(void);
|
||||
int server_queue_ctrl_reset_work(void);
|
||||
#endif /* __SERVER_H__ */
|
||||
900
fs/cifsd/transport_ipc.c
Normal file
900
fs/cifsd/transport_ipc.c
Normal file
File diff suppressed because it is too large
Load Diff
63
fs/cifsd/transport_ipc.h
Normal file
63
fs/cifsd/transport_ipc.h
Normal file
@@ -0,0 +1,63 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Copyright (C) 2018 Samsung Electronics Co., Ltd.
|
||||
*/
|
||||
|
||||
#ifndef __KSMBD_TRANSPORT_IPC_H__
|
||||
#define __KSMBD_TRANSPORT_IPC_H__
|
||||
|
||||
#include <linux/wait.h>
|
||||
#include "ksmbd_server.h" /* FIXME */
|
||||
|
||||
#define KSMBD_IPC_MAX_PAYLOAD 4096
|
||||
|
||||
struct ksmbd_login_response *
|
||||
ksmbd_ipc_login_request(const char *account);
|
||||
|
||||
struct ksmbd_session;
|
||||
struct ksmbd_share_config;
|
||||
struct ksmbd_tree_connect;
|
||||
struct sockaddr;
|
||||
|
||||
struct ksmbd_tree_connect_response *
|
||||
ksmbd_ipc_tree_connect_request(struct ksmbd_session *sess,
|
||||
struct ksmbd_share_config *share,
|
||||
struct ksmbd_tree_connect *tree_conn,
|
||||
struct sockaddr *peer_addr);
|
||||
|
||||
int ksmbd_ipc_tree_disconnect_request(unsigned long long session_id,
|
||||
unsigned long long connect_id);
|
||||
int ksmbd_ipc_logout_request(const char *account);
|
||||
|
||||
struct ksmbd_share_config_response *
|
||||
ksmbd_ipc_share_config_request(const char *name);
|
||||
|
||||
struct ksmbd_spnego_authen_response *
|
||||
ksmbd_ipc_spnego_authen_request(const char *spnego_blob, int blob_len);
|
||||
|
||||
int ksmbd_ipc_id_alloc(void);
|
||||
void ksmbd_rpc_id_free(int handle);
|
||||
|
||||
struct ksmbd_rpc_command *ksmbd_rpc_open(struct ksmbd_session *sess,
|
||||
int handle);
|
||||
struct ksmbd_rpc_command *ksmbd_rpc_close(struct ksmbd_session *sess,
|
||||
int handle);
|
||||
|
||||
struct ksmbd_rpc_command *ksmbd_rpc_write(struct ksmbd_session *sess,
|
||||
int handle,
|
||||
void *payload,
|
||||
size_t payload_sz);
|
||||
struct ksmbd_rpc_command *ksmbd_rpc_read(struct ksmbd_session *sess,
|
||||
int handle);
|
||||
struct ksmbd_rpc_command *ksmbd_rpc_ioctl(struct ksmbd_session *sess,
|
||||
int handle,
|
||||
void *payload,
|
||||
size_t payload_sz);
|
||||
struct ksmbd_rpc_command *ksmbd_rpc_rap(struct ksmbd_session *sess,
|
||||
void *payload,
|
||||
size_t payload_sz);
|
||||
|
||||
void ksmbd_ipc_release(void);
|
||||
void ksmbd_ipc_soft_reset(void);
|
||||
int ksmbd_ipc_init(void);
|
||||
#endif /* __KSMBD_TRANSPORT_IPC_H__ */
|
||||
2050
fs/cifsd/transport_rdma.c
Normal file
2050
fs/cifsd/transport_rdma.c
Normal file
File diff suppressed because it is too large
Load Diff
61
fs/cifsd/transport_rdma.h
Normal file
61
fs/cifsd/transport_rdma.h
Normal file
@@ -0,0 +1,61 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Copyright (C) 2017, Microsoft Corporation.
|
||||
* Copyright (C) 2018, LG Electronics.
|
||||
*/
|
||||
|
||||
#ifndef __KSMBD_TRANSPORT_RDMA_H__
|
||||
#define __KSMBD_TRANSPORT_RDMA_H__
|
||||
|
||||
#define SMB_DIRECT_PORT 5445
|
||||
|
||||
/* SMB DIRECT negotiation request packet [MS-KSMBD] 2.2.1 */
|
||||
struct smb_direct_negotiate_req {
|
||||
__le16 min_version;
|
||||
__le16 max_version;
|
||||
__le16 reserved;
|
||||
__le16 credits_requested;
|
||||
__le32 preferred_send_size;
|
||||
__le32 max_receive_size;
|
||||
__le32 max_fragmented_size;
|
||||
} __packed;
|
||||
|
||||
/* SMB DIRECT negotiation response packet [MS-KSMBD] 2.2.2 */
|
||||
struct smb_direct_negotiate_resp {
|
||||
__le16 min_version;
|
||||
__le16 max_version;
|
||||
__le16 negotiated_version;
|
||||
__le16 reserved;
|
||||
__le16 credits_requested;
|
||||
__le16 credits_granted;
|
||||
__le32 status;
|
||||
__le32 max_readwrite_size;
|
||||
__le32 preferred_send_size;
|
||||
__le32 max_receive_size;
|
||||
__le32 max_fragmented_size;
|
||||
} __packed;
|
||||
|
||||
#define SMB_DIRECT_RESPONSE_REQUESTED 0x0001
|
||||
|
||||
/* SMB DIRECT data transfer packet with payload [MS-KSMBD] 2.2.3 */
|
||||
struct smb_direct_data_transfer {
|
||||
__le16 credits_requested;
|
||||
__le16 credits_granted;
|
||||
__le16 flags;
|
||||
__le16 reserved;
|
||||
__le32 remaining_data_length;
|
||||
__le32 data_offset;
|
||||
__le32 data_length;
|
||||
__le32 padding;
|
||||
__u8 buffer[];
|
||||
} __packed;
|
||||
|
||||
#ifdef CONFIG_SMB_SERVER_SMBDIRECT
|
||||
int ksmbd_rdma_init(void);
|
||||
int ksmbd_rdma_destroy(void);
|
||||
#else
|
||||
static inline int ksmbd_rdma_init(void) { return 0; }
|
||||
static inline int ksmbd_rdma_destroy(void) { return 0; }
|
||||
#endif
|
||||
|
||||
#endif /* __KSMBD_TRANSPORT_RDMA_H__ */
|
||||
624
fs/cifsd/transport_tcp.c
Normal file
624
fs/cifsd/transport_tcp.c
Normal file
File diff suppressed because it is too large
Load Diff
13
fs/cifsd/transport_tcp.h
Normal file
13
fs/cifsd/transport_tcp.h
Normal file
@@ -0,0 +1,13 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Copyright (C) 2018 Samsung Electronics Co., Ltd.
|
||||
*/
|
||||
|
||||
#ifndef __KSMBD_TRANSPORT_TCP_H__
|
||||
#define __KSMBD_TRANSPORT_TCP_H__
|
||||
|
||||
int ksmbd_tcp_set_interfaces(char *ifc_list, int ifc_list_sz);
|
||||
int ksmbd_tcp_init(void);
|
||||
void ksmbd_tcp_destroy(void);
|
||||
|
||||
#endif /* __KSMBD_TRANSPORT_TCP_H__ */
|
||||
Reference in New Issue
Block a user