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