diff options
Diffstat (limited to 'fs/cifs/cifssmb.c')
-rw-r--r-- | fs/cifs/cifssmb.c | 135 |
1 files changed, 87 insertions, 48 deletions
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 2f6795e524d3..df959bae6728 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c | |||
@@ -136,18 +136,15 @@ cifs_reconnect_tcon(struct cifsTconInfo *tcon, int smb_command) | |||
136 | } | 136 | } |
137 | } | 137 | } |
138 | 138 | ||
139 | if (ses->status == CifsExiting) | ||
140 | return -EIO; | ||
141 | |||
142 | /* | 139 | /* |
143 | * Give demultiplex thread up to 10 seconds to reconnect, should be | 140 | * Give demultiplex thread up to 10 seconds to reconnect, should be |
144 | * greater than cifs socket timeout which is 7 seconds | 141 | * greater than cifs socket timeout which is 7 seconds |
145 | */ | 142 | */ |
146 | while (server->tcpStatus == CifsNeedReconnect) { | 143 | while (server->tcpStatus == CifsNeedReconnect) { |
147 | wait_event_interruptible_timeout(server->response_q, | 144 | wait_event_interruptible_timeout(server->response_q, |
148 | (server->tcpStatus == CifsGood), 10 * HZ); | 145 | (server->tcpStatus != CifsNeedReconnect), 10 * HZ); |
149 | 146 | ||
150 | /* is TCP session is reestablished now ?*/ | 147 | /* are we still trying to reconnect? */ |
151 | if (server->tcpStatus != CifsNeedReconnect) | 148 | if (server->tcpStatus != CifsNeedReconnect) |
152 | break; | 149 | break; |
153 | 150 | ||
@@ -156,7 +153,7 @@ cifs_reconnect_tcon(struct cifsTconInfo *tcon, int smb_command) | |||
156 | * retrying until process is killed or server comes | 153 | * retrying until process is killed or server comes |
157 | * back on-line | 154 | * back on-line |
158 | */ | 155 | */ |
159 | if (!tcon->retry || ses->status == CifsExiting) { | 156 | if (!tcon->retry) { |
160 | cFYI(1, "gave up waiting on reconnect in smb_init"); | 157 | cFYI(1, "gave up waiting on reconnect in smb_init"); |
161 | return -EHOSTDOWN; | 158 | return -EHOSTDOWN; |
162 | } | 159 | } |
@@ -331,37 +328,35 @@ smb_init_no_reconnect(int smb_command, int wct, struct cifsTconInfo *tcon, | |||
331 | 328 | ||
332 | static int validate_t2(struct smb_t2_rsp *pSMB) | 329 | static int validate_t2(struct smb_t2_rsp *pSMB) |
333 | { | 330 | { |
334 | int rc = -EINVAL; | 331 | unsigned int total_size; |
335 | int total_size; | 332 | |
336 | char *pBCC; | 333 | /* check for plausible wct */ |
334 | if (pSMB->hdr.WordCount < 10) | ||
335 | goto vt2_err; | ||
337 | 336 | ||
338 | /* check for plausible wct, bcc and t2 data and parm sizes */ | ||
339 | /* check for parm and data offset going beyond end of smb */ | 337 | /* check for parm and data offset going beyond end of smb */ |
340 | if (pSMB->hdr.WordCount >= 10) { | 338 | if (get_unaligned_le16(&pSMB->t2_rsp.ParameterOffset) > 1024 || |
341 | if ((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) && | 339 | get_unaligned_le16(&pSMB->t2_rsp.DataOffset) > 1024) |
342 | (le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) { | 340 | goto vt2_err; |
343 | /* check that bcc is at least as big as parms + data */ | 341 | |
344 | /* check that bcc is less than negotiated smb buffer */ | 342 | /* check that bcc is at least as big as parms + data */ |
345 | total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount); | 343 | /* check that bcc is less than negotiated smb buffer */ |
346 | if (total_size < 512) { | 344 | total_size = get_unaligned_le16(&pSMB->t2_rsp.ParameterCount); |
347 | total_size += | 345 | if (total_size >= 512) |
348 | le16_to_cpu(pSMB->t2_rsp.DataCount); | 346 | goto vt2_err; |
349 | /* BCC le converted in SendReceive */ | 347 | |
350 | pBCC = (pSMB->hdr.WordCount * 2) + | 348 | total_size += get_unaligned_le16(&pSMB->t2_rsp.DataCount); |
351 | sizeof(struct smb_hdr) + | 349 | if (total_size > get_bcc(&pSMB->hdr) || |
352 | (char *)pSMB; | 350 | total_size >= CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) |
353 | if ((total_size <= (*(u16 *)pBCC)) && | 351 | goto vt2_err; |
354 | (total_size < | 352 | |
355 | CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) { | 353 | return 0; |
356 | return 0; | 354 | vt2_err: |
357 | } | ||
358 | } | ||
359 | } | ||
360 | } | ||
361 | cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB, | 355 | cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB, |
362 | sizeof(struct smb_t2_rsp) + 16); | 356 | sizeof(struct smb_t2_rsp) + 16); |
363 | return rc; | 357 | return -EINVAL; |
364 | } | 358 | } |
359 | |||
365 | int | 360 | int |
366 | CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) | 361 | CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) |
367 | { | 362 | { |
@@ -452,7 +447,6 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) | |||
452 | server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize), | 447 | server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize), |
453 | (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE); | 448 | (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE); |
454 | server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs); | 449 | server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs); |
455 | GETU32(server->sessid) = le32_to_cpu(rsp->SessionKey); | ||
456 | /* even though we do not use raw we might as well set this | 450 | /* even though we do not use raw we might as well set this |
457 | accurately, in case we ever find a need for it */ | 451 | accurately, in case we ever find a need for it */ |
458 | if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) { | 452 | if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) { |
@@ -566,7 +560,6 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) | |||
566 | (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE); | 560 | (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE); |
567 | server->max_rw = le32_to_cpu(pSMBr->MaxRawSize); | 561 | server->max_rw = le32_to_cpu(pSMBr->MaxRawSize); |
568 | cFYI(DBG2, "Max buf = %d", ses->server->maxBuf); | 562 | cFYI(DBG2, "Max buf = %d", ses->server->maxBuf); |
569 | GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey); | ||
570 | server->capabilities = le32_to_cpu(pSMBr->Capabilities); | 563 | server->capabilities = le32_to_cpu(pSMBr->Capabilities); |
571 | server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone); | 564 | server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone); |
572 | server->timeAdj *= 60; | 565 | server->timeAdj *= 60; |
@@ -706,6 +699,53 @@ CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon) | |||
706 | return rc; | 699 | return rc; |
707 | } | 700 | } |
708 | 701 | ||
702 | /* | ||
703 | * This is a no-op for now. We're not really interested in the reply, but | ||
704 | * rather in the fact that the server sent one and that server->lstrp | ||
705 | * gets updated. | ||
706 | * | ||
707 | * FIXME: maybe we should consider checking that the reply matches request? | ||
708 | */ | ||
709 | static void | ||
710 | cifs_echo_callback(struct mid_q_entry *mid) | ||
711 | { | ||
712 | struct TCP_Server_Info *server = mid->callback_data; | ||
713 | |||
714 | DeleteMidQEntry(mid); | ||
715 | atomic_dec(&server->inFlight); | ||
716 | wake_up(&server->request_q); | ||
717 | } | ||
718 | |||
719 | int | ||
720 | CIFSSMBEcho(struct TCP_Server_Info *server) | ||
721 | { | ||
722 | ECHO_REQ *smb; | ||
723 | int rc = 0; | ||
724 | |||
725 | cFYI(1, "In echo request"); | ||
726 | |||
727 | rc = small_smb_init(SMB_COM_ECHO, 0, NULL, (void **)&smb); | ||
728 | if (rc) | ||
729 | return rc; | ||
730 | |||
731 | /* set up echo request */ | ||
732 | smb->hdr.Tid = 0xffff; | ||
733 | smb->hdr.WordCount = 1; | ||
734 | put_unaligned_le16(1, &smb->EchoCount); | ||
735 | put_bcc_le(1, &smb->hdr); | ||
736 | smb->Data[0] = 'a'; | ||
737 | smb->hdr.smb_buf_length += 3; | ||
738 | |||
739 | rc = cifs_call_async(server, (struct smb_hdr *)smb, | ||
740 | cifs_echo_callback, server); | ||
741 | if (rc) | ||
742 | cFYI(1, "Echo request failed: %d", rc); | ||
743 | |||
744 | cifs_small_buf_release(smb); | ||
745 | |||
746 | return rc; | ||
747 | } | ||
748 | |||
709 | int | 749 | int |
710 | CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses) | 750 | CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses) |
711 | { | 751 | { |
@@ -1193,7 +1233,7 @@ OldOpenRetry: | |||
1193 | pSMB->ByteCount = cpu_to_le16(count); | 1233 | pSMB->ByteCount = cpu_to_le16(count); |
1194 | /* long_op set to 1 to allow for oplock break timeouts */ | 1234 | /* long_op set to 1 to allow for oplock break timeouts */ |
1195 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 1235 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
1196 | (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP); | 1236 | (struct smb_hdr *)pSMBr, &bytes_returned, 0); |
1197 | cifs_stats_inc(&tcon->num_opens); | 1237 | cifs_stats_inc(&tcon->num_opens); |
1198 | if (rc) { | 1238 | if (rc) { |
1199 | cFYI(1, "Error in Open = %d", rc); | 1239 | cFYI(1, "Error in Open = %d", rc); |
@@ -1306,7 +1346,7 @@ openRetry: | |||
1306 | pSMB->ByteCount = cpu_to_le16(count); | 1346 | pSMB->ByteCount = cpu_to_le16(count); |
1307 | /* long_op set to 1 to allow for oplock break timeouts */ | 1347 | /* long_op set to 1 to allow for oplock break timeouts */ |
1308 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 1348 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
1309 | (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP); | 1349 | (struct smb_hdr *)pSMBr, &bytes_returned, 0); |
1310 | cifs_stats_inc(&tcon->num_opens); | 1350 | cifs_stats_inc(&tcon->num_opens); |
1311 | if (rc) { | 1351 | if (rc) { |
1312 | cFYI(1, "Error in Open = %d", rc); | 1352 | cFYI(1, "Error in Open = %d", rc); |
@@ -1388,7 +1428,7 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid, | |||
1388 | iov[0].iov_base = (char *)pSMB; | 1428 | iov[0].iov_base = (char *)pSMB; |
1389 | iov[0].iov_len = pSMB->hdr.smb_buf_length + 4; | 1429 | iov[0].iov_len = pSMB->hdr.smb_buf_length + 4; |
1390 | rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */, | 1430 | rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */, |
1391 | &resp_buf_type, CIFS_STD_OP | CIFS_LOG_ERROR); | 1431 | &resp_buf_type, CIFS_LOG_ERROR); |
1392 | cifs_stats_inc(&tcon->num_reads); | 1432 | cifs_stats_inc(&tcon->num_reads); |
1393 | pSMBr = (READ_RSP *)iov[0].iov_base; | 1433 | pSMBr = (READ_RSP *)iov[0].iov_base; |
1394 | if (rc) { | 1434 | if (rc) { |
@@ -1663,7 +1703,8 @@ int | |||
1663 | CIFSSMBLock(const int xid, struct cifsTconInfo *tcon, | 1703 | CIFSSMBLock(const int xid, struct cifsTconInfo *tcon, |
1664 | const __u16 smb_file_id, const __u64 len, | 1704 | const __u16 smb_file_id, const __u64 len, |
1665 | const __u64 offset, const __u32 numUnlock, | 1705 | const __u64 offset, const __u32 numUnlock, |
1666 | const __u32 numLock, const __u8 lockType, const bool waitFlag) | 1706 | const __u32 numLock, const __u8 lockType, |
1707 | const bool waitFlag, const __u8 oplock_level) | ||
1667 | { | 1708 | { |
1668 | int rc = 0; | 1709 | int rc = 0; |
1669 | LOCK_REQ *pSMB = NULL; | 1710 | LOCK_REQ *pSMB = NULL; |
@@ -1691,6 +1732,7 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon, | |||
1691 | pSMB->NumberOfLocks = cpu_to_le16(numLock); | 1732 | pSMB->NumberOfLocks = cpu_to_le16(numLock); |
1692 | pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock); | 1733 | pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock); |
1693 | pSMB->LockType = lockType; | 1734 | pSMB->LockType = lockType; |
1735 | pSMB->OplockLevel = oplock_level; | ||
1694 | pSMB->AndXCommand = 0xFF; /* none */ | 1736 | pSMB->AndXCommand = 0xFF; /* none */ |
1695 | pSMB->Fid = smb_file_id; /* netfid stays le */ | 1737 | pSMB->Fid = smb_file_id; /* netfid stays le */ |
1696 | 1738 | ||
@@ -1842,10 +1884,10 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon, | |||
1842 | __constant_cpu_to_le16(CIFS_WRLCK)) | 1884 | __constant_cpu_to_le16(CIFS_WRLCK)) |
1843 | pLockData->fl_type = F_WRLCK; | 1885 | pLockData->fl_type = F_WRLCK; |
1844 | 1886 | ||
1845 | pLockData->fl_start = parm_data->start; | 1887 | pLockData->fl_start = le64_to_cpu(parm_data->start); |
1846 | pLockData->fl_end = parm_data->start + | 1888 | pLockData->fl_end = pLockData->fl_start + |
1847 | parm_data->length - 1; | 1889 | le64_to_cpu(parm_data->length) - 1; |
1848 | pLockData->fl_pid = parm_data->pid; | 1890 | pLockData->fl_pid = le32_to_cpu(parm_data->pid); |
1849 | } | 1891 | } |
1850 | } | 1892 | } |
1851 | 1893 | ||
@@ -3087,7 +3129,7 @@ CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid, | |||
3087 | iov[0].iov_len = pSMB->hdr.smb_buf_length + 4; | 3129 | iov[0].iov_len = pSMB->hdr.smb_buf_length + 4; |
3088 | 3130 | ||
3089 | rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type, | 3131 | rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type, |
3090 | CIFS_STD_OP); | 3132 | 0); |
3091 | cifs_stats_inc(&tcon->num_acl_get); | 3133 | cifs_stats_inc(&tcon->num_acl_get); |
3092 | if (rc) { | 3134 | if (rc) { |
3093 | cFYI(1, "Send error in QuerySecDesc = %d", rc); | 3135 | cFYI(1, "Send error in QuerySecDesc = %d", rc); |
@@ -4869,7 +4911,6 @@ CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size, | |||
4869 | __u16 fid, __u32 pid_of_opener, bool SetAllocation) | 4911 | __u16 fid, __u32 pid_of_opener, bool SetAllocation) |
4870 | { | 4912 | { |
4871 | struct smb_com_transaction2_sfi_req *pSMB = NULL; | 4913 | struct smb_com_transaction2_sfi_req *pSMB = NULL; |
4872 | char *data_offset; | ||
4873 | struct file_end_of_file_info *parm_data; | 4914 | struct file_end_of_file_info *parm_data; |
4874 | int rc = 0; | 4915 | int rc = 0; |
4875 | __u16 params, param_offset, offset, byte_count, count; | 4916 | __u16 params, param_offset, offset, byte_count, count; |
@@ -4893,8 +4934,6 @@ CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size, | |||
4893 | param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4; | 4934 | param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4; |
4894 | offset = param_offset + params; | 4935 | offset = param_offset + params; |
4895 | 4936 | ||
4896 | data_offset = (char *) (&pSMB->hdr.Protocol) + offset; | ||
4897 | |||
4898 | count = sizeof(struct file_end_of_file_info); | 4937 | count = sizeof(struct file_end_of_file_info); |
4899 | pSMB->MaxParameterCount = cpu_to_le16(2); | 4938 | pSMB->MaxParameterCount = cpu_to_le16(2); |
4900 | /* BB find exact max SMB PDU from sess structure BB */ | 4939 | /* BB find exact max SMB PDU from sess structure BB */ |
@@ -5208,7 +5247,7 @@ cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset, | |||
5208 | * Samba server ignores set of file size to zero due to bugs in some | 5247 | * Samba server ignores set of file size to zero due to bugs in some |
5209 | * older clients, but we should be precise - we use SetFileSize to | 5248 | * older clients, but we should be precise - we use SetFileSize to |
5210 | * set file size and do not want to truncate file size to zero | 5249 | * set file size and do not want to truncate file size to zero |
5211 | * accidently as happened on one Samba server beta by putting | 5250 | * accidentally as happened on one Samba server beta by putting |
5212 | * zero instead of -1 here | 5251 | * zero instead of -1 here |
5213 | */ | 5252 | */ |
5214 | data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64); | 5253 | data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64); |
@@ -5562,7 +5601,7 @@ QAllEAsRetry: | |||
5562 | } | 5601 | } |
5563 | 5602 | ||
5564 | /* make sure list_len doesn't go past end of SMB */ | 5603 | /* make sure list_len doesn't go past end of SMB */ |
5565 | end_of_smb = (char *)pByteArea(&pSMBr->hdr) + BCC(&pSMBr->hdr); | 5604 | end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr); |
5566 | if ((char *)ea_response_data + list_len > end_of_smb) { | 5605 | if ((char *)ea_response_data + list_len > end_of_smb) { |
5567 | cFYI(1, "EA list appears to go beyond SMB"); | 5606 | cFYI(1, "EA list appears to go beyond SMB"); |
5568 | rc = -EIO; | 5607 | rc = -EIO; |