2 * Routines for X11 dissection
3 * Copyright 2000, Christophe Tronche <ch.tronche@computer.org>
5 * $Id: packet-x11.c,v 1.41 2002/04/17 08:33:08 guy Exp $
7 * Ethereal - Network traffic analyzer
8 * By Gerald Combs <gerald@ethereal.com>
9 * Copyright 1998 Gerald Combs
11 * Copied from README.developer
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
28 /* TODO (in no particular order):
30 * - keep track of Atom creation by server to be able to display
31 * non-predefined atoms
32 * - Idem for keysym <-> keycode ???
34 * - Subtree the request ids (that is x11.create-window.window and
35 * x11.change-window.window should be distinct), and add hidden fields
36 * (so we still have x11.window).
37 * - add hidden fields so we can have x11.circulate-window in addition to
38 * x11.opcode == 13 (but you could match on x11.opcode == "CirculateWindow"
40 * - add hidden fields so we have x11.listOfStuff.length
41 * - use a faster scheme that linear list searching for the opcode.
42 * - correct display of Unicode chars.
43 * - Not everything is homogeneous, in particular the handling of items in
44 * list is a total mess.
47 /* By the way, I wrote a program to generate every request and test
48 * that stuff. If you're interested, you can get it at
49 * http://tronche.com/gui/x/
61 #ifdef HAVE_SYS_TYPES_H
62 # include <sys/types.h>
67 #include <epan/packet.h>
68 #include <epan/conversation.h>
71 #include "packet-frame.h"
73 #define cVALS(x) (const value_string*)(x)
75 /* Initialize the protocol and registered fields */
76 static int proto_x11 = -1;
78 #include "x11-declarations.h"
80 /* Initialize the subtree pointers */
81 static gint ett_x11 = -1;
82 static gint ett_x11_color_flags = -1;
83 static gint ett_x11_list_of_arc = -1;
84 static gint ett_x11_arc = -1;
85 static gint ett_x11_list_of_atom = -1;
86 static gint ett_x11_list_of_card32 = -1;
87 static gint ett_x11_list_of_color_item = -1;
88 static gint ett_x11_color_item = -1;
89 static gint ett_x11_list_of_keycode = -1;
90 static gint ett_x11_list_of_keysyms = -1;
91 static gint ett_x11_keysym = -1;
92 static gint ett_x11_list_of_point = -1;
93 static gint ett_x11_point = -1;
94 static gint ett_x11_list_of_rectangle = -1;
95 static gint ett_x11_rectangle = -1;
96 static gint ett_x11_list_of_segment = -1;
97 static gint ett_x11_segment = -1;
98 static gint ett_x11_list_of_string8 = -1;
99 static gint ett_x11_list_of_text_item = -1;
100 static gint ett_x11_text_item = -1;
101 static gint ett_x11_gc_value_mask = -1;
102 static gint ett_x11_event_mask = -1;
103 static gint ett_x11_do_not_propagate_mask = -1;
104 static gint ett_x11_set_of_key_mask = -1;
105 static gint ett_x11_pointer_event_mask = -1;
106 static gint ett_x11_window_value_mask = -1;
107 static gint ett_x11_configure_window_mask = -1;
108 static gint ett_x11_keyboard_value_mask = -1;
110 /* desegmentation of X11 messages */
111 static gboolean x11_desegment = TRUE;
113 static dissector_handle_t data_handle;
115 #define TCP_PORT_X11 6000
116 #define TCP_PORT_X11_2 6001
117 #define TCP_PORT_X11_3 6002
120 * Round a length to a multiple of 4 bytes.
122 #define ROUND_LENGTH(n) ((((n) + 3)/4) * 4)
124 /************************************************************************
126 *** E N U M T A B L E S D E F I N I T I O N S ***
128 ************************************************************************/
130 static const value_string byte_order_vals[] = {
131 { 'B', "Big-endian" },
132 { 'l', "Little-endian" },
136 static const value_string access_mode_vals[] = {
142 static const value_string all_temporary_vals[] = {
143 { 0, "AllTemporary" },
147 static const value_string alloc_vals[] = {
153 static const value_string allow_events_mode_vals[] = {
154 { 0, "AsyncPointer" },
155 { 1, "SyncPointer" },
156 { 2, "ReplayPointer" },
157 { 3, "AsyncKeyboard" },
158 { 4, "SyncKeyboard" },
159 { 5, "ReplayKeyboard" },
165 static const value_string arc_mode_vals[] = {
171 static const char *atom_predefined_interpretation[] = {
223 "UNDERLINE_POSITION",
224 "UNDERLINE_THICKNESS",
243 static const value_string auto_repeat_mode_vals[] = {
250 static const value_string background_pixmap_vals[] = {
252 { 1, "ParentRelative" },
256 static const value_string backing_store_vals[] = {
263 static const value_string border_pixmap_vals[] = {
264 { 0, "CopyFromParent" },
268 static const value_string button_vals[] = {
269 { 0x8000, "AnyButton" },
273 static const value_string cap_style_vals[] = {
281 static const value_string class_vals[] = {
288 static const value_string close_down_mode_vals[] = {
290 { 1, "RetainPermanent" },
291 { 2, "RetainTemporary" },
295 static const value_string coordinate_mode_vals[] = {
301 static const value_string direction_vals[] = {
302 { 0, "RaiseLowest" },
303 { 1, "LowerHighest" },
307 #define FAMILY_INTERNET 0
308 #define FAMILY_DECNET 1
309 #define FAMILY_CHAOS 2
311 static const value_string family_vals[] = {
312 { FAMILY_INTERNET, "Internet" },
313 { FAMILY_DECNET, "DECnet" },
314 { FAMILY_CHAOS, "Chaos" },
318 static const value_string fill_rule_vals[] = {
324 static const value_string fill_style_vals[] = {
328 { 3, "OpaqueStippled" },
332 static const value_string focus_vals[] = {
334 { 1, "PointerRoot" },
338 static const value_string function_vals[] = {
343 { 4, "AndInverted" },
351 { 12, "CopyInverted" },
352 { 13, "OrInverted" },
358 static const value_string gravity_vals[] = {
372 static const value_string image_format_vals[] = {
379 static const value_string image_pixmap_format_vals[] = {
385 static const value_string join_style_vals[] = {
392 static const value_string key_vals[] = {
397 #include "packet-x11-keysym.h"
399 static const value_string line_style_vals[] = {
406 static const value_string mode_vals[] = {
413 static const value_string on_off_vals[] = {
419 static const value_string opcode_vals[] = {
420 { 1, "CreateWindow" },
421 { 2, "ChangeWindowAttributes" },
422 { 3, "GetWindowAttributes" },
423 { 4, "DestroyWindow" },
424 { 5, "DestroySubwindows" },
425 { 6, "ChangeSaveSet" },
426 { 7, "ReparentWindow" },
428 { 9, "MapSubwindows" },
429 { 10, "UnmapWindow" },
430 { 11, "UnmapSubwindows" },
431 { 12, "ConfigureWindow" },
432 { 13, "CirculateWindow" },
433 { 14, "GetGeometry" },
435 { 16, "InternAtom" },
436 { 17, "GetAtomName" },
437 { 18, "ChangeProperty" },
438 { 19, "DeleteProperty" },
439 { 20, "GetProperty" },
440 { 21, "ListProperties" },
441 { 22, "SetSelectionOwner" },
442 { 23, "GetSelectionOwner" },
443 { 24, "ConvertSelection" },
445 { 26, "GrabPointer" },
446 { 27, "UngrabPointer" },
447 { 28, "GrabButton" },
448 { 29, "UngrabButton" },
449 { 30, "ChangeActivePointerGrab" },
450 { 31, "GrabKeyboard" },
451 { 32, "UngrabKeyboard" },
454 { 35, "AllowEvents" },
455 { 36, "GrabServer" },
456 { 37, "UngrabServer" },
457 { 38, "QueryPointer" },
458 { 39, "GetMotionEvents" },
459 { 40, "TranslateCoordinates" },
460 { 41, "WarpPointer" },
461 { 42, "SetInputFocus" },
462 { 43, "GetInputFocus" },
463 { 44, "QueryKeymap" },
467 { 48, "QueryTextExtents" },
469 { 50, "ListFontsWithInfo" },
470 { 51, "SetFontPath" },
471 { 52, "GetFontPath" },
472 { 53, "CreatePixmap" },
473 { 54, "FreePixmap" },
478 { 59, "SetClipRectangles" },
485 { 66, "PolySegment" },
486 { 67, "PolyRectangle" },
489 { 70, "PolyFillRectangle" },
490 { 71, "PolyFillArc" },
494 { 75, "PolyText16" },
495 { 76, "ImageText8" },
496 { 77, "ImageText16" },
497 { 78, "CreateColormap" },
498 { 79, "FreeColormap" },
499 { 80, "CopyColormapAndFree" },
500 { 81, "InstallColormap" },
501 { 82, "UninstallColormap" },
502 { 83, "ListInstalledColormaps" },
503 { 84, "AllocColor" },
504 { 85, "AllocNamedColor" },
505 { 86, "AllocColorCells" },
506 { 87, "AllocColorPlanes" },
507 { 88, "FreeColors" },
508 { 89, "StoreColors" },
509 { 90, "StoreNamedColor" },
510 { 91, "QueryColors" },
511 { 92, "LookupColor" },
512 { 93, "CreateCursor" },
513 { 94, "CreateGlyphCursor" },
514 { 95, "FreeCursor" },
515 { 96, "RecolorCursor" },
516 { 97, "QueryBestSize" },
517 { 98, "QueryExtension" },
518 { 99, "ListExtensions" },
519 { 100, "ChangeKeyboardMapping" },
520 { 101, "GetKeyboardMapping" },
521 { 102, "ChangeKeyboardControl" },
522 { 103, "GetKeyboardControl" },
524 { 105, "ChangePointerControl" },
525 { 106, "GetPointerControl" },
526 { 107, "SetScreenSaver" },
527 { 108, "GetScreenSaver" },
528 { 109, "ChangeHosts" },
529 { 110, "ListHosts" },
530 { 111, "SetAccessControl" },
531 { 112, "SetCloseDownMode" },
532 { 113, "KillClient" },
533 { 114, "RotateProperties" },
534 { 115, "ForceScreenSaver" },
535 { 116, "SetPointerMapping" },
536 { 117, "GetPointerMapping" },
537 { 118, "SetModifierMapping" },
538 { 119, "GetModifierMapping" },
539 { 127, "NoOperation" },
543 static const value_string ordering_vals[] = {
551 static const value_string plane_mask_vals[] = {
552 { 0xFFFFFFFF, "AllPlanes" },
556 static const value_string pointer_keyboard_mode_vals[] = {
557 { 0, "Synchronous" },
558 { 1, "Asynchronous" },
562 static const value_string revert_to_vals[] = {
564 { 1, "PointerRoot" },
569 static const value_string insert_delete_vals[] = {
575 static const value_string screen_saver_mode_vals[] = {
581 static const value_string shape_vals[] = {
588 static const value_string stack_mode_vals[] = {
597 static const value_string subwindow_mode_vals[] = {
598 { 0, "ClipByChildren" },
599 { 1, "IncludeInferiors" },
603 static const value_string window_class_vals[] = {
604 { 0, "CopyFromParent" },
605 { 1, "InputOutput" },
610 static const value_string yes_no_default_vals[] = {
617 static const value_string zero_is_any_property_type_vals[] = {
618 { 0, "AnyPropertyType" },
622 static const value_string zero_is_none_vals[] = {
627 /************************************************************************
629 *** G L O B A L V A R I A B L E S ( A R G H H ! ) ***
631 ************************************************************************/
633 static gboolean little_endian = TRUE;
635 /************************************************************************
637 *** F I E L D D E C O D I N G M A C R O S ***
639 ************************************************************************/
641 #define VALUE8(tvb, offset) (tvb_get_guint8(tvb, offset))
642 #define VALUE16(tvb, offset) (little_endian ? tvb_get_letohs(tvb, offset) : tvb_get_ntohs(tvb, offset))
643 #define VALUE32(tvb, offset) (little_endian ? tvb_get_letohl(tvb, offset) : tvb_get_ntohl(tvb, offset))
645 #define FIELD8(name) (field8(tvb, offsetp, t, hf_x11_##name))
646 #define FIELD16(name) (field16(tvb, offsetp, t, hf_x11_##name))
647 #define FIELD32(name) (field32(tvb, offsetp, t, hf_x11_##name))
649 #define BITFIELD(TYPE, position, name) {\
651 int save = *offsetp;\
652 proto_tree_add_item(bitmask_tree, hf_x11_##position##_##name, tvb, bitmask_offset, \
653 bitmask_size, little_endian); \
654 if (bitmask_value & proto_registrar_get_nth(hf_x11_##position##_##name) -> bitmask) {\
656 unused = save + 4 - *offsetp;\
658 proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, unused, little_endian);\
659 *offsetp = save + 4;\
663 #define FLAG(position, name) {\
664 proto_tree_add_boolean(bitmask_tree, hf_x11_##position##_mask##_##name, tvb, bitmask_offset, bitmask_size, bitmask_value); }
666 #define FLAG_IF_NONZERO(position, name) {\
667 if (bitmask_value & proto_registrar_get_nth(hf_x11_##position##_mask##_##name) -> bitmask)\
668 proto_tree_add_boolean(bitmask_tree, hf_x11_##position##_mask##_##name, tvb, bitmask_offset, bitmask_size, bitmask_value); }
670 #define ATOM(name) { atom(tvb, offsetp, t, hf_x11_##name); }
671 #define BITGRAVITY(name) { gravity(tvb, offsetp, t, #name, hf_x11_##name, "Forget"); }
672 #define BITMASK(name, size) {\
674 guint32 bitmask_value; \
675 int bitmask_offset; \
677 proto_tree *bitmask_tree; \
678 bitmask_value = ((size == 1) ? VALUE8(tvb, *offsetp) : \
679 ((size == 2) ? VALUE16(tvb, *offsetp) : \
680 VALUE32(tvb, *offsetp))); \
681 bitmask_offset = *offsetp; \
682 bitmask_size = size; \
683 ti = proto_tree_add_uint(t, hf_x11_##name##_mask, tvb, *offsetp, size, bitmask_value); \
684 bitmask_tree = proto_item_add_subtree(ti, ett_x11_##name##_mask); \
687 #define BITMASK8(name) BITMASK(name, 1);
688 #define BITMASK16(name) BITMASK(name, 2);
689 #define BITMASK32(name) BITMASK(name, 4);
690 #define BOOL(name) (add_boolean(tvb, offsetp, t, hf_x11_##name))
691 #define BUTTON(name) { FIELD8(name); }
692 #define CARD8(name) { FIELD8(name); }
693 #define CARD16(name) (FIELD16(name))
694 #define CARD32(name) (FIELD32(name))
695 #define COLOR_FLAGS(name) { colorFlags(tvb, offsetp, t); }
696 #define COLORMAP(name) { FIELD32(name); }
697 #define CURSOR(name) { FIELD32(name); }
698 #define DRAWABLE(name) { FIELD32(name); }
699 #define ENUM8(name) (FIELD8(name))
700 #define ENUM16(name) { FIELD16(name); }
701 #define FONT(name) { FIELD32(name); }
702 #define FONTABLE(name) { FIELD32(name); }
703 #define GCONTEXT(name) { FIELD32(name); }
704 #define INT8(name) { FIELD8(name); }
705 #define INT16(name) { FIELD16(name); }
706 #define KEYCODE(name) { FIELD8(name); }
707 #define LISTofARC(name) { listOfArc(tvb, offsetp, t, hf_x11_##name, (next_offset - *offsetp) / 12); }
708 #define LISTofATOM(name, length) { listOfAtom(tvb, offsetp, t, hf_x11_##name, (length) / 4); }
709 #define LISTofBYTE(name, length) { listOfByte(tvb, offsetp, t, hf_x11_##name, (length)); }
710 #define LISTofCARD8(name, length) { listOfByte(tvb, offsetp, t, hf_x11_##name, (length)); }
711 #define LISTofCARD32(name, length) { listOfCard32(tvb, offsetp, t, hf_x11_##name, hf_x11_##name##_item, (length) / 4); }
712 #define LISTofCOLORITEM(name, length) { listOfColorItem(tvb, offsetp, t, hf_x11_##name, (length) / 12); }
713 #define LISTofKEYCODE(name, length) { listOfKeycode(tvb, offsetp, t, hf_x11_##name, (length)); }
714 #define LISTofKEYSYM(name, keycode_count, keysyms_per_keycode) { \
715 listOfKeysyms(tvb, offsetp, t, hf_x11_##name, hf_x11_##name##_item, (keycode_count), (keysyms_per_keycode)); }
716 #define LISTofPOINT(name, length) { listOfPoint(tvb, offsetp, t, hf_x11_##name, (length) / 4); }
717 #define LISTofRECTANGLE(name) { listOfRectangle(tvb, offsetp, t, hf_x11_##name, (next_offset - *offsetp) / 8); }
718 #define LISTofSEGMENT(name) { listOfSegment(tvb, offsetp, t, hf_x11_##name, (next_offset - *offsetp) / 8); }
719 #define LISTofSTRING8(name, length) { listOfString8(tvb, offsetp, t, hf_x11_##name, hf_x11_##name##_string, (length)); }
720 #define LISTofTEXTITEM8(name) { listOfTextItem(tvb, offsetp, t, hf_x11_##name, FALSE, next_offset); }
721 #define LISTofTEXTITEM16(name) { listOfTextItem(tvb, offsetp, t, hf_x11_##name, TRUE, next_offset); }
722 #define OPCODE() { opcode = FIELD8(opcode); }
723 #define PIXMAP(name) { FIELD32(name); }
724 #define REQUEST_LENGTH() (requestLength(tvb, offsetp, t))
725 #define SETofEVENT(name) { setOfEvent(tvb, offsetp, t); }
726 #define SETofDEVICEEVENT(name) { setOfDeviceEvent(tvb, offsetp, t);}
727 #define SETofKEYMASK(name) { setOfKeyMask(tvb, offsetp, t); }
728 #define SETofPOINTEREVENT(name) { setOfPointerEvent(tvb, offsetp, t); }
729 #define STRING8(name, length) { string8(tvb, offsetp, t, #name, hf_x11_##name, length); }
730 #define STRING16(name, length) { string16(tvb, offsetp, t, hf_x11_##name, hf_x11_##name##_bytes, length); }
731 #define TIMESTAMP(name){ timestamp(tvb, offsetp, t, #name, hf_x11_##name); }
732 #define UNDECODED(x) { proto_tree_add_item(t, hf_x11_undecoded, tvb, *offsetp, x, little_endian); *offsetp += x; }
733 #define UNUSED(x) { proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, x, little_endian); *offsetp += x; }
734 #define PAD() { if (next_offset - *offsetp > 0) proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, next_offset - *offsetp, little_endian); *offsetp = next_offset; }
735 #define WINDOW(name) { FIELD32(name); }
736 #define WINGRAVITY(name) { gravity(tvb, offsetp, t, #name, hf_x11_##name, "Unmap"); }
738 #define VISUALID(name) { gint32 v = VALUE32(tvb, *offsetp); \
739 proto_tree_add_uint_format(t, hf_x11_##name, tvb, *offsetp, 4, v, "Visualid: 0x%08x%s", v, \
740 v ? "" : " (CopyFromParent)"); *offsetp += 4; }
742 /************************************************************************
744 *** D E C O D I N G F I E L D S ***
746 ************************************************************************/
748 static void atom(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf)
750 const char *interpretation = NULL;
752 guint32 v = VALUE32(tvb, *offsetp);
753 if (v >= 1 && v < array_length(atom_predefined_interpretation))
754 interpretation = atom_predefined_interpretation[v];
756 interpretation = "Not a predefined atom";
758 header_field_info *hfi = proto_registrar_get_nth(hf);
760 interpretation = match_strval(v, cVALS(hfi -> strings));
762 if (!interpretation) interpretation = "error in Xlib client program ?";
763 proto_tree_add_uint_format(t, hf, tvb, *offsetp, 4, v, "%s: %u (%s)",
764 proto_registrar_get_nth(hf) -> name, v, interpretation);
768 static guint32 add_boolean(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf)
770 guint32 v = VALUE8(tvb, *offsetp);
771 proto_tree_add_boolean(t, hf, tvb, *offsetp, 1, v);
776 static void colorFlags(tvbuff_t *tvb, int *offsetp, proto_tree *t)
778 unsigned do_red_green_blue = VALUE8(tvb, *offsetp);
782 if (do_red_green_blue) {
785 char *bp = buffer + sprintf(buffer, "flags: ");
787 if (do_red_green_blue & 0x1) {
788 bp += sprintf(bp, "DoRed");
792 if (do_red_green_blue & 0x2) {
793 if (sep) bp += sprintf(bp, " | ");
794 bp += sprintf(bp, "DoGreen");
798 if (do_red_green_blue & 0x4) {
799 if (sep) bp += sprintf(bp, " | ");
800 bp += sprintf(bp, "DoBlue");
804 if (do_red_green_blue & 0xf8) {
805 if (sep) bp += sprintf(bp, " + ");
806 sprintf(bp, "trash");
809 ti = proto_tree_add_uint_format(t, hf_x11_coloritem_flags, tvb, *offsetp, 1, do_red_green_blue,
811 tt = proto_item_add_subtree(ti, ett_x11_color_flags);
812 if (do_red_green_blue & 0x1)
813 proto_tree_add_boolean(tt, hf_x11_coloritem_flags_do_red, tvb, *offsetp, 1,
814 do_red_green_blue & 0x1);
815 if (do_red_green_blue & 0x2)
816 proto_tree_add_boolean(tt, hf_x11_coloritem_flags_do_green, tvb, *offsetp, 1,
817 do_red_green_blue & 0x2);
818 if (do_red_green_blue & 0x4)
819 proto_tree_add_boolean(tt, hf_x11_coloritem_flags_do_blue, tvb, *offsetp, 1,
820 do_red_green_blue & 0x4);
821 if (do_red_green_blue & 0xf8)
822 proto_tree_add_boolean(tt, hf_x11_coloritem_flags_unused, tvb, *offsetp, 1,
823 do_red_green_blue & 0xf8);
825 proto_tree_add_uint_format(t, hf_x11_coloritem_flags, tvb, *offsetp, 1, do_red_green_blue,
830 static void gravity(tvbuff_t *tvb, int *offsetp, proto_tree *t,
831 const char *nameAsChar, int hf, const char *nullInterpretation)
833 guint8 v = VALUE8(tvb, *offsetp);
835 proto_tree_add_uint_format(t, hf, tvb, *offsetp, 1, v, "%s: 0 (%s)", nameAsChar,
838 proto_tree_add_uint(t, hf, tvb, *offsetp, 1, v);
842 static void listOfArc(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
845 proto_item *ti = proto_tree_add_item(t, hf, tvb, *offsetp, length * 8, little_endian);
846 proto_tree *tt = proto_item_add_subtree(ti, ett_x11_list_of_arc);
848 gint16 x = VALUE16(tvb, *offsetp);
849 gint16 y = VALUE16(tvb, *offsetp + 2);
850 guint16 width = VALUE16(tvb, *offsetp + 4);
851 guint16 height = VALUE16(tvb, *offsetp + 6);
852 gint16 angle1 = VALUE16(tvb, *offsetp + 8);
853 gint16 angle2 = VALUE16(tvb, *offsetp + 10);
855 proto_item *tti = proto_tree_add_none_format(tt, hf_x11_arc, tvb, *offsetp, 12,
856 "arc: %dx%d+%d+%d, angle %d -> %d (%f degrees -> %f degrees)",
857 width, height, x, y, angle1, angle2,
858 angle1 / 64.0, angle2 / 64.0);
859 proto_tree *ttt = proto_item_add_subtree(tti, ett_x11_arc);
860 proto_tree_add_int(ttt, hf_x11_arc_x, tvb, *offsetp, 2, x);
862 proto_tree_add_int(ttt, hf_x11_arc_y, tvb, *offsetp, 2, y);
864 proto_tree_add_uint(ttt, hf_x11_arc_width, tvb, *offsetp, 2, y);
866 proto_tree_add_uint(ttt, hf_x11_arc_height, tvb, *offsetp, 2, y);
868 proto_tree_add_int(ttt, hf_x11_arc_angle1, tvb, *offsetp, 2, y);
870 proto_tree_add_int(ttt, hf_x11_arc_angle2, tvb, *offsetp, 2, y);
875 static void listOfAtom(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
878 proto_item *ti = proto_tree_add_item(t, hf, tvb, *offsetp, length * 4, little_endian);
879 proto_tree *tt = proto_item_add_subtree(ti, ett_x11_list_of_atom);
881 atom(tvb, offsetp, tt, hf_x11_properties_item);
884 static void listOfByte(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
887 if (length <= 0) length = 1;
888 proto_tree_add_item(t, hf, tvb, *offsetp, length, little_endian);
892 static void listOfCard32(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
893 int hf_item, int length)
895 proto_item *ti = proto_tree_add_item(t, hf, tvb, *offsetp, length * 4, little_endian);
896 proto_tree *tt = proto_item_add_subtree(ti, ett_x11_list_of_card32);
898 proto_tree_add_uint(tt, hf_item, tvb, *offsetp, 4, VALUE32(tvb, *offsetp));
903 static void listOfColorItem(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
906 proto_item *ti = proto_tree_add_item(t, hf, tvb, *offsetp, length * 8, little_endian);
907 proto_tree *tt = proto_item_add_subtree(ti, ett_x11_list_of_color_item);
911 unsigned do_red_green_blue;
912 guint16 red, green, blue;
917 red = VALUE16(tvb, *offsetp + 4);
918 green = VALUE16(tvb, *offsetp + 6);
919 blue = VALUE16(tvb, *offsetp + 8);
920 do_red_green_blue = VALUE8(tvb, *offsetp + 10);
922 bp = buffer + sprintf(buffer, "colorItem: ");
924 if (do_red_green_blue & 0x1) {
925 bp += sprintf(bp, "red = %d", red);
928 if (do_red_green_blue & 0x2) {
929 bp += sprintf(bp, "%sgreen = %d", sep, green);
932 if (do_red_green_blue & 0x4)
933 bp += sprintf(bp, "%sblue = %d", sep, blue);
935 tti = proto_tree_add_none_format(tt, hf_x11_coloritem, tvb, *offsetp, 12, "%s", buffer);
936 ttt = proto_item_add_subtree(tti, ett_x11_color_item);
937 proto_tree_add_item(ttt, hf_x11_coloritem_pixel, tvb, *offsetp, 4, little_endian);
939 proto_tree_add_item(ttt, hf_x11_coloritem_red, tvb, *offsetp, 2, little_endian);
941 proto_tree_add_item(ttt, hf_x11_coloritem_green, tvb, *offsetp, 2, little_endian);
943 proto_tree_add_item(ttt, hf_x11_coloritem_blue, tvb, *offsetp, 2, little_endian);
945 colorFlags(tvb, offsetp, ttt);
946 proto_tree_add_item(ttt, hf_x11_coloritem_unused, tvb, *offsetp, 1, little_endian);
951 static GTree *keysymTable = NULL;
953 static gint compareGuint32(gconstpointer a, gconstpointer b)
955 return GPOINTER_TO_INT(b) - GPOINTER_TO_INT(a);;
958 static const char *keysymString(guint32 v)
963 /* This table is so big that we built it only if necessary */
965 const value_string *p = keysym_vals_source;
966 keysymTable = g_tree_new(compareGuint32);
967 for(; p -> strptr; p++)
968 g_tree_insert(keysymTable, GINT_TO_POINTER(p -> value), p -> strptr);
970 res = g_tree_lookup(keysymTable, GINT_TO_POINTER(v));
971 return res ? res : "Unknown";
974 static const char *modifiers[] = { "Shift", "Lock", "Control", "Mod1", "Mod2", "Mod3", "Mod4", "Mod5" };
976 static void listOfKeycode(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
980 proto_item *ti = proto_tree_add_item(t, hf, tvb, *offsetp, length * 8, little_endian);
981 proto_tree *tt = proto_item_add_subtree(ti, ett_x11_list_of_keycode);
988 for(i = 8, m = modifiers; i; i--, m++) {
989 u_char c = tvb_get_guint8(tvb, *offsetp);
992 bp += sprintf(bp, " %s=%d", *m, c);
995 proto_tree_add_bytes_format(tt, hf_x11_keycodes_item, tvb, *offsetp - 8, 8, tvb_get_ptr(tvb, *offsetp - 8, 8), "item: %s", buffer);
999 static void listOfKeysyms(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
1000 int hf_item, int keycode_count, int keysyms_per_keycode)
1002 proto_item *ti = proto_tree_add_item(t, hf, tvb, *offsetp, keycode_count * keysyms_per_keycode * 4, little_endian);
1003 proto_tree *tt = proto_item_add_subtree(ti, ett_x11_list_of_keysyms);
1008 while(keycode_count--) {
1009 tti = proto_tree_add_none_format(tt, hf_item, tvb, *offsetp, keysyms_per_keycode * 4,
1011 ttt = proto_item_add_subtree(tti, ett_x11_keysym);
1012 for(i = keysyms_per_keycode; i; i--) {
1013 guint32 v = VALUE32(tvb, *offsetp);
1014 proto_item_append_text(tti, " %s", keysymString(v));
1015 proto_tree_add_uint_format(ttt, hf_x11_keysyms_item_keysym, tvb, *offsetp, 4, v,
1016 "keysym: 0x%08x (%s)", v, keysymString(v));
1022 static void listOfPoint(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf, int length)
1024 proto_item *ti = proto_tree_add_item(t, hf, tvb, *offsetp, length * 4, little_endian);
1025 proto_tree *tt = proto_item_add_subtree(ti, ett_x11_list_of_point);
1031 x = VALUE16(tvb, *offsetp);
1032 y = VALUE16(tvb, *offsetp + 2);
1034 tti = proto_tree_add_none_format(tt, hf_x11_point, tvb, *offsetp, 4, "point: (%d,%d)", x, y);
1035 ttt = proto_item_add_subtree(tti, ett_x11_point);
1036 proto_tree_add_int(ttt, hf_x11_point_x, tvb, *offsetp, 2, x);
1038 proto_tree_add_int(ttt, hf_x11_point_y, tvb, *offsetp, 2, y);
1043 static void listOfRectangle(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
1046 proto_item *ti = proto_tree_add_item(t, hf, tvb, *offsetp, length * 8, little_endian);
1047 proto_tree *tt = proto_item_add_subtree(ti, ett_x11_list_of_rectangle);
1050 unsigned width, height;
1054 x = VALUE16(tvb, *offsetp);
1055 y = VALUE16(tvb, *offsetp + 2);
1056 width = VALUE16(tvb, *offsetp + 4);
1057 height = VALUE16(tvb, *offsetp + 6);
1059 tti = proto_tree_add_none_format(tt, hf_x11_rectangle, tvb, *offsetp, 8,
1060 "rectangle: %dx%d+%d+%d", width, height, x, y);
1061 ttt = proto_item_add_subtree(tti, ett_x11_rectangle);
1062 proto_tree_add_int(ttt, hf_x11_rectangle_x, tvb, *offsetp, 2, x);
1064 proto_tree_add_int(ttt, hf_x11_rectangle_y, tvb, *offsetp, 2, y);
1066 proto_tree_add_uint(ttt, hf_x11_rectangle_width, tvb, *offsetp, 2, width);
1068 proto_tree_add_uint(ttt, hf_x11_rectangle_height, tvb, *offsetp, 2, height);
1073 static void listOfSegment(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
1076 proto_item *ti = proto_tree_add_item(t, hf, tvb, *offsetp, length * 8, little_endian);
1077 proto_tree *tt = proto_item_add_subtree(ti, ett_x11_list_of_segment);
1079 gint16 x1, y1, x2, y2;
1083 x1 = VALUE16(tvb, *offsetp);
1084 y1 = VALUE16(tvb, *offsetp + 2);
1085 x2 = VALUE16(tvb, *offsetp + 4);
1086 y2 = VALUE16(tvb, *offsetp + 6);
1088 tti = proto_tree_add_none_format(tt, hf_x11_segment, tvb, *offsetp, 8,
1089 "segment: (%d,%d)-(%d,%d)", x1, y1, x2, y2);
1090 ttt = proto_item_add_subtree(tti, ett_x11_segment);
1091 proto_tree_add_item(ttt, hf_x11_segment_x1, tvb, *offsetp, 2, little_endian);
1093 proto_tree_add_item(ttt, hf_x11_segment_y1, tvb, *offsetp, 2, little_endian);
1095 proto_tree_add_item(ttt, hf_x11_segment_x2, tvb, *offsetp, 2, little_endian);
1097 proto_tree_add_item(ttt, hf_x11_segment_y2, tvb, *offsetp, 2, little_endian);
1102 /* XXX - the protocol tree code should handle non-printable characters.
1103 Note that "non-printable characters" may depend on your locale.... */
1104 static void stringCopy(char *dest, const char *source, int length)
1109 if (!isgraph(c) && c != ' ') c = '.';
1115 static void listOfString8(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
1116 int hf_item, int length)
1119 guint allocated = 0;
1124 /* Compute total length */
1126 int scanning_offset = *offsetp; /* Scanning pointer */
1128 for(i = length; i; i--) {
1129 l = tvb_get_guint8(tvb, scanning_offset);
1130 scanning_offset += 1 + l;
1133 ti = proto_tree_add_item(t, hf, tvb, *offsetp, scanning_offset - *offsetp, little_endian);
1134 tt = proto_item_add_subtree(ti, ett_x11_list_of_string8);
1137 * In case we throw an exception, clean up whatever stuff we've
1138 * allocated (if any).
1140 CLEANUP_PUSH(g_free, s);
1143 unsigned l = VALUE8(tvb, *offsetp);
1144 if (allocated < (l + 1)) {
1145 /* g_realloc doesn't work ??? */
1147 s = g_malloc(l + 1);
1150 stringCopy(s, tvb_get_ptr(tvb, *offsetp + 1, l), l); /* Nothing better for now. We need a better string handling API. */
1151 proto_tree_add_string_format(tt, hf_item, tvb, *offsetp, l + 1, s, "\"%s\"", s);
1156 * Call the cleanup handler to free the string and pop the handler.
1158 CLEANUP_CALL_AND_POP;
1161 #define STRING16_MAX_DISPLAYED_LENGTH 150
1163 static int stringIsActuallyAn8BitString(tvbuff_t *tvb, int offset, unsigned length)
1165 if (length > STRING16_MAX_DISPLAYED_LENGTH) length = STRING16_MAX_DISPLAYED_LENGTH;
1166 for(; length > 0; offset += 2, length--) {
1167 if (tvb_get_guint8(tvb, offset))
1173 /* length is the length of the _byte_zone_ (that is, twice the length of the string) */
1175 static void string16_with_buffer_preallocated(tvbuff_t *tvb, proto_tree *t,
1176 int hf, int hf_bytes,
1177 int offset, unsigned length,
1178 char **s, int *sLength)
1180 int truncated = FALSE;
1181 unsigned l = length / 2;
1183 if (stringIsActuallyAn8BitString(tvb, offset, l)) {
1185 int soffset = offset;
1187 if (l > STRING16_MAX_DISPLAYED_LENGTH) {
1189 l = STRING16_MAX_DISPLAYED_LENGTH;
1191 if (*sLength < (int) l + 3) {
1193 *s = g_malloc(l + 3);
1198 if (truncated) l -= 3;
1202 *dp++ = tvb_get_guint8(tvb, soffset);
1207 /* If truncated, add an ellipsis */
1208 if (truncated) { *dp++ = '.'; *dp++ = '.'; *dp++ = '.'; }
1211 proto_tree_add_string_format(t, hf, tvb, offset, length, tvb_get_ptr(tvb, offset, length), "%s: %s",
1212 proto_registrar_get_nth(hf) -> name, *s);
1214 proto_tree_add_item(t, hf_bytes, tvb, offset, length, little_endian);
1218 static void listOfTextItem(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
1219 int sizeIs16, int next_offset)
1227 /* Compute total length */
1229 int scanning_offset = *offsetp; /* Scanning pointer */
1230 int l; /* Length of an individual item */
1231 int n = 0; /* Number of items */
1233 while(scanning_offset < next_offset) {
1234 l = tvb_get_guint8(tvb, scanning_offset);
1238 scanning_offset += l == 255 ? 4 : l + (sizeIs16 ? l : 0) + 1;
1241 ti = proto_tree_add_item(t, hf, tvb, *offsetp, scanning_offset - *offsetp, little_endian);
1242 tt = proto_item_add_subtree(ti, ett_x11_list_of_text_item);
1245 * In case we throw an exception, clean up whatever stuff we've
1246 * allocated (if any).
1248 CLEANUP_PUSH(g_free, s);
1251 unsigned l = VALUE8(tvb, *offsetp);
1252 if (l == 255) { /* Item is a font */
1253 fid = tvb_get_ntohl(tvb, *offsetp + 1);
1254 proto_tree_add_uint(tt, hf_x11_textitem_font, tvb, *offsetp, 5, fid);
1256 } else { /* Item is a string */
1259 gint8 delta = VALUE8(tvb, *offsetp + 1);
1260 if (sizeIs16) l += l;
1261 if ((unsigned) allocated < l + 1) {
1262 /* g_realloc doesn't work ??? */
1264 s = g_malloc(l + 1);
1267 stringCopy(s, tvb_get_ptr(tvb, *offsetp + 2, l), l);
1268 tti = proto_tree_add_none_format(tt, hf_x11_textitem_string, tvb, *offsetp, l + 2,
1269 "textitem (string): delta = %d, \"%s\"",
1271 ttt = proto_item_add_subtree(tti, ett_x11_text_item);
1272 proto_tree_add_item(ttt, hf_x11_textitem_string_delta, tvb, *offsetp + 1, 1, little_endian);
1274 string16_with_buffer_preallocated(tvb, ttt, hf_x11_textitem_string_string16,
1275 hf_x11_textitem_string_string16_bytes,
1279 proto_tree_add_string_format(ttt, hf_x11_textitem_string_string8, tvb,
1280 *offsetp + 2, l, s, "\"%s\"", s);
1286 * Call the cleanup handler to free the string and pop the handler.
1288 CLEANUP_CALL_AND_POP;
1291 static guint32 field8(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf)
1293 guint32 v = VALUE8(tvb, *offsetp);
1294 header_field_info *hfi = proto_registrar_get_nth(hf);
1295 gchar *enumValue = NULL;
1296 gchar *nameAsChar = hfi -> name;
1299 enumValue = match_strval(v, cVALS(hfi -> strings));
1301 proto_tree_add_uint_format(t, hf, tvb, *offsetp, 1, v,
1302 hfi -> display == BASE_DEC ? "%s: %u (%s)" : "%s: 0x%02x (%s)",
1303 nameAsChar, v, enumValue);
1305 proto_tree_add_item(t, hf, tvb, *offsetp, 1, little_endian);
1310 static guint32 field16(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf)
1312 guint32 v = VALUE16(tvb, *offsetp);
1313 proto_tree_add_item(t, hf, tvb, *offsetp, 2, little_endian);
1318 static guint32 field32(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf)
1320 guint32 v = VALUE32(tvb, *offsetp);
1321 header_field_info *hfi = proto_registrar_get_nth(hf);
1322 gchar *enumValue = NULL;
1323 gchar *nameAsChar = hfi -> name;
1326 enumValue = match_strval(v, cVALS(hfi -> strings));
1328 proto_tree_add_uint_format(t, hf, tvb, *offsetp, 4, v,
1329 hfi -> display == BASE_DEC ? "%s: %u (%s)" : "%s: 0x%08x (%s)",
1330 nameAsChar, v, enumValue);
1332 proto_tree_add_uint_format(t, hf, tvb, *offsetp, 4, v,
1333 hfi -> display == BASE_DEC ? "%s: %u" : "%s: 0x%08x",
1339 static void gcAttributes(tvbuff_t *tvb, int *offsetp, proto_tree *t)
1341 BITMASK32(gc_value);
1342 BITFIELD(ENUM8, gc_value_mask, function);
1343 BITFIELD(CARD32, gc_value_mask, plane_mask);
1344 BITFIELD(CARD32, gc_value_mask, foreground);
1345 BITFIELD(CARD32, gc_value_mask, background);
1346 BITFIELD(CARD16, gc_value_mask, line_width);
1347 BITFIELD(ENUM8, gc_value_mask, line_style);
1348 BITFIELD(ENUM8, gc_value_mask, cap_style);
1349 BITFIELD(ENUM8, gc_value_mask, join_style);
1350 BITFIELD(ENUM8, gc_value_mask, fill_style);
1351 BITFIELD(ENUM8, gc_value_mask, fill_rule);
1352 BITFIELD(PIXMAP, gc_value_mask, tile);
1353 BITFIELD(PIXMAP, gc_value_mask, stipple);
1354 BITFIELD(INT16, gc_value_mask, tile_stipple_x_origin);
1355 BITFIELD(INT16, gc_value_mask, tile_stipple_y_origin);
1356 BITFIELD(FONT, gc_value_mask, font);
1357 BITFIELD(ENUM8, gc_value_mask, subwindow_mode);
1358 BITFIELD(BOOL, gc_value_mask, graphics_exposures);
1359 BITFIELD(INT16, gc_value_mask, clip_x_origin);
1360 BITFIELD(INT16, gc_value_mask, clip_y_origin);
1361 BITFIELD(PIXMAP, gc_value_mask, clip_mask);
1362 BITFIELD(CARD16, gc_value_mask, dash_offset);
1363 BITFIELD(CARD8, gc_value_mask, gc_dashes);
1364 BITFIELD(ENUM8, gc_value_mask, arc_mode);
1368 static void gcMask(tvbuff_t *tvb, int *offsetp, proto_tree *t)
1370 BITMASK32(gc_value);
1371 FLAG(gc_value, function);
1372 FLAG(gc_value, plane_mask);
1373 FLAG(gc_value, foreground);
1374 FLAG(gc_value, background);
1375 FLAG(gc_value, line_width);
1376 FLAG(gc_value, line_style);
1377 FLAG(gc_value, cap_style);
1378 FLAG(gc_value, join_style);
1379 FLAG(gc_value, fill_style);
1380 FLAG(gc_value, fill_rule);
1381 FLAG(gc_value, tile);
1382 FLAG(gc_value, stipple);
1383 FLAG(gc_value, tile_stipple_x_origin);
1384 FLAG(gc_value, tile_stipple_y_origin);
1385 FLAG(gc_value, font);
1386 FLAG(gc_value, subwindow_mode);
1387 FLAG(gc_value, graphics_exposures);
1388 FLAG(gc_value, clip_x_origin);
1389 FLAG(gc_value, clip_y_origin);
1390 FLAG(gc_value, clip_mask);
1391 FLAG(gc_value, dash_offset);
1392 FLAG(gc_value, gc_dashes);
1393 FLAG(gc_value, arc_mode);
1397 static guint32 requestLength(tvbuff_t *tvb, int *offsetp, proto_tree *t)
1399 guint32 res = VALUE16(tvb, *offsetp) * 4;
1400 proto_tree_add_uint(t, hf_x11_request_length, tvb, *offsetp, 2, res);
1405 static void setOfEvent(tvbuff_t *tvb, int *offsetp, proto_tree *t)
1408 FLAG(event, KeyPress);
1409 FLAG(event, KeyRelease);
1410 FLAG(event, ButtonPress);
1411 FLAG(event, ButtonRelease);
1412 FLAG(event, EnterWindow);
1413 FLAG(event, LeaveWindow);
1414 FLAG(event, PointerMotion);
1415 FLAG(event, PointerMotionHint);
1416 FLAG(event, Button1Motion);
1417 FLAG(event, Button2Motion);
1418 FLAG(event, Button3Motion);
1419 FLAG(event, Button4Motion);
1420 FLAG(event, Button5Motion);
1421 FLAG(event, ButtonMotion);
1422 FLAG(event, KeymapState);
1423 FLAG(event, Exposure);
1424 FLAG(event, VisibilityChange);
1425 FLAG(event, StructureNotify);
1426 FLAG(event, ResizeRedirect);
1427 FLAG(event, SubstructureNotify);
1428 FLAG(event, SubstructureRedirect);
1429 FLAG(event, FocusChange);
1430 FLAG(event, PropertyChange);
1431 FLAG(event, ColormapChange);
1432 FLAG(event, OwnerGrabButton);
1433 FLAG_IF_NONZERO(event, erroneous_bits);
1437 static void setOfDeviceEvent(tvbuff_t *tvb, int *offsetp, proto_tree *t)
1439 BITMASK32(do_not_propagate);
1440 FLAG(do_not_propagate, KeyPress);
1441 FLAG(do_not_propagate, KeyRelease);
1442 FLAG(do_not_propagate, ButtonPress);
1443 FLAG(do_not_propagate, ButtonRelease);
1444 FLAG(do_not_propagate, PointerMotion);
1445 FLAG(do_not_propagate, Button1Motion);
1446 FLAG(do_not_propagate, Button2Motion);
1447 FLAG(do_not_propagate, Button3Motion);
1448 FLAG(do_not_propagate, Button4Motion);
1449 FLAG(do_not_propagate, Button5Motion);
1450 FLAG(do_not_propagate, ButtonMotion);
1451 FLAG_IF_NONZERO(do_not_propagate, erroneous_bits);
1455 static void setOfKeyMask(tvbuff_t *tvb, int *offsetp, proto_tree *t)
1458 guint32 bitmask_value;
1461 proto_tree *bitmask_tree;
1463 bitmask_value = VALUE16(tvb, *offsetp);
1464 bitmask_offset = *offsetp;
1466 if (bitmask_value == 0x8000)
1467 proto_tree_add_uint_format(t, hf_x11_modifiers_mask_AnyModifier, tvb, *offsetp, 2, 0x8000,
1468 "modifiers-masks: 0x8000 (AnyModifier)");
1470 ti = proto_tree_add_uint(t, hf_x11_modifiers_mask, tvb, *offsetp, 2,
1472 bitmask_tree = proto_item_add_subtree(ti, ett_x11_set_of_key_mask);
1473 FLAG(modifiers, Shift);
1474 FLAG(modifiers, Lock);
1475 FLAG(modifiers, Control);
1476 FLAG(modifiers, Mod1);
1477 FLAG(modifiers, Mod2);
1478 FLAG(modifiers, Mod3);
1479 FLAG(modifiers, Mod4);
1480 FLAG(modifiers, Mod5);
1481 FLAG_IF_NONZERO(modifiers, erroneous_bits);
1486 static void setOfPointerEvent(tvbuff_t *tvb, int *offsetp, proto_tree *t)
1488 BITMASK16(pointer_event);
1489 FLAG(pointer_event, ButtonPress);
1490 FLAG(pointer_event, ButtonRelease);
1491 FLAG(pointer_event, EnterWindow);
1492 FLAG(pointer_event, LeaveWindow);
1493 FLAG(pointer_event, PointerMotion);
1494 FLAG(pointer_event, PointerMotionHint);
1495 FLAG(pointer_event, Button1Motion);
1496 FLAG(pointer_event, Button2Motion);
1497 FLAG(pointer_event, Button3Motion);
1498 FLAG(pointer_event, Button4Motion);
1499 FLAG(pointer_event, Button5Motion);
1500 FLAG(pointer_event, ButtonMotion);
1501 FLAG(pointer_event, KeymapState);
1502 FLAG_IF_NONZERO(pointer_event, erroneous_bits);
1506 static void string8(tvbuff_t *tvb, int *offsetp, proto_tree *t,
1507 const char *nameAsChar, int hf, unsigned length)
1509 char *s = g_malloc(length + 1);
1512 * In case we throw an exception, clean up whatever stuff we've
1513 * allocated (if any).
1515 CLEANUP_PUSH(g_free, s);
1517 stringCopy(s, tvb_get_ptr(tvb, *offsetp, length), length);
1518 proto_tree_add_string_format(t, hf, tvb, *offsetp, length, s, "%s: %s", nameAsChar, s);
1521 * Call the cleanup handler to free the string and pop the handler.
1523 CLEANUP_CALL_AND_POP;
1528 /* The length is the length of the _byte_zone_ (twice the length of the string) */
1530 static void string16(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
1531 int hf_bytes, unsigned length)
1537 * In case we throw an exception, clean up whatever stuff we've
1538 * allocated (if any).
1540 CLEANUP_PUSH(g_free, s);
1543 string16_with_buffer_preallocated(tvb, t, hf, hf_bytes, *offsetp, length, &s, &l);
1546 * Call the cleanup handler to free the string and pop the handler.
1548 CLEANUP_CALL_AND_POP;
1553 static void timestamp(tvbuff_t *tvb, int *offsetp, proto_tree *t,
1554 const char *nameAsChar, int hf)
1556 guint32 v = VALUE32(tvb, *offsetp);
1558 proto_tree_add_uint_format(t, hf, tvb, *offsetp, 4, 0, "%s: 0 (CurrentTime)", nameAsChar);
1560 proto_tree_add_uint(t, hf, tvb, *offsetp, 4, v);
1564 static void windowAttributes(tvbuff_t *tvb, int *offsetp, proto_tree *t)
1566 BITMASK32(window_value);
1567 BITFIELD(PIXMAP, window_value_mask, background_pixmap);
1568 BITFIELD(CARD32, window_value_mask, background_pixel);
1569 BITFIELD(PIXMAP, window_value_mask, border_pixmap);
1570 BITFIELD(CARD32, window_value_mask, border_pixel);
1571 BITFIELD(BITGRAVITY, window_value_mask, bit_gravity);
1572 BITFIELD(WINGRAVITY, window_value_mask, win_gravity);
1573 BITFIELD(ENUM8, window_value_mask, backing_store);
1574 BITFIELD(CARD32, window_value_mask, backing_planes);
1575 BITFIELD(CARD32, window_value_mask, backing_pixel);
1576 BITFIELD(BOOL, window_value_mask, override_redirect);
1577 BITFIELD(BOOL, window_value_mask, save_under);
1578 BITFIELD(SETofEVENT, window_value_mask, event_mask);
1579 BITFIELD(SETofDEVICEEVENT, window_value_mask, do_not_propagate_mask);
1580 BITFIELD(COLORMAP, window_value_mask, colormap);
1581 BITFIELD(CURSOR, window_value_mask, cursor);
1586 * Data structure associated with a conversation; keeps track of the
1587 * request for which we're expecting a reply, the frame number of
1588 * the initial connection request, and the byte order of the connection.
1590 * An opcode of -3 means we haven't yet seen any requests yet.
1591 * An opcode of -2 means we're not expecting a reply.
1592 * An opcode of -1 means means we're waiting for a reply to the initial
1593 * connection request.
1594 * Other values are the opcode of the request for which we're expecting
1597 * XXX - assumes only one outstanding request is awaiting a reply,
1598 * which should always be the case.
1600 #define NOTHING_SEEN -3
1601 #define NOTHING_EXPECTED -2
1602 #define INITIAL_CONN -1
1604 #define BYTE_ORDER_BE 0
1605 #define BYTE_ORDER_LE 1
1606 #define BYTE_ORDER_UNKNOWN -1
1609 int opcode; /* opcode for which we're awaiting a reply */
1610 guint32 iconn_frame; /* frame # of initial connection request */
1611 int byte_order; /* byte order of connection */
1614 static GMemChunk *x11_state_chunk = NULL;
1616 static void x11_init_protocol(void)
1618 if (x11_state_chunk != NULL)
1619 g_mem_chunk_destroy(x11_state_chunk);
1621 x11_state_chunk = g_mem_chunk_new("x11_state_chunk",
1622 sizeof (x11_conv_data_t),
1623 128 * sizeof (x11_conv_data_t),
1627 /************************************************************************
1629 *** G U E S S I N G T H E B Y T E O R D E R I N G ***
1631 ************************************************************************/
1633 /* If we can't guess, we return TRUE (that is little_endian), cause
1634 I'm developing on a Linux box :-). The (non-)guess isn't cached
1635 however, so we may have more luck next time. I'm quite conservative
1636 in my assertions, cause once it's cached, it's stay in cache, and
1637 we may be fooled up by a packet starting with the end of a request
1638 started in a previous packet...
1641 static int numberOfBitSetTable[] = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4 };
1643 static int numberOfBitSet(tvbuff_t *tvb, int offset, int maskLength)
1646 while(maskLength--) {
1647 int c = tvb_get_guint8(tvb, offset);
1649 res += numberOfBitSetTable[c & 0xf] + numberOfBitSetTable[c >> 4];
1654 static int listOfStringLengthConsistent(tvbuff_t *tvb, int offset, int length, int listLength)
1656 if (listLength > length) return FALSE;
1657 while(listLength--) {
1659 if (!tvb_bytes_exist(tvb, offset, 1)) return TRUE;
1660 l = tvb_get_guint8(tvb, offset);
1663 if (l > length) return FALSE;
1664 if (!tvb_bytes_exist(tvb, offset, l)) return TRUE;
1668 if (length > 3) return FALSE;
1672 static int rounded4(int n)
1674 int remainder = n % 4;
1676 if (remainder) res++;
1680 /* We assume the order to be consistent, until proven wrong. */
1682 static gboolean consistentWithOrder(int length, tvbuff_t *tvb, int offset, guint16 (*v16)(tvbuff_t *, gint))
1684 switch(tvb_get_guint8(tvb, offset)) {
1685 case 1: /* CreateWindow */
1686 return !tvb_bytes_exist(tvb, offset, 32) || length == 8 + numberOfBitSet(tvb, offset + 7 * 4, 4);
1688 case 2: /* ChangeWindowAttributes */
1689 case 56: /* ChangeGC */
1690 return !tvb_bytes_exist(tvb, offset, 12) || length == 3 + numberOfBitSet(tvb, offset + 8, 4);
1692 case 3: /* GetWindowAttributes */
1693 case 4: /* DestroyWindow */
1694 case 5: /* DestroySubwindows */
1695 case 6: /* ChangeSaveSet */
1696 case 8: /* MapWindow */
1697 case 9: /* MapSubWindow */
1698 case 10: /* UnmapWindow */
1699 case 11: /* UnmapSubwindows */
1700 case 13: /* CirculateWindow */
1701 case 14: /* GetGeometry */
1702 case 15: /* QueryTree */
1703 case 17: /* GetAtomName */
1704 case 21: /* ListProperties */
1705 case 23: /* GetSelectionOwner */
1706 case 27: /* UngrabPointer */
1707 case 32: /* UngrabKeyboard */
1708 case 35: /* AllowEvents */
1709 case 38: /* QueryPointer */
1710 case 46: /* CloseFont */
1711 case 47: /* QueryFont */
1712 case 54: /* FreePixmap */
1713 case 60: /* FreeGC */
1714 case 79: /* FreeColormap */
1715 case 81: /* InstallColormap */
1716 case 82: /* UninstallColormap */
1717 case 83: /* ListInstalledColormaps */
1718 case 95: /* FreeCursor */
1719 case 101: /* GetKeyboardMapping */
1720 case 113: /* KillClient */
1723 case 7: /* ReparentWindow */
1724 case 22: /* SetSelectionOwner */
1725 case 30: /* ChangeActivePointerGrab */
1726 case 31: /* GrabKeyboard */
1727 case 33: /* GrabKey */
1728 case 39: /* GetMotionEvents */
1729 case 40: /* TranslateCoordinates */
1730 case 53: /* CreatePixmap */
1731 case 57: /* CopyGC */
1732 case 61: /* ClearArea */
1733 case 78: /* CreateColormap */
1734 case 84: /* AllocColor */
1735 case 87: /* AllocColorPlanes */
1738 case 12: /* ConfigureWindow */
1739 return !tvb_bytes_exist(tvb, offset, 10) || length == 3 + numberOfBitSet(tvb, offset + 8, 2);
1741 case 16: /* InternAtom */
1742 case 98: /* QueryExtension */
1743 return !tvb_bytes_exist(tvb, offset, 6) || length == 2 + rounded4(v16(tvb, offset + 4));
1745 case 18: /* ChangeProperty */
1747 int multiplier, type;
1748 if (!tvb_bytes_exist(tvb, offset, 17)) return TRUE;
1749 type = tvb_get_guint8(tvb, 16);
1750 if (type != 8 && type != 16 && type != 32) return FALSE;
1751 multiplier = type == 8 ? 1 : type == 16 ? 2 : 4;
1752 if (!tvb_bytes_exist(tvb, offset, 24)) return TRUE;
1753 return length == 6 + rounded4((v16 == tvb_get_letohs ? tvb_get_letohl : tvb_get_ntohl)(tvb, offset + 20) * multiplier);
1756 case 19: /* DeleteProperty */
1757 case 29: /* UngrabButton */
1758 case 34: /* UngrabKey */
1759 case 42: /* SetInputFocus */
1760 case 80: /* CopyColormapAndFree */
1761 case 86: /* AllocColorCells */
1762 case 97: /* QueryBestSize */
1763 case 105: /* ChangePointerControl */
1764 case 107: /* SetScreenSaver */
1767 case 20: /* GetProperty */
1768 case 24: /* ConvertSelection */
1769 case 26: /* GrabPointer */
1770 case 28: /* GrabButton */
1771 case 41: /* WarpPointer */
1774 case 25: /* SendEvent */
1775 return length == 11;
1777 case 36: /* GrabServer */
1778 case 37: /* UngrabServer */
1779 case 43: /* GetInputFocus */
1780 case 44: /* QueryKeymap */
1781 case 52: /* GetFontPath */
1782 case 99: /* ListExtensions */
1783 case 103: /* GetKeyboardControl */
1784 case 104: /* Bell */
1785 case 106: /* GetPointerControl */
1786 case 108: /* GetScreenSaver */
1787 case 110: /* ListHosts */
1788 case 111: /* SetAccessControl */
1789 case 112: /* SetCloseDownMode */
1790 case 115: /* ForceScreenSaver */
1791 case 117: /* GetPointerMapping */
1792 case 119: /* GetModifierMapping */
1795 case 45: /* OpenFont */
1796 case 85: /* AllocNamedColor */
1797 case 92: /* LookupColor */
1798 return !tvb_bytes_exist(tvb, offset, 10) || length == 3 + rounded4(v16(tvb, offset + 8));
1800 case 48: /* QueryTextExtents */
1803 case 49: /* ListFonts */
1804 case 50: /* ListFontsWithInfo */
1805 case 109: /* ChangeHosts */
1806 return !tvb_bytes_exist(tvb, offset, 8) || length == 2 + rounded4(v16(tvb, offset + 6));
1808 case 51: /* SetFontPath */
1809 if (length < 2) return FALSE;
1810 if (!tvb_bytes_exist(tvb, offset, 8)) return TRUE;
1811 return listOfStringLengthConsistent(tvb, offset + 8, (length - 2) * 4, v16(tvb, offset + 4));
1813 case 55: /* CreateGC */
1814 return !tvb_bytes_exist(tvb, offset, 16) || length == 4 + numberOfBitSet(tvb, offset + 12, 4);
1816 case 58: /* SetDashes */
1817 return !tvb_bytes_exist(tvb, offset, 12) || length == 3 + rounded4(v16(tvb, offset + 10));
1819 case 59: /* SetClipRectangles */
1820 case 66: /* PolySegment */
1821 case 67: /* PolyRectangle */
1822 case 70: /* PolyFillRectangle */
1823 return length >= 3 && (length - 3) % 2 == 0;
1825 case 62: /* CopyArea */
1828 case 63: /* CopyPlane */
1829 case 93: /* CreateCursor */
1830 case 94: /* CreateGlyphCursor */
1833 case 64: /* PolyPoint */
1834 case 65: /* PolyLine */
1835 case 88: /* FreeColors */
1838 case 68: /* PolyArc */
1839 case 71: /* PolyFillArc */
1840 return length >= 3 && (length - 3) % 3 == 0;
1842 case 69: /* FillPoly */
1843 case 76: /* ImageText8 */
1846 case 72: /* PutImage */
1849 case 73: /* GetImage */
1850 case 96: /* RecolorCursor */
1853 case 74: /* PolyText8 */
1854 if (length < 4) return FALSE;
1855 return TRUE; /* We don't perform many controls on this one */
1857 case 75: /* PolyText16 */
1858 if (length < 4) return FALSE;
1859 return TRUE; /* We don't perform many controls on this one */
1861 case 77: /* ImageText16 */
1864 case 89: /* StoreColors */
1865 return length > 2 && (length - 2) % 3 == 0;
1867 case 90: /* StoreNamedColor */
1868 return !tvb_bytes_exist(tvb, offset, 14) || length == 4 + rounded4(v16(tvb, offset + 12));
1870 case 91: /* QueryColors */
1873 case 100: /* ChangeKeyboardMapping */
1874 return !tvb_bytes_exist(tvb, offset, 6) || length == 2 + tvb_get_guint8(tvb, 1) * tvb_get_guint8(tvb, 5);
1876 case 102: /* ChangeKeyboardControl */
1877 return !tvb_bytes_exist(tvb, offset, 6) || length == 2 + numberOfBitSet(tvb, offset + 4, 2);
1879 case 114: /* RotateProperties */
1880 return !tvb_bytes_exist(tvb, offset, 10) || length == 3 + v16(tvb, offset + 8);
1882 case 116: /* SetPointerMapping */
1883 return length == 1 + rounded4(tvb_get_guint8(tvb, 1));
1885 case 118: /* SetModifierMapping */
1886 return length == 1 + tvb_get_guint8(tvb, 1) * 2;
1888 case 127: /* NoOperation */
1896 /* -1 means doesn't match, +1 means match, 0 means don't know */
1898 static int x_endian_match(tvbuff_t *tvb, guint16 (*v16)(tvbuff_t *, gint))
1900 int offset, nextoffset;
1903 for(offset = 0; tvb_bytes_exist(tvb, offset, 4); offset = nextoffset) {
1905 length = v16(tvb, offset + 2);
1906 if (!length) return -1;
1907 nextoffset = offset + length * 4;
1908 if (!consistentWithOrder(length, tvb, offset, v16)) return -1;
1915 guess_byte_ordering(tvbuff_t *tvb, packet_info *pinfo,
1916 x11_conv_data_t *state_info)
1918 /* With X the client gives the byte ordering for the protocol,
1919 and the port on the server tells us we're speaking X. */
1921 int le, be, decision, decisionToCache;
1923 if (state_info->byte_order == BYTE_ORDER_BE)
1924 return FALSE; /* known to be big-endian */
1925 else if (state_info->byte_order == BYTE_ORDER_LE)
1926 return TRUE; /* known to be little-endian */
1928 if (pinfo->srcport == pinfo->match_port) {
1930 * This is a reply or event; we don't try to guess the
1931 * byte order on it for now.
1936 le = x_endian_match(tvb, tvb_get_letohs);
1937 be = x_endian_match(tvb, tvb_get_ntohs);
1939 /* remember that "decision" really means "little_endian". */
1941 /* We have no reason to believe it's little- rather than
1942 big-endian, so we guess the shortest length is the
1945 if (!tvb_bytes_exist(tvb, 0, 4))
1946 /* Not even a way to get the length. We're biased
1947 toward little endianness here (essentially the
1948 x86 world right now). Decoding won't go very far
1953 decision = tvb_get_letohs(tvb, 2) <= tvb_get_ntohs(tvb, 2);
1955 decision = le >= be;
1957 decisionToCache = (le < 0 && be > 0) || (le > 0 && be < 0);
1958 if (decisionToCache) {
1960 * Remember the decision.
1962 state_info->byte_order = decision ? BYTE_ORDER_LE : BYTE_ORDER_BE;
1966 fprintf(stderr, "packet %d\tle %d\tbe %d\tlittle_endian %d\tcache %d\n",
1967 pinfo->fd -> num, le, be, decision, decisionToCache);
1972 /************************************************************************
1974 *** D E C O D I N G O N E P A C K E T ***
1976 ************************************************************************/
1979 * Decode an initial connection request.
1981 static void dissect_x11_initial_conn(tvbuff_t *tvb, packet_info *pinfo,
1982 proto_tree *tree, x11_conv_data_t *state_info)
1985 int *offsetp = &offset;
1988 guint16 auth_proto_name_length, auth_proto_data_length;
1991 ti = proto_tree_add_item(tree, proto_x11, tvb, 0, -1, FALSE);
1992 t = proto_item_add_subtree(ti, ett_x11);
1996 CARD16(protocol_major_version);
1997 CARD16(protocol_minor_version);
1998 auth_proto_name_length = CARD16(authorization_protocol_name_length);
1999 auth_proto_data_length = CARD16(authorization_protocol_data_length);
2001 if (auth_proto_name_length != 0) {
2002 STRING8(authorization_protocol_name, auth_proto_name_length);
2003 offset = ROUND_LENGTH(offset);
2005 if (auth_proto_data_length != 0) {
2006 STRING8(authorization_protocol_data, auth_proto_data_length);
2007 offset = ROUND_LENGTH(offset);
2009 left = tvb_length_remaining(tvb, offset);
2011 proto_tree_add_item(t, hf_x11_undecoded, tvb, offset, left, little_endian);
2014 * This is the initial connection request...
2016 state_info->iconn_frame = pinfo->fd->num;
2019 * ...and we're expecting a reply to it.
2021 state_info->opcode = INITIAL_CONN;
2024 static void dissect_x11_request(tvbuff_t *tvb, packet_info *pinfo,
2025 proto_tree *tree, const char *sep, x11_conv_data_t *state_info)
2028 int *offsetp = &offset;
2038 length = VALUE16(tvb, 2) * 4;
2041 /* Bogus message length? */
2045 next_offset = offset + length;
2047 ti = proto_tree_add_item(tree, proto_x11, tvb, 0, -1, FALSE);
2048 t = proto_item_add_subtree(ti, ett_x11);
2052 if (check_col(pinfo->cinfo, COL_INFO))
2053 col_append_fstr(pinfo->cinfo, COL_INFO, "%s %s", sep,
2054 val_to_str(opcode, opcode_vals, "Unknown (%u)"));
2057 * Does this request expect a reply?
2061 case 3: /* GetWindowAttributes */
2062 case 14: /* GetGeometry */
2063 case 15: /* QueryTree */
2064 case 16: /* InternAtom */
2065 case 17: /* GetAtomName */
2066 case 20: /* GetProperty */
2067 case 21: /* ListProperties */
2068 case 23: /* GetSelectionOwner */
2069 case 26: /* GrabPointer */
2070 case 31: /* GrabKeyboard */
2071 case 38: /* QueryPointer */
2072 case 39: /* GetMotionEvents */
2073 case 40: /* TranslateCoordinates */
2074 case 44: /* QueryKeymap */
2075 case 47: /* QueryFont */
2076 case 48: /* QueryTextExtents */
2077 case 49: /* ListFonts */
2078 case 73: /* GetImage */
2079 case 83: /* ListInstalledColormaps */
2080 case 84: /* AllocColor */
2081 case 91: /* QueryColors */
2082 case 92: /* LookupColor */
2083 case 97: /* QueryBestSize */
2084 case 98: /* QueryExtension */
2085 case 99: /* ListExtensions */
2086 case 101: /* GetKeyboardMapping */
2087 case 103: /* GetKeyboardControl */
2088 case 106: /* GetPointerControl */
2089 case 108: /* GetScreenSaver */
2090 case 110: /* ListHosts */
2091 case 116: /* SetPointerMapping */
2092 case 117: /* GetPointerMapping */
2093 case 118: /* SetModifierMapping */
2094 case 119: /* GetModifierMapping */
2096 * Those requests expect a reply.
2098 state_info->opcode = opcode;
2103 * No reply is expected from any other request.
2105 state_info->opcode = NOTHING_EXPECTED;
2113 case 1: /* CreateWindow */
2122 CARD16(border_width);
2123 ENUM16(window_class);
2125 windowAttributes(tvb, offsetp, t);
2128 case 2: /* ChangeWindowAttributes */
2132 windowAttributes(tvb, offsetp, t);
2135 case 3: /* GetWindowAttributes */
2136 case 4: /* DestroyWindow */
2137 case 5: /* DestroySubwindows */
2143 case 6: /* ChangeSaveSet */
2144 ENUM8(save_set_mode);
2149 case 7: /* ReparentWindow */
2158 case 8: /* MapWindow */
2159 case 9: /* MapSubWindow */
2160 case 10: /* UnmapWindow */
2161 case 11: /* UnmapSubwindows */
2167 case 12: /* ConfigureWindow */
2171 BITMASK16(configure_window);
2173 BITFIELD(INT16, configure_window_mask, x);
2174 BITFIELD(INT16, configure_window_mask, y);
2175 BITFIELD(CARD16, configure_window_mask, width);
2176 BITFIELD(CARD16, configure_window_mask, height);
2177 BITFIELD(CARD16, configure_window_mask, border_width);
2178 BITFIELD(WINDOW, configure_window_mask, sibling);
2179 BITFIELD(ENUM8, configure_window_mask, stack_mode);
2184 case 13: /* CirculateWindow */
2190 case 14: /* GetGeometry */
2191 case 15: /* QueryTree */
2197 case 16: /* InternAtom */
2198 BOOL(only_if_exists);
2200 v16 = FIELD16(name_length);
2206 case 17: /* GetAtomName */
2212 case 18: /* ChangeProperty */
2220 v32 = CARD32(data_length);
2221 LISTofBYTE(data, v32);
2225 case 19: /* DeleteProperty */
2232 case 20: /* GetProperty */
2237 ATOM(get_property_type);
2238 CARD32(long_offset);
2239 CARD32(long_length);
2242 case 21: /* ListProperties */
2248 case 22: /* SetSelectionOwner */
2256 case 23: /* GetSelectionOwner */
2262 case 24: /* ConvertSelection */
2272 case 26: /* GrabPointer */
2275 WINDOW(grab_window);
2276 SETofPOINTEREVENT(pointer_event_mask);
2277 ENUM8(pointer_mode);
2278 ENUM8(keyboard_mode);
2284 case 27: /* UngrabPointer */
2290 case 28: /* GrabButton */
2293 WINDOW(grab_window);
2294 SETofPOINTEREVENT(event_mask);
2295 ENUM8(pointer_mode);
2296 ENUM8(keyboard_mode);
2301 SETofKEYMASK(modifiers);
2304 case 29: /* UngrabButton */
2307 WINDOW(grab_window);
2308 SETofKEYMASK(modifiers);
2312 case 30: /* ChangeActivePointerGrab */
2317 SETofPOINTEREVENT(event_mask);
2321 case 31: /* GrabKeyboard */
2324 WINDOW(grab_window);
2326 ENUM8(pointer_mode);
2327 ENUM8(keyboard_mode);
2331 case 32: /* UngrabKeyboard */
2337 case 33: /* GrabKey */
2340 WINDOW(grab_window);
2341 SETofKEYMASK(modifiers);
2343 ENUM8(pointer_mode);
2344 ENUM8(keyboard_mode);
2348 case 34: /* UngrabKey */
2351 WINDOW(grab_window);
2352 SETofKEYMASK(modifiers);
2356 case 35: /* AllowEvents */
2357 ENUM8(allow_events_mode);
2362 case 36: /* GrabServer */
2367 case 37: /* UngrabServer */
2372 case 38: /* QueryPointer */
2378 case 39: /* GetMotionEvents */
2386 case 40: /* TranslateCoordinates */
2395 case 41: /* WarpPointer */
2398 WINDOW(warp_pointer_src_window);
2399 WINDOW(warp_pointer_dst_window);
2408 case 42: /* SetInputFocus */
2415 case 43: /* GetInputFocus */
2420 case 44: /* QueryKeymap */
2425 case 45: /* OpenFont */
2429 v16 = FIELD16(name_length);
2435 case 46: /* CloseFont */
2441 case 47: /* QueryFont */
2447 case 48: /* QueryTextExtents */
2448 v8 = BOOL(odd_length);
2451 STRING16(string16, (next_offset - offset - (v8 ? 2 : 0)) / 2);
2455 case 49: /* ListFonts */
2459 v16 = FIELD16(pattern_length);
2460 STRING8(pattern, v16);
2464 case 50: /* ListFontsWithInfo */
2468 v16 = FIELD16(pattern_length);
2469 STRING8(pattern, v16);
2473 case 51: /* SetFontPath */
2476 v16 = CARD16(str_number_in_path);
2478 LISTofSTRING8(path, v16);
2482 case 52: /* GetFontPath */
2487 case 53: /* CreatePixmap */
2496 case 54: /* FreePixmap */
2502 case 55: /* CreateGC */
2507 gcAttributes(tvb, offsetp, t);
2510 case 56: /* ChangeGC */
2514 gcAttributes(tvb, offsetp, t);
2517 case 57: /* CopyGC */
2522 gcMask(tvb, offsetp, t);
2525 case 58: /* SetDashes */
2529 CARD16(dash_offset);
2530 v16 = FIELD16(dashes_length);
2531 LISTofCARD8(dashes, v16);
2535 case 59: /* SetClipRectangles */
2539 INT16(clip_x_origin);
2540 INT16(clip_y_origin);
2541 LISTofRECTANGLE(rectangles);
2544 case 60: /* FreeGC */
2550 case 61: /* ClearArea */
2560 case 62: /* CopyArea */
2563 DRAWABLE(src_drawable);
2564 DRAWABLE(dst_drawable);
2574 case 63: /* CopyPlane */
2577 DRAWABLE(src_drawable);
2578 DRAWABLE(dst_drawable);
2589 case 64: /* PolyPoint */
2590 ENUM8(coordinate_mode);
2591 v16 = REQUEST_LENGTH();
2594 LISTofPOINT(points, v16 - 12);
2597 case 65: /* PolyLine */
2598 ENUM8(coordinate_mode);
2599 v16 = REQUEST_LENGTH();
2602 LISTofPOINT(points, v16 - 12);
2605 case 66: /* PolySegment */
2610 LISTofSEGMENT(segments);
2613 case 67: /* PolyRectangle */
2618 LISTofRECTANGLE(rectangles);
2621 case 68: /* PolyArc */
2629 case 69: /* FillPoly */
2631 v16 = REQUEST_LENGTH();
2635 ENUM8(coordinate_mode);
2637 LISTofPOINT(points, v16 - 16);
2640 case 70: /* PolyFillRectangle */
2645 LISTofRECTANGLE(rectangles);
2648 case 71: /* PolyFillArc */
2656 case 72: /* PutImage */
2657 ENUM8(image_format);
2658 v16 = REQUEST_LENGTH();
2668 LISTofBYTE(data, v16 - 24);
2672 case 73: /* GetImage */
2673 ENUM8(image_pixmap_format);
2683 case 74: /* PolyText8 */
2685 v16 = REQUEST_LENGTH();
2690 LISTofTEXTITEM8(items);
2694 case 75: /* PolyText16 */
2696 v16 = REQUEST_LENGTH();
2701 LISTofTEXTITEM16(items);
2705 case 76: /* ImageText8 */
2706 v8 = FIELD8(string_length);
2712 STRING8(string, v8);
2716 case 77: /* ImageText16 */
2717 v8 = FIELD8(string_length);
2723 STRING16(string16, v8);
2727 case 78: /* CreateColormap */
2735 case 79: /* FreeColormap */
2741 case 80: /* CopyColormapAndFree */
2748 case 81: /* InstallColormap */
2754 case 82: /* UninstallColormap */
2760 case 83: /* ListInstalledColormaps */
2766 case 84: /* AllocColor */
2776 case 85: /* AllocNamedColor */
2780 v16 = FIELD16(name_length);
2786 case 86: /* AllocColorCells */
2794 case 87: /* AllocColorPlanes */
2804 case 88: /* FreeColors */
2806 v16 = REQUEST_LENGTH();
2809 LISTofCARD32(pixels, v16 - 12);
2812 case 89: /* StoreColors */
2814 v16 = REQUEST_LENGTH();
2816 LISTofCOLORITEM(color_items, v16 - 8);
2819 case 90: /* StoreNamedColor */
2824 v16 = FIELD16(name_length);
2830 case 91: /* QueryColors */
2832 v16 = REQUEST_LENGTH();
2834 LISTofCARD32(pixels, v16 - 8);
2837 case 92: /* LookupColor */
2841 v16 = FIELD16(name_length);
2847 case 93: /* CreateCursor */
2851 PIXMAP(source_pixmap);
2863 case 94: /* CreateGlyphCursor */
2869 CARD16(source_char);
2879 case 95: /* FreeCursor */
2885 case 96: /* RecolorCursor */
2897 case 97: /* QueryBestSize */
2905 case 98: /* QueryExtension */
2908 v16 = FIELD16(name_length);
2914 case 99: /* ListExtensions */
2919 case 100: /* ChangeKeyboardMapping */
2920 v8 = FIELD8(keycode_count);
2922 KEYCODE(first_keycode);
2923 v8_2 = FIELD8(keysyms_per_keycode);
2925 LISTofKEYSYM(keysyms, v8, v8_2);
2928 case 101: /* GetKeyboardMapping */
2931 KEYCODE(first_keycode);
2936 case 102: /* ChangeKeyboardControl */
2939 BITMASK32(keyboard_value);
2940 BITFIELD(INT8, keyboard_value_mask, key_click_percent);
2941 BITFIELD(INT8, keyboard_value_mask, bell_percent);
2942 BITFIELD(INT16, keyboard_value_mask, bell_pitch);
2943 BITFIELD(INT16, keyboard_value_mask, bell_duration);
2944 BITFIELD(INT16, keyboard_value_mask, led);
2945 BITFIELD(ENUM8, keyboard_value_mask, led_mode);
2946 BITFIELD(KEYCODE, keyboard_value_mask, keyboard_key);
2947 BITFIELD(ENUM8, keyboard_value_mask, auto_repeat_mode);
2951 case 103: /* GetKeyboardControl */
2956 case 104: /* Bell */
2961 case 105: /* ChangePointerControl */
2964 INT16(acceleration_numerator);
2965 INT16(acceleration_denominator);
2967 BOOL(do_acceleration);
2971 case 106: /* GetPointerControl */
2976 case 107: /* SetScreenSaver */
2981 ENUM8(prefer_blanking);
2982 ENUM8(allow_exposures);
2986 case 108: /* GetScreenSaver */
2991 case 109: /* ChangeHosts */
2992 ENUM8(change_host_mode);
2996 v16 = CARD16(address_length);
2997 if (v8 == FAMILY_INTERNET && v16 == 4) {
3000 * XXX - what about IPv6? Is that a family of
3001 * FAMILY_INTERNET (0) with a length of 16?
3003 LISTofCARD8(ip_address, v16);
3005 LISTofCARD8(address, v16);
3008 case 110: /* ListHosts */
3013 case 111: /* SetAccessControl */
3018 case 112: /* SetCloseDownMode */
3019 ENUM8(close_down_mode);
3023 case 113: /* KillClient */
3029 case 114: /* RotateProperties */
3031 v16 = REQUEST_LENGTH();
3033 CARD16(property_number);
3035 LISTofATOM(properties, (v16 - 12));
3038 case 115: /* ForceScreenSaver */
3039 ENUM8(screen_saver_mode);
3043 case 116: /* SetPointerMapping */
3044 v8 = FIELD8(map_length);
3046 LISTofCARD8(map, v8);
3050 case 117: /* GetPointerMapping */
3055 case 118: /* SetModifierMapping */
3056 v8 = FIELD8(keycodes_per_modifier);
3058 LISTofKEYCODE(keycodes, v8);
3061 case 119: /* GetModifierMapping */
3066 case 127: /* NoOperation */
3071 left = tvb_length_remaining(tvb, offset);
3073 proto_tree_add_item(t, hf_x11_undecoded, tvb, offset, left, little_endian);
3076 static void dissect_x11_requests(tvbuff_t *tvb, packet_info *pinfo,
3079 volatile int offset = 0;
3080 int length_remaining;
3085 volatile gboolean is_initial_creq;
3086 guint16 auth_proto_len, auth_data_len;
3087 const char *volatile sep = NULL;
3088 conversation_t *conversation;
3089 x11_conv_data_t *volatile state_info;
3094 while (tvb_reported_length_remaining(tvb, offset) != 0) {
3095 length_remaining = tvb_length_remaining(tvb, offset);
3098 * Can we do reassembly?
3100 if (x11_desegment && pinfo->can_desegment) {
3102 * Yes - is the X11 request header split across
3103 * segment boundaries?
3105 if (length_remaining < 4) {
3107 * Yes. Tell the TCP dissector where the data
3108 * for this message starts in the data it handed
3109 * us, and how many more bytes we need, and return.
3111 pinfo->desegment_offset = offset;
3112 pinfo->desegment_len = 4 - length_remaining;
3118 * Get the state for this conversation; create the conversation
3119 * if we don't have one, and create the state if we don't have
3122 conversation = find_conversation(&pinfo->src, &pinfo->dst,
3123 pinfo->ptype, pinfo->srcport, pinfo->destport, 0);
3124 if (conversation == NULL) {
3128 conversation = conversation_new(&pinfo->src,
3129 &pinfo->dst, pinfo->ptype, pinfo->srcport,
3130 pinfo->destport, 0);
3134 * Is there state attached to this conversation?
3136 state_info = conversation_get_proto_data(conversation, proto_x11);
3137 if (state_info == NULL) {
3139 * No - create a state structure and attach it.
3141 state_info = g_mem_chunk_alloc(x11_state_chunk);
3142 state_info->opcode = NOTHING_SEEN; /* nothing seen yet */
3143 state_info->iconn_frame = 0; /* don't know it yet */
3144 state_info->byte_order = BYTE_ORDER_UNKNOWN; /* don't know it yet */
3145 conversation_add_proto_data(conversation, proto_x11,
3150 * Guess the byte order if we don't already know it.
3152 little_endian = guess_byte_ordering(tvb, pinfo, state_info);
3155 * Get the opcode and length of the putative X11 request.
3157 opcode = VALUE8(tvb, 0);
3158 plen = VALUE16(tvb, offset + 2);
3162 * This can't be 0, as it includes the header length.
3163 * A different choice of byte order wouldn't have
3167 ti = proto_tree_add_item(tree, proto_x11, tvb, offset, -1, FALSE);
3168 t = proto_item_add_subtree(ti, ett_x11);
3169 proto_tree_add_text(t, tvb, offset, -1, "Bogus request length (0)");
3173 if (state_info->iconn_frame == pinfo->fd->num ||
3174 (state_info->opcode == NOTHING_SEEN &&
3175 (opcode == 'B' || opcode == 'l') &&
3176 (plen == 11 || plen == 2816))) {
3180 * we saw this on the first pass and this is
3184 * we haven't already seen any requests, the first
3185 * byte of the message is 'B' or 'l', and the 16-bit
3186 * integer 2 bytes into the data stream is either 11
3187 * or a byte-swapped 11.
3189 * This means it's probably an initial connection
3190 * request, not a message.
3192 * 'B' is decimal 66, which is the opcode for a
3193 * PolySegment request; unfortunately, 11 is a valid
3194 * length for a PolySegment request request, so we
3195 * might mis-identify that request. (Are there any
3196 * other checks we can do?)
3198 * 'l' is decimal 108, which is the opcode for a
3199 * GetScreenSaver request; the only valid length
3200 * for that request is 1.
3202 is_initial_creq = TRUE;
3205 * We now know the byte order. Override the guess.
3207 if (state_info->byte_order == BYTE_ORDER_UNKNOWN) {
3208 if (opcode == 'B') {
3212 state_info->byte_order = BYTE_ORDER_BE;
3213 little_endian = FALSE;
3218 state_info->byte_order = BYTE_ORDER_LE;
3219 little_endian = TRUE;
3224 * Can we do reassembly?
3226 if (x11_desegment && pinfo->can_desegment) {
3228 * Yes - is the fixed-length portion of the
3229 * initial connection header split across
3230 * segment boundaries?
3232 if (length_remaining < 10) {
3234 * Yes. Tell the TCP dissector where the
3235 * data for this message starts in the data
3236 * it handed us, and how many more bytes we
3239 pinfo->desegment_offset = offset;
3240 pinfo->desegment_len = 10 - length_remaining;
3246 * Get the lengths of the authorization protocol and
3247 * the authorization data.
3249 auth_proto_len = VALUE16(tvb, offset + 6);
3250 auth_data_len = VALUE16(tvb, offset + 8);
3251 plen = 12 + ROUND_LENGTH(auth_proto_len) +
3252 ROUND_LENGTH(auth_data_len);
3255 * This is probably an ordinary request.
3257 is_initial_creq = FALSE;
3260 * The length of a request is in 4-byte words.
3266 * Can we do reassembly?
3268 if (x11_desegment && pinfo->can_desegment) {
3270 * Yes - is the X11 request split across segment
3273 if (length_remaining < plen) {
3275 * Yes. Tell the TCP dissector where the data
3276 * for this message starts in the data it handed
3277 * us, and how many more bytes we need, and return.
3279 pinfo->desegment_offset = offset;
3280 pinfo->desegment_len = plen - length_remaining;
3286 * Construct a tvbuff containing the amount of the payload
3287 * we have available. Make its reported length the
3288 * amount of data in the X11 request.
3290 * XXX - if reassembly isn't enabled. the subdissector
3291 * will throw a BoundsError exception, rather than a
3292 * ReportedBoundsError exception. We really want a tvbuff
3293 * where the length is "length", the reported length is "plen",
3294 * and the "if the snapshot length were infinite" length is the
3295 * minimum of the reported length of the tvbuff handed to us
3296 * and "plen", with a new type of exception thrown if the offset
3297 * is within the reported length but beyond that third length,
3298 * with that exception getting the "Unreassembled Packet" error.
3300 length = length_remaining;
3303 next_tvb = tvb_new_subset(tvb, offset, length, plen);
3306 * Set the column appropriately.
3308 if (is_initial_creq) {
3309 if (check_col(pinfo->cinfo, COL_INFO))
3310 col_set_str(pinfo->cinfo, COL_INFO, "Initial connection request");
3314 * We haven't set the column yet; set it.
3316 if (check_col(pinfo->cinfo, COL_INFO))
3317 col_add_str(pinfo->cinfo, COL_INFO, "Requests");
3320 * Initialize the separator.
3327 * Dissect the X11 request.
3329 * Catch the ReportedBoundsError exception; if this
3330 * particular message happens to get a ReportedBoundsError
3331 * exception, that doesn't mean that we should stop
3332 * dissecting X11 requests within this frame or chunk of
3335 * If it gets a BoundsError, we can stop, as there's nothing
3336 * more to see, so we just re-throw it.
3339 if (is_initial_creq) {
3340 dissect_x11_initial_conn(next_tvb, pinfo, tree,
3343 dissect_x11_request(next_tvb, pinfo, tree, sep,
3347 CATCH(BoundsError) {
3350 CATCH(ReportedBoundsError) {
3351 show_reported_bounds_error(tvb, pinfo, tree);
3356 * Skip the X11 message.
3365 dissect_x11_replies(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
3367 /* Set up structures we will need to add the protocol subtree and manage it */
3369 proto_tree *x11_tree;
3371 /* This field shows up as the "Info" column in the display; you should make
3372 it, if possible, summarize what's in the packet, so that a user looking
3373 at the list of packets can tell what type of packet it is. */
3374 if (check_col(pinfo->cinfo, COL_INFO))
3375 col_set_str(pinfo->cinfo, COL_INFO, "Replies/events");
3377 /* In the interest of speed, if "tree" is NULL, don't do any work not
3378 necessary to generate protocol tree items. */
3380 ti = proto_tree_add_item(tree, proto_x11, tvb, 0, -1, FALSE);
3381 x11_tree = proto_item_add_subtree(ti, ett_x11);
3384 * XXX - dissect these in a loop, like the requests.
3386 call_dissector(data_handle,tvb, pinfo, x11_tree);
3389 /************************************************************************
3391 *** I N I T I A L I Z A T I O N A N D M A I N ***
3393 ************************************************************************/
3396 dissect_x11(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
3398 if (check_col(pinfo->cinfo, COL_PROTOCOL))
3399 col_set_str(pinfo->cinfo, COL_PROTOCOL, "X11");
3401 if (pinfo->match_port == pinfo->destport)
3402 dissect_x11_requests(tvb, pinfo, tree);
3404 dissect_x11_replies(tvb, pinfo, tree);
3407 /* Register the protocol with Ethereal */
3408 void proto_register_x11(void)
3411 /* Setup list of header fields */
3412 static hf_register_info hf[] = {
3414 { &hf_x11_FIELDABBREV,
3415 { "FIELDNAME", "x11.FIELDABBREV",
3416 FIELDTYPE, FIELDBASE, FIELDCONVERT, BITMASK,
3417 "FIELDDESCR", HFILL }
3420 #include "x11-register-info.h"
3423 /* Setup protocol subtree array */
3424 static gint *ett[] = {
3426 &ett_x11_color_flags,
3427 &ett_x11_list_of_arc,
3429 &ett_x11_list_of_atom,
3430 &ett_x11_list_of_card32,
3431 &ett_x11_list_of_color_item,
3432 &ett_x11_color_item,
3433 &ett_x11_list_of_keycode,
3434 &ett_x11_list_of_keysyms,
3436 &ett_x11_list_of_point,
3438 &ett_x11_list_of_rectangle,
3440 &ett_x11_list_of_segment,
3442 &ett_x11_list_of_string8,
3443 &ett_x11_list_of_text_item,
3445 &ett_x11_gc_value_mask,
3446 &ett_x11_event_mask,
3447 &ett_x11_do_not_propagate_mask,
3448 &ett_x11_set_of_key_mask,
3449 &ett_x11_pointer_event_mask,
3450 &ett_x11_window_value_mask,
3451 &ett_x11_configure_window_mask,
3452 &ett_x11_keyboard_value_mask,
3454 module_t *x11_module;
3456 /* Register the protocol name and description */
3457 proto_x11 = proto_register_protocol("X11", "X11", "x11");
3459 /* Required function calls to register the header fields and subtrees used */
3460 proto_register_field_array(proto_x11, hf, array_length(hf));
3461 proto_register_subtree_array(ett, array_length(ett));
3463 register_init_routine(x11_init_protocol);
3465 x11_module = prefs_register_protocol(proto_x11, NULL);
3466 prefs_register_bool_preference(x11_module, "desegment",
3467 "Desegment all X11 messages spanning multiple TCP segments",
3468 "Whether the X11 dissector should desegment all messages spanning multiple TCP segments",
3473 proto_reg_handoff_x11(void)
3475 dissector_handle_t x11_handle;
3477 x11_handle = create_dissector_handle(dissect_x11, proto_x11);
3478 dissector_add("tcp.port", TCP_PORT_X11, x11_handle);
3479 dissector_add("tcp.port", TCP_PORT_X11_2, x11_handle);
3480 dissector_add("tcp.port", TCP_PORT_X11_3, x11_handle);
3481 data_handle = find_dissector("data");