diff options
Diffstat (limited to 'epan/dissectors/packet-x11.c')
-rw-r--r-- | epan/dissectors/packet-x11.c | 6324 |
1 files changed, 6324 insertions, 0 deletions
diff --git a/epan/dissectors/packet-x11.c b/epan/dissectors/packet-x11.c new file mode 100644 index 00000000..c4dcf9b4 --- /dev/null +++ b/epan/dissectors/packet-x11.c @@ -0,0 +1,6324 @@ +/* packet-x11.c + * Routines for X11 dissection + * Copyright 2000, Christophe Tronche <ch.tronche@computer.org> + * Copyright 2003, Michael Shuldman + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1998 Gerald Combs + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +/* TODO (in no particular order): + * + * - keep track of Atom creation by server to be able to display + * non-predefined atoms + * - Idem for keysym <-> keycode ??? + * - Idem for fonts + * - Subtree the request ids (that is x11.create-window.window and + * x11.change-window.window should be distinct), and add hidden fields + * (so we still have x11.window). + * - add hidden fields so we can have x11.circulate-window in addition to + * x11.opcode == 13 (but you could match on x11.opcode == "CirculateWindow" + * now) + * - add hidden fields so we have x11.listOfStuff.length + * - use a faster scheme that linear list searching for the opcode. + * - correct display of Unicode chars. + * - Not everything is homogeneous, in particular the handling of items in + * list is a total mess. + */ + +/* By the way, I wrote a program to generate every request and test + * that stuff. If you're interested, you can get it at + * http://tronche.com/gui/x/ + */ + +#include "config.h" + + +#include <epan/packet.h> +#include <epan/exceptions.h> +#include <epan/conversation.h> +#include <epan/expert.h> +#include <epan/show_exception.h> +#include <epan/prefs.h> + +#include "packet-x11-keysymdef.h" +#include "packet-x11.h" + +#include <wsutil/bits_count_ones.h> + +void proto_register_x11(void); +void proto_reg_handoff_x11(void); + +static dissector_handle_t x11_handle = NULL; + +#define cVALS(x) (const value_string*)(x) + + +/* + * Data structure associated with a conversation; keeps track of the + * request for which we're expecting a reply, the frame number of + * the initial connection request, and the byte order of the connection. + * + * An opcode of -3 means we haven't yet seen any requests yet. + * An opcode of -2 means we're not expecting a reply (unused). + * An opcode of -1 means we're waiting for a reply to the initial + * connection request. + * An opcode of 0 means the request was not seen (or unknown). + * Other values are the opcode of the request for which we're expecting + * a reply. + * + */ +#define NOTHING_SEEN -3 +#define NOTHING_EXPECTED -2 +#define INITIAL_CONN -1 +#define UNKNOWN_OPCODE 0 + +#define MAX_OPCODES (255 + 1) /* 255 + INITIAL_CONN */ +#define LastExtensionError 255 +#define LastExtensionEvent 127 + +#define BYTE_ORDER_UNKNOWN 0xFFFFFFFF + +static const char *modifiers[] = { + "Shift", + "Lock", + "Control", + "Mod1", + "Mod2", + "Mod3", + "Mod4", + "Mod5" +}; + +/* Keymasks. From <X11/X.h>. */ +#define ShiftMask (1<<0) +#define LockMask (1<<1) +#define ControlMask (1<<2) +#define Mod1Mask (1<<3) +#define Mod2Mask (1<<4) +#define Mod3Mask (1<<5) +#define Mod4Mask (1<<6) +#define Mod5Mask (1<<7) + +static const int modifiermask[] = { ShiftMask, LockMask, ControlMask, +Mod1Mask, Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask }; + +/* from <X11/X.h> */ +#define NoSymbol 0L /* special KeySym */ + +typedef struct _x11_conv_data { + wmem_map_t *seqtable; /* hashtable of sequencenumber <-> opcode. */ + wmem_map_t *valtable; /* hashtable of sequencenumber <-> &opcode_vals */ + /* major opcodes including extensions (NULL terminated) */ + value_string opcode_vals[MAX_OPCODES+1]; + /* error codes including extensions (NULL terminated) */ + value_string errorcode_vals[LastExtensionError + 2]; + /* event codes including extensions (NULL terminated) */ + value_string eventcode_vals[LastExtensionEvent + 2]; + wmem_map_t *eventcode_funcs; /* hashtable of eventcode <-> dissect_event() */ + wmem_map_t *reply_funcs; /* hashtable of opcode <-> dissect_reply() */ + + int sequencenumber; /* sequencenumber of current packet. */ + guint32 iconn_frame; /* frame # of initial connection request */ + guint32 iconn_reply; /* frame # of initial connection reply */ + guint byte_order; /* byte order of connection */ + gboolean resync; /* resynchronization of sequence number performed */ + + int *keycodemap[256]; /* keycode to keysymvalue map. */ + int keysyms_per_keycode; + int first_keycode; + int *modifiermap[array_length(modifiers)];/* modifier to keycode.*/ + int keycodes_per_modifier; + + union { + struct { + int first_keycode; + } GetKeyboardMapping; + } request; +} x11_conv_data_t; + +static wmem_map_t *extension_table; /* hashtable of extension name <-> dispatch function */ +static wmem_map_t *event_table; /* hashtable of extension name <-> event info list */ +static wmem_map_t *genevent_table; /* hashtable of extension name <-> generic event info list */ +static wmem_map_t *error_table; /* hashtable of extension name <-> error list */ +static wmem_map_t *reply_table; /* hashtable of extension name <-> reply list */ + +/* Initialize the protocol and registered fields */ +static int proto_x11 = -1; + +#include "x11-declarations.h" + +/* Initialize the subtree pointers */ +static gint ett_x11 = -1; +static gint ett_x11_color_flags = -1; +static gint ett_x11_list_of_arc = -1; +static gint ett_x11_arc = -1; +static gint ett_x11_list_of_atom = -1; +static gint ett_x11_list_of_card32 = -1; +static gint ett_x11_list_of_float = -1; +static gint ett_x11_list_of_double = -1; +static gint ett_x11_list_of_color_item = -1; +static gint ett_x11_color_item = -1; +static gint ett_x11_list_of_keycode = -1; +static gint ett_x11_list_of_keysyms = -1; +static gint ett_x11_keysym = -1; +static gint ett_x11_list_of_point = -1; +static gint ett_x11_point = -1; +static gint ett_x11_list_of_rectangle = -1; +static gint ett_x11_rectangle = -1; +static gint ett_x11_list_of_segment = -1; +static gint ett_x11_segment = -1; +static gint ett_x11_list_of_string8 = -1; +static gint ett_x11_list_of_text_item = -1; +static gint ett_x11_text_item = -1; +static gint ett_x11_gc_value_mask = -1; /* XXX - unused */ +static gint ett_x11_event_mask = -1; /* XXX - unused */ +static gint ett_x11_do_not_propagate_mask = -1; /* XXX - unused */ +static gint ett_x11_set_of_key_mask = -1; +static gint ett_x11_pointer_event_mask = -1; /* XXX - unused */ +static gint ett_x11_window_value_mask = -1; /* XXX - unused */ +static gint ett_x11_configure_window_mask = -1; /* XXX - unused */ +static gint ett_x11_keyboard_value_mask = -1; /* XXX - unused */ +static gint ett_x11_same_screen_focus = -1; +static gint ett_x11_event = -1; +static gint ett_x11_list_of_pixmap_format = -1; +static gint ett_x11_pixmap_format = -1; +static gint ett_x11_list_of_screen = -1; +static gint ett_x11_screen = -1; +static gint ett_x11_list_of_depth_detail = -1; +static gint ett_x11_depth_detail = -1; +static gint ett_x11_list_of_visualtype= -1; +static gint ett_x11_visualtype= -1; + +static expert_field ei_x11_invalid_format = EI_INIT; +static expert_field ei_x11_request_length = EI_INIT; +static expert_field ei_x11_keycode_value_out_of_range = EI_INIT; + +/* desegmentation of X11 messages */ +static gboolean x11_desegment = TRUE; + +#define DEFAULT_X11_PORT_RANGE "6000-6063" + +/* + * Round a length to a multiple of 4 bytes. + */ +#define ROUND_LENGTH(n) ((((n) + 3)/4) * 4) + +/************************************************************************ + *** *** + *** E N U M T A B L E S D E F I N I T I O N S *** + *** *** + ************************************************************************/ + +static const value_string byte_order_vals[] = { + { 'B', "Big-endian" }, + { 'l', "Little-endian" }, + { 0, NULL } +}; + +static const value_string image_byte_order_vals[] = { + { 0, "LSBFirst" }, + { 1, "MSBFirst" }, + { 0, NULL } +}; + +static const value_string access_mode_vals[] = { + { 0, "Disable" }, + { 1, "Enable" }, + { 0, NULL } +}; + +static const value_string all_temporary_vals[] = { + { 0, "AllTemporary" }, + { 0, NULL } +}; + +static const value_string alloc_vals[] = { + { 0, "None" }, + { 1, "All" }, + { 0, NULL } +}; + +static const value_string allow_events_mode_vals[] = { + { 0, "AsyncPointer" }, + { 1, "SyncPointer" }, + { 2, "ReplayPointer" }, + { 3, "AsyncKeyboard" }, + { 4, "SyncKeyboard" }, + { 5, "ReplayKeyboard" }, + { 6, "AsyncBoth" }, + { 7, "SyncBoth" }, + { 0, NULL } +}; + +static const value_string arc_mode_vals[] = { + { 0, "Chord" }, + { 1, "PieSlice" }, + { 0, NULL } +}; + +static const char *atom_predefined_interpretation[] = { + "<error>", + "PRIMARY", + "SECONDARY", + "ARC", + "ATOM", + "BITMAP", + "CARDINAL", + "COLORMAP", + "CURSOR", + "CUT_BUFFER0", + "CUT_BUFFER1", + "CUT_BUFFER2", + "CUT_BUFFER3", + "CUT_BUFFER4", + "CUT_BUFFER5", + "CUT_BUFFER6", + "CUT_BUFFER7", + "DRAWABLE", + "FONT", + "INTEGER", + "PIXMAP", + "POINT", + "RECTANGLE", + "RESOURCE_MANAGER", + "RGB_COLOR_MAP", + "RGB_BEST_MAP", + "RGB_BLUE_MAP", + "RGB_DEFAULT_MAP", + "RGB_GRAY_MAP", + "RGB_GREEN_MAP", + "RGB_RED_MAP", + "STRING", + "VISUALID", + "WINDOW", + "WM_COMMAND", + "WM_HINTS", + "WM_CLIENT_MACHINE", + "WM_ICON_NAME", + "WM_ICON_SIZE", + "WM_NAME", + "WM_NORMAL_HINTS", + "WM_SIZE_HINTS", + "WM_ZOOM_HINTS", + "MIN_SPACE", + "NORM_SPACE", + "MAX_SPACE", + "END_SPACE", + "SUPERSCRIPT_X", + "SUPERSCRIPT_Y", + "SUBSCRIPT_X", + "SUBSCRIPT_Y", + "UNDERLINE_POSITION", + "UNDERLINE_THICKNESS", + "STRIKEOUT_ASCENT", + "STRIKEOUT_DESCENT", + "ITALIC_ANGLE", + "X_HEIGHT", + "QUAD_WIDTH", + "WEIGHT", + "POINT_SIZE", + "RESOLUTION", + "COPYRIGHT", + "NOTICE", + "FONT_NAME", + "FAMILY_NAME", + "FULL_NAME", + "CAP_HEIGHT", + "WM_CLASS", + "WM_TRANSIENT_FOR", +}; + +static const value_string auto_repeat_mode_vals[] = { + { 0, "Off" }, + { 1, "On" }, + { 2, "Default" }, + { 0, NULL } +}; + +static const value_string background_pixmap_vals[] = { + { 0, "None" }, + { 1, "ParentRelative" }, + { 0, NULL } +}; + +static const value_string backing_store_vals[] = { + { 0, "NotUseful" }, + { 1, "WhenMapped" }, + { 2, "Always" }, + { 0, NULL } +}; + +static const value_string border_pixmap_vals[] = { + { 0, "CopyFromParent" }, + { 0, NULL } +}; + +static const value_string button_vals[] = { + { 0x8000, "AnyButton" }, + { 0, NULL } +}; + +static const value_string cap_style_vals[] = { + { 0, "NotLast" }, + { 1, "Butt" }, + { 2, "Round" }, + { 3, "Projecting" }, + { 0, NULL } +}; + +static const value_string class_vals[] = { + { 0, "Cursor" }, + { 1, "Tile" }, + { 2, "Stipple" }, + { 0, NULL } +}; + +static const value_string close_down_mode_vals[] = { + { 0, "Destroy" }, + { 1, "RetainPermanent" }, + { 2, "RetainTemporary" }, + { 0, NULL } +}; + +static const value_string colormap_state_vals[] = { + { 0, "Uninstalled" }, + { 1, "Installed" }, + { 0, NULL } +}; + +static const value_string coordinate_mode_vals[] = { + { 0, "Origin" }, + { 1, "Previous" }, + { 0, NULL } +}; + +static const value_string destination_vals[] = { + { 0, "PointerWindow" }, + { 1, "InputFocus" }, + { 0, NULL } +}; + +static const value_string direction_vals[] = { + { 0, "RaiseLowest" }, + { 1, "LowerHighest" }, + { 0, NULL } +}; + +static const value_string event_detail_vals[] = { + { 0, "Ancestor" }, + { 1, "Virtual" }, + { 2, "Inferior" }, + { 3, "Nonlinear" }, + { 4, "NonlinearVirtual" }, + { 0, NULL } +}; + +#define FAMILY_INTERNET 0 +#define FAMILY_DECNET 1 +#define FAMILY_CHAOS 2 + +static const value_string family_vals[] = { + { FAMILY_INTERNET, "Internet" }, + { FAMILY_DECNET, "DECnet" }, + { FAMILY_CHAOS, "Chaos" }, + { 0, NULL } +}; + +static const value_string fill_rule_vals[] = { + { 0, "EvenOdd" }, + { 1, "Winding" }, + { 0, NULL } +}; + +static const value_string fill_style_vals[] = { + { 0, "Solid" }, + { 1, "Tiled" }, + { 2, "Stippled" }, + { 3, "OpaqueStippled" }, + { 0, NULL } +}; + +static const value_string focus_detail_vals[] = { + { 0, "Ancestor" }, + { 1, "Virtual" }, + { 2, "Inferior" }, + { 3, "Nonlinear" }, + { 4, "NonlinearVirtual" }, + { 5, "Pointer" }, + { 6, "PointerRoot" }, + { 7, "None" }, + { 0, NULL } +}; + +static const value_string focus_mode_vals[] = { + { 0, "Normal" }, + { 1, "Grab" }, + { 2, "Ungrab" }, + { 3, "WhileGrabbed" }, + { 0, NULL } +}; + +static const value_string focus_vals[] = { + { 0, "None" }, + { 1, "PointerRoot" }, + { 0, NULL } +}; + +static const value_string function_vals[] = { + { 0, "Clear" }, + { 1, "And" }, + { 2, "AndReverse" }, + { 3, "Copy" }, + { 4, "AndInverted" }, + { 5, "NoOp" }, + { 6, "Xor" }, + { 7, "Or" }, + { 8, "Nor" }, + { 9, "Equiv" }, + { 10, "Invert" }, + { 11, "OrReverse" }, + { 12, "CopyInverted" }, + { 13, "OrInverted" }, + { 14, "Nand" }, + { 15, "Set" }, + { 0, NULL } +}; + +static const value_string grab_mode_vals[] = { + { 0, "Normal" }, + { 1, "Grab" }, + { 2, "Ungrab" }, + { 0, NULL } +}; + +static const value_string grab_status_vals[] = { + { 0, "Success" }, + { 1, "AlreadyGrabbed" }, + { 2, "InvalidTime" }, + { 3, "NotViewable" }, + { 4, "Frozen" }, + { 0, NULL } +}; + +static const value_string bit_gravity_vals[] = { + { 0, "Forget" }, + { 1, "NorthWest" }, + { 2, "North" }, + { 3, "NorthEast" }, + { 4, "West" }, + { 5, "Center" }, + { 6, "East" }, + { 7, "SouthWest" }, + { 8, "South" }, + { 9, "SouthEast" }, + { 10, "Static" }, + { 0, NULL } +}; + +static const value_string win_gravity_vals[] = { + { 0, "Unmap" }, + { 1, "NorthWest" }, + { 2, "North" }, + { 3, "NorthEast" }, + { 4, "West" }, + { 5, "Center" }, + { 6, "East" }, + { 7, "SouthWest" }, + { 8, "South" }, + { 9, "SouthEast" }, + { 10, "Static" }, + { 0, NULL } +}; + +static const value_string image_format_vals[] = { + { 0, "Bitmap" }, + { 1, "XYPixmap" }, + { 2, "ZPixmap" }, + { 0, NULL } +}; + +static const value_string image_pixmap_format_vals[] = { + { 1, "XYPixmap" }, + { 2, "ZPixmap" }, + { 0, NULL } +}; + +static const value_string join_style_vals[] = { + { 0, "Miter" }, + { 1, "Round" }, + { 2, "Bevel" }, + { 0, NULL } +}; + +static const value_string key_vals[] = { + { 0, "AnyKey" }, + { 0, NULL } +}; + +#include "x11-keysym.h" + +static const value_string line_style_vals[] = { + { 0, "Solid" }, + { 1, "OnOffDash" }, + { 2, "DoubleDash" }, + { 0, NULL } +}; + +static const value_string mode_vals[] = { + { 0, "Replace" }, + { 1, "Prepend" }, + { 2, "Append" }, + { 0, NULL } +}; + +static const value_string on_off_vals[] = { + { 0, "Off" }, + { 1, "On" }, + { 0, NULL } +}; + +static const value_string place_vals[] = { + { 0, "Top" }, + { 1, "Bottom" }, + { 0, NULL } +}; + +static const value_string property_state_vals[] = { + { 0, "NewValue" }, + { 1, "Deleted" }, + { 0, NULL } +}; + +static const value_string visibility_state_vals[] = { + { 0, "Unobscured" }, + { 1, "PartiallyObscured" }, + { 2, "FullyObscured" }, + { 0, NULL } +}; + +static const value_string mapping_request_vals[] = { + { 0, "MappingModifier" }, + { 1, "MappingKeyboard" }, + { 2, "MappingPointer" }, + { 0, NULL } +}; + +/* Requestcodes. From <X11/Xproto.h>. */ +#define X_CreateWindow 1 +#define X_ChangeWindowAttributes 2 +#define X_GetWindowAttributes 3 +#define X_DestroyWindow 4 +#define X_DestroySubwindows 5 +#define X_ChangeSaveSet 6 +#define X_ReparentWindow 7 +#define X_MapWindow 8 +#define X_MapSubwindows 9 +#define X_UnmapWindow 10 +#define X_UnmapSubwindows 11 +#define X_ConfigureWindow 12 +#define X_CirculateWindow 13 +#define X_GetGeometry 14 +#define X_QueryTree 15 +#define X_InternAtom 16 +#define X_GetAtomName 17 +#define X_ChangeProperty 18 +#define X_DeleteProperty 19 +#define X_GetProperty 20 +#define X_ListProperties 21 +#define X_SetSelectionOwner 22 +#define X_GetSelectionOwner 23 +#define X_ConvertSelection 24 +#define X_SendEvent 25 +#define X_GrabPointer 26 +#define X_UngrabPointer 27 +#define X_GrabButton 28 +#define X_UngrabButton 29 +#define X_ChangeActivePointerGrab 30 +#define X_GrabKeyboard 31 +#define X_UngrabKeyboard 32 +#define X_GrabKey 33 +#define X_UngrabKey 34 +#define X_AllowEvents 35 +#define X_GrabServer 36 +#define X_UngrabServer 37 +#define X_QueryPointer 38 +#define X_GetMotionEvents 39 +#define X_TranslateCoords 40 +#define X_WarpPointer 41 +#define X_SetInputFocus 42 +#define X_GetInputFocus 43 +#define X_QueryKeymap 44 +#define X_OpenFont 45 +#define X_CloseFont 46 +#define X_QueryFont 47 +#define X_QueryTextExtents 48 +#define X_ListFonts 49 +#define X_ListFontsWithInfo 50 +#define X_SetFontPath 51 +#define X_GetFontPath 52 +#define X_CreatePixmap 53 +#define X_FreePixmap 54 +#define X_CreateGC 55 +#define X_ChangeGC 56 +#define X_CopyGC 57 +#define X_SetDashes 58 +#define X_SetClipRectangles 59 +#define X_FreeGC 60 +#define X_ClearArea 61 +#define X_CopyArea 62 +#define X_CopyPlane 63 +#define X_PolyPoint 64 +#define X_PolyLine 65 +#define X_PolySegment 66 +#define X_PolyRectangle 67 +#define X_PolyArc 68 +#define X_FillPoly 69 +#define X_PolyFillRectangle 70 +#define X_PolyFillArc 71 +#define X_PutImage 72 +#define X_GetImage 73 +#define X_PolyText8 74 +#define X_PolyText16 75 +#define X_ImageText8 76 +#define X_ImageText16 77 +#define X_CreateColormap 78 +#define X_FreeColormap 79 +#define X_CopyColormapAndFree 80 +#define X_InstallColormap 81 +#define X_UninstallColormap 82 +#define X_ListInstalledColormaps 83 +#define X_AllocColor 84 +#define X_AllocNamedColor 85 +#define X_AllocColorCells 86 +#define X_AllocColorPlanes 87 +#define X_FreeColors 88 +#define X_StoreColors 89 +#define X_StoreNamedColor 90 +#define X_QueryColors 91 +#define X_LookupColor 92 +#define X_CreateCursor 93 +#define X_CreateGlyphCursor 94 +#define X_FreeCursor 95 +#define X_RecolorCursor 96 +#define X_QueryBestSize 97 +#define X_QueryExtension 98 +#define X_ListExtensions 99 +#define X_ChangeKeyboardMapping 100 +#define X_GetKeyboardMapping 101 +#define X_ChangeKeyboardControl 102 +#define X_GetKeyboardControl 103 +#define X_Bell 104 +#define X_ChangePointerControl 105 +#define X_GetPointerControl 106 +#define X_SetScreenSaver 107 +#define X_GetScreenSaver 108 +#define X_ChangeHosts 109 +#define X_ListHosts 110 +#define X_SetAccessControl 111 +#define X_SetCloseDownMode 112 +#define X_KillClient 113 +#define X_RotateProperties 114 +#define X_ForceScreenSaver 115 +#define X_SetPointerMapping 116 +#define X_GetPointerMapping 117 +#define X_SetModifierMapping 118 +#define X_GetModifierMapping 119 +#define X_NoOperation 127 +#define X_FirstExtension 128 +#define X_LastExtension 255 + +static const value_string opcode_vals[] = { + { INITIAL_CONN, "Initial connection request" }, + { X_CreateWindow, "CreateWindow" }, + { X_ChangeWindowAttributes, "ChangeWindowAttributes" }, + { X_GetWindowAttributes, "GetWindowAttributes" }, + { X_DestroyWindow, "DestroyWindow" }, + { X_DestroySubwindows, "DestroySubwindows" }, + { X_ChangeSaveSet, "ChangeSaveSet" }, + { X_ReparentWindow, "ReparentWindow" }, + { X_MapWindow, "MapWindow" }, + { X_MapSubwindows, "MapSubwindows" }, + { X_UnmapWindow, "UnmapWindow" }, + { X_UnmapSubwindows, "UnmapSubwindows" }, + { X_ConfigureWindow, "ConfigureWindow" }, + { X_CirculateWindow, "CirculateWindow" }, + { X_GetGeometry, "GetGeometry" }, + { X_QueryTree, "QueryTree" }, + { X_InternAtom, "InternAtom" }, + { X_GetAtomName, "GetAtomName" }, + { X_ChangeProperty, "ChangeProperty" }, + { X_DeleteProperty, "DeleteProperty" }, + { X_GetProperty, "GetProperty" }, + { X_ListProperties, "ListProperties" }, + { X_SetSelectionOwner, "SetSelectionOwner" }, + { X_GetSelectionOwner, "GetSelectionOwner" }, + { X_ConvertSelection, "ConvertSelection" }, + { X_SendEvent, "SendEvent" }, + { X_GrabPointer, "GrabPointer" }, + { X_UngrabPointer, "UngrabPointer" }, + { X_GrabButton, "GrabButton" }, + { X_UngrabButton, "UngrabButton" }, + { X_ChangeActivePointerGrab, "ChangeActivePointerGrab" }, + { X_GrabKeyboard, "GrabKeyboard" }, + { X_UngrabKeyboard, "UngrabKeyboard" }, + { X_GrabKey, "GrabKey" }, + { X_UngrabKey, "UngrabKey" }, + { X_AllowEvents, "AllowEvents" }, + { X_GrabServer, "GrabServer" }, + { X_UngrabServer, "UngrabServer" }, + { X_QueryPointer, "QueryPointer" }, + { X_GetMotionEvents, "GetMotionEvents" }, + { X_TranslateCoords, "TranslateCoordinates" }, + { X_WarpPointer, "WarpPointer" }, + { X_SetInputFocus, "SetInputFocus" }, + { X_GetInputFocus, "GetInputFocus" }, + { X_QueryKeymap, "QueryKeymap" }, + { X_OpenFont, "OpenFont" }, + { X_CloseFont, "CloseFont" }, + { X_QueryFont, "QueryFont" }, + { X_QueryTextExtents, "QueryTextExtents" }, + { X_ListFonts, "ListFonts" }, + { X_ListFontsWithInfo, "ListFontsWithInfo" }, + { X_SetFontPath, "SetFontPath" }, + { X_GetFontPath, "GetFontPath" }, + { X_CreatePixmap, "CreatePixmap" }, + { X_FreePixmap, "FreePixmap" }, + { X_CreateGC, "CreateGC" }, + { X_ChangeGC, "ChangeGC" }, + { X_CopyGC, "CopyGC" }, + { X_SetDashes, "SetDashes" }, + { X_SetClipRectangles, "SetClipRectangles" }, + { X_FreeGC, "FreeGC" }, + { X_ClearArea, "ClearArea" }, + { X_CopyArea, "CopyArea" }, + { X_CopyPlane, "CopyPlane" }, + { X_PolyPoint, "PolyPoint" }, + { X_PolyLine, "PolyLine" }, + { X_PolySegment, "PolySegment" }, + { X_PolyRectangle, "PolyRectangle" }, + { X_PolyArc, "PolyArc" }, + { X_FillPoly, "FillPoly" }, + { X_PolyFillRectangle, "PolyFillRectangle" }, + { X_PolyFillArc, "PolyFillArc" }, + { X_PutImage, "PutImage" }, + { X_GetImage, "GetImage" }, + { X_PolyText8, "PolyText8" }, + { X_PolyText16, "PolyText16" }, + { X_ImageText8, "ImageText8" }, + { X_ImageText16, "ImageText16" }, + { X_CreateColormap, "CreateColormap" }, + { X_FreeColormap, "FreeColormap" }, + { X_CopyColormapAndFree, "CopyColormapAndFree" }, + { X_InstallColormap, "InstallColormap" }, + { X_UninstallColormap, "UninstallColormap" }, + { X_ListInstalledColormaps, "ListInstalledColormaps" }, + { X_AllocColor, "AllocColor" }, + { X_AllocNamedColor, "AllocNamedColor" }, + { X_AllocColorCells, "AllocColorCells" }, + { X_AllocColorPlanes, "AllocColorPlanes" }, + { X_FreeColors, "FreeColors" }, + { X_StoreColors, "StoreColors" }, + { X_StoreNamedColor, "StoreNamedColor" }, + { X_QueryColors, "QueryColors" }, + { X_LookupColor, "LookupColor" }, + { X_CreateCursor, "CreateCursor" }, + { X_CreateGlyphCursor, "CreateGlyphCursor" }, + { X_FreeCursor, "FreeCursor" }, + { X_RecolorCursor, "RecolorCursor" }, + { X_QueryBestSize, "QueryBestSize" }, + { X_QueryExtension, "QueryExtension" }, + { X_ListExtensions, "ListExtensions" }, + { X_ChangeKeyboardMapping, "ChangeKeyboardMapping" }, + { X_GetKeyboardMapping, "GetKeyboardMapping" }, + { X_ChangeKeyboardControl, "ChangeKeyboardControl" }, + { X_GetKeyboardControl, "GetKeyboardControl" }, + { X_Bell, "Bell" }, + { X_ChangePointerControl, "ChangePointerControl" }, + { X_GetPointerControl, "GetPointerControl" }, + { X_SetScreenSaver, "SetScreenSaver" }, + { X_GetScreenSaver, "GetScreenSaver" }, + { X_ChangeHosts, "ChangeHosts" }, + { X_ListHosts, "ListHosts" }, + { X_SetAccessControl, "SetAccessControl" }, + { X_SetCloseDownMode, "SetCloseDownMode" }, + { X_KillClient, "KillClient" }, + { X_RotateProperties, "RotateProperties" }, + { X_ForceScreenSaver, "ForceScreenSaver" }, + { X_SetPointerMapping, "SetPointerMapping" }, + { X_GetPointerMapping, "GetPointerMapping" }, + { X_SetModifierMapping, "SetModifierMapping" }, + { X_GetModifierMapping, "GetModifierMapping" }, + { X_NoOperation, "NoOperation" }, + { 0, NULL } +}; + +/* Eventscodes. From <X11/X.h>. */ +#define KeyPress 2 +#define KeyRelease 3 +#define ButtonPress 4 +#define ButtonRelease 5 +#define MotionNotify 6 +#define EnterNotify 7 +#define LeaveNotify 8 +#define FocusIn 9 +#define FocusOut 10 +#define KeymapNotify 11 +#define Expose 12 +#define GraphicsExpose 13 +#define NoExpose 14 +#define VisibilityNotify 15 +#define CreateNotify 16 +#define DestroyNotify 17 +#define UnmapNotify 18 +#define MapNotify 19 +#define MapRequest 20 +#define ReparentNotify 21 +#define ConfigureNotify 22 +#define ConfigureRequest 23 +#define GravityNotify 24 +#define ResizeRequest 25 +#define CirculateNotify 26 +#define CirculateRequest 27 +#define PropertyNotify 28 +#define SelectionClear 29 +#define SelectionRequest 30 +#define SelectionNotify 31 +#define ColormapNotify 32 +#define ClientMessage 33 +#define MappingNotify 34 +#define GenericEvent 35 + +static const value_string eventcode_vals[] = { + { KeyPress, "KeyPress" }, + { KeyRelease, "KeyRelease" }, + { ButtonPress, "ButtonPress" }, + { ButtonRelease, "ButtonRelease" }, + { MotionNotify, "MotionNotify" }, + { EnterNotify, "EnterNotify" }, + { LeaveNotify, "LeaveNotify" }, + { FocusIn, "FocusIn" }, + { FocusOut, "FocusOut" }, + { KeymapNotify, "KeymapNotify" }, + { Expose, "Expose" }, + { GraphicsExpose, "GraphicsExpose" }, + { NoExpose, "NoExpose" }, + { VisibilityNotify, "VisibilityNotify" }, + { CreateNotify, "CreateNotify" }, + { DestroyNotify, "DestroyNotify" }, + { UnmapNotify, "UnmapNotify" }, + { MapNotify, "MapNotify" }, + { MapRequest, "MapRequest" }, + { ReparentNotify, "ReparentNotify" }, + { ConfigureNotify, "ConfigureNotify" }, + { ConfigureRequest, "ConfigureRequest" }, + { GravityNotify, "GravityNotify" }, + { ResizeRequest, "ResizeRequest" }, + { CirculateNotify, "CirculateNotify" }, + { CirculateRequest, "CirculateRequest" }, + { PropertyNotify, "PropertyNotify" }, + { SelectionClear, "SelectionClear" }, + { SelectionRequest, "SelectionRequest" }, + { SelectionNotify, "SelectionNotify" }, + { ColormapNotify, "ColormapNotify" }, + { ClientMessage, "ClientMessage" }, + { MappingNotify, "MappingNotify" }, + { GenericEvent, "GenericEvent" }, + { 0, NULL } +}; + +/* Errorcodes. From <X11/X.h> */ +#define Success 0 /* everything's okay */ +#define BadRequest 1 /* bad request code */ +#define BadValue 2 /* int parameter out of range */ +#define BadWindow 3 /* parameter not a Window */ +#define BadPixmap 4 /* parameter not a Pixmap */ +#define BadAtom 5 /* parameter not an Atom */ +#define BadCursor 6 /* parameter not a Cursor */ +#define BadFont 7 /* parameter not a Font */ +#define BadMatch 8 /* parameter mismatch */ +#define BadDrawable 9 /* parameter not a Pixmap or Window */ +#define BadAccess 10 /* depending on context: + - key/button already grabbed + - attempt to free an illegal + cmap entry + - attempt to store into a read-only + color map entry. + - attempt to modify the access control + list from other than the local host. + */ +#define BadAlloc 11 /* insufficient resources */ +#define BadColormap 12 /* no such colormap */ +#define BadGC 13 /* parameter not a GC */ +#define BadIDChoice 14 /* choice not in range or already used */ +#define BadName 15 /* font or color name doesn't exist */ +#define BadLength 16 /* Request length incorrect */ +#define BadImplementation 17 /* server is defective */ + +static const value_string errorcode_vals[] = { + { Success, "Success" }, + { BadRequest, "BadRequest" }, + { BadValue, "BadValue" }, + { BadWindow, "BadWindow" }, + { BadPixmap, "BadPixmap" }, + { BadAtom, "BadAtom" }, + { BadCursor, "BadCursor" }, + { BadFont, "BadFont" }, + { BadMatch, "BadMatch" }, + { BadDrawable, "BadDrawable" }, + { BadAccess, "BadAccess" }, + { BadAlloc, "BadAlloc" }, + { BadColormap, "BadColormap" }, + { BadGC, "BadGC" }, + { BadIDChoice, "BadIDChoice" }, + { BadName, "BadName" }, + { BadLength, "BadLength" }, + { BadImplementation, "BadImplementation" }, + { 0, NULL } +}; + +static const value_string ordering_vals[] = { + { 0, "UnSorted" }, + { 1, "YSorted" }, + { 2, "YXSorted" }, + { 3, "YXBanded" }, + { 0, NULL } +}; + +static const value_string plane_mask_vals[] = { + { 0xFFFFFFFF, "AllPlanes" }, + { 0, NULL } +}; + +static const value_string pointer_keyboard_mode_vals[] = { + { 0, "Synchronous" }, + { 1, "Asynchronous" }, + { 0, NULL } +}; + +static const value_string revert_to_vals[] = { + { 0, "None" }, + { 1, "PointerRoot" }, + { 2, "Parent" }, + { 0, NULL } +}; + +static const value_string insert_delete_vals[] = { + { 0, "Insert" }, + { 1, "Delete" }, + { 0, NULL } +}; + +static const value_string screen_saver_mode_vals[] = { + { 0, "Reset" }, + { 1, "Activate" }, + { 0, NULL } +}; + +static const value_string shape_vals[] = { + { 0, "Complex" }, + { 1, "Nonconvex" }, + { 2, "Convex" }, + { 0, NULL } +}; + +static const value_string stack_mode_vals[] = { + { 0, "Above" }, + { 1, "Below" }, + { 2, "TopIf" }, + { 3, "BottomIf" }, + { 4, "Opposite" }, + { 0, NULL } +}; + +static const value_string subwindow_mode_vals[] = { + { 0, "ClipByChildren" }, + { 1, "IncludeInferiors" }, + { 0, NULL } +}; + +static const value_string window_class_vals[] = { + { 0, "CopyFromParent" }, + { 1, "InputOutput" }, + { 2, "InputOnly" }, + { 0, NULL } +}; + +static const value_string yes_no_default_vals[] = { + { 0, "No" }, + { 1, "Yes" }, + { 2, "Default" }, + { 0, NULL } +}; + +static const value_string zero_is_any_property_type_vals[] = { + { 0, "AnyPropertyType" }, + { 0, NULL } +}; + +static const value_string zero_is_none_vals[] = { + { 0, "None" }, + { 0, NULL } +}; + +/************************************************************************ + *** *** + *** F I E L D D E C O D I N G M A C R O S *** + *** *** + ************************************************************************/ +#define FIELD8(name) (field8(tvb, offsetp, t, hf_x11_##name, byte_order)) +#define FIELD16(name) (field16(tvb, offsetp, t, hf_x11_##name, byte_order)) +#define FIELD32(name) (field32(tvb, offsetp, t, hf_x11_##name, byte_order)) + +#define FLAG(position, name) {\ + proto_tree_add_boolean(bitmask_tree, hf_x11_##position##_mask##_##name, tvb, bitmask_offset, bitmask_size, bitmask_value); } + +#define FLAG_IF_NONZERO(position, name) do {\ + if (bitmask_value & proto_registrar_get_nth(hf_x11_##position##_mask##_##name) -> bitmask) \ + proto_tree_add_boolean(bitmask_tree, hf_x11_##position##_mask##_##name, tvb, bitmask_offset, bitmask_size, bitmask_value); } while (0) + +#define ATOM(name) { atom(tvb, offsetp, t, hf_x11_##name, byte_order); } +#define BOOL(name) (add_boolean(tvb, offsetp, t, hf_x11_##name)) +#define BUTTON(name) FIELD8(name) +#define CARD8(name) FIELD8(name) +#define CARD16(name) (FIELD16(name)) +#define CARD32(name) (FIELD32(name)) +#define COLOR_FLAGS(name) colorFlags(tvb, offsetp, t) +#define COLORMAP(name) FIELD32(name) +#define CURSOR(name) FIELD32(name) +#define DRAWABLE(name) FIELD32(name) +#define ENUM8(name) (FIELD8(name)) +#define ENUM16(name) (FIELD16(name)) +#define FONT(name) FIELD32(name) +#define FONTABLE(name) FIELD32(name) +#define GCONTEXT(name) FIELD32(name) +#define INT8(name) FIELD8(name) +#define INT16(name) FIELD16(name) +#define INT32(name) FIELD32(name) +#define KEYCODE(name) FIELD8(name) +#define KEYCODE_DECODED(name, keycode, mask) do { \ + proto_tree_add_uint_format(t, hf_x11_##name, tvb, offset, 1, \ + keycode, "keycode: %d (%s)", \ + keycode, keycode2keysymString(state->keycodemap, \ + state->first_keycode, state->keysyms_per_keycode, \ + state->modifiermap, state->keycodes_per_modifier, \ + keycode, mask)); \ + ++offset; \ +} while (0) +#define EVENT() do { \ + tvbuff_t *next_tvb; \ + unsigned char eventcode; \ + const char *sent; \ + proto_tree *event_proto_tree; \ + next_tvb = tvb_new_subset_length_caplen(tvb, offset, next_offset - offset, \ + next_offset - offset); \ + eventcode = tvb_get_guint8(next_tvb, 0); \ + sent = (eventcode & 0x80) ? "Sent-" : ""; \ + event_proto_tree = proto_tree_add_subtree_format(t, next_tvb, \ + 0, -1, ett_x11_event, NULL, \ + "event: %d (%s)", \ + eventcode, \ + val_to_str(eventcode & 0x7F, \ + state->eventcode_vals, \ + "<Unknown eventcode %u>")); \ + decode_x11_event(next_tvb, eventcode, sent, event_proto_tree, \ + state, byte_order); \ + offset = next_offset; \ +} while (0) + +#define LISTofARC(name) { listOfArc(tvb, offsetp, t, hf_x11_##name, (next_offset - *offsetp) / 12, byte_order); } +#define LISTofATOM(name, length) { listOfAtom(tvb, offsetp, t, hf_x11_##name, (length) / 4, byte_order); } +#define LISTofBYTE(name, length) { listOfByte(tvb, offsetp, t, hf_x11_##name, (length), byte_order); } +#define LISTofCARD8(name, length) { listOfByte(tvb, offsetp, t, hf_x11_##name, (length), byte_order); } +#define LISTofIPADDRESS(name, length) { listOfByte(tvb, offsetp, t, hf_x11_##name, (length), FALSE); } +#define LISTofCARD16(name, length) { listOfCard16(tvb, offsetp, t, hf_x11_##name, hf_x11_##name##_item, (length) / 2, byte_order); } +#define LISTofCARD32(name, length) { listOfCard32(tvb, offsetp, t, hf_x11_##name, hf_x11_##name##_item, (length) / 4, byte_order); } +#define LISTofCOLORITEM(name, length) { listOfColorItem(tvb, offsetp, t, hf_x11_##name, (length) / 12, byte_order); } +#define LISTofKEYCODE(map, name, length) { listOfKeycode(tvb, offsetp, t, hf_x11_##name, map, (length), byte_order); } +#define LISTofKEYSYM(name, map, keycode_first, keycode_count, \ + keysyms_per_keycode) {\ + listOfKeysyms(tvb, pinfo, offsetp, t, hf_x11_##name, hf_x11_##name##_item, map, (keycode_first), (keycode_count), (keysyms_per_keycode), byte_order); } +#define LISTofPOINT(name, length) { listOfPoint(tvb, offsetp, t, hf_x11_##name, (length) / 4, byte_order); } +#define LISTofRECTANGLE(name) { listOfRectangle(tvb, offsetp, t, hf_x11_##name, (next_offset - *offsetp) / 8, byte_order); } +#define LISTofPIXMAPFORMAT(name, length) { listOfPixmapFormat(tvb, offsetp, t, hf_x11_##name, (length), byte_order); } +#define LISTofSCREEN(name, length) { listOfScreen(tvb, offsetp, t, hf_x11_##name, (length), byte_order); } +#define LISTofSEGMENT(name) { listOfSegment(tvb, offsetp, t, hf_x11_##name, (next_offset - *offsetp) / 8, byte_order); } +#define LISTofSTRING8(name, length) { listOfString8(tvb, offsetp, t, hf_x11_##name, hf_x11_##name##_string, (length), byte_order); } +#define LISTofTEXTITEM8(name) { listOfTextItem(tvb, offsetp, t, hf_x11_##name, FALSE, next_offset, byte_order); } +#define LISTofTEXTITEM16(name) { listOfTextItem(tvb, offsetp, t, hf_x11_##name, TRUE, next_offset, byte_order); } +#define OPCODE() { \ + opcode = tvb_get_guint8(tvb, *offsetp); \ + proto_tree_add_uint(t, hf_x11_opcode, tvb, *offsetp, \ + 1, opcode); \ + *offsetp += 1; \ + } + +#define PIXMAP(name) { FIELD32(name); } +#define REQUEST_LENGTH() (requestLength(tvb, offsetp, t, byte_order)) +#define SETofEVENT(name) { setOfEvent(tvb, offsetp, t, byte_order); } +#define SETofDEVICEEVENT(name) { setOfDeviceEvent(tvb, offsetp, t, byte_order);} +#define SETofKEYMASK(name) { setOfKeyButMask(tvb, offsetp, t, byte_order, 0); } +#define SETofKEYBUTMASK(name) { setOfKeyButMask(tvb, offsetp, t, byte_order, 1); } +#define SETofPOINTEREVENT(name) { setOfPointerEvent(tvb, offsetp, t, byte_order); } +#define STRING8(name, length) { string8(tvb, offsetp, t, hf_x11_##name, length); } +#define STRING16(name, length) { string16(tvb, offsetp, t, hf_x11_##name, hf_x11_##name##_bytes, length, byte_order); } +#define TIMESTAMP(name){ timestamp(tvb, offsetp, t, hf_x11_##name, byte_order); } +#define UNDECODED(x) { proto_tree_add_item(t, hf_x11_undecoded, tvb, *offsetp, x, ENC_NA); *offsetp += x; } +#define PAD() { if (next_offset - *offsetp > 0) proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, next_offset - *offsetp, ENC_NA); *offsetp = next_offset; } +#define WINDOW(name) { FIELD32(name); } + +#define VISUALID(name) { gint32 v = tvb_get_guint32(tvb, *offsetp, byte_order); \ + proto_tree_add_uint_format(t, hf_x11_##name, tvb, *offsetp, 4, v, "Visualid: 0x%08x%s", v, \ + v ? "" : " (CopyFromParent)"); *offsetp += 4; } +#define REPLY(name) FIELD8(name); +#define REPLYLENGTH(name) FIELD32(name); + +#define EVENTCONTENTS_COMMON() do { \ + TIMESTAMP(time); \ + WINDOW(rootwindow); \ + WINDOW(eventwindow); \ + WINDOW(childwindow); \ + INT16(root_x); \ + INT16(root_y); \ + INT16(event_x); \ + INT16(event_y); \ + setOfKeyButMask(tvb, offsetp, t, byte_order, 1); \ +} while (0) + +#define SEQUENCENUMBER_REPLY(name) do { \ + guint16 seqno; \ + \ + seqno = tvb_get_guint16(tvb, *offsetp, byte_order); \ + proto_tree_add_uint_format(t, hf_x11_reply_##name, tvb, \ + *offsetp, 2, seqno, \ + "sequencenumber: %d (%s)", \ + (int)seqno, \ + val_to_str(opcode & 0xFF, state->opcode_vals, "<Unknown opcode %d>")); \ + *offsetp += 2; \ +} while (0) + +#define REPLYCONTENTS_COMMON() do { \ + REPLY(reply); \ + proto_tree_add_item(t, hf_x11_undecoded, tvb, *offsetp, \ + 1, ENC_NA); \ + ++(*offsetp); \ + SEQUENCENUMBER_REPLY(sequencenumber); \ + REPLYLENGTH(replylength); \ + proto_tree_add_item(t, hf_x11_undecoded, tvb, *offsetp, \ + tvb_reported_length_remaining(tvb, *offsetp), ENC_NA); \ + *offsetp += tvb_reported_length_remaining(tvb, *offsetp); \ +} while (0) + + +#define HANDLE_REPLY(plen, length_remaining, str, func) do { \ + if (length_remaining < plen) { \ + if (x11_desegment && pinfo->can_desegment) { \ + pinfo->desegment_offset = offset; \ + pinfo->desegment_len = plen - length_remaining; \ + return; \ + } else { \ + ; /* XXX yes, what then? Need to skip/join. */ \ + } \ + } \ + if (length_remaining > plen) \ + length_remaining = plen; \ + next_tvb = tvb_new_subset_length_caplen(tvb, offset, length_remaining, plen); \ + \ + if (sep == NULL) { \ + col_set_str(pinfo->cinfo, COL_INFO, str); \ + sep = ":"; \ + } \ + \ + TRY { \ + func(next_tvb, pinfo, tree, sep, state, byte_order); \ + } \ + \ + CATCH_NONFATAL_ERRORS { \ + show_exception(next_tvb, pinfo, tree, EXCEPT_CODE, GET_MESSAGE); \ + } \ + ENDTRY; \ + \ + sep = ","; \ +} while (0) + +static void +dissect_x11_initial_reply(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, + const char *sep, x11_conv_data_t *state, + guint byte_order); + +static void +dissect_x11_reply(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, + const char *sep, x11_conv_data_t *state, + guint byte_order); + +static void +dissect_x11_error(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, + const char *sep, x11_conv_data_t *state, + guint byte_order); + +static void +dissect_x11_event(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, + const char *sep, x11_conv_data_t *state, + guint byte_order); + +static void +decode_x11_event(tvbuff_t *tvb, unsigned char eventcode, const char *sent, + proto_tree *t, x11_conv_data_t *state, + guint byte_order); + +static x11_conv_data_t * +x11_stateinit(conversation_t *conversation); + +static const char * +keysymString(guint32 v); + + +/************************************************************************ + *** *** + *** D E C O D I N G F I E L D S *** + *** *** + ************************************************************************/ + +static void atom(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf, + guint byte_order) +{ + const char *interpretation = NULL; + + guint32 v = tvb_get_guint32(tvb, *offsetp, byte_order); + if (v >= 1 && v < array_length(atom_predefined_interpretation)) + interpretation = atom_predefined_interpretation[v]; + else if (v) + interpretation = "Not a predefined atom"; + else { + header_field_info *hfi = proto_registrar_get_nth(hf); + if (hfi -> strings) + interpretation = try_val_to_str(v, cVALS(hfi -> strings)); + } + if (!interpretation) interpretation = "error in Xlib client program ?"; + proto_tree_add_uint_format(t, hf, tvb, *offsetp, 4, v, "%s: %u (%s)", + proto_registrar_get_nth(hf) -> name, v, interpretation); + *offsetp += 4; +} + +static guint32 add_boolean(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf) +{ + guint32 v = tvb_get_guint8(tvb, *offsetp); + proto_tree_add_boolean(t, hf, tvb, *offsetp, 1, v); + *offsetp += 1; + return v; +} + +static void colorFlags(tvbuff_t *tvb, int *offsetp, proto_tree *t) +{ + guint do_red_green_blue = tvb_get_guint8(tvb, *offsetp); + proto_item *ti; + proto_tree *tt; + + if (do_red_green_blue) { + int sep = FALSE; + wmem_strbuf_t *buffer = wmem_strbuf_create(wmem_packet_scope()); + wmem_strbuf_append(buffer, "flags: "); + + if (do_red_green_blue & 0x1) { + wmem_strbuf_append(buffer, "DoRed"); + sep = TRUE; + } + + if (do_red_green_blue & 0x2) { + if (sep) wmem_strbuf_append(buffer, " | "); + wmem_strbuf_append(buffer, "DoGreen"); + sep = TRUE; + } + + if (do_red_green_blue & 0x4) { + if (sep) wmem_strbuf_append(buffer, " | "); + wmem_strbuf_append(buffer, "DoBlue"); + sep = TRUE; + } + + if (do_red_green_blue & 0xf8) { + if (sep) wmem_strbuf_append(buffer, " + trash"); + } + + ti = proto_tree_add_uint_format(t, hf_x11_coloritem_flags, tvb, *offsetp, 1, do_red_green_blue, + "%s", wmem_strbuf_get_str(buffer)); + tt = proto_item_add_subtree(ti, ett_x11_color_flags); + if (do_red_green_blue & 0x1) + proto_tree_add_boolean(tt, hf_x11_coloritem_flags_do_red, tvb, *offsetp, 1, + do_red_green_blue & 0x1); + if (do_red_green_blue & 0x2) + proto_tree_add_boolean(tt, hf_x11_coloritem_flags_do_green, tvb, *offsetp, 1, + do_red_green_blue & 0x2); + if (do_red_green_blue & 0x4) + proto_tree_add_boolean(tt, hf_x11_coloritem_flags_do_blue, tvb, *offsetp, 1, + do_red_green_blue & 0x4); + if (do_red_green_blue & 0xf8) + proto_tree_add_boolean(tt, hf_x11_coloritem_flags_unused, tvb, *offsetp, 1, + do_red_green_blue & 0xf8); + } else + proto_tree_add_uint_format(t, hf_x11_coloritem_flags, tvb, *offsetp, 1, do_red_green_blue, + "flags: none"); + *offsetp += 1; +} + +static void listOfArc(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf, + int length, guint byte_order) +{ + proto_item *ti = proto_tree_add_item(t, hf, tvb, *offsetp, length * 8, byte_order); + proto_tree *tt = proto_item_add_subtree(ti, ett_x11_list_of_arc); + while(length--) { + gint16 x = tvb_get_guint16(tvb, *offsetp, byte_order); + gint16 y = tvb_get_guint16(tvb, *offsetp + 2, byte_order); + guint16 width = tvb_get_guint16(tvb, *offsetp + 4, byte_order); + guint16 height = tvb_get_guint16(tvb, *offsetp + 6, byte_order); + gint16 angle1 = tvb_get_guint16(tvb, *offsetp + 8, byte_order); + gint16 angle2 = tvb_get_guint16(tvb, *offsetp + 10, byte_order); + + proto_item *tti = proto_tree_add_none_format(tt, hf_x11_arc, tvb, *offsetp, 12, + "arc: %dx%d+%d+%d, angle %d -> %d (%f degrees -> %f degrees)", + width, height, x, y, angle1, angle2, + angle1 / 64.0, angle2 / 64.0); + proto_tree *ttt = proto_item_add_subtree(tti, ett_x11_arc); + proto_tree_add_int(ttt, hf_x11_arc_x, tvb, *offsetp, 2, x); + *offsetp += 2; + proto_tree_add_int(ttt, hf_x11_arc_y, tvb, *offsetp, 2, y); + *offsetp += 2; + proto_tree_add_uint(ttt, hf_x11_arc_width, tvb, *offsetp, 2, y); + *offsetp += 2; + proto_tree_add_uint(ttt, hf_x11_arc_height, tvb, *offsetp, 2, y); + *offsetp += 2; + proto_tree_add_int(ttt, hf_x11_arc_angle1, tvb, *offsetp, 2, y); + *offsetp += 2; + proto_tree_add_int(ttt, hf_x11_arc_angle2, tvb, *offsetp, 2, y); + *offsetp += 2; + } +} + +static void listOfAtom(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf, + int length, guint byte_order) +{ + proto_item *ti = proto_tree_add_item(t, hf, tvb, *offsetp, length * 4, byte_order); + proto_tree *tt = proto_item_add_subtree(ti, ett_x11_list_of_atom); + while(length--) + atom(tvb, offsetp, tt, hf_x11_properties_item, byte_order); +} + +static void listOfByte(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf, + int length, guint byte_order) +{ + if (length <= 0) length = 1; + proto_tree_add_item(t, hf, tvb, *offsetp, length, byte_order); + *offsetp += length; +} + +static void listOfCard16(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf, + int hf_item, int length, guint byte_order) +{ + proto_item *ti = proto_tree_add_item(t, hf, tvb, *offsetp, length * 2, byte_order); + proto_tree *tt = proto_item_add_subtree(ti, ett_x11_list_of_card32); + while(length--) { + proto_tree_add_item(tt, hf_item, tvb, *offsetp, 2, byte_order); + *offsetp += 2; + } +} + +static void listOfInt16(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf, + int hf_item, int length, guint byte_order) +{ + proto_item *ti = proto_tree_add_item(t, hf, tvb, *offsetp, length * 2, byte_order); + proto_tree *tt = proto_item_add_subtree(ti, ett_x11_list_of_card32); + while(length--) { + proto_tree_add_item(tt, hf_item, tvb, *offsetp, 2, byte_order); + *offsetp += 2; + } +} + +static void listOfCard32(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf, + int hf_item, int length, guint byte_order) +{ + proto_item *ti = proto_tree_add_item(t, hf, tvb, *offsetp, length * 4, byte_order); + proto_tree *tt = proto_item_add_subtree(ti, ett_x11_list_of_card32); + while(length--) { + proto_tree_add_item(tt, hf_item, tvb, *offsetp, 4, byte_order); + *offsetp += 4; + } +} + +static void listOfInt32(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf, + int hf_item, int length, guint byte_order) +{ + proto_item *ti = proto_tree_add_item(t, hf, tvb, *offsetp, length * 4, byte_order); + proto_tree *tt = proto_item_add_subtree(ti, ett_x11_list_of_card32); + while(length--) { + proto_tree_add_item(tt, hf_item, tvb, *offsetp, 4, byte_order); + *offsetp += 4; + } +} + +static void listOfCard64(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf, + int hf_item, int length, guint byte_order) +{ + proto_item *ti = proto_tree_add_item(t, hf, tvb, *offsetp, length * 8, byte_order); + proto_tree *tt = proto_item_add_subtree(ti, ett_x11_list_of_card32); + while(length--) { + proto_tree_add_item(tt, hf_item, tvb, *offsetp, 8, byte_order); + *offsetp += 8; + } +} + +#if 0 /* Not yet used by any extension */ +static void listOfInt64(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf, + int hf_item, int length, guint byte_order) +{ + proto_item *ti = proto_tree_add_item(t, hf, tvb, *offsetp, length * 8, byte_order); + proto_tree *tt = proto_item_add_subtree(ti, ett_x11_list_of_card32); + while(length--) { + proto_tree_add_item(tt, hf_item, tvb, *offsetp, 8, byte_order); + *offsetp += 8; + } +} +#endif + +static void listOfFloat(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf, + int hf_item, int length, guint byte_order) +{ + proto_item *ti = proto_tree_add_item(t, hf, tvb, *offsetp, length * 4, byte_order); + proto_tree *tt = proto_item_add_subtree(ti, ett_x11_list_of_float); + while(length--) { + proto_tree_add_item(tt, hf_item, tvb, *offsetp, 4, byte_order); + *offsetp += 4; + } +} + +static void listOfDouble(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf, + int hf_item, int length, guint byte_order) +{ + proto_item *ti = proto_tree_add_item(t, hf, tvb, *offsetp, length * 8, byte_order); + proto_tree *tt = proto_item_add_subtree(ti, ett_x11_list_of_double); + while(length--) { + proto_tree_add_item(tt, hf_item, tvb, *offsetp, 8, byte_order); + *offsetp += 8; + } +} + +static void listOfColorItem(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf, + int length, guint byte_order) +{ + proto_item *ti = proto_tree_add_item(t, hf, tvb, *offsetp, length * 8, byte_order); + proto_tree *tt = proto_item_add_subtree(ti, ett_x11_list_of_color_item); + while(length--) { + proto_item *tti; + proto_tree *ttt; + guint do_red_green_blue; + guint16 red, green, blue; + wmem_strbuf_t *buffer; + const char *sep; + + buffer=wmem_strbuf_create(wmem_packet_scope()); + wmem_strbuf_append(buffer, "colorItem "); + red = tvb_get_guint16(tvb, *offsetp + 4, byte_order); + green = tvb_get_guint16(tvb, *offsetp + 6, byte_order); + blue = tvb_get_guint16(tvb, *offsetp + 8, byte_order); + do_red_green_blue = tvb_get_guint8(tvb, *offsetp + 10); + + sep = ""; + if (do_red_green_blue & 0x1) { + wmem_strbuf_append_printf(buffer, "red = %d", red); + sep = ", "; + } + if (do_red_green_blue & 0x2) { + wmem_strbuf_append_printf(buffer, "%sgreen = %d", sep, green); + sep = ", "; + } + if (do_red_green_blue & 0x4) + wmem_strbuf_append_printf(buffer, "%sblue = %d", sep, blue); + + tti = proto_tree_add_none_format(tt, hf_x11_coloritem, tvb, *offsetp, 12, "%s", wmem_strbuf_get_str(buffer)); + ttt = proto_item_add_subtree(tti, ett_x11_color_item); + proto_tree_add_item(ttt, hf_x11_coloritem_pixel, tvb, *offsetp, 4, byte_order); + *offsetp += 4; + proto_tree_add_item(ttt, hf_x11_coloritem_red, tvb, *offsetp, 2, byte_order); + *offsetp += 2; + proto_tree_add_item(ttt, hf_x11_coloritem_green, tvb, *offsetp, 2, byte_order); + *offsetp += 2; + proto_tree_add_item(ttt, hf_x11_coloritem_blue, tvb, *offsetp, 2, byte_order); + *offsetp += 2; + colorFlags(tvb, offsetp, ttt); + proto_tree_add_item(ttt, hf_x11_coloritem_unused, tvb, *offsetp, 1, byte_order); + *offsetp += 1; + } +} + +#if 0 /* XXX: Use of GTree no longer needed; use value_string_ext */ +static gint compareGuint32(gconstpointer a, gconstpointer b) +{ + return GPOINTER_TO_INT(b) - GPOINTER_TO_INT(a); +} +#endif + +static void +XConvertCase(register int sym, int *lower, int *upper) +{ + *lower = sym; + *upper = sym; + switch(sym >> 8) { + case 0: /* Latin 1 */ + if ((sym >= XK_A) && (sym <= XK_Z)) + *lower += (XK_a - XK_A); + else if ((sym >= XK_a) && (sym <= XK_z)) + *upper -= (XK_a - XK_A); + else if ((sym >= XK_Agrave) && (sym <= XK_Odiaeresis)) + *lower += (XK_agrave - XK_Agrave); + else if ((sym >= XK_agrave) && (sym <= XK_odiaeresis)) + *upper -= (XK_agrave - XK_Agrave); + else if ((sym >= XK_Ooblique) && (sym <= XK_Thorn)) + *lower += (XK_oslash - XK_Ooblique); + else if ((sym >= XK_oslash) && (sym <= XK_thorn)) + *upper -= (XK_oslash - XK_Ooblique); + break; + case 1: /* Latin 2 */ + /* Assume the KeySym is a legal value (ignore discontinuities) */ + if (sym == XK_Aogonek) + *lower = XK_aogonek; + else if (sym >= XK_Lstroke && sym <= XK_Sacute) + *lower += (XK_lstroke - XK_Lstroke); + else if (sym >= XK_Scaron && sym <= XK_Zacute) + *lower += (XK_scaron - XK_Scaron); + else if (sym >= XK_Zcaron && sym <= XK_Zabovedot) + *lower += (XK_zcaron - XK_Zcaron); + else if (sym == XK_aogonek) + *upper = XK_Aogonek; + else if (sym >= XK_lstroke && sym <= XK_sacute) + *upper -= (XK_lstroke - XK_Lstroke); + else if (sym >= XK_scaron && sym <= XK_zacute) + *upper -= (XK_scaron - XK_Scaron); + else if (sym >= XK_zcaron && sym <= XK_zabovedot) + *upper -= (XK_zcaron - XK_Zcaron); + else if (sym >= XK_Racute && sym <= XK_Tcedilla) + *lower += (XK_racute - XK_Racute); + else if (sym >= XK_racute && sym <= XK_tcedilla) + *upper -= (XK_racute - XK_Racute); + break; + case 2: /* Latin 3 */ + /* Assume the KeySym is a legal value (ignore discontinuities) */ + if (sym >= XK_Hstroke && sym <= XK_Hcircumflex) + *lower += (XK_hstroke - XK_Hstroke); + else if (sym >= XK_Gbreve && sym <= XK_Jcircumflex) + *lower += (XK_gbreve - XK_Gbreve); + else if (sym >= XK_hstroke && sym <= XK_hcircumflex) + *upper -= (XK_hstroke - XK_Hstroke); + else if (sym >= XK_gbreve && sym <= XK_jcircumflex) + *upper -= (XK_gbreve - XK_Gbreve); + else if (sym >= XK_Cabovedot && sym <= XK_Scircumflex) + *lower += (XK_cabovedot - XK_Cabovedot); + else if (sym >= XK_cabovedot && sym <= XK_scircumflex) + *upper -= (XK_cabovedot - XK_Cabovedot); + break; + case 3: /* Latin 4 */ + /* Assume the KeySym is a legal value (ignore discontinuities) */ + if (sym >= XK_Rcedilla && sym <= XK_Tslash) + *lower += (XK_rcedilla - XK_Rcedilla); + else if (sym >= XK_rcedilla && sym <= XK_tslash) + *upper -= (XK_rcedilla - XK_Rcedilla); + else if (sym == XK_ENG) + *lower = XK_eng; + else if (sym == XK_eng) + *upper = XK_ENG; + else if (sym >= XK_Amacron && sym <= XK_Umacron) + *lower += (XK_amacron - XK_Amacron); + else if (sym >= XK_amacron && sym <= XK_umacron) + *upper -= (XK_amacron - XK_Amacron); + break; + case 6: /* Cyrillic */ + /* Assume the KeySym is a legal value (ignore discontinuities) */ + if (sym >= XK_Serbian_DJE && sym <= XK_Serbian_DZE) + *lower -= (XK_Serbian_DJE - XK_Serbian_dje); + else if (sym >= XK_Serbian_dje && sym <= XK_Serbian_dze) + *upper += (XK_Serbian_DJE - XK_Serbian_dje); + else if (sym >= XK_Cyrillic_YU && sym <= XK_Cyrillic_HARDSIGN) + *lower -= (XK_Cyrillic_YU - XK_Cyrillic_yu); + else if (sym >= XK_Cyrillic_yu && sym <= XK_Cyrillic_hardsign) + *upper += (XK_Cyrillic_YU - XK_Cyrillic_yu); + break; + case 7: /* Greek */ + /* Assume the KeySym is a legal value (ignore discontinuities) */ + if (sym >= XK_Greek_ALPHAaccent && sym <= XK_Greek_OMEGAaccent) + *lower += (XK_Greek_alphaaccent - XK_Greek_ALPHAaccent); + else if (sym >= XK_Greek_alphaaccent && sym <= XK_Greek_omegaaccent && + sym != XK_Greek_iotaaccentdieresis && + sym != XK_Greek_upsilonaccentdieresis) + *upper -= (XK_Greek_alphaaccent - XK_Greek_ALPHAaccent); + else if (sym >= XK_Greek_ALPHA && sym <= XK_Greek_OMEGA) + *lower += (XK_Greek_alpha - XK_Greek_ALPHA); + else if (sym >= XK_Greek_alpha && sym <= XK_Greek_omega && + sym != XK_Greek_finalsmallsigma) + *upper -= (XK_Greek_alpha - XK_Greek_ALPHA); + break; + } +} + +static const char * +keycode2keysymString(int *keycodemap[256], int first_keycode, + int keysyms_per_keycode, + int *modifiermap[array_length(modifiers)], + int keycodes_per_modifier, + guint32 keycode, guint32 bitmask) +{ + int *syms; + int groupmodkc, numlockkc, numlockmod, groupmod; + int lockmod_is_capslock = 0, lockmod_is_shiftlock = 0; + int lockmod_is_nosymbol = 1; + int modifier, kc, keysym; + + if ((syms = keycodemap[keycode]) == NULL) + return "<Unknown>"; + + for (kc = first_keycode, groupmodkc = numlockkc = -1; kc < 256; ++kc) + for (keysym = 0; keysym < keysyms_per_keycode; ++keysym) { + if (keycodemap[kc] == NULL) + return "<Unknown>"; + switch (keycodemap[kc][keysym]) { + case 0xff7e: + groupmodkc = kc; + break; + + case 0xff7f: + numlockkc = kc; + break; + + case 0xffe5: + lockmod_is_capslock = kc; + break; + + case 0xffe6: + lockmod_is_shiftlock = kc; + break; + } + } + + + /* + * If we have not seen the modifiermap we don't know what the + * keycode translates to, but we do know it's one of the keys + * in syms (give or take a case-conversion), so we could in + * theory list them all. + */ + if (modifiermap[array_length(modifiers) - 1] == NULL) /* all or none */ + return "<Unknown>"; + + /* find out what the numlockmodifer and groupmodifier is. */ + for (modifier = 0, numlockmod = groupmod = -1; + modifier < (int)array_length(modifiers) && numlockmod == -1; + ++modifier) + for (kc = 0; kc < keycodes_per_modifier; ++kc) + if (modifiermap[modifier][kc] == numlockkc) + numlockmod = modifier; + else if (modifiermap[modifier][kc] == groupmodkc) + groupmod = modifier; + + /* + * ... and what the lockmodifier is interpreted as. + * (X11v4r6 ref, keyboard and pointers section.) + */ + for (kc = 0; kc < keycodes_per_modifier; ++kc) + if (modifiermap[1][kc] == lockmod_is_capslock) { + lockmod_is_shiftlock = lockmod_is_nosymbol = 0; + break; + } + else if (modifiermap[0][kc] == lockmod_is_shiftlock) { + lockmod_is_capslock = lockmod_is_nosymbol = 0; + break; + } + +#if 0 + /* + * This is (how I understand) the X11v4R6 protocol description given + * in A. Nye's book. It is quite different from the + * code in _XTranslateKey() in the file + * "$XConsortium: KeyBind.c /main/55 1996/02/02 14:08:55 kaleb $" + * as shipped with XFree, and doesn't work correctly, nor do I see + * how it could (e.g. the case of lower/uppercase-letters). + * -- Michael Shuldman + */ + + if (numlockmod >= 0 && (bitmask & modifiermask[numlockmod]) + && ((syms[1] >= 0xff80 + && syms[1] <= 0xffbd) + || (syms[1] >= 0x11000000 + && syms[1] <= 0x1100ffff))) { + if ((bitmask & ShiftMask) || lockmod_is_shiftlock) + return keysymString(syms[groupmod + 0]); + else + if (syms[groupmod + 1] == NoSymbol) + return keysymString(syms[groupmod + 0]); + else + return keysymString(syms[groupmod + 1]); + } + else if (!(bitmask & ShiftMask) && !(bitmask & LockMask)) + return keysymString(syms[groupmod + 0]); + else if (!(bitmask & ShiftMask) + && ((bitmask & LockMask) && lockmod_is_capslock)) + if (islower(syms[groupmod + 0])) +/* return toupper(keysymString(syms[groupmod + 0])); */ + return "Uppercase"; /* XXX */ + else + return keysymString(syms[groupmod + 0]); + + else if ((bitmask & ShiftMask) + && ((bitmask & LockMask) && lockmod_is_capslock)) + if (islower(syms[groupmod + 1])) +/* return toupper(keysymString(syms[groupmod + 1])); */ + return "Uppercase"; /* XXX */ + else + return keysymString(syms[groupmod + 1]); + + else if ((bitmask & ShiftMask) + || ((bitmask & LockMask) && lockmod_is_shiftlock)) + return keysymString(syms[groupmod + 1]); +#else /* _XTranslateKey() based code. */ + + while (keysyms_per_keycode > 2 + && keycodemap[keysyms_per_keycode - 1] == NoSymbol) + --keysyms_per_keycode; + if (keysyms_per_keycode > 2 + && (groupmod >= 0 && (modifiermask[groupmod] & bitmask))) { + syms += 2; + keysyms_per_keycode -= 2; + } + + if (numlockmod >= 0 && (bitmask & modifiermask[numlockmod]) + && keysyms_per_keycode > 1 + && ((syms[1] >= 0xff80 && syms[1] <= 0xffbd) + || (syms[1] >= 0x11000000 && syms[1] <= 0x1100ffff))) { + if ((bitmask & ShiftMask) + || (bitmask & LockMask && lockmod_is_shiftlock)) + keysym = syms[0]; + else + keysym = syms[1]; + } + else if (!(bitmask & ShiftMask) + && (!(bitmask & LockMask) || lockmod_is_nosymbol)) { + if (keysyms_per_keycode == 1 + || (keysyms_per_keycode > 1 && syms[1] == NoSymbol)) { + int usym; + + XConvertCase(syms[0], &keysym, &usym); + } + else + keysym = syms[0]; + } + else if (!(bitmask & LockMask) || !lockmod_is_capslock) { + int lsym, usym = 0; + + if (keysyms_per_keycode == 1 + || (keysyms_per_keycode > 1 && (usym = syms[1]) == NoSymbol)) + XConvertCase(syms[0], &lsym, &usym); + keysym = usym; + } + else { + int lsym, usym = 0; + + if (keysyms_per_keycode == 1 + || (keysyms_per_keycode > 1 && syms[1] == NoSymbol)) + keysym = syms[0]; + + XConvertCase(keysym, &lsym, &usym); + + if (!(bitmask & ShiftMask) && keysym != syms[0] + && ((keysym != usym) || (lsym == usym))) + XConvertCase(syms[0], &lsym, &usym); + keysym = usym; + } + + if (keysym == XK_VoidSymbol) + keysym = NoSymbol; + + return wmem_strdup_printf(wmem_packet_scope(), "%d, \"%s\"", keysym, keysymString(keysym)); +#endif +} + +static const char *keysymString(guint32 v) +{ +#if 0 /* XXX: Use of GTree no longer needed; use value_string_ext */ + static GTree *keysymTable = NULL; + + gpointer res; + if (!keysymTable) { + + /* This table is so big that we built it only if necessary */ + const value_string *p = x11_keysym_vals_source; + keysymTable = g_tree_new(compareGuint32); + for(; p -> strptr; p++) + g_tree_insert(keysymTable, GINT_TO_POINTER(p -> value), (gpointer) (p -> strptr) ); + } + res = g_tree_lookup(keysymTable, GINT_TO_POINTER(v)); + return res ? res : "<Unknown>"; +#endif + + return val_to_str_ext_const(v, &x11_keysym_vals_source_ext, "<Unknown>"); + +} + +static void listOfKeycode(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf, + int *modifiermap[], int keycodes_per_modifier, + guint byte_order _U_) +{ + proto_item *ti = proto_tree_add_item(t, hf, tvb, *offsetp, + (int)array_length(modifiers) * keycodes_per_modifier, ENC_NA); + proto_tree *tt = proto_item_add_subtree(ti, ett_x11_list_of_keycode); + size_t m; + + for (m = 0; m < array_length(modifiers); + ++m, *offsetp += keycodes_per_modifier) { + proto_item *tikc; + int i; + + tikc = proto_tree_add_bytes_format(tt, hf_x11_keycodes_item, tvb, + *offsetp, keycodes_per_modifier, NULL, "item: "); + modifiermap[m] = (int *) + wmem_alloc(wmem_file_scope(), sizeof(*modifiermap[m]) * keycodes_per_modifier); + for(i = 0; i < keycodes_per_modifier; ++i) { + guchar c = tvb_get_guint8(tvb, (*offsetp) + i); + + if (c) + proto_item_append_text(tikc, " %s=%d", modifiers[m], c); + + modifiermap[m][i] = c; + } + } +} + +static void listOfKeysyms(tvbuff_t *tvb, packet_info *pinfo, int *offsetp, proto_tree *t, int hf, + int hf_item, int *keycodemap[256], + int keycode_first, int keycode_count, + int keysyms_per_keycode, guint byte_order) +{ + proto_item *ti = proto_tree_add_item(t, hf, tvb, *offsetp, keycode_count * keysyms_per_keycode * 4, byte_order); + proto_tree *tt = proto_item_add_subtree(ti, ett_x11_list_of_keysyms); + proto_item *tti; + proto_tree *ttt; + int i, keycode; + + DISSECTOR_ASSERT(keycode_first >= 0); + DISSECTOR_ASSERT(keycode_count >= 0); + + for (keycode = keycode_first; keycode_count > 0; + ++keycode, --keycode_count) { + tti = proto_tree_add_none_format(tt, hf_item, tvb, *offsetp, + 4 * keysyms_per_keycode, "keysyms (keycode %d):", keycode); + if (keycode >= 256) { + expert_add_info_format(pinfo, tti, &ei_x11_keycode_value_out_of_range, + "keycode value %d is out of range", keycode); + *offsetp += 4 * keysyms_per_keycode; + continue; + } + + ttt = proto_item_add_subtree(tti, ett_x11_keysym); + + tvb_ensure_bytes_exist(tvb, *offsetp, 4 * keysyms_per_keycode); + keycodemap[keycode] + = (int *)wmem_alloc(wmem_file_scope(), sizeof(*keycodemap[keycode]) * keysyms_per_keycode); + + for(i = 0; i < keysyms_per_keycode; ++i) { + /* keysymvalue = byte3 * 256 + byte4. */ + guint32 v = tvb_get_guint32(tvb, *offsetp, byte_order); + + proto_item_append_text(tti, " %s", keysymString(v)); + proto_tree_add_uint_format(ttt, hf_x11_keysyms_item_keysym, + tvb, *offsetp, 4, v, + "keysym (keycode %d): 0x%08x (%s)", + keycode, v, keysymString(v)); + + keycodemap[keycode][i] = v; + *offsetp += 4; + } + + for (i = 1; i < keysyms_per_keycode; ++i) + if (keycodemap[keycode][i] != NoSymbol) + break; + + if (i == keysyms_per_keycode) { + /* all but (possibly) first were NoSymbol. */ + if (keysyms_per_keycode == 4) { + keycodemap[keycode][1] = NoSymbol; + keycodemap[keycode][2] = keycodemap[keycode][0]; + keycodemap[keycode][3] = NoSymbol; + } + + continue; + } + + for (i = 2; i < keysyms_per_keycode; ++i) + if (keycodemap[keycode][i] != NoSymbol) + break; + if (i == keysyms_per_keycode) { + /* all but (possibly) first two were NoSymbol. */ + if (keysyms_per_keycode == 4) { + keycodemap[keycode][2] = keycodemap[keycode][0]; + keycodemap[keycode][3] = keycodemap[keycode][1]; + } + + continue; + } + } +} + +static void listOfPoint(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf, + int length, guint byte_order) +{ + proto_item *ti = proto_tree_add_item(t, hf, tvb, *offsetp, length * 4, byte_order); + proto_tree *tt = proto_item_add_subtree(ti, ett_x11_list_of_point); + while(length--) { + gint16 x, y; + proto_item *tti; + proto_tree *ttt; + + x = tvb_get_guint16(tvb, *offsetp, byte_order); + y = tvb_get_guint16(tvb, *offsetp + 2, byte_order); + + tti = proto_tree_add_none_format(tt, hf_x11_point, tvb, *offsetp, 4, "point: (%d,%d)", x, y); + ttt = proto_item_add_subtree(tti, ett_x11_point); + proto_tree_add_int(ttt, hf_x11_point_x, tvb, *offsetp, 2, x); + *offsetp += 2; + proto_tree_add_int(ttt, hf_x11_point_y, tvb, *offsetp, 2, y); + *offsetp += 2; + } +} + +static void listOfRectangle(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf, + int length, guint byte_order) +{ + proto_item *ti = proto_tree_add_item(t, hf, tvb, *offsetp, length * 8, byte_order); + proto_tree *tt = proto_item_add_subtree(ti, ett_x11_list_of_rectangle); + while(length--) { + gint16 x, y; + guint width, height; + proto_item *tti; + proto_tree *ttt; + + x = tvb_get_guint16(tvb, *offsetp, byte_order); + y = tvb_get_guint16(tvb, *offsetp + 2, byte_order); + width = tvb_get_guint16(tvb, *offsetp + 4, byte_order); + height = tvb_get_guint16(tvb, *offsetp + 6, byte_order); + + tti = proto_tree_add_none_format(tt, hf_x11_rectangle, tvb, *offsetp, 8, + "rectangle: %dx%d+%d+%d", width, height, x, y); + ttt = proto_item_add_subtree(tti, ett_x11_rectangle); + proto_tree_add_int(ttt, hf_x11_rectangle_x, tvb, *offsetp, 2, x); + *offsetp += 2; + proto_tree_add_int(ttt, hf_x11_rectangle_y, tvb, *offsetp, 2, y); + *offsetp += 2; + proto_tree_add_uint(ttt, hf_x11_rectangle_width, tvb, *offsetp, 2, width); + *offsetp += 2; + proto_tree_add_uint(ttt, hf_x11_rectangle_height, tvb, *offsetp, 2, height); + *offsetp += 2; + } +} + +static void listOfSegment(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf, + int length, guint byte_order) +{ + proto_item *ti = proto_tree_add_item(t, hf, tvb, *offsetp, length * 8, byte_order); + proto_tree *tt = proto_item_add_subtree(ti, ett_x11_list_of_segment); + while(length--) { + gint16 x1, y1, x2, y2; + proto_item *tti; + proto_tree *ttt; + + x1 = tvb_get_guint16(tvb, *offsetp, byte_order); + y1 = tvb_get_guint16(tvb, *offsetp + 2, byte_order); + x2 = tvb_get_guint16(tvb, *offsetp + 4, byte_order); + y2 = tvb_get_guint16(tvb, *offsetp + 6, byte_order); + + tti = proto_tree_add_none_format(tt, hf_x11_segment, tvb, *offsetp, 8, + "segment: (%d,%d)-(%d,%d)", x1, y1, x2, y2); + ttt = proto_item_add_subtree(tti, ett_x11_segment); + proto_tree_add_item(ttt, hf_x11_segment_x1, tvb, *offsetp, 2, byte_order); + *offsetp += 2; + proto_tree_add_item(ttt, hf_x11_segment_y1, tvb, *offsetp, 2, byte_order); + *offsetp += 2; + proto_tree_add_item(ttt, hf_x11_segment_x2, tvb, *offsetp, 2, byte_order); + *offsetp += 2; + proto_tree_add_item(ttt, hf_x11_segment_y2, tvb, *offsetp, 2, byte_order); + *offsetp += 2; + } +} + +static void listOfVisualTypes(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf, + int length, guint byte_order) +{ + proto_item *ti = proto_tree_add_item(t, hf, tvb, *offsetp, length * 24, byte_order); + proto_tree *tt = proto_item_add_subtree(ti, ett_x11_list_of_visualtype); + while(length--) { + proto_item *tti; + proto_tree *ttt; + + tti = proto_tree_add_none_format(tt, hf_x11_visualtype, tvb, *offsetp, 24, + "visualtype"); + ttt = proto_item_add_subtree(tti, ett_x11_visualtype); + proto_tree_add_item(ttt, hf_x11_visualtype_visualid, tvb, *offsetp, 4, byte_order); + *offsetp += 4; + proto_tree_add_item(ttt, hf_x11_visualtype_class, tvb, *offsetp, 1, byte_order); + *offsetp += 1; + proto_tree_add_item(ttt, hf_x11_visualtype_bits_per_rgb_value, tvb, *offsetp, 1, byte_order); + *offsetp += 1; + proto_tree_add_item(ttt, hf_x11_visualtype_colormap_entries, tvb, *offsetp, 2, byte_order); + *offsetp += 2; + proto_tree_add_item(ttt, hf_x11_visualtype_red_mask, tvb, *offsetp, 4, byte_order); + *offsetp += 4; + proto_tree_add_item(ttt, hf_x11_visualtype_green_mask, tvb, *offsetp, 4, byte_order); + *offsetp += 4; + proto_tree_add_item(ttt, hf_x11_visualtype_blue_mask, tvb, *offsetp, 4, byte_order); + *offsetp += 4; + proto_tree_add_item(ttt, hf_x11_unused, tvb, *offsetp, 4, byte_order); + *offsetp += 4; + } +} +static void listOfDepth(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf, + int length, guint byte_order) +{ + guint16 number_of_visualtypes; + proto_item *ti; + proto_tree *tt; + + ti = proto_tree_add_item(t, hf, tvb, *offsetp, -1, byte_order); + tt = proto_item_add_subtree(ti, ett_x11_list_of_depth_detail); + while(length--) { + proto_item *tti; + proto_tree *ttt; + number_of_visualtypes = tvb_get_guint16(tvb, *offsetp + 2, byte_order); + + tti = proto_tree_add_none_format(tt, hf_x11_depth_detail, tvb, *offsetp, 8 + 24 * number_of_visualtypes, + "depth-detail"); + ttt = proto_item_add_subtree(tti, ett_x11_screen); + proto_tree_add_item(ttt, hf_x11_depth_detail_depth, tvb, *offsetp, 1, byte_order); + *offsetp += 1; + proto_tree_add_item(ttt, hf_x11_unused, tvb, *offsetp, 1, byte_order); + *offsetp += 1; + proto_tree_add_item(ttt, hf_x11_depth_detail_visualtypes_numbers, tvb, *offsetp, 2, byte_order); + *offsetp += 2; + proto_tree_add_item(ttt, hf_x11_unused, tvb, *offsetp, 4, byte_order); + *offsetp += 4; + if (number_of_visualtypes > 0) + listOfVisualTypes(tvb, offsetp, ttt, hf_x11_visualtype, number_of_visualtypes, byte_order); + } +} + +static void listOfScreen(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf, + int length, guint byte_order) +{ + proto_item *ti = proto_tree_add_item(t, hf, tvb, *offsetp, -1, byte_order); + proto_tree *tt = proto_item_add_subtree(ti, ett_x11_list_of_screen); + while(length--) { + guint8 number_of_depths, root_depth; + guint16 width_in_pixels, height_in_pixels; + guint32 screen_root; + proto_item *tti; + proto_tree *ttt; + + screen_root = tvb_get_guint32(tvb, *offsetp, byte_order); + width_in_pixels = tvb_get_guint16(tvb, *offsetp + 20, byte_order); + height_in_pixels = tvb_get_guint16(tvb, *offsetp + 22, byte_order); + root_depth = tvb_get_guint8(tvb, *offsetp + 38); + tti = proto_tree_add_none_format(tt, hf_x11_screen, tvb, *offsetp, 0, + "screen (%08x: %d x %d x %d)", screen_root, + width_in_pixels, height_in_pixels, root_depth); + ttt = proto_item_add_subtree(tti, ett_x11_screen); + proto_tree_add_item(ttt, hf_x11_screen_root, tvb, *offsetp, 4, byte_order); + *offsetp += 4; + proto_tree_add_item(ttt, hf_x11_screen_default_colormap, tvb, *offsetp, 4, byte_order); + *offsetp += 4; + proto_tree_add_item(ttt, hf_x11_screen_white_pixel, tvb, *offsetp, 4, byte_order); + *offsetp += 4; + proto_tree_add_item(ttt, hf_x11_screen_black_pixel, tvb, *offsetp, 4, byte_order); + *offsetp += 4; + proto_tree_add_item(ttt, hf_x11_screen_current_input_masks, tvb, *offsetp, 4, byte_order); + *offsetp += 4; + proto_tree_add_item(ttt, hf_x11_screen_width_in_pixels, tvb, *offsetp, 2, byte_order); + *offsetp += 2; + proto_tree_add_item(ttt, hf_x11_screen_height_in_pixels, tvb, *offsetp, 2, byte_order); + *offsetp += 2; + proto_tree_add_item(ttt, hf_x11_screen_width_in_millimeters, tvb, *offsetp, 2, byte_order); + *offsetp += 2; + proto_tree_add_item(ttt, hf_x11_screen_height_in_millimeters, tvb, *offsetp, 2, byte_order); + *offsetp += 2; + proto_tree_add_item(ttt, hf_x11_screen_min_installed_maps, tvb, *offsetp, 2, byte_order); + *offsetp += 2; + proto_tree_add_item(ttt, hf_x11_screen_max_installed_maps, tvb, *offsetp, 2, byte_order); + *offsetp += 2; + proto_tree_add_item(ttt, hf_x11_screen_root_visual, tvb, *offsetp, 4, byte_order); + *offsetp += 4; + proto_tree_add_item(ttt, hf_x11_screen_backing_stores, tvb, *offsetp, 1, byte_order); + *offsetp += 1; + proto_tree_add_item(ttt, hf_x11_screen_save_unders, tvb, *offsetp, 1, byte_order); + *offsetp += 1; + proto_tree_add_item(ttt, hf_x11_screen_root_depth, tvb, *offsetp, 1, byte_order); + *offsetp += 1; + number_of_depths = tvb_get_guint8(tvb, *offsetp); + proto_tree_add_item(ttt, hf_x11_screen_allowed_depths_len, tvb, *offsetp, 1, byte_order); + *offsetp += 1; + listOfDepth(tvb, offsetp, ttt, hf_x11_depth_detail, number_of_depths, byte_order); + } +} +static void listOfPixmapFormat(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf, + int length, guint byte_order) +{ + proto_item *ti = proto_tree_add_item(t, hf, tvb, *offsetp, length * 8, byte_order); + proto_tree *tt = proto_item_add_subtree(ti, ett_x11_list_of_pixmap_format); + while(length--) { + proto_item *tti; + proto_tree *ttt; + + tti = proto_tree_add_none_format(tt, hf_x11_pixmap_format, tvb, *offsetp, 8, + "pixmap-format"); + ttt = proto_item_add_subtree(tti, ett_x11_pixmap_format); + proto_tree_add_item(ttt, hf_x11_pixmap_format_depth, tvb, *offsetp, 1, byte_order); + *offsetp += 1; + proto_tree_add_item(ttt, hf_x11_pixmap_format_bits_per_pixel, tvb, *offsetp, 1, byte_order); + *offsetp += 1; + proto_tree_add_item(ttt, hf_x11_pixmap_format_scanline_pad, tvb, *offsetp, 1, byte_order); + *offsetp += 1; + proto_tree_add_item(ttt, hf_x11_unused, tvb, *offsetp, 5, byte_order); + *offsetp += 5; + } +} + +static void listOfString8(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf, + int hf_item, int length, guint byte_order) +{ + char *s = NULL; + proto_item *ti; + proto_tree *tt; + int i; + + /* Compute total length */ + + int scanning_offset = *offsetp; /* Scanning pointer */ + for(i = length; i; i--) { + int l; + l = tvb_get_guint8(tvb, scanning_offset); + scanning_offset += 1 + l; + } + + ti = proto_tree_add_item(t, hf, tvb, *offsetp, scanning_offset - *offsetp, byte_order); + tt = proto_item_add_subtree(ti, ett_x11_list_of_string8); + + while(length--) { + guint l = tvb_get_guint8(tvb, *offsetp); + s = tvb_get_string_enc(wmem_packet_scope(), tvb, *offsetp + 1, l, ENC_ASCII); + proto_tree_add_string_format(tt, hf_item, tvb, *offsetp, l + 1, s, "\"%s\"", s); + *offsetp += l + 1; + } +} + +static int stringIsActuallyAn8BitString(tvbuff_t *tvb, int offset, guint length) +{ + for(; length > 0; offset += 2, length--) { + if (tvb_get_guint8(tvb, offset)) + return FALSE; + } + return TRUE; +} + +/* XXX - assumes that the string encoding is ASCII; even if 0x00 through + 0x7F are ASCII, 0x80 through 0xFF might not be, and even 0x00 through + 0x7F aren't necessarily ASCII. */ +static char *tvb_get_ascii_string16(tvbuff_t *tvb, int offset, guint length) +{ + wmem_strbuf_t *str; + guint8 ch; + + str = wmem_strbuf_new_sized(wmem_packet_scope(), length + 1); + + while(length--) { + offset++; + ch = tvb_get_guint8(tvb, offset); + if (ch < 0x80) + wmem_strbuf_append_c(str, ch); + else + wmem_strbuf_append_unichar_repl(str); + offset++; + } + return wmem_strbuf_finalize(str); +} + +static void listOfTextItem(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf, + int sizeIs16, int next_offset, guint byte_order) +{ + char *s = NULL; + proto_item *ti; + proto_tree *tt; + guint32 fid; + + /* Compute total length */ + + int scanning_offset = *offsetp; /* Scanning pointer */ + int n = 0; /* Number of items */ + + while(scanning_offset < next_offset) { + int l; /* Length of an individual item */ + l = tvb_get_guint8(tvb, scanning_offset); + scanning_offset++; + if (!l) break; + n++; + scanning_offset += l == 255 ? 4 : l + (sizeIs16 ? l : 0) + 1; + } + + ti = proto_tree_add_item(t, hf, tvb, *offsetp, scanning_offset - *offsetp, byte_order); + tt = proto_item_add_subtree(ti, ett_x11_list_of_text_item); + + while(n--) { + guint l = tvb_get_guint8(tvb, *offsetp); + if (l == 255) { /* Item is a font */ + fid = tvb_get_ntohl(tvb, *offsetp + 1); + proto_tree_add_uint(tt, hf_x11_textitem_font, tvb, *offsetp, 5, fid); + *offsetp += 5; + } else { /* Item is a string */ + proto_item *tti; + proto_tree *ttt; + gint8 delta = tvb_get_guint8(tvb, *offsetp + 1); + if (sizeIs16) { + if (stringIsActuallyAn8BitString(tvb, *offsetp + 2, l)) { + s = tvb_get_ascii_string16(tvb, *offsetp + 2, l); + tti = proto_tree_add_none_format(tt, hf_x11_textitem_string, tvb, *offsetp, l*2 + 2, + "textitem (string): delta = %d, \"%s\"", + delta, s); + ttt = proto_item_add_subtree(tti, ett_x11_text_item); + proto_tree_add_item(ttt, hf_x11_textitem_string_delta, tvb, *offsetp + 1, 1, byte_order); + proto_tree_add_string_format_value(ttt, hf_x11_textitem_string_string16, tvb, + *offsetp + 2, l, s, "\"%s\"", s); + } else { + tti = proto_tree_add_none_format(tt, hf_x11_textitem_string, tvb, *offsetp, l*2 + 2, + "textitem (string): delta = %d, %s", + delta, + tvb_bytes_to_str(wmem_packet_scope(), tvb, *offsetp + 2, l*2)); + ttt = proto_item_add_subtree(tti, ett_x11_text_item); + proto_tree_add_item(ttt, hf_x11_textitem_string_delta, tvb, *offsetp + 1, 1, byte_order); + proto_tree_add_item(ttt, hf_x11_textitem_string_string16_bytes, tvb, *offsetp + 2, l*2, byte_order); + } + *offsetp += l*2 + 2; + } else { + s = tvb_get_string_enc(wmem_packet_scope(), tvb, *offsetp + 2, l, ENC_ASCII); + tti = proto_tree_add_none_format(tt, hf_x11_textitem_string, tvb, *offsetp, l + 2, + "textitem (string): delta = %d, \"%s\"", + delta, s); + ttt = proto_item_add_subtree(tti, ett_x11_text_item); + proto_tree_add_item(ttt, hf_x11_textitem_string_delta, tvb, *offsetp + 1, 1, byte_order); + proto_tree_add_string_format(ttt, hf_x11_textitem_string_string8, tvb, + *offsetp + 2, l, s, "\"%s\"", s); + *offsetp += l + 2; + } + } + } +} + +static guint32 field8(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf, + guint byte_order) +{ + guint32 v = tvb_get_guint8(tvb, *offsetp); + header_field_info *hfi = proto_registrar_get_nth(hf); + const gchar *enumValue = NULL; + + if (hfi -> strings) + enumValue = try_val_to_str(v, cVALS(hfi -> strings)); + if (enumValue) + proto_tree_add_uint_format(t, hf, tvb, *offsetp, 1, v, + hfi -> display == BASE_DEC ? "%s: %u (%s)" : "%s: 0x%02x (%s)", + hfi -> name, v, enumValue); + else + proto_tree_add_item(t, hf, tvb, *offsetp, 1, byte_order); + *offsetp += 1; + return v; +} + +static guint32 field16(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf, + guint byte_order) +{ + guint32 v = tvb_get_guint16(tvb, *offsetp, byte_order); + header_field_info *hfi = proto_registrar_get_nth(hf); + const gchar *enumValue = NULL; + + if (hfi -> strings) + enumValue = try_val_to_str(v, cVALS(hfi -> strings)); + if (enumValue) + proto_tree_add_uint_format(t, hf, tvb, *offsetp, 2, v, + hfi -> display == BASE_DEC ? "%s: %u (%s)" : "%s: 0x%02x (%s)", + hfi -> name, v, enumValue); + else + proto_tree_add_item(t, hf, tvb, *offsetp, 2, byte_order); + *offsetp += 2; + return v; +} + +static guint32 field32(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf, + guint byte_order) +{ + guint32 v = tvb_get_guint32(tvb, *offsetp, byte_order); + header_field_info *hfi = proto_registrar_get_nth(hf); + const gchar *enumValue = NULL; + const gchar *nameAsChar = hfi -> name; + + if (hfi -> strings) + enumValue = try_val_to_str(v, cVALS(hfi -> strings)); + if (enumValue) + proto_tree_add_uint_format(t, hf, tvb, *offsetp, 4, v, + hfi -> display == BASE_DEC ? "%s: %u (%s)" : "%s: 0x%08x (%s)", + nameAsChar, v, enumValue); + else + proto_tree_add_uint_format(t, hf, tvb, *offsetp, 4, v, + hfi -> display == BASE_DEC ? "%s: %u" : "%s: 0x%08x", + nameAsChar, v); + *offsetp += 4; + return v; +} + +static int * const gc_mask_attributes[] = { + &hf_x11_gc_value_mask_function, + &hf_x11_gc_value_mask_plane_mask, + &hf_x11_gc_value_mask_foreground, + &hf_x11_gc_value_mask_background, + &hf_x11_gc_value_mask_line_width, + &hf_x11_gc_value_mask_line_style, + &hf_x11_gc_value_mask_cap_style, + &hf_x11_gc_value_mask_join_style, + &hf_x11_gc_value_mask_fill_style, + &hf_x11_gc_value_mask_fill_rule, + &hf_x11_gc_value_mask_tile, + &hf_x11_gc_value_mask_stipple, + &hf_x11_gc_value_mask_tile_stipple_x_origin, + &hf_x11_gc_value_mask_tile_stipple_y_origin, + &hf_x11_gc_value_mask_font, + &hf_x11_gc_value_mask_subwindow_mode, + &hf_x11_gc_value_mask_graphics_exposures, + &hf_x11_gc_value_mask_clip_x_origin, + &hf_x11_gc_value_mask_clip_y_origin, + &hf_x11_gc_value_mask_clip_mask, + &hf_x11_gc_value_mask_dash_offset, + &hf_x11_gc_value_mask_gc_dashes, + &hf_x11_gc_value_mask_arc_mode, + NULL +}; + +static void gcAttributes(tvbuff_t *tvb, int *offsetp, proto_tree *t, + guint byte_order) +{ + guint32 bitmask; + bitmask = tvb_get_guint32(tvb, *offsetp, byte_order); + proto_tree_add_bitmask(t, tvb, *offsetp, hf_x11_gc_value_mask, ett_x11_gc_value_mask, gc_mask_attributes, byte_order); + *offsetp += 4; + + if (bitmask & 0x00000001) { + proto_tree_add_item(t, hf_x11_function, tvb, *offsetp, 1, byte_order); + *offsetp += 1; + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 3, ENC_NA); + *offsetp += 3; + } + if (bitmask & 0x00000002) { + proto_tree_add_item(t, hf_x11_plane_mask, tvb, *offsetp, 4, byte_order); + *offsetp += 4; + } + if (bitmask & 0x00000004) { + proto_tree_add_item(t, hf_x11_foreground, tvb, *offsetp, 4, byte_order); + *offsetp += 4; + } + if (bitmask & 0x00000008) { + proto_tree_add_item(t, hf_x11_background, tvb, *offsetp, 4, byte_order); + *offsetp += 4; + } + if (bitmask & 0x00000010) { + proto_tree_add_item(t, hf_x11_line_width, tvb, *offsetp, 2, byte_order); + *offsetp += 2; + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 2, ENC_NA); + *offsetp += 2; + } + if (bitmask & 0x00000020) { + proto_tree_add_item(t, hf_x11_line_style, tvb, *offsetp, 1, byte_order); + *offsetp += 1; + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 3, ENC_NA); + *offsetp += 3; + } + if (bitmask & 0x00000040) { + proto_tree_add_item(t, hf_x11_cap_style, tvb, *offsetp, 1, byte_order); + *offsetp += 1; + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 3, ENC_NA); + *offsetp += 3; + } + if (bitmask & 0x00000080) { + proto_tree_add_item(t, hf_x11_join_style, tvb, *offsetp, 1, byte_order); + *offsetp += 1; + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 3, ENC_NA); + *offsetp += 3; + } + if (bitmask & 0x00000100) { + proto_tree_add_item(t, hf_x11_fill_style, tvb, *offsetp, 1, byte_order); + *offsetp += 1; + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 3, ENC_NA); + *offsetp += 3; + } + if (bitmask & 0x00000200) { + proto_tree_add_item(t, hf_x11_fill_rule, tvb, *offsetp, 1, byte_order); + *offsetp += 1; + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 3, ENC_NA); + *offsetp += 3; + } + if (bitmask & 0x00000400) { + proto_tree_add_item(t, hf_x11_tile, tvb, *offsetp, 4, byte_order); + *offsetp += 4; + } + if (bitmask & 0x00000800) { + proto_tree_add_item(t, hf_x11_stipple, tvb, *offsetp, 4, byte_order); + *offsetp += 4; + } + if (bitmask & 0x00001000) { + proto_tree_add_item(t, hf_x11_tile_stipple_x_origin, tvb, *offsetp, 2, byte_order); + *offsetp += 2; + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 2, ENC_NA); + *offsetp += 2; + } + if (bitmask & 0x00002000) { + proto_tree_add_item(t, hf_x11_tile_stipple_y_origin, tvb, *offsetp, 2, byte_order); + *offsetp += 2; + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 2, ENC_NA); + *offsetp += 2; + } + if (bitmask & 0x00004000) { + proto_tree_add_item(t, hf_x11_font, tvb, *offsetp, 4, byte_order); + *offsetp += 4; + } + if (bitmask & 0x00008000) { + proto_tree_add_item(t, hf_x11_subwindow_mode, tvb, *offsetp, 1, byte_order); + *offsetp += 1; + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 3, ENC_NA); + *offsetp += 3; + } + if (bitmask & 0x00010000) { + proto_tree_add_item(t, hf_x11_graphics_exposures, tvb, *offsetp, 1, byte_order); + *offsetp += 1; + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 3, ENC_NA); + *offsetp += 3; + } + if (bitmask & 0x00020000) { + proto_tree_add_item(t, hf_x11_clip_x_origin, tvb, *offsetp, 2, byte_order); + *offsetp += 2; + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 2, ENC_NA); + *offsetp += 2; + } + if (bitmask & 0x00040000) { + proto_tree_add_item(t, hf_x11_clip_y_origin, tvb, *offsetp, 2, byte_order); + *offsetp += 2; + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 2, ENC_NA); + *offsetp += 2; + } + if (bitmask & 0x00080000) { + proto_tree_add_item(t, hf_x11_clip_mask, tvb, *offsetp, 4, byte_order); + *offsetp += 4; + } + if (bitmask & 0x00100000) { + proto_tree_add_item(t, hf_x11_dash_offset, tvb, *offsetp, 2, byte_order); + *offsetp += 2; + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 2, ENC_NA); + *offsetp += 2; + } + if (bitmask & 0x00200000) { + proto_tree_add_item(t, hf_x11_gc_dashes, tvb, *offsetp, 1, byte_order); + *offsetp += 1; + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 3, ENC_NA); + *offsetp += 3; + } + if (bitmask & 0x00400000) { + proto_tree_add_item(t, hf_x11_arc_mode, tvb, *offsetp, 1, byte_order); + *offsetp += 1; + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 3, ENC_NA); + *offsetp += 3; + } +} + +static void gcMask(tvbuff_t *tvb, int *offsetp, proto_tree *t, + guint byte_order) +{ + proto_tree_add_bitmask(t, tvb, *offsetp, hf_x11_gc_value_mask, ett_x11_gc_value_mask, gc_mask_attributes, byte_order); + *offsetp += 4; +} + +static guint32 requestLength(tvbuff_t *tvb, int *offsetp, proto_tree *t, + guint byte_order) +{ + guint32 res; + proto_item *ti = proto_tree_add_item_ret_uint(t, hf_x11_request_length, tvb, *offsetp, 2, byte_order, &res); + *offsetp += 2; + if (res == 0) { + proto_item_append_text(ti, " (extended length flag)"); + proto_tree_add_item_ret_uint(t, hf_x11_request_length, tvb, *offsetp, 4, byte_order, &res); + *offsetp += 4; + } + return res * 4; +} + +static void setOfEvent(tvbuff_t *tvb, int *offsetp, proto_tree *t, + guint byte_order) +{ + static int * const events[] = { + &hf_x11_event_mask_KeyPress, + &hf_x11_event_mask_KeyRelease, + &hf_x11_event_mask_ButtonPress, + &hf_x11_event_mask_ButtonRelease, + &hf_x11_event_mask_EnterWindow, + &hf_x11_event_mask_LeaveWindow, + &hf_x11_event_mask_PointerMotion, + &hf_x11_event_mask_PointerMotionHint, + &hf_x11_event_mask_Button1Motion, + &hf_x11_event_mask_Button2Motion, + &hf_x11_event_mask_Button3Motion, + &hf_x11_event_mask_Button4Motion, + &hf_x11_event_mask_Button5Motion, + &hf_x11_event_mask_ButtonMotion, + &hf_x11_event_mask_KeymapState, + &hf_x11_event_mask_Exposure, + &hf_x11_event_mask_VisibilityChange, + &hf_x11_event_mask_StructureNotify, + &hf_x11_event_mask_ResizeRedirect, + &hf_x11_event_mask_SubstructureNotify, + &hf_x11_event_mask_SubstructureRedirect, + &hf_x11_event_mask_FocusChange, + &hf_x11_event_mask_PropertyChange, + &hf_x11_event_mask_ColormapChange, + &hf_x11_event_mask_OwnerGrabButton, + NULL + }; + + proto_tree_add_bitmask(t, tvb, *offsetp, hf_x11_event_mask, ett_x11_event_mask, events, byte_order); + *offsetp += 4; +} + +static void setOfDeviceEvent(tvbuff_t *tvb, int *offsetp, proto_tree *t, + guint byte_order) +{ + static int * const do_not_propagate_events[] = { + &hf_x11_do_not_propagate_mask_KeyPress, + &hf_x11_do_not_propagate_mask_KeyRelease, + &hf_x11_do_not_propagate_mask_ButtonPress, + &hf_x11_do_not_propagate_mask_ButtonRelease, + &hf_x11_do_not_propagate_mask_PointerMotion, + &hf_x11_do_not_propagate_mask_Button1Motion, + &hf_x11_do_not_propagate_mask_Button2Motion, + &hf_x11_do_not_propagate_mask_Button3Motion, + &hf_x11_do_not_propagate_mask_Button4Motion, + &hf_x11_do_not_propagate_mask_Button5Motion, + &hf_x11_do_not_propagate_mask_ButtonMotion, + NULL + }; + + proto_tree_add_bitmask(t, tvb, *offsetp, hf_x11_do_not_propagate_mask, ett_x11_do_not_propagate_mask, do_not_propagate_events, byte_order); + *offsetp += 4; +} + + +static void setOfKeyButMask(tvbuff_t *tvb, int *offsetp, proto_tree *t, + guint byte_order, gboolean butmask) +{ + proto_item *ti; + guint32 bitmask_value; + int bitmask_offset; + int bitmask_size; + proto_tree *bitmask_tree; + + bitmask_value = tvb_get_guint16(tvb, *offsetp, byte_order); + bitmask_offset = *offsetp; + bitmask_size = 2; + + if (!butmask && bitmask_value == 0x8000) + proto_tree_add_uint_format(t, hf_x11_modifiers_mask_AnyModifier, tvb, *offsetp, 2, 0x8000, + "modifiers-masks: 0x8000 (AnyModifier)"); + else { + ti = proto_tree_add_uint(t, hf_x11_modifiers_mask, tvb, *offsetp, 2, + bitmask_value); + bitmask_tree = proto_item_add_subtree(ti, ett_x11_set_of_key_mask); + FLAG(modifiers, Shift); + FLAG(modifiers, Lock); + FLAG(modifiers, Control); + FLAG(modifiers, Mod1); + FLAG(modifiers, Mod2); + FLAG(modifiers, Mod3); + FLAG(modifiers, Mod4); + FLAG(modifiers, Mod5); + + if (butmask) { + FLAG(modifiers, Button1); + FLAG(modifiers, Button2); + FLAG(modifiers, Button3); + FLAG(modifiers, Button4); + FLAG(modifiers, Button5); + } + + if (butmask) + FLAG_IF_NONZERO(keybut, erroneous_bits); + else + FLAG_IF_NONZERO(modifiers, erroneous_bits); + } + *offsetp += 2; +} + +static void setOfPointerEvent(tvbuff_t *tvb, int *offsetp, proto_tree *t, + guint byte_order) +{ + static int * const pointer_events[] = { + &hf_x11_pointer_event_mask_ButtonRelease, + &hf_x11_pointer_event_mask_EnterWindow, + &hf_x11_pointer_event_mask_LeaveWindow, + &hf_x11_pointer_event_mask_PointerMotion, + &hf_x11_pointer_event_mask_PointerMotionHint, + &hf_x11_pointer_event_mask_Button1Motion, + &hf_x11_pointer_event_mask_Button2Motion, + &hf_x11_pointer_event_mask_Button3Motion, + &hf_x11_pointer_event_mask_Button4Motion, + &hf_x11_pointer_event_mask_Button5Motion, + &hf_x11_pointer_event_mask_ButtonMotion, + &hf_x11_pointer_event_mask_KeymapState, + NULL + }; + + proto_tree_add_bitmask(t, tvb, *offsetp, hf_x11_pointer_event_mask, ett_x11_pointer_event_mask, pointer_events, byte_order); + *offsetp += 2; +} + +static void string8(tvbuff_t *tvb, int *offsetp, proto_tree *t, + int hf, guint length) +{ + proto_tree_add_item(t, hf, tvb, *offsetp, length, ENC_NA|ENC_ASCII); + *offsetp += length; +} + +/* The length supplied is the length of the string in CHAR2Bs (half the number of bytes) */ + +static void string16(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf, + int hf_bytes, guint length, guint byte_order) +{ + guint l = length*2; /* byte count */ + char *s; + + if (stringIsActuallyAn8BitString(tvb, *offsetp, length)) { + s = tvb_get_ascii_string16(tvb, *offsetp, length); + proto_tree_add_string_format_value(t, hf, tvb, *offsetp, l, s, "\"%s\"", s); + } else + proto_tree_add_item(t, hf_bytes, tvb, *offsetp, l, byte_order); + + *offsetp += l; +} + +static void timestamp(tvbuff_t *tvb, int *offsetp, proto_tree *t, int hf, + guint byte_order) +{ + guint32 v = tvb_get_guint32(tvb, *offsetp, byte_order); + + if (!v) + proto_tree_add_uint_format(t, hf, tvb, *offsetp, 4, 0, "%s: 0 (CurrentTime)", + proto_registrar_get_nth(hf) -> name); + else + proto_tree_add_uint(t, hf, tvb, *offsetp, 4, v); + *offsetp += 4; +} + +static void windowAttributes(tvbuff_t *tvb, int *offsetp, proto_tree *t, + guint byte_order) +{ + guint32 bitmask; + static int * const window_attributes_flags[] = { + &hf_x11_window_value_mask_background_pixmap, + &hf_x11_window_value_mask_background_pixel, + &hf_x11_window_value_mask_border_pixmap, + &hf_x11_window_value_mask_border_pixel, + &hf_x11_window_value_mask_bit_gravity, + &hf_x11_window_value_mask_win_gravity, + &hf_x11_window_value_mask_backing_store, + &hf_x11_window_value_mask_backing_planes, + &hf_x11_window_value_mask_backing_pixel, + &hf_x11_window_value_mask_override_redirect, + &hf_x11_window_value_mask_save_under, + &hf_x11_window_value_mask_event_mask, + &hf_x11_window_value_mask_do_not_propagate_mask, + &hf_x11_window_value_mask_colormap, + &hf_x11_window_value_mask_cursor, + NULL + }; + + bitmask = tvb_get_guint32(tvb, *offsetp, byte_order); + proto_tree_add_bitmask(t, tvb, *offsetp, hf_x11_window_value_mask, ett_x11_window_value_mask, window_attributes_flags, byte_order); + *offsetp += 4; + + if (bitmask & 0x00000001) { + proto_tree_add_item(t, hf_x11_background_pixmap, tvb, *offsetp, 4, byte_order); + *offsetp += 4; + } + if (bitmask & 0x00000002) { + proto_tree_add_item(t, hf_x11_background_pixel, tvb, *offsetp, 4, byte_order); + *offsetp += 4; + } + if (bitmask & 0x00000004) { + proto_tree_add_item(t, hf_x11_border_pixmap, tvb, *offsetp, 4, byte_order); + *offsetp += 4; + } + if (bitmask & 0x00000008) { + proto_tree_add_item(t, hf_x11_border_pixel, tvb, *offsetp, 4, byte_order); + *offsetp += 4; + } + if (bitmask & 0x00000010) { + proto_tree_add_item(t, hf_x11_bit_gravity, tvb, *offsetp, 1, byte_order); + *offsetp += 1; + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 3, ENC_NA); + *offsetp += 3; + } + if (bitmask & 0x00000020) { + proto_tree_add_item(t, hf_x11_win_gravity, tvb, *offsetp, 1, byte_order); + *offsetp += 1; + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 3, ENC_NA); + *offsetp += 3; + } + if (bitmask & 0x00000040) { + proto_tree_add_item(t, hf_x11_backing_store, tvb, *offsetp, 1, byte_order); + *offsetp += 1; + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 3, ENC_NA); + *offsetp += 3; + } + if (bitmask & 0x00000080) { + proto_tree_add_item(t, hf_x11_backing_planes, tvb, *offsetp, 4, byte_order); + *offsetp += 4; + } + if (bitmask & 0x00000100) { + proto_tree_add_item(t, hf_x11_backing_pixel, tvb, *offsetp, 4, byte_order); + *offsetp += 4; + } + if (bitmask & 0x00000200) { + proto_tree_add_item(t, hf_x11_override_redirect, tvb, *offsetp, 1, byte_order); + *offsetp += 1; + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 3, ENC_NA); + *offsetp += 3; + } + if (bitmask & 0x00000400) { + proto_tree_add_item(t, hf_x11_save_under, tvb, *offsetp, 1, byte_order); + *offsetp += 1; + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 3, ENC_NA); + *offsetp += 3; + } + if (bitmask & 0x00000800) { + setOfEvent(tvb, offsetp, t, byte_order); + } + if (bitmask & 0x00001000) { + setOfDeviceEvent(tvb, offsetp, t, byte_order); + } + if (bitmask & 0x00002000) { + proto_tree_add_item(t, hf_x11_colormap, tvb, *offsetp, 4, byte_order); + *offsetp += 4; + } + if (bitmask & 0x00004000) { + proto_tree_add_item(t, hf_x11_cursor, tvb, *offsetp, 4, byte_order); + *offsetp += 4; + } +} + +/************************************************************************ + *** *** + *** G U E S S I N G T H E B Y T E O R D E R I N G *** + *** *** + ************************************************************************/ + +/* If we can't guess, we return ENC_LITTLE_ENDIAN, cause + I'm developing on a Linux box :-). The (non-)guess isn't cached + however, so we may have more luck next time. I'm quite conservative + in my assertions, cause once it's cached, it stays in cache, and + we may be fooled up by a packet starting with the end of a request + started in a previous packet... +*/ + +static int numberOfBitSetTable[] = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4 }; + +static int numberOfBitSet(tvbuff_t *tvb, int offset, int maskLength) +{ + int res = 0; + while(maskLength--) { + int c = tvb_get_guint8(tvb, offset); + offset++; + res += numberOfBitSetTable[c & 0xf] + numberOfBitSetTable[c >> 4]; + } + return res; +} + +static int listOfStringLengthConsistent(tvbuff_t *tvb, int offset, int length, int listLength) +{ + if (listLength > length) return FALSE; + while(listLength--) { + int l; + if (!tvb_bytes_exist(tvb, offset, 1)) return TRUE; + l = tvb_get_guint8(tvb, offset); + if (!l) break; + l++; + if (l > length) return FALSE; + if (!tvb_bytes_exist(tvb, offset, l)) return TRUE; + offset += l; + length -= l; + } + if (length > 3) return FALSE; + return TRUE; +} + +static int rounded4(int n) +{ + int remainder = n % 4; + int res = n / 4; + if (remainder) res++; + return res; +} + +/* We assume the order to be consistent, until proven wrong. */ + +static gboolean consistentWithOrder(int length, tvbuff_t *tvb, int offset, int encoding) +{ + switch(tvb_get_guint8(tvb, offset)) { + case X_CreateWindow: + return !tvb_bytes_exist(tvb, offset, 32) || length == 8 + numberOfBitSet(tvb, offset + 7 * 4, 4); + + case X_ChangeWindowAttributes: + case X_ChangeGC: + return !tvb_bytes_exist(tvb, offset, 12) || length == 3 + numberOfBitSet(tvb, offset + 8, 4); + + case X_GetWindowAttributes: + case X_DestroyWindow: + case X_DestroySubwindows: + case X_ChangeSaveSet: + case X_MapWindow: + case X_MapSubwindows: + case X_UnmapWindow: + case X_UnmapSubwindows: + case X_CirculateWindow: + case X_GetGeometry: + case X_QueryTree: + case X_GetAtomName: + case X_ListProperties: + case X_GetSelectionOwner: + case X_UngrabPointer: + case X_UngrabKeyboard: + case X_AllowEvents: + case X_QueryPointer: + case X_CloseFont: + case X_QueryFont: + case X_FreePixmap: + case X_FreeGC: + case X_FreeColormap: + case X_InstallColormap: + case X_UninstallColormap: + case X_ListInstalledColormaps: + case X_FreeCursor: + case X_GetKeyboardMapping: + case X_KillClient: + return length == 2; + + case X_ReparentWindow: + case X_SetSelectionOwner: + case X_ChangeActivePointerGrab: + case X_GrabKeyboard: + case X_GrabKey: + case X_GetMotionEvents: + case X_TranslateCoords: + case X_CreatePixmap: + case X_CopyGC: + case X_ClearArea: + case X_CreateColormap: + case X_AllocColor: + case X_AllocColorPlanes: + return length == 4; + + case X_ConfigureWindow: + return !tvb_bytes_exist(tvb, offset, 10) || length == 3 + numberOfBitSet(tvb, offset + 8, 2); + + case X_InternAtom: + case X_QueryExtension: + return !tvb_bytes_exist(tvb, offset, 6) || length == 2 + rounded4(tvb_get_guint16(tvb, offset + 4, encoding)); + + case X_ChangeProperty: + { + int multiplier, type; + if (!tvb_bytes_exist(tvb, offset, 17)) return TRUE; + type = tvb_get_guint8(tvb, 16); + if (type != 8 && type != 16 && type != 32) return FALSE; + multiplier = type == 8 ? 1 : type == 16 ? 2 : 4; + if (!tvb_bytes_exist(tvb, offset, 24)) return TRUE; + return length == 6 + rounded4(tvb_get_guint32(tvb, offset + 20, encoding) * multiplier); + } + + case X_DeleteProperty: + case X_UngrabButton: + case X_UngrabKey: + case X_SetInputFocus: + case X_CopyColormapAndFree: + case X_AllocColorCells: + case X_QueryBestSize: + case X_ChangePointerControl: + case X_SetScreenSaver: + return length == 3; + + case X_GetProperty: + case X_ConvertSelection: + case X_GrabPointer: + case X_GrabButton: + case X_WarpPointer: + return length == 6; + + case X_SendEvent: + return length == 11; + + case X_GrabServer: + case X_UngrabServer: + case X_GetInputFocus: + case X_QueryKeymap: + case X_GetFontPath: + case X_ListExtensions: + case X_GetKeyboardControl: + case X_Bell: + case X_GetPointerControl: + case X_GetScreenSaver: + case X_ListHosts: + case X_SetAccessControl: + case X_SetCloseDownMode: + case X_ForceScreenSaver: + case X_GetPointerMapping: + case X_GetModifierMapping: + return length == 1; + + case X_OpenFont: + case X_AllocNamedColor: + case X_LookupColor: + return !tvb_bytes_exist(tvb, offset, 10) || length == 3 + rounded4(tvb_get_guint16(tvb, offset + 8, encoding)); + + case X_QueryTextExtents: + return length >= 2; + + case X_ListFonts: + case X_ListFontsWithInfo: + case X_ChangeHosts: + return !tvb_bytes_exist(tvb, offset, 8) || length == 2 + rounded4(tvb_get_guint16(tvb, offset + 6, encoding)); + + case X_SetFontPath: + if (length < 2) return FALSE; + if (!tvb_bytes_exist(tvb, offset, 8)) return TRUE; + return listOfStringLengthConsistent(tvb, offset + 8, (length - 2) * 4, tvb_get_guint16(tvb, offset + 4, encoding)); + + case X_CreateGC: + return !tvb_bytes_exist(tvb, offset, 16) || length == 4 + numberOfBitSet(tvb, offset + 12, 4); + + case X_SetDashes: + return !tvb_bytes_exist(tvb, offset, 12) || length == 3 + rounded4(tvb_get_guint16(tvb, offset + 10, encoding)); + + case X_SetClipRectangles: + case X_PolySegment: + case X_PolyRectangle: + case X_PolyFillRectangle: + return length >= 3 && (length - 3) % 2 == 0; + + case X_CopyArea: + return length == 7; + + case X_CopyPlane: + case X_CreateCursor: + case X_CreateGlyphCursor: + return length == 8; + + case X_PolyPoint: + case X_PolyLine: + case X_FreeColors: + return length >= 3; + + case X_PolyArc: + case X_PolyFillArc: + return length >= 3 && (length - 3) % 3 == 0; + + case X_FillPoly: + case X_ImageText8: + return length >= 4; + + case X_PutImage: + return length >= 6; + + case X_GetImage: + case X_RecolorCursor: + return length == 5; + + case X_PolyText8: + if (length < 4) return FALSE; + return TRUE; /* We don't perform many controls on this one */ + + case X_PolyText16: + if (length < 4) return FALSE; + return TRUE; /* We don't perform many controls on this one */ + + case X_ImageText16: + return length >= 4; + + case X_StoreColors: + return length > 2 && (length - 2) % 3 == 0; + + case X_StoreNamedColor: + return !tvb_bytes_exist(tvb, offset, 14) || length == 4 + rounded4(tvb_get_guint16(tvb, offset + 12, encoding)); + + case X_QueryColors: + return length >= 2; + + case X_ChangeKeyboardMapping: + return !tvb_bytes_exist(tvb, offset, 6) || length == 2 + tvb_get_guint8(tvb, 1) * tvb_get_guint8(tvb, 5); + + case X_ChangeKeyboardControl: + return !tvb_bytes_exist(tvb, offset, 6) || length == 2 + numberOfBitSet(tvb, offset + 4, 2); + + case X_RotateProperties: + return !tvb_bytes_exist(tvb, offset, 10) || length == 3 + tvb_get_guint16(tvb, offset + 8, encoding); + + case X_SetPointerMapping: + return length == 1 + rounded4(tvb_get_guint8(tvb, 1)); + + case X_SetModifierMapping: + return length == 1 + tvb_get_guint8(tvb, 1) * 2; + + case X_NoOperation: + return length >= 1; + + default: + return TRUE; + } +} + +/* -1 means doesn't match, +1 means match, 0 means don't know */ + +static int x_endian_match(tvbuff_t *tvb, int encoding) +{ + int offset, nextoffset; + int atLeastOne = 0; + + for(offset = 0; tvb_bytes_exist(tvb, offset, 4); offset = nextoffset) { + int length; + length = tvb_get_guint16(tvb, offset + 2, encoding); + if (!length) + return -1; + nextoffset = offset + length * 4; + if (!consistentWithOrder(length, tvb, offset, encoding)) + return -1; + atLeastOne = 1; + } + return atLeastOne; +} + +static guint +guess_byte_ordering(tvbuff_t *tvb, packet_info *pinfo, + x11_conv_data_t *state) +{ + /* With X the client gives the byte ordering for the protocol, + and the port on the server tells us we're speaking X. */ + + int le, be; + guint decision; + + if (state->byte_order == ENC_BIG_ENDIAN) + return ENC_BIG_ENDIAN; /* known to be big-endian */ + else if (state->byte_order == ENC_LITTLE_ENDIAN) + return ENC_LITTLE_ENDIAN; /* known to be little-endian */ + + if (pinfo->srcport == pinfo->match_uint) { + /* + * This is a reply or event; we don't try to guess the + * byte order on it for now. + */ + return ENC_LITTLE_ENDIAN; + } + + le = x_endian_match(tvb, ENC_LITTLE_ENDIAN); + be = x_endian_match(tvb, ENC_BIG_ENDIAN); + + if (le == be) { + /* We have no reason to believe it's little- rather than + big-endian, so we guess the shortest length is the + right one. + */ + if (!tvb_bytes_exist(tvb, 0, 4)) + /* Not even a way to get the length. We're biased + toward little endianness here (essentially the + x86 world right now). Decoding won't go very far + anyway. + */ + decision = ENC_LITTLE_ENDIAN; + else { + if (tvb_get_letohs(tvb, 2) <= tvb_get_ntohs(tvb, 2)) + decision = ENC_LITTLE_ENDIAN; + else + decision = ENC_BIG_ENDIAN; + } + } else { + if (le >= be) + decision = ENC_LITTLE_ENDIAN; + else + decision = ENC_BIG_ENDIAN; + } + + if ((le < 0 && be > 0) || (le > 0 && be < 0)) { + /* + * Remember the decision. + */ + state->byte_order = decision; + } + + return decision; +} + +/************************************************************************ + *** *** + *** D E C O D I N G O N E P A C K E T *** + *** *** + ************************************************************************/ + +/* + * Decode an initial connection request. + */ +static void dissect_x11_initial_conn(tvbuff_t *tvb, packet_info *pinfo, + proto_tree *tree, x11_conv_data_t *state, guint byte_order) +{ + int offset = 0; + int *offsetp = &offset; + proto_item *ti; + proto_tree *t; + guint16 auth_proto_name_length, auth_proto_data_length; + gint left; + + ti = proto_tree_add_item(tree, proto_x11, tvb, 0, -1, ENC_NA); + proto_item_append_text(ti, ", Request, Initial connection request"); + t = proto_item_add_subtree(ti, ett_x11); + + CARD8(byte_order); + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + CARD16(protocol_major_version); + CARD16(protocol_minor_version); + auth_proto_name_length = CARD16(authorization_protocol_name_length); + auth_proto_data_length = CARD16(authorization_protocol_data_length); + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 2, ENC_NA); + *offsetp += 2; + + if (auth_proto_name_length != 0) { + STRING8(authorization_protocol_name, auth_proto_name_length); + offset = ROUND_LENGTH(offset); + } + + if (auth_proto_data_length != 0) { + STRING8(authorization_protocol_data, auth_proto_data_length); + offset = ROUND_LENGTH(offset); + } + + if ((left = tvb_reported_length_remaining(tvb, offset)) > 0) + proto_tree_add_item(t, hf_x11_undecoded, tvb, offset, left, + ENC_NA); + + /* + * This is the initial connection request... + */ + state->iconn_frame = pinfo->num; + + /* + * ...and we're expecting a reply to it. + */ + state->sequencenumber = 0; + wmem_map_insert(state->seqtable, GINT_TO_POINTER(state->sequencenumber), + (int *)INITIAL_CONN); +} + +static void dissect_x11_initial_reply(tvbuff_t *tvb, packet_info *pinfo, + proto_tree *tree, const char _U_ *sep, x11_conv_data_t *state, + guint byte_order) +{ + int offset = 0, *offsetp = &offset, left; + unsigned char success; + int length_of_vendor; + int length_of_reason; + int number_of_formats_in_pixmap_formats; + int number_of_screens_in_roots; + int unused; + proto_item *ti; + proto_tree *t; + + ti = proto_tree_add_item(tree, proto_x11, tvb, 0, -1, ENC_NA); + proto_item_append_text(ti, ", Reply, Initial connection reply"); + t = proto_item_add_subtree(ti, ett_x11); + + state->iconn_reply = pinfo->num; + success = INT8(success); + if (success) { + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + length_of_reason = 0; + } + else { + length_of_reason = INT8(length_of_reason); + } + + INT16(protocol_major_version); + INT16(protocol_minor_version); + INT16(replylength); + if (success) { + INT32(release_number); + INT32(resource_id_base); + INT32(resource_id_mask); + INT32(motion_buffer_size); + length_of_vendor = INT16(length_of_vendor); + INT16(maximum_request_length); + number_of_screens_in_roots = INT8(number_of_screens_in_roots); + number_of_formats_in_pixmap_formats = INT8(number_of_formats_in_pixmap_formats); + INT8(image_byte_order); + INT8(bitmap_format_bit_order); + INT8(bitmap_format_scanline_unit); + INT8(bitmap_format_scanline_pad); + INT8(min_keycode); + INT8(max_keycode); + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 4, ENC_NA); + *offsetp += 4; + STRING8(vendor, length_of_vendor); + unused = (4 - (length_of_vendor % 4)) % 4; + if (unused > 0) { + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, unused, ENC_NA); + *offsetp += unused; + } + LISTofPIXMAPFORMAT(pixmap_format, number_of_formats_in_pixmap_formats); + LISTofSCREEN(screen, number_of_screens_in_roots); + } else { + STRING8(reason, length_of_reason); + } + + if ((left = tvb_reported_length_remaining(tvb, offset)) > 0) + UNDECODED(left); + +} + +typedef struct x11_reply_info { + const guint8 minor; + void (*dissect)(tvbuff_t *tvb, packet_info *pinfo, int *offsetp, proto_tree *t, guint byte_order); +} x11_reply_info; + +typedef struct event_info { + const gchar *name; + void (*dissect)(tvbuff_t *tvb, int *offsetp, proto_tree *t, guint byte_order); +} x11_event_info; + +typedef struct x11_generic_event_info { + const guint16 minor; + void (*dissect)(tvbuff_t *tvb, int length, int *offsetp, proto_tree *t, guint byte_order); +} x11_generic_event_info; + +static void set_handler(const char *name, void (*func)(tvbuff_t *tvb, packet_info *pinfo, int *offsetp, proto_tree *t, guint byte_order), + const char **errors, + const x11_event_info *event_info, + const x11_generic_event_info *genevent_info, + const x11_reply_info *reply_info) +{ + wmem_map_insert(extension_table, (gpointer)name, (gpointer)func); + wmem_map_insert(error_table, (gpointer)name, (gpointer)errors); + wmem_map_insert(event_table, (gpointer)name, (gpointer)event_info); + if (genevent_info) + wmem_map_insert(genevent_table, (gpointer)name, (gpointer)genevent_info); + wmem_map_insert(reply_table, (gpointer)name, (gpointer)reply_info); +} + +#include "x11-extension-errors.h" +#include "x11-extension-implementation.h" + +static void tryExtension(int opcode, tvbuff_t *tvb, packet_info *pinfo, int *offsetp, proto_tree *t, + x11_conv_data_t *state, guint byte_order) +{ + const gchar *extension; + void (*func)(tvbuff_t *tvb, packet_info *pinfo, int *offsetp, proto_tree *t, guint byte_order); + + extension = try_val_to_str(opcode, state->opcode_vals); + if (!extension) + return; + + func = (void (*)(tvbuff_t *, packet_info *, int *, proto_tree *, guint))wmem_map_lookup(extension_table, extension); + if (func) + func(tvb, pinfo, offsetp, t, byte_order); +} + +static void tryExtensionReply(int opcode, tvbuff_t *tvb, packet_info *pinfo, int *offsetp, proto_tree *t, + x11_conv_data_t *state, guint byte_order) +{ + void (*func)(tvbuff_t *tvb, packet_info *pinfo, int *offsetp, proto_tree *t, guint byte_order); + + func = (void (*)(tvbuff_t *, packet_info *, int *, proto_tree *, guint))wmem_map_lookup(state->reply_funcs, GINT_TO_POINTER(opcode)); + if (func) + func(tvb, pinfo, offsetp, t, byte_order); + else + REPLYCONTENTS_COMMON(); +} + +static void tryExtensionEvent(int event, tvbuff_t *tvb, int *offsetp, proto_tree *t, + x11_conv_data_t *state, guint byte_order) +{ + void (*func)(tvbuff_t *tvb, int *offsetp, proto_tree *t, guint byte_order); + + func = (void (*)(tvbuff_t *, int *, proto_tree *, guint))wmem_map_lookup(state->eventcode_funcs, GINT_TO_POINTER(event)); + if (func) + func(tvb, offsetp, t, byte_order); +} + +static void tryGenericExtensionEvent(tvbuff_t *tvb, int *offsetp, proto_tree *t, + x11_conv_data_t *state, guint byte_order) +{ + const gchar *extname; + int extension, length; + + extension = tvb_get_guint8(tvb, *offsetp); + (*offsetp)++; + extname = try_val_to_str(extension, state->opcode_vals); + + if (extname) { + proto_tree_add_uint_format(t, hf_x11_extension, tvb, *offsetp, 1, extension, "extension: %d (%s)", extension, extname); + } else { + proto_tree_add_uint(t, hf_x11_extension, tvb, *offsetp, 1, extension); + } + + CARD16(event_sequencenumber); + + length = REPLYLENGTH(eventlength); + length = length * 4 + 32; + *offsetp += 4; + + if (extname) { + x11_generic_event_info *info; + info = (x11_generic_event_info *)wmem_map_lookup(genevent_table, extname); + + if (info) { + int i; + + int opcode = tvb_get_guint16(tvb, *offsetp, byte_order); + + for (i = 0; info[i].dissect != NULL; i++) { + if (info[i].minor == opcode) { + *offsetp += 2; + info[i].dissect(tvb, length, offsetp, t, byte_order); + return; + } + } + } + } + CARD16(minor_opcode); +} + +static void register_extension(x11_conv_data_t *state, value_string *vals_p, + int major_opcode, unsigned int first_event, unsigned int first_error) +{ + const char **error_string; + x11_event_info *event_info; + x11_reply_info *reply_info; + int i; + + vals_p->value = major_opcode; + + error_string = (const char **)wmem_map_lookup(error_table, vals_p->strptr); + while (error_string && *error_string && first_error <= LastExtensionError) { + /* store string of extension error */ + for (i = 0; i <= LastExtensionError; i++) { + if (state->errorcode_vals[i].strptr == NULL) { + state->errorcode_vals[i].value = first_error; + state->errorcode_vals[i].strptr = *error_string; + break; + } else if (state->errorcode_vals[i].value == first_error) { + /* TODO: Warn about extensions stepping on each other */ + state->errorcode_vals[i].strptr = *error_string; + break; + } + } + first_error++; + error_string++; + } + + event_info = (x11_event_info *)wmem_map_lookup(event_table, vals_p->strptr); + while (event_info && event_info->name && first_event <= LastExtensionEvent) { + /* store string of extension event */ + for (i = 0; i <= LastExtensionEvent; i++) { + if (state->eventcode_vals[i].strptr == NULL) { + state->eventcode_vals[i].value = first_event; + state->eventcode_vals[i].strptr = event_info->name; + break; + } else if (state->eventcode_vals[i].value == first_event) { + /* TODO: Warn about extensions stepping on each other */ + state->eventcode_vals[i].strptr = event_info->name; + break; + } + } + + /* store event decode function */ + wmem_map_insert(state->eventcode_funcs, GINT_TO_POINTER(first_event), (gpointer)event_info->dissect); + + first_event++; + event_info++; + } + + reply_info = (x11_reply_info *)wmem_map_lookup(reply_table, vals_p->strptr); + if (reply_info) + for (i = 0; reply_info[i].dissect; i++) + wmem_map_insert(state->reply_funcs, + GINT_TO_POINTER(major_opcode | (reply_info[i].minor << 8)), + (gpointer)reply_info[i].dissect); +} + + +static void dissect_x11_request(tvbuff_t *tvb, packet_info *pinfo, + proto_tree *tree, const char *sep, x11_conv_data_t *state, + guint byte_order) +{ + int offset = 0; + int *offsetp = &offset; + int query_ext_offset; + int next_offset; + proto_item *ti; + proto_tree *t; + int length, opcode, i; + guint8 v8, v8_2, v8_3; + guint16 v16; + guint32 v32; + gint left; + gchar *name; + + query_ext_offset = 2; /* "opcode" and "unused" */ + + length = tvb_get_guint16(tvb, query_ext_offset, byte_order) * 4; + query_ext_offset += 2; + + if (length == 0) { + /* BIG-REQUESTS extension */ + length = tvb_get_guint32(tvb, query_ext_offset, byte_order); + if ((gint64)length * 4 > G_MAXINT32) + return; + length *= 4; + query_ext_offset += 4; + } + + if (length < 4) { + /* Bogus message length? */ + return; + } + + next_offset = offset + length; + + ti = proto_tree_add_item(tree, proto_x11, tvb, 0, -1, ENC_NA); + t = proto_item_add_subtree(ti, ett_x11); + + if (!pinfo->fd->visited) + ++state->sequencenumber; + + OPCODE(); + + col_append_fstr(pinfo->cinfo, COL_INFO, "%s %s", sep, + val_to_str(opcode, state->opcode_vals, + "<Unknown opcode %d>")); + + proto_item_append_text(ti, ", Request, opcode: %d (%s)", + opcode, val_to_str(opcode, state->opcode_vals, + "<Unknown opcode %d>")); + + /* + * Does this request expect a reply? + */ + switch(opcode) { + + case X_QueryExtension: + + /* necessary processing even if tree == NULL */ + + v16 = tvb_get_guint16(tvb, query_ext_offset, byte_order); + query_ext_offset += 2; + /* Some unused bytes */ + query_ext_offset += 2; + name = tvb_get_string_enc(wmem_file_scope(), tvb, query_ext_offset, v16, ENC_ASCII); + + /* store string of extension, opcode will be set at reply */ + i = 0; + while(i < MAX_OPCODES) { + if (state->opcode_vals[i].strptr == NULL) { + state->opcode_vals[i].strptr = name; + state->opcode_vals[i].value = -1; + wmem_map_insert(state->valtable, + GINT_TO_POINTER(state->sequencenumber), + (int *)&state->opcode_vals[i]); + break; + } else if (strcmp(state->opcode_vals[i].strptr, + name) == 0) { + wmem_map_insert(state->valtable, + GINT_TO_POINTER(state->sequencenumber), + (int *)&state->opcode_vals[i]); + break; + } + i++; + } + + /* QueryExtension expects a reply, fall through */ + /* FALLTHROUGH */ + case X_AllocColor: + case X_AllocColorCells: + case X_AllocColorPlanes: + case X_AllocNamedColor: + case X_GetAtomName: + case X_GetFontPath: + case X_GetGeometry: + case X_GetImage: + case X_GetInputFocus: + case X_GetKeyboardControl: + case X_GetKeyboardMapping: + case X_GetModifierMapping: + case X_GetMotionEvents: + case X_GetPointerControl: + case X_GetPointerMapping: + case X_GetProperty: + case X_GetScreenSaver: + case X_GetSelectionOwner: + case X_GetWindowAttributes: + case X_GrabKeyboard: + case X_GrabPointer: + case X_InternAtom: + case X_ListExtensions: + case X_ListFonts: + case X_ListFontsWithInfo: + case X_ListHosts: + case X_ListInstalledColormaps: + case X_ListProperties: + case X_LookupColor: + case X_QueryBestSize: + case X_QueryColors: + case X_QueryFont: + case X_QueryKeymap: + case X_QueryPointer: + case X_QueryTextExtents: + case X_QueryTree: + case X_SetModifierMapping: + case X_SetPointerMapping: + case X_TranslateCoords: + /* + * Those requests expect a reply. + */ + wmem_map_insert(state->seqtable, + GINT_TO_POINTER(state->sequencenumber), + GINT_TO_POINTER(opcode)); + + break; + + default: + /* + * With Extension, we don't know, so assume there could be one + */ + if (opcode >= X_FirstExtension && opcode <= X_LastExtension) { + guint32 minor; + minor = tvb_get_guint8(tvb, 1); + + wmem_map_insert(state->seqtable, + GINT_TO_POINTER(state->sequencenumber), + GINT_TO_POINTER(opcode | (minor << 8))); + } + + /* + * No reply is expected from any other request. + */ + break; + } + + if (tree == NULL) + return; + + switch(opcode) { + + case X_CreateWindow: + CARD8(depth); + requestLength(tvb, offsetp, t, byte_order); + WINDOW(wid); + WINDOW(parent); + INT16(x); + INT16(y); + CARD16(width); + CARD16(height); + CARD16(border_width); + ENUM16(window_class); + VISUALID(visual); + windowAttributes(tvb, offsetp, t, byte_order); + break; + + case X_ChangeWindowAttributes: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + requestLength(tvb, offsetp, t, byte_order); + WINDOW(window); + windowAttributes(tvb, offsetp, t, byte_order); + break; + + case X_GetWindowAttributes: + case X_DestroyWindow: + case X_DestroySubwindows: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + requestLength(tvb, offsetp, t, byte_order); + WINDOW(window); + break; + + case X_ChangeSaveSet: + ENUM8(save_set_mode); + requestLength(tvb, offsetp, t, byte_order); + WINDOW(window); + break; + + case X_ReparentWindow: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + requestLength(tvb, offsetp, t, byte_order); + WINDOW(window); + WINDOW(parent); + INT16(x); + INT16(y); + break; + + case X_MapWindow: + case X_MapSubwindows: + case X_UnmapWindow: + case X_UnmapSubwindows: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + requestLength(tvb, offsetp, t, byte_order); + WINDOW(window); + break; + + case X_ConfigureWindow: + { + guint16 bitmask16; + static int * const window_attributes_flags[] = { + &hf_x11_window_value_mask_background_pixmap, + &hf_x11_window_value_mask_background_pixel, + &hf_x11_window_value_mask_border_pixmap, + &hf_x11_window_value_mask_border_pixel, + &hf_x11_window_value_mask_bit_gravity, + &hf_x11_window_value_mask_win_gravity, + &hf_x11_window_value_mask_backing_store, + &hf_x11_window_value_mask_backing_planes, + &hf_x11_window_value_mask_backing_pixel, + &hf_x11_window_value_mask_override_redirect, + &hf_x11_window_value_mask_save_under, + &hf_x11_window_value_mask_event_mask, + &hf_x11_window_value_mask_do_not_propagate_mask, + &hf_x11_window_value_mask_colormap, + &hf_x11_window_value_mask_cursor, + NULL + }; + + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + requestLength(tvb, offsetp, t, byte_order); + proto_tree_add_item(t, hf_x11_window, tvb, *offsetp, 1, byte_order); + *offsetp += 4; + bitmask16 = tvb_get_guint16(tvb, *offsetp, byte_order); + proto_tree_add_bitmask(t, tvb, *offsetp, hf_x11_configure_window_mask, ett_x11_configure_window_mask, window_attributes_flags, byte_order); + *offsetp += 2; + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 2, ENC_NA); + *offsetp += 2; + if (bitmask16 & 0x0001) { + proto_tree_add_item(t, hf_x11_x, tvb, *offsetp, 2, byte_order); + *offsetp += 2; + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 2, ENC_NA); + *offsetp += 2; + } + if (bitmask16 & 0x0002) { + proto_tree_add_item(t, hf_x11_y, tvb, *offsetp, 2, byte_order); + *offsetp += 2; + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 2, ENC_NA); + *offsetp += 2; + } + if (bitmask16 & 0x0004) { + proto_tree_add_item(t, hf_x11_width, tvb, *offsetp, 2, byte_order); + *offsetp += 2; + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 2, ENC_NA); + *offsetp += 2; + } + if (bitmask16 & 0x0008) { + proto_tree_add_item(t, hf_x11_height, tvb, *offsetp, 2, byte_order); + *offsetp += 2; + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 2, ENC_NA); + *offsetp += 2; + } + if (bitmask16 & 0x0010) { + proto_tree_add_item(t, hf_x11_border_width, tvb, *offsetp, 2, byte_order); + *offsetp += 2; + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 2, ENC_NA); + *offsetp += 2; + } + if (bitmask16 & 0x0020) { + proto_tree_add_item(t, hf_x11_sibling, tvb, *offsetp, 4, byte_order); + *offsetp += 4; + } + if (bitmask16 & 0x0040) { + proto_tree_add_item(t, hf_x11_stack_mode, tvb, *offsetp, 1, byte_order); + *offsetp += 1; + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 3, ENC_NA); + *offsetp += 3; + } + if (next_offset - *offsetp > 0) { + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, next_offset - *offsetp, ENC_NA); + *offsetp = next_offset; + } + } + break; + + case X_CirculateWindow: + ENUM8(direction); + requestLength(tvb, offsetp, t, byte_order); + WINDOW(window); + break; + + case X_GetGeometry: + case X_QueryTree: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + requestLength(tvb, offsetp, t, byte_order); + DRAWABLE(drawable); + break; + + case X_InternAtom: + BOOL(only_if_exists); + requestLength(tvb, offsetp, t, byte_order); + v16 = FIELD16(name_length); + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 2, ENC_NA); + *offsetp += 2; + STRING8(name, v16); + PAD(); + break; + + case X_GetAtomName: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + requestLength(tvb, offsetp, t, byte_order); + ATOM(atom); + break; + + case X_ChangeProperty: + ENUM8(mode); + requestLength(tvb, offsetp, t, byte_order); + WINDOW(window); + ATOM(property); + ATOM(type); + v8 = CARD8(format); + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 3, ENC_NA); + *offsetp += 3; + v32 = CARD32(data_length); + switch (v8) { + case 8: + if (v32) + LISTofBYTE(data, v32); + break; + case 16: + if (v32) + LISTofCARD16(data16, v32 * 2); + break; + case 32: + if (v32) + LISTofCARD32(data32, v32 * 4); + break; + default: + expert_add_info(pinfo, ti, &ei_x11_invalid_format); + break; + } + PAD(); + break; + + case X_DeleteProperty: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + requestLength(tvb, offsetp, t, byte_order); + WINDOW(window); + ATOM(property); + break; + + case X_GetProperty: + BOOL(delete); + requestLength(tvb, offsetp, t, byte_order); + WINDOW(window); + ATOM(property); + ATOM(get_property_type); + CARD32(long_offset); + CARD32(long_length); + break; + + case X_ListProperties: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + requestLength(tvb, offsetp, t, byte_order); + WINDOW(window); + break; + + case X_SetSelectionOwner: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + requestLength(tvb, offsetp, t, byte_order); + WINDOW(owner); + ATOM(selection); + TIMESTAMP(time); + break; + + case X_GetSelectionOwner: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + requestLength(tvb, offsetp, t, byte_order); + ATOM(selection); + break; + + case X_ConvertSelection: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + requestLength(tvb, offsetp, t, byte_order); + WINDOW(requestor); + ATOM(selection); + ATOM(target); + ATOM(property); + TIMESTAMP(time); + break; + + case X_SendEvent: + BOOL(propagate); + requestLength(tvb, offsetp, t, byte_order); + WINDOW(destination); + SETofEVENT(event_mask); + EVENT(); + break; + + case X_GrabPointer: + BOOL(owner_events); + requestLength(tvb, offsetp, t, byte_order); + WINDOW(grab_window); + SETofPOINTEREVENT(pointer_event_mask); + ENUM8(pointer_mode); + ENUM8(keyboard_mode); + WINDOW(confine_to); + CURSOR(cursor); + TIMESTAMP(time); + break; + + case X_UngrabPointer: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + requestLength(tvb, offsetp, t, byte_order); + TIMESTAMP(time); + break; + + case X_GrabButton: + BOOL(owner_events); + requestLength(tvb, offsetp, t, byte_order); + WINDOW(grab_window); + SETofPOINTEREVENT(event_mask); + ENUM8(pointer_mode); + ENUM8(keyboard_mode); + WINDOW(confine_to); + CURSOR(cursor); + BUTTON(button); + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + SETofKEYMASK(modifiers); + break; + + case X_UngrabButton: + BUTTON(button); + requestLength(tvb, offsetp, t, byte_order); + WINDOW(grab_window); + SETofKEYMASK(modifiers); + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 2, ENC_NA); + *offsetp += 2; + break; + + case X_ChangeActivePointerGrab: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + requestLength(tvb, offsetp, t, byte_order); + CURSOR(cursor); + TIMESTAMP(time); + SETofPOINTEREVENT(event_mask); + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 2, ENC_NA); + *offsetp += 2; + break; + + case X_GrabKeyboard: + BOOL(owner_events); + requestLength(tvb, offsetp, t, byte_order); + WINDOW(grab_window); + TIMESTAMP(time); + ENUM8(pointer_mode); + ENUM8(keyboard_mode); + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 2, ENC_NA); + *offsetp += 2; + break; + + case X_UngrabKeyboard: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + requestLength(tvb, offsetp, t, byte_order); + TIMESTAMP(time); + break; + + case X_GrabKey: + BOOL(owner_events); + requestLength(tvb, offsetp, t, byte_order); + WINDOW(grab_window); + SETofKEYMASK(modifiers); + KEYCODE(key); + ENUM8(pointer_mode); + ENUM8(keyboard_mode); + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 3, ENC_NA); + *offsetp += 3; + break; + + case X_UngrabKey: + KEYCODE(key); + requestLength(tvb, offsetp, t, byte_order); + WINDOW(grab_window); + SETofKEYMASK(modifiers); + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 2, ENC_NA); + *offsetp += 2; + break; + + case X_AllowEvents: + ENUM8(allow_events_mode); + requestLength(tvb, offsetp, t, byte_order); + TIMESTAMP(time); + break; + + case X_GrabServer: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + requestLength(tvb, offsetp, t, byte_order); + break; + + case X_UngrabServer: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + requestLength(tvb, offsetp, t, byte_order); + break; + + case X_QueryPointer: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + requestLength(tvb, offsetp, t, byte_order); + WINDOW(window); + break; + + case X_GetMotionEvents: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + requestLength(tvb, offsetp, t, byte_order); + WINDOW(window); + TIMESTAMP(start); + TIMESTAMP(stop); + break; + + case X_TranslateCoords: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + requestLength(tvb, offsetp, t, byte_order); + WINDOW(src_window); + WINDOW(dst_window); + INT16(src_x); + INT16(src_y); + break; + + case X_WarpPointer: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + requestLength(tvb, offsetp, t, byte_order); + WINDOW(warp_pointer_src_window); + WINDOW(warp_pointer_dst_window); + INT16(src_x); + INT16(src_y); + CARD16(src_width); + CARD16(src_height); + INT16(dst_x); + INT16(dst_y); + break; + + case X_SetInputFocus: + ENUM8(revert_to); + requestLength(tvb, offsetp, t, byte_order); + WINDOW(focus); + TIMESTAMP(time); + break; + + case X_GetInputFocus: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + requestLength(tvb, offsetp, t, byte_order); + break; + + case X_QueryKeymap: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + requestLength(tvb, offsetp, t, byte_order); + break; + + case X_OpenFont: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + requestLength(tvb, offsetp, t, byte_order); + FONT(fid); + v16 = FIELD16(name_length); + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 2, ENC_NA); + *offsetp += 2; + STRING8(name, v16); + PAD(); + break; + + case X_CloseFont: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + requestLength(tvb, offsetp, t, byte_order); + FONT(font); + break; + + case X_QueryFont: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + requestLength(tvb, offsetp, t, byte_order); + FONTABLE(font); + break; + + case X_QueryTextExtents: + v8 = BOOL(odd_length); + requestLength(tvb, offsetp, t, byte_order); + FONTABLE(font); + STRING16(string16, (next_offset - offset - (v8 ? 2 : 0)) / 2); + PAD(); + break; + + case X_ListFonts: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + requestLength(tvb, offsetp, t, byte_order); + CARD16(max_names); + v16 = FIELD16(pattern_length); + STRING8(pattern, v16); + PAD(); + break; + + case X_ListFontsWithInfo: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + requestLength(tvb, offsetp, t, byte_order); + CARD16(max_names); + v16 = FIELD16(pattern_length); + STRING8(pattern, v16); + PAD(); + break; + + case X_SetFontPath: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + requestLength(tvb, offsetp, t, byte_order); + v16 = CARD16(str_number_in_path); + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 2, ENC_NA); + *offsetp += 2; + LISTofSTRING8(path, v16); + PAD(); + break; + + case X_GetFontPath: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + requestLength(tvb, offsetp, t, byte_order); + break; + + case X_CreatePixmap: + CARD8(depth); + requestLength(tvb, offsetp, t, byte_order); + PIXMAP(pid); + DRAWABLE(drawable); + CARD16(width); + CARD16(height); + break; + + case X_FreePixmap: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + requestLength(tvb, offsetp, t, byte_order); + PIXMAP(pixmap); + break; + + case X_CreateGC: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + requestLength(tvb, offsetp, t, byte_order); + GCONTEXT(cid); + DRAWABLE(drawable); + gcAttributes(tvb, offsetp, t, byte_order); + break; + + case X_ChangeGC: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + requestLength(tvb, offsetp, t, byte_order); + GCONTEXT(gc); + gcAttributes(tvb, offsetp, t, byte_order); + break; + + case X_CopyGC: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + requestLength(tvb, offsetp, t, byte_order); + GCONTEXT(src_gc); + GCONTEXT(dst_gc); + gcMask(tvb, offsetp, t, byte_order); + break; + + case X_SetDashes: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + requestLength(tvb, offsetp, t, byte_order); + GCONTEXT(gc); + CARD16(dash_offset); + v16 = FIELD16(dashes_length); + LISTofCARD8(dashes, v16); + PAD(); + break; + + case X_SetClipRectangles: + ENUM8(ordering); + requestLength(tvb, offsetp, t, byte_order); + GCONTEXT(gc); + INT16(clip_x_origin); + INT16(clip_y_origin); + LISTofRECTANGLE(rectangles); + break; + + case X_FreeGC: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + requestLength(tvb, offsetp, t, byte_order); + GCONTEXT(gc); + break; + + case X_ClearArea: + BOOL(exposures); + requestLength(tvb, offsetp, t, byte_order); + WINDOW(window); + INT16(x); + INT16(y); + CARD16(width); + CARD16(height); + break; + + case X_CopyArea: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + requestLength(tvb, offsetp, t, byte_order); + DRAWABLE(src_drawable); + DRAWABLE(dst_drawable); + GCONTEXT(gc); + INT16(src_x); + INT16(src_y); + INT16(dst_x); + INT16(dst_y); + CARD16(width); + CARD16(height); + break; + + case X_CopyPlane: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + requestLength(tvb, offsetp, t, byte_order); + DRAWABLE(src_drawable); + DRAWABLE(dst_drawable); + GCONTEXT(gc); + INT16(src_x); + INT16(src_y); + INT16(dst_x); + INT16(dst_y); + CARD16(width); + CARD16(height); + CARD32(bit_plane); + break; + + case X_PolyPoint: + ENUM8(coordinate_mode); + v16 = requestLength(tvb, offsetp, t, byte_order); + DRAWABLE(drawable); + GCONTEXT(gc); + LISTofPOINT(points, v16 - 12); + break; + + case X_PolyLine: + ENUM8(coordinate_mode); + v16 = requestLength(tvb, offsetp, t, byte_order); + DRAWABLE(drawable); + GCONTEXT(gc); + LISTofPOINT(points, v16 - 12); + break; + + case X_PolySegment: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + requestLength(tvb, offsetp, t, byte_order); + DRAWABLE(drawable); + GCONTEXT(gc); + LISTofSEGMENT(segments); + break; + + case X_PolyRectangle: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + requestLength(tvb, offsetp, t, byte_order); + DRAWABLE(drawable); + GCONTEXT(gc); + LISTofRECTANGLE(rectangles); + break; + + case X_PolyArc: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + requestLength(tvb, offsetp, t, byte_order); + DRAWABLE(drawable); + GCONTEXT(gc); + LISTofARC(arcs); + break; + + case X_FillPoly: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + v16 = requestLength(tvb, offsetp, t, byte_order); + DRAWABLE(drawable); + GCONTEXT(gc); + ENUM8(shape); + ENUM8(coordinate_mode); + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 2, ENC_NA); + *offsetp += 2; + LISTofPOINT(points, v16 - 16); + break; + + case X_PolyFillRectangle: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + requestLength(tvb, offsetp, t, byte_order); + DRAWABLE(drawable); + GCONTEXT(gc); + LISTofRECTANGLE(rectangles); + break; + + case X_PolyFillArc: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + requestLength(tvb, offsetp, t, byte_order); + DRAWABLE(drawable); + GCONTEXT(gc); + LISTofARC(arcs); + break; + + case X_PutImage: + ENUM8(image_format); + v16 = requestLength(tvb, offsetp, t, byte_order); + DRAWABLE(drawable); + GCONTEXT(gc); + CARD16(width); + CARD16(height); + INT16(dst_x); + INT16(dst_y); + CARD8(left_pad); + CARD8(depth); + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 2, ENC_NA); + *offsetp += 2; + LISTofBYTE(data, v16 - 24); + PAD(); + break; + + case X_GetImage: + ENUM8(image_pixmap_format); + requestLength(tvb, offsetp, t, byte_order); + DRAWABLE(drawable); + INT16(x); + INT16(y); + CARD16(width); + CARD16(height); + CARD32(plane_mask); + break; + + case X_PolyText8: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + requestLength(tvb, offsetp, t, byte_order); + DRAWABLE(drawable); + GCONTEXT(gc); + INT16(x); + INT16(y); + LISTofTEXTITEM8(items); + PAD(); + break; + + case X_PolyText16: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + requestLength(tvb, offsetp, t, byte_order); + DRAWABLE(drawable); + GCONTEXT(gc); + INT16(x); + INT16(y); + LISTofTEXTITEM16(items); + PAD(); + break; + + case X_ImageText8: + v8 = FIELD8(string_length); + requestLength(tvb, offsetp, t, byte_order); + DRAWABLE(drawable); + GCONTEXT(gc); + INT16(x); + INT16(y); + STRING8(string, v8); + PAD(); + break; + + case X_ImageText16: + v8 = FIELD8(string_length); + requestLength(tvb, offsetp, t, byte_order); + DRAWABLE(drawable); + GCONTEXT(gc); + INT16(x); + INT16(y); + STRING16(string16, v8); + PAD(); + break; + + case X_CreateColormap: + ENUM8(alloc); + requestLength(tvb, offsetp, t, byte_order); + COLORMAP(mid); + WINDOW(window); + VISUALID(visual); + break; + + case X_FreeColormap: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + requestLength(tvb, offsetp, t, byte_order); + COLORMAP(cmap); + break; + + case X_CopyColormapAndFree: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + requestLength(tvb, offsetp, t, byte_order); + COLORMAP(mid); + COLORMAP(src_cmap); + break; + + case X_InstallColormap: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + requestLength(tvb, offsetp, t, byte_order); + COLORMAP(cmap); + break; + + case X_UninstallColormap: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + requestLength(tvb, offsetp, t, byte_order); + COLORMAP(cmap); + break; + + case X_ListInstalledColormaps: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + requestLength(tvb, offsetp, t, byte_order); + WINDOW(window); + break; + + case X_AllocColor: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + requestLength(tvb, offsetp, t, byte_order); + COLORMAP(cmap); + CARD16(red); + CARD16(green); + CARD16(blue); + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 2, ENC_NA); + *offsetp += 2; + break; + + case X_AllocNamedColor: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + requestLength(tvb, offsetp, t, byte_order); + COLORMAP(cmap); + v16 = FIELD16(name_length); + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 2, ENC_NA); + *offsetp += 2; + STRING8(name, v16); + PAD(); + break; + + case X_AllocColorCells: + BOOL(contiguous); + requestLength(tvb, offsetp, t, byte_order); + COLORMAP(cmap); + CARD16(colors); + CARD16(planes); + break; + + case X_AllocColorPlanes: + BOOL(contiguous); + requestLength(tvb, offsetp, t, byte_order); + COLORMAP(cmap); + CARD16(colors); + CARD16(reds); + CARD16(greens); + CARD16(blues); + break; + + case X_FreeColors: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + v16 = requestLength(tvb, offsetp, t, byte_order); + COLORMAP(cmap); + CARD32(plane_mask); + LISTofCARD32(pixels, v16 - 12); + break; + + case X_StoreColors: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + v16 = requestLength(tvb, offsetp, t, byte_order); + COLORMAP(cmap); + LISTofCOLORITEM(color_items, v16 - 8); + break; + + case X_StoreNamedColor: + COLOR_FLAGS(color); + requestLength(tvb, offsetp, t, byte_order); + COLORMAP(cmap); + CARD32(pixel); + v16 = FIELD16(name_length); + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 2, ENC_NA); + *offsetp += 2; + STRING8(name, v16); + PAD(); + break; + + case X_QueryColors: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + v16 = requestLength(tvb, offsetp, t, byte_order); + COLORMAP(cmap); + LISTofCARD32(pixels, v16 - 8); + break; + + case X_LookupColor: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + requestLength(tvb, offsetp, t, byte_order); + COLORMAP(cmap); + v16 = FIELD16(name_length); + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 2, ENC_NA); + *offsetp += 2; + STRING8(name, v16); + PAD(); + break; + + case X_CreateCursor: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + requestLength(tvb, offsetp, t, byte_order); + CURSOR(cid); + PIXMAP(source_pixmap); + PIXMAP(mask); + CARD16(fore_red); + CARD16(fore_green); + CARD16(fore_blue); + CARD16(back_red); + CARD16(back_green); + CARD16(back_blue); + CARD16(x); + CARD16(y); + break; + + case X_CreateGlyphCursor: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + requestLength(tvb, offsetp, t, byte_order); + CURSOR(cid); + FONT(source_font); + FONT(mask_font); + CARD16(source_char); + CARD16(mask_char); + CARD16(fore_red); + CARD16(fore_green); + CARD16(fore_blue); + CARD16(back_red); + CARD16(back_green); + CARD16(back_blue); + break; + + case X_FreeCursor: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + requestLength(tvb, offsetp, t, byte_order); + CURSOR(cursor); + break; + + case X_RecolorCursor: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + requestLength(tvb, offsetp, t, byte_order); + CURSOR(cursor); + CARD16(fore_red); + CARD16(fore_green); + CARD16(fore_blue); + CARD16(back_red); + CARD16(back_green); + CARD16(back_blue); + break; + + case X_QueryBestSize: + ENUM8(class); + requestLength(tvb, offsetp, t, byte_order); + DRAWABLE(drawable); + CARD16(width); + CARD16(height); + break; + + case X_QueryExtension: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + requestLength(tvb, offsetp, t, byte_order); + v16 = FIELD16(name_length); + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 2, ENC_NA); + *offsetp += 2; + STRING8(name, v16); + PAD(); + break; + + case X_ListExtensions: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + requestLength(tvb, offsetp, t, byte_order); + break; + + case X_ChangeKeyboardMapping: + v8 = FIELD8(keycode_count); + requestLength(tvb, offsetp, t, byte_order); + v8_2 = KEYCODE(first_keycode); + v8_3 = FIELD8(keysyms_per_keycode); + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 2, ENC_NA); + *offsetp += 2; + LISTofKEYSYM(keysyms, state->keycodemap, v8_2, v8, v8_3); + break; + + case X_GetKeyboardMapping: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + requestLength(tvb, offsetp, t, byte_order); + state->request.GetKeyboardMapping.first_keycode + = KEYCODE(first_keycode); + FIELD8(count); + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 2, ENC_NA); + *offsetp += 2; + break; + + case X_ChangeKeyboardControl: + { + guint32 bitmask32; + static int * const keyboard_value_flags[] = { + &hf_x11_keyboard_value_mask_key_click_percent, + &hf_x11_keyboard_value_mask_bell_percent, + &hf_x11_keyboard_value_mask_bell_pitch, + &hf_x11_keyboard_value_mask_bell_duration, + &hf_x11_keyboard_value_mask_led, + &hf_x11_keyboard_value_mask_led_mode, + &hf_x11_keyboard_value_mask_keyboard_key, + &hf_x11_keyboard_value_mask_auto_repeat_mode, + NULL + }; + + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + requestLength(tvb, offsetp, t, byte_order); + bitmask32 = tvb_get_guint32(tvb, *offsetp, byte_order); + proto_tree_add_bitmask(t, tvb, *offsetp, hf_x11_keyboard_value_mask, ett_x11_keyboard_value_mask, keyboard_value_flags, byte_order); + *offsetp += 4; + if (bitmask32 & 0x00000001) { + proto_tree_add_item(t, hf_x11_key_click_percent, tvb, *offsetp, 1, byte_order); + *offsetp += 1; + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 3, ENC_NA); + *offsetp += 3; + } + if (bitmask32 & 0x00000002) { + proto_tree_add_item(t, hf_x11_bell_percent, tvb, *offsetp, 1, byte_order); + *offsetp += 1; + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 3, ENC_NA); + *offsetp += 3; + } + if (bitmask32 & 0x00000004) { + proto_tree_add_item(t, hf_x11_bell_pitch, tvb, *offsetp, 2, byte_order); + *offsetp += 2; + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 2, ENC_NA); + *offsetp += 2; + } + if (bitmask32 & 0x00000008) { + proto_tree_add_item(t, hf_x11_bell_duration, tvb, *offsetp, 2, byte_order); + *offsetp += 2; + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 2, ENC_NA); + *offsetp += 2; + } + if (bitmask32 & 0x00000010) { + proto_tree_add_item(t, hf_x11_led, tvb, *offsetp, 2, byte_order); + *offsetp += 2; + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 2, ENC_NA); + *offsetp += 2; + } + if (bitmask32 & 0x00000020) { + proto_tree_add_item(t, hf_x11_led_mode, tvb, *offsetp, 1, byte_order); + *offsetp += 1; + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 3, ENC_NA); + *offsetp += 3; + } + if (bitmask32 & 0x00000040) { + proto_tree_add_item(t, hf_x11_keyboard_key, tvb, *offsetp, 1, byte_order); + *offsetp += 1; + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 3, ENC_NA); + *offsetp += 3; + } + if (bitmask32 & 0x00000080) { + proto_tree_add_item(t, hf_x11_auto_repeat_mode, tvb, *offsetp, 1, byte_order); + *offsetp += 1; + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 3, ENC_NA); + *offsetp += 3; + } + } + break; + + case X_GetKeyboardControl: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + requestLength(tvb, offsetp, t, byte_order); + break; + + case X_Bell: + INT8(percent); + requestLength(tvb, offsetp, t, byte_order); + break; + + case X_ChangePointerControl: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + requestLength(tvb, offsetp, t, byte_order); + INT16(acceleration_numerator); + INT16(acceleration_denominator); + INT16(threshold); + BOOL(do_acceleration); + BOOL(do_threshold); + break; + + case X_GetPointerControl: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + requestLength(tvb, offsetp, t, byte_order); + break; + + case X_SetScreenSaver: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + requestLength(tvb, offsetp, t, byte_order); + INT16(timeout); + INT16(interval); + ENUM8(prefer_blanking); + ENUM8(allow_exposures); + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 2, ENC_NA); + *offsetp += 2; + break; + + case X_GetScreenSaver: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + requestLength(tvb, offsetp, t, byte_order); + break; + + case X_ChangeHosts: + ENUM8(change_host_mode); + requestLength(tvb, offsetp, t, byte_order); + v8 = ENUM8(family); + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + v16 = CARD16(address_length); + if (v8 == FAMILY_INTERNET && v16 == 4) { + /* + * IPv4 addresses. + * XXX - what about IPv6? Is that a family of + * FAMILY_INTERNET (0) with a length of 16? + */ + LISTofIPADDRESS(ip_address, v16); + } else + LISTofCARD8(address, v16); + break; + + case X_ListHosts: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + requestLength(tvb, offsetp, t, byte_order); + break; + + case X_SetAccessControl: + ENUM8(access_mode); + requestLength(tvb, offsetp, t, byte_order); + break; + + case X_SetCloseDownMode: + ENUM8(close_down_mode); + requestLength(tvb, offsetp, t, byte_order); + break; + + case X_KillClient: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + requestLength(tvb, offsetp, t, byte_order); + CARD32(resource); + break; + + case X_RotateProperties: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + v16 = requestLength(tvb, offsetp, t, byte_order); + WINDOW(window); + CARD16(property_number); + INT16(delta); + LISTofATOM(properties, (v16 - 12)); + break; + + case X_ForceScreenSaver: + ENUM8(screen_saver_mode); + requestLength(tvb, offsetp, t, byte_order); + break; + + case X_SetPointerMapping: + v8 = FIELD8(map_length); + requestLength(tvb, offsetp, t, byte_order); + LISTofCARD8(map, v8); + PAD(); + break; + + case X_GetPointerMapping: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + requestLength(tvb, offsetp, t, byte_order); + break; + + case X_SetModifierMapping: + v8 = FIELD8(keycodes_per_modifier); + requestLength(tvb, offsetp, t, byte_order); + LISTofKEYCODE(state->modifiermap, keycodes, v8); + break; + + case X_GetModifierMapping: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + requestLength(tvb, offsetp, t, byte_order); + break; + + case X_NoOperation: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + requestLength(tvb, offsetp, t, byte_order); + break; + default: + tryExtension(opcode, tvb, pinfo, offsetp, t, state, byte_order); + break; + } + + if ((left = tvb_reported_length_remaining(tvb, offset)) > 0) + UNDECODED(left); +} + +static void dissect_x11_requests(tvbuff_t *tvb, packet_info *pinfo, + proto_tree *tree) +{ + volatile int offset = 0; + int length_remaining; + volatile guint byte_order; + guint8 opcode; + volatile gint plen; + proto_item *ti; + volatile gboolean is_initial_creq; + guint16 auth_proto_len, auth_data_len; + const char *volatile sep = NULL; + conversation_t *conversation; + x11_conv_data_t *volatile state; + int length; + tvbuff_t *volatile next_tvb; + + while ((length_remaining = tvb_reported_length_remaining(tvb, offset)) > 0) { + + /* + * Can we do reassembly? + */ + if (x11_desegment && pinfo->can_desegment) { + /* + * Yes - is the X11 request header split across + * segment boundaries? + */ + if (length_remaining < 4) { + /* + * Yes. Tell the TCP dissector where the data + * for this message starts in the data it handed + * us and that we need "some more data." Don't tell + * it exactly how many bytes we need because if/when + * we ask for even more (after the header) that will + * break reassembly. + */ + pinfo->desegment_offset = offset; + pinfo->desegment_len = DESEGMENT_ONE_MORE_SEGMENT; + return; + } + } + + /* + * Get the state for this conversation; create the conversation + * if we don't have one, and create the state if we don't have + * any. + */ + conversation = find_or_create_conversation(pinfo); + + /* + * Is there state attached to this conversation? + */ + if ((state = (x11_conv_data_t *)conversation_get_proto_data(conversation, proto_x11)) + == NULL) + state = x11_stateinit(conversation); + + /* + * Guess the byte order if we don't already know it. + */ + byte_order = guess_byte_ordering(tvb, pinfo, state); + + /* + * Get the opcode and length of the putative X11 request. + */ + opcode = tvb_get_guint8(tvb, 0); + plen = tvb_get_guint16(tvb, offset + 2, byte_order); + + if (plen == 0) { + /* + * A length field of 0 indicates that the BIG-REQUESTS + * extension is used: The next four bytes are the real length. + */ + plen = tvb_get_guint32(tvb, offset + 4, byte_order); + } + + if (plen <= 0) { + /* + * This can't be less then 0, as it includes the header length. + * A different choice of byte order wouldn't have + * helped. + * Give up. + */ + ti = proto_tree_add_item(tree, proto_x11, tvb, offset, -1, ENC_NA); + expert_add_info_format(pinfo, ti, &ei_x11_request_length, "Bogus request length (%d)", plen); + return; + } + + if (state->iconn_frame == pinfo->num || + (wmem_map_lookup(state->seqtable, + GINT_TO_POINTER(state->sequencenumber)) == (int *)NOTHING_SEEN && + (opcode == 'B' || opcode == 'l') && + (plen == 11 || plen == 2816))) { + /* + * Either + * + * we saw this on the first pass and this is + * it again + * + * or + * we haven't already seen any requests, the first + * byte of the message is 'B' or 'l', and the 16-bit + * integer 2 bytes into the data stream is either 11 + * or a byte-swapped 11. + * + * This means it's probably an initial connection + * request, not a message. + * + * 'B' is decimal 66, which is the opcode for a + * PolySegment request; unfortunately, 11 is a valid + * length for a PolySegment request request, so we + * might mis-identify that request. (Are there any + * other checks we can do?) + * + * 'l' is decimal 108, which is the opcode for a + * GetScreenSaver request; the only valid length + * for that request is 1. + */ + is_initial_creq = TRUE; + + /* + * We now know the byte order. Override the guess. + */ + if (state->byte_order == BYTE_ORDER_UNKNOWN) { + if (opcode == 'B') { + /* + * Big-endian. + */ + byte_order = state->byte_order = ENC_BIG_ENDIAN; + } else { + /* + * Little-endian. + */ + byte_order = state->byte_order = ENC_LITTLE_ENDIAN; + } + } + + /* + * Can we do reassembly? + */ + if (x11_desegment && pinfo->can_desegment) { + /* + * Yes - is the fixed-length portion of the + * initial connection header split across + * segment boundaries? + */ + if (length_remaining < 10) { + /* + * Yes. Tell the TCP dissector where the + * data for this message starts in the data + * it handed us and that we need "some more + * data." Don't tell it exactly how many bytes + * we need because if/when we ask for even more + * (after the header) that will break reassembly. + */ + pinfo->desegment_offset = offset; + pinfo->desegment_len = DESEGMENT_ONE_MORE_SEGMENT; + return; + } + } + + /* + * Get the lengths of the authorization protocol and + * the authorization data. + */ + auth_proto_len = tvb_get_guint16(tvb, offset + 6, byte_order); + auth_data_len = tvb_get_guint16(tvb, offset + 8, byte_order); + plen = 12 + ROUND_LENGTH(auth_proto_len) + + ROUND_LENGTH(auth_data_len); + } else { + volatile gint64 tmp = (gint64)plen * 4; + /* + * This is probably an ordinary request. + */ + is_initial_creq = FALSE; + + /* + * The length of a request is in 4-byte words. + */ + if (tmp > G_MAXINT32) { + ti = proto_tree_add_item(tree, proto_x11, tvb, offset, -1, ENC_NA); + expert_add_info_format(pinfo, ti, &ei_x11_request_length, "Bogus request length (%"PRId64")", tmp); + return; + } + plen = (gint)tmp; + } + + /* + * Can we do reassembly? + */ + if (x11_desegment && pinfo->can_desegment) { + /* + * Yes - is the X11 request split across segment + * boundaries? + */ + if (length_remaining < plen) { + /* + * Yes. Tell the TCP dissector where the data + * for this message starts in the data it handed + * us, and how many more bytes we need, and return. + */ + pinfo->desegment_offset = offset; + pinfo->desegment_len = plen - length_remaining; + return; + } + } + + /* + * Construct a tvbuff containing the amount of the payload + * we have available. Make its reported length the + * amount of data in the X11 request. + * + * XXX - if reassembly isn't enabled. the subdissector + * will throw a BoundsError exception, rather than a + * ReportedBoundsError exception. We really want a tvbuff + * where the length is "length", the reported length is "plen", + * and the "if the snapshot length were infinite" length is the + * minimum of the reported length of the tvbuff handed to us + * and "plen", with a new type of exception thrown if the offset + * is within the reported length but beyond that third length, + * with that exception getting the "Unreassembled Packet" error. + */ + length = length_remaining; + if (length > plen) + length = plen; + next_tvb = tvb_new_subset_length_caplen(tvb, offset, length, plen); + + /* + * Set the column appropriately. + */ + if (is_initial_creq) { + col_set_str(pinfo->cinfo, COL_INFO, "Initial connection request"); + } else { + if (sep == NULL) { + /* + * We haven't set the column yet; set it. + */ + col_set_str(pinfo->cinfo, COL_INFO, "Requests"); + + /* + * Initialize the separator. + */ + sep = ":"; + } + } + + /* + * Dissect the X11 request. + * + * Catch the ReportedBoundsError exception; if this + * particular message happens to get a ReportedBoundsError + * exception, that doesn't mean that we should stop + * dissecting X11 requests within this frame or chunk of + * reassembled data. + * + * If it gets a BoundsError, we can stop, as there's nothing + * more to see, so we just re-throw it. + */ + TRY { + if (is_initial_creq) { + dissect_x11_initial_conn(next_tvb, pinfo, tree, + state, byte_order); + } else { + dissect_x11_request(next_tvb, pinfo, tree, sep, + state, byte_order); + } + } + CATCH_NONFATAL_ERRORS { + show_exception(tvb, pinfo, tree, EXCEPT_CODE, GET_MESSAGE); + } + ENDTRY; + + /* + * Skip the X11 message. + */ + offset += plen; + + sep = ","; + } +} + +static x11_conv_data_t * +x11_stateinit(conversation_t *conversation) +{ + x11_conv_data_t *state; + static x11_conv_data_t stateinit; + int i; + + state = wmem_new(wmem_file_scope(), x11_conv_data_t); + *state = stateinit; + + /* initialise opcodes */ + for (i = 0; opcode_vals[i].strptr != NULL; i++) { + state->opcode_vals[i].value = opcode_vals[i].value; + state->opcode_vals[i].strptr = opcode_vals[i].strptr; + } + for (; i <= MAX_OPCODES; i++) { + state->opcode_vals[i].value = 0; + state->opcode_vals[i].strptr = NULL; + } + + /* initialise errorcodes */ + for (i = 0; errorcode_vals[i].strptr != NULL; i++) { + state->errorcode_vals[i].value = errorcode_vals[i].value; + state->errorcode_vals[i].strptr = errorcode_vals[i].strptr; + } + for (; i <= LastExtensionError + 1; i++) { + state->errorcode_vals[i].value = 0; + state->errorcode_vals[i].strptr = NULL; + } + + /* initialise eventcodes */ + for (i = 0; eventcode_vals[i].strptr != NULL; i++) { + state->eventcode_vals[i].value = eventcode_vals[i].value; + state->eventcode_vals[i].strptr = eventcode_vals[i].strptr; + } + for (; i <= LastExtensionEvent + 1; i++) { + state->eventcode_vals[i].value = 0; + state->eventcode_vals[i].strptr = NULL; + } + state->eventcode_funcs = wmem_map_new(wmem_file_scope(), g_direct_hash, g_direct_equal); + state->reply_funcs = wmem_map_new(wmem_file_scope(), g_direct_hash, g_direct_equal); + + state->seqtable = wmem_map_new(wmem_file_scope(), g_direct_hash, g_direct_equal); + state->valtable = wmem_map_new(wmem_file_scope(), g_direct_hash, g_direct_equal); + wmem_map_insert(state->seqtable, (int *)0, (int *)NOTHING_SEEN); + state->byte_order = BYTE_ORDER_UNKNOWN; /* don't know yet*/ + conversation_add_proto_data(conversation, proto_x11, state); + return state; +} + + +static void +dissect_x11_replies(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) +{ +/* Set up structures we will need to add the protocol subtree and manage it */ + volatile int offset, plen; + tvbuff_t *volatile next_tvb; + conversation_t *conversation; + x11_conv_data_t *volatile state; + volatile guint byte_order; + int length_remaining; + const char *volatile sep = NULL; + + + /* + * Get the state for this conversation; create the conversation + * if we don't have one, and create the state if we don't have + * any. + */ + conversation = find_or_create_conversation(pinfo); + + /* + * Is there state attached to this conversation? + */ + if ((state = (x11_conv_data_t *)conversation_get_proto_data(conversation, proto_x11)) + == NULL) { + /* + * No - create a state structure and attach it. + */ + state = x11_stateinit(conversation); + } + + /* + * Guess the byte order if we don't already know it. + */ + byte_order = guess_byte_ordering(tvb, pinfo, state); + + offset = 0; + while ((length_remaining = tvb_reported_length_remaining(tvb, offset)) > 0) { + /* + * Can we do reassembly? + */ + if (x11_desegment && pinfo->can_desegment) { + /* + * Yes - is the X11 Reply or GenericEvent header split across + * segment boundaries? + */ + if (length_remaining < 8) { + /* + * Yes. Tell the TCP dissector where the data + * for this message starts in the data it handed + * us and that we need "some more data." Don't tell + * it exactly how many bytes we need because if/when + * we ask for even more (after the header) that will + * break reassembly. + */ + pinfo->desegment_offset = offset; + pinfo->desegment_len = DESEGMENT_ONE_MORE_SEGMENT; + return; + } + } + + /* + * Find out what kind of a reply it is. + * There are four possible: + * - reply to initial connection + * - errorreply (a request generated an error) + * - requestreply (reply to a request) + * - event (some event occurred) + */ + if (wmem_map_lookup(state->seqtable, + GINT_TO_POINTER(state->sequencenumber)) == (int *)INITIAL_CONN + || (state->iconn_reply == pinfo->num)) { + /* + * Either the connection is in the "initial + * connection" state, or this frame is known + * to have the initial connection reply. + * That means this is the initial connection + * reply. + */ + plen = 8 + tvb_get_guint16(tvb, offset + 6, byte_order) * 4; + + HANDLE_REPLY(plen, length_remaining, + "Initial connection reply", + dissect_x11_initial_reply); + } else { + /* + * This isn't an initial connection reply + * (XXX - unless we missed the initial + * connection request). Look at the first + * byte to determine what it is; errors + * start with a byte of 0, replies start + * with a byte of 1, events start with + * a byte with of 2 or greater. + */ + switch (tvb_get_guint8(tvb, offset)) { + + case 0: + plen = 32; + HANDLE_REPLY(plen, length_remaining, + "Error", dissect_x11_error); + break; + + case 1: + { + /* To avoid an "assert w/side-effect" warning, + * use a non-volatile temp variable instead. */ + int tmp_plen; + + /* replylength is in units of four. */ + tmp_plen = plen = 32 + tvb_get_guint32(tvb, offset + 4, byte_order) * 4; + /* If tmp_plen < 32, we got an overflow; + * the reply length is too long. */ + THROW_ON(tmp_plen < 32, ReportedBoundsError); + HANDLE_REPLY(plen, length_remaining, + "Reply", dissect_x11_reply); + break; + } + + case GenericEvent: + { + /* An Event, but with a length field like a Reply. */ + + /* To avoid an "assert w/side-effect" warning, + * use a non-volatile temp variable instead. */ + int tmp_plen; + + /* GenericEvent's length is also in units of four. */ + tmp_plen = plen = 32 + tvb_get_guint32(tvb, offset + 4, byte_order) * 4; + /* If tmp_plen < 32, we got an overflow; + * the event length is too long. */ + THROW_ON(tmp_plen < 32, ReportedBoundsError); + HANDLE_REPLY(plen, length_remaining, + "Event", dissect_x11_event); + break; + } + + default: + /* Event */ + plen = 32; + HANDLE_REPLY(plen, length_remaining, + "Event", dissect_x11_event); + break; + } + } + + offset += plen; + } + + return; +} + +static void +dissect_x11_reply(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, + const char *sep, x11_conv_data_t *state, + guint byte_order) +{ + int offset = 0, *offsetp = &offset, length, left, opcode; + int major_opcode, sequence_number, first_error, first_event; + value_string *vals_p; + proto_item *ti; + proto_tree *t; + + ti = proto_tree_add_item(tree, proto_x11, tvb, 0, -1, ENC_NA); + t = proto_item_add_subtree(ti, ett_x11); + + + /* + * XXX - this doesn't work correctly if either + * + * 1) the request sequence number wraps in the lower 16 + * bits; + * + * 2) we don't see the initial connection request and the + * resynchronization of sequence number fails and thus + * don't have the right sequence numbers + * + * 3) we don't have all the packets in the capture and + * get out of sequence. + * + * We might, instead, want to assume that a reply is a reply to + * the most recent not-already-replied-to request in the same + * connection. That also might mismatch replies to requests if + * packets are lost, but there's nothing you can do to fix that. + */ + + sequence_number = tvb_get_guint16(tvb, offset + 2, byte_order); + opcode = GPOINTER_TO_INT(wmem_map_lookup(state->seqtable, + GINT_TO_POINTER(sequence_number))); + + if (state->iconn_frame == 0 && state->resync == FALSE) { + + /* + * We don't see the initial connection request and no + * resynchronization has been performed yet (first reply), + * set the current sequence number to the one of the + * current reply (this is only performed once). + */ + state->sequencenumber = sequence_number; + state->resync = TRUE; + } + + if (opcode == UNKNOWN_OPCODE) { + col_append_fstr(pinfo->cinfo, COL_INFO, + "%s to unknown request", sep); + proto_item_append_text(ti, ", Reply to unknown request"); + } else { + col_append_fstr(pinfo->cinfo, COL_INFO, "%s %s", + sep, + val_to_str(opcode & 0xFF, state->opcode_vals, + "<Unknown opcode %d>")); + + if (opcode > 0xFF) + proto_item_append_text(ti, ", Reply, opcode: %d.%d (%s)", + opcode & 0xFF, opcode >> 8, val_to_str(opcode & 0xFF, + state->opcode_vals, + "<Unknown opcode %d>")); + else + proto_item_append_text(ti, ", Reply, opcode: %d (%s)", + opcode, val_to_str(opcode, + state->opcode_vals, + "<Unknown opcode %d>")); + } + + switch (opcode) { + + /* + * Replies that need special processing outside tree + */ + + case X_QueryExtension: + + /* + * if extension is present and request is known: + * store opcode of extension in value_string of + * opcodes + */ + if (!tvb_get_guint8(tvb, offset + 8)) { + /* not present */ + break; + } + + vals_p = (value_string *)wmem_map_lookup(state->valtable, + GINT_TO_POINTER(sequence_number)); + if (vals_p != NULL) { + major_opcode = tvb_get_guint8(tvb, offset + 9); + first_event = tvb_get_guint8(tvb, offset + 10); + first_error = tvb_get_guint8(tvb, offset + 11); + + register_extension(state, vals_p, major_opcode, first_event, first_error); + wmem_map_remove(state->valtable, + GINT_TO_POINTER(sequence_number)); + } + break; + + default: + break; + } + + if (tree == NULL) + return; + + switch (opcode) { + /* + * Requests that expect a reply. + */ + + case X_GetWindowAttributes: + REPLYCONTENTS_COMMON(); + break; + + case X_GetGeometry: + REPLY(reply); + CARD8(depth); + SEQUENCENUMBER_REPLY(sequencenumber); + REPLYLENGTH(replylength); + WINDOW(rootwindow); + INT16(x); + INT16(y); + CARD16(width); + CARD16(height); + CARD16(border_width); + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 10, ENC_NA); + *offsetp += 10; + break; + + case X_QueryTree: + REPLYCONTENTS_COMMON(); + break; + + case X_InternAtom: + REPLY(reply); + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + SEQUENCENUMBER_REPLY(sequencenumber); + REPLYLENGTH(replylength); + ATOM(atom); + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 20, ENC_NA); + *offsetp += 20; + break; + + case X_GetAtomName: + REPLYCONTENTS_COMMON(); + break; + + case X_GetProperty: + REPLY(reply); + CARD8(format); + SEQUENCENUMBER_REPLY(sequencenumber); + REPLYLENGTH(replylength); + ATOM(get_property_type); + CARD32(bytes_after); + CARD32(valuelength); + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 12, ENC_NA); + *offsetp += 12; + break; + + case X_ListProperties: + REPLY(reply); + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + SEQUENCENUMBER_REPLY(sequencenumber); + REPLYLENGTH(replylength); + length = CARD16(property_number); + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 22, ENC_NA); + *offsetp += 22; + LISTofATOM(properties, length*4); + break; + + case X_GetSelectionOwner: + REPLY(reply); + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + SEQUENCENUMBER_REPLY(sequencenumber); + REPLYLENGTH(replylength); + WINDOW(owner); + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 20, ENC_NA); + *offsetp += 20; + break; + + case X_GrabPointer: + case X_GrabKeyboard: + REPLY(reply); + ENUM8(grab_status); + SEQUENCENUMBER_REPLY(sequencenumber); + REPLYLENGTH(replylength); + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 24, ENC_NA); + *offsetp += 24; + break; + + case X_QueryPointer: + REPLY(reply); + BOOL(same_screen); + SEQUENCENUMBER_REPLY(sequencenumber); + REPLYLENGTH(replylength); + WINDOW(rootwindow); + WINDOW(childwindow); + INT16(root_x); + INT16(root_y); + INT16(win_x); + INT16(win_y); + SETofKEYBUTMASK(mask); + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 6, ENC_NA); + *offsetp += 6; + break; + + case X_GetMotionEvents: + REPLYCONTENTS_COMMON(); + break; + + case X_TranslateCoords: + REPLY(reply); + BOOL(same_screen); + SEQUENCENUMBER_REPLY(sequencenumber); + REPLYLENGTH(replylength); + WINDOW(childwindow); + INT16(dst_x); + INT16(dst_y); + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 16, ENC_NA); + *offsetp += 16; + break; + + case X_GetInputFocus: + REPLY(reply); + ENUM8(revert_to); + SEQUENCENUMBER_REPLY(sequencenumber); + REPLYLENGTH(replylength); + WINDOW(focus); + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 20, ENC_NA); + *offsetp += 20; + break; + + case X_QueryKeymap: + REPLY(reply); + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + SEQUENCENUMBER_REPLY(sequencenumber); + REPLYLENGTH(replylength); + LISTofCARD8(keys, 32); + break; + + case X_QueryFont: + case X_QueryTextExtents: + case X_ListFonts: + case X_GetImage: + case X_ListInstalledColormaps: + REPLYCONTENTS_COMMON(); + break; + + case X_AllocColor: + REPLY(reply); + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + SEQUENCENUMBER_REPLY(sequencenumber); + REPLYLENGTH(replylength); + CARD16(red); + CARD16(green); + CARD16(blue); + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 2, ENC_NA); + *offsetp += 2; + CARD32(pixel); + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 12, ENC_NA); + *offsetp += 12; + break; + + case X_QueryColors: + REPLYCONTENTS_COMMON(); + break; + + case X_LookupColor: + REPLY(reply); + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + SEQUENCENUMBER_REPLY(sequencenumber); + REPLYLENGTH(replylength); + CARD16(exact_red); + CARD16(exact_green); + CARD16(exact_blue); + CARD16(visual_red); + CARD16(visual_green); + CARD16(visual_blue); + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 12, ENC_NA); + *offsetp += 12; + break; + + case X_QueryBestSize: + REPLY(reply); + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + SEQUENCENUMBER_REPLY(sequencenumber); + REPLYLENGTH(replylength); + CARD16(width); + CARD16(height); + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 20, ENC_NA); + *offsetp += 20; + break; + + case X_QueryExtension: + REPLY(reply); + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + SEQUENCENUMBER_REPLY(sequencenumber); + REPLYLENGTH(replylength); + BOOL(present); + CARD8(major_opcode); + CARD8(first_event); + CARD8(first_error); + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 20, ENC_NA); + *offsetp += 20; + break; + + case X_ListExtensions: + REPLYCONTENTS_COMMON(); + break; + + case X_GetKeyboardMapping: + state->first_keycode = + state->request.GetKeyboardMapping.first_keycode; + REPLY(reply); + state->keysyms_per_keycode = + FIELD8(keysyms_per_keycode); + SEQUENCENUMBER_REPLY(sequencenumber); + length = REPLYLENGTH(replylength); + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 24, ENC_NA); + *offsetp += 24; + LISTofKEYSYM(keysyms, state->keycodemap, + state->request.GetKeyboardMapping.first_keycode, + /* XXX - length / state->keysyms_per_keycode can raise a division by zero, + * don't know if this is the *right* way to fix it ... */ + state->keysyms_per_keycode ? length / state->keysyms_per_keycode : 0, + state->keysyms_per_keycode); + break; + + case X_GetKeyboardControl: + REPLYCONTENTS_COMMON(); + break; + + case X_GetPointerControl: + REPLY(reply); + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + SEQUENCENUMBER_REPLY(sequencenumber); + REPLYLENGTH(replylength); + CARD16(acceleration_numerator); + CARD16(acceleration_denominator); + CARD16(threshold); + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 18, ENC_NA); + *offsetp += 18; + break; + + case X_GetScreenSaver: + REPLY(reply); + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + SEQUENCENUMBER_REPLY(sequencenumber); + REPLYLENGTH(replylength); + CARD16(timeout); + CARD16(interval); + ENUM8(prefer_blanking); + ENUM8(allow_exposures); + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 18, ENC_NA); + *offsetp += 18; + break; + + case X_ListHosts: + case X_SetPointerMapping: + case X_GetPointerMapping: + case X_SetModifierMapping: + REPLYCONTENTS_COMMON(); + break; + + case X_GetModifierMapping: + REPLY(reply); + state->keycodes_per_modifier = + FIELD8(keycodes_per_modifier); + SEQUENCENUMBER_REPLY(sequencenumber); + REPLYLENGTH(replylength); + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 24, ENC_NA); + *offsetp += 24; + LISTofKEYCODE(state->modifiermap, keycodes, + state->keycodes_per_modifier); + break; + + case UNKNOWN_OPCODE: + REPLYCONTENTS_COMMON(); + break; + + default: + tryExtensionReply(opcode, tvb, pinfo, offsetp, t, state, byte_order); + } + + if ((left = tvb_reported_length_remaining(tvb, offset)) > 0) + UNDECODED(left); +} + +static void +same_screen_focus(tvbuff_t *tvb, int *offsetp, proto_tree *t) +{ + proto_item *ti; + guint32 bitmask_value; + int bitmask_offset; + int bitmask_size; + proto_tree *bitmask_tree; + + bitmask_value = tvb_get_guint8(tvb, *offsetp); + bitmask_offset = *offsetp; + bitmask_size = 1; + + ti = proto_tree_add_uint(t, hf_x11_same_screen_focus_mask, tvb, *offsetp, 1, + bitmask_value); + bitmask_tree = proto_item_add_subtree(ti, ett_x11_same_screen_focus); + FLAG(same_screen_focus, focus); + FLAG(same_screen_focus, same_screen); + + *offsetp += 1; +} + +static void +dissect_x11_event(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, + const char *sep, x11_conv_data_t *state, + guint byte_order) +{ + unsigned char eventcode; + const char *sent; + proto_item *ti; + proto_tree *t; + + ti = proto_tree_add_item(tree, proto_x11, tvb, 0, -1, ENC_NA); + t = proto_item_add_subtree(ti, ett_x11); + + eventcode = tvb_get_guint8(tvb, 0); + sent = (eventcode & 0x80) ? "Sent-" : ""; + + col_append_fstr(pinfo->cinfo, COL_INFO, "%s %s%s", + sep, sent, + val_to_str(eventcode & 0x7F, state->eventcode_vals, + "<Unknown eventcode %u>")); + + proto_item_append_text(ti, ", Event, eventcode: %d (%s%s)", + eventcode, sent, + val_to_str(eventcode & 0x7F, state->eventcode_vals, + "<Unknown eventcode %u>")); + + if (tree == NULL) + return; + + decode_x11_event(tvb, eventcode, sent, t, state, byte_order); + + return; +} + +static void +decode_x11_event(tvbuff_t *tvb, unsigned char eventcode, const char *sent, + proto_tree *t, x11_conv_data_t *state, + guint byte_order) +{ + int offset = 0, *offsetp = &offset, left; + + proto_tree_add_uint_format(t, hf_x11_eventcode, tvb, offset, 1, + eventcode, + "eventcode: %d (%s%s)", + eventcode, sent, + val_to_str(eventcode & 0x7F, state->eventcode_vals, + "<Unknown eventcode %u>")); + ++offset; + + switch (eventcode & 0x7F) { + case KeyPress: + case KeyRelease: { + int code, mask; + + /* need to do some prefetching here ... */ + code = tvb_get_guint8(tvb, offset); + mask = tvb_get_guint16(tvb, 28, byte_order); + + KEYCODE_DECODED(keycode, code, mask); + CARD16(event_sequencenumber); + EVENTCONTENTS_COMMON(); + BOOL(same_screen); + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + break; + } + + case ButtonPress: + case ButtonRelease: + BUTTON(eventbutton); + CARD16(event_sequencenumber); + EVENTCONTENTS_COMMON(); + BOOL(same_screen); + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + break; + + case MotionNotify: + CARD8(detail); + CARD16(event_sequencenumber); + EVENTCONTENTS_COMMON(); + BOOL(same_screen); + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + break; + + case EnterNotify: + case LeaveNotify: + ENUM8(event_detail); + CARD16(event_sequencenumber); + EVENTCONTENTS_COMMON(); + ENUM8(grab_mode); + same_screen_focus(tvb, offsetp, t); + break; + + case FocusIn: + case FocusOut: + ENUM8(focus_detail); + CARD16(event_sequencenumber); + WINDOW(eventwindow); + ENUM8(focus_mode); + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 23, ENC_NA); + *offsetp += 23; + break; + + case KeymapNotify: + break; + + case Expose: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + CARD16(event_sequencenumber); + WINDOW(eventwindow); + INT16(x); + INT16(y); + CARD16(width); + CARD16(height); + CARD16(count); + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 14, ENC_NA); + *offsetp += 14; + break; + + case GraphicsExpose: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + CARD16(event_sequencenumber); + DRAWABLE(drawable); + CARD16(x); + CARD16(y); + CARD16(width); + CARD16(height); + CARD16(minor_opcode); + CARD16(count); + CARD8(major_opcode); + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 11, ENC_NA); + *offsetp += 11; + break; + + case NoExpose: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + CARD16(event_sequencenumber); + DRAWABLE(drawable); + CARD16(minor_opcode); + CARD8(major_opcode); + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 21, ENC_NA); + *offsetp += 21; + break; + + case VisibilityNotify: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + CARD16(event_sequencenumber); + WINDOW(eventwindow); + ENUM8(visibility_state); + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 23, ENC_NA); + *offsetp += 23; + break; + + case CreateNotify: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + CARD16(event_sequencenumber); + WINDOW(parent); + WINDOW(eventwindow); + INT16(x); + INT16(y); + CARD16(width); + CARD16(height); + CARD16(border_width); + BOOL(override_redirect); + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 9, ENC_NA); + *offsetp += 9; + break; + + case DestroyNotify: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + CARD16(event_sequencenumber); + WINDOW(eventwindow); + WINDOW(window); + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 20, ENC_NA); + *offsetp += 20; + break; + + case UnmapNotify: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + CARD16(event_sequencenumber); + WINDOW(eventwindow); + WINDOW(window); + BOOL(from_configure); + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 19, ENC_NA); + *offsetp += 19; + break; + + case MapNotify: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + CARD16(event_sequencenumber); + WINDOW(eventwindow); + WINDOW(window); + BOOL(override_redirect); + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 19, ENC_NA); + *offsetp += 19; + break; + + case MapRequest: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + CARD16(event_sequencenumber); + WINDOW(parent); + WINDOW(eventwindow); + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 20, ENC_NA); + *offsetp += 20; + break; + + case ReparentNotify: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + CARD16(event_sequencenumber); + WINDOW(eventwindow); + WINDOW(window); + WINDOW(parent); + INT16(x); + INT16(y); + BOOL(override_redirect); + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 11, ENC_NA); + *offsetp += 11; + break; + + case ConfigureNotify: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + CARD16(event_sequencenumber); + WINDOW(eventwindow); + WINDOW(window); + WINDOW(above_sibling); + INT16(x); + INT16(y); + CARD16(width); + CARD16(height); + CARD16(border_width); + BOOL(override_redirect); + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 5, ENC_NA); + *offsetp += 5; + break; + + case ConfigureRequest: + break; + + case GravityNotify: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + CARD16(event_sequencenumber); + WINDOW(eventwindow); + WINDOW(window); + INT16(x); + INT16(y); + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 16, ENC_NA); + *offsetp += 16; + break; + + case ResizeRequest: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + CARD16(event_sequencenumber); + WINDOW(eventwindow); + CARD16(width); + CARD16(height); + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 20, ENC_NA); + *offsetp += 20; + break; + + case CirculateNotify: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + CARD16(event_sequencenumber); + WINDOW(eventwindow); + WINDOW(window); + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 4, ENC_NA); + *offsetp += 4; + ENUM8(place); + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 15, ENC_NA); + *offsetp += 15; + break; + + case CirculateRequest: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + CARD16(event_sequencenumber); + WINDOW(parent); + WINDOW(eventwindow); + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 4, ENC_NA); + *offsetp += 4; + ENUM8(place); + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 15, ENC_NA); + *offsetp += 15; + break; + + case PropertyNotify: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + CARD16(event_sequencenumber); + WINDOW(eventwindow); + ATOM(atom); + TIMESTAMP(time); + ENUM8(property_state); + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 15, ENC_NA); + *offsetp += 15; + break; + + case SelectionClear: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + CARD16(event_sequencenumber); + TIMESTAMP(time); + WINDOW(owner); + ATOM(selection); + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 16, ENC_NA); + *offsetp += 16; + break; + + case SelectionRequest: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + CARD16(event_sequencenumber); + TIMESTAMP(time); + WINDOW(owner); + WINDOW(requestor); + ATOM(selection); + ATOM(target); + ATOM(property); + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 4, ENC_NA); + *offsetp += 4; + break; + + case SelectionNotify: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + CARD16(event_sequencenumber); + TIMESTAMP(time); + WINDOW(requestor); + ATOM(selection); + ATOM(target); + ATOM(property); + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 8, ENC_NA); + *offsetp += 8; + break; + + case ColormapNotify: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + CARD16(event_sequencenumber); + WINDOW(eventwindow); + COLORMAP(cmap); + BOOL(new); + ENUM8(colormap_state); + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 18, ENC_NA); + *offsetp += 18; + break; + + case ClientMessage: + CARD8(format); + CARD16(event_sequencenumber); + WINDOW(eventwindow); + ATOM(type); + LISTofBYTE(data, 20); + break; + + case MappingNotify: + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 1, ENC_NA); + *offsetp += 1; + CARD16(event_sequencenumber); + ENUM8(mapping_request); + CARD8(first_keycode); + CARD8(count); + proto_tree_add_item(t, hf_x11_unused, tvb, *offsetp, 25, ENC_NA); + *offsetp += 25; + break; + + case GenericEvent: + tryGenericExtensionEvent(tvb, offsetp, t, state, byte_order); + break; + + default: + tryExtensionEvent(eventcode & 0x7F, tvb, offsetp, t, state, byte_order); + break; + } + + if ((left = tvb_reported_length_remaining(tvb, offset)) > 0) + UNDECODED(left); +} + +static void +dissect_x11_error(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, + const char *sep, x11_conv_data_t *state _U_, + guint byte_order) +{ + int offset = 0, *offsetp = &offset, left; + unsigned char errorcode; + proto_item *ti; + proto_tree *t; + + ti = proto_tree_add_item(tree, proto_x11, tvb, 0, -1, ENC_NA); + t = proto_item_add_subtree(ti, ett_x11); + + CARD8(error); + + errorcode = tvb_get_guint8(tvb, offset); + col_append_fstr(pinfo->cinfo, COL_INFO, "%s %s", + sep, val_to_str(errorcode, state->errorcode_vals, "<Unknown errorcode %u>")); + + proto_tree_add_uint_format(t, hf_x11_errorcode, tvb, offset, 1, + errorcode, + "errorcode: %d (%s)", + errorcode, + val_to_str(errorcode, state->errorcode_vals, + "<Unknown errorcode %u>")); + ++offset; + + proto_item_append_text(ti, ", Error, errorcode: %d (%s)", + errorcode, val_to_str(errorcode, state->errorcode_vals, + "<Unknown errorcode %u>")); + + if (tree == NULL) + return; + + CARD16(error_sequencenumber); + + switch (errorcode) { + case BadValue: + CARD32(error_badvalue); + break; + case BadWindow: + case BadPixmap: + case BadCursor: + case BadFont: + case BadDrawable: + case BadColormap: + case BadGC: + case BadIDChoice: + CARD32(error_badresourceid); + break; + + default: + UNDECODED(4); + } + + CARD16(minor_opcode); + CARD8(major_opcode); + + if ((left = tvb_reported_length_remaining(tvb, offset)) > 0) + UNDECODED(left); +} + + + +/************************************************************************ + *** *** + *** I N I T I A L I Z A T I O N A N D M A I N *** + *** *** + ************************************************************************/ + +static int +dissect_x11(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_) +{ + col_set_str(pinfo->cinfo, COL_PROTOCOL, "X11"); + + if (pinfo->match_uint == pinfo->srcport) + dissect_x11_replies(tvb, pinfo, tree); + else + dissect_x11_requests(tvb, pinfo, tree); + + return tvb_captured_length(tvb); +} + +/* Register the protocol with Wireshark */ +void proto_register_x11(void) +{ + +/* Setup list of header fields */ + static hf_register_info hf[] = { +#include "x11-register-info.h" + }; + +/* Setup protocol subtree array */ + static gint *ett[] = { + &ett_x11, + &ett_x11_color_flags, + &ett_x11_list_of_arc, + &ett_x11_arc, + &ett_x11_list_of_atom, + &ett_x11_list_of_card32, + &ett_x11_list_of_float, + &ett_x11_list_of_double, + &ett_x11_list_of_color_item, + &ett_x11_color_item, + &ett_x11_list_of_keycode, + &ett_x11_list_of_keysyms, + &ett_x11_keysym, + &ett_x11_list_of_point, + &ett_x11_point, + &ett_x11_list_of_rectangle, + &ett_x11_rectangle, + &ett_x11_list_of_segment, + &ett_x11_segment, + &ett_x11_list_of_string8, + &ett_x11_list_of_text_item, + &ett_x11_text_item, + &ett_x11_gc_value_mask, + &ett_x11_event_mask, + &ett_x11_do_not_propagate_mask, + &ett_x11_set_of_key_mask, + &ett_x11_pointer_event_mask, + &ett_x11_window_value_mask, + &ett_x11_configure_window_mask, + &ett_x11_keyboard_value_mask, + &ett_x11_same_screen_focus, + &ett_x11_event, + &ett_x11_list_of_pixmap_format, + &ett_x11_pixmap_format, + &ett_x11_list_of_screen, + &ett_x11_screen, + &ett_x11_list_of_depth_detail, + &ett_x11_depth_detail, + &ett_x11_list_of_visualtype, + &ett_x11_visualtype, + }; + + static ei_register_info ei[] = { + { &ei_x11_invalid_format, { "x11.invalid_format", PI_PROTOCOL, PI_WARN, "Invalid Format", EXPFILL }}, + { &ei_x11_request_length, { "x11.request-length.invalid", PI_PROTOCOL, PI_WARN, "Invalid Length", EXPFILL }}, + { &ei_x11_keycode_value_out_of_range, { "x11.keycode_value_out_of_range", PI_PROTOCOL, PI_WARN, "keycode value is out of range", EXPFILL }}, + }; + + module_t *x11_module; + expert_module_t* expert_x11; + +/* Register the protocol name and description */ + proto_x11 = proto_register_protocol("X11", "X11", "x11"); + x11_handle = register_dissector("x11", dissect_x11, proto_x11); + +/* Required function calls to register the header fields and subtrees used */ + proto_register_field_array(proto_x11, hf, array_length(hf)); + proto_register_subtree_array(ett, array_length(ett)); + expert_x11 = expert_register_protocol(proto_x11); + expert_register_field_array(expert_x11, ei, array_length(ei)); + + extension_table = wmem_map_new(wmem_epan_scope(), wmem_str_hash, g_str_equal); + error_table = wmem_map_new(wmem_epan_scope(), wmem_str_hash, g_str_equal); + event_table = wmem_map_new(wmem_epan_scope(), wmem_str_hash, g_str_equal); + genevent_table = wmem_map_new(wmem_epan_scope(), wmem_str_hash, g_str_equal); + reply_table = wmem_map_new(wmem_epan_scope(), wmem_str_hash, g_str_equal); + register_x11_extensions(); + + x11_module = prefs_register_protocol(proto_x11, NULL); + prefs_register_bool_preference(x11_module, "desegment", + "Reassemble X11 messages spanning multiple TCP segments", + "Whether the X11 dissector should reassemble messages spanning multiple TCP segments. " + "To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.", + &x11_desegment); +} + +void +proto_reg_handoff_x11(void) +{ + dissector_add_uint_range_with_preference("tcp.port", DEFAULT_X11_PORT_RANGE, x11_handle); +} + +/* + * Editor modelines + * + * Local Variables: + * c-basic-offset: 6 + * tab-width: 8 + * indent-tabs-mode: nil + * End: + * + * ex: set shiftwidth=6 tabstop=8 expandtab: + * :indentSize=6:tabSize=8:noTabs=true: + */ |