Commit f5a544e3 authored by Namjae Jeon's avatar Namjae Jeon

ksmbd: add support for SMB3 multichannel

Add support for SMB3 multichannel. It will be enable by setting
'server multi channel support = yes' in smb.conf.
Signed-off-by: default avatarNamjae Jeon <namjae.jeon@samsung.com>
Signed-off-by: default avatarSteve French <stfrench@microsoft.com>
parent 5fb68864
...@@ -921,13 +921,14 @@ static int generate_key(struct ksmbd_session *sess, struct kvec label, ...@@ -921,13 +921,14 @@ static int generate_key(struct ksmbd_session *sess, struct kvec label,
} }
static int generate_smb3signingkey(struct ksmbd_session *sess, static int generate_smb3signingkey(struct ksmbd_session *sess,
struct ksmbd_conn *conn,
const struct derivation *signing) const struct derivation *signing)
{ {
int rc; int rc;
struct channel *chann; struct channel *chann;
char *key; char *key;
chann = lookup_chann_list(sess); chann = lookup_chann_list(sess, conn);
if (!chann) if (!chann)
return 0; return 0;
...@@ -953,7 +954,8 @@ static int generate_smb3signingkey(struct ksmbd_session *sess, ...@@ -953,7 +954,8 @@ static int generate_smb3signingkey(struct ksmbd_session *sess,
return 0; return 0;
} }
int ksmbd_gen_smb30_signingkey(struct ksmbd_session *sess) int ksmbd_gen_smb30_signingkey(struct ksmbd_session *sess,
struct ksmbd_conn *conn)
{ {
struct derivation d; struct derivation d;
...@@ -961,22 +963,32 @@ int ksmbd_gen_smb30_signingkey(struct ksmbd_session *sess) ...@@ -961,22 +963,32 @@ int ksmbd_gen_smb30_signingkey(struct ksmbd_session *sess)
d.label.iov_len = 12; d.label.iov_len = 12;
d.context.iov_base = "SmbSign"; d.context.iov_base = "SmbSign";
d.context.iov_len = 8; d.context.iov_len = 8;
d.binding = false; d.binding = conn->binding;
return generate_smb3signingkey(sess, &d); return generate_smb3signingkey(sess, conn, &d);
} }
int ksmbd_gen_smb311_signingkey(struct ksmbd_session *sess) int ksmbd_gen_smb311_signingkey(struct ksmbd_session *sess,
struct ksmbd_conn *conn)
{ {
struct derivation d; struct derivation d;
d.label.iov_base = "SMBSigningKey"; d.label.iov_base = "SMBSigningKey";
d.label.iov_len = 14; d.label.iov_len = 14;
if (conn->binding) {
struct preauth_session *preauth_sess;
preauth_sess = ksmbd_preauth_session_lookup(conn, sess->id);
if (!preauth_sess)
return -ENOENT;
d.context.iov_base = preauth_sess->Preauth_HashValue;
} else {
d.context.iov_base = sess->Preauth_HashValue; d.context.iov_base = sess->Preauth_HashValue;
}
d.context.iov_len = 64; d.context.iov_len = 64;
d.binding = false; d.binding = conn->binding;
return generate_smb3signingkey(sess, &d); return generate_smb3signingkey(sess, conn, &d);
} }
struct derivation_twin { struct derivation_twin {
...@@ -1148,7 +1160,7 @@ static int ksmbd_get_encryption_key(struct ksmbd_conn *conn, __u64 ses_id, ...@@ -1148,7 +1160,7 @@ static int ksmbd_get_encryption_key(struct ksmbd_conn *conn, __u64 ses_id,
struct ksmbd_session *sess; struct ksmbd_session *sess;
u8 *ses_enc_key; u8 *ses_enc_key;
sess = ksmbd_session_lookup(conn, ses_id); sess = ksmbd_session_lookup_all(conn, ses_id);
if (!sess) if (!sess)
return -EINVAL; return -EINVAL;
......
...@@ -54,8 +54,10 @@ int ksmbd_sign_smb2_pdu(struct ksmbd_conn *conn, char *key, struct kvec *iov, ...@@ -54,8 +54,10 @@ int ksmbd_sign_smb2_pdu(struct ksmbd_conn *conn, char *key, struct kvec *iov,
int n_vec, char *sig); int n_vec, char *sig);
int ksmbd_sign_smb3_pdu(struct ksmbd_conn *conn, char *key, struct kvec *iov, int ksmbd_sign_smb3_pdu(struct ksmbd_conn *conn, char *key, struct kvec *iov,
int n_vec, char *sig); int n_vec, char *sig);
int ksmbd_gen_smb30_signingkey(struct ksmbd_session *sess); int ksmbd_gen_smb30_signingkey(struct ksmbd_session *sess,
int ksmbd_gen_smb311_signingkey(struct ksmbd_session *sess); struct ksmbd_conn *conn);
int ksmbd_gen_smb311_signingkey(struct ksmbd_session *sess,
struct ksmbd_conn *conn);
int ksmbd_gen_smb30_encryptionkey(struct ksmbd_session *sess); int ksmbd_gen_smb30_encryptionkey(struct ksmbd_session *sess);
int ksmbd_gen_smb311_encryptionkey(struct ksmbd_session *sess); int ksmbd_gen_smb311_encryptionkey(struct ksmbd_session *sess);
int ksmbd_gen_preauth_integrity_hash(struct ksmbd_conn *conn, char *buf, int ksmbd_gen_preauth_integrity_hash(struct ksmbd_conn *conn, char *buf,
......
...@@ -106,6 +106,7 @@ struct ksmbd_conn { ...@@ -106,6 +106,7 @@ struct ksmbd_conn {
__le16 cipher_type; __le16 cipher_type;
__le16 compress_algorithm; __le16 compress_algorithm;
bool posix_ext_supported; bool posix_ext_supported;
bool binding;
}; };
struct ksmbd_conn_ops { struct ksmbd_conn_ops {
......
...@@ -33,6 +33,7 @@ struct ksmbd_heartbeat { ...@@ -33,6 +33,7 @@ struct ksmbd_heartbeat {
#define KSMBD_GLOBAL_FLAG_CACHE_TBUF BIT(1) #define KSMBD_GLOBAL_FLAG_CACHE_TBUF BIT(1)
#define KSMBD_GLOBAL_FLAG_CACHE_RBUF BIT(2) #define KSMBD_GLOBAL_FLAG_CACHE_RBUF BIT(2)
#define KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION BIT(3) #define KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION BIT(3)
#define KSMBD_GLOBAL_FLAG_SMB3_MULTICHANNEL BIT(4)
struct ksmbd_startup_request { struct ksmbd_startup_request {
__u32 flags; __u32 flags;
......
...@@ -207,7 +207,8 @@ void ksmbd_sessions_deregister(struct ksmbd_conn *conn) ...@@ -207,7 +207,8 @@ void ksmbd_sessions_deregister(struct ksmbd_conn *conn)
} }
} }
bool ksmbd_session_id_match(struct ksmbd_session *sess, unsigned long long id) static bool ksmbd_session_id_match(struct ksmbd_session *sess,
unsigned long long id)
{ {
return sess->id == id; return sess->id == id;
} }
...@@ -250,6 +251,52 @@ struct ksmbd_session *ksmbd_session_lookup_slowpath(unsigned long long id) ...@@ -250,6 +251,52 @@ struct ksmbd_session *ksmbd_session_lookup_slowpath(unsigned long long id)
return sess; return sess;
} }
struct ksmbd_session *ksmbd_session_lookup_all(struct ksmbd_conn *conn,
unsigned long long id)
{
struct ksmbd_session *sess;
sess = ksmbd_session_lookup(conn, id);
if (!sess && conn->binding)
sess = ksmbd_session_lookup_slowpath(id);
return sess;
}
struct preauth_session *ksmbd_preauth_session_alloc(struct ksmbd_conn *conn,
u64 sess_id)
{
struct preauth_session *sess;
sess = kmalloc(sizeof(struct preauth_session), GFP_KERNEL);
if (!sess)
return NULL;
sess->id = sess_id;
memcpy(sess->Preauth_HashValue, conn->preauth_info->Preauth_HashValue,
PREAUTH_HASHVALUE_SIZE);
list_add(&sess->preauth_entry, &conn->preauth_sess_table);
return sess;
}
static bool ksmbd_preauth_session_id_match(struct preauth_session *sess,
unsigned long long id)
{
return sess->id == id;
}
struct preauth_session *ksmbd_preauth_session_lookup(struct ksmbd_conn *conn,
unsigned long long id)
{
struct preauth_session *sess = NULL;
list_for_each_entry(sess, &conn->preauth_sess_table, preauth_entry) {
if (ksmbd_preauth_session_id_match(sess, id))
return sess;
}
return NULL;
}
static int __init_smb2_session(struct ksmbd_session *sess) static int __init_smb2_session(struct ksmbd_session *sess)
{ {
int id = ksmbd_acquire_smb2_uid(&session_ida); int id = ksmbd_acquire_smb2_uid(&session_ida);
......
...@@ -26,8 +26,8 @@ struct channel { ...@@ -26,8 +26,8 @@ struct channel {
struct preauth_session { struct preauth_session {
__u8 Preauth_HashValue[PREAUTH_HASHVALUE_SIZE]; __u8 Preauth_HashValue[PREAUTH_HASHVALUE_SIZE];
u64 sess_id; u64 id;
struct list_head list_entry; struct list_head preauth_entry;
}; };
struct ksmbd_session { struct ksmbd_session {
...@@ -82,13 +82,18 @@ struct ksmbd_session *ksmbd_smb2_session_create(void); ...@@ -82,13 +82,18 @@ struct ksmbd_session *ksmbd_smb2_session_create(void);
void ksmbd_session_destroy(struct ksmbd_session *sess); void ksmbd_session_destroy(struct ksmbd_session *sess);
bool ksmbd_session_id_match(struct ksmbd_session *sess, unsigned long long id);
struct ksmbd_session *ksmbd_session_lookup_slowpath(unsigned long long id); struct ksmbd_session *ksmbd_session_lookup_slowpath(unsigned long long id);
struct ksmbd_session *ksmbd_session_lookup(struct ksmbd_conn *conn, struct ksmbd_session *ksmbd_session_lookup(struct ksmbd_conn *conn,
unsigned long long id); unsigned long long id);
void ksmbd_session_register(struct ksmbd_conn *conn, void ksmbd_session_register(struct ksmbd_conn *conn,
struct ksmbd_session *sess); struct ksmbd_session *sess);
void ksmbd_sessions_deregister(struct ksmbd_conn *conn); void ksmbd_sessions_deregister(struct ksmbd_conn *conn);
struct ksmbd_session *ksmbd_session_lookup_all(struct ksmbd_conn *conn,
unsigned long long id);
struct preauth_session *ksmbd_preauth_session_alloc(struct ksmbd_conn *conn,
u64 sess_id);
struct preauth_session *ksmbd_preauth_session_lookup(struct ksmbd_conn *conn,
unsigned long long id);
int ksmbd_acquire_tree_conn_id(struct ksmbd_session *sess); int ksmbd_acquire_tree_conn_id(struct ksmbd_session *sess);
void ksmbd_release_tree_conn_id(struct ksmbd_session *sess, int id); void ksmbd_release_tree_conn_id(struct ksmbd_session *sess, int id);
......
...@@ -229,6 +229,9 @@ void init_smb3_0_server(struct ksmbd_conn *conn) ...@@ -229,6 +229,9 @@ void init_smb3_0_server(struct ksmbd_conn *conn)
if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION && if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION &&
conn->cli_cap & SMB2_GLOBAL_CAP_ENCRYPTION) conn->cli_cap & SMB2_GLOBAL_CAP_ENCRYPTION)
conn->vals->capabilities |= SMB2_GLOBAL_CAP_ENCRYPTION; conn->vals->capabilities |= SMB2_GLOBAL_CAP_ENCRYPTION;
if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB3_MULTICHANNEL)
conn->vals->capabilities |= SMB2_GLOBAL_CAP_MULTI_CHANNEL;
} }
/** /**
...@@ -250,6 +253,9 @@ void init_smb3_02_server(struct ksmbd_conn *conn) ...@@ -250,6 +253,9 @@ void init_smb3_02_server(struct ksmbd_conn *conn)
if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION && if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION &&
conn->cli_cap & SMB2_GLOBAL_CAP_ENCRYPTION) conn->cli_cap & SMB2_GLOBAL_CAP_ENCRYPTION)
conn->vals->capabilities |= SMB2_GLOBAL_CAP_ENCRYPTION; conn->vals->capabilities |= SMB2_GLOBAL_CAP_ENCRYPTION;
if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB3_MULTICHANNEL)
conn->vals->capabilities |= SMB2_GLOBAL_CAP_MULTI_CHANNEL;
} }
/** /**
...@@ -271,6 +277,9 @@ int init_smb3_11_server(struct ksmbd_conn *conn) ...@@ -271,6 +277,9 @@ int init_smb3_11_server(struct ksmbd_conn *conn)
if (conn->cipher_type) if (conn->cipher_type)
conn->vals->capabilities |= SMB2_GLOBAL_CAP_ENCRYPTION; conn->vals->capabilities |= SMB2_GLOBAL_CAP_ENCRYPTION;
if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB3_MULTICHANNEL)
conn->vals->capabilities |= SMB2_GLOBAL_CAP_MULTI_CHANNEL;
INIT_LIST_HEAD(&conn->preauth_sess_table); INIT_LIST_HEAD(&conn->preauth_sess_table);
return 0; return 0;
} }
......
This diff is collapsed.
...@@ -1647,7 +1647,8 @@ struct file_lock *smb_flock_init(struct file *f); ...@@ -1647,7 +1647,8 @@ struct file_lock *smb_flock_init(struct file *f);
int setup_async_work(struct ksmbd_work *work, void (*fn)(void **), int setup_async_work(struct ksmbd_work *work, void (*fn)(void **),
void **arg); void **arg);
void smb2_send_interim_resp(struct ksmbd_work *work, __le32 status); void smb2_send_interim_resp(struct ksmbd_work *work, __le32 status);
struct channel *lookup_chann_list(struct ksmbd_session *sess); struct channel *lookup_chann_list(struct ksmbd_session *sess,
struct ksmbd_conn *conn);
void smb3_preauth_hash_rsp(struct ksmbd_work *work); void smb3_preauth_hash_rsp(struct ksmbd_work *work);
int smb3_is_transform_hdr(void *buf); int smb3_is_transform_hdr(void *buf);
int smb3_decrypt_req(struct ksmbd_work *work); int smb3_decrypt_req(struct ksmbd_work *work);
......
...@@ -479,7 +479,7 @@ struct smb_version_ops { ...@@ -479,7 +479,7 @@ struct smb_version_ops {
bool (*is_sign_req)(struct ksmbd_work *work, unsigned int command); bool (*is_sign_req)(struct ksmbd_work *work, unsigned int command);
int (*check_sign_req)(struct ksmbd_work *work); int (*check_sign_req)(struct ksmbd_work *work);
void (*set_sign_rsp)(struct ksmbd_work *work); void (*set_sign_rsp)(struct ksmbd_work *work);
int (*generate_signingkey)(struct ksmbd_session *sess); int (*generate_signingkey)(struct ksmbd_session *sess, struct ksmbd_conn *conn);
int (*generate_encryptionkey)(struct ksmbd_session *sess); int (*generate_encryptionkey)(struct ksmbd_session *sess);
int (*is_transform_hdr)(void *buf); int (*is_transform_hdr)(void *buf);
int (*decrypt_req)(struct ksmbd_work *work); int (*decrypt_req)(struct ksmbd_work *work);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment