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