1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Copyright (C) 2016 Namjae Jeon <namjae.jeon@protocolfreedom.org> |
4 | * Copyright (C) 2018 Samsung Electronics Co., Ltd. |
5 | */ |
6 | |
7 | #include <linux/mutex.h> |
8 | #include <linux/freezer.h> |
9 | #include <linux/module.h> |
10 | |
11 | #include "server.h" |
12 | #include "smb_common.h" |
13 | #include "mgmt/ksmbd_ida.h" |
14 | #include "connection.h" |
15 | #include "transport_tcp.h" |
16 | #include "transport_rdma.h" |
17 | |
18 | static DEFINE_MUTEX(init_lock); |
19 | |
20 | static struct ksmbd_conn_ops default_conn_ops; |
21 | |
22 | LIST_HEAD(conn_list); |
23 | DECLARE_RWSEM(conn_list_lock); |
24 | |
25 | /** |
26 | * ksmbd_conn_free() - free resources of the connection instance |
27 | * |
28 | * @conn: connection instance to be cleand up |
29 | * |
30 | * During the thread termination, the corresponding conn instance |
31 | * resources(sock/memory) are released and finally the conn object is freed. |
32 | */ |
33 | void ksmbd_conn_free(struct ksmbd_conn *conn) |
34 | { |
35 | down_write(sem: &conn_list_lock); |
36 | list_del(entry: &conn->conns_list); |
37 | up_write(sem: &conn_list_lock); |
38 | |
39 | xa_destroy(&conn->sessions); |
40 | kvfree(addr: conn->request_buf); |
41 | kfree(objp: conn->preauth_info); |
42 | kfree(objp: conn); |
43 | } |
44 | |
45 | /** |
46 | * ksmbd_conn_alloc() - initialize a new connection instance |
47 | * |
48 | * Return: ksmbd_conn struct on success, otherwise NULL |
49 | */ |
50 | struct ksmbd_conn *ksmbd_conn_alloc(void) |
51 | { |
52 | struct ksmbd_conn *conn; |
53 | |
54 | conn = kzalloc(size: sizeof(struct ksmbd_conn), GFP_KERNEL); |
55 | if (!conn) |
56 | return NULL; |
57 | |
58 | conn->need_neg = true; |
59 | ksmbd_conn_set_new(conn); |
60 | conn->local_nls = load_nls(charset: "utf8" ); |
61 | if (!conn->local_nls) |
62 | conn->local_nls = load_nls_default(); |
63 | if (IS_ENABLED(CONFIG_UNICODE)) |
64 | conn->um = utf8_load(UNICODE_AGE(12, 1, 0)); |
65 | else |
66 | conn->um = ERR_PTR(error: -EOPNOTSUPP); |
67 | if (IS_ERR(ptr: conn->um)) |
68 | conn->um = NULL; |
69 | atomic_set(v: &conn->req_running, i: 0); |
70 | atomic_set(v: &conn->r_count, i: 0); |
71 | conn->total_credits = 1; |
72 | conn->outstanding_credits = 0; |
73 | |
74 | init_waitqueue_head(&conn->req_running_q); |
75 | init_waitqueue_head(&conn->r_count_q); |
76 | INIT_LIST_HEAD(list: &conn->conns_list); |
77 | INIT_LIST_HEAD(list: &conn->requests); |
78 | INIT_LIST_HEAD(list: &conn->async_requests); |
79 | spin_lock_init(&conn->request_lock); |
80 | spin_lock_init(&conn->credits_lock); |
81 | ida_init(ida: &conn->async_ida); |
82 | xa_init(xa: &conn->sessions); |
83 | |
84 | spin_lock_init(&conn->llist_lock); |
85 | INIT_LIST_HEAD(list: &conn->lock_list); |
86 | |
87 | init_rwsem(&conn->session_lock); |
88 | |
89 | down_write(sem: &conn_list_lock); |
90 | list_add(new: &conn->conns_list, head: &conn_list); |
91 | up_write(sem: &conn_list_lock); |
92 | return conn; |
93 | } |
94 | |
95 | bool ksmbd_conn_lookup_dialect(struct ksmbd_conn *c) |
96 | { |
97 | struct ksmbd_conn *t; |
98 | bool ret = false; |
99 | |
100 | down_read(sem: &conn_list_lock); |
101 | list_for_each_entry(t, &conn_list, conns_list) { |
102 | if (memcmp(p: t->ClientGUID, q: c->ClientGUID, SMB2_CLIENT_GUID_SIZE)) |
103 | continue; |
104 | |
105 | ret = true; |
106 | break; |
107 | } |
108 | up_read(sem: &conn_list_lock); |
109 | return ret; |
110 | } |
111 | |
112 | void ksmbd_conn_enqueue_request(struct ksmbd_work *work) |
113 | { |
114 | struct ksmbd_conn *conn = work->conn; |
115 | struct list_head *requests_queue = NULL; |
116 | |
117 | if (conn->ops->get_cmd_val(work) != SMB2_CANCEL_HE) |
118 | requests_queue = &conn->requests; |
119 | |
120 | if (requests_queue) { |
121 | atomic_inc(v: &conn->req_running); |
122 | spin_lock(lock: &conn->request_lock); |
123 | list_add_tail(new: &work->request_entry, head: requests_queue); |
124 | spin_unlock(lock: &conn->request_lock); |
125 | } |
126 | } |
127 | |
128 | void ksmbd_conn_try_dequeue_request(struct ksmbd_work *work) |
129 | { |
130 | struct ksmbd_conn *conn = work->conn; |
131 | |
132 | if (list_empty(head: &work->request_entry) && |
133 | list_empty(head: &work->async_request_entry)) |
134 | return; |
135 | |
136 | atomic_dec(v: &conn->req_running); |
137 | spin_lock(lock: &conn->request_lock); |
138 | list_del_init(entry: &work->request_entry); |
139 | spin_unlock(lock: &conn->request_lock); |
140 | if (work->asynchronous) |
141 | release_async_work(work); |
142 | |
143 | wake_up_all(&conn->req_running_q); |
144 | } |
145 | |
146 | void ksmbd_conn_lock(struct ksmbd_conn *conn) |
147 | { |
148 | mutex_lock(&conn->srv_mutex); |
149 | } |
150 | |
151 | void ksmbd_conn_unlock(struct ksmbd_conn *conn) |
152 | { |
153 | mutex_unlock(lock: &conn->srv_mutex); |
154 | } |
155 | |
156 | void ksmbd_all_conn_set_status(u64 sess_id, u32 status) |
157 | { |
158 | struct ksmbd_conn *conn; |
159 | |
160 | down_read(sem: &conn_list_lock); |
161 | list_for_each_entry(conn, &conn_list, conns_list) { |
162 | if (conn->binding || xa_load(&conn->sessions, index: sess_id)) |
163 | WRITE_ONCE(conn->status, status); |
164 | } |
165 | up_read(sem: &conn_list_lock); |
166 | } |
167 | |
168 | void ksmbd_conn_wait_idle(struct ksmbd_conn *conn, u64 sess_id) |
169 | { |
170 | wait_event(conn->req_running_q, atomic_read(&conn->req_running) < 2); |
171 | } |
172 | |
173 | int ksmbd_conn_write(struct ksmbd_work *work) |
174 | { |
175 | struct ksmbd_conn *conn = work->conn; |
176 | int sent; |
177 | |
178 | if (!work->response_buf) { |
179 | pr_err("NULL response header\n" ); |
180 | return -EINVAL; |
181 | } |
182 | |
183 | if (work->send_no_response) |
184 | return 0; |
185 | |
186 | if (!work->iov_idx) |
187 | return -EINVAL; |
188 | |
189 | ksmbd_conn_lock(conn); |
190 | sent = conn->transport->ops->writev(conn->transport, work->iov, |
191 | work->iov_cnt, |
192 | get_rfc1002_len(buf: work->iov[0].iov_base) + 4, |
193 | work->need_invalidate_rkey, |
194 | work->remote_key); |
195 | ksmbd_conn_unlock(conn); |
196 | |
197 | if (sent < 0) { |
198 | pr_err("Failed to send message: %d\n" , sent); |
199 | return sent; |
200 | } |
201 | |
202 | return 0; |
203 | } |
204 | |
205 | int ksmbd_conn_rdma_read(struct ksmbd_conn *conn, |
206 | void *buf, unsigned int buflen, |
207 | struct smb2_buffer_desc_v1 *desc, |
208 | unsigned int desc_len) |
209 | { |
210 | int ret = -EINVAL; |
211 | |
212 | if (conn->transport->ops->rdma_read) |
213 | ret = conn->transport->ops->rdma_read(conn->transport, |
214 | buf, buflen, |
215 | desc, desc_len); |
216 | return ret; |
217 | } |
218 | |
219 | int ksmbd_conn_rdma_write(struct ksmbd_conn *conn, |
220 | void *buf, unsigned int buflen, |
221 | struct smb2_buffer_desc_v1 *desc, |
222 | unsigned int desc_len) |
223 | { |
224 | int ret = -EINVAL; |
225 | |
226 | if (conn->transport->ops->rdma_write) |
227 | ret = conn->transport->ops->rdma_write(conn->transport, |
228 | buf, buflen, |
229 | desc, desc_len); |
230 | return ret; |
231 | } |
232 | |
233 | bool ksmbd_conn_alive(struct ksmbd_conn *conn) |
234 | { |
235 | if (!ksmbd_server_running()) |
236 | return false; |
237 | |
238 | if (ksmbd_conn_exiting(conn)) |
239 | return false; |
240 | |
241 | if (kthread_should_stop()) |
242 | return false; |
243 | |
244 | if (atomic_read(v: &conn->stats.open_files_count) > 0) |
245 | return true; |
246 | |
247 | /* |
248 | * Stop current session if the time that get last request from client |
249 | * is bigger than deadtime user configured and opening file count is |
250 | * zero. |
251 | */ |
252 | if (server_conf.deadtime > 0 && |
253 | time_after(jiffies, conn->last_active + server_conf.deadtime)) { |
254 | ksmbd_debug(CONN, "No response from client in %lu minutes\n" , |
255 | server_conf.deadtime / SMB_ECHO_INTERVAL); |
256 | return false; |
257 | } |
258 | return true; |
259 | } |
260 | |
261 | #define (sizeof(struct smb_hdr)) |
262 | #define (sizeof(struct smb2_hdr) + 4) |
263 | |
264 | /** |
265 | * ksmbd_conn_handler_loop() - session thread to listen on new smb requests |
266 | * @p: connection instance |
267 | * |
268 | * One thread each per connection |
269 | * |
270 | * Return: 0 on success |
271 | */ |
272 | int ksmbd_conn_handler_loop(void *p) |
273 | { |
274 | struct ksmbd_conn *conn = (struct ksmbd_conn *)p; |
275 | struct ksmbd_transport *t = conn->transport; |
276 | unsigned int pdu_size, max_allowed_pdu_size; |
277 | char hdr_buf[4] = {0,}; |
278 | int size; |
279 | |
280 | mutex_init(&conn->srv_mutex); |
281 | __module_get(THIS_MODULE); |
282 | |
283 | if (t->ops->prepare && t->ops->prepare(t)) |
284 | goto out; |
285 | |
286 | conn->last_active = jiffies; |
287 | set_freezable(); |
288 | while (ksmbd_conn_alive(conn)) { |
289 | if (try_to_freeze()) |
290 | continue; |
291 | |
292 | kvfree(addr: conn->request_buf); |
293 | conn->request_buf = NULL; |
294 | |
295 | size = t->ops->read(t, hdr_buf, sizeof(hdr_buf), -1); |
296 | if (size != sizeof(hdr_buf)) |
297 | break; |
298 | |
299 | pdu_size = get_rfc1002_len(buf: hdr_buf); |
300 | ksmbd_debug(CONN, "RFC1002 header %u bytes\n" , pdu_size); |
301 | |
302 | if (ksmbd_conn_good(conn)) |
303 | max_allowed_pdu_size = |
304 | SMB3_MAX_MSGSIZE + conn->vals->max_write_size; |
305 | else |
306 | max_allowed_pdu_size = SMB3_MAX_MSGSIZE; |
307 | |
308 | if (pdu_size > max_allowed_pdu_size) { |
309 | pr_err_ratelimited("PDU length(%u) exceeded maximum allowed pdu size(%u) on connection(%d)\n" , |
310 | pdu_size, max_allowed_pdu_size, |
311 | READ_ONCE(conn->status)); |
312 | break; |
313 | } |
314 | |
315 | /* |
316 | * Check maximum pdu size(0x00FFFFFF). |
317 | */ |
318 | if (pdu_size > MAX_STREAM_PROT_LEN) |
319 | break; |
320 | |
321 | if (pdu_size < SMB1_MIN_SUPPORTED_HEADER_SIZE) |
322 | break; |
323 | |
324 | /* 4 for rfc1002 length field */ |
325 | /* 1 for implied bcc[0] */ |
326 | size = pdu_size + 4 + 1; |
327 | conn->request_buf = kvmalloc(size, GFP_KERNEL); |
328 | if (!conn->request_buf) |
329 | break; |
330 | |
331 | memcpy(conn->request_buf, hdr_buf, sizeof(hdr_buf)); |
332 | |
333 | /* |
334 | * We already read 4 bytes to find out PDU size, now |
335 | * read in PDU |
336 | */ |
337 | size = t->ops->read(t, conn->request_buf + 4, pdu_size, 2); |
338 | if (size < 0) { |
339 | pr_err("sock_read failed: %d\n" , size); |
340 | break; |
341 | } |
342 | |
343 | if (size != pdu_size) { |
344 | pr_err("PDU error. Read: %d, Expected: %d\n" , |
345 | size, pdu_size); |
346 | continue; |
347 | } |
348 | |
349 | if (!ksmbd_smb_request(conn)) |
350 | break; |
351 | |
352 | if (((struct smb2_hdr *)smb2_get_msg(buf: conn->request_buf))->ProtocolId == |
353 | SMB2_PROTO_NUMBER) { |
354 | if (pdu_size < SMB2_MIN_SUPPORTED_HEADER_SIZE) |
355 | break; |
356 | } |
357 | |
358 | if (!default_conn_ops.process_fn) { |
359 | pr_err("No connection request callback\n" ); |
360 | break; |
361 | } |
362 | |
363 | if (default_conn_ops.process_fn(conn)) { |
364 | pr_err("Cannot handle request\n" ); |
365 | break; |
366 | } |
367 | } |
368 | |
369 | out: |
370 | ksmbd_conn_set_releasing(conn); |
371 | /* Wait till all reference dropped to the Server object*/ |
372 | wait_event(conn->r_count_q, atomic_read(&conn->r_count) == 0); |
373 | |
374 | if (IS_ENABLED(CONFIG_UNICODE)) |
375 | utf8_unload(um: conn->um); |
376 | unload_nls(conn->local_nls); |
377 | if (default_conn_ops.terminate_fn) |
378 | default_conn_ops.terminate_fn(conn); |
379 | t->ops->disconnect(t); |
380 | module_put(THIS_MODULE); |
381 | return 0; |
382 | } |
383 | |
384 | void ksmbd_conn_init_server_callbacks(struct ksmbd_conn_ops *ops) |
385 | { |
386 | default_conn_ops.process_fn = ops->process_fn; |
387 | default_conn_ops.terminate_fn = ops->terminate_fn; |
388 | } |
389 | |
390 | int ksmbd_conn_transport_init(void) |
391 | { |
392 | int ret; |
393 | |
394 | mutex_lock(&init_lock); |
395 | ret = ksmbd_tcp_init(); |
396 | if (ret) { |
397 | pr_err("Failed to init TCP subsystem: %d\n" , ret); |
398 | goto out; |
399 | } |
400 | |
401 | ret = ksmbd_rdma_init(); |
402 | if (ret) { |
403 | pr_err("Failed to init RDMA subsystem: %d\n" , ret); |
404 | goto out; |
405 | } |
406 | out: |
407 | mutex_unlock(lock: &init_lock); |
408 | return ret; |
409 | } |
410 | |
411 | static void stop_sessions(void) |
412 | { |
413 | struct ksmbd_conn *conn; |
414 | struct ksmbd_transport *t; |
415 | |
416 | again: |
417 | down_read(sem: &conn_list_lock); |
418 | list_for_each_entry(conn, &conn_list, conns_list) { |
419 | t = conn->transport; |
420 | ksmbd_conn_set_exiting(conn); |
421 | if (t->ops->shutdown) { |
422 | up_read(sem: &conn_list_lock); |
423 | t->ops->shutdown(t); |
424 | down_read(sem: &conn_list_lock); |
425 | } |
426 | } |
427 | up_read(sem: &conn_list_lock); |
428 | |
429 | if (!list_empty(head: &conn_list)) { |
430 | schedule_timeout_interruptible(HZ / 10); /* 100ms */ |
431 | goto again; |
432 | } |
433 | } |
434 | |
435 | void ksmbd_conn_transport_destroy(void) |
436 | { |
437 | mutex_lock(&init_lock); |
438 | ksmbd_tcp_destroy(); |
439 | ksmbd_rdma_destroy(); |
440 | stop_sessions(); |
441 | mutex_unlock(lock: &init_lock); |
442 | } |
443 | |