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 * Wireshark - Network traffic analyzer
11 * By Gerald Combs <gerald@wireshark.org>
12 * Copyright 1998 Gerald Combs
14 * Copied from packet-quakeworld.c
16 * SPDX-License-Identifier: GPL-2.0-or-later
21 #include <epan/packet.h>
22 #include <epan/prefs.h>
24 void proto_register_quake2(void);
25 void proto_reg_handoff_quake2(void);
27 static dissector_handle_t quake2_handle
;
29 static int proto_quake2
;
31 static int hf_quake2_s2c
;
32 static int hf_quake2_c2s
;
33 static int hf_quake2_connectionless
;
34 static int hf_quake2_game
;
35 static int hf_quake2_userinfo
;
36 static int hf_quake2_command
;
37 static int hf_quake2_connectionless_marker
;
38 static int hf_quake2_connectionless_text
;
39 static int hf_quake2_game_seq1
;
40 static int hf_quake2_game_rel1
;
41 static int hf_quake2_game_seq2
;
42 static int hf_quake2_game_rel2
;
43 static int hf_quake2_game_qport
;
44 static int hf_quake2_game_client_command
;
45 static int hf_quake2_game_server_command
;
46 static int hf_quake2_game_client_command_move
;
47 static int hf_quake2_game_client_command_move_chksum
;
48 static int hf_quake2_game_client_command_move_lframe
;
49 static int hf_quake2_game_client_command_move_bitfield_angles1
;
50 static int hf_quake2_game_client_command_move_bitfield_angles2
;
51 static int hf_quake2_game_client_command_move_bitfield_angles3
;
52 static int hf_quake2_game_client_command_move_bitfield_movement_fwd
;
53 static int hf_quake2_game_client_command_move_bitfield_movement_side
;
54 static int hf_quake2_game_client_command_move_bitfield_movement_up
;
55 static int hf_quake2_game_client_command_move_bitfield_buttons
;
56 static int hf_quake2_game_client_command_move_bitfield_impulse
;
57 static int hf_quake2_game_client_command_move_msec
;
58 static int hf_quake2_game_client_command_move_lightlevel
;
60 static int ett_quake2
;
61 static int ett_quake2_connectionless
;
62 static int ett_quake2_game
;
63 static int ett_quake2_game_seq1
;
64 static int ett_quake2_game_seq2
;
65 static int ett_quake2_game_clc
;
66 static int ett_quake2_game_svc
;
67 static int ett_quake2_game_clc_cmd
;
68 static int ett_quake2_game_svc_cmd
;
69 static int ett_quake2_game_clc_cmd_move_bitfield
;
70 static int ett_quake2_game_clc_cmd_move_moves
;
73 #define PORT_MASTER 27910 /* Not IANA registered */
74 static range_t
*gbl_quake2ServerPorts
;
78 dissect_quake2_ConnectionlessPacket(tvbuff_t
*tvb
, packet_info
*pinfo _U_
,
79 proto_tree
*tree
, int direction _U_
)
87 marker
= tvb_get_ntohl(tvb
, 0);
88 cl_tree
= proto_tree_add_subtree(tree
, tvb
,
89 0, -1, ett_quake2_connectionless
, NULL
, "Connectionless");
90 proto_tree_add_uint(cl_tree
, hf_quake2_connectionless_marker
,
93 /* all the rest of the packet is just text */
96 len
= tvb_captured_length_remaining(tvb
, offset
);
97 proto_tree_add_item(cl_tree
, hf_quake2_connectionless_text
,
98 tvb
, offset
, len
, ENC_ASCII
);
101 /* we should analyse the result 'text' a bit further */
102 /* for this we need the direction parameter */
105 static const value_string hf_quake2_game_client_command_move_vals
[] = {
112 dissect_quake2_client_commands_move(tvbuff_t
*tvb
, packet_info
*pinfo _U_
,
115 #define MOVES 3 /* 3 updates per command */
117 /* taken from qcommon.h */
118 #define CM_ANGLE1 (1<<0)
119 #define CM_ANGLE2 (1<<1)
120 #define CM_ANGLE3 (1<<2)
121 #define CM_FORWARD (1<<3)
122 #define CM_SIDE (1<<4)
124 #define CM_BUTTONS (1<<6)
125 #define CM_IMPULSE (1<<7)
127 #define BUTTON_ATTACK 1
129 #define BUTTON_ANY 128
133 enum { Q_OFFSET
, Q_VALUE
, Q_SIZE
};
135 uint8_t bits
[Q_SIZE
];
136 uint16_t angles
[3][Q_SIZE
];
137 int16_t movement
[3][Q_SIZE
];
138 uint8_t buttons
[Q_SIZE
];
139 uint8_t lightlevel
[Q_SIZE
];
140 uint8_t msec
[Q_SIZE
];
141 uint8_t impulse
[Q_SIZE
];
145 lastframe
= tvb_get_letohl(tvb
, offset
);
148 for (i
=0; i
< MOVES
; i
++) {
149 move
[i
].bits
[Q_VALUE
] = tvb_get_uint8(tvb
, offset
);
150 move
[i
].bits
[Q_OFFSET
] = offset
;
152 if (move
[i
].bits
[Q_VALUE
] & CM_ANGLE1
) {
153 move
[i
].angles
[0][Q_VALUE
] = tvb_get_letohs(tvb
, offset
);
154 move
[i
].angles
[0][Q_OFFSET
] = offset
;
157 if (move
[i
].bits
[Q_VALUE
] & CM_ANGLE2
) {
158 move
[i
].angles
[1][Q_VALUE
] = tvb_get_letohs(tvb
, offset
);
159 move
[i
].angles
[1][Q_OFFSET
] = offset
;
162 if (move
[i
].bits
[Q_VALUE
] & CM_ANGLE3
) {
163 move
[i
].angles
[2][Q_VALUE
] = tvb_get_letohs(tvb
, offset
);
164 move
[i
].angles
[2][Q_OFFSET
] = offset
;
167 if (move
[i
].bits
[Q_VALUE
] & CM_FORWARD
) {
168 move
[i
].movement
[0][Q_VALUE
] = tvb_get_letohs(tvb
, offset
);
169 move
[i
].movement
[0][Q_OFFSET
] = offset
;
172 if (move
[i
].bits
[Q_VALUE
] & CM_SIDE
) {
173 move
[i
].movement
[1][Q_VALUE
] = tvb_get_letohs(tvb
, offset
);
174 move
[i
].movement
[1][Q_OFFSET
] = offset
;
177 if (move
[i
].bits
[Q_VALUE
] & CM_UP
) {
178 move
[i
].movement
[2][Q_VALUE
] = tvb_get_letohs(tvb
, offset
);
179 move
[i
].movement
[2][Q_OFFSET
] = offset
;
182 if (move
[i
].bits
[Q_VALUE
] & CM_BUTTONS
) {
183 move
[i
].buttons
[Q_VALUE
] = tvb_get_uint8(tvb
, offset
);
184 move
[i
].buttons
[Q_OFFSET
] = offset
;
187 if (move
[i
].bits
[Q_VALUE
] & CM_IMPULSE
) {
188 move
[i
].impulse
[Q_VALUE
] = tvb_get_uint8(tvb
, offset
);
189 move
[i
].impulse
[Q_OFFSET
] = offset
;
193 move
[i
].msec
[Q_VALUE
] = tvb_get_uint8(tvb
, offset
);
194 move
[i
].msec
[Q_OFFSET
] = offset
;
196 move
[i
].lightlevel
[Q_VALUE
] = tvb_get_uint8(tvb
, offset
);
197 move
[i
].lightlevel
[Q_OFFSET
] = offset
;
204 proto_tree_add_checksum(tree
, tvb
, 0, hf_quake2_game_client_command_move_chksum
, -1, NULL
, pinfo
, 0, ENC_BIG_ENDIAN
, PROTO_CHECKSUM_NO_FLAGS
);
205 proto_tree_add_uint(tree
, hf_quake2_game_client_command_move_lframe
, tvb
,
208 move
[MOVES
].bits
[Q_OFFSET
] = offset
;
209 for (i
=0; i
< MOVES
; i
++) {
210 proto_item
*movebits_item
, *bit_item
;
211 proto_item
*sub_tree
, *field_tree
;
212 #define SHORT2ANGLE(x) ((float)x/65536.0*360.0)
214 sub_tree
= proto_tree_add_subtree_format(tree
,
216 move
[i
].bits
[Q_OFFSET
],
217 move
[i
+1].bits
[Q_OFFSET
]-move
[i
].bits
[Q_OFFSET
],
218 ett_quake2_game_clc_cmd_move_moves
, NULL
, "Move %u", i
+1);
221 proto_tree_add_uint(sub_tree
, hf_quake2_game_client_command_move
,
223 move
[i
].bits
[Q_OFFSET
],
225 move
[i
].bits
[Q_VALUE
]);
227 proto_tree_add_uint(sub_tree
,
228 hf_quake2_game_client_command_move_msec
,
229 tvb
, move
[i
].msec
[Q_OFFSET
], 1, move
[i
].msec
[Q_VALUE
]);
230 proto_tree_add_uint(sub_tree
,
231 hf_quake2_game_client_command_move_lightlevel
,
232 tvb
, move
[i
].lightlevel
[Q_OFFSET
], 1, move
[i
].lightlevel
[Q_VALUE
]);
234 if (move
[i
].bits
[Q_VALUE
] == 0) {
235 proto_item_append_text(movebits_item
, " (no moves)");
239 field_tree
= proto_item_add_subtree(movebits_item
,
240 ett_quake2_game_clc_cmd_move_bitfield
);
242 if (move
[i
].bits
[Q_VALUE
] & CM_ANGLE1
) {
243 bit_item
= proto_tree_add_uint(field_tree
,
244 hf_quake2_game_client_command_move_bitfield_angles1
, tvb
,
245 move
[i
].angles
[0][Q_OFFSET
], 2, move
[i
].bits
[Q_VALUE
]);
246 proto_item_append_text(bit_item
, " (%d", move
[i
].angles
[0][Q_VALUE
]);
247 proto_item_append_text(bit_item
, " = %.2f deg)",
248 SHORT2ANGLE(move
[i
].angles
[0][Q_VALUE
]));
251 if (move
[i
].bits
[Q_VALUE
] & CM_ANGLE2
) {
252 bit_item
= proto_tree_add_uint(field_tree
,
253 hf_quake2_game_client_command_move_bitfield_angles2
, tvb
,
254 move
[i
].angles
[1][Q_OFFSET
], 2, move
[i
].bits
[Q_VALUE
]);
255 proto_item_append_text(bit_item
, " (%d", move
[i
].angles
[1][Q_VALUE
]);
256 proto_item_append_text(bit_item
, " = %.2f deg)",
257 SHORT2ANGLE(move
[i
].angles
[1][Q_VALUE
]));
259 if (move
[i
].bits
[Q_VALUE
] & CM_ANGLE3
) {
260 bit_item
= proto_tree_add_uint(field_tree
,
261 hf_quake2_game_client_command_move_bitfield_angles3
, tvb
,
262 move
[i
].angles
[2][Q_OFFSET
], 2, move
[i
].bits
[Q_VALUE
]);
263 proto_item_append_text(bit_item
, " (%d", move
[i
].angles
[2][Q_VALUE
]);
264 proto_item_append_text(bit_item
, " = %.2f deg)",
265 SHORT2ANGLE(move
[i
].angles
[2][Q_VALUE
]));
267 if (move
[i
].bits
[Q_VALUE
] & CM_FORWARD
) {
268 bit_item
= proto_tree_add_uint(field_tree
,
269 hf_quake2_game_client_command_move_bitfield_movement_fwd
, tvb
,
270 move
[i
].movement
[0][Q_OFFSET
], 2, move
[i
].bits
[Q_VALUE
]);
271 proto_item_append_text(bit_item
, " (%hd)",
272 move
[i
].movement
[0][Q_VALUE
]);
274 if (move
[i
].bits
[Q_VALUE
] & CM_SIDE
) {
275 bit_item
= proto_tree_add_uint(field_tree
,
276 hf_quake2_game_client_command_move_bitfield_movement_side
, tvb
,
277 move
[i
].movement
[1][Q_OFFSET
], 2, move
[i
].bits
[Q_VALUE
]);
278 proto_item_append_text(bit_item
, " (%hd)",
279 move
[i
].movement
[1][Q_VALUE
]);
281 if (move
[i
].bits
[Q_VALUE
] & CM_UP
) {
282 bit_item
= proto_tree_add_uint(field_tree
,
283 hf_quake2_game_client_command_move_bitfield_movement_up
, tvb
,
284 move
[i
].movement
[2][Q_OFFSET
], 2, move
[i
].bits
[Q_VALUE
]);
285 proto_item_append_text(bit_item
, " (%hd)",
286 move
[i
].movement
[2][Q_VALUE
]);
288 if (move
[i
].bits
[Q_VALUE
] & CM_BUTTONS
) {
289 bit_item
= proto_tree_add_uint(field_tree
,
290 hf_quake2_game_client_command_move_bitfield_buttons
, tvb
,
291 move
[i
].buttons
[Q_OFFSET
], 1, move
[i
].bits
[Q_VALUE
]);
292 proto_item_append_text(bit_item
, " (%d)",
293 move
[i
].buttons
[Q_VALUE
]);
294 if (move
[i
].buttons
[Q_VALUE
] & BUTTON_ATTACK
)
295 proto_item_append_text(bit_item
, " (Attack)");
296 if (move
[i
].buttons
[Q_VALUE
] & BUTTON_USE
)
297 proto_item_append_text(bit_item
, " (Use)");
298 if (move
[i
].buttons
[Q_VALUE
] & BUTTON_ANY
)
299 proto_item_append_text(bit_item
, " (Any)");
301 if (move
[i
].bits
[Q_VALUE
] & CM_IMPULSE
) {
302 bit_item
= proto_tree_add_uint(field_tree
,
303 hf_quake2_game_client_command_move_bitfield_impulse
, tvb
,
304 move
[i
].impulse
[Q_OFFSET
], 1, move
[i
].bits
[Q_VALUE
]);
305 proto_item_append_text(bit_item
, " (%d)",
306 move
[i
].impulse
[Q_VALUE
]);
315 dissect_quake2_client_commands_uinfo(tvbuff_t
*tvb
, packet_info
*pinfo _U_
,
320 len
= tvb_strsize(tvb
, 0);
322 proto_tree_add_item(tree
, hf_quake2_userinfo
, tvb
, 0, len
, ENC_NA
|ENC_ASCII
);
328 dissect_quake2_client_commands_stringcmd(tvbuff_t
*tvb
, packet_info
*pinfo _U_
,
333 len
= tvb_strsize(tvb
, 0);
335 proto_tree_add_item(tree
, hf_quake2_command
, tvb
, 0, len
, ENC_NA
|ENC_ASCII
);
340 static const value_string names_client_cmd
[] = {
343 { CLC_BAD
, "clc_bad" },
345 { CLC_NOP
, "clc_nop" },
347 { CLC_MOVE
, "clc_move" },
348 #define CLC_USERINFO 3
349 { CLC_USERINFO
, "clc_userinfo" },
350 #define CLC_STRINGCMD 4
351 { CLC_STRINGCMD
, "clc_stringcmd" },
356 dissect_quake2_client_commands(tvbuff_t
*tvb
, packet_info
*pinfo
,
359 proto_tree
*clc_tree
= NULL
;
360 tvbuff_t
*next_tvb
= NULL
;
361 uint8_t client_cmd_type
;
362 proto_item
*cmd_type_item
;
363 unsigned rest_length
= 0;
367 client_cmd_type
= tvb_get_uint8(tvb
, offset
);
369 cmd_type_item
= proto_tree_add_uint(tree
,
370 hf_quake2_game_client_command
, tvb
, offset
, 1,
373 proto_item_append_text(cmd_type_item
, " (%s)",
374 val_to_str(client_cmd_type
, names_client_cmd
, "%u"));
375 clc_tree
= proto_item_add_subtree(cmd_type_item
, ett_quake2_game_clc_cmd
);
378 rest_length
= tvb_reported_length(tvb
) - offset
;
380 next_tvb
= tvb_new_subset_remaining(tvb
, offset
);
385 switch (client_cmd_type
) {
392 dissect_quake2_client_commands_move(next_tvb
,
397 dissect_quake2_client_commands_uinfo(next_tvb
,
402 dissect_quake2_client_commands_stringcmd(next_tvb
,
408 offset
+= rest_length
;
409 } while (tvb_reported_length(tvb
) - offset
> 0);
412 static const value_string names_server_cmd
[] = {
415 { SVC_BAD
, "svc_bad" },
416 #define SVC_MUZZLEFLASH 1
417 { SVC_MUZZLEFLASH
, "svc_muzzleflash" },
418 #define SVC_MUZZLEFLASH2 2
419 { SVC_MUZZLEFLASH2
, "svc_muzzleflash2" },
420 #define SVC_TEMP_ENTITY 3
421 { SVC_TEMP_ENTITY
, "svc_temp_entity" },
423 { SVC_LAYOUT
, "svc_layout" },
424 #define SVC_INVENTORY 5
425 { SVC_INVENTORY
, "svc_inventory" },
427 { SVC_NOP
, "svc_nop" },
428 #define SVC_DISCONNECT 7
429 { SVC_DISCONNECT
, "svc_disconnect" },
430 #define SVC_RECONNECT 8
431 { SVC_RECONNECT
, "svc_reconnect" },
433 { SVC_SOUND
, "svc_sound" },
435 { SVC_PRINT
, "svc_print" },
436 #define SVC_STUFFTEXT 11
437 { SVC_STUFFTEXT
, "svc_stufftext" },
438 #define SVC_SERVERDATA 12
439 { SVC_SERVERDATA
, "svc_serverdata" },
440 #define SVC_CONFIGSTRING 13
441 { SVC_CONFIGSTRING
, "svc_configstring" },
442 #define SVC_SPAWNBASELINE 14
443 { SVC_SPAWNBASELINE
, "svc_spawnbaseline" },
444 #define SVC_CENTERPRINT 15
445 { SVC_CENTERPRINT
, "svc_centerprint" },
446 #define SVC_DOWNLOAD 16
447 { SVC_DOWNLOAD
, "svc_download" },
448 #define SVC_PLAYERINFO 17
449 { SVC_PLAYERINFO
, "svc_playerinfo" },
450 #define SVC_PACKETENTITIES 18
451 { SVC_PACKETENTITIES
, "svc_packetentities" },
452 #define SVC_DELTAPACKETENTITIES 19
453 { SVC_DELTAPACKETENTITIES
, "svc_deltapacketentities" },
455 { SVC_FRAME
, "svc_frame" },
460 dissect_quake2_server_commands(tvbuff_t
*tvb
, packet_info
*pinfo
,
463 tvbuff_t
*next_tvb
= NULL
;
464 uint8_t server_cmd_type
;
465 proto_item
*cmd_type_item
;
466 unsigned rest_length
= 0;
469 server_cmd_type
= tvb_get_uint8(tvb
, offset
);
471 cmd_type_item
= proto_tree_add_uint(tree
,
472 hf_quake2_game_server_command
, tvb
, offset
, 1, server_cmd_type
);
474 proto_item_append_text(cmd_type_item
, " (%s)",
475 val_to_str(server_cmd_type
, names_server_cmd
, "%u"));
478 rest_length
= tvb_reported_length(tvb
) - offset
;
480 next_tvb
= tvb_new_subset_remaining(tvb
, offset
);
485 switch (server_cmd_type
) {
488 case SVC_MUZZLEFLASH
:
490 case SVC_MUZZLEFLASH2
:
492 case SVC_TEMP_ENTITY
:
510 case SVC_CONFIGSTRING
:
512 case SVC_SPAWNBASELINE
:
514 case SVC_CENTERPRINT
:
520 case SVC_PACKETENTITIES
:
522 case SVC_DELTAPACKETENTITIES
:
530 call_data_dissector(next_tvb
, pinfo
, tree
);
534 static const value_string names_reliable
[] = {
535 { 0, "Non Reliable" },
540 static const value_string names_direction
[] = {
542 { DIR_C2S
, "Client to Server" },
544 { DIR_S2C
, "Server to Client" },
550 dissect_quake2_GamePacket(tvbuff_t
*tvb
, packet_info
*pinfo
,
551 proto_tree
*tree
, int direction
)
553 proto_tree
*game_tree
;
559 unsigned rest_length
;
561 direction
= value_is_in_range(gbl_quake2ServerPorts
, pinfo
->destport
) ?
564 game_tree
= proto_tree_add_subtree(tree
, tvb
,
565 0, -1, ett_quake2_game
, NULL
, "Game");
569 seq1
= tvb_get_letohl(tvb
, offset
);
570 rel1
= seq1
& 0x80000000 ? 1 : 0;
573 proto_tree
*seq1_tree
= proto_tree_add_subtree_format(game_tree
,
574 tvb
, offset
, 4, ett_quake2_game_seq1
, NULL
, "Current Sequence: %u (%s)",
575 seq1
, val_to_str(rel1
,names_reliable
,"%u"));
576 proto_tree_add_uint(seq1_tree
, hf_quake2_game_seq1
,
577 tvb
, offset
, 4, seq1
);
578 proto_tree_add_boolean(seq1_tree
, hf_quake2_game_rel1
,
579 tvb
, offset
+3, 1, rel1
);
583 seq2
= tvb_get_letohl(tvb
, offset
);
584 rel2
= seq2
& 0x80000000 ? 1 : 0;
587 proto_tree
*seq2_tree
= proto_tree_add_subtree_format(game_tree
,
588 tvb
, offset
, 4, ett_quake2_game_seq2
, NULL
, "Acknowledge Sequence: %u (%s)",
589 seq2
, val_to_str(rel2
,names_reliable
,"%u"));
590 proto_tree_add_uint(seq2_tree
, hf_quake2_game_seq2
,
591 tvb
, offset
, 4, seq2
);
592 proto_tree_add_boolean(seq2_tree
, hf_quake2_game_rel2
,
593 tvb
, offset
+3, 1, rel2
);
597 if (direction
== DIR_C2S
) {
598 /* client to server */
599 uint16_t qport
= tvb_get_letohs(tvb
, offset
);
601 proto_tree_add_uint(game_tree
, hf_quake2_game_qport
,
602 tvb
, offset
, 2, qport
);
607 /* all the rest is pure game data */
608 rest_length
= tvb_reported_length(tvb
) - offset
;
611 tvb_new_subset_remaining(tvb
, offset
);
614 if (direction
== DIR_C2S
) {
615 c_tree
= proto_tree_add_subtree(game_tree
, next_tvb
,
616 0, -1, ett_quake2_game_clc
, NULL
, "Client Commands");
617 dissect_quake2_client_commands(next_tvb
, pinfo
, c_tree
);
620 c_tree
= proto_tree_add_subtree(game_tree
, next_tvb
,
621 0, -1, ett_quake2_game_svc
, NULL
, "Server Commands");
622 dissect_quake2_server_commands(next_tvb
, pinfo
, c_tree
);
629 dissect_quake2(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data _U_
)
631 proto_tree
*quake2_tree
= NULL
;
634 direction
= value_is_in_range(gbl_quake2ServerPorts
, pinfo
->destport
) ?
637 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "QUAKE2");
638 col_add_str(pinfo
->cinfo
, COL_INFO
, val_to_str(direction
,
639 names_direction
, "%u"));
642 proto_item
*quake2_item
;
643 quake2_item
= proto_tree_add_item(tree
, proto_quake2
,
645 quake2_tree
= proto_item_add_subtree(quake2_item
, ett_quake2
);
646 proto_tree_add_uint_format(quake2_tree
,
647 direction
== DIR_S2C
?
651 "Direction: %s", val_to_str(direction
, names_direction
, "%u"));
654 if (tvb_get_ntohl(tvb
, 0) == 0xffffffff) {
655 col_append_str(pinfo
->cinfo
, COL_INFO
, " Connectionless");
656 proto_tree_add_uint_format(quake2_tree
,
657 hf_quake2_connectionless
,
659 "Type: Connectionless");
660 dissect_quake2_ConnectionlessPacket(
661 tvb
, pinfo
, quake2_tree
, direction
);
664 col_append_str(pinfo
->cinfo
, COL_INFO
, " Game");
665 proto_tree_add_uint_format(quake2_tree
,
669 dissect_quake2_GamePacket(
670 tvb
, pinfo
, quake2_tree
, direction
);
672 return tvb_captured_length(tvb
);
676 apply_quake2_prefs(void)
678 /* Port preference used to determine client/server */
679 gbl_quake2ServerPorts
= prefs_get_range_value("quake2", "udp.port");
683 proto_register_quake2(void)
685 static hf_register_info hf
[] = {
687 { "Client to Server", "quake2.c2s",
688 FT_UINT32
, BASE_DEC
, NULL
, 0x0,
691 { "Server to Client", "quake2.s2c",
692 FT_UINT32
, BASE_DEC
, NULL
, 0x0,
694 { &hf_quake2_connectionless
,
695 { "Connectionless", "quake2.connectionless",
696 FT_UINT32
, BASE_DEC
, NULL
, 0x0,
699 { "Game", "quake2.game",
700 FT_UINT32
, BASE_DEC
, NULL
, 0x0,
702 { &hf_quake2_userinfo
,
703 { "Userinfo", "quake2.userinfo",
704 FT_STRING
, BASE_NONE
, NULL
, 0x0,
706 { &hf_quake2_command
,
707 { "Command", "quake2.command",
708 FT_STRING
, BASE_NONE
, NULL
, 0x0,
710 { &hf_quake2_connectionless_marker
,
711 { "Marker", "quake2.connectionless.marker",
712 FT_UINT32
, BASE_HEX
, NULL
, 0x0,
714 { &hf_quake2_connectionless_text
,
715 { "Text", "quake2.connectionless.text",
716 FT_STRING
, BASE_NONE
, NULL
, 0x0,
718 { &hf_quake2_game_seq1
,
719 { "Sequence Number", "quake2.game.seq1",
720 FT_UINT32
, BASE_DEC
, NULL
, 0x0,
721 "Sequence number of the current packet", HFILL
}},
722 { &hf_quake2_game_rel1
,
723 { "Reliable", "quake2.game.rel1",
724 FT_BOOLEAN
, BASE_NONE
, NULL
, 0x0,
725 "Packet is reliable and may be retransmitted", HFILL
}},
726 { &hf_quake2_game_seq2
,
727 { "Sequence Number", "quake2.game.seq2",
728 FT_UINT32
, BASE_DEC
, NULL
, 0x0,
729 "Sequence number of the last received packet", HFILL
}},
730 { &hf_quake2_game_rel2
,
731 { "Reliable", "quake2.game.rel2",
732 FT_BOOLEAN
, BASE_NONE
, NULL
, 0x0,
733 "Packet was reliable and may be retransmitted", HFILL
}},
734 { &hf_quake2_game_qport
,
735 { "QPort", "quake2.game.qport",
736 FT_UINT32
, BASE_DEC
, NULL
, 0x0,
737 "Quake II Client Port", HFILL
}},
738 { &hf_quake2_game_client_command
,
739 { "Client Command Type", "quake2.game.client.command",
740 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
741 "Quake II Client Command", HFILL
}},
742 { &hf_quake2_game_server_command
,
743 { "Server Command", "quake2.game.server.command",
744 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
745 "Quake II Server Command", HFILL
}},
746 { &hf_quake2_game_client_command_move_chksum
,
747 { "Checksum", "quake2.game.client.command.move.chksum",
748 FT_UINT8
, BASE_HEX
, NULL
, 0x0,
749 "Quake II Client Command Move", HFILL
}},
750 { &hf_quake2_game_client_command_move_lframe
,
751 { "Last Frame", "quake2.game.client.command.move.lframe",
752 FT_UINT32
, BASE_DEC
, NULL
, 0x0,
753 "Quake II Client Command Move", HFILL
}},
754 { &hf_quake2_game_client_command_move
,
755 { "Bitfield", "quake2.game.client.command.move",
756 FT_UINT8
, BASE_HEX
, NULL
, 0x0,
757 "Quake II Client Command Move", HFILL
}},
758 { &hf_quake2_game_client_command_move_bitfield_angles1
,
759 { "Angles (pitch)", "quake2.game.client.command.move.angles",
761 VALS(hf_quake2_game_client_command_move_vals
),
762 CM_ANGLE1
, NULL
, HFILL
}},
763 { &hf_quake2_game_client_command_move_bitfield_angles2
,
764 { "Angles (yaw)", "quake2.game.client.command.move.angles",
766 VALS(hf_quake2_game_client_command_move_vals
),
767 CM_ANGLE2
, NULL
, HFILL
}},
768 { &hf_quake2_game_client_command_move_bitfield_angles3
,
769 { "Angles (roll)", "quake2.game.client.command.move.angles",
771 VALS(hf_quake2_game_client_command_move_vals
),
772 CM_ANGLE3
, NULL
, HFILL
}},
773 { &hf_quake2_game_client_command_move_bitfield_movement_fwd
,
774 { "Movement (fwd)", "quake2.game.client.command.move.movement",
776 VALS(hf_quake2_game_client_command_move_vals
),
777 CM_FORWARD
, NULL
, HFILL
}},
778 { &hf_quake2_game_client_command_move_bitfield_movement_side
,
779 { "Movement (side)", "quake2.game.client.command.move.movement",
781 VALS(hf_quake2_game_client_command_move_vals
),
782 CM_SIDE
, NULL
, HFILL
}},
783 { &hf_quake2_game_client_command_move_bitfield_movement_up
,
784 { "Movement (up)", "quake2.game.client.command.move.movement",
786 VALS(hf_quake2_game_client_command_move_vals
),
787 CM_UP
, NULL
, HFILL
}},
788 { &hf_quake2_game_client_command_move_bitfield_buttons
,
789 { "Buttons", "quake2.game.client.command.move.buttons",
791 VALS(hf_quake2_game_client_command_move_vals
),
792 CM_BUTTONS
, NULL
, HFILL
}},
793 { &hf_quake2_game_client_command_move_bitfield_impulse
,
794 { "Impulse", "quake2.game.client.command.move.impulse",
796 VALS(hf_quake2_game_client_command_move_vals
),
797 CM_IMPULSE
, NULL
, HFILL
}},
798 { &hf_quake2_game_client_command_move_msec
,
799 { "Msec", "quake2.game.client.command.move.msec",
800 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
801 "Quake II Client Command Move", HFILL
}},
802 { &hf_quake2_game_client_command_move_lightlevel
,
803 { "Lightlevel", "quake2.game.client.command.move.lightlevel",
804 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
805 "Quake II Client Command Move", HFILL
}}
807 static int *ett
[] = {
809 &ett_quake2_connectionless
,
811 &ett_quake2_game_seq1
,
812 &ett_quake2_game_seq2
,
813 &ett_quake2_game_clc
,
814 &ett_quake2_game_svc
,
815 &ett_quake2_game_clc_cmd
,
816 &ett_quake2_game_svc_cmd
,
817 &ett_quake2_game_clc_cmd_move_moves
,
818 &ett_quake2_game_clc_cmd_move_bitfield
821 proto_quake2
= proto_register_protocol("Quake II Network Protocol", "QUAKE2", "quake2");
822 proto_register_field_array(proto_quake2
, hf
, array_length(hf
));
823 proto_register_subtree_array(ett
, array_length(ett
));
825 /* Register the dissector handle */
826 quake2_handle
= register_dissector("quake2", dissect_quake2
, proto_quake2
);
828 /* Register a configuration option for port */
829 prefs_register_protocol(proto_quake2
, apply_quake2_prefs
);
833 proto_reg_handoff_quake2(void)
835 dissector_add_uint_with_preference("udp.port", PORT_MASTER
, quake2_handle
);
836 apply_quake2_prefs();
840 * Editor modelines - https://www.wireshark.org/tools/modelines.html
845 * indent-tabs-mode: nil
848 * vi: set shiftwidth=4 tabstop=8 expandtab:
849 * :indentSize=4:tabSize=8:noTabs=true: