For proto_tree_add_item(..., proto_xxx, ...)use ENC_NA as the encoding arg.
[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 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
345         len = tvb_strsize(tvb, 0);
346
347         if (tree) {
348                 proto_tree_add_text(tree, tvb, 0, len, "Userinfo: %s",
349                                     tvb_get_ephemeral_string(tvb, 0, len));
350         }
351
352         return len;
353 }
354
355 static int
356 dissect_quake2_client_commands_stringcmd(tvbuff_t *tvb, packet_info *pinfo _U_,
357         proto_tree *tree)
358 {
359         guint len;
360
361         len = tvb_strsize(tvb, 0);
362
363         if (tree) {
364                 proto_tree_add_text(tree, tvb, 0, len, "Command: %s",
365                                     tvb_get_ephemeral_string(tvb, 0, len));
366         }
367
368         return len;
369 }
370
371 static const value_string names_client_cmd[] = {
372         /* qcommon.h */
373 #define CLC_BAD 0
374         { CLC_BAD, "clc_bad" },
375 #define CLC_NOP 1
376         { CLC_NOP, "clc_nop" },
377 #define CLC_MOVE 2
378         { CLC_MOVE, "clc_move" },
379 #define CLC_USERINFO 3
380         { CLC_USERINFO, "clc_userinfo" },
381 #define CLC_STRINGCMD 4
382         { CLC_STRINGCMD, "clc_stringcmd" },
383         { 0, NULL }
384 };
385
386 static void
387 dissect_quake2_client_commands(tvbuff_t *tvb, packet_info *pinfo,
388         proto_tree *tree)
389 {
390         proto_tree *clc_tree = NULL;
391         tvbuff_t *next_tvb   = NULL;
392         guint8 client_cmd_type;
393         guint rest_length = 0;
394         int   offset      = 0;
395
396         do {
397                 client_cmd_type = tvb_get_guint8(tvb, offset);
398
399                 if (tree) {
400                         proto_item *cmd_type_item = proto_tree_add_uint(tree,
401                                         hf_quake2_game_client_command, tvb, offset, 1,
402                                         client_cmd_type);
403
404                         proto_item_append_text(cmd_type_item, " (%s)",
405                                                val_to_str(client_cmd_type, names_client_cmd, "%u"));
406                         clc_tree = proto_item_add_subtree(cmd_type_item, ett_quake2_game_clc_cmd);
407                 }
408
409                 offset++;
410                 rest_length = tvb_reported_length(tvb) - offset;
411                 if (rest_length)
412                         next_tvb = tvb_new_subset(tvb, offset,
413                                         rest_length, rest_length);
414                 else
415                         return;
416
417                 rest_length = 0;
418                 switch (client_cmd_type) {
419                         case CLC_BAD:
420                                 break;
421                         case CLC_NOP:
422                                 break;
423                         case CLC_MOVE:
424                                 rest_length =
425                                         dissect_quake2_client_commands_move(next_tvb,
426                                                         pinfo, clc_tree);
427                                 break;
428                         case CLC_USERINFO:
429                                 rest_length =
430                                         dissect_quake2_client_commands_uinfo(next_tvb,
431                                                         pinfo, clc_tree);
432                                 break;
433                         case CLC_STRINGCMD:
434                                 rest_length =
435                                         dissect_quake2_client_commands_stringcmd(next_tvb,
436                                                         pinfo, clc_tree);
437                                 break;
438                         default:
439                                 break;
440                 }
441                 offset += rest_length;
442         } while (tvb_reported_length(tvb) - offset > 0);
443 }
444
445 static const value_string names_server_cmd[] = {
446         /* qcommon.h */
447 #define SVC_BAD 0
448         { SVC_BAD, "svc_bad" },
449 #define SVC_MUZZLEFLASH 1
450         { SVC_MUZZLEFLASH, "svc_muzzleflash" },
451 #define SVC_MUZZLEFLASH2 2
452         { SVC_MUZZLEFLASH2, "svc_muzzleflash2" },
453 #define SVC_TEMP_ENTITY 3
454         { SVC_TEMP_ENTITY, "svc_temp_entity" },
455 #define SVC_LAYOUT 4
456         { SVC_LAYOUT, "svc_layout" },
457 #define SVC_INVENTORY 5
458         { SVC_INVENTORY, "svc_inventory" },
459 #define SVC_NOP 6
460         { SVC_NOP, "svc_nop" },
461 #define SVC_DISCONNECT 7
462         { SVC_DISCONNECT, "svc_disconnect" },
463 #define SVC_RECONNECT 8
464         { SVC_RECONNECT, "svc_reconnect" },
465 #define SVC_SOUND 9
466         { SVC_SOUND, "svc_sound" },
467 #define SVC_PRINT 10
468         { SVC_PRINT, "svc_print" },
469 #define SVC_STUFFTEXT 11
470         { SVC_STUFFTEXT, "svc_stufftext" },
471 #define SVC_SERVERDATA 12
472         { SVC_SERVERDATA, "svc_serverdata" },
473 #define  SVC_CONFIGSTRING 13
474         { SVC_CONFIGSTRING, "svc_configstring" },
475 #define SVC_SPAWNBASELINE 14
476         { SVC_SPAWNBASELINE, "svc_spawnbaseline" },
477 #define SVC_CENTERPRINT 15
478         { SVC_CENTERPRINT, "svc_centerprint" },
479 #define SVC_DOWNLOAD 16
480         { SVC_DOWNLOAD, "svc_download" },
481 #define SVC_PLAYERINFO 17
482         { SVC_PLAYERINFO, "svc_playerinfo" },
483 #define SVC_PACKETENTITIES 18
484         { SVC_PACKETENTITIES, "svc_packetentities" },
485 #define SVC_DELTAPACKETENTITIES 19
486         { SVC_DELTAPACKETENTITIES, "svc_deltapacketentities" },
487 #define SVC_FRAME 20
488         { SVC_FRAME, "svc_frame" },
489         { 0, NULL }
490 };
491
492 static void
493 dissect_quake2_server_commands(tvbuff_t *tvb, packet_info *pinfo,
494         proto_tree *tree)
495 {
496         tvbuff_t *next_tvb = NULL;
497         guint8 server_cmd_type;
498         guint rest_length = 0;
499         int offset = 0;
500
501         server_cmd_type = tvb_get_guint8(tvb, offset);
502
503         if (tree) {
504                 proto_item *cmd_type_item;
505                 cmd_type_item = proto_tree_add_uint(tree,
506                                 hf_quake2_game_server_command, tvb, offset, 1, server_cmd_type);
507
508                 proto_item_append_text(cmd_type_item, " (%s)",
509                                        val_to_str(server_cmd_type, names_server_cmd, "%u"));
510         }
511
512         offset++;
513         rest_length = tvb_reported_length(tvb) - offset;
514         if (rest_length)
515                 next_tvb = tvb_new_subset(tvb, offset, rest_length, rest_length);
516         else
517                 return;
518
519
520         switch (server_cmd_type) {
521                 case SVC_BAD:
522                         break;
523                 case SVC_MUZZLEFLASH:
524                         break;
525                 case SVC_MUZZLEFLASH2:
526                         break;
527                 case SVC_TEMP_ENTITY:
528                         break;
529                 case SVC_LAYOUT:
530                         break;
531                 case SVC_NOP:
532                         break;
533                 case SVC_DISCONNECT:
534                         break;
535                 case SVC_RECONNECT:
536                         break;
537                 case SVC_SOUND:
538                         break;
539                 case SVC_PRINT:
540                         break;
541                 case SVC_STUFFTEXT:
542                         break;
543                 case SVC_SERVERDATA:
544                         break;
545                 case SVC_CONFIGSTRING:
546                         break;
547                 case SVC_SPAWNBASELINE:
548                         break;
549                 case SVC_CENTERPRINT:
550                         break;
551                 case SVC_DOWNLOAD:
552                         break;
553                 case SVC_PLAYERINFO:
554                         break;
555                 case SVC_PACKETENTITIES:
556                         break;
557                 case SVC_DELTAPACKETENTITIES:
558                         break;
559                 case SVC_FRAME:
560                         break;
561
562                 default:
563                         break;
564         }
565         call_dissector(data_handle, next_tvb, pinfo, tree);
566 }
567
568
569 static const value_string names_reliable[] = {
570         { 0, "Non Reliable" },
571         { 1, "Reliable" },
572         { 0, NULL }
573 };
574
575 static const value_string names_direction[] = {
576 #define DIR_C2S 0
577         { DIR_C2S, "Client to Server" },
578 #define DIR_S2C 1
579         { DIR_S2C, "Server to Client" },
580         { 0, NULL }
581 };
582
583
584 static void
585 dissect_quake2_GamePacket(tvbuff_t *tvb, packet_info *pinfo,
586         proto_tree *tree, int direction)
587 {
588         proto_tree *game_tree = NULL;
589         guint32    seq1;
590         guint32    seq2;
591         int        rel1;
592         int        rel2;
593         int        offset;
594         guint      rest_length;
595
596         direction = (pinfo->destport == gbl_quake2ServerPort) ?
597                         DIR_C2S : DIR_S2C;
598
599         if (tree) {
600                 proto_item *game_item;
601                 game_item = proto_tree_add_text(tree, tvb,
602                                 0, -1, "Game");
603                 game_tree = proto_item_add_subtree(game_item, ett_quake2_game);
604         }
605
606         offset = 0;
607
608         seq1 = tvb_get_letohl(tvb, offset);
609         rel1 = seq1 & 0x80000000 ? 1 : 0;
610         seq1 &= ~0x80000000;
611         if (game_tree) {
612                 proto_item *seq1_item = proto_tree_add_text(game_tree,
613                         tvb, offset, 4, "Current Sequence: %u (%s)",
614                         seq1, val_to_str(rel1,names_reliable,"%u"));
615                 proto_tree *seq1_tree = proto_item_add_subtree(
616                         seq1_item, ett_quake2_game_seq1);
617                 proto_tree_add_uint(seq1_tree, hf_quake2_game_seq1,
618                                     tvb, offset, 4, seq1);
619                 proto_tree_add_boolean(seq1_tree, hf_quake2_game_rel1,
620                                        tvb, offset+3, 1, rel1);
621         }
622         offset += 4;
623
624         seq2 = tvb_get_letohl(tvb, offset);
625         rel2 = seq2 & 0x80000000 ? 1 : 0;
626         seq2 &= ~0x80000000;
627         if (game_tree) {
628                 proto_item *seq2_item = proto_tree_add_text(game_tree,
629                         tvb, offset, 4, "Acknowledge Sequence: %u (%s)",
630                         seq2, val_to_str(rel2,names_reliable,"%u"));
631                 proto_tree *seq2_tree = proto_item_add_subtree(
632                         seq2_item, ett_quake2_game_seq2);
633                 proto_tree_add_uint(seq2_tree, hf_quake2_game_seq2,
634                                     tvb, offset, 4, seq2);
635                 proto_tree_add_boolean(seq2_tree, hf_quake2_game_rel2,
636                                        tvb, offset+3, 1, rel2);
637         }
638         offset += 4;
639
640         if (direction == DIR_C2S) {
641                 /* client to server */
642                 guint16 qport = tvb_get_letohs(tvb, offset);
643                 if (game_tree) {
644                         proto_tree_add_uint(game_tree, hf_quake2_game_qport,
645                                 tvb, offset, 2, qport);
646                 }
647                 offset +=2;
648         }
649
650         /* all the rest is pure game data */
651         rest_length = tvb_reported_length(tvb) - offset;
652         if (rest_length) {
653                 tvbuff_t *next_tvb =
654                 tvb_new_subset(tvb, offset, rest_length , rest_length);
655
656                 if (direction == DIR_C2S) {
657                         proto_tree *c_tree = NULL;
658                         if (tree) {
659                                 proto_item *c_item;
660                                 c_item = proto_tree_add_text(game_tree, next_tvb,
661                                                              0, -1, "Client Commands");
662                                 c_tree = proto_item_add_subtree(c_item, ett_quake2_game_clc);
663                         }
664                         dissect_quake2_client_commands(next_tvb, pinfo, c_tree);
665                 }
666                 else {
667                         proto_tree *c_tree = NULL;
668                         if (tree) {
669                                 proto_item *c_item;
670                                 c_item = proto_tree_add_text(game_tree, next_tvb,
671                                                              0, -1, "Server Commands");
672                                 c_tree = proto_item_add_subtree(c_item, ett_quake2_game_svc);
673                         }
674                         dissect_quake2_server_commands(next_tvb, pinfo, c_tree);
675                 }
676         }
677 }
678
679
680 static void
681 dissect_quake2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
682 {
683         proto_tree      *quake2_tree = NULL;
684         int             direction;
685
686         direction = (pinfo->destport == gbl_quake2ServerPort) ?
687                         DIR_C2S : DIR_S2C;
688
689         col_set_str(pinfo->cinfo, COL_PROTOCOL, "QUAKE2");
690         if (check_col(pinfo->cinfo, COL_INFO))
691                 col_add_str(pinfo->cinfo, COL_INFO, val_to_str(direction,
692                         names_direction, "%u"));
693
694         if (tree) {
695                 proto_item *quake2_item;
696                 quake2_item = proto_tree_add_item(tree, proto_quake2,
697                                                   tvb, 0, -1, ENC_NA);
698                 quake2_tree = proto_item_add_subtree(quake2_item, ett_quake2);
699                 proto_tree_add_uint_format(quake2_tree,
700                                            direction == DIR_S2C ?
701                                            hf_quake2_s2c :
702                                            hf_quake2_c2s,
703                                            tvb, 0, 0, 1,
704                                            "Direction: %s", val_to_str(direction, names_direction, "%u"));
705         }
706
707         if (tvb_get_ntohl(tvb, 0) == 0xffffffff) {
708                 col_append_str(pinfo->cinfo, COL_INFO, " Connectionless");
709                 if (quake2_tree)
710                         proto_tree_add_uint_format(quake2_tree,
711                                 hf_quake2_connectionless,
712                                 tvb, 0, 0, 1,
713                                 "Type: Connectionless");
714                 dissect_quake2_ConnectionlessPacket(
715                         tvb, pinfo, quake2_tree, direction);
716         }
717         else {
718                 col_append_str(pinfo->cinfo, COL_INFO, " Game");
719                 if (quake2_tree)
720                         proto_tree_add_uint_format(quake2_tree,
721                                 hf_quake2_game,
722                                 tvb, 0, 0, 1,
723                                 "Type: Game");
724                 dissect_quake2_GamePacket(
725                         tvb, pinfo, quake2_tree, direction);
726         }
727 }
728
729
730 void proto_reg_handoff_quake2(void);
731
732 void
733 proto_register_quake2(void)
734 {
735         static hf_register_info hf[] = {
736                 { &hf_quake2_c2s,
737                         { "Client to Server", "quake2.c2s",
738                         FT_UINT32, BASE_DEC, NULL, 0x0,
739                         NULL, HFILL }},
740                 { &hf_quake2_s2c,
741                         { "Server to Client", "quake2.s2c",
742                         FT_UINT32, BASE_DEC, NULL, 0x0,
743                         NULL, HFILL }},
744                 { &hf_quake2_connectionless,
745                         { "Connectionless", "quake2.connectionless",
746                         FT_UINT32, BASE_DEC, NULL, 0x0,
747                         NULL, HFILL }},
748                 { &hf_quake2_game,
749                         { "Game", "quake2.game",
750                         FT_UINT32, BASE_DEC, NULL, 0x0,
751                         NULL, HFILL }},
752                 { &hf_quake2_connectionless_marker,
753                         { "Marker", "quake2.connectionless.marker",
754                         FT_UINT32, BASE_HEX, NULL, 0x0,
755                         NULL, HFILL }},
756                 { &hf_quake2_connectionless_text,
757                         { "Text", "quake2.connectionless.text",
758                         FT_STRING, BASE_NONE, NULL, 0x0,
759                         NULL, HFILL }},
760                 { &hf_quake2_game_seq1,
761                         { "Sequence Number", "quake2.game.seq1",
762                         FT_UINT32, BASE_DEC, NULL, 0x0,
763                         "Sequence number of the current packet", HFILL }},
764                 { &hf_quake2_game_rel1,
765                         { "Reliable", "quake2.game.rel1",
766                         FT_BOOLEAN, BASE_NONE, NULL, 0x0,
767                         "Packet is reliable and may be retransmitted", HFILL }},
768                 { &hf_quake2_game_seq2,
769                         { "Sequence Number", "quake2.game.seq2",
770                         FT_UINT32, BASE_DEC, NULL, 0x0,
771                         "Sequence number of the last received packet", HFILL }},
772                 { &hf_quake2_game_rel2,
773                         { "Reliable", "quake2.game.rel2",
774                         FT_BOOLEAN, BASE_NONE, NULL, 0x0,
775                         "Packet was reliable and may be retransmitted", HFILL }},
776                 { &hf_quake2_game_qport,
777                         { "QPort", "quake2.game.qport",
778                         FT_UINT32, BASE_DEC, NULL, 0x0,
779                         "Quake II Client Port", HFILL }},
780                 { &hf_quake2_game_client_command,
781                         { "Client Command Type", "quake2.game.client.command",
782                         FT_UINT8, BASE_DEC, NULL, 0x0,
783                         "Quake II Client Command", HFILL }},
784                 { &hf_quake2_game_server_command,
785                         { "Server Command", "quake2.game.server.command",
786                         FT_UINT8, BASE_DEC, NULL, 0x0,
787                         "Quake II Server Command", HFILL }},
788                 { &hf_quake2_game_client_command_move_chksum,
789                         { "Checksum", "quake2.game.client.command.move.chksum",
790                         FT_UINT8, BASE_HEX, NULL, 0x0,
791                         "Quake II Client Command Move", HFILL }},
792                 { &hf_quake2_game_client_command_move_lframe,
793                         { "Last Frame", "quake2.game.client.command.move.lframe",
794                         FT_UINT32, BASE_DEC, NULL, 0x0,
795                         "Quake II Client Command Move", HFILL }},
796                 { &hf_quake2_game_client_command_move,
797                         { "Bitfield", "quake2.game.client.command.move",
798                         FT_UINT8, BASE_HEX, NULL, 0x0,
799                         "Quake II Client Command Move", HFILL }},
800                 { &hf_quake2_game_client_command_move_bitfield_angles1,
801                         { "Angles (pitch)", "quake2.game.client.command.move.angles",
802                         FT_UINT8, BASE_HEX,
803                         VALS(hf_quake2_game_client_command_move_vals),
804                         CM_ANGLE1, NULL, HFILL }},
805                 { &hf_quake2_game_client_command_move_bitfield_angles2,
806                         { "Angles (yaw)", "quake2.game.client.command.move.angles",
807                         FT_UINT8, BASE_HEX,
808                         VALS(hf_quake2_game_client_command_move_vals),
809                         CM_ANGLE2, NULL, HFILL }},
810                 { &hf_quake2_game_client_command_move_bitfield_angles3,
811                         { "Angles (roll)", "quake2.game.client.command.move.angles",
812                         FT_UINT8, BASE_HEX,
813                         VALS(hf_quake2_game_client_command_move_vals),
814                         CM_ANGLE3, NULL, HFILL }},
815                 { &hf_quake2_game_client_command_move_bitfield_movement_fwd,
816                         { "Movement (fwd)", "quake2.game.client.command.move.movement",
817                         FT_UINT8, BASE_HEX,
818                         VALS(hf_quake2_game_client_command_move_vals),
819                         CM_FORWARD, NULL, HFILL }},
820                 { &hf_quake2_game_client_command_move_bitfield_movement_side,
821                         { "Movement (side)", "quake2.game.client.command.move.movement",
822                         FT_UINT8, BASE_HEX,
823                         VALS(hf_quake2_game_client_command_move_vals),
824                         CM_SIDE, NULL, HFILL }},
825                 { &hf_quake2_game_client_command_move_bitfield_movement_up,
826                         { "Movement (up)", "quake2.game.client.command.move.movement",
827                         FT_UINT8, BASE_HEX,
828                         VALS(hf_quake2_game_client_command_move_vals),
829                         CM_UP, NULL, HFILL }},
830                 { &hf_quake2_game_client_command_move_bitfield_buttons,
831                         { "Buttons", "quake2.game.client.command.move.buttons",
832                         FT_UINT8, BASE_HEX,
833                         VALS(hf_quake2_game_client_command_move_vals),
834                         CM_BUTTONS, NULL, HFILL }},
835                 { &hf_quake2_game_client_command_move_bitfield_impulse,
836                         { "Impulse", "quake2.game.client.command.move.impulse",
837                         FT_UINT8, BASE_HEX,
838                         VALS(hf_quake2_game_client_command_move_vals),
839                         CM_IMPULSE, NULL, HFILL }},
840                 { &hf_quake2_game_client_command_move_msec,
841                         { "Msec", "quake2.game.client.command.move.msec",
842                         FT_UINT8, BASE_DEC, NULL, 0x0,
843                         "Quake II Client Command Move", HFILL }},
844                 { &hf_quake2_game_client_command_move_lightlevel,
845                         { "Lightlevel", "quake2.game.client.command.move.lightlevel",
846                         FT_UINT8, BASE_DEC, NULL, 0x0,
847                         "Quake II Client Command Move", HFILL }}
848         };
849         static gint *ett[] = {
850                 &ett_quake2,
851                 &ett_quake2_connectionless,
852                 &ett_quake2_game,
853                 &ett_quake2_game_seq1,
854                 &ett_quake2_game_seq2,
855                 &ett_quake2_game_clc,
856                 &ett_quake2_game_svc,
857                 &ett_quake2_game_clc_cmd,
858                 &ett_quake2_game_svc_cmd,
859                 &ett_quake2_game_clc_cmd_move_moves,
860                 &ett_quake2_game_clc_cmd_move_bitfield
861         };
862         module_t *quake2_module;
863
864         proto_quake2 = proto_register_protocol("Quake II Network Protocol",
865                                                 "QUAKE2", "quake2");
866         proto_register_field_array(proto_quake2, hf, array_length(hf));
867         proto_register_subtree_array(ett, array_length(ett));
868
869         /* Register a configuration option for port */
870         quake2_module = prefs_register_protocol(proto_quake2,
871                 proto_reg_handoff_quake2);
872         prefs_register_uint_preference(quake2_module, "udp.port",
873                                         "Quake II Server UDP Port",
874                                         "Set the UDP port for the Quake II Server",
875                                         10, &gbl_quake2ServerPort);
876 }
877
878
879 void
880 proto_reg_handoff_quake2(void)
881 {
882         static gboolean Initialized=FALSE;
883         static dissector_handle_t quake2_handle;
884         static guint ServerPort;
885
886         if (!Initialized) {
887                 quake2_handle = create_dissector_handle(dissect_quake2,
888                                 proto_quake2);
889                 data_handle = find_dissector("data");
890                 Initialized=TRUE;
891         } else {
892                 dissector_delete_uint("udp.port", ServerPort, quake2_handle);
893         }
894
895         /* set port for future deletes */
896         ServerPort=gbl_quake2ServerPort;
897
898         dissector_add_uint("udp.port", gbl_quake2ServerPort, quake2_handle);
899 }
900
901