diff options
Diffstat (limited to 'fs/smb/client/cifstransport.c')
| -rw-r--r-- | fs/smb/client/cifstransport.c | 208 |
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; |
