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 } 153