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 2019 Nexenta by DDN, Inc. All rights reserved. 14 * Copyright 2019 RackTop Systems. 15 */ 16 17 /* 18 * Dispatch function for SMB2_OPLOCK_BREAK 19 */ 20 21 #include <smbsrv/smb2_kproto.h> 22 23 #define BATCH_OR_EXCL (OPLOCK_LEVEL_BATCH | OPLOCK_LEVEL_ONE) 24 25 /* StructSize for the two "break" message formats. */ 26 #define SSZ_OPLOCK 24 27 #define SSZ_LEASE 36 28 29 /* 30 * SMB2 Oplock Break Acknowledgement 31 * [MS-SMB2] 3.3.5.22.1 Processing an Oplock Acknowledgment 32 * Called via smb2_disp_table[] 33 */ 34 smb_sdrc_t 35 smb2_oplock_break_ack(smb_request_t *sr) 36 { 37 smb_ofile_t *ofile; 38 smb2fid_t smb2fid; 39 uint32_t status; 40 uint32_t NewLevel; 41 uint8_t smbOplockLevel; 42 int rc = 0; 43 uint16_t StructSize; 44 45 /* 46 * Decode the SMB2 Oplock Break Ack (24 bytes) or 47 * Lease Break Ack (36 bytes), starting with just 48 * the StructSize, which tells us what this is. 49 */ 50 rc = smb_mbc_decodef(&sr->smb_data, "w", &StructSize); 51 if (rc != 0) 52 return (SDRC_ERROR); 53 54 if (StructSize == SSZ_LEASE) { 55 /* See smb2_lease.c */ 56 return (smb2_lease_break_ack(sr)); 57 } 58 if (StructSize != SSZ_OPLOCK) 59 return (SDRC_ERROR); 60 61 /* 62 * Decode an SMB2 Oplock Break Ack. 63 * [MS-SMB2] 2.2.24.1 64 * Note: Struct size decoded above. 65 */ 66 rc = smb_mbc_decodef( 67 &sr->smb_data, "b5.qq", 68 &smbOplockLevel, /* b */ 69 /* reserved 5. */ 70 &smb2fid.persistent, /* q */ 71 &smb2fid.temporal); /* q */ 72 if (rc != 0) 73 return (SDRC_ERROR); 74 75 /* Find the ofile */ 76 status = smb2sr_lookup_fid(sr, &smb2fid); 77 /* Success or NT_STATUS_FILE_CLOSED */ 78 79 DTRACE_SMB2_START(op__OplockBreak, smb_request_t *, sr); 80 if (status != 0) 81 goto errout; 82 83 /* 84 * Process an (old-style) oplock break ack. 85 */ 86 switch (smbOplockLevel) { 87 case SMB2_OPLOCK_LEVEL_NONE: /* 0x00 */ 88 NewLevel = OPLOCK_LEVEL_NONE; 89 break; 90 case SMB2_OPLOCK_LEVEL_II: /* 0x01 */ 91 NewLevel = OPLOCK_LEVEL_TWO; 92 break; 93 case SMB2_OPLOCK_LEVEL_EXCLUSIVE: /* 0x08 */ 94 NewLevel = OPLOCK_LEVEL_ONE; 95 break; 96 case SMB2_OPLOCK_LEVEL_BATCH: /* 0x09 */ 97 NewLevel = OPLOCK_LEVEL_BATCH; 98 break; 99 case SMB2_OPLOCK_LEVEL_LEASE: /* 0xFF */ 100 NewLevel = OPLOCK_LEVEL_NONE; 101 break; 102 default: 103 status = NT_STATUS_INVALID_PARAMETER; 104 goto errout; 105 } 106 107 ofile = sr->fid_ofile; 108 if (ofile->f_oplock.og_breaking == 0) { 109 /* 110 * This is an unsolicited Ack. (There is no 111 * outstanding oplock break in progress now.) 112 * There are WPTS tests that care which error 113 * is returned. See [MS-SMB2] 3.3.5.22.1 114 */ 115 if (smbOplockLevel == SMB2_OPLOCK_LEVEL_LEASE) { 116 status = NT_STATUS_INVALID_PARAMETER; 117 goto errout; 118 } 119 if (NewLevel >= (ofile->f_oplock.og_state & 120 OPLOCK_LEVEL_TYPE_MASK)) { 121 status = NT_STATUS_INVALID_OPLOCK_PROTOCOL; 122 goto errout; 123 } 124 status = NT_STATUS_INVALID_DEVICE_STATE; 125 goto errout; 126 } 127 ofile->f_oplock.og_breaking = 0; 128 129 status = smb_oplock_ack_break(sr, ofile, &NewLevel); 130 if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) { 131 status = smb2sr_go_async(sr); 132 if (status != 0) 133 goto errout; 134 (void) smb_oplock_wait_break(ofile->f_node, 0); 135 status = 0; 136 } 137 if (status != 0) { 138 NewLevel = OPLOCK_LEVEL_NONE; 139 goto errout; 140 } 141 142 ofile->f_oplock.og_state = NewLevel; 143 switch (NewLevel & OPLOCK_LEVEL_TYPE_MASK) { 144 case OPLOCK_LEVEL_NONE: 145 smbOplockLevel = SMB2_OPLOCK_LEVEL_NONE; 146 break; 147 case OPLOCK_LEVEL_TWO: 148 smbOplockLevel = SMB2_OPLOCK_LEVEL_II; 149 break; 150 case OPLOCK_LEVEL_ONE: 151 smbOplockLevel = SMB2_OPLOCK_LEVEL_EXCLUSIVE; 152 break; 153 case OPLOCK_LEVEL_BATCH: 154 smbOplockLevel = SMB2_OPLOCK_LEVEL_BATCH; 155 break; 156 case OPLOCK_LEVEL_GRANULAR: 157 default: 158 smbOplockLevel = SMB2_OPLOCK_LEVEL_NONE; 159 break; 160 } 161 162 errout: 163 sr->smb2_status = status; 164 DTRACE_SMB2_DONE(op__OplockBreak, smb_request_t *, sr); 165 if (status) { 166 smb2sr_put_error(sr, status); 167 return (SDRC_SUCCESS); 168 } 169 170 /* 171 * Encode an SMB2 Oplock Break Ack response 172 * [MS-SMB2] 2.2.25.1 173 */ 174 (void) smb_mbc_encodef( 175 &sr->reply, "wb5.qq", 176 SSZ_OPLOCK, /* w */ 177 smbOplockLevel, /* b */ 178 /* reserved 5. */ 179 smb2fid.persistent, /* q */ 180 smb2fid.temporal); /* q */ 181 182 return (SDRC_SUCCESS); 183 } 184 185 /* 186 * Compose an SMB2 Oplock Break Notification packet, including 187 * the SMB2 header and everything, in sr->reply. 188 * The caller will send it and free the request. 189 */ 190 void 191 smb2_oplock_break_notification(smb_request_t *sr, uint32_t NewLevel) 192 { 193 smb_ofile_t *ofile = sr->fid_ofile; 194 smb2fid_t smb2fid; 195 uint16_t StructSize; 196 uint8_t OplockLevel; 197 198 /* 199 * Convert internal level to SMB2 200 */ 201 switch (NewLevel) { 202 default: 203 ASSERT(0); 204 /* FALLTHROUGH */ 205 case OPLOCK_LEVEL_NONE: 206 OplockLevel = SMB2_OPLOCK_LEVEL_NONE; 207 break; 208 case OPLOCK_LEVEL_TWO: 209 OplockLevel = SMB2_OPLOCK_LEVEL_II; 210 break; 211 } 212 213 /* 214 * SMB2 Header 215 */ 216 sr->smb2_cmd_code = SMB2_OPLOCK_BREAK; 217 sr->smb2_hdr_flags = SMB2_FLAGS_SERVER_TO_REDIR; 218 sr->smb_tid = 0; 219 sr->smb_pid = 0; 220 sr->smb2_ssnid = 0; 221 sr->smb2_messageid = UINT64_MAX; 222 (void) smb2_encode_header(sr, B_FALSE); 223 224 /* 225 * SMB2 Oplock Break, variable part 226 */ 227 StructSize = 24; 228 smb2fid.persistent = ofile->f_persistid; 229 smb2fid.temporal = ofile->f_fid; 230 (void) smb_mbc_encodef( 231 &sr->reply, "wb5.qq", 232 StructSize, /* w */ 233 OplockLevel, /* b */ 234 /* reserved 5. */ 235 smb2fid.persistent, /* q */ 236 smb2fid.temporal); /* q */ 237 } 238 239 /* 240 * Client has an open handle and requests an oplock. 241 * Convert SMB2 oplock request info in to internal form, 242 * call common oplock code, convert result to SMB2. 243 * 244 * If necessary, "go async" here. 245 */ 246 void 247 smb2_oplock_acquire(smb_request_t *sr) 248 { 249 smb_arg_open_t *op = &sr->arg.open; 250 smb_ofile_t *ofile = sr->fid_ofile; 251 uint32_t status; 252 253 /* Only disk trees get oplocks. */ 254 ASSERT((sr->tid_tree->t_res_type & STYPE_MASK) == STYPE_DISKTREE); 255 256 /* Only plain files... */ 257 if (!smb_node_is_file(ofile->f_node)) { 258 op->op_oplock_level = SMB2_OPLOCK_LEVEL_NONE; 259 return; 260 } 261 262 if (!smb_tree_has_feature(sr->tid_tree, SMB_TREE_OPLOCKS)) { 263 op->op_oplock_level = SMB2_OPLOCK_LEVEL_NONE; 264 return; 265 } 266 267 /* 268 * SMB2: Convert to internal form. 269 */ 270 switch (op->op_oplock_level) { 271 case SMB2_OPLOCK_LEVEL_BATCH: 272 op->op_oplock_state = OPLOCK_LEVEL_BATCH; 273 break; 274 case SMB2_OPLOCK_LEVEL_EXCLUSIVE: 275 op->op_oplock_state = OPLOCK_LEVEL_ONE; 276 break; 277 case SMB2_OPLOCK_LEVEL_II: 278 op->op_oplock_state = OPLOCK_LEVEL_TWO; 279 break; 280 case SMB2_OPLOCK_LEVEL_LEASE: 281 ASSERT(0); /* Handled elsewhere */ 282 /* FALLTHROUGH */ 283 case SMB2_OPLOCK_LEVEL_NONE: 284 default: 285 op->op_oplock_level = SMB2_OPLOCK_LEVEL_NONE; 286 return; 287 } 288 289 /* 290 * Tree options may force shared oplocks, 291 * in which case we reduce the request. 292 */ 293 if (smb_tree_has_feature(sr->tid_tree, SMB_TREE_FORCE_L2_OPLOCK)) { 294 op->op_oplock_state = OPLOCK_LEVEL_TWO; 295 } 296 297 /* 298 * Try exclusive first, if requested 299 */ 300 if ((op->op_oplock_state & BATCH_OR_EXCL) != 0) { 301 status = smb_oplock_request(sr, ofile, 302 &op->op_oplock_state); 303 } else { 304 status = NT_STATUS_OPLOCK_NOT_GRANTED; 305 } 306 307 /* 308 * If exclusive failed (or the tree forced shared oplocks) 309 * try for a shared oplock (Level II) 310 */ 311 if (status == NT_STATUS_OPLOCK_NOT_GRANTED) { 312 op->op_oplock_state = OPLOCK_LEVEL_TWO; 313 status = smb_oplock_request(sr, ofile, 314 &op->op_oplock_state); 315 } 316 317 /* 318 * Either of the above may have returned the 319 * status code that says we should wait. 320 */ 321 if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) { 322 (void) smb2sr_go_async(sr); 323 (void) smb_oplock_wait_break(ofile->f_node, 0); 324 status = 0; 325 } 326 327 /* 328 * Keep track of what we got (in ofile->f_oplock.og_state) 329 * so we'll know what we had when sending a break later. 330 * The og_dialect here is the oplock dialect, not the 331 * SMB dialect. No lease here, so SMB 2.0. 332 */ 333 ofile->f_oplock.og_dialect = SMB_VERS_2_002; 334 switch (status) { 335 case NT_STATUS_SUCCESS: 336 ofile->f_oplock.og_state = op->op_oplock_state; 337 break; 338 case NT_STATUS_OPLOCK_NOT_GRANTED: 339 ofile->f_oplock.og_state = 0; 340 op->op_oplock_level = SMB2_OPLOCK_LEVEL_NONE; 341 return; 342 default: 343 /* Caller did not check args sufficiently? */ 344 cmn_err(CE_NOTE, "clnt %s oplock req. err 0x%x", 345 sr->session->ip_addr_str, status); 346 ofile->f_oplock.og_state = 0; 347 op->op_oplock_level = SMB2_OPLOCK_LEVEL_NONE; 348 return; 349 } 350 351 /* 352 * Have STATUS_SUCCESS 353 * Convert internal oplock state to SMB2 354 */ 355 if (op->op_oplock_state & OPLOCK_LEVEL_GRANULAR) { 356 ASSERT(0); 357 op->op_oplock_level = SMB2_OPLOCK_LEVEL_NONE; 358 } else if (op->op_oplock_state & OPLOCK_LEVEL_BATCH) { 359 op->op_oplock_level = SMB2_OPLOCK_LEVEL_BATCH; 360 } else if (op->op_oplock_state & OPLOCK_LEVEL_ONE) { 361 op->op_oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE; 362 } else if (op->op_oplock_state & OPLOCK_LEVEL_TWO) { 363 op->op_oplock_level = SMB2_OPLOCK_LEVEL_II; 364 } else { 365 op->op_oplock_level = SMB2_OPLOCK_LEVEL_NONE; 366 } 367 } 368 369 /* 370 * smb2_oplock_reconnect() Helper for smb2_dh_reconnect 371 * Get oplock state into op->op_oplock_level etc. 372 * 373 * Similar to the end of smb2_lease_acquire (for leases) or 374 * the end of smb2_oplock_acquire (for old-style oplocks). 375 */ 376 void 377 smb2_oplock_reconnect(smb_request_t *sr) 378 { 379 smb_arg_open_t *op = &sr->arg.open; 380 smb_ofile_t *ofile = sr->fid_ofile; 381 382 op->op_oplock_state = ofile->f_oplock.og_state; 383 if (ofile->f_lease != NULL) { 384 smb_lease_t *ls = ofile->f_lease; 385 386 op->op_oplock_level = SMB2_OPLOCK_LEVEL_LEASE; 387 op->lease_state = ls->ls_state & 388 OPLOCK_LEVEL_CACHE_MASK; 389 op->lease_flags = (ls->ls_breaking != 0) ? 390 SMB2_LEASE_FLAG_BREAK_IN_PROGRESS : 0; 391 op->lease_epoch = ls->ls_epoch; 392 op->lease_version = ls->ls_version; 393 } else { 394 switch (op->op_oplock_state & OPLOCK_LEVEL_TYPE_MASK) { 395 default: 396 case OPLOCK_LEVEL_NONE: 397 op->op_oplock_level = SMB2_OPLOCK_LEVEL_NONE; 398 break; 399 case OPLOCK_LEVEL_TWO: 400 op->op_oplock_level = SMB2_OPLOCK_LEVEL_II; 401 break; 402 case OPLOCK_LEVEL_ONE: 403 op->op_oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE; 404 break; 405 case OPLOCK_LEVEL_BATCH: 406 op->op_oplock_level = SMB2_OPLOCK_LEVEL_BATCH; 407 break; 408 } 409 } 410 } 411