1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. 24 * Copyright 2017 Nexenta Systems, Inc. All rights reserved. 25 */ 26 27 /* 28 * Dispatch function for SMB2_CHANGE_NOTIFY 29 */ 30 31 #include <smbsrv/smb2_kproto.h> 32 33 /* For the output DataOffset fields in here. */ 34 #define DATA_OFF (SMB2_HDR_SIZE + 8) 35 36 static smb_sdrc_t smb2_change_notify_async(smb_request_t *); 37 38 smb_sdrc_t 39 smb2_change_notify(smb_request_t *sr) 40 { 41 uint16_t StructSize; 42 uint16_t iFlags; 43 uint32_t oBufLength; 44 smb2fid_t smb2fid; 45 uint32_t CompletionFilter; 46 uint32_t reserved; 47 uint32_t status; 48 int rc = 0; 49 50 /* 51 * SMB2 Change Notify request 52 */ 53 rc = smb_mbc_decodef( 54 &sr->smb_data, "wwlqqll", 55 &StructSize, /* w */ 56 &iFlags, /* w */ 57 &oBufLength, /* l */ 58 &smb2fid.persistent, /* q */ 59 &smb2fid.temporal, /* q */ 60 &CompletionFilter, /* l */ 61 &reserved); /* l */ 62 if (rc || StructSize != 32) 63 return (SDRC_ERROR); 64 65 status = smb2sr_lookup_fid(sr, &smb2fid); 66 DTRACE_SMB2_START(op__ChangeNotify, smb_request_t *, sr); 67 68 if (status != 0) 69 goto errout; /* Bad FID */ 70 71 CompletionFilter &= FILE_NOTIFY_VALID_MASK; 72 if (iFlags & SMB2_WATCH_TREE) 73 CompletionFilter |= FILE_NOTIFY_CHANGE_EV_SUBDIR; 74 75 if (oBufLength > smb2_max_trans) 76 oBufLength = smb2_max_trans; 77 78 /* 79 * Check for events and consume, non-blocking. 80 * Special return STATUS_PENDING means: 81 * No events; caller must call "act2" next. 82 * SMB2 does that in the "async" handler. 83 */ 84 status = smb_notify_act1(sr, oBufLength, CompletionFilter); 85 if (status == NT_STATUS_PENDING) { 86 status = smb2sr_go_async(sr, smb2_change_notify_async); 87 } 88 89 errout: 90 sr->smb2_status = status; 91 if (status != NT_STATUS_PENDING) { 92 DTRACE_SMB2_DONE(op__ChangeNotify, smb_request_t *, sr); 93 } 94 95 if (NT_SC_SEVERITY(status) == NT_STATUS_SEVERITY_SUCCESS) { 96 oBufLength = sr->raw_data.chain_offset; 97 (void) smb_mbc_encodef( 98 &sr->reply, "wwlC", 99 9, /* StructSize */ /* w */ 100 DATA_OFF, /* w */ 101 oBufLength, /* l */ 102 &sr->raw_data); /* C */ 103 } else { 104 smb2sr_put_error(sr, status); 105 } 106 107 return (SDRC_SUCCESS); 108 } 109 110 /* 111 * This is called when the dispatch loop has made it to the end of a 112 * compound request, and we had a notify that will require blocking. 113 */ 114 static smb_sdrc_t 115 smb2_change_notify_async(smb_request_t *sr) 116 { 117 uint32_t status; 118 119 status = smb_notify_act2(sr); 120 if (status == NT_STATUS_PENDING) { 121 /* See next: smb2_change_notify_finish */ 122 return (SDRC_SR_KEPT); 123 } 124 125 /* Note: Never NT_STATUS_NOTIFY_ENUM_DIR here. */ 126 ASSERT(status != NT_STATUS_NOTIFY_ENUM_DIR); 127 128 if (status != 0) 129 smb2sr_put_error(sr, status); 130 131 return (SDRC_SUCCESS); 132 } 133 134 /* 135 * This is called via taskq_dispatch in smb_notify.c 136 * to finish up an NT transact notify change request. 137 * Build an SMB2 Change Notify reply and send it. 138 */ 139 void 140 smb2_change_notify_finish(void *arg) 141 { 142 smb_request_t *sr = arg; 143 uint32_t status; 144 uint32_t oBufLength; 145 146 SMB_REQ_VALID(sr); 147 148 /* 149 * Common part of notify, puts data in sr->raw_data 150 */ 151 status = smb_notify_act3(sr); 152 153 sr->smb2_status = status; 154 DTRACE_SMB2_DONE(op__ChangeNotify, smb_request_t *, sr); 155 156 if (NT_SC_SEVERITY(status) == NT_STATUS_SEVERITY_SUCCESS) { 157 oBufLength = sr->raw_data.chain_offset; 158 (void) smb_mbc_encodef( 159 &sr->reply, "wwlC", 160 9, /* StructSize */ /* w */ 161 DATA_OFF, /* w */ 162 oBufLength, /* l */ 163 &sr->raw_data); /* C */ 164 } else { 165 smb2sr_put_error(sr, status); 166 } 167 168 smb2sr_finish_async(sr); 169 } 170