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