1
/* -*- c-basic-offset: 8 -*-
2
FreeRDP: A Remote Desktop Protocol client.
3
Device Redirection - Interrupt Request Packet (IRP) Processing
5
Copyright (C) Marc-Andre Moreau <marcandre.moreau@gmail.com> 2009
7
This program is free software; you can redistribute it and/or modify
8
it under the terms of the GNU General Public License as published by
9
the Free Software Foundation; either version 2 of the License, or
10
(at your option) any later version.
12
This program is distributed in the hope that it will be useful,
13
but WITHOUT ANY WARRANTY; without even the implied warranty of
14
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
GNU General Public License for more details.
17
You should have received a copy of the GNU General Public License
18
along with this program; if not, write to the Free Software
19
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26
#include "rdpdr_types.h"
27
#include "rdpdr_constants.h"
31
irp_output_device_io_completion(IRP* irp, int * data_size)
35
*data_size = 20 + irp->outputBufferLength;
36
data = malloc(*data_size);
37
memset(data, 0, *data_size);
39
SET_UINT16(data, 0, RDPDR_CTYP_CORE); /* component */
40
SET_UINT16(data, 2, PAKID_CORE_DEVICE_IOCOMPLETION); /* packetID */
41
SET_UINT32(data, 4, irp->dev->id); /* deviceID */
42
SET_UINT32(data, 8, irp->completionID); /* completionID */
43
SET_UINT32(data, 12, irp->ioStatus); /* ioStatus */
44
SET_UINT32(data, 16, irp->outputResult);
45
if (irp->outputBufferLength > 0)
47
memcpy(data + 20, irp->outputBuffer, irp->outputBufferLength);
53
irp_process_create_request(IRP* irp, char* data, int data_size)
59
irp->desiredAccess = GET_UINT32(data, 0); /* desiredAccess */
60
//irp->allocationSize = GET_UINT64(data, 4); /* allocationSize */
61
irp->fileAttributes = GET_UINT32(data, 12); /* fileAttributes */
62
irp->sharedAccess = GET_UINT32(data, 16); /* sharedAccess */
63
irp->createDisposition = GET_UINT32(data, 20); /* createDisposition */
64
irp->createOptions = GET_UINT32(data, 24); /* createOptions */
65
pathLength = GET_UINT32(data, 28); /* pathLength */
67
size = pathLength * 3 / 2 + 1;
68
path = (char *) malloc(size);
69
memset(path, 0, size);
72
get_wstr(path, size, &data[32], pathLength);
75
if (!irp->dev->service->create)
77
irp->ioStatus = RD_STATUS_NOT_SUPPORTED;
81
irp->ioStatus = irp->dev->service->create(irp, path);
85
/* construct create response */
86
irp->outputResult = irp->fileID;
87
irp->outputBufferLength = 1;
88
irp->outputBuffer = malloc(1);
90
switch (irp->createDisposition)
96
irp->outputBuffer[0] = FILE_SUPERSEDED;
99
irp->outputBuffer[0] = FILE_OPENED;
101
case FILE_OVERWRITE_IF:
102
irp->outputBuffer[0] = FILE_OVERWRITTEN;
105
irp->outputBuffer[0] = 0;
111
irp_process_close_request(IRP* irp, char* data, int data_size)
114
if (!irp->dev->service->close)
116
irp->ioStatus = RD_STATUS_NOT_SUPPORTED;
120
irp->ioStatus = irp->dev->service->close(irp);
123
/* construct close response */
124
irp->outputBufferLength = 1;
125
irp->outputBuffer = malloc(1);
126
irp->outputBuffer[0] = 0;
130
irp_process_read_request(IRP* irp, char* data, int data_size)
132
irp->length = GET_UINT32(data, 0); /* length */
133
irp->offset = GET_UINT64(data, 4); /* offset */
136
if (!irp->dev->service->read)
138
irp->ioStatus = RD_STATUS_NOT_SUPPORTED;
142
irp->ioStatus = irp->dev->service->read(irp);
143
irp->outputResult = irp->outputBufferLength;
148
irp_process_write_request(IRP* irp, char* data, int data_size)
150
irp->length = GET_UINT32(data, 0); /* length */
151
irp->offset = GET_UINT64(data, 4); /* offset */
153
irp->inputBuffer = data + 32;
154
irp->inputBufferLength = irp->length;
156
if (!irp->dev->service->write)
158
irp->ioStatus = RD_STATUS_NOT_SUPPORTED;
162
irp->ioStatus = irp->dev->service->write(irp);
164
if (irp->ioStatus == RD_STATUS_SUCCESS)
166
irp->outputResult = irp->length;
167
/* [MS-RDPEFS] says this is an optional padding, but unfortunately it's required! */
168
irp->outputBufferLength = 1;
169
irp->outputBuffer = malloc(1);
170
irp->outputBuffer[0] = '\0';
175
irp_process_query_volume_information_request(IRP* irp, char* data, int data_size)
177
irp->infoClass = GET_UINT32(data, 0); /* fsInformationClass */
178
irp->inputBufferLength = GET_UINT32(data, 4); /* length */
181
/* queryVolumeBuffer */
182
irp->inputBuffer = data + 32;
184
if (!irp->dev->service->query_volume_info)
186
irp->ioStatus = RD_STATUS_NOT_SUPPORTED;
190
irp->ioStatus = irp->dev->service->query_volume_info(irp);
191
irp->outputResult = irp->outputBufferLength;
196
irp_process_set_volume_information_request(IRP* irp, char* data, int data_size)
199
uint32 fsInformationClass;
202
fsInformationClass = GET_UINT32(data, 0); /* fsInformationClass */
203
length = GET_UINT32(data, 4); /* length */
206
/* setVolumeBuffer */
211
irp_process_query_information_request(IRP* irp, char* data, int data_size)
213
irp->infoClass = GET_UINT32(data, 0); /* fsInformationClass */
214
irp->inputBufferLength = GET_UINT32(data, 4); /* length */
218
irp->inputBuffer = data + 32;
220
if (!irp->dev->service->query_info)
222
irp->ioStatus = RD_STATUS_NOT_SUPPORTED;
226
irp->ioStatus = irp->dev->service->query_info(irp);
227
irp->outputResult = irp->outputBufferLength;
232
irp_process_set_information_request(IRP* irp, char* data, int data_size)
234
irp->infoClass = GET_UINT32(data, 0); /* fsInformationClass */
235
irp->inputBufferLength = GET_UINT32(data, 4); /* length */
239
irp->inputBuffer = data + 32;
241
if (!irp->dev->service->set_info)
243
irp->ioStatus = RD_STATUS_NOT_SUPPORTED;
247
irp->ioStatus = irp->dev->service->set_info(irp);
248
irp->outputResult = irp->inputBufferLength;
253
irp_process_directory_control_request(IRP* irp, char* data, int data_size)
255
switch(irp->minorFunction)
257
case IRP_MN_QUERY_DIRECTORY:
258
LLOGLN(10, ("IRP_MN_QUERY_DIRECTORY"));
259
irp_process_query_directory_request(irp, data, data_size);
262
case IRP_MN_NOTIFY_CHANGE_DIRECTORY:
263
LLOGLN(10, ("IRP_MN_NOTIFY_CHANGE_DIRECTORY"));
264
irp_process_notify_change_directory_request(irp, data, data_size);
268
LLOGLN(0, ("IRP majorFunction=0x%x minorFunction=0x%x", irp->majorFunction, irp->minorFunction));
269
irp->ioStatus = RD_STATUS_INVALID_PARAMETER;
275
irp_process_device_control_request(IRP* irp, char* data, int data_size)
277
//irp->outputBufferLength = GET_UINT32(data, 0); /* outputBufferLength */
278
irp->inputBufferLength = GET_UINT32(data, 4); /* inputBufferLength */
279
irp->ioControlCode = GET_UINT32(data, 8); /* ioControlCode */
283
irp->inputBuffer = data + 32;
285
if (!irp->dev->service->control)
287
irp->ioStatus = RD_STATUS_NOT_SUPPORTED;
291
irp->ioStatus = irp->dev->service->control(irp);
292
irp->outputResult = irp->outputBufferLength;
297
irp_process_file_lock_control_request(IRP* irp, char* data, int data_size)
301
irp->operation = GET_UINT32(data, 0); /* operation */
302
irp->waitOperation = GET_UINT8(data, 4); /* f (first bit) */
303
/* pad (f + pad = 32 bits) */
304
numLocks = GET_UINT32(data, 8); /* numLocks */
305
irp->inputBufferLength = numLocks * 16; /* sizeof(RDP_LOCK_INFO) */
307
irp->inputBuffer = data + 32;
309
if (!irp->dev->service->lock_control)
311
irp->ioStatus = RD_STATUS_NOT_SUPPORTED;
315
irp->ioStatus = irp->dev->service->lock_control(irp);
316
irp->outputResult = irp->outputBufferLength;
321
irp_process_query_directory_request(IRP* irp, char* data, int data_size)
328
irp->infoClass = GET_UINT32(data, 0); /* fsInformationClass */
329
initialQuery = GET_UINT8(data, 4); /* initialQuery */
330
pathLength = GET_UINT32(data, 5); /* pathLength */
333
size = pathLength * 3 / 2 + 1;
334
path = (char *) malloc(size);
335
memset(path, 0, size);
338
get_wstr(path, size, &data[32], pathLength);
341
if (!irp->dev->service->query_directory)
343
irp->ioStatus = RD_STATUS_NOT_SUPPORTED;
347
irp->ioStatus = irp->dev->service->query_directory(irp, initialQuery, path);
351
if (irp->ioStatus == RD_STATUS_NO_MORE_FILES)
353
/* [MS-RDPEFS] said it's an optional padding, however it's *required* for this last query!!! */
354
irp->outputBufferLength = 1;
355
irp->outputBuffer = malloc(1);
356
irp->outputBuffer[0] = '\0';
360
irp->outputResult = irp->outputBufferLength;
365
irp_process_notify_change_directory_request(IRP* irp, char* data, int data_size)
367
irp->watchTree = GET_UINT8(data, 0); /* watchQuery */
368
irp->completionFilter = GET_UINT32(data, 1); /* completionQuery */
371
if (!irp->dev->service->notify_change_directory)
373
irp->ioStatus = RD_STATUS_NOT_SUPPORTED;
377
irp->ioStatus = irp->dev->service->notify_change_directory(irp);