summaryrefslogtreecommitdiff
path: root/fs/smb/client/cifstransport.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/smb/client/cifstransport.c')
-rw-r--r--fs/smb/client/cifstransport.c208
1 files changed, 87 insertions, 121 deletions
diff --git a/fs/smb/client/cifstransport.c b/fs/smb/client/cifstransport.c
index 4c4f5befb6d3..d12578b37179 100644
--- a/fs/smb/client/cifstransport.c
+++ b/fs/smb/client/cifstransport.c
@@ -74,14 +74,14 @@ int
smb_send(struct TCP_Server_Info *server, struct smb_hdr *smb_buffer,
unsigned int smb_buf_length)
{
- struct kvec iov[2];
- struct smb_rqst rqst = { .rq_iov = iov,
- .rq_nvec = 2 };
-
- iov[0].iov_base = smb_buffer;
- iov[0].iov_len = 4;
- iov[1].iov_base = (char *)smb_buffer + 4;
- iov[1].iov_len = smb_buf_length;
+ struct kvec iov[1] = {
+ [0].iov_base = smb_buffer,
+ [0].iov_len = smb_buf_length,
+ };
+ struct smb_rqst rqst = {
+ .rq_iov = iov,
+ .rq_nvec = ARRAY_SIZE(iov),
+ };
return __smb_send_rqst(server, 1, &rqst);
}
@@ -125,10 +125,6 @@ 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 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 */
if (server->sign)
hdr->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
@@ -157,7 +153,7 @@ cifs_setup_async_request(struct TCP_Server_Info *server, struct smb_rqst *rqst)
*/
int
SendReceiveNoRsp(const unsigned int xid, struct cifs_ses *ses,
- char *in_buf, int flags)
+ char *in_buf, unsigned int in_len, int flags)
{
int rc;
struct kvec iov[1];
@@ -165,7 +161,7 @@ SendReceiveNoRsp(const unsigned int xid, struct cifs_ses *ses,
int resp_buf_type;
iov[0].iov_base = in_buf;
- iov[0].iov_len = get_rfc1002_len(in_buf) + 4;
+ iov[0].iov_len = in_len;
flags |= CIFS_NO_RSP_BUF;
rc = SendReceive2(xid, ses, iov, 1, &resp_buf_type, flags, &rsp_iov);
cifs_dbg(NOISY, "SendRcvNoRsp flags %d rc %d\n", flags, rc);
@@ -177,21 +173,19 @@ int
cifs_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server,
bool log_error)
{
- unsigned int len = get_rfc1002_len(mid->resp_buf) + 4;
+ unsigned int len = mid->response_pdu_len;
dump_smb(mid->resp_buf, min_t(u32, 92, len));
/* convert the length into a more usable form */
if (server->sign) {
- struct kvec iov[2];
+ struct kvec iov[1];
int rc = 0;
struct smb_rqst rqst = { .rq_iov = iov,
- .rq_nvec = 2 };
+ .rq_nvec = ARRAY_SIZE(iov) };
iov[0].iov_base = mid->resp_buf;
- iov[0].iov_len = 4;
- iov[1].iov_base = (char *)mid->resp_buf + 4;
- iov[1].iov_len = len - 4;
+ iov[0].iov_len = len;
/* FIXME: add code to kill session */
rc = cifs_verify_signature(&rqst, server,
mid->sequence_number);
@@ -212,10 +206,6 @@ cifs_setup_request(struct cifs_ses *ses, struct TCP_Server_Info *ignored,
struct smb_hdr *hdr = (struct smb_hdr *)rqst->rq_iov[0].iov_base;
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);
if (rc)
return ERR_PTR(rc);
@@ -232,53 +222,29 @@ 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 s_iov[CIFS_MAX_IOV_SIZE], *new_iov;
- int rc;
-
- if (n_vec + 1 > CIFS_MAX_IOV_SIZE) {
- new_iov = kmalloc_array(n_vec + 1, sizeof(struct kvec),
- GFP_KERNEL);
- if (!new_iov) {
- /* otherwise cifs_send_recv below sets resp_buf_type */
- *resp_buf_type = CIFS_NO_BUFFER;
- return -ENOMEM;
- }
- } else
- new_iov = s_iov;
-
- /* 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;
+ struct smb_rqst rqst = {
+ .rq_iov = iov,
+ .rq_nvec = n_vec,
+ };
- rc = cifs_send_recv(xid, ses, ses->server,
- &rqst, resp_buf_type, flags, resp_iov);
- if (n_vec + 1 > CIFS_MAX_IOV_SIZE)
- kfree(new_iov);
- return rc;
+ return cifs_send_recv(xid, ses, ses->server,
+ &rqst, resp_buf_type, flags, resp_iov);
}
int
SendReceive(const unsigned int xid, struct cifs_ses *ses,
- struct smb_hdr *in_buf, struct smb_hdr *out_buf,
- int *pbytes_returned, const int flags)
+ struct smb_hdr *in_buf, unsigned int in_len,
+ struct smb_hdr *out_buf, int *pbytes_returned, const int flags)
{
int rc = 0;
- struct mid_q_entry *midQ;
- unsigned int len = be32_to_cpu(in_buf->smb_buf_length);
- struct kvec iov = { .iov_base = in_buf, .iov_len = len };
+ struct mid_q_entry *mid;
+ struct kvec iov = { .iov_base = in_buf, .iov_len = in_len };
struct smb_rqst rqst = { .rq_iov = &iov, .rq_nvec = 1 };
struct cifs_credits credits = { .value = 1, .instance = 0 };
struct TCP_Server_Info *server;
+ if (WARN_ON_ONCE(in_len > 0xffffff))
+ return -EIO;
if (ses == NULL) {
cifs_dbg(VFS, "Null smb session\n");
return -EIO;
@@ -300,9 +266,9 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
to the same server. We may make this configurable later or
use ses->maxReq */
- if (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
+ if (in_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
cifs_server_dbg(VFS, "Invalid length, greater than maximum frame, %d\n",
- len);
+ in_len);
return -EIO;
}
@@ -316,7 +282,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
cifs_server_lock(server);
- rc = allocate_mid(ses, in_buf, &midQ);
+ rc = allocate_mid(ses, in_buf, &mid);
if (rc) {
cifs_server_unlock(server);
/* Update # of requests on wire to server */
@@ -324,16 +290,16 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
return rc;
}
- rc = cifs_sign_smb(in_buf, server, &midQ->sequence_number);
+ rc = cifs_sign_smb(in_buf, in_len, server, &mid->sequence_number);
if (rc) {
cifs_server_unlock(server);
goto out;
}
- midQ->mid_state = MID_REQUEST_SUBMITTED;
+ mid->mid_state = MID_REQUEST_SUBMITTED;
- rc = smb_send(server, in_buf, len);
- cifs_save_when_sent(midQ);
+ rc = smb_send(server, in_buf, in_len);
+ cifs_save_when_sent(mid);
if (rc < 0)
server->sequence_number -= 2;
@@ -343,38 +309,38 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
if (rc < 0)
goto out;
- rc = wait_for_response(server, midQ);
+ rc = wait_for_response(server, mid);
if (rc != 0) {
- send_cancel(server, &rqst, midQ);
- spin_lock(&midQ->mid_lock);
- if (midQ->callback) {
+ send_cancel(server, &rqst, mid);
+ spin_lock(&mid->mid_lock);
+ if (mid->callback) {
/* no longer considered to be "in-flight" */
- midQ->callback = release_mid;
- spin_unlock(&midQ->mid_lock);
+ mid->callback = release_mid;
+ spin_unlock(&mid->mid_lock);
add_credits(server, &credits, 0);
return rc;
}
- spin_unlock(&midQ->mid_lock);
+ spin_unlock(&mid->mid_lock);
}
- rc = cifs_sync_mid_result(midQ, server);
+ rc = cifs_sync_mid_result(mid, server);
if (rc != 0) {
add_credits(server, &credits, 0);
return rc;
}
- if (!midQ->resp_buf || !out_buf ||
- midQ->mid_state != MID_RESPONSE_READY) {
+ if (!mid->resp_buf || !out_buf ||
+ mid->mid_state != MID_RESPONSE_READY) {
rc = -EIO;
cifs_server_dbg(VFS, "Bad MID state?\n");
goto out;
}
- *pbytes_returned = get_rfc1002_len(midQ->resp_buf);
- memcpy(out_buf, midQ->resp_buf, *pbytes_returned + 4);
- rc = cifs_check_receive(midQ, server, 0);
+ *pbytes_returned = mid->response_pdu_len;
+ memcpy(out_buf, mid->resp_buf, *pbytes_returned);
+ rc = cifs_check_receive(mid, server, 0);
out:
- delete_mid(midQ);
+ delete_mid(mid);
add_credits(server, &credits, 0);
return rc;
@@ -385,8 +351,8 @@ out:
static int
send_lock_cancel(const unsigned int xid, struct cifs_tcon *tcon,
- struct smb_hdr *in_buf,
- struct smb_hdr *out_buf)
+ struct smb_hdr *in_buf, unsigned int in_len,
+ struct smb_hdr *out_buf)
{
int bytes_returned;
struct cifs_ses *ses = tcon->ses;
@@ -401,25 +367,25 @@ send_lock_cancel(const unsigned int xid, struct cifs_tcon *tcon,
pSMB->Timeout = 0;
pSMB->hdr.Mid = get_next_mid(ses->server);
- return SendReceive(xid, ses, in_buf, out_buf,
+ return SendReceive(xid, ses, in_buf, in_len, out_buf,
&bytes_returned, 0);
}
-int
-SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
- struct smb_hdr *in_buf, struct smb_hdr *out_buf,
- int *pbytes_returned)
+int SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
+ struct smb_hdr *in_buf, unsigned int in_len,
+ struct smb_hdr *out_buf, int *pbytes_returned)
{
int rc = 0;
int rstart = 0;
- struct mid_q_entry *midQ;
+ struct mid_q_entry *mid;
struct cifs_ses *ses;
- unsigned int len = be32_to_cpu(in_buf->smb_buf_length);
- struct kvec iov = { .iov_base = in_buf, .iov_len = len };
+ struct kvec iov = { .iov_base = in_buf, .iov_len = in_len };
struct smb_rqst rqst = { .rq_iov = &iov, .rq_nvec = 1 };
unsigned int instance;
struct TCP_Server_Info *server;
+ if (WARN_ON_ONCE(in_len > 0xffffff))
+ return -EIO;
if (tcon == NULL || tcon->ses == NULL) {
cifs_dbg(VFS, "Null smb session\n");
return -EIO;
@@ -443,9 +409,9 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
to the same server. We may make this configurable later or
use ses->maxReq */
- if (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
+ if (in_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
cifs_tcon_dbg(VFS, "Invalid length, greater than maximum frame, %d\n",
- len);
+ in_len);
return -EIO;
}
@@ -459,22 +425,22 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
cifs_server_lock(server);
- rc = allocate_mid(ses, in_buf, &midQ);
+ rc = allocate_mid(ses, in_buf, &mid);
if (rc) {
cifs_server_unlock(server);
return rc;
}
- rc = cifs_sign_smb(in_buf, server, &midQ->sequence_number);
+ rc = cifs_sign_smb(in_buf, in_len, server, &mid->sequence_number);
if (rc) {
- delete_mid(midQ);
+ delete_mid(mid);
cifs_server_unlock(server);
return rc;
}
- midQ->mid_state = MID_REQUEST_SUBMITTED;
- rc = smb_send(server, in_buf, len);
- cifs_save_when_sent(midQ);
+ mid->mid_state = MID_REQUEST_SUBMITTED;
+ rc = smb_send(server, in_buf, in_len);
+ cifs_save_when_sent(mid);
if (rc < 0)
server->sequence_number -= 2;
@@ -482,22 +448,22 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
cifs_server_unlock(server);
if (rc < 0) {
- delete_mid(midQ);
+ delete_mid(mid);
return rc;
}
/* Wait for a reply - allow signals to interrupt. */
rc = wait_event_interruptible(server->response_q,
- (!(midQ->mid_state == MID_REQUEST_SUBMITTED ||
- midQ->mid_state == MID_RESPONSE_RECEIVED)) ||
+ (!(mid->mid_state == MID_REQUEST_SUBMITTED ||
+ mid->mid_state == MID_RESPONSE_RECEIVED)) ||
((server->tcpStatus != CifsGood) &&
(server->tcpStatus != CifsNew)));
/* Were we interrupted by a signal ? */
spin_lock(&server->srv_lock);
if ((rc == -ERESTARTSYS) &&
- (midQ->mid_state == MID_REQUEST_SUBMITTED ||
- midQ->mid_state == MID_RESPONSE_RECEIVED) &&
+ (mid->mid_state == MID_REQUEST_SUBMITTED ||
+ mid->mid_state == MID_RESPONSE_RECEIVED) &&
((server->tcpStatus == CifsGood) ||
(server->tcpStatus == CifsNew))) {
spin_unlock(&server->srv_lock);
@@ -505,36 +471,36 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
if (in_buf->Command == SMB_COM_TRANSACTION2) {
/* POSIX lock. We send a NT_CANCEL SMB to cause the
blocking lock to return. */
- rc = send_cancel(server, &rqst, midQ);
+ rc = send_cancel(server, &rqst, mid);
if (rc) {
- delete_mid(midQ);
+ delete_mid(mid);
return rc;
}
} else {
/* Windows lock. We send a LOCKINGX_CANCEL_LOCK
to cause the blocking lock to return. */
- rc = send_lock_cancel(xid, tcon, in_buf, out_buf);
+ rc = send_lock_cancel(xid, tcon, in_buf, in_len, out_buf);
/* If we get -ENOLCK back the lock may have
already been removed. Don't exit in this case. */
if (rc && rc != -ENOLCK) {
- delete_mid(midQ);
+ delete_mid(mid);
return rc;
}
}
- rc = wait_for_response(server, midQ);
+ rc = wait_for_response(server, mid);
if (rc) {
- send_cancel(server, &rqst, midQ);
- spin_lock(&midQ->mid_lock);
- if (midQ->callback) {
+ send_cancel(server, &rqst, mid);
+ spin_lock(&mid->mid_lock);
+ if (mid->callback) {
/* no longer considered to be "in-flight" */
- midQ->callback = release_mid;
- spin_unlock(&midQ->mid_lock);
+ mid->callback = release_mid;
+ spin_unlock(&mid->mid_lock);
return rc;
}
- spin_unlock(&midQ->mid_lock);
+ spin_unlock(&mid->mid_lock);
}
/* We got the response - restart system call. */
@@ -543,22 +509,22 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
}
spin_unlock(&server->srv_lock);
- rc = cifs_sync_mid_result(midQ, server);
+ rc = cifs_sync_mid_result(mid, server);
if (rc != 0)
return rc;
/* rcvd frame is ok */
- if (out_buf == NULL || midQ->mid_state != MID_RESPONSE_READY) {
+ if (out_buf == NULL || mid->mid_state != MID_RESPONSE_READY) {
rc = -EIO;
cifs_tcon_dbg(VFS, "Bad MID state?\n");
goto out;
}
- *pbytes_returned = get_rfc1002_len(midQ->resp_buf);
- memcpy(out_buf, midQ->resp_buf, *pbytes_returned + 4);
- rc = cifs_check_receive(midQ, server, 0);
+ *pbytes_returned = mid->response_pdu_len;
+ memcpy(out_buf, mid->resp_buf, *pbytes_returned);
+ rc = cifs_check_receive(mid, server, 0);
out:
- delete_mid(midQ);
+ delete_mid(mid);
if (rstart && rc == -EACCES)
return -ERESTARTSYS;
return rc;