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