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