Commit | Line | Data |
---|---|---|
e2f34481 NJ |
1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* | |
3 | * Copyright (C) 2018 Samsung Electronics Co., Ltd. | |
4 | */ | |
5 | ||
6 | #include <linux/list.h> | |
7 | #include <linux/slab.h> | |
02b68b20 | 8 | #include <linux/xarray.h> |
e2f34481 | 9 | |
e2f34481 NJ |
10 | #include "../transport_ipc.h" |
11 | #include "../connection.h" | |
12 | ||
13 | #include "tree_connect.h" | |
14 | #include "user_config.h" | |
15 | #include "share_config.h" | |
16 | #include "user_session.h" | |
17 | ||
18 | struct ksmbd_tree_conn_status | |
af7c39d9 NJ |
19 | ksmbd_tree_conn_connect(struct ksmbd_conn *conn, struct ksmbd_session *sess, |
20 | char *share_name) | |
e2f34481 NJ |
21 | { |
22 | struct ksmbd_tree_conn_status status = {-EINVAL, NULL}; | |
23 | struct ksmbd_tree_connect_response *resp = NULL; | |
24 | struct ksmbd_share_config *sc; | |
25 | struct ksmbd_tree_connect *tree_conn = NULL; | |
26 | struct sockaddr *peer_addr; | |
02b68b20 | 27 | int ret; |
e2f34481 NJ |
28 | |
29 | sc = ksmbd_share_config_get(share_name); | |
30 | if (!sc) | |
31 | return status; | |
32 | ||
79f6b11a | 33 | tree_conn = kzalloc(sizeof(struct ksmbd_tree_connect), GFP_KERNEL); |
e2f34481 NJ |
34 | if (!tree_conn) { |
35 | status.ret = -ENOMEM; | |
36 | goto out_error; | |
37 | } | |
38 | ||
39 | tree_conn->id = ksmbd_acquire_tree_conn_id(sess); | |
40 | if (tree_conn->id < 0) { | |
41 | status.ret = -EINVAL; | |
42 | goto out_error; | |
43 | } | |
44 | ||
af7c39d9 | 45 | peer_addr = KSMBD_TCP_PEER_SOCKADDR(conn); |
e2f34481 NJ |
46 | resp = ksmbd_ipc_tree_connect_request(sess, |
47 | sc, | |
48 | tree_conn, | |
49 | peer_addr); | |
50 | if (!resp) { | |
51 | status.ret = -EINVAL; | |
52 | goto out_error; | |
53 | } | |
54 | ||
55 | status.ret = resp->status; | |
56 | if (status.ret != KSMBD_TREE_CONN_STATUS_OK) | |
57 | goto out_error; | |
58 | ||
59 | tree_conn->flags = resp->connection_flags; | |
60 | tree_conn->user = sess->user; | |
61 | tree_conn->share_conf = sc; | |
62 | status.tree_conn = tree_conn; | |
63 | ||
02b68b20 | 64 | ret = xa_err(xa_store(&sess->tree_conns, tree_conn->id, tree_conn, |
97d7f3d3 | 65 | GFP_KERNEL)); |
02b68b20 NJ |
66 | if (ret) { |
67 | status.ret = -ENOMEM; | |
68 | goto out_error; | |
69 | } | |
79f6b11a | 70 | kvfree(resp); |
e2f34481 NJ |
71 | return status; |
72 | ||
73 | out_error: | |
74 | if (tree_conn) | |
75 | ksmbd_release_tree_conn_id(sess, tree_conn->id); | |
76 | ksmbd_share_config_put(sc); | |
79f6b11a NJ |
77 | kfree(tree_conn); |
78 | kvfree(resp); | |
e2f34481 NJ |
79 | return status; |
80 | } | |
81 | ||
82 | int ksmbd_tree_conn_disconnect(struct ksmbd_session *sess, | |
83 | struct ksmbd_tree_connect *tree_conn) | |
84 | { | |
85 | int ret; | |
86 | ||
87 | ret = ksmbd_ipc_tree_disconnect_request(sess->id, tree_conn->id); | |
88 | ksmbd_release_tree_conn_id(sess, tree_conn->id); | |
02b68b20 | 89 | xa_erase(&sess->tree_conns, tree_conn->id); |
e2f34481 | 90 | ksmbd_share_config_put(tree_conn->share_conf); |
79f6b11a | 91 | kfree(tree_conn); |
e2f34481 NJ |
92 | return ret; |
93 | } | |
94 | ||
95 | struct ksmbd_tree_connect *ksmbd_tree_conn_lookup(struct ksmbd_session *sess, | |
96 | unsigned int id) | |
97 | { | |
02b68b20 | 98 | return xa_load(&sess->tree_conns, id); |
e2f34481 NJ |
99 | } |
100 | ||
101 | struct ksmbd_share_config *ksmbd_tree_conn_share(struct ksmbd_session *sess, | |
102 | unsigned int id) | |
103 | { | |
104 | struct ksmbd_tree_connect *tc; | |
105 | ||
106 | tc = ksmbd_tree_conn_lookup(sess, id); | |
107 | if (tc) | |
108 | return tc->share_conf; | |
109 | return NULL; | |
110 | } | |
111 | ||
112 | int ksmbd_tree_conn_session_logoff(struct ksmbd_session *sess) | |
113 | { | |
114 | int ret = 0; | |
02b68b20 NJ |
115 | struct ksmbd_tree_connect *tc; |
116 | unsigned long id; | |
e2f34481 | 117 | |
02b68b20 | 118 | xa_for_each(&sess->tree_conns, id, tc) |
e2f34481 | 119 | ret |= ksmbd_tree_conn_disconnect(sess, tc); |
02b68b20 | 120 | xa_destroy(&sess->tree_conns); |
e2f34481 NJ |
121 | return ret; |
122 | } |