Fix build and thread runtime compat with older GLib
[metze/wireshark/wip.git] / epan / dissectors / packet-tibia.c
1 /* packet-tibia.c
2  * Routines for Tibia/OTServ login and game protocol dissection
3  *
4  * Copyright 2017, Ahmad Fatoum <ahmad[AT]a3f.at>
5  *
6  * A dissector for:
7  * Wireshark - Network traffic analyzer
8  * By Gerald Combs <gerald@wireshark.org>
9  * Copyright 1998 Gerald Combs
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24  */
25
26
27 /* Tibia (https://tibia.com) is a Massively Multiplayer Online Role-Playing
28  * Game (MMORPG) by Cipsoft GmbH.
29  *
30  * Three official clients exist: The current Qt-based 11.0+ client,
31  * the old C++ client used from Tibia 7.0 till 10.99 and the Flash client.
32  * The latter two are being phased out. They use the same protocol,
33  * except that the session key for the Flash client is transported alongside
34  * the character list over HTTPS. It's possible this is done in the same manner
35  * as in the native client from 10.74 up. We don't support the Flash client.
36  *
37  * The dissector supports Tibia versions from 7.0 (2001) till
38  * 11.00 (2016-10-12). Tibia has an active open source server emulator
39  * community (OTServ) that still makes use of older versions and surpasses
40  * the official servers in popularity, therefore compatibility with older
41  * protocol iterations should be maintained.
42  *
43  * Transport is over TCP, with recent versions encrypting player interaction
44  * with XTEA. Authentication and key exchange is done with a hard-coded
45  * RSA public key in the client.
46  *
47  * Two protocols are dissected: The Tibia login protocol and the Tibia game
48  * protocol. Traditionally, login servers were stateless and only responsible
49  * for providing the addresses of the game servers alongside the character
50  * list upon successful authentication. Then a new authentication request
51  * (this time with character selection) is sent to the game server.
52  * That way, a client who knows the game server address can very well skip
53  * the login server entirely. Starting with 10.61, this is no longer possible,
54  * as the login server provides a session key that needs to be sent to the
55  * game server.
56  *
57  * Starting with Tibia 7.61, login server requests can't be reliably
58  * differentiated from game server requests. Therefore we apply some heuristics
59  * to classify packets.
60  *
61  * Starting with Tibia 11.01, a web service takes the role of the login server.
62  * Starting with Tibia 11.11, the Adler32 checksum was replaced by a 32-bit
63  * sequence number. The most significant bit indicates whether the packet was
64  * DEFLATE-compressed. These features are not yet supported.
65  *
66  * Packets from and to the game server contain commands. Commands are
67  * identified by the first octet and are variable in length. The dissector has
68  * most command names hard-coded. However, a complete implementation of the
69  * game protocol is unlikely.
70  *
71  * The RSA private key usually used by OTServ is hard-coded in. Server
72  * administrators may add their own private key in PEM or PKCS#12 format over
73  * an UAT. For servers where the private key is indeed private (like
74  * for official servers), the symmetric XTEA key (retrievable by memory
75  * peeking or MitM) may be provided to the dissector via UAT.
76  *
77  * Unsurprisingly, no official specification of the protocol exist, following
78  * resources have been written by the community:
79  *
80  * - OTServ: Community effort to replicate a Tibia Server.
81  * - Outcast: A Tibia client implementation of the game protocol as of 2006.
82  *            Comes with a PDF spec written by Khaos
83  * - TibiaAPI: Bot framework, containing a listing of commands as of 2009
84  * - TFS: OTServ-Fork which is kept up-to-date with most of the official protocol
85  * - otclient: Open Source implementation of an up-to-date Tibia client
86  *
87  * An official slide set by Cipsoft detailing the architecture of Tibia
88  * from Game Developers Conference Europe 2011 is also available:
89  * http://www.gdcvault.com/play/1014908/Inside-Tibia-The-Technical-Infrastructure
90  *
91  * The login protocol, as implemented here, has been inferred from network
92  * footage and game client execution traces and was written from scratch.
93  * The listing of game protocol commands were taken from TibiaAPI and Khaos' spec
94  * No code of Cipsoft GmbH was used.
95  *
96  * Tibia is a registered trademark of Cipsoft GmbH.
97  */
98
99 #include "config.h"
100 #include <epan/packet.h>
101 #include "packet-tcp.h"
102 #include <wsutil/adler32.h>
103 #include <epan/address.h>
104 #include <epan/to_str.h>
105 #include <epan/prefs.h>
106 #include <epan/uat.h>
107 #include <epan/conversation.h>
108 #include <epan/value_string.h>
109 #include <epan/expert.h>
110 #include <epan/address.h>
111 #include <wsutil/filesystem.h>
112 #include <wsutil/file_util.h>
113 #include <wsutil/wsgcrypt.h>
114 #include <wsutil/report_message.h>
115 #include <wsutil/xtea.h>
116 #include <wsutil/strtoi.h>
117 #include <wsutil/rsa.h>
118 #include <errno.h>
119 #include <wsutil/ws_printf.h>
120 #include <epan/ptvcursor.h>
121
122 void proto_register_tibia(void);
123 void proto_reg_handoff_tibia(void);
124
125 /* preferences */
126 static gboolean try_otserv_key          = TRUE,
127                 show_char_name          = TRUE,
128                 show_acc_info           = TRUE,
129                 show_xtea_key           = FALSE,
130                 dissect_game_commands   = FALSE,
131                 reassemble_tcp_segments = TRUE;
132
133 /* User Access Tables */
134 #if HAVE_LIBGNUTLS
135 struct rsakey {
136     address addr;
137     guint16 port;
138
139     gcry_sexp_t privkey;
140 };
141 GHashTable *rsakeys;
142
143 struct rsakeys_assoc {
144     char *ipaddr;
145     char *port;
146
147     char *keyfile;
148     char *password;
149 };
150
151 UAT_CSTRING_CB_DEF(rsakeylist_uats,  ipaddr,   struct rsakeys_assoc)
152 UAT_CSTRING_CB_DEF(rsakeylist_uats,  port,     struct rsakeys_assoc)
153 UAT_FILENAME_CB_DEF(rsakeylist_uats, keyfile,  struct rsakeys_assoc)
154 UAT_CSTRING_CB_DEF(rsakeylist_uats,  password, struct rsakeys_assoc)
155
156 static void rsakey_free(void *_rsakey);
157
158 static uat_t *rsakeys_uat = NULL;
159 static struct rsakeys_assoc  *rsakeylist_uats = NULL;
160 static guint nrsakeys = 0;
161 #endif
162
163 #define XTEA_KEY_LEN 16
164
165 struct xteakeys_assoc {
166     guint32 framenum;
167
168     char *key;
169 };
170 GHashTable *xteakeys;
171
172 static void *xteakeys_copy_cb(void *, const void *, size_t);
173 static void xteakeys_free_cb(void *);
174 static void xtea_parse_uat(void);
175 static gboolean xteakeys_uat_fld_key_chk_cb(void *, const char *, guint, const void *, const void *, char **);
176
177 UAT_DEC_CB_DEF(xteakeylist_uats, framenum, struct xteakeys_assoc)
178 UAT_CSTRING_CB_DEF(xteakeylist_uats, key, struct xteakeys_assoc)
179
180 static uat_t *xteakeys_uat = NULL;
181 static struct xteakeys_assoc *xteakeylist_uats = NULL;
182 static guint nxteakeys = 0;
183
184 #define COND_POISONED     0x1
185 #define COND_BURNING      0x2
186 #define COND_ELECTROCUTED 0x4
187 #define COND_DRUNK        0x8
188 #define COND_MANASHIELD   0x10
189 #define COND_PARALYZED    0x20
190 #define COND_HASTE        0x40
191 #define COND_BATTLE       0x80
192 #define COND_DROWNING     0x100
193 #define COND_FREEZING     0x200
194 #define COND_DAZZLED      0x400
195 #define COND_CURSED       0x800
196 #define COND_BUFF         0x1000
197 #define COND_PZBLOCK      0x2000
198 #define COND_PZ           0x4000
199 #define COND_BLEEDING     0x8000
200 #define COND_HUNGRY       0x10000
201
202 /* The login server has been traditionally on 7171,
203  * For OTServ, the game server often listens on the same IP/port,
204  * but occasionally on 7172. Official Tibia doesn't host login and
205  * game servers on the same IP address
206  */
207
208 #define TIBIA_DEFAULT_TCP_PORT_RANGE "7171,7172"
209
210 static gint proto_tibia = -1;
211
212 static gint hf_tibia_len                     = -1;
213 static gint hf_tibia_nonce                   = -1;
214 static gint hf_tibia_adler32                 = -1;
215 static gint hf_tibia_adler32_status          = -1;
216 static gint hf_tibia_os                      = -1;
217 static gint hf_tibia_proto_version           = -1;
218 static gint hf_tibia_client_version          = -1;
219 static gint hf_tibia_file_versions           = -1;
220 static gint hf_tibia_file_version_spr        = -1;
221 static gint hf_tibia_file_version_dat        = -1;
222 static gint hf_tibia_file_version_pic        = -1;
223 static gint hf_tibia_game_preview_state      = -1;
224 static gint hf_tibia_content_revision        = -1;
225 static gint hf_tibia_undecoded_rsa_data      = -1;
226 static gint hf_tibia_undecoded_xtea_data     = -1;
227 static gint hf_tibia_unknown                 = -1;
228 static gint hf_tibia_xtea_key                = -1;
229 static gint hf_tibia_loginflags_gm           = -1;
230 static gint hf_tibia_acc_name                = -1;
231 static gint hf_tibia_acc_number              = -1;
232 static gint hf_tibia_session_key             = -1;
233 static gint hf_tibia_char_name               = -1;
234 static gint hf_tibia_acc_pass                = -1;
235 static gint hf_tibia_char_name_convo         = -1;
236 static gint hf_tibia_acc_name_convo          = -1;
237 static gint hf_tibia_acc_pass_convo          = -1;
238 static gint hf_tibia_session_key_convo       = -1;
239
240 static gint hf_tibia_client_info             = -1;
241 static gint hf_tibia_client_locale           = -1;
242 static gint hf_tibia_client_locale_id        = -1;
243 static gint hf_tibia_client_locale_name      = -1;
244 static gint hf_tibia_client_ram              = -1;
245 static gint hf_tibia_client_cpu              = -1;
246 static gint hf_tibia_client_cpu_name         = -1;
247 static gint hf_tibia_client_clock            = -1;
248 static gint hf_tibia_client_clock2           = -1;
249 static gint hf_tibia_client_gpu              = -1;
250 static gint hf_tibia_client_vram             = -1;
251 static gint hf_tibia_client_resolution       = -1;
252 static gint hf_tibia_client_resolution_x     = -1;
253 static gint hf_tibia_client_resolution_y     = -1;
254 static gint hf_tibia_client_resolution_hz    = -1;
255
256 static gint hf_tibia_payload_len             = -1;
257 static gint hf_tibia_loginserv_command       = -1;
258 static gint hf_tibia_gameserv_command        = -1;
259 static gint hf_tibia_client_command          = -1;
260
261 static gint hf_tibia_motd                    = -1;
262 static gint hf_tibia_dlg_error               = -1;
263 static gint hf_tibia_dlg_info                = -1;
264
265 static gint hf_tibia_charlist                = -1;
266 static gint hf_tibia_charlist_length         = -1;
267 static gint hf_tibia_charlist_entry_name     = -1;
268 static gint hf_tibia_charlist_entry_world    = -1;
269 static gint hf_tibia_charlist_entry_ip       = -1;
270 static gint hf_tibia_charlist_entry_port     = -1;
271
272 static gint hf_tibia_worldlist               = -1;
273 static gint hf_tibia_worldlist_length        = -1;
274 static gint hf_tibia_worldlist_entry_name    = -1;
275 static gint hf_tibia_worldlist_entry_ip      = -1;
276 static gint hf_tibia_worldlist_entry_port    = -1;
277 static gint hf_tibia_worldlist_entry_preview = -1;
278 static gint hf_tibia_worldlist_entry_id      = -1;
279 static gint hf_tibia_pacc_days               = -1;
280
281 static gint hf_tibia_channel_id              = -1;
282 static gint hf_tibia_channel_name            = -1;
283
284 static gint hf_tibia_char_cond               = -1;
285 static gint hf_tibia_char_cond_poisoned      = -1;
286 static gint hf_tibia_char_cond_burning       = -1;
287 static gint hf_tibia_char_cond_electrocuted  = -1;
288 static gint hf_tibia_char_cond_drunk         = -1;
289 static gint hf_tibia_char_cond_manashield    = -1;
290 static gint hf_tibia_char_cond_paralyzed     = -1;
291 static gint hf_tibia_char_cond_haste         = -1;
292 static gint hf_tibia_char_cond_battle        = -1;
293 static gint hf_tibia_char_cond_drowning      = -1;
294 static gint hf_tibia_char_cond_freezing      = -1;
295 static gint hf_tibia_char_cond_dazzled       = -1;
296 static gint hf_tibia_char_cond_cursed        = -1;
297 static gint hf_tibia_char_cond_buff          = -1;
298 static gint hf_tibia_char_cond_pzblock       = -1;
299 static gint hf_tibia_char_cond_pz            = -1;
300 static gint hf_tibia_char_cond_bleeding      = -1;
301 static gint hf_tibia_char_cond_hungry        = -1;
302
303 static const int *char_conds[] = {
304     &hf_tibia_char_cond_poisoned,
305     &hf_tibia_char_cond_burning,
306     &hf_tibia_char_cond_electrocuted,
307     &hf_tibia_char_cond_drunk,
308     &hf_tibia_char_cond_manashield,
309     &hf_tibia_char_cond_paralyzed,
310     &hf_tibia_char_cond_haste,
311     &hf_tibia_char_cond_battle,
312     &hf_tibia_char_cond_drowning,
313     &hf_tibia_char_cond_freezing,
314     &hf_tibia_char_cond_dazzled,
315     &hf_tibia_char_cond_cursed,
316     &hf_tibia_char_cond_buff,
317     &hf_tibia_char_cond_pzblock,
318     &hf_tibia_char_cond_pz,
319     &hf_tibia_char_cond_bleeding,
320     &hf_tibia_char_cond_hungry,
321     NULL
322 };
323
324 static gint hf_tibia_chat_msg            = -1;
325 static gint hf_tibia_speech_type         = -1;
326
327 static gint hf_tibia_coords_x            = -1;
328 static gint hf_tibia_coords_y            = -1;
329 static gint hf_tibia_coords_z            = -1;
330 static gint hf_tibia_coords              = -1;
331 static gint hf_tibia_stackpos            = -1;
332
333 #if 0
334 static gint hf_tibia_item                = -1;
335 #endif
336 static gint hf_tibia_container           = -1;
337 static gint hf_tibia_container_icon      = -1;
338 static gint hf_tibia_container_slot      = -1;
339 static gint hf_tibia_container_slots     = -1;
340 static gint hf_tibia_inventory           = -1;
341 static gint hf_tibia_vip                 = -1;
342 static gint hf_tibia_vip_online          = -1;
343 static gint hf_tibia_player              = -1;
344 static gint hf_tibia_creature            = -1;
345 static gint hf_tibia_creature_health     = -1;
346 static gint hf_tibia_window              = -1;
347 static gint hf_tibia_window_icon         = -1;
348 static gint hf_tibia_window_textlen      = -1;
349 static gint hf_tibia_window_text         = -1;
350
351 static gint hf_tibia_light_level         = -1;
352 static gint hf_tibia_light_color         = -1;
353 static gint hf_tibia_magic_effect_id     = -1;
354 static gint hf_tibia_animated_text_color = -1;
355 static gint hf_tibia_animated_text       = -1;
356 static gint hf_tibia_projectile          = -1;
357 static gint hf_tibia_squarecolor         = -1;
358 static gint hf_tibia_textmsg_class       = -1;
359 static gint hf_tibia_textmsg             = -1;
360 static gint hf_tibia_walk_dir            = -1;
361
362
363 static gint ett_tibia               = -1;
364 static gint ett_command             = -1;
365 static gint ett_file_versions       = -1;
366 static gint ett_client_info         = -1;
367 static gint ett_locale              = -1;
368 static gint ett_cpu                 = -1;
369 static gint ett_resolution          = -1;
370 static gint ett_charlist            = -1;
371 static gint ett_worldlist           = -1;
372 static gint ett_char                = -1;
373 static gint ett_world               = -1;
374 static gint ett_coords              = -1;
375 static gint ett_char_cond           = -1;
376
377
378 static expert_field ei_xtea_len_toobig               = EI_INIT;
379 static expert_field ei_adler32_checksum_bad          = EI_INIT;
380 static expert_field ei_rsa_plaintext_no_leading_zero = EI_INIT;
381 static expert_field ei_rsa_ciphertext_too_short      = EI_INIT;
382 static expert_field ei_rsa_decrypt_failed            = EI_INIT;
383
384
385 struct proto_traits {
386     guint32 adler32:1, rsa:1, compression:1, xtea:1, login_webservice:1, acc_name:1, nonce:1,
387             extra_gpu_info:1, gmbyte:1, hwinfo:1;
388     guint32 outfit_addons:1, stamina:1, lvl_on_msg:1;
389     guint32 ping:1, client_version:1, game_preview:1, auth_token:1, session_key:1;
390     guint32 game_content_revision:1, worldlist_in_charlist:1;
391     guint string_enc;
392 };
393
394 struct tibia_convo {
395     guint32 xtea_key[XTEA_KEY_LEN / sizeof (guint32)];
396     guint32 xtea_framenum;
397     const guint8 *acc, *pass, *char_name, *session_key;
398     struct proto_traits has;
399
400     guint16 proto_version;
401     guint8 loginserv_is_peer :1;
402     guint16 clientport;
403     guint16 servport;
404
405     gcry_sexp_t privkey;
406 };
407
408 static struct proto_traits
409 get_version_traits(guint16 version)
410 {
411     struct proto_traits has;
412     memset(&has, 0, sizeof has);
413     has.gmbyte = TRUE; /* Not sure when the GM byte first appeared */
414     has.string_enc = ENC_ISO_8859_1;
415
416     if (version >= 761) /* 761 was a test client. 770 was the first release */
417         has.xtea = has.rsa = TRUE;
418     if (version >= 780)
419         has.outfit_addons = has.stamina = has.lvl_on_msg = TRUE;
420     if (version >= 830)
421         has.adler32 = has.acc_name = TRUE;
422     if (version >= 841)
423         has.hwinfo = has.nonce = TRUE;
424     if (version >= 953)
425         has.ping = TRUE;
426     if (version >= 980)
427         has.client_version = has.game_preview = TRUE;
428     if (version >= 1010)
429         has.worldlist_in_charlist = TRUE;
430     if (version >= 1061)
431         has.extra_gpu_info = TRUE;
432     if (version >= 1071)
433         has.game_content_revision = TRUE;
434     if (version >= 1072)
435         has.auth_token = TRUE;
436     if (version >= 1074)
437         has.session_key = TRUE;
438     if (version >= 1101)
439         has.login_webservice = TRUE;
440     if (version >= 1111) {
441         has.compression = TRUE; /* with DEFLATE */
442         has.adler32 = FALSE;
443     }
444 #if 0 /* With the legacy client being phased out, maybe Unicode support incoming? */
445     if (version >= 11xy)
446         has.string_enc = ENC_UTF_8;
447 #endif
448
449     return has;
450 }
451
452 static guint16
453 get_version_get_charlist_packet_size(struct proto_traits *has)
454 {
455     guint16 size = 2;
456     if (has->adler32 || has->compression)
457         size += 4;
458     size += 17;
459     if (has->extra_gpu_info)
460         size += 222;
461     if (has->rsa)
462         size += 128;
463
464     return size;
465 }
466 static guint16
467 get_version_char_login_packet_size(struct proto_traits *has)
468 {
469     guint16 size = 2;
470     if (has->adler32 || has->compression)
471         size += 4;
472     size += 5;
473     if (has->client_version)
474         size += 4;
475     if (has->game_content_revision)
476         size += 2;
477     if (has->game_preview)
478         size += 1;
479     if (has->rsa)
480         size += 128;
481
482     return size;
483 }
484
485
486 #define XTEA_FROM_UAT 0
487 #define XTEA_UNKNOWN  0xFFFFFFFF
488
489 static struct tibia_convo *
490 tibia_get_convo(packet_info *pinfo)
491 {
492     conversation_t *epan_conversation = find_or_create_conversation(pinfo);
493
494     struct tibia_convo *convo = (struct tibia_convo*)conversation_get_proto_data(epan_conversation, proto_tibia);
495
496     if (!convo) {
497         address *servaddr;
498         convo = wmem_new0(wmem_file_scope(), struct tibia_convo);
499
500         /* FIXME there gotta be a cleaner way... */
501         if (pinfo->srcport >= 0xC000) {
502             convo->clientport = pinfo->srcport;
503
504             convo->servport = pinfo->destport;
505             servaddr = &pinfo->dst;
506         } else {
507             convo->clientport = pinfo->destport;
508
509             convo->servport = pinfo->srcport;
510             servaddr = &pinfo->src;
511         }
512         (void)servaddr;
513 #ifdef HAVE_LIBGNUTLS
514         struct rsakey rsa_key;
515         rsa_key.port = convo->servport;
516         rsa_key.addr = *servaddr;
517         convo->privkey = (gcry_sexp_t)g_hash_table_lookup(rsakeys, &rsa_key);
518 #endif
519         convo->xtea_framenum = XTEA_UNKNOWN;
520
521         conversation_add_proto_data(epan_conversation, proto_tibia, (void *)convo);
522     }
523
524     if (convo->xtea_framenum == XTEA_UNKNOWN) {
525         guint8 *xtea_key = (guint8*)g_hash_table_lookup(xteakeys, GUINT_TO_POINTER(pinfo->num));
526         if (xtea_key) {
527             memcpy(convo->xtea_key, xtea_key, XTEA_KEY_LEN);
528             convo->xtea_framenum = XTEA_FROM_UAT;
529         }
530     }
531
532     return convo;
533 }
534
535 static guint32
536 ipv4tonl(const char *str)
537 {
538         guint32 ipaddr = 0;
539         for (int octet = 0; octet < 4; octet++) {
540             ws_strtou8(str, &str, &((guint8*)&ipaddr)[octet]);
541             str++;
542         }
543         return ipaddr;
544 }
545
546 static void
547 register_gameserv_addr(struct tibia_convo *convo, guint32 ipaddr, guint16 port)
548 {
549     (void)convo; (void)ipaddr; (void)port;
550 #if HAVE_LIBGNUTLS
551     /* Game servers in the list inherit the same RSA key as the login server */
552     if (convo->has.rsa) {
553         struct rsakey *entry = g_new(struct rsakey, 1);
554         alloc_address_wmem(NULL, &entry->addr, AT_IPv4, sizeof ipaddr, &ipaddr);
555         entry->port = port;
556         entry->privkey = NULL;
557         if (g_hash_table_lookup(rsakeys, entry) == NULL) {
558             entry->privkey = convo->privkey;
559             g_hash_table_insert(rsakeys, entry, entry->privkey);
560         } else {
561             rsakey_free(entry);
562         }
563     }
564
565     /* TODO Mark all communication with the IP/Port pair above
566      * as Tibia communication. How?
567      */
568 #endif
569 }
570
571 static gcry_sexp_t otserv_key;
572 static gcry_sexp_t
573 convo_get_privkey(struct tibia_convo *convo)
574 {
575     return convo->privkey ? convo->privkey
576          : try_otserv_key ? otserv_key
577          : NULL;
578 }
579
580 enum client_cmd {
581     /* from TibiaAPI */
582     C_GET_CHARLIST          = 0x01,
583     C_LOGIN_CHAR            = 0x0A,
584     C_LOGOUT                = 0x14, /* I think this is a 7.7+ thing */
585     C_PONG                  = 0x1E,
586
587     C_AUTO_WALK             = 0x64,
588     C_GO_NORTH              = 0x65,
589     C_GO_EAST               = 0x66,
590     C_GO_SOUTH              = 0x67,
591     C_GO_WEST               = 0x68,
592     C_AUTO_WALK_CANCEL      = 0x69,
593     C_GO_NE                 = 0x6A,
594     C_GO_SE                 = 0x6B,
595     C_GO_SW                 = 0x6C,
596     C_GO_NW                 = 0x6D,
597     C_TURN_NORTH            = 0x6F,
598     C_TURN_EAST             = 0x70,
599     C_TURN_SOUTH            = 0x71,
600     C_TURN_WEST             = 0x72,
601     C_MOVE_ITEM             = 0x78,
602     C_SHOP_BUY              = 0x7A,
603     C_SHOP_SELL             = 0x7B,
604     C_SHOP_CLOSE            = 0x7C,
605     C_ITEM_USE              = 0x82,
606     C_ITEM_USE_ON           = 0x83,
607     C_ITEM_USE_BATTLELIST   = 0x84,
608     C_ITEM_ROTATE           = 0x85,
609     C_CONTAINER_CLOSE       = 0x87,
610     C_CONTAINER_OPEN_PARENT = 0x88,
611     C_LOOK_AT               = 0x8C,
612     C_PLAYER_SPEECH         = 0x96,
613     C_CHANNEL_LIST          = 0x97,
614     C_CHANNEL_OPEN          = 0x98,
615     C_CHANNEL_CLOSE         = 0x99,
616     C_PRIVATE_CHANNEL_OPEN  = 0x9A,
617     C_NPC_CHANNEL_CLOSE     = 0x9E,
618     C_FIGHT_MODES           = 0xA0,
619     C_ATTACK                = 0xA1,
620     C_FOLLOW                = 0xA2,
621     C_CANCEL_GO             = 0xBE,
622     C_TILE_UPDATE           = 0xC9,
623     C_CONTAINER_UPDATE      = 0xCA,
624     C_SET_OUTFIT            = 0xD3,
625     C_VIP_ADD               = 0xDC,
626     C_VIP_REMOVE            = 0xDD
627  };
628
629 static const value_string from_client_packet_types[] = {
630     { C_GET_CHARLIST,     "Charlist request" },
631     { C_LOGIN_CHAR,       "Character login" },
632
633     { C_LOGOUT,           "Logout" },
634     { C_PONG,             "Pong" },
635
636     { C_AUTO_WALK,        "Map walk" },
637     { C_GO_NORTH,         "Go north"},
638     { C_GO_EAST,          "Go east"},
639     { C_GO_SOUTH,         "Go south"},
640     { C_GO_WEST,          "Go west"},
641     { C_AUTO_WALK_CANCEL, "Map walk cancel" },
642     { C_GO_NE,            "Go north-east"},
643     { C_GO_SE,            "Go south-east"},
644     { C_GO_SW,            "Go south-west"},
645     { C_GO_NW,            "Go north-west"},
646
647     { C_TURN_NORTH,      "Turn north" },
648     { C_TURN_EAST,       "Turn east" },
649     { C_TURN_SOUTH,      "Turn south" },
650     { C_TURN_WEST,       "Turn west" },
651     { C_MOVE_ITEM,       "Move item" },
652     { C_SHOP_BUY,        "Buy in shop" },
653     { C_SHOP_SELL,       "Sell in shop" },
654     { C_SHOP_CLOSE,      "Close shop" },
655     { C_ITEM_USE,        "Use item" },
656     { C_ITEM_USE_ON,     "Use item on" },
657     { C_ITEM_USE_BATTLELIST,   "Use item on battle list" },
658     { C_ITEM_ROTATE,           "Rotate item" },
659
660     { C_CONTAINER_CLOSE,       "Close container" },
661     { C_CONTAINER_OPEN_PARENT, "Open parent container" },
662     { C_LOOK_AT,               "Look at" },
663     { C_PLAYER_SPEECH,         "Speech" },
664     { C_CHANNEL_LIST,          "List channels" },
665     { C_CHANNEL_OPEN,          "Open public channel" },
666     { C_CHANNEL_CLOSE,         "close channel" },
667     { C_PRIVATE_CHANNEL_OPEN,  "Open private channel" },
668     { C_NPC_CHANNEL_CLOSE,     "Open NPC channel" },
669     { C_FIGHT_MODES,           "Set fight modes" },
670     { C_ATTACK,                "Attack" },
671     { C_FOLLOW,                "Follow" },
672     { C_CANCEL_GO,             "Cancel go" },
673     { C_TILE_UPDATE,           "Update tile" },
674     { C_CONTAINER_UPDATE,      "Update container" },
675     { C_SET_OUTFIT,            "Set outfit" },
676     { C_VIP_ADD,               "Add VIP" },
677     { C_VIP_REMOVE,            "Remove VIP" },
678
679     { 0, NULL }
680 };
681
682 static value_string_ext from_client_packet_types_ext = VALUE_STRING_EXT_INIT(from_client_packet_types);
683
684 enum loginserv_cmd {
685     LOGINSERV_DLG_ERROR    = 0x0A,
686     LOGINSERV_DLG_ERROR2   = 0x0B,
687     LOGINSERV_DLG_MOTD     = 0x14,
688     LOGINSERV_SESSION_KEY  = 0x28,
689     LOGINSERV_DLG_CHARLIST = 0x64
690 };
691
692 static const value_string from_loginserv_packet_types[] = {
693     { LOGINSERV_DLG_ERROR,    "Error" },
694     { LOGINSERV_DLG_ERROR2,   "Error" },
695     { LOGINSERV_DLG_MOTD,     "MOTD" },
696     { LOGINSERV_SESSION_KEY,  "Session key" },
697     { LOGINSERV_DLG_CHARLIST, "Charlist" },
698
699     { 0, NULL }
700 };
701
702 enum gameserv_cmd {
703     /* Credit to Khaos (OBJECT Networks). Values and comments extracted from PDF table */
704     S_MAPINIT =                0x0A, /* Long playerCreatureId Int unknownU16 (Byte reportBugs?) */
705     S_GMACTIONS =              0x0B, /* Used to be 32 unknown bytes, but with GMs removed it                                      might not be in use anymore */
706     S_DLG_ERROR =              0x14, /* String errorMessage */
707     S_DLG_INFO =               0x15,
708     S_DLG_TOOMANYPLAYERS =     0x16,
709     S_PING =                   0x1E,
710     S_NONCE =                  0x1F,
711     S_PLAYERLOC =              0x64, /* Coord pos */
712     S_GO_NORTH =               0x65, /* MapDescription (18,1) */
713     S_GO_EAST =                0x66, /* MapDescription (1,14) */
714     S_GO_SOUTH =               0x67, /* MapDescription (18,1) */
715     S_GO_WEST =                0x68, /* MapDescription (1,14) */
716     S_TILEUPDATE =             0x69, /* Coord pos TileDescription td */
717     S_ADDITEM =                0x6a, /* Coord pos ThingDescription thing */
718     S_REPLACEITEM =            0x6b, /* Coord pos Byte stackpos ThingDescription thing */
719     S_REMOVEITEM =             0x6c, /* Coord pos Byte stackpos */
720     S_MOVE_THING =             0x6d,
721     S_CONTAINER =              0x6e, /* Byte index Short containerIcon Byte slotCount ThingDescription item */
722     S_CONTAINERCLOSE =         0x6f, /* Byte index */
723     S_ADDITEMCONTAINER =       0x70, /* Byte index ThingDescription itm */
724     S_TRANSFORMITEMCONTAINER = 0x71, /* Byte index Byte slot */
725     S_REMOVEITEMCONTAINER =    0x72, /* Byte index Byte slot */
726     S_INVENTORYEMPTY =         0x78, /* Byte invSlot */
727     S_INVENTORYITEM =          0x79, /* Byte invSlot ThingDescription itm */
728     S_TRADEREQ =               0x7d, /* String otherperson Byte slotCount ThingDescription itm */
729     S_TRADEACK =               0x7e, /* String otherperson Byte slotCount ThingDescription itm */
730     S_TRADECLOSE =             0x7f,
731     S_LIGHTLEVEL =             0x82, /* Byte lightlevel Byte lightcolor */
732     S_MAGIC_EFFECT =           0x83,
733     S_ANIMATEDTEXT =           0x84, /* Coord pos Byte color String message */
734     S_DISTANCESHOT =           0x85, /* Coord pos1 Byte stackposition Coord pos2 */
735     S_CREATURESQUARE =         0x86, /* Long creatureid Byte squarecolor */
736     S_CREATURE_HEALTH =        0x8C,
737     S_CREATURELIGHT =          0x8d, /* Long creatureid Byte ? Byte ? */
738     S_SETOUTFIT =              0x8e, /* Long creatureid Byte lookType Byte headType Byte bodyType Byte legsType Byte feetType // can extended look go here too? */
739     S_CREATURESPEED =          0x8f, /* YIKES! I didnt handle this! */
740     S_TEXTWINDOW =             0x96, /* Long windowId Byte icon Byte maxlength String message */
741     S_STATUSMSG =              0xA0, /* Status status */
742     S_SKILLS =                 0xA1, /* Skills skills */
743     S_PLAYER_CONDITION =       0xA2,
744     S_CANCELATTACK =           0xA3,
745     S_SPEAK =                  0xAA,
746     S_CHANNELSDIALOG =         0xAB, /* Byte channelCount (Int channelId String channelName) */
747     S_CHANNEL_OPEN =           0xAC,
748     S_OPENPRIV =               0xAD, /* String playerName */
749     S_TEXTMESSAGE =            0xB4, /* Byte msgClass String string */
750     S_CANCELWALK =             0xB5, /* Byte direction */
751     S_FLOORUP =                0xBE, /* Advanced topic; read separate text */
752     S_FLOORDOWN =              0xBF, /* Advanced topic; read separate text */
753     S_OUTFITLIST =             0xC8, /* Byte lookType Byte headType Byte bodyType Byte legsType Byte feetType Byte firstModel Byte lastModel */
754     S_VIPADD =                 0xD2, /* long guid string name byte isonline */
755     S_VIPLOGIN =               0xD3, /* long guid */
756     S_VIPLOGOUT =              0xD4  /* long guid*/
757 };
758 static const value_string from_gameserv_packet_types[] = {
759
760     { S_MAPINIT,            "Initialize map" },
761     { S_GMACTIONS,          "GM actions" },
762     { S_DLG_ERROR,          "Error" },
763     { S_DLG_INFO,           "Info" },
764     { S_DLG_TOOMANYPLAYERS, "Too many players" },
765     { S_PING,               "Ping" },
766     { S_NONCE,              "Nonce" },
767     { S_PLAYERLOC,      "Set player location" },
768     { S_GO_NORTH,       "Go north" },
769     { S_GO_EAST,        "Go east" },
770     { S_GO_SOUTH,       "Go south" },
771     { S_GO_WEST,        "Go west" },
772     { S_TILEUPDATE,     "Update tile" },
773     { S_ADDITEM,        "Add item" },
774     { S_REPLACEITEM,    "Replace item" },
775     { S_REMOVEITEM,     "Remove item" },
776     { S_MOVE_THING,     "Move thing" },
777     { S_CONTAINER,      "Open container" },
778     { S_CONTAINERCLOSE, "Close container" },
779
780     { S_ADDITEMCONTAINER,       "Add item in container" },
781     { S_TRANSFORMITEMCONTAINER, "Transform item in container" },
782     { S_REMOVEITEMCONTAINER,    "Remove item in container" },
783
784     { S_INVENTORYEMPTY,   "Inventory empty" },
785     { S_INVENTORYITEM,    "Inventory item" },
786     { S_TRADEREQ,         "Trade request" },
787     { S_TRADEACK,         "Trade acknowledge" },
788     { S_TRADECLOSE,       "Trade over" },
789     { S_LIGHTLEVEL,       "Light level" },
790     { S_MAGIC_EFFECT,     "Magic effect" },
791     { S_ANIMATEDTEXT,     "Animated text" },
792     { S_DISTANCESHOT,     "Distance shot" },
793     { S_CREATURESQUARE,   "Creature square" },
794     { S_CREATURE_HEALTH,  "Creature health" },
795     { S_CREATURELIGHT,    "Creature light" },
796     { S_SETOUTFIT,        "Set outfit" },
797     { S_CREATURESPEED,    "Set creature speed" },
798     { S_TEXTWINDOW,       "Text window" },
799     { S_STATUSMSG,        "Status message" },
800     { S_SKILLS,           "Skills" },
801     { S_PLAYER_CONDITION, "Player condition" },
802     { S_CANCELATTACK,     "Cancel attack" },
803     { S_SPEAK,            "Creature speech" },
804     { S_CHANNELSDIALOG,   "Channels dialog" },
805     { S_CHANNEL_OPEN,     "Channel open" },
806     { S_OPENPRIV,         "Private channel open" },
807     { S_TEXTMESSAGE,      "Text message" },
808     { S_CANCELWALK,       "Cancel walk" },
809     { S_FLOORUP,          "Floor +1" },
810     { S_FLOORDOWN,        "Floor -1" },
811     { S_OUTFITLIST,       "Outfit list" },
812     { S_VIPADD,           "Add VIP" },
813     { S_VIPLOGIN,         "VIP login" },
814     { S_VIPLOGOUT,        "VIP logout" },
815
816     { 0, NULL }
817 };
818
819 static value_string_ext from_gameserv_packet_types_ext = VALUE_STRING_EXT_INIT(from_gameserv_packet_types);
820
821 static const unit_name_string mb_unit = {"MB", NULL};
822
823 static int
824 dissect_loginserv_packet(struct tibia_convo *convo, tvbuff_t *tvb, int offset, int len, packet_info *pinfo, proto_tree *tree, gboolean first_fragment )
825 {
826     ptvcursor_t *ptvc = ptvcursor_new(tree, tvb, offset);
827
828     col_append_str(pinfo->cinfo, COL_INFO, first_fragment ? " commands:" : ",");
829     len += offset;
830
831     if (ptvcursor_current_offset(ptvc) < len) {
832         for (;;) {
833             int cmd = tvb_get_guint8(tvb, ptvcursor_current_offset(ptvc));
834             ptvcursor_add_with_subtree(ptvc, hf_tibia_loginserv_command, 1, convo->has.string_enc, ett_command);
835             ptvcursor_advance(ptvc, 1);
836
837             switch ((enum loginserv_cmd)cmd) {
838                 case LOGINSERV_DLG_ERROR:
839                 case LOGINSERV_DLG_ERROR2:
840                     ptvcursor_add(ptvc, hf_tibia_dlg_error, 2, ENC_LITTLE_ENDIAN | convo->has.string_enc);
841                     break;
842                 case LOGINSERV_DLG_MOTD:
843                     ptvcursor_add(ptvc, hf_tibia_motd, 2, ENC_LITTLE_ENDIAN | convo->has.string_enc);
844                     break;
845                 case LOGINSERV_SESSION_KEY:
846                     ptvcursor_add(ptvc, hf_tibia_session_key, 2, ENC_LITTLE_ENDIAN | convo->has.string_enc);
847                     break;
848                 case LOGINSERV_DLG_CHARLIST:
849                     if (convo->has.worldlist_in_charlist) {
850                         guint8 world_count = tvb_get_guint8(tvb, ptvcursor_current_offset(ptvc));
851                         ptvcursor_add(ptvc, hf_tibia_worldlist_length, 1, ENC_NA);
852                         /* Empty character list? */
853                         if (world_count) {
854                             ptvcursor_add_with_subtree(ptvc, hf_tibia_worldlist, SUBTREE_UNDEFINED_LENGTH, ENC_NA, ett_worldlist);
855                             while (world_count--) {
856                                 proto_item *it = ptvcursor_add(ptvc, hf_tibia_worldlist_entry_id, 1, ENC_NA);
857                                 ptvcursor_push_subtree(ptvc, it, ett_world);
858
859                                 ptvcursor_add(ptvc, hf_tibia_worldlist_entry_name, 2, convo->has.string_enc | ENC_LITTLE_ENDIAN);
860                                 guint ipv4addr_len = tvb_get_letohs(tvb, ptvcursor_current_offset(ptvc));
861                                 char *ipv4addr_str = (char*)tvb_get_string_enc(wmem_packet_scope(), tvb, ptvcursor_current_offset(ptvc) + 2, ipv4addr_len, ENC_LITTLE_ENDIAN | convo->has.string_enc);
862                                 guint32 ipv4addr = ipv4tonl(ipv4addr_str);
863                                 ptvcursor_add(ptvc, hf_tibia_worldlist_entry_ip, 2, ENC_LITTLE_ENDIAN | convo->has.string_enc);
864                                 guint16 port = tvb_get_letohs(tvb, ptvcursor_current_offset(ptvc));
865                                 ptvcursor_add(ptvc, hf_tibia_worldlist_entry_port, 2, ENC_LITTLE_ENDIAN);
866                                 ptvcursor_add(ptvc, hf_tibia_worldlist_entry_preview, 1, ENC_NA);
867
868                                 ptvcursor_pop_subtree(ptvc);
869
870                                 register_gameserv_addr(convo, ipv4addr, port);
871                             }
872                             ptvcursor_pop_subtree(ptvc);
873                         }
874
875                         guint8 char_count = tvb_get_guint8(tvb, ptvcursor_current_offset(ptvc));
876                         ptvcursor_add(ptvc, hf_tibia_charlist_length, 1, ENC_NA);
877                         if (char_count) {
878                             ptvcursor_add_with_subtree(ptvc, hf_tibia_charlist, SUBTREE_UNDEFINED_LENGTH, ENC_NA, ett_charlist);
879                             while (char_count--) {
880                                 proto_item *it = ptvcursor_add(ptvc, hf_tibia_worldlist_entry_id, 1, ENC_NA);
881                                 ptvcursor_push_subtree(ptvc, it, ett_char);
882                                 ptvcursor_add(ptvc, hf_tibia_charlist_entry_name, 2, convo->has.string_enc | ENC_LITTLE_ENDIAN);
883
884
885                                 ptvcursor_pop_subtree(ptvc);
886                             }
887                             ptvcursor_pop_subtree(ptvc);
888                         }
889                     } else {
890                         guint8 char_count = tvb_get_guint8(tvb, ptvcursor_current_offset(ptvc));
891                         ptvcursor_add(ptvc, hf_tibia_charlist_length, 1, ENC_NA);
892                         if (char_count) {
893                             ptvcursor_add_with_subtree(ptvc, hf_tibia_charlist, SUBTREE_UNDEFINED_LENGTH, ENC_NA, ett_charlist);
894
895                             while (char_count--) {
896                                 proto_item *it = ptvcursor_add(ptvc, hf_tibia_charlist_entry_name, 2, convo->has.string_enc | ENC_LITTLE_ENDIAN);
897                                 ptvcursor_push_subtree(ptvc, it, ett_char);
898
899                                 ptvcursor_add(ptvc, hf_tibia_charlist_entry_world, 2, ENC_LITTLE_ENDIAN | convo->has.string_enc);
900
901                                 guint32 ipv4addr = tvb_get_ipv4(tvb, ptvcursor_current_offset(ptvc));
902                                 ptvcursor_add(ptvc, hf_tibia_charlist_entry_ip, 4, ENC_BIG_ENDIAN);
903
904                                 guint16 port = tvb_get_letohs(tvb, ptvcursor_current_offset(ptvc));
905                                 ptvcursor_add(ptvc, hf_tibia_charlist_entry_port, 2, ENC_BIG_ENDIAN);
906
907
908                                 ptvcursor_pop_subtree(ptvc);
909
910                                 register_gameserv_addr(convo, ipv4addr, port);
911                             }
912
913                             ptvcursor_pop_subtree(ptvc);
914                         }
915
916                         ptvcursor_add(ptvc, hf_tibia_pacc_days, 2, ENC_LITTLE_ENDIAN);
917                     }
918                     break;
919                 default:
920                     offset = ptvcursor_current_offset(ptvc);
921                     call_data_dissector(tvb_new_subset_length(tvb, offset, len - offset), pinfo, ptvcursor_tree(ptvc));
922                     ptvcursor_advance(ptvc, len - offset);
923             }
924
925             ptvcursor_pop_subtree(ptvc);
926
927             col_append_fstr(pinfo->cinfo, COL_INFO, " %s (0x%x)",
928                     val_to_str(cmd, from_loginserv_packet_types, "Unknown"), cmd);
929
930             if (ptvcursor_current_offset(ptvc) >= len)
931                 break;
932
933             col_append_str(pinfo->cinfo, COL_INFO, ",");
934         }
935     }
936
937     offset = ptvcursor_current_offset(ptvc);
938     ptvcursor_free(ptvc);
939
940     return offset;
941 }
942
943 static void
944 dissect_coord(ptvcursor_t *ptvc, gboolean with_stackpos)
945 {
946     tvbuff_t *tvb;
947     proto_tree *tree;
948     int offset;
949
950     guint32 x, y, z, stackpos;
951     proto_item *coords_tuple = ptvcursor_add_with_subtree(ptvc, hf_tibia_coords, SUBTREE_UNDEFINED_LENGTH, ENC_NA, ett_coords);
952     {
953         tvb = ptvcursor_tvbuff(ptvc);
954         tree = ptvcursor_tree(ptvc);
955         offset = ptvcursor_current_offset(ptvc);
956
957         proto_tree_add_item_ret_uint(tree, hf_tibia_coords_x, tvb, offset, 2, ENC_LITTLE_ENDIAN, &x);
958         offset += 2;
959         proto_tree_add_item_ret_uint(tree, hf_tibia_coords_y, tvb, offset, 2, ENC_LITTLE_ENDIAN, &y);
960         offset += 2;
961         proto_tree_add_item_ret_uint(tree, hf_tibia_coords_z, tvb, offset, 1, ENC_NA, &z);
962         offset += 1;
963
964         ptvcursor_advance(ptvc, 5);
965     }
966     if (with_stackpos) {
967         proto_tree_add_item_ret_uint(tree, hf_tibia_stackpos, tvb, offset, 1, ENC_NA, &stackpos);
968         proto_item_set_text(coords_tuple, "Coordinates: (%u, %u, %u)[%u]", x, y, z, stackpos);
969         ptvcursor_advance(ptvc, 1);
970     } else {
971         proto_item_set_text(coords_tuple, "Coordinates: (%u, %u, %u)", x, y, z);
972     }
973
974     ptvcursor_pop_subtree(ptvc);
975 }
976
977
978 static int
979 dissect_gameserv_packet(struct tibia_convo *convo, tvbuff_t *tvb, int offset, int len, packet_info *pinfo, proto_tree *tree, gboolean first_fragment)
980 {
981     ptvcursor_t *ptvc = ptvcursor_new(tree, tvb, offset);
982
983     col_append_str(pinfo->cinfo, COL_INFO, first_fragment ? " commands:" : ",");
984     len += offset;
985
986     if (ptvcursor_current_offset(ptvc) < len) {
987         for (;;) {
988             int cmd = tvb_get_guint8(tvb, ptvcursor_current_offset(ptvc));
989             ptvcursor_add_with_subtree(ptvc, hf_tibia_gameserv_command, 1, convo->has.string_enc, ett_command);
990             ptvcursor_advance(ptvc, 1);
991
992             switch ((enum gameserv_cmd)cmd) {
993                 case S_DLG_INFO:
994                 case S_DLG_ERROR:
995                 case S_DLG_TOOMANYPLAYERS:
996                     ptvcursor_add(ptvc, cmd == S_DLG_ERROR ? hf_tibia_dlg_error : hf_tibia_dlg_info, 2, ENC_LITTLE_ENDIAN | convo->has.string_enc);
997                     break;
998                 case S_GMACTIONS: /* 0x0B, Used to be 32 unknown bytes, but with GMs removed it                                     might not be in use anymore */
999                     ptvcursor_add(ptvc, hf_tibia_unknown, 32, ENC_NA);
1000                     break;
1001                 case S_PLAYERLOC: /* 0x64,Coord pos */
1002                     dissect_coord(ptvc, FALSE);
1003                     break;
1004                 case S_TILEUPDATE: /* 0x69,Coord pos TileDescription td */
1005                     dissect_coord(ptvc, FALSE);
1006                     ptvcursor_add(ptvc, hf_tibia_unknown, len - ptvcursor_current_offset(ptvc), ENC_NA);
1007                     break;
1008                 case S_ADDITEM: /* 0x6a,Coord pos ThingDescription thing */
1009                     dissect_coord(ptvc, FALSE);
1010                     ptvcursor_add(ptvc, hf_tibia_unknown, len - ptvcursor_current_offset(ptvc), ENC_NA);
1011                     break;
1012                 case S_REPLACEITEM: /* 0x6b,Coord pos Byte stackpos ThingDescription thing */
1013                     dissect_coord(ptvc, TRUE);
1014                     ptvcursor_add(ptvc, hf_tibia_unknown, len - ptvcursor_current_offset(ptvc), ENC_NA);
1015                     break;
1016                 case S_REMOVEITEM: /* 0x6c,Coord pos Byte stackpos */
1017                     dissect_coord(ptvc, TRUE);
1018                     break;
1019                 case S_MOVE_THING: /* 0x6d, */
1020                     dissect_coord(ptvc, TRUE);
1021                     dissect_coord(ptvc, FALSE);
1022                     break;
1023                 case S_CONTAINER: /* 0x6e,Byte index Short containerIcon Byte slotCount ThingDescription item */
1024                     ptvcursor_add(ptvc, hf_tibia_container, 1, ENC_NA);
1025                     ptvcursor_add(ptvc, hf_tibia_container_icon, 2, ENC_LITTLE_ENDIAN);
1026                     ptvcursor_add(ptvc, hf_tibia_container_slots, 2, ENC_LITTLE_ENDIAN);
1027                     ptvcursor_add(ptvc, hf_tibia_unknown, len - ptvcursor_current_offset(ptvc), ENC_NA);
1028                     break;
1029                 case S_CONTAINERCLOSE: /* 0x6f,Byte index */
1030                     ptvcursor_add(ptvc, hf_tibia_container, 1, ENC_NA);
1031                     break;
1032                 case S_ADDITEMCONTAINER: /* 0x70,Byte index ThingDescription itm */
1033                     ptvcursor_add(ptvc, hf_tibia_container, 1, ENC_NA);
1034                     ptvcursor_add(ptvc, hf_tibia_unknown, len - ptvcursor_current_offset(ptvc), ENC_NA);
1035                     break;
1036                 case S_TRANSFORMITEMCONTAINER:/* 0x71,Byte index Byte slot */
1037                     ptvcursor_add(ptvc, hf_tibia_container, 1, ENC_NA);
1038                     ptvcursor_add(ptvc, hf_tibia_container_slot, 1, ENC_NA);
1039                     break;
1040                 case S_REMOVEITEMCONTAINER: /* 0x72,Byte index Byte slot */
1041                     ptvcursor_add(ptvc, hf_tibia_container, 1, ENC_NA);
1042                     ptvcursor_add(ptvc, hf_tibia_container_slot, 1, ENC_NA);
1043                     break;
1044                 case S_INVENTORYEMPTY: /* 0x78,Byte invSlot */
1045                     ptvcursor_add(ptvc, hf_tibia_inventory, 1, ENC_NA);
1046                     break;
1047                 case S_INVENTORYITEM: /* 0x79,Byte invSlot ThingDescription itm */
1048                     ptvcursor_add(ptvc, hf_tibia_inventory, 1, ENC_NA);
1049                     ptvcursor_add(ptvc, hf_tibia_unknown, len - ptvcursor_current_offset(ptvc), ENC_NA);
1050                     break;
1051                 case S_TRADEREQ: /* 0x7d,String otherperson Byte slotCount ThingDescription itm */
1052                     ptvcursor_add(ptvc, hf_tibia_player, 2, ENC_LITTLE_ENDIAN | convo->has.string_enc);
1053                     ptvcursor_add(ptvc, hf_tibia_inventory, 1, ENC_NA);
1054                     ptvcursor_add(ptvc, hf_tibia_unknown, len - ptvcursor_current_offset(ptvc), ENC_NA);
1055                     break;
1056                 case S_TRADEACK: /* 0x7e,String otherperson Byte slotCount ThingDescription itm */
1057                     ptvcursor_add(ptvc, hf_tibia_player, 2, ENC_LITTLE_ENDIAN | convo->has.string_enc);
1058                     ptvcursor_add(ptvc, hf_tibia_inventory, 1, ENC_NA);
1059                     ptvcursor_add(ptvc, hf_tibia_unknown, len - ptvcursor_current_offset(ptvc), ENC_NA);
1060                     break;
1061
1062                 case S_TRADECLOSE: /* 0x7f, */
1063                     break;
1064                 case S_LIGHTLEVEL: /* 0x82,Byte lightlevel Byte lightcolor */
1065                     ptvcursor_add(ptvc, hf_tibia_light_level, 1, ENC_NA);
1066                     ptvcursor_add(ptvc, hf_tibia_light_color, 1, ENC_NA);
1067                     break;
1068                 case S_MAGIC_EFFECT: /* 0x83, */
1069                     dissect_coord(ptvc, FALSE);
1070                     ptvcursor_add(ptvc, hf_tibia_magic_effect_id, 1, ENC_NA);
1071                     break;
1072                 case S_ANIMATEDTEXT: /* 0x84,Coord pos Byte color String message */
1073                     dissect_coord(ptvc, FALSE);
1074                     ptvcursor_add(ptvc, hf_tibia_animated_text_color, 1, ENC_NA);
1075                     ptvcursor_add(ptvc, hf_tibia_animated_text, 2, ENC_LITTLE_ENDIAN | convo->has.string_enc);
1076                     break;
1077                 case S_DISTANCESHOT: /* 0x85,Coord pos1 Byte stackposition Coord pos2 */
1078                     dissect_coord(ptvc, FALSE);
1079                     ptvcursor_add(ptvc, hf_tibia_projectile, 4, ENC_LITTLE_ENDIAN);
1080                     dissect_coord(ptvc, FALSE);
1081                     break;
1082                 case S_CREATURESQUARE: /* 0x86,Long creatureid Byte squarecolor */
1083                     ptvcursor_add(ptvc, hf_tibia_creature, 4, ENC_LITTLE_ENDIAN);
1084                     ptvcursor_add(ptvc, hf_tibia_squarecolor, 1, ENC_NA);
1085                     break;
1086                 case S_CREATURE_HEALTH: /* 0x8C, */
1087                     ptvcursor_add(ptvc, hf_tibia_creature, 1, ENC_LITTLE_ENDIAN);
1088                     ptvcursor_add(ptvc, hf_tibia_creature_health, 1, ENC_NA);
1089                     break;
1090                 case S_CREATURELIGHT: /* 0x8d,Long creatureid Byte ? Byte ? */
1091                     ptvcursor_add(ptvc, hf_tibia_creature, 1, ENC_LITTLE_ENDIAN);
1092                     ptvcursor_add(ptvc, hf_tibia_unknown, 2, ENC_NA);
1093                     break;
1094                 case S_SETOUTFIT: /* 0x8e,Long creatureid Byte lookType Byte headType Byte bodyType Byte legsType Byte feetType // can extended look go here too? */
1095                     ptvcursor_add(ptvc, hf_tibia_creature, 1, ENC_LITTLE_ENDIAN);
1096                     ptvcursor_add(ptvc, hf_tibia_unknown, len - ptvcursor_current_offset(ptvc), ENC_NA);
1097                     break;
1098                 case S_TEXTWINDOW: /* 0x96,Long windowId Byte icon Byte maxlength String message */
1099                     ptvcursor_add(ptvc, hf_tibia_window, 4, ENC_LITTLE_ENDIAN);
1100                     ptvcursor_add(ptvc, hf_tibia_window_icon, 1, ENC_NA);
1101                     ptvcursor_add(ptvc, hf_tibia_window_textlen, 1, ENC_NA);
1102                     ptvcursor_add(ptvc, hf_tibia_window_text, 1, ENC_LITTLE_ENDIAN | convo->has.string_enc);
1103                     break;
1104                 case S_PLAYER_CONDITION: /* 0xA2, */
1105                     proto_tree_add_bitmask(ptvcursor_tree(ptvc), ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc), hf_tibia_char_cond, ett_char_cond, char_conds, ENC_LITTLE_ENDIAN);
1106                     ptvcursor_advance(ptvc, sizeof(guint32));
1107                     break;
1108                 case S_CANCELATTACK: /* 0xA3, */
1109                     break;
1110                 case S_CHANNEL_OPEN:
1111                     ptvcursor_add(ptvc, hf_tibia_channel_id, 2, ENC_LITTLE_ENDIAN);
1112                     ptvcursor_add(ptvc, hf_tibia_channel_name, 2, ENC_LITTLE_ENDIAN|convo->has.string_enc);
1113                     ptvcursor_add(ptvc, hf_tibia_unknown, 4, ENC_NA);
1114                     break;
1115                 case S_OPENPRIV: /* 0xAD,String playerName */
1116                     ptvcursor_add(ptvc, hf_tibia_player, 2, ENC_LITTLE_ENDIAN | convo->has.string_enc);
1117                     break;
1118                 case S_TEXTMESSAGE: /* 0xB4,Byte msgClass String string */
1119                     ptvcursor_add(ptvc, hf_tibia_textmsg_class, 1, ENC_NA);
1120                     ptvcursor_add(ptvc, hf_tibia_textmsg, 2, ENC_LITTLE_ENDIAN | convo->has.string_enc);
1121                     break;
1122                 case S_CANCELWALK: /* 0xB5,Byte direction */
1123                     ptvcursor_add(ptvc, hf_tibia_walk_dir, 1, ENC_NA);
1124                     break;
1125                 case S_VIPADD: /* 0xd2,long guid string name byte isonline */
1126                     ptvcursor_add(ptvc, hf_tibia_vip, 4, ENC_LITTLE_ENDIAN);
1127                     ptvcursor_add(ptvc, hf_tibia_player, 2, ENC_LITTLE_ENDIAN | convo->has.string_enc);
1128                     ptvcursor_add(ptvc, hf_tibia_vip_online, 1, ENC_NA);
1129                     break;
1130                 case S_VIPLOGIN: /* 0xd3,long guid */
1131                     ptvcursor_add(ptvc, hf_tibia_vip, 4, ENC_LITTLE_ENDIAN);
1132                     break;
1133                 case S_VIPLOGOUT: /* 0xd4long guid*/
1134                     ptvcursor_add(ptvc, hf_tibia_vip, 4, ENC_LITTLE_ENDIAN);
1135                     break;
1136                 case S_PING:
1137                     break;
1138                 case S_NONCE: /* 0x1F, */
1139                     ptvcursor_add(ptvc, hf_tibia_nonce, 5, ENC_NA);
1140                     break;
1141
1142                 case S_MAPINIT: /* 0x0A, Long playerCreatureId Int unknownU16 (Byte reportBugs?) */
1143                 case S_OUTFITLIST: /* 0xC8,Byte lookType Byte headType Byte bodyType Byte legsType Byte feetType Byte firstModel Byte lastModel */
1144                     /* TODO This changed with mounts and outfit */
1145                 case S_FLOORUP: /* 0xBE,Advanced topic; read separate text */
1146                 case S_FLOORDOWN: /* 0xBF,Advanced topic; read separate text */
1147                 case S_SPEAK: /* 0xAA, */
1148                 case S_CHANNELSDIALOG: /* 0xAB,Byte channelCount (Int channelId String channelName) */
1149                 case S_STATUSMSG: /* 0xA0,Status status */
1150                 case S_SKILLS: /* 0xA1,Skills skills */
1151                 case S_CREATURESPEED: /* 0x8f,YIKES! I didnt handle this! */
1152                 case S_GO_NORTH: /* 0x65,MapDescription (18,1) */
1153                 case S_GO_EAST: /* 0x66,MapDescription (1,14) */
1154                 case S_GO_SOUTH: /* 0x67,MapDescription (18,1) */
1155                 case S_GO_WEST: /* 0x68,MapDescription (1,14) */
1156                 default:
1157                     offset = ptvcursor_current_offset(ptvc);
1158                     call_data_dissector(tvb_new_subset_length(tvb, offset, len - offset), pinfo, ptvcursor_tree(ptvc));
1159                     ptvcursor_advance(ptvc, len - offset);
1160             }
1161
1162
1163             ptvcursor_pop_subtree(ptvc);
1164
1165             col_append_fstr(pinfo->cinfo, COL_INFO, " %s (0x%x)",
1166                     val_to_str(cmd, from_gameserv_packet_types, "Unknown"), cmd);
1167
1168             if (ptvcursor_current_offset(ptvc) >= len)
1169                 break;
1170
1171             col_append_str(pinfo->cinfo, COL_INFO, ",");
1172         }
1173     }
1174
1175     offset = ptvcursor_current_offset(ptvc);
1176     ptvcursor_free(ptvc);
1177
1178     return offset;
1179 }
1180
1181 static int
1182 dissect_client_packet(struct tibia_convo *convo, tvbuff_t *tvb, int offset, int len, packet_info *pinfo, proto_tree *tree, gboolean first_fragment)
1183 {
1184     ptvcursor_t *ptvc = ptvcursor_new(tree, tvb, offset);
1185
1186     col_append_str(pinfo->cinfo, COL_INFO, first_fragment ? " commands:" : ",");
1187     len += offset;
1188
1189     if (ptvcursor_current_offset(ptvc) < len) {
1190         for (;;) {
1191             int cmd = tvb_get_guint8(tvb, ptvcursor_current_offset(ptvc));
1192             ptvcursor_add_with_subtree(ptvc, hf_tibia_client_command, 1, convo->has.string_enc, ett_command);
1193             ptvcursor_advance(ptvc, 1);
1194
1195             switch ((enum client_cmd)cmd) {
1196                 case C_PLAYER_SPEECH: {
1197                     guint8 type = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc));
1198
1199                     ptvcursor_add(ptvc, hf_tibia_speech_type, 1, ENC_NA);
1200                     if (type == 0x7)
1201                         ptvcursor_add(ptvc, hf_tibia_channel_id, 2, ENC_LITTLE_ENDIAN);
1202                     ptvcursor_add(ptvc, hf_tibia_chat_msg, 2, ENC_LITTLE_ENDIAN|convo->has.string_enc);
1203                     }
1204                     break;
1205                 case C_PONG:
1206                     break;
1207                 default:
1208                     offset = ptvcursor_current_offset(ptvc);
1209                     call_data_dissector(tvb_new_subset_length(tvb, offset, len - offset), pinfo, ptvcursor_tree(ptvc));
1210                     ptvcursor_advance(ptvc, len - offset);
1211             }
1212
1213             ptvcursor_pop_subtree(ptvc);
1214
1215             col_append_fstr(pinfo->cinfo, COL_INFO, " %s (0x%x)",
1216                     val_to_str(cmd, from_client_packet_types, "Unknown"), cmd);
1217
1218             if (ptvcursor_current_offset(ptvc) >= len)
1219                 break;
1220
1221             col_append_str(pinfo->cinfo, COL_INFO, ",");
1222         }
1223     }
1224
1225     offset = ptvcursor_current_offset(ptvc);
1226     ptvcursor_free(ptvc);
1227
1228     return offset;
1229 }
1230
1231 static int
1232 dissect_game_packet(struct tibia_convo *convo, tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, gboolean is_xtea_encrypted, gboolean first_fragment)
1233 {
1234     proto_item *ti = NULL;
1235     int len = tvb_captured_length_remaining(tvb, offset);
1236
1237     if (show_acc_info) {
1238         if (convo->has.session_key) {
1239             if (convo->session_key) {
1240                 ti = proto_tree_add_string(tree, hf_tibia_session_key_convo, tvb, offset, 0, (const char*)convo->session_key);
1241                 PROTO_ITEM_SET_GENERATED(ti);
1242             }
1243         } else {
1244             if (convo->acc) {
1245                 ti = proto_tree_add_string(tree, hf_tibia_acc_name_convo, tvb, offset, 0, (const char*)convo->acc);
1246                 PROTO_ITEM_SET_GENERATED(ti);
1247             }
1248
1249             if (convo->pass) {
1250                 ti = proto_tree_add_string(tree, hf_tibia_acc_pass_convo, tvb, offset, 0, (const char*)convo->pass);
1251                 PROTO_ITEM_SET_GENERATED(ti);
1252             }
1253         }
1254     }
1255
1256     if (show_char_name && convo->char_name) {
1257         ti = proto_tree_add_string(tree, hf_tibia_char_name_convo, tvb, offset, 0, (const char*)convo->char_name);
1258         PROTO_ITEM_SET_GENERATED(ti);
1259     }
1260
1261     if (is_xtea_encrypted) {
1262         if (pinfo->num > convo->xtea_framenum) {
1263             if (show_xtea_key && convo->has.xtea) {
1264                 ti = proto_tree_add_bytes_with_length(tree, hf_tibia_xtea_key, tvb, 0, 0, (guint8*)convo->xtea_key, XTEA_KEY_LEN);
1265                 PROTO_ITEM_SET_GENERATED(ti);
1266             }
1267
1268             int end = offset + len;
1269
1270             if (len % 8 != 0)
1271                 return -1;
1272
1273             guint8 *decrypted_buffer = (guint8*)g_malloc(len);
1274
1275             for (guint8 *dstblock = decrypted_buffer; offset < end; offset += 8) {
1276                 decrypt_xtea_le_ecb(dstblock, tvb_get_ptr(tvb, offset, 8), convo->xtea_key, 32);
1277                 dstblock += 8;
1278             }
1279
1280             tvb = tvb_new_child_real_data(tvb, decrypted_buffer, len, len);
1281             tvb_set_free_cb(tvb, g_free);
1282             add_new_data_source(pinfo, tvb, "Decrypted Game Data");
1283
1284             offset = 0;
1285         } else {
1286             proto_tree_add_item(tree, hf_tibia_undecoded_xtea_data, tvb, offset, len, ENC_NA);
1287             return offset;
1288         }
1289     }
1290     if (convo->has.xtea) {
1291         len = tvb_get_letohs(tvb, offset);
1292         ti = proto_tree_add_item(tree, hf_tibia_payload_len, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1293         offset += 2;
1294         if (len > tvb_captured_length_remaining(tvb, offset)) {
1295             expert_add_info(pinfo, ti, &ei_xtea_len_toobig);
1296             return offset;
1297         }
1298     }
1299
1300
1301     if (pinfo->srcport == convo->servport && convo->loginserv_is_peer)
1302         return dissect_loginserv_packet(convo, tvb, offset, len, pinfo, tree, first_fragment);
1303
1304     if (!dissect_game_commands) {
1305         call_data_dissector(tvb_new_subset_length(tvb, offset, len), pinfo, tree);
1306         return offset + len;
1307     }
1308
1309     if (pinfo->srcport == convo->servport)
1310         return dissect_gameserv_packet(convo, tvb, offset, len, pinfo, tree, first_fragment);
1311     else
1312         return dissect_client_packet(convo, tvb, offset, len, pinfo, tree, first_fragment);
1313 }
1314
1315 static int
1316 dissect_tibia(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *fragment_num)
1317 {
1318     tvbuff_t *tvb_decrypted = tvb;
1319     gboolean is_xtea_encrypted = FALSE;
1320     enum { TIBIA_GAMESERV, TIBIA_LOGINSERV } serv = TIBIA_GAMESERV;
1321     guint16 plen = tvb_get_letohs(tvb, 0) + sizeof(guint16);
1322
1323     /* if announced length != real length it's not a tibia packet */
1324     if (tvb_reported_length_remaining(tvb, 0) != plen)
1325         return 0;
1326
1327     struct tibia_convo *convo = tibia_get_convo(pinfo);
1328
1329     int offset = 2;
1330     int a32len = tvb_reported_length_remaining(tvb, offset + 4);
1331     guint32 packet_cksum = tvb_get_letohl(tvb, offset);
1332     guint32 computed_cksum = GUINT32_TO_LE(adler32_bytes(tvb_get_ptr(tvb, offset + 4, a32len), a32len));
1333     convo->has.adler32 = packet_cksum == computed_cksum;
1334     if (convo->has.adler32)
1335         offset += sizeof(guint32);
1336
1337     /* FIXME Tibia >=11.11 has a sequence number instead, this is yet unhandled */
1338
1339     /* Is it a nonce? */
1340     if (tvb_get_letohs(tvb, offset) == plen - offset - sizeof(guint16)
1341             && tvb_get_guint8(tvb, offset+sizeof(guint16)) == S_NONCE) {
1342         /* Don't do anything. We'll handle it as unencrypted game command later */
1343     } else {
1344         guint8 cmd;
1345         guint16 version;
1346         struct proto_traits version_has;
1347         cmd = tvb_get_guint8(tvb, offset);
1348         offset += sizeof(guint8);
1349         offset += sizeof(guint16); /* OS */
1350         version = tvb_get_letohs(tvb, offset);
1351         version_has = get_version_traits(version);
1352
1353         switch(cmd) {
1354             case C_GET_CHARLIST:
1355                 if ((700 <= version && version <= 760 && !convo->has.adler32 && 25 <= plen && plen <= 54)
1356                         || get_version_get_charlist_packet_size(&version_has) == plen) {
1357                     serv = TIBIA_LOGINSERV;
1358                     convo->loginserv_is_peer = TRUE;
1359                 }
1360                 break;
1361             case C_LOGIN_CHAR:
1362                 /* The outcast client I tried, zero-pads the 760 login request.
1363                  * I don't think the Cipsoft client ever did this.
1364                  */
1365                 if ((700 <= version && version <= 760 && !convo->has.adler32 && 25 <= plen && plen <= 54)
1366                         ||  get_version_char_login_packet_size(&version_has) == plen)
1367                     serv = TIBIA_LOGINSERV;
1368                 break;
1369             default:
1370                 is_xtea_encrypted = convo->has.xtea;
1371         }
1372     }
1373
1374
1375     offset = 0; /* With the version extracted, let's build the tree */
1376
1377     col_set_str(pinfo->cinfo, COL_PROTOCOL, "Tibia");
1378     if (GPOINTER_TO_UINT(fragment_num) == 1) {
1379         /* We don't want to repeat ourselves in the info column if there are fragments */
1380         if (serv == TIBIA_LOGINSERV)
1381             col_set_str(pinfo->cinfo, COL_INFO, "Login");
1382         else if (pinfo->srcport == convo->servport)
1383             col_set_str(pinfo->cinfo, COL_INFO, "Server");
1384         else
1385             col_set_str(pinfo->cinfo, COL_INFO, "Client");
1386
1387     }
1388
1389     proto_item *ti = proto_tree_add_item(tree, proto_tibia, tvb, 0, -1, ENC_NA);
1390     proto_tree *tibia_tree = proto_item_add_subtree(ti, ett_tibia);
1391
1392     proto_tree_add_item(tibia_tree, hf_tibia_len, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1393     offset += 2;
1394     if (convo->has.adler32) {
1395         proto_tree_add_checksum(tibia_tree, tvb, offset, hf_tibia_adler32, hf_tibia_adler32_status, &ei_adler32_checksum_bad, pinfo, computed_cksum, ENC_LITTLE_ENDIAN, PROTO_CHECKSUM_VERIFY);
1396         offset += 4;
1397     } else if (convo->has.compression) {
1398         offset += 4;
1399     }
1400
1401     if (serv == TIBIA_GAMESERV)
1402         return dissect_game_packet(convo, tvb, offset, pinfo, tibia_tree, is_xtea_encrypted, GPOINTER_TO_UINT(fragment_num) == 1);
1403
1404     proto_tree_add_item(tibia_tree, hf_tibia_client_command, tvb, offset, 1, ENC_LITTLE_ENDIAN);
1405     offset += 1;
1406     proto_tree_add_item(tibia_tree, hf_tibia_os, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1407     offset += 2;
1408
1409     convo->proto_version = tvb_get_letohs(tvb, offset);
1410     convo->has = get_version_traits(convo->proto_version);
1411     proto_tree_add_item(tibia_tree, hf_tibia_proto_version, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1412     offset += 2;
1413     if (convo->has.client_version) {
1414         proto_tree_add_item(tibia_tree, hf_tibia_client_version, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1415         offset += 4;
1416     }
1417     if (convo->loginserv_is_peer) {
1418         proto_tree *vertree;
1419         /* The first 4 bytes of the client's tibia.pic, tibia.dat and tibia.spr files */
1420         proto_item *subti = proto_tree_add_item(tibia_tree, hf_tibia_file_versions, tvb, offset, 12, ENC_NA);
1421         vertree = proto_item_add_subtree(subti, ett_file_versions);
1422         proto_tree_add_item(vertree, hf_tibia_file_version_spr, tvb, offset, 4, ENC_BIG_ENDIAN);
1423         offset += 4;
1424         proto_tree_add_item(vertree, hf_tibia_file_version_dat, tvb, offset, 4, ENC_BIG_ENDIAN);
1425         offset += 4;
1426         proto_tree_add_item(vertree, hf_tibia_file_version_pic, tvb, offset, 4, ENC_BIG_ENDIAN);
1427         offset += 4;
1428     } else if (convo->has.game_content_revision) {
1429         proto_tree_add_item(tibia_tree, hf_tibia_content_revision, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1430         offset += 2;
1431     }
1432
1433     if (convo->has.game_preview) {
1434         proto_tree_add_item(tibia_tree, hf_tibia_game_preview_state, tvb, offset, 1, ENC_NA);
1435         offset += 1;
1436     }
1437
1438     int rsa1_end = 0; /* End of first RSA block */
1439     if (convo->has.rsa) {
1440         gcry_sexp_t privkey;
1441         if (!(privkey = convo_get_privkey(convo))) {
1442             proto_tree_add_item(tibia_tree, hf_tibia_undecoded_rsa_data, tvb, offset, plen - offset, ENC_NA);
1443             return offset;
1444         }
1445
1446         guint ciphertext_len = tvb_captured_length_remaining(tvb, offset);
1447         if (ciphertext_len < 128) {
1448             expert_add_info(pinfo, ti, &ei_rsa_ciphertext_too_short);
1449             return offset;
1450         }
1451         rsa1_end = offset + 128;
1452         guint8 *payload = (guint8*)tvb_memdup(pinfo->pool, tvb, offset, 128);
1453
1454         char *err = NULL;
1455         size_t payload_len;
1456         if (!(payload_len = rsa_decrypt_inplace(128, payload, privkey, FALSE, &err))) {
1457             expert_add_info_format(pinfo, ti, &ei_rsa_decrypt_failed, "Decrypting RSA block failed: %s", err);
1458             g_free(err);
1459             return offset;
1460         }
1461         size_t leading_zeroes = 128 - payload_len;
1462         memmove(payload + leading_zeroes, payload, payload_len);
1463         memset(payload, 0x00, leading_zeroes);
1464
1465         tvb_decrypted = tvb_new_child_real_data(tvb, payload, 128, 128);
1466         add_new_data_source(pinfo, tvb_decrypted, "Decrypted Login Data");
1467
1468         if (tvb_get_guint8(tvb_decrypted, 0) != 0x00) {
1469             expert_add_info(pinfo, ti, &ei_rsa_plaintext_no_leading_zero);
1470             return offset;
1471         }
1472
1473         offset = 1;
1474
1475         tvb_memcpy(tvb_decrypted, convo->xtea_key, 1, XTEA_KEY_LEN);
1476         proto_tree_add_item(tibia_tree, hf_tibia_xtea_key, tvb_decrypted, 1, XTEA_KEY_LEN, ENC_NA);
1477         offset += XTEA_KEY_LEN;
1478         convo->xtea_framenum = pinfo->num;
1479     }
1480
1481     if (!convo->loginserv_is_peer && convo->has.gmbyte) {
1482         proto_tree_add_item(tibia_tree, hf_tibia_loginflags_gm, tvb_decrypted, offset, 1, ENC_NA);
1483         offset += 1;
1484     }
1485
1486     int len;
1487     if (convo->has.session_key && !convo->loginserv_is_peer) {
1488         /* OTServs I tested against use "$acc\n$pacc" as session key */
1489         if (convo->session_key) {
1490             proto_tree_add_item_ret_length(tibia_tree, hf_tibia_session_key, tvb_decrypted, offset, 2, ENC_LITTLE_ENDIAN | convo->has.string_enc, &len);
1491         } else {
1492             proto_tree_add_item_ret_string_and_length(tibia_tree, hf_tibia_session_key, tvb_decrypted, offset, 2, ENC_LITTLE_ENDIAN | convo->has.string_enc, wmem_file_scope(), &convo->session_key, &len);
1493         }
1494         offset += len;
1495     } else if (convo->has.acc_name) {
1496         if (convo->acc) {
1497             proto_tree_add_item_ret_length(tibia_tree, hf_tibia_acc_name, tvb_decrypted, offset, 2, ENC_LITTLE_ENDIAN | convo->has.string_enc, &len);
1498         } else {
1499             proto_tree_add_item_ret_string_and_length(tibia_tree, hf_tibia_acc_name, tvb_decrypted, offset, 2, ENC_LITTLE_ENDIAN | convo->has.string_enc, wmem_file_scope(), &convo->acc, &len);
1500         }
1501         offset += len;
1502     } else /* account number */ {
1503         char *accnum = wmem_strdup_printf(wmem_packet_scope(), "%" G_GUINT32_FORMAT, tvb_get_letohl(tvb_decrypted, offset));
1504         proto_tree_add_string(tibia_tree, hf_tibia_acc_number, tvb_decrypted, offset, 4, accnum);
1505         if (!convo->acc)
1506             convo->acc = (guint8*)wmem_strdup(wmem_file_scope(), accnum);
1507         offset += 4;
1508     }
1509
1510     if (!convo->loginserv_is_peer) {
1511         if (convo->char_name) {
1512             proto_tree_add_item_ret_length(tibia_tree, hf_tibia_char_name, tvb_decrypted, offset, 2, ENC_LITTLE_ENDIAN | convo->has.string_enc, &len);
1513         } else {
1514             proto_tree_add_item_ret_string_and_length(tibia_tree, hf_tibia_char_name, tvb_decrypted, offset, 2, ENC_LITTLE_ENDIAN | convo->has.string_enc, wmem_file_scope(), &convo->char_name, &len);
1515         }
1516         offset += len;
1517     }
1518
1519     if (!convo->has.session_key || convo->loginserv_is_peer) {
1520         if (convo->pass) {
1521             proto_tree_add_item_ret_length(tibia_tree, hf_tibia_acc_pass, tvb_decrypted, offset, 2, ENC_LITTLE_ENDIAN | convo->has.string_enc, &len);
1522         } else {
1523             proto_tree_add_item_ret_string_and_length(tibia_tree, hf_tibia_acc_pass, tvb_decrypted, offset, 2, ENC_LITTLE_ENDIAN | convo->has.string_enc, wmem_file_scope(), &convo->pass, &len);
1524         }
1525         offset += len;
1526     }
1527
1528     if (convo->loginserv_is_peer && convo->has.hwinfo) {
1529         proto_item *item;
1530         proto_tree *infotree, *subtree;
1531
1532         item = proto_tree_add_item(tibia_tree, hf_tibia_client_info, tvb_decrypted, offset, 47, ENC_NA);
1533         infotree = proto_item_add_subtree(item, ett_client_info);
1534
1535         /* Subtree { */
1536         guint locale_id;
1537         const guint8 *locale_name;
1538
1539         item = proto_tree_add_item(infotree, hf_tibia_client_locale, tvb_decrypted, offset, 4, ENC_NA);
1540         subtree = proto_item_add_subtree(item, ett_locale);
1541
1542         proto_tree_add_item_ret_uint(subtree, hf_tibia_client_locale_id, tvb_decrypted, offset, 1, ENC_NA, &locale_id);
1543         offset += 1;
1544
1545         proto_tree_add_item_ret_string(subtree, hf_tibia_client_locale_name, tvb_decrypted, offset, 3, convo->has.string_enc|ENC_NA, wmem_packet_scope(), &locale_name);
1546         offset += 3;
1547         proto_item_set_text(item, "Locale: %s (0x%X)", locale_name, locale_id);
1548         /* } */
1549
1550         proto_tree_add_item(infotree, hf_tibia_client_ram, tvb_decrypted, offset, 2, ENC_LITTLE_ENDIAN);
1551         offset += 2;
1552
1553         proto_tree_add_item(infotree, hf_tibia_unknown, tvb_decrypted, offset, 6, ENC_NA);
1554         offset += 6;
1555
1556         /* Subtree { */
1557         guint clock1, clock2;
1558         const guint8 *cpu;
1559
1560         item = proto_tree_add_item(infotree, hf_tibia_client_cpu, tvb_decrypted, offset, 15, ENC_NA);
1561         subtree = proto_item_add_subtree(item, ett_cpu);
1562
1563         proto_tree_add_item_ret_string(subtree, hf_tibia_client_cpu_name, tvb_decrypted, offset, 9, convo->has.string_enc|ENC_NA, wmem_packet_scope(), &cpu);
1564         offset += 9;
1565
1566         proto_tree_add_item(subtree, hf_tibia_unknown, tvb_decrypted, offset, 2, ENC_NA);
1567         offset += 2;
1568
1569         proto_tree_add_item_ret_uint(subtree, hf_tibia_client_clock, tvb_decrypted, offset, 2, ENC_LITTLE_ENDIAN, &clock1);
1570         offset += 2;
1571
1572         proto_tree_add_item_ret_uint(subtree, hf_tibia_client_clock2, tvb_decrypted, offset, 2, ENC_LITTLE_ENDIAN, &clock2);
1573         offset += 2;
1574
1575         proto_item_set_text(item, "CPU: %s (%uMhz/%uMhz)", cpu, clock2, clock1);
1576         /* } */
1577
1578
1579         proto_tree_add_item(infotree, hf_tibia_unknown, tvb_decrypted, offset, 4, ENC_NA);
1580         offset += 4;
1581
1582         proto_tree_add_item(infotree, hf_tibia_client_gpu, tvb_decrypted, offset, 9, convo->has.string_enc|ENC_NA);
1583         offset += 9;
1584
1585         proto_tree_add_item(infotree, hf_tibia_client_vram, tvb_decrypted, offset, 2, ENC_LITTLE_ENDIAN);
1586         offset += 2;
1587
1588         /* Subtree { */
1589         guint x, y, hz;
1590
1591         item = proto_tree_add_item(infotree, hf_tibia_client_resolution, tvb_decrypted, offset, 5, ENC_NA);
1592         subtree = proto_item_add_subtree(item, ett_resolution);
1593
1594         proto_tree_add_item_ret_uint(subtree, hf_tibia_client_resolution_x, tvb_decrypted, offset, 2, ENC_LITTLE_ENDIAN, &x);
1595         offset += 2;
1596         proto_tree_add_item_ret_uint(subtree, hf_tibia_client_resolution_y, tvb_decrypted, offset, 2, ENC_LITTLE_ENDIAN, &y);
1597         offset += 2;
1598         proto_tree_add_item_ret_uint(subtree, hf_tibia_client_resolution_hz, tvb_decrypted, offset, 1, ENC_LITTLE_ENDIAN, &hz);
1599         offset += 1;
1600
1601         proto_item_set_text(item, "Resolution: %ux%u @ %uHz", x, y, hz);
1602         /* } */
1603
1604     } else if (!convo->loginserv_is_peer && convo->has.nonce) {
1605         proto_tree_add_item(tibia_tree, hf_tibia_nonce, tvb_decrypted, offset, 5, ENC_NA);
1606         offset += 5;
1607     }
1608
1609     if (convo->has.rsa) {
1610         /* Undecoded hardware info maybe */
1611         call_data_dissector(tvb_new_subset_length(tvb_decrypted, offset, 128 - offset), pinfo, tibia_tree);
1612     }
1613
1614     if (rsa1_end)
1615         offset = rsa1_end;
1616
1617     if (offset != plen) {
1618         /* TODO Extended GPU info and authentication token (RSA-encrypted again) */
1619         call_data_dissector(tvb_new_subset_length(tvb, offset, plen - offset), pinfo, tibia_tree);
1620     }
1621     return plen;
1622 }
1623
1624 static const value_string operating_systems[] = {
1625     { 2, "Windows" },
1626     { 0, NULL }
1627 };
1628
1629 static const value_string speech_types[] = {
1630     { 0x1, "Say" },
1631     { 0x2, "Whisper" },
1632     { 0x3, "Yell" },
1633     { 0x7, "Public Channel" },
1634     { 0, NULL }
1635 };
1636
1637 #if defined(HAVE_LIBGNUTLS)
1638 static guint
1639 rsakey_hash(gconstpointer _rsakey)
1640 {
1641     const struct rsakey *rsakey = (const struct rsakey *)_rsakey;
1642     return add_address_to_hash(rsakey->port, &rsakey->addr);
1643 }
1644
1645 static gboolean
1646 rsakey_equal(gconstpointer _a, gconstpointer _b)
1647 {
1648     const struct rsakey *a = (const struct rsakey *)_a,
1649                         *b = (const struct rsakey *)_b;
1650     return a->port == b->port && addresses_equal(&a->addr, &b->addr);
1651 }
1652 static void
1653 rsakey_free(void *_rsakey)
1654 {
1655     struct rsakey *rsakey = (struct rsakey *)_rsakey;
1656
1657     /* gcry_sexp_release(rsakey->privkey); */ /* private key may be shared. */
1658     free_address_wmem(NULL, &rsakey->addr);
1659     g_free(rsakey);
1660 }
1661
1662 static void
1663 rsa_parse_uat(void)
1664 {
1665     g_hash_table_remove_all(rsakeys);
1666
1667     for (guint i = 0; i < nrsakeys; i++) {
1668         struct rsakeys_assoc *uats = &rsakeylist_uats[i];
1669
1670         /* try to load keys file first */
1671         FILE *fp = ws_fopen(uats->keyfile, "rb");
1672         if (!fp) {
1673             report_open_failure(uats->keyfile, errno, FALSE);
1674             return;
1675         }
1676
1677         gnutls_x509_privkey_t priv_key;
1678         char *err = NULL;
1679         if (*uats->password) {
1680             priv_key = rsa_load_pkcs12(fp, uats->password, &err);
1681             if (err) {
1682                 report_failure("%s\n", err);
1683                 g_free(err);
1684             }
1685         } else {
1686             priv_key = rsa_load_pem_key(fp, &err);
1687             if (err) {
1688                 report_failure("%s\n", err);
1689                 g_free(err);
1690             }
1691         }
1692         fclose(fp);
1693
1694         if (!priv_key) {
1695             report_failure("Can't load private key from %s\n", uats->keyfile);
1696             return;
1697         }
1698
1699         struct rsakey *entry;
1700         guint32 ipaddr;
1701         gcry_sexp_t private_key = rsa_privkey_to_sexp(priv_key, &err);
1702         if (!private_key) {
1703             g_free(err);
1704             report_failure("Can't extract private key parameters for %s", uats->keyfile);
1705             goto end;
1706         }
1707
1708         entry = g_new(struct rsakey, 1);
1709         ws_strtou16(uats->port, NULL, &entry->port);
1710         ipaddr = ipv4tonl(uats->ipaddr);
1711         alloc_address_wmem(NULL, &entry->addr, AT_IPv4, sizeof ipaddr, &ipaddr);
1712         entry->privkey = private_key;
1713
1714
1715         g_hash_table_insert(rsakeys, entry, entry->privkey);
1716
1717 end:
1718         gnutls_x509_privkey_deinit(priv_key);
1719     }
1720 }
1721
1722 static void
1723 rsakeys_free_cb(void *r)
1724 {
1725     struct rsakeys_assoc *h = (struct rsakeys_assoc *)r;
1726
1727     g_free(h->ipaddr);
1728     g_free(h->port);
1729     g_free(h->keyfile);
1730     g_free(h->password);
1731 }
1732
1733 static void*
1734 rsakeys_copy_cb(void *dst_, const void *src_, size_t len _U_)
1735 {
1736     const struct rsakeys_assoc *src = (const struct rsakeys_assoc *)src_;
1737     struct rsakeys_assoc       *dst = (struct rsakeys_assoc *)dst_;
1738
1739     dst->ipaddr    = g_strdup(src->ipaddr);
1740     dst->port      = g_strdup(src->port);
1741     dst->keyfile   = g_strdup(src->keyfile);
1742     dst->password  = g_strdup(src->password);
1743
1744     return dst;
1745 }
1746
1747 static gboolean
1748 rsakeys_uat_fld_ip_chk_cb(void* r _U_, const char* ipaddr, guint len _U_, const void* u1 _U_, const void* u2 _U_, char** err)
1749 {
1750     /* There are no Tibia IPv6 servers, although Tibia 11.0+'s Protocol in theory supports it */
1751     if (ipaddr && g_hostname_is_ip_address(ipaddr) && strchr(ipaddr, '.')) {
1752         *err = NULL;
1753         return TRUE;
1754     }
1755
1756     *err = g_strdup_printf("No IPv4 address given.");
1757     return FALSE;
1758 }
1759
1760 static gboolean
1761 rsakeys_uat_fld_port_chk_cb(void *_record _U_, const char *str, guint len _U_, const void *chk_data _U_, const void *fld_data _U_, char **err)
1762 {
1763     guint16 val;
1764     if (!ws_strtou16(str, NULL, &val)) {
1765         *err = g_strdup("Invalid argument. Expected a decimal between [0-65535]");
1766         return FALSE;
1767     }
1768     *err = NULL;
1769     return TRUE;
1770 }
1771
1772 static gboolean
1773 rsakeys_uat_fld_fileopen_chk_cb(void* r _U_, const char* p, guint len _U_, const void* u1 _U_, const void* u2 _U_, char** err)
1774 {
1775     if (p && *p) {
1776         ws_statb64 st;
1777         if (ws_stat64(p, &st) != 0) {
1778             *err = g_strdup_printf("File '%s' does not exist or access is denied.", p);
1779             return FALSE;
1780         }
1781     } else {
1782         *err = g_strdup("No filename given.");
1783         return FALSE;
1784     }
1785
1786     *err = NULL;
1787     return TRUE;
1788 }
1789
1790 static gboolean
1791 rsakeys_uat_fld_password_chk_cb(void *r, const char *p, guint len _U_, const void *u1 _U_, const void *u2 _U_, char **err)
1792 {
1793     if (p && *p) {
1794         struct rsakeys_assoc *f = (struct rsakeys_assoc *)r;
1795         FILE *fp = ws_fopen(f->keyfile, "rb");
1796         if (fp) {
1797             char *msg = NULL;
1798             gnutls_x509_privkey_t priv_key = rsa_load_pkcs12(fp, p, &msg);
1799             if (!priv_key) {
1800                 fclose(fp);
1801                 *err = g_strdup_printf("Could not load PKCS#12 key file: %s", msg);
1802                 g_free(msg);
1803                 return FALSE;
1804             }
1805             g_free(msg);
1806             gnutls_x509_privkey_deinit(priv_key);
1807             fclose(fp);
1808         } else {
1809             *err = g_strdup_printf("Leave this field blank if the keyfile is not PKCS#12.");
1810             return FALSE;
1811         }
1812     }
1813
1814     *err = NULL;
1815     return TRUE;
1816 }
1817 #endif
1818
1819 static void
1820 xtea_parse_uat(void)
1821 {
1822     g_hash_table_remove_all(xteakeys);
1823
1824     for (guint i = 0; i < nxteakeys; i++) {
1825         guint key_idx = 0;
1826         guint8 *key = (guint8*)g_malloc(XTEA_KEY_LEN);
1827
1828         for (const char *str = xteakeylist_uats[i].key; str[0] && str[1] && key_idx < XTEA_KEY_LEN; str++) {
1829             if (g_ascii_ispunct(*str))
1830                 continue;
1831
1832             key[key_idx++] = (g_ascii_xdigit_value(str[0]) << 4)
1833                            +  g_ascii_xdigit_value(str[1]);
1834             str++;
1835         }
1836
1837         g_hash_table_insert(xteakeys, GUINT_TO_POINTER(xteakeylist_uats[i].framenum), key);
1838     }
1839 }
1840
1841 static void
1842 xteakeys_free_cb(void *r)
1843 {
1844     struct xteakeys_assoc *h = (struct xteakeys_assoc *)r;
1845
1846     g_free(h->key);
1847 }
1848
1849 static void*
1850 xteakeys_copy_cb(void *dst_, const void *src_, size_t len _U_)
1851 {
1852     const struct xteakeys_assoc *src = (const struct xteakeys_assoc *)src_;
1853     struct xteakeys_assoc       *dst = (struct xteakeys_assoc *)dst_;
1854
1855     dst->framenum = src->framenum;
1856     dst->key      = g_strdup(src->key);
1857
1858     return dst;
1859 }
1860
1861 static gboolean
1862 xteakeys_uat_fld_key_chk_cb(void *r _U_, const char *key, guint len, const void *u1 _U_, const void *u2 _U_, char **err)
1863 {
1864     if (len >= XTEA_KEY_LEN*2) {
1865         gsize i = 0;
1866
1867         do {
1868             if (g_ascii_ispunct(*key))
1869                 continue;
1870             if (!g_ascii_isxdigit(*key))
1871                 break;
1872             i++;
1873         } while (*++key);
1874
1875         if (*key == '\0' && i == 2*XTEA_KEY_LEN) {
1876             *err = NULL;
1877             return TRUE;
1878         }
1879     }
1880
1881     *err = g_strdup_printf("XTEA keys are 32 character long hex strings.");
1882     return FALSE;
1883 }
1884
1885
1886 void
1887 proto_register_tibia(void)
1888 {
1889     static hf_register_info hf[] = {
1890         { &hf_tibia_len,
1891             { "Packet length", "tibia.len",
1892                 FT_UINT16, BASE_DEC,
1893                 NULL, 0x0,
1894                 NULL, HFILL }
1895         },
1896         { &hf_tibia_adler32,
1897             { "Adler32 checksum", "tibia.checksum",
1898                 FT_UINT32, BASE_HEX,
1899                 NULL, 0x0,
1900                 NULL, HFILL }
1901         },
1902         { &hf_tibia_adler32_status,
1903             { "Checksum status", "tibia.checksum.status",
1904                 FT_UINT8, BASE_NONE,
1905                 VALS(proto_checksum_vals), 0x0,
1906                 NULL, HFILL }
1907         },
1908         { &hf_tibia_nonce,
1909             { "Game server nonce", "tibia.nonce",
1910                 FT_BYTES, BASE_NONE,
1911                 NULL, 0x0,
1912                 NULL, HFILL }
1913         },
1914         { &hf_tibia_os,
1915             { "Operating system", "tibia.os",
1916                 FT_UINT16, BASE_HEX,
1917                 VALS(operating_systems), 0x0,
1918                 NULL, HFILL }
1919         },
1920         { &hf_tibia_proto_version,
1921             { "Protocol version", "tibia.version",
1922                 FT_UINT16, BASE_DEC,
1923                 NULL, 0x0,
1924                 NULL, HFILL }
1925         },
1926         { &hf_tibia_client_version,
1927             { "Client version", "tibia.client_version",
1928                 FT_UINT32, BASE_DEC,
1929                 NULL, 0x0,
1930                 NULL, HFILL }
1931         },
1932         { &hf_tibia_file_versions,
1933             { "File versions", "tibia.version.files",
1934                 FT_NONE, BASE_NONE, NULL, 0x0,
1935                 NULL, HFILL }
1936         },
1937         { &hf_tibia_file_version_spr,
1938             { "Tibia.spr version", "tibia.version.spr",
1939                 FT_UINT32, BASE_HEX,
1940                 NULL, 0x0,
1941                 NULL, HFILL }
1942         },
1943         { &hf_tibia_file_version_dat,
1944             { "Tibia.dat version", "tibia.version.dat",
1945                 FT_UINT32, BASE_HEX,
1946                 NULL, 0x0,
1947                 NULL, HFILL }
1948         },
1949         { &hf_tibia_file_version_pic,
1950             { "Tibia.pic version", "tibia.version.pic",
1951                 FT_UINT32, BASE_HEX,
1952                 NULL, 0x0,
1953                 NULL, HFILL }
1954         },
1955         { &hf_tibia_content_revision,
1956             { "Content revision", "tibia.version.content",
1957                 FT_UINT16, BASE_HEX,
1958                 NULL, 0x0,
1959                 NULL, HFILL }
1960         },
1961         { &hf_tibia_undecoded_rsa_data,
1962             { "RSA-encrypted login data", "tibia.rsa_data",
1963                 FT_BYTES, BASE_NONE,
1964                 NULL, 0x0,
1965                 NULL, HFILL }
1966         },
1967         { &hf_tibia_undecoded_xtea_data,
1968             { "XTEA-encrypted game data", "tibia.xtea_data",
1969                 FT_BYTES, BASE_NONE,
1970                 NULL, 0x0,
1971                 NULL, HFILL }
1972         },
1973         { &hf_tibia_unknown,
1974             { "Unknown Data", "tibia.unknown",
1975                 FT_BYTES, BASE_NONE,
1976                 NULL, 0x0,
1977                 NULL, HFILL }
1978         },
1979         { &hf_tibia_xtea_key,
1980             { "Symmetric key (XTEA)", "tibia.xtea",
1981                 FT_BYTES, BASE_NONE,
1982                 NULL, 0x0,
1983                 NULL, HFILL }
1984         },
1985         { &hf_tibia_loginflags_gm,
1986             { "Gamemaster", "tibia.login.flags.gm",
1987                 FT_BOOLEAN, 8,
1988                 NULL, 0x1,
1989                 NULL, HFILL }
1990         },
1991         { &hf_tibia_game_preview_state,
1992             { "Game Preview State", "tibia.login.flags.preview",
1993                 FT_BOOLEAN, 8,
1994                 NULL, 0x1,
1995                 NULL, HFILL }
1996         },
1997         { &hf_tibia_char_cond,
1998           {"Character Condition", "tibia.cond",
1999                 FT_UINT32, BASE_HEX,
2000                 NULL, 0,
2001                 NULL, HFILL}
2002         },
2003         { &hf_tibia_char_cond_poisoned,
2004             { "Poisoned", "tibia.cond.poisoned",
2005                 FT_BOOLEAN, 32,
2006                 TFS(&tfs_yes_no), COND_POISONED,
2007                 NULL, HFILL }
2008         },
2009         { &hf_tibia_char_cond_burning,
2010             { "Burning", "tibia.cond.burning",
2011                 FT_BOOLEAN, 32,
2012                 TFS(&tfs_yes_no), COND_BURNING,
2013                 NULL, HFILL }
2014         },
2015         { &hf_tibia_char_cond_electrocuted,
2016             { "Electrocuted", "tibia.cond.electrocuted",
2017                 FT_BOOLEAN, 32,
2018                 TFS(&tfs_yes_no), COND_ELECTROCUTED,
2019                 NULL, HFILL }
2020         },
2021         { &hf_tibia_char_cond_drunk,
2022             { "Drunk", "tibia.cond.drunk",
2023                 FT_BOOLEAN, 32,
2024                 TFS(&tfs_yes_no), COND_DRUNK,
2025                 NULL, HFILL }
2026         },
2027         { &hf_tibia_char_cond_manashield, /* Utamo Vita */
2028             { "Mana Shield", "tibia.cond.manashield",
2029                 FT_BOOLEAN, 32,
2030                 TFS(&tfs_yes_no), COND_MANASHIELD,
2031                 NULL, HFILL }
2032         },
2033         { &hf_tibia_char_cond_paralyzed,
2034             { "Paralyzed", "tibia.cond.paralyzed",
2035                 FT_BOOLEAN, 32,
2036                 TFS(&tfs_yes_no), COND_PARALYZED,
2037                 NULL, HFILL }
2038         },
2039         { &hf_tibia_char_cond_haste,
2040             { "Haste", "tibia.cond.haste",
2041                 FT_BOOLEAN, 32,
2042                 TFS(&tfs_yes_no), COND_HASTE,
2043                 NULL, HFILL }
2044         },
2045         { &hf_tibia_char_cond_battle,
2046             { "Battle lock", "tibia.cond.battle",
2047                 FT_BOOLEAN, 32,
2048                 TFS(&tfs_yes_no), COND_BATTLE,
2049                 NULL, HFILL }
2050         },
2051         { &hf_tibia_char_cond_drowning,
2052             { "Drowning", "tibia.cond.drowning",
2053                 FT_BOOLEAN, 32,
2054                 TFS(&tfs_yes_no), COND_DROWNING,
2055                 NULL, HFILL }
2056         },
2057         { &hf_tibia_char_cond_freezing,
2058             { "Freezing", "tibia.cond.freezing",
2059                 FT_BOOLEAN, 32,
2060                 TFS(&tfs_yes_no), COND_FREEZING,
2061                 NULL, HFILL }
2062         },
2063         { &hf_tibia_char_cond_dazzled,
2064             { "Dazzled", "tibia.cond.dazzled",
2065                 FT_BOOLEAN, 32,
2066                 TFS(&tfs_yes_no), COND_DAZZLED,
2067                 NULL, HFILL }
2068         },
2069         { &hf_tibia_char_cond_cursed,
2070             { "Cursed", "tibia.cond.cursed",
2071                 FT_BOOLEAN, 32,
2072                 TFS(&tfs_yes_no), COND_CURSED,
2073                 NULL, HFILL }
2074         },
2075         { &hf_tibia_char_cond_buff, /* e.g. after casting Utura */
2076             { "Buff", "tibia.cond.buff",
2077                 FT_BOOLEAN, 32,
2078                 TFS(&tfs_yes_no), COND_BUFF,
2079                 NULL, HFILL }
2080         },
2081         { &hf_tibia_char_cond_pzblock, /* Blocked from entering PZ */
2082             { "Protection Zone Block", "tibia.cond.pzblock",
2083                 FT_BOOLEAN, 32,
2084                 TFS(&tfs_yes_no), COND_PZBLOCK,
2085                 NULL, HFILL }
2086         },
2087         { &hf_tibia_char_cond_pz,
2088             { "Protection Zone", "tibia.cond.pz",
2089                 FT_BOOLEAN, 32,
2090                 TFS(&tfs_yes_no), COND_PZ,
2091                 NULL, HFILL }
2092         },
2093         { &hf_tibia_char_cond_bleeding,
2094             { "Bleeding", "tibia.cond.bleeding",
2095                 FT_BOOLEAN, 32,
2096                 TFS(&tfs_yes_no), COND_BLEEDING,
2097                 NULL, HFILL }
2098         },
2099         { &hf_tibia_char_cond_hungry,
2100             { "Hungry", "tibia.cond.hungry",
2101                 FT_BOOLEAN, 32,
2102                 TFS(&tfs_yes_no), COND_HUNGRY,
2103                 NULL, HFILL }
2104         },
2105         { &hf_tibia_acc_name,
2106             { "Account", "tibia.acc",
2107                 FT_UINT_STRING, BASE_NONE,
2108                 NULL, 0x0,
2109                 NULL, HFILL }
2110         },
2111         { &hf_tibia_acc_number,
2112             { "Account", "tibia.acc",
2113                 FT_STRING, BASE_NONE,
2114                 NULL, 0x0,
2115                 NULL, HFILL }
2116         },
2117         { &hf_tibia_session_key,
2118             { "Session key", "tibia.session_key",
2119                 FT_UINT_STRING, BASE_NONE,
2120                 NULL, 0x0,
2121                 NULL, HFILL }
2122         },
2123         { &hf_tibia_char_name,
2124             { "Character name", "tibia.char",
2125                 FT_UINT_STRING, BASE_NONE,
2126                 NULL, 0x0,
2127                 NULL, HFILL }
2128         },
2129         { &hf_tibia_acc_pass,
2130             { "Password", "tibia.pass",
2131                 FT_UINT_STRING, BASE_NONE,
2132                 NULL, 0x0,
2133                 NULL, HFILL }
2134         },
2135         { &hf_tibia_char_name_convo,
2136             { "Character name", "tibia.char",
2137                 FT_STRING, BASE_NONE,
2138                 NULL, 0x0,
2139                 NULL, HFILL }
2140         },
2141         { &hf_tibia_acc_name_convo,
2142             { "Account", "tibia.acc",
2143                 FT_STRING, BASE_NONE,
2144                 NULL, 0x0,
2145                 NULL, HFILL }
2146         },
2147         { &hf_tibia_acc_pass_convo,
2148             { "Password", "tibia.pass",
2149                 FT_STRING, BASE_NONE,
2150                 NULL, 0x0,
2151                 NULL, HFILL }
2152         },
2153         { &hf_tibia_session_key_convo,
2154             { "Session key", "tibia.session_key",
2155                 FT_STRING, BASE_NONE,
2156                 NULL, 0x0,
2157                 NULL, HFILL }
2158         },
2159         { &hf_tibia_client_info,
2160             { "Client information", "tibia.client.info",
2161                 FT_NONE, BASE_NONE,
2162                 NULL, 0x0,
2163                 NULL, HFILL }
2164         },
2165         { &hf_tibia_client_locale,
2166             { "Locale", "tibia.client.locale",
2167                 FT_NONE, BASE_NONE,
2168                 NULL, 0x0,
2169                 NULL, HFILL }
2170         },
2171         { &hf_tibia_client_locale_id,
2172             { "Locale ID", "tibia.client.locale.id",
2173                 FT_UINT8, BASE_DEC,
2174                 NULL, 0x0,
2175                 NULL, HFILL }
2176         },
2177         { &hf_tibia_client_locale_name,
2178             { "Locale", "tibia.client.locale.name",
2179                 FT_STRING, BASE_NONE,
2180                 NULL, 0x0,
2181                 NULL, HFILL }
2182         },
2183         { &hf_tibia_client_ram,
2184             { "Total RAM", "tibia.client.ram",
2185                 FT_UINT8, BASE_DEC,
2186                 NULL, 0x0,
2187                 NULL, HFILL }
2188         },
2189         { &hf_tibia_client_cpu,
2190             { "CPU", "tibia.client.cpu",
2191                 FT_NONE, BASE_NONE,
2192                 NULL, 0x0,
2193                 NULL, HFILL }
2194         },
2195         { &hf_tibia_client_cpu_name,
2196             { "CPU", "tibia.client.cpu.name",
2197                 FT_STRINGZ, BASE_NONE,
2198                 NULL, 0x0,
2199                 NULL, HFILL }
2200         },
2201         { &hf_tibia_client_clock,
2202             { "CPU clock", "tibia.client.cpu.clock",
2203                 FT_UINT8, BASE_DEC,
2204                 NULL, 0x0,
2205                 NULL, HFILL }
2206         },
2207         { &hf_tibia_client_clock2,
2208             { "CPU clock2", "tibia.client.cpu.clock2",
2209                 FT_UINT8, BASE_DEC,
2210                 NULL, 0x0,
2211                 NULL, HFILL }
2212         },
2213         { &hf_tibia_client_gpu,
2214             { "GPU", "tibia.client.gpu",
2215                 FT_STRINGZ, BASE_NONE,
2216                 NULL, 0x0,
2217                 NULL, HFILL }
2218         },
2219         { &hf_tibia_client_vram,
2220             { "Video RAM", "tibia.client.vram",
2221                 FT_UINT8, BASE_DEC|BASE_UNIT_STRING,
2222                 &mb_unit, 0x0,
2223                 NULL, HFILL }
2224         },
2225         { &hf_tibia_client_resolution,
2226             { "Screen resolution", "tibia.client.resolution",
2227                 FT_NONE, BASE_NONE,
2228                 NULL, 0x0,
2229                 NULL, HFILL }
2230         },
2231         { &hf_tibia_client_resolution_x,
2232             { "Horizontal resolution", "tibia.client.resolution.x",
2233                 FT_UINT16, BASE_DEC,
2234                 NULL, 0x0,
2235                 NULL, HFILL }
2236         },
2237         { &hf_tibia_client_resolution_y,
2238             { "Vertical resolution", "tibia.client.resolution.y",
2239                 FT_UINT16, BASE_DEC,
2240                 NULL, 0x0,
2241                 NULL, HFILL }
2242         },
2243         { &hf_tibia_client_resolution_hz,
2244             { "Refresh rate", "tibia.client.resolution.hz",
2245                 FT_UINT8, BASE_DEC,
2246                 NULL, 0x0,
2247                 NULL, HFILL }
2248         },
2249         { &hf_tibia_payload_len,
2250             { "Payload length", "tibia.payload.len",
2251                 FT_UINT16, BASE_DEC,
2252                 NULL, 0x0,
2253                 NULL, HFILL }
2254         },
2255         { &hf_tibia_loginserv_command,
2256             { "Command", "tibia.cmd",
2257                 FT_UINT8, BASE_HEX,
2258                 VALS(from_loginserv_packet_types), 0x0,
2259                 NULL, HFILL }
2260         },
2261         { &hf_tibia_gameserv_command,
2262             { "Command", "tibia.cmd",
2263                 FT_UINT8, BASE_HEX|BASE_EXT_STRING,
2264                 &from_gameserv_packet_types_ext, 0x0,
2265                 NULL, HFILL }
2266         },
2267         { &hf_tibia_client_command,
2268             { "Command", "tibia.cmd",
2269                 FT_UINT8, BASE_HEX|BASE_EXT_STRING,
2270                 &from_client_packet_types_ext, 0x0,
2271                 NULL, HFILL }
2272         },
2273         { &hf_tibia_motd,
2274             { "Message of the day", "tibia.motd",
2275                 FT_UINT_STRING, BASE_NONE, NULL, 0x0,
2276                 NULL, HFILL }
2277         },
2278         { &hf_tibia_dlg_error,
2279             { "Error message", "tibia.login.err",
2280                 FT_UINT_STRING, BASE_NONE, NULL, 0x0,
2281                 NULL, HFILL }
2282         },
2283         { &hf_tibia_dlg_info,
2284             { "Info message", "tibia.login.info",
2285                 FT_UINT_STRING, BASE_NONE, NULL, 0x0,
2286                 NULL, HFILL }
2287         },
2288         { &hf_tibia_charlist,
2289             { "Character list", "tibia.charlist",
2290                 FT_NONE, BASE_NONE, NULL, 0x0,
2291                 NULL, HFILL }
2292         },
2293         { &hf_tibia_charlist_length,
2294             { "Character count", "tibia.charlist.count",
2295                 FT_UINT8, BASE_DEC,
2296                 NULL, 0x0,
2297                 NULL, HFILL }
2298         },
2299         { &hf_tibia_charlist_entry_name,
2300             { "Character name", "tibia.charlist.name",
2301                 FT_UINT_STRING, BASE_NONE,
2302                 NULL, 0x0,
2303                 NULL, HFILL }
2304         },
2305         { &hf_tibia_charlist_entry_world,
2306             { "World", "tibia.charlist.world",
2307                 FT_UINT_STRING, BASE_NONE,
2308                 NULL, 0x0,
2309                 NULL, HFILL }
2310         },
2311         { &hf_tibia_charlist_entry_ip,
2312             { "IP", "tibia.charlist.ip",
2313                 FT_IPv4, BASE_NONE,
2314                 NULL, 0x0,
2315                 NULL, HFILL }
2316         },
2317         { &hf_tibia_charlist_entry_port,
2318             { "Port", "tibia.charlist.port",
2319                 FT_UINT16, BASE_DEC,
2320                 NULL, 0x0,
2321                 NULL, HFILL }
2322         },
2323         { &hf_tibia_worldlist,
2324             { "World list", "tibia.worldlist",
2325                 FT_NONE, BASE_NONE, NULL, 0x0,
2326                 NULL, HFILL }
2327         },
2328         { &hf_tibia_worldlist_entry_name,
2329             { "World", "tibia.worldlist.name",
2330                 FT_UINT_STRING, BASE_NONE,
2331                 NULL, 0x0,
2332                 NULL, HFILL }
2333         },
2334         { &hf_tibia_worldlist_length,
2335             { "World count", "tibia.worldlist.count",
2336                 FT_UINT16, BASE_DEC,
2337                 NULL, 0x0,
2338                 NULL, HFILL }
2339         },
2340         { &hf_tibia_worldlist_entry_id,
2341             { "World ID", "tibia.worldlist.id",
2342                 FT_UINT8, BASE_DEC,
2343                 NULL, 0x0,
2344                 NULL, HFILL }
2345         },
2346         { &hf_tibia_worldlist_entry_ip,
2347             { "IP", "tibia.worldlist.ip",
2348                 FT_UINT_STRING, BASE_NONE,
2349                 NULL, 0x0,
2350                 NULL, HFILL }
2351         },
2352         { &hf_tibia_worldlist_entry_port,
2353             { "Port", "tibia.worldlist.port",
2354                 FT_UINT16, BASE_DEC,
2355                 NULL, 0x0,
2356                 NULL, HFILL }
2357         },
2358         { &hf_tibia_worldlist_entry_preview,
2359             { "Preview State", "tibia.worldlist.preview",
2360                 FT_BOOLEAN, 8,
2361                 NULL, 0x1,
2362                 NULL, HFILL }
2363         },
2364         { &hf_tibia_pacc_days,
2365             { "Premium days left", "tibia.pacc",
2366                 FT_UINT16, BASE_DEC,
2367                 NULL, 0x0,
2368                 NULL, HFILL }
2369         },
2370         { &hf_tibia_channel_id,
2371             { "Channel id", "tibia.channel.id",
2372                 FT_UINT16, BASE_HEX,
2373                 NULL, 0x0,
2374                 NULL, HFILL }
2375         },
2376         { &hf_tibia_channel_name,
2377             { "Channel name", "tibia.channel",
2378                 FT_UINT_STRING, BASE_NONE,
2379                 NULL, 0x0,
2380                 NULL, HFILL }
2381         },
2382         { &hf_tibia_speech_type,
2383             { "Type", "tibia.speechtype",
2384                 FT_UINT8, BASE_HEX,
2385                 VALS(speech_types), 0x0,
2386                 NULL, HFILL }
2387         },
2388         { &hf_tibia_chat_msg,
2389             { "Message", "tibia.msg",
2390                 FT_UINT_STRING, BASE_NONE, NULL, 0x0,
2391                 NULL, HFILL }
2392         },
2393         { &hf_tibia_coords_x,
2394             { "X-Coordinate", "tibia.coord.x",
2395                 FT_UINT16, BASE_DEC, NULL, 0x0,
2396                 NULL, HFILL }
2397         },
2398         { &hf_tibia_coords_y,
2399             { "Y-Coordinate", "tibia.coords.y",
2400                 FT_UINT16, BASE_DEC, NULL, 0x0,
2401                 NULL, HFILL }
2402         },
2403         { &hf_tibia_coords_z,
2404             { "Z-Coordinate", "tibia.coords.z",
2405                 FT_UINT8, BASE_DEC, NULL, 0x0,
2406                 NULL, HFILL }
2407         },
2408         { &hf_tibia_coords,
2409             { "Coordinates", "tibia.coords",
2410                 FT_STRING, BASE_NONE,
2411                 NULL, 0x0,
2412                 NULL, HFILL }
2413         },
2414         { &hf_tibia_stackpos,
2415             { "Stack position", "tibia.coords.stackpos",
2416                 FT_UINT8, BASE_DEC,
2417                 NULL, 0x0,
2418                 NULL, HFILL }
2419         },
2420 #if 0
2421         { &hf_tibia_item,
2422             { "Item ID", "tibia.item",
2423                 FT_UINT16, BASE_DEC,
2424                 NULL, 0x0,
2425                 NULL, HFILL }
2426         },
2427 #endif
2428         { &hf_tibia_container,
2429             { "Container index", "tibia.container",
2430                 FT_UINT8, BASE_DEC,
2431                 NULL, 0x0,
2432                 NULL, HFILL }
2433         },
2434         { &hf_tibia_container_icon,
2435             { "Container icon", "tibia.container.icon",
2436                 FT_UINT8, BASE_DEC,
2437                 NULL, 0x0,
2438                 NULL, HFILL }
2439         },
2440         { &hf_tibia_container_slot,
2441             { "Container slot", "tibia.container.slot",
2442                 FT_UINT8, BASE_DEC,
2443                 NULL, 0x0,
2444                 NULL, HFILL }
2445         },
2446         { &hf_tibia_container_slots,
2447             { "Container slots", "tibia.container.slots",
2448                 FT_UINT8, BASE_DEC,
2449                 NULL, 0x0,
2450                 NULL, HFILL }
2451         },
2452         { &hf_tibia_inventory,
2453             { "Inventory slot", "tibia.inventory",
2454                 FT_UINT16, BASE_DEC,
2455                 NULL, 0x0,
2456                 NULL, HFILL }
2457         },
2458         { &hf_tibia_vip,
2459             { "VIP GUID", "tibia.vip",
2460                 FT_UINT32, BASE_HEX, NULL, 0x0,
2461                 NULL, HFILL }
2462         },
2463         { &hf_tibia_vip_online,
2464             { "Online", "tibia.vip.online",
2465                 FT_BOOLEAN, 8,
2466                 NULL, 0x1,
2467                 NULL, HFILL }
2468         },
2469         { &hf_tibia_player,
2470             { "Player name", "tibia.player",
2471                 FT_UINT_STRING, BASE_NONE,
2472                 NULL, 0x0,
2473                 NULL, HFILL }
2474         },
2475         { &hf_tibia_creature,
2476             { "Creature", "tibia.creature",
2477                 FT_UINT32, BASE_HEX,
2478                 NULL, 0x0,
2479                 NULL, HFILL }
2480         },
2481         { &hf_tibia_creature_health,
2482             { "Creature", "tibia.creature.health",
2483                 FT_UINT8, BASE_DEC|BASE_UNIT_STRING,
2484                 &units_percent, 0x0,
2485                 NULL, HFILL }
2486         },
2487         { &hf_tibia_window,
2488             { "Window", "tibia.window",
2489                 FT_UINT32, BASE_HEX,
2490                 NULL, 0x0,
2491                 NULL, HFILL }
2492         },
2493         { &hf_tibia_window_icon,
2494             { "Window Icon", "tibia.window.icon",
2495                 FT_UINT8, BASE_HEX,
2496                 NULL, 0x0,
2497                 NULL, HFILL }
2498         },
2499         { &hf_tibia_window_textlen,
2500             { "Window Text Length", "tibia.window.text.len",
2501                 FT_UINT8, BASE_DEC,
2502                 NULL, 0x0,
2503                 NULL, HFILL }
2504         },
2505         { &hf_tibia_window_text,
2506             { "Window Text", "tibia.window.text",
2507                 FT_UINT_STRING, BASE_NONE,
2508                 NULL, 0x0,
2509                 NULL, HFILL }
2510         },
2511         { &hf_tibia_squarecolor,
2512             { "Square Color", "tibia.creature.square",
2513                 FT_UINT8, BASE_HEX,
2514                 NULL, 0x0,
2515                 NULL, HFILL }
2516         },
2517         { &hf_tibia_light_color,
2518             { "Light Color", "tibia.light.color",
2519                 FT_UINT8, BASE_HEX,
2520                 NULL, 0x0,
2521                 NULL, HFILL }
2522         },
2523         { &hf_tibia_light_level,
2524             { "Light Level", "tibia.light.level",
2525                 FT_UINT8, BASE_DEC,
2526                 NULL, 0x0,
2527                 NULL, HFILL }
2528         },
2529         { &hf_tibia_magic_effect_id,
2530             { "Magic Effect", "tibia.magic_effect",
2531                 FT_UINT8, BASE_HEX,
2532                 NULL, 0x0,
2533                 NULL, HFILL }
2534         },
2535         { &hf_tibia_animated_text_color,
2536             { "Text Color", "tibia.animated_text.color",
2537                 FT_UINT8, BASE_HEX,
2538                 NULL, 0x0,
2539                 NULL, HFILL }
2540         },
2541         { &hf_tibia_animated_text,
2542             { "Text", "tibia.animated_text",
2543                 FT_UINT16, BASE_HEX,
2544                 NULL, 0x0,
2545                 NULL, HFILL }
2546         },
2547         { &hf_tibia_textmsg_class,
2548             { "Text Message Class", "tibia.textmsg.class",
2549                 FT_UINT8, BASE_HEX,
2550                 NULL, 0x0,
2551                 NULL, HFILL }
2552         },
2553         { &hf_tibia_textmsg,
2554             { "Text", "tibia.textmsg",
2555                 FT_UINT_STRING, BASE_NONE,
2556                 NULL, 0x0,
2557                 NULL, HFILL }
2558         },
2559         { &hf_tibia_projectile,
2560             { "Projectile", "tibia.projectile",
2561                 FT_UINT32, BASE_HEX,
2562                 NULL, 0x0,
2563                 NULL, HFILL }
2564         },
2565         { &hf_tibia_walk_dir,
2566             { "Walk Direction", "tibia.walk_dir",
2567                 FT_UINT8, BASE_HEX,
2568                 NULL, 0x0,
2569                 NULL, HFILL }
2570         },
2571     };
2572
2573     /* Setup protocol subtree array */
2574     static gint *ett[] = {
2575         &ett_tibia,
2576         &ett_command,
2577         &ett_file_versions,
2578         &ett_client_info,
2579         &ett_locale,
2580         &ett_cpu,
2581         &ett_resolution,
2582         &ett_charlist,
2583         &ett_char,
2584         &ett_worldlist,
2585         &ett_world,
2586         &ett_coords,
2587         &ett_char_cond,
2588     };
2589
2590     static ei_register_info ei[] = {
2591         { &ei_xtea_len_toobig,
2592             { "tibia.error.xtea.length.toobig", PI_DECRYPTION, PI_ERROR,
2593                 "XTEA-encrypted length exceeds packet", EXPFILL }
2594         },
2595         { &ei_adler32_checksum_bad, { "tibia.error.checksum_bad", PI_CHECKSUM, PI_ERROR,
2596                 "Bad checksum", EXPFILL }
2597         },
2598         { &ei_rsa_plaintext_no_leading_zero,
2599             { "tibia.error.rsa", PI_DECRYPTION, PI_ERROR,
2600                 "First byte after RSA decryption must be zero", EXPFILL }
2601         },
2602         { &ei_rsa_ciphertext_too_short,
2603             { "tibia.error.rsa.length.tooshort", PI_DECRYPTION, PI_ERROR,
2604                 "RSA-encrypted data is at least 128 byte long", EXPFILL }
2605         },
2606         { &ei_rsa_decrypt_failed,
2607             { "tibia.error.rsa.failed", PI_DECRYPTION, PI_ERROR,
2608                 "Decrypting RSA block failed", EXPFILL }
2609         },
2610     };
2611
2612     proto_tibia = proto_register_protocol (
2613             "Tibia Protocol", /* name */
2614             "Tibia",          /* short name */
2615             "tibia"           /* abbrev */
2616             );
2617     proto_register_field_array(proto_tibia, hf, array_length(hf));
2618     proto_register_subtree_array(ett, array_length(ett));
2619
2620     expert_module_t *expert_tibia = expert_register_protocol(proto_tibia);
2621     expert_register_field_array (expert_tibia, ei, array_length (ei));
2622
2623     module_t *tibia_module = prefs_register_protocol(proto_tibia, proto_reg_handoff_tibia);
2624
2625     prefs_register_bool_preference(tibia_module, "try_otserv_key", "Try OTServ's RSA key",
2626         "Try the default RSA key in use by nearly all Open Tibia servers", &try_otserv_key);
2627
2628     prefs_register_bool_preference(tibia_module, "show_char_name", "Show character name for each packet",
2629         "Shows active character for every packet", &show_char_name);
2630     prefs_register_bool_preference(tibia_module, "show_acc_info", "Show account info for each packet",
2631         "Shows account name/password or session key for every packet", &show_acc_info);
2632     prefs_register_bool_preference(tibia_module, "show_xtea_key", "Show symmetric key used for each packet",
2633         "Shows which XTEA key was applied for a packet", &show_xtea_key);
2634     prefs_register_bool_preference(tibia_module, "dissect_game_commands", "Attempt dissection of game packet commands",
2635         "Only decrypt packets and dissect login packets. Pass game commands to the data dissector", &dissect_game_commands);
2636     prefs_register_bool_preference(tibia_module, "reassemble_tcp_segments",
2637                                    "Reassemble Tibia packets spanning multiple TCP segments",
2638                                    "Whether the Tibia dissector should reassemble packets spanning multiple TCP segments."
2639                                    " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
2640                                    &reassemble_tcp_segments);
2641
2642
2643 #ifdef HAVE_LIBGNUTLS
2644     static uat_field_t rsakeylist_uats_flds[] = {
2645         UAT_FLD_CSTRING_OTHER(rsakeylist_uats, ipaddr, "IP address", rsakeys_uat_fld_ip_chk_cb, "IPv4 address"),
2646         UAT_FLD_CSTRING_OTHER(rsakeylist_uats, port, "Port", rsakeys_uat_fld_port_chk_cb, "Port Number"),
2647         UAT_FLD_FILENAME_OTHER(rsakeylist_uats, keyfile, "Key File", rsakeys_uat_fld_fileopen_chk_cb, "Private keyfile."),
2648         UAT_FLD_CSTRING_OTHER(rsakeylist_uats, password,"Password", rsakeys_uat_fld_password_chk_cb, "Password (for keyfile)"),
2649         UAT_END_FIELDS
2650     };
2651
2652     rsakeys_uat = uat_new("RSA Keys",
2653             sizeof(struct rsakeys_assoc),
2654             "tibia_rsa_keys",        /* filename */
2655             TRUE,                    /* from_profile */
2656             &rsakeylist_uats,        /* data_ptr */
2657             &nrsakeys,               /* numitems_ptr */
2658             UAT_AFFECTS_DISSECTION,
2659             NULL,
2660             rsakeys_copy_cb,
2661             NULL,
2662             rsakeys_free_cb,
2663             rsa_parse_uat,
2664             NULL,
2665             rsakeylist_uats_flds);
2666     prefs_register_uat_preference(tibia_module, "rsakey_table",
2667             "RSA keys list",
2668             "A table of RSA keys for decrypting protocols newer than 7.61",
2669             rsakeys_uat
2670     );
2671
2672     rsakeys = g_hash_table_new_full(rsakey_hash, rsakey_equal, rsakey_free, NULL);
2673 #endif
2674
2675     static uat_field_t xteakeylist_uats_flds[] = {
2676         UAT_FLD_DEC(xteakeylist_uats, framenum, "Frame Number", "XTEA key"),
2677         UAT_FLD_CSTRING_OTHER(xteakeylist_uats, key, "XTEA Key", xteakeys_uat_fld_key_chk_cb, "Symmetric (XTEA) key"),
2678         UAT_END_FIELDS
2679     };
2680
2681     xteakeys_uat = uat_new("XTEA Keys",
2682             sizeof(struct xteakeys_assoc),
2683             "tibia_xtea_keys",       /* filename */
2684             TRUE,                    /* from_profile */
2685             &xteakeylist_uats,       /* data_ptr */
2686             &nxteakeys,              /* numitems_ptr */
2687             UAT_AFFECTS_DISSECTION,
2688             NULL,
2689             xteakeys_copy_cb,
2690             NULL,
2691             xteakeys_free_cb,
2692             xtea_parse_uat,
2693             NULL,
2694             xteakeylist_uats_flds);
2695     prefs_register_uat_preference(tibia_module, "xteakey_table",
2696             "XTEA keys list",
2697             "A table of XTEA keys for decrypting protocols newer than 7.61",
2698             xteakeys_uat
2699     );
2700
2701     xteakeys = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, g_free);
2702
2703     /* TODO best way to store this in source? */
2704     const char sexp[] =
2705         "(private-key (rsa"
2706         "(n #9b646903b45b07ac956568d87353bd7165139dd7940703b03e6dd079399661b4a837aa60561d7ccb9452fa0080594909882ab5bca58a1a1b35f8b1059b72b1212611c6152ad3dbb3cfbee7adc142a75d3d75971509c321c5c24a5bd51fd460f01b4e15beb0de1930528a5d3f15c1e3cbf5c401d6777e10acaab33dbe8d5b7ff5#)"
2707         "(e #010001#)"
2708         "(d #428bd3b5346daf71a761106f71a43102f8c857d6549c54660bb6378b52b0261399de8ce648bac410e2ea4e0a1ced1fac2756331220ca6db7ad7b5d440b7828865856e7aa6d8f45837feee9b4a3a0aa21322a1e2ab75b1825e786cf81a28a8a09a1e28519db64ff9baf311e850c2bfa1fb7b08a056cc337f7df443761aefe8d81#)"
2709         "(p #91b37307abe12c05a1b78754746cda444177a784b035cbb96c945affdc022d21da4bd25a4eae259638153e9d73c97c89092096a459e5d16bcadd07fa9d504885#)"
2710         "(q #0111071b206bafb9c7a2287d7c8d17a42e32abee88dfe9520692b5439d9675817ff4f8c94a4abcd4b5f88e220f3a8658e39247a46c6983d85618fd891001a0acb1#)"
2711         "(u #6b21cd5e373fe462a22061b44a41fd01738a3892e0bd8728dbb5b5d86e7675235a469fea3266412fe9a659f486144c1e593d56eb3f6cfc7b2edb83ba8e95403a#)"
2712         "))";
2713
2714     gcry_error_t err = gcry_sexp_new(&otserv_key, sexp, 0, 1);
2715     if (err)
2716         report_failure("Loading OTServ RSA key failed: %s/%s\n", gcry_strerror(err), gcry_strsource(err));
2717 }
2718
2719 static guint
2720 get_dissect_tibia_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset, void *data _U_)
2721 {
2722     return tvb_get_letohs(tvb, offset) + sizeof(guint16);
2723 }
2724
2725 static int
2726 dissect_tibia_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
2727 {
2728     static guint32 packet_num, fragment_num;
2729
2730     if (!packet_num) packet_num = pinfo->num;
2731     if (packet_num != pinfo->num) {
2732         fragment_num = 0;
2733         packet_num = pinfo->num;
2734     }
2735
2736     fragment_num++;
2737
2738
2739     tcp_dissect_pdus(tvb, pinfo, tree, reassemble_tcp_segments, 2,
2740                get_dissect_tibia_len, dissect_tibia, GUINT_TO_POINTER(fragment_num));
2741     return tvb_reported_length(tvb);
2742 }
2743
2744 void
2745 proto_reg_handoff_tibia(void)
2746 {
2747     dissector_handle_t tibia_handle = create_dissector_handle(dissect_tibia_tcp, proto_tibia);
2748
2749     dissector_add_uint_range_with_preference("tcp.port", TIBIA_DEFAULT_TCP_PORT_RANGE, tibia_handle);
2750 }
2751
2752
2753 /*
2754  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
2755  *
2756  * Local variables:
2757  * c-basic-offset: 4
2758  * tab-width: 8
2759  * indent-tabs-mode: nil
2760  * End:
2761  *
2762  * vi: set shiftwidth=4 tabstop=8 expandtab:
2763  * :indentSize=4:tabSize=8:noTabs=true:
2764  */