diff options
author | stig <stig@f5534014-38df-0310-8fa8-9805f1628bb7> | 2008-08-09 18:36:22 +0000 |
---|---|---|
committer | stig <stig@f5534014-38df-0310-8fa8-9805f1628bb7> | 2008-08-09 18:36:22 +0000 |
commit | 3e616563d28975e18d1b16de302b494c6569243d (patch) | |
tree | 387a9e4a7337fffd4448b5d601b4f7bbd2f0c51b /epan/dissectors/packet-teamspeak2.c | |
parent | 7569fc6d0b5d6557ddbb0e2505cd633df6b6b732 (diff) |
From Brooss (bug 2373):
Added TeamSpeak2 dissector
From me:
- Made all local functions static
- Renamed my_vals to conv_vals
- Call correct function to parse LOGINEND
- Fixed some obvious errors in typenames list
- Fixed some indentation
git-svn-id: http://anonsvn.wireshark.org/wireshark/trunk@25973 f5534014-38df-0310-8fa8-9805f1628bb7
Diffstat (limited to 'epan/dissectors/packet-teamspeak2.c')
-rw-r--r-- | epan/dissectors/packet-teamspeak2.c | 1166 |
1 files changed, 1166 insertions, 0 deletions
diff --git a/epan/dissectors/packet-teamspeak2.c b/epan/dissectors/packet-teamspeak2.c new file mode 100644 index 0000000000..56bf3a833e --- /dev/null +++ b/epan/dissectors/packet-teamspeak2.c @@ -0,0 +1,1166 @@ +/* packet-teamspeak2.c + * Routines for TeamSpeak2 protocol packet disassembly + * By brooss <brooss.teambb@gmail.com> + * Copyright 2008 brooss + * + * $Id$ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1998 + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <epan/packet.h> +#include <epan/prefs.h> +#include <epan/crc32.h> +#include <epan/reassemble.h> +#include <epan/conversation.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + + +/* Packet Classes */ +#define TS2C_STANDARD 0xbef0 +#define TS2C_ACK 0xbef1 +#define TS2C_CLIENT_VOICE 0xbef2 +#define TS2C_SERVER_VOICE 0xbef3 +#define TS2C_CONNECTION 0xbef4 + +/* Packet Types */ +#define TS2T_PING 0x0001 +#define TS2T_PINGREPLY 0x0002 +#define TS2T_LOGINREQUEST 0x0003 +#define TS2T_LOGINREPLY 0x0004 +#define TS2T_LOGINPART2 0x0005 +#define TS2T_CHANNELLIST 0x0006 +#define TS2T_PLAYERLIST 0x0007 +#define TS2T_LOGINEND 0x0008 + +#define TS2T_TEXTMESSAGE 0x0082 +#define TS2T_CHANNEL_PLAYERLIST 0x006c +#define TS2T_CHANNELCHANGE 0x0067 +#define TS2T_CHANNELLISTUPDATE 0x006e +#define TS2T_PLAYERKICKED 0x0066 +#define TS2T_PLAYERLEFT 0x0065 +#define TS2T_NEWPLAYERJOINED 0x0064 +#define TS2T_KNOWNPLAYERUPDATE 0x0068 +#define TS2T_CHANNELDELETED 0x0073 +#define TS2T_CHANNELNAMECHANGED 0x006f +#define TS2T_CHANNELTOPICCHANGED 0x0070 +#define TS2T_CHANNELPASSWORDCHANGED 0x0071 +#define TS2T_CREATECHANNEL 0x00c9 +#define TS2T_DISCONNECT 0x012c +#define TS2T_SWITCHCHANNEL 0x012f +#define TS2T_CHANGESTATUS 0x0130 +#define TS2T_CHATMESSAGEBOUNCE 0xfc0f + +#define TS2T_VOICE_DATA_CELP_5_1 0x0000 +#define TS2T_VOICE_DATA_CELP_6_3 0x0100 +#define TS2T_VOICE_DATA_GSM_14_8 0x0200 +#define TS2T_VOICE_DATA_GSM_16_4 0x0300 +#define TS2T_VOICE_DATA_CELP_WINDOWS_5_2 0x0400 +#define TS2T_VOICE_DATA_SPEEX_3_4 0x0500 +#define TS2T_VOICE_DATA_SPEEX_5_2 0x0600 +#define TS2T_VOICE_DATA_SPEEX_7_2 0x0700 +#define TS2T_VOICE_DATA_SPEEX_9_3 0x0800 +#define TS2T_VOICE_DATA_SPEEX_12_3 0x0900 +#define TS2T_VOICE_DATA_SPEEX_16_3 0x0a00 +#define TS2T_VOICE_DATA_SPEEX_19_5 0x0b00 +#define TS2T_VOICE_DATA_SPEEX_25_9 0x0c00 + +/* Codec Types */ +#define TS2T_CODEC_CELP_5_1 0x0000 +#define TS2T_CODEC_CELP_6_3 0x0001 +#define TS2T_CODEC_GSM_14_8 0x0002 +#define TS2T_CODEC_GSM_16_4 0x0003 +#define TS2T_CODEC_CELP_WINDOWS_5_2 0x0004 +#define TS2T_CODEC_SPEEX_3_4 0x0005 +#define TS2T_CODEC_SPEEX_5_2 0x0006 +#define TS2T_CODEC_SPEEX_7_2 0x0007 +#define TS2T_CODEC_SPEEX_9_3 0x0008 +#define TS2T_CODEC_SPEEX_12_3 0x0009 +#define TS2T_CODEC_SPEEX_16_3 0x000a +#define TS2T_CODEC_SPEEX_19_5 0x000b +#define TS2T_CODEC_SPEEX_25_9 0x000c + +/* Player Status Flags */ +#define TS2_STATUS_CHANNELCOMMANDER 1 +#define TS2_STATUS_BLOCKWHISPERS 4 +#define TS2_STATUS_AWAY 8 +#define TS2_STATUS_MUTEMICROPHONE 16 +#define TS2_STATUS_MUTE 32 + + +static int hf_msg_fragments = -1; +static int hf_msg_fragment = -1; +static int hf_msg_fragment_overlap = -1; +static int hf_msg_fragment_overlap_conflicts = -1; +static int hf_msg_fragment_multiple_tails = -1; +static int hf_msg_fragment_too_long_fragment = -1; +static int hf_msg_fragment_error = -1; +static int hf_msg_reassembled_in = -1; + +static gint ett_msg_fragment = -1; +static gint ett_msg_fragments = -1; + +static const fragment_items msg_frag_items = { + /* Fragment subtrees */ + &ett_msg_fragment, + &ett_msg_fragments, + /* Fragment fields */ + &hf_msg_fragments, + &hf_msg_fragment, + &hf_msg_fragment_overlap, + &hf_msg_fragment_overlap_conflicts, + &hf_msg_fragment_multiple_tails, + &hf_msg_fragment_too_long_fragment, + &hf_msg_fragment_error, + /* Reassembled in field */ + &hf_msg_reassembled_in, + /* Tag */ + "Message fragments" +}; + +/* Class names */ +static const value_string classnames[] = +{ + { TS2C_CONNECTION, "Connection" }, + { TS2C_ACK, "ACK"}, + { TS2C_STANDARD, "Standard (reliable)"}, + { TS2C_SERVER_VOICE, "Voice"}, + { TS2C_CLIENT_VOICE, "Voice"}, + { 0, NULL } +}; + +/* Type names */ +static const value_string typenames[] = { + { TS2T_PING, "Ping" }, + { TS2T_PINGREPLY, "Ping Reply" }, + { TS2T_LOGINREQUEST, "Login Request" }, + { TS2T_LOGINREPLY, "Login Reply" }, + { TS2T_LOGINPART2, "Login Part 2" }, + { TS2T_CHANNELLIST, "Channel List" }, + { TS2T_PLAYERLIST, "Player List" }, + { TS2T_LOGINEND, "Login End" }, + { TS2T_TEXTMESSAGE, "Text Message" }, + + + { TS2T_CHANNEL_PLAYERLIST, "Channel Player List" }, + { TS2T_CHANNELCHANGE, "Channel Change" }, + + { TS2T_CHANNELLISTUPDATE, "Channel List Update" }, + { TS2T_PLAYERKICKED, "Player Kicked" }, + { TS2T_PLAYERLEFT, "Player Left" }, + { TS2T_NEWPLAYERJOINED, "New Player Joined" }, + { TS2T_KNOWNPLAYERUPDATE, "Known Player Update" }, + { TS2T_CHANNELDELETED, "Channel Deleted" }, + { TS2T_CHANNELNAMECHANGED, "Channel Name Change" }, + { TS2T_CHANNELTOPICCHANGED, "Channel Topic Change" }, + { TS2T_CHANNELPASSWORDCHANGED, "Channel Password Change" }, + { TS2T_CREATECHANNEL, "Create Channel" }, + { TS2T_DISCONNECT, "Disconnect" }, + { TS2T_SWITCHCHANNEL, "Switch Channel"}, + { TS2T_CHANGESTATUS, "Change Status" }, + + { TS2T_CHATMESSAGEBOUNCE, "Chat Message Bounce" }, + + { TS2T_VOICE_DATA_CELP_5_1, "TS2T_VOICE_DATA_CELP_5_1" }, + { TS2T_VOICE_DATA_CELP_6_3, "TS2T_VOICE_DATA_CELP_6_3" }, + { TS2T_VOICE_DATA_GSM_14_8, "TS2T_VOICE_DATA_GSM_14_8" }, + { TS2T_VOICE_DATA_GSM_16_4, "TS2T_VOICE_DATA_GSM_16_4" }, + { TS2T_VOICE_DATA_CELP_WINDOWS_5_2, "TS2T_VOICE_DATA_CELP_WINDOWS_5_2" }, + { TS2T_VOICE_DATA_SPEEX_3_4, "TS2T_VOICE_DATA_SPEEX_3_4" }, + { TS2T_VOICE_DATA_SPEEX_5_2, "TS2T_VOICE_DATA_SPEEX_5_2" }, + { TS2T_VOICE_DATA_SPEEX_7_2, "TS2T_VOICE_DATA_SPEEX_7_2" }, + { TS2T_VOICE_DATA_SPEEX_9_3, "TS2T_VOICE_DATA_SPEEX_9_3" }, + { TS2T_VOICE_DATA_SPEEX_12_3, "TS2T_VOICE_DATA_SPEEX_12_3" }, + { TS2T_VOICE_DATA_SPEEX_16_3, "TS2T_VOICE_DATA_SPEEX_16_3" }, + { TS2T_VOICE_DATA_SPEEX_19_5, "TS2T_VOICE_DATA_SPEEX_19_5" }, + { TS2T_VOICE_DATA_SPEEX_25_9, "TS2T_VOICE_DATA_SPEEX_25_9" }, + + { 0, NULL } +}; + +/* Codec Names */ +static const value_string codecnames[] = +{ + { TS2T_CODEC_CELP_5_1, "CELP 5.1" }, + { TS2T_CODEC_CELP_6_3, "CELP 6.3" }, + { TS2T_CODEC_GSM_14_8, "GSM 14.8" }, + { TS2T_CODEC_GSM_16_4, "GSM 16.4" }, + { TS2T_CODEC_CELP_WINDOWS_5_2, "CELP Windows 5.2" }, + { TS2T_CODEC_SPEEX_3_4, "Speex 3.4" }, + { TS2T_CODEC_SPEEX_5_2, "Speex 5.2" }, + { TS2T_CODEC_SPEEX_7_2, "Speex 7.2" }, + { TS2T_CODEC_SPEEX_9_3, "Speex 9.3" }, + { TS2T_CODEC_SPEEX_12_3, "Speex 12.3" }, + { TS2T_CODEC_SPEEX_16_3, "Speex 16.3" }, + { TS2T_CODEC_SPEEX_19_5, "Speex 19.5" }, + { TS2T_CODEC_SPEEX_25_9, "Speex 25.9" }, + { 0, NULL } +}; + + +static int proto_ts2 = -1; +static int global_ts2_port = 8767; +static dissector_handle_t ts2_handle; + +static int hf_ts2_type = -1; +static int hf_ts2_class = -1; +static int hf_ts2_clientid = -1; +static int hf_ts2_sessionkey = -1; +static int hf_ts2_crc32 = -1; +static int hf_ts2_ackto = -1; +static int hf_ts2_seqnum = -1; +static int hf_ts2_protocol_string = -1; +static int hf_ts2_string = -1; +static int hf_ts2_registeredlogin = -1; +static int hf_ts2_name = -1; +static int hf_ts2_password = -1; +static int hf_ts2_nick = -1; +static int hf_ts2_badlogin = -1; +static int hf_ts2_unknown = -1; +static int hf_ts2_channel = -1; +static int hf_ts2_subchannel = -1; +static int hf_ts2_channelpassword = -1; +static int hf_ts2_emptyspace = -1; +static int hf_ts2_fragmentnumber = -1; +static int hf_ts2_platform_string = -1; +static int hf_ts2_server_name = -1; +static int hf_ts2_server_welcome_message = -1; +static int hf_ts2_endmarker = -1; +static int hf_ts2_codec = -1; +static int hf_ts2_channel_flags = -1; +static int hf_ts2_channel_id = -1; +static int hf_ts2_channel_name = -1; +static int hf_ts2_channel_topic = -1; +static int hf_ts2_channel_description = -1; +static int hf_ts2_player_id = -1; +static int hf_ts2_player_status_flags = -1; +static int hf_ts2_number_of_players = -1; +static int hf_ts2_number_of_channels = -1; +static int hf_ts2_resend_count = -1; +static int hf_ts2_status_channelcommander = -1; +static int hf_ts2_status_blockwhispers = -1; +static int hf_ts2_status_away = -1; +static int hf_ts2_status_mutemicrophone = -1; +static int hf_ts2_status_mute = -1; + + +static gint ett_ts2 = -1; + +static gint *ett[] = { + &ett_ts2, + &ett_msg_fragment, + &ett_msg_fragments +}; + +/* Conversation Variables */ +typedef struct +{ + guint32 last_inorder_server_frame; + guint32 last_inorder_client_frame; + address server_addr; + guint32 server_port; + guint32 server_frag_size; + guint32 server_frag_num; + guint32 client_frag_size; + guint32 client_frag_num; + +} ts2_conversation; + +/* Packet Variables */ +typedef struct +{ + guint32 frag_num; + guint32 frag_size; + gboolean fragmented; + gboolean outoforder; +} ts2_frag; + +static hf_register_info hf[] = { + { &hf_ts2_class, + { "Class", "ts2.class", + FT_UINT16, BASE_HEX, + VALS(classnames), 0x0, + NULL, HFILL } + }, + { &hf_ts2_type, + { "Type", "ts2.type", + FT_UINT16, BASE_HEX, + VALS(typenames), 0x0, + NULL, HFILL } + }, + { &hf_ts2_clientid, + { "Client id", "ts2.clientid", + FT_UINT32, BASE_DEC, + NULL, 0x0, + NULL, HFILL } + }, + { &hf_ts2_sessionkey, + { "Session Key", "ts2.sessionkey", + FT_UINT32, BASE_HEX, + NULL, 0x0, + NULL, HFILL } + }, + { &hf_ts2_ackto, + { "Ping Reply To", "ts2.ping_ackto", + FT_UINT32, BASE_DEC, + NULL, 0x0, + NULL, HFILL } + }, + { &hf_ts2_crc32, + { "CRC32 Checksum", "ts2.crc32", + FT_UINT32, BASE_HEX, + NULL, 0x0, + NULL, HFILL } + }, + { &hf_ts2_seqnum, + { "Sequence Number", "ts2.sequencenum", + FT_UINT32, BASE_DEC, + NULL, 0x0, + NULL, HFILL } + }, + { &hf_ts2_protocol_string, + { "Protocol String", "ts2.protocolstring", + FT_UINT_STRING, BASE_NONE, + NULL, 0x0, + NULL, HFILL } + }, + { &hf_ts2_string, + { "String", "ts2.string", + FT_STRING, BASE_NONE, + NULL, 0x0, + NULL, HFILL } + }, + { &hf_ts2_registeredlogin, + { "Registered Login", "ts2.registeredlogin", + FT_BOOLEAN, BASE_NONE, + NULL, 0x0, + NULL, HFILL } + }, + { &hf_ts2_name, + { "Name", "ts2.name", + FT_UINT_STRING, BASE_NONE, + NULL, 0x0, + NULL, HFILL } + }, + { &hf_ts2_password, + { "Password", "ts2.password", + FT_UINT_STRING, BASE_NONE, + NULL, 0x0, + NULL, HFILL } + }, + { &hf_ts2_nick, + { "Nick", "ts2.nick", + FT_UINT_STRING, BASE_NONE, + NULL, 0x0, + NULL, HFILL } + }, + { &hf_ts2_badlogin, + { "Bad Login", "ts2.badlogin", + FT_BOOLEAN, BASE_NONE, + NULL, 0x0, + NULL, HFILL } + }, + { &hf_ts2_unknown, + { "Unknown", "ts2.unknown", + FT_BYTES, BASE_HEX, + NULL, 0x0, + NULL, HFILL } + }, + { &hf_ts2_channel, + { "Channel", "ts2.channel", + FT_UINT_STRING, BASE_NONE, + NULL, 0x0, + NULL, HFILL } + }, + { &hf_ts2_subchannel, + { "Sub-Channel", "ts2.subchannel", + FT_UINT_STRING, BASE_NONE, + NULL, 0x0, + NULL, HFILL } + }, + { &hf_ts2_channelpassword, + { "Channel Password", "ts2.channelpassword", + FT_UINT_STRING, BASE_NONE, + NULL, 0x0, + NULL, HFILL } + }, + { &hf_ts2_emptyspace, + { "Empty Space", "ts2.emptyspace", + FT_NONE, BASE_NONE, + NULL, 0x0, + NULL, HFILL } + }, + { &hf_ts2_fragmentnumber, + { "Fragment Number", "ts2.fragmentnumber", + FT_UINT16, BASE_DEC, + NULL, 0x0, + NULL, HFILL } + }, + { &hf_ts2_platform_string, + { "Platform String", "ts2.platformstring", + FT_UINT_STRING, BASE_NONE, + NULL, 0x0, + NULL, HFILL } + }, + { &hf_ts2_server_name, + { "Server Name", "ts2.servername", + FT_UINT_STRING, BASE_NONE, + NULL, 0x0, + NULL, HFILL } + }, + { &hf_ts2_server_welcome_message, + { "Server Welcome Message", "ts2.serverwelcomemessage", + FT_UINT_STRING, BASE_NONE, + NULL, 0x0, + NULL, HFILL } + }, + { &hf_ts2_endmarker, + { "End Marker", "ts2.endmarker", + FT_NONE, BASE_NONE, + NULL, 0x0, + NULL, HFILL } + }, + { &hf_ts2_codec, + { "Codec", "ts2.codec", + FT_UINT16, BASE_HEX, + VALS(codecnames), 0x0, + NULL, HFILL } + }, + { &hf_ts2_channel_flags, + { "Channel Flags", "ts2.channelflags", + FT_BOOLEAN, BASE_NONE, + NULL, 0x0, + NULL, HFILL } + }, + { &hf_ts2_channel_id, + { "Channel Id", "ts2.chanelid", + FT_UINT32, BASE_DEC, + NULL, 0x0, + NULL, HFILL } + }, + { &hf_ts2_channel_name, + { "Channel Name", "ts2.chanelname", + FT_STRINGZ, BASE_NONE, + NULL, 0x0, + NULL, HFILL } + }, + { &hf_ts2_channel_topic, + { "Channel Topic", "ts2.chaneltopic", + FT_STRINGZ, BASE_NONE, + NULL, 0x0, + NULL, HFILL } + }, + { &hf_ts2_channel_description, + { "Channel Description", "ts2.chaneldescription", + FT_STRINGZ, BASE_NONE, + NULL, 0x0, + NULL, HFILL } + }, + { &hf_ts2_player_id, + { "Player Id", "ts2.playerid", + FT_UINT32, BASE_DEC, + NULL, 0x0, + NULL, HFILL } + }, + { &hf_ts2_player_status_flags, + { "Player Status Flags", "ts2.playerstatusflags", + FT_UINT16, BASE_DEC, + NULL, 0x0, + NULL, HFILL } + }, + { &hf_ts2_number_of_players, + { "Number Of Players", "ts2.numberofplayers", + FT_UINT32, BASE_DEC, + NULL, 0x0, + NULL, HFILL } + }, + { &hf_ts2_number_of_channels, + { "Number Of Channels", "ts2.numberofchannels", + FT_UINT32, BASE_DEC, + NULL, 0x0, + NULL, HFILL } + }, + { &hf_ts2_resend_count, + { "Resend Count", "ts2.resendcount", + FT_UINT16, BASE_DEC, + NULL, 0x0, + NULL, HFILL } + }, + { &hf_ts2_status_channelcommander, + { "Channel Commander", "ts2.playerstatusflags.channelcommander", + FT_BOOLEAN, 8, + NULL, TS2_STATUS_CHANNELCOMMANDER, + NULL, HFILL } + }, + { &hf_ts2_status_blockwhispers, + { "Block Whispers", "ts2.playerstatusflags.blockwhispers", + FT_BOOLEAN, 8, + NULL, TS2_STATUS_BLOCKWHISPERS, + NULL, HFILL } + }, + { &hf_ts2_status_away, + { "Away", "ts2.playerstatusflags.away", + FT_BOOLEAN, 8, + NULL, TS2_STATUS_AWAY, + NULL, HFILL } + }, + { &hf_ts2_status_mutemicrophone, + { "Mute Microphone", "ts2.playerstatusflags.mutemicrophone", + FT_BOOLEAN, 8, + NULL, TS2_STATUS_MUTEMICROPHONE, + NULL, HFILL } + }, + { &hf_ts2_status_mute, + { "Mute", "ts2.playerstatusflags.mute", + FT_BOOLEAN, 8, + NULL, TS2_STATUS_MUTE, + NULL, HFILL } + }, + { &hf_msg_fragments, + {"Message fragments", "ts2.fragments", + FT_NONE, BASE_NONE, NULL, 0x00, NULL, HFILL } }, + { &hf_msg_fragment, + {"Message fragment", "ts2.fragment", + FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL } }, + { &hf_msg_fragment_overlap, + {"Message fragment overlap", "ts2.fragment.overlap", + FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL } }, + { &hf_msg_fragment_overlap_conflicts, + {"Message fragment overlapping with conflicting data", + "ts2.fragment.overlap.conflicts", + FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL } }, + { &hf_msg_fragment_multiple_tails, + {"Message has multiple tail fragments", + "ts2.fragment.multiple_tails", + FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL } }, + { &hf_msg_fragment_too_long_fragment, + {"Message fragment too long", "ts2.fragment.too_long_fragment", + FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL } }, + { &hf_msg_fragment_error, + {"Message defragmentation error", "ts2.fragment.error", + FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL } }, + { &hf_msg_reassembled_in, + {"Reassembled in", "ts2.reassembled.in", + FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL } } + }; + +/* the GMemChunk base structure */ +static GMemChunk *conv_vals = NULL; + +#define my_init_count 5 + +static GHashTable *msg_fragment_table = NULL; +static GHashTable *msg_reassembled_table = NULL; + +/* forward reference */ +static void dissect_ts2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree); +static gboolean ts2_add_checked_crc32(proto_tree *tree, int hf_item, tvbuff_t *tvb, guint16 offset, guint32 icrc32); +static void ts2_standard_dissect(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, ts2_conversation *conversation_data); +static gboolean ts2_standard_find_fragments(tvbuff_t *tvb, guint32 *last_inorder_frame, guint32 *frag_size, guint32 *frag_num, gboolean *outoforder); +static ts2_conversation* ts2_get_conversation(packet_info *pinfo); +static void ts2_parse_playerlist(tvbuff_t *tvb, proto_tree *ts2_tree); +static void ts2_parse_channellist(tvbuff_t *tvb, proto_tree *ts2_tree); +static void ts2_parse_newplayerjoined(tvbuff_t *tvb, proto_tree *ts2_tree); +static void ts2_parse_knownplayerupdate(tvbuff_t *tvb, proto_tree *ts2_tree); +static void ts2_parse_playerleft(tvbuff_t *tvb, proto_tree *ts2_tree); +static void ts2_parse_loginend(tvbuff_t *tvb, proto_tree *ts2_tree); +static void ts2_parse_changestatus(tvbuff_t *tvb, proto_tree *ts2_tree); +static void ts2_parse_switchchannel(tvbuff_t *tvb, proto_tree *ts2_tree); +static void ts2_add_statusflags(tvbuff_t *tvb, proto_tree *ts2_tree, guint32 offset); +static void ts2_parse_channelchange(tvbuff_t *tvb, proto_tree *ts2_tree); +static void ts2_parse_loginpart2(tvbuff_t *tvb, proto_tree *ts2_tree); + + + +/* + * proto_register_ts2() + * */ +void proto_register_ts2(void) +{ + /* Setup protocol subtree array */ + if (proto_ts2 == -1) { + proto_ts2 = proto_register_protocol ( + "Teamspeak2 Protocol", /* name */ + "TeamSpeak2", /* short name */ + "ts2" /* abbrev */ + ); + proto_register_field_array(proto_ts2, hf, array_length(hf)); + proto_register_subtree_array(ett, array_length(ett)); + + fragment_table_init(&msg_fragment_table); + reassembled_table_init(&msg_reassembled_table); + if (conv_vals) + g_mem_chunk_destroy(conv_vals); + + /* now create memory chunks */ + conv_vals = g_mem_chunk_new("ts2_conv_vals", + sizeof(ts2_conversation), + my_init_count * sizeof(ts2_conversation), + G_ALLOC_AND_FREE); + } +} + +/* + * proto_reg_handoff_ts2() + * */ +void proto_reg_handoff_ts2(void) +{ + static gboolean initialized = FALSE; + + if (!initialized) { + ts2_handle = create_dissector_handle(dissect_ts2, proto_ts2); + dissector_add("udp.port", global_ts2_port, ts2_handle); + } +} + + + +/* + * Check if a packet is in order and if it is set its fragmentation details into the passed pointers. + * Returns TRUE if the packet is fragmented. + * Must be run sequentially + * */ +static gboolean ts2_standard_find_fragments(tvbuff_t *tvb, guint32 *last_inorder_frame, guint32 *frag_size, guint32 *frag_num, gboolean *outoforder) +{ + guint32 frag_count; + gboolean ret; + frag_count=tvb_get_letohs(tvb, 18); + ret=FALSE; + *outoforder=FALSE; + + /* if last_inorder_frame is zero, then this is the first reliable packet */ + if(*last_inorder_frame==0) + { + *last_inorder_frame=tvb_get_letohl(tvb, 12); + *frag_size=tvb_get_letohs(tvb, 18); + *frag_num=0; + if(*frag_size>0) + ret=TRUE; + else + ret=FALSE; + } + /* This packet is in order */ + else if(*last_inorder_frame==tvb_get_letohl(tvb, 12)-1) + { + if(*frag_size>0) + { + *frag_num=*frag_size-frag_count; + if(frag_count==0) + { + *frag_size=0; + } + ret=TRUE; + } + else + { + *frag_size=tvb_get_letohs(tvb, 18); + *frag_num=*frag_size-frag_count; + if(*frag_size>0) + ret=TRUE; + else + ret=FALSE; + } + *last_inorder_frame=tvb_get_letohl(tvb, 12); + } + else /* out of order */ + *outoforder=TRUE; + return ret; +} + + + +/* + * Dissect a standard (reliable) ts2 packet, reassembling if required. + */ +static void ts2_standard_dissect(tvbuff_t *tvb, packet_info *pinfo, proto_tree *ts2_tree, ts2_conversation *conversation_data) +{ + guint8 save_fragmented; + tvbuff_t *new_tvb, *next_tvb; + fragment_data *frag_msg ; + guint16 fragment_number; + ts2_frag *frag; + gboolean outoforder; + guint16 type = tvb_get_letohs(tvb, 2); + /*guint16 class = tvb_get_letohs(tvb, 0);*/ + proto_tree_add_item(ts2_tree, hf_ts2_seqnum, tvb, 12, 4, TRUE); + frag = se_alloc(sizeof(ts2_frag)); + frag->frag_num=0; + + /* decide if the packet is server to client or client to server + * then check its fragmentation + */ + if(!(pinfo->fd->flags.visited)) + { + if(conversation_data->server_port == pinfo->srcport) + { + frag->fragmented = ts2_standard_find_fragments(tvb, &conversation_data->last_inorder_server_frame, &conversation_data->server_frag_size, &conversation_data->server_frag_num, &outoforder); + frag->frag_num=conversation_data->server_frag_num; + frag->frag_size=conversation_data->server_frag_size; + } + else + { + + frag->fragmented = ts2_standard_find_fragments(tvb, &conversation_data->last_inorder_client_frame, &conversation_data->client_frag_size, &conversation_data->client_frag_num, &outoforder); + frag->frag_num=conversation_data->client_frag_num; + frag->frag_size=conversation_data->client_frag_size; + } + frag->outoforder=outoforder; + p_add_proto_data(pinfo->fd, proto_ts2, frag); + } + + /* Get our stored fragmentation data */ + frag = p_get_proto_data(pinfo->fd, proto_ts2); + + proto_tree_add_item(ts2_tree, hf_ts2_resend_count, tvb, 16, 2, TRUE); + proto_tree_add_item(ts2_tree, hf_ts2_fragmentnumber, tvb, 18, 2, TRUE); + ts2_add_checked_crc32(ts2_tree, hf_ts2_crc32, tvb, 20, tvb_get_letohl(tvb, 20)); + + /* Reassemble the packet if its fragmented */ + new_tvb = NULL; + if(frag->fragmented) + { + save_fragmented = pinfo->fragmented; + frag_msg = NULL; + pinfo->fragmented = TRUE; + fragment_number = tvb_get_letohs(tvb, 18); + frag_msg = fragment_add_seq_check(tvb, 24, pinfo, type, msg_fragment_table, msg_reassembled_table, frag->frag_num, tvb_length_remaining(tvb, 24), fragment_number); + new_tvb = process_reassembled_data(tvb, 24, pinfo,"Reassembled Message", frag_msg, &msg_frag_items, NULL, ts2_tree); + if (frag_msg) + { /* Reassembled */ + if (check_col(pinfo->cinfo, COL_INFO)) col_append_str(pinfo->cinfo, COL_INFO, " (Message Reassembled)"); + } + else + { /* Not last packet of reassembled Short Message */ + if (check_col(pinfo->cinfo, COL_INFO))col_append_fstr(pinfo->cinfo, COL_INFO," (Message fragment %u)", frag->frag_num); + } + if (new_tvb) + next_tvb = new_tvb; + else + next_tvb = tvb_new_subset(tvb, 24, -1, -1); + pinfo->fragmented = save_fragmented; + } + else + next_tvb = tvb_new_subset(tvb, 24, -1, -1); + + /* If we have a full packet now dissect it */ + if((new_tvb || !frag->fragmented) && !frag->outoforder) + { + switch(type) + { + case TS2T_LOGINPART2: + { + ts2_parse_loginpart2(next_tvb, ts2_tree); + break; + } + case TS2T_CHANNELLIST: + { + ts2_parse_channellist(next_tvb, ts2_tree); + break; + } + case TS2T_PLAYERLIST: + { + ts2_parse_playerlist(next_tvb, ts2_tree); + break; + } + case TS2T_NEWPLAYERJOINED: + { + ts2_parse_newplayerjoined(next_tvb, ts2_tree); + break; + } + case TS2T_KNOWNPLAYERUPDATE: + { + ts2_parse_knownplayerupdate(next_tvb, ts2_tree); + break; + } + case TS2T_PLAYERLEFT: + { + ts2_parse_playerleft(next_tvb, ts2_tree); + break; + } + case TS2T_PLAYERKICKED: + { + ts2_parse_playerleft(next_tvb, ts2_tree); + break; + } + case TS2T_LOGINEND: + { + ts2_parse_loginend(next_tvb, ts2_tree); + break; + } + case TS2T_CHANGESTATUS: + { + ts2_parse_changestatus(next_tvb, ts2_tree); + break; + } + case TS2T_SWITCHCHANNEL: + { + ts2_parse_switchchannel(next_tvb, ts2_tree); + break; + } + case TS2T_CHANNELCHANGE: + { + ts2_parse_channelchange(next_tvb, ts2_tree); + break; + } + } + } + /* The packet is out of order, update the cinfo and ignore the packet */ + if(frag->outoforder) + if (check_col(pinfo->cinfo, COL_INFO)) col_append_str(pinfo->cinfo, COL_INFO, " (Out Of Order, ignored)"); +} + + +/* Parses a ts2 new player joined (TS2_NEWPLAYERJOINED) packet and adds it to the tree */ +static void ts2_parse_newplayerjoined(tvbuff_t *tvb, proto_tree *ts2_tree) +{ + gint32 offset; + offset=0; + proto_tree_add_item(ts2_tree, hf_ts2_player_id, tvb, offset, 4, TRUE); + offset+=4; + proto_tree_add_item(ts2_tree, hf_ts2_channel_id, tvb, offset, 4, TRUE); + offset+=4; + proto_tree_add_item(ts2_tree, hf_ts2_unknown, tvb, offset, 6, TRUE); + offset+=6; + proto_tree_add_item(ts2_tree, hf_ts2_nick, tvb, offset, 1, TRUE); + offset+=30; +} + +/* Parses TS2_LOGINEND packet and adds it to the tree */ +static void ts2_parse_loginend(tvbuff_t *tvb, proto_tree *ts2_tree) +{ + gint32 offset; + offset=0; + proto_tree_add_item(ts2_tree, hf_ts2_unknown, tvb, offset, tvb_length_remaining(tvb, offset), TRUE); +} + +/* Parses a ts2 known player joined (TS2_KNOWNPLAYERUPDATE) packet and adds it to the tree */ +static void ts2_parse_knownplayerupdate(tvbuff_t *tvb, proto_tree *ts2_tree) +{ + gint32 offset; + offset=0; + proto_tree_add_item(ts2_tree, hf_ts2_player_id, tvb, offset, 4, TRUE); + offset+=4; + proto_tree_add_item(ts2_tree, hf_ts2_player_status_flags, tvb, offset, 2, TRUE); + ts2_add_statusflags(tvb, ts2_tree, offset); +} + +/* Parses a ts2 switch channel (TS2_SWITCHCHANNEL) packet and adds it to the tree */ +static void ts2_parse_switchchannel(tvbuff_t *tvb, proto_tree *ts2_tree) +{ + gint32 offset; + offset=0; + proto_tree_add_item(ts2_tree, hf_ts2_channel_id, tvb, offset, 4, TRUE); + offset+=4; + proto_tree_add_item(ts2_tree, hf_ts2_password, tvb, offset, 1, TRUE); + offset+=30; +} + +/* Parses a ts2 channel change (TS2T_CHANNELCHANGE) packet and adds it to the tree */ +static void ts2_parse_channelchange(tvbuff_t *tvb, proto_tree *ts2_tree) +{ + gint32 offset; + offset=0; + proto_tree_add_item(ts2_tree, hf_ts2_player_id, tvb, offset, 4, TRUE); + offset+=4; + proto_tree_add_item(ts2_tree, hf_ts2_channel_id, tvb, offset, 4, TRUE); + offset+=4; + proto_tree_add_item(ts2_tree, hf_ts2_channel_id, tvb, offset, 4, TRUE); + offset+=4; + proto_tree_add_item(ts2_tree, hf_ts2_unknown, tvb, offset, 2, TRUE); + +} + +/* Parses a ts2 change status (TS2_CHANGESTATUS) packet and adds it to the tree */ +static void ts2_parse_changestatus(tvbuff_t *tvb, proto_tree *ts2_tree) +{ + gint32 offset; + offset=0; + proto_tree_add_item(ts2_tree, hf_ts2_player_status_flags, tvb, offset, 2, TRUE); + ts2_add_statusflags(tvb, ts2_tree, offset); + +} + +/* Parses a ts2 known player left (TS2_PLAYERLEFT) packet and adds it to the tree */ +static void ts2_parse_playerleft(tvbuff_t *tvb, proto_tree *ts2_tree) +{ + gint32 offset; + offset=0; + proto_tree_add_item(ts2_tree, hf_ts2_player_id, tvb, offset, 4, TRUE); + offset+=4; + proto_tree_add_item(ts2_tree, hf_ts2_unknown, tvb, offset, 4, TRUE); + offset+=4; + proto_tree_add_item(ts2_tree, hf_ts2_unknown, tvb, offset, 4, TRUE); + offset+=4; + proto_tree_add_item(ts2_tree, hf_ts2_unknown, tvb, offset, tvb_length_remaining(tvb, offset), TRUE); +} + +/* Parses a ts2 login part 2 (TS2T_LOGINPART2) packet and adds it to the tree */ +static void ts2_parse_loginpart2(tvbuff_t *tvb, proto_tree *ts2_tree) +{ + gint32 offset; + offset=0; + proto_tree_add_item(ts2_tree, hf_ts2_unknown, tvb, 0, 2, TRUE); + offset+=2; + proto_tree_add_item(ts2_tree, hf_ts2_channel, tvb, offset, 1, TRUE); + offset+=30; + proto_tree_add_item(ts2_tree, hf_ts2_subchannel, tvb, offset, 1, TRUE); + offset+=30; + proto_tree_add_item(ts2_tree, hf_ts2_channelpassword, tvb, offset, 1, TRUE); + offset+=30; + proto_tree_add_item(ts2_tree, hf_ts2_unknown, tvb, offset, 4, TRUE); + +} +/* Parses a ts2 channel list (TS2T_CHANNELLIST) and adds it to the tree */ +static void ts2_parse_channellist(tvbuff_t *tvb, proto_tree *ts2_tree) +{ + gint32 offset; + guint32 string_len; + offset=0; + proto_tree_add_item(ts2_tree, hf_ts2_number_of_channels, tvb, offset, 4, TRUE); + offset+=4; + while(offset<tvb_length_remaining(tvb, 0)) + { + proto_tree_add_item(ts2_tree, hf_ts2_channel_id, tvb, offset, 4, TRUE); + offset+=4; + proto_tree_add_item(ts2_tree, hf_ts2_channel_flags, tvb, offset, 1, TRUE); + offset+=1; + proto_tree_add_item(ts2_tree, hf_ts2_unknown, tvb, offset, 1, TRUE); + offset+=1; + proto_tree_add_item(ts2_tree, hf_ts2_codec, tvb, offset, 2, TRUE); + offset+=2; + proto_tree_add_item(ts2_tree, hf_ts2_endmarker, tvb, offset, 4, TRUE); + offset+=4; + proto_tree_add_item(ts2_tree, hf_ts2_unknown, tvb, offset, 4, TRUE); + offset+=4; + tvb_get_ephemeral_stringz(tvb, offset, &string_len); + proto_tree_add_item(ts2_tree, hf_ts2_channel_name, tvb, offset,string_len , TRUE); + offset+=string_len; + tvb_get_ephemeral_stringz(tvb, offset, &string_len); + proto_tree_add_item(ts2_tree, hf_ts2_channel_topic, tvb, offset,string_len ,TRUE); + offset+=string_len; + tvb_get_ephemeral_stringz(tvb, offset, &string_len); + proto_tree_add_item(ts2_tree, hf_ts2_channel_description, tvb, offset,string_len , TRUE); + offset+=string_len; + } +} + +static void ts2_add_statusflags(tvbuff_t *tvb, proto_tree *ts2_tree, guint32 offset) +{ + proto_tree_add_item(ts2_tree, hf_ts2_status_channelcommander, tvb, offset, 2, TRUE); + proto_tree_add_item(ts2_tree, hf_ts2_status_blockwhispers, tvb, offset, 2, TRUE); + proto_tree_add_item(ts2_tree, hf_ts2_status_away, tvb, offset, 2, TRUE); + proto_tree_add_item(ts2_tree, hf_ts2_status_mutemicrophone, tvb, offset, 2, TRUE); + proto_tree_add_item(ts2_tree, hf_ts2_status_mute, tvb, offset, 2, TRUE); + +} + +/* Parses a ts2 player list (TS2T_PLAYERLIST) and adds it to the tree */ +static void ts2_parse_playerlist(tvbuff_t *tvb, proto_tree *ts2_tree) +{ + gint32 offset; + gint32 number_of_players; + gint32 x; + offset=0; + x=0; + proto_tree_add_item(ts2_tree, hf_ts2_number_of_players, tvb, offset, 4, TRUE); + number_of_players = tvb_get_letohl(tvb, 0); + offset+=4; + while(offset<tvb_length_remaining(tvb, 0) && x<number_of_players) + { + proto_tree_add_item(ts2_tree, hf_ts2_player_id, tvb, offset, 4, TRUE); + offset+=4; + proto_tree_add_item(ts2_tree, hf_ts2_channel_id, tvb, offset, 4, TRUE); + offset+=4; + proto_tree_add_item(ts2_tree, hf_ts2_unknown, tvb, offset, 4, TRUE); + offset+=4; + proto_tree_add_item(ts2_tree, hf_ts2_player_status_flags, tvb, offset, 2, TRUE); + ts2_add_statusflags(tvb, ts2_tree, offset); + offset+=2; + proto_tree_add_item(ts2_tree, hf_ts2_nick, tvb, offset, 1, TRUE); + offset+=30; + x++; + } + proto_tree_add_item(ts2_tree, hf_ts2_emptyspace, tvb, offset, tvb_length_remaining(tvb, 0), TRUE); +} + + + +/* Find the current conversation or make a new one if required */ +static ts2_conversation* ts2_get_conversation(packet_info *pinfo) +{ + conversation_t *conversation; + ts2_conversation *conversation_data; + conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype, pinfo->srcport, pinfo->destport, 0); + if(conversation) + { + + conversation_data = (ts2_conversation*)conversation_get_proto_data(conversation, proto_ts2); + } + else + { + conversation_data = g_mem_chunk_alloc(conv_vals); + conversation_data->last_inorder_server_frame=0; /* sequence number should never be zero so we can use this as an initial number */ + conversation_data->last_inorder_client_frame=0; + conversation_data->server_port=pinfo->srcport; + conversation_data->server_frag_size=0; + conversation_data->server_frag_num=0; + conversation_data->client_frag_size=0; + conversation_data->client_frag_num=0; + conversation = conversation_new(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype, pinfo->srcport, pinfo->destport, 0); + conversation_add_proto_data(conversation, proto_ts2, (void *)conversation_data); + } + return conversation_data; +} + + + +/* Dissect a TS2 packet */ +static void dissect_ts2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) +{ + ts2_conversation *conversation_data; + guint16 type = tvb_get_letohs(tvb, 2); + guint16 class = tvb_get_letohs(tvb, 0); + + conversation_data = ts2_get_conversation(pinfo); + if (check_col(pinfo->cinfo, COL_PROTOCOL)) { + col_set_str(pinfo->cinfo, COL_PROTOCOL, "TS2"); + } + /* Clear out stuff in the info column */ + if (check_col(pinfo->cinfo,COL_INFO)) { + col_clear(pinfo->cinfo,COL_INFO); + } + if (check_col(pinfo->cinfo, COL_INFO)) + { + if(class==TS2C_ACK) + col_add_fstr(pinfo->cinfo, COL_INFO, "Class: %s", val_to_str(class, classnames, "Unknown (0x%02x)")); + else + col_add_fstr(pinfo->cinfo, COL_INFO, "Type: %s, Class: %s", val_to_str(type, typenames, "Unknown (0x%02x)"), val_to_str(class, classnames, "Unknown (0x%02x)")); + } + if (tree) { /* we are being asked for details */ + proto_item *ti = NULL; + proto_tree *ts2_tree = NULL; + + + + ti = proto_tree_add_item(tree, proto_ts2, tvb, 0, -1, TRUE); + ts2_tree = proto_item_add_subtree(ti, ett_ts2); + + proto_tree_add_item(ts2_tree, hf_ts2_class, tvb, 0, 2, TRUE); + if(class==TS2C_ACK) + proto_tree_add_item(ts2_tree, hf_ts2_resend_count, tvb, 2, 2, TRUE); + else + proto_tree_add_item(ts2_tree, hf_ts2_type, tvb, 2, 2, TRUE); + + proto_tree_add_item(ts2_tree, hf_ts2_sessionkey, tvb, 4, 4, TRUE); + proto_tree_add_item(ts2_tree, hf_ts2_clientid, tvb, 8, 4, TRUE); + switch(class) + { + case TS2C_CONNECTION: + { + proto_tree_add_item(ts2_tree, hf_ts2_seqnum, tvb, 12, 4, TRUE); + ts2_add_checked_crc32(ts2_tree, hf_ts2_crc32, tvb, 16, tvb_get_letohl(tvb, 16)); + + switch(type) + { + case TS2T_PING: + { + break; + } + case TS2T_PINGREPLY: + { + proto_tree_add_item(ts2_tree, hf_ts2_ackto, tvb, 20, 4, TRUE); + break; + } + case TS2T_LOGINREQUEST: + { + proto_tree_add_item(ts2_tree, hf_ts2_protocol_string, tvb, 20, 1, TRUE); + proto_tree_add_item(ts2_tree, hf_ts2_platform_string, tvb, 50, 1, TRUE); + proto_tree_add_item(ts2_tree, hf_ts2_unknown, tvb, 80, 9, TRUE); + proto_tree_add_item(ts2_tree, hf_ts2_registeredlogin, tvb, 90, 1, TRUE); + proto_tree_add_item(ts2_tree, hf_ts2_name, tvb, 90, 1, TRUE); + proto_tree_add_item(ts2_tree, hf_ts2_password, tvb, 120, 1, TRUE); + proto_tree_add_item(ts2_tree, hf_ts2_nick, tvb, 150, 1, TRUE); + + conversation_data->server_port=pinfo->destport; + conversation_data->server_addr=pinfo->dst; + + break; + } + case TS2T_LOGINREPLY: + { + proto_tree_add_item(ts2_tree, hf_ts2_server_name, tvb, 20, 1, TRUE); + proto_tree_add_item(ts2_tree, hf_ts2_platform_string, tvb, 50, 1, TRUE); + proto_tree_add_item(ts2_tree, hf_ts2_unknown, tvb, 80, 9, TRUE); + proto_tree_add_item(ts2_tree, hf_ts2_badlogin, tvb, 89, 3, TRUE); + proto_tree_add_item(ts2_tree, hf_ts2_unknown, tvb, 92, 80, TRUE); + proto_tree_add_item(ts2_tree, hf_ts2_sessionkey, tvb, 172, 4, TRUE); + proto_tree_add_item(ts2_tree, hf_ts2_unknown, tvb, 178, 3, TRUE); + proto_tree_add_item(ts2_tree, hf_ts2_server_welcome_message, tvb, 180, 1, TRUE); + + } + } + break; + } + case TS2C_ACK: + { + /* Ignore the type for ACK, its always zero and clashes with CELP_5_1 */ + + proto_tree_add_item(ts2_tree, hf_ts2_seqnum, tvb, 12, 4, TRUE); + break; + } + case TS2C_STANDARD: + { + ts2_standard_dissect(tvb, pinfo, ts2_tree, conversation_data); + } + break; + } + } +} + + + +/* 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 + * Returns true if the calculated CRC32 matches the passed CRC32. + * */ +static gboolean ts2_add_checked_crc32(proto_tree *tree, int hf_item, tvbuff_t *tvb, guint16 offset, guint32 icrc32 ) +{ + guint8 *zero; + guint32 ocrc32; + zero = ep_alloc(4); + memset(zero, 0, 4); + ocrc32 = crc32_ccitt_tvb(tvb, offset); + ocrc32 = crc32_ccitt_seed(zero, 4, 0xffffffff-ocrc32); + ocrc32 = crc32_ccitt_tvb_offset_seed(tvb, offset+4, tvb_reported_length_remaining(tvb, offset+4), 0xffffffff-ocrc32); + if(icrc32==ocrc32) + { + 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)); + return TRUE; + } + else + { + 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); + return FALSE; + } +} |