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