138c8a9a5SSteve French // SPDX-License-Identifier: GPL-2.0-or-later
238c8a9a5SSteve French /*
338c8a9a5SSteve French * Copyright (C) 2016 Namjae Jeon <namjae.jeon@protocolfreedom.org>
438c8a9a5SSteve French * Copyright (C) 2018 Samsung Electronics Co., Ltd.
538c8a9a5SSteve French */
638c8a9a5SSteve French
738c8a9a5SSteve French #include <linux/mutex.h>
838c8a9a5SSteve French #include <linux/freezer.h>
938c8a9a5SSteve French #include <linux/module.h>
1038c8a9a5SSteve French
1138c8a9a5SSteve French #include "server.h"
1238c8a9a5SSteve French #include "smb_common.h"
1338c8a9a5SSteve French #include "mgmt/ksmbd_ida.h"
1438c8a9a5SSteve French #include "connection.h"
1538c8a9a5SSteve French #include "transport_tcp.h"
1638c8a9a5SSteve French #include "transport_rdma.h"
1738c8a9a5SSteve French
1838c8a9a5SSteve French static DEFINE_MUTEX(init_lock);
1938c8a9a5SSteve French
2038c8a9a5SSteve French static struct ksmbd_conn_ops default_conn_ops;
2138c8a9a5SSteve French
2238c8a9a5SSteve French LIST_HEAD(conn_list);
2338c8a9a5SSteve French DECLARE_RWSEM(conn_list_lock);
2438c8a9a5SSteve French
2538c8a9a5SSteve French /**
2638c8a9a5SSteve French * ksmbd_conn_free() - free resources of the connection instance
2738c8a9a5SSteve French *
2838c8a9a5SSteve French * @conn: connection instance to be cleand up
2938c8a9a5SSteve French *
3038c8a9a5SSteve French * During the thread termination, the corresponding conn instance
3138c8a9a5SSteve French * resources(sock/memory) are released and finally the conn object is freed.
3238c8a9a5SSteve French */
ksmbd_conn_free(struct ksmbd_conn * conn)3338c8a9a5SSteve French void ksmbd_conn_free(struct ksmbd_conn *conn)
3438c8a9a5SSteve French {
3538c8a9a5SSteve French down_write(&conn_list_lock);
3638c8a9a5SSteve French list_del(&conn->conns_list);
3738c8a9a5SSteve French up_write(&conn_list_lock);
3838c8a9a5SSteve French
3938c8a9a5SSteve French xa_destroy(&conn->sessions);
4038c8a9a5SSteve French kvfree(conn->request_buf);
4138c8a9a5SSteve French kfree(conn->preauth_info);
4218f06bacSNamjae Jeon if (atomic_dec_and_test(&conn->refcnt))
4338c8a9a5SSteve French kfree(conn);
4438c8a9a5SSteve French }
4538c8a9a5SSteve French
4638c8a9a5SSteve French /**
4738c8a9a5SSteve French * ksmbd_conn_alloc() - initialize a new connection instance
4838c8a9a5SSteve French *
4938c8a9a5SSteve French * Return: ksmbd_conn struct on success, otherwise NULL
5038c8a9a5SSteve French */
ksmbd_conn_alloc(void)5138c8a9a5SSteve French struct ksmbd_conn *ksmbd_conn_alloc(void)
5238c8a9a5SSteve French {
5338c8a9a5SSteve French struct ksmbd_conn *conn;
5438c8a9a5SSteve French
5538c8a9a5SSteve French conn = kzalloc(sizeof(struct ksmbd_conn), GFP_KERNEL);
5638c8a9a5SSteve French if (!conn)
5738c8a9a5SSteve French return NULL;
5838c8a9a5SSteve French
5938c8a9a5SSteve French conn->need_neg = true;
6038c8a9a5SSteve French ksmbd_conn_set_new(conn);
6138c8a9a5SSteve French conn->local_nls = load_nls("utf8");
6238c8a9a5SSteve French if (!conn->local_nls)
6338c8a9a5SSteve French conn->local_nls = load_nls_default();
6438c8a9a5SSteve French if (IS_ENABLED(CONFIG_UNICODE))
6538c8a9a5SSteve French conn->um = utf8_load(UNICODE_AGE(12, 1, 0));
6638c8a9a5SSteve French else
6738c8a9a5SSteve French conn->um = ERR_PTR(-EOPNOTSUPP);
6838c8a9a5SSteve French if (IS_ERR(conn->um))
6938c8a9a5SSteve French conn->um = NULL;
7038c8a9a5SSteve French atomic_set(&conn->req_running, 0);
7138c8a9a5SSteve French atomic_set(&conn->r_count, 0);
7218f06bacSNamjae Jeon atomic_set(&conn->refcnt, 1);
7338c8a9a5SSteve French conn->total_credits = 1;
7438c8a9a5SSteve French conn->outstanding_credits = 0;
7538c8a9a5SSteve French
7638c8a9a5SSteve French init_waitqueue_head(&conn->req_running_q);
7738c8a9a5SSteve French init_waitqueue_head(&conn->r_count_q);
7838c8a9a5SSteve French INIT_LIST_HEAD(&conn->conns_list);
7938c8a9a5SSteve French INIT_LIST_HEAD(&conn->requests);
8038c8a9a5SSteve French INIT_LIST_HEAD(&conn->async_requests);
8138c8a9a5SSteve French spin_lock_init(&conn->request_lock);
8238c8a9a5SSteve French spin_lock_init(&conn->credits_lock);
8338c8a9a5SSteve French ida_init(&conn->async_ida);
8438c8a9a5SSteve French xa_init(&conn->sessions);
8538c8a9a5SSteve French
8638c8a9a5SSteve French spin_lock_init(&conn->llist_lock);
8738c8a9a5SSteve French INIT_LIST_HEAD(&conn->lock_list);
8838c8a9a5SSteve French
8953ff5cf8SNamjae Jeon init_rwsem(&conn->session_lock);
9053ff5cf8SNamjae Jeon
9138c8a9a5SSteve French down_write(&conn_list_lock);
9238c8a9a5SSteve French list_add(&conn->conns_list, &conn_list);
9338c8a9a5SSteve French up_write(&conn_list_lock);
9438c8a9a5SSteve French return conn;
9538c8a9a5SSteve French }
9638c8a9a5SSteve French
ksmbd_conn_lookup_dialect(struct ksmbd_conn * c)9738c8a9a5SSteve French bool ksmbd_conn_lookup_dialect(struct ksmbd_conn *c)
9838c8a9a5SSteve French {
9938c8a9a5SSteve French struct ksmbd_conn *t;
10038c8a9a5SSteve French bool ret = false;
10138c8a9a5SSteve French
10238c8a9a5SSteve French down_read(&conn_list_lock);
10338c8a9a5SSteve French list_for_each_entry(t, &conn_list, conns_list) {
10438c8a9a5SSteve French if (memcmp(t->ClientGUID, c->ClientGUID, SMB2_CLIENT_GUID_SIZE))
10538c8a9a5SSteve French continue;
10638c8a9a5SSteve French
10738c8a9a5SSteve French ret = true;
10838c8a9a5SSteve French break;
10938c8a9a5SSteve French }
11038c8a9a5SSteve French up_read(&conn_list_lock);
11138c8a9a5SSteve French return ret;
11238c8a9a5SSteve French }
11338c8a9a5SSteve French
ksmbd_conn_enqueue_request(struct ksmbd_work * work)11438c8a9a5SSteve French void ksmbd_conn_enqueue_request(struct ksmbd_work *work)
11538c8a9a5SSteve French {
11638c8a9a5SSteve French struct ksmbd_conn *conn = work->conn;
11738c8a9a5SSteve French struct list_head *requests_queue = NULL;
11838c8a9a5SSteve French
11938c8a9a5SSteve French if (conn->ops->get_cmd_val(work) != SMB2_CANCEL_HE)
12038c8a9a5SSteve French requests_queue = &conn->requests;
12138c8a9a5SSteve French
12238c8a9a5SSteve French atomic_inc(&conn->req_running);
1238077d33fSMarios Makassikis if (requests_queue) {
12438c8a9a5SSteve French spin_lock(&conn->request_lock);
12538c8a9a5SSteve French list_add_tail(&work->request_entry, requests_queue);
12638c8a9a5SSteve French spin_unlock(&conn->request_lock);
12738c8a9a5SSteve French }
12838c8a9a5SSteve French }
12938c8a9a5SSteve French
ksmbd_conn_try_dequeue_request(struct ksmbd_work * work)130e2b76ab8SNamjae Jeon void ksmbd_conn_try_dequeue_request(struct ksmbd_work *work)
13138c8a9a5SSteve French {
13238c8a9a5SSteve French struct ksmbd_conn *conn = work->conn;
13338c8a9a5SSteve French
1348077d33fSMarios Makassikis atomic_dec(&conn->req_running);
13555a81dcfSMarios Makassikis if (waitqueue_active(&conn->req_running_q))
13655a81dcfSMarios Makassikis wake_up(&conn->req_running_q);
1378077d33fSMarios Makassikis
13838c8a9a5SSteve French if (list_empty(&work->request_entry) &&
13938c8a9a5SSteve French list_empty(&work->async_request_entry))
140e2b76ab8SNamjae Jeon return;
14138c8a9a5SSteve French
14238c8a9a5SSteve French spin_lock(&conn->request_lock);
14338c8a9a5SSteve French list_del_init(&work->request_entry);
14438c8a9a5SSteve French spin_unlock(&conn->request_lock);
14538c8a9a5SSteve French if (work->asynchronous)
14638c8a9a5SSteve French release_async_work(work);
14738c8a9a5SSteve French
14838c8a9a5SSteve French wake_up_all(&conn->req_running_q);
14938c8a9a5SSteve French }
15038c8a9a5SSteve French
ksmbd_conn_lock(struct ksmbd_conn * conn)15138c8a9a5SSteve French void ksmbd_conn_lock(struct ksmbd_conn *conn)
15238c8a9a5SSteve French {
15338c8a9a5SSteve French mutex_lock(&conn->srv_mutex);
15438c8a9a5SSteve French }
15538c8a9a5SSteve French
ksmbd_conn_unlock(struct ksmbd_conn * conn)15638c8a9a5SSteve French void ksmbd_conn_unlock(struct ksmbd_conn *conn)
15738c8a9a5SSteve French {
15838c8a9a5SSteve French mutex_unlock(&conn->srv_mutex);
15938c8a9a5SSteve French }
16038c8a9a5SSteve French
ksmbd_all_conn_set_status(u64 sess_id,u32 status)16138c8a9a5SSteve French void ksmbd_all_conn_set_status(u64 sess_id, u32 status)
16238c8a9a5SSteve French {
16338c8a9a5SSteve French struct ksmbd_conn *conn;
16438c8a9a5SSteve French
16538c8a9a5SSteve French down_read(&conn_list_lock);
16638c8a9a5SSteve French list_for_each_entry(conn, &conn_list, conns_list) {
16738c8a9a5SSteve French if (conn->binding || xa_load(&conn->sessions, sess_id))
16838c8a9a5SSteve French WRITE_ONCE(conn->status, status);
16938c8a9a5SSteve French }
17038c8a9a5SSteve French up_read(&conn_list_lock);
17138c8a9a5SSteve French }
17238c8a9a5SSteve French
ksmbd_conn_wait_idle(struct ksmbd_conn * conn)173118fd997SNamjae Jeon void ksmbd_conn_wait_idle(struct ksmbd_conn *conn)
17438c8a9a5SSteve French {
17538c8a9a5SSteve French wait_event(conn->req_running_q, atomic_read(&conn->req_running) < 2);
17638c8a9a5SSteve French }
17738c8a9a5SSteve French
ksmbd_conn_wait_idle_sess_id(struct ksmbd_conn * curr_conn,u64 sess_id)178118fd997SNamjae Jeon int ksmbd_conn_wait_idle_sess_id(struct ksmbd_conn *curr_conn, u64 sess_id)
179118fd997SNamjae Jeon {
180118fd997SNamjae Jeon struct ksmbd_conn *conn;
181118fd997SNamjae Jeon int rc, retry_count = 0, max_timeout = 120;
182118fd997SNamjae Jeon int rcount = 1;
183118fd997SNamjae Jeon
184118fd997SNamjae Jeon retry_idle:
185118fd997SNamjae Jeon if (retry_count >= max_timeout)
186118fd997SNamjae Jeon return -EIO;
187118fd997SNamjae Jeon
188118fd997SNamjae Jeon down_read(&conn_list_lock);
189118fd997SNamjae Jeon list_for_each_entry(conn, &conn_list, conns_list) {
190118fd997SNamjae Jeon if (conn->binding || xa_load(&conn->sessions, sess_id)) {
191118fd997SNamjae Jeon if (conn == curr_conn)
192118fd997SNamjae Jeon rcount = 2;
193118fd997SNamjae Jeon if (atomic_read(&conn->req_running) >= rcount) {
194118fd997SNamjae Jeon rc = wait_event_timeout(conn->req_running_q,
195118fd997SNamjae Jeon atomic_read(&conn->req_running) < rcount,
196118fd997SNamjae Jeon HZ);
197118fd997SNamjae Jeon if (!rc) {
198118fd997SNamjae Jeon up_read(&conn_list_lock);
199118fd997SNamjae Jeon retry_count++;
200118fd997SNamjae Jeon goto retry_idle;
201118fd997SNamjae Jeon }
202118fd997SNamjae Jeon }
203118fd997SNamjae Jeon }
204118fd997SNamjae Jeon }
205118fd997SNamjae Jeon up_read(&conn_list_lock);
206118fd997SNamjae Jeon
207118fd997SNamjae Jeon return 0;
208118fd997SNamjae Jeon }
209118fd997SNamjae Jeon
ksmbd_conn_write(struct ksmbd_work * work)21038c8a9a5SSteve French int ksmbd_conn_write(struct ksmbd_work *work)
21138c8a9a5SSteve French {
21238c8a9a5SSteve French struct ksmbd_conn *conn = work->conn;
21338c8a9a5SSteve French int sent;
21438c8a9a5SSteve French
21538c8a9a5SSteve French if (!work->response_buf) {
21638c8a9a5SSteve French pr_err("NULL response header\n");
21738c8a9a5SSteve French return -EINVAL;
21838c8a9a5SSteve French }
21938c8a9a5SSteve French
220e2b76ab8SNamjae Jeon if (work->send_no_response)
221e2b76ab8SNamjae Jeon return 0;
22238c8a9a5SSteve French
22373f949eaSNamjae Jeon if (!work->iov_idx)
22473f949eaSNamjae Jeon return -EINVAL;
22573f949eaSNamjae Jeon
22638c8a9a5SSteve French ksmbd_conn_lock(conn);
227e2b76ab8SNamjae Jeon sent = conn->transport->ops->writev(conn->transport, work->iov,
228e2b76ab8SNamjae Jeon work->iov_cnt,
229e2b76ab8SNamjae Jeon get_rfc1002_len(work->iov[0].iov_base) + 4,
23038c8a9a5SSteve French work->need_invalidate_rkey,
23138c8a9a5SSteve French work->remote_key);
23238c8a9a5SSteve French ksmbd_conn_unlock(conn);
23338c8a9a5SSteve French
23438c8a9a5SSteve French if (sent < 0) {
23538c8a9a5SSteve French pr_err("Failed to send message: %d\n", sent);
23638c8a9a5SSteve French return sent;
23738c8a9a5SSteve French }
23838c8a9a5SSteve French
23938c8a9a5SSteve French return 0;
24038c8a9a5SSteve French }
24138c8a9a5SSteve French
ksmbd_conn_rdma_read(struct ksmbd_conn * conn,void * buf,unsigned int buflen,struct smb2_buffer_desc_v1 * desc,unsigned int desc_len)24238c8a9a5SSteve French int ksmbd_conn_rdma_read(struct ksmbd_conn *conn,
24338c8a9a5SSteve French void *buf, unsigned int buflen,
24438c8a9a5SSteve French struct smb2_buffer_desc_v1 *desc,
24538c8a9a5SSteve French unsigned int desc_len)
24638c8a9a5SSteve French {
24738c8a9a5SSteve French int ret = -EINVAL;
24838c8a9a5SSteve French
24938c8a9a5SSteve French if (conn->transport->ops->rdma_read)
25038c8a9a5SSteve French ret = conn->transport->ops->rdma_read(conn->transport,
25138c8a9a5SSteve French buf, buflen,
25238c8a9a5SSteve French desc, desc_len);
25338c8a9a5SSteve French return ret;
25438c8a9a5SSteve French }
25538c8a9a5SSteve French
ksmbd_conn_rdma_write(struct ksmbd_conn * conn,void * buf,unsigned int buflen,struct smb2_buffer_desc_v1 * desc,unsigned int desc_len)25638c8a9a5SSteve French int ksmbd_conn_rdma_write(struct ksmbd_conn *conn,
25738c8a9a5SSteve French void *buf, unsigned int buflen,
25838c8a9a5SSteve French struct smb2_buffer_desc_v1 *desc,
25938c8a9a5SSteve French unsigned int desc_len)
26038c8a9a5SSteve French {
26138c8a9a5SSteve French int ret = -EINVAL;
26238c8a9a5SSteve French
26338c8a9a5SSteve French if (conn->transport->ops->rdma_write)
26438c8a9a5SSteve French ret = conn->transport->ops->rdma_write(conn->transport,
26538c8a9a5SSteve French buf, buflen,
26638c8a9a5SSteve French desc, desc_len);
26738c8a9a5SSteve French return ret;
26838c8a9a5SSteve French }
26938c8a9a5SSteve French
ksmbd_conn_alive(struct ksmbd_conn * conn)27038c8a9a5SSteve French bool ksmbd_conn_alive(struct ksmbd_conn *conn)
27138c8a9a5SSteve French {
27238c8a9a5SSteve French if (!ksmbd_server_running())
27338c8a9a5SSteve French return false;
27438c8a9a5SSteve French
27538c8a9a5SSteve French if (ksmbd_conn_exiting(conn))
27638c8a9a5SSteve French return false;
27738c8a9a5SSteve French
27838c8a9a5SSteve French if (kthread_should_stop())
27938c8a9a5SSteve French return false;
28038c8a9a5SSteve French
28138c8a9a5SSteve French if (atomic_read(&conn->stats.open_files_count) > 0)
28238c8a9a5SSteve French return true;
28338c8a9a5SSteve French
28438c8a9a5SSteve French /*
28538c8a9a5SSteve French * Stop current session if the time that get last request from client
28638c8a9a5SSteve French * is bigger than deadtime user configured and opening file count is
28738c8a9a5SSteve French * zero.
28838c8a9a5SSteve French */
28938c8a9a5SSteve French if (server_conf.deadtime > 0 &&
29038c8a9a5SSteve French time_after(jiffies, conn->last_active + server_conf.deadtime)) {
29138c8a9a5SSteve French ksmbd_debug(CONN, "No response from client in %lu minutes\n",
29238c8a9a5SSteve French server_conf.deadtime / SMB_ECHO_INTERVAL);
29338c8a9a5SSteve French return false;
29438c8a9a5SSteve French }
29538c8a9a5SSteve French return true;
29638c8a9a5SSteve French }
29738c8a9a5SSteve French
298368ba068SNamjae Jeon #define SMB1_MIN_SUPPORTED_HEADER_SIZE (sizeof(struct smb_hdr))
299368ba068SNamjae Jeon #define SMB2_MIN_SUPPORTED_HEADER_SIZE (sizeof(struct smb2_hdr) + 4)
300368ba068SNamjae Jeon
30138c8a9a5SSteve French /**
30238c8a9a5SSteve French * ksmbd_conn_handler_loop() - session thread to listen on new smb requests
30338c8a9a5SSteve French * @p: connection instance
30438c8a9a5SSteve French *
30538c8a9a5SSteve French * One thread each per connection
30638c8a9a5SSteve French *
30738c8a9a5SSteve French * Return: 0 on success
30838c8a9a5SSteve French */
ksmbd_conn_handler_loop(void * p)30938c8a9a5SSteve French int ksmbd_conn_handler_loop(void *p)
31038c8a9a5SSteve French {
31138c8a9a5SSteve French struct ksmbd_conn *conn = (struct ksmbd_conn *)p;
31238c8a9a5SSteve French struct ksmbd_transport *t = conn->transport;
31355a81dcfSMarios Makassikis unsigned int pdu_size, max_allowed_pdu_size, max_req;
31438c8a9a5SSteve French char hdr_buf[4] = {0,};
31538c8a9a5SSteve French int size;
31638c8a9a5SSteve French
31738c8a9a5SSteve French mutex_init(&conn->srv_mutex);
31838c8a9a5SSteve French __module_get(THIS_MODULE);
31938c8a9a5SSteve French
32038c8a9a5SSteve French if (t->ops->prepare && t->ops->prepare(t))
32138c8a9a5SSteve French goto out;
32238c8a9a5SSteve French
32355a81dcfSMarios Makassikis max_req = server_conf.max_inflight_req;
32438c8a9a5SSteve French conn->last_active = jiffies;
3254c78c771SNamjae Jeon set_freezable();
32638c8a9a5SSteve French while (ksmbd_conn_alive(conn)) {
32738c8a9a5SSteve French if (try_to_freeze())
32838c8a9a5SSteve French continue;
32938c8a9a5SSteve French
33038c8a9a5SSteve French kvfree(conn->request_buf);
33138c8a9a5SSteve French conn->request_buf = NULL;
33238c8a9a5SSteve French
33355a81dcfSMarios Makassikis recheck:
33455a81dcfSMarios Makassikis if (atomic_read(&conn->req_running) + 1 > max_req) {
33555a81dcfSMarios Makassikis wait_event_interruptible(conn->req_running_q,
33655a81dcfSMarios Makassikis atomic_read(&conn->req_running) < max_req);
33755a81dcfSMarios Makassikis goto recheck;
33855a81dcfSMarios Makassikis }
33955a81dcfSMarios Makassikis
34038c8a9a5SSteve French size = t->ops->read(t, hdr_buf, sizeof(hdr_buf), -1);
34138c8a9a5SSteve French if (size != sizeof(hdr_buf))
34238c8a9a5SSteve French break;
34338c8a9a5SSteve French
34438c8a9a5SSteve French pdu_size = get_rfc1002_len(hdr_buf);
34538c8a9a5SSteve French ksmbd_debug(CONN, "RFC1002 header %u bytes\n", pdu_size);
34638c8a9a5SSteve French
34738c8a9a5SSteve French if (ksmbd_conn_good(conn))
34838c8a9a5SSteve French max_allowed_pdu_size =
34938c8a9a5SSteve French SMB3_MAX_MSGSIZE + conn->vals->max_write_size;
35038c8a9a5SSteve French else
35138c8a9a5SSteve French max_allowed_pdu_size = SMB3_MAX_MSGSIZE;
35238c8a9a5SSteve French
35338c8a9a5SSteve French if (pdu_size > max_allowed_pdu_size) {
35438c8a9a5SSteve French pr_err_ratelimited("PDU length(%u) exceeded maximum allowed pdu size(%u) on connection(%d)\n",
35538c8a9a5SSteve French pdu_size, max_allowed_pdu_size,
35638c8a9a5SSteve French READ_ONCE(conn->status));
35738c8a9a5SSteve French break;
35838c8a9a5SSteve French }
35938c8a9a5SSteve French
36038c8a9a5SSteve French /*
36138c8a9a5SSteve French * Check maximum pdu size(0x00FFFFFF).
36238c8a9a5SSteve French */
36338c8a9a5SSteve French if (pdu_size > MAX_STREAM_PROT_LEN)
36438c8a9a5SSteve French break;
36538c8a9a5SSteve French
366368ba068SNamjae Jeon if (pdu_size < SMB1_MIN_SUPPORTED_HEADER_SIZE)
367368ba068SNamjae Jeon break;
368368ba068SNamjae Jeon
36938c8a9a5SSteve French /* 4 for rfc1002 length field */
37038c8a9a5SSteve French /* 1 for implied bcc[0] */
37138c8a9a5SSteve French size = pdu_size + 4 + 1;
37238c8a9a5SSteve French conn->request_buf = kvmalloc(size, GFP_KERNEL);
37338c8a9a5SSteve French if (!conn->request_buf)
37438c8a9a5SSteve French break;
37538c8a9a5SSteve French
37638c8a9a5SSteve French memcpy(conn->request_buf, hdr_buf, sizeof(hdr_buf));
37738c8a9a5SSteve French
37838c8a9a5SSteve French /*
37938c8a9a5SSteve French * We already read 4 bytes to find out PDU size, now
38038c8a9a5SSteve French * read in PDU
38138c8a9a5SSteve French */
38238c8a9a5SSteve French size = t->ops->read(t, conn->request_buf + 4, pdu_size, 2);
38338c8a9a5SSteve French if (size < 0) {
38438c8a9a5SSteve French pr_err("sock_read failed: %d\n", size);
38538c8a9a5SSteve French break;
38638c8a9a5SSteve French }
38738c8a9a5SSteve French
38838c8a9a5SSteve French if (size != pdu_size) {
38938c8a9a5SSteve French pr_err("PDU error. Read: %d, Expected: %d\n",
39038c8a9a5SSteve French size, pdu_size);
39138c8a9a5SSteve French continue;
39238c8a9a5SSteve French }
39338c8a9a5SSteve French
3941c1bcf2dSNamjae Jeon if (!ksmbd_smb_request(conn))
3951c1bcf2dSNamjae Jeon break;
3961c1bcf2dSNamjae Jeon
397368ba068SNamjae Jeon if (((struct smb2_hdr *)smb2_get_msg(conn->request_buf))->ProtocolId ==
398368ba068SNamjae Jeon SMB2_PROTO_NUMBER) {
399368ba068SNamjae Jeon if (pdu_size < SMB2_MIN_SUPPORTED_HEADER_SIZE)
400368ba068SNamjae Jeon break;
401368ba068SNamjae Jeon }
402368ba068SNamjae Jeon
40338c8a9a5SSteve French if (!default_conn_ops.process_fn) {
40438c8a9a5SSteve French pr_err("No connection request callback\n");
40538c8a9a5SSteve French break;
40638c8a9a5SSteve French }
40738c8a9a5SSteve French
40838c8a9a5SSteve French if (default_conn_ops.process_fn(conn)) {
40938c8a9a5SSteve French pr_err("Cannot handle request\n");
41038c8a9a5SSteve French break;
41138c8a9a5SSteve French }
41238c8a9a5SSteve French }
41338c8a9a5SSteve French
41438c8a9a5SSteve French out:
41538c8a9a5SSteve French ksmbd_conn_set_releasing(conn);
41638c8a9a5SSteve French /* Wait till all reference dropped to the Server object*/
41738c8a9a5SSteve French wait_event(conn->r_count_q, atomic_read(&conn->r_count) == 0);
41838c8a9a5SSteve French
41938c8a9a5SSteve French if (IS_ENABLED(CONFIG_UNICODE))
42038c8a9a5SSteve French utf8_unload(conn->um);
42138c8a9a5SSteve French unload_nls(conn->local_nls);
42238c8a9a5SSteve French if (default_conn_ops.terminate_fn)
42338c8a9a5SSteve French default_conn_ops.terminate_fn(conn);
42438c8a9a5SSteve French t->ops->disconnect(t);
42538c8a9a5SSteve French module_put(THIS_MODULE);
42638c8a9a5SSteve French return 0;
42738c8a9a5SSteve French }
42838c8a9a5SSteve French
ksmbd_conn_init_server_callbacks(struct ksmbd_conn_ops * ops)42938c8a9a5SSteve French void ksmbd_conn_init_server_callbacks(struct ksmbd_conn_ops *ops)
43038c8a9a5SSteve French {
43138c8a9a5SSteve French default_conn_ops.process_fn = ops->process_fn;
43238c8a9a5SSteve French default_conn_ops.terminate_fn = ops->terminate_fn;
43338c8a9a5SSteve French }
43438c8a9a5SSteve French
ksmbd_conn_transport_init(void)435*09aeab68SNamjae Jeon void ksmbd_conn_r_count_inc(struct ksmbd_conn *conn)
436*09aeab68SNamjae Jeon {
437*09aeab68SNamjae Jeon atomic_inc(&conn->r_count);
438*09aeab68SNamjae Jeon }
439*09aeab68SNamjae Jeon
440*09aeab68SNamjae Jeon void ksmbd_conn_r_count_dec(struct ksmbd_conn *conn)
441*09aeab68SNamjae Jeon {
442*09aeab68SNamjae Jeon /*
443*09aeab68SNamjae Jeon * Checking waitqueue to dropping pending requests on
444*09aeab68SNamjae Jeon * disconnection. waitqueue_active is safe because it
445*09aeab68SNamjae Jeon * uses atomic operation for condition.
446*09aeab68SNamjae Jeon */
447*09aeab68SNamjae Jeon atomic_inc(&conn->refcnt);
448*09aeab68SNamjae Jeon if (!atomic_dec_return(&conn->r_count) && waitqueue_active(&conn->r_count_q))
449*09aeab68SNamjae Jeon wake_up(&conn->r_count_q);
450*09aeab68SNamjae Jeon
451*09aeab68SNamjae Jeon if (atomic_dec_and_test(&conn->refcnt))
452*09aeab68SNamjae Jeon kfree(conn);
453*09aeab68SNamjae Jeon }
454*09aeab68SNamjae Jeon
45538c8a9a5SSteve French int ksmbd_conn_transport_init(void)
stop_sessions(void)45638c8a9a5SSteve French {
45738c8a9a5SSteve French int ret;
45838c8a9a5SSteve French
45938c8a9a5SSteve French mutex_lock(&init_lock);
46038c8a9a5SSteve French ret = ksmbd_tcp_init();
46138c8a9a5SSteve French if (ret) {
46238c8a9a5SSteve French pr_err("Failed to init TCP subsystem: %d\n", ret);
46338c8a9a5SSteve French goto out;
46438c8a9a5SSteve French }
46538c8a9a5SSteve French
46638c8a9a5SSteve French ret = ksmbd_rdma_init();
46738c8a9a5SSteve French if (ret) {
46838c8a9a5SSteve French pr_err("Failed to init RDMA subsystem: %d\n", ret);
46938c8a9a5SSteve French goto out;
47038c8a9a5SSteve French }
47138c8a9a5SSteve French out:
47238c8a9a5SSteve French mutex_unlock(&init_lock);
47338c8a9a5SSteve French return ret;
47438c8a9a5SSteve French }
47538c8a9a5SSteve French
47638c8a9a5SSteve French static void stop_sessions(void)
47738c8a9a5SSteve French {
47838c8a9a5SSteve French struct ksmbd_conn *conn;
47938c8a9a5SSteve French struct ksmbd_transport *t;
ksmbd_conn_transport_destroy(void)48038c8a9a5SSteve French
48138c8a9a5SSteve French again:
48238c8a9a5SSteve French down_read(&conn_list_lock);
48338c8a9a5SSteve French list_for_each_entry(conn, &conn_list, conns_list) {
48438c8a9a5SSteve French t = conn->transport;
48538c8a9a5SSteve French ksmbd_conn_set_exiting(conn);
48638c8a9a5SSteve French if (t->ops->shutdown) {
48738c8a9a5SSteve French up_read(&conn_list_lock);
48838c8a9a5SSteve French t->ops->shutdown(t);
48938c8a9a5SSteve French down_read(&conn_list_lock);
49038c8a9a5SSteve French }
49138c8a9a5SSteve French }
49238c8a9a5SSteve French up_read(&conn_list_lock);
49338c8a9a5SSteve French
49438c8a9a5SSteve French if (!list_empty(&conn_list)) {
49538c8a9a5SSteve French schedule_timeout_interruptible(HZ / 10); /* 100ms */
49638c8a9a5SSteve French goto again;
49738c8a9a5SSteve French }
49838c8a9a5SSteve French }
49938c8a9a5SSteve French
50038c8a9a5SSteve French void ksmbd_conn_transport_destroy(void)
50138c8a9a5SSteve French {
50238c8a9a5SSteve French mutex_lock(&init_lock);
50338c8a9a5SSteve French ksmbd_tcp_destroy();
50438c8a9a5SSteve French ksmbd_rdma_destroy();
50538c8a9a5SSteve French stop_sessions();
50638c8a9a5SSteve French mutex_unlock(&init_lock);
50738c8a9a5SSteve French }
508