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 /* 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 DTRACE_SMB2_START(op__OplockBreak, smb_request_t *, sr); 52 if (status) 53 goto errout; 54 if ((node = sr->fid_ofile->f_node) == NULL) { 55 /* Not a regular file */ 56 status = NT_STATUS_INVALID_PARAMETER; 57 goto errout; 58 } 59 60 /* 61 * Process the oplock break ack. We only expect levels 62 * at or below the hightest break levels we send, which is 63 * currently SMB2_OPLOCK_LEVEL_II. 64 */ 65 switch (OplockLevel) { 66 case SMB2_OPLOCK_LEVEL_NONE: /* 0x00 */ 67 brk = SMB_OPLOCK_BREAK_TO_NONE; 68 break; 69 70 case SMB2_OPLOCK_LEVEL_II: /* 0x01 */ 71 brk = SMB_OPLOCK_BREAK_TO_LEVEL_II; 72 break; 73 74 /* We don't break to these levels (yet). */ 75 case SMB2_OPLOCK_LEVEL_EXCLUSIVE: /* 0x08 */ 76 case SMB2_OPLOCK_LEVEL_BATCH: /* 0x09 */ 77 case SMB2_OPLOCK_LEVEL_LEASE: /* 0xFF */ 78 default: /* gcc -Wuninitialized */ 79 status = NT_STATUS_INVALID_PARAMETER; 80 goto errout; 81 } 82 83 smb_oplock_ack(node, sr->fid_ofile, brk); 84 85 errout: 86 sr->smb2_status = status; 87 DTRACE_SMB2_DONE(op__OplockBreak, smb_request_t *, sr); 88 if (status) { 89 smb2sr_put_error(sr, status); 90 return (SDRC_SUCCESS); 91 } 92 93 /* 94 * Generate SMB2 Oplock Break response 95 * [MS-SMB2] 2.2.25 96 */ 97 StructSize = 24; 98 (void) smb_mbc_encodef( 99 &sr->reply, "wb5.qq", 100 StructSize, /* w */ 101 OplockLevel, /* b */ 102 /* reserved 5. */ 103 smb2fid.persistent, /* q */ 104 smb2fid.temporal); /* q */ 105 return (SDRC_SUCCESS); 106 } 107 108 /* 109 * Compose an SMB2 Oplock Break Notification packet, including 110 * the SMB2 header and everything, in sr->reply. 111 * The caller will send it and free the request. 112 */ 113 void 114 smb2_oplock_break_notification(smb_request_t *sr, uint8_t brk) 115 { 116 smb_ofile_t *ofile = sr->fid_ofile; 117 smb2fid_t smb2fid; 118 uint16_t StructSize; 119 uint8_t OplockLevel; 120 121 switch (brk) { 122 default: 123 ASSERT(0); 124 /* FALLTHROUGH */ 125 case SMB_OPLOCK_BREAK_TO_NONE: 126 OplockLevel = SMB2_OPLOCK_LEVEL_NONE; 127 break; 128 case SMB_OPLOCK_BREAK_TO_LEVEL_II: 129 OplockLevel = SMB2_OPLOCK_LEVEL_II; 130 break; 131 } 132 133 /* 134 * SMB2 Header 135 */ 136 sr->smb2_cmd_code = SMB2_OPLOCK_BREAK; 137 sr->smb2_hdr_flags = SMB2_FLAGS_SERVER_TO_REDIR; 138 sr->smb_tid = 0; 139 sr->smb_pid = 0; 140 sr->smb2_ssnid = 0; 141 sr->smb2_messageid = UINT64_MAX; 142 (void) smb2_encode_header(sr, B_FALSE); 143 144 /* 145 * SMB2 Oplock Break, variable part 146 */ 147 StructSize = 24; 148 smb2fid.persistent = ofile->f_persistid; 149 smb2fid.temporal = ofile->f_fid; 150 (void) smb_mbc_encodef( 151 &sr->reply, "wb5.qq", 152 StructSize, /* w */ 153 OplockLevel, /* b */ 154 /* reserved 5. */ 155 smb2fid.persistent, /* q */ 156 smb2fid.temporal); /* q */ 157 } 158