connection.h 5.4 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
 *   Copyright (C) 2018 Samsung Electronics Co., Ltd.
 */

#ifndef __KSMBD_CONNECTION_H__
#define __KSMBD_CONNECTION_H__

#include <linux/list.h>
#include <linux/ip.h>
#include <net/sock.h>
#include <net/tcp.h>
#include <net/inet_connection_sock.h>
#include <net/request_sock.h>
#include <linux/kthread.h>
#include <linux/nls.h>

#include "smb_common.h"
#include "ksmbd_work.h"

#define KSMBD_SOCKET_BACKLOG		16

/*
 * WARNING
 *
 * This is nothing but a HACK. Session status should move to channel
 * or to session. As of now we have 1 tcp_conn : 1 ksmbd_session, but
 * we need to change it to 1 tcp_conn : N ksmbd_sessions.
 */
enum {
	KSMBD_SESS_NEW = 0,
	KSMBD_SESS_GOOD,
	KSMBD_SESS_EXITING,
	KSMBD_SESS_NEED_RECONNECT,
	KSMBD_SESS_NEED_NEGOTIATE
};

struct ksmbd_stats {
	atomic_t			open_files_count;
	atomic64_t			request_served;
};

struct ksmbd_transport;

struct ksmbd_conn {
	struct smb_version_values	*vals;
	struct smb_version_ops		*ops;
	struct smb_version_cmds		*cmds;
	unsigned int			max_cmds;
	struct mutex			srv_mutex;
	int				status;
	unsigned int			cli_cap;
	char				*request_buf;
	struct ksmbd_transport		*transport;
	struct nls_table		*local_nls;
	struct list_head		conns_list;
	/* smb session 1 per user */
	struct list_head		sessions;
	unsigned long			last_active;
	/* How many request are running currently */
	atomic_t			req_running;
	/* References which are made for this Server object*/
	atomic_t			r_count;
	unsigned short			total_credits;
	unsigned short			max_credits;
	spinlock_t			credits_lock;
	wait_queue_head_t		req_running_q;
	/* Lock to protect requests list*/
	spinlock_t			request_lock;
	struct list_head		requests;
	struct list_head		async_requests;
	int				connection_type;
	struct ksmbd_stats		stats;
	char				ClientGUID[SMB2_CLIENT_GUID_SIZE];
	union {
		/* pending trans request table */
		struct trans_state	*recent_trans;
		/* Used by ntlmssp */
		char			*ntlmssp_cryptkey;
	};

	struct preauth_integrity_info	*preauth_info;

	bool				need_neg;
	unsigned int			auth_mechs;
	unsigned int			preferred_auth_mech;
	bool				sign;
	bool				use_spnego:1;
	__u16				cli_sec_mode;
	__u16				srv_sec_mode;
	/* dialect index that server chose */
	__u16				dialect;

	char				*mechToken;

	struct ksmbd_conn_ops	*conn_ops;

	/* Preauth Session Table */
	struct list_head		preauth_sess_table;

	struct sockaddr_storage		peer_addr;

	/* Identifier for async message */
N
Namjae Jeon 已提交
104
	struct ida			async_ida;
105 106 107 108 109 110 111 112 113 114 115 116 117 118

	__le16				cipher_type;
	__le16				compress_algorithm;
	bool				posix_ext_supported;
};

struct ksmbd_conn_ops {
	int	(*process_fn)(struct ksmbd_conn *conn);
	int	(*terminate_fn)(struct ksmbd_conn *conn);
};

struct ksmbd_transport_ops {
	int (*prepare)(struct ksmbd_transport *t);
	void (*disconnect)(struct ksmbd_transport *t);
119 120
	int (*read)(struct ksmbd_transport *t, char *buf, unsigned int size);
	int (*writev)(struct ksmbd_transport *t, struct kvec *iovs, int niov,
121 122
		      int size, bool need_invalidate_rkey,
		      unsigned int remote_key);
123
	int (*rdma_read)(struct ksmbd_transport *t, void *buf, unsigned int len,
124
			 u32 remote_key, u64 remote_offset, u32 remote_len);
125
	int (*rdma_write)(struct ksmbd_transport *t, void *buf,
126 127
			  unsigned int len, u32 remote_key, u64 remote_offset,
			  u32 remote_len);
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
};

struct ksmbd_transport {
	struct ksmbd_conn		*conn;
	struct ksmbd_transport_ops	*ops;
	struct task_struct		*handler;
};

#define KSMBD_TCP_RECV_TIMEOUT	(7 * HZ)
#define KSMBD_TCP_SEND_TIMEOUT	(5 * HZ)
#define KSMBD_TCP_PEER_SOCKADDR(c)	((struct sockaddr *)&((c)->peer_addr))

bool ksmbd_conn_alive(struct ksmbd_conn *conn);
void ksmbd_conn_wait_idle(struct ksmbd_conn *conn);
struct ksmbd_conn *ksmbd_conn_alloc(void);
void ksmbd_conn_free(struct ksmbd_conn *conn);
bool ksmbd_conn_lookup_dialect(struct ksmbd_conn *c);
int ksmbd_conn_write(struct ksmbd_work *work);
146
int ksmbd_conn_rdma_read(struct ksmbd_conn *conn, void *buf,
147 148
			 unsigned int buflen, u32 remote_key, u64 remote_offset,
			 u32 remote_len);
149
int ksmbd_conn_rdma_write(struct ksmbd_conn *conn, void *buf,
150 151
			  unsigned int buflen, u32 remote_key, u64 remote_offset,
			  u32 remote_len);
152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204
void ksmbd_conn_enqueue_request(struct ksmbd_work *work);
int ksmbd_conn_try_dequeue_request(struct ksmbd_work *work);
void ksmbd_conn_init_server_callbacks(struct ksmbd_conn_ops *ops);
int ksmbd_conn_handler_loop(void *p);
int ksmbd_conn_transport_init(void);
void ksmbd_conn_transport_destroy(void);

/*
 * WARNING
 *
 * This is a hack. We will move status to a proper place once we land
 * a multi-sessions support.
 */
static inline bool ksmbd_conn_good(struct ksmbd_work *work)
{
	return work->conn->status == KSMBD_SESS_GOOD;
}

static inline bool ksmbd_conn_need_negotiate(struct ksmbd_work *work)
{
	return work->conn->status == KSMBD_SESS_NEED_NEGOTIATE;
}

static inline bool ksmbd_conn_need_reconnect(struct ksmbd_work *work)
{
	return work->conn->status == KSMBD_SESS_NEED_RECONNECT;
}

static inline bool ksmbd_conn_exiting(struct ksmbd_work *work)
{
	return work->conn->status == KSMBD_SESS_EXITING;
}

static inline void ksmbd_conn_set_good(struct ksmbd_work *work)
{
	work->conn->status = KSMBD_SESS_GOOD;
}

static inline void ksmbd_conn_set_need_negotiate(struct ksmbd_work *work)
{
	work->conn->status = KSMBD_SESS_NEED_NEGOTIATE;
}

static inline void ksmbd_conn_set_need_reconnect(struct ksmbd_work *work)
{
	work->conn->status = KSMBD_SESS_NEED_RECONNECT;
}

static inline void ksmbd_conn_set_exiting(struct ksmbd_work *work)
{
	work->conn->status = KSMBD_SESS_EXITING;
}
#endif /* __CONNECTION_H__ */