[SCM] Samba Shared Repository - branch master updated

Stefan Metzmacher metze at samba.org
Thu Jun 28 18:08:02 MDT 2012


The branch, master has been updated
       via  ded2cb8 docs-xml: document "server max protocol" "SMB2" selects PROTOCOL_SMB2_10
       via  dc66e63 s3:param: change "server max protocol" to "SMB2" (SMB2_10)
       via  a5b62a6 lib/param: let "SMB2" select PROTOCOL_SMB2_10
       via  34a9892 s3:smb2_server: make the logic in smbd_smb2_request_verify_creditcharge() simpler
       via  967f2c4 s3:smb2_server: simplify smbd_smb2_request_verify_creditcharge() a bit.
       via  5b7f5d0 s3:smb2_negprot: support SMB2_CAP_LARGE_MTU on everything but port 139
       via  1db83d2 s3:smb2_server: grant extra credits for multi-credit requests
       via  648b959 s3:smb2_server: implement credit granting similar to windows
       via  82dc0b3 s3:smb2_server: make sure sequence numbers don't wrap at UINT64_MAX
       via  ee8ae45 s3:smb2_server: make sure we don't grant more credits than we allow
       via  4fe41c0 s3:smb2_server: check the credit_charge against the already granted credits
       via  984fdaf s3:smb2_server: split out a smb2_validate_sequence_number() function
       via  d6e7a76 s3:smb2_server: clear sequence window if we got the lowest sequence id
       via  bd6d415 s3:smb2_server: fix calculation of the next bitmap_offset
       via  d1ee774 s3:smb2_server: remove unused and confusing DEFAULT_SMB2_MAX_CREDIT_BITMAP_FACTOR
       via  925994e s3:smb2_server: call smbd_smb2_request_validate() also in smbd_smb2_first_negprot()
       via  0b8eac9 s3:smb2_server: start the connection with one credit granted to the client
      from  7560b1c s3: fine tune and clean up statvfs tests

http://gitweb.samba.org/?p=samba.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit ded2cb8f278b513d01cd143312cda2e3b4bb7da5
Author: Stefan Metzmacher <metze at samba.org>
Date:   Sun Jun 3 23:09:33 2012 +0200

    docs-xml: document "server max protocol" "SMB2" selects PROTOCOL_SMB2_10
    
    metze
    
    Autobuild-User(master): Stefan Metzmacher <metze at samba.org>
    Autobuild-Date(master): Fri Jun 29 02:07:17 CEST 2012 on sn-devel-104

commit dc66e63d5feca2890ebe6325b5eee3141d89831e
Author: Stefan Metzmacher <metze at samba.org>
Date:   Sun Jun 3 23:04:44 2012 +0200

    s3:param: change "server max protocol" to "SMB2" (SMB2_10)
    
    metze

commit a5b62a60cc2421664da51d4ad080390644f280b7
Author: Stefan Metzmacher <metze at samba.org>
Date:   Sun Jun 3 23:02:56 2012 +0200

    lib/param: let "SMB2" select PROTOCOL_SMB2_10
    
    metze

commit 34a9892ec17a831bf785ee5c1dc4e0ab0edda0ce
Author: Stefan Metzmacher <metze at samba.org>
Date:   Mon Jun 25 23:35:46 2012 +0200

    s3:smb2_server: make the logic in smbd_smb2_request_verify_creditcharge() simpler
    
    We just need a max_charge variable to make the algorithm independent
    of multi_credit support.
    
    metze

commit 967f2c44b3b911d151ea262b748d68654ba9e2fc
Author: Stefan Metzmacher <metze at samba.org>
Date:   Mon Jun 25 21:14:43 2012 +0200

    s3:smb2_server: simplify smbd_smb2_request_verify_creditcharge() a bit.
    
    A credit charge of 0 is really not a special case, it just means the same
    as 1.
    
    metze

commit 5b7f5d02b5a432fff116f5e2a17e956e3255cd35
Author: Stefan Metzmacher <metze at samba.org>
Date:   Mon Jun 25 21:40:00 2012 +0200

    s3:smb2_negprot: support SMB2_CAP_LARGE_MTU on everything but port 139
    
    In future we'll have other transports like RDMA.
    This makes NBT (tcp port 139) special instead of port 445.
    
    metze

commit 1db83d2b376fc409a51c28dd7a30717819b366a6
Author: Stefan Metzmacher <metze at samba.org>
Date:   Mon Jun 25 21:45:54 2012 +0200

    s3:smb2_server: grant extra credits for multi-credit requests
    
    metze

commit 648b959b13224105addaae483823bc422ed1cc21
Author: Stefan Metzmacher <metze at samba.org>
Date:   Wed Jun 27 15:33:43 2012 +0200

    s3:smb2_server: implement credit granting similar to windows
    
    This makes it much easier to compare traces.
    
    metze

commit 82dc0b33b9af5094d78f3ecd855900e49c580343
Author: Stefan Metzmacher <metze at samba.org>
Date:   Wed Jun 27 15:33:43 2012 +0200

    s3:smb2_server: make sure sequence numbers don't wrap at UINT64_MAX
    
    metze

commit ee8ae459aea6879377b5510851a6dc673cf72aad
Author: Stefan Metzmacher <metze at samba.org>
Date:   Wed Jun 27 15:33:43 2012 +0200

    s3:smb2_server: make sure we don't grant more credits than we allow
    
    If the client hasn't consumed the lowest seqnum, but the distance
    between lowest and highest seqnum has reached max credits.
    
    In that case we should stop granting credits.
    
    metze

commit 4fe41c0bb14f6ae7e52aa7f180e66c7695eb6fa0
Author: Stefan Metzmacher <metze at samba.org>
Date:   Tue Jun 26 14:28:07 2012 +0200

    s3:smb2_server: check the credit_charge against the already granted credits
    
    metze

commit 984fdaf9149d96d0d28600443981d87d13eb355c
Author: Stefan Metzmacher <metze at samba.org>
Date:   Mon Jun 25 23:17:55 2012 +0200

    s3:smb2_server: split out a smb2_validate_sequence_number() function
    
    metze

commit d6e7a76461ad7582efa510676aa2bea230ea9f02
Author: Stefan Metzmacher <metze at samba.org>
Date:   Tue Jun 26 08:08:37 2012 +0200

    s3:smb2_server: clear sequence window if we got the lowest sequence id
    
    Otherwise we'll never consume sequence id '0'.
    
    metze

commit bd6d415cae550e97e04830eecefa2881b497de89
Author: Stefan Metzmacher <metze at samba.org>
Date:   Mon Jun 25 23:39:37 2012 +0200

    s3:smb2_server: fix calculation of the next bitmap_offset
    
    metze

commit d1ee774ed0b4b3882b4b85da16d9bb9c082a0c49
Author: Stefan Metzmacher <metze at samba.org>
Date:   Mon Jun 25 23:38:32 2012 +0200

    s3:smb2_server: remove unused and confusing DEFAULT_SMB2_MAX_CREDIT_BITMAP_FACTOR
    
    metze

commit 925994e42eba5b72ce605b68e8980adc1b5ecd83
Author: Stefan Metzmacher <metze at samba.org>
Date:   Mon Jun 25 23:14:24 2012 +0200

    s3:smb2_server: call smbd_smb2_request_validate() also in smbd_smb2_first_negprot()
    
    We need to consume message_id 0, for SMB1 negprot starts.
    
    metze

commit 0b8eac9b79197c4659a5738f1b9399b3c88f2f8d
Author: Stefan Metzmacher <metze at samba.org>
Date:   Tue Jun 26 14:23:12 2012 +0200

    s3:smb2_server: start the connection with one credit granted to the client
    
    metze

-----------------------------------------------------------------------

Summary of changes:
 docs-xml/smbdotconf/protocol/servermaxprotocol.xml |    2 +-
 lib/param/param_enums.c                            |    2 +-
 source3/include/local.h                            |    1 -
 source3/param/loadparm.c                           |    2 +-
 source3/smbd/globals.h                             |   46 +++-
 source3/smbd/smb2_negprot.c                        |   13 +-
 source3/smbd/smb2_server.c                         |  328 ++++++++++++++------
 7 files changed, 281 insertions(+), 113 deletions(-)


Changeset truncated at 500 lines:

diff --git a/docs-xml/smbdotconf/protocol/servermaxprotocol.xml b/docs-xml/smbdotconf/protocol/servermaxprotocol.xml
index f91523b..68f2579 100644
--- a/docs-xml/smbdotconf/protocol/servermaxprotocol.xml
+++ b/docs-xml/smbdotconf/protocol/servermaxprotocol.xml
@@ -50,7 +50,7 @@
 		    <para><constant>SMB2_24</constant>: Windows 8 beta SMB2 version.</para>
 		</listitem>
 	    </itemizedlist>
-	    <para>By default SMB2 selects the SMB2_02 variant.</para>
+	    <para>By default SMB2 selects the SMB2_10 variant.</para>
 	</listitem>
 
 	<listitem>
diff --git a/lib/param/param_enums.c b/lib/param/param_enums.c
index baf1696..922b147 100644
--- a/lib/param/param_enums.c
+++ b/lib/param/param_enums.c
@@ -28,7 +28,7 @@
 */
 
 static const struct enum_list enum_protocol[] = {
-	{PROTOCOL_SMB2_02, "SMB2"}, /* for now keep PROTOCOL_SMB2_02 */
+	{PROTOCOL_SMB2_10, "SMB2"}, /* for now keep PROTOCOL_SMB2_10 */
 	{PROTOCOL_SMB3_00, "SMB3"}, /* for now keep PROTOCOL_SMB3_00 */
 	{PROTOCOL_SMB3_00, "SMB3_00"},
 	{PROTOCOL_SMB2_24, "SMB2_24"},
diff --git a/source3/include/local.h b/source3/include/local.h
index 653c671..02e6b43 100644
--- a/source3/include/local.h
+++ b/source3/include/local.h
@@ -236,6 +236,5 @@
 #define DEFAULT_SMB2_MAX_WRITE (1024*1024)
 #define DEFAULT_SMB2_MAX_TRANSACT (1024*1024)
 #define DEFAULT_SMB2_MAX_CREDITS 8192
-#define DEFAULT_SMB2_MAX_CREDIT_BITMAP_FACTOR 2
 
 #endif
diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c
index f9d14cd..ba57553 100644
--- a/source3/param/loadparm.c
+++ b/source3/param/loadparm.c
@@ -4780,7 +4780,7 @@ static void init_globals(bool reinit_globals)
 	Globals.max_log_size = 5000;
 	Globals.max_open_files = max_open_files();
 	Globals.open_files_db_hash_size = SMB_OPEN_DATABASE_TDB_HASH_SIZE;
-	Globals.srv_maxprotocol = PROTOCOL_SMB2_02;
+	Globals.srv_maxprotocol = PROTOCOL_SMB2_10;
 	Globals.srv_minprotocol = PROTOCOL_LANMAN1;
 	Globals.security = SEC_USER;
 	Globals.paranoid_server_security = true;
diff --git a/source3/smbd/globals.h b/source3/smbd/globals.h
index 4cbafe4..b93b373 100644
--- a/source3/smbd/globals.h
+++ b/source3/smbd/globals.h
@@ -641,14 +641,52 @@ struct smbd_server_connection {
 			bool blocking_lock_unlock_state;
 		} locks;
 		struct smbd_smb2_request *requests;
+		/*
+		 * seqnum_low is the lowest sequence number
+		 * we will accept.
+		 */
 		uint64_t seqnum_low;
-		uint32_t credits_granted;
-		uint32_t max_credits;
+		/*
+		 * seqnum_range is the range of credits we have
+		 * granted from the sequence windows starting
+		 * at seqnum_low.
+		 *
+		 * This gets incremented when new credits are
+		 * granted and gets decremented when the
+		 * lowest sequence number is consumed
+		 * (when seqnum_low gets incremented).
+		 */
+		uint16_t seqnum_range;
+		/*
+		 * credits_grantedThe number of credits we have currently granted
+		 * to the client.
+		 *
+		 * This gets incremented when new credits are
+		 * granted and gets decremented when any credit
+		 * is comsumed.
+		 *
+		 * Note: the decrementing is different compared
+		 *       to seqnum_range.
+		 */
+		uint16_t credits_granted;
+		/*
+		 * 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;
+		/*
+		 * a bitmap of size max_credits
+		 */
+		struct bitmap *credits_bitmap;
+		bool supports_multicredit;
 		uint32_t max_trans;
 		uint32_t max_read;
 		uint32_t max_write;
-		bool supports_multicredit;
-		struct bitmap *credits_bitmap;
 		bool compound_related_in_progress;
 	} smb2;
 
diff --git a/source3/smbd/smb2_negprot.c b/source3/smbd/smb2_negprot.c
index d3a709b..c084114 100644
--- a/source3/smbd/smb2_negprot.c
+++ b/source3/smbd/smb2_negprot.c
@@ -261,15 +261,18 @@ NTSTATUS smbd_smb2_request_process_negprot(struct smbd_smb2_request *req)
 	max_limit = 0x10000;
 
 	if (protocol >= PROTOCOL_SMB2_10) {
-		/* largeMTU is only available on port 445 */
-		if (TCP_SMB_PORT ==
-		    tsocket_address_inet_port(req->sconn->local_address))
-		{
+		int p = 0;
 
+		if (tsocket_address_is_inet(req->sconn->local_address, "ip")) {
+			p = tsocket_address_inet_port(req->sconn->local_address);
+		}
+
+		/* largeMTU is not supported over NBT (tcp port 139) */
+		if (p != NBT_SMB_PORT) {
 			capabilities |= SMB2_CAP_LARGE_MTU;
 			req->sconn->smb2.supports_multicredit = true;
 
-			/* SMB2.1 has 1 MB of allowed size */
+			/* SMB >= 2.1 has 1 MB of allowed size */
 			max_limit = 0x100000; /* 1MB */
 		}
 	}
diff --git a/source3/smbd/smb2_server.c b/source3/smbd/smb2_server.c
index de43bcf..c9c6431 100644
--- a/source3/smbd/smb2_server.c
+++ b/source3/smbd/smb2_server.c
@@ -109,10 +109,11 @@ static NTSTATUS smbd_initialize_smb2(struct smbd_server_connection *sconn)
 	}
 
 	sconn->smb2.seqnum_low = 0;
-	sconn->smb2.credits_granted = 0;
+	sconn->smb2.seqnum_range = 1;
+	sconn->smb2.credits_granted = 1;
 	sconn->smb2.max_credits = lp_smb2_max_credits();
 	sconn->smb2.credits_bitmap = bitmap_talloc(sconn,
-			DEFAULT_SMB2_MAX_CREDIT_BITMAP_FACTOR*sconn->smb2.max_credits);
+						   sconn->smb2.max_credits);
 	if (sconn->smb2.credits_bitmap == NULL) {
 		return NT_STATUS_NO_MEMORY;
 	}
@@ -293,54 +294,117 @@ static NTSTATUS smbd_smb2_request_create(struct smbd_server_connection *sconn,
 	return NT_STATUS_OK;
 }
 
-static bool smb2_validate_message_id(struct smbd_server_connection *sconn,
-				const uint8_t *inhdr)
+static bool smb2_validate_sequence_number(struct smbd_server_connection *sconn,
+					  uint64_t message_id, uint64_t seq_id)
 {
-	uint64_t message_id = BVAL(inhdr, SMB2_HDR_MESSAGE_ID);
 	struct bitmap *credits_bm = sconn->smb2.credits_bitmap;
-	uint16_t opcode = IVAL(inhdr, SMB2_HDR_OPCODE);
-	unsigned int bitmap_offset;
-	uint16_t credit_charge = 1;
-	uint64_t i;
+	unsigned int offset;
 
-	if (opcode == SMB2_OP_CANCEL) {
-		/* SMB2_CANCEL requests by definition resend messageids. */
-		return true;
+	if (seq_id < sconn->smb2.seqnum_low) {
+		DEBUG(0,("smb2_validate_sequence_number: bad message_id "
+			"%llu (sequence id %llu) "
+			"(granted = %u, low = %llu, range = %u)\n",
+			(unsigned long long)message_id,
+			(unsigned long long)seq_id,
+			(unsigned int)sconn->smb2.credits_granted,
+			(unsigned long long)sconn->smb2.seqnum_low,
+			(unsigned int)sconn->smb2.seqnum_range));
+		return false;
 	}
 
-	if (message_id < sconn->smb2.seqnum_low ||
-			message_id > (sconn->smb2.seqnum_low +
-			(sconn->smb2.max_credits * DEFAULT_SMB2_MAX_CREDIT_BITMAP_FACTOR))) {
-		DEBUG(0,("smb2_validate_message_id: bad message_id "
-			"%llu (low = %llu, max = %lu)\n",
+	if (seq_id >= sconn->smb2.seqnum_low + sconn->smb2.seqnum_range) {
+		DEBUG(0,("smb2_validate_sequence_number: bad message_id "
+			"%llu (sequence id %llu) "
+			"(granted = %u, low = %llu, range = %u)\n",
 			(unsigned long long)message_id,
+			(unsigned long long)seq_id,
+			(unsigned int)sconn->smb2.credits_granted,
 			(unsigned long long)sconn->smb2.seqnum_low,
-			(unsigned long)sconn->smb2.max_credits ));
+			(unsigned int)sconn->smb2.seqnum_range));
 		return false;
 	}
 
-	if (sconn->smb2.credits_granted == 0) {
-		DEBUG(0,("smb2_validate_message_id: client used more "
-			 "credits than granted, message_id (%llu)\n",
-			 (unsigned long long)message_id));
+	offset = seq_id % sconn->smb2.max_credits;
+
+	if (bitmap_query(credits_bm, offset)) {
+		DEBUG(0,("smb2_validate_sequence_number: duplicate message_id "
+			"%llu (sequence id %llu) "
+			"(granted = %u, low = %llu, range = %u) "
+			"(bm offset %u)\n",
+			(unsigned long long)message_id,
+			(unsigned long long)seq_id,
+			(unsigned int)sconn->smb2.credits_granted,
+			(unsigned long long)sconn->smb2.seqnum_low,
+			(unsigned int)sconn->smb2.seqnum_range,
+			offset));
 		return false;
 	}
 
+	/* Mark the message_ids as seen in the bitmap. */
+	bitmap_set(credits_bm, offset);
+
+	if (seq_id != sconn->smb2.seqnum_low) {
+		return true;
+	}
+
+	/*
+	 * Move the window forward by all the message_id's
+	 * already seen.
+	 */
+	while (bitmap_query(credits_bm, offset)) {
+		DEBUG(10,("smb2_validate_sequence_number: clearing "
+			  "id %llu (position %u) from bitmap\n",
+			  (unsigned long long)(sconn->smb2.seqnum_low),
+			  offset));
+		bitmap_clear(credits_bm, offset);
+
+		sconn->smb2.seqnum_low += 1;
+		sconn->smb2.seqnum_range -= 1;
+		offset = sconn->smb2.seqnum_low % sconn->smb2.max_credits;
+	}
+
+	return true;
+}
+
+static bool smb2_validate_message_id(struct smbd_server_connection *sconn,
+				const uint8_t *inhdr)
+{
+	uint64_t message_id = BVAL(inhdr, SMB2_HDR_MESSAGE_ID);
+	uint16_t opcode = IVAL(inhdr, SMB2_HDR_OPCODE);
+	uint16_t credit_charge = 1;
+	uint64_t i;
+
+	if (opcode == SMB2_OP_CANCEL) {
+		/* SMB2_CANCEL requests by definition resend messageids. */
+		return true;
+	}
+
 	if (sconn->smb2.supports_multicredit) {
 		credit_charge = SVAL(inhdr, SMB2_HDR_CREDIT_CHARGE);
 		credit_charge = MAX(credit_charge, 1);
 	}
 
-	DEBUG(11, ("smb2_validate_message_id: mid %llu, credits_granted %llu, "
-		   "charge %llu, max_credits %llu, seqnum_low: %llu\n",
+	DEBUG(11, ("smb2_validate_message_id: mid %llu (charge %llu), "
+		   "credits_granted %llu, "
+		   "seqnum low/range: %llu/%llu\n",
 		   (unsigned long long) message_id,
-		   (unsigned long long) sconn->smb2.credits_granted,
 		   (unsigned long long) credit_charge,
-		   (unsigned long long) sconn->smb2.max_credits,
-		   (unsigned long long) sconn->smb2.seqnum_low));
-
-	/* substract used credits */
-	sconn->smb2.credits_granted -= credit_charge;
+		   (unsigned long long) sconn->smb2.credits_granted,
+		   (unsigned long long) sconn->smb2.seqnum_low,
+		   (unsigned long long) sconn->smb2.seqnum_range));
+
+	if (sconn->smb2.credits_granted < credit_charge) {
+		DEBUG(0, ("smb2_validate_message_id: client used more "
+			  "credits than granted, mid %llu, charge %llu, "
+			  "credits_granted %llu, "
+			  "seqnum low/range: %llu/%llu\n",
+			  (unsigned long long) message_id,
+			  (unsigned long long) credit_charge,
+			  (unsigned long long) sconn->smb2.credits_granted,
+			  (unsigned long long) sconn->smb2.seqnum_low,
+			  (unsigned long long) sconn->smb2.seqnum_range));
+		return false;
+	}
 
 	/*
 	 * now check the message ids
@@ -350,39 +414,24 @@ static bool smb2_validate_message_id(struct smbd_server_connection *sconn,
 	 * e.g. current mid = 15, charge 5 => mark 15-19 as used
 	 */
 
-	for (i = message_id; i <= (message_id+credit_charge-1); i++) {
+	for (i = 0; i <= (credit_charge-1); i++) {
+		uint64_t id = message_id + i;
+		bool ok;
 
-		DEBUG(11, ("Iterating mid %llu\n", (unsigned long long) i));
+		DEBUG(11, ("Iterating mid %llu charge %u (sequence %llu)\n",
+			   (unsigned long long)message_id,
+			   credit_charge,
+			   (unsigned long long)id));
 
-		/* Mark the message_ids as seen in the bitmap. */
-		bitmap_offset = (unsigned int)(i %
-				(uint64_t)(sconn->smb2.max_credits *
-					DEFAULT_SMB2_MAX_CREDIT_BITMAP_FACTOR));
-		if (bitmap_query(credits_bm, bitmap_offset)) {
-			DEBUG(0,("smb2_validate_message_id: duplicate "
-				 "message_id %llu (bm offset %u)\n",
-				 (unsigned long long)i, bitmap_offset));
+		ok = smb2_validate_sequence_number(sconn, message_id, id);
+		if (!ok) {
 			return false;
 		}
-		bitmap_set(credits_bm, bitmap_offset);
-
-		if (i == sconn->smb2.seqnum_low + 1) {
-			/* Move the window forward by all the message_id's
-			   already seen. */
-			while (bitmap_query(credits_bm, bitmap_offset)) {
-				DEBUG(10,("smb2_validate_message_id: clearing "
-					  "id %llu (position %u) from bitmap\n",
-					  (unsigned long long)(sconn->smb2.seqnum_low + 1),
-					  bitmap_offset));
-				bitmap_clear(credits_bm, bitmap_offset);
-				sconn->smb2.seqnum_low += 1;
-				bitmap_offset = (bitmap_offset + 1) %
-					(sconn->smb2.max_credits *
-					 DEFAULT_SMB2_MAX_CREDIT_BITMAP_FACTOR);
-			}
-		}
 	}
 
+	/* substract used credits */
+	sconn->smb2.credits_granted -= credit_charge;
+
 	return true;
 }
 
@@ -475,14 +524,44 @@ static void smb2_set_operation_credit(struct smbd_server_connection *sconn,
 {
 	const uint8_t *inhdr = (const uint8_t *)in_vector->iov_base;
 	uint8_t *outhdr = (uint8_t *)out_vector->iov_base;
+	uint16_t credit_charge = 1;
 	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);
+
+	if (sconn->smb2.supports_multicredit) {
+		credit_charge = SVAL(inhdr, SMB2_HDR_CREDIT_CHARGE);
+		credit_charge = MAX(credit_charge, 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);
+	SMB_ASSERT(sconn->smb2.max_credits >= credit_charge);
 
 	if (out_flags & SMB2_HDR_FLAG_ASYNC) {
 		/*
@@ -490,48 +569,84 @@ static void smb2_set_operation_credit(struct smbd_server_connection *sconn,
 		 * response, we should not grant
 		 * credits on the final response.
 		 */
-		credits_requested = 0;
-	}
+		credits_granted = 0;
+	} else if (credits_requested > 0) {
+		uint16_t additional_max = 0;
+		uint16_t additional_credits = 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;
+		}
 
-	if (credits_requested) {
-		uint16_t modified_credits_requested;
-		uint32_t multiplier;
+		additional_credits = MIN(additional_credits, additional_max);
 
+		credits_granted = credit_charge + additional_credits;
+	} else if (sconn->smb2.credits_granted == 0) {
 		/*
-		 * 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.
+		 * Make sure the client has always at least one credit
 		 */
-
-		multiplier = 16 - (((sconn->smb2.credits_granted * 16) / sconn->smb2.max_credits) % 16);
-
-		modified_credits_requested = (multiplier * credits_requested) / 16;
-		if (modified_credits_requested == 0) {
-			modified_credits_requested = 1;
-		}
-
-		/* Remember what we gave out. */
-		credits_granted = MIN(modified_credits_requested,
-					(sconn->smb2.max_credits - sconn->smb2.credits_granted));
+		credits_granted = 1;
 	}
 
-	if (credits_granted == 0 && sconn->smb2.credits_granted == 0) {
-		/* First negprot packet, or ensure the client credits can
-		   never drop to zero. */
-		credits_granted = 1;
+	/*
+	 * sequence numbers should not wrap
+	 *
+	 * 1. calculate the possible credits until
+	 *    the sequence numbers start to wrap on 64-bit.
+	 *
+	 * 2. UINT64_MAX is used for Break Notifications.
+	 *
+	 * 2. truncate the possible credits to the maximum
+	 *    credits we want to grant to the client in total.
+	 *
+	 * 3. remove the range we'll already granted to the client
+	 *    this makes sure the client consumes the lowest sequence
+	 *    number, before we can grant additional credits.
+	 */
+	credits_possible = UINT64_MAX - sconn->smb2.seqnum_low;
+	if (credits_possible > 0) {
+		/* remove UINT64_MAX */
+		credits_possible -= 1;
 	}
+	credits_possible = MIN(credits_possible, current_max_credits);
+	credits_possible -= sconn->smb2.seqnum_range;
+
+	credits_granted = MIN(credits_granted, credits_possible);
 
 	SSVAL(outhdr, SMB2_HDR_CREDIT, credits_granted);
 	sconn->smb2.credits_granted += credits_granted;
+	sconn->smb2.seqnum_range += credits_granted;
 
-	DEBUG(10,("smb2_set_operation_credit: requested %u, "
-		"granted %u, total granted %u\n",
+	DEBUG(10,("smb2_set_operation_credit: requested %u, charge %u, "
+		"granted %u, current possible/max %u/%u, "


-- 
Samba Shared Repository


More information about the samba-cvs mailing list