2 * Routines for X11 dissection
3 * Copyright 2000, Christophe Tronche <ch.tronche@computer.org>
5 * $Id: packet-x11.c,v 1.39 2002/04/15 00:10:26 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 * In case we throw an exception, clean up whatever stuff we've
1156 * allocated (if any).
1158 CLEANUP_PUSH(g_free, s);
1161 unsigned l = VALUE8(tvb, *offsetp);
1162 if (allocated < (l + 1)) {
1163 /* g_realloc doesn't work ??? */
1165 s = g_malloc(l + 1);
1168 stringCopy(s, tvb_get_ptr(tvb, *offsetp + 1, l), l); /* Nothing better for now. We need a better string handling API. */
1169 proto_tree_add_string_format(tt, hf_item, tvb, *offsetp, l + 1, s, "\"%s\"", s);
1174 * Call the cleanup handler to free the string and pop the handler.
1176 CLEANUP_CALL_AND_POP;
1179 #define STRING16_MAX_DISPLAYED_LENGTH 150
1181 static int stringIsActuallyAn8BitString(tvbuff_t *tvb, int offset, unsigned length)
1183 if (length > STRING16_MAX_DISPLAYED_LENGTH) length = STRING16_MAX_DISPLAYED_LENGTH;
1184 for(; length > 0; offset += 2, length--) {
1185 if (tvb_get_guint8(tvb, offset))
1191 /* length is the length of the _byte_zone_ (that is, twice the length of the string) */
1193 static void string16_with_buffer_preallocated(tvbuff_t *tvb, proto_tree *t,
1194 int hf, int hf_bytes,
1195 int offset, unsigned length,
1196 char **s, int *sLength)
1198 int truncated = FALSE;
1199 unsigned l = length / 2;
1201 if (stringIsActuallyAn8BitString(tvb, offset, l)) {
1203 int soffset = offset;
1205 if (l > STRING16_MAX_DISPLAYED_LENGTH) {
1207 l = STRING16_MAX_DISPLAYED_LENGTH;
1209 if (*sLength < (int) l + 3) {
1211 *s = g_malloc(l + 3);
1216 if (truncated) l -= 3;
1220 *dp++ = tvb_get_guint8(tvb, soffset);
1225 /* If truncated, add an ellipsis */
1226 if (truncated) { *dp++ = '.'; *dp++ = '.'; *dp++ = '.'; }
1229 proto_tree_add_string_format(t, hf, tvb, offset, length, tvb_get_ptr(tvb, offset, length), "%s: %s",
1230 proto_registrar_get_nth(hf) -> name, *s);
1232 proto_tree_add_item(t, hf_bytes, tvb, offset, length, little_endian);
1236 static void listOfTextItem(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
1245 /* Compute total length */
1247 int scanning_offset = *offsetp; /* Scanning pointer */
1248 int l; /* Length of an individual item */
1249 int n = 0; /* Number of items */
1251 while(scanning_offset < next_offset) {
1252 l = tvb_get_guint8(tvb, scanning_offset);
1256 scanning_offset += l == 255 ? 4 : l + (sizeIs16 ? l : 0) + 1;
1259 ti = proto_tree_add_item(t, hf, tvb, *offsetp, scanning_offset - *offsetp, little_endian);
1260 tt = proto_item_add_subtree(ti, ett_x11_list_of_text_item);
1263 * In case we throw an exception, clean up whatever stuff we've
1264 * allocated (if any).
1266 CLEANUP_PUSH(g_free, s);
1269 unsigned l = VALUE8(tvb, *offsetp);
1270 if (l == 255) { /* Item is a font */
1271 fid = tvb_get_ntohl(tvb, *offsetp + 1);
1272 proto_tree_add_uint(tt, hf_x11_textitem_font, tvb, *offsetp, 5, fid);
1274 } else { /* Item is a string */
1277 gint8 delta = VALUE8(tvb, *offsetp + 1);
1278 if (sizeIs16) l += l;
1279 if ((unsigned) allocated < l + 1) {
1280 /* g_realloc doesn't work ??? */
1282 s = g_malloc(l + 1);
1285 stringCopy(s, tvb_get_ptr(tvb, *offsetp + 2, l), l);
1286 tti = proto_tree_add_none_format(tt, hf_x11_textitem_string, tvb, *offsetp, l + 2,
1287 "textitem (string): delta = %d, \"%s\"",
1289 ttt = proto_item_add_subtree(tti, ett_x11_text_item);
1290 proto_tree_add_item(ttt, hf_x11_textitem_string_delta, tvb, *offsetp + 1, 1, little_endian);
1292 string16_with_buffer_preallocated(tvb, ttt, hf_x11_textitem_string_string16,
1293 hf_x11_textitem_string_string16_bytes,
1297 proto_tree_add_string_format(ttt, hf_x11_textitem_string_string8, tvb,
1298 *offsetp + 2, l, s, "\"%s\"", s);
1304 * Call the cleanup handler to free the string and pop the handler.
1306 CLEANUP_CALL_AND_POP;
1309 static guint32 field8(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf)
1311 guint32 v = VALUE8(tvb, *offsetp);
1312 header_field_info *hfi = proto_registrar_get_nth(hf);
1313 gchar *enumValue = NULL;
1314 gchar *nameAsChar = hfi -> name;
1317 enumValue = match_strval(v, cVALS(hfi -> strings));
1319 proto_tree_add_uint_format(t, hf, tvb, *offsetp, 1, v, "%s: %u (%s)", nameAsChar, v, enumValue);
1321 proto_tree_add_item(t, hf, tvb, *offsetp, 1, little_endian);
1326 static guint32 field16(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf)
1328 guint32 v = VALUE16(tvb, *offsetp);
1329 proto_tree_add_item(t, hf, tvb, *offsetp, 2, little_endian);
1334 static guint32 field32(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf)
1336 guint32 v = VALUE32(tvb, *offsetp);
1337 header_field_info *hfi = proto_registrar_get_nth(hf);
1338 gchar *enumValue = NULL;
1339 gchar *nameAsChar = hfi -> name;
1342 enumValue = match_strval(v, cVALS(hfi -> strings));
1344 proto_tree_add_uint_format(t, hf, tvb, *offsetp, 4, v, "%s: 0x%08x (%s)", nameAsChar, v, enumValue);
1346 proto_tree_add_uint_format(t, hf, tvb, *offsetp, 4, v,
1347 hfi -> display == BASE_DEC ? "%s: %u" : "%s: 0x%08x",
1353 static void gcAttributes(tvbuff_t *tvb, int *offsetp, proto_tree *t)
1355 BITMASK32(gc_value);
1356 BITFIELD(ENUM8, gc_value_mask, function);
1357 BITFIELD(CARD32, gc_value_mask, plane_mask);
1358 BITFIELD(CARD32, gc_value_mask, foreground);
1359 BITFIELD(CARD32, gc_value_mask, background);
1360 BITFIELD(CARD16, gc_value_mask, line_width);
1361 BITFIELD(ENUM8, gc_value_mask, line_style);
1362 BITFIELD(ENUM8, gc_value_mask, cap_style);
1363 BITFIELD(ENUM8, gc_value_mask, join_style);
1364 BITFIELD(ENUM8, gc_value_mask, fill_style);
1365 BITFIELD(ENUM8, gc_value_mask, fill_rule);
1366 BITFIELD(PIXMAP, gc_value_mask, tile);
1367 BITFIELD(PIXMAP, gc_value_mask, stipple);
1368 BITFIELD(INT16, gc_value_mask, tile_stipple_x_origin);
1369 BITFIELD(INT16, gc_value_mask, tile_stipple_y_origin);
1370 BITFIELD(FONT, gc_value_mask, font);
1371 BITFIELD(ENUM8, gc_value_mask, subwindow_mode);
1372 BITFIELD(BOOL, gc_value_mask, graphics_exposures);
1373 BITFIELD(INT16, gc_value_mask, clip_x_origin);
1374 BITFIELD(INT16, gc_value_mask, clip_y_origin);
1375 BITFIELD(PIXMAP, gc_value_mask, clip_mask);
1376 BITFIELD(CARD16, gc_value_mask, dash_offset);
1377 BITFIELD(CARD8, gc_value_mask, gc_dashes);
1378 BITFIELD(ENUM8, gc_value_mask, arc_mode);
1382 static void gcMask(tvbuff_t *tvb, int *offsetp, proto_tree *t)
1384 BITMASK32(gc_value);
1385 FLAG(gc_value, function);
1386 FLAG(gc_value, plane_mask);
1387 FLAG(gc_value, foreground);
1388 FLAG(gc_value, background);
1389 FLAG(gc_value, line_width);
1390 FLAG(gc_value, line_style);
1391 FLAG(gc_value, cap_style);
1392 FLAG(gc_value, join_style);
1393 FLAG(gc_value, fill_style);
1394 FLAG(gc_value, fill_rule);
1395 FLAG(gc_value, tile);
1396 FLAG(gc_value, stipple);
1397 FLAG(gc_value, tile_stipple_x_origin);
1398 FLAG(gc_value, tile_stipple_y_origin);
1399 FLAG(gc_value, font);
1400 FLAG(gc_value, subwindow_mode);
1401 FLAG(gc_value, graphics_exposures);
1402 FLAG(gc_value, clip_x_origin);
1403 FLAG(gc_value, clip_y_origin);
1404 FLAG(gc_value, clip_mask);
1405 FLAG(gc_value, dash_offset);
1406 FLAG(gc_value, gc_dashes);
1407 FLAG(gc_value, arc_mode);
1411 static guint32 requestLength(tvbuff_t *tvb, int *offsetp, proto_tree *t)
1413 guint32 res = VALUE16(tvb, *offsetp) * 4;
1414 proto_tree_add_uint(t, hf_x11_request_length, tvb, *offsetp, 2, res);
1419 static void setOfEvent(tvbuff_t *tvb, int *offsetp, proto_tree *t)
1422 FLAG(event, KeyPress);
1423 FLAG(event, KeyRelease);
1424 FLAG(event, ButtonPress);
1425 FLAG(event, ButtonRelease);
1426 FLAG(event, EnterWindow);
1427 FLAG(event, LeaveWindow);
1428 FLAG(event, PointerMotion);
1429 FLAG(event, PointerMotionHint);
1430 FLAG(event, Button1Motion);
1431 FLAG(event, Button2Motion);
1432 FLAG(event, Button3Motion);
1433 FLAG(event, Button4Motion);
1434 FLAG(event, Button5Motion);
1435 FLAG(event, ButtonMotion);
1436 FLAG(event, KeymapState);
1437 FLAG(event, Exposure);
1438 FLAG(event, VisibilityChange);
1439 FLAG(event, StructureNotify);
1440 FLAG(event, ResizeRedirect);
1441 FLAG(event, SubstructureNotify);
1442 FLAG(event, SubstructureRedirect);
1443 FLAG(event, FocusChange);
1444 FLAG(event, PropertyChange);
1445 FLAG(event, ColormapChange);
1446 FLAG(event, OwnerGrabButton);
1447 FLAG_IF_NONZERO(event, erroneous_bits);
1451 static void setOfDeviceEvent(tvbuff_t *tvb, int *offsetp, proto_tree *t)
1453 BITMASK32(do_not_propagate);
1454 FLAG(do_not_propagate, KeyPress);
1455 FLAG(do_not_propagate, KeyRelease);
1456 FLAG(do_not_propagate, ButtonPress);
1457 FLAG(do_not_propagate, ButtonRelease);
1458 FLAG(do_not_propagate, PointerMotion);
1459 FLAG(do_not_propagate, Button1Motion);
1460 FLAG(do_not_propagate, Button2Motion);
1461 FLAG(do_not_propagate, Button3Motion);
1462 FLAG(do_not_propagate, Button4Motion);
1463 FLAG(do_not_propagate, Button5Motion);
1464 FLAG(do_not_propagate, ButtonMotion);
1465 FLAG_IF_NONZERO(do_not_propagate, erroneous_bits);
1469 static void setOfKeyMask(tvbuff_t *tvb, int *offsetp, proto_tree *t)
1472 guint32 bitmask_value;
1475 proto_tree *bitmask_tree;
1477 bitmask_value = VALUE16(tvb, *offsetp);
1478 bitmask_offset = *offsetp;
1480 if (bitmask_value == 0x8000)
1481 proto_tree_add_uint_format(t, hf_x11_modifiers_mask_AnyModifier, tvb, *offsetp, 2, 0x8000,
1482 "modifiers-masks: 0x8000 (AnyModifier)");
1484 ti = proto_tree_add_uint(t, hf_x11_modifiers_mask, tvb, *offsetp, 2,
1486 bitmask_tree = proto_item_add_subtree(ti, ett_x11_set_of_key_mask);
1487 FLAG(modifiers, Shift);
1488 FLAG(modifiers, Lock);
1489 FLAG(modifiers, Control);
1490 FLAG(modifiers, Mod1);
1491 FLAG(modifiers, Mod2);
1492 FLAG(modifiers, Mod3);
1493 FLAG(modifiers, Mod4);
1494 FLAG(modifiers, Mod5);
1495 FLAG_IF_NONZERO(modifiers, erroneous_bits);
1500 static void setOfPointerEvent(tvbuff_t *tvb, int *offsetp, proto_tree *t)
1502 BITMASK16(pointer_event);
1503 FLAG(pointer_event, ButtonPress);
1504 FLAG(pointer_event, ButtonRelease);
1505 FLAG(pointer_event, EnterWindow);
1506 FLAG(pointer_event, LeaveWindow);
1507 FLAG(pointer_event, PointerMotion);
1508 FLAG(pointer_event, PointerMotionHint);
1509 FLAG(pointer_event, Button1Motion);
1510 FLAG(pointer_event, Button2Motion);
1511 FLAG(pointer_event, Button3Motion);
1512 FLAG(pointer_event, Button4Motion);
1513 FLAG(pointer_event, Button5Motion);
1514 FLAG(pointer_event, ButtonMotion);
1515 FLAG(pointer_event, KeymapState);
1516 FLAG_IF_NONZERO(pointer_event, erroneous_bits);
1520 static void string8(tvbuff_t *tvb, int *offsetp, proto_tree *t,
1521 const char *nameAsChar, int hf, unsigned length)
1523 char *s = g_malloc(length + 1);
1526 * In case we throw an exception, clean up whatever stuff we've
1527 * allocated (if any).
1529 CLEANUP_PUSH(g_free, s);
1531 stringCopy(s, tvb_get_ptr(tvb, *offsetp, length), length);
1532 proto_tree_add_string_format(t, hf, tvb, *offsetp, length, s, "%s: %s", nameAsChar, s);
1535 * Call the cleanup handler to free the string and pop the handler.
1537 CLEANUP_CALL_AND_POP;
1542 /* The length is the length of the _byte_zone_ (twice the length of the string) */
1544 static void string16(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf,
1545 int hf_bytes, unsigned length)
1551 * In case we throw an exception, clean up whatever stuff we've
1552 * allocated (if any).
1554 CLEANUP_PUSH(g_free, s);
1557 string16_with_buffer_preallocated(tvb, t, hf, hf_bytes, *offsetp, length, &s, &l);
1560 * Call the cleanup handler to free the string and pop the handler.
1562 CLEANUP_CALL_AND_POP;
1567 static void timestamp(tvbuff_t *tvb, int *offsetp, proto_tree *t,
1568 const char *nameAsChar, int hf)
1570 guint32 v = VALUE32(tvb, *offsetp);
1572 proto_tree_add_uint_format(t, hf, tvb, *offsetp, 4, 0, "%s: 0 (CurrentTime)", nameAsChar);
1574 proto_tree_add_uint(t, hf, tvb, *offsetp, 4, v);
1578 static void windowAttributes(tvbuff_t *tvb, int *offsetp, proto_tree *t)
1580 BITMASK32(window_value);
1581 BITFIELD(PIXMAP, window_value_mask, background_pixmap);
1582 BITFIELD(CARD32, window_value_mask, background_pixel);
1583 BITFIELD(PIXMAP, window_value_mask, border_pixmap);
1584 BITFIELD(CARD32, window_value_mask, border_pixel);
1585 BITFIELD(BITGRAVITY, window_value_mask, bit_gravity);
1586 BITFIELD(WINGRAVITY, window_value_mask, win_gravity);
1587 BITFIELD(ENUM8, window_value_mask, backing_store);
1588 BITFIELD(CARD32, window_value_mask, backing_planes);
1589 BITFIELD(CARD32, window_value_mask, backing_pixel);
1590 BITFIELD(BOOL, window_value_mask, override_redirect);
1591 BITFIELD(BOOL, window_value_mask, save_under);
1592 BITFIELD(SETofEVENT, window_value_mask, event_mask);
1593 BITFIELD(SETofDEVICEEVENT, window_value_mask, do_not_propagate_mask);
1594 BITFIELD(COLORMAP, window_value_mask, colormap);
1595 BITFIELD(CURSOR, window_value_mask, cursor);
1599 /************************************************************************
1601 *** D E C O D I N G O N E P A C K E T ***
1603 ************************************************************************/
1605 static int dissect_x11_requests_loop(tvbuff_t *tvb, int *offsetp, proto_tree *root)
1607 int left = tvb_reported_length(tvb), nextLeft;
1614 /* The X11 data stream to the server is just a sequence of requests,
1615 each of which contains a length; for now, we dissect all the
1616 requests in this frame until we run out of data in the frame.
1617 Eventually, we should handle requests that cross frame
1620 Note that "in this frame" refers to everything in the frame
1621 as it appeared in the wire, not as it was captured; we want
1622 an exception to be thrown if we go past the end of the
1623 captured data in the frame without going past the end of the
1624 data in the frame. */
1628 /* fprintf(stderr, "Starting loop, left = %d, *offsetp = %d\n", left, *offsetp); */
1630 /* We ran out of data - we don't have enough data in
1631 the frame to get the length of this request. */
1634 length = VALUE16(tvb, *offsetp + 2) * 4;
1635 /* fprintf(stderr, "length = %d\n", length);*/
1636 if (left < length) {
1637 /* We ran out of data - we don't have enough data in
1638 the frame for the full request. */
1642 /* Bogus message length? */
1646 next_offset = *offsetp + length;
1647 nextLeft = left - length;
1649 ti = proto_tree_add_uint(root, hf_x11_request, tvb, *offsetp, length, tvb_get_guint8(tvb, *offsetp));
1650 t = proto_item_add_subtree(ti, ett_x11_request);
1655 case 1: /* CreateWindow */
1664 CARD16(border_width);
1665 ENUM16(window_class);
1667 windowAttributes(tvb, offsetp, t);
1670 case 2: /* ChangeWindowAttributes */
1674 windowAttributes(tvb, offsetp, t);
1677 case 3: /* GetWindowAttributes */
1678 case 4: /* DestroyWindow */
1679 case 5: /* DestroySubwindows */
1685 case 6: /* ChangeSaveSet */
1686 ENUM8(save_set_mode);
1691 case 7: /* ReparentWindow */
1700 case 8: /* MapWindow */
1701 case 9: /* MapSubWindow */
1702 case 10: /* UnmapWindow */
1703 case 11: /* UnmapSubwindows */
1709 case 12: /* ConfigureWindow */
1713 BITMASK16(configure_window);
1715 BITFIELD(INT16, configure_window_mask, x);
1716 BITFIELD(INT16, configure_window_mask, y);
1717 BITFIELD(CARD16, configure_window_mask, width);
1718 BITFIELD(CARD16, configure_window_mask, height);
1719 BITFIELD(CARD16, configure_window_mask, border_width);
1720 BITFIELD(WINDOW, configure_window_mask, sibling);
1721 BITFIELD(ENUM8, configure_window_mask, stack_mode);
1726 case 13: /* CirculateWindow */
1732 case 14: /* GetGeometry */
1733 case 15: /* QueryTree */
1739 case 16: /* InternAtom */
1740 BOOL(only_if_exists);
1742 v16 = FIELD16(name_length);
1748 case 17: /* GetAtomName */
1754 case 18: /* ChangeProperty */
1762 v32 = CARD32(data_length);
1763 LISTofBYTE(data, v32);
1767 case 19: /* DeleteProperty */
1774 case 20: /* GetProperty */
1779 ATOM(get_property_type);
1780 CARD32(long_offset);
1781 CARD32(long_length);
1784 case 21: /* ListProperties */
1790 case 22: /* SetSelectionOwner */
1798 case 23: /* GetSelectionOwner */
1804 case 24: /* ConvertSelection */
1814 case 26: /* GrabPointer */
1817 WINDOW(grab_window);
1818 SETofPOINTEREVENT(pointer_event_mask);
1819 ENUM8(pointer_mode);
1820 ENUM8(keyboard_mode);
1826 case 27: /* UngrabPointer */
1832 case 28: /* GrabButton */
1835 WINDOW(grab_window);
1836 SETofPOINTEREVENT(event_mask);
1837 ENUM8(pointer_mode);
1838 ENUM8(keyboard_mode);
1843 SETofKEYMASK(modifiers);
1846 case 29: /* UngrabButton */
1849 WINDOW(grab_window);
1850 SETofKEYMASK(modifiers);
1854 case 30: /* ChangeActivePointerGrab */
1859 SETofPOINTEREVENT(event_mask);
1863 case 31: /* GrabKeyboard */
1866 WINDOW(grab_window);
1868 ENUM8(pointer_mode);
1869 ENUM8(keyboard_mode);
1873 case 32: /* UngrabKeyboard */
1879 case 33: /* GrabKey */
1882 WINDOW(grab_window);
1883 SETofKEYMASK(modifiers);
1885 ENUM8(pointer_mode);
1886 ENUM8(keyboard_mode);
1890 case 34: /* UngrabKey */
1893 WINDOW(grab_window);
1894 SETofKEYMASK(modifiers);
1898 case 35: /* AllowEvents */
1899 ENUM8(allow_events_mode);
1904 case 36: /* GrabServer */
1909 case 37: /* UngrabServer */
1914 case 38: /* QueryPointer */
1920 case 39: /* GetMotionEvents */
1928 case 40: /* TranslateCoordinates */
1937 case 41: /* WarpPointer */
1940 WINDOW(warp_pointer_src_window);
1941 WINDOW(warp_pointer_dst_window);
1950 case 42: /* SetInputFocus */
1957 case 43: /* GetInputFocus */
1962 case 44: /* QueryKeymap */
1967 case 45: /* OpenFont */
1971 v16 = FIELD16(name_length);
1977 case 46: /* CloseFont */
1983 case 47: /* QueryFont */
1989 case 48: /* QueryTextExtents */
1990 v8 = BOOL(odd_length);
1993 STRING16(string16, (next_offset - *offsetp - (v8 ? 2 : 0)) / 2);
1997 case 49: /* ListFonts */
2001 v16 = FIELD16(pattern_length);
2002 STRING8(pattern, v16);
2006 case 50: /* ListFontsWithInfo */
2010 v16 = FIELD16(pattern_length);
2011 STRING8(pattern, v16);
2015 case 51: /* SetFontPath */
2018 v16 = CARD16(str_number_in_path);
2020 LISTofSTRING8(path, v16);
2024 case 52: /* GetFontPath */
2029 case 53: /* CreatePixmap */
2038 case 54: /* FreePixmap */
2044 case 55: /* CreateGC */
2049 gcAttributes(tvb, offsetp, t);
2052 case 56: /* ChangeGC */
2056 gcAttributes(tvb, offsetp, t);
2059 case 57: /* CopyGC */
2064 gcMask(tvb, offsetp, t);
2067 case 58: /* SetDashes */
2071 CARD16(dash_offset);
2072 v16 = FIELD16(dashes_length);
2073 LISTofCARD8(dashes, v16);
2077 case 59: /* SetClipRectangles */
2081 INT16(clip_x_origin);
2082 INT16(clip_y_origin);
2083 LISTofRECTANGLE(rectangles);
2086 case 60: /* FreeGC */
2092 case 61: /* ClearArea */
2102 case 62: /* CopyArea */
2105 DRAWABLE(src_drawable);
2106 DRAWABLE(dst_drawable);
2116 case 63: /* CopyPlane */
2119 DRAWABLE(src_drawable);
2120 DRAWABLE(dst_drawable);
2131 case 64: /* PolyPoint */
2132 ENUM8(coordinate_mode);
2133 v16 = REQUEST_LENGTH();
2136 LISTofPOINT(points, v16 - 12);
2139 case 65: /* PolyLine */
2140 ENUM8(coordinate_mode);
2141 v16 = REQUEST_LENGTH();
2144 LISTofPOINT(points, v16 - 12);
2147 case 66: /* PolySegment */
2152 LISTofSEGMENT(segments);
2155 case 67: /* PolyRectangle */
2160 LISTofRECTANGLE(rectangles);
2163 case 68: /* PolyArc */
2171 case 69: /* FillPoly */
2173 v16 = REQUEST_LENGTH();
2177 ENUM8(coordinate_mode);
2179 LISTofPOINT(points, v16 - 16);
2182 case 70: /* PolyFillRectangle */
2187 LISTofRECTANGLE(rectangles);
2190 case 71: /* PolyFillArc */
2198 case 72: /* PutImage */
2199 ENUM8(image_format);
2200 v16 = REQUEST_LENGTH();
2210 LISTofBYTE(data, v16 - 24);
2214 case 73: /* GetImage */
2215 ENUM8(image_pixmap_format);
2225 case 74: /* PolyText8 */
2227 v16 = REQUEST_LENGTH();
2232 LISTofTEXTITEM8(items);
2236 case 75: /* PolyText16 */
2238 v16 = REQUEST_LENGTH();
2243 LISTofTEXTITEM16(items);
2247 case 76: /* ImageText8 */
2248 v8 = FIELD8(string_length);
2254 STRING8(string, v8);
2258 case 77: /* ImageText16 */
2259 v8 = FIELD8(string_length);
2265 STRING16(string16, v8);
2269 case 78: /* CreateColormap */
2277 case 79: /* FreeColormap */
2283 case 80: /* CopyColormapAndFree */
2290 case 81: /* InstallColormap */
2296 case 82: /* UninstallColormap */
2302 case 83: /* ListInstalledColormaps */
2308 case 84: /* AllocColor */
2318 case 85: /* AllocNamedColor */
2322 v16 = FIELD16(name_length);
2328 case 86: /* AllocColorCells */
2336 case 87: /* AllocColorPlanes */
2346 case 88: /* FreeColors */
2348 v16 = REQUEST_LENGTH();
2351 LISTofCARD32(pixels, v16 - 12);
2354 case 89: /* StoreColors */
2356 v16 = REQUEST_LENGTH();
2358 LISTofCOLORITEM(color_items, v16 - 8);
2361 case 90: /* StoreNamedColor */
2366 v16 = FIELD16(name_length);
2372 case 91: /* QueryColors */
2374 v16 = REQUEST_LENGTH();
2376 LISTofCARD32(pixels, v16 - 8);
2379 case 92: /* LookupColor */
2383 v16 = FIELD16(name_length);
2389 case 93: /* CreateCursor */
2393 PIXMAP(source_pixmap);
2405 case 94: /* CreateGlyphCursor */
2411 CARD16(source_char);
2421 case 95: /* FreeCursor */
2427 case 96: /* RecolorCursor */
2439 case 97: /* QueryBestSize */
2447 case 98: /* QueryExtension */
2450 v16 = FIELD16(name_length);
2456 case 99: /* ListExtensions */
2461 case 100: /* ChangeKeyboardMapping */
2462 v8 = FIELD8(keycode_count);
2464 KEYCODE(first_keycode);
2465 v8_2 = FIELD8(keysyms_per_keycode);
2467 LISTofKEYSYM(keysyms, v8, v8_2);
2470 case 101: /* GetKeyboardMapping */
2473 KEYCODE(first_keycode);
2478 case 102: /* ChangeKeyboardControl */
2481 BITMASK32(keyboard_value);
2482 BITFIELD(INT8, keyboard_value_mask, key_click_percent);
2483 BITFIELD(INT8, keyboard_value_mask, bell_percent);
2484 BITFIELD(INT16, keyboard_value_mask, bell_pitch);
2485 BITFIELD(INT16, keyboard_value_mask, bell_duration);
2486 BITFIELD(INT16, keyboard_value_mask, led);
2487 BITFIELD(ENUM8, keyboard_value_mask, led_mode);
2488 BITFIELD(KEYCODE, keyboard_value_mask, keyboard_key);
2489 BITFIELD(ENUM8, keyboard_value_mask, auto_repeat_mode);
2493 case 103: /* GetKeyboardControl */
2498 case 104: /* Bell */
2503 case 105: /* ChangePointerControl */
2506 INT16(acceleration_numerator);
2507 INT16(acceleration_denominator);
2509 BOOL(do_acceleration);
2513 case 106: /* GetPointerControl */
2518 case 107: /* SetScreenSaver */
2523 ENUM8(prefer_blanking);
2524 ENUM8(allow_exposures);
2528 case 108: /* GetScreenSaver */
2533 case 109: /* ChangeHosts */
2534 ENUM8(change_host_mode);
2538 v16 = CARD16(address_length);
2539 LISTofCARD8(address, v16);
2542 case 110: /* ListHosts */
2547 case 111: /* SetAccessControl */
2552 case 112: /* SetCloseDownMode */
2553 ENUM8(close_down_mode);
2557 case 113: /* KillClient */
2563 case 114: /* RotateProperties */
2565 v16 = REQUEST_LENGTH();
2567 CARD16(property_number);
2569 LISTofATOM(properties, (v16 - 12));
2572 case 115: /* ForceScreenSaver */
2573 ENUM8(screen_saver_mode);
2577 case 116: /* SetPointerMapping */
2578 v8 = FIELD8(map_length);
2580 LISTofCARD8(map, v8);
2584 case 117: /* GetPointerMapping */
2589 case 118: /* SetModifierMapping */
2590 v8 = FIELD8(keycodes_per_modifier);
2592 LISTofKEYCODE(keycodes, v8);
2595 case 119: /* GetModifierMapping */
2600 case 127: /* NoOperation */
2605 if (*offsetp < next_offset)
2606 proto_tree_add_item(t, hf_x11_undecoded, tvb, *offsetp, next_offset - *offsetp, little_endian);
2607 *offsetp = next_offset;
2614 /************************************************************************
2616 *** G U E S S I N G T H E B Y T E O R D E R I N G ***
2618 ************************************************************************/
2620 static GTree *byte_ordering_cache = NULL;
2621 static GMemChunk *address_chunk = NULL;
2622 static GMemChunk *ipv4_chunk = NULL;
2623 static GMemChunk *ipv6_chunk = NULL;
2625 static gint compareAddresses(gconstpointer aa, gconstpointer bb)
2627 const address *a = (const address *)aa;
2628 const address *b = (const address *)bb;
2629 int c = b -> type - a -> type;
2631 c = b -> len - a -> len;
2633 return memcmp(b -> data, a -> data, a -> len);
2636 /* If we can't guess, we return TRUE (that is little_endian), cause
2637 I'm developing on a Linux box :-). The (non-)guess isn't cached
2638 however, so we may have more luck next time. I'm quite conservative
2639 in my assertions, cause once it's cached, it's stay in cache, and
2640 we may be fooled up by a packet starting with the end of a request
2641 started in a previous packet...
2644 static int numberOfBitSetTable[] = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4 };
2646 static int numberOfBitSet(tvbuff_t *tvb, int offset, int maskLength)
2649 while(maskLength--) {
2650 int c = tvb_get_guint8(tvb, offset);
2652 res += numberOfBitSetTable[c & 0xf] + numberOfBitSetTable[c >> 4];
2657 static int listOfStringLengthConsistent(tvbuff_t *tvb, int offset, int length, int listLength)
2659 if (listLength > length) return FALSE;
2660 while(listLength--) {
2662 if (!tvb_bytes_exist(tvb, offset, 1)) return TRUE;
2663 l = tvb_get_guint8(tvb, offset);
2666 if (l > length) return FALSE;
2667 if (!tvb_bytes_exist(tvb, offset, l)) return TRUE;
2671 if (length > 3) return FALSE;
2675 static int rounded4(int n)
2677 int remainder = n % 4;
2679 if (remainder) res++;
2683 /* We assume the order to be consistent, until proven wrong. */
2685 static gboolean consistentWithOrder(int length, tvbuff_t *tvb, int offset, guint16 (*v16)(tvbuff_t *, gint))
2687 switch(tvb_get_guint8(tvb, offset)) {
2688 case 1: /* CreateWindow */
2689 return !tvb_bytes_exist(tvb, offset, 32) || length == 8 + numberOfBitSet(tvb, offset + 7 * 4, 4);
2691 case 2: /* ChangeWindowAttributes */
2692 case 56: /* ChangeGC */
2693 return !tvb_bytes_exist(tvb, offset, 12) || length == 3 + numberOfBitSet(tvb, offset + 8, 4);
2695 case 3: /* GetWindowAttributes */
2696 case 4: /* DestroyWindow */
2697 case 5: /* DestroySubwindows */
2698 case 6: /* ChangeSaveSet */
2699 case 8: /* MapWindow */
2700 case 9: /* MapSubWindow */
2701 case 10: /* UnmapWindow */
2702 case 11: /* UnmapSubwindows */
2703 case 13: /* CirculateWindow */
2704 case 14: /* GetGeometry */
2705 case 15: /* QueryTree */
2706 case 17: /* GetAtomName */
2707 case 21: /* ListProperties */
2708 case 23: /* GetSelectionOwner */
2709 case 27: /* UngrabPointer */
2710 case 32: /* UngrabKeyboard */
2711 case 35: /* AllowEvents */
2712 case 38: /* QueryPointer */
2713 case 46: /* CloseFont */
2714 case 47: /* QueryFont */
2715 case 54: /* FreePixmap */
2716 case 60: /* FreeGC */
2717 case 79: /* FreeColormap */
2718 case 81: /* InstallColormap */
2719 case 82: /* UninstallColormap */
2720 case 83: /* ListInstalledColormaps */
2721 case 95: /* FreeCursor */
2722 case 101: /* GetKeyboardMapping */
2723 case 113: /* KillClient */
2726 case 7: /* ReparentWindow */
2727 case 22: /* SetSelectionOwner */
2728 case 30: /* ChangeActivePointerGrab */
2729 case 31: /* GrabKeyboard */
2730 case 33: /* GrabKey */
2731 case 39: /* GetMotionEvents */
2732 case 40: /* TranslateCoordinates */
2733 case 53: /* CreatePixmap */
2734 case 57: /* CopyGC */
2735 case 61: /* ClearArea */
2736 case 78: /* CreateColormap */
2737 case 84: /* AllocColor */
2738 case 87: /* AllocColorPlanes */
2741 case 12: /* ConfigureWindow */
2742 return !tvb_bytes_exist(tvb, offset, 10) || length == 3 + numberOfBitSet(tvb, offset + 8, 2);
2744 case 16: /* InternAtom */
2745 case 98: /* QueryExtension */
2746 return !tvb_bytes_exist(tvb, offset, 6) || length == 2 + rounded4(v16(tvb, offset + 4));
2748 case 18: /* ChangeProperty */
2750 int multiplier, type;
2751 if (!tvb_bytes_exist(tvb, offset, 17)) return TRUE;
2752 type = tvb_get_guint8(tvb, 16);
2753 if (type != 8 && type != 16 && type != 32) return FALSE;
2754 multiplier = type == 8 ? 1 : type == 16 ? 2 : 4;
2755 if (!tvb_bytes_exist(tvb, offset, 24)) return TRUE;
2756 return length == 6 + rounded4((v16 == tvb_get_letohs ? tvb_get_letohl : tvb_get_ntohl)(tvb, offset + 20) * multiplier);
2759 case 19: /* DeleteProperty */
2760 case 29: /* UngrabButton */
2761 case 34: /* UngrabKey */
2762 case 42: /* SetInputFocus */
2763 case 80: /* CopyColormapAndFree */
2764 case 86: /* AllocColorCells */
2765 case 97: /* QueryBestSize */
2766 case 105: /* ChangePointerControl */
2767 case 107: /* SetScreenSaver */
2770 case 20: /* GetProperty */
2771 case 24: /* ConvertSelection */
2772 case 26: /* GrabPointer */
2773 case 28: /* GrabButton */
2774 case 41: /* WarpPointer */
2777 case 25: /* SendEvent */
2778 return length == 11;
2780 case 36: /* GrabServer */
2781 case 37: /* UngrabServer */
2782 case 43: /* GetInputFocus */
2783 case 44: /* QueryKeymap */
2784 case 52: /* GetFontPath */
2785 case 99: /* ListExtensions */
2786 case 103: /* GetKeyboardControl */
2787 case 104: /* Bell */
2788 case 106: /* GetPointerControl */
2789 case 108: /* GetScreenSaver */
2790 case 110: /* ListHosts */
2791 case 111: /* SetAccessControl */
2792 case 112: /* SetCloseDownMode */
2793 case 115: /* ForceScreenSaver */
2794 case 117: /* GetPointerMapping */
2795 case 119: /* GetModifierMapping */
2798 case 45: /* OpenFont */
2799 case 85: /* AllocNamedColor */
2800 case 92: /* LookupColor */
2801 return !tvb_bytes_exist(tvb, offset, 10) || length == 3 + rounded4(v16(tvb, offset + 8));
2803 case 48: /* QueryTextExtents */
2806 case 49: /* ListFonts */
2807 case 50: /* ListFontsWithInfo */
2808 case 109: /* ChangeHosts */
2809 return !tvb_bytes_exist(tvb, offset, 8) || length == 2 + rounded4(v16(tvb, offset + 6));
2811 case 51: /* SetFontPath */
2812 if (length < 2) return FALSE;
2813 if (!tvb_bytes_exist(tvb, offset, 8)) return TRUE;
2814 return listOfStringLengthConsistent(tvb, offset + 8, (length - 2) * 4, v16(tvb, offset + 4));
2816 case 55: /* CreateGC */
2817 return !tvb_bytes_exist(tvb, offset, 16) || length == 4 + numberOfBitSet(tvb, offset + 12, 4);
2819 case 58: /* SetDashes */
2820 return !tvb_bytes_exist(tvb, offset, 12) || length == 3 + rounded4(v16(tvb, offset + 10));
2822 case 59: /* SetClipRectangles */
2823 case 66: /* PolySegment */
2824 case 67: /* PolyRectangle */
2825 case 70: /* PolyFillRectangle */
2826 return length >= 3 && (length - 3) % 2 == 0;
2828 case 62: /* CopyArea */
2831 case 63: /* CopyPlane */
2832 case 93: /* CreateCursor */
2833 case 94: /* CreateGlyphCursor */
2836 case 64: /* PolyPoint */
2837 case 65: /* PolyLine */
2838 case 88: /* FreeColors */
2841 case 68: /* PolyArc */
2842 case 71: /* PolyFillArc */
2843 return length >= 3 && (length - 3) % 3 == 0;
2845 case 69: /* FillPoly */
2846 case 76: /* ImageText8 */
2849 case 72: /* PutImage */
2852 case 73: /* GetImage */
2853 case 96: /* RecolorCursor */
2856 case 74: /* PolyText8 */
2857 if (length < 4) return FALSE;
2858 return TRUE; /* We don't perform many controls on this one */
2860 case 75: /* PolyText16 */
2861 if (length < 4) return FALSE;
2862 return TRUE; /* We don't perform many controls on this one */
2864 case 77: /* ImageText16 */
2867 case 89: /* StoreColors */
2868 return length > 2 && (length - 2) % 3 == 0;
2870 case 90: /* StoreNamedColor */
2871 return !tvb_bytes_exist(tvb, offset, 14) || length == 4 + rounded4(v16(tvb, offset + 12));
2873 case 91: /* QueryColors */
2876 case 100: /* ChangeKeyboardMapping */
2877 return !tvb_bytes_exist(tvb, offset, 6) || length == 2 + tvb_get_guint8(tvb, 1) * tvb_get_guint8(tvb, 5);
2879 case 102: /* ChangeKeyboardControl */
2880 return !tvb_bytes_exist(tvb, offset, 6) || length == 2 + numberOfBitSet(tvb, offset + 4, 2);
2882 case 114: /* RotateProperties */
2883 return !tvb_bytes_exist(tvb, offset, 10) || length == 3 + v16(tvb, offset + 8);
2885 case 116: /* SetPointerMapping */
2886 return length == 1 + rounded4(tvb_get_guint8(tvb, 1));
2888 case 118: /* SetModifierMapping */
2889 return length == 1 + tvb_get_guint8(tvb, 1) * 2;
2891 case 127: /* NoOperation */
2899 /* -1 means doesn't match, +1 means match, 0 means don't know */
2901 static int x_endian_match(tvbuff_t *tvb, guint16 (*v16)(tvbuff_t *, gint))
2903 int offset, nextoffset;
2906 for(offset = 0; tvb_bytes_exist(tvb, offset, 4); offset = nextoffset) {
2908 length = v16(tvb, offset + 2);
2909 if (!length) return -1;
2910 nextoffset = offset + length * 4;
2911 if (!consistentWithOrder(length, tvb, offset, v16)) return -1;
2918 guess_byte_ordering(tvbuff_t *tvb, packet_info *pinfo)
2920 /* With X the client gives the byte ordering for the protocol,
2921 and the port on the server tells us we're speaking X. */
2923 int le, be, decision, decisionToCache;
2925 gboolean is_reply = (pinfo->srcport == pinfo->match_port);
2926 address *addr = is_reply ? &pinfo->net_dst : &pinfo->net_src;
2927 gint32 cache = GPOINTER_TO_INT(g_tree_lookup(byte_ordering_cache, addr));
2928 if (cache) return cache > 0 ? TRUE : FALSE;
2929 if (is_reply) return TRUE; /* We don't try to guess on a reply / event for now */
2931 le = x_endian_match(tvb, tvb_get_letohs);
2932 be = x_endian_match(tvb, tvb_get_ntohs);
2934 /* remember that "decision" really means "little_endian". */
2936 /* We have no reason to believe it's little- rather than
2937 big-endian, so we guess the shortest length is the
2940 if (!tvb_bytes_exist(tvb, 0, 4))
2941 /* Not even a way to get the length. We're biased
2942 toward little endianness here (essentially the
2943 x86 world right now). Decoding won't go very far
2948 decision = tvb_get_letohs(tvb, 2) <= tvb_get_ntohs(tvb, 2);
2950 decision = le >= be;
2952 decisionToCache = (le < 0 && be > 0) || (le > 0 && be < 0);
2953 if (decisionToCache) {
2954 /* We encode the decision as 1 for TRUE and -1 for FALSE
2955 to be able to distinguish between FALSE and no value in
2956 the cache when recalling the value.
2961 if (addr -> type == AT_IPv4) {
2963 address_data = g_mem_chunk_alloc(ipv4_chunk);
2964 } else if (addr -> type == AT_IPv6) {
2965 address_length = 16;
2966 address_data = g_mem_chunk_alloc(ipv6_chunk);
2968 address_length = addr -> len;
2969 address_data = g_malloc(address_length);
2971 cached = g_mem_chunk_alloc(address_chunk);
2972 memcpy(address_data, addr -> data, address_length);
2973 SET_ADDRESS(cached, addr -> type, addr -> len, address_data);
2974 g_tree_insert(byte_ordering_cache, cached, GINT_TO_POINTER(decision ? 1 : -1));
2978 fprintf(stderr, "packet %d\tle %d\tbe %d\tlittle_endian %d\tcache %d\n",
2979 pinfo->fd -> num, le, be, decision, decisionToCache);
2984 /************************************************************************
2986 *** I N I T I A L I Z A T I O N A N D M A I N ***
2988 ************************************************************************/
2991 dissect_x11_requests(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
2993 /* Set up structures we will need to add the protocol subtree and manage it */
2995 proto_tree *x11_tree;
2999 /* This field shows up as the "Info" column in the display; you should make
3000 it, if possible, summarize what's in the packet, so that a user looking
3001 at the list of packets can tell what type of packet it is. */
3002 if (check_col(pinfo->cinfo, COL_INFO))
3003 col_set_str(pinfo->cinfo, COL_INFO, "Requests");
3005 /* In the interest of speed, if "tree" is NULL, don't do any work not
3006 necessary to generate protocol tree items. */
3008 ti = proto_tree_add_item(tree, proto_x11, tvb, 0, -1, FALSE);
3009 x11_tree = proto_item_add_subtree(ti, ett_x11);
3012 little_endian = guess_byte_ordering(tvb, pinfo);
3013 left = dissect_x11_requests_loop(tvb, &offset, x11_tree);
3015 call_dissector(data_handle, tvb_new_subset(tvb, offset,-1, tvb_reported_length_remaining(tvb, offset)), pinfo, x11_tree);
3019 dissect_x11_replies(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
3021 /* Set up structures we will need to add the protocol subtree and manage it */
3023 proto_tree *x11_tree;
3025 /* This field shows up as the "Info" column in the display; you should make
3026 it, if possible, summarize what's in the packet, so that a user looking
3027 at the list of packets can tell what type of packet it is. */
3028 if (check_col(pinfo->cinfo, COL_INFO))
3029 col_set_str(pinfo->cinfo, COL_INFO, "Replies/events");
3031 /* In the interest of speed, if "tree" is NULL, don't do any work not
3032 necessary to generate protocol tree items. */
3034 ti = proto_tree_add_item(tree, proto_x11, tvb, 0, -1, FALSE);
3035 x11_tree = proto_item_add_subtree(ti, ett_x11);
3038 * XXX - dissect these in a loop, like the requests.
3040 call_dissector(data_handle,tvb, pinfo, x11_tree);
3044 dissect_x11(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
3046 if (check_col(pinfo->cinfo, COL_PROTOCOL))
3047 col_set_str(pinfo->cinfo, COL_PROTOCOL, "X11");
3049 if (pinfo->match_port == pinfo->destport)
3050 dissect_x11_requests(tvb, pinfo, tree);
3052 dissect_x11_replies(tvb, pinfo, tree);
3055 /* Register the protocol with Ethereal */
3056 void proto_register_x11(void)
3059 /* Setup list of header fields */
3060 static hf_register_info hf[] = {
3062 { &hf_x11_FIELDABBREV,
3063 { "FIELDNAME", "x11.FIELDABBREV",
3064 FIELDTYPE, FIELDBASE, FIELDCONVERT, BITMASK,
3065 "FIELDDESCR", HFILL }
3068 #include "x11-register-info.h"
3071 /* Setup protocol subtree array */
3072 static gint *ett[] = {
3075 &ett_x11_color_flags,
3076 &ett_x11_list_of_arc,
3078 &ett_x11_list_of_atom,
3079 &ett_x11_list_of_card32,
3080 &ett_x11_list_of_color_item,
3081 &ett_x11_color_item,
3082 &ett_x11_list_of_keycode,
3083 &ett_x11_list_of_keysyms,
3085 &ett_x11_list_of_point,
3087 &ett_x11_list_of_rectangle,
3089 &ett_x11_list_of_segment,
3091 &ett_x11_list_of_string8,
3092 &ett_x11_list_of_text_item,
3094 &ett_x11_gc_value_mask,
3095 &ett_x11_event_mask,
3096 &ett_x11_do_not_propagate_mask,
3097 &ett_x11_set_of_key_mask,
3098 &ett_x11_pointer_event_mask,
3099 &ett_x11_window_value_mask,
3100 &ett_x11_configure_window_mask,
3101 &ett_x11_keyboard_value_mask,
3104 /* Register the protocol name and description */
3105 proto_x11 = proto_register_protocol("X11", "X11", "x11");
3107 /* Required function calls to register the header fields and subtrees used */
3108 proto_register_field_array(proto_x11, hf, array_length(hf));
3109 proto_register_subtree_array(ett, array_length(ett));
3111 byte_ordering_cache = g_tree_new(compareAddresses);
3112 address_chunk = g_mem_chunk_new("x11 byte ordering address cache", sizeof(address),
3113 sizeof(address) * 128, G_ALLOC_ONLY);
3114 ipv4_chunk = g_mem_chunk_new("x11 byte ordering ipv4 address cache", 4, 4 * 128, G_ALLOC_ONLY);
3115 ipv6_chunk = g_mem_chunk_new("x11 byte ordering ipv6 address cache", 16, 16 * 128, G_ALLOC_ONLY);
3120 proto_reg_handoff_x11(void)
3122 dissector_handle_t x11_handle;
3124 x11_handle = create_dissector_handle(dissect_x11, proto_x11);
3125 dissector_add("tcp.port", TCP_PORT_X11, x11_handle);
3126 dissector_add("tcp.port", TCP_PORT_X11_2, x11_handle);
3127 dissector_add("tcp.port", TCP_PORT_X11_3, x11_handle);
3128 data_handle = find_dissector("data");