HACK: 2nd try to match RowsetProperties
[wireshark-wip.git] / epan / dissectors / packet-teamspeak2.c
blob7f9a86e8a43f46854445e32d347db53bcd9cbae4
1 /* packet-teamspeak2.c
2 * Routines for TeamSpeak2 protocol packet disassembly
3 * By brooss <brooss.teambb@gmail.com>
4 * Copyright 2008 brooss
6 * $Id$
8 * Wireshark - Network traffic analyzer
9 * By Gerald Combs <gerald@wireshark.org>
10 * Copyright 1998
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27 #include "config.h"
29 #include <glib.h>
31 #include <epan/packet.h>
32 #include <wsutil/crc32.h>
33 #include <epan/crc32-tvb.h>
34 #include <epan/wmem/wmem.h>
35 #include <epan/reassemble.h>
36 #include <epan/conversation.h>
38 /* Packet Classes */
39 #define TS2C_STANDARD 0xbef0
40 #define TS2C_ACK 0xbef1
41 #define TS2C_CLIENT_VOICE 0xbef2
42 #define TS2C_SERVER_VOICE 0xbef3
43 #define TS2C_CONNECTION 0xbef4
45 /* Packet Types */
46 #define TS2T_PING 0x0001
47 #define TS2T_PINGREPLY 0x0002
48 #define TS2T_LOGINREQUEST 0x0003
49 #define TS2T_LOGINREPLY 0x0004
50 #define TS2T_LOGINPART2 0x0005
51 #define TS2T_CHANNELLIST 0x0006
52 #define TS2T_PLAYERLIST 0x0007
53 #define TS2T_LOGINEND 0x0008
55 #define TS2T_TEXTMESSAGE 0x0082
56 #define TS2T_CHANNEL_PLAYERLIST 0x006c
57 #define TS2T_CHANNELCHANGE 0x0067
58 #define TS2T_CHANNELLISTUPDATE 0x006e
59 #define TS2T_PLAYERKICKED 0x0066
60 #define TS2T_PLAYERLEFT 0x0065
61 #define TS2T_NEWPLAYERJOINED 0x0064
62 #define TS2T_KNOWNPLAYERUPDATE 0x0068
63 #define TS2T_CHANNELDELETED 0x0073
64 #define TS2T_CHANNELNAMECHANGED 0x006f
65 #define TS2T_CHANNELTOPICCHANGED 0x0070
66 #define TS2T_CHANNELPASSWORDCHANGED 0x0071
67 #define TS2T_CREATECHANNEL 0x00c9
68 #define TS2T_DISCONNECT 0x012c
69 #define TS2T_SWITCHCHANNEL 0x012f
70 #define TS2T_CHANGESTATUS 0x0130
71 #define TS2T_CHATMESSAGEBOUNCE 0xfc0f
73 #define TS2T_VOICE_DATA_CELP_5_1 0x0000
74 #define TS2T_VOICE_DATA_CELP_6_3 0x0100
75 #define TS2T_VOICE_DATA_GSM_14_8 0x0200
76 #define TS2T_VOICE_DATA_GSM_16_4 0x0300
77 #define TS2T_VOICE_DATA_CELP_WINDOWS_5_2 0x0400
78 #define TS2T_VOICE_DATA_SPEEX_3_4 0x0500
79 #define TS2T_VOICE_DATA_SPEEX_5_2 0x0600
80 #define TS2T_VOICE_DATA_SPEEX_7_2 0x0700
81 #define TS2T_VOICE_DATA_SPEEX_9_3 0x0800
82 #define TS2T_VOICE_DATA_SPEEX_12_3 0x0900
83 #define TS2T_VOICE_DATA_SPEEX_16_3 0x0a00
84 #define TS2T_VOICE_DATA_SPEEX_19_5 0x0b00
85 #define TS2T_VOICE_DATA_SPEEX_25_9 0x0c00
87 /* Codec Types */
88 #define TS2T_CODEC_CELP_5_1 0x0000
89 #define TS2T_CODEC_CELP_6_3 0x0001
90 #define TS2T_CODEC_GSM_14_8 0x0002
91 #define TS2T_CODEC_GSM_16_4 0x0003
92 #define TS2T_CODEC_CELP_WINDOWS_5_2 0x0004
93 #define TS2T_CODEC_SPEEX_3_4 0x0005
94 #define TS2T_CODEC_SPEEX_5_2 0x0006
95 #define TS2T_CODEC_SPEEX_7_2 0x0007
96 #define TS2T_CODEC_SPEEX_9_3 0x0008
97 #define TS2T_CODEC_SPEEX_12_3 0x0009
98 #define TS2T_CODEC_SPEEX_16_3 0x000a
99 #define TS2T_CODEC_SPEEX_19_5 0x000b
100 #define TS2T_CODEC_SPEEX_25_9 0x000c
102 /* Player Status Flags */
103 #define TS2_STATUS_CHANNELCOMMANDER 1
104 #define TS2_STATUS_BLOCKWHISPERS 4
105 #define TS2_STATUS_AWAY 8
106 #define TS2_STATUS_MUTEMICROPHONE 16
107 #define TS2_STATUS_MUTE 32
110 static int hf_msg_fragments = -1;
111 static int hf_msg_fragment = -1;
112 static int hf_msg_fragment_overlap = -1;
113 static int hf_msg_fragment_overlap_conflicts = -1;
114 static int hf_msg_fragment_multiple_tails = -1;
115 static int hf_msg_fragment_too_long_fragment = -1;
116 static int hf_msg_fragment_error = -1;
117 static int hf_msg_fragment_count = -1;
118 static int hf_msg_reassembled_in = -1;
119 static int hf_msg_reassembled_length = -1;
121 static gint ett_msg_fragment = -1;
122 static gint ett_msg_fragments = -1;
124 static const fragment_items msg_frag_items = {
125 /* Fragment subtrees */
126 &ett_msg_fragment,
127 &ett_msg_fragments,
128 /* Fragment fields */
129 &hf_msg_fragments,
130 &hf_msg_fragment,
131 &hf_msg_fragment_overlap,
132 &hf_msg_fragment_overlap_conflicts,
133 &hf_msg_fragment_multiple_tails,
134 &hf_msg_fragment_too_long_fragment,
135 &hf_msg_fragment_error,
136 &hf_msg_fragment_count,
137 /* Reassembled in field */
138 &hf_msg_reassembled_in,
139 /* Reassembled length field */
140 &hf_msg_reassembled_length,
141 /* Reassembled data field */
142 NULL,
143 /* Tag */
144 "Message fragments"
147 /* Class names */
148 static const value_string classnames[] =
150 { TS2C_CONNECTION, "Connection" },
151 { TS2C_ACK, "ACK"},
152 { TS2C_STANDARD, "Standard (reliable)"},
153 { TS2C_SERVER_VOICE, "Voice"},
154 { TS2C_CLIENT_VOICE, "Voice"},
155 { 0, NULL }
158 /* Type names */
159 static const value_string typenames[] = {
160 { TS2T_PING, "Ping" },
161 { TS2T_PINGREPLY, "Ping Reply" },
162 { TS2T_LOGINREQUEST, "Login Request" },
163 { TS2T_LOGINREPLY, "Login Reply" },
164 { TS2T_LOGINPART2, "Login Part 2" },
165 { TS2T_CHANNELLIST, "Channel List" },
166 { TS2T_PLAYERLIST, "Player List" },
167 { TS2T_LOGINEND, "Login End" },
168 { TS2T_TEXTMESSAGE, "Text Message" },
171 { TS2T_CHANNEL_PLAYERLIST, "Channel Player List" },
172 { TS2T_CHANNELCHANGE, "Channel Change" },
174 { TS2T_CHANNELLISTUPDATE, "Channel List Update" },
175 { TS2T_PLAYERKICKED, "Player Kicked" },
176 { TS2T_PLAYERLEFT, "Player Left" },
177 { TS2T_NEWPLAYERJOINED, "New Player Joined" },
178 { TS2T_KNOWNPLAYERUPDATE, "Known Player Update" },
179 { TS2T_CHANNELDELETED, "Channel Deleted" },
180 { TS2T_CHANNELNAMECHANGED, "Channel Name Change" },
181 { TS2T_CHANNELTOPICCHANGED, "Channel Topic Change" },
182 { TS2T_CHANNELPASSWORDCHANGED, "Channel Password Change" },
183 { TS2T_CREATECHANNEL, "Create Channel" },
184 { TS2T_DISCONNECT, "Disconnect" },
185 { TS2T_SWITCHCHANNEL, "Switch Channel"},
186 { TS2T_CHANGESTATUS, "Change Status" },
188 { TS2T_CHATMESSAGEBOUNCE, "Chat Message Bounce" },
190 { TS2T_VOICE_DATA_CELP_5_1, "TS2T_VOICE_DATA_CELP_5_1" },
191 { TS2T_VOICE_DATA_CELP_6_3, "TS2T_VOICE_DATA_CELP_6_3" },
192 { TS2T_VOICE_DATA_GSM_14_8, "TS2T_VOICE_DATA_GSM_14_8" },
193 { TS2T_VOICE_DATA_GSM_16_4, "TS2T_VOICE_DATA_GSM_16_4" },
194 { TS2T_VOICE_DATA_CELP_WINDOWS_5_2, "TS2T_VOICE_DATA_CELP_WINDOWS_5_2" },
195 { TS2T_VOICE_DATA_SPEEX_3_4, "TS2T_VOICE_DATA_SPEEX_3_4" },
196 { TS2T_VOICE_DATA_SPEEX_5_2, "TS2T_VOICE_DATA_SPEEX_5_2" },
197 { TS2T_VOICE_DATA_SPEEX_7_2, "TS2T_VOICE_DATA_SPEEX_7_2" },
198 { TS2T_VOICE_DATA_SPEEX_9_3, "TS2T_VOICE_DATA_SPEEX_9_3" },
199 { TS2T_VOICE_DATA_SPEEX_12_3, "TS2T_VOICE_DATA_SPEEX_12_3" },
200 { TS2T_VOICE_DATA_SPEEX_16_3, "TS2T_VOICE_DATA_SPEEX_16_3" },
201 { TS2T_VOICE_DATA_SPEEX_19_5, "TS2T_VOICE_DATA_SPEEX_19_5" },
202 { TS2T_VOICE_DATA_SPEEX_25_9, "TS2T_VOICE_DATA_SPEEX_25_9" },
204 { 0, NULL }
207 /* Codec Names */
208 static const value_string codecnames[] =
210 { TS2T_CODEC_CELP_5_1, "CELP 5.1" },
211 { TS2T_CODEC_CELP_6_3, "CELP 6.3" },
212 { TS2T_CODEC_GSM_14_8, "GSM 14.8" },
213 { TS2T_CODEC_GSM_16_4, "GSM 16.4" },
214 { TS2T_CODEC_CELP_WINDOWS_5_2, "CELP Windows 5.2" },
215 { TS2T_CODEC_SPEEX_3_4, "Speex 3.4" },
216 { TS2T_CODEC_SPEEX_5_2, "Speex 5.2" },
217 { TS2T_CODEC_SPEEX_7_2, "Speex 7.2" },
218 { TS2T_CODEC_SPEEX_9_3, "Speex 9.3" },
219 { TS2T_CODEC_SPEEX_12_3, "Speex 12.3" },
220 { TS2T_CODEC_SPEEX_16_3, "Speex 16.3" },
221 { TS2T_CODEC_SPEEX_19_5, "Speex 19.5" },
222 { TS2T_CODEC_SPEEX_25_9, "Speex 25.9" },
223 { 0, NULL }
226 #define TS2_PORT 8767
228 static int proto_ts2 = -1;
230 static int hf_ts2_type = -1;
231 static int hf_ts2_class = -1;
232 static int hf_ts2_clientid = -1;
233 static int hf_ts2_sessionkey = -1;
234 static int hf_ts2_crc32 = -1;
235 static int hf_ts2_ackto = -1;
236 static int hf_ts2_seqnum = -1;
237 static int hf_ts2_protocol_string = -1;
238 /* static int hf_ts2_string = -1; */
239 static int hf_ts2_registeredlogin = -1;
240 static int hf_ts2_name = -1;
241 static int hf_ts2_password = -1;
242 static int hf_ts2_nick = -1;
243 static int hf_ts2_badlogin = -1;
244 static int hf_ts2_unknown = -1;
245 static int hf_ts2_channel = -1;
246 static int hf_ts2_subchannel = -1;
247 static int hf_ts2_channelpassword = -1;
248 static int hf_ts2_emptyspace = -1;
249 static int hf_ts2_fragmentnumber = -1;
250 static int hf_ts2_platform_string = -1;
251 static int hf_ts2_server_name = -1;
252 static int hf_ts2_server_welcome_message = -1;
253 static int hf_ts2_parent_channel_id = -1;
254 static int hf_ts2_codec = -1;
255 static int hf_ts2_channel_flags = -1;
256 static int hf_ts2_channel_id = -1;
257 static int hf_ts2_channel_name = -1;
258 static int hf_ts2_channel_topic = -1;
259 static int hf_ts2_channel_description = -1;
260 static int hf_ts2_player_id = -1;
261 static int hf_ts2_player_status_flags = -1;
262 static int hf_ts2_number_of_players = -1;
263 static int hf_ts2_number_of_channels = -1;
264 static int hf_ts2_resend_count = -1;
265 static int hf_ts2_status_channelcommander = -1;
266 static int hf_ts2_status_blockwhispers = -1;
267 static int hf_ts2_status_away = -1;
268 static int hf_ts2_status_mutemicrophone = -1;
269 static int hf_ts2_status_mute = -1;
270 static int hf_ts2_channel_unregistered = -1;
271 static int hf_ts2_channel_moderated = -1;
272 static int hf_ts2_channel_password = -1;
273 static int hf_ts2_channel_subchannels = -1;
274 static int hf_ts2_channel_default = -1;
275 static int hf_ts2_channel_order = -1;
276 static int hf_ts2_max_users = -1;
278 static gint ett_ts2 = -1;
279 static gint ett_ts2_channel_flags = -1;
281 /* Conversation Variables */
282 typedef struct
284 guint32 last_inorder_server_frame;
285 guint32 last_inorder_client_frame;
286 address server_addr;
287 guint32 server_port;
288 guint32 server_frag_size;
289 guint32 server_frag_num;
290 guint32 client_frag_size;
291 guint32 client_frag_num;
293 } ts2_conversation;
295 /* Packet Variables */
296 typedef struct
298 guint32 frag_num;
299 guint32 frag_size;
300 gboolean fragmented;
301 gboolean outoforder;
302 } ts2_frag;
304 #define my_init_count 5
306 static reassembly_table msg_reassembly_table;
308 /* forward reference */
309 static gboolean ts2_add_checked_crc32(proto_tree *tree, int hf_item, tvbuff_t *tvb, guint16 offset, guint32 icrc32);
310 static void ts2_parse_playerlist(tvbuff_t *tvb, proto_tree *ts2_tree);
311 static void ts2_parse_channellist(tvbuff_t *tvb, proto_tree *ts2_tree);
312 static void ts2_parse_newplayerjoined(tvbuff_t *tvb, proto_tree *ts2_tree);
313 static void ts2_parse_knownplayerupdate(tvbuff_t *tvb, proto_tree *ts2_tree);
314 static void ts2_parse_playerleft(tvbuff_t *tvb, proto_tree *ts2_tree);
315 static void ts2_parse_loginend(tvbuff_t *tvb, proto_tree *ts2_tree);
316 static void ts2_parse_changestatus(tvbuff_t *tvb, proto_tree *ts2_tree);
317 static void ts2_parse_switchchannel(tvbuff_t *tvb, proto_tree *ts2_tree);
318 static void ts2_add_statusflags(tvbuff_t *tvb, proto_tree *ts2_tree, guint32 offset);
319 static void ts2_parse_channelchange(tvbuff_t *tvb, proto_tree *ts2_tree);
320 static void ts2_parse_loginpart2(tvbuff_t *tvb, proto_tree *ts2_tree);
323 * Check if a packet is in order and if it is set its fragmentation details into the passed pointers.
324 * Returns TRUE if the packet is fragmented.
325 * Must be run sequentially
326 * */
327 static gboolean ts2_standard_find_fragments(tvbuff_t *tvb, guint32 *last_inorder_frame, guint32 *frag_size, guint32 *frag_num, gboolean *outoforder)
329 guint32 frag_count;
330 gboolean ret;
331 frag_count=tvb_get_letohs(tvb, 18);
332 ret=FALSE;
333 *outoforder=FALSE;
335 /* if last_inorder_frame is zero, then this is the first reliable packet */
336 if(*last_inorder_frame==0)
338 *last_inorder_frame=tvb_get_letohl(tvb, 12);
339 *frag_size=tvb_get_letohs(tvb, 18);
340 *frag_num=0;
341 if(*frag_size>0)
342 ret=TRUE;
343 else
344 ret=FALSE;
346 /* This packet is in order */
347 else if(*last_inorder_frame==tvb_get_letohl(tvb, 12)-1)
349 if(*frag_size>0)
351 *frag_num=*frag_size-frag_count;
352 if(frag_count==0)
354 *frag_size=0;
356 ret=TRUE;
358 else
360 *frag_size=tvb_get_letohs(tvb, 18);
361 *frag_num=*frag_size-frag_count;
362 if(*frag_size>0)
363 ret=TRUE;
364 else
365 ret=FALSE;
367 *last_inorder_frame=tvb_get_letohl(tvb, 12);
369 else /* out of order */
370 *outoforder=TRUE;
371 return ret;
377 * Dissect a standard (reliable) ts2 packet, reassembling if required.
379 static void ts2_standard_dissect(tvbuff_t *tvb, packet_info *pinfo, proto_tree *ts2_tree, ts2_conversation *conversation_data)
381 guint8 save_fragmented;
382 tvbuff_t *new_tvb, *next_tvb;
383 fragment_head *frag_msg ;
384 guint16 fragment_number;
385 ts2_frag *frag;
386 gboolean outoforder;
388 guint16 type = tvb_get_letohs(tvb, 2);
389 /*guint16 klass = tvb_get_letohs(tvb, 0);*/
390 proto_tree_add_item(ts2_tree, hf_ts2_seqnum, tvb, 12, 4, ENC_LITTLE_ENDIAN);
392 /* XXX: Following fragmentation stuff should be separate from the GUI stuff ?? */
393 /* Get our stored fragmentation data or create one! */
394 if ( ! ( frag = (ts2_frag *)p_get_proto_data(pinfo->fd, proto_ts2, 0) ) ) {
395 frag = wmem_new(wmem_file_scope(), ts2_frag);
396 frag->frag_num=0;
399 /* decide if the packet is server to client or client to server
400 * then check its fragmentation
402 if(!(pinfo->fd->flags.visited))
404 if(conversation_data->server_port == pinfo->srcport)
406 frag->fragmented = ts2_standard_find_fragments(tvb, &conversation_data->last_inorder_server_frame, &conversation_data->server_frag_size, &conversation_data->server_frag_num, &outoforder);
407 frag->frag_num=conversation_data->server_frag_num;
408 frag->frag_size=conversation_data->server_frag_size;
410 else
413 frag->fragmented = ts2_standard_find_fragments(tvb, &conversation_data->last_inorder_client_frame, &conversation_data->client_frag_size, &conversation_data->client_frag_num, &outoforder);
414 frag->frag_num=conversation_data->client_frag_num;
415 frag->frag_size=conversation_data->client_frag_size;
417 frag->outoforder=outoforder;
418 p_add_proto_data(pinfo->fd, proto_ts2, 0, frag);
421 /* Get our stored fragmentation data */
422 frag = (ts2_frag *)p_get_proto_data(pinfo->fd, proto_ts2, 0);
424 proto_tree_add_item(ts2_tree, hf_ts2_resend_count, tvb, 16, 2, ENC_LITTLE_ENDIAN);
425 proto_tree_add_item(ts2_tree, hf_ts2_fragmentnumber, tvb, 18, 2, ENC_LITTLE_ENDIAN);
426 ts2_add_checked_crc32(ts2_tree, hf_ts2_crc32, tvb, 20, tvb_get_letohl(tvb, 20));
428 /* Reassemble the packet if it's fragmented */
429 new_tvb = NULL;
430 if(frag && frag->fragmented)
432 save_fragmented = pinfo->fragmented;
433 frag_msg = NULL;
434 pinfo->fragmented = TRUE;
435 fragment_number = tvb_get_letohs(tvb, 18);
436 frag_msg = fragment_add_seq_check(&msg_reassembly_table, tvb, 24, pinfo, type, NULL, frag->frag_num, tvb_length_remaining(tvb, 24), fragment_number);
437 new_tvb = process_reassembled_data(tvb, 24, pinfo,"Reassembled TeamSpeak2", frag_msg, &msg_frag_items, NULL, ts2_tree);
438 if (frag_msg) /* XXX: should be if (new_tvb) ?? */
439 { /* Reassembled */
440 col_append_str(pinfo->cinfo, COL_INFO, " (Message Reassembled)");
442 else
443 { /* Not last packet of reassembled Short Message */
444 col_append_fstr(pinfo->cinfo, COL_INFO," (Message fragment %u)", frag->frag_num);
446 if (new_tvb)
447 next_tvb = new_tvb;
448 else
449 next_tvb = tvb_new_subset_remaining(tvb, 24);
450 pinfo->fragmented = save_fragmented;
452 else
453 next_tvb = tvb_new_subset_remaining(tvb, 24);
455 /* If we have a full packet now dissect it */
456 if((new_tvb || !frag->fragmented) && !frag->outoforder)
458 switch(type)
460 case TS2T_LOGINPART2:
461 ts2_parse_loginpart2(next_tvb, ts2_tree);
462 break;
463 case TS2T_CHANNELLIST:
464 ts2_parse_channellist(next_tvb, ts2_tree);
465 break;
466 case TS2T_PLAYERLIST:
467 ts2_parse_playerlist(next_tvb, ts2_tree);
468 break;
469 case TS2T_NEWPLAYERJOINED:
470 ts2_parse_newplayerjoined(next_tvb, ts2_tree);
471 break;
472 case TS2T_KNOWNPLAYERUPDATE:
473 ts2_parse_knownplayerupdate(next_tvb, ts2_tree);
474 break;
475 case TS2T_PLAYERLEFT:
476 ts2_parse_playerleft(next_tvb, ts2_tree);
477 break;
478 case TS2T_PLAYERKICKED:
479 ts2_parse_playerleft(next_tvb, ts2_tree);
480 break;
481 case TS2T_LOGINEND:
482 ts2_parse_loginend(next_tvb, ts2_tree);
483 break;
484 case TS2T_CHANGESTATUS:
485 ts2_parse_changestatus(next_tvb, ts2_tree);
486 break;
487 case TS2T_SWITCHCHANNEL:
488 ts2_parse_switchchannel(next_tvb, ts2_tree);
489 break;
490 case TS2T_CHANNELCHANGE:
491 ts2_parse_channelchange(next_tvb, ts2_tree);
492 break;
495 /* The packet is out of order, update the cinfo and ignore the packet */
496 if(frag->outoforder)
497 col_append_str(pinfo->cinfo, COL_INFO, " (Out Of Order, ignored)");
501 /* Parses a ts2 new player joined (TS2_NEWPLAYERJOINED) packet and adds it to the tree */
502 static void ts2_parse_newplayerjoined(tvbuff_t *tvb, proto_tree *ts2_tree)
504 gint32 offset;
505 offset=0;
506 proto_tree_add_item(ts2_tree, hf_ts2_player_id, tvb, offset, 4, ENC_LITTLE_ENDIAN);
507 offset+=4;
508 proto_tree_add_item(ts2_tree, hf_ts2_channel_id, tvb, offset, 4, ENC_LITTLE_ENDIAN);
509 offset+=4;
510 proto_tree_add_item(ts2_tree, hf_ts2_unknown, tvb, offset, 6, ENC_NA);
511 offset+=6;
512 proto_tree_add_item(ts2_tree, hf_ts2_nick, tvb, offset, 1, ENC_ASCII|ENC_NA);
515 /* Parses TS2_LOGINEND packet and adds it to the tree */
516 static void ts2_parse_loginend(tvbuff_t *tvb, proto_tree *ts2_tree)
518 gint32 offset;
519 offset=0;
520 proto_tree_add_item(ts2_tree, hf_ts2_unknown, tvb, offset, tvb_length_remaining(tvb, offset), ENC_NA);
523 /* Parses a ts2 known player joined (TS2_KNOWNPLAYERUPDATE) packet and adds it to the tree */
524 static void ts2_parse_knownplayerupdate(tvbuff_t *tvb, proto_tree *ts2_tree)
526 gint32 offset;
527 offset=0;
528 proto_tree_add_item(ts2_tree, hf_ts2_player_id, tvb, offset, 4, ENC_LITTLE_ENDIAN);
529 offset+=4;
530 proto_tree_add_item(ts2_tree, hf_ts2_player_status_flags, tvb, offset, 2, ENC_LITTLE_ENDIAN);
531 ts2_add_statusflags(tvb, ts2_tree, offset);
534 /* Parses a ts2 switch channel (TS2_SWITCHCHANNEL) packet and adds it to the tree */
535 static void ts2_parse_switchchannel(tvbuff_t *tvb, proto_tree *ts2_tree)
537 gint32 offset;
538 offset=0;
539 proto_tree_add_item(ts2_tree, hf_ts2_channel_id, tvb, offset, 4, ENC_LITTLE_ENDIAN);
540 offset+=4;
541 proto_tree_add_item(ts2_tree, hf_ts2_password, tvb, offset, 1, ENC_ASCII|ENC_NA);
544 /* Parses a ts2 channel change (TS2T_CHANNELCHANGE) packet and adds it to the tree */
545 static void ts2_parse_channelchange(tvbuff_t *tvb, proto_tree *ts2_tree)
547 gint32 offset;
548 offset=0;
549 proto_tree_add_item(ts2_tree, hf_ts2_player_id, tvb, offset, 4, ENC_LITTLE_ENDIAN);
550 offset+=4;
551 proto_tree_add_item(ts2_tree, hf_ts2_channel_id, tvb, offset, 4, ENC_LITTLE_ENDIAN);
552 offset+=4;
553 proto_tree_add_item(ts2_tree, hf_ts2_channel_id, tvb, offset, 4, ENC_LITTLE_ENDIAN);
554 offset+=4;
555 proto_tree_add_item(ts2_tree, hf_ts2_unknown, tvb, offset, 2, ENC_NA);
559 /* Parses a ts2 change status (TS2_CHANGESTATUS) packet and adds it to the tree */
560 static void ts2_parse_changestatus(tvbuff_t *tvb, proto_tree *ts2_tree)
562 gint32 offset;
563 offset=0;
564 proto_tree_add_item(ts2_tree, hf_ts2_player_status_flags, tvb, offset, 2, ENC_LITTLE_ENDIAN);
565 ts2_add_statusflags(tvb, ts2_tree, offset);
569 /* Parses a ts2 known player left (TS2_PLAYERLEFT) packet and adds it to the tree */
570 static void ts2_parse_playerleft(tvbuff_t *tvb, proto_tree *ts2_tree)
572 gint32 offset;
573 offset=0;
574 proto_tree_add_item(ts2_tree, hf_ts2_player_id, tvb, offset, 4, ENC_LITTLE_ENDIAN);
575 offset+=4;
576 proto_tree_add_item(ts2_tree, hf_ts2_unknown, tvb, offset, 4, ENC_NA);
577 offset+=4;
578 proto_tree_add_item(ts2_tree, hf_ts2_unknown, tvb, offset, 4, ENC_NA);
579 offset+=4;
580 proto_tree_add_item(ts2_tree, hf_ts2_unknown, tvb, offset, tvb_length_remaining(tvb, offset), ENC_NA);
583 /* Parses a ts2 login part 2 (TS2T_LOGINPART2) packet and adds it to the tree */
584 static void ts2_parse_loginpart2(tvbuff_t *tvb, proto_tree *ts2_tree)
586 gint32 offset;
587 offset=0;
588 proto_tree_add_item(ts2_tree, hf_ts2_unknown, tvb, 0, 2, ENC_NA);
589 offset+=2;
590 proto_tree_add_item(ts2_tree, hf_ts2_channel, tvb, offset, 1, ENC_ASCII|ENC_NA);
591 offset+=30;
592 proto_tree_add_item(ts2_tree, hf_ts2_subchannel, tvb, offset, 1, ENC_ASCII|ENC_NA);
593 offset+=30;
594 proto_tree_add_item(ts2_tree, hf_ts2_channelpassword, tvb, offset, 1, ENC_ASCII|ENC_NA);
595 offset+=30;
596 proto_tree_add_item(ts2_tree, hf_ts2_unknown, tvb, offset, 4, ENC_NA);
599 /* Parses a ts2 channel list (TS2T_CHANNELLIST) and adds it to the tree */
600 static void ts2_parse_channellist(tvbuff_t *tvb, proto_tree *ts2_tree)
602 gint32 offset;
603 guint32 string_len;
604 proto_tree *subtree;
605 proto_item *item;
607 offset=0;
608 proto_tree_add_item(ts2_tree, hf_ts2_number_of_channels, tvb, offset, 4, ENC_LITTLE_ENDIAN);
609 offset+=4;
610 while(offset<tvb_length_remaining(tvb, 0))
612 proto_tree_add_item(ts2_tree, hf_ts2_channel_id, tvb, offset, 4, ENC_LITTLE_ENDIAN);
613 offset+=4;
615 /* Channel flags */
616 item = proto_tree_add_item(ts2_tree, hf_ts2_channel_flags, tvb, offset, 1, ENC_LITTLE_ENDIAN);
617 subtree = proto_item_add_subtree(item, ett_ts2_channel_flags);
618 proto_tree_add_item(subtree, hf_ts2_channel_unregistered, tvb, offset, 1, ENC_BIG_ENDIAN);
619 proto_tree_add_item(subtree, hf_ts2_channel_moderated, tvb, offset, 1, ENC_BIG_ENDIAN);
620 proto_tree_add_item(subtree, hf_ts2_channel_password, tvb, offset, 1, ENC_BIG_ENDIAN);
621 proto_tree_add_item(subtree, hf_ts2_channel_subchannels, tvb, offset, 1, ENC_BIG_ENDIAN);
622 proto_tree_add_item(subtree, hf_ts2_channel_default, tvb, offset, 1, ENC_BIG_ENDIAN);
623 offset+=1;
625 proto_tree_add_item(ts2_tree, hf_ts2_unknown, tvb, offset, 1, ENC_NA);
626 offset+=1;
627 proto_tree_add_item(ts2_tree, hf_ts2_codec, tvb, offset, 2, ENC_LITTLE_ENDIAN);
628 offset+=2;
629 proto_tree_add_item(ts2_tree, hf_ts2_parent_channel_id, tvb, offset, 4, ENC_LITTLE_ENDIAN);
630 offset+=4;
631 proto_tree_add_item(ts2_tree, hf_ts2_channel_order, tvb, offset, 2, ENC_LITTLE_ENDIAN);
632 offset+=2;
633 proto_tree_add_item(ts2_tree, hf_ts2_max_users, tvb, offset, 2, ENC_LITTLE_ENDIAN);
634 offset+=2;
635 tvb_get_stringz(wmem_packet_scope(), tvb, offset, &string_len);
636 proto_tree_add_item(ts2_tree, hf_ts2_channel_name, tvb, offset,string_len , ENC_ASCII|ENC_NA);
637 offset+=string_len;
638 tvb_get_stringz(wmem_packet_scope(), tvb, offset, &string_len);
639 proto_tree_add_item(ts2_tree, hf_ts2_channel_topic, tvb, offset,string_len ,ENC_ASCII|ENC_NA);
640 offset+=string_len;
641 tvb_get_stringz(wmem_packet_scope(), tvb, offset, &string_len);
642 proto_tree_add_item(ts2_tree, hf_ts2_channel_description, tvb, offset,string_len , ENC_ASCII|ENC_NA);
643 offset+=string_len;
647 static void ts2_add_statusflags(tvbuff_t *tvb, proto_tree *ts2_tree, guint32 offset)
649 proto_tree_add_item(ts2_tree, hf_ts2_status_channelcommander, tvb, offset, 2, ENC_LITTLE_ENDIAN);
650 proto_tree_add_item(ts2_tree, hf_ts2_status_blockwhispers, tvb, offset, 2, ENC_LITTLE_ENDIAN);
651 proto_tree_add_item(ts2_tree, hf_ts2_status_away, tvb, offset, 2, ENC_LITTLE_ENDIAN);
652 proto_tree_add_item(ts2_tree, hf_ts2_status_mutemicrophone, tvb, offset, 2, ENC_LITTLE_ENDIAN);
653 proto_tree_add_item(ts2_tree, hf_ts2_status_mute, tvb, offset, 2, ENC_LITTLE_ENDIAN);
657 /* Parses a ts2 player list (TS2T_PLAYERLIST) and adds it to the tree */
658 static void ts2_parse_playerlist(tvbuff_t *tvb, proto_tree *ts2_tree)
660 gint32 offset;
661 gint32 number_of_players;
662 gint32 x;
663 offset=0;
664 x=0;
665 proto_tree_add_item(ts2_tree, hf_ts2_number_of_players, tvb, offset, 4, ENC_LITTLE_ENDIAN);
666 number_of_players = tvb_get_letohl(tvb, 0);
667 offset+=4;
668 while(offset<tvb_length_remaining(tvb, 0) && x<number_of_players)
670 proto_tree_add_item(ts2_tree, hf_ts2_player_id, tvb, offset, 4, ENC_LITTLE_ENDIAN);
671 offset+=4;
672 proto_tree_add_item(ts2_tree, hf_ts2_channel_id, tvb, offset, 4, ENC_LITTLE_ENDIAN);
673 offset+=4;
674 proto_tree_add_item(ts2_tree, hf_ts2_unknown, tvb, offset, 4, ENC_NA);
675 offset+=4;
676 proto_tree_add_item(ts2_tree, hf_ts2_player_status_flags, tvb, offset, 2, ENC_LITTLE_ENDIAN);
677 ts2_add_statusflags(tvb, ts2_tree, offset);
678 offset+=2;
679 proto_tree_add_item(ts2_tree, hf_ts2_nick, tvb, offset, 1, ENC_ASCII|ENC_NA);
680 offset+=30;
681 x++;
683 proto_tree_add_item(ts2_tree, hf_ts2_emptyspace, tvb, offset, tvb_length_remaining(tvb, 0), ENC_NA);
688 /* Find the current conversation or make a new one if required */
689 static ts2_conversation* ts2_get_conversation(packet_info *pinfo)
691 conversation_t *conversation;
692 ts2_conversation *conversation_data;
693 conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype, pinfo->srcport, pinfo->destport, 0);
694 if(conversation)
696 conversation_data = (ts2_conversation*)conversation_get_proto_data(conversation, proto_ts2);
698 else
700 conversation_data = wmem_new(wmem_file_scope(), ts2_conversation);
701 conversation_data->last_inorder_server_frame=0; /* sequence number should never be zero so we can use this as an initial number */
702 conversation_data->last_inorder_client_frame=0;
703 conversation_data->server_port=pinfo->srcport;
704 conversation_data->server_frag_size=0;
705 conversation_data->server_frag_num=0;
706 conversation_data->client_frag_size=0;
707 conversation_data->client_frag_num=0;
708 conversation = conversation_new(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype, pinfo->srcport, pinfo->destport, 0);
709 conversation_add_proto_data(conversation, proto_ts2, (void *)conversation_data);
711 return conversation_data;
716 /* Dissect a TS2 packet */
717 static void dissect_ts2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
719 ts2_conversation *conversation_data;
720 guint16 type = tvb_get_letohs(tvb, 2);
721 guint16 klass = tvb_get_letohs(tvb, 0);
723 conversation_data = ts2_get_conversation(pinfo);
725 col_set_str(pinfo->cinfo, COL_PROTOCOL, "TS2");
727 if(klass==TS2C_ACK)
728 col_add_fstr(pinfo->cinfo, COL_INFO, "Class: %s", val_to_str(klass, classnames, "Unknown (0x%02x)"));
729 else
730 col_add_fstr(pinfo->cinfo, COL_INFO, "Type: %s, Class: %s", val_to_str(type, typenames, "Unknown (0x%02x)"), val_to_str(klass, classnames, "Unknown (0x%02x)"));
732 /* XXX: We need to do all the non GUI stuff whether or not if(tree) */
733 /* Do only once by checking visited ? */
734 /* ToDo: Rewrite ?? */
735 if (!tree) {
736 switch(klass) {
737 case TS2C_CONNECTION:
738 switch(type) {
739 case TS2T_LOGINREQUEST:
740 conversation_data->server_port=pinfo->destport;
741 conversation_data->server_addr=pinfo->dst;
742 break;
744 break;
745 case TS2C_STANDARD:
746 ts2_standard_dissect(tvb, pinfo, tree, conversation_data);
747 break;
751 if (tree) { /* we are being asked for details */
752 proto_item *ti = NULL;
753 proto_tree *ts2_tree = NULL;
755 ti = proto_tree_add_item(tree, proto_ts2, tvb, 0, -1, ENC_NA);
756 ts2_tree = proto_item_add_subtree(ti, ett_ts2);
758 proto_tree_add_item(ts2_tree, hf_ts2_class, tvb, 0, 2, ENC_LITTLE_ENDIAN);
759 if(klass==TS2C_ACK)
760 proto_tree_add_item(ts2_tree, hf_ts2_resend_count, tvb, 2, 2, ENC_LITTLE_ENDIAN);
761 else
762 proto_tree_add_item(ts2_tree, hf_ts2_type, tvb, 2, 2, ENC_LITTLE_ENDIAN);
764 proto_tree_add_item(ts2_tree, hf_ts2_sessionkey, tvb, 4, 4, ENC_LITTLE_ENDIAN);
765 proto_tree_add_item(ts2_tree, hf_ts2_clientid, tvb, 8, 4, ENC_LITTLE_ENDIAN);
766 switch(klass)
768 case TS2C_CONNECTION:
769 proto_tree_add_item(ts2_tree, hf_ts2_seqnum, tvb, 12, 4, ENC_LITTLE_ENDIAN);
770 ts2_add_checked_crc32(ts2_tree, hf_ts2_crc32, tvb, 16, tvb_get_letohl(tvb, 16));
772 switch(type)
774 case TS2T_PING:
775 break;
776 case TS2T_PINGREPLY:
777 proto_tree_add_item(ts2_tree, hf_ts2_ackto, tvb, 20, 4, ENC_LITTLE_ENDIAN);
778 break;
779 case TS2T_LOGINREQUEST:
780 proto_tree_add_item(ts2_tree, hf_ts2_protocol_string, tvb, 20, 1, ENC_ASCII|ENC_NA);
781 proto_tree_add_item(ts2_tree, hf_ts2_platform_string, tvb, 50, 1, ENC_ASCII|ENC_NA);
782 proto_tree_add_item(ts2_tree, hf_ts2_unknown, tvb, 80, 9, ENC_NA);
783 proto_tree_add_item(ts2_tree, hf_ts2_registeredlogin, tvb, 90, 1, ENC_LITTLE_ENDIAN);
784 proto_tree_add_item(ts2_tree, hf_ts2_name, tvb, 90, 1, ENC_ASCII|ENC_NA);
785 proto_tree_add_item(ts2_tree, hf_ts2_password, tvb, 120, 1, ENC_ASCII|ENC_NA);
786 proto_tree_add_item(ts2_tree, hf_ts2_nick, tvb, 150, 1, ENC_ASCII|ENC_NA);
788 conversation_data->server_port=pinfo->destport;
789 conversation_data->server_addr=pinfo->dst;
791 break;
792 case TS2T_LOGINREPLY:
793 proto_tree_add_item(ts2_tree, hf_ts2_server_name, tvb, 20, 1, ENC_ASCII|ENC_NA);
794 proto_tree_add_item(ts2_tree, hf_ts2_platform_string, tvb, 50, 1, ENC_ASCII|ENC_NA);
795 proto_tree_add_item(ts2_tree, hf_ts2_unknown, tvb, 80, 9, ENC_NA);
796 proto_tree_add_item(ts2_tree, hf_ts2_badlogin, tvb, 89, 3, ENC_LITTLE_ENDIAN);
797 proto_tree_add_item(ts2_tree, hf_ts2_unknown, tvb, 92, 80, ENC_NA);
798 proto_tree_add_item(ts2_tree, hf_ts2_sessionkey, tvb, 172, 4, ENC_LITTLE_ENDIAN);
799 proto_tree_add_item(ts2_tree, hf_ts2_unknown, tvb, 178, 3, ENC_NA);
800 proto_tree_add_item(ts2_tree, hf_ts2_server_welcome_message, tvb, 180, 1, ENC_ASCII|ENC_NA);
801 break;
803 break;
804 case TS2C_ACK:
805 /* Ignore the type for ACK, it's always zero and clashes with CELP_5_1 */
807 proto_tree_add_item(ts2_tree, hf_ts2_seqnum, tvb, 12, 4, ENC_LITTLE_ENDIAN);
808 break;
809 case TS2C_STANDARD:
810 ts2_standard_dissect(tvb, pinfo, ts2_tree, conversation_data);
811 break;
813 } /* if (tree) */
818 /* Calculates a CRC32 checksum from the tvb zeroing out four bytes at the offset and checks it with the given crc32 and adds the result to the tree
819 * Returns true if the calculated CRC32 matches the passed CRC32.
820 * */
821 static gboolean ts2_add_checked_crc32(proto_tree *tree, int hf_item, tvbuff_t *tvb, guint16 offset, guint32 icrc32 )
823 guint8 *zero;
824 gint len;
825 guint32 ocrc32;
827 zero = (guint8 *)wmem_alloc0(wmem_packet_scope(), 4);
828 ocrc32 = crc32_ccitt_tvb(tvb, offset);
829 ocrc32 = crc32_ccitt_seed(zero, 4, 0xffffffff-ocrc32);
830 len = tvb_reported_length_remaining(tvb, offset+4);
831 if (len<0)
832 return FALSE;
833 ocrc32 = crc32_ccitt_tvb_offset_seed(tvb, offset+4, (guint)len, 0xffffffff-ocrc32);
834 if(icrc32==ocrc32)
836 proto_tree_add_uint_format(tree, hf_item, tvb, offset, 4, tvb_get_letohl(tvb, 16), "crc32: 0x%04x [correct]", tvb_get_letohl(tvb, offset));
837 return TRUE;
839 else
841 proto_tree_add_uint_format(tree, hf_item, tvb, offset, 4, tvb_get_letohl(tvb,16), "crc32: 0x%04x [incorrect, should be 0x%04x]", tvb_get_letohl(tvb, offset),ocrc32);
842 return FALSE;
846 static void ts2_init(void)
848 reassembly_table_init(&msg_reassembly_table,
849 &addresses_reassembly_table_functions);
853 * proto_register_ts2()
854 * */
855 void proto_register_ts2(void)
857 static hf_register_info hf[] = {
858 { &hf_ts2_class,
859 { "Class", "ts2.class",
860 FT_UINT16, BASE_HEX,
861 VALS(classnames), 0x0,
862 NULL, HFILL }
864 { &hf_ts2_type,
865 { "Type", "ts2.type",
866 FT_UINT16, BASE_HEX,
867 VALS(typenames), 0x0,
868 NULL, HFILL }
870 { &hf_ts2_clientid,
871 { "Client id", "ts2.clientid",
872 FT_UINT32, BASE_DEC,
873 NULL, 0x0,
874 NULL, HFILL }
876 { &hf_ts2_sessionkey,
877 { "Session Key", "ts2.sessionkey",
878 FT_UINT32, BASE_HEX,
879 NULL, 0x0,
880 NULL, HFILL }
882 { &hf_ts2_ackto,
883 { "Ping Reply To", "ts2.ping_ackto",
884 FT_UINT32, BASE_DEC,
885 NULL, 0x0,
886 NULL, HFILL }
888 { &hf_ts2_crc32,
889 { "CRC32 Checksum", "ts2.crc32",
890 FT_UINT32, BASE_HEX,
891 NULL, 0x0,
892 NULL, HFILL }
894 { &hf_ts2_seqnum,
895 { "Sequence Number", "ts2.sequencenum",
896 FT_UINT32, BASE_DEC,
897 NULL, 0x0,
898 NULL, HFILL }
900 { &hf_ts2_protocol_string,
901 { "Protocol String", "ts2.protocolstring",
902 FT_UINT_STRING, BASE_NONE,
903 NULL, 0x0,
904 NULL, HFILL }
906 #if 0
907 { &hf_ts2_string,
908 { "String", "ts2.string",
909 FT_STRING, BASE_NONE,
910 NULL, 0x0,
911 NULL, HFILL }
913 #endif
914 { &hf_ts2_registeredlogin,
915 { "Registered Login", "ts2.registeredlogin",
916 FT_BOOLEAN, BASE_NONE,
917 NULL, 0x0,
918 NULL, HFILL }
920 { &hf_ts2_name,
921 { "Name", "ts2.name",
922 FT_UINT_STRING, BASE_NONE,
923 NULL, 0x0,
924 NULL, HFILL }
926 { &hf_ts2_password,
927 { "Password", "ts2.password",
928 FT_UINT_STRING, BASE_NONE,
929 NULL, 0x0,
930 NULL, HFILL }
932 { &hf_ts2_nick,
933 { "Nick", "ts2.nick",
934 FT_UINT_STRING, BASE_NONE,
935 NULL, 0x0,
936 NULL, HFILL }
938 { &hf_ts2_badlogin,
939 { "Bad Login", "ts2.badlogin",
940 FT_BOOLEAN, BASE_NONE,
941 NULL, 0x0,
942 NULL, HFILL }
944 { &hf_ts2_unknown,
945 { "Unknown", "ts2.unknown",
946 FT_BYTES, BASE_NONE,
947 NULL, 0x0,
948 NULL, HFILL }
950 { &hf_ts2_channel,
951 { "Channel", "ts2.channel",
952 FT_UINT_STRING, BASE_NONE,
953 NULL, 0x0,
954 NULL, HFILL }
956 { &hf_ts2_subchannel,
957 { "Sub-Channel", "ts2.subchannel",
958 FT_UINT_STRING, BASE_NONE,
959 NULL, 0x0,
960 NULL, HFILL }
962 { &hf_ts2_channelpassword,
963 { "Channel Password", "ts2.channelpassword",
964 FT_UINT_STRING, BASE_NONE,
965 NULL, 0x0,
966 NULL, HFILL }
968 { &hf_ts2_emptyspace,
969 { "Empty Space", "ts2.emptyspace",
970 FT_NONE, BASE_NONE,
971 NULL, 0x0,
972 NULL, HFILL }
974 { &hf_ts2_fragmentnumber,
975 { "Fragment Number", "ts2.fragmentnumber",
976 FT_UINT16, BASE_DEC,
977 NULL, 0x0,
978 NULL, HFILL }
980 { &hf_ts2_platform_string,
981 { "Platform String", "ts2.platformstring",
982 FT_UINT_STRING, BASE_NONE,
983 NULL, 0x0,
984 NULL, HFILL }
986 { &hf_ts2_server_name,
987 { "Server Name", "ts2.servername",
988 FT_UINT_STRING, BASE_NONE,
989 NULL, 0x0,
990 NULL, HFILL }
992 { &hf_ts2_server_welcome_message,
993 { "Server Welcome Message", "ts2.serverwelcomemessage",
994 FT_UINT_STRING, BASE_NONE,
995 NULL, 0x0,
996 NULL, HFILL }
998 { &hf_ts2_parent_channel_id,
999 { "Parent Channel ID", "ts2.parentchannelid",
1000 FT_UINT32, BASE_HEX,
1001 NULL, 0x0,
1002 NULL, HFILL }
1004 { &hf_ts2_codec,
1005 { "Codec", "ts2.codec",
1006 FT_UINT16, BASE_HEX,
1007 VALS(codecnames), 0x0,
1008 NULL, HFILL }
1010 { &hf_ts2_channel_flags,
1011 { "Channel Flags", "ts2.channelflags",
1012 FT_UINT8, BASE_HEX,
1013 NULL, 0x0,
1014 NULL, HFILL }
1016 { &hf_ts2_channel_id,
1017 { "Channel Id", "ts2.chanelid",
1018 FT_UINT32, BASE_DEC,
1019 NULL, 0x0,
1020 NULL, HFILL }
1022 { &hf_ts2_channel_name,
1023 { "Channel Name", "ts2.chanelname",
1024 FT_STRINGZ, BASE_NONE,
1025 NULL, 0x0,
1026 NULL, HFILL }
1028 { &hf_ts2_channel_topic,
1029 { "Channel Topic", "ts2.chaneltopic",
1030 FT_STRINGZ, BASE_NONE,
1031 NULL, 0x0,
1032 NULL, HFILL }
1034 { &hf_ts2_channel_description,
1035 { "Channel Description", "ts2.chaneldescription",
1036 FT_STRINGZ, BASE_NONE,
1037 NULL, 0x0,
1038 NULL, HFILL }
1040 { &hf_ts2_player_id,
1041 { "Player Id", "ts2.playerid",
1042 FT_UINT32, BASE_DEC,
1043 NULL, 0x0,
1044 NULL, HFILL }
1046 { &hf_ts2_player_status_flags,
1047 { "Player Status Flags", "ts2.playerstatusflags",
1048 FT_UINT16, BASE_DEC,
1049 NULL, 0x0,
1050 NULL, HFILL }
1052 { &hf_ts2_number_of_players,
1053 { "Number Of Players", "ts2.numberofplayers",
1054 FT_UINT32, BASE_DEC,
1055 NULL, 0x0,
1056 NULL, HFILL }
1058 { &hf_ts2_number_of_channels,
1059 { "Number Of Channels", "ts2.numberofchannels",
1060 FT_UINT32, BASE_DEC,
1061 NULL, 0x0,
1062 NULL, HFILL }
1064 { &hf_ts2_resend_count,
1065 { "Resend Count", "ts2.resendcount",
1066 FT_UINT16, BASE_DEC,
1067 NULL, 0x0,
1068 NULL, HFILL }
1070 { &hf_ts2_status_channelcommander,
1071 { "Channel Commander", "ts2.playerstatusflags.channelcommander",
1072 FT_BOOLEAN, 8,
1073 NULL, TS2_STATUS_CHANNELCOMMANDER,
1074 NULL, HFILL }
1076 { &hf_ts2_status_blockwhispers,
1077 { "Block Whispers", "ts2.playerstatusflags.blockwhispers",
1078 FT_BOOLEAN, 8,
1079 NULL, TS2_STATUS_BLOCKWHISPERS,
1080 NULL, HFILL }
1082 { &hf_ts2_status_away,
1083 { "Away", "ts2.playerstatusflags.away",
1084 FT_BOOLEAN, 8,
1085 NULL, TS2_STATUS_AWAY,
1086 NULL, HFILL }
1088 { &hf_ts2_status_mutemicrophone,
1089 { "Mute Microphone", "ts2.playerstatusflags.mutemicrophone",
1090 FT_BOOLEAN, 8,
1091 NULL, TS2_STATUS_MUTEMICROPHONE,
1092 NULL, HFILL }
1094 { &hf_ts2_status_mute,
1095 { "Mute", "ts2.playerstatusflags.mute",
1096 FT_BOOLEAN, 8,
1097 NULL, TS2_STATUS_MUTE,
1098 NULL, HFILL }
1100 { &hf_msg_fragments,
1101 {"Message fragments", "ts2.fragments",
1102 FT_NONE, BASE_NONE,
1103 NULL, 0x00,
1104 NULL, HFILL }
1106 { &hf_msg_fragment,
1107 {"Message fragment", "ts2.fragment",
1108 FT_FRAMENUM, BASE_NONE,
1109 NULL, 0x00,
1110 NULL, HFILL }
1112 { &hf_msg_fragment_overlap,
1113 {"Message fragment overlap", "ts2.fragment.overlap",
1114 FT_BOOLEAN, BASE_NONE,
1115 NULL, 0x0,
1116 NULL, HFILL }
1118 { &hf_msg_fragment_overlap_conflicts,
1119 {"Message fragment overlapping with conflicting data",
1120 "ts2.fragment.overlap.conflicts",
1121 FT_BOOLEAN, BASE_NONE,
1122 NULL, 0x0,
1123 NULL, HFILL }
1125 { &hf_msg_fragment_multiple_tails,
1126 {"Message has multiple tail fragments",
1127 "ts2.fragment.multiple_tails",
1128 FT_BOOLEAN, BASE_NONE,
1129 NULL, 0x0,
1130 NULL, HFILL }
1132 { &hf_msg_fragment_too_long_fragment,
1133 {"Message fragment too long", "ts2.fragment.too_long_fragment",
1134 FT_BOOLEAN, BASE_NONE,
1135 NULL, 0x0,
1136 NULL, HFILL }
1138 { &hf_msg_fragment_error,
1139 {"Message defragmentation error", "ts2.fragment.error",
1140 FT_FRAMENUM, BASE_NONE,
1141 NULL, 0x00,
1142 NULL, HFILL }
1144 { &hf_msg_fragment_count,
1145 {"Message fragment count", "ts2.fragment.count",
1146 FT_UINT32, BASE_DEC,
1147 NULL, 0x00,
1148 NULL, HFILL }
1150 { &hf_msg_reassembled_in,
1151 {"Reassembled in", "ts2.reassembled.in",
1152 FT_FRAMENUM, BASE_NONE,
1153 NULL, 0x00,
1154 NULL, HFILL }
1156 { &hf_msg_reassembled_length,
1157 {"Reassembled TeamSpeak2 length", "ts2.reassembled.length",
1158 FT_UINT32, BASE_DEC,
1159 NULL, 0x00,
1160 NULL, HFILL }
1162 { &hf_ts2_channel_unregistered,
1163 { "Unregistered", "ts2.channelflags.unregistered",
1164 FT_BOOLEAN, 8,
1165 NULL, 0x01,
1166 NULL, HFILL }
1168 { &hf_ts2_channel_moderated,
1169 { "Moderated", "ts2.channelflags.moderated",
1170 FT_BOOLEAN, 8,
1171 NULL, 0x02,
1172 NULL, HFILL }
1174 { &hf_ts2_channel_password,
1175 { "Has password", "ts2.channelflags.has_password",
1176 FT_BOOLEAN, 8,
1177 NULL, 0x04,
1178 NULL, HFILL }
1180 { &hf_ts2_channel_subchannels,
1181 { "Has subchannels", "ts2.channelflags.has_subchannels",
1182 FT_BOOLEAN, 8,
1183 NULL, 0x08,
1184 NULL, HFILL }
1186 { &hf_ts2_channel_default,
1187 { "Default", "ts2.channelflags.default",
1188 FT_BOOLEAN, 8,
1189 NULL, 0x10,
1190 NULL, HFILL }
1192 { &hf_ts2_channel_order,
1193 { "Channel order", "ts2.channelorder",
1194 FT_UINT16, BASE_DEC,
1195 NULL, 0x00,
1196 NULL, HFILL }
1198 { &hf_ts2_max_users,
1199 { "Max users", "ts2.maxusers",
1200 FT_UINT16, BASE_DEC,
1201 NULL, 0x00,
1202 NULL, HFILL }
1206 static gint *ett[] = {
1207 &ett_ts2,
1208 &ett_msg_fragment,
1209 &ett_msg_fragments,
1210 &ett_ts2_channel_flags
1213 /* Setup protocol subtree array */
1214 proto_ts2 = proto_register_protocol (
1215 "Teamspeak2 Protocol", /* name */
1216 "TeamSpeak2", /* short name */
1217 "ts2" /* abbrev */
1219 proto_register_field_array(proto_ts2, hf, array_length(hf));
1220 proto_register_subtree_array(ett, array_length(ett));
1222 register_init_routine(ts2_init);
1226 * proto_reg_handoff_ts2()
1227 * */
1228 void proto_reg_handoff_ts2(void)
1230 dissector_handle_t ts2_handle;
1231 ts2_handle = create_dissector_handle(dissect_ts2, proto_ts2);
1232 dissector_add_uint("udp.port", TS2_PORT, ts2_handle);
1236 * Editor modelines - http://www.wireshark.org/tools/modelines.html
1238 * Local variables:
1239 * c-basic-offset: 4
1240 * tab-width: 8
1241 * indent-tabs-mode: nil
1242 * End:
1244 * vi: set shiftwidth=4 tabstop=8 expandtab:
1245 * :indentSize=4:tabSize=8:noTabs=true: