From 5ce3e4deac60cbc6babeda6fa109b57a2086a90a Mon Sep 17 00:00:00 2001 From: Vic Lee Date: Sat, 6 Aug 2011 01:54:40 +0800 Subject: [PATCH] rdpdr: implement irp. --- channels/rdpdr/CMakeLists.txt | 2 + channels/rdpdr/devman.c | 14 +++++ channels/rdpdr/devman.h | 1 + channels/rdpdr/disk/disk_main.c | 11 +++- channels/rdpdr/irp.c | 97 +++++++++++++++++++++++++++++++++ channels/rdpdr/irp.h | 28 ++++++++++ channels/rdpdr/rdpdr_main.c | 18 +++++- channels/rdpdr/rdpdr_types.h | 14 ++--- 8 files changed, 173 insertions(+), 12 deletions(-) create mode 100644 channels/rdpdr/irp.c create mode 100644 channels/rdpdr/irp.h diff --git a/channels/rdpdr/CMakeLists.txt b/channels/rdpdr/CMakeLists.txt index 6501b2177..059f4a442 100644 --- a/channels/rdpdr/CMakeLists.txt +++ b/channels/rdpdr/CMakeLists.txt @@ -24,6 +24,8 @@ set(RDPDR_SRCS rdpdr_capabilities.h devman.c devman.h + irp.c + irp.h rdpdr_main.c rdpdr_main.h ) diff --git a/channels/rdpdr/devman.c b/channels/rdpdr/devman.c index 37b41b52e..1281665da 100644 --- a/channels/rdpdr/devman.c +++ b/channels/rdpdr/devman.c @@ -87,3 +87,17 @@ boolean devman_load_device_service(DEVMAN* devman, FRDP_PLUGIN_DATA* plugin_data return True; } + +DEVICE* devman_get_device_by_id(DEVMAN* devman, uint32 id) +{ + LIST_ITEM* item; + DEVICE* device; + + for (item = devman->devices->head; item; item = item->next) + { + device = (DEVICE*)item->data; + if (device->id == id) + return device; + } + return NULL; +} diff --git a/channels/rdpdr/devman.h b/channels/rdpdr/devman.h index 399ab4d56..ee0ee2bb5 100644 --- a/channels/rdpdr/devman.h +++ b/channels/rdpdr/devman.h @@ -24,5 +24,6 @@ DEVMAN* devman_new(rdpSvcPlugin* plugin); void devman_free(DEVMAN* devman); boolean devman_load_device_service(DEVMAN* devman, FRDP_PLUGIN_DATA* plugin_data); +DEVICE* devman_get_device_by_id(DEVMAN* devman, uint32 id); #endif /* __DEVMAN_H */ diff --git a/channels/rdpdr/disk/disk_main.c b/channels/rdpdr/disk/disk_main.c index 1ed92cc38..def18e2f1 100644 --- a/channels/rdpdr/disk/disk_main.c +++ b/channels/rdpdr/disk/disk_main.c @@ -26,8 +26,6 @@ #include #include #include -#include -#include #include #include #include @@ -37,6 +35,13 @@ #include #include +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef HAVE_FCNTL_H +#include +#endif + #include "rdpdr_constants.h" #include "rdpdr_types.h" @@ -66,7 +71,7 @@ void disk_irp_request(DEVICE* device, IRP* irp) { DISK_DEVICE* disk = (DISK_DEVICE*)device; - irp->Discard(irp); + IFCALL(irp->Complete, irp); } void disk_free(DEVICE* device) diff --git a/channels/rdpdr/irp.c b/channels/rdpdr/irp.c new file mode 100644 index 000000000..3668b1cc4 --- /dev/null +++ b/channels/rdpdr/irp.c @@ -0,0 +1,97 @@ +/** + * FreeRDP: A Remote Desktop Protocol client. + * File System Virtual Channel + * + * Copyright 2010-2011 Marc-Andre Moreau + * Copyright 2010-2011 Vic Lee + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "config.h" +#include +#include +#include +#include +#include +#include + +#include "rdpdr_types.h" +#include "rdpdr_constants.h" +#include "devman.h" +#include "irp.h" + +static void irp_free(IRP* irp) +{ + DEBUG_SVC("DeviceId %d FileId %d CompletionId %d", irp->device->id, irp->FileId, irp->CompletionId); + + stream_free(irp->input); + stream_free(irp->output); + xfree(irp); +} + +static void irp_complete(IRP* irp) +{ + int pos; + + DEBUG_SVC("DeviceId %d FileId %d CompletionId %d", irp->device->id, irp->FileId, irp->CompletionId); + + pos = stream_get_pos(irp->output); + stream_set_pos(irp->output, 12); + stream_write_uint32(irp->output, irp->IoStatus); + stream_set_pos(irp->output, pos); + + svc_plugin_send(irp->devman->plugin, irp->output); + irp->output = NULL; + + irp_free(irp); +} + +IRP* irp_new(DEVMAN* devman, STREAM* data_in) +{ + IRP* irp; + uint32 DeviceId; + DEVICE* device; + + stream_read_uint32(data_in, DeviceId); + device = devman_get_device_by_id(devman, DeviceId); + if (device == NULL) + { + DEBUG_WARN("unknown DeviceId %d", DeviceId); + return NULL; + } + + irp = xnew(IRP); + irp->device = device; + irp->devman = devman; + stream_read_uint32(data_in, irp->FileId); + stream_read_uint32(data_in, irp->CompletionId); + stream_read_uint32(data_in, irp->MajorFunction); + stream_read_uint32(data_in, irp->MinorFunction); + irp->input = data_in; + + irp->output = stream_new(256); + stream_write_uint16(irp->output, RDPDR_CTYP_CORE); + stream_write_uint16(irp->output, PAKID_CORE_DEVICE_IOCOMPLETION); + stream_write_uint32(irp->output, DeviceId); + stream_write_uint32(irp->output, irp->CompletionId); + stream_seek_uint32(irp->output); /* IoStatus */ + + irp->Complete = irp_complete; + irp->Discard = irp_free; + + DEBUG_SVC("DeviceId %d FileId %d CompletionId %d MajorFunction 0x%X MinorFunction 0x%x", + irp->device->id, irp->FileId, irp->CompletionId, irp->MajorFunction, irp->MinorFunction); + + return irp; +} diff --git a/channels/rdpdr/irp.h b/channels/rdpdr/irp.h new file mode 100644 index 000000000..d33e51885 --- /dev/null +++ b/channels/rdpdr/irp.h @@ -0,0 +1,28 @@ +/** + * FreeRDP: A Remote Desktop Protocol client. + * File System Virtual Channel + * + * Copyright 2010-2011 Marc-Andre Moreau + * Copyright 2010-2011 Vic Lee + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __IRP_H +#define __IRP_H + +#include "rdpdr_types.h" + +IRP* irp_new(DEVMAN* devman, STREAM* data_in); + +#endif /* __IRP_H */ diff --git a/channels/rdpdr/rdpdr_main.c b/channels/rdpdr/rdpdr_main.c index 2e6467ef9..cc527fedd 100644 --- a/channels/rdpdr/rdpdr_main.c +++ b/channels/rdpdr/rdpdr_main.c @@ -35,8 +35,9 @@ #include "rdpdr_types.h" #include "rdpdr_constants.h" -#include "devman.h" #include "rdpdr_capabilities.h" +#include "devman.h" +#include "irp.h" #include "rdpdr_main.h" static void rdpdr_process_connect(rdpSvcPlugin* plugin) @@ -207,6 +208,19 @@ static void rdpdr_send_device_list_announce_request(rdpdrPlugin* rdpdr, boolean svc_plugin_send((rdpSvcPlugin*)rdpdr, data_out); } +static boolean rdpdr_process_irp(rdpdrPlugin* rdpdr, STREAM* data_in) +{ + IRP* irp; + + irp = irp_new(rdpdr->devman, data_in); + if (irp == NULL) + return False; + + IFCALL(irp->device->IRPRequest, irp->device, irp); + + return True; +} + static void rdpdr_process_receive(rdpSvcPlugin* plugin, STREAM* data_in) { rdpdrPlugin* rdpdr = (rdpdrPlugin*)plugin; @@ -255,6 +269,8 @@ static void rdpdr_process_receive(rdpSvcPlugin* plugin, STREAM* data_in) case PAKID_CORE_DEVICE_IOREQUEST: DEBUG_SVC("RDPDR_CTYP_CORE / PAKID_CORE_DEVICE_IOREQUEST"); + if (rdpdr_process_irp(rdpdr, data_in)) + data_in = NULL; break; default: diff --git a/channels/rdpdr/rdpdr_types.h b/channels/rdpdr/rdpdr_types.h index 5db08a423..305741773 100644 --- a/channels/rdpdr/rdpdr_types.h +++ b/channels/rdpdr/rdpdr_types.h @@ -49,17 +49,15 @@ typedef void (*pcIRPResponse)(IRP* irp); struct _IRP { - DEVICE* dev; + DEVICE* device; DEVMAN* devman; - uint32 packetID; - uint32 fileID; - uint32 completionID; - uint32 majorFunction; - uint32 minorFunction; + uint32 FileId; + uint32 CompletionId; + uint32 MajorFunction; + uint32 MinorFunction; STREAM* input; - uint32 ioStatus; - uint32 outputResult; + uint32 IoStatus; STREAM* output; pcIRPResponse Complete;