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