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.7 2001/12/10 00:25:33 guy 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.
37 #ifdef HAVE_SYS_TYPES_H
38 # include <sys/types.h>
45 static int proto_quake2 = -1;
47 static int hf_quake2_s2c = -1;
48 static int hf_quake2_c2s = -1;
49 static int hf_quake2_connectionless = -1;
50 static int hf_quake2_game = -1;
51 static int hf_quake2_connectionless_marker = -1;
52 static int hf_quake2_connectionless_text = -1;
53 static int hf_quake2_game_seq1 = -1;
54 static int hf_quake2_game_rel1 = -1;
55 static int hf_quake2_game_seq2 = -1;
56 static int hf_quake2_game_rel2 = -1;
57 static int hf_quake2_game_qport = -1;
59 static gint ett_quake2 = -1;
60 static gint ett_quake2_connectionless = -1;
61 static gint ett_quake2_game = -1;
62 static gint ett_quake2_game_seq1 = -1;
63 static gint ett_quake2_game_seq2 = -1;
64 static gint ett_quake2_game_clc = -1;
65 static gint ett_quake2_game_svc = -1;
67 static dissector_handle_t data_handle;
69 #define PORT_MASTER 27910
70 static unsigned int gbl_quake2ServerPort=PORT_MASTER;
74 dissect_quake2_ConnectionlessPacket(tvbuff_t *tvb, packet_info *pinfo,
75 proto_tree *tree, int direction)
77 proto_tree *cl_tree = NULL;
78 proto_item *cl_item = NULL;
86 marker = tvb_get_ntohl(tvb, 0);
88 cl_item = proto_tree_add_text(tree, tvb,
89 0, tvb_length(tvb), "Connectionless");
91 cl_tree = proto_item_add_subtree(
92 cl_item, ett_quake2_connectionless);
96 proto_tree_add_uint(cl_tree, hf_quake2_connectionless_marker,
100 /* all the rest of the packet is just text */
103 maxbufsize = MIN((gint)sizeof(text), tvb_length_remaining(tvb, offset));
104 len = tvb_get_nstringz0(tvb, offset, maxbufsize, text);
106 proto_tree_add_string(cl_tree, hf_quake2_connectionless_text,
107 tvb, offset, len + 1, text);
111 /* we should analyse the result 'text' a bit further */
112 /* for this we need the direction parameter */
117 dissect_quake2_client_commands(tvbuff_t *tvb, packet_info *pinfo,
120 /* If I have too much time at hand, I'll fill it with all
121 the information from my DM2 specs:
122 http://www.planetquake.com/demospecs/dm2/
124 call_dissector(data_handle,tvb, pinfo, tree);
129 dissect_quake2_server_commands(tvbuff_t *tvb, packet_info *pinfo,
132 /* If I have too much time at hand, I'll fill it with all
133 the information from my DM2 specs:
134 http://www.planetquake.com/demospecs/dm2/
136 call_dissector(data_handle,tvb, pinfo, tree);
140 static const value_string names_reliable[] = {
141 { 0, "Non Reliable" },
147 static const value_string names_direction[] = {
149 { DIR_C2S, "Client to Server" },
151 { DIR_S2C, "Server to Client" },
157 dissect_quake2_GamePacket(tvbuff_t *tvb, packet_info *pinfo,
158 proto_tree *tree, int direction)
160 proto_tree *game_tree = NULL;
161 proto_item *game_item = NULL;
169 direction = (pinfo->destport == gbl_quake2ServerPort) ?
173 game_item = proto_tree_add_text(tree, tvb,
174 0, tvb_length(tvb), "Game");
176 game_tree = proto_item_add_subtree(
177 game_item, ett_quake2_game);
182 seq1 = tvb_get_letohl(tvb, offset);
183 rel1 = seq1 & 0x80000000 ? 1 : 0;
186 proto_item *seq1_item = proto_tree_add_text(game_tree,
187 tvb, offset, 4, "Current Sequence: %u (%s)",
188 seq1, val_to_str(rel1,names_reliable,"%u"));
190 proto_tree *seq1_tree = proto_item_add_subtree(
191 seq1_item, ett_quake2_game_seq1);
192 proto_tree_add_uint(seq1_tree, hf_quake2_game_seq1,
193 tvb, offset, 4, seq1);
194 proto_tree_add_boolean(seq1_tree, hf_quake2_game_rel1,
195 tvb, offset+3, 1, rel1);
200 seq2 = tvb_get_letohl(tvb, offset);
201 rel2 = seq2 & 0x80000000 ? 1 : 0;
204 proto_item *seq2_item = proto_tree_add_text(game_tree,
205 tvb, offset, 4, "Acknowledge Sequence: %u (%s)",
206 seq2, val_to_str(rel2,names_reliable,"%u"));;
208 proto_tree *seq2_tree = proto_item_add_subtree(
209 seq2_item, ett_quake2_game_seq2);
210 proto_tree_add_uint(seq2_tree, hf_quake2_game_seq2,
211 tvb, offset, 4, seq2);
212 proto_tree_add_boolean(seq2_tree, hf_quake2_game_rel2,
213 tvb, offset+3, 1, rel2);
218 if (direction == DIR_C2S) {
219 /* client to server */
220 guint16 qport = tvb_get_letohs(tvb, offset);
222 proto_tree_add_uint(game_tree, hf_quake2_game_qport,
223 tvb, offset, 2, qport);
228 /* all the rest is pure game data */
229 rest_length = tvb_reported_length(tvb) - offset;
232 tvb_new_subset(tvb, offset, rest_length , rest_length);
234 if (direction == DIR_C2S) {
235 proto_item *c_item = NULL;
236 proto_tree *c_tree = NULL;
238 c_item = proto_tree_add_text(game_tree, next_tvb,
239 0, tvb_length(next_tvb),
242 c_tree = proto_item_add_subtree(
243 c_item, ett_quake2_game_clc);
246 dissect_quake2_client_commands(next_tvb, pinfo, c_tree);
249 proto_item *c_item = NULL;
250 proto_tree *c_tree = NULL;
252 c_item = proto_tree_add_text(game_tree, next_tvb,
253 0, tvb_length(next_tvb),
256 c_tree = proto_item_add_subtree(
257 c_item, ett_quake2_game_svc);
260 dissect_quake2_server_commands(next_tvb, pinfo, c_tree);
267 dissect_quake2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
269 proto_tree *quake2_tree = NULL;
270 proto_item *quake2_item = NULL;
273 direction = (pinfo->destport == gbl_quake2ServerPort) ?
276 if (check_col(pinfo->cinfo, COL_PROTOCOL))
277 col_set_str(pinfo->cinfo, COL_PROTOCOL, "QUAKE2");
278 if (check_col(pinfo->cinfo, COL_INFO))
279 col_set_str(pinfo->cinfo, COL_INFO, val_to_str(direction,
280 names_direction, "%u"));
283 quake2_item = proto_tree_add_item(tree, proto_quake2,
284 tvb, 0, tvb_length(tvb), FALSE);
286 quake2_tree = proto_item_add_subtree(
287 quake2_item, ett_quake2);
289 proto_tree_add_uint_format(quake2_tree,
290 direction == DIR_S2C ?
294 "Direction: %s", val_to_str(direction, names_direction, "%u"));
298 if (tvb_get_ntohl(tvb, 0) == 0xffffffff) {
299 if (check_col(pinfo->cinfo, COL_INFO)) {
300 col_append_str(pinfo->cinfo, COL_INFO, " Connectionless");
303 proto_tree_add_uint_format(quake2_tree,
304 hf_quake2_connectionless,
306 "Type: Connectionless");
307 dissect_quake2_ConnectionlessPacket(
308 tvb, pinfo, quake2_tree, direction);
311 if (check_col(pinfo->cinfo, COL_INFO)) {
312 col_append_str(pinfo->cinfo, COL_INFO, " Game");
315 proto_tree_add_uint_format(quake2_tree,
319 dissect_quake2_GamePacket(
320 tvb, pinfo, quake2_tree, direction);
326 proto_reg_handoff_quake2(void)
328 static int Initialized=FALSE;
329 static dissector_handle_t quake2_handle;
330 static int ServerPort=0;
333 quake2_handle = create_dissector_handle(dissect_quake2,
337 dissector_delete("udp.port", ServerPort, quake2_handle);
340 /* set port for future deletes */
341 ServerPort=gbl_quake2ServerPort;
343 dissector_add("udp.port", gbl_quake2ServerPort, quake2_handle);
344 data_handle = find_dissector("data");
349 proto_register_quake2(void)
351 static hf_register_info hf[] = {
353 { "Client to Server", "quake2.c2s",
354 FT_UINT32, BASE_DEC, NULL, 0x0,
355 "Client to Server", HFILL }},
357 { "Server to Client", "quake2.s2c",
358 FT_UINT32, BASE_DEC, NULL, 0x0,
359 "Server to Client", HFILL }},
360 { &hf_quake2_connectionless,
361 { "Connectionless", "quake2.connectionless",
362 FT_UINT32, BASE_DEC, NULL, 0x0,
363 "Connectionless", HFILL }},
365 { "Game", "quake2.game",
366 FT_UINT32, BASE_DEC, NULL, 0x0,
368 { &hf_quake2_connectionless_marker,
369 { "Marker", "quake2.connectionless.marker",
370 FT_UINT32, BASE_HEX, NULL, 0x0,
372 { &hf_quake2_connectionless_text,
373 { "Text", "quake2.connectionless.text",
374 FT_STRING, BASE_DEC, NULL, 0x0,
376 { &hf_quake2_game_seq1,
377 { "Sequence Number", "quake2.game.seq1",
378 FT_UINT32, BASE_DEC, NULL, 0x0,
379 "Sequence number of the current packet", HFILL }},
380 { &hf_quake2_game_rel1,
381 { "Reliable", "quake2.game.rel1",
382 FT_BOOLEAN, BASE_DEC, NULL, 0x0,
383 "Packet is reliable and may be retransmitted", HFILL }},
384 { &hf_quake2_game_seq2,
385 { "Sequence Number", "quake2.game.seq2",
386 FT_UINT32, BASE_DEC, NULL, 0x0,
387 "Sequence number of the last received packet", HFILL }},
388 { &hf_quake2_game_rel2,
389 { "Reliable", "quake2.game.rel2",
390 FT_BOOLEAN, BASE_DEC, NULL, 0x0,
391 "Packet was reliable and may be retransmitted", HFILL }},
392 { &hf_quake2_game_qport,
393 { "QPort", "quake2.game.qport",
394 FT_UINT32, BASE_DEC, NULL, 0x0,
395 "Quake II Client Port", HFILL }}
397 static gint *ett[] = {
399 &ett_quake2_connectionless,
401 &ett_quake2_game_seq1,
402 &ett_quake2_game_seq2,
403 &ett_quake2_game_clc,
406 module_t *quake2_module;
408 proto_quake2 = proto_register_protocol("Quake II Network Protocol",
410 proto_register_field_array(proto_quake2, hf, array_length(hf));
411 proto_register_subtree_array(ett, array_length(ett));
413 /* Register a configuration option for port */
414 quake2_module = prefs_register_protocol(proto_quake2,
415 proto_reg_handoff_quake2);
416 prefs_register_uint_preference(quake2_module, "udp.port",
417 "Quake II Server UDP Port",
418 "Set the UDP port for the Quake II Server",
419 10, &gbl_quake2ServerPort);