tree_connect.c (2787B)
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> 8#include <linux/xarray.h> 9 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 18struct ksmbd_tree_conn_status 19ksmbd_tree_conn_connect(struct ksmbd_session *sess, char *share_name) 20{ 21 struct ksmbd_tree_conn_status status = {-EINVAL, NULL}; 22 struct ksmbd_tree_connect_response *resp = NULL; 23 struct ksmbd_share_config *sc; 24 struct ksmbd_tree_connect *tree_conn = NULL; 25 struct sockaddr *peer_addr; 26 int ret; 27 28 sc = ksmbd_share_config_get(share_name); 29 if (!sc) 30 return status; 31 32 tree_conn = kzalloc(sizeof(struct ksmbd_tree_connect), GFP_KERNEL); 33 if (!tree_conn) { 34 status.ret = -ENOMEM; 35 goto out_error; 36 } 37 38 tree_conn->id = ksmbd_acquire_tree_conn_id(sess); 39 if (tree_conn->id < 0) { 40 status.ret = -EINVAL; 41 goto out_error; 42 } 43 44 peer_addr = KSMBD_TCP_PEER_SOCKADDR(sess->conn); 45 resp = ksmbd_ipc_tree_connect_request(sess, 46 sc, 47 tree_conn, 48 peer_addr); 49 if (!resp) { 50 status.ret = -EINVAL; 51 goto out_error; 52 } 53 54 status.ret = resp->status; 55 if (status.ret != KSMBD_TREE_CONN_STATUS_OK) 56 goto out_error; 57 58 tree_conn->flags = resp->connection_flags; 59 tree_conn->user = sess->user; 60 tree_conn->share_conf = sc; 61 status.tree_conn = tree_conn; 62 63 ret = xa_err(xa_store(&sess->tree_conns, tree_conn->id, tree_conn, 64 GFP_KERNEL)); 65 if (ret) { 66 status.ret = -ENOMEM; 67 goto out_error; 68 } 69 kvfree(resp); 70 return status; 71 72out_error: 73 if (tree_conn) 74 ksmbd_release_tree_conn_id(sess, tree_conn->id); 75 ksmbd_share_config_put(sc); 76 kfree(tree_conn); 77 kvfree(resp); 78 return status; 79} 80 81int ksmbd_tree_conn_disconnect(struct ksmbd_session *sess, 82 struct ksmbd_tree_connect *tree_conn) 83{ 84 int ret; 85 86 ret = ksmbd_ipc_tree_disconnect_request(sess->id, tree_conn->id); 87 ksmbd_release_tree_conn_id(sess, tree_conn->id); 88 xa_erase(&sess->tree_conns, tree_conn->id); 89 ksmbd_share_config_put(tree_conn->share_conf); 90 kfree(tree_conn); 91 return ret; 92} 93 94struct ksmbd_tree_connect *ksmbd_tree_conn_lookup(struct ksmbd_session *sess, 95 unsigned int id) 96{ 97 return xa_load(&sess->tree_conns, id); 98} 99 100struct ksmbd_share_config *ksmbd_tree_conn_share(struct ksmbd_session *sess, 101 unsigned int id) 102{ 103 struct ksmbd_tree_connect *tc; 104 105 tc = ksmbd_tree_conn_lookup(sess, id); 106 if (tc) 107 return tc->share_conf; 108 return NULL; 109} 110 111int ksmbd_tree_conn_session_logoff(struct ksmbd_session *sess) 112{ 113 int ret = 0; 114 struct ksmbd_tree_connect *tc; 115 unsigned long id; 116 117 xa_for_each(&sess->tree_conns, id, tc) 118 ret |= ksmbd_tree_conn_disconnect(sess, tc); 119 xa_destroy(&sess->tree_conns); 120 return ret; 121}