Wireshark-dev: [Wireshark-dev] [PATCH] acn: Add DMX streaming protocol (E1.31)
From: "Shaun Jackman" <sjackman@xxxxxxxxx>
Date: Wed, 25 Oct 2006 11:10:22 -0600
I had just finished writing this patch this morning, checked my email,
and saw that Bill Florac from ETC has been working on the same thing!
Since I'd already finished writing the patch, I thought I would post
it anyways, for what it's worth. It does fix a few of the items that
Ronnie Sahlberg mentioned, so it might be useful as a reference.

I did not update the session data transport (SDT) protocol, since the
DMX streaming protocol (E1.31) does not use it. That being the case, I
didn't move this dissector from a plugin to a built-in dissector, even
though I understand that ACN (E1.17) was ratified by ANSI this
Thursday.

Cheers,
Shaun Jackman
Pathway Connectivity

2006-10-25  Shaun Jackman  <sjackman@xxxxxxxxx>

	* plugins/acn/acn.c: Add DMX streaming protocol (E1.31) and device
	management protocol (DMP). Update root layer protocol (RLP) to the
	latest draft standard.
	* plugins/acn/acn.h: Ditto.

Index: plugins/acn/acn.h
===================================================================
--- plugins/acn/acn.h	(revision 19609)
+++ plugins/acn/acn.h	(working copy)
@@ -1,52 +1,28 @@
-#ifndef __ACN_H__
-#define __ACN_H__
+#ifndef ACN_H
+#define ACN_H 1

-#define ACN_PDU_MIN_SIZE	2
+#include <stdint.h>

-#define ACN_PDU_DES		0xC0
-#define ACN_PDU_DES_SAME	0x00
-#define ACN_PDU_DES_PS		0x40
-#define ACN_PDU_DES_CID		0x80
-#define ACN_PDU_DES_ALL		0xC0
+enum { IPPORT_ACN = 5568 };

-#define ACN_PDU_SRC		0x30
-#define ACN_PDU_SRC_SAME	0x00
-#define ACN_PDU_SRC_PS		0x10
-#define ACN_PDU_SRC_CID		0x20
-#define ACN_PDU_SRC_UM		0x30
+#define ACN_PDU_MIN_SIZE	2

-#define ACN_PDU_FLAG_P		0x08
-#define ACN_PDU_FLAG_T		0x04
-#define ACN_PDU_FLAG_RES	0x02
-#define ACN_PDU_FLAG_Z		0x01
+/* flags_length */
+enum {
+	ACN_FLAG_MASK = 0xf0,
+	ACN_FLAG_LENGTH = 0x80,
+	ACN_FLAG_VECTOR = 0x40,
+	ACN_FLAG_HEADER = 0x20,
+	ACN_FLAG_DATA = 0x10,
+	ACN_LENGTH_MASK = 0xfff,
+	ACN_LENGTH_MASK20 = 0xfffff,
+};

-typedef struct acn_pdu_history_s
-{
-	guint8 source_type;
-	union {
-		guint16 ps;
-		guint8 cid[16];
-	} source;
+#define ACN_VECTOR_SDT	1
+#define ACN_VECTOR_DMP	2
+#define ACN_VECTOR_DMXSP	3

-	guint8 destination_type;
-	union {
-		guint16 ps;
-		guint8 cid[16];	
-	} destination;
-	
-	guint16 protocol;
-	guint16 type;
-} acn_pdu_history_t;
-
-
-#define ACN_PDU_PROTO_UNKNOWN	0
-#define ACN_PDU_PROTO_SDT	1
-#define ACN_PDU_PROTO_DMP	2
-
-#define ACN_PDU_TYPE_UNKNOWN	0
-
/* SDT */
-#define ACN_SDT_TYPE_UNKNOWN		0
#define ACN_SDT_TYPE_RELSEQDATA		1
#define ACN_SDT_TYPE_UNRELSEQDATA	2
#define ACN_SDT_TYPE_UNSEQDATA		3
@@ -70,12 +46,42 @@
#define ACN_SDT_TYPE_SEQLOST		21
#define ACN_SDT_TYPE_NAKPARAMS		22

-
#define ACN_SDT_ADDR_NULL 0
#define ACN_SDT_ADDR_IPV4 1
#define ACN_SDT_ADDR_IPV6 2

/* DMP */
-#define ACN_DMP_TYPE_UNKNOWN	0
+enum {
+	DMP_GET_PROPERTY = 1,
+	DMP_SET_PROPERTY = 2,
+	DMP_GET_PROPERTY_REPLY = 3,
+	DMP_EVENT = 4,
+	DMP_MAP_PROPERTY = 5,
+	DMP_UNMAP_PROPERTY = 6,
+	DMP_SUBSCRIBE = 7,
+	DMP_UNSUBSCRIBE = 8,
+	DMP_GET_PROPERTY_FAIL = 9,
+	DMP_SET_PROPERTY_FAIL = 10,
+	DMP_MAP_PROPERTY_FAIL = 11,
+	DMP_SUBSCRIBE_ACCEPT = 12,
+	DMP_SUBSCRIBE_REJECT = 13,
+	DMP_ALLOCATE_MAP = 14,
+	DMP_ALLOCATE_MAP_REPLY = 15,
+	DMP_DEALLOCATE_MAP = 16,
+};

+enum {
+	DMP_VIRTUAL = 0x80,
+	DMP_RELATIVE = 0x40,
+	DMP_ADDRESS_DATA_TYPE = 0x30,
+	DMP_SINGLE_ADDRESS_SINGLE_DATA = 0x00,
+	DMP_RANGE_ADDRESS_SINGLE_DATA = 0x10,
+	DMP_RANGE_ADDRESS_EQUAL_SIZE_DATA = 0x20,
+	DMP_RANGE_ADDRESS_MIXED_SIZE_DATA = 0x30,
+	DMP_ADDRESS_SIZE = 0x03,
+	DMP_ADDRESS_SIZE_1 = 0,
+	DMP_ADDRESS_SIZE_2 = 1,
+	DMP_ADDRESS_SIZE_4 = 2,
+};
+
#endif /* !__ACN_H__ */
Index: plugins/acn/packet-acn.c
===================================================================
--- plugins/acn/packet-acn.c	(revision 19609)
+++ plugins/acn/packet-acn.c	(working copy)
@@ -1,10 +1,17 @@
/* packet-acn.c
- * Routines for ACN packet disassembly
+ * Routines for Architecture for Control Network protocol (ACN, E1.17)
+ * packet disassembly.
 *
 * $Id$
 *
- * Copyright (c) 2003 by Erwin Rol <erwin@xxxxxxxxxxxx>
+ * This dissector is written by
 *
+ *  Shaun Jackman <sjackman@xxxxxxxxx>
+ *  Copyright 2006 Pathway Connectivity
+ *
+ *  Erwin Rol <erwin@xxxxxxxxxxxx>
+ *  Copyright 2003 Erwin Rol
+ *
 * Wireshark - Network traffic analyzer
 * By Gerald Combs <gerald@xxxxxxxxxxxxx>
 * Copyright 1999 Gerald Combs
@@ -30,6 +37,7 @@
#include "config.h"
#endif

+#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
@@ -45,21 +53,15 @@

#include "acn.h"

-/*
- * See
- *
- *	http://www.esta.org/tsp/E1-17inst.htm
- */
-
-static const value_string acn_proto_vals[] = {
-	{ ACN_PDU_PROTO_UNKNOWN,	"Unknown"},
-	{ ACN_PDU_PROTO_SDT,		"SDT" },
-	{ ACN_PDU_PROTO_DMP,		"DMP" },
+static const value_string acn_vector_vals[] = {
+	{ ACN_VECTOR_SDT,		"Session data transport" },
+	{ ACN_VECTOR_DMP,		"Device management protocol" },
+	{ ACN_VECTOR_DMXSP,		"DMX streaming protocol" },
	{ 0,				NULL }
};

+/* SDT */
static const value_string acn_sdt_type_vals[] = {
-	{ ACN_SDT_TYPE_UNKNOWN,		"Unknown"},
	{ ACN_SDT_TYPE_RELSEQDATA,	"RELSEQDATA"},
	{ ACN_SDT_TYPE_UNRELSEQDATA,	"UNRELSEQDATA"},
	{ ACN_SDT_TYPE_UNSEQDATA,	"UNSEQDATA"},
@@ -85,12 +87,6 @@
	{ 0,				NULL }
};

-static const value_string acn_dmp_type_vals[] = {
-	{ ACN_DMP_TYPE_UNKNOWN,		"Unknown"},
-	{ 0,				NULL }
-};
-
-
static const value_string acn_sdt_address_type_vals[] = {
	{ ACN_SDT_ADDR_NULL,		"Unspecified"},
	{ ACN_SDT_ADDR_IPV4,		"IP version 4"},
@@ -98,61 +94,81 @@
	{ 0,				NULL }
};

-static const value_string acn_sdt_des_flag_vals[] = {
-	{ 0,				"Default"},
-	{ 1,				"Protocol Specific"},
-	{ 2,				"CID"},
-	{ 3,				"All"},
-	{ 0,				NULL }
+/* DMP */
+static const value_string acn_dmp_vector_vals[] = {
+	{ 1, "Get property" },
+	{ 2, "Set property" },
+	{ 3, "Get property reply" },
+	{ 4, "Event" },
+	{ 5, "Map property" },
+	{ 6, "Unmap property" },
+	{ 7, "Subscribe" },
+	{ 8, "Unsubscribe" },
+	{ 9, "Get property fail" },
+	{ 10, "Set property fail" },
+	{ 11, "Map property fail" },
+	{ 12, "Subscribe accept" },
+	{ 13, "Subscribe reject" },
+	{ 14, "Allocate map" },
+	{ 15, "Allocate map reply" },
+	{ 16, "Deallocate map" },
+	{ 0, NULL }
};

-static const value_string acn_sdt_src_flag_vals[] = {
-	{ 0,				"Default"},
-	{ 1,				"Protocol Specific"},
-	{ 2,				"CID"},
-	{ 3,				"Unspecified"},
-	{ 0,				NULL }
+static const value_string acn_dmp_address_data_type_vals[] = {
+	{ 0, "Single address, single data" },
+	{ 1, "Range address, single data" },
+	{ 2, "Range address, equal size data" },
+	{ 3, "Range address, mixed size data" },
+	{ 0, NULL }
};

+static const value_string acn_dmp_address_size_vals[] = {
+	{ 0, "1 byte" },
+	{ 1, "2 bytes" },
+	{ 2, "4 bytes" },
+	{ 0, NULL }
+};

void proto_reg_handoff_acn(void);

-/* Define the acn proto */
+static dissector_handle_t data_handle;
+
static int proto_acn = -1;

-/* Define the tree for acn */
static int ett_acn = -1;
+static int ett_acn_flags = -1;
+static int ett_acn_preamble = -1;
+static int ett_acn_rlp = -1;
+static int ett_acn_sdt = -1;
+static int ett_acn_dmp = -1;
+static int ett_acn_dmp_flags = -1;
+static int ett_acn_dmxsp = -1;
+static int ett_acn_pdu = -1;

-/* PDU */
+/* Preamble */
+static int hf_acn_preamble = -1;
+static int hf_acn_preamble_size = -1;
+static int hf_acn_postamble_size = -1;
+static int hf_acn_id = -1;
+
+/* ACN */
static int hf_acn_pdu = -1;
+static int hf_acn_flags = -1;
+static int hf_acn_flag_length = -1;
+static int hf_acn_flag_vector = -1;
+static int hf_acn_flag_header = -1;
+static int hf_acn_flag_data = -1;
+static int hf_acn_length = -1;
+static int hf_acn_vector = -1;

-static int hf_acn_pdu_flags = -1;
+/* RLP */
+static int hf_acn_rlp = -1;
+static int hf_acn_rlp_source_cid = -1;

-static int hf_acn_pdu_des = -1;
-static int hf_acn_pdu_src = -1;
-static int hf_acn_pdu_flag_p = -1;
-static int hf_acn_pdu_flag_t = -1;
-static int hf_acn_pdu_flag_res = -1;
-static int hf_acn_pdu_flag_z = -1;
-static int hf_acn_pdu_length = -1;
-
-/* PDU optional */
-static int hf_acn_pdu_ext_length_16 = -1;
-static int hf_acn_pdu_ext_length_32 = -1;
-static int hf_acn_pdu_source_ps = -1;
-static int hf_acn_pdu_source_cid = -1;
-static int hf_acn_pdu_destination_ps = -1;
-static int hf_acn_pdu_destination_cid = -1;
-static int hf_acn_pdu_protocol = -1;
-static int hf_acn_pdu_type = -1;
-static int hf_acn_pdu_type_sdt = -1;
-static int hf_acn_pdu_type_dmp = -1;
-static int hf_acn_pdu_data = -1;
-static int hf_acn_pdu_unknown_data = -1;
-
-static int hf_acn_pdu_padding = -1;
-
/* SDT */
+static int hf_acn_sdt = -1;
+static int hf_acn_sdt_vector = -1;
static int hf_acn_sdt_session_nr = -1;
static int hf_acn_sdt_tot_seq_nr = -1;
static int hf_acn_sdt_rel_seq_nr = -1;
@@ -185,39 +201,173 @@
static int hf_acn_sdt_member_cid = -1;
static int hf_acn_sdt_ack_threshold = -1;

-/*
- * Here are the global variables associated with the preferences
- * for acn
- */
+/* DMP */
+static int hf_acn_dmp = -1;
+static int hf_acn_dmp_vector = -1;
+static int hf_acn_dmp_flags = -1;
+static int hf_acn_dmp_virtual = -1;
+static int hf_acn_dmp_relative = -1;
+static int hf_acn_dmp_address_data_type = -1;
+static int hf_acn_dmp_address_size = -1;
+static int hf_acn_dmp_address = -1;
+static int hf_acn_dmp_increment = -1;
+static int hf_acn_dmp_count = -1;

-static guint global_udp_port_acn = 0;
-static guint udp_port_acn = 0;
+/* DMX streaming protocol (E1.31) */
+static int hf_acn_dmxsp = -1;
+static int hf_acn_dmxsp_source_name = -1;
+static int hf_acn_dmxsp_priority = -1;
+static int hf_acn_dmxsp_sequence = -1;
+static int hf_acn_dmxsp_universe = -1;

-/* A static handle for the ip dissector */
-static dissector_handle_t ip_handle;
+static unsigned
+dissect_flags_length(tvbuff_t *tvb, unsigned offset, proto_tree *tree,
+	uint8_t *flags)
+{
+	/* Flags */
+	*flags = tvb_get_guint8(tvb, offset);
+	proto_tree *flags_item = proto_tree_add_item(tree, hf_acn_flags,
+			tvb, offset, 1, FALSE);
+	proto_tree *flags_tree = proto_item_add_subtree(flags_item,
+			ett_acn_flags);
+	proto_tree_add_item(flags_tree, hf_acn_flag_length,
+			tvb, offset, 1, FALSE);
+	proto_tree_add_item(flags_tree, hf_acn_flag_vector,
+			tvb, offset, 1, FALSE);
+	proto_tree_add_item(flags_tree, hf_acn_flag_header,
+			tvb, offset, 1, FALSE);
+	proto_tree_add_item(flags_tree, hf_acn_flag_data,
+			tvb, offset, 1, FALSE);

-static guint dissect_pdu(tvbuff_t *tvb, guint offset, proto_tree
*tree, acn_pdu_history_t* parent_hist, guint max_size);
-static guint dissect_sdt(tvbuff_t *tvb, guint offset, proto_tree
*tree, acn_pdu_history_t* parent_hist, guint max_size);
-static guint dissect_dmp(tvbuff_t *tvb, guint offset, proto_tree
*tree, acn_pdu_history_t* parent_hist, guint max_size);
+	/* Length */
+	if (*flags & ACN_FLAG_LENGTH) {
+		unsigned length = tvb_get_ntoh24(tvb, offset)
+			& ACN_LENGTH_MASK20;
+		proto_tree_add_uint(tree, hf_acn_length,
+				tvb, offset, 3, length);
+		tvb_set_reported_length(tvb, offset + length);
+		offset += 3;
+	} else {
+		unsigned length = tvb_get_ntohs(tvb, offset)
+			& ACN_LENGTH_MASK;
+		proto_tree_add_uint(tree, hf_acn_length,
+				tvb, offset, 2, length);
+		tvb_set_reported_length(tvb, offset + length);
+		offset += 2;
+	}

-static guint
-dissect_sdt(tvbuff_t *tvb, guint offset, proto_tree *tree,
acn_pdu_history_t* parent_hist, guint max_size)
+	return offset;
+}
+
+static unsigned
+dissect_data(tvbuff_t *tvb, unsigned offset,
+		packet_info *pinfo, proto_tree *tree, uint32_t vector);
+
+/* Root layer protocol. */
+static unsigned
+dissect_rlp_header(tvbuff_t *tvb, unsigned offset, proto_tree *tree,
+		proto_tree *rlp)
{
+	e_guid_t guid;
+	tvb_get_guid(tvb, offset, &guid, FALSE);
+	char buf[GUID_STR_LEN];
+	guid_to_str_buf(&guid, buf, sizeof buf);
+	proto_item_append_text(rlp, ", Src: %s", buf);
+
+	proto_tree_add_item(tree, hf_acn_rlp_source_cid,
+		tvb, offset, 16, FALSE);
+	offset += 16;
+
+	return offset;
+}
+
+static unsigned
+dissect_rlp(tvbuff_t *tvb, unsigned offset,
+		packet_info *pinfo, proto_tree *root)
+{
+	proto_tree *item = proto_tree_add_item(root, hf_acn_rlp,
+			tvb, offset, 0, FALSE);
+	proto_tree *tree = proto_item_add_subtree(item, ett_acn_rlp);
+
+	uint8_t flags;
+	offset = dissect_flags_length(tvb, offset, tree, &flags);
+
+	uint32_t vector = 0;
+	if (flags & ACN_FLAG_VECTOR) {
+		vector = tvb_get_ntohl(tvb, offset);
+		proto_tree_add_item(tree, hf_acn_vector, tvb,
+				offset, 4, FALSE);
+		offset += 4;
+	}
+
+	if (flags & ACN_FLAG_HEADER)
+		offset = dissect_rlp_header(tvb, offset, tree, item);
+
+	proto_item_set_end(item, tvb, offset);
+
+	if (flags & ACN_FLAG_DATA)
+		offset = dissect_data(tvb, offset, pinfo, root, vector);
+
+	return offset;
+}
+
+static unsigned
+dissect_pdu(tvbuff_t *tvb, unsigned offset, proto_tree *root)
+{
+	proto_tree *item = proto_tree_add_item(root, hf_acn_pdu,
+			tvb, offset, 0, FALSE);
+	proto_tree *tree = proto_item_add_subtree(item, ett_acn_pdu);
+
+	uint8_t flags;
+	offset = dissect_flags_length(tvb, offset, tree, &flags);
+
+	uint32_t vector = 0;
+	if (flags & ACN_FLAG_VECTOR) {
+		vector = tvb_get_ntohs(tvb, offset);
+		proto_tree_add_item(tree, hf_acn_sdt_mid, tvb,
+				offset, 2, FALSE);
+		offset += 2;
+	}
+
+	if (flags & ACN_FLAG_HEADER) {
+		/* xxx todo */
+		offset += 6;
+	}
+
+	proto_item_set_end(item, tvb, offset);
+
+	return offset;
+}
+
+static unsigned
+dissect_sdt(tvbuff_t *tvb, unsigned offset,
+		packet_info *pinfo, proto_tree *root)
+{
+	(void)pinfo;
+
	proto_tree *flags_tree, *flags_item;
-	guint start_offset = offset;
-	acn_pdu_history_t hist;
	guint size = 0;
-	guint flags;
	guint type;
	guint count;
+	unsigned max_size = tvb_reported_length_remaining(tvb, offset);

-	hist = *parent_hist;
+	proto_tree *item = proto_tree_add_item(root, hf_acn_sdt,
+			tvb, offset, 0, FALSE);
+	proto_tree *tree = proto_item_add_subtree(item, ett_acn_sdt);

-	switch( parent_hist->type )
-	{
-		case ACN_SDT_TYPE_UNKNOWN:
-			break;
+	unsigned start_offset = offset;
+	uint8_t flags;
+	offset = dissect_flags_length(tvb, offset, tree, &flags);

+	uint8_t vector = 0;
+	if (flags & ACN_FLAG_VECTOR) {
+		vector = tvb_get_guint8(tvb, offset);
+		proto_tree_add_item(tree, hf_acn_sdt_vector, tvb,
+				offset, 1, FALSE);
+		offset++;
+	}
+
+	switch (vector) {
		case ACN_SDT_TYPE_RELSEQDATA:
		case ACN_SDT_TYPE_UNRELSEQDATA:
			proto_tree_add_item(tree, hf_acn_sdt_session_nr, tvb,
@@ -238,7 +388,7 @@

			max_size = max_size - (offset - start_offset);
			while( max_size >= ACN_PDU_MIN_SIZE) {
-				size = dissect_pdu( tvb, offset, tree, &hist, max_size);
+				size = dissect_pdu(tvb, offset, tree);
				offset += size;
				max_size -= size;
			}
@@ -254,7 +404,7 @@

			max_size = max_size - (offset - start_offset);
			while( max_size >= ACN_PDU_MIN_SIZE) {
-				size = dissect_pdu( tvb, offset, tree, &hist, max_size);
+				size = dissect_pdu(tvb, offset, tree);
				offset += size;
				max_size -= size;
			}
@@ -272,7 +422,7 @@
			flags_item = proto_tree_add_uint(tree, hf_acn_sdt_flags, tvb,
							offset, 1, flags);

-			flags_tree=proto_item_add_subtree(flags_item, ett_acn);
+			flags_tree=proto_item_add_subtree(flags_item, ett_acn_sdt);
			proto_tree_add_item(flags_tree, hf_acn_sdt_flag_u, tvb, offset, 1, FALSE);
			proto_tree_add_item(flags_tree, hf_acn_sdt_flag_d, tvb, offset, 1, FALSE);
			proto_tree_add_item(flags_tree, hf_acn_sdt_flag_l, tvb, offset, 1, FALSE);
@@ -316,7 +466,7 @@
			flags_item = proto_tree_add_uint(tree, hf_acn_sdt_flags, tvb,
							offset, 1, flags);

-			flags_tree=proto_item_add_subtree(flags_item, ett_acn);
+			flags_tree=proto_item_add_subtree(flags_item, ett_acn_sdt);
			offset += 1;

			type = tvb_get_guint8(tvb, offset);
@@ -400,7 +550,7 @@
			flags_item = proto_tree_add_uint(tree, hf_acn_sdt_flags, tvb,
							offset, 1, flags);

-			flags_tree=proto_item_add_subtree(flags_item, ett_acn);
+			flags_tree=proto_item_add_subtree(flags_item, ett_acn_sdt);
			proto_tree_add_item(flags_tree, hf_acn_sdt_flag_u, tvb, offset, 1, FALSE);
			proto_tree_add_item(flags_tree, hf_acn_sdt_flag_d, tvb, offset, 1, FALSE);
			proto_tree_add_item(flags_tree, hf_acn_sdt_flag_l, tvb, offset, 1, FALSE);
@@ -443,7 +593,7 @@
			flags_item = proto_tree_add_uint(tree, hf_acn_sdt_flags, tvb,
							offset, 1, flags);

-			flags_tree=proto_item_add_subtree(flags_item, ett_acn);
+			flags_tree=proto_item_add_subtree(flags_item, ett_acn_sdt);
			offset += 1;

			type = tvb_get_guint8(tvb, offset);
@@ -644,355 +794,316 @@
			break;
	}
	
-	return size;
+	return offset;
}

-static guint
-dissect_dmp(tvbuff_t *tvb _U_, guint offset _U_, proto_tree *tree
_U_, acn_pdu_history_t* parent_hist _U_, guint max_size _U_)
+static unsigned
+dissect_dmp_header(tvbuff_t *tvb, unsigned offset, proto_tree *tree,
+		proto_tree *dmp)
{
-	return 0;
+	uint8_t flags = tvb_get_guint8(tvb, offset);
+
+	proto_tree *flags_item = proto_tree_add_item(tree, hf_acn_dmp_flags,
+			tvb, offset, 1, FALSE);
+	proto_tree *flags_tree = proto_item_add_subtree(flags_item,
+			ett_acn_dmp_flags);
+	proto_tree_add_item(flags_tree, hf_acn_dmp_virtual,
+			tvb, offset, 1, FALSE);
+	proto_tree_add_item(flags_tree, hf_acn_dmp_relative,
+			tvb, offset, 1, FALSE);
+	proto_tree_add_item(flags_tree, hf_acn_dmp_address_data_type,
+			tvb, offset, 1, FALSE);
+	proto_tree_add_item(flags_tree, hf_acn_dmp_address_size,
+			tvb, offset, 1, FALSE);
+	offset++;
+
+	unsigned address_size = 0, address = 0, count = 0;
+	switch (flags & DMP_ADDRESS_SIZE) {
+		case DMP_ADDRESS_SIZE_1:
+			address_size = 1;
+			address = tvb_get_guint8(tvb, offset);
+			count = tvb_get_guint8(tvb, offset + 2 * address_size);
+			break;
+		case DMP_ADDRESS_SIZE_2:
+			address_size = 2;
+			address = tvb_get_ntohs(tvb, offset);
+			count = tvb_get_ntohs(tvb, offset + 2 * address_size);
+			break;
+		case DMP_ADDRESS_SIZE_4:
+			address_size = 4;
+			address = tvb_get_ntohl(tvb, offset);
+			count = tvb_get_ntohl(tvb, offset + 2 * address_size);
+			break;
+	}
+	proto_item_append_text(dmp, ", Address: %d, Count %d",
+			address, count);
+
+	proto_tree_add_item(tree, hf_acn_dmp_address,
+			tvb, offset, address_size, FALSE);
+	offset += address_size;
+
+	proto_tree_add_item(tree, hf_acn_dmp_increment,
+			tvb, offset, address_size, FALSE);
+	offset += address_size;
+
+	proto_tree_add_item(tree, hf_acn_dmp_count,
+			tvb, offset, address_size, FALSE);
+	offset += address_size;
+
+	return offset;
}

-static guint
-dissect_pdu(tvbuff_t *tvb, guint offset, proto_tree *tree,
acn_pdu_history_t* parent_hist, guint max_size)
+static unsigned
+dissect_dmp(tvbuff_t *tvb, unsigned offset,
+		packet_info *pinfo, proto_tree *root)
{
-	guint size,data_size;
-	guint8 flags;
-	guint src,des;
-	proto_tree *ti, *si, *flags_tree, *flags_item, *data_tree, *data_item;
-	guint start_offset = offset;
-	acn_pdu_history_t hist = *parent_hist;
-	
+	(void)pinfo;

-	ti = proto_tree_add_item(tree,
-				hf_acn_pdu,
-				tvb,
-				offset,
-				0,
-				FALSE);
-
-	si = proto_item_add_subtree(ti, ett_acn);
-
-	flags = tvb_get_guint8(tvb, offset);
-	flags_item = proto_tree_add_uint(si, hf_acn_pdu_flags, tvb,
-					offset, 1, flags);
+	proto_tree *item = proto_tree_add_item(root, hf_acn_dmp,
+			tvb, offset, 0, FALSE);
+	proto_tree *tree = proto_item_add_subtree(item, ett_acn_dmp);

-	flags_tree=proto_item_add_subtree(flags_item, ett_acn);
-	
-	proto_tree_add_item(flags_tree, hf_acn_pdu_des, tvb, offset, 1, FALSE);
-	proto_tree_add_item(flags_tree, hf_acn_pdu_src, tvb, offset, 1, FALSE);
-	proto_tree_add_item(flags_tree, hf_acn_pdu_flag_p, tvb, offset, 1, FALSE);
-	proto_tree_add_item(flags_tree, hf_acn_pdu_flag_t, tvb, offset, 1, FALSE);
-	proto_tree_add_item(flags_tree, hf_acn_pdu_flag_res, tvb, offset, 1, FALSE);
-	proto_tree_add_item(flags_tree, hf_acn_pdu_flag_z, tvb, offset, 1, FALSE);
+	uint8_t flags;
+	offset = dissect_flags_length(tvb, offset, tree, &flags);

-	offset += 1;
+	uint8_t vector = 0;
+	if (flags & ACN_FLAG_VECTOR) {
+		vector = tvb_get_guint8(tvb, offset);
+		proto_tree_add_item(tree, hf_acn_dmp_vector, tvb,
+				offset, 1, FALSE);
+		offset++;
+	}

-	size = tvb_get_guint8(tvb, offset);	
-	proto_tree_add_uint(si, hf_acn_pdu_length, tvb,
-	                          offset, 1, size);
-	offset += 1;
-	
+	if (flags & ACN_FLAG_HEADER)
+		offset = dissect_dmp_header(tvb, offset, tree, item);

-	if( size == 0 ){
-		size = tvb_get_ntohs(tvb, offset);
-		proto_tree_add_uint(si, hf_acn_pdu_ext_length_16, tvb,
-					offset, 2, size);	
-		offset += 2;	
-	} else if( size == 1 ){
-		size = tvb_get_ntohl( tvb, offset);
-		proto_tree_add_uint(si, hf_acn_pdu_ext_length_32, tvb,
-					offset, 4, size);	
-		offset += 4;
-	}
-	
-	if(size > max_size )
-		size = max_size;
+	proto_item_set_end(item, tvb, offset);

-	switch( flags & ACN_PDU_DES )
-	{	
-		case ACN_PDU_DES_SAME:
-			break;
-			
-		case ACN_PDU_DES_PS:
-			hist.destination_type = ACN_PDU_DES_PS;
-			des = tvb_get_ntohs(tvb, offset);
-			hist.destination.ps = des;
-			proto_tree_add_uint(si, hf_acn_pdu_destination_ps, tvb,
-						offset, 2, des);	
-			offset += 2;
-			break;
-			
-		case ACN_PDU_DES_CID:
-			hist.destination_type = ACN_PDU_DES_CID;
-			tvb_memcpy(tvb, hist.destination.cid, offset, 16 );
-			proto_tree_add_item(si, hf_acn_pdu_destination_cid, tvb,
-						offset, 16, FALSE);
-			offset += 16;
-			break;
-			
-		case ACN_PDU_DES_ALL:
-			hist.destination_type = ACN_PDU_DES_ALL;
-			break;	
-	}
+	return offset;
+}

+/* DMX streaming protocol (E1.31) */
+static unsigned
+dissect_dmxsp_header(tvbuff_t *tvb, unsigned offset,
+		packet_info *pinfo, proto_tree *tree,
+		proto_tree *dmxsp)
+{
+	if (check_col(pinfo->cinfo, COL_INFO))
+		col_set_str(pinfo->cinfo, COL_INFO, "DMX streaming protocol");

-	switch( flags & ACN_PDU_SRC )
-	{
-		case ACN_PDU_SRC_SAME:
-			break;
-			
-		case ACN_PDU_SRC_PS:
-			hist.source_type = ACN_PDU_SRC_PS;
-			src = tvb_get_ntohs(tvb, offset);
-			hist.source.ps = src;
-			proto_tree_add_uint(si, hf_acn_pdu_source_ps, tvb,
-						offset, 2, src);
-			offset += 2;
-			break;
-			
-		case ACN_PDU_SRC_CID:
-			hist.source_type = ACN_PDU_SRC_CID;
-			tvb_memcpy(tvb, hist.source.cid, offset, 16 );
-			proto_tree_add_item(si, hf_acn_pdu_source_cid, tvb,
-						offset, 16, FALSE);
-			offset += 16;
-			break;
-			
-		case ACN_PDU_SRC_UM:
-			hist.source_type = ACN_PDU_SRC_UM;
-			break;	
-	}
+	proto_tree_add_item(tree, hf_acn_dmxsp_source_name,
+			tvb, offset, 32, FALSE);
+	offset += 32;

+	uint8_t priority = tvb_get_guint8(tvb, offset);
+	proto_tree_add_item(tree, hf_acn_dmxsp_priority,
+			tvb, offset, 1, FALSE);
+	offset++;

+	proto_tree_add_item(tree, hf_acn_dmxsp_sequence,
+			tvb, offset, 1, FALSE);
+	offset++;

-	if( flags & ACN_PDU_FLAG_P )
-	{
-		hist.protocol = tvb_get_ntohs( tvb, offset );
-		proto_tree_add_item(si, hf_acn_pdu_protocol, tvb,
-					offset, 2, FALSE );
-		offset += 2;
-	}
+	uint16_t universe = tvb_get_ntohs(tvb, offset);
+	proto_item_append_text(dmxsp, ", Universe: %d, Priority: %d",
+			universe, priority);

-	if( flags & ACN_PDU_FLAG_T )
-	{
-		hist.type = tvb_get_ntohs( tvb, offset );
-	
-		switch( hist.protocol ) {
-			case ACN_PDU_PROTO_SDT:
-				proto_tree_add_item(si, hf_acn_pdu_type_sdt, tvb,
-						offset, 2, FALSE );
-				break;
+	proto_tree_add_item(tree, hf_acn_dmxsp_universe,
+			tvb, offset, 2, FALSE);
+	offset += 2;

-			case ACN_PDU_PROTO_DMP:
-				proto_tree_add_item(si, hf_acn_pdu_type_dmp, tvb,
-						offset, 2, FALSE );
-				break;
-				
-			default:
-				proto_tree_add_item(si, hf_acn_pdu_type, tvb,
-						offset, 2, FALSE );
-				break;	
-	
-	
-	
-		}
-		
-		offset += 2;
+	return offset;
+}
+
+static unsigned
+dissect_dmxsp(tvbuff_t *tvb, unsigned offset,
+		packet_info *pinfo, proto_tree *root)
+{
+	proto_tree *item = proto_tree_add_item(root, hf_acn_dmxsp,
+			tvb, offset, 0, FALSE);
+	proto_tree *tree = proto_item_add_subtree(item, ett_acn_dmxsp);
+
+	uint8_t flags;
+	offset = dissect_flags_length(tvb, offset, tree, &flags);
+
+	uint32_t vector = 0;
+	if (flags & ACN_FLAG_VECTOR) {
+		vector = tvb_get_ntohl(tvb, offset);
+		proto_tree_add_item(tree, hf_acn_vector, tvb,
+				offset, 4, FALSE);
+		offset += 4;
	}

-	if( flags & ACN_PDU_FLAG_Z )
-	{
-		data_size = size - (offset - start_offset);
+	if (flags & ACN_FLAG_HEADER)
+		offset = dissect_dmxsp_header(tvb, offset, pinfo, tree,
+			item);

+	proto_item_set_end(item, tvb, offset);

-		data_item = proto_tree_add_item(si, hf_acn_pdu_data, tvb,
-						offset, data_size, FALSE);
+	if (flags & ACN_FLAG_DATA)
+		offset = dissect_data(tvb, offset, pinfo, root, vector);

-		data_tree=proto_item_add_subtree(data_item, ett_acn);
+	return offset;
+}

+static unsigned
+dissect_unknown(tvbuff_t *tvb, unsigned offset,
+		packet_info *pinfo, proto_tree *tree)
+{
+	(void)tvb; (void)offset; (void)tree;
+	if (check_col(pinfo->cinfo, COL_INFO))
+		col_set_str(pinfo->cinfo, COL_INFO, "Unknown PDU");
+	return 0;
+}

-		switch( hist.protocol ) {
-			case ACN_PDU_PROTO_SDT:
-				dissect_sdt( tvb, offset, data_tree, &hist, data_size);
-				break;
-			
-			case ACN_PDU_PROTO_DMP:
-				dissect_dmp( tvb, offset, data_tree, &hist, data_size);	
-				break;
-	
-			default:
-				proto_tree_add_item(si, hf_acn_pdu_unknown_data, tvb,
-							offset, data_size, FALSE );
-				break;	
-		}
+static unsigned
+dissect_data(tvbuff_t *tvb, unsigned offset,
+		packet_info *pinfo, proto_tree *tree, uint32_t vector)
+{
+	return (vector == ACN_VECTOR_SDT ? dissect_sdt :
+			vector == ACN_VECTOR_DMP ? dissect_dmp :
+			vector == ACN_VECTOR_DMXSP ? dissect_dmxsp :
+			dissect_unknown)(tvb, offset, pinfo, tree);
+}

-		offset += data_size;
-	}
+static unsigned dissect_preamble(tvbuff_t *tvb, unsigned offset,
+		proto_tree *tree)
+{
+	uint16_t preamble_size = tvb_get_ntohs(tvb, offset);
+	unsigned id_size = preamble_size - 4;

-	if( size & 0x00000001 )
-	{
-	
-		proto_tree_add_item(si, hf_acn_pdu_padding, tvb,
-					offset, 1, TRUE );
-		
-		size += 1;
-		offset += 1;
-	}
+	proto_tree *item = proto_tree_add_item(tree, hf_acn_preamble,
+			tvb, offset, preamble_size, FALSE);
+	proto_tree *subtree = proto_item_add_subtree(item,
+			ett_acn_preamble);

-	proto_item_set_len(si, size);
+	proto_tree_add_item(subtree, hf_acn_preamble_size,
+			tvb, offset, 2, FALSE);
+	offset += 2;
+	proto_tree_add_item(subtree, hf_acn_postamble_size,
+			tvb, offset, 2, FALSE);
+	offset += 2;
+	proto_tree_add_item(subtree, hf_acn_id,
+			tvb, offset, id_size, FALSE);
+	offset += id_size;

-	return size;
+	return offset;
}

-static void
-dissect_acn(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
-	gint offset = 0;
-	guint size,max_size;
-	acn_pdu_history_t hist;
+static int
+dissect_acn(tvbuff_t *tvb, packet_info *pinfo, proto_tree *root)
+{
+	const uint8_t id[12] = "ASC-E1.17";
+	if (tvb_memeql(tvb, 4, id, sizeof id) != 0)
+		return 0;

-	/* Set the protocol column */
-	if(check_col(pinfo->cinfo,COL_PROTOCOL)){
-		col_set_str(pinfo->cinfo,COL_PROTOCOL,"ACN");
-	}
+	if (check_col(pinfo->cinfo, COL_PROTOCOL))
+		col_set_str(pinfo->cinfo, COL_PROTOCOL, "ACN");
+	if (check_col(pinfo->cinfo, COL_INFO))
+		col_clear(pinfo->cinfo, COL_INFO);

-	/* Clear out stuff in the info column */
-	if(check_col(pinfo->cinfo,COL_INFO)){
-		col_clear(pinfo->cinfo,COL_INFO);
-	}
+	if (root != NULL) {
+		unsigned offset = 0;
+		proto_tree *item = proto_tree_add_item(root, proto_acn,
+				tvb, offset, -1, FALSE);
+		proto_tree *tree = proto_item_add_subtree(item,
+				ett_acn);

-	if (tree)
-	{
-		/* history default values */
-		hist.destination_type = ACN_PDU_DES_ALL;
-		hist.source_type = ACN_PDU_SRC_UM;
-		hist.protocol = ACN_PDU_PROTO_UNKNOWN;
-		hist.type = ACN_PDU_TYPE_UNKNOWN;
-		
-		max_size = tvb_reported_length_remaining(tvb, offset);
-		
-		while( max_size >= ACN_PDU_MIN_SIZE) {
-			size = dissect_pdu( tvb, offset, tree, &hist, max_size);
-			offset += size;
-			max_size -= size;
-		}
+		offset = dissect_preamble(tvb, offset, tree);
+		offset = dissect_rlp(tvb, offset, pinfo, tree);
+
+		proto_item_set_end(item, tvb, offset);
+
+		tvbuff_t *next_tvb = tvb_new_subset(tvb,
+				offset, -1, -1);
+		call_dissector(data_handle, next_tvb, pinfo, root);
+		return offset;
	}
+	return tvb_length(tvb);
}

void
-proto_register_acn(void) {
+proto_register_acn(void)
+{
  static hf_register_info hf[] = {
+	/* Preamble */
+	{ &hf_acn_preamble,
+	    { "Preamble", "acn.preamble",
+		FT_NONE, BASE_NONE, NULL, 0,
+		NULL, HFILL }},
+	{ &hf_acn_preamble_size,
+	    { "Preamble size", "acn.preamble_size",
+		FT_UINT16, BASE_DEC, NULL, 0,
+		NULL, HFILL }},
+	{ &hf_acn_postamble_size,
+	    { "Postamble size", "acn.postamble_size",
+		FT_UINT16, BASE_DEC, NULL, 0,
+		NULL, HFILL }},
+	{ &hf_acn_id,
+	    { "Packet identififer", "acn.id",
+		FT_STRING, BASE_NONE, NULL, 0,
+		NULL, HFILL }},
+
	/* PDU */
	{ &hf_acn_pdu,
-	    { "ACN PDU", "acn.pdu",
+	    { "PDU", "acn.pdu",
		FT_NONE, BASE_NONE, NULL, 0,
-		"ACN PDU", HFILL }},
+		NULL, HFILL }},

-	{ &hf_acn_pdu_flags,
-	    { "Flags","acn.pdu.flags",
-		FT_UINT8, BASE_HEX, NULL, 0x0,
+	{ &hf_acn_flags,
+	    { "Flags", "acn.flags",
+		FT_UINT8, BASE_HEX, NULL, ACN_FLAG_MASK,
		"Flags", HFILL }},

-	{ &hf_acn_pdu_des,
-	    { "des","acn.pdu.des",
-		FT_UINT8, BASE_HEX, VALS( acn_sdt_des_flag_vals ), 0xC0,
-		"des", HFILL }},
+	{ &hf_acn_flag_length,
+	    { "Length", "acn.flag_length",
+		FT_UINT8, BASE_DEC, NULL, ACN_FLAG_LENGTH,
+		NULL, HFILL }},

-	{ &hf_acn_pdu_src,
-	    { "src","acn.pdu.src",
-		FT_UINT8, BASE_HEX, VALS( acn_sdt_src_flag_vals ), 0x30,
-		"src", HFILL }},
+	{ &hf_acn_flag_vector,
+	    { "Vector", "acn.flag_vector",
+		FT_UINT8, BASE_DEC, NULL, ACN_FLAG_VECTOR,
+		NULL, HFILL }},

-	{ &hf_acn_pdu_flag_p,
-	    { "P","acn.pdu.flag_p",
-		FT_UINT8, BASE_HEX, NULL, 0x08,
-		"P", HFILL }},
+	{ &hf_acn_flag_header,
+	    { "Header", "acn.flag_header",
+		FT_UINT8, BASE_DEC, NULL, ACN_FLAG_HEADER,
+		NULL, HFILL }},

-	{ &hf_acn_pdu_flag_t,
-	    { "T","acn.pdu.flag_t",
-		FT_UINT8, BASE_HEX, NULL, 0x04,
-		"T", HFILL }},
+	{ &hf_acn_flag_data,
+	    { "Data", "acn.flag_data",
+		FT_UINT8, BASE_DEC, NULL, ACN_FLAG_DATA,
+		NULL, HFILL }},

-	{ &hf_acn_pdu_flag_z,
-	    { "Z","acn.pdu.flag_z",
-		FT_UINT8, BASE_HEX, NULL, 0x01,
-		"Z", HFILL }},
-
-	{ &hf_acn_pdu_flag_res,
-	    { "res","acn.pdu.flag_res",
-		FT_UINT8, BASE_HEX, NULL, 0x02,
-		"res", HFILL }},
-
-	{ &hf_acn_pdu_length,
-	    { "Length","acn.pdu.length",
-		FT_UINT8, BASE_DEC, NULL, 0x0,
+	{ &hf_acn_length,
+	    { "Length", "acn.length",
+		FT_UINT16, BASE_DEC, NULL, 0,
		"Length", HFILL }},

-	{ &hf_acn_pdu_ext_length_16,
-	    { "Ext Length 16bit","acn.pdu.ext_length_16",
-		FT_UINT16, BASE_DEC, NULL, 0x0,
-		"Ext Length 16bit", HFILL }},
+	{ &hf_acn_vector,
+	    { "Vector", "acn.vector",
+		FT_UINT32, BASE_DEC, VALS(acn_vector_vals), 0x0,
+		NULL, HFILL }},

-	{ &hf_acn_pdu_ext_length_32,
-	    { "Ext Length 32bit","acn.pdu.ext_length_32",
-		FT_UINT32, BASE_DEC, NULL, 0x0,
-		"Ext Length 32bit", HFILL }},
+	/* RLP */
+	{ &hf_acn_rlp,
+	    { "Root level protocol", "acn.rlp",
+		FT_NONE, BASE_NONE, NULL, 0,
+		NULL, HFILL }},
+	{ &hf_acn_rlp_source_cid,
+	    { "Source CID", "acn.rlp.source_cid",
+		FT_GUID, BASE_NONE, NULL, 0,
+		NULL, HFILL }},

-	{ &hf_acn_pdu_source_ps,
-	    { "Source PS","acn.pdu.source_ps",
-		FT_UINT16, BASE_HEX, NULL, 0x0,
-		"Source PS", HFILL }},
-
-	{ &hf_acn_pdu_source_cid,
-	    { "Source CID","acn.pdu.source_cid",
-		FT_BYTES, BASE_HEX, NULL, 0x0,
-		"Source CID", HFILL }},
-
-	{ &hf_acn_pdu_destination_ps,
-	    { "Destination PS","acn.pdu.destination_ps",
-		FT_UINT16, BASE_HEX, NULL, 0x0,
-		"Destination PS", HFILL }},
-
-	{ &hf_acn_pdu_destination_cid,
-	    { "Destination CID","acn.pdu.destination_cid",
-		FT_BYTES, BASE_HEX, NULL, 0x0,
-		"Destination CID", HFILL }},
-
-	{ &hf_acn_pdu_protocol,
-	    { "Protocol","acn.pdu.protocol",
-		FT_UINT16, BASE_HEX, VALS(acn_proto_vals), 0x0,
-		"Protocol", HFILL }},
-
-	{ &hf_acn_pdu_type,
-	    { "Type","acn.pdu.type",
-		FT_UINT16, BASE_HEX, NULL, 0x0,
-		"Type", HFILL }},
-
-	{ &hf_acn_pdu_type_sdt,
-	    { "SDT Type","acn.pdu.type_sdt",
-		FT_UINT16, BASE_HEX, VALS(acn_sdt_type_vals), 0x0,
+	/* SDT */
+	{ &hf_acn_sdt,
+	    { "Session data transport", "acn.sdt",
+		FT_NONE, BASE_NONE, NULL, 0,
+		NULL, HFILL }},
+	{ &hf_acn_sdt_vector,
+	    { "SDT vector", "acn.sdt.vector",
+		FT_UINT8, BASE_DEC, VALS(acn_sdt_type_vals), 0x0,
		"SDT Type", HFILL }},
-
-	{ &hf_acn_pdu_type_dmp,
-	    { "DMP Type","acn.pdu.type_dmp",
-		FT_UINT16, BASE_HEX, VALS(acn_dmp_type_vals), 0x0,
-		"DMP Type", HFILL }},
-		
-	{ &hf_acn_pdu_data,
-	    { "Data","acn.pdu.data",
-		FT_NONE, BASE_HEX, NULL, 0x0,
-		"Data", HFILL }},
-
-	{ &hf_acn_pdu_unknown_data,
-	    { "Unknown Data","acn.pdu.unknown_data",
-		FT_BYTES, BASE_HEX, NULL, 0x0,
-		"Unknown Data", HFILL }},
-
-	{ &hf_acn_pdu_padding,
-	    { "Padding","acn.pdu.padding",
-		FT_UINT8, BASE_DEC, NULL, 0x0,
-		"Padding", HFILL }},
-
	{ &hf_acn_sdt_session_nr,
	    { "SDT Session Nr","acn.sdt.session_nr",
		FT_UINT16, BASE_DEC, NULL, 0x0,
@@ -1136,50 +1247,102 @@
	{ &hf_acn_sdt_leader_cid,
	    { "SDT Leader CID","acn.sdt.leader_cid",
		FT_BYTES, BASE_HEX, NULL, 0x0,
-		"SDT Leader CID", HFILL }}
+		"SDT Leader CID", HFILL }},

+	/* DMP */
+	{ &hf_acn_dmp,
+	    { "Device management protocol", "acn.dmp",
+		FT_NONE, BASE_NONE, NULL, 0,
+		NULL, HFILL }},
+	{ &hf_acn_dmp_vector,
+	    { "Vector", "acn.dmp.vector",
+		FT_UINT8, BASE_DEC, VALS(acn_dmp_vector_vals), 0,
+		NULL, HFILL }},
+	{ &hf_acn_dmp_flags,
+	    { "Flags", "acn.dmp.flags",
+		FT_UINT8, BASE_HEX, NULL, 0,
+		NULL, HFILL }},
+	{ &hf_acn_dmp_virtual,
+	    { "Virtual address", "acn.dmp.virtual",
+		FT_UINT8, BASE_DEC, NULL, DMP_VIRTUAL,
+		NULL, HFILL }},
+	{ &hf_acn_dmp_relative,
+	    { "Relative address", "acn.dmp.relative",
+		FT_UINT8, BASE_DEC, NULL, DMP_RELATIVE,
+		NULL, HFILL }},
+	{ &hf_acn_dmp_address_data_type,
+	    { "Address and data type", "acn.dmp.address_data_type",
+		FT_UINT8, BASE_DEC, VALS(acn_dmp_address_data_type_vals),
+		DMP_ADDRESS_DATA_TYPE,
+		NULL, HFILL }},
+	{ &hf_acn_dmp_address_size,
+	    { "Address size", "acn.dmp.address_size",
+		FT_UINT8, BASE_DEC, VALS(acn_dmp_address_size_vals),
+		DMP_ADDRESS_SIZE,
+		NULL, HFILL }},
+	{ &hf_acn_dmp_address,
+	    { "Address", "acn.dmp.address",
+		FT_UINT16, BASE_DEC, NULL, 0,
+		NULL, HFILL }},
+	{ &hf_acn_dmp_increment,
+	    { "Increment", "acn.dmp.increment",
+		FT_UINT16, BASE_DEC, NULL, 0,
+		NULL, HFILL }},
+	{ &hf_acn_dmp_count,
+	    { "Count", "acn.dmp.count",
+		FT_UINT16, BASE_DEC, NULL, 0,
+		NULL, HFILL }},
+		
+	/* DMX streaming protocol (E1.31) */
+	{ &hf_acn_dmxsp,
+	    { "DMX streaming protocol", "acn.dmxsp",
+		FT_NONE, BASE_NONE, NULL, 0,
+		NULL, HFILL }},
+	{ &hf_acn_dmxsp_source_name,
+		{ "Source name", "acn.dmxsp.source_name",
+		FT_STRING, BASE_NONE, NULL, 0,
+		NULL, HFILL }},
+
+	{ &hf_acn_dmxsp_priority,
+		{ "Priority", "acn.dmxsp.priority",
+		FT_UINT8, BASE_DEC, NULL, 0,
+		NULL, HFILL }},
+
+	{ &hf_acn_dmxsp_sequence,
+		{ "Sequence", "acn.dmxsp.seq",
+		FT_UINT8, BASE_DEC, NULL, 0,
+		NULL, HFILL }},
+
+	{ &hf_acn_dmxsp_universe,
+		{ "Universe", "acn.dmxsp.universe",
+		FT_UINT16, BASE_DEC, NULL, 0,
+		NULL, HFILL }},
  };

  static gint *ett[] = {
-    &ett_acn,
+		&ett_acn,
+		&ett_acn_preamble,
+		&ett_acn_flags,
+		&ett_acn_rlp,
+		&ett_acn_sdt,
+		&ett_acn_dmp,
+		&ett_acn_dmp_flags,
+		&ett_acn_dmxsp,
+		&ett_acn_pdu,
  };

-  module_t *acn_module;
-
-  proto_acn = proto_register_protocol("ACN",
-				      "ACN","acn");
-  proto_register_field_array(proto_acn,hf,array_length(hf));
-  proto_register_subtree_array(ett,array_length(ett));
-
-  acn_module = prefs_register_protocol(proto_acn,
-				       proto_reg_handoff_acn);
-#if 0
-  prefs_register_uint_preference(artnet_module, "udp_port",
-				 "ARTNET UDP Port",
-				 "The UDP port on which "
-				 "Art-Net "
-				 "packets will be sent",
-				 10,&global_udp_port_artnet);
-#endif
+  proto_acn = proto_register_protocol(
+			"Architecture for Control Network", "ACN", "acn");
+  proto_register_field_array(proto_acn, hf, array_length(hf));
+  proto_register_subtree_array(ett, array_length(ett));
}

-/* The registration hand-off routing */
-
void
-proto_reg_handoff_acn(void) {
-  static int acn_initialized = FALSE;
-  static dissector_handle_t acn_handle;
+proto_reg_handoff_acn(void)
+{
+	static dissector_handle_t acn_handle;

-  ip_handle = find_dissector("ip");
-
-  if(!acn_initialized) {
-    acn_handle = create_dissector_handle(dissect_acn,proto_acn);
-    acn_initialized = TRUE;
-  } else {
-    dissector_delete("udp.port",udp_port_acn,acn_handle);
-  }
-
-  udp_port_acn = global_udp_port_acn;
-
-  dissector_add("udp.port",global_udp_port_acn,acn_handle);
+	acn_handle = new_create_dissector_handle(dissect_acn, proto_acn);
+	data_handle = find_dissector("data");
+	dissector_add("udp.port", IPPORT_ACN, acn_handle);
}
2006-10-25  Shaun Jackman  <sjackman@xxxxxxxxx>

	* plugins/acn/acn.c: Add DMX streaming protocol (E1.31) and device
	management protocol (DMP). Update root layer protocol (RLP) to the
	latest draft standard.
	* plugins/acn/acn.h: Ditto.

Index: plugins/acn/acn.h
===================================================================
--- plugins/acn/acn.h	(revision 19609)
+++ plugins/acn/acn.h	(working copy)
@@ -1,52 +1,28 @@
-#ifndef __ACN_H__
-#define __ACN_H__
+#ifndef ACN_H
+#define ACN_H 1
 
-#define ACN_PDU_MIN_SIZE	2
+#include <stdint.h>
 
-#define ACN_PDU_DES		0xC0
-#define ACN_PDU_DES_SAME	0x00
-#define ACN_PDU_DES_PS		0x40
-#define ACN_PDU_DES_CID		0x80
-#define ACN_PDU_DES_ALL		0xC0
+enum { IPPORT_ACN = 5568 };
 
-#define ACN_PDU_SRC		0x30
-#define ACN_PDU_SRC_SAME	0x00
-#define ACN_PDU_SRC_PS		0x10
-#define ACN_PDU_SRC_CID		0x20
-#define ACN_PDU_SRC_UM		0x30
+#define ACN_PDU_MIN_SIZE	2
 
-#define ACN_PDU_FLAG_P		0x08
-#define ACN_PDU_FLAG_T		0x04
-#define ACN_PDU_FLAG_RES	0x02
-#define ACN_PDU_FLAG_Z		0x01
+/* flags_length */
+enum {
+	ACN_FLAG_MASK = 0xf0,
+	ACN_FLAG_LENGTH = 0x80,
+	ACN_FLAG_VECTOR = 0x40,
+	ACN_FLAG_HEADER = 0x20,
+	ACN_FLAG_DATA = 0x10,
+	ACN_LENGTH_MASK = 0xfff,
+	ACN_LENGTH_MASK20 = 0xfffff,
+};
 
-typedef struct acn_pdu_history_s 
-{
-	guint8 source_type;
-	union {
-		guint16 ps;
-		guint8 cid[16];
-	} source;
+#define ACN_VECTOR_SDT	1
+#define ACN_VECTOR_DMP	2
+#define ACN_VECTOR_DMXSP	3
 
-	guint8 destination_type;
-	union {
-		guint16 ps;
-		guint8 cid[16];	
-	} destination;
-	
-	guint16 protocol;
-	guint16 type;
-} acn_pdu_history_t;
-
-
-#define ACN_PDU_PROTO_UNKNOWN	0
-#define ACN_PDU_PROTO_SDT	1
-#define ACN_PDU_PROTO_DMP	2
-
-#define ACN_PDU_TYPE_UNKNOWN	0
-
 /* SDT */
-#define ACN_SDT_TYPE_UNKNOWN		0
 #define ACN_SDT_TYPE_RELSEQDATA		1
 #define ACN_SDT_TYPE_UNRELSEQDATA	2
 #define ACN_SDT_TYPE_UNSEQDATA		3
@@ -70,12 +46,42 @@
 #define ACN_SDT_TYPE_SEQLOST		21
 #define ACN_SDT_TYPE_NAKPARAMS		22
 
-
 #define ACN_SDT_ADDR_NULL 0
 #define ACN_SDT_ADDR_IPV4 1
 #define ACN_SDT_ADDR_IPV6 2
 
 /* DMP */
-#define ACN_DMP_TYPE_UNKNOWN	0
+enum {
+	DMP_GET_PROPERTY = 1,
+	DMP_SET_PROPERTY = 2,
+	DMP_GET_PROPERTY_REPLY = 3,
+	DMP_EVENT = 4,
+	DMP_MAP_PROPERTY = 5,
+	DMP_UNMAP_PROPERTY = 6,
+	DMP_SUBSCRIBE = 7,
+	DMP_UNSUBSCRIBE = 8,
+	DMP_GET_PROPERTY_FAIL = 9,
+	DMP_SET_PROPERTY_FAIL = 10,
+	DMP_MAP_PROPERTY_FAIL = 11,
+	DMP_SUBSCRIBE_ACCEPT = 12,
+	DMP_SUBSCRIBE_REJECT = 13,
+	DMP_ALLOCATE_MAP = 14,
+	DMP_ALLOCATE_MAP_REPLY = 15,
+	DMP_DEALLOCATE_MAP = 16,
+};
 
+enum {
+	DMP_VIRTUAL = 0x80,
+	DMP_RELATIVE = 0x40,
+	DMP_ADDRESS_DATA_TYPE = 0x30,
+	DMP_SINGLE_ADDRESS_SINGLE_DATA = 0x00,
+	DMP_RANGE_ADDRESS_SINGLE_DATA = 0x10,
+	DMP_RANGE_ADDRESS_EQUAL_SIZE_DATA = 0x20,
+	DMP_RANGE_ADDRESS_MIXED_SIZE_DATA = 0x30,
+	DMP_ADDRESS_SIZE = 0x03,
+	DMP_ADDRESS_SIZE_1 = 0,
+	DMP_ADDRESS_SIZE_2 = 1,
+	DMP_ADDRESS_SIZE_4 = 2,
+};
+
 #endif /* !__ACN_H__ */
Index: plugins/acn/packet-acn.c
===================================================================
--- plugins/acn/packet-acn.c	(revision 19609)
+++ plugins/acn/packet-acn.c	(working copy)
@@ -1,10 +1,17 @@
 /* packet-acn.c
- * Routines for ACN packet disassembly
+ * Routines for Architecture for Control Network protocol (ACN, E1.17)
+ * packet disassembly.
  *
  * $Id$
  *
- * Copyright (c) 2003 by Erwin Rol <erwin@xxxxxxxxxxxx>
+ * This dissector is written by
  *
+ *  Shaun Jackman <sjackman@xxxxxxxxx>
+ *  Copyright 2006 Pathway Connectivity
+ *
+ *  Erwin Rol <erwin@xxxxxxxxxxxx>
+ *  Copyright 2003 Erwin Rol
+ *
  * Wireshark - Network traffic analyzer
  * By Gerald Combs <gerald@xxxxxxxxxxxxx>
  * Copyright 1999 Gerald Combs
@@ -30,6 +37,7 @@
 #include "config.h"
 #endif
 
+#include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <ctype.h>
@@ -45,21 +53,15 @@
 
 #include "acn.h"
 
-/*
- * See
- *
- *	http://www.esta.org/tsp/E1-17inst.htm
- */
-
-static const value_string acn_proto_vals[] = {
-	{ ACN_PDU_PROTO_UNKNOWN,	"Unknown"},
-	{ ACN_PDU_PROTO_SDT,		"SDT" },
-	{ ACN_PDU_PROTO_DMP,		"DMP" },
+static const value_string acn_vector_vals[] = {
+	{ ACN_VECTOR_SDT,		"Session data transport" },
+	{ ACN_VECTOR_DMP,		"Device management protocol" },
+	{ ACN_VECTOR_DMXSP,		"DMX streaming protocol" },
 	{ 0,				NULL }
 };
 
+/* SDT */
 static const value_string acn_sdt_type_vals[] = {
-	{ ACN_SDT_TYPE_UNKNOWN,		"Unknown"},
 	{ ACN_SDT_TYPE_RELSEQDATA,	"RELSEQDATA"},
 	{ ACN_SDT_TYPE_UNRELSEQDATA,	"UNRELSEQDATA"},
 	{ ACN_SDT_TYPE_UNSEQDATA,	"UNSEQDATA"},
@@ -85,12 +87,6 @@
 	{ 0,				NULL }
 };
 
-static const value_string acn_dmp_type_vals[] = {
-	{ ACN_DMP_TYPE_UNKNOWN,		"Unknown"},
-	{ 0,				NULL }
-};
-
-
 static const value_string acn_sdt_address_type_vals[] = {
 	{ ACN_SDT_ADDR_NULL,		"Unspecified"},
 	{ ACN_SDT_ADDR_IPV4,		"IP version 4"},
@@ -98,61 +94,81 @@
 	{ 0,				NULL }
 };
 
-static const value_string acn_sdt_des_flag_vals[] = {
-	{ 0,				"Default"},
-	{ 1,				"Protocol Specific"},
-	{ 2,				"CID"},
-	{ 3,				"All"}, 
-	{ 0,				NULL }
+/* DMP */
+static const value_string acn_dmp_vector_vals[] = {
+	{ 1, "Get property" },
+	{ 2, "Set property" },
+	{ 3, "Get property reply" },
+	{ 4, "Event" },
+	{ 5, "Map property" },
+	{ 6, "Unmap property" },
+	{ 7, "Subscribe" },
+	{ 8, "Unsubscribe" },
+	{ 9, "Get property fail" },
+	{ 10, "Set property fail" },
+	{ 11, "Map property fail" },
+	{ 12, "Subscribe accept" },
+	{ 13, "Subscribe reject" },
+	{ 14, "Allocate map" },
+	{ 15, "Allocate map reply" },
+	{ 16, "Deallocate map" },
+	{ 0, NULL }
 };
 
-static const value_string acn_sdt_src_flag_vals[] = {
-	{ 0,				"Default"},
-	{ 1,				"Protocol Specific"},
-	{ 2,				"CID"},
-	{ 3,				"Unspecified"}, 
-	{ 0,				NULL }
+static const value_string acn_dmp_address_data_type_vals[] = {
+	{ 0, "Single address, single data" },
+	{ 1, "Range address, single data" },
+	{ 2, "Range address, equal size data" },
+	{ 3, "Range address, mixed size data" },
+	{ 0, NULL }
 };
 
+static const value_string acn_dmp_address_size_vals[] = {
+	{ 0, "1 byte" },
+	{ 1, "2 bytes" },
+	{ 2, "4 bytes" },
+	{ 0, NULL }
+};
 
 void proto_reg_handoff_acn(void);
 
-/* Define the acn proto */
+static dissector_handle_t data_handle;
+
 static int proto_acn = -1;
 
-/* Define the tree for acn */
 static int ett_acn = -1;
+static int ett_acn_flags = -1;
+static int ett_acn_preamble = -1;
+static int ett_acn_rlp = -1;
+static int ett_acn_sdt = -1;
+static int ett_acn_dmp = -1;
+static int ett_acn_dmp_flags = -1;
+static int ett_acn_dmxsp = -1;
+static int ett_acn_pdu = -1;
 
-/* PDU */
+/* Preamble */
+static int hf_acn_preamble = -1;
+static int hf_acn_preamble_size = -1;
+static int hf_acn_postamble_size = -1;
+static int hf_acn_id = -1;
+
+/* ACN */
 static int hf_acn_pdu = -1;
+static int hf_acn_flags = -1;
+static int hf_acn_flag_length = -1;
+static int hf_acn_flag_vector = -1;
+static int hf_acn_flag_header = -1;
+static int hf_acn_flag_data = -1;
+static int hf_acn_length = -1;
+static int hf_acn_vector = -1;
 
-static int hf_acn_pdu_flags = -1;
+/* RLP */
+static int hf_acn_rlp = -1;
+static int hf_acn_rlp_source_cid = -1;
 
-static int hf_acn_pdu_des = -1;
-static int hf_acn_pdu_src = -1;
-static int hf_acn_pdu_flag_p = -1;
-static int hf_acn_pdu_flag_t = -1;
-static int hf_acn_pdu_flag_res = -1;
-static int hf_acn_pdu_flag_z = -1;
-static int hf_acn_pdu_length = -1;
-
-/* PDU optional */
-static int hf_acn_pdu_ext_length_16 = -1;
-static int hf_acn_pdu_ext_length_32 = -1;
-static int hf_acn_pdu_source_ps = -1;
-static int hf_acn_pdu_source_cid = -1;
-static int hf_acn_pdu_destination_ps = -1;
-static int hf_acn_pdu_destination_cid = -1;
-static int hf_acn_pdu_protocol = -1;
-static int hf_acn_pdu_type = -1;
-static int hf_acn_pdu_type_sdt = -1;
-static int hf_acn_pdu_type_dmp = -1;
-static int hf_acn_pdu_data = -1;
-static int hf_acn_pdu_unknown_data = -1;
-
-static int hf_acn_pdu_padding = -1;
-
 /* SDT */
+static int hf_acn_sdt = -1;
+static int hf_acn_sdt_vector = -1;
 static int hf_acn_sdt_session_nr = -1;
 static int hf_acn_sdt_tot_seq_nr = -1;
 static int hf_acn_sdt_rel_seq_nr = -1;
@@ -185,39 +201,173 @@
 static int hf_acn_sdt_member_cid = -1;
 static int hf_acn_sdt_ack_threshold = -1;
 
-/*
- * Here are the global variables associated with the preferences
- * for acn
- */
+/* DMP */
+static int hf_acn_dmp = -1;
+static int hf_acn_dmp_vector = -1;
+static int hf_acn_dmp_flags = -1;
+static int hf_acn_dmp_virtual = -1;
+static int hf_acn_dmp_relative = -1;
+static int hf_acn_dmp_address_data_type = -1;
+static int hf_acn_dmp_address_size = -1;
+static int hf_acn_dmp_address = -1;
+static int hf_acn_dmp_increment = -1;
+static int hf_acn_dmp_count = -1;
 
-static guint global_udp_port_acn = 0;
-static guint udp_port_acn = 0;
+/* DMX streaming protocol (E1.31) */
+static int hf_acn_dmxsp = -1;
+static int hf_acn_dmxsp_source_name = -1;
+static int hf_acn_dmxsp_priority = -1;
+static int hf_acn_dmxsp_sequence = -1;
+static int hf_acn_dmxsp_universe = -1;
 
-/* A static handle for the ip dissector */
-static dissector_handle_t ip_handle;
+static unsigned 
+dissect_flags_length(tvbuff_t *tvb, unsigned offset, proto_tree *tree,
+	uint8_t *flags)
+{
+	/* Flags */
+	*flags = tvb_get_guint8(tvb, offset);
+	proto_tree *flags_item = proto_tree_add_item(tree, hf_acn_flags,
+			tvb, offset, 1, FALSE);
+	proto_tree *flags_tree = proto_item_add_subtree(flags_item,
+			ett_acn_flags);
+	proto_tree_add_item(flags_tree, hf_acn_flag_length,
+			tvb, offset, 1, FALSE);
+	proto_tree_add_item(flags_tree, hf_acn_flag_vector,
+			tvb, offset, 1, FALSE);
+	proto_tree_add_item(flags_tree, hf_acn_flag_header,
+			tvb, offset, 1, FALSE);
+	proto_tree_add_item(flags_tree, hf_acn_flag_data,
+			tvb, offset, 1, FALSE);
 
-static guint dissect_pdu(tvbuff_t *tvb, guint offset, proto_tree *tree, acn_pdu_history_t* parent_hist, guint max_size);
-static guint dissect_sdt(tvbuff_t *tvb, guint offset, proto_tree *tree, acn_pdu_history_t* parent_hist, guint max_size);
-static guint dissect_dmp(tvbuff_t *tvb, guint offset, proto_tree *tree, acn_pdu_history_t* parent_hist, guint max_size);
+	/* Length */
+	if (*flags & ACN_FLAG_LENGTH) {
+		unsigned length = tvb_get_ntoh24(tvb, offset)
+			& ACN_LENGTH_MASK20;
+		proto_tree_add_uint(tree, hf_acn_length,
+				tvb, offset, 3, length);
+		tvb_set_reported_length(tvb, offset + length);
+		offset += 3;
+	} else {
+		unsigned length = tvb_get_ntohs(tvb, offset)
+			& ACN_LENGTH_MASK;
+		proto_tree_add_uint(tree, hf_acn_length,
+				tvb, offset, 2, length);
+		tvb_set_reported_length(tvb, offset + length);
+		offset += 2;
+	}
 
-static guint 
-dissect_sdt(tvbuff_t *tvb, guint offset, proto_tree *tree, acn_pdu_history_t* parent_hist, guint max_size)
+	return offset;
+}
+
+static unsigned
+dissect_data(tvbuff_t *tvb, unsigned offset,
+		packet_info *pinfo, proto_tree *tree, uint32_t vector);
+
+/* Root layer protocol. */
+static unsigned
+dissect_rlp_header(tvbuff_t *tvb, unsigned offset, proto_tree *tree,
+		proto_tree *rlp)
 {
+	e_guid_t guid;
+	tvb_get_guid(tvb, offset, &guid, FALSE);
+	char buf[GUID_STR_LEN];
+	guid_to_str_buf(&guid, buf, sizeof buf);
+	proto_item_append_text(rlp, ", Src: %s", buf);
+
+	proto_tree_add_item(tree, hf_acn_rlp_source_cid,
+		tvb, offset, 16, FALSE);
+	offset += 16;
+
+	return offset;
+}
+
+static unsigned
+dissect_rlp(tvbuff_t *tvb, unsigned offset,
+		packet_info *pinfo, proto_tree *root)
+{
+	proto_tree *item = proto_tree_add_item(root, hf_acn_rlp,
+			tvb, offset, 0, FALSE);
+	proto_tree *tree = proto_item_add_subtree(item, ett_acn_rlp);
+
+	uint8_t flags;
+	offset = dissect_flags_length(tvb, offset, tree, &flags);
+
+	uint32_t vector = 0;
+	if (flags & ACN_FLAG_VECTOR) {
+		vector = tvb_get_ntohl(tvb, offset);
+		proto_tree_add_item(tree, hf_acn_vector, tvb,
+				offset, 4, FALSE);
+		offset += 4;
+	}
+
+	if (flags & ACN_FLAG_HEADER)
+		offset = dissect_rlp_header(tvb, offset, tree, item);
+
+	proto_item_set_end(item, tvb, offset);
+
+	if (flags & ACN_FLAG_DATA)
+		offset = dissect_data(tvb, offset, pinfo, root, vector);
+
+	return offset;
+}
+
+static unsigned 
+dissect_pdu(tvbuff_t *tvb, unsigned offset, proto_tree *root)
+{
+	proto_tree *item = proto_tree_add_item(root, hf_acn_pdu,
+			tvb, offset, 0, FALSE);
+	proto_tree *tree = proto_item_add_subtree(item, ett_acn_pdu);
+
+	uint8_t flags;
+	offset = dissect_flags_length(tvb, offset, tree, &flags);
+
+	uint32_t vector = 0;
+	if (flags & ACN_FLAG_VECTOR) {
+		vector = tvb_get_ntohs(tvb, offset);
+		proto_tree_add_item(tree, hf_acn_sdt_mid, tvb,
+				offset, 2, FALSE);
+		offset += 2;
+	}
+
+	if (flags & ACN_FLAG_HEADER) {
+		/* xxx todo */
+		offset += 6;
+	}
+
+	proto_item_set_end(item, tvb, offset);
+
+	return offset;
+}
+
+static unsigned 
+dissect_sdt(tvbuff_t *tvb, unsigned offset,
+		packet_info *pinfo, proto_tree *root)
+{
+	(void)pinfo;
+
 	proto_tree *flags_tree, *flags_item;
-	guint start_offset = offset;
-	acn_pdu_history_t hist;
 	guint size = 0;
-	guint flags;
 	guint type;
 	guint count;
+	unsigned max_size = tvb_reported_length_remaining(tvb, offset);
 
-	hist = *parent_hist;
+	proto_tree *item = proto_tree_add_item(root, hf_acn_sdt,
+			tvb, offset, 0, FALSE);
+	proto_tree *tree = proto_item_add_subtree(item, ett_acn_sdt);
 
-	switch( parent_hist->type )
-	{
-		case ACN_SDT_TYPE_UNKNOWN:
-			break;
+	unsigned start_offset = offset;
+	uint8_t flags;
+	offset = dissect_flags_length(tvb, offset, tree, &flags);
 
+	uint8_t vector = 0;
+	if (flags & ACN_FLAG_VECTOR) {
+		vector = tvb_get_guint8(tvb, offset);
+		proto_tree_add_item(tree, hf_acn_sdt_vector, tvb,
+				offset, 1, FALSE);
+		offset++;
+	}
+
+	switch (vector) {
 		case ACN_SDT_TYPE_RELSEQDATA:
 		case ACN_SDT_TYPE_UNRELSEQDATA:
 			proto_tree_add_item(tree, hf_acn_sdt_session_nr, tvb,
@@ -238,7 +388,7 @@
 
 			max_size = max_size - (offset - start_offset);
 			while( max_size >= ACN_PDU_MIN_SIZE) {
-				size = dissect_pdu( tvb, offset, tree, &hist, max_size);
+				size = dissect_pdu(tvb, offset, tree);
 				offset += size;
 				max_size -= size;
 			}
@@ -254,7 +404,7 @@
 
 			max_size = max_size - (offset - start_offset);
 			while( max_size >= ACN_PDU_MIN_SIZE) {
-				size = dissect_pdu( tvb, offset, tree, &hist, max_size);
+				size = dissect_pdu(tvb, offset, tree);
 				offset += size;
 				max_size -= size;
 			}
@@ -272,7 +422,7 @@
 			flags_item = proto_tree_add_uint(tree, hf_acn_sdt_flags, tvb,
 							offset, 1, flags);
 
-			flags_tree=proto_item_add_subtree(flags_item, ett_acn);
+			flags_tree=proto_item_add_subtree(flags_item, ett_acn_sdt);
 			proto_tree_add_item(flags_tree, hf_acn_sdt_flag_u, tvb, offset, 1, FALSE);
 			proto_tree_add_item(flags_tree, hf_acn_sdt_flag_d, tvb, offset, 1, FALSE);
 			proto_tree_add_item(flags_tree, hf_acn_sdt_flag_l, tvb, offset, 1, FALSE);
@@ -316,7 +466,7 @@
 			flags_item = proto_tree_add_uint(tree, hf_acn_sdt_flags, tvb,
 							offset, 1, flags);
 
-			flags_tree=proto_item_add_subtree(flags_item, ett_acn);
+			flags_tree=proto_item_add_subtree(flags_item, ett_acn_sdt);
 			offset += 1;
 
 			type = tvb_get_guint8(tvb, offset);
@@ -400,7 +550,7 @@
 			flags_item = proto_tree_add_uint(tree, hf_acn_sdt_flags, tvb,
 							offset, 1, flags);
 
-			flags_tree=proto_item_add_subtree(flags_item, ett_acn);
+			flags_tree=proto_item_add_subtree(flags_item, ett_acn_sdt);
 			proto_tree_add_item(flags_tree, hf_acn_sdt_flag_u, tvb, offset, 1, FALSE);
 			proto_tree_add_item(flags_tree, hf_acn_sdt_flag_d, tvb, offset, 1, FALSE);
 			proto_tree_add_item(flags_tree, hf_acn_sdt_flag_l, tvb, offset, 1, FALSE);
@@ -443,7 +593,7 @@
 			flags_item = proto_tree_add_uint(tree, hf_acn_sdt_flags, tvb,
 							offset, 1, flags);
 
-			flags_tree=proto_item_add_subtree(flags_item, ett_acn);
+			flags_tree=proto_item_add_subtree(flags_item, ett_acn_sdt);
 			offset += 1;
 
 			type = tvb_get_guint8(tvb, offset);
@@ -644,355 +794,316 @@
 			break;
 	}
 	
-	return size;
+	return offset;
 }
 
-static guint 
-dissect_dmp(tvbuff_t *tvb _U_, guint offset _U_, proto_tree *tree _U_, acn_pdu_history_t* parent_hist _U_, guint max_size _U_)
+static unsigned 
+dissect_dmp_header(tvbuff_t *tvb, unsigned offset, proto_tree *tree,
+		proto_tree *dmp)
 {
-	return 0;
+	uint8_t flags = tvb_get_guint8(tvb, offset);
+
+	proto_tree *flags_item = proto_tree_add_item(tree, hf_acn_dmp_flags,
+			tvb, offset, 1, FALSE);
+	proto_tree *flags_tree = proto_item_add_subtree(flags_item,
+			ett_acn_dmp_flags);
+	proto_tree_add_item(flags_tree, hf_acn_dmp_virtual,
+			tvb, offset, 1, FALSE);
+	proto_tree_add_item(flags_tree, hf_acn_dmp_relative,
+			tvb, offset, 1, FALSE);
+	proto_tree_add_item(flags_tree, hf_acn_dmp_address_data_type,
+			tvb, offset, 1, FALSE);
+	proto_tree_add_item(flags_tree, hf_acn_dmp_address_size,
+			tvb, offset, 1, FALSE);
+	offset++;
+
+	unsigned address_size = 0, address = 0, count = 0;
+	switch (flags & DMP_ADDRESS_SIZE) {
+		case DMP_ADDRESS_SIZE_1:
+			address_size = 1;
+			address = tvb_get_guint8(tvb, offset);
+			count = tvb_get_guint8(tvb, offset + 2 * address_size);
+			break;
+		case DMP_ADDRESS_SIZE_2:
+			address_size = 2;
+			address = tvb_get_ntohs(tvb, offset);
+			count = tvb_get_ntohs(tvb, offset + 2 * address_size);
+			break;
+		case DMP_ADDRESS_SIZE_4:
+			address_size = 4;
+			address = tvb_get_ntohl(tvb, offset);
+			count = tvb_get_ntohl(tvb, offset + 2 * address_size);
+			break;
+	}
+	proto_item_append_text(dmp, ", Address: %d, Count %d",
+			address, count);
+
+	proto_tree_add_item(tree, hf_acn_dmp_address,
+			tvb, offset, address_size, FALSE);
+	offset += address_size;
+
+	proto_tree_add_item(tree, hf_acn_dmp_increment,
+			tvb, offset, address_size, FALSE);
+	offset += address_size;
+
+	proto_tree_add_item(tree, hf_acn_dmp_count,
+			tvb, offset, address_size, FALSE);
+	offset += address_size;
+
+	return offset;
 }
 
-static guint 
-dissect_pdu(tvbuff_t *tvb, guint offset, proto_tree *tree, acn_pdu_history_t* parent_hist, guint max_size)
+static unsigned 
+dissect_dmp(tvbuff_t *tvb, unsigned offset,
+		packet_info *pinfo, proto_tree *root)
 {
-	guint size,data_size;
-	guint8 flags;
-	guint src,des;
-	proto_tree *ti, *si, *flags_tree, *flags_item, *data_tree, *data_item;
-	guint start_offset = offset;
-	acn_pdu_history_t hist = *parent_hist;
-	
+	(void)pinfo;
 
-	ti = proto_tree_add_item(tree,
-				hf_acn_pdu,
-				tvb,
-				offset,
-				0,
-				FALSE);
- 
-	si = proto_item_add_subtree(ti, ett_acn);
- 
-	flags = tvb_get_guint8(tvb, offset);
-	flags_item = proto_tree_add_uint(si, hf_acn_pdu_flags, tvb,
-					offset, 1, flags);
+	proto_tree *item = proto_tree_add_item(root, hf_acn_dmp,
+			tvb, offset, 0, FALSE);
+	proto_tree *tree = proto_item_add_subtree(item, ett_acn_dmp);
 
-	flags_tree=proto_item_add_subtree(flags_item, ett_acn);
-	
-	proto_tree_add_item(flags_tree, hf_acn_pdu_des, tvb, offset, 1, FALSE);
-	proto_tree_add_item(flags_tree, hf_acn_pdu_src, tvb, offset, 1, FALSE);
-	proto_tree_add_item(flags_tree, hf_acn_pdu_flag_p, tvb, offset, 1, FALSE);
-	proto_tree_add_item(flags_tree, hf_acn_pdu_flag_t, tvb, offset, 1, FALSE);
-	proto_tree_add_item(flags_tree, hf_acn_pdu_flag_res, tvb, offset, 1, FALSE);
-	proto_tree_add_item(flags_tree, hf_acn_pdu_flag_z, tvb, offset, 1, FALSE);
+	uint8_t flags;
+	offset = dissect_flags_length(tvb, offset, tree, &flags);
 
-	offset += 1;
+	uint8_t vector = 0;
+	if (flags & ACN_FLAG_VECTOR) {
+		vector = tvb_get_guint8(tvb, offset);
+		proto_tree_add_item(tree, hf_acn_dmp_vector, tvb,
+				offset, 1, FALSE);
+		offset++;
+	}
 
-	size = tvb_get_guint8(tvb, offset);	
-	proto_tree_add_uint(si, hf_acn_pdu_length, tvb,
-	                          offset, 1, size);
-	offset += 1;
-	
+	if (flags & ACN_FLAG_HEADER)
+		offset = dissect_dmp_header(tvb, offset, tree, item);
 
-	if( size == 0 ){
-		size = tvb_get_ntohs(tvb, offset);
-		proto_tree_add_uint(si, hf_acn_pdu_ext_length_16, tvb,
-					offset, 2, size);	
-		offset += 2;	
-	} else if( size == 1 ){
-		size = tvb_get_ntohl( tvb, offset);
-		proto_tree_add_uint(si, hf_acn_pdu_ext_length_32, tvb,
-					offset, 4, size);	
-		offset += 4;
-	}
-	
-	if(size > max_size )
-		size = max_size;
+	proto_item_set_end(item, tvb, offset);
 
-	switch( flags & ACN_PDU_DES )
-	{	
-		case ACN_PDU_DES_SAME:
-			break;
-			
-		case ACN_PDU_DES_PS:
-			hist.destination_type = ACN_PDU_DES_PS;
-			des = tvb_get_ntohs(tvb, offset);
-			hist.destination.ps = des;
-			proto_tree_add_uint(si, hf_acn_pdu_destination_ps, tvb,
-						offset, 2, des);	
-			offset += 2;
-			break;
-			
-		case ACN_PDU_DES_CID:
-			hist.destination_type = ACN_PDU_DES_CID;
-			tvb_memcpy(tvb, hist.destination.cid, offset, 16 );
-			proto_tree_add_item(si, hf_acn_pdu_destination_cid, tvb,
-						offset, 16, FALSE);
-			offset += 16;
-			break;
-			
-		case ACN_PDU_DES_ALL:
-			hist.destination_type = ACN_PDU_DES_ALL;
-			break;	
-	} 
+	return offset;
+}
 
+/* DMX streaming protocol (E1.31) */
+static unsigned
+dissect_dmxsp_header(tvbuff_t *tvb, unsigned offset,
+		packet_info *pinfo, proto_tree *tree,
+		proto_tree *dmxsp)
+{
+	if (check_col(pinfo->cinfo, COL_INFO))
+		col_set_str(pinfo->cinfo, COL_INFO, "DMX streaming protocol");
 
-	switch( flags & ACN_PDU_SRC )
-	{
-		case ACN_PDU_SRC_SAME:
-			break;
-			
-		case ACN_PDU_SRC_PS:
-			hist.source_type = ACN_PDU_SRC_PS;
-			src = tvb_get_ntohs(tvb, offset);
-			hist.source.ps = src;
-			proto_tree_add_uint(si, hf_acn_pdu_source_ps, tvb,
-						offset, 2, src);
-			offset += 2;
-			break;
-			
-		case ACN_PDU_SRC_CID:
-			hist.source_type = ACN_PDU_SRC_CID;
-			tvb_memcpy(tvb, hist.source.cid, offset, 16 );
-			proto_tree_add_item(si, hf_acn_pdu_source_cid, tvb,
-						offset, 16, FALSE);
-			offset += 16;
-			break;
-			
-		case ACN_PDU_SRC_UM:
-			hist.source_type = ACN_PDU_SRC_UM;
-			break;	
-	} 
+	proto_tree_add_item(tree, hf_acn_dmxsp_source_name,
+			tvb, offset, 32, FALSE);
+	offset += 32;
 
+	uint8_t priority = tvb_get_guint8(tvb, offset);
+	proto_tree_add_item(tree, hf_acn_dmxsp_priority,
+			tvb, offset, 1, FALSE);
+	offset++;
 
+	proto_tree_add_item(tree, hf_acn_dmxsp_sequence,
+			tvb, offset, 1, FALSE);
+	offset++;
 
-	if( flags & ACN_PDU_FLAG_P )
-	{
-		hist.protocol = tvb_get_ntohs( tvb, offset );
-		proto_tree_add_item(si, hf_acn_pdu_protocol, tvb,
-					offset, 2, FALSE );
-		offset += 2;
-	}
+	uint16_t universe = tvb_get_ntohs(tvb, offset);
+	proto_item_append_text(dmxsp, ", Universe: %d, Priority: %d",
+			universe, priority);
 
-	if( flags & ACN_PDU_FLAG_T )
-	{
-		hist.type = tvb_get_ntohs( tvb, offset );
-	
-		switch( hist.protocol ) { 
-			case ACN_PDU_PROTO_SDT:
-				proto_tree_add_item(si, hf_acn_pdu_type_sdt, tvb,
-						offset, 2, FALSE );
-				break;
+	proto_tree_add_item(tree, hf_acn_dmxsp_universe,
+			tvb, offset, 2, FALSE);
+	offset += 2;
 
-			case ACN_PDU_PROTO_DMP:
-				proto_tree_add_item(si, hf_acn_pdu_type_dmp, tvb,
-						offset, 2, FALSE );
-				break;
-				
-			default:
-				proto_tree_add_item(si, hf_acn_pdu_type, tvb,
-						offset, 2, FALSE );
-				break;	
-	
-	
-	
-		}
-		
-		offset += 2;
+	return offset;
+}
+
+static unsigned
+dissect_dmxsp(tvbuff_t *tvb, unsigned offset,
+		packet_info *pinfo, proto_tree *root)
+{
+	proto_tree *item = proto_tree_add_item(root, hf_acn_dmxsp,
+			tvb, offset, 0, FALSE);
+	proto_tree *tree = proto_item_add_subtree(item, ett_acn_dmxsp);
+
+	uint8_t flags;
+	offset = dissect_flags_length(tvb, offset, tree, &flags);
+
+	uint32_t vector = 0;
+	if (flags & ACN_FLAG_VECTOR) {
+		vector = tvb_get_ntohl(tvb, offset);
+		proto_tree_add_item(tree, hf_acn_vector, tvb,
+				offset, 4, FALSE);
+		offset += 4;
 	}
 
-	if( flags & ACN_PDU_FLAG_Z )
-	{
-		data_size = size - (offset - start_offset);
+	if (flags & ACN_FLAG_HEADER)
+		offset = dissect_dmxsp_header(tvb, offset, pinfo, tree,
+			item);
 
+	proto_item_set_end(item, tvb, offset);
 
-		data_item = proto_tree_add_item(si, hf_acn_pdu_data, tvb,
-						offset, data_size, FALSE);
+	if (flags & ACN_FLAG_DATA)
+		offset = dissect_data(tvb, offset, pinfo, root, vector);
 
-		data_tree=proto_item_add_subtree(data_item, ett_acn);
+	return offset;
+}
 
+static unsigned
+dissect_unknown(tvbuff_t *tvb, unsigned offset,
+		packet_info *pinfo, proto_tree *tree)
+{
+	(void)tvb; (void)offset; (void)tree;
+	if (check_col(pinfo->cinfo, COL_INFO))
+		col_set_str(pinfo->cinfo, COL_INFO, "Unknown PDU");
+	return 0;
+}
 
-		switch( hist.protocol ) {
-			case ACN_PDU_PROTO_SDT:
-				dissect_sdt( tvb, offset, data_tree, &hist, data_size);
-				break;
-			
-			case ACN_PDU_PROTO_DMP:
-				dissect_dmp( tvb, offset, data_tree, &hist, data_size);	
-				break;
-	
-			default:
-				proto_tree_add_item(si, hf_acn_pdu_unknown_data, tvb,
-							offset, data_size, FALSE );
-				break;	
-		}
+static unsigned
+dissect_data(tvbuff_t *tvb, unsigned offset,
+		packet_info *pinfo, proto_tree *tree, uint32_t vector)
+{
+	return (vector == ACN_VECTOR_SDT ? dissect_sdt :
+			vector == ACN_VECTOR_DMP ? dissect_dmp :
+			vector == ACN_VECTOR_DMXSP ? dissect_dmxsp :
+			dissect_unknown)(tvb, offset, pinfo, tree);
+}
 
-		offset += data_size;
-	}
+static unsigned dissect_preamble(tvbuff_t *tvb, unsigned offset,
+		proto_tree *tree)
+{
+	uint16_t preamble_size = tvb_get_ntohs(tvb, offset);
+	unsigned id_size = preamble_size - 4;
 
-	if( size & 0x00000001 )
-	{
-	
-		proto_tree_add_item(si, hf_acn_pdu_padding, tvb,
-					offset, 1, TRUE );
-		
-		size += 1;
-		offset += 1;
-	}
+	proto_tree *item = proto_tree_add_item(tree, hf_acn_preamble,
+			tvb, offset, preamble_size, FALSE);
+	proto_tree *subtree = proto_item_add_subtree(item,
+			ett_acn_preamble);
 
-	proto_item_set_len(si, size);
+	proto_tree_add_item(subtree, hf_acn_preamble_size,
+			tvb, offset, 2, FALSE);
+	offset += 2;
+	proto_tree_add_item(subtree, hf_acn_postamble_size,
+			tvb, offset, 2, FALSE);
+	offset += 2;
+	proto_tree_add_item(subtree, hf_acn_id,
+			tvb, offset, id_size, FALSE);
+	offset += id_size;
 
-	return size;
+	return offset;
 }
 
-static void
-dissect_acn(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
-	gint offset = 0;
-	guint size,max_size;
-	acn_pdu_history_t hist;
+static int
+dissect_acn(tvbuff_t *tvb, packet_info *pinfo, proto_tree *root)
+{
+	const uint8_t id[12] = "ASC-E1.17";
+	if (tvb_memeql(tvb, 4, id, sizeof id) != 0)
+		return 0;
 
-	/* Set the protocol column */
-	if(check_col(pinfo->cinfo,COL_PROTOCOL)){
-		col_set_str(pinfo->cinfo,COL_PROTOCOL,"ACN");
-	}
+	if (check_col(pinfo->cinfo, COL_PROTOCOL))
+		col_set_str(pinfo->cinfo, COL_PROTOCOL, "ACN");
+	if (check_col(pinfo->cinfo, COL_INFO))
+		col_clear(pinfo->cinfo, COL_INFO);
 
-	/* Clear out stuff in the info column */
-	if(check_col(pinfo->cinfo,COL_INFO)){
-		col_clear(pinfo->cinfo,COL_INFO);
-	}
+	if (root != NULL) {
+		unsigned offset = 0;
+		proto_tree *item = proto_tree_add_item(root, proto_acn,
+				tvb, offset, -1, FALSE);
+		proto_tree *tree = proto_item_add_subtree(item,
+				ett_acn);
 
-	if (tree) 
-	{
-		/* history default values */
-		hist.destination_type = ACN_PDU_DES_ALL; 
-		hist.source_type = ACN_PDU_SRC_UM;
-		hist.protocol = ACN_PDU_PROTO_UNKNOWN;
-		hist.type = ACN_PDU_TYPE_UNKNOWN;
-		
-		max_size = tvb_reported_length_remaining(tvb, offset);
-		
-		while( max_size >= ACN_PDU_MIN_SIZE) {
-			size = dissect_pdu( tvb, offset, tree, &hist, max_size);
-			offset += size;
-			max_size -= size;
-		}
+		offset = dissect_preamble(tvb, offset, tree);
+		offset = dissect_rlp(tvb, offset, pinfo, tree);
+
+		proto_item_set_end(item, tvb, offset);
+
+		tvbuff_t *next_tvb = tvb_new_subset(tvb,
+				offset, -1, -1);
+		call_dissector(data_handle, next_tvb, pinfo, root);
+		return offset;
 	}
+	return tvb_length(tvb);
 }
 
 void
-proto_register_acn(void) {
+proto_register_acn(void)
+{
   static hf_register_info hf[] = {
+	/* Preamble */
+	{ &hf_acn_preamble,
+	    { "Preamble", "acn.preamble",
+		FT_NONE, BASE_NONE, NULL, 0,
+		NULL, HFILL }},
+	{ &hf_acn_preamble_size,
+	    { "Preamble size", "acn.preamble_size",
+		FT_UINT16, BASE_DEC, NULL, 0,
+		NULL, HFILL }},
+	{ &hf_acn_postamble_size,
+	    { "Postamble size", "acn.postamble_size",
+		FT_UINT16, BASE_DEC, NULL, 0,
+		NULL, HFILL }},
+	{ &hf_acn_id,
+	    { "Packet identififer", "acn.id",
+		FT_STRING, BASE_NONE, NULL, 0,
+		NULL, HFILL }},
+
 	/* PDU */
 	{ &hf_acn_pdu,
-	    { "ACN PDU", "acn.pdu",
+	    { "PDU", "acn.pdu",
 		FT_NONE, BASE_NONE, NULL, 0,
-		"ACN PDU", HFILL }},
+		NULL, HFILL }},
 
-	{ &hf_acn_pdu_flags,
-	    { "Flags","acn.pdu.flags",
-		FT_UINT8, BASE_HEX, NULL, 0x0,
+	{ &hf_acn_flags,
+	    { "Flags", "acn.flags",
+		FT_UINT8, BASE_HEX, NULL, ACN_FLAG_MASK,
 		"Flags", HFILL }},
 
-	{ &hf_acn_pdu_des,
-	    { "des","acn.pdu.des",
-		FT_UINT8, BASE_HEX, VALS( acn_sdt_des_flag_vals ), 0xC0,
-		"des", HFILL }},
+	{ &hf_acn_flag_length,
+	    { "Length", "acn.flag_length",
+		FT_UINT8, BASE_DEC, NULL, ACN_FLAG_LENGTH,
+		NULL, HFILL }},
 
-	{ &hf_acn_pdu_src,
-	    { "src","acn.pdu.src",
-		FT_UINT8, BASE_HEX, VALS( acn_sdt_src_flag_vals ), 0x30,
-		"src", HFILL }},
+	{ &hf_acn_flag_vector,
+	    { "Vector", "acn.flag_vector",
+		FT_UINT8, BASE_DEC, NULL, ACN_FLAG_VECTOR,
+		NULL, HFILL }},
 
-	{ &hf_acn_pdu_flag_p,
-	    { "P","acn.pdu.flag_p",
-		FT_UINT8, BASE_HEX, NULL, 0x08,
-		"P", HFILL }},
+	{ &hf_acn_flag_header,
+	    { "Header", "acn.flag_header",
+		FT_UINT8, BASE_DEC, NULL, ACN_FLAG_HEADER,
+		NULL, HFILL }},
 
-	{ &hf_acn_pdu_flag_t,
-	    { "T","acn.pdu.flag_t",
-		FT_UINT8, BASE_HEX, NULL, 0x04,
-		"T", HFILL }},
+	{ &hf_acn_flag_data,
+	    { "Data", "acn.flag_data",
+		FT_UINT8, BASE_DEC, NULL, ACN_FLAG_DATA,
+		NULL, HFILL }},
 
-	{ &hf_acn_pdu_flag_z,
-	    { "Z","acn.pdu.flag_z",
-		FT_UINT8, BASE_HEX, NULL, 0x01,
-		"Z", HFILL }},
-
-	{ &hf_acn_pdu_flag_res,
-	    { "res","acn.pdu.flag_res",
-		FT_UINT8, BASE_HEX, NULL, 0x02,
-		"res", HFILL }},
-
-	{ &hf_acn_pdu_length,
-	    { "Length","acn.pdu.length",
-		FT_UINT8, BASE_DEC, NULL, 0x0,
+	{ &hf_acn_length,
+	    { "Length", "acn.length",
+		FT_UINT16, BASE_DEC, NULL, 0,
 		"Length", HFILL }},
 
-	{ &hf_acn_pdu_ext_length_16,
-	    { "Ext Length 16bit","acn.pdu.ext_length_16",
-		FT_UINT16, BASE_DEC, NULL, 0x0,
-		"Ext Length 16bit", HFILL }},
+	{ &hf_acn_vector,
+	    { "Vector", "acn.vector",
+		FT_UINT32, BASE_DEC, VALS(acn_vector_vals), 0x0,
+		NULL, HFILL }},
 
-	{ &hf_acn_pdu_ext_length_32,
-	    { "Ext Length 32bit","acn.pdu.ext_length_32",
-		FT_UINT32, BASE_DEC, NULL, 0x0,
-		"Ext Length 32bit", HFILL }},
+	/* RLP */
+	{ &hf_acn_rlp,
+	    { "Root level protocol", "acn.rlp",
+		FT_NONE, BASE_NONE, NULL, 0,
+		NULL, HFILL }},
+	{ &hf_acn_rlp_source_cid,
+	    { "Source CID", "acn.rlp.source_cid",
+		FT_GUID, BASE_NONE, NULL, 0,
+		NULL, HFILL }},
 
-	{ &hf_acn_pdu_source_ps,
-	    { "Source PS","acn.pdu.source_ps",
-		FT_UINT16, BASE_HEX, NULL, 0x0,
-		"Source PS", HFILL }},
-
-	{ &hf_acn_pdu_source_cid,
-	    { "Source CID","acn.pdu.source_cid",
-		FT_BYTES, BASE_HEX, NULL, 0x0,
-		"Source CID", HFILL }},
-
-	{ &hf_acn_pdu_destination_ps,
-	    { "Destination PS","acn.pdu.destination_ps",
-		FT_UINT16, BASE_HEX, NULL, 0x0,
-		"Destination PS", HFILL }},
-
-	{ &hf_acn_pdu_destination_cid,
-	    { "Destination CID","acn.pdu.destination_cid",
-		FT_BYTES, BASE_HEX, NULL, 0x0,
-		"Destination CID", HFILL }},
-
-	{ &hf_acn_pdu_protocol,
-	    { "Protocol","acn.pdu.protocol",
-		FT_UINT16, BASE_HEX, VALS(acn_proto_vals), 0x0,
-		"Protocol", HFILL }},
-
-	{ &hf_acn_pdu_type,
-	    { "Type","acn.pdu.type",
-		FT_UINT16, BASE_HEX, NULL, 0x0,
-		"Type", HFILL }},
-
-	{ &hf_acn_pdu_type_sdt,
-	    { "SDT Type","acn.pdu.type_sdt",
-		FT_UINT16, BASE_HEX, VALS(acn_sdt_type_vals), 0x0,
+	/* SDT */
+	{ &hf_acn_sdt,
+	    { "Session data transport", "acn.sdt",
+		FT_NONE, BASE_NONE, NULL, 0,
+		NULL, HFILL }},
+	{ &hf_acn_sdt_vector,
+	    { "SDT vector", "acn.sdt.vector",
+		FT_UINT8, BASE_DEC, VALS(acn_sdt_type_vals), 0x0,
 		"SDT Type", HFILL }},
-
-	{ &hf_acn_pdu_type_dmp,
-	    { "DMP Type","acn.pdu.type_dmp",
-		FT_UINT16, BASE_HEX, VALS(acn_dmp_type_vals), 0x0,
-		"DMP Type", HFILL }},
-		
-	{ &hf_acn_pdu_data,
-	    { "Data","acn.pdu.data",
-		FT_NONE, BASE_HEX, NULL, 0x0,
-		"Data", HFILL }},
-
-	{ &hf_acn_pdu_unknown_data,
-	    { "Unknown Data","acn.pdu.unknown_data",
-		FT_BYTES, BASE_HEX, NULL, 0x0,
-		"Unknown Data", HFILL }},
-
-	{ &hf_acn_pdu_padding,
-	    { "Padding","acn.pdu.padding",
-		FT_UINT8, BASE_DEC, NULL, 0x0,
-		"Padding", HFILL }},
-
 	{ &hf_acn_sdt_session_nr,
 	    { "SDT Session Nr","acn.sdt.session_nr",
 		FT_UINT16, BASE_DEC, NULL, 0x0,
@@ -1136,50 +1247,102 @@
 	{ &hf_acn_sdt_leader_cid,
 	    { "SDT Leader CID","acn.sdt.leader_cid",
 		FT_BYTES, BASE_HEX, NULL, 0x0,
-		"SDT Leader CID", HFILL }}
+		"SDT Leader CID", HFILL }},
 
+	/* DMP */
+	{ &hf_acn_dmp,
+	    { "Device management protocol", "acn.dmp",
+		FT_NONE, BASE_NONE, NULL, 0,
+		NULL, HFILL }},
+	{ &hf_acn_dmp_vector,
+	    { "Vector", "acn.dmp.vector",
+		FT_UINT8, BASE_DEC, VALS(acn_dmp_vector_vals), 0,
+		NULL, HFILL }},
+	{ &hf_acn_dmp_flags,
+	    { "Flags", "acn.dmp.flags",
+		FT_UINT8, BASE_HEX, NULL, 0,
+		NULL, HFILL }},
+	{ &hf_acn_dmp_virtual,
+	    { "Virtual address", "acn.dmp.virtual",
+		FT_UINT8, BASE_DEC, NULL, DMP_VIRTUAL,
+		NULL, HFILL }},
+	{ &hf_acn_dmp_relative,
+	    { "Relative address", "acn.dmp.relative",
+		FT_UINT8, BASE_DEC, NULL, DMP_RELATIVE,
+		NULL, HFILL }},
+	{ &hf_acn_dmp_address_data_type,
+	    { "Address and data type", "acn.dmp.address_data_type",
+		FT_UINT8, BASE_DEC, VALS(acn_dmp_address_data_type_vals),
+		DMP_ADDRESS_DATA_TYPE,
+		NULL, HFILL }},
+	{ &hf_acn_dmp_address_size,
+	    { "Address size", "acn.dmp.address_size",
+		FT_UINT8, BASE_DEC, VALS(acn_dmp_address_size_vals),
+		DMP_ADDRESS_SIZE,
+		NULL, HFILL }},
+	{ &hf_acn_dmp_address,
+	    { "Address", "acn.dmp.address",
+		FT_UINT16, BASE_DEC, NULL, 0,
+		NULL, HFILL }},
+	{ &hf_acn_dmp_increment,
+	    { "Increment", "acn.dmp.increment",
+		FT_UINT16, BASE_DEC, NULL, 0,
+		NULL, HFILL }},
+	{ &hf_acn_dmp_count,
+	    { "Count", "acn.dmp.count",
+		FT_UINT16, BASE_DEC, NULL, 0,
+		NULL, HFILL }},
+		
+	/* DMX streaming protocol (E1.31) */
+	{ &hf_acn_dmxsp,
+	    { "DMX streaming protocol", "acn.dmxsp",
+		FT_NONE, BASE_NONE, NULL, 0,
+		NULL, HFILL }},
+	{ &hf_acn_dmxsp_source_name,
+		{ "Source name", "acn.dmxsp.source_name",
+		FT_STRING, BASE_NONE, NULL, 0,
+		NULL, HFILL }},
+
+	{ &hf_acn_dmxsp_priority,
+		{ "Priority", "acn.dmxsp.priority",
+		FT_UINT8, BASE_DEC, NULL, 0,
+		NULL, HFILL }},
+
+	{ &hf_acn_dmxsp_sequence,
+		{ "Sequence", "acn.dmxsp.seq",
+		FT_UINT8, BASE_DEC, NULL, 0,
+		NULL, HFILL }},
+
+	{ &hf_acn_dmxsp_universe,
+		{ "Universe", "acn.dmxsp.universe",
+		FT_UINT16, BASE_DEC, NULL, 0,
+		NULL, HFILL }},
   };
 
   static gint *ett[] = {
-    &ett_acn,
+		&ett_acn,
+		&ett_acn_preamble,
+		&ett_acn_flags,
+		&ett_acn_rlp,
+		&ett_acn_sdt,
+		&ett_acn_dmp,
+		&ett_acn_dmp_flags,
+		&ett_acn_dmxsp,
+		&ett_acn_pdu,
   };
 
-  module_t *acn_module;
-
-  proto_acn = proto_register_protocol("ACN",
-				      "ACN","acn");
-  proto_register_field_array(proto_acn,hf,array_length(hf));
-  proto_register_subtree_array(ett,array_length(ett));
-
-  acn_module = prefs_register_protocol(proto_acn,
-				       proto_reg_handoff_acn);
-#if 0
-  prefs_register_uint_preference(artnet_module, "udp_port",
-				 "ARTNET UDP Port",
-				 "The UDP port on which "
-				 "Art-Net "
-				 "packets will be sent",
-				 10,&global_udp_port_artnet);
-#endif
+  proto_acn = proto_register_protocol(
+			"Architecture for Control Network", "ACN", "acn");
+  proto_register_field_array(proto_acn, hf, array_length(hf));
+  proto_register_subtree_array(ett, array_length(ett));
 }
 
-/* The registration hand-off routing */
-
 void
-proto_reg_handoff_acn(void) {
-  static int acn_initialized = FALSE;
-  static dissector_handle_t acn_handle;
+proto_reg_handoff_acn(void)
+{
+	static dissector_handle_t acn_handle;
 
-  ip_handle = find_dissector("ip");
-
-  if(!acn_initialized) {
-    acn_handle = create_dissector_handle(dissect_acn,proto_acn);
-    acn_initialized = TRUE;
-  } else {
-    dissector_delete("udp.port",udp_port_acn,acn_handle);
-  }
-
-  udp_port_acn = global_udp_port_acn;
-  
-  dissector_add("udp.port",global_udp_port_acn,acn_handle);
+	acn_handle = new_create_dissector_handle(dissect_acn, proto_acn);
+	data_handle = find_dissector("data");
+	dissector_add("udp.port", IPPORT_ACN, acn_handle);
 }