#include "../libcli/smb/smb_common.h"
#include "../lib/util/tevent_ntstatus.h"
#include "locking/leases_db.h"
+#include "lib/tevent_wait.h"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_SMB2
uint8_t *out_oplock_level);
static void smbd_smb2_request_oplock_break_done(struct tevent_req *subreq);
+static void smbd_smb2_request_break_done(struct smbXsrv_connection *xconn, uint64_t data0,
+ uint64_t data1, int is_lease);
NTSTATUS smbd_smb2_request_process_break(struct smbd_smb2_request *req)
{
NTSTATUS status;
req, NT_STATUS_INVALID_OPLOCK_PROTOCOL);
}
+ smbd_smb2_request_break_done(req->xconn, in_file_id_persistent,
+ in_file_id_volatile, 0);
+
if (in_oplock_level != SMB2_OPLOCK_LEVEL_NONE &&
in_oplock_level != SMB2_OPLOCK_LEVEL_II) {
return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
return smbd_smb2_request_pending_queue(req, subreq, 500);
}
+static void smbd_smb2_request_break_done(struct smbXsrv_connection *xconn,
+ uint64_t data0, uint64_t data1,
+ int is_lease)
+{
+ struct smbXsrv_pending_breaks *cur = NULL;
+ struct smbXsrv_pending_breaks *next = NULL;
+
+ for (cur = xconn->client->pending_breaks; cur != NULL; cur = next) {
+ next = cur->next;
+
+ if ((cur->is_lease == is_lease) &&
+ (cur->data[0] == data0) &&
+ (cur->data[1] == data1)) {
+ DLIST_REMOVE(xconn->client->pending_breaks, cur);
+ tevent_wait_done(cur->req);
+ }
+
+ }
+
+ return;
+}
+
static void smbd_smb2_request_oplock_break_done(struct tevent_req *subreq)
{
struct smbd_smb2_request *req = tevent_req_callback_data(subreq,
in_lease_key.data[1] = BVAL(inbody, 16);
in_lease_state = IVAL(inbody, 24);
+ smbd_smb2_request_break_done(req->xconn, in_lease_key.data[0],
+ in_lease_key.data[1], 1);
+
subreq = smbd_smb2_lease_break_send(req, req->sconn->ev_ctx, req,
in_lease_key, in_lease_state);
if (subreq == NULL) {
struct smbd_smb2_send_break_state {
struct smbd_smb2_send_queue queue_entry;
+ struct smbXsrv_pending_breaks break_queue_entry;
TALLOC_CTX *mem_ctx;
struct tevent_context *ev_ctx;
struct smbXsrv_connection *xconn;
static NTSTATUS smbd_smb2_send_break(struct smbXsrv_connection *xconn,
struct smbXsrv_session *session,
struct smbXsrv_tcon *tcon,
- const uint8_t *body,
- size_t body_len)
+ const uint8_t *body, size_t body_len,
+ bool is_lease, bool ack_needed)
{
NTSTATUS status;
struct smbd_smb2_send_break_state *state;
return status;
}
+ if (ack_needed) {
+ tevent_req_set_endtime(state->queue_entry.req,
+ state->ev_ctx,
+ timeval_current_ofs(OPLOCK_BREAK_TIMEOUT, 0));
+ /* Build smbXsrv_pending_breaks */
+ state->break_queue_entry.req = state->queue_entry.req;
+ /* FileId for oplock breaks, LeaseKey for lease breaks */
+ memcpy(&state->break_queue_entry.data[0], &body[0x8],
+ sizeof(uint64_t));
+ memcpy(&state->break_queue_entry.data[1], &body[0x10],
+ sizeof(uint64_t));
+ state->break_queue_entry.is_lease = is_lease;
+ DLIST_ADD_END(xconn->client->pending_breaks,
+ &state->break_queue_entry);
+ }
+
tevent_req_set_callback(state->queue_entry.req, smbd_smb2_send_break_done,
state);
TALLOC_FREE(state);
return status;
}
- tevent_wait_done(state->queue_entry.req);
+
+ /* No acks being received. */
+ if (!ack_needed) {
+ tevent_wait_done(state->queue_entry.req);
+ }
return NT_STATUS_OK;
}
TALLOC_FREE(ack_req);
xconn = state->xconn;
+ if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
+ DLIST_REMOVE(xconn->client->pending_breaks,
+ &state->break_queue_entry);
+ }
TALLOC_FREE(state);
}
SBVAL(body, 0x08, op->global->open_persistent_id);
SBVAL(body, 0x10, op->global->open_volatile_id);
- return smbd_smb2_send_break(xconn, NULL, NULL, body, sizeof(body));
+ return smbd_smb2_send_break(xconn, NULL, NULL, body, sizeof(body),
+ false, /* Not lease */
+ 0);
}
NTSTATUS smbd_smb2_send_lease_break(struct smbXsrv_connection *xconn,
SIVAL(body, 0x24, 0); /* AccessMaskHint, MUST be 0 */
SIVAL(body, 0x28, 0); /* ShareMaskHint, MUST be 0 */
- return smbd_smb2_send_break(xconn, NULL, NULL, body, sizeof(body));
+ return smbd_smb2_send_break(xconn, NULL, NULL, body, sizeof(body),
+ true, /* Is Lease */
+ 0);
}
static bool is_smb2_recvfile_write(struct smbd_smb2_request_read_state *state)