2 * Routines for Quake II packet dissection
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
10 * $Id: packet-quake2.c,v 1.13 2002/08/28 21:00:27 jmayer Exp $
12 * Ethereal - Network traffic analyzer
13 * By Gerald Combs <gerald@ethereal.com>
14 * Copyright 1998 Gerald Combs
16 * Copied from packet-quakeworld.c
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.
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.
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.
38 #include <epan/packet.h>
41 static int proto_quake2 = -1;
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;
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;
83 static dissector_handle_t data_handle;
85 #define PORT_MASTER 27910
86 static unsigned int gbl_quake2ServerPort=PORT_MASTER;
90 dissect_quake2_ConnectionlessPacket(tvbuff_t *tvb, packet_info *pinfo _U_,
91 proto_tree *tree, int direction _U_)
93 proto_tree *cl_tree = NULL;
94 proto_item *cl_item = NULL;
102 marker = tvb_get_ntohl(tvb, 0);
104 cl_item = proto_tree_add_text(tree, tvb,
105 0, -1, "Connectionless");
107 cl_tree = proto_item_add_subtree(
108 cl_item, ett_quake2_connectionless);
112 proto_tree_add_uint(cl_tree, hf_quake2_connectionless_marker,
116 /* all the rest of the packet is just text */
119 maxbufsize = MIN((gint)sizeof(text), tvb_length_remaining(tvb, offset));
120 len = tvb_get_nstringz0(tvb, offset, maxbufsize, text);
122 proto_tree_add_string(cl_tree, hf_quake2_connectionless_text,
123 tvb, offset, len + 1, text);
127 /* we should analyse the result 'text' a bit further */
128 /* for this we need the direction parameter */
131 static const value_string hf_quake2_game_client_command_move_vals[] = {
138 dissect_quake2_client_commands_move(tvbuff_t *tvb, packet_info *pinfo _U_,
141 #define MOVES 3 /* 3 updates per command */
143 /* taken from qcommon.h */
144 #define CM_ANGLE1 (1<<0)
145 #define CM_ANGLE2 (1<<1)
146 #define CM_ANGLE3 (1<<2)
147 #define CM_FORWARD (1<<3)
148 #define CM_SIDE (1<<4)
150 #define CM_BUTTONS (1<<6)
151 #define CM_IMPULSE (1<<7)
153 #define BUTTON_ATTACK 1
155 #define BUTTON_ANY 128
160 enum { OFFSET, VALUE, SIZE };
163 guint16 angles[3][SIZE];
164 gint16 movement[3][SIZE];
165 guint8 buttons[SIZE];
166 guint8 lightlevel[SIZE];
168 guint8 impulse[SIZE];
171 chksum = tvb_get_guint8(tvb, offset);
173 lastframe = tvb_get_letohl(tvb, offset);
176 for (i=0; i < MOVES; i++) {
177 move[i].bits[VALUE] = tvb_get_guint8(tvb, offset);
178 move[i].bits[OFFSET] = offset;
180 if (move[i].bits[VALUE] & CM_ANGLE1) {
181 move[i].angles[0][VALUE] = tvb_get_letohs(tvb, offset);
182 move[i].angles[0][OFFSET] = offset;
185 if (move[i].bits[VALUE] & CM_ANGLE2) {
186 move[i].angles[1][VALUE] = tvb_get_letohs(tvb, offset);
187 move[i].angles[1][OFFSET] = offset;
190 if (move[i].bits[VALUE] & CM_ANGLE3) {
191 move[i].angles[2][VALUE] = tvb_get_letohs(tvb, offset);
192 move[i].angles[2][OFFSET] = offset;
195 if (move[i].bits[VALUE] & CM_FORWARD) {
196 move[i].movement[0][VALUE] = tvb_get_letohs(tvb, offset);
197 move[i].movement[0][OFFSET] = offset;
200 if (move[i].bits[VALUE] & CM_SIDE) {
201 move[i].movement[1][VALUE] = tvb_get_letohs(tvb, offset);
202 move[i].movement[1][OFFSET] = offset;
205 if (move[i].bits[VALUE] & CM_UP) {
206 move[i].movement[2][VALUE] = tvb_get_letohs(tvb, offset);
207 move[i].movement[2][OFFSET] = offset;
210 if (move[i].bits[VALUE] & CM_BUTTONS) {
211 move[i].buttons[VALUE] = tvb_get_guint8(tvb, offset);
212 move[i].buttons[OFFSET] = offset;
215 if (move[i].bits[VALUE] & CM_IMPULSE) {
216 move[i].impulse[VALUE] = tvb_get_guint8(tvb, offset);
217 move[i].impulse[OFFSET] = offset;
221 move[i].msec[VALUE] = tvb_get_guint8(tvb, offset);
222 move[i].msec[OFFSET] = offset;
224 move[i].lightlevel[VALUE] = tvb_get_guint8(tvb, offset);
225 move[i].lightlevel[OFFSET] = offset;
232 proto_tree_add_uint(tree, hf_quake2_game_client_command_move_chksum, tvb,
234 proto_tree_add_uint(tree, hf_quake2_game_client_command_move_lframe, tvb,
237 move[MOVES].bits[OFFSET] = offset;
238 for (i=0; i < MOVES; i++) {
239 proto_item *move_item, *movebits_item, *bit_item;
240 proto_item *sub_tree, *field_tree;
241 #define SHORT2ANGLE(x) ((float)x/65536.0*360.0)
243 move_item = proto_tree_add_text(tree,
245 move[i].bits[OFFSET],
246 move[i+1].bits[OFFSET]-move[i].bits[OFFSET],
248 sub_tree = proto_item_add_subtree(move_item,
249 ett_quake2_game_clc_cmd_move_moves);
252 proto_tree_add_uint(sub_tree, hf_quake2_game_client_command_move,
254 move[i].bits[OFFSET],
256 move[i].bits[VALUE]);
258 proto_tree_add_uint(sub_tree,
259 hf_quake2_game_client_command_move_msec,
260 tvb, move[i].msec[OFFSET], 1, move[i].msec[VALUE]);
261 proto_tree_add_uint(sub_tree,
262 hf_quake2_game_client_command_move_lightlevel,
263 tvb, move[i].lightlevel[OFFSET], 1, move[i].lightlevel[VALUE]);
265 if (move[i].bits[VALUE] == 0) {
266 proto_item_append_text(movebits_item, " (no moves)");
270 field_tree = proto_item_add_subtree(movebits_item,
271 ett_quake2_game_clc_cmd_move_bitfield);
273 if (move[i].bits[VALUE] & CM_ANGLE1) {
274 bit_item = proto_tree_add_uint(field_tree,
275 hf_quake2_game_client_command_move_bitfield_angles1, tvb,
276 move[i].angles[0][OFFSET], 2, move[i].bits[VALUE]);
277 proto_item_append_text(bit_item, " (%d", move[i].angles[0][VALUE]);
278 proto_item_append_text(bit_item, " = %.2f deg)",
279 SHORT2ANGLE(move[i].angles[0][VALUE]));
282 if (move[i].bits[VALUE] & CM_ANGLE2) {
283 bit_item = proto_tree_add_uint(field_tree,
284 hf_quake2_game_client_command_move_bitfield_angles2, tvb,
285 move[i].angles[1][OFFSET], 2, move[i].bits[VALUE]);
286 proto_item_append_text(bit_item, " (%d", move[i].angles[1][VALUE]);
287 proto_item_append_text(bit_item, " = %.2f deg)",
288 SHORT2ANGLE(move[i].angles[1][VALUE]));
290 if (move[i].bits[VALUE] & CM_ANGLE3) {
291 bit_item = proto_tree_add_uint(field_tree,
292 hf_quake2_game_client_command_move_bitfield_angles3, tvb,
293 move[i].angles[2][OFFSET], 2, move[i].bits[VALUE]);
294 proto_item_append_text(bit_item, " (%d", move[i].angles[2][VALUE]);
295 proto_item_append_text(bit_item, " = %.2f deg)",
296 SHORT2ANGLE(move[i].angles[2][VALUE]));
298 if (move[i].bits[VALUE] & CM_FORWARD) {
299 bit_item = proto_tree_add_uint(field_tree,
300 hf_quake2_game_client_command_move_bitfield_movement_fwd, tvb,
301 move[i].movement[0][OFFSET], 2, move[i].bits[VALUE]);
302 proto_item_append_text(bit_item, " (%hd)",
303 move[i].movement[0][VALUE]);
305 if (move[i].bits[VALUE] & CM_SIDE) {
306 bit_item = proto_tree_add_uint(field_tree,
307 hf_quake2_game_client_command_move_bitfield_movement_side, tvb,
308 move[i].movement[1][OFFSET], 2, move[i].bits[VALUE]);
309 proto_item_append_text(bit_item, " (%hd)",
310 move[i].movement[1][VALUE]);
312 if (move[i].bits[VALUE] & CM_UP) {
313 bit_item = proto_tree_add_uint(field_tree,
314 hf_quake2_game_client_command_move_bitfield_movement_up, tvb,
315 move[i].movement[2][OFFSET], 2, move[i].bits[VALUE]);
316 proto_item_append_text(bit_item, " (%hd)",
317 move[i].movement[2][VALUE]);
319 if (move[i].bits[VALUE] & CM_BUTTONS) {
320 bit_item = proto_tree_add_uint(field_tree,
321 hf_quake2_game_client_command_move_bitfield_buttons, tvb,
322 move[i].buttons[OFFSET], 1, move[i].bits[VALUE]);
323 proto_item_append_text(bit_item, " (%d)",
324 move[i].buttons[VALUE]);
325 if (move[i].buttons[VALUE] & BUTTON_ATTACK)
326 proto_item_append_text(bit_item, " (Attack)");
327 if (move[i].buttons[VALUE] & BUTTON_USE)
328 proto_item_append_text(bit_item, " (Use)");
329 if (move[i].buttons[VALUE] & BUTTON_ANY)
330 proto_item_append_text(bit_item, " (Any)");
332 if (move[i].bits[VALUE] & CM_IMPULSE) {
333 bit_item = proto_tree_add_uint(field_tree,
334 hf_quake2_game_client_command_move_bitfield_impulse, tvb,
335 move[i].impulse[OFFSET], 1, move[i].bits[VALUE]);
336 proto_item_append_text(bit_item, " (%d)",
337 move[i].impulse[VALUE]);
346 dissect_quake2_client_commands_uinfo(tvbuff_t *tvb, packet_info *pinfo _U_,
349 proto_item *userinfo_item;
350 #define MAX_MSGLEN 1400 /* qcommon.h */
351 guint8 message[MAX_MSGLEN];
354 len = tvb_get_nstringz0(tvb, 0,
355 (guint) MIN(tvb_reported_length(tvb), sizeof(message)),
358 if (message[len] == '\0')
362 userinfo_item = proto_tree_add_text(tree, tvb, 0, len, "Userinfo: %s", message);
368 dissect_quake2_client_commands_stringcmd(tvbuff_t *tvb, packet_info *pinfo _U_,
371 proto_item *stringcmd_item;
372 guint8 message[MAX_MSGLEN];
375 len = tvb_get_nstringz0(tvb, 0,
376 (guint) MIN(tvb_reported_length(tvb), sizeof(message)),
379 if (message[len] == '\0')
383 stringcmd_item = proto_tree_add_text(tree, tvb, 0, len, "Command: %s",
389 static const value_string names_client_cmd[] = {
392 { CLC_BAD, "clc_bad" },
394 { CLC_NOP, "clc_nop" },
396 { CLC_MOVE, "clc_move" },
397 #define CLC_USERINFO 3
398 { CLC_USERINFO, "clc_userinfo" },
399 #define CLC_STRINGCMD 4
400 { CLC_STRINGCMD, "clc_stringcmd" },
405 dissect_quake2_client_commands(tvbuff_t *tvb, packet_info *pinfo,
408 proto_tree *clc_tree = NULL;
409 tvbuff_t *next_tvb = NULL;
410 guint8 client_cmd_type;
411 guint rest_length = 0;
415 client_cmd_type = tvb_get_guint8(tvb, offset);
418 proto_item *cmd_type_item = proto_tree_add_uint(tree,
419 hf_quake2_game_client_command, tvb, offset, 1,
423 proto_item_append_text(cmd_type_item, " (%s)",
424 val_to_str(client_cmd_type, names_client_cmd, "%u"));
425 clc_tree = proto_item_add_subtree(
426 cmd_type_item, ett_quake2_game_clc_cmd);
431 rest_length = tvb_reported_length(tvb) - offset;
433 next_tvb = tvb_new_subset(tvb, offset,
434 rest_length, rest_length);
439 switch (client_cmd_type) {
446 dissect_quake2_client_commands_move(next_tvb,
451 dissect_quake2_client_commands_uinfo(next_tvb,
456 dissect_quake2_client_commands_stringcmd(next_tvb,
462 offset += rest_length;
463 } while (tvb_reported_length(tvb) - offset > 0);
466 static const value_string names_server_cmd[] = {
469 { SVC_BAD, "svc_bad" },
470 #define SVC_MUZZLEFLASH 1
471 { SVC_MUZZLEFLASH, "svc_muzzleflash" },
472 #define SVC_MUZZLEFLASH2 2
473 { SVC_MUZZLEFLASH2, "svc_muzzleflash2" },
474 #define SVC_TEMP_ENTITY 3
475 { SVC_TEMP_ENTITY, "svc_temp_entity" },
477 { SVC_LAYOUT, "svc_layout" },
478 #define SVC_INVENTORY 5
479 { SVC_INVENTORY, "svc_inventory" },
481 { SVC_NOP, "svc_nop" },
482 #define SVC_DISCONNECT 7
483 { SVC_DISCONNECT, "svc_disconnect" },
484 #define SVC_RECONNECT 8
485 { SVC_RECONNECT, "svc_reconnect" },
487 { SVC_SOUND, "svc_sound" },
489 { SVC_PRINT, "svc_print" },
490 #define SVC_STUFFTEXT 11
491 { SVC_STUFFTEXT, "svc_stufftext" },
492 #define SVC_SERVERDATA 12
493 { SVC_SERVERDATA, "svc_serverdata" },
494 #define SVC_CONFIGSTRING 13
495 { SVC_CONFIGSTRING, "svc_configstring" },
496 #define SVC_SPAWNBASELINE 14
497 { SVC_SPAWNBASELINE, "svc_spawnbaseline" },
498 #define SVC_CENTERPRINT 15
499 { SVC_CENTERPRINT, "svc_centerprint" },
500 #define SVC_DOWNLOAD 16
501 { SVC_DOWNLOAD, "svc_download" },
502 #define SVC_PLAYERINFO 17
503 { SVC_PLAYERINFO, "svc_playerinfo" },
504 #define SVC_PACKETENTITIES 18
505 { SVC_PACKETENTITIES, "svc_packetentities" },
506 #define SVC_DELTAPACKETENTITIES 19
507 { SVC_DELTAPACKETENTITIES, "svc_deltapacketentities" },
509 { SVC_FRAME, "svc_frame" },
514 dissect_quake2_server_commands(tvbuff_t *tvb, packet_info *pinfo,
517 tvbuff_t *next_tvb = NULL;
518 proto_item *cmd_type_item = NULL;
519 guint8 server_cmd_type;
520 guint rest_length = 0;
523 server_cmd_type = tvb_get_guint8(tvb, offset);
526 cmd_type_item = proto_tree_add_uint(tree,
527 hf_quake2_game_server_command, tvb, offset, 1, server_cmd_type);
530 proto_item_append_text(cmd_type_item, " (%s)",
531 val_to_str(server_cmd_type, names_server_cmd, "%u"));
536 rest_length = tvb_reported_length(tvb) - offset;
538 next_tvb = tvb_new_subset(tvb, offset, rest_length, rest_length);
543 switch (server_cmd_type) {
546 case SVC_MUZZLEFLASH:
548 case SVC_MUZZLEFLASH2:
550 case SVC_TEMP_ENTITY:
568 case SVC_CONFIGSTRING:
570 case SVC_SPAWNBASELINE:
572 case SVC_CENTERPRINT:
578 case SVC_PACKETENTITIES:
580 case SVC_DELTAPACKETENTITIES:
588 call_dissector(data_handle, next_tvb, pinfo, tree);
592 static const value_string names_reliable[] = {
593 { 0, "Non Reliable" },
599 static const value_string names_direction[] = {
601 { DIR_C2S, "Client to Server" },
603 { DIR_S2C, "Server to Client" },
609 dissect_quake2_GamePacket(tvbuff_t *tvb, packet_info *pinfo,
610 proto_tree *tree, int direction)
612 proto_tree *game_tree = NULL;
613 proto_item *game_item = NULL;
621 direction = (pinfo->destport == gbl_quake2ServerPort) ?
625 game_item = proto_tree_add_text(tree, tvb,
628 game_tree = proto_item_add_subtree(
629 game_item, ett_quake2_game);
634 seq1 = tvb_get_letohl(tvb, offset);
635 rel1 = seq1 & 0x80000000 ? 1 : 0;
638 proto_item *seq1_item = proto_tree_add_text(game_tree,
639 tvb, offset, 4, "Current Sequence: %u (%s)",
640 seq1, val_to_str(rel1,names_reliable,"%u"));
642 proto_tree *seq1_tree = proto_item_add_subtree(
643 seq1_item, ett_quake2_game_seq1);
644 proto_tree_add_uint(seq1_tree, hf_quake2_game_seq1,
645 tvb, offset, 4, seq1);
646 proto_tree_add_boolean(seq1_tree, hf_quake2_game_rel1,
647 tvb, offset+3, 1, rel1);
652 seq2 = tvb_get_letohl(tvb, offset);
653 rel2 = seq2 & 0x80000000 ? 1 : 0;
656 proto_item *seq2_item = proto_tree_add_text(game_tree,
657 tvb, offset, 4, "Acknowledge Sequence: %u (%s)",
658 seq2, val_to_str(rel2,names_reliable,"%u"));;
660 proto_tree *seq2_tree = proto_item_add_subtree(
661 seq2_item, ett_quake2_game_seq2);
662 proto_tree_add_uint(seq2_tree, hf_quake2_game_seq2,
663 tvb, offset, 4, seq2);
664 proto_tree_add_boolean(seq2_tree, hf_quake2_game_rel2,
665 tvb, offset+3, 1, rel2);
670 if (direction == DIR_C2S) {
671 /* client to server */
672 guint16 qport = tvb_get_letohs(tvb, offset);
674 proto_tree_add_uint(game_tree, hf_quake2_game_qport,
675 tvb, offset, 2, qport);
680 /* all the rest is pure game data */
681 rest_length = tvb_reported_length(tvb) - offset;
684 tvb_new_subset(tvb, offset, rest_length , rest_length);
686 if (direction == DIR_C2S) {
687 proto_item *c_item = NULL;
688 proto_tree *c_tree = NULL;
690 c_item = proto_tree_add_text(game_tree, next_tvb,
691 0, -1, "Client Commands");
693 c_tree = proto_item_add_subtree(
694 c_item, ett_quake2_game_clc);
697 dissect_quake2_client_commands(next_tvb, pinfo, c_tree);
700 proto_item *c_item = NULL;
701 proto_tree *c_tree = NULL;
703 c_item = proto_tree_add_text(game_tree, next_tvb,
704 0, -1, "Server Commands");
706 c_tree = proto_item_add_subtree(
707 c_item, ett_quake2_game_svc);
710 dissect_quake2_server_commands(next_tvb, pinfo, c_tree);
717 dissect_quake2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
719 proto_tree *quake2_tree = NULL;
720 proto_item *quake2_item = NULL;
723 direction = (pinfo->destport == gbl_quake2ServerPort) ?
726 if (check_col(pinfo->cinfo, COL_PROTOCOL))
727 col_set_str(pinfo->cinfo, COL_PROTOCOL, "QUAKE2");
728 if (check_col(pinfo->cinfo, COL_INFO))
729 col_set_str(pinfo->cinfo, COL_INFO, val_to_str(direction,
730 names_direction, "%u"));
733 quake2_item = proto_tree_add_item(tree, proto_quake2,
736 quake2_tree = proto_item_add_subtree(
737 quake2_item, ett_quake2);
739 proto_tree_add_uint_format(quake2_tree,
740 direction == DIR_S2C ?
744 "Direction: %s", val_to_str(direction, names_direction, "%u"));
748 if (tvb_get_ntohl(tvb, 0) == 0xffffffff) {
749 if (check_col(pinfo->cinfo, COL_INFO)) {
750 col_append_str(pinfo->cinfo, COL_INFO, " Connectionless");
753 proto_tree_add_uint_format(quake2_tree,
754 hf_quake2_connectionless,
756 "Type: Connectionless");
757 dissect_quake2_ConnectionlessPacket(
758 tvb, pinfo, quake2_tree, direction);
761 if (check_col(pinfo->cinfo, COL_INFO)) {
762 col_append_str(pinfo->cinfo, COL_INFO, " Game");
765 proto_tree_add_uint_format(quake2_tree,
769 dissect_quake2_GamePacket(
770 tvb, pinfo, quake2_tree, direction);
776 proto_reg_handoff_quake2(void)
778 static int Initialized=FALSE;
779 static dissector_handle_t quake2_handle;
780 static int ServerPort=0;
783 quake2_handle = create_dissector_handle(dissect_quake2,
787 dissector_delete("udp.port", ServerPort, quake2_handle);
790 /* set port for future deletes */
791 ServerPort=gbl_quake2ServerPort;
793 dissector_add("udp.port", gbl_quake2ServerPort, quake2_handle);
794 data_handle = find_dissector("data");
799 proto_register_quake2(void)
801 static hf_register_info hf[] = {
803 { "Client to Server", "quake2.c2s",
804 FT_UINT32, BASE_DEC, NULL, 0x0,
805 "Client to Server", HFILL }},
807 { "Server to Client", "quake2.s2c",
808 FT_UINT32, BASE_DEC, NULL, 0x0,
809 "Server to Client", HFILL }},
810 { &hf_quake2_connectionless,
811 { "Connectionless", "quake2.connectionless",
812 FT_UINT32, BASE_DEC, NULL, 0x0,
813 "Connectionless", HFILL }},
815 { "Game", "quake2.game",
816 FT_UINT32, BASE_DEC, NULL, 0x0,
818 { &hf_quake2_connectionless_marker,
819 { "Marker", "quake2.connectionless.marker",
820 FT_UINT32, BASE_HEX, NULL, 0x0,
822 { &hf_quake2_connectionless_text,
823 { "Text", "quake2.connectionless.text",
824 FT_STRING, BASE_DEC, NULL, 0x0,
826 { &hf_quake2_game_seq1,
827 { "Sequence Number", "quake2.game.seq1",
828 FT_UINT32, BASE_DEC, NULL, 0x0,
829 "Sequence number of the current packet", HFILL }},
830 { &hf_quake2_game_rel1,
831 { "Reliable", "quake2.game.rel1",
832 FT_BOOLEAN, BASE_DEC, NULL, 0x0,
833 "Packet is reliable and may be retransmitted", HFILL }},
834 { &hf_quake2_game_seq2,
835 { "Sequence Number", "quake2.game.seq2",
836 FT_UINT32, BASE_DEC, NULL, 0x0,
837 "Sequence number of the last received packet", HFILL }},
838 { &hf_quake2_game_rel2,
839 { "Reliable", "quake2.game.rel2",
840 FT_BOOLEAN, BASE_DEC, NULL, 0x0,
841 "Packet was reliable and may be retransmitted", HFILL }},
842 { &hf_quake2_game_qport,
843 { "QPort", "quake2.game.qport",
844 FT_UINT32, BASE_DEC, NULL, 0x0,
845 "Quake II Client Port", HFILL }},
846 { &hf_quake2_game_client_command,
847 { "Client Command Type", "quake2.game.client.command",
848 FT_UINT8, BASE_DEC, NULL, 0x0,
849 "Quake II Client Command", HFILL }},
850 { &hf_quake2_game_server_command,
851 { "Server Command", "quake2.game.server.command",
852 FT_UINT8, BASE_DEC, NULL, 0x0,
853 "Quake II Server Command", HFILL }},
854 { &hf_quake2_game_client_command_move_chksum,
855 { "Checksum", "quake2.game.client.command.move.chksum",
856 FT_UINT8, BASE_HEX, NULL, 0x0,
857 "Quake II Client Command Move", HFILL }},
858 { &hf_quake2_game_client_command_move_lframe,
859 { "Last Frame", "quake2.game.client.command.move.lframe",
860 FT_UINT32, BASE_DEC, NULL, 0x0,
861 "Quake II Client Command Move", HFILL }},
862 { &hf_quake2_game_client_command_move,
863 { "Bitfield", "quake2.game.client.command.move",
864 FT_UINT8, BASE_HEX, NULL, 0x0,
865 "Quake II Client Command Move", HFILL }},
866 { &hf_quake2_game_client_command_move_bitfield_angles1,
867 { "Angles (pitch)", "quake2.game.client.command.move.angles",
869 VALS(hf_quake2_game_client_command_move_vals),
870 CM_ANGLE1, "", HFILL }},
871 { &hf_quake2_game_client_command_move_bitfield_angles2,
872 { "Angles (yaw)", "quake2.game.client.command.move.angles",
874 VALS(hf_quake2_game_client_command_move_vals),
875 CM_ANGLE2, "", HFILL }},
876 { &hf_quake2_game_client_command_move_bitfield_angles3,
877 { "Angles (roll)", "quake2.game.client.command.move.angles",
879 VALS(hf_quake2_game_client_command_move_vals),
880 CM_ANGLE3, "", HFILL }},
881 { &hf_quake2_game_client_command_move_bitfield_movement_fwd,
882 { "Movement (fwd)", "quake2.game.client.command.move.movement",
884 VALS(hf_quake2_game_client_command_move_vals),
885 CM_FORWARD, "", HFILL }},
886 { &hf_quake2_game_client_command_move_bitfield_movement_side,
887 { "Movement (side)", "quake2.game.client.command.move.movement",
889 VALS(hf_quake2_game_client_command_move_vals),
890 CM_SIDE, "", HFILL }},
891 { &hf_quake2_game_client_command_move_bitfield_movement_up,
892 { "Movement (up)", "quake2.game.client.command.move.movement",
894 VALS(hf_quake2_game_client_command_move_vals),
896 { &hf_quake2_game_client_command_move_bitfield_buttons,
897 { "Buttons", "quake2.game.client.command.move.buttons",
899 VALS(hf_quake2_game_client_command_move_vals),
900 CM_BUTTONS, "", HFILL }},
901 { &hf_quake2_game_client_command_move_bitfield_impulse,
902 { "Impulse", "quake2.game.client.command.move.impulse",
904 VALS(hf_quake2_game_client_command_move_vals),
905 CM_IMPULSE, "", HFILL }},
906 { &hf_quake2_game_client_command_move_msec,
907 { "Msec", "quake2.game.client.command.move.msec",
908 FT_UINT8, BASE_DEC, NULL, 0x0,
909 "Quake II Client Command Move", HFILL }},
910 { &hf_quake2_game_client_command_move_lightlevel,
911 { "Lightlevel", "quake2.game.client.command.move.lightlevel",
912 FT_UINT8, BASE_DEC, NULL, 0x0,
913 "Quake II Client Command Move", HFILL }}
915 static gint *ett[] = {
917 &ett_quake2_connectionless,
919 &ett_quake2_game_seq1,
920 &ett_quake2_game_seq2,
921 &ett_quake2_game_clc,
922 &ett_quake2_game_svc,
923 &ett_quake2_game_clc_cmd,
924 &ett_quake2_game_svc_cmd,
925 &ett_quake2_game_clc_cmd_move_moves,
926 &ett_quake2_game_clc_cmd_move_bitfield
928 module_t *quake2_module;
930 proto_quake2 = proto_register_protocol("Quake II Network Protocol",
932 proto_register_field_array(proto_quake2, hf, array_length(hf));
933 proto_register_subtree_array(ett, array_length(ett));
935 /* Register a configuration option for port */
936 quake2_module = prefs_register_protocol(proto_quake2,
937 proto_reg_handoff_quake2);
938 prefs_register_uint_preference(quake2_module, "udp.port",
939 "Quake II Server UDP Port",
940 "Set the UDP port for the Quake II Server",
941 10, &gbl_quake2ServerPort);