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 Version: 0.0.9 wrf 10-25-2006 Released to Wireshark community
37 Version: 0.0.10 wrf 10-25-2006 small revisions to submit...
38 Version: 0.0.11 wrf 10-29-2006 revisions to submit...
49 #include <epan/packet.h>
50 #include <epan/prefs.h>
51 #include <epan/emem.h>
52 #include <epan/packet.h>
53 #include <epan/ipv6-utils.h>
56 #include "packet-acn.h"
60 * ANSI BSR E1.17 Architecture for Control Networks
64 #define ACTUAL_ADDRESS 0
65 /* forward reference */
66 static gboolean dissect_acn_heur( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree );
67 static guint32 acn_add_channel_owner_info_block(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree _U_, int offset);
68 static guint32 acn_add_channel_member_info_block(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree _U_, int offset);
69 static guint32 acn_add_expiry(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, const char *label);
70 static guint32 acn_add_channel_parameter(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset);
71 static guint32 acn_add_address(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, const char *label);
72 static guint32 acn_add_dmp_address_type(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, acn_dmp_adt_type *adt);
73 static guint32 acn_add_dmp_address(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, acn_dmp_adt_type *adt);
74 static guint32 dissect_acn_dmp_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, acn_pdu_offsets *last_pdu_offsets);
75 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);
76 static guint32 dissect_acn_sdt_client_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, acn_pdu_offsets *last_pdu_offsets);
77 static guint32 dissect_acn_dmx_data_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, acn_pdu_offsets *last_pdu_offsets);
78 static guint32 dissect_acn_dmx_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, acn_pdu_offsets *last_pdu_offsets);
79 static guint32 dissect_acn_sdt_base_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, acn_pdu_offsets *last_pdu_offsets);
80 static guint32 dissect_acn_root_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, acn_pdu_offsets *last_pdu_offsets);
81 static int dissect_acn(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
82 static gboolean is_acn(tvbuff_t *tvb);
83 void proto_register_acn(void);
84 void proto_reg_handoff_acn(void);
86 /* Global variables */
87 static int proto_acn = -1;
88 static gint ett_acn = -1;
89 static gint ett_acn_channel_owner_info_block = -1;
90 static gint ett_acn_channel_member_info_block = -1;
91 static gint ett_acn_channel_parameter = -1;
92 static gint ett_acn_address = -1;
93 static gint ett_acn_address_type = -1;
94 static gint ett_acn_pdu_flags = -1;
95 static gint ett_acn_dmp_pdu = -1;
96 static gint ett_acn_sdt_pdu = -1;
97 static gint ett_acn_sdt_client_pdu = -1;
98 static gint ett_acn_sdt_base_pdu = -1;
99 static gint ett_acn_root_pdu = -1;
100 static gint ett_acn_dmx_address = -1;
101 static gint ett_acn_dmx_data_pdu = -1;
102 static gint ett_acn_dmx_pdu = -1;
104 /* Register fields */
105 /* In alphabetical order */
106 static int hf_acn_association = -1;
107 static int hf_acn_channel_number = -1;
108 static int hf_acn_cid = -1;
109 static int hf_acn_client_protocol_id = -1;
110 static int hf_acn_data = -1;
111 static int hf_acn_data8 = -1;
112 static int hf_acn_data16 = -1;
113 static int hf_acn_data24 = -1;
114 static int hf_acn_data32 = -1;
115 static int hf_acn_dmp_address1 = -1;
116 static int hf_acn_dmp_address2 = -1;
117 static int hf_acn_dmp_address4 = -1;
118 static int hf_acn_dmp_adt = -1; /* address and data type*/
119 static int hf_acn_dmp_adt_a = -1;
120 static int hf_acn_dmp_adt_v = -1;
121 static int hf_acn_dmp_adt_r = -1;
122 static int hf_acn_dmp_adt_d = -1;
123 static int hf_acn_dmp_adt_x = -1;
124 static int hf_acn_dmp_reason_code = -1;
125 static int hf_acn_dmp_vector = -1;
126 static int hf_acn_dmp_address_data_pairs = -1;
127 static int hf_acn_expiry = -1;
128 static int hf_acn_first_memeber_to_ack = -1;
129 static int hf_acn_first_missed_sequence = -1;
130 static int hf_acn_ip_address_type = -1;
131 static int hf_acn_ipv4 = -1;
132 static int hf_acn_ipv6 = -1;
133 static int hf_acn_last_memeber_to_ack = -1;
134 static int hf_acn_last_missed_sequence = -1;
135 static int hf_acn_mak_threshold = -1;
136 static int hf_acn_member_id = -1;
137 static int hf_acn_nak_holdoff = -1;
138 static int hf_acn_nak_max_wait = -1;
139 static int hf_acn_nak_modulus = -1;
140 static int hf_acn_nak_outbound_flag = -1;
141 static int hf_acn_oldest_available_wrapper = -1;
142 static int hf_acn_packet_identifier = -1;
143 static int hf_acn_pdu = -1;
144 static int hf_acn_pdu_flag_d = -1;
145 static int hf_acn_pdu_flag_h = -1;
146 static int hf_acn_pdu_flag_l = -1;
147 static int hf_acn_pdu_flag_v = -1;
148 static int hf_acn_pdu_flags = -1;
149 static int hf_acn_pdu_length = -1;
150 static int hf_acn_port = -1;
151 static int hf_acn_postamble_size = -1;
152 static int hf_acn_preamble_size = -1;
153 static int hf_acn_protocol_id = -1;
154 static int hf_acn_reason_code = -1;
155 static int hf_acn_reciprocal_channel = -1;
156 static int hf_acn_refuse_code = -1;
157 static int hf_acn_reliable_sequence_number = -1;
158 /* static int hf_acn_sdt_pdu = -1; */
159 static int hf_acn_sdt_vector = -1;
160 static int hf_acn_dmx_vector = -1;
161 static int hf_acn_session_count = -1;
162 static int hf_acn_total_sequence_number = -1;
163 static int hf_acn_dmx_source_name = -1;
164 static int hf_acn_dmx_priority = -1;
165 static int hf_acn_dmx_sequence_number = -1;
166 static int hf_acn_dmx_universe = -1;
167 /* static int hf_acn_dmx_dmp_vector = -1; */
169 /* Try heuristic ACN decode */
170 static gboolean global_acn_heur = FALSE;
171 static gboolean global_acn_dmx_enable = FALSE;
172 static gint global_acn_dmx_display_view = 0;
173 static gboolean global_acn_dmx_display_zeros = FALSE;
174 static gboolean global_acn_dmx_display_leading_zeros = FALSE;
177 static const value_string acn_protocol_id_vals[] = {
178 { ACN_PROTOCOL_ID_SDT, "SDT Protocol" },
179 { ACN_PROTOCOL_ID_DMP, "DMP Protocol" },
180 { ACN_PROTOCOL_ID_DMX, "DMX Protocol" },
184 static const value_string acn_dmp_adt_r_vals[] = {
190 static const value_string acn_dmp_adt_v_vals[] = {
196 static const value_string acn_dmp_adt_d_vals[] = {
197 { ACN_DMP_ADT_D_NS, "Non-range, single data item" },
198 { ACN_DMP_ADT_D_RS, "Range, single data item" },
199 { ACN_DMP_ADT_D_RE, "Range, array of equal size data items" },
200 { ACN_DMP_ADT_D_RM, "Range, series of mixed size data items" },
204 static const value_string acn_dmp_adt_a_vals[] = {
205 { ACN_DMP_ADT_A_1, "1 octet" },
206 { ACN_DMP_ADT_A_2, "2 octets" },
207 { ACN_DMP_ADT_A_4, "4 octets" },
208 { ACN_DMP_ADT_A_R, "reserved" },
213 static const value_string acn_sdt_vector_vals[] = {
214 {ACN_SDT_VECTOR_UNKNOWN, "Unknown"},
215 {ACN_SDT_VECTOR_REL_WRAP, "Reliable Wrapper"},
216 {ACN_SDT_VECTOR_UNREL_WRAP, "Unreliable Wrapper"},
217 {ACN_SDT_VECTOR_CHANNEL_PARAMS, "Channel Parameters"},
218 {ACN_SDT_VECTOR_JOIN, "Join"},
219 {ACN_SDT_VECTOR_JOIN_REFUSE, "Join Refuse"},
220 {ACN_SDT_VECTOR_JOIN_ACCEPT, "Join Accept"},
221 {ACN_SDT_VECTOR_LEAVE, "Leave"},
222 {ACN_SDT_VECTOR_LEAVING, "Leaving"},
223 {ACN_SDT_VECTOR_CONNECT, "Connect"},
224 {ACN_SDT_VECTOR_CONNECT_ACCEPT, "Connect Accept"},
225 {ACN_SDT_VECTOR_CONNECT_REFUSE, "Connect Refuse"},
226 {ACN_SDT_VECTOR_DISCONNECT, "Disconnect"},
227 {ACN_SDT_VECTOR_DISCONNECTING, "Disconnecting"},
228 {ACN_SDT_VECTOR_ACK, "Ack"},
229 {ACN_SDT_VECTOR_NAK, "Nak"},
230 {ACN_SDT_VECTOR_GET_SESSION, "Get Session"},
231 {ACN_SDT_VECTOR_SESSIONS, "Sessions"},
235 static const value_string acn_dmx_vector_vals[] = {
236 {ACN_DMX_VECTOR, "Streaming DMX"},
240 static const value_string acn_dmp_vector_vals[] = {
241 {ACN_DMP_VECTOR_UNKNOWN, "Unknown"},
242 {ACN_DMP_VECTOR_GET_PROPERTY, "Get Property"},
243 {ACN_DMP_VECTOR_SET_PROPERTY, "Set Property"},
244 {ACN_DMP_VECTOR_GET_PROPERTY_REPLY, "Get property reply"},
245 {ACN_DMP_VECTOR_EVENT, "Event"},
246 {ACN_DMP_VECTOR_MAP_PROPERTY, "Map Property"},
247 {ACN_DMP_VECTOR_UNMAP_PROPERTY, "Unmap Property"},
248 {ACN_DMP_VECTOR_SUBSCRIBE, "Subscribe"},
249 {ACN_DMP_VECTOR_UNSUBSCRIBE, "Unsubscribe"},
250 {ACN_DMP_VECTOR_GET_PROPERTY_FAIL, "Get Property Fail"},
251 {ACN_DMP_VECTOR_SET_PROPERTY_FAIL, "Set Property Fail"},
252 {ACN_DMP_VECTOR_MAP_PROPERTY_FAIL, "Map Property Fail"},
253 {ACN_DMP_VECTOR_SUBSCRIBE_ACCEPT, "Subscribe Accept"},
254 {ACN_DMP_VECTOR_SUBSCRIBE_REJECT, "Subscribe Reject"},
255 {ACN_DMP_VECTOR_ALLOCATE_MAP, "Allocate Map"},
256 {ACN_DMP_VECTOR_ALLOCATE_MAP_REPLY, "Allocate Map Reply"},
257 {ACN_DMP_VECTOR_DEALLOCATE_MAP, "Deallocate Map"},
261 static const value_string acn_ip_address_type_vals[] = {
262 { ACN_ADDR_NULL, "Null"},
263 { ACN_ADDR_IPV4, "IPv4"},
264 { ACN_ADDR_IPV6, "IPv6"},
265 { ACN_ADDR_IPPORT, "Port"},
269 static const value_string acn_refuse_code_vals[] = {
270 { ACN_REFUSE_CODE_NONSPECIFIC, "Nonspecific" },
271 { ACN_REFUSE_CODE_ILLEGAL_PARAMS, "Illegal Parameters" },
272 { ACN_REFUSE_CODE_LOW_RESOURCES, "Low Resources" },
273 { ACN_REFUSE_CODE_ALREADY_MEMBER, "Already Member" },
274 { ACN_REFUSE_CODE_BAD_ADDR_TYPE, "Bad Address Type" },
275 { ACN_REFUSE_CODE_NO_RECIP_CHAN, "No Reciprocal Channel" },
279 static const value_string acn_reason_code_vals[] = {
280 { ACN_REASON_CODE_NONSPECIFIC, "Nonspecific" },
281 { ACN_REASON_CODE_NO_RECIP_CHAN, "No Reciprocal Channel" },
282 { ACN_REASON_CODE_CHANNEL_EXPIRED, "Channel Expired" },
283 { ACN_REASON_CODE_LOST_SEQUENCE, "Lost Sequence" },
284 { ACN_REASON_CODE_SATURATED, "Saturated" },
285 { ACN_REASON_CODE_TRANS_ADDR_CHANGING, "Transport Address Changing" },
286 { ACN_REASON_CODE_ASKED_TO_LEAVE, "Asked to Leave" },
287 { ACN_REASON_CODE_NO_RECIPIENT, "No Recipient"},
291 static const value_string acn_dmp_reason_code_vals[] = {
292 { ACN_DMP_REASON_CODE_NONSPECIFIC, "Nonspecific" },
293 { ACN_DMP_REASON_CODE_NOT_A_PROPERTY, "Not a Property" },
294 { ACN_DMP_REASON_CODE_WRITE_ONLY, "Write Only" },
295 { ACN_DMP_REASON_CODE_NOT_WRITABLE, "Not Writable" },
296 { ACN_DMP_REASON_CODE_DATA_ERROR, "Data Error" },
297 { ACN_DMP_REASON_CODE_MAPS_NOT_SUPPORTED, "Maps not Supported" },
298 { ACN_DMP_REASON_CODE_SPACE_NOT_AVAILABLE, "Space not Available" },
299 { ACN_DMP_REASON_CODE_PROP_NOT_MAPABLE, "Property not Mapable"},
300 { ACN_DMP_REASON_CODE_MAP_NOT_ALLOCATED, "Map not Allocated"},
301 { ACN_DMP_REASON_CODE_SUBSCRIPTION_NOT_SUPPORTED, "Subscription not Supported"},
302 { ACN_DMP_REASON_CODE_NO_SUBSCRIPTIONS_SUPPORTED, "No Subscriptions Supported"},
306 static const enum_val_t dmx_display_view[] = {
307 { "hex" , "Hex ", ACN_PREF_DMX_DISPLAY_HEX },
308 { "decimal", "Decimal", ACN_PREF_DMX_DISPLAY_DEC },
309 { "percent", "Percent", ACN_PREF_DMX_DISPLAY_PER },
313 /******************************************************************************/
314 /* Test to see if it is an ACN Packet */
315 static gboolean is_acn(tvbuff_t *tvb)
317 static char acn_packet_id[] = "ASC-E1.17\0\0\0"; /* must be 12 bytes */
320 /* Get the fields in octets 2 - 12 octet */
321 packet_id = tvb_get_ephemeral_string(tvb, 4, 12);
322 if (memcmp(packet_id, &acn_packet_id, 12) == 0) {
329 /******************************************************************************/
330 /* Heuristic dissector */
332 dissect_acn_heur( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree )
334 /* This is a heuristic dissector, which means we get all the UDP
335 * traffic not sent to a known dissector and not claimed by
336 * a heuristic dissector called before us!
339 /* abort if not enabled! */
340 if (!global_acn_heur) return FALSE;
342 /* abort if it is NOT an ACN packet */
343 if (!is_acn(tvb)) return FALSE;
345 /* else, dissect it */
346 dissect_acn(tvb, pinfo, tree);
350 /******************************************************************************/
351 /* Adds tree branch for channel owner info block */
353 acn_add_channel_owner_info_block(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree _U_, int offset)
356 proto_tree *this_tree = NULL;
357 guint32 session_count;
360 pi = proto_tree_add_text(this_tree, tvb, offset, 8, "Channel Owner Info Block");
361 this_tree = proto_item_add_subtree(pi, ett_acn_channel_owner_info_block);
363 proto_tree_add_item(this_tree, hf_acn_member_id, tvb, offset, 2, FALSE);
365 proto_tree_add_item(this_tree, hf_acn_channel_number, tvb, offset, 2, FALSE);
367 offset += acn_add_address(tvb, pinfo, this_tree, offset, "Destination Address: ");
368 offset += acn_add_address(tvb, pinfo, this_tree, offset, "Source Address: ");
370 session_count = tvb_get_ntohs(tvb, offset);
371 for (x=0; x<session_count; x++) {
372 pi = proto_tree_add_item(this_tree, hf_acn_protocol_id, tvb, offset, 4, FALSE);
373 proto_item_append_text(pi, " #%d", x+1);
379 /******************************************************************************/
380 /* Adds tree branch for channel member info block */
382 acn_add_channel_member_info_block(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree _U_, int offset)
385 proto_tree *this_tree = NULL;
386 guint32 session_count;
389 pi = proto_tree_add_text(this_tree, tvb, offset, 8, "Channel Member Info Block");
390 this_tree = proto_item_add_subtree(pi, ett_acn_channel_member_info_block);
392 proto_tree_add_item(this_tree, hf_acn_member_id, tvb, offset, 2, FALSE);
394 proto_tree_add_item(this_tree, hf_acn_cid, tvb, offset, 16, FALSE);
396 proto_tree_add_item(this_tree, hf_acn_channel_number, tvb, offset, 2, FALSE);
398 offset += acn_add_address(tvb, pinfo, this_tree, offset, "Destination Address: ");
399 offset += acn_add_address(tvb, pinfo, this_tree, offset, "Source Address: ");
400 proto_tree_add_item(this_tree, hf_acn_reciprocal_channel, tvb, offset, 2, FALSE);
403 session_count = tvb_get_ntohs(tvb, offset);
404 for (x=0; x<session_count; x++) {
405 pi = proto_tree_add_item(this_tree, hf_acn_protocol_id, tvb, offset, 4, FALSE);
406 proto_item_append_text(pi, " #%d", x+1);
413 /******************************************************************************/
414 /* Add labled exiry */
416 acn_add_expiry(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, const char *label)
421 expiry = tvb_get_ntohs(tvb, offset);
422 pi = proto_tree_add_text(tree, tvb, offset, 2, label);
423 proto_item_append_text(pi, " %d", expiry);
429 /******************************************************************************/
430 /* Adds tree branch for channel parameters */
432 acn_add_channel_parameter(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset)
435 proto_tree *param_tree = NULL;
437 pi = proto_tree_add_text(tree, tvb, offset, 8, "Channel Parameter Block");
438 param_tree = proto_item_add_subtree(pi, ett_acn_channel_parameter);
439 proto_tree_add_item(param_tree, hf_acn_expiry, tvb, offset, 1, FALSE);
441 proto_tree_add_item(param_tree, hf_acn_nak_outbound_flag, tvb, offset, 1, FALSE);
443 proto_tree_add_item(param_tree, hf_acn_nak_holdoff, tvb, offset, 2, FALSE);
445 proto_tree_add_item(param_tree, hf_acn_nak_modulus, tvb, offset, 2, FALSE);
447 proto_tree_add_item(param_tree, hf_acn_nak_max_wait, tvb, offset, 2, FALSE);
449 return offset; /* bytes used */
453 /******************************************************************************/
454 /* Add an address tree */
456 acn_add_address(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, const char *label)
459 proto_tree *addr_tree = NULL;
460 guint8 ip_address_type;
465 struct e_in6_addr IPv6;
469 ip_address_type = tvb_get_guint8(tvb, offset);
471 switch (ip_address_type) {
475 /* Build tree and add type*/
476 pi = proto_tree_add_text(tree, tvb, offset, 7, label);
477 addr_tree = proto_item_add_subtree(pi, ett_acn_address);
478 proto_tree_add_item(addr_tree, hf_acn_ip_address_type, tvb, offset, 1, FALSE);
481 port = tvb_get_ntohs(tvb, offset);
482 proto_tree_add_item(addr_tree, hf_acn_port, tvb, offset, 2, FALSE);
485 proto_tree_add_item(addr_tree, hf_acn_ipv4, tvb, offset, 4, FALSE);
486 /* Append port and address to tree item */
487 IPv4 = tvb_get_ipv4(tvb, offset);
488 SET_ADDRESS(&addr, AT_IPv4, sizeof(IPv4), &IPv4);
489 proto_item_append_text(pi, "%s, Port %d", address_to_str(&addr), port);
493 /* Build tree and add type*/
494 pi = proto_tree_add_text(tree, tvb, offset, 19, label);
495 addr_tree = proto_item_add_subtree(pi, ett_acn_address);
496 proto_tree_add_item(addr_tree, hf_acn_ip_address_type, tvb, offset, 1, FALSE);
499 port = tvb_get_ntohs(tvb, offset);
500 proto_tree_add_item(addr_tree, hf_acn_port, tvb, offset, 2, FALSE);
503 proto_tree_add_item(addr_tree, hf_acn_ipv6, tvb, offset, 16, FALSE);
504 /* Append port and address to tree item */
505 tvb_get_ipv6(tvb, offset, &IPv6);
506 SET_ADDRESS(&addr, AT_IPv6, sizeof(struct e_in6_addr), &IPv6);
507 proto_item_append_text(pi, "%s, Port %d", address_to_str(&addr), port);
510 case ACN_ADDR_IPPORT:
511 /* Build tree and add type*/
512 pi = proto_tree_add_text(tree, tvb, offset, 3, label);
513 addr_tree = proto_item_add_subtree(pi, ett_acn_address);
514 proto_tree_add_item(addr_tree, hf_acn_ip_address_type, tvb, offset, 1, FALSE);
517 port = tvb_get_ntohs(tvb, offset);
518 proto_tree_add_item(addr_tree, hf_acn_port, tvb, offset, 2, FALSE);
519 /* Append port to tree item */
520 proto_item_append_text(pi, "%s Port %d", address_to_str(&addr), port);
527 /******************************************************************************/
528 /* Adds tree branch for address type */
530 acn_add_dmp_address_type(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, acn_dmp_adt_type *adt)
533 proto_tree *this_tree = NULL;
536 /* header contains address and data type */
537 adt->flags = tvb_get_guint8(tvb, offset);
539 D = ACN_DMP_ADT_EXTRACT_D(adt->flags);
540 pi = proto_tree_add_text(tree, tvb, offset, 1, "Address and Data Type: %s (%d)", match_strval(D, acn_dmp_adt_d_vals), D);
542 this_tree = proto_item_add_subtree(pi, ett_acn_address_type);
543 proto_tree_add_uint(this_tree, hf_acn_dmp_adt_v, tvb, offset, 1, adt->flags);
544 proto_tree_add_uint(this_tree, hf_acn_dmp_adt_r, tvb, offset, 1, adt->flags);
545 proto_tree_add_uint(this_tree, hf_acn_dmp_adt_d, tvb, offset, 1, adt->flags);
546 proto_tree_add_uint(this_tree, hf_acn_dmp_adt_x, tvb, offset, 1, adt->flags);
547 proto_tree_add_uint(this_tree, hf_acn_dmp_adt_a, tvb, offset, 1, adt->flags);
550 return offset; /* bytes used */
553 /******************************************************************************/
554 /* Add an dmp address */
556 acn_add_dmp_address(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, acn_dmp_adt_type *adt)
558 guint32 start_offset;
562 start_offset = offset;
564 D = ACN_DMP_ADT_EXTRACT_D(adt->flags);
565 A = ACN_DMP_ADT_EXTRACT_A(adt->flags);
567 case ACN_DMP_ADT_D_NS: /* Non-range address, Single data item */
570 switch (A) { /* address */
571 case ACN_DMP_ADT_A_1: /* One octet address, (range: one octet address, increment, and count). */
572 adt->address = tvb_get_guint8(tvb, offset);
576 case ACN_DMP_ADT_A_2: /* Two octet address, (range: two octet address, increment, and count). */
577 adt->address = tvb_get_ntohs(tvb, offset);
581 case ACN_DMP_ADT_A_4: /* Four octet address, (range: one octet address, increment, and count). */
582 adt->address = tvb_get_ntohl(tvb, offset);
586 default: /* and ACN_DMP_ADT_A_R (Four octet address, (range: four octet address, increment, and count)*/
588 } /* of switch (A) */
590 if (adt->flags & ACN_DMP_ADT_FLAG_V) {
591 proto_tree_add_text(tree, tvb, start_offset, bytes_used, "Virtual Address: %d", adt->address);
593 proto_tree_add_text(tree, tvb, start_offset, bytes_used, "Actual Address: %d", adt->address);
597 case ACN_DMP_ADT_D_RS: /* Range address, Single data item */
599 case ACN_DMP_ADT_A_1: /* One octet address, (range: one octet address, increment, and count). */
600 adt->address = tvb_get_guint8(tvb, offset);
602 adt->increment = tvb_get_guint8(tvb, offset);
604 adt->count = tvb_get_guint8(tvb, offset);
608 case ACN_DMP_ADT_A_2: /* Two octet address, (range: two octet address, increment, and count). */
609 adt->address = tvb_get_ntohs(tvb, offset);
611 adt->increment = tvb_get_ntohs(tvb, offset);
613 adt->count = tvb_get_ntohs(tvb, offset);
617 case ACN_DMP_ADT_A_4: /* Four octet address, (range: four octet address, increment, and count). */
618 adt->address = tvb_get_ntohl(tvb, offset);
620 adt->increment = tvb_get_ntohl(tvb, offset);
622 adt->count = tvb_get_ntohl(tvb, offset);
626 default: /* and ACN_DMP_ADT_A_R, this reserved....so it has no meaning yet */
628 } /* of switch (A) */
630 if (adt->flags & ACN_DMP_ADT_FLAG_V) {
631 proto_tree_add_text(tree, tvb, start_offset, bytes_used, "Virtual Address first: %d, inc: %d, count: %d", adt->address, adt->increment, adt->count);
633 proto_tree_add_text(tree, tvb, start_offset, bytes_used, "Actual Address first: %d, inc: %d, count: %d", adt->address, adt->increment, adt->count);
637 case ACN_DMP_ADT_D_RE: /* Range address, Array of equal size data items */
639 case ACN_DMP_ADT_A_1: /* One octet address, (range: one octet address, increment, and count). */
640 adt->address = tvb_get_guint8(tvb, offset);
642 adt->increment = tvb_get_guint8(tvb, offset);
644 adt->count = tvb_get_guint8(tvb, offset);
648 case ACN_DMP_ADT_A_2: /* Two octet address, (range: two octet address, increment, and count). */
649 adt->address = tvb_get_ntohs(tvb, offset);
651 adt->increment = tvb_get_ntohs(tvb, offset);
653 adt->count = tvb_get_ntohs(tvb, offset);
657 case ACN_DMP_ADT_A_4: /* Four octet address, (range: four octet address, increment, and count). */
658 adt->address = tvb_get_ntohl(tvb, offset);
660 adt->increment = tvb_get_ntohl(tvb, offset);
662 adt->count = tvb_get_ntohl(tvb, offset);
666 default: /* and ACN_DMP_ADT_A_R, this reserved....so it has no meaning yet */
668 } /* of switch (A) */
670 if (adt->flags & ACN_DMP_ADT_FLAG_V) {
671 proto_tree_add_text(tree, tvb, start_offset, bytes_used, "Virtual Address first: %d, inc: %d, count: %d", adt->address, adt->increment, adt->count);
673 proto_tree_add_text(tree, tvb, start_offset, bytes_used, "Actual Address first: %d, inc: %d, count: %d", adt->address, adt->increment, adt->count);
677 case ACN_DMP_ADT_D_RM: /* Range address, Series of mixed size data items */
679 case ACN_DMP_ADT_A_1: /* One octet address, (range: one octet address, increment, and count). */
680 adt->address = tvb_get_guint8(tvb, offset);
682 adt->increment = tvb_get_guint8(tvb, offset);
684 adt->count = tvb_get_guint8(tvb, offset);
688 case ACN_DMP_ADT_A_2: /* Two octet address, (range: two octet address, increment, and count). */
689 adt->address = tvb_get_ntohs(tvb, offset);
691 adt->increment = tvb_get_ntohs(tvb, offset);
693 adt->count = tvb_get_ntohs(tvb, offset);
697 case ACN_DMP_ADT_A_4: /* Four octet address, (range: four octet address, increment, and count). */
698 adt->address = tvb_get_ntohl(tvb, offset);
700 adt->increment = tvb_get_ntohl(tvb, offset);
702 adt->count = tvb_get_ntohl(tvb, offset);
706 default: /* and ACN_DMP_ADT_A_R, this reserved....so it has no meaning yet */
708 } /* of switch (A) */
710 if (adt->flags & ACN_DMP_ADT_FLAG_V) {
711 proto_tree_add_text(tree, tvb, start_offset, bytes_used, "Virtual Address first: %d, inc: %d, count: %d", adt->address, adt->increment, adt->count);
713 proto_tree_add_text(tree, tvb, start_offset, bytes_used, "Actual Address first: %d, inc: %d, count: %d", adt->address, adt->increment, adt->count);
716 } /* of switch (D) */
722 /*******************************************************************************/
723 /* Display DMP Data */
725 acn_add_dmp_data(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, acn_dmp_adt_type *adt)
728 guint32 start_offset;
731 guint32 data_address;
735 guint32 ok_to_process = FALSE;
737 start_offset = offset;
739 /* We would like to rip through Property Address-Data pairs */
740 /* but since we don't now how many there are nor how big the data size is, */
741 /* it not possible. So, we just show the whole thing as a block of date! */
743 /* There are a few exceptions however */
744 /* 1) if the address type is ACN_DMP_ADT_D_NS or ACN_DMP_ADT_D_RS and */
745 /* or ACN_DMP_ADT_D_RE */
746 /* then number of bytes is <= count + 4. Each value is at least one byte */
747 /* and another address/data pair is at least 4 bytes so if the remaining */
748 /* bytes is less than the count plus 4 then the remaining data */
749 /* must be all data */
751 /* 2) if the address type is ACN_DMP_ADT_D_RE and the number of bytes */
752 /* equals the number of bytes in remaining in the pdu then there is */
753 /* a 1 to one match */
755 D = ACN_DMP_ADT_EXTRACT_D(adt->flags);
757 case ACN_DMP_ADT_D_NS:
758 case ACN_DMP_ADT_D_RS:
759 if (adt->data_length <= adt->count + 4) {
760 ok_to_process = TRUE;
763 case ACN_DMP_ADT_D_RE:
764 if (adt->data_length == adt->count) {
765 ok_to_process = TRUE;
767 if (adt->data_length <= adt->count + 4) {
768 ok_to_process = TRUE;
773 if (!ok_to_process) {
774 data_size = adt->data_length;
775 ti = proto_tree_add_item(tree, hf_acn_data, tvb, offset, data_size, FALSE);
777 proto_item_set_text(ti, "Data and more Address-Data Pairs (further dissection not possible)");
781 /* Allocate some memory, not using ep_alloc here as there could be LOT of calls to
782 this in the same capture frame. Could use se_alloc...
784 #define BUFFER_SIZE 128
785 buffer = g_malloc(BUFFER_SIZE);
788 A = ACN_DMP_ADT_EXTRACT_A(adt->flags);
790 case ACN_DMP_ADT_D_NS: /* Non-range address, Single data item */
791 /* calculate data size */
792 data_size = adt->data_length;
793 data_address = adt->address;
796 case ACN_DMP_ADT_A_1: /* One octet address, (range: one octet address, increment, and count). */
797 g_snprintf(buffer, BUFFER_SIZE, "Addr %2.2X ->", data_address);
799 case ACN_DMP_ADT_A_2: /* Two octet address, (range: two octet address, increment, and count). */
800 g_snprintf(buffer, BUFFER_SIZE, "Addr %4.4X ->", data_address);
802 case ACN_DMP_ADT_A_4: /* Four octet address, (range: four octet address, increment, and count). */
803 g_snprintf(buffer, BUFFER_SIZE, "Addr %8.8X ->", data_address);
805 default: /* and ACN_DMP_ADT_A_R, this reserved....so it has no meaning yet */
811 data_value = tvb_get_guint8(tvb, offset);
812 proto_tree_add_int_format(tree, hf_acn_data8, tvb, offset, 1, data_value, "%s %2.2X", buffer, data_value);
815 data_value = tvb_get_ntohs(tvb, offset);
816 proto_tree_add_int_format(tree, hf_acn_data16, tvb, offset, 2, data_value, "%s %4.4X", buffer, data_value);
819 data_value = tvb_get_ntoh24(tvb, offset);
820 proto_tree_add_int_format(tree, hf_acn_data24, tvb, offset, 3, data_value, "%s %6.6X", buffer, data_value);
823 data_value = tvb_get_ntohl(tvb, offset);
824 proto_tree_add_int_format(tree, hf_acn_data32, tvb, offset, 4, data_value, "%s %8.8X", buffer, data_value);
827 /* build string of values */
828 for (y=0;y<20 && y<data_size;y++) {
829 data_value = tvb_get_guint8(tvb, offset+y);
830 g_snprintf(buffer, BUFFER_SIZE, "%s %2.2X", buffer, data_value);
833 ti = proto_tree_add_item(tree, hf_acn_data, tvb, offset, data_size, FALSE);
835 /* change the text */
836 proto_item_set_text(ti, "%s", buffer);
838 } /* of switch (data_size) */
842 case ACN_DMP_ADT_D_RS: /* Range address, Single data item */
843 /* calculate data size */
844 data_size = adt->data_length;
845 data_address = adt->address;
847 for (x=0;x<adt->count;x++) {
849 case ACN_DMP_ADT_A_1: /* One octet address, (range: one octet address, increment, and count). */
850 g_snprintf(buffer, BUFFER_SIZE, "Addr %2.2X ->", data_address);
852 case ACN_DMP_ADT_A_2: /* Two octet address, (range: two octet address, increment, and count). */
853 g_snprintf(buffer, BUFFER_SIZE, "Addr %4.4X ->", data_address);
855 case ACN_DMP_ADT_A_4: /* Four octet address, (range: four octet address, increment, and count). */
856 g_snprintf(buffer, BUFFER_SIZE, "Addr %8.8X ->", data_address);
858 default: /* and ACN_DMP_ADT_A_R, this reserved....so it has no meaning yet */
864 data_value = tvb_get_guint8(tvb, offset);
865 proto_tree_add_int_format(tree, hf_acn_data8, tvb, offset, 1, data_value, "%s %2.2X", buffer, data_value);
868 data_value = tvb_get_ntohs(tvb, offset);
869 proto_tree_add_int_format(tree, hf_acn_data8, tvb, offset, 2, data_value, "%s %4.4X", buffer, data_value);
872 data_value = tvb_get_ntoh24(tvb, offset);
873 proto_tree_add_int_format(tree, hf_acn_data8, tvb, offset, 3, data_value, "%s %6.6X", buffer, data_value);
876 data_value = tvb_get_ntohl(tvb, offset);
877 proto_tree_add_int_format(tree, hf_acn_data8, tvb, offset, 4, data_value, "%s %8.8X", buffer, data_value);
880 /* build string of values */
881 for (y=0;y<20 && y<data_size;y++) {
882 data_value = tvb_get_guint8(tvb, offset+y);
883 g_snprintf(buffer, BUFFER_SIZE, "%s %2.2X", buffer, data_value);
886 ti = proto_tree_add_item(tree, hf_acn_data, tvb, offset, data_size, FALSE);
887 /* change the text */
888 proto_item_set_text(ti, "%s", buffer);
890 } /* of switch (data_size) */
891 data_address += adt->increment;
892 } /* of (x=0;x<adt->count;x++) */
896 case ACN_DMP_ADT_D_RE: /* Range address, Array of equal size data items */
897 /* calculate data size */
898 data_size = adt->data_length / adt->count;
899 data_address = adt->address;
901 for (x=0;x<adt->count;x++) {
903 case ACN_DMP_ADT_A_1: /* One octet address, (range: one octet address, increment, and count). */
904 g_snprintf(buffer, BUFFER_SIZE, "Addr %2.2X ->", data_address);
906 case ACN_DMP_ADT_A_2: /* Two octet address, (range: two octet address, increment, and count). */
907 g_snprintf(buffer, BUFFER_SIZE, "Addr %4.4X ->", data_address);
909 case ACN_DMP_ADT_A_4: /* Four octet address, (range: four octet address, increment, and count). */
910 g_snprintf(buffer, BUFFER_SIZE, "Addr %8.8X ->", data_address);
912 default: /* and ACN_DMP_ADT_A_R, this reserved....so it has no meaning yet */
918 data_value = tvb_get_guint8(tvb, offset);
919 proto_tree_add_int_format(tree, hf_acn_data8, tvb, offset, 1, data_value, "%s %2.2X", buffer, data_value);
922 data_value = tvb_get_ntohs(tvb, offset);
923 proto_tree_add_int_format(tree, hf_acn_data8, tvb, offset, 2, data_value, "%s %4.4X", buffer, data_value);
926 data_value = tvb_get_ntoh24(tvb, offset);
927 proto_tree_add_int_format(tree, hf_acn_data8, tvb, offset, 3, data_value, "%s %6.6X", buffer, data_value);
930 data_value = tvb_get_ntohl(tvb, offset);
931 proto_tree_add_int_format(tree, hf_acn_data8, tvb, offset, 4, data_value, "%s %8.8X", buffer, data_value);
934 /* build string of values */
935 for (y=0;y<20 && y<data_size;y++) {
936 data_value = tvb_get_guint8(tvb, offset+y);
937 g_snprintf(buffer, BUFFER_SIZE, "%s %2.2X", buffer, data_value);
940 ti = proto_tree_add_item(tree, hf_acn_data, tvb, offset, data_size, FALSE);
941 /* change the text */
942 proto_item_set_text(ti, "%s", buffer);
944 } /* of switch (data_size) */
947 data_address += adt->increment;
948 } /* of (x=0;x<adt->count;x++) */
951 case ACN_DMP_ADT_D_RM: /* Range address, Series of mixed size data items */
952 data_size = adt->data_length;
953 ti = proto_tree_add_item(tree, hf_acn_data, tvb, offset, data_size, FALSE);
955 /* change the text */
956 proto_item_set_text(ti, "Mixed size data items");
958 } /* of switch (D) */
959 /* free our memory! */
965 /*******************************************************************************/
966 /* Display DMP Reason codes */
968 acn_add_dmp_reason_codes(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, acn_dmp_adt_type *adt)
971 guint32 start_offset;
973 guint32 data_address;
979 start_offset = offset;
981 /* Allocate some memory, not using ep_alloc here as there could be LOT of calls to
982 this in the same capture frame. Could use se_alloc...
984 #define BUFFER_SIZE 128
985 buffer = g_malloc(BUFFER_SIZE);
989 D = ACN_DMP_ADT_EXTRACT_D(adt->flags);
990 A = ACN_DMP_ADT_EXTRACT_A(adt->flags);
992 case ACN_DMP_ADT_D_NS: /* Non-range address, Single data item */
993 data_address = adt->address;
995 case ACN_DMP_ADT_A_1: /* One octet address, (range: one octet address, increment, and count). */
996 g_snprintf(buffer, BUFFER_SIZE, "Addr %2.2X ->", data_address);
998 case ACN_DMP_ADT_A_2: /* Two octet address, (range: two octet address, increment, and count). */
999 g_snprintf(buffer, BUFFER_SIZE, "Addr %4.4X ->", data_address);
1001 case ACN_DMP_ADT_A_4: /* Four octet address, (range: four octet address, increment, and count). */
1002 g_snprintf(buffer, BUFFER_SIZE, "Addr %8.8X ->", data_address);
1004 default: /* and ACN_DMP_ADT_A_R, this reserved....so it has no meaning yet */
1009 data_value = tvb_get_guint8(tvb, offset);
1010 /* convert to string */
1011 ptr = match_strval(data_value, acn_dmp_reason_code_vals);
1013 proto_tree_add_int_format(tree, hf_acn_data8, tvb, offset, 1, data_value, "%s %s", buffer, ptr);
1017 case ACN_DMP_ADT_D_RS: /* Range address, Single data item */
1018 data_address = adt->address;
1019 for (x=0;x<adt->count;x++) {
1021 case ACN_DMP_ADT_A_1: /* One octet address, (range: one octet address, increment, and count). */
1022 g_snprintf(buffer, BUFFER_SIZE, "Addr %2.2X ->", data_address);
1024 case ACN_DMP_ADT_A_2: /* Two octet address, (range: two octet address, increment, and count). */
1025 g_snprintf(buffer, BUFFER_SIZE, "Addr %4.4X ->", data_address);
1027 case ACN_DMP_ADT_A_4: /* Four octet address, (range: four octet address, increment, and count). */
1028 g_snprintf(buffer, BUFFER_SIZE, "Addr %8.8X ->", data_address);
1030 default: /* and ACN_DMP_ADT_A_R, this reserved....so it has no meaning yet */
1035 data_value = tvb_get_guint8(tvb, offset);
1036 /* convert to string */
1037 ptr = match_strval(data_value, acn_dmp_reason_code_vals);
1039 proto_tree_add_int_format(tree, hf_acn_data8, tvb, offset, 1, data_value, "%s %s", buffer, ptr);
1040 data_address += adt->increment;
1041 } /* of (x=0;x<adt->count;x++) */
1045 case ACN_DMP_ADT_D_RE: /* Range address, Array of equal size data items */
1046 case ACN_DMP_ADT_D_RM: /* Range address, Series of mixed size data items */
1047 data_address = adt->address;
1048 for (x=0;x<adt->count;x++) {
1050 case ACN_DMP_ADT_A_1: /* One octet address, (range: one octet address, increment, and count). */
1051 g_snprintf(buffer, BUFFER_SIZE, "Addr %2.2X ->", data_address);
1053 case ACN_DMP_ADT_A_2: /* Two octet address, (range: two octet address, increment, and count). */
1054 g_snprintf(buffer, BUFFER_SIZE, "Addr %4.4X ->", data_address);
1056 case ACN_DMP_ADT_A_4: /* Four octet address, (range: four octet address, increment, and count). */
1057 g_snprintf(buffer, BUFFER_SIZE, "Addr %8.8X ->", data_address);
1059 default: /* and ACN_DMP_ADT_A_R, this reserved....so it has no meaning yet */
1063 data_value = tvb_get_guint8(tvb, offset);
1064 /* convert to string */
1065 ptr = match_strval(data_value, acn_dmp_reason_code_vals);
1067 proto_tree_add_int_format(tree, hf_acn_data8, tvb, offset, 1, data_value, "%s %s", buffer, ptr);
1068 data_address += adt->increment;
1070 } /* of (x=0;x<adt->count;x++) */
1072 } /* of switch (D) */
1073 /* free our memory! */
1079 /******************************************************************************/
1080 /* Dissect wrapped SDT PDU */
1082 dissect_acn_dmp_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, acn_pdu_offsets *last_pdu_offsets)
1084 /* common to all pdu */
1088 guint32 pdu_flvh_length; /* flags, length, vector, header */
1089 acn_pdu_offsets pdu_offsets = {0,0,0,0,0};
1095 guint32 vector_offset;
1096 guint32 header_offset;
1097 guint32 data_offset;
1100 guint32 data_length;
1101 guint32 address_count;
1103 proto_item *ti, *pi;
1104 proto_tree *pdu_tree = NULL;
1105 proto_tree *flag_tree = NULL;
1109 acn_dmp_adt_type adt = {0,0,0,0,0,0};
1110 acn_dmp_adt_type adt2 = {0,0,0,0,0,0};
1113 /* save start of pdu block */
1115 pdu_offsets.start = pdu_start;
1117 /* get PDU flags and length flag first */
1118 octet = tvb_get_guint8(tvb, offset++);
1119 pdu_flags = octet & 0xf0;
1120 length1 = octet & 0x0f; /* bottom 4 bits only */
1121 length2 = tvb_get_guint8(tvb, offset++);
1123 /* if length flag is set, then we have a 20 bit length else we have a 12 bit */
1124 /* flvh = flags, length, vector, header */
1125 if (pdu_flags & ACN_PDU_FLAG_L) {
1126 length3 = tvb_get_guint8(tvb, offset);
1128 pdu_length = length3 | (length2 << 8) | (length1 << 16);
1129 pdu_flvh_length = 3;
1131 pdu_length = length2 | (length1 << 8);
1132 pdu_flvh_length = 2;
1134 /* offset should now be pointing to vector (if one exists) */
1136 /* Add pdu item and tree */
1137 ti = proto_tree_add_item(tree, hf_acn_pdu, tvb, pdu_start, pdu_length, FALSE);
1138 pdu_tree = proto_item_add_subtree(ti, ett_acn_dmp_pdu);
1140 /* Add flag item and tree */
1141 pi = proto_tree_add_uint(pdu_tree, hf_acn_pdu_flags, tvb, pdu_start, 1, pdu_flags);
1142 flag_tree = proto_item_add_subtree(pi, ett_acn_pdu_flags);
1143 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_l, tvb, pdu_start, 1, FALSE);
1144 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_v, tvb, pdu_start, 1, FALSE);
1145 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_h, tvb, pdu_start, 1, FALSE);
1146 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_d, tvb, pdu_start, 1, FALSE);
1148 /* Add PDU Length item */
1149 proto_tree_add_uint(pdu_tree, hf_acn_pdu_length, tvb, pdu_start, pdu_flvh_length, pdu_length);
1151 /* Set vector offset */
1152 if (pdu_flags & ACN_PDU_FLAG_V) {
1153 /* use new values */
1154 vector_offset = offset;
1155 last_pdu_offsets->vector = offset;
1159 /* use last values */
1160 vector_offset = last_pdu_offsets->vector;
1162 /* offset should now be pointing to header (if one exists) */
1164 /* Add Vector item */
1165 vector = tvb_get_guint8(tvb, vector_offset);
1166 proto_tree_add_uint(pdu_tree, hf_acn_dmp_vector, tvb, vector_offset, 1, vector);
1168 /* Add Vector item to tree*/
1169 ptr = match_strval(vector, acn_dmp_vector_vals);
1170 proto_item_append_text(ti, ": ");
1171 proto_item_append_text(ti, ptr);
1173 /* Set header offset */
1174 if (pdu_flags & ACN_PDU_FLAG_H) {
1175 /* use new values */
1176 header_offset = offset;
1177 last_pdu_offsets->header = offset;
1181 /* use last values */
1182 header_offset = last_pdu_offsets->header;
1184 /* offset should now be pointing to data (if one exists) */
1186 /* header contains address and data type */
1187 acn_add_dmp_address_type(tvb, pinfo, pdu_tree, header_offset, &adt);
1190 if (pdu_flags & ACN_PDU_FLAG_D) {
1191 /* use new values */
1192 data_offset = offset;
1193 data_length = pdu_length - pdu_flvh_length;
1194 last_pdu_offsets->data = offset;
1195 last_pdu_offsets->data_length = data_length;
1197 /* use last values */
1198 data_offset = last_pdu_offsets->data;
1199 data_length = last_pdu_offsets->data_length;
1201 end_offset = data_offset + data_length;
1204 case ACN_DMP_VECTOR_UNKNOWN:
1206 case ACN_DMP_VECTOR_GET_PROPERTY:
1207 /* Rip trough property address */
1208 while (data_offset < end_offset) {
1209 old_offset = data_offset;
1210 data_offset = acn_add_dmp_address(tvb, pinfo, pdu_tree, data_offset, &adt);
1211 if (old_offset == data_offset) break;
1214 case ACN_DMP_VECTOR_SET_PROPERTY:
1215 /* Rip through Property Address-Data pairs */
1216 /* But, in reality, this generally won't work as we have know way of */
1217 /* calculating the next Address-Data pair */
1218 while (data_offset < end_offset) {
1219 old_offset = data_offset;
1220 data_offset = acn_add_dmp_address(tvb, pinfo, pdu_tree, data_offset, &adt);
1221 if (old_offset == data_offset) break;
1223 adt.data_length = data_length - (data_offset - old_offset);
1224 old_offset = data_offset;
1225 data_offset = acn_add_dmp_data(tvb, pinfo, pdu_tree, data_offset, &adt);
1226 if (old_offset == data_offset) break;
1229 case ACN_DMP_VECTOR_GET_PROPERTY_REPLY:
1230 /* Rip through Property Address-Data pairs */
1231 /* But, in reality, this generally won't work as we have know way of */
1232 /* calculating the next Address-Data pair */
1233 while (data_offset < end_offset) {
1234 old_offset = data_offset;
1235 data_offset = acn_add_dmp_address(tvb, pinfo, pdu_tree, data_offset, &adt);
1236 if (old_offset == data_offset) break;
1239 adt.data_length = data_length - (data_offset - old_offset);
1240 old_offset = data_offset;
1241 data_offset = acn_add_dmp_data(tvb, pinfo, pdu_tree, data_offset, &adt);
1242 if (old_offset == data_offset) break;
1245 case ACN_DMP_VECTOR_EVENT:
1246 /* Rip through Property Address-Data pairs */
1247 /* But, in reality, this generally won't work as we have know way of */
1248 /* calculating the next Address-Data pair */
1249 while (data_offset < end_offset) {
1250 old_offset = data_offset;
1251 data_offset = acn_add_dmp_address(tvb, pinfo, pdu_tree, data_offset, &adt);
1252 if (old_offset == data_offset) break;
1254 adt.data_length = data_length - (data_offset - old_offset);
1255 old_offset = data_offset;
1256 data_offset = acn_add_dmp_data(tvb, pinfo, pdu_tree, data_offset, &adt);
1257 if (old_offset == data_offset) break;
1260 case ACN_DMP_VECTOR_MAP_PROPERTY:
1261 /* Virtual Address type */
1262 data_offset = acn_add_dmp_address_type(tvb, pinfo, pdu_tree, data_offset, &adt2);
1263 /* Rip through Actual-Virtual Address Pairs */
1264 while (data_offset < end_offset) {
1266 old_offset = data_offset;
1267 data_offset = acn_add_dmp_address(tvb, pinfo, pdu_tree, data_offset, &adt);
1268 if (old_offset == data_offset) break;
1269 D = ACN_DMP_ADT_EXTRACT_D(adt.flags);
1271 case ACN_DMP_ADT_D_NS:
1274 case ACN_DMP_ADT_D_RS:
1277 case ACN_DMP_ADT_D_RE:
1278 address_count = adt.count;
1280 /*case ACN_DMP_ADT_D_RM: */
1283 return pdu_start + pdu_length;
1288 while (address_count > 0) {
1289 data_offset = acn_add_dmp_address(tvb, pinfo, pdu_tree, data_offset, &adt2);
1294 case ACN_DMP_VECTOR_UNMAP_PROPERTY:
1295 /* Rip trough Actaul 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_SUBSCRIBE:
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_UNSUBSCRIBE:
1311 /* Rip trough Proptery Address */
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;
1318 case ACN_DMP_VECTOR_GET_PROPERTY_FAIL:
1319 /* Rip trough Address-Reason Code Pairs */
1320 while (data_offset < end_offset) {
1321 old_offset = data_offset;
1322 data_offset = acn_add_dmp_address(tvb, pinfo, pdu_tree, data_offset, &adt);
1323 if (old_offset == data_offset) break;
1325 adt.data_length = data_length - (data_offset - old_offset);
1326 old_offset = data_offset;
1327 data_offset = acn_add_dmp_reason_codes(tvb, pinfo, pdu_tree, data_offset, &adt);
1328 if (old_offset == data_offset) break;
1331 case ACN_DMP_VECTOR_SET_PROPERTY_FAIL:
1332 /* Rip trough Address-Reason Code Pairs */
1333 while (data_offset < end_offset) {
1334 old_offset = data_offset;
1335 data_offset = acn_add_dmp_address(tvb, pinfo, pdu_tree, data_offset, &adt);
1336 if (old_offset == data_offset) break;
1338 adt.data_length = data_length - (data_offset - old_offset);
1339 old_offset = data_offset;
1340 data_offset = acn_add_dmp_reason_codes(tvb, pinfo, pdu_tree, data_offset, &adt);
1341 if (old_offset == data_offset) break;
1344 case ACN_DMP_VECTOR_MAP_PROPERTY_FAIL:
1345 /* Rip trough Address-Reason Code Pairs */
1346 while (data_offset < end_offset) {
1347 old_offset = data_offset;
1348 data_offset = acn_add_dmp_address(tvb, pinfo, pdu_tree, data_offset, &adt);
1349 if (old_offset == data_offset) break;
1351 adt.data_length = data_length - (data_offset - old_offset);
1352 old_offset = data_offset;
1353 data_offset = acn_add_dmp_reason_codes(tvb, pinfo, pdu_tree, data_offset, &adt);
1354 if (old_offset == data_offset) break;
1357 case ACN_DMP_VECTOR_SUBSCRIBE_ACCEPT:
1358 /* Rip through Property Addrsses */
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;
1365 case ACN_DMP_VECTOR_SUBSCRIBE_REJECT:
1366 /* Rip trough Address-Reason Code Pairs */
1367 while (data_offset < end_offset) {
1368 old_offset = data_offset;
1369 data_offset = acn_add_dmp_address(tvb, pinfo, pdu_tree, data_offset, &adt);
1370 if (old_offset == data_offset) break;
1372 adt.data_length = data_length - (data_offset - old_offset);
1373 old_offset = data_offset;
1374 data_offset = acn_add_dmp_reason_codes(tvb, pinfo, pdu_tree, data_offset, &adt);
1375 if (old_offset == data_offset) break;
1378 case ACN_DMP_VECTOR_ALLOCATE_MAP:
1379 /* No data for this */
1381 case ACN_DMP_VECTOR_ALLOCATE_MAP_REPLY:
1382 /* Single reason code */
1383 proto_tree_add_item(pdu_tree, hf_acn_dmp_reason_code, tvb, data_offset, 1, FALSE);
1385 case ACN_DMP_VECTOR_DEALLOCATE_MAP:
1386 /* No data for this */
1390 return pdu_start + pdu_length;
1394 /******************************************************************************/
1395 /* Dissect wrapped SDT PDU */
1397 dissect_acn_sdt_wrapped_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree _U_, int offset, acn_pdu_offsets *last_pdu_offsets)
1399 /* common to all pdu */
1403 guint32 pdu_flvh_length; /* flags, length, vector, header */
1404 acn_pdu_offsets pdu_offsets = {0,0,0,0,0};
1409 guint32 vector_offset;
1410 guint32 data_offset;
1412 guint32 data_length;
1414 proto_item *ti, *pi;
1415 proto_tree *pdu_tree = NULL;
1416 proto_tree *flag_tree = NULL;
1422 /* save start of pdu block */
1424 pdu_offsets.start = pdu_start;
1426 /* get PDU flags and length flag first */
1427 octet = tvb_get_guint8(tvb, offset++);
1428 pdu_flags = octet & 0xf0;
1429 length1 = octet & 0x0f; /* bottom 4 bits only */
1430 length2 = tvb_get_guint8(tvb, offset++);
1432 /* if length flag is set, then we have a 20 bit length else we have a 12 bit */
1433 /* flvh = flags, length, vector, header */
1434 if (pdu_flags & ACN_PDU_FLAG_L) {
1435 length3 = tvb_get_guint8(tvb, offset);
1437 pdu_length = length3 | (length2 << 8) | (length1 << 16);
1438 pdu_flvh_length = 3;
1440 pdu_length = length2 | (length1 << 8);
1441 pdu_flvh_length = 2;
1443 /* offset should now be pointing to vector (if one exists) */
1445 /* Add pdu item and tree */
1446 ti = proto_tree_add_item(tree, hf_acn_pdu, tvb, pdu_start, pdu_length, FALSE);
1447 pdu_tree = proto_item_add_subtree(ti, ett_acn_sdt_pdu);
1449 /* Add flag item and tree */
1450 pi = proto_tree_add_uint(pdu_tree, hf_acn_pdu_flags, tvb, pdu_start, 1, pdu_flags);
1451 flag_tree = proto_item_add_subtree(pi, ett_acn_pdu_flags);
1452 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_l, tvb, pdu_start, 1, FALSE);
1453 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_v, tvb, pdu_start, 1, FALSE);
1454 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_h, tvb, pdu_start, 1, FALSE);
1455 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_d, tvb, pdu_start, 1, FALSE);
1457 /* Add PDU Length item */
1458 proto_tree_add_uint(pdu_tree, hf_acn_pdu_length, tvb, pdu_start, pdu_flvh_length, pdu_length);
1460 /* Set vector offset */
1461 if (pdu_flags & ACN_PDU_FLAG_V) {
1462 /* use new values */
1463 vector_offset = offset;
1464 last_pdu_offsets->vector = offset;
1468 /* use last values */
1469 vector_offset = last_pdu_offsets->vector;
1471 /* offset should now be pointing to header (if one exists) */
1473 /* Add Vector item */
1474 vector = tvb_get_guint8(tvb, vector_offset);
1475 proto_tree_add_uint(pdu_tree, hf_acn_sdt_vector, tvb, vector_offset, 1, vector);
1477 /* Add Vector item to tree*/
1478 ptr = match_strval(vector, acn_sdt_vector_vals);
1479 proto_item_append_text(ti, ": ");
1480 proto_item_append_text(ti, ptr);
1482 /* NO HEADER DATA ON THESE* (at least so far) */
1485 if (pdu_flags & ACN_PDU_FLAG_D) {
1486 /* use new values */
1487 data_offset = offset;
1488 data_length = pdu_length - pdu_flvh_length;
1489 last_pdu_offsets->data = offset;
1490 last_pdu_offsets->data_length = data_length;
1492 /* use last values */
1493 data_offset = last_pdu_offsets->data;
1494 data_length = last_pdu_offsets->data_length;
1496 end_offset = data_offset + data_length;
1499 case ACN_SDT_VECTOR_ACK:
1500 proto_tree_add_item(pdu_tree, hf_acn_reliable_sequence_number, tvb, data_offset, 4, FALSE);
1503 case ACN_SDT_VECTOR_CHANNEL_PARAMS:
1504 data_offset = acn_add_channel_parameter(tvb, pinfo, pdu_tree, data_offset);
1505 data_offset = acn_add_address(tvb, pinfo, pdu_tree, data_offset, "Ad-hoc Address: ");
1506 data_offset = acn_add_expiry(tvb, pinfo, pdu_tree, data_offset, "Ad-hoc Expiry: ");
1508 case ACN_SDT_VECTOR_LEAVE:
1511 case ACN_SDT_VECTOR_CONNECT:
1512 /* Protocol ID item */
1513 proto_tree_add_item(pdu_tree, hf_acn_protocol_id, tvb, data_offset, 4, FALSE);
1516 case ACN_SDT_VECTOR_CONNECT_ACCEPT:
1517 /* Protocol ID item */
1518 proto_tree_add_item(pdu_tree, hf_acn_protocol_id, tvb, data_offset, 4, FALSE);
1521 case ACN_SDT_VECTOR_CONNECT_REFUSE:
1522 /* Protocol ID item */
1523 proto_tree_add_item(pdu_tree, hf_acn_protocol_id, tvb, data_offset, 4, FALSE);
1525 proto_tree_add_item(pdu_tree, hf_acn_refuse_code, tvb, data_offset, 1, FALSE);
1528 case ACN_SDT_VECTOR_DISCONNECT:
1529 /* Protocol ID item */
1530 proto_tree_add_item(pdu_tree, hf_acn_protocol_id, tvb, data_offset, 4, FALSE);
1533 case ACN_SDT_VECTOR_DISCONNECTING:
1534 /* Protocol ID item */
1535 proto_tree_add_item(pdu_tree, hf_acn_protocol_id, tvb, data_offset, 4, FALSE);
1537 proto_tree_add_item(pdu_tree, hf_acn_reason_code, tvb, data_offset, 1, FALSE);
1543 return pdu_start + pdu_length;
1547 /******************************************************************************/
1548 /* Dissect SDT Client PDU */
1550 dissect_acn_sdt_client_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, acn_pdu_offsets *last_pdu_offsets)
1552 /* common to all pdu */
1556 guint32 pdu_flvh_length; /* flags, length, vector, header */
1557 acn_pdu_offsets pdu_offsets = {0,0,0,0,0};
1562 guint32 vector_offset;
1563 guint32 header_offset;
1564 guint32 data_offset;
1565 guint32 data_length;
1569 proto_item *ti, *pi;
1570 proto_tree *pdu_tree = NULL;
1571 proto_tree *flag_tree = NULL;
1576 guint32 protocol_id;
1577 guint16 association;
1579 /* save start of pdu block */
1581 pdu_offsets.start = pdu_start;
1583 /* get PDU flags and length flag first */
1584 octet = tvb_get_guint8(tvb, offset++);
1585 pdu_flags = octet & 0xf0;
1586 length1 = octet & 0x0f; /* bottom 4 bits only */
1587 length2 = tvb_get_guint8(tvb, offset++);
1589 /* if length flag is set, then we have a 20 bit length else we have a 12 bit */
1590 /* flvh = flags, length, vector, header */
1591 if (pdu_flags & ACN_PDU_FLAG_L) {
1592 length3 = tvb_get_guint8(tvb, offset);
1594 pdu_length = length3 | (length2 << 8) | (length1 << 16);
1595 pdu_flvh_length = 3;
1597 pdu_length = length2 | (length1 << 8);
1598 pdu_flvh_length = 2;
1600 /* offset should now be pointing to vector (if one exists) */
1602 /* Add pdu item and tree */
1603 ti = proto_tree_add_item(tree, hf_acn_pdu, tvb, pdu_start, pdu_length, FALSE);
1604 pdu_tree = proto_item_add_subtree(ti, ett_acn_sdt_client_pdu);
1606 /* Add flag item and tree */
1607 pi = proto_tree_add_uint(pdu_tree, hf_acn_pdu_flags, tvb, pdu_start, 1, pdu_flags);
1608 flag_tree = proto_item_add_subtree(pi, ett_acn_pdu_flags);
1609 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_l, tvb, pdu_start, 1, FALSE);
1610 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_v, tvb, pdu_start, 1, FALSE);
1611 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_h, tvb, pdu_start, 1, FALSE);
1612 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_d, tvb, pdu_start, 1, FALSE);
1614 /* Add PDU Length item */
1615 proto_tree_add_uint(pdu_tree, hf_acn_pdu_length, tvb, pdu_start, pdu_flvh_length, pdu_length);
1617 /* Set vector offset */
1618 if (pdu_flags & ACN_PDU_FLAG_V) {
1619 /* use new values */
1620 vector_offset = offset;
1621 last_pdu_offsets->vector = offset;
1623 pdu_flvh_length += 2;
1625 /* use last values */
1626 vector_offset = last_pdu_offsets->vector;
1628 /* offset should now be pointing to header (if one exists) */
1630 /* add Member ID item */
1631 member_id = tvb_get_ntohs(tvb, vector_offset);
1632 proto_tree_add_uint(pdu_tree, hf_acn_member_id, tvb, vector_offset, 2, member_id);
1634 /* Set header offset */
1635 if (pdu_flags & ACN_PDU_FLAG_H) {
1636 /* use new values */
1637 header_offset = offset;
1638 last_pdu_offsets->header = offset;
1640 pdu_flvh_length += 6;
1642 /* use last values */
1643 header_offset = last_pdu_offsets->header;
1645 /* offset should now be pointing to data (if one exists) */
1647 /* add Protocol ID item (Header)*/
1648 protocol_id = tvb_get_ntohl(tvb, header_offset);
1649 proto_tree_add_uint(pdu_tree, hf_acn_protocol_id, tvb, header_offset, 4, protocol_id);
1652 /* Add protocol to tree*/
1653 ptr = match_strval(protocol_id, acn_protocol_id_vals);
1654 proto_item_append_text(ti, ": ");
1655 proto_item_append_text(ti, ptr);
1657 /* add association item */
1658 association = tvb_get_ntohs(tvb, header_offset);
1659 proto_tree_add_uint(pdu_tree, hf_acn_association, tvb, header_offset, 2, association);
1663 if (pdu_flags & ACN_PDU_FLAG_D) {
1664 /* use new values */
1665 data_offset = offset;
1666 data_length = pdu_length - pdu_flvh_length;
1667 last_pdu_offsets->data = offset;
1668 last_pdu_offsets->data_length = data_length;
1670 /* use last values */
1671 data_offset = last_pdu_offsets->data;
1672 data_length = last_pdu_offsets->data_length;
1674 end_offset = data_offset + data_length;
1676 switch (protocol_id) {
1677 case ACN_PROTOCOL_ID_SDT:
1678 while (data_offset < end_offset) {
1679 old_offset = data_offset;
1680 data_offset = dissect_acn_sdt_wrapped_pdu(tvb, pinfo, pdu_tree, data_offset, &pdu_offsets);
1681 if (old_offset == data_offset) break;
1684 case ACN_PROTOCOL_ID_DMP:
1685 while (data_offset < end_offset) {
1686 old_offset = data_offset;
1687 data_offset = dissect_acn_dmp_pdu(tvb, pinfo, pdu_tree, data_offset, &pdu_offsets);
1688 if (data_offset == old_offset) break;
1692 return pdu_start + pdu_length;
1696 /******************************************************************************/
1697 /* reverses the characters in a string */
1703 for (i=0, j=strlen(s)-1; i < j; i++, j--) {
1711 /******************************************************************************/
1712 /* level to string (ascii) */
1713 /* level : 8 bit value */
1714 /* string : pointer to buffer to fill */
1715 /* leading_char: character to buffer left of digits */
1716 /* min_char : mininum number of characters (for filling, not including space)*/
1717 /* show_zero: show zeros or dots */
1718 /* also adds a space to right end */
1720 /* returns end of string */
1721 /* faster than printf() */
1723 ltos(guint8 level, gchar *string, guint8 base, gchar leading_char, guint8 min_chars, gboolean show_zero)
1727 if (base < 2 || base > 16) {
1731 /* deal with zeros */
1732 if ((level == 0) && (!show_zero)) {
1733 for (i=0;i<min_chars;i++) {
1742 /* do our convert, comes out backwords! */
1744 string[i++] = "0123456789ABCDEF"[level % base];
1745 } while ((level /= base) > 0);
1747 /* expand to needed character */
1748 for (;i<min_chars;i++) {
1749 string[i] = leading_char;
1754 /* now reverse (and correct) the order */
1757 /* add a space at the end (ok its at the start but it will be at the end)*/
1764 /******************************************************************************/
1765 /* Dissect DMX data PDU */
1767 dissect_acn_dmx_data_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, acn_pdu_offsets *last_pdu_offsets)
1769 /* common to all pdu */
1773 guint32 pdu_flvh_length; /* flags, length, vector, header */
1774 acn_pdu_offsets pdu_offsets = {0,0,0,0,0};
1779 guint32 vector_offset;
1780 guint32 data_offset;
1783 guint32 data_length;
1784 guint32 header_offset;
1789 proto_item *ti, *pi;
1790 proto_tree *pdu_tree = NULL;
1791 proto_tree *flag_tree = NULL;
1792 /* proto_tree *addr_tree = NULL; */
1795 acn_dmp_adt_type adt = {0,0,0,0,0,0};
1807 /* save start of pdu block */
1809 pdu_offsets.start = pdu_start;
1811 /* get PDU flags and length flag first */
1812 octet = tvb_get_guint8(tvb, offset++);
1813 pdu_flags = octet & 0xf0;
1814 length1 = octet & 0x0f; /* bottom 4 bits only */
1815 length2 = tvb_get_guint8(tvb, offset++);
1817 /* if length flag is set, then we have a 20 bit length else we have a 12 bit */
1818 /* flvh = flags, length, vector, header */
1819 if (pdu_flags & ACN_PDU_FLAG_L) {
1820 length3 = tvb_get_guint8(tvb, offset);
1822 pdu_length = length3 | (length2 << 8) | (length1 << 16);
1823 pdu_flvh_length = 3;
1825 pdu_length = length2 | (length1 << 8);
1826 pdu_flvh_length = 2;
1828 /* offset should now be pointing to vector (if one exists) */
1830 /* Add pdu item and tree */
1831 ti = proto_tree_add_item(tree, hf_acn_pdu, tvb, pdu_start, pdu_length, FALSE);
1832 pdu_tree = proto_item_add_subtree(ti, ett_acn_dmx_data_pdu);
1834 /* Add flag item and tree */
1835 pi = proto_tree_add_uint(pdu_tree, hf_acn_pdu_flags, tvb, pdu_start, 1, pdu_flags);
1836 flag_tree = proto_item_add_subtree(pi, ett_acn_pdu_flags);
1837 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_l, tvb, pdu_start, 1, FALSE);
1838 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_v, tvb, pdu_start, 1, FALSE);
1839 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_h, tvb, pdu_start, 1, FALSE);
1840 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_d, tvb, pdu_start, 1, FALSE);
1842 /* Add PDU Length item */
1843 proto_tree_add_uint(pdu_tree, hf_acn_pdu_length, tvb, pdu_start, pdu_flvh_length, pdu_length);
1845 /* Set vector offset */
1846 if (pdu_flags & ACN_PDU_FLAG_V) {
1847 /* use new values */
1848 vector_offset = offset;
1849 last_pdu_offsets->vector = offset;
1851 pdu_flvh_length += 1;
1853 /* use last values */
1854 vector_offset = last_pdu_offsets->vector;
1856 /* offset should now be pointing to header (if one exists) */
1858 /* Add Vector item */
1859 vector = tvb_get_guint8(tvb, vector_offset);
1860 proto_tree_add_uint(pdu_tree, hf_acn_dmp_vector, tvb, vector_offset, 1, vector);
1862 /* Add Vector item to tree*/
1863 ptr = match_strval(vector, acn_dmp_vector_vals);
1864 proto_item_append_text(ti, ": ");
1865 proto_item_append_text(ti, ptr);
1867 /* Set header offset */
1868 if (pdu_flags & ACN_PDU_FLAG_H) {
1869 /* use new values */
1870 header_offset = offset;
1871 last_pdu_offsets->header = offset;
1875 /* use last values */
1876 header_offset = last_pdu_offsets->header;
1878 /* offset should now be pointing to data (if one exists) */
1880 /* process based on vector */
1881 acn_add_dmp_address_type(tvb, pinfo, pdu_tree, header_offset, &adt);
1884 if (pdu_flags & ACN_PDU_FLAG_D) {
1885 /* use new values */
1886 data_offset = offset;
1887 data_length = pdu_length - pdu_flvh_length;
1888 last_pdu_offsets->data = offset;
1889 last_pdu_offsets->data_length = data_length;
1891 /* use last values */
1892 data_offset = last_pdu_offsets->data;
1893 data_length = last_pdu_offsets->data_length;
1895 end_offset = data_offset + data_length;
1898 case ACN_DMP_VECTOR_SET_PROPERTY:
1899 old_offset = data_offset;
1900 data_offset = acn_add_dmp_address(tvb, pinfo, pdu_tree, data_offset, &adt);
1901 if (data_offset == old_offset) break;
1903 #define BUFFER_SIZE 128
1905 buffer = ep_alloc(BUFFER_SIZE);
1909 /* values base on display mode */
1910 switch ((guint)global_acn_dmx_display_view) {
1911 case ACN_PREF_DMX_DISPLAY_HEX:
1915 /* case ACN_PREF_DMX_DISPLAY_PER: */
1921 /* do we display leading zeros */
1922 if (global_acn_dmx_display_leading_zeros) {
1928 /* add a header line */
1929 memset(buffer, ' ', 10);
1931 for (x=1;x<=20;x++) {
1932 buf_ptr = ltos((guint8)x, buf_ptr, 10, ' ', min_char, FALSE);
1939 proto_tree_add_text(pdu_tree, tvb, data_offset, 0, buffer);
1941 /* start our line */
1942 g_snprintf(buffer, BUFFER_SIZE, "001-020: ");
1943 buf_ptr = buffer + 9;
1947 for (x=data_offset; x < end_offset; x++) {
1948 level = tvb_get_guint8(tvb, x);
1949 if (global_acn_dmx_display_view==ACN_PREF_DMX_DISPLAY_PER) {
1950 if ((level > 0) && (level < 3)) {
1953 level = level * 100 / 255;
1956 buf_ptr = ltos(level, buf_ptr, base, leading_char, min_char, global_acn_dmx_display_zeros);
1960 if (item_cnt == 20 || x == (end_offset-1)) {
1962 proto_tree_add_text(pdu_tree, tvb, data_offset, item_cnt, buffer);
1964 g_snprintf(buffer, BUFFER_SIZE, "%03d-%03d: ",total_cnt, total_cnt+20);
1965 buf_ptr = buffer + 9;
1968 /* add separater character */
1969 if (item_cnt == 10) {
1977 address data type (fixed at 0xA2)
1978 start code - 1 byte, reserved (should be 0)
1979 - 1 byte, start code (0x255)
1980 - 2 bytes, packet offset (should be 0000)
1981 address increment - 4 bytes (ignore)
1982 number of dmx values - 4 bytes (0-512)
1983 dmx values 0-512 bytes (data)
1988 return pdu_start + pdu_length;
1993 /******************************************************************************/
1994 /* Dissect DMX Base PDU */
1996 dissect_acn_dmx_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, acn_pdu_offsets *last_pdu_offsets)
1998 /* common to all pdu */
2002 guint32 pdu_flvh_length; /* flags, length, vector, header */
2003 acn_pdu_offsets pdu_offsets = {0,0,0,0,0};
2008 guint32 vector_offset;
2009 guint32 data_offset;
2011 guint32 data_length;
2013 proto_item *ti, *pi;
2014 proto_tree *pdu_tree = NULL;
2015 proto_tree *flag_tree = NULL;
2023 /* save start of pdu block */
2025 pdu_offsets.start = pdu_start;
2027 /* get PDU flags and length flag first */
2028 octet = tvb_get_guint8(tvb, offset++);
2029 pdu_flags = octet & 0xf0;
2030 length1 = octet & 0x0f; /* bottom 4 bits only */
2031 length2 = tvb_get_guint8(tvb, offset++);
2033 /* if length flag is set, then we have a 20 bit length else we have a 12 bit */
2034 /* flvh = flags, length, vector, header */
2035 if (pdu_flags & ACN_PDU_FLAG_L) {
2036 length3 = tvb_get_guint8(tvb, offset);
2038 pdu_length = length3 | (length2 << 8) | (length1 << 16);
2039 pdu_flvh_length = 3;
2041 pdu_length = length2 | (length1 << 8);
2042 pdu_flvh_length = 2;
2045 /* offset should now be pointing to vector (if one exists) */
2047 /* Add pdu item and tree */
2048 ti = proto_tree_add_item(tree, hf_acn_pdu, tvb, pdu_start, pdu_length, FALSE);
2049 pdu_tree = proto_item_add_subtree(ti, ett_acn_dmx_pdu);
2051 /* Add flag item and tree */
2052 pi = proto_tree_add_uint(pdu_tree, hf_acn_pdu_flags, tvb, pdu_start, 1, pdu_flags);
2053 flag_tree = proto_item_add_subtree(pi, ett_acn_pdu_flags);
2054 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_l, tvb, pdu_start, 1, FALSE);
2055 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_v, tvb, pdu_start, 1, FALSE);
2056 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_h, tvb, pdu_start, 1, FALSE);
2057 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_d, tvb, pdu_start, 1, FALSE);
2059 /* Add PDU Length item */
2060 proto_tree_add_uint(pdu_tree, hf_acn_pdu_length, tvb, pdu_start, pdu_flvh_length, pdu_length);
2062 /* Set vector offset */
2063 if (pdu_flags & ACN_PDU_FLAG_V) {
2064 /* use new values */
2065 vector_offset = offset;
2066 last_pdu_offsets->vector = offset;
2068 pdu_flvh_length += 4;
2070 /* use last values */
2071 vector_offset = last_pdu_offsets->vector;
2073 /* offset should now be pointing to header (if one exists) */
2075 /* Add Vector item */
2076 vector = tvb_get_ntohl(tvb, vector_offset);
2077 proto_tree_add_item(pdu_tree, hf_acn_dmx_vector, tvb, vector_offset, 4, FALSE);
2078 /* vector_offset +=4; */
2080 /* Add Vector item to tree*/
2081 proto_item_append_text(ti, ": %s", match_strval(vector, acn_dmx_vector_vals));
2083 /* NO HEADER DATA ON THESE* (at least so far) */
2086 if (pdu_flags & ACN_PDU_FLAG_D) {
2087 /* use new values */
2088 data_offset = offset;
2089 data_length = pdu_length - pdu_flvh_length;
2090 last_pdu_offsets->data = offset;
2091 last_pdu_offsets->data_length = data_length;
2093 /* use last values */
2094 data_offset = last_pdu_offsets->data;
2095 data_length = last_pdu_offsets->data_length;
2097 end_offset = data_offset + data_length;
2099 /* process based on vector */
2102 proto_tree_add_item(pdu_tree, hf_acn_dmx_source_name, tvb, data_offset, 32, FALSE);
2105 priority = tvb_get_guint8(tvb, data_offset);
2106 proto_tree_add_item(pdu_tree, hf_acn_dmx_priority, tvb, data_offset, 1, FALSE);
2109 proto_tree_add_item(pdu_tree, hf_acn_dmx_sequence_number, tvb, data_offset, 1, FALSE);
2112 universe = tvb_get_ntohs(tvb, data_offset);
2113 proto_tree_add_item(pdu_tree, hf_acn_dmx_universe , tvb, data_offset, 2, FALSE);
2116 proto_item_append_text(ti, ", Universe: %d, Priority: %d", universe, priority);
2118 data_offset = dissect_acn_dmx_data_pdu(tvb, pinfo, pdu_tree, data_offset, &pdu_offsets);
2122 return pdu_start + pdu_length;
2125 /******************************************************************************/
2126 /* Dissect SDT Base PDU */
2128 dissect_acn_sdt_base_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, acn_pdu_offsets *last_pdu_offsets)
2130 /* common to all pdu */
2134 guint32 pdu_flvh_length; /* flags, length, vector, header */
2135 acn_pdu_offsets pdu_offsets = {0,0,0,0,0};
2140 guint32 vector_offset;
2141 guint32 data_offset;
2144 guint32 data_length;
2146 proto_item *ti, *pi;
2147 proto_tree *pdu_tree = NULL;
2148 proto_tree *flag_tree = NULL;
2155 /* save start of pdu block */
2157 pdu_offsets.start = pdu_start;
2159 /* get PDU flags and length flag first */
2160 octet = tvb_get_guint8(tvb, offset++);
2161 pdu_flags = octet & 0xf0;
2162 length1 = octet & 0x0f; /* bottom 4 bits only */
2163 length2 = tvb_get_guint8(tvb, offset++);
2165 /* if length flag is set, then we have a 20 bit length else we have a 12 bit */
2166 /* flvh = flags, length, vector, header */
2167 if (pdu_flags & ACN_PDU_FLAG_L) {
2168 length3 = tvb_get_guint8(tvb, offset);
2170 pdu_length = length3 | (length2 << 8) | (length1 << 16);
2171 pdu_flvh_length = 3;
2173 pdu_length = length2 | (length1 << 8);
2174 pdu_flvh_length = 2;
2176 /* offset should now be pointing to vector (if one exists) */
2178 /* Add pdu item and tree */
2179 ti = proto_tree_add_item(tree, hf_acn_pdu, tvb, pdu_start, pdu_length, FALSE);
2180 pdu_tree = proto_item_add_subtree(ti, ett_acn_sdt_base_pdu);
2182 /* Add flag item and tree */
2183 pi = proto_tree_add_uint(pdu_tree, hf_acn_pdu_flags, tvb, pdu_start, 1, pdu_flags);
2184 flag_tree = proto_item_add_subtree(pi, ett_acn_pdu_flags);
2185 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_l, tvb, pdu_start, 1, FALSE);
2186 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_v, tvb, pdu_start, 1, FALSE);
2187 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_h, tvb, pdu_start, 1, FALSE);
2188 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_d, tvb, pdu_start, 1, FALSE);
2190 /* Add PDU Length item */
2191 proto_tree_add_uint(pdu_tree, hf_acn_pdu_length, tvb, pdu_start, pdu_flvh_length, pdu_length);
2193 /* Set vector offset */
2194 if (pdu_flags & ACN_PDU_FLAG_V) {
2195 /* use new values */
2196 vector_offset = offset;
2197 last_pdu_offsets->vector = offset;
2201 /* use last values */
2202 vector_offset = last_pdu_offsets->vector;
2204 /* offset should now be pointing to header (if one exists) */
2206 /* Add Vector item */
2207 vector = tvb_get_guint8(tvb, vector_offset);
2208 proto_tree_add_uint(pdu_tree, hf_acn_sdt_vector, tvb, vector_offset, 1, vector);
2210 /* Add Vector item to tree*/
2211 ptr = match_strval(vector, acn_sdt_vector_vals);
2212 proto_item_append_text(ti, ": ");
2213 proto_item_append_text(ti, ptr);
2215 /* NO HEADER DATA ON THESE* (at least so far) */
2218 if (pdu_flags & ACN_PDU_FLAG_D) {
2219 /* use new values */
2220 data_offset = offset;
2221 data_length = pdu_length - pdu_flvh_length;
2222 last_pdu_offsets->data = offset;
2223 last_pdu_offsets->data_length = data_length;
2225 /* use last values */
2226 data_offset = last_pdu_offsets->data;
2227 data_length = last_pdu_offsets->data_length;
2229 end_offset = data_offset + data_length;
2231 /* process based on vector */
2233 case ACN_SDT_VECTOR_UNKNOWN:
2235 case ACN_SDT_VECTOR_REL_WRAP:
2236 case ACN_SDT_VECTOR_UNREL_WRAP:
2237 proto_tree_add_item(pdu_tree, hf_acn_channel_number, tvb, data_offset, 2, FALSE);
2239 proto_tree_add_item(pdu_tree, hf_acn_total_sequence_number, tvb, data_offset, 4, FALSE);
2241 proto_tree_add_item(pdu_tree, hf_acn_reliable_sequence_number, tvb, data_offset, 4, FALSE);
2243 proto_tree_add_item(pdu_tree, hf_acn_oldest_available_wrapper, tvb, data_offset, 4, FALSE);
2245 proto_tree_add_item(pdu_tree, hf_acn_first_memeber_to_ack, tvb, data_offset, 2, FALSE);
2247 proto_tree_add_item(pdu_tree, hf_acn_last_memeber_to_ack, tvb, data_offset, 2, FALSE);
2249 proto_tree_add_item(pdu_tree, hf_acn_mak_threshold, tvb, data_offset, 2, FALSE);
2252 while (data_offset < end_offset) {
2253 old_offset = data_offset;
2254 data_offset = dissect_acn_sdt_client_pdu(tvb, pinfo, pdu_tree, data_offset, &pdu_offsets);
2255 if (data_offset == old_offset) break;
2258 case ACN_SDT_VECTOR_CHANNEL_PARAMS:
2260 case ACN_SDT_VECTOR_JOIN:
2261 proto_tree_add_item(pdu_tree, hf_acn_cid, tvb, data_offset, 16, FALSE);
2263 proto_tree_add_item(pdu_tree, hf_acn_member_id, tvb, data_offset, 2, FALSE);
2265 proto_tree_add_item(pdu_tree, hf_acn_channel_number, tvb, data_offset, 2, FALSE);
2267 proto_tree_add_item(pdu_tree, hf_acn_reciprocal_channel, tvb, data_offset, 2, FALSE);
2269 proto_tree_add_item(pdu_tree, hf_acn_total_sequence_number, tvb, data_offset, 4, FALSE);
2271 proto_tree_add_item(pdu_tree, hf_acn_reliable_sequence_number, tvb, data_offset, 4, FALSE);
2273 data_offset = acn_add_address(tvb, pinfo, pdu_tree, data_offset, "Destination Address: ");
2274 data_offset = acn_add_channel_parameter(tvb, pinfo, pdu_tree, data_offset);
2275 data_offset = acn_add_expiry(tvb, pinfo, pdu_tree, data_offset, "Ad-hoc Expiry: ");
2277 case ACN_SDT_VECTOR_JOIN_REFUSE:
2278 pi = proto_tree_add_item(pdu_tree, hf_acn_cid, tvb, data_offset, 16, FALSE);
2280 proto_item_append_text(pi, "(Leader)");
2281 proto_tree_add_item(pdu_tree, hf_acn_channel_number, tvb, data_offset, 2, FALSE);
2283 proto_tree_add_item(pdu_tree, hf_acn_member_id, tvb, data_offset, 2, FALSE);
2285 proto_tree_add_item(pdu_tree, hf_acn_reliable_sequence_number, tvb, data_offset, 4, FALSE);
2287 proto_tree_add_item(pdu_tree, hf_acn_refuse_code, tvb, data_offset, 1, FALSE);
2290 case ACN_SDT_VECTOR_JOIN_ACCEPT:
2291 pi = proto_tree_add_item(pdu_tree, hf_acn_cid, tvb, data_offset, 16, FALSE);
2293 proto_item_append_text(pi, "(Leader)");
2294 proto_tree_add_item(pdu_tree, hf_acn_channel_number, tvb, data_offset, 2, FALSE);
2296 proto_tree_add_item(pdu_tree, hf_acn_member_id, tvb, data_offset, 2, FALSE);
2298 proto_tree_add_item(pdu_tree, hf_acn_reliable_sequence_number, tvb, data_offset, 4, FALSE);
2300 proto_tree_add_item(pdu_tree, hf_acn_reciprocal_channel, tvb, data_offset, 2, FALSE);
2303 case ACN_SDT_VECTOR_LEAVE:
2305 case ACN_SDT_VECTOR_LEAVING:
2306 pi = proto_tree_add_item(pdu_tree, hf_acn_cid, tvb, data_offset, 16, FALSE);
2308 proto_item_append_text(pi, "(Leader)");
2309 proto_tree_add_item(pdu_tree, hf_acn_channel_number, tvb, data_offset, 2, FALSE);
2311 proto_tree_add_item(pdu_tree, hf_acn_member_id, tvb, data_offset, 2, FALSE);
2313 proto_tree_add_item(pdu_tree, hf_acn_reliable_sequence_number, tvb, data_offset, 4, FALSE);
2315 proto_tree_add_item(pdu_tree, hf_acn_reason_code, tvb, data_offset, 1, FALSE);
2318 case ACN_SDT_VECTOR_CONNECT:
2320 case ACN_SDT_VECTOR_CONNECT_ACCEPT:
2322 case ACN_SDT_VECTOR_CONNECT_REFUSE:
2324 case ACN_SDT_VECTOR_DISCONNECT:
2326 case ACN_SDT_VECTOR_DISCONNECTING:
2328 case ACN_SDT_VECTOR_ACK:
2330 case ACN_SDT_VECTOR_NAK:
2331 pi = proto_tree_add_item(pdu_tree, hf_acn_cid, tvb, data_offset, 16, FALSE);
2333 proto_item_append_text(pi, "(Leader)");
2334 proto_tree_add_item(pdu_tree, hf_acn_channel_number, tvb, data_offset, 2, FALSE);
2336 proto_tree_add_item(pdu_tree, hf_acn_member_id, tvb, data_offset, 2, FALSE);
2338 proto_tree_add_item(pdu_tree, hf_acn_reliable_sequence_number, tvb, data_offset, 4, FALSE);
2340 proto_tree_add_item(pdu_tree, hf_acn_first_missed_sequence, tvb, data_offset, 4, FALSE);
2342 proto_tree_add_item(pdu_tree, hf_acn_last_missed_sequence, tvb, data_offset, 4, FALSE);
2345 case ACN_SDT_VECTOR_GET_SESSION:
2346 proto_tree_add_item(pdu_tree, hf_acn_cid, tvb, data_offset, 16, FALSE);
2349 case ACN_SDT_VECTOR_SESSIONS:
2350 member_id = tvb_get_ntohs(tvb, data_offset);
2351 switch (member_id) {
2353 data_offset = acn_add_channel_owner_info_block(tvb, pinfo, pdu_tree, data_offset);
2356 data_offset = acn_add_channel_member_info_block(tvb, pinfo, pdu_tree, data_offset);
2362 return pdu_start + pdu_length;
2365 /******************************************************************************/
2366 /* Dissect Root PDU */
2368 dissect_acn_root_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, acn_pdu_offsets *last_pdu_offsets)
2370 /* common to all pdu */
2374 guint32 pdu_flvh_length; /* flags, length, vector, header */
2375 acn_pdu_offsets pdu_offsets = {0,0,0,0,0};
2380 guint32 vector_offset;
2381 guint32 header_offset;
2382 guint32 data_offset;
2385 guint32 data_length;
2387 proto_item *ti, *pi;
2388 proto_tree *pdu_tree = NULL;
2389 proto_tree *flag_tree = NULL;
2392 guint32 protocol_id;
2394 gchar buf[GUID_STR_LEN];
2396 /* save start of pdu block */
2398 pdu_offsets.start = pdu_start;
2400 /* get PDU flags and length flag first */
2401 octet = tvb_get_guint8(tvb, offset++);
2402 pdu_flags = octet & 0xf0;
2403 length1 = octet & 0x0f; /* bottom 4 bits only */
2404 length2 = tvb_get_guint8(tvb, offset++);
2406 /* if length flag is set, then we have a 20 bit length else we have a 12 bit */
2407 /* flvh = flags, length, vector, header */
2408 if (pdu_flags & ACN_PDU_FLAG_L) {
2409 length3 = tvb_get_guint8(tvb, offset);
2411 pdu_length = length3 | (length2 << 8) | (length1 << 16);
2412 pdu_flvh_length = 3;
2414 pdu_length = length2 | (length1 << 8);
2415 pdu_flvh_length = 2;
2417 /* offset should now be pointing to vector (if one exists) */
2419 /* Add pdu item and tree */
2420 ti = proto_tree_add_item(tree, hf_acn_pdu, tvb, pdu_start, pdu_length, FALSE);
2421 pdu_tree = proto_item_add_subtree(ti, ett_acn_root_pdu);
2423 /* Add flag item and tree */
2424 pi = proto_tree_add_uint(pdu_tree, hf_acn_pdu_flags, tvb, pdu_start, 1, pdu_flags);
2425 flag_tree = proto_item_add_subtree(pi, ett_acn_pdu_flags);
2426 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_l, tvb, pdu_start, 1, FALSE);
2427 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_v, tvb, pdu_start, 1, FALSE);
2428 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_h, tvb, pdu_start, 1, FALSE);
2429 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_d, tvb, pdu_start, 1, FALSE);
2431 /* Add PDU Length item */
2432 proto_tree_add_uint(pdu_tree, hf_acn_pdu_length, tvb, pdu_start, pdu_flvh_length, pdu_length);
2434 /* Set vector offset */
2435 if (pdu_flags & ACN_PDU_FLAG_V) {
2436 /* use new values */
2437 vector_offset = offset;
2438 last_pdu_offsets->vector = offset;
2440 pdu_flvh_length += 4;
2442 /* use last values */
2443 vector_offset = last_pdu_offsets->vector;
2445 /* offset should now be pointing to header (if one exists) */
2449 /* Get Protocol ID (vector) */
2450 protocol_id = tvb_get_ntohl(tvb, vector_offset);
2451 proto_tree_add_uint(pdu_tree, hf_acn_protocol_id, tvb, vector_offset, 4, protocol_id);
2453 /* process based on protocol_id */
2454 switch (protocol_id) {
2455 case ACN_PROTOCOL_ID_DMX:
2456 if (global_acn_dmx_enable) {
2457 proto_item_append_text(ti,": Root DMX");
2459 /* Set header offset */
2460 if (pdu_flags & ACN_PDU_FLAG_H) {
2461 /* use new values */
2462 header_offset = offset;
2463 last_pdu_offsets->header = offset;
2465 pdu_flvh_length += 16;
2467 /* use last values */
2468 header_offset = last_pdu_offsets->header;
2470 /* offset should now be pointing to data (if one exists) */
2472 /* get Header (CID) 16 bytes */
2473 tvb_get_guid(tvb, header_offset, &guid, FALSE);
2474 guid_to_str_buf(&guid, buf, sizeof(buf));
2475 proto_item_append_text(ti, ", Src: %s", buf);
2476 proto_tree_add_item(pdu_tree, hf_acn_cid, tvb, header_offset, 16, FALSE);
2477 header_offset += 16;
2480 if (pdu_flags & ACN_PDU_FLAG_D) {
2481 /* use new values */
2482 data_offset = offset;
2483 data_length = pdu_length - pdu_flvh_length;
2484 last_pdu_offsets->data = offset;
2485 last_pdu_offsets->data_length = data_length;
2487 /* use last values */
2488 data_offset = last_pdu_offsets->data;
2489 data_length = last_pdu_offsets->data_length;
2491 end_offset = data_offset + data_length;
2493 /* adjust for what we used */
2494 while (data_offset < end_offset) {
2495 old_offset = data_offset;
2496 data_offset = dissect_acn_dmx_pdu(tvb, pinfo, pdu_tree, data_offset, &pdu_offsets);
2497 if (data_offset == old_offset) break;
2501 case ACN_PROTOCOL_ID_SDT:
2503 proto_item_append_text(ti,": Root SDT");
2505 /* Set header offset */
2506 if (pdu_flags & ACN_PDU_FLAG_H) {
2507 /* use new values */
2508 header_offset = offset;
2509 last_pdu_offsets->header = offset;
2511 pdu_flvh_length += 16;
2513 /* use last values */
2514 header_offset = last_pdu_offsets->header;
2516 /* offset should now be pointing to data (if one exists) */
2518 /* get Header (CID) 16 bytes */
2519 tvb_get_guid(tvb, header_offset, &guid, FALSE);
2520 guid_to_str_buf(&guid, buf, sizeof(buf));
2521 proto_item_append_text(ti, ", Src: %s", buf);
2522 proto_tree_add_item(pdu_tree, hf_acn_cid, tvb, header_offset, 16, FALSE);
2523 header_offset += 16;
2526 if (pdu_flags & ACN_PDU_FLAG_D) {
2527 /* use new values */
2528 data_offset = offset;
2529 data_length = pdu_length - pdu_flvh_length;
2530 last_pdu_offsets->data = offset;
2531 last_pdu_offsets->data_length = data_length;
2533 /* use last values */
2534 data_offset = last_pdu_offsets->data;
2535 data_length = last_pdu_offsets->data_length;
2537 end_offset = data_offset + data_length;
2539 /* adjust for what we used */
2540 while (data_offset < end_offset) {
2541 old_offset = data_offset;
2542 data_offset = dissect_acn_sdt_base_pdu(tvb, pinfo, pdu_tree, data_offset, &pdu_offsets);
2543 if (data_offset == old_offset) break;
2548 return pdu_start + pdu_length;
2551 /******************************************************************************/
2554 dissect_acn(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
2556 proto_item *ti = NULL;
2557 proto_tree *acn_tree = NULL;
2558 guint32 data_offset = 0;
2561 acn_pdu_offsets pdu_offsets = {0,0,0,0,0};
2563 /* if (!is_acn(tvb)) { */
2567 /* Set the protocol column */
2568 if (check_col(pinfo->cinfo, COL_PROTOCOL)) {
2569 col_set_str(pinfo->cinfo, COL_PROTOCOL, "ACN");
2572 /* Clear out stuff in the info column */
2573 if(check_col(pinfo->cinfo,COL_INFO)){
2574 /* col_clear(pinfo->cinfo,COL_INFO); */
2575 col_add_fstr(pinfo->cinfo,COL_INFO, "ACN [Src Port: %d, Dst Port: %d]", pinfo->srcport, pinfo->destport );
2578 if (tree) { /* we are being asked for details */
2579 ti = proto_tree_add_item(tree, proto_acn, tvb, 0, -1, FALSE);
2580 acn_tree = proto_item_add_subtree(ti, ett_acn);
2582 pdu_offsets.start = data_offset;
2584 /* add preamble, postamble and ACN Packet ID */
2585 proto_tree_add_item(acn_tree, hf_acn_preamble_size, tvb, data_offset, 2, FALSE);
2587 proto_tree_add_item(acn_tree, hf_acn_postamble_size, tvb, data_offset, 2, FALSE);
2589 proto_tree_add_item(acn_tree, hf_acn_packet_identifier, tvb, data_offset, 12, FALSE);
2592 /* one past the last byte */
2593 end_offset = data_offset + tvb_reported_length_remaining(tvb, data_offset);
2594 while (data_offset < end_offset) {
2595 old_offset = data_offset;
2596 data_offset = dissect_acn_root_pdu(tvb, pinfo, acn_tree, data_offset, &pdu_offsets);
2597 if (data_offset == old_offset) break;
2600 return tvb_length(tvb);
2603 /******************************************************************************/
2604 /* Register protocol */
2605 void proto_register_acn(void)
2607 static hf_register_info hf[] = {
2608 /**************************************************************************/
2609 /* In alphabetical order */
2612 { &hf_acn_ip_address_type,
2613 { "Type", "acn.ip_address_type",
2614 FT_UINT8, BASE_DEC, VALS(acn_ip_address_type_vals), 0x0,
2618 { &hf_acn_association,
2619 { "Association", "acn.association",
2620 FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
2621 "Association", HFILL }
2623 /* Channel Number */
2624 { &hf_acn_channel_number,
2625 { "Channel Number", "acn.channel_number",
2626 FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
2627 "Channel Number", HFILL }
2632 FT_GUID, BASE_NONE, NULL, 0x0,
2635 /* Client Protocol ID */
2636 { &hf_acn_client_protocol_id,
2637 { "Client Protocol ID", "acn.client_protocol_id",
2638 FT_UINT32, BASE_DEC, VALS(acn_protocol_id_vals), 0x0,
2639 "ClientProtocol ID", HFILL }
2643 { "Data", "acn.dmp_data",
2644 FT_BYTES, BASE_HEX, NULL, 0x0,
2648 { "Addr", "acn.dmp_data8",
2649 FT_INT8, BASE_DEC_HEX, NULL, 0x0,
2653 { "Addr", "acn.dmp_data16",
2654 FT_INT16, BASE_DEC_HEX, NULL, 0x0,
2658 { "Addr", "acn.dmp_data24",
2659 FT_INT24, BASE_DEC_HEX, NULL, 0x0,
2663 { "Addr", "acn.dmp_data32",
2664 FT_INT32, BASE_DEC_HEX, NULL, 0x0,
2668 { &hf_acn_dmp_address_data_pairs,
2669 { "Address-Data Pairs", "acn.dmp_address_data_pairs",
2670 FT_BYTES, BASE_DEC, NULL, 0x0,
2671 "More address-data pairs", HFILL }
2675 { &hf_acn_dmp_address1,
2676 { "Address", "acn.dmp_address",
2677 FT_UINT8, BASE_DEC_HEX, NULL, 0x0,
2680 { &hf_acn_dmp_address2,
2681 { "Address", "acn.dmp_address",
2682 FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
2685 { &hf_acn_dmp_address4,
2686 { "Address", "acn.dmp_address",
2687 FT_UINT32, BASE_DEC_HEX, NULL, 0x0,
2691 /* DMP Address type*/
2693 { "Address and Data Type", "acn.dmp_adt",
2694 FT_UINT8, BASE_DEC_HEX, NULL, 0x0,
2695 "Address and Data Type", HFILL }
2697 { &hf_acn_dmp_adt_a,
2698 { "Size", "acn.dmp_adt_a",
2699 FT_UINT8, BASE_DEC, VALS(acn_dmp_adt_a_vals), 0x03,
2702 { &hf_acn_dmp_adt_d,
2703 { "Data Type", "acn.dmp_adt_d",
2704 FT_UINT8, BASE_DEC, VALS(acn_dmp_adt_d_vals), 0x30,
2705 "Data Type", HFILL }
2707 { &hf_acn_dmp_adt_r,
2708 { "Relative", "acn.dmp_adt_r",
2709 FT_UINT8, BASE_DEC, VALS(acn_dmp_adt_r_vals), 0x40,
2712 { &hf_acn_dmp_adt_v,
2713 { "Virtual", "acn.dmp_adt_v",
2714 FT_UINT8, BASE_DEC, VALS(acn_dmp_adt_v_vals), 0x80,
2717 { &hf_acn_dmp_adt_x,
2718 { "Reserved", "acn.dmp_adt_x",
2719 FT_UINT8, BASE_DEC, NULL, 0x0c,
2723 /* DMP Reason Code */
2724 { &hf_acn_dmp_reason_code,
2725 { "Reason Code", "acn.dmp_reason_code",
2726 FT_UINT8, BASE_DEC, VALS(acn_dmp_reason_code_vals), 0x0,
2727 "Reason Code", HFILL }
2731 { &hf_acn_dmp_vector,
2732 { "DMP Vector", "acn.dmp_vector",
2733 FT_UINT8, BASE_DEC, VALS(acn_dmp_vector_vals), 0x0,
2734 "DMP Vector", HFILL }
2738 { "Expiry", "acn.expiry",
2739 FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
2742 /* First Member to ACK */
2743 { &hf_acn_first_memeber_to_ack,
2744 { "First Member to ACK", "acn.first_member_to_ack",
2745 FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
2746 "First Member to ACK", HFILL }
2748 /* First Missed Sequence */
2749 { &hf_acn_first_missed_sequence,
2750 { "First Missed Sequence", "acn.first_missed_sequence",
2751 FT_UINT32, BASE_DEC_HEX, NULL, 0x0,
2752 "First Missed Sequence", HFILL }
2756 { "IPV4", "acn.ipv4",
2757 FT_IPv4, BASE_NONE, NULL, 0x0,
2762 { "IPV6", "acn.ipv6",
2763 FT_IPv6, BASE_NONE, NULL, 0x0,
2766 /* Last Member to ACK */
2767 { &hf_acn_last_memeber_to_ack,
2768 { "Last Member to ACK", "acn.last_member_to_ack",
2769 FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
2770 "Last Member to ACK", HFILL }
2772 /* Last Missed Sequence */
2773 { &hf_acn_last_missed_sequence,
2774 { "Last Missed Sequence", "acn.last_missed_sequence",
2775 FT_UINT32, BASE_DEC_HEX, NULL, 0x0,
2776 "Last Missed Sequence", HFILL }
2779 { &hf_acn_mak_threshold,
2780 { "MAK Threshold", "acn.mak_threshold",
2781 FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
2782 "MAK Threshold", HFILL }
2785 { &hf_acn_member_id,
2786 { "Member ID", "acn.member_id",
2787 FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
2788 "Member ID", HFILL }
2791 { &hf_acn_nak_holdoff,
2792 { "NAK holdoff (ms)", "acn.nak_holdoff",
2793 FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
2794 "NAK holdoff", HFILL }
2797 { &hf_acn_nak_max_wait,
2798 { "NAK Max Wait (ms)", "acn.nak_max_wait",
2799 FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
2800 "NAK Max Wait", HFILL }
2803 { &hf_acn_nak_modulus,
2804 { "NAK Modulus", "acn.nak_modulus",
2805 FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
2806 "NAK Modulus", HFILL }
2808 /* NAK Outbound Flag */
2809 { &hf_acn_nak_outbound_flag,
2810 { "NAK Outbound Flag", "acn.nak_outbound_flag",
2811 FT_BOOLEAN, 8, NULL, 0x80,
2812 "NAK Outbound Flag", HFILL }
2814 /* Oldest Available Wrapper */
2815 { &hf_acn_oldest_available_wrapper,
2816 { "Oldest Available Wrapper", "acn.oldest_available_wrapper",
2817 FT_UINT32, BASE_DEC_HEX, NULL, 0x0,
2818 "Oldest Available Wrapper", HFILL }
2820 /* Preamble Sizet */
2821 { &hf_acn_preamble_size,
2822 { "Size of preamble", "acn.preamble_size",
2823 FT_UINT16, BASE_DEC, NULL, 0x0,
2824 "Preamble size in bytes", HFILL }
2826 /* Packet Identifier */
2827 { &hf_acn_packet_identifier,
2828 { "Packet Identifier", "acn.packet_identifier",
2829 FT_STRING, BASE_NONE, NULL, 0x0,
2830 "Packet Identififer", HFILL }
2835 FT_NONE, BASE_NONE, NULL, 0x0,
2839 { &hf_acn_pdu_flags,
2840 { "Flags", "acn.pdu.flags",
2841 FT_UINT8, BASE_HEX, NULL, 0x0,
2842 "PDU Flags", HFILL }
2844 { &hf_acn_pdu_flag_d,
2845 { "Data", "acn.pdu.flag_d",
2846 FT_BOOLEAN, 8, NULL, ACN_PDU_FLAG_D,
2847 "Data flag", HFILL }
2849 { &hf_acn_pdu_flag_h,
2850 { "Header", "acn.pdu.flag_h",
2851 FT_BOOLEAN, 8, NULL, ACN_PDU_FLAG_H,
2852 "Header flag", HFILL }
2854 { &hf_acn_pdu_flag_l,
2855 { "Length", "acn.pdu.flag_l",
2856 FT_BOOLEAN, 8, NULL, ACN_PDU_FLAG_L,
2857 "Length flag", HFILL }
2859 { &hf_acn_pdu_flag_v,
2860 { "Vector", "acn.pdu.flag_v",
2861 FT_BOOLEAN, 8, NULL, ACN_PDU_FLAG_V,
2862 "Vector flag", HFILL }
2865 { &hf_acn_pdu_length,
2866 { "Length", "acn.pdu.flag_d",
2867 FT_UINT32, BASE_DEC, NULL, 0x0,
2868 "PDU Length", HFILL }
2872 { "Port", "acn.port",
2873 FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
2876 /* Postamble Size */
2877 { &hf_acn_postamble_size,
2878 { "Size of postamble", "acn.postamble_size",
2879 FT_UINT16, BASE_DEC, NULL, 0x0,
2880 "Postamble size in bytes", HFILL }
2883 { &hf_acn_protocol_id,
2884 { "Protocol ID", "acn.protocol_id",
2885 FT_UINT32, BASE_DEC, VALS(acn_protocol_id_vals), 0x0,
2886 "Protocol ID", HFILL }
2889 { &hf_acn_reason_code,
2890 { "Reason Code", "acn.reason_code",
2891 FT_UINT8, BASE_DEC, VALS(acn_reason_code_vals), 0x0,
2892 "Reason Code", HFILL }
2894 /* Reciprocal Channel */
2895 { &hf_acn_reciprocal_channel,
2896 { "Reciprocal Sequence Number", "acn.acn_reciprocal_channel",
2897 FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
2898 "Reciprocal Channel", HFILL }
2901 { &hf_acn_refuse_code,
2902 { "Refuse Code", "acn.acn_refuse_code",
2903 FT_UINT8, BASE_DEC, VALS(acn_refuse_code_vals), 0x0,
2904 "Refuse Code", HFILL }
2906 /* Reliable Sequence Number */
2907 { &hf_acn_reliable_sequence_number,
2908 { "Reliable Sequence Number", "acn.reliable_sequence_number",
2909 FT_UINT32, BASE_DEC_HEX, NULL, 0x0,
2910 "Reliable Sequence Number", HFILL }
2913 { &hf_acn_sdt_vector,
2914 { "STD Vector", "acn.sdt_vector",
2915 FT_UINT8, BASE_DEC, VALS(acn_sdt_vector_vals), 0x0,
2916 "STD Vector", HFILL }
2920 { &hf_acn_dmx_vector,
2921 { "Vector", "acn.dmx_vector",
2922 FT_UINT32, BASE_DEC, VALS(acn_dmx_vector_vals), 0x0,
2923 "DMX Vector", HFILL }
2925 /* DMX Source Name */
2926 { &hf_acn_dmx_source_name,
2927 { "Source", "acn.dmx.source_name",
2928 FT_STRING, BASE_NONE, NULL, 0x0,
2929 "DMX Source Name", HFILL }
2933 { &hf_acn_dmx_priority,
2934 { "Priority", "acn.dmx.priority",
2935 FT_UINT8, BASE_DEC, NULL, 0x0,
2936 "DMX Priority", HFILL }
2938 /* DMX Sequence number */
2939 { &hf_acn_dmx_sequence_number,
2940 { "Seq No", "acn.dmx.seq_number",
2941 FT_UINT8, BASE_DEC, NULL, 0x0,
2942 "DMX Sequence Number", HFILL }
2945 { &hf_acn_dmx_universe,
2946 { "Universe", "acn.dmx.universe",
2947 FT_UINT16, BASE_DEC, NULL, 0x0,
2948 "DMX Universe", HFILL }
2951 { &hf_acn_session_count,
2952 { "Session Count", "acn.session_count",
2953 FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
2954 "Session Count", HFILL }
2956 /* Total Sequence Number */
2957 { &hf_acn_total_sequence_number,
2958 { "Total Sequence Number", "acn.total_sequence_number",
2959 FT_UINT32, BASE_DEC_HEX, NULL, 0x0,
2960 "Total Sequence Number", HFILL }
2964 /* Setup protocol subtree array */
2965 static gint *ett[] = {
2967 &ett_acn_channel_owner_info_block,
2968 &ett_acn_channel_member_info_block,
2969 &ett_acn_channel_parameter,
2971 &ett_acn_address_type,
2975 &ett_acn_sdt_client_pdu,
2976 &ett_acn_sdt_base_pdu,
2978 &ett_acn_dmx_address,
2979 &ett_acn_dmx_data_pdu,
2983 module_t *acn_module;
2984 if (proto_acn == -1) {
2985 proto_acn = proto_register_protocol (
2986 "Architecture for Control Networks", /* name */
2987 "ACN", /* short name */
2992 acn_module = prefs_register_protocol(proto_acn, proto_reg_handoff_acn);
2993 proto_register_field_array(proto_acn, hf, array_length(hf));
2994 proto_register_subtree_array(ett, array_length(ett));
2995 prefs_register_bool_preference(acn_module, "heuristic_acn",
2997 "Enable Architecture for Control Networks dissector (ANSI BSR E1.17)",
3000 prefs_register_bool_preference(acn_module, "dmx_enable",
3002 "Enable Streaming DMX extension dissector (ANSI BSR E1.31)",
3003 &global_acn_dmx_enable);
3005 prefs_register_enum_preference(acn_module, "dmx_display_view",
3006 "DMX, display format",
3008 &global_acn_dmx_display_view,
3012 prefs_register_bool_preference(acn_module, "dmx_display_zeros",
3013 "DMX, display zeros",
3014 "Display zeros instead of dots",
3015 &global_acn_dmx_display_zeros);
3017 prefs_register_bool_preference(acn_module, "dmx_display_leading_zeros",
3018 "DMX, display leading zeros",
3019 "Display leading zeros on levels",
3020 &global_acn_dmx_display_leading_zeros);
3024 /******************************************************************************/
3025 /* Register handoff */
3027 proto_reg_handoff_acn(void)
3029 static guint initialized = FALSE;
3030 /* static dissector_handle_t acn_handle; */
3033 /* acn_handle = new_create_dissector_handle(dissect_acn, proto_acn); */
3034 /* dissector_add("udp.port", 0, acn_handle); */
3035 heur_dissector_add("udp", dissect_acn_heur, proto_acn);