goto done; \
}} while (0)
+#define CHECK_VAL_GREATER_THAN(v, gt_val) do { \
+ if ((v) <= (gt_val)) { \
+ torture_result(tctx, TORTURE_FAIL, "(%s): wrong value for %s got 0x%x - should be greater than 0x%x\n", \
+ __location__, #v, (int)v, (int)gt_val); \
+ ret = false; \
+ goto done; \
+ }} while (0)
+
+
#define CHECK_CREATED(__io, __created, __attribute) \
do { \
CHECK_VAL((__io)->out.create_action, NTCREATEX_ACTION_ ## __created); \
* open file1 in 2A
* open file2 in 2B
* open file1 in session 1
- * oplock break received on 2C(last opened channel)
- * block 2C
+ * oplock break received
+ * block channel on which oplock break received
* open file2 in session 1
- * oplock break never received
- * file allowed to be open after ~ 30 secs
+ * oplock break not received. Retry received.
+ * file opened
* write to file2 on 2B
* Break sent to session 1(which has file2 open)
+ * Break sent to session 2A(which has read oplock)
* close file1 in session 1
* open file1 with session 1
- * unblock 2C
- * disconnect 2C
- * reconnect 2C
- * open file3 in 2C
+ * unblock blocked channel
+ * disconnect blocked channel
+ * connect channel 2D
+ * open file3 in 2D
* open file3 in session 1
- * receive break on 2C
+ * receive break
*/
static bool test_multichannel_oplock_break_test2(struct torture_context *tctx,
struct smb2_tree *tree1)
struct smb2_tree *tree2A = NULL;
struct smb2_tree *tree2B = NULL;
struct smb2_tree *tree2C = NULL;
+ struct smb2_tree *tree2D = NULL;
struct smb2_transport *transport1 = tree1->session->transport;
- struct smb2_transport *transport2C = NULL;
+ struct smb2_transport *transport2 = NULL;
struct smbcli_options transport2_options;
struct smb2_session *session1 = tree1->session;
uint16_t local_port = 0;
&transport2_options,
&tree2A, &tree2B, &tree2C);
CHECK_VAL(rval, 0);
- transport2C = tree2C->session->transport;
torture_comment(tctx, "client2 opens fname1 via session 2A\n");
io1.in.oplock_level = smb2_util_oplock_level("b");
CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("s"));
torture_wait_for_oplock_break(tctx);
CHECK_VAL(break_info.count, 1);
- //CHECK_PTR(break_info.received_transport, transport2C);
+ /* We use the transport over which this oplock break was received */
+ transport2 = break_info.received_transport;
torture_reset_break_info(tctx, &break_info);
- block_ok = torture_block_tcp_transport(tctx, transport2C);
+ /* block transport which is used by the server for oplock breaks */
+ block_ok = torture_block_tcp_transport(tctx, transport2);
torture_assert(tctx, block_ok, "we could not block tcp transport");
torture_comment(tctx, "client1 opens fname2 via session 1\n");
CHECK_VAL(io2.out.oplock_level, smb2_util_oplock_level("s"));
/*
- * Important: when filtered, Windows will really let the open succeed
- * and *NOT* send a new oplock break over the remaining channels, thus
- * the break info count stays at zero.
+ * Samba downgrades oplock to a level 2 oplock.
+ * Windows 2016 revokes oplock
*/
-
torture_wait_for_oplock_break(tctx);
- CHECK_VAL(break_info.count, 0);
-
+ CHECK_VAL(break_info.count, 1);
torture_reset_break_info(tctx, &break_info);
- blob = data_blob_string_const("Here I am");
-
torture_comment(tctx, "Trying write to file2 on tree2B\n");
+ blob = data_blob_string_const("Here I am");
status = smb2_util_write(tree2B,
h_client2_file2,
blob.data,
torture_assert_ntstatus_ok(tctx, status,
"failed to write file2 via channel 2B");
- /* Write above triggers oplock break for session 1 which has file2 open */
+ /*
+ * Samba: Write triggers 2 oplock breaks
+ * for session 1 which has file2 open
+ * for session 2 which has type 2 oplock
+ * Windows 2016: Only one oplock break for session 1
+ */
torture_wait_for_oplock_break(tctx);
- CHECK_VAL(break_info.count, 1);
- //CHECK_PTR(break_info.received_transport, transport1);
+ CHECK_VAL_GREATER_THAN(break_info.count, 0);
torture_reset_break_info(tctx, &break_info);
torture_comment(tctx, "client1 closes fname2 via session 1\n");
CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
CHECK_VAL(io2.out.oplock_level, smb2_util_oplock_level("s"));
- unblock_ok = torture_unblock_tcp_transport(tctx, transport2C);
+ unblock_ok = torture_unblock_tcp_transport(tctx, transport2);
torture_assert(tctx, unblock_ok, "we could not unblock tcp transport");
- /* disconnect 2C */
- torture_comment(tctx, "explicit disconnect of transport2C\n");
- smbXcli_conn_disconnect(transport2C->conn, NT_STATUS_FOOBAR);
+ /* disconnect transport2 */
+ torture_comment(tctx, "explicit disconnect of transport2\n");
+ smbXcli_conn_disconnect(transport2->conn, NT_STATUS_FOOBAR);
/*
- * now add a third channel and repeat the test, we need to reestablish
- * transport2C because the remote end has invalidated our connection
+ * now add a fourth channel and repeat the test, we need to reestablish
+ * transport2 because the remote end has invalidated our connection
*/
- torture_comment(tctx, "Reconnecting session 2C\n");
- talloc_free(tree2C);
- tree2C = test_multichannel_create_channel(tctx, host, share,
- credentials, &transport2_options, tree2A);
- if (!tree2C)
+ torture_comment(tctx, "Connecting session 2D\n");
+ tree2D = test_multichannel_create_channel(tctx, host, share,
+ credentials, &transport2_options, tree2B);
+ if (!tree2D)
goto done;
- transport2C = tree2C->session->transport;
+ transport2 = tree2D->session->transport;
- torture_comment(tctx, "client 2 opening fname3 over newly established transport2C\n");
- status = smb2_create(tree2C, mem_ctx, &io3);
+ torture_comment(tctx, "client 2 opening fname3 over transport2D\n");
+ status = smb2_create(tree2D, mem_ctx, &io3);
CHECK_STATUS(status, NT_STATUS_OK);
h_client2_file3 = io3.out.file.handle;
CHECK_CREATED(&io3, CREATED, FILE_ATTRIBUTE_ARCHIVE);
CHECK_VAL(io3.out.oplock_level, smb2_util_oplock_level("s"));
torture_wait_for_oplock_break(tctx);
CHECK_VAL(break_info.count, 1);
- //CHECK_PTR(break_info.received_transport, transport2C);
done:
if (block_ok && !unblock_ok) {
- /* unblock tcp connection of transport2C */
- unblock_ok = torture_unblock_tcp_transport(tctx, transport2C);
+ /* unblock tcp connection of transport2 */
+ unblock_ok = torture_unblock_tcp_transport(tctx, transport2);
}
tree1->session = session1;
smb2_util_close(tree1, h_client1_file1);
smb2_util_close(tree1, h_client1_file2);
smb2_util_close(tree1, h_client1_file3);
- if (tree2A != NULL) {
- smb2_util_close(tree2A, h_client2_file1);
- smb2_util_close(tree2A, h_client2_file2);
- smb2_util_close(tree2A, h_client2_file3);
+ if (tree2B != NULL) {
+ smb2_util_close(tree2B, h_client2_file1);
+ smb2_util_close(tree2B, h_client2_file2);
+ smb2_util_close(tree2B, h_client2_file3);
}
smb2_util_unlink(tree1, fname1);
smb2_deltree(tree1, BASEDIR);
test_multichannel_free_channels2(tree2A, tree2B, tree2C);
+ if (tree2D != NULL)
+ TALLOC_FREE(tree2D);
talloc_free(tree1);
talloc_free(mem_ctx);