Add a inflateEnd() call to free up the stream in the re-init block.
[obnox/wireshark/wip.git] / epan / dissectors / packet-quake2.c
1 /* packet-quake2.c
2  * Routines for Quake II packet dissection
3  *
4  * Uwe Girlich <uwe@planetquake.com>
5  *      http://www.idsoftware.com/q1source/q1source.zip
6  *      http://www.planetquake.com/demospecs/dm2
7  *      http://www.dgs.monash.edu.au/~timf/bottim/
8  *      http://www.opt-sci.Arizona.EDU/Pandora/default.asp
9  *
10  * $Id$
11  *
12  * Wireshark - Network traffic analyzer
13  * By Gerald Combs <gerald@wireshark.org>
14  * Copyright 1998 Gerald Combs
15  *
16  * Copied from packet-quakeworld.c
17  *
18  * This program is free software; you can redistribute it and/or
19  * modify it under the terms of the GNU General Public License
20  * as published by the Free Software Foundation; either version 2
21  * of the License, or (at your option) any later version.
22  *
23  * This program is distributed in the hope that it will be useful,
24  * but WITHOUT ANY WARRANTY; without even the implied warranty of
25  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
26  * GNU General Public License for more details.
27  *
28  * You should have received a copy of the GNU General Public License
29  * along with this program; if not, write to the Free Software
30  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
31  */
32
33 #ifdef HAVE_CONFIG_H
34 # include "config.h"
35 #endif
36
37 #include <glib.h>
38 #include <epan/packet.h>
39 #include <epan/prefs.h>
40
41 static int proto_quake2 = -1;
42
43 static int hf_quake2_s2c = -1;
44 static int hf_quake2_c2s = -1;
45 static int hf_quake2_connectionless = -1;
46 static int hf_quake2_game = -1;
47 static int hf_quake2_connectionless_marker = -1;
48 static int hf_quake2_connectionless_text = -1;
49 static int hf_quake2_game_seq1 = -1;
50 static int hf_quake2_game_rel1 = -1;
51 static int hf_quake2_game_seq2 = -1;
52 static int hf_quake2_game_rel2 = -1;
53 static int hf_quake2_game_qport = -1;
54 static int hf_quake2_game_client_command = -1;
55 static int hf_quake2_game_server_command = -1;
56 static int hf_quake2_game_client_command_move = -1;
57 static int hf_quake2_game_client_command_move_chksum = -1;
58 static int hf_quake2_game_client_command_move_lframe = -1;
59 static int hf_quake2_game_client_command_move_bitfield_angles1 = -1;
60 static int hf_quake2_game_client_command_move_bitfield_angles2 = -1;
61 static int hf_quake2_game_client_command_move_bitfield_angles3 = -1;
62 static int hf_quake2_game_client_command_move_bitfield_movement_fwd = -1;
63 static int hf_quake2_game_client_command_move_bitfield_movement_side = -1;
64 static int hf_quake2_game_client_command_move_bitfield_movement_up = -1;
65 static int hf_quake2_game_client_command_move_bitfield_buttons = -1;
66 static int hf_quake2_game_client_command_move_bitfield_impulse = -1;
67 static int hf_quake2_game_client_command_move_msec = -1;
68 static int hf_quake2_game_client_command_move_lightlevel = -1;
69
70 static gint ett_quake2 = -1;
71 static gint ett_quake2_connectionless = -1;
72 static gint ett_quake2_game = -1;
73 static gint ett_quake2_game_seq1 = -1;
74 static gint ett_quake2_game_seq2 = -1;
75 static gint ett_quake2_game_clc = -1;
76 static gint ett_quake2_game_svc = -1;
77 static gint ett_quake2_game_clc_cmd = -1;
78 static gint ett_quake2_game_svc_cmd = -1;
79 static gint ett_quake2_game_clc_cmd_move_bitfield = -1;
80 static gint ett_quake2_game_clc_cmd_move_moves = -1;
81
82
83 static dissector_handle_t data_handle;
84
85 #define PORT_MASTER 27910
86 static unsigned int gbl_quake2ServerPort=PORT_MASTER;
87
88
89 static void
90 dissect_quake2_ConnectionlessPacket(tvbuff_t *tvb, packet_info *pinfo _U_,
91         proto_tree *tree, int direction _U_)
92 {
93         proto_tree      *cl_tree = NULL;
94         proto_item      *cl_item = NULL;
95         guint8          *text;
96         int             len;
97         int             offset;
98
99         guint32 marker;
100
101         marker = tvb_get_ntohl(tvb, 0);
102         if (tree) {
103                 cl_item = proto_tree_add_text(tree, tvb,
104                                 0, -1, "Connectionless");
105                 if (cl_item)
106                         cl_tree = proto_item_add_subtree(
107                                 cl_item, ett_quake2_connectionless);
108         }
109
110         if (cl_tree) {
111                 proto_tree_add_uint(cl_tree, hf_quake2_connectionless_marker,
112                                 tvb, 0, 4, marker);
113         }
114
115         /* all the rest of the packet is just text */
116         offset = 4;
117
118         len = tvb_length_remaining(tvb, offset);
119         if (cl_tree) {
120                 text = tvb_get_ephemeral_string(tvb, offset, len);
121                 proto_tree_add_string(cl_tree, hf_quake2_connectionless_text,
122                         tvb, offset, len, text);
123         }
124         offset += len;
125
126         /* we should analyse the result 'text' a bit further */
127         /* for this we need the direction parameter */
128 }
129
130 static const value_string hf_quake2_game_client_command_move_vals[] = {
131         { 0x00,         "-"   },
132         { 0x01,         "set" },
133         { 0, NULL }
134 };
135
136 static int
137 dissect_quake2_client_commands_move(tvbuff_t *tvb, packet_info *pinfo _U_,
138         proto_tree *tree)
139 {
140         #define MOVES 3         /* 3 updates per command */
141
142         /* taken from qcommon.h */
143         #define CM_ANGLE1   (1<<0)
144         #define CM_ANGLE2   (1<<1)
145         #define CM_ANGLE3   (1<<2)
146         #define CM_FORWARD  (1<<3)
147         #define CM_SIDE     (1<<4)
148         #define CM_UP       (1<<5)
149         #define CM_BUTTONS  (1<<6)
150         #define CM_IMPULSE  (1<<7)
151         /* qshared.h */
152         #define BUTTON_ATTACK   1
153         #define BUTTON_USE              2
154         #define BUTTON_ANY              128
155
156         guint8  chksum;
157         guint32 lastframe;
158         int i, offset = 0;
159         enum { OFFSET, VALUE, SIZE };
160         struct movement {
161                 guint8 bits[SIZE];
162                 guint16 angles[3][SIZE];
163                 gint16 movement[3][SIZE];
164                 guint8 buttons[SIZE];
165                 guint8 lightlevel[SIZE];
166                 guint8 msec[SIZE];
167                 guint8 impulse[SIZE];
168         } move[MOVES+1];
169
170         chksum = tvb_get_guint8(tvb, offset);
171         offset++;
172         lastframe = tvb_get_letohl(tvb, offset);
173         offset += 4;
174
175         for (i=0; i < MOVES; i++) {
176                 move[i].bits[VALUE] = tvb_get_guint8(tvb, offset);
177                 move[i].bits[OFFSET] = offset;
178                 offset++;
179                 if (move[i].bits[VALUE] & CM_ANGLE1) {
180                         move[i].angles[0][VALUE] = tvb_get_letohs(tvb, offset);
181                         move[i].angles[0][OFFSET] = offset;
182                         offset += 2;
183                 }
184                 if (move[i].bits[VALUE] & CM_ANGLE2) {
185                         move[i].angles[1][VALUE] = tvb_get_letohs(tvb, offset);
186                         move[i].angles[1][OFFSET] = offset;
187                         offset += 2;
188                 }
189                 if (move[i].bits[VALUE] & CM_ANGLE3) {
190                         move[i].angles[2][VALUE] = tvb_get_letohs(tvb, offset);
191                         move[i].angles[2][OFFSET] = offset;
192                         offset += 2;
193                 }
194                 if (move[i].bits[VALUE] & CM_FORWARD) {
195                         move[i].movement[0][VALUE] = tvb_get_letohs(tvb, offset);
196                         move[i].movement[0][OFFSET] = offset;
197                         offset += 2;
198                 }
199                 if (move[i].bits[VALUE] & CM_SIDE) {
200                         move[i].movement[1][VALUE] = tvb_get_letohs(tvb, offset);
201                         move[i].movement[1][OFFSET] = offset;
202                         offset += 2;
203                 }
204                 if (move[i].bits[VALUE] & CM_UP) {
205                         move[i].movement[2][VALUE] = tvb_get_letohs(tvb, offset);
206                         move[i].movement[2][OFFSET] = offset;
207                         offset += 2;
208                 }
209                 if (move[i].bits[VALUE] & CM_BUTTONS) {
210                         move[i].buttons[VALUE] = tvb_get_guint8(tvb, offset);
211                         move[i].buttons[OFFSET] = offset;
212                         offset++;
213                 }
214                 if (move[i].bits[VALUE] & CM_IMPULSE) {
215                         move[i].impulse[VALUE] = tvb_get_guint8(tvb, offset);
216                         move[i].impulse[OFFSET] = offset;
217                         offset++;
218                 }
219
220                 move[i].msec[VALUE] = tvb_get_guint8(tvb, offset);
221                 move[i].msec[OFFSET] = offset;
222                 offset++;
223                 move[i].lightlevel[VALUE] = tvb_get_guint8(tvb, offset);
224                 move[i].lightlevel[OFFSET] = offset;
225                 offset++;
226         }
227
228         if (!tree)
229                 return offset;
230
231         proto_tree_add_uint(tree, hf_quake2_game_client_command_move_chksum, tvb,
232                 0, 1, chksum);
233         proto_tree_add_uint(tree, hf_quake2_game_client_command_move_lframe, tvb,
234                 1, 4, lastframe);
235
236         move[MOVES].bits[OFFSET] = offset;
237         for (i=0; i < MOVES; i++) {
238                 proto_item *move_item, *movebits_item, *bit_item;
239                 proto_item *sub_tree, *field_tree;
240                 #define SHORT2ANGLE(x) ((float)x/65536.0*360.0)
241
242                 move_item = proto_tree_add_text(tree,
243                                 tvb,
244                                 move[i].bits[OFFSET],
245                                 move[i+1].bits[OFFSET]-move[i].bits[OFFSET],
246                                 "Move %u", i+1);
247                 sub_tree = proto_item_add_subtree(move_item,
248                                 ett_quake2_game_clc_cmd_move_moves);
249
250                 movebits_item =
251                         proto_tree_add_uint(sub_tree, hf_quake2_game_client_command_move,
252                                         tvb,
253                                         move[i].bits[OFFSET],
254                                         1,
255                                         move[i].bits[VALUE]);
256
257                 proto_tree_add_uint(sub_tree,
258                                 hf_quake2_game_client_command_move_msec,
259                                 tvb, move[i].msec[OFFSET], 1, move[i].msec[VALUE]);
260                 proto_tree_add_uint(sub_tree,
261                                 hf_quake2_game_client_command_move_lightlevel,
262                                 tvb, move[i].lightlevel[OFFSET], 1, move[i].lightlevel[VALUE]);
263
264                 if (move[i].bits[VALUE] == 0) {
265                         proto_item_append_text(movebits_item, " (no moves)");
266                         continue;
267                 }
268
269                 field_tree = proto_item_add_subtree(movebits_item,
270                                 ett_quake2_game_clc_cmd_move_bitfield);
271
272                 if (move[i].bits[VALUE] & CM_ANGLE1) {
273                         bit_item = proto_tree_add_uint(field_tree,
274                                 hf_quake2_game_client_command_move_bitfield_angles1, tvb,
275                                 move[i].angles[0][OFFSET], 2, move[i].bits[VALUE]);
276                         proto_item_append_text(bit_item, " (%d", move[i].angles[0][VALUE]);
277                         proto_item_append_text(bit_item, " = %.2f deg)",
278                                         SHORT2ANGLE(move[i].angles[0][VALUE]));
279                 }
280
281                 if (move[i].bits[VALUE] & CM_ANGLE2) {
282                         bit_item = proto_tree_add_uint(field_tree,
283                                 hf_quake2_game_client_command_move_bitfield_angles2, tvb,
284                                 move[i].angles[1][OFFSET], 2, move[i].bits[VALUE]);
285                         proto_item_append_text(bit_item, " (%d", move[i].angles[1][VALUE]);
286                         proto_item_append_text(bit_item, " = %.2f deg)",
287                                         SHORT2ANGLE(move[i].angles[1][VALUE]));
288                 }
289                 if (move[i].bits[VALUE] & CM_ANGLE3) {
290                         bit_item = proto_tree_add_uint(field_tree,
291                                 hf_quake2_game_client_command_move_bitfield_angles3, tvb,
292                                 move[i].angles[2][OFFSET], 2, move[i].bits[VALUE]);
293                         proto_item_append_text(bit_item, " (%d", move[i].angles[2][VALUE]);
294                         proto_item_append_text(bit_item, " = %.2f deg)",
295                                         SHORT2ANGLE(move[i].angles[2][VALUE]));
296                 }
297                 if (move[i].bits[VALUE] & CM_FORWARD) {
298                         bit_item = proto_tree_add_uint(field_tree,
299                                 hf_quake2_game_client_command_move_bitfield_movement_fwd, tvb,
300                                 move[i].movement[0][OFFSET], 2, move[i].bits[VALUE]);
301                         proto_item_append_text(bit_item, " (%hd)",
302                                         move[i].movement[0][VALUE]);
303                 }
304                 if (move[i].bits[VALUE] & CM_SIDE) {
305                         bit_item = proto_tree_add_uint(field_tree,
306                                 hf_quake2_game_client_command_move_bitfield_movement_side, tvb,
307                                 move[i].movement[1][OFFSET], 2, move[i].bits[VALUE]);
308                         proto_item_append_text(bit_item, " (%hd)",
309                                         move[i].movement[1][VALUE]);
310                 }
311                 if (move[i].bits[VALUE] & CM_UP) {
312                         bit_item = proto_tree_add_uint(field_tree,
313                                 hf_quake2_game_client_command_move_bitfield_movement_up, tvb,
314                                 move[i].movement[2][OFFSET], 2, move[i].bits[VALUE]);
315                         proto_item_append_text(bit_item, " (%hd)",
316                                         move[i].movement[2][VALUE]);
317                 }
318                 if (move[i].bits[VALUE] & CM_BUTTONS) {
319                         bit_item = proto_tree_add_uint(field_tree,
320                                 hf_quake2_game_client_command_move_bitfield_buttons, tvb,
321                                 move[i].buttons[OFFSET], 1, move[i].bits[VALUE]);
322                         proto_item_append_text(bit_item, " (%d)",
323                                         move[i].buttons[VALUE]);
324                         if (move[i].buttons[VALUE] & BUTTON_ATTACK)
325                                 proto_item_append_text(bit_item, " (Attack)");
326                         if (move[i].buttons[VALUE] & BUTTON_USE)
327                                 proto_item_append_text(bit_item, " (Use)");
328                         if (move[i].buttons[VALUE] & BUTTON_ANY)
329                                 proto_item_append_text(bit_item, " (Any)");
330                 }
331                 if (move[i].bits[VALUE] & CM_IMPULSE) {
332                         bit_item = proto_tree_add_uint(field_tree,
333                                 hf_quake2_game_client_command_move_bitfield_impulse, tvb,
334                                 move[i].impulse[OFFSET], 1, move[i].bits[VALUE]);
335                         proto_item_append_text(bit_item, " (%d)",
336                                 move[i].impulse[VALUE]);
337                 }
338
339         }
340
341         return offset;
342 }
343
344 static int
345 dissect_quake2_client_commands_uinfo(tvbuff_t *tvb, packet_info *pinfo _U_,
346         proto_tree *tree)
347 {
348         guint len;
349         proto_item *userinfo_item;
350
351         len = tvb_strsize(tvb, 0);
352
353         if (tree) {
354                 userinfo_item = proto_tree_add_text(tree, tvb, 0, len, "Userinfo: %s",
355                         tvb_get_ptr(tvb, 0, len));
356         }
357
358         return len;
359 }
360
361 static int
362 dissect_quake2_client_commands_stringcmd(tvbuff_t *tvb, packet_info *pinfo _U_,
363         proto_tree *tree)
364 {
365         guint len;
366         proto_item *stringcmd_item;
367
368         len = tvb_strsize(tvb, 0);
369
370         if (tree) {
371                 stringcmd_item = proto_tree_add_text(tree, tvb, 0, len, "Command: %s",
372                         tvb_get_ptr(tvb, 0, len));
373         }
374
375         return len;
376 }
377
378 static const value_string names_client_cmd[] = {
379         /* qcommon.h */
380 #define CLC_BAD 0
381         { CLC_BAD, "clc_bad" },
382 #define CLC_NOP 1
383         { CLC_NOP, "clc_nop" },
384 #define CLC_MOVE 2
385         { CLC_MOVE, "clc_move" },
386 #define CLC_USERINFO 3
387         { CLC_USERINFO, "clc_userinfo" },
388 #define CLC_STRINGCMD 4
389         { CLC_STRINGCMD, "clc_stringcmd" },
390         { 0, NULL }
391 };
392
393 static void
394 dissect_quake2_client_commands(tvbuff_t *tvb, packet_info *pinfo,
395         proto_tree *tree)
396 {
397         proto_tree *clc_tree = NULL;
398         tvbuff_t *next_tvb   = NULL;
399         guint8 client_cmd_type;
400         guint rest_length = 0;
401         int   offset      = 0;
402
403         do {
404                 client_cmd_type = tvb_get_guint8(tvb, offset);
405
406                 if (tree) {
407                         proto_item *cmd_type_item = proto_tree_add_uint(tree,
408                                         hf_quake2_game_client_command, tvb, offset, 1,
409                                         client_cmd_type);
410
411                         if (cmd_type_item) {
412                                 proto_item_append_text(cmd_type_item, " (%s)",
413                                                 val_to_str(client_cmd_type, names_client_cmd, "%u"));
414                                 clc_tree = proto_item_add_subtree(
415                                                 cmd_type_item, ett_quake2_game_clc_cmd);
416                         }
417                 }
418
419                 offset++;
420                 rest_length = tvb_reported_length(tvb) - offset;
421                 if (rest_length)
422                         next_tvb = tvb_new_subset(tvb, offset,
423                                         rest_length, rest_length);
424                 else
425                         return;
426
427                 rest_length = 0;
428                 switch (client_cmd_type) {
429                         case CLC_BAD:
430                                 break;
431                         case CLC_NOP:
432                                 break;
433                         case CLC_MOVE:
434                                 rest_length =
435                                         dissect_quake2_client_commands_move(next_tvb,
436                                                         pinfo, clc_tree);
437                                 break;
438                         case CLC_USERINFO:
439                                 rest_length =
440                                         dissect_quake2_client_commands_uinfo(next_tvb,
441                                                         pinfo, clc_tree);
442                                 break;
443                         case CLC_STRINGCMD:
444                                 rest_length =
445                                         dissect_quake2_client_commands_stringcmd(next_tvb,
446                                                         pinfo, clc_tree);
447                                 break;
448                         default:
449                                 break;
450                 }
451                 offset += rest_length;
452         } while (tvb_reported_length(tvb) - offset > 0);
453 }
454
455 static const value_string names_server_cmd[] = {
456         /* qcommon.h */
457 #define SVC_BAD 0
458         { SVC_BAD, "svc_bad" },
459 #define SVC_MUZZLEFLASH 1
460         { SVC_MUZZLEFLASH, "svc_muzzleflash" },
461 #define SVC_MUZZLEFLASH2 2
462         { SVC_MUZZLEFLASH2, "svc_muzzleflash2" },
463 #define SVC_TEMP_ENTITY 3
464         { SVC_TEMP_ENTITY, "svc_temp_entity" },
465 #define SVC_LAYOUT 4
466         { SVC_LAYOUT, "svc_layout" },
467 #define SVC_INVENTORY 5
468         { SVC_INVENTORY, "svc_inventory" },
469 #define SVC_NOP 6
470         { SVC_NOP, "svc_nop" },
471 #define SVC_DISCONNECT 7
472         { SVC_DISCONNECT, "svc_disconnect" },
473 #define SVC_RECONNECT 8
474         { SVC_RECONNECT, "svc_reconnect" },
475 #define SVC_SOUND 9
476         { SVC_SOUND, "svc_sound" },
477 #define SVC_PRINT 10
478         { SVC_PRINT, "svc_print" },
479 #define SVC_STUFFTEXT 11
480         { SVC_STUFFTEXT, "svc_stufftext" },
481 #define SVC_SERVERDATA 12
482         { SVC_SERVERDATA, "svc_serverdata" },
483 #define  SVC_CONFIGSTRING 13
484         { SVC_CONFIGSTRING, "svc_configstring" },
485 #define SVC_SPAWNBASELINE 14
486         { SVC_SPAWNBASELINE, "svc_spawnbaseline" },
487 #define SVC_CENTERPRINT 15
488         { SVC_CENTERPRINT, "svc_centerprint" },
489 #define SVC_DOWNLOAD 16
490         { SVC_DOWNLOAD, "svc_download" },
491 #define SVC_PLAYERINFO 17
492         { SVC_PLAYERINFO, "svc_playerinfo" },
493 #define SVC_PACKETENTITIES 18
494         { SVC_PACKETENTITIES, "svc_packetentities" },
495 #define SVC_DELTAPACKETENTITIES 19
496         { SVC_DELTAPACKETENTITIES, "svc_deltapacketentities" },
497 #define SVC_FRAME 20
498         { SVC_FRAME, "svc_frame" },
499         { 0, NULL }
500 };
501
502 static void
503 dissect_quake2_server_commands(tvbuff_t *tvb, packet_info *pinfo,
504         proto_tree *tree)
505 {
506         tvbuff_t *next_tvb = NULL;
507         proto_item *cmd_type_item = NULL;
508         guint8 server_cmd_type;
509         guint rest_length = 0;
510         int offset = 0;
511
512         server_cmd_type = tvb_get_guint8(tvb, offset);
513
514         if (tree) {
515                 cmd_type_item = proto_tree_add_uint(tree,
516                                 hf_quake2_game_server_command, tvb, offset, 1, server_cmd_type);
517
518                 if (cmd_type_item) {
519                         proto_item_append_text(cmd_type_item, " (%s)",
520                                         val_to_str(server_cmd_type, names_server_cmd, "%u"));
521                 }
522         }
523
524         offset++;
525         rest_length = tvb_reported_length(tvb) - offset;
526         if (rest_length)
527                 next_tvb = tvb_new_subset(tvb, offset, rest_length, rest_length);
528         else
529                 return;
530
531
532         switch (server_cmd_type) {
533                 case SVC_BAD:
534                         break;
535                 case SVC_MUZZLEFLASH:
536                         break;
537                 case SVC_MUZZLEFLASH2:
538                         break;
539                 case SVC_TEMP_ENTITY:
540                         break;
541                 case SVC_LAYOUT:
542                         break;
543                 case SVC_NOP:
544                         break;
545                 case SVC_DISCONNECT:
546                         break;
547                 case SVC_RECONNECT:
548                         break;
549                 case SVC_SOUND:
550                         break;
551                 case SVC_PRINT:
552                         break;
553                 case SVC_STUFFTEXT:
554                         break;
555                 case SVC_SERVERDATA:
556                         break;
557                 case SVC_CONFIGSTRING:
558                         break;
559                 case SVC_SPAWNBASELINE:
560                         break;
561                 case SVC_CENTERPRINT:
562                         break;
563                 case SVC_DOWNLOAD:
564                         break;
565                 case SVC_PLAYERINFO:
566                         break;
567                 case SVC_PACKETENTITIES:
568                         break;
569                 case SVC_DELTAPACKETENTITIES:
570                         break;
571                 case SVC_FRAME:
572                         break;
573
574                 default:
575                         break;
576         }
577         call_dissector(data_handle, next_tvb, pinfo, tree);
578 }
579
580
581 static const value_string names_reliable[] = {
582         { 0, "Non Reliable" },
583         { 1, "Reliable" },
584         { 0, NULL }
585 };
586
587
588 static const value_string names_direction[] = {
589 #define DIR_C2S 0
590         { DIR_C2S, "Client to Server" },
591 #define DIR_S2C 1
592         { DIR_S2C, "Server to Client" },
593         { 0, NULL }
594 };
595
596
597 static void
598 dissect_quake2_GamePacket(tvbuff_t *tvb, packet_info *pinfo,
599         proto_tree *tree, int direction)
600 {
601         proto_tree      *game_tree = NULL;
602         proto_item      *game_item = NULL;
603         guint32 seq1;
604         guint32 seq2;
605         int rel1;
606         int rel2;
607         int offset;
608         guint           rest_length;
609
610         direction = (pinfo->destport == gbl_quake2ServerPort) ?
611                         DIR_C2S : DIR_S2C;
612
613         if (tree) {
614                 game_item = proto_tree_add_text(tree, tvb,
615                                 0, -1, "Game");
616                 if (game_item)
617                         game_tree = proto_item_add_subtree(
618                                 game_item, ett_quake2_game);
619         }
620
621         offset = 0;
622
623         seq1 = tvb_get_letohl(tvb, offset);
624         rel1 = seq1 & 0x80000000 ? 1 : 0;
625         seq1 &= ~0x80000000;
626         if (game_tree) {
627                 proto_item *seq1_item = proto_tree_add_text(game_tree,
628                         tvb, offset, 4, "Current Sequence: %u (%s)",
629                         seq1, val_to_str(rel1,names_reliable,"%u"));
630                 if (seq1_item) {
631                         proto_tree *seq1_tree = proto_item_add_subtree(
632                                 seq1_item, ett_quake2_game_seq1);
633                         proto_tree_add_uint(seq1_tree, hf_quake2_game_seq1,
634                                         tvb, offset, 4, seq1);
635                         proto_tree_add_boolean(seq1_tree, hf_quake2_game_rel1,
636                                         tvb, offset+3, 1, rel1);
637                 }
638         }
639         offset += 4;
640
641         seq2 = tvb_get_letohl(tvb, offset);
642         rel2 = seq2 & 0x80000000 ? 1 : 0;
643         seq2 &= ~0x80000000;
644         if (game_tree) {
645                 proto_item *seq2_item = proto_tree_add_text(game_tree,
646                         tvb, offset, 4, "Acknowledge Sequence: %u (%s)",
647                         seq2, val_to_str(rel2,names_reliable,"%u"));
648                 if (seq2_item) {
649                         proto_tree *seq2_tree = proto_item_add_subtree(
650                                 seq2_item, ett_quake2_game_seq2);
651                         proto_tree_add_uint(seq2_tree, hf_quake2_game_seq2,
652                                         tvb, offset, 4, seq2);
653                         proto_tree_add_boolean(seq2_tree, hf_quake2_game_rel2,
654                                         tvb, offset+3, 1, rel2);
655                 }
656         }
657         offset += 4;
658
659         if (direction == DIR_C2S) {
660                 /* client to server */
661                 guint16 qport = tvb_get_letohs(tvb, offset);
662                 if (game_tree) {
663                         proto_tree_add_uint(game_tree, hf_quake2_game_qport,
664                                 tvb, offset, 2, qport);
665                 }
666                 offset +=2;
667         }
668
669         /* all the rest is pure game data */
670         rest_length = tvb_reported_length(tvb) - offset;
671         if (rest_length) {
672                 tvbuff_t *next_tvb =
673                 tvb_new_subset(tvb, offset, rest_length , rest_length);
674
675                 if (direction == DIR_C2S) {
676                         proto_item *c_item = NULL;
677                         proto_tree *c_tree = NULL;
678                         if (tree) {
679                                 c_item = proto_tree_add_text(game_tree, next_tvb,
680                                 0, -1, "Client Commands");
681                                 if (c_item) {
682                                         c_tree = proto_item_add_subtree(
683                                                 c_item, ett_quake2_game_clc);
684                                 }
685                         }
686                         dissect_quake2_client_commands(next_tvb, pinfo, c_tree);
687                 }
688                 else {
689                         proto_item *c_item = NULL;
690                         proto_tree *c_tree = NULL;
691                         if (tree) {
692                                 c_item = proto_tree_add_text(game_tree, next_tvb,
693                                 0, -1, "Server Commands");
694                                 if (c_item) {
695                                         c_tree = proto_item_add_subtree(
696                                         c_item, ett_quake2_game_svc);
697                                 }
698                         }
699                         dissect_quake2_server_commands(next_tvb, pinfo, c_tree);
700                 }
701         }
702 }
703
704
705 static void
706 dissect_quake2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
707 {
708         proto_tree      *quake2_tree = NULL;
709         proto_item      *quake2_item = NULL;
710         int             direction;
711
712         direction = (pinfo->destport == gbl_quake2ServerPort) ?
713                         DIR_C2S : DIR_S2C;
714
715         if (check_col(pinfo->cinfo, COL_PROTOCOL))
716                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "QUAKE2");
717         if (check_col(pinfo->cinfo, COL_INFO))
718                 col_add_str(pinfo->cinfo, COL_INFO, val_to_str(direction,
719                         names_direction, "%u"));
720
721         if (tree) {
722                 quake2_item = proto_tree_add_item(tree, proto_quake2,
723                                 tvb, 0, -1, FALSE);
724                 if (quake2_item)
725                         quake2_tree = proto_item_add_subtree(
726                                 quake2_item, ett_quake2);
727                         if (quake2_tree) {
728                                 proto_tree_add_uint_format(quake2_tree,
729                                         direction == DIR_S2C ?
730                                         hf_quake2_s2c :
731                                         hf_quake2_c2s,
732                                         tvb, 0, 0, 1,
733                                         "Direction: %s", val_to_str(direction, names_direction, "%u"));
734                         }
735         }
736
737         if (tvb_get_ntohl(tvb, 0) == 0xffffffff) {
738                 if (check_col(pinfo->cinfo, COL_INFO)) {
739                         col_append_str(pinfo->cinfo, COL_INFO, " Connectionless");
740                 }
741                 if (quake2_tree)
742                         proto_tree_add_uint_format(quake2_tree,
743                                 hf_quake2_connectionless,
744                                 tvb, 0, 0, 1,
745                                 "Type: Connectionless");
746                 dissect_quake2_ConnectionlessPacket(
747                         tvb, pinfo, quake2_tree, direction);
748         }
749         else {
750                 if (check_col(pinfo->cinfo, COL_INFO)) {
751                         col_append_str(pinfo->cinfo, COL_INFO, " Game");
752                 }
753                 if (quake2_tree)
754                         proto_tree_add_uint_format(quake2_tree,
755                                 hf_quake2_game,
756                                 tvb, 0, 0, 1,
757                                 "Type: Game");
758                 dissect_quake2_GamePacket(
759                         tvb, pinfo, quake2_tree, direction);
760         }
761 }
762
763
764 void
765 proto_reg_handoff_quake2(void)
766 {
767         static int Initialized=FALSE;
768         static dissector_handle_t quake2_handle;
769         static int ServerPort=0;
770
771         if (!Initialized) {
772                 quake2_handle = create_dissector_handle(dissect_quake2,
773                                 proto_quake2);
774                 Initialized=TRUE;
775         } else {
776                 dissector_delete("udp.port", ServerPort, quake2_handle);
777         }
778
779         /* set port for future deletes */
780         ServerPort=gbl_quake2ServerPort;
781
782         dissector_add("udp.port", gbl_quake2ServerPort, quake2_handle);
783         data_handle = find_dissector("data");
784 }
785
786
787 void
788 proto_register_quake2(void)
789 {
790         static hf_register_info hf[] = {
791                 { &hf_quake2_c2s,
792                         { "Client to Server", "quake2.c2s",
793                         FT_UINT32, BASE_DEC, NULL, 0x0,
794                         "Client to Server", HFILL }},
795                 { &hf_quake2_s2c,
796                         { "Server to Client", "quake2.s2c",
797                         FT_UINT32, BASE_DEC, NULL, 0x0,
798                         "Server to Client", HFILL }},
799                 { &hf_quake2_connectionless,
800                         { "Connectionless", "quake2.connectionless",
801                         FT_UINT32, BASE_DEC, NULL, 0x0,
802                         "Connectionless", HFILL }},
803                 { &hf_quake2_game,
804                         { "Game", "quake2.game",
805                         FT_UINT32, BASE_DEC, NULL, 0x0,
806                         "Game", HFILL }},
807                 { &hf_quake2_connectionless_marker,
808                         { "Marker", "quake2.connectionless.marker",
809                         FT_UINT32, BASE_HEX, NULL, 0x0,
810                         "Marker", HFILL }},
811                 { &hf_quake2_connectionless_text,
812                         { "Text", "quake2.connectionless.text",
813                         FT_STRING, BASE_DEC, NULL, 0x0,
814                         "Text", HFILL }},
815                 { &hf_quake2_game_seq1,
816                         { "Sequence Number", "quake2.game.seq1",
817                         FT_UINT32, BASE_DEC, NULL, 0x0,
818                         "Sequence number of the current packet", HFILL }},
819                 { &hf_quake2_game_rel1,
820                         { "Reliable", "quake2.game.rel1",
821                         FT_BOOLEAN, BASE_DEC, NULL, 0x0,
822                         "Packet is reliable and may be retransmitted", HFILL }},
823                 { &hf_quake2_game_seq2,
824                         { "Sequence Number", "quake2.game.seq2",
825                         FT_UINT32, BASE_DEC, NULL, 0x0,
826                         "Sequence number of the last received packet", HFILL }},
827                 { &hf_quake2_game_rel2,
828                         { "Reliable", "quake2.game.rel2",
829                         FT_BOOLEAN, BASE_DEC, NULL, 0x0,
830                         "Packet was reliable and may be retransmitted", HFILL }},
831                 { &hf_quake2_game_qport,
832                         { "QPort", "quake2.game.qport",
833                         FT_UINT32, BASE_DEC, NULL, 0x0,
834                         "Quake II Client Port", HFILL }},
835                 { &hf_quake2_game_client_command,
836                         { "Client Command Type", "quake2.game.client.command",
837                         FT_UINT8, BASE_DEC, NULL, 0x0,
838                         "Quake II Client Command", HFILL }},
839                 { &hf_quake2_game_server_command,
840                         { "Server Command", "quake2.game.server.command",
841                         FT_UINT8, BASE_DEC, NULL, 0x0,
842                         "Quake II Server Command", HFILL }},
843                 { &hf_quake2_game_client_command_move_chksum,
844                         { "Checksum", "quake2.game.client.command.move.chksum",
845                         FT_UINT8, BASE_HEX, NULL, 0x0,
846                         "Quake II Client Command Move", HFILL }},
847                 { &hf_quake2_game_client_command_move_lframe,
848                         { "Last Frame", "quake2.game.client.command.move.lframe",
849                         FT_UINT32, BASE_DEC, NULL, 0x0,
850                         "Quake II Client Command Move", HFILL }},
851                 { &hf_quake2_game_client_command_move,
852                         { "Bitfield", "quake2.game.client.command.move",
853                         FT_UINT8, BASE_HEX, NULL, 0x0,
854                         "Quake II Client Command Move", HFILL }},
855                 { &hf_quake2_game_client_command_move_bitfield_angles1,
856                         { "Angles (pitch)", "quake2.game.client.command.move.angles",
857                         FT_UINT8, BASE_HEX,
858                         VALS(hf_quake2_game_client_command_move_vals),
859                         CM_ANGLE1, "", HFILL }},
860                 { &hf_quake2_game_client_command_move_bitfield_angles2,
861                         { "Angles (yaw)", "quake2.game.client.command.move.angles",
862                         FT_UINT8, BASE_HEX,
863                         VALS(hf_quake2_game_client_command_move_vals),
864                         CM_ANGLE2, "", HFILL }},
865                 { &hf_quake2_game_client_command_move_bitfield_angles3,
866                         { "Angles (roll)", "quake2.game.client.command.move.angles",
867                         FT_UINT8, BASE_HEX,
868                         VALS(hf_quake2_game_client_command_move_vals),
869                         CM_ANGLE3, "", HFILL }},
870                 { &hf_quake2_game_client_command_move_bitfield_movement_fwd,
871                         { "Movement (fwd)", "quake2.game.client.command.move.movement",
872                         FT_UINT8, BASE_HEX,
873                         VALS(hf_quake2_game_client_command_move_vals),
874                         CM_FORWARD, "", HFILL }},
875                 { &hf_quake2_game_client_command_move_bitfield_movement_side,
876                         { "Movement (side)", "quake2.game.client.command.move.movement",
877                         FT_UINT8, BASE_HEX,
878                         VALS(hf_quake2_game_client_command_move_vals),
879                         CM_SIDE, "", HFILL }},
880                 { &hf_quake2_game_client_command_move_bitfield_movement_up,
881                         { "Movement (up)", "quake2.game.client.command.move.movement",
882                         FT_UINT8, BASE_HEX,
883                         VALS(hf_quake2_game_client_command_move_vals),
884                         CM_UP, "", HFILL }},
885                 { &hf_quake2_game_client_command_move_bitfield_buttons,
886                         { "Buttons", "quake2.game.client.command.move.buttons",
887                         FT_UINT8, BASE_HEX,
888                         VALS(hf_quake2_game_client_command_move_vals),
889                         CM_BUTTONS, "", HFILL }},
890                 { &hf_quake2_game_client_command_move_bitfield_impulse,
891                         { "Impulse", "quake2.game.client.command.move.impulse",
892                         FT_UINT8, BASE_HEX,
893                         VALS(hf_quake2_game_client_command_move_vals),
894                         CM_IMPULSE, "", HFILL }},
895                 { &hf_quake2_game_client_command_move_msec,
896                         { "Msec", "quake2.game.client.command.move.msec",
897                         FT_UINT8, BASE_DEC, NULL, 0x0,
898                         "Quake II Client Command Move", HFILL }},
899                 { &hf_quake2_game_client_command_move_lightlevel,
900                         { "Lightlevel", "quake2.game.client.command.move.lightlevel",
901                         FT_UINT8, BASE_DEC, NULL, 0x0,
902                         "Quake II Client Command Move", HFILL }}
903         };
904         static gint *ett[] = {
905                 &ett_quake2,
906                 &ett_quake2_connectionless,
907                 &ett_quake2_game,
908                 &ett_quake2_game_seq1,
909                 &ett_quake2_game_seq2,
910                 &ett_quake2_game_clc,
911                 &ett_quake2_game_svc,
912                 &ett_quake2_game_clc_cmd,
913                 &ett_quake2_game_svc_cmd,
914                 &ett_quake2_game_clc_cmd_move_moves,
915                 &ett_quake2_game_clc_cmd_move_bitfield
916         };
917         module_t *quake2_module;
918
919         proto_quake2 = proto_register_protocol("Quake II Network Protocol",
920                                                 "QUAKE2", "quake2");
921         proto_register_field_array(proto_quake2, hf, array_length(hf));
922         proto_register_subtree_array(ett, array_length(ett));
923
924         /* Register a configuration option for port */
925         quake2_module = prefs_register_protocol(proto_quake2,
926                 proto_reg_handoff_quake2);
927         prefs_register_uint_preference(quake2_module, "udp.port",
928                                         "Quake II Server UDP Port",
929                                         "Set the UDP port for the Quake II Server",
930                                         10, &gbl_quake2ServerPort);
931 }