1 /*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
6 *
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
10 */
11
12 /*
13 * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
14 */
15
16 /*
17 * Dispatch function for SMB2_OPLOCK_BREAK
18 */
19
20 #include <smbsrv/smb2_kproto.h>
21
22 /*
23 * SMB2 Oplock Break Acknowledgement
24 * [MS-SMB2 2.2.24]
25 */
26 smb_sdrc_t
27 smb2_oplock_break_ack(smb_request_t *sr)
28 {
29 smb_node_t *node;
30 smb2fid_t smb2fid;
31 uint32_t status;
32 uint16_t StructSize;
33 uint8_t OplockLevel;
34 uint8_t brk;
35 int rc = 0;
36
37 /*
38 * Decode the SMB2 Oplock Break Ack.
39 */
40 rc = smb_mbc_decodef(
41 &sr->smb_data, "wb5.qq",
42 &StructSize, /* w */
43 &OplockLevel, /* b */
44 /* reserved 5. */
45 &smb2fid.persistent, /* q */
46 &smb2fid.temporal); /* q */
47 if (rc || StructSize != 24)
48 return (SDRC_ERROR);
49
50 status = smb2sr_lookup_fid(sr, &smb2fid);
51 if (status)
52 goto errout;
53 if ((node = sr->fid_ofile->f_node) == NULL) {
54 /* Not a regular file */
55 status = NT_STATUS_INVALID_PARAMETER;
56 goto errout;
57 }
58
59 /*
60 * Process the oplock break ack. We only expect levels
61 * at or below the hightest break levels we send, which is
62 * currently SMB2_OPLOCK_LEVEL_II.
63 */
64 switch (OplockLevel) {
65 case SMB2_OPLOCK_LEVEL_NONE: /* 0x00 */
66 brk = SMB_OPLOCK_BREAK_TO_NONE;
67 break;
68
69 case SMB2_OPLOCK_LEVEL_II: /* 0x01 */
70 brk = SMB_OPLOCK_BREAK_TO_LEVEL_II;
71 break;
72
73 /* We don't break to these levels (yet). */
74 case SMB2_OPLOCK_LEVEL_EXCLUSIVE: /* 0x08 */
75 case SMB2_OPLOCK_LEVEL_BATCH: /* 0x09 */
76 case SMB2_OPLOCK_LEVEL_LEASE: /* 0xFF */
77 default: /* gcc -Wuninitialized */
78 status = NT_STATUS_INVALID_PARAMETER;
79 goto errout;
80 }
81
82 smb_oplock_ack(node, sr->fid_ofile, brk);
83
84 /*
85 * Generate SMB2 Oplock Break response
86 * [MS-SMB2] 2.2.25
87 */
88 StructSize = 24;
89 (void) smb_mbc_encodef(
90 &sr->reply, "wb5.qq",
91 StructSize, /* w */
92 OplockLevel, /* b */
93 /* reserved 5. */
94 smb2fid.persistent, /* q */
95 smb2fid.temporal); /* q */
96 return (SDRC_SUCCESS);
97
98 errout:
99 smb2sr_put_error(sr, status);
100 return (SDRC_SUCCESS);
101 }
102
103 /*
104 * Compose an SMB2 Oplock Break Notification packet, including
105 * the SMB2 header and everything, in sr->reply.
106 * The caller will send it and free the request.
107 */
108 void
109 smb2_oplock_break_notification(smb_request_t *sr, uint8_t brk)
110 {
111 smb_ofile_t *ofile = sr->fid_ofile;
112 smb2fid_t smb2fid;
113 uint16_t StructSize;
114 uint8_t OplockLevel;
115
116 switch (brk) {
117 default:
118 ASSERT(0);
119 /* FALLTHROUGH */
120 case SMB_OPLOCK_BREAK_TO_NONE:
121 OplockLevel = SMB2_OPLOCK_LEVEL_NONE;
122 break;
123 case SMB_OPLOCK_BREAK_TO_LEVEL_II:
124 OplockLevel = SMB2_OPLOCK_LEVEL_II;
125 break;
126 }
127
128 /*
129 * SMB2 Header
130 */
131 sr->smb2_cmd_code = SMB2_OPLOCK_BREAK;
132 sr->smb2_hdr_flags = SMB2_FLAGS_SERVER_TO_REDIR;
133 sr->smb_tid = ofile->f_tree->t_tid;
134 sr->smb_pid = 0;
135 sr->smb_uid = 0;
136 sr->smb2_messageid = UINT64_MAX;
137 (void) smb2_encode_header(sr, B_FALSE);
138
139 /*
140 * SMB2 Oplock Break, variable part
141 */
142 StructSize = 24;
143 smb2fid.persistent = 0;
144 smb2fid.temporal = ofile->f_fid;
145 (void) smb_mbc_encodef(
146 &sr->reply, "wb5.qq",
147 StructSize, /* w */
148 OplockLevel, /* b */
149 /* reserved 5. */
150 smb2fid.persistent, /* q */
151 smb2fid.temporal); /* q */
152 }
|
1 /*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
6 *
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
10 */
11
12 /*
13 * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
14 */
15
16 /*
17 * Dispatch function for SMB2_OPLOCK_BREAK
18 */
19
20 #include <smbsrv/smb2_kproto.h>
21
22 #define BATCH_OR_EXCL (OPLOCK_LEVEL_BATCH | OPLOCK_LEVEL_ONE)
23
24 /* StructSize for the two "break" message formats. */
25 #define SSZ_OPLOCK 24
26 #define SSZ_LEASE 36
27
28 /*
29 * SMB2 Oplock Break Acknowledgement
30 * [MS-SMB2] 3.3.5.22.1 Processing an Oplock Acknowledgment
31 * Called via smb2_disp_table[]
32 */
33 smb_sdrc_t
34 smb2_oplock_break_ack(smb_request_t *sr)
35 {
36 smb_ofile_t *ofile;
37 smb2fid_t smb2fid;
38 uint32_t status;
39 uint32_t NewLevel;
40 uint8_t smbOplockLevel;
41 int rc = 0;
42 uint16_t StructSize;
43
44 /*
45 * Decode the SMB2 Oplock Break Ack (24 bytes) or
46 * Lease Break Ack (36 bytes), starting with just
47 * the StructSize, which tells us what this is.
48 */
49 rc = smb_mbc_decodef(&sr->smb_data, "w", &StructSize);
50 if (rc != 0)
51 return (SDRC_ERROR);
52
53 if (StructSize == SSZ_LEASE) {
54 /* See smb2_lease.c */
55 return (smb2_lease_break_ack(sr));
56 }
57 if (StructSize != SSZ_OPLOCK)
58 return (SDRC_ERROR);
59
60 /*
61 * Decode an SMB2 Oplock Break Ack.
62 * [MS-SMB2] 2.2.24.1
63 * Note: Struct size decoded above.
64 */
65 rc = smb_mbc_decodef(
66 &sr->smb_data, "b5.qq",
67 &smbOplockLevel, /* b */
68 /* reserved 5. */
69 &smb2fid.persistent, /* q */
70 &smb2fid.temporal); /* q */
71 if (rc != 0)
72 return (SDRC_ERROR);
73
74 /* Find the ofile */
75 status = smb2sr_lookup_fid(sr, &smb2fid);
76 /* Success or NT_STATUS_FILE_CLOSED */
77
78 DTRACE_SMB2_START(op__OplockBreak, smb_request_t *, sr);
79 if (status != 0)
80 goto errout;
81
82 /*
83 * Process an (old-style) oplock break ack.
84 */
85 switch (smbOplockLevel) {
86 case SMB2_OPLOCK_LEVEL_NONE: /* 0x00 */
87 NewLevel = OPLOCK_LEVEL_NONE;
88 break;
89 case SMB2_OPLOCK_LEVEL_II: /* 0x01 */
90 NewLevel = OPLOCK_LEVEL_TWO;
91 break;
92 case SMB2_OPLOCK_LEVEL_EXCLUSIVE: /* 0x08 */
93 NewLevel = OPLOCK_LEVEL_ONE;
94 break;
95 case SMB2_OPLOCK_LEVEL_BATCH: /* 0x09 */
96 NewLevel = OPLOCK_LEVEL_BATCH;
97 break;
98 case SMB2_OPLOCK_LEVEL_LEASE: /* 0xFF */
99 default:
100 NewLevel = OPLOCK_LEVEL_NONE;
101 break;
102 }
103
104 ofile = sr->fid_ofile;
105 ofile->f_oplock.og_breaking = 0;
106 status = smb_oplock_ack_break(sr, ofile, &NewLevel);
107 if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) {
108 status = smb2sr_go_async(sr);
109 if (status != 0)
110 goto errout;
111 (void) smb_oplock_wait_break(ofile->f_node, 0);
112 status = 0;
113 }
114 if (status != 0) {
115 NewLevel = OPLOCK_LEVEL_NONE;
116 goto errout;
117 }
118
119 ofile->f_oplock.og_state = NewLevel;
120 switch (NewLevel & OPLOCK_LEVEL_TYPE_MASK) {
121 case OPLOCK_LEVEL_NONE:
122 smbOplockLevel = SMB2_OPLOCK_LEVEL_NONE;
123 break;
124 case OPLOCK_LEVEL_TWO:
125 smbOplockLevel = SMB2_OPLOCK_LEVEL_II;
126 break;
127 case OPLOCK_LEVEL_ONE:
128 smbOplockLevel = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
129 break;
130 case OPLOCK_LEVEL_BATCH:
131 smbOplockLevel = SMB2_OPLOCK_LEVEL_BATCH;
132 break;
133 case OPLOCK_LEVEL_GRANULAR:
134 default:
135 smbOplockLevel = SMB2_OPLOCK_LEVEL_NONE;
136 break;
137 }
138
139 errout:
140 sr->smb2_status = status;
141 DTRACE_SMB2_DONE(op__OplockBreak, smb_request_t *, sr);
142 if (status) {
143 smb2sr_put_error(sr, status);
144 return (SDRC_SUCCESS);
145 }
146
147 /*
148 * Encode an SMB2 Oplock Break Ack response
149 * [MS-SMB2] 2.2.25.1
150 */
151 (void) smb_mbc_encodef(
152 &sr->reply, "wb5.qq",
153 SSZ_OPLOCK, /* w */
154 smbOplockLevel, /* b */
155 /* reserved 5. */
156 smb2fid.persistent, /* q */
157 smb2fid.temporal); /* q */
158
159 return (SDRC_SUCCESS);
160 }
161
162 /*
163 * Compose an SMB2 Oplock Break Notification packet, including
164 * the SMB2 header and everything, in sr->reply.
165 * The caller will send it and free the request.
166 */
167 void
168 smb2_oplock_break_notification(smb_request_t *sr, uint32_t NewLevel)
169 {
170 smb_ofile_t *ofile = sr->fid_ofile;
171 smb2fid_t smb2fid;
172 uint16_t StructSize;
173 uint8_t OplockLevel;
174
175 /*
176 * Convert internal level to SMB2
177 */
178 switch (NewLevel) {
179 default:
180 ASSERT(0);
181 /* FALLTHROUGH */
182 case OPLOCK_LEVEL_NONE:
183 OplockLevel = SMB2_OPLOCK_LEVEL_NONE;
184 break;
185 case OPLOCK_LEVEL_TWO:
186 OplockLevel = SMB2_OPLOCK_LEVEL_II;
187 break;
188 }
189
190 /*
191 * SMB2 Header
192 */
193 sr->smb2_cmd_code = SMB2_OPLOCK_BREAK;
194 sr->smb2_hdr_flags = SMB2_FLAGS_SERVER_TO_REDIR;
195 sr->smb_tid = 0;
196 sr->smb_pid = 0;
197 sr->smb2_ssnid = 0;
198 sr->smb2_messageid = UINT64_MAX;
199 (void) smb2_encode_header(sr, B_FALSE);
200
201 /*
202 * SMB2 Oplock Break, variable part
203 */
204 StructSize = 24;
205 smb2fid.persistent = ofile->f_persistid;
206 smb2fid.temporal = ofile->f_fid;
207 (void) smb_mbc_encodef(
208 &sr->reply, "wb5.qq",
209 StructSize, /* w */
210 OplockLevel, /* b */
211 /* reserved 5. */
212 smb2fid.persistent, /* q */
213 smb2fid.temporal); /* q */
214 }
215
216 /*
217 * Client has an open handle and requests an oplock.
218 * Convert SMB2 oplock request info in to internal form,
219 * call common oplock code, convert result to SMB2.
220 *
221 * If necessary, "go async" here.
222 */
223 void
224 smb2_oplock_acquire(smb_request_t *sr)
225 {
226 smb_arg_open_t *op = &sr->arg.open;
227 smb_ofile_t *ofile = sr->fid_ofile;
228 uint32_t status;
229
230 /* Only disk trees get oplocks. */
231 ASSERT((sr->tid_tree->t_res_type & STYPE_MASK) == STYPE_DISKTREE);
232
233 /* Only plain files... */
234 if (!smb_node_is_file(ofile->f_node)) {
235 op->op_oplock_level = SMB2_OPLOCK_LEVEL_NONE;
236 return;
237 }
238
239 if (!smb_tree_has_feature(sr->tid_tree, SMB_TREE_OPLOCKS)) {
240 op->op_oplock_level = SMB2_OPLOCK_LEVEL_NONE;
241 return;
242 }
243
244 /*
245 * SMB2: Convert to internal form.
246 */
247 switch (op->op_oplock_level) {
248 case SMB2_OPLOCK_LEVEL_BATCH:
249 op->op_oplock_state = OPLOCK_LEVEL_BATCH;
250 break;
251 case SMB2_OPLOCK_LEVEL_EXCLUSIVE:
252 op->op_oplock_state = OPLOCK_LEVEL_ONE;
253 break;
254 case SMB2_OPLOCK_LEVEL_II:
255 op->op_oplock_state = OPLOCK_LEVEL_TWO;
256 break;
257 case SMB2_OPLOCK_LEVEL_LEASE:
258 ASSERT(0); /* Handled elsewhere */
259 /* FALLTHROUGH */
260 case SMB2_OPLOCK_LEVEL_NONE:
261 default:
262 op->op_oplock_level = SMB2_OPLOCK_LEVEL_NONE;
263 return;
264 }
265
266 /*
267 * Tree options may force shared oplocks,
268 * in which case we reduce the request.
269 */
270 if (smb_tree_has_feature(sr->tid_tree, SMB_TREE_FORCE_L2_OPLOCK)) {
271 op->op_oplock_state = OPLOCK_LEVEL_TWO;
272 }
273
274 /*
275 * Try exclusive first, if requested
276 */
277 if ((op->op_oplock_state & BATCH_OR_EXCL) != 0) {
278 status = smb_oplock_request(sr, ofile,
279 &op->op_oplock_state);
280 } else {
281 status = NT_STATUS_OPLOCK_NOT_GRANTED;
282 }
283
284 /*
285 * If exclusive failed (or the tree forced shared oplocks)
286 * try for a shared oplock (Level II)
287 */
288 if (status == NT_STATUS_OPLOCK_NOT_GRANTED) {
289 op->op_oplock_state = OPLOCK_LEVEL_TWO;
290 status = smb_oplock_request(sr, ofile,
291 &op->op_oplock_state);
292 }
293
294 /*
295 * Either of the above may have returned the
296 * status code that says we should wait.
297 */
298 if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) {
299 (void) smb2sr_go_async(sr);
300 (void) smb_oplock_wait_break(ofile->f_node, 0);
301 status = 0;
302 }
303
304 /*
305 * Keep track of what we got (in ofile->f_oplock.og_state)
306 * so we'll know what we had when sending a break later.
307 * The og_dialect here is the oplock dialect, not the
308 * SMB dialect. No lease here, so SMB 2.0.
309 */
310 ofile->f_oplock.og_dialect = SMB_VERS_2_002;
311 switch (status) {
312 case NT_STATUS_SUCCESS:
313 ofile->f_oplock.og_state = op->op_oplock_state;
314 break;
315 case NT_STATUS_OPLOCK_NOT_GRANTED:
316 ofile->f_oplock.og_state = 0;
317 op->op_oplock_level = SMB2_OPLOCK_LEVEL_NONE;
318 return;
319 default:
320 /* Caller did not check args sufficiently? */
321 cmn_err(CE_NOTE, "clnt %s oplock req. err 0x%x",
322 sr->session->ip_addr_str, status);
323 ofile->f_oplock.og_state = 0;
324 op->op_oplock_level = SMB2_OPLOCK_LEVEL_NONE;
325 return;
326 }
327
328 /*
329 * Have STATUS_SUCCESS
330 * Convert internal oplock state to SMB2
331 */
332 if (op->op_oplock_state & OPLOCK_LEVEL_GRANULAR) {
333 ASSERT(0);
334 op->op_oplock_level = SMB2_OPLOCK_LEVEL_NONE;
335 } else if (op->op_oplock_state & OPLOCK_LEVEL_BATCH) {
336 op->op_oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
337 } else if (op->op_oplock_state & OPLOCK_LEVEL_ONE) {
338 op->op_oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
339 } else if (op->op_oplock_state & OPLOCK_LEVEL_TWO) {
340 op->op_oplock_level = SMB2_OPLOCK_LEVEL_II;
341 } else {
342 op->op_oplock_level = SMB2_OPLOCK_LEVEL_NONE;
343 }
344 }
|