#include <smbsrv/smb2_kproto.h>
static void smb2_cancel_async(smb_request_t *);
static void smb2_cancel_sync(smb_request_t *);
int
smb2_newrq_cancel(smb_request_t *sr)
{
if (sr->smb2_next_command != 0)
return (EINVAL);
DTRACE_SMB2_START(op__Cancel, smb_request_t *, sr);
if (sr->smb2_hdr_flags & SMB2_FLAGS_ASYNC_COMMAND)
smb2_cancel_async(sr);
else
smb2_cancel_sync(sr);
DTRACE_SMB2_DONE(op__Cancel, smb_request_t *, sr);
return (0);
}
smb_sdrc_t
smb2_cancel(smb_request_t *sr)
{
if (sr->smb2_cmd_hdr != 0 || sr->smb2_next_command != 0)
return (SDRC_DROP_VC);
DTRACE_SMB2_START(op__Cancel, smb_request_t *, sr);
if (sr->smb2_hdr_flags & SMB2_FLAGS_ASYNC_COMMAND) {
smb2_cancel_async(sr);
} else {
smb2_cancel_sync(sr);
}
DTRACE_SMB2_DONE(op__Cancel, smb_request_t *, sr);
return (SDRC_NO_REPLY);
}
static void
smb2_cancel_sync(smb_request_t *sr)
{
struct smb_request *req;
struct smb_session *session = sr->session;
int cnt = 0;
if (sr->smb2_messageid == 0 || sr->smb2_messageid == UINT64_MAX)
return;
smb_slist_enter(&session->s_req_list);
for (req = smb_slist_head(&session->s_req_list); req != NULL;
req = smb_slist_next(&session->s_req_list, req)) {
if (req == sr)
continue;
if (sr->smb2_messageid >= req->smb2_first_msgid &&
sr->smb2_messageid < (req->smb2_first_msgid +
req->smb2_total_credits)) {
smb_request_cancel(req);
cnt++;
}
}
smb_slist_exit(&session->s_req_list);
if (cnt != 1) {
DTRACE_PROBE2(smb2__cancel__error,
uint64_t, sr->smb2_messageid, int, cnt);
#ifdef DEBUG
cmn_err(CE_WARN, "SMB2 cancel failed, "
"client=%s, MID=0x%llx",
sr->session->ip_addr_str,
(u_longlong_t)sr->smb2_messageid);
#endif
}
}
static void
smb2_cancel_async(smb_request_t *sr)
{
struct smb_request *req;
struct smb_session *session = sr->session;
int cnt = 0;
if (sr->smb2_async_id == 0)
return;
smb_slist_enter(&session->s_req_list);
req = smb_slist_head(&session->s_req_list);
while (req) {
ASSERT(req->sr_magic == SMB_REQ_MAGIC);
if ((req != sr) &&
(req->smb2_async_id == sr->smb2_async_id)) {
smb_request_cancel(req);
cnt++;
}
req = smb_slist_next(&session->s_req_list, req);
}
if (cnt != 1) {
DTRACE_PROBE2(smb2__cancel__error,
uint64_t, sr->smb2_async_id, int, cnt);
}
smb_slist_exit(&session->s_req_list);
}