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