aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAnders Broman <anders.broman@ericsson.com>2010-02-07 14:30:11 +0000
committerAnders Broman <anders.broman@ericsson.com>2010-02-07 14:30:11 +0000
commit5ffc91810b56b1b03e2fabb540fb906d4304e6e7 (patch)
treeaed8d5d39da3dc300e4ce3d431e8670c1a77aa3b
parent0d999e6e74c76a4ca3a9516a0b46bc6e16c08600 (diff)
From Tobias Erichsen:
AppleMIDI - dissector for lightweight session protocol used in Apple network MIDI. https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=4455 svn path=/trunk/; revision=31814
-rw-r--r--AUTHORS4
-rw-r--r--epan/dissectors/Makefile.common1
-rw-r--r--epan/dissectors/packet-applemidi.c468
3 files changed, 473 insertions, 0 deletions
diff --git a/AUTHORS b/AUTHORS
index f56d5763db..83929fd99e 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -2970,6 +2970,10 @@ Vladimir Smrekar <vladimir.smrekar [AT] gmail.com> {
V5UA dissector
}
+Tobias Erichsen <t.erichsen [AT] gmx.de> {
+ Apple network-midi session establishment dissector
+}
+
and by:
Pavel Roskin <proski [AT] gnu.org>
diff --git a/epan/dissectors/Makefile.common b/epan/dissectors/Makefile.common
index 50db9b4175..df3dde0a58 100644
--- a/epan/dissectors/Makefile.common
+++ b/epan/dissectors/Makefile.common
@@ -231,6 +231,7 @@ DISSECTOR_SRC = \
packet-aoe.c \
packet-ap1394.c \
packet-app-pkix-cert.c \
+ packet-applemidi.c \
packet-arcnet.c \
packet-armagetronad.c \
packet-arp.c \
diff --git a/epan/dissectors/packet-applemidi.c b/epan/dissectors/packet-applemidi.c
new file mode 100644
index 0000000000..d85de3d567
--- /dev/null
+++ b/epan/dissectors/packet-applemidi.c
@@ -0,0 +1,468 @@
+/* packet-applemidi.c
+ * Routines for dissection of Apple network-midi session establishment.
+ * Copyright 2006-2010, Tobias Erichsen <t.erichsen@gmx.de>
+ *
+ * $Id$
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * Copied from packet-data.c, README.developer, and various other files.
+ *
+ * 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.
+ *
+ *
+ * Apple network-midi session establishment is a lightweight protocol for providing
+ * a simple session establishment for MIDI-data sent in the form of RTP-MIDI (RFC 4695)
+ * Peers recognize each other using the Apple Bonjour scheme with the service-name
+ * "_apple-midi._udp", establish a connection using AppleMIDI (no official name, just
+ * an abbreviation) and then send payload using RTP-MIDI. The implementation of
+ * this dissector is based on the Apple implementation summary from May 6th, 2005.
+ *
+ * Here are some links:
+ *
+ * http://www.cs.berkeley.edu/~lazzaro/rtpmidi/
+ * http://www.faqs.org/rfcs/rfc4695.html
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <glib.h>
+#include <epan/packet.h>
+#include <epan/prefs.h>
+#include <epan/conversation.h>
+
+/* Definitions for protocol name during dissector-register */
+#define APPLEMIDI_DISSECTOR_NAME "Apple Network-MIDI Session Protocol"
+#define APPLEMIDI_DISSECTOR_SHORTNAME "AppleMIDI"
+#define APPLEMIDI_DISSECTOR_ABBREVIATION "applemidi"
+
+/* Signature "Magic Value" for Apple network MIDI session establishment */
+#define APPLEMIDI_PROTOCOL_SIGNATURE 0xffff
+
+/* Apple network MIDI valid commands */
+#define APPLEMIDI_COMMAND_INVITATION 0x494e /* "IN" */
+#define APPLEMIDI_COMMAND_INVITATION_REJECTED 0x4e4f /* "NO" */
+#define APLLEMIDI_COMMAND_INVITATION_ACCEPTED 0x4f4b /* "OK" */
+#define APPLEMIDI_COMMAND_ENDSESSION 0x4259 /* "BY" */
+#define APPLEMIDI_COMMAND_SYNCHRONIZATION 0x434b /* "CK" */
+#define APPLEMIDI_COMMAND_RECEIVER_FEEDBACK 0x5253 /* "RS" */
+
+
+static int hf_applemidi_signature = -1;
+static int hf_applemidi_command = -1;
+static int hf_applemidi_protocol_version = -1;
+static int hf_applemidi_token = -1;
+static int hf_applemidi_ssrc = -1;
+static int hf_applemidi_name = -1;
+static int hf_applemidi_count = -1;
+static int hf_applemidi_padding = -1;
+static int hf_applemidi_timestamp1 = -1;
+static int hf_applemidi_timestamp2 = -1;
+static int hf_applemidi_timestamp3 = -1;
+static int hf_applemidi_sequence_num = -1;
+static int hf_applemidi_rtp_sequence_num = -1;
+
+
+static gint ett_applemidi = -1;
+static gint ett_applemidi_seq_num = -1;
+
+
+static const value_string applemidi_commands[] = {
+ { APPLEMIDI_COMMAND_INVITATION, "Invitation" },
+ { APPLEMIDI_COMMAND_INVITATION_REJECTED, "Invitation Rejected" },
+ { APLLEMIDI_COMMAND_INVITATION_ACCEPTED, "Invitation Accepted" },
+ { APPLEMIDI_COMMAND_ENDSESSION, "End Session" },
+ { APPLEMIDI_COMMAND_SYNCHRONIZATION, "Synchronization" },
+ { APPLEMIDI_COMMAND_RECEIVER_FEEDBACK, "Receiver Feedback" },
+ { 0, NULL },
+};
+
+
+void proto_reg_handoff_applemidi( void );
+
+static guint udp_port = 0;
+
+static int proto_applemidi = -1;
+static dissector_handle_t applemidi_handle = NULL;
+static dissector_handle_t rtp_handle = NULL;
+
+
+
+
+
+
+static void
+dissect_applemidi( tvbuff_t *tvb, packet_info *pinfo _U_ , proto_tree *tree ) {
+
+ guint16 command;
+ guint16 seq_num;
+ guint8 count;
+ guint8 *name;
+ unsigned int offset = 0;
+ proto_tree *applemidi_tree = NULL;
+ proto_tree *applemidi_tree_seq_num = NULL;
+
+
+ col_set_str( pinfo->cinfo, COL_PROTOCOL, APPLEMIDI_DISSECTOR_SHORTNAME );
+
+ /* Clear out stuff in the info column */
+ col_clear( pinfo->cinfo, COL_INFO );
+
+ command = tvb_get_ntohs( tvb, offset + 2 );
+
+ col_add_fstr( pinfo->cinfo, COL_INFO, val_to_str( command, applemidi_commands, "Unknown Command: 0x%04x" ) );
+
+ if ( tree ) {
+ proto_item *ti = NULL;
+ ti = proto_tree_add_item( tree, proto_applemidi, tvb, 0, -1, FALSE );
+ applemidi_tree = proto_item_add_subtree( ti, ett_applemidi );
+
+ proto_tree_add_item( applemidi_tree, hf_applemidi_signature, tvb, offset, 2, FALSE );
+ offset += 2;
+
+ proto_tree_add_item( applemidi_tree, hf_applemidi_command, tvb, offset, 2, FALSE );
+ offset += 2;
+
+ /* the format of packets for "IN", "NO", "OK" and "BY" is identical and contains
+ * the protocol version, a random number generated by the initiator of the session
+ * the SSRC that is used by the respective sides RTP-entity and optionally the
+ * name of the participant */
+ if ( ( APPLEMIDI_COMMAND_INVITATION == command ) || ( APPLEMIDI_COMMAND_INVITATION_REJECTED == command ) || ( APLLEMIDI_COMMAND_INVITATION_ACCEPTED == command ) || ( APPLEMIDI_COMMAND_ENDSESSION == command ) ) {
+ int len;
+
+ proto_tree_add_item( applemidi_tree, hf_applemidi_protocol_version, tvb, offset, 4, FALSE );
+ offset += 4;
+
+ proto_tree_add_item( applemidi_tree, hf_applemidi_token, tvb, offset, 4, FALSE );
+ offset += 4;
+
+ proto_tree_add_item( applemidi_tree, hf_applemidi_ssrc, tvb, offset, 4, FALSE );
+ offset += 4;
+
+ len = tvb->length - offset;
+
+ /* Name is optional */
+ if ( len > 0 ) {
+ name = tvb_get_ephemeral_string( tvb, offset, len );
+ proto_tree_add_item( applemidi_tree, hf_applemidi_name, tvb, offset, len, FALSE );
+ col_append_fstr( pinfo->cinfo, COL_INFO, ": peer = \"%s\"", name );
+ }
+
+ /* the synchronization packet contains three 64bit timestamps, and a value to define how
+ * many of the timestamps transmitted are valid */
+ } else if ( APPLEMIDI_COMMAND_SYNCHRONIZATION == command ) {
+ proto_tree_add_item( applemidi_tree, hf_applemidi_ssrc, tvb, offset, 4, FALSE );
+ offset += 4;
+
+ count = tvb_get_guint8( tvb, offset );
+ proto_tree_add_item( applemidi_tree, hf_applemidi_count, tvb, offset, 1, FALSE );
+ col_append_fstr( pinfo->cinfo, COL_INFO, ": count = %u", count );
+ offset += 1;
+
+ proto_tree_add_item( applemidi_tree, hf_applemidi_padding, tvb, offset, 3, FALSE );
+ offset += 3;
+
+ proto_tree_add_item(applemidi_tree, hf_applemidi_timestamp1, tvb, offset, 8, FALSE );
+ offset += 8;
+
+ proto_tree_add_item( applemidi_tree, hf_applemidi_timestamp2, tvb, offset, 8, FALSE );
+ offset += 8;
+
+ proto_tree_add_item( applemidi_tree, hf_applemidi_timestamp3, tvb, offset, 8, FALSE );
+ offset += 8;
+ /* With the receiver feedback packet, the recipient can tell the sender up to what sequence
+ * number in the RTP-stream the packets have been received, this can be used to shorten the
+ * recovery-journal-section in the RTP-session */
+ } else if ( APPLEMIDI_COMMAND_RECEIVER_FEEDBACK == command ) {
+ proto_tree_add_item( applemidi_tree, hf_applemidi_ssrc, tvb, offset, 4, FALSE );
+ offset += 4;
+
+ ti = proto_tree_add_item( applemidi_tree, hf_applemidi_sequence_num, tvb, offset, 4, FALSE );
+ /* Apple includes a 32bit sequence-number, but the RTP-packet only specifies 16bit
+ * this subtree and subitem are added to be able to associate the sequence-number
+ * here easier with the one specified in the corresponding RTP-packet */
+ applemidi_tree_seq_num = proto_item_add_subtree( ti, ett_applemidi_seq_num );
+ seq_num = tvb_get_ntohs( tvb, offset );
+ proto_tree_add_uint( applemidi_tree_seq_num, hf_applemidi_rtp_sequence_num, tvb, offset, 2, seq_num );
+ offset += 4;
+
+ col_append_fstr( pinfo->cinfo, COL_INFO, ": seq = %u", seq_num );
+ }
+ }
+}
+
+
+static gboolean
+dissect_applemidi_heur( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree ) {
+
+ unsigned int offset = 0;
+ guint16 signature;
+ guint16 command;
+ conversation_t *p_conv;
+ gboolean result = FALSE;
+
+
+
+ /* Get the two octets making up the magic value */
+ signature = tvb_get_ntohs( tvb, offset );
+
+
+ /* An applemidi session protocol UDP-packet must start with the "magic value" of 0xffff ... */
+ if ( APPLEMIDI_PROTOCOL_SIGNATURE == signature ) {
+
+ command = tvb_get_ntohs( tvb, offset + 2 );
+
+ /* ... followed by packet-command: "IN", "NO", "OK", "BY", "CK" and "RS" */
+ if( APPLEMIDI_COMMAND_INVITATION == command )
+ result = TRUE;
+ else if( APPLEMIDI_COMMAND_INVITATION_REJECTED == command )
+ result = TRUE;
+ else if( APLLEMIDI_COMMAND_INVITATION_ACCEPTED == command )
+ result = TRUE;
+ else if( APPLEMIDI_COMMAND_ENDSESSION == command )
+ result = TRUE;
+ else if( APPLEMIDI_COMMAND_SYNCHRONIZATION == command )
+ result = TRUE;
+ else if( APPLEMIDI_COMMAND_RECEIVER_FEEDBACK == command )
+ result = TRUE;
+
+ }
+
+ p_conv=find_conversation( pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype, pinfo->srcport, pinfo->destport, 0 );
+
+ if( result ) {
+ if( !p_conv ) {
+ p_conv = conversation_new( 0, &pinfo->src, &pinfo->dst, pinfo->ptype, pinfo->srcport, pinfo->destport, 0 );
+ }
+ if( p_conv ) {
+ conversation_set_dissector( p_conv, applemidi_handle );
+ }
+
+ dissect_applemidi( tvb, pinfo, tree );
+ } else {
+ if( p_conv ) {
+ if( p_conv->dissector_handle == applemidi_handle ) {
+ result = TRUE;
+ /* punt packets not containing valid AppleMIDI-commands to RTP (or in
+ * case it exists, the more specialized RTP-MIDI-dissector */
+ call_dissector( rtp_handle, tvb, pinfo, tree );
+ }
+ }
+ }
+ return result;
+}
+
+
+void
+proto_register_applemidi( void )
+{
+ module_t *applemidi_module;
+
+ static hf_register_info hf[] = {
+ {
+ &hf_applemidi_signature,
+ {
+ "Signature",
+ "applemidi.signature",
+ FT_UINT16,
+ BASE_HEX,
+ NULL,
+ 0x0,
+ NULL, HFILL
+ }
+ },
+ {
+ &hf_applemidi_command,
+ {
+ "Command",
+ "applemidi.command",
+ FT_UINT16,
+ BASE_HEX,
+ VALS( applemidi_commands ),
+ 0x0,
+ NULL, HFILL
+ }
+ },
+ {
+ &hf_applemidi_protocol_version,
+ {
+ "Protocol Version",
+ "applemidi.protocol_version",
+ FT_UINT32,
+ BASE_DEC,
+ NULL,
+ 0x0,
+ NULL, HFILL
+ }
+ },
+ {
+ &hf_applemidi_token,
+ {
+ "Initiator Token",
+ "applemidi.initiator_token",
+ FT_UINT32,
+ BASE_HEX,
+ NULL,
+ 0x0,
+ NULL, HFILL
+ }
+ },
+ {
+ &hf_applemidi_ssrc,
+ {
+ "Sender SSRC",
+ "applemidi.sender_ssrc",
+ FT_UINT32,
+ BASE_HEX,
+ NULL,
+ 0x0,
+ NULL, HFILL
+ }
+ },
+ {
+ &hf_applemidi_name,
+ {
+ "Name",
+ "applemidi.name",
+ FT_STRING,
+ BASE_NONE,
+ NULL,
+ 0x0,
+ NULL, HFILL
+ }
+ },
+ {
+ &hf_applemidi_count,
+ {
+ "Count",
+ "applemidi.count",
+ FT_UINT8,
+ BASE_DEC,
+ NULL,
+ 0x0,
+ NULL, HFILL
+ }
+ },
+ {
+ &hf_applemidi_padding,
+ {
+ "Padding",
+ "applemidi.padding",
+ FT_UINT24,
+ BASE_HEX,
+ NULL,
+ 0x0,
+ NULL, HFILL
+ }
+ },
+ {
+ &hf_applemidi_timestamp1,
+ {
+ "Timestamp 1",
+ "applemidi.timestamp1",
+ FT_UINT64,
+ BASE_HEX,
+ NULL,
+ 0x0,
+ NULL, HFILL
+ }
+ },
+ {
+ &hf_applemidi_timestamp2,
+ {
+ "Timestamp 2",
+ "applemidi.timestamp2",
+ FT_UINT64,
+ BASE_HEX,
+ NULL,
+ 0x0,
+ NULL, HFILL
+ }
+ },
+ {
+ &hf_applemidi_timestamp3,
+ {
+ "Timestamp 3",
+ "applemidi.timestamp3",
+ FT_UINT64,
+ BASE_HEX,
+ NULL,
+ 0x0,
+ NULL, HFILL
+ }
+ },
+ {
+ &hf_applemidi_sequence_num,
+ {
+ "Sequence Number",
+ "applemidi.sequence_number",
+ FT_UINT32,
+ BASE_HEX,
+ NULL,
+ 0x0,
+ NULL, HFILL
+ }
+ },
+ {
+ &hf_applemidi_rtp_sequence_num,
+ {
+ "RTP Sequence Number",
+ "applemidi.rtp_sequence_number",
+ FT_UINT16,
+ BASE_DEC,
+ NULL,
+ 0x0,
+ NULL, HFILL
+ }
+ },
+ };
+
+
+ static gint *ett[] = {
+ &ett_applemidi,
+ &ett_applemidi_seq_num
+ };
+
+ proto_applemidi = proto_register_protocol( APPLEMIDI_DISSECTOR_NAME, APPLEMIDI_DISSECTOR_SHORTNAME, APPLEMIDI_DISSECTOR_ABBREVIATION );
+ proto_register_field_array( proto_applemidi, hf, array_length( hf ) );
+ proto_register_subtree_array( ett, array_length( ett ) );
+
+ applemidi_module = prefs_register_protocol( proto_applemidi, proto_reg_handoff_applemidi );
+
+}
+
+void
+proto_reg_handoff_applemidi( void ) {
+
+
+ if ( !applemidi_handle ) {
+ applemidi_handle = create_dissector_handle( dissect_applemidi, proto_applemidi );
+ }
+
+ /* If we cannot decode the data it will be RTP-MIDI since the Apple session protocol uses
+ * two ports: the control-port and the MIDI-port. On both ports an invitation is being sent.
+ * The second port is then used for the RTP-MIDI-data. So if we can't find valid AppleMidi
+ * packets, it will be most likely RTP-MIDI...
+ */
+ rtp_handle = find_dissector( "rtp" );
+ dissector_add( "udp.port" , udp_port, applemidi_handle );
+ heur_dissector_add( "udp", dissect_applemidi_heur, proto_applemidi );
+ applemidi_handle = find_dissector( "applemidi" );
+
+}