Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-rdp_egfx.c
blob0698e48301c858a3fbb78c8e4e79bcbbfd882f58
1 /* Packet-rdp_egfx.c
2 * Routines for the EGFX RDP channel
3 * Copyright 2021, David Fort <contact@hardening-consulting.com>
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
9 * SPDX-License-Identifier: GPL-2.0-or-later
13 * See: "[MS-RDPEGFX] "
16 #include "config.h"
18 #include <epan/packet.h>
19 #include <epan/prefs.h>
20 #include <epan/conversation.h>
21 #include <epan/expert.h>
22 #include <epan/proto_data.h>
23 #include <epan/tvbuff_rdp.h>
24 #include <epan/crc32-tvb.h>
26 #include "packet-rdp.h"
27 #include "packet-rdpudp.h"
29 void proto_register_rdp_egfx(void);
30 void proto_reg_handoff_rdp_egfx(void);
32 static int proto_rdp_egfx;
34 static int hf_egfx_cmdId;
35 static int hf_egfx_flags;
36 static int hf_egfx_pduLength;
38 static int hf_egfx_caps_capsSetCount;
39 static int hf_egfx_cap_version;
40 static int hf_egfx_cap_length;
42 static int hf_egfx_reset_width;
43 static int hf_egfx_reset_height;
44 static int hf_egfx_reset_monitorCount;
45 static int hf_egfx_reset_monitorDefLeft;
46 static int hf_egfx_reset_monitorDefTop;
47 static int hf_egfx_reset_monitorDefRight;
48 static int hf_egfx_reset_monitorDefBottom;
49 static int hf_egfx_reset_monitorDefFlags;
52 static int hf_egfx_ack_queue_depth;
53 static int hf_egfx_ack_frame_id;
54 static int hf_egfx_ack_total_decoded;
55 static int hf_egfx_ack_frame_start;
56 static int hf_egfx_ack_frame_end;
58 static int hf_egfx_ackqoe_frame_id;
59 static int hf_egfx_ackqoe_timestamp;
60 static int hf_egfx_ackqoe_timediffse;
61 static int hf_egfx_ackqoe_timediffedr;
62 static int hf_egfx_ackqoe_frame_start;
63 static int hf_egfx_ackqoe_frame_end;
65 static int hf_egfx_start_timestamp;
66 static int hf_egfx_start_frameid;
67 static int hf_egfx_start_acked_in;
69 static int hf_egfx_end_frameid;
70 static int hf_egfx_end_acked_in;
73 static int ett_rdp_egfx;
74 static int ett_egfx_caps;
75 static int ett_egfx_capsconfirm;
76 static int ett_egfx_cap;
77 static int ett_egfx_cap_version;
78 static int ett_egfx_ack;
79 static int ett_egfx_ackqoe;
80 static int ett_egfx_reset;
81 static int ett_egfx_monitors;
82 static int ett_egfx_monitordef;
85 static expert_field ei_egfx_pdulen_invalid;
86 static expert_field ei_egfx_invalid_compression;
89 #define PNAME "RDP Graphic pipeline channel Protocol"
90 #define PSNAME "EGFX"
91 #define PFNAME "rdp_egfx"
93 enum {
94 RDPGFX_CMDID_WIRETOSURFACE_1 = 0x0001,
95 RDPGFX_CMDID_WIRETOSURFACE_2 = 0x0002,
96 RDPGFX_CMDID_DELETEENCODINGCONTEXT = 0x0003,
97 RDPGFX_CMDID_SOLIDFILL = 0x0004,
98 RDPGFX_CMDID_SURFACETOSURFACE = 0x0005,
99 RDPGFX_CMDID_SURFACETOCACHE = 0x0006,
100 RDPGFX_CMDID_CACHETOSURFACE = 0x0007,
101 RDPGFX_CMDID_EVICTCACHEENTRY = 0x0008,
102 RDPGFX_CMDID_CREATESURFACE = 0x0009,
103 RDPGFX_CMDID_DELETESURFACE = 0x000a,
104 RDPGFX_CMDID_STARTFRAME = 0x000b,
105 RDPGFX_CMDID_ENDFRAME = 0x000c,
106 RDPGFX_CMDID_FRAMEACKNOWLEDGE = 0x000d,
107 RDPGFX_CMDID_RESETGRAPHICS = 0x000e,
108 RDPGFX_CMDID_MAPSURFACETOOUTPUT = 0x000f,
109 RDPGFX_CMDID_CACHEIMPORTOFFER = 0x0010,
110 RDPGFX_CMDID_CACHEIMPORTREPLY = 0x0011,
111 RDPGFX_CMDID_CAPSADVERTISE = 0x0012,
112 RDPGFX_CMDID_CAPSCONFIRM = 0x0013,
113 RDPGFX_CMDID_MAPSURFACETOWINDOW = 0x0015,
114 RDPGFX_CMDID_QOEFRAMEACKNOWLEDGE = 0x0016,
115 RDPGFX_CMDID_MAPSURFACETOSCALEDOUTPUT = 0x0017,
116 RDPGFX_CMDID_MAPSURFACETOSCALEDWINDOW = 0x0018,
119 enum {
120 RDPGFX_CAPVERSION_8 = 0x00080004,
121 RDPGFX_CAPVERSION_81 = 0x00080105,
122 RDPGFX_CAPVERSION_10 = 0x000A0002,
123 RDPGFX_CAPVERSION_101 = 0x000A0100,
124 RDPGFX_CAPVERSION_102 = 0x000A0200,
125 RDPGFX_CAPVERSION_103 = 0x000A0301,
126 RDPGFX_CAPVERSION_104 = 0x000A0400,
127 RDPGFX_CAPVERSION_105 = 0x000A0502,
128 RDPGFX_CAPVERSION_106_ERROR = 0x000A0600,
129 RDPGFX_CAPVERSION_106 = 0x000A0601,
130 RDPGFX_CAPVERSION_107 = 0x000A0701
133 static const value_string rdp_egfx_cmd_vals[] = {
134 { RDPGFX_CMDID_WIRETOSURFACE_1, "Wire to surface 1" },
135 { RDPGFX_CMDID_WIRETOSURFACE_2, "Wire to surface 2" },
136 { RDPGFX_CMDID_DELETEENCODINGCONTEXT, "delete encoding context" },
137 { RDPGFX_CMDID_SOLIDFILL, "Solid fill" },
138 { RDPGFX_CMDID_SURFACETOSURFACE, "Surface to surface" },
139 { RDPGFX_CMDID_SURFACETOCACHE, "Surface to cache" },
140 { RDPGFX_CMDID_CACHETOSURFACE, "Cache to surface" },
141 { RDPGFX_CMDID_EVICTCACHEENTRY, "Evict cache entry" },
142 { RDPGFX_CMDID_CREATESURFACE, "Create surface" },
143 { RDPGFX_CMDID_DELETESURFACE, "Delete surface" },
144 { RDPGFX_CMDID_STARTFRAME, "Start frame" },
145 { RDPGFX_CMDID_ENDFRAME, "End frame" },
146 { RDPGFX_CMDID_FRAMEACKNOWLEDGE, "Frame acknowledge" },
147 { RDPGFX_CMDID_RESETGRAPHICS, "Reset graphics" },
148 { RDPGFX_CMDID_MAPSURFACETOOUTPUT, "Map Surface to output" },
149 { RDPGFX_CMDID_CACHEIMPORTOFFER, "Cache import offer" },
150 { RDPGFX_CMDID_CACHEIMPORTREPLY, "Cache import reply" },
151 { RDPGFX_CMDID_CAPSADVERTISE, "Caps advertise" },
152 { RDPGFX_CMDID_CAPSCONFIRM, "Caps confirm" },
153 { RDPGFX_CMDID_MAPSURFACETOWINDOW, "Map surface to window" },
154 { RDPGFX_CMDID_QOEFRAMEACKNOWLEDGE, "Qoe frame acknowledge" },
155 { RDPGFX_CMDID_MAPSURFACETOSCALEDOUTPUT, "Map surface to scaled output" },
156 { RDPGFX_CMDID_MAPSURFACETOSCALEDWINDOW, "Map surface to scaled window" },
157 { 0x0, NULL },
160 static const value_string rdp_egfx_caps_version_vals[] = {
161 { RDPGFX_CAPVERSION_8, "8.0" },
162 { RDPGFX_CAPVERSION_81, "8.1" } ,
163 { RDPGFX_CAPVERSION_10, "10.0" } ,
164 { RDPGFX_CAPVERSION_101, "10.1" },
165 { RDPGFX_CAPVERSION_102, "10.2" },
166 { RDPGFX_CAPVERSION_103, "10.3" },
167 { RDPGFX_CAPVERSION_104, "10.4" },
168 { RDPGFX_CAPVERSION_105, "10.5" },
169 { RDPGFX_CAPVERSION_106_ERROR, "10.6 bogus" },
170 { RDPGFX_CAPVERSION_106, "10.6" },
171 { RDPGFX_CAPVERSION_107, "10.7" },
172 { 0x0, NULL },
175 static const value_string rdp_egfx_monitor_flags_vals[] = {
176 { 0x00000000, "is secondary" },
177 { 0x00000001, "is primary" },
178 { 0x0, NULL },
182 typedef struct {
183 zgfx_context_t *zgfx;
184 wmem_map_t *frames;
185 } egfx_conv_info_t;
187 enum {
188 EGFX_PDU_KEY = 1
191 typedef struct {
192 wmem_tree_t* pdus;
193 } egfx_pdu_info_t;
195 typedef struct {
196 int startNum;
197 int endNum;
198 int ackNum;
199 } egfx_frame_t;
201 static const char *
202 find_egfx_version(uint32_t v) {
203 const value_string *vs = rdp_egfx_caps_version_vals;
204 for ( ; vs->strptr; vs++)
205 if (vs->value == v)
206 return vs->strptr;
208 return "<unknown>";
211 static egfx_conv_info_t *
212 egfx_get_conversation_data(packet_info *pinfo)
214 conversation_t *conversation, *conversation_tcp;
215 egfx_conv_info_t *info;
217 conversation = find_or_create_conversation(pinfo);
219 info = (egfx_conv_info_t *)conversation_get_proto_data(conversation, proto_rdp_egfx);
220 if (!info) {
221 conversation_tcp = rdp_find_tcp_conversation_from_udp(conversation);
222 if (conversation_tcp)
223 info = (egfx_conv_info_t *)conversation_get_proto_data(conversation_tcp, proto_rdp_egfx);
226 if (info == NULL) {
227 info = wmem_new0(wmem_file_scope(), egfx_conv_info_t);
228 info->zgfx = zgfx_context_new(wmem_file_scope());
229 info->frames = wmem_map_new(wmem_file_scope(), g_direct_hash, g_direct_equal);
230 conversation_add_proto_data(conversation, proto_rdp_egfx, info);
233 return info;
237 static int
238 dissect_rdp_egfx_payload(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, egfx_conv_info_t *conv, void *data _U_)
240 proto_item *item;
241 proto_item *pi;
242 proto_tree *tree;
243 proto_tree *subtree;
244 int offset = 0;
245 uint32_t cmdId = 0;
246 uint32_t pduLength;
247 uint32_t i;
249 parent_tree = proto_tree_get_root(parent_tree);
250 col_set_str(pinfo->cinfo, COL_PROTOCOL, "EGFX");
251 col_clear(pinfo->cinfo, COL_INFO);
253 while (tvb_captured_length_remaining(tvb, offset) > 8) {
254 pduLength = tvb_get_uint32(tvb, offset + 4, ENC_LITTLE_ENDIAN);
256 item = proto_tree_add_item(parent_tree, proto_rdp_egfx, tvb, offset, pduLength, ENC_NA);
257 tree = proto_item_add_subtree(item, ett_rdp_egfx);
259 proto_tree_add_item_ret_uint(tree, hf_egfx_cmdId, tvb, offset, 2, ENC_LITTLE_ENDIAN, &cmdId);
260 offset += 2;
262 proto_tree_add_item(tree, hf_egfx_flags, tvb, offset, 2, ENC_LITTLE_ENDIAN);
263 offset += 2;
265 proto_tree_add_item(tree, hf_egfx_pduLength, tvb, offset, 4, ENC_LITTLE_ENDIAN);
266 offset += 4;
268 if (pduLength < 8) {
269 expert_add_info_format(pinfo, item, &ei_egfx_pdulen_invalid, "pduLength is %u, not < 8", pduLength);
270 return offset;
273 int nextOffset = offset + (pduLength - 8);
274 switch (cmdId) {
275 case RDPGFX_CMDID_CAPSADVERTISE: {
276 uint16_t capsSetCount = tvb_get_uint16(tvb, offset, ENC_LITTLE_ENDIAN);
278 col_append_sep_str(pinfo->cinfo, COL_INFO, ",", "Caps advertise");
279 proto_tree_add_item(tree, hf_egfx_caps_capsSetCount, tvb, offset, 2, ENC_LITTLE_ENDIAN);
281 subtree = proto_tree_add_subtree(tree, tvb, offset, pduLength-8, ett_egfx_caps, NULL, "Caps");
282 offset += 2;
284 for (i = 0; i < capsSetCount; i++) {
285 uint32_t version = tvb_get_uint32(tvb, offset, ENC_LITTLE_ENDIAN);
286 uint32_t capsDataLength = tvb_get_uint32(tvb, offset + 4, ENC_LITTLE_ENDIAN);
287 proto_tree* vtree = proto_tree_add_subtree(subtree, tvb, offset, 8 + capsDataLength, ett_egfx_cap_version, NULL, find_egfx_version(version));
289 proto_tree_add_item(vtree, hf_egfx_cap_version, tvb, offset, 4, ENC_LITTLE_ENDIAN);
290 offset += 4;
292 proto_tree_add_item(vtree, hf_egfx_cap_length, tvb, offset, 4, ENC_LITTLE_ENDIAN);
293 offset += 4;
295 offset += capsDataLength;
297 break;
300 case RDPGFX_CMDID_CAPSCONFIRM: {
301 uint32_t capsDataLength;
303 col_append_sep_str(pinfo->cinfo, COL_INFO, ",", "Caps confirm");
305 subtree = proto_tree_add_subtree(tree, tvb, offset, pduLength-8, ett_egfx_capsconfirm, NULL, "Caps confirm");
306 proto_tree_add_item(subtree, hf_egfx_cap_version, tvb, offset, 4, ENC_LITTLE_ENDIAN);
307 offset += 4;
309 proto_tree_add_item_ret_uint(subtree, hf_egfx_cap_length, tvb, offset, 4, ENC_LITTLE_ENDIAN, &capsDataLength);
310 break;
313 case RDPGFX_CMDID_RESETGRAPHICS: {
314 uint32_t nmonitor;
315 proto_tree *monitors_tree;
316 col_append_sep_str(pinfo->cinfo, COL_INFO, ",", "Reset graphics");
318 subtree = proto_tree_add_subtree(tree, tvb, offset, pduLength-8, ett_egfx_reset, NULL, "Reset graphics");
319 proto_tree_add_item(subtree, hf_egfx_reset_width, tvb, offset, 4, ENC_LITTLE_ENDIAN);
320 offset += 4;
322 proto_tree_add_item(subtree, hf_egfx_reset_height, tvb, offset, 4, ENC_LITTLE_ENDIAN);
323 offset += 4;
325 proto_tree_add_item_ret_uint(subtree, hf_egfx_reset_monitorCount, tvb, offset, 4, ENC_LITTLE_ENDIAN, &nmonitor);
326 offset += 4;
328 monitors_tree = proto_tree_add_subtree(subtree, tvb, offset, nmonitor * 20, ett_egfx_monitors, NULL, "Monitors");
329 for (i = 0; i < nmonitor; i++) {
330 proto_item *monitor_tree;
331 uint32_t left, top, right, bottom;
332 left = tvb_get_uint32(tvb, offset, ENC_LITTLE_ENDIAN);
333 top = tvb_get_uint32(tvb, offset+4, ENC_LITTLE_ENDIAN);
334 right = tvb_get_uint32(tvb, offset+8, ENC_LITTLE_ENDIAN);
335 bottom = tvb_get_uint32(tvb, offset+12, ENC_LITTLE_ENDIAN);
337 monitor_tree = proto_tree_add_subtree_format(monitors_tree, tvb, offset, 20, ett_egfx_monitordef, NULL,
338 "(%d,%d) - (%d,%d)", left, top, right, bottom);
340 proto_tree_add_item(monitor_tree, hf_egfx_reset_monitorDefLeft, tvb, offset, 4, ENC_LITTLE_ENDIAN);
341 offset += 4;
343 proto_tree_add_item(monitor_tree, hf_egfx_reset_monitorDefTop, tvb, offset, 4, ENC_LITTLE_ENDIAN);
344 offset += 4;
346 proto_tree_add_item(monitor_tree, hf_egfx_reset_monitorDefRight, tvb, offset, 4, ENC_LITTLE_ENDIAN);
347 offset += 4;
349 proto_tree_add_item(monitor_tree, hf_egfx_reset_monitorDefBottom, tvb, offset, 4, ENC_LITTLE_ENDIAN);
350 offset += 4;
352 proto_tree_add_item(monitor_tree, hf_egfx_reset_monitorDefFlags, tvb, offset, 4, ENC_LITTLE_ENDIAN);
353 offset += 4;
355 break;
358 case RDPGFX_CMDID_STARTFRAME: {
359 uint32_t frameId;
360 egfx_frame_t *frame;
361 col_append_sep_str(pinfo->cinfo, COL_INFO, ",", "Start frame");
362 proto_tree_add_item(tree, hf_egfx_start_timestamp, tvb, offset, 4, ENC_LITTLE_ENDIAN);
363 // TODO: dissect timestamp
364 offset += 4;
366 proto_tree_add_item_ret_uint(tree, hf_egfx_start_frameid, tvb, offset, 4, ENC_LITTLE_ENDIAN, &frameId);
367 frame = wmem_map_lookup(conv->frames, GUINT_TO_POINTER(frameId));
368 if (!frame) {
369 frame = wmem_alloc0(wmem_file_scope(), sizeof(*frame));
370 frame->startNum = pinfo->num;
371 frame->endNum = -1;
372 frame->ackNum = -1;
373 wmem_map_insert(conv->frames, GUINT_TO_POINTER(frameId), frame);
376 if (PINFO_FD_VISITED(pinfo) && frame->ackNum != -1) {
377 pi = proto_tree_add_uint(tree, hf_egfx_start_acked_in, tvb, 0, 0, frame->ackNum);
378 proto_item_set_generated(pi);
380 break;
383 case RDPGFX_CMDID_ENDFRAME: {
384 uint32_t frameId;
385 egfx_frame_t *frame;
387 col_append_sep_str(pinfo->cinfo, COL_INFO, ",", "End frame");
388 proto_tree_add_item_ret_uint(tree, hf_egfx_end_frameid, tvb, offset, 4, ENC_LITTLE_ENDIAN, &frameId);
390 frame = wmem_map_lookup(conv->frames, GUINT_TO_POINTER(frameId));
391 if (!frame) {
392 frame = wmem_alloc0(wmem_file_scope(), sizeof(*frame));
393 frame->startNum = -1;
394 frame->ackNum = -1;
395 wmem_map_insert(conv->frames, GUINT_TO_POINTER(frameId), frame);
398 frame->endNum = pinfo->num;
400 if (PINFO_FD_VISITED(pinfo) && frame->ackNum != -1) {
401 pi = proto_tree_add_uint(tree, hf_egfx_end_acked_in, tvb, 0, 0, frame->ackNum);
402 proto_item_set_generated(pi);
405 break;
408 case RDPGFX_CMDID_FRAMEACKNOWLEDGE: {
409 uint32_t frameId;
410 egfx_frame_t *frame;
412 col_append_sep_str(pinfo->cinfo, COL_INFO, ",", "Frame acknowledge");
413 subtree = proto_tree_add_subtree(tree, tvb, offset, -1, ett_egfx_ack, NULL, "Frame acknowledge");
414 proto_tree_add_item(subtree, hf_egfx_ack_queue_depth, tvb, offset, 4, ENC_LITTLE_ENDIAN);
415 offset += 4;
417 proto_tree_add_item_ret_uint(subtree, hf_egfx_ack_frame_id, tvb, offset, 4, ENC_LITTLE_ENDIAN, &frameId);
418 offset += 4;
420 proto_tree_add_item(subtree, hf_egfx_ack_total_decoded, tvb, offset, 4, ENC_LITTLE_ENDIAN);
422 frame = wmem_map_lookup(conv->frames, GUINT_TO_POINTER(frameId));
423 if (!frame) {
424 frame = wmem_alloc0(wmem_file_scope(), sizeof(*frame));
425 frame->startNum = -1;
426 frame->endNum = -1;
427 frame->ackNum = frameId;
428 wmem_map_insert(conv->frames, GUINT_TO_POINTER(frameId), frame);
431 frame->ackNum = pinfo->num;
433 if (PINFO_FD_VISITED(pinfo) && frame->startNum != -1) {
434 pi = proto_tree_add_uint(tree, hf_egfx_ack_frame_start, tvb, 0, 0, frame->startNum);
435 proto_item_set_generated(pi);
438 if (PINFO_FD_VISITED(pinfo) && frame->endNum != -1) {
439 pi = proto_tree_add_uint(tree, hf_egfx_ack_frame_end, tvb, 0, 0, frame->endNum);
440 proto_item_set_generated(pi);
442 break;
445 case RDPGFX_CMDID_QOEFRAMEACKNOWLEDGE: {
446 uint32_t frameId;
447 egfx_frame_t *frame;
449 col_append_sep_str(pinfo->cinfo, COL_INFO, ",", "Frame acknowledge QoE");
450 subtree = proto_tree_add_subtree(tree, tvb, offset, -1, ett_egfx_ackqoe, NULL, "Frame acknowledge QoE");
451 proto_tree_add_item_ret_uint(subtree, hf_egfx_ackqoe_frame_id, tvb, offset, 4, ENC_LITTLE_ENDIAN, &frameId);
452 offset += 4;
454 proto_tree_add_item(subtree, hf_egfx_ackqoe_timestamp, tvb, offset, 4, ENC_LITTLE_ENDIAN);
455 offset += 4;
457 proto_tree_add_item(subtree, hf_egfx_ackqoe_timediffse, tvb, offset, 2, ENC_LITTLE_ENDIAN);
458 offset += 2;
460 proto_tree_add_item(subtree, hf_egfx_ackqoe_timediffedr, tvb, offset, 2, ENC_LITTLE_ENDIAN);
461 frame = wmem_map_lookup(conv->frames, GUINT_TO_POINTER(frameId));
462 if (!frame) {
463 frame = wmem_alloc0(wmem_file_scope(), sizeof(*frame));
464 frame->startNum = -1;
465 frame->endNum = -1;
466 frame->ackNum = frameId;
467 wmem_map_insert(conv->frames, GUINT_TO_POINTER(frameId), frame);
470 frame->ackNum = pinfo->num;
472 if (PINFO_FD_VISITED(pinfo) && frame->startNum != -1) {
473 pi = proto_tree_add_uint(tree, hf_egfx_ackqoe_frame_start, tvb, 0, 0, frame->startNum);
474 proto_item_set_generated(pi);
477 if (PINFO_FD_VISITED(pinfo) && frame->endNum != -1) {
478 pi = proto_tree_add_uint(tree, hf_egfx_ackqoe_frame_end, tvb, 0, 0, frame->endNum);
479 proto_item_set_generated(pi);
482 break;
485 case RDPGFX_CMDID_CREATESURFACE:
486 col_append_sep_str(pinfo->cinfo, COL_INFO, ",", "Create Surface");
487 break;
489 case RDPGFX_CMDID_MAPSURFACETOOUTPUT:
490 col_append_sep_str(pinfo->cinfo, COL_INFO, ",", "Map Surface To Output");
491 break;
493 case RDPGFX_CMDID_WIRETOSURFACE_1:
494 col_append_sep_str(pinfo->cinfo, COL_INFO, ",", "Wire To Surface 1");
495 break;
497 case RDPGFX_CMDID_WIRETOSURFACE_2:
498 col_append_sep_str(pinfo->cinfo, COL_INFO, ",", "Wire To Surface 2");
499 break;
501 case RDPGFX_CMDID_DELETEENCODINGCONTEXT:
502 col_append_sep_str(pinfo->cinfo, COL_INFO, ",", "Delete Encoding Context");
503 break;
505 case RDPGFX_CMDID_SOLIDFILL:
506 col_append_sep_str(pinfo->cinfo, COL_INFO, ",", "Solid Fill");
507 break;
509 case RDPGFX_CMDID_SURFACETOSURFACE:
510 col_append_sep_str(pinfo->cinfo, COL_INFO, ",", "Surface To Surface");
511 break;
513 case RDPGFX_CMDID_SURFACETOCACHE:
514 col_append_sep_str(pinfo->cinfo, COL_INFO, ",", "Surface To Cache");
515 break;
517 case RDPGFX_CMDID_CACHETOSURFACE:
518 col_append_sep_str(pinfo->cinfo, COL_INFO, ",", "Cache To Surface");
519 break;
521 case RDPGFX_CMDID_EVICTCACHEENTRY:
522 col_append_sep_str(pinfo->cinfo, COL_INFO, ",", "Evict Cache Entry");
523 break;
525 case RDPGFX_CMDID_DELETESURFACE:
526 col_append_sep_str(pinfo->cinfo, COL_INFO, ",", "Delete Surface");
527 break;
529 case RDPGFX_CMDID_CACHEIMPORTOFFER:
530 col_append_sep_str(pinfo->cinfo, COL_INFO, ",", "Cache Import Offer");
531 break;
533 case RDPGFX_CMDID_CACHEIMPORTREPLY:
534 col_append_sep_str(pinfo->cinfo, COL_INFO, ",", "Cache Import Reply");
535 break;
537 case RDPGFX_CMDID_MAPSURFACETOWINDOW:
538 col_append_sep_str(pinfo->cinfo, COL_INFO, ",", "Map Surface To Window");
539 break;
541 case RDPGFX_CMDID_MAPSURFACETOSCALEDOUTPUT:
542 col_append_sep_str(pinfo->cinfo, COL_INFO, ",", "Map Surface To Scaled Output");
543 break;
545 case RDPGFX_CMDID_MAPSURFACETOSCALEDWINDOW:
546 col_append_sep_str(pinfo->cinfo, COL_INFO, ",", "Map Surface To Scaled Window");
547 break;
549 default:
550 break;
553 offset = nextOffset;
555 return offset;
558 static int
559 dissect_rdp_egfx(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, void *data)
561 tvbuff_t *work_tvb = tvb;
562 egfx_conv_info_t *infos = egfx_get_conversation_data(pinfo);
564 col_set_str(pinfo->cinfo, COL_PROTOCOL, "EGFX");
565 col_clear(pinfo->cinfo, COL_INFO);
567 parent_tree = proto_tree_get_root(parent_tree);
569 if (!rdp_isServerAddressTarget(pinfo)) {
570 uint32_t hash = crc32_ccitt_tvb(tvb, tvb_captured_length_remaining(tvb, 0));
571 egfx_pdu_info_t *pdu_infos = p_get_proto_data(wmem_file_scope(), pinfo, proto_rdp_egfx, EGFX_PDU_KEY);
572 if (!pdu_infos) {
573 pdu_infos = wmem_alloc(wmem_file_scope(), sizeof(*pdu_infos));
574 pdu_infos->pdus = wmem_tree_new(wmem_file_scope());
575 p_set_proto_data(wmem_file_scope(), pinfo, proto_rdp_egfx, EGFX_PDU_KEY, pdu_infos);
578 if (!PINFO_FD_VISITED(pinfo)) {
579 work_tvb = rdp8_decompress(infos->zgfx, wmem_file_scope(), tvb, 0);
580 if (work_tvb) {
581 //printf("%d: zgfx sz=%d\n", pinfo->num, tvb_captured_length(work_tvb));
582 wmem_tree_insert32(pdu_infos->pdus, hash, work_tvb);
584 } else {
585 pdu_infos = p_get_proto_data(wmem_file_scope(), pinfo, proto_rdp_egfx, EGFX_PDU_KEY);
586 work_tvb = wmem_tree_lookup32(pdu_infos->pdus, hash);
589 if (work_tvb)
590 add_new_data_source(pinfo, work_tvb, "Uncompressed GFX");
593 if (work_tvb)
594 dissect_rdp_egfx_payload(work_tvb, pinfo, parent_tree, infos, data);
595 else {
596 if (parent_tree)
597 expert_add_info_format(pinfo, parent_tree->last_child, &ei_egfx_invalid_compression, "invalid compression");
600 return tvb_reported_length(tvb);
604 void proto_register_rdp_egfx(void) {
605 static hf_register_info hf[] = {
606 { &hf_egfx_cmdId,
607 { "CmdId", "rdp_egfx.cmdid",
608 FT_UINT16, BASE_HEX, VALS(rdp_egfx_cmd_vals), 0x0,
609 NULL, HFILL }
611 { &hf_egfx_flags,
612 { "flags", "rdp_egfx.flags",
613 FT_UINT16, BASE_HEX, NULL, 0x0,
614 NULL, HFILL }
616 { &hf_egfx_pduLength,
617 { "pduLength", "rdp_egfx.pdulength",
618 FT_UINT32, BASE_DEC, NULL, 0x0,
619 NULL, HFILL }
621 { &hf_egfx_caps_capsSetCount,
622 { "capsSetCount", "rdp_egfx.caps.setcount",
623 FT_UINT16, BASE_DEC, NULL, 0x0,
624 NULL, HFILL }
626 { &hf_egfx_cap_version,
627 { "Version", "rdp_egfx.cap.version",
628 FT_UINT32, BASE_HEX, VALS(rdp_egfx_caps_version_vals), 0x0,
629 NULL, HFILL }
631 { &hf_egfx_cap_length,
632 { "capsDataLength", "rdp_egfx.cap.length",
633 FT_UINT32, BASE_DEC, NULL, 0x0,
634 NULL, HFILL }
636 { &hf_egfx_ack_queue_depth,
637 { "queueDepth", "rdp_egfx.ack.queuedepth",
638 FT_UINT32, BASE_DEC, NULL, 0x0,
639 NULL, HFILL }
641 { &hf_egfx_ack_frame_id,
642 { "frameId", "rdp_egfx.ack.frameid",
643 FT_UINT32, BASE_HEX, NULL, 0x0,
644 NULL, HFILL }
646 { &hf_egfx_ack_total_decoded,
647 { "Total frames decoded", "rdp_egfx.ack.totalframesdecoded",
648 FT_UINT32, BASE_DEC, NULL, 0x0,
649 NULL, HFILL }
651 { &hf_egfx_ack_frame_start,
652 { "Frame starts in", "rdp_egfx.ack.framestart",
653 FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_REQUEST), 0x0,
654 NULL, HFILL }
656 { &hf_egfx_ack_frame_end,
657 { "Frame ends in", "rdp_egfx.ack.frameend",
658 FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_REQUEST), 0x0,
659 NULL, HFILL }
661 { &hf_egfx_ackqoe_frame_id,
662 { "frameId", "rdp_egfx.ackqoe.frameid",
663 FT_UINT32, BASE_HEX, NULL, 0x0,
664 NULL, HFILL }
666 { &hf_egfx_ackqoe_timestamp,
667 { "Timestamp", "rdp_egfx.ackqoe.timestamp",
668 FT_UINT32, BASE_DEC, NULL, 0x0,
669 NULL, HFILL }
671 { &hf_egfx_ackqoe_timediffse,
672 { "TimeDiffSE", "rdp_egfx.ackqoe.timediffse",
673 FT_UINT16, BASE_DEC, NULL, 0x0,
674 NULL, HFILL }
676 { &hf_egfx_ackqoe_timediffedr,
677 { "TimeDiffEDR", "rdp_egfx.ackqoe.timediffedr",
678 FT_UINT16, BASE_DEC, NULL, 0x0,
679 NULL, HFILL }
681 { &hf_egfx_ackqoe_frame_start,
682 { "Frame starts in", "rdp_egfx.ackqoe.framestart",
683 FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_REQUEST), 0x0,
684 NULL, HFILL }
686 { &hf_egfx_ackqoe_frame_end,
687 { "Frame ends in", "rdp_egfx.ackqoe.frameend",
688 FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_REQUEST), 0x0,
689 NULL, HFILL }
691 { &hf_egfx_reset_width,
692 { "Width", "rdp_egfx.reset.width",
693 FT_UINT32, BASE_DEC, NULL, 0x0,
694 NULL, HFILL }
696 { &hf_egfx_reset_height,
697 { "Height", "rdp_egfx.reset.height",
698 FT_UINT32, BASE_DEC, NULL, 0x0,
699 NULL, HFILL }
701 { &hf_egfx_reset_monitorCount,
702 { "Monitor count", "rdp_egfx.reset.monitorcount",
703 FT_UINT32, BASE_DEC, NULL, 0x0,
704 NULL, HFILL }
706 { &hf_egfx_reset_monitorDefLeft,
707 { "Left", "rdp_egfx.monitor.left",
708 FT_UINT32, BASE_DEC, NULL, 0x0,
709 NULL, HFILL }
711 { &hf_egfx_reset_monitorDefTop,
712 { "Top", "rdp_egfx.monitor.top",
713 FT_UINT32, BASE_DEC, NULL, 0x0,
714 NULL, HFILL }
716 { &hf_egfx_reset_monitorDefRight,
717 { "Right", "rdp_egfx.monitor.right",
718 FT_UINT32, BASE_DEC, NULL, 0x0,
719 NULL, HFILL }
721 { &hf_egfx_reset_monitorDefBottom,
722 { "Bottom", "rdp_egfx.monitor.bottom",
723 FT_UINT32, BASE_DEC, NULL, 0x0,
724 NULL, HFILL }
726 { &hf_egfx_reset_monitorDefFlags,
727 { "Flags", "rdp_egfx.monitor.flags",
728 FT_UINT32, BASE_HEX, VALS(rdp_egfx_monitor_flags_vals), 0x0,
729 NULL, HFILL }
731 { &hf_egfx_start_timestamp,
732 { "Timestamp", "rdp_egfx.startframe.timestamp",
733 FT_UINT32, BASE_DEC, NULL, 0x0,
734 NULL, HFILL }
736 { &hf_egfx_start_frameid,
737 { "Frame id", "rdp_egfx.startframe.frameid",
738 FT_UINT32, BASE_HEX, NULL, 0x0,
739 NULL, HFILL }
741 { &hf_egfx_start_acked_in,
742 { "Frame acked in", "rdp_egfx.startframe.ackedin",
743 FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_RESPONSE), 0x0,
744 NULL, HFILL }
747 { &hf_egfx_end_frameid,
748 { "Frame id", "rdp_egfx.endframe.frameid",
749 FT_UINT32, BASE_HEX, NULL, 0x0,
750 NULL, HFILL }
752 { &hf_egfx_end_acked_in,
753 { "Frame acked in", "rdp_egfx.endframe.ackedin",
754 FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_RESPONSE), 0x0,
755 NULL, HFILL }
759 static int *ett[] = {
760 &ett_rdp_egfx,
761 &ett_egfx_caps,
762 &ett_egfx_cap,
763 &ett_egfx_cap_version,
764 &ett_egfx_ack,
765 &ett_egfx_ackqoe,
766 &ett_egfx_reset,
767 &ett_egfx_capsconfirm,
768 &ett_egfx_monitors,
769 &ett_egfx_monitordef,
772 static ei_register_info ei[] = {
773 { &ei_egfx_pdulen_invalid, { "rdp_egfx.pdulength.invalid", PI_PROTOCOL, PI_ERROR, "Invalid length", EXPFILL }},
774 { &ei_egfx_invalid_compression, { "rdp_egfx.compression.invalid", PI_PROTOCOL, PI_ERROR, "Invalid compression", EXPFILL }},
776 expert_module_t* expert_egfx;
779 proto_rdp_egfx = proto_register_protocol(PNAME, PSNAME, PFNAME);
780 /* Register fields and subtrees */
781 proto_register_field_array(proto_rdp_egfx, hf, array_length(hf));
782 proto_register_subtree_array(ett, array_length(ett));
783 expert_egfx = expert_register_protocol(proto_rdp_egfx);
784 expert_register_field_array(expert_egfx, ei, array_length(ei));
786 register_dissector("rdp_egfx", dissect_rdp_egfx, proto_rdp_egfx);
789 void proto_reg_handoff_rdp_egfx(void) {