#include <smbsrv/smb2_kproto.h>
#define DATA_OFF (SMB2_HDR_SIZE + 8)
smb_sdrc_t
smb2_change_notify(smb_request_t *sr)
{
uint16_t StructSize;
uint16_t iFlags;
uint32_t oBufLength;
smb2fid_t smb2fid;
uint32_t CompletionFilter;
uint32_t reserved;
uint32_t status;
int rc = 0;
rc = smb_mbc_decodef(
&sr->smb_data, "wwlqqll",
&StructSize,
&iFlags,
&oBufLength,
&smb2fid.persistent,
&smb2fid.temporal,
&CompletionFilter,
&reserved);
if (rc || StructSize != 32)
return (SDRC_ERROR);
status = smb2sr_lookup_fid(sr, &smb2fid);
DTRACE_SMB2_START(op__ChangeNotify, smb_request_t *, sr);
if (status != 0)
goto errout;
if (sr->smb2_next_command != 0) {
status = NT_STATUS_INSUFFICIENT_RESOURCES;
goto errout;
}
CompletionFilter &= FILE_NOTIFY_VALID_MASK;
if (iFlags & SMB2_WATCH_TREE)
CompletionFilter |= FILE_NOTIFY_CHANGE_EV_SUBDIR;
if (oBufLength > smb2_max_trans) {
status = NT_STATUS_INVALID_PARAMETER;
goto errout;
}
status = smb_notify_act1(sr, oBufLength, CompletionFilter);
if (status == NT_STATUS_PENDING) {
smb_disp_stats_t *sds;
hrtime_t start_time = sr->sr_time_start;
ASSERT(sr->smb2_cmd_code == SMB2_CHANGE_NOTIFY);
sds = &sr->sr_server->sv_disp_stats2[SMB2_CHANGE_NOTIFY];
status = smb2sr_go_async_indefinite(sr);
if (status != 0)
goto errout;
status = smb_notify_act2(sr);
if (status == NT_STATUS_PENDING) {
smb_latency_add_sample(&sds->sdt_lat,
gethrtime() - start_time);
return (SDRC_SR_KEPT);
}
}
errout:
sr->smb2_status = status;
DTRACE_SMB2_DONE(op__ChangeNotify, smb_request_t *, sr);
if (NT_SC_SEVERITY(status) == NT_STATUS_SEVERITY_SUCCESS) {
oBufLength = sr->raw_data.chain_offset;
(void) smb_mbc_encodef(
&sr->reply, "wwlC",
9,
DATA_OFF,
oBufLength,
&sr->raw_data);
} else {
smb2sr_put_error(sr, status);
}
return (SDRC_SUCCESS);
}
void
smb2_change_notify_finish(void *arg)
{
smb_request_t *sr = arg;
smb_disp_stats_t *sds;
uint32_t status;
uint32_t oBufLength;
SMB_REQ_VALID(sr);
status = smb_notify_act3(sr);
sr->smb2_status = status;
DTRACE_SMB2_DONE(op__ChangeNotify, smb_request_t *, sr);
if (NT_SC_SEVERITY(status) == NT_STATUS_SEVERITY_SUCCESS) {
oBufLength = sr->raw_data.chain_offset;
(void) smb_mbc_encodef(
&sr->reply, "wwlC",
9,
DATA_OFF,
oBufLength,
&sr->raw_data);
} else {
smb2sr_put_error(sr, status);
}
sds = &sr->session->s_server->sv_disp_stats2[SMB2_CHANGE_NOTIFY];
smb2_record_stats(sr, sds, B_FALSE);
(void) smb2_encode_header(sr, B_TRUE);
if (sr->smb2_hdr_flags & SMB2_FLAGS_SIGNED)
smb2_sign_reply(sr);
smb2_send_reply(sr);
mutex_enter(&sr->sr_mutex);
sr->sr_state = SMB_REQ_STATE_COMPLETED;
mutex_exit(&sr->sr_mutex);
smb_request_free(sr);
}