2 * Routines for X11 dissection
3 * Copyright 2000, Christophe Tronche <ch.tronche@computer.org>
5 * $Id: packet-x11.c,v 1.43 2002/04/23 06:06:03 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 *** F I E L D D E C O D I N G M A C R O S ***
631 ************************************************************************/
633 #define VALUE8(tvb, offset) (tvb_get_guint8(tvb, offset))
634 #define VALUE16(tvb, offset) (little_endian ? tvb_get_letohs(tvb, offset) : tvb_get_ntohs(tvb, offset))
635 #define VALUE32(tvb, offset) (little_endian ? tvb_get_letohl(tvb, offset) : tvb_get_ntohl(tvb, offset))
637 #define FIELD8(name) (field8(tvb, offsetp, t, hf_x11_##name, little_endian))
638 #define FIELD16(name) (field16(tvb, offsetp, t, hf_x11_##name, little_endian))
639 #define FIELD32(name) (field32(tvb, offsetp, t, hf_x11_##name, little_endian))
641 #define BITFIELD(TYPE, position, name) {\
643 int save = *offsetp;\
644 proto_tree_add_item(bitmask_tree, hf_x11_##position##_##name, tvb, bitmask_offset, \
645 bitmask_size, little_endian); \
646 if (bitmask_value & proto_registrar_get_nth(hf_x11_##position##_##name) -> bitmask) {\
648 unused = save + 4 - *offsetp;\
650 proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, unused, little_endian);\
651 *offsetp = save + 4;\
655 #define FLAG(position, name) {\
656 proto_tree_add_boolean(bitmask_tree, hf_x11_##position##_mask##_##name, tvb, bitmask_offset, bitmask_size, bitmask_value); }
658 #define FLAG_IF_NONZERO(position, name) {\
659 if (bitmask_value & proto_registrar_get_nth(hf_x11_##position##_mask##_##name) -> bitmask)\
660 proto_tree_add_boolean(bitmask_tree, hf_x11_##position##_mask##_##name, tvb, bitmask_offset, bitmask_size, bitmask_value); }
662 #define ATOM(name) { atom(tvb, offsetp, t, hf_x11_##name, little_endian); }
663 #define BITGRAVITY(name) { gravity(tvb, offsetp, t, hf_x11_##name, "Forget"); }
664 #define BITMASK(name, size) {\
666 guint32 bitmask_value; \
667 int bitmask_offset; \
669 proto_tree *bitmask_tree; \
670 bitmask_value = ((size == 1) ? VALUE8(tvb, *offsetp) : \
671 ((size == 2) ? VALUE16(tvb, *offsetp) : \
672 VALUE32(tvb, *offsetp))); \
673 bitmask_offset = *offsetp; \
674 bitmask_size = size; \
675 ti = proto_tree_add_uint(t, hf_x11_##name##_mask, tvb, *offsetp, size, bitmask_value); \
676 bitmask_tree = proto_item_add_subtree(ti, ett_x11_##name##_mask); \
679 #define BITMASK8(name) BITMASK(name, 1);
680 #define BITMASK16(name) BITMASK(name, 2);
681 #define BITMASK32(name) BITMASK(name, 4);
682 #define BOOL(name) (add_boolean(tvb, offsetp, t, hf_x11_##name))
683 #define BUTTON(name) { FIELD8(name); }
684 #define CARD8(name) { FIELD8(name); }
685 #define CARD16(name) (FIELD16(name))
686 #define CARD32(name) (FIELD32(name))
687 #define COLOR_FLAGS(name) { colorFlags(tvb, offsetp, t); }
688 #define COLORMAP(name) { FIELD32(name); }
689 #define CURSOR(name) { FIELD32(name); }
690 #define DRAWABLE(name) { FIELD32(name); }
691 #define ENUM8(name) (FIELD8(name))
692 #define ENUM16(name) { FIELD16(name); }
693 #define FONT(name) { FIELD32(name); }
694 #define FONTABLE(name) { FIELD32(name); }
695 #define GCONTEXT(name) { FIELD32(name); }
696 #define INT8(name) { FIELD8(name); }
697 #define INT16(name) { FIELD16(name); }
698 #define KEYCODE(name) { FIELD8(name); }
699 #define LISTofARC(name) { listOfArc(tvb, offsetp, t, hf_x11_##name, (next_offset - *offsetp) / 12, little_endian); }
700 #define LISTofATOM(name, length) { listOfAtom(tvb, offsetp, t, hf_x11_##name, (length) / 4, little_endian); }
701 #define LISTofBYTE(name, length) { listOfByte(tvb, offsetp, t, hf_x11_##name, (length), little_endian); }
702 #define LISTofCARD8(name, length) { listOfByte(tvb, offsetp, t, hf_x11_##name, (length), little_endian); }
703 #define LISTofCARD32(name, length) { listOfCard32(tvb, offsetp, t, hf_x11_##name, hf_x11_##name##_item, (length) / 4, little_endian); }
704 #define LISTofCOLORITEM(name, length) { listOfColorItem(tvb, offsetp, t, hf_x11_##name, (length) / 12, little_endian); }
705 #define LISTofKEYCODE(name, length) { listOfKeycode(tvb, offsetp, t, hf_x11_##name, (length), little_endian); }
706 #define LISTofKEYSYM(name, keycode_count, keysyms_per_keycode) { \
707 listOfKeysyms(tvb, offsetp, t, hf_x11_##name, hf_x11_##name##_item, (keycode_count), (keysyms_per_keycode), little_endian); }
708 #define LISTofPOINT(name, length) { listOfPoint(tvb, offsetp, t, hf_x11_##name, (length) / 4, little_endian); }
709 #define LISTofRECTANGLE(name) { listOfRectangle(tvb, offsetp, t, hf_x11_##name, (next_offset - *offsetp) / 8, little_endian); }
710 #define LISTofSEGMENT(name) { listOfSegment(tvb, offsetp, t, hf_x11_##name, (next_offset - *offsetp) / 8, little_endian); }
711 #define LISTofSTRING8(name, length) { listOfString8(tvb, offsetp, t, hf_x11_##name, hf_x11_##name##_string, (length), little_endian); }
712 #define LISTofTEXTITEM8(name) { listOfTextItem(tvb, offsetp, t, hf_x11_##name, FALSE, next_offset, little_endian); }
713 #define LISTofTEXTITEM16(name) { listOfTextItem(tvb, offsetp, t, hf_x11_##name, TRUE, next_offset, little_endian); }
714 #define OPCODE() { opcode = FIELD8(opcode); }
715 #define PIXMAP(name) { FIELD32(name); }
716 #define REQUEST_LENGTH() (requestLength(tvb, offsetp, t, little_endian))
717 #define SETofEVENT(name) { setOfEvent(tvb, offsetp, t, little_endian); }
718 #define SETofDEVICEEVENT(name) { setOfDeviceEvent(tvb, offsetp, t, little_endian);}
719 #define SETofKEYMASK(name) { setOfKeyMask(tvb, offsetp, t, little_endian); }
720 #define SETofPOINTEREVENT(name) { setOfPointerEvent(tvb, offsetp, t, little_endian); }
721 #define STRING8(name, length) { string8(tvb, offsetp, t, hf_x11_##name, length); }
722 #define STRING16(name, length) { string16(tvb, offsetp, t, hf_x11_##name, hf_x11_##name##_bytes, length, little_endian); }
723 #define TIMESTAMP(name){ timestamp(tvb, offsetp, t, hf_x11_##name, little_endian); }
724 #define UNDECODED(x) { proto_tree_add_item(t, hf_x11_undecoded, tvb, *offsetp, x, little_endian); *offsetp += x; }
725 #define UNUSED(x) { proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, x, little_endian); *offsetp += x; }
726 #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; }
727 #define WINDOW(name) { FIELD32(name); }
728 #define WINGRAVITY(name) { gravity(tvb, offsetp, t, hf_x11_##name, "Unmap"); }
730 #define VISUALID(name) { gint32 v = VALUE32(tvb, *offsetp); \
731 proto_tree_add_uint_format(t, hf_x11_##name, tvb, *offsetp, 4, v, "Visualid: 0x%08x%s", v, \
732 v ? "" : " (CopyFromParent)"); *offsetp += 4; }
734 /************************************************************************
736 *** D E C O D I N G F I E L D S ***
738 ************************************************************************/
740 static void atom(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
741 gboolean little_endian)
743 const char *interpretation = NULL;
745 guint32 v = VALUE32(tvb, *offsetp);
746 if (v >= 1 && v < array_length(atom_predefined_interpretation))
747 interpretation = atom_predefined_interpretation[v];
749 interpretation = "Not a predefined atom";
751 header_field_info *hfi = proto_registrar_get_nth(hf);
753 interpretation = match_strval(v, cVALS(hfi -> strings));
755 if (!interpretation) interpretation = "error in Xlib client program ?";
756 proto_tree_add_uint_format(t, hf, tvb, *offsetp, 4, v, "%s: %u (%s)",
757 proto_registrar_get_nth(hf) -> name, v, interpretation);
761 static guint32 add_boolean(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf)
763 guint32 v = VALUE8(tvb, *offsetp);
764 proto_tree_add_boolean(t, hf, tvb, *offsetp, 1, v);
769 static void colorFlags(tvbuff_t *tvb, int *offsetp, proto_tree *t)
771 unsigned do_red_green_blue = VALUE8(tvb, *offsetp);
775 if (do_red_green_blue) {
778 char *bp = buffer + sprintf(buffer, "flags: ");
780 if (do_red_green_blue & 0x1) {
781 bp += sprintf(bp, "DoRed");
785 if (do_red_green_blue & 0x2) {
786 if (sep) bp += sprintf(bp, " | ");
787 bp += sprintf(bp, "DoGreen");
791 if (do_red_green_blue & 0x4) {
792 if (sep) bp += sprintf(bp, " | ");
793 bp += sprintf(bp, "DoBlue");
797 if (do_red_green_blue & 0xf8) {
798 if (sep) bp += sprintf(bp, " + ");
799 sprintf(bp, "trash");
802 ti = proto_tree_add_uint_format(t, hf_x11_coloritem_flags, tvb, *offsetp, 1, do_red_green_blue,
804 tt = proto_item_add_subtree(ti, ett_x11_color_flags);
805 if (do_red_green_blue & 0x1)
806 proto_tree_add_boolean(tt, hf_x11_coloritem_flags_do_red, tvb, *offsetp, 1,
807 do_red_green_blue & 0x1);
808 if (do_red_green_blue & 0x2)
809 proto_tree_add_boolean(tt, hf_x11_coloritem_flags_do_green, tvb, *offsetp, 1,
810 do_red_green_blue & 0x2);
811 if (do_red_green_blue & 0x4)
812 proto_tree_add_boolean(tt, hf_x11_coloritem_flags_do_blue, tvb, *offsetp, 1,
813 do_red_green_blue & 0x4);
814 if (do_red_green_blue & 0xf8)
815 proto_tree_add_boolean(tt, hf_x11_coloritem_flags_unused, tvb, *offsetp, 1,
816 do_red_green_blue & 0xf8);
818 proto_tree_add_uint_format(t, hf_x11_coloritem_flags, tvb, *offsetp, 1, do_red_green_blue,
823 static void gravity(tvbuff_t *tvb, int *offsetp, proto_tree *t,
824 int hf, const char *nullInterpretation)
826 guint8 v = VALUE8(tvb, *offsetp);
829 proto_tree_add_uint_format(t, hf, tvb, *offsetp, 1, v, "%s: 0 (%s)",
830 proto_registrar_get_nth(hf) -> name,
833 proto_tree_add_uint(t, hf, tvb, *offsetp, 1, v);
837 static void listOfArc(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
838 int length, gboolean little_endian)
840 proto_item *ti = proto_tree_add_item(t, hf, tvb, *offsetp, length * 8, little_endian);
841 proto_tree *tt = proto_item_add_subtree(ti, ett_x11_list_of_arc);
843 gint16 x = VALUE16(tvb, *offsetp);
844 gint16 y = VALUE16(tvb, *offsetp + 2);
845 guint16 width = VALUE16(tvb, *offsetp + 4);
846 guint16 height = VALUE16(tvb, *offsetp + 6);
847 gint16 angle1 = VALUE16(tvb, *offsetp + 8);
848 gint16 angle2 = VALUE16(tvb, *offsetp + 10);
850 proto_item *tti = proto_tree_add_none_format(tt, hf_x11_arc, tvb, *offsetp, 12,
851 "arc: %dx%d+%d+%d, angle %d -> %d (%f degrees -> %f degrees)",
852 width, height, x, y, angle1, angle2,
853 angle1 / 64.0, angle2 / 64.0);
854 proto_tree *ttt = proto_item_add_subtree(tti, ett_x11_arc);
855 proto_tree_add_int(ttt, hf_x11_arc_x, tvb, *offsetp, 2, x);
857 proto_tree_add_int(ttt, hf_x11_arc_y, tvb, *offsetp, 2, y);
859 proto_tree_add_uint(ttt, hf_x11_arc_width, tvb, *offsetp, 2, y);
861 proto_tree_add_uint(ttt, hf_x11_arc_height, tvb, *offsetp, 2, y);
863 proto_tree_add_int(ttt, hf_x11_arc_angle1, tvb, *offsetp, 2, y);
865 proto_tree_add_int(ttt, hf_x11_arc_angle2, tvb, *offsetp, 2, y);
870 static void listOfAtom(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
871 int length, gboolean little_endian)
873 proto_item *ti = proto_tree_add_item(t, hf, tvb, *offsetp, length * 4, little_endian);
874 proto_tree *tt = proto_item_add_subtree(ti, ett_x11_list_of_atom);
876 atom(tvb, offsetp, tt, hf_x11_properties_item, little_endian);
879 static void listOfByte(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
880 int length, gboolean little_endian)
882 if (length <= 0) length = 1;
883 proto_tree_add_item(t, hf, tvb, *offsetp, length, little_endian);
887 static void listOfCard32(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
888 int hf_item, int length, gboolean little_endian)
890 proto_item *ti = proto_tree_add_item(t, hf, tvb, *offsetp, length * 4, little_endian);
891 proto_tree *tt = proto_item_add_subtree(ti, ett_x11_list_of_card32);
893 proto_tree_add_uint(tt, hf_item, tvb, *offsetp, 4, VALUE32(tvb, *offsetp));
898 static void listOfColorItem(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
899 int length, gboolean little_endian)
901 proto_item *ti = proto_tree_add_item(t, hf, tvb, *offsetp, length * 8, little_endian);
902 proto_tree *tt = proto_item_add_subtree(ti, ett_x11_list_of_color_item);
906 unsigned do_red_green_blue;
907 guint16 red, green, blue;
912 red = VALUE16(tvb, *offsetp + 4);
913 green = VALUE16(tvb, *offsetp + 6);
914 blue = VALUE16(tvb, *offsetp + 8);
915 do_red_green_blue = VALUE8(tvb, *offsetp + 10);
917 bp = buffer + sprintf(buffer, "colorItem: ");
919 if (do_red_green_blue & 0x1) {
920 bp += sprintf(bp, "red = %d", red);
923 if (do_red_green_blue & 0x2) {
924 bp += sprintf(bp, "%sgreen = %d", sep, green);
927 if (do_red_green_blue & 0x4)
928 bp += sprintf(bp, "%sblue = %d", sep, blue);
930 tti = proto_tree_add_none_format(tt, hf_x11_coloritem, tvb, *offsetp, 12, "%s", buffer);
931 ttt = proto_item_add_subtree(tti, ett_x11_color_item);
932 proto_tree_add_item(ttt, hf_x11_coloritem_pixel, tvb, *offsetp, 4, little_endian);
934 proto_tree_add_item(ttt, hf_x11_coloritem_red, tvb, *offsetp, 2, little_endian);
936 proto_tree_add_item(ttt, hf_x11_coloritem_green, tvb, *offsetp, 2, little_endian);
938 proto_tree_add_item(ttt, hf_x11_coloritem_blue, tvb, *offsetp, 2, little_endian);
940 colorFlags(tvb, offsetp, ttt);
941 proto_tree_add_item(ttt, hf_x11_coloritem_unused, tvb, *offsetp, 1, little_endian);
946 static GTree *keysymTable = NULL;
948 static gint compareGuint32(gconstpointer a, gconstpointer b)
950 return GPOINTER_TO_INT(b) - GPOINTER_TO_INT(a);;
953 static const char *keysymString(guint32 v)
958 /* This table is so big that we built it only if necessary */
960 const value_string *p = keysym_vals_source;
961 keysymTable = g_tree_new(compareGuint32);
962 for(; p -> strptr; p++)
963 g_tree_insert(keysymTable, GINT_TO_POINTER(p -> value), p -> strptr);
965 res = g_tree_lookup(keysymTable, GINT_TO_POINTER(v));
966 return res ? res : "Unknown";
969 static const char *modifiers[] = { "Shift", "Lock", "Control", "Mod1", "Mod2", "Mod3", "Mod4", "Mod5" };
971 static void listOfKeycode(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
972 int length, gboolean little_endian)
975 proto_item *ti = proto_tree_add_item(t, hf, tvb, *offsetp, length * 8, little_endian);
976 proto_tree *tt = proto_item_add_subtree(ti, ett_x11_list_of_keycode);
983 for(i = 8, m = modifiers; i; i--, m++) {
984 u_char c = tvb_get_guint8(tvb, *offsetp);
987 bp += sprintf(bp, " %s=%d", *m, c);
990 proto_tree_add_bytes_format(tt, hf_x11_keycodes_item, tvb, *offsetp - 8, 8, tvb_get_ptr(tvb, *offsetp - 8, 8), "item: %s", buffer);
994 static void listOfKeysyms(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
995 int hf_item, int keycode_count,
996 int keysyms_per_keycode, gboolean little_endian)
998 proto_item *ti = proto_tree_add_item(t, hf, tvb, *offsetp, keycode_count * keysyms_per_keycode * 4, little_endian);
999 proto_tree *tt = proto_item_add_subtree(ti, ett_x11_list_of_keysyms);
1004 while(keycode_count--) {
1005 tti = proto_tree_add_none_format(tt, hf_item, tvb, *offsetp, keysyms_per_keycode * 4,
1007 ttt = proto_item_add_subtree(tti, ett_x11_keysym);
1008 for(i = keysyms_per_keycode; i; i--) {
1009 guint32 v = VALUE32(tvb, *offsetp);
1010 proto_item_append_text(tti, " %s", keysymString(v));
1011 proto_tree_add_uint_format(ttt, hf_x11_keysyms_item_keysym, tvb, *offsetp, 4, v,
1012 "keysym: 0x%08x (%s)", v, keysymString(v));
1018 static void listOfPoint(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
1019 int length, gboolean little_endian)
1021 proto_item *ti = proto_tree_add_item(t, hf, tvb, *offsetp, length * 4, little_endian);
1022 proto_tree *tt = proto_item_add_subtree(ti, ett_x11_list_of_point);
1028 x = VALUE16(tvb, *offsetp);
1029 y = VALUE16(tvb, *offsetp + 2);
1031 tti = proto_tree_add_none_format(tt, hf_x11_point, tvb, *offsetp, 4, "point: (%d,%d)", x, y);
1032 ttt = proto_item_add_subtree(tti, ett_x11_point);
1033 proto_tree_add_int(ttt, hf_x11_point_x, tvb, *offsetp, 2, x);
1035 proto_tree_add_int(ttt, hf_x11_point_y, tvb, *offsetp, 2, y);
1040 static void listOfRectangle(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
1041 int length, gboolean little_endian)
1043 proto_item *ti = proto_tree_add_item(t, hf, tvb, *offsetp, length * 8, little_endian);
1044 proto_tree *tt = proto_item_add_subtree(ti, ett_x11_list_of_rectangle);
1047 unsigned width, height;
1051 x = VALUE16(tvb, *offsetp);
1052 y = VALUE16(tvb, *offsetp + 2);
1053 width = VALUE16(tvb, *offsetp + 4);
1054 height = VALUE16(tvb, *offsetp + 6);
1056 tti = proto_tree_add_none_format(tt, hf_x11_rectangle, tvb, *offsetp, 8,
1057 "rectangle: %dx%d+%d+%d", width, height, x, y);
1058 ttt = proto_item_add_subtree(tti, ett_x11_rectangle);
1059 proto_tree_add_int(ttt, hf_x11_rectangle_x, tvb, *offsetp, 2, x);
1061 proto_tree_add_int(ttt, hf_x11_rectangle_y, tvb, *offsetp, 2, y);
1063 proto_tree_add_uint(ttt, hf_x11_rectangle_width, tvb, *offsetp, 2, width);
1065 proto_tree_add_uint(ttt, hf_x11_rectangle_height, tvb, *offsetp, 2, height);
1070 static void listOfSegment(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
1071 int length, gboolean little_endian)
1073 proto_item *ti = proto_tree_add_item(t, hf, tvb, *offsetp, length * 8, little_endian);
1074 proto_tree *tt = proto_item_add_subtree(ti, ett_x11_list_of_segment);
1076 gint16 x1, y1, x2, y2;
1080 x1 = VALUE16(tvb, *offsetp);
1081 y1 = VALUE16(tvb, *offsetp + 2);
1082 x2 = VALUE16(tvb, *offsetp + 4);
1083 y2 = VALUE16(tvb, *offsetp + 6);
1085 tti = proto_tree_add_none_format(tt, hf_x11_segment, tvb, *offsetp, 8,
1086 "segment: (%d,%d)-(%d,%d)", x1, y1, x2, y2);
1087 ttt = proto_item_add_subtree(tti, ett_x11_segment);
1088 proto_tree_add_item(ttt, hf_x11_segment_x1, tvb, *offsetp, 2, little_endian);
1090 proto_tree_add_item(ttt, hf_x11_segment_y1, tvb, *offsetp, 2, little_endian);
1092 proto_tree_add_item(ttt, hf_x11_segment_x2, tvb, *offsetp, 2, little_endian);
1094 proto_tree_add_item(ttt, hf_x11_segment_y2, tvb, *offsetp, 2, little_endian);
1099 /* XXX - the protocol tree code should handle non-printable characters.
1100 Note that "non-printable characters" may depend on your locale.... */
1101 static void stringCopy(char *dest, const char *source, int length)
1106 if (!isgraph(c) && c != ' ') c = '.';
1112 static void listOfString8(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
1113 int hf_item, int length, gboolean little_endian)
1116 guint allocated = 0;
1121 /* Compute total length */
1123 int scanning_offset = *offsetp; /* Scanning pointer */
1125 for(i = length; i; i--) {
1126 l = tvb_get_guint8(tvb, scanning_offset);
1127 scanning_offset += 1 + l;
1130 ti = proto_tree_add_item(t, hf, tvb, *offsetp, scanning_offset - *offsetp, little_endian);
1131 tt = proto_item_add_subtree(ti, ett_x11_list_of_string8);
1134 * In case we throw an exception, clean up whatever stuff we've
1135 * allocated (if any).
1137 CLEANUP_PUSH(g_free, s);
1140 unsigned l = VALUE8(tvb, *offsetp);
1141 if (allocated < (l + 1)) {
1142 /* g_realloc doesn't work ??? */
1144 s = g_malloc(l + 1);
1147 stringCopy(s, tvb_get_ptr(tvb, *offsetp + 1, l), l); /* Nothing better for now. We need a better string handling API. */
1148 proto_tree_add_string_format(tt, hf_item, tvb, *offsetp, l + 1, s, "\"%s\"", s);
1153 * Call the cleanup handler to free the string and pop the handler.
1155 CLEANUP_CALL_AND_POP;
1158 #define STRING16_MAX_DISPLAYED_LENGTH 150
1160 static int stringIsActuallyAn8BitString(tvbuff_t *tvb, int offset, unsigned length)
1162 if (length > STRING16_MAX_DISPLAYED_LENGTH) length = STRING16_MAX_DISPLAYED_LENGTH;
1163 for(; length > 0; offset += 2, length--) {
1164 if (tvb_get_guint8(tvb, offset))
1170 /* length is the length of the _byte_zone_ (that is, twice the length of the string) */
1172 static void string16_with_buffer_preallocated(tvbuff_t *tvb, proto_tree *t,
1173 int hf, int hf_bytes,
1174 int offset, unsigned length,
1175 char **s, int *sLength,
1176 gboolean little_endian)
1178 int truncated = FALSE;
1179 unsigned l = length / 2;
1181 if (stringIsActuallyAn8BitString(tvb, offset, l)) {
1183 int soffset = offset;
1185 if (l > STRING16_MAX_DISPLAYED_LENGTH) {
1187 l = STRING16_MAX_DISPLAYED_LENGTH;
1189 if (*sLength < (int) l + 3) {
1191 *s = g_malloc(l + 3);
1196 if (truncated) l -= 3;
1200 *dp++ = tvb_get_guint8(tvb, soffset);
1205 /* If truncated, add an ellipsis */
1206 if (truncated) { *dp++ = '.'; *dp++ = '.'; *dp++ = '.'; }
1209 proto_tree_add_string_format(t, hf, tvb, offset, length, tvb_get_ptr(tvb, offset, length), "%s: %s",
1210 proto_registrar_get_nth(hf) -> name, *s);
1212 proto_tree_add_item(t, hf_bytes, tvb, offset, length, little_endian);
1216 static void listOfTextItem(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
1217 int sizeIs16, int next_offset, gboolean little_endian)
1225 /* Compute total length */
1227 int scanning_offset = *offsetp; /* Scanning pointer */
1228 int l; /* Length of an individual item */
1229 int n = 0; /* Number of items */
1231 while(scanning_offset < next_offset) {
1232 l = tvb_get_guint8(tvb, scanning_offset);
1236 scanning_offset += l == 255 ? 4 : l + (sizeIs16 ? l : 0) + 1;
1239 ti = proto_tree_add_item(t, hf, tvb, *offsetp, scanning_offset - *offsetp, little_endian);
1240 tt = proto_item_add_subtree(ti, ett_x11_list_of_text_item);
1243 * In case we throw an exception, clean up whatever stuff we've
1244 * allocated (if any).
1246 CLEANUP_PUSH(g_free, s);
1249 unsigned l = VALUE8(tvb, *offsetp);
1250 if (l == 255) { /* Item is a font */
1251 fid = tvb_get_ntohl(tvb, *offsetp + 1);
1252 proto_tree_add_uint(tt, hf_x11_textitem_font, tvb, *offsetp, 5, fid);
1254 } else { /* Item is a string */
1257 gint8 delta = VALUE8(tvb, *offsetp + 1);
1258 if (sizeIs16) l += l;
1259 if ((unsigned) allocated < l + 1) {
1260 /* g_realloc doesn't work ??? */
1262 s = g_malloc(l + 1);
1265 stringCopy(s, tvb_get_ptr(tvb, *offsetp + 2, l), l);
1266 tti = proto_tree_add_none_format(tt, hf_x11_textitem_string, tvb, *offsetp, l + 2,
1267 "textitem (string): delta = %d, \"%s\"",
1269 ttt = proto_item_add_subtree(tti, ett_x11_text_item);
1270 proto_tree_add_item(ttt, hf_x11_textitem_string_delta, tvb, *offsetp + 1, 1, little_endian);
1272 string16_with_buffer_preallocated(tvb, ttt, hf_x11_textitem_string_string16,
1273 hf_x11_textitem_string_string16_bytes,
1278 proto_tree_add_string_format(ttt, hf_x11_textitem_string_string8, tvb,
1279 *offsetp + 2, l, s, "\"%s\"", s);
1285 * Call the cleanup handler to free the string and pop the handler.
1287 CLEANUP_CALL_AND_POP;
1290 static guint32 field8(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
1291 gboolean little_endian)
1293 guint32 v = VALUE8(tvb, *offsetp);
1294 header_field_info *hfi = proto_registrar_get_nth(hf);
1295 gchar *enumValue = NULL;
1298 enumValue = match_strval(v, cVALS(hfi -> strings));
1300 proto_tree_add_uint_format(t, hf, tvb, *offsetp, 1, v,
1301 hfi -> display == BASE_DEC ? "%s: %u (%s)" : "%s: 0x%02x (%s)",
1302 hfi -> name, v, enumValue);
1304 proto_tree_add_item(t, hf, tvb, *offsetp, 1, little_endian);
1309 static guint32 field16(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
1310 gboolean little_endian)
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,
1319 gboolean little_endian)
1321 guint32 v = VALUE32(tvb, *offsetp);
1322 header_field_info *hfi = proto_registrar_get_nth(hf);
1323 gchar *enumValue = NULL;
1324 gchar *nameAsChar = hfi -> name;
1327 enumValue = match_strval(v, cVALS(hfi -> strings));
1329 proto_tree_add_uint_format(t, hf, tvb, *offsetp, 4, v,
1330 hfi -> display == BASE_DEC ? "%s: %u (%s)" : "%s: 0x%08x (%s)",
1331 nameAsChar, v, enumValue);
1333 proto_tree_add_uint_format(t, hf, tvb, *offsetp, 4, v,
1334 hfi -> display == BASE_DEC ? "%s: %u" : "%s: 0x%08x",
1340 static void gcAttributes(tvbuff_t *tvb, int *offsetp, proto_tree *t,
1341 gboolean little_endian)
1343 BITMASK32(gc_value);
1344 BITFIELD(ENUM8, gc_value_mask, function);
1345 BITFIELD(CARD32, gc_value_mask, plane_mask);
1346 BITFIELD(CARD32, gc_value_mask, foreground);
1347 BITFIELD(CARD32, gc_value_mask, background);
1348 BITFIELD(CARD16, gc_value_mask, line_width);
1349 BITFIELD(ENUM8, gc_value_mask, line_style);
1350 BITFIELD(ENUM8, gc_value_mask, cap_style);
1351 BITFIELD(ENUM8, gc_value_mask, join_style);
1352 BITFIELD(ENUM8, gc_value_mask, fill_style);
1353 BITFIELD(ENUM8, gc_value_mask, fill_rule);
1354 BITFIELD(PIXMAP, gc_value_mask, tile);
1355 BITFIELD(PIXMAP, gc_value_mask, stipple);
1356 BITFIELD(INT16, gc_value_mask, tile_stipple_x_origin);
1357 BITFIELD(INT16, gc_value_mask, tile_stipple_y_origin);
1358 BITFIELD(FONT, gc_value_mask, font);
1359 BITFIELD(ENUM8, gc_value_mask, subwindow_mode);
1360 BITFIELD(BOOL, gc_value_mask, graphics_exposures);
1361 BITFIELD(INT16, gc_value_mask, clip_x_origin);
1362 BITFIELD(INT16, gc_value_mask, clip_y_origin);
1363 BITFIELD(PIXMAP, gc_value_mask, clip_mask);
1364 BITFIELD(CARD16, gc_value_mask, dash_offset);
1365 BITFIELD(CARD8, gc_value_mask, gc_dashes);
1366 BITFIELD(ENUM8, gc_value_mask, arc_mode);
1370 static void gcMask(tvbuff_t *tvb, int *offsetp, proto_tree *t,
1371 gboolean little_endian)
1373 BITMASK32(gc_value);
1374 FLAG(gc_value, function);
1375 FLAG(gc_value, plane_mask);
1376 FLAG(gc_value, foreground);
1377 FLAG(gc_value, background);
1378 FLAG(gc_value, line_width);
1379 FLAG(gc_value, line_style);
1380 FLAG(gc_value, cap_style);
1381 FLAG(gc_value, join_style);
1382 FLAG(gc_value, fill_style);
1383 FLAG(gc_value, fill_rule);
1384 FLAG(gc_value, tile);
1385 FLAG(gc_value, stipple);
1386 FLAG(gc_value, tile_stipple_x_origin);
1387 FLAG(gc_value, tile_stipple_y_origin);
1388 FLAG(gc_value, font);
1389 FLAG(gc_value, subwindow_mode);
1390 FLAG(gc_value, graphics_exposures);
1391 FLAG(gc_value, clip_x_origin);
1392 FLAG(gc_value, clip_y_origin);
1393 FLAG(gc_value, clip_mask);
1394 FLAG(gc_value, dash_offset);
1395 FLAG(gc_value, gc_dashes);
1396 FLAG(gc_value, arc_mode);
1400 static guint32 requestLength(tvbuff_t *tvb, int *offsetp, proto_tree *t,
1401 gboolean little_endian)
1403 guint32 res = VALUE16(tvb, *offsetp) * 4;
1404 proto_tree_add_uint(t, hf_x11_request_length, tvb, *offsetp, 2, res);
1409 static void setOfEvent(tvbuff_t *tvb, int *offsetp, proto_tree *t,
1410 gboolean little_endian)
1413 FLAG(event, KeyPress);
1414 FLAG(event, KeyRelease);
1415 FLAG(event, ButtonPress);
1416 FLAG(event, ButtonRelease);
1417 FLAG(event, EnterWindow);
1418 FLAG(event, LeaveWindow);
1419 FLAG(event, PointerMotion);
1420 FLAG(event, PointerMotionHint);
1421 FLAG(event, Button1Motion);
1422 FLAG(event, Button2Motion);
1423 FLAG(event, Button3Motion);
1424 FLAG(event, Button4Motion);
1425 FLAG(event, Button5Motion);
1426 FLAG(event, ButtonMotion);
1427 FLAG(event, KeymapState);
1428 FLAG(event, Exposure);
1429 FLAG(event, VisibilityChange);
1430 FLAG(event, StructureNotify);
1431 FLAG(event, ResizeRedirect);
1432 FLAG(event, SubstructureNotify);
1433 FLAG(event, SubstructureRedirect);
1434 FLAG(event, FocusChange);
1435 FLAG(event, PropertyChange);
1436 FLAG(event, ColormapChange);
1437 FLAG(event, OwnerGrabButton);
1438 FLAG_IF_NONZERO(event, erroneous_bits);
1442 static void setOfDeviceEvent(tvbuff_t *tvb, int *offsetp, proto_tree *t,
1443 gboolean little_endian)
1445 BITMASK32(do_not_propagate);
1446 FLAG(do_not_propagate, KeyPress);
1447 FLAG(do_not_propagate, KeyRelease);
1448 FLAG(do_not_propagate, ButtonPress);
1449 FLAG(do_not_propagate, ButtonRelease);
1450 FLAG(do_not_propagate, PointerMotion);
1451 FLAG(do_not_propagate, Button1Motion);
1452 FLAG(do_not_propagate, Button2Motion);
1453 FLAG(do_not_propagate, Button3Motion);
1454 FLAG(do_not_propagate, Button4Motion);
1455 FLAG(do_not_propagate, Button5Motion);
1456 FLAG(do_not_propagate, ButtonMotion);
1457 FLAG_IF_NONZERO(do_not_propagate, erroneous_bits);
1461 static void setOfKeyMask(tvbuff_t *tvb, int *offsetp, proto_tree *t,
1462 gboolean little_endian)
1465 guint32 bitmask_value;
1468 proto_tree *bitmask_tree;
1470 bitmask_value = VALUE16(tvb, *offsetp);
1471 bitmask_offset = *offsetp;
1473 if (bitmask_value == 0x8000)
1474 proto_tree_add_uint_format(t, hf_x11_modifiers_mask_AnyModifier, tvb, *offsetp, 2, 0x8000,
1475 "modifiers-masks: 0x8000 (AnyModifier)");
1477 ti = proto_tree_add_uint(t, hf_x11_modifiers_mask, tvb, *offsetp, 2,
1479 bitmask_tree = proto_item_add_subtree(ti, ett_x11_set_of_key_mask);
1480 FLAG(modifiers, Shift);
1481 FLAG(modifiers, Lock);
1482 FLAG(modifiers, Control);
1483 FLAG(modifiers, Mod1);
1484 FLAG(modifiers, Mod2);
1485 FLAG(modifiers, Mod3);
1486 FLAG(modifiers, Mod4);
1487 FLAG(modifiers, Mod5);
1488 FLAG_IF_NONZERO(modifiers, erroneous_bits);
1493 static void setOfPointerEvent(tvbuff_t *tvb, int *offsetp, proto_tree *t,
1494 gboolean little_endian)
1496 BITMASK16(pointer_event);
1497 FLAG(pointer_event, ButtonPress);
1498 FLAG(pointer_event, ButtonRelease);
1499 FLAG(pointer_event, EnterWindow);
1500 FLAG(pointer_event, LeaveWindow);
1501 FLAG(pointer_event, PointerMotion);
1502 FLAG(pointer_event, PointerMotionHint);
1503 FLAG(pointer_event, Button1Motion);
1504 FLAG(pointer_event, Button2Motion);
1505 FLAG(pointer_event, Button3Motion);
1506 FLAG(pointer_event, Button4Motion);
1507 FLAG(pointer_event, Button5Motion);
1508 FLAG(pointer_event, ButtonMotion);
1509 FLAG(pointer_event, KeymapState);
1510 FLAG_IF_NONZERO(pointer_event, erroneous_bits);
1514 static void string8(tvbuff_t *tvb, int *offsetp, proto_tree *t,
1515 int hf, unsigned length)
1517 char *s = g_malloc(length + 1);
1520 * In case we throw an exception, clean up whatever stuff we've
1521 * allocated (if any).
1523 CLEANUP_PUSH(g_free, s);
1525 stringCopy(s, tvb_get_ptr(tvb, *offsetp, length), length);
1526 proto_tree_add_string(t, hf, tvb, *offsetp, length, s);
1529 * Call the cleanup handler to free the string and pop the handler.
1531 CLEANUP_CALL_AND_POP;
1536 /* The length is the length of the _byte_zone_ (twice the length of the string) */
1538 static void string16(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
1539 int hf_bytes, unsigned length, gboolean little_endian)
1545 * In case we throw an exception, clean up whatever stuff we've
1546 * allocated (if any).
1548 CLEANUP_PUSH(g_free, s);
1551 string16_with_buffer_preallocated(tvb, t, hf, hf_bytes, *offsetp, length,
1552 &s, &l, little_endian);
1555 * Call the cleanup handler to free the string and pop the handler.
1557 CLEANUP_CALL_AND_POP;
1562 static void timestamp(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
1563 gboolean little_endian)
1565 guint32 v = VALUE32(tvb, *offsetp);
1568 proto_tree_add_uint_format(t, hf, tvb, *offsetp, 4, 0, "%s: 0 (CurrentTime)",
1569 proto_registrar_get_nth(hf) -> name);
1571 proto_tree_add_uint(t, hf, tvb, *offsetp, 4, v);
1575 static void windowAttributes(tvbuff_t *tvb, int *offsetp, proto_tree *t,
1576 gboolean little_endian)
1578 BITMASK32(window_value);
1579 BITFIELD(PIXMAP, window_value_mask, background_pixmap);
1580 BITFIELD(CARD32, window_value_mask, background_pixel);
1581 BITFIELD(PIXMAP, window_value_mask, border_pixmap);
1582 BITFIELD(CARD32, window_value_mask, border_pixel);
1583 BITFIELD(BITGRAVITY, window_value_mask, bit_gravity);
1584 BITFIELD(WINGRAVITY, window_value_mask, win_gravity);
1585 BITFIELD(ENUM8, window_value_mask, backing_store);
1586 BITFIELD(CARD32, window_value_mask, backing_planes);
1587 BITFIELD(CARD32, window_value_mask, backing_pixel);
1588 BITFIELD(BOOL, window_value_mask, override_redirect);
1589 BITFIELD(BOOL, window_value_mask, save_under);
1590 BITFIELD(SETofEVENT, window_value_mask, event_mask);
1591 BITFIELD(SETofDEVICEEVENT, window_value_mask, do_not_propagate_mask);
1592 BITFIELD(COLORMAP, window_value_mask, colormap);
1593 BITFIELD(CURSOR, window_value_mask, cursor);
1598 * Data structure associated with a conversation; keeps track of the
1599 * request for which we're expecting a reply, the frame number of
1600 * the initial connection request, and the byte order of the connection.
1602 * An opcode of -3 means we haven't yet seen any requests yet.
1603 * An opcode of -2 means we're not expecting a reply.
1604 * An opcode of -1 means means we're waiting for a reply to the initial
1605 * connection request.
1606 * Other values are the opcode of the request for which we're expecting
1609 * XXX - assumes only one outstanding request is awaiting a reply,
1610 * which should always be the case.
1612 #define NOTHING_SEEN -3
1613 #define NOTHING_EXPECTED -2
1614 #define INITIAL_CONN -1
1616 #define BYTE_ORDER_BE 0
1617 #define BYTE_ORDER_LE 1
1618 #define BYTE_ORDER_UNKNOWN -1
1621 int opcode; /* opcode for which we're awaiting a reply */
1622 guint32 iconn_frame; /* frame # of initial connection request */
1623 int byte_order; /* byte order of connection */
1626 static GMemChunk *x11_state_chunk = NULL;
1628 static void x11_init_protocol(void)
1630 if (x11_state_chunk != NULL)
1631 g_mem_chunk_destroy(x11_state_chunk);
1633 x11_state_chunk = g_mem_chunk_new("x11_state_chunk",
1634 sizeof (x11_conv_data_t),
1635 128 * sizeof (x11_conv_data_t),
1639 /************************************************************************
1641 *** G U E S S I N G T H E B Y T E O R D E R I N G ***
1643 ************************************************************************/
1645 /* If we can't guess, we return TRUE (that is little_endian), cause
1646 I'm developing on a Linux box :-). The (non-)guess isn't cached
1647 however, so we may have more luck next time. I'm quite conservative
1648 in my assertions, cause once it's cached, it's stay in cache, and
1649 we may be fooled up by a packet starting with the end of a request
1650 started in a previous packet...
1653 static int numberOfBitSetTable[] = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4 };
1655 static int numberOfBitSet(tvbuff_t *tvb, int offset, int maskLength)
1658 while(maskLength--) {
1659 int c = tvb_get_guint8(tvb, offset);
1661 res += numberOfBitSetTable[c & 0xf] + numberOfBitSetTable[c >> 4];
1666 static int listOfStringLengthConsistent(tvbuff_t *tvb, int offset, int length, int listLength)
1668 if (listLength > length) return FALSE;
1669 while(listLength--) {
1671 if (!tvb_bytes_exist(tvb, offset, 1)) return TRUE;
1672 l = tvb_get_guint8(tvb, offset);
1675 if (l > length) return FALSE;
1676 if (!tvb_bytes_exist(tvb, offset, l)) return TRUE;
1680 if (length > 3) return FALSE;
1684 static int rounded4(int n)
1686 int remainder = n % 4;
1688 if (remainder) res++;
1692 /* We assume the order to be consistent, until proven wrong. */
1694 static gboolean consistentWithOrder(int length, tvbuff_t *tvb, int offset, guint16 (*v16)(tvbuff_t *, gint))
1696 switch(tvb_get_guint8(tvb, offset)) {
1697 case 1: /* CreateWindow */
1698 return !tvb_bytes_exist(tvb, offset, 32) || length == 8 + numberOfBitSet(tvb, offset + 7 * 4, 4);
1700 case 2: /* ChangeWindowAttributes */
1701 case 56: /* ChangeGC */
1702 return !tvb_bytes_exist(tvb, offset, 12) || length == 3 + numberOfBitSet(tvb, offset + 8, 4);
1704 case 3: /* GetWindowAttributes */
1705 case 4: /* DestroyWindow */
1706 case 5: /* DestroySubwindows */
1707 case 6: /* ChangeSaveSet */
1708 case 8: /* MapWindow */
1709 case 9: /* MapSubWindow */
1710 case 10: /* UnmapWindow */
1711 case 11: /* UnmapSubwindows */
1712 case 13: /* CirculateWindow */
1713 case 14: /* GetGeometry */
1714 case 15: /* QueryTree */
1715 case 17: /* GetAtomName */
1716 case 21: /* ListProperties */
1717 case 23: /* GetSelectionOwner */
1718 case 27: /* UngrabPointer */
1719 case 32: /* UngrabKeyboard */
1720 case 35: /* AllowEvents */
1721 case 38: /* QueryPointer */
1722 case 46: /* CloseFont */
1723 case 47: /* QueryFont */
1724 case 54: /* FreePixmap */
1725 case 60: /* FreeGC */
1726 case 79: /* FreeColormap */
1727 case 81: /* InstallColormap */
1728 case 82: /* UninstallColormap */
1729 case 83: /* ListInstalledColormaps */
1730 case 95: /* FreeCursor */
1731 case 101: /* GetKeyboardMapping */
1732 case 113: /* KillClient */
1735 case 7: /* ReparentWindow */
1736 case 22: /* SetSelectionOwner */
1737 case 30: /* ChangeActivePointerGrab */
1738 case 31: /* GrabKeyboard */
1739 case 33: /* GrabKey */
1740 case 39: /* GetMotionEvents */
1741 case 40: /* TranslateCoordinates */
1742 case 53: /* CreatePixmap */
1743 case 57: /* CopyGC */
1744 case 61: /* ClearArea */
1745 case 78: /* CreateColormap */
1746 case 84: /* AllocColor */
1747 case 87: /* AllocColorPlanes */
1750 case 12: /* ConfigureWindow */
1751 return !tvb_bytes_exist(tvb, offset, 10) || length == 3 + numberOfBitSet(tvb, offset + 8, 2);
1753 case 16: /* InternAtom */
1754 case 98: /* QueryExtension */
1755 return !tvb_bytes_exist(tvb, offset, 6) || length == 2 + rounded4(v16(tvb, offset + 4));
1757 case 18: /* ChangeProperty */
1759 int multiplier, type;
1760 if (!tvb_bytes_exist(tvb, offset, 17)) return TRUE;
1761 type = tvb_get_guint8(tvb, 16);
1762 if (type != 8 && type != 16 && type != 32) return FALSE;
1763 multiplier = type == 8 ? 1 : type == 16 ? 2 : 4;
1764 if (!tvb_bytes_exist(tvb, offset, 24)) return TRUE;
1765 return length == 6 + rounded4((v16 == tvb_get_letohs ? tvb_get_letohl : tvb_get_ntohl)(tvb, offset + 20) * multiplier);
1768 case 19: /* DeleteProperty */
1769 case 29: /* UngrabButton */
1770 case 34: /* UngrabKey */
1771 case 42: /* SetInputFocus */
1772 case 80: /* CopyColormapAndFree */
1773 case 86: /* AllocColorCells */
1774 case 97: /* QueryBestSize */
1775 case 105: /* ChangePointerControl */
1776 case 107: /* SetScreenSaver */
1779 case 20: /* GetProperty */
1780 case 24: /* ConvertSelection */
1781 case 26: /* GrabPointer */
1782 case 28: /* GrabButton */
1783 case 41: /* WarpPointer */
1786 case 25: /* SendEvent */
1787 return length == 11;
1789 case 36: /* GrabServer */
1790 case 37: /* UngrabServer */
1791 case 43: /* GetInputFocus */
1792 case 44: /* QueryKeymap */
1793 case 52: /* GetFontPath */
1794 case 99: /* ListExtensions */
1795 case 103: /* GetKeyboardControl */
1796 case 104: /* Bell */
1797 case 106: /* GetPointerControl */
1798 case 108: /* GetScreenSaver */
1799 case 110: /* ListHosts */
1800 case 111: /* SetAccessControl */
1801 case 112: /* SetCloseDownMode */
1802 case 115: /* ForceScreenSaver */
1803 case 117: /* GetPointerMapping */
1804 case 119: /* GetModifierMapping */
1807 case 45: /* OpenFont */
1808 case 85: /* AllocNamedColor */
1809 case 92: /* LookupColor */
1810 return !tvb_bytes_exist(tvb, offset, 10) || length == 3 + rounded4(v16(tvb, offset + 8));
1812 case 48: /* QueryTextExtents */
1815 case 49: /* ListFonts */
1816 case 50: /* ListFontsWithInfo */
1817 case 109: /* ChangeHosts */
1818 return !tvb_bytes_exist(tvb, offset, 8) || length == 2 + rounded4(v16(tvb, offset + 6));
1820 case 51: /* SetFontPath */
1821 if (length < 2) return FALSE;
1822 if (!tvb_bytes_exist(tvb, offset, 8)) return TRUE;
1823 return listOfStringLengthConsistent(tvb, offset + 8, (length - 2) * 4, v16(tvb, offset + 4));
1825 case 55: /* CreateGC */
1826 return !tvb_bytes_exist(tvb, offset, 16) || length == 4 + numberOfBitSet(tvb, offset + 12, 4);
1828 case 58: /* SetDashes */
1829 return !tvb_bytes_exist(tvb, offset, 12) || length == 3 + rounded4(v16(tvb, offset + 10));
1831 case 59: /* SetClipRectangles */
1832 case 66: /* PolySegment */
1833 case 67: /* PolyRectangle */
1834 case 70: /* PolyFillRectangle */
1835 return length >= 3 && (length - 3) % 2 == 0;
1837 case 62: /* CopyArea */
1840 case 63: /* CopyPlane */
1841 case 93: /* CreateCursor */
1842 case 94: /* CreateGlyphCursor */
1845 case 64: /* PolyPoint */
1846 case 65: /* PolyLine */
1847 case 88: /* FreeColors */
1850 case 68: /* PolyArc */
1851 case 71: /* PolyFillArc */
1852 return length >= 3 && (length - 3) % 3 == 0;
1854 case 69: /* FillPoly */
1855 case 76: /* ImageText8 */
1858 case 72: /* PutImage */
1861 case 73: /* GetImage */
1862 case 96: /* RecolorCursor */
1865 case 74: /* PolyText8 */
1866 if (length < 4) return FALSE;
1867 return TRUE; /* We don't perform many controls on this one */
1869 case 75: /* PolyText16 */
1870 if (length < 4) return FALSE;
1871 return TRUE; /* We don't perform many controls on this one */
1873 case 77: /* ImageText16 */
1876 case 89: /* StoreColors */
1877 return length > 2 && (length - 2) % 3 == 0;
1879 case 90: /* StoreNamedColor */
1880 return !tvb_bytes_exist(tvb, offset, 14) || length == 4 + rounded4(v16(tvb, offset + 12));
1882 case 91: /* QueryColors */
1885 case 100: /* ChangeKeyboardMapping */
1886 return !tvb_bytes_exist(tvb, offset, 6) || length == 2 + tvb_get_guint8(tvb, 1) * tvb_get_guint8(tvb, 5);
1888 case 102: /* ChangeKeyboardControl */
1889 return !tvb_bytes_exist(tvb, offset, 6) || length == 2 + numberOfBitSet(tvb, offset + 4, 2);
1891 case 114: /* RotateProperties */
1892 return !tvb_bytes_exist(tvb, offset, 10) || length == 3 + v16(tvb, offset + 8);
1894 case 116: /* SetPointerMapping */
1895 return length == 1 + rounded4(tvb_get_guint8(tvb, 1));
1897 case 118: /* SetModifierMapping */
1898 return length == 1 + tvb_get_guint8(tvb, 1) * 2;
1900 case 127: /* NoOperation */
1908 /* -1 means doesn't match, +1 means match, 0 means don't know */
1910 static int x_endian_match(tvbuff_t *tvb, guint16 (*v16)(tvbuff_t *, gint))
1912 int offset, nextoffset;
1915 for(offset = 0; tvb_bytes_exist(tvb, offset, 4); offset = nextoffset) {
1917 length = v16(tvb, offset + 2);
1918 if (!length) return -1;
1919 nextoffset = offset + length * 4;
1920 if (!consistentWithOrder(length, tvb, offset, v16)) return -1;
1927 guess_byte_ordering(tvbuff_t *tvb, packet_info *pinfo,
1928 x11_conv_data_t *state_info)
1930 /* With X the client gives the byte ordering for the protocol,
1931 and the port on the server tells us we're speaking X. */
1933 int le, be, decision, decisionToCache;
1935 if (state_info->byte_order == BYTE_ORDER_BE)
1936 return FALSE; /* known to be big-endian */
1937 else if (state_info->byte_order == BYTE_ORDER_LE)
1938 return TRUE; /* known to be little-endian */
1940 if (pinfo->srcport == pinfo->match_port) {
1942 * This is a reply or event; we don't try to guess the
1943 * byte order on it for now.
1948 le = x_endian_match(tvb, tvb_get_letohs);
1949 be = x_endian_match(tvb, tvb_get_ntohs);
1951 /* remember that "decision" really means "little_endian". */
1953 /* We have no reason to believe it's little- rather than
1954 big-endian, so we guess the shortest length is the
1957 if (!tvb_bytes_exist(tvb, 0, 4))
1958 /* Not even a way to get the length. We're biased
1959 toward little endianness here (essentially the
1960 x86 world right now). Decoding won't go very far
1965 decision = tvb_get_letohs(tvb, 2) <= tvb_get_ntohs(tvb, 2);
1967 decision = le >= be;
1969 decisionToCache = (le < 0 && be > 0) || (le > 0 && be < 0);
1970 if (decisionToCache) {
1972 * Remember the decision.
1974 state_info->byte_order = decision ? BYTE_ORDER_LE : BYTE_ORDER_BE;
1978 fprintf(stderr, "packet %d\tle %d\tbe %d\tlittle_endian %d\tcache %d\n",
1979 pinfo->fd -> num, le, be, decision, decisionToCache);
1984 /************************************************************************
1986 *** D E C O D I N G O N E P A C K E T ***
1988 ************************************************************************/
1991 * Decode an initial connection request.
1993 static void dissect_x11_initial_conn(tvbuff_t *tvb, packet_info *pinfo,
1994 proto_tree *tree, x11_conv_data_t *state_info, gboolean little_endian)
1997 int *offsetp = &offset;
2000 guint16 auth_proto_name_length, auth_proto_data_length;
2003 ti = proto_tree_add_item(tree, proto_x11, tvb, 0, -1, FALSE);
2004 t = proto_item_add_subtree(ti, ett_x11);
2008 CARD16(protocol_major_version);
2009 CARD16(protocol_minor_version);
2010 auth_proto_name_length = CARD16(authorization_protocol_name_length);
2011 auth_proto_data_length = CARD16(authorization_protocol_data_length);
2013 if (auth_proto_name_length != 0) {
2014 STRING8(authorization_protocol_name, auth_proto_name_length);
2015 offset = ROUND_LENGTH(offset);
2017 if (auth_proto_data_length != 0) {
2018 STRING8(authorization_protocol_data, auth_proto_data_length);
2019 offset = ROUND_LENGTH(offset);
2021 left = tvb_length_remaining(tvb, offset);
2023 proto_tree_add_item(t, hf_x11_undecoded, tvb, offset, left, little_endian);
2026 * This is the initial connection request...
2028 state_info->iconn_frame = pinfo->fd->num;
2031 * ...and we're expecting a reply to it.
2033 state_info->opcode = INITIAL_CONN;
2036 static void dissect_x11_request(tvbuff_t *tvb, packet_info *pinfo,
2037 proto_tree *tree, const char *sep, x11_conv_data_t *state_info,
2038 gboolean little_endian)
2041 int *offsetp = &offset;
2051 length = VALUE16(tvb, 2) * 4;
2054 /* Bogus message length? */
2058 next_offset = offset + length;
2060 ti = proto_tree_add_item(tree, proto_x11, tvb, 0, -1, FALSE);
2061 t = proto_item_add_subtree(ti, ett_x11);
2065 if (check_col(pinfo->cinfo, COL_INFO))
2066 col_append_fstr(pinfo->cinfo, COL_INFO, "%s %s", sep,
2067 val_to_str(opcode, opcode_vals, "Unknown (%u)"));
2070 * Does this request expect a reply?
2074 case 3: /* GetWindowAttributes */
2075 case 14: /* GetGeometry */
2076 case 15: /* QueryTree */
2077 case 16: /* InternAtom */
2078 case 17: /* GetAtomName */
2079 case 20: /* GetProperty */
2080 case 21: /* ListProperties */
2081 case 23: /* GetSelectionOwner */
2082 case 26: /* GrabPointer */
2083 case 31: /* GrabKeyboard */
2084 case 38: /* QueryPointer */
2085 case 39: /* GetMotionEvents */
2086 case 40: /* TranslateCoordinates */
2087 case 44: /* QueryKeymap */
2088 case 47: /* QueryFont */
2089 case 48: /* QueryTextExtents */
2090 case 49: /* ListFonts */
2091 case 73: /* GetImage */
2092 case 83: /* ListInstalledColormaps */
2093 case 84: /* AllocColor */
2094 case 91: /* QueryColors */
2095 case 92: /* LookupColor */
2096 case 97: /* QueryBestSize */
2097 case 98: /* QueryExtension */
2098 case 99: /* ListExtensions */
2099 case 101: /* GetKeyboardMapping */
2100 case 103: /* GetKeyboardControl */
2101 case 106: /* GetPointerControl */
2102 case 108: /* GetScreenSaver */
2103 case 110: /* ListHosts */
2104 case 116: /* SetPointerMapping */
2105 case 117: /* GetPointerMapping */
2106 case 118: /* SetModifierMapping */
2107 case 119: /* GetModifierMapping */
2109 * Those requests expect a reply.
2111 state_info->opcode = opcode;
2116 * No reply is expected from any other request.
2118 state_info->opcode = NOTHING_EXPECTED;
2126 case 1: /* CreateWindow */
2135 CARD16(border_width);
2136 ENUM16(window_class);
2138 windowAttributes(tvb, offsetp, t, little_endian);
2141 case 2: /* ChangeWindowAttributes */
2145 windowAttributes(tvb, offsetp, t, little_endian);
2148 case 3: /* GetWindowAttributes */
2149 case 4: /* DestroyWindow */
2150 case 5: /* DestroySubwindows */
2156 case 6: /* ChangeSaveSet */
2157 ENUM8(save_set_mode);
2162 case 7: /* ReparentWindow */
2171 case 8: /* MapWindow */
2172 case 9: /* MapSubWindow */
2173 case 10: /* UnmapWindow */
2174 case 11: /* UnmapSubwindows */
2180 case 12: /* ConfigureWindow */
2184 BITMASK16(configure_window);
2186 BITFIELD(INT16, configure_window_mask, x);
2187 BITFIELD(INT16, configure_window_mask, y);
2188 BITFIELD(CARD16, configure_window_mask, width);
2189 BITFIELD(CARD16, configure_window_mask, height);
2190 BITFIELD(CARD16, configure_window_mask, border_width);
2191 BITFIELD(WINDOW, configure_window_mask, sibling);
2192 BITFIELD(ENUM8, configure_window_mask, stack_mode);
2197 case 13: /* CirculateWindow */
2203 case 14: /* GetGeometry */
2204 case 15: /* QueryTree */
2210 case 16: /* InternAtom */
2211 BOOL(only_if_exists);
2213 v16 = FIELD16(name_length);
2219 case 17: /* GetAtomName */
2225 case 18: /* ChangeProperty */
2233 v32 = CARD32(data_length);
2234 LISTofBYTE(data, v32);
2238 case 19: /* DeleteProperty */
2245 case 20: /* GetProperty */
2250 ATOM(get_property_type);
2251 CARD32(long_offset);
2252 CARD32(long_length);
2255 case 21: /* ListProperties */
2261 case 22: /* SetSelectionOwner */
2269 case 23: /* GetSelectionOwner */
2275 case 24: /* ConvertSelection */
2285 case 26: /* GrabPointer */
2288 WINDOW(grab_window);
2289 SETofPOINTEREVENT(pointer_event_mask);
2290 ENUM8(pointer_mode);
2291 ENUM8(keyboard_mode);
2297 case 27: /* UngrabPointer */
2303 case 28: /* GrabButton */
2306 WINDOW(grab_window);
2307 SETofPOINTEREVENT(event_mask);
2308 ENUM8(pointer_mode);
2309 ENUM8(keyboard_mode);
2314 SETofKEYMASK(modifiers);
2317 case 29: /* UngrabButton */
2320 WINDOW(grab_window);
2321 SETofKEYMASK(modifiers);
2325 case 30: /* ChangeActivePointerGrab */
2330 SETofPOINTEREVENT(event_mask);
2334 case 31: /* GrabKeyboard */
2337 WINDOW(grab_window);
2339 ENUM8(pointer_mode);
2340 ENUM8(keyboard_mode);
2344 case 32: /* UngrabKeyboard */
2350 case 33: /* GrabKey */
2353 WINDOW(grab_window);
2354 SETofKEYMASK(modifiers);
2356 ENUM8(pointer_mode);
2357 ENUM8(keyboard_mode);
2361 case 34: /* UngrabKey */
2364 WINDOW(grab_window);
2365 SETofKEYMASK(modifiers);
2369 case 35: /* AllowEvents */
2370 ENUM8(allow_events_mode);
2375 case 36: /* GrabServer */
2380 case 37: /* UngrabServer */
2385 case 38: /* QueryPointer */
2391 case 39: /* GetMotionEvents */
2399 case 40: /* TranslateCoordinates */
2408 case 41: /* WarpPointer */
2411 WINDOW(warp_pointer_src_window);
2412 WINDOW(warp_pointer_dst_window);
2421 case 42: /* SetInputFocus */
2428 case 43: /* GetInputFocus */
2433 case 44: /* QueryKeymap */
2438 case 45: /* OpenFont */
2442 v16 = FIELD16(name_length);
2448 case 46: /* CloseFont */
2454 case 47: /* QueryFont */
2460 case 48: /* QueryTextExtents */
2461 v8 = BOOL(odd_length);
2464 STRING16(string16, (next_offset - offset - (v8 ? 2 : 0)) / 2);
2468 case 49: /* ListFonts */
2472 v16 = FIELD16(pattern_length);
2473 STRING8(pattern, v16);
2477 case 50: /* ListFontsWithInfo */
2481 v16 = FIELD16(pattern_length);
2482 STRING8(pattern, v16);
2486 case 51: /* SetFontPath */
2489 v16 = CARD16(str_number_in_path);
2491 LISTofSTRING8(path, v16);
2495 case 52: /* GetFontPath */
2500 case 53: /* CreatePixmap */
2509 case 54: /* FreePixmap */
2515 case 55: /* CreateGC */
2520 gcAttributes(tvb, offsetp, t, little_endian);
2523 case 56: /* ChangeGC */
2527 gcAttributes(tvb, offsetp, t, little_endian);
2530 case 57: /* CopyGC */
2535 gcMask(tvb, offsetp, t, little_endian);
2538 case 58: /* SetDashes */
2542 CARD16(dash_offset);
2543 v16 = FIELD16(dashes_length);
2544 LISTofCARD8(dashes, v16);
2548 case 59: /* SetClipRectangles */
2552 INT16(clip_x_origin);
2553 INT16(clip_y_origin);
2554 LISTofRECTANGLE(rectangles);
2557 case 60: /* FreeGC */
2563 case 61: /* ClearArea */
2573 case 62: /* CopyArea */
2576 DRAWABLE(src_drawable);
2577 DRAWABLE(dst_drawable);
2587 case 63: /* CopyPlane */
2590 DRAWABLE(src_drawable);
2591 DRAWABLE(dst_drawable);
2602 case 64: /* PolyPoint */
2603 ENUM8(coordinate_mode);
2604 v16 = REQUEST_LENGTH();
2607 LISTofPOINT(points, v16 - 12);
2610 case 65: /* PolyLine */
2611 ENUM8(coordinate_mode);
2612 v16 = REQUEST_LENGTH();
2615 LISTofPOINT(points, v16 - 12);
2618 case 66: /* PolySegment */
2623 LISTofSEGMENT(segments);
2626 case 67: /* PolyRectangle */
2631 LISTofRECTANGLE(rectangles);
2634 case 68: /* PolyArc */
2642 case 69: /* FillPoly */
2644 v16 = REQUEST_LENGTH();
2648 ENUM8(coordinate_mode);
2650 LISTofPOINT(points, v16 - 16);
2653 case 70: /* PolyFillRectangle */
2658 LISTofRECTANGLE(rectangles);
2661 case 71: /* PolyFillArc */
2669 case 72: /* PutImage */
2670 ENUM8(image_format);
2671 v16 = REQUEST_LENGTH();
2681 LISTofBYTE(data, v16 - 24);
2685 case 73: /* GetImage */
2686 ENUM8(image_pixmap_format);
2696 case 74: /* PolyText8 */
2698 v16 = REQUEST_LENGTH();
2703 LISTofTEXTITEM8(items);
2707 case 75: /* PolyText16 */
2709 v16 = REQUEST_LENGTH();
2714 LISTofTEXTITEM16(items);
2718 case 76: /* ImageText8 */
2719 v8 = FIELD8(string_length);
2725 STRING8(string, v8);
2729 case 77: /* ImageText16 */
2730 v8 = FIELD8(string_length);
2736 STRING16(string16, v8);
2740 case 78: /* CreateColormap */
2748 case 79: /* FreeColormap */
2754 case 80: /* CopyColormapAndFree */
2761 case 81: /* InstallColormap */
2767 case 82: /* UninstallColormap */
2773 case 83: /* ListInstalledColormaps */
2779 case 84: /* AllocColor */
2789 case 85: /* AllocNamedColor */
2793 v16 = FIELD16(name_length);
2799 case 86: /* AllocColorCells */
2807 case 87: /* AllocColorPlanes */
2817 case 88: /* FreeColors */
2819 v16 = REQUEST_LENGTH();
2822 LISTofCARD32(pixels, v16 - 12);
2825 case 89: /* StoreColors */
2827 v16 = REQUEST_LENGTH();
2829 LISTofCOLORITEM(color_items, v16 - 8);
2832 case 90: /* StoreNamedColor */
2837 v16 = FIELD16(name_length);
2843 case 91: /* QueryColors */
2845 v16 = REQUEST_LENGTH();
2847 LISTofCARD32(pixels, v16 - 8);
2850 case 92: /* LookupColor */
2854 v16 = FIELD16(name_length);
2860 case 93: /* CreateCursor */
2864 PIXMAP(source_pixmap);
2876 case 94: /* CreateGlyphCursor */
2882 CARD16(source_char);
2892 case 95: /* FreeCursor */
2898 case 96: /* RecolorCursor */
2910 case 97: /* QueryBestSize */
2918 case 98: /* QueryExtension */
2921 v16 = FIELD16(name_length);
2927 case 99: /* ListExtensions */
2932 case 100: /* ChangeKeyboardMapping */
2933 v8 = FIELD8(keycode_count);
2935 KEYCODE(first_keycode);
2936 v8_2 = FIELD8(keysyms_per_keycode);
2938 LISTofKEYSYM(keysyms, v8, v8_2);
2941 case 101: /* GetKeyboardMapping */
2944 KEYCODE(first_keycode);
2949 case 102: /* ChangeKeyboardControl */
2952 BITMASK32(keyboard_value);
2953 BITFIELD(INT8, keyboard_value_mask, key_click_percent);
2954 BITFIELD(INT8, keyboard_value_mask, bell_percent);
2955 BITFIELD(INT16, keyboard_value_mask, bell_pitch);
2956 BITFIELD(INT16, keyboard_value_mask, bell_duration);
2957 BITFIELD(INT16, keyboard_value_mask, led);
2958 BITFIELD(ENUM8, keyboard_value_mask, led_mode);
2959 BITFIELD(KEYCODE, keyboard_value_mask, keyboard_key);
2960 BITFIELD(ENUM8, keyboard_value_mask, auto_repeat_mode);
2964 case 103: /* GetKeyboardControl */
2969 case 104: /* Bell */
2974 case 105: /* ChangePointerControl */
2977 INT16(acceleration_numerator);
2978 INT16(acceleration_denominator);
2980 BOOL(do_acceleration);
2984 case 106: /* GetPointerControl */
2989 case 107: /* SetScreenSaver */
2994 ENUM8(prefer_blanking);
2995 ENUM8(allow_exposures);
2999 case 108: /* GetScreenSaver */
3004 case 109: /* ChangeHosts */
3005 ENUM8(change_host_mode);
3009 v16 = CARD16(address_length);
3010 if (v8 == FAMILY_INTERNET && v16 == 4) {
3013 * XXX - what about IPv6? Is that a family of
3014 * FAMILY_INTERNET (0) with a length of 16?
3016 LISTofCARD8(ip_address, v16);
3018 LISTofCARD8(address, v16);
3021 case 110: /* ListHosts */
3026 case 111: /* SetAccessControl */
3031 case 112: /* SetCloseDownMode */
3032 ENUM8(close_down_mode);
3036 case 113: /* KillClient */
3042 case 114: /* RotateProperties */
3044 v16 = REQUEST_LENGTH();
3046 CARD16(property_number);
3048 LISTofATOM(properties, (v16 - 12));
3051 case 115: /* ForceScreenSaver */
3052 ENUM8(screen_saver_mode);
3056 case 116: /* SetPointerMapping */
3057 v8 = FIELD8(map_length);
3059 LISTofCARD8(map, v8);
3063 case 117: /* GetPointerMapping */
3068 case 118: /* SetModifierMapping */
3069 v8 = FIELD8(keycodes_per_modifier);
3071 LISTofKEYCODE(keycodes, v8);
3074 case 119: /* GetModifierMapping */
3079 case 127: /* NoOperation */
3084 left = tvb_length_remaining(tvb, offset);
3086 proto_tree_add_item(t, hf_x11_undecoded, tvb, offset, left, little_endian);
3089 static void dissect_x11_requests(tvbuff_t *tvb, packet_info *pinfo,
3092 volatile int offset = 0;
3093 int length_remaining;
3094 volatile gboolean little_endian;
3099 volatile gboolean is_initial_creq;
3100 guint16 auth_proto_len, auth_data_len;
3101 const char *volatile sep = NULL;
3102 conversation_t *conversation;
3103 x11_conv_data_t *volatile state_info;
3107 while (tvb_reported_length_remaining(tvb, offset) != 0) {
3108 length_remaining = tvb_length_remaining(tvb, offset);
3111 * Can we do reassembly?
3113 if (x11_desegment && pinfo->can_desegment) {
3115 * Yes - is the X11 request header split across
3116 * segment boundaries?
3118 if (length_remaining < 4) {
3120 * Yes. Tell the TCP dissector where the data
3121 * for this message starts in the data it handed
3122 * us, and how many more bytes we need, and return.
3124 pinfo->desegment_offset = offset;
3125 pinfo->desegment_len = 4 - length_remaining;
3131 * Get the state for this conversation; create the conversation
3132 * if we don't have one, and create the state if we don't have
3135 conversation = find_conversation(&pinfo->src, &pinfo->dst,
3136 pinfo->ptype, pinfo->srcport, pinfo->destport, 0);
3137 if (conversation == NULL) {
3141 conversation = conversation_new(&pinfo->src,
3142 &pinfo->dst, pinfo->ptype, pinfo->srcport,
3143 pinfo->destport, 0);
3147 * Is there state attached to this conversation?
3149 state_info = conversation_get_proto_data(conversation, proto_x11);
3150 if (state_info == NULL) {
3152 * No - create a state structure and attach it.
3154 state_info = g_mem_chunk_alloc(x11_state_chunk);
3155 state_info->opcode = NOTHING_SEEN; /* nothing seen yet */
3156 state_info->iconn_frame = 0; /* don't know it yet */
3157 state_info->byte_order = BYTE_ORDER_UNKNOWN; /* don't know it yet */
3158 conversation_add_proto_data(conversation, proto_x11,
3163 * Guess the byte order if we don't already know it.
3165 little_endian = guess_byte_ordering(tvb, pinfo, state_info);
3168 * Get the opcode and length of the putative X11 request.
3170 opcode = VALUE8(tvb, 0);
3171 plen = VALUE16(tvb, offset + 2);
3175 * This can't be 0, as it includes the header length.
3176 * A different choice of byte order wouldn't have
3180 ti = proto_tree_add_item(tree, proto_x11, tvb, offset, -1, FALSE);
3181 t = proto_item_add_subtree(ti, ett_x11);
3182 proto_tree_add_text(t, tvb, offset, -1, "Bogus request length (0)");
3186 if (state_info->iconn_frame == pinfo->fd->num ||
3187 (state_info->opcode == NOTHING_SEEN &&
3188 (opcode == 'B' || opcode == 'l') &&
3189 (plen == 11 || plen == 2816))) {
3193 * we saw this on the first pass and this is
3197 * we haven't already seen any requests, the first
3198 * byte of the message is 'B' or 'l', and the 16-bit
3199 * integer 2 bytes into the data stream is either 11
3200 * or a byte-swapped 11.
3202 * This means it's probably an initial connection
3203 * request, not a message.
3205 * 'B' is decimal 66, which is the opcode for a
3206 * PolySegment request; unfortunately, 11 is a valid
3207 * length for a PolySegment request request, so we
3208 * might mis-identify that request. (Are there any
3209 * other checks we can do?)
3211 * 'l' is decimal 108, which is the opcode for a
3212 * GetScreenSaver request; the only valid length
3213 * for that request is 1.
3215 is_initial_creq = TRUE;
3218 * We now know the byte order. Override the guess.
3220 if (state_info->byte_order == BYTE_ORDER_UNKNOWN) {
3221 if (opcode == 'B') {
3225 state_info->byte_order = BYTE_ORDER_BE;
3226 little_endian = FALSE;
3231 state_info->byte_order = BYTE_ORDER_LE;
3232 little_endian = TRUE;
3237 * Can we do reassembly?
3239 if (x11_desegment && pinfo->can_desegment) {
3241 * Yes - is the fixed-length portion of the
3242 * initial connection header split across
3243 * segment boundaries?
3245 if (length_remaining < 10) {
3247 * Yes. Tell the TCP dissector where the
3248 * data for this message starts in the data
3249 * it handed us, and how many more bytes we
3252 pinfo->desegment_offset = offset;
3253 pinfo->desegment_len = 10 - length_remaining;
3259 * Get the lengths of the authorization protocol and
3260 * the authorization data.
3262 auth_proto_len = VALUE16(tvb, offset + 6);
3263 auth_data_len = VALUE16(tvb, offset + 8);
3264 plen = 12 + ROUND_LENGTH(auth_proto_len) +
3265 ROUND_LENGTH(auth_data_len);
3268 * This is probably an ordinary request.
3270 is_initial_creq = FALSE;
3273 * The length of a request is in 4-byte words.
3279 * Can we do reassembly?
3281 if (x11_desegment && pinfo->can_desegment) {
3283 * Yes - is the X11 request split across segment
3286 if (length_remaining < plen) {
3288 * Yes. Tell the TCP dissector where the data
3289 * for this message starts in the data it handed
3290 * us, and how many more bytes we need, and return.
3292 pinfo->desegment_offset = offset;
3293 pinfo->desegment_len = plen - length_remaining;
3299 * Construct a tvbuff containing the amount of the payload
3300 * we have available. Make its reported length the
3301 * amount of data in the X11 request.
3303 * XXX - if reassembly isn't enabled. the subdissector
3304 * will throw a BoundsError exception, rather than a
3305 * ReportedBoundsError exception. We really want a tvbuff
3306 * where the length is "length", the reported length is "plen",
3307 * and the "if the snapshot length were infinite" length is the
3308 * minimum of the reported length of the tvbuff handed to us
3309 * and "plen", with a new type of exception thrown if the offset
3310 * is within the reported length but beyond that third length,
3311 * with that exception getting the "Unreassembled Packet" error.
3313 length = length_remaining;
3316 next_tvb = tvb_new_subset(tvb, offset, length, plen);
3319 * Set the column appropriately.
3321 if (is_initial_creq) {
3322 if (check_col(pinfo->cinfo, COL_INFO))
3323 col_set_str(pinfo->cinfo, COL_INFO, "Initial connection request");
3327 * We haven't set the column yet; set it.
3329 if (check_col(pinfo->cinfo, COL_INFO))
3330 col_add_str(pinfo->cinfo, COL_INFO, "Requests");
3333 * Initialize the separator.
3340 * Dissect the X11 request.
3342 * Catch the ReportedBoundsError exception; if this
3343 * particular message happens to get a ReportedBoundsError
3344 * exception, that doesn't mean that we should stop
3345 * dissecting X11 requests within this frame or chunk of
3348 * If it gets a BoundsError, we can stop, as there's nothing
3349 * more to see, so we just re-throw it.
3352 if (is_initial_creq) {
3353 dissect_x11_initial_conn(next_tvb, pinfo, tree,
3354 state_info, little_endian);
3356 dissect_x11_request(next_tvb, pinfo, tree, sep,
3357 state_info, little_endian);
3360 CATCH(BoundsError) {
3363 CATCH(ReportedBoundsError) {
3364 show_reported_bounds_error(tvb, pinfo, tree);
3369 * Skip the X11 message.
3378 dissect_x11_replies(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
3380 /* Set up structures we will need to add the protocol subtree and manage it */
3382 proto_tree *x11_tree;
3384 /* This field shows up as the "Info" column in the display; you should make
3385 it, if possible, summarize what's in the packet, so that a user looking
3386 at the list of packets can tell what type of packet it is. */
3387 if (check_col(pinfo->cinfo, COL_INFO))
3388 col_set_str(pinfo->cinfo, COL_INFO, "Replies/events");
3390 /* In the interest of speed, if "tree" is NULL, don't do any work not
3391 necessary to generate protocol tree items. */
3393 ti = proto_tree_add_item(tree, proto_x11, tvb, 0, -1, FALSE);
3394 x11_tree = proto_item_add_subtree(ti, ett_x11);
3397 * XXX - dissect these in a loop, like the requests.
3399 call_dissector(data_handle,tvb, pinfo, x11_tree);
3402 /************************************************************************
3404 *** I N I T I A L I Z A T I O N A N D M A I N ***
3406 ************************************************************************/
3409 dissect_x11(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
3411 if (check_col(pinfo->cinfo, COL_PROTOCOL))
3412 col_set_str(pinfo->cinfo, COL_PROTOCOL, "X11");
3414 if (pinfo->match_port == pinfo->destport)
3415 dissect_x11_requests(tvb, pinfo, tree);
3417 dissect_x11_replies(tvb, pinfo, tree);
3420 /* Register the protocol with Ethereal */
3421 void proto_register_x11(void)
3424 /* Setup list of header fields */
3425 static hf_register_info hf[] = {
3427 { &hf_x11_FIELDABBREV,
3428 { "FIELDNAME", "x11.FIELDABBREV",
3429 FIELDTYPE, FIELDBASE, FIELDCONVERT, BITMASK,
3430 "FIELDDESCR", HFILL }
3433 #include "x11-register-info.h"
3436 /* Setup protocol subtree array */
3437 static gint *ett[] = {
3439 &ett_x11_color_flags,
3440 &ett_x11_list_of_arc,
3442 &ett_x11_list_of_atom,
3443 &ett_x11_list_of_card32,
3444 &ett_x11_list_of_color_item,
3445 &ett_x11_color_item,
3446 &ett_x11_list_of_keycode,
3447 &ett_x11_list_of_keysyms,
3449 &ett_x11_list_of_point,
3451 &ett_x11_list_of_rectangle,
3453 &ett_x11_list_of_segment,
3455 &ett_x11_list_of_string8,
3456 &ett_x11_list_of_text_item,
3458 &ett_x11_gc_value_mask,
3459 &ett_x11_event_mask,
3460 &ett_x11_do_not_propagate_mask,
3461 &ett_x11_set_of_key_mask,
3462 &ett_x11_pointer_event_mask,
3463 &ett_x11_window_value_mask,
3464 &ett_x11_configure_window_mask,
3465 &ett_x11_keyboard_value_mask,
3467 module_t *x11_module;
3469 /* Register the protocol name and description */
3470 proto_x11 = proto_register_protocol("X11", "X11", "x11");
3472 /* Required function calls to register the header fields and subtrees used */
3473 proto_register_field_array(proto_x11, hf, array_length(hf));
3474 proto_register_subtree_array(ett, array_length(ett));
3476 register_init_routine(x11_init_protocol);
3478 x11_module = prefs_register_protocol(proto_x11, NULL);
3479 prefs_register_bool_preference(x11_module, "desegment",
3480 "Desegment all X11 messages spanning multiple TCP segments",
3481 "Whether the X11 dissector should desegment all messages spanning multiple TCP segments",
3486 proto_reg_handoff_x11(void)
3488 dissector_handle_t x11_handle;
3490 x11_handle = create_dissector_handle(dissect_x11, proto_x11);
3491 dissector_add("tcp.port", TCP_PORT_X11, x11_handle);
3492 dissector_add("tcp.port", TCP_PORT_X11_2, x11_handle);
3493 dissector_add("tcp.port", TCP_PORT_X11_3, x11_handle);
3494 data_handle = find_dissector("data");