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