]> Pileus Git - ~andy/linux/blobdiff - fs/cifs/transport.c
Merge branch 'x86-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[~andy/linux] / fs / cifs / transport.c
index 46d8756f2b241673878da87a8c1b905537c4c935..147aa22c3c3a4b0f2b647b6978ec31340ff1a5da 100644 (file)
@@ -129,7 +129,7 @@ smb_sendv(struct TCP_Server_Info *server, struct kvec *iov, int n_vec)
        unsigned int len = iov[0].iov_len;
        unsigned int total_len;
        int first_vec = 0;
-       unsigned int smb_buf_length = smb_buffer->smb_buf_length;
+       unsigned int smb_buf_length = be32_to_cpu(smb_buffer->smb_buf_length);
        struct socket *ssocket = server->ssocket;
 
        if (ssocket == NULL)
@@ -144,17 +144,10 @@ smb_sendv(struct TCP_Server_Info *server, struct kvec *iov, int n_vec)
        else
                smb_msg.msg_flags = MSG_NOSIGNAL;
 
-       /* smb header is converted in header_assemble. bcc and rest of SMB word
-          area, and byte area if necessary, is converted to littleendian in
-          cifssmb.c and RFC1001 len is converted to bigendian in smb_send
-          Flags2 is converted in SendReceive */
-
-
        total_len = 0;
        for (i = 0; i < n_vec; i++)
                total_len += iov[i].iov_len;
 
-       smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length);
        cFYI(1, "Sending smb:  total_len %d", total_len);
        dump_smb(smb_buffer, len);
 
@@ -243,7 +236,7 @@ smb_sendv(struct TCP_Server_Info *server, struct kvec *iov, int n_vec)
 
        /* Don't want to modify the buffer as a
           side effect of this call. */
-       smb_buffer->smb_buf_length = smb_buf_length;
+       smb_buffer->smb_buf_length = cpu_to_be32(smb_buf_length);
 
        return rc;
 }
@@ -302,7 +295,7 @@ static int wait_for_free_request(struct TCP_Server_Info *server,
        return 0;
 }
 
-static int allocate_mid(struct cifsSesInfo *ses, struct smb_hdr *in_buf,
+static int allocate_mid(struct cifs_ses *ses, struct smb_hdr *in_buf,
                        struct mid_q_entry **ppmidQ)
 {
        if (ses->server->tcpStatus == CifsExiting) {
@@ -349,22 +342,24 @@ wait_for_response(struct TCP_Server_Info *server, struct mid_q_entry *midQ)
  * the result. Caller is responsible for dealing with timeouts.
  */
 int
-cifs_call_async(struct TCP_Server_Info *server, struct smb_hdr *in_buf,
-               mid_callback_t *callback, void *cbdata)
+cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov,
+               unsigned int nvec, mid_callback_t *callback, void *cbdata,
+               bool ignore_pend)
 {
        int rc;
        struct mid_q_entry *mid;
+       struct smb_hdr *hdr = (struct smb_hdr *)iov[0].iov_base;
 
-       rc = wait_for_free_request(server, CIFS_ASYNC_OP);
+       rc = wait_for_free_request(server, ignore_pend ? CIFS_ASYNC_OP : 0);
        if (rc)
                return rc;
 
        /* enable signing if server requires it */
-       if (server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
-               in_buf->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
+       if (server->sec_mode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
+               hdr->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
 
        mutex_lock(&server->srv_mutex);
-       mid = AllocMidQEntry(in_buf, server);
+       mid = AllocMidQEntry(hdr, server);
        if (mid == NULL) {
                mutex_unlock(&server->srv_mutex);
                return -ENOMEM;
@@ -375,7 +370,7 @@ cifs_call_async(struct TCP_Server_Info *server, struct smb_hdr *in_buf,
        list_add_tail(&mid->qhead, &server->pending_mid_q);
        spin_unlock(&GlobalMid_Lock);
 
-       rc = cifs_sign_smb(in_buf, server, &mid->sequence_number);
+       rc = cifs_sign_smb2(iov, nvec, server, &mid->sequence_number);
        if (rc) {
                mutex_unlock(&server->srv_mutex);
                goto out_err;
@@ -387,7 +382,7 @@ cifs_call_async(struct TCP_Server_Info *server, struct smb_hdr *in_buf,
 #ifdef CONFIG_CIFS_STATS2
        atomic_inc(&server->inSend);
 #endif
-       rc = smb_send(server, in_buf, in_buf->smb_buf_length);
+       rc = smb_sendv(server, iov, nvec);
 #ifdef CONFIG_CIFS_STATS2
        atomic_dec(&server->inSend);
        mid->when_sent = jiffies;
@@ -414,7 +409,7 @@ out_err:
  *
  */
 int
-SendReceiveNoRsp(const unsigned int xid, struct cifsSesInfo *ses,
+SendReceiveNoRsp(const unsigned int xid, struct cifs_ses *ses,
                struct smb_hdr *in_buf, int flags)
 {
        int rc;
@@ -422,7 +417,7 @@ SendReceiveNoRsp(const unsigned int xid, struct cifsSesInfo *ses,
        int resp_buf_type;
 
        iov[0].iov_base = (char *)in_buf;
-       iov[0].iov_len = in_buf->smb_buf_length + 4;
+       iov[0].iov_len = be32_to_cpu(in_buf->smb_buf_length) + 4;
        flags |= CIFS_NO_RESP;
        rc = SendReceive2(xid, ses, iov, 1, &resp_buf_type, flags);
        cFYI(DBG2, "SendRcvNoRsp flags %d rc %d", flags, rc);
@@ -431,7 +426,7 @@ SendReceiveNoRsp(const unsigned int xid, struct cifsSesInfo *ses,
 }
 
 static int
-sync_mid_result(struct mid_q_entry *mid, struct TCP_Server_Info *server)
+cifs_sync_mid_result(struct mid_q_entry *mid, struct TCP_Server_Info *server)
 {
        int rc = 0;
 
@@ -439,28 +434,21 @@ sync_mid_result(struct mid_q_entry *mid, struct TCP_Server_Info *server)
                mid->mid, mid->midState);
 
        spin_lock(&GlobalMid_Lock);
-       /* ensure that it's no longer on the pending_mid_q */
-       list_del_init(&mid->qhead);
-
        switch (mid->midState) {
        case MID_RESPONSE_RECEIVED:
                spin_unlock(&GlobalMid_Lock);
                return rc;
-       case MID_REQUEST_SUBMITTED:
-               /* socket is going down, reject all calls */
-               if (server->tcpStatus == CifsExiting) {
-                       cERROR(1, "%s: canceling mid=%d cmd=0x%x state=%d",
-                              __func__, mid->mid, mid->command, mid->midState);
-                       rc = -EHOSTDOWN;
-                       break;
-               }
        case MID_RETRY_NEEDED:
                rc = -EAGAIN;
                break;
        case MID_RESPONSE_MALFORMED:
                rc = -EIO;
                break;
+       case MID_SHUTDOWN:
+               rc = -EHOSTDOWN;
+               break;
        default:
+               list_del_init(&mid->qhead);
                cERROR(1, "%s: invalid mid state mid=%d state=%d", __func__,
                        mid->mid, mid->midState);
                rc = -EIO;
@@ -488,10 +476,10 @@ send_nt_cancel(struct TCP_Server_Info *server, struct smb_hdr *in_buf,
        int rc = 0;
 
        /* -4 for RFC1001 length and +2 for BCC field */
-       in_buf->smb_buf_length = sizeof(struct smb_hdr) - 4  + 2;
+       in_buf->smb_buf_length = cpu_to_be32(sizeof(struct smb_hdr) - 4  + 2);
        in_buf->Command = SMB_COM_NT_CANCEL;
        in_buf->WordCount = 0;
-       put_bcc_le(0, in_buf);
+       put_bcc(0, in_buf);
 
        mutex_lock(&server->srv_mutex);
        rc = cifs_sign_smb(in_buf, server, &mid->sequence_number);
@@ -499,7 +487,7 @@ send_nt_cancel(struct TCP_Server_Info *server, struct smb_hdr *in_buf,
                mutex_unlock(&server->srv_mutex);
                return rc;
        }
-       rc = smb_send(server, in_buf, in_buf->smb_buf_length);
+       rc = smb_send(server, in_buf, be32_to_cpu(in_buf->smb_buf_length));
        mutex_unlock(&server->srv_mutex);
 
        cFYI(1, "issued NT_CANCEL for mid %u, rc = %d",
@@ -509,13 +497,31 @@ send_nt_cancel(struct TCP_Server_Info *server, struct smb_hdr *in_buf,
 }
 
 int
-SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
+cifs_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server,
+                  bool log_error)
+{
+       dump_smb(mid->resp_buf,
+                min_t(u32, 92, be32_to_cpu(mid->resp_buf->smb_buf_length)));
+
+       /* convert the length into a more usable form */
+       if (server->sec_mode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) {
+               /* FIXME: add code to kill session */
+               if (cifs_verify_signature(mid->resp_buf, server,
+                                         mid->sequence_number + 1) != 0)
+                       cERROR(1, "Unexpected SMB signature");
+       }
+
+       /* BB special case reconnect tid and uid here? */
+       return map_smb_to_linux_error(mid->resp_buf, log_error);
+}
+
+int
+SendReceive2(const unsigned int xid, struct cifs_ses *ses,
             struct kvec *iov, int n_vec, int *pRespBufType /* ret */,
             const int flags)
 {
        int rc = 0;
        int long_op;
-       unsigned int receive_len;
        struct mid_q_entry *midQ;
        struct smb_hdr *in_buf = iov[0].iov_base;
 
@@ -605,66 +611,31 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
 
        cifs_small_buf_release(in_buf);
 
-       rc = sync_mid_result(midQ, ses->server);
+       rc = cifs_sync_mid_result(midQ, ses->server);
        if (rc != 0) {
                atomic_dec(&ses->server->inFlight);
                wake_up(&ses->server->request_q);
                return rc;
        }
 
-       receive_len = midQ->resp_buf->smb_buf_length;
-
-       if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
-               cERROR(1, "Frame too large received.  Length: %d  Xid: %d",
-                       receive_len, xid);
+       if (!midQ->resp_buf || midQ->midState != MID_RESPONSE_RECEIVED) {
                rc = -EIO;
+               cFYI(1, "Bad MID state?");
                goto out;
        }
 
-       /* rcvd frame is ok */
-
-       if (midQ->resp_buf &&
-           (midQ->midState == MID_RESPONSE_RECEIVED)) {
-
-               iov[0].iov_base = (char *)midQ->resp_buf;
-               if (midQ->largeBuf)
-                       *pRespBufType = CIFS_LARGE_BUFFER;
-               else
-                       *pRespBufType = CIFS_SMALL_BUFFER;
-               iov[0].iov_len = receive_len + 4;
-
-               dump_smb(midQ->resp_buf, 80);
-               /* convert the length into a more usable form */
-               if ((receive_len > 24) &&
-                   (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
-                                            SECMODE_SIGN_ENABLED))) {
-                       rc = cifs_verify_signature(midQ->resp_buf,
-                                               ses->server,
-                                               midQ->sequence_number+1);
-                       if (rc) {
-                               cERROR(1, "Unexpected SMB signature");
-                               /* BB FIXME add code to kill session */
-                       }
-               }
+       iov[0].iov_base = (char *)midQ->resp_buf;
+       iov[0].iov_len = be32_to_cpu(midQ->resp_buf->smb_buf_length) + 4;
+       if (midQ->largeBuf)
+               *pRespBufType = CIFS_LARGE_BUFFER;
+       else
+               *pRespBufType = CIFS_SMALL_BUFFER;
 
-               /* BB special case reconnect tid and uid here? */
-               rc = map_smb_to_linux_error(midQ->resp_buf,
-                                           flags & CIFS_LOG_ERROR);
-
-               /* convert ByteCount if necessary */
-               if (receive_len >= sizeof(struct smb_hdr) - 4
-                   /* do not count RFC1001 header */  +
-                   (2 * midQ->resp_buf->WordCount) + 2 /* bcc */ )
-                       put_bcc(get_bcc_le(midQ->resp_buf), midQ->resp_buf);
-               if ((flags & CIFS_NO_RESP) == 0)
-                       midQ->resp_buf = NULL;  /* mark it so buf will
-                                                  not be freed by
-                                                  delete_mid */
-       } else {
-               rc = -EIO;
-               cFYI(1, "Bad MID state?");
-       }
+       rc = cifs_check_receive(midQ, ses->server, flags & CIFS_LOG_ERROR);
 
+       /* mark it so buf will not be freed by delete_mid */
+       if ((flags & CIFS_NO_RESP) == 0)
+               midQ->resp_buf = NULL;
 out:
        delete_mid(midQ);
        atomic_dec(&ses->server->inFlight);
@@ -674,12 +645,11 @@ out:
 }
 
 int
-SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
+SendReceive(const unsigned int xid, struct cifs_ses *ses,
            struct smb_hdr *in_buf, struct smb_hdr *out_buf,
            int *pbytes_returned, const int long_op)
 {
        int rc = 0;
-       unsigned int receive_len;
        struct mid_q_entry *midQ;
 
        if (ses == NULL) {
@@ -698,9 +668,10 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
           to the same server. We may make this configurable later or
           use ses->maxReq */
 
-       if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
+       if (be32_to_cpu(in_buf->smb_buf_length) > CIFSMaxBufSize +
+                       MAX_CIFS_HDR_SIZE - 4) {
                cERROR(1, "Illegal length, greater than maximum frame, %d",
-                          in_buf->smb_buf_length);
+                          be32_to_cpu(in_buf->smb_buf_length));
                return -EIO;
        }
 
@@ -733,7 +704,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
 #ifdef CONFIG_CIFS_STATS2
        atomic_inc(&ses->server->inSend);
 #endif
-       rc = smb_send(ses->server, in_buf, in_buf->smb_buf_length);
+       rc = smb_send(ses->server, in_buf, be32_to_cpu(in_buf->smb_buf_length));
 #ifdef CONFIG_CIFS_STATS2
        atomic_dec(&ses->server->inSend);
        midQ->when_sent = jiffies;
@@ -761,60 +732,23 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
                spin_unlock(&GlobalMid_Lock);
        }
 
-       rc = sync_mid_result(midQ, ses->server);
+       rc = cifs_sync_mid_result(midQ, ses->server);
        if (rc != 0) {
                atomic_dec(&ses->server->inFlight);
                wake_up(&ses->server->request_q);
                return rc;
        }
 
-       receive_len = midQ->resp_buf->smb_buf_length;
-
-       if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
-               cERROR(1, "Frame too large received.  Length: %d  Xid: %d",
-                       receive_len, xid);
-               rc = -EIO;
-               goto out;
-       }
-
-       /* rcvd frame is ok */
-
-       if (midQ->resp_buf && out_buf
-           && (midQ->midState == MID_RESPONSE_RECEIVED)) {
-               out_buf->smb_buf_length = receive_len;
-               memcpy((char *)out_buf + 4,
-                      (char *)midQ->resp_buf + 4,
-                      receive_len);
-
-               dump_smb(out_buf, 92);
-               /* convert the length into a more usable form */
-               if ((receive_len > 24) &&
-                   (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
-                                            SECMODE_SIGN_ENABLED))) {
-                       rc = cifs_verify_signature(out_buf,
-                                               ses->server,
-                                               midQ->sequence_number+1);
-                       if (rc) {
-                               cERROR(1, "Unexpected SMB signature");
-                               /* BB FIXME add code to kill session */
-                       }
-               }
-
-               *pbytes_returned = out_buf->smb_buf_length;
-
-               /* BB special case reconnect tid and uid here? */
-               rc = map_smb_to_linux_error(out_buf, 0 /* no log */ );
-
-               /* convert ByteCount if necessary */
-               if (receive_len >= sizeof(struct smb_hdr) - 4
-                   /* do not count RFC1001 header */  +
-                   (2 * out_buf->WordCount) + 2 /* bcc */ )
-                       put_bcc(get_bcc_le(midQ->resp_buf), midQ->resp_buf);
-       } else {
+       if (!midQ->resp_buf || !out_buf ||
+           midQ->midState != MID_RESPONSE_RECEIVED) {
                rc = -EIO;
                cERROR(1, "Bad MID state?");
+               goto out;
        }
 
+       *pbytes_returned = be32_to_cpu(midQ->resp_buf->smb_buf_length);
+       memcpy(out_buf, midQ->resp_buf, *pbytes_returned + 4);
+       rc = cifs_check_receive(midQ, ses->server, 0);
 out:
        delete_mid(midQ);
        atomic_dec(&ses->server->inFlight);
@@ -827,12 +761,12 @@ out:
    blocking lock to return. */
 
 static int
-send_lock_cancel(const unsigned int xid, struct cifsTconInfo *tcon,
+send_lock_cancel(const unsigned int xid, struct cifs_tcon *tcon,
                        struct smb_hdr *in_buf,
                        struct smb_hdr *out_buf)
 {
        int bytes_returned;
-       struct cifsSesInfo *ses = tcon->ses;
+       struct cifs_ses *ses = tcon->ses;
        LOCK_REQ *pSMB = (LOCK_REQ *)in_buf;
 
        /* We just modify the current in_buf to change
@@ -849,15 +783,14 @@ send_lock_cancel(const unsigned int xid, struct cifsTconInfo *tcon,
 }
 
 int
-SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
+SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
            struct smb_hdr *in_buf, struct smb_hdr *out_buf,
            int *pbytes_returned)
 {
        int rc = 0;
        int rstart = 0;
-       unsigned int receive_len;
        struct mid_q_entry *midQ;
-       struct cifsSesInfo *ses;
+       struct cifs_ses *ses;
 
        if (tcon == NULL || tcon->ses == NULL) {
                cERROR(1, "Null smb session");
@@ -877,9 +810,10 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
           to the same server. We may make this configurable later or
           use ses->maxReq */
 
-       if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
+       if (be32_to_cpu(in_buf->smb_buf_length) > CIFSMaxBufSize +
+                       MAX_CIFS_HDR_SIZE - 4) {
                cERROR(1, "Illegal length, greater than maximum frame, %d",
-                          in_buf->smb_buf_length);
+                          be32_to_cpu(in_buf->smb_buf_length));
                return -EIO;
        }
 
@@ -910,7 +844,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
 #ifdef CONFIG_CIFS_STATS2
        atomic_inc(&ses->server->inSend);
 #endif
-       rc = smb_send(ses->server, in_buf, in_buf->smb_buf_length);
+       rc = smb_send(ses->server, in_buf, be32_to_cpu(in_buf->smb_buf_length));
 #ifdef CONFIG_CIFS_STATS2
        atomic_dec(&ses->server->inSend);
        midQ->when_sent = jiffies;
@@ -973,56 +907,20 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
                rstart = 1;
        }
 
-       rc = sync_mid_result(midQ, ses->server);
+       rc = cifs_sync_mid_result(midQ, ses->server);
        if (rc != 0)
                return rc;
 
-       receive_len = midQ->resp_buf->smb_buf_length;
-       if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
-               cERROR(1, "Frame too large received.  Length: %d  Xid: %d",
-                       receive_len, xid);
-               rc = -EIO;
-               goto out;
-       }
-
        /* rcvd frame is ok */
-
-       if ((out_buf == NULL) || (midQ->midState != MID_RESPONSE_RECEIVED)) {
+       if (out_buf == NULL || midQ->midState != MID_RESPONSE_RECEIVED) {
                rc = -EIO;
                cERROR(1, "Bad MID state?");
                goto out;
        }
 
-       out_buf->smb_buf_length = receive_len;
-       memcpy((char *)out_buf + 4,
-              (char *)midQ->resp_buf + 4,
-              receive_len);
-
-       dump_smb(out_buf, 92);
-       /* convert the length into a more usable form */
-       if ((receive_len > 24) &&
-           (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
-                                    SECMODE_SIGN_ENABLED))) {
-               rc = cifs_verify_signature(out_buf,
-                                          ses->server,
-                                          midQ->sequence_number+1);
-               if (rc) {
-                       cERROR(1, "Unexpected SMB signature");
-                       /* BB FIXME add code to kill session */
-               }
-       }
-
-       *pbytes_returned = out_buf->smb_buf_length;
-
-       /* BB special case reconnect tid and uid here? */
-       rc = map_smb_to_linux_error(out_buf, 0 /* no log */ );
-
-       /* convert ByteCount if necessary */
-       if (receive_len >= sizeof(struct smb_hdr) - 4
-           /* do not count RFC1001 header */  +
-           (2 * out_buf->WordCount) + 2 /* bcc */ )
-               put_bcc(get_bcc_le(out_buf), out_buf);
-
+       *pbytes_returned = be32_to_cpu(midQ->resp_buf->smb_buf_length);
+       memcpy(out_buf, midQ->resp_buf, *pbytes_returned + 4);
+       rc = cifs_check_receive(midQ, ses->server, 0);
 out:
        delete_mid(midQ);
        if (rstart && rc == -EACCES)