Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-spice.c
blob26b0aab2e875f9ccb5b3067024d26f1923e548df
1 /* packet-spice.c
2 * Routines for Spice protocol dissection
3 * Copyright 2011, Yaniv Kaul <ykaul@redhat.com>
4 * Copyright 2013, Jonathon Jongsma <jjongsma@redhat.com>
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
10 * SPDX-License-Identifier: GPL-2.0-or-later
12 * This code is based on the protocol specification:
13 * https://www.spice-space.org/spice-protocol.html
14 * and the source - git://cgit.freedesktop.org/spice/spice-protocol
17 #include "config.h"
19 #include <epan/packet.h>
20 #include <epan/conversation.h>
21 #include <epan/expert.h>
22 #include <epan/proto_data.h>
23 #include <epan/tfs.h>
24 #include <epan/unit_strings.h>
26 #include <wsutil/array.h>
28 /* NOTE:
29 * packet-spice.h is auto-generated from a Spice protocol definition by a tool
30 * included in the spice-common repository
31 * (https://gitlab.freedesktop.org/spice/spice-common)
32 * To re-generate this file, run the following command from the root of the
33 * spice-common tree:
34 * python ./spice_codegen.py --generate-wireshark-dissector \
35 * spice.proto packet-spice.h
37 #if WS_IS_AT_LEAST_GNUC_VERSION(6,0)
38 DIAG_OFF(unused-const-variable)
39 #endif
40 #include "packet-spice.h"
41 #if WS_IS_AT_LEAST_GNUC_VERSION(6,0)
42 DIAG_ON(unused-const-variable)
43 #endif
45 void proto_register_spice(void);
46 void proto_reg_handoff_spice(void);
48 #define SPICE_MAGIC 0x52454451 /* = "REDQ" */
50 #define SPICE_VERSION_MAJOR_1 1
51 #define SPICE_VERSION_MINOR_0 0
52 #define SPICE_VERSION_MAJOR_UNSTABLE 0xfffe
53 #define SPICE_VERSION_MINOR_UNSTABLE 0xffff
55 #define SPICE_TICKET_PUBKEY_BYTES 162
57 #define SPICE_ALIGN(a, size) (((a) + ((size) - 1)) & ~((size) - 1))
59 typedef enum {
60 SPICE_LINK_CLIENT,
61 SPICE_LINK_SERVER,
63 SPICE_TICKET_CLIENT,
64 SPICE_TICKET_SERVER,
66 SPICE_CLIENT_AUTH_SELECT,
67 SPICE_SASL_INIT_FROM_SERVER,
68 SPICE_SASL_START_TO_SERVER,
69 SPICE_SASL_START_FROM_SERVER,
70 SPICE_SASL_START_FROM_SERVER_CONT,
71 SPICE_SASL_STEP_TO_SERVER,
72 SPICE_SASL_STEP_FROM_SERVER,
73 SPICE_SASL_STEP_FROM_SERVER_CONT,
74 SPICE_SASL_DATA,
75 SPICE_DATA
76 } spice_session_state_e;
78 static const value_string state_name_vs[] = {
79 { SPICE_LINK_CLIENT, "Client link message" },
80 { SPICE_LINK_SERVER, "Server link message" },
81 { SPICE_TICKET_CLIENT, "Client ticket" },
82 { SPICE_TICKET_SERVER, "Server ticket" },
83 { SPICE_CLIENT_AUTH_SELECT, "Client authentication method selection" },
84 { SPICE_SASL_INIT_FROM_SERVER, "SASL supported authentication mechanisms (init from server)" },
85 { SPICE_SASL_START_TO_SERVER, "SASL authentication (start to server)" },
86 { SPICE_SASL_START_FROM_SERVER, "SASL authentication (start from server)" },
87 { SPICE_SASL_START_FROM_SERVER_CONT, "SASL authentication - result from server" },
88 { SPICE_SASL_STEP_TO_SERVER, "SASL authentication from client (step to server)" },
89 { SPICE_SASL_STEP_FROM_SERVER, "SASL authentication (step from server)" },
90 { SPICE_SASL_STEP_FROM_SERVER_CONT, "SASL authentication - result from server" },
91 { SPICE_SASL_DATA, "SASL wrapped Spice message" },
92 { SPICE_DATA, "" }, /* Intentionally "blank" to help col_append_sep_str() logic */
93 { 0, NULL }
96 static dissector_handle_t spice_handle;
98 #define SPICE_CHANNEL_NONE 0
100 #define SPICE_FIRST_AVAIL_MESSAGE 101
102 #define sizeof_SpiceLinkHeader 16
103 #define sizeof_SpiceDataHeader 18
104 #define sizeof_SpiceMiniDataHeader 6
106 static const value_string playback_mode_vals[] = {
107 { SPICE_AUDIO_DATA_MODE_INVALID, "INVALID" },
108 { SPICE_AUDIO_DATA_MODE_RAW, "RAW" },
109 { SPICE_AUDIO_DATA_MODE_CELT_0_5_1, "CELT_0_5_1" },
110 { 0, NULL }
113 /* main channel */
115 enum {
116 SPICE_MAIN_CAP_SEMI_SEAMLESS_MIGRATE,
117 SPICE_MAIN_CAP_VM_NAME_UUID,
118 SPICE_MAIN_CAP_AGENT_CONNECTED_TOKENS,
119 SPICE_MAIN_CAP_SEAMLESS_MIGRATE
122 enum
124 SPICE_MAIN_CAP_SEMI_SEAMLESS_MIGRATE_MASK = (1 << SPICE_MAIN_CAP_SEMI_SEAMLESS_MIGRATE),
125 SPICE_MAIN_CAP_VM_NAME_UUID_MASK = (1 << SPICE_MAIN_CAP_VM_NAME_UUID),
126 SPICE_MAIN_CAP_AGENT_CONNECTED_TOKENS_MASK = (1 << SPICE_MAIN_CAP_AGENT_CONNECTED_TOKENS),
127 SPICE_MAIN_CAP_SEAMLESS_MIGRATE_MASK = (1 << SPICE_MAIN_CAP_SEAMLESS_MIGRATE)
130 enum {
131 VD_AGENT_MOUSE_STATE = 1,
132 VD_AGENT_MONITORS_CONFIG,
133 VD_AGENT_REPLY,
134 VD_AGENT_CLIPBOARD,
135 VD_AGENT_DISPLAY_CONFIG,
136 VD_AGENT_ANNOUNCE_CAPABILITIES,
137 VD_AGENT_CLIPBOARD_GRAB,
138 VD_AGENT_CLIPBOARD_REQUEST,
139 VD_AGENT_CLIPBOARD_RELEASE,
140 VD_AGENT_FILE_XFER_START,
141 VD_AGENT_FILE_XFER_STATUS,
142 VD_AGENT_FILE_XFER_DATA,
143 VD_AGENT_CLIENT_DISCONNECTED,
144 VD_AGENT_END_MESSAGE
147 static const value_string agent_message_type_vs[] = {
148 { VD_AGENT_MOUSE_STATE, "VD_AGENT_MOUSE_STATE" },
149 { VD_AGENT_MONITORS_CONFIG, "VD_AGENT_MONITORS_CONFIG" },
150 { VD_AGENT_REPLY, "VD_AGENT_REPLY" },
151 { VD_AGENT_CLIPBOARD, "VD_AGENT_CLIPBOARD" },
152 { VD_AGENT_DISPLAY_CONFIG, "VD_AGENT_DISPLAY_CONFIG" },
153 { VD_AGENT_ANNOUNCE_CAPABILITIES, "VD_AGENT_ANNOUNCE_CAPABILITIES" },
154 { VD_AGENT_CLIPBOARD_GRAB, "VD_AGENT_CLIPBOARD_GRAB" },
155 { VD_AGENT_CLIPBOARD_REQUEST, "VD_AGENT_CLIPBOARD_REQUEST" },
156 { VD_AGENT_CLIPBOARD_RELEASE, "VD_AGENT_CLIPBOARD_RELEASE" },
157 { VD_AGENT_FILE_XFER_START, "VD_AGENT_FILE_XFER_START" },
158 { VD_AGENT_FILE_XFER_STATUS, "VD_AGENT_FILE_XFER_STATUS" },
159 { VD_AGENT_FILE_XFER_DATA, "VD_AGENT_FILE_XFER_DATA" },
160 { VD_AGENT_CLIENT_DISCONNECTED, "VD_AGENT_CLIENT_DISCONNECTED" },
161 { VD_AGENT_END_MESSAGE, "VD_AGENT_END_MESSAGE" },
162 { 0, NULL }
165 enum {
166 VD_AGENT_CLIPBOARD_NONE,
167 VD_AGENT_CLIPBOARD_UTF8_TEXT,
168 VD_AGENT_CLIPBOARD_IMAGE_PNG,
169 VD_AGENT_CLIPBOARD_IMAGE_BMP,
170 VD_AGENT_CLIPBOARD_IMAGE_TIFF,
171 VD_AGENT_CLIPBOARD_IMAGE_JPG
174 static const value_string agent_clipboard_type[] = {
175 { VD_AGENT_CLIPBOARD_NONE, "NONE" },
176 { VD_AGENT_CLIPBOARD_UTF8_TEXT, "UTF8_TEXT" },
177 { VD_AGENT_CLIPBOARD_IMAGE_PNG, "IMAGE_PNG" },
178 { VD_AGENT_CLIPBOARD_IMAGE_BMP, "IMAGE_BMP" },
179 { VD_AGENT_CLIPBOARD_IMAGE_TIFF,"IMAGE_TIFF" },
180 { VD_AGENT_CLIPBOARD_IMAGE_JPG, "IMAGE_JPG" },
181 { 0, NULL }
184 enum {
185 VD_AGENT_CAP_MOUSE_STATE = (1 << 0),
186 VD_AGENT_CAP_MONITORS_CONFIG = (1 << 1),
187 VD_AGENT_CAP_REPLY = (1 << 2),
188 VD_AGENT_CAP_CLIPBOARD = (1 << 3),
189 VD_AGENT_CAP_DISPLAY_CONFIG = (1 << 4),
190 VD_AGENT_CAP_CLIPBOARD_BY_DEMAND = (1 << 5),
191 VD_AGENT_CAP_CLIPBOARD_SELECTION = (1 << 6),
192 VD_AGENT_CAP_SPARSE_MONITORS_CONFIG = (1 << 7),
193 VD_AGENT_CAP_GUEST_LINEEND_LF = (1 << 8),
194 VD_AGENT_CAP_GUEST_LINEEND_CRLF = (1 << 9)
197 #if 0
198 static const value_string vd_agent_cap_vs[] = {
199 { VD_AGENT_CAP_MOUSE_STATE, "VD_AGENT_CAP_MOUSE_STATE" },
200 { VD_AGENT_CAP_MONITORS_CONFIG, "VD_AGENT_CAP_MONITORS_CONFIG" },
201 { VD_AGENT_CAP_REPLY, "VD_AGENT_CAP_REPLY" },
202 { VD_AGENT_CAP_CLIPBOARD, "VD_AGENT_CAP_CLIPBOARD" },
203 { VD_AGENT_CAP_DISPLAY_CONFIG, "VD_AGENT_CAP_DISPLAY_CONFIG" },
204 { VD_AGENT_CAP_CLIPBOARD_BY_DEMAND, "VD_AGENT_CAP_CLIPBOARD_BY_DEMAND" },
205 { VD_AGENT_CAP_CLIPBOARD_SELECTION, "VD_AGENT_CAP_CLIPBOARD_SELECTION" },
206 { VD_AGENT_CAP_SPARSE_MONITORS_CONFIG, "VD_AGENT_CAP_SPARSE_MONITORS_CONFIG" },
207 { VD_AGENT_CAP_GUEST_LINEEND_LF, "VD_AGENT_CAP_GUEST_LINEEND_LF" },
208 { VD_AGENT_CAP_GUEST_LINEEND_CRLF, "VD_AGENT_CAP_GUEST_LINEEND_CRLF" },
209 { 0, NULL }
211 #endif
213 enum {
214 VD_AGENT_CONFIG_MONITORS_FLAG_USE_POS = (1 << 0)
217 #if 0
218 static const value_string vd_agent_monitors_config_flag_vs[] = {
219 { VD_AGENT_CONFIG_MONITORS_FLAG_USE_POS, "VD_AGENT_CONFIG_MONITORS_FLAG_USE_POS"},
220 { 0, NULL }
222 #endif
224 enum {
225 VD_AGENT_SUCCESS = 1,
226 VD_AGENT_ERROR
229 static const value_string vd_agent_reply_error_vs[] = {
230 { VD_AGENT_SUCCESS, "SUCCESS"},
231 { VD_AGENT_ERROR, "ERROR"},
232 { 0, NULL }
235 /* playback channel capabilities */
236 enum {
237 SPICE_PLAYBACK_CAP_CELT_0_5_1,
238 SPICE_PLAYBACK_CAP_VOLUME,
239 SPICE_PLAYBACK_CAP_LATENCY,
240 SPICE_PLAYBACK_CAP_OPUS,
241 /* Number of bits to display for capabilities of the playback channel. */
242 PLAYBACK_CAP_NBITS
245 enum {
246 SPICE_PLAYBACK_CAP_CELT_0_5_1_MASK = (1 << SPICE_PLAYBACK_CAP_CELT_0_5_1),
247 SPICE_PLAYBACK_CAP_VOLUME_MASK = (1 << SPICE_PLAYBACK_CAP_VOLUME),
248 SPICE_PLAYBACK_CAP_LATENCY_MASK = (1 << SPICE_PLAYBACK_CAP_LATENCY),
249 SPICE_PLAYBACK_CAP_OPUS_MASK = (1 << SPICE_PLAYBACK_CAP_OPUS),
252 /* record channel capabilities */
253 enum {
254 SPICE_RECORD_CAP_CELT_0_5_1,
255 SPICE_RECORD_CAP_VOLUME,
256 SPICE_RECORD_CAP_OPUS,
257 /* Number of bits to display for capabilities of the record channel. */
258 RECORD_CAP_NBITS
261 enum {
262 SPICE_RECORD_CAP_CELT_0_5_1_MASK = (1 << SPICE_RECORD_CAP_CELT_0_5_1),
263 SPICE_RECORD_CAP_VOLUME_MASK = (1 << SPICE_RECORD_CAP_VOLUME),
264 SPICE_RECORD_CAP_OPUS_MASK = (1 << SPICE_RECORD_CAP_OPUS),
267 /* display channel */
268 enum {
269 SPICE_DISPLAY_CAP_SIZED_STREAM,
270 SPICE_DISPLAY_CAP_MONITORS_CONFIG,
271 SPICE_DISPLAY_CAP_COMPOSITE,
272 SPICE_DISPLAY_CAP_A8_SURFACE,
273 SPICE_DISPLAY_CAP_STREAM_REPORT,
274 SPICE_DISPLAY_CAP_LZ4_COMPRESSION,
275 SPICE_DISPLAY_CAP_PREF_COMPRESSION,
276 SPICE_DISPLAY_CAP_GL_SCANOUT,
277 SPICE_DISPLAY_CAP_MULTI_CODEC,
278 SPICE_DISPLAY_CAP_CODEC_MJPEG,
279 SPICE_DISPLAY_CAP_CODEC_VP8,
280 SPICE_DISPLAY_CAP_CODEC_H264,
281 SPICE_DISPLAY_CAP_PREF_VIDEO_CODEC_TYPE,
282 SPICE_DISPLAY_CAP_CODEC_VP9,
283 SPICE_DISPLAY_CAP_CODEC_H265,
284 /* Number of bits to display for capabilities of the display channel. */
285 DISPLAY_CAP_NBITS
288 enum {
289 SPICE_DISPLAY_CAP_SIZED_STREAM_MASK = (1 << SPICE_DISPLAY_CAP_SIZED_STREAM),
290 SPICE_DISPLAY_CAP_MONITORS_CONFIG_MASK = (1 << SPICE_DISPLAY_CAP_MONITORS_CONFIG),
291 SPICE_DISPLAY_CAP_COMPOSITE_MASK = (1 << SPICE_DISPLAY_CAP_COMPOSITE),
292 SPICE_DISPLAY_CAP_A8_SURFACE_MASK = (1 << SPICE_DISPLAY_CAP_A8_SURFACE),
293 SPICE_DISPLAY_CAP_STREAM_REPORT_MASK = (1 << SPICE_DISPLAY_CAP_STREAM_REPORT),
294 SPICE_DISPLAY_CAP_LZ4_COMPRESSION_MASK = (1 << SPICE_DISPLAY_CAP_LZ4_COMPRESSION),
295 SPICE_DISPLAY_CAP_PREF_COMPRESSION_MASK = (1 << SPICE_DISPLAY_CAP_PREF_COMPRESSION),
296 SPICE_DISPLAY_CAP_GL_SCANOUT_MASK = (1 << SPICE_DISPLAY_CAP_GL_SCANOUT),
297 SPICE_DISPLAY_CAP_MULTI_CODEC_MASK = (1 << SPICE_DISPLAY_CAP_MULTI_CODEC),
298 SPICE_DISPLAY_CAP_CODEC_MJPEG_MASK = (1 << SPICE_DISPLAY_CAP_CODEC_MJPEG),
299 SPICE_DISPLAY_CAP_CODEC_VP8_MASK = (1 << SPICE_DISPLAY_CAP_CODEC_VP8),
300 SPICE_DISPLAY_CAP_CODEC_H264_MASK = (1 << SPICE_DISPLAY_CAP_CODEC_H264),
301 SPICE_DISPLAY_CAP_PREF_VIDEO_CODEC_TYPE_MASK = (1 << SPICE_DISPLAY_CAP_PREF_VIDEO_CODEC_TYPE),
302 SPICE_DISPLAY_CAP_CODEC_VP9_MASK = (1 << SPICE_DISPLAY_CAP_CODEC_VP9),
303 SPICE_DISPLAY_CAP_CODEC_H265_MASK = (1 << SPICE_DISPLAY_CAP_CODEC_H265)
307 /* display channel */
309 #define sizeof_RedcDisplayInit 14
311 /* cursor channel */
312 static const value_string cursor_visible_vs[] = {
313 { 1, "Visible" },
314 { 0, "Invisible" },
315 { 0, NULL }
318 typedef struct {
319 uint64_t unique;
320 uint8_t type;
321 uint16_t width;
322 uint16_t height;
323 uint16_t hot_spot_x;
324 uint16_t hot_spot_y;
325 } CursorHeader;
327 #define sizeof_CursorHeader 17
329 static const value_string spice_agent_vs[] = {
330 { 0, "Disconnected" },
331 { 1, "Connected" },
332 { 0, NULL }
335 /* This structure will be tied to each conversation. */
336 typedef struct {
337 uint32_t connection_id;
338 uint32_t num_channel_caps;
339 uint32_t destport;
340 uint32_t client_auth;
341 uint32_t server_auth;
342 uint32_t auth_selected;
343 spice_session_state_e next_state;
344 uint16_t playback_mode;
345 uint8_t channel_type;
346 uint8_t channel_id;
347 bool client_mini_header;
348 bool server_mini_header;
349 } spice_conversation_t;
351 typedef struct {
352 spice_session_state_e state;
353 } spice_packet_t;
355 typedef struct {
356 int32_t left;
357 int32_t top;
358 int32_t right;
359 int32_t bottom;
360 } SpiceRect;
362 #define sizeof_SpiceRect 16
364 typedef struct {
365 uint8_t type;
366 } Clip;
367 #define sizeof_Clip 1 /* This is correct only if the type is none. If it is RECTS, this is followed by: */
369 typedef struct {
370 uint32_t num_rects; /* this is followed by RECT rects[num_rects] */
371 } ClipRects;
374 typedef struct {
375 uint32_t surface_id;
376 SpiceRect bounding_box;
377 Clip clip;
378 } DisplayBase;
380 #define sizeof_DisplayBase 21 /* size without a rect list in the Clip */
382 typedef struct {
383 int32_t x;
384 int32_t y;
385 } point32_t;
387 typedef struct {
388 int16_t x;
389 int16_t y;
390 } point16_t;
392 #define sizeof_Mask 13
394 #define sizeof_ImageDescriptor 18
396 enum {
397 QUIC_IMAGE_TYPE_INVALID,
398 QUIC_IMAGE_TYPE_GRAY,
399 QUIC_IMAGE_TYPE_RGB16,
400 QUIC_IMAGE_TYPE_RGB24,
401 QUIC_IMAGE_TYPE_RGB32,
402 QUIC_IMAGE_TYPE_RGBA
405 static const value_string quic_type_vs[] = {
406 { QUIC_IMAGE_TYPE_INVALID, "INVALID" },
407 { QUIC_IMAGE_TYPE_GRAY, "GRAY" },
408 { QUIC_IMAGE_TYPE_RGB16, "RGB16" },
409 { QUIC_IMAGE_TYPE_RGB24, "RGB24" },
410 { QUIC_IMAGE_TYPE_RGB32, "RGB32" },
411 { QUIC_IMAGE_TYPE_RGBA, "RGBA" },
412 { 0, NULL }
415 enum {
416 LZ_IMAGE_TYPE_INVALID,
417 LZ_IMAGE_TYPE_PLT1_LE,
418 LZ_IMAGE_TYPE_PLT1_BE,
419 LZ_IMAGE_TYPE_PLT4_LE,
420 LZ_IMAGE_TYPE_PLT4_BE,
421 LZ_IMAGE_TYPE_PLT8,
422 LZ_IMAGE_TYPE_RGB16,
423 LZ_IMAGE_TYPE_RGB24,
424 LZ_IMAGE_TYPE_RGB32,
425 LZ_IMAGE_TYPE_RGBA,
426 LZ_IMAGE_TYPE_XXXA
429 static const value_string LzImage_type_vs[] = {
430 { LZ_IMAGE_TYPE_INVALID, "INVALID" },
431 { LZ_IMAGE_TYPE_PLT1_LE, "PLT1_LE" },
432 { LZ_IMAGE_TYPE_PLT1_BE, "PLT1_BE" },
433 { LZ_IMAGE_TYPE_PLT4_LE, "PLT4_LE" },
434 { LZ_IMAGE_TYPE_PLT4_BE, "PLT4_BE" },
435 { LZ_IMAGE_TYPE_PLT8, "PLT8" },
436 { LZ_IMAGE_TYPE_RGB16, "RGB16" },
437 { LZ_IMAGE_TYPE_RGB24, "RGB24" },
438 { LZ_IMAGE_TYPE_RGB32, "RGB32" },
439 { LZ_IMAGE_TYPE_RGBA, "RGBA" },
440 { LZ_IMAGE_TYPE_XXXA, "RGB JPEG (w/ Alpha LZ)" },
441 { 0, NULL }
444 #define sizeof_SpiceHead 28
446 enum {
447 SPICE_COMMON_CAP_PROTOCOL_AUTH_SELECTION,
448 SPICE_COMMON_CAP_AUTH_SPICE,
449 SPICE_COMMON_CAP_AUTH_SASL,
450 SPICE_COMMON_CAP_MINI_HEADER
453 enum {
454 SPICE_COMMON_CAP_PROTOCOL_AUTH_SELECTION_MASK = (1 << SPICE_COMMON_CAP_PROTOCOL_AUTH_SELECTION),
455 SPICE_COMMON_CAP_AUTH_SPICE_MASK = (1 << SPICE_COMMON_CAP_AUTH_SPICE),
456 SPICE_COMMON_CAP_AUTH_SASL_MASK = (1 << SPICE_COMMON_CAP_AUTH_SASL),
457 SPICE_COMMON_CAP_MINI_HEADER_MASK = (1 << SPICE_COMMON_CAP_MINI_HEADER)
460 static const value_string spice_auth_select_vs[] = {
461 { SPICE_COMMON_CAP_PROTOCOL_AUTH_SELECTION, "Auth Selection" },
462 { SPICE_COMMON_CAP_AUTH_SPICE, "Spice" },
463 { SPICE_COMMON_CAP_AUTH_SASL, "SASL" },
464 { SPICE_COMMON_CAP_MINI_HEADER, "Mini header" },
465 { 0, NULL }
468 static const value_string spice_sasl_auth_result_vs[] = {
469 { 0, "CONTINUE" },
470 { 1, "DONE" },
471 { 0, NULL }
474 #define GET_PDU_FROM_OFFSET(OFFSET) if (avail < pdu_len) { \
475 pinfo->desegment_offset = OFFSET; \
476 pinfo->desegment_len = pdu_len - avail; \
477 return avail; \
480 static int ett_spice;
481 static int ett_link_client;
482 static int ett_link_server;
483 static int ett_link_caps;
484 static int ett_data;
485 static int ett_message;
486 static int ett_ticket_client;
487 static int ett_auth_select_client;
488 static int ett_ticket_server;
489 static int ett_playback;
490 static int ett_display_client;
491 static int ett_display_server;
492 static int ett_common_server_message;
493 static int ett_common_client_message;
494 static int ett_point;
495 static int ett_point16;
496 static int ett_cursor;
497 static int ett_spice_main;
498 static int ett_rect;
499 static int ett_DisplayBase;
500 static int ett_Clip;
501 static int ett_Mask;
502 static int ett_imagedesc;
503 static int ett_imageQuic;
504 static int ett_GLZ_RGB;
505 static int ett_LZ_RGB;
506 static int ett_LZ_PLT;
507 static int ett_ZLIB_GLZ;
508 static int ett_Uncomp_tree;
509 static int ett_LZ_JPEG;
510 static int ett_JPEG;
511 static int ett_cursor_header;
512 static int ett_RedCursor;
513 static int ett_pattern;
514 static int ett_brush;
515 static int ett_Pixmap;
516 static int ett_SpiceHead;
517 static int ett_inputs_client;
518 static int ett_rectlist;
519 static int ett_inputs_server;
520 static int ett_record_client;
521 static int ett_record_server;
522 static int ett_main_client;
523 static int ett_spice_agent;
524 static int ett_cap_tree;
525 static int proto_spice;
526 static int hf_spice_magic;
527 static int hf_major_version;
528 static int hf_minor_version;
529 static int hf_message_size;
530 static int hf_message_type;
531 static int hf_conn_id;
532 static int hf_channel_type;
533 static int hf_channel_id;
534 static int hf_num_common_caps;
535 static int hf_num_channel_caps;
536 static int hf_caps_offset;
537 static int hf_error_code;
538 static int hf_data;
539 static int hf_serial;
540 static int hf_data_size;
541 static int hf_data_sublist;
542 static int hf_link_client;
543 static int hf_link_server;
544 static int hf_ticket_client;
545 static int hf_auth_select_client;
546 static int hf_ticket_server;
547 static int hf_main_num_channels;
548 static int hf_main_cap_semi_migrate;
549 static int hf_main_cap_vm_name_uuid;
550 static int hf_main_cap_agent_connected_tokens;
551 static int hf_main_cap_seamless_migrate;
552 static int hf_inputs_cap;
553 static int hf_cursor_cap;
554 static int hf_common_cap_auth_select;
555 static int hf_common_cap_auth_spice;
556 static int hf_common_cap_auth_sasl;
557 static int hf_common_cap_mini_header;
558 static int hf_audio_timestamp;
559 static int hf_audio_mode;
560 static int hf_audio_channels;
561 static int hf_audio_format;
562 static int hf_audio_frequency;
563 static int hf_audio_volume;
564 static int hf_audio_mute;
565 static int hf_audio_latency;
566 static int hf_red_set_ack_generation;
567 static int hf_red_set_ack_window;
568 static int hf_Clip_type;
569 static int hf_Mask_flag;
570 static int hf_display_rop_descriptor;
571 static int hf_display_scale_mode;
572 static int hf_display_stream_id;
573 static int hf_display_stream_report_unique_id;
574 static int hf_display_stream_report_max_window_size;
575 static int hf_display_stream_report_timeout;
576 static int hf_display_stream_width;
577 static int hf_display_stream_height;
578 static int hf_display_stream_src_width;
579 static int hf_display_stream_src_height;
580 static int hf_display_stream_data_size;
581 static int hf_display_stream_codec_type;
582 static int hf_display_stream_stamp;
583 static int hf_display_stream_flags;
584 static int hf_red_ping_id;
585 static int hf_red_timestamp;
586 static int hf_spice_display_mode_width;
587 static int hf_spice_display_mode_height;
588 static int hf_spice_display_mode_depth;
589 static int hf_image_desc_id;
590 static int hf_image_desc_type;
591 static int hf_image_desc_flags;
592 static int hf_image_desc_width;
593 static int hf_image_desc_height;
594 static int hf_quic_width;
595 static int hf_quic_height;
596 static int hf_quic_major_version;
597 static int hf_quic_minor_version;
598 static int hf_quic_type;
599 static int hf_LZ_width;
600 static int hf_LZ_height;
601 static int hf_LZ_major_version;
602 static int hf_LZ_minor_version;
603 static int hf_LZ_PLT_type;
604 static int hf_LZ_RGB_type;
605 static int hf_LZ_stride;
606 static int hf_LZ_RGB_dict_id;
607 static int hf_cursor_trail_len;
608 static int hf_cursor_trail_freq;
609 static int hf_cursor_trail_visible;
610 static int hf_cursor_unique;
611 static int hf_cursor_type;
612 static int hf_cursor_width;
613 static int hf_cursor_height;
614 static int hf_cursor_hotspot_x;
615 static int hf_cursor_hotspot_y;
616 static int hf_cursor_flags;
617 static int hf_cursor_id;
618 static int hf_spice_display_init_cache_id;
619 static int hf_spice_display_init_cache_size;
620 static int hf_spice_display_init_glz_dict_id;
621 static int hf_spice_display_init_dict_window_size;
622 static int hf_brush_type;
623 static int hf_brush_rgb;
624 static int hf_pixmap_width;
625 static int hf_pixmap_height;
626 static int hf_pixmap_stride;
627 static int hf_pixmap_address;
628 static int hf_pixmap_format;
629 static int hf_pixmap_flags;
630 static int hf_keyboard_modifiers;
631 static int hf_keyboard_modifier_scroll_lock;
632 static int hf_keyboard_modifier_num_lock;
633 static int hf_keyboard_modifier_caps_lock;
634 static int hf_keyboard_code;
635 static int hf_rectlist_size;
636 static int hf_migrate_dest_port;
637 static int hf_migrate_dest_sport;
638 static int hf_migrate_src_mig_version;
639 static int hf_session_id;
640 static int hf_display_channels_hint;
641 static int hf_supported_mouse_modes;
642 static int hf_current_mouse_mode;
643 static int hf_supported_mouse_modes_flags;
644 static int hf_supported_mouse_modes_flag_client;
645 static int hf_supported_mouse_modes_flag_server;
646 static int hf_current_mouse_mode_flags;
647 static int hf_agent_connected;
648 static int hf_agent_tokens;
649 static int hf_agent_protocol;
650 static int hf_agent_type;
651 static int hf_agent_opaque;
652 static int hf_agent_size;
653 static int hf_agent_token;
654 static int hf_agent_clipboard_selection;
655 static int hf_agent_clipboard_type;
656 static int hf_agent_num_monitors;
657 static int hf_agent_monitor_height;
658 static int hf_agent_monitor_width;
659 static int hf_agent_monitor_depth;
660 static int hf_agent_monitor_x;
661 static int hf_agent_monitor_y;
662 static int hf_multi_media_time;
663 static int hf_ram_hint;
664 static int hf_button;
665 static int hf_buttons_state;
666 static int hf_button_mask_left;
667 static int hf_button_mask_middle;
668 static int hf_button_mask_right;
669 static int hf_button_mask_reserved_bits;
670 static int hf_mouse_display_id;
671 static int hf_display_text_fore_mode;
672 static int hf_display_text_back_mode;
673 static int hf_display_surface_id;
674 static int hf_display_surface_width;
675 static int hf_display_surface_height;
676 static int hf_display_surface_format;
677 static int hf_display_surface_flags;
678 static int hf_main_client_agent_tokens;
679 static int hf_tranparent_src_color;
680 static int hf_tranparent_true_color;
681 static int hf_spice_sasl_auth_result;
682 static int hf_playback_cap_celt_0_5_1;
683 static int hf_playback_cap_volume;
684 static int hf_playback_cap_latency;
685 static int hf_playback_cap_opus;
686 static int hf_record_cap_celt;
687 static int hf_record_cap_volume;
688 static int hf_record_cap_opus;
689 static int hf_display_cap_sized_stream;
690 static int hf_display_cap_monitors_config;
691 static int hf_display_cap_composite;
692 static int hf_display_cap_a8_surface;
693 static int hf_display_cap_stream_report;
694 static int hf_display_cap_lz4_compression;
695 static int hf_display_cap_pref_compression;
696 static int hf_display_cap_gl_scanout;
697 static int hf_display_cap_multi_codec;
698 static int hf_display_cap_codec_mjpeg;
699 static int hf_display_cap_codec_vp8;
700 static int hf_display_cap_codec_h264;
701 static int hf_display_cap_pref_video_codec_type;
702 static int hf_display_cap_codec_vp9;
703 static int hf_display_cap_codec_h265;
704 static int hf_main_uuid;
705 static int hf_main_name;
706 static int hf_main_name_len;
707 static int hf_display_monitor_config_count;
708 static int hf_display_monitor_config_max_allowed;
709 static int hf_display_head_id;
710 static int hf_display_head_surface_id;
711 static int hf_display_head_width;
712 static int hf_display_head_height;
713 static int hf_display_head_x;
714 static int hf_display_head_y;
715 static int hf_display_head_flags;
716 static int hf_zlib_uncompress_size;
717 static int hf_zlib_compress_size;
718 static int hf_rect_left;
719 static int hf_rect_top;
720 static int hf_rect_right;
721 static int hf_rect_bottom;
722 static int hf_point32_x;
723 static int hf_point32_y;
724 static int hf_point16_x;
725 static int hf_point16_y;
726 static int hf_severity;
727 static int hf_visibility;
728 static int hf_notify_code;
729 static int hf_notify_message_len;
730 static int hf_notify_message;
731 static int hf_num_glyphs;
732 static int hf_port_opened;
733 static int hf_port_event;
734 static int hf_raw_data;
735 static int hf_display_inval_list_count;
736 static int hf_resource_type;
737 static int hf_resource_id;
738 static int hf_ref_image;
739 static int hf_ref_string;
740 static int hf_vd_agent_buttons;
741 static int hf_vd_agent_caps_request;
742 static int hf_vd_agent_cap_mouse_state;
743 static int hf_vd_agent_cap_monitors_config;
744 static int hf_vd_agent_cap_reply;
745 static int hf_vd_agent_cap_clipboard;
746 static int hf_vd_agent_cap_display_config;
747 static int hf_vd_agent_cap_clipboard_by_demand;
748 static int hf_vd_agent_cap_clipboard_selection;
749 static int hf_vd_agent_cap_sparse_monitors_config;
750 static int hf_vd_agent_cap_guest_lineend_lf;
751 static int hf_vd_agent_cap_guest_lineend_crlf;
752 static int hf_vd_agent_monitors_config_flag_use_pos;
753 static int hf_vd_agent_reply_type;
754 static int hf_vd_agent_reply_error;
755 /* Generated from convert_proto_tree_add_text.pl */
756 static int hf_spice_supported_authentication_mechanisms_list;
757 static int hf_spice_selected_client_out_mechanism;
758 static int hf_spice_scale_mode;
759 static int hf_spice_supported_authentication_mechanisms_list_length;
760 static int hf_spice_rop3;
761 static int hf_spice_x509_subjectpublickeyinfo;
762 static int hf_spice_glz_rgb_image_size;
763 static int hf_spice_vd_agent_display_config_message;
764 static int hf_spice_stream_data;
765 static int hf_spice_client_out_mechanism_length;
766 static int hf_spice_vd_agent_clipboard_message;
767 static int hf_spice_image_from_cache;
768 static int hf_spice_lz_rgb_compressed_image_data;
769 static int hf_spice_unknown_bytes;
770 static int hf_spice_sasl_data;
771 static int hf_spice_name_length;
772 static int hf_spice_zlib_stream;
773 static int hf_spice_lz_plt_image_size;
774 static int hf_spice_reserved;
775 static int hf_spice_sasl_authentication_data;
776 static int hf_spice_image_from_cache_lossless;
777 static int hf_spice_quic_magic;
778 static int hf_spice_surface_id;
779 static int hf_spice_ping_data;
780 static int hf_spice_display_mark_message;
781 static int hf_spice_pixmap_pixels;
782 static int hf_spice_vd_agent_clipboard_release_message;
783 static int hf_spice_clientout_list;
784 static int hf_spice_server_inputs_mouse_motion_ack_message;
785 static int hf_spice_cursor_data;
786 static int hf_spice_clientout_length;
787 static int hf_spice_lz_magic;
788 static int hf_spice_lz_rgb_image_size;
789 static int hf_spice_lz_plt_data;
790 static int hf_spice_glyph_flags;
791 static int hf_spice_palette_offset;
792 #if 0
793 static int hf_spice_lz_jpeg_image_size;
794 #endif
795 static int hf_spice_palette;
796 static int hf_spice_selected_authentication_mechanism_length;
797 static int hf_spice_display_reset_message;
798 static int hf_spice_topdown_flag;
799 static int hf_spice_quic_image_size;
800 static int hf_spice_sasl_message_length;
801 static int hf_spice_selected_authentication_mechanism;
802 static int hf_spice_lz_plt_flag;
803 static int hf_spice_quic_compressed_image_data;
805 static expert_field ei_spice_decompress_error;
806 static expert_field ei_spice_unknown_message;
807 static expert_field ei_spice_not_dissected;
808 static expert_field ei_spice_auth_unknown;
809 static expert_field ei_spice_sasl_auth_result;
810 static expert_field ei_spice_expected_from_client;
811 /* Generated from convert_proto_tree_add_text.pl */
812 static expert_field ei_spice_brush_type;
813 static expert_field ei_spice_unknown_image_type;
814 static expert_field ei_spice_Mask_flag;
815 static expert_field ei_spice_Mask_point;
816 static expert_field ei_spice_common_cap_unknown;
817 static expert_field ei_spice_unknown_channel;
820 static dissector_handle_t jpeg_handle;
822 static uint32_t
823 dissect_SpiceHead(tvbuff_t *tvb, proto_tree *tree, uint32_t offset, const uint16_t num)
825 proto_tree *SpiceHead_tree;
827 SpiceHead_tree = proto_tree_add_subtree_format(tree, tvb, offset, sizeof_SpiceHead,
828 ett_SpiceHead, NULL, "Display Head #%u", num);
829 proto_tree_add_item(SpiceHead_tree, hf_display_head_id, tvb, offset, 4, ENC_LITTLE_ENDIAN);
830 offset += 4;
831 proto_tree_add_item(SpiceHead_tree, hf_display_head_surface_id, tvb, offset, 4, ENC_LITTLE_ENDIAN);
832 offset += 4;
833 proto_tree_add_item(SpiceHead_tree, hf_display_head_width, tvb, offset, 4, ENC_LITTLE_ENDIAN);
834 offset += 4;
835 proto_tree_add_item(SpiceHead_tree, hf_display_head_height, tvb, offset, 4, ENC_LITTLE_ENDIAN);
836 offset += 4;
837 proto_tree_add_item(SpiceHead_tree, hf_display_head_x, tvb, offset, 4, ENC_LITTLE_ENDIAN);
838 offset += 4;
839 proto_tree_add_item(SpiceHead_tree, hf_display_head_y, tvb, offset, 4, ENC_LITTLE_ENDIAN);
840 offset += 4;
841 proto_tree_add_item(SpiceHead_tree, hf_display_head_flags, tvb, offset, 4, ENC_LITTLE_ENDIAN);
842 offset += 4;
844 return offset;
847 #define sizeof_AgentMonitorConfig 20
848 static uint32_t
849 dissect_AgentMonitorConfig(tvbuff_t *tvb, proto_tree *tree, uint32_t offset, const uint16_t num)
851 proto_tree *subtree;
853 subtree = proto_tree_add_subtree_format(tree, tvb, offset, sizeof_AgentMonitorConfig,
854 ett_SpiceHead, NULL, "Monitor Config #%u", num);
855 proto_tree_add_item(subtree, hf_agent_monitor_height, tvb, offset, 4, ENC_LITTLE_ENDIAN);
856 offset += 4;
857 proto_tree_add_item(subtree, hf_agent_monitor_width, tvb, offset, 4, ENC_LITTLE_ENDIAN);
858 offset += 4;
859 proto_tree_add_item(subtree, hf_agent_monitor_depth, tvb, offset, 4, ENC_LITTLE_ENDIAN);
860 offset += 4;
861 proto_tree_add_item(subtree, hf_agent_monitor_x, tvb, offset, 4, ENC_LITTLE_ENDIAN);
862 offset += 4;
863 proto_tree_add_item(subtree, hf_agent_monitor_y, tvb, offset, 4, ENC_LITTLE_ENDIAN);
864 offset += 4;
866 return offset;
869 /* returns the pixmap size in bytes */
870 static uint32_t
871 dissect_Pixmap(tvbuff_t *tvb, proto_tree *tree, uint32_t offset)
873 proto_item *ti;
874 proto_tree *Pixmap_tree;
875 uint32_t PixmapSize;
876 uint32_t strides, height, palette_ptr;
878 Pixmap_tree = proto_tree_add_subtree(tree, tvb, offset, 0, ett_Pixmap, &ti, "Pixmap"); /* size is fixed later */
879 proto_tree_add_item(Pixmap_tree, hf_pixmap_format, tvb, offset, 1, ENC_LITTLE_ENDIAN);
880 offset += 1;
881 proto_tree_add_item(Pixmap_tree, hf_pixmap_flags, tvb, offset, 1, ENC_LITTLE_ENDIAN);
882 offset += 1;
883 proto_tree_add_item(Pixmap_tree, hf_pixmap_width, tvb, offset, 4, ENC_LITTLE_ENDIAN);
884 offset += 4;
885 height = tvb_get_letohl(tvb, offset);
886 proto_tree_add_item(Pixmap_tree, hf_pixmap_height, tvb, offset, 4, ENC_LITTLE_ENDIAN);
887 offset += 4;
888 strides = tvb_get_letohl(tvb, offset);
889 proto_tree_add_item(Pixmap_tree, hf_pixmap_stride, tvb, offset, 4, ENC_LITTLE_ENDIAN);
890 offset += 4;
891 palette_ptr = tvb_get_letohl(tvb, offset);
892 proto_tree_add_item(Pixmap_tree, hf_pixmap_address, tvb, offset, 4, ENC_LITTLE_ENDIAN);
893 offset += 4;
894 PixmapSize = height * strides;
895 proto_item_set_len(ti, 18 + PixmapSize);
896 proto_tree_add_bytes_format(Pixmap_tree, hf_spice_pixmap_pixels, tvb, offset, PixmapSize, NULL,
897 "Pixmap pixels (%d bytes)", PixmapSize);
898 offset += PixmapSize;
899 /* FIXME: compute palette size */
900 proto_tree_add_bytes_format(Pixmap_tree, hf_spice_palette, tvb, offset, 0, NULL, "Palette (offset from message start - %u)", palette_ptr);
901 /*TODO: complete pixmap dissection */
903 return PixmapSize + 18;
906 /* returns the type of cursor */
907 static uint8_t
908 dissect_CursorHeader(tvbuff_t *tvb, proto_tree *tree, uint32_t offset, uint16_t *width, uint16_t *height)
910 const uint8_t type = tvb_get_uint8(tvb, offset + 8);
912 *width = tvb_get_letohs(tvb, offset + 8 + 1);
913 *height = tvb_get_letohs(tvb, offset + 8 + 1 + 2);
915 if (tree) {
916 proto_tree *CursorHeader_tree;
918 CursorHeader_tree = proto_tree_add_subtree(tree, tvb, offset, sizeof_CursorHeader, ett_cursor_header, NULL, "Cursor Header");
919 proto_tree_add_item(CursorHeader_tree, hf_cursor_unique, tvb, offset, 8, ENC_LITTLE_ENDIAN);
920 offset += 8;
921 proto_tree_add_item(CursorHeader_tree, hf_cursor_type, tvb, offset, 1, ENC_LITTLE_ENDIAN);
922 offset += 1;
923 proto_tree_add_item(CursorHeader_tree, hf_cursor_width, tvb, offset, 2, ENC_LITTLE_ENDIAN);
924 offset += 2;
925 proto_tree_add_item(CursorHeader_tree, hf_cursor_height, tvb, offset, 2, ENC_LITTLE_ENDIAN);
926 offset += 2;
927 proto_tree_add_item(CursorHeader_tree, hf_cursor_hotspot_x, tvb, offset, 2, ENC_LITTLE_ENDIAN);
928 offset += 2;
929 proto_tree_add_item(CursorHeader_tree, hf_cursor_hotspot_y, tvb, offset, 2, ENC_LITTLE_ENDIAN);
932 return type;
935 /* returns the size of RedCursor */
936 static uint32_t
937 dissect_RedCursor(tvbuff_t *tvb, proto_tree *tree, uint32_t offset)
939 proto_item *ti;
940 proto_tree *RedCursor_tree;
941 uint8_t type;
942 uint16_t height, width;
943 uint32_t init_offset = offset;
944 const uint16_t flags = tvb_get_letohs(tvb, offset);
945 uint32_t data_size = 0;
947 RedCursor_tree = proto_tree_add_subtree(tree, tvb, offset, 2, ett_RedCursor, &ti, "RedCursor"); /* FIXME - fix size if flag is not NONE */
949 proto_tree_add_item(RedCursor_tree, hf_cursor_flags, tvb, offset, 2, ENC_LITTLE_ENDIAN);
950 if (flags == SPICE_CURSOR_FLAGS_NONE) {
951 return 2;
954 offset += 2;
956 type = dissect_CursorHeader(tvb, RedCursor_tree, offset, &width, &height);
957 offset += (int)sizeof_CursorHeader;
960 if (((width == 0) || (height == 0)) || (flags == SPICE_CURSOR_FLAGS_FROM_CACHE)) {
961 proto_item_set_len(ti, offset - init_offset);
962 return (offset - init_offset);
965 switch (type) {
966 case SPICE_CURSOR_TYPE_ALPHA:
967 data_size = (width << 2) * height;
968 break;
969 case SPICE_CURSOR_TYPE_MONO:
970 data_size = (SPICE_ALIGN(width, 8) >> 2) * height;
971 break;
972 /* TODO: fix all size calculations for below cursor types, using SPICE_ALIGN */
973 case SPICE_CURSOR_TYPE_COLOR4:
974 case SPICE_CURSOR_TYPE_COLOR8:
975 case SPICE_CURSOR_TYPE_COLOR16:
976 case SPICE_CURSOR_TYPE_COLOR24:
977 case SPICE_CURSOR_TYPE_COLOR32:
978 break;
979 default:
980 data_size = 0;
981 break;
983 if (data_size != 0) {
984 proto_tree_add_item(RedCursor_tree, hf_spice_cursor_data, tvb, offset, data_size, ENC_NA);
985 } else {
986 proto_tree_add_item(RedCursor_tree, hf_spice_cursor_data, tvb, offset, -1, ENC_NA);
988 offset += data_size;
991 return (offset - init_offset);
994 /* returns the image type, needed for later */
995 static uint8_t
996 dissect_ImageDescriptor(tvbuff_t *tvb, proto_tree *tree, uint32_t offset)
998 const uint8_t type = tvb_get_uint8(tvb, offset + 8);
1000 if (tree) {
1001 proto_tree *ImageDescriptor_tree;
1003 ImageDescriptor_tree = proto_tree_add_subtree(tree, tvb, offset, sizeof_ImageDescriptor, ett_imagedesc, NULL, "Image Descriptor");
1005 proto_tree_add_item(ImageDescriptor_tree, hf_image_desc_id, tvb, offset, 8, ENC_LITTLE_ENDIAN);
1006 offset += 8;
1007 proto_tree_add_item(ImageDescriptor_tree, hf_image_desc_type, tvb, offset, 1, ENC_LITTLE_ENDIAN);
1008 offset += 1;
1009 proto_tree_add_item(ImageDescriptor_tree, hf_image_desc_flags, tvb, offset, 1, ENC_LITTLE_ENDIAN);
1010 offset += 1;
1011 proto_tree_add_item(ImageDescriptor_tree, hf_image_desc_width, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1012 offset += 4;
1013 proto_tree_add_item(ImageDescriptor_tree, hf_image_desc_height, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1016 return type;
1019 static uint32_t
1020 dissect_ImageQuic(tvbuff_t *tvb, proto_tree *tree, uint32_t offset)
1022 const uint32_t QuicSize = tvb_get_letohl(tvb, offset);
1024 if (tree) {
1025 proto_tree *ImageQuic_tree;
1027 ImageQuic_tree = proto_tree_add_subtree(tree, tvb, offset, QuicSize + 4, ett_imageQuic, NULL, "QUIC Image");
1029 proto_tree_add_uint(ImageQuic_tree, hf_spice_quic_image_size, tvb, offset, 4, QuicSize);
1030 offset += 4;
1031 proto_tree_add_item(ImageQuic_tree, hf_spice_quic_magic, tvb, offset, 4, ENC_ASCII);
1032 offset += 4;
1033 proto_tree_add_item(ImageQuic_tree, hf_quic_major_version, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1034 offset += 2;
1035 proto_tree_add_item(ImageQuic_tree, hf_quic_minor_version, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1036 offset += 2;
1037 proto_tree_add_item(ImageQuic_tree, hf_quic_type, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1038 offset += 4;
1039 proto_tree_add_item(ImageQuic_tree, hf_quic_width, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1040 offset += 4;
1041 proto_tree_add_item(ImageQuic_tree, hf_quic_height, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1042 offset += 4;
1043 proto_tree_add_bytes_format(ImageQuic_tree, hf_spice_quic_compressed_image_data, tvb, offset, QuicSize - 20, NULL, "QUIC compressed image data (%u bytes)", QuicSize);
1046 return QuicSize + 4;
1049 static uint32_t
1050 dissect_ImageLZ_common_header(tvbuff_t *tvb, proto_tree *tree, const uint32_t offset)
1053 proto_tree_add_item(tree, hf_spice_lz_magic, tvb, offset, 4, ENC_ASCII);
1054 proto_tree_add_item(tree, hf_LZ_major_version, tvb, offset + 4, 2, ENC_BIG_ENDIAN);
1055 proto_tree_add_item(tree, hf_LZ_minor_version, tvb, offset + 6, 2, ENC_BIG_ENDIAN);
1057 return 8;
1060 static uint32_t
1061 dissect_ImageLZ_common(tvbuff_t *tvb, proto_tree *tree, uint32_t offset, const bool IsLZ, const uint32_t size)
1064 uint8_t type;
1065 uint32_t end_offset = offset + size;
1067 offset += dissect_ImageLZ_common_header(tvb, tree, offset);
1069 if (IsLZ)
1070 offset +=3; /* alignment in LZ? Does not exist in GLZ?*/
1072 proto_tree_add_item(tree, hf_LZ_RGB_type, tvb, offset, 1, ENC_NA);
1073 type = tvb_get_uint8(tvb, offset);
1074 offset += 1;
1075 switch (type & 0xf) { /* 0xf is the MASK */
1076 case LZ_IMAGE_TYPE_RGB16:
1077 case LZ_IMAGE_TYPE_RGB24:
1078 case LZ_IMAGE_TYPE_RGB32:
1079 proto_tree_add_item(tree, hf_LZ_width, tvb, offset, 4, ENC_BIG_ENDIAN);
1080 offset += 4;
1081 proto_tree_add_item(tree, hf_LZ_height, tvb, offset, 4, ENC_BIG_ENDIAN);
1082 offset += 4;
1083 proto_tree_add_item(tree, hf_LZ_stride, tvb, offset, 4, ENC_BIG_ENDIAN);
1084 offset += 4;
1085 proto_tree_add_item(tree, hf_LZ_RGB_dict_id, tvb, offset, 8, ENC_BIG_ENDIAN);
1086 offset += 8;
1087 proto_tree_add_bytes_format(tree, hf_spice_lz_rgb_compressed_image_data, tvb, offset, end_offset - offset, NULL, "LZ_RGB compressed image data (%u bytes)", end_offset - offset);
1088 break;
1089 case LZ_IMAGE_TYPE_RGBA:
1090 offset += 2;
1091 break;
1092 case LZ_IMAGE_TYPE_XXXA:
1093 proto_tree_add_item(tree, hf_LZ_width, tvb, offset, 4, ENC_BIG_ENDIAN);
1094 offset += 4;
1095 proto_tree_add_item(tree, hf_LZ_height, tvb, offset, 4, ENC_BIG_ENDIAN);
1096 offset += 4;
1097 proto_tree_add_item(tree, hf_LZ_stride, tvb, offset, 4, ENC_BIG_ENDIAN);
1098 offset += 4;
1099 proto_tree_add_item(tree, hf_spice_topdown_flag, tvb, offset, 4, ENC_BIG_ENDIAN);
1100 offset += 4;
1101 proto_tree_add_item(tree, hf_spice_unknown_bytes, tvb, offset, 12, ENC_NA);
1102 offset += 8;
1103 break;
1104 default:
1105 proto_tree_add_item(tree, hf_LZ_width, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1106 offset += 4;
1107 proto_tree_add_item(tree, hf_LZ_height, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1108 offset += 4;
1109 proto_tree_add_item(tree, hf_LZ_stride, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1110 offset += 4;
1111 proto_tree_add_item(tree, hf_LZ_RGB_dict_id, tvb, offset, 8, ENC_LITTLE_ENDIAN);
1112 offset += 8;
1113 proto_tree_add_bytes_format(tree, hf_spice_lz_rgb_compressed_image_data, tvb, offset, end_offset - offset, NULL, "LZ_RGB compressed image data (%u bytes)", end_offset - offset);
1114 break;
1116 return offset;
1119 #if 0
1120 static uint32_t
1121 dissect_ImageLZ_JPEG(tvbuff_t *tvb, proto_tree *tree, uint32_t offset)
1123 proto_tree *LZ_JPEG_tree;
1124 const uint32_t LZ_JPEGSize = tvb_get_letohl(tvb, offset);
1126 LZ_JPEG_tree = proto_tree_add_subtree(tree, tvb, offset, LZ_JPEGSize + 4, ett_LZ_JPEG, NULL, "LZ_JPEG Image");
1127 proto_tree_add_uint(LZ_JPEG_tree, hf_spice_lz_jpeg_image_size, tvb, offset, 4, LZ_JPEGSize);
1128 offset += 4;
1129 offset += dissect_ImageLZ_common_header(tvb, LZ_JPEG_tree, offset);
1131 return offset;
1133 #endif
1135 static uint32_t
1136 dissect_ImageGLZ_RGB(tvbuff_t *tvb, proto_tree *tree, uint32_t offset, const uint32_t size)
1138 proto_tree *GLZ_RGB_tree;
1139 uint32_t GLZ_RGBSize;
1141 if (size == 0) { /* if no size was passed to us, need to fetch it. Otherwise, we already have it from the callee */
1142 GLZ_RGBSize = tvb_get_letohl(tvb, offset);
1143 GLZ_RGB_tree = proto_tree_add_subtree(tree, tvb, offset, GLZ_RGBSize + 4, ett_GLZ_RGB, NULL, "GLZ_RGB Image");
1144 proto_tree_add_uint(GLZ_RGB_tree, hf_spice_glz_rgb_image_size, tvb, offset, 4, GLZ_RGBSize);
1145 offset += 4;
1146 } else {
1147 GLZ_RGBSize = size;
1148 GLZ_RGB_tree = proto_tree_add_subtree(tree, tvb, offset, GLZ_RGBSize, ett_GLZ_RGB, NULL, "GLZ_RGB Image");
1151 dissect_ImageLZ_common(tvb, GLZ_RGB_tree, offset, false, GLZ_RGBSize);
1153 return GLZ_RGBSize + 4;
1156 static uint32_t
1157 dissect_ImageLZ_RGB(tvbuff_t *tvb, proto_tree *tree, uint32_t offset)
1159 proto_tree *LZ_RGB_tree;
1160 const uint32_t LZ_RGBSize = tvb_get_letohl(tvb, offset);
1162 LZ_RGB_tree = proto_tree_add_subtree(tree, tvb, offset, LZ_RGBSize + 4, ett_LZ_RGB, NULL, "LZ_RGB Image");
1163 proto_tree_add_uint(LZ_RGB_tree, hf_spice_lz_rgb_image_size, tvb, offset, 4, LZ_RGBSize);
1164 offset += 4;
1166 dissect_ImageLZ_common(tvb, LZ_RGB_tree, offset, true, LZ_RGBSize);
1168 return LZ_RGBSize + 4;
1171 static uint32_t
1172 dissect_ImageLZ_PLT(tvbuff_t *tvb, proto_tree *tree, uint32_t offset)
1174 proto_tree *LZ_PLT_tree;
1175 uint32_t LZ_PLTSize, pal_size;
1177 const uint32_t current_offset = offset;
1179 LZ_PLTSize = tvb_get_letohl(tvb, offset + 1); /* for some reason, it reports two extra bytes */
1180 LZ_PLT_tree = proto_tree_add_subtree(tree, tvb, offset, (LZ_PLTSize - 2)+ 1 + 4 + 4 + 8 + 4 + 4 + 4 + 4 + 4, ett_LZ_PLT, NULL, "LZ_PLT Image");
1182 proto_tree_add_item(LZ_PLT_tree, hf_spice_lz_plt_flag, tvb, offset, 1, ENC_NA); /* TODO: dissect */
1183 offset += 1;
1184 proto_tree_add_uint_format_value(LZ_PLT_tree, hf_spice_lz_plt_image_size, tvb, offset, 4, LZ_PLTSize, "%u bytes (2 extra bytes?)", LZ_PLTSize);
1185 offset += 4;
1187 proto_tree_add_item_ret_uint(LZ_PLT_tree, hf_spice_palette_offset, tvb, offset, 4, ENC_LITTLE_ENDIAN, &pal_size); /* TODO: not sure it's correct */
1188 offset += 4;
1190 dissect_ImageLZ_common_header(tvb, LZ_PLT_tree, offset);
1191 offset += 8;
1193 proto_tree_add_item(LZ_PLT_tree, hf_LZ_PLT_type, tvb, offset, 4, ENC_BIG_ENDIAN);
1194 offset += 4;
1195 proto_tree_add_item(LZ_PLT_tree, hf_LZ_width, tvb, offset, 4, ENC_BIG_ENDIAN);
1196 offset += 4;
1197 proto_tree_add_item(LZ_PLT_tree, hf_LZ_height, tvb, offset, 4, ENC_BIG_ENDIAN);
1198 offset += 4;
1199 proto_tree_add_item(LZ_PLT_tree, hf_LZ_stride, tvb, offset, 4, ENC_BIG_ENDIAN);
1200 offset += 4;
1201 proto_tree_add_item(LZ_PLT_tree, hf_spice_topdown_flag, tvb, offset, 4, ENC_BIG_ENDIAN);
1202 offset += 4;
1203 proto_tree_add_bytes_format(LZ_PLT_tree, hf_spice_lz_plt_data, tvb, offset, (LZ_PLTSize - 2), NULL, "LZ_PLT data (%u bytes)", (LZ_PLTSize - 2));
1204 offset += (LZ_PLTSize - 2);
1205 /* TODO:
1206 * proto_tree_add_bytes_format(LZ_PLT_tree, tvb, offset, pal_size, "palette (%u bytes)" , pal_size);
1207 * offset += pal_size;
1209 return offset - current_offset;
1214 static uint32_t
1215 dissect_ImageJPEG_Alpha(tvbuff_t *tvb, proto_tree *tree, packet_info *pinfo, uint32_t offset)
1217 proto_tree *JPEG_tree;
1218 tvbuff_t *jpeg_tvb;
1219 uint32_t JPEG_Size, Data_Size;
1221 /*TODO: const uint8_t flags = tvb_get_uint8(tvb, offset); dissect and present */
1222 offset += 1;
1224 JPEG_Size = tvb_get_letohl(tvb, offset);
1225 offset += 4;
1227 Data_Size = tvb_get_letohl(tvb, offset);
1228 offset += 4;
1230 JPEG_tree = proto_tree_add_subtree_format(tree, tvb, offset - 9, Data_Size + 9,
1231 ett_JPEG, NULL, "RGB JPEG Image, Alpha channel (%u bytes)", Data_Size);
1233 jpeg_tvb = tvb_new_subset_length(tvb, offset, JPEG_Size);
1234 call_dissector(jpeg_handle, jpeg_tvb, pinfo, JPEG_tree);
1235 offset += JPEG_Size;
1237 dissect_ImageLZ_common(tvb, tree, offset, true, JPEG_Size);
1239 return Data_Size + 9;
1242 static uint32_t
1243 dissect_ImageJPEG(tvbuff_t *tvb, proto_tree *tree, packet_info *pinfo, const uint32_t offset)
1245 proto_tree *JPEG_tree;
1246 tvbuff_t *jpeg_tvb;
1248 const uint32_t JPEG_Size = tvb_get_letohl(tvb, offset);
1249 JPEG_tree = proto_tree_add_subtree_format(tree, tvb, offset, JPEG_Size + 4, ett_JPEG, NULL, "JPEG Image (%u bytes)", JPEG_Size);
1251 jpeg_tvb = tvb_new_subset_length(tvb, offset + 4, JPEG_Size);
1252 call_dissector(jpeg_handle, jpeg_tvb, pinfo, JPEG_tree);
1254 return JPEG_Size + 4;
1257 #if defined (HAVE_ZLIB) || defined (HAVE_ZLIBNG)
1258 static void
1259 dissect_ImageZLIB_GLZ_stream(tvbuff_t *tvb, proto_tree *ZLIB_GLZ_tree, packet_info *pinfo,
1260 uint32_t offset, uint32_t ZLIB_GLZSize, uint32_t ZLIB_uncompSize)
1262 proto_item *ti;
1263 proto_tree *Uncomp_tree;
1264 tvbuff_t *uncompressed_tvb;
1266 Uncomp_tree = proto_tree_add_subtree_format(ZLIB_GLZ_tree, tvb, offset, ZLIB_GLZSize, ett_Uncomp_tree, &ti, "ZLIB stream (%u bytes)", ZLIB_GLZSize);
1267 uncompressed_tvb = tvb_child_uncompress_zlib(tvb, tvb, offset, ZLIB_GLZSize);
1268 if (uncompressed_tvb != NULL) {
1269 add_new_data_source(pinfo, uncompressed_tvb, "Uncompressed GLZ stream");
1270 dissect_ImageGLZ_RGB(uncompressed_tvb, Uncomp_tree, 0, ZLIB_uncompSize);
1271 } else {
1272 expert_add_info(pinfo, ti, &ei_spice_decompress_error);
1275 #else
1276 static void
1277 dissect_ImageZLIB_GLZ_stream(tvbuff_t *tvb, proto_tree *ZLIB_GLZ_tree, packet_info *pinfo _U_,
1278 uint32_t offset, uint32_t ZLIB_GLZSize, uint32_t ZLIB_uncompSize _U_)
1280 proto_tree_add_bytes_format(ZLIB_GLZ_tree, hf_spice_zlib_stream, tvb, offset, ZLIB_GLZSize, NULL, "ZLIB stream (%u bytes)", ZLIB_GLZSize);
1282 #endif
1284 static uint32_t
1285 dissect_ImageZLIB_GLZ(tvbuff_t *tvb, proto_tree *tree, packet_info *pinfo, uint32_t offset)
1287 proto_tree *ZLIB_GLZ_tree;
1288 uint32_t ZLIB_GLZSize, ZLIB_uncompSize;
1290 ZLIB_uncompSize = tvb_get_letohl(tvb, offset);
1291 ZLIB_GLZSize = tvb_get_letohl(tvb, offset + 4); /* compressed size */
1292 if (tree) {
1293 ZLIB_GLZ_tree = proto_tree_add_subtree(tree, tvb, offset, ZLIB_GLZSize + 8, ett_ZLIB_GLZ, NULL, "ZLIB over GLZ Image");
1295 proto_tree_add_item(ZLIB_GLZ_tree, hf_zlib_uncompress_size, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1296 offset += 4;
1297 proto_tree_add_item(ZLIB_GLZ_tree, hf_zlib_compress_size, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1298 offset += 4;
1299 dissect_ImageZLIB_GLZ_stream(tvb, ZLIB_GLZ_tree, pinfo, offset, ZLIB_GLZSize, ZLIB_uncompSize);
1302 return ZLIB_GLZSize + 8;
1305 /* returns the size of an image, not offset */
1306 static uint32_t
1307 dissect_Image(tvbuff_t *tvb, proto_tree *tree, packet_info *pinfo, uint32_t offset)
1309 uint32_t ImageSize = 0;
1310 const uint8_t type = dissect_ImageDescriptor(tvb, tree, offset);
1312 offset += (int)sizeof_ImageDescriptor;
1314 switch (type) {
1315 case SPICE_IMAGE_TYPE_BITMAP:
1316 ImageSize = dissect_Pixmap(tvb, tree, offset);
1317 break;
1318 case SPICE_IMAGE_TYPE_QUIC:
1319 ImageSize = dissect_ImageQuic(tvb, tree, offset);
1320 break;
1321 case SPICE_IMAGE_TYPE_LZ_PLT:
1322 ImageSize = dissect_ImageLZ_PLT(tvb, tree, offset);
1323 break;
1324 case SPICE_IMAGE_TYPE_LZ_RGB:
1325 ImageSize = dissect_ImageLZ_RGB(tvb, tree, offset);
1326 break;
1327 case SPICE_IMAGE_TYPE_GLZ_RGB:
1328 ImageSize = dissect_ImageGLZ_RGB(tvb, tree, offset, 0);
1329 break;
1330 case SPICE_IMAGE_TYPE_FROM_CACHE:
1331 proto_tree_add_item(tree, hf_spice_image_from_cache, tvb, offset, 0, ENC_NA);
1332 break;
1333 case SPICE_IMAGE_TYPE_SURFACE:
1334 ImageSize = 4; /* surface ID */
1335 proto_tree_add_item(tree, hf_spice_surface_id, tvb, offset, ImageSize, ENC_LITTLE_ENDIAN);
1336 break;
1337 case SPICE_IMAGE_TYPE_JPEG:
1338 ImageSize = dissect_ImageJPEG(tvb, tree, pinfo, offset);
1339 break;
1340 case SPICE_IMAGE_TYPE_FROM_CACHE_LOSSLESS:
1341 proto_tree_add_item(tree, hf_spice_image_from_cache_lossless, tvb, offset, 0, ENC_NA);
1342 break;
1343 case SPICE_IMAGE_TYPE_ZLIB_GLZ_RGB:
1344 ImageSize = dissect_ImageZLIB_GLZ(tvb, tree, pinfo, offset);
1345 break;
1346 case SPICE_IMAGE_TYPE_JPEG_ALPHA:
1347 ImageSize = dissect_ImageJPEG_Alpha(tvb, tree, pinfo, offset);
1348 break;
1349 default:
1350 proto_tree_add_expert(tree, pinfo, &ei_spice_unknown_image_type, tvb, offset, -1);
1353 return sizeof_ImageDescriptor + ImageSize;
1356 static SpiceRect
1357 dissect_SpiceRect(tvbuff_t *tvb, proto_tree *tree, const uint32_t offset, const int32_t id)
1359 proto_tree *rect_tree;
1360 SpiceRect rect;
1362 rect.left = tvb_get_letohl(tvb, offset);
1363 rect.top = tvb_get_letohl(tvb, offset + 4);
1364 rect.right = tvb_get_letohl(tvb, offset + 8);
1365 rect.bottom = tvb_get_letohl(tvb, offset + 12);
1367 if (tree) {
1368 if (id != -1) {
1369 rect_tree = proto_tree_add_subtree_format(tree, tvb, offset, sizeof_SpiceRect, ett_rect, NULL,
1370 "RECT %u: (%u-%u, %u-%u)", id, rect.left, rect.top, rect.right, rect.bottom);
1371 } else { /* single rectangle */
1372 rect_tree = proto_tree_add_subtree_format(tree, tvb, offset, sizeof_SpiceRect, ett_rect, NULL,
1373 "RECT: (%u-%u, %u-%u)", rect.left, rect.top, rect.right, rect.bottom);
1376 proto_tree_add_item(rect_tree, hf_rect_left, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1377 proto_tree_add_item(rect_tree, hf_rect_top, tvb, offset + 4, 4, ENC_LITTLE_ENDIAN);
1378 proto_tree_add_item(rect_tree, hf_rect_right, tvb, offset + 8, 4, ENC_LITTLE_ENDIAN);
1379 proto_tree_add_item(rect_tree, hf_rect_bottom, tvb, offset + 12, 4, ENC_LITTLE_ENDIAN);
1382 return rect;
1385 static uint32_t
1386 rect_is_empty(const SpiceRect r)
1388 return r.top == r.bottom || r.left == r.right;
1391 static uint32_t
1392 dissect_RectList(tvbuff_t *tvb, proto_tree *tree, uint32_t offset)
1394 proto_tree *rectlist_tree;
1395 uint32_t i;
1396 const uint32_t rectlist_size = tvb_get_letohl(tvb, offset);
1398 if (tree) {
1399 rectlist_tree = proto_tree_add_subtree_format(tree, tvb, offset, 4 + (rectlist_size * sizeof_SpiceRect),
1400 ett_rectlist, NULL, "RectList (%d rects)", rectlist_size);
1402 proto_tree_add_item(rectlist_tree, hf_rectlist_size, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1403 offset += 4;
1404 for (i = 0; i < rectlist_size; i++ ) {
1405 dissect_SpiceRect(tvb, rectlist_tree, offset, i);
1406 offset += (int)sizeof_SpiceRect;
1410 return (4 + (rectlist_size * sizeof_SpiceRect));
1413 /* returns clip type */
1414 static uint8_t
1415 dissect_Clip(tvbuff_t *tvb, proto_tree *tree, const uint32_t offset)
1417 proto_tree *Clip_tree;
1418 const uint8_t type = tvb_get_uint8(tvb, offset);
1420 if (tree) {
1421 Clip_tree = proto_tree_add_subtree(tree, tvb, offset, 1, ett_Clip, NULL, "SpiceClip");
1422 proto_tree_add_item(Clip_tree, hf_Clip_type, tvb, offset, sizeof_Clip, ENC_LITTLE_ENDIAN);
1425 return type;
1428 static proto_item*
1429 dissect_POINT32(tvbuff_t *tvb, proto_tree *tree, const uint32_t offset)
1431 proto_tree *point_tree;
1432 proto_item *ret_item;
1433 point32_t point;
1435 point.x = tvb_get_letohil(tvb, offset);
1436 point.y = tvb_get_letohil(tvb, offset + 4);
1438 point_tree = proto_tree_add_subtree_format(tree, tvb, offset, sizeof(point32_t), ett_point, &ret_item, "POINT (%d, %d)", point.x, point.y);
1440 proto_tree_add_item(point_tree, hf_point32_x, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1441 proto_tree_add_item(point_tree, hf_point32_y, tvb, offset + 4, 4, ENC_LITTLE_ENDIAN);
1443 return ret_item;
1446 static point16_t
1447 dissect_POINT16(tvbuff_t *tvb, proto_tree *tree, const uint32_t offset)
1449 proto_tree *point16_tree;
1450 point16_t point16;
1452 point16.x = tvb_get_letohis(tvb, offset);
1453 point16.y = tvb_get_letohis(tvb, offset + 2);
1455 if (tree) {
1456 point16_tree = proto_tree_add_subtree_format(tree, tvb, offset, sizeof(point16_t), ett_point16, NULL, "POINT16 (%d, %d)", point16.x, point16.y);
1458 proto_tree_add_item(point16_tree, hf_point16_x, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1459 proto_tree_add_item(point16_tree, hf_point16_y, tvb, offset + 2, 2, ENC_LITTLE_ENDIAN);
1462 return point16;
1465 static uint32_t
1466 dissect_Mask(tvbuff_t *tvb, packet_info* pinfo, proto_tree *tree, uint32_t offset)
1468 proto_item *ti, *mask_item, *point_item;
1469 proto_tree *Mask_tree;
1470 uint32_t bitmap;
1472 Mask_tree = proto_tree_add_subtree(tree, tvb, offset, sizeof_Mask, ett_Mask, &ti, "Mask");
1473 mask_item = proto_tree_add_item(Mask_tree, hf_Mask_flag, tvb, offset, 1, ENC_NA);
1474 offset += 1;
1475 point_item = dissect_POINT32(tvb, Mask_tree, offset);
1476 offset += (int)sizeof(point32_t);
1477 bitmap = tvb_get_letohl(tvb, offset);
1478 proto_tree_add_item(Mask_tree, hf_ref_image, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1479 offset += 4;
1481 if (bitmap != 0) {
1482 proto_item_set_len(ti, sizeof_Mask + sizeof_ImageDescriptor);
1483 dissect_ImageDescriptor(tvb, Mask_tree, offset);
1484 return sizeof_Mask + sizeof_ImageDescriptor;
1487 expert_add_info(pinfo, mask_item, &ei_spice_Mask_flag);
1488 expert_add_info(pinfo, point_item, &ei_spice_Mask_point);
1489 return sizeof_Mask;
1492 /* returns brush size */
1493 static uint32_t
1494 dissect_Brush(tvbuff_t *tvb, packet_info* pinfo, proto_tree *tree, uint32_t offset)
1496 proto_tree *brush_tree;
1497 proto_item *ti;
1498 const uint8_t type = tvb_get_uint8(tvb, offset);
1499 ti = proto_tree_add_item(tree, hf_brush_type, tvb, offset, 1, ENC_LITTLE_ENDIAN);
1501 switch (type) {
1502 case SPICE_BRUSH_TYPE_SOLID:
1503 proto_item_set_len(ti, 5);
1504 brush_tree = proto_item_add_subtree(ti, ett_brush);
1505 offset += 1;
1506 proto_tree_add_item(brush_tree, hf_brush_rgb, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1507 return 5;
1508 case SPICE_BRUSH_TYPE_PATTERN:
1509 proto_item_set_len(ti, 17);
1510 brush_tree = proto_item_add_subtree(ti, ett_brush);
1511 proto_tree_add_item(brush_tree, hf_brush_type, tvb, offset, 1, ENC_LITTLE_ENDIAN);
1512 offset += 1;
1513 /* FIXME: this is supposed to be the offset to the image to be used as the pattern. */
1514 /* For now the hack is that callers check if the returned size was not 5 (therefore SOLID, */
1515 /* it's a pattern and later on dissect the image. That's bad. Really. */
1516 proto_tree_add_item(brush_tree, hf_ref_image, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1517 offset += 4;
1518 dissect_POINT32(tvb, brush_tree, offset);
1519 return (1 + 4 + 8);
1520 case SPICE_BRUSH_TYPE_NONE:
1521 return 1;
1522 default:
1523 expert_add_info(pinfo, ti, &ei_spice_brush_type);
1524 return 0;
1527 return 0;
1530 static uint32_t
1531 dissect_DisplayBase(tvbuff_t *tvb, proto_tree *tree, uint32_t offset)
1533 proto_item *ti;
1534 proto_tree *DisplayBase_tree;
1535 SpiceRect rect;
1536 uint8_t clip_type;
1537 uint32_t clip_size = 0;
1539 DisplayBase_tree = proto_tree_add_subtree(tree, tvb, offset, sizeof_DisplayBase, ett_DisplayBase, &ti, "SpiceMsgDisplayBase");
1540 proto_tree_add_item(DisplayBase_tree, hf_display_surface_id, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1541 offset += 4;
1542 rect = dissect_SpiceRect(tvb, DisplayBase_tree, offset, -1);
1543 proto_item_append_text(ti, " - SpiceRect box (%u-%u, %u-%u)",rect.left, rect.top, rect.right, rect.bottom);
1544 offset += (int)sizeof_SpiceRect;
1545 clip_type = dissect_Clip(tvb, DisplayBase_tree, offset);
1546 offset += (int)sizeof_Clip;
1547 if (clip_type == SPICE_CLIP_TYPE_RECTS) {
1548 clip_size = dissect_RectList(tvb, DisplayBase_tree, offset);
1549 proto_item_set_len(ti, sizeof_DisplayBase + clip_size);
1550 return sizeof_DisplayBase + clip_size;
1552 return sizeof_DisplayBase;
1556 #define sizeof_ResourceId 9
1557 static uint32_t
1558 dissect_SpiceResourceId(tvbuff_t *tvb, proto_tree *tree, uint32_t offset, uint16_t count)
1560 proto_tree *resource_tree;
1562 resource_tree = proto_tree_add_subtree_format(tree, tvb, offset, sizeof_ResourceId,
1563 ett_cursor_header, NULL, "Resource #%d", count);
1564 proto_tree_add_item(resource_tree, hf_resource_type, tvb, offset, 1, ENC_LITTLE_ENDIAN);
1565 proto_tree_add_item(resource_tree, hf_resource_id, tvb, offset, 8, ENC_LITTLE_ENDIAN);
1567 return sizeof_ResourceId;
1571 static const char* get_message_type_string(const uint16_t message_type, const spice_conversation_t *spice_info,
1572 const bool client_message)
1575 if (message_type < SPICE_FIRST_AVAIL_MESSAGE) { /* this is a common message */
1576 if (client_message) {
1577 return val_to_str_const(message_type, spice_msgc_vs, "Unknown client message");
1578 } else {
1579 return val_to_str_const(message_type, spice_msg_vs, "Unknown server message");
1583 switch (spice_info->channel_type) {
1584 case SPICE_CHANNEL_MAIN:
1585 if (client_message) {
1586 return val_to_str_const(message_type, spice_msgc_main_vs, "Unknown main channel client message");
1587 } else {
1588 return val_to_str_const(message_type, spice_msg_main_vs, "Unknown main channel server message");
1590 break;
1591 case SPICE_CHANNEL_DISPLAY:
1592 if (client_message) {
1593 return val_to_str_const(message_type, spice_msgc_display_vs, "Unknown display channel client message");
1594 } else {
1595 return val_to_str_const(message_type, spice_msg_display_vs, "Unknown display channel server message");
1597 break;
1598 case SPICE_CHANNEL_INPUTS:
1599 if (client_message) {
1600 return val_to_str_const(message_type, spice_msgc_inputs_vs, "Unknown inputs channel client message");
1601 } else {
1602 return val_to_str_const(message_type, spice_msg_inputs_vs, "Unknown inputs channel server message");
1604 break;
1605 case SPICE_CHANNEL_CURSOR:
1606 if (client_message) {
1607 return val_to_str_const(message_type, NULL, "Unknown cursor channel client message");
1608 } else {
1609 return val_to_str_const(message_type, spice_msg_cursor_vs, "Unknown cursor channel server message");
1611 break;
1612 case SPICE_CHANNEL_PLAYBACK:
1613 return val_to_str_const(message_type, spice_msg_playback_vs, "Unknown playback channel server message");
1614 case SPICE_CHANNEL_RECORD:
1615 if (client_message) {
1616 return val_to_str_const(message_type, spice_msgc_record_vs, "Unknown record channel client message");
1617 } else {
1618 return val_to_str_const(message_type, spice_msg_record_vs, "Unknown record channel server message");
1620 break;
1621 case SPICE_CHANNEL_TUNNEL:
1622 if (client_message) {
1623 return val_to_str_const(message_type, spice_msgc_tunnel_vs, "Unknown tunnel channel client message");
1624 } else {
1625 return val_to_str_const(message_type, spice_msg_tunnel_vs, "Unknown tunnel channel server message");
1627 break;
1628 case SPICE_CHANNEL_SMARTCARD:
1629 if (client_message) {
1630 return val_to_str_const(message_type, spice_msgc_smartcard_vs, "Unknown smartcard channel client message");
1631 } else {
1632 return val_to_str_const(message_type, spice_msg_smartcard_vs, "Unknown smartcard channel server message");
1634 break;
1635 case SPICE_CHANNEL_USBREDIR:
1636 if (client_message) {
1637 const value_string *values = NULL;
1638 if (message_type < SPICE_MSG_END_SPICEVMC)
1639 values = spice_msg_spicevmc_vs;
1640 return val_to_str_const(message_type, values, "Unknown usbredir channel client message");
1641 } else {
1642 const value_string *values = NULL;
1643 if (message_type < SPICE_MSGC_END_SPICEVMC)
1644 values = spice_msgc_spicevmc_vs;
1645 return val_to_str_const(message_type, values, "Unknown usbredir channel server message");
1647 break;
1648 default:
1649 break;
1651 return "Unknown message";
1653 static void
1654 dissect_spice_mini_data_header(tvbuff_t *tvb, proto_tree *tree, const spice_conversation_t *spice_info,
1655 const bool client_message, const uint16_t message_type, uint32_t offset)
1657 proto_tree* subtree;
1659 if (tree) {
1660 subtree = proto_tree_add_subtree_format(tree, tvb, offset, 2, ett_common_client_message, NULL,
1661 "Message type: %s (%d)", get_message_type_string(message_type, spice_info, client_message), message_type);
1662 proto_tree_add_item(subtree, hf_message_type, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1663 offset += 2;
1664 proto_tree_add_item(tree, hf_data_size, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1668 static void
1669 dissect_spice_data_header(tvbuff_t *tvb, proto_tree *tree, const spice_conversation_t *spice_info,
1670 const bool client_message, const uint16_t message_type, proto_item** msgtype_item, uint32_t *sublist_size, uint32_t offset)
1672 proto_tree* subtree;
1673 *sublist_size = tvb_get_letohl(tvb, offset + 14);
1675 if (tree) {
1676 proto_tree_add_item(tree, hf_serial, tvb, offset, 8, ENC_LITTLE_ENDIAN);
1677 offset += 8;
1678 subtree = proto_tree_add_subtree_format(tree, tvb, offset, 2, ett_common_client_message, NULL,
1679 "Message type: %s (%d)", get_message_type_string(message_type, spice_info, client_message), message_type);
1680 *msgtype_item = proto_tree_add_item(subtree, hf_message_type, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1681 offset += 2;
1682 proto_tree_add_item(tree, hf_data_size, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1683 offset += 4;
1684 proto_tree_add_item(tree, hf_data_sublist, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1689 static uint32_t
1690 dissect_spice_common_client_messages(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, const uint16_t message_type, proto_item* msgtype_item, uint32_t offset)
1692 switch (message_type) {
1693 case SPICE_MSGC_ACK_SYNC:
1694 proto_tree_add_item(tree, hf_red_set_ack_generation, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1695 offset += 4;
1696 break;
1697 case SPICE_MSGC_ACK:
1698 break;
1699 case SPICE_MSGC_PONG:
1700 proto_tree_add_item(tree, hf_red_ping_id, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1701 offset += 4;
1702 proto_tree_add_item(tree, hf_red_timestamp, tvb, offset, 8, ENC_LITTLE_ENDIAN);
1703 offset += 8;
1704 break;
1706 case SPICE_MSGC_MIGRATE_FLUSH_MARK:
1707 case SPICE_MSGC_MIGRATE_DATA:
1708 case SPICE_MSGC_DISCONNECTING:
1710 default:
1711 expert_add_info_format(pinfo, msgtype_item, &ei_spice_unknown_message, "Unknown common client message - cannot dissect");
1712 break;
1715 return offset;
1718 static uint32_t
1719 dissect_spice_common_server_messages(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, const uint16_t message_type, proto_item* msgtype_item,
1720 uint32_t offset, const uint32_t total_message_size)
1722 uint32_t message_len;
1724 switch (message_type) {
1726 case SPICE_MSG_MIGRATE:
1727 case SPICE_MSG_MIGRATE_DATA:
1728 case SPICE_MSG_WAIT_FOR_CHANNELS:
1729 case SPICE_MSG_DISCONNECTING:
1731 case SPICE_MSG_SET_ACK:
1732 proto_tree_add_item(tree, hf_red_set_ack_generation, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1733 offset += 4;
1734 proto_tree_add_item(tree, hf_red_set_ack_window, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1735 offset += 4;
1736 break;
1737 case SPICE_MSG_PING:
1738 proto_tree_add_item(tree, hf_red_ping_id, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1739 offset += 4;
1740 proto_tree_add_item(tree, hf_red_timestamp, tvb, offset, 8, ENC_LITTLE_ENDIAN);
1741 offset += 8;
1742 if (total_message_size > 12) {
1743 proto_tree_add_bytes_format(tree, hf_spice_ping_data, tvb, offset, total_message_size - 12,
1744 NULL, "PING DATA (%d bytes)", total_message_size - 12);
1745 offset += (total_message_size - 12);
1747 break;
1748 case SPICE_MSG_NOTIFY:
1749 proto_tree_add_item(tree, hf_red_timestamp, tvb, offset, 8, ENC_LITTLE_ENDIAN);
1750 offset += 8;
1751 proto_tree_add_item(tree, hf_severity, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1752 offset += 4;
1753 proto_tree_add_item(tree, hf_visibility, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1754 offset += 4;
1755 /*TODO: based on severity, dissect the error code */
1756 proto_tree_add_item(tree, hf_notify_code, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1757 offset += 4;
1758 message_len = tvb_get_letohl(tvb, offset);
1759 proto_tree_add_item(tree, hf_notify_message_len, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1760 offset += 4;
1761 proto_tree_add_item(tree, hf_notify_message, tvb, offset, message_len + 1, ENC_ASCII);
1762 offset += (message_len + 1);
1763 break;
1764 default:
1765 expert_add_info_format(pinfo, msgtype_item, &ei_spice_unknown_message, "Unknown common server message - cannot dissect");
1766 break;
1769 return offset;
1771 static uint32_t
1772 dissect_spice_record_client(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, const uint16_t message_type, proto_item* msgtype_item, uint32_t offset)
1774 proto_tree *record_tree;
1776 switch (message_type) {
1777 case SPICE_MSGC_RECORD_MODE:
1778 record_tree = proto_tree_add_subtree(tree, tvb, offset, 8, ett_record_client, NULL, "Client RECORD_MODE message"); /* size is incorrect, fixed later */
1779 proto_tree_add_item(record_tree, hf_audio_timestamp, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1780 offset += 4;
1781 proto_tree_add_item(record_tree, hf_audio_mode, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1782 offset += 2;
1783 /* TODO - mode dependent, there may be more data here */
1784 break;
1785 default:
1786 expert_add_info_format(pinfo, msgtype_item, &ei_spice_unknown_message, "Unknown record client message - cannot dissect");
1787 break;
1790 return offset;
1793 static uint32_t
1794 dissect_spice_display_client(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, const uint16_t message_type, proto_item* msgtype_item, uint32_t offset)
1796 switch (message_type) {
1797 case SPICE_MSGC_DISPLAY_INIT:
1798 proto_tree_add_item(tree, hf_spice_display_init_cache_id, tvb, offset, 1, ENC_LITTLE_ENDIAN);
1799 offset += 1;
1800 proto_tree_add_item(tree, hf_spice_display_init_cache_size, tvb, offset, 8, ENC_LITTLE_ENDIAN);
1801 offset += 8;
1802 proto_tree_add_item(tree, hf_spice_display_init_glz_dict_id, tvb, offset, 1, ENC_LITTLE_ENDIAN);
1803 offset += 1;
1804 proto_tree_add_item(tree, hf_spice_display_init_dict_window_size, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1805 offset += 4;
1806 break;
1807 default:
1808 expert_add_info_format(pinfo, msgtype_item, &ei_spice_unknown_message, "Unknown display client message - cannot dissect");
1809 break;
1812 return offset;
1815 static uint32_t
1816 dissect_spice_display_server(tvbuff_t *tvb, proto_tree *tree, packet_info *pinfo, const uint16_t message_type, proto_item* msgtype_item, uint32_t offset)
1818 uint32_t data_size, displayBaseLen;
1819 uint8_t clip_type;
1820 uint16_t count, i;
1821 SpiceRect r;
1822 tvbuff_t *jpeg_tvb;
1824 switch (message_type) {
1825 case SPICE_MSG_DISPLAY_MODE:
1826 proto_tree_add_item(tree, hf_spice_display_mode_width, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1827 offset += 4;
1828 proto_tree_add_item(tree, hf_spice_display_mode_height, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1829 offset += 4;
1830 proto_tree_add_item(tree, hf_spice_display_mode_depth, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1831 offset += 4;
1832 break;
1833 case SPICE_MSG_DISPLAY_MARK:
1834 proto_tree_add_item(tree, hf_spice_display_mark_message, tvb, offset, 0, ENC_NA);
1835 break;
1836 case SPICE_MSG_DISPLAY_RESET:
1837 proto_tree_add_item(tree, hf_spice_display_reset_message, tvb, offset, 0, ENC_NA);
1838 break;
1839 case SPICE_MSG_DISPLAY_INVAL_LIST:
1840 proto_tree_add_item(tree, hf_display_inval_list_count, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1841 count = tvb_get_letohs(tvb, offset);
1842 offset += 2;
1843 for (i = 0; i < count; i++) {
1844 offset += dissect_SpiceResourceId(tvb, tree, offset, i + 1);
1846 break;
1847 case SPICE_MSG_DISPLAY_DRAW_ALPHA_BLEND:
1848 displayBaseLen = dissect_DisplayBase(tvb, tree, offset);
1849 offset += displayBaseLen;
1850 /* TODO: Flag 1 byte, Alpha 1 byte dissection*/
1851 offset += 2;
1852 proto_tree_add_item(tree, hf_ref_image, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1853 offset += 4;
1854 dissect_SpiceRect(tvb, tree, offset, -1);
1855 offset += (int)sizeof_SpiceRect;
1856 data_size = dissect_Image(tvb, tree, pinfo, offset);
1857 offset += data_size;
1858 break;
1859 case SPICE_MSG_DISPLAY_DRAW_BLACKNESS:
1860 displayBaseLen = dissect_DisplayBase(tvb, tree, offset);
1861 offset += displayBaseLen;
1862 offset += dissect_Mask(tvb, pinfo, tree, offset);
1863 break;
1864 case SPICE_MSG_DISPLAY_COPY_BITS:
1865 displayBaseLen = dissect_DisplayBase(tvb, tree, offset);
1866 offset += displayBaseLen;
1867 dissect_POINT32(tvb, tree, offset);
1868 offset += (int)sizeof(point32_t);
1869 break;
1870 case SPICE_MSG_DISPLAY_DRAW_WHITENESS:
1871 displayBaseLen = dissect_DisplayBase(tvb, tree, offset);
1872 offset += displayBaseLen;
1873 offset += dissect_Mask(tvb, pinfo, tree, offset);
1874 break;
1875 case SPICE_MSG_DISPLAY_DRAW_INVERS:
1876 displayBaseLen = dissect_DisplayBase(tvb, tree, offset);
1877 offset += displayBaseLen;
1878 offset += dissect_Mask(tvb, pinfo, tree, offset);
1879 break;
1880 case SPICE_MSG_DISPLAY_DRAW_FILL:
1881 displayBaseLen = dissect_DisplayBase(tvb, tree, offset);
1882 offset += displayBaseLen;
1883 data_size = dissect_Brush(tvb, pinfo, tree, offset);
1884 offset += data_size;
1886 proto_tree_add_item(tree, hf_display_rop_descriptor, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1887 offset += 2;
1889 offset += dissect_Mask(tvb, pinfo, tree, offset);
1891 if (data_size != 5) { /* if it's not a SOLID brush, it's a PATTERN, dissect its image descriptor */
1892 offset += dissect_Image(tvb, tree, pinfo, offset);
1894 break;
1895 case SPICE_MSG_DISPLAY_DRAW_TRANSPARENT:
1896 displayBaseLen = dissect_DisplayBase(tvb, tree, offset);
1897 offset += displayBaseLen;
1898 proto_tree_add_item(tree, hf_ref_image, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1899 offset += 4;
1900 /* source area */
1901 dissect_SpiceRect(tvb, tree, offset, -1);
1902 offset += (int)sizeof_SpiceRect;
1903 proto_tree_add_item(tree, hf_tranparent_src_color, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1904 offset += 4;
1905 proto_tree_add_item(tree, hf_tranparent_true_color, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1906 offset += 4;
1907 data_size = dissect_Image(tvb, tree, pinfo, offset);
1908 offset += data_size;
1909 break;
1910 case SPICE_MSG_DISPLAY_DRAW_BLEND:
1911 case SPICE_MSG_DISPLAY_DRAW_COPY:
1912 displayBaseLen = dissect_DisplayBase(tvb, tree, offset);
1913 offset += displayBaseLen;
1914 /* SpiceImage *src_bitmap */
1915 proto_tree_add_item(tree, hf_ref_image, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1916 offset += 4;
1918 /* source area */
1919 dissect_SpiceRect(tvb, tree, offset, -1);
1920 offset += (int)sizeof_SpiceRect;
1922 proto_tree_add_item(tree, hf_display_rop_descriptor, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1923 offset += 2;
1925 proto_tree_add_item(tree, hf_display_scale_mode, tvb, offset, 1, ENC_NA);
1926 offset += 1;
1928 offset += dissect_Mask(tvb, pinfo, tree, offset);
1930 data_size = dissect_Image(tvb, tree, pinfo, offset);
1931 offset += data_size;
1932 break;
1933 case SPICE_MSG_DISPLAY_DRAW_ROP3:
1934 displayBaseLen = dissect_DisplayBase(tvb, tree, offset);
1935 offset += displayBaseLen;
1936 /* SpiceImage *src_bitmap */
1937 proto_tree_add_item(tree, hf_ref_image, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1938 offset += 4;
1940 /* source area */
1941 dissect_SpiceRect(tvb, tree, offset, -1);
1942 offset += (int)sizeof_SpiceRect;
1944 data_size = dissect_Brush(tvb, pinfo, tree, offset);
1945 offset += data_size;
1947 proto_tree_add_item(tree, hf_spice_rop3, tvb, offset, 1, ENC_NA);
1948 offset += 1;
1949 proto_tree_add_item(tree, hf_spice_scale_mode, tvb, offset, 1, ENC_NA);
1950 offset += 1;
1952 offset += dissect_Mask(tvb, pinfo, tree, offset);
1953 /*FIXME - need to understand what the rest of the message contains. */
1954 data_size = dissect_Image(tvb, tree, pinfo, offset);
1955 offset += data_size;
1956 break;
1957 case SPICE_MSG_DISPLAY_INVAL_ALL_PALETTES:
1958 break;
1959 case SPICE_MSG_DISPLAY_DRAW_TEXT:
1960 displayBaseLen = dissect_DisplayBase(tvb, tree, offset);
1961 offset += displayBaseLen;
1962 proto_tree_add_item(tree, hf_ref_string, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1963 offset += 4;
1965 r = dissect_SpiceRect(tvb, tree, offset, -1);
1966 offset += (int)sizeof_SpiceRect;
1967 if (!rect_is_empty(r)) {
1968 data_size = dissect_Brush(tvb, pinfo, tree, offset);
1969 offset += data_size;
1971 proto_tree_add_item(tree, hf_display_text_fore_mode, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1972 offset += 2;
1973 proto_tree_add_item(tree, hf_display_text_back_mode, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1974 offset += 2;
1976 proto_tree_add_item(tree, hf_num_glyphs, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1977 offset += 2;
1978 proto_tree_add_item(tree, hf_spice_glyph_flags, tvb, offset, 2, ENC_BIG_ENDIAN);
1979 /*TODO finish dissecting glyph list */
1980 break;
1981 case SPICE_MSG_DISPLAY_DRAW_STROKE:
1982 displayBaseLen = dissect_DisplayBase(tvb, tree, offset);
1983 offset += displayBaseLen;
1984 /*TODO: complete and correct dissection */
1986 break;
1987 case SPICE_MSG_DISPLAY_STREAM_CLIP:
1988 proto_tree_add_item(tree, hf_display_stream_id, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1989 offset += 4;
1990 clip_type = dissect_Clip(tvb, tree, offset);
1991 offset += (int)sizeof_Clip;
1992 if (clip_type == SPICE_CLIP_TYPE_RECTS) {
1993 offset += dissect_RectList(tvb, tree, offset);
1995 break;
1996 case SPICE_MSG_DISPLAY_STREAM_CREATE:
1997 proto_tree_add_item(tree, hf_display_surface_id, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1998 offset += 4;
1999 proto_tree_add_item(tree, hf_display_stream_id, tvb, offset, 4, ENC_LITTLE_ENDIAN);
2000 offset += 4;
2001 proto_tree_add_item(tree, hf_display_stream_flags, tvb, offset, 1, ENC_LITTLE_ENDIAN);
2002 offset += 1;
2003 proto_tree_add_item(tree, hf_display_stream_codec_type, tvb, offset, 1, ENC_LITTLE_ENDIAN);
2004 offset += 1;
2005 proto_tree_add_item(tree, hf_display_stream_stamp, tvb, offset, 8, ENC_LITTLE_ENDIAN);
2006 offset += 8;
2007 proto_tree_add_item(tree, hf_display_stream_width, tvb, offset, 4, ENC_LITTLE_ENDIAN);
2008 offset += 4;
2009 proto_tree_add_item(tree, hf_display_stream_height, tvb, offset, 4, ENC_LITTLE_ENDIAN);
2010 offset += 4;
2011 proto_tree_add_item(tree, hf_display_stream_src_width, tvb, offset, 4, ENC_LITTLE_ENDIAN);
2012 offset += 4;
2013 proto_tree_add_item(tree, hf_display_stream_src_height, tvb, offset, 4, ENC_LITTLE_ENDIAN);
2014 offset += 4;
2015 dissect_SpiceRect(tvb, tree, offset, -1);
2016 offset += (int)sizeof_SpiceRect;
2017 clip_type = dissect_Clip(tvb, tree, offset);
2018 offset += (int)sizeof_Clip;
2019 if (clip_type == SPICE_CLIP_TYPE_RECTS) {
2020 offset += dissect_RectList(tvb, tree, offset);
2022 break;
2023 case SPICE_MSG_DISPLAY_STREAM_DATA:
2024 data_size = tvb_get_letohl(tvb, offset + 8);
2025 proto_tree_add_item(tree, hf_display_stream_id, tvb, offset, 4, ENC_LITTLE_ENDIAN);
2026 offset += 4;
2027 proto_tree_add_item(tree, hf_multi_media_time, tvb, offset, 4, ENC_LITTLE_ENDIAN);
2028 offset += 4;
2029 proto_tree_add_item(tree, hf_display_stream_data_size, tvb, offset, 4, ENC_LITTLE_ENDIAN);
2030 offset += 4;
2031 proto_tree_add_bytes_format(tree, hf_spice_stream_data, tvb, offset, data_size, NULL, "Stream data");
2032 jpeg_tvb = tvb_new_subset_length(tvb, offset, data_size);
2033 call_dissector(jpeg_handle, jpeg_tvb, pinfo, tree);
2034 offset += data_size;
2035 break;
2036 case SPICE_MSG_DISPLAY_STREAM_DESTROY:
2037 proto_tree_add_item(tree, hf_display_stream_id, tvb, offset, 4, ENC_LITTLE_ENDIAN);
2038 offset += 4;
2039 break;
2040 case SPICE_MSG_DISPLAY_STREAM_DATA_SIZED:
2041 proto_tree_add_item(tree, hf_display_stream_id, tvb, offset, 4, ENC_LITTLE_ENDIAN);
2042 offset += 4;
2043 proto_tree_add_item(tree, hf_multi_media_time, tvb, offset, 4, ENC_LITTLE_ENDIAN);
2044 offset += 4;
2045 proto_tree_add_item(tree, hf_display_stream_width, tvb, offset, 4, ENC_LITTLE_ENDIAN);
2046 offset += 4;
2047 proto_tree_add_item(tree, hf_display_stream_height, tvb, offset, 4, ENC_LITTLE_ENDIAN);
2048 offset += 4;
2049 dissect_SpiceRect(tvb, tree, offset, -1);
2050 offset += (int)sizeof_SpiceRect;
2051 proto_tree_add_item(tree, hf_display_stream_data_size, tvb, offset, 4, ENC_LITTLE_ENDIAN);
2052 offset += 4;
2053 break;
2054 case SPICE_MSG_DISPLAY_STREAM_DESTROY_ALL:
2055 break;
2056 case SPICE_MSG_DISPLAY_SURFACE_CREATE:
2057 proto_tree_add_item(tree, hf_display_surface_id, tvb, offset, 4, ENC_LITTLE_ENDIAN);
2058 offset += 4;
2059 proto_tree_add_item(tree, hf_display_surface_width, tvb, offset, 4, ENC_LITTLE_ENDIAN);
2060 offset += 4;
2061 proto_tree_add_item(tree, hf_display_surface_height, tvb, offset, 4, ENC_LITTLE_ENDIAN);
2062 offset += 4;
2063 proto_tree_add_item(tree, hf_display_surface_format, tvb, offset, 4, ENC_LITTLE_ENDIAN);
2064 offset += 4;
2065 proto_tree_add_item(tree, hf_display_surface_flags, tvb, offset, 4, ENC_LITTLE_ENDIAN);
2066 offset += 4;
2067 break;
2068 case SPICE_MSG_DISPLAY_SURFACE_DESTROY:
2069 proto_tree_add_item(tree, hf_display_surface_id, tvb, offset, 4, ENC_LITTLE_ENDIAN);
2070 offset += 4;
2071 break;
2072 case SPICE_MSG_DISPLAY_MONITORS_CONFIG:
2073 proto_tree_add_item(tree, hf_display_monitor_config_count, tvb, offset, 2, ENC_LITTLE_ENDIAN);
2074 count = tvb_get_letohs(tvb, offset);
2075 offset += 2;
2076 proto_tree_add_item(tree, hf_display_monitor_config_max_allowed, tvb, offset, 2, ENC_LITTLE_ENDIAN);
2077 offset += 2;
2078 for (i = 0; i < count; i++) {
2079 offset = dissect_SpiceHead(tvb, tree, offset, i);
2081 break;
2082 case SPICE_MSG_DISPLAY_DRAW_COMPOSITE:
2083 break;
2084 case SPICE_MSG_DISPLAY_STREAM_ACTIVATE_REPORT:
2085 proto_tree_add_item(tree, hf_display_stream_id, tvb, offset, 4, ENC_LITTLE_ENDIAN);
2086 offset += 4;
2087 proto_tree_add_item(tree, hf_display_stream_report_unique_id, tvb, offset, 4, ENC_LITTLE_ENDIAN);
2088 offset += 4;
2089 proto_tree_add_item(tree, hf_display_stream_report_max_window_size, tvb, offset, 4, ENC_LITTLE_ENDIAN);
2090 offset += 4;
2091 proto_tree_add_item(tree, hf_display_stream_report_timeout, tvb, offset, 4, ENC_LITTLE_ENDIAN);
2092 offset += 4;
2093 break;
2094 default:
2095 expert_add_info_format(pinfo, msgtype_item, &ei_spice_unknown_message, "Unknown display server message - cannot dissect");
2096 break;
2098 return offset;
2101 static uint32_t
2102 dissect_spice_playback_server(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, const uint16_t message_type, proto_item* msgtype_item,
2103 uint32_t message_size, spice_conversation_t *spice_info, uint32_t offset)
2105 uint8_t num_channels, i;
2106 proto_tree* subtree;
2108 switch (message_type) {
2109 case SPICE_MSG_PLAYBACK_DATA:
2110 proto_tree_add_item(tree, hf_audio_timestamp, tvb, offset, 4, ENC_LITTLE_ENDIAN);
2111 offset += 4;
2112 proto_tree_add_item(tree, hf_raw_data, tvb, offset, message_size - 4, ENC_NA);
2113 offset += (message_size - 4);
2114 break;
2115 case SPICE_MSG_PLAYBACK_MODE:
2116 proto_tree_add_item(tree, hf_audio_timestamp, tvb, offset, 4, ENC_LITTLE_ENDIAN);
2117 offset += 4;
2118 spice_info->playback_mode = tvb_get_letohs(tvb, offset);
2119 proto_tree_add_item(tree, hf_audio_mode, tvb, offset, 2, ENC_LITTLE_ENDIAN);
2120 offset += 2;
2121 /* TODO - mode dependent, there may be more data here */
2122 break;
2123 case SPICE_MSG_PLAYBACK_START:
2124 proto_tree_add_item(tree, hf_audio_channels, tvb, offset, 4, ENC_LITTLE_ENDIAN);
2125 offset += 4;
2126 proto_tree_add_item(tree, hf_audio_format, tvb, offset, 2, ENC_LITTLE_ENDIAN);
2127 offset += 2;
2128 proto_tree_add_item(tree, hf_audio_frequency, tvb, offset, 4, ENC_LITTLE_ENDIAN);
2129 offset += 4;
2130 proto_tree_add_item(tree, hf_audio_timestamp, tvb, offset, 4, ENC_LITTLE_ENDIAN);
2131 offset += 4;
2132 break;
2133 case SPICE_MSG_PLAYBACK_STOP:
2134 break;
2135 case SPICE_MSG_PLAYBACK_VOLUME:
2136 num_channels = tvb_get_uint8(tvb, offset);
2137 proto_tree_add_item(tree, hf_audio_channels, tvb, offset, 1, ENC_LITTLE_ENDIAN);
2138 offset += 1;
2139 subtree = proto_tree_add_subtree(tree, tvb, offset, 2 * num_channels, ett_record_server, NULL, "Channel volume array");
2140 for (i = 0; i < num_channels; i++) {
2141 proto_tree_add_item(subtree, hf_audio_volume, tvb, offset, 2, ENC_LITTLE_ENDIAN);
2142 offset += 2;
2144 break;
2145 case SPICE_MSG_PLAYBACK_MUTE:
2146 proto_tree_add_item(tree, hf_audio_mute, tvb, offset, 1, ENC_LITTLE_ENDIAN);
2147 offset += 1;
2148 break;
2149 case SPICE_MSG_PLAYBACK_LATENCY:
2150 proto_tree_add_item(tree, hf_audio_latency, tvb, offset, 4, ENC_LITTLE_ENDIAN);
2151 offset += 4;
2152 break;
2153 default:
2154 expert_add_info_format(pinfo, msgtype_item, &ei_spice_unknown_message, "Unknown playback server message - cannot dissect");
2155 break;
2157 return offset;
2160 static uint32_t
2161 dissect_spice_cursor_server(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, const uint16_t message_type, proto_item* msgtype_item, uint32_t offset)
2163 uint32_t RedCursorSize;
2165 switch (message_type) {
2166 case SPICE_MSG_CURSOR_INIT:
2167 dissect_POINT16(tvb, tree, offset);
2168 offset += (int)sizeof(point16_t);
2169 proto_tree_add_item(tree, hf_cursor_trail_len, tvb, offset, 2, ENC_LITTLE_ENDIAN);
2170 offset += 2;
2171 proto_tree_add_item(tree, hf_cursor_trail_freq, tvb, offset, 2, ENC_LITTLE_ENDIAN);
2172 offset += 2;
2173 proto_tree_add_item(tree, hf_cursor_trail_visible, tvb, offset, 1, ENC_LITTLE_ENDIAN);
2174 offset += 1;
2175 RedCursorSize = dissect_RedCursor(tvb, tree, offset);
2176 offset += RedCursorSize;
2177 break;
2178 case SPICE_MSG_CURSOR_RESET:
2179 break;
2180 case SPICE_MSG_CURSOR_SET:
2181 dissect_POINT16(tvb, tree, offset);
2182 offset += (int)sizeof(point16_t);
2183 offset +=1; /*TODO flags */
2184 RedCursorSize = dissect_RedCursor(tvb, tree, offset);
2185 offset += RedCursorSize;
2186 break;
2187 case SPICE_MSG_CURSOR_MOVE:
2188 dissect_POINT16(tvb, tree, offset);
2189 offset += (int)sizeof(point16_t);
2190 break;
2191 case SPICE_MSG_CURSOR_HIDE:
2192 break;
2193 case SPICE_MSG_CURSOR_TRAIL:
2194 proto_tree_add_item(tree, hf_cursor_trail_len, tvb, offset, 2, ENC_LITTLE_ENDIAN);
2195 offset += 2;
2196 proto_tree_add_item(tree, hf_cursor_trail_freq, tvb, offset, 2, ENC_LITTLE_ENDIAN);
2197 offset += 2;
2198 break;
2199 case SPICE_MSG_CURSOR_INVAL_ONE:
2200 proto_tree_add_item(tree, hf_cursor_id, tvb, offset, 8, ENC_LITTLE_ENDIAN);
2201 offset += 8;
2202 break;
2203 case SPICE_MSG_CURSOR_INVAL_ALL:
2204 break;
2205 default:
2206 expert_add_info_format(pinfo, msgtype_item, &ei_spice_unknown_message, "Unknown cursor server message - cannot dissect");
2207 break;
2209 return offset;
2212 static uint32_t
2213 dissect_spice_record_server(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, const uint16_t message_type, proto_item* msgtype_item, uint32_t offset)
2215 uint8_t num_channels, i;
2216 proto_tree* subtree;
2218 switch (message_type) {
2219 case SPICE_MSG_RECORD_STOP:
2220 break;
2221 case SPICE_MSG_RECORD_VOLUME:
2222 num_channels = tvb_get_uint8(tvb, offset);
2223 proto_tree_add_item(tree, hf_audio_channels, tvb, offset, 1, ENC_LITTLE_ENDIAN);
2224 offset += 1;
2225 subtree = proto_tree_add_subtree(tree, tvb, offset, 2 * num_channels, ett_record_server, NULL, "Volume Array");
2226 for (i = 0; i < num_channels; i++) {
2227 proto_tree_add_item(subtree, hf_audio_volume, tvb, offset, 2, ENC_LITTLE_ENDIAN);
2228 offset += 2;
2230 break;
2231 case SPICE_MSG_RECORD_MUTE:
2232 proto_tree_add_item(tree, hf_audio_mute, tvb, offset, 1, ENC_LITTLE_ENDIAN);
2233 offset += 1;
2234 break;
2235 default:
2236 expert_add_info_format(pinfo, msgtype_item, &ei_spice_unknown_message, "Unknown record server message - cannot dissect");
2237 break;
2239 return offset;
2242 static uint32_t
2243 dissect_spice_agent_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, const uint32_t message_type, proto_item* msgtype_item, uint32_t message_len, uint32_t offset)
2245 proto_tree *agent_tree;
2246 uint32_t n_monitors = 0, i;
2248 switch (message_type) {
2249 case VD_AGENT_MOUSE_STATE:
2250 dissect_POINT32(tvb, tree, offset);
2251 offset += (int)sizeof(point32_t);
2252 proto_tree_add_item(tree, hf_vd_agent_buttons, tvb, offset, 4, ENC_LITTLE_ENDIAN);
2253 offset += 4;
2254 proto_tree_add_item(tree, hf_mouse_display_id, tvb, offset, 1, ENC_NA);
2255 offset += 1;
2256 break;
2257 case VD_AGENT_MONITORS_CONFIG:
2258 n_monitors = tvb_get_letohl(tvb, offset);
2259 proto_tree_add_item(tree, hf_agent_num_monitors, tvb, offset, 4, ENC_LITTLE_ENDIAN);
2260 offset += 4;
2261 proto_tree_add_item(tree, hf_vd_agent_monitors_config_flag_use_pos, tvb, offset, 4, ENC_LITTLE_ENDIAN);
2262 offset += 4;
2263 for (i = 0; i < n_monitors; i++) {
2264 offset = dissect_AgentMonitorConfig(tvb, tree, offset, i);
2266 break;
2267 case VD_AGENT_REPLY:
2268 proto_tree_add_item(tree, hf_vd_agent_reply_type, tvb, offset, 4, ENC_LITTLE_ENDIAN);
2269 offset += 4;
2270 proto_tree_add_item(tree, hf_vd_agent_reply_error, tvb, offset, 4, ENC_LITTLE_ENDIAN);
2271 offset += 4;
2272 break;
2273 case VD_AGENT_CLIPBOARD:
2274 /*ti = */proto_tree_add_item(tree, hf_spice_vd_agent_clipboard_message, tvb, offset, message_len, ENC_NA);
2275 /* TODO: display string
2276 agent_tree = proto_item_add_subtree(ti, ett_spice_agent);
2278 offset += message_len;
2279 break;
2280 case VD_AGENT_DISPLAY_CONFIG:
2281 proto_tree_add_item(tree, hf_spice_vd_agent_display_config_message, tvb, offset, 4, ENC_NA);
2282 offset += 4;
2283 break;
2284 case VD_AGENT_ANNOUNCE_CAPABILITIES:
2285 proto_tree_add_item(tree, hf_vd_agent_caps_request, tvb, offset, 4, ENC_LITTLE_ENDIAN);
2286 offset += 4;
2287 proto_tree_add_item(tree, hf_vd_agent_cap_mouse_state, tvb, offset, 4, ENC_LITTLE_ENDIAN);
2288 proto_tree_add_item(tree, hf_vd_agent_cap_monitors_config, tvb, offset, 4, ENC_LITTLE_ENDIAN);
2289 proto_tree_add_item(tree, hf_vd_agent_cap_reply, tvb, offset, 4, ENC_LITTLE_ENDIAN);
2290 proto_tree_add_item(tree, hf_vd_agent_cap_clipboard, tvb, offset, 4, ENC_LITTLE_ENDIAN);
2291 proto_tree_add_item(tree, hf_vd_agent_cap_display_config, tvb, offset, 4, ENC_LITTLE_ENDIAN);
2292 proto_tree_add_item(tree, hf_vd_agent_cap_clipboard_by_demand, tvb, offset, 4, ENC_LITTLE_ENDIAN);
2293 proto_tree_add_item(tree, hf_vd_agent_cap_clipboard_selection, tvb, offset, 4, ENC_LITTLE_ENDIAN);
2294 proto_tree_add_item(tree, hf_vd_agent_cap_sparse_monitors_config, tvb, offset, 4, ENC_LITTLE_ENDIAN);
2295 proto_tree_add_item(tree, hf_vd_agent_cap_guest_lineend_lf, tvb, offset, 4, ENC_LITTLE_ENDIAN);
2296 proto_tree_add_item(tree, hf_vd_agent_cap_guest_lineend_crlf, tvb, offset, 4, ENC_LITTLE_ENDIAN);
2297 offset += 4;
2298 break;
2299 case VD_AGENT_CLIPBOARD_GRAB:
2300 agent_tree = proto_tree_add_subtree(tree, tvb, offset, 4, ett_spice_agent, NULL, "VD_AGENT_CLIPBOARD_GRAB message");
2301 proto_tree_add_item(agent_tree, hf_agent_clipboard_selection, tvb, offset, 1, ENC_LITTLE_ENDIAN);
2302 offset += 1;
2303 proto_tree_add_item(agent_tree, hf_spice_reserved, tvb, offset, 3, ENC_NA);
2304 offset += 3;
2305 break;
2306 case VD_AGENT_CLIPBOARD_REQUEST:
2307 agent_tree = proto_tree_add_subtree(tree, tvb, offset, 8, ett_spice_agent, NULL, "VD_AGENT_CLIPBOARD_REQUEST message");
2308 proto_tree_add_item(agent_tree, hf_agent_clipboard_selection, tvb, offset, 1, ENC_LITTLE_ENDIAN);
2309 offset += 1;
2310 proto_tree_add_item(agent_tree, hf_spice_reserved, tvb, offset, 3, ENC_NA);
2311 offset += 3;
2312 proto_tree_add_item(agent_tree, hf_agent_clipboard_type, tvb, offset, 4, ENC_LITTLE_ENDIAN);
2313 offset += 4;
2314 break;
2315 case VD_AGENT_CLIPBOARD_RELEASE:
2316 proto_tree_add_item(tree, hf_spice_vd_agent_clipboard_release_message, tvb, offset, 0, ENC_NA);
2317 break;
2318 default:
2319 expert_add_info_format(pinfo, msgtype_item, &ei_spice_unknown_message, "Unknown agent message (%u) - cannot dissect", message_type);
2320 break;
2322 return offset;
2325 /* note that the size property is necessary here because the protocol uses
2326 * uint32 in the INIT message, and flags16 in the MOUSE_MODE message
2328 static uint32_t
2329 dissect_supported_mouse_modes(tvbuff_t *tvb, proto_tree *tree, uint32_t offset, uint32_t size)
2331 proto_item* ti;
2332 proto_tree *sub_tree;
2333 int hf = hf_supported_mouse_modes;
2335 if (size == 2)
2336 hf = hf_supported_mouse_modes_flags;
2338 ti = proto_tree_add_item(tree, hf, tvb, offset, size, ENC_LITTLE_ENDIAN);
2339 sub_tree = proto_item_add_subtree(ti, ett_main_client);
2341 proto_tree_add_item(sub_tree, hf_supported_mouse_modes_flag_client, tvb, offset, 2, ENC_LITTLE_ENDIAN);
2342 proto_tree_add_item(sub_tree, hf_supported_mouse_modes_flag_server, tvb, offset, 2, ENC_LITTLE_ENDIAN);
2344 return offset + size;
2347 static uint32_t
2348 dissect_spice_main_server(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, const uint16_t message_type, proto_item* msgtype_item, uint32_t offset)
2350 uint32_t num_channels, i, agent_msg_type, agent_msg_len, name_len, data_size;
2351 proto_tree *subtree = NULL;
2353 switch (message_type) {
2354 case SPICE_MSG_MAIN_MIGRATE_BEGIN:
2355 case SPICE_MSG_MAIN_MIGRATE_SWITCH_HOST:
2356 case SPICE_MSG_MAIN_MIGRATE_BEGIN_SEAMLESS:
2357 proto_tree_add_item(tree, hf_migrate_dest_port, tvb, offset, 2, ENC_LITTLE_ENDIAN);
2358 offset += 2;
2359 proto_tree_add_item(tree, hf_migrate_dest_sport, tvb, offset, 2, ENC_LITTLE_ENDIAN);
2360 offset += 2;
2361 data_size = tvb_get_letohl(tvb, offset);
2362 offset += 4;
2363 proto_tree_add_item(tree, hf_raw_data, tvb, offset, data_size, ENC_NA);
2364 offset += data_size;
2365 data_size = tvb_get_letohl(tvb, offset);
2366 offset += 4;
2367 proto_tree_add_item(tree, hf_raw_data, tvb, offset, data_size, ENC_NA);
2368 offset += data_size;
2369 if (message_type == SPICE_MSG_MAIN_MIGRATE_BEGIN_SEAMLESS) {
2370 proto_tree_add_item(tree, hf_migrate_src_mig_version, tvb, offset, 4, ENC_LITTLE_ENDIAN);
2371 offset += 4;
2373 break;
2374 case SPICE_MSG_MAIN_MIGRATE_CANCEL:
2375 break;
2376 case SPICE_MSG_MAIN_INIT:
2377 proto_tree_add_item(tree, hf_session_id, tvb, offset, 4, ENC_BIG_ENDIAN);
2378 offset += 4;
2379 proto_tree_add_item(tree, hf_display_channels_hint, tvb, offset, 4, ENC_LITTLE_ENDIAN);
2380 offset += 4;
2381 dissect_supported_mouse_modes(tvb, tree, offset, 4);
2382 offset += 4;
2383 proto_tree_add_item(tree, hf_current_mouse_mode, tvb, offset, 4, ENC_LITTLE_ENDIAN);
2384 offset += 4;
2385 proto_tree_add_item(tree, hf_agent_connected, tvb, offset, 4, ENC_LITTLE_ENDIAN);
2386 offset += 4;
2387 proto_tree_add_item(tree, hf_agent_tokens, tvb, offset, 4, ENC_LITTLE_ENDIAN);
2388 offset += 4;
2389 proto_tree_add_item(tree, hf_multi_media_time, tvb, offset, 4, ENC_LITTLE_ENDIAN);
2390 offset += 4;
2391 proto_tree_add_item(tree, hf_ram_hint, tvb, offset, 4, ENC_LITTLE_ENDIAN);
2392 offset += 4;
2393 break;
2394 case SPICE_MSG_MAIN_CHANNELS_LIST:
2395 num_channels = tvb_get_letohl(tvb, offset);
2396 proto_tree_add_item(tree, hf_main_num_channels, tvb, offset, 4, ENC_LITTLE_ENDIAN);
2397 offset += 4;
2398 subtree = proto_tree_add_subtree(tree, tvb, offset, 2 * num_channels, ett_main_client, NULL, "Channel Array");
2399 for (i = 0; i < num_channels; i++ ) {
2400 proto_tree *subsubtree;
2402 subsubtree = proto_tree_add_subtree_format(subtree, tvb, offset, 2, ett_main_client, NULL, "channels[%u]: %s", i,
2403 val_to_str_const(tvb_get_uint8(tvb, offset), channel_types_vs, "Unknown"));
2405 proto_tree_add_item(subsubtree, hf_channel_type, tvb, offset, 1, ENC_LITTLE_ENDIAN);
2406 offset += 1;
2407 proto_tree_add_item(subsubtree, hf_channel_id, tvb, offset, 1, ENC_LITTLE_ENDIAN);
2408 offset += 1;
2410 break;
2411 case SPICE_MSG_MAIN_MOUSE_MODE:
2412 dissect_supported_mouse_modes(tvb, tree, offset, 2);
2413 offset += 2;
2414 proto_tree_add_item(tree, hf_current_mouse_mode_flags, tvb, offset, 2, ENC_LITTLE_ENDIAN);
2415 offset += 2;
2416 break;
2417 case SPICE_MSG_MAIN_MULTI_MEDIA_TIME:
2418 proto_tree_add_item(tree, hf_multi_media_time, tvb, offset, 4, ENC_LITTLE_ENDIAN);
2419 offset += 4;
2420 break;
2421 case SPICE_MSG_MAIN_AGENT_DISCONNECTED:
2422 proto_tree_add_item(tree, hf_error_code, tvb, offset, 4, ENC_LITTLE_ENDIAN);
2423 offset += 4;
2424 break;
2425 case SPICE_MSG_MAIN_AGENT_DATA:
2426 proto_tree_add_item(tree, hf_agent_protocol, tvb, offset, 4, ENC_LITTLE_ENDIAN);
2427 offset += 4;
2428 proto_tree_add_item(tree, hf_agent_type, tvb, offset, 4, ENC_LITTLE_ENDIAN);
2429 agent_msg_type = tvb_get_letohl(tvb, offset);
2430 offset += 4;
2431 proto_tree_add_item(tree, hf_agent_opaque, tvb, offset, 8, ENC_LITTLE_ENDIAN);
2432 offset += 8;
2433 proto_tree_add_item(tree, hf_agent_size, tvb, offset, 4, ENC_LITTLE_ENDIAN);
2434 agent_msg_len = tvb_get_letohl(tvb, offset);
2435 offset += 4;
2436 offset = dissect_spice_agent_message(tvb, pinfo, tree, agent_msg_type, msgtype_item, agent_msg_len, offset);
2437 break;
2438 case SPICE_MSG_MAIN_AGENT_TOKEN:
2439 case SPICE_MSG_MAIN_AGENT_CONNECTED_TOKENS:
2440 proto_tree_add_item(tree, hf_agent_token, tvb, offset, 4, ENC_LITTLE_ENDIAN);
2441 offset += 4;
2442 break;
2443 case SPICE_MSG_MAIN_NAME:
2444 name_len = tvb_get_letohl(tvb, offset);
2445 proto_tree_add_item(tree, hf_main_name_len, tvb, offset, 4, ENC_LITTLE_ENDIAN);
2446 offset += 4;
2447 proto_tree_add_item(tree, hf_main_name, tvb, offset, name_len, ENC_ASCII);
2448 offset += name_len;
2449 break;
2450 case SPICE_MSG_MAIN_UUID:
2451 proto_tree_add_item(tree, hf_main_uuid, tvb, offset, 16, ENC_BIG_ENDIAN);
2452 offset += 16;
2453 break;
2454 case SPICE_MSG_MAIN_MIGRATE_END:
2455 break;
2456 case SPICE_MSG_MAIN_MIGRATE_DST_SEAMLESS_ACK:
2457 break;
2458 case SPICE_MSG_MAIN_MIGRATE_DST_SEAMLESS_NACK:
2459 break;
2460 default:
2461 expert_add_info_format(pinfo, msgtype_item, &ei_spice_unknown_message, "Unknown main server message - cannot dissect");
2462 break;
2464 return offset;
2467 static uint32_t
2468 dissect_spice_main_client(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, const uint16_t message_type, proto_item* msgtype_item, uint32_t offset)
2470 proto_tree *main_tree;
2471 uint32_t agent_msg_type, agent_msg_len;
2473 switch (message_type) {
2474 case SPICE_MSGC_MAIN_MOUSE_MODE_REQUEST:
2475 proto_tree_add_item(tree, hf_current_mouse_mode_flags, tvb, offset, 2, ENC_LITTLE_ENDIAN);
2476 offset += 2;
2477 break;
2478 case SPICE_MSGC_MAIN_ATTACH_CHANNELS:
2479 break;
2480 case SPICE_MSGC_MAIN_AGENT_START:
2481 main_tree = proto_tree_add_subtree(tree, tvb, offset, 4, ett_main_client, NULL, "Client AGENT_START message");
2482 proto_tree_add_item(main_tree, hf_main_client_agent_tokens, tvb, offset, 4, ENC_LITTLE_ENDIAN);
2483 offset += 4;
2484 break;
2485 case SPICE_MSGC_MAIN_AGENT_DATA:
2486 main_tree = proto_tree_add_subtree(tree, tvb, offset, 24, ett_main_client, NULL, "Client AGENT_DATA message");
2487 proto_tree_add_item(main_tree, hf_agent_protocol, tvb, offset, 4, ENC_LITTLE_ENDIAN);
2488 offset += 4;
2489 proto_tree_add_item(main_tree, hf_agent_type, tvb, offset, 4, ENC_LITTLE_ENDIAN);
2490 agent_msg_type = tvb_get_letohl(tvb, offset);
2491 offset += 4;
2492 proto_tree_add_item(main_tree, hf_agent_opaque, tvb, offset, 8, ENC_LITTLE_ENDIAN);
2493 offset += 8;
2494 proto_tree_add_item(main_tree, hf_agent_size, tvb, offset, 4, ENC_LITTLE_ENDIAN);
2495 agent_msg_len = tvb_get_letohl(tvb, offset);
2496 offset += 4;
2497 offset = dissect_spice_agent_message(tvb, pinfo, main_tree, agent_msg_type, msgtype_item, agent_msg_len, offset);
2498 break;
2499 default:
2500 expert_add_info_format(pinfo, msgtype_item, &ei_spice_unknown_message, "Unknown main client message - cannot dissect");
2501 break;
2503 return offset;
2506 static int
2507 dissect_spice_keyboard_modifiers(tvbuff_t *tvb, proto_tree *tree, uint32_t offset)
2509 proto_item *ti;
2510 proto_tree *subtree;
2512 ti = proto_tree_add_item(tree, hf_keyboard_modifiers, tvb, offset, 2, ENC_LITTLE_ENDIAN);
2513 subtree = proto_item_add_subtree(ti, ett_link_caps);
2515 proto_tree_add_item(subtree, hf_keyboard_modifier_scroll_lock, tvb, offset, 2, ENC_LITTLE_ENDIAN);
2516 proto_tree_add_item(subtree, hf_keyboard_modifier_num_lock, tvb, offset, 2, ENC_LITTLE_ENDIAN);
2517 proto_tree_add_item(subtree, hf_keyboard_modifier_caps_lock, tvb, offset, 2, ENC_LITTLE_ENDIAN);
2518 return 2;
2521 static int
2522 dissect_buttons_state(tvbuff_t *tvb, proto_tree *tree, uint32_t offset)
2524 proto_item* ti;
2525 proto_tree *subtree;
2527 ti = proto_tree_add_item(tree, hf_buttons_state, tvb, offset, 2, ENC_LITTLE_ENDIAN);
2528 subtree = proto_item_add_subtree(ti, ett_inputs_client);
2530 static int *const hf_buttons_mask[] = {
2531 &hf_button_mask_left,
2532 &hf_button_mask_middle,
2533 &hf_button_mask_right,
2534 &hf_button_mask_reserved_bits,
2535 NULL
2538 proto_tree_add_bitmask_list(subtree, tvb, offset, 2, hf_buttons_mask, ENC_LITTLE_ENDIAN);
2540 return 2;
2543 static uint32_t
2544 dissect_spice_inputs_client(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, const uint16_t message_type, proto_item* msgtype_item, uint32_t offset)
2546 proto_tree *inputs_tree;
2548 switch (message_type) {
2549 case SPICE_MSGC_INPUTS_KEY_DOWN:
2550 inputs_tree = proto_tree_add_subtree(tree, tvb, offset, 4, ett_inputs_client, NULL, "Client KEY_DOWN message");
2551 proto_tree_add_item(inputs_tree, hf_keyboard_code, tvb, offset, 4, ENC_LITTLE_ENDIAN);
2552 offset += 4;
2553 break;
2554 case SPICE_MSGC_INPUTS_KEY_UP:
2555 inputs_tree = proto_tree_add_subtree(tree, tvb, offset, 4, ett_inputs_client, NULL, "Client KEY_UP message");
2556 proto_tree_add_item(inputs_tree, hf_keyboard_code, tvb, offset, 4, ENC_LITTLE_ENDIAN);
2557 offset += 4;
2558 break;
2559 case SPICE_MSGC_INPUTS_KEY_MODIFIERS:
2560 offset += dissect_spice_keyboard_modifiers(tvb, tree, offset);
2561 break;
2562 case SPICE_MSGC_INPUTS_MOUSE_POSITION:
2563 inputs_tree = proto_tree_add_subtree(tree, tvb, offset, sizeof(point32_t) + 3, ett_inputs_client, NULL, "Client MOUSE_POSITION message");
2564 dissect_POINT32(tvb, inputs_tree, offset);
2565 offset += (int)sizeof(point32_t);
2566 offset += dissect_buttons_state(tvb, inputs_tree, offset);
2567 proto_tree_add_item(inputs_tree, hf_mouse_display_id, tvb, offset, 1, ENC_LITTLE_ENDIAN);
2568 offset += 1;
2569 break;
2570 case SPICE_MSGC_INPUTS_MOUSE_MOTION:
2571 inputs_tree = proto_tree_add_subtree(tree, tvb, offset, sizeof(point32_t) + 2, ett_inputs_client, NULL, "Client MOUSE_MOTION message");
2572 dissect_POINT32(tvb, inputs_tree, offset);
2573 offset += (int)sizeof(point32_t);
2574 offset += dissect_buttons_state(tvb, inputs_tree, offset);
2575 break;
2576 case SPICE_MSGC_INPUTS_MOUSE_PRESS:
2577 inputs_tree = proto_tree_add_subtree(tree, tvb, offset, 3, ett_inputs_client, NULL, "Client MOUSE_PRESS message");
2578 proto_tree_add_item(inputs_tree, hf_button, tvb, offset, 1, ENC_LITTLE_ENDIAN);
2579 offset += 1;
2580 offset += dissect_buttons_state(tvb, inputs_tree, offset);
2581 break;
2582 case SPICE_MSGC_INPUTS_MOUSE_RELEASE:
2583 inputs_tree = proto_tree_add_subtree(tree, tvb, offset, 3, ett_inputs_client, NULL, "Client MOUSE_RELEASE message");
2584 proto_tree_add_item(inputs_tree, hf_button, tvb, offset, 1, ENC_LITTLE_ENDIAN);
2585 offset += 1;
2586 offset += dissect_buttons_state(tvb, inputs_tree, offset);
2587 break;
2588 default:
2589 expert_add_info_format(pinfo, msgtype_item, &ei_spice_unknown_message, "Unknown inputs client message - cannot dissect");
2590 break;
2592 return offset;
2595 static uint32_t
2596 dissect_spice_inputs_server(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, const uint16_t message_type, proto_item* msgtype_item, uint32_t offset)
2598 switch (message_type) {
2599 case SPICE_MSG_INPUTS_INIT:
2600 offset += dissect_spice_keyboard_modifiers(tvb, tree, offset);
2601 break;
2602 case SPICE_MSG_INPUTS_KEY_MODIFIERS:
2603 offset += dissect_spice_keyboard_modifiers(tvb, tree, offset);
2604 break;
2605 case SPICE_MSG_INPUTS_MOUSE_MOTION_ACK:
2606 proto_tree_add_item(tree, hf_spice_server_inputs_mouse_motion_ack_message, tvb, offset, 0, ENC_NA);
2607 break;
2608 default:
2609 expert_add_info_format(pinfo, msgtype_item, &ei_spice_unknown_message, "Unknown inputs server message - cannot dissect");
2610 break;
2612 return offset;
2615 static uint32_t
2616 dissect_spice_tunnel_client(packet_info *pinfo, const uint16_t message_type, proto_item* msgtype_item, uint32_t offset)
2618 /* TODO: Not implemented yet */
2619 switch (message_type) {
2620 default:
2621 expert_add_info_format(pinfo, msgtype_item, &ei_spice_unknown_message, "Unknown message - cannot dissect");
2622 break;
2624 return offset;
2627 static uint32_t
2628 dissect_spice_tunnel_server(packet_info *pinfo, const uint16_t message_type, proto_item* msgtype_item, uint32_t offset)
2630 /* TODO: Not implemented yet */
2631 switch (message_type) {
2632 default:
2633 expert_add_info_format(pinfo, msgtype_item, &ei_spice_unknown_message, "Unknown message - cannot dissect");
2634 break;
2636 return offset;
2639 static uint32_t
2640 dissect_spice_smartcard_client(packet_info *pinfo, const uint16_t message_type, proto_item* msgtype_item, uint32_t offset)
2642 /* TODO: Not implemented yet */
2643 switch (message_type) {
2644 default:
2645 expert_add_info_format(pinfo, msgtype_item, &ei_spice_unknown_message, "Unknown message - cannot dissect");
2646 break;
2648 return offset;
2651 static uint32_t
2652 dissect_spice_smartcard_server(packet_info *pinfo, const uint16_t message_type, proto_item* msgtype_item, uint32_t offset)
2654 /* TODO: Not implemented yet */
2655 switch (message_type) {
2656 default:
2657 expert_add_info_format(pinfo, msgtype_item, &ei_spice_unknown_message, "Unknown message - cannot dissect");
2658 break;
2660 return offset;
2663 static uint32_t
2664 dissect_spice_usbredir_client(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, const uint16_t message_type, proto_item* msgtype_item, uint32_t message_size, uint32_t offset)
2666 switch (message_type) {
2667 case SPICE_MSGC_SPICEVMC_DATA:
2668 proto_tree_add_item(tree, hf_raw_data, tvb, offset, message_size, ENC_NA);
2669 offset += message_size;
2670 break;
2671 default:
2672 expert_add_info_format(pinfo, msgtype_item, &ei_spice_unknown_message, "Unknown message - cannot dissect");
2673 break;
2675 return offset;
2678 static uint32_t
2679 dissect_spice_usbredir_server(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, const uint16_t message_type, proto_item* msgtype_item, uint32_t message_size, uint32_t offset)
2681 switch (message_type) {
2682 case SPICE_MSG_SPICEVMC_DATA:
2683 proto_tree_add_item(tree, hf_raw_data, tvb, offset, message_size, ENC_NA);
2684 offset += message_size;
2685 break;
2686 default:
2687 expert_add_info_format(pinfo, msgtype_item, &ei_spice_unknown_message, "Unknown message - cannot dissect");
2688 break;
2690 return offset;
2693 static uint32_t
2694 dissect_spice_port_client(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, const uint16_t message_type, proto_item* msgtype_item, uint32_t message_size, uint32_t offset)
2696 switch (message_type) {
2697 case SPICE_MSGC_SPICEVMC_DATA:
2698 proto_tree_add_item(tree, hf_raw_data, tvb, offset, message_size, ENC_NA);
2699 offset += message_size;
2700 break;
2701 case SPICE_MSGC_PORT_EVENT:
2702 proto_tree_add_item(tree, hf_port_event, tvb, offset, 1, ENC_LITTLE_ENDIAN);
2703 offset += 1;
2704 break;
2705 default:
2706 expert_add_info_format(pinfo, msgtype_item, &ei_spice_unknown_message, "Unknown message - cannot dissect");
2707 break;
2709 return offset;
2712 static uint32_t
2713 dissect_spice_port_server(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, const uint16_t message_type, proto_item* msgtype_item, uint32_t message_size, uint32_t offset)
2715 switch (message_type) {
2716 case SPICE_MSG_SPICEVMC_DATA:
2717 proto_tree_add_item(tree, hf_raw_data, tvb, offset, message_size, ENC_NA);
2718 offset += message_size;
2719 break;
2720 case SPICE_MSG_PORT_INIT:
2722 uint32_t size = tvb_get_letohl(tvb, offset);
2723 proto_tree_add_item(tree, hf_spice_name_length, tvb, offset, 4, ENC_LITTLE_ENDIAN);
2724 offset += 4;
2725 proto_tree_add_item(tree, hf_main_name, tvb, offset, size, ENC_ASCII);
2726 offset += size;
2727 proto_tree_add_item(tree, hf_port_opened, tvb, offset, 1, ENC_LITTLE_ENDIAN);
2728 offset += 1;
2730 break;
2731 case SPICE_MSG_PORT_EVENT:
2732 proto_tree_add_item(tree, hf_port_event, tvb, offset, 1, ENC_LITTLE_ENDIAN);
2733 offset += 1;
2734 break;
2735 default:
2736 expert_add_info_format(pinfo, msgtype_item, &ei_spice_unknown_message, "Unknown message - cannot dissect");
2737 break;
2739 return offset;
2743 static uint32_t
2744 dissect_spice_data_server_pdu(tvbuff_t *tvb, proto_tree *tree, packet_info *pinfo, spice_conversation_t *spice_info, uint32_t offset, const uint32_t total_message_size)
2746 proto_item *ti = NULL, *msg_ti=NULL, *msgtype_ti=NULL;
2747 proto_tree *data_header_tree, *message_tree;
2748 uint16_t message_type;
2749 uint32_t message_size, sublist_size, old_offset;
2750 uint32_t header_size;
2752 if (spice_info->client_mini_header && spice_info->server_mini_header) {
2753 header_size = sizeof_SpiceMiniDataHeader;
2754 message_type = tvb_get_letohs(tvb, offset);
2755 message_size = tvb_get_letohl(tvb, offset +2);
2756 message_tree = proto_tree_add_subtree_format(tree, tvb, offset, 0,
2757 ett_message, &msg_ti, "%s (%d bytes)",
2758 get_message_type_string(message_type, spice_info, false),
2759 message_size + header_size);
2760 ti = proto_tree_add_item(message_tree, hf_data, tvb, offset, header_size, ENC_NA);
2761 data_header_tree = proto_item_add_subtree(ti, ett_data);
2762 dissect_spice_mini_data_header(tvb, data_header_tree, spice_info, false, message_type, offset);
2763 proto_item_set_len(msg_ti, message_size + header_size);
2764 } else {
2765 header_size = sizeof_SpiceDataHeader;
2766 message_type = tvb_get_letohs(tvb, offset + 8);
2767 message_size = tvb_get_letohl(tvb, offset + 10);
2768 message_tree = proto_tree_add_subtree_format(tree, tvb, offset, 0,
2769 ett_message, &msg_ti, "%s (%d bytes)",
2770 get_message_type_string(message_type, spice_info, false),
2771 message_size + header_size);
2772 ti = proto_tree_add_item(message_tree, hf_data, tvb, offset, header_size, ENC_NA);
2773 data_header_tree = proto_item_add_subtree(ti, ett_data);
2774 dissect_spice_data_header(tvb, data_header_tree, spice_info, false, message_type, &msgtype_ti, &sublist_size, offset);
2776 proto_item_set_len(msg_ti, message_size + header_size);
2777 offset += header_size;
2778 old_offset = offset;
2780 col_append_sep_str(pinfo->cinfo, COL_INFO, ", ", get_message_type_string(message_type, spice_info, false));
2781 if (message_type < SPICE_FIRST_AVAIL_MESSAGE) { /* this is a common message */
2782 offset = dissect_spice_common_server_messages(tvb, pinfo, message_tree, message_type, msgtype_ti, offset, total_message_size - header_size);
2783 return offset;
2786 switch (spice_info->channel_type) {
2787 case SPICE_CHANNEL_PLAYBACK:
2788 offset = dissect_spice_playback_server(tvb, pinfo, message_tree, message_type, msgtype_ti, message_size, spice_info, offset);
2789 break;
2790 case SPICE_CHANNEL_RECORD:
2791 offset = dissect_spice_record_server(tvb, pinfo, message_tree, message_type, msgtype_ti, offset);
2792 break;
2793 case SPICE_CHANNEL_MAIN:
2794 offset = dissect_spice_main_server(tvb, pinfo, message_tree, message_type, msgtype_ti, offset);
2795 break;
2796 case SPICE_CHANNEL_CURSOR:
2797 offset = dissect_spice_cursor_server(tvb, pinfo, message_tree, message_type, msgtype_ti, offset);
2798 break;
2799 case SPICE_CHANNEL_DISPLAY:
2800 offset = dissect_spice_display_server(tvb, message_tree, pinfo, message_type, msgtype_ti, offset);
2801 break;
2802 case SPICE_CHANNEL_INPUTS:
2803 offset = dissect_spice_inputs_server(tvb, pinfo, message_tree, message_type, msgtype_ti, offset);
2804 break;
2805 case SPICE_CHANNEL_TUNNEL:
2806 offset = dissect_spice_tunnel_server(pinfo, message_type, msgtype_ti, offset);
2807 break;
2808 case SPICE_CHANNEL_SMARTCARD:
2809 offset = dissect_spice_smartcard_server(pinfo, message_type, msgtype_ti, offset);
2810 break;
2811 case SPICE_CHANNEL_USBREDIR:
2812 offset = dissect_spice_usbredir_server(tvb, pinfo, message_tree, message_type, msgtype_ti, message_size, offset);
2813 break;
2814 case SPICE_CHANNEL_PORT:
2815 offset = dissect_spice_port_server(tvb, pinfo, message_tree, message_type, msgtype_ti, message_size, offset);
2816 break;
2817 default:
2818 expert_add_info_format(pinfo, msgtype_ti, &ei_spice_unknown_message, "Unknown server PDU - cannot dissect");
2821 if ((offset - old_offset) != message_size) {
2822 proto_tree_add_expert_format(tree, pinfo, &ei_spice_not_dissected, tvb, offset, -1,
2823 "message type %s (%u) not fully dissected", get_message_type_string(message_type, spice_info, false), message_type);
2824 offset = old_offset + message_size;
2827 return offset;
2830 static uint32_t
2831 dissect_spice_data_client_pdu(tvbuff_t *tvb, proto_tree *tree, packet_info *pinfo, spice_conversation_t *spice_info, uint32_t offset)
2833 proto_item *ti = NULL, *msgtype_ti = NULL;
2834 proto_tree *data_header_tree;
2835 uint16_t message_type;
2836 uint32_t message_size = 0, sublist_size;
2837 uint32_t header_size;
2839 if (spice_info->client_mini_header && spice_info->server_mini_header) {
2840 header_size = sizeof_SpiceMiniDataHeader;
2841 ti = proto_tree_add_item(tree, hf_data, tvb, offset, header_size, ENC_NA);
2842 data_header_tree = proto_item_add_subtree(ti, ett_data);
2843 message_type = tvb_get_letohs(tvb, offset);
2844 message_size = tvb_get_letohl(tvb, offset + 2);
2845 dissect_spice_mini_data_header(tvb, data_header_tree, spice_info, true, message_type, offset);
2846 } else {
2847 header_size = sizeof_SpiceDataHeader;
2848 ti = proto_tree_add_item(tree, hf_data, tvb, offset, header_size, ENC_NA);
2849 data_header_tree = proto_item_add_subtree(ti, ett_data);
2850 message_type = tvb_get_letohs(tvb, offset + 8);
2851 message_size = tvb_get_letohl(tvb, offset + 10);
2852 dissect_spice_data_header(tvb, data_header_tree, spice_info, true, message_type, &msgtype_ti, &sublist_size, offset);
2854 col_append_sep_str(pinfo->cinfo, COL_INFO, ", ", get_message_type_string(message_type, spice_info, true));
2855 offset += header_size;
2856 /* TODO: deal with sub-messages list first. As implementation does not uses sub-messages list yet, */
2857 /* it cannot be implemented in the dissector yet. */
2859 if (message_type < SPICE_FIRST_AVAIL_MESSAGE) { /* this is a common message */
2860 return dissect_spice_common_client_messages(tvb, pinfo, tree, message_type, msgtype_ti, offset);
2863 switch (spice_info->channel_type) {
2864 case SPICE_CHANNEL_PLAYBACK:
2865 break;
2866 case SPICE_CHANNEL_RECORD:
2867 offset = dissect_spice_record_client(tvb, pinfo, tree, message_type, msgtype_ti, offset);
2868 break;
2869 case SPICE_CHANNEL_MAIN:
2870 offset = dissect_spice_main_client(tvb, pinfo, tree, message_type, msgtype_ti, offset);
2871 break;
2872 case SPICE_CHANNEL_DISPLAY:
2873 offset = dissect_spice_display_client(tvb, pinfo, tree, message_type, msgtype_ti, offset);
2874 break;
2875 case SPICE_CHANNEL_INPUTS:
2876 offset = dissect_spice_inputs_client(tvb, pinfo, tree, message_type, msgtype_ti, offset);
2877 break;
2878 case SPICE_CHANNEL_TUNNEL:
2879 offset = dissect_spice_tunnel_client(pinfo, message_type, msgtype_ti, offset);
2880 break;
2881 case SPICE_CHANNEL_SMARTCARD:
2882 offset = dissect_spice_smartcard_client(pinfo, message_type, msgtype_ti, offset);
2883 break;
2884 case SPICE_CHANNEL_USBREDIR:
2885 offset = dissect_spice_usbredir_client(tvb, pinfo, tree, message_type, msgtype_ti, message_size, offset);
2886 break;
2887 case SPICE_CHANNEL_PORT:
2888 offset = dissect_spice_port_client(tvb, pinfo, tree, message_type, msgtype_ti, message_size, offset);
2889 break;
2890 default:
2891 expert_add_info_format(pinfo, msgtype_ti, &ei_spice_unknown_message, "Unknown client PDU - cannot dissect");
2892 break;
2895 return offset;
2898 static void
2899 dissect_spice_link_common_header(tvbuff_t *tvb, proto_tree *tree)
2901 if (tree) {
2902 /* dissect common header */
2903 proto_tree_add_item(tree, hf_spice_magic, tvb, 0, 4, ENC_ASCII);
2904 proto_tree_add_item(tree, hf_major_version, tvb, 4, 4, ENC_LITTLE_ENDIAN);
2905 proto_tree_add_item(tree, hf_minor_version, tvb, 8, 4, ENC_LITTLE_ENDIAN);
2906 proto_tree_add_item(tree, hf_message_size, tvb, 12, 4, ENC_LITTLE_ENDIAN);
2910 static void
2911 dissect_spice_common_capabilities(tvbuff_t *tvb, packet_info* pinfo, proto_tree *tree, uint32_t offset, const unsigned caps_len, spice_conversation_t *spice_info, bool is_client)
2913 /* TODO: save common and per-channel capabilities in spice_info ? */
2914 unsigned i;
2915 uint32_t val;
2916 static int * const caps[] = {
2917 &hf_common_cap_auth_select,
2918 &hf_common_cap_auth_spice,
2919 &hf_common_cap_auth_sasl,
2920 &hf_common_cap_mini_header,
2921 NULL
2924 for(i = 0; i < caps_len; i++) {
2925 val = tvb_get_letohl(tvb, offset);
2926 switch (i) {
2927 case 0:
2928 if (is_client) {
2929 spice_info->client_auth = val;
2930 } else {
2931 spice_info->server_auth = val;
2934 proto_tree_add_bitmask_list(tree, tvb, offset, 4, caps, ENC_LITTLE_ENDIAN);
2935 if (val & SPICE_COMMON_CAP_MINI_HEADER_MASK) {
2936 if (is_client) {
2937 spice_info->client_mini_header = true;
2938 } else {
2939 spice_info->server_mini_header = true;
2942 offset += 4;
2943 break;
2944 default:
2945 proto_tree_add_expert(tree, pinfo, &ei_spice_common_cap_unknown, tvb, offset, 4);
2946 offset += 4;
2947 break;
2952 static void
2953 dissect_spice_link_capabilities(tvbuff_t *tvb, packet_info* pinfo, proto_tree *tree, uint32_t offset, const unsigned caps_len, const spice_conversation_t *spice_info)
2955 /* TODO: save common and per-channel capabilities in spice_info ? */
2956 unsigned i;
2958 for(i = 0; i < caps_len; i++) {
2959 switch (spice_info->channel_type) {
2960 case SPICE_CHANNEL_PLAYBACK:
2962 static int * const playback_cap[] = {
2963 &hf_playback_cap_celt_0_5_1,
2964 &hf_playback_cap_volume,
2965 &hf_playback_cap_latency,
2966 &hf_playback_cap_opus,
2967 NULL
2970 if (i != 0)
2971 return;
2973 proto_tree_add_bitmask_list(tree, tvb, offset, 4, playback_cap, ENC_LITTLE_ENDIAN);
2975 break;
2976 case SPICE_CHANNEL_MAIN:
2978 static int * const main_cap[] = {
2979 &hf_main_cap_semi_migrate,
2980 &hf_main_cap_vm_name_uuid, /*Note: only relevant for client. TODO: dissect only for client */
2981 &hf_main_cap_agent_connected_tokens,
2982 &hf_main_cap_seamless_migrate,
2983 NULL
2986 if (i != 0)
2987 return;
2989 proto_tree_add_bitmask_list(tree, tvb, offset, 4, main_cap, ENC_LITTLE_ENDIAN);
2991 break;
2992 case SPICE_CHANNEL_DISPLAY:
2994 static int * const display_cap[] = {
2995 &hf_display_cap_sized_stream,
2996 &hf_display_cap_monitors_config,
2997 &hf_display_cap_composite,
2998 &hf_display_cap_a8_surface,
2999 &hf_display_cap_stream_report,
3000 &hf_display_cap_lz4_compression,
3001 &hf_display_cap_pref_compression,
3002 &hf_display_cap_gl_scanout,
3003 &hf_display_cap_multi_codec,
3004 &hf_display_cap_codec_mjpeg,
3005 &hf_display_cap_codec_vp8,
3006 &hf_display_cap_codec_h264,
3007 &hf_display_cap_pref_video_codec_type,
3008 &hf_display_cap_codec_vp9,
3009 &hf_display_cap_codec_h265,
3010 NULL
3013 if (i != 0)
3014 return;
3016 proto_tree_add_bitmask_list(tree, tvb, offset, 4, display_cap, ENC_LITTLE_ENDIAN);
3018 break;
3019 case SPICE_CHANNEL_INPUTS:
3020 proto_tree_add_item(tree, hf_inputs_cap, tvb, offset, 4, ENC_LITTLE_ENDIAN);
3021 break;
3022 case SPICE_CHANNEL_CURSOR:
3023 proto_tree_add_item(tree, hf_cursor_cap, tvb, offset, 4, ENC_LITTLE_ENDIAN);
3024 break;
3025 case SPICE_CHANNEL_RECORD:
3027 static int * const record_cap[] = {
3028 &hf_record_cap_celt,
3029 &hf_record_cap_volume,
3030 &hf_record_cap_opus,
3031 NULL
3034 if (i != 0)
3035 return;
3037 proto_tree_add_bitmask_list(tree, tvb, offset, 4, record_cap, ENC_LITTLE_ENDIAN);
3039 break;
3040 default:
3041 proto_tree_add_expert(tree, pinfo, &ei_spice_unknown_channel, tvb, offset, -1);
3042 return;
3044 offset += 4;
3048 static void
3049 dissect_spice_link_client_pdu(tvbuff_t *tvb, packet_info* pinfo, proto_tree *tree, spice_conversation_t *spice_info)
3051 uint32_t offset;
3052 uint32_t common_caps_len, channel_caps_len;
3053 proto_item *ti = NULL;
3054 proto_tree *link_header_tree = NULL;
3055 proto_tree *caps_tree = NULL;
3057 if (tree) {
3058 ti = proto_tree_add_item(tree, hf_link_client, tvb, 0, sizeof_SpiceLinkHeader, ENC_NA);
3059 link_header_tree = proto_item_add_subtree(ti, ett_link_client);
3061 dissect_spice_link_common_header(tvb, link_header_tree);
3063 offset = sizeof_SpiceLinkHeader;
3065 if (spice_info->channel_type == SPICE_CHANNEL_NONE) {
3066 spice_info->channel_type = tvb_get_uint8(tvb, offset + 4);
3068 common_caps_len = tvb_get_letohl(tvb, offset + 6);
3069 channel_caps_len = tvb_get_letohl(tvb, offset + 10);
3070 proto_tree_add_item(tree, hf_conn_id, tvb, offset, 4, ENC_LITTLE_ENDIAN);
3071 offset += 4;
3072 proto_tree_add_item(tree, hf_channel_type, tvb, offset, 1, ENC_NA);
3073 offset += 1;
3074 proto_tree_add_item(tree, hf_channel_id, tvb, offset, 1, ENC_NA);
3075 offset += 1;
3076 proto_tree_add_item(tree, hf_num_common_caps, tvb, offset, 4, ENC_LITTLE_ENDIAN);
3077 offset += 4;
3078 proto_tree_add_item(tree, hf_num_channel_caps, tvb, offset, 4, ENC_LITTLE_ENDIAN);
3079 offset += 4;
3080 proto_tree_add_item(tree, hf_caps_offset, tvb, offset, 4, ENC_LITTLE_ENDIAN);
3081 offset += 4;
3083 if (common_caps_len > 0) {
3084 caps_tree = proto_tree_add_subtree_format(tree, tvb, offset, common_caps_len * 4,
3085 ett_link_caps, NULL, "Client Common Capabilities (%d bytes)",
3086 common_caps_len * 4); /* caps_len multiplied by 4 as length is in UINT32 units */
3087 dissect_spice_common_capabilities(tvb, pinfo, caps_tree, offset, common_caps_len, spice_info, true);
3088 offset += (common_caps_len * 4);
3090 if (channel_caps_len > 0) {
3091 caps_tree = proto_tree_add_subtree_format(tree, tvb, offset, channel_caps_len * 4,
3092 ett_link_caps, NULL, "Client Channel-specific Capabilities (%d bytes)",
3093 channel_caps_len * 4); /* caps_len multiplied by 4 as length is in UINT32 units */
3094 dissect_spice_link_capabilities(tvb, pinfo, caps_tree, offset, channel_caps_len, spice_info);
3098 static void
3099 dissect_spice_link_server_pdu(tvbuff_t *tvb, packet_info* pinfo, proto_tree *tree, spice_conversation_t *spice_info)
3101 uint32_t offset;
3102 uint32_t common_caps_len, channel_caps_len;
3103 proto_item *ti = NULL;
3104 proto_tree *link_tree = NULL;
3105 proto_tree *caps_tree = NULL;
3107 if (tree) {
3108 ti = proto_tree_add_item(tree, hf_link_server, tvb, 0, sizeof_SpiceLinkHeader, ENC_NA);
3109 link_tree = proto_item_add_subtree(ti, ett_link_server);
3111 dissect_spice_link_common_header(tvb, link_tree);
3114 offset = sizeof_SpiceLinkHeader;
3116 if (tree) {
3117 proto_tree_add_item(tree, hf_error_code, tvb, offset, 4, ENC_LITTLE_ENDIAN);
3118 proto_tree_add_bytes_format(tree, hf_spice_x509_subjectpublickeyinfo, tvb, offset + 4, SPICE_TICKET_PUBKEY_BYTES, NULL, "X.509 SubjectPublicKeyInfo (ASN.1)");
3119 proto_tree_add_item(tree, hf_num_common_caps, tvb, offset + 4 + SPICE_TICKET_PUBKEY_BYTES, 4, ENC_LITTLE_ENDIAN);
3120 proto_tree_add_item(tree, hf_num_channel_caps, tvb, offset + 8 + SPICE_TICKET_PUBKEY_BYTES, 4, ENC_LITTLE_ENDIAN);
3122 proto_tree_add_item(tree, hf_caps_offset, tvb, offset + 12 + SPICE_TICKET_PUBKEY_BYTES, 4, ENC_LITTLE_ENDIAN);
3125 common_caps_len = tvb_get_letohl(tvb, offset + 4 + SPICE_TICKET_PUBKEY_BYTES);
3126 channel_caps_len = tvb_get_letohl(tvb, offset + 8 + SPICE_TICKET_PUBKEY_BYTES);
3127 offset += (int)sizeof_SpiceLinkHeader + SPICE_TICKET_PUBKEY_BYTES;
3129 if (common_caps_len > 0) {
3130 caps_tree = proto_tree_add_subtree_format(tree, tvb, offset, common_caps_len * 4,
3131 ett_link_caps, NULL, "Common Capabilities (%d bytes)",
3132 common_caps_len * 4); /* caps_len multiplied by 4 as length is in UINT32 units */
3133 dissect_spice_common_capabilities(tvb, pinfo, caps_tree, offset, common_caps_len, spice_info, false);
3134 offset += (common_caps_len * 4);
3136 if (channel_caps_len > 0) {
3137 caps_tree = proto_tree_add_subtree_format(tree, tvb, offset, channel_caps_len * 4,
3138 ett_link_caps, NULL, "Channel Capabilities (%d bytes)",
3139 channel_caps_len * 4); /* caps_len multiplied by 4 as length is in UINT32 units */
3140 dissect_spice_link_capabilities(tvb, pinfo, caps_tree, offset, channel_caps_len, spice_info);
3144 static int
3145 dissect_spice(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
3148 conversation_t *conversation;
3149 spice_conversation_t *spice_info;
3150 spice_packet_t *per_packet_info;
3151 uint32_t avail;
3152 uint32_t pdu_len = 0;
3153 uint32_t offset;
3154 proto_item *ti, *auth_item;
3155 proto_tree *spice_tree;
3156 bool client_sasl_list = false;
3157 uint8_t sasl_auth_result;
3159 conversation = find_or_create_conversation(pinfo);
3161 spice_info = (spice_conversation_t*)conversation_get_proto_data(conversation, proto_spice);
3162 if (!spice_info) {
3163 spice_info = wmem_new0(wmem_file_scope(), spice_conversation_t);
3164 spice_info->destport = pinfo->destport;
3165 spice_info->channel_type = SPICE_CHANNEL_NONE;
3166 spice_info->next_state = SPICE_LINK_CLIENT;
3167 spice_info->client_auth = 0;
3168 spice_info->server_auth = 0;
3169 spice_info->playback_mode = SPICE_AUDIO_DATA_MODE_INVALID;
3170 spice_info->client_mini_header = false;
3171 spice_info->server_mini_header = false;
3172 conversation_add_proto_data(conversation, proto_spice, spice_info);
3173 conversation_set_dissector(conversation, spice_handle);
3176 per_packet_info = (spice_packet_t *)p_get_proto_data(wmem_file_scope(), pinfo, proto_spice, 0);
3177 if (!per_packet_info) {
3178 per_packet_info = wmem_new(wmem_file_scope(), spice_packet_t);
3179 per_packet_info->state = spice_info->next_state;
3180 p_add_proto_data(wmem_file_scope(), pinfo, proto_spice, 0, per_packet_info);
3183 col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "Spice %s", val_to_str_const(spice_info->channel_type,channel_types_vs, "Unknown"));
3184 col_clear(pinfo->cinfo, COL_INFO);
3185 col_set_str(pinfo->cinfo, COL_INFO, val_to_str_const(per_packet_info->state, state_name_vs, ""));
3187 ti = proto_tree_add_item(tree, proto_spice, tvb, 0, -1, ENC_NA);
3188 spice_tree = proto_item_add_subtree(ti, ett_spice);
3190 switch (per_packet_info->state) {
3191 case SPICE_LINK_CLIENT:
3192 avail = tvb_reported_length(tvb);
3193 pdu_len = sizeof_SpiceLinkHeader;
3194 GET_PDU_FROM_OFFSET(0)
3195 pdu_len = tvb_get_letohl(tvb, 12) + sizeof_SpiceLinkHeader;
3196 GET_PDU_FROM_OFFSET(0)
3197 proto_item_set_len(ti, pdu_len);
3198 dissect_spice_link_client_pdu(tvb, pinfo, spice_tree, spice_info);
3199 col_add_fstr(pinfo->cinfo, COL_PROTOCOL,
3200 "Spice %s", val_to_str_const(spice_info->channel_type,channel_types_vs, "Unknown"));
3201 spice_info->next_state = SPICE_LINK_SERVER;
3202 return pdu_len;
3203 case SPICE_LINK_SERVER:
3204 avail = tvb_reported_length(tvb);
3205 pdu_len = sizeof_SpiceLinkHeader;
3206 GET_PDU_FROM_OFFSET(0)
3207 pdu_len = tvb_get_letohl(tvb, 12) + sizeof_SpiceLinkHeader;
3208 GET_PDU_FROM_OFFSET(0)
3209 proto_item_set_len(ti, pdu_len);
3210 dissect_spice_link_server_pdu(tvb, pinfo, spice_tree, spice_info);
3211 if (!(spice_info->server_auth & SPICE_COMMON_CAP_PROTOCOL_AUTH_SELECTION_MASK) ||
3212 !(spice_info->client_auth & SPICE_COMMON_CAP_PROTOCOL_AUTH_SELECTION_MASK)) {
3213 /* Server or clients support spice ticket auth only */
3214 spice_info->next_state = SPICE_TICKET_CLIENT;
3215 } else { /* Protocol selection between client and server */
3216 spice_info->next_state = SPICE_CLIENT_AUTH_SELECT;
3218 return pdu_len;
3219 case SPICE_CLIENT_AUTH_SELECT:
3220 if (spice_info->destport != pinfo->destport) { /* ignore anything from the server, wait for data from client */
3221 expert_add_info(pinfo, ti, &ei_spice_expected_from_client);
3222 break;
3225 avail = tvb_reported_length(tvb);
3226 pdu_len = 4;
3227 GET_PDU_FROM_OFFSET(0)
3228 proto_item_set_len(ti, 4);
3230 auth_item = proto_tree_add_item(spice_tree, hf_auth_select_client, tvb, 0, 4, ENC_LITTLE_ENDIAN);
3231 spice_info->auth_selected = tvb_get_letohl(tvb, 0);
3232 switch (spice_info->auth_selected) {
3233 case SPICE_COMMON_CAP_AUTH_SPICE:
3234 spice_info->next_state = SPICE_TICKET_CLIENT;
3235 break;
3236 case SPICE_COMMON_CAP_AUTH_SASL:
3237 spice_info->next_state = SPICE_SASL_INIT_FROM_SERVER;
3238 break;
3239 default:
3240 expert_add_info(pinfo, auth_item, &ei_spice_auth_unknown);
3241 break;
3243 return 4;
3244 case SPICE_SASL_INIT_FROM_SERVER:
3245 offset = 0;
3246 avail = tvb_reported_length_remaining(tvb, offset);
3247 pdu_len = 4;
3248 GET_PDU_FROM_OFFSET(offset)
3249 pdu_len = tvb_get_letohl(tvb, offset); /* the length of the following messages */
3250 proto_item_set_len(ti, 4);
3251 proto_tree_add_item(spice_tree, hf_spice_sasl_message_length, tvb, offset, 4, ENC_LITTLE_ENDIAN);
3252 pdu_len += 4;
3253 GET_PDU_FROM_OFFSET(offset)
3254 proto_item_set_len(ti, pdu_len);
3255 proto_tree_add_uint(spice_tree, hf_spice_supported_authentication_mechanisms_list_length, tvb, offset, 4, pdu_len - 4);
3256 offset += 4;
3257 proto_tree_add_item(spice_tree, hf_spice_supported_authentication_mechanisms_list, tvb, offset, pdu_len - 4, ENC_NA|ENC_ASCII);
3258 offset += (pdu_len - 4);
3259 spice_info->next_state = SPICE_SASL_START_TO_SERVER;
3260 return offset;
3261 case SPICE_SASL_START_TO_SERVER:
3262 offset = 0;
3263 while (offset < tvb_reported_length(tvb)) {
3264 avail = tvb_reported_length_remaining(tvb, offset);
3265 pdu_len = 4;
3266 GET_PDU_FROM_OFFSET(offset)
3267 pdu_len = tvb_get_letohl(tvb, offset); /* the length of the following messages */
3268 proto_item_set_len(ti, 4);
3269 proto_tree_add_item(spice_tree, hf_spice_sasl_message_length, tvb, offset, 4, ENC_LITTLE_ENDIAN);
3270 if (pdu_len == 0) {
3271 /* meaning, empty PDU - assuming the client_out_list, which may be empty*/
3272 spice_info->next_state = SPICE_SASL_START_FROM_SERVER;
3273 pdu_len = 4; /* only the size field.*/
3274 offset += pdu_len;
3275 } else {
3276 pdu_len += 4;
3277 GET_PDU_FROM_OFFSET(offset)
3278 proto_item_set_len(ti, pdu_len);
3279 if (client_sasl_list == false) {
3280 client_sasl_list = true;
3281 col_set_str(pinfo->cinfo, COL_INFO, "Client selected SASL authentication mechanism (start to server)");
3282 proto_tree_add_uint(spice_tree, hf_spice_selected_authentication_mechanism_length, tvb, offset, 4, pdu_len - 4);
3283 offset += 4;
3284 proto_tree_add_item(spice_tree, hf_spice_selected_authentication_mechanism, tvb, offset, pdu_len - 4, ENC_NA|ENC_ASCII);
3285 } else {
3286 /* this is the client out list, ending the start from client message */
3287 col_set_str(pinfo->cinfo, COL_INFO, "Client out mechanism (start to server)");
3288 proto_tree_add_uint(spice_tree, hf_spice_client_out_mechanism_length, tvb, offset, 4, pdu_len - 4);
3289 offset += 4;
3290 proto_tree_add_item(spice_tree, hf_spice_selected_client_out_mechanism, tvb, offset, pdu_len - 4, ENC_NA|ENC_ASCII);
3291 spice_info->next_state = SPICE_SASL_START_FROM_SERVER;
3293 offset += (pdu_len - 4);
3296 return pdu_len;
3297 case SPICE_SASL_START_FROM_SERVER:
3298 case SPICE_SASL_STEP_FROM_SERVER:
3299 offset = 0;
3300 while (offset < tvb_reported_length(tvb)) {
3301 avail = tvb_reported_length_remaining(tvb, offset);
3302 pdu_len = 4;
3303 GET_PDU_FROM_OFFSET(offset)
3304 pdu_len = tvb_get_letohl(tvb, offset); /* the length of the following messages */
3305 proto_item_set_len(ti, 4 + pdu_len);
3306 proto_tree_add_item(spice_tree, hf_spice_sasl_message_length, tvb, offset, 4, ENC_LITTLE_ENDIAN);
3307 if (pdu_len == 0) { /* meaning, empty PDU */
3308 offset += 4; /* only the size field.*/
3309 } else {
3310 pdu_len += 4;
3311 GET_PDU_FROM_OFFSET(offset)
3312 offset += 4;
3313 proto_tree_add_item(spice_tree, hf_spice_sasl_authentication_data, tvb, offset, pdu_len - 4, ENC_ASCII);
3314 offset += (pdu_len - 4);
3317 if (per_packet_info->state == SPICE_SASL_START_FROM_SERVER) {
3318 spice_info->next_state = SPICE_SASL_START_FROM_SERVER_CONT;
3319 } else {
3320 spice_info->next_state = SPICE_SASL_STEP_FROM_SERVER_CONT;
3322 return pdu_len;
3323 case SPICE_SASL_START_FROM_SERVER_CONT:
3324 case SPICE_SASL_STEP_FROM_SERVER_CONT:
3325 offset = 0;
3326 avail = tvb_reported_length_remaining(tvb, offset);
3327 if (avail >= 1) {
3328 proto_item_set_len(ti, 1);
3329 sasl_auth_result = tvb_get_uint8(tvb, offset);
3330 proto_tree_add_item(spice_tree, hf_spice_sasl_auth_result, tvb, offset, 1, ENC_NA);
3332 if (per_packet_info->state == SPICE_SASL_START_FROM_SERVER_CONT) {
3333 /* if we are in the sasl start, and can continue */
3334 if (sasl_auth_result == 0) { /* 0 = continue */
3335 spice_info->next_state = SPICE_SASL_STEP_TO_SERVER;
3336 } else {
3337 expert_add_info_format(pinfo, ti, &ei_spice_sasl_auth_result, "SPICE_SASL_START_FROM_SERVER_CONT and sasl_auth_result is %d",
3338 sasl_auth_result);
3340 } else { /* SPICE_SASL_STEP_FROM_SERVER_CONT state. */
3341 spice_info->next_state = SPICE_TICKET_SERVER;
3344 return 1;
3345 case SPICE_SASL_STEP_TO_SERVER:
3346 offset = 0;
3347 while (offset < tvb_reported_length(tvb)) {
3348 avail = tvb_reported_length_remaining(tvb, offset);
3349 pdu_len = 4;
3350 GET_PDU_FROM_OFFSET(offset)
3351 pdu_len = tvb_get_letohl(tvb, offset); /* the length of the following messages */
3352 proto_item_set_len(ti, 4);
3353 proto_tree_add_item(spice_tree, hf_spice_sasl_message_length, tvb, offset, 4, ENC_LITTLE_ENDIAN);
3354 if (pdu_len == 0) {
3355 /* meaning, empty PDU - assuming the client_out_list, which may be empty*/
3356 col_set_str(pinfo->cinfo, COL_INFO, "SASL authentication from client (step to server)");
3357 spice_info->next_state = SPICE_SASL_STEP_FROM_SERVER;
3358 pdu_len = 4; /* only the size field.*/
3359 offset += pdu_len;
3360 } else {
3361 pdu_len += 4;
3362 GET_PDU_FROM_OFFSET(offset)
3363 proto_item_set_len(ti, pdu_len);
3364 col_set_str(pinfo->cinfo, COL_INFO, "Clientout (step to server)");
3365 proto_tree_add_uint(spice_tree, hf_spice_clientout_length, tvb, offset, 4, pdu_len - 4);
3366 offset += 4;
3367 proto_tree_add_item(spice_tree, hf_spice_clientout_list, tvb, offset, pdu_len - 4, ENC_NA|ENC_ASCII);
3368 spice_info->next_state = SPICE_SASL_STEP_FROM_SERVER;
3369 offset += (pdu_len - 4);
3372 return pdu_len;
3373 case SPICE_SASL_DATA:
3374 offset = 0;
3375 while (offset < tvb_reported_length(tvb)) {
3376 avail = tvb_reported_length_remaining(tvb, offset);
3377 pdu_len = 4;
3378 GET_PDU_FROM_OFFSET(offset)
3379 pdu_len = tvb_get_ntohl(tvb, offset); /* the length of the following messages */
3380 proto_item_set_len(ti, pdu_len);
3381 proto_tree_add_item(spice_tree, hf_spice_sasl_message_length, tvb, offset, 4, ENC_LITTLE_ENDIAN);
3382 if (pdu_len == 0) { /* meaning, empty PDU */
3383 return 4; /* only the size field.*/
3384 } else {
3385 pdu_len += 4;
3387 GET_PDU_FROM_OFFSET(offset)
3388 proto_item_set_len(ti, pdu_len);
3389 col_add_fstr(pinfo->cinfo, COL_PROTOCOL,
3390 "Spice %s (SASL wrapped)", val_to_str_const(spice_info->channel_type,channel_types_vs, "Unknown"));
3392 offset += 4;
3393 proto_tree_add_bytes_format(spice_tree, hf_spice_sasl_data, tvb, offset, pdu_len - 4, NULL, "SASL data (%u bytes)", pdu_len - 4);
3394 offset += (pdu_len - 4);
3396 return pdu_len;
3397 case SPICE_DATA:
3398 offset = 0;
3399 while (offset < tvb_reported_length(tvb)) {
3400 avail = tvb_reported_length_remaining(tvb, offset);
3401 if (spice_info->client_mini_header && spice_info->server_mini_header) {
3402 pdu_len = sizeof_SpiceMiniDataHeader;
3403 GET_PDU_FROM_OFFSET(offset)
3404 pdu_len = tvb_get_letohl(tvb, offset + 2);
3405 pdu_len += sizeof_SpiceMiniDataHeader;
3406 } else {
3407 pdu_len = sizeof_SpiceDataHeader;
3408 GET_PDU_FROM_OFFSET(offset)
3409 /* if there are no sub-messages, get the usual message body size. */
3410 /* Note that we do not dissect properly yet sub-messages - but they */
3411 /* are not used in the protocol either */
3412 pdu_len = tvb_get_letohl(tvb, offset + 10);
3413 pdu_len += sizeof_SpiceDataHeader; /* +sizeof_SpiceDataHeader since you need to exclude the SPICE */
3414 /* data header, which is sizeof_SpiceDataHeader (18) bytes long) */
3416 GET_PDU_FROM_OFFSET(offset)
3417 proto_item_set_len(ti, pdu_len);
3419 if (spice_info->destport == pinfo->destport) { /* client to server traffic */
3420 offset = dissect_spice_data_client_pdu(tvb, spice_tree, pinfo, spice_info, offset);
3421 } else { /* server to client traffic */
3422 offset = dissect_spice_data_server_pdu(tvb, spice_tree, pinfo, spice_info, offset, pdu_len);
3425 return offset;
3426 break;
3427 case SPICE_TICKET_CLIENT:
3428 if (spice_info->destport != pinfo->destport) /* ignore anything from the server, wait for ticket from client */
3429 break;
3430 avail = tvb_reported_length(tvb);
3431 pdu_len = 128;
3432 GET_PDU_FROM_OFFSET(0)
3433 proto_item_set_len(ti, 128);
3434 proto_tree_add_item(spice_tree, hf_ticket_client, tvb, 0, 128, ENC_NA);
3435 spice_info->next_state = SPICE_TICKET_SERVER;
3436 return 128;
3437 case SPICE_TICKET_SERVER:
3438 if (spice_info->destport != pinfo->srcport) /* ignore anything from the client, wait for ticket from server */
3439 break;
3440 avail = tvb_reported_length(tvb);
3441 pdu_len = 4;
3442 GET_PDU_FROM_OFFSET(0)
3443 proto_item_set_len(ti, 4);
3444 proto_tree_add_item(spice_tree, hf_ticket_server, tvb, 0, 4, ENC_LITTLE_ENDIAN);
3445 if (spice_info->auth_selected == SPICE_COMMON_CAP_AUTH_SASL) {
3446 spice_info->next_state = SPICE_SASL_DATA;
3447 } else {
3448 spice_info->next_state = SPICE_DATA;
3450 return pdu_len;
3451 default:
3452 break;
3454 return 0;
3457 static bool
3458 test_spice_protocol(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
3461 if ((tvb_reported_length(tvb) >= 4) && (tvb_get_ntohl(tvb, 0) == SPICE_MAGIC)) {
3462 dissect_spice(tvb, pinfo, tree, data);
3463 return true;
3465 return false;
3468 /* Register the protocol with Wireshark */
3469 void
3470 proto_register_spice(void)
3472 /* Setup list of header fields */
3473 static hf_register_info hf[] = {
3474 { &hf_link_client,
3475 { "Link client header", "spice.link_client",
3476 FT_NONE, BASE_NONE, NULL, 0x0,
3477 NULL, HFILL }
3479 { &hf_link_server,
3480 { "Link server header", "spice.link_server",
3481 FT_NONE, BASE_NONE, NULL, 0x0,
3482 NULL, HFILL }
3484 { &hf_spice_magic,
3485 { "SPICE MAGIC", "spice.magic",
3486 FT_STRING, BASE_NONE, NULL, 0x0,
3487 NULL, HFILL }
3489 { &hf_major_version,
3490 { "Protocol major version", "spice.major_version",
3491 FT_INT32, BASE_DEC, NULL, 0x0,
3492 NULL, HFILL }
3494 { &hf_minor_version,
3495 { "Protocol minor version", "spice.minor_version",
3496 FT_INT32, BASE_DEC, NULL, 0x0,
3497 NULL, HFILL }
3499 { &hf_message_size,
3500 { "Message size", "spice.message_size",
3501 FT_UINT32, BASE_DEC, NULL, 0x0,
3502 NULL, HFILL }
3504 { &hf_message_type,
3505 { "Message type", "spice.message_type",
3506 FT_UINT16, BASE_DEC, NULL, 0x0,
3507 NULL, HFILL }
3509 { &hf_conn_id,
3510 { "Session ID", "spice.conn_id",
3511 FT_UINT32, BASE_HEX, NULL, 0x0,
3512 NULL, HFILL }
3514 { &hf_channel_type,
3515 { "Channel type", "spice.channel_type",
3516 FT_UINT8, BASE_DEC, VALS(channel_types_vs), 0x0,
3517 NULL, HFILL }
3519 { &hf_channel_id,
3520 { "Channel ID", "spice.channel_id",
3521 FT_UINT8, BASE_DEC, NULL, 0x0,
3522 NULL, HFILL }
3524 { &hf_num_common_caps,
3525 { "Number of common capabilities", "spice.num_common_caps",
3526 FT_UINT32, BASE_DEC, NULL, 0x0,
3527 NULL, HFILL }
3529 { &hf_num_channel_caps,
3530 { "Number of channel capabilities", "spice.num_channel_caps",
3531 FT_UINT32, BASE_DEC, NULL, 0x0,
3532 NULL, HFILL }
3534 { &hf_caps_offset,
3535 { "Capabilities offset (bytes)", "spice.caps_offset",
3536 FT_UINT32, BASE_DEC, NULL, 0x0,
3537 NULL, HFILL }
3539 { &hf_error_code,
3540 { "spice ERROR", "spice.error_code",
3541 FT_UINT32, BASE_DEC, VALS(spice_link_err_vs), 0x0,
3542 NULL, HFILL }
3544 { &hf_serial,
3545 { "Message serial number", "spice.serial",
3546 FT_UINT64, BASE_DEC, NULL, 0x0,
3547 NULL, HFILL }
3549 { &hf_data,
3550 { "Message header", "spice.message_header",
3551 FT_NONE, BASE_NONE, NULL, 0x0,
3552 NULL, HFILL }
3554 { &hf_data_size,
3555 { "Message body size (bytes)", "spice.message_size",
3556 FT_UINT32, BASE_DEC, NULL, 0x0,
3557 NULL, HFILL }
3559 { &hf_data_sublist,
3560 { "Sub-list offset (bytes)", "spice.message_sublist",
3561 FT_UINT32, BASE_DEC, NULL, 0x0,
3562 NULL, HFILL }
3564 { &hf_ticket_client,
3565 { "Ticket - client", "spice.ticket_client",
3566 FT_BYTES, BASE_NONE, NULL, 0x0,
3567 NULL, HFILL }
3569 { &hf_ticket_server,
3570 { "Link result", "spice.ticket_server",
3571 FT_UINT32, BASE_DEC, VALS(spice_link_err_vs), 0x0,
3572 NULL, HFILL }
3574 { &hf_auth_select_client,
3575 { "Authentication selected by client", "spice.auth_select_client",
3576 FT_UINT32, BASE_DEC, VALS(spice_auth_select_vs), 0x0,
3577 NULL, HFILL }
3579 { &hf_common_cap_auth_select,
3580 { "Auth Selection", "spice.common_cap_auth_select",
3581 FT_BOOLEAN, 4, TFS(&tfs_set_notset), SPICE_COMMON_CAP_PROTOCOL_AUTH_SELECTION_MASK,
3582 NULL, HFILL }
3584 { &hf_common_cap_auth_spice,
3585 { "Auth Spice", "spice.common_cap_auth_spice",
3586 FT_BOOLEAN, 4, TFS(&tfs_set_notset), SPICE_COMMON_CAP_AUTH_SPICE_MASK,
3587 NULL, HFILL }
3589 { &hf_common_cap_auth_sasl,
3590 { "Auth SASL", "spice.common_cap_auth_sasl",
3591 FT_BOOLEAN, 4, TFS(&tfs_set_notset), SPICE_COMMON_CAP_AUTH_SASL_MASK,
3592 NULL, HFILL }
3594 { &hf_common_cap_mini_header,
3595 { "Mini Header", "spice.common_cap_mini_header",
3596 FT_BOOLEAN, 4, TFS(&tfs_set_notset), SPICE_COMMON_CAP_MINI_HEADER_MASK,
3597 NULL, HFILL }
3599 { &hf_playback_cap_celt_0_5_1,
3600 { "CELT 0.5.1 playback channel support", "spice.playback_cap_celt_0_5_1",
3601 FT_BOOLEAN, PLAYBACK_CAP_NBITS, TFS(&tfs_set_notset), SPICE_PLAYBACK_CAP_CELT_0_5_1_MASK,
3602 NULL, HFILL }
3604 { &hf_playback_cap_volume,
3605 { "Volume playback channel support", "spice.playback_cap_volume",
3606 FT_BOOLEAN, PLAYBACK_CAP_NBITS, TFS(&tfs_set_notset), SPICE_PLAYBACK_CAP_VOLUME_MASK,
3607 NULL, HFILL }
3609 { &hf_playback_cap_latency,
3610 { "Latency playback channel support", "spice.playback_cap_latency",
3611 FT_BOOLEAN, PLAYBACK_CAP_NBITS, TFS(&tfs_set_notset), SPICE_PLAYBACK_CAP_LATENCY_MASK,
3612 NULL, HFILL }
3614 { &hf_playback_cap_opus,
3615 { "OPUS playback channel support", "spice.playback_cap_opus",
3616 FT_BOOLEAN, PLAYBACK_CAP_NBITS, TFS(&tfs_set_notset), SPICE_PLAYBACK_CAP_OPUS_MASK,
3617 NULL, HFILL }
3619 { &hf_record_cap_celt,
3620 { "CELT 0.5.1 record channel support", "spice.record_cap_celt",
3621 FT_BOOLEAN, RECORD_CAP_NBITS, TFS(&tfs_set_notset), SPICE_RECORD_CAP_CELT_0_5_1_MASK,
3622 NULL, HFILL }
3624 { &hf_record_cap_volume,
3625 { "Volume record channel support", "spice.record_cap_volume",
3626 FT_BOOLEAN, RECORD_CAP_NBITS, TFS(&tfs_set_notset), SPICE_RECORD_CAP_VOLUME_MASK,
3627 NULL, HFILL }
3629 { &hf_record_cap_opus,
3630 { "Opus record channel support", "spice.record_cap_opus",
3631 FT_BOOLEAN, RECORD_CAP_NBITS, TFS(&tfs_set_notset), SPICE_RECORD_CAP_OPUS_MASK,
3632 NULL, HFILL }
3634 { &hf_display_cap_sized_stream,
3635 { "Sized stream display channel support", "spice.display_cap_sized_stream",
3636 FT_BOOLEAN, DISPLAY_CAP_NBITS, TFS(&tfs_set_notset), SPICE_DISPLAY_CAP_SIZED_STREAM_MASK,
3637 NULL, HFILL }
3639 { &hf_display_cap_monitors_config,
3640 { "Monitors configuration display channel support", "spice.display_cap_monitors_config",
3641 FT_BOOLEAN, DISPLAY_CAP_NBITS, TFS(&tfs_set_notset), SPICE_DISPLAY_CAP_MONITORS_CONFIG_MASK,
3642 NULL, HFILL }
3644 { &hf_display_cap_composite,
3645 { "Composite capability display channel support", "spice.display_cap_composite",
3646 FT_BOOLEAN, DISPLAY_CAP_NBITS, TFS(&tfs_set_notset), SPICE_DISPLAY_CAP_COMPOSITE_MASK,
3647 NULL, HFILL }
3649 { &hf_display_cap_a8_surface,
3650 { "A8 bitmap display channel support", "spice.display_cap_a8_surface",
3651 FT_BOOLEAN, DISPLAY_CAP_NBITS, TFS(&tfs_set_notset), SPICE_DISPLAY_CAP_A8_SURFACE_MASK,
3652 NULL, HFILL }
3654 { &hf_display_cap_stream_report,
3655 { "Stream Report display channel support", "spice.display_cap_stream_report",
3656 FT_BOOLEAN, DISPLAY_CAP_NBITS, TFS(&tfs_set_notset), SPICE_DISPLAY_CAP_STREAM_REPORT_MASK,
3657 NULL, HFILL }
3659 { &hf_display_cap_lz4_compression,
3660 { "LZ4 Compression display channel support", "spice.display_cap_lz4_compression",
3661 FT_BOOLEAN, DISPLAY_CAP_NBITS, TFS(&tfs_set_notset), SPICE_DISPLAY_CAP_LZ4_COMPRESSION_MASK,
3662 NULL, HFILL }
3664 { &hf_display_cap_pref_compression,
3665 { "Pref Compression display channel support", "spice.display_cap_pref_compression",
3666 FT_BOOLEAN, DISPLAY_CAP_NBITS, TFS(&tfs_set_notset), SPICE_DISPLAY_CAP_PREF_COMPRESSION_MASK,
3667 NULL, HFILL }
3669 { &hf_display_cap_gl_scanout,
3670 { "GL Scanout display channel support", "spice.display_cap_gl_scanout",
3671 FT_BOOLEAN, DISPLAY_CAP_NBITS, TFS(&tfs_set_notset), SPICE_DISPLAY_CAP_GL_SCANOUT_MASK,
3672 NULL, HFILL }
3674 { &hf_display_cap_multi_codec,
3675 { "Multi-codec display channel support", "spice.display_cap_multi_codec",
3676 FT_BOOLEAN, DISPLAY_CAP_NBITS, TFS(&tfs_set_notset), SPICE_DISPLAY_CAP_MULTI_CODEC_MASK,
3677 NULL, HFILL }
3679 { &hf_display_cap_codec_mjpeg,
3680 { "MJPEG codec display channel support", "spice.display_cap_codec_mjpeg",
3681 FT_BOOLEAN, DISPLAY_CAP_NBITS, TFS(&tfs_set_notset), SPICE_DISPLAY_CAP_CODEC_MJPEG_MASK,
3682 NULL, HFILL }
3684 { &hf_display_cap_codec_vp8,
3685 { "VP8 codec display channel support", "spice.display_cap_codec_vp8",
3686 FT_BOOLEAN, DISPLAY_CAP_NBITS, TFS(&tfs_set_notset), SPICE_DISPLAY_CAP_CODEC_VP8_MASK,
3687 NULL, HFILL }
3689 { &hf_display_cap_codec_h264,
3690 { "H264 codec display channel support", "spice.display_cap_codec_h264",
3691 FT_BOOLEAN, DISPLAY_CAP_NBITS, TFS(&tfs_set_notset), SPICE_DISPLAY_CAP_CODEC_H264_MASK,
3692 NULL, HFILL }
3694 { &hf_display_cap_pref_video_codec_type,
3695 { "Preferred Video Codec Type display channel support", "spice.display_cap_pref_video_codec_type",
3696 FT_BOOLEAN, DISPLAY_CAP_NBITS, TFS(&tfs_set_notset), SPICE_DISPLAY_CAP_PREF_VIDEO_CODEC_TYPE_MASK,
3697 NULL, HFILL }
3699 { &hf_display_cap_codec_vp9,
3700 { "VP9 codec display channel support", "spice.display_cap_codec_vp9",
3701 FT_BOOLEAN, DISPLAY_CAP_NBITS, TFS(&tfs_set_notset), SPICE_DISPLAY_CAP_CODEC_VP9_MASK,
3702 NULL, HFILL }
3704 { &hf_display_cap_codec_h265,
3705 { "H265 codec display channel support", "spice.display_cap_codec_h265",
3706 FT_BOOLEAN, DISPLAY_CAP_NBITS, TFS(&tfs_set_notset), SPICE_DISPLAY_CAP_CODEC_H265_MASK,
3707 NULL, HFILL }
3709 { &hf_cursor_cap,
3710 { "Cursor channel capability", "spice.cursor_cap",
3711 FT_UINT32, BASE_DEC, NULL, 0x0,
3712 NULL, HFILL }
3714 { &hf_inputs_cap,
3715 { "Inputs channel capability", "spice.inputs_cap",
3716 FT_UINT32, BASE_DEC, NULL, 0x0,
3717 NULL, HFILL }
3719 { &hf_main_num_channels,
3720 { "Number of Channels", "spice.main_num_channels",
3721 FT_UINT32, 4, NULL, 0x0,
3722 NULL, HFILL }
3724 { &hf_main_cap_semi_migrate,
3725 { "Semi-seamless migration capability", "spice.main_cap_semi_migrate",
3726 FT_BOOLEAN, 4, TFS(&tfs_set_notset), SPICE_MAIN_CAP_SEMI_SEAMLESS_MIGRATE_MASK,
3727 NULL, HFILL }
3729 { &hf_main_cap_vm_name_uuid,
3730 { "VM name and UUID messages capability", "spice.main_cap_vm_name_uuid",
3731 FT_BOOLEAN, 4, TFS(&tfs_set_notset), SPICE_MAIN_CAP_VM_NAME_UUID_MASK,
3732 NULL, HFILL }
3734 { &hf_main_cap_agent_connected_tokens,
3735 { "Agent connected tokens capability", "spice.main_cap_agent_connected_tokens",
3736 FT_BOOLEAN, 4, TFS(&tfs_set_notset), SPICE_MAIN_CAP_AGENT_CONNECTED_TOKENS_MASK,
3737 NULL, HFILL }
3739 { &hf_main_cap_seamless_migrate,
3740 { "Seamless migration capability", "spice.main_cap_seamless_migrate",
3741 FT_BOOLEAN, 4, TFS(&tfs_set_notset), SPICE_MAIN_CAP_SEAMLESS_MIGRATE_MASK,
3742 NULL, HFILL }
3744 { &hf_audio_timestamp,
3745 { "Timestamp", "spice.audio_timestamp",
3746 FT_UINT32, BASE_DEC, NULL, 0x0,
3747 NULL, HFILL }
3749 { &hf_audio_mode,
3750 { "Mode", "spice.audio_mode",
3751 FT_UINT16, BASE_DEC, VALS(playback_mode_vals), 0x0,
3752 NULL, HFILL }
3754 { &hf_audio_channels,
3755 { "Channels", "spice.audio_channels",
3756 FT_UINT32, BASE_DEC, NULL, 0x0,
3757 NULL, HFILL }
3759 { &hf_audio_format,
3760 { "Format", "spice.audio_format",
3761 FT_UINT16, BASE_DEC, VALS(spice_audio_fmt_vs), 0x0,
3762 NULL, HFILL }
3764 { &hf_audio_frequency,
3765 { "Frequency", "spice.audio_frequency",
3766 FT_UINT32, BASE_DEC, NULL, 0x0,
3767 NULL, HFILL }
3769 { &hf_audio_volume,
3770 { "Volume", "spice.audio_volume",
3771 FT_UINT16, BASE_DEC, NULL, 0x0,
3772 NULL, HFILL }
3774 { &hf_audio_mute,
3775 { "Mute", "spice.audio_mute",
3776 FT_UINT8, BASE_DEC, NULL, 0x0,
3777 NULL, HFILL }
3779 { &hf_audio_latency,
3780 { "Latency (ms)", "spice.audio_latency",
3781 FT_UINT32, BASE_DEC, NULL, 0x0,
3782 NULL, HFILL }
3784 { &hf_red_set_ack_generation,
3785 { "Set ACK generation", "spice.red_set_ack_generation",
3786 FT_UINT32, BASE_DEC, NULL, 0x0,
3787 NULL, HFILL }
3789 { &hf_red_set_ack_window,
3790 { "Set ACK window (messages)", "spice.red_set_ack_window",
3791 FT_UINT32, BASE_DEC, NULL, 0x0,
3792 NULL, HFILL }
3794 { &hf_Clip_type,
3795 { "Clip type", "spice.clip_type",
3796 FT_UINT8, BASE_DEC, VALS(spice_clip_type_vs), 0x0,
3797 NULL, HFILL }
3799 { &hf_Mask_flag,
3800 { "Mask flag", "spice.mask_flag",
3801 FT_UINT8, BASE_DEC, VALS(spice_mask_flags_vs), 0x0,
3802 NULL, HFILL }
3804 { &hf_display_rop_descriptor,
3805 { "ROP descriptor", "spice.display_rop_descriptor",
3806 FT_UINT16, BASE_HEX, VALS(spice_ropd_vs), 0x0,
3807 NULL, HFILL }
3809 { &hf_display_scale_mode,
3810 { "Scale mode", "spice.scale_mode",
3811 FT_UINT8, BASE_DEC, VALS(spice_image_scale_mode_vs), 0x0,
3812 NULL, HFILL }
3814 { &hf_red_ping_id,
3815 { "Ping ID", "spice.ping_id",
3816 FT_UINT32, BASE_DEC, NULL, 0x0,
3817 NULL, HFILL }
3819 { &hf_red_timestamp,
3820 { "timestamp", "spice.timestamp",
3821 FT_UINT64, BASE_DEC, NULL, 0x0,
3822 NULL, HFILL }
3824 { &hf_spice_display_mode_width,
3825 { "Display Width", "spice.display_width",
3826 FT_UINT32, BASE_DEC, NULL, 0x0,
3827 NULL, HFILL }
3829 { &hf_spice_display_mode_height,
3830 { "Display Height", "spice.display_height",
3831 FT_UINT32, BASE_DEC, NULL, 0x0,
3832 NULL, HFILL }
3834 { &hf_spice_display_mode_depth,
3835 { "Color depth", "spice.display_depth",
3836 FT_UINT32, BASE_DEC, NULL, 0x0,
3837 NULL, HFILL }
3839 { &hf_image_desc_id,
3840 { "Image ID", "spice.image_id",
3841 FT_UINT64, BASE_HEX, NULL, 0x0,
3842 NULL, HFILL }
3844 { &hf_image_desc_type,
3845 { "Image type", "spice.image_type",
3846 FT_UINT8, BASE_DEC, VALS(spice_image_type_vs), 0x0,
3847 NULL, HFILL }
3849 { &hf_image_desc_flags,
3850 { "Flags", "spice.image_flags",
3851 FT_UINT8, BASE_HEX, VALS(spice_image_flags_vs), 0x0,
3852 NULL, HFILL }
3854 { &hf_image_desc_width,
3855 { "Width", "spice.image_width",
3856 FT_UINT32, BASE_DEC, NULL, 0x0,
3857 NULL, HFILL }
3859 { &hf_image_desc_height,
3860 { "Height", "spice.image_height",
3861 FT_UINT32, BASE_DEC, NULL, 0x0,
3862 NULL, HFILL }
3864 { &hf_quic_width,
3865 { "Width", "spice.quic_width",
3866 FT_UINT32, BASE_DEC, NULL, 0x0,
3867 NULL, HFILL }
3869 { &hf_quic_type,
3870 { "QUIC image type", "spice.quic_type",
3871 FT_UINT32, BASE_DEC, VALS(quic_type_vs), 0x0,
3872 NULL, HFILL }
3874 { &hf_quic_height,
3875 { "Height", "spice.quic_height",
3876 FT_UINT32, BASE_DEC, NULL, 0x0,
3877 NULL, HFILL }
3879 { &hf_quic_major_version,
3880 { "QUIC major version", "spice.quic_major_version",
3881 FT_UINT16, BASE_DEC, NULL, 0x0,
3882 NULL, HFILL }
3884 { &hf_quic_minor_version,
3885 { "QUIC minor version", "spice.quic_minor_version",
3886 FT_UINT16, BASE_DEC, NULL, 0x0,
3887 NULL, HFILL }
3889 { &hf_LZ_width,
3890 { "Width", "spice.LZ_width",
3891 FT_UINT32, BASE_DEC, NULL, 0x0,
3892 NULL, HFILL }
3894 { &hf_LZ_height,
3895 { "Height", "spice.LZ_height",
3896 FT_UINT32, BASE_DEC, NULL, 0x0,
3897 NULL, HFILL }
3899 { &hf_LZ_RGB_type,
3900 { "Image type", "spice.LZ_RGB_type",
3901 FT_UINT8, BASE_DEC, VALS(LzImage_type_vs), 0xf,
3902 NULL, HFILL }
3904 { &hf_LZ_major_version,
3905 { "LZ major version", "spice.LZ_major_version",
3906 FT_UINT16, BASE_DEC, NULL, 0x0,
3907 NULL, HFILL }
3909 { &hf_LZ_minor_version,
3910 { "LZ minor version", "spice.LZ_minor_version",
3911 FT_UINT16, BASE_DEC, NULL, 0x0,
3912 NULL, HFILL }
3914 { &hf_LZ_stride,
3915 { "Stride", "spice.LZ_stride",
3916 FT_UINT32, BASE_DEC, NULL, 0x0,
3917 NULL, HFILL }
3919 { &hf_LZ_RGB_dict_id,
3920 { "LZ RGB Dictionary ID", "spice.LZ_RGB_dict_id",
3921 FT_UINT64, BASE_HEX, NULL, 0x0,
3922 NULL, HFILL }
3924 { &hf_cursor_trail_len,
3925 { "Cursor trail length", "spice.cursor_trail_len",
3926 FT_UINT16, BASE_DEC, NULL, 0x0,
3927 NULL, HFILL }
3929 { &hf_cursor_trail_freq,
3930 { "Cursor trail frequency", "spice.cursor_trail_freq",
3931 FT_UINT16, BASE_DEC, NULL, 0x0,
3932 NULL, HFILL }
3934 { &hf_cursor_trail_visible,
3935 { "Cursor trail visibility", "spice.cursor_trail_visible",
3936 FT_UINT8, BASE_DEC, VALS(cursor_visible_vs), 0x0,
3937 NULL, HFILL }
3939 { &hf_cursor_unique,
3940 { "Cursor unique ID", "spice.cursor_unique",
3941 FT_UINT64, BASE_HEX, NULL, 0x0,
3942 NULL, HFILL }
3944 { &hf_cursor_type,
3945 { "Cursor type", "spice.cursor_type",
3946 FT_UINT8, BASE_HEX, VALS(spice_cursor_type_vs), 0x0,
3947 NULL, HFILL }
3949 { &hf_cursor_width,
3950 { "Cursor width", "spice.cursor_width",
3951 FT_UINT16, BASE_DEC, NULL, 0x0,
3952 NULL, HFILL }
3954 { &hf_cursor_height,
3955 { "Cursor height", "spice.cursor_height",
3956 FT_UINT16, BASE_DEC, NULL, 0x0,
3957 NULL, HFILL }
3959 { &hf_cursor_hotspot_x,
3960 { "Cursor hotspot X", "spice.cursor_hotspot_x",
3961 FT_UINT16, BASE_DEC, NULL, 0x0,
3962 NULL, HFILL }
3964 { &hf_cursor_hotspot_y,
3965 { "Cursor hotspot Y", "spice.cursor_hotspot_y",
3966 FT_UINT16, BASE_DEC, NULL, 0x0,
3967 NULL, HFILL }
3969 { &hf_cursor_flags, /*FIXME - those are flags */
3970 { "Cursor flags", "spice.cursor_flags",
3971 FT_UINT16, BASE_HEX, VALS(spice_cursor_flags_vs), 0x0,
3972 NULL, HFILL }
3974 { &hf_cursor_id,
3975 { "Cursor ID", "spice.cursor_id",
3976 FT_UINT64, BASE_DEC, NULL, 0x0,
3977 NULL, HFILL }
3979 { &hf_spice_display_init_cache_id,
3980 { "Cache ID", "spice.display_init_cache_id",
3981 FT_UINT8, BASE_DEC, NULL, 0x0,
3982 NULL, HFILL }
3984 { &hf_spice_display_init_cache_size,
3985 { "Cache size (pixels)", "spice.display_init_cache_size",
3986 FT_UINT64, BASE_DEC, NULL, 0x0,
3987 NULL, HFILL }
3989 { &hf_spice_display_init_glz_dict_id,
3990 { "GLZ Dictionary ID", "spice.display_init_glz_dict_id",
3991 FT_UINT8, BASE_DEC, NULL, 0x0,
3992 NULL, HFILL }
3994 { &hf_spice_display_init_dict_window_size,
3995 { "Dictionary window size", "spice.display_init_dict_window_size",
3996 FT_UINT32, BASE_DEC, NULL, 0x0,
3997 NULL, HFILL }
3999 { &hf_brush_type,
4000 { "Brush type", "spice.brush_type",
4001 FT_UINT8, BASE_DEC, VALS(spice_brush_type_vs), 0x0,
4002 NULL, HFILL }
4004 { &hf_brush_rgb,
4005 { "Brush color", "spice.brush_rgb",
4006 FT_UINT32, BASE_HEX, NULL, 0x0,
4007 NULL, HFILL }
4009 { &hf_pixmap_width,
4010 { "Pixmap width", "spice.pixmap_width",
4011 FT_UINT32, BASE_DEC, NULL, 0x0,
4012 NULL, HFILL }
4014 { &hf_pixmap_height,
4015 { "Pixmap height", "spice.pixmap_height",
4016 FT_UINT32, BASE_DEC, NULL, 0x0,
4017 NULL, HFILL }
4019 { &hf_pixmap_stride,
4020 { "Pixmap stride", "spice.pixmap_stride",
4021 FT_UINT32, BASE_DEC, NULL, 0x0,
4022 NULL, HFILL }
4024 { &hf_pixmap_address,
4025 { "Pixmap palette pointer", "spice.pixmap_palette_address",
4026 FT_UINT32, BASE_HEX_DEC, NULL, 0x0,
4027 NULL, HFILL }
4029 { &hf_pixmap_format,
4030 { "Pixmap format", "spice.pixmap_format",
4031 FT_UINT8, BASE_DEC, VALS(spice_bitmap_fmt_vs), 0x0,
4032 NULL, HFILL }
4034 { &hf_pixmap_flags,
4035 { "Pixmap flags", "spice.pixmap_flags",
4036 FT_UINT8, BASE_HEX, VALS(spice_bitmap_flags_vs), 0x0,
4037 NULL, HFILL }
4039 { &hf_keyboard_modifiers,
4040 { "Keyboard modifiers", "spice.keyboard_modifiers",
4041 FT_UINT16, BASE_HEX, NULL, 0x0,
4042 NULL, HFILL }
4044 { &hf_keyboard_modifier_scroll_lock,
4045 { "Scroll Lock", "spice.keyboard_modifier_scroll_lock",
4046 FT_BOOLEAN, 16, TFS(&tfs_set_notset), SPICE_KEYBOARD_MODIFIER_FLAGS_SCROLL_LOCK,
4047 NULL, HFILL }
4049 { &hf_keyboard_modifier_num_lock,
4050 { "Num Lock", "spice.keyboard_modifier_num_lock",
4051 FT_BOOLEAN, 16, TFS(&tfs_set_notset), SPICE_KEYBOARD_MODIFIER_FLAGS_NUM_LOCK,
4052 NULL, HFILL }
4054 { &hf_keyboard_modifier_caps_lock,
4055 { "Caps Lock", "spice.keyboard_modifier_caps_lock",
4056 FT_BOOLEAN, 16, TFS(&tfs_set_notset), SPICE_KEYBOARD_MODIFIER_FLAGS_CAPS_LOCK,
4057 NULL, HFILL }
4059 { &hf_keyboard_code,
4060 { "Key scan code", "spice.keyboard_key_code",
4061 FT_UINT32, BASE_DEC_HEX, NULL, 0x0,
4062 NULL, HFILL }
4064 { &hf_rectlist_size,
4065 { "RectList size", "spice.rectlist_size",
4066 FT_UINT32, BASE_DEC, NULL, 0x0,
4067 NULL, HFILL }
4069 { &hf_migrate_dest_port,
4070 { "Migrate Dest Port", "spice.migrate_dest_port",
4071 FT_UINT16, BASE_DEC, NULL, 0x0,
4072 NULL, HFILL }
4074 { &hf_migrate_dest_sport,
4075 { "Migrate Dest Secure Port", "spice.migrate_dest_sport",
4076 FT_UINT16, BASE_DEC, NULL, 0x0,
4077 NULL, HFILL }
4079 { &hf_migrate_src_mig_version,
4080 { "Migrate Source Migration Version", "spice.migrate_src_version",
4081 FT_UINT32, BASE_DEC, NULL, 0x0,
4082 NULL, HFILL }
4084 { &hf_session_id,
4085 { "Session ID", "spice.main_session_id",
4086 FT_UINT32, BASE_DEC, NULL, 0x0,
4087 NULL, HFILL }
4089 { &hf_display_channels_hint,
4090 { "Number of display channels", "spice.display_channels_hint",
4091 FT_UINT32, BASE_DEC, NULL, 0x0,
4092 NULL, HFILL }
4094 { &hf_supported_mouse_modes,
4095 { "Supported mouse modes", "spice.supported_mouse_modes",
4096 FT_UINT32, BASE_HEX, NULL, 0x0,
4097 NULL, HFILL }
4099 { &hf_supported_mouse_modes_flags,
4100 { "Supported mouse modes", "spice.supported_mouse_modes_flags",
4101 FT_UINT16, BASE_HEX, NULL, 0x0,
4102 NULL, HFILL }
4104 { &hf_current_mouse_mode,
4105 { "Current mouse mode", "spice.current_mouse_mode",
4106 FT_UINT32, BASE_HEX, VALS(spice_mouse_mode_vs), 0x0,
4107 NULL, HFILL }
4109 { &hf_supported_mouse_modes_flag_client,
4110 { "Client mode", "spice.supported_mouse_modes_flag_client",
4111 FT_BOOLEAN, 2, TFS(&tfs_set_notset), SPICE_MOUSE_MODE_CLIENT,
4112 NULL, HFILL }
4114 { &hf_supported_mouse_modes_flag_server,
4115 { "Server mode", "spice.supported_mouse_modes_flags_server",
4116 FT_BOOLEAN, 2, TFS(&tfs_set_notset), SPICE_MOUSE_MODE_SERVER,
4117 NULL, HFILL }
4119 { &hf_current_mouse_mode_flags,
4120 { "Current mouse mode", "spice.current_mouse_mode_flags",
4121 FT_UINT16, BASE_HEX, VALS(spice_mouse_mode_vs), 0x0,
4122 NULL, HFILL }
4124 { &hf_agent_connected,
4125 { "Agent", "spice.agent",
4126 FT_UINT32, BASE_DEC, VALS(spice_agent_vs), 0x0,
4127 NULL, HFILL }
4129 { &hf_agent_tokens,
4130 { "Agent tokens", "spice.agent_tokens",
4131 FT_UINT32, BASE_DEC, NULL, 0x0,
4132 NULL, HFILL }
4134 { &hf_multi_media_time,
4135 { "Current server multimedia time", "spice.multimedia_time",
4136 FT_UINT32, BASE_DEC, NULL, 0x0,
4137 NULL, HFILL }
4139 { &hf_ram_hint,
4140 { "RAM hint", "spice.ram_hint",
4141 FT_UINT32, BASE_DEC, NULL, 0x0,
4142 NULL, HFILL }
4144 { &hf_button,
4145 { "Mouse button ID", "spice.button",
4146 FT_UINT8, BASE_DEC, VALS(spice_mouse_button_vs), 0x0,
4147 NULL, HFILL }
4149 { &hf_buttons_state,
4150 { "Mouse buttons state mask", "spice.buttons_state",
4151 FT_UINT16, BASE_HEX, NULL, 0x0,
4152 NULL, HFILL }
4154 { &hf_button_mask_left,
4155 { "Left", "spice.button_mask_left",
4156 FT_BOOLEAN, 16, TFS(&tfs_set_notset), SPICE_MOUSE_BUTTON_MASK_LEFT,
4157 NULL, HFILL }
4159 { &hf_button_mask_middle,
4160 { "Middle", "spice.button_mask_middle",
4161 FT_BOOLEAN, 16, TFS(&tfs_set_notset), SPICE_MOUSE_BUTTON_MASK_MIDDLE,
4162 NULL, HFILL }
4164 { &hf_button_mask_right,
4165 { "Right", "spice.button_mask_right",
4166 FT_BOOLEAN, 16, TFS(&tfs_set_notset), SPICE_MOUSE_BUTTON_MASK_RIGHT,
4167 NULL, HFILL }
4169 { &hf_button_mask_reserved_bits,
4170 { "Reserved bits", "spice.button_mask_reserved_bits",
4171 FT_UINT16, BASE_HEX, NULL, 0xFFF8,
4172 "Must be zero", HFILL }
4174 { &hf_mouse_display_id,
4175 { "Mouse display ID", "spice.mouse_display_id",
4176 FT_UINT8, BASE_DEC, NULL, 0x0,
4177 NULL, HFILL }
4179 { &hf_display_text_fore_mode,
4180 { "Text foreground mode", "spice.draw_text_fore_mode",
4181 FT_UINT16, BASE_DEC, NULL, 0x0,
4182 NULL, HFILL }
4184 { &hf_display_text_back_mode,
4185 { "Text background mode", "spice.draw_text_back_mode",
4186 FT_UINT16, BASE_DEC, NULL, 0x0,
4187 NULL, HFILL }
4189 { &hf_display_monitor_config_count,
4190 { "Monitor count", "spice.monitor_config_count",
4191 FT_UINT16, BASE_DEC, NULL, 0x0,
4192 NULL, HFILL }
4194 { &hf_display_monitor_config_max_allowed,
4195 { "Max.allowed monitors", "spice.monitor_config_max_allowed",
4196 FT_UINT16, BASE_DEC, NULL, 0x0,
4197 NULL, HFILL }
4199 { &hf_display_stream_id,
4200 { "Stream ID", "spice.display_stream_id",
4201 FT_UINT32, BASE_DEC, NULL, 0x0,
4202 NULL, HFILL }
4204 { &hf_display_stream_report_unique_id,
4205 { "Unique ID", "spice.display_stream_report_unique_id",
4206 FT_UINT32, BASE_DEC, NULL, 0x0,
4207 NULL, HFILL }
4209 { &hf_display_stream_report_max_window_size,
4210 { "Max window size", "spice.display_stream_report_max_window_size",
4211 FT_UINT32, BASE_DEC, NULL, 0x0,
4212 NULL, HFILL }
4214 { &hf_display_stream_report_timeout,
4215 { "Timeout (ms)", "spice.display_stream_report_timeout",
4216 FT_UINT32, BASE_DEC, NULL, 0x0,
4217 NULL, HFILL }
4219 { &hf_display_stream_flags,
4220 { "Stream flags", "spice.display_stream_flags",
4221 FT_UINT8, BASE_DEC, VALS(spice_stream_flags_vs), 0x0,
4222 NULL, HFILL }
4224 { &hf_display_stream_codec_type,
4225 { "Stream codec type", "spice.display_stream_codec_type",
4226 FT_UINT32, BASE_DEC, VALS(spice_video_codec_type_vs), 0x0,
4227 NULL, HFILL }
4229 { &hf_display_stream_stamp,
4230 { "Stream stamp", "spice.display_stream_stamp",
4231 FT_UINT64, BASE_DEC, NULL, 0x0,
4232 NULL, HFILL }
4234 { &hf_display_stream_data_size,
4235 { "Stream data size", "spice.display_stream_data_size",
4236 FT_UINT32, BASE_DEC, NULL, 0x0,
4237 NULL, HFILL }
4239 { &hf_display_stream_width,
4240 { "Stream width", "spice.stream_width",
4241 FT_UINT32, BASE_DEC, NULL, 0x0,
4242 NULL, HFILL }
4244 { &hf_display_stream_height,
4245 { "Stream height", "spice.stream_height",
4246 FT_UINT32, BASE_DEC, NULL, 0x0,
4247 NULL, HFILL }
4249 { &hf_display_stream_src_width,
4250 { "Stream source width", "spice.stream_src_width",
4251 FT_UINT32, BASE_DEC, NULL, 0x0,
4252 NULL, HFILL }
4254 { &hf_display_stream_src_height,
4255 { "Stream source height", "spice.stream_src_height",
4256 FT_UINT32, BASE_DEC, NULL, 0x0,
4257 NULL, HFILL }
4259 { &hf_display_surface_id,
4260 { "Surface ID", "spice.surface_id",
4261 FT_UINT32, BASE_DEC, NULL, 0x0,
4262 NULL, HFILL }
4264 { &hf_display_surface_width,
4265 { "Surface width", "spice.surface_width",
4266 FT_UINT32, BASE_DEC, NULL, 0x0,
4267 NULL, HFILL }
4269 { &hf_display_surface_height,
4270 { "Surface height", "spice.surface_height",
4271 FT_UINT32, BASE_DEC, NULL, 0x0,
4272 NULL, HFILL }
4274 { &hf_display_surface_format,
4275 { "Surface format", "spice.surface_format",
4276 FT_UINT32, BASE_DEC, NULL, 0x0,
4277 NULL, HFILL }
4279 { &hf_display_surface_flags,
4280 { "Surface flags", "spice.surface_flags",
4281 FT_UINT32, BASE_DEC, VALS(spice_surface_flags_vs), 0x0,
4282 NULL, HFILL }
4284 { &hf_tranparent_src_color,
4285 { "Transparent source color", "spice.display_transparent_src_color",
4286 FT_UINT32, BASE_HEX, NULL, 0x0,
4287 NULL, HFILL }
4289 { &hf_tranparent_true_color,
4290 { "Transparent true color", "spice.display_transparent_true_color",
4291 FT_UINT32, BASE_HEX, NULL, 0x0,
4292 NULL, HFILL }
4294 { &hf_main_client_agent_tokens,
4295 { "Agent tokens", "spice.main_agent_tokens",
4296 FT_UINT32, BASE_DEC, NULL, 0x0,
4297 NULL, HFILL }
4299 { &hf_agent_protocol,
4300 { "Agent Protocol version", "spice.main_agent_protocol",
4301 FT_UINT32, BASE_DEC, NULL, 0x0,
4302 NULL, HFILL }
4304 { &hf_agent_type,
4305 { "Agent message type", "spice.agent_message_type",
4306 FT_UINT32, BASE_DEC, VALS(agent_message_type_vs), 0x0,
4307 NULL, HFILL }
4309 { &hf_agent_opaque,
4310 { "Agent Opaque", "spice.main_agent_opaque",
4311 FT_UINT64, BASE_DEC, NULL, 0x0,
4312 NULL, HFILL }
4314 { &hf_agent_size,
4315 { "Agent message size", "spice.main_agent_size",
4316 FT_UINT32, BASE_DEC, NULL, 0x0,
4317 NULL, HFILL }
4319 { &hf_agent_token,
4320 { "Agent token", "spice.main_agent_token",
4321 FT_UINT32, BASE_DEC, NULL, 0x0,
4322 NULL, HFILL }
4324 { &hf_agent_clipboard_selection,
4325 { "Agent clipboard selection", "spice.main_agent_clipboard_selection",
4326 FT_UINT8, BASE_DEC, NULL, 0x0,
4327 NULL, HFILL }
4329 { &hf_agent_clipboard_type,
4330 { "Agent clipboard type", "spice.main_agent_clipboard_type",
4331 FT_UINT32, BASE_DEC, VALS(agent_clipboard_type), 0x0,
4332 NULL, HFILL }
4334 { &hf_LZ_PLT_type,
4335 { "LZ_PLT image type", "spice.LZ_PLT_type",
4336 FT_UINT32, BASE_DEC, VALS(LzImage_type_vs), 0x0,
4337 NULL, HFILL }
4339 { &hf_spice_sasl_auth_result,
4340 { "Authentication result", "spice.sasl_auth_result",
4341 FT_UINT8, BASE_DEC, VALS(spice_sasl_auth_result_vs), 0x0,
4342 NULL, HFILL }
4344 { &hf_main_uuid,
4345 { "UUID", "spice.main_uuid",
4346 FT_GUID, BASE_NONE, NULL, 0x0,
4347 NULL, HFILL }
4349 { &hf_main_name_len,
4350 { "Name length", "spice.main_name_length",
4351 FT_UINT32, BASE_DEC, NULL, 0x0,
4352 NULL, HFILL }
4354 { &hf_main_name,
4355 { "Name", "spice.main_name",
4356 FT_STRINGZ, BASE_NONE, NULL, 0x0,
4357 NULL, HFILL }
4359 { &hf_display_head_id,
4360 { "Head ID", "spice.display_head_id",
4361 FT_UINT32, BASE_DEC, NULL, 0x0,
4362 NULL, HFILL }
4364 { &hf_display_head_surface_id,
4365 { "Head surface ID", "spice.display_head_surface_id",
4366 FT_UINT32, BASE_DEC, NULL, 0x0,
4367 NULL, HFILL }
4369 { &hf_display_head_width,
4370 { "Head width", "spice.display_head_width",
4371 FT_UINT32, BASE_DEC, NULL, 0x0,
4372 NULL, HFILL }
4374 { &hf_display_head_height,
4375 { "Head height", "spice.display_head_height",
4376 FT_UINT32, BASE_DEC, NULL, 0x0,
4377 NULL, HFILL }
4379 { &hf_display_head_x,
4380 { "Head X coordinate", "spice.display_head_x",
4381 FT_UINT32, BASE_DEC, NULL, 0x0,
4382 NULL, HFILL }
4384 { &hf_display_head_y,
4385 { "Head Y coordinate", "spice.display_head_y",
4386 FT_UINT32, BASE_DEC, NULL, 0x0,
4387 NULL, HFILL }
4389 { &hf_display_head_flags,
4390 { "Head flags", "spice.display_head_flags",
4391 FT_UINT32, BASE_DEC, NULL, 0x0,
4392 NULL, HFILL }
4394 { &hf_zlib_uncompress_size,
4395 { "ZLIB stream uncompressed size", "spice.zlib_uncompress_size",
4396 FT_UINT32, BASE_DEC|BASE_UNIT_STRING, UNS(&units_byte_bytes), 0x0,
4397 NULL, HFILL }
4399 { &hf_zlib_compress_size,
4400 { "ZLIB stream compressed size", "spice.zlib_compress_size",
4401 FT_UINT32, BASE_DEC|BASE_UNIT_STRING, UNS(&units_byte_bytes), 0x0,
4402 NULL, HFILL }
4404 { &hf_rect_left,
4405 { "left", "spice.rect.left",
4406 FT_UINT32, BASE_DEC, NULL, 0x0,
4407 NULL, HFILL }
4409 { &hf_rect_top,
4410 { "top", "spice.rect.top",
4411 FT_UINT32, BASE_DEC, NULL, 0x0,
4412 NULL, HFILL }
4414 { &hf_rect_right,
4415 { "right", "spice.rect.right",
4416 FT_UINT32, BASE_DEC, NULL, 0x0,
4417 NULL, HFILL }
4419 { &hf_rect_bottom,
4420 { "bottom", "spice.rect.bottom",
4421 FT_UINT32, BASE_DEC, NULL, 0x0,
4422 NULL, HFILL }
4424 { &hf_point32_x,
4425 { "x", "spice.point32.x",
4426 FT_INT32, BASE_DEC, NULL, 0x0,
4427 NULL, HFILL }
4429 { &hf_point32_y,
4430 { "y", "spice.point32.y",
4431 FT_INT32, BASE_DEC, NULL, 0x0,
4432 NULL, HFILL }
4434 { &hf_point16_x,
4435 { "x", "spice.point16.x",
4436 FT_INT16, BASE_DEC, NULL, 0x0,
4437 NULL, HFILL }
4439 { &hf_point16_y,
4440 { "y", "spice.point16.y",
4441 FT_INT16, BASE_DEC, NULL, 0x0,
4442 NULL, HFILL }
4444 { &hf_severity,
4445 { "Severity", "spice.notify_severity",
4446 FT_UINT32, BASE_DEC, VALS(spice_notify_severity_vs), 0x0,
4447 NULL, HFILL }
4449 { &hf_visibility,
4450 { "Visibility", "spice.notify_visibility",
4451 FT_UINT32, BASE_DEC, VALS(spice_notify_visibility_vs), 0x0,
4452 NULL, HFILL }
4454 { &hf_notify_code,
4455 { "error/warn/info code", "spice.notify_code",
4456 FT_UINT32, BASE_DEC, NULL, 0x0,
4457 NULL, HFILL }
4459 { &hf_notify_message_len,
4460 { "Message length", "spice.notify_message_length",
4461 FT_UINT32, BASE_DEC, NULL, 0x0,
4462 NULL, HFILL }
4464 { &hf_notify_message,
4465 { "Message", "spice.notify_message",
4466 FT_STRING, BASE_NONE, NULL, 0x0,
4467 NULL, HFILL }
4469 { &hf_num_glyphs,
4470 { "Number of glyphs", "spice.num_glyphs",
4471 FT_UINT16, BASE_DEC, NULL, 0x0,
4472 NULL, HFILL }
4474 { &hf_port_opened,
4475 { "Opened", "spice.port_opened",
4476 FT_UINT8, BASE_DEC, NULL, 0x0,
4477 NULL, HFILL }
4479 { &hf_port_event,
4480 { "Event", "spice.port_event",
4481 FT_UINT8, BASE_DEC, NULL, 0x0,
4482 NULL, HFILL }
4484 { &hf_raw_data,
4485 { "data", "spice.data",
4486 FT_BYTES, BASE_NONE, NULL, 0x0,
4487 NULL, HFILL }
4489 { &hf_display_inval_list_count,
4490 { "count", "spice.display_inval_list_count",
4491 FT_UINT16, BASE_DEC, NULL, 0x0,
4492 NULL, HFILL }
4494 { &hf_resource_type,
4495 { "Type", "spice.resource_type",
4496 FT_UINT8, BASE_DEC, NULL, 0x0,
4497 NULL, HFILL }
4499 { &hf_resource_id,
4500 { "id", "spice.resource_id",
4501 FT_UINT64, BASE_DEC, NULL, 0x0,
4502 NULL, HFILL }
4504 { &hf_ref_image,
4505 { "Image address", "spice.ref_image",
4506 FT_UINT32, BASE_HEX_DEC, NULL, 0x0,
4507 NULL, HFILL }
4509 { &hf_ref_string,
4510 { "String address", "spice.ref_string",
4511 FT_UINT32, BASE_HEX, NULL, 0x0,
4512 NULL, HFILL }
4514 { &hf_agent_num_monitors,
4515 { "Number of monitors", "spice.agent_num_monitors",
4516 FT_UINT32, BASE_DEC, NULL, 0x0,
4517 NULL, HFILL }
4519 { &hf_agent_monitor_height,
4520 { "Height", "spice.agent_monitor_height",
4521 FT_UINT32, BASE_DEC, NULL, 0x0,
4522 NULL, HFILL }
4524 { &hf_agent_monitor_width,
4525 { "Width", "spice.agent_monitor_width",
4526 FT_UINT32, BASE_DEC, NULL, 0x0,
4527 NULL, HFILL }
4529 { &hf_agent_monitor_depth,
4530 { "Depth", "spice.agent_monitor_depth",
4531 FT_UINT32, BASE_DEC, NULL, 0x0,
4532 NULL, HFILL }
4534 { &hf_agent_monitor_x,
4535 { "x", "spice.agent_monitor_x",
4536 FT_INT32, BASE_DEC, NULL, 0x0,
4537 NULL, HFILL }
4539 { &hf_agent_monitor_y,
4540 { "y", "spice.agent_monitor_y",
4541 FT_INT32, BASE_DEC, NULL, 0x0,
4542 NULL, HFILL }
4544 { &hf_vd_agent_buttons,
4545 { "Buttons", "spice.vd_agent_buttons",
4546 FT_UINT32, BASE_DEC, NULL, 0x0,
4547 NULL, HFILL }
4549 { &hf_vd_agent_caps_request,
4550 { "Request", "spice.vd_agent_caps_request",
4551 FT_UINT32, BASE_DEC, NULL, 0x0,
4552 NULL, HFILL }
4554 { &hf_vd_agent_cap_mouse_state,
4555 { "Mouse State", "spice.vd_agent_cap_mouse_state",
4556 FT_BOOLEAN, 32, TFS(&tfs_set_notset), VD_AGENT_CAP_MOUSE_STATE,
4557 NULL, HFILL }
4559 { &hf_vd_agent_cap_monitors_config,
4560 { "Monitors config", "spice.vd_agent_cap_monitors_config",
4561 FT_BOOLEAN, 32, TFS(&tfs_set_notset), VD_AGENT_CAP_MONITORS_CONFIG,
4562 NULL, HFILL }
4564 { &hf_vd_agent_cap_reply,
4565 { "Reply", "spice.vd_agent_cap_reply",
4566 FT_BOOLEAN, 32, TFS(&tfs_set_notset), VD_AGENT_CAP_REPLY,
4567 NULL, HFILL }
4569 { &hf_vd_agent_cap_clipboard,
4570 { "Clipboard", "spice.vd_agent_cap_clipboard",
4571 FT_BOOLEAN, 32, TFS(&tfs_set_notset), VD_AGENT_CAP_CLIPBOARD,
4572 NULL, HFILL }
4574 { &hf_vd_agent_cap_display_config,
4575 { "Display config", "spice.vd_agent_cap_display_config",
4576 FT_BOOLEAN, 32, TFS(&tfs_set_notset), VD_AGENT_CAP_DISPLAY_CONFIG,
4577 NULL, HFILL }
4579 { &hf_vd_agent_cap_clipboard_by_demand,
4580 { "Clipboard by demand", "spice.vd_agent_cap_clipboard_by_demand",
4581 FT_BOOLEAN, 32, TFS(&tfs_set_notset), VD_AGENT_CAP_CLIPBOARD_BY_DEMAND,
4582 NULL, HFILL }
4584 { &hf_vd_agent_cap_clipboard_selection,
4585 { "Clipboard selection", "spice.vd_agent_cap_clipboard_selection",
4586 FT_BOOLEAN, 32, TFS(&tfs_set_notset), VD_AGENT_CAP_CLIPBOARD_SELECTION,
4587 NULL, HFILL }
4589 { &hf_vd_agent_cap_sparse_monitors_config,
4590 { "Sparse monitors config", "spice.vd_agent_cap_sparse_monitors_config",
4591 FT_BOOLEAN, 32, TFS(&tfs_set_notset), VD_AGENT_CAP_SPARSE_MONITORS_CONFIG,
4592 NULL, HFILL }
4594 { &hf_vd_agent_cap_guest_lineend_lf,
4595 { "Guest line-end LF", "spice.vd_agent_cap_guest_lineend_lf",
4596 FT_BOOLEAN, 32, TFS(&tfs_set_notset), VD_AGENT_CAP_GUEST_LINEEND_LF,
4597 NULL, HFILL }
4599 { &hf_vd_agent_cap_guest_lineend_crlf,
4600 { "Guest line-end CRLF", "spice.vd_agent_cap_guest_lineend_crlf",
4601 FT_BOOLEAN, 32, TFS(&tfs_set_notset), VD_AGENT_CAP_GUEST_LINEEND_CRLF,
4602 NULL, HFILL }
4604 { &hf_vd_agent_monitors_config_flag_use_pos,
4605 { "Use position", "spice.vd_agent_monitors_config_flag_use_pos",
4606 FT_BOOLEAN, 32, TFS(&tfs_set_notset), VD_AGENT_CONFIG_MONITORS_FLAG_USE_POS,
4607 NULL, HFILL }
4609 { &hf_vd_agent_reply_type,
4610 { "Type", "spice.vd_agent_reply_type",
4611 FT_UINT32, BASE_DEC, NULL, 0x0,
4612 NULL, HFILL }
4614 { &hf_vd_agent_reply_error,
4615 { "Error", "spice.vd_agent_reply_error",
4616 FT_UINT32, BASE_DEC, VALS(vd_agent_reply_error_vs), 0x0,
4617 NULL, HFILL }
4619 /* Generated from convert_proto_tree_add_text.pl */
4620 { &hf_spice_pixmap_pixels, { "Pixmap pixels", "spice.pixmap_pixels", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
4621 { &hf_spice_palette, { "Palette", "spice.palette", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
4622 { &hf_spice_cursor_data, { "Cursor data", "spice.cursor_data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
4623 { &hf_spice_quic_image_size, { "QUIC image size", "spice.quic_image_size", FT_UINT32, BASE_DEC|BASE_UNIT_STRING, UNS(&units_byte_bytes), 0x0, NULL, HFILL }},
4624 { &hf_spice_quic_magic, { "QUIC magic", "spice.quic_magic", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
4625 { &hf_spice_quic_compressed_image_data, { "QUIC compressed image data", "spice.quic_compressed_image_data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
4626 { &hf_spice_lz_magic, { "LZ magic", "spice.lz_magic", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
4627 { &hf_spice_lz_rgb_compressed_image_data, { "LZ_RGB compressed image data", "spice.lz_rgb_compressed_image_data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
4628 { &hf_spice_topdown_flag, { "Topdown flag", "spice.topdown_flag", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
4629 { &hf_spice_unknown_bytes, { "Unknown bytes", "spice.unknown_bytes", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
4630 #if 0
4631 { &hf_spice_lz_jpeg_image_size, { "LZ JPEG image size", "spice.lz_jpeg_image_size", FT_UINT32, BASE_DEC|BASE_UNIT_STRING, UNS(&units_byte_bytes), 0x0, NULL, HFILL }},
4632 #endif
4633 { &hf_spice_glz_rgb_image_size, { "GLZ RGB image size", "spice.glz_rgb_image_size", FT_UINT32, BASE_DEC|BASE_UNIT_STRING, UNS(&units_byte_bytes), 0x0, NULL, HFILL }},
4634 { &hf_spice_lz_rgb_image_size, { "LZ RGB image size", "spice.lz_rgb_image_size", FT_UINT32, BASE_DEC|BASE_UNIT_STRING, UNS(&units_byte_bytes), 0x0, NULL, HFILL }},
4635 { &hf_spice_lz_plt_flag, { "LZ_PLT Flag", "spice.lz_plt_flag", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
4636 { &hf_spice_lz_plt_image_size, { "LZ PLT image size", "spice.lz_plt_image_size", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
4637 { &hf_spice_palette_offset, { "palette offset", "spice.palette_offset", FT_UINT32, BASE_DEC|BASE_UNIT_STRING, UNS(&units_byte_bytes), 0x0, NULL, HFILL }},
4638 { &hf_spice_lz_plt_data, { "LZ_PLT data", "spice.lz_plt_data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
4639 { &hf_spice_zlib_stream, { "ZLIB stream", "spice.zlib_stream", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
4640 { &hf_spice_image_from_cache, { "Image from Cache", "spice.image_from_cache", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
4641 { &hf_spice_surface_id, { "Surface ID", "spice.surface_id", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
4642 { &hf_spice_image_from_cache_lossless, { "Image from Cache - lossless", "spice.image_from_cache_lossless", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
4643 { &hf_spice_ping_data, { "PING DATA", "spice.ping_data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
4644 { &hf_spice_display_mark_message, { "DISPLAY_MARK message", "spice.display_mark_message", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
4645 { &hf_spice_display_reset_message, { "DISPLAY_RESET message", "spice.display_reset_message", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
4646 { &hf_spice_rop3, { "ROP3", "spice.rop3", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
4647 { &hf_spice_scale_mode, { "scale mode", "spice.scale_mode", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
4648 { &hf_spice_glyph_flags, { "Glyph flags", "spice.glyph_flags", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }},
4649 { &hf_spice_stream_data, { "Stream data", "spice.stream_data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
4650 { &hf_spice_vd_agent_clipboard_message, { "VD_AGENT_CLIPBOARD message", "spice.vd_agent_clipboard_message", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
4651 { &hf_spice_vd_agent_display_config_message, { "VD_AGENT_DISPLAY_CONFIG message", "spice.vd_agent_display_config_message", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
4652 { &hf_spice_reserved, { "Reserved", "spice.reserved", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
4653 { &hf_spice_vd_agent_clipboard_release_message, { "VD_AGENT_CLIPBOARD_RELEASE message", "spice.vd_agent_clipboard_release_message", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
4654 { &hf_spice_server_inputs_mouse_motion_ack_message, { "Server INPUTS_MOUSE_MOTION_ACK message", "spice.server_inputs_mouse_motion_ack_message", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
4655 { &hf_spice_name_length, { "Name length (bytes)", "spice.name_length", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
4656 { &hf_spice_x509_subjectpublickeyinfo, { "X.509 SubjectPublicKeyInfo (ASN.1)", "spice.x509_subjectpublickeyinfo", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
4657 { &hf_spice_sasl_message_length, { "SASL message length", "spice.sasl_message_length", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
4658 { &hf_spice_supported_authentication_mechanisms_list_length, { "Supported authentication mechanisms list length", "spice.supported_authentication_mechanisms_list_length", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
4659 { &hf_spice_supported_authentication_mechanisms_list, { "Supported authentication mechanisms list", "spice.supported_authentication_mechanisms_list", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
4660 { &hf_spice_selected_authentication_mechanism_length, { "Selected authentication mechanism length", "spice.selected_authentication_mechanism_length", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
4661 { &hf_spice_selected_authentication_mechanism, { "Selected authentication mechanism", "spice.selected_authentication_mechanism", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
4662 { &hf_spice_client_out_mechanism_length, { "Client out mechanism length", "spice.client_out_mechanism_length", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
4663 { &hf_spice_selected_client_out_mechanism, { "Selected client out mechanism", "spice.selected_client_out_mechanism", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
4664 { &hf_spice_sasl_authentication_data, { "SASL authentication data", "spice.sasl_authentication_data", FT_STRINGZ, BASE_NONE, NULL, 0x0, NULL, HFILL }},
4665 { &hf_spice_clientout_length, { "clientout length", "spice.clientout_length", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
4666 { &hf_spice_clientout_list, { "clientout list", "spice.clientout_list", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
4667 { &hf_spice_sasl_data, { "SASL data", "spice.sasl_data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
4670 /* Setup protocol subtree arrays */
4671 static int *ett[] = {
4672 &ett_spice,
4673 &ett_link_client,
4674 &ett_link_server,
4675 &ett_link_caps,
4676 &ett_ticket_client,
4677 &ett_auth_select_client,
4678 &ett_ticket_server,
4679 &ett_data,
4680 &ett_message,
4681 &ett_playback,
4682 &ett_common_server_message,
4683 &ett_common_client_message,
4684 &ett_display_client,
4685 &ett_display_server,
4686 &ett_point,
4687 &ett_point16,
4688 &ett_rect,
4689 &ett_DisplayBase,
4690 &ett_Clip,
4691 &ett_Mask,
4692 &ett_imagedesc,
4693 &ett_imageQuic,
4694 &ett_GLZ_RGB,
4695 &ett_LZ_RGB,
4696 &ett_ZLIB_GLZ,
4697 &ett_Uncomp_tree,
4698 &ett_LZ_JPEG,
4699 &ett_LZ_PLT,
4700 &ett_JPEG,
4701 &ett_cursor_header,
4702 &ett_RedCursor,
4703 &ett_cursor,
4704 &ett_spice_main,
4705 &ett_brush,
4706 &ett_pattern,
4707 &ett_Pixmap,
4708 &ett_SpiceHead,
4709 &ett_inputs_client,
4710 &ett_rectlist,
4711 &ett_inputs_server,
4712 &ett_record_client,
4713 &ett_record_server,
4714 &ett_main_client,
4715 &ett_spice_agent,
4716 &ett_cap_tree
4719 static ei_register_info ei[] = {
4720 { &ei_spice_decompress_error, { "spice.decompress_error", PI_PROTOCOL, PI_WARN, "Error: Unable to decompress content", EXPFILL }},
4721 { &ei_spice_unknown_message, { "spice.unknown_message", PI_UNDECODED, PI_WARN, "Unknown message - cannot dissect", EXPFILL }},
4722 { &ei_spice_not_dissected, { "spice.not_dissected", PI_UNDECODED, PI_WARN, "Message not dissected", EXPFILL }},
4723 { &ei_spice_auth_unknown, { "spice.auth_unknown", PI_PROTOCOL, PI_WARN, "Unknown authentication selected", EXPFILL }},
4724 { &ei_spice_sasl_auth_result, { "spice.sasl_auth_result.expert", PI_PROTOCOL, PI_WARN, "Bad sasl_auth_result", EXPFILL }},
4725 { &ei_spice_expected_from_client, { "spice.expected_from_client", PI_PROTOCOL, PI_WARN, "SPICE_CLIENT_AUTH_SELECT: packet from server - expected from client", EXPFILL }},
4726 /* Generated from convert_proto_tree_add_text.pl */
4727 { &ei_spice_unknown_image_type, { "spice.unknown_image_type", PI_UNDECODED, PI_WARN, "Unknown image type - cannot dissect", EXPFILL }},
4728 { &ei_spice_brush_type, { "spice.brush_type.invalid", PI_PROTOCOL, PI_WARN, "Invalid Brush type", EXPFILL }},
4729 { &ei_spice_Mask_flag, { "spice.mask_flag.irrelevant", PI_PROTOCOL, PI_NOTE, "value irrelevant as bitmap address is 0", EXPFILL }},
4730 { &ei_spice_Mask_point, { "spice.mask_point.irrelevant", PI_PROTOCOL, PI_NOTE, "value irrelevant as bitmap address is 0", EXPFILL }},
4731 { &ei_spice_unknown_channel, { "spice.unknown_channel", PI_UNDECODED, PI_WARN, "Unknown channel - cannot dissect", EXPFILL }},
4732 { &ei_spice_common_cap_unknown, { "spice.common_cap.unknown", PI_PROTOCOL, PI_WARN, "Unknown common capability", EXPFILL }},
4735 expert_module_t* expert_spice;
4737 /* Register the protocol name and description */
4738 proto_spice = proto_register_protocol("Spice protocol", "Spice", "spice");
4740 /* Register the dissector handle */
4741 spice_handle = register_dissector("spice", dissect_spice, proto_spice);
4743 /* Required function calls to register the header fields and subtrees */
4744 proto_register_field_array(proto_spice, hf, array_length(hf));
4745 proto_register_subtree_array(ett, array_length(ett));
4746 expert_spice = expert_register_protocol(proto_spice);
4747 expert_register_field_array(expert_spice, ei, array_length(ei));
4751 void
4752 proto_reg_handoff_spice(void)
4754 dissector_add_for_decode_as_with_preference("tcp.port", spice_handle);
4755 heur_dissector_add("tcp", test_spice_protocol, "Spice over TCP", "spice_tcp", proto_spice, HEURISTIC_ENABLE);
4756 jpeg_handle = find_dissector_add_dependency("image-jfif", proto_spice);
4760 * Editor modelines - https://www.wireshark.org/tools/modelines.html
4762 * Local variables:
4763 * c-basic-offset: 4
4764 * tab-width: 8
4765 * indent-tabs-mode: nil
4766 * End:
4768 * vi: set shiftwidth=4 tabstop=8 expandtab:
4769 * :indentSize=4:tabSize=8:noTabs=true: