2 * Routines for X11 dissection
3 * Copyright 2000, Christophe Tronche <ch.tronche@computer.org>
5 * $Id: packet-x11.c,v 1.37 2002/04/14 22:50:07 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 non predefined atoms
31 * - Idem for keysym <-> keycode ???
33 * - Subtree the request ids (that is x11.create-window.window and x11.change-window.window should be
34 * distinct), and add hidden fields (so we still have x11.window).
35 * - add hidden fields so we can have x11.circulate-window in addition to x11.opcode == 13
36 * - add hidden fields so we have x11.listOfStuff.length
37 * - use a faster scheme that linear list searching for the opcode.
38 * - correct display of unicode chars.
39 * - Not everything is homogeneous, in particular the handling of items in list is a total mess.
42 /* By the way, I wrote a program to generate every request and test
43 * that stuff. If you're interested, you can get it at
44 * http://tronche.com/gui/x/
56 #ifdef HAVE_SYS_TYPES_H
57 # include <sys/types.h>
62 #include <epan/packet.h>
64 #define cVALS(x) (const value_string*)(x)
66 /* Initialize the protocol and registered fields */
67 static int proto_x11 = -1;
69 #include "x11-declarations.h"
71 /* Initialize the subtree pointers */
72 static gint ett_x11 = -1;
73 static gint ett_x11_request = -1;
74 static gint ett_x11_color_flags = -1;
75 static gint ett_x11_list_of_arc = -1;
76 static gint ett_x11_arc = -1;
77 static gint ett_x11_list_of_atom = -1;
78 static gint ett_x11_list_of_card32 = -1;
79 static gint ett_x11_list_of_color_item = -1;
80 static gint ett_x11_color_item = -1;
81 static gint ett_x11_list_of_keycode = -1;
82 static gint ett_x11_list_of_keysyms = -1;
83 static gint ett_x11_keysym = -1;
84 static gint ett_x11_list_of_point = -1;
85 static gint ett_x11_point = -1;
86 static gint ett_x11_list_of_rectangle = -1;
87 static gint ett_x11_rectangle = -1;
88 static gint ett_x11_list_of_segment = -1;
89 static gint ett_x11_segment = -1;
90 static gint ett_x11_list_of_string8 = -1;
91 static gint ett_x11_list_of_text_item = -1;
92 static gint ett_x11_text_item = -1;
93 static gint ett_x11_gc_value_mask = -1;
94 static gint ett_x11_event_mask = -1;
95 static gint ett_x11_do_not_propagate_mask = -1;
96 static gint ett_x11_set_of_key_mask = -1;
97 static gint ett_x11_pointer_event_mask = -1;
98 static gint ett_x11_window_value_mask = -1;
99 static gint ett_x11_configure_window_mask = -1;
100 static gint ett_x11_keyboard_value_mask = -1;
102 static dissector_handle_t data_handle;
104 #define TCP_PORT_X11 6000
105 #define TCP_PORT_X11_2 6001
106 #define TCP_PORT_X11_3 6002
108 /************************************************************************
110 *** E N U M T A B L E S D E F I N I T I O N S ***
112 ************************************************************************/
114 static const value_string access_mode_vals[] = {
120 static const value_string all_temporary_vals[] = {
121 { 0, "AllTemporary" },
125 static const value_string alloc_vals[] = {
131 static const value_string allow_events_mode_vals[] = {
132 { 0, "AsyncPointer" },
133 { 1, "SyncPointer" },
134 { 2, "ReplayPointer" },
135 { 3, "AsyncKeyboard" },
136 { 4, "SyncKeyboard" },
137 { 5, "ReplayKeyboard" },
143 static const value_string arc_mode_vals[] = {
149 static const char *atom_predefined_interpretation[] = {
201 "UNDERLINE_POSITION",
202 "UNDERLINE_THICKNESS",
221 static const value_string auto_repeat_mode_vals[] = {
228 static const value_string background_pixmap_vals[] = {
230 { 1, "ParentRelative" },
234 static const value_string backing_store_vals[] = {
241 static const value_string border_pixmap_vals[] = {
242 { 0, "CopyFromParent" },
246 static const value_string button_vals[] = {
247 { 0x8000, "AnyButton" },
251 static const value_string cap_style_vals[] = {
259 static const value_string class_vals[] = {
266 static const value_string close_down_mode_vals[] = {
268 { 1, "RetainPermanent" },
269 { 2, "RetainTemporary" },
273 static const value_string coordinate_mode_vals[] = {
279 static const value_string direction_vals[] = {
280 { 0, "RaiseLowest" },
281 { 1, "LowerHighest" },
285 static const value_string family_vals[] = {
292 static const value_string fill_rule_vals[] = {
298 static const value_string fill_style_vals[] = {
302 { 3, "OpaqueStippled" },
306 static const value_string focus_vals[] = {
308 { 1, "PointerRoot" },
312 static const value_string function_vals[] = {
317 { 4, "AndInverted" },
325 { 12, "CopyInverted" },
326 { 13, "OrInverted" },
332 static const value_string gravity_vals[] = {
346 static const value_string image_format_vals[] = {
353 static const value_string image_pixmap_format_vals[] = {
359 static const value_string join_style_vals[] = {
366 static const value_string key_vals[] = {
371 #include "packet-x11-keysym.h"
373 static const value_string line_style_vals[] = {
380 static const value_string mode_vals[] = {
387 static const value_string on_off_vals[] = {
393 static const value_string opcode_vals[] = {
394 { 1, "CreateWindow" },
395 { 2, "ChangeWindowAttributes" },
396 { 3, "GetWindowAttributes" },
397 { 4, "DestroyWindow" },
398 { 5, "DestroySubwindows" },
399 { 6, "ChangeSaveSet" },
400 { 7, "ReparentWindow" },
402 { 9, "MapSubwindows" },
403 { 10, "UnmapWindow" },
404 { 11, "UnmapSubwindows" },
405 { 12, "ConfigureWindow" },
406 { 13, "CirculateWindow" },
407 { 14, "GetGeometry" },
409 { 16, "InternAtom" },
410 { 17, "GetAtomName" },
411 { 18, "ChangeProperty" },
412 { 19, "DeleteProperty" },
413 { 20, "GetProperty" },
414 { 21, "ListProperties" },
415 { 22, "SetSelectionOwner" },
416 { 23, "GetSelectionOwner" },
417 { 24, "ConvertSelection" },
419 { 26, "GrabPointer" },
420 { 27, "UngrabPointer" },
421 { 28, "GrabButton" },
422 { 29, "UngrabButton" },
423 { 30, "ChangeActivePointerGrab" },
424 { 31, "GrabKeyboard" },
425 { 32, "UngrabKeyboard" },
428 { 35, "AllowEvents" },
429 { 36, "GrabServer" },
430 { 37, "UngrabServer" },
431 { 38, "QueryPointer" },
432 { 39, "GetMotionEvents" },
433 { 40, "TranslateCoordinates" },
434 { 41, "WarpPointer" },
435 { 42, "SetInputFocus" },
436 { 43, "GetInputFocus" },
437 { 44, "QueryKeymap" },
441 { 48, "QueryTextExtents" },
443 { 50, "ListFontsWithInfo" },
444 { 51, "SetFontPath" },
445 { 52, "GetFontPath" },
446 { 53, "CreatePixmap" },
447 { 54, "FreePixmap" },
452 { 59, "SetClipRectangles" },
459 { 66, "PolySegment" },
460 { 67, "PolyRectangle" },
463 { 70, "PolyFillRectangle" },
464 { 71, "PolyFillArc" },
468 { 75, "PolyText16" },
469 { 76, "ImageText8" },
470 { 77, "ImageText16" },
471 { 78, "CreateColormap" },
472 { 79, "FreeColormap" },
473 { 80, "CopyColormapAndFree" },
474 { 81, "InstallColormap" },
475 { 82, "UninstallColormap" },
476 { 83, "ListInstalledColormaps" },
477 { 84, "AllocColor" },
478 { 85, "AllocNamedColor" },
479 { 86, "AllocColorCells" },
480 { 87, "AllocColorPlanes" },
481 { 88, "FreeColors" },
482 { 89, "StoreColors" },
483 { 90, "StoreNamedColor" },
484 { 91, "QueryColors" },
485 { 92, "LookupColor" },
486 { 93, "CreateCursor" },
487 { 94, "CreateGlyphCursor" },
488 { 95, "FreeCursor" },
489 { 96, "RecolorCursor" },
490 { 97, "QueryBestSize" },
491 { 98, "QueryExtension" },
492 { 99, "ListExtensions" },
493 { 100, "ChangeKeyboardMapping" },
494 { 101, "GetKeyboardMapping" },
495 { 102, "ChangeKeyboardControl" },
496 { 103, "GetKeyboardControl" },
498 { 105, "ChangePointerControl" },
499 { 106, "GetPointerControl" },
500 { 107, "SetScreenSaver" },
501 { 108, "GetScreenSaver" },
502 { 109, "ChangeHosts" },
503 { 110, "ListHosts" },
504 { 111, "SetAccessControl" },
505 { 112, "SetCloseDownMode" },
506 { 113, "KillClient" },
507 { 114, "RotateProperties" },
508 { 115, "ForceScreenSaver" },
509 { 116, "SetPointerMapping" },
510 { 117, "GetPointerMapping" },
511 { 118, "SetModifierMapping" },
512 { 119, "GetModifierMapping" },
513 { 127, "NoOperation" },
517 static const value_string ordering_vals[] = {
525 static const value_string plane_mask_vals[] = {
526 { 0xFFFFFFFF, "AllPlanes" },
530 static const value_string pointer_keyboard_mode_vals[] = {
531 { 0, "Synchronous" },
532 { 1, "Asynchronous" },
536 static const value_string revert_to_vals[] = {
538 { 1, "PointerRoot" },
543 static const value_string insert_delete_vals[] = {
549 static const value_string screen_saver_mode_vals[] = {
555 static const value_string shape_vals[] = {
562 static const value_string stack_mode_vals[] = {
571 static const value_string subwindow_mode_vals[] = {
572 { 0, "ClipByChildren" },
573 { 1, "IncludeInferiors" },
577 static const value_string window_class_vals[] = {
578 { 0, "CopyFromParent" },
579 { 1, "InputOutput" },
584 static const value_string yes_no_default_vals[] = {
591 static const value_string zero_is_any_property_type_vals[] = {
592 { 0, "AnyPropertyType" },
596 static const value_string zero_is_none_vals[] = {
601 /************************************************************************
603 *** G L O B A L V A R I A B L E S ( A R G H H ! ) ***
605 ************************************************************************/
607 static int next_offset = 0; /* Offset of the next request in the frame */
608 static gboolean little_endian = TRUE;
610 /************************************************************************
612 *** F I E L D D E C O D I N G M A C R O S ***
614 ************************************************************************/
616 #define VALUE8(tvb, offset) (tvb_get_guint8(tvb, offset))
617 #define VALUE16(tvb, offset) (little_endian ? tvb_get_letohs(tvb, offset) : tvb_get_ntohs(tvb, offset))
618 #define VALUE32(tvb, offset) (little_endian ? tvb_get_letohl(tvb, offset) : tvb_get_ntohl(tvb, offset))
620 #define FIELD8(name) (field8(tvb, offsetp, t, hf_x11_##name))
621 #define FIELD16(name) (field16(tvb, offsetp, t, hf_x11_##name))
622 #define FIELD32(name) (field32(tvb, offsetp, t, hf_x11_##name))
624 #define BITFIELD(TYPE, position, name) {\
626 int save = *offsetp;\
627 proto_tree_add_item(bitmask_tree, hf_x11_##position##_##name, tvb, bitmask_offset, \
628 bitmask_size, little_endian); \
629 if (bitmask_value & proto_registrar_get_nth(hf_x11_##position##_##name) -> bitmask) {\
631 unused = save + 4 - *offsetp;\
633 proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, unused, little_endian);\
634 *offsetp = save + 4;\
638 #define FLAG(position, name) {\
639 proto_tree_add_boolean(bitmask_tree, hf_x11_##position##_mask##_##name, tvb, bitmask_offset, bitmask_size, bitmask_value); }
641 #define FLAG_IF_NONZERO(position, name) {\
642 if (bitmask_value & proto_registrar_get_nth(hf_x11_##position##_mask##_##name) -> bitmask)\
643 proto_tree_add_boolean(bitmask_tree, hf_x11_##position##_mask##_##name, tvb, bitmask_offset, bitmask_size, bitmask_value); }
645 #define ATOM(name) { atom(tvb, offsetp, t, hf_x11_##name); }
646 #define BITGRAVITY(name) { gravity(tvb, offsetp, t, #name, hf_x11_##name, "Forget"); }
647 #define BITMASK(name, size) {\
649 guint32 bitmask_value; \
650 int bitmask_offset; \
652 proto_tree *bitmask_tree; \
653 bitmask_value = ((size == 1) ? VALUE8(tvb, *offsetp) : \
654 ((size == 2) ? VALUE16(tvb, *offsetp) : \
655 VALUE32(tvb, *offsetp))); \
656 bitmask_offset = *offsetp; \
657 bitmask_size = size; \
658 ti = proto_tree_add_uint(t, hf_x11_##name##_mask, tvb, *offsetp, size, bitmask_value); \
659 bitmask_tree = proto_item_add_subtree(ti, ett_x11_##name##_mask); \
662 #define BITMASK8(name) BITMASK(name, 1);
663 #define BITMASK16(name) BITMASK(name, 2);
664 #define BITMASK32(name) BITMASK(name, 4);
665 #define BOOL(name) (add_boolean(tvb, offsetp, t, hf_x11_##name))
666 #define BUTTON(name) { FIELD8(name); }
667 #define CARD8(name) { FIELD8(name); }
668 #define CARD16(name) (FIELD16(name))
669 #define CARD32(name) (FIELD32(name))
670 #define COLOR_FLAGS(name) { colorFlags(tvb, offsetp, t); }
671 #define COLORMAP(name) { FIELD32(name); }
672 #define CURSOR(name) { FIELD32(name); }
673 #define DRAWABLE(name) { FIELD32(name); }
674 #define ENUM8(name) { FIELD8(name); }
675 #define ENUM16(name) { FIELD16(name); }
676 #define FONT(name) { FIELD32(name); }
677 #define FONTABLE(name) { FIELD32(name); }
678 #define GCONTEXT(name) { FIELD32(name); }
679 #define INT8(name) { FIELD8(name); }
680 #define INT16(name) { FIELD16(name); }
681 #define KEYCODE(name) { FIELD8(name); }
682 #define LISTofARC(name) { listOfArc(tvb, offsetp, t, hf_x11_##name, (next_offset - *offsetp) / 12); }
683 #define LISTofATOM(name, length) { listOfAtom(tvb, offsetp, t, hf_x11_##name, (length) / 4); }
684 #define LISTofBYTE(name, length) { listOfByte(tvb, offsetp, t, hf_x11_##name, (length)); }
685 #define LISTofCARD8(name, length) { listOfByte(tvb, offsetp, t, hf_x11_##name, (length)); }
686 #define LISTofCARD32(name, length) { listOfCard32(tvb, offsetp, t, hf_x11_##name, hf_x11_##name##_item, (length) / 4); }
687 #define LISTofCOLORITEM(name, length) { listOfColorItem(tvb, offsetp, t, hf_x11_##name, (length) / 12); }
688 #define LISTofKEYCODE(name, length) { listOfKeycode(tvb, offsetp, t, hf_x11_##name, (length)); }
689 #define LISTofKEYSYM(name, keycode_count, keysyms_per_keycode) { \
690 listOfKeysyms(tvb, offsetp, t, hf_x11_##name, hf_x11_##name##_item, (keycode_count), (keysyms_per_keycode)); }
691 #define LISTofPOINT(name, length) { listOfPoint(tvb, offsetp, t, hf_x11_##name, (length) / 4); }
692 #define LISTofRECTANGLE(name) { listOfRectangle(tvb, offsetp, t, hf_x11_##name, (next_offset - *offsetp) / 8); }
693 #define LISTofSEGMENT(name) { listOfSegment(tvb, offsetp, t, hf_x11_##name, (next_offset - *offsetp) / 8); }
694 #define LISTofSTRING8(name, length) { listOfString8(tvb, offsetp, t, hf_x11_##name, hf_x11_##name##_string, (length)); }
695 #define LISTofTEXTITEM8(name) { listOfTextItem(tvb, offsetp, t, hf_x11_##name, FALSE); }
696 #define LISTofTEXTITEM16(name) { listOfTextItem(tvb, offsetp, t, hf_x11_##name, TRUE); }
697 #define OPCODE() { opcode = FIELD8(opcode); }
698 #define PIXMAP(name) { FIELD32(name); }
699 #define REQUEST_LENGTH() (requestLength(tvb, offsetp, t))
700 #define SETofEVENT(name) { setOfEvent(tvb, offsetp, t); }
701 #define SETofDEVICEEVENT(name) { setOfDeviceEvent(tvb, offsetp, t);}
702 #define SETofKEYMASK(name) { setOfKeyMask(tvb, offsetp, t); }
703 #define SETofPOINTEREVENT(name) { setOfPointerEvent(tvb, offsetp, t); }
704 #define STRING8(name, length) { string8(tvb, offsetp, t, #name, hf_x11_##name, length); }
705 #define STRING16(name, length) { string16(tvb, offsetp, t, hf_x11_##name, hf_x11_##name##_bytes, length); }
706 #define TIMESTAMP(name){ timestamp(tvb, offsetp, t, #name, hf_x11_##name); }
707 #define UNDECODED(x) { proto_tree_add_item(t, hf_x11_undecoded, tvb, *offsetp, x, little_endian); *offsetp += x; }
708 #define UNUSED(x) { proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, x, little_endian); *offsetp += x; }
709 #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; }
710 #define WINDOW(name) { FIELD32(name); }
711 #define WINGRAVITY(name) { gravity(tvb, offsetp, t, #name, hf_x11_##name, "Unmap"); }
713 #define VISUALID(name) { gint32 v = VALUE32(tvb, *offsetp); \
714 proto_tree_add_uint_format(t, hf_x11_##name, tvb, *offsetp, 4, v, "Visualid: 0x%08x%s", v, \
715 v ? "" : " (CopyFromParent)"); *offsetp += 4; }
717 /************************************************************************
719 *** D E C O D I N G F I E L D S ***
721 ************************************************************************/
723 static void atom(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf)
725 const char *interpretation = NULL;
727 guint32 v = VALUE32(tvb, *offsetp);
728 if (v >= 1 && v < array_length(atom_predefined_interpretation))
729 interpretation = atom_predefined_interpretation[v];
731 interpretation = "Not a predefined atom";
733 header_field_info *hfi = proto_registrar_get_nth(hf);
735 interpretation = match_strval(v, cVALS(hfi -> strings));
737 if (!interpretation) interpretation = "error in Xlib client program ?";
738 proto_tree_add_uint_format(t, hf, tvb, *offsetp, 4, v, "%s: %u (%s)",
739 proto_registrar_get_nth(hf) -> name, v, interpretation);
743 static guint32 add_boolean(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf)
745 guint32 v = VALUE8(tvb, *offsetp);
746 proto_tree_add_boolean(t, hf, tvb, *offsetp, 1, v);
751 static void colorFlags(tvbuff_t *tvb, int *offsetp, proto_tree *t)
753 unsigned do_red_green_blue = VALUE8(tvb, *offsetp);
757 if (do_red_green_blue) {
760 char *bp = buffer + sprintf(buffer, "flags: ");
762 if (do_red_green_blue & 0x1) {
763 bp += sprintf(bp, "DoRed");
767 if (do_red_green_blue & 0x2) {
768 if (sep) bp += sprintf(bp, " | ");
769 bp += sprintf(bp, "DoGreen");
773 if (do_red_green_blue & 0x4) {
774 if (sep) bp += sprintf(bp, " | ");
775 bp += sprintf(bp, "DoBlue");
779 if (do_red_green_blue & 0xf8) {
780 if (sep) bp += sprintf(bp, " + ");
781 sprintf(bp, "trash");
784 ti = proto_tree_add_uint_format(t, hf_x11_coloritem_flags, tvb, *offsetp, 1, do_red_green_blue,
786 tt = proto_item_add_subtree(ti, ett_x11_color_flags);
787 if (do_red_green_blue & 0x1)
788 proto_tree_add_boolean(tt, hf_x11_coloritem_flags_do_red, tvb, *offsetp, 1,
789 do_red_green_blue & 0x1);
790 if (do_red_green_blue & 0x2)
791 proto_tree_add_boolean(tt, hf_x11_coloritem_flags_do_green, tvb, *offsetp, 1,
792 do_red_green_blue & 0x2);
793 if (do_red_green_blue & 0x4)
794 proto_tree_add_boolean(tt, hf_x11_coloritem_flags_do_blue, tvb, *offsetp, 1,
795 do_red_green_blue & 0x4);
796 if (do_red_green_blue & 0xf8)
797 proto_tree_add_boolean(tt, hf_x11_coloritem_flags_unused, tvb, *offsetp, 1,
798 do_red_green_blue & 0xf8);
800 proto_tree_add_uint_format(t, hf_x11_coloritem_flags, tvb, *offsetp, 1, do_red_green_blue,
805 static void gravity(tvbuff_t *tvb, int *offsetp, proto_tree *t,
806 const char *nameAsChar, int hf, const char *nullInterpretation)
808 guint8 v = VALUE8(tvb, *offsetp);
810 proto_tree_add_uint_format(t, hf, tvb, *offsetp, 1, v, "%s: 0 (%s)", nameAsChar,
813 proto_tree_add_uint(t, hf, tvb, *offsetp, 1, v);
817 static void listOfArc(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
820 proto_item *ti = proto_tree_add_item(t, hf, tvb, *offsetp, length * 8, little_endian);
821 proto_tree *tt = proto_item_add_subtree(ti, ett_x11_list_of_arc);
823 gint16 x = VALUE16(tvb, *offsetp);
824 gint16 y = VALUE16(tvb, *offsetp + 2);
825 guint16 width = VALUE16(tvb, *offsetp + 4);
826 guint16 height = VALUE16(tvb, *offsetp + 6);
827 gint16 angle1 = VALUE16(tvb, *offsetp + 8);
828 gint16 angle2 = VALUE16(tvb, *offsetp + 10);
830 proto_item *tti = proto_tree_add_none_format(tt, hf_x11_arc, tvb, *offsetp, 12,
831 "arc: %dx%d+%d+%d, angle %d -> %d (%f degrees -> %f degrees)",
832 width, height, x, y, angle1, angle2,
833 angle1 / 64.0, angle2 / 64.0);
834 proto_tree *ttt = proto_item_add_subtree(tti, ett_x11_arc);
835 proto_tree_add_int(ttt, hf_x11_arc_x, tvb, *offsetp, 2, x);
837 proto_tree_add_int(ttt, hf_x11_arc_y, tvb, *offsetp, 2, y);
839 proto_tree_add_uint(ttt, hf_x11_arc_width, tvb, *offsetp, 2, y);
841 proto_tree_add_uint(ttt, hf_x11_arc_height, tvb, *offsetp, 2, y);
843 proto_tree_add_int(ttt, hf_x11_arc_angle1, tvb, *offsetp, 2, y);
845 proto_tree_add_int(ttt, hf_x11_arc_angle2, tvb, *offsetp, 2, y);
850 static void listOfAtom(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
853 proto_item *ti = proto_tree_add_item(t, hf, tvb, *offsetp, length * 4, little_endian);
854 proto_tree *tt = proto_item_add_subtree(ti, ett_x11_list_of_atom);
856 if (*offsetp + 4 > next_offset) {
857 /* List runs past end of message. */
860 atom(tvb, offsetp, tt, hf_x11_properties_item);
864 static void listOfByte(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
867 if (*offsetp + length > next_offset) {
868 /* List runs past end of message. */
869 length = next_offset - *offsetp;
871 if (length <= 0) length = 1;
872 proto_tree_add_item(t, hf, tvb, *offsetp, length, little_endian);
876 static void listOfCard32(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
877 int hf_item, int length)
879 proto_item *ti = proto_tree_add_item(t, hf, tvb, *offsetp, length * 4, little_endian);
880 proto_tree *tt = proto_item_add_subtree(ti, ett_x11_list_of_card32);
882 if (*offsetp + 4 > next_offset) {
883 /* List runs past end of message. */
886 proto_tree_add_uint(tt, hf_item, tvb, *offsetp, 4, VALUE32(tvb, *offsetp));
891 static void listOfColorItem(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
894 proto_item *ti = proto_tree_add_item(t, hf, tvb, *offsetp, length * 8, little_endian);
895 proto_tree *tt = proto_item_add_subtree(ti, ett_x11_list_of_color_item);
899 unsigned do_red_green_blue;
900 guint16 red, green, blue;
905 if (*offsetp + 12 > next_offset) {
906 /* List runs past end of message. */
909 red = VALUE16(tvb, *offsetp + 4);
910 green = VALUE16(tvb, *offsetp + 6);
911 blue = VALUE16(tvb, *offsetp + 8);
912 do_red_green_blue = VALUE8(tvb, *offsetp + 10);
914 bp = buffer + sprintf(buffer, "colorItem: ");
916 if (do_red_green_blue & 0x1) {
917 bp += sprintf(bp, "red = %d", red);
920 if (do_red_green_blue & 0x2) {
921 bp += sprintf(bp, "%sgreen = %d", sep, green);
924 if (do_red_green_blue & 0x4)
925 bp += sprintf(bp, "%sblue = %d", sep, blue);
927 tti = proto_tree_add_none_format(tt, hf_x11_coloritem, tvb, *offsetp, 12, "%s", buffer);
928 ttt = proto_item_add_subtree(tti, ett_x11_color_item);
929 proto_tree_add_item(ttt, hf_x11_coloritem_pixel, tvb, *offsetp, 4, little_endian);
931 proto_tree_add_item(ttt, hf_x11_coloritem_red, tvb, *offsetp, 2, little_endian);
933 proto_tree_add_item(ttt, hf_x11_coloritem_green, tvb, *offsetp, 2, little_endian);
935 proto_tree_add_item(ttt, hf_x11_coloritem_blue, tvb, *offsetp, 2, little_endian);
937 colorFlags(tvb, offsetp, ttt);
938 proto_tree_add_item(ttt, hf_x11_coloritem_unused, tvb, *offsetp, 1, little_endian);
943 static GTree *keysymTable = NULL;
945 static gint compareGuint32(gconstpointer a, gconstpointer b)
947 return GPOINTER_TO_INT(b) - GPOINTER_TO_INT(a);;
950 static const char *keysymString(guint32 v)
955 /* This table is so big that we built it only if necessary */
957 const value_string *p = keysym_vals_source;
958 keysymTable = g_tree_new(compareGuint32);
959 for(; p -> strptr; p++)
960 g_tree_insert(keysymTable, GINT_TO_POINTER(p -> value), p -> strptr);
962 res = g_tree_lookup(keysymTable, GINT_TO_POINTER(v));
963 return res ? res : "Unknown";
966 static const char *modifiers[] = { "Shift", "Lock", "Control", "Mod1", "Mod2", "Mod3", "Mod4", "Mod5" };
968 static void listOfKeycode(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
972 proto_item *ti = proto_tree_add_item(t, hf, tvb, *offsetp, length * 8, little_endian);
973 proto_tree *tt = proto_item_add_subtree(ti, ett_x11_list_of_keycode);
980 if (*offsetp + 8 > next_offset) {
981 /* List runs past end of message. */
984 for(i = 8, m = modifiers; i; i--, m++) {
985 u_char c = tvb_get_guint8(tvb, *offsetp);
988 bp += sprintf(bp, " %s=%d", *m, c);
991 proto_tree_add_bytes_format(tt, hf_x11_keycodes_item, tvb, *offsetp - 8, 8, tvb_get_ptr(tvb, *offsetp - 8, 8), "item: %s", buffer);
995 static void listOfKeysyms(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
996 int hf_item, int keycode_count, int keysyms_per_keycode)
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);
1006 while(keycode_count--) {
1007 if (*offsetp + keysyms_per_keycode * 4 > next_offset) {
1008 /* List runs past end of message. */
1011 bp = buffer + sprintf(buffer, "keysyms:");
1012 for(i = 0; i < keysyms_per_keycode; i++) {
1013 bp += sprintf(bp, " %s", keysymString(VALUE32(tvb, *offsetp + i * 4)));
1016 tti = proto_tree_add_none_format(tt, hf_item, tvb, *offsetp, keysyms_per_keycode * 4,
1018 ttt = proto_item_add_subtree(tti, ett_x11_keysym);
1019 for(i = keysyms_per_keycode; i; i--) {
1020 guint32 v = VALUE32(tvb, *offsetp);
1021 proto_tree_add_uint_format(ttt, hf_x11_keysyms_item_keysym, tvb, *offsetp, 4, v,
1022 "keysym: 0x%08x (%s)", v, keysymString(v));
1028 static void listOfPoint(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf, int length)
1030 proto_item *ti = proto_tree_add_item(t, hf, tvb, *offsetp, length * 4, little_endian);
1031 proto_tree *tt = proto_item_add_subtree(ti, ett_x11_list_of_point);
1037 if (*offsetp + 4 > next_offset) {
1038 /* List runs past end of message. */
1041 x = VALUE16(tvb, *offsetp);
1042 y = VALUE16(tvb, *offsetp + 2);
1044 tti = proto_tree_add_none_format(tt, hf_x11_point, tvb, *offsetp, 4, "point: (%d,%d)", x, y);
1045 ttt = proto_item_add_subtree(tti, ett_x11_point);
1046 proto_tree_add_int(ttt, hf_x11_point_x, tvb, *offsetp, 2, x);
1048 proto_tree_add_int(ttt, hf_x11_point_y, tvb, *offsetp, 2, y);
1053 static void listOfRectangle(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
1056 proto_item *ti = proto_tree_add_item(t, hf, tvb, *offsetp, length * 8, little_endian);
1057 proto_tree *tt = proto_item_add_subtree(ti, ett_x11_list_of_rectangle);
1060 unsigned width, height;
1064 if (*offsetp + 8 > next_offset) {
1065 /* List runs past end of message. */
1068 x = VALUE16(tvb, *offsetp);
1069 y = VALUE16(tvb, *offsetp + 2);
1070 width = VALUE16(tvb, *offsetp + 4);
1071 height = VALUE16(tvb, *offsetp + 6);
1073 tti = proto_tree_add_none_format(tt, hf_x11_rectangle, tvb, *offsetp, 8,
1074 "rectangle: %dx%d+%d+%d", width, height, x, y);
1075 ttt = proto_item_add_subtree(tti, ett_x11_rectangle);
1076 proto_tree_add_int(ttt, hf_x11_rectangle_x, tvb, *offsetp, 2, x);
1078 proto_tree_add_int(ttt, hf_x11_rectangle_y, tvb, *offsetp, 2, y);
1080 proto_tree_add_uint(ttt, hf_x11_rectangle_width, tvb, *offsetp, 2, width);
1082 proto_tree_add_uint(ttt, hf_x11_rectangle_height, tvb, *offsetp, 2, height);
1087 static void listOfSegment(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
1090 proto_item *ti = proto_tree_add_item(t, hf, tvb, *offsetp, length * 8, little_endian);
1091 proto_tree *tt = proto_item_add_subtree(ti, ett_x11_list_of_segment);
1093 gint16 x1, y1, x2, y2;
1097 if (*offsetp + 8 > next_offset) {
1098 /* List runs past end of message. */
1101 x1 = VALUE16(tvb, *offsetp);
1102 y1 = VALUE16(tvb, *offsetp + 2);
1103 x2 = VALUE16(tvb, *offsetp + 4);
1104 y2 = VALUE16(tvb, *offsetp + 6);
1106 tti = proto_tree_add_none_format(tt, hf_x11_segment, tvb, *offsetp, 8,
1107 "segment: (%d,%d)-(%d,%d)", x1, y1, x2, y2);
1108 ttt = proto_item_add_subtree(tti, ett_x11_segment);
1109 proto_tree_add_item(ttt, hf_x11_segment_x1, tvb, *offsetp, 2, little_endian);
1111 proto_tree_add_item(ttt, hf_x11_segment_y1, tvb, *offsetp, 2, little_endian);
1113 proto_tree_add_item(ttt, hf_x11_segment_x2, tvb, *offsetp, 2, little_endian);
1115 proto_tree_add_item(ttt, hf_x11_segment_y2, tvb, *offsetp, 2, little_endian);
1120 /* XXX - the protocol tree code should handle non-printable characters.
1121 Note that "non-printable characters" may depend on your locale.... */
1122 static void stringCopy(char *dest, const char *source, int length)
1127 if (!isgraph(c) && c != ' ') c = '.';
1133 static void listOfString8(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
1134 int hf_item, int length)
1137 guint allocated = 0;
1142 /* Compute total length */
1144 int scanning_offset = *offsetp; /* Scanning pointer */
1146 for(i = length; i; i--) {
1147 l = tvb_get_guint8(tvb, scanning_offset);
1148 scanning_offset += 1 + l;
1151 ti = proto_tree_add_item(t, hf, tvb, *offsetp, scanning_offset - *offsetp, little_endian);
1152 tt = proto_item_add_subtree(ti, ett_x11_list_of_string8);
1155 unsigned l = VALUE8(tvb, *offsetp);
1156 if (allocated < (l + 1)) {
1157 /* g_realloc doesn't work ??? */
1159 s = g_malloc(l + 1);
1162 stringCopy(s, tvb_get_ptr(tvb, *offsetp + 1, l), l); /* Nothing better for now. We need a better string handling API. */
1163 proto_tree_add_string_format(tt, hf_item, tvb, *offsetp, l + 1, s, "\"%s\"", s);
1169 #define STRING16_MAX_DISPLAYED_LENGTH 150
1171 static int stringIsActuallyAn8BitString(tvbuff_t *tvb, int offset, unsigned length)
1173 if (length > STRING16_MAX_DISPLAYED_LENGTH) length = STRING16_MAX_DISPLAYED_LENGTH;
1174 for(; length > 0; offset += 2, length--) {
1175 if (tvb_get_guint8(tvb, offset))
1181 /* length is the length of the _byte_zone_ (that is, twice the length of the string) */
1183 static void string16_with_buffer_preallocated(tvbuff_t *tvb, proto_tree *t,
1184 int hf, int hf_bytes,
1185 int offset, unsigned length,
1186 char **s, int *sLength)
1188 int truncated = FALSE;
1189 unsigned l = length / 2;
1191 if (stringIsActuallyAn8BitString(tvb, offset, l)) {
1193 int soffset = offset;
1195 if (l > STRING16_MAX_DISPLAYED_LENGTH) {
1197 l = STRING16_MAX_DISPLAYED_LENGTH;
1199 if (*sLength < (int) l + 3) {
1201 *s = g_malloc(l + 3);
1206 if (truncated) l -= 3;
1210 *dp++ = tvb_get_guint8(tvb, soffset);
1215 /* If truncated, add an ellipsis */
1216 if (truncated) { *dp++ = '.'; *dp++ = '.'; *dp++ = '.'; }
1219 proto_tree_add_string_format(t, hf, tvb, offset, length, tvb_get_ptr(tvb, offset, length), "%s: %s",
1220 proto_registrar_get_nth(hf) -> name, *s);
1222 proto_tree_add_item(t, hf_bytes, tvb, offset, length, little_endian);
1226 static void listOfTextItem(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
1235 /* Compute total length */
1237 int scanning_offset = *offsetp; /* Scanning pointer */
1238 int l; /* Length of an individual item */
1239 int n = 0; /* Number of items */
1241 while(scanning_offset < next_offset) {
1242 l = tvb_get_guint8(tvb, scanning_offset);
1246 scanning_offset += l == 255 ? 4 : l + (sizeIs16 ? l : 0) + 1;
1249 ti = proto_tree_add_item(t, hf, tvb, *offsetp, scanning_offset - *offsetp, little_endian);
1250 tt = proto_item_add_subtree(ti, ett_x11_list_of_text_item);
1253 unsigned l = VALUE8(tvb, *offsetp);
1254 if (l == 255) { /* Item is a font */
1255 fid = tvb_get_ntohl(tvb, *offsetp + 1);
1256 proto_tree_add_uint(tt, hf_x11_textitem_font, tvb, *offsetp, 5, fid);
1258 } else { /* Item is a string */
1261 gint8 delta = VALUE8(tvb, *offsetp + 1);
1262 if (sizeIs16) l += l;
1263 if ((unsigned) allocated < l + 1) {
1264 /* g_realloc doesn't work ??? */
1266 s = g_malloc(l + 1);
1269 stringCopy(s, tvb_get_ptr(tvb, *offsetp + 2, l), l);
1270 tti = proto_tree_add_none_format(tt, hf_x11_textitem_string, tvb, *offsetp, l + 2,
1271 "textitem (string): delta = %d, \"%s\"",
1273 ttt = proto_item_add_subtree(tti, ett_x11_text_item);
1274 proto_tree_add_item(ttt, hf_x11_textitem_string_delta, tvb, *offsetp + 1, 1, little_endian);
1276 string16_with_buffer_preallocated(tvb, ttt, hf_x11_textitem_string_string16,
1277 hf_x11_textitem_string_string16_bytes,
1281 proto_tree_add_string_format(ttt, hf_x11_textitem_string_string8, tvb,
1282 *offsetp + 2, l, s, "\"%s\"", s);
1289 static guint32 field8(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf)
1291 guint32 v = VALUE8(tvb, *offsetp);
1292 header_field_info *hfi = proto_registrar_get_nth(hf);
1293 gchar *enumValue = NULL;
1294 gchar *nameAsChar = hfi -> name;
1297 enumValue = match_strval(v, cVALS(hfi -> strings));
1299 proto_tree_add_uint_format(t, hf, tvb, *offsetp, 1, v, "%s: %u (%s)", nameAsChar, v, enumValue);
1301 proto_tree_add_item(t, hf, tvb, *offsetp, 1, little_endian);
1306 static guint32 field16(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf)
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)
1316 guint32 v = VALUE32(tvb, *offsetp);
1317 header_field_info *hfi = proto_registrar_get_nth(hf);
1318 gchar *enumValue = NULL;
1319 gchar *nameAsChar = hfi -> name;
1322 enumValue = match_strval(v, cVALS(hfi -> strings));
1324 proto_tree_add_uint_format(t, hf, tvb, *offsetp, 4, v, "%s: 0x%08x (%s)", nameAsChar, v, enumValue);
1326 proto_tree_add_uint_format(t, hf, tvb, *offsetp, 4, v,
1327 hfi -> display == BASE_DEC ? "%s: %u" : "%s: 0x%08x",
1333 static void gcAttributes(tvbuff_t *tvb, int *offsetp, proto_tree *t)
1335 BITMASK32(gc_value);
1336 BITFIELD(ENUM8, gc_value_mask, function);
1337 BITFIELD(CARD32, gc_value_mask, plane_mask);
1338 BITFIELD(CARD32, gc_value_mask, foreground);
1339 BITFIELD(CARD32, gc_value_mask, background);
1340 BITFIELD(CARD16, gc_value_mask, line_width);
1341 BITFIELD(ENUM8, gc_value_mask, line_style);
1342 BITFIELD(ENUM8, gc_value_mask, cap_style);
1343 BITFIELD(ENUM8, gc_value_mask, join_style);
1344 BITFIELD(ENUM8, gc_value_mask, fill_style);
1345 BITFIELD(ENUM8, gc_value_mask, fill_rule);
1346 BITFIELD(PIXMAP, gc_value_mask, tile);
1347 BITFIELD(PIXMAP, gc_value_mask, stipple);
1348 BITFIELD(INT16, gc_value_mask, tile_stipple_x_origin);
1349 BITFIELD(INT16, gc_value_mask, tile_stipple_y_origin);
1350 BITFIELD(FONT, gc_value_mask, font);
1351 BITFIELD(ENUM8, gc_value_mask, subwindow_mode);
1352 BITFIELD(BOOL, gc_value_mask, graphics_exposures);
1353 BITFIELD(INT16, gc_value_mask, clip_x_origin);
1354 BITFIELD(INT16, gc_value_mask, clip_y_origin);
1355 BITFIELD(PIXMAP, gc_value_mask, clip_mask);
1356 BITFIELD(CARD16, gc_value_mask, dash_offset);
1357 BITFIELD(CARD8, gc_value_mask, gc_dashes);
1358 BITFIELD(ENUM8, gc_value_mask, arc_mode);
1362 static void gcMask(tvbuff_t *tvb, int *offsetp, proto_tree *t)
1364 BITMASK32(gc_value);
1365 FLAG(gc_value, function);
1366 FLAG(gc_value, plane_mask);
1367 FLAG(gc_value, foreground);
1368 FLAG(gc_value, background);
1369 FLAG(gc_value, line_width);
1370 FLAG(gc_value, line_style);
1371 FLAG(gc_value, cap_style);
1372 FLAG(gc_value, join_style);
1373 FLAG(gc_value, fill_style);
1374 FLAG(gc_value, fill_rule);
1375 FLAG(gc_value, tile);
1376 FLAG(gc_value, stipple);
1377 FLAG(gc_value, tile_stipple_x_origin);
1378 FLAG(gc_value, tile_stipple_y_origin);
1379 FLAG(gc_value, font);
1380 FLAG(gc_value, subwindow_mode);
1381 FLAG(gc_value, graphics_exposures);
1382 FLAG(gc_value, clip_x_origin);
1383 FLAG(gc_value, clip_y_origin);
1384 FLAG(gc_value, clip_mask);
1385 FLAG(gc_value, dash_offset);
1386 FLAG(gc_value, gc_dashes);
1387 FLAG(gc_value, arc_mode);
1391 static guint32 requestLength(tvbuff_t *tvb, int *offsetp, proto_tree *t)
1393 guint32 res = VALUE16(tvb, *offsetp) * 4;
1394 proto_tree_add_uint(t, hf_x11_request_length, tvb, *offsetp, 2, res);
1399 static void setOfEvent(tvbuff_t *tvb, int *offsetp, proto_tree *t)
1402 FLAG(event, KeyPress);
1403 FLAG(event, KeyRelease);
1404 FLAG(event, ButtonPress);
1405 FLAG(event, ButtonRelease);
1406 FLAG(event, EnterWindow);
1407 FLAG(event, LeaveWindow);
1408 FLAG(event, PointerMotion);
1409 FLAG(event, PointerMotionHint);
1410 FLAG(event, Button1Motion);
1411 FLAG(event, Button2Motion);
1412 FLAG(event, Button3Motion);
1413 FLAG(event, Button4Motion);
1414 FLAG(event, Button5Motion);
1415 FLAG(event, ButtonMotion);
1416 FLAG(event, KeymapState);
1417 FLAG(event, Exposure);
1418 FLAG(event, VisibilityChange);
1419 FLAG(event, StructureNotify);
1420 FLAG(event, ResizeRedirect);
1421 FLAG(event, SubstructureNotify);
1422 FLAG(event, SubstructureRedirect);
1423 FLAG(event, FocusChange);
1424 FLAG(event, PropertyChange);
1425 FLAG(event, ColormapChange);
1426 FLAG(event, OwnerGrabButton);
1427 FLAG_IF_NONZERO(event, erroneous_bits);
1431 static void setOfDeviceEvent(tvbuff_t *tvb, int *offsetp, proto_tree *t)
1433 BITMASK32(do_not_propagate);
1434 FLAG(do_not_propagate, KeyPress);
1435 FLAG(do_not_propagate, KeyRelease);
1436 FLAG(do_not_propagate, ButtonPress);
1437 FLAG(do_not_propagate, ButtonRelease);
1438 FLAG(do_not_propagate, PointerMotion);
1439 FLAG(do_not_propagate, Button1Motion);
1440 FLAG(do_not_propagate, Button2Motion);
1441 FLAG(do_not_propagate, Button3Motion);
1442 FLAG(do_not_propagate, Button4Motion);
1443 FLAG(do_not_propagate, Button5Motion);
1444 FLAG(do_not_propagate, ButtonMotion);
1445 FLAG_IF_NONZERO(do_not_propagate, erroneous_bits);
1449 static void setOfKeyMask(tvbuff_t *tvb, int *offsetp, proto_tree *t)
1452 guint32 bitmask_value;
1455 proto_tree *bitmask_tree;
1457 bitmask_value = VALUE16(tvb, *offsetp);
1458 bitmask_offset = *offsetp;
1460 if (bitmask_value == 0x8000)
1461 proto_tree_add_uint_format(t, hf_x11_modifiers_mask_AnyModifier, tvb, *offsetp, 2, 0x8000,
1462 "modifiers-masks: 0x8000 (AnyModifier)");
1464 ti = proto_tree_add_uint(t, hf_x11_modifiers_mask, tvb, *offsetp, 2,
1466 bitmask_tree = proto_item_add_subtree(ti, ett_x11_set_of_key_mask);
1467 FLAG(modifiers, Shift);
1468 FLAG(modifiers, Lock);
1469 FLAG(modifiers, Control);
1470 FLAG(modifiers, Mod1);
1471 FLAG(modifiers, Mod2);
1472 FLAG(modifiers, Mod3);
1473 FLAG(modifiers, Mod4);
1474 FLAG(modifiers, Mod5);
1475 FLAG_IF_NONZERO(modifiers, erroneous_bits);
1480 static void setOfPointerEvent(tvbuff_t *tvb, int *offsetp, proto_tree *t)
1482 BITMASK16(pointer_event);
1483 FLAG(pointer_event, ButtonPress);
1484 FLAG(pointer_event, ButtonRelease);
1485 FLAG(pointer_event, EnterWindow);
1486 FLAG(pointer_event, LeaveWindow);
1487 FLAG(pointer_event, PointerMotion);
1488 FLAG(pointer_event, PointerMotionHint);
1489 FLAG(pointer_event, Button1Motion);
1490 FLAG(pointer_event, Button2Motion);
1491 FLAG(pointer_event, Button3Motion);
1492 FLAG(pointer_event, Button4Motion);
1493 FLAG(pointer_event, Button5Motion);
1494 FLAG(pointer_event, ButtonMotion);
1495 FLAG(pointer_event, KeymapState);
1496 FLAG_IF_NONZERO(pointer_event, erroneous_bits);
1500 static void string8(tvbuff_t *tvb, int *offsetp, proto_tree *t,
1501 const char *nameAsChar, int hf, unsigned length)
1503 char *s = g_malloc(length + 1);
1505 stringCopy(s, tvb_get_ptr(tvb, *offsetp, length), length);
1506 proto_tree_add_string_format(t, hf, tvb, *offsetp, length, s, "%s: %s", nameAsChar, s);
1511 /* The length is the length of the _byte_zone_ (twice the length of the string) */
1513 static void string16(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
1514 int hf_bytes, unsigned length)
1520 string16_with_buffer_preallocated(tvb, t, hf, hf_bytes, *offsetp, length, &s, &l);
1525 static void timestamp(tvbuff_t *tvb, int *offsetp, proto_tree *t,
1526 const char *nameAsChar, int hf)
1528 guint32 v = VALUE32(tvb, *offsetp);
1530 proto_tree_add_uint_format(t, hf, tvb, *offsetp, 4, 0, "%s: 0 (CurrentTime)", nameAsChar);
1532 proto_tree_add_uint(t, hf, tvb, *offsetp, 4, v);
1536 static void windowAttributes(tvbuff_t *tvb, int *offsetp, proto_tree *t)
1538 BITMASK32(window_value);
1539 BITFIELD(PIXMAP, window_value_mask, background_pixmap);
1540 BITFIELD(CARD32, window_value_mask, background_pixel);
1541 BITFIELD(PIXMAP, window_value_mask, border_pixmap);
1542 BITFIELD(CARD32, window_value_mask, border_pixel);
1543 BITFIELD(BITGRAVITY, window_value_mask, bit_gravity);
1544 BITFIELD(WINGRAVITY, window_value_mask, win_gravity);
1545 BITFIELD(ENUM8, window_value_mask, backing_store);
1546 BITFIELD(CARD32, window_value_mask, backing_planes);
1547 BITFIELD(CARD32, window_value_mask, backing_pixel);
1548 BITFIELD(BOOL, window_value_mask, override_redirect);
1549 BITFIELD(BOOL, window_value_mask, save_under);
1550 BITFIELD(SETofEVENT, window_value_mask, event_mask);
1551 BITFIELD(SETofDEVICEEVENT, window_value_mask, do_not_propagate_mask);
1552 BITFIELD(COLORMAP, window_value_mask, colormap);
1553 BITFIELD(CURSOR, window_value_mask, cursor);
1557 /************************************************************************
1559 *** D E C O D I N G O N E P A C K E T ***
1561 ************************************************************************/
1563 static int dissect_x11_request_loop(tvbuff_t *tvb, int *offsetp, proto_tree *root)
1565 int left = tvb_reported_length(tvb), nextLeft;
1572 /* The X11 data stream to the server is just a sequence of requests,
1573 each of which contains a length; for now, we dissect all the
1574 requests in this frame until we run out of data in the frame.
1575 Eventually, we should handle requests that cross frame
1578 Note that "in this frame" refers to everything in the frame
1579 as it appeared in the wire, not as it was captured; we want
1580 an exception to be thrown if we go past the end of the
1581 captured data in the frame without going past the end of the
1582 data in the frame. */
1586 /* fprintf(stderr, "Starting loop, left = %d, *offsetp = %d\n", left, *offsetp); */
1588 /* We ran out of data - we don't have enough data in
1589 the frame to get the length of this request. */
1592 length = VALUE16(tvb, *offsetp + 2) * 4;
1593 /* fprintf(stderr, "length = %d\n", length);*/
1594 if (left < length) {
1595 /* We ran out of data - we don't have enough data in
1596 the frame for the full request. */
1600 /* Bogus message length? */
1604 next_offset = *offsetp + length;
1605 nextLeft = left - length;
1607 ti = proto_tree_add_uint(root, hf_x11_request, tvb, *offsetp, length, tvb_get_guint8(tvb, *offsetp));
1608 t = proto_item_add_subtree(ti, ett_x11_request);
1613 case 1: /* CreateWindow */
1622 CARD16(border_width);
1623 ENUM16(window_class);
1625 windowAttributes(tvb, offsetp, t);
1628 case 2: /* ChangeWindowAttributes */
1632 windowAttributes(tvb, offsetp, t);
1635 case 3: /* GetWindowAttributes */
1636 case 4: /* DestroyWindow */
1637 case 5: /* DestroySubwindows */
1643 case 6: /* ChangeSaveSet */
1644 ENUM8(save_set_mode);
1649 case 7: /* ReparentWindow */
1658 case 8: /* MapWindow */
1659 case 9: /* MapSubWindow */
1660 case 10: /* UnmapWindow */
1661 case 11: /* UnmapSubwindows */
1667 case 12: /* ConfigureWindow */
1671 BITMASK16(configure_window);
1673 BITFIELD(INT16, configure_window_mask, x);
1674 BITFIELD(INT16, configure_window_mask, y);
1675 BITFIELD(CARD16, configure_window_mask, width);
1676 BITFIELD(CARD16, configure_window_mask, height);
1677 BITFIELD(CARD16, configure_window_mask, border_width);
1678 BITFIELD(WINDOW, configure_window_mask, sibling);
1679 BITFIELD(ENUM8, configure_window_mask, stack_mode);
1684 case 13: /* CirculateWindow */
1690 case 14: /* GetGeometry */
1691 case 15: /* QueryTree */
1697 case 16: /* InternAtom */
1698 BOOL(only_if_exists);
1700 v16 = FIELD16(name_length);
1706 case 17: /* GetAtomName */
1712 case 18: /* ChangeProperty */
1720 v32 = CARD32(data_length);
1721 LISTofBYTE(data, v32);
1725 case 19: /* DeleteProperty */
1732 case 20: /* GetProperty */
1737 ATOM(get_property_type);
1738 CARD32(long_offset);
1739 CARD32(long_length);
1742 case 21: /* ListProperties */
1748 case 22: /* SetSelectionOwner */
1756 case 23: /* GetSelectionOwner */
1762 case 24: /* ConvertSelection */
1772 case 26: /* GrabPointer */
1775 WINDOW(grab_window);
1776 SETofPOINTEREVENT(pointer_event_mask);
1777 ENUM8(pointer_mode);
1778 ENUM8(keyboard_mode);
1784 case 27: /* UngrabPointer */
1790 case 28: /* GrabButton */
1793 WINDOW(grab_window);
1794 SETofPOINTEREVENT(event_mask);
1795 ENUM8(pointer_mode);
1796 ENUM8(keyboard_mode);
1801 SETofKEYMASK(modifiers);
1804 case 29: /* UngrabButton */
1807 WINDOW(grab_window);
1808 SETofKEYMASK(modifiers);
1812 case 30: /* ChangeActivePointerGrab */
1817 SETofPOINTEREVENT(event_mask);
1821 case 31: /* GrabKeyboard */
1824 WINDOW(grab_window);
1826 ENUM8(pointer_mode);
1827 ENUM8(keyboard_mode);
1831 case 32: /* UngrabKeyboard */
1837 case 33: /* GrabKey */
1840 WINDOW(grab_window);
1841 SETofKEYMASK(modifiers);
1843 ENUM8(pointer_mode);
1844 ENUM8(keyboard_mode);
1848 case 34: /* UngrabKey */
1851 WINDOW(grab_window);
1852 SETofKEYMASK(modifiers);
1856 case 35: /* AllowEvents */
1857 ENUM8(allow_events_mode);
1862 case 36: /* GrabServer */
1867 case 37: /* UngrabServer */
1872 case 38: /* QueryPointer */
1878 case 39: /* GetMotionEvents */
1886 case 40: /* TranslateCoordinates */
1895 case 41: /* WarpPointer */
1898 WINDOW(warp_pointer_src_window);
1899 WINDOW(warp_pointer_dst_window);
1908 case 42: /* SetInputFocus */
1915 case 43: /* GetInputFocus */
1920 case 44: /* QueryKeymap */
1925 case 45: /* OpenFont */
1929 v16 = FIELD16(name_length);
1935 case 46: /* CloseFont */
1941 case 47: /* QueryFont */
1947 case 48: /* QueryTextExtents */
1948 v8 = BOOL(odd_length);
1951 STRING16(string16, (next_offset - *offsetp - (v8 ? 2 : 0)) / 2);
1955 case 49: /* ListFonts */
1959 v16 = FIELD16(pattern_length);
1960 STRING8(pattern, v16);
1964 case 50: /* ListFontsWithInfo */
1968 v16 = FIELD16(pattern_length);
1969 STRING8(pattern, v16);
1973 case 51: /* SetFontPath */
1976 v16 = CARD16(str_number_in_path);
1978 LISTofSTRING8(path, v16);
1982 case 52: /* GetFontPath */
1987 case 53: /* CreatePixmap */
1996 case 54: /* FreePixmap */
2002 case 55: /* CreateGC */
2007 gcAttributes(tvb, offsetp, t);
2010 case 56: /* ChangeGC */
2014 gcAttributes(tvb, offsetp, t);
2017 case 57: /* CopyGC */
2022 gcMask(tvb, offsetp, t);
2025 case 58: /* SetDashes */
2029 CARD16(dash_offset);
2030 v16 = FIELD16(dashes_length);
2031 LISTofCARD8(dashes, v16);
2035 case 59: /* SetClipRectangles */
2039 INT16(clip_x_origin);
2040 INT16(clip_y_origin);
2041 LISTofRECTANGLE(rectangles);
2044 case 60: /* FreeGC */
2050 case 61: /* ClearArea */
2060 case 62: /* CopyArea */
2063 DRAWABLE(src_drawable);
2064 DRAWABLE(dst_drawable);
2074 case 63: /* CopyPlane */
2077 DRAWABLE(src_drawable);
2078 DRAWABLE(dst_drawable);
2089 case 64: /* PolyPoint */
2090 ENUM8(coordinate_mode);
2091 v16 = REQUEST_LENGTH();
2094 LISTofPOINT(points, v16 - 12);
2097 case 65: /* PolyLine */
2098 ENUM8(coordinate_mode);
2099 v16 = REQUEST_LENGTH();
2102 LISTofPOINT(points, v16 - 12);
2105 case 66: /* PolySegment */
2110 LISTofSEGMENT(segments);
2113 case 67: /* PolyRectangle */
2118 LISTofRECTANGLE(rectangles);
2121 case 68: /* PolyArc */
2129 case 69: /* FillPoly */
2131 v16 = REQUEST_LENGTH();
2135 ENUM8(coordinate_mode);
2137 LISTofPOINT(points, v16 - 16);
2140 case 70: /* PolyFillRectangle */
2145 LISTofRECTANGLE(rectangles);
2148 case 71: /* PolyFillArc */
2156 case 72: /* PutImage */
2157 ENUM8(image_format);
2158 v16 = REQUEST_LENGTH();
2168 LISTofBYTE(data, v16 - 24);
2172 case 73: /* GetImage */
2173 ENUM8(image_pixmap_format);
2183 case 74: /* PolyText8 */
2185 v16 = REQUEST_LENGTH();
2190 LISTofTEXTITEM8(items);
2194 case 75: /* PolyText16 */
2196 v16 = REQUEST_LENGTH();
2201 LISTofTEXTITEM16(items);
2205 case 76: /* ImageText8 */
2206 v8 = FIELD8(string_length);
2212 STRING8(string, v8);
2216 case 77: /* ImageText16 */
2217 v8 = FIELD8(string_length);
2223 STRING16(string16, v8);
2227 case 78: /* CreateColormap */
2235 case 79: /* FreeColormap */
2241 case 80: /* CopyColormapAndFree */
2248 case 81: /* InstallColormap */
2254 case 82: /* UninstallColormap */
2260 case 83: /* ListInstalledColormaps */
2266 case 84: /* AllocColor */
2276 case 85: /* AllocNamedColor */
2280 v16 = FIELD16(name_length);
2286 case 86: /* AllocColorCells */
2294 case 87: /* AllocColorPlanes */
2304 case 88: /* FreeColors */
2306 v16 = REQUEST_LENGTH();
2309 LISTofCARD32(pixels, v16 - 12);
2312 case 89: /* StoreColors */
2314 v16 = REQUEST_LENGTH();
2316 LISTofCOLORITEM(color_items, v16 - 8);
2319 case 90: /* StoreNamedColor */
2324 v16 = FIELD16(name_length);
2330 case 91: /* QueryColors */
2332 v16 = REQUEST_LENGTH();
2334 LISTofCARD32(pixels, v16 - 8);
2337 case 92: /* LookupColor */
2341 v16 = FIELD16(name_length);
2347 case 93: /* CreateCursor */
2351 PIXMAP(source_pixmap);
2363 case 94: /* CreateGlyphCursor */
2369 CARD16(source_char);
2379 case 95: /* FreeCursor */
2385 case 96: /* RecolorCursor */
2397 case 97: /* QueryBestSize */
2405 case 98: /* QueryExtension */
2408 v16 = FIELD16(name_length);
2414 case 99: /* ListExtensions */
2419 case 100: /* ChangeKeyboardMapping */
2420 v8 = FIELD8(keycode_count);
2422 KEYCODE(first_keycode);
2423 v8_2 = FIELD8(keysyms_per_keycode);
2425 LISTofKEYSYM(keysyms, v8, v8_2);
2428 case 101: /* GetKeyboardMapping */
2431 KEYCODE(first_keycode);
2436 case 102: /* ChangeKeyboardControl */
2439 BITMASK32(keyboard_value);
2440 BITFIELD(INT8, keyboard_value_mask, key_click_percent);
2441 BITFIELD(INT8, keyboard_value_mask, bell_percent);
2442 BITFIELD(INT16, keyboard_value_mask, bell_pitch);
2443 BITFIELD(INT16, keyboard_value_mask, bell_duration);
2444 BITFIELD(INT16, keyboard_value_mask, led);
2445 BITFIELD(ENUM8, keyboard_value_mask, led_mode);
2446 BITFIELD(KEYCODE, keyboard_value_mask, keyboard_key);
2447 BITFIELD(ENUM8, keyboard_value_mask, auto_repeat_mode);
2451 case 103: /* GetKeyboardControl */
2456 case 104: /* Bell */
2461 case 105: /* ChangePointerControl */
2464 INT16(acceleration_numerator);
2465 INT16(acceleration_denominator);
2467 BOOL(do_acceleration);
2471 case 106: /* GetPointerControl */
2476 case 107: /* SetScreenSaver */
2481 ENUM8(prefer_blanking);
2482 ENUM8(allow_exposures);
2486 case 108: /* GetScreenSaver */
2491 case 109: /* ChangeHosts */
2492 ENUM8(change_host_mode);
2496 v16 = CARD16(address_length);
2497 LISTofCARD8(address, v16);
2500 case 110: /* ListHosts */
2505 case 111: /* SetAccessControl */
2510 case 112: /* SetCloseDownMode */
2511 ENUM8(close_down_mode);
2515 case 113: /* KillClient */
2521 case 114: /* RotateProperties */
2523 v16 = REQUEST_LENGTH();
2525 CARD16(property_number);
2527 LISTofATOM(properties, (v16 - 12));
2530 case 115: /* ForceScreenSaver */
2531 ENUM8(screen_saver_mode);
2535 case 116: /* SetPointerMapping */
2536 v8 = FIELD8(map_length);
2538 LISTofCARD8(map, v8);
2542 case 117: /* GetPointerMapping */
2547 case 118: /* SetModifierMapping */
2548 v8 = FIELD8(keycodes_per_modifier);
2550 LISTofKEYCODE(keycodes, v8);
2553 case 119: /* GetModifierMapping */
2558 case 127: /* NoOperation */
2563 if (*offsetp < next_offset)
2564 proto_tree_add_item(t, hf_x11_undecoded, tvb, *offsetp, next_offset - *offsetp, little_endian);
2565 *offsetp = next_offset;
2572 /************************************************************************
2574 *** G U E S S I N G T H E B Y T E O R D E R I N G ***
2576 ************************************************************************/
2578 static GTree *byte_ordering_cache = NULL;
2579 static GMemChunk *address_chunk = NULL;
2580 static GMemChunk *ipv4_chunk = NULL;
2581 static GMemChunk *ipv6_chunk = NULL;
2583 static gint compareAddresses(gconstpointer aa, gconstpointer bb)
2585 const address *a = (const address *)aa;
2586 const address *b = (const address *)bb;
2587 int c = b -> type - a -> type;
2589 c = b -> len - a -> len;
2591 return memcmp(b -> data, a -> data, a -> len);
2594 /* If we can't guess, we return TRUE (that is little_endian), cause
2595 I'm developing on a Linux box :-). The (non-)guess isn't cached
2596 however, so we may have more luck next time. I'm quite conservative
2597 in my assertions, cause once it's cached, it's stay in cache, and
2598 we may be fooled up by a packet starting with the end of a request
2599 started in a previous packet...
2602 int numberOfBitSetTable[] = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4 };
2604 int numberOfBitSet(tvbuff_t *tvb, int offset, int maskLength)
2607 while(maskLength--) {
2608 int c = tvb_get_guint8(tvb, offset);
2610 res += numberOfBitSetTable[c & 0xf] + numberOfBitSetTable[c >> 4];
2615 static int listOfStringLengthConsistent(tvbuff_t *tvb, int offset, int length, int listLength)
2617 if (listLength > length) return FALSE;
2618 while(listLength--) {
2620 if (!tvb_bytes_exist(tvb, offset, 1)) return TRUE;
2621 l = tvb_get_guint8(tvb, offset);
2624 if (l > length) return FALSE;
2625 if (!tvb_bytes_exist(tvb, offset, l)) return TRUE;
2629 if (length > 3) return FALSE;
2633 static int rounded4(int n)
2635 int remainder = n % 4;
2637 if (remainder) res++;
2641 /* We assume the order to be consistent, until proven wrong. */
2643 static gboolean consistentWithOrder(int length, tvbuff_t *tvb, int offset, guint16 (*v16)(tvbuff_t *, gint))
2645 switch(tvb_get_guint8(tvb, offset)) {
2646 case 1: /* CreateWindow */
2647 return !tvb_bytes_exist(tvb, offset, 32) || length == 8 + numberOfBitSet(tvb, offset + 7 * 4, 4);
2649 case 2: /* ChangeWindowAttributes */
2650 case 56: /* ChangeGC */
2651 return !tvb_bytes_exist(tvb, offset, 12) || length == 3 + numberOfBitSet(tvb, offset + 8, 4);
2653 case 3: /* GetWindowAttributes */
2654 case 4: /* DestroyWindow */
2655 case 5: /* DestroySubwindows */
2656 case 6: /* ChangeSaveSet */
2657 case 8: /* MapWindow */
2658 case 9: /* MapSubWindow */
2659 case 10: /* UnmapWindow */
2660 case 11: /* UnmapSubwindows */
2661 case 13: /* CirculateWindow */
2662 case 14: /* GetGeometry */
2663 case 15: /* QueryTree */
2664 case 17: /* GetAtomName */
2665 case 21: /* ListProperties */
2666 case 23: /* GetSelectionOwner */
2667 case 27: /* UngrabPointer */
2668 case 32: /* UngrabKeyboard */
2669 case 35: /* AllowEvents */
2670 case 38: /* QueryPointer */
2671 case 46: /* CloseFont */
2672 case 47: /* QueryFont */
2673 case 54: /* FreePixmap */
2674 case 60: /* FreeGC */
2675 case 79: /* FreeColormap */
2676 case 81: /* InstallColormap */
2677 case 82: /* UninstallColormap */
2678 case 83: /* ListInstalledColormaps */
2679 case 95: /* FreeCursor */
2680 case 101: /* GetKeyboardMapping */
2681 case 113: /* KillClient */
2684 case 7: /* ReparentWindow */
2685 case 22: /* SetSelectionOwner */
2686 case 30: /* ChangeActivePointerGrab */
2687 case 31: /* GrabKeyboard */
2688 case 33: /* GrabKey */
2689 case 39: /* GetMotionEvents */
2690 case 40: /* TranslateCoordinates */
2691 case 53: /* CreatePixmap */
2692 case 57: /* CopyGC */
2693 case 61: /* ClearArea */
2694 case 78: /* CreateColormap */
2695 case 84: /* AllocColor */
2696 case 87: /* AllocColorPlanes */
2699 case 12: /* ConfigureWindow */
2700 return !tvb_bytes_exist(tvb, offset, 10) || length == 3 + numberOfBitSet(tvb, offset + 8, 2);
2702 case 16: /* InternAtom */
2703 case 98: /* QueryExtension */
2704 return !tvb_bytes_exist(tvb, offset, 6) || length == 2 + rounded4(v16(tvb, offset + 4));
2706 case 18: /* ChangeProperty */
2708 int multiplier, type;
2709 if (!tvb_bytes_exist(tvb, offset, 17)) return TRUE;
2710 type = tvb_get_guint8(tvb, 16);
2711 if (type != 8 && type != 16 && type != 32) return FALSE;
2712 multiplier = type == 8 ? 1 : type == 16 ? 2 : 4;
2713 if (!tvb_bytes_exist(tvb, offset, 24)) return TRUE;
2714 return length == 6 + rounded4((v16 == tvb_get_letohs ? tvb_get_letohl : tvb_get_ntohl)(tvb, offset + 20) * multiplier);
2717 case 19: /* DeleteProperty */
2718 case 29: /* UngrabButton */
2719 case 34: /* UngrabKey */
2720 case 42: /* SetInputFocus */
2721 case 80: /* CopyColormapAndFree */
2722 case 86: /* AllocColorCells */
2723 case 97: /* QueryBestSize */
2724 case 105: /* ChangePointerControl */
2725 case 107: /* SetScreenSaver */
2728 case 20: /* GetProperty */
2729 case 24: /* ConvertSelection */
2730 case 26: /* GrabPointer */
2731 case 28: /* GrabButton */
2732 case 41: /* WarpPointer */
2735 case 25: /* SendEvent */
2736 return length == 11;
2738 case 36: /* GrabServer */
2739 case 37: /* UngrabServer */
2740 case 43: /* GetInputFocus */
2741 case 44: /* QueryKeymap */
2742 case 52: /* GetFontPath */
2743 case 99: /* ListExtensions */
2744 case 103: /* GetKeyboardControl */
2745 case 104: /* Bell */
2746 case 106: /* GetPointerControl */
2747 case 108: /* GetScreenSaver */
2748 case 110: /* ListHosts */
2749 case 111: /* SetAccessControl */
2750 case 112: /* SetCloseDownMode */
2751 case 115: /* ForceScreenSaver */
2752 case 117: /* GetPointerMapping */
2753 case 119: /* GetModifierMapping */
2756 case 45: /* OpenFont */
2757 case 85: /* AllocNamedColor */
2758 case 92: /* LookupColor */
2759 return !tvb_bytes_exist(tvb, offset, 10) || length == 3 + rounded4(v16(tvb, offset + 8));
2761 case 48: /* QueryTextExtents */
2764 case 49: /* ListFonts */
2765 case 50: /* ListFontsWithInfo */
2766 case 109: /* ChangeHosts */
2767 return !tvb_bytes_exist(tvb, offset, 8) || length == 2 + rounded4(v16(tvb, offset + 6));
2769 case 51: /* SetFontPath */
2770 if (length < 2) return FALSE;
2771 if (!tvb_bytes_exist(tvb, offset, 8)) return TRUE;
2772 return listOfStringLengthConsistent(tvb, offset + 8, (length - 2) * 4, v16(tvb, offset + 4));
2774 case 55: /* CreateGC */
2775 return !tvb_bytes_exist(tvb, offset, 16) || length == 4 + numberOfBitSet(tvb, offset + 12, 4);
2777 case 58: /* SetDashes */
2778 return !tvb_bytes_exist(tvb, offset, 12) || length == 3 + rounded4(v16(tvb, offset + 10));
2780 case 59: /* SetClipRectangles */
2781 case 66: /* PolySegment */
2782 case 67: /* PolyRectangle */
2783 case 70: /* PolyFillRectangle */
2784 return length >= 3 && (length - 3) % 2 == 0;
2786 case 62: /* CopyArea */
2789 case 63: /* CopyPlane */
2790 case 93: /* CreateCursor */
2791 case 94: /* CreateGlyphCursor */
2794 case 64: /* PolyPoint */
2795 case 65: /* PolyLine */
2796 case 88: /* FreeColors */
2799 case 68: /* PolyArc */
2800 case 71: /* PolyFillArc */
2801 return length >= 3 && (length - 3) % 3 == 0;
2803 case 69: /* FillPoly */
2804 case 76: /* ImageText8 */
2807 case 72: /* PutImage */
2810 case 73: /* GetImage */
2811 case 96: /* RecolorCursor */
2814 case 74: /* PolyText8 */
2815 if (length < 4) return FALSE;
2816 return TRUE; /* We don't perform many controls on this one */
2818 case 75: /* PolyText16 */
2819 if (length < 4) return FALSE;
2820 return TRUE; /* We don't perform many controls on this one */
2822 case 77: /* ImageText16 */
2825 case 89: /* StoreColors */
2826 return length > 2 && (length - 2) % 3 == 0;
2828 case 90: /* StoreNamedColor */
2829 return !tvb_bytes_exist(tvb, offset, 14) || length == 4 + rounded4(v16(tvb, offset + 12));
2831 case 91: /* QueryColors */
2834 case 100: /* ChangeKeyboardMapping */
2835 return !tvb_bytes_exist(tvb, offset, 6) || length == 2 + tvb_get_guint8(tvb, 1) * tvb_get_guint8(tvb, 5);
2837 case 102: /* ChangeKeyboardControl */
2838 return !tvb_bytes_exist(tvb, offset, 6) || length == 2 + numberOfBitSet(tvb, offset + 4, 2);
2840 case 114: /* RotateProperties */
2841 return !tvb_bytes_exist(tvb, offset, 10) || length == 3 + v16(tvb, offset + 8);
2843 case 116: /* SetPointerMapping */
2844 return length == 1 + rounded4(tvb_get_guint8(tvb, 1));
2846 case 118: /* SetModifierMapping */
2847 return length == 1 + tvb_get_guint8(tvb, 1) * 2;
2849 case 127: /* NoOperation */
2857 /* -1 means doesn't match, +1 means match, 0 means don't know */
2859 static int x_endian_match(tvbuff_t *tvb, guint16 (*v16)(tvbuff_t *, gint))
2861 int offset, nextoffset;
2864 for(offset = 0; tvb_bytes_exist(tvb, offset, 4); offset = nextoffset) {
2866 length = v16(tvb, offset + 2);
2867 if (!length) return -1;
2868 nextoffset = offset + length * 4;
2869 if (!consistentWithOrder(length, tvb, offset, v16)) return -1;
2876 guess_byte_ordering(tvbuff_t *tvb, packet_info *pinfo)
2878 /* With X the client gives the byte ordering for the protocol,
2879 and the port on the server tells us we're speaking X. */
2881 int le, be, decision, decisionToCache;
2883 gboolean is_reply = (pinfo->srcport == pinfo->match_port);
2884 address *addr = is_reply ? &pinfo->net_dst : &pinfo->net_src;
2885 gint32 cache = GPOINTER_TO_INT(g_tree_lookup(byte_ordering_cache, addr));
2886 if (cache) return cache > 0 ? TRUE : FALSE;
2887 if (is_reply) return TRUE; /* We don't try to guess on a reply / event for now */
2889 le = x_endian_match(tvb, tvb_get_letohs);
2890 be = x_endian_match(tvb, tvb_get_ntohs);
2892 /* remember that "decision" really means "little_endian". */
2894 /* We have no reason to believe it's little- rather than
2895 big-endian, so we guess the shortest length is the
2898 if (!tvb_bytes_exist(tvb, 0, 4))
2899 /* Not even a way to get the length. We're biased
2900 toward little endianness here (essentially the
2901 x86 world right now). Decoding won't go very far
2906 decision = tvb_get_letohs(tvb, 2) <= tvb_get_ntohs(tvb, 2);
2908 decision = le >= be;
2910 decisionToCache = (le < 0 && be > 0) || (le > 0 && be < 0);
2911 if (decisionToCache) {
2912 /* We encode the decision as 1 for TRUE and -1 for FALSE
2913 to be able to distinguish between FALSE and no value in
2914 the cache when recalling the value.
2919 if (addr -> type == AT_IPv4) {
2921 address_data = g_mem_chunk_alloc(ipv4_chunk);
2922 } else if (addr -> type == AT_IPv6) {
2923 address_length = 16;
2924 address_data = g_mem_chunk_alloc(ipv6_chunk);
2926 address_length = addr -> len;
2927 address_data = g_malloc(address_length);
2929 cached = g_mem_chunk_alloc(address_chunk);
2930 memcpy(address_data, addr -> data, address_length);
2931 SET_ADDRESS(cached, addr -> type, addr -> len, address_data);
2932 g_tree_insert(byte_ordering_cache, cached, GINT_TO_POINTER(decision ? 1 : -1));
2936 fprintf(stderr, "packet %d\tle %d\tbe %d\tlittle_endian %d\tcache %d\n",
2937 pinfo->fd -> num, le, be, decision, decisionToCache);
2942 /************************************************************************
2944 *** I N I T I A L I Z A T I O N A N D M A I N ***
2946 ************************************************************************/
2949 dissect_x11_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
2951 /* Set up structures we will need to add the protocol subtree and manage it */
2953 proto_tree *x11_tree;
2957 /* This field shows up as the "Info" column in the display; you should make
2958 it, if possible, summarize what's in the packet, so that a user looking
2959 at the list of packets can tell what type of packet it is. */
2960 if (check_col(pinfo->cinfo, COL_INFO))
2961 col_set_str(pinfo->cinfo, COL_INFO, "X11 request");
2963 /* In the interest of speed, if "tree" is NULL, don't do any work not
2964 necessary to generate protocol tree items. */
2966 ti = proto_tree_add_item(tree, proto_x11, tvb, 0, -1, FALSE);
2967 x11_tree = proto_item_add_subtree(ti, ett_x11);
2970 little_endian = guess_byte_ordering(tvb, pinfo);
2971 left = dissect_x11_request_loop(tvb, &offset, x11_tree);
2973 call_dissector(data_handle, tvb_new_subset(tvb, offset,-1, tvb_reported_length_remaining(tvb, offset)), pinfo, x11_tree);
2977 dissect_x11_event(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
2979 /* Set up structures we will need to add the protocol subtree and manage it */
2981 proto_tree *x11_tree;
2983 /* This field shows up as the "Info" column in the display; you should make
2984 it, if possible, summarize what's in the packet, so that a user looking
2985 at the list of packets can tell what type of packet it is. */
2986 if (check_col(pinfo->cinfo, COL_INFO))
2987 col_set_str(pinfo->cinfo, COL_INFO, "X11 event");
2989 /* In the interest of speed, if "tree" is NULL, don't do any work not
2990 necessary to generate protocol tree items. */
2992 ti = proto_tree_add_item(tree, proto_x11, tvb, 0, -1, FALSE);
2993 x11_tree = proto_item_add_subtree(ti, ett_x11);
2995 /* Code to process the packet goes here */
2997 call_dissector(data_handle,tvb, pinfo, x11_tree);
3002 dissect_x11(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
3004 if (check_col(pinfo->cinfo, COL_PROTOCOL))
3005 col_set_str(pinfo->cinfo, COL_PROTOCOL, "X11");
3007 if (pinfo->match_port == pinfo->destport)
3008 dissect_x11_request(tvb, pinfo, tree);
3010 dissect_x11_event(tvb, pinfo, tree);
3013 /* Register the protocol with Ethereal */
3014 void proto_register_x11(void)
3017 /* Setup list of header fields */
3018 static hf_register_info hf[] = {
3020 { &hf_x11_FIELDABBREV,
3021 { "FIELDNAME", "x11.FIELDABBREV",
3022 FIELDTYPE, FIELDBASE, FIELDCONVERT, BITMASK,
3023 "FIELDDESCR", HFILL }
3026 #include "x11-register-info.h"
3029 /* Setup protocol subtree array */
3030 static gint *ett[] = {
3033 &ett_x11_color_flags,
3034 &ett_x11_list_of_arc,
3036 &ett_x11_list_of_atom,
3037 &ett_x11_list_of_card32,
3038 &ett_x11_list_of_color_item,
3039 &ett_x11_color_item,
3040 &ett_x11_list_of_keycode,
3041 &ett_x11_list_of_keysyms,
3043 &ett_x11_list_of_point,
3045 &ett_x11_list_of_rectangle,
3047 &ett_x11_list_of_segment,
3049 &ett_x11_list_of_string8,
3050 &ett_x11_list_of_text_item,
3052 &ett_x11_gc_value_mask,
3053 &ett_x11_event_mask,
3054 &ett_x11_do_not_propagate_mask,
3055 &ett_x11_set_of_key_mask,
3056 &ett_x11_pointer_event_mask,
3057 &ett_x11_window_value_mask,
3058 &ett_x11_configure_window_mask,
3059 &ett_x11_keyboard_value_mask,
3062 /* Register the protocol name and description */
3063 proto_x11 = proto_register_protocol("X11", "X11", "x11");
3065 /* Required function calls to register the header fields and subtrees used */
3066 proto_register_field_array(proto_x11, hf, array_length(hf));
3067 proto_register_subtree_array(ett, array_length(ett));
3069 byte_ordering_cache = g_tree_new(compareAddresses);
3070 address_chunk = g_mem_chunk_new("x11 byte ordering address cache", sizeof(address),
3071 sizeof(address) * 128, G_ALLOC_ONLY);
3072 ipv4_chunk = g_mem_chunk_new("x11 byte ordering ipv4 address cache", 4, 4 * 128, G_ALLOC_ONLY);
3073 ipv6_chunk = g_mem_chunk_new("x11 byte ordering ipv6 address cache", 16, 16 * 128, G_ALLOC_ONLY);
3078 proto_reg_handoff_x11(void)
3080 dissector_handle_t x11_handle;
3082 x11_handle = create_dissector_handle(dissect_x11, proto_x11);
3083 dissector_add("tcp.port", TCP_PORT_X11, x11_handle);
3084 dissector_add("tcp.port", TCP_PORT_X11_2, x11_handle);
3085 dissector_add("tcp.port", TCP_PORT_X11_3, x11_handle);
3086 data_handle = find_dissector("data");