* This is a hack. We will move status to a proper place once we land
* a multi-sessions support.
*/
+static inline bool ksmbd_conn_new(struct ksmbd_conn *conn)
+{
+ return READ_ONCE(conn->status) == KSMBD_SESS_NEW;
+}
+
static inline bool ksmbd_conn_good(struct ksmbd_conn *conn)
{
return READ_ONCE(conn->status) == KSMBD_SESS_GOOD;
* smb2_handle_negotiate() - handler for smb2 negotiate command
* @work: smb work containing smb request buffer
*
+ * The caller holds conn->srv_mutex.
+ *
* Return: 0
*/
int smb2_handle_negotiate(struct ksmbd_work *work)
ksmbd_debug(SMB, "Received negotiate request\n");
conn->need_neg = false;
- if (ksmbd_conn_good(conn)) {
- pr_err("conn->tcp_status is already in CifsGood State\n");
- work->send_no_response = 1;
- return rc;
- }
-
- ksmbd_conn_lock(conn);
smb2_buf_len = get_rfc1002_len(work->request_buf);
smb2_neg_size = offsetof(struct smb2_negotiate_req, Dialects);
if (smb2_neg_size > smb2_buf_len) {
ksmbd_conn_set_need_setup(conn);
err_out:
- ksmbd_conn_unlock(conn);
if (rc)
rsp->hdr.Status = STATUS_INSUFFICIENT_RESOURCES;
struct ksmbd_conn *conn = work->conn;
int ret;
- conn->dialect =
- ksmbd_negotiate_smb_dialect(work->request_buf);
- ksmbd_debug(SMB, "conn->dialect 0x%x\n", conn->dialect);
-
if (command == SMB2_NEGOTIATE_HE) {
+ /*
+ * An SMB2 NEGOTIATE is valid for a new connection, or after an
+ * SMB1 multi-protocol negotiate has selected SMB2. Do not allow
+ * a second SMB2 NEGOTIATE to replace connection-wide state
+ * while a session setup is pending. KSMBD_SESS_NEED_RECONNECT
+ * is a transient session state and does not restart transport
+ * negotiation.
+ */
+ ksmbd_conn_lock(conn);
+ if (!ksmbd_conn_new(conn) &&
+ !ksmbd_conn_need_negotiate(conn)) {
+ work->send_no_response = 1;
+ ksmbd_conn_set_exiting(conn);
+ ksmbd_conn_unlock(conn);
+ return 0;
+ }
+
+ conn->dialect =
+ ksmbd_negotiate_smb_dialect(work->request_buf);
+ ksmbd_debug(SMB, "conn->dialect 0x%x\n", conn->dialect);
ret = smb2_handle_negotiate(work);
+ ksmbd_conn_unlock(conn);
return ret;
}
if (command == SMB_COM_NEGOTIATE) {
+ ksmbd_conn_lock(conn);
+ conn->dialect =
+ ksmbd_negotiate_smb_dialect(work->request_buf);
+ ksmbd_debug(SMB, "conn->dialect 0x%x\n", conn->dialect);
if (__smb2_negotiate(conn)) {
init_smb3_11_server(conn);
- init_smb2_neg_rsp(work);
+ ret = init_smb2_neg_rsp(work);
ksmbd_debug(SMB, "Upgrade to SMB2 negotiation\n");
- return 0;
+ } else {
+ ret = smb_handle_negotiate(work);
}
- return smb_handle_negotiate(work);
+ ksmbd_conn_unlock(conn);
+ return ret;
}
pr_err("Unknown SMB negotiation command: %u\n", command);