1 /**
2  * FreeRDP: A Remote Desktop Protocol Implementation
3  * Device Redirection Virtual Channel
4  *
5  * Copyright 2010-2011 Vic Lee
6  * Copyright 2010-2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
7  * Copyright 2015 Thincast Technologies GmbH
8  * Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
9  *
10  * Licensed under the Apache License, Version 2.0 (the "License");
11  * you may not use this file except in compliance with the License.
12  * You may obtain a copy of the License at
13  *
14  *     http://www.apache.org/licenses/LICENSE-2.0
15  *
16  * Unless required by applicable law or agreed to in writing, software
17  * distributed under the License is distributed on an "AS IS" BASIS,
18  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19  * See the License for the specific language governing permissions and
20  * limitations under the License.
21  */
22 
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26 
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 
31 #include <winpr/crt.h>
32 #include <winpr/stream.h>
33 
34 #include "rdpdr_main.h"
35 #include "devman.h"
36 #include "irp.h"
37 
38 /**
39  * Function description
40  *
41  * @return 0 on success, otherwise a Win32 error code
42  */
irp_free(IRP * irp)43 static UINT irp_free(IRP* irp)
44 {
45 	if (!irp)
46 		return CHANNEL_RC_OK;
47 
48 	Stream_Free(irp->input, TRUE);
49 	Stream_Free(irp->output, TRUE);
50 
51 	_aligned_free(irp);
52 	return CHANNEL_RC_OK;
53 }
54 
55 /**
56  * Function description
57  *
58  * @return 0 on success, otherwise a Win32 error code
59  */
irp_complete(IRP * irp)60 static UINT irp_complete(IRP* irp)
61 {
62 	size_t pos;
63 	rdpdrPlugin* rdpdr;
64 	UINT error;
65 
66 	rdpdr = (rdpdrPlugin*)irp->devman->plugin;
67 
68 	pos = Stream_GetPosition(irp->output);
69 	Stream_SetPosition(irp->output, RDPDR_DEVICE_IO_RESPONSE_LENGTH - 4);
70 	Stream_Write_UINT32(irp->output, irp->IoStatus); /* IoStatus (4 bytes) */
71 	Stream_SetPosition(irp->output, pos);
72 
73 	error = rdpdr_send(rdpdr, irp->output);
74 	irp->output = NULL;
75 
76 	return irp_free(irp);
77 }
78 
irp_new(DEVMAN * devman,wStream * s,UINT * error)79 IRP* irp_new(DEVMAN* devman, wStream* s, UINT* error)
80 {
81 	IRP* irp;
82 	DEVICE* device;
83 	UINT32 DeviceId;
84 
85 	if (Stream_GetRemainingLength(s) < 20)
86 	{
87 		if (error)
88 			*error = ERROR_INVALID_DATA;
89 		return NULL;
90 	}
91 
92 	Stream_Read_UINT32(s, DeviceId); /* DeviceId (4 bytes) */
93 	device = devman_get_device_by_id(devman, DeviceId);
94 
95 	if (!device)
96 	{
97 		WLog_WARN(TAG, "devman_get_device_by_id failed!");
98 		if (error)
99 			*error = CHANNEL_RC_OK;
100 
101 		return NULL;
102 	};
103 
104 	irp = (IRP*)_aligned_malloc(sizeof(IRP), MEMORY_ALLOCATION_ALIGNMENT);
105 
106 	if (!irp)
107 	{
108 		WLog_ERR(TAG, "_aligned_malloc failed!");
109 		if (error)
110 			*error = CHANNEL_RC_NO_MEMORY;
111 		return NULL;
112 	}
113 
114 	ZeroMemory(irp, sizeof(IRP));
115 
116 	irp->input = s;
117 	irp->device = device;
118 	irp->devman = devman;
119 
120 	Stream_Read_UINT32(s, irp->FileId);        /* FileId (4 bytes) */
121 	Stream_Read_UINT32(s, irp->CompletionId);  /* CompletionId (4 bytes) */
122 	Stream_Read_UINT32(s, irp->MajorFunction); /* MajorFunction (4 bytes) */
123 	Stream_Read_UINT32(s, irp->MinorFunction); /* MinorFunction (4 bytes) */
124 
125 	irp->output = Stream_New(NULL, 256);
126 	if (!irp->output)
127 	{
128 		WLog_ERR(TAG, "Stream_New failed!");
129 		_aligned_free(irp);
130 		if (error)
131 			*error = CHANNEL_RC_NO_MEMORY;
132 		return NULL;
133 	}
134 	Stream_Write_UINT16(irp->output, RDPDR_CTYP_CORE);                /* Component (2 bytes) */
135 	Stream_Write_UINT16(irp->output, PAKID_CORE_DEVICE_IOCOMPLETION); /* PacketId (2 bytes) */
136 	Stream_Write_UINT32(irp->output, DeviceId);                       /* DeviceId (4 bytes) */
137 	Stream_Write_UINT32(irp->output, irp->CompletionId);              /* CompletionId (4 bytes) */
138 	Stream_Write_UINT32(irp->output, 0);                              /* IoStatus (4 bytes) */
139 
140 	irp->Complete = irp_complete;
141 	irp->Discard = irp_free;
142 
143 	irp->thread = NULL;
144 	irp->cancelled = FALSE;
145 
146 	if (error)
147 		*error = CHANNEL_RC_OK;
148 
149 	return irp;
150 }
151