/src/wireshark/epan/dissectors/packet-rdp_drdynvc.c
Line | Count | Source |
1 | | /* packet-rdp_drdynvc.c |
2 | | * Routines for Dynamic Virtual channel RDP packet dissection |
3 | | * Copyright 2021, David Fort |
4 | | * |
5 | | * Wireshark - Network traffic analyzer |
6 | | * By Gerald Combs <gerald@wireshark.org> |
7 | | * Copyright 1998 Gerald Combs |
8 | | * |
9 | | * SPDX-License-Identifier: GPL-2.0-or-later |
10 | | */ |
11 | | |
12 | | #include "config.h" |
13 | | |
14 | | #include <epan/packet.h> |
15 | | #include <epan/prefs.h> |
16 | | #include <epan/proto_data.h> |
17 | | #include <epan/conversation.h> |
18 | | #include <epan/crc32-tvb.h> |
19 | | #include <epan/tvbuff_rdp.h> |
20 | | #include "packet-rdp.h" |
21 | | #include "packet-rdpudp.h" |
22 | | |
23 | | void proto_register_rdp_drdynvc(void); |
24 | | void proto_reg_handoff_drdynvc(void); |
25 | | |
26 | | static int proto_rdp_drdynvc; |
27 | | |
28 | | static int hf_rdp_drdynvc_cbId; |
29 | | static int hf_rdp_drdynvc_sp; |
30 | | static int hf_rdp_drdynvc_pri; |
31 | | static int hf_rdp_drdynvc_cmd; |
32 | | static int hf_rdp_drdynvc_capa_version; |
33 | | static int hf_rdp_drdynvc_capa_prio0; |
34 | | static int hf_rdp_drdynvc_capa_prio1; |
35 | | static int hf_rdp_drdynvc_capa_prio2; |
36 | | static int hf_rdp_drdynvc_capa_prio3; |
37 | | static int hf_rdp_drdynvc_channelId; |
38 | | static int hf_rdp_drdynvc_pad; |
39 | | static int hf_rdp_drdynvc_channelName; |
40 | | static int hf_rdp_drdynvc_creationStatus; |
41 | | static int hf_rdp_drdynvc_createresp_channelname; |
42 | | static int hf_rdp_drdynvc_length; |
43 | | static int hf_rdp_drdynvc_softsync_req_length; |
44 | | static int hf_rdp_drdynvc_softsync_req_flags; |
45 | | static int hf_rdp_drdynvc_softsync_req_ntunnels; |
46 | | static int hf_rdp_drdynvc_softsync_req_channel_tunnelType; |
47 | | static int hf_rdp_drdynvc_softsync_req_channel_ndvc; |
48 | | static int hf_rdp_drdynvc_softsync_req_channel_dvcid; |
49 | | static int hf_rdp_drdynvc_softsync_resp_ntunnels; |
50 | | static int hf_rdp_drdynvc_softsync_resp_tunnel; |
51 | | static int hf_rdp_drdynvc_data; |
52 | | static int hf_rdp_drdynvc_data_progress; |
53 | | static int hf_rdp_drdynvc_createreq_frameid; |
54 | | static int hf_rdp_drdynvc_createresp_frameid; |
55 | | |
56 | | |
57 | | static int ett_rdp_drdynvc; |
58 | | static int ett_rdp_drdynvc_softsync_channels; |
59 | | static int ett_rdp_drdynvc_softsync_channel; |
60 | | static int ett_rdp_drdynvc_softsync_dvc; |
61 | | |
62 | | dissector_handle_t egfx_handle; |
63 | | dissector_handle_t rail_handle; |
64 | | dissector_handle_t cliprdr_handle; |
65 | | dissector_handle_t rdpdr_handle; |
66 | | dissector_handle_t snd_handle; |
67 | | dissector_handle_t ear_handle; |
68 | | dissector_handle_t ecam_handle; |
69 | | |
70 | | enum { |
71 | | DRDYNVC_CREATE_REQUEST_PDU = 0x01, |
72 | | DRDYNVC_DATA_FIRST_PDU = 0x02, |
73 | | DRDYNVC_DATA_PDU = 0x03, |
74 | | DRDYNVC_CLOSE_REQUEST_PDU = 0x04, |
75 | | DRDYNVC_CAPABILITY_REQUEST_PDU = 0x05, |
76 | | DRDYNVC_DATA_FIRST_COMPRESSED_PDU = 0x06, |
77 | | DRDYNVC_DATA_COMPRESSED_PDU = 0x07, |
78 | | DRDYNVC_SOFT_SYNC_REQUEST_PDU = 0x08, |
79 | | DRDYNVC_SOFT_SYNC_RESPONSE_PDU = 0x09 |
80 | | }; |
81 | | |
82 | | typedef enum { |
83 | | DRDYNVC_CHANNEL_UNKNOWN, |
84 | | DRDYNVC_CHANNEL_EGFX, /* MS-RDPEGX */ |
85 | | DRDYNVC_CHANNEL_TELEMETRY, /* MS-RDPET */ |
86 | | DRDYNVC_CHANNEL_AUDIOUT, /* MS-RDPEA */ |
87 | | DRDYNVC_CHANNEL_AUDIN, /* MS-RDPEAI */ |
88 | | DRDYNVC_CHANNEL_VIDEO_CTL, /*MS-RDPEVOR */ |
89 | | DRDYNVC_CHANNEL_VIDEO_DATA, /*MS-RDPEVOR */ |
90 | | DRDYNVC_CHANNEL_CAM, /* MS-RDPECAM */ |
91 | | DRDYNVC_CHANNEL_DISPLAY, /* MS-RDPEDISP */ |
92 | | DRDYNVC_CHANNEL_GEOMETRY,/* MS-RDPEGT */ |
93 | | DRDYNVC_CHANNEL_MULTITOUCH, /* MS-RDPEI */ |
94 | | DRDYNVC_CHANNEL_AUTH_REDIR, /* MS-RDPEAR */ |
95 | | |
96 | | DRDYNVC_CHANNEL_RAIL, /* MS-RDPERP */ |
97 | | DRDYNVC_CHANNEL_CLIPRDR, /* MS-RDPECLIP */ |
98 | | DRDYNVC_CHANNEL_DR, /* MS-RDPDR */ |
99 | | } drdynvc_known_channel_t; |
100 | | |
101 | | enum { |
102 | | DRDYNVC_CHANNEL_PDUS_KEY = 1, |
103 | | }; |
104 | | |
105 | | |
106 | | typedef struct { |
107 | | bool reassembled; |
108 | | bool decodePayload; |
109 | | uint32_t progressStart; |
110 | | uint32_t progressEnd; |
111 | | uint32_t packetLen; |
112 | | uint32_t startReassemblyFrame; |
113 | | uint32_t endReassemblyFrame; |
114 | | tvbuff_t* tvb; |
115 | | } drdynvc_pdu_info_t; |
116 | | |
117 | | typedef struct { |
118 | | wmem_tree_t *pdus; |
119 | | } drdynvc_pinfo_t; |
120 | | |
121 | | /** @brief context for tracking a list of packet chunks */ |
122 | | typedef struct { |
123 | | wmem_array_t *currentPacket; |
124 | | uint32_t packetLen; |
125 | | uint32_t pendingLen; |
126 | | uint32_t startFrame; |
127 | | uint32_t endReassemblyFrame; |
128 | | wmem_array_t *chunks; |
129 | | } drdynvc_pending_packet_t; |
130 | | |
131 | | /** @brief context associated with a dynamic channel */ |
132 | | typedef struct { |
133 | | drdynvc_known_channel_t type; |
134 | | char *name; |
135 | | uint32_t channelId; |
136 | | uint32_t createFrameId; |
137 | | uint32_t createConfirmFrameId; |
138 | | |
139 | | drdynvc_pending_packet_t pending_cs; |
140 | | drdynvc_pending_packet_t pending_sc; |
141 | | zgfx_context_t *zgfx_cs; |
142 | | zgfx_context_t *zgfx_sc; |
143 | | } drdynvc_channel_def_t; |
144 | | |
145 | | typedef struct _drdynvc_conv_info_t { |
146 | | wmem_multimap_t *channels; |
147 | | } drdynvc_conv_info_t; |
148 | | |
149 | | |
150 | | typedef struct { |
151 | | const char *name; |
152 | | const char *shortName; |
153 | | drdynvc_known_channel_t type; |
154 | | } drdynvc_know_channel_def; |
155 | | |
156 | | static drdynvc_know_channel_def knownChannels[] = { |
157 | | {"AUDIO_INPUT", "audin", DRDYNVC_CHANNEL_AUDIN}, |
158 | | {"AUDIO_PLAYBACK_DVC", "audiout", DRDYNVC_CHANNEL_AUDIOUT}, |
159 | | {"AUDIO_PLAYBACK_LOSSY_DVC", "audiout lossy", DRDYNVC_CHANNEL_AUDIOUT}, |
160 | | {"RDCamera_Device_Enumerator", "cam", DRDYNVC_CHANNEL_CAM}, |
161 | | {"Microsoft::Windows::RDS::Video::Control::v08.01", "videoctl", DRDYNVC_CHANNEL_VIDEO_CTL}, |
162 | | {"Microsoft::Windows::RDS::Video::Data::v08.01", "videodata", DRDYNVC_CHANNEL_VIDEO_DATA}, |
163 | | {"Microsoft::Windows::RDS::AuthRedirection", "authredir", DRDYNVC_CHANNEL_AUTH_REDIR}, |
164 | | {"Microsoft::Windows::RDS::Telemetry", "telemetry", DRDYNVC_CHANNEL_TELEMETRY}, |
165 | | {"Microsoft::Windows::RDS::Graphics", "egfx", DRDYNVC_CHANNEL_EGFX}, |
166 | | {"Microsoft::Windows::RDS::DisplayControl", "display", DRDYNVC_CHANNEL_DISPLAY}, |
167 | | {"Microsoft::Windows::RDS::Geometry::v08.01", "geometry", DRDYNVC_CHANNEL_GEOMETRY}, |
168 | | {"Microsoft::Windows::RDS::Input", "input", DRDYNVC_CHANNEL_MULTITOUCH}, |
169 | | {"Microsoft::Windows::RDS::RAIL", "rail", DRDYNVC_CHANNEL_RAIL}, |
170 | | |
171 | | /* static channels that can be reopened on the dynamic channel */ |
172 | | {"rail", "rail", DRDYNVC_CHANNEL_RAIL}, |
173 | | {"cliprdr", "cliprdr", DRDYNVC_CHANNEL_CLIPRDR}, |
174 | | {"rdpdr", "rdpdr", DRDYNVC_CHANNEL_DR}, |
175 | | }; |
176 | | |
177 | | static const value_string drdynvc_tunneltype_vals[] = { |
178 | | { 0x1, "reliable" }, |
179 | | { 0x3, "lossy" }, |
180 | | { 0x0, NULL}, |
181 | | }; |
182 | | |
183 | | static const value_string rdp_drdynvc_cbId_vals[] = { |
184 | | { 0x0, "1 byte" }, |
185 | | { 0x1, "2 bytes" }, |
186 | | { 0x2, "4 bytes" }, |
187 | | { 0x0, NULL}, |
188 | | }; |
189 | | |
190 | | static const value_string rdp_drdynvc_prio_vals[] = { |
191 | | { 0x0, "PriorityCharge0" }, |
192 | | { 0x1, "PriorityCharge1" }, |
193 | | { 0x2, "PriorityCharge2" }, |
194 | | { 0x3, "PriorityCharge3" }, |
195 | | { 0x0, NULL}, |
196 | | }; |
197 | | |
198 | | static const value_string rdp_drdynvc_cmd_vals[] = { |
199 | | { DRDYNVC_CREATE_REQUEST_PDU, "Create PDU" }, |
200 | | { DRDYNVC_DATA_FIRST_PDU, "Data first PDU" }, |
201 | | { DRDYNVC_DATA_PDU, "Data PDU" }, |
202 | | { DRDYNVC_CLOSE_REQUEST_PDU, "Close PDU" }, |
203 | | { DRDYNVC_CAPABILITY_REQUEST_PDU, "Capabilities PDU" }, |
204 | | { DRDYNVC_DATA_FIRST_COMPRESSED_PDU, "Data first compressed PDU" }, |
205 | | { DRDYNVC_DATA_COMPRESSED_PDU, "Data compressed PDU" }, |
206 | | { DRDYNVC_SOFT_SYNC_REQUEST_PDU,"Soft-Sync request PDU" }, |
207 | | { DRDYNVC_SOFT_SYNC_RESPONSE_PDU,"Soft-Sync response PDU" }, |
208 | | { 0x0, NULL}, |
209 | | }; |
210 | | |
211 | 0 | static unsigned channel_hashFunc(const void *key) { |
212 | 0 | uint32_t *intPtr = (uint32_t *)key; |
213 | |
|
214 | 0 | return *intPtr; |
215 | 0 | } |
216 | | |
217 | 0 | static gboolean channel_equalFunc(const void *a, const void *b) { |
218 | 0 | uint32_t *aPtr = (uint32_t *)a; |
219 | 0 | uint32_t *bPtr = (uint32_t *)b; |
220 | |
|
221 | 0 | return (*aPtr == *bPtr); |
222 | 0 | } |
223 | | |
224 | | |
225 | | static void |
226 | | drdynvc_pending_packet_init(drdynvc_pending_packet_t *pending, uint32_t startFrame) |
227 | 0 | { |
228 | 0 | pending->packetLen = 0; |
229 | 0 | pending->pendingLen = 0; |
230 | 0 | pending->startFrame = startFrame; |
231 | 0 | pending->endReassemblyFrame = 0; |
232 | 0 | pending->currentPacket = NULL; |
233 | 0 | pending->chunks = NULL; |
234 | 0 | } |
235 | | |
236 | | static drdynvc_known_channel_t |
237 | | drdynvc_find_channel_type(const char *name) |
238 | 0 | { |
239 | 0 | unsigned i; |
240 | |
|
241 | 0 | for (i = 0; i < array_length(knownChannels); i++) |
242 | 0 | { |
243 | 0 | if (strcmp(knownChannels[i].name, name) == 0) |
244 | 0 | return knownChannels[i].type; |
245 | 0 | } |
246 | | |
247 | | // TODO: replace with proper registration of announced ecam sub channels |
248 | 0 | if (strstr(name, "RDCamera_Device_") == name) |
249 | 0 | return DRDYNVC_CHANNEL_CAM; |
250 | | |
251 | 0 | return DRDYNVC_CHANNEL_UNKNOWN; |
252 | 0 | } |
253 | | |
254 | | static drdynvc_conv_info_t * |
255 | | drdynvc_get_conversation_data(packet_info *pinfo) |
256 | 0 | { |
257 | 0 | conversation_t *conversation = rdp_find_main_conversation(pinfo); |
258 | 0 | if (!conversation) |
259 | 0 | return NULL; |
260 | | |
261 | 0 | drdynvc_conv_info_t *info = (drdynvc_conv_info_t *)conversation_get_proto_data(conversation, proto_rdp_drdynvc); |
262 | 0 | if (info == NULL) { |
263 | 0 | info = wmem_new0(wmem_file_scope(), drdynvc_conv_info_t); |
264 | 0 | info->channels = wmem_multimap_new(wmem_file_scope(), channel_hashFunc, channel_equalFunc); |
265 | 0 | conversation_add_proto_data(conversation, proto_rdp_drdynvc, info); |
266 | 0 | } |
267 | |
|
268 | 0 | return info; |
269 | 0 | } |
270 | | |
271 | | |
272 | | static int |
273 | | dissect_rdp_vlength(tvbuff_t *tvb, int hf_index, int offset, uint8_t vlen, proto_tree *tree, uint32_t *ret) |
274 | 0 | { |
275 | 0 | int len; |
276 | 0 | uint32_t value = 0; |
277 | |
|
278 | 0 | switch (vlen) { |
279 | 0 | case 0: |
280 | 0 | value = tvb_get_uint8(tvb, offset); |
281 | 0 | len = 1; |
282 | 0 | break; |
283 | 0 | case 1: |
284 | 0 | value = tvb_get_uint16(tvb, offset, ENC_LITTLE_ENDIAN); |
285 | 0 | len = 2; |
286 | 0 | break; |
287 | 0 | case 2: |
288 | 0 | value = tvb_get_uint32(tvb, offset, ENC_LITTLE_ENDIAN); |
289 | 0 | len = 4; |
290 | 0 | break; |
291 | 0 | default: |
292 | 0 | if (ret) |
293 | 0 | *ret = 0; |
294 | 0 | return 0; |
295 | 0 | } |
296 | | |
297 | 0 | proto_tree_add_uint(tree, hf_index, tvb, offset, len, value); |
298 | 0 | if (ret) |
299 | 0 | *ret = value; |
300 | 0 | return len; |
301 | 0 | } |
302 | | |
303 | | static const char * |
304 | 0 | find_channel_name_by_id(packet_info *pinfo, drdynvc_conv_info_t *dyninfo, uint32_t dvcId) { |
305 | 0 | drdynvc_channel_def_t *dynChannel = wmem_multimap_lookup32_le(dyninfo->channels, &dvcId, pinfo->num); |
306 | 0 | if (dynChannel) |
307 | 0 | return dynChannel->name; |
308 | | |
309 | 0 | return NULL; |
310 | 0 | } |
311 | | |
312 | | static drdynvc_pinfo_t *getDrDynPacketInfo(packet_info *pinfo) |
313 | 0 | { |
314 | 0 | drdynvc_pinfo_t *ret = p_get_proto_data(wmem_file_scope(), pinfo, proto_rdp_drdynvc, DRDYNVC_CHANNEL_PDUS_KEY); |
315 | 0 | if (ret) |
316 | 0 | return ret; |
317 | | |
318 | 0 | ret = wmem_alloc(wmem_file_scope(), sizeof(*ret)); |
319 | 0 | ret->pdus = wmem_tree_new(wmem_file_scope()); |
320 | |
|
321 | 0 | p_set_proto_data(wmem_file_scope(), pinfo, proto_rdp_drdynvc, DRDYNVC_CHANNEL_PDUS_KEY, ret); |
322 | 0 | return ret; |
323 | 0 | } |
324 | | |
325 | | static int |
326 | | dissect_rdp_drdynvc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, void *data _U_) |
327 | 0 | { |
328 | 0 | proto_item *item; |
329 | 0 | proto_tree *tree; |
330 | 0 | int offset = 0; |
331 | 0 | uint8_t cbIdSpCmd, cmdId; |
332 | 0 | uint8_t cbId, Len; |
333 | 0 | bool haveChannelId, havePri, haveLen; |
334 | 0 | bool isServerTarget = rdp_isServerAddressTarget(pinfo); |
335 | 0 | uint32_t channelId = 0; |
336 | 0 | uint32_t fullPduLen = 0; |
337 | 0 | drdynvc_conv_info_t *info; |
338 | 0 | drdynvc_channel_def_t *channel = NULL; |
339 | |
|
340 | 0 | col_set_str(pinfo->cinfo, COL_PROTOCOL, "DRDYNVC"); |
341 | 0 | col_clear(pinfo->cinfo, COL_INFO); |
342 | |
|
343 | 0 | parent_tree = proto_tree_get_root(parent_tree); |
344 | 0 | item = proto_tree_add_item(parent_tree, proto_rdp_drdynvc, tvb, 0, -1, ENC_NA); |
345 | 0 | tree = proto_item_add_subtree(item, ett_rdp_drdynvc); |
346 | |
|
347 | 0 | cbIdSpCmd = tvb_get_uint8(tvb, offset); |
348 | 0 | cmdId = (cbIdSpCmd >> 4) & 0xf; |
349 | 0 | cbId = (cbIdSpCmd & 0x3); |
350 | |
|
351 | 0 | haveChannelId = true; |
352 | 0 | havePri = false; |
353 | 0 | haveLen = false; |
354 | 0 | switch (cmdId) { |
355 | 0 | case DRDYNVC_CREATE_REQUEST_PDU: |
356 | 0 | havePri = true; |
357 | 0 | break; |
358 | 0 | case DRDYNVC_DATA_FIRST_PDU: |
359 | 0 | haveLen = true; |
360 | 0 | break; |
361 | 0 | case DRDYNVC_DATA_FIRST_COMPRESSED_PDU: |
362 | 0 | haveLen = true; |
363 | 0 | break; |
364 | 0 | case DRDYNVC_CAPABILITY_REQUEST_PDU: |
365 | 0 | case DRDYNVC_SOFT_SYNC_REQUEST_PDU: |
366 | 0 | case DRDYNVC_SOFT_SYNC_RESPONSE_PDU: |
367 | 0 | haveChannelId = false; |
368 | 0 | break; |
369 | 0 | default: |
370 | 0 | break; |
371 | 0 | } |
372 | | |
373 | 0 | proto_tree_add_item(tree, hf_rdp_drdynvc_cbId, tvb, offset, 1, ENC_NA); |
374 | 0 | if (havePri) |
375 | 0 | proto_tree_add_item(tree, hf_rdp_drdynvc_pri, tvb, offset, 1, ENC_NA); |
376 | 0 | else |
377 | 0 | proto_tree_add_item(tree, hf_rdp_drdynvc_sp, tvb, offset, 1, ENC_NA); |
378 | 0 | proto_tree_add_item(tree, hf_rdp_drdynvc_cmd, tvb, offset, 1, ENC_NA); |
379 | |
|
380 | 0 | offset++; |
381 | |
|
382 | 0 | info = drdynvc_get_conversation_data(pinfo); |
383 | 0 | if (!info) |
384 | 0 | return offset; |
385 | | |
386 | 0 | if (haveChannelId) { |
387 | 0 | offset += dissect_rdp_vlength(tvb, hf_rdp_drdynvc_channelId, offset, cbId, tree, &channelId); |
388 | |
|
389 | 0 | channel = wmem_multimap_lookup32_le(info->channels, &channelId, pinfo->num); |
390 | | #if 0 |
391 | | if (channel) |
392 | | printf("%d: channels=%p haveChannelId and channel (0x%x) %s\n", pinfo->num, info->channels, channelId, channel->name); |
393 | | else |
394 | | printf("%d: channels=%p haveChannelId and no channel for 0x%x\n", pinfo->num, info->channels, channelId); |
395 | | #endif |
396 | 0 | } |
397 | |
|
398 | 0 | if (haveLen) { |
399 | 0 | Len = (cbIdSpCmd >> 2) & 0x3; |
400 | 0 | offset += dissect_rdp_vlength(tvb, hf_rdp_drdynvc_length, offset, Len, tree, &fullPduLen); |
401 | 0 | } |
402 | |
|
403 | 0 | switch (cmdId) { |
404 | 0 | case DRDYNVC_CREATE_REQUEST_PDU: |
405 | 0 | if (!isServerTarget) { |
406 | 0 | unsigned nameLen = tvb_strsize(tvb, offset); |
407 | |
|
408 | 0 | char *channelName = NULL; |
409 | 0 | proto_tree_add_item_ret_display_string(tree, hf_rdp_drdynvc_channelName, tvb, offset, -1, ENC_ASCII, pinfo->pool, &channelName); |
410 | |
|
411 | 0 | col_append_sep_fstr(pinfo->cinfo, COL_INFO, ",", "CreateChannel Request(%s)", channelName); |
412 | |
|
413 | 0 | if (!PINFO_FD_VISITED(pinfo)) { |
414 | 0 | channel = wmem_alloc(wmem_file_scope(), sizeof(*channel)); |
415 | 0 | channel->channelId = channelId; |
416 | 0 | channel->name = (char*)tvb_get_string_enc(wmem_file_scope(), tvb, offset, nameLen, ENC_ASCII); |
417 | 0 | channel->type = drdynvc_find_channel_type(channel->name); |
418 | 0 | channel->createFrameId = pinfo->num; |
419 | 0 | channel->createConfirmFrameId = 0; |
420 | 0 | drdynvc_pending_packet_init(&channel->pending_cs, pinfo->num); |
421 | 0 | drdynvc_pending_packet_init(&channel->pending_sc, pinfo->num); |
422 | 0 | channel->zgfx_cs = zgfx_context_new(wmem_file_scope()); |
423 | 0 | channel->zgfx_sc = zgfx_context_new(wmem_file_scope()); |
424 | |
|
425 | 0 | wmem_multimap_insert32(info->channels, &channel->channelId, pinfo->num, channel); |
426 | | #if 0 |
427 | | printf("%d: adding new channel %s 0x%x, channels=%p\n", pinfo->num, channel->name, channelId, info->channels); |
428 | | #endif |
429 | 0 | } |
430 | |
|
431 | 0 | if (channel->createConfirmFrameId) { |
432 | 0 | proto_item_set_generated( |
433 | 0 | proto_tree_add_uint(tree, hf_rdp_drdynvc_createresp_frameid, tvb, 0, 0, channel->createConfirmFrameId) |
434 | 0 | ); |
435 | 0 | } |
436 | |
|
437 | 0 | } else { |
438 | 0 | char *channelName = "unknown"; |
439 | 0 | proto_tree_add_item(tree, hf_rdp_drdynvc_creationStatus, tvb, offset, 4, ENC_LITTLE_ENDIAN); |
440 | |
|
441 | 0 | if (channel) { |
442 | 0 | proto_item_set_generated( |
443 | 0 | proto_tree_add_string_format_value(tree, hf_rdp_drdynvc_createresp_channelname, tvb, offset, 0, NULL, "%s", channel->name) |
444 | 0 | ); |
445 | |
|
446 | 0 | if (!PINFO_FD_VISITED(pinfo)) { |
447 | 0 | if (!channel->createConfirmFrameId) |
448 | 0 | channel->createConfirmFrameId = pinfo->num; |
449 | 0 | } |
450 | |
|
451 | 0 | if (channel->createFrameId) { |
452 | 0 | proto_item_set_generated( |
453 | 0 | proto_tree_add_uint(tree, hf_rdp_drdynvc_createreq_frameid, tvb, 0, 0, channel->createFrameId) |
454 | 0 | ); |
455 | 0 | } |
456 | 0 | channelName = channel->name; |
457 | 0 | } |
458 | 0 | col_append_sep_fstr(pinfo->cinfo, COL_INFO, ",", "CreateChannel Response(%s)", channelName); |
459 | |
|
460 | 0 | } |
461 | 0 | break; |
462 | 0 | case DRDYNVC_CAPABILITY_REQUEST_PDU: { |
463 | | /* Pad */ |
464 | 0 | proto_tree_add_item(tree, hf_rdp_drdynvc_pad, tvb, offset, 1, ENC_NA); |
465 | 0 | offset++; |
466 | |
|
467 | 0 | uint32_t version; |
468 | 0 | proto_tree_add_item_ret_uint(tree, hf_rdp_drdynvc_capa_version, tvb, offset, 2, ENC_LITTLE_ENDIAN, &version); |
469 | 0 | offset += 2; |
470 | |
|
471 | 0 | if (!isServerTarget) { |
472 | 0 | col_append_sep_str(pinfo->cinfo, COL_INFO, ",", "Capabilities request"); |
473 | |
|
474 | 0 | if (version > 1) { |
475 | 0 | proto_tree_add_item(tree, hf_rdp_drdynvc_capa_prio0, tvb, offset, 2, ENC_LITTLE_ENDIAN); |
476 | 0 | offset += 2; |
477 | 0 | proto_tree_add_item(tree, hf_rdp_drdynvc_capa_prio1, tvb, offset, 2, ENC_LITTLE_ENDIAN); |
478 | 0 | offset += 2; |
479 | 0 | proto_tree_add_item(tree, hf_rdp_drdynvc_capa_prio2, tvb, offset, 2, ENC_LITTLE_ENDIAN); |
480 | 0 | offset += 2; |
481 | 0 | proto_tree_add_item(tree, hf_rdp_drdynvc_capa_prio3, tvb, offset, 2, ENC_LITTLE_ENDIAN); |
482 | 0 | offset += 2; |
483 | 0 | } |
484 | 0 | } else { |
485 | 0 | col_append_sep_str(pinfo->cinfo, COL_INFO, ",", "Capabilities response"); |
486 | 0 | } |
487 | 0 | break; |
488 | 0 | } |
489 | 0 | case DRDYNVC_DATA_FIRST_PDU: |
490 | 0 | case DRDYNVC_DATA_FIRST_COMPRESSED_PDU: { |
491 | 0 | col_append_sep_str(pinfo->cinfo, COL_INFO, ",", (cmdId == DRDYNVC_DATA_FIRST_PDU) ? "Data first" : "Data compressed first"); |
492 | |
|
493 | 0 | if (channel) { |
494 | 0 | drdynvc_pdu_info_t *pduInfo = NULL; |
495 | 0 | drdynvc_pending_packet_t *pendingPacket = isServerTarget ? &channel->pending_cs : &channel->pending_sc; |
496 | 0 | int payloadLen = tvb_reported_length_remaining(tvb, offset); |
497 | 0 | bool isSinglePacket = (fullPduLen == (uint32_t)payloadLen); |
498 | 0 | drdynvc_pinfo_t *drdynvcPinfo = getDrDynPacketInfo(pinfo); |
499 | 0 | uint32_t key = crc32_ccitt_tvb_offset(tvb, offset, payloadLen); |
500 | |
|
501 | 0 | proto_item_set_generated( |
502 | 0 | proto_tree_add_string_format_value(tree, hf_rdp_drdynvc_createresp_channelname, tvb, offset, 0, NULL, "%s", channel->name) |
503 | 0 | ); |
504 | |
|
505 | 0 | proto_item_set_generated( |
506 | 0 | proto_tree_add_string_format_value(tree, hf_rdp_drdynvc_data_progress, tvb, offset, 0, NULL, "0-%d/%d", payloadLen, fullPduLen) |
507 | 0 | ); |
508 | |
|
509 | 0 | if (!PINFO_FD_VISITED(pinfo)) { |
510 | 0 | tvbuff_t *input = tvb; |
511 | 0 | int offset2 = offset; |
512 | |
|
513 | 0 | if (cmdId == DRDYNVC_DATA_FIRST_COMPRESSED_PDU) { |
514 | 0 | zgfx_context_t *compressor = isServerTarget ? channel->zgfx_cs : channel->zgfx_sc; |
515 | 0 | input = rdp8_decompress(compressor, wmem_file_scope(), tvb, offset); |
516 | 0 | offset2 = 0; |
517 | 0 | add_new_data_source(pinfo, input, "decompressed dynvc"); |
518 | 0 | } |
519 | |
|
520 | 0 | if (!isSinglePacket) { |
521 | 0 | if (pendingPacket->chunks) |
522 | 0 | wmem_destroy_array(pendingPacket->chunks); |
523 | 0 | pendingPacket->chunks = wmem_array_new(wmem_file_scope(), sizeof(drdynvc_pdu_info_t*)); |
524 | |
|
525 | 0 | pduInfo = wmem_alloc(wmem_file_scope(), sizeof(*pduInfo)); |
526 | 0 | pduInfo->reassembled = true; |
527 | 0 | pduInfo->startReassemblyFrame = pinfo->num; |
528 | 0 | pduInfo->progressStart = 0; |
529 | 0 | pduInfo->progressEnd = fullPduLen; |
530 | 0 | pduInfo->tvb = (cmdId == DRDYNVC_DATA_FIRST_COMPRESSED_PDU) ? input : NULL; |
531 | |
|
532 | 0 | wmem_tree_insert32(drdynvcPinfo->pdus, key, pduInfo); |
533 | 0 | wmem_array_append(pendingPacket->chunks, &pduInfo, 1); |
534 | |
|
535 | 0 | pendingPacket->packetLen = fullPduLen; |
536 | 0 | pendingPacket->pendingLen = fullPduLen - payloadLen; |
537 | 0 | pendingPacket->startFrame = pinfo->num; |
538 | 0 | pendingPacket->currentPacket = wmem_array_sized_new(wmem_file_scope(), 1, fullPduLen); |
539 | 0 | wmem_array_append(pendingPacket->currentPacket, tvb_get_ptr(input, offset2, payloadLen), payloadLen); |
540 | 0 | } else { |
541 | 0 | if (pendingPacket->pendingLen || pendingPacket->chunks) |
542 | 0 | printf("(%d) looks like we have a non completed packet...\n", pinfo->num); |
543 | 0 | if (pendingPacket->chunks) |
544 | 0 | wmem_destroy_array(pendingPacket->chunks); |
545 | 0 | memset(pendingPacket, 0, sizeof(*pendingPacket)); |
546 | 0 | } |
547 | 0 | } else { |
548 | 0 | pduInfo = (drdynvc_pdu_info_t*)wmem_tree_lookup32(drdynvcPinfo->pdus, key); |
549 | 0 | } |
550 | |
|
551 | 0 | if (isSinglePacket) { |
552 | 0 | switch (channel->type) { |
553 | 0 | case DRDYNVC_CHANNEL_EGFX: |
554 | 0 | call_dissector(egfx_handle, tvb_new_subset_remaining(tvb, offset), pinfo, tree); |
555 | 0 | break; |
556 | 0 | case DRDYNVC_CHANNEL_RAIL: |
557 | 0 | call_dissector(rail_handle, tvb_new_subset_remaining(tvb, offset), pinfo, tree); |
558 | 0 | break; |
559 | 0 | case DRDYNVC_CHANNEL_CLIPRDR: |
560 | 0 | call_dissector(cliprdr_handle, tvb_new_subset_remaining(tvb, offset), pinfo, tree); |
561 | 0 | break; |
562 | 0 | case DRDYNVC_CHANNEL_AUDIOUT: |
563 | 0 | call_dissector(snd_handle, tvb_new_subset_remaining(tvb, offset), pinfo, tree); |
564 | 0 | break; |
565 | 0 | case DRDYNVC_CHANNEL_AUTH_REDIR: |
566 | 0 | call_dissector(ear_handle, tvb_new_subset_remaining(tvb, offset), pinfo, tree); |
567 | 0 | break; |
568 | 0 | case DRDYNVC_CHANNEL_CAM: |
569 | 0 | call_dissector(ecam_handle, tvb_new_subset_remaining(tvb, offset), pinfo, tree); |
570 | 0 | break; |
571 | 0 | case DRDYNVC_CHANNEL_DR: |
572 | 0 | call_dissector(rdpdr_handle, tvb_new_subset_remaining(tvb, offset), pinfo, tree); |
573 | 0 | break; |
574 | 0 | default: |
575 | 0 | proto_tree_add_item(tree, hf_rdp_drdynvc_data, tvb, offset, -1, ENC_NA); |
576 | 0 | break; |
577 | 0 | } |
578 | | |
579 | 0 | offset += payloadLen; |
580 | 0 | return offset; |
581 | 0 | } |
582 | |
|
583 | 0 | } |
584 | | |
585 | 0 | proto_tree_add_item(tree, hf_rdp_drdynvc_data, tvb, offset, -1, ENC_NA); |
586 | 0 | break; |
587 | 0 | } |
588 | 0 | case DRDYNVC_DATA_PDU: |
589 | 0 | case DRDYNVC_DATA_COMPRESSED_PDU: { |
590 | 0 | col_append_sep_str(pinfo->cinfo, COL_INFO, ",", (cmdId == DRDYNVC_DATA_PDU) ? "Data" : "Data compressed"); |
591 | |
|
592 | 0 | if (channel) { |
593 | 0 | tvbuff_t *targetTvb = NULL; |
594 | |
|
595 | 0 | proto_item_set_generated( |
596 | 0 | proto_tree_add_string_format_value(tree, hf_rdp_drdynvc_createresp_channelname, tvb, offset, 0, NULL, "%s", channel->name) |
597 | 0 | ); |
598 | |
|
599 | 0 | drdynvc_pinfo_t *drdynvcPinfo = getDrDynPacketInfo(pinfo); |
600 | 0 | drdynvc_pdu_info_t *pduInfo = NULL; |
601 | 0 | int payloadLen = tvb_reported_length_remaining(tvb, offset); |
602 | 0 | uint32_t key = crc32_ccitt_tvb_offset(tvb, offset, payloadLen); |
603 | |
|
604 | 0 | if (!PINFO_FD_VISITED(pinfo)) { |
605 | 0 | drdynvc_pending_packet_t *pendingPacket = isServerTarget ? &channel->pending_cs : &channel->pending_sc; |
606 | |
|
607 | 0 | tvbuff_t *input = tvb; |
608 | 0 | int offset2 = offset; |
609 | |
|
610 | 0 | if (cmdId == DRDYNVC_DATA_COMPRESSED_PDU) { |
611 | 0 | zgfx_context_t *compressor = isServerTarget ? channel->zgfx_cs : channel->zgfx_sc; |
612 | 0 | input = rdp8_decompress(compressor, wmem_file_scope(), tvb, offset); |
613 | 0 | offset2 = 0; |
614 | 0 | add_new_data_source(pinfo, input, "decompressed dynvc"); |
615 | 0 | } |
616 | |
|
617 | 0 | pduInfo = wmem_alloc(wmem_file_scope(), sizeof(*pduInfo)); |
618 | 0 | wmem_tree_insert32(drdynvcPinfo->pdus, key, pduInfo); |
619 | |
|
620 | 0 | if (pendingPacket->pendingLen) { |
621 | | /* we have a fragmented packet in progress */ |
622 | 0 | if ((uint32_t)payloadLen > pendingPacket->pendingLen) { |
623 | | // TODO: error |
624 | 0 | printf("num=%d error payload too big\n", pinfo->num); |
625 | 0 | return offset; |
626 | 0 | } |
627 | | |
628 | 0 | pduInfo->reassembled = true; |
629 | 0 | pduInfo->decodePayload = false; |
630 | 0 | pduInfo->progressStart = pendingPacket->packetLen - pendingPacket->pendingLen; |
631 | 0 | pduInfo->progressEnd = pduInfo->progressStart + payloadLen; |
632 | 0 | pduInfo->packetLen = pendingPacket->packetLen; |
633 | |
|
634 | 0 | wmem_array_append(pendingPacket->chunks, &pduInfo, 1); |
635 | |
|
636 | 0 | pendingPacket->pendingLen -= payloadLen; |
637 | 0 | wmem_array_append(pendingPacket->currentPacket, tvb_get_ptr(input, offset2, payloadLen), payloadLen); |
638 | |
|
639 | 0 | if (!pendingPacket->pendingLen) { |
640 | | /* last packet of the reassembly */ |
641 | 0 | int reassembled_len = wmem_array_get_count(pendingPacket->currentPacket); |
642 | 0 | pduInfo->tvb = tvb_new_real_data(wmem_array_get_raw(pendingPacket->currentPacket), reassembled_len, reassembled_len); |
643 | 0 | pduInfo->decodePayload = true; |
644 | 0 | pendingPacket->currentPacket = NULL; |
645 | |
|
646 | 0 | for (unsigned i = 0; i < wmem_array_get_count(pendingPacket->chunks); i++) { |
647 | 0 | drdynvc_pdu_info_t *chunk = *(drdynvc_pdu_info_t **)wmem_array_index(pendingPacket->chunks, i); |
648 | 0 | chunk->endReassemblyFrame = pinfo->num; |
649 | 0 | } |
650 | 0 | wmem_destroy_array(pendingPacket->chunks); |
651 | 0 | pendingPacket->chunks = NULL; |
652 | 0 | } |
653 | 0 | } else { |
654 | | /* single data packet */ |
655 | 0 | pduInfo->reassembled = false; |
656 | 0 | pduInfo->decodePayload = true; |
657 | 0 | pduInfo->progressStart = 0; |
658 | 0 | pduInfo->progressEnd = payloadLen; |
659 | 0 | pduInfo->packetLen = payloadLen; |
660 | 0 | pduInfo->tvb = (input == tvb) ? NULL : input; |
661 | 0 | pduInfo->startReassemblyFrame = pduInfo->endReassemblyFrame = pinfo->num; |
662 | 0 | } |
663 | 0 | } else { |
664 | 0 | pduInfo = (drdynvc_pdu_info_t*)wmem_tree_lookup32(drdynvcPinfo->pdus, key); |
665 | 0 | } |
666 | | |
667 | 0 | if (pduInfo) { |
668 | 0 | proto_item_set_generated( |
669 | 0 | proto_tree_add_string_format_value(tree, hf_rdp_drdynvc_data_progress, tvb, offset, 0, NULL, "%d-%d/%d", |
670 | 0 | pduInfo->progressStart, pduInfo->progressEnd, pduInfo->packetLen) |
671 | 0 | ); |
672 | |
|
673 | 0 | if (pduInfo->tvb) { |
674 | 0 | targetTvb = pduInfo->tvb; |
675 | 0 | add_new_data_source(pinfo, targetTvb, "Reassembled/decompressed DRDYNVC"); |
676 | 0 | } else { |
677 | 0 | targetTvb = tvb_new_subset_remaining(tvb, offset); |
678 | 0 | } |
679 | |
|
680 | 0 | if (pduInfo->endReassemblyFrame && (pduInfo->endReassemblyFrame != pinfo->num)) { |
681 | | // TODO: show a link to the end frame ? |
682 | 0 | } |
683 | 0 | } |
684 | |
|
685 | 0 | if (pduInfo && pduInfo->decodePayload) { |
686 | 0 | switch (channel->type) { |
687 | 0 | case DRDYNVC_CHANNEL_EGFX: |
688 | 0 | call_dissector(egfx_handle, targetTvb, pinfo, tree); |
689 | 0 | break; |
690 | 0 | case DRDYNVC_CHANNEL_RAIL: |
691 | 0 | call_dissector(rail_handle, targetTvb, pinfo, tree); |
692 | 0 | break; |
693 | 0 | case DRDYNVC_CHANNEL_CLIPRDR: |
694 | 0 | call_dissector(cliprdr_handle, targetTvb, pinfo, tree); |
695 | 0 | break; |
696 | 0 | case DRDYNVC_CHANNEL_AUDIOUT: |
697 | 0 | call_dissector(snd_handle, targetTvb, pinfo, tree); |
698 | 0 | break; |
699 | 0 | case DRDYNVC_CHANNEL_AUTH_REDIR: |
700 | 0 | call_dissector(ear_handle, targetTvb, pinfo, tree); |
701 | 0 | break; |
702 | 0 | case DRDYNVC_CHANNEL_CAM: |
703 | 0 | call_dissector(ecam_handle, targetTvb, pinfo, tree); |
704 | 0 | break; |
705 | 0 | case DRDYNVC_CHANNEL_DR: |
706 | 0 | call_dissector(rdpdr_handle, targetTvb, pinfo, tree); |
707 | 0 | break; |
708 | 0 | default: |
709 | 0 | proto_tree_add_item(tree, hf_rdp_drdynvc_data, targetTvb, 0, -1, ENC_NA); |
710 | 0 | break; |
711 | 0 | } |
712 | 0 | return tvb_reported_length(tvb); |
713 | 0 | } |
714 | 0 | } |
715 | | |
716 | 0 | proto_tree_add_item(tree, hf_rdp_drdynvc_data, tvb, offset, -1, ENC_NA); |
717 | 0 | return tvb_reported_length(tvb); |
718 | 0 | } |
719 | 0 | case DRDYNVC_SOFT_SYNC_REQUEST_PDU: { |
720 | 0 | uint32_t ntunnels; |
721 | 0 | uint32_t flags; |
722 | |
|
723 | 0 | col_set_str(pinfo->cinfo, COL_INFO, "SoftSync Request"); |
724 | | |
725 | | /* Pad */ |
726 | 0 | proto_tree_add_item(tree, hf_rdp_drdynvc_pad, tvb, offset, 1, ENC_NA); |
727 | 0 | offset++; |
728 | |
|
729 | 0 | proto_tree_add_item(tree, hf_rdp_drdynvc_softsync_req_length, tvb, offset, 4, ENC_LITTLE_ENDIAN); |
730 | 0 | offset += 4; |
731 | |
|
732 | 0 | proto_tree_add_item_ret_uint(tree, hf_rdp_drdynvc_softsync_req_flags, tvb, offset, 2, ENC_LITTLE_ENDIAN, &flags); |
733 | 0 | offset += 2; |
734 | | // XXX: TODO should decode flags but they are always set to SOFT_SYNC_TCP_FLUSHED|SOFT_SYNC_CHANNEL_LIST_PRESENT |
735 | |
|
736 | 0 | proto_tree_add_item_ret_uint(tree, hf_rdp_drdynvc_softsync_req_ntunnels, tvb, offset, 2, ENC_LITTLE_ENDIAN, &ntunnels); |
737 | 0 | offset += 2; |
738 | |
|
739 | 0 | if (flags & 0x02) { /* SOFT_SYNC_CHANNEL_LIST_PRESENT */ |
740 | 0 | proto_tree *tunnels_tree = proto_tree_add_subtree(tree, tvb, offset, -1, ett_rdp_drdynvc_softsync_channels, NULL, "Channels"); |
741 | |
|
742 | 0 | for (unsigned i = 0; i < ntunnels; i++) { |
743 | 0 | uint16_t j; |
744 | 0 | uint32_t tunnelType = tvb_get_uint32(tvb, offset, ENC_LITTLE_ENDIAN); |
745 | 0 | uint16_t ndvcs = tvb_get_uint16(tvb, offset + 4, ENC_LITTLE_ENDIAN); |
746 | 0 | int channelSz = 4 + 2 + (ndvcs * 4); |
747 | 0 | proto_tree *channel_tree; |
748 | 0 | const char *label = (tunnelType == 0x1) ? "Reliable channels" : "Lossy channels"; |
749 | |
|
750 | 0 | channel_tree = proto_tree_add_subtree(tunnels_tree, tvb, offset, channelSz, ett_rdp_drdynvc_softsync_channel, NULL, label); |
751 | |
|
752 | 0 | proto_tree_add_item(channel_tree, hf_rdp_drdynvc_softsync_req_channel_tunnelType, tvb, offset, 4, ENC_LITTLE_ENDIAN); |
753 | 0 | offset += 4; |
754 | |
|
755 | 0 | proto_tree_add_item(channel_tree, hf_rdp_drdynvc_softsync_req_channel_ndvc, tvb, offset, 2, ENC_LITTLE_ENDIAN); |
756 | 0 | offset += 2; |
757 | |
|
758 | 0 | for (j = 0; j < ndvcs; j++, offset += 4) { |
759 | 0 | proto_tree *dvc_tree; |
760 | 0 | uint32_t dvcId; |
761 | 0 | const char *showLabel; |
762 | |
|
763 | 0 | dvcId = tvb_get_uint32(tvb, offset, ENC_LITTLE_ENDIAN); |
764 | 0 | showLabel = label = find_channel_name_by_id(pinfo, info, dvcId); |
765 | 0 | if (!label) |
766 | 0 | showLabel = "DVC"; |
767 | 0 | dvc_tree = proto_tree_add_subtree(channel_tree, tvb, offset, 4, ett_rdp_drdynvc_softsync_dvc, NULL, showLabel); |
768 | 0 | proto_tree_add_item(dvc_tree, hf_rdp_drdynvc_softsync_req_channel_dvcid, tvb, offset, 4, ENC_LITTLE_ENDIAN); |
769 | |
|
770 | 0 | if (label) { |
771 | 0 | proto_item *pi = proto_tree_add_string_format(dvc_tree, hf_rdp_drdynvc_channelName, tvb, offset, 4, label, "%s", label); |
772 | 0 | proto_item_set_generated(pi); |
773 | 0 | } |
774 | 0 | } |
775 | 0 | } |
776 | 0 | } |
777 | 0 | break; |
778 | 0 | } |
779 | 0 | case DRDYNVC_SOFT_SYNC_RESPONSE_PDU: { |
780 | 0 | uint32_t ntunnels, i; |
781 | |
|
782 | 0 | col_set_str(pinfo->cinfo, COL_INFO, "SoftSync Response"); |
783 | | |
784 | | /* Pad */ |
785 | 0 | proto_tree_add_item(tree, hf_rdp_drdynvc_pad, tvb, offset, 1, ENC_NA); |
786 | 0 | offset++; |
787 | |
|
788 | 0 | proto_tree_add_item_ret_uint(tree, hf_rdp_drdynvc_softsync_resp_ntunnels, tvb, offset, 4, ENC_LITTLE_ENDIAN, &ntunnels); |
789 | 0 | offset += 4; |
790 | |
|
791 | 0 | if (ntunnels) { |
792 | 0 | proto_tree *tunnels_tree = proto_tree_add_subtree(tree, tvb, offset, 4, ett_rdp_drdynvc_softsync_dvc, NULL, "TunnelsToSwitch"); |
793 | 0 | for (i = 0; i < ntunnels; i++, offset += 4) { |
794 | 0 | proto_tree_add_item(tunnels_tree, hf_rdp_drdynvc_softsync_resp_tunnel, tvb, offset, 4, ENC_LITTLE_ENDIAN); |
795 | 0 | } |
796 | 0 | } |
797 | 0 | break; |
798 | 0 | } |
799 | 0 | case DRDYNVC_CLOSE_REQUEST_PDU: { |
800 | 0 | col_set_str(pinfo->cinfo, COL_INFO, "Close request"); |
801 | 0 | if (channel) { |
802 | 0 | proto_item_set_generated( |
803 | 0 | proto_tree_add_string_format_value(tree, hf_rdp_drdynvc_channelName, tvb, offset, 0, NULL, "%s", channel->name) |
804 | 0 | ); |
805 | 0 | } |
806 | 0 | break; |
807 | 0 | } |
808 | 0 | default: |
809 | 0 | break; |
810 | 0 | } |
811 | 0 | return offset; |
812 | 0 | } |
813 | | |
814 | 15 | void proto_register_rdp_drdynvc(void) { |
815 | | |
816 | | /* List of fields */ |
817 | 15 | static hf_register_info hf[] = { |
818 | 15 | { &hf_rdp_drdynvc_cbId, |
819 | 15 | { "ChannelId length", "rdp_drdynvc.cbid", |
820 | 15 | FT_UINT8, BASE_HEX, VALS(rdp_drdynvc_cbId_vals), 0x3, |
821 | 15 | NULL, HFILL }}, |
822 | 15 | { &hf_rdp_drdynvc_sp, |
823 | 15 | { "Sp", "rdp_drdynvc.sp", |
824 | 15 | FT_UINT8, BASE_HEX, NULL, 0xc, |
825 | 15 | NULL, HFILL }}, |
826 | 15 | { &hf_rdp_drdynvc_pri, |
827 | 15 | { "Pri", "rdp_drdynvc.pri", |
828 | 15 | FT_UINT8, BASE_HEX, VALS(rdp_drdynvc_prio_vals), 0xc, |
829 | 15 | NULL, HFILL }}, |
830 | 15 | { &hf_rdp_drdynvc_cmd, |
831 | 15 | { "PDU type", "rdp_drdynvc.cmd", |
832 | 15 | FT_UINT8, BASE_HEX, VALS(rdp_drdynvc_cmd_vals), 0xf0, |
833 | 15 | NULL, HFILL }}, |
834 | 15 | { &hf_rdp_drdynvc_capa_version, |
835 | 15 | { "Version", "rdp_drdynvc.capabilities.version", |
836 | 15 | FT_UINT16, BASE_DEC, NULL, 0, |
837 | 15 | NULL, HFILL }}, |
838 | 15 | { &hf_rdp_drdynvc_capa_prio0, |
839 | 15 | { "Priority charge 0", "rdp_drdynvc.capabilities.prioritycharge0", |
840 | 15 | FT_UINT16, BASE_DEC, NULL, 0, |
841 | 15 | NULL, HFILL }}, |
842 | 15 | { &hf_rdp_drdynvc_capa_prio1, |
843 | 15 | { "Priority charge 1", "rdp_drdynvc.capabilities.prioritycharge1", |
844 | 15 | FT_UINT16, BASE_DEC, NULL, 0, |
845 | 15 | NULL, HFILL }}, |
846 | 15 | { &hf_rdp_drdynvc_capa_prio2, |
847 | 15 | { "Priority charge 2", "rdp_drdynvc.capabilities.prioritycharge2", |
848 | 15 | FT_UINT16, BASE_DEC, NULL, 0, |
849 | 15 | NULL, HFILL }}, |
850 | 15 | { &hf_rdp_drdynvc_capa_prio3, |
851 | 15 | { "Priority charge 3", "rdp_drdynvc.capabilities.prioritycharge3", |
852 | 15 | FT_UINT16, BASE_DEC, NULL, 0, |
853 | 15 | NULL, HFILL }}, |
854 | 15 | { &hf_rdp_drdynvc_pad, |
855 | 15 | { "Padding", "rdp_drdynvc.pad", |
856 | 15 | FT_UINT8, BASE_HEX, NULL, 0, |
857 | 15 | NULL, HFILL }}, |
858 | 15 | { &hf_rdp_drdynvc_channelId, |
859 | 15 | { "Channel Id", "rdp_drdynvc.channelId", |
860 | 15 | FT_UINT32, BASE_HEX, NULL, 0, |
861 | 15 | NULL, HFILL }}, |
862 | 15 | { &hf_rdp_drdynvc_length, |
863 | 15 | { "Length", "rdp_drdynvc.length", |
864 | 15 | FT_UINT32, BASE_DEC, NULL, 0, |
865 | 15 | NULL, HFILL }}, |
866 | 15 | { &hf_rdp_drdynvc_channelName, |
867 | 15 | { "Channel Name", "rdp_drdynvc.channelName", |
868 | 15 | FT_STRINGZ, BASE_NONE, NULL, 0, |
869 | 15 | NULL, HFILL }}, |
870 | 15 | { &hf_rdp_drdynvc_creationStatus, |
871 | 15 | { "Creation status", "rdp_drdynvc.createresponse.status", |
872 | 15 | FT_INT32, BASE_DEC, NULL, 0, |
873 | 15 | NULL, HFILL }}, |
874 | 15 | { &hf_rdp_drdynvc_softsync_req_length, |
875 | 15 | { "Length", "rdp_drdynvc.softsyncreq.length", |
876 | 15 | FT_UINT32, BASE_DEC, NULL, 0, |
877 | 15 | NULL, HFILL }}, |
878 | 15 | { &hf_rdp_drdynvc_softsync_req_flags, |
879 | 15 | { "Flags", "rdp_drdynvc.softsyncreq.flags", |
880 | 15 | FT_UINT16, BASE_DEC, NULL, 0, |
881 | 15 | NULL, HFILL }}, |
882 | 15 | { &hf_rdp_drdynvc_softsync_req_ntunnels, |
883 | 15 | { "NumberOfTunnels", "rdp_drdynvc.softsyncreq.ntunnels", |
884 | 15 | FT_UINT16, BASE_DEC, NULL, 0, |
885 | 15 | NULL, HFILL }}, |
886 | 15 | { &hf_rdp_drdynvc_softsync_req_channel_tunnelType, |
887 | 15 | { "Tunnel type", "rdp_drdynvc.softsyncreq.channel.tunnelType", |
888 | 15 | FT_UINT32, BASE_HEX, VALS(drdynvc_tunneltype_vals), 0, |
889 | 15 | NULL, HFILL }}, |
890 | 15 | { &hf_rdp_drdynvc_softsync_req_channel_ndvc, |
891 | 15 | { "Number of DVCs", "rdp_drdynvc.softsyncreq.channel.ndvcid", |
892 | 15 | FT_UINT16, BASE_DEC, NULL, 0, |
893 | 15 | NULL, HFILL }}, |
894 | 15 | { &hf_rdp_drdynvc_softsync_req_channel_dvcid, |
895 | 15 | { "DVC Id", "rdp_drdynvc.softsyncreq.channel.dvcid", |
896 | 15 | FT_UINT32, BASE_HEX, NULL, 0, |
897 | 15 | NULL, HFILL }}, |
898 | 15 | { &hf_rdp_drdynvc_softsync_resp_ntunnels, |
899 | 15 | { "Number of tunnels", "rdp_drdynvc.softsyncresp.ntunnels", |
900 | 15 | FT_UINT32, BASE_DEC, NULL, 0, |
901 | 15 | NULL, HFILL }}, |
902 | 15 | { &hf_rdp_drdynvc_softsync_resp_tunnel, |
903 | 15 | { "Number of tunnels", "rdp_drdynvc.softsyncresp.tunnel", |
904 | 15 | FT_UINT32, BASE_DEC, VALS(drdynvc_tunneltype_vals), 0, |
905 | 15 | NULL, HFILL }}, |
906 | 15 | { &hf_rdp_drdynvc_createreq_frameid, |
907 | 15 | { "Created at framed id", "rdp_drdynvc.createreqframeid", |
908 | 15 | FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_REQUEST), 0x0, |
909 | 15 | NULL, HFILL } |
910 | 15 | }, |
911 | 15 | { &hf_rdp_drdynvc_createresp_frameid, |
912 | 15 | { "Create response at framed id", "rdp_drdynvc.createrespframeid", |
913 | 15 | FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_RESPONSE), 0x0, |
914 | 15 | NULL, HFILL } |
915 | 15 | }, |
916 | 15 | { &hf_rdp_drdynvc_createresp_channelname, |
917 | 15 | { "ChannelName", "rdp_drdynvc.createresp", |
918 | 15 | FT_STRINGZ, BASE_NONE, NULL, 0x0, |
919 | 15 | NULL, HFILL }}, |
920 | 15 | { &hf_rdp_drdynvc_data_progress, |
921 | 15 | { "DataProgress", "rdp_drdynvc.data_progress", |
922 | 15 | FT_STRINGZ, BASE_NONE, NULL, 0x0, |
923 | 15 | NULL, HFILL }}, |
924 | 15 | { &hf_rdp_drdynvc_data, |
925 | 15 | { "Data", "rdp_drdynvc.data", |
926 | 15 | FT_BYTES, BASE_NONE, NULL, 0, |
927 | 15 | NULL, HFILL }}, |
928 | 15 | }; |
929 | | |
930 | | /* List of subtrees */ |
931 | 15 | static int *ett[] = { |
932 | 15 | &ett_rdp_drdynvc, |
933 | 15 | &ett_rdp_drdynvc_softsync_channels, |
934 | 15 | &ett_rdp_drdynvc_softsync_channel, |
935 | 15 | &ett_rdp_drdynvc_softsync_dvc |
936 | 15 | }; |
937 | | |
938 | 15 | proto_rdp_drdynvc = proto_register_protocol("RDP Dynamic Channel Protocol", "DRDYNVC", "rdp_drdynvc"); |
939 | | /* Register fields and subtrees */ |
940 | 15 | proto_register_field_array(proto_rdp_drdynvc, hf, array_length(hf)); |
941 | 15 | proto_register_subtree_array(ett, array_length(ett)); |
942 | | |
943 | 15 | register_dissector("rdp_drdynvc", dissect_rdp_drdynvc, proto_rdp_drdynvc); |
944 | 15 | } |
945 | | |
946 | 15 | void proto_reg_handoff_drdynvc(void) { |
947 | 15 | egfx_handle = find_dissector("rdp_egfx"); |
948 | 15 | rail_handle = find_dissector("rdp_rail"); |
949 | 15 | rdpdr_handle = find_dissector("rdpdr"); |
950 | 15 | cliprdr_handle = find_dissector("rdp_cliprdr"); |
951 | 15 | snd_handle = find_dissector("rdp_snd"); |
952 | 15 | ear_handle = find_dissector("rdp_ear"); |
953 | 15 | ecam_handle = find_dissector("rdp_ecam"); |
954 | 15 | } |
955 | | |
956 | | /* |
957 | | * Editor modelines - https://www.wireshark.org/tools/modelines.html |
958 | | * |
959 | | * Local Variables: |
960 | | * c-basic-offset: 2 |
961 | | * tab-width: 8 |
962 | | * indent-tabs-mode: nil |
963 | | * End: |
964 | | * |
965 | | * ex: set shiftwidth=2 tabstop=8 expandtab: |
966 | | * :indentSize=2:tabSize=8:noTabs=true: |
967 | | */ |