2 * Routines for ACN packet disassembly
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
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
48 #include <epan/packet.h>
49 #include <epan/prefs.h>
50 #include <epan/packet.h>
51 #include <epan/ipv6-utils.h>
54 #include "packet-acn.h"
58 * ANSI BSR E1.17 Architecture for Control Networks
62 #define ACTUAL_ADDRESS 0
63 /* forward reference */
64 static gboolean dissect_acn_heur( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree );
65 static guint32 acn_add_channel_owner_info_block(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree _U_, int offset);
66 static guint32 acn_add_channel_member_info_block(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree _U_, int offset);
67 static guint32 acn_add_expiry(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, const char *label);
68 static guint32 acn_add_channel_parameter(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset);
69 static guint32 acn_add_address(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, const char *label);
70 static guint32 acn_add_dmp_address_type(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, acn_dmp_adt_type *adt);
71 static guint32 acn_add_dmp_address(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, acn_dmp_adt_type *adt);
72 static guint32 dissect_acn_dmp_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, acn_pdu_offsets *last_pdu_offsets);
73 static guint32 dissect_acn_sdt_wrapped_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree _U_, int offset, acn_pdu_offsets *last_pdu_offsets);
74 static guint32 dissect_acn_sdt_client_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, acn_pdu_offsets *last_pdu_offsets);
75 static guint32 dissect_acn_dmx_data_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, acn_pdu_offsets *last_pdu_offsets);
76 static guint32 dissect_acn_dmx_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, acn_pdu_offsets *last_pdu_offsets);
77 static guint32 dissect_acn_sdt_base_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, acn_pdu_offsets *last_pdu_offsets);
78 static guint32 dissect_acn_root_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, acn_pdu_offsets *last_pdu_offsets);
79 static int dissect_acn(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
80 static gboolean is_acn(tvbuff_t *tvb);
82 /* Global variables */
83 static int proto_acn = -1;
84 static gint ett_acn = -1;
85 static gint ett_acn_channel_owner_info_block = -1;
86 static gint ett_acn_channel_member_info_block = -1;
87 static gint ett_acn_channel_parameter = -1;
88 static gint ett_acn_address = -1;
89 static gint ett_acn_address_type = -1;
90 static gint ett_acn_pdu_flags = -1;
91 static gint ett_acn_dmp_pdu = -1;
92 static gint ett_acn_sdt_pdu = -1;
93 static gint ett_acn_sdt_client_pdu = -1;
94 static gint ett_acn_sdt_base_pdu = -1;
95 static gint ett_acn_root_pdu = -1;
96 static gint ett_acn_dmx_address = -1;
97 static gint ett_acn_dmx_data_pdu = -1;
98 static gint ett_acn_dmx_pdu = -1;
100 /* Register fields */
101 /* In alphabetical order */
102 static int hf_acn_association = -1;
103 static int hf_acn_channel_number = -1;
104 static int hf_acn_cid = -1;
105 static int hf_acn_client_protocol_id = -1;
106 static int hf_acn_data = -1;
107 static int hf_acn_data8 = -1;
108 static int hf_acn_data16 = -1;
109 static int hf_acn_data24 = -1;
110 static int hf_acn_data32 = -1;
111 static int hf_acn_dmp_address1 = -1;
112 static int hf_acn_dmp_address2 = -1;
113 static int hf_acn_dmp_address4 = -1;
114 static int hf_acn_dmp_adt = -1; /* address and data type*/
115 static int hf_acn_dmp_adt_a = -1;
116 static int hf_acn_dmp_adt_v = -1;
117 static int hf_acn_dmp_adt_r = -1;
118 static int hf_acn_dmp_adt_d = -1;
119 static int hf_acn_dmp_adt_x = -1;
120 static int hf_acn_dmp_reason_code = -1;
121 static int hf_acn_dmp_vector = -1;
122 static int hf_acn_dmp_address_data_pairs = -1;
123 static int hf_acn_expiry = -1;
124 static int hf_acn_first_memeber_to_ack = -1;
125 static int hf_acn_first_missed_sequence = -1;
126 static int hf_acn_ip_address_type = -1;
127 static int hf_acn_ipv4 = -1;
128 static int hf_acn_ipv6 = -1;
129 static int hf_acn_last_memeber_to_ack = -1;
130 static int hf_acn_last_missed_sequence = -1;
131 static int hf_acn_mak_threshold = -1;
132 static int hf_acn_member_id = -1;
133 static int hf_acn_nak_holdoff = -1;
134 static int hf_acn_nak_max_wait = -1;
135 static int hf_acn_nak_modulus = -1;
136 static int hf_acn_nak_outbound_flag = -1;
137 static int hf_acn_oldest_available_wrapper = -1;
138 static int hf_acn_packet_identifier = -1;
139 static int hf_acn_pdu = -1;
140 static int hf_acn_pdu_flag_d = -1;
141 static int hf_acn_pdu_flag_h = -1;
142 static int hf_acn_pdu_flag_l = -1;
143 static int hf_acn_pdu_flag_v = -1;
144 static int hf_acn_pdu_flags = -1;
145 static int hf_acn_pdu_length = -1;
146 static int hf_acn_port = -1;
147 static int hf_acn_postamble_size = -1;
148 static int hf_acn_preamble_size = -1;
149 static int hf_acn_protocol_id = -1;
150 static int hf_acn_reason_code = -1;
151 static int hf_acn_reciprocal_channel = -1;
152 static int hf_acn_refuse_code = -1;
153 static int hf_acn_reliable_sequence_number = -1;
154 /* static int hf_acn_sdt_pdu = -1; */
155 static int hf_acn_sdt_vector = -1;
156 static int hf_acn_dmx_vector = -1;
157 static int hf_acn_session_count = -1;
158 static int hf_acn_total_sequence_number = -1;
159 static int hf_acn_dmx_source_name = -1;
160 static int hf_acn_dmx_priority = -1;
161 static int hf_acn_dmx_sequence_number = -1;
162 static int hf_acn_dmx_universe = -1;
164 static int hf_acn_dmx_start_code = -1;
165 static int hf_acn_dmx_increment = -1;
166 static int hf_acn_dmx_count = -1;
168 /* static int hf_acn_dmx_dmp_vector = -1; */
170 /* Try heuristic ACN decode */
171 static gboolean global_acn_heur = FALSE;
172 static gboolean global_acn_dmx_enable = FALSE;
173 static gint global_acn_dmx_display_view = 0;
174 static gint global_acn_dmx_display_line_format = 0;
175 static gboolean global_acn_dmx_display_zeros = FALSE;
176 static gboolean global_acn_dmx_display_leading_zeros = FALSE;
179 static const value_string acn_protocol_id_vals[] = {
180 { ACN_PROTOCOL_ID_SDT, "SDT Protocol" },
181 { ACN_PROTOCOL_ID_DMP, "DMP Protocol" },
182 { ACN_PROTOCOL_ID_DMX, "DMX Protocol" },
186 static const value_string acn_dmp_adt_r_vals[] = {
192 static const value_string acn_dmp_adt_v_vals[] = {
198 static const value_string acn_dmp_adt_d_vals[] = {
199 { ACN_DMP_ADT_D_NS, "Non-range, single data item" },
200 { ACN_DMP_ADT_D_RS, "Range, single data item" },
201 { ACN_DMP_ADT_D_RE, "Range, array of equal size data items" },
202 { ACN_DMP_ADT_D_RM, "Range, series of mixed size data items" },
206 static const value_string acn_dmp_adt_a_vals[] = {
207 { ACN_DMP_ADT_A_1, "1 octet" },
208 { ACN_DMP_ADT_A_2, "2 octets" },
209 { ACN_DMP_ADT_A_4, "4 octets" },
210 { ACN_DMP_ADT_A_R, "reserved" },
215 static const value_string acn_sdt_vector_vals[] = {
216 {ACN_SDT_VECTOR_UNKNOWN, "Unknown"},
217 {ACN_SDT_VECTOR_REL_WRAP, "Reliable Wrapper"},
218 {ACN_SDT_VECTOR_UNREL_WRAP, "Unreliable Wrapper"},
219 {ACN_SDT_VECTOR_CHANNEL_PARAMS, "Channel Parameters"},
220 {ACN_SDT_VECTOR_JOIN, "Join"},
221 {ACN_SDT_VECTOR_JOIN_REFUSE, "Join Refuse"},
222 {ACN_SDT_VECTOR_JOIN_ACCEPT, "Join Accept"},
223 {ACN_SDT_VECTOR_LEAVE, "Leave"},
224 {ACN_SDT_VECTOR_LEAVING, "Leaving"},
225 {ACN_SDT_VECTOR_CONNECT, "Connect"},
226 {ACN_SDT_VECTOR_CONNECT_ACCEPT, "Connect Accept"},
227 {ACN_SDT_VECTOR_CONNECT_REFUSE, "Connect Refuse"},
228 {ACN_SDT_VECTOR_DISCONNECT, "Disconnect"},
229 {ACN_SDT_VECTOR_DISCONNECTING, "Disconnecting"},
230 {ACN_SDT_VECTOR_ACK, "Ack"},
231 {ACN_SDT_VECTOR_NAK, "Nak"},
232 {ACN_SDT_VECTOR_GET_SESSION, "Get Session"},
233 {ACN_SDT_VECTOR_SESSIONS, "Sessions"},
237 static const value_string acn_dmx_vector_vals[] = {
238 {ACN_DMX_VECTOR, "Streaming DMX"},
242 static const value_string acn_dmp_vector_vals[] = {
243 {ACN_DMP_VECTOR_UNKNOWN, "Unknown"},
244 {ACN_DMP_VECTOR_GET_PROPERTY, "Get Property"},
245 {ACN_DMP_VECTOR_SET_PROPERTY, "Set Property"},
246 {ACN_DMP_VECTOR_GET_PROPERTY_REPLY, "Get property reply"},
247 {ACN_DMP_VECTOR_EVENT, "Event"},
248 {ACN_DMP_VECTOR_MAP_PROPERTY, "Map Property"},
249 {ACN_DMP_VECTOR_UNMAP_PROPERTY, "Unmap Property"},
250 {ACN_DMP_VECTOR_SUBSCRIBE, "Subscribe"},
251 {ACN_DMP_VECTOR_UNSUBSCRIBE, "Unsubscribe"},
252 {ACN_DMP_VECTOR_GET_PROPERTY_FAIL, "Get Property Fail"},
253 {ACN_DMP_VECTOR_SET_PROPERTY_FAIL, "Set Property Fail"},
254 {ACN_DMP_VECTOR_MAP_PROPERTY_FAIL, "Map Property Fail"},
255 {ACN_DMP_VECTOR_SUBSCRIBE_ACCEPT, "Subscribe Accept"},
256 {ACN_DMP_VECTOR_SUBSCRIBE_REJECT, "Subscribe Reject"},
257 {ACN_DMP_VECTOR_ALLOCATE_MAP, "Allocate Map"},
258 {ACN_DMP_VECTOR_ALLOCATE_MAP_REPLY, "Allocate Map Reply"},
259 {ACN_DMP_VECTOR_DEALLOCATE_MAP, "Deallocate Map"},
263 static const value_string acn_ip_address_type_vals[] = {
264 { ACN_ADDR_NULL, "Null"},
265 { ACN_ADDR_IPV4, "IPv4"},
266 { ACN_ADDR_IPV6, "IPv6"},
267 { ACN_ADDR_IPPORT, "Port"},
271 static const value_string acn_refuse_code_vals[] = {
272 { ACN_REFUSE_CODE_NONSPECIFIC, "Nonspecific" },
273 { ACN_REFUSE_CODE_ILLEGAL_PARAMS, "Illegal Parameters" },
274 { ACN_REFUSE_CODE_LOW_RESOURCES, "Low Resources" },
275 { ACN_REFUSE_CODE_ALREADY_MEMBER, "Already Member" },
276 { ACN_REFUSE_CODE_BAD_ADDR_TYPE, "Bad Address Type" },
277 { ACN_REFUSE_CODE_NO_RECIP_CHAN, "No Reciprocal Channel" },
281 static const value_string acn_reason_code_vals[] = {
282 { ACN_REASON_CODE_NONSPECIFIC, "Nonspecific" },
283 { ACN_REASON_CODE_NO_RECIP_CHAN, "No Reciprocal Channel" },
284 { ACN_REASON_CODE_CHANNEL_EXPIRED, "Channel Expired" },
285 { ACN_REASON_CODE_LOST_SEQUENCE, "Lost Sequence" },
286 { ACN_REASON_CODE_SATURATED, "Saturated" },
287 { ACN_REASON_CODE_TRANS_ADDR_CHANGING, "Transport Address Changing" },
288 { ACN_REASON_CODE_ASKED_TO_LEAVE, "Asked to Leave" },
289 { ACN_REASON_CODE_NO_RECIPIENT, "No Recipient"},
293 static const value_string acn_dmp_reason_code_vals[] = {
294 { ACN_DMP_REASON_CODE_NONSPECIFIC, "Nonspecific" },
295 { ACN_DMP_REASON_CODE_NOT_A_PROPERTY, "Not a Property" },
296 { ACN_DMP_REASON_CODE_WRITE_ONLY, "Write Only" },
297 { ACN_DMP_REASON_CODE_NOT_WRITABLE, "Not Writable" },
298 { ACN_DMP_REASON_CODE_DATA_ERROR, "Data Error" },
299 { ACN_DMP_REASON_CODE_MAPS_NOT_SUPPORTED, "Maps not Supported" },
300 { ACN_DMP_REASON_CODE_SPACE_NOT_AVAILABLE, "Space not Available" },
301 { ACN_DMP_REASON_CODE_PROP_NOT_MAPPABLE, "Property not Mappable"},
302 { ACN_DMP_REASON_CODE_MAP_NOT_ALLOCATED, "Map not Allocated"},
303 { ACN_DMP_REASON_CODE_SUBSCRIPTION_NOT_SUPPORTED, "Subscription not Supported"},
304 { ACN_DMP_REASON_CODE_NO_SUBSCRIPTIONS_SUPPORTED, "No Subscriptions Supported"},
308 static const enum_val_t dmx_display_view[] = {
309 { "hex" , "Hex ", ACN_PREF_DMX_DISPLAY_HEX },
310 { "decimal", "Decimal", ACN_PREF_DMX_DISPLAY_DEC },
311 { "percent", "Percent", ACN_PREF_DMX_DISPLAY_PER },
315 static const enum_val_t dmx_display_line_format[] = {
316 { "20 per line", "20 per line", ACN_PREF_DMX_DISPLAY_20PL },
317 { "16 per line", "16 per line", ACN_PREF_DMX_DISPLAY_16PL },
321 /******************************************************************************/
322 /* Test to see if it is an ACN Packet */
323 static gboolean is_acn(tvbuff_t *tvb)
325 static char acn_packet_id[] = "ASC-E1.17\0\0\0"; /* must be 12 bytes */
328 /* Get the fields in octets 2 - 12 octet */
329 packet_id = tvb_get_ephemeral_string(tvb, 4, 12);
330 if (memcmp(packet_id, &acn_packet_id, 12) == 0) {
337 /******************************************************************************/
338 /* Heuristic dissector */
340 dissect_acn_heur( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree )
342 /* This is a heuristic dissector, which means we get all the UDP
343 * traffic not sent to a known dissector and not claimed by
344 * a heuristic dissector called before us!
347 /* abort if not enabled! */
348 if (!global_acn_heur) return FALSE;
350 /* abort if it is NOT an ACN packet */
351 if (!is_acn(tvb)) return FALSE;
353 /* else, dissect it */
354 dissect_acn(tvb, pinfo, tree);
358 /******************************************************************************/
359 /* Adds tree branch for channel owner info block */
361 acn_add_channel_owner_info_block(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree _U_, int offset)
364 proto_tree *this_tree = NULL;
365 guint32 session_count;
368 pi = proto_tree_add_text(this_tree, tvb, offset, 8, "Channel Owner Info Block");
369 this_tree = proto_item_add_subtree(pi, ett_acn_channel_owner_info_block);
371 proto_tree_add_item(this_tree, hf_acn_member_id, tvb, offset, 2, FALSE);
373 proto_tree_add_item(this_tree, hf_acn_channel_number, tvb, offset, 2, FALSE);
375 offset += acn_add_address(tvb, pinfo, this_tree, offset, "Destination Address:");
376 offset += acn_add_address(tvb, pinfo, this_tree, offset, "Source Address:");
378 session_count = tvb_get_ntohs(tvb, offset);
379 for (x=0; x<session_count; x++) {
380 pi = proto_tree_add_item(this_tree, hf_acn_protocol_id, tvb, offset, 4, FALSE);
381 proto_item_append_text(pi, " #%d", x+1);
387 /******************************************************************************/
388 /* Adds tree branch for channel member info block */
390 acn_add_channel_member_info_block(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree _U_, int offset)
393 proto_tree *this_tree = NULL;
394 guint32 session_count;
397 pi = proto_tree_add_text(this_tree, tvb, offset, 8, "Channel Member Info Block");
398 this_tree = proto_item_add_subtree(pi, ett_acn_channel_member_info_block);
400 proto_tree_add_item(this_tree, hf_acn_member_id, tvb, offset, 2, FALSE);
402 proto_tree_add_item(this_tree, hf_acn_cid, tvb, offset, 16, FALSE);
404 proto_tree_add_item(this_tree, hf_acn_channel_number, tvb, offset, 2, FALSE);
406 offset += acn_add_address(tvb, pinfo, this_tree, offset, "Destination Address:");
407 offset += acn_add_address(tvb, pinfo, this_tree, offset, "Source Address:");
408 proto_tree_add_item(this_tree, hf_acn_reciprocal_channel, tvb, offset, 2, FALSE);
411 session_count = tvb_get_ntohs(tvb, offset);
412 for (x=0; x<session_count; x++) {
413 pi = proto_tree_add_item(this_tree, hf_acn_protocol_id, tvb, offset, 4, FALSE);
414 proto_item_append_text(pi, " #%d", x+1);
421 /******************************************************************************/
422 /* Add labeled expiry */
424 acn_add_expiry(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, const char *label)
426 proto_tree_add_text(tree, tvb, offset, 2, "%s %d", label, tvb_get_guint8(tvb, offset));
432 /******************************************************************************/
433 /* Adds tree branch for channel parameters */
435 acn_add_channel_parameter(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset)
438 proto_tree *param_tree = NULL;
440 pi = proto_tree_add_text(tree, tvb, offset, 8, "Channel Parameter Block");
441 param_tree = proto_item_add_subtree(pi, ett_acn_channel_parameter);
442 proto_tree_add_item(param_tree, hf_acn_expiry, tvb, offset, 1, FALSE);
444 proto_tree_add_item(param_tree, hf_acn_nak_outbound_flag, tvb, offset, 1, FALSE);
446 proto_tree_add_item(param_tree, hf_acn_nak_holdoff, tvb, offset, 2, FALSE);
448 proto_tree_add_item(param_tree, hf_acn_nak_modulus, tvb, offset, 2, FALSE);
450 proto_tree_add_item(param_tree, hf_acn_nak_max_wait, tvb, offset, 2, FALSE);
452 return offset; /* bytes used */
456 /******************************************************************************/
457 /* Add an address tree */
459 acn_add_address(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, const char *label)
462 proto_tree *addr_tree = NULL;
463 guint8 ip_address_type;
468 struct e_in6_addr IPv6;
472 ip_address_type = tvb_get_guint8(tvb, offset);
474 switch (ip_address_type) {
476 proto_tree_add_item(tree, hf_acn_ip_address_type, tvb, offset, 1, FALSE);
480 /* Build tree and add type*/
481 pi = proto_tree_add_text(tree, tvb, offset, 7, label);
482 addr_tree = proto_item_add_subtree(pi, ett_acn_address);
483 proto_tree_add_item(addr_tree, hf_acn_ip_address_type, tvb, offset, 1, FALSE);
486 port = tvb_get_ntohs(tvb, offset);
487 proto_tree_add_item(addr_tree, hf_acn_port, tvb, offset, 2, FALSE);
490 proto_tree_add_item(addr_tree, hf_acn_ipv4, tvb, offset, 4, FALSE);
491 /* Append port and address to tree item */
492 IPv4 = tvb_get_ipv4(tvb, offset);
493 SET_ADDRESS(&addr, AT_IPv4, sizeof(IPv4), &IPv4);
494 proto_item_append_text(pi, " %s, Port %d", address_to_str(&addr), port);
498 /* Build tree and add type*/
499 pi = proto_tree_add_text(tree, tvb, offset, 19, label);
500 addr_tree = proto_item_add_subtree(pi, ett_acn_address);
501 proto_tree_add_item(addr_tree, hf_acn_ip_address_type, tvb, offset, 1, FALSE);
504 port = tvb_get_ntohs(tvb, offset);
505 proto_tree_add_item(addr_tree, hf_acn_port, tvb, offset, 2, FALSE);
508 proto_tree_add_item(addr_tree, hf_acn_ipv6, tvb, offset, 16, FALSE);
509 /* Append port and address to tree item */
510 tvb_get_ipv6(tvb, offset, &IPv6);
511 SET_ADDRESS(&addr, AT_IPv6, sizeof(struct e_in6_addr), &IPv6);
512 proto_item_append_text(pi, " %s, Port %d", address_to_str(&addr), port);
515 case ACN_ADDR_IPPORT:
516 /* Build tree and add type*/
517 pi = proto_tree_add_text(tree, tvb, offset, 3, label);
518 addr_tree = proto_item_add_subtree(pi, ett_acn_address);
519 proto_tree_add_item(addr_tree, hf_acn_ip_address_type, tvb, offset, 1, FALSE);
522 port = tvb_get_ntohs(tvb, offset);
523 proto_tree_add_item(addr_tree, hf_acn_port, tvb, offset, 2, FALSE);
524 /* Append port to tree item */
525 proto_item_append_text(pi, " %s Port %d", address_to_str(&addr), port);
532 /******************************************************************************/
533 /* Adds tree branch for address type */
535 acn_add_dmp_address_type(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, acn_dmp_adt_type *adt)
538 proto_tree *this_tree = NULL;
542 /* header contains address and data type */
543 adt->flags = tvb_get_guint8(tvb, offset);
545 D = ACN_DMP_ADT_EXTRACT_D(adt->flags);
546 name = val_to_str(D, acn_dmp_adt_d_vals, "not valid (%d)");
547 pi = proto_tree_add_text(tree, tvb, offset, 1, "Address and Data Type: %s", name);
549 this_tree = proto_item_add_subtree(pi, ett_acn_address_type);
550 proto_tree_add_uint(this_tree, hf_acn_dmp_adt_v, tvb, offset, 1, adt->flags);
551 proto_tree_add_uint(this_tree, hf_acn_dmp_adt_r, tvb, offset, 1, adt->flags);
552 proto_tree_add_uint(this_tree, hf_acn_dmp_adt_d, tvb, offset, 1, adt->flags);
553 proto_tree_add_uint(this_tree, hf_acn_dmp_adt_x, tvb, offset, 1, adt->flags);
554 proto_tree_add_uint(this_tree, hf_acn_dmp_adt_a, tvb, offset, 1, adt->flags);
557 return offset; /* bytes used */
560 /******************************************************************************/
561 /* Add an dmp address */
563 acn_add_dmp_address(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, acn_dmp_adt_type *adt)
565 guint32 start_offset;
569 start_offset = offset;
571 D = ACN_DMP_ADT_EXTRACT_D(adt->flags);
572 A = ACN_DMP_ADT_EXTRACT_A(adt->flags);
574 case ACN_DMP_ADT_D_NS: /* Non-range address, Single data item */
577 switch (A) { /* address */
578 case ACN_DMP_ADT_A_1: /* One octet address, (range: one octet address, increment, and count). */
579 adt->address = tvb_get_guint8(tvb, offset);
583 case ACN_DMP_ADT_A_2: /* Two octet address, (range: two octet address, increment, and count). */
584 adt->address = tvb_get_ntohs(tvb, offset);
588 case ACN_DMP_ADT_A_4: /* Four octet address, (range: one octet address, increment, and count). */
589 adt->address = tvb_get_ntohl(tvb, offset);
593 default: /* and ACN_DMP_ADT_A_R (Four octet address, (range: four octet address, increment, and count)*/
595 } /* of switch (A) */
597 if (adt->flags & ACN_DMP_ADT_FLAG_V) {
598 proto_tree_add_text(tree, tvb, start_offset, bytes_used, "Virtual Address: 0x%X", adt->address);
600 proto_tree_add_text(tree, tvb, start_offset, bytes_used, "Actual Address: 0x%X", adt->address);
604 case ACN_DMP_ADT_D_RS: /* Range address, Single data item */
606 case ACN_DMP_ADT_A_1: /* One octet address, (range: one octet address, increment, and count). */
607 adt->address = tvb_get_guint8(tvb, offset);
609 adt->increment = tvb_get_guint8(tvb, offset);
611 adt->count = tvb_get_guint8(tvb, offset);
615 case ACN_DMP_ADT_A_2: /* Two octet address, (range: two octet address, increment, and count). */
616 adt->address = tvb_get_ntohs(tvb, offset);
618 adt->increment = tvb_get_ntohs(tvb, offset);
620 adt->count = tvb_get_ntohs(tvb, offset);
624 case ACN_DMP_ADT_A_4: /* Four octet address, (range: four octet address, increment, and count). */
625 adt->address = tvb_get_ntohl(tvb, offset);
627 adt->increment = tvb_get_ntohl(tvb, offset);
629 adt->count = tvb_get_ntohl(tvb, offset);
633 default: /* and ACN_DMP_ADT_A_R, this reserved....so it has no meaning yet */
635 } /* of switch (A) */
637 if (adt->flags & ACN_DMP_ADT_FLAG_V) {
638 proto_tree_add_text(tree, tvb, start_offset, bytes_used, "Virtual Address first: 0x%X, inc: %d, count: %d", adt->address, adt->increment, adt->count);
640 proto_tree_add_text(tree, tvb, start_offset, bytes_used, "Actual Address first: 0x%X, inc: %d, count: %d", adt->address, adt->increment, adt->count);
644 case ACN_DMP_ADT_D_RE: /* Range address, Array of equal size data items */
646 case ACN_DMP_ADT_A_1: /* One octet address, (range: one octet address, increment, and count). */
647 adt->address = tvb_get_guint8(tvb, offset);
649 adt->increment = tvb_get_guint8(tvb, offset);
651 adt->count = tvb_get_guint8(tvb, offset);
655 case ACN_DMP_ADT_A_2: /* Two octet address, (range: two octet address, increment, and count). */
656 adt->address = tvb_get_ntohs(tvb, offset);
658 adt->increment = tvb_get_ntohs(tvb, offset);
660 adt->count = tvb_get_ntohs(tvb, offset);
664 case ACN_DMP_ADT_A_4: /* Four octet address, (range: four octet address, increment, and count). */
665 adt->address = tvb_get_ntohl(tvb, offset);
667 adt->increment = tvb_get_ntohl(tvb, offset);
669 adt->count = tvb_get_ntohl(tvb, offset);
673 default: /* and ACN_DMP_ADT_A_R, this reserved....so it has no meaning yet */
675 } /* of switch (A) */
677 if (adt->flags & ACN_DMP_ADT_FLAG_V) {
678 proto_tree_add_text(tree, tvb, start_offset, bytes_used, "Virtual Address first: 0x%X, inc: %d, count: %d", adt->address, adt->increment, adt->count);
680 proto_tree_add_text(tree, tvb, start_offset, bytes_used, "Actual Address first: 0x%X, inc: %d, count: %d", adt->address, adt->increment, adt->count);
684 case ACN_DMP_ADT_D_RM: /* Range address, Series of mixed size data items */
686 case ACN_DMP_ADT_A_1: /* One octet address, (range: one octet address, increment, and count). */
687 adt->address = tvb_get_guint8(tvb, offset);
689 adt->increment = tvb_get_guint8(tvb, offset);
691 adt->count = tvb_get_guint8(tvb, offset);
695 case ACN_DMP_ADT_A_2: /* Two octet address, (range: two octet address, increment, and count). */
696 adt->address = tvb_get_ntohs(tvb, offset);
698 adt->increment = tvb_get_ntohs(tvb, offset);
700 adt->count = tvb_get_ntohs(tvb, offset);
704 case ACN_DMP_ADT_A_4: /* Four octet address, (range: four octet address, increment, and count). */
705 adt->address = tvb_get_ntohl(tvb, offset);
707 adt->increment = tvb_get_ntohl(tvb, offset);
709 adt->count = tvb_get_ntohl(tvb, offset);
713 default: /* and ACN_DMP_ADT_A_R, this reserved....so it has no meaning yet */
715 } /* of switch (A) */
717 if (adt->flags & ACN_DMP_ADT_FLAG_V) {
718 proto_tree_add_text(tree, tvb, start_offset, bytes_used, "Virtual Address first: 0x%X, inc: %d, count: %d", adt->address, adt->increment, adt->count);
720 proto_tree_add_text(tree, tvb, start_offset, bytes_used, "Actual Address first: 0x%X, inc: %d, count: %d", adt->address, adt->increment, adt->count);
723 } /* of switch (D) */
729 /*******************************************************************************/
730 /* Display DMP Data */
731 #define BUFFER_SIZE 128
733 acn_add_dmp_data(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, acn_dmp_adt_type *adt)
736 guint32 start_offset;
739 guint32 data_address;
741 gchar buffer[BUFFER_SIZE];
743 guint32 ok_to_process = FALSE;
745 start_offset = offset;
748 /* We would like to rip through Property Address-Data pairs */
749 /* but since we don't now how many there are nor how big the data size is, */
750 /* it not possible. So, we just show the whole thing as a block of date! */
752 /* There are a few exceptions however */
753 /* 1) if the address type is ACN_DMP_ADT_D_NS or ACN_DMP_ADT_D_RS and */
754 /* or ACN_DMP_ADT_D_RE */
755 /* then number of bytes is <= count + 4. Each value is at least one byte */
756 /* and another address/data pair is at least 4 bytes so if the remaining */
757 /* bytes is less than the count plus 4 then the remaining data */
758 /* must be all data */
760 /* 2) if the address type is ACN_DMP_ADT_D_RE and the number of bytes */
761 /* equals the number of bytes in remaining in the pdu then there is */
762 /* a 1 to one match */
764 D = ACN_DMP_ADT_EXTRACT_D(adt->flags);
766 case ACN_DMP_ADT_D_NS:
767 case ACN_DMP_ADT_D_RS:
768 if (adt->data_length <= adt->count + 4) {
769 ok_to_process = TRUE;
772 case ACN_DMP_ADT_D_RE:
773 if (adt->data_length == adt->count) {
774 ok_to_process = TRUE;
776 if (adt->data_length <= adt->count + 4) {
777 ok_to_process = TRUE;
782 if (!ok_to_process) {
783 data_size = adt->data_length;
784 ti = proto_tree_add_item(tree, hf_acn_data, tvb, offset, data_size, FALSE);
786 proto_item_set_text(ti, "Data and more Address-Data Pairs (further dissection not possible)");
790 A = ACN_DMP_ADT_EXTRACT_A(adt->flags);
792 case ACN_DMP_ADT_D_NS: /* Non-range address, Single data item */
793 /* calculate data size */
794 data_size = adt->data_length;
795 data_address = adt->address;
798 case ACN_DMP_ADT_A_1: /* One octet address, (range: one octet address, increment, and count). */
799 g_snprintf(buffer, BUFFER_SIZE, "Addr 0x%2.2X ->", data_address);
801 case ACN_DMP_ADT_A_2: /* Two octet address, (range: two octet address, increment, and count). */
802 g_snprintf(buffer, BUFFER_SIZE, "Addr 0x%4.4X ->", data_address);
804 case ACN_DMP_ADT_A_4: /* Four octet address, (range: four octet address, increment, and count). */
805 g_snprintf(buffer, BUFFER_SIZE, "Addr 0x%8.8X ->", data_address);
807 default: /* and ACN_DMP_ADT_A_R, this reserved....so it has no meaning yet */
813 data_value = tvb_get_guint8(tvb, offset);
814 proto_tree_add_int_format(tree, hf_acn_data8, tvb, offset, 1, data_value, "%s %2.2X", buffer, data_value);
817 data_value = tvb_get_ntohs(tvb, offset);
818 proto_tree_add_int_format(tree, hf_acn_data16, tvb, offset, 2, data_value, "%s %4.4X", buffer, data_value);
821 data_value = tvb_get_ntoh24(tvb, offset);
822 proto_tree_add_int_format(tree, hf_acn_data24, tvb, offset, 3, data_value, "%s %6.6X", buffer, data_value);
825 data_value = tvb_get_ntohl(tvb, offset);
826 proto_tree_add_int_format(tree, hf_acn_data32, tvb, offset, 4, data_value, "%s %8.8X", buffer, data_value);
829 /* build string of values */
830 for (y=0;y<20 && y<data_size;y++) {
831 data_value = tvb_get_guint8(tvb, offset+y);
832 g_snprintf(buffer, BUFFER_SIZE, "%s %2.2X", buffer, data_value);
835 ti = proto_tree_add_item(tree, hf_acn_data, tvb, offset, data_size, FALSE);
837 /* change the text */
838 proto_item_set_text(ti, "%s", buffer);
840 } /* of switch (data_size) */
844 case ACN_DMP_ADT_D_RS: /* Range address, Single data item */
845 /* calculate data size */
846 data_size = adt->data_length;
847 data_address = adt->address;
849 for (x=0;x<adt->count;x++) {
851 case ACN_DMP_ADT_A_1: /* One octet address, (range: one octet address, increment, and count). */
852 g_snprintf(buffer, BUFFER_SIZE, "Addr 0x%2.2X ->", data_address);
854 case ACN_DMP_ADT_A_2: /* Two octet address, (range: two octet address, increment, and count). */
855 g_snprintf(buffer, BUFFER_SIZE, "Addr 0x%4.4X ->", data_address);
857 case ACN_DMP_ADT_A_4: /* Four octet address, (range: four octet address, increment, and count). */
858 g_snprintf(buffer, BUFFER_SIZE, "Addr 0x%8.8X ->", data_address);
860 default: /* and ACN_DMP_ADT_A_R, this reserved....so it has no meaning yet */
866 data_value = tvb_get_guint8(tvb, offset);
867 proto_tree_add_int_format(tree, hf_acn_data8, tvb, offset, 1, data_value, "%s %2.2X", buffer, data_value);
870 data_value = tvb_get_ntohs(tvb, offset);
871 proto_tree_add_int_format(tree, hf_acn_data8, tvb, offset, 2, data_value, "%s %4.4X", buffer, data_value);
874 data_value = tvb_get_ntoh24(tvb, offset);
875 proto_tree_add_int_format(tree, hf_acn_data8, tvb, offset, 3, data_value, "%s %6.6X", buffer, data_value);
878 data_value = tvb_get_ntohl(tvb, offset);
879 proto_tree_add_int_format(tree, hf_acn_data8, tvb, offset, 4, data_value, "%s %8.8X", buffer, data_value);
882 /* build string of values */
883 for (y=0;y<20 && y<data_size;y++) {
884 data_value = tvb_get_guint8(tvb, offset+y);
885 g_snprintf(buffer, BUFFER_SIZE, "%s %2.2X", buffer, data_value);
888 ti = proto_tree_add_item(tree, hf_acn_data, tvb, offset, data_size, FALSE);
889 /* change the text */
890 proto_item_set_text(ti, "%s", buffer);
892 } /* of switch (data_size) */
893 data_address += adt->increment;
894 } /* of (x=0;x<adt->count;x++) */
898 case ACN_DMP_ADT_D_RE: /* Range address, Array of equal size data items */
899 /* calculate data size */
900 data_size = adt->data_length / adt->count;
901 data_address = adt->address;
903 for (x=0;x<adt->count;x++) {
905 case ACN_DMP_ADT_A_1: /* One octet address, (range: one octet address, increment, and count). */
906 g_snprintf(buffer, BUFFER_SIZE, "Addr 0x%2.2X ->", data_address);
908 case ACN_DMP_ADT_A_2: /* Two octet address, (range: two octet address, increment, and count). */
909 g_snprintf(buffer, BUFFER_SIZE, "Addr 0x%4.4X ->", data_address);
911 case ACN_DMP_ADT_A_4: /* Four octet address, (range: four octet address, increment, and count). */
912 g_snprintf(buffer, BUFFER_SIZE, "Addr 0x%8.8X ->", data_address);
914 default: /* and ACN_DMP_ADT_A_R, this reserved....so it has no meaning yet */
920 data_value = tvb_get_guint8(tvb, offset);
921 proto_tree_add_int_format(tree, hf_acn_data8, tvb, offset, 1, data_value, "%s %2.2X", buffer, data_value);
924 data_value = tvb_get_ntohs(tvb, offset);
925 proto_tree_add_int_format(tree, hf_acn_data8, tvb, offset, 2, data_value, "%s %4.4X", buffer, data_value);
928 data_value = tvb_get_ntoh24(tvb, offset);
929 proto_tree_add_int_format(tree, hf_acn_data8, tvb, offset, 3, data_value, "%s %6.6X", buffer, data_value);
932 data_value = tvb_get_ntohl(tvb, offset);
933 proto_tree_add_int_format(tree, hf_acn_data8, tvb, offset, 4, data_value, "%s %8.8X", buffer, data_value);
936 /* build string of values */
937 for (y=0;y<20 && y<data_size;y++) {
938 data_value = tvb_get_guint8(tvb, offset+y);
939 g_snprintf(buffer, BUFFER_SIZE, "%s %2.2X", buffer, data_value);
942 ti = proto_tree_add_item(tree, hf_acn_data, tvb, offset, data_size, FALSE);
943 /* change the text */
944 proto_item_set_text(ti, "%s", buffer);
946 } /* of switch (data_size) */
949 data_address += adt->increment;
950 } /* of (x=0;x<adt->count;x++) */
953 case ACN_DMP_ADT_D_RM: /* Range address, Series of mixed size data items */
954 data_size = adt->data_length;
955 ti = proto_tree_add_item(tree, hf_acn_data, tvb, offset, data_size, FALSE);
957 /* change the text */
958 proto_item_set_text(ti, "Mixed size data items");
960 } /* of switch (D) */
965 /*******************************************************************************/
966 /* Display DMP Reason codes */
967 #define BUFFER_SIZE 128
969 acn_add_dmp_reason_codes(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, acn_dmp_adt_type *adt)
972 guint32 start_offset;
974 guint32 data_address;
977 gchar buffer[BUFFER_SIZE];
980 start_offset = offset;
983 D = ACN_DMP_ADT_EXTRACT_D(adt->flags);
984 A = ACN_DMP_ADT_EXTRACT_A(adt->flags);
986 case ACN_DMP_ADT_D_NS: /* Non-range address, Single data item */
987 data_address = adt->address;
989 case ACN_DMP_ADT_A_1: /* One octet address, (range: one octet address, increment, and count). */
990 g_snprintf(buffer, BUFFER_SIZE, "Addr 0x%2.2X ->", data_address);
992 case ACN_DMP_ADT_A_2: /* Two octet address, (range: two octet address, increment, and count). */
993 g_snprintf(buffer, BUFFER_SIZE, "Addr 0x%4.4X ->", data_address);
995 case ACN_DMP_ADT_A_4: /* Four octet address, (range: four octet address, increment, and count). */
996 g_snprintf(buffer, BUFFER_SIZE, "Addr 0x%8.8X ->", data_address);
998 default: /* and ACN_DMP_ADT_A_R, this reserved....so it has no meaning yet */
1003 data_value = tvb_get_guint8(tvb, offset);
1004 /* convert to string */
1005 name = val_to_str(data_value, acn_dmp_reason_code_vals, "reason not valid (%d)");
1007 proto_tree_add_int_format(tree, hf_acn_data8, tvb, offset, 1, data_value, "%s %s", buffer, name);
1011 case ACN_DMP_ADT_D_RS: /* Range address, Single data item */
1012 data_address = adt->address;
1013 for (x=0;x<adt->count;x++) {
1015 case ACN_DMP_ADT_A_1: /* One octet address, (range: one octet address, increment, and count). */
1016 g_snprintf(buffer, BUFFER_SIZE, "Addr 0x%2.2X ->", data_address);
1018 case ACN_DMP_ADT_A_2: /* Two octet address, (range: two octet address, increment, and count). */
1019 g_snprintf(buffer, BUFFER_SIZE, "Addr 0x%4.4X ->", data_address);
1021 case ACN_DMP_ADT_A_4: /* Four octet address, (range: four octet address, increment, and count). */
1022 g_snprintf(buffer, BUFFER_SIZE, "Addr 0x%8.8X ->", data_address);
1024 default: /* and ACN_DMP_ADT_A_R, this reserved....so it has no meaning yet */
1029 data_value = tvb_get_guint8(tvb, offset);
1030 /* convert to string */
1031 name = val_to_str(data_value, acn_dmp_reason_code_vals, "reason not valid (%d)");
1033 proto_tree_add_int_format(tree, hf_acn_data8, tvb, offset, 1, data_value, "%s %s", buffer, name);
1035 data_address += adt->increment;
1036 } /* of (x=0;x<adt->count;x++) */
1040 case ACN_DMP_ADT_D_RE: /* Range address, Array of equal size data items */
1041 case ACN_DMP_ADT_D_RM: /* Range address, Series of mixed size data items */
1042 data_address = adt->address;
1043 for (x=0;x<adt->count;x++) {
1045 case ACN_DMP_ADT_A_1: /* One octet address, (range: one octet address, increment, and count). */
1046 g_snprintf(buffer, BUFFER_SIZE, "Addr 0x%2.2X ->", data_address);
1048 case ACN_DMP_ADT_A_2: /* Two octet address, (range: two octet address, increment, and count). */
1049 g_snprintf(buffer, BUFFER_SIZE, "Addr 0x%4.4X ->", data_address);
1051 case ACN_DMP_ADT_A_4: /* Four octet address, (range: four octet address, increment, and count). */
1052 g_snprintf(buffer, BUFFER_SIZE, "Addr 0x%8.8X ->", data_address);
1054 default: /* and ACN_DMP_ADT_A_R, this reserved....so it has no meaning yet */
1058 data_value = tvb_get_guint8(tvb, offset);
1059 /* convert to string */
1060 name = val_to_str(data_value, acn_dmp_reason_code_vals, "reason not valid (%d)");
1062 proto_tree_add_int_format(tree, hf_acn_data8, tvb, offset, 1, data_value, "%s %s", buffer, name);
1063 data_address += adt->increment;
1065 } /* of (x=0;x<adt->count;x++) */
1067 } /* of switch (D) */
1072 /******************************************************************************/
1073 /* Dissect wrapped SDT PDU */
1075 dissect_acn_dmp_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, acn_pdu_offsets *last_pdu_offsets)
1077 /* common to all pdu */
1081 guint32 pdu_flvh_length; /* flags, length, vector, header */
1082 acn_pdu_offsets pdu_offsets = {0,0,0,0,0};
1088 guint32 vector_offset;
1089 guint32 header_offset;
1090 guint32 data_offset;
1093 guint32 data_length;
1094 guint32 address_count;
1096 proto_item *ti, *pi;
1097 proto_tree *pdu_tree = NULL;
1098 proto_tree *flag_tree = NULL;
1102 acn_dmp_adt_type adt = {0,0,0,0,0,0};
1103 acn_dmp_adt_type adt2 = {0,0,0,0,0,0};
1106 /* save start of pdu block */
1108 pdu_offsets.start = pdu_start;
1110 /* get PDU flags and length flag first */
1111 octet = tvb_get_guint8(tvb, offset++);
1112 pdu_flags = octet & 0xf0;
1113 length1 = octet & 0x0f; /* bottom 4 bits only */
1114 length2 = tvb_get_guint8(tvb, offset++);
1116 /* if length flag is set, then we have a 20 bit length else we have a 12 bit */
1117 /* flvh = flags, length, vector, header */
1118 if (pdu_flags & ACN_PDU_FLAG_L) {
1119 length3 = tvb_get_guint8(tvb, offset);
1121 pdu_length = length3 | (length2 << 8) | (length1 << 16);
1122 pdu_flvh_length = 3;
1124 pdu_length = length2 | (length1 << 8);
1125 pdu_flvh_length = 2;
1127 /* offset should now be pointing to vector (if one exists) */
1129 /* Add pdu item and tree */
1130 ti = proto_tree_add_item(tree, hf_acn_pdu, tvb, pdu_start, pdu_length, FALSE);
1131 pdu_tree = proto_item_add_subtree(ti, ett_acn_dmp_pdu);
1133 /* Add flag item and tree */
1134 pi = proto_tree_add_uint(pdu_tree, hf_acn_pdu_flags, tvb, pdu_start, 1, pdu_flags);
1135 flag_tree = proto_item_add_subtree(pi, ett_acn_pdu_flags);
1136 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_l, tvb, pdu_start, 1, FALSE);
1137 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_v, tvb, pdu_start, 1, FALSE);
1138 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_h, tvb, pdu_start, 1, FALSE);
1139 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_d, tvb, pdu_start, 1, FALSE);
1141 /* Add PDU Length item */
1142 proto_tree_add_uint(pdu_tree, hf_acn_pdu_length, tvb, pdu_start, pdu_flvh_length, pdu_length);
1144 /* Set vector offset */
1145 if (pdu_flags & ACN_PDU_FLAG_V) {
1146 /* use new values */
1147 vector_offset = offset;
1148 last_pdu_offsets->vector = offset;
1152 /* use last values */
1153 vector_offset = last_pdu_offsets->vector;
1155 /* offset should now be pointing to header (if one exists) */
1157 /* Add Vector item */
1158 vector = tvb_get_guint8(tvb, vector_offset);
1159 proto_tree_add_uint(pdu_tree, hf_acn_dmp_vector, tvb, vector_offset, 1, vector);
1161 /* Add Vector item to tree*/
1162 name = val_to_str(vector, acn_dmp_vector_vals, "not valid (%d)");
1163 proto_item_append_text(ti, ": ");
1164 proto_item_append_text(ti, name);
1166 /* Set header offset */
1167 if (pdu_flags & ACN_PDU_FLAG_H) {
1168 /* use new values */
1169 header_offset = offset;
1170 last_pdu_offsets->header = offset;
1174 /* use last values */
1175 header_offset = last_pdu_offsets->header;
1177 /* offset should now be pointing to data (if one exists) */
1179 /* header contains address and data type */
1180 acn_add_dmp_address_type(tvb, pinfo, pdu_tree, header_offset, &adt);
1183 if (pdu_flags & ACN_PDU_FLAG_D) {
1184 /* use new values */
1185 data_offset = offset;
1186 data_length = pdu_length - pdu_flvh_length;
1187 last_pdu_offsets->data = offset;
1188 last_pdu_offsets->data_length = data_length;
1190 /* use last values */
1191 data_offset = last_pdu_offsets->data;
1192 data_length = last_pdu_offsets->data_length;
1194 end_offset = data_offset + data_length;
1197 case ACN_DMP_VECTOR_UNKNOWN:
1199 case ACN_DMP_VECTOR_GET_PROPERTY:
1200 /* Rip trough property address */
1201 while (data_offset < end_offset) {
1202 old_offset = data_offset;
1203 data_offset = acn_add_dmp_address(tvb, pinfo, pdu_tree, data_offset, &adt);
1204 if (old_offset == data_offset) break;
1207 case ACN_DMP_VECTOR_SET_PROPERTY:
1208 /* Rip through Property Address-Data pairs */
1209 /* But, in reality, this generally won't work as we have know way of */
1210 /* calculating the next Address-Data pair */
1211 while (data_offset < end_offset) {
1212 old_offset = data_offset;
1213 data_offset = acn_add_dmp_address(tvb, pinfo, pdu_tree, data_offset, &adt);
1214 if (old_offset == data_offset) break;
1216 adt.data_length = data_length - (data_offset - old_offset);
1217 old_offset = data_offset;
1218 data_offset = acn_add_dmp_data(tvb, pinfo, pdu_tree, data_offset, &adt);
1219 if (old_offset == data_offset) break;
1222 case ACN_DMP_VECTOR_GET_PROPERTY_REPLY:
1223 /* Rip through Property Address-Data pairs */
1224 /* But, in reality, this generally won't work as we have know way of */
1225 /* calculating the next Address-Data pair */
1226 while (data_offset < end_offset) {
1227 old_offset = data_offset;
1228 data_offset = acn_add_dmp_address(tvb, pinfo, pdu_tree, data_offset, &adt);
1229 if (old_offset == data_offset) break;
1231 adt.data_length = data_length - (data_offset - old_offset);
1232 old_offset = data_offset;
1233 data_offset = acn_add_dmp_data(tvb, pinfo, pdu_tree, data_offset, &adt);
1234 if (old_offset == data_offset) break;
1237 case ACN_DMP_VECTOR_EVENT:
1238 /* Rip through Property Address-Data pairs */
1239 /* But, in reality, this generally won't work as we have know way of */
1240 /* calculating the next Address-Data pair */
1241 while (data_offset < end_offset) {
1242 old_offset = data_offset;
1243 data_offset = acn_add_dmp_address(tvb, pinfo, pdu_tree, data_offset, &adt);
1244 if (old_offset == data_offset) break;
1246 adt.data_length = data_length - (data_offset - old_offset);
1247 old_offset = data_offset;
1248 data_offset = acn_add_dmp_data(tvb, pinfo, pdu_tree, data_offset, &adt);
1249 if (old_offset == data_offset) break;
1252 case ACN_DMP_VECTOR_MAP_PROPERTY:
1253 /* Virtual Address type */
1254 data_offset = acn_add_dmp_address_type(tvb, pinfo, pdu_tree, data_offset, &adt2);
1255 /* Rip through Actual-Virtual Address Pairs */
1256 while (data_offset < end_offset) {
1258 old_offset = data_offset;
1259 data_offset = acn_add_dmp_address(tvb, pinfo, pdu_tree, data_offset, &adt);
1260 if (old_offset == data_offset) break;
1261 D = ACN_DMP_ADT_EXTRACT_D(adt.flags);
1263 case ACN_DMP_ADT_D_NS:
1266 case ACN_DMP_ADT_D_RS:
1269 case ACN_DMP_ADT_D_RE:
1270 address_count = adt.count;
1272 /*case ACN_DMP_ADT_D_RM: */
1275 return pdu_start + pdu_length;
1280 while (address_count > 0) {
1281 data_offset = acn_add_dmp_address(tvb, pinfo, pdu_tree, data_offset, &adt2);
1286 case ACN_DMP_VECTOR_UNMAP_PROPERTY:
1287 /* Rip trough Actaul Proptery Address */
1288 while (data_offset < end_offset) {
1289 old_offset = data_offset;
1290 data_offset = acn_add_dmp_address(tvb, pinfo, pdu_tree, data_offset, &adt);
1291 if (old_offset == data_offset) break;
1294 case ACN_DMP_VECTOR_SUBSCRIBE:
1295 /* Rip trough Proptery Address */
1296 while (data_offset < end_offset) {
1297 old_offset = data_offset;
1298 data_offset = acn_add_dmp_address(tvb, pinfo, pdu_tree, data_offset, &adt);
1299 if (old_offset == data_offset) break;
1302 case ACN_DMP_VECTOR_UNSUBSCRIBE:
1303 /* Rip trough Proptery Address */
1304 while (data_offset < end_offset) {
1305 old_offset = data_offset;
1306 data_offset = acn_add_dmp_address(tvb, pinfo, pdu_tree, data_offset, &adt);
1307 if (old_offset == data_offset) break;
1310 case ACN_DMP_VECTOR_GET_PROPERTY_FAIL:
1311 /* Rip trough Address-Reason Code Pairs */
1312 while (data_offset < end_offset) {
1313 old_offset = data_offset;
1314 data_offset = acn_add_dmp_address(tvb, pinfo, pdu_tree, data_offset, &adt);
1315 if (old_offset == data_offset) break;
1317 adt.data_length = data_length - (data_offset - old_offset);
1318 old_offset = data_offset;
1319 data_offset = acn_add_dmp_reason_codes(tvb, pinfo, pdu_tree, data_offset, &adt);
1320 if (old_offset == data_offset) break;
1323 case ACN_DMP_VECTOR_SET_PROPERTY_FAIL:
1324 /* Rip trough Address-Reason Code Pairs */
1325 while (data_offset < end_offset) {
1326 old_offset = data_offset;
1327 data_offset = acn_add_dmp_address(tvb, pinfo, pdu_tree, data_offset, &adt);
1328 if (old_offset == data_offset) break;
1330 adt.data_length = data_length - (data_offset - old_offset);
1331 old_offset = data_offset;
1332 data_offset = acn_add_dmp_reason_codes(tvb, pinfo, pdu_tree, data_offset, &adt);
1333 if (old_offset == data_offset) break;
1336 case ACN_DMP_VECTOR_MAP_PROPERTY_FAIL:
1337 /* Rip trough Address-Reason Code Pairs */
1338 while (data_offset < end_offset) {
1339 old_offset = data_offset;
1340 data_offset = acn_add_dmp_address(tvb, pinfo, pdu_tree, data_offset, &adt);
1341 if (old_offset == data_offset) break;
1343 adt.data_length = data_length - (data_offset - old_offset);
1344 old_offset = data_offset;
1345 data_offset = acn_add_dmp_reason_codes(tvb, pinfo, pdu_tree, data_offset, &adt);
1346 if (old_offset == data_offset) break;
1349 case ACN_DMP_VECTOR_SUBSCRIBE_ACCEPT:
1350 /* Rip through Property Addrsses */
1351 while (data_offset < end_offset) {
1352 old_offset = data_offset;
1353 data_offset = acn_add_dmp_address(tvb, pinfo, pdu_tree, data_offset, &adt);
1354 if (old_offset == data_offset) break;
1357 case ACN_DMP_VECTOR_SUBSCRIBE_REJECT:
1358 /* Rip trough Address-Reason Code Pairs */
1359 while (data_offset < end_offset) {
1360 old_offset = data_offset;
1361 data_offset = acn_add_dmp_address(tvb, pinfo, pdu_tree, data_offset, &adt);
1362 if (old_offset == data_offset) break;
1364 adt.data_length = data_length - (data_offset - old_offset);
1365 old_offset = data_offset;
1366 data_offset = acn_add_dmp_reason_codes(tvb, pinfo, pdu_tree, data_offset, &adt);
1367 if (old_offset == data_offset) break;
1370 case ACN_DMP_VECTOR_ALLOCATE_MAP:
1371 /* No data for this */
1373 case ACN_DMP_VECTOR_ALLOCATE_MAP_REPLY:
1374 /* Single reason code */
1375 proto_tree_add_item(pdu_tree, hf_acn_dmp_reason_code, tvb, data_offset, 1, FALSE);
1377 case ACN_DMP_VECTOR_DEALLOCATE_MAP:
1378 /* No data for this */
1382 return pdu_start + pdu_length;
1386 /******************************************************************************/
1387 /* Dissect wrapped SDT PDU */
1389 dissect_acn_sdt_wrapped_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree _U_, int offset, acn_pdu_offsets *last_pdu_offsets)
1391 /* common to all pdu */
1395 guint32 pdu_flvh_length; /* flags, length, vector, header */
1396 acn_pdu_offsets pdu_offsets = {0,0,0,0,0};
1401 guint32 vector_offset;
1402 guint32 data_offset;
1404 guint32 data_length;
1406 proto_item *ti, *pi;
1407 proto_tree *pdu_tree = NULL;
1408 proto_tree *flag_tree = NULL;
1414 /* save start of pdu block */
1416 pdu_offsets.start = pdu_start;
1418 /* get PDU flags and length flag first */
1419 octet = tvb_get_guint8(tvb, offset++);
1420 pdu_flags = octet & 0xf0;
1421 length1 = octet & 0x0f; /* bottom 4 bits only */
1422 length2 = tvb_get_guint8(tvb, offset++);
1424 /* if length flag is set, then we have a 20 bit length else we have a 12 bit */
1425 /* flvh = flags, length, vector, header */
1426 if (pdu_flags & ACN_PDU_FLAG_L) {
1427 length3 = tvb_get_guint8(tvb, offset);
1429 pdu_length = length3 | (length2 << 8) | (length1 << 16);
1430 pdu_flvh_length = 3;
1432 pdu_length = length2 | (length1 << 8);
1433 pdu_flvh_length = 2;
1435 /* offset should now be pointing to vector (if one exists) */
1437 /* Add pdu item and tree */
1438 ti = proto_tree_add_item(tree, hf_acn_pdu, tvb, pdu_start, pdu_length, FALSE);
1439 pdu_tree = proto_item_add_subtree(ti, ett_acn_sdt_pdu);
1441 /* Add flag item and tree */
1442 pi = proto_tree_add_uint(pdu_tree, hf_acn_pdu_flags, tvb, pdu_start, 1, pdu_flags);
1443 flag_tree = proto_item_add_subtree(pi, ett_acn_pdu_flags);
1444 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_l, tvb, pdu_start, 1, FALSE);
1445 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_v, tvb, pdu_start, 1, FALSE);
1446 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_h, tvb, pdu_start, 1, FALSE);
1447 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_d, tvb, pdu_start, 1, FALSE);
1449 /* Add PDU Length item */
1450 proto_tree_add_uint(pdu_tree, hf_acn_pdu_length, tvb, pdu_start, pdu_flvh_length, pdu_length);
1452 /* Set vector offset */
1453 if (pdu_flags & ACN_PDU_FLAG_V) {
1454 /* use new values */
1455 vector_offset = offset;
1456 last_pdu_offsets->vector = offset;
1460 /* use last values */
1461 vector_offset = last_pdu_offsets->vector;
1463 /* offset should now be pointing to header (if one exists) */
1465 /* Add Vector item */
1466 vector = tvb_get_guint8(tvb, vector_offset);
1467 proto_tree_add_uint(pdu_tree, hf_acn_sdt_vector, tvb, vector_offset, 1, vector);
1469 /* Add Vector item to tree*/
1470 name = val_to_str(vector, acn_sdt_vector_vals, "not valid (%d)");
1471 proto_item_append_text(ti, ": ");
1472 proto_item_append_text(ti, name);
1474 /* NO HEADER DATA ON THESE* (at least so far) */
1477 if (pdu_flags & ACN_PDU_FLAG_D) {
1478 /* use new values */
1479 data_offset = offset;
1480 data_length = pdu_length - pdu_flvh_length;
1481 last_pdu_offsets->data = offset;
1482 last_pdu_offsets->data_length = data_length;
1484 /* use last values */
1485 data_offset = last_pdu_offsets->data;
1486 data_length = last_pdu_offsets->data_length;
1488 end_offset = data_offset + data_length;
1491 case ACN_SDT_VECTOR_ACK:
1492 proto_tree_add_item(pdu_tree, hf_acn_reliable_sequence_number, tvb, data_offset, 4, FALSE);
1495 case ACN_SDT_VECTOR_CHANNEL_PARAMS:
1496 data_offset = acn_add_channel_parameter(tvb, pinfo, pdu_tree, data_offset);
1497 data_offset = acn_add_address(tvb, pinfo, pdu_tree, data_offset, "Ad-hoc Address:");
1498 data_offset = acn_add_expiry(tvb, pinfo, pdu_tree, data_offset, "Ad-hoc Expiry:");
1500 case ACN_SDT_VECTOR_LEAVE:
1503 case ACN_SDT_VECTOR_CONNECT:
1504 /* Protocol ID item */
1505 proto_tree_add_item(pdu_tree, hf_acn_protocol_id, tvb, data_offset, 4, FALSE);
1508 case ACN_SDT_VECTOR_CONNECT_ACCEPT:
1509 /* Protocol ID item */
1510 proto_tree_add_item(pdu_tree, hf_acn_protocol_id, tvb, data_offset, 4, FALSE);
1513 case ACN_SDT_VECTOR_CONNECT_REFUSE:
1514 /* Protocol ID item */
1515 proto_tree_add_item(pdu_tree, hf_acn_protocol_id, tvb, data_offset, 4, FALSE);
1517 proto_tree_add_item(pdu_tree, hf_acn_refuse_code, tvb, data_offset, 1, FALSE);
1520 case ACN_SDT_VECTOR_DISCONNECT:
1521 /* Protocol ID item */
1522 proto_tree_add_item(pdu_tree, hf_acn_protocol_id, tvb, data_offset, 4, FALSE);
1525 case ACN_SDT_VECTOR_DISCONNECTING:
1526 /* Protocol ID item */
1527 proto_tree_add_item(pdu_tree, hf_acn_protocol_id, tvb, data_offset, 4, FALSE);
1529 proto_tree_add_item(pdu_tree, hf_acn_reason_code, tvb, data_offset, 1, FALSE);
1535 return pdu_start + pdu_length;
1539 /******************************************************************************/
1540 /* Dissect SDT Client PDU */
1542 dissect_acn_sdt_client_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, acn_pdu_offsets *last_pdu_offsets)
1544 /* common to all pdu */
1548 guint32 pdu_flvh_length; /* flags, length, vector, header */
1549 acn_pdu_offsets pdu_offsets = {0,0,0,0,0};
1554 guint32 vector_offset;
1555 guint32 header_offset;
1556 guint32 data_offset;
1557 guint32 data_length;
1561 proto_item *ti, *pi;
1562 proto_tree *pdu_tree = NULL;
1563 proto_tree *flag_tree = NULL;
1568 guint32 protocol_id;
1569 guint16 association;
1571 /* save start of pdu block */
1573 pdu_offsets.start = pdu_start;
1575 /* get PDU flags and length flag first */
1576 octet = tvb_get_guint8(tvb, offset++);
1577 pdu_flags = octet & 0xf0;
1578 length1 = octet & 0x0f; /* bottom 4 bits only */
1579 length2 = tvb_get_guint8(tvb, offset++);
1581 /* if length flag is set, then we have a 20 bit length else we have a 12 bit */
1582 /* flvh = flags, length, vector, header */
1583 if (pdu_flags & ACN_PDU_FLAG_L) {
1584 length3 = tvb_get_guint8(tvb, offset);
1586 pdu_length = length3 | (length2 << 8) | (length1 << 16);
1587 pdu_flvh_length = 3;
1589 pdu_length = length2 | (length1 << 8);
1590 pdu_flvh_length = 2;
1592 /* offset should now be pointing to vector (if one exists) */
1594 /* Add pdu item and tree */
1595 ti = proto_tree_add_item(tree, hf_acn_pdu, tvb, pdu_start, pdu_length, FALSE);
1596 pdu_tree = proto_item_add_subtree(ti, ett_acn_sdt_client_pdu);
1598 /* Add flag item and tree */
1599 pi = proto_tree_add_uint(pdu_tree, hf_acn_pdu_flags, tvb, pdu_start, 1, pdu_flags);
1600 flag_tree = proto_item_add_subtree(pi, ett_acn_pdu_flags);
1601 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_l, tvb, pdu_start, 1, FALSE);
1602 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_v, tvb, pdu_start, 1, FALSE);
1603 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_h, tvb, pdu_start, 1, FALSE);
1604 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_d, tvb, pdu_start, 1, FALSE);
1606 /* Add PDU Length item */
1607 proto_tree_add_uint(pdu_tree, hf_acn_pdu_length, tvb, pdu_start, pdu_flvh_length, pdu_length);
1609 /* Set vector offset */
1610 if (pdu_flags & ACN_PDU_FLAG_V) {
1611 /* use new values */
1612 vector_offset = offset;
1613 last_pdu_offsets->vector = offset;
1615 pdu_flvh_length += 2;
1617 /* use last values */
1618 vector_offset = last_pdu_offsets->vector;
1620 /* offset should now be pointing to header (if one exists) */
1622 /* add Member ID item */
1623 member_id = tvb_get_ntohs(tvb, vector_offset);
1624 proto_tree_add_uint(pdu_tree, hf_acn_member_id, tvb, vector_offset, 2, member_id);
1626 /* Set header offset */
1627 if (pdu_flags & ACN_PDU_FLAG_H) {
1628 /* use new values */
1629 header_offset = offset;
1630 last_pdu_offsets->header = offset;
1632 pdu_flvh_length += 6;
1634 /* use last values */
1635 header_offset = last_pdu_offsets->header;
1637 /* offset should now be pointing to data (if one exists) */
1639 /* add Protocol ID item (Header)*/
1640 protocol_id = tvb_get_ntohl(tvb, header_offset);
1641 proto_tree_add_uint(pdu_tree, hf_acn_protocol_id, tvb, header_offset, 4, protocol_id);
1644 /* Add protocol to tree*/
1645 name = val_to_str(protocol_id, acn_protocol_id_vals, "id not valid (%d)");
1646 proto_item_append_text(ti, ": ");
1647 proto_item_append_text(ti, name);
1649 /* add association item */
1650 association = tvb_get_ntohs(tvb, header_offset);
1651 proto_tree_add_uint(pdu_tree, hf_acn_association, tvb, header_offset, 2, association);
1655 if (pdu_flags & ACN_PDU_FLAG_D) {
1656 /* use new values */
1657 data_offset = offset;
1658 data_length = pdu_length - pdu_flvh_length;
1659 last_pdu_offsets->data = offset;
1660 last_pdu_offsets->data_length = data_length;
1662 /* use last values */
1663 data_offset = last_pdu_offsets->data;
1664 data_length = last_pdu_offsets->data_length;
1666 end_offset = data_offset + data_length;
1668 switch (protocol_id) {
1669 case ACN_PROTOCOL_ID_SDT:
1670 while (data_offset < end_offset) {
1671 old_offset = data_offset;
1672 data_offset = dissect_acn_sdt_wrapped_pdu(tvb, pinfo, pdu_tree, data_offset, &pdu_offsets);
1673 if (old_offset == data_offset) break;
1676 case ACN_PROTOCOL_ID_DMP:
1677 while (data_offset < end_offset) {
1678 old_offset = data_offset;
1679 data_offset = dissect_acn_dmp_pdu(tvb, pinfo, pdu_tree, data_offset, &pdu_offsets);
1680 if (data_offset == old_offset) break;
1684 return pdu_start + pdu_length;
1688 /******************************************************************************/
1689 /* reverses the characters in a string */
1695 for (i=0, j=strlen(s)-1; i < j; i++, j--) {
1703 /******************************************************************************/
1704 /* level to string (ascii) */
1705 /* level : 8 bit value */
1706 /* string : pointer to buffer to fill */
1707 /* leading_char: character to buffer left of digits */
1708 /* min_char : mininum number of characters (for filling, not including space)*/
1709 /* show_zero: show zeros or dots */
1710 /* also adds a space to right end */
1712 /* returns end of string */
1713 /* faster than printf() */
1715 ltos(guint8 level, gchar *string, guint8 base, gchar leading_char, guint8 min_chars, gboolean show_zero)
1719 if (base < 2 || base > 16) {
1723 /* deal with zeros */
1724 if ((level == 0) && (!show_zero)) {
1725 for (i=0;i<min_chars;i++) {
1734 /* do our convert, comes out backwords! */
1736 string[i++] = "0123456789ABCDEF"[level % base];
1737 } while ((level /= base) > 0);
1739 /* expand to needed character */
1740 for (;i<min_chars;i++) {
1741 string[i] = leading_char;
1746 /* now reverse (and correct) the order */
1749 /* add a space at the end (ok its at the start but it will be at the end)*/
1756 /******************************************************************************/
1757 /* Dissect DMX data PDU */
1758 #define BUFFER_SIZE 128
1760 dissect_acn_dmx_data_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, acn_pdu_offsets *last_pdu_offsets)
1762 /* common to all pdu */
1766 guint32 pdu_flvh_length; /* flags, length, vector, header */
1767 acn_pdu_offsets pdu_offsets = {0,0,0,0,0};
1772 guint32 vector_offset;
1773 guint32 data_offset;
1775 guint32 data_length;
1776 guint32 header_offset;
1781 proto_item *ti, *pi;
1782 proto_tree *pdu_tree = NULL;
1783 proto_tree *flag_tree = NULL;
1784 /* proto_tree *addr_tree = NULL; */
1787 acn_dmp_adt_type adt = {0,0,0,0,0,0};
1790 gchar buffer[BUFFER_SIZE];
1800 guint16 dmx_start_code;
1804 /* save start of pdu block */
1806 pdu_offsets.start = pdu_start;
1808 /* get PDU flags and length flag first */
1809 octet = tvb_get_guint8(tvb, offset++);
1810 pdu_flags = octet & 0xf0;
1811 length1 = octet & 0x0f; /* bottom 4 bits only */
1812 length2 = tvb_get_guint8(tvb, offset++);
1814 /* if length flag is set, then we have a 20 bit length else we have a 12 bit */
1815 /* flvh = flags, length, vector, header */
1816 if (pdu_flags & ACN_PDU_FLAG_L) {
1817 length3 = tvb_get_guint8(tvb, offset);
1819 pdu_length = length3 | (length2 << 8) | (length1 << 16);
1820 pdu_flvh_length = 3;
1822 pdu_length = length2 | (length1 << 8);
1823 pdu_flvh_length = 2;
1825 /* offset should now be pointing to vector (if one exists) */
1827 /* Add pdu item and tree */
1828 ti = proto_tree_add_item(tree, hf_acn_pdu, tvb, pdu_start, pdu_length, FALSE);
1829 pdu_tree = proto_item_add_subtree(ti, ett_acn_dmx_data_pdu);
1831 /* Add flag item and tree */
1832 pi = proto_tree_add_uint(pdu_tree, hf_acn_pdu_flags, tvb, pdu_start, 1, pdu_flags);
1833 flag_tree = proto_item_add_subtree(pi, ett_acn_pdu_flags);
1834 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_l, tvb, pdu_start, 1, FALSE);
1835 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_v, tvb, pdu_start, 1, FALSE);
1836 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_h, tvb, pdu_start, 1, FALSE);
1837 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_d, tvb, pdu_start, 1, FALSE);
1839 /* Add PDU Length item */
1840 proto_tree_add_uint(pdu_tree, hf_acn_pdu_length, tvb, pdu_start, pdu_flvh_length, pdu_length);
1842 /* Set vector offset */
1843 if (pdu_flags & ACN_PDU_FLAG_V) {
1844 /* use new values */
1845 vector_offset = offset;
1846 last_pdu_offsets->vector = offset;
1848 pdu_flvh_length += 1;
1850 /* use last values */
1851 vector_offset = last_pdu_offsets->vector;
1853 /* offset should now be pointing to header (if one exists) */
1855 /* Add Vector item */
1856 vector = tvb_get_guint8(tvb, vector_offset);
1857 proto_tree_add_uint(pdu_tree, hf_acn_dmp_vector, tvb, vector_offset, 1, vector);
1859 /* Add Vector item to tree*/
1860 name = val_to_str(vector, acn_dmp_vector_vals, "not valid (%d)");
1861 proto_item_append_text(ti, ": ");
1862 proto_item_append_text(ti, name);
1864 /* Set header offset */
1865 if (pdu_flags & ACN_PDU_FLAG_H) {
1866 /* use new values */
1867 header_offset = offset;
1868 last_pdu_offsets->header = offset;
1872 /* use last values */
1873 header_offset = last_pdu_offsets->header;
1875 /* offset should now be pointing to data (if one exists) */
1877 /* process based on vector */
1878 acn_add_dmp_address_type(tvb, pinfo, pdu_tree, header_offset, &adt);
1881 if (pdu_flags & ACN_PDU_FLAG_D) {
1882 /* use new values */
1883 data_offset = offset;
1884 data_length = pdu_length - pdu_flvh_length;
1885 last_pdu_offsets->data = offset;
1886 last_pdu_offsets->data_length = data_length;
1888 /* use last values */
1889 data_offset = last_pdu_offsets->data;
1890 data_length = last_pdu_offsets->data_length;
1892 end_offset = data_offset + data_length;
1895 case ACN_DMP_VECTOR_SET_PROPERTY:
1896 dmx_start_code = tvb_get_ntohs(tvb, data_offset);
1897 proto_tree_add_item(pdu_tree, hf_acn_dmx_start_code, tvb, data_offset, 2, FALSE);
1899 proto_tree_add_item(pdu_tree, hf_acn_dmx_increment, tvb, data_offset, 2, FALSE);
1901 dmx_count = tvb_get_ntohs(tvb, data_offset);
1902 proto_tree_add_item(pdu_tree, hf_acn_dmx_count, tvb, data_offset, 2, FALSE);
1907 switch (global_acn_dmx_display_line_format) {
1908 case ACN_PREF_DMX_DISPLAY_16PL:
1917 /* values base on display mode */
1918 switch ((guint)global_acn_dmx_display_view) {
1919 case ACN_PREF_DMX_DISPLAY_HEX:
1923 /* case ACN_PREF_DMX_DISPLAY_PER: */
1929 /* do we display leading zeros */
1930 if (global_acn_dmx_display_leading_zeros) {
1936 /* add a snippet to info (this may be slow) */
1937 if(check_col(pinfo->cinfo,COL_INFO)){
1938 col_append_fstr(pinfo->cinfo,COL_INFO, ", Sc %02x, [%02x %02x %02x %02x %02x %02x...]",
1940 tvb_get_guint8(tvb, data_offset),
1941 tvb_get_guint8(tvb, data_offset+1),
1942 tvb_get_guint8(tvb, data_offset+2),
1943 tvb_get_guint8(tvb, data_offset+3),
1944 tvb_get_guint8(tvb, data_offset+4),
1945 tvb_get_guint8(tvb, data_offset+5));
1948 /* add a header line */
1949 g_snprintf(buffer, BUFFER_SIZE, "%-10s: ", "Data...");
1952 for (x=1;x<=perline;x++) {
1953 buf_ptr = ltos((guint8)x, buf_ptr, 10, ' ', min_char, FALSE);
1960 proto_tree_add_text(pdu_tree, tvb, data_offset, dmx_count, buffer);
1962 /* start our line */
1963 g_snprintf(buffer, BUFFER_SIZE, "001-%03d: ", perline);
1964 buf_ptr = buffer + 9;
1968 for (x=data_offset; x < end_offset; x++) {
1969 level = tvb_get_guint8(tvb, x);
1970 if (global_acn_dmx_display_view==ACN_PREF_DMX_DISPLAY_PER) {
1971 if ((level > 0) && (level < 3)) {
1974 level = level * 100 / 255;
1977 buf_ptr = ltos(level, buf_ptr, base, leading_char, min_char, global_acn_dmx_display_zeros);
1981 if (item_cnt == perline || x == (end_offset-1)) {
1983 proto_tree_add_text(pdu_tree, tvb, data_offset, item_cnt, buffer);
1984 data_offset += perline;
1985 g_snprintf(buffer, BUFFER_SIZE, "%03d-%03d: ",total_cnt, total_cnt+perline);
1986 buf_ptr = buffer + 9;
1989 /* add separater character */
1990 if (item_cnt == halfline) {
1998 address data type (fixed at 0xA2)
1999 start code - 1 byte, reserved (should be 0)
2000 - 1 byte, start code (0x255)
2001 - 2 bytes, packet offset (should be 0000)
2002 address increment - 4 bytes (ignore)
2003 number of dmx values - 4 bytes (0-512)
2004 dmx values 0-512 bytes (data)
2009 return pdu_start + pdu_length;
2014 /******************************************************************************/
2015 /* Dissect DMX Base PDU */
2017 dissect_acn_dmx_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, acn_pdu_offsets *last_pdu_offsets)
2019 /* common to all pdu */
2023 guint32 pdu_flvh_length; /* flags, length, vector, header */
2024 acn_pdu_offsets pdu_offsets = {0,0,0,0,0};
2029 guint32 vector_offset;
2030 guint32 data_offset;
2032 guint32 data_length;
2034 proto_item *ti, *pi;
2035 proto_tree *pdu_tree = NULL;
2036 proto_tree *flag_tree = NULL;
2047 /* save start of pdu block */
2049 pdu_offsets.start = pdu_start;
2051 /* get PDU flags and length flag first */
2052 octet = tvb_get_guint8(tvb, offset++);
2053 pdu_flags = octet & 0xf0;
2054 length1 = octet & 0x0f; /* bottom 4 bits only */
2055 length2 = tvb_get_guint8(tvb, offset++);
2057 /* if length flag is set, then we have a 20 bit length else we have a 12 bit */
2058 /* flvh = flags, length, vector, header */
2059 if (pdu_flags & ACN_PDU_FLAG_L) {
2060 length3 = tvb_get_guint8(tvb, offset);
2062 pdu_length = length3 | (length2 << 8) | (length1 << 16);
2063 pdu_flvh_length = 3;
2065 pdu_length = length2 | (length1 << 8);
2066 pdu_flvh_length = 2;
2069 /* offset should now be pointing to vector (if one exists) */
2071 /* Add pdu item and tree */
2072 ti = proto_tree_add_item(tree, hf_acn_pdu, tvb, pdu_start, pdu_length, FALSE);
2073 pdu_tree = proto_item_add_subtree(ti, ett_acn_dmx_pdu);
2075 /* Add flag item and tree */
2076 pi = proto_tree_add_uint(pdu_tree, hf_acn_pdu_flags, tvb, pdu_start, 1, pdu_flags);
2077 flag_tree = proto_item_add_subtree(pi, ett_acn_pdu_flags);
2078 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_l, tvb, pdu_start, 1, FALSE);
2079 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_v, tvb, pdu_start, 1, FALSE);
2080 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_h, tvb, pdu_start, 1, FALSE);
2081 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_d, tvb, pdu_start, 1, FALSE);
2083 /* Add PDU Length item */
2084 proto_tree_add_uint(pdu_tree, hf_acn_pdu_length, tvb, pdu_start, pdu_flvh_length, pdu_length);
2086 /* Set vector offset */
2087 if (pdu_flags & ACN_PDU_FLAG_V) {
2088 /* use new values */
2089 vector_offset = offset;
2090 last_pdu_offsets->vector = offset;
2092 pdu_flvh_length += 4;
2094 /* use last values */
2095 vector_offset = last_pdu_offsets->vector;
2097 /* offset should now be pointing to header (if one exists) */
2099 /* Add Vector item */
2100 vector = tvb_get_ntohl(tvb, vector_offset);
2101 proto_tree_add_item(pdu_tree, hf_acn_dmx_vector, tvb, vector_offset, 4, FALSE);
2102 /* vector_offset +=4; */
2104 /* Add Vector item to tree*/
2105 name = val_to_str(vector, acn_dmx_vector_vals, "not valid (%d)");
2106 proto_item_append_text(ti, ": %s", name);
2108 /* NO HEADER DATA ON THESE* (at least so far) */
2111 if (pdu_flags & ACN_PDU_FLAG_D) {
2112 /* use new values */
2113 data_offset = offset;
2114 data_length = pdu_length - pdu_flvh_length;
2115 last_pdu_offsets->data = offset;
2116 last_pdu_offsets->data_length = data_length;
2118 /* use last values */
2119 data_offset = last_pdu_offsets->data;
2120 data_length = last_pdu_offsets->data_length;
2122 end_offset = data_offset + data_length;
2124 /* process based on vector */
2127 proto_tree_add_item(pdu_tree, hf_acn_dmx_source_name, tvb, data_offset, 32, FALSE);
2130 priority = tvb_get_guint8(tvb, data_offset);
2131 proto_tree_add_item(pdu_tree, hf_acn_dmx_priority, tvb, data_offset, 1, FALSE);
2134 sequence = tvb_get_guint8(tvb, data_offset);
2135 proto_tree_add_item(pdu_tree, hf_acn_dmx_sequence_number, tvb, data_offset, 1, FALSE);
2138 universe = tvb_get_ntohs(tvb, data_offset);
2139 proto_tree_add_item(pdu_tree, hf_acn_dmx_universe , tvb, data_offset, 2, FALSE);
2142 /* add universe to info */
2143 if(check_col(pinfo->cinfo,COL_INFO)){
2144 col_append_fstr(pinfo->cinfo,COL_INFO, ", Universe %d, Seq %3d", universe, sequence );
2147 proto_item_append_text(ti, ", Universe: %d, Priority: %d", universe, priority);
2149 data_offset = dissect_acn_dmx_data_pdu(tvb, pinfo, pdu_tree, data_offset, &pdu_offsets);
2153 return pdu_start + pdu_length;
2156 /******************************************************************************/
2157 /* Dissect SDT Base PDU */
2159 dissect_acn_sdt_base_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, acn_pdu_offsets *last_pdu_offsets)
2161 /* common to all pdu */
2165 guint32 pdu_flvh_length; /* flags, length, vector, header */
2166 acn_pdu_offsets pdu_offsets = {0,0,0,0,0};
2171 guint32 vector_offset;
2172 guint32 data_offset;
2175 guint32 data_length;
2177 proto_item *ti, *pi;
2178 proto_tree *pdu_tree = NULL;
2179 proto_tree *flag_tree = NULL;
2186 /* save start of pdu block */
2188 pdu_offsets.start = pdu_start;
2190 /* get PDU flags and length flag first */
2191 octet = tvb_get_guint8(tvb, offset++);
2192 pdu_flags = octet & 0xf0;
2193 length1 = octet & 0x0f; /* bottom 4 bits only */
2194 length2 = tvb_get_guint8(tvb, offset++);
2196 /* if length flag is set, then we have a 20 bit length else we have a 12 bit */
2197 /* flvh = flags, length, vector, header */
2198 if (pdu_flags & ACN_PDU_FLAG_L) {
2199 length3 = tvb_get_guint8(tvb, offset);
2201 pdu_length = length3 | (length2 << 8) | (length1 << 16);
2202 pdu_flvh_length = 3;
2204 pdu_length = length2 | (length1 << 8);
2205 pdu_flvh_length = 2;
2207 /* offset should now be pointing to vector (if one exists) */
2209 /* Add pdu item and tree */
2210 ti = proto_tree_add_item(tree, hf_acn_pdu, tvb, pdu_start, pdu_length, FALSE);
2211 pdu_tree = proto_item_add_subtree(ti, ett_acn_sdt_base_pdu);
2213 /* Add flag item and tree */
2214 pi = proto_tree_add_uint(pdu_tree, hf_acn_pdu_flags, tvb, pdu_start, 1, pdu_flags);
2215 flag_tree = proto_item_add_subtree(pi, ett_acn_pdu_flags);
2216 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_l, tvb, pdu_start, 1, FALSE);
2217 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_v, tvb, pdu_start, 1, FALSE);
2218 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_h, tvb, pdu_start, 1, FALSE);
2219 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_d, tvb, pdu_start, 1, FALSE);
2221 /* Add PDU Length item */
2222 proto_tree_add_uint(pdu_tree, hf_acn_pdu_length, tvb, pdu_start, pdu_flvh_length, pdu_length);
2224 /* Set vector offset */
2225 if (pdu_flags & ACN_PDU_FLAG_V) {
2226 /* use new values */
2227 vector_offset = offset;
2228 last_pdu_offsets->vector = offset;
2232 /* use last values */
2233 vector_offset = last_pdu_offsets->vector;
2235 /* offset should now be pointing to header (if one exists) */
2237 /* Add Vector item */
2238 vector = tvb_get_guint8(tvb, vector_offset);
2239 proto_tree_add_uint(pdu_tree, hf_acn_sdt_vector, tvb, vector_offset, 1, vector);
2241 /* Add Vector item to tree*/
2242 name = val_to_str(vector, acn_sdt_vector_vals, "not valid (%d)");
2243 proto_item_append_text(ti, ": ");
2244 proto_item_append_text(ti, name);
2246 /* NO HEADER DATA ON THESE* (at least so far) */
2249 if (pdu_flags & ACN_PDU_FLAG_D) {
2250 /* use new values */
2251 data_offset = offset;
2252 data_length = pdu_length - pdu_flvh_length;
2253 last_pdu_offsets->data = offset;
2254 last_pdu_offsets->data_length = data_length;
2256 /* use last values */
2257 data_offset = last_pdu_offsets->data;
2258 data_length = last_pdu_offsets->data_length;
2260 end_offset = data_offset + data_length;
2262 /* process based on vector */
2264 case ACN_SDT_VECTOR_UNKNOWN:
2266 case ACN_SDT_VECTOR_REL_WRAP:
2267 case ACN_SDT_VECTOR_UNREL_WRAP:
2268 proto_tree_add_item(pdu_tree, hf_acn_channel_number, tvb, data_offset, 2, FALSE);
2270 proto_tree_add_item(pdu_tree, hf_acn_total_sequence_number, tvb, data_offset, 4, FALSE);
2272 proto_tree_add_item(pdu_tree, hf_acn_reliable_sequence_number, tvb, data_offset, 4, FALSE);
2274 proto_tree_add_item(pdu_tree, hf_acn_oldest_available_wrapper, tvb, data_offset, 4, FALSE);
2276 proto_tree_add_item(pdu_tree, hf_acn_first_memeber_to_ack, tvb, data_offset, 2, FALSE);
2278 proto_tree_add_item(pdu_tree, hf_acn_last_memeber_to_ack, tvb, data_offset, 2, FALSE);
2280 proto_tree_add_item(pdu_tree, hf_acn_mak_threshold, tvb, data_offset, 2, FALSE);
2283 while (data_offset < end_offset) {
2284 old_offset = data_offset;
2285 data_offset = dissect_acn_sdt_client_pdu(tvb, pinfo, pdu_tree, data_offset, &pdu_offsets);
2286 if (data_offset == old_offset) break;
2289 case ACN_SDT_VECTOR_CHANNEL_PARAMS:
2291 case ACN_SDT_VECTOR_JOIN:
2292 proto_tree_add_item(pdu_tree, hf_acn_cid, tvb, data_offset, 16, FALSE);
2294 proto_tree_add_item(pdu_tree, hf_acn_member_id, tvb, data_offset, 2, FALSE);
2296 proto_tree_add_item(pdu_tree, hf_acn_channel_number, tvb, data_offset, 2, FALSE);
2298 proto_tree_add_item(pdu_tree, hf_acn_reciprocal_channel, tvb, data_offset, 2, FALSE);
2300 proto_tree_add_item(pdu_tree, hf_acn_total_sequence_number, tvb, data_offset, 4, FALSE);
2302 proto_tree_add_item(pdu_tree, hf_acn_reliable_sequence_number, tvb, data_offset, 4, FALSE);
2304 data_offset = acn_add_address(tvb, pinfo, pdu_tree, data_offset, "Destination Address:");
2305 data_offset = acn_add_channel_parameter(tvb, pinfo, pdu_tree, data_offset);
2306 data_offset = acn_add_expiry(tvb, pinfo, pdu_tree, data_offset, "Ad-hoc Expiry:");
2308 case ACN_SDT_VECTOR_JOIN_REFUSE:
2309 pi = proto_tree_add_item(pdu_tree, hf_acn_cid, tvb, data_offset, 16, FALSE);
2311 proto_item_append_text(pi, "(Leader)");
2312 proto_tree_add_item(pdu_tree, hf_acn_channel_number, tvb, data_offset, 2, FALSE);
2314 proto_tree_add_item(pdu_tree, hf_acn_member_id, tvb, data_offset, 2, FALSE);
2316 proto_tree_add_item(pdu_tree, hf_acn_reliable_sequence_number, tvb, data_offset, 4, FALSE);
2318 proto_tree_add_item(pdu_tree, hf_acn_refuse_code, tvb, data_offset, 1, FALSE);
2321 case ACN_SDT_VECTOR_JOIN_ACCEPT:
2322 pi = proto_tree_add_item(pdu_tree, hf_acn_cid, tvb, data_offset, 16, FALSE);
2324 proto_item_append_text(pi, "(Leader)");
2325 proto_tree_add_item(pdu_tree, hf_acn_channel_number, tvb, data_offset, 2, FALSE);
2327 proto_tree_add_item(pdu_tree, hf_acn_member_id, tvb, data_offset, 2, FALSE);
2329 proto_tree_add_item(pdu_tree, hf_acn_reliable_sequence_number, tvb, data_offset, 4, FALSE);
2331 proto_tree_add_item(pdu_tree, hf_acn_reciprocal_channel, tvb, data_offset, 2, FALSE);
2334 case ACN_SDT_VECTOR_LEAVE:
2336 case ACN_SDT_VECTOR_LEAVING:
2337 pi = proto_tree_add_item(pdu_tree, hf_acn_cid, tvb, data_offset, 16, FALSE);
2339 proto_item_append_text(pi, "(Leader)");
2340 proto_tree_add_item(pdu_tree, hf_acn_channel_number, tvb, data_offset, 2, FALSE);
2342 proto_tree_add_item(pdu_tree, hf_acn_member_id, tvb, data_offset, 2, FALSE);
2344 proto_tree_add_item(pdu_tree, hf_acn_reliable_sequence_number, tvb, data_offset, 4, FALSE);
2346 proto_tree_add_item(pdu_tree, hf_acn_reason_code, tvb, data_offset, 1, FALSE);
2349 case ACN_SDT_VECTOR_CONNECT:
2351 case ACN_SDT_VECTOR_CONNECT_ACCEPT:
2353 case ACN_SDT_VECTOR_CONNECT_REFUSE:
2355 case ACN_SDT_VECTOR_DISCONNECT:
2357 case ACN_SDT_VECTOR_DISCONNECTING:
2359 case ACN_SDT_VECTOR_ACK:
2361 case ACN_SDT_VECTOR_NAK:
2362 pi = proto_tree_add_item(pdu_tree, hf_acn_cid, tvb, data_offset, 16, FALSE);
2364 proto_item_append_text(pi, "(Leader)");
2365 proto_tree_add_item(pdu_tree, hf_acn_channel_number, tvb, data_offset, 2, FALSE);
2367 proto_tree_add_item(pdu_tree, hf_acn_member_id, tvb, data_offset, 2, FALSE);
2369 proto_tree_add_item(pdu_tree, hf_acn_reliable_sequence_number, tvb, data_offset, 4, FALSE);
2371 proto_tree_add_item(pdu_tree, hf_acn_first_missed_sequence, tvb, data_offset, 4, FALSE);
2373 proto_tree_add_item(pdu_tree, hf_acn_last_missed_sequence, tvb, data_offset, 4, FALSE);
2376 case ACN_SDT_VECTOR_GET_SESSION:
2377 proto_tree_add_item(pdu_tree, hf_acn_cid, tvb, data_offset, 16, FALSE);
2380 case ACN_SDT_VECTOR_SESSIONS:
2381 member_id = tvb_get_ntohs(tvb, data_offset);
2382 switch (member_id) {
2384 data_offset = acn_add_channel_owner_info_block(tvb, pinfo, pdu_tree, data_offset);
2387 data_offset = acn_add_channel_member_info_block(tvb, pinfo, pdu_tree, data_offset);
2393 return pdu_start + pdu_length;
2396 /******************************************************************************/
2397 /* Dissect Root PDU */
2399 dissect_acn_root_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, acn_pdu_offsets *last_pdu_offsets)
2401 /* common to all pdu */
2405 guint32 pdu_flvh_length; /* flags, length, vector, header */
2406 acn_pdu_offsets pdu_offsets = {0,0,0,0,0};
2411 guint32 vector_offset;
2412 guint32 header_offset;
2413 guint32 data_offset;
2416 guint32 data_length;
2418 proto_item *ti, *pi;
2419 proto_tree *pdu_tree = NULL;
2420 proto_tree *flag_tree = NULL;
2423 guint32 protocol_id;
2426 /* save start of pdu block */
2428 pdu_offsets.start = pdu_start;
2430 /* get PDU flags and length flag first */
2431 octet = tvb_get_guint8(tvb, offset++);
2432 pdu_flags = octet & 0xf0;
2433 length1 = octet & 0x0f; /* bottom 4 bits only */
2434 length2 = tvb_get_guint8(tvb, offset++);
2436 /* if length flag is set, then we have a 20 bit length else we have a 12 bit */
2437 /* flvh = flags, length, vector, header */
2438 if (pdu_flags & ACN_PDU_FLAG_L) {
2439 length3 = tvb_get_guint8(tvb, offset);
2441 pdu_length = length3 | (length2 << 8) | (length1 << 16);
2442 pdu_flvh_length = 3;
2444 pdu_length = length2 | (length1 << 8);
2445 pdu_flvh_length = 2;
2447 /* offset should now be pointing to vector (if one exists) */
2449 /* Add pdu item and tree */
2450 ti = proto_tree_add_item(tree, hf_acn_pdu, tvb, pdu_start, pdu_length, FALSE);
2451 pdu_tree = proto_item_add_subtree(ti, ett_acn_root_pdu);
2453 /* Add flag item and tree */
2454 pi = proto_tree_add_uint(pdu_tree, hf_acn_pdu_flags, tvb, pdu_start, 1, pdu_flags);
2455 flag_tree = proto_item_add_subtree(pi, ett_acn_pdu_flags);
2456 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_l, tvb, pdu_start, 1, FALSE);
2457 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_v, tvb, pdu_start, 1, FALSE);
2458 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_h, tvb, pdu_start, 1, FALSE);
2459 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_d, tvb, pdu_start, 1, FALSE);
2461 /* Add PDU Length item */
2462 proto_tree_add_uint(pdu_tree, hf_acn_pdu_length, tvb, pdu_start, pdu_flvh_length, pdu_length);
2464 /* Set vector offset */
2465 if (pdu_flags & ACN_PDU_FLAG_V) {
2466 /* use new values */
2467 vector_offset = offset;
2468 last_pdu_offsets->vector = offset;
2470 pdu_flvh_length += 4;
2472 /* use last values */
2473 vector_offset = last_pdu_offsets->vector;
2475 /* offset should now be pointing to header (if one exists) */
2479 /* Get Protocol ID (vector) */
2480 protocol_id = tvb_get_ntohl(tvb, vector_offset);
2481 proto_tree_add_uint(pdu_tree, hf_acn_protocol_id, tvb, vector_offset, 4, protocol_id);
2483 /* process based on protocol_id */
2484 switch (protocol_id) {
2485 case ACN_PROTOCOL_ID_DMX:
2486 if (global_acn_dmx_enable) {
2487 proto_item_append_text(ti,": Root DMX");
2489 /* Set header offset */
2490 if (pdu_flags & ACN_PDU_FLAG_H) {
2491 /* use new values */
2492 header_offset = offset;
2493 last_pdu_offsets->header = offset;
2495 pdu_flvh_length += 16;
2497 /* use last values */
2498 header_offset = last_pdu_offsets->header;
2500 /* offset should now be pointing to data (if one exists) */
2502 /* get Header (CID) 16 bytes */
2503 tvb_get_guid(tvb, header_offset, &guid, FALSE);
2504 proto_item_append_text(ti, ", Src: %s", guid_to_str(&guid));
2506 /* add cid to info */
2507 if(check_col(pinfo->cinfo,COL_INFO)){
2508 col_clear(pinfo->cinfo,COL_INFO);
2509 col_add_fstr(pinfo->cinfo,COL_INFO, "CID %s", guid_to_str(&guid));
2512 proto_tree_add_item(pdu_tree, hf_acn_cid, tvb, header_offset, 16, FALSE);
2513 header_offset += 16;
2516 if (pdu_flags & ACN_PDU_FLAG_D) {
2517 /* use new values */
2518 data_offset = offset;
2519 data_length = pdu_length - pdu_flvh_length;
2520 last_pdu_offsets->data = offset;
2521 last_pdu_offsets->data_length = data_length;
2523 /* use last values */
2524 data_offset = last_pdu_offsets->data;
2525 data_length = last_pdu_offsets->data_length;
2527 end_offset = data_offset + data_length;
2529 /* adjust for what we used */
2530 while (data_offset < end_offset) {
2531 old_offset = data_offset;
2532 data_offset = dissect_acn_dmx_pdu(tvb, pinfo, pdu_tree, data_offset, &pdu_offsets);
2533 if (data_offset == old_offset) break;
2537 case ACN_PROTOCOL_ID_SDT:
2539 proto_item_append_text(ti,": Root SDT");
2541 /* Set header offset */
2542 if (pdu_flags & ACN_PDU_FLAG_H) {
2543 /* use new values */
2544 header_offset = offset;
2545 last_pdu_offsets->header = offset;
2547 pdu_flvh_length += 16;
2549 /* use last values */
2550 header_offset = last_pdu_offsets->header;
2552 /* offset should now be pointing to data (if one exists) */
2554 /* get Header (CID) 16 bytes */
2555 tvb_get_guid(tvb, header_offset, &guid, FALSE);
2556 proto_item_append_text(ti, ", Src: %s", guid_to_str(&guid));
2558 proto_tree_add_item(pdu_tree, hf_acn_cid, tvb, header_offset, 16, FALSE);
2559 header_offset += 16;
2562 if (pdu_flags & ACN_PDU_FLAG_D) {
2563 /* use new values */
2564 data_offset = offset;
2565 data_length = pdu_length - pdu_flvh_length;
2566 last_pdu_offsets->data = offset;
2567 last_pdu_offsets->data_length = data_length;
2569 /* use last values */
2570 data_offset = last_pdu_offsets->data;
2571 data_length = last_pdu_offsets->data_length;
2573 end_offset = data_offset + data_length;
2575 /* adjust for what we used */
2576 while (data_offset < end_offset) {
2577 old_offset = data_offset;
2578 data_offset = dissect_acn_sdt_base_pdu(tvb, pinfo, pdu_tree, data_offset, &pdu_offsets);
2579 if (data_offset == old_offset) break;
2584 return pdu_start + pdu_length;
2587 /******************************************************************************/
2590 dissect_acn(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
2592 proto_item *ti = NULL;
2593 proto_tree *acn_tree = NULL;
2594 guint32 data_offset = 0;
2597 acn_pdu_offsets pdu_offsets = {0,0,0,0,0};
2599 /* if (!is_acn(tvb)) { */
2603 /* Set the protocol column */
2604 if (check_col(pinfo->cinfo, COL_PROTOCOL)) {
2605 col_set_str(pinfo->cinfo, COL_PROTOCOL, "ACN");
2608 /* Clear out stuff in the info column */
2609 if(check_col(pinfo->cinfo,COL_INFO)){
2610 /* col_clear(pinfo->cinfo,COL_INFO); */
2611 col_add_fstr(pinfo->cinfo,COL_INFO, "ACN [Src Port: %d, Dst Port: %d]", pinfo->srcport, pinfo->destport );
2614 if (tree) { /* we are being asked for details */
2615 ti = proto_tree_add_item(tree, proto_acn, tvb, 0, -1, FALSE);
2616 acn_tree = proto_item_add_subtree(ti, ett_acn);
2618 pdu_offsets.start = data_offset;
2620 /* add preamble, postamble and ACN Packet ID */
2621 proto_tree_add_item(acn_tree, hf_acn_preamble_size, tvb, data_offset, 2, FALSE);
2623 proto_tree_add_item(acn_tree, hf_acn_postamble_size, tvb, data_offset, 2, FALSE);
2625 proto_tree_add_item(acn_tree, hf_acn_packet_identifier, tvb, data_offset, 12, FALSE);
2628 /* one past the last byte */
2629 end_offset = data_offset + tvb_reported_length_remaining(tvb, data_offset);
2630 while (data_offset < end_offset) {
2631 old_offset = data_offset;
2632 data_offset = dissect_acn_root_pdu(tvb, pinfo, acn_tree, data_offset, &pdu_offsets);
2633 if (data_offset == old_offset) break;
2636 return tvb_length(tvb);
2639 /******************************************************************************/
2640 /* Register protocol */
2641 void proto_register_acn(void)
2643 static hf_register_info hf[] = {
2644 /**************************************************************************/
2645 /* In alphabetical order */
2648 { &hf_acn_ip_address_type,
2649 { "Addr Type", "acn.ip_address_type",
2650 FT_UINT8, BASE_DEC, VALS(acn_ip_address_type_vals), 0x0,
2654 { &hf_acn_association,
2655 { "Association", "acn.association",
2656 FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
2659 /* Channel Number */
2660 { &hf_acn_channel_number,
2661 { "Channel Number", "acn.channel_number",
2662 FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
2668 FT_GUID, BASE_NONE, NULL, 0x0,
2671 /* Client Protocol ID */
2672 { &hf_acn_client_protocol_id,
2673 { "Client Protocol ID", "acn.client_protocol_id",
2674 FT_UINT32, BASE_DEC, VALS(acn_protocol_id_vals), 0x0,
2679 { "Data", "acn.dmp_data",
2680 FT_BYTES, BASE_HEX, NULL, 0x0,
2684 { "Addr", "acn.dmp_data8",
2685 FT_UINT8, BASE_DEC_HEX, NULL, 0x0,
2689 { "Addr", "acn.dmp_data16",
2690 FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
2694 { "Addr", "acn.dmp_data24",
2695 FT_UINT24, BASE_DEC_HEX, NULL, 0x0,
2699 { "Addr", "acn.dmp_data32",
2700 FT_UINT32, BASE_DEC_HEX, NULL, 0x0,
2704 { &hf_acn_dmp_address_data_pairs,
2705 { "Address-Data Pairs", "acn.dmp_address_data_pairs",
2706 FT_BYTES, BASE_DEC, NULL, 0x0,
2707 "More address-data pairs", HFILL }
2711 { &hf_acn_dmp_address1,
2712 { "Address", "acn.dmp_address",
2713 FT_UINT8, BASE_DEC_HEX, NULL, 0x0,
2716 { &hf_acn_dmp_address2,
2717 { "Address", "acn.dmp_address",
2718 FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
2721 { &hf_acn_dmp_address4,
2722 { "Address", "acn.dmp_address",
2723 FT_UINT32, BASE_DEC_HEX, NULL, 0x0,
2727 /* DMP Address type*/
2729 { "Address and Data Type", "acn.dmp_adt",
2730 FT_UINT8, BASE_DEC_HEX, NULL, 0x0,
2733 { &hf_acn_dmp_adt_a,
2734 { "Size", "acn.dmp_adt_a",
2735 FT_UINT8, BASE_DEC, VALS(acn_dmp_adt_a_vals), 0x03,
2738 { &hf_acn_dmp_adt_d,
2739 { "Data Type", "acn.dmp_adt_d",
2740 FT_UINT8, BASE_DEC, VALS(acn_dmp_adt_d_vals), 0x30,
2743 { &hf_acn_dmp_adt_r,
2744 { "Relative", "acn.dmp_adt_r",
2745 FT_UINT8, BASE_DEC, VALS(acn_dmp_adt_r_vals), 0x40,
2748 { &hf_acn_dmp_adt_v,
2749 { "Virtual", "acn.dmp_adt_v",
2750 FT_UINT8, BASE_DEC, VALS(acn_dmp_adt_v_vals), 0x80,
2753 { &hf_acn_dmp_adt_x,
2754 { "Reserved", "acn.dmp_adt_x",
2755 FT_UINT8, BASE_DEC, NULL, 0x0c,
2759 /* DMP Reason Code */
2760 { &hf_acn_dmp_reason_code,
2761 { "Reason Code", "acn.dmp_reason_code",
2762 FT_UINT8, BASE_DEC, VALS(acn_dmp_reason_code_vals), 0x0,
2767 { &hf_acn_dmp_vector,
2768 { "DMP Vector", "acn.dmp_vector",
2769 FT_UINT8, BASE_DEC, VALS(acn_dmp_vector_vals), 0x0,
2774 { "Expiry", "acn.expiry",
2775 FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
2778 /* First Member to ACK */
2779 { &hf_acn_first_memeber_to_ack,
2780 { "First Member to ACK", "acn.first_member_to_ack",
2781 FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
2784 /* First Missed Sequence */
2785 { &hf_acn_first_missed_sequence,
2786 { "First Missed Sequence", "acn.first_missed_sequence",
2787 FT_UINT32, BASE_DEC_HEX, NULL, 0x0,
2792 { "IPV4", "acn.ipv4",
2793 FT_IPv4, BASE_NONE, NULL, 0x0,
2798 { "IPV6", "acn.ipv6",
2799 FT_IPv6, BASE_NONE, NULL, 0x0,
2802 /* Last Member to ACK */
2803 { &hf_acn_last_memeber_to_ack,
2804 { "Last Member to ACK", "acn.last_member_to_ack",
2805 FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
2808 /* Last Missed Sequence */
2809 { &hf_acn_last_missed_sequence,
2810 { "Last Missed Sequence", "acn.last_missed_sequence",
2811 FT_UINT32, BASE_DEC_HEX, NULL, 0x0,
2815 { &hf_acn_mak_threshold,
2816 { "MAK Threshold", "acn.mak_threshold",
2817 FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
2821 { &hf_acn_member_id,
2822 { "Member ID", "acn.member_id",
2823 FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
2827 { &hf_acn_nak_holdoff,
2828 { "NAK holdoff (ms)", "acn.nak_holdoff",
2829 FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
2833 { &hf_acn_nak_max_wait,
2834 { "NAK Max Wait (ms)", "acn.nak_max_wait",
2835 FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
2839 { &hf_acn_nak_modulus,
2840 { "NAK Modulus", "acn.nak_modulus",
2841 FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
2844 /* NAK Outbound Flag */
2845 { &hf_acn_nak_outbound_flag,
2846 { "NAK Outbound Flag", "acn.nak_outbound_flag",
2847 FT_BOOLEAN, 8, NULL, 0x80,
2850 /* Oldest Available Wrapper */
2851 { &hf_acn_oldest_available_wrapper,
2852 { "Oldest Available Wrapper", "acn.oldest_available_wrapper",
2853 FT_UINT32, BASE_DEC_HEX, NULL, 0x0,
2856 /* Preamble Sizet */
2857 { &hf_acn_preamble_size,
2858 { "Size of preamble", "acn.preamble_size",
2859 FT_UINT16, BASE_DEC, NULL, 0x0,
2860 "Preamble size in bytes", HFILL }
2862 /* Packet Identifier */
2863 { &hf_acn_packet_identifier,
2864 { "Packet Identifier", "acn.packet_identifier",
2865 FT_STRING, BASE_NONE, NULL, 0x0,
2871 FT_NONE, BASE_NONE, NULL, 0x0,
2875 { &hf_acn_pdu_flags,
2876 { "Flags", "acn.pdu.flags",
2877 FT_UINT8, BASE_HEX, NULL, 0x0,
2878 "PDU Flags", HFILL }
2880 { &hf_acn_pdu_flag_d,
2881 { "Data", "acn.pdu.flag_d",
2882 FT_BOOLEAN, 8, NULL, ACN_PDU_FLAG_D,
2883 "Data flag", HFILL }
2885 { &hf_acn_pdu_flag_h,
2886 { "Header", "acn.pdu.flag_h",
2887 FT_BOOLEAN, 8, NULL, ACN_PDU_FLAG_H,
2888 "Header flag", HFILL }
2890 { &hf_acn_pdu_flag_l,
2891 { "Length", "acn.pdu.flag_l",
2892 FT_BOOLEAN, 8, NULL, ACN_PDU_FLAG_L,
2893 "Length flag", HFILL }
2895 { &hf_acn_pdu_flag_v,
2896 { "Vector", "acn.pdu.flag_v",
2897 FT_BOOLEAN, 8, NULL, ACN_PDU_FLAG_V,
2898 "Vector flag", HFILL }
2901 { &hf_acn_pdu_length,
2902 { "Length", "acn.pdu.flag_d",
2903 FT_UINT32, BASE_DEC, NULL, 0x0,
2904 "PDU Length", HFILL }
2908 { "Port", "acn.port",
2909 FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
2912 /* Postamble Size */
2913 { &hf_acn_postamble_size,
2914 { "Size of postamble", "acn.postamble_size",
2915 FT_UINT16, BASE_DEC, NULL, 0x0,
2916 "Postamble size in bytes", HFILL }
2919 { &hf_acn_protocol_id,
2920 { "Protocol ID", "acn.protocol_id",
2921 FT_UINT32, BASE_DEC, VALS(acn_protocol_id_vals), 0x0,
2925 { &hf_acn_reason_code,
2926 { "Reason Code", "acn.reason_code",
2927 FT_UINT8, BASE_DEC, VALS(acn_reason_code_vals), 0x0,
2930 /* Reciprocal Channel */
2931 { &hf_acn_reciprocal_channel,
2932 { "Reciprocal Channel Number", "acn.acn_reciprocal_channel",
2933 FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
2934 "Reciprocal Channel", HFILL }
2937 { &hf_acn_refuse_code,
2938 { "Refuse Code", "acn.acn_refuse_code",
2939 FT_UINT8, BASE_DEC, VALS(acn_refuse_code_vals), 0x0,
2942 /* Reliable Sequence Number */
2943 { &hf_acn_reliable_sequence_number,
2944 { "Reliable Sequence Number", "acn.reliable_sequence_number",
2945 FT_UINT32, BASE_DEC_HEX, NULL, 0x0,
2949 { &hf_acn_sdt_vector,
2950 { "STD Vector", "acn.sdt_vector",
2951 FT_UINT8, BASE_DEC, VALS(acn_sdt_vector_vals), 0x0,
2956 { &hf_acn_dmx_vector,
2957 { "Vector", "acn.dmx_vector",
2958 FT_UINT32, BASE_DEC, VALS(acn_dmx_vector_vals), 0x0,
2959 "DMX Vector", HFILL }
2961 /* DMX Source Name */
2962 { &hf_acn_dmx_source_name,
2963 { "Source", "acn.dmx.source_name",
2964 FT_STRING, BASE_NONE, NULL, 0x0,
2965 "DMX Source Name", HFILL }
2969 { &hf_acn_dmx_priority,
2970 { "Priority", "acn.dmx.priority",
2971 FT_UINT8, BASE_DEC, NULL, 0x0,
2972 "DMX Priority", HFILL }
2974 /* DMX Sequence number */
2975 { &hf_acn_dmx_sequence_number,
2976 { "Seq No", "acn.dmx.seq_number",
2977 FT_UINT8, BASE_DEC, NULL, 0x0,
2978 "DMX Sequence Number", HFILL }
2981 { &hf_acn_dmx_universe,
2982 { "Universe", "acn.dmx.universe",
2983 FT_UINT16, BASE_DEC, NULL, 0x0,
2984 "DMX Universe", HFILL }
2987 /* DMX Start Code */
2988 { &hf_acn_dmx_start_code,
2989 { "Start Code", "acn.dmx.start_code",
2990 FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
2991 "DMX Start Code", HFILL }
2994 /* DMX Address Increment */
2995 { &hf_acn_dmx_increment,
2996 { "Increment", "acn.dmx.increment",
2997 FT_UINT16, BASE_DEC, NULL, 0x0,
2998 "DMX Increment", HFILL }
3001 /* DMX Packet Count */
3002 { &hf_acn_dmx_count,
3003 { "Count", "acn.dmx.count",
3004 FT_UINT16, BASE_DEC, NULL, 0x0,
3005 "DMX Count", HFILL }
3009 { &hf_acn_session_count,
3010 { "Session Count", "acn.session_count",
3011 FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
3014 /* Total Sequence Number */
3015 { &hf_acn_total_sequence_number,
3016 { "Total Sequence Number", "acn.total_sequence_number",
3017 FT_UINT32, BASE_DEC_HEX, NULL, 0x0,
3022 /* Setup protocol subtree array */
3023 static gint *ett[] = {
3025 &ett_acn_channel_owner_info_block,
3026 &ett_acn_channel_member_info_block,
3027 &ett_acn_channel_parameter,
3029 &ett_acn_address_type,
3033 &ett_acn_sdt_client_pdu,
3034 &ett_acn_sdt_base_pdu,
3036 &ett_acn_dmx_address,
3037 &ett_acn_dmx_data_pdu,
3041 module_t *acn_module;
3042 if (proto_acn == -1) {
3043 proto_acn = proto_register_protocol (
3044 "Architecture for Control Networks", /* name */
3045 "ACN", /* short name */
3050 proto_register_field_array(proto_acn, hf, array_length(hf));
3051 proto_register_subtree_array(ett, array_length(ett));
3053 acn_module = prefs_register_protocol(proto_acn, NULL);
3054 prefs_register_bool_preference(acn_module, "heuristic_acn",
3056 "Enable Architecture for Control Networks dissector (ANSI BSR E1.17)",
3059 prefs_register_bool_preference(acn_module, "dmx_enable",
3061 "Enable Streaming DMX extension dissector (ANSI BSR E1.31)",
3062 &global_acn_dmx_enable);
3064 prefs_register_enum_preference(acn_module, "dmx_display_view",
3065 "DMX, display format",
3067 &global_acn_dmx_display_view,
3071 prefs_register_bool_preference(acn_module, "dmx_display_zeros",
3072 "DMX, display zeros",
3073 "Display zeros instead of dots",
3074 &global_acn_dmx_display_zeros);
3076 prefs_register_bool_preference(acn_module, "dmx_display_leading_zeros",
3077 "DMX, display leading zeros",
3078 "Display leading zeros on levels",
3079 &global_acn_dmx_display_leading_zeros);
3081 prefs_register_enum_preference(acn_module, "dmx_display_line_format",
3082 "DMX, display line format",
3083 "Display line format",
3084 &global_acn_dmx_display_line_format,
3085 dmx_display_line_format,
3090 /******************************************************************************/
3091 /* Register handoff */
3093 proto_reg_handoff_acn(void)
3095 /* dissector_handle_t acn_handle; */
3096 /* acn_handle = new_create_dissector_handle(dissect_acn, proto_acn); */
3097 /* dissector_add_handle("udp.port", acn_handle); */
3098 heur_dissector_add("udp", dissect_acn_heur, proto_acn);