Commit 83bfbd0b authored by David Howells's avatar David Howells Committed by Steve French
Browse files

cifs: Remove the RFC1002 header from smb_hdr



Remove the RFC1002 header from struct smb_hdr as used for SMB-1.0.  This
simplifies the SMB-1.0 code by simplifying a lot of places that have to add
or subtract 4 to work around the fact that the RFC1002 header isn't really
part of the message and the base for various offsets within the message is
from the base of the smb_hdr, not the RFC1002 header.

Further, clean up a bunch of places that require an extra kvec struct
specifically pointing to the RFC1002 header, such that kvec[0].iov_base
must be exactly 4 bytes before kvec[1].iov_base.

This allows the header preamble size stuff to be removed too.

The size of the request and response message are then handed around either
directly or by summing the size of all the iov_len members in the kvec
array for which we have a count.

Also, this simplifies and cleans up the common transmission and receive
paths for SMB1 and SMB2/3 as there no longer needs to be special handling
casing for SMB1 messages as the RFC1002 header is now generated on the fly
for SMB1 as it is for SMB2/3.

Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
Reviewed-by: default avatarTom Talpey <tom@talpey.com>
Reviewed-by: default avatarPaulo Alcantara (Red Hat) <pc@manguebit.org>
cc: Shyam Prasad N <sprasad@microsoft.com>
cc: linux-cifs@vger.kernel.org
cc: netfs@lists.linux.dev
cc: linux-fsdevel@vger.kernel.org
Signed-off-by: default avatarSteve French <stfrench@microsoft.com>
parent 9d85ac93
Loading
Loading
Loading
Loading
+5 −5
Original line number Diff line number Diff line
@@ -37,7 +37,7 @@ cifs_dump_mem(char *label, void *data, int length)
		       data, length, true);
}

void cifs_dump_detail(void *buf, struct TCP_Server_Info *server)
void cifs_dump_detail(void *buf, size_t buf_len, struct TCP_Server_Info *server)
{
#ifdef CONFIG_CIFS_DEBUG2
	struct smb_hdr *smb = buf;
@@ -45,7 +45,7 @@ void cifs_dump_detail(void *buf, struct TCP_Server_Info *server)
	cifs_dbg(VFS, "Cmd: %d Err: 0x%x Flags: 0x%x Flgs2: 0x%x Mid: %d Pid: %d Wct: %d\n",
		 smb->Command, smb->Status.CifsError, smb->Flags,
		 smb->Flags2, smb->Mid, smb->Pid, smb->WordCount);
	if (!server->ops->check_message(buf, server->total_read, server)) {
	if (!server->ops->check_message(buf, buf_len, server->total_read, server)) {
		cifs_dbg(VFS, "smb buf %p len %u\n", smb,
			 server->ops->calc_smb_size(smb));
	}
@@ -79,9 +79,9 @@ void cifs_dump_mids(struct TCP_Server_Info *server)
		cifs_dbg(VFS, "IsMult: %d IsEnd: %d\n",
			 mid_entry->multiRsp, mid_entry->multiEnd);
		if (mid_entry->resp_buf) {
			cifs_dump_detail(mid_entry->resp_buf, server);
			cifs_dump_mem("existing buf: ",
				mid_entry->resp_buf, 62);
			cifs_dump_detail(mid_entry->resp_buf,
					 mid_entry->response_pdu_len, server);
			cifs_dump_mem("existing buf: ", mid_entry->resp_buf, 62);
		}
	}
	spin_unlock(&server->mid_queue_lock);
+3 −3
Original line number Diff line number Diff line
@@ -15,10 +15,10 @@
#define pr_fmt(fmt) "CIFS: " fmt

void cifs_dump_mem(char *label, void *data, int length);
void cifs_dump_detail(void *buf, struct TCP_Server_Info *ptcp_info);
void cifs_dump_mids(struct TCP_Server_Info *);
void cifs_dump_detail(void *buf, size_t buf_len, struct TCP_Server_Info *server);
void cifs_dump_mids(struct TCP_Server_Info *server);
extern bool traceSMB;		/* flag which enables the function below */
void dump_smb(void *, int);
void dump_smb(void *buf, int smb_buf_length);
#define CIFS_INFO	0x01
#define CIFS_RC		0x02
#define CIFS_TIMER	0x04
+8 −28
Original line number Diff line number Diff line
@@ -91,18 +91,7 @@ int __cifs_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server,
	struct kvec *iov = rqst->rq_iov;
	int n_vec = rqst->rq_nvec;

	/* iov[0] is actual data and not the rfc1002 length for SMB2+ */
	if (!is_smb1(server)) {
		if (iov[0].iov_len <= 4)
			return -EIO;
		i = 0;
	} else {
		if (n_vec < 2 || iov[0].iov_len != 4)
			return -EIO;
		i = 1; /* skip rfc1002 length */
	}

	for (; i < n_vec; i++) {
	for (i = 0; i < n_vec; i++) {
		if (iov[i].iov_len == 0)
			continue;
		if (iov[i].iov_base == NULL) {
@@ -165,10 +154,6 @@ int cifs_sign_rqst(struct smb_rqst *rqst, struct TCP_Server_Info *server,
	char smb_signature[20];
	struct smb_hdr *cifs_pdu = (struct smb_hdr *)rqst->rq_iov[0].iov_base;

	if (rqst->rq_iov[0].iov_len != 4 ||
	    rqst->rq_iov[0].iov_base + 4 != rqst->rq_iov[1].iov_base)
		return -EIO;

	if ((cifs_pdu == NULL) || (server == NULL))
		return -EINVAL;

@@ -211,17 +196,16 @@ int cifs_sign_smbv(struct kvec *iov, int n_vec, struct TCP_Server_Info *server,
}

/* must be called with server->srv_mutex held */
int cifs_sign_smb(struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server,
int cifs_sign_smb(struct smb_hdr *cifs_pdu, unsigned int pdu_len,
		  struct TCP_Server_Info *server,
		  __u32 *pexpected_response_sequence_number)
{
	struct kvec iov[2];

	iov[0].iov_base = cifs_pdu;
	iov[0].iov_len = 4;
	iov[1].iov_base = (char *)cifs_pdu + 4;
	iov[1].iov_len = be32_to_cpu(cifs_pdu->smb_buf_length);
	struct kvec iov[1] = {
		[0].iov_base = (char *)cifs_pdu,
		[0].iov_len = pdu_len,
	};

	return cifs_sign_smbv(iov, 2, server,
	return cifs_sign_smbv(iov, ARRAY_SIZE(iov), server,
			      pexpected_response_sequence_number);
}

@@ -234,10 +218,6 @@ int cifs_verify_signature(struct smb_rqst *rqst,
	char what_we_think_sig_should_be[20];
	struct smb_hdr *cifs_pdu = (struct smb_hdr *)rqst->rq_iov[0].iov_base;

	if (rqst->rq_iov[0].iov_len != 4 ||
	    rqst->rq_iov[0].iov_base + 4 != rqst->rq_iov[1].iov_base)
		return -EIO;

	if (cifs_pdu == NULL || server == NULL)
		return -EINVAL;

+12 −11
Original line number Diff line number Diff line
@@ -346,13 +346,14 @@ struct smb_version_operations {
	/* map smb to linux error */
	int (*map_error)(char *, bool);
	/* find mid corresponding to the response message */
	struct mid_q_entry * (*find_mid)(struct TCP_Server_Info *, char *);
	void (*dump_detail)(void *buf, struct TCP_Server_Info *ptcp_info);
	struct mid_q_entry *(*find_mid)(struct TCP_Server_Info *server, char *buf);
	void (*dump_detail)(void *buf, size_t buf_len, struct TCP_Server_Info *ptcp_info);
	void (*clear_stats)(struct cifs_tcon *);
	void (*print_stats)(struct seq_file *m, struct cifs_tcon *);
	void (*dump_share_caps)(struct seq_file *, struct cifs_tcon *);
	/* verify the message */
	int (*check_message)(char *, unsigned int, struct TCP_Server_Info *);
	int (*check_message)(char *buf, unsigned int pdu_len, unsigned int len,
			     struct TCP_Server_Info *server);
	bool (*is_oplock_break)(char *, struct TCP_Server_Info *);
	int (*handle_cancelled_mid)(struct mid_q_entry *, struct TCP_Server_Info *);
	void (*downgrade_oplock)(struct TCP_Server_Info *server,
@@ -636,8 +637,7 @@ struct smb_version_operations {

#define HEADER_SIZE(server) (server->vals->header_size)
#define MAX_HEADER_SIZE(server) (server->vals->max_header_size)
#define HEADER_PREAMBLE_SIZE(server) (server->vals->header_preamble_size)
#define MID_HEADER_SIZE(server) (HEADER_SIZE(server) - 1 - HEADER_PREAMBLE_SIZE(server))
#define MID_HEADER_SIZE(server) (HEADER_SIZE(server) - 1)

/**
 * CIFS superblock mount flags (mnt_cifs_flags) to consider when
@@ -832,9 +832,9 @@ struct TCP_Server_Info {
	char dns_dom[CIFS_MAX_DOMAINNAME_LEN + 1];
};

static inline bool is_smb1(struct TCP_Server_Info *server)
static inline bool is_smb1(const struct TCP_Server_Info *server)
{
	return HEADER_PREAMBLE_SIZE(server) != 0;
	return server->vals->protocol_id == SMB10_PROT_ID;
}

static inline void cifs_server_lock(struct TCP_Server_Info *server)
@@ -973,16 +973,16 @@ compare_mid(__u16 mid, const struct smb_hdr *smb)
 * of kvecs to handle the receive, though that should only need to be done
 * once.
 */
#define CIFS_MAX_WSIZE ((1<<24) - 1 - sizeof(WRITE_REQ) + 4)
#define CIFS_MAX_RSIZE ((1<<24) - sizeof(READ_RSP) + 4)
#define CIFS_MAX_WSIZE ((1<<24) - 1 - sizeof(WRITE_REQ))
#define CIFS_MAX_RSIZE ((1<<24) - sizeof(READ_RSP))

/*
 * When the server doesn't allow large posix writes, only allow a rsize/wsize
 * of 2^17-1 minus the size of the call header. That allows for a read or
 * write up to the maximum size described by RFC1002.
 */
#define CIFS_MAX_RFC1002_WSIZE ((1<<17) - 1 - sizeof(WRITE_REQ) + 4)
#define CIFS_MAX_RFC1002_RSIZE ((1<<17) - 1 - sizeof(READ_RSP) + 4)
#define CIFS_MAX_RFC1002_WSIZE ((1<<17) - 1 - sizeof(WRITE_REQ))
#define CIFS_MAX_RFC1002_RSIZE ((1<<17) - 1 - sizeof(READ_RSP))

/*
 * Windows only supports a max of 60kb reads and 65535 byte writes. Default to
@@ -1701,6 +1701,7 @@ struct mid_q_entry {
	struct task_struct *creator;
	void *resp_buf;		/* pointer to received SMB header */
	unsigned int resp_buf_size;
	u32 response_pdu_len;
	int mid_state;	/* wish this were enum but can not pass to wait_event */
	int mid_rc;		/* rc for MID_RC */
	__le16 command;		/* smb command code */
+1 −1
Original line number Diff line number Diff line
@@ -90,7 +90,7 @@

/* future chained NTCreateXReadX bigger, but for time being NTCreateX biggest */
/* among the requests (NTCreateX response is bigger with wct of 34) */
#define MAX_CIFS_HDR_SIZE 0x58 /* 4 len + 32 hdr + (2*24 wct) + 2 bct + 2 pad */
#define MAX_CIFS_HDR_SIZE 0x54 /* 32 hdr + (2*24 wct) + 2 bct + 2 pad */
#define CIFS_SMALL_PATH 120 /* allows for (448-88)/3 */

/* internal cifs vfs structures */
Loading