CIFS: Send RFC1001 length in a separate iov

In order to simplify further encryption support we need to separate
RFC1001 length and SMB2 header when sending a request. Put the length
field in iov[0] and the rest of the packet into following iovs.

Signed-off-by: Pavel Shilovsky <pshilov@microsoft.com>
This commit is contained in:
Pavel Shilovsky 2016-11-23 15:14:57 -08:00 committed by Steve French
parent fb2036d817
commit 738f9de5cd
6 changed files with 174 additions and 95 deletions

View File

@ -75,24 +75,20 @@ int __cifs_calc_signature(struct smb_rqst *rqst,
struct kvec *iov = rqst->rq_iov; struct kvec *iov = rqst->rq_iov;
int n_vec = rqst->rq_nvec; int n_vec = rqst->rq_nvec;
for (i = 0; i < n_vec; i++) { if (n_vec < 2 || iov[0].iov_len != 4)
return -EIO;
for (i = 1; i < n_vec; i++) {
if (iov[i].iov_len == 0) if (iov[i].iov_len == 0)
continue; continue;
if (iov[i].iov_base == NULL) { if (iov[i].iov_base == NULL) {
cifs_dbg(VFS, "null iovec entry\n"); cifs_dbg(VFS, "null iovec entry\n");
return -EIO; return -EIO;
} }
/* The first entry includes a length field (which does not get if (i == 1 && iov[1].iov_len <= 4)
signed that occupies the first 4 bytes before the header */ break; /* nothing to sign or corrupt header */
if (i == 0) { rc = crypto_shash_update(shash,
if (iov[0].iov_len <= 8) /* cmd field at offset 9 */ iov[i].iov_base, iov[i].iov_len);
break; /* nothing to sign or corrupt header */
rc = crypto_shash_update(shash,
iov[i].iov_base + 4, iov[i].iov_len - 4);
} else {
rc = crypto_shash_update(shash,
iov[i].iov_base, iov[i].iov_len);
}
if (rc) { if (rc) {
cifs_dbg(VFS, "%s: Could not update with payload\n", cifs_dbg(VFS, "%s: Could not update with payload\n",
__func__); __func__);
@ -168,6 +164,10 @@ int cifs_sign_rqst(struct smb_rqst *rqst, struct TCP_Server_Info *server,
char smb_signature[20]; char smb_signature[20];
struct smb_hdr *cifs_pdu = (struct smb_hdr *)rqst->rq_iov[0].iov_base; 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)) if ((cifs_pdu == NULL) || (server == NULL))
return -EINVAL; return -EINVAL;
@ -209,12 +209,14 @@ int cifs_sign_smbv(struct kvec *iov, int n_vec, struct TCP_Server_Info *server,
int cifs_sign_smb(struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server, int cifs_sign_smb(struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server,
__u32 *pexpected_response_sequence_number) __u32 *pexpected_response_sequence_number)
{ {
struct kvec iov; struct kvec iov[2];
iov.iov_base = cifs_pdu; iov[0].iov_base = cifs_pdu;
iov.iov_len = be32_to_cpu(cifs_pdu->smb_buf_length) + 4; 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);
return cifs_sign_smbv(&iov, 1, server, return cifs_sign_smbv(iov, 2, server,
pexpected_response_sequence_number); pexpected_response_sequence_number);
} }
@ -227,6 +229,10 @@ int cifs_verify_signature(struct smb_rqst *rqst,
char what_we_think_sig_should_be[20]; char what_we_think_sig_should_be[20];
struct smb_hdr *cifs_pdu = (struct smb_hdr *)rqst->rq_iov[0].iov_base; 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) if (cifs_pdu == NULL || server == NULL)
return -EINVAL; return -EINVAL;

View File

@ -1119,7 +1119,7 @@ struct cifs_readdata {
int (*read_into_pages)(struct TCP_Server_Info *server, int (*read_into_pages)(struct TCP_Server_Info *server,
struct cifs_readdata *rdata, struct cifs_readdata *rdata,
unsigned int len); unsigned int len);
struct kvec iov; struct kvec iov[2];
unsigned int pagesz; unsigned int pagesz;
unsigned int tailsz; unsigned int tailsz;
unsigned int credits; unsigned int credits;

View File

@ -708,9 +708,9 @@ CIFSSMBEcho(struct TCP_Server_Info *server)
{ {
ECHO_REQ *smb; ECHO_REQ *smb;
int rc = 0; int rc = 0;
struct kvec iov; struct kvec iov[2];
struct smb_rqst rqst = { .rq_iov = &iov, struct smb_rqst rqst = { .rq_iov = iov,
.rq_nvec = 1 }; .rq_nvec = 2 };
cifs_dbg(FYI, "In echo request\n"); cifs_dbg(FYI, "In echo request\n");
@ -725,8 +725,11 @@ CIFSSMBEcho(struct TCP_Server_Info *server)
put_bcc(1, &smb->hdr); put_bcc(1, &smb->hdr);
smb->Data[0] = 'a'; smb->Data[0] = 'a';
inc_rfc1001_len(smb, 3); inc_rfc1001_len(smb, 3);
iov.iov_base = smb;
iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4; iov[0].iov_len = 4;
iov[0].iov_base = smb;
iov[1].iov_len = get_rfc1002_length(smb);
iov[1].iov_base = (char *)smb + 4;
rc = cifs_call_async(server, &rqst, NULL, cifs_echo_callback, rc = cifs_call_async(server, &rqst, NULL, cifs_echo_callback,
server, CIFS_ASYNC_OP | CIFS_ECHO_OP); server, CIFS_ASYNC_OP | CIFS_ECHO_OP);
@ -1509,10 +1512,12 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
} }
/* set up first iov for signature check */ /* set up first iov for signature check */
rdata->iov.iov_base = buf; rdata->iov[0].iov_base = buf;
rdata->iov.iov_len = server->total_read; rdata->iov[0].iov_len = 4;
cifs_dbg(FYI, "0: iov_base=%p iov_len=%zu\n", rdata->iov[1].iov_base = buf + 4;
rdata->iov.iov_base, rdata->iov.iov_len); rdata->iov[1].iov_len = server->total_read - 4;
cifs_dbg(FYI, "0: iov_base=%p iov_len=%u\n",
rdata->iov[0].iov_base, server->total_read);
/* how much data is in the response? */ /* how much data is in the response? */
data_len = server->ops->read_data_length(buf); data_len = server->ops->read_data_length(buf);
@ -1545,8 +1550,8 @@ cifs_readv_callback(struct mid_q_entry *mid)
struct cifs_readdata *rdata = mid->callback_data; struct cifs_readdata *rdata = mid->callback_data;
struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink); struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
struct TCP_Server_Info *server = tcon->ses->server; struct TCP_Server_Info *server = tcon->ses->server;
struct smb_rqst rqst = { .rq_iov = &rdata->iov, struct smb_rqst rqst = { .rq_iov = rdata->iov,
.rq_nvec = 1, .rq_nvec = 2,
.rq_pages = rdata->pages, .rq_pages = rdata->pages,
.rq_npages = rdata->nr_pages, .rq_npages = rdata->nr_pages,
.rq_pagesz = rdata->pagesz, .rq_pagesz = rdata->pagesz,
@ -1601,8 +1606,8 @@ cifs_async_readv(struct cifs_readdata *rdata)
READ_REQ *smb = NULL; READ_REQ *smb = NULL;
int wct; int wct;
struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink); struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
struct smb_rqst rqst = { .rq_iov = &rdata->iov, struct smb_rqst rqst = { .rq_iov = rdata->iov,
.rq_nvec = 1 }; .rq_nvec = 2 };
cifs_dbg(FYI, "%s: offset=%llu bytes=%u\n", cifs_dbg(FYI, "%s: offset=%llu bytes=%u\n",
__func__, rdata->offset, rdata->bytes); __func__, rdata->offset, rdata->bytes);
@ -1642,8 +1647,10 @@ cifs_async_readv(struct cifs_readdata *rdata)
} }
/* 4 for RFC1001 length + 1 for BCC */ /* 4 for RFC1001 length + 1 for BCC */
rdata->iov.iov_base = smb; rdata->iov[0].iov_base = smb;
rdata->iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4; rdata->iov[0].iov_len = 4;
rdata->iov[1].iov_base = (char *)smb + 4;
rdata->iov[1].iov_len = get_rfc1002_length(smb);
kref_get(&rdata->refcount); kref_get(&rdata->refcount);
rc = cifs_call_async(tcon->ses->server, &rqst, cifs_readv_receive, rc = cifs_call_async(tcon->ses->server, &rqst, cifs_readv_receive,
@ -2096,7 +2103,7 @@ cifs_async_writev(struct cifs_writedata *wdata,
WRITE_REQ *smb = NULL; WRITE_REQ *smb = NULL;
int wct; int wct;
struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink); struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
struct kvec iov; struct kvec iov[2];
struct smb_rqst rqst = { }; struct smb_rqst rqst = { };
if (tcon->ses->capabilities & CAP_LARGE_FILES) { if (tcon->ses->capabilities & CAP_LARGE_FILES) {
@ -2129,11 +2136,13 @@ cifs_async_writev(struct cifs_writedata *wdata,
cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4); cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
/* 4 for RFC1001 length + 1 for BCC */ /* 4 for RFC1001 length + 1 for BCC */
iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4 + 1; iov[0].iov_len = 4;
iov.iov_base = smb; iov[0].iov_base = smb;
iov[1].iov_len = get_rfc1002_length(smb) + 1;
iov[1].iov_base = (char *)smb + 4;
rqst.rq_iov = &iov; rqst.rq_iov = iov;
rqst.rq_nvec = 1; rqst.rq_nvec = 2;
rqst.rq_pages = wdata->pages; rqst.rq_pages = wdata->pages;
rqst.rq_npages = wdata->nr_pages; rqst.rq_npages = wdata->nr_pages;
rqst.rq_pagesz = wdata->pagesz; rqst.rq_pagesz = wdata->pagesz;
@ -2154,7 +2163,7 @@ cifs_async_writev(struct cifs_writedata *wdata,
(struct smb_com_writex_req *)smb; (struct smb_com_writex_req *)smb;
inc_rfc1001_len(&smbw->hdr, wdata->bytes + 5); inc_rfc1001_len(&smbw->hdr, wdata->bytes + 5);
put_bcc(wdata->bytes + 5, &smbw->hdr); put_bcc(wdata->bytes + 5, &smbw->hdr);
iov.iov_len += 4; /* pad bigger by four bytes */ iov[1].iov_len += 4; /* pad bigger by four bytes */
} }
kref_get(&wdata->refcount); kref_get(&wdata->refcount);

View File

@ -2047,9 +2047,9 @@ SMB2_echo(struct TCP_Server_Info *server)
{ {
struct smb2_echo_req *req; struct smb2_echo_req *req;
int rc = 0; int rc = 0;
struct kvec iov; struct kvec iov[2];
struct smb_rqst rqst = { .rq_iov = &iov, struct smb_rqst rqst = { .rq_iov = iov,
.rq_nvec = 1 }; .rq_nvec = 2 };
cifs_dbg(FYI, "In echo request\n"); cifs_dbg(FYI, "In echo request\n");
@ -2065,9 +2065,11 @@ SMB2_echo(struct TCP_Server_Info *server)
req->hdr.sync_hdr.CreditRequest = cpu_to_le16(1); req->hdr.sync_hdr.CreditRequest = cpu_to_le16(1);
iov.iov_base = (char *)req;
/* 4 for rfc1002 length field */ /* 4 for rfc1002 length field */
iov.iov_len = get_rfc1002_length(req) + 4; iov[0].iov_len = 4;
iov[0].iov_base = (char *)req;
iov[1].iov_len = get_rfc1002_length(req);
iov[1].iov_base = (char *)req + 4;
rc = cifs_call_async(server, &rqst, NULL, smb2_echo_callback, server, rc = cifs_call_async(server, &rqst, NULL, smb2_echo_callback, server,
CIFS_ECHO_OP); CIFS_ECHO_OP);
@ -2123,8 +2125,9 @@ SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
* have the end_of_chain boolean set to true. * have the end_of_chain boolean set to true.
*/ */
static int static int
smb2_new_read_req(struct kvec *iov, struct cifs_io_parms *io_parms, smb2_new_read_req(void **buf, unsigned int *total_len,
unsigned int remaining_bytes, int request_type) struct cifs_io_parms *io_parms, unsigned int remaining_bytes,
int request_type)
{ {
int rc = -EACCES; int rc = -EACCES;
struct smb2_read_req *req = NULL; struct smb2_read_req *req = NULL;
@ -2172,9 +2175,9 @@ smb2_new_read_req(struct kvec *iov, struct cifs_io_parms *io_parms,
else else
req->RemainingBytes = 0; req->RemainingBytes = 0;
iov[0].iov_base = (char *)req; *buf = req;
/* 4 for rfc1002 length field */ /* 4 for rfc1002 length field */
iov[0].iov_len = get_rfc1002_length(req) + 4; *total_len = get_rfc1002_length(req) + 4;
return rc; return rc;
} }
@ -2184,10 +2187,11 @@ smb2_readv_callback(struct mid_q_entry *mid)
struct cifs_readdata *rdata = mid->callback_data; struct cifs_readdata *rdata = mid->callback_data;
struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink); struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
struct TCP_Server_Info *server = tcon->ses->server; struct TCP_Server_Info *server = tcon->ses->server;
struct smb2_sync_hdr *shdr = get_sync_hdr(rdata->iov.iov_base); struct smb2_sync_hdr *shdr =
(struct smb2_sync_hdr *)rdata->iov[1].iov_base;
unsigned int credits_received = 1; unsigned int credits_received = 1;
struct smb_rqst rqst = { .rq_iov = &rdata->iov, struct smb_rqst rqst = { .rq_iov = rdata->iov,
.rq_nvec = 1, .rq_nvec = 2,
.rq_pages = rdata->pages, .rq_pages = rdata->pages,
.rq_npages = rdata->nr_pages, .rq_npages = rdata->nr_pages,
.rq_pagesz = rdata->pagesz, .rq_pagesz = rdata->pagesz,
@ -2238,7 +2242,7 @@ smb2_readv_callback(struct mid_q_entry *mid)
add_credits(server, credits_received, 0); add_credits(server, credits_received, 0);
} }
/* smb2_async_readv - send an async write, and set up mid to handle result */ /* smb2_async_readv - send an async read, and set up mid to handle result */
int int
smb2_async_readv(struct cifs_readdata *rdata) smb2_async_readv(struct cifs_readdata *rdata)
{ {
@ -2246,9 +2250,10 @@ smb2_async_readv(struct cifs_readdata *rdata)
char *buf; char *buf;
struct smb2_sync_hdr *shdr; struct smb2_sync_hdr *shdr;
struct cifs_io_parms io_parms; struct cifs_io_parms io_parms;
struct smb_rqst rqst = { .rq_iov = &rdata->iov, struct smb_rqst rqst = { .rq_iov = rdata->iov,
.rq_nvec = 1 }; .rq_nvec = 2 };
struct TCP_Server_Info *server; struct TCP_Server_Info *server;
unsigned int total_len;
cifs_dbg(FYI, "%s: offset=%llu bytes=%u\n", cifs_dbg(FYI, "%s: offset=%llu bytes=%u\n",
__func__, rdata->offset, rdata->bytes); __func__, rdata->offset, rdata->bytes);
@ -2262,7 +2267,7 @@ smb2_async_readv(struct cifs_readdata *rdata)
server = io_parms.tcon->ses->server; server = io_parms.tcon->ses->server;
rc = smb2_new_read_req(&rdata->iov, &io_parms, 0, 0); rc = smb2_new_read_req((void **) &buf, &total_len, &io_parms, 0, 0);
if (rc) { if (rc) {
if (rc == -EAGAIN && rdata->credits) { if (rc == -EAGAIN && rdata->credits) {
/* credits was reset by reconnect */ /* credits was reset by reconnect */
@ -2275,10 +2280,12 @@ smb2_async_readv(struct cifs_readdata *rdata)
return rc; return rc;
} }
buf = rdata->iov.iov_base;
shdr = get_sync_hdr(buf); shdr = get_sync_hdr(buf);
/* 4 for rfc1002 length field */ /* 4 for rfc1002 length field */
rdata->iov.iov_len = get_rfc1002_length(rdata->iov.iov_base) + 4; rdata->iov[0].iov_len = 4;
rdata->iov[0].iov_base = buf;
rdata->iov[1].iov_len = total_len - 4;
rdata->iov[1].iov_base = buf + 4;
if (rdata->credits) { if (rdata->credits) {
shdr->CreditCharge = cpu_to_le16(DIV_ROUND_UP(rdata->bytes, shdr->CreditCharge = cpu_to_le16(DIV_ROUND_UP(rdata->bytes,
@ -2314,12 +2321,17 @@ SMB2_read(const unsigned int xid, struct cifs_io_parms *io_parms,
struct smb2_sync_hdr *shdr; struct smb2_sync_hdr *shdr;
struct kvec iov[1]; struct kvec iov[1];
struct kvec rsp_iov; struct kvec rsp_iov;
unsigned int total_len;
char *req;
*nbytes = 0; *nbytes = 0;
rc = smb2_new_read_req(iov, io_parms, 0, 0); rc = smb2_new_read_req((void **)&req, &total_len, io_parms, 0, 0);
if (rc) if (rc)
return rc; return rc;
iov[0].iov_base = buf;
iov[0].iov_len = total_len;
rc = SendReceive2(xid, io_parms->tcon->ses, iov, 1, rc = SendReceive2(xid, io_parms->tcon->ses, iov, 1,
&resp_buftype, CIFS_LOG_ERROR, &rsp_iov); &resp_buftype, CIFS_LOG_ERROR, &rsp_iov);
cifs_small_buf_release(iov[0].iov_base); cifs_small_buf_release(iov[0].iov_base);
@ -2424,8 +2436,8 @@ smb2_async_writev(struct cifs_writedata *wdata,
struct smb2_sync_hdr *shdr; struct smb2_sync_hdr *shdr;
struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink); struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
struct TCP_Server_Info *server = tcon->ses->server; struct TCP_Server_Info *server = tcon->ses->server;
struct kvec iov; struct kvec iov[2];
struct smb_rqst rqst; struct smb_rqst rqst = { };
rc = small_smb2_init(SMB2_WRITE, tcon, (void **) &req); rc = small_smb2_init(SMB2_WRITE, tcon, (void **) &req);
if (rc) { if (rc) {
@ -2455,11 +2467,13 @@ smb2_async_writev(struct cifs_writedata *wdata,
req->RemainingBytes = 0; req->RemainingBytes = 0;
/* 4 for rfc1002 length field and 1 for Buffer */ /* 4 for rfc1002 length field and 1 for Buffer */
iov.iov_len = get_rfc1002_length(req) + 4 - 1; iov[0].iov_len = 4;
iov.iov_base = req; iov[0].iov_base = req;
iov[1].iov_len = get_rfc1002_length(req) - 1;
iov[1].iov_base = (char *)req + 4;
rqst.rq_iov = &iov; rqst.rq_iov = iov;
rqst.rq_nvec = 1; rqst.rq_nvec = 2;
rqst.rq_pages = wdata->pages; rqst.rq_pages = wdata->pages;
rqst.rq_npages = wdata->nr_pages; rqst.rq_npages = wdata->nr_pages;
rqst.rq_pagesz = wdata->pagesz; rqst.rq_pagesz = wdata->pagesz;

View File

@ -138,7 +138,7 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
unsigned char smb2_signature[SMB2_HMACSHA256_SIZE]; unsigned char smb2_signature[SMB2_HMACSHA256_SIZE];
unsigned char *sigptr = smb2_signature; unsigned char *sigptr = smb2_signature;
struct kvec *iov = rqst->rq_iov; struct kvec *iov = rqst->rq_iov;
struct smb2_sync_hdr *shdr = get_sync_hdr(iov[0].iov_base); struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)iov[1].iov_base;
struct cifs_ses *ses; struct cifs_ses *ses;
ses = smb2_find_smb_ses(shdr, server); ses = smb2_find_smb_ses(shdr, server);
@ -355,7 +355,7 @@ smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
unsigned char smb3_signature[SMB2_CMACAES_SIZE]; unsigned char smb3_signature[SMB2_CMACAES_SIZE];
unsigned char *sigptr = smb3_signature; unsigned char *sigptr = smb3_signature;
struct kvec *iov = rqst->rq_iov; struct kvec *iov = rqst->rq_iov;
struct smb2_sync_hdr *shdr = get_sync_hdr(iov[0].iov_base); struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)iov[1].iov_base;
struct cifs_ses *ses; struct cifs_ses *ses;
ses = smb2_find_smb_ses(shdr, server); ses = smb2_find_smb_ses(shdr, server);
@ -400,7 +400,8 @@ static int
smb2_sign_rqst(struct smb_rqst *rqst, struct TCP_Server_Info *server) smb2_sign_rqst(struct smb_rqst *rqst, struct TCP_Server_Info *server)
{ {
int rc = 0; int rc = 0;
struct smb2_sync_hdr *shdr = get_sync_hdr(rqst->rq_iov[0].iov_base); struct smb2_sync_hdr *shdr =
(struct smb2_sync_hdr *)rqst->rq_iov[1].iov_base;
if (!(shdr->Flags & SMB2_FLAGS_SIGNED) || if (!(shdr->Flags & SMB2_FLAGS_SIGNED) ||
server->tcpStatus == CifsNeedNegotiate) server->tcpStatus == CifsNeedNegotiate)
@ -421,7 +422,8 @@ smb2_verify_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
{ {
unsigned int rc; unsigned int rc;
char server_response_sig[16]; char server_response_sig[16];
struct smb2_sync_hdr *shdr = get_sync_hdr(rqst->rq_iov[0].iov_base); struct smb2_sync_hdr *shdr =
(struct smb2_sync_hdr *)rqst->rq_iov[1].iov_base;
if ((shdr->Command == SMB2_NEGOTIATE) || if ((shdr->Command == SMB2_NEGOTIATE) ||
(shdr->Command == SMB2_SESSION_SETUP) || (shdr->Command == SMB2_SESSION_SETUP) ||
@ -550,12 +552,14 @@ smb2_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server,
bool log_error) bool log_error)
{ {
unsigned int len = get_rfc1002_length(mid->resp_buf); unsigned int len = get_rfc1002_length(mid->resp_buf);
struct kvec iov; struct kvec iov[2];
struct smb_rqst rqst = { .rq_iov = &iov, struct smb_rqst rqst = { .rq_iov = iov,
.rq_nvec = 1 }; .rq_nvec = 2 };
iov.iov_base = (char *)mid->resp_buf; iov[0].iov_base = (char *)mid->resp_buf;
iov.iov_len = get_rfc1002_length(mid->resp_buf) + 4; iov[0].iov_len = 4;
iov[1].iov_base = (char *)mid->resp_buf + 4;
iov[1].iov_len = len;
dump_smb(mid->resp_buf, min_t(u32, 80, len)); dump_smb(mid->resp_buf, min_t(u32, 80, len));
/* convert the length into a more usable form */ /* convert the length into a more usable form */
@ -575,7 +579,8 @@ struct mid_q_entry *
smb2_setup_request(struct cifs_ses *ses, struct smb_rqst *rqst) smb2_setup_request(struct cifs_ses *ses, struct smb_rqst *rqst)
{ {
int rc; int rc;
struct smb2_sync_hdr *shdr = get_sync_hdr(rqst->rq_iov[0].iov_base); struct smb2_sync_hdr *shdr =
(struct smb2_sync_hdr *)rqst->rq_iov[1].iov_base;
struct mid_q_entry *mid; struct mid_q_entry *mid;
smb2_seq_num_into_buf(ses->server, shdr); smb2_seq_num_into_buf(ses->server, shdr);
@ -595,7 +600,8 @@ struct mid_q_entry *
smb2_setup_async_request(struct TCP_Server_Info *server, struct smb_rqst *rqst) smb2_setup_async_request(struct TCP_Server_Info *server, struct smb_rqst *rqst)
{ {
int rc; int rc;
struct smb2_sync_hdr *shdr = get_sync_hdr(rqst->rq_iov[0].iov_base); struct smb2_sync_hdr *shdr =
(struct smb2_sync_hdr *)rqst->rq_iov[1].iov_base;
struct mid_q_entry *mid; struct mid_q_entry *mid;
smb2_seq_num_into_buf(server, shdr); smb2_seq_num_into_buf(server, shdr);

View File

@ -245,8 +245,12 @@ smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst)
return -EIO; return -EIO;
} }
if (n_vec < 2)
return -EIO;
cifs_dbg(FYI, "Sending smb: smb_len=%u\n", smb_buf_length); cifs_dbg(FYI, "Sending smb: smb_len=%u\n", smb_buf_length);
dump_smb(iov[0].iov_base, iov[0].iov_len); dump_smb(iov[0].iov_base, iov[0].iov_len);
dump_smb(iov[1].iov_base, iov[1].iov_len);
/* cork the socket */ /* cork the socket */
kernel_setsockopt(ssocket, SOL_TCP, TCP_CORK, kernel_setsockopt(ssocket, SOL_TCP, TCP_CORK,
@ -321,12 +325,14 @@ int
smb_send(struct TCP_Server_Info *server, struct smb_hdr *smb_buffer, smb_send(struct TCP_Server_Info *server, struct smb_hdr *smb_buffer,
unsigned int smb_buf_length) unsigned int smb_buf_length)
{ {
struct kvec iov; struct kvec iov[2];
iov.iov_base = smb_buffer; iov[0].iov_base = smb_buffer;
iov.iov_len = smb_buf_length + 4; iov[0].iov_len = 4;
iov[1].iov_base = (char *)smb_buffer + 4;
iov[1].iov_len = smb_buf_length;
return smb_sendv(server, &iov, 1); return smb_sendv(server, iov, 2);
} }
static int static int
@ -454,6 +460,10 @@ cifs_setup_async_request(struct TCP_Server_Info *server, struct smb_rqst *rqst)
struct smb_hdr *hdr = (struct smb_hdr *)rqst->rq_iov[0].iov_base; struct smb_hdr *hdr = (struct smb_hdr *)rqst->rq_iov[0].iov_base;
struct mid_q_entry *mid; struct mid_q_entry *mid;
if (rqst->rq_iov[0].iov_len != 4 ||
rqst->rq_iov[0].iov_base + 4 != rqst->rq_iov[1].iov_base)
return ERR_PTR(-EIO);
/* enable signing if server requires it */ /* enable signing if server requires it */
if (server->sign) if (server->sign)
hdr->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; hdr->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
@ -477,8 +487,8 @@ cifs_setup_async_request(struct TCP_Server_Info *server, struct smb_rqst *rqst)
*/ */
int int
cifs_call_async(struct TCP_Server_Info *server, struct smb_rqst *rqst, cifs_call_async(struct TCP_Server_Info *server, struct smb_rqst *rqst,
mid_receive_t *receive, mid_callback_t *callback, mid_receive_t *receive, mid_callback_t *callback, void *cbdata,
void *cbdata, const int flags) const int flags)
{ {
int rc, timeout, optype; int rc, timeout, optype;
struct mid_q_entry *mid; struct mid_q_entry *mid;
@ -613,13 +623,15 @@ cifs_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server,
/* convert the length into a more usable form */ /* convert the length into a more usable form */
if (server->sign) { if (server->sign) {
struct kvec iov; struct kvec iov[2];
int rc = 0; int rc = 0;
struct smb_rqst rqst = { .rq_iov = &iov, struct smb_rqst rqst = { .rq_iov = iov,
.rq_nvec = 1 }; .rq_nvec = 2 };
iov.iov_base = mid->resp_buf; iov[0].iov_base = mid->resp_buf;
iov.iov_len = len; iov[0].iov_len = 4;
iov[1].iov_base = (char *)mid->resp_buf + 4;
iov[1].iov_len = len - 4;
/* FIXME: add code to kill session */ /* FIXME: add code to kill session */
rc = cifs_verify_signature(&rqst, server, rc = cifs_verify_signature(&rqst, server,
mid->sequence_number); mid->sequence_number);
@ -639,6 +651,10 @@ cifs_setup_request(struct cifs_ses *ses, struct smb_rqst *rqst)
struct smb_hdr *hdr = (struct smb_hdr *)rqst->rq_iov[0].iov_base; struct smb_hdr *hdr = (struct smb_hdr *)rqst->rq_iov[0].iov_base;
struct mid_q_entry *mid; struct mid_q_entry *mid;
if (rqst->rq_iov[0].iov_len != 4 ||
rqst->rq_iov[0].iov_base + 4 != rqst->rq_iov[1].iov_base)
return ERR_PTR(-EIO);
rc = allocate_mid(ses, hdr, &mid); rc = allocate_mid(ses, hdr, &mid);
if (rc) if (rc)
return ERR_PTR(rc); return ERR_PTR(rc);
@ -650,18 +666,16 @@ cifs_setup_request(struct cifs_ses *ses, struct smb_rqst *rqst)
return mid; return mid;
} }
int static int
SendReceive2(const unsigned int xid, struct cifs_ses *ses, cifs_send_recv(const unsigned int xid, struct cifs_ses *ses,
struct kvec *iov, int n_vec, int *resp_buf_type /* ret */, struct smb_rqst *rqst, int *resp_buf_type, const int flags,
const int flags, struct kvec *resp_iov) struct kvec *resp_iov)
{ {
int rc = 0; int rc = 0;
int timeout, optype; int timeout, optype;
struct mid_q_entry *midQ; struct mid_q_entry *midQ;
char *buf = iov[0].iov_base;
unsigned int credits = 1; unsigned int credits = 1;
struct smb_rqst rqst = { .rq_iov = iov, char *buf;
.rq_nvec = n_vec };
timeout = flags & CIFS_TIMEOUT_MASK; timeout = flags & CIFS_TIMEOUT_MASK;
optype = flags & CIFS_OP_MASK; optype = flags & CIFS_OP_MASK;
@ -694,7 +708,7 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
mutex_lock(&ses->server->srv_mutex); mutex_lock(&ses->server->srv_mutex);
midQ = ses->server->ops->setup_request(ses, &rqst); midQ = ses->server->ops->setup_request(ses, rqst);
if (IS_ERR(midQ)) { if (IS_ERR(midQ)) {
mutex_unlock(&ses->server->srv_mutex); mutex_unlock(&ses->server->srv_mutex);
/* Update # of requests on wire to server */ /* Update # of requests on wire to server */
@ -704,7 +718,7 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
midQ->mid_state = MID_REQUEST_SUBMITTED; midQ->mid_state = MID_REQUEST_SUBMITTED;
cifs_in_send_inc(ses->server); cifs_in_send_inc(ses->server);
rc = smb_sendv(ses->server, iov, n_vec); rc = smb_send_rqst(ses->server, rqst);
cifs_in_send_dec(ses->server); cifs_in_send_dec(ses->server);
cifs_save_when_sent(midQ); cifs_save_when_sent(midQ);
@ -720,7 +734,7 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
rc = wait_for_response(ses->server, midQ); rc = wait_for_response(ses->server, midQ);
if (rc != 0) { if (rc != 0) {
send_cancel(ses->server, &rqst, midQ); send_cancel(ses->server, rqst, midQ);
spin_lock(&GlobalMid_Lock); spin_lock(&GlobalMid_Lock);
if (midQ->mid_state == MID_REQUEST_SUBMITTED) { if (midQ->mid_state == MID_REQUEST_SUBMITTED) {
midQ->callback = DeleteMidQEntry; midQ->callback = DeleteMidQEntry;
@ -766,6 +780,36 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
return rc; return rc;
} }
int
SendReceive2(const unsigned int xid, struct cifs_ses *ses,
struct kvec *iov, int n_vec, int *resp_buf_type /* ret */,
const int flags, struct kvec *resp_iov)
{
struct smb_rqst rqst;
struct kvec *new_iov;
int rc;
new_iov = kmalloc(sizeof(struct kvec) * (n_vec + 1), GFP_KERNEL);
if (!new_iov)
return -ENOMEM;
/* 1st iov is a RFC1001 length followed by the rest of the packet */
memcpy(new_iov + 1, iov, (sizeof(struct kvec) * n_vec));
new_iov[0].iov_base = new_iov[1].iov_base;
new_iov[0].iov_len = 4;
new_iov[1].iov_base += 4;
new_iov[1].iov_len -= 4;
memset(&rqst, 0, sizeof(struct smb_rqst));
rqst.rq_iov = new_iov;
rqst.rq_nvec = n_vec + 1;
rc = cifs_send_recv(xid, ses, &rqst, resp_buf_type, flags, resp_iov);
kfree(new_iov);
return rc;
}
int int
SendReceive(const unsigned int xid, struct cifs_ses *ses, SendReceive(const unsigned int xid, struct cifs_ses *ses,
struct smb_hdr *in_buf, struct smb_hdr *out_buf, struct smb_hdr *in_buf, struct smb_hdr *out_buf,