1 /**
2  * FreeRDP: A Remote Desktop Protocol Implementation
3  * Server USB redirection channel - helper functions
4  *
5  * Copyright 2019 Armin Novak <armin.novak@thincast.com>
6  * Copyright 2019 Thincast Technologies GmbH
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *	 http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  */
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23 
24 #include "urbdrc_helpers.h"
25 #include "urbdrc_types.h"
26 #include <winpr/print.h>
27 
mask_to_string(UINT32 mask)28 const char* mask_to_string(UINT32 mask)
29 {
30 	switch (mask)
31 	{
32 		case STREAM_ID_NONE:
33 			return "STREAM_ID_NONE";
34 
35 		case STREAM_ID_PROXY:
36 			return "STREAM_ID_PROXY";
37 
38 		case STREAM_ID_STUB:
39 			return "STREAM_ID_STUB";
40 
41 		default:
42 			return "UNKNOWN";
43 	}
44 }
interface_to_string(UINT32 id)45 const char* interface_to_string(UINT32 id)
46 {
47 	switch (id)
48 	{
49 		case CAPABILITIES_NEGOTIATOR:
50 			return "CAPABILITIES_NEGOTIATOR";
51 
52 		case SERVER_CHANNEL_NOTIFICATION:
53 			return "SERVER_CHANNEL_NOTIFICATION";
54 
55 		case CLIENT_CHANNEL_NOTIFICATION:
56 			return "CLIENT_CHANNEL_NOTIFICATION";
57 
58 		default:
59 			return "DEVICE_MESSAGE";
60 	}
61 }
62 
call_to_string_none(BOOL client,UINT32 interfaceId,UINT32 functionId)63 static const char* call_to_string_none(BOOL client, UINT32 interfaceId, UINT32 functionId)
64 {
65 	WINPR_UNUSED(interfaceId);
66 
67 	if (client)
68 		return "RIM_EXCHANGE_CAPABILITY_RESPONSE  [none |client]";
69 	else
70 	{
71 		switch (functionId)
72 		{
73 			case RIM_EXCHANGE_CAPABILITY_REQUEST:
74 				return "RIM_EXCHANGE_CAPABILITY_REQUEST   [none |server]";
75 
76 			case RIMCALL_RELEASE:
77 				return "RIMCALL_RELEASE                   [none |server]";
78 
79 			case RIMCALL_QUERYINTERFACE:
80 				return "RIMCALL_QUERYINTERFACE            [none |server]";
81 
82 			default:
83 				return "UNKNOWN                           [none |server]";
84 		}
85 	}
86 }
87 
call_to_string_proxy_server(UINT32 functionId)88 static const char* call_to_string_proxy_server(UINT32 functionId)
89 {
90 	switch (functionId)
91 	{
92 		case QUERY_DEVICE_TEXT:
93 			return "QUERY_DEVICE_TEXT                 [proxy|server]";
94 
95 		case INTERNAL_IO_CONTROL:
96 			return "INTERNAL_IO_CONTROL               [proxy|server]";
97 
98 		case IO_CONTROL:
99 			return "IO_CONTROL                        [proxy|server]";
100 
101 		case REGISTER_REQUEST_CALLBACK:
102 			return "REGISTER_REQUEST_CALLBACK         [proxy|server]";
103 
104 		case CANCEL_REQUEST:
105 			return "CANCEL_REQUEST                    [proxy|server]";
106 
107 		case RETRACT_DEVICE:
108 			return "RETRACT_DEVICE                    [proxy|server]";
109 
110 		case TRANSFER_IN_REQUEST:
111 			return "TRANSFER_IN_REQUEST               [proxy|server]";
112 
113 		default:
114 			return "UNKNOWN                           [proxy|server]";
115 	}
116 }
117 
call_to_string_proxy_client(UINT32 functionId)118 static const char* call_to_string_proxy_client(UINT32 functionId)
119 {
120 	switch (functionId)
121 	{
122 		case URB_COMPLETION_NO_DATA:
123 			return "URB_COMPLETION_NO_DATA            [proxy|client]";
124 
125 		case URB_COMPLETION:
126 			return "URB_COMPLETION                    [proxy|client]";
127 
128 		case IOCONTROL_COMPLETION:
129 			return "IOCONTROL_COMPLETION              [proxy|client]";
130 
131 		case TRANSFER_OUT_REQUEST:
132 			return "TRANSFER_OUT_REQUEST              [proxy|client]";
133 
134 		default:
135 			return "UNKNOWN                           [proxy|client]";
136 	}
137 }
138 
call_to_string_proxy(BOOL client,UINT32 interfaceId,UINT32 functionId)139 static const char* call_to_string_proxy(BOOL client, UINT32 interfaceId, UINT32 functionId)
140 {
141 	switch (interfaceId & INTERFACE_ID_MASK)
142 	{
143 		case CLIENT_DEVICE_SINK:
144 			switch (functionId)
145 			{
146 				case ADD_VIRTUAL_CHANNEL:
147 					return "ADD_VIRTUAL_CHANNEL               [proxy|sink  ]";
148 
149 				case ADD_DEVICE:
150 					return "ADD_DEVICE                        [proxy|sink  ]";
151 				case RIMCALL_RELEASE:
152 					return "RIMCALL_RELEASE                   [proxy|sink  ]";
153 
154 				case RIMCALL_QUERYINTERFACE:
155 					return "RIMCALL_QUERYINTERFACE            [proxy|sink  ]";
156 				default:
157 					return "UNKNOWN                           [proxy|sink  ]";
158 			}
159 
160 		case SERVER_CHANNEL_NOTIFICATION:
161 			switch (functionId)
162 			{
163 				case CHANNEL_CREATED:
164 					return "CHANNEL_CREATED                   [proxy|server]";
165 
166 				case RIMCALL_RELEASE:
167 					return "RIMCALL_RELEASE                   [proxy|server]";
168 
169 				case RIMCALL_QUERYINTERFACE:
170 					return "RIMCALL_QUERYINTERFACE            [proxy|server]";
171 
172 				default:
173 					return "UNKNOWN                           [proxy|server]";
174 			}
175 
176 		case CLIENT_CHANNEL_NOTIFICATION:
177 			switch (functionId)
178 			{
179 				case CHANNEL_CREATED:
180 					return "CHANNEL_CREATED                   [proxy|client]";
181 				case RIMCALL_RELEASE:
182 					return "RIMCALL_RELEASE                   [proxy|client]";
183 				case RIMCALL_QUERYINTERFACE:
184 					return "RIMCALL_QUERYINTERFACE            [proxy|client]";
185 				default:
186 					return "UNKNOWN                           [proxy|client]";
187 			}
188 
189 		default:
190 			if (client)
191 				return call_to_string_proxy_client(functionId);
192 			else
193 				return call_to_string_proxy_server(functionId);
194 	}
195 }
196 
call_to_string_stub(BOOL client,UINT32 interfaceId,UINT32 functionId)197 static const char* call_to_string_stub(BOOL client, UINT32 interfaceId, UINT32 functionId)
198 {
199 	return "QUERY_DEVICE_TEXT_RSP             [stub  |client]";
200 }
201 
call_to_string(BOOL client,UINT32 interface,UINT32 functionId)202 const char* call_to_string(BOOL client, UINT32 interface, UINT32 functionId)
203 {
204 	const UINT32 mask = (interface & STREAM_ID_MASK) >> 30;
205 	const UINT32 interfaceId = interface & INTERFACE_ID_MASK;
206 
207 	switch (mask)
208 	{
209 		case STREAM_ID_NONE:
210 			return call_to_string_none(client, interfaceId, functionId);
211 
212 		case STREAM_ID_PROXY:
213 			return call_to_string_proxy(client, interfaceId, functionId);
214 
215 		case STREAM_ID_STUB:
216 			return call_to_string_stub(client, interfaceId, functionId);
217 
218 		default:
219 			return "UNKNOWN[mask]";
220 	}
221 }
222 
urb_function_string(UINT16 urb)223 const char* urb_function_string(UINT16 urb)
224 {
225 	switch (urb)
226 	{
227 		case TS_URB_SELECT_CONFIGURATION:
228 			return "TS_URB_SELECT_CONFIGURATION";
229 
230 		case TS_URB_SELECT_INTERFACE:
231 			return "TS_URB_SELECT_INTERFACE";
232 
233 		case TS_URB_PIPE_REQUEST:
234 			return "TS_URB_PIPE_REQUEST";
235 
236 		case TS_URB_TAKE_FRAME_LENGTH_CONTROL:
237 			return "TS_URB_TAKE_FRAME_LENGTH_CONTROL";
238 
239 		case TS_URB_RELEASE_FRAME_LENGTH_CONTROL:
240 			return "TS_URB_RELEASE_FRAME_LENGTH_CONTROL";
241 
242 		case TS_URB_GET_FRAME_LENGTH:
243 			return "TS_URB_GET_FRAME_LENGTH";
244 
245 		case TS_URB_SET_FRAME_LENGTH:
246 			return "TS_URB_SET_FRAME_LENGTH";
247 
248 		case TS_URB_GET_CURRENT_FRAME_NUMBER:
249 			return "TS_URB_GET_CURRENT_FRAME_NUMBER";
250 
251 		case TS_URB_CONTROL_TRANSFER:
252 			return "TS_URB_CONTROL_TRANSFER";
253 
254 		case TS_URB_BULK_OR_INTERRUPT_TRANSFER:
255 			return "TS_URB_BULK_OR_INTERRUPT_TRANSFER";
256 
257 		case TS_URB_ISOCH_TRANSFER:
258 			return "TS_URB_ISOCH_TRANSFER";
259 
260 		case TS_URB_GET_DESCRIPTOR_FROM_DEVICE:
261 			return "TS_URB_GET_DESCRIPTOR_FROM_DEVICE";
262 
263 		case TS_URB_SET_DESCRIPTOR_TO_DEVICE:
264 			return "TS_URB_SET_DESCRIPTOR_TO_DEVICE";
265 
266 		case TS_URB_SET_FEATURE_TO_DEVICE:
267 			return "TS_URB_SET_FEATURE_TO_DEVICE";
268 
269 		case TS_URB_SET_FEATURE_TO_INTERFACE:
270 			return "TS_URB_SET_FEATURE_TO_INTERFACE";
271 
272 		case TS_URB_SET_FEATURE_TO_ENDPOINT:
273 			return "TS_URB_SET_FEATURE_TO_ENDPOINT";
274 
275 		case TS_URB_CLEAR_FEATURE_TO_DEVICE:
276 			return "TS_URB_CLEAR_FEATURE_TO_DEVICE";
277 
278 		case TS_URB_CLEAR_FEATURE_TO_INTERFACE:
279 			return "TS_URB_CLEAR_FEATURE_TO_INTERFACE";
280 
281 		case TS_URB_CLEAR_FEATURE_TO_ENDPOINT:
282 			return "TS_URB_CLEAR_FEATURE_TO_ENDPOINT";
283 
284 		case TS_URB_GET_STATUS_FROM_DEVICE:
285 			return "TS_URB_GET_STATUS_FROM_DEVICE";
286 
287 		case TS_URB_GET_STATUS_FROM_INTERFACE:
288 			return "TS_URB_GET_STATUS_FROM_INTERFACE";
289 
290 		case TS_URB_GET_STATUS_FROM_ENDPOINT:
291 			return "TS_URB_GET_STATUS_FROM_ENDPOINT";
292 
293 		case TS_URB_RESERVED_0X0016:
294 			return "TS_URB_RESERVED_0X0016";
295 
296 		case TS_URB_VENDOR_DEVICE:
297 			return "TS_URB_VENDOR_DEVICE";
298 
299 		case TS_URB_VENDOR_INTERFACE:
300 			return "TS_URB_VENDOR_INTERFACE";
301 
302 		case TS_URB_VENDOR_ENDPOINT:
303 			return "TS_URB_VENDOR_ENDPOINT";
304 
305 		case TS_URB_CLASS_DEVICE:
306 			return "TS_URB_CLASS_DEVICE";
307 
308 		case TS_URB_CLASS_INTERFACE:
309 			return "TS_URB_CLASS_INTERFACE";
310 
311 		case TS_URB_CLASS_ENDPOINT:
312 			return "TS_URB_CLASS_ENDPOINT";
313 
314 		case TS_URB_RESERVE_0X001D:
315 			return "TS_URB_RESERVE_0X001D";
316 
317 		case TS_URB_SYNC_RESET_PIPE_AND_CLEAR_STALL:
318 			return "TS_URB_SYNC_RESET_PIPE_AND_CLEAR_STALL";
319 
320 		case TS_URB_CLASS_OTHER:
321 			return "TS_URB_CLASS_OTHER";
322 
323 		case TS_URB_VENDOR_OTHER:
324 			return "TS_URB_VENDOR_OTHER";
325 
326 		case TS_URB_GET_STATUS_FROM_OTHER:
327 			return "TS_URB_GET_STATUS_FROM_OTHER";
328 
329 		case TS_URB_CLEAR_FEATURE_TO_OTHER:
330 			return "TS_URB_CLEAR_FEATURE_TO_OTHER";
331 
332 		case TS_URB_SET_FEATURE_TO_OTHER:
333 			return "TS_URB_SET_FEATURE_TO_OTHER";
334 
335 		case TS_URB_GET_DESCRIPTOR_FROM_ENDPOINT:
336 			return "TS_URB_GET_DESCRIPTOR_FROM_ENDPOINT";
337 
338 		case TS_URB_SET_DESCRIPTOR_TO_ENDPOINT:
339 			return "TS_URB_SET_DESCRIPTOR_TO_ENDPOINT";
340 
341 		case TS_URB_CONTROL_GET_CONFIGURATION_REQUEST:
342 			return "TS_URB_CONTROL_GET_CONFIGURATION_REQUEST";
343 
344 		case TS_URB_CONTROL_GET_INTERFACE_REQUEST:
345 			return "TS_URB_CONTROL_GET_INTERFACE_REQUEST";
346 
347 		case TS_URB_GET_DESCRIPTOR_FROM_INTERFACE:
348 			return "TS_URB_GET_DESCRIPTOR_FROM_INTERFACE";
349 
350 		case TS_URB_SET_DESCRIPTOR_TO_INTERFACE:
351 			return "TS_URB_SET_DESCRIPTOR_TO_INTERFACE";
352 
353 		case TS_URB_GET_OS_FEATURE_DESCRIPTOR_REQUEST:
354 			return "TS_URB_GET_OS_FEATURE_DESCRIPTOR_REQUEST";
355 
356 		case TS_URB_RESERVE_0X002B:
357 			return "TS_URB_RESERVE_0X002B";
358 
359 		case TS_URB_RESERVE_0X002C:
360 			return "TS_URB_RESERVE_0X002C";
361 
362 		case TS_URB_RESERVE_0X002D:
363 			return "TS_URB_RESERVE_0X002D";
364 
365 		case TS_URB_RESERVE_0X002E:
366 			return "TS_URB_RESERVE_0X002E";
367 
368 		case TS_URB_RESERVE_0X002F:
369 			return "TS_URB_RESERVE_0X002F";
370 
371 		case TS_URB_SYNC_RESET_PIPE:
372 			return "TS_URB_SYNC_RESET_PIPE";
373 
374 		case TS_URB_SYNC_CLEAR_STALL:
375 			return "TS_URB_SYNC_CLEAR_STALL";
376 
377 		case TS_URB_CONTROL_TRANSFER_EX:
378 			return "TS_URB_CONTROL_TRANSFER_EX";
379 
380 		default:
381 			return "UNKNOWN";
382 	}
383 }
384 
urbdrc_dump_message(wLog * log,BOOL client,BOOL write,wStream * s)385 void urbdrc_dump_message(wLog* log, BOOL client, BOOL write, wStream* s)
386 {
387 	const char* type = write ? "WRITE" : "READ";
388 	UINT32 InterfaceId, MessageId, FunctionId;
389 	size_t length, pos;
390 
391 	pos = Stream_GetPosition(s);
392 	if (write)
393 	{
394 		length = pos;
395 		Stream_SetPosition(s, 0);
396 	}
397 	else
398 		length = Stream_GetRemainingLength(s);
399 
400 	if (length < 12)
401 		return;
402 
403 	Stream_Read_UINT32(s, InterfaceId);
404 	Stream_Read_UINT32(s, MessageId);
405 	Stream_Read_UINT32(s, FunctionId);
406 	Stream_SetPosition(s, pos);
407 
408 	WLog_Print(log, WLOG_DEBUG,
409 	           "[%-5s] %s [%08" PRIx32 "] InterfaceId=%08" PRIx32 ", MessageId=%08" PRIx32
410 	           ", FunctionId=%08" PRIx32 ", length=%" PRIuz,
411 	           type, call_to_string(client, InterfaceId, FunctionId), FunctionId, InterfaceId,
412 	           MessageId, FunctionId, length);
413 #if defined(WITH_DEBUG_URBDRC)
414 	if (write)
415 		WLog_Print(log, WLOG_TRACE, "-------------------------- URBDRC sent: ---");
416 	else
417 		WLog_Print(log, WLOG_TRACE, "-------------------------- URBDRC received:");
418 	winpr_HexLogDump(log, WLOG_TRACE, Stream_Buffer(s), length);
419 	WLog_Print(log, WLOG_TRACE, "-------------------------- URBDRC end -----");
420 #endif
421 }
422