1 /*
2    Unix SMB/CIFS implementation.
3 
4    test suite for SMB2 leases
5 
6    Copyright (C) Zachary Loafman 2009
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 "torture/util.h"
23 
24 struct lease_break_info {
25 	struct torture_context *tctx;
26 
27 	struct smb2_lease_break lease_break;
28 	struct smb2_transport *lease_transport;
29 	bool lease_skip_ack;
30 	struct smb2_lease_break_ack lease_break_ack;
31 	int count;
32 	int failures;
33 
34 	struct smb2_handle oplock_handle;
35 	uint8_t held_oplock_level;
36 	uint8_t oplock_level;
37 	int oplock_count;
38 	int oplock_failures;
39 };
40 
41 #define CHECK_LEASE_BREAK(__lb, __oldstate, __state, __key)		\
42 	do {								\
43 		uint16_t __new = smb2_util_lease_state(__state); \
44 		uint16_t __old = smb2_util_lease_state(__oldstate); \
45 		CHECK_VAL((__lb)->new_lease_state, __new);	\
46 		CHECK_VAL((__lb)->current_lease.lease_state, __old); \
47 		CHECK_VAL((__lb)->current_lease.lease_key.data[0], (__key)); \
48 		CHECK_VAL((__lb)->current_lease.lease_key.data[1], ~(__key)); \
49 		if (__old & (SMB2_LEASE_WRITE | SMB2_LEASE_HANDLE)) { \
50 			CHECK_VAL((__lb)->break_flags, \
51 				  SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED);	\
52 		} else { \
53 			CHECK_VAL((__lb)->break_flags, 0); \
54 		} \
55 	} while(0)
56 
57 #define CHECK_LEASE_BREAK_ACK(__lba, __state, __key)			\
58 	do {								\
59 		CHECK_VAL((__lba)->out.reserved, 0);			\
60 		CHECK_VAL((__lba)->out.lease.lease_key.data[0], (__key)); \
61 		CHECK_VAL((__lba)->out.lease.lease_key.data[1], ~(__key)); \
62 		CHECK_VAL((__lba)->out.lease.lease_state, smb2_util_lease_state(__state)); \
63 		CHECK_VAL((__lba)->out.lease.lease_flags, 0);		\
64 		CHECK_VAL((__lba)->out.lease.lease_duration, 0);	\
65 	} while(0)
66 
67 #define CHECK_NO_BREAK(tctx)	\
68 	do {								\
69 		torture_wait_for_lease_break(tctx);			\
70 		CHECK_VAL(lease_break_info.failures, 0);			\
71 		CHECK_VAL(lease_break_info.count, 0);				\
72 		CHECK_VAL(lease_break_info.oplock_failures, 0);		\
73 		CHECK_VAL(lease_break_info.oplock_count, 0);			\
74 	} while(0)
75 
76 #define CHECK_OPLOCK_BREAK(__brokento)	\
77 	do {								\
78 		torture_wait_for_lease_break(tctx);			\
79 		CHECK_VAL(lease_break_info.oplock_count, 1);			\
80 		CHECK_VAL(lease_break_info.oplock_failures, 0);		\
81 		CHECK_VAL(lease_break_info.oplock_level,			\
82 			  smb2_util_oplock_level(__brokento)); \
83 		lease_break_info.held_oplock_level = lease_break_info.oplock_level; \
84 	} while(0)
85 
86 #define _CHECK_BREAK_INFO(__oldstate, __state, __key)			\
87 	do {								\
88 		torture_wait_for_lease_break(tctx);			\
89 		CHECK_VAL(lease_break_info.failures, 0);			\
90 		CHECK_VAL(lease_break_info.count, 1);				\
91 		CHECK_LEASE_BREAK(&lease_break_info.lease_break, (__oldstate), \
92 		    (__state), (__key));				\
93 		if (!lease_break_info.lease_skip_ack && \
94 		    (lease_break_info.lease_break.break_flags &		\
95 		     SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED))	\
96 		{	\
97 			torture_wait_for_lease_break(tctx);		\
98 			CHECK_LEASE_BREAK_ACK(&lease_break_info.lease_break_ack, \
99 				              (__state), (__key));	\
100 		}							\
101 	} while(0)
102 
103 #define CHECK_BREAK_INFO(__oldstate, __state, __key)			\
104 	do {								\
105 		_CHECK_BREAK_INFO(__oldstate, __state, __key);		\
106 		CHECK_VAL(lease_break_info.lease_break.new_epoch, 0);		\
107 	} while(0)
108 
109 #define CHECK_BREAK_INFO_V2(__transport, __oldstate, __state, __key, __epoch) \
110 	do {								\
111 		_CHECK_BREAK_INFO(__oldstate, __state, __key);		\
112 		CHECK_VAL(lease_break_info.lease_break.new_epoch, __epoch);	\
113 		if (!TARGET_IS_SAMBA3(tctx)) {				\
114 			CHECK_VAL((uintptr_t)lease_break_info.lease_transport, \
115 				  (uintptr_t)__transport);		\
116 		} \
117 	} while(0)
118 
119 extern struct lease_break_info lease_break_info;
120 
121 bool torture_lease_handler(struct smb2_transport *transport,
122 			   const struct smb2_lease_break *lb,
123 			   void *private_data);
124 bool torture_lease_ignore_handler(struct smb2_transport *transport,
125 				  const struct smb2_lease_break *lb,
126 				  void *private_data);
127 void torture_wait_for_lease_break(struct torture_context *tctx);
128 
torture_reset_lease_break_info(struct torture_context * tctx,struct lease_break_info * r)129 static inline void torture_reset_lease_break_info(struct torture_context *tctx,
130 						  struct lease_break_info *r)
131 {
132 	ZERO_STRUCTP(r);
133 	r->tctx = tctx;
134 }
135