LCOV - code coverage report
Current view: top level - source4/torture/smb2 - multichannel.c (source / functions) Hit Total Coverage
Test: coverage report for master 6248eab5 Lines: 1194 1241 96.2 %
Date: 2021-08-25 13:27:56 Functions: 21 21 100.0 %

          Line data    Source code
       1             : /*
       2             :  * Unix SMB/CIFS implementation.
       3             :  *
       4             :  * test SMB2 multichannel operations
       5             :  *
       6             :  * Copyright (C) Guenther Deschner, 2016
       7             :  *
       8             :  * This program is free software; you can redistribute it and/or modify
       9             :  * it under the terms of the GNU General Public License as published by
      10             :  * the Free Software Foundation; either version 3 of the License, or
      11             :  * (at your option) any later version.
      12             :  *
      13             :  * This program is distributed in the hope that it will be useful,
      14             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16             :  * GNU General Public License for more details.
      17             :  *
      18             :  * You should have received a copy of the GNU General Public License
      19             :  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
      20             :  */
      21             : 
      22             : #include "includes.h"
      23             : #include "libcli/smb2/smb2.h"
      24             : #include "libcli/smb2/smb2_calls.h"
      25             : #include "torture/torture.h"
      26             : #include "torture/smb2/proto.h"
      27             : #include "libcli/security/security.h"
      28             : #include "librpc/gen_ndr/ndr_security.h"
      29             : #include "librpc/gen_ndr/ndr_ioctl.h"
      30             : #include "../libcli/smb/smbXcli_base.h"
      31             : #include "lib/cmdline/cmdline.h"
      32             : #include "libcli/security/security.h"
      33             : #include "libcli/resolve/resolve.h"
      34             : #include "lib/param/param.h"
      35             : #include "lib/events/events.h"
      36             : #include "oplock_break_handler.h"
      37             : #include "lease_break_handler.h"
      38             : #include "torture/smb2/block.h"
      39             : 
      40             : #define BASEDIR "multichanneltestdir"
      41             : 
      42             : #define CHECK_STATUS(status, correct) \
      43             :         torture_assert_ntstatus_equal_goto(tctx, status, correct,\
      44             :                                            ret, done, "")
      45             : 
      46             : #define CHECK_VAL(v, correct) do { \
      47             :         if ((v) != (correct)) { \
      48             :                 torture_result(tctx, TORTURE_FAIL, "(%s): wrong value for %s" \
      49             :                                 " got 0x%x - should be 0x%x\n", \
      50             :                                 __location__, #v, (int)v, (int)correct); \
      51             :                 ret = false; \
      52             :                 goto done; \
      53             :         } } while (0)
      54             : 
      55             : #define CHECK_VAL_GREATER_THAN(v, gt_val) do { \
      56             :         if ((v) <= (gt_val)) { \
      57             :                 torture_result(tctx, TORTURE_FAIL, \
      58             :                                 "(%s): wrong value for %s got 0x%x - " \
      59             :                                 "should be greater than 0x%x\n", \
      60             :                                 __location__, #v, (int)v, (int)gt_val); \
      61             :                 ret = false; \
      62             :                 goto done; \
      63             :         } } while (0)
      64             : 
      65             : #define CHECK_CREATED(__io, __created, __attribute)                     \
      66             :         do {                                                            \
      67             :                 CHECK_VAL((__io)->out.create_action,                 \
      68             :                                 NTCREATEX_ACTION_ ## __created);        \
      69             :                 CHECK_VAL((__io)->out.alloc_size, 0);                        \
      70             :                 CHECK_VAL((__io)->out.size, 0);                              \
      71             :                 CHECK_VAL((__io)->out.file_attr, (__attribute));     \
      72             :                 CHECK_VAL((__io)->out.reserved2, 0);                 \
      73             :         } while (0)
      74             : 
      75             : #define CHECK_PTR(ptr, correct) do { \
      76             :         if ((ptr) != (correct)) { \
      77             :                 torture_result(tctx, TORTURE_FAIL, "(%s): wrong value for %s " \
      78             :                                 "got 0x%p - should be 0x%p\n", \
      79             :                                 __location__, #ptr, ptr, correct); \
      80             :                 ret = false; \
      81             :                 goto done; \
      82             :         } } while (0)
      83             : 
      84             : #define CHECK_LEASE(__io, __state, __oplevel, __key, __flags)           \
      85             :         do {                                                            \
      86             :                 CHECK_VAL((__io)->out.lease_response.lease_version, 1); \
      87             :                 if (__oplevel) {                                        \
      88             :                         CHECK_VAL((__io)->out.oplock_level, \
      89             :                                         SMB2_OPLOCK_LEVEL_LEASE); \
      90             :                         CHECK_VAL((__io)->out.lease_response.lease_key.data[0],\
      91             :                                   (__key)); \
      92             :                         CHECK_VAL((__io)->out.lease_response.lease_key.data[1],\
      93             :                                   ~(__key)); \
      94             :                         CHECK_VAL((__io)->out.lease_response.lease_state,\
      95             :                                   smb2_util_lease_state(__state)); \
      96             :                 } else {                                                \
      97             :                         CHECK_VAL((__io)->out.oplock_level,\
      98             :                                   SMB2_OPLOCK_LEVEL_NONE); \
      99             :                         CHECK_VAL((__io)->out.lease_response.lease_key.data[0],\
     100             :                                   0); \
     101             :                         CHECK_VAL((__io)->out.lease_response.lease_key.data[1],\
     102             :                                   0); \
     103             :                         CHECK_VAL((__io)->out.lease_response.lease_state, 0); \
     104             :                 }                                                       \
     105             :                                                                         \
     106             :                 CHECK_VAL((__io)->out.lease_response.lease_flags, (__flags)); \
     107             :                 CHECK_VAL((__io)->out.lease_response.lease_duration, 0); \
     108             :                 CHECK_VAL((__io)->out.lease_response.lease_epoch, 0); \
     109             :         } while (0)
     110             : 
     111             : #define CHECK_LEASE_V2(__io, __state, __oplevel, __key, __flags, __parent, __epoch) \
     112             :         do {                                                            \
     113             :                 CHECK_VAL((__io)->out.lease_response_v2.lease_version, 2); \
     114             :                 if (__oplevel) {                                        \
     115             :                         CHECK_VAL((__io)->out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE); \
     116             :                         CHECK_VAL((__io)->out.lease_response_v2.lease_key.data[0], (__key)); \
     117             :                         CHECK_VAL((__io)->out.lease_response_v2.lease_key.data[1], ~(__key)); \
     118             :                         CHECK_VAL((__io)->out.lease_response_v2.lease_state, smb2_util_lease_state(__state)); \
     119             :                 } else {                                                \
     120             :                         CHECK_VAL((__io)->out.oplock_level, SMB2_OPLOCK_LEVEL_NONE); \
     121             :                         CHECK_VAL((__io)->out.lease_response_v2.lease_key.data[0], 0); \
     122             :                         CHECK_VAL((__io)->out.lease_response_v2.lease_key.data[1], 0); \
     123             :                         CHECK_VAL((__io)->out.lease_response_v2.lease_state, 0); \
     124             :                 }                                                       \
     125             :                                                                         \
     126             :                 CHECK_VAL((__io)->out.lease_response_v2.lease_flags, __flags); \
     127             :                 if (__flags & SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET) { \
     128             :                         CHECK_VAL((__io)->out.lease_response_v2.parent_lease_key.data[0], (__parent)); \
     129             :                         CHECK_VAL((__io)->out.lease_response_v2.parent_lease_key.data[1], ~(__parent)); \
     130             :                 } \
     131             :                 CHECK_VAL((__io)->out.lease_response_v2.lease_duration, 0); \
     132             :                 CHECK_VAL((__io)->out.lease_response_v2.lease_epoch, (__epoch)); \
     133             :         } while(0)
     134             : 
     135             : #define CHECK_LEASE_BREAK_V2(__lb, __key, __from, __to, __break_flags, __new_epoch) \
     136             :         do {                                                            \
     137             :                 CHECK_VAL((__lb).current_lease.lease_key.data[0], (__key)); \
     138             :                 CHECK_VAL((__lb).current_lease.lease_key.data[1], ~(__key)); \
     139             :                 CHECK_VAL((__lb).current_lease.lease_state, smb2_util_lease_state(__from)); \
     140             :                 CHECK_VAL((__lb).new_epoch, (__new_epoch)); \
     141             :                 CHECK_VAL((__lb).break_flags, (__break_flags)); \
     142             :                 CHECK_VAL((__lb).new_lease_state, smb2_util_lease_state(__to)); \
     143             :         } while(0)
     144             : 
     145          36 : static bool test_ioctl_network_interface_info(struct torture_context *tctx,
     146             :                                               struct smb2_tree *tree,
     147             :                                               struct fsctl_net_iface_info *info)
     148             : {
     149             :         union smb_ioctl ioctl;
     150             :         struct smb2_handle fh;
     151             :         uint32_t caps;
     152             : 
     153          36 :         caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
     154          36 :         if (!(caps & SMB2_CAP_MULTI_CHANNEL)) {
     155           0 :                 torture_skip(tctx,
     156             :                             "server doesn't support SMB2_CAP_MULTI_CHANNEL\n");
     157             :         }
     158             : 
     159          36 :         ZERO_STRUCT(ioctl);
     160             : 
     161          36 :         ioctl.smb2.level = RAW_IOCTL_SMB2;
     162             : 
     163          36 :         fh.data[0] = UINT64_MAX;
     164          36 :         fh.data[1] = UINT64_MAX;
     165             : 
     166          36 :         ioctl.smb2.in.file.handle = fh;
     167          36 :         ioctl.smb2.in.function = FSCTL_QUERY_NETWORK_INTERFACE_INFO;
     168             :         /* Windows client sets this to 64KiB */
     169          36 :         ioctl.smb2.in.max_output_response = 0x10000;
     170          36 :         ioctl.smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL;
     171             : 
     172          36 :         torture_assert_ntstatus_ok(tctx,
     173             :                 smb2_ioctl(tree, tctx, &ioctl.smb2),
     174             :                 "FSCTL_QUERY_NETWORK_INTERFACE_INFO failed");
     175             : 
     176          36 :         torture_assert(tctx,
     177             :                 (ioctl.smb2.out.out.length != 0),
     178             :                 "no interface info returned???");
     179             : 
     180          36 :         torture_assert_ndr_success(tctx,
     181             :                 ndr_pull_struct_blob(&ioctl.smb2.out.out, tctx, info,
     182             :                         (ndr_pull_flags_fn_t)ndr_pull_fsctl_net_iface_info),
     183             :                 "failed to ndr pull");
     184             : 
     185          36 :         if (DEBUGLVL(1)) {
     186          36 :                 NDR_PRINT_DEBUG(fsctl_net_iface_info, info);
     187             :         }
     188             : 
     189          36 :         return true;
     190             : }
     191             : 
     192           4 : static bool test_multichannel_interface_info(struct torture_context *tctx,
     193             :                                              struct smb2_tree *tree)
     194             : {
     195             :         struct fsctl_net_iface_info info;
     196             : 
     197           4 :         return test_ioctl_network_interface_info(tctx, tree, &info);
     198             : }
     199             : 
     200         436 : static struct smb2_tree *test_multichannel_create_channel(
     201             :                                 struct torture_context *tctx,
     202             :                                 const char *host,
     203             :                                 const char *share,
     204             :                                 struct cli_credentials *credentials,
     205             :                                 const struct smbcli_options *_transport_options,
     206             :                                 struct smb2_tree *parent_tree
     207             :                                 )
     208             : {
     209         436 :         struct smbcli_options transport_options = *_transport_options;
     210             :         NTSTATUS status;
     211             :         struct smb2_transport *transport;
     212             :         struct smb2_session *session;
     213         436 :         bool ret = true;
     214             :         struct smb2_tree *tree;
     215             : 
     216         436 :         if (parent_tree) {
     217         404 :                 transport_options.only_negprot = true;
     218             :         }
     219             : 
     220         436 :         status = smb2_connect(tctx,
     221             :                         host,
     222             :                         lpcfg_smb_ports(tctx->lp_ctx),
     223             :                         share,
     224             :                         lpcfg_resolve_context(tctx->lp_ctx),
     225             :                         credentials,
     226             :                         &tree,
     227             :                         tctx->ev,
     228             :                         &transport_options,
     229             :                         lpcfg_socket_options(tctx->lp_ctx),
     230             :                         lpcfg_gensec_settings(tctx, tctx->lp_ctx)
     231             :                         );
     232         436 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     233             :                         "smb2_connect failed");
     234         436 :         transport = tree->session->transport;
     235         436 :         transport->oplock.handler = torture_oplock_ack_handler;
     236         436 :         transport->oplock.private_data = tree;
     237         436 :         transport->lease.handler = torture_lease_handler;
     238         436 :         transport->lease.private_data = tree;
     239         436 :         torture_comment(tctx, "established transport [%p]\n", transport);
     240             : 
     241             :         /*
     242             :          * If parent tree is set, bind the session to the parent transport
     243             :          */
     244         436 :         if (parent_tree) {
     245         404 :                 session = smb2_session_channel(transport,
     246             :                                 lpcfg_gensec_settings(tctx, tctx->lp_ctx),
     247             :                                 parent_tree, parent_tree->session);
     248         404 :                 torture_assert_goto(tctx, session != NULL, ret, done,
     249             :                                 "smb2_session_channel failed");
     250             : 
     251         404 :                 tree->smbXcli = parent_tree->smbXcli;
     252         404 :                 tree->session = session;
     253         404 :                 status = smb2_session_setup_spnego(session,
     254             :                                                 credentials,
     255             :                                                 0 /* previous_session_id */);
     256         404 :                 CHECK_STATUS(status, NT_STATUS_OK);
     257         404 :                 torture_comment(tctx, "bound new session to parent\n");
     258             :         }
     259             :         /*
     260             :          * We absolutely need to make sure to send something over this
     261             :          * connection to register the oplock break handler with the smb client
     262             :          * connection. If we do not send something (at least a keepalive), we
     263             :          * will *NEVER* receive anything over this transport.
     264             :          */
     265         436 :         smb2_keepalive(transport);
     266             : 
     267         436 : done:
     268         436 :         if (ret) {
     269         436 :                 return tree;
     270             :         } else {
     271           0 :                 return NULL;
     272             :         }
     273             : }
     274             : 
     275          32 : bool test_multichannel_create_channel_array(
     276             :                                 struct torture_context *tctx,
     277             :                                 const char *host,
     278             :                                 const char *share,
     279             :                                 struct cli_credentials *credentials,
     280             :                                 struct smbcli_options *transport_options,
     281             :                                 uint8_t num_trees,
     282             :                                 struct smb2_tree **trees)
     283             : {
     284             :         uint8_t i;
     285             : 
     286          32 :         transport_options->client_guid = GUID_random();
     287             : 
     288         464 :         for (i = 0; i < num_trees; i++) {
     289         432 :                 struct smb2_tree *parent_tree = NULL;
     290         432 :                 struct smb2_tree *tree = NULL;
     291         432 :                 struct smb2_transport *transport = NULL;
     292         432 :                 uint16_t local_port = 0;
     293             : 
     294         432 :                 if (i > 0) {
     295         400 :                         parent_tree = trees[0];
     296             :                 }
     297             : 
     298         432 :                 torture_comment(tctx, "Setting up connection %d\n", i);
     299         432 :                 tree = test_multichannel_create_channel(tctx, host, share,
     300             :                                         credentials, transport_options,
     301             :                                         parent_tree);
     302         432 :                 torture_assert(tctx, tree, "failed to created new channel");
     303             : 
     304         432 :                 trees[i] = tree;
     305         432 :                 transport = tree->session->transport;
     306         432 :                 local_port = torture_get_local_port_from_transport(transport);
     307         432 :                 torture_comment(tctx, "transport[%d] uses tcp port: %d\n",
     308             :                                 i, local_port);
     309             :         }
     310             : 
     311          32 :         return true;
     312             : }
     313             : 
     314          20 : bool test_multichannel_create_channels(
     315             :                                 struct torture_context *tctx,
     316             :                                 const char *host,
     317             :                                 const char *share,
     318             :                                 struct cli_credentials *credentials,
     319             :                                 struct smbcli_options *transport_options,
     320             :                                 struct smb2_tree **tree2A,
     321             :                                 struct smb2_tree **tree2B,
     322             :                                 struct smb2_tree **tree2C
     323             :                                 )
     324             : {
     325          20 :         struct smb2_tree **trees = NULL;
     326          20 :         size_t num_trees = 0;
     327             :         bool ret;
     328             : 
     329          20 :         torture_assert(tctx, tree2A, "tree2A required!");
     330          20 :         num_trees += 1;
     331          20 :         torture_assert(tctx, tree2B, "tree2B required!");
     332          20 :         num_trees += 1;
     333          20 :         if (tree2C != NULL) {
     334           8 :                 num_trees += 1;
     335             :         }
     336          20 :         trees = talloc_zero_array(tctx, struct smb2_tree *, num_trees);
     337          20 :         torture_assert(tctx, trees, "out of memory");
     338             : 
     339          20 :         ret = test_multichannel_create_channel_array(tctx, host, share, credentials,
     340             :                                                      transport_options,
     341             :                                                      num_trees, trees);
     342          20 :         if (!ret) {
     343           0 :                 return false;
     344             :         }
     345             : 
     346          20 :         *tree2A = trees[0];
     347          20 :         *tree2B = trees[1];
     348          20 :         if (tree2C != NULL) {
     349           8 :                 *tree2C = trees[2];
     350             :         }
     351             : 
     352          20 :         return true;
     353             : }
     354             : 
     355          28 : static void test_multichannel_free_channels(struct smb2_tree *tree2A,
     356             :                                              struct smb2_tree *tree2B,
     357             :                                              struct smb2_tree *tree2C)
     358             : {
     359          28 :         TALLOC_FREE(tree2A);
     360          28 :         TALLOC_FREE(tree2B);
     361          28 :         TALLOC_FREE(tree2C);
     362          28 : }
     363             : 
     364          32 : static bool test_multichannel_initial_checks(struct torture_context *tctx,
     365             :                                              struct smb2_tree *tree1)
     366             : {
     367          32 :         struct smb2_transport *transport1 = tree1->session->transport;
     368             :         uint32_t server_capabilities;
     369             :         struct fsctl_net_iface_info info;
     370             : 
     371          32 :         if (smbXcli_conn_protocol(transport1->conn) < PROTOCOL_SMB3_00) {
     372           0 :                 torture_skip_goto(tctx, fail,
     373             :                                   "SMB 3.X Dialect family required for "
     374             :                                   "Multichannel tests\n");
     375             :         }
     376             : 
     377          32 :         server_capabilities = smb2cli_conn_server_capabilities(
     378          32 :                                         tree1->session->transport->conn);
     379          32 :         if (!(server_capabilities & SMB2_CAP_MULTI_CHANNEL)) {
     380           0 :                 torture_skip_goto(tctx, fail,
     381             :                              "Server does not support multichannel.");
     382             :         }
     383             : 
     384          32 :         torture_assert(tctx,
     385             :                 test_ioctl_network_interface_info(tctx, tree1, &info),
     386             :                 "failed to retrieve network interface info");
     387             : 
     388          32 :         return true;
     389           0 : fail:
     390           0 :         return false;
     391             : }
     392             : 
     393          52 : static void test_multichannel_init_smb_create(struct smb2_create *io)
     394             : {
     395          52 :         io->in.durable_open = false;
     396          52 :         io->in.durable_open_v2 = true;
     397          52 :         io->in.persistent_open = false;
     398          52 :         io->in.create_guid = GUID_random();
     399          52 :         io->in.timeout = 0x493E0; /* 300000 */
     400             :         /* windows 2016 returns 300000 0x493E0 */
     401          52 : }
     402             : 
     403             : /* Timer handler function notifies the registering function that time is up */
     404           2 : static void timeout_cb(struct tevent_context *ev,
     405             :                        struct tevent_timer *te,
     406             :                        struct timeval current_time,
     407             :                        void *private_data)
     408             : {
     409           2 :         bool *timesup = (bool *)private_data;
     410           2 :         *timesup = true;
     411           2 : }
     412             : 
     413             : /*
     414             :  * Oplock break - Test 1
     415             :  * Test to confirm that server sends oplock breaks as expected.
     416             :  * open file1 in session 2A
     417             :  * open file2 in session 2B
     418             :  * open file1 in session 1
     419             :  *      oplock break received
     420             :  * open file1 in session 1
     421             :  *      oplock break received
     422             :  * Cleanup
     423             :  */
     424           4 : static bool test_multichannel_oplock_break_test1(struct torture_context *tctx,
     425             :                                            struct smb2_tree *tree1)
     426             : {
     427           4 :         const char *host = torture_setting_string(tctx, "host", NULL);
     428           4 :         const char *share = torture_setting_string(tctx, "share", NULL);
     429           4 :         struct cli_credentials *credentials = samba_cmdline_get_creds();
     430             :         NTSTATUS status;
     431           4 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
     432             :         struct smb2_handle _h;
     433           4 :         struct smb2_handle h_client1_file1 = {{0}};
     434           4 :         struct smb2_handle h_client1_file2 = {{0}};
     435           4 :         struct smb2_handle h_client1_file3 = {{0}};
     436           4 :         struct smb2_handle h_client2_file1 = {{0}};
     437           4 :         struct smb2_handle h_client2_file2 = {{0}};
     438           4 :         struct smb2_handle h_client2_file3 = {{0}};
     439             :         struct smb2_create io1, io2, io3;
     440           4 :         bool ret = true;
     441           4 :         const char *fname1 = BASEDIR "\\oplock_break_test1.dat";
     442           4 :         const char *fname2 = BASEDIR "\\oplock_break_test2.dat";
     443           4 :         const char *fname3 = BASEDIR "\\oplock_break_test3.dat";
     444           4 :         struct smb2_tree *tree2A = NULL;
     445           4 :         struct smb2_tree *tree2B = NULL;
     446           4 :         struct smb2_tree *tree2C = NULL;
     447           4 :         struct smb2_transport *transport1 = tree1->session->transport;
     448             :         struct smbcli_options transport2_options;
     449           4 :         struct smb2_session *session1 = tree1->session;
     450           4 :         uint16_t local_port = 0;
     451             : 
     452           4 :         if (!test_multichannel_initial_checks(tctx, tree1)) {
     453           0 :                 return true;
     454             :         }
     455             : 
     456           4 :         torture_comment(tctx, "Oplock break retry: Test1\n");
     457             : 
     458           4 :         torture_reset_break_info(tctx, &break_info);
     459             : 
     460           4 :         transport1->oplock.handler = torture_oplock_ack_handler;
     461           4 :         transport1->oplock.private_data = tree1;
     462           4 :         torture_comment(tctx, "transport1  [%p]\n", transport1);
     463           4 :         local_port = torture_get_local_port_from_transport(transport1);
     464           4 :         torture_comment(tctx, "transport1 uses tcp port: %d\n", local_port);
     465             : 
     466           4 :         status = torture_smb2_testdir(tree1, BASEDIR, &_h);
     467           4 :         CHECK_STATUS(status, NT_STATUS_OK);
     468           4 :         smb2_util_close(tree1, _h);
     469           4 :         smb2_util_unlink(tree1, fname1);
     470           4 :         smb2_util_unlink(tree1, fname2);
     471           4 :         smb2_util_unlink(tree1, fname3);
     472           4 :         CHECK_VAL(break_info.count, 0);
     473             : 
     474           4 :         smb2_oplock_create_share(&io1, fname1,
     475             :                         smb2_util_share_access("RWD"),
     476           4 :                         smb2_util_oplock_level("b"));
     477           4 :         test_multichannel_init_smb_create(&io1);
     478             : 
     479           4 :         smb2_oplock_create_share(&io2, fname2,
     480             :                         smb2_util_share_access("RWD"),
     481           4 :                         smb2_util_oplock_level("b"));
     482           4 :         test_multichannel_init_smb_create(&io2);
     483             : 
     484           4 :         smb2_oplock_create_share(&io3, fname3,
     485             :                         smb2_util_share_access("RWD"),
     486           4 :                         smb2_util_oplock_level("b"));
     487           4 :         test_multichannel_init_smb_create(&io3);
     488             : 
     489           4 :         transport2_options = transport1->options;
     490             : 
     491           4 :         ret = test_multichannel_create_channels(tctx, host, share,
     492             :                                                   credentials,
     493             :                                                   &transport2_options,
     494             :                                                   &tree2A, &tree2B, NULL);
     495           4 :         torture_assert(tctx, ret, "Could not create channels.\n");
     496             : 
     497             :         /* 2a opens file1 */
     498           4 :         torture_comment(tctx, "client2 opens fname1 via session 2A\n");
     499           4 :         status = smb2_create(tree2A, mem_ctx, &io1);
     500           4 :         CHECK_STATUS(status, NT_STATUS_OK);
     501           4 :         h_client2_file1 = io1.out.file.handle;
     502           4 :         CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
     503           4 :         CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("b"));
     504           4 :         torture_wait_for_oplock_break(tctx);
     505           4 :         CHECK_VAL(break_info.count, 0);
     506             : 
     507             :         /* 2b opens file2 */
     508           4 :         torture_comment(tctx, "client2 opens fname2 via session 2B\n");
     509           4 :         status = smb2_create(tree2B, mem_ctx, &io2);
     510           4 :         CHECK_STATUS(status, NT_STATUS_OK);
     511           4 :         h_client2_file2 = io2.out.file.handle;
     512           4 :         CHECK_CREATED(&io2, CREATED, FILE_ATTRIBUTE_ARCHIVE);
     513           4 :         CHECK_VAL(io2.out.oplock_level, smb2_util_oplock_level("b"));
     514           4 :         torture_wait_for_oplock_break(tctx);
     515           4 :         CHECK_VAL(break_info.count, 0);
     516             : 
     517             : 
     518             :         /* 1 opens file1 - batchoplock break? */
     519           4 :         torture_comment(tctx, "client1 opens fname1 via session 1\n");
     520           4 :         io1.in.oplock_level = smb2_util_oplock_level("b");
     521           4 :         status = smb2_create(tree1, mem_ctx, &io1);
     522           4 :         CHECK_STATUS(status, NT_STATUS_OK);
     523           4 :         h_client1_file1 = io1.out.file.handle;
     524           4 :         CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
     525           4 :         CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("s"));
     526           4 :         torture_wait_for_oplock_break(tctx);
     527           4 :         CHECK_VAL(break_info.count, 1);
     528             : 
     529           4 :         torture_reset_break_info(tctx, &break_info);
     530             : 
     531             :         /* 1 opens file2 - batchoplock break? */
     532           4 :         torture_comment(tctx, "client1 opens fname2 via session 1\n");
     533           4 :         io2.in.oplock_level = smb2_util_oplock_level("b");
     534           4 :         status = smb2_create(tree1, mem_ctx, &io2);
     535           4 :         CHECK_STATUS(status, NT_STATUS_OK);
     536           4 :         h_client1_file2 = io2.out.file.handle;
     537           4 :         CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
     538           4 :         CHECK_VAL(io2.out.oplock_level, smb2_util_oplock_level("s"));
     539           4 :         torture_wait_for_oplock_break(tctx);
     540           4 :         CHECK_VAL(break_info.count, 1);
     541             : 
     542             :         /* cleanup everything */
     543           4 :         torture_reset_break_info(tctx, &break_info);
     544             : 
     545           4 :         smb2_util_close(tree1, h_client1_file1);
     546           4 :         smb2_util_close(tree1, h_client1_file2);
     547           4 :         smb2_util_close(tree1, h_client1_file3);
     548           4 :         smb2_util_close(tree2A, h_client2_file1);
     549           4 :         smb2_util_close(tree2A, h_client2_file2);
     550           4 :         smb2_util_close(tree2A, h_client2_file3);
     551             : 
     552           4 :         smb2_util_unlink(tree1, fname1);
     553           4 :         smb2_util_unlink(tree1, fname2);
     554           4 :         smb2_util_unlink(tree1, fname3);
     555           4 :         CHECK_VAL(break_info.count, 0);
     556           4 :         test_multichannel_free_channels(tree2A, tree2B, tree2C);
     557           4 :         tree2A = tree2B = tree2C = NULL;
     558           4 : done:
     559           4 :         tree1->session = session1;
     560             : 
     561           4 :         smb2_util_close(tree1, h_client1_file1);
     562           4 :         smb2_util_close(tree1, h_client1_file2);
     563           4 :         smb2_util_close(tree1, h_client1_file3);
     564           4 :         if (tree2A != NULL) {
     565           0 :                 smb2_util_close(tree2A, h_client2_file1);
     566           0 :                 smb2_util_close(tree2A, h_client2_file2);
     567           0 :                 smb2_util_close(tree2A, h_client2_file3);
     568             :         }
     569             : 
     570           4 :         smb2_util_unlink(tree1, fname1);
     571           4 :         smb2_util_unlink(tree1, fname2);
     572           4 :         smb2_util_unlink(tree1, fname3);
     573           4 :         smb2_deltree(tree1, BASEDIR);
     574             : 
     575           4 :         test_multichannel_free_channels(tree2A, tree2B, tree2C);
     576           4 :         talloc_free(tree1);
     577           4 :         talloc_free(mem_ctx);
     578             : 
     579           4 :         return ret;
     580             : }
     581             : 
     582             : /*
     583             :  * Oplock Break Test 2
     584             :  * Test to see if oplock break retries are sent by the server.
     585             :  * Also checks to see if new channels can be created and used
     586             :  * after an oplock break retry.
     587             :  * open file1 in 2A
     588             :  * open file2 in 2B
     589             :  * open file1 in session 1
     590             :  *      oplock break received
     591             :  * block channel on which oplock break received
     592             :  * open file2 in session 1
     593             :  *      oplock break not received. Retry received.
     594             :  *      file opened
     595             :  * write to file2 on 2B
     596             :  *      Break sent to session 1(which has file2 open)
     597             :  *      Break sent to session 2A(which has read oplock)
     598             :  * close file1 in session 1
     599             :  * open file1 with session 1
     600             :  * unblock blocked channel
     601             :  * disconnect blocked channel
     602             :  * connect channel 2D
     603             :  * open file3 in 2D
     604             :  * open file3 in session 1
     605             :  *      receive break
     606             :  */
     607           4 : static bool test_multichannel_oplock_break_test2(struct torture_context *tctx,
     608             :                                            struct smb2_tree *tree1)
     609             : {
     610           4 :         const char *host = torture_setting_string(tctx, "host", NULL);
     611           4 :         const char *share = torture_setting_string(tctx, "share", NULL);
     612           4 :         struct cli_credentials *credentials = samba_cmdline_get_creds();
     613             :         NTSTATUS status;
     614           4 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
     615             :         struct smb2_handle _h;
     616           4 :         struct smb2_handle h_client1_file1 = {{0}};
     617           4 :         struct smb2_handle h_client1_file2 = {{0}};
     618           4 :         struct smb2_handle h_client1_file3 = {{0}};
     619           4 :         struct smb2_handle h_client2_file1 = {{0}};
     620           4 :         struct smb2_handle h_client2_file2 = {{0}};
     621           4 :         struct smb2_handle h_client2_file3 = {{0}};
     622             :         struct smb2_create io1, io2, io3;
     623           4 :         bool ret = true;
     624           4 :         const char *fname1 = BASEDIR "\\oplock_break_test1.dat";
     625           4 :         const char *fname2 = BASEDIR "\\oplock_break_test2.dat";
     626           4 :         const char *fname3 = BASEDIR "\\oplock_break_test3.dat";
     627           4 :         struct smb2_tree *tree2A = NULL;
     628           4 :         struct smb2_tree *tree2B = NULL;
     629           4 :         struct smb2_tree *tree2C = NULL;
     630           4 :         struct smb2_tree *tree2D = NULL;
     631           4 :         struct smb2_transport *transport1 = tree1->session->transport;
     632           4 :         struct smb2_transport *transport2 = NULL;
     633             :         struct smbcli_options transport2_options;
     634           4 :         struct smb2_session *session1 = tree1->session;
     635           4 :         uint16_t local_port = 0;
     636             :         DATA_BLOB blob;
     637           4 :         bool block_setup = false;
     638           4 :         bool block_ok = false;
     639           4 :         bool unblock_ok = false;
     640             : 
     641           4 :         if (!test_multichannel_initial_checks(tctx, tree1)) {
     642           0 :                 return true;
     643             :         }
     644             : 
     645           4 :         torture_comment(tctx, "Oplock break retry: Test2\n");
     646             : 
     647           4 :         torture_reset_break_info(tctx, &break_info);
     648             : 
     649           4 :         transport1->oplock.handler = torture_oplock_ack_handler;
     650           4 :         transport1->oplock.private_data = tree1;
     651           4 :         torture_comment(tctx, "transport1  [%p]\n", transport1);
     652           4 :         local_port = torture_get_local_port_from_transport(transport1);
     653           4 :         torture_comment(tctx, "transport1 uses tcp port: %d\n", local_port);
     654             : 
     655           4 :         status = torture_smb2_testdir(tree1, BASEDIR, &_h);
     656           4 :         CHECK_STATUS(status, NT_STATUS_OK);
     657           4 :         smb2_util_close(tree1, _h);
     658           4 :         smb2_util_unlink(tree1, fname1);
     659           4 :         smb2_util_unlink(tree1, fname2);
     660           4 :         smb2_util_unlink(tree1, fname3);
     661           4 :         CHECK_VAL(break_info.count, 0);
     662             : 
     663           4 :         smb2_oplock_create_share(&io1, fname1,
     664             :                         smb2_util_share_access("RWD"),
     665           4 :                         smb2_util_oplock_level("b"));
     666           4 :         test_multichannel_init_smb_create(&io1);
     667             : 
     668           4 :         smb2_oplock_create_share(&io2, fname2,
     669             :                         smb2_util_share_access("RWD"),
     670           4 :                         smb2_util_oplock_level("b"));
     671           4 :         test_multichannel_init_smb_create(&io2);
     672             : 
     673           4 :         smb2_oplock_create_share(&io3, fname3,
     674             :                         smb2_util_share_access("RWD"),
     675           4 :                         smb2_util_oplock_level("b"));
     676           4 :         test_multichannel_init_smb_create(&io3);
     677             : 
     678           4 :         transport2_options = transport1->options;
     679             : 
     680           4 :         ret = test_multichannel_create_channels(tctx, host, share,
     681             :                                                   credentials,
     682             :                                                   &transport2_options,
     683             :                                                   &tree2A, &tree2B, &tree2C);
     684           4 :         torture_assert(tctx, ret, "Could not create channels.\n");
     685             : 
     686           4 :         torture_comment(tctx, "client2 opens fname1 via session 2A\n");
     687           4 :         io1.in.oplock_level = smb2_util_oplock_level("b");
     688           4 :         status = smb2_create(tree2A, mem_ctx, &io1);
     689           4 :         CHECK_STATUS(status, NT_STATUS_OK);
     690           4 :         h_client2_file1 = io1.out.file.handle;
     691           4 :         CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
     692           4 :         CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("b"));
     693           4 :         torture_wait_for_oplock_break(tctx);
     694           4 :         CHECK_VAL(break_info.count, 0);
     695             : 
     696             : 
     697           4 :         torture_comment(tctx, "client2 opens fname2 via session 2B\n");
     698           4 :         io2.in.oplock_level = smb2_util_oplock_level("b");
     699           4 :         status = smb2_create(tree2B, mem_ctx, &io2);
     700           4 :         CHECK_STATUS(status, NT_STATUS_OK);
     701           4 :         h_client2_file2 = io2.out.file.handle;
     702           4 :         CHECK_CREATED(&io2, CREATED, FILE_ATTRIBUTE_ARCHIVE);
     703           4 :         CHECK_VAL(io2.out.oplock_level, smb2_util_oplock_level("b"));
     704           4 :         torture_wait_for_oplock_break(tctx);
     705           4 :         CHECK_VAL(break_info.count, 0);
     706             : 
     707             : 
     708           4 :         torture_comment(tctx, "client1 opens fname1 via session 1\n");
     709           4 :         io1.in.oplock_level = smb2_util_oplock_level("b");
     710           4 :         status = smb2_create(tree1, mem_ctx, &io1);
     711           4 :         CHECK_STATUS(status, NT_STATUS_OK);
     712           4 :         h_client1_file1 = io1.out.file.handle;
     713           4 :         CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
     714           4 :         CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("s"));
     715           4 :         torture_wait_for_oplock_break(tctx);
     716           4 :         CHECK_VAL(break_info.count, 1);
     717             : 
     718             :         /* We use the transport over which this oplock break was received */
     719           4 :         transport2 = break_info.received_transport;
     720           4 :         torture_reset_break_info(tctx, &break_info);
     721             : 
     722           4 :         block_setup = test_setup_blocked_transports(tctx);
     723           4 :         torture_assert(tctx, block_setup, "test_setup_blocked_transports");
     724             : 
     725             :         /* block channel */
     726           4 :         block_ok = test_block_smb2_transport(tctx, transport2);
     727             : 
     728           4 :         torture_comment(tctx, "client1 opens fname2 via session 1\n");
     729           4 :         io2.in.oplock_level = smb2_util_oplock_level("b");
     730           4 :         status = smb2_create(tree1, mem_ctx, &io2);
     731           4 :         CHECK_STATUS(status, NT_STATUS_OK);
     732           4 :         h_client1_file2 = io2.out.file.handle;
     733           4 :         CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
     734           4 :         CHECK_VAL(io2.out.oplock_level, smb2_util_oplock_level("s"));
     735             : 
     736             :         /*
     737             :          * Samba downgrades oplock to a level 2 oplock.
     738             :          * Windows 2016 revokes oplock
     739             :          */
     740           4 :         torture_wait_for_oplock_break(tctx);
     741           4 :         CHECK_VAL(break_info.count, 1);
     742           2 :         torture_reset_break_info(tctx, &break_info);
     743             : 
     744           2 :         torture_comment(tctx, "Trying write to file2 on tree2B\n");
     745             : 
     746           2 :         blob = data_blob_string_const("Here I am");
     747           4 :         status = smb2_util_write(tree2B,
     748             :                                  h_client2_file2,
     749           2 :                                  blob.data,
     750             :                                  0,
     751             :                                  blob.length);
     752           2 :         torture_assert_ntstatus_ok(tctx, status,
     753             :                 "failed to write file2 via channel 2B");
     754             : 
     755             :         /*
     756             :          * Samba: Write triggers 2 oplock breaks
     757             :          *  for session 1 which has file2 open
     758             :          *  for session 2 which has type 2 oplock
     759             :          * Windows 2016: Only one oplock break for session 1
     760             :          */
     761           2 :         torture_wait_for_oplock_break(tctx);
     762           2 :         CHECK_VAL_GREATER_THAN(break_info.count, 0);
     763           2 :         torture_reset_break_info(tctx, &break_info);
     764             : 
     765           2 :         torture_comment(tctx, "client1 closes fname2 via session 1\n");
     766           2 :         smb2_util_close(tree1, h_client1_file2);
     767             : 
     768           2 :         torture_comment(tctx, "client1 opens fname2 via session 1 again\n");
     769           2 :         io2.in.oplock_level = smb2_util_oplock_level("b");
     770           2 :         status = smb2_create(tree1, mem_ctx, &io2);
     771           2 :         CHECK_STATUS(status, NT_STATUS_OK);
     772           2 :         h_client1_file2 = io2.out.file.handle;
     773           2 :         io2.out.alloc_size = 0;
     774           2 :         io2.out.size = 0;
     775           2 :         CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
     776           2 :         CHECK_VAL(io2.out.oplock_level, smb2_util_oplock_level("s"));
     777             : 
     778             :         /*
     779             :          * now add a fourth channel and repeat the test, we need to reestablish
     780             :          * transport2 because the remote end has invalidated our connection
     781             :          */
     782           2 :         torture_comment(tctx, "Connecting session 2D\n");
     783           2 :         tree2D = test_multichannel_create_channel(tctx, host, share,
     784             :                                      credentials, &transport2_options, tree2B);
     785           2 :         if (!tree2D) {
     786           0 :                 goto done;
     787             :         }
     788             : 
     789           2 :         torture_reset_break_info(tctx, &break_info);
     790           2 :         torture_comment(tctx, "client 2 opening fname3 over transport2D\n");
     791           2 :         status = smb2_create(tree2D, mem_ctx, &io3);
     792           2 :         CHECK_STATUS(status, NT_STATUS_OK);
     793           2 :         h_client2_file3 = io3.out.file.handle;
     794           2 :         CHECK_CREATED(&io3, CREATED, FILE_ATTRIBUTE_ARCHIVE);
     795           2 :         CHECK_VAL(io3.out.oplock_level, smb2_util_oplock_level("b"));
     796           2 :         torture_wait_for_oplock_break(tctx);
     797           2 :         CHECK_VAL(break_info.count, 0);
     798             : 
     799           2 :         torture_comment(tctx, "client1 opens fname3 via session 1\n");
     800           2 :         status = smb2_create(tree1, mem_ctx, &io3);
     801           2 :         CHECK_STATUS(status, NT_STATUS_OK);
     802           2 :         h_client1_file3 = io3.out.file.handle;
     803           2 :         CHECK_CREATED(&io3, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
     804           2 :         CHECK_VAL(io3.out.oplock_level, smb2_util_oplock_level("s"));
     805           2 :         torture_wait_for_oplock_break(tctx);
     806           2 :         CHECK_VAL(break_info.count, 1);
     807             : 
     808           6 : done:
     809           4 :         if (block_ok && !unblock_ok) {
     810           4 :                 test_unblock_smb2_transport(tctx, transport2);
     811             :         }
     812           4 :         test_cleanup_blocked_transports(tctx);
     813             : 
     814           4 :         tree1->session = session1;
     815             : 
     816           4 :         smb2_util_close(tree1, h_client1_file1);
     817           4 :         smb2_util_close(tree1, h_client1_file2);
     818           4 :         smb2_util_close(tree1, h_client1_file3);
     819           4 :         if (tree2B != NULL) {
     820           4 :                 smb2_util_close(tree2B, h_client2_file1);
     821           4 :                 smb2_util_close(tree2B, h_client2_file2);
     822           4 :                 smb2_util_close(tree2B, h_client2_file3);
     823             :         }
     824             : 
     825           4 :         smb2_util_unlink(tree1, fname1);
     826           4 :         smb2_util_unlink(tree1, fname2);
     827           4 :         smb2_util_unlink(tree1, fname3);
     828           4 :         smb2_deltree(tree1, BASEDIR);
     829             : 
     830           4 :         test_multichannel_free_channels(tree2A, tree2B, tree2C);
     831           4 :         if (tree2D != NULL) {
     832           2 :                 TALLOC_FREE(tree2D);
     833             :         }
     834           4 :         talloc_free(tree1);
     835           4 :         talloc_free(mem_ctx);
     836             : 
     837           4 :         return ret;
     838             : }
     839             : 
     840             : struct test_multichannel_oplock_break_state;
     841             : 
     842             : struct test_multichannel_oplock_break_channel {
     843             :         struct test_multichannel_oplock_break_state *state;
     844             :         size_t idx;
     845             :         char name[64];
     846             :         struct smb2_tree *tree;
     847             :         bool blocked;
     848             :         struct timeval break_time;
     849             :         double full_duration;
     850             :         double relative_duration;
     851             :         uint8_t level;
     852             :         size_t break_num;
     853             : };
     854             : 
     855             : struct test_multichannel_oplock_break_state {
     856             :         struct torture_context *tctx;
     857             :         struct timeval open_req_time;
     858             :         struct timeval open_rep_time;
     859             :         size_t num_breaks;
     860             :         struct timeval last_break_time;
     861             :         struct test_multichannel_oplock_break_channel channels[32];
     862             : };
     863             : 
     864         128 : static bool test_multichannel_oplock_break_handler(struct smb2_transport *transport,
     865             :                                                    const struct smb2_handle *handle,
     866             :                                                    uint8_t level,
     867             :                                                    void *private_data)
     868             : {
     869         128 :         struct test_multichannel_oplock_break_channel *c =
     870             :                 (struct test_multichannel_oplock_break_channel *)private_data;
     871         128 :         struct test_multichannel_oplock_break_state *state = c->state;
     872             : 
     873         128 :         c->break_time = timeval_current();
     874         128 :         c->full_duration = timeval_elapsed2(&state->open_req_time,
     875         128 :                                             &c->break_time);
     876         128 :         c->relative_duration = timeval_elapsed2(&state->last_break_time,
     877         128 :                                                 &c->break_time);
     878         128 :         state->last_break_time = c->break_time;
     879         128 :         c->level = level;
     880         128 :         c->break_num = ++state->num_breaks;
     881             : 
     882         256 :         torture_comment(state->tctx, "Got OPLOCK break %zu on %s after %f ( %f)\n",
     883         128 :                         c->break_num, c->name,
     884             :                         c->relative_duration,
     885             :                         c->full_duration);
     886             : 
     887         128 :         return torture_oplock_ack_handler(transport, handle, level, c->tree);
     888             : }
     889             : 
     890           4 : static bool test_multichannel_oplock_break_test3_windows(struct torture_context *tctx,
     891             :                                                          struct smb2_tree *tree1)
     892             : {
     893           4 :         const char *host = torture_setting_string(tctx, "host", NULL);
     894           4 :         const char *share = torture_setting_string(tctx, "share", NULL);
     895           4 :         struct cli_credentials *credentials = samba_cmdline_get_creds();
     896             :         NTSTATUS status;
     897           4 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
     898           4 :         struct test_multichannel_oplock_break_state state = {
     899             :                 .tctx = tctx,
     900             :         };
     901           4 :         struct test_multichannel_oplock_break_channel *open2_channel = NULL;
     902             :         struct smb2_handle _h;
     903           4 :         struct smb2_handle *h = NULL;
     904           4 :         struct smb2_handle h_client1_file1 = {{0}};
     905           4 :         struct smb2_handle h_client2_file1 = {{0}};
     906             :         struct smb2_create io1;
     907             :         struct smb2_create io2;
     908           4 :         bool ret = true;
     909           4 :         const char *fname1 = BASEDIR "\\oplock_break_test3w.dat";
     910           4 :         struct smb2_tree *trees2[32] = { NULL, };
     911             :         size_t i;
     912           4 :         struct smb2_transport *transport1 = tree1->session->transport;
     913             :         struct smbcli_options transport2_options;
     914           4 :         struct smb2_session *session1 = tree1->session;
     915           4 :         uint16_t local_port = 0;
     916           4 :         bool block_setup = false;
     917           4 :         bool block_ok = false;
     918             :         double open_duration;
     919             : 
     920           4 :         if (!test_multichannel_initial_checks(tctx, tree1)) {
     921           0 :                 return true;
     922             :         }
     923             : 
     924           4 :         torture_comment(tctx, "Oplock break retry: Test3 (Windows behavior)\n");
     925             : 
     926           4 :         torture_reset_break_info(tctx, &break_info);
     927           4 :         break_info.oplock_skip_ack = true;
     928             : 
     929           4 :         transport1->oplock.handler = torture_oplock_ack_handler;
     930           4 :         transport1->oplock.private_data = tree1;
     931           4 :         torture_comment(tctx, "transport1  [%p]\n", transport1);
     932           4 :         local_port = torture_get_local_port_from_transport(transport1);
     933           4 :         torture_comment(tctx, "transport1 uses tcp port: %d\n", local_port);
     934             : 
     935           4 :         status = torture_smb2_testdir(tree1, BASEDIR, &_h);
     936           4 :         CHECK_STATUS(status, NT_STATUS_OK);
     937           4 :         smb2_util_close(tree1, _h);
     938           4 :         smb2_util_unlink(tree1, fname1);
     939           4 :         CHECK_VAL(break_info.count, 0);
     940             : 
     941           4 :         smb2_oplock_create_share(&io2, fname1,
     942             :                         smb2_util_share_access("RWD"),
     943           4 :                         smb2_util_oplock_level("b"));
     944             : 
     945           4 :         transport2_options = transport1->options;
     946             : 
     947           4 :         ret = test_multichannel_create_channel_array(tctx, host, share, credentials,
     948             :                                                      &transport2_options,
     949             :                                                      ARRAY_SIZE(trees2), trees2);
     950           4 :         torture_assert(tctx, ret, "Could not create channels.\n");
     951             : 
     952         132 :         for (i = 0; i < ARRAY_SIZE(trees2); i++) {
     953         128 :                 struct test_multichannel_oplock_break_channel *c = &state.channels[i];
     954         128 :                 struct smb2_transport *t = trees2[i]->session->transport;
     955             : 
     956         128 :                 c->state = &state;
     957         128 :                 c->idx = i+1;
     958         128 :                 c->tree = trees2[i];
     959         128 :                 snprintf(c->name, sizeof(c->name), "trees2_%zu", c->idx);
     960             : 
     961         128 :                 t->oplock.handler = test_multichannel_oplock_break_handler;
     962         128 :                 t->oplock.private_data = c;
     963             :         }
     964             : 
     965           4 :         open2_channel = &state.channels[0];
     966             : 
     967             :         /* 2a opens file1 */
     968           4 :         torture_comment(tctx, "client2 opens fname1 via %s\n",
     969           4 :                         open2_channel->name);
     970           4 :         status = smb2_create(open2_channel->tree, mem_ctx, &io2);
     971           4 :         CHECK_STATUS(status, NT_STATUS_OK);
     972           4 :         h_client2_file1 = io2.out.file.handle;
     973           4 :         CHECK_CREATED(&io2, CREATED, FILE_ATTRIBUTE_ARCHIVE);
     974           4 :         CHECK_VAL(io2.out.oplock_level, smb2_util_oplock_level("b"));
     975           4 :         CHECK_VAL(io2.out.durable_open_v2, false);
     976           4 :         CHECK_VAL(io2.out.timeout, io2.in.timeout);
     977           4 :         CHECK_VAL(io2.out.durable_open, false);
     978           4 :         CHECK_VAL(break_info.count, 0);
     979             : 
     980           4 :         block_setup = test_setup_blocked_transports(tctx);
     981           4 :         torture_assert(tctx, block_setup, "test_setup_blocked_transports");
     982             : 
     983         132 :         for (i = 0; i < ARRAY_SIZE(state.channels); i++) {
     984         128 :                 struct test_multichannel_oplock_break_channel *c = &state.channels[i];
     985         128 :                 struct smb2_transport *t = c->tree->session->transport;
     986             : 
     987         128 :                 torture_comment(tctx, "Blocking %s\n", c->name);
     988         128 :                 block_ok = _test_block_smb2_transport(tctx, t, c->name);
     989         128 :                 torture_assert_goto(tctx, block_ok, ret, done, "we could not block tcp transport");
     990         128 :                 c->blocked = true;
     991             :         }
     992             : 
     993             :         /* 1 opens file2 */
     994           4 :         torture_comment(tctx,
     995             :                         "Client opens fname1 with session 1 with all %zu blocked\n",
     996             :                         ARRAY_SIZE(trees2));
     997           4 :         smb2_oplock_create_share(&io1, fname1,
     998             :                         smb2_util_share_access("RWD"),
     999           4 :                         smb2_util_oplock_level("b"));
    1000           4 :         CHECK_VAL(lease_break_info.count, 0);
    1001           4 :         state.open_req_time = timeval_current();
    1002           4 :         state.last_break_time = state.open_req_time;
    1003           4 :         status = smb2_create(tree1, mem_ctx, &io1);
    1004           4 :         state.open_rep_time = timeval_current();
    1005           4 :         CHECK_STATUS(status, NT_STATUS_OK);
    1006           4 :         h_client1_file1 = io1.out.file.handle;
    1007           4 :         CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("s"));
    1008             : 
    1009           4 :         CHECK_VAL(break_info.count, 1);
    1010             : 
    1011           2 :         open_duration = timeval_elapsed2(&state.open_req_time,
    1012             :                                          &state.open_rep_time);
    1013           2 :         torture_comment(tctx, "open_duration: %f\n", open_duration);
    1014           2 :         CHECK_VAL_GREATER_THAN(open_duration, 35);
    1015             : 
    1016           2 :         if (break_info.count == 0) {
    1017           0 :                 torture_comment(tctx,
    1018             :                                 "Did not receive expected oplock break!!\n");
    1019             :         } else {
    1020           2 :                 torture_comment(tctx, "Received %d oplock break(s)!!\n",
    1021             :                                 break_info.count);
    1022             :         }
    1023             : 
    1024          66 :         for (i = 0; i < ARRAY_SIZE(state.channels); i++) {
    1025          64 :                 struct test_multichannel_oplock_break_channel *c = &state.channels[i];
    1026          64 :                 size_t expected_break_num = 0;
    1027             : 
    1028             :                 /*
    1029             :                  * Only the latest channel gets a break notification
    1030             :                  */
    1031          64 :                 if (i == (ARRAY_SIZE(state.channels) - 1)) {
    1032           2 :                         expected_break_num = 1;
    1033             :                 }
    1034             : 
    1035          64 :                 torture_comment(tctx, "Verify %s\n", c->name);
    1036          64 :                 torture_assert_int_equal(tctx, c->break_num, expected_break_num,
    1037             :                                          "Got oplock break on wrong channel");
    1038          64 :                 if (expected_break_num != 0) {
    1039           2 :                         CHECK_VAL(c->level, smb2_util_oplock_level("s"));
    1040             :                 }
    1041             :         }
    1042             : 
    1043           2 : done:
    1044         132 :         for (i = 0; i < ARRAY_SIZE(state.channels); i++) {
    1045         128 :                 struct test_multichannel_oplock_break_channel *c = &state.channels[i];
    1046         128 :                 struct smb2_transport *t = NULL;
    1047             : 
    1048         128 :                 if (!c->blocked) {
    1049           0 :                         continue;
    1050             :                 }
    1051             : 
    1052         128 :                 t = c->tree->session->transport;
    1053             : 
    1054         128 :                 torture_comment(tctx, "Unblocking %s\n", c->name);
    1055         128 :                 _test_unblock_smb2_transport(tctx, t, c->name);
    1056         128 :                 c->blocked = false;
    1057             :         }
    1058           4 :         if (block_setup) {
    1059           4 :                 test_cleanup_blocked_transports(tctx);
    1060             :         }
    1061             : 
    1062           4 :         tree1->session = session1;
    1063             : 
    1064           4 :         smb2_util_close(tree1, h_client1_file1);
    1065           4 :         if (trees2[0] != NULL) {
    1066           4 :                 smb2_util_close(trees2[0], h_client2_file1);
    1067             :         }
    1068             : 
    1069           4 :         if (h != NULL) {
    1070           0 :                 smb2_util_close(tree1, *h);
    1071             :         }
    1072             : 
    1073           4 :         smb2_util_unlink(tree1, fname1);
    1074           4 :         smb2_deltree(tree1, BASEDIR);
    1075             : 
    1076         132 :         for (i = 0; i < ARRAY_SIZE(trees2); i++) {
    1077         128 :                 if (trees2[i] == NULL) {
    1078           0 :                         continue;
    1079             :                 }
    1080         128 :                 TALLOC_FREE(trees2[i]);
    1081             :         }
    1082           4 :         talloc_free(tree1);
    1083           4 :         talloc_free(mem_ctx);
    1084             : 
    1085           4 :         return ret;
    1086             : }
    1087             : 
    1088           4 : static bool test_multichannel_oplock_break_test3_specification(struct torture_context *tctx,
    1089             :                                                                struct smb2_tree *tree1)
    1090             : {
    1091           4 :         const char *host = torture_setting_string(tctx, "host", NULL);
    1092           4 :         const char *share = torture_setting_string(tctx, "share", NULL);
    1093           4 :         struct cli_credentials *credentials = samba_cmdline_get_creds();
    1094             :         NTSTATUS status;
    1095           4 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
    1096           4 :         struct test_multichannel_oplock_break_state state = {
    1097             :                 .tctx = tctx,
    1098             :         };
    1099           4 :         struct test_multichannel_oplock_break_channel *open2_channel = NULL;
    1100             :         struct smb2_handle _h;
    1101           4 :         struct smb2_handle *h = NULL;
    1102           4 :         struct smb2_handle h_client1_file1 = {{0}};
    1103           4 :         struct smb2_handle h_client2_file1 = {{0}};
    1104             :         struct smb2_create io1;
    1105             :         struct smb2_create io2;
    1106           4 :         bool ret = true;
    1107           4 :         const char *fname1 = BASEDIR "\\oplock_break_test3s.dat";
    1108           4 :         struct smb2_tree *trees2[32] = { NULL, };
    1109             :         size_t i;
    1110           4 :         struct smb2_transport *transport1 = tree1->session->transport;
    1111             :         struct smbcli_options transport2_options;
    1112           4 :         struct smb2_session *session1 = tree1->session;
    1113           4 :         uint16_t local_port = 0;
    1114           4 :         bool block_setup = false;
    1115           4 :         bool block_ok = false;
    1116             :         double open_duration;
    1117             : 
    1118           4 :         if (!test_multichannel_initial_checks(tctx, tree1)) {
    1119           0 :                 return true;
    1120             :         }
    1121             : 
    1122           4 :         torture_comment(tctx, "Oplock break retry: Test3 (Specification behavior)\n");
    1123             : 
    1124           4 :         torture_reset_break_info(tctx, &break_info);
    1125           4 :         break_info.oplock_skip_ack = true;
    1126             : 
    1127           4 :         transport1->oplock.handler = torture_oplock_ack_handler;
    1128           4 :         transport1->oplock.private_data = tree1;
    1129           4 :         torture_comment(tctx, "transport1  [%p]\n", transport1);
    1130           4 :         local_port = torture_get_local_port_from_transport(transport1);
    1131           4 :         torture_comment(tctx, "transport1 uses tcp port: %d\n", local_port);
    1132             : 
    1133           4 :         status = torture_smb2_testdir(tree1, BASEDIR, &_h);
    1134           4 :         CHECK_STATUS(status, NT_STATUS_OK);
    1135           4 :         smb2_util_close(tree1, _h);
    1136           4 :         smb2_util_unlink(tree1, fname1);
    1137           4 :         CHECK_VAL(break_info.count, 0);
    1138             : 
    1139           4 :         smb2_oplock_create_share(&io2, fname1,
    1140             :                         smb2_util_share_access("RWD"),
    1141           4 :                         smb2_util_oplock_level("b"));
    1142             : 
    1143           4 :         transport2_options = transport1->options;
    1144             : 
    1145           4 :         ret = test_multichannel_create_channel_array(tctx, host, share, credentials,
    1146             :                                                      &transport2_options,
    1147             :                                                      ARRAY_SIZE(trees2), trees2);
    1148           4 :         torture_assert(tctx, ret, "Could not create channels.\n");
    1149             : 
    1150         132 :         for (i = 0; i < ARRAY_SIZE(trees2); i++) {
    1151         128 :                 struct test_multichannel_oplock_break_channel *c = &state.channels[i];
    1152         128 :                 struct smb2_transport *t = trees2[i]->session->transport;
    1153             : 
    1154         128 :                 c->state = &state;
    1155         128 :                 c->idx = i+1;
    1156         128 :                 c->tree = trees2[i];
    1157         128 :                 snprintf(c->name, sizeof(c->name), "trees2_%zu", c->idx);
    1158             : 
    1159         128 :                 t->oplock.handler = test_multichannel_oplock_break_handler;
    1160         128 :                 t->oplock.private_data = c;
    1161             :         }
    1162             : 
    1163           4 :         open2_channel = &state.channels[0];
    1164             : 
    1165             :         /* 2a opens file1 */
    1166           4 :         torture_comment(tctx, "client2 opens fname1 via %s\n",
    1167           4 :                         open2_channel->name);
    1168           4 :         status = smb2_create(open2_channel->tree, mem_ctx, &io2);
    1169           4 :         CHECK_STATUS(status, NT_STATUS_OK);
    1170           4 :         h_client2_file1 = io2.out.file.handle;
    1171           4 :         CHECK_CREATED(&io2, CREATED, FILE_ATTRIBUTE_ARCHIVE);
    1172           4 :         CHECK_VAL(io2.out.oplock_level, smb2_util_oplock_level("b"));
    1173           4 :         CHECK_VAL(io2.out.durable_open_v2, false);
    1174           4 :         CHECK_VAL(io2.out.timeout, io2.in.timeout);
    1175           4 :         CHECK_VAL(io2.out.durable_open, false);
    1176           4 :         CHECK_VAL(break_info.count, 0);
    1177             : 
    1178           4 :         block_setup = test_setup_blocked_transports(tctx);
    1179           4 :         torture_assert(tctx, block_setup, "test_setup_blocked_transports");
    1180             : 
    1181         132 :         for (i = 0; i < ARRAY_SIZE(state.channels); i++) {
    1182         128 :                 struct test_multichannel_oplock_break_channel *c = &state.channels[i];
    1183         128 :                 struct smb2_transport *t = c->tree->session->transport;
    1184             : 
    1185         128 :                 torture_comment(tctx, "Blocking %s\n", c->name);
    1186         128 :                 block_ok = _test_block_smb2_transport(tctx, t, c->name);
    1187         128 :                 torture_assert_goto(tctx, block_ok, ret, done, "we could not block tcp transport");
    1188         128 :                 c->blocked = true;
    1189             :         }
    1190             : 
    1191             :         /* 1 opens file2 */
    1192           4 :         torture_comment(tctx,
    1193             :                         "Client opens fname1 with session 1 with all %zu blocked\n",
    1194             :                         ARRAY_SIZE(trees2));
    1195           4 :         smb2_oplock_create_share(&io1, fname1,
    1196             :                         smb2_util_share_access("RWD"),
    1197           4 :                         smb2_util_oplock_level("b"));
    1198           4 :         CHECK_VAL(lease_break_info.count, 0);
    1199           4 :         state.open_req_time = timeval_current();
    1200           4 :         state.last_break_time = state.open_req_time;
    1201           4 :         status = smb2_create(tree1, mem_ctx, &io1);
    1202           4 :         state.open_rep_time = timeval_current();
    1203           4 :         CHECK_STATUS(status, NT_STATUS_OK);
    1204           4 :         h_client1_file1 = io1.out.file.handle;
    1205             : 
    1206           4 :         CHECK_VAL_GREATER_THAN(break_info.count, 1);
    1207             : 
    1208           2 :         open_duration = timeval_elapsed2(&state.open_req_time,
    1209             :                                          &state.open_rep_time);
    1210           2 :         torture_comment(tctx, "open_duration: %f\n", open_duration);
    1211           2 :         if (break_info.count < ARRAY_SIZE(state.channels)) {
    1212           2 :                 CHECK_VAL_GREATER_THAN(open_duration, 35);
    1213           2 :                 CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("s"));
    1214             :         } else {
    1215           0 :                 CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("b"));
    1216             :         }
    1217             : 
    1218          10 :         for (i = 0; i < ARRAY_SIZE(state.channels); i++) {
    1219          10 :                 if (break_info.count >= ARRAY_SIZE(state.channels)) {
    1220           2 :                         break;
    1221             :                 }
    1222           8 :                 torture_comment(tctx, "Received %d oplock break(s) wait for more!!\n",
    1223             :                                 break_info.count);
    1224           8 :                 torture_wait_for_oplock_break(tctx);
    1225             :         }
    1226             : 
    1227           2 :         if (break_info.count == 0) {
    1228           0 :                 torture_comment(tctx,
    1229             :                                 "Did not receive expected oplock break!!\n");
    1230             :         } else {
    1231           2 :                 torture_comment(tctx, "Received %d oplock break(s)!!\n",
    1232             :                                 break_info.count);
    1233             :         }
    1234             : 
    1235           2 :         if (break_info.count < ARRAY_SIZE(state.channels)) {
    1236           0 :                 CHECK_VAL_GREATER_THAN(break_info.count, 3);
    1237             :         } else {
    1238           2 :                 CHECK_VAL(break_info.count, ARRAY_SIZE(state.channels));
    1239             :         }
    1240             : 
    1241          66 :         for (i = 0; i < break_info.count; i++) {
    1242          64 :                 struct test_multichannel_oplock_break_channel *c = &state.channels[i];
    1243             : 
    1244          64 :                 torture_comment(tctx, "Verify %s\n", c->name);
    1245          64 :                 torture_assert_int_equal(tctx, c->break_num, c->idx,
    1246             :                                          "Got oplock break on wrong channel");
    1247          64 :                 CHECK_VAL(c->level, smb2_util_oplock_level("s"));
    1248             :         }
    1249             : 
    1250           2 : done:
    1251         132 :         for (i = 0; i < ARRAY_SIZE(state.channels); i++) {
    1252         128 :                 struct test_multichannel_oplock_break_channel *c = &state.channels[i];
    1253         128 :                 struct smb2_transport *t = NULL;
    1254             : 
    1255         128 :                 if (!c->blocked) {
    1256           0 :                         continue;
    1257             :                 }
    1258             : 
    1259         128 :                 t = c->tree->session->transport;
    1260             : 
    1261         128 :                 torture_comment(tctx, "Unblocking %s\n", c->name);
    1262         128 :                 _test_unblock_smb2_transport(tctx, t, c->name);
    1263         128 :                 c->blocked = false;
    1264             :         }
    1265           4 :         if (block_setup) {
    1266           4 :                 test_cleanup_blocked_transports(tctx);
    1267             :         }
    1268             : 
    1269           4 :         tree1->session = session1;
    1270             : 
    1271           4 :         smb2_util_close(tree1, h_client1_file1);
    1272           4 :         if (trees2[0] != NULL) {
    1273           4 :                 smb2_util_close(trees2[0], h_client2_file1);
    1274             :         }
    1275             : 
    1276           4 :         if (h != NULL) {
    1277           0 :                 smb2_util_close(tree1, *h);
    1278             :         }
    1279             : 
    1280           4 :         smb2_util_unlink(tree1, fname1);
    1281           4 :         smb2_deltree(tree1, BASEDIR);
    1282             : 
    1283         132 :         for (i = 0; i < ARRAY_SIZE(trees2); i++) {
    1284         128 :                 if (trees2[i] == NULL) {
    1285           0 :                         continue;
    1286             :                 }
    1287         128 :                 TALLOC_FREE(trees2[i]);
    1288             :         }
    1289           4 :         talloc_free(tree1);
    1290           4 :         talloc_free(mem_ctx);
    1291             : 
    1292           4 :         return ret;
    1293             : }
    1294             : 
    1295             : static const uint64_t LEASE1F1 = 0xBADC0FFEE0DDF00Dull;
    1296             : static const uint64_t LEASE1F2 = 0xBADC0FFEE0DDD00Dull;
    1297             : static const uint64_t LEASE1F3 = 0xDADC0FFEE0DDD00Dull;
    1298             : static const uint64_t LEASE2F1 = 0xDEADBEEFFEEDBEADull;
    1299             : static const uint64_t LEASE2F2 = 0xDAD0FFEDD00DF00Dull;
    1300             : static const uint64_t LEASE2F3 = 0xBAD0FFEDD00DF00Dull;
    1301             : 
    1302             : /*
    1303             :  * Lease Break Test 1:
    1304             :  * Test to check if lease breaks are sent by the server as expected.
    1305             :  *      open file1 in session 2A
    1306             :  *      open file2 in session 2B
    1307             :  *      open file3 in session 2C
    1308             :  *      open file1 in session 1
    1309             :  *           lease break sent
    1310             :  *      open file2 in session 1
    1311             :  *           lease break sent
    1312             :  *      open file3 in session 1
    1313             :  *           lease break sent
    1314             :  */
    1315           4 : static bool test_multichannel_lease_break_test1(struct torture_context *tctx,
    1316             :                                                 struct smb2_tree *tree1)
    1317             : {
    1318           4 :         const char *host = torture_setting_string(tctx, "host", NULL);
    1319           4 :         const char *share = torture_setting_string(tctx, "share", NULL);
    1320           4 :         struct cli_credentials *credentials = samba_cmdline_get_creds();
    1321             :         NTSTATUS status;
    1322           4 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
    1323             :         struct smb2_handle _h;
    1324           4 :         struct smb2_handle *h = NULL;
    1325           4 :         struct smb2_handle h_client1_file1 = {{0}};
    1326           4 :         struct smb2_handle h_client1_file2 = {{0}};
    1327           4 :         struct smb2_handle h_client1_file3 = {{0}};
    1328           4 :         struct smb2_handle h_client2_file1 = {{0}};
    1329           4 :         struct smb2_handle h_client2_file2 = {{0}};
    1330           4 :         struct smb2_handle h_client2_file3 = {{0}};
    1331             :         struct smb2_create io1, io2, io3;
    1332           4 :         bool ret = true;
    1333           4 :         const char *fname1 = BASEDIR "\\lease_break_test1.dat";
    1334           4 :         const char *fname2 = BASEDIR "\\lease_break_test2.dat";
    1335           4 :         const char *fname3 = BASEDIR "\\lease_break_test3.dat";
    1336           4 :         struct smb2_tree *tree2A = NULL;
    1337           4 :         struct smb2_tree *tree2B = NULL;
    1338           4 :         struct smb2_tree *tree2C = NULL;
    1339           4 :         struct smb2_transport *transport1 = tree1->session->transport;
    1340             :         struct smbcli_options transport2_options;
    1341           4 :         struct smb2_session *session1 = tree1->session;
    1342           4 :         uint16_t local_port = 0;
    1343             :         struct smb2_lease ls1;
    1344             :         struct smb2_lease ls2;
    1345             :         struct smb2_lease ls3;
    1346             : 
    1347           4 :         if (!test_multichannel_initial_checks(tctx, tree1)) {
    1348           0 :                 return true;
    1349             :         }
    1350             : 
    1351           4 :         torture_comment(tctx, "Lease break retry: Test1\n");
    1352             : 
    1353           4 :         torture_reset_lease_break_info(tctx, &lease_break_info);
    1354             : 
    1355           4 :         transport1->lease.handler = torture_lease_handler;
    1356           4 :         transport1->lease.private_data = tree1;
    1357           4 :         torture_comment(tctx, "transport1  [%p]\n", transport1);
    1358           4 :         local_port = torture_get_local_port_from_transport(transport1);
    1359           4 :         torture_comment(tctx, "transport1 uses tcp port: %d\n", local_port);
    1360             : 
    1361           4 :         status = torture_smb2_testdir(tree1, BASEDIR, &_h);
    1362           4 :         CHECK_STATUS(status, NT_STATUS_OK);
    1363           4 :         smb2_util_close(tree1, _h);
    1364           4 :         smb2_util_unlink(tree1, fname1);
    1365           4 :         smb2_util_unlink(tree1, fname2);
    1366           4 :         smb2_util_unlink(tree1, fname3);
    1367           4 :         CHECK_VAL(lease_break_info.count, 0);
    1368             : 
    1369           4 :         smb2_lease_create(&io1, &ls1, false, fname1, LEASE2F1,
    1370             :                           smb2_util_lease_state("RHW"));
    1371           4 :         test_multichannel_init_smb_create(&io1);
    1372             : 
    1373           4 :         smb2_lease_create(&io2, &ls2, false, fname2, LEASE2F2,
    1374             :                           smb2_util_lease_state("RHW"));
    1375           4 :         test_multichannel_init_smb_create(&io2);
    1376             : 
    1377           4 :         smb2_lease_create(&io3, &ls3, false, fname3, LEASE2F3,
    1378             :                           smb2_util_lease_state("RHW"));
    1379           4 :         test_multichannel_init_smb_create(&io3);
    1380             : 
    1381           4 :         transport2_options = transport1->options;
    1382             : 
    1383           4 :         ret = test_multichannel_create_channels(tctx, host, share,
    1384             :                                                   credentials,
    1385             :                                                   &transport2_options,
    1386             :                                                   &tree2A, &tree2B, &tree2C);
    1387           4 :         torture_assert(tctx, ret, "Could not create channels.\n");
    1388             : 
    1389             :         /* 2a opens file1 */
    1390           4 :         torture_comment(tctx, "client2 opens fname1 via session 2A\n");
    1391           4 :         status = smb2_create(tree2A, mem_ctx, &io1);
    1392           4 :         CHECK_STATUS(status, NT_STATUS_OK);
    1393           4 :         h_client2_file1 = io1.out.file.handle;
    1394           4 :         CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
    1395           4 :         CHECK_LEASE(&io1, "RHW", true, LEASE2F1, 0);
    1396           2 :         CHECK_VAL(lease_break_info.count, 0);
    1397             : 
    1398             :         /* 2b opens file2 */
    1399           2 :         torture_comment(tctx, "client2 opens fname2 via session 2B\n");
    1400           2 :         status = smb2_create(tree2B, mem_ctx, &io2);
    1401           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    1402           2 :         h_client2_file2 = io2.out.file.handle;
    1403           2 :         CHECK_CREATED(&io2, CREATED, FILE_ATTRIBUTE_ARCHIVE);
    1404           2 :         CHECK_LEASE(&io2, "RHW", true, LEASE2F2, 0);
    1405           2 :         CHECK_VAL(lease_break_info.count, 0);
    1406             : 
    1407             :         /* 2c opens file3 */
    1408           2 :         torture_comment(tctx, "client2 opens fname3 via session 2C\n");
    1409           2 :         smb2_lease_create(&io3, &ls3, false, fname3, LEASE2F3,
    1410             :                           smb2_util_lease_state("RHW"));
    1411           2 :         status = smb2_create(tree2C, mem_ctx, &io3);
    1412           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    1413           2 :         h_client2_file3 = io3.out.file.handle;
    1414           2 :         CHECK_CREATED(&io3, CREATED, FILE_ATTRIBUTE_ARCHIVE);
    1415           2 :         CHECK_LEASE(&io3, "RHW", true, LEASE2F3, 0);
    1416           2 :         CHECK_VAL(lease_break_info.count, 0);
    1417             : 
    1418             :         /* 1 opens file1 - lease break? */
    1419           2 :         torture_comment(tctx, "client1 opens fname1 via session 1\n");
    1420           2 :         smb2_lease_create(&io1, &ls1, false, fname1, LEASE1F1,
    1421             :                           smb2_util_lease_state("RHW"));
    1422           2 :         status = smb2_create(tree1, mem_ctx, &io1);
    1423           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    1424           2 :         h_client1_file1 = io1.out.file.handle;
    1425           2 :         CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
    1426           2 :         CHECK_LEASE(&io1, "RH", true, LEASE1F1, 0);
    1427           2 :         CHECK_BREAK_INFO("RHW", "RH", LEASE2F1);
    1428           2 :         CHECK_VAL(lease_break_info.count, 1);
    1429             : 
    1430           2 :         torture_reset_lease_break_info(tctx, &lease_break_info);
    1431             : 
    1432             :         /* 1 opens file2 - lease break? */
    1433           2 :         torture_comment(tctx, "client1 opens fname2 via session 1\n");
    1434           2 :         smb2_lease_create(&io2, &ls2, false, fname2, LEASE1F2,
    1435             :                           smb2_util_lease_state("RHW"));
    1436           2 :         status = smb2_create(tree1, mem_ctx, &io2);
    1437           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    1438           2 :         h_client1_file2 = io2.out.file.handle;
    1439           2 :         CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
    1440           2 :         CHECK_LEASE(&io2, "RH", true, LEASE1F2, 0);
    1441           2 :         CHECK_BREAK_INFO("RHW", "RH", LEASE2F2);
    1442           2 :         CHECK_VAL(lease_break_info.count, 1);
    1443             : 
    1444           2 :         torture_reset_lease_break_info(tctx, &lease_break_info);
    1445             : 
    1446             :         /* 1 opens file3 - lease break? */
    1447           2 :         torture_comment(tctx, "client1 opens fname3 via session 1\n");
    1448           2 :         smb2_lease_create(&io3, &ls3, false, fname3, LEASE1F3,
    1449             :                           smb2_util_lease_state("RHW"));
    1450           2 :         status = smb2_create(tree1, mem_ctx, &io3);
    1451           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    1452           2 :         h_client1_file3 = io3.out.file.handle;
    1453           2 :         CHECK_CREATED(&io3, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
    1454           2 :         CHECK_LEASE(&io3, "RH", true, LEASE1F3, 0);
    1455           2 :         CHECK_BREAK_INFO("RHW", "RH", LEASE2F3);
    1456           2 :         CHECK_VAL(lease_break_info.count, 1);
    1457             : 
    1458             :         /* cleanup everything */
    1459           2 :         torture_reset_lease_break_info(tctx, &lease_break_info);
    1460             : 
    1461           2 :         smb2_util_close(tree1, h_client1_file1);
    1462           2 :         smb2_util_close(tree1, h_client1_file2);
    1463           2 :         smb2_util_close(tree1, h_client1_file3);
    1464           2 :         smb2_util_close(tree2A, h_client2_file1);
    1465           2 :         smb2_util_close(tree2A, h_client2_file2);
    1466           2 :         smb2_util_close(tree2A, h_client2_file3);
    1467             : 
    1468           2 :         smb2_util_unlink(tree1, fname1);
    1469           2 :         smb2_util_unlink(tree1, fname2);
    1470           2 :         smb2_util_unlink(tree1, fname3);
    1471           2 :         CHECK_VAL(lease_break_info.count, 0);
    1472           2 :         test_multichannel_free_channels(tree2A, tree2B, tree2C);
    1473           2 :         tree2A = tree2B = tree2C = NULL;
    1474           4 : done:
    1475           4 :         tree1->session = session1;
    1476             : 
    1477           4 :         smb2_util_close(tree1, h_client1_file1);
    1478           4 :         smb2_util_close(tree1, h_client1_file2);
    1479           4 :         smb2_util_close(tree1, h_client1_file3);
    1480           4 :         if (tree2A != NULL) {
    1481           2 :                 smb2_util_close(tree2A, h_client2_file1);
    1482           2 :                 smb2_util_close(tree2A, h_client2_file2);
    1483           2 :                 smb2_util_close(tree2A, h_client2_file3);
    1484             :         }
    1485             : 
    1486           4 :         if (h != NULL) {
    1487           0 :                 smb2_util_close(tree1, *h);
    1488             :         }
    1489             : 
    1490           4 :         smb2_util_unlink(tree1, fname1);
    1491           4 :         smb2_util_unlink(tree1, fname2);
    1492           4 :         smb2_util_unlink(tree1, fname3);
    1493           4 :         smb2_deltree(tree1, BASEDIR);
    1494             : 
    1495           4 :         test_multichannel_free_channels(tree2A, tree2B, tree2C);
    1496           4 :         talloc_free(tree1);
    1497           4 :         talloc_free(mem_ctx);
    1498             : 
    1499           4 :         return ret;
    1500             : }
    1501             : 
    1502             : /*
    1503             :  * Lease Break Test 2:
    1504             :  * Test for lease break retries being sent by the server.
    1505             :  *      Connect 2A, 2B
    1506             :  *      open file1 in session 2A
    1507             :  *      open file2 in session 2B
    1508             :  *      block 2A
    1509             :  *      open file2 in session 1
    1510             :  *           lease break retry reaches the client?
    1511             :  *      Connect 2C
    1512             :  *      open file3 in session 2C
    1513             :  *      unblock 2A
    1514             :  *      open file1 in session 1
    1515             :  *           lease break reaches the client?
    1516             :  *      open file3 in session 1
    1517             :  *           lease break reached the client?
    1518             :  *      Cleanup
    1519             :  *           On deletion by 1, lease breaks sent for file1, file2 and file3
    1520             :  *           on 2B
    1521             :  *           This changes RH lease to R for Session 2.
    1522             :  *           (This has been disabled while we add support for sending lease
    1523             :  *            break for handle leases.)
    1524             :  */
    1525           4 : static bool test_multichannel_lease_break_test2(struct torture_context *tctx,
    1526             :                                                 struct smb2_tree *tree1)
    1527             : {
    1528           4 :         const char *host = torture_setting_string(tctx, "host", NULL);
    1529           4 :         const char *share = torture_setting_string(tctx, "share", NULL);
    1530           4 :         struct cli_credentials *credentials = samba_cmdline_get_creds();
    1531             :         NTSTATUS status;
    1532           4 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
    1533             :         struct smb2_handle _h;
    1534           4 :         struct smb2_handle *h = NULL;
    1535           4 :         struct smb2_handle h_client1_file1 = {{0}};
    1536           4 :         struct smb2_handle h_client1_file2 = {{0}};
    1537           4 :         struct smb2_handle h_client1_file3 = {{0}};
    1538           4 :         struct smb2_handle h_client2_file1 = {{0}};
    1539           4 :         struct smb2_handle h_client2_file2 = {{0}};
    1540           4 :         struct smb2_handle h_client2_file3 = {{0}};
    1541             :         struct smb2_create io1, io2, io3;
    1542           4 :         bool ret = true;
    1543           4 :         const char *fname1 = BASEDIR "\\lease_break_test1.dat";
    1544           4 :         const char *fname2 = BASEDIR "\\lease_break_test2.dat";
    1545           4 :         const char *fname3 = BASEDIR "\\lease_break_test3.dat";
    1546           4 :         struct smb2_tree *tree2A = NULL;
    1547           4 :         struct smb2_tree *tree2B = NULL;
    1548           4 :         struct smb2_tree *tree2C = NULL;
    1549           4 :         struct smb2_transport *transport1 = tree1->session->transport;
    1550           4 :         struct smb2_transport *transport2A = NULL;
    1551             :         struct smbcli_options transport2_options;
    1552           4 :         struct smb2_session *session1 = tree1->session;
    1553           4 :         uint16_t local_port = 0;
    1554             :         struct smb2_lease ls1;
    1555             :         struct smb2_lease ls2;
    1556             :         struct smb2_lease ls3;
    1557           4 :         bool block_setup = false;
    1558           4 :         bool block_ok = false;
    1559           4 :         bool unblock_ok = false;
    1560             : 
    1561             : 
    1562           4 :         if (!test_multichannel_initial_checks(tctx, tree1)) {
    1563           0 :                 return true;
    1564             :         }
    1565             : 
    1566           4 :         torture_comment(tctx, "Lease break retry: Test2\n");
    1567             : 
    1568           4 :         torture_reset_lease_break_info(tctx, &lease_break_info);
    1569             : 
    1570           4 :         transport1->lease.handler = torture_lease_handler;
    1571           4 :         transport1->lease.private_data = tree1;
    1572           4 :         torture_comment(tctx, "transport1  [%p]\n", transport1);
    1573           4 :         local_port = torture_get_local_port_from_transport(transport1);
    1574           4 :         torture_comment(tctx, "transport1 uses tcp port: %d\n", local_port);
    1575             : 
    1576           4 :         status = torture_smb2_testdir(tree1, BASEDIR, &_h);
    1577           4 :         CHECK_STATUS(status, NT_STATUS_OK);
    1578           4 :         smb2_util_close(tree1, _h);
    1579           4 :         smb2_util_unlink(tree1, fname1);
    1580           4 :         smb2_util_unlink(tree1, fname2);
    1581           4 :         smb2_util_unlink(tree1, fname3);
    1582           4 :         CHECK_VAL(lease_break_info.count, 0);
    1583             : 
    1584           4 :         smb2_lease_create(&io1, &ls1, false, fname1, LEASE2F1,
    1585             :                           smb2_util_lease_state("RHW"));
    1586           4 :         test_multichannel_init_smb_create(&io1);
    1587             : 
    1588           4 :         smb2_lease_create(&io2, &ls2, false, fname2, LEASE2F2,
    1589             :                           smb2_util_lease_state("RHW"));
    1590           4 :         test_multichannel_init_smb_create(&io2);
    1591             : 
    1592           4 :         smb2_lease_create(&io3, &ls3, false, fname3, LEASE2F3,
    1593             :                           smb2_util_lease_state("RHW"));
    1594           4 :         test_multichannel_init_smb_create(&io3);
    1595             : 
    1596           4 :         transport2_options = transport1->options;
    1597             : 
    1598           4 :         ret = test_multichannel_create_channels(tctx, host, share,
    1599             :                                                   credentials,
    1600             :                                                   &transport2_options,
    1601             :                                                   &tree2A, &tree2B, NULL);
    1602           4 :         torture_assert(tctx, ret, "Could not create channels.\n");
    1603           4 :         transport2A = tree2A->session->transport;
    1604             : 
    1605             :         /* 2a opens file1 */
    1606           4 :         torture_comment(tctx, "client2 opens fname1 via session 2A\n");
    1607           4 :         smb2_lease_create(&io1, &ls1, false, fname1, LEASE2F1,
    1608             :                           smb2_util_lease_state("RHW"));
    1609           4 :         status = smb2_create(tree2A, mem_ctx, &io1);
    1610           4 :         CHECK_STATUS(status, NT_STATUS_OK);
    1611           4 :         h_client2_file1 = io1.out.file.handle;
    1612           4 :         CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
    1613           4 :         CHECK_LEASE(&io1, "RHW", true, LEASE2F1, 0);
    1614           2 :         CHECK_VAL(io1.out.durable_open_v2, false); //true);
    1615           2 :         CHECK_VAL(io1.out.timeout, io1.in.timeout);
    1616           2 :         CHECK_VAL(io1.out.durable_open, false);
    1617           2 :         CHECK_VAL(lease_break_info.count, 0);
    1618             : 
    1619             :         /* 2b opens file2 */
    1620           2 :         torture_comment(tctx, "client2 opens fname2 via session 2B\n");
    1621           2 :         smb2_lease_create(&io2, &ls2, false, fname2, LEASE2F2,
    1622             :                           smb2_util_lease_state("RHW"));
    1623           2 :         status = smb2_create(tree2B, mem_ctx, &io2);
    1624           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    1625           2 :         h_client2_file2 = io2.out.file.handle;
    1626           2 :         CHECK_CREATED(&io2, CREATED, FILE_ATTRIBUTE_ARCHIVE);
    1627           2 :         CHECK_LEASE(&io2, "RHW", true, LEASE2F2, 0);
    1628           2 :         CHECK_VAL(io2.out.durable_open_v2, false); //true);
    1629           2 :         CHECK_VAL(io2.out.timeout, io2.in.timeout);
    1630           2 :         CHECK_VAL(io2.out.durable_open, false);
    1631           2 :         CHECK_VAL(lease_break_info.count, 0);
    1632             : 
    1633           2 :         block_setup = test_setup_blocked_transports(tctx);
    1634           2 :         torture_assert(tctx, block_setup, "test_setup_blocked_transports");
    1635             : 
    1636           2 :         torture_comment(tctx, "Blocking 2A\n");
    1637             :         /* Block 2A */
    1638           2 :         block_ok = test_block_smb2_transport(tctx, transport2A);
    1639           2 :         torture_assert(tctx, block_ok, "we could not block tcp transport");
    1640             : 
    1641           2 :         torture_wait_for_lease_break(tctx);
    1642           2 :         CHECK_VAL(lease_break_info.count, 0);
    1643             : 
    1644             :         /* 1 opens file2 */
    1645           2 :         torture_comment(tctx,
    1646             :                         "Client opens fname2 with session1 with 2A blocked\n");
    1647           2 :         smb2_lease_create(&io2, &ls2, false, fname2, LEASE1F2,
    1648             :                           smb2_util_lease_state("RHW"));
    1649           2 :         status = smb2_create(tree1, mem_ctx, &io2);
    1650           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    1651           2 :         h_client1_file2 = io2.out.file.handle;
    1652           2 :         CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
    1653           2 :         CHECK_LEASE(&io2, "RH", true, LEASE1F2, 0);
    1654           2 :         CHECK_VAL(io2.out.durable_open_v2, false);
    1655           2 :         CHECK_VAL(io2.out.timeout, 0);
    1656           2 :         CHECK_VAL(io2.out.durable_open, false);
    1657             : 
    1658           2 :         if (lease_break_info.count == 0) {
    1659           0 :                 torture_comment(tctx,
    1660             :                                 "Did not receive expected lease break!!\n");
    1661             :         } else {
    1662           2 :                 torture_comment(tctx, "Received %d lease break(s)!!\n",
    1663             :                                 lease_break_info.count);
    1664             :         }
    1665             : 
    1666             :         /*
    1667             :          * We got breaks on both channels
    1668             :          * (one failed on the blocked connection)
    1669             :          */
    1670           2 :         CHECK_VAL(lease_break_info.count, 2);
    1671           2 :         lease_break_info.count -= 1;
    1672           2 :         CHECK_VAL(lease_break_info.failures, 1);
    1673           2 :         lease_break_info.failures -= 1;
    1674           2 :         CHECK_BREAK_INFO("RHW", "RH", LEASE2F2);
    1675           2 :         torture_reset_lease_break_info(tctx, &lease_break_info);
    1676             : 
    1677             :         /* Connect 2C */
    1678           2 :         torture_comment(tctx, "Connecting session 2C\n");
    1679           2 :         talloc_free(tree2C);
    1680           2 :         tree2C = test_multichannel_create_channel(tctx, host, share,
    1681             :                                 credentials, &transport2_options, tree2A);
    1682           2 :         if (!tree2C) {
    1683           0 :                 goto done;
    1684             :         }
    1685             : 
    1686             :         /* 2c opens file3 */
    1687           2 :         torture_comment(tctx, "client2 opens fname3 via session 2C\n");
    1688           2 :         smb2_lease_create(&io3, &ls3, false, fname3, LEASE2F3,
    1689             :                           smb2_util_lease_state("RHW"));
    1690           2 :         status = smb2_create(tree2C, mem_ctx, &io3);
    1691           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    1692           2 :         h_client2_file3 = io3.out.file.handle;
    1693           2 :         CHECK_CREATED(&io3, CREATED, FILE_ATTRIBUTE_ARCHIVE);
    1694           2 :         CHECK_LEASE(&io3, "RHW", true, LEASE2F3, 0);
    1695           2 :         CHECK_VAL(io3.out.durable_open_v2, false);
    1696           2 :         CHECK_VAL(io3.out.timeout, io2.in.timeout);
    1697           2 :         CHECK_VAL(io3.out.durable_open, false);
    1698           2 :         CHECK_VAL(lease_break_info.count, 0);
    1699             : 
    1700             :         /* Unblock 2A */
    1701           2 :         torture_comment(tctx, "Unblocking 2A\n");
    1702           2 :         unblock_ok = test_unblock_smb2_transport(tctx, transport2A);
    1703           2 :         torture_assert(tctx, unblock_ok, "we could not unblock tcp transport");
    1704             : 
    1705             :         /* 1 opens file1 */
    1706           2 :         torture_comment(tctx, "Client opens fname1 with session 1\n");
    1707           2 :         smb2_lease_create(&io1, &ls1, false, fname1, LEASE1F1,
    1708             :                           smb2_util_lease_state("RHW"));
    1709           2 :         status = smb2_create(tree1, mem_ctx, &io1);
    1710           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    1711           2 :         h_client1_file1 = io1.out.file.handle;
    1712           2 :         CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
    1713           2 :         CHECK_LEASE(&io1, "RH", true, LEASE1F1, 0);
    1714             : 
    1715           2 :         if (lease_break_info.count == 0) {
    1716           0 :                 torture_comment(tctx,
    1717             :                                 "Did not receive expected lease break!!\n");
    1718             :         } else {
    1719           2 :                 torture_comment(tctx,
    1720             :                                 "Received %d lease break(s)!!\n",
    1721             :                                 lease_break_info.count);
    1722             :         }
    1723           2 :         CHECK_VAL(lease_break_info.count, 1);
    1724           2 :         CHECK_BREAK_INFO("RHW", "RH", LEASE2F1);
    1725           2 :         torture_reset_lease_break_info(tctx, &lease_break_info);
    1726             : 
    1727             :         /*1 opens file3 */
    1728           2 :         torture_comment(tctx, "client opens fname3 via session 1\n");
    1729             : 
    1730           2 :         smb2_lease_create(&io3, &ls3, false, fname3, LEASE1F3,
    1731             :                           smb2_util_lease_state("RHW"));
    1732           2 :         status = smb2_create(tree1, mem_ctx, &io3);
    1733           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    1734           2 :         h_client1_file3 = io3.out.file.handle;
    1735           2 :         CHECK_CREATED(&io3, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
    1736           2 :         CHECK_LEASE(&io3, "RH", true, LEASE1F3, 0);
    1737             : 
    1738           2 :         if (lease_break_info.count == 0) {
    1739           0 :                 torture_comment(tctx,
    1740             :                                 "Did not receive expected lease break!!\n");
    1741             :         } else {
    1742           2 :                 torture_comment(tctx,
    1743             :                                 "Received %d lease break(s)!!\n",
    1744             :                                 lease_break_info.count);
    1745             :         }
    1746           2 :         CHECK_VAL(lease_break_info.count, 1);
    1747           2 :         CHECK_BREAK_INFO("RHW", "RH", LEASE2F3);
    1748           2 :         torture_reset_lease_break_info(tctx, &lease_break_info);
    1749             : 
    1750           2 :         smb2_util_close(tree1, h_client1_file1);
    1751           2 :         smb2_util_close(tree1, h_client1_file2);
    1752           2 :         smb2_util_close(tree1, h_client1_file3);
    1753             : 
    1754             :         /*
    1755             :          * Session 2 still has RW lease on file 1. Deletion of this file by 1
    1756             :          *  leads to a lease break call to session 2 file1
    1757             :          */
    1758           2 :         smb2_util_unlink(tree1, fname1);
    1759             :         /*
    1760             :          * Bug - Samba does not revoke Handle lease on unlink
    1761             :          * CHECK_BREAK_INFO("RH", "R", LEASE2F1);
    1762             :          */
    1763           2 :         torture_reset_lease_break_info(tctx, &lease_break_info);
    1764             : 
    1765             :         /*
    1766             :          * Session 2 still has RW lease on file 2. Deletion of this file by 1
    1767             :          *  leads to a lease break call to session 2 file2
    1768             :          */
    1769           2 :         smb2_util_unlink(tree1, fname2);
    1770             :         /*
    1771             :          * Bug - Samba does not revoke Handle lease on unlink
    1772             :          * CHECK_BREAK_INFO("RH", "R", LEASE2F2);
    1773             :          */
    1774           2 :         torture_reset_lease_break_info(tctx, &lease_break_info);
    1775             : 
    1776             :         /*
    1777             :          * Session 2 still has RW lease on file 3. Deletion of this file by 1
    1778             :          *  leads to a lease break call to session 2 file3
    1779             :          */
    1780           2 :         smb2_util_unlink(tree1, fname3);
    1781             :         /*
    1782             :          * Bug - Samba does not revoke Handle lease on unlink
    1783             :          * CHECK_BREAK_INFO("RH", "R", LEASE2F3);
    1784             :          */
    1785           2 :         torture_reset_lease_break_info(tctx, &lease_break_info);
    1786             : 
    1787           2 :         smb2_util_close(tree2C, h_client2_file1);
    1788           2 :         smb2_util_close(tree2C, h_client2_file2);
    1789           2 :         smb2_util_close(tree2C, h_client2_file3);
    1790             : 
    1791           2 :         test_multichannel_free_channels(tree2A, tree2B, tree2C);
    1792           2 :         tree2A = tree2B = tree2C = NULL;
    1793             : 
    1794           4 : done:
    1795           4 :         if (block_ok && !unblock_ok) {
    1796           0 :                 test_unblock_smb2_transport(tctx, transport2A);
    1797             :         }
    1798           4 :         if (block_setup) {
    1799           2 :                 test_cleanup_blocked_transports(tctx);
    1800             :         }
    1801             : 
    1802           4 :         tree1->session = session1;
    1803             : 
    1804           4 :         smb2_util_close(tree1, h_client1_file1);
    1805           4 :         smb2_util_close(tree1, h_client1_file2);
    1806           4 :         smb2_util_close(tree1, h_client1_file3);
    1807           4 :         if (tree2A != NULL) {
    1808           2 :                 smb2_util_close(tree2A, h_client2_file1);
    1809           2 :                 smb2_util_close(tree2A, h_client2_file2);
    1810           2 :                 smb2_util_close(tree2A, h_client2_file3);
    1811             :         }
    1812             : 
    1813           4 :         if (h != NULL) {
    1814           0 :                 smb2_util_close(tree1, *h);
    1815             :         }
    1816             : 
    1817           4 :         smb2_util_unlink(tree1, fname1);
    1818           4 :         smb2_util_unlink(tree1, fname2);
    1819           4 :         smb2_util_unlink(tree1, fname3);
    1820           4 :         smb2_deltree(tree1, BASEDIR);
    1821             : 
    1822           4 :         test_multichannel_free_channels(tree2A, tree2B, tree2C);
    1823           4 :         talloc_free(tree1);
    1824           4 :         talloc_free(mem_ctx);
    1825             : 
    1826           4 :         return ret;
    1827             : }
    1828             : 
    1829             : /*
    1830             :  * Test 3: Check to see how the server behaves if lease break
    1831             :  *      response is sent over a different channel to one over which
    1832             :  *      the break is received.
    1833             :  *      Connect 2A, 2B
    1834             :  *      open file1 in session 2A
    1835             :  *      open file1 in session 1
    1836             :  *           Lease break sent to 2A
    1837             :  *           2B sends back lease break reply.
    1838             :  *      session 1 allowed to open file
    1839             :  */
    1840           4 : static bool test_multichannel_lease_break_test3(struct torture_context *tctx,
    1841             :                                                 struct smb2_tree *tree1)
    1842             : {
    1843           4 :         const char *host = torture_setting_string(tctx, "host", NULL);
    1844           4 :         const char *share = torture_setting_string(tctx, "share", NULL);
    1845           4 :         struct cli_credentials *credentials = samba_cmdline_get_creds();
    1846             :         NTSTATUS status;
    1847           4 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
    1848             :         struct smb2_handle _h;
    1849           4 :         struct smb2_handle *h = NULL;
    1850           4 :         struct smb2_handle h_client1_file1 = {{0}};
    1851           4 :         struct smb2_handle h_client2_file1 = {{0}};
    1852             :         struct smb2_create io1;
    1853           4 :         bool ret = true;
    1854           4 :         const char *fname1 = BASEDIR "\\lease_break_test1.dat";
    1855           4 :         struct smb2_tree *tree2A = NULL;
    1856           4 :         struct smb2_tree *tree2B = NULL;
    1857           4 :         struct smb2_transport *transport1 = tree1->session->transport;
    1858           4 :         struct smb2_transport *transport2A = NULL;
    1859             :         struct smbcli_options transport2_options;
    1860           4 :         uint16_t local_port = 0;
    1861             :         struct smb2_lease ls1;
    1862           4 :         struct tevent_timer *te = NULL;
    1863             :         struct timeval ne;
    1864           4 :         bool timesup = false;
    1865           4 :         TALLOC_CTX *tmp_ctx = talloc_new(NULL);
    1866             : 
    1867           4 :         if (!test_multichannel_initial_checks(tctx, tree1)) {
    1868           0 :                 return true;
    1869             :         }
    1870             : 
    1871           4 :         torture_comment(tctx, "Lease break retry: Test3\n");
    1872             : 
    1873           4 :         torture_reset_lease_break_info(tctx, &lease_break_info);
    1874             : 
    1875           4 :         transport1->lease.handler = torture_lease_handler;
    1876           4 :         transport1->lease.private_data = tree1;
    1877           4 :         torture_comment(tctx, "transport1  [%p]\n", transport1);
    1878           4 :         local_port = torture_get_local_port_from_transport(transport1);
    1879           4 :         torture_comment(tctx, "transport1 uses tcp port: %d\n", local_port);
    1880             : 
    1881           4 :         status = torture_smb2_testdir(tree1, BASEDIR, &_h);
    1882           4 :         CHECK_STATUS(status, NT_STATUS_OK);
    1883           4 :         smb2_util_close(tree1, _h);
    1884           4 :         smb2_util_unlink(tree1, fname1);
    1885           4 :         CHECK_VAL(lease_break_info.count, 0);
    1886             : 
    1887           4 :         smb2_lease_create(&io1, &ls1, false, fname1, LEASE2F1,
    1888             :                           smb2_util_lease_state("RHW"));
    1889           4 :         test_multichannel_init_smb_create(&io1);
    1890             : 
    1891           4 :         transport2_options = transport1->options;
    1892             : 
    1893           4 :         ret = test_multichannel_create_channels(tctx, host, share,
    1894             :                                                 credentials,
    1895             :                                                 &transport2_options,
    1896             :                                                 &tree2A, &tree2B, NULL);
    1897           4 :         torture_assert(tctx, ret, "Could not create channels.\n");
    1898           4 :         transport2A = tree2A->session->transport;
    1899           4 :         transport2A->lease.private_data = tree2B;
    1900             : 
    1901             :         /* 2a opens file1 */
    1902           4 :         torture_comment(tctx, "client2 opens fname1 via session 2A\n");
    1903           4 :         smb2_lease_create(&io1, &ls1, false, fname1, LEASE2F1,
    1904             :                           smb2_util_lease_state("RHW"));
    1905           4 :         status = smb2_create(tree2A, mem_ctx, &io1);
    1906           4 :         CHECK_STATUS(status, NT_STATUS_OK);
    1907           4 :         h_client2_file1 = io1.out.file.handle;
    1908           4 :         CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
    1909           4 :         CHECK_LEASE(&io1, "RHW", true, LEASE2F1, 0);
    1910           2 :         CHECK_VAL(io1.out.durable_open_v2, false); //true);
    1911           2 :         CHECK_VAL(io1.out.timeout, io1.in.timeout);
    1912           2 :         CHECK_VAL(io1.out.durable_open, false);
    1913           2 :         CHECK_VAL(lease_break_info.count, 0);
    1914             : 
    1915             :         /* Set a timeout for 5 seconds for session 1 to open file1 */
    1916           2 :         ne = tevent_timeval_current_ofs(0, 5000000);
    1917           2 :         te = tevent_add_timer(tctx->ev, tmp_ctx, ne, timeout_cb, &timesup);
    1918           2 :         if (te == NULL) {
    1919           0 :                 torture_comment(tctx, "Failed to add timer.");
    1920           0 :                 goto done;
    1921             :         }
    1922             : 
    1923             :         /* 1 opens file2 */
    1924           2 :         torture_comment(tctx, "Client opens fname1 with session 1\n");
    1925           2 :         smb2_lease_create(&io1, &ls1, false, fname1, LEASE1F1,
    1926             :                           smb2_util_lease_state("RHW"));
    1927           2 :         status = smb2_create(tree1, mem_ctx, &io1);
    1928           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    1929           2 :         h_client1_file1 = io1.out.file.handle;
    1930           2 :         CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
    1931           2 :         CHECK_LEASE(&io1, "RH", true, LEASE1F1, 0);
    1932           2 :         CHECK_VAL(io1.out.durable_open_v2, false);
    1933           2 :         CHECK_VAL(io1.out.timeout, 0);
    1934           2 :         CHECK_VAL(io1.out.durable_open, false);
    1935             : 
    1936           2 :         CHECK_VAL(lease_break_info.count, 1);
    1937           2 :         CHECK_BREAK_INFO("RHW", "RH", LEASE2F1);
    1938             : 
    1939             :         /*
    1940             :          * Check if timeout handler was fired. This would indicate
    1941             :          * that the server didn't receive a reply for the oplock break
    1942             :          * from the client and the server let session 1 open the file
    1943             :          * only after the oplock break timeout.
    1944             :          */
    1945           2 :         CHECK_VAL(timesup, false);
    1946             : 
    1947           6 : done:
    1948           4 :         smb2_util_close(tree1, h_client1_file1);
    1949           4 :         if (tree2A != NULL) {
    1950           4 :                 smb2_util_close(tree2A, h_client2_file1);
    1951             :         }
    1952             : 
    1953           4 :         if (h != NULL) {
    1954           0 :                 smb2_util_close(tree1, *h);
    1955             :         }
    1956             : 
    1957           4 :         smb2_util_unlink(tree1, fname1);
    1958           4 :         smb2_deltree(tree1, BASEDIR);
    1959             : 
    1960           4 :         test_multichannel_free_channels(tree2A, tree2B, NULL);
    1961           4 :         talloc_free(tree1);
    1962           4 :         talloc_free(mem_ctx);
    1963             : 
    1964           4 :         return ret;
    1965             : }
    1966             : 
    1967             : /*
    1968             :  * Test limits of channels
    1969             :  */
    1970           4 : static bool test_multichannel_num_channels(struct torture_context *tctx,
    1971             :                                            struct smb2_tree *tree1)
    1972             : {
    1973           4 :         const char *host = torture_setting_string(tctx, "host", NULL);
    1974           4 :         const char *share = torture_setting_string(tctx, "share", NULL);
    1975           4 :         struct cli_credentials *credentials = samba_cmdline_get_creds();
    1976           4 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
    1977           4 :         bool ret = true;
    1978           4 :         struct smb2_tree **tree2 = NULL;
    1979           4 :         struct smb2_transport *transport1 = tree1->session->transport;
    1980           4 :         struct smb2_transport **transport2 = NULL;
    1981             :         struct smbcli_options transport2_options;
    1982           4 :         struct smb2_session **session2 = NULL;
    1983             :         uint32_t server_capabilities;
    1984             :         int i;
    1985           4 :         int max_channels = 33; /* 32 is the W2K12R2 and W2K16 limit */
    1986             : 
    1987           4 :         if (smbXcli_conn_protocol(transport1->conn) < PROTOCOL_SMB3_00) {
    1988           0 :                 torture_fail(tctx,
    1989             :                              "SMB 3.X Dialect family required for Multichannel"
    1990             :                              " tests\n");
    1991             :         }
    1992             : 
    1993           4 :         server_capabilities = smb2cli_conn_server_capabilities(
    1994           4 :                                         tree1->session->transport->conn);
    1995           4 :         if (!(server_capabilities & SMB2_CAP_MULTI_CHANNEL)) {
    1996           0 :                 torture_fail(tctx,
    1997             :                              "Server does not support multichannel.");
    1998             :         }
    1999             : 
    2000           4 :         torture_comment(tctx, "Testing max. number of channels\n");
    2001             : 
    2002           4 :         transport2_options = transport1->options;
    2003           4 :         transport2_options.client_guid = GUID_random();
    2004             : 
    2005           4 :         tree2           = talloc_zero_array(mem_ctx, struct smb2_tree *,
    2006             :                                             max_channels);
    2007           4 :         transport2      = talloc_zero_array(mem_ctx, struct smb2_transport *,
    2008             :                                             max_channels);
    2009           4 :         session2        = talloc_zero_array(mem_ctx, struct smb2_session *,
    2010             :                                             max_channels);
    2011           4 :         if (tree2 == NULL || transport2 == NULL || session2 == NULL) {
    2012           0 :                 torture_fail(tctx, "out of memory");
    2013             :         }
    2014             : 
    2015         136 :         for (i = 0; i < max_channels; i++) {
    2016             : 
    2017             :                 NTSTATUS expected_status;
    2018             : 
    2019         132 :                 torture_assert_ntstatus_ok_goto(tctx,
    2020             :                         smb2_connect(tctx,
    2021             :                                 host,
    2022             :                                 lpcfg_smb_ports(tctx->lp_ctx),
    2023             :                                 share,
    2024             :                                 lpcfg_resolve_context(tctx->lp_ctx),
    2025             :                                 credentials,
    2026             :                                 &tree2[i],
    2027             :                                 tctx->ev,
    2028             :                                 &transport2_options,
    2029             :                                 lpcfg_socket_options(tctx->lp_ctx),
    2030             :                                 lpcfg_gensec_settings(tctx, tctx->lp_ctx)
    2031             :                                 ),
    2032             :                         ret, done, "smb2_connect failed");
    2033             : 
    2034         132 :                 transport2[i] = tree2[i]->session->transport;
    2035             : 
    2036         132 :                 if (i == 0) {
    2037             :                         /*
    2038             :                          * done for the 1st channel
    2039             :                          *
    2040             :                          * For all remaining channels we do the
    2041             :                          * session setup on our own.
    2042             :                          */
    2043           4 :                         transport2_options.only_negprot = true;
    2044           4 :                         continue;
    2045             :                 }
    2046             : 
    2047             :                 /*
    2048             :                  * Now bind the session2[i] to the transport2
    2049             :                  */
    2050         128 :                 session2[i] = smb2_session_channel(transport2[i],
    2051             :                                                    lpcfg_gensec_settings(tctx,
    2052             :                                                                  tctx->lp_ctx),
    2053             :                                                    tree2[0],
    2054         128 :                                                    tree2[0]->session);
    2055             : 
    2056         128 :                 torture_assert(tctx, session2[i] != NULL,
    2057             :                                "smb2_session_channel failed");
    2058             : 
    2059         128 :                 torture_comment(tctx, "established transport2 [#%d]\n", i);
    2060             : 
    2061         128 :                 if (i >= 32) {
    2062           4 :                         expected_status = NT_STATUS_INSUFFICIENT_RESOURCES;
    2063             :                 } else {
    2064         124 :                         expected_status = NT_STATUS_OK;
    2065             :                 }
    2066             : 
    2067         128 :                 torture_assert_ntstatus_equal_goto(tctx,
    2068             :                         smb2_session_setup_spnego(session2[i],
    2069             :                                 samba_cmdline_get_creds(),
    2070             :                                 0 /* previous_session_id */),
    2071             :                         expected_status,
    2072             :                         ret, done,
    2073             :                         talloc_asprintf(tctx, "failed to establish session "
    2074             :                                               "setup for channel #%d", i));
    2075             : 
    2076         128 :                 torture_comment(tctx, "bound session2 [#%d] to session2 [0]\n",
    2077             :                                 i);
    2078             :         }
    2079             : 
    2080           4 :  done:
    2081           4 :         talloc_free(mem_ctx);
    2082             : 
    2083           4 :         return ret;
    2084             : }
    2085             : 
    2086             : struct test_multichannel_lease_break_state;
    2087             : 
    2088             : struct test_multichannel_lease_break_channel {
    2089             :         struct test_multichannel_lease_break_state *state;
    2090             :         size_t idx;
    2091             :         char name[64];
    2092             :         struct smb2_tree *tree;
    2093             :         bool blocked;
    2094             :         struct timeval break_time;
    2095             :         double full_duration;
    2096             :         double relative_duration;
    2097             :         struct smb2_lease_break lb;
    2098             :         size_t break_num;
    2099             : };
    2100             : 
    2101             : struct test_multichannel_lease_break_state {
    2102             :         struct torture_context *tctx;
    2103             :         struct timeval open_req_time;
    2104             :         struct timeval open_rep_time;
    2105             :         size_t num_breaks;
    2106             :         struct timeval last_break_time;
    2107             :         struct test_multichannel_lease_break_channel channels[32];
    2108             : };
    2109             : 
    2110          64 : static bool test_multichannel_lease_break_handler(struct smb2_transport *transport,
    2111             :                                                   const struct smb2_lease_break *lb,
    2112             :                                                   void *private_data)
    2113             : {
    2114          64 :         struct test_multichannel_lease_break_channel *c =
    2115             :                 (struct test_multichannel_lease_break_channel *)private_data;
    2116          64 :         struct test_multichannel_lease_break_state *state = c->state;
    2117             : 
    2118          64 :         c->break_time = timeval_current();
    2119          64 :         c->full_duration = timeval_elapsed2(&state->open_req_time,
    2120          64 :                                             &c->break_time);
    2121          64 :         c->relative_duration = timeval_elapsed2(&state->last_break_time,
    2122          64 :                                                 &c->break_time);
    2123          64 :         state->last_break_time = c->break_time;
    2124          64 :         c->lb = *lb;
    2125          64 :         c->break_num = ++state->num_breaks;
    2126             : 
    2127         192 :         torture_comment(state->tctx, "Got LEASE break epoch[0x%x] %zu on %s after %f ( %f)\n",
    2128         128 :                         c->lb.new_epoch, c->break_num, c->name,
    2129             :                         c->relative_duration,
    2130             :                         c->full_duration);
    2131             : 
    2132          64 :         return torture_lease_handler(transport, lb, c->tree);
    2133             : }
    2134             : 
    2135           4 : static bool test_multichannel_lease_break_test4(struct torture_context *tctx,
    2136             :                                                 struct smb2_tree *tree1)
    2137             : {
    2138           4 :         const char *host = torture_setting_string(tctx, "host", NULL);
    2139           4 :         const char *share = torture_setting_string(tctx, "share", NULL);
    2140           4 :         struct cli_credentials *credentials = samba_cmdline_get_creds();
    2141             :         NTSTATUS status;
    2142           4 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
    2143           4 :         struct test_multichannel_lease_break_state state = {
    2144             :                 .tctx = tctx,
    2145             :         };
    2146           4 :         struct test_multichannel_lease_break_channel *open2_channel = NULL;
    2147             :         struct smb2_handle _h;
    2148           4 :         struct smb2_handle *h = NULL;
    2149           4 :         struct smb2_handle h_client1_file1 = {{0}};
    2150           4 :         struct smb2_handle h_client2_file1 = {{0}};
    2151             :         struct smb2_create io1;
    2152             :         struct smb2_create io2;
    2153           4 :         bool ret = true;
    2154           4 :         const char *fname1 = BASEDIR "\\lease_break_test4.dat";
    2155           4 :         struct smb2_tree *trees2[32] = { NULL, };
    2156             :         size_t i;
    2157           4 :         struct smb2_transport *transport1 = tree1->session->transport;
    2158             :         struct smbcli_options transport2_options;
    2159           4 :         struct smb2_session *session1 = tree1->session;
    2160           4 :         uint16_t local_port = 0;
    2161             :         struct smb2_lease ls1;
    2162             :         struct smb2_lease ls2;
    2163           4 :         bool block_setup = false;
    2164           4 :         bool block_ok = false;
    2165             :         double open_duration;
    2166             : 
    2167           4 :         if (!test_multichannel_initial_checks(tctx, tree1)) {
    2168           0 :                 return true;
    2169             :         }
    2170             : 
    2171           4 :         torture_comment(tctx, "Lease break retry: Test4\n");
    2172             : 
    2173           4 :         torture_reset_lease_break_info(tctx, &lease_break_info);
    2174           4 :         lease_break_info.lease_skip_ack = true;
    2175             : 
    2176           4 :         transport1->lease.handler = torture_lease_handler;
    2177           4 :         transport1->lease.private_data = tree1;
    2178           4 :         torture_comment(tctx, "transport1  [%p]\n", transport1);
    2179           4 :         local_port = torture_get_local_port_from_transport(transport1);
    2180           4 :         torture_comment(tctx, "transport1 uses tcp port: %d\n", local_port);
    2181             : 
    2182           4 :         status = torture_smb2_testdir(tree1, BASEDIR, &_h);
    2183           4 :         CHECK_STATUS(status, NT_STATUS_OK);
    2184           4 :         smb2_util_close(tree1, _h);
    2185           4 :         smb2_util_unlink(tree1, fname1);
    2186           4 :         CHECK_VAL(lease_break_info.count, 0);
    2187             : 
    2188           4 :         smb2_lease_v2_create(&io2, &ls2, false, fname1,
    2189             :                              LEASE2F1, NULL,
    2190             :                              smb2_util_lease_state("RHW"),
    2191             :                              0x20);
    2192             : 
    2193           4 :         transport2_options = transport1->options;
    2194             : 
    2195           4 :         ret = test_multichannel_create_channel_array(tctx, host, share, credentials,
    2196             :                                                      &transport2_options,
    2197             :                                                      ARRAY_SIZE(trees2), trees2);
    2198           4 :         torture_assert(tctx, ret, "Could not create channels.\n");
    2199             : 
    2200         132 :         for (i = 0; i < ARRAY_SIZE(trees2); i++) {
    2201         128 :                 struct test_multichannel_lease_break_channel *c = &state.channels[i];
    2202         128 :                 struct smb2_transport *t = trees2[i]->session->transport;
    2203             : 
    2204         128 :                 c->state = &state;
    2205         128 :                 c->idx = i+1;
    2206         128 :                 c->tree = trees2[i];
    2207         128 :                 snprintf(c->name, sizeof(c->name), "trees2_%zu", c->idx);
    2208             : 
    2209         128 :                 t->lease.handler = test_multichannel_lease_break_handler;
    2210         128 :                 t->lease.private_data = c;
    2211             :         }
    2212             : 
    2213           4 :         open2_channel = &state.channels[0];
    2214             : 
    2215             :         /* 2a opens file1 */
    2216           4 :         torture_comment(tctx, "client2 opens fname1 via %s\n",
    2217           4 :                         open2_channel->name);
    2218           4 :         status = smb2_create(open2_channel->tree, mem_ctx, &io2);
    2219           4 :         CHECK_STATUS(status, NT_STATUS_OK);
    2220           4 :         h_client2_file1 = io2.out.file.handle;
    2221           4 :         CHECK_CREATED(&io2, CREATED, FILE_ATTRIBUTE_ARCHIVE);
    2222           4 :         CHECK_LEASE_V2(&io2, "RHW", true, LEASE2F1, 0, 0, 0x21);
    2223           2 :         CHECK_VAL(io2.out.durable_open_v2, false);
    2224           2 :         CHECK_VAL(io2.out.timeout, io2.in.timeout);
    2225           2 :         CHECK_VAL(io2.out.durable_open, false);
    2226           2 :         CHECK_VAL(lease_break_info.count, 0);
    2227             : 
    2228           2 :         block_setup = test_setup_blocked_transports(tctx);
    2229           2 :         torture_assert(tctx, block_setup, "test_setup_blocked_transports");
    2230             : 
    2231          66 :         for (i = 0; i < ARRAY_SIZE(state.channels); i++) {
    2232          64 :                 struct test_multichannel_lease_break_channel *c = &state.channels[i];
    2233          64 :                 struct smb2_transport *t = c->tree->session->transport;
    2234             : 
    2235          64 :                 torture_comment(tctx, "Blocking %s\n", c->name);
    2236          64 :                 block_ok = _test_block_smb2_transport(tctx, t, c->name);
    2237          64 :                 torture_assert_goto(tctx, block_ok, ret, done, "we could not block tcp transport");
    2238          64 :                 c->blocked = true;
    2239             :         }
    2240             : 
    2241             :         /* 1 opens file2 */
    2242           2 :         torture_comment(tctx,
    2243             :                         "Client opens fname1 with session 1 with all %zu blocked\n",
    2244             :                         ARRAY_SIZE(trees2));
    2245           2 :         smb2_lease_v2_create(&io1, &ls1, false, fname1,
    2246             :                              LEASE1F1, NULL,
    2247             :                              smb2_util_lease_state("RHW"),
    2248             :                              0x10);
    2249           2 :         CHECK_VAL(lease_break_info.count, 0);
    2250           2 :         state.open_req_time = timeval_current();
    2251           2 :         state.last_break_time = state.open_req_time;
    2252           2 :         status = smb2_create(tree1, mem_ctx, &io1);
    2253           2 :         state.open_rep_time = timeval_current();
    2254           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    2255           2 :         h_client1_file1 = io1.out.file.handle;
    2256             : 
    2257           2 :         CHECK_VAL_GREATER_THAN(lease_break_info.count, 1);
    2258             : 
    2259           2 :         open_duration = timeval_elapsed2(&state.open_req_time,
    2260             :                                          &state.open_rep_time);
    2261           2 :         torture_comment(tctx, "open_duration: %f\n", open_duration);
    2262           2 :         if (lease_break_info.count < ARRAY_SIZE(state.channels)) {
    2263           2 :                 CHECK_VAL_GREATER_THAN(open_duration, 35);
    2264           2 :                 CHECK_LEASE_V2(&io1, "RH", true, LEASE1F1, 0, 0, 0x11);
    2265             :         } else {
    2266           0 :                 CHECK_LEASE_V2(&io1, "RWH", true, LEASE1F1, 0, 0, 0x11);
    2267             :         }
    2268             : 
    2269          10 :         for (i = 0; i < ARRAY_SIZE(state.channels); i++) {
    2270          10 :                 if (lease_break_info.count >= ARRAY_SIZE(state.channels)) {
    2271           2 :                         break;
    2272             :                 }
    2273           8 :                 torture_comment(tctx, "Received %d lease break(s) wait for more!!\n",
    2274             :                                 lease_break_info.count);
    2275           8 :                 torture_wait_for_lease_break(tctx);
    2276             :         }
    2277             : 
    2278           2 :         if (lease_break_info.count == 0) {
    2279           0 :                 torture_comment(tctx,
    2280             :                                 "Did not receive expected lease break!!\n");
    2281             :         } else {
    2282           2 :                 torture_comment(tctx, "Received %d lease break(s)!!\n",
    2283             :                                 lease_break_info.count);
    2284             :         }
    2285             : 
    2286           2 :         if (lease_break_info.count < ARRAY_SIZE(state.channels)) {
    2287           0 :                 CHECK_VAL_GREATER_THAN(lease_break_info.count, 3);
    2288             :         } else {
    2289           2 :                 CHECK_VAL(lease_break_info.count, ARRAY_SIZE(state.channels));
    2290             :         }
    2291             : 
    2292          66 :         for (i = 0; i < lease_break_info.count; i++) {
    2293          64 :                 struct test_multichannel_lease_break_channel *c = &state.channels[i];
    2294             : 
    2295          64 :                 torture_comment(tctx, "Verify %s\n", c->name);
    2296          64 :                 torture_assert_int_equal(tctx, c->break_num, c->idx,
    2297             :                                          "Got lease break in wrong order");
    2298          64 :                 CHECK_LEASE_BREAK_V2(c->lb, LEASE2F1, "RWH", "RH",
    2299             :                                      SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED,
    2300             :                                      0x22);
    2301             :         }
    2302             : 
    2303           2 : done:
    2304         132 :         for (i = 0; i < ARRAY_SIZE(state.channels); i++) {
    2305         128 :                 struct test_multichannel_lease_break_channel *c = &state.channels[i];
    2306         128 :                 struct smb2_transport *t = NULL;
    2307             : 
    2308         128 :                 if (!c->blocked) {
    2309          64 :                         continue;
    2310             :                 }
    2311             : 
    2312          64 :                 t = c->tree->session->transport;
    2313             : 
    2314          64 :                 torture_comment(tctx, "Unblocking %s\n", c->name);
    2315          64 :                 _test_unblock_smb2_transport(tctx, t, c->name);
    2316          64 :                 c->blocked = false;
    2317             :         }
    2318           4 :         if (block_setup) {
    2319           2 :                 test_cleanup_blocked_transports(tctx);
    2320             :         }
    2321             : 
    2322           4 :         tree1->session = session1;
    2323             : 
    2324           4 :         smb2_util_close(tree1, h_client1_file1);
    2325           4 :         if (trees2[0] != NULL) {
    2326           4 :                 smb2_util_close(trees2[0], h_client2_file1);
    2327             :         }
    2328             : 
    2329           4 :         if (h != NULL) {
    2330           0 :                 smb2_util_close(tree1, *h);
    2331             :         }
    2332             : 
    2333           4 :         smb2_util_unlink(tree1, fname1);
    2334           4 :         smb2_deltree(tree1, BASEDIR);
    2335             : 
    2336         132 :         for (i = 0; i < ARRAY_SIZE(trees2); i++) {
    2337         128 :                 if (trees2[i] == NULL) {
    2338           0 :                         continue;
    2339             :                 }
    2340         128 :                 TALLOC_FREE(trees2[i]);
    2341             :         }
    2342           4 :         talloc_free(tree1);
    2343           4 :         talloc_free(mem_ctx);
    2344             : 
    2345           4 :         return ret;
    2346             : }
    2347             : 
    2348        2353 : struct torture_suite *torture_smb2_multichannel_init(TALLOC_CTX *ctx)
    2349             : {
    2350        2353 :         struct torture_suite *suite = torture_suite_create(ctx, "multichannel");
    2351        2353 :         struct torture_suite *suite_generic = torture_suite_create(ctx,
    2352             :                                                                    "generic");
    2353        2353 :         struct torture_suite *suite_oplocks = torture_suite_create(ctx,
    2354             :                                                                    "oplocks");
    2355        2353 :         struct torture_suite *suite_leases = torture_suite_create(ctx,
    2356             :                                                                   "leases");
    2357             : 
    2358        2353 :         torture_suite_add_suite(suite, suite_generic);
    2359        2353 :         torture_suite_add_suite(suite, suite_oplocks);
    2360        2353 :         torture_suite_add_suite(suite, suite_leases);
    2361             : 
    2362        2353 :         torture_suite_add_1smb2_test(suite_generic, "interface_info",
    2363             :                                      test_multichannel_interface_info);
    2364        2353 :         torture_suite_add_1smb2_test(suite_generic, "num_channels",
    2365             :                                      test_multichannel_num_channels);
    2366        2353 :         torture_suite_add_1smb2_test(suite_oplocks, "test1",
    2367             :                                      test_multichannel_oplock_break_test1);
    2368        2353 :         torture_suite_add_1smb2_test(suite_oplocks, "test2",
    2369             :                                      test_multichannel_oplock_break_test2);
    2370        2353 :         torture_suite_add_1smb2_test(suite_oplocks, "test3_windows",
    2371             :                                      test_multichannel_oplock_break_test3_windows);
    2372        2353 :         torture_suite_add_1smb2_test(suite_oplocks, "test3_specification",
    2373             :                                      test_multichannel_oplock_break_test3_specification);
    2374        2353 :         torture_suite_add_1smb2_test(suite_leases, "test1",
    2375             :                                      test_multichannel_lease_break_test1);
    2376        2353 :         torture_suite_add_1smb2_test(suite_leases, "test2",
    2377             :                                      test_multichannel_lease_break_test2);
    2378        2353 :         torture_suite_add_1smb2_test(suite_leases, "test3",
    2379             :                                      test_multichannel_lease_break_test3);
    2380        2353 :         torture_suite_add_1smb2_test(suite_leases, "test4",
    2381             :                                      test_multichannel_lease_break_test4);
    2382             : 
    2383        2353 :         suite->description = talloc_strdup(suite, "SMB2 Multichannel tests");
    2384             : 
    2385        2353 :         return suite;
    2386             : }

Generated by: LCOV version 1.13