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