Add Winsock AF_ values to epan/aftypes.h; the DirectPlay and ActiveSync
[obnox/wireshark/wip.git] / epan / dissectors / packet-dplay.c
1 /* packet-dplay.c
2  * This is a dissector for the DirectPlay protocol.
3  * Copyright 2006 - 2008 by Kai Blin
4  *
5  * $Id$
6  *
7  * Wireshark - Network traffic analyzer
8  * By Gerald Combs <gerald@wireshark.org>
9  * Copyright 1998 Gerald Combs
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
24  * USA.59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
25  *
26  */
27
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #include <epan/packet.h>
33 #include <epan/prefs.h>
34 #include <epan/emem.h>
35 #include <epan/aftypes.h>
36 #include <string.h>
37
38 /* function declarations */
39 void proto_reg_handoff_dplay(void);
40 static gboolean heur_dissect_dplay(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
41 static void dissect_dplay(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
42 static gint dissect_type1a_message(proto_tree *tree, tvbuff_t *tvb, gint offset);
43
44 static int proto_dplay = -1;
45 static dissector_handle_t dplay_handle;
46
47 /* Common data fields */
48 static int hf_dplay_size = -1;              /* Size of the whole data */
49 static int hf_dplay_token = -1;
50 static int hf_dplay_saddr_af = -1;          /* WINSOCK_AF_INET, as this dissector does not handle IPX yet */
51 static int hf_dplay_saddr_port = -1;        /* port to use for the reply to this packet */
52 static int hf_dplay_saddr_ip = -1;          /* IP to use for the reply to this packet, or 0.0.0.0,
53                                                then use the same IP as this packet used. */
54 static int hf_dplay_saddr_padding = -1;     /* null padding used in s_addr_in structures */
55 static int hf_dplay_play_str = -1;          /* always "play" without a null terminator */
56 static int hf_dplay_command = -1;           /* the dplay command this message contains*/
57 static int hf_dplay_proto_dialect = -1;     /* 0x0b00 for dplay7, 0x0e00 for dplay9 */
58 static int hf_dplay_play_str_2 = -1;        /* packet type 0x0015 encapsulates another packet */
59 static int hf_dplay_command_2 = -1;         /* that also has a "play" string, a command and a */
60 static int hf_dplay_proto_dialect_2 = -1;   /* protocol dialect, same as above */
61 static const int DPLAY_HEADER_OFFSET = 28;  /* The dplay header is 28 bytes in size */
62 static int hf_dplay_player_msg = -1;
63
64 /* The following fields are not part of the header, but hopefully have the same
65  * meaning for all packets they show up in. */
66
67 static int hf_dplay_sess_desc_flags = -1; /* This is a 32bit field with some sort of a flag */
68 static int hf_dplay_flags_no_create_players = -1;
69 static int hf_dplay_flags_0002 = -1;
70 static int hf_dplay_flags_migrate_host = -1;
71 static int hf_dplay_flags_short_player_msg = -1;
72 static int hf_dplay_flags_ignored = -1;
73 static int hf_dplay_flags_can_join = -1;
74 static int hf_dplay_flags_use_ping = -1;
75 static int hf_dplay_flags_no_player_updates = -1;
76 static int hf_dplay_flags_use_auth = -1;
77 static int hf_dplay_flags_private_session = -1;
78 static int hf_dplay_flags_password_req = -1;
79 static int hf_dplay_flags_route = -1;
80 static int hf_dplay_flags_server_player_only = -1;
81 static int hf_dplay_flags_reliable = -1;
82 static int hf_dplay_flags_preserve_order = -1;
83 static int hf_dplay_flags_optimize_latency = -1;
84 static int hf_dplay_flags_acqire_voice = -1;
85 static int hf_dplay_flags_no_sess_desc_changes = -1;
86
87 #define DPLAY_FLAG_NO_CREATE_PLAYERS 0x0001
88 #define DPLAY_FLAG_0002 0x0002
89 #define DPLAY_FLAG_MIGRATE_HOST 0x0004
90 #define DPLAY_FLAG_SHORT_PLAYER_MSG 0x0008
91 #define DPLAY_FLAG_IGNORED 0x0010
92 #define DPLAY_FLAG_CAN_JOIN 0x0020
93 #define DPLAY_FLAG_USE_PING 0x0040
94 #define DPLAY_FLAG_NO_P_UPD 0x0080
95 #define DPLAY_FLAG_USE_AUTH 0x0100
96 #define DPLAY_FLAG_PRIV_SESS 0x0200
97 #define DPLAY_FLAG_PASS_REQ 0x0400
98 #define DPLAY_FLAG_ROUTE 0x0800
99 #define DPLAY_FLAG_SRV_ONLY 0x1000
100 #define DPLAY_FLAG_RELIABLE 0x2000
101 #define DPLAY_FLAG_ORDER 0x4000
102 #define DPLAY_FLAG_OPT_LAT 0x8000
103 #define DPLAY_FLAG_ACQ_VOICE 0x10000
104 #define DPLAY_FLAG_NO_SESS_DESC_CHANGES 0x20000
105
106 /* Session description structure fields */
107 static int hf_dplay_sess_desc_length = -1;
108 static int hf_dplay_game_guid = -1;
109 static int hf_dplay_instance_guid = -1;
110 static int hf_dplay_max_players = -1;
111 static int hf_dplay_curr_players = -1;
112 static int hf_dplay_sess_name_ptr = -1;
113 static int hf_dplay_passwd_ptr = -1;
114 static int hf_dplay_sess_desc_reserved_1 = -1;
115 static int hf_dplay_sess_desc_reserved_2 = -1;
116 static int hf_dplay_sess_desc_user_1 = -1;
117 static int hf_dplay_sess_desc_user_2 = -1;
118 static int hf_dplay_sess_desc_user_3 = -1;
119 static int hf_dplay_sess_desc_user_4 = -1;
120
121 /* PackedPlayer structure fields */
122 static int hf_dplay_pp_size = -1;
123 static int hf_dplay_pp_flags = -1;
124 static int hf_dplay_pp_flag_sysplayer = -1;
125 static int hf_dplay_pp_flag_nameserver = -1;
126 static int hf_dplay_pp_flag_in_group = -1;
127 static int hf_dplay_pp_flag_sending = -1;
128 static int hf_dplay_pp_id = -1;
129 static int hf_dplay_pp_short_name_len = -1;
130 static int hf_dplay_pp_long_name_len = -1;
131 static int hf_dplay_pp_sp_data_size = -1;
132 static int hf_dplay_pp_player_data_size = -1;
133 static int hf_dplay_pp_num_players = -1;
134 static int hf_dplay_pp_system_player = -1;
135 static int hf_dplay_pp_fixed_size = -1;
136 static int hf_dplay_pp_dialect = -1;
137 static int hf_dplay_pp_unknown_1 = -1;
138 static int hf_dplay_pp_short_name = -1;
139 static int hf_dplay_pp_long_name = -1;
140 static int hf_dplay_pp_sp_data = -1;
141 static int hf_dplay_pp_player_data = -1;
142 static int hf_dplay_pp_player_id = -1;
143 static int hf_dplay_pp_parent_id = -1;
144 #define DPLAY_PP_FLAG_SYSPLAYER 0x01
145 #define DPLAY_PP_FLAG_NAMESERVER 0x02
146 #define DPLAY_PP_FLAG_IN_GROUP 0x04
147 #define DPLAY_PP_FLAG_SENDING 0x08
148
149 /* SuperPackedPlayer structure fields */
150 static int hf_dplay_spp_size = -1;
151 static int hf_dplay_spp_flags = -1;
152 static int hf_dplay_spp_flags_sysplayer = -1;
153 static int hf_dplay_spp_flags_nameserver = -1;
154 static int hf_dplay_spp_flags_in_group = -1;
155 static int hf_dplay_spp_flags_sending = -1;
156 static int hf_dplay_spp_id = -1;
157 static int hf_dplay_spp_player_info_mask = -1;
158 static int hf_dplay_spp_have_short_name = -1;
159 static int hf_dplay_spp_have_long_name = -1;
160 static int hf_dplay_spp_sp_length_type = -1;
161 static int hf_dplay_spp_pd_length_type = -1;
162 static int hf_dplay_spp_player_count_type = -1;
163 static int hf_dplay_spp_have_parent_id = -1;
164 static int hf_dplay_spp_shortcut_count_type = -1;
165 static int hf_dplay_spp_dialect = -1;
166 static int hf_dplay_spp_sys_player_id = -1;
167 static int hf_dplay_spp_short_name = -1;
168 static int hf_dplay_spp_long_name = -1;
169 static int hf_dplay_spp_player_data_length = -1;
170 static int hf_dplay_spp_player_data = -1;
171 static int hf_dplay_spp_sp_data_length = -1;
172 static int hf_dplay_spp_sp_data = -1;
173 static int hf_dplay_spp_player_count = -1;
174 static int hf_dplay_spp_player_id = -1;
175 static int hf_dplay_spp_parent_id = -1;
176 static int hf_dplay_spp_shortcut_count = -1;
177 static int hf_dplay_spp_shortcut_id = -1;
178 #define DPLAY_SPP_FLAG_SYSPLAYER 0x01
179 #define DPLAY_SPP_FLAG_NAMESERVER 0x02
180 #define DPLAY_SPP_FLAG_IN_GROUP 0x04
181 #define DPLAY_SPP_FLAG_SENDING 0x08
182
183 /* SecurityDesc structure fields */
184 static int hf_dplay_sd_size = -1;
185 static int hf_dplay_sd_flags = -1;
186 static int hf_dplay_sd_sspi = -1;
187 static int hf_dplay_sd_capi = -1;
188 static int hf_dplay_sd_capi_type = -1;
189 static int hf_dplay_sd_enc_alg = -1;
190
191 /* Message Type 0x0001 data fields */
192 static int hf_dplay_type_01_name_offset = -1;
193 static int hf_dplay_type_01_game_name = -1;
194
195 /* Message Type 0x0002 data fields */
196 static int hf_dplay_type_02_game_guid = -1;
197 static int hf_dplay_type_02_password_offset = -1;
198 static int hf_dplay_type_02_flags = -1;
199 static int hf_dplay_type_02_password = -1;
200 static int hf_enum_sess_flag_join = -1;
201 static int hf_enum_sess_flag_all = -1;
202 static int hf_enum_sess_flag_passwd = -1;
203 #define DPLAY_ENUM_SESS_FLAG_JOIN 0x0001
204 #define DPLAY_ENUM_SESS_FLAG_ALL 0x0002
205 #define DPLAY_ENUM_SESS_FLAG_PASSWD 0x0040
206
207 /* Message Type 0x0005 data fields */
208 static int hf_dplay_type_05_flags = -1;
209 static int hf_dplay_type_05_system_player = -1;
210 static int hf_dplay_type_05_name_server = -1;
211 static int hf_dplay_type_05_local = -1;
212 static int hf_dplay_type_05_unknown = -1; /* unknown, but always set */
213 static int hf_dplay_type_05_secure = -1;
214 #define DPLAY_TYPE05_FLAG_SYSPLAYER 0x001
215 #define DPLAY_TYPE05_FLAG_NAMESERVER 0x002
216 #define DPLAY_TYPE05_FLAG_LOCAL 0x004
217 #define DPLAY_TYPE05_FLAG_UNKNOWN 0x008
218 #define DPLAY_TYPE05_FLAG_SECURE 0x200
219
220 /* Message Type 0x0007 data fields */
221 static int hf_dplay_type_07_dpid = -1;
222 static int hf_dplay_type_07_sspi_offset = -1;
223 static int hf_dplay_type_07_capi_offset = -1;
224 static int hf_dplay_type_07_hresult = -1;
225 static int hf_dplay_type_07_sspi = -1;
226 static int hf_dplay_type_07_capi = -1;
227
228 /* Data fields for message types 0x08, 0x09, 0x0b, 0x0c, 0x0d, 0x0e */
229 static int hf_dplay_multi_id_to = -1;
230 static int hf_dplay_multi_player_id = -1;
231 static int hf_dplay_multi_group_id = -1;
232 static int hf_dplay_multi_create_offset = -1;
233 static int hf_dplay_multi_password_offset = -1;
234 static int hf_dplay_multi_password = -1;
235
236 /* Message Type 0x000f data fields */
237 static int hf_dplay_type_0f_id_to = -1;
238 static int hf_dplay_type_0f_id = -1;
239 static int hf_dplay_type_0f_data_size = -1;
240 static int hf_dplay_type_0f_data_offset = -1;
241 static int hf_dplay_type_0f_data = -1;
242
243 /* Message Type 0x0013 data fields */
244 static int hf_dplay_type_13_id_to = -1;
245 static int hf_dplay_type_13_player_id = -1;
246 static int hf_dplay_type_13_group_id = -1;
247 static int hf_dplay_type_13_create_offset = -1;
248 static int hf_dplay_type_13_password_offset = -1;
249 static int hf_dplay_type_13_password = -1;
250 static int hf_dplay_type_13_tick_count = -1;
251
252 /* Message Type 0x0015 data fields */
253 static int hf_dplay_message_guid = -1;
254 static int hf_dplay_type_15_packet_idx = -1;
255 static int hf_dplay_type_15_data_size = -1;
256 static int hf_dplay_type_15_offset = -1;
257 static int hf_dplay_type_15_total_packets = -1;
258 static int hf_dplay_type_15_msg_size = -1;
259 static int hf_dplay_type_15_packet_offset = -1;
260
261 /* Message Type 0x0016 and 0x0017 data fields */
262 static int hf_dplay_ping_id_from = -1;
263 static int hf_dplay_ping_tick_count = -1;
264
265 /* Message Type 0x001a data fields */
266 static int hf_dplay_type_1a_id_to = -1;
267 static int hf_dplay_type_1a_sess_name_ofs = -1;
268 static int hf_dplay_type_1a_password_ofs = -1;
269 static int hf_dplay_type_1a_session_name = -1;
270 static int hf_dplay_type_1a_password = -1;
271
272 /* Message Type 0x0029 data fields */
273 static int hf_dplay_type_29_player_count = -1;
274 static int hf_dplay_type_29_group_count = -1;
275 static int hf_dplay_type_29_packed_offset = -1;
276 static int hf_dplay_type_29_shortcut_count = -1;
277 static int hf_dplay_type_29_description_offset = -1;
278 static int hf_dplay_type_29_name_offset = -1;
279 static int hf_dplay_type_29_password_offset = -1;
280 static int hf_dplay_type_29_game_name = -1;
281 static int hf_dplay_type_29_password = -1;
282
283 /* Message Type 0x002f data fields */
284 static int hf_dplay_type_2f_dpid = -1;
285
286 /* various */
287 static gint ett_dplay = -1;
288 static gint ett_dplay_header = -1;
289 static gint ett_dplay_sockaddr = -1;
290 static gint ett_dplay_data = -1;
291 static gint ett_dplay_enc_packet = -1;
292 static gint ett_dplay_flags = -1;
293 static gint ett_dplay_sess_desc_flags = -1;
294 static gint ett_dplay_pp_flags = -1;
295 static gint ett_dplay_spp_flags = -1;
296 static gint ett_dplay_spp_info_mask = -1;
297 static gint ett_dplay_type02_flags = -1;
298 static gint ett_dplay_type05_flags = -1;
299 static gint ett_dplay_type29_spp = -1;
300
301 static const value_string dplay_command_val[] = {
302     { 0x0001, "Enum Sessions Reply" },
303     { 0x0002, "Enum Sessions" },
304     { 0x0003, "Enum Players Reply" },
305     { 0x0004, "Enum Players" },
306     { 0x0005, "Request Player ID" },
307     { 0x0006, "Request Group ID" },
308     { 0x0007, "Request Player Reply" },
309     { 0x0008, "Create Player" },
310     { 0x0009, "Create Group" },
311     { 0x000a, "Player Message" },
312     { 0x000b, "Delete Player" },
313     { 0x000c, "Delete Group" },
314     { 0x000d, "Add Player To Group" },
315     { 0x000e, "Delete Player From Group" },
316     { 0x000f, "Player Data Changed" },
317     { 0x0010, "Player Name Changed" },
318     { 0x0011, "Group Data Changed" },
319     { 0x0012, "Group Name Changed" },
320     { 0x0013, "Add Forward Request" },
321     /* There is no command 0x0014 */
322     { 0x0015, "Packet" },
323     { 0x0016, "Ping" },
324     { 0x0017, "Pong" },
325     { 0x0018, "You Are Dead" },
326     { 0x0019, "Player Wrapper" },
327     { 0x001a, "Session Desc Changed" },
328     { 0x001c, "Challenge" },
329     { 0x001d, "Access Granted" },
330     { 0x001e, "Logon Denied" },
331     { 0x001f, "Auth Error" },
332     { 0x0020, "Negotiate" },
333     { 0x0021, "Challenge Response" },
334     { 0x0022, "Signed"},
335     /* There is no command 0x0023 */
336     { 0x0024, "Add Forward Reply" },
337     { 0x0025, "Ask For Multicast" },
338     { 0x0026, "Ask For Multicast Guaranteed" },
339     { 0x0027, "Add Shortcut To Group" },
340     { 0x0028, "Delete Group From Group" },
341     { 0x0029, "Super Enum Players Reply" },
342     /* There is no command 0x002a */
343     { 0x002b, "Key Exchange" },
344     { 0x002c, "Key Exchange Reply" },
345     { 0x002d, "Chat" },
346     { 0x002e, "Add Forward" },
347     { 0x002f, "Add Forward ACK" },
348     { 0x0030, "Packet2 Data" },
349     { 0x0031, "Packet2 ACK" },
350     /* No commands 0x0032, 0x0033, 0x0034 */
351     { 0x0035, "I Am Nameserver" },
352     { 0x0036, "Voice" },
353     { 0x0037, "Multicast Delivery" },
354     { 0x0038, "Create Players Verify"},
355     { 0     , NULL },
356 };
357
358 static const value_string dplay_af_val[] = {
359     { WINSOCK_AF_INET, "AF_INET" },
360     { WINSOCK_AF_IPX, "AF_IPX" },
361     { 0     , NULL},
362 };
363
364 static const value_string dplay_proto_dialect_val[] = {
365     { 0x0009, "dplay 6" },
366     { 0x000a, "dplay 6.1" },
367     { 0x000b, "dplay 6.1a" },
368     { 0x000c, "dplay 7.1" },
369     { 0x000d, "dplay 8" },
370     { 0x000e, "dplay 9"},
371     { 0     , NULL},
372 };
373
374 static const value_string dplay_token_val[] = {
375     { 0xfab, "Remote Message" },
376     { 0xcab, "Forwarded Message" },
377     { 0xbab, "Server Message" },
378     { 0    , NULL },
379 };
380
381 static const value_string dplay_spp_length_val[] = {
382     { 0x0, "Not present" },
383     { 0x1, "One byte" },
384     { 0x2, "Two bytes" },
385     { 0x3, "Four bytes" },
386     { 0  , NULL},
387 };
388
389 static const value_string dplay_enc_alg_val[] = {
390     { 0x0000, "Default" },
391     { 0x6611, "AES" },
392     { 0x6603, "3DES" },
393     { 0x6601, "DES" },
394     { 0x6602, "RC2" },
395     { 0x6801, "RC4" },
396     { 0     , NULL },
397 };
398
399 static const value_string yes_no_val[] = {
400     { 0x0, "No" },
401     { 0x1, "Yes" },
402     { 0  , NULL },
403 };
404
405 static const true_false_string tfs_dplay_flag = {
406     "present",
407     "absent"
408 };
409
410 /* borrowed from epan/dissectors/packets-smb-common.c */
411 static gint display_unicode_string(proto_tree *tree, gint hf_index, tvbuff_t *tvb, gint offset)
412 {
413     char *str, *p;
414     gint len;
415     gint charoffset;
416     guint16 character;
417
418     /* display a unicode string from the tree and return new offset */
419
420     /*
421      * Get the length of the string.
422      * XXX - is it a bug or a feature that this will throw an exception
423      * if we don't find the '\0'?  I think it's a feature.
424      */
425     len = 0;
426     while ((character = tvb_get_letohs(tvb, offset + len)) != '\0')
427         len += 2;
428     len += 2;   /* count the '\0' too */
429
430     /*
431      * Allocate a buffer for the string; "len" is the length in
432      * bytes, not the length in characters.
433      */
434     str = ep_alloc(len/2);
435
436     /*
437      * XXX - this assumes the string is just ISO 8859-1; we need
438      * to better handle multiple character sets in Wireshark,
439      * including Unicode/ISO 10646, and multiple encodings of
440      * that character set (UCS-2, UTF-8, etc.).
441      */
442     charoffset = offset;
443     p = str;
444     while ((character = tvb_get_letohs(tvb, charoffset)) != '\0') {
445         *p++ = (char) character;
446         charoffset += 2;
447     }
448     *p = '\0';
449
450     proto_tree_add_string(tree, hf_index, tvb, offset, len, str);
451
452     return  offset+len;
453 }
454
455 static gint dissect_sockaddr_in(proto_tree *tree, tvbuff_t *tvb, gint offset)
456 {
457     proto_item *sa_item = NULL;
458     proto_tree *sa_tree = NULL;
459
460     sa_item = proto_tree_add_text(tree, tvb, offset, 16,
461             "DirectPlay sockaddr_in structure");
462     sa_tree = proto_item_add_subtree(sa_item, ett_dplay_sockaddr);
463     proto_tree_add_item(sa_tree, hf_dplay_saddr_af, tvb, offset, 2, TRUE); offset += 2;
464     proto_tree_add_item(sa_tree, hf_dplay_saddr_port, tvb, offset, 2, FALSE); offset += 2;
465     proto_tree_add_item(sa_tree, hf_dplay_saddr_ip, tvb, offset, 4, FALSE); offset += 4;
466     proto_tree_add_item(sa_tree, hf_dplay_saddr_padding, tvb, offset, 8, FALSE); offset += 8;
467     return offset;
468 }
469
470 static gint dissect_session_desc(proto_tree *tree, tvbuff_t *tvb, gint offset)
471 {
472     gint data_len;
473     guint32 flags;
474     proto_item *flags_item = NULL;
475     proto_tree *flags_tree = NULL;
476
477     data_len = tvb_get_letohl(tvb, offset);
478     flags = tvb_get_letohl(tvb, offset+4);
479
480     proto_tree_add_item(tree, hf_dplay_sess_desc_length, tvb, offset, 4, TRUE); offset += 4;
481     flags_item = proto_tree_add_item(tree, hf_dplay_sess_desc_flags, tvb, offset, 4, TRUE);
482     flags_tree = proto_item_add_subtree(flags_item, ett_dplay_sess_desc_flags);
483     proto_tree_add_boolean(flags_tree, hf_dplay_flags_no_sess_desc_changes, tvb, offset, 4, flags);
484     proto_tree_add_boolean(flags_tree, hf_dplay_flags_acqire_voice, tvb, offset, 4, flags);
485     proto_tree_add_boolean(flags_tree, hf_dplay_flags_optimize_latency, tvb, offset, 4, flags);
486     proto_tree_add_boolean(flags_tree, hf_dplay_flags_preserve_order, tvb, offset, 4, flags);
487     proto_tree_add_boolean(flags_tree, hf_dplay_flags_reliable, tvb, offset, 4, flags);
488     proto_tree_add_boolean(flags_tree, hf_dplay_flags_server_player_only, tvb, offset, 4, flags);
489     proto_tree_add_boolean(flags_tree, hf_dplay_flags_route, tvb, offset, 4, flags);
490     proto_tree_add_boolean(flags_tree, hf_dplay_flags_password_req, tvb, offset, 4, flags);
491     proto_tree_add_boolean(flags_tree, hf_dplay_flags_private_session, tvb, offset, 4, flags);
492     proto_tree_add_boolean(flags_tree, hf_dplay_flags_use_auth, tvb, offset, 4, flags);
493     proto_tree_add_boolean(flags_tree, hf_dplay_flags_no_player_updates, tvb, offset, 4, flags);
494     proto_tree_add_boolean(flags_tree, hf_dplay_flags_use_ping, tvb, offset, 4, flags);
495     proto_tree_add_boolean(flags_tree, hf_dplay_flags_can_join, tvb, offset, 4, flags);
496     proto_tree_add_boolean(flags_tree, hf_dplay_flags_ignored, tvb, offset, 4, flags);
497     proto_tree_add_boolean(flags_tree, hf_dplay_flags_short_player_msg, tvb, offset, 4, flags);
498     proto_tree_add_boolean(flags_tree, hf_dplay_flags_migrate_host, tvb, offset, 4, flags);
499     proto_tree_add_boolean(flags_tree, hf_dplay_flags_0002, tvb, offset, 4, flags);
500     proto_tree_add_boolean(flags_tree, hf_dplay_flags_no_create_players, tvb, offset, 4, flags);
501     offset += 4;
502
503     proto_tree_add_item(tree, hf_dplay_instance_guid, tvb, offset, 16, FALSE); offset += 16;
504     proto_tree_add_item(tree, hf_dplay_game_guid, tvb, offset, 16, FALSE); offset += 16;
505     proto_tree_add_item(tree, hf_dplay_max_players, tvb, offset, 4, TRUE); offset += 4;
506     proto_tree_add_item(tree, hf_dplay_curr_players, tvb, offset, 4, TRUE); offset += 4;
507     proto_tree_add_item(tree, hf_dplay_sess_name_ptr, tvb, offset, 4, FALSE); offset += 4;
508     proto_tree_add_item(tree, hf_dplay_passwd_ptr, tvb, offset, 4, FALSE); offset += 4;
509     proto_tree_add_item(tree, hf_dplay_sess_desc_reserved_1, tvb, offset, 4, FALSE); offset += 4;
510     proto_tree_add_item(tree, hf_dplay_sess_desc_reserved_2, tvb, offset, 4, FALSE); offset += 4;
511     proto_tree_add_item(tree, hf_dplay_sess_desc_user_1, tvb, offset, 4, FALSE); offset += 4;
512     proto_tree_add_item(tree, hf_dplay_sess_desc_user_2, tvb, offset, 4, FALSE); offset += 4;
513     proto_tree_add_item(tree, hf_dplay_sess_desc_user_3, tvb, offset, 4, FALSE); offset += 4;
514     proto_tree_add_item(tree, hf_dplay_sess_desc_user_4, tvb, offset, 4, FALSE); offset += 4;
515
516     return offset;
517 }
518
519 static gint dissect_packed_player(proto_tree *tree, tvbuff_t *tvb, gint offset)
520 {
521     proto_tree *flags_tree;
522     proto_item *flags_item;
523     guint32 flags, sn_len, ln_len, sd_len, pd_len, num_players, i;
524     gint size;
525
526     size = tvb_get_letohl(tvb, offset);
527     proto_tree_add_item(tree, hf_dplay_pp_size, tvb, offset, 4, TRUE); offset += 4;
528
529     flags = tvb_get_letohl(tvb, offset);
530     flags_item = proto_tree_add_item(tree, hf_dplay_pp_flags, tvb, offset, 4, TRUE);
531     flags_tree = proto_item_add_subtree(flags_item, ett_dplay_pp_flags);
532     proto_tree_add_boolean(flags_tree, hf_dplay_pp_flag_sending, tvb, offset, 4, flags);
533     proto_tree_add_boolean(flags_tree, hf_dplay_pp_flag_in_group, tvb, offset, 4, flags);
534     proto_tree_add_boolean(flags_tree, hf_dplay_pp_flag_nameserver, tvb, offset, 4, flags);
535     proto_tree_add_boolean(flags_tree, hf_dplay_pp_flag_sysplayer, tvb, offset, 4, flags);
536     offset += 4;
537
538     proto_tree_add_item(tree, hf_dplay_pp_id, tvb, offset, 4, FALSE); offset += 4;
539
540     sn_len = tvb_get_letohl(tvb, offset);
541     proto_tree_add_item(tree, hf_dplay_pp_short_name_len, tvb, offset, 4, TRUE); offset += 4;
542     ln_len = tvb_get_letohl(tvb, offset);
543     proto_tree_add_item(tree, hf_dplay_pp_long_name_len, tvb, offset, 4, TRUE); offset += 4;
544     sd_len = tvb_get_letohl(tvb, offset);
545     proto_tree_add_item(tree, hf_dplay_pp_sp_data_size, tvb, offset, 4, TRUE); offset += 4;
546     pd_len = tvb_get_letohl(tvb, offset);
547     proto_tree_add_item(tree, hf_dplay_pp_player_data_size, tvb, offset, 4, TRUE); offset += 4;
548     num_players = tvb_get_letohl(tvb, offset);
549     proto_tree_add_item(tree, hf_dplay_pp_num_players, tvb, offset, 4, TRUE); offset += 4;
550
551     proto_tree_add_item(tree, hf_dplay_pp_system_player, tvb, offset, 4, FALSE); offset += 4;
552     proto_tree_add_item(tree, hf_dplay_pp_fixed_size, tvb, offset, 4, TRUE); offset += 4;
553     proto_tree_add_item(tree, hf_dplay_pp_dialect, tvb, offset, 4, TRUE); offset += 4;
554     proto_tree_add_item(tree, hf_dplay_pp_unknown_1, tvb, offset, 4, FALSE); offset += 4;
555
556     if (sn_len)
557         offset = display_unicode_string(tree, hf_dplay_pp_short_name, tvb, offset);
558
559     if (ln_len)
560         offset = display_unicode_string(tree, hf_dplay_pp_long_name, tvb, offset);
561
562     proto_tree_add_item(tree, hf_dplay_pp_sp_data, tvb, offset, sd_len, FALSE);
563     offset += sd_len;
564
565     if (pd_len) {
566         proto_tree_add_item(tree, hf_dplay_pp_player_data, tvb, offset, pd_len, FALSE);
567         offset += pd_len;
568     }
569
570     for (i=0; i < num_players; ++i) {
571         proto_tree_add_item(tree, hf_dplay_pp_player_id, tvb, offset, 4, FALSE); offset += 4;
572     }
573
574     /* Size seems to miss the unknown empty dword */
575     if (size + 4 > offset) {
576         proto_tree_add_item(tree, hf_dplay_pp_parent_id, tvb, offset, 4, FALSE); offset += 4;
577     }
578
579     return offset;
580 }
581
582 static gint spp_get_value(guint32 length_type, tvbuff_t *tvb, gint offset, guint32 *value)
583 {
584     gint len = 0;
585
586     *value = 0;
587
588     switch (length_type) {
589         case 1:
590             len = 1;
591             *value = tvb_get_guint8(tvb, offset);
592             break;
593         case 2:
594             len = 2;
595             *value = tvb_get_letohs(tvb, offset);
596             break;
597         case 3:
598             len = 4;
599             *value = tvb_get_letohl(tvb, offset);
600             break;
601     }
602
603     return len;
604 }
605
606 static gint dissect_dplay_super_packed_player(proto_tree *tree, tvbuff_t *tvb, gint offset)
607 {
608     guint32 flags, is_sysplayer, info_mask;
609     guint32 have_short_name, have_long_name, sp_length_type, pd_length_type;
610     guint32 player_count_type, have_parent_id, shortcut_count_type;
611     guint32 player_data_length, sp_data_length, player_count, shortcut_count;
612     proto_item *flags_item = NULL, *im_item = NULL;
613     proto_tree *flags_tree = NULL, *im_tree = NULL;
614     gint len;
615
616     proto_tree_add_item(tree, hf_dplay_spp_size, tvb, offset, 4, TRUE); offset += 4;
617
618     flags = tvb_get_letohl(tvb, offset);
619     is_sysplayer = flags & 0x00000001;
620     flags_item = proto_tree_add_item(tree, hf_dplay_spp_flags, tvb, offset, 4, TRUE);
621     flags_tree = proto_item_add_subtree(flags_item, ett_dplay_spp_flags);
622     proto_tree_add_boolean(flags_tree, hf_dplay_spp_flags_sending, tvb, offset, 4, flags);
623     proto_tree_add_boolean(flags_tree, hf_dplay_spp_flags_in_group, tvb, offset, 4, flags);
624     proto_tree_add_boolean(flags_tree, hf_dplay_spp_flags_nameserver, tvb, offset, 4, flags);
625     proto_tree_add_boolean(flags_tree, hf_dplay_spp_flags_sysplayer, tvb, offset, 4, flags);
626     offset += 4;
627     proto_tree_add_item(tree, hf_dplay_spp_id, tvb, offset, 4, TRUE); offset += 4;
628
629     info_mask = tvb_get_letohl(tvb, offset);
630
631     have_short_name     =  info_mask & 0x00000001;
632     have_long_name      = (info_mask & 0x00000002) >> 1;
633     sp_length_type      = (info_mask & 0x0000000c) >> 2;
634     pd_length_type      = (info_mask & 0x00000030) >> 4;
635     player_count_type   = (info_mask & 0x000000c0) >> 6;
636     have_parent_id      = (info_mask & 0x00000100) >> 8;
637     shortcut_count_type = (info_mask & 0x00000600) >> 9;
638
639     im_item = proto_tree_add_item(tree, hf_dplay_spp_player_info_mask, tvb, offset, 4, TRUE);
640
641     im_tree = proto_item_add_subtree(im_item, ett_dplay_spp_info_mask);
642     proto_tree_add_uint(im_tree, hf_dplay_spp_have_short_name, tvb, offset, 4, have_short_name);
643     proto_tree_add_uint(im_tree, hf_dplay_spp_have_long_name, tvb, offset, 4, have_long_name);
644     proto_tree_add_uint(im_tree, hf_dplay_spp_sp_length_type, tvb, offset, 4, sp_length_type);
645     proto_tree_add_uint(im_tree, hf_dplay_spp_pd_length_type, tvb, offset, 4, pd_length_type);
646     proto_tree_add_uint(im_tree, hf_dplay_spp_player_count_type, tvb, offset, 4, player_count_type);
647     proto_tree_add_uint(im_tree, hf_dplay_spp_have_parent_id, tvb, offset, 4, have_parent_id);
648     proto_tree_add_uint(im_tree, hf_dplay_spp_shortcut_count_type, tvb, offset, 4, shortcut_count_type);
649     offset+=4;
650
651     if (is_sysplayer) {
652         proto_tree_add_item(tree, hf_dplay_spp_dialect, tvb, offset, 4, TRUE);
653     } else {
654         proto_tree_add_item(tree, hf_dplay_spp_sys_player_id, tvb, offset, 4, FALSE);
655     }
656     offset += 4;
657
658     if (have_short_name) {
659         offset = display_unicode_string(tree, hf_dplay_spp_short_name, tvb, offset);
660     }
661
662     if (have_long_name) {
663         offset = display_unicode_string(tree, hf_dplay_spp_long_name, tvb, offset);
664     }
665
666     if (pd_length_type) {
667         len = spp_get_value(pd_length_type, tvb, offset, &player_data_length);
668         proto_tree_add_item(tree, hf_dplay_spp_player_data_length, tvb, offset, len, TRUE);
669         offset += len;
670         proto_tree_add_item(tree, hf_dplay_spp_player_data, tvb, offset, player_data_length, FALSE);
671         offset += player_data_length;
672     }
673
674     if (sp_length_type) {
675         len = spp_get_value(sp_length_type, tvb, offset, &sp_data_length);
676         proto_tree_add_item(tree, hf_dplay_spp_sp_data_length, tvb, offset, len, TRUE);
677         offset += len;
678         proto_tree_add_item(tree, hf_dplay_spp_sp_data, tvb, offset, sp_data_length, FALSE);
679         offset += sp_data_length;
680     }
681
682     if (player_count_type) {
683         guint32 i;
684
685         len = spp_get_value(player_count_type, tvb, offset, &player_count);
686         proto_tree_add_item(tree, hf_dplay_spp_player_count, tvb, offset, len, TRUE);
687         offset += len;
688         for (i=0; i < player_count; ++i) {
689             proto_tree_add_item(tree, hf_dplay_spp_player_id, tvb, offset, 4, FALSE); offset += 4;
690         }
691     }
692
693     if (have_parent_id) {
694         proto_tree_add_item(tree, hf_dplay_spp_parent_id, tvb, offset, 4, FALSE); offset += 4;
695     }
696
697     if (shortcut_count_type) {
698         guint32 i;
699
700         len = spp_get_value(shortcut_count_type, tvb, offset, &shortcut_count);
701         proto_tree_add_item(tree, hf_dplay_spp_shortcut_count, tvb, offset, len, TRUE);
702         offset += len;
703         for (i=0; i < shortcut_count; ++i) {
704             proto_tree_add_item(tree, hf_dplay_spp_shortcut_id, tvb, offset, 4, FALSE); offset += 4;
705         }
706     }
707
708     return offset;
709 }
710
711 static gint dissect_security_desc(proto_tree *tree, tvbuff_t *tvb, gint offset)
712 {
713     proto_tree_add_item(tree, hf_dplay_sd_size, tvb, offset, 4, TRUE); offset += 4;
714     proto_tree_add_item(tree, hf_dplay_sd_flags, tvb, offset, 4, TRUE); offset += 4;
715     proto_tree_add_item(tree, hf_dplay_sd_sspi, tvb, offset, 4, TRUE); offset += 4;
716     proto_tree_add_item(tree, hf_dplay_sd_capi, tvb, offset, 4, TRUE); offset += 4;
717     proto_tree_add_item(tree, hf_dplay_sd_capi_type, tvb, offset, 4, TRUE); offset += 4;
718     proto_tree_add_item(tree, hf_dplay_sd_enc_alg, tvb, offset, 4, TRUE); offset += 4;
719     return offset;
720 }
721
722 static gint dissect_dplay_header(proto_tree *tree, tvbuff_t *tvb, gint offset)
723 {
724     guint32 mixed, size, token;
725
726     mixed = tvb_get_letohl(tvb, offset);
727     size = mixed & 0x000FFFFF;
728     token = (mixed & 0xFFF00000) >> 20;
729
730     proto_tree_add_uint(tree, hf_dplay_size, tvb, offset, 4, size);
731     proto_tree_add_uint(tree, hf_dplay_token, tvb, offset, 4, token);
732     offset += 4;
733     offset = dissect_sockaddr_in(tree, tvb, offset);
734     proto_tree_add_item(tree, hf_dplay_play_str, tvb, offset, 4, TRUE); offset += 4;
735     proto_tree_add_item(tree, hf_dplay_command, tvb, offset, 2, TRUE); offset += 2;
736     proto_tree_add_item(tree, hf_dplay_proto_dialect, tvb, offset, 2, TRUE); offset += 2;
737     return offset;
738 }
739
740 static gint dissect_type01_message(proto_tree *tree, tvbuff_t *tvb, gint offset)
741 {
742     guint32 name_offset;
743
744     offset = dissect_session_desc(tree, tvb, offset);
745     name_offset = tvb_get_letohl(tvb, offset);
746     proto_tree_add_item(tree, hf_dplay_type_01_name_offset, tvb, offset, 4, TRUE); offset += 4;
747
748     if (name_offset != 0) {
749         offset = display_unicode_string(tree, hf_dplay_type_01_game_name, tvb, offset);
750     }
751     return offset;
752 }
753
754 static gint dissect_type02_message(proto_tree *tree, tvbuff_t *tvb, gint offset)
755 {
756     guint32 passwd_offset;
757     guint32 flags;
758     proto_item *flags_item = NULL;
759     proto_tree *flags_tree = NULL;
760
761     passwd_offset = tvb_get_letohl(tvb, offset + 16);
762     flags = tvb_get_letohl(tvb, offset + 20);
763
764     proto_tree_add_item(tree, hf_dplay_type_02_game_guid, tvb, offset, 16, FALSE); offset += 16;
765     proto_tree_add_item(tree, hf_dplay_type_02_password_offset, tvb, offset, 4, TRUE); offset += 4;
766
767     flags_item = proto_tree_add_item(tree, hf_dplay_type_02_flags, tvb, offset, 4, TRUE);
768     flags_tree = proto_item_add_subtree(flags_item, ett_dplay_type02_flags);
769     proto_tree_add_boolean(flags_tree, hf_enum_sess_flag_passwd, tvb, offset, 4, flags);
770     proto_tree_add_boolean(flags_tree, hf_enum_sess_flag_all, tvb, offset, 4, flags);
771     proto_tree_add_boolean(flags_tree, hf_enum_sess_flag_join, tvb, offset, 4, flags);
772     offset += 4;
773
774     if (passwd_offset != 0) {
775         offset = display_unicode_string(tree, hf_dplay_type_02_password, tvb, offset);
776     }
777     return offset;
778 }
779
780 static gint dissect_type05_message(proto_tree *tree, tvbuff_t *tvb, gint offset)
781 {
782     proto_item *flag_item;
783     proto_item *flag_tree;
784     guint32 flags;
785
786     flags = tvb_get_letohl(tvb, offset);
787     flag_item = proto_tree_add_item(tree, hf_dplay_type_05_flags, tvb, offset, 4, TRUE);
788     flag_tree = proto_item_add_subtree(flag_item, ett_dplay_type05_flags);
789     proto_tree_add_boolean(flag_tree, hf_dplay_type_05_secure, tvb, offset, 4, flags);
790     proto_tree_add_boolean(flag_tree, hf_dplay_type_05_unknown, tvb, offset, 4, flags);
791     proto_tree_add_boolean(flag_tree, hf_dplay_type_05_local, tvb, offset, 4, flags);
792     proto_tree_add_boolean(flag_tree, hf_dplay_type_05_name_server, tvb, offset, 4, flags);
793     proto_tree_add_boolean(flag_tree, hf_dplay_type_05_system_player, tvb, offset, 4, flags);
794     offset += 4;
795     return offset;
796 }
797
798 static gint dissect_type07_message(proto_tree *tree, tvbuff_t *tvb, gint offset)
799 {
800     guint32 sspi_offset, capi_offset;
801
802     proto_tree_add_item(tree, hf_dplay_type_07_dpid, tvb, offset, 4, FALSE); offset += 4;
803     offset = dissect_security_desc(tree, tvb, offset);
804
805     sspi_offset = tvb_get_letohl(tvb, offset);
806     proto_tree_add_item(tree, hf_dplay_type_07_sspi_offset, tvb, offset, 4, TRUE); offset += 4;
807
808     capi_offset = tvb_get_letohl(tvb, offset);
809     proto_tree_add_item(tree, hf_dplay_type_07_capi_offset, tvb, offset, 4, TRUE); offset += 4;
810
811     proto_tree_add_item(tree, hf_dplay_type_07_hresult, tvb, offset, 4, TRUE); offset += 4;
812
813     if (sspi_offset) {
814         offset = display_unicode_string(tree, hf_dplay_type_07_sspi, tvb, offset);
815     }
816
817     if (capi_offset) {
818         offset = display_unicode_string(tree, hf_dplay_type_07_capi, tvb, offset);
819     }
820     return offset;
821 }
822
823 static gint dissect_player_message(proto_tree *tree, tvbuff_t *tvb, gint offset)
824 {
825     guint32 pp_ofs;
826
827     proto_tree_add_item(tree, hf_dplay_multi_id_to, tvb, offset, 4, FALSE); offset += 4;
828     proto_tree_add_item(tree, hf_dplay_multi_player_id, tvb, offset, 4, FALSE); offset += 4;
829     proto_tree_add_item(tree, hf_dplay_multi_group_id, tvb, offset, 4, FALSE); offset += 4;
830     pp_ofs = tvb_get_letohl(tvb, offset);
831     proto_tree_add_item(tree, hf_dplay_multi_create_offset, tvb, offset, 4, TRUE); offset += 4;
832     proto_tree_add_item(tree, hf_dplay_multi_password_offset, tvb, offset, 4, TRUE); offset += 4;
833     if (pp_ofs)
834         offset = dissect_packed_player(tree, tvb, offset);
835     if (tvb_bytes_exist(tvb, offset, 2))
836         offset = display_unicode_string(tree, hf_dplay_multi_password, tvb, offset);
837     return offset;
838 }
839
840 static gint dissect_type0f_message(proto_tree *tree, tvbuff_t *tvb, gint offset)
841 {
842     guint32 data_size;
843
844     proto_tree_add_item(tree, hf_dplay_type_0f_id_to, tvb, offset, 4, FALSE); offset += 4;
845     proto_tree_add_item(tree, hf_dplay_type_0f_id, tvb, offset, 4, FALSE); offset += 4;
846     data_size = tvb_get_letohl(tvb, offset);
847     proto_tree_add_item(tree, hf_dplay_type_0f_data_size, tvb, offset, 4, TRUE); offset += 4;
848     proto_tree_add_item(tree, hf_dplay_type_0f_data_offset, tvb, offset, 4, TRUE); offset += 4;
849     proto_tree_add_item(tree, hf_dplay_type_0f_data, tvb, offset, data_size, FALSE);
850     offset += data_size;
851
852     return offset;
853 }
854
855 static gint dissect_type13_message(proto_tree *tree, tvbuff_t *tvb, gint offset)
856 {
857     guint32 pp_ofs, pw_ofs;
858
859     proto_tree_add_item(tree, hf_dplay_type_13_id_to, tvb, offset, 4, FALSE); offset += 4;
860     proto_tree_add_item(tree, hf_dplay_type_13_player_id, tvb, offset, 4, FALSE); offset += 4;
861     proto_tree_add_item(tree, hf_dplay_type_13_group_id, tvb, offset, 4, FALSE); offset += 4;
862     pp_ofs = tvb_get_letohl(tvb, offset);
863     proto_tree_add_item(tree, hf_dplay_type_13_create_offset, tvb, offset, 4, TRUE); offset += 4;
864     pw_ofs = tvb_get_letohl(tvb, offset);
865     proto_tree_add_item(tree, hf_dplay_type_13_password_offset, tvb, offset, 4, TRUE); offset += 4;
866     if (pp_ofs)
867         offset = dissect_packed_player(tree, tvb, offset);
868     if (pw_ofs)
869         offset = display_unicode_string(tree, hf_dplay_type_13_password, tvb, offset);
870     proto_tree_add_item(tree, hf_dplay_type_13_tick_count, tvb, offset, 4, TRUE); offset += 4;
871
872     return offset;
873 }
874
875 static gint dissect_type15_message(proto_tree *tree, tvbuff_t *tvb, gint offset)
876 {
877     guint16 second_message_type;
878     proto_item *enc_item = NULL;
879     proto_tree *enc_tree = NULL;
880     second_message_type = tvb_get_letohs(tvb, 72);
881
882     proto_tree_add_item(tree, hf_dplay_message_guid, tvb, offset, 16, FALSE); offset += 16;
883     proto_tree_add_item(tree, hf_dplay_type_15_packet_idx, tvb, offset, 4, TRUE); offset += 4;
884     proto_tree_add_item(tree, hf_dplay_type_15_data_size, tvb, offset, 4, TRUE); offset += 4;
885     proto_tree_add_item(tree, hf_dplay_type_15_offset, tvb, offset, 4, TRUE); offset += 4;
886     proto_tree_add_item(tree, hf_dplay_type_15_total_packets, tvb, offset, 4, TRUE); offset += 4;
887     proto_tree_add_item(tree, hf_dplay_type_15_msg_size, tvb, offset, 4, TRUE); offset += 4;
888     proto_tree_add_item(tree, hf_dplay_type_15_packet_offset, tvb, offset, 4, TRUE); offset += 4;
889
890     enc_item = proto_tree_add_text(tree, tvb, offset, -1, "DirectPlay encapsulated packet");
891     enc_tree = proto_item_add_subtree(enc_item, ett_dplay_enc_packet);
892
893     proto_tree_add_item(enc_tree, hf_dplay_play_str_2, tvb, offset, 4, FALSE); offset += 4;
894     proto_tree_add_item(enc_tree, hf_dplay_command_2, tvb, offset, 2, TRUE); offset += 2;
895     proto_tree_add_item(enc_tree, hf_dplay_proto_dialect_2, tvb, offset, 2, TRUE); offset += 2;
896
897     switch(second_message_type)
898     {
899         case 0x0005:
900             offset = dissect_type05_message(enc_tree, tvb, offset);
901             break;
902         case 0x0007:
903             offset = dissect_type05_message(enc_tree, tvb, offset);
904             break;
905         case 0x0008:
906         case 0x0009:
907         case 0x000b:
908         case 0x000c:
909         case 0x000d:
910         case 0x000e:
911         case 0x002e:
912             offset = dissect_player_message(enc_tree, tvb, offset);
913             break;
914         case 0x0013:
915             offset = dissect_type13_message(enc_tree, tvb, offset);
916             break;
917         case 0x001a:
918             offset = dissect_type1a_message(enc_tree, tvb, offset);
919             break;
920     }
921
922     return offset;
923 }
924
925 static gint dissect_ping_message(proto_tree *tree, tvbuff_t *tvb, gint offset)
926 {
927     proto_tree_add_item(tree, hf_dplay_ping_id_from, tvb, offset, 4, FALSE); offset += 4;
928     proto_tree_add_item(tree, hf_dplay_ping_tick_count, tvb, offset, 4, TRUE); offset += 4;
929
930     return offset;
931 }
932
933 static gint dissect_type1a_message(proto_tree *tree, tvbuff_t *tvb, gint offset)
934 {
935     guint32 sn_ofs, pw_ofs;
936
937     proto_tree_add_item(tree, hf_dplay_type_1a_id_to, tvb, offset, 4, FALSE); offset += 4;
938     sn_ofs = tvb_get_letohl(tvb, offset);
939     proto_tree_add_item(tree, hf_dplay_type_1a_sess_name_ofs, tvb, offset, 4, TRUE); offset += 4;
940     pw_ofs = tvb_get_letohl(tvb, offset);
941     proto_tree_add_item(tree, hf_dplay_type_1a_password_ofs, tvb, offset, 4, TRUE); offset += 4;
942     offset = dissect_session_desc(tree, tvb, offset);
943
944     if (sn_ofs) {
945         offset = display_unicode_string(tree, hf_dplay_type_1a_session_name, tvb, offset);
946     }
947
948     if (pw_ofs) {
949         offset = display_unicode_string(tree, hf_dplay_type_1a_password, tvb, offset);
950     }
951
952     return offset;
953 }
954
955 static gint dissect_type29_message(proto_tree *tree, tvbuff_t *tvb, gint offset)
956 {
957     guint32 password_offset = tvb_get_letohl(tvb, offset + 24);
958     gint player_count, group_count, shortcut_count;
959     gint i;
960
961     player_count = tvb_get_letohl(tvb, offset);
962     proto_tree_add_item(tree, hf_dplay_type_29_player_count, tvb, offset, 4, TRUE); offset += 4;
963     group_count = tvb_get_letohl(tvb, offset);
964     proto_tree_add_item(tree, hf_dplay_type_29_group_count, tvb, offset, 4, TRUE); offset += 4;
965     proto_tree_add_item(tree, hf_dplay_type_29_packed_offset, tvb, offset, 4, TRUE); offset += 4;
966     shortcut_count = tvb_get_letohl(tvb, offset);
967     proto_tree_add_item(tree, hf_dplay_type_29_shortcut_count, tvb, offset, 4, TRUE); offset += 4;
968     proto_tree_add_item(tree, hf_dplay_type_29_description_offset, tvb, offset, 4, TRUE); offset += 4;
969     proto_tree_add_item(tree, hf_dplay_type_29_name_offset, tvb, offset, 4, TRUE); offset += 4;
970     proto_tree_add_item(tree, hf_dplay_type_29_password_offset, tvb, offset, 4, TRUE); offset += 4;
971     offset = dissect_session_desc(tree, tvb, offset);
972     offset = display_unicode_string(tree, hf_dplay_type_29_game_name, tvb, offset);
973
974     if (password_offset != 0) {
975         offset = display_unicode_string(tree, hf_dplay_type_29_password, tvb, offset);
976     }
977
978     for (i=0; i < player_count; ++i) {
979         proto_item *spp_item;
980         proto_tree *spp_tree;
981
982         spp_item = proto_tree_add_text(tree, tvb, offset, 0, "Player %d", i);
983         spp_tree = proto_item_add_subtree(spp_item, ett_dplay_type29_spp);
984         offset = dissect_dplay_super_packed_player(spp_tree, tvb, offset);
985     }
986
987     for (i=0; i < group_count; ++i) {
988         proto_item *spp_item;
989         proto_tree *spp_tree;
990
991         spp_item = proto_tree_add_text(tree, tvb, offset, 0, "Group %d", i);
992         spp_tree = proto_item_add_subtree(spp_item, ett_dplay_type29_spp);
993         offset = dissect_dplay_super_packed_player(spp_tree, tvb, offset);
994     }
995
996     for (i=0; i < shortcut_count; ++i) {
997         proto_item *spp_item;
998         proto_tree *spp_tree;
999
1000         spp_item = proto_tree_add_text(tree, tvb, offset, 0, "Shortcut %d", i);
1001         spp_tree = proto_item_add_subtree(spp_item, ett_dplay_type29_spp);
1002         offset = dissect_dplay_super_packed_player(spp_tree, tvb, offset);
1003     }
1004
1005     return offset;
1006 }
1007
1008 static gint dissect_type2f_message(proto_tree *tree, tvbuff_t *tvb, gint offset)
1009 {
1010     proto_tree_add_item(tree, hf_dplay_type_2f_dpid, tvb, offset, 4, FALSE); offset += 4;
1011     return offset;
1012 }
1013
1014 static void dissect_dplay(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1015 {
1016     guint16 message_type;
1017     guint16 second_message_type = -1;
1018     guint16 proto_version;
1019     guint16 packet_size;
1020     guint32 dplay_id;
1021     guint8 play_id[] = {'p','l','a','y'};
1022
1023     packet_size = tvb_get_letohs(tvb, 0);
1024     dplay_id = tvb_get_letohl(tvb, 20);
1025     message_type = tvb_get_letohs(tvb, 24);
1026     proto_version = tvb_get_letohs(tvb, 26);
1027
1028     if(memcmp(play_id, (guint8 *)&dplay_id, 4) != 0)
1029     {
1030         if(check_col(pinfo->cinfo, COL_PROTOCOL))
1031             col_set_str(pinfo->cinfo, COL_PROTOCOL, "DPLAY");
1032         /* Clear out stuff in the info column */
1033         if(check_col(pinfo->cinfo,COL_INFO))
1034             col_clear(pinfo->cinfo,COL_INFO);
1035         if(check_col(pinfo->cinfo,COL_INFO))
1036             col_add_fstr(pinfo->cinfo,COL_INFO, "DPlay data packet");
1037         return;
1038     }
1039
1040     if(message_type == 0x0015)
1041     {
1042         second_message_type = tvb_get_letohs(tvb, 72);
1043     }
1044
1045     if(check_col(pinfo->cinfo, COL_PROTOCOL))
1046         col_set_str(pinfo->cinfo, COL_PROTOCOL, "DPLAY");
1047     /* Clear out stuff in the info column */
1048     if(check_col(pinfo->cinfo,COL_INFO))
1049     {
1050         col_clear(pinfo->cinfo,COL_INFO);
1051     }
1052
1053     if(check_col(pinfo->cinfo,COL_INFO))
1054     {
1055         if(message_type == 0x0015)
1056             col_add_fstr(pinfo->cinfo,COL_INFO, "%s: %s, holding a %s",
1057                 val_to_str(proto_version, dplay_proto_dialect_val, "Unknown (0x%04x)"),
1058                 val_to_str(message_type, dplay_command_val, "Unknown (0x%04x)"),
1059                 val_to_str(second_message_type, dplay_command_val, "Unknown (0x%04x)"));
1060         else
1061             col_add_fstr(pinfo->cinfo,COL_INFO, "%s: %s",
1062                 val_to_str(proto_version, dplay_proto_dialect_val, "Unknown (0x%04x)"),
1063                 val_to_str(message_type, dplay_command_val, "Unknown (0x%04x)"));
1064     }
1065
1066     if(tree)
1067     {
1068         proto_item *dplay_item = NULL;
1069         proto_item *header_item = NULL;
1070         proto_item *data_item = NULL;
1071         proto_tree *dplay_tree = NULL;
1072         proto_tree *dplay_header = NULL;
1073         proto_tree *dplay_data = NULL;
1074         gint offset = 0;
1075
1076         dplay_item = proto_tree_add_item(tree, proto_dplay, tvb, 0, -1, FALSE);
1077         dplay_tree = proto_item_add_subtree(dplay_item, ett_dplay);
1078         header_item = proto_tree_add_text(dplay_tree, tvb, offset, DPLAY_HEADER_OFFSET, "DirectPlay header");
1079         dplay_header = proto_item_add_subtree(header_item, ett_dplay_header);
1080
1081         offset = dissect_dplay_header(dplay_header, tvb, offset);
1082
1083         /* Special handling for empty type 0x0004 packets */
1084         if(message_type == 0x0004)
1085             return;
1086
1087         data_item = proto_tree_add_text(dplay_tree, tvb, offset, -1, "DirectPlay data");
1088         dplay_data = proto_item_add_subtree(data_item, ett_dplay_data);
1089
1090         switch(message_type)
1091         {
1092             case 0x0001:
1093                 offset = dissect_type01_message(dplay_data, tvb, offset);
1094                 break;
1095             case 0x0002:
1096                 offset = dissect_type02_message(dplay_data, tvb, offset);
1097                 break;
1098             case 0x0004:
1099                 /* We should not get here. */
1100                 break;
1101             case 0x0005:
1102                 offset = dissect_type05_message(dplay_data, tvb, offset);
1103                 break;
1104             case 0x0007:
1105                 offset = dissect_type07_message(dplay_data, tvb, offset);
1106                 break;
1107             case 0x0008:
1108             case 0x0009:
1109             /* type 0a doesn't have a dplay header and is not handled here */
1110             case 0x000b:
1111             case 0x000c:
1112             case 0x000d:
1113             case 0x000e:
1114             case 0x002e:
1115             case 0x0038:
1116                 offset = dissect_player_message(dplay_data, tvb, offset);
1117                 break;
1118             case 0x000f:
1119                 offset = dissect_type0f_message(dplay_data, tvb, offset);
1120                 break;
1121             case 0x0013:
1122                 offset = dissect_type13_message(dplay_data, tvb, offset);
1123                 break;
1124             case 0x0015:
1125                 offset = dissect_type15_message(dplay_data, tvb, offset);
1126                 break;
1127             case 0x0016:
1128             case 0x0017:
1129                 offset = dissect_ping_message(dplay_data, tvb, offset);
1130                 break;
1131             case 0x001a:
1132                 offset = dissect_type1a_message(dplay_data, tvb, offset);
1133                 break;
1134             case 0x0029:
1135                 offset = dissect_type29_message(dplay_data, tvb, offset);
1136                 break;
1137             case 0x002f:
1138                 offset = dissect_type2f_message(dplay_data, tvb, offset);
1139                 break;
1140         }
1141     }
1142
1143 }
1144
1145 static void dissect_dplay_player_msg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1146 {
1147     guint32 mixed, size, token;
1148
1149     if(check_col(pinfo->cinfo, COL_PROTOCOL))
1150         col_set_str(pinfo->cinfo, COL_PROTOCOL, "DPLAY");
1151     /* Clear out stuff in the info column */
1152     if(check_col(pinfo->cinfo,COL_INFO))
1153         col_clear(pinfo->cinfo,COL_INFO);
1154     if(check_col(pinfo->cinfo,COL_INFO))
1155         col_add_fstr(pinfo->cinfo,COL_INFO, "DPlay player to player message");
1156
1157     if(tree)
1158     {
1159         proto_item *dplay_item = NULL;
1160         proto_item *data_item = NULL;
1161         proto_tree *dplay_tree = NULL;
1162         proto_tree *data_tree = NULL;
1163         gint offset = 0;
1164
1165         dplay_item = proto_tree_add_item(tree, proto_dplay, tvb, offset, -1, FALSE);
1166         dplay_tree = proto_item_add_subtree(dplay_item, ett_dplay);
1167         data_item  = proto_tree_add_text(dplay_tree, tvb, offset, -1, "Message content");
1168         data_tree  = proto_item_add_subtree(data_item, ett_dplay_data);
1169         mixed = tvb_get_letohl(tvb, offset);
1170         size = mixed & 0x000FFFFF;
1171         token = (mixed & 0xFFF00000) >> 20;
1172
1173         proto_tree_add_uint(data_tree, hf_dplay_size, tvb, offset, 4, size);
1174         proto_tree_add_uint(data_tree, hf_dplay_token, tvb, offset, 4, token);
1175         offset += 4;
1176         offset = dissect_sockaddr_in(data_tree, tvb, offset);
1177         /* Now there's two dplay IDs iff the session desc does not have the
1178          * "short player message" flag set */
1179         proto_tree_add_item(data_tree, hf_dplay_player_msg, tvb, offset, -1, FALSE);
1180
1181     }
1182 }
1183 static gboolean heur_dissect_dplay(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1184 {
1185     guint8 signature[] = {'p','l','a','y'};
1186     guint32 dplay_id, token;
1187
1188     if(!tvb_bytes_exist(tvb, 0, 24))
1189         return FALSE;
1190
1191     dplay_id = tvb_get_letohl(tvb, 20);
1192     if( memcmp(signature, (guint8 *)&dplay_id, 4) == 0) {
1193         dissect_dplay(tvb, pinfo, tree);
1194         return TRUE;
1195     }
1196
1197     /* There is a player to player message that does not contain "play" */
1198     token = tvb_get_letohl(tvb, 0);
1199     token = (token & 0xfff00000) >> 20;
1200     if (token == 0xfab || token == 0xbab || token == 0xcab) {
1201       /* Check the s_addr_in structure */
1202       if (tvb_get_letohs(tvb, 4) == WINSOCK_AF_INET) {
1203         int offset;
1204         for (offset = 12; offset <= 20; offset++)
1205           if (tvb_get_guint8(tvb, offset) != 0)
1206             return FALSE;
1207
1208         dissect_dplay_player_msg(tvb, pinfo, tree);
1209         return TRUE;
1210       }
1211     }
1212
1213     return FALSE;
1214 }
1215
1216 void proto_register_dplay()
1217 {
1218     static hf_register_info hf [] = {
1219     /* Common data fields */
1220     { &hf_dplay_size,
1221         { "DirectPlay package size", "dplay.size", FT_UINT32, BASE_DEC,
1222         NULL, 0x0, "", HFILL}},
1223     { &hf_dplay_token,
1224         { "DirectPlay token", "dplay.token", FT_UINT32, BASE_HEX,
1225         VALS(dplay_token_val), 0x0, "", HFILL}},
1226     { &hf_dplay_saddr_af,
1227         { "DirectPlay s_addr_in address family", "dplay.saddr.af", FT_UINT16, BASE_HEX,
1228         VALS(dplay_af_val), 0x0, "", HFILL}},
1229     { &hf_dplay_saddr_port,
1230         { "DirectPlay s_addr_in port", "dplay.saddr.port", FT_UINT16, BASE_DEC,
1231         NULL, 0x0, "", HFILL}},
1232     { &hf_dplay_saddr_ip,
1233         { "DirectPlay s_addr_in ip address", "dplay.saddr.ip", FT_IPv4, BASE_NONE,
1234         NULL, 0x0, "", HFILL}},
1235     { &hf_dplay_saddr_padding,
1236         { "DirectPlay s_addr_in null padding", "dplay.saddr.padding", FT_BYTES, BASE_NONE,
1237         NULL, 0x0, "", HFILL}},
1238     { &hf_dplay_play_str,
1239         { "DirectPlay action string", "dplay.dplay_str", FT_STRING, BASE_NONE,
1240         NULL, 0x0, "", HFILL}},
1241     { &hf_dplay_command,
1242         { "DirectPlay command", "dplay.command", FT_UINT16, BASE_HEX,
1243         VALS(dplay_command_val), 0x0, "", HFILL}},
1244     { &hf_dplay_proto_dialect,
1245         { "DirectPlay dialect version", "dplay.dialect.version", FT_UINT16, BASE_HEX,
1246         VALS(dplay_proto_dialect_val), 0x0, "", HFILL}},
1247     { &hf_dplay_play_str_2,
1248         { "DirectPlay second action string", "dplay.dplay_str_2", FT_STRING, BASE_NONE,
1249         NULL, 0x0, "", HFILL}},
1250     { &hf_dplay_command_2,
1251         { "DirectPlay second command", "dplay.command_2", FT_UINT16, BASE_HEX,
1252         VALS(dplay_command_val), 0x0, "", HFILL}},
1253     { &hf_dplay_proto_dialect_2,
1254         { "DirectPlay second dialect version", "dplay.dialect.version_2", FT_UINT16, BASE_HEX,
1255         VALS(dplay_proto_dialect_val), 0x0, "", HFILL}},
1256     { &hf_dplay_player_msg,
1257         { "DirectPlay Player to Player message", "dplay.player_msg", FT_BYTES, BASE_HEX,
1258         NULL, 0x0, "", HFILL}},
1259
1260     /* Session Desc structure fields */
1261     { &hf_dplay_sess_desc_flags,
1262         { "DirectPlay session desc flags", "dplay.flags", FT_UINT32, BASE_HEX,
1263         NULL, 0x0, "", HFILL}},
1264     { &hf_dplay_flags_no_create_players,
1265         { "no create players flag", "dplay.flags.no_create_players", FT_BOOLEAN, 32,
1266         TFS(&tfs_dplay_flag), DPLAY_FLAG_NO_CREATE_PLAYERS, "No Create Players", HFILL}},
1267     { &hf_dplay_flags_0002,
1268         { "unused", "dplay.flags.unused", FT_BOOLEAN, 32,
1269         TFS(&tfs_dplay_flag), DPLAY_FLAG_0002, "Unused", HFILL}},
1270     { &hf_dplay_flags_migrate_host,
1271         { "migrate host flag", "dplay.flags.migrate_host", FT_BOOLEAN, 32,
1272         TFS(&tfs_dplay_flag), DPLAY_FLAG_MIGRATE_HOST, "Migrate Host", HFILL}},
1273     { &hf_dplay_flags_short_player_msg,
1274         { "short player message", "dplay.flags.short_player_msg", FT_BOOLEAN, 32,
1275         TFS(&tfs_dplay_flag), DPLAY_FLAG_SHORT_PLAYER_MSG, "Short Player Msg", HFILL}},
1276     { &hf_dplay_flags_ignored,
1277         { "ignored", "dplay.flags.ignored", FT_BOOLEAN, 32,
1278         TFS(&tfs_dplay_flag), DPLAY_FLAG_IGNORED, "Ignored", HFILL}},
1279     { &hf_dplay_flags_can_join,
1280         { "can join", "dplay.flags.can_join", FT_BOOLEAN, 32,
1281         TFS(&tfs_dplay_flag), DPLAY_FLAG_CAN_JOIN, "Can Join", HFILL}},
1282     { &hf_dplay_flags_use_ping,
1283         { "use ping", "dplay.flags.use_ping", FT_BOOLEAN, 32,
1284         TFS(&tfs_dplay_flag), DPLAY_FLAG_USE_PING, "Use Ping", HFILL}},
1285     { &hf_dplay_flags_no_player_updates,
1286         { "no player updates", "dplay.flags.no_player_updates", FT_BOOLEAN, 32,
1287         TFS(&tfs_dplay_flag), DPLAY_FLAG_NO_P_UPD, "No Player Updates", HFILL}},
1288     { &hf_dplay_flags_use_auth,
1289         { "use authentication", "dplay.flags.use_auth", FT_BOOLEAN, 32,
1290         TFS(&tfs_dplay_flag), DPLAY_FLAG_USE_AUTH, "Use Auth", HFILL}},
1291     { &hf_dplay_flags_private_session,
1292         { "private session", "dplay.flags.priv_sess", FT_BOOLEAN, 32,
1293         TFS(&tfs_dplay_flag), DPLAY_FLAG_PRIV_SESS, "Priv Session", HFILL}},
1294     { &hf_dplay_flags_password_req,
1295         { "password required", "dplay.flags.pass_req", FT_BOOLEAN, 32,
1296         TFS(&tfs_dplay_flag), DPLAY_FLAG_PASS_REQ, "Pass Req", HFILL}},
1297     { &hf_dplay_flags_route,
1298         { "route via game host", "dplay.flags.route", FT_BOOLEAN, 32,
1299         TFS(&tfs_dplay_flag), DPLAY_FLAG_ROUTE, "Route", HFILL}},
1300     { &hf_dplay_flags_server_player_only,
1301         { "get server player only", "dplay.flags.srv_p_only", FT_BOOLEAN, 32,
1302         TFS(&tfs_dplay_flag), DPLAY_FLAG_SRV_ONLY, "Svr Player Only", HFILL}},
1303     { &hf_dplay_flags_reliable,
1304         { "use reliable protocol", "dplay.flags.reliable", FT_BOOLEAN, 32,
1305         TFS(&tfs_dplay_flag), DPLAY_FLAG_RELIABLE, "Reliable", HFILL}},
1306     { &hf_dplay_flags_preserve_order,
1307         { "preserve order", "dplay.flags.order", FT_BOOLEAN, 32,
1308         TFS(&tfs_dplay_flag), DPLAY_FLAG_ORDER, "Order", HFILL}},
1309     { &hf_dplay_flags_optimize_latency,
1310         { "optimize for latency", "dplay.flags.opt_latency", FT_BOOLEAN, 32,
1311         TFS(&tfs_dplay_flag), DPLAY_FLAG_OPT_LAT, "Opt Latency", HFILL}},
1312     { &hf_dplay_flags_acqire_voice,
1313         { "acquire voice", "dplay.flags.acq_voice", FT_BOOLEAN, 32,
1314         TFS(&tfs_dplay_flag), DPLAY_FLAG_ACQ_VOICE, "Acq Voice", HFILL}},
1315     { &hf_dplay_flags_no_sess_desc_changes,
1316         { "no session desc changes", "dplay.flags.no_sess_desc", FT_BOOLEAN, 32,
1317         TFS(&tfs_dplay_flag), DPLAY_FLAG_NO_SESS_DESC_CHANGES, "No Sess Desc Changes", HFILL}},
1318     { &hf_dplay_instance_guid,
1319         { "DirectPlay instance guid", "dplay.instance.guid", FT_GUID, BASE_NONE,
1320         NULL, 0x0, "", HFILL}},
1321     { &hf_dplay_game_guid,
1322         { "DirectPlay game GUID", "dplay.game.guid", FT_GUID, BASE_NONE,
1323         NULL, 0x0, "", HFILL}},
1324     { &hf_dplay_sess_desc_length,
1325         { "DirectPlay session desc length", "dplay.sess_desc.length", FT_UINT32, BASE_DEC,
1326         NULL, 0x0, "", HFILL}},
1327     { &hf_dplay_max_players,
1328         { "DirectPlay max players ", "dplay.sess_desc.max_players", FT_UINT32, BASE_DEC,
1329         NULL, 0x0, "", HFILL}},
1330     { &hf_dplay_curr_players,
1331         { "DirectPlay current players", "dplay.sess_desc.curr_players", FT_UINT32, BASE_DEC,
1332         NULL, 0x0, "", HFILL}},
1333     { &hf_dplay_sess_name_ptr,
1334         { "Session description name pointer placeholder", "dplay.sess_desc.name_ptr", FT_BYTES, BASE_HEX,
1335         NULL, 0x0, "", HFILL}},
1336     { &hf_dplay_passwd_ptr,
1337         { "Session description password pointer placeholder", "dplay.sess_desc.pw_ptr", FT_BYTES, BASE_HEX,
1338         NULL, 0x0, "", HFILL}},
1339     { &hf_dplay_sess_desc_reserved_1,
1340         { "Session description reserved 1", "dplay.sess_desc.res_1", FT_BYTES, BASE_HEX,
1341         NULL, 0x0, "", HFILL}},
1342     { &hf_dplay_sess_desc_reserved_2,
1343         { "Session description reserved 2", "dplay.sess_desc.res_2", FT_BYTES, BASE_HEX,
1344         NULL, 0x0, "", HFILL}},
1345     { &hf_dplay_sess_desc_user_1,
1346         { "Session description user defined 1", "dplay.sess_desc.user_1", FT_BYTES, BASE_HEX,
1347         NULL, 0x0, "", HFILL}},
1348     { &hf_dplay_sess_desc_user_2,
1349         { "Session description user defined 2", "dplay.sess_desc.user_2", FT_BYTES, BASE_HEX,
1350         NULL, 0x0, "", HFILL}},
1351     { &hf_dplay_sess_desc_user_3,
1352         { "Session description user defined 3", "dplay.sess_desc.user_3", FT_BYTES, BASE_HEX,
1353         NULL, 0x0, "", HFILL}},
1354     { &hf_dplay_sess_desc_user_4,
1355         { "Session description user defined 4", "dplay.sess_desc.user_4", FT_BYTES, BASE_HEX,
1356         NULL, 0x0, "", HFILL}},
1357
1358     /* PackedPlayer structure fields */
1359     { &hf_dplay_pp_size,
1360         { "PackedPlayer size", "dplay.pp.size", FT_UINT32, BASE_DEC,
1361         NULL, 0x0, "", HFILL}},
1362     { &hf_dplay_pp_flags,
1363         { "PackedPlayer flags", "dplay.pp.flags", FT_UINT32, BASE_HEX,
1364         NULL, 0x0, "", HFILL}},
1365     { &hf_dplay_pp_flag_sysplayer,
1366         { "is system player", "dplay.pp.flags.sysplayer", FT_BOOLEAN, 32,
1367         TFS(&tfs_dplay_flag), DPLAY_PP_FLAG_SYSPLAYER, "", HFILL}},
1368     { &hf_dplay_pp_flag_nameserver,
1369         { "is name server", "dplay.pp.flags.nameserver", FT_BOOLEAN, 32,
1370         TFS(&tfs_dplay_flag), DPLAY_PP_FLAG_NAMESERVER, "", HFILL}},
1371     { &hf_dplay_pp_flag_in_group,
1372         { "in group", "dplay.pp.flags.in_group", FT_BOOLEAN, 32,
1373         TFS(&tfs_dplay_flag), DPLAY_PP_FLAG_IN_GROUP, "", HFILL}},
1374     { &hf_dplay_pp_flag_sending,
1375         { "sending player on local machine", "dplay.pp.flags.sending", FT_BOOLEAN, 32,
1376         TFS(&tfs_dplay_flag), DPLAY_SPP_FLAG_SENDING, "", HFILL}},
1377     { &hf_dplay_pp_id,
1378         { "PackedPlayer ID", "dplay.pp.id", FT_BYTES, BASE_HEX,
1379         NULL, 0x0, "", HFILL}},
1380     { &hf_dplay_pp_short_name_len,
1381         { "PackedPlayer short name length", "dplay.pp.short_name_len", FT_UINT32, BASE_HEX,
1382         NULL, 0x0, "", HFILL}},
1383     { &hf_dplay_pp_long_name_len,
1384         { "PackedPlayer long name length", "dplay.pp.long_name_len", FT_UINT32, BASE_HEX,
1385         NULL, 0x0, "", HFILL}},
1386     { &hf_dplay_pp_sp_data_size,
1387         { "PackedPlayer service provider data size", "dplay.pp.sp_data_size", FT_UINT32, BASE_HEX,
1388         NULL, 0x0, "", HFILL}},
1389     { &hf_dplay_pp_player_data_size,
1390         { "PackedPlayer player data size", "dplay.pp.player_data_size", FT_UINT32, BASE_HEX,
1391         NULL, 0x0, "", HFILL}},
1392     { &hf_dplay_pp_num_players,
1393         { "PackedPlayer player count", "dplay.pp.player_count", FT_UINT32, BASE_HEX,
1394         NULL, 0x0, "", HFILL}},
1395     { &hf_dplay_pp_system_player,
1396         { "PackedPlayer system player ID", "dplay.pp.sysplayer_id", FT_BYTES, BASE_HEX,
1397         NULL, 0x0, "", HFILL}},
1398     { &hf_dplay_pp_fixed_size,
1399         { "PackedPlayer fixed size", "dplay.pp.fixed_size", FT_UINT32, BASE_DEC,
1400         NULL, 0x0, "", HFILL}},
1401     { &hf_dplay_pp_dialect,
1402         { "PackedPlayer dialect version", "dplay.pp.dialect", FT_UINT32, BASE_HEX,
1403         VALS(&dplay_proto_dialect_val), 0x0, "", HFILL}},
1404     { &hf_dplay_pp_unknown_1,
1405         { "PackedPlayer unknown 1", "dplay.pp.unknown_1", FT_BYTES, BASE_HEX,
1406         NULL, 0x0, "", HFILL}},
1407     { &hf_dplay_pp_short_name,
1408         { "PackedPlayer short name", "dplay.pp.short_name", FT_STRING, BASE_NONE,
1409         NULL, 0x0, "", HFILL}},
1410     { &hf_dplay_pp_long_name,
1411         { "PackedPlayer long name", "dplay.pp.short_name", FT_STRING, BASE_NONE,
1412         NULL, 0x0, "", HFILL}},
1413     { &hf_dplay_pp_player_data,
1414         { "PackedPlayer player data", "dplay.pp.player_data", FT_BYTES, BASE_HEX,
1415         NULL, 0x0, "", HFILL}},
1416     { &hf_dplay_pp_sp_data,
1417         { "PackedPlayer service provider data", "dplay.pp.sp_data", FT_BYTES, BASE_HEX,
1418         NULL, 0x0, "", HFILL}},
1419     { &hf_dplay_pp_player_id,
1420         { "PackedPlayer player ID", "dplay.pp.player_id", FT_BYTES, BASE_HEX,
1421         NULL, 0x0, "", HFILL}},
1422     { &hf_dplay_pp_parent_id,
1423         { "PackedPlayer parent ID", "dplay.pp.parent_id", FT_BYTES, BASE_HEX,
1424         NULL, 0x0, "", HFILL}},
1425
1426     /* SuperPackedPlayer structure fields */
1427     { &hf_dplay_spp_size,
1428         { "SuperPackedPlayer size", "dplay.spp.size", FT_UINT32, BASE_DEC,
1429         NULL, 0x0, "", HFILL}},
1430     { &hf_dplay_spp_flags,
1431         { "SuperPackedPlayer flags", "dplay.spp.flags", FT_UINT32, BASE_HEX,
1432         NULL, 0x0, "", HFILL}},
1433     { &hf_dplay_spp_flags_sysplayer,
1434         { "is system player", "dplay.spp.flags.sysplayer", FT_BOOLEAN, 32,
1435         TFS(&tfs_dplay_flag), DPLAY_SPP_FLAG_SYSPLAYER, "", HFILL}},
1436     { &hf_dplay_spp_flags_nameserver,
1437         { "is name server", "dplay.spp.flags.nameserver", FT_BOOLEAN, 32,
1438         TFS(&tfs_dplay_flag), DPLAY_SPP_FLAG_NAMESERVER, "", HFILL}},
1439     { &hf_dplay_spp_flags_in_group,
1440         { "in group", "dplay.spp.flags.in_group", FT_BOOLEAN, 32,
1441         TFS(&tfs_dplay_flag), DPLAY_SPP_FLAG_IN_GROUP, "", HFILL}},
1442     { &hf_dplay_spp_flags_sending,
1443         { "sending player on local machine", "dplay.spp.flags.sending", FT_BOOLEAN, 32,
1444         TFS(&tfs_dplay_flag), DPLAY_SPP_FLAG_SENDING, "", HFILL}},
1445     { &hf_dplay_spp_id,
1446         { "SuperPackedPlayer ID", "dplay.spp.id", FT_BYTES, BASE_HEX,
1447         NULL, 0x0, "", HFILL}},
1448     { &hf_dplay_spp_player_info_mask,
1449         { "SuperPackedPlayer player info mask", "dplay.spp.pim", FT_UINT32, BASE_HEX,
1450         NULL, 0x0, "", HFILL}},
1451     { &hf_dplay_spp_have_short_name,
1452         { "SuperPackedPlayer have short name", "dplay.spp.pim.short_name", FT_UINT32, BASE_HEX,
1453         VALS(yes_no_val), 0x0, "", HFILL}},
1454     { &hf_dplay_spp_have_long_name,
1455         { "SuperPackedPlayer have long name", "dplay.spp.pim.long_name", FT_UINT32, BASE_HEX,
1456         VALS(yes_no_val), 0x0, "", HFILL}},
1457     { &hf_dplay_spp_sp_length_type,
1458         { "SuperPackedPlayer service provider length info", "dplay.spp.pim.sp_length", FT_UINT32, BASE_HEX,
1459         VALS(dplay_spp_length_val), 0x0, "", HFILL}},
1460     { &hf_dplay_spp_pd_length_type,
1461         { "SuperPackedPlayer player data length info", "dplay.spp.pim.pd_length", FT_UINT32, BASE_HEX,
1462         VALS(dplay_spp_length_val), 0x0, "", HFILL}},
1463     { &hf_dplay_spp_player_count_type,
1464         { "SuperPackedPlayer player count info", "dplay.spp.pim.player_count", FT_UINT32, BASE_HEX,
1465         VALS(dplay_spp_length_val), 0x0, "", HFILL}},
1466     { &hf_dplay_spp_have_parent_id,
1467         { "SuperPackedPlayer have parent ID", "dplay.spp.pim.parent_id", FT_UINT32, BASE_HEX,
1468         VALS(yes_no_val), 0x0, "", HFILL}},
1469     { &hf_dplay_spp_shortcut_count_type,
1470         { "SuperPackedPlayer shortcut count info", "dplay.spp.pim.shortcut_count", FT_UINT32, BASE_HEX,
1471         VALS(dplay_spp_length_val), 0x0, "", HFILL}},
1472     { &hf_dplay_spp_dialect,
1473         { "SuperPackedPlayer dialect version", "dplay.spp.dialect", FT_UINT32, BASE_HEX,
1474         VALS(&dplay_proto_dialect_val), 0x0, "", HFILL}},
1475     { &hf_dplay_spp_sys_player_id,
1476         { "SuperPackedPlayer system player ID", "dplay.spp.sysplayer_id", FT_BYTES, BASE_HEX,
1477         NULL, 0x0, "", HFILL}},
1478     { &hf_dplay_spp_short_name,
1479         { "SuperPackedPlayer short name", "dplay.spp.short_name", FT_STRING, BASE_NONE,
1480         NULL, 0x0, "", HFILL}},
1481     { &hf_dplay_spp_long_name,
1482         { "SuperPackedPlayer long name", "dplay.spp.short_name", FT_STRING, BASE_NONE,
1483         NULL, 0x0, "", HFILL}},
1484     { &hf_dplay_spp_player_data_length,
1485         { "SuperPackedPlayer player data length", "dplay.spp.pd_length", FT_UINT32, BASE_HEX,
1486         NULL, 0x0, "", HFILL}},
1487     { &hf_dplay_spp_player_data,
1488         { "SuperPackedPlayer player data", "dplay.spp.player_data", FT_BYTES, BASE_HEX,
1489         NULL, 0x0, "", HFILL}},
1490     { &hf_dplay_spp_sp_data_length,
1491         { "SuperPackedPlayer service provider data length", "dplay.spp.sp_data_length", FT_UINT32, BASE_HEX,
1492         NULL, 0x0, "", HFILL}},
1493     { &hf_dplay_spp_sp_data,
1494         { "SuperPackedPlayer service provider data", "dplay.spp.sp_data", FT_BYTES, BASE_HEX,
1495         NULL, 0x0, "", HFILL}},
1496     { &hf_dplay_spp_player_count,
1497         { "SuperPackedPlayer player count", "dplay.spp.player_count", FT_UINT32, BASE_HEX,
1498         NULL, 0x0, "", HFILL}},
1499     { &hf_dplay_spp_player_id,
1500         { "SuperPackedPlayer player ID", "dplay.spp.player_id", FT_BYTES, BASE_HEX,
1501         NULL, 0x0, "", HFILL}},
1502     { &hf_dplay_spp_parent_id,
1503         { "SuperPackedPlayer parent ID", "dplay.spp.parent_id", FT_BYTES, BASE_HEX,
1504         NULL, 0x0, "", HFILL}},
1505     { &hf_dplay_spp_shortcut_count,
1506         { "SuperPackedPlayer shortcut count", "dplay.spp.shortcut_count", FT_UINT32, BASE_HEX,
1507         NULL, 0x0, "", HFILL}},
1508     { &hf_dplay_spp_shortcut_id,
1509         { "SuperPackedPlayer shortcut ID", "dplay.spp.shortcut_id", FT_BYTES, BASE_HEX,
1510         NULL, 0x0, "", HFILL}},
1511
1512     /* Data fields for SecDesc struct */
1513     { &hf_dplay_sd_size,
1514         { "SecDesc struct size", "dplay.sd.size", FT_UINT32, BASE_DEC,
1515         NULL, 0x0, "", HFILL}},
1516     { &hf_dplay_sd_flags,
1517         { "SecDesc flags", "dplay.sd.flags", FT_UINT32, BASE_HEX,
1518         NULL, 0x0, "", HFILL}},
1519     { &hf_dplay_sd_sspi,
1520         { "SecDesc SSPI provider ptr", "dplay.sd.sspi", FT_BYTES, BASE_HEX,
1521         NULL, 0x0, "", HFILL}},
1522     { &hf_dplay_sd_capi,
1523         { "SecDesc CAPI provider ptr", "dplay.sd.capi", FT_BYTES, BASE_HEX,
1524         NULL, 0x0, "", HFILL}},
1525     { &hf_dplay_sd_capi_type,
1526         { "SecDesc CAPI provider type", "dplay.sd.capi_type", FT_UINT32, BASE_HEX,
1527         NULL, 0x0, "", HFILL}},
1528     { &hf_dplay_sd_enc_alg,
1529         { "SecDesc encryption algorithm" , "dplay.sd.enc_alg", FT_UINT32, BASE_HEX,
1530         VALS(dplay_enc_alg_val), 0x0, "", HFILL}},
1531
1532     /* Data fields for message type 0x0001 */
1533     { &hf_dplay_type_01_name_offset,
1534         { "Enum Session Reply name offset", "dplay.type_01.name_offs", FT_UINT32, BASE_DEC,
1535         NULL, 0x0, "", HFILL}},
1536     { &hf_dplay_type_01_game_name,
1537         { "Enum Session Reply game name", "dplay.type_01.game_name", FT_STRING, BASE_NONE,
1538         NULL, 0x0, "", HFILL}},
1539
1540     /* Data fields for message type 0x0002 */
1541     { &hf_dplay_type_02_game_guid,
1542         { "DirectPlay game GUID", "dplay.type02.game.guid", FT_GUID, BASE_NONE,
1543         NULL, 0x0, "", HFILL}},
1544     { &hf_dplay_type_02_password_offset,
1545         { "Enum Sessions password offset", "dplay.type02.password_offset", FT_UINT32, BASE_DEC,
1546         NULL, 0x0, "", HFILL}},
1547     { &hf_dplay_type_02_flags,
1548         { "Enum Session flags", "dplay.type02.flags", FT_UINT32, BASE_HEX,
1549         NULL, 0x0, "", HFILL}},
1550     { &hf_dplay_type_02_password,
1551         { "Session password", "dplay.type02.password", FT_STRING, BASE_NONE,
1552         NULL, 0x0, "", HFILL}},
1553     { &hf_enum_sess_flag_join,
1554         { "Enumerate joinable sessions", "dplay.type02.joinable", FT_BOOLEAN, 32,
1555         TFS(&tfs_dplay_flag), DPLAY_ENUM_SESS_FLAG_JOIN, "Joinable", HFILL}},
1556     { &hf_enum_sess_flag_all,
1557         { "Enumerate all sessions", "dplay.type02.all", FT_BOOLEAN, 32,
1558         TFS(&tfs_dplay_flag), DPLAY_ENUM_SESS_FLAG_ALL, "All", HFILL}},
1559     { &hf_enum_sess_flag_passwd,
1560         { "Enumerate sessions requiring a password", "dplay.type02.pw_req", FT_BOOLEAN, 32,
1561         TFS(&tfs_dplay_flag), DPLAY_ENUM_SESS_FLAG_PASSWD, "Password", HFILL}},
1562
1563     /* Data fields for message type 0x0005 */
1564     { &hf_dplay_type_05_flags,
1565         { "Player ID request flags", "dplay.type_05.flags", FT_UINT32, BASE_HEX,
1566         NULL, 0x0, "", HFILL}},
1567     { &hf_dplay_type_05_system_player,
1568         { "is system player", "dplay.type_05.flags.sys_player", FT_BOOLEAN, 32,
1569         TFS(&tfs_dplay_flag), DPLAY_TYPE05_FLAG_SYSPLAYER, "", HFILL}},
1570     { &hf_dplay_type_05_name_server,
1571         { "is name server", "dplay.type_05.flags.name_server", FT_BOOLEAN, 32,
1572         TFS(&tfs_dplay_flag), DPLAY_TYPE05_FLAG_NAMESERVER, "", HFILL}},
1573     { &hf_dplay_type_05_local,
1574         { "is local player", "dplay.type_05.flags.local", FT_BOOLEAN, 32,
1575         TFS(&tfs_dplay_flag), DPLAY_TYPE05_FLAG_LOCAL, "", HFILL}},
1576     { &hf_dplay_type_05_unknown,
1577         { "unknown", "dplay.type_05.flags.unknown", FT_BOOLEAN, 32,
1578         TFS(&tfs_dplay_flag), DPLAY_TYPE05_FLAG_UNKNOWN, "", HFILL}},
1579     { &hf_dplay_type_05_secure,
1580         { "is secure session", "dplay.type_05.flags.secure", FT_BOOLEAN, 32,
1581         TFS(&tfs_dplay_flag), DPLAY_TYPE05_FLAG_SECURE, "", HFILL}},
1582
1583     /* Data fields for message type 0x0007 */
1584     { &hf_dplay_type_07_dpid,
1585         { "DirectPlay ID", "dplay.type_07.dpid", FT_BYTES, BASE_HEX,
1586         NULL, 0x0, "", HFILL}},
1587     { &hf_dplay_type_07_sspi_offset,
1588         { "SSPI provider offset", "dplay.type_07.sspi_offset", FT_UINT32, BASE_DEC,
1589         NULL, 0x0, "", HFILL}},
1590     { &hf_dplay_type_07_capi_offset,
1591         { "CAPI provider offset", "dplay.type_07.capi_offset", FT_UINT32, BASE_DEC,
1592         NULL, 0x0, "", HFILL}},
1593     { &hf_dplay_type_07_hresult,
1594         { "Request player HRESULT", "dplay.type_07.hresult", FT_UINT32, BASE_DEC,
1595         NULL, 0x0, "", HFILL}},
1596     { &hf_dplay_type_07_sspi,
1597         { "SSPI provider", "dplay.type_07.sspi", FT_STRING, BASE_NONE,
1598         NULL, 0x0, "", HFILL}},
1599     { &hf_dplay_type_07_capi,
1600         { "CAPI provider", "dplay.type_07.capi", FT_STRING, BASE_NONE,
1601         NULL, 0x0, "", HFILL}},
1602
1603     /* Data fields for message type 0x0008, 0x0009, 0x000b, 0x000c, 0x000d,
1604      * 0x000e, 0x002e and 0x0038*/
1605     { &hf_dplay_multi_id_to,
1606         { "ID to", "dplay.multi.id_to", FT_BYTES, BASE_HEX,
1607         NULL, 0x0, "", HFILL}},
1608     { &hf_dplay_multi_player_id,
1609         { "Player ID", "dplay.multi.player_id", FT_BYTES, BASE_HEX,
1610         NULL, 0x0, "", HFILL}},
1611     { &hf_dplay_multi_group_id,
1612         { "Group ID", "dplay.multi.group_id", FT_BYTES, BASE_HEX,
1613         NULL, 0x0, "", HFILL}},
1614     { &hf_dplay_multi_create_offset,
1615         { "Offset to PackedPlayer struct", "dplay.multi.create_offset", FT_UINT32, BASE_DEC,
1616         NULL, 0x0, "", HFILL}},
1617     { &hf_dplay_multi_password_offset,
1618         { "Offset to password", "dplay.multi.password_offset", FT_UINT32, BASE_DEC,
1619         NULL, 0x0, "", HFILL}},
1620     { &hf_dplay_multi_password,
1621         { "Password", "dplay.multi.password", FT_STRING, BASE_NONE,
1622         NULL, 0x0, "", HFILL}},
1623
1624     /* Data fields for message type 0x000f */
1625     { &hf_dplay_type_0f_id_to,
1626         { "ID to", "dplay.type_0f.id_to", FT_BYTES, BASE_HEX,
1627         NULL, 0x0, "", HFILL}},
1628     { &hf_dplay_type_0f_id,
1629         { "Player ID", "dplay.type_0f.player_id", FT_BYTES, BASE_HEX,
1630         NULL, 0x0, "", HFILL}},
1631     { &hf_dplay_type_0f_data_size,
1632         { "Data Size", "dplay.multi.group_id", FT_UINT32, BASE_DEC,
1633         NULL, 0x0, "", HFILL}},
1634     { &hf_dplay_type_0f_data_offset,
1635         { "Data Offset", "dplay.type_0f.data_offset", FT_UINT32, BASE_DEC,
1636         NULL, 0x0, "", HFILL}},
1637     { &hf_dplay_type_0f_data,
1638         { "Player Data", "dplay.type_0f.player_data", FT_BYTES, BASE_HEX,
1639         NULL, 0x0, "", HFILL}},
1640
1641     /* Data fields for message type 0x0013 */
1642     { &hf_dplay_type_13_id_to,
1643         { "ID to", "dplay.type_13.id_to", FT_BYTES, BASE_HEX,
1644         NULL, 0x0, "", HFILL}},
1645     { &hf_dplay_type_13_player_id,
1646         { "Player ID", "dplay.type_13.player_id", FT_BYTES, BASE_HEX,
1647         NULL, 0x0, "", HFILL}},
1648     { &hf_dplay_type_13_group_id,
1649         { "Group ID", "dplay.type_13.group_id", FT_BYTES, BASE_HEX,
1650         NULL, 0x0, "", HFILL}},
1651     { &hf_dplay_type_13_create_offset,
1652         { "Create Offset", "dplay.type_13.create_offset", FT_UINT32, BASE_DEC,
1653         NULL, 0x0, "", HFILL}},
1654     { &hf_dplay_type_13_password_offset,
1655         { "Password Offset", "dplay.type_13.password_offset", FT_UINT32, BASE_DEC,
1656         NULL, 0x0, "", HFILL}},
1657     { &hf_dplay_type_13_password,
1658         { "Password", "dplay.type_13.password", FT_STRING, BASE_NONE,
1659         NULL, 0x0, "", HFILL}},
1660     { &hf_dplay_type_13_tick_count,
1661         { "Tick count? Looks like an ID", "dplay.type_13.tick_count", FT_BYTES, BASE_HEX,
1662         NULL, 0x0, "", HFILL}},
1663
1664     /* Data fields for message type 0x0015 */
1665     { &hf_dplay_message_guid,
1666         { "Message GUID", "dplay.message.guid", FT_GUID, BASE_NONE,
1667         NULL, 0x0, "", HFILL}},
1668     { &hf_dplay_type_15_packet_idx,
1669         { "Packet Index", "dplay.type_15.packet_idx", FT_UINT32, BASE_DEC,
1670         NULL, 0x0, "", HFILL}},
1671     { &hf_dplay_type_15_data_size,
1672         { "Data Size", "dplay.type_15.data_size", FT_UINT32, BASE_DEC,
1673         NULL, 0x0, "", HFILL}},
1674     { &hf_dplay_type_15_offset,
1675         { "Offset", "dplay.type_15.offset", FT_UINT32, BASE_DEC,
1676         NULL, 0x0, "", HFILL}},
1677     { &hf_dplay_type_15_total_packets,
1678         { "Total Packets", "dplay.type_15.total_packets", FT_UINT32, BASE_DEC,
1679         NULL, 0x0, "", HFILL}},
1680     { &hf_dplay_type_15_msg_size,
1681         { "Message size", "dplay.type_15.message.size", FT_UINT32, BASE_DEC,
1682         NULL, 0x0, "", HFILL}},
1683     { &hf_dplay_type_15_packet_offset,
1684         { "Packet offset", "dplay.type_15.packet_offset", FT_UINT32, BASE_DEC,
1685         NULL, 0x0, "", HFILL}},
1686
1687     /* Data field for message type 0x0016 and 0x0017 */
1688     { &hf_dplay_ping_id_from,
1689         { "ID From", "dplay.ping.id_from", FT_BYTES, BASE_HEX,
1690         NULL, 0x0, "", HFILL}},
1691     { &hf_dplay_ping_tick_count,
1692         { "Tick Count", "dplay.ping.tick_count", FT_UINT32, BASE_DEC,
1693         NULL, 0x0, "", HFILL}},
1694
1695     /* Data fields for message type 0x001a */
1696     { &hf_dplay_type_1a_id_to,
1697         { "ID From", "dplay.type_1a.id_to", FT_BYTES, BASE_HEX,
1698         NULL, 0x0, "", HFILL}},
1699     { &hf_dplay_type_1a_sess_name_ofs,
1700         { "Session Name Offset", "dplay.type_1a.sess_name_ofs", FT_UINT32, BASE_DEC,
1701         NULL, 0x0, "", HFILL}},
1702     { &hf_dplay_type_1a_password_ofs,
1703         { "Password Offset", "dplay.type_1a.password_offset", FT_UINT32, BASE_DEC,
1704         NULL, 0x0, "", HFILL}},
1705     { &hf_dplay_type_1a_session_name,
1706         { "Session Name", "dplay.type_1a.session_name", FT_STRING, BASE_NONE,
1707         NULL, 0x0, "", HFILL}},
1708     { &hf_dplay_type_1a_password,
1709         { "Password", "dplay.type_1a.password", FT_STRING, BASE_NONE,
1710         NULL, 0x0, "", HFILL}},
1711
1712     /* Data fields for message type 0x0029 */
1713     { &hf_dplay_type_29_player_count,
1714         { "SuperEnumPlayers Reply player count", "dplay.type_29.player_count", FT_UINT32,
1715         BASE_DEC, NULL, 0x0, "", HFILL}},
1716     { &hf_dplay_type_29_group_count,
1717         { "SuperEnumPlayers Reply group count", "dplay.type_29.group_count", FT_UINT32,
1718         BASE_DEC, NULL, 0x0, "", HFILL}},
1719     { &hf_dplay_type_29_packed_offset,
1720         { "SuperEnumPlayers Reply packed offset", "dplay.type_29.packed_offset", FT_UINT32,
1721         BASE_DEC, NULL, 0x0, "", HFILL}},
1722     { &hf_dplay_type_29_shortcut_count,
1723         { "SuperEnumPlayers Reply shortcut count", "dplay.type_29.shortcut_count", FT_UINT32,
1724         BASE_DEC, NULL, 0x0, "", HFILL}},
1725     { &hf_dplay_type_29_description_offset,
1726         { "SuperEnumPlayers Reply description offset", "dplay.type_29.desc_offset", FT_UINT32,
1727         BASE_DEC, NULL, 0x0, "", HFILL}},
1728     { &hf_dplay_type_29_name_offset,
1729         { "SuperEnumPlayers Reply name offset", "dplay.type_29.name_offset", FT_UINT32,
1730         BASE_DEC, NULL, 0x0, "", HFILL}},
1731     { &hf_dplay_type_29_password_offset,
1732         { "SuperEnumPlayers Reply password offset", "dplay.type_29.pass_offset", FT_UINT32,
1733         BASE_DEC, NULL, 0x0, "", HFILL}},
1734     { &hf_dplay_type_29_game_name,
1735         { "SuperEnumPlayers Reply game name", "dplay.type_29.game_name", FT_STRING, BASE_NONE,
1736         NULL, 0x0, "", HFILL}},
1737     { &hf_dplay_type_29_password,
1738         { "SuperEnumPlayers Reply Password", "dplay.type_29.password", FT_STRING, BASE_NONE,
1739         NULL, 0x0, "", HFILL}},
1740
1741     /* Data fields for message type 0x002f */
1742     { &hf_dplay_type_2f_dpid,
1743         { "ID of the forwarded player", "dplay.type_29.id", FT_BYTES, BASE_HEX,
1744         NULL, 0x0, "", HFILL}},
1745     };
1746
1747     static gint *ett[] = {
1748         &ett_dplay,
1749         &ett_dplay_header,
1750         &ett_dplay_sockaddr,
1751         &ett_dplay_data,
1752         &ett_dplay_flags,
1753         &ett_dplay_enc_packet,
1754         &ett_dplay_sess_desc_flags,
1755         &ett_dplay_pp_flags,
1756         &ett_dplay_spp_flags,
1757         &ett_dplay_spp_info_mask,
1758         &ett_dplay_type02_flags,
1759         &ett_dplay_type05_flags,
1760         &ett_dplay_type29_spp,
1761     };
1762     module_t *dplay_module;
1763
1764     if(proto_dplay == -1)
1765     {
1766         proto_dplay = proto_register_protocol (
1767                 "DirectPlay Protocol",
1768                 "DPLAY",
1769                 "dplay"
1770                 );
1771         proto_register_field_array(proto_dplay, hf, array_length(hf));
1772         proto_register_subtree_array(ett, array_length(ett));
1773         dplay_module = prefs_register_protocol(proto_dplay, proto_reg_handoff_dplay);
1774     }
1775 }
1776
1777 void proto_reg_handoff_dplay(void)
1778 {
1779     static int initialized = FALSE;
1780
1781     if(!initialized)
1782     {
1783         initialized = TRUE;
1784         heur_dissector_add("udp", heur_dissect_dplay, proto_dplay);
1785         heur_dissector_add("tcp", heur_dissect_dplay, proto_dplay);
1786         dplay_handle = create_dissector_handle(dissect_dplay, proto_dplay);
1787     }
1788 }
1789