summaryrefslogtreecommitdiff
path: root/source3
diff options
context:
space:
mode:
Diffstat (limited to 'source3')
-rw-r--r--source3/smbd/globals.h3
-rw-r--r--source3/smbd/smb2_server.c69
2 files changed, 53 insertions, 19 deletions
diff --git a/source3/smbd/globals.h b/source3/smbd/globals.h
index 9512d05735..b93b373ca5 100644
--- a/source3/smbd/globals.h
+++ b/source3/smbd/globals.h
@@ -673,6 +673,9 @@ struct smbd_server_connection {
* The maximum number of credits we will ever
* grant to the client.
*
+ * Typically we will only grant 1/16th of
+ * max_credits.
+ *
* This is the "server max credits" parameter.
*/
uint16_t max_credits;
diff --git a/source3/smbd/smb2_server.c b/source3/smbd/smb2_server.c
index b01d01f8d5..e4b0277a07 100644
--- a/source3/smbd/smb2_server.c
+++ b/source3/smbd/smb2_server.c
@@ -526,11 +526,33 @@ static void smb2_set_operation_credit(struct smbd_server_connection *sconn,
uint8_t *outhdr = (uint8_t *)out_vector->iov_base;
uint16_t credits_requested;
uint32_t out_flags;
+ uint16_t cmd;
+ NTSTATUS out_status;
uint16_t credits_granted = 0;
uint64_t credits_possible;
+ uint16_t current_max_credits;
+
+ /*
+ * first we grant only 1/16th of the max range.
+ *
+ * Windows also starts with the 1/16th and then grants
+ * more later. I was only able to trigger higher
+ * values, when using a verify high credit charge.
+ *
+ * TODO: scale up depending one load, free memory
+ * or other stuff.
+ * Maybe also on the relationship between number
+ * of requests and the used sequence number.
+ * Which means we would grant more credits
+ * for client which use multi credit requests.
+ */
+ current_max_credits = sconn->smb2.max_credits / 16;
+ current_max_credits = MAX(current_max_credits, 1);
+ cmd = SVAL(inhdr, SMB2_HDR_OPCODE);
credits_requested = SVAL(inhdr, SMB2_HDR_CREDIT);
out_flags = IVAL(outhdr, SMB2_HDR_FLAGS);
+ out_status = NT_STATUS(IVAL(outhdr, SMB2_HDR_STATUS));
SMB_ASSERT(sconn->smb2.max_credits >= sconn->smb2.credits_granted);
@@ -542,26 +564,34 @@ static void smb2_set_operation_credit(struct smbd_server_connection *sconn,
*/
credits_granted = 0;
} else if (credits_requested > 0) {
- uint16_t modified_credits_requested;
- uint32_t multiplier;
-
- /*
- * Split up max_credits into 1/16ths, and then scale
- * the requested credits by how many 16ths have been
- * currently granted. Less than 1/16th == grant all
- * requested (100%), scale down as more have been
- * granted. Never ask for less than 1 as the client
- * asked for at least 1. JRA.
- */
-
- multiplier = 16 - (((sconn->smb2.credits_granted * 16) / sconn->smb2.max_credits) % 16);
+ uint16_t additional_max = 0;
+ uint16_t additional_credits = credits_requested - 1;
- modified_credits_requested = (multiplier * credits_requested) / 16;
- if (modified_credits_requested == 0) {
- modified_credits_requested = 1;
+ switch (cmd) {
+ case SMB2_OP_NEGPROT:
+ break;
+ case SMB2_OP_SESSSETUP:
+ /*
+ * Windows 2012 RC1 starts to grant
+ * additional credits
+ * with a successful session setup
+ */
+ if (NT_STATUS_IS_OK(out_status)) {
+ additional_max = 32;
+ }
+ break;
+ default:
+ /*
+ * We match windows and only grant additional credits
+ * in chunks of 32.
+ */
+ additional_max = 32;
+ break;
}
- credits_granted = modified_credits_requested;
+ additional_credits = MIN(additional_credits, additional_max);
+
+ credits_granted = 1 + additional_credits;
} else if (sconn->smb2.credits_granted == 0) {
/*
* Make sure the client has always at least one credit
@@ -589,7 +619,7 @@ static void smb2_set_operation_credit(struct smbd_server_connection *sconn,
/* remove UINT64_MAX */
credits_possible -= 1;
}
- credits_possible = MIN(credits_possible, sconn->smb2.max_credits);
+ credits_possible = MIN(credits_possible, current_max_credits);
credits_possible -= sconn->smb2.seqnum_range;
credits_granted = MIN(credits_granted, credits_possible);
@@ -599,11 +629,12 @@ static void smb2_set_operation_credit(struct smbd_server_connection *sconn,
sconn->smb2.seqnum_range += credits_granted;
DEBUG(10,("smb2_set_operation_credit: requested %u, "
- "granted %u, current possible %u, "
+ "granted %u, current possible/max %u/%u, "
"total granted/max/low/range %u/%u/%llu/%u\n",
(unsigned int)credits_requested,
(unsigned int)credits_granted,
(unsigned int)credits_possible,
+ (unsigned int)current_max_credits,
(unsigned int)sconn->smb2.credits_granted,
(unsigned int)sconn->smb2.max_credits,
(unsigned long long)sconn->smb2.seqnum_low,