2 * Routines for X11 dissection
3 * Copyright 2000, Christophe Tronche <ch.tronche@computer.org>
5 * $Id: packet-x11.c,v 1.47 2003/09/21 20:06:01 gerald 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/
63 #include <epan/packet.h>
64 #include <epan/conversation.h>
67 #include "packet-frame.h"
69 #define cVALS(x) (const value_string*)(x)
71 /* Initialize the protocol and registered fields */
72 static int proto_x11 = -1;
74 #include "x11-declarations.h"
76 /* Initialize the subtree pointers */
77 static gint ett_x11 = -1;
78 static gint ett_x11_color_flags = -1;
79 static gint ett_x11_list_of_arc = -1;
80 static gint ett_x11_arc = -1;
81 static gint ett_x11_list_of_atom = -1;
82 static gint ett_x11_list_of_card32 = -1;
83 static gint ett_x11_list_of_color_item = -1;
84 static gint ett_x11_color_item = -1;
85 static gint ett_x11_list_of_keycode = -1;
86 static gint ett_x11_list_of_keysyms = -1;
87 static gint ett_x11_keysym = -1;
88 static gint ett_x11_list_of_point = -1;
89 static gint ett_x11_point = -1;
90 static gint ett_x11_list_of_rectangle = -1;
91 static gint ett_x11_rectangle = -1;
92 static gint ett_x11_list_of_segment = -1;
93 static gint ett_x11_segment = -1;
94 static gint ett_x11_list_of_string8 = -1;
95 static gint ett_x11_list_of_text_item = -1;
96 static gint ett_x11_text_item = -1;
97 static gint ett_x11_gc_value_mask = -1;
98 static gint ett_x11_event_mask = -1;
99 static gint ett_x11_do_not_propagate_mask = -1;
100 static gint ett_x11_set_of_key_mask = -1;
101 static gint ett_x11_pointer_event_mask = -1;
102 static gint ett_x11_window_value_mask = -1;
103 static gint ett_x11_configure_window_mask = -1;
104 static gint ett_x11_keyboard_value_mask = -1;
106 /* desegmentation of X11 messages */
107 static gboolean x11_desegment = TRUE;
109 static dissector_handle_t data_handle;
111 #define TCP_PORT_X11 6000
112 #define TCP_PORT_X11_2 6001
113 #define TCP_PORT_X11_3 6002
116 * Round a length to a multiple of 4 bytes.
118 #define ROUND_LENGTH(n) ((((n) + 3)/4) * 4)
120 /************************************************************************
122 *** E N U M T A B L E S D E F I N I T I O N S ***
124 ************************************************************************/
126 static const value_string byte_order_vals[] = {
127 { 'B', "Big-endian" },
128 { 'l', "Little-endian" },
132 static const value_string access_mode_vals[] = {
138 static const value_string all_temporary_vals[] = {
139 { 0, "AllTemporary" },
143 static const value_string alloc_vals[] = {
149 static const value_string allow_events_mode_vals[] = {
150 { 0, "AsyncPointer" },
151 { 1, "SyncPointer" },
152 { 2, "ReplayPointer" },
153 { 3, "AsyncKeyboard" },
154 { 4, "SyncKeyboard" },
155 { 5, "ReplayKeyboard" },
161 static const value_string arc_mode_vals[] = {
167 static const char *atom_predefined_interpretation[] = {
219 "UNDERLINE_POSITION",
220 "UNDERLINE_THICKNESS",
239 static const value_string auto_repeat_mode_vals[] = {
246 static const value_string background_pixmap_vals[] = {
248 { 1, "ParentRelative" },
252 static const value_string backing_store_vals[] = {
259 static const value_string border_pixmap_vals[] = {
260 { 0, "CopyFromParent" },
264 static const value_string button_vals[] = {
265 { 0x8000, "AnyButton" },
269 static const value_string cap_style_vals[] = {
277 static const value_string class_vals[] = {
284 static const value_string close_down_mode_vals[] = {
286 { 1, "RetainPermanent" },
287 { 2, "RetainTemporary" },
291 static const value_string coordinate_mode_vals[] = {
297 static const value_string direction_vals[] = {
298 { 0, "RaiseLowest" },
299 { 1, "LowerHighest" },
303 #define FAMILY_INTERNET 0
304 #define FAMILY_DECNET 1
305 #define FAMILY_CHAOS 2
307 static const value_string family_vals[] = {
308 { FAMILY_INTERNET, "Internet" },
309 { FAMILY_DECNET, "DECnet" },
310 { FAMILY_CHAOS, "Chaos" },
314 static const value_string fill_rule_vals[] = {
320 static const value_string fill_style_vals[] = {
324 { 3, "OpaqueStippled" },
328 static const value_string focus_vals[] = {
330 { 1, "PointerRoot" },
334 static const value_string function_vals[] = {
339 { 4, "AndInverted" },
347 { 12, "CopyInverted" },
348 { 13, "OrInverted" },
354 static const value_string gravity_vals[] = {
368 static const value_string image_format_vals[] = {
375 static const value_string image_pixmap_format_vals[] = {
381 static const value_string join_style_vals[] = {
388 static const value_string key_vals[] = {
393 #include "packet-x11-keysym.h"
395 static const value_string line_style_vals[] = {
402 static const value_string mode_vals[] = {
409 static const value_string on_off_vals[] = {
415 static const value_string opcode_vals[] = {
416 { 1, "CreateWindow" },
417 { 2, "ChangeWindowAttributes" },
418 { 3, "GetWindowAttributes" },
419 { 4, "DestroyWindow" },
420 { 5, "DestroySubwindows" },
421 { 6, "ChangeSaveSet" },
422 { 7, "ReparentWindow" },
424 { 9, "MapSubwindows" },
425 { 10, "UnmapWindow" },
426 { 11, "UnmapSubwindows" },
427 { 12, "ConfigureWindow" },
428 { 13, "CirculateWindow" },
429 { 14, "GetGeometry" },
431 { 16, "InternAtom" },
432 { 17, "GetAtomName" },
433 { 18, "ChangeProperty" },
434 { 19, "DeleteProperty" },
435 { 20, "GetProperty" },
436 { 21, "ListProperties" },
437 { 22, "SetSelectionOwner" },
438 { 23, "GetSelectionOwner" },
439 { 24, "ConvertSelection" },
441 { 26, "GrabPointer" },
442 { 27, "UngrabPointer" },
443 { 28, "GrabButton" },
444 { 29, "UngrabButton" },
445 { 30, "ChangeActivePointerGrab" },
446 { 31, "GrabKeyboard" },
447 { 32, "UngrabKeyboard" },
450 { 35, "AllowEvents" },
451 { 36, "GrabServer" },
452 { 37, "UngrabServer" },
453 { 38, "QueryPointer" },
454 { 39, "GetMotionEvents" },
455 { 40, "TranslateCoordinates" },
456 { 41, "WarpPointer" },
457 { 42, "SetInputFocus" },
458 { 43, "GetInputFocus" },
459 { 44, "QueryKeymap" },
463 { 48, "QueryTextExtents" },
465 { 50, "ListFontsWithInfo" },
466 { 51, "SetFontPath" },
467 { 52, "GetFontPath" },
468 { 53, "CreatePixmap" },
469 { 54, "FreePixmap" },
474 { 59, "SetClipRectangles" },
481 { 66, "PolySegment" },
482 { 67, "PolyRectangle" },
485 { 70, "PolyFillRectangle" },
486 { 71, "PolyFillArc" },
490 { 75, "PolyText16" },
491 { 76, "ImageText8" },
492 { 77, "ImageText16" },
493 { 78, "CreateColormap" },
494 { 79, "FreeColormap" },
495 { 80, "CopyColormapAndFree" },
496 { 81, "InstallColormap" },
497 { 82, "UninstallColormap" },
498 { 83, "ListInstalledColormaps" },
499 { 84, "AllocColor" },
500 { 85, "AllocNamedColor" },
501 { 86, "AllocColorCells" },
502 { 87, "AllocColorPlanes" },
503 { 88, "FreeColors" },
504 { 89, "StoreColors" },
505 { 90, "StoreNamedColor" },
506 { 91, "QueryColors" },
507 { 92, "LookupColor" },
508 { 93, "CreateCursor" },
509 { 94, "CreateGlyphCursor" },
510 { 95, "FreeCursor" },
511 { 96, "RecolorCursor" },
512 { 97, "QueryBestSize" },
513 { 98, "QueryExtension" },
514 { 99, "ListExtensions" },
515 { 100, "ChangeKeyboardMapping" },
516 { 101, "GetKeyboardMapping" },
517 { 102, "ChangeKeyboardControl" },
518 { 103, "GetKeyboardControl" },
520 { 105, "ChangePointerControl" },
521 { 106, "GetPointerControl" },
522 { 107, "SetScreenSaver" },
523 { 108, "GetScreenSaver" },
524 { 109, "ChangeHosts" },
525 { 110, "ListHosts" },
526 { 111, "SetAccessControl" },
527 { 112, "SetCloseDownMode" },
528 { 113, "KillClient" },
529 { 114, "RotateProperties" },
530 { 115, "ForceScreenSaver" },
531 { 116, "SetPointerMapping" },
532 { 117, "GetPointerMapping" },
533 { 118, "SetModifierMapping" },
534 { 119, "GetModifierMapping" },
535 { 127, "NoOperation" },
539 static const value_string ordering_vals[] = {
547 static const value_string plane_mask_vals[] = {
548 { 0xFFFFFFFF, "AllPlanes" },
552 static const value_string pointer_keyboard_mode_vals[] = {
553 { 0, "Synchronous" },
554 { 1, "Asynchronous" },
558 static const value_string revert_to_vals[] = {
560 { 1, "PointerRoot" },
565 static const value_string insert_delete_vals[] = {
571 static const value_string screen_saver_mode_vals[] = {
577 static const value_string shape_vals[] = {
584 static const value_string stack_mode_vals[] = {
593 static const value_string subwindow_mode_vals[] = {
594 { 0, "ClipByChildren" },
595 { 1, "IncludeInferiors" },
599 static const value_string window_class_vals[] = {
600 { 0, "CopyFromParent" },
601 { 1, "InputOutput" },
606 static const value_string yes_no_default_vals[] = {
613 static const value_string zero_is_any_property_type_vals[] = {
614 { 0, "AnyPropertyType" },
618 static const value_string zero_is_none_vals[] = {
623 /************************************************************************
625 *** F I E L D D E C O D I N G M A C R O S ***
627 ************************************************************************/
629 #define VALUE8(tvb, offset) (tvb_get_guint8(tvb, offset))
630 #define VALUE16(tvb, offset) (little_endian ? tvb_get_letohs(tvb, offset) : tvb_get_ntohs(tvb, offset))
631 #define VALUE32(tvb, offset) (little_endian ? tvb_get_letohl(tvb, offset) : tvb_get_ntohl(tvb, offset))
633 #define FIELD8(name) (field8(tvb, offsetp, t, hf_x11_##name, little_endian))
634 #define FIELD16(name) (field16(tvb, offsetp, t, hf_x11_##name, little_endian))
635 #define FIELD32(name) (field32(tvb, offsetp, t, hf_x11_##name, little_endian))
637 #define BITFIELD(TYPE, position, name) {\
639 int save = *offsetp;\
640 proto_tree_add_item(bitmask_tree, hf_x11_##position##_##name, tvb, bitmask_offset, \
641 bitmask_size, little_endian); \
642 if (bitmask_value & proto_registrar_get_nth(hf_x11_##position##_##name) -> bitmask) {\
644 unused = save + 4 - *offsetp;\
646 proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, unused, little_endian);\
647 *offsetp = save + 4;\
651 #define FLAG(position, name) {\
652 proto_tree_add_boolean(bitmask_tree, hf_x11_##position##_mask##_##name, tvb, bitmask_offset, bitmask_size, bitmask_value); }
654 #define FLAG_IF_NONZERO(position, name) {\
655 if (bitmask_value & proto_registrar_get_nth(hf_x11_##position##_mask##_##name) -> bitmask)\
656 proto_tree_add_boolean(bitmask_tree, hf_x11_##position##_mask##_##name, tvb, bitmask_offset, bitmask_size, bitmask_value); }
658 #define ATOM(name) { atom(tvb, offsetp, t, hf_x11_##name, little_endian); }
659 #define BITGRAVITY(name) { gravity(tvb, offsetp, t, hf_x11_##name, "Forget"); }
660 #define BITMASK(name, size) {\
662 guint32 bitmask_value; \
663 int bitmask_offset; \
665 proto_tree *bitmask_tree; \
666 bitmask_value = ((size == 1) ? (guint32)VALUE8(tvb, *offsetp) : \
667 ((size == 2) ? (guint32)VALUE16(tvb, *offsetp) : \
668 (guint32)VALUE32(tvb, *offsetp))); \
669 bitmask_offset = *offsetp; \
670 bitmask_size = size; \
671 ti = proto_tree_add_uint(t, hf_x11_##name##_mask, tvb, *offsetp, size, bitmask_value); \
672 bitmask_tree = proto_item_add_subtree(ti, ett_x11_##name##_mask); \
675 #define BITMASK8(name) BITMASK(name, 1);
676 #define BITMASK16(name) BITMASK(name, 2);
677 #define BITMASK32(name) BITMASK(name, 4);
678 #define BOOL(name) (add_boolean(tvb, offsetp, t, hf_x11_##name))
679 #define BUTTON(name) { FIELD8(name); }
680 #define CARD8(name) { FIELD8(name); }
681 #define CARD16(name) (FIELD16(name))
682 #define CARD32(name) (FIELD32(name))
683 #define COLOR_FLAGS(name) { colorFlags(tvb, offsetp, t); }
684 #define COLORMAP(name) { FIELD32(name); }
685 #define CURSOR(name) { FIELD32(name); }
686 #define DRAWABLE(name) { FIELD32(name); }
687 #define ENUM8(name) (FIELD8(name))
688 #define ENUM16(name) { FIELD16(name); }
689 #define FONT(name) { FIELD32(name); }
690 #define FONTABLE(name) { FIELD32(name); }
691 #define GCONTEXT(name) { FIELD32(name); }
692 #define INT8(name) { FIELD8(name); }
693 #define INT16(name) { FIELD16(name); }
694 #define KEYCODE(name) { FIELD8(name); }
695 #define LISTofARC(name) { listOfArc(tvb, offsetp, t, hf_x11_##name, (next_offset - *offsetp) / 12, little_endian); }
696 #define LISTofATOM(name, length) { listOfAtom(tvb, offsetp, t, hf_x11_##name, (length) / 4, little_endian); }
697 #define LISTofBYTE(name, length) { listOfByte(tvb, offsetp, t, hf_x11_##name, (length), little_endian); }
698 #define LISTofCARD8(name, length) { listOfByte(tvb, offsetp, t, hf_x11_##name, (length), little_endian); }
699 #define LISTofCARD32(name, length) { listOfCard32(tvb, offsetp, t, hf_x11_##name, hf_x11_##name##_item, (length) / 4, little_endian); }
700 #define LISTofCOLORITEM(name, length) { listOfColorItem(tvb, offsetp, t, hf_x11_##name, (length) / 12, little_endian); }
701 #define LISTofKEYCODE(name, length) { listOfKeycode(tvb, offsetp, t, hf_x11_##name, (length), little_endian); }
702 #define LISTofKEYSYM(name, keycode_count, keysyms_per_keycode) { \
703 listOfKeysyms(tvb, offsetp, t, hf_x11_##name, hf_x11_##name##_item, (keycode_count), (keysyms_per_keycode), little_endian); }
704 #define LISTofPOINT(name, length) { listOfPoint(tvb, offsetp, t, hf_x11_##name, (length) / 4, little_endian); }
705 #define LISTofRECTANGLE(name) { listOfRectangle(tvb, offsetp, t, hf_x11_##name, (next_offset - *offsetp) / 8, little_endian); }
706 #define LISTofSEGMENT(name) { listOfSegment(tvb, offsetp, t, hf_x11_##name, (next_offset - *offsetp) / 8, little_endian); }
707 #define LISTofSTRING8(name, length) { listOfString8(tvb, offsetp, t, hf_x11_##name, hf_x11_##name##_string, (length), little_endian); }
708 #define LISTofTEXTITEM8(name) { listOfTextItem(tvb, offsetp, t, hf_x11_##name, FALSE, next_offset, little_endian); }
709 #define LISTofTEXTITEM16(name) { listOfTextItem(tvb, offsetp, t, hf_x11_##name, TRUE, next_offset, little_endian); }
710 #define OPCODE() { opcode = FIELD8(opcode); }
711 #define PIXMAP(name) { FIELD32(name); }
712 #define REQUEST_LENGTH() (requestLength(tvb, offsetp, t, little_endian))
713 #define SETofEVENT(name) { setOfEvent(tvb, offsetp, t, little_endian); }
714 #define SETofDEVICEEVENT(name) { setOfDeviceEvent(tvb, offsetp, t, little_endian);}
715 #define SETofKEYMASK(name) { setOfKeyMask(tvb, offsetp, t, little_endian); }
716 #define SETofPOINTEREVENT(name) { setOfPointerEvent(tvb, offsetp, t, little_endian); }
717 #define STRING8(name, length) { string8(tvb, offsetp, t, hf_x11_##name, length); }
718 #define STRING16(name, length) { string16(tvb, offsetp, t, hf_x11_##name, hf_x11_##name##_bytes, length, little_endian); }
719 #define TIMESTAMP(name){ timestamp(tvb, offsetp, t, hf_x11_##name, little_endian); }
720 #define UNDECODED(x) { proto_tree_add_item(t, hf_x11_undecoded, tvb, *offsetp, x, little_endian); *offsetp += x; }
721 #define UNUSED(x) { proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, x, little_endian); *offsetp += x; }
722 #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; }
723 #define WINDOW(name) { FIELD32(name); }
724 #define WINGRAVITY(name) { gravity(tvb, offsetp, t, hf_x11_##name, "Unmap"); }
726 #define VISUALID(name) { gint32 v = VALUE32(tvb, *offsetp); \
727 proto_tree_add_uint_format(t, hf_x11_##name, tvb, *offsetp, 4, v, "Visualid: 0x%08x%s", v, \
728 v ? "" : " (CopyFromParent)"); *offsetp += 4; }
730 /************************************************************************
732 *** D E C O D I N G F I E L D S ***
734 ************************************************************************/
736 static void atom(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
737 gboolean little_endian)
739 const char *interpretation = NULL;
741 guint32 v = VALUE32(tvb, *offsetp);
742 if (v >= 1 && v < array_length(atom_predefined_interpretation))
743 interpretation = atom_predefined_interpretation[v];
745 interpretation = "Not a predefined atom";
747 header_field_info *hfi = proto_registrar_get_nth(hf);
749 interpretation = match_strval(v, cVALS(hfi -> strings));
751 if (!interpretation) interpretation = "error in Xlib client program ?";
752 proto_tree_add_uint_format(t, hf, tvb, *offsetp, 4, v, "%s: %u (%s)",
753 proto_registrar_get_nth(hf) -> name, v, interpretation);
757 static guint32 add_boolean(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf)
759 guint32 v = VALUE8(tvb, *offsetp);
760 proto_tree_add_boolean(t, hf, tvb, *offsetp, 1, v);
765 static void colorFlags(tvbuff_t *tvb, int *offsetp, proto_tree *t)
767 unsigned do_red_green_blue = VALUE8(tvb, *offsetp);
771 if (do_red_green_blue) {
774 char *bp = buffer + sprintf(buffer, "flags: ");
776 if (do_red_green_blue & 0x1) {
777 bp += sprintf(bp, "DoRed");
781 if (do_red_green_blue & 0x2) {
782 if (sep) bp += sprintf(bp, " | ");
783 bp += sprintf(bp, "DoGreen");
787 if (do_red_green_blue & 0x4) {
788 if (sep) bp += sprintf(bp, " | ");
789 bp += sprintf(bp, "DoBlue");
793 if (do_red_green_blue & 0xf8) {
794 if (sep) bp += sprintf(bp, " + ");
795 sprintf(bp, "trash");
798 ti = proto_tree_add_uint_format(t, hf_x11_coloritem_flags, tvb, *offsetp, 1, do_red_green_blue,
800 tt = proto_item_add_subtree(ti, ett_x11_color_flags);
801 if (do_red_green_blue & 0x1)
802 proto_tree_add_boolean(tt, hf_x11_coloritem_flags_do_red, tvb, *offsetp, 1,
803 do_red_green_blue & 0x1);
804 if (do_red_green_blue & 0x2)
805 proto_tree_add_boolean(tt, hf_x11_coloritem_flags_do_green, tvb, *offsetp, 1,
806 do_red_green_blue & 0x2);
807 if (do_red_green_blue & 0x4)
808 proto_tree_add_boolean(tt, hf_x11_coloritem_flags_do_blue, tvb, *offsetp, 1,
809 do_red_green_blue & 0x4);
810 if (do_red_green_blue & 0xf8)
811 proto_tree_add_boolean(tt, hf_x11_coloritem_flags_unused, tvb, *offsetp, 1,
812 do_red_green_blue & 0xf8);
814 proto_tree_add_uint_format(t, hf_x11_coloritem_flags, tvb, *offsetp, 1, do_red_green_blue,
819 static void gravity(tvbuff_t *tvb, int *offsetp, proto_tree *t,
820 int hf, const char *nullInterpretation)
822 guint8 v = VALUE8(tvb, *offsetp);
825 proto_tree_add_uint_format(t, hf, tvb, *offsetp, 1, v, "%s: 0 (%s)",
826 proto_registrar_get_nth(hf) -> name,
829 proto_tree_add_uint(t, hf, tvb, *offsetp, 1, v);
833 static void listOfArc(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
834 int length, gboolean little_endian)
836 proto_item *ti = proto_tree_add_item(t, hf, tvb, *offsetp, length * 8, little_endian);
837 proto_tree *tt = proto_item_add_subtree(ti, ett_x11_list_of_arc);
839 gint16 x = VALUE16(tvb, *offsetp);
840 gint16 y = VALUE16(tvb, *offsetp + 2);
841 guint16 width = VALUE16(tvb, *offsetp + 4);
842 guint16 height = VALUE16(tvb, *offsetp + 6);
843 gint16 angle1 = VALUE16(tvb, *offsetp + 8);
844 gint16 angle2 = VALUE16(tvb, *offsetp + 10);
846 proto_item *tti = proto_tree_add_none_format(tt, hf_x11_arc, tvb, *offsetp, 12,
847 "arc: %dx%d+%d+%d, angle %d -> %d (%f degrees -> %f degrees)",
848 width, height, x, y, angle1, angle2,
849 angle1 / 64.0, angle2 / 64.0);
850 proto_tree *ttt = proto_item_add_subtree(tti, ett_x11_arc);
851 proto_tree_add_int(ttt, hf_x11_arc_x, tvb, *offsetp, 2, x);
853 proto_tree_add_int(ttt, hf_x11_arc_y, tvb, *offsetp, 2, y);
855 proto_tree_add_uint(ttt, hf_x11_arc_width, tvb, *offsetp, 2, y);
857 proto_tree_add_uint(ttt, hf_x11_arc_height, tvb, *offsetp, 2, y);
859 proto_tree_add_int(ttt, hf_x11_arc_angle1, tvb, *offsetp, 2, y);
861 proto_tree_add_int(ttt, hf_x11_arc_angle2, tvb, *offsetp, 2, y);
866 static void listOfAtom(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
867 int length, gboolean little_endian)
869 proto_item *ti = proto_tree_add_item(t, hf, tvb, *offsetp, length * 4, little_endian);
870 proto_tree *tt = proto_item_add_subtree(ti, ett_x11_list_of_atom);
872 atom(tvb, offsetp, tt, hf_x11_properties_item, little_endian);
875 static void listOfByte(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
876 int length, gboolean little_endian)
878 if (length <= 0) length = 1;
879 proto_tree_add_item(t, hf, tvb, *offsetp, length, little_endian);
883 static void listOfCard32(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
884 int hf_item, int length, gboolean little_endian)
886 proto_item *ti = proto_tree_add_item(t, hf, tvb, *offsetp, length * 4, little_endian);
887 proto_tree *tt = proto_item_add_subtree(ti, ett_x11_list_of_card32);
889 proto_tree_add_uint(tt, hf_item, tvb, *offsetp, 4, VALUE32(tvb, *offsetp));
894 static void listOfColorItem(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
895 int length, gboolean little_endian)
897 proto_item *ti = proto_tree_add_item(t, hf, tvb, *offsetp, length * 8, little_endian);
898 proto_tree *tt = proto_item_add_subtree(ti, ett_x11_list_of_color_item);
902 unsigned do_red_green_blue;
903 guint16 red, green, blue;
908 red = VALUE16(tvb, *offsetp + 4);
909 green = VALUE16(tvb, *offsetp + 6);
910 blue = VALUE16(tvb, *offsetp + 8);
911 do_red_green_blue = VALUE8(tvb, *offsetp + 10);
913 bp = buffer + sprintf(buffer, "colorItem: ");
915 if (do_red_green_blue & 0x1) {
916 bp += sprintf(bp, "red = %d", red);
919 if (do_red_green_blue & 0x2) {
920 bp += sprintf(bp, "%sgreen = %d", sep, green);
923 if (do_red_green_blue & 0x4)
924 bp += sprintf(bp, "%sblue = %d", sep, blue);
926 tti = proto_tree_add_none_format(tt, hf_x11_coloritem, tvb, *offsetp, 12, "%s", buffer);
927 ttt = proto_item_add_subtree(tti, ett_x11_color_item);
928 proto_tree_add_item(ttt, hf_x11_coloritem_pixel, tvb, *offsetp, 4, little_endian);
930 proto_tree_add_item(ttt, hf_x11_coloritem_red, tvb, *offsetp, 2, little_endian);
932 proto_tree_add_item(ttt, hf_x11_coloritem_green, tvb, *offsetp, 2, little_endian);
934 proto_tree_add_item(ttt, hf_x11_coloritem_blue, tvb, *offsetp, 2, little_endian);
936 colorFlags(tvb, offsetp, ttt);
937 proto_tree_add_item(ttt, hf_x11_coloritem_unused, tvb, *offsetp, 1, little_endian);
942 static GTree *keysymTable = NULL;
944 static gint compareGuint32(gconstpointer a, gconstpointer b)
946 return GPOINTER_TO_INT(b) - GPOINTER_TO_INT(a);
949 static const char *keysymString(guint32 v)
954 /* This table is so big that we built it only if necessary */
956 const value_string *p = keysym_vals_source;
957 keysymTable = g_tree_new(compareGuint32);
958 for(; p -> strptr; p++)
959 g_tree_insert(keysymTable, GINT_TO_POINTER(p -> value), p -> strptr);
961 res = g_tree_lookup(keysymTable, GINT_TO_POINTER(v));
962 return res ? res : "Unknown";
965 static const char *modifiers[] = { "Shift", "Lock", "Control", "Mod1", "Mod2", "Mod3", "Mod4", "Mod5" };
967 static void listOfKeycode(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
968 int length, gboolean little_endian)
971 proto_item *ti = proto_tree_add_item(t, hf, tvb, *offsetp, length * 8, little_endian);
972 proto_tree *tt = proto_item_add_subtree(ti, ett_x11_list_of_keycode);
979 for(i = 8, m = modifiers; i; i--, m++) {
980 guchar c = tvb_get_guint8(tvb, *offsetp);
983 bp += sprintf(bp, " %s=%d", *m, c);
986 proto_tree_add_bytes_format(tt, hf_x11_keycodes_item, tvb, *offsetp - 8, 8, tvb_get_ptr(tvb, *offsetp - 8, 8), "item: %s", buffer);
990 static void listOfKeysyms(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
991 int hf_item, int keycode_count,
992 int keysyms_per_keycode, gboolean little_endian)
994 proto_item *ti = proto_tree_add_item(t, hf, tvb, *offsetp, keycode_count * keysyms_per_keycode * 4, little_endian);
995 proto_tree *tt = proto_item_add_subtree(ti, ett_x11_list_of_keysyms);
1000 while(keycode_count--) {
1001 tti = proto_tree_add_none_format(tt, hf_item, tvb, *offsetp, keysyms_per_keycode * 4,
1003 ttt = proto_item_add_subtree(tti, ett_x11_keysym);
1004 for(i = keysyms_per_keycode; i; i--) {
1005 guint32 v = VALUE32(tvb, *offsetp);
1006 proto_item_append_text(tti, " %s", keysymString(v));
1007 proto_tree_add_uint_format(ttt, hf_x11_keysyms_item_keysym, tvb, *offsetp, 4, v,
1008 "keysym: 0x%08x (%s)", v, keysymString(v));
1014 static void listOfPoint(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
1015 int length, gboolean little_endian)
1017 proto_item *ti = proto_tree_add_item(t, hf, tvb, *offsetp, length * 4, little_endian);
1018 proto_tree *tt = proto_item_add_subtree(ti, ett_x11_list_of_point);
1024 x = VALUE16(tvb, *offsetp);
1025 y = VALUE16(tvb, *offsetp + 2);
1027 tti = proto_tree_add_none_format(tt, hf_x11_point, tvb, *offsetp, 4, "point: (%d,%d)", x, y);
1028 ttt = proto_item_add_subtree(tti, ett_x11_point);
1029 proto_tree_add_int(ttt, hf_x11_point_x, tvb, *offsetp, 2, x);
1031 proto_tree_add_int(ttt, hf_x11_point_y, tvb, *offsetp, 2, y);
1036 static void listOfRectangle(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
1037 int length, gboolean little_endian)
1039 proto_item *ti = proto_tree_add_item(t, hf, tvb, *offsetp, length * 8, little_endian);
1040 proto_tree *tt = proto_item_add_subtree(ti, ett_x11_list_of_rectangle);
1043 unsigned width, height;
1047 x = VALUE16(tvb, *offsetp);
1048 y = VALUE16(tvb, *offsetp + 2);
1049 width = VALUE16(tvb, *offsetp + 4);
1050 height = VALUE16(tvb, *offsetp + 6);
1052 tti = proto_tree_add_none_format(tt, hf_x11_rectangle, tvb, *offsetp, 8,
1053 "rectangle: %dx%d+%d+%d", width, height, x, y);
1054 ttt = proto_item_add_subtree(tti, ett_x11_rectangle);
1055 proto_tree_add_int(ttt, hf_x11_rectangle_x, tvb, *offsetp, 2, x);
1057 proto_tree_add_int(ttt, hf_x11_rectangle_y, tvb, *offsetp, 2, y);
1059 proto_tree_add_uint(ttt, hf_x11_rectangle_width, tvb, *offsetp, 2, width);
1061 proto_tree_add_uint(ttt, hf_x11_rectangle_height, tvb, *offsetp, 2, height);
1066 static void listOfSegment(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
1067 int length, gboolean little_endian)
1069 proto_item *ti = proto_tree_add_item(t, hf, tvb, *offsetp, length * 8, little_endian);
1070 proto_tree *tt = proto_item_add_subtree(ti, ett_x11_list_of_segment);
1072 gint16 x1, y1, x2, y2;
1076 x1 = VALUE16(tvb, *offsetp);
1077 y1 = VALUE16(tvb, *offsetp + 2);
1078 x2 = VALUE16(tvb, *offsetp + 4);
1079 y2 = VALUE16(tvb, *offsetp + 6);
1081 tti = proto_tree_add_none_format(tt, hf_x11_segment, tvb, *offsetp, 8,
1082 "segment: (%d,%d)-(%d,%d)", x1, y1, x2, y2);
1083 ttt = proto_item_add_subtree(tti, ett_x11_segment);
1084 proto_tree_add_item(ttt, hf_x11_segment_x1, tvb, *offsetp, 2, little_endian);
1086 proto_tree_add_item(ttt, hf_x11_segment_y1, tvb, *offsetp, 2, little_endian);
1088 proto_tree_add_item(ttt, hf_x11_segment_x2, tvb, *offsetp, 2, little_endian);
1090 proto_tree_add_item(ttt, hf_x11_segment_y2, tvb, *offsetp, 2, little_endian);
1095 /* XXX - the protocol tree code should handle non-printable characters.
1096 Note that "non-printable characters" may depend on your locale.... */
1097 static void stringCopy(char *dest, const char *source, int length)
1102 if (!isgraph(c) && c != ' ') c = '.';
1108 static void listOfString8(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
1109 int hf_item, int length, gboolean little_endian)
1112 guint allocated = 0;
1117 /* Compute total length */
1119 int scanning_offset = *offsetp; /* Scanning pointer */
1121 for(i = length; i; i--) {
1122 l = tvb_get_guint8(tvb, scanning_offset);
1123 scanning_offset += 1 + l;
1126 ti = proto_tree_add_item(t, hf, tvb, *offsetp, scanning_offset - *offsetp, little_endian);
1127 tt = proto_item_add_subtree(ti, ett_x11_list_of_string8);
1130 * In case we throw an exception, clean up whatever stuff we've
1131 * allocated (if any).
1133 CLEANUP_PUSH(g_free, s);
1136 unsigned l = VALUE8(tvb, *offsetp);
1137 if (allocated < (l + 1)) {
1138 /* g_realloc doesn't work ??? */
1140 s = g_malloc(l + 1);
1143 stringCopy(s, tvb_get_ptr(tvb, *offsetp + 1, l), l); /* Nothing better for now. We need a better string handling API. */
1144 proto_tree_add_string_format(tt, hf_item, tvb, *offsetp, l + 1, s, "\"%s\"", s);
1149 * Call the cleanup handler to free the string and pop the handler.
1151 CLEANUP_CALL_AND_POP;
1154 #define STRING16_MAX_DISPLAYED_LENGTH 150
1156 static int stringIsActuallyAn8BitString(tvbuff_t *tvb, int offset, unsigned length)
1158 if (length > STRING16_MAX_DISPLAYED_LENGTH) length = STRING16_MAX_DISPLAYED_LENGTH;
1159 for(; length > 0; offset += 2, length--) {
1160 if (tvb_get_guint8(tvb, offset))
1166 /* length is the length of the _byte_zone_ (that is, twice the length of the string) */
1168 static void string16_with_buffer_preallocated(tvbuff_t *tvb, proto_tree *t,
1169 int hf, int hf_bytes,
1170 int offset, unsigned length,
1171 char **s, int *sLength,
1172 gboolean little_endian)
1174 int truncated = FALSE;
1175 unsigned l = length / 2;
1177 if (stringIsActuallyAn8BitString(tvb, offset, l)) {
1179 int soffset = offset;
1181 if (l > STRING16_MAX_DISPLAYED_LENGTH) {
1183 l = STRING16_MAX_DISPLAYED_LENGTH;
1185 if (*sLength < (int) l + 3) {
1187 *s = g_malloc(l + 3);
1192 if (truncated) l -= 3;
1196 *dp++ = tvb_get_guint8(tvb, soffset);
1201 /* If truncated, add an ellipsis */
1202 if (truncated) { *dp++ = '.'; *dp++ = '.'; *dp++ = '.'; }
1205 proto_tree_add_string_format(t, hf, tvb, offset, length, tvb_get_ptr(tvb, offset, length), "%s: %s",
1206 proto_registrar_get_nth(hf) -> name, *s);
1208 proto_tree_add_item(t, hf_bytes, tvb, offset, length, little_endian);
1212 static void listOfTextItem(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
1213 int sizeIs16, int next_offset, gboolean little_endian)
1221 /* Compute total length */
1223 int scanning_offset = *offsetp; /* Scanning pointer */
1224 int l; /* Length of an individual item */
1225 int n = 0; /* Number of items */
1227 while(scanning_offset < next_offset) {
1228 l = tvb_get_guint8(tvb, scanning_offset);
1232 scanning_offset += l == 255 ? 4 : l + (sizeIs16 ? l : 0) + 1;
1235 ti = proto_tree_add_item(t, hf, tvb, *offsetp, scanning_offset - *offsetp, little_endian);
1236 tt = proto_item_add_subtree(ti, ett_x11_list_of_text_item);
1239 * In case we throw an exception, clean up whatever stuff we've
1240 * allocated (if any).
1242 CLEANUP_PUSH(g_free, s);
1245 unsigned l = VALUE8(tvb, *offsetp);
1246 if (l == 255) { /* Item is a font */
1247 fid = tvb_get_ntohl(tvb, *offsetp + 1);
1248 proto_tree_add_uint(tt, hf_x11_textitem_font, tvb, *offsetp, 5, fid);
1250 } else { /* Item is a string */
1253 gint8 delta = VALUE8(tvb, *offsetp + 1);
1254 if (sizeIs16) l += l;
1255 if ((unsigned) allocated < l + 1) {
1256 /* g_realloc doesn't work ??? */
1258 s = g_malloc(l + 1);
1261 stringCopy(s, tvb_get_ptr(tvb, *offsetp + 2, l), l);
1262 tti = proto_tree_add_none_format(tt, hf_x11_textitem_string, tvb, *offsetp, l + 2,
1263 "textitem (string): delta = %d, \"%s\"",
1265 ttt = proto_item_add_subtree(tti, ett_x11_text_item);
1266 proto_tree_add_item(ttt, hf_x11_textitem_string_delta, tvb, *offsetp + 1, 1, little_endian);
1268 string16_with_buffer_preallocated(tvb, ttt, hf_x11_textitem_string_string16,
1269 hf_x11_textitem_string_string16_bytes,
1274 proto_tree_add_string_format(ttt, hf_x11_textitem_string_string8, tvb,
1275 *offsetp + 2, l, s, "\"%s\"", s);
1281 * Call the cleanup handler to free the string and pop the handler.
1283 CLEANUP_CALL_AND_POP;
1286 static guint32 field8(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
1287 gboolean little_endian)
1289 guint32 v = VALUE8(tvb, *offsetp);
1290 header_field_info *hfi = proto_registrar_get_nth(hf);
1291 gchar *enumValue = NULL;
1294 enumValue = match_strval(v, cVALS(hfi -> strings));
1296 proto_tree_add_uint_format(t, hf, tvb, *offsetp, 1, v,
1297 hfi -> display == BASE_DEC ? "%s: %u (%s)" : "%s: 0x%02x (%s)",
1298 hfi -> name, v, enumValue);
1300 proto_tree_add_item(t, hf, tvb, *offsetp, 1, little_endian);
1305 static guint32 field16(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
1306 gboolean little_endian)
1308 guint32 v = VALUE16(tvb, *offsetp);
1309 proto_tree_add_item(t, hf, tvb, *offsetp, 2, little_endian);
1314 static guint32 field32(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
1315 gboolean little_endian)
1317 guint32 v = VALUE32(tvb, *offsetp);
1318 header_field_info *hfi = proto_registrar_get_nth(hf);
1319 gchar *enumValue = NULL;
1320 gchar *nameAsChar = hfi -> name;
1323 enumValue = match_strval(v, cVALS(hfi -> strings));
1325 proto_tree_add_uint_format(t, hf, tvb, *offsetp, 4, v,
1326 hfi -> display == BASE_DEC ? "%s: %u (%s)" : "%s: 0x%08x (%s)",
1327 nameAsChar, v, enumValue);
1329 proto_tree_add_uint_format(t, hf, tvb, *offsetp, 4, v,
1330 hfi -> display == BASE_DEC ? "%s: %u" : "%s: 0x%08x",
1336 static void gcAttributes(tvbuff_t *tvb, int *offsetp, proto_tree *t,
1337 gboolean little_endian)
1339 BITMASK32(gc_value);
1340 BITFIELD(ENUM8, gc_value_mask, function);
1341 BITFIELD(CARD32, gc_value_mask, plane_mask);
1342 BITFIELD(CARD32, gc_value_mask, foreground);
1343 BITFIELD(CARD32, gc_value_mask, background);
1344 BITFIELD(CARD16, gc_value_mask, line_width);
1345 BITFIELD(ENUM8, gc_value_mask, line_style);
1346 BITFIELD(ENUM8, gc_value_mask, cap_style);
1347 BITFIELD(ENUM8, gc_value_mask, join_style);
1348 BITFIELD(ENUM8, gc_value_mask, fill_style);
1349 BITFIELD(ENUM8, gc_value_mask, fill_rule);
1350 BITFIELD(PIXMAP, gc_value_mask, tile);
1351 BITFIELD(PIXMAP, gc_value_mask, stipple);
1352 BITFIELD(INT16, gc_value_mask, tile_stipple_x_origin);
1353 BITFIELD(INT16, gc_value_mask, tile_stipple_y_origin);
1354 BITFIELD(FONT, gc_value_mask, font);
1355 BITFIELD(ENUM8, gc_value_mask, subwindow_mode);
1356 BITFIELD(BOOL, gc_value_mask, graphics_exposures);
1357 BITFIELD(INT16, gc_value_mask, clip_x_origin);
1358 BITFIELD(INT16, gc_value_mask, clip_y_origin);
1359 BITFIELD(PIXMAP, gc_value_mask, clip_mask);
1360 BITFIELD(CARD16, gc_value_mask, dash_offset);
1361 BITFIELD(CARD8, gc_value_mask, gc_dashes);
1362 BITFIELD(ENUM8, gc_value_mask, arc_mode);
1366 static void gcMask(tvbuff_t *tvb, int *offsetp, proto_tree *t,
1367 gboolean little_endian)
1369 BITMASK32(gc_value);
1370 FLAG(gc_value, function);
1371 FLAG(gc_value, plane_mask);
1372 FLAG(gc_value, foreground);
1373 FLAG(gc_value, background);
1374 FLAG(gc_value, line_width);
1375 FLAG(gc_value, line_style);
1376 FLAG(gc_value, cap_style);
1377 FLAG(gc_value, join_style);
1378 FLAG(gc_value, fill_style);
1379 FLAG(gc_value, fill_rule);
1380 FLAG(gc_value, tile);
1381 FLAG(gc_value, stipple);
1382 FLAG(gc_value, tile_stipple_x_origin);
1383 FLAG(gc_value, tile_stipple_y_origin);
1384 FLAG(gc_value, font);
1385 FLAG(gc_value, subwindow_mode);
1386 FLAG(gc_value, graphics_exposures);
1387 FLAG(gc_value, clip_x_origin);
1388 FLAG(gc_value, clip_y_origin);
1389 FLAG(gc_value, clip_mask);
1390 FLAG(gc_value, dash_offset);
1391 FLAG(gc_value, gc_dashes);
1392 FLAG(gc_value, arc_mode);
1396 static guint32 requestLength(tvbuff_t *tvb, int *offsetp, proto_tree *t,
1397 gboolean little_endian)
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,
1406 gboolean little_endian)
1409 FLAG(event, KeyPress);
1410 FLAG(event, KeyRelease);
1411 FLAG(event, ButtonPress);
1412 FLAG(event, ButtonRelease);
1413 FLAG(event, EnterWindow);
1414 FLAG(event, LeaveWindow);
1415 FLAG(event, PointerMotion);
1416 FLAG(event, PointerMotionHint);
1417 FLAG(event, Button1Motion);
1418 FLAG(event, Button2Motion);
1419 FLAG(event, Button3Motion);
1420 FLAG(event, Button4Motion);
1421 FLAG(event, Button5Motion);
1422 FLAG(event, ButtonMotion);
1423 FLAG(event, KeymapState);
1424 FLAG(event, Exposure);
1425 FLAG(event, VisibilityChange);
1426 FLAG(event, StructureNotify);
1427 FLAG(event, ResizeRedirect);
1428 FLAG(event, SubstructureNotify);
1429 FLAG(event, SubstructureRedirect);
1430 FLAG(event, FocusChange);
1431 FLAG(event, PropertyChange);
1432 FLAG(event, ColormapChange);
1433 FLAG(event, OwnerGrabButton);
1434 FLAG_IF_NONZERO(event, erroneous_bits);
1438 static void setOfDeviceEvent(tvbuff_t *tvb, int *offsetp, proto_tree *t,
1439 gboolean little_endian)
1441 BITMASK32(do_not_propagate);
1442 FLAG(do_not_propagate, KeyPress);
1443 FLAG(do_not_propagate, KeyRelease);
1444 FLAG(do_not_propagate, ButtonPress);
1445 FLAG(do_not_propagate, ButtonRelease);
1446 FLAG(do_not_propagate, PointerMotion);
1447 FLAG(do_not_propagate, Button1Motion);
1448 FLAG(do_not_propagate, Button2Motion);
1449 FLAG(do_not_propagate, Button3Motion);
1450 FLAG(do_not_propagate, Button4Motion);
1451 FLAG(do_not_propagate, Button5Motion);
1452 FLAG(do_not_propagate, ButtonMotion);
1453 FLAG_IF_NONZERO(do_not_propagate, erroneous_bits);
1457 static void setOfKeyMask(tvbuff_t *tvb, int *offsetp, proto_tree *t,
1458 gboolean little_endian)
1461 guint32 bitmask_value;
1464 proto_tree *bitmask_tree;
1466 bitmask_value = VALUE16(tvb, *offsetp);
1467 bitmask_offset = *offsetp;
1469 if (bitmask_value == 0x8000)
1470 proto_tree_add_uint_format(t, hf_x11_modifiers_mask_AnyModifier, tvb, *offsetp, 2, 0x8000,
1471 "modifiers-masks: 0x8000 (AnyModifier)");
1473 ti = proto_tree_add_uint(t, hf_x11_modifiers_mask, tvb, *offsetp, 2,
1475 bitmask_tree = proto_item_add_subtree(ti, ett_x11_set_of_key_mask);
1476 FLAG(modifiers, Shift);
1477 FLAG(modifiers, Lock);
1478 FLAG(modifiers, Control);
1479 FLAG(modifiers, Mod1);
1480 FLAG(modifiers, Mod2);
1481 FLAG(modifiers, Mod3);
1482 FLAG(modifiers, Mod4);
1483 FLAG(modifiers, Mod5);
1484 FLAG_IF_NONZERO(modifiers, erroneous_bits);
1489 static void setOfPointerEvent(tvbuff_t *tvb, int *offsetp, proto_tree *t,
1490 gboolean little_endian)
1492 BITMASK16(pointer_event);
1493 FLAG(pointer_event, ButtonPress);
1494 FLAG(pointer_event, ButtonRelease);
1495 FLAG(pointer_event, EnterWindow);
1496 FLAG(pointer_event, LeaveWindow);
1497 FLAG(pointer_event, PointerMotion);
1498 FLAG(pointer_event, PointerMotionHint);
1499 FLAG(pointer_event, Button1Motion);
1500 FLAG(pointer_event, Button2Motion);
1501 FLAG(pointer_event, Button3Motion);
1502 FLAG(pointer_event, Button4Motion);
1503 FLAG(pointer_event, Button5Motion);
1504 FLAG(pointer_event, ButtonMotion);
1505 FLAG(pointer_event, KeymapState);
1506 FLAG_IF_NONZERO(pointer_event, erroneous_bits);
1510 static void string8(tvbuff_t *tvb, int *offsetp, proto_tree *t,
1511 int hf, unsigned length)
1513 char *s = g_malloc(length + 1);
1516 * In case we throw an exception, clean up whatever stuff we've
1517 * allocated (if any).
1519 CLEANUP_PUSH(g_free, s);
1521 stringCopy(s, tvb_get_ptr(tvb, *offsetp, length), length);
1522 proto_tree_add_string(t, hf, tvb, *offsetp, length, s);
1525 * Call the cleanup handler to free the string and pop the handler.
1527 CLEANUP_CALL_AND_POP;
1532 /* The length is the length of the _byte_zone_ (twice the length of the string) */
1534 static void string16(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
1535 int hf_bytes, unsigned length, gboolean little_endian)
1541 * In case we throw an exception, clean up whatever stuff we've
1542 * allocated (if any).
1544 CLEANUP_PUSH(g_free, s);
1547 string16_with_buffer_preallocated(tvb, t, hf, hf_bytes, *offsetp, length,
1548 &s, &l, little_endian);
1551 * Call the cleanup handler to free the string and pop the handler.
1553 CLEANUP_CALL_AND_POP;
1558 static void timestamp(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
1559 gboolean little_endian)
1561 guint32 v = VALUE32(tvb, *offsetp);
1564 proto_tree_add_uint_format(t, hf, tvb, *offsetp, 4, 0, "%s: 0 (CurrentTime)",
1565 proto_registrar_get_nth(hf) -> name);
1567 proto_tree_add_uint(t, hf, tvb, *offsetp, 4, v);
1571 static void windowAttributes(tvbuff_t *tvb, int *offsetp, proto_tree *t,
1572 gboolean little_endian)
1574 BITMASK32(window_value);
1575 BITFIELD(PIXMAP, window_value_mask, background_pixmap);
1576 BITFIELD(CARD32, window_value_mask, background_pixel);
1577 BITFIELD(PIXMAP, window_value_mask, border_pixmap);
1578 BITFIELD(CARD32, window_value_mask, border_pixel);
1579 BITFIELD(BITGRAVITY, window_value_mask, bit_gravity);
1580 BITFIELD(WINGRAVITY, window_value_mask, win_gravity);
1581 BITFIELD(ENUM8, window_value_mask, backing_store);
1582 BITFIELD(CARD32, window_value_mask, backing_planes);
1583 BITFIELD(CARD32, window_value_mask, backing_pixel);
1584 BITFIELD(BOOL, window_value_mask, override_redirect);
1585 BITFIELD(BOOL, window_value_mask, save_under);
1586 BITFIELD(SETofEVENT, window_value_mask, event_mask);
1587 BITFIELD(SETofDEVICEEVENT, window_value_mask, do_not_propagate_mask);
1588 BITFIELD(COLORMAP, window_value_mask, colormap);
1589 BITFIELD(CURSOR, window_value_mask, cursor);
1594 * Data structure associated with a conversation; keeps track of the
1595 * request for which we're expecting a reply, the frame number of
1596 * the initial connection request, and the byte order of the connection.
1598 * An opcode of -3 means we haven't yet seen any requests yet.
1599 * An opcode of -2 means we're not expecting a reply.
1600 * An opcode of -1 means means we're waiting for a reply to the initial
1601 * connection request.
1602 * Other values are the opcode of the request for which we're expecting
1605 * XXX - assumes only one outstanding request is awaiting a reply,
1606 * which should always be the case.
1608 #define NOTHING_SEEN -3
1609 #define NOTHING_EXPECTED -2
1610 #define INITIAL_CONN -1
1612 #define BYTE_ORDER_BE 0
1613 #define BYTE_ORDER_LE 1
1614 #define BYTE_ORDER_UNKNOWN -1
1617 int opcode; /* opcode for which we're awaiting a reply */
1618 guint32 iconn_frame; /* frame # of initial connection request */
1619 int byte_order; /* byte order of connection */
1622 static GMemChunk *x11_state_chunk = NULL;
1624 static void x11_init_protocol(void)
1626 if (x11_state_chunk != NULL)
1627 g_mem_chunk_destroy(x11_state_chunk);
1629 x11_state_chunk = g_mem_chunk_new("x11_state_chunk",
1630 sizeof (x11_conv_data_t),
1631 128 * sizeof (x11_conv_data_t),
1635 /************************************************************************
1637 *** G U E S S I N G T H E B Y T E O R D E R I N G ***
1639 ************************************************************************/
1641 /* If we can't guess, we return TRUE (that is little_endian), cause
1642 I'm developing on a Linux box :-). The (non-)guess isn't cached
1643 however, so we may have more luck next time. I'm quite conservative
1644 in my assertions, cause once it's cached, it's stay in cache, and
1645 we may be fooled up by a packet starting with the end of a request
1646 started in a previous packet...
1649 static int numberOfBitSetTable[] = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4 };
1651 static int numberOfBitSet(tvbuff_t *tvb, int offset, int maskLength)
1654 while(maskLength--) {
1655 int c = tvb_get_guint8(tvb, offset);
1657 res += numberOfBitSetTable[c & 0xf] + numberOfBitSetTable[c >> 4];
1662 static int listOfStringLengthConsistent(tvbuff_t *tvb, int offset, int length, int listLength)
1664 if (listLength > length) return FALSE;
1665 while(listLength--) {
1667 if (!tvb_bytes_exist(tvb, offset, 1)) return TRUE;
1668 l = tvb_get_guint8(tvb, offset);
1671 if (l > length) return FALSE;
1672 if (!tvb_bytes_exist(tvb, offset, l)) return TRUE;
1676 if (length > 3) return FALSE;
1680 static int rounded4(int n)
1682 int remainder = n % 4;
1684 if (remainder) res++;
1688 /* We assume the order to be consistent, until proven wrong. */
1690 static gboolean consistentWithOrder(int length, tvbuff_t *tvb, int offset, guint16 (*v16)(tvbuff_t *, gint))
1692 switch(tvb_get_guint8(tvb, offset)) {
1693 case 1: /* CreateWindow */
1694 return !tvb_bytes_exist(tvb, offset, 32) || length == 8 + numberOfBitSet(tvb, offset + 7 * 4, 4);
1696 case 2: /* ChangeWindowAttributes */
1697 case 56: /* ChangeGC */
1698 return !tvb_bytes_exist(tvb, offset, 12) || length == 3 + numberOfBitSet(tvb, offset + 8, 4);
1700 case 3: /* GetWindowAttributes */
1701 case 4: /* DestroyWindow */
1702 case 5: /* DestroySubwindows */
1703 case 6: /* ChangeSaveSet */
1704 case 8: /* MapWindow */
1705 case 9: /* MapSubWindow */
1706 case 10: /* UnmapWindow */
1707 case 11: /* UnmapSubwindows */
1708 case 13: /* CirculateWindow */
1709 case 14: /* GetGeometry */
1710 case 15: /* QueryTree */
1711 case 17: /* GetAtomName */
1712 case 21: /* ListProperties */
1713 case 23: /* GetSelectionOwner */
1714 case 27: /* UngrabPointer */
1715 case 32: /* UngrabKeyboard */
1716 case 35: /* AllowEvents */
1717 case 38: /* QueryPointer */
1718 case 46: /* CloseFont */
1719 case 47: /* QueryFont */
1720 case 54: /* FreePixmap */
1721 case 60: /* FreeGC */
1722 case 79: /* FreeColormap */
1723 case 81: /* InstallColormap */
1724 case 82: /* UninstallColormap */
1725 case 83: /* ListInstalledColormaps */
1726 case 95: /* FreeCursor */
1727 case 101: /* GetKeyboardMapping */
1728 case 113: /* KillClient */
1731 case 7: /* ReparentWindow */
1732 case 22: /* SetSelectionOwner */
1733 case 30: /* ChangeActivePointerGrab */
1734 case 31: /* GrabKeyboard */
1735 case 33: /* GrabKey */
1736 case 39: /* GetMotionEvents */
1737 case 40: /* TranslateCoordinates */
1738 case 53: /* CreatePixmap */
1739 case 57: /* CopyGC */
1740 case 61: /* ClearArea */
1741 case 78: /* CreateColormap */
1742 case 84: /* AllocColor */
1743 case 87: /* AllocColorPlanes */
1746 case 12: /* ConfigureWindow */
1747 return !tvb_bytes_exist(tvb, offset, 10) || length == 3 + numberOfBitSet(tvb, offset + 8, 2);
1749 case 16: /* InternAtom */
1750 case 98: /* QueryExtension */
1751 return !tvb_bytes_exist(tvb, offset, 6) || length == 2 + rounded4(v16(tvb, offset + 4));
1753 case 18: /* ChangeProperty */
1755 int multiplier, type;
1756 if (!tvb_bytes_exist(tvb, offset, 17)) return TRUE;
1757 type = tvb_get_guint8(tvb, 16);
1758 if (type != 8 && type != 16 && type != 32) return FALSE;
1759 multiplier = type == 8 ? 1 : type == 16 ? 2 : 4;
1760 if (!tvb_bytes_exist(tvb, offset, 24)) return TRUE;
1761 return length == 6 + rounded4((v16 == tvb_get_letohs ? tvb_get_letohl : tvb_get_ntohl)(tvb, offset + 20) * multiplier);
1764 case 19: /* DeleteProperty */
1765 case 29: /* UngrabButton */
1766 case 34: /* UngrabKey */
1767 case 42: /* SetInputFocus */
1768 case 80: /* CopyColormapAndFree */
1769 case 86: /* AllocColorCells */
1770 case 97: /* QueryBestSize */
1771 case 105: /* ChangePointerControl */
1772 case 107: /* SetScreenSaver */
1775 case 20: /* GetProperty */
1776 case 24: /* ConvertSelection */
1777 case 26: /* GrabPointer */
1778 case 28: /* GrabButton */
1779 case 41: /* WarpPointer */
1782 case 25: /* SendEvent */
1783 return length == 11;
1785 case 36: /* GrabServer */
1786 case 37: /* UngrabServer */
1787 case 43: /* GetInputFocus */
1788 case 44: /* QueryKeymap */
1789 case 52: /* GetFontPath */
1790 case 99: /* ListExtensions */
1791 case 103: /* GetKeyboardControl */
1792 case 104: /* Bell */
1793 case 106: /* GetPointerControl */
1794 case 108: /* GetScreenSaver */
1795 case 110: /* ListHosts */
1796 case 111: /* SetAccessControl */
1797 case 112: /* SetCloseDownMode */
1798 case 115: /* ForceScreenSaver */
1799 case 117: /* GetPointerMapping */
1800 case 119: /* GetModifierMapping */
1803 case 45: /* OpenFont */
1804 case 85: /* AllocNamedColor */
1805 case 92: /* LookupColor */
1806 return !tvb_bytes_exist(tvb, offset, 10) || length == 3 + rounded4(v16(tvb, offset + 8));
1808 case 48: /* QueryTextExtents */
1811 case 49: /* ListFonts */
1812 case 50: /* ListFontsWithInfo */
1813 case 109: /* ChangeHosts */
1814 return !tvb_bytes_exist(tvb, offset, 8) || length == 2 + rounded4(v16(tvb, offset + 6));
1816 case 51: /* SetFontPath */
1817 if (length < 2) return FALSE;
1818 if (!tvb_bytes_exist(tvb, offset, 8)) return TRUE;
1819 return listOfStringLengthConsistent(tvb, offset + 8, (length - 2) * 4, v16(tvb, offset + 4));
1821 case 55: /* CreateGC */
1822 return !tvb_bytes_exist(tvb, offset, 16) || length == 4 + numberOfBitSet(tvb, offset + 12, 4);
1824 case 58: /* SetDashes */
1825 return !tvb_bytes_exist(tvb, offset, 12) || length == 3 + rounded4(v16(tvb, offset + 10));
1827 case 59: /* SetClipRectangles */
1828 case 66: /* PolySegment */
1829 case 67: /* PolyRectangle */
1830 case 70: /* PolyFillRectangle */
1831 return length >= 3 && (length - 3) % 2 == 0;
1833 case 62: /* CopyArea */
1836 case 63: /* CopyPlane */
1837 case 93: /* CreateCursor */
1838 case 94: /* CreateGlyphCursor */
1841 case 64: /* PolyPoint */
1842 case 65: /* PolyLine */
1843 case 88: /* FreeColors */
1846 case 68: /* PolyArc */
1847 case 71: /* PolyFillArc */
1848 return length >= 3 && (length - 3) % 3 == 0;
1850 case 69: /* FillPoly */
1851 case 76: /* ImageText8 */
1854 case 72: /* PutImage */
1857 case 73: /* GetImage */
1858 case 96: /* RecolorCursor */
1861 case 74: /* PolyText8 */
1862 if (length < 4) return FALSE;
1863 return TRUE; /* We don't perform many controls on this one */
1865 case 75: /* PolyText16 */
1866 if (length < 4) return FALSE;
1867 return TRUE; /* We don't perform many controls on this one */
1869 case 77: /* ImageText16 */
1872 case 89: /* StoreColors */
1873 return length > 2 && (length - 2) % 3 == 0;
1875 case 90: /* StoreNamedColor */
1876 return !tvb_bytes_exist(tvb, offset, 14) || length == 4 + rounded4(v16(tvb, offset + 12));
1878 case 91: /* QueryColors */
1881 case 100: /* ChangeKeyboardMapping */
1882 return !tvb_bytes_exist(tvb, offset, 6) || length == 2 + tvb_get_guint8(tvb, 1) * tvb_get_guint8(tvb, 5);
1884 case 102: /* ChangeKeyboardControl */
1885 return !tvb_bytes_exist(tvb, offset, 6) || length == 2 + numberOfBitSet(tvb, offset + 4, 2);
1887 case 114: /* RotateProperties */
1888 return !tvb_bytes_exist(tvb, offset, 10) || length == 3 + v16(tvb, offset + 8);
1890 case 116: /* SetPointerMapping */
1891 return length == 1 + rounded4(tvb_get_guint8(tvb, 1));
1893 case 118: /* SetModifierMapping */
1894 return length == 1 + tvb_get_guint8(tvb, 1) * 2;
1896 case 127: /* NoOperation */
1904 /* -1 means doesn't match, +1 means match, 0 means don't know */
1906 static int x_endian_match(tvbuff_t *tvb, guint16 (*v16)(tvbuff_t *, gint))
1908 int offset, nextoffset;
1911 for(offset = 0; tvb_bytes_exist(tvb, offset, 4); offset = nextoffset) {
1913 length = v16(tvb, offset + 2);
1914 if (!length) return -1;
1915 nextoffset = offset + length * 4;
1916 if (!consistentWithOrder(length, tvb, offset, v16)) return -1;
1923 guess_byte_ordering(tvbuff_t *tvb, packet_info *pinfo,
1924 x11_conv_data_t *state_info)
1926 /* With X the client gives the byte ordering for the protocol,
1927 and the port on the server tells us we're speaking X. */
1929 int le, be, decision, decisionToCache;
1931 if (state_info->byte_order == BYTE_ORDER_BE)
1932 return FALSE; /* known to be big-endian */
1933 else if (state_info->byte_order == BYTE_ORDER_LE)
1934 return TRUE; /* known to be little-endian */
1936 if (pinfo->srcport == pinfo->match_port) {
1938 * This is a reply or event; we don't try to guess the
1939 * byte order on it for now.
1944 le = x_endian_match(tvb, tvb_get_letohs);
1945 be = x_endian_match(tvb, tvb_get_ntohs);
1947 /* remember that "decision" really means "little_endian". */
1949 /* We have no reason to believe it's little- rather than
1950 big-endian, so we guess the shortest length is the
1953 if (!tvb_bytes_exist(tvb, 0, 4))
1954 /* Not even a way to get the length. We're biased
1955 toward little endianness here (essentially the
1956 x86 world right now). Decoding won't go very far
1961 decision = tvb_get_letohs(tvb, 2) <= tvb_get_ntohs(tvb, 2);
1963 decision = le >= be;
1965 decisionToCache = (le < 0 && be > 0) || (le > 0 && be < 0);
1966 if (decisionToCache) {
1968 * Remember the decision.
1970 state_info->byte_order = decision ? BYTE_ORDER_LE : BYTE_ORDER_BE;
1974 fprintf(stderr, "packet %d\tle %d\tbe %d\tlittle_endian %d\tcache %d\n",
1975 pinfo->fd -> num, le, be, decision, decisionToCache);
1980 /************************************************************************
1982 *** D E C O D I N G O N E P A C K E T ***
1984 ************************************************************************/
1987 * Decode an initial connection request.
1989 static void dissect_x11_initial_conn(tvbuff_t *tvb, packet_info *pinfo,
1990 proto_tree *tree, x11_conv_data_t *state_info, gboolean little_endian)
1993 int *offsetp = &offset;
1996 guint16 auth_proto_name_length, auth_proto_data_length;
1999 ti = proto_tree_add_item(tree, proto_x11, tvb, 0, -1, FALSE);
2000 t = proto_item_add_subtree(ti, ett_x11);
2004 CARD16(protocol_major_version);
2005 CARD16(protocol_minor_version);
2006 auth_proto_name_length = CARD16(authorization_protocol_name_length);
2007 auth_proto_data_length = CARD16(authorization_protocol_data_length);
2009 if (auth_proto_name_length != 0) {
2010 STRING8(authorization_protocol_name, auth_proto_name_length);
2011 offset = ROUND_LENGTH(offset);
2013 if (auth_proto_data_length != 0) {
2014 STRING8(authorization_protocol_data, auth_proto_data_length);
2015 offset = ROUND_LENGTH(offset);
2017 left = tvb_length_remaining(tvb, offset);
2019 proto_tree_add_item(t, hf_x11_undecoded, tvb, offset, left, little_endian);
2022 * This is the initial connection request...
2024 state_info->iconn_frame = pinfo->fd->num;
2027 * ...and we're expecting a reply to it.
2029 state_info->opcode = INITIAL_CONN;
2032 static void dissect_x11_request(tvbuff_t *tvb, packet_info *pinfo,
2033 proto_tree *tree, const char *sep, x11_conv_data_t *state_info,
2034 gboolean little_endian)
2037 int *offsetp = &offset;
2047 length = VALUE16(tvb, 2) * 4;
2050 /* Bogus message length? */
2054 next_offset = offset + length;
2056 ti = proto_tree_add_item(tree, proto_x11, tvb, 0, -1, FALSE);
2057 t = proto_item_add_subtree(ti, ett_x11);
2061 if (check_col(pinfo->cinfo, COL_INFO))
2062 col_append_fstr(pinfo->cinfo, COL_INFO, "%s %s", sep,
2063 val_to_str(opcode, opcode_vals, "Unknown (%u)"));
2066 * Does this request expect a reply?
2070 case 3: /* GetWindowAttributes */
2071 case 14: /* GetGeometry */
2072 case 15: /* QueryTree */
2073 case 16: /* InternAtom */
2074 case 17: /* GetAtomName */
2075 case 20: /* GetProperty */
2076 case 21: /* ListProperties */
2077 case 23: /* GetSelectionOwner */
2078 case 26: /* GrabPointer */
2079 case 31: /* GrabKeyboard */
2080 case 38: /* QueryPointer */
2081 case 39: /* GetMotionEvents */
2082 case 40: /* TranslateCoordinates */
2083 case 44: /* QueryKeymap */
2084 case 47: /* QueryFont */
2085 case 48: /* QueryTextExtents */
2086 case 49: /* ListFonts */
2087 case 73: /* GetImage */
2088 case 83: /* ListInstalledColormaps */
2089 case 84: /* AllocColor */
2090 case 91: /* QueryColors */
2091 case 92: /* LookupColor */
2092 case 97: /* QueryBestSize */
2093 case 98: /* QueryExtension */
2094 case 99: /* ListExtensions */
2095 case 101: /* GetKeyboardMapping */
2096 case 103: /* GetKeyboardControl */
2097 case 106: /* GetPointerControl */
2098 case 108: /* GetScreenSaver */
2099 case 110: /* ListHosts */
2100 case 116: /* SetPointerMapping */
2101 case 117: /* GetPointerMapping */
2102 case 118: /* SetModifierMapping */
2103 case 119: /* GetModifierMapping */
2105 * Those requests expect a reply.
2107 state_info->opcode = opcode;
2112 * No reply is expected from any other request.
2114 state_info->opcode = NOTHING_EXPECTED;
2122 case 1: /* CreateWindow */
2131 CARD16(border_width);
2132 ENUM16(window_class);
2134 windowAttributes(tvb, offsetp, t, little_endian);
2137 case 2: /* ChangeWindowAttributes */
2141 windowAttributes(tvb, offsetp, t, little_endian);
2144 case 3: /* GetWindowAttributes */
2145 case 4: /* DestroyWindow */
2146 case 5: /* DestroySubwindows */
2152 case 6: /* ChangeSaveSet */
2153 ENUM8(save_set_mode);
2158 case 7: /* ReparentWindow */
2167 case 8: /* MapWindow */
2168 case 9: /* MapSubWindow */
2169 case 10: /* UnmapWindow */
2170 case 11: /* UnmapSubwindows */
2176 case 12: /* ConfigureWindow */
2180 BITMASK16(configure_window);
2182 BITFIELD(INT16, configure_window_mask, x);
2183 BITFIELD(INT16, configure_window_mask, y);
2184 BITFIELD(CARD16, configure_window_mask, width);
2185 BITFIELD(CARD16, configure_window_mask, height);
2186 BITFIELD(CARD16, configure_window_mask, border_width);
2187 BITFIELD(WINDOW, configure_window_mask, sibling);
2188 BITFIELD(ENUM8, configure_window_mask, stack_mode);
2193 case 13: /* CirculateWindow */
2199 case 14: /* GetGeometry */
2200 case 15: /* QueryTree */
2206 case 16: /* InternAtom */
2207 BOOL(only_if_exists);
2209 v16 = FIELD16(name_length);
2215 case 17: /* GetAtomName */
2221 case 18: /* ChangeProperty */
2229 v32 = CARD32(data_length);
2230 LISTofBYTE(data, v32);
2234 case 19: /* DeleteProperty */
2241 case 20: /* GetProperty */
2246 ATOM(get_property_type);
2247 CARD32(long_offset);
2248 CARD32(long_length);
2251 case 21: /* ListProperties */
2257 case 22: /* SetSelectionOwner */
2265 case 23: /* GetSelectionOwner */
2271 case 24: /* ConvertSelection */
2281 case 26: /* GrabPointer */
2284 WINDOW(grab_window);
2285 SETofPOINTEREVENT(pointer_event_mask);
2286 ENUM8(pointer_mode);
2287 ENUM8(keyboard_mode);
2293 case 27: /* UngrabPointer */
2299 case 28: /* GrabButton */
2302 WINDOW(grab_window);
2303 SETofPOINTEREVENT(event_mask);
2304 ENUM8(pointer_mode);
2305 ENUM8(keyboard_mode);
2310 SETofKEYMASK(modifiers);
2313 case 29: /* UngrabButton */
2316 WINDOW(grab_window);
2317 SETofKEYMASK(modifiers);
2321 case 30: /* ChangeActivePointerGrab */
2326 SETofPOINTEREVENT(event_mask);
2330 case 31: /* GrabKeyboard */
2333 WINDOW(grab_window);
2335 ENUM8(pointer_mode);
2336 ENUM8(keyboard_mode);
2340 case 32: /* UngrabKeyboard */
2346 case 33: /* GrabKey */
2349 WINDOW(grab_window);
2350 SETofKEYMASK(modifiers);
2352 ENUM8(pointer_mode);
2353 ENUM8(keyboard_mode);
2357 case 34: /* UngrabKey */
2360 WINDOW(grab_window);
2361 SETofKEYMASK(modifiers);
2365 case 35: /* AllowEvents */
2366 ENUM8(allow_events_mode);
2371 case 36: /* GrabServer */
2376 case 37: /* UngrabServer */
2381 case 38: /* QueryPointer */
2387 case 39: /* GetMotionEvents */
2395 case 40: /* TranslateCoordinates */
2404 case 41: /* WarpPointer */
2407 WINDOW(warp_pointer_src_window);
2408 WINDOW(warp_pointer_dst_window);
2417 case 42: /* SetInputFocus */
2424 case 43: /* GetInputFocus */
2429 case 44: /* QueryKeymap */
2434 case 45: /* OpenFont */
2438 v16 = FIELD16(name_length);
2444 case 46: /* CloseFont */
2450 case 47: /* QueryFont */
2456 case 48: /* QueryTextExtents */
2457 v8 = BOOL(odd_length);
2460 STRING16(string16, (next_offset - offset - (v8 ? 2 : 0)) / 2);
2464 case 49: /* ListFonts */
2468 v16 = FIELD16(pattern_length);
2469 STRING8(pattern, v16);
2473 case 50: /* ListFontsWithInfo */
2477 v16 = FIELD16(pattern_length);
2478 STRING8(pattern, v16);
2482 case 51: /* SetFontPath */
2485 v16 = CARD16(str_number_in_path);
2487 LISTofSTRING8(path, v16);
2491 case 52: /* GetFontPath */
2496 case 53: /* CreatePixmap */
2505 case 54: /* FreePixmap */
2511 case 55: /* CreateGC */
2516 gcAttributes(tvb, offsetp, t, little_endian);
2519 case 56: /* ChangeGC */
2523 gcAttributes(tvb, offsetp, t, little_endian);
2526 case 57: /* CopyGC */
2531 gcMask(tvb, offsetp, t, little_endian);
2534 case 58: /* SetDashes */
2538 CARD16(dash_offset);
2539 v16 = FIELD16(dashes_length);
2540 LISTofCARD8(dashes, v16);
2544 case 59: /* SetClipRectangles */
2548 INT16(clip_x_origin);
2549 INT16(clip_y_origin);
2550 LISTofRECTANGLE(rectangles);
2553 case 60: /* FreeGC */
2559 case 61: /* ClearArea */
2569 case 62: /* CopyArea */
2572 DRAWABLE(src_drawable);
2573 DRAWABLE(dst_drawable);
2583 case 63: /* CopyPlane */
2586 DRAWABLE(src_drawable);
2587 DRAWABLE(dst_drawable);
2598 case 64: /* PolyPoint */
2599 ENUM8(coordinate_mode);
2600 v16 = REQUEST_LENGTH();
2603 LISTofPOINT(points, v16 - 12);
2606 case 65: /* PolyLine */
2607 ENUM8(coordinate_mode);
2608 v16 = REQUEST_LENGTH();
2611 LISTofPOINT(points, v16 - 12);
2614 case 66: /* PolySegment */
2619 LISTofSEGMENT(segments);
2622 case 67: /* PolyRectangle */
2627 LISTofRECTANGLE(rectangles);
2630 case 68: /* PolyArc */
2638 case 69: /* FillPoly */
2640 v16 = REQUEST_LENGTH();
2644 ENUM8(coordinate_mode);
2646 LISTofPOINT(points, v16 - 16);
2649 case 70: /* PolyFillRectangle */
2654 LISTofRECTANGLE(rectangles);
2657 case 71: /* PolyFillArc */
2665 case 72: /* PutImage */
2666 ENUM8(image_format);
2667 v16 = REQUEST_LENGTH();
2677 LISTofBYTE(data, v16 - 24);
2681 case 73: /* GetImage */
2682 ENUM8(image_pixmap_format);
2692 case 74: /* PolyText8 */
2694 v16 = REQUEST_LENGTH();
2699 LISTofTEXTITEM8(items);
2703 case 75: /* PolyText16 */
2705 v16 = REQUEST_LENGTH();
2710 LISTofTEXTITEM16(items);
2714 case 76: /* ImageText8 */
2715 v8 = FIELD8(string_length);
2721 STRING8(string, v8);
2725 case 77: /* ImageText16 */
2726 v8 = FIELD8(string_length);
2732 STRING16(string16, v8);
2736 case 78: /* CreateColormap */
2744 case 79: /* FreeColormap */
2750 case 80: /* CopyColormapAndFree */
2757 case 81: /* InstallColormap */
2763 case 82: /* UninstallColormap */
2769 case 83: /* ListInstalledColormaps */
2775 case 84: /* AllocColor */
2785 case 85: /* AllocNamedColor */
2789 v16 = FIELD16(name_length);
2795 case 86: /* AllocColorCells */
2803 case 87: /* AllocColorPlanes */
2813 case 88: /* FreeColors */
2815 v16 = REQUEST_LENGTH();
2818 LISTofCARD32(pixels, v16 - 12);
2821 case 89: /* StoreColors */
2823 v16 = REQUEST_LENGTH();
2825 LISTofCOLORITEM(color_items, v16 - 8);
2828 case 90: /* StoreNamedColor */
2833 v16 = FIELD16(name_length);
2839 case 91: /* QueryColors */
2841 v16 = REQUEST_LENGTH();
2843 LISTofCARD32(pixels, v16 - 8);
2846 case 92: /* LookupColor */
2850 v16 = FIELD16(name_length);
2856 case 93: /* CreateCursor */
2860 PIXMAP(source_pixmap);
2872 case 94: /* CreateGlyphCursor */
2878 CARD16(source_char);
2888 case 95: /* FreeCursor */
2894 case 96: /* RecolorCursor */
2906 case 97: /* QueryBestSize */
2914 case 98: /* QueryExtension */
2917 v16 = FIELD16(name_length);
2923 case 99: /* ListExtensions */
2928 case 100: /* ChangeKeyboardMapping */
2929 v8 = FIELD8(keycode_count);
2931 KEYCODE(first_keycode);
2932 v8_2 = FIELD8(keysyms_per_keycode);
2934 LISTofKEYSYM(keysyms, v8, v8_2);
2937 case 101: /* GetKeyboardMapping */
2940 KEYCODE(first_keycode);
2945 case 102: /* ChangeKeyboardControl */
2948 BITMASK32(keyboard_value);
2949 BITFIELD(INT8, keyboard_value_mask, key_click_percent);
2950 BITFIELD(INT8, keyboard_value_mask, bell_percent);
2951 BITFIELD(INT16, keyboard_value_mask, bell_pitch);
2952 BITFIELD(INT16, keyboard_value_mask, bell_duration);
2953 BITFIELD(INT16, keyboard_value_mask, led);
2954 BITFIELD(ENUM8, keyboard_value_mask, led_mode);
2955 BITFIELD(KEYCODE, keyboard_value_mask, keyboard_key);
2956 BITFIELD(ENUM8, keyboard_value_mask, auto_repeat_mode);
2960 case 103: /* GetKeyboardControl */
2965 case 104: /* Bell */
2970 case 105: /* ChangePointerControl */
2973 INT16(acceleration_numerator);
2974 INT16(acceleration_denominator);
2976 BOOL(do_acceleration);
2980 case 106: /* GetPointerControl */
2985 case 107: /* SetScreenSaver */
2990 ENUM8(prefer_blanking);
2991 ENUM8(allow_exposures);
2995 case 108: /* GetScreenSaver */
3000 case 109: /* ChangeHosts */
3001 ENUM8(change_host_mode);
3005 v16 = CARD16(address_length);
3006 if (v8 == FAMILY_INTERNET && v16 == 4) {
3009 * XXX - what about IPv6? Is that a family of
3010 * FAMILY_INTERNET (0) with a length of 16?
3012 LISTofCARD8(ip_address, v16);
3014 LISTofCARD8(address, v16);
3017 case 110: /* ListHosts */
3022 case 111: /* SetAccessControl */
3027 case 112: /* SetCloseDownMode */
3028 ENUM8(close_down_mode);
3032 case 113: /* KillClient */
3038 case 114: /* RotateProperties */
3040 v16 = REQUEST_LENGTH();
3042 CARD16(property_number);
3044 LISTofATOM(properties, (v16 - 12));
3047 case 115: /* ForceScreenSaver */
3048 ENUM8(screen_saver_mode);
3052 case 116: /* SetPointerMapping */
3053 v8 = FIELD8(map_length);
3055 LISTofCARD8(map, v8);
3059 case 117: /* GetPointerMapping */
3064 case 118: /* SetModifierMapping */
3065 v8 = FIELD8(keycodes_per_modifier);
3067 LISTofKEYCODE(keycodes, v8);
3070 case 119: /* GetModifierMapping */
3075 case 127: /* NoOperation */
3080 left = tvb_length_remaining(tvb, offset);
3082 proto_tree_add_item(t, hf_x11_undecoded, tvb, offset, left, little_endian);
3085 static void dissect_x11_requests(tvbuff_t *tvb, packet_info *pinfo,
3088 volatile int offset = 0;
3089 int length_remaining;
3090 volatile gboolean little_endian;
3095 volatile gboolean is_initial_creq;
3096 guint16 auth_proto_len, auth_data_len;
3097 const char *volatile sep = NULL;
3098 conversation_t *conversation;
3099 x11_conv_data_t *volatile state_info;
3103 while (tvb_reported_length_remaining(tvb, offset) != 0) {
3104 length_remaining = tvb_length_remaining(tvb, offset);
3107 * Can we do reassembly?
3109 if (x11_desegment && pinfo->can_desegment) {
3111 * Yes - is the X11 request header split across
3112 * segment boundaries?
3114 if (length_remaining < 4) {
3116 * Yes. Tell the TCP dissector where the data
3117 * for this message starts in the data it handed
3118 * us, and how many more bytes we need, and return.
3120 pinfo->desegment_offset = offset;
3121 pinfo->desegment_len = 4 - length_remaining;
3127 * Get the state for this conversation; create the conversation
3128 * if we don't have one, and create the state if we don't have
3131 conversation = find_conversation(&pinfo->src, &pinfo->dst,
3132 pinfo->ptype, pinfo->srcport, pinfo->destport, 0);
3133 if (conversation == NULL) {
3137 conversation = conversation_new(&pinfo->src,
3138 &pinfo->dst, pinfo->ptype, pinfo->srcport,
3139 pinfo->destport, 0);
3143 * Is there state attached to this conversation?
3145 state_info = conversation_get_proto_data(conversation, proto_x11);
3146 if (state_info == NULL) {
3148 * No - create a state structure and attach it.
3150 state_info = g_mem_chunk_alloc(x11_state_chunk);
3151 state_info->opcode = NOTHING_SEEN; /* nothing seen yet */
3152 state_info->iconn_frame = 0; /* don't know it yet */
3153 state_info->byte_order = BYTE_ORDER_UNKNOWN; /* don't know it yet */
3154 conversation_add_proto_data(conversation, proto_x11,
3159 * Guess the byte order if we don't already know it.
3161 little_endian = guess_byte_ordering(tvb, pinfo, state_info);
3164 * Get the opcode and length of the putative X11 request.
3166 opcode = VALUE8(tvb, 0);
3167 plen = VALUE16(tvb, offset + 2);
3171 * This can't be 0, as it includes the header length.
3172 * A different choice of byte order wouldn't have
3176 ti = proto_tree_add_item(tree, proto_x11, tvb, offset, -1, FALSE);
3177 t = proto_item_add_subtree(ti, ett_x11);
3178 proto_tree_add_text(t, tvb, offset, -1, "Bogus request length (0)");
3182 if (state_info->iconn_frame == pinfo->fd->num ||
3183 (state_info->opcode == NOTHING_SEEN &&
3184 (opcode == 'B' || opcode == 'l') &&
3185 (plen == 11 || plen == 2816))) {
3189 * we saw this on the first pass and this is
3193 * we haven't already seen any requests, the first
3194 * byte of the message is 'B' or 'l', and the 16-bit
3195 * integer 2 bytes into the data stream is either 11
3196 * or a byte-swapped 11.
3198 * This means it's probably an initial connection
3199 * request, not a message.
3201 * 'B' is decimal 66, which is the opcode for a
3202 * PolySegment request; unfortunately, 11 is a valid
3203 * length for a PolySegment request request, so we
3204 * might mis-identify that request. (Are there any
3205 * other checks we can do?)
3207 * 'l' is decimal 108, which is the opcode for a
3208 * GetScreenSaver request; the only valid length
3209 * for that request is 1.
3211 is_initial_creq = TRUE;
3214 * We now know the byte order. Override the guess.
3216 if (state_info->byte_order == BYTE_ORDER_UNKNOWN) {
3217 if (opcode == 'B') {
3221 state_info->byte_order = BYTE_ORDER_BE;
3222 little_endian = FALSE;
3227 state_info->byte_order = BYTE_ORDER_LE;
3228 little_endian = TRUE;
3233 * Can we do reassembly?
3235 if (x11_desegment && pinfo->can_desegment) {
3237 * Yes - is the fixed-length portion of the
3238 * initial connection header split across
3239 * segment boundaries?
3241 if (length_remaining < 10) {
3243 * Yes. Tell the TCP dissector where the
3244 * data for this message starts in the data
3245 * it handed us, and how many more bytes we
3248 pinfo->desegment_offset = offset;
3249 pinfo->desegment_len = 10 - length_remaining;
3255 * Get the lengths of the authorization protocol and
3256 * the authorization data.
3258 auth_proto_len = VALUE16(tvb, offset + 6);
3259 auth_data_len = VALUE16(tvb, offset + 8);
3260 plen = 12 + ROUND_LENGTH(auth_proto_len) +
3261 ROUND_LENGTH(auth_data_len);
3264 * This is probably an ordinary request.
3266 is_initial_creq = FALSE;
3269 * The length of a request is in 4-byte words.
3275 * Can we do reassembly?
3277 if (x11_desegment && pinfo->can_desegment) {
3279 * Yes - is the X11 request split across segment
3282 if (length_remaining < plen) {
3284 * Yes. Tell the TCP dissector where the data
3285 * for this message starts in the data it handed
3286 * us, and how many more bytes we need, and return.
3288 pinfo->desegment_offset = offset;
3289 pinfo->desegment_len = plen - length_remaining;
3295 * Construct a tvbuff containing the amount of the payload
3296 * we have available. Make its reported length the
3297 * amount of data in the X11 request.
3299 * XXX - if reassembly isn't enabled. the subdissector
3300 * will throw a BoundsError exception, rather than a
3301 * ReportedBoundsError exception. We really want a tvbuff
3302 * where the length is "length", the reported length is "plen",
3303 * and the "if the snapshot length were infinite" length is the
3304 * minimum of the reported length of the tvbuff handed to us
3305 * and "plen", with a new type of exception thrown if the offset
3306 * is within the reported length but beyond that third length,
3307 * with that exception getting the "Unreassembled Packet" error.
3309 length = length_remaining;
3312 next_tvb = tvb_new_subset(tvb, offset, length, plen);
3315 * Set the column appropriately.
3317 if (is_initial_creq) {
3318 if (check_col(pinfo->cinfo, COL_INFO))
3319 col_set_str(pinfo->cinfo, COL_INFO, "Initial connection request");
3323 * We haven't set the column yet; set it.
3325 if (check_col(pinfo->cinfo, COL_INFO))
3326 col_add_str(pinfo->cinfo, COL_INFO, "Requests");
3329 * Initialize the separator.
3336 * Dissect the X11 request.
3338 * Catch the ReportedBoundsError exception; if this
3339 * particular message happens to get a ReportedBoundsError
3340 * exception, that doesn't mean that we should stop
3341 * dissecting X11 requests within this frame or chunk of
3344 * If it gets a BoundsError, we can stop, as there's nothing
3345 * more to see, so we just re-throw it.
3348 if (is_initial_creq) {
3349 dissect_x11_initial_conn(next_tvb, pinfo, tree,
3350 state_info, little_endian);
3352 dissect_x11_request(next_tvb, pinfo, tree, sep,
3353 state_info, little_endian);
3356 CATCH(BoundsError) {
3359 CATCH(ReportedBoundsError) {
3360 show_reported_bounds_error(tvb, pinfo, tree);
3365 * Skip the X11 message.
3374 dissect_x11_replies(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
3376 /* Set up structures we will need to add the protocol subtree and manage it */
3378 proto_tree *x11_tree;
3380 /* This field shows up as the "Info" column in the display; you should make
3381 it, if possible, summarize what's in the packet, so that a user looking
3382 at the list of packets can tell what type of packet it is. */
3383 if (check_col(pinfo->cinfo, COL_INFO))
3384 col_set_str(pinfo->cinfo, COL_INFO, "Replies/events");
3386 /* In the interest of speed, if "tree" is NULL, don't do any work not
3387 necessary to generate protocol tree items. */
3389 ti = proto_tree_add_item(tree, proto_x11, tvb, 0, -1, FALSE);
3390 x11_tree = proto_item_add_subtree(ti, ett_x11);
3393 * XXX - dissect these in a loop, like the requests.
3395 call_dissector(data_handle,tvb, pinfo, x11_tree);
3398 /************************************************************************
3400 *** I N I T I A L I Z A T I O N A N D M A I N ***
3402 ************************************************************************/
3405 dissect_x11(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
3407 if (check_col(pinfo->cinfo, COL_PROTOCOL))
3408 col_set_str(pinfo->cinfo, COL_PROTOCOL, "X11");
3410 if (pinfo->match_port == pinfo->destport)
3411 dissect_x11_requests(tvb, pinfo, tree);
3413 dissect_x11_replies(tvb, pinfo, tree);
3416 /* Register the protocol with Ethereal */
3417 void proto_register_x11(void)
3420 /* Setup list of header fields */
3421 static hf_register_info hf[] = {
3423 { &hf_x11_FIELDABBREV,
3424 { "FIELDNAME", "x11.FIELDABBREV",
3425 FIELDTYPE, FIELDBASE, FIELDCONVERT, BITMASK,
3426 "FIELDDESCR", HFILL }
3429 #include "x11-register-info.h"
3432 /* Setup protocol subtree array */
3433 static gint *ett[] = {
3435 &ett_x11_color_flags,
3436 &ett_x11_list_of_arc,
3438 &ett_x11_list_of_atom,
3439 &ett_x11_list_of_card32,
3440 &ett_x11_list_of_color_item,
3441 &ett_x11_color_item,
3442 &ett_x11_list_of_keycode,
3443 &ett_x11_list_of_keysyms,
3445 &ett_x11_list_of_point,
3447 &ett_x11_list_of_rectangle,
3449 &ett_x11_list_of_segment,
3451 &ett_x11_list_of_string8,
3452 &ett_x11_list_of_text_item,
3454 &ett_x11_gc_value_mask,
3455 &ett_x11_event_mask,
3456 &ett_x11_do_not_propagate_mask,
3457 &ett_x11_set_of_key_mask,
3458 &ett_x11_pointer_event_mask,
3459 &ett_x11_window_value_mask,
3460 &ett_x11_configure_window_mask,
3461 &ett_x11_keyboard_value_mask,
3463 module_t *x11_module;
3465 /* Register the protocol name and description */
3466 proto_x11 = proto_register_protocol("X11", "X11", "x11");
3468 /* Required function calls to register the header fields and subtrees used */
3469 proto_register_field_array(proto_x11, hf, array_length(hf));
3470 proto_register_subtree_array(ett, array_length(ett));
3472 register_init_routine(x11_init_protocol);
3474 x11_module = prefs_register_protocol(proto_x11, NULL);
3475 prefs_register_bool_preference(x11_module, "desegment",
3476 "Desegment all X11 messages spanning multiple TCP segments",
3477 "Whether the X11 dissector should desegment all messages spanning multiple TCP segments",
3482 proto_reg_handoff_x11(void)
3484 dissector_handle_t x11_handle;
3486 x11_handle = create_dissector_handle(dissect_x11, proto_x11);
3487 dissector_add("tcp.port", TCP_PORT_X11, x11_handle);
3488 dissector_add("tcp.port", TCP_PORT_X11_2, x11_handle);
3489 dissector_add("tcp.port", TCP_PORT_X11_3, x11_handle);
3490 data_handle = find_dissector("data");