mirror of https://github.com/Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
121 lines
2.7 KiB
121 lines
2.7 KiB
// SPDX-License-Identifier: GPL-2.0-or-later |
|
/* |
|
* Copyright (C) 2018 Samsung Electronics Co., Ltd. |
|
*/ |
|
|
|
#include <linux/list.h> |
|
#include <linux/slab.h> |
|
#include <linux/xarray.h> |
|
|
|
#include "../transport_ipc.h" |
|
#include "../connection.h" |
|
|
|
#include "tree_connect.h" |
|
#include "user_config.h" |
|
#include "share_config.h" |
|
#include "user_session.h" |
|
|
|
struct ksmbd_tree_conn_status |
|
ksmbd_tree_conn_connect(struct ksmbd_session *sess, char *share_name) |
|
{ |
|
struct ksmbd_tree_conn_status status = {-EINVAL, NULL}; |
|
struct ksmbd_tree_connect_response *resp = NULL; |
|
struct ksmbd_share_config *sc; |
|
struct ksmbd_tree_connect *tree_conn = NULL; |
|
struct sockaddr *peer_addr; |
|
int ret; |
|
|
|
sc = ksmbd_share_config_get(share_name); |
|
if (!sc) |
|
return status; |
|
|
|
tree_conn = kzalloc(sizeof(struct ksmbd_tree_connect), GFP_KERNEL); |
|
if (!tree_conn) { |
|
status.ret = -ENOMEM; |
|
goto out_error; |
|
} |
|
|
|
tree_conn->id = ksmbd_acquire_tree_conn_id(sess); |
|
if (tree_conn->id < 0) { |
|
status.ret = -EINVAL; |
|
goto out_error; |
|
} |
|
|
|
peer_addr = KSMBD_TCP_PEER_SOCKADDR(sess->conn); |
|
resp = ksmbd_ipc_tree_connect_request(sess, |
|
sc, |
|
tree_conn, |
|
peer_addr); |
|
if (!resp) { |
|
status.ret = -EINVAL; |
|
goto out_error; |
|
} |
|
|
|
status.ret = resp->status; |
|
if (status.ret != KSMBD_TREE_CONN_STATUS_OK) |
|
goto out_error; |
|
|
|
tree_conn->flags = resp->connection_flags; |
|
tree_conn->user = sess->user; |
|
tree_conn->share_conf = sc; |
|
status.tree_conn = tree_conn; |
|
|
|
ret = xa_err(xa_store(&sess->tree_conns, tree_conn->id, tree_conn, |
|
GFP_KERNEL)); |
|
if (ret) { |
|
status.ret = -ENOMEM; |
|
goto out_error; |
|
} |
|
kvfree(resp); |
|
return status; |
|
|
|
out_error: |
|
if (tree_conn) |
|
ksmbd_release_tree_conn_id(sess, tree_conn->id); |
|
ksmbd_share_config_put(sc); |
|
kfree(tree_conn); |
|
kvfree(resp); |
|
return status; |
|
} |
|
|
|
int ksmbd_tree_conn_disconnect(struct ksmbd_session *sess, |
|
struct ksmbd_tree_connect *tree_conn) |
|
{ |
|
int ret; |
|
|
|
ret = ksmbd_ipc_tree_disconnect_request(sess->id, tree_conn->id); |
|
ksmbd_release_tree_conn_id(sess, tree_conn->id); |
|
xa_erase(&sess->tree_conns, tree_conn->id); |
|
ksmbd_share_config_put(tree_conn->share_conf); |
|
kfree(tree_conn); |
|
return ret; |
|
} |
|
|
|
struct ksmbd_tree_connect *ksmbd_tree_conn_lookup(struct ksmbd_session *sess, |
|
unsigned int id) |
|
{ |
|
return xa_load(&sess->tree_conns, id); |
|
} |
|
|
|
struct ksmbd_share_config *ksmbd_tree_conn_share(struct ksmbd_session *sess, |
|
unsigned int id) |
|
{ |
|
struct ksmbd_tree_connect *tc; |
|
|
|
tc = ksmbd_tree_conn_lookup(sess, id); |
|
if (tc) |
|
return tc->share_conf; |
|
return NULL; |
|
} |
|
|
|
int ksmbd_tree_conn_session_logoff(struct ksmbd_session *sess) |
|
{ |
|
int ret = 0; |
|
struct ksmbd_tree_connect *tc; |
|
unsigned long id; |
|
|
|
xa_for_each(&sess->tree_conns, id, tc) |
|
ret |= ksmbd_tree_conn_disconnect(sess, tc); |
|
xa_destroy(&sess->tree_conns); |
|
return ret; |
|
}
|
|
|