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 } 345 346 /* 347 * smb2_oplock_reconnect() Helper for smb2_dh_reconnect 348 * Get oplock state into op->op_oplock_level etc. 349 * 350 * Similar to the end of smb2_lease_acquire (for leases) or 351 * the end of smb2_oplock_acquire (for old-style oplocks). 352 */ 353 void 354 smb2_oplock_reconnect(smb_request_t *sr) 355 { 356 smb_arg_open_t *op = &sr->arg.open; 357 smb_ofile_t *ofile = sr->fid_ofile; 358 359 op->op_oplock_state = ofile->f_oplock.og_state; 360 if (ofile->f_lease != NULL) { 361 smb_lease_t *ls = ofile->f_lease; 362 363 op->op_oplock_level = SMB2_OPLOCK_LEVEL_LEASE; 364 op->lease_state = ls->ls_state & 365 OPLOCK_LEVEL_CACHE_MASK; 366 op->lease_flags = (ls->ls_breaking != 0) ? 367 SMB2_LEASE_FLAG_BREAK_IN_PROGRESS : 0; 368 op->lease_epoch = ls->ls_epoch; 369 op->lease_version = ls->ls_version; 370 } else { 371 switch (op->op_oplock_state & OPLOCK_LEVEL_TYPE_MASK) { 372 default: 373 case OPLOCK_LEVEL_NONE: 374 op->op_oplock_level = SMB2_OPLOCK_LEVEL_NONE; 375 break; 376 case OPLOCK_LEVEL_TWO: 377 op->op_oplock_level = SMB2_OPLOCK_LEVEL_II; 378 break; 379 case OPLOCK_LEVEL_ONE: 380 op->op_oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE; 381 break; 382 case OPLOCK_LEVEL_BATCH: 383 op->op_oplock_level = SMB2_OPLOCK_LEVEL_BATCH; 384 break; 385 } 386 } 387 } 388