Eliminate proto_tree_add_text from some dissectors.
[metze/wireshark/wip.git] / epan / dissectors / packet-acn.c
1 /* packet-acn.c
2  * Routines for ACN packet disassembly
3  *
4  * Copyright (c) 2003 by Erwin Rol <erwin@erwinrol.com>
5  * Copyright (c) 2006 by Electronic Theatre Controls, Inc.
6  *                    Bill Florac <bflorac@etcconnect.com>
7  *
8  * Wireshark - Network traffic analyzer
9  * By Gerald Combs <gerald@wireshark.org>
10  * Copyright 1999 Gerald Combs
11  *
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License
14  * as published by the Free Software Foundation; either version 2
15  * of the License, or (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25  */
26
27  /*
28     Todo:
29       Add reading of DDL files so we can futher explode DMP packets
30       For some of the Set/Get properties where we have a range of data
31       it would be better to show the block of data rather and
32       address-data pair on each line...
33
34       Build CID to "Name" table from file so we can display real names
35       rather than CIDs
36  */
37
38 /* Include files */
39
40 #include "config.h"
41
42 #include <glib.h>
43
44 #include <epan/packet.h>
45 #include <epan/prefs.h>
46 #include <epan/ipv6-utils.h>
47 #include <epan/to_str.h>
48
49 /* Forward declarations */
50 void proto_register_acn(void);
51 void proto_reg_handoff_acn(void);
52
53 /* pdu flags */
54 #define ACN_PDU_FLAG_L     0x80
55 #define ACN_PDU_FLAG_V     0x40
56 #define ACN_PDU_FLAG_H     0x20
57 #define ACN_PDU_FLAG_D     0x10
58
59 #define ACN_DMX_OPTION_P   0x80
60 #define ACN_DMX_OPTION_S   0x40
61
62 #define ACN_DMP_ADT_FLAG_V 0x80 /* V = Specifies whether address is a virtual address or not. */
63 #define ACN_DMP_ADT_FLAG_R 0x40 /* R = Specifies whether address is relative to last valid address in packet or not. */
64 #define ACN_DMP_ADT_FLAG_D 0x30 /* D1, D0 = Specify non-range or range address, single data, equal size
65                                    or mixed size data array */
66 #define ACN_DMP_ADT_EXTRACT_D(f)        (((f) & ACN_DMP_ADT_FLAG_D) >> 4)
67
68 #define ACN_DMP_ADT_FLAG_X 0x0c /* X1, X0 = These bits are reserved and their values shall be set to 0
69                                    when encoded. Their values shall be ignored when decoding. */
70
71 #define ACN_DMP_ADT_FLAG_A 0x03 /* A1, A0 = Size of Address elements */
72 #define ACN_DMP_ADT_EXTRACT_A(f)        ((f) & ACN_DMP_ADT_FLAG_A)
73
74 #define ACN_DMP_ADT_V_VIRTUAL   0
75 #define ACN_DMP_ADT_V_ACTUAL    1
76
77 #define ACN_DMP_ADT_R_ABSOLUTE  0
78 #define ACN_DMP_ADT_R_RELATIVE  1
79
80 #define ACN_DMP_ADT_D_NS        0
81 #define ACN_DMP_ADT_D_RS        1
82 #define ACN_DMP_ADT_D_RE        2
83 #define ACN_DMP_ADT_D_RM        3
84
85 #define ACN_DMP_ADT_A_1         0
86 #define ACN_DMP_ADT_A_2         1
87 #define ACN_DMP_ADT_A_4         2
88 #define ACN_DMP_ADT_A_R         3
89
90 #define ACN_PROTOCOL_ID_SDT           1
91 #define ACN_PROTOCOL_ID_DMP           2
92 #define ACN_PROTOCOL_ID_DMX           3
93 #define ACN_PROTOCOL_ID_DMX_2         4
94
95 #define ACN_ADDR_NULL                 0
96 #define ACN_ADDR_IPV4                 1
97 #define ACN_ADDR_IPV6                 2
98 #define ACN_ADDR_IPPORT               3
99
100 /* STD Messages */
101 #define ACN_SDT_VECTOR_UNKNOWN          0
102 #define ACN_SDT_VECTOR_REL_WRAP         1
103 #define ACN_SDT_VECTOR_UNREL_WRAP       2
104 #define ACN_SDT_VECTOR_CHANNEL_PARAMS   3
105 #define ACN_SDT_VECTOR_JOIN             4
106 #define ACN_SDT_VECTOR_JOIN_REFUSE      5
107 #define ACN_SDT_VECTOR_JOIN_ACCEPT      6
108 #define ACN_SDT_VECTOR_LEAVE            7
109 #define ACN_SDT_VECTOR_LEAVING          8
110 #define ACN_SDT_VECTOR_CONNECT          9
111 #define ACN_SDT_VECTOR_CONNECT_ACCEPT  10
112 #define ACN_SDT_VECTOR_CONNECT_REFUSE  11
113 #define ACN_SDT_VECTOR_DISCONNECT      12
114 #define ACN_SDT_VECTOR_DISCONNECTING   13
115 #define ACN_SDT_VECTOR_ACK             14
116 #define ACN_SDT_VECTOR_NAK             15
117 #define ACN_SDT_VECTOR_GET_SESSION     16
118 #define ACN_SDT_VECTOR_SESSIONS        17
119
120 #define ACN_REFUSE_CODE_NONSPECIFIC     1
121 #define ACN_REFUSE_CODE_ILLEGAL_PARAMS  2
122 #define ACN_REFUSE_CODE_LOW_RESOURCES   3
123 #define ACN_REFUSE_CODE_ALREADY_MEMBER  4
124 #define ACN_REFUSE_CODE_BAD_ADDR_TYPE   5
125 #define ACN_REFUSE_CODE_NO_RECIP_CHAN   6
126
127 #define ACN_REASON_CODE_NONSPECIFIC          1
128 /*#define ACN_REASON_CODE_                   2 */
129 /*#define ACN_REASON_CODE_                   3 */
130 /*#define ACN_REASON_CODE_                   4 */
131 /*#define ACN_REASON_CODE_                   5 */
132 #define ACN_REASON_CODE_NO_RECIP_CHAN        6
133 #define ACN_REASON_CODE_CHANNEL_EXPIRED      7
134 #define ACN_REASON_CODE_LOST_SEQUENCE        8
135 #define ACN_REASON_CODE_SATURATED            9
136 #define ACN_REASON_CODE_TRANS_ADDR_CHANGING 10
137 #define ACN_REASON_CODE_ASKED_TO_LEAVE      11
138 #define ACN_REASON_CODE_NO_RECIPIENT        12
139
140 #define ACN_DMP_VECTOR_UNKNOWN               0
141 #define ACN_DMP_VECTOR_GET_PROPERTY          1
142 #define ACN_DMP_VECTOR_SET_PROPERTY          2
143 #define ACN_DMP_VECTOR_GET_PROPERTY_REPLY    3
144 #define ACN_DMP_VECTOR_EVENT                 4
145 #define ACN_DMP_VECTOR_MAP_PROPERTY          5
146 #define ACN_DMP_VECTOR_UNMAP_PROPERTY        6
147 #define ACN_DMP_VECTOR_SUBSCRIBE             7
148 #define ACN_DMP_VECTOR_UNSUBSCRIBE           8
149 #define ACN_DMP_VECTOR_GET_PROPERTY_FAIL     9
150 #define ACN_DMP_VECTOR_SET_PROPERTY_FAIL    10
151 #define ACN_DMP_VECTOR_MAP_PROPERTY_FAIL    11
152 #define ACN_DMP_VECTOR_SUBSCRIBE_ACCEPT     12
153 #define ACN_DMP_VECTOR_SUBSCRIBE_REJECT     13
154 #define ACN_DMP_VECTOR_ALLOCATE_MAP         14
155 #define ACN_DMP_VECTOR_ALLOCATE_MAP_REPLY   15
156 #define ACN_DMP_VECTOR_DEALLOCATE_MAP       16
157
158 #define ACN_DMP_REASON_CODE_NONSPECIFIC                  1
159 #define ACN_DMP_REASON_CODE_NOT_A_PROPERTY               2
160 #define ACN_DMP_REASON_CODE_WRITE_ONLY                   3
161 #define ACN_DMP_REASON_CODE_NOT_WRITABLE                 4
162 #define ACN_DMP_REASON_CODE_DATA_ERROR                   5
163 #define ACN_DMP_REASON_CODE_MAPS_NOT_SUPPORTED           6
164 #define ACN_DMP_REASON_CODE_SPACE_NOT_AVAILABLE          7
165 #define ACN_DMP_REASON_CODE_PROP_NOT_MAPPABLE            8
166 #define ACN_DMP_REASON_CODE_MAP_NOT_ALLOCATED            9
167 #define ACN_DMP_REASON_CODE_SUBSCRIPTION_NOT_SUPPORTED  10
168 #define ACN_DMP_REASON_CODE_NO_SUBSCRIPTIONS_SUPPORTED  11
169
170 #define ACN_DMX_VECTOR      2
171
172 #define ACN_PREF_DMX_DISPLAY_HEX  0
173 #define ACN_PREF_DMX_DISPLAY_DEC  1
174 #define ACN_PREF_DMX_DISPLAY_PER  2
175
176 #define ACN_PREF_DMX_DISPLAY_20PL 0
177 #define ACN_PREF_DMX_DISPLAY_16PL 1
178
179 typedef struct
180 {
181   guint32 start;
182   guint32 vector;
183   guint32 header;
184   guint32 data;
185   guint32 data_length;
186 } acn_pdu_offsets;
187
188 typedef struct
189 {
190   guint8  flags;
191   guint32 address;  /* or first address */
192   guint32 increment;
193   guint32 count;
194   guint32 size;
195   guint32 data_length;
196 } acn_dmp_adt_type;
197
198 /*
199  * See
200  * ANSI BSR E1.17 Architecture for Control Networks
201  * ANSI BSR E1.31
202  */
203
204 #define ACTUAL_ADDRESS  0
205 /* forward reference */
206 static guint32 acn_add_address(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, const char *label);
207 static int     dissect_acn(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
208
209 /* Global variables */
210 static int proto_acn = -1;
211 static gint ett_acn = -1;
212 static gint ett_acn_channel_owner_info_block = -1;
213 static gint ett_acn_channel_member_info_block = -1;
214 static gint ett_acn_channel_parameter = -1;
215 static gint ett_acn_address = -1;
216 static gint ett_acn_address_type = -1;
217 static gint ett_acn_pdu_flags = -1;
218 static gint ett_acn_dmp_pdu = -1;
219 static gint ett_acn_sdt_pdu = -1;
220 static gint ett_acn_sdt_client_pdu = -1;
221 static gint ett_acn_sdt_base_pdu = -1;
222 static gint ett_acn_root_pdu = -1;
223 static gint ett_acn_dmx_address = -1;
224 static gint ett_acn_dmx_2_options = -1;
225 static gint ett_acn_dmx_data_pdu = -1;
226 static gint ett_acn_dmx_pdu = -1;
227
228 /*  Register fields */
229 /* In alphabetical order */
230 static int hf_acn_association = -1;
231 static int hf_acn_channel_number = -1;
232 static int hf_acn_cid = -1;
233 /* static int hf_acn_client_protocol_id = -1; */
234 static int hf_acn_data = -1;
235 static int hf_acn_data8 = -1;
236 static int hf_acn_data16 = -1;
237 static int hf_acn_data24 = -1;
238 static int hf_acn_data32 = -1;
239 /* static int hf_acn_dmp_adt = -1; */ /* address and data type*/
240 static int hf_acn_dmp_adt_a = -1;
241 static int hf_acn_dmp_adt_v = -1;
242 static int hf_acn_dmp_adt_r = -1;
243 static int hf_acn_dmp_adt_d = -1;
244 static int hf_acn_dmp_adt_x = -1;
245 static int hf_acn_dmp_reason_code = -1;
246 static int hf_acn_dmp_vector = -1;
247 static int hf_acn_dmp_actual_address = -1;
248 static int hf_acn_dmp_virtual_address = -1;
249 static int hf_acn_dmp_actual_address_first = -1;
250 static int hf_acn_dmp_virtual_address_first = -1;
251 static int hf_acn_expiry = -1;
252 static int hf_acn_first_memeber_to_ack = -1;
253 static int hf_acn_first_missed_sequence = -1;
254 static int hf_acn_ip_address_type = -1;
255 static int hf_acn_ipv4 = -1;
256 static int hf_acn_ipv6 = -1;
257 static int hf_acn_last_memeber_to_ack = -1;
258 static int hf_acn_last_missed_sequence = -1;
259 static int hf_acn_mak_threshold = -1;
260 static int hf_acn_member_id = -1;
261 static int hf_acn_nak_holdoff = -1;
262 static int hf_acn_nak_max_wait = -1;
263 static int hf_acn_nak_modulus = -1;
264 static int hf_acn_nak_outbound_flag = -1;
265 static int hf_acn_oldest_available_wrapper = -1;
266 static int hf_acn_packet_identifier = -1;
267 static int hf_acn_pdu = -1;
268 static int hf_acn_pdu_flag_d = -1;
269 static int hf_acn_pdu_flag_h = -1;
270 static int hf_acn_pdu_flag_l = -1;
271 static int hf_acn_pdu_flag_v = -1;
272 static int hf_acn_pdu_flags = -1;
273 static int hf_acn_pdu_length = -1;
274 static int hf_acn_port = -1;
275 static int hf_acn_postamble_size = -1;
276 static int hf_acn_preamble_size = -1;
277 static int hf_acn_protocol_id = -1;
278 static int hf_acn_reason_code = -1;
279 static int hf_acn_reciprocal_channel = -1;
280 static int hf_acn_refuse_code = -1;
281 static int hf_acn_reliable_sequence_number = -1;
282 static int hf_acn_adhoc_expiry = -1;
283 /* static int hf_acn_sdt_pdu = -1; */
284 static int hf_acn_sdt_vector = -1;
285 static int hf_acn_dmx_vector = -1;
286 /* static int hf_acn_session_count = -1; */
287 static int hf_acn_total_sequence_number = -1;
288 static int hf_acn_dmx_source_name = -1;
289 static int hf_acn_dmx_priority = -1;
290 static int hf_acn_dmx_2_reserved = -1;
291 static int hf_acn_dmx_sequence_number = -1;
292 static int hf_acn_dmx_2_options = -1;
293 static int hf_acn_dmx_2_option_p = -1;
294 static int hf_acn_dmx_2_option_s = -1;
295 static int hf_acn_dmx_universe = -1;
296
297 static int hf_acn_dmx_start_code = -1;
298 static int hf_acn_dmx_2_first_property_address = -1;
299 static int hf_acn_dmx_increment = -1;
300 static int hf_acn_dmx_count = -1;
301 static int hf_acn_dmx_2_start_code = -1;
302 static int hf_acn_dmx_data = -1;
303
304 /* static int hf_acn_dmx_dmp_vector = -1; */
305
306 /* Try heuristic ACN decode */
307 static gboolean global_acn_heur = FALSE;
308 static gboolean global_acn_dmx_enable = FALSE;
309 static gint     global_acn_dmx_display_view = 0;
310 static gint     global_acn_dmx_display_line_format = 0;
311 static gboolean global_acn_dmx_display_zeros = FALSE;
312 static gboolean global_acn_dmx_display_leading_zeros = FALSE;
313
314
315 static const value_string acn_protocol_id_vals[] = {
316   { ACN_PROTOCOL_ID_SDT, "SDT Protocol" },
317   { ACN_PROTOCOL_ID_DMP, "DMP Protocol" },
318   { ACN_PROTOCOL_ID_DMX, "DMX Protocol" },
319   { ACN_PROTOCOL_ID_DMX_2, "Ratified DMX Protocol" },
320   { 0,       NULL },
321 };
322
323 static const value_string acn_dmp_adt_r_vals[] = {
324   { 0, "Relative" },
325   { 1, "Absolute" },
326   { 0,       NULL },
327 };
328
329 static const value_string acn_dmp_adt_v_vals[] = {
330   { 0, "Actual" },
331   { 1, "Virtual" },
332   { 0,       NULL },
333 };
334
335 static const value_string acn_dmp_adt_d_vals[] = {
336   { ACN_DMP_ADT_D_NS, "Non-range, single data item" },
337   { ACN_DMP_ADT_D_RS, "Range, single data item" },
338   { ACN_DMP_ADT_D_RE, "Range, array of equal size data items" },
339   { ACN_DMP_ADT_D_RM, "Range, series of mixed size data items" },
340   { 0,       NULL },
341 };
342
343 static const value_string acn_dmp_adt_a_vals[] = {
344   { ACN_DMP_ADT_A_1, "1 octet" },
345   { ACN_DMP_ADT_A_2, "2 octets" },
346   { ACN_DMP_ADT_A_4, "4 octets" },
347   { ACN_DMP_ADT_A_R, "reserved" },
348   { 0,       NULL },
349 };
350
351
352 static const value_string acn_sdt_vector_vals[] = {
353   {ACN_SDT_VECTOR_UNKNOWN,        "Unknown"},
354   {ACN_SDT_VECTOR_REL_WRAP,       "Reliable Wrapper"},
355   {ACN_SDT_VECTOR_UNREL_WRAP,     "Unreliable Wrapper"},
356   {ACN_SDT_VECTOR_CHANNEL_PARAMS, "Channel Parameters"},
357   {ACN_SDT_VECTOR_JOIN,           "Join"},
358   {ACN_SDT_VECTOR_JOIN_REFUSE,    "Join Refuse"},
359   {ACN_SDT_VECTOR_JOIN_ACCEPT,    "Join Accept"},
360   {ACN_SDT_VECTOR_LEAVE,          "Leave"},
361   {ACN_SDT_VECTOR_LEAVING,        "Leaving"},
362   {ACN_SDT_VECTOR_CONNECT,        "Connect"},
363   {ACN_SDT_VECTOR_CONNECT_ACCEPT, "Connect Accept"},
364   {ACN_SDT_VECTOR_CONNECT_REFUSE, "Connect Refuse"},
365   {ACN_SDT_VECTOR_DISCONNECT,     "Disconnect"},
366   {ACN_SDT_VECTOR_DISCONNECTING,  "Disconnecting"},
367   {ACN_SDT_VECTOR_ACK,            "Ack"},
368   {ACN_SDT_VECTOR_NAK,            "Nak"},
369   {ACN_SDT_VECTOR_GET_SESSION,    "Get Session"},
370   {ACN_SDT_VECTOR_SESSIONS,       "Sessions"},
371   { 0,       NULL },
372 };
373
374 static const value_string acn_dmx_vector_vals[] = {
375   {ACN_DMX_VECTOR,  "Streaming DMX"},
376   { 0,       NULL },
377 };
378
379 static const value_string acn_dmp_vector_vals[] = {
380   {ACN_DMP_VECTOR_UNKNOWN,            "Unknown"},
381   {ACN_DMP_VECTOR_GET_PROPERTY,       "Get Property"},
382   {ACN_DMP_VECTOR_SET_PROPERTY,       "Set Property"},
383   {ACN_DMP_VECTOR_GET_PROPERTY_REPLY, "Get property reply"},
384   {ACN_DMP_VECTOR_EVENT,              "Event"},
385   {ACN_DMP_VECTOR_MAP_PROPERTY,       "Map Property"},
386   {ACN_DMP_VECTOR_UNMAP_PROPERTY,     "Unmap Property"},
387   {ACN_DMP_VECTOR_SUBSCRIBE,          "Subscribe"},
388   {ACN_DMP_VECTOR_UNSUBSCRIBE,        "Unsubscribe"},
389   {ACN_DMP_VECTOR_GET_PROPERTY_FAIL,  "Get Property Fail"},
390   {ACN_DMP_VECTOR_SET_PROPERTY_FAIL,  "Set Property Fail"},
391   {ACN_DMP_VECTOR_MAP_PROPERTY_FAIL,  "Map Property Fail"},
392   {ACN_DMP_VECTOR_SUBSCRIBE_ACCEPT,   "Subscribe Accept"},
393   {ACN_DMP_VECTOR_SUBSCRIBE_REJECT,   "Subscribe Reject"},
394   {ACN_DMP_VECTOR_ALLOCATE_MAP,       "Allocate Map"},
395   {ACN_DMP_VECTOR_ALLOCATE_MAP_REPLY, "Allocate Map Reply"},
396   {ACN_DMP_VECTOR_DEALLOCATE_MAP,     "Deallocate Map"},
397   { 0,       NULL },
398 };
399
400 static const value_string acn_ip_address_type_vals[] = {
401   { ACN_ADDR_NULL,   "Null"},
402   { ACN_ADDR_IPV4,   "IPv4"},
403   { ACN_ADDR_IPV6,   "IPv6"},
404   { ACN_ADDR_IPPORT, "Port"},
405   { 0,       NULL },
406 };
407
408 static const value_string acn_refuse_code_vals[] = {
409   { ACN_REFUSE_CODE_NONSPECIFIC,    "Nonspecific" },
410   { ACN_REFUSE_CODE_ILLEGAL_PARAMS, "Illegal Parameters" },
411   { ACN_REFUSE_CODE_LOW_RESOURCES,  "Low Resources" },
412   { ACN_REFUSE_CODE_ALREADY_MEMBER, "Already Member" },
413   { ACN_REFUSE_CODE_BAD_ADDR_TYPE,  "Bad Address Type" },
414   { ACN_REFUSE_CODE_NO_RECIP_CHAN,  "No Reciprocal Channel" },
415   { 0,       NULL },
416 };
417
418 static const value_string acn_reason_code_vals[] = {
419   { ACN_REASON_CODE_NONSPECIFIC,         "Nonspecific" },
420   { ACN_REASON_CODE_NO_RECIP_CHAN,       "No Reciprocal Channel" },
421   { ACN_REASON_CODE_CHANNEL_EXPIRED,     "Channel Expired" },
422   { ACN_REASON_CODE_LOST_SEQUENCE,       "Lost Sequence" },
423   { ACN_REASON_CODE_SATURATED,           "Saturated" },
424   { ACN_REASON_CODE_TRANS_ADDR_CHANGING, "Transport Address Changing" },
425   { ACN_REASON_CODE_ASKED_TO_LEAVE,      "Asked to Leave" },
426   { ACN_REASON_CODE_NO_RECIPIENT,        "No Recipient"},
427   { 0,       NULL },
428 };
429
430 static const value_string acn_dmp_reason_code_vals[] = {
431   { ACN_DMP_REASON_CODE_NONSPECIFIC,                "Nonspecific" },
432   { ACN_DMP_REASON_CODE_NOT_A_PROPERTY,             "Not a Property" },
433   { ACN_DMP_REASON_CODE_WRITE_ONLY,                 "Write Only" },
434   { ACN_DMP_REASON_CODE_NOT_WRITABLE,               "Not Writable" },
435   { ACN_DMP_REASON_CODE_DATA_ERROR,                 "Data Error" },
436   { ACN_DMP_REASON_CODE_MAPS_NOT_SUPPORTED,         "Maps not Supported" },
437   { ACN_DMP_REASON_CODE_SPACE_NOT_AVAILABLE,        "Space not Available" },
438   { ACN_DMP_REASON_CODE_PROP_NOT_MAPPABLE,          "Property not Mappable"},
439   { ACN_DMP_REASON_CODE_MAP_NOT_ALLOCATED,          "Map not Allocated"},
440   { ACN_DMP_REASON_CODE_SUBSCRIPTION_NOT_SUPPORTED, "Subscription not Supported"},
441   { ACN_DMP_REASON_CODE_NO_SUBSCRIPTIONS_SUPPORTED, "No Subscriptions Supported"},
442   { 0,       NULL },
443 };
444
445 static const enum_val_t dmx_display_view[] = {
446   { "hex"    , "Hex    ",     ACN_PREF_DMX_DISPLAY_HEX  },
447   { "decimal", "Decimal",     ACN_PREF_DMX_DISPLAY_DEC  },
448   { "percent", "Percent",     ACN_PREF_DMX_DISPLAY_PER  },
449   { NULL, NULL, 0 }
450 };
451
452 static const enum_val_t dmx_display_line_format[] = {
453   { "20 per line", "20 per line",     ACN_PREF_DMX_DISPLAY_20PL  },
454   { "16 per line", "16 per line",     ACN_PREF_DMX_DISPLAY_16PL  },
455   { NULL, NULL, 0 }
456 };
457
458 /******************************************************************************/
459 /* Test to see if it is an ACN Packet                                         */
460 static gboolean
461 is_acn(tvbuff_t *tvb)
462 {
463   static const char acn_packet_id[] = "ASC-E1.17\0\0\0";  /* must be 12 bytes */
464
465   if (tvb_captured_length(tvb) < (4+sizeof(acn_packet_id)))
466     return FALSE;
467
468   /* Check the bytes in octets 4 - 16 */
469   if (tvb_memeql(tvb, 4, acn_packet_id, sizeof(acn_packet_id)-1) != 0)
470     return FALSE;
471
472   return TRUE;
473 }
474
475
476 /******************************************************************************/
477 /* Heuristic dissector                                                        */
478 static gboolean
479 dissect_acn_heur( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_ )
480 {
481   /* This is a heuristic dissector, which means we get all the UDP
482    * traffic not sent to a known dissector and not claimed by
483    * a heuristic dissector called before us!
484    */
485
486   /* abort if not enabled! */
487   if (!global_acn_heur) return FALSE;
488
489   /* abort if it is NOT an ACN packet */
490   if (!is_acn(tvb)) return FALSE;
491
492   /* else, dissect it */
493   dissect_acn(tvb, pinfo, tree);
494   return TRUE;
495 }
496
497 /******************************************************************************/
498 /*  Adds tree branch for channel owner info block                             */
499 static guint32
500 acn_add_channel_owner_info_block(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset)
501 {
502   proto_item *pi;
503   proto_tree *this_tree;
504   guint32     session_count;
505   guint32     x;
506
507   this_tree = proto_tree_add_subtree(tree, tvb, offset, 8, ett_acn_channel_owner_info_block, NULL,
508                                     "Channel Owner Info Block");
509
510   proto_tree_add_item(this_tree, hf_acn_member_id, tvb, offset, 2, ENC_BIG_ENDIAN);
511   offset += 2;
512   proto_tree_add_item(this_tree, hf_acn_channel_number, tvb, offset, 2, ENC_BIG_ENDIAN);
513   offset += 2;
514   offset += acn_add_address(tvb, pinfo, this_tree, offset, "Destination Address:");
515   offset += acn_add_address(tvb, pinfo, this_tree, offset, "Source Address:");
516
517   session_count = tvb_get_ntohs(tvb, offset);
518   for (x=0; x<session_count; x++) {
519     pi = proto_tree_add_item(this_tree, hf_acn_protocol_id, tvb, offset, 4, ENC_BIG_ENDIAN);
520     proto_item_append_text(pi, " #%d",  x+1);
521     offset += 4;
522   }
523   return offset;
524 }
525
526 /******************************************************************************/
527 /*  Adds tree branch for channel member info block                            */
528 static guint32
529 acn_add_channel_member_info_block(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset)
530 {
531   proto_item *pi;
532   proto_tree *this_tree;
533   guint32     session_count;
534   guint32     x;
535
536   this_tree = proto_tree_add_subtree(tree, tvb, offset, 8, ett_acn_channel_member_info_block,
537                                 NULL, "Channel Member Info Block");
538
539   proto_tree_add_item(this_tree, hf_acn_member_id, tvb, offset, 2, ENC_BIG_ENDIAN);
540   offset += 2;
541   proto_tree_add_item(this_tree, hf_acn_cid, tvb, offset, 16, ENC_BIG_ENDIAN);
542   offset += 16;
543   proto_tree_add_item(this_tree, hf_acn_channel_number, tvb, offset, 2, ENC_BIG_ENDIAN);
544   offset += 2;
545   offset += acn_add_address(tvb, pinfo, this_tree, offset, "Destination Address:");
546   offset += acn_add_address(tvb, pinfo, this_tree, offset, "Source Address:");
547   proto_tree_add_item(this_tree, hf_acn_reciprocal_channel, tvb, offset, 2, ENC_BIG_ENDIAN);
548   offset += 2;
549
550   session_count = tvb_get_ntohs(tvb, offset);
551   for (x=0; x<session_count; x++) {
552     pi = proto_tree_add_item(this_tree, hf_acn_protocol_id, tvb, offset, 4, ENC_BIG_ENDIAN);
553     proto_item_append_text(pi, " #%d",  x+1);
554     offset += 4;
555   }
556   return offset;
557 }
558
559
560 /******************************************************************************/
561 /* Add labeled expiry                                                         */
562 static guint32
563 acn_add_expiry(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, int hf)
564 {
565   proto_tree_add_item(tree, hf, tvb, offset, 2, ENC_NA);
566   offset += 1;
567   return offset;
568 }
569
570
571 /******************************************************************************/
572 /*  Adds tree branch for channel parameters                                   */
573 static guint32
574 acn_add_channel_parameter(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset)
575 {
576   proto_tree *param_tree;
577
578   param_tree = proto_tree_add_subtree(tree, tvb, offset, 8, ett_acn_channel_parameter,
579                             NULL, "Channel Parameter Block");
580
581   proto_tree_add_item(param_tree, hf_acn_expiry, tvb, offset, 1, ENC_BIG_ENDIAN);
582   offset += 1;
583   proto_tree_add_item(param_tree, hf_acn_nak_outbound_flag, tvb, offset, 1, ENC_BIG_ENDIAN);
584   offset += 1;
585   proto_tree_add_item(param_tree, hf_acn_nak_holdoff, tvb, offset, 2, ENC_BIG_ENDIAN);
586   offset += 2;
587   proto_tree_add_item(param_tree, hf_acn_nak_modulus, tvb, offset, 2, ENC_BIG_ENDIAN);
588   offset += 2;
589   proto_tree_add_item(param_tree, hf_acn_nak_max_wait, tvb, offset, 2, ENC_BIG_ENDIAN);
590   offset += 2;
591   return offset; /* bytes used */
592 }
593
594
595 /******************************************************************************/
596 /* Add an address tree                                                        */
597 static guint32
598 acn_add_address(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, const char *label)
599 {
600   proto_item *pi;
601   proto_tree *addr_tree = NULL;
602   guint8      ip_address_type;
603   address     addr;
604   guint32     IPv4;
605   guint32     port;
606
607   struct e_in6_addr IPv6;
608
609
610   /* Get type */
611   ip_address_type = tvb_get_guint8(tvb, offset);
612
613   switch (ip_address_type) {
614     case ACN_ADDR_NULL:
615       proto_tree_add_item(tree, hf_acn_ip_address_type, tvb, offset, 1, ENC_BIG_ENDIAN);
616       offset    += 1;
617       break;
618     case ACN_ADDR_IPV4:
619       /* Build tree and add type*/
620       addr_tree = proto_tree_add_subtree(tree, tvb, offset, 7, ett_acn_address, &pi, label);
621       proto_tree_add_item(addr_tree, hf_acn_ip_address_type, tvb, offset, 1, ENC_BIG_ENDIAN);
622       offset    += 1;
623       /* Add port */
624       port       = tvb_get_ntohs(tvb, offset);
625       proto_tree_add_item(addr_tree, hf_acn_port, tvb, offset, 2, ENC_BIG_ENDIAN);
626       offset    += 2;
627       /* Add Address */
628       proto_tree_add_item(addr_tree, hf_acn_ipv4, tvb, offset, 4, ENC_BIG_ENDIAN);
629       /* Append port and address to tree item */
630       IPv4       = tvb_get_ipv4(tvb, offset);
631       SET_ADDRESS(&addr, AT_IPv4, sizeof(IPv4), &IPv4);
632       proto_item_append_text(pi, " %s, Port %d", address_to_str(wmem_packet_scope(), &addr), port);
633       offset    += 4;
634       break;
635     case ACN_ADDR_IPV6:
636       /* Build tree and add type*/
637       addr_tree = proto_tree_add_subtree(tree, tvb, offset, 19, ett_acn_address, &pi, label);
638       proto_tree_add_item(addr_tree, hf_acn_ip_address_type, tvb, offset, 1, ENC_BIG_ENDIAN);
639       offset    += 1;
640       /* Add port */
641       port       = tvb_get_ntohs(tvb, offset);
642       proto_tree_add_item(addr_tree, hf_acn_port, tvb, offset, 2, ENC_BIG_ENDIAN);
643       offset    += 2;
644       /* Add Address */
645       proto_tree_add_item(addr_tree, hf_acn_ipv6, tvb, offset, 16, ENC_NA);
646       /* Append port and address to tree item */
647       tvb_get_ipv6(tvb, offset, &IPv6);
648       SET_ADDRESS(&addr, AT_IPv6, sizeof(struct e_in6_addr), &IPv6);
649       proto_item_append_text(pi, " %s, Port %d", address_to_str(wmem_packet_scope(), &addr), port);
650       offset    += 16;
651       break;
652     case ACN_ADDR_IPPORT:
653       /* Build tree and add type*/
654       addr_tree = proto_tree_add_subtree(tree, tvb, offset, 3, ett_acn_address, &pi, label);
655       proto_tree_add_item(addr_tree, hf_acn_ip_address_type, tvb, offset, 1, ENC_BIG_ENDIAN);
656       offset    += 1;
657       /* Add port */
658       port       = tvb_get_ntohs(tvb, offset);
659       proto_tree_add_item(addr_tree, hf_acn_port, tvb, offset, 2, ENC_BIG_ENDIAN);
660       /* Append port to tree item */
661       proto_item_append_text(pi, " %s Port %d", address_to_str(wmem_packet_scope(), &addr), port);
662       offset    += 2;
663       break;
664   }
665   return offset;
666 }
667
668 /******************************************************************************/
669 /*  Adds tree branch for address type                             */
670 static guint32
671 acn_add_dmp_address_type(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, acn_dmp_adt_type *adt)
672 {
673   proto_tree  *this_tree;
674   guint8       D;
675   const gchar *name;
676
677     /* header contains address and data type */
678   adt->flags = tvb_get_guint8(tvb, offset);
679
680   D = ACN_DMP_ADT_EXTRACT_D(adt->flags);
681   name = val_to_str(D, acn_dmp_adt_d_vals, "not valid (%d)");
682   this_tree = proto_tree_add_subtree_format(tree, tvb, offset, 1, ett_acn_address_type,
683                                 NULL, "Address and Data Type: %s", name);
684
685   proto_tree_add_uint(this_tree, hf_acn_dmp_adt_v, tvb, offset, 1, adt->flags);
686   proto_tree_add_uint(this_tree, hf_acn_dmp_adt_r, tvb, offset, 1, adt->flags);
687   proto_tree_add_uint(this_tree, hf_acn_dmp_adt_d, tvb, offset, 1, adt->flags);
688   proto_tree_add_uint(this_tree, hf_acn_dmp_adt_x, tvb, offset, 1, adt->flags);
689   proto_tree_add_uint(this_tree, hf_acn_dmp_adt_a, tvb, offset, 1, adt->flags);
690   offset += 1;
691
692   return offset; /* bytes used */
693 }
694
695 /******************************************************************************/
696 /* Add an dmp address                                                         */
697 static guint32
698 acn_add_dmp_address(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, acn_dmp_adt_type *adt)
699 {
700   guint32 start_offset;
701   guint32 bytes_used;
702   guint8  D, A;
703
704   start_offset = offset;
705
706   D = ACN_DMP_ADT_EXTRACT_D(adt->flags);
707   A = ACN_DMP_ADT_EXTRACT_A(adt->flags);
708
709   switch (D) {
710     case ACN_DMP_ADT_D_NS:      /* Non-range address, Single data item */
711       adt->increment    = 1;
712       adt->count        = 1;
713       switch (A) {              /* address */
714         case ACN_DMP_ADT_A_1:   /* One octet address, (range: one octet address, increment, and count). */
715           adt->address  = tvb_get_guint8(tvb, offset);
716           offset       += 1;
717           bytes_used    = 1;
718           break;
719         case ACN_DMP_ADT_A_2:   /* Two octet address, (range: two octet address, increment, and count). */
720           adt->address  = tvb_get_ntohs(tvb, offset);
721           offset       += 2;
722           bytes_used    = 2;
723           break;
724         case ACN_DMP_ADT_A_4:   /* Four octet address, (range: one octet address, increment, and count). */
725           adt->address  = tvb_get_ntohl(tvb, offset);
726           offset       += 4;
727           bytes_used    = 4;
728           break;
729         default:                /* and ACN_DMP_ADT_A_R (Four octet address, (range: four octet address, increment, and count)*/
730           return offset;
731       }                         /* of switch (A)  */
732
733       if (adt->flags & ACN_DMP_ADT_FLAG_V) {
734         proto_tree_add_uint(tree, hf_acn_dmp_virtual_address, tvb, start_offset, bytes_used, adt->address);
735       } else {
736         proto_tree_add_uint(tree, hf_acn_dmp_actual_address, tvb, start_offset, bytes_used, adt->address);
737       }
738       break;
739
740     case ACN_DMP_ADT_D_RS:      /* Range address, Single data item */
741       switch (A) {
742         case ACN_DMP_ADT_A_1:   /* One octet address, (range: one octet address, increment, and count). */
743           adt->address    = tvb_get_guint8(tvb, offset);
744           offset         += 1;
745           adt->increment  = tvb_get_guint8(tvb, offset);
746           offset         += 1;
747           adt->count      = tvb_get_guint8(tvb, offset);
748           offset         += 1;
749           bytes_used      = 3;
750           break;
751         case ACN_DMP_ADT_A_2:   /* Two octet address, (range: two octet address, increment, and count). */
752           adt->address    = tvb_get_ntohs(tvb, offset);
753           offset         += 2;
754           adt->increment  = tvb_get_ntohs(tvb, offset);
755           offset         += 2;
756           adt->count      = tvb_get_ntohs(tvb, offset);
757           offset         += 2;
758           bytes_used      = 6;
759           break;
760         case ACN_DMP_ADT_A_4:   /* Four octet address, (range: four octet address, increment, and count). */
761           adt->address    = tvb_get_ntohl(tvb, offset);
762           offset         += 4;
763           adt->increment  = tvb_get_ntohl(tvb, offset);
764           offset         += 4;
765           adt->count      = tvb_get_ntohl(tvb, offset);
766           offset         += 4;
767           bytes_used      = 12;
768           break;
769         default:                /* and ACN_DMP_ADT_A_R, this reserved....so it has no meaning yet */
770           return offset;
771       }                         /* of switch (A)  */
772
773       if (adt->flags & ACN_DMP_ADT_FLAG_V) {
774         proto_tree_add_uint_format_value(tree, hf_acn_dmp_virtual_address_first, tvb, start_offset, bytes_used,
775                             adt->address, "0x%X, inc: %d, count: %d",
776                             adt->address, adt->increment, adt->count);
777       } else {
778         proto_tree_add_uint_format_value(tree, hf_acn_dmp_actual_address_first, tvb, start_offset, bytes_used,
779                             adt->address, "0x%X, inc: %d, count: %d",
780                             adt->address, adt->increment, adt->count);
781       }
782       break;
783
784     case ACN_DMP_ADT_D_RE:      /* Range address, Array of equal size data items */
785       switch (A) {
786         case ACN_DMP_ADT_A_1:   /* One octet address, (range: one octet address, increment, and count). */
787           adt->address    = tvb_get_guint8(tvb, offset);
788           offset         += 1;
789           adt->increment  = tvb_get_guint8(tvb, offset);
790           offset         += 1;
791           adt->count      = tvb_get_guint8(tvb, offset);
792           offset         += 1;
793           bytes_used      = 3;
794           break;
795         case ACN_DMP_ADT_A_2:   /* Two octet address, (range: two octet address, increment, and count). */
796           adt->address    = tvb_get_ntohs(tvb, offset);
797           offset         += 2;
798           adt->increment  = tvb_get_ntohs(tvb, offset);
799           offset         += 2;
800           adt->count      = tvb_get_ntohs(tvb, offset);
801           offset         += 2;
802           bytes_used      = 6;
803           break;
804         case ACN_DMP_ADT_A_4:   /* Four octet address, (range: four octet address, increment, and count). */
805           adt->address    = tvb_get_ntohl(tvb, offset);
806           offset         += 4;
807           adt->increment  = tvb_get_ntohl(tvb, offset);
808           offset         += 4;
809           adt->count      = tvb_get_ntohl(tvb, offset);
810           offset         += 4;
811           bytes_used      = 12;
812           break;
813         default:                /* and ACN_DMP_ADT_A_R, this reserved....so it has no meaning yet */
814           return offset;
815       }                         /* of switch (A)  */
816
817       if (adt->flags & ACN_DMP_ADT_FLAG_V) {
818         proto_tree_add_uint_format_value(tree, hf_acn_dmp_virtual_address_first, tvb, start_offset, bytes_used,
819                             adt->address, "0x%X, inc: %d, count: %d",
820                             adt->address, adt->increment, adt->count);
821       } else {
822         proto_tree_add_uint_format_value(tree, hf_acn_dmp_actual_address_first, tvb, start_offset, bytes_used,
823                             adt->address, "0x%X, inc: %d, count: %d",
824                             adt->address, adt->increment, adt->count);
825       }
826       break;
827
828     case ACN_DMP_ADT_D_RM: /* Range address, Series of mixed size data items */
829       switch (A) {
830         case ACN_DMP_ADT_A_1: /* One octet address, (range: one octet address, increment, and count). */
831           adt->address =   tvb_get_guint8(tvb, offset);
832           offset += 1;
833           adt->increment =   tvb_get_guint8(tvb, offset);
834           offset += 1;
835           adt->count =   tvb_get_guint8(tvb, offset);
836           offset += 1;
837           bytes_used = 3;
838           break;
839         case ACN_DMP_ADT_A_2: /* Two octet address, (range: two octet address, increment, and count). */
840           adt->address =   tvb_get_ntohs(tvb, offset);
841           offset += 2;
842           adt->increment =   tvb_get_ntohs(tvb, offset);
843           offset += 2;
844           adt->count =   tvb_get_ntohs(tvb, offset);
845           offset += 2;
846           bytes_used = 6;
847           break;
848         case ACN_DMP_ADT_A_4: /* Four octet address, (range: four octet address, increment, and count). */
849           adt->address =   tvb_get_ntohl(tvb, offset);
850           offset += 4;
851           adt->increment =   tvb_get_ntohl(tvb, offset);
852           offset += 4;
853           adt->count =   tvb_get_ntohl(tvb, offset);
854           offset += 4;
855           bytes_used = 12;
856           break;
857         default: /* and ACN_DMP_ADT_A_R, this reserved....so it has no meaning yet */
858           return offset;
859       } /* of switch (A)  */
860
861       if (adt->flags & ACN_DMP_ADT_FLAG_V) {
862         proto_tree_add_uint_format_value(tree, hf_acn_dmp_virtual_address_first, tvb, start_offset, bytes_used,
863                             adt->address, "0x%X, inc: %d, count: %d",
864                             adt->address, adt->increment, adt->count);
865       } else {
866         proto_tree_add_uint_format_value(tree, hf_acn_dmp_actual_address_first, tvb, start_offset, bytes_used,
867                             adt->address, "0x%X, inc: %d, count: %d",
868                             adt->address, adt->increment, adt->count);
869       }
870       break;
871   } /* of switch (D) */
872
873   return offset;
874 }
875
876
877 /*******************************************************************************/
878 /* Display DMP Data                                                            */
879 #define BUFFER_SIZE 128
880 static guint32
881 acn_add_dmp_data(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, acn_dmp_adt_type *adt)
882 {
883   guint8      D, A;
884   guint32     data_size;
885   guint32     data_value;
886   guint32     data_address;
887   guint32     x,y;
888   gchar       buffer[BUFFER_SIZE];
889   proto_item *ti;
890   guint32     ok_to_process = FALSE;
891
892   buffer[0] = 0;
893
894   /* We would like to rip through Property Address-Data pairs                 */
895   /* but since we don't now how many there are nor how big the data size is,  */
896   /* it not possible. So, we just show the whole thing as a block of date!    */
897   /*                                                                          */
898   /* There are a few exceptions however                                       */
899   /* 1) if the address type is ACN_DMP_ADT_D_NS or ACN_DMP_ADT_D_RS and       */
900   /*    or ACN_DMP_ADT_D_RE                                                   */
901   /*    then number of bytes is <= count + 4. Each value is at least one byte */
902   /*    and another address/data pair is at least 4 bytes so if the remaining */
903   /*    bytes is less than the count plus 4 then the remaining data           */
904   /*    must be all data                                                      */
905   /*                                                                          */
906   /* 2) if the address type is ACN_DMP_ADT_D_RE and the number of bytes       */
907   /*    equals the number of bytes in remaining in the pdu then there is      */
908   /*    a 1 to one match                                                      */
909
910   D = ACN_DMP_ADT_EXTRACT_D(adt->flags);
911   switch (D) {
912     case ACN_DMP_ADT_D_NS:
913     case ACN_DMP_ADT_D_RS:
914       if (adt->data_length <= adt->count + 4) {
915         ok_to_process = TRUE;
916       }
917       break;
918     case ACN_DMP_ADT_D_RE:
919       if (adt->count == 0) {
920         break;
921       }
922       if (adt->data_length <= adt->count + 4) {
923         ok_to_process = TRUE;
924       }
925       break;
926   }
927
928   if (!ok_to_process) {
929     data_size  = adt->data_length;
930     ti         = proto_tree_add_item(tree, hf_acn_data, tvb, offset, data_size, ENC_NA);
931     offset    += data_size;
932     proto_item_set_text(ti, "Data and more Address-Data Pairs (further dissection not possible)");
933     return offset;
934   }
935
936   A = ACN_DMP_ADT_EXTRACT_A(adt->flags);
937
938   switch (D) {
939     case ACN_DMP_ADT_D_NS:      /* Non-range address, Single data item */
940       /* calculate data size */
941       data_size    = adt->data_length;
942       data_address = adt->address;
943
944       switch (A) {
945         case ACN_DMP_ADT_A_1: /* One octet address, (range: one octet address, increment, and count). */
946           g_snprintf(buffer, BUFFER_SIZE, "Addr 0x%2.2X ->", data_address);
947           break;
948         case ACN_DMP_ADT_A_2: /* Two octet address, (range: two octet address, increment, and count). */
949           g_snprintf(buffer, BUFFER_SIZE, "Addr 0x%4.4X ->", data_address);
950           break;
951         case ACN_DMP_ADT_A_4: /* Four octet address, (range: four octet address, increment, and count). */
952           g_snprintf(buffer, BUFFER_SIZE, "Addr 0x%8.8X ->", data_address);
953           break;
954         default: /* and ACN_DMP_ADT_A_R, this reserved....so it has no meaning yet */
955           offset += data_size;
956           return offset;
957       }
958
959       switch (data_size) {
960         case 1:
961           data_value = tvb_get_guint8(tvb, offset);
962           proto_tree_add_uint_format(tree, hf_acn_data8, tvb, offset, 1, data_value, "%s %2.2X", buffer, data_value);
963           break;
964         case 2:
965           data_value = tvb_get_ntohs(tvb, offset);
966           proto_tree_add_uint_format(tree, hf_acn_data16, tvb, offset, 2, data_value, "%s %4.4X", buffer, data_value);
967           break;
968         case 3:
969           data_value = tvb_get_ntoh24(tvb, offset);
970           proto_tree_add_uint_format(tree, hf_acn_data24, tvb, offset, 3, data_value, "%s %6.6X", buffer, data_value);
971           break;
972         case 4:
973           data_value = tvb_get_ntohl(tvb, offset);
974           proto_tree_add_uint_format(tree, hf_acn_data32, tvb, offset, 4, data_value, "%s %8.8X", buffer, data_value);
975           break;
976         default:
977           /* build string of values */
978           for (y=0; y<20 && y<data_size; y++) {
979             data_value = tvb_get_guint8(tvb, offset+y);
980             g_snprintf(buffer, BUFFER_SIZE, "%s %2.2X", buffer, data_value);
981           }
982           /* add the item */
983           ti = proto_tree_add_item(tree, hf_acn_data, tvb, offset, data_size, ENC_NA);
984           offset += data_size;
985           /* change the text */
986           proto_item_set_text(ti, "%s", buffer);
987           break;
988       } /* of switch (data_size) */
989       offset += data_size;
990       break;
991
992     case ACN_DMP_ADT_D_RS: /* Range address, Single data item */
993       /* calculate data size */
994       data_size = adt->data_length;
995       data_address = adt->address;
996
997       for (x=0; x<adt->count; x++) {
998         switch (A) {
999           case ACN_DMP_ADT_A_1: /* One octet address, (range: one octet address, increment, and count). */
1000             g_snprintf(buffer, BUFFER_SIZE, "Addr 0x%2.2X ->", data_address);
1001             break;
1002           case ACN_DMP_ADT_A_2: /* Two octet address, (range: two octet address, increment, and count). */
1003             g_snprintf(buffer, BUFFER_SIZE, "Addr 0x%4.4X ->", data_address);
1004             break;
1005           case ACN_DMP_ADT_A_4: /* Four octet address, (range: four octet address, increment, and count). */
1006             g_snprintf(buffer, BUFFER_SIZE, "Addr 0x%8.8X ->", data_address);
1007             break;
1008           default: /* and ACN_DMP_ADT_A_R, this reserved....so it has no meaning yet */
1009             return offset;
1010         }
1011
1012         switch (data_size) {
1013           case 1:
1014             data_value = tvb_get_guint8(tvb, offset);
1015             proto_tree_add_uint_format(tree, hf_acn_data8, tvb, offset, 1, data_value, "%s %2.2X", buffer, data_value);
1016             break;
1017           case 2:
1018             data_value = tvb_get_ntohs(tvb, offset);
1019             proto_tree_add_uint_format(tree, hf_acn_data8, tvb, offset, 2, data_value, "%s %4.4X", buffer, data_value);
1020             break;
1021           case 3:
1022             data_value = tvb_get_ntoh24(tvb, offset);
1023             proto_tree_add_uint_format(tree, hf_acn_data8, tvb, offset, 3, data_value, "%s %6.6X", buffer, data_value);
1024             break;
1025           case 4:
1026             data_value = tvb_get_ntohl(tvb, offset);
1027             proto_tree_add_uint_format(tree, hf_acn_data8, tvb, offset, 4, data_value, "%s %8.8X", buffer, data_value);
1028             break;
1029           default:
1030             /* build string of values */
1031             for (y=0; y<20 && y<data_size; y++) {
1032               data_value = tvb_get_guint8(tvb, offset+y);
1033               g_snprintf(buffer, BUFFER_SIZE, "%s %2.2X", buffer, data_value);
1034             }
1035             /* add the item */
1036             ti = proto_tree_add_item(tree, hf_acn_data, tvb, offset, data_size, ENC_NA);
1037             /* change the text */
1038             proto_item_set_text(ti, "%s", buffer);
1039             break;
1040         } /* of switch (data_size) */
1041         data_address += adt->increment;
1042       } /* of (x=0;x<adt->count;x++) */
1043       offset += data_size;
1044       break;
1045
1046     case ACN_DMP_ADT_D_RE: /* Range address, Array of equal size data items */
1047       /* calculate data size */
1048       data_size = adt->data_length / adt->count;
1049       data_address = adt->address;
1050
1051       for (x=0; x<adt->count; x++) {
1052         switch (A) {
1053           case ACN_DMP_ADT_A_1: /* One octet address, (range: one octet address, increment, and count). */
1054             g_snprintf(buffer, BUFFER_SIZE, "Addr 0x%2.2X ->", data_address);
1055             break;
1056           case ACN_DMP_ADT_A_2: /* Two octet address, (range: two octet address, increment, and count). */
1057             g_snprintf(buffer, BUFFER_SIZE, "Addr 0x%4.4X ->", data_address);
1058             break;
1059           case ACN_DMP_ADT_A_4: /* Four octet address, (range: four octet address, increment, and count). */
1060             g_snprintf(buffer, BUFFER_SIZE, "Addr 0x%8.8X ->", data_address);
1061             break;
1062           default: /* and ACN_DMP_ADT_A_R, this reserved....so it has no meaning yet */
1063             return offset;
1064         }
1065
1066         switch (data_size) {
1067           case 1:
1068             data_value = tvb_get_guint8(tvb, offset);
1069             proto_tree_add_uint_format(tree, hf_acn_data8, tvb, offset, 1, data_value, "%s %2.2X", buffer, data_value);
1070             break;
1071           case 2:
1072             data_value = tvb_get_ntohs(tvb, offset);
1073             proto_tree_add_uint_format(tree, hf_acn_data8, tvb, offset, 2, data_value, "%s %4.4X", buffer, data_value);
1074             break;
1075           case 3:
1076             data_value = tvb_get_ntoh24(tvb, offset);
1077             proto_tree_add_uint_format(tree, hf_acn_data8, tvb, offset, 3, data_value, "%s %6.6X", buffer, data_value);
1078             break;
1079           case 4:
1080             data_value = tvb_get_ntohl(tvb, offset);
1081             proto_tree_add_uint_format(tree, hf_acn_data8, tvb, offset, 4, data_value, "%s %8.8X", buffer, data_value);
1082             break;
1083           default:
1084             /* build string of values */
1085             for (y=0; y<20 && y<data_size; y++) {
1086               data_value = tvb_get_guint8(tvb, offset+y);
1087               g_snprintf(buffer, BUFFER_SIZE, "%s %2.2X", buffer, data_value);
1088             }
1089             /* add the item */
1090             ti = proto_tree_add_item(tree, hf_acn_data, tvb, offset, data_size, ENC_NA);
1091             /* change the text */
1092             proto_item_set_text(ti, "%s", buffer);
1093             break;
1094         } /* of switch (data_size) */
1095
1096         offset += data_size;
1097         data_address += adt->increment;
1098       } /* of (x=0;x<adt->count;x++) */
1099       break;
1100
1101     case ACN_DMP_ADT_D_RM: /* Range address, Series of mixed size data items */
1102       data_size = adt->data_length;
1103       ti = proto_tree_add_item(tree, hf_acn_data, tvb, offset, data_size, ENC_NA);
1104       offset += data_size;
1105       /* change the text */
1106       proto_item_set_text(ti, "Mixed size data items");
1107       break;
1108   } /* of switch (D) */
1109
1110   return offset;
1111 }
1112
1113 /*******************************************************************************/
1114 /* Display DMP Reason codes                                                    */
1115   #define BUFFER_SIZE 128
1116 static guint32
1117 acn_add_dmp_reason_codes(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, acn_dmp_adt_type *adt)
1118 {
1119   guint8       D, A;
1120   guint32      data_value;
1121   guint32      data_address;
1122   guint32      x;
1123
1124   gchar        buffer[BUFFER_SIZE];
1125   const gchar *name;
1126
1127   buffer[0] = 0;
1128
1129   D = ACN_DMP_ADT_EXTRACT_D(adt->flags);
1130   A = ACN_DMP_ADT_EXTRACT_A(adt->flags);
1131   switch (D) {
1132     case ACN_DMP_ADT_D_NS: /* Non-range address, Single data item */
1133       data_address = adt->address;
1134       switch (A) {
1135         case ACN_DMP_ADT_A_1: /* One octet address, (range: one octet address, increment, and count). */
1136           g_snprintf(buffer, BUFFER_SIZE, "Addr 0x%2.2X ->", data_address);
1137           break;
1138         case ACN_DMP_ADT_A_2: /* Two octet address, (range: two octet address, increment, and count). */
1139           g_snprintf(buffer, BUFFER_SIZE, "Addr 0x%4.4X ->", data_address);
1140           break;
1141         case ACN_DMP_ADT_A_4: /* Four octet address, (range: four octet address, increment, and count). */
1142           g_snprintf(buffer, BUFFER_SIZE, "Addr 0x%8.8X ->", data_address);
1143           break;
1144         default: /* and ACN_DMP_ADT_A_R, this reserved....so it has no meaning yet */
1145           return offset;
1146       }
1147
1148       /* Get reason */
1149       data_value  = tvb_get_guint8(tvb, offset);
1150       name        = val_to_str(data_value, acn_dmp_reason_code_vals, "reason not valid (%d)");
1151       proto_tree_add_uint_format(tree, hf_acn_data8, tvb, offset, 1, data_value, "%s %s", buffer, name);
1152       offset     += 1;
1153       break;
1154
1155     case ACN_DMP_ADT_D_RS: /* Range address, Single data item */
1156       data_address = adt->address;
1157       for (x=0; x<adt->count; x++) {
1158         switch (A) {
1159           case ACN_DMP_ADT_A_1: /* One octet address, (range: one octet address, increment, and count). */
1160             g_snprintf(buffer, BUFFER_SIZE, "Addr 0x%2.2X ->", data_address);
1161             break;
1162           case ACN_DMP_ADT_A_2: /* Two octet address, (range: two octet address, increment, and count). */
1163             g_snprintf(buffer, BUFFER_SIZE, "Addr 0x%4.4X ->", data_address);
1164             break;
1165           case ACN_DMP_ADT_A_4: /* Four octet address, (range: four octet address, increment, and count). */
1166             g_snprintf(buffer, BUFFER_SIZE, "Addr 0x%8.8X ->", data_address);
1167             break;
1168           default: /* and ACN_DMP_ADT_A_R, this reserved....so it has no meaning yet */
1169             return offset;
1170         }
1171
1172         /* Get reason */
1173         data_value = tvb_get_guint8(tvb, offset);
1174         name       = val_to_str(data_value, acn_dmp_reason_code_vals, "reason not valid (%d)");
1175         proto_tree_add_uint_format(tree, hf_acn_data8, tvb, offset, 1, data_value, "%s %s", buffer, name);
1176
1177         data_address += adt->increment;
1178       } /* of (x=0;x<adt->count;x++) */
1179       offset += 1;
1180       break;
1181
1182     case ACN_DMP_ADT_D_RE: /* Range address, Array of equal size data items */
1183     case ACN_DMP_ADT_D_RM: /* Range address, Series of mixed size data items */
1184       data_address = adt->address;
1185       for (x=0; x<adt->count; x++) {
1186         switch (A) {
1187           case ACN_DMP_ADT_A_1: /* One octet address, (range: one octet address, increment, and count). */
1188             g_snprintf(buffer, BUFFER_SIZE, "Addr 0x%2.2X ->", data_address);
1189             break;
1190           case ACN_DMP_ADT_A_2: /* Two octet address, (range: two octet address, increment, and count). */
1191             g_snprintf(buffer, BUFFER_SIZE, "Addr 0x%4.4X ->", data_address);
1192             break;
1193           case ACN_DMP_ADT_A_4: /* Four octet address, (range: four octet address, increment, and count). */
1194             g_snprintf(buffer, BUFFER_SIZE, "Addr 0x%8.8X ->", data_address);
1195             break;
1196           default: /* and ACN_DMP_ADT_A_R, this reserved....so it has no meaning yet */
1197             return offset;
1198         }
1199         /* Get reason */
1200         data_value    = tvb_get_guint8(tvb, offset);
1201         name          = val_to_str(data_value, acn_dmp_reason_code_vals, "reason not valid (%d)");
1202         proto_tree_add_uint_format(tree, hf_acn_data8, tvb, offset, 1, data_value, "%s %s", buffer, name);
1203         data_address += adt->increment;
1204         offset       += 1;
1205       } /* of (x=0;x<adt->count;x++) */
1206       break;
1207   } /* of switch (D) */
1208
1209   return offset;
1210 }
1211
1212 /******************************************************************************/
1213 /* Dissect wrapped SDT PDU                                                    */
1214 static guint32
1215 dissect_acn_dmp_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, acn_pdu_offsets *last_pdu_offsets)
1216 {
1217   /* common to all pdu */
1218   guint8            pdu_flags;
1219   guint32           pdu_start;
1220   guint32           pdu_length;
1221   guint32           pdu_flvh_length; /* flags, length, vector, header */
1222   guint8            D;
1223   guint8            octet;
1224   guint32           length1;
1225   guint32           length2;
1226   guint32           length3;
1227   guint32           vector_offset;
1228   guint32           header_offset;
1229   guint32           data_offset;
1230   guint32           old_offset;
1231   guint32           end_offset;
1232   guint32           data_length;
1233   guint32           address_count;
1234
1235   proto_item       *ti, *pi;
1236   proto_tree       *pdu_tree  = NULL;
1237   proto_tree       *flag_tree = NULL;
1238
1239   /* this pdu */
1240   const gchar      *name;
1241   acn_dmp_adt_type  adt       = {0,0,0,0,0,0};
1242   acn_dmp_adt_type  adt2      = {0,0,0,0,0,0};
1243   guint32           vector;
1244
1245   /* save start of pdu block */
1246   pdu_start = offset;
1247
1248   /* get PDU flags and length flag first */
1249   octet     = tvb_get_guint8(tvb, offset++);
1250   pdu_flags = octet & 0xf0;
1251   length1   = octet & 0x0f;     /* bottom 4 bits only */
1252   length2   = tvb_get_guint8(tvb, offset++);
1253
1254   /* if length flag is set, then we have a 20 bit length else we have a 12 bit */
1255   /* flvh = flags, length, vector, header */
1256   if (pdu_flags & ACN_PDU_FLAG_L) {
1257     length3 = tvb_get_guint8(tvb, offset);
1258     offset += 1;
1259     pdu_length = length3 | (length2 << 8) | (length1 << 16);
1260     pdu_flvh_length = 3;
1261   } else {
1262     pdu_length = length2 | (length1 << 8);
1263     pdu_flvh_length = 2;
1264   }
1265   /* offset should now be pointing to vector (if one exists) */
1266
1267   /* Add pdu item and tree */
1268   ti       = proto_tree_add_item(tree, hf_acn_pdu, tvb, pdu_start, pdu_length, ENC_NA);
1269   pdu_tree = proto_item_add_subtree(ti, ett_acn_dmp_pdu);
1270
1271   /* Add flag item and tree */
1272   pi        = proto_tree_add_uint(pdu_tree, hf_acn_pdu_flags, tvb, pdu_start, 1, pdu_flags);
1273   flag_tree = proto_item_add_subtree(pi, ett_acn_pdu_flags);
1274   proto_tree_add_item(flag_tree, hf_acn_pdu_flag_l, tvb, pdu_start, 1, ENC_BIG_ENDIAN);
1275   proto_tree_add_item(flag_tree, hf_acn_pdu_flag_v, tvb, pdu_start, 1, ENC_BIG_ENDIAN);
1276   proto_tree_add_item(flag_tree, hf_acn_pdu_flag_h, tvb, pdu_start, 1, ENC_BIG_ENDIAN);
1277   proto_tree_add_item(flag_tree, hf_acn_pdu_flag_d, tvb, pdu_start, 1, ENC_BIG_ENDIAN);
1278
1279   /* Add PDU Length item */
1280   proto_tree_add_uint(pdu_tree, hf_acn_pdu_length, tvb, pdu_start, pdu_flvh_length, pdu_length);
1281
1282   /* Set vector offset */
1283   if (pdu_flags & ACN_PDU_FLAG_V) {
1284     /* use new values */
1285     vector_offset             = offset;
1286     last_pdu_offsets->vector  = offset;
1287     offset                   += 1;
1288     pdu_flvh_length++;
1289   } else {
1290     /* use last values */
1291     vector_offset             = last_pdu_offsets->vector;
1292   }
1293   /* offset should now be pointing to header (if one exists) */
1294
1295   /* Add Vector item */
1296   vector = tvb_get_guint8(tvb, vector_offset);
1297   proto_tree_add_uint(pdu_tree, hf_acn_dmp_vector, tvb, vector_offset, 1, vector);
1298
1299   /* Add Vector item to tree*/
1300   name = val_to_str(vector, acn_dmp_vector_vals, "not valid (%d)");
1301   proto_item_append_text(ti, ": ");
1302   proto_item_append_text(ti, "%s", name);
1303
1304   /* Set header offset */
1305   if (pdu_flags & ACN_PDU_FLAG_H) {
1306     /* use new values */
1307     header_offset             = offset;
1308     last_pdu_offsets->header  = offset;
1309     offset                   += 1;
1310     pdu_flvh_length++;
1311   } else {
1312     /* use last values */
1313     header_offset             = last_pdu_offsets->header;
1314   }
1315   /* offset should now be pointing to data (if one exists) */
1316
1317   /* header contains address and data type */
1318   acn_add_dmp_address_type(tvb, pinfo, pdu_tree, header_offset, &adt);
1319
1320   /* Adjust data */
1321   if (pdu_flags & ACN_PDU_FLAG_D) {
1322     /* use new values */
1323     data_offset                   = offset;
1324     data_length                   = pdu_length - pdu_flvh_length;
1325     last_pdu_offsets->data        = offset;
1326     last_pdu_offsets->data_length = data_length;
1327   } else {
1328     /* use last values */
1329     data_offset                   = last_pdu_offsets->data;
1330     data_length                   = last_pdu_offsets->data_length;
1331   }
1332   end_offset = data_offset + data_length;
1333
1334   switch (vector) {
1335     case ACN_DMP_VECTOR_UNKNOWN:
1336       break;
1337     case ACN_DMP_VECTOR_GET_PROPERTY:
1338       /* Rip trough property address */
1339       while (data_offset < end_offset) {
1340         old_offset      = data_offset;
1341         data_offset     = acn_add_dmp_address(tvb, pinfo, pdu_tree, data_offset, &adt);
1342         if (old_offset == data_offset) break;
1343       }
1344       break;
1345     case ACN_DMP_VECTOR_SET_PROPERTY:
1346       /* Rip through Property Address-Data pairs                                 */
1347       /* But, in reality, this generally won't work as we have know way of       */
1348       /* calculating the next Address-Data pair                                  */
1349       while (data_offset < end_offset) {
1350         old_offset      = data_offset;
1351         data_offset     = acn_add_dmp_address(tvb, pinfo, pdu_tree, data_offset, &adt);
1352         if (old_offset == data_offset) break;
1353
1354         adt.data_length = data_length - (data_offset - old_offset);
1355         old_offset      = data_offset;
1356         data_offset     = acn_add_dmp_data(tvb, pinfo, pdu_tree, data_offset, &adt);
1357         if (old_offset == data_offset) break;
1358       }
1359       break;
1360     case ACN_DMP_VECTOR_GET_PROPERTY_REPLY:
1361       /* Rip through Property Address-Data pairs */
1362       /* But, in reality, this generally won't work as we have know way of       */
1363       /* calculating the next Address-Data pair                                  */
1364       while (data_offset < end_offset) {
1365         old_offset      = data_offset;
1366         data_offset     = acn_add_dmp_address(tvb, pinfo, pdu_tree, data_offset, &adt);
1367         if (old_offset == data_offset) break;
1368
1369         adt.data_length = data_length - (data_offset - old_offset);
1370         old_offset      = data_offset;
1371         data_offset     = acn_add_dmp_data(tvb, pinfo, pdu_tree, data_offset, &adt);
1372         if (old_offset == data_offset) break;
1373       }
1374       break;
1375     case ACN_DMP_VECTOR_EVENT:
1376       /* Rip through Property Address-Data pairs */
1377       /* But, in reality, this generally won't work as we have know way of       */
1378       /* calculating the next Address-Data pair                                  */
1379       while (data_offset < end_offset) {
1380         old_offset      = data_offset;
1381         data_offset     = acn_add_dmp_address(tvb, pinfo, pdu_tree, data_offset, &adt);
1382         if (old_offset == data_offset) break;
1383
1384         adt.data_length = data_length - (data_offset - old_offset);
1385         old_offset      = data_offset;
1386         data_offset     = acn_add_dmp_data(tvb, pinfo, pdu_tree, data_offset, &adt);
1387         if (old_offset == data_offset) break;
1388       }
1389       break;
1390     case ACN_DMP_VECTOR_MAP_PROPERTY:
1391       /* Virtual Address type */
1392       data_offset = acn_add_dmp_address_type(tvb, pinfo, pdu_tree, data_offset, &adt2);
1393       /* Rip through Actual-Virtual Address Pairs */
1394       while (data_offset < end_offset) {
1395         /* actual */
1396         old_offset      = data_offset;
1397         data_offset     = acn_add_dmp_address(tvb, pinfo, pdu_tree, data_offset, &adt);
1398         if (old_offset == data_offset) break;
1399         D = ACN_DMP_ADT_EXTRACT_D(adt.flags);
1400         switch (D) {
1401           case ACN_DMP_ADT_D_NS:
1402             address_count = 1;
1403             break;
1404           case ACN_DMP_ADT_D_RS:
1405             address_count = 1;
1406             break;
1407           case ACN_DMP_ADT_D_RE:
1408             address_count = adt.count;
1409             break;
1410             /*case ACN_DMP_ADT_D_RM: */
1411           default:
1412             /* OUCH */
1413             return pdu_start + pdu_length;
1414             break;
1415         }
1416
1417         /* virtual */
1418         while (address_count > 0) {
1419           data_offset = acn_add_dmp_address(tvb, pinfo, pdu_tree, data_offset, &adt2);
1420           address_count--;
1421         }
1422       }
1423       break;
1424     case ACN_DMP_VECTOR_UNMAP_PROPERTY:
1425       /* Rip trough Actaul Proptery Address */
1426       while (data_offset < end_offset) {
1427         old_offset      = data_offset;
1428         data_offset     = acn_add_dmp_address(tvb, pinfo, pdu_tree, data_offset, &adt);
1429         if (old_offset == data_offset) break;
1430       }
1431       break;
1432     case ACN_DMP_VECTOR_SUBSCRIBE:
1433       /* Rip trough Proptery Address */
1434       while (data_offset < end_offset) {
1435         old_offset      = data_offset;
1436         data_offset     = acn_add_dmp_address(tvb, pinfo, pdu_tree, data_offset, &adt);
1437         if (old_offset == data_offset) break;
1438       }
1439       break;
1440     case ACN_DMP_VECTOR_UNSUBSCRIBE:
1441       /* Rip trough Proptery Address */
1442       while (data_offset < end_offset) {
1443         old_offset      = data_offset;
1444         data_offset     = acn_add_dmp_address(tvb, pinfo, pdu_tree, data_offset, &adt);
1445         if (old_offset == data_offset) break;
1446       }
1447       break;
1448     case ACN_DMP_VECTOR_GET_PROPERTY_FAIL:
1449       /* Rip trough Address-Reason Code Pairs */
1450       while (data_offset < end_offset) {
1451         old_offset      = data_offset;
1452         data_offset     = acn_add_dmp_address(tvb, pinfo, pdu_tree, data_offset, &adt);
1453         if (old_offset == data_offset) break;
1454
1455         adt.data_length = data_length - (data_offset - old_offset);
1456         old_offset      = data_offset;
1457         data_offset     = acn_add_dmp_reason_codes(tvb, pinfo, pdu_tree, data_offset, &adt);
1458         if (old_offset == data_offset) break;
1459       }
1460       break;
1461     case ACN_DMP_VECTOR_SET_PROPERTY_FAIL:
1462       /* Rip trough Address-Reason Code Pairs */
1463       while (data_offset < end_offset) {
1464         old_offset      = data_offset;
1465         data_offset     = acn_add_dmp_address(tvb, pinfo, pdu_tree, data_offset, &adt);
1466         if (old_offset == data_offset) break;
1467
1468         adt.data_length = data_length - (data_offset - old_offset);
1469         old_offset      = data_offset;
1470         data_offset     = acn_add_dmp_reason_codes(tvb, pinfo, pdu_tree, data_offset, &adt);
1471         if (old_offset == data_offset) break;
1472       }
1473       break;
1474     case ACN_DMP_VECTOR_MAP_PROPERTY_FAIL:
1475       /* Rip trough Address-Reason Code Pairs */
1476       while (data_offset < end_offset) {
1477         old_offset      = data_offset;
1478         data_offset     = acn_add_dmp_address(tvb, pinfo, pdu_tree, data_offset, &adt);
1479         if (old_offset == data_offset) break;
1480
1481         adt.data_length = data_length - (data_offset - old_offset);
1482         old_offset      = data_offset;
1483         data_offset     = acn_add_dmp_reason_codes(tvb, pinfo, pdu_tree, data_offset, &adt);
1484         if (old_offset == data_offset) break;
1485       }
1486       break;
1487     case ACN_DMP_VECTOR_SUBSCRIBE_ACCEPT:
1488       /* Rip through Property Addrsses */
1489       while (data_offset < end_offset) {
1490         old_offset      = data_offset;
1491         data_offset     = acn_add_dmp_address(tvb, pinfo, pdu_tree, data_offset, &adt);
1492         if (old_offset == data_offset) break;
1493       }
1494       break;
1495     case ACN_DMP_VECTOR_SUBSCRIBE_REJECT:
1496       /* Rip trough Address-Reason Code Pairs */
1497       while (data_offset < end_offset) {
1498         old_offset      = data_offset;
1499         data_offset     = acn_add_dmp_address(tvb, pinfo, pdu_tree, data_offset, &adt);
1500         if (old_offset == data_offset) break;
1501
1502         adt.data_length = data_length - (data_offset - old_offset);
1503         old_offset      = data_offset;
1504         data_offset     = acn_add_dmp_reason_codes(tvb, pinfo, pdu_tree, data_offset, &adt);
1505         if (old_offset == data_offset) break;
1506       }
1507       break;
1508     case ACN_DMP_VECTOR_ALLOCATE_MAP:
1509       /* No data for this */
1510       break;
1511     case ACN_DMP_VECTOR_ALLOCATE_MAP_REPLY:
1512       /* Single reason code  */
1513       proto_tree_add_item(pdu_tree, hf_acn_dmp_reason_code, tvb, data_offset, 1, ENC_BIG_ENDIAN);
1514       /* data_offset += 1; */
1515     case ACN_DMP_VECTOR_DEALLOCATE_MAP:
1516       /* No data for this */
1517       break;
1518   }
1519
1520   return pdu_start + pdu_length;
1521 }
1522
1523
1524 /******************************************************************************/
1525 /* Dissect wrapped SDT PDU                                                    */
1526 static guint32
1527 dissect_acn_sdt_wrapped_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree _U_, int offset, acn_pdu_offsets *last_pdu_offsets)
1528 {
1529   /* common to all pdu */
1530   guint8       pdu_flags;
1531   guint32      pdu_start;
1532   guint32      pdu_length;
1533   guint32      pdu_flvh_length; /* flags, length, vector, header */
1534   guint8       octet;
1535   guint32      length1;
1536   guint32      length2;
1537   guint32      length3;
1538   guint32      vector_offset;
1539   guint32      data_offset;
1540   guint32      data_length;
1541
1542   proto_item  *ti, *pi;
1543   proto_tree  *pdu_tree  = NULL;
1544   proto_tree  *flag_tree = NULL;
1545
1546   /* this pdu */
1547   const gchar *name;
1548   guint32      vector;
1549
1550   /* save start of pdu block */
1551   pdu_start = offset;
1552
1553   /* get PDU flags and length flag first */
1554   octet     = tvb_get_guint8(tvb, offset++);
1555   pdu_flags = octet & 0xf0;
1556   length1   = octet & 0x0f;     /* bottom 4 bits only */
1557   length2   = tvb_get_guint8(tvb, offset++);
1558
1559   /* if length flag is set, then we have a 20 bit length else we have a 12 bit */
1560   /* flvh = flags, length, vector, header */
1561   if (pdu_flags & ACN_PDU_FLAG_L) {
1562     length3 = tvb_get_guint8(tvb, offset);
1563     offset += 1;
1564     pdu_length = length3 | (length2 << 8) | (length1 << 16);
1565     pdu_flvh_length = 3;
1566   } else {
1567     pdu_length = length2 | (length1 << 8);
1568     pdu_flvh_length = 2;
1569   }
1570   /* offset should now be pointing to vector (if one exists) */
1571
1572   /* Add pdu item and tree */
1573   ti = proto_tree_add_item(tree, hf_acn_pdu, tvb, pdu_start, pdu_length, ENC_NA);
1574   pdu_tree = proto_item_add_subtree(ti, ett_acn_sdt_pdu);
1575
1576   /* Add flag item and tree */
1577   pi = proto_tree_add_uint(pdu_tree, hf_acn_pdu_flags, tvb, pdu_start, 1, pdu_flags);
1578   flag_tree = proto_item_add_subtree(pi, ett_acn_pdu_flags);
1579   proto_tree_add_item(flag_tree, hf_acn_pdu_flag_l, tvb, pdu_start, 1, ENC_BIG_ENDIAN);
1580   proto_tree_add_item(flag_tree, hf_acn_pdu_flag_v, tvb, pdu_start, 1, ENC_BIG_ENDIAN);
1581   proto_tree_add_item(flag_tree, hf_acn_pdu_flag_h, tvb, pdu_start, 1, ENC_BIG_ENDIAN);
1582   proto_tree_add_item(flag_tree, hf_acn_pdu_flag_d, tvb, pdu_start, 1, ENC_BIG_ENDIAN);
1583
1584   /* Add PDU Length item */
1585   proto_tree_add_uint(pdu_tree, hf_acn_pdu_length, tvb, pdu_start, pdu_flvh_length, pdu_length);
1586
1587   /* Set vector offset */
1588   if (pdu_flags & ACN_PDU_FLAG_V) {
1589     /* use new values */
1590     vector_offset = offset;
1591     last_pdu_offsets->vector = offset;
1592     offset += 1;
1593     pdu_flvh_length++;
1594   } else {
1595     /* use last values */
1596     vector_offset = last_pdu_offsets->vector;
1597   }
1598   /* offset should now be pointing to header (if one exists) */
1599
1600   /* Add Vector item */
1601   vector = tvb_get_guint8(tvb, vector_offset);
1602   proto_tree_add_uint(pdu_tree, hf_acn_sdt_vector, tvb, vector_offset, 1, vector);
1603
1604   /* Add Vector item to tree*/
1605   name = val_to_str(vector, acn_sdt_vector_vals, "not valid (%d)");
1606   proto_item_append_text(ti, ": ");
1607   proto_item_append_text(ti, "%s", name);
1608
1609   /* NO HEADER DATA ON THESE* (at least so far) */
1610
1611   /* Adjust data */
1612   if (pdu_flags & ACN_PDU_FLAG_D) {
1613     /* use new values */
1614     data_offset = offset;
1615     data_length = pdu_length - pdu_flvh_length;
1616     last_pdu_offsets->data = offset;
1617     last_pdu_offsets->data_length = data_length;
1618   } else {
1619     /* use last values */
1620     data_offset = last_pdu_offsets->data;
1621     /*data_length = last_pdu_offsets->data_length;*/
1622   }
1623
1624   switch (vector) {
1625     case ACN_SDT_VECTOR_ACK:
1626       proto_tree_add_item(pdu_tree, hf_acn_reliable_sequence_number, tvb, data_offset, 4, ENC_BIG_ENDIAN);
1627       /*data_offset += 4;*/
1628       break;
1629     case ACN_SDT_VECTOR_CHANNEL_PARAMS:
1630       data_offset = acn_add_channel_parameter(tvb, pinfo, pdu_tree, data_offset);
1631       data_offset = acn_add_address(tvb, pinfo, pdu_tree, data_offset, "Ad-hoc Address:");
1632       /*data_offset =*/ acn_add_expiry(tvb, pinfo, pdu_tree, data_offset, hf_acn_adhoc_expiry);
1633       break;
1634     case ACN_SDT_VECTOR_LEAVE:
1635       /* nothing more */
1636       break;
1637     case ACN_SDT_VECTOR_CONNECT:
1638       /* Protocol ID item */
1639       proto_tree_add_item(pdu_tree, hf_acn_protocol_id, tvb, data_offset, 4, ENC_BIG_ENDIAN);
1640       /*data_offset += 4;*/
1641       break;
1642     case ACN_SDT_VECTOR_CONNECT_ACCEPT:
1643       /* Protocol ID item */
1644       proto_tree_add_item(pdu_tree, hf_acn_protocol_id, tvb, data_offset, 4, ENC_BIG_ENDIAN);
1645       /*data_offset += 4;*/
1646       break;
1647     case ACN_SDT_VECTOR_CONNECT_REFUSE:
1648       /* Protocol ID item */
1649       proto_tree_add_item(pdu_tree, hf_acn_protocol_id, tvb, data_offset, 4, ENC_BIG_ENDIAN);
1650       data_offset += 4;
1651       proto_tree_add_item(pdu_tree, hf_acn_refuse_code, tvb, data_offset, 1, ENC_BIG_ENDIAN);
1652       /*data_offset += 1;*/
1653       break;
1654     case ACN_SDT_VECTOR_DISCONNECT:
1655       /* Protocol ID item */
1656       proto_tree_add_item(pdu_tree, hf_acn_protocol_id, tvb, data_offset, 4, ENC_BIG_ENDIAN);
1657       /*data_offset += 4;*/
1658       break;
1659     case ACN_SDT_VECTOR_DISCONNECTING:
1660       /* Protocol ID item */
1661       proto_tree_add_item(pdu_tree, hf_acn_protocol_id, tvb, data_offset, 4, ENC_BIG_ENDIAN);
1662       data_offset += 4;
1663       proto_tree_add_item(pdu_tree, hf_acn_reason_code, tvb, data_offset, 1, ENC_BIG_ENDIAN);
1664       /*data_offset += 1;*/
1665       break;
1666
1667   }
1668
1669   return pdu_start + pdu_length;
1670 }
1671
1672
1673 /******************************************************************************/
1674 /* Dissect SDT Client PDU                                                     */
1675 static guint32
1676 dissect_acn_sdt_client_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, acn_pdu_offsets *last_pdu_offsets)
1677 {
1678   /* common to all pdu */
1679   guint8           pdu_flags;
1680   guint32          pdu_start;
1681   guint32          pdu_length;
1682   guint32          pdu_flvh_length; /* flags, length, vector, header */
1683   acn_pdu_offsets  pdu_offsets = {0,0,0,0,0};
1684   guint8           octet;
1685   guint32          length1;
1686   guint32          length2;
1687   guint32          length3;
1688   guint32          vector_offset;
1689   guint32          header_offset;
1690   guint32          data_offset;
1691   guint32          data_length;
1692   guint32          old_offset;
1693   guint32          end_offset;
1694
1695   proto_item      *ti, *pi;
1696   proto_tree      *pdu_tree    = NULL;
1697   proto_tree      *flag_tree   = NULL;
1698
1699   /* this pdu */
1700   const gchar     *name;
1701   guint32          member_id;
1702   guint32          protocol_id;
1703   guint16          association;
1704
1705   /* save start of pdu block */
1706   pdu_start         = offset;
1707   pdu_offsets.start = pdu_start;
1708
1709   /* get PDU flags and length flag first */
1710   octet     = tvb_get_guint8(tvb, offset++);
1711   pdu_flags = octet & 0xf0;
1712   length1   = octet & 0x0f;     /* bottom 4 bits only */
1713   length2   = tvb_get_guint8(tvb, offset++);
1714
1715   /* if length flag is set, then we have a 20 bit length else we have a 12 bit */
1716   /* flvh = flags, length, vector, header */
1717   if (pdu_flags & ACN_PDU_FLAG_L) {
1718     length3 = tvb_get_guint8(tvb, offset);
1719     offset += 1;
1720     pdu_length = length3 | (length2 << 8) | (length1 << 16);
1721     pdu_flvh_length = 3;
1722   } else {
1723     pdu_length = length2 | (length1 << 8);
1724     pdu_flvh_length = 2;
1725   }
1726   /* offset should now be pointing to vector (if one exists) */
1727
1728   /* Add pdu item and tree */
1729   ti       = proto_tree_add_item(tree, hf_acn_pdu, tvb, pdu_start, pdu_length, ENC_NA);
1730   pdu_tree = proto_item_add_subtree(ti, ett_acn_sdt_client_pdu);
1731
1732   /* Add flag item and tree */
1733   pi = proto_tree_add_uint(pdu_tree, hf_acn_pdu_flags, tvb, pdu_start, 1, pdu_flags);
1734   flag_tree = proto_item_add_subtree(pi, ett_acn_pdu_flags);
1735   proto_tree_add_item(flag_tree, hf_acn_pdu_flag_l, tvb, pdu_start, 1, ENC_BIG_ENDIAN);
1736   proto_tree_add_item(flag_tree, hf_acn_pdu_flag_v, tvb, pdu_start, 1, ENC_BIG_ENDIAN);
1737   proto_tree_add_item(flag_tree, hf_acn_pdu_flag_h, tvb, pdu_start, 1, ENC_BIG_ENDIAN);
1738   proto_tree_add_item(flag_tree, hf_acn_pdu_flag_d, tvb, pdu_start, 1, ENC_BIG_ENDIAN);
1739
1740   /* Add PDU Length item */
1741   proto_tree_add_uint(pdu_tree, hf_acn_pdu_length, tvb, pdu_start, pdu_flvh_length, pdu_length);
1742
1743   /* Set vector offset */
1744   if (pdu_flags & ACN_PDU_FLAG_V) {
1745     /* use new values */
1746     vector_offset = offset;
1747     last_pdu_offsets->vector = offset;
1748     offset += 2;
1749     pdu_flvh_length += 2;
1750   } else {
1751     /* use last values */
1752     vector_offset = last_pdu_offsets->vector;
1753   }
1754   /* offset should now be pointing to header (if one exists) */
1755
1756   /* add Member ID item  */
1757   member_id = tvb_get_ntohs(tvb, vector_offset);
1758   proto_tree_add_uint(pdu_tree, hf_acn_member_id, tvb, vector_offset, 2, member_id);
1759
1760   /* Set header offset */
1761   if (pdu_flags & ACN_PDU_FLAG_H) {
1762     /* use new values */
1763     header_offset             = offset;
1764     last_pdu_offsets->header  = offset;
1765     offset                   += 6;
1766     pdu_flvh_length          += 6;
1767   } else {
1768     /* use last values */
1769     header_offset             = last_pdu_offsets->header;
1770   }
1771   /* offset should now be pointing to data (if one exists) */
1772
1773   /* add Protocol ID item (Header)*/
1774   protocol_id = tvb_get_ntohl(tvb, header_offset);
1775   proto_tree_add_uint(pdu_tree, hf_acn_protocol_id, tvb, header_offset, 4, protocol_id);
1776   header_offset += 4;
1777
1778   /* Add protocol to tree*/
1779   name = val_to_str(protocol_id, acn_protocol_id_vals, "id not valid (%d)");
1780   proto_item_append_text(ti, ": ");
1781   proto_item_append_text(ti, "%s", name);
1782
1783   /* add association item */
1784   association = tvb_get_ntohs(tvb, header_offset);
1785   proto_tree_add_uint(pdu_tree, hf_acn_association, tvb, header_offset, 2, association);
1786   /*header_offset += 2;*/
1787
1788   /* Adjust data */
1789   if (pdu_flags & ACN_PDU_FLAG_D) {
1790     /* use new values */
1791     data_offset = offset;
1792     data_length = pdu_length - pdu_flvh_length;
1793     last_pdu_offsets->data = offset;
1794     last_pdu_offsets->data_length = data_length;
1795   } else {
1796     /* use last values */
1797     data_offset = last_pdu_offsets->data;
1798     data_length = last_pdu_offsets->data_length;
1799   }
1800   end_offset = data_offset + data_length;
1801
1802   switch (protocol_id) {
1803     case ACN_PROTOCOL_ID_SDT:
1804       while (data_offset < end_offset) {
1805         old_offset  = data_offset;
1806         data_offset = dissect_acn_sdt_wrapped_pdu(tvb, pinfo, pdu_tree, data_offset, &pdu_offsets);
1807         if (old_offset == data_offset) break;
1808       }
1809       break;
1810     case ACN_PROTOCOL_ID_DMP:
1811       while (data_offset < end_offset) {
1812         old_offset  = data_offset;
1813         data_offset = dissect_acn_dmp_pdu(tvb, pinfo, pdu_tree, data_offset, &pdu_offsets);
1814         if (data_offset == old_offset) break;
1815       }
1816       break;
1817   }
1818   return pdu_start + pdu_length;
1819 }
1820
1821
1822 /******************************************************************************/
1823 /* level to string (ascii)                                                    */
1824 /*  level    : 8 bit value                                                    */
1825 /*  string   : pointer to buffer to fill                                      */
1826 /*  leading_char: character to buffer left of digits                             */
1827 /*  min_char : mininum number of characters (for filling, not including space)*/
1828 /*  show_zero: show zeros or dots                                             */
1829 /* also adds a space to right end                                             */
1830 /*                                                                            */
1831 /*  returns end of string                                                     */
1832 /*  faster than printf()                                                      */
1833 static char *
1834 ltos(guint8 level, gchar *string, guint8 base, gchar leading_char, guint8 min_chars, gboolean show_zero)
1835 {
1836   guint8 i;
1837   /* verify base */
1838   if (base < 2 || base > 16) {
1839     *string = '\0';
1840     return(string);
1841   }
1842   /* deal with zeros */
1843   if ((level == 0) && (!show_zero)) {
1844     for (i=0; i<min_chars; i++) {
1845       string[i] = '.';
1846     }
1847     string[i++] = ' ';
1848     string[i] = '\0';
1849     return(string + i);
1850   }
1851
1852   i = 0;
1853   /* do our convert, comes out backwards! */
1854   do {
1855     string[i++] = "0123456789ABCDEF"[level % base];
1856   } while ((level /= base) > 0);
1857
1858   /* expand to needed character */
1859   for (; i<min_chars; i++) {
1860     string[i] = leading_char;
1861   }
1862   /* terminate */
1863   string[i] = '\0';
1864
1865   /* now reverse (and correct) the order */
1866   g_strreverse(string);
1867
1868   /* add a space at the end (ok it's at the start but it will be at the end)*/
1869   string[i++] = ' ';
1870   string[i] = '\0';
1871   return(string + i);
1872 }
1873
1874
1875 /******************************************************************************/
1876 /* Dissect DMX data PDU                                                       */
1877 #define BUFFER_SIZE 128
1878 static guint32
1879 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)
1880 {
1881   /* common to all pdu */
1882   guint8            pdu_flags;
1883   guint32           pdu_start;
1884   guint32           pdu_length;
1885   guint32           pdu_flvh_length; /* flags, length, vector, header */
1886   guint8            octet;
1887   guint32           length1;
1888   guint32           length2;
1889   guint32           length3;
1890   guint32           vector_offset;
1891   guint32           data_offset;
1892   guint32           end_offset;
1893   guint32           data_length;
1894   guint32           header_offset;
1895   guint32           total_cnt;
1896   guint32           item_cnt;
1897
1898   proto_item       *ti, *pi;
1899   proto_tree       *pdu_tree  = NULL;
1900   proto_tree       *flag_tree = NULL;
1901 /*  proto_tree *addr_tree = NULL; */
1902
1903 /* this pdu */
1904   acn_dmp_adt_type  adt       = {0,0,0,0,0,0};
1905   const gchar      *name;
1906   guint32           vector;
1907   gchar             buffer[BUFFER_SIZE];
1908   char             *buf_ptr;
1909   guint             x;
1910   guint8            level;
1911   guint8            min_char;
1912   guint8            base;
1913   gchar             leading_char;
1914   guint             perline;
1915   guint             halfline;
1916   guint16           dmx_count;
1917   guint16           dmx_start_code;
1918
1919   buffer[0] = 0;
1920
1921   /* save start of pdu block */
1922   pdu_start = offset;
1923
1924   /* get PDU flags and length flag first */
1925   octet     = tvb_get_guint8(tvb, offset++);
1926   pdu_flags = octet & 0xf0;
1927   length1   = octet & 0x0f;     /* bottom 4 bits only */
1928   length2   = tvb_get_guint8(tvb, offset++);
1929
1930   /* if length flag is set, then we have a 20 bit length else we have a 12 bit */
1931   /* flvh = flags, length, vector, header */
1932   if (pdu_flags & ACN_PDU_FLAG_L) {
1933     length3 = tvb_get_guint8(tvb, offset);
1934     offset += 1;
1935     pdu_length = length3 | (length2 << 8) | (length1 << 16);
1936     pdu_flvh_length = 3;
1937   } else {
1938     pdu_length = length2 | (length1 << 8);
1939     pdu_flvh_length = 2;
1940   }
1941   /* offset should now be pointing to vector (if one exists) */
1942
1943   /* Add pdu item and tree */
1944   ti       = proto_tree_add_item(tree, hf_acn_pdu, tvb, pdu_start, pdu_length, ENC_NA);
1945   pdu_tree = proto_item_add_subtree(ti, ett_acn_dmx_data_pdu);
1946
1947   /* Add flag item and tree */
1948   pi = proto_tree_add_uint(pdu_tree, hf_acn_pdu_flags, tvb, pdu_start, 1, pdu_flags);
1949   flag_tree = proto_item_add_subtree(pi, ett_acn_pdu_flags);
1950   proto_tree_add_item(flag_tree, hf_acn_pdu_flag_l, tvb, pdu_start, 1, ENC_BIG_ENDIAN);
1951   proto_tree_add_item(flag_tree, hf_acn_pdu_flag_v, tvb, pdu_start, 1, ENC_BIG_ENDIAN);
1952   proto_tree_add_item(flag_tree, hf_acn_pdu_flag_h, tvb, pdu_start, 1, ENC_BIG_ENDIAN);
1953   proto_tree_add_item(flag_tree, hf_acn_pdu_flag_d, tvb, pdu_start, 1, ENC_BIG_ENDIAN);
1954
1955   /* Add PDU Length item */
1956   proto_tree_add_uint(pdu_tree, hf_acn_pdu_length, tvb, pdu_start, pdu_flvh_length, pdu_length);
1957
1958   /* Set vector offset */
1959   if (pdu_flags & ACN_PDU_FLAG_V) {
1960     /* use new values */
1961     vector_offset = offset;
1962     last_pdu_offsets->vector = offset;
1963     offset += 1;
1964     pdu_flvh_length += 1;
1965   } else {
1966     /* use last values */
1967     vector_offset = last_pdu_offsets->vector;
1968   }
1969   /* offset should now be pointing to header (if one exists) */
1970
1971   /* Add Vector item */
1972   vector = tvb_get_guint8(tvb, vector_offset);
1973   proto_tree_add_uint(pdu_tree, hf_acn_dmp_vector, tvb, vector_offset, 1, vector);
1974
1975   /* Add Vector item to tree*/
1976   name = val_to_str(vector, acn_dmp_vector_vals, "not valid (%d)");
1977   proto_item_append_text(ti, ": ");
1978   proto_item_append_text(ti, "%s", name);
1979
1980   /* Set header offset */
1981   if (pdu_flags & ACN_PDU_FLAG_H) {
1982     /* use new values */
1983     header_offset = offset;
1984     last_pdu_offsets->header = offset;
1985     offset += 1;
1986     pdu_flvh_length++;
1987   } else {
1988     /* use last values */
1989     header_offset = last_pdu_offsets->header;
1990   }
1991   /* offset should now be pointing to data (if one exists) */
1992
1993   /* process based on vector */
1994   acn_add_dmp_address_type(tvb, pinfo, pdu_tree, header_offset, &adt);
1995
1996   /* Adjust data */
1997   if (pdu_flags & ACN_PDU_FLAG_D) {
1998     /* use new values */
1999     data_offset = offset;
2000     data_length = pdu_length - pdu_flvh_length;
2001     last_pdu_offsets->data = offset;
2002     last_pdu_offsets->data_length = data_length;
2003   } else {
2004     /* use last values */
2005     data_offset = last_pdu_offsets->data;
2006     data_length = last_pdu_offsets->data_length;
2007   }
2008   end_offset = data_offset + data_length;
2009
2010   switch (vector) {
2011     case ACN_DMP_VECTOR_SET_PROPERTY:
2012       dmx_start_code = tvb_get_ntohs(tvb, data_offset);
2013       if (protocol_id==ACN_PROTOCOL_ID_DMX_2) {
2014         proto_tree_add_item(pdu_tree, hf_acn_dmx_2_first_property_address, tvb, data_offset, 2, ENC_BIG_ENDIAN);
2015       } else{
2016         proto_tree_add_item(pdu_tree, hf_acn_dmx_start_code, tvb, data_offset, 2, ENC_BIG_ENDIAN);
2017       }
2018       data_offset += 2;
2019       proto_tree_add_item(pdu_tree, hf_acn_dmx_increment, tvb, data_offset, 2, ENC_BIG_ENDIAN);
2020       data_offset += 2;
2021       dmx_count    = tvb_get_ntohs(tvb, data_offset);
2022       proto_tree_add_item(pdu_tree, hf_acn_dmx_count, tvb, data_offset, 2, ENC_BIG_ENDIAN);
2023       data_offset += 2;
2024
2025       if (protocol_id==ACN_PROTOCOL_ID_DMX_2) {
2026         proto_tree_add_item(pdu_tree, hf_acn_dmx_2_start_code, tvb, data_offset, 1, ENC_BIG_ENDIAN);
2027         data_offset += 1;
2028         dmx_count   -= 1;
2029       }
2030
2031       buf_ptr = buffer;
2032
2033       switch (global_acn_dmx_display_line_format) {
2034         case ACN_PREF_DMX_DISPLAY_16PL:
2035           perline  = 16;
2036           halfline = 8;
2037           break;
2038         default:
2039           perline  = 20;
2040           halfline = 10;
2041       }
2042
2043       /* values base on display mode */
2044       switch ((guint)global_acn_dmx_display_view) {
2045         case ACN_PREF_DMX_DISPLAY_HEX:
2046           min_char = 2;
2047           base     = 16;
2048           break;
2049 /*        case ACN_PREF_DMX_DISPLAY_PER: */
2050         default:
2051           min_char = 3;
2052           base     = 10;
2053       }
2054
2055       /* do we display leading zeros */
2056       if (global_acn_dmx_display_leading_zeros) {
2057         leading_char = '0';
2058       } else {
2059         leading_char = ' ';
2060       }
2061
2062       /* add a snippet to info (this may be slow) */
2063       col_append_fstr(pinfo->cinfo,COL_INFO, ", Sc %02x, [%02x %02x %02x %02x %02x %02x...]",
2064         dmx_start_code,
2065         tvb_get_guint8(tvb, data_offset),
2066         tvb_get_guint8(tvb, data_offset+1),
2067         tvb_get_guint8(tvb, data_offset+2),
2068         tvb_get_guint8(tvb, data_offset+3),
2069         tvb_get_guint8(tvb, data_offset+4),
2070         tvb_get_guint8(tvb, data_offset+5));
2071
2072       /* add a header line */
2073       for (x=0; x<perline; x++) {
2074         buf_ptr = ltos((guint8)(x+1), buf_ptr, 10, ' ', min_char, FALSE);
2075         if ((x+1)==halfline) {
2076           *buf_ptr++ =  '|';
2077           *buf_ptr++ =  ' ';
2078         }
2079       }
2080       *buf_ptr = '\0';
2081       proto_tree_add_string(pdu_tree, hf_acn_dmx_data, tvb, data_offset, dmx_count, 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_string_format(pdu_tree, hf_acn_dmx_data, tvb, data_offset, item_cnt, buffer, "%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, hf_acn_adhoc_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_ep_str(&guid));
2642
2643         /* add cid to info */
2644         col_add_fstr(pinfo->cinfo,COL_INFO, "CID %s", guid_to_ep_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_ep_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_captured_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 #if 0
2800     { &hf_acn_client_protocol_id,
2801       { "Client Protocol ID", "acn.client_protocol_id",
2802         FT_UINT32, BASE_DEC, VALS(acn_protocol_id_vals), 0x0,
2803         NULL, HFILL }
2804     },
2805 #endif
2806     /* DMP data */
2807     { &hf_acn_data,
2808       { "Data", "acn.dmp_data",
2809         FT_BYTES, BASE_NONE, NULL, 0x0,
2810         NULL, HFILL }
2811     },
2812     { &hf_acn_data8,
2813       { "Addr", "acn.dmp_data8",
2814         FT_UINT8, BASE_DEC_HEX, NULL, 0x0,
2815         "Data8", HFILL }
2816     },
2817     { &hf_acn_data16,
2818       { "Addr", "acn.dmp_data16",
2819         FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
2820         "Data16", HFILL }
2821     },
2822     { &hf_acn_data24,
2823       { "Addr", "acn.dmp_data24",
2824         FT_UINT24, BASE_DEC_HEX, NULL, 0x0,
2825         "Data24", HFILL }
2826     },
2827     { &hf_acn_data32,
2828       { "Addr", "acn.dmp_data32",
2829         FT_UINT32, BASE_DEC_HEX, NULL, 0x0,
2830         "Data32", HFILL }
2831     },
2832
2833     /* DMP Address type*/
2834 #if 0
2835     { &hf_acn_dmp_adt,
2836       { "Address and Data Type", "acn.dmp_adt",
2837         FT_UINT8, BASE_DEC_HEX, NULL, 0x0,
2838         NULL, HFILL }
2839     },
2840 #endif
2841     { &hf_acn_dmp_adt_a,
2842       { "Size", "acn.dmp_adt_a",
2843         FT_UINT8, BASE_DEC, VALS(acn_dmp_adt_a_vals), 0x03,
2844         NULL, HFILL }
2845     },
2846     { &hf_acn_dmp_adt_d,
2847       { "Data Type", "acn.dmp_adt_d",
2848         FT_UINT8, BASE_DEC, VALS(acn_dmp_adt_d_vals), 0x30,
2849         NULL, HFILL }
2850     },
2851     { &hf_acn_dmp_adt_r,
2852       { "Relative", "acn.dmp_adt_r",
2853         FT_UINT8, BASE_DEC, VALS(acn_dmp_adt_r_vals), 0x40,
2854         NULL, HFILL }
2855     },
2856     { &hf_acn_dmp_adt_v,
2857       { "Virtual", "acn.dmp_adt_v",
2858         FT_UINT8, BASE_DEC, VALS(acn_dmp_adt_v_vals), 0x80,
2859         NULL, HFILL }
2860     },
2861     { &hf_acn_dmp_adt_x,
2862       { "Reserved", "acn.dmp_adt_x",
2863         FT_UINT8, BASE_DEC, NULL, 0x0c,
2864         NULL, HFILL }
2865     },
2866
2867     /* DMP Reason Code */
2868     { &hf_acn_dmp_reason_code,
2869       { "Reason Code", "acn.dmp_reason_code",
2870         FT_UINT8, BASE_DEC, VALS(acn_dmp_reason_code_vals), 0x0,
2871         NULL, HFILL }
2872     },
2873
2874     /* DMP Vector */
2875     { &hf_acn_dmp_vector,
2876       { "DMP Vector", "acn.dmp_vector",
2877         FT_UINT8, BASE_DEC, VALS(acn_dmp_vector_vals), 0x0,
2878         NULL, HFILL }
2879     },
2880
2881     { &hf_acn_dmp_actual_address,
2882       { "Actual Address", "acn.dmp_actual_address",
2883         FT_UINT32, BASE_HEX, NULL, 0x0,
2884         NULL, HFILL }
2885     },
2886
2887     { &hf_acn_dmp_virtual_address,
2888       { "Virtual Address", "acn.dmp_virtual_address",
2889         FT_UINT32, BASE_HEX, NULL, 0x0,
2890         NULL, HFILL }
2891     },
2892
2893     { &hf_acn_dmp_actual_address_first,
2894       { "Actual Address First", "acn.dmp_actual_address_first",
2895         FT_UINT32, BASE_HEX, NULL, 0x0,
2896         NULL, HFILL }
2897     },
2898
2899     { &hf_acn_dmp_virtual_address_first,
2900       { "Virtual Address First", "acn.dmp_virtual_address_first",
2901         FT_UINT32, BASE_HEX, NULL, 0x0,
2902         NULL, HFILL }
2903     },
2904
2905     /* Expiry */
2906     { &hf_acn_expiry,
2907       { "Expiry", "acn.expiry",
2908         FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
2909         NULL, HFILL }
2910     },
2911     /* First Member to ACK */
2912     { &hf_acn_first_memeber_to_ack,
2913       { "First Member to ACK", "acn.first_member_to_ack",
2914         FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
2915         NULL, HFILL }
2916     },
2917     /* First Missed Sequence */
2918     { &hf_acn_first_missed_sequence,
2919       { "First Missed Sequence", "acn.first_missed_sequence",
2920         FT_UINT32, BASE_DEC_HEX, NULL, 0x0,
2921         NULL, HFILL }
2922     },
2923     /* IPV4 */
2924     { &hf_acn_ipv4,
2925       { "IPV4", "acn.ipv4",
2926         FT_IPv4, BASE_NONE, NULL, 0x0,
2927         NULL, HFILL }
2928     },
2929     /* IPV6 */
2930     { &hf_acn_ipv6,
2931       { "IPV6", "acn.ipv6",
2932         FT_IPv6, BASE_NONE, NULL, 0x0,
2933         NULL, HFILL }
2934     },
2935     /* Last Member to ACK */
2936     { &hf_acn_last_memeber_to_ack,
2937       { "Last Member to ACK", "acn.last_member_to_ack",
2938         FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
2939         NULL, HFILL }
2940     },
2941     /* Last Missed Sequence */
2942     { &hf_acn_last_missed_sequence,
2943       { "Last Missed Sequence", "acn.last_missed_sequence",
2944         FT_UINT32, BASE_DEC_HEX, NULL, 0x0,
2945         NULL, HFILL }
2946     },
2947     /* MAK threshold */
2948     { &hf_acn_mak_threshold,
2949       { "MAK Threshold", "acn.mak_threshold",
2950         FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
2951         NULL, HFILL }
2952     },
2953     /* MemberID */
2954     { &hf_acn_member_id,
2955       { "Member ID", "acn.member_id",
2956         FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
2957         NULL, HFILL }
2958     },
2959     /* NAK Holdoff */
2960     { &hf_acn_nak_holdoff,
2961       { "NAK holdoff (ms)", "acn.nak_holdoff",
2962         FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
2963         NULL, HFILL }
2964     },
2965     /* NAK Max Wait */
2966     { &hf_acn_nak_max_wait,
2967       { "NAK Max Wait (ms)", "acn.nak_max_wait",
2968         FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
2969         NULL, HFILL }
2970     },
2971     /* NAK Modulus */
2972     { &hf_acn_nak_modulus,
2973       { "NAK Modulus", "acn.nak_modulus",
2974         FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
2975         NULL, HFILL }
2976     },
2977     /* NAK Outbound Flag */
2978     { &hf_acn_nak_outbound_flag,
2979       { "NAK Outbound Flag", "acn.nak_outbound_flag",
2980         FT_BOOLEAN, 8, NULL, 0x80,
2981         NULL, HFILL }
2982     },
2983     /* Oldest Available Wrapper */
2984     { &hf_acn_oldest_available_wrapper,
2985       { "Oldest Available Wrapper", "acn.oldest_available_wrapper",
2986         FT_UINT32, BASE_DEC_HEX, NULL, 0x0,
2987         NULL, HFILL }
2988     },
2989     /* Preamble Sizet */
2990     { &hf_acn_preamble_size,
2991       { "Size of preamble", "acn.preamble_size",
2992         FT_UINT16, BASE_DEC, NULL, 0x0,
2993         "Preamble size in bytes", HFILL }
2994     },
2995     /* Packet Identifier */
2996     { &hf_acn_packet_identifier,
2997       { "Packet Identifier", "acn.packet_identifier",
2998         FT_STRING, BASE_NONE, NULL, 0x0,
2999         NULL, HFILL }
3000     },
3001     /* PDU */
3002     { &hf_acn_pdu,
3003       { "PDU", "acn.pdu",
3004         FT_NONE, BASE_NONE, NULL, 0x0,
3005         NULL, HFILL }
3006     },
3007     /* PDU flags*/
3008     { &hf_acn_pdu_flags,
3009       { "Flags", "acn.pdu.flags",
3010         FT_UINT8, BASE_HEX, NULL, 0x0,
3011         "PDU Flags", HFILL }
3012     },
3013     { &hf_acn_pdu_flag_d,
3014       { "Data", "acn.pdu.flag_d",
3015         FT_BOOLEAN, 8, NULL, ACN_PDU_FLAG_D,
3016         "Data flag", HFILL }
3017     },
3018     { &hf_acn_pdu_flag_h,
3019       { "Header", "acn.pdu.flag_h",
3020         FT_BOOLEAN, 8, NULL, ACN_PDU_FLAG_H,
3021         "Header flag", HFILL }
3022     },
3023     { &hf_acn_pdu_flag_l,
3024       { "Length", "acn.pdu.flag_l",
3025         FT_BOOLEAN, 8, NULL, ACN_PDU_FLAG_L,
3026         "Length flag", HFILL }
3027     },
3028     { &hf_acn_pdu_flag_v,
3029       { "Vector", "acn.pdu.flag_v",
3030         FT_BOOLEAN, 8, NULL, ACN_PDU_FLAG_V,
3031         "Vector flag", HFILL }
3032     },
3033     /* PDU Length */
3034     { &hf_acn_pdu_length,
3035       { "Length", "acn.pdu.length",
3036         FT_UINT32, BASE_DEC, NULL, 0x0,
3037         "PDU Length", HFILL }
3038     },
3039     /* Port */
3040     { &hf_acn_port,
3041       { "Port", "acn.port",
3042         FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
3043         NULL, HFILL }
3044     },
3045     /* Postamble Size */
3046     { &hf_acn_postamble_size,
3047       { "Size of postamble", "acn.postamble_size",
3048         FT_UINT16, BASE_DEC, NULL, 0x0,
3049         "Postamble size in bytes", HFILL }
3050     },
3051     /* Protocol ID */
3052     { &hf_acn_protocol_id,
3053       { "Protocol ID", "acn.protocol_id",
3054         FT_UINT32, BASE_DEC, VALS(acn_protocol_id_vals), 0x0,
3055         NULL, HFILL }
3056     },
3057     /* Reason Code */
3058     { &hf_acn_reason_code,
3059       { "Reason Code", "acn.reason_code",
3060         FT_UINT8, BASE_DEC, VALS(acn_reason_code_vals), 0x0,
3061         NULL, HFILL }
3062     },
3063     /* Reciprocal Channel */
3064     { &hf_acn_reciprocal_channel,
3065       { "Reciprocal Channel Number", "acn.reciprocal_channel",
3066         FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
3067         "Reciprocal Channel", HFILL }
3068     },
3069     /* Refuse Code */
3070     { &hf_acn_refuse_code,
3071       { "Refuse Code", "acn.refuse_code",
3072         FT_UINT8, BASE_DEC, VALS(acn_refuse_code_vals), 0x0,
3073         NULL, HFILL }
3074     },
3075     /* Reliable Sequence Number */
3076     { &hf_acn_reliable_sequence_number,
3077       { "Reliable Sequence Number", "acn.reliable_sequence_number",
3078         FT_UINT32, BASE_DEC_HEX, NULL, 0x0,
3079         NULL, HFILL }
3080     },
3081     /* Ad-hoc Expiry */
3082     { &hf_acn_adhoc_expiry,
3083       { "Ad-hoc Expiry", "acn.adhoc_expiry",
3084         FT_UINT8, BASE_DEC, NULL, 0x0,
3085         NULL, HFILL }
3086     },
3087     /* SDT Vector */
3088     { &hf_acn_sdt_vector,
3089       { "STD Vector", "acn.sdt_vector",
3090         FT_UINT8, BASE_DEC, VALS(acn_sdt_vector_vals), 0x0,
3091         NULL, HFILL }
3092     },
3093
3094     /* DMX Vector */
3095     { &hf_acn_dmx_vector,
3096       { "Vector", "acn.dmx_vector",
3097         FT_UINT32, BASE_DEC, VALS(acn_dmx_vector_vals), 0x0,
3098         "DMX Vector", HFILL }
3099     },
3100     /* DMX Source Name */
3101     { &hf_acn_dmx_source_name,
3102       { "Source", "acn.dmx.source_name",
3103         FT_STRING, BASE_NONE, NULL, 0x0,
3104         "DMX Source Name", HFILL }
3105     },
3106
3107     /* DMX priority */
3108     { &hf_acn_dmx_priority,
3109       { "Priority", "acn.dmx.priority",
3110         FT_UINT8, BASE_DEC, NULL, 0x0,
3111         "DMX Priority", HFILL }
3112     },
3113
3114     /* DMX 2 reserved */
3115     { &hf_acn_dmx_2_reserved,
3116       { "Reserved", "acn.dmx.reserved",
3117         FT_UINT16, BASE_DEC, NULL, 0x0,
3118         "DMX Reserved", HFILL }
3119     },
3120
3121     /* DMX Sequence number */
3122     { &hf_acn_dmx_sequence_number,
3123       { "Seq No", "acn.dmx.seq_number",
3124         FT_UINT8, BASE_DEC, NULL, 0x0,
3125         "DMX Sequence Number", HFILL }
3126     },
3127
3128     /* DMX 2 options */
3129     { &hf_acn_dmx_2_options,
3130       { "Options", "acn.dmx.options",
3131         FT_UINT8, BASE_DEC, NULL, 0x0,
3132         "DMX Options", HFILL }
3133     },
3134
3135     { &hf_acn_dmx_2_option_p,
3136       { "Preview Data", "acn.dmx.option_p",
3137         FT_BOOLEAN, 8, NULL, ACN_DMX_OPTION_P,
3138         "Preview Data flag", HFILL }
3139     },
3140
3141     { &hf_acn_dmx_2_option_s,
3142       { "Stream Terminated", "acn.dmx.option_s",
3143         FT_BOOLEAN, 8, NULL, ACN_DMX_OPTION_S,
3144         "Stream Terminated flag", HFILL }
3145     },
3146
3147     /* DMX Universe */
3148     { &hf_acn_dmx_universe,
3149       { "Universe", "acn.dmx.universe",
3150         FT_UINT16, BASE_DEC, NULL, 0x0,
3151         "DMX Universe", HFILL }
3152     },
3153
3154     /* DMX Start Code */
3155     { &hf_acn_dmx_start_code,
3156       { "Start Code", "acn.dmx.start_code",
3157         FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
3158         "DMX Start Code", HFILL }
3159     },
3160
3161     /* DMX 2 First Property Address */
3162     { &hf_acn_dmx_2_first_property_address,
3163       { "First Property Address", "acn.dmx.start_code",
3164         FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
3165         "DMX First Property Address", HFILL }
3166     },
3167
3168     /* DMX Address Increment */
3169     { &hf_acn_dmx_increment,
3170       { "Increment", "acn.dmx.increment",
3171         FT_UINT16, BASE_DEC, NULL, 0x0,
3172         "DMX Increment", HFILL }
3173     },
3174
3175     /* DMX Packet Count */
3176     { &hf_acn_dmx_count,
3177       { "Count", "acn.dmx.count",
3178         FT_UINT16, BASE_DEC, NULL, 0x0,
3179         "DMX Count", HFILL }
3180     },
3181
3182     /* DMX 2 Start Code */
3183     { &hf_acn_dmx_2_start_code,
3184       { "Start Code", "acn.dmx.start_code2",
3185         FT_UINT8, BASE_DEC_HEX, NULL, 0x0,
3186         "DMX Start Code", HFILL }
3187     },
3188
3189     { &hf_acn_dmx_data,
3190       { "Data", "acn.dmx.data",
3191         FT_BYTES, BASE_NONE, NULL, 0x0,
3192         NULL, HFILL }
3193     },
3194
3195     /* Session Count */
3196 #if 0
3197     { &hf_acn_session_count,
3198       { "Session Count", "acn.session_count",
3199         FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
3200         NULL, HFILL }
3201     },
3202 #endif
3203     /* Total Sequence Number */
3204     { &hf_acn_total_sequence_number,
3205       { "Total Sequence Number", "acn.total_sequence_number",
3206         FT_UINT32, BASE_DEC_HEX, NULL, 0x0,
3207         NULL, HFILL }
3208     }
3209   };
3210
3211   /* Setup protocol subtree array */
3212   static gint *ett[] = {
3213     &ett_acn,
3214     &ett_acn_channel_owner_info_block,
3215     &ett_acn_channel_member_info_block,
3216     &ett_acn_channel_parameter,
3217     &ett_acn_address,
3218     &ett_acn_address_type,
3219     &ett_acn_pdu_flags,
3220     &ett_acn_dmp_pdu,
3221     &ett_acn_sdt_pdu,
3222     &ett_acn_sdt_client_pdu,
3223     &ett_acn_sdt_base_pdu,
3224     &ett_acn_root_pdu,
3225     &ett_acn_dmx_address,
3226     &ett_acn_dmx_2_options,
3227     &ett_acn_dmx_data_pdu,
3228     &ett_acn_dmx_pdu
3229   };
3230
3231   module_t *acn_module;
3232   proto_acn = proto_register_protocol (
3233     "Architecture for Control Networks", /* name */
3234     "ACN",                               /* short name */
3235     "acn"                                /* abbrev */
3236     );
3237
3238   proto_register_field_array(proto_acn, hf, array_length(hf));
3239   proto_register_subtree_array(ett, array_length(ett));
3240
3241   acn_module = prefs_register_protocol(proto_acn, NULL);
3242   prefs_register_bool_preference(acn_module, "heuristic_acn",
3243                                  "Decode ACN",
3244                                  "Enable Architecture for Control Networks dissector (ANSI BSR E1.17)",
3245                                  &global_acn_heur);
3246
3247   prefs_register_bool_preference(acn_module, "dmx_enable",
3248                                  "Streaming DMX",
3249                                  "Enable Streaming DMX extension dissector (ANSI BSR E1.31)",
3250                                  &global_acn_dmx_enable);
3251
3252   prefs_register_enum_preference(acn_module, "dmx_display_view",
3253                                  "DMX, display format",
3254                                  "Display format",
3255                                  &global_acn_dmx_display_view,
3256                                  dmx_display_view,
3257                                  TRUE);
3258
3259   prefs_register_bool_preference(acn_module, "dmx_display_zeros",
3260                                  "DMX, display zeros",
3261                                  "Display zeros instead of dots",
3262                                  &global_acn_dmx_display_zeros);
3263
3264   prefs_register_bool_preference(acn_module, "dmx_display_leading_zeros",
3265                                  "DMX, display leading zeros",
3266                                  "Display leading zeros on levels",
3267                                  &global_acn_dmx_display_leading_zeros);
3268
3269   prefs_register_enum_preference(acn_module, "dmx_display_line_format",
3270                                  "DMX, display line format",
3271                                  "Display line format",
3272                                  &global_acn_dmx_display_line_format,
3273                                  dmx_display_line_format,
3274                                  TRUE);
3275 }
3276
3277
3278 /******************************************************************************/
3279 /* Register handoff                                                           */
3280 void
3281 proto_reg_handoff_acn(void)
3282 {
3283   /* dissector_handle_t acn_handle; */
3284   /* acn_handle = new_create_dissector_handle(dissect_acn, proto_acn); */
3285   /* dissector_add_for_decode_as("udp.port", acn_handle);                         */
3286   heur_dissector_add("udp", dissect_acn_heur, proto_acn);
3287 }
3288
3289
3290 /*
3291  * Editor modelines
3292  *
3293  * Local Variables:
3294  * c-basic-offset: 2
3295  * tab-width: 8
3296  * indent-tabs-mode: nil
3297  * End:
3298  *
3299  * ex: set shiftwidth=2 tabstop=8 expandtab:
3300  * :indentSize=2:tabSize=8:noTabs=true:
3301  */