1/* 2 Unix SMB/CIFS implementation. 3 SMB client oplock functions 4 Copyright (C) Andrew Tridgell 2001 5 6 This program is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 3 of the License, or 9 (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program. If not, see <http://www.gnu.org/licenses/>. 18*/ 19 20#include "includes.h" 21 22/**************************************************************************** 23send an ack for an oplock break request 24****************************************************************************/ 25 26struct cli_oplock_ack_state { 27 uint16_t vwv[8]; 28}; 29 30static void cli_oplock_ack_done(struct tevent_req *subreq); 31 32struct tevent_req *cli_oplock_ack_send(TALLOC_CTX *mem_ctx, 33 struct tevent_context *ev, 34 struct cli_state *cli, 35 uint16_t fnum, uint8_t level) 36{ 37 struct tevent_req *req, *subreq; 38 struct cli_oplock_ack_state *state; 39 40 req = tevent_req_create(mem_ctx, &state, struct cli_oplock_ack_state);; 41 if (req == NULL) { 42 return NULL; 43 } 44 SCVAL(state->vwv+0, 0, 0xff); 45 SCVAL(state->vwv+0, 1, 0); 46 SSVAL(state->vwv+1, 0, 0); 47 SSVAL(state->vwv+2, 0, fnum); 48 SCVAL(state->vwv+3, 0, LOCKING_ANDX_OPLOCK_RELEASE); 49 SCVAL(state->vwv+3, 1, level); 50 SIVAL(state->vwv+4, 0, 0); /* timeout */ 51 SSVAL(state->vwv+6, 0, 0); /* unlockcount */ 52 SSVAL(state->vwv+7, 0, 0); /* lockcount */ 53 54 subreq = cli_smb_send(state, ev, cli, SMBlockingX, 0, 8, state->vwv, 55 0, NULL); 56 if (tevent_req_nomem(subreq, req)) { 57 return tevent_req_post(req, ev); 58 } 59 tevent_req_set_callback(subreq, cli_oplock_ack_done, req); 60 return req; 61} 62 63static void cli_oplock_ack_done(struct tevent_req *subreq) 64{ 65 struct tevent_req *req = tevent_req_callback_data( 66 subreq, struct tevent_req); 67 NTSTATUS status; 68 69 status = cli_smb_recv(subreq, 0, NULL, NULL, NULL, NULL); 70 TALLOC_FREE(subreq); 71 if (!NT_STATUS_IS_OK(status)) { 72 tevent_req_nterror(req, status); 73 return; 74 } 75 tevent_req_done(req); 76} 77 78NTSTATUS cli_oplock_ack_recv(struct tevent_req *req) 79{ 80 return tevent_req_simple_recv_ntstatus(req); 81} 82 83NTSTATUS cli_oplock_ack(struct cli_state *cli, uint16_t fnum, unsigned char level) 84{ 85 TALLOC_CTX *frame = talloc_stackframe(); 86 struct event_context *ev; 87 struct tevent_req *req; 88 NTSTATUS status = NT_STATUS_OK; 89 90 if (cli_has_async_calls(cli)) { 91 /* 92 * Can't use sync call while an async call is in flight 93 */ 94 status = NT_STATUS_INVALID_PARAMETER; 95 goto fail; 96 } 97 98 ev = event_context_init(frame); 99 if (ev == NULL) { 100 status = NT_STATUS_NO_MEMORY; 101 goto fail; 102 } 103 104 req = cli_oplock_ack_send(frame, ev, cli, fnum, level); 105 if (req == NULL) { 106 status = NT_STATUS_NO_MEMORY; 107 goto fail; 108 } 109 110 if (!tevent_req_poll(req, ev)) { 111 status = map_nt_error_from_unix(errno); 112 goto fail; 113 } 114 115 status = cli_oplock_ack_recv(req); 116 fail: 117 TALLOC_FREE(frame); 118 if (!NT_STATUS_IS_OK(status)) { 119 cli_set_error(cli, status); 120 } 121 return status; 122} 123 124/**************************************************************************** 125set the oplock handler for a connection 126****************************************************************************/ 127 128void cli_oplock_handler(struct cli_state *cli, 129 NTSTATUS (*handler)(struct cli_state *, uint16_t, unsigned char)) 130{ 131 cli->oplock_handler = handler; 132} 133