Bitfields are bad - the C language spec does *NOT* guarantee which bits
[obnox/wireshark/wip.git] / epan / dissectors / packet-acn.c
1 /* packet-acn.c
2  * Routines for ACN packet disassembly
3  *
4  * $Id$
5  *
6  * Copyright (c) 2003 by Erwin Rol <erwin@erwinrol.com>
7  * Copyright (c) 2006 by Electronic Theatre Controls, Inc.
8  *                    Bill Florac <bflorac@etcconnect.com>
9  *
10  * Wireshark - Network traffic analyzer
11  * By Gerald Combs <gerald@wireshark.org>
12  * Copyright 1999 Gerald Combs
13  *
14  * This program is free software; you can redistribute it and/or
15  * modify it under the terms of the GNU General Public License
16  * as published by the Free Software Foundation; either version 2
17  * of the License, or (at your option) any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with this program; if not, write to the Free Software
26  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
27  */
28
29  /*
30     Todo: 
31       Add reading of DDL files so we can futher explode DMP packets
32       For some of the Set/Get properties where we have a range of data
33       it would be better to show the block of data rather and
34       address-data pair on each line...
35
36     Version: 0.0.9   wrf 10-25-2006 Released to Wireshark community
37     Version: 0.0.10  wrf 10-25-2006 small revisions to submit...
38     Version: 0.0.11  wrf 10-29-2006 revisions to submit...
39  */
40
41 /* Include files */
42
43 #ifdef HAVE_CONFIG_H
44 #include "config.h"
45 #endif
46
47 #include <gmodule.h>
48
49 #include <epan/packet.h>
50 #include <epan/prefs.h>
51 #include <epan/emem.h>
52 #include <epan/packet.h>
53 #include <epan/ipv6-utils.h>
54 #include <string.h>
55
56 #include "packet-acn.h"
57
58 /*
59  * See
60  * ANSI BSR E1.17 Architecture for Control Networks
61  * ANSI BSR E1.31
62  */
63
64 #define ACTUAL_ADDRESS  0                                                          
65 /* forward reference */
66 static gboolean dissect_acn_heur( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree );
67 static guint32 acn_add_channel_owner_info_block(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree _U_, int offset);
68 static guint32 acn_add_channel_member_info_block(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree _U_, int offset);
69 static guint32 acn_add_expiry(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, const char *label);
70 static guint32 acn_add_channel_parameter(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset);
71 static guint32 acn_add_address(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, const char *label);
72 static guint32 acn_add_dmp_address_type(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, acn_dmp_adt_type *adt);
73 static guint32 acn_add_dmp_address(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, acn_dmp_adt_type *adt);
74 static guint32 dissect_acn_dmp_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, acn_pdu_offsets *last_pdu_offsets);
75 static guint32 dissect_acn_sdt_wrapped_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree _U_, int offset, acn_pdu_offsets *last_pdu_offsets);
76 static guint32 dissect_acn_sdt_client_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, acn_pdu_offsets *last_pdu_offsets);
77 static guint32 dissect_acn_dmx_data_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, acn_pdu_offsets *last_pdu_offsets);
78 static guint32 dissect_acn_dmx_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, acn_pdu_offsets *last_pdu_offsets);
79 static guint32 dissect_acn_sdt_base_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, acn_pdu_offsets *last_pdu_offsets);
80 static guint32 dissect_acn_root_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, acn_pdu_offsets *last_pdu_offsets);
81 static int dissect_acn(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
82 static gboolean is_acn(tvbuff_t *tvb);
83 void proto_register_acn(void);
84 void proto_reg_handoff_acn(void);
85
86 /* Global variables */
87 static int proto_acn = -1;
88 static gint ett_acn = -1;
89 static gint ett_acn_channel_owner_info_block = -1;
90 static gint ett_acn_channel_member_info_block = -1;
91 static gint ett_acn_channel_parameter = -1;
92 static gint ett_acn_address = -1;
93 static gint ett_acn_address_type = -1;
94 static gint ett_acn_pdu_flags = -1;
95 static gint ett_acn_dmp_pdu = -1;
96 static gint ett_acn_sdt_pdu = -1;
97 static gint ett_acn_sdt_client_pdu = -1;
98 static gint ett_acn_sdt_base_pdu = -1;
99 static gint ett_acn_root_pdu = -1;
100 static gint ett_acn_dmx_address = -1;
101 static gint ett_acn_dmx_data_pdu = -1;
102 static gint ett_acn_dmx_pdu = -1;
103
104 /*  Register fields */
105 /* In alphabetical order */
106 static int hf_acn_association = -1;
107 static int hf_acn_channel_number = -1;
108 static int hf_acn_cid = -1;
109 static int hf_acn_client_protocol_id = -1;
110 static int hf_acn_data = -1;
111 static int hf_acn_data8 = -1;
112 static int hf_acn_data16 = -1;
113 static int hf_acn_data24 = -1;
114 static int hf_acn_data32 = -1;
115 static int hf_acn_dmp_address1 = -1;
116 static int hf_acn_dmp_address2 = -1;
117 static int hf_acn_dmp_address4 = -1;
118 static int hf_acn_dmp_adt = -1; /* address and data type*/
119 static int hf_acn_dmp_adt_a = -1;
120 static int hf_acn_dmp_adt_v = -1;
121 static int hf_acn_dmp_adt_r = -1;
122 static int hf_acn_dmp_adt_d = -1;
123 static int hf_acn_dmp_adt_x = -1;
124 static int hf_acn_dmp_reason_code = -1;
125 static int hf_acn_dmp_vector = -1;
126 static int hf_acn_dmp_address_data_pairs = -1;
127 static int hf_acn_expiry = -1;
128 static int hf_acn_first_memeber_to_ack = -1;
129 static int hf_acn_first_missed_sequence = -1;
130 static int hf_acn_ip_address_type = -1;
131 static int hf_acn_ipv4 = -1;
132 static int hf_acn_ipv6 = -1;
133 static int hf_acn_last_memeber_to_ack = -1;
134 static int hf_acn_last_missed_sequence = -1;
135 static int hf_acn_mak_threshold = -1;
136 static int hf_acn_member_id = -1;
137 static int hf_acn_nak_holdoff = -1;
138 static int hf_acn_nak_max_wait = -1;
139 static int hf_acn_nak_modulus = -1;
140 static int hf_acn_nak_outbound_flag = -1;
141 static int hf_acn_oldest_available_wrapper = -1;
142 static int hf_acn_packet_identifier = -1;
143 static int hf_acn_pdu = -1;
144 static int hf_acn_pdu_flag_d = -1;
145 static int hf_acn_pdu_flag_h = -1;
146 static int hf_acn_pdu_flag_l = -1;
147 static int hf_acn_pdu_flag_v = -1;
148 static int hf_acn_pdu_flags = -1;
149 static int hf_acn_pdu_length = -1;
150 static int hf_acn_port = -1;
151 static int hf_acn_postamble_size = -1;
152 static int hf_acn_preamble_size = -1;
153 static int hf_acn_protocol_id = -1;
154 static int hf_acn_reason_code = -1;
155 static int hf_acn_reciprocal_channel = -1;
156 static int hf_acn_refuse_code = -1;
157 static int hf_acn_reliable_sequence_number = -1;
158 /* static int hf_acn_sdt_pdu = -1; */
159 static int hf_acn_sdt_vector = -1;
160 static int hf_acn_dmx_vector = -1;
161 static int hf_acn_session_count = -1;
162 static int hf_acn_total_sequence_number = -1;
163 static int hf_acn_dmx_source_name = -1;
164 static int hf_acn_dmx_priority = -1;
165 static int hf_acn_dmx_sequence_number = -1;
166 static int hf_acn_dmx_universe = -1;
167 /* static int hf_acn_dmx_dmp_vector = -1; */
168
169 /* Try heuristic ACN decode */
170 static gboolean global_acn_heur = FALSE;
171 static gboolean global_acn_dmx_enable = FALSE;
172 static gint     global_acn_dmx_display_view = 0; 
173 static gboolean global_acn_dmx_display_zeros = FALSE;
174 static gboolean global_acn_dmx_display_leading_zeros = FALSE;
175
176
177 static const value_string acn_protocol_id_vals[] = {
178   { ACN_PROTOCOL_ID_SDT, "SDT Protocol" }, 
179   { ACN_PROTOCOL_ID_DMP, "DMP Protocol" }, 
180   { ACN_PROTOCOL_ID_DMX, "DMX Protocol" }, 
181   { 0,       NULL },
182 };
183
184 static const value_string acn_dmp_adt_r_vals[] = {
185   { 0, "Relative" }, 
186   { 1, "Absolute" }, 
187   { 0,       NULL },
188 };
189
190 static const value_string acn_dmp_adt_v_vals[] = {
191   { 0, "Actual" }, 
192   { 1, "Virtual" }, 
193   { 0,       NULL },
194 };
195
196 static const value_string acn_dmp_adt_d_vals[] = {
197   { ACN_DMP_ADT_D_NS, "Non-range, single data item" }, 
198   { ACN_DMP_ADT_D_RS, "Range, single data item" }, 
199   { ACN_DMP_ADT_D_RE, "Range, array of equal size data items" }, 
200   { ACN_DMP_ADT_D_RM, "Range, series of mixed size data items" }, 
201   { 0,       NULL },
202 };
203
204 static const value_string acn_dmp_adt_a_vals[] = {
205   { ACN_DMP_ADT_A_1, "1 octet" }, 
206   { ACN_DMP_ADT_A_2, "2 octets" }, 
207   { ACN_DMP_ADT_A_4, "4 octets" }, 
208   { ACN_DMP_ADT_A_R, "reserved" }, 
209   { 0,       NULL },
210 };
211
212
213 static const value_string acn_sdt_vector_vals[] = {
214   {ACN_SDT_VECTOR_UNKNOWN, "Unknown"},
215   {ACN_SDT_VECTOR_REL_WRAP, "Reliable Wrapper"},
216   {ACN_SDT_VECTOR_UNREL_WRAP, "Unreliable Wrapper"},
217   {ACN_SDT_VECTOR_CHANNEL_PARAMS, "Channel Parameters"},
218   {ACN_SDT_VECTOR_JOIN, "Join"},
219   {ACN_SDT_VECTOR_JOIN_REFUSE, "Join Refuse"},
220   {ACN_SDT_VECTOR_JOIN_ACCEPT, "Join Accept"},
221   {ACN_SDT_VECTOR_LEAVE, "Leave"},
222   {ACN_SDT_VECTOR_LEAVING, "Leaving"},
223   {ACN_SDT_VECTOR_CONNECT, "Connect"},
224   {ACN_SDT_VECTOR_CONNECT_ACCEPT, "Connect Accept"},
225   {ACN_SDT_VECTOR_CONNECT_REFUSE, "Connect Refuse"},
226   {ACN_SDT_VECTOR_DISCONNECT, "Disconnect"},
227   {ACN_SDT_VECTOR_DISCONNECTING, "Disconnecting"},
228   {ACN_SDT_VECTOR_ACK, "Ack"},
229   {ACN_SDT_VECTOR_NAK, "Nak"},
230   {ACN_SDT_VECTOR_GET_SESSION, "Get Session"},
231   {ACN_SDT_VECTOR_SESSIONS, "Sessions"},
232   { 0,       NULL },
233 };
234
235 static const value_string acn_dmx_vector_vals[] = {
236   {ACN_DMX_VECTOR,  "Streaming DMX"},
237   { 0,       NULL },
238 };
239
240 static const value_string acn_dmp_vector_vals[] = {
241   {ACN_DMP_VECTOR_UNKNOWN, "Unknown"},
242   {ACN_DMP_VECTOR_GET_PROPERTY, "Get Property"},
243   {ACN_DMP_VECTOR_SET_PROPERTY, "Set Property"},
244   {ACN_DMP_VECTOR_GET_PROPERTY_REPLY, "Get property reply"},
245   {ACN_DMP_VECTOR_EVENT, "Event"},
246   {ACN_DMP_VECTOR_MAP_PROPERTY, "Map Property"},
247   {ACN_DMP_VECTOR_UNMAP_PROPERTY, "Unmap Property"},
248   {ACN_DMP_VECTOR_SUBSCRIBE, "Subscribe"},
249   {ACN_DMP_VECTOR_UNSUBSCRIBE, "Unsubscribe"},
250   {ACN_DMP_VECTOR_GET_PROPERTY_FAIL, "Get Property Fail"},
251   {ACN_DMP_VECTOR_SET_PROPERTY_FAIL, "Set Property Fail"},
252   {ACN_DMP_VECTOR_MAP_PROPERTY_FAIL, "Map Property Fail"},
253   {ACN_DMP_VECTOR_SUBSCRIBE_ACCEPT, "Subscribe Accept"},
254   {ACN_DMP_VECTOR_SUBSCRIBE_REJECT, "Subscribe Reject"},
255   {ACN_DMP_VECTOR_ALLOCATE_MAP, "Allocate Map"},
256   {ACN_DMP_VECTOR_ALLOCATE_MAP_REPLY, "Allocate Map Reply"},
257   {ACN_DMP_VECTOR_DEALLOCATE_MAP, "Deallocate Map"},
258   { 0,       NULL },
259 };
260
261 static const value_string acn_ip_address_type_vals[] = {
262   { ACN_ADDR_NULL, "Null"},
263   { ACN_ADDR_IPV4, "IPv4"},
264   { ACN_ADDR_IPV6, "IPv6"},
265   { ACN_ADDR_IPPORT, "Port"},
266   { 0,       NULL },
267 };
268
269 static const value_string acn_refuse_code_vals[] = {
270   { ACN_REFUSE_CODE_NONSPECIFIC, "Nonspecific" }, 
271   { ACN_REFUSE_CODE_ILLEGAL_PARAMS, "Illegal Parameters" }, 
272   { ACN_REFUSE_CODE_LOW_RESOURCES, "Low Resources" }, 
273   { ACN_REFUSE_CODE_ALREADY_MEMBER, "Already Member" }, 
274   { ACN_REFUSE_CODE_BAD_ADDR_TYPE, "Bad Address Type" }, 
275   { ACN_REFUSE_CODE_NO_RECIP_CHAN, "No Reciprocal Channel" }, 
276   { 0,       NULL },
277 };
278
279 static const value_string acn_reason_code_vals[] = {
280   { ACN_REASON_CODE_NONSPECIFIC, "Nonspecific" }, 
281   { ACN_REASON_CODE_NO_RECIP_CHAN, "No Reciprocal Channel" }, 
282   { ACN_REASON_CODE_CHANNEL_EXPIRED, "Channel Expired" }, 
283   { ACN_REASON_CODE_LOST_SEQUENCE, "Lost Sequence" }, 
284   { ACN_REASON_CODE_SATURATED, "Saturated" }, 
285   { ACN_REASON_CODE_TRANS_ADDR_CHANGING, "Transport Address Changing" }, 
286   { ACN_REASON_CODE_ASKED_TO_LEAVE, "Asked to Leave" }, 
287   { ACN_REASON_CODE_NO_RECIPIENT, "No Recipient"},
288   { 0,       NULL },
289 };
290
291 static const value_string acn_dmp_reason_code_vals[] = {
292   { ACN_DMP_REASON_CODE_NONSPECIFIC, "Nonspecific" }, 
293   { ACN_DMP_REASON_CODE_NOT_A_PROPERTY, "Not a Property" }, 
294   { ACN_DMP_REASON_CODE_WRITE_ONLY, "Write Only" }, 
295   { ACN_DMP_REASON_CODE_NOT_WRITABLE, "Not Writable" }, 
296   { ACN_DMP_REASON_CODE_DATA_ERROR, "Data Error" }, 
297   { ACN_DMP_REASON_CODE_MAPS_NOT_SUPPORTED, "Maps not Supported" }, 
298   { ACN_DMP_REASON_CODE_SPACE_NOT_AVAILABLE, "Space not Available" }, 
299   { ACN_DMP_REASON_CODE_PROP_NOT_MAPABLE, "Property not Mapable"},
300   { ACN_DMP_REASON_CODE_MAP_NOT_ALLOCATED, "Map not Allocated"},
301   { ACN_DMP_REASON_CODE_SUBSCRIPTION_NOT_SUPPORTED, "Subscription not Supported"},
302   { ACN_DMP_REASON_CODE_NO_SUBSCRIPTIONS_SUPPORTED, "No Subscriptions Supported"},
303   { 0,       NULL },
304 };
305
306 static const enum_val_t dmx_display_view[] = {
307   { "hex"    , "Hex    ",     ACN_PREF_DMX_DISPLAY_HEX  },
308   { "decimal", "Decimal",     ACN_PREF_DMX_DISPLAY_DEC  },
309   { "percent", "Percent",     ACN_PREF_DMX_DISPLAY_PER  },
310   { NULL, NULL, 0 }
311 };
312
313 /******************************************************************************/
314 /* Test to see if it is an ACN Packet                                         */
315 static gboolean is_acn(tvbuff_t *tvb) 
316 {
317   static char acn_packet_id[] = "ASC-E1.17\0\0\0";  /* must be 12 bytes */
318   guint8      *packet_id;
319
320   /* Get the fields in octets 2 - 12 octet */
321   packet_id = tvb_get_ephemeral_string(tvb, 4, 12); 
322   if (memcmp(packet_id, &acn_packet_id, 12) == 0) {
323     return TRUE;
324   }
325   return FALSE;
326 }
327
328
329 /******************************************************************************/
330 /* Heuristic dissector                                                        */
331 static gboolean
332 dissect_acn_heur( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree )
333 {
334   /* This is a heuristic dissector, which means we get all the UDP
335          * traffic not sent to a known dissector and not claimed by
336          * a heuristic dissector called before us!
337          */
338
339   /* abort if not enabled! */
340   if (!global_acn_heur) return FALSE;
341
342   /* abort if it is NOT an ACN packet */
343   if (!is_acn(tvb)) return FALSE;
344
345   /* else, dissect it */
346   dissect_acn(tvb, pinfo, tree);
347   return TRUE;
348 }
349
350 /******************************************************************************/
351 /*  Adds tree branch for channel owner info block                             */
352 static guint32
353 acn_add_channel_owner_info_block(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree _U_, int offset)
354 {
355   proto_item *pi;
356   proto_tree *this_tree = NULL;
357   guint32 session_count;
358   guint32 x;
359
360   pi = proto_tree_add_text(this_tree, tvb, offset, 8, "Channel Owner Info Block");
361   this_tree = proto_item_add_subtree(pi, ett_acn_channel_owner_info_block);
362
363   proto_tree_add_item(this_tree, hf_acn_member_id, tvb, offset, 2, FALSE);
364   offset += 2;
365   proto_tree_add_item(this_tree, hf_acn_channel_number, tvb, offset, 2, FALSE);
366   offset += 2;
367   offset += acn_add_address(tvb, pinfo, this_tree, offset, "Destination Address: ");
368   offset += acn_add_address(tvb, pinfo, this_tree, offset, "Source Address: ");
369
370   session_count = tvb_get_ntohs(tvb, offset);
371   for (x=0; x<session_count; x++) {
372     pi = proto_tree_add_item(this_tree, hf_acn_protocol_id, tvb, offset, 4, FALSE);
373     proto_item_append_text(pi, " #%d",  x+1);
374     offset += 4;
375   }
376   return offset;
377 }
378
379 /******************************************************************************/
380 /*  Adds tree branch for channel member info block                            */
381 static guint32
382 acn_add_channel_member_info_block(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree _U_, int offset)
383 {
384   proto_item *pi;
385   proto_tree *this_tree = NULL;
386   guint32 session_count;
387   guint32 x;
388
389   pi = proto_tree_add_text(this_tree, tvb, offset, 8, "Channel Member Info Block");
390   this_tree = proto_item_add_subtree(pi, ett_acn_channel_member_info_block);
391
392   proto_tree_add_item(this_tree, hf_acn_member_id, tvb, offset, 2, FALSE);
393   offset += 2;
394   proto_tree_add_item(this_tree, hf_acn_cid, tvb, offset, 16, FALSE);
395   offset += 16;
396   proto_tree_add_item(this_tree, hf_acn_channel_number, tvb, offset, 2, FALSE);
397   offset += 2;
398   offset += acn_add_address(tvb, pinfo, this_tree, offset, "Destination Address: ");
399   offset += acn_add_address(tvb, pinfo, this_tree, offset, "Source Address: ");
400   proto_tree_add_item(this_tree, hf_acn_reciprocal_channel, tvb, offset, 2, FALSE);
401   offset += 2;
402
403   session_count = tvb_get_ntohs(tvb, offset);
404   for (x=0; x<session_count; x++) {
405     pi = proto_tree_add_item(this_tree, hf_acn_protocol_id, tvb, offset, 4, FALSE);
406     proto_item_append_text(pi, " #%d",  x+1);
407     offset += 4;
408   }
409   return offset;
410 }
411
412
413 /******************************************************************************/
414 /* Add labled exiry                                                           */
415 static guint32
416 acn_add_expiry(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, const char *label)
417 {
418   proto_item *pi;
419   guint32 expiry;
420
421   expiry = tvb_get_ntohs(tvb, offset);
422   pi = proto_tree_add_text(tree, tvb, offset, 2, label);
423   proto_item_append_text(pi, " %d",  expiry);
424   offset += 2;
425   return offset;
426 }
427
428
429 /******************************************************************************/
430 /*  Adds tree branch for channel parameters                                   */
431 static guint32
432 acn_add_channel_parameter(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset)
433 {
434   proto_item *pi;
435   proto_tree *param_tree = NULL;
436
437   pi = proto_tree_add_text(tree, tvb, offset, 8, "Channel Parameter Block");
438   param_tree = proto_item_add_subtree(pi, ett_acn_channel_parameter);
439   proto_tree_add_item(param_tree, hf_acn_expiry, tvb, offset, 1, FALSE);
440   offset += 1;
441   proto_tree_add_item(param_tree, hf_acn_nak_outbound_flag, tvb, offset, 1, FALSE);
442   offset += 1;
443   proto_tree_add_item(param_tree, hf_acn_nak_holdoff, tvb, offset, 2, FALSE);
444   offset += 2;
445   proto_tree_add_item(param_tree, hf_acn_nak_modulus, tvb, offset, 2, FALSE);
446   offset += 2;
447   proto_tree_add_item(param_tree, hf_acn_nak_max_wait, tvb, offset, 2, FALSE);
448   offset += 2;
449   return offset; /* bytes used */
450 }
451
452
453 /******************************************************************************/
454 /* Add an address tree                                                        */
455 static guint32
456 acn_add_address(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, const char *label)
457 {
458   proto_item *pi;
459   proto_tree *addr_tree = NULL;
460   guint8 ip_address_type;
461
462   address addr;
463   guint32  IPv4;
464   guint32  port;
465   struct e_in6_addr IPv6;
466
467
468   /* Get type */
469   ip_address_type = tvb_get_guint8(tvb, offset);
470
471   switch (ip_address_type) {
472   case ACN_ADDR_NULL:
473     break;
474   case ACN_ADDR_IPV4:
475     /* Build tree and add type*/
476     pi = proto_tree_add_text(tree, tvb, offset, 7, label);
477     addr_tree = proto_item_add_subtree(pi, ett_acn_address);
478     proto_tree_add_item(addr_tree, hf_acn_ip_address_type, tvb, offset, 1, FALSE);
479     offset +=1;
480     /* Add port */
481     port = tvb_get_ntohs(tvb, offset);
482     proto_tree_add_item(addr_tree, hf_acn_port, tvb, offset, 2, FALSE);
483     offset += 2;
484     /* Add Address */
485     proto_tree_add_item(addr_tree, hf_acn_ipv4, tvb, offset, 4, FALSE);
486     /* Append port and address to tree item */
487     IPv4 = tvb_get_ipv4(tvb, offset);
488     SET_ADDRESS(&addr, AT_IPv4, sizeof(IPv4), &IPv4);
489     proto_item_append_text(pi, "%s, Port %d", address_to_str(&addr), port);
490     offset += 4;
491     break;
492   case ACN_ADDR_IPV6:
493     /* Build tree and add type*/
494     pi = proto_tree_add_text(tree, tvb, offset, 19, label);
495     addr_tree = proto_item_add_subtree(pi, ett_acn_address);
496     proto_tree_add_item(addr_tree, hf_acn_ip_address_type, tvb, offset, 1, FALSE);
497     offset +=1;
498     /* Add port */
499     port = tvb_get_ntohs(tvb, offset);
500     proto_tree_add_item(addr_tree, hf_acn_port, tvb, offset, 2, FALSE);
501     offset += 2;
502     /* Add Address */
503     proto_tree_add_item(addr_tree, hf_acn_ipv6, tvb, offset, 16, FALSE);
504     /* Append port and address to tree item */
505     tvb_get_ipv6(tvb, offset, &IPv6);
506     SET_ADDRESS(&addr, AT_IPv6, sizeof(struct e_in6_addr), &IPv6);
507     proto_item_append_text(pi, "%s, Port %d", address_to_str(&addr), port);
508     offset += 16;
509     break;
510   case ACN_ADDR_IPPORT:
511     /* Build tree and add type*/
512     pi = proto_tree_add_text(tree, tvb, offset, 3, label);
513     addr_tree = proto_item_add_subtree(pi, ett_acn_address);
514     proto_tree_add_item(addr_tree, hf_acn_ip_address_type, tvb, offset, 1, FALSE);
515     offset +=1;
516     /* Add port */
517     port = tvb_get_ntohs(tvb, offset);
518     proto_tree_add_item(addr_tree, hf_acn_port, tvb, offset, 2, FALSE);
519     /* Append port to tree item */
520     proto_item_append_text(pi, "%s Port %d", address_to_str(&addr), port);
521     offset += 2;
522     break;
523   }
524   return offset;
525 }
526
527 /******************************************************************************/
528 /*  Adds tree branch for address type                             */
529 static guint32
530 acn_add_dmp_address_type(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, acn_dmp_adt_type *adt)
531 {
532   proto_item *pi;
533   proto_tree *this_tree = NULL;
534   guint8 D;
535
536     /* header contains address and data type */
537   adt->flags = tvb_get_guint8(tvb, offset);
538
539   D = ACN_DMP_ADT_EXTRACT_D(adt->flags);
540   pi = proto_tree_add_text(tree, tvb, offset, 1, "Address and Data Type: %s (%d)", match_strval(D, acn_dmp_adt_d_vals), D);
541
542   this_tree = proto_item_add_subtree(pi, ett_acn_address_type);
543   proto_tree_add_uint(this_tree, hf_acn_dmp_adt_v, tvb, offset, 1, adt->flags);
544   proto_tree_add_uint(this_tree, hf_acn_dmp_adt_r, tvb, offset, 1, adt->flags);
545   proto_tree_add_uint(this_tree, hf_acn_dmp_adt_d, tvb, offset, 1, adt->flags);
546   proto_tree_add_uint(this_tree, hf_acn_dmp_adt_x, tvb, offset, 1, adt->flags);
547   proto_tree_add_uint(this_tree, hf_acn_dmp_adt_a, tvb, offset, 1, adt->flags);
548   offset++;
549
550   return offset; /* bytes used */
551 }
552
553 /******************************************************************************/
554 /* Add an dmp address                                                         */
555 static guint32
556 acn_add_dmp_address(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, acn_dmp_adt_type *adt)
557 {
558   guint32 start_offset;
559   guint32 bytes_used;
560   guint8 D, A;
561
562   start_offset = offset;
563
564   D = ACN_DMP_ADT_EXTRACT_D(adt->flags);
565   A = ACN_DMP_ADT_EXTRACT_A(adt->flags);
566   switch (D) {
567     case ACN_DMP_ADT_D_NS: /* Non-range address, Single data item */
568       adt->increment = 1;
569       adt->count = 1;
570       switch (A) { /* address */
571         case ACN_DMP_ADT_A_1: /* One octet address, (range: one octet address, increment, and count). */
572           adt->address =   tvb_get_guint8(tvb, offset);
573           offset += 1;
574           bytes_used = 1;
575           break;
576         case ACN_DMP_ADT_A_2: /* Two octet address, (range: two octet address, increment, and count). */
577           adt->address =   tvb_get_ntohs(tvb, offset);
578           offset += 2;
579           bytes_used = 2;
580           break;
581         case ACN_DMP_ADT_A_4: /* Four octet address, (range: one octet address, increment, and count). */
582           adt->address =   tvb_get_ntohl(tvb, offset);
583           offset += 4;
584           bytes_used = 4;
585           break;
586         default: /* and ACN_DMP_ADT_A_R (Four octet address, (range: four octet address, increment, and count)*/
587           return offset;
588       } /* of switch (A)  */
589
590       if (adt->flags & ACN_DMP_ADT_FLAG_V) {
591         proto_tree_add_text(tree, tvb, start_offset, bytes_used, "Virtual Address: %d", adt->address);
592       } else {
593         proto_tree_add_text(tree, tvb, start_offset, bytes_used, "Actual Address: %d", adt->address);
594       }
595       break;
596
597     case ACN_DMP_ADT_D_RS: /* Range address, Single data item */
598       switch (A) {
599         case ACN_DMP_ADT_A_1: /* One octet address, (range: one octet address, increment, and count). */
600           adt->address =   tvb_get_guint8(tvb, offset);
601           offset += 1;
602           adt->increment =   tvb_get_guint8(tvb, offset);
603           offset += 1;
604           adt->count =   tvb_get_guint8(tvb, offset);
605           offset += 1;
606           bytes_used = 3;
607           break;
608         case ACN_DMP_ADT_A_2: /* Two octet address, (range: two octet address, increment, and count). */
609           adt->address =   tvb_get_ntohs(tvb, offset);
610           offset += 2;
611           adt->increment =   tvb_get_ntohs(tvb, offset);
612           offset += 2;
613           adt->count =   tvb_get_ntohs(tvb, offset);
614           offset += 2;
615           bytes_used = 6;
616           break;
617         case ACN_DMP_ADT_A_4: /* Four octet address, (range: four octet address, increment, and count). */
618           adt->address =   tvb_get_ntohl(tvb, offset);
619           offset += 4;
620           adt->increment =   tvb_get_ntohl(tvb, offset);
621           offset += 4;
622           adt->count =   tvb_get_ntohl(tvb, offset);
623           offset += 12;
624           bytes_used = 12;
625           break;
626         default: /* and ACN_DMP_ADT_A_R, this reserved....so it has no meaning yet */
627           return offset;
628       } /* of switch (A)  */
629
630       if (adt->flags & ACN_DMP_ADT_FLAG_V) {
631         proto_tree_add_text(tree, tvb, start_offset, bytes_used, "Virtual Address first: %d, inc: %d, count: %d", adt->address, adt->increment, adt->count);
632       } else {
633         proto_tree_add_text(tree, tvb, start_offset, bytes_used, "Actual Address first: %d, inc: %d, count: %d", adt->address, adt->increment, adt->count);
634       }
635       break;
636
637     case ACN_DMP_ADT_D_RE: /* Range address, Array of equal size data items */
638       switch (A) {
639         case ACN_DMP_ADT_A_1: /* One octet address, (range: one octet address, increment, and count). */
640           adt->address =   tvb_get_guint8(tvb, offset);
641           offset += 1;
642           adt->increment =   tvb_get_guint8(tvb, offset);
643           offset += 1;
644           adt->count =   tvb_get_guint8(tvb, offset);
645           offset += 1;
646           bytes_used = 3;
647           break;
648         case ACN_DMP_ADT_A_2: /* Two octet address, (range: two octet address, increment, and count). */
649           adt->address =   tvb_get_ntohs(tvb, offset);
650           offset += 2;
651           adt->increment =   tvb_get_ntohs(tvb, offset);
652           offset += 2;
653           adt->count =   tvb_get_ntohs(tvb, offset);
654           offset += 2;
655           bytes_used = 6;
656           break;
657         case ACN_DMP_ADT_A_4: /* Four octet address, (range: four octet address, increment, and count). */
658           adt->address =   tvb_get_ntohl(tvb, offset);
659           offset += 4;
660           adt->increment =   tvb_get_ntohl(tvb, offset);
661           offset += 4;
662           adt->count =   tvb_get_ntohl(tvb, offset);
663           offset += 12;
664           bytes_used = 12;
665           break;
666         default: /* and ACN_DMP_ADT_A_R, this reserved....so it has no meaning yet */
667           return offset;
668       } /* of switch (A)  */
669
670       if (adt->flags & ACN_DMP_ADT_FLAG_V) {
671         proto_tree_add_text(tree, tvb, start_offset, bytes_used, "Virtual Address first: %d, inc: %d, count: %d", adt->address, adt->increment, adt->count);
672       } else {
673         proto_tree_add_text(tree, tvb, start_offset, bytes_used, "Actual Address first: %d, inc: %d, count: %d", adt->address, adt->increment, adt->count);
674       }
675       break;
676
677     case ACN_DMP_ADT_D_RM: /* Range address, Series of mixed size data items */
678       switch (A) {
679         case ACN_DMP_ADT_A_1: /* One octet address, (range: one octet address, increment, and count). */
680           adt->address =   tvb_get_guint8(tvb, offset);
681           offset += 1;
682           adt->increment =   tvb_get_guint8(tvb, offset);
683           offset += 1;
684           adt->count =   tvb_get_guint8(tvb, offset);
685           offset += 1;
686           bytes_used = 3;
687           break;
688         case ACN_DMP_ADT_A_2: /* Two octet address, (range: two octet address, increment, and count). */
689           adt->address =   tvb_get_ntohs(tvb, offset);
690           offset += 2;
691           adt->increment =   tvb_get_ntohs(tvb, offset);
692           offset += 2;
693           adt->count =   tvb_get_ntohs(tvb, offset);
694           offset += 2;
695           bytes_used = 6;
696           break;
697         case ACN_DMP_ADT_A_4: /* Four octet address, (range: four octet address, increment, and count). */
698           adt->address =   tvb_get_ntohl(tvb, offset);
699           offset += 4;
700           adt->increment =   tvb_get_ntohl(tvb, offset);
701           offset += 4;
702           adt->count =   tvb_get_ntohl(tvb, offset);
703           offset += 12;
704           bytes_used = 12;
705           break;
706         default: /* and ACN_DMP_ADT_A_R, this reserved....so it has no meaning yet */
707           return offset;
708       } /* of switch (A)  */
709       
710       if (adt->flags & ACN_DMP_ADT_FLAG_V) {
711         proto_tree_add_text(tree, tvb, start_offset, bytes_used, "Virtual Address first: %d, inc: %d, count: %d", adt->address, adt->increment, adt->count);
712       } else {
713         proto_tree_add_text(tree, tvb, start_offset, bytes_used, "Actual Address first: %d, inc: %d, count: %d", adt->address, adt->increment, adt->count);
714       }
715       break;
716   } /* of switch (D) */
717   
718   return offset;
719 }
720
721
722 /*******************************************************************************/
723 /* Display DMP Data                                                            */
724 static guint32
725 acn_add_dmp_data(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, acn_dmp_adt_type *adt)
726 {
727   guint8 D, A;
728   guint32 start_offset;
729   guint32 data_size;
730   guint32 data_value;
731   guint32 data_address;
732   guint32 x,y;
733   gchar *buffer=NULL;
734   proto_item *ti;
735   guint32 ok_to_process = FALSE;
736
737   start_offset = offset;
738
739   /* We would like to rip through Property Address-Data pairs                 */
740   /* but since we don't now how many there are nor how big the data size is,  */
741   /* it not possible. So, we just show the whole thing as a block of date!    */
742   /*                                                                          */
743   /* There are a few exceptions however                                       */
744   /* 1) if the address type is ACN_DMP_ADT_D_NS or ACN_DMP_ADT_D_RS and       */
745   /*    or ACN_DMP_ADT_D_RE                                                   */   
746   /*    then number of bytes is <= count + 4. Each value is at least one byte */
747   /*    and another address/data pair is at least 4 bytes so if the remaining */
748   /*    bytes is less than the count plus 4 then the remaining data           */
749   /*    must be all data                                                      */
750   /*                                                                          */
751   /* 2) if the address type is ACN_DMP_ADT_D_RE and the number of bytes       */
752   /*    equals the number of bytes in remaining in the pdu then there is      */
753   /*    a 1 to one match                                                      */
754
755   D = ACN_DMP_ADT_EXTRACT_D(adt->flags);
756   switch (D) {
757     case ACN_DMP_ADT_D_NS:
758     case ACN_DMP_ADT_D_RS:
759       if (adt->data_length <= adt->count + 4) {
760         ok_to_process = TRUE;
761       }
762       break;
763     case ACN_DMP_ADT_D_RE:
764       if (adt->data_length == adt->count) {
765         ok_to_process = TRUE;
766       }
767       if (adt->data_length <= adt->count + 4) {
768         ok_to_process = TRUE;
769       }
770       break;
771   }
772   
773   if (!ok_to_process) {
774     data_size = adt->data_length;
775     ti = proto_tree_add_item(tree, hf_acn_data, tvb, offset, data_size, FALSE);
776     offset += data_size;
777     proto_item_set_text(ti, "Data and more Address-Data Pairs (further dissection not possible)");
778     return offset;
779   } 
780
781   /* Allocate some memory, not using ep_alloc here as there could be LOT of calls to 
782      this in the same capture frame.  Could use se_alloc...
783   */
784   #define BUFFER_SIZE 128
785   buffer = g_malloc(BUFFER_SIZE);
786   buffer[0] = 0;
787
788   A = ACN_DMP_ADT_EXTRACT_A(adt->flags);
789   switch (D) {
790     case ACN_DMP_ADT_D_NS: /* Non-range address, Single data item */
791       /* calculate data size */
792       data_size = adt->data_length;
793       data_address = adt->address;
794
795       switch (A) {
796         case ACN_DMP_ADT_A_1: /* One octet address, (range: one octet address, increment, and count). */
797           g_snprintf(buffer, BUFFER_SIZE, "Addr %2.2X ->", data_address);
798           break;
799         case ACN_DMP_ADT_A_2: /* Two octet address, (range: two octet address, increment, and count). */
800           g_snprintf(buffer, BUFFER_SIZE, "Addr %4.4X ->", data_address);
801           break;
802         case ACN_DMP_ADT_A_4: /* Four octet address, (range: four octet address, increment, and count). */
803           g_snprintf(buffer, BUFFER_SIZE, "Addr %8.8X ->", data_address);
804           break;
805         default: /* and ACN_DMP_ADT_A_R, this reserved....so it has no meaning yet */
806           return offset;
807       }
808
809       switch (data_size) {
810         case 1:
811           data_value = tvb_get_guint8(tvb, offset); 
812           proto_tree_add_int_format(tree, hf_acn_data8, tvb, offset, 1, data_value, "%s %2.2X", buffer, data_value);
813           break;
814         case 2:
815           data_value = tvb_get_ntohs(tvb, offset);
816           proto_tree_add_int_format(tree, hf_acn_data16, tvb, offset, 2, data_value, "%s %4.4X", buffer, data_value);
817           break;
818         case 3:
819           data_value = tvb_get_ntoh24(tvb, offset);
820           proto_tree_add_int_format(tree, hf_acn_data24, tvb, offset, 3, data_value, "%s %6.6X", buffer, data_value);
821           break;
822         case 4:
823           data_value = tvb_get_ntohl(tvb, offset);
824           proto_tree_add_int_format(tree, hf_acn_data32, tvb, offset, 4, data_value, "%s %8.8X", buffer, data_value);
825           break;
826         default:
827           /* build string of values */
828           for (y=0;y<20 && y<data_size;y++) {
829             data_value = tvb_get_guint8(tvb, offset+y);
830             g_snprintf(buffer, BUFFER_SIZE, "%s %2.2X", buffer, data_value);
831           }
832           /* add the item */
833           ti = proto_tree_add_item(tree, hf_acn_data, tvb, offset, data_size, FALSE);
834           offset += data_size;
835           /* change the text */
836           proto_item_set_text(ti, "%s", buffer);
837           break;
838       } /* of switch (data_size) */
839       offset += data_size;
840       break;
841
842     case ACN_DMP_ADT_D_RS: /* Range address, Single data item */
843       /* calculate data size */
844       data_size = adt->data_length;
845       data_address = adt->address;
846
847       for (x=0;x<adt->count;x++) {
848         switch (A) {
849           case ACN_DMP_ADT_A_1: /* One octet address, (range: one octet address, increment, and count). */
850             g_snprintf(buffer, BUFFER_SIZE, "Addr %2.2X ->", data_address);
851             break;
852           case ACN_DMP_ADT_A_2: /* Two octet address, (range: two octet address, increment, and count). */
853             g_snprintf(buffer, BUFFER_SIZE, "Addr %4.4X ->", data_address);
854             break;
855           case ACN_DMP_ADT_A_4: /* Four octet address, (range: four octet address, increment, and count). */
856             g_snprintf(buffer, BUFFER_SIZE, "Addr %8.8X ->", data_address);
857             break;
858           default: /* and ACN_DMP_ADT_A_R, this reserved....so it has no meaning yet */
859             return offset;
860         }
861
862         switch (data_size) {
863           case 1:
864             data_value = tvb_get_guint8(tvb, offset); 
865             proto_tree_add_int_format(tree, hf_acn_data8, tvb, offset, 1, data_value, "%s %2.2X", buffer, data_value);
866             break;
867           case 2:
868             data_value = tvb_get_ntohs(tvb, offset);
869             proto_tree_add_int_format(tree, hf_acn_data8, tvb, offset, 2, data_value, "%s %4.4X", buffer, data_value);
870             break;
871           case 3:
872             data_value = tvb_get_ntoh24(tvb, offset);
873             proto_tree_add_int_format(tree, hf_acn_data8, tvb, offset, 3, data_value, "%s %6.6X", buffer, data_value);
874             break;
875           case 4:
876             data_value = tvb_get_ntohl(tvb, offset);
877             proto_tree_add_int_format(tree, hf_acn_data8, tvb, offset, 4, data_value, "%s %8.8X", buffer, data_value);
878             break;
879           default:
880             /* build string of values */
881             for (y=0;y<20 && y<data_size;y++) {
882               data_value = tvb_get_guint8(tvb, offset+y);
883               g_snprintf(buffer, BUFFER_SIZE, "%s %2.2X", buffer, data_value);
884             }
885             /* add the item */
886             ti = proto_tree_add_item(tree, hf_acn_data, tvb, offset, data_size, FALSE);
887             /* change the text */
888             proto_item_set_text(ti, "%s", buffer);
889             break;
890         } /* of switch (data_size) */
891         data_address += adt->increment;
892       } /* of (x=0;x<adt->count;x++) */
893       offset += data_size;
894       break;
895
896     case ACN_DMP_ADT_D_RE: /* Range address, Array of equal size data items */
897       /* calculate data size */
898       data_size = adt->data_length / adt->count;
899       data_address = adt->address;
900
901       for (x=0;x<adt->count;x++) {
902         switch (A) {
903           case ACN_DMP_ADT_A_1: /* One octet address, (range: one octet address, increment, and count). */
904             g_snprintf(buffer, BUFFER_SIZE, "Addr %2.2X ->", data_address);
905             break;
906           case ACN_DMP_ADT_A_2: /* Two octet address, (range: two octet address, increment, and count). */
907             g_snprintf(buffer, BUFFER_SIZE, "Addr %4.4X ->", data_address);
908             break;
909           case ACN_DMP_ADT_A_4: /* Four octet address, (range: four octet address, increment, and count). */
910             g_snprintf(buffer, BUFFER_SIZE, "Addr %8.8X ->", data_address);
911             break;
912           default: /* and ACN_DMP_ADT_A_R, this reserved....so it has no meaning yet */
913             return offset;
914         }
915
916         switch (data_size) {
917           case 1:
918             data_value = tvb_get_guint8(tvb, offset); 
919             proto_tree_add_int_format(tree, hf_acn_data8, tvb, offset, 1, data_value, "%s %2.2X", buffer, data_value);
920             break;
921           case 2:
922             data_value = tvb_get_ntohs(tvb, offset);
923             proto_tree_add_int_format(tree, hf_acn_data8, tvb, offset, 2, data_value, "%s %4.4X", buffer, data_value);
924             break;
925           case 3:
926             data_value = tvb_get_ntoh24(tvb, offset);
927             proto_tree_add_int_format(tree, hf_acn_data8, tvb, offset, 3, data_value, "%s %6.6X", buffer, data_value);
928             break;
929           case 4:
930             data_value = tvb_get_ntohl(tvb, offset);
931             proto_tree_add_int_format(tree, hf_acn_data8, tvb, offset, 4, data_value, "%s %8.8X", buffer, data_value);
932             break;
933           default:
934             /* build string of values */
935             for (y=0;y<20 && y<data_size;y++) {
936               data_value = tvb_get_guint8(tvb, offset+y);
937               g_snprintf(buffer, BUFFER_SIZE, "%s %2.2X", buffer, data_value);
938             }
939             /* add the item */
940             ti = proto_tree_add_item(tree, hf_acn_data, tvb, offset, data_size, FALSE);
941             /* change the text */
942             proto_item_set_text(ti, "%s", buffer);
943             break;
944         } /* of switch (data_size) */
945
946         offset += data_size;
947         data_address += adt->increment;
948       } /* of (x=0;x<adt->count;x++) */
949       break;
950
951     case ACN_DMP_ADT_D_RM: /* Range address, Series of mixed size data items */
952       data_size = adt->data_length;
953       ti = proto_tree_add_item(tree, hf_acn_data, tvb, offset, data_size, FALSE);
954       offset += data_size;
955       /* change the text */
956       proto_item_set_text(ti, "Mixed size data items");
957       break;
958   } /* of switch (D) */
959   /* free our memory! */
960   g_free(buffer);
961   
962   return offset;
963 }
964
965 /*******************************************************************************/
966 /* Display DMP Reason codes                                                    */
967 static guint32
968 acn_add_dmp_reason_codes(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, acn_dmp_adt_type *adt)
969 {
970   guint8 D, A;
971   guint32 start_offset;
972   guint32 data_value;
973   guint32 data_address;
974   guint32 x;
975
976   char *buffer=NULL;
977   const gchar *ptr;
978
979   start_offset = offset;
980
981   /* Allocate some memory, not using ep_alloc here as there could be LOT of calls to 
982      this in the same capture frame.  Could use se_alloc...
983   */
984   #define BUFFER_SIZE 128
985   buffer = g_malloc(BUFFER_SIZE);
986
987   buffer[0] = 0;
988
989   D = ACN_DMP_ADT_EXTRACT_D(adt->flags);
990   A = ACN_DMP_ADT_EXTRACT_A(adt->flags);
991   switch (D) {
992     case ACN_DMP_ADT_D_NS: /* Non-range address, Single data item */
993       data_address = adt->address;
994       switch (A) {
995         case ACN_DMP_ADT_A_1: /* One octet address, (range: one octet address, increment, and count). */
996           g_snprintf(buffer, BUFFER_SIZE, "Addr %2.2X ->", data_address);
997           break;
998         case ACN_DMP_ADT_A_2: /* Two octet address, (range: two octet address, increment, and count). */
999           g_snprintf(buffer, BUFFER_SIZE, "Addr %4.4X ->", data_address);
1000           break;
1001         case ACN_DMP_ADT_A_4: /* Four octet address, (range: four octet address, increment, and count). */
1002           g_snprintf(buffer, BUFFER_SIZE, "Addr %8.8X ->", data_address);
1003           break;
1004         default: /* and ACN_DMP_ADT_A_R, this reserved....so it has no meaning yet */
1005           return offset;
1006       }
1007
1008       /* Get reason */
1009       data_value = tvb_get_guint8(tvb, offset); 
1010       /* convert to string */
1011       ptr = match_strval(data_value, acn_dmp_reason_code_vals); 
1012       /* Add item */
1013       proto_tree_add_int_format(tree, hf_acn_data8, tvb, offset, 1, data_value, "%s %s", buffer, ptr);
1014       offset++;
1015       break;
1016
1017     case ACN_DMP_ADT_D_RS: /* Range address, Single data item */
1018       data_address = adt->address;
1019       for (x=0;x<adt->count;x++) {
1020         switch (A) {
1021           case ACN_DMP_ADT_A_1: /* One octet address, (range: one octet address, increment, and count). */
1022             g_snprintf(buffer, BUFFER_SIZE, "Addr %2.2X ->", data_address);
1023             break;
1024           case ACN_DMP_ADT_A_2: /* Two octet address, (range: two octet address, increment, and count). */
1025             g_snprintf(buffer, BUFFER_SIZE, "Addr %4.4X ->", data_address);
1026             break;
1027           case ACN_DMP_ADT_A_4: /* Four octet address, (range: four octet address, increment, and count). */
1028             g_snprintf(buffer, BUFFER_SIZE, "Addr %8.8X ->", data_address);
1029             break;
1030           default: /* and ACN_DMP_ADT_A_R, this reserved....so it has no meaning yet */
1031             return offset;
1032         }
1033
1034         /* Get reason */
1035         data_value = tvb_get_guint8(tvb, offset); 
1036         /* convert to string */
1037         ptr = match_strval(data_value, acn_dmp_reason_code_vals); 
1038         /* Add item */
1039         proto_tree_add_int_format(tree, hf_acn_data8, tvb, offset, 1, data_value, "%s %s", buffer, ptr);
1040         data_address += adt->increment;
1041       } /* of (x=0;x<adt->count;x++) */
1042       offset++;
1043       break;
1044
1045     case ACN_DMP_ADT_D_RE: /* Range address, Array of equal size data items */
1046     case ACN_DMP_ADT_D_RM: /* Range address, Series of mixed size data items */
1047       data_address = adt->address;
1048       for (x=0;x<adt->count;x++) {
1049         switch (A) {
1050           case ACN_DMP_ADT_A_1: /* One octet address, (range: one octet address, increment, and count). */
1051             g_snprintf(buffer, BUFFER_SIZE, "Addr %2.2X ->", data_address);
1052             break;
1053           case ACN_DMP_ADT_A_2: /* Two octet address, (range: two octet address, increment, and count). */
1054             g_snprintf(buffer, BUFFER_SIZE, "Addr %4.4X ->", data_address);
1055             break;
1056           case ACN_DMP_ADT_A_4: /* Four octet address, (range: four octet address, increment, and count). */
1057             g_snprintf(buffer, BUFFER_SIZE, "Addr %8.8X ->", data_address);
1058             break;
1059           default: /* and ACN_DMP_ADT_A_R, this reserved....so it has no meaning yet */
1060             return offset;
1061         }
1062         /* Get reason */
1063         data_value = tvb_get_guint8(tvb, offset); 
1064         /* convert to string */
1065         ptr = match_strval(data_value, acn_dmp_reason_code_vals); 
1066         /* Add item */
1067         proto_tree_add_int_format(tree, hf_acn_data8, tvb, offset, 1, data_value, "%s %s", buffer, ptr);
1068         data_address += adt->increment;
1069         offset++;
1070       } /* of (x=0;x<adt->count;x++) */
1071       break;
1072   } /* of switch (D) */
1073   /* free our memory! */
1074   g_free(buffer);
1075   
1076   return offset;
1077 }
1078
1079 /******************************************************************************/
1080 /* Dissect wrapped SDT PDU                                                    */
1081 static guint32
1082 dissect_acn_dmp_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, acn_pdu_offsets *last_pdu_offsets)
1083 {
1084   /* common to all pdu */
1085   guint8 pdu_flags;
1086   guint32 pdu_start;
1087   guint32 pdu_length;
1088   guint32 pdu_flvh_length; /* flags, length, vector, header */
1089   acn_pdu_offsets pdu_offsets = {0,0,0,0,0};
1090   guint8 D;
1091   guint8 octet;
1092   guint32 length1;
1093   guint32 length2;
1094   guint32 length3;
1095   guint32 vector_offset;
1096   guint32 header_offset;
1097   guint32 data_offset;
1098   guint32 old_offset;
1099   guint32 end_offset;
1100   guint32 data_length;
1101   guint32 address_count;
1102
1103   proto_item *ti, *pi;
1104   proto_tree *pdu_tree = NULL;
1105   proto_tree *flag_tree = NULL;
1106   
1107   /* this pdu */
1108   const gchar *ptr;
1109   acn_dmp_adt_type adt = {0,0,0,0,0,0};
1110   acn_dmp_adt_type adt2 = {0,0,0,0,0,0};
1111   guint32 vector;
1112
1113   /* save start of pdu block */
1114   pdu_start = offset;
1115   pdu_offsets.start = pdu_start;
1116
1117   /* get PDU flags and length flag first */
1118   octet = tvb_get_guint8(tvb, offset++); 
1119   pdu_flags =  octet & 0xf0;
1120   length1 = octet & 0x0f;                   /* bottom 4 bits only */
1121   length2 = tvb_get_guint8(tvb, offset++);  
1122
1123   /* if length flag is set, then we have a 20 bit length else we have a 12 bit */
1124   /* flvh = flags, length, vector, header */
1125   if (pdu_flags & ACN_PDU_FLAG_L) {
1126     length3 = tvb_get_guint8(tvb, offset);
1127     offset++;
1128     pdu_length = length3 | (length2 << 8) | (length1 << 16);
1129     pdu_flvh_length = 3;
1130   } else {
1131     pdu_length = length2 | (length1 << 8);
1132     pdu_flvh_length = 2;
1133   }
1134   /* offset should now be pointing to vector (if one exists) */
1135
1136   /* Add pdu item and tree */
1137   ti = proto_tree_add_item(tree, hf_acn_pdu, tvb, pdu_start, pdu_length, FALSE); 
1138   pdu_tree = proto_item_add_subtree(ti, ett_acn_dmp_pdu);
1139
1140   /* Add flag item and tree */
1141   pi = proto_tree_add_uint(pdu_tree, hf_acn_pdu_flags, tvb, pdu_start, 1, pdu_flags);
1142   flag_tree = proto_item_add_subtree(pi, ett_acn_pdu_flags);
1143   proto_tree_add_item(flag_tree, hf_acn_pdu_flag_l, tvb, pdu_start, 1, FALSE);
1144   proto_tree_add_item(flag_tree, hf_acn_pdu_flag_v, tvb, pdu_start, 1, FALSE);
1145   proto_tree_add_item(flag_tree, hf_acn_pdu_flag_h, tvb, pdu_start, 1, FALSE);
1146   proto_tree_add_item(flag_tree, hf_acn_pdu_flag_d, tvb, pdu_start, 1, FALSE);
1147
1148   /* Add PDU Length item */
1149   proto_tree_add_uint(pdu_tree, hf_acn_pdu_length, tvb, pdu_start, pdu_flvh_length, pdu_length);
1150
1151   /* Set vector offset */
1152   if (pdu_flags & ACN_PDU_FLAG_V) {
1153     /* use new values */
1154     vector_offset = offset;
1155     last_pdu_offsets->vector = offset;
1156     offset++;
1157     pdu_flvh_length++;
1158   } else {
1159     /* use last values */
1160     vector_offset = last_pdu_offsets->vector;
1161   }
1162   /* offset should now be pointing to header (if one exists) */
1163
1164   /* Add Vector item */
1165   vector = tvb_get_guint8(tvb, vector_offset);
1166   proto_tree_add_uint(pdu_tree, hf_acn_dmp_vector, tvb, vector_offset, 1, vector);
1167
1168   /* Add Vector item to tree*/
1169   ptr = match_strval(vector, acn_dmp_vector_vals); 
1170   proto_item_append_text(ti, ": ");
1171   proto_item_append_text(ti, ptr);
1172
1173   /* Set header offset */
1174   if (pdu_flags & ACN_PDU_FLAG_H) {
1175     /* use new values */
1176     header_offset = offset;
1177     last_pdu_offsets->header = offset;
1178     offset++;
1179     pdu_flvh_length++;
1180   } else {
1181     /* use last values */
1182     header_offset = last_pdu_offsets->header;
1183   }
1184   /* offset should now be pointing to data (if one exists) */
1185
1186   /* header contains address and data type */
1187   acn_add_dmp_address_type(tvb, pinfo, pdu_tree, header_offset, &adt);
1188
1189   /* Adjust data */
1190   if (pdu_flags & ACN_PDU_FLAG_D) {
1191     /* use new values */
1192     data_offset = offset;
1193     data_length = pdu_length - pdu_flvh_length;
1194     last_pdu_offsets->data = offset;
1195     last_pdu_offsets->data_length = data_length;
1196   } else {
1197     /* use last values */
1198     data_offset = last_pdu_offsets->data;
1199     data_length = last_pdu_offsets->data_length;
1200   }
1201   end_offset = data_offset + data_length;
1202
1203   switch (vector) {
1204   case ACN_DMP_VECTOR_UNKNOWN:
1205     break;
1206   case ACN_DMP_VECTOR_GET_PROPERTY:
1207     /* Rip trough property address */
1208     while (data_offset < end_offset) {
1209       old_offset = data_offset;
1210       data_offset = acn_add_dmp_address(tvb, pinfo, pdu_tree, data_offset, &adt);
1211       if (old_offset == data_offset) break;
1212     }
1213     break;
1214   case ACN_DMP_VECTOR_SET_PROPERTY:
1215     /* Rip through Property Address-Data pairs                                 */
1216     /* But, in reality, this generally won't work as we have know way of       */
1217     /* calculating the next Address-Data pair                                  */
1218     while (data_offset < end_offset) {
1219       old_offset = data_offset;
1220       data_offset = acn_add_dmp_address(tvb, pinfo, pdu_tree, data_offset, &adt);
1221       if (old_offset == data_offset) break;
1222
1223       adt.data_length = data_length - (data_offset - old_offset);
1224       old_offset = data_offset;
1225       data_offset = acn_add_dmp_data(tvb, pinfo, pdu_tree, data_offset, &adt);
1226       if (old_offset == data_offset) break;
1227     }
1228     break;
1229   case ACN_DMP_VECTOR_GET_PROPERTY_REPLY:
1230     /* Rip through Property Address-Data pairs */
1231     /* But, in reality, this generally won't work as we have know way of       */
1232     /* calculating the next Address-Data pair                                  */
1233     while (data_offset < end_offset) {
1234       old_offset = data_offset;
1235       data_offset = acn_add_dmp_address(tvb, pinfo, pdu_tree, data_offset, &adt);
1236       if (old_offset == data_offset) break;
1237
1238
1239       adt.data_length = data_length - (data_offset - old_offset);
1240       old_offset = data_offset;
1241       data_offset = acn_add_dmp_data(tvb, pinfo, pdu_tree, data_offset, &adt);
1242       if (old_offset == data_offset) break;
1243     }
1244     break;
1245   case ACN_DMP_VECTOR_EVENT:
1246     /* Rip through Property Address-Data pairs */
1247     /* But, in reality, this generally won't work as we have know way of       */
1248     /* calculating the next Address-Data pair                                  */
1249     while (data_offset < end_offset) {
1250       old_offset = data_offset;
1251       data_offset = acn_add_dmp_address(tvb, pinfo, pdu_tree, data_offset, &adt);
1252       if (old_offset == data_offset) break;
1253
1254       adt.data_length = data_length - (data_offset - old_offset);
1255       old_offset = data_offset;
1256       data_offset = acn_add_dmp_data(tvb, pinfo, pdu_tree, data_offset, &adt);
1257       if (old_offset == data_offset) break;
1258     }
1259     break;
1260   case ACN_DMP_VECTOR_MAP_PROPERTY:
1261     /* Virtual Address type */
1262     data_offset = acn_add_dmp_address_type(tvb, pinfo, pdu_tree, data_offset, &adt2);
1263     /* Rip through Actual-Virtual Address Pairs */
1264     while (data_offset < end_offset) {
1265       /* actual */
1266       old_offset = data_offset;
1267       data_offset = acn_add_dmp_address(tvb, pinfo, pdu_tree, data_offset, &adt);
1268       if (old_offset == data_offset) break;
1269       D = ACN_DMP_ADT_EXTRACT_D(adt.flags);
1270       switch (D) {
1271         case ACN_DMP_ADT_D_NS:
1272           address_count = 1;
1273           break;
1274         case ACN_DMP_ADT_D_RS:
1275           address_count = 1;
1276           break;
1277         case ACN_DMP_ADT_D_RE:
1278           address_count = adt.count;
1279           break;
1280         /*case ACN_DMP_ADT_D_RM: */
1281         default: 
1282           /* OUCH */
1283           return pdu_start + pdu_length;
1284           break;
1285       }
1286
1287       /* virtual */
1288       while (address_count > 0) {
1289         data_offset = acn_add_dmp_address(tvb, pinfo, pdu_tree, data_offset, &adt2);
1290         address_count--;
1291       }
1292     }
1293     break;
1294   case ACN_DMP_VECTOR_UNMAP_PROPERTY:
1295     /* Rip trough Actaul Proptery Address */
1296     while (data_offset < end_offset) {
1297       old_offset = data_offset;
1298       data_offset = acn_add_dmp_address(tvb, pinfo, pdu_tree, data_offset, &adt);
1299       if (old_offset == data_offset) break;
1300     }
1301     break;
1302   case ACN_DMP_VECTOR_SUBSCRIBE:
1303     /* Rip trough Proptery Address */
1304     while (data_offset < end_offset) {
1305       old_offset = data_offset;
1306       data_offset = acn_add_dmp_address(tvb, pinfo, pdu_tree, data_offset, &adt);
1307       if (old_offset == data_offset) break;
1308     }
1309     break;
1310   case ACN_DMP_VECTOR_UNSUBSCRIBE:
1311     /* Rip trough Proptery Address */
1312     while (data_offset < end_offset) {
1313       old_offset = data_offset;
1314       data_offset = acn_add_dmp_address(tvb, pinfo, pdu_tree, data_offset, &adt);
1315       if (old_offset == data_offset) break;
1316     }
1317     break;
1318   case ACN_DMP_VECTOR_GET_PROPERTY_FAIL:
1319     /* Rip trough Address-Reason Code Pairs */
1320     while (data_offset < end_offset) {
1321       old_offset = data_offset;
1322       data_offset = acn_add_dmp_address(tvb, pinfo, pdu_tree, data_offset, &adt);
1323       if (old_offset == data_offset) break;
1324
1325       adt.data_length = data_length - (data_offset - old_offset);
1326       old_offset = data_offset;
1327       data_offset = acn_add_dmp_reason_codes(tvb, pinfo, pdu_tree, data_offset, &adt);
1328       if (old_offset == data_offset) break;
1329     }
1330     break;
1331   case ACN_DMP_VECTOR_SET_PROPERTY_FAIL:
1332     /* Rip trough Address-Reason Code Pairs */
1333     while (data_offset < end_offset) {
1334       old_offset = data_offset;
1335       data_offset = acn_add_dmp_address(tvb, pinfo, pdu_tree, data_offset, &adt);
1336       if (old_offset == data_offset) break;
1337
1338       adt.data_length = data_length - (data_offset - old_offset);
1339       old_offset = data_offset;
1340       data_offset = acn_add_dmp_reason_codes(tvb, pinfo, pdu_tree, data_offset, &adt);
1341       if (old_offset == data_offset) break;
1342     }
1343     break;
1344   case ACN_DMP_VECTOR_MAP_PROPERTY_FAIL:
1345     /* Rip trough Address-Reason Code Pairs */
1346     while (data_offset < end_offset) {
1347       old_offset = data_offset;
1348       data_offset = acn_add_dmp_address(tvb, pinfo, pdu_tree, data_offset, &adt);
1349       if (old_offset == data_offset) break;
1350
1351       adt.data_length = data_length - (data_offset - old_offset);
1352       old_offset = data_offset;
1353       data_offset = acn_add_dmp_reason_codes(tvb, pinfo, pdu_tree, data_offset, &adt);
1354       if (old_offset == data_offset) break;
1355     }
1356     break;
1357   case ACN_DMP_VECTOR_SUBSCRIBE_ACCEPT:
1358     /* Rip through Property Addrsses */
1359     while (data_offset < end_offset) {
1360       old_offset = data_offset;
1361       data_offset = acn_add_dmp_address(tvb, pinfo, pdu_tree, data_offset, &adt);
1362       if (old_offset == data_offset) break;
1363     }
1364     break;
1365   case ACN_DMP_VECTOR_SUBSCRIBE_REJECT:
1366     /* Rip trough Address-Reason Code Pairs */
1367     while (data_offset < end_offset) {
1368       old_offset = data_offset;
1369       data_offset = acn_add_dmp_address(tvb, pinfo, pdu_tree, data_offset, &adt);
1370       if (old_offset == data_offset) break;
1371
1372       adt.data_length = data_length - (data_offset - old_offset);
1373       old_offset = data_offset;
1374       data_offset = acn_add_dmp_reason_codes(tvb, pinfo, pdu_tree, data_offset, &adt);
1375       if (old_offset == data_offset) break;
1376     }
1377     break;
1378   case ACN_DMP_VECTOR_ALLOCATE_MAP:
1379     /* No data for this */
1380     break;
1381   case ACN_DMP_VECTOR_ALLOCATE_MAP_REPLY:
1382     /* Single reason code  */
1383     proto_tree_add_item(pdu_tree, hf_acn_dmp_reason_code, tvb, data_offset, 1, FALSE);
1384     data_offset++;
1385   case ACN_DMP_VECTOR_DEALLOCATE_MAP:
1386     /* No data for this */
1387     break;
1388   }
1389
1390   return pdu_start + pdu_length;
1391 }
1392
1393
1394 /******************************************************************************/
1395 /* Dissect wrapped SDT PDU                                                    */
1396 static guint32
1397 dissect_acn_sdt_wrapped_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree _U_, int offset, acn_pdu_offsets *last_pdu_offsets)
1398 {
1399   /* common to all pdu */
1400   guint8 pdu_flags;
1401   guint32 pdu_start;
1402   guint32 pdu_length;
1403   guint32 pdu_flvh_length; /* flags, length, vector, header */
1404   acn_pdu_offsets pdu_offsets = {0,0,0,0,0}; 
1405   guint8 octet;
1406   guint32 length1;
1407   guint32 length2;
1408   guint32 length3;
1409   guint32 vector_offset;
1410   guint32 data_offset;
1411   guint32 end_offset;
1412   guint32 data_length;
1413
1414   proto_item *ti, *pi;
1415   proto_tree *pdu_tree = NULL;
1416   proto_tree *flag_tree = NULL;
1417
1418   /* this pdu */
1419   const gchar *ptr;
1420   guint32 vector;
1421
1422   /* save start of pdu block */
1423   pdu_start = offset;
1424   pdu_offsets.start = pdu_start;
1425
1426   /* get PDU flags and length flag first */
1427   octet = tvb_get_guint8(tvb, offset++); 
1428   pdu_flags =  octet & 0xf0;
1429   length1 = octet & 0x0f;                   /* bottom 4 bits only */
1430   length2 = tvb_get_guint8(tvb, offset++);  
1431
1432   /* if length flag is set, then we have a 20 bit length else we have a 12 bit */
1433   /* flvh = flags, length, vector, header */
1434   if (pdu_flags & ACN_PDU_FLAG_L) {
1435     length3 = tvb_get_guint8(tvb, offset);
1436     offset++;
1437     pdu_length = length3 | (length2 << 8) | (length1 << 16);
1438     pdu_flvh_length = 3;
1439   } else {
1440     pdu_length = length2 | (length1 << 8);
1441     pdu_flvh_length = 2;
1442   }
1443   /* offset should now be pointing to vector (if one exists) */
1444
1445   /* Add pdu item and tree */
1446   ti = proto_tree_add_item(tree, hf_acn_pdu, tvb, pdu_start, pdu_length, FALSE); 
1447   pdu_tree = proto_item_add_subtree(ti, ett_acn_sdt_pdu);
1448
1449   /* Add flag item and tree */
1450   pi = proto_tree_add_uint(pdu_tree, hf_acn_pdu_flags, tvb, pdu_start, 1, pdu_flags);
1451   flag_tree = proto_item_add_subtree(pi, ett_acn_pdu_flags);
1452   proto_tree_add_item(flag_tree, hf_acn_pdu_flag_l, tvb, pdu_start, 1, FALSE);
1453   proto_tree_add_item(flag_tree, hf_acn_pdu_flag_v, tvb, pdu_start, 1, FALSE);
1454   proto_tree_add_item(flag_tree, hf_acn_pdu_flag_h, tvb, pdu_start, 1, FALSE);
1455   proto_tree_add_item(flag_tree, hf_acn_pdu_flag_d, tvb, pdu_start, 1, FALSE);
1456
1457   /* Add PDU Length item */
1458   proto_tree_add_uint(pdu_tree, hf_acn_pdu_length, tvb, pdu_start, pdu_flvh_length, pdu_length);
1459
1460   /* Set vector offset */
1461   if (pdu_flags & ACN_PDU_FLAG_V) {
1462     /* use new values */
1463     vector_offset = offset;
1464     last_pdu_offsets->vector = offset;
1465     offset++;
1466     pdu_flvh_length++;
1467   } else {
1468     /* use last values */
1469     vector_offset = last_pdu_offsets->vector;
1470   }
1471   /* offset should now be pointing to header (if one exists) */
1472
1473   /* Add Vector item */
1474   vector = tvb_get_guint8(tvb, vector_offset);
1475   proto_tree_add_uint(pdu_tree, hf_acn_sdt_vector, tvb, vector_offset, 1, vector);
1476
1477   /* Add Vector item to tree*/
1478   ptr = match_strval(vector, acn_sdt_vector_vals); 
1479   proto_item_append_text(ti, ": ");
1480   proto_item_append_text(ti, ptr);
1481
1482   /* NO HEADER DATA ON THESE* (at least so far) */
1483
1484   /* Adjust data */
1485   if (pdu_flags & ACN_PDU_FLAG_D) {
1486     /* use new values */
1487     data_offset = offset;
1488     data_length = pdu_length - pdu_flvh_length;
1489     last_pdu_offsets->data = offset;
1490     last_pdu_offsets->data_length = data_length;
1491   } else {
1492     /* use last values */
1493     data_offset = last_pdu_offsets->data;
1494     data_length = last_pdu_offsets->data_length;
1495   }
1496   end_offset = data_offset + data_length;
1497
1498   switch (vector) {
1499   case ACN_SDT_VECTOR_ACK:
1500     proto_tree_add_item(pdu_tree, hf_acn_reliable_sequence_number, tvb, data_offset, 4, FALSE);
1501     data_offset += 4;
1502     break;
1503   case ACN_SDT_VECTOR_CHANNEL_PARAMS:
1504     data_offset = acn_add_channel_parameter(tvb, pinfo, pdu_tree, data_offset);
1505     data_offset = acn_add_address(tvb, pinfo, pdu_tree, data_offset, "Ad-hoc Address: ");
1506     data_offset = acn_add_expiry(tvb, pinfo, pdu_tree, data_offset, "Ad-hoc Expiry: ");
1507    break;
1508   case ACN_SDT_VECTOR_LEAVE:
1509     /* nothing more */
1510     break;
1511   case ACN_SDT_VECTOR_CONNECT:
1512     /* Protocol ID item */
1513     proto_tree_add_item(pdu_tree, hf_acn_protocol_id, tvb, data_offset, 4, FALSE);
1514     data_offset += 4;
1515     break;
1516   case ACN_SDT_VECTOR_CONNECT_ACCEPT:
1517     /* Protocol ID item */
1518     proto_tree_add_item(pdu_tree, hf_acn_protocol_id, tvb, data_offset, 4, FALSE);
1519     data_offset += 4;
1520     break;
1521   case ACN_SDT_VECTOR_CONNECT_REFUSE:
1522     /* Protocol ID item */
1523     proto_tree_add_item(pdu_tree, hf_acn_protocol_id, tvb, data_offset, 4, FALSE);
1524     data_offset += 4;
1525     proto_tree_add_item(pdu_tree, hf_acn_refuse_code, tvb, data_offset, 1, FALSE);
1526     data_offset++;
1527     break;
1528   case ACN_SDT_VECTOR_DISCONNECT:
1529     /* Protocol ID item */
1530     proto_tree_add_item(pdu_tree, hf_acn_protocol_id, tvb, data_offset, 4, FALSE);
1531     data_offset += 4;
1532     break;
1533   case ACN_SDT_VECTOR_DISCONNECTING:
1534     /* Protocol ID item */
1535     proto_tree_add_item(pdu_tree, hf_acn_protocol_id, tvb, data_offset, 4, FALSE);
1536     data_offset += 4;
1537     proto_tree_add_item(pdu_tree, hf_acn_reason_code, tvb, data_offset, 1, FALSE);
1538     data_offset++;
1539     break;
1540
1541   }
1542
1543   return pdu_start + pdu_length;
1544 }
1545
1546
1547 /******************************************************************************/
1548 /* Dissect SDT Client PDU                                                     */
1549 static guint32
1550 dissect_acn_sdt_client_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, acn_pdu_offsets *last_pdu_offsets)
1551 {
1552   /* common to all pdu */
1553   guint8 pdu_flags;
1554   guint32 pdu_start;
1555   guint32 pdu_length;
1556   guint32 pdu_flvh_length; /* flags, length, vector, header */
1557   acn_pdu_offsets pdu_offsets = {0,0,0,0,0}; 
1558   guint8 octet;
1559   guint32 length1;
1560   guint32 length2;
1561   guint32 length3;
1562   guint32 vector_offset;
1563   guint32 header_offset;
1564   guint32 data_offset;
1565   guint32 data_length;
1566   guint32 old_offset;
1567   guint32 end_offset;
1568
1569   proto_item *ti, *pi;
1570   proto_tree *pdu_tree = NULL;
1571   proto_tree *flag_tree = NULL;
1572
1573   /* this pdu */
1574   const gchar *ptr;
1575   guint32 member_id;
1576   guint32 protocol_id;
1577   guint16 association;
1578
1579   /* save start of pdu block */
1580   pdu_start = offset;
1581   pdu_offsets.start = pdu_start;
1582
1583   /* get PDU flags and length flag first */
1584   octet = tvb_get_guint8(tvb, offset++); 
1585   pdu_flags =  octet & 0xf0;
1586   length1 = octet & 0x0f;                   /* bottom 4 bits only */
1587   length2 = tvb_get_guint8(tvb, offset++);  
1588
1589   /* if length flag is set, then we have a 20 bit length else we have a 12 bit */
1590   /* flvh = flags, length, vector, header */
1591   if (pdu_flags & ACN_PDU_FLAG_L) {
1592     length3 = tvb_get_guint8(tvb, offset);
1593     offset++;
1594     pdu_length = length3 | (length2 << 8) | (length1 << 16);
1595     pdu_flvh_length = 3;
1596   } else {
1597     pdu_length = length2 | (length1 << 8);
1598     pdu_flvh_length = 2;
1599   }
1600   /* offset should now be pointing to vector (if one exists) */
1601
1602   /* Add pdu item and tree */
1603   ti = proto_tree_add_item(tree, hf_acn_pdu, tvb, pdu_start, pdu_length, FALSE); 
1604   pdu_tree = proto_item_add_subtree(ti, ett_acn_sdt_client_pdu);
1605
1606   /* Add flag item and tree */
1607   pi = proto_tree_add_uint(pdu_tree, hf_acn_pdu_flags, tvb, pdu_start, 1, pdu_flags);
1608   flag_tree = proto_item_add_subtree(pi, ett_acn_pdu_flags);
1609   proto_tree_add_item(flag_tree, hf_acn_pdu_flag_l, tvb, pdu_start, 1, FALSE);
1610   proto_tree_add_item(flag_tree, hf_acn_pdu_flag_v, tvb, pdu_start, 1, FALSE);
1611   proto_tree_add_item(flag_tree, hf_acn_pdu_flag_h, tvb, pdu_start, 1, FALSE);
1612   proto_tree_add_item(flag_tree, hf_acn_pdu_flag_d, tvb, pdu_start, 1, FALSE);
1613
1614   /* Add PDU Length item */
1615   proto_tree_add_uint(pdu_tree, hf_acn_pdu_length, tvb, pdu_start, pdu_flvh_length, pdu_length);
1616
1617   /* Set vector offset */
1618   if (pdu_flags & ACN_PDU_FLAG_V) {
1619     /* use new values */
1620     vector_offset = offset;
1621     last_pdu_offsets->vector = offset;
1622     offset += 2;
1623     pdu_flvh_length += 2;
1624   } else {
1625     /* use last values */
1626     vector_offset = last_pdu_offsets->vector;
1627   }
1628   /* offset should now be pointing to header (if one exists) */
1629
1630   /* add Member ID item  */
1631   member_id = tvb_get_ntohs(tvb, vector_offset);
1632   proto_tree_add_uint(pdu_tree, hf_acn_member_id, tvb, vector_offset, 2, member_id);
1633
1634   /* Set header offset */
1635   if (pdu_flags & ACN_PDU_FLAG_H) {
1636     /* use new values */
1637     header_offset = offset;
1638     last_pdu_offsets->header = offset;
1639     offset += 6;
1640     pdu_flvh_length += 6;
1641   } else {
1642     /* use last values */
1643     header_offset = last_pdu_offsets->header;
1644   }
1645   /* offset should now be pointing to data (if one exists) */
1646
1647   /* add Protocol ID item (Header)*/
1648   protocol_id = tvb_get_ntohl(tvb, header_offset);
1649   proto_tree_add_uint(pdu_tree, hf_acn_protocol_id, tvb, header_offset, 4, protocol_id);
1650   header_offset += 4;
1651
1652   /* Add protocol to tree*/
1653   ptr = match_strval(protocol_id, acn_protocol_id_vals); 
1654   proto_item_append_text(ti, ": ");
1655   proto_item_append_text(ti, ptr);
1656
1657   /* add association item */
1658   association = tvb_get_ntohs(tvb, header_offset);
1659   proto_tree_add_uint(pdu_tree, hf_acn_association, tvb, header_offset, 2, association);
1660   header_offset += 2;
1661
1662   /* Adjust data */
1663   if (pdu_flags & ACN_PDU_FLAG_D) {
1664     /* use new values */
1665     data_offset = offset;
1666     data_length = pdu_length - pdu_flvh_length;
1667     last_pdu_offsets->data = offset;
1668     last_pdu_offsets->data_length = data_length;
1669   } else {
1670     /* use last values */
1671     data_offset = last_pdu_offsets->data;
1672     data_length = last_pdu_offsets->data_length;
1673   }
1674   end_offset = data_offset + data_length;
1675
1676   switch (protocol_id) {
1677   case ACN_PROTOCOL_ID_SDT:
1678     while (data_offset < end_offset) {
1679       old_offset = data_offset;
1680       data_offset = dissect_acn_sdt_wrapped_pdu(tvb, pinfo, pdu_tree, data_offset, &pdu_offsets);
1681       if (old_offset == data_offset) break;
1682     }
1683     break;
1684   case ACN_PROTOCOL_ID_DMP:
1685     while (data_offset < end_offset) {
1686       old_offset = data_offset;
1687       data_offset = dissect_acn_dmp_pdu(tvb, pinfo, pdu_tree, data_offset, &pdu_offsets);
1688       if (data_offset == old_offset) break;
1689     }
1690     break;
1691   }
1692   return pdu_start + pdu_length;
1693 }
1694
1695
1696 /******************************************************************************/
1697 /* reverses the characters in a string */
1698 static void
1699 reverse(char *s)
1700 {
1701         char c;
1702   long i,j;
1703   for (i=0, j=strlen(s)-1; i < j; i++, j--) {
1704     c = s[i];
1705     s[i] = s[j];
1706     s[j] = c;
1707   }
1708 }
1709
1710
1711 /******************************************************************************/
1712 /* level to string (ascii)                                                    */
1713 /*  level    : 8 bit value                                                    */
1714 /*  string   : pointer to buffer to fill                                      */
1715 /*  leading_char: character to buffer left of digits                             */
1716 /*  min_char : mininum number of characters (for filling, not including space)*/
1717 /*  show_zero: show zeros or dots                                             */
1718 /* also adds a space to right end                                             */
1719 /*                                                                            */
1720 /*  returns end of string                                                     */
1721 /*  faster than printf()                                                      */
1722 static char *
1723 ltos(guint8 level, gchar *string, guint8 base, gchar leading_char, guint8 min_chars, gboolean show_zero)
1724 {
1725   guint8 i;
1726   /* verify base */
1727   if (base < 2 || base > 16) {
1728     *string = '\0';
1729     return(string);
1730   }
1731   /* deal with zeros */
1732   if ((level == 0) && (!show_zero)) {
1733     for (i=0;i<min_chars;i++) {
1734       string[i] = '.';
1735     }
1736     string[i++] = ' ';
1737     string[i] = '\0';
1738     return(string + i);
1739   }
1740
1741   i = 0;
1742   /* do our convert, comes out backwords! */
1743   do { 
1744     string[i++] = "0123456789ABCDEF"[level % base];
1745   } while ((level /= base) > 0);
1746
1747   /* expand to needed character */
1748   for (;i<min_chars;i++) {
1749     string[i] = leading_char;
1750   }
1751   /* terminate */
1752   string[i] = '\0';
1753
1754   /* now reverse (and correct) the order */
1755   reverse(string);
1756
1757   /* add a space at the end (ok its at the start but it will be at the end)*/
1758   string[i++] = ' ';
1759   string[i] = '\0';
1760   return(string + i);
1761 }
1762
1763
1764 /******************************************************************************/
1765 /* Dissect DMX data PDU                                                       */
1766 static guint32
1767 dissect_acn_dmx_data_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, acn_pdu_offsets *last_pdu_offsets)
1768 {
1769   /* common to all pdu */
1770   guint8 pdu_flags;
1771   guint32 pdu_start;
1772   guint32 pdu_length;
1773   guint32 pdu_flvh_length; /* flags, length, vector, header */
1774   acn_pdu_offsets pdu_offsets = {0,0,0,0,0}; 
1775   guint8 octet;
1776   guint32 length1;
1777   guint32 length2;
1778   guint32 length3;
1779   guint32 vector_offset;
1780   guint32 data_offset;
1781   guint32 end_offset;
1782   guint32 old_offset;
1783   guint32 data_length;
1784   guint32 header_offset;
1785   guint32 total_cnt;
1786   guint32 item_cnt;
1787
1788
1789   proto_item *ti, *pi;
1790   proto_tree *pdu_tree = NULL;
1791   proto_tree *flag_tree = NULL;
1792 /*  proto_tree *addr_tree = NULL; */
1793
1794 /* this pdu */
1795   acn_dmp_adt_type adt = {0,0,0,0,0,0};
1796   const gchar *ptr;
1797   guint32 vector;
1798   char *buffer=NULL;
1799   char *buf_ptr;
1800   guint32 x;
1801   guint8 level;
1802   guint8  min_char;
1803   guint8  base;
1804   gchar   leading_char;
1805
1806
1807   /* save start of pdu block */
1808   pdu_start = offset;
1809   pdu_offsets.start = pdu_start;
1810
1811   /* get PDU flags and length flag first */
1812   octet = tvb_get_guint8(tvb, offset++); 
1813   pdu_flags =  octet & 0xf0;
1814   length1 = octet & 0x0f;                   /* bottom 4 bits only */
1815   length2 = tvb_get_guint8(tvb, offset++);  
1816
1817   /* if length flag is set, then we have a 20 bit length else we have a 12 bit */
1818   /* flvh = flags, length, vector, header */
1819   if (pdu_flags & ACN_PDU_FLAG_L) {
1820     length3 = tvb_get_guint8(tvb, offset);
1821     offset++;
1822     pdu_length = length3 | (length2 << 8) | (length1 << 16);
1823     pdu_flvh_length = 3;
1824   } else {
1825     pdu_length = length2 | (length1 << 8);
1826     pdu_flvh_length = 2;
1827   }
1828   /* offset should now be pointing to vector (if one exists) */
1829
1830   /* Add pdu item and tree */
1831   ti = proto_tree_add_item(tree, hf_acn_pdu, tvb, pdu_start, pdu_length, FALSE); 
1832   pdu_tree = proto_item_add_subtree(ti, ett_acn_dmx_data_pdu);
1833
1834   /* Add flag item and tree */
1835   pi = proto_tree_add_uint(pdu_tree, hf_acn_pdu_flags, tvb, pdu_start, 1, pdu_flags);
1836   flag_tree = proto_item_add_subtree(pi, ett_acn_pdu_flags);
1837   proto_tree_add_item(flag_tree, hf_acn_pdu_flag_l, tvb, pdu_start, 1, FALSE);
1838   proto_tree_add_item(flag_tree, hf_acn_pdu_flag_v, tvb, pdu_start, 1, FALSE);
1839   proto_tree_add_item(flag_tree, hf_acn_pdu_flag_h, tvb, pdu_start, 1, FALSE);
1840   proto_tree_add_item(flag_tree, hf_acn_pdu_flag_d, tvb, pdu_start, 1, FALSE);
1841
1842   /* Add PDU Length item */
1843   proto_tree_add_uint(pdu_tree, hf_acn_pdu_length, tvb, pdu_start, pdu_flvh_length, pdu_length);
1844
1845   /* Set vector offset */
1846   if (pdu_flags & ACN_PDU_FLAG_V) {
1847     /* use new values */
1848     vector_offset = offset;
1849     last_pdu_offsets->vector = offset;
1850     offset += 1;
1851     pdu_flvh_length += 1;
1852   } else {
1853     /* use last values */
1854     vector_offset = last_pdu_offsets->vector;
1855   }
1856   /* offset should now be pointing to header (if one exists) */
1857
1858   /* Add Vector item */
1859   vector = tvb_get_guint8(tvb, vector_offset);
1860   proto_tree_add_uint(pdu_tree, hf_acn_dmp_vector, tvb, vector_offset, 1, vector);
1861
1862   /* Add Vector item to tree*/
1863   ptr = match_strval(vector, acn_dmp_vector_vals); 
1864   proto_item_append_text(ti, ": ");
1865   proto_item_append_text(ti, ptr);
1866
1867   /* Set header offset */
1868   if (pdu_flags & ACN_PDU_FLAG_H) {
1869     /* use new values */
1870     header_offset = offset;
1871     last_pdu_offsets->header = offset;
1872     offset++;
1873     pdu_flvh_length++;
1874   } else {
1875     /* use last values */
1876     header_offset = last_pdu_offsets->header;
1877   }
1878   /* offset should now be pointing to data (if one exists) */
1879
1880   /* process based on vector */
1881   acn_add_dmp_address_type(tvb, pinfo, pdu_tree, header_offset, &adt);
1882
1883   /* Adjust data */
1884   if (pdu_flags & ACN_PDU_FLAG_D) {
1885     /* use new values */
1886     data_offset = offset;
1887     data_length = pdu_length - pdu_flvh_length;
1888     last_pdu_offsets->data = offset;
1889     last_pdu_offsets->data_length = data_length;
1890   } else {
1891     /* use last values */
1892     data_offset = last_pdu_offsets->data;
1893     data_length = last_pdu_offsets->data_length;
1894   }
1895   end_offset = data_offset + data_length;
1896
1897   switch (vector) {
1898     case ACN_DMP_VECTOR_SET_PROPERTY:
1899       old_offset = data_offset;
1900       data_offset = acn_add_dmp_address(tvb, pinfo, pdu_tree, data_offset, &adt);
1901       if (data_offset == old_offset) break;
1902
1903 #define BUFFER_SIZE 128
1904
1905       buffer = ep_alloc(BUFFER_SIZE);
1906       buffer[0] = 0;
1907       buf_ptr = buffer;
1908
1909       /* values base on display mode */
1910       switch ((guint)global_acn_dmx_display_view) {
1911         case ACN_PREF_DMX_DISPLAY_HEX:
1912           min_char = 2;
1913           base = 16;
1914           break;
1915 /*        case ACN_PREF_DMX_DISPLAY_PER: */
1916         default:
1917           min_char = 3;
1918           base = 10;
1919       }
1920
1921       /* do we display leading zeros */
1922       if (global_acn_dmx_display_leading_zeros) {
1923         leading_char = '0';
1924       } else {
1925         leading_char = ' ';
1926       }
1927
1928       /* add a header line */
1929       memset(buffer, ' ', 10);
1930       buf_ptr += 9;
1931       for (x=1;x<=20;x++) {
1932         buf_ptr = ltos((guint8)x, buf_ptr, 10, ' ', min_char, FALSE);
1933         if (x==10) {
1934           *buf_ptr++ =  '|';
1935           *buf_ptr++ =  ' ';
1936         }
1937       }
1938       *buf_ptr = '\0';
1939       proto_tree_add_text(pdu_tree, tvb, data_offset, 0, buffer);
1940
1941       /* start our line */
1942       g_snprintf(buffer, BUFFER_SIZE, "001-020: ");
1943       buf_ptr = buffer + 9;
1944
1945       total_cnt = 0;
1946       item_cnt = 0;
1947       for (x=data_offset; x < end_offset; x++) {
1948         level = tvb_get_guint8(tvb, x);
1949         if (global_acn_dmx_display_view==ACN_PREF_DMX_DISPLAY_PER) {
1950           if ((level > 0) && (level < 3)) {
1951             level = 1;
1952           } else {
1953             level = level * 100 / 255;
1954           }
1955         }
1956         buf_ptr = ltos(level, buf_ptr, base, leading_char, min_char, global_acn_dmx_display_zeros);
1957         total_cnt++;
1958         item_cnt++;
1959
1960         if (item_cnt == 20 || x == (end_offset-1)) {
1961           /* add leader... */
1962           proto_tree_add_text(pdu_tree, tvb, data_offset, item_cnt, buffer);
1963           data_offset += 20;
1964           g_snprintf(buffer, BUFFER_SIZE, "%03d-%03d: ",total_cnt, total_cnt+20);
1965           buf_ptr = buffer + 9;
1966           item_cnt = 0;
1967         } else {
1968           /* add separater character */
1969           if (item_cnt == 10) {
1970             *buf_ptr++ = '|';
1971             *buf_ptr++ = ' ';
1972             *buf_ptr = '\0';
1973           }
1974         }
1975       }
1976     /* NOTE:
1977      address data type                   (fixed at 0xA2)
1978      start code - 1 byte, reserved       (should be 0)
1979                 - 1 byte, start code     (0x255)
1980                 - 2 bytes, packet offset (should be 0000)
1981      address increment - 4 bytes         (ignore)
1982      number of dmx values - 4 bytes      (0-512)
1983      dmx values 0-512 bytes              (data)
1984      */
1985     
1986     break;
1987   }
1988   return pdu_start + pdu_length;
1989 }
1990
1991
1992
1993 /******************************************************************************/
1994 /* Dissect DMX Base PDU                                                       */
1995 static guint32
1996 dissect_acn_dmx_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, acn_pdu_offsets *last_pdu_offsets)
1997 {
1998   /* common to all pdu */
1999   guint8 pdu_flags;
2000   guint32 pdu_start;
2001   guint32 pdu_length;
2002   guint32 pdu_flvh_length; /* flags, length, vector, header */
2003   acn_pdu_offsets pdu_offsets = {0,0,0,0,0}; 
2004   guint8 octet;
2005   guint32 length1;
2006   guint32 length2;
2007   guint32 length3;
2008   guint32 vector_offset;
2009   guint32 data_offset;
2010   guint32 end_offset;
2011   guint32 data_length;
2012
2013   proto_item *ti, *pi;
2014   proto_tree *pdu_tree = NULL;
2015   proto_tree *flag_tree = NULL;
2016
2017 /* this pdu */
2018   guint32 vector;
2019
2020   guint32 universe;
2021   guint32 priority;
2022
2023   /* save start of pdu block */
2024   pdu_start = offset;
2025   pdu_offsets.start = pdu_start;
2026
2027   /* get PDU flags and length flag first */
2028   octet = tvb_get_guint8(tvb, offset++); 
2029   pdu_flags =  octet & 0xf0;
2030   length1 = octet & 0x0f;                   /* bottom 4 bits only */
2031   length2 = tvb_get_guint8(tvb, offset++);  
2032
2033   /* if length flag is set, then we have a 20 bit length else we have a 12 bit */
2034   /* flvh = flags, length, vector, header */
2035   if (pdu_flags & ACN_PDU_FLAG_L) {
2036     length3 = tvb_get_guint8(tvb, offset);
2037     offset++;
2038     pdu_length = length3 | (length2 << 8) | (length1 << 16);
2039     pdu_flvh_length = 3;
2040   } else {
2041     pdu_length = length2 | (length1 << 8);
2042     pdu_flvh_length = 2;
2043   }
2044
2045   /* offset should now be pointing to vector (if one exists) */
2046
2047   /* Add pdu item and tree */
2048   ti = proto_tree_add_item(tree, hf_acn_pdu, tvb, pdu_start, pdu_length, FALSE); 
2049   pdu_tree = proto_item_add_subtree(ti, ett_acn_dmx_pdu);
2050
2051   /* Add flag item and tree */
2052   pi = proto_tree_add_uint(pdu_tree, hf_acn_pdu_flags, tvb, pdu_start, 1, pdu_flags);
2053   flag_tree = proto_item_add_subtree(pi, ett_acn_pdu_flags);
2054   proto_tree_add_item(flag_tree, hf_acn_pdu_flag_l, tvb, pdu_start, 1, FALSE);
2055   proto_tree_add_item(flag_tree, hf_acn_pdu_flag_v, tvb, pdu_start, 1, FALSE);
2056   proto_tree_add_item(flag_tree, hf_acn_pdu_flag_h, tvb, pdu_start, 1, FALSE);
2057   proto_tree_add_item(flag_tree, hf_acn_pdu_flag_d, tvb, pdu_start, 1, FALSE);
2058
2059   /* Add PDU Length item */
2060   proto_tree_add_uint(pdu_tree, hf_acn_pdu_length, tvb, pdu_start, pdu_flvh_length, pdu_length);
2061
2062   /* Set vector offset */
2063   if (pdu_flags & ACN_PDU_FLAG_V) {
2064     /* use new values */
2065     vector_offset = offset;
2066     last_pdu_offsets->vector = offset;
2067     offset += 4;
2068     pdu_flvh_length += 4;
2069   } else {
2070     /* use last values */
2071     vector_offset = last_pdu_offsets->vector;
2072   }
2073   /* offset should now be pointing to header (if one exists) */
2074
2075   /* Add Vector item */
2076   vector = tvb_get_ntohl(tvb, vector_offset);
2077   proto_tree_add_item(pdu_tree, hf_acn_dmx_vector, tvb, vector_offset, 4, FALSE);
2078   /* vector_offset +=4; */
2079
2080   /* Add Vector item to tree*/
2081   proto_item_append_text(ti, ": %s", match_strval(vector, acn_dmx_vector_vals));
2082
2083   /* NO HEADER DATA ON THESE* (at least so far) */
2084
2085   /* Adjust data */
2086   if (pdu_flags & ACN_PDU_FLAG_D) {
2087     /* use new values */
2088     data_offset = offset;
2089     data_length = pdu_length - pdu_flvh_length;
2090     last_pdu_offsets->data = offset;
2091     last_pdu_offsets->data_length = data_length;
2092   } else {
2093     /* use last values */
2094     data_offset = last_pdu_offsets->data;
2095     data_length = last_pdu_offsets->data_length;
2096   }
2097   end_offset = data_offset + data_length;
2098
2099   /* process based on vector */
2100   switch (vector) {
2101   case 0x02:
2102     proto_tree_add_item(pdu_tree, hf_acn_dmx_source_name, tvb, data_offset, 32, FALSE);
2103     data_offset += 32;
2104
2105     priority = tvb_get_guint8(tvb, data_offset); 
2106     proto_tree_add_item(pdu_tree, hf_acn_dmx_priority, tvb, data_offset, 1, FALSE);
2107     data_offset += 1;
2108
2109     proto_tree_add_item(pdu_tree, hf_acn_dmx_sequence_number, tvb, data_offset, 1, FALSE);
2110     data_offset += 1;
2111
2112     universe = tvb_get_ntohs(tvb, data_offset); 
2113     proto_tree_add_item(pdu_tree, hf_acn_dmx_universe       , tvb, data_offset, 2, FALSE);
2114     data_offset += 2;
2115
2116     proto_item_append_text(ti, ", Universe: %d, Priority: %d", universe, priority);
2117
2118     data_offset = dissect_acn_dmx_data_pdu(tvb, pinfo, pdu_tree, data_offset, &pdu_offsets);
2119
2120     break;
2121   }
2122   return pdu_start + pdu_length;
2123 }
2124
2125 /******************************************************************************/
2126 /* Dissect SDT Base PDU                                                       */
2127 static guint32
2128 dissect_acn_sdt_base_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, acn_pdu_offsets *last_pdu_offsets)
2129 {
2130   /* common to all pdu */
2131   guint8 pdu_flags;
2132   guint32 pdu_start;
2133   guint32 pdu_length;
2134   guint32 pdu_flvh_length; /* flags, length, vector, header */
2135   acn_pdu_offsets pdu_offsets = {0,0,0,0,0}; 
2136   guint8 octet;
2137   guint32 length1;
2138   guint32 length2;
2139   guint32 length3;
2140   guint32 vector_offset;
2141   guint32 data_offset;
2142   guint32 end_offset;
2143   guint32 old_offset;
2144   guint32 data_length;
2145
2146   proto_item *ti, *pi;
2147   proto_tree *pdu_tree = NULL;
2148   proto_tree *flag_tree = NULL;
2149
2150   /* this pdu */
2151   const gchar *ptr;
2152   guint32 vector;
2153   guint32 member_id;
2154
2155   /* save start of pdu block */
2156   pdu_start = offset;
2157   pdu_offsets.start = pdu_start;
2158
2159   /* get PDU flags and length flag first */
2160   octet = tvb_get_guint8(tvb, offset++); 
2161   pdu_flags =  octet & 0xf0;
2162   length1 = octet & 0x0f;                   /* bottom 4 bits only */
2163   length2 = tvb_get_guint8(tvb, offset++);  
2164
2165   /* if length flag is set, then we have a 20 bit length else we have a 12 bit */
2166   /* flvh = flags, length, vector, header */
2167   if (pdu_flags & ACN_PDU_FLAG_L) {
2168     length3 = tvb_get_guint8(tvb, offset);
2169     offset++; 
2170     pdu_length = length3 | (length2 << 8) | (length1 << 16);
2171     pdu_flvh_length = 3;
2172   } else {
2173     pdu_length = length2 | (length1 << 8);
2174     pdu_flvh_length = 2;
2175   }
2176   /* offset should now be pointing to vector (if one exists) */
2177
2178   /* Add pdu item and tree */
2179   ti = proto_tree_add_item(tree, hf_acn_pdu, tvb, pdu_start, pdu_length, FALSE); 
2180   pdu_tree = proto_item_add_subtree(ti, ett_acn_sdt_base_pdu);
2181
2182   /* Add flag item and tree */
2183   pi = proto_tree_add_uint(pdu_tree, hf_acn_pdu_flags, tvb, pdu_start, 1, pdu_flags);
2184   flag_tree = proto_item_add_subtree(pi, ett_acn_pdu_flags);
2185   proto_tree_add_item(flag_tree, hf_acn_pdu_flag_l, tvb, pdu_start, 1, FALSE);
2186   proto_tree_add_item(flag_tree, hf_acn_pdu_flag_v, tvb, pdu_start, 1, FALSE);
2187   proto_tree_add_item(flag_tree, hf_acn_pdu_flag_h, tvb, pdu_start, 1, FALSE);
2188   proto_tree_add_item(flag_tree, hf_acn_pdu_flag_d, tvb, pdu_start, 1, FALSE);
2189
2190   /* Add PDU Length item */
2191   proto_tree_add_uint(pdu_tree, hf_acn_pdu_length, tvb, pdu_start, pdu_flvh_length, pdu_length);
2192
2193   /* Set vector offset */
2194   if (pdu_flags & ACN_PDU_FLAG_V) {
2195     /* use new values */
2196     vector_offset = offset;
2197     last_pdu_offsets->vector = offset;
2198     offset++;
2199     pdu_flvh_length++;
2200   } else {
2201     /* use last values */
2202     vector_offset = last_pdu_offsets->vector;
2203   }
2204   /* offset should now be pointing to header (if one exists) */
2205
2206   /* Add Vector item */
2207   vector = tvb_get_guint8(tvb, vector_offset);
2208   proto_tree_add_uint(pdu_tree, hf_acn_sdt_vector, tvb, vector_offset, 1, vector);
2209
2210   /* Add Vector item to tree*/
2211   ptr = match_strval(vector, acn_sdt_vector_vals); 
2212   proto_item_append_text(ti, ": ");
2213   proto_item_append_text(ti, ptr);
2214
2215   /* NO HEADER DATA ON THESE* (at least so far) */
2216
2217   /* Adjust data */
2218   if (pdu_flags & ACN_PDU_FLAG_D) {
2219     /* use new values */
2220     data_offset = offset;
2221     data_length = pdu_length - pdu_flvh_length;
2222     last_pdu_offsets->data = offset;
2223     last_pdu_offsets->data_length = data_length;
2224   } else {
2225     /* use last values */
2226     data_offset = last_pdu_offsets->data;
2227     data_length = last_pdu_offsets->data_length;
2228   }
2229   end_offset = data_offset + data_length;
2230
2231   /* process based on vector */
2232   switch (vector) {
2233   case ACN_SDT_VECTOR_UNKNOWN:
2234     break;
2235   case ACN_SDT_VECTOR_REL_WRAP:
2236   case ACN_SDT_VECTOR_UNREL_WRAP: 
2237     proto_tree_add_item(pdu_tree, hf_acn_channel_number, tvb, data_offset, 2, FALSE);
2238     data_offset += 2;
2239     proto_tree_add_item(pdu_tree, hf_acn_total_sequence_number, tvb, data_offset, 4, FALSE);
2240     data_offset += 4;
2241     proto_tree_add_item(pdu_tree, hf_acn_reliable_sequence_number, tvb, data_offset, 4, FALSE);
2242     data_offset += 4;
2243     proto_tree_add_item(pdu_tree, hf_acn_oldest_available_wrapper, tvb, data_offset, 4, FALSE);
2244     data_offset += 4;
2245     proto_tree_add_item(pdu_tree, hf_acn_first_memeber_to_ack, tvb, data_offset, 2, FALSE);
2246     data_offset += 2;
2247     proto_tree_add_item(pdu_tree, hf_acn_last_memeber_to_ack, tvb, data_offset, 2, FALSE);
2248     data_offset += 2;
2249     proto_tree_add_item(pdu_tree, hf_acn_mak_threshold, tvb, data_offset, 2, FALSE);
2250     data_offset += 2;
2251
2252     while (data_offset < end_offset) {
2253       old_offset = data_offset;
2254       data_offset = dissect_acn_sdt_client_pdu(tvb, pinfo, pdu_tree, data_offset, &pdu_offsets);
2255       if (data_offset == old_offset) break;
2256     }
2257     break;
2258   case ACN_SDT_VECTOR_CHANNEL_PARAMS:
2259     break;
2260   case ACN_SDT_VECTOR_JOIN:
2261     proto_tree_add_item(pdu_tree, hf_acn_cid, tvb, data_offset, 16, FALSE);
2262     data_offset += 16;
2263     proto_tree_add_item(pdu_tree, hf_acn_member_id, tvb, data_offset, 2, FALSE);
2264     data_offset += 2;
2265     proto_tree_add_item(pdu_tree, hf_acn_channel_number, tvb, data_offset, 2, FALSE);
2266     data_offset += 2;
2267     proto_tree_add_item(pdu_tree, hf_acn_reciprocal_channel, tvb, data_offset, 2, FALSE);
2268     data_offset += 2;
2269     proto_tree_add_item(pdu_tree, hf_acn_total_sequence_number, tvb, data_offset, 4, FALSE);
2270     data_offset += 4;
2271     proto_tree_add_item(pdu_tree, hf_acn_reliable_sequence_number, tvb, data_offset, 4, FALSE);
2272     data_offset += 4;
2273     data_offset = acn_add_address(tvb, pinfo, pdu_tree, data_offset, "Destination Address: ");
2274     data_offset = acn_add_channel_parameter(tvb, pinfo, pdu_tree, data_offset);
2275     data_offset = acn_add_expiry(tvb, pinfo, pdu_tree, data_offset, "Ad-hoc Expiry: ");
2276     break;
2277   case ACN_SDT_VECTOR_JOIN_REFUSE:
2278     pi = proto_tree_add_item(pdu_tree, hf_acn_cid, tvb, data_offset, 16, FALSE);
2279     data_offset += 16;
2280     proto_item_append_text(pi, "(Leader)");
2281     proto_tree_add_item(pdu_tree, hf_acn_channel_number, tvb, data_offset, 2, FALSE);
2282     data_offset += 2;
2283     proto_tree_add_item(pdu_tree, hf_acn_member_id, tvb, data_offset, 2, FALSE);
2284     data_offset += 2;
2285     proto_tree_add_item(pdu_tree, hf_acn_reliable_sequence_number, tvb, data_offset, 4, FALSE);
2286     data_offset += 4;
2287     proto_tree_add_item(pdu_tree, hf_acn_refuse_code, tvb, data_offset, 1, FALSE);
2288     data_offset ++;
2289     break;
2290   case ACN_SDT_VECTOR_JOIN_ACCEPT:
2291     pi = proto_tree_add_item(pdu_tree, hf_acn_cid, tvb, data_offset, 16, FALSE);
2292     data_offset += 16;
2293     proto_item_append_text(pi, "(Leader)");
2294     proto_tree_add_item(pdu_tree, hf_acn_channel_number, tvb, data_offset, 2, FALSE);
2295     data_offset += 2;
2296     proto_tree_add_item(pdu_tree, hf_acn_member_id, tvb, data_offset, 2, FALSE);
2297     data_offset += 2;
2298     proto_tree_add_item(pdu_tree, hf_acn_reliable_sequence_number, tvb, data_offset, 4, FALSE);
2299     data_offset += 4;
2300     proto_tree_add_item(pdu_tree, hf_acn_reciprocal_channel, tvb, data_offset, 2, FALSE);
2301     data_offset += 2;
2302     break;
2303   case ACN_SDT_VECTOR_LEAVE:
2304     break;
2305   case ACN_SDT_VECTOR_LEAVING:
2306     pi = proto_tree_add_item(pdu_tree, hf_acn_cid, tvb, data_offset, 16, FALSE);
2307     data_offset += 16;
2308     proto_item_append_text(pi, "(Leader)");
2309     proto_tree_add_item(pdu_tree, hf_acn_channel_number, tvb, data_offset, 2, FALSE);
2310     data_offset += 2;
2311     proto_tree_add_item(pdu_tree, hf_acn_member_id, tvb, data_offset, 2, FALSE);
2312     data_offset += 2;
2313     proto_tree_add_item(pdu_tree, hf_acn_reliable_sequence_number, tvb, data_offset, 4, FALSE);
2314     data_offset += 4;
2315     proto_tree_add_item(pdu_tree, hf_acn_reason_code, tvb, data_offset, 1, FALSE);
2316     offset++;
2317     break;
2318   case ACN_SDT_VECTOR_CONNECT:
2319     break;
2320   case ACN_SDT_VECTOR_CONNECT_ACCEPT:
2321     break;
2322   case ACN_SDT_VECTOR_CONNECT_REFUSE:
2323     break;
2324   case ACN_SDT_VECTOR_DISCONNECT:
2325     break;
2326   case ACN_SDT_VECTOR_DISCONNECTING:
2327     break;
2328   case ACN_SDT_VECTOR_ACK:
2329     break;
2330   case ACN_SDT_VECTOR_NAK:
2331     pi = proto_tree_add_item(pdu_tree, hf_acn_cid, tvb, data_offset, 16, FALSE);
2332     data_offset += 16;
2333     proto_item_append_text(pi, "(Leader)");
2334     proto_tree_add_item(pdu_tree, hf_acn_channel_number, tvb, data_offset, 2, FALSE);
2335     data_offset += 2;
2336     proto_tree_add_item(pdu_tree, hf_acn_member_id, tvb, data_offset, 2, FALSE);
2337     data_offset += 2;
2338     proto_tree_add_item(pdu_tree, hf_acn_reliable_sequence_number, tvb, data_offset, 4, FALSE);
2339     data_offset += 4;
2340     proto_tree_add_item(pdu_tree, hf_acn_first_missed_sequence, tvb, data_offset, 4, FALSE);
2341     data_offset += 4;
2342     proto_tree_add_item(pdu_tree, hf_acn_last_missed_sequence, tvb, data_offset, 4, FALSE);
2343     data_offset += 4;
2344     break;
2345   case ACN_SDT_VECTOR_GET_SESSION:
2346     proto_tree_add_item(pdu_tree, hf_acn_cid, tvb, data_offset, 16, FALSE);
2347     data_offset += 16;
2348     break;
2349   case ACN_SDT_VECTOR_SESSIONS:
2350     member_id = tvb_get_ntohs(tvb, data_offset);
2351     switch (member_id) {
2352     case 0:
2353       data_offset = acn_add_channel_owner_info_block(tvb, pinfo, pdu_tree, data_offset);
2354       break;
2355     case 1:
2356       data_offset = acn_add_channel_member_info_block(tvb, pinfo, pdu_tree, data_offset);
2357       break;
2358     }
2359     break;
2360   }
2361
2362   return pdu_start + pdu_length;
2363 }
2364
2365 /******************************************************************************/
2366 /* Dissect Root PDU                                                           */
2367 static guint32
2368 dissect_acn_root_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, acn_pdu_offsets *last_pdu_offsets)
2369 {
2370   /* common to all pdu */
2371   guint8 pdu_flags;
2372   guint32 pdu_start;
2373   guint32 pdu_length;
2374   guint32 pdu_flvh_length; /* flags, length, vector, header */
2375   acn_pdu_offsets pdu_offsets = {0,0,0,0,0}; 
2376   guint8 octet;
2377   guint32 length1;
2378   guint32 length2;
2379   guint32 length3;
2380   guint32 vector_offset;
2381   guint32 header_offset;
2382   guint32 data_offset;
2383   guint32 end_offset;
2384   guint32 old_offset;
2385   guint32 data_length;
2386
2387   proto_item *ti, *pi;
2388   proto_tree *pdu_tree = NULL;
2389   proto_tree *flag_tree = NULL;
2390
2391   /* this pdu */
2392   guint32 protocol_id;
2393   e_guid_t guid;
2394   gchar buf[GUID_STR_LEN];
2395
2396   /* save start of pdu block */
2397   pdu_start = offset;
2398   pdu_offsets.start = pdu_start;
2399
2400   /* get PDU flags and length flag first */
2401   octet = tvb_get_guint8(tvb, offset++); 
2402   pdu_flags =  octet & 0xf0;
2403   length1 = octet & 0x0f;                   /* bottom 4 bits only */
2404   length2 = tvb_get_guint8(tvb, offset++);  
2405
2406   /* if length flag is set, then we have a 20 bit length else we have a 12 bit */
2407   /* flvh = flags, length, vector, header */
2408   if (pdu_flags & ACN_PDU_FLAG_L) {
2409     length3 = tvb_get_guint8(tvb, offset);
2410     offset++;
2411     pdu_length = length3 | (length2 << 8) | (length1 << 16);
2412     pdu_flvh_length = 3;
2413   } else {
2414     pdu_length = length2 | (length1 << 8);
2415     pdu_flvh_length = 2;
2416   }
2417   /* offset should now be pointing to vector (if one exists) */
2418
2419   /* Add pdu item and tree */
2420   ti = proto_tree_add_item(tree, hf_acn_pdu, tvb, pdu_start, pdu_length, FALSE); 
2421   pdu_tree = proto_item_add_subtree(ti, ett_acn_root_pdu);
2422
2423   /* Add flag item and tree */
2424   pi = proto_tree_add_uint(pdu_tree, hf_acn_pdu_flags, tvb, pdu_start, 1, pdu_flags);
2425   flag_tree = proto_item_add_subtree(pi, ett_acn_pdu_flags);
2426   proto_tree_add_item(flag_tree, hf_acn_pdu_flag_l, tvb, pdu_start, 1, FALSE);
2427   proto_tree_add_item(flag_tree, hf_acn_pdu_flag_v, tvb, pdu_start, 1, FALSE);
2428   proto_tree_add_item(flag_tree, hf_acn_pdu_flag_h, tvb, pdu_start, 1, FALSE);
2429   proto_tree_add_item(flag_tree, hf_acn_pdu_flag_d, tvb, pdu_start, 1, FALSE);
2430
2431   /* Add PDU Length item */
2432   proto_tree_add_uint(pdu_tree, hf_acn_pdu_length, tvb, pdu_start, pdu_flvh_length, pdu_length);
2433
2434   /* Set vector offset */
2435   if (pdu_flags & ACN_PDU_FLAG_V) {
2436     /* use new values */
2437     vector_offset = offset;
2438     last_pdu_offsets->vector = offset;
2439     offset += 4;
2440     pdu_flvh_length += 4;
2441   } else {
2442     /* use last values */
2443     vector_offset = last_pdu_offsets->vector;
2444   }
2445   /* offset should now be pointing to header (if one exists) */
2446
2447
2448
2449   /* Get Protocol ID (vector) */
2450   protocol_id = tvb_get_ntohl(tvb, vector_offset);
2451   proto_tree_add_uint(pdu_tree, hf_acn_protocol_id, tvb, vector_offset, 4, protocol_id);
2452   
2453   /* process based on protocol_id */
2454   switch (protocol_id) {
2455   case ACN_PROTOCOL_ID_DMX:
2456     if (global_acn_dmx_enable) {
2457       proto_item_append_text(ti,": Root DMX");
2458   
2459       /* Set header offset */
2460       if (pdu_flags & ACN_PDU_FLAG_H) {
2461         /* use new values */
2462         header_offset = offset;
2463         last_pdu_offsets->header = offset;
2464         offset += 16;
2465         pdu_flvh_length += 16;
2466       } else {
2467         /* use last values */
2468         header_offset = last_pdu_offsets->header;
2469       }
2470       /* offset should now be pointing to data (if one exists) */
2471   
2472       /* get Header (CID) 16 bytes */
2473       tvb_get_guid(tvb, header_offset, &guid, FALSE);
2474       guid_to_str_buf(&guid, buf, sizeof(buf));
2475       proto_item_append_text(ti, ", Src: %s", buf);
2476       proto_tree_add_item(pdu_tree, hf_acn_cid, tvb, header_offset, 16, FALSE);
2477       header_offset += 16;
2478   
2479       /* Adjust data */
2480       if (pdu_flags & ACN_PDU_FLAG_D) {
2481         /* use new values */
2482         data_offset = offset;
2483         data_length = pdu_length - pdu_flvh_length;
2484         last_pdu_offsets->data = offset;
2485         last_pdu_offsets->data_length = data_length;
2486       } else {
2487         /* use last values */
2488         data_offset = last_pdu_offsets->data;
2489         data_length = last_pdu_offsets->data_length;
2490       }
2491       end_offset = data_offset + data_length; 
2492
2493       /* adjust for what we used */
2494       while (data_offset < end_offset) {
2495         old_offset = data_offset;
2496         data_offset = dissect_acn_dmx_pdu(tvb, pinfo, pdu_tree, data_offset, &pdu_offsets);
2497         if (data_offset == old_offset) break;
2498       }
2499     }
2500     break;
2501   case ACN_PROTOCOL_ID_SDT:
2502     /* Adjust header */
2503     proto_item_append_text(ti,": Root SDT");
2504
2505     /* Set header offset */
2506     if (pdu_flags & ACN_PDU_FLAG_H) {
2507       /* use new values */
2508       header_offset = offset;
2509       last_pdu_offsets->header = offset;
2510       offset += 16;
2511       pdu_flvh_length += 16;
2512     } else {
2513       /* use last values */
2514       header_offset = last_pdu_offsets->header;
2515     }
2516     /* offset should now be pointing to data (if one exists) */
2517
2518     /* get Header (CID) 16 bytes */
2519     tvb_get_guid(tvb, header_offset, &guid, FALSE);
2520     guid_to_str_buf(&guid, buf, sizeof(buf));
2521     proto_item_append_text(ti, ", Src: %s", buf);
2522     proto_tree_add_item(pdu_tree, hf_acn_cid, tvb, header_offset, 16, FALSE);
2523     header_offset += 16;
2524
2525     /* Adjust data */
2526     if (pdu_flags & ACN_PDU_FLAG_D) {
2527       /* use new values */
2528       data_offset = offset;
2529       data_length = pdu_length - pdu_flvh_length;
2530       last_pdu_offsets->data = offset;
2531       last_pdu_offsets->data_length = data_length;
2532     } else {
2533       /* use last values */
2534       data_offset = last_pdu_offsets->data;
2535       data_length = last_pdu_offsets->data_length;
2536     }
2537     end_offset = data_offset + data_length;
2538
2539     /* adjust for what we used */
2540     while (data_offset < end_offset) {
2541       old_offset = data_offset;
2542       data_offset = dissect_acn_sdt_base_pdu(tvb, pinfo, pdu_tree, data_offset, &pdu_offsets);
2543       if (data_offset == old_offset) break;
2544     }
2545     break;
2546   }
2547
2548   return pdu_start + pdu_length;
2549 }
2550
2551 /******************************************************************************/
2552 /* Dissect ACN                                                                */
2553 static int
2554 dissect_acn(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
2555 {
2556   proto_item *ti = NULL;
2557   proto_tree *acn_tree = NULL;
2558   guint32 data_offset = 0;
2559   guint32 old_offset;
2560   guint32 end_offset;
2561   acn_pdu_offsets pdu_offsets = {0,0,0,0,0}; 
2562
2563 /*   if (!is_acn(tvb)) { */
2564 /*     return 0;         */
2565 /*   }                   */
2566
2567   /* Set the protocol column */
2568   if (check_col(pinfo->cinfo, COL_PROTOCOL)) {
2569     col_set_str(pinfo->cinfo, COL_PROTOCOL, "ACN");
2570   }
2571
2572   /* Clear out stuff in the info column */
2573   if(check_col(pinfo->cinfo,COL_INFO)){
2574   /* col_clear(pinfo->cinfo,COL_INFO); */
2575     col_add_fstr(pinfo->cinfo,COL_INFO, "ACN [Src Port: %d, Dst Port: %d]", pinfo->srcport, pinfo->destport );
2576   }
2577
2578   if (tree) { /* we are being asked for details */
2579     ti = proto_tree_add_item(tree, proto_acn, tvb, 0, -1, FALSE);
2580     acn_tree = proto_item_add_subtree(ti, ett_acn);
2581
2582     pdu_offsets.start = data_offset;
2583
2584     /* add preamble, postamble and ACN Packet ID */
2585     proto_tree_add_item(acn_tree, hf_acn_preamble_size, tvb, data_offset, 2, FALSE);
2586     data_offset += 2;
2587     proto_tree_add_item(acn_tree, hf_acn_postamble_size, tvb, data_offset, 2, FALSE);
2588     data_offset += 2;
2589     proto_tree_add_item(acn_tree, hf_acn_packet_identifier, tvb, data_offset, 12, FALSE);
2590     data_offset += 12;
2591
2592     /* one past the last byte */
2593     end_offset = data_offset + tvb_reported_length_remaining(tvb, data_offset);
2594     while (data_offset < end_offset) {
2595       old_offset = data_offset;
2596       data_offset = dissect_acn_root_pdu(tvb, pinfo, acn_tree, data_offset, &pdu_offsets);
2597       if (data_offset == old_offset) break;
2598     }
2599   }
2600   return tvb_length(tvb);
2601 }
2602
2603 /******************************************************************************/
2604 /* Register protocol                                                          */
2605 void proto_register_acn(void)
2606 {
2607   static hf_register_info hf[] = {
2608     /**************************************************************************/
2609     /* In alphabetical order */
2610     /* Address Type */
2611     /* PDU flags*/
2612     { &hf_acn_ip_address_type,
2613       { "Type", "acn.ip_address_type",
2614         FT_UINT8, BASE_DEC, VALS(acn_ip_address_type_vals), 0x0,
2615         "Type", HFILL }
2616     },
2617     /* Association */
2618     { &hf_acn_association,
2619       { "Association", "acn.association",
2620         FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
2621         "Association", HFILL }
2622     },
2623     /* Channel Number */
2624     { &hf_acn_channel_number,
2625       { "Channel Number", "acn.channel_number",
2626         FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
2627         "Channel Number", HFILL }
2628     },
2629     /* CID */
2630     { &hf_acn_cid,
2631       { "CID", "acn.cid",
2632         FT_GUID, BASE_NONE, NULL, 0x0,
2633         NULL, HFILL }
2634     },
2635     /* Client Protocol ID */
2636     { &hf_acn_client_protocol_id,
2637       { "Client Protocol ID", "acn.client_protocol_id",
2638         FT_UINT32, BASE_DEC, VALS(acn_protocol_id_vals), 0x0,
2639         "ClientProtocol ID", HFILL }
2640     },
2641     /* DMP data */
2642     { &hf_acn_data,
2643       { "Data", "acn.dmp_data",
2644         FT_BYTES, BASE_HEX, NULL, 0x0,
2645         "Data", HFILL }
2646     },
2647     { &hf_acn_data8,
2648       { "Addr", "acn.dmp_data8",
2649         FT_INT8, BASE_DEC_HEX, NULL, 0x0,
2650         "Data8", HFILL }
2651     },
2652     { &hf_acn_data16,
2653       { "Addr", "acn.dmp_data16",
2654         FT_INT16, BASE_DEC_HEX, NULL, 0x0,
2655         "Data16", HFILL }
2656     },
2657     { &hf_acn_data24,
2658       { "Addr", "acn.dmp_data24",
2659         FT_INT24, BASE_DEC_HEX, NULL, 0x0,
2660         "Data24", HFILL }
2661     },
2662     { &hf_acn_data32,
2663       { "Addr", "acn.dmp_data32",
2664         FT_INT32, BASE_DEC_HEX, NULL, 0x0,
2665         "Data32", HFILL }
2666     },
2667
2668     { &hf_acn_dmp_address_data_pairs,
2669       { "Address-Data Pairs", "acn.dmp_address_data_pairs",
2670         FT_BYTES, BASE_DEC, NULL, 0x0,
2671         "More address-data pairs", HFILL }
2672     },
2673
2674     /* DMP Address */
2675     { &hf_acn_dmp_address1,
2676       { "Address", "acn.dmp_address",
2677         FT_UINT8, BASE_DEC_HEX, NULL, 0x0,
2678         "Address", HFILL }
2679     },
2680     { &hf_acn_dmp_address2,
2681       { "Address", "acn.dmp_address",
2682         FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
2683         "Address", HFILL }
2684     },
2685     { &hf_acn_dmp_address4,
2686       { "Address", "acn.dmp_address",
2687         FT_UINT32, BASE_DEC_HEX, NULL, 0x0,
2688         "Address", HFILL }
2689     },
2690
2691     /* DMP Address type*/
2692     { &hf_acn_dmp_adt,
2693       { "Address and Data Type", "acn.dmp_adt",
2694         FT_UINT8, BASE_DEC_HEX, NULL, 0x0,
2695         "Address and Data Type", HFILL }
2696     },
2697     { &hf_acn_dmp_adt_a,
2698       { "Size", "acn.dmp_adt_a",
2699         FT_UINT8, BASE_DEC, VALS(acn_dmp_adt_a_vals), 0x03,
2700         "Size", HFILL }
2701     },
2702     { &hf_acn_dmp_adt_d,
2703       { "Data Type", "acn.dmp_adt_d",
2704         FT_UINT8, BASE_DEC, VALS(acn_dmp_adt_d_vals), 0x30,
2705         "Data Type", HFILL }
2706     },
2707     { &hf_acn_dmp_adt_r,
2708       { "Relative", "acn.dmp_adt_r",
2709         FT_UINT8, BASE_DEC, VALS(acn_dmp_adt_r_vals), 0x40,
2710         "Relative", HFILL }
2711     },
2712     { &hf_acn_dmp_adt_v,
2713       { "Virtual", "acn.dmp_adt_v",
2714         FT_UINT8, BASE_DEC, VALS(acn_dmp_adt_v_vals), 0x80,
2715         "Virtual", HFILL }
2716     },
2717     { &hf_acn_dmp_adt_x,
2718       { "Reserved", "acn.dmp_adt_x",
2719         FT_UINT8, BASE_DEC, NULL, 0x0c,
2720         "Reserved", HFILL }
2721     },
2722
2723     /* DMP Reason Code */
2724     { &hf_acn_dmp_reason_code,
2725       { "Reason Code", "acn.dmp_reason_code",
2726         FT_UINT8, BASE_DEC, VALS(acn_dmp_reason_code_vals), 0x0,
2727         "Reason Code", HFILL }
2728     },
2729
2730     /* DMP Vector */
2731     { &hf_acn_dmp_vector,
2732       { "DMP Vector", "acn.dmp_vector",
2733         FT_UINT8, BASE_DEC, VALS(acn_dmp_vector_vals), 0x0,
2734         "DMP Vector", HFILL }
2735     },
2736     /* Expiry */
2737     { &hf_acn_expiry,
2738       { "Expiry", "acn.expiry",
2739         FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
2740         "Expiry", HFILL }
2741     },
2742     /* First Member to ACK */
2743     { &hf_acn_first_memeber_to_ack,
2744       { "First Member to ACK", "acn.first_member_to_ack",
2745         FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
2746         "First Member to ACK", HFILL }
2747     },
2748     /* First Missed Sequence */
2749     { &hf_acn_first_missed_sequence,
2750       { "First Missed Sequence", "acn.first_missed_sequence",
2751         FT_UINT32, BASE_DEC_HEX, NULL, 0x0,
2752         "First Missed Sequence", HFILL }
2753     },
2754     /* IPV4 */
2755     { &hf_acn_ipv4,
2756       { "IPV4", "acn.ipv4",
2757         FT_IPv4, BASE_NONE, NULL, 0x0,
2758         "IPV4", HFILL }
2759     },
2760     /* IPV6 */
2761     { &hf_acn_ipv6,
2762       { "IPV6", "acn.ipv6",
2763         FT_IPv6, BASE_NONE, NULL, 0x0,
2764         "IPV6", HFILL }
2765     },
2766     /* Last Member to ACK */
2767     { &hf_acn_last_memeber_to_ack,
2768       { "Last Member to ACK", "acn.last_member_to_ack",
2769         FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
2770         "Last Member to ACK", HFILL }
2771     },
2772     /* Last Missed Sequence */
2773     { &hf_acn_last_missed_sequence,
2774       { "Last Missed Sequence", "acn.last_missed_sequence",
2775         FT_UINT32, BASE_DEC_HEX, NULL, 0x0,
2776         "Last Missed Sequence", HFILL }
2777     },
2778     /* MAK threshold */
2779     { &hf_acn_mak_threshold,
2780       { "MAK Threshold", "acn.mak_threshold",
2781         FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
2782         "MAK Threshold", HFILL }
2783     },
2784     /* MemberID */
2785     { &hf_acn_member_id,
2786       { "Member ID", "acn.member_id",
2787         FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
2788         "Member ID", HFILL }
2789     },
2790     /* NAK Holdoff */
2791     { &hf_acn_nak_holdoff,
2792       { "NAK holdoff (ms)", "acn.nak_holdoff",
2793         FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
2794         "NAK holdoff", HFILL }
2795     },
2796     /* NAK Max Wait */
2797     { &hf_acn_nak_max_wait,
2798       { "NAK Max Wait (ms)", "acn.nak_max_wait",
2799         FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
2800         "NAK Max Wait", HFILL }
2801     },
2802     /* NAK Modulus */
2803     { &hf_acn_nak_modulus,
2804       { "NAK Modulus", "acn.nak_modulus",
2805         FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
2806         "NAK Modulus", HFILL }
2807     },
2808     /* NAK Outbound Flag */
2809     { &hf_acn_nak_outbound_flag,
2810       { "NAK Outbound Flag", "acn.nak_outbound_flag",
2811         FT_BOOLEAN, 8, NULL, 0x80,
2812         "NAK Outbound Flag", HFILL }
2813     },
2814     /* Oldest Available Wrapper */
2815     { &hf_acn_oldest_available_wrapper,
2816       { "Oldest Available Wrapper", "acn.oldest_available_wrapper",
2817         FT_UINT32, BASE_DEC_HEX, NULL, 0x0,
2818         "Oldest Available Wrapper", HFILL }
2819     },
2820     /* Preamble Sizet */
2821     { &hf_acn_preamble_size,
2822       { "Size of preamble", "acn.preamble_size",
2823         FT_UINT16, BASE_DEC, NULL, 0x0,
2824         "Preamble size in bytes", HFILL }
2825     },
2826     /* Packet Identifier */
2827     { &hf_acn_packet_identifier,
2828       { "Packet Identifier", "acn.packet_identifier",
2829         FT_STRING, BASE_NONE, NULL, 0x0,
2830         "Packet Identififer", HFILL }
2831     },
2832     /* PDU */
2833     { &hf_acn_pdu,
2834       { "PDU", "acn.pdu",
2835         FT_NONE, BASE_NONE, NULL, 0x0,
2836         "PDU", HFILL }
2837     },
2838     /* PDU flags*/
2839     { &hf_acn_pdu_flags,
2840       { "Flags", "acn.pdu.flags",
2841         FT_UINT8, BASE_HEX, NULL, 0x0,
2842         "PDU Flags", HFILL }
2843     },
2844     { &hf_acn_pdu_flag_d,
2845       { "Data", "acn.pdu.flag_d",
2846         FT_BOOLEAN, 8, NULL, ACN_PDU_FLAG_D,
2847         "Data flag", HFILL }
2848     },
2849     { &hf_acn_pdu_flag_h,
2850       { "Header", "acn.pdu.flag_h",
2851         FT_BOOLEAN, 8, NULL, ACN_PDU_FLAG_H,
2852         "Header flag", HFILL }
2853     },
2854     { &hf_acn_pdu_flag_l,
2855       { "Length", "acn.pdu.flag_l",
2856         FT_BOOLEAN, 8, NULL, ACN_PDU_FLAG_L,
2857         "Length flag", HFILL }
2858     },
2859     { &hf_acn_pdu_flag_v,
2860       { "Vector", "acn.pdu.flag_v",
2861         FT_BOOLEAN, 8, NULL, ACN_PDU_FLAG_V,
2862         "Vector flag", HFILL }
2863     },
2864     /* PDU Length */
2865     { &hf_acn_pdu_length,
2866       { "Length", "acn.pdu.flag_d",
2867         FT_UINT32, BASE_DEC, NULL, 0x0,
2868         "PDU Length", HFILL }
2869     },
2870     /* Port */
2871     { &hf_acn_port,
2872       { "Port", "acn.port",
2873         FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
2874         "Port", HFILL }
2875     },
2876     /* Postamble Size */
2877     { &hf_acn_postamble_size,
2878       { "Size of postamble", "acn.postamble_size",
2879         FT_UINT16, BASE_DEC, NULL, 0x0,
2880         "Postamble size in bytes", HFILL }
2881     },
2882     /* Protocol ID */
2883     { &hf_acn_protocol_id,
2884       { "Protocol ID", "acn.protocol_id",
2885         FT_UINT32, BASE_DEC, VALS(acn_protocol_id_vals), 0x0,
2886         "Protocol ID", HFILL }
2887     },
2888     /* Reason Code */
2889     { &hf_acn_reason_code,
2890       { "Reason Code", "acn.reason_code",
2891         FT_UINT8, BASE_DEC, VALS(acn_reason_code_vals), 0x0,
2892         "Reason Code", HFILL }
2893     },
2894     /* Reciprocal Channel */
2895     { &hf_acn_reciprocal_channel,
2896       { "Reciprocal Sequence Number", "acn.acn_reciprocal_channel",
2897         FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
2898         "Reciprocal Channel", HFILL }
2899     },
2900     /* Refuse Code */
2901     { &hf_acn_refuse_code,
2902       { "Refuse Code", "acn.acn_refuse_code",
2903         FT_UINT8, BASE_DEC, VALS(acn_refuse_code_vals), 0x0,
2904         "Refuse Code", HFILL }
2905     },
2906     /* Reliable Sequence Number */
2907     { &hf_acn_reliable_sequence_number,
2908       { "Reliable Sequence Number", "acn.reliable_sequence_number",
2909         FT_UINT32, BASE_DEC_HEX, NULL, 0x0,
2910         "Reliable Sequence Number", HFILL }
2911     },
2912     /* SDT Vector */
2913     { &hf_acn_sdt_vector,
2914       { "STD Vector", "acn.sdt_vector",
2915         FT_UINT8, BASE_DEC, VALS(acn_sdt_vector_vals), 0x0,
2916         "STD Vector", HFILL }
2917     },
2918
2919     /* DMX Vector */
2920     { &hf_acn_dmx_vector,
2921       { "Vector", "acn.dmx_vector",
2922         FT_UINT32, BASE_DEC, VALS(acn_dmx_vector_vals), 0x0,
2923         "DMX Vector", HFILL }
2924     },
2925     /* DMX Source Name */
2926     { &hf_acn_dmx_source_name,
2927       { "Source", "acn.dmx.source_name",
2928         FT_STRING, BASE_NONE, NULL, 0x0,
2929         "DMX Source Name", HFILL }
2930     },
2931
2932     /* DMX priority */
2933     { &hf_acn_dmx_priority,
2934       { "Priority", "acn.dmx.priority",
2935         FT_UINT8, BASE_DEC, NULL, 0x0,
2936         "DMX Priority", HFILL }
2937     },
2938     /* DMX Sequence number */
2939     { &hf_acn_dmx_sequence_number,
2940       { "Seq No", "acn.dmx.seq_number",
2941         FT_UINT8, BASE_DEC, NULL, 0x0,
2942         "DMX Sequence Number", HFILL }
2943     },
2944     /* DMX Universe */
2945     { &hf_acn_dmx_universe,
2946       { "Universe", "acn.dmx.universe",
2947         FT_UINT16, BASE_DEC, NULL, 0x0,
2948         "DMX Universe", HFILL }
2949     },
2950     /* Session Count */
2951     { &hf_acn_session_count,
2952       { "Session Count", "acn.session_count",
2953         FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
2954         "Session Count", HFILL }
2955     },
2956     /* Total Sequence Number */
2957     { &hf_acn_total_sequence_number,
2958       { "Total Sequence Number", "acn.total_sequence_number",
2959         FT_UINT32, BASE_DEC_HEX, NULL, 0x0,
2960         "Total Sequence Number", HFILL }
2961     },
2962   };
2963
2964   /* Setup protocol subtree array */
2965   static gint *ett[] = {
2966     &ett_acn,
2967     &ett_acn_channel_owner_info_block,
2968     &ett_acn_channel_member_info_block,
2969     &ett_acn_channel_parameter,
2970     &ett_acn_address,
2971     &ett_acn_address_type,
2972     &ett_acn_pdu_flags,
2973     &ett_acn_dmp_pdu,
2974     &ett_acn_sdt_pdu,
2975     &ett_acn_sdt_client_pdu,
2976     &ett_acn_sdt_base_pdu,
2977     &ett_acn_root_pdu,
2978     &ett_acn_dmx_address,
2979     &ett_acn_dmx_data_pdu,
2980     &ett_acn_dmx_pdu
2981   };
2982
2983   module_t *acn_module;
2984   if (proto_acn == -1) {
2985     proto_acn = proto_register_protocol (
2986       "Architecture for Control Networks", /* name */
2987       "ACN",                               /* short name */
2988       "acn"                               /* abbrev */
2989       );
2990   }
2991
2992   acn_module = prefs_register_protocol(proto_acn, proto_reg_handoff_acn);
2993   proto_register_field_array(proto_acn, hf, array_length(hf));
2994   proto_register_subtree_array(ett, array_length(ett));
2995   prefs_register_bool_preference(acn_module, "heuristic_acn",
2996                                  "Decode ACN",
2997                                  "Enable Architecture for Control Networks dissector (ANSI BSR E1.17)",
2998                                  &global_acn_heur);
2999
3000   prefs_register_bool_preference(acn_module, "dmx_enable",
3001                                  "Streaming DMX", 
3002                                  "Enable Streaming DMX extension dissector (ANSI BSR E1.31)",
3003                                  &global_acn_dmx_enable);
3004
3005   prefs_register_enum_preference(acn_module, "dmx_display_view",
3006                                  "DMX, display format", 
3007                                  "Display format", 
3008                                  &global_acn_dmx_display_view,
3009                                  dmx_display_view, 
3010                                  TRUE);
3011
3012   prefs_register_bool_preference(acn_module, "dmx_display_zeros",
3013                                  "DMX, display zeros", 
3014                                  "Display zeros instead of dots",
3015                                  &global_acn_dmx_display_zeros);
3016
3017   prefs_register_bool_preference(acn_module, "dmx_display_leading_zeros",
3018                                  "DMX, display leading zeros", 
3019                                  "Display leading zeros on levels",
3020                                  &global_acn_dmx_display_leading_zeros);
3021 }
3022
3023
3024 /******************************************************************************/
3025 /* Register handoff                                                           */
3026 void
3027 proto_reg_handoff_acn(void)
3028 {
3029   static guint initialized = FALSE;
3030   /* static dissector_handle_t acn_handle; */
3031
3032   if (!initialized) {
3033     /* acn_handle = new_create_dissector_handle(dissect_acn, proto_acn); */
3034     /* dissector_add("udp.port", 0, acn_handle);                         */
3035     heur_dissector_add("udp", dissect_acn_heur, proto_acn);
3036     initialized = TRUE;
3037   }
3038 }
3039