diff --git a/SMBLibrary/Client/SMB2Client.cs b/SMBLibrary/Client/SMB2Client.cs index d311f5a..59abdb5 100644 --- a/SMBLibrary/Client/SMB2Client.cs +++ b/SMBLibrary/Client/SMB2Client.cs @@ -24,9 +24,10 @@ namespace SMBLibrary.Client public const int NetBiosOverTCPPort = 139; public const int DirectTCPPort = 445; - public const uint ClientMaxTransactSize = 65536; - public const uint ClientMaxReadSize = 65536; - public const uint ClientMaxWriteSize = 65536; + public static readonly uint ClientMaxTransactSize = 8388608; + public static readonly uint ClientMaxReadSize = 8388608; + public static readonly uint ClientMaxWriteSize = 8388608; + private static readonly ushort DesiredCredits = 128; private SMBTransportType m_transport; private bool m_isConnected; @@ -49,6 +50,7 @@ namespace SMBLibrary.Client private ulong m_sessionID; private byte[] m_securityBlob; private byte[] m_sessionKey; + private ushort m_availableCredits = 1; public SMB2Client() { @@ -388,6 +390,8 @@ namespace SMBLibrary.Client return; } + m_availableCredits += command.Header.Credits; + // [MS-SMB2] 3.2.5.1.2 - If the MessageId is 0xFFFFFFFFFFFFFFFF, this is not a reply to a previous request, // and the client MUST NOT attempt to locate the request, but instead process it as follows: // If the command field in the SMB2 header is SMB2 OPLOCK_BREAK, it MUST be processed as specified in 3.2.5.19. @@ -469,7 +473,32 @@ namespace SMBLibrary.Client internal void TrySendCommand(SMB2Command request) { - request.Header.Credits = 1; + if (m_dialect == SMB2Dialect.SMB202 || m_transport == SMBTransportType.NetBiosOverTCP) + { + request.Header.CreditCharge = 0; + request.Header.Credits = 1; + m_availableCredits -= 1; + } + else + { + if (request.Header.CreditCharge == 0) + { + request.Header.CreditCharge = 1; + } + + if (m_availableCredits < request.Header.CreditCharge) + { + throw new Exception("Not enough credits"); + } + + m_availableCredits -= request.Header.CreditCharge; + + if (m_availableCredits < DesiredCredits) + { + request.Header.Credits += (ushort)(DesiredCredits - m_availableCredits); + } + } + request.Header.MessageID = m_messageID; request.Header.SessionID = m_sessionID; if (m_signingRequired) @@ -485,7 +514,14 @@ namespace SMBLibrary.Client } } TrySendCommand(m_clientSocket, request); - m_messageID++; + if (m_dialect == SMB2Dialect.SMB202 || m_transport == SMBTransportType.NetBiosOverTCP) + { + m_messageID++; + } + else + { + m_messageID += request.Header.CreditCharge; + } } public uint MaxTransactSize diff --git a/SMBLibrary/Client/SMB2FileStore.cs b/SMBLibrary/Client/SMB2FileStore.cs index 3b470c4..1e0cf91 100644 --- a/SMBLibrary/Client/SMB2FileStore.cs +++ b/SMBLibrary/Client/SMB2FileStore.cs @@ -1,4 +1,4 @@ -/* Copyright (C) 2017-2019 Tal Aloni . All rights reserved. +/* Copyright (C) 2017-2020 Tal Aloni . All rights reserved. * * You can redistribute this program and/or modify it under the terms of * the GNU Lesser Public License as published by the Free Software Foundation, @@ -13,6 +13,8 @@ namespace SMBLibrary.Client { public class SMB2FileStore : ISMBFileStore { + private const int BytesPerCredit = 65536; + private SMB2Client m_client; private uint m_treeID; @@ -69,6 +71,7 @@ namespace SMBLibrary.Client { data = null; ReadRequest request = new ReadRequest(); + request.Header.CreditCharge = (ushort)Math.Ceiling((double)maxCount / BytesPerCredit); request.FileId = (FileID)handle; request.Offset = (ulong)offset; request.ReadLength = (uint)maxCount; @@ -91,6 +94,7 @@ namespace SMBLibrary.Client { numberOfBytesWritten = 0; WriteRequest request = new WriteRequest(); + request.Header.CreditCharge = (ushort)Math.Ceiling((double)data.Length / BytesPerCredit); request.FileId = (FileID)handle; request.Offset = (ulong)offset; request.Data = data; @@ -128,6 +132,7 @@ namespace SMBLibrary.Client { result = new List(); QueryDirectoryRequest request = new QueryDirectoryRequest(); + request.Header.CreditCharge = (ushort)Math.Ceiling((double)m_client.MaxTransactSize / BytesPerCredit); request.FileInformationClass = informationClass; request.Reopen = true; request.FileId = (FileID)handle; @@ -279,6 +284,7 @@ namespace SMBLibrary.Client { output = null; IOCtlRequest request = new IOCtlRequest(); + request.Header.CreditCharge = (ushort)Math.Ceiling((double)maxOutputLength / BytesPerCredit); request.CtlCode = ctlCode; request.IsFSCtl = true; request.FileId = (FileID)handle;