2 * Routines for ACN packet disassembly
6 * Copyright (c) 2003 by Erwin Rol <erwin@erwinrol.com>
7 * Copyright (c) 2006 by Electronic Theatre Controls, Inc.
8 * Bill Florac <bflorac@etcconnect.com>
10 * Wireshark - Network traffic analyzer
11 * By Gerald Combs <gerald@wireshark.org>
12 * Copyright 1999 Gerald Combs
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
31 Add reading of DDL files so we can futher explode DMP packets
32 For some of the Set/Get properties where we have a range of data
33 it would be better to show the block of data rather and
34 address-data pair on each line...
36 Build CID to "Name" table from file so we can display real names
48 #include <epan/packet.h>
49 #include <epan/prefs.h>
50 #include <epan/emem.h>
51 #include <epan/packet.h>
52 #include <epan/ipv6-utils.h>
55 #include "packet-acn.h"
59 * ANSI BSR E1.17 Architecture for Control Networks
63 #define ACTUAL_ADDRESS 0
64 /* forward reference */
65 static gboolean dissect_acn_heur( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree );
66 static guint32 acn_add_channel_owner_info_block(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree _U_, int offset);
67 static guint32 acn_add_channel_member_info_block(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree _U_, int offset);
68 static guint32 acn_add_expiry(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, const char *label);
69 static guint32 acn_add_channel_parameter(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset);
70 static guint32 acn_add_address(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, const char *label);
71 static guint32 acn_add_dmp_address_type(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, acn_dmp_adt_type *adt);
72 static guint32 acn_add_dmp_address(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, acn_dmp_adt_type *adt);
73 static guint32 dissect_acn_dmp_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, acn_pdu_offsets *last_pdu_offsets);
74 static guint32 dissect_acn_sdt_wrapped_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree _U_, int offset, acn_pdu_offsets *last_pdu_offsets);
75 static guint32 dissect_acn_sdt_client_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, acn_pdu_offsets *last_pdu_offsets);
76 static guint32 dissect_acn_dmx_data_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, acn_pdu_offsets *last_pdu_offsets);
77 static guint32 dissect_acn_dmx_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, acn_pdu_offsets *last_pdu_offsets);
78 static guint32 dissect_acn_sdt_base_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, acn_pdu_offsets *last_pdu_offsets);
79 static guint32 dissect_acn_root_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, acn_pdu_offsets *last_pdu_offsets);
80 static int dissect_acn(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
81 static gboolean is_acn(tvbuff_t *tvb);
82 void proto_register_acn(void);
83 void proto_reg_handoff_acn(void);
85 /* Global variables */
86 static int proto_acn = -1;
87 static gint ett_acn = -1;
88 static gint ett_acn_channel_owner_info_block = -1;
89 static gint ett_acn_channel_member_info_block = -1;
90 static gint ett_acn_channel_parameter = -1;
91 static gint ett_acn_address = -1;
92 static gint ett_acn_address_type = -1;
93 static gint ett_acn_pdu_flags = -1;
94 static gint ett_acn_dmp_pdu = -1;
95 static gint ett_acn_sdt_pdu = -1;
96 static gint ett_acn_sdt_client_pdu = -1;
97 static gint ett_acn_sdt_base_pdu = -1;
98 static gint ett_acn_root_pdu = -1;
99 static gint ett_acn_dmx_address = -1;
100 static gint ett_acn_dmx_data_pdu = -1;
101 static gint ett_acn_dmx_pdu = -1;
103 /* Register fields */
104 /* In alphabetical order */
105 static int hf_acn_association = -1;
106 static int hf_acn_channel_number = -1;
107 static int hf_acn_cid = -1;
108 static int hf_acn_client_protocol_id = -1;
109 static int hf_acn_data = -1;
110 static int hf_acn_data8 = -1;
111 static int hf_acn_data16 = -1;
112 static int hf_acn_data24 = -1;
113 static int hf_acn_data32 = -1;
114 static int hf_acn_dmp_address1 = -1;
115 static int hf_acn_dmp_address2 = -1;
116 static int hf_acn_dmp_address4 = -1;
117 static int hf_acn_dmp_adt = -1; /* address and data type*/
118 static int hf_acn_dmp_adt_a = -1;
119 static int hf_acn_dmp_adt_v = -1;
120 static int hf_acn_dmp_adt_r = -1;
121 static int hf_acn_dmp_adt_d = -1;
122 static int hf_acn_dmp_adt_x = -1;
123 static int hf_acn_dmp_reason_code = -1;
124 static int hf_acn_dmp_vector = -1;
125 static int hf_acn_dmp_address_data_pairs = -1;
126 static int hf_acn_expiry = -1;
127 static int hf_acn_first_memeber_to_ack = -1;
128 static int hf_acn_first_missed_sequence = -1;
129 static int hf_acn_ip_address_type = -1;
130 static int hf_acn_ipv4 = -1;
131 static int hf_acn_ipv6 = -1;
132 static int hf_acn_last_memeber_to_ack = -1;
133 static int hf_acn_last_missed_sequence = -1;
134 static int hf_acn_mak_threshold = -1;
135 static int hf_acn_member_id = -1;
136 static int hf_acn_nak_holdoff = -1;
137 static int hf_acn_nak_max_wait = -1;
138 static int hf_acn_nak_modulus = -1;
139 static int hf_acn_nak_outbound_flag = -1;
140 static int hf_acn_oldest_available_wrapper = -1;
141 static int hf_acn_packet_identifier = -1;
142 static int hf_acn_pdu = -1;
143 static int hf_acn_pdu_flag_d = -1;
144 static int hf_acn_pdu_flag_h = -1;
145 static int hf_acn_pdu_flag_l = -1;
146 static int hf_acn_pdu_flag_v = -1;
147 static int hf_acn_pdu_flags = -1;
148 static int hf_acn_pdu_length = -1;
149 static int hf_acn_port = -1;
150 static int hf_acn_postamble_size = -1;
151 static int hf_acn_preamble_size = -1;
152 static int hf_acn_protocol_id = -1;
153 static int hf_acn_reason_code = -1;
154 static int hf_acn_reciprocal_channel = -1;
155 static int hf_acn_refuse_code = -1;
156 static int hf_acn_reliable_sequence_number = -1;
157 /* static int hf_acn_sdt_pdu = -1; */
158 static int hf_acn_sdt_vector = -1;
159 static int hf_acn_dmx_vector = -1;
160 static int hf_acn_session_count = -1;
161 static int hf_acn_total_sequence_number = -1;
162 static int hf_acn_dmx_source_name = -1;
163 static int hf_acn_dmx_priority = -1;
164 static int hf_acn_dmx_sequence_number = -1;
165 static int hf_acn_dmx_universe = -1;
166 /* static int hf_acn_dmx_dmp_vector = -1; */
168 /* Try heuristic ACN decode */
169 static gboolean global_acn_heur = FALSE;
170 static gboolean global_acn_dmx_enable = FALSE;
171 static gint global_acn_dmx_display_view = 0;
172 static gboolean global_acn_dmx_display_zeros = FALSE;
173 static gboolean global_acn_dmx_display_leading_zeros = FALSE;
176 static const value_string acn_protocol_id_vals[] = {
177 { ACN_PROTOCOL_ID_SDT, "SDT Protocol" },
178 { ACN_PROTOCOL_ID_DMP, "DMP Protocol" },
179 { ACN_PROTOCOL_ID_DMX, "DMX Protocol" },
183 static const value_string acn_dmp_adt_r_vals[] = {
189 static const value_string acn_dmp_adt_v_vals[] = {
195 static const value_string acn_dmp_adt_d_vals[] = {
196 { ACN_DMP_ADT_D_NS, "Non-range, single data item" },
197 { ACN_DMP_ADT_D_RS, "Range, single data item" },
198 { ACN_DMP_ADT_D_RE, "Range, array of equal size data items" },
199 { ACN_DMP_ADT_D_RM, "Range, series of mixed size data items" },
203 static const value_string acn_dmp_adt_a_vals[] = {
204 { ACN_DMP_ADT_A_1, "1 octet" },
205 { ACN_DMP_ADT_A_2, "2 octets" },
206 { ACN_DMP_ADT_A_4, "4 octets" },
207 { ACN_DMP_ADT_A_R, "reserved" },
212 static const value_string acn_sdt_vector_vals[] = {
213 {ACN_SDT_VECTOR_UNKNOWN, "Unknown"},
214 {ACN_SDT_VECTOR_REL_WRAP, "Reliable Wrapper"},
215 {ACN_SDT_VECTOR_UNREL_WRAP, "Unreliable Wrapper"},
216 {ACN_SDT_VECTOR_CHANNEL_PARAMS, "Channel Parameters"},
217 {ACN_SDT_VECTOR_JOIN, "Join"},
218 {ACN_SDT_VECTOR_JOIN_REFUSE, "Join Refuse"},
219 {ACN_SDT_VECTOR_JOIN_ACCEPT, "Join Accept"},
220 {ACN_SDT_VECTOR_LEAVE, "Leave"},
221 {ACN_SDT_VECTOR_LEAVING, "Leaving"},
222 {ACN_SDT_VECTOR_CONNECT, "Connect"},
223 {ACN_SDT_VECTOR_CONNECT_ACCEPT, "Connect Accept"},
224 {ACN_SDT_VECTOR_CONNECT_REFUSE, "Connect Refuse"},
225 {ACN_SDT_VECTOR_DISCONNECT, "Disconnect"},
226 {ACN_SDT_VECTOR_DISCONNECTING, "Disconnecting"},
227 {ACN_SDT_VECTOR_ACK, "Ack"},
228 {ACN_SDT_VECTOR_NAK, "Nak"},
229 {ACN_SDT_VECTOR_GET_SESSION, "Get Session"},
230 {ACN_SDT_VECTOR_SESSIONS, "Sessions"},
234 static const value_string acn_dmx_vector_vals[] = {
235 {ACN_DMX_VECTOR, "Streaming DMX"},
239 static const value_string acn_dmp_vector_vals[] = {
240 {ACN_DMP_VECTOR_UNKNOWN, "Unknown"},
241 {ACN_DMP_VECTOR_GET_PROPERTY, "Get Property"},
242 {ACN_DMP_VECTOR_SET_PROPERTY, "Set Property"},
243 {ACN_DMP_VECTOR_GET_PROPERTY_REPLY, "Get property reply"},
244 {ACN_DMP_VECTOR_EVENT, "Event"},
245 {ACN_DMP_VECTOR_MAP_PROPERTY, "Map Property"},
246 {ACN_DMP_VECTOR_UNMAP_PROPERTY, "Unmap Property"},
247 {ACN_DMP_VECTOR_SUBSCRIBE, "Subscribe"},
248 {ACN_DMP_VECTOR_UNSUBSCRIBE, "Unsubscribe"},
249 {ACN_DMP_VECTOR_GET_PROPERTY_FAIL, "Get Property Fail"},
250 {ACN_DMP_VECTOR_SET_PROPERTY_FAIL, "Set Property Fail"},
251 {ACN_DMP_VECTOR_MAP_PROPERTY_FAIL, "Map Property Fail"},
252 {ACN_DMP_VECTOR_SUBSCRIBE_ACCEPT, "Subscribe Accept"},
253 {ACN_DMP_VECTOR_SUBSCRIBE_REJECT, "Subscribe Reject"},
254 {ACN_DMP_VECTOR_ALLOCATE_MAP, "Allocate Map"},
255 {ACN_DMP_VECTOR_ALLOCATE_MAP_REPLY, "Allocate Map Reply"},
256 {ACN_DMP_VECTOR_DEALLOCATE_MAP, "Deallocate Map"},
260 static const value_string acn_ip_address_type_vals[] = {
261 { ACN_ADDR_NULL, "Null"},
262 { ACN_ADDR_IPV4, "IPv4"},
263 { ACN_ADDR_IPV6, "IPv6"},
264 { ACN_ADDR_IPPORT, "Port"},
268 static const value_string acn_refuse_code_vals[] = {
269 { ACN_REFUSE_CODE_NONSPECIFIC, "Nonspecific" },
270 { ACN_REFUSE_CODE_ILLEGAL_PARAMS, "Illegal Parameters" },
271 { ACN_REFUSE_CODE_LOW_RESOURCES, "Low Resources" },
272 { ACN_REFUSE_CODE_ALREADY_MEMBER, "Already Member" },
273 { ACN_REFUSE_CODE_BAD_ADDR_TYPE, "Bad Address Type" },
274 { ACN_REFUSE_CODE_NO_RECIP_CHAN, "No Reciprocal Channel" },
278 static const value_string acn_reason_code_vals[] = {
279 { ACN_REASON_CODE_NONSPECIFIC, "Nonspecific" },
280 { ACN_REASON_CODE_NO_RECIP_CHAN, "No Reciprocal Channel" },
281 { ACN_REASON_CODE_CHANNEL_EXPIRED, "Channel Expired" },
282 { ACN_REASON_CODE_LOST_SEQUENCE, "Lost Sequence" },
283 { ACN_REASON_CODE_SATURATED, "Saturated" },
284 { ACN_REASON_CODE_TRANS_ADDR_CHANGING, "Transport Address Changing" },
285 { ACN_REASON_CODE_ASKED_TO_LEAVE, "Asked to Leave" },
286 { ACN_REASON_CODE_NO_RECIPIENT, "No Recipient"},
290 static const value_string acn_dmp_reason_code_vals[] = {
291 { ACN_DMP_REASON_CODE_NONSPECIFIC, "Nonspecific" },
292 { ACN_DMP_REASON_CODE_NOT_A_PROPERTY, "Not a Property" },
293 { ACN_DMP_REASON_CODE_WRITE_ONLY, "Write Only" },
294 { ACN_DMP_REASON_CODE_NOT_WRITABLE, "Not Writable" },
295 { ACN_DMP_REASON_CODE_DATA_ERROR, "Data Error" },
296 { ACN_DMP_REASON_CODE_MAPS_NOT_SUPPORTED, "Maps not Supported" },
297 { ACN_DMP_REASON_CODE_SPACE_NOT_AVAILABLE, "Space not Available" },
298 { ACN_DMP_REASON_CODE_PROP_NOT_MAPABLE, "Property not Mapable"},
299 { ACN_DMP_REASON_CODE_MAP_NOT_ALLOCATED, "Map not Allocated"},
300 { ACN_DMP_REASON_CODE_SUBSCRIPTION_NOT_SUPPORTED, "Subscription not Supported"},
301 { ACN_DMP_REASON_CODE_NO_SUBSCRIPTIONS_SUPPORTED, "No Subscriptions Supported"},
305 static const enum_val_t dmx_display_view[] = {
306 { "hex" , "Hex ", ACN_PREF_DMX_DISPLAY_HEX },
307 { "decimal", "Decimal", ACN_PREF_DMX_DISPLAY_DEC },
308 { "percent", "Percent", ACN_PREF_DMX_DISPLAY_PER },
312 /******************************************************************************/
313 /* Test to see if it is an ACN Packet */
314 static gboolean is_acn(tvbuff_t *tvb)
316 static char acn_packet_id[] = "ASC-E1.17\0\0\0"; /* must be 12 bytes */
319 /* Get the fields in octets 2 - 12 octet */
320 packet_id = tvb_get_ephemeral_string(tvb, 4, 12);
321 if (memcmp(packet_id, &acn_packet_id, 12) == 0) {
328 /******************************************************************************/
329 /* Heuristic dissector */
331 dissect_acn_heur( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree )
333 /* This is a heuristic dissector, which means we get all the UDP
334 * traffic not sent to a known dissector and not claimed by
335 * a heuristic dissector called before us!
338 /* abort if not enabled! */
339 if (!global_acn_heur) return FALSE;
341 /* abort if it is NOT an ACN packet */
342 if (!is_acn(tvb)) return FALSE;
344 /* else, dissect it */
345 dissect_acn(tvb, pinfo, tree);
349 /******************************************************************************/
350 /* Adds tree branch for channel owner info block */
352 acn_add_channel_owner_info_block(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree _U_, int offset)
355 proto_tree *this_tree = NULL;
356 guint32 session_count;
359 pi = proto_tree_add_text(this_tree, tvb, offset, 8, "Channel Owner Info Block");
360 this_tree = proto_item_add_subtree(pi, ett_acn_channel_owner_info_block);
362 proto_tree_add_item(this_tree, hf_acn_member_id, tvb, offset, 2, FALSE);
364 proto_tree_add_item(this_tree, hf_acn_channel_number, tvb, offset, 2, FALSE);
366 offset += acn_add_address(tvb, pinfo, this_tree, offset, "Destination Address:");
367 offset += acn_add_address(tvb, pinfo, this_tree, offset, "Source Address:");
369 session_count = tvb_get_ntohs(tvb, offset);
370 for (x=0; x<session_count; x++) {
371 pi = proto_tree_add_item(this_tree, hf_acn_protocol_id, tvb, offset, 4, FALSE);
372 proto_item_append_text(pi, " #%d", x+1);
378 /******************************************************************************/
379 /* Adds tree branch for channel member info block */
381 acn_add_channel_member_info_block(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree _U_, int offset)
384 proto_tree *this_tree = NULL;
385 guint32 session_count;
388 pi = proto_tree_add_text(this_tree, tvb, offset, 8, "Channel Member Info Block");
389 this_tree = proto_item_add_subtree(pi, ett_acn_channel_member_info_block);
391 proto_tree_add_item(this_tree, hf_acn_member_id, tvb, offset, 2, FALSE);
393 proto_tree_add_item(this_tree, hf_acn_cid, tvb, offset, 16, FALSE);
395 proto_tree_add_item(this_tree, hf_acn_channel_number, tvb, offset, 2, FALSE);
397 offset += acn_add_address(tvb, pinfo, this_tree, offset, "Destination Address:");
398 offset += acn_add_address(tvb, pinfo, this_tree, offset, "Source Address:");
399 proto_tree_add_item(this_tree, hf_acn_reciprocal_channel, tvb, offset, 2, FALSE);
402 session_count = tvb_get_ntohs(tvb, offset);
403 for (x=0; x<session_count; x++) {
404 pi = proto_tree_add_item(this_tree, hf_acn_protocol_id, tvb, offset, 4, FALSE);
405 proto_item_append_text(pi, " #%d", x+1);
412 /******************************************************************************/
413 /* Add labeled expiry */
415 acn_add_expiry(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, const char *label)
417 proto_tree_add_text(tree, tvb, offset, 2, "%s %d", label, tvb_get_guint8(tvb, offset));
423 /******************************************************************************/
424 /* Adds tree branch for channel parameters */
426 acn_add_channel_parameter(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset)
429 proto_tree *param_tree = NULL;
431 pi = proto_tree_add_text(tree, tvb, offset, 8, "Channel Parameter Block");
432 param_tree = proto_item_add_subtree(pi, ett_acn_channel_parameter);
433 proto_tree_add_item(param_tree, hf_acn_expiry, tvb, offset, 1, FALSE);
435 proto_tree_add_item(param_tree, hf_acn_nak_outbound_flag, tvb, offset, 1, FALSE);
437 proto_tree_add_item(param_tree, hf_acn_nak_holdoff, tvb, offset, 2, FALSE);
439 proto_tree_add_item(param_tree, hf_acn_nak_modulus, tvb, offset, 2, FALSE);
441 proto_tree_add_item(param_tree, hf_acn_nak_max_wait, tvb, offset, 2, FALSE);
443 return offset; /* bytes used */
447 /******************************************************************************/
448 /* Add an address tree */
450 acn_add_address(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, const char *label)
453 proto_tree *addr_tree = NULL;
454 guint8 ip_address_type;
459 struct e_in6_addr IPv6;
463 ip_address_type = tvb_get_guint8(tvb, offset);
465 switch (ip_address_type) {
469 /* Build tree and add type*/
470 pi = proto_tree_add_text(tree, tvb, offset, 7, label);
471 addr_tree = proto_item_add_subtree(pi, ett_acn_address);
472 proto_tree_add_item(addr_tree, hf_acn_ip_address_type, tvb, offset, 1, FALSE);
475 port = tvb_get_ntohs(tvb, offset);
476 proto_tree_add_item(addr_tree, hf_acn_port, tvb, offset, 2, FALSE);
479 proto_tree_add_item(addr_tree, hf_acn_ipv4, tvb, offset, 4, FALSE);
480 /* Append port and address to tree item */
481 IPv4 = tvb_get_ipv4(tvb, offset);
482 SET_ADDRESS(&addr, AT_IPv4, sizeof(IPv4), &IPv4);
483 proto_item_append_text(pi, " %s, Port %d", address_to_str(&addr), port);
487 /* Build tree and add type*/
488 pi = proto_tree_add_text(tree, tvb, offset, 19, label);
489 addr_tree = proto_item_add_subtree(pi, ett_acn_address);
490 proto_tree_add_item(addr_tree, hf_acn_ip_address_type, tvb, offset, 1, FALSE);
493 port = tvb_get_ntohs(tvb, offset);
494 proto_tree_add_item(addr_tree, hf_acn_port, tvb, offset, 2, FALSE);
497 proto_tree_add_item(addr_tree, hf_acn_ipv6, tvb, offset, 16, FALSE);
498 /* Append port and address to tree item */
499 tvb_get_ipv6(tvb, offset, &IPv6);
500 SET_ADDRESS(&addr, AT_IPv6, sizeof(struct e_in6_addr), &IPv6);
501 proto_item_append_text(pi, " %s, Port %d", address_to_str(&addr), port);
504 case ACN_ADDR_IPPORT:
505 /* Build tree and add type*/
506 pi = proto_tree_add_text(tree, tvb, offset, 3, label);
507 addr_tree = proto_item_add_subtree(pi, ett_acn_address);
508 proto_tree_add_item(addr_tree, hf_acn_ip_address_type, tvb, offset, 1, FALSE);
511 port = tvb_get_ntohs(tvb, offset);
512 proto_tree_add_item(addr_tree, hf_acn_port, tvb, offset, 2, FALSE);
513 /* Append port to tree item */
514 proto_item_append_text(pi, " %s Port %d", address_to_str(&addr), port);
521 /******************************************************************************/
522 /* Adds tree branch for address type */
524 acn_add_dmp_address_type(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, acn_dmp_adt_type *adt)
527 proto_tree *this_tree = NULL;
530 /* header contains address and data type */
531 adt->flags = tvb_get_guint8(tvb, offset);
533 D = ACN_DMP_ADT_EXTRACT_D(adt->flags);
534 pi = proto_tree_add_text(tree, tvb, offset, 1, "Address and Data Type: %s (%d)", match_strval(D, acn_dmp_adt_d_vals), D);
536 this_tree = proto_item_add_subtree(pi, ett_acn_address_type);
537 proto_tree_add_uint(this_tree, hf_acn_dmp_adt_v, tvb, offset, 1, adt->flags);
538 proto_tree_add_uint(this_tree, hf_acn_dmp_adt_r, tvb, offset, 1, adt->flags);
539 proto_tree_add_uint(this_tree, hf_acn_dmp_adt_d, tvb, offset, 1, adt->flags);
540 proto_tree_add_uint(this_tree, hf_acn_dmp_adt_x, tvb, offset, 1, adt->flags);
541 proto_tree_add_uint(this_tree, hf_acn_dmp_adt_a, tvb, offset, 1, adt->flags);
544 return offset; /* bytes used */
547 /******************************************************************************/
548 /* Add an dmp address */
550 acn_add_dmp_address(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, acn_dmp_adt_type *adt)
552 guint32 start_offset;
556 start_offset = offset;
558 D = ACN_DMP_ADT_EXTRACT_D(adt->flags);
559 A = ACN_DMP_ADT_EXTRACT_A(adt->flags);
561 case ACN_DMP_ADT_D_NS: /* Non-range address, Single data item */
564 switch (A) { /* address */
565 case ACN_DMP_ADT_A_1: /* One octet address, (range: one octet address, increment, and count). */
566 adt->address = tvb_get_guint8(tvb, offset);
570 case ACN_DMP_ADT_A_2: /* Two octet address, (range: two octet address, increment, and count). */
571 adt->address = tvb_get_ntohs(tvb, offset);
575 case ACN_DMP_ADT_A_4: /* Four octet address, (range: one octet address, increment, and count). */
576 adt->address = tvb_get_ntohl(tvb, offset);
580 default: /* and ACN_DMP_ADT_A_R (Four octet address, (range: four octet address, increment, and count)*/
582 } /* of switch (A) */
584 if (adt->flags & ACN_DMP_ADT_FLAG_V) {
585 proto_tree_add_text(tree, tvb, start_offset, bytes_used, "Virtual Address: %d", adt->address);
587 proto_tree_add_text(tree, tvb, start_offset, bytes_used, "Actual Address: %d", adt->address);
591 case ACN_DMP_ADT_D_RS: /* Range address, Single data item */
593 case ACN_DMP_ADT_A_1: /* One octet address, (range: one octet address, increment, and count). */
594 adt->address = tvb_get_guint8(tvb, offset);
596 adt->increment = tvb_get_guint8(tvb, offset);
598 adt->count = tvb_get_guint8(tvb, offset);
602 case ACN_DMP_ADT_A_2: /* Two octet address, (range: two octet address, increment, and count). */
603 adt->address = tvb_get_ntohs(tvb, offset);
605 adt->increment = tvb_get_ntohs(tvb, offset);
607 adt->count = tvb_get_ntohs(tvb, offset);
611 case ACN_DMP_ADT_A_4: /* Four octet address, (range: four octet address, increment, and count). */
612 adt->address = tvb_get_ntohl(tvb, offset);
614 adt->increment = tvb_get_ntohl(tvb, offset);
616 adt->count = tvb_get_ntohl(tvb, offset);
620 default: /* and ACN_DMP_ADT_A_R, this reserved....so it has no meaning yet */
622 } /* of switch (A) */
624 if (adt->flags & ACN_DMP_ADT_FLAG_V) {
625 proto_tree_add_text(tree, tvb, start_offset, bytes_used, "Virtual Address first: %d, inc: %d, count: %d", adt->address, adt->increment, adt->count);
627 proto_tree_add_text(tree, tvb, start_offset, bytes_used, "Actual Address first: %d, inc: %d, count: %d", adt->address, adt->increment, adt->count);
631 case ACN_DMP_ADT_D_RE: /* Range address, Array of equal size data items */
633 case ACN_DMP_ADT_A_1: /* One octet address, (range: one octet address, increment, and count). */
634 adt->address = tvb_get_guint8(tvb, offset);
636 adt->increment = tvb_get_guint8(tvb, offset);
638 adt->count = tvb_get_guint8(tvb, offset);
642 case ACN_DMP_ADT_A_2: /* Two octet address, (range: two octet address, increment, and count). */
643 adt->address = tvb_get_ntohs(tvb, offset);
645 adt->increment = tvb_get_ntohs(tvb, offset);
647 adt->count = tvb_get_ntohs(tvb, offset);
651 case ACN_DMP_ADT_A_4: /* Four octet address, (range: four octet address, increment, and count). */
652 adt->address = tvb_get_ntohl(tvb, offset);
654 adt->increment = tvb_get_ntohl(tvb, offset);
656 adt->count = tvb_get_ntohl(tvb, offset);
660 default: /* and ACN_DMP_ADT_A_R, this reserved....so it has no meaning yet */
662 } /* of switch (A) */
664 if (adt->flags & ACN_DMP_ADT_FLAG_V) {
665 proto_tree_add_text(tree, tvb, start_offset, bytes_used, "Virtual Address first: %d, inc: %d, count: %d", adt->address, adt->increment, adt->count);
667 proto_tree_add_text(tree, tvb, start_offset, bytes_used, "Actual Address first: %d, inc: %d, count: %d", adt->address, adt->increment, adt->count);
671 case ACN_DMP_ADT_D_RM: /* Range address, Series of mixed size data items */
673 case ACN_DMP_ADT_A_1: /* One octet address, (range: one octet address, increment, and count). */
674 adt->address = tvb_get_guint8(tvb, offset);
676 adt->increment = tvb_get_guint8(tvb, offset);
678 adt->count = tvb_get_guint8(tvb, offset);
682 case ACN_DMP_ADT_A_2: /* Two octet address, (range: two octet address, increment, and count). */
683 adt->address = tvb_get_ntohs(tvb, offset);
685 adt->increment = tvb_get_ntohs(tvb, offset);
687 adt->count = tvb_get_ntohs(tvb, offset);
691 case ACN_DMP_ADT_A_4: /* Four octet address, (range: four octet address, increment, and count). */
692 adt->address = tvb_get_ntohl(tvb, offset);
694 adt->increment = tvb_get_ntohl(tvb, offset);
696 adt->count = tvb_get_ntohl(tvb, offset);
700 default: /* and ACN_DMP_ADT_A_R, this reserved....so it has no meaning yet */
702 } /* of switch (A) */
704 if (adt->flags & ACN_DMP_ADT_FLAG_V) {
705 proto_tree_add_text(tree, tvb, start_offset, bytes_used, "Virtual Address first: %d, inc: %d, count: %d", adt->address, adt->increment, adt->count);
707 proto_tree_add_text(tree, tvb, start_offset, bytes_used, "Actual Address first: %d, inc: %d, count: %d", adt->address, adt->increment, adt->count);
710 } /* of switch (D) */
716 /*******************************************************************************/
717 /* Display DMP Data */
719 acn_add_dmp_data(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, acn_dmp_adt_type *adt)
722 guint32 start_offset;
725 guint32 data_address;
729 guint32 ok_to_process = FALSE;
731 start_offset = offset;
733 /* We would like to rip through Property Address-Data pairs */
734 /* but since we don't now how many there are nor how big the data size is, */
735 /* it not possible. So, we just show the whole thing as a block of date! */
737 /* There are a few exceptions however */
738 /* 1) if the address type is ACN_DMP_ADT_D_NS or ACN_DMP_ADT_D_RS and */
739 /* or ACN_DMP_ADT_D_RE */
740 /* then number of bytes is <= count + 4. Each value is at least one byte */
741 /* and another address/data pair is at least 4 bytes so if the remaining */
742 /* bytes is less than the count plus 4 then the remaining data */
743 /* must be all data */
745 /* 2) if the address type is ACN_DMP_ADT_D_RE and the number of bytes */
746 /* equals the number of bytes in remaining in the pdu then there is */
747 /* a 1 to one match */
749 D = ACN_DMP_ADT_EXTRACT_D(adt->flags);
751 case ACN_DMP_ADT_D_NS:
752 case ACN_DMP_ADT_D_RS:
753 if (adt->data_length <= adt->count + 4) {
754 ok_to_process = TRUE;
757 case ACN_DMP_ADT_D_RE:
758 if (adt->data_length == adt->count) {
759 ok_to_process = TRUE;
761 if (adt->data_length <= adt->count + 4) {
762 ok_to_process = TRUE;
767 if (!ok_to_process) {
768 data_size = adt->data_length;
769 ti = proto_tree_add_item(tree, hf_acn_data, tvb, offset, data_size, FALSE);
771 proto_item_set_text(ti, "Data and more Address-Data Pairs (further dissection not possible)");
775 /* Allocate some memory, not using ep_alloc here as there could be LOT of calls to
776 this in the same capture frame. Could use se_alloc...
778 #define BUFFER_SIZE 128
779 buffer = g_malloc(BUFFER_SIZE);
782 A = ACN_DMP_ADT_EXTRACT_A(adt->flags);
784 case ACN_DMP_ADT_D_NS: /* Non-range address, Single data item */
785 /* calculate data size */
786 data_size = adt->data_length;
787 data_address = adt->address;
790 case ACN_DMP_ADT_A_1: /* One octet address, (range: one octet address, increment, and count). */
791 g_snprintf(buffer, BUFFER_SIZE, "Addr %2.2X ->", data_address);
793 case ACN_DMP_ADT_A_2: /* Two octet address, (range: two octet address, increment, and count). */
794 g_snprintf(buffer, BUFFER_SIZE, "Addr %4.4X ->", data_address);
796 case ACN_DMP_ADT_A_4: /* Four octet address, (range: four octet address, increment, and count). */
797 g_snprintf(buffer, BUFFER_SIZE, "Addr %8.8X ->", data_address);
799 default: /* and ACN_DMP_ADT_A_R, this reserved....so it has no meaning yet */
805 data_value = tvb_get_guint8(tvb, offset);
806 proto_tree_add_int_format(tree, hf_acn_data8, tvb, offset, 1, data_value, "%s %2.2X", buffer, data_value);
809 data_value = tvb_get_ntohs(tvb, offset);
810 proto_tree_add_int_format(tree, hf_acn_data16, tvb, offset, 2, data_value, "%s %4.4X", buffer, data_value);
813 data_value = tvb_get_ntoh24(tvb, offset);
814 proto_tree_add_int_format(tree, hf_acn_data24, tvb, offset, 3, data_value, "%s %6.6X", buffer, data_value);
817 data_value = tvb_get_ntohl(tvb, offset);
818 proto_tree_add_int_format(tree, hf_acn_data32, tvb, offset, 4, data_value, "%s %8.8X", buffer, data_value);
821 /* build string of values */
822 for (y=0;y<20 && y<data_size;y++) {
823 data_value = tvb_get_guint8(tvb, offset+y);
824 g_snprintf(buffer, BUFFER_SIZE, "%s %2.2X", buffer, data_value);
827 ti = proto_tree_add_item(tree, hf_acn_data, tvb, offset, data_size, FALSE);
829 /* change the text */
830 proto_item_set_text(ti, "%s", buffer);
832 } /* of switch (data_size) */
836 case ACN_DMP_ADT_D_RS: /* Range address, Single data item */
837 /* calculate data size */
838 data_size = adt->data_length;
839 data_address = adt->address;
841 for (x=0;x<adt->count;x++) {
843 case ACN_DMP_ADT_A_1: /* One octet address, (range: one octet address, increment, and count). */
844 g_snprintf(buffer, BUFFER_SIZE, "Addr %2.2X ->", data_address);
846 case ACN_DMP_ADT_A_2: /* Two octet address, (range: two octet address, increment, and count). */
847 g_snprintf(buffer, BUFFER_SIZE, "Addr %4.4X ->", data_address);
849 case ACN_DMP_ADT_A_4: /* Four octet address, (range: four octet address, increment, and count). */
850 g_snprintf(buffer, BUFFER_SIZE, "Addr %8.8X ->", data_address);
852 default: /* and ACN_DMP_ADT_A_R, this reserved....so it has no meaning yet */
858 data_value = tvb_get_guint8(tvb, offset);
859 proto_tree_add_int_format(tree, hf_acn_data8, tvb, offset, 1, data_value, "%s %2.2X", buffer, data_value);
862 data_value = tvb_get_ntohs(tvb, offset);
863 proto_tree_add_int_format(tree, hf_acn_data8, tvb, offset, 2, data_value, "%s %4.4X", buffer, data_value);
866 data_value = tvb_get_ntoh24(tvb, offset);
867 proto_tree_add_int_format(tree, hf_acn_data8, tvb, offset, 3, data_value, "%s %6.6X", buffer, data_value);
870 data_value = tvb_get_ntohl(tvb, offset);
871 proto_tree_add_int_format(tree, hf_acn_data8, tvb, offset, 4, data_value, "%s %8.8X", buffer, data_value);
874 /* build string of values */
875 for (y=0;y<20 && y<data_size;y++) {
876 data_value = tvb_get_guint8(tvb, offset+y);
877 g_snprintf(buffer, BUFFER_SIZE, "%s %2.2X", buffer, data_value);
880 ti = proto_tree_add_item(tree, hf_acn_data, tvb, offset, data_size, FALSE);
881 /* change the text */
882 proto_item_set_text(ti, "%s", buffer);
884 } /* of switch (data_size) */
885 data_address += adt->increment;
886 } /* of (x=0;x<adt->count;x++) */
890 case ACN_DMP_ADT_D_RE: /* Range address, Array of equal size data items */
891 /* calculate data size */
892 data_size = adt->data_length / adt->count;
893 data_address = adt->address;
895 for (x=0;x<adt->count;x++) {
897 case ACN_DMP_ADT_A_1: /* One octet address, (range: one octet address, increment, and count). */
898 g_snprintf(buffer, BUFFER_SIZE, "Addr %2.2X ->", data_address);
900 case ACN_DMP_ADT_A_2: /* Two octet address, (range: two octet address, increment, and count). */
901 g_snprintf(buffer, BUFFER_SIZE, "Addr %4.4X ->", data_address);
903 case ACN_DMP_ADT_A_4: /* Four octet address, (range: four octet address, increment, and count). */
904 g_snprintf(buffer, BUFFER_SIZE, "Addr %8.8X ->", data_address);
906 default: /* and ACN_DMP_ADT_A_R, this reserved....so it has no meaning yet */
912 data_value = tvb_get_guint8(tvb, offset);
913 proto_tree_add_int_format(tree, hf_acn_data8, tvb, offset, 1, data_value, "%s %2.2X", buffer, data_value);
916 data_value = tvb_get_ntohs(tvb, offset);
917 proto_tree_add_int_format(tree, hf_acn_data8, tvb, offset, 2, data_value, "%s %4.4X", buffer, data_value);
920 data_value = tvb_get_ntoh24(tvb, offset);
921 proto_tree_add_int_format(tree, hf_acn_data8, tvb, offset, 3, data_value, "%s %6.6X", buffer, data_value);
924 data_value = tvb_get_ntohl(tvb, offset);
925 proto_tree_add_int_format(tree, hf_acn_data8, tvb, offset, 4, data_value, "%s %8.8X", buffer, data_value);
928 /* build string of values */
929 for (y=0;y<20 && y<data_size;y++) {
930 data_value = tvb_get_guint8(tvb, offset+y);
931 g_snprintf(buffer, BUFFER_SIZE, "%s %2.2X", buffer, data_value);
934 ti = proto_tree_add_item(tree, hf_acn_data, tvb, offset, data_size, FALSE);
935 /* change the text */
936 proto_item_set_text(ti, "%s", buffer);
938 } /* of switch (data_size) */
941 data_address += adt->increment;
942 } /* of (x=0;x<adt->count;x++) */
945 case ACN_DMP_ADT_D_RM: /* Range address, Series of mixed size data items */
946 data_size = adt->data_length;
947 ti = proto_tree_add_item(tree, hf_acn_data, tvb, offset, data_size, FALSE);
949 /* change the text */
950 proto_item_set_text(ti, "Mixed size data items");
952 } /* of switch (D) */
953 /* free our memory! */
959 /*******************************************************************************/
960 /* Display DMP Reason codes */
962 acn_add_dmp_reason_codes(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, acn_dmp_adt_type *adt)
965 guint32 start_offset;
967 guint32 data_address;
973 start_offset = offset;
975 /* Allocate some memory, not using ep_alloc here as there could be LOT of calls to
976 this in the same capture frame. Could use se_alloc...
978 #define BUFFER_SIZE 128
979 buffer = g_malloc(BUFFER_SIZE);
983 D = ACN_DMP_ADT_EXTRACT_D(adt->flags);
984 A = ACN_DMP_ADT_EXTRACT_A(adt->flags);
986 case ACN_DMP_ADT_D_NS: /* Non-range address, Single data item */
987 data_address = adt->address;
989 case ACN_DMP_ADT_A_1: /* One octet address, (range: one octet address, increment, and count). */
990 g_snprintf(buffer, BUFFER_SIZE, "Addr %2.2X ->", data_address);
992 case ACN_DMP_ADT_A_2: /* Two octet address, (range: two octet address, increment, and count). */
993 g_snprintf(buffer, BUFFER_SIZE, "Addr %4.4X ->", data_address);
995 case ACN_DMP_ADT_A_4: /* Four octet address, (range: four octet address, increment, and count). */
996 g_snprintf(buffer, BUFFER_SIZE, "Addr %8.8X ->", data_address);
998 default: /* and ACN_DMP_ADT_A_R, this reserved....so it has no meaning yet */
1003 data_value = tvb_get_guint8(tvb, offset);
1004 /* convert to string */
1005 ptr = match_strval(data_value, acn_dmp_reason_code_vals);
1007 proto_tree_add_int_format(tree, hf_acn_data8, tvb, offset, 1, data_value, "%s %s", buffer, ptr);
1011 case ACN_DMP_ADT_D_RS: /* Range address, Single data item */
1012 data_address = adt->address;
1013 for (x=0;x<adt->count;x++) {
1015 case ACN_DMP_ADT_A_1: /* One octet address, (range: one octet address, increment, and count). */
1016 g_snprintf(buffer, BUFFER_SIZE, "Addr %2.2X ->", data_address);
1018 case ACN_DMP_ADT_A_2: /* Two octet address, (range: two octet address, increment, and count). */
1019 g_snprintf(buffer, BUFFER_SIZE, "Addr %4.4X ->", data_address);
1021 case ACN_DMP_ADT_A_4: /* Four octet address, (range: four octet address, increment, and count). */
1022 g_snprintf(buffer, BUFFER_SIZE, "Addr %8.8X ->", data_address);
1024 default: /* and ACN_DMP_ADT_A_R, this reserved....so it has no meaning yet */
1029 data_value = tvb_get_guint8(tvb, offset);
1030 /* convert to string */
1031 ptr = match_strval(data_value, acn_dmp_reason_code_vals);
1033 proto_tree_add_int_format(tree, hf_acn_data8, tvb, offset, 1, data_value, "%s %s", buffer, ptr);
1034 data_address += adt->increment;
1035 } /* of (x=0;x<adt->count;x++) */
1039 case ACN_DMP_ADT_D_RE: /* Range address, Array of equal size data items */
1040 case ACN_DMP_ADT_D_RM: /* Range address, Series of mixed size data items */
1041 data_address = adt->address;
1042 for (x=0;x<adt->count;x++) {
1044 case ACN_DMP_ADT_A_1: /* One octet address, (range: one octet address, increment, and count). */
1045 g_snprintf(buffer, BUFFER_SIZE, "Addr %2.2X ->", data_address);
1047 case ACN_DMP_ADT_A_2: /* Two octet address, (range: two octet address, increment, and count). */
1048 g_snprintf(buffer, BUFFER_SIZE, "Addr %4.4X ->", data_address);
1050 case ACN_DMP_ADT_A_4: /* Four octet address, (range: four octet address, increment, and count). */
1051 g_snprintf(buffer, BUFFER_SIZE, "Addr %8.8X ->", data_address);
1053 default: /* and ACN_DMP_ADT_A_R, this reserved....so it has no meaning yet */
1057 data_value = tvb_get_guint8(tvb, offset);
1058 /* convert to string */
1059 ptr = match_strval(data_value, acn_dmp_reason_code_vals);
1061 proto_tree_add_int_format(tree, hf_acn_data8, tvb, offset, 1, data_value, "%s %s", buffer, ptr);
1062 data_address += adt->increment;
1064 } /* of (x=0;x<adt->count;x++) */
1066 } /* of switch (D) */
1067 /* free our memory! */
1073 /******************************************************************************/
1074 /* Dissect wrapped SDT PDU */
1076 dissect_acn_dmp_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, acn_pdu_offsets *last_pdu_offsets)
1078 /* common to all pdu */
1082 guint32 pdu_flvh_length; /* flags, length, vector, header */
1083 acn_pdu_offsets pdu_offsets = {0,0,0,0,0};
1089 guint32 vector_offset;
1090 guint32 header_offset;
1091 guint32 data_offset;
1094 guint32 data_length;
1095 guint32 address_count;
1097 proto_item *ti, *pi;
1098 proto_tree *pdu_tree = NULL;
1099 proto_tree *flag_tree = NULL;
1103 acn_dmp_adt_type adt = {0,0,0,0,0,0};
1104 acn_dmp_adt_type adt2 = {0,0,0,0,0,0};
1107 /* save start of pdu block */
1109 pdu_offsets.start = pdu_start;
1111 /* get PDU flags and length flag first */
1112 octet = tvb_get_guint8(tvb, offset++);
1113 pdu_flags = octet & 0xf0;
1114 length1 = octet & 0x0f; /* bottom 4 bits only */
1115 length2 = tvb_get_guint8(tvb, offset++);
1117 /* if length flag is set, then we have a 20 bit length else we have a 12 bit */
1118 /* flvh = flags, length, vector, header */
1119 if (pdu_flags & ACN_PDU_FLAG_L) {
1120 length3 = tvb_get_guint8(tvb, offset);
1122 pdu_length = length3 | (length2 << 8) | (length1 << 16);
1123 pdu_flvh_length = 3;
1125 pdu_length = length2 | (length1 << 8);
1126 pdu_flvh_length = 2;
1128 /* offset should now be pointing to vector (if one exists) */
1130 /* Add pdu item and tree */
1131 ti = proto_tree_add_item(tree, hf_acn_pdu, tvb, pdu_start, pdu_length, FALSE);
1132 pdu_tree = proto_item_add_subtree(ti, ett_acn_dmp_pdu);
1134 /* Add flag item and tree */
1135 pi = proto_tree_add_uint(pdu_tree, hf_acn_pdu_flags, tvb, pdu_start, 1, pdu_flags);
1136 flag_tree = proto_item_add_subtree(pi, ett_acn_pdu_flags);
1137 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_l, tvb, pdu_start, 1, FALSE);
1138 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_v, tvb, pdu_start, 1, FALSE);
1139 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_h, tvb, pdu_start, 1, FALSE);
1140 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_d, tvb, pdu_start, 1, FALSE);
1142 /* Add PDU Length item */
1143 proto_tree_add_uint(pdu_tree, hf_acn_pdu_length, tvb, pdu_start, pdu_flvh_length, pdu_length);
1145 /* Set vector offset */
1146 if (pdu_flags & ACN_PDU_FLAG_V) {
1147 /* use new values */
1148 vector_offset = offset;
1149 last_pdu_offsets->vector = offset;
1153 /* use last values */
1154 vector_offset = last_pdu_offsets->vector;
1156 /* offset should now be pointing to header (if one exists) */
1158 /* Add Vector item */
1159 vector = tvb_get_guint8(tvb, vector_offset);
1160 proto_tree_add_uint(pdu_tree, hf_acn_dmp_vector, tvb, vector_offset, 1, vector);
1162 /* Add Vector item to tree*/
1163 ptr = match_strval(vector, acn_dmp_vector_vals);
1164 proto_item_append_text(ti, ": ");
1165 proto_item_append_text(ti, ptr);
1167 /* Set header offset */
1168 if (pdu_flags & ACN_PDU_FLAG_H) {
1169 /* use new values */
1170 header_offset = offset;
1171 last_pdu_offsets->header = offset;
1175 /* use last values */
1176 header_offset = last_pdu_offsets->header;
1178 /* offset should now be pointing to data (if one exists) */
1180 /* header contains address and data type */
1181 acn_add_dmp_address_type(tvb, pinfo, pdu_tree, header_offset, &adt);
1184 if (pdu_flags & ACN_PDU_FLAG_D) {
1185 /* use new values */
1186 data_offset = offset;
1187 data_length = pdu_length - pdu_flvh_length;
1188 last_pdu_offsets->data = offset;
1189 last_pdu_offsets->data_length = data_length;
1191 /* use last values */
1192 data_offset = last_pdu_offsets->data;
1193 data_length = last_pdu_offsets->data_length;
1195 end_offset = data_offset + data_length;
1198 case ACN_DMP_VECTOR_UNKNOWN:
1200 case ACN_DMP_VECTOR_GET_PROPERTY:
1201 /* Rip trough property address */
1202 while (data_offset < end_offset) {
1203 old_offset = data_offset;
1204 data_offset = acn_add_dmp_address(tvb, pinfo, pdu_tree, data_offset, &adt);
1205 if (old_offset == data_offset) break;
1208 case ACN_DMP_VECTOR_SET_PROPERTY:
1209 /* Rip through Property Address-Data pairs */
1210 /* But, in reality, this generally won't work as we have know way of */
1211 /* calculating the next Address-Data pair */
1212 while (data_offset < end_offset) {
1213 old_offset = data_offset;
1214 data_offset = acn_add_dmp_address(tvb, pinfo, pdu_tree, data_offset, &adt);
1215 if (old_offset == data_offset) break;
1217 adt.data_length = data_length - (data_offset - old_offset);
1218 old_offset = data_offset;
1219 data_offset = acn_add_dmp_data(tvb, pinfo, pdu_tree, data_offset, &adt);
1220 if (old_offset == data_offset) break;
1223 case ACN_DMP_VECTOR_GET_PROPERTY_REPLY:
1224 /* Rip through Property Address-Data pairs */
1225 /* But, in reality, this generally won't work as we have know way of */
1226 /* calculating the next Address-Data pair */
1227 while (data_offset < end_offset) {
1228 old_offset = data_offset;
1229 data_offset = acn_add_dmp_address(tvb, pinfo, pdu_tree, data_offset, &adt);
1230 if (old_offset == data_offset) break;
1233 adt.data_length = data_length - (data_offset - old_offset);
1234 old_offset = data_offset;
1235 data_offset = acn_add_dmp_data(tvb, pinfo, pdu_tree, data_offset, &adt);
1236 if (old_offset == data_offset) break;
1239 case ACN_DMP_VECTOR_EVENT:
1240 /* Rip through Property Address-Data pairs */
1241 /* But, in reality, this generally won't work as we have know way of */
1242 /* calculating the next Address-Data pair */
1243 while (data_offset < end_offset) {
1244 old_offset = data_offset;
1245 data_offset = acn_add_dmp_address(tvb, pinfo, pdu_tree, data_offset, &adt);
1246 if (old_offset == data_offset) break;
1248 adt.data_length = data_length - (data_offset - old_offset);
1249 old_offset = data_offset;
1250 data_offset = acn_add_dmp_data(tvb, pinfo, pdu_tree, data_offset, &adt);
1251 if (old_offset == data_offset) break;
1254 case ACN_DMP_VECTOR_MAP_PROPERTY:
1255 /* Virtual Address type */
1256 data_offset = acn_add_dmp_address_type(tvb, pinfo, pdu_tree, data_offset, &adt2);
1257 /* Rip through Actual-Virtual Address Pairs */
1258 while (data_offset < end_offset) {
1260 old_offset = data_offset;
1261 data_offset = acn_add_dmp_address(tvb, pinfo, pdu_tree, data_offset, &adt);
1262 if (old_offset == data_offset) break;
1263 D = ACN_DMP_ADT_EXTRACT_D(adt.flags);
1265 case ACN_DMP_ADT_D_NS:
1268 case ACN_DMP_ADT_D_RS:
1271 case ACN_DMP_ADT_D_RE:
1272 address_count = adt.count;
1274 /*case ACN_DMP_ADT_D_RM: */
1277 return pdu_start + pdu_length;
1282 while (address_count > 0) {
1283 data_offset = acn_add_dmp_address(tvb, pinfo, pdu_tree, data_offset, &adt2);
1288 case ACN_DMP_VECTOR_UNMAP_PROPERTY:
1289 /* Rip trough Actaul Proptery Address */
1290 while (data_offset < end_offset) {
1291 old_offset = data_offset;
1292 data_offset = acn_add_dmp_address(tvb, pinfo, pdu_tree, data_offset, &adt);
1293 if (old_offset == data_offset) break;
1296 case ACN_DMP_VECTOR_SUBSCRIBE:
1297 /* Rip trough Proptery Address */
1298 while (data_offset < end_offset) {
1299 old_offset = data_offset;
1300 data_offset = acn_add_dmp_address(tvb, pinfo, pdu_tree, data_offset, &adt);
1301 if (old_offset == data_offset) break;
1304 case ACN_DMP_VECTOR_UNSUBSCRIBE:
1305 /* Rip trough Proptery Address */
1306 while (data_offset < end_offset) {
1307 old_offset = data_offset;
1308 data_offset = acn_add_dmp_address(tvb, pinfo, pdu_tree, data_offset, &adt);
1309 if (old_offset == data_offset) break;
1312 case ACN_DMP_VECTOR_GET_PROPERTY_FAIL:
1313 /* Rip trough Address-Reason Code Pairs */
1314 while (data_offset < end_offset) {
1315 old_offset = data_offset;
1316 data_offset = acn_add_dmp_address(tvb, pinfo, pdu_tree, data_offset, &adt);
1317 if (old_offset == data_offset) break;
1319 adt.data_length = data_length - (data_offset - old_offset);
1320 old_offset = data_offset;
1321 data_offset = acn_add_dmp_reason_codes(tvb, pinfo, pdu_tree, data_offset, &adt);
1322 if (old_offset == data_offset) break;
1325 case ACN_DMP_VECTOR_SET_PROPERTY_FAIL:
1326 /* Rip trough Address-Reason Code Pairs */
1327 while (data_offset < end_offset) {
1328 old_offset = data_offset;
1329 data_offset = acn_add_dmp_address(tvb, pinfo, pdu_tree, data_offset, &adt);
1330 if (old_offset == data_offset) break;
1332 adt.data_length = data_length - (data_offset - old_offset);
1333 old_offset = data_offset;
1334 data_offset = acn_add_dmp_reason_codes(tvb, pinfo, pdu_tree, data_offset, &adt);
1335 if (old_offset == data_offset) break;
1338 case ACN_DMP_VECTOR_MAP_PROPERTY_FAIL:
1339 /* Rip trough Address-Reason Code Pairs */
1340 while (data_offset < end_offset) {
1341 old_offset = data_offset;
1342 data_offset = acn_add_dmp_address(tvb, pinfo, pdu_tree, data_offset, &adt);
1343 if (old_offset == data_offset) break;
1345 adt.data_length = data_length - (data_offset - old_offset);
1346 old_offset = data_offset;
1347 data_offset = acn_add_dmp_reason_codes(tvb, pinfo, pdu_tree, data_offset, &adt);
1348 if (old_offset == data_offset) break;
1351 case ACN_DMP_VECTOR_SUBSCRIBE_ACCEPT:
1352 /* Rip through Property Addrsses */
1353 while (data_offset < end_offset) {
1354 old_offset = data_offset;
1355 data_offset = acn_add_dmp_address(tvb, pinfo, pdu_tree, data_offset, &adt);
1356 if (old_offset == data_offset) break;
1359 case ACN_DMP_VECTOR_SUBSCRIBE_REJECT:
1360 /* Rip trough Address-Reason Code Pairs */
1361 while (data_offset < end_offset) {
1362 old_offset = data_offset;
1363 data_offset = acn_add_dmp_address(tvb, pinfo, pdu_tree, data_offset, &adt);
1364 if (old_offset == data_offset) break;
1366 adt.data_length = data_length - (data_offset - old_offset);
1367 old_offset = data_offset;
1368 data_offset = acn_add_dmp_reason_codes(tvb, pinfo, pdu_tree, data_offset, &adt);
1369 if (old_offset == data_offset) break;
1372 case ACN_DMP_VECTOR_ALLOCATE_MAP:
1373 /* No data for this */
1375 case ACN_DMP_VECTOR_ALLOCATE_MAP_REPLY:
1376 /* Single reason code */
1377 proto_tree_add_item(pdu_tree, hf_acn_dmp_reason_code, tvb, data_offset, 1, FALSE);
1379 case ACN_DMP_VECTOR_DEALLOCATE_MAP:
1380 /* No data for this */
1384 return pdu_start + pdu_length;
1388 /******************************************************************************/
1389 /* Dissect wrapped SDT PDU */
1391 dissect_acn_sdt_wrapped_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree _U_, int offset, acn_pdu_offsets *last_pdu_offsets)
1393 /* common to all pdu */
1397 guint32 pdu_flvh_length; /* flags, length, vector, header */
1398 acn_pdu_offsets pdu_offsets = {0,0,0,0,0};
1403 guint32 vector_offset;
1404 guint32 data_offset;
1406 guint32 data_length;
1408 proto_item *ti, *pi;
1409 proto_tree *pdu_tree = NULL;
1410 proto_tree *flag_tree = NULL;
1416 /* save start of pdu block */
1418 pdu_offsets.start = pdu_start;
1420 /* get PDU flags and length flag first */
1421 octet = tvb_get_guint8(tvb, offset++);
1422 pdu_flags = octet & 0xf0;
1423 length1 = octet & 0x0f; /* bottom 4 bits only */
1424 length2 = tvb_get_guint8(tvb, offset++);
1426 /* if length flag is set, then we have a 20 bit length else we have a 12 bit */
1427 /* flvh = flags, length, vector, header */
1428 if (pdu_flags & ACN_PDU_FLAG_L) {
1429 length3 = tvb_get_guint8(tvb, offset);
1431 pdu_length = length3 | (length2 << 8) | (length1 << 16);
1432 pdu_flvh_length = 3;
1434 pdu_length = length2 | (length1 << 8);
1435 pdu_flvh_length = 2;
1437 /* offset should now be pointing to vector (if one exists) */
1439 /* Add pdu item and tree */
1440 ti = proto_tree_add_item(tree, hf_acn_pdu, tvb, pdu_start, pdu_length, FALSE);
1441 pdu_tree = proto_item_add_subtree(ti, ett_acn_sdt_pdu);
1443 /* Add flag item and tree */
1444 pi = proto_tree_add_uint(pdu_tree, hf_acn_pdu_flags, tvb, pdu_start, 1, pdu_flags);
1445 flag_tree = proto_item_add_subtree(pi, ett_acn_pdu_flags);
1446 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_l, tvb, pdu_start, 1, FALSE);
1447 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_v, tvb, pdu_start, 1, FALSE);
1448 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_h, tvb, pdu_start, 1, FALSE);
1449 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_d, tvb, pdu_start, 1, FALSE);
1451 /* Add PDU Length item */
1452 proto_tree_add_uint(pdu_tree, hf_acn_pdu_length, tvb, pdu_start, pdu_flvh_length, pdu_length);
1454 /* Set vector offset */
1455 if (pdu_flags & ACN_PDU_FLAG_V) {
1456 /* use new values */
1457 vector_offset = offset;
1458 last_pdu_offsets->vector = offset;
1462 /* use last values */
1463 vector_offset = last_pdu_offsets->vector;
1465 /* offset should now be pointing to header (if one exists) */
1467 /* Add Vector item */
1468 vector = tvb_get_guint8(tvb, vector_offset);
1469 proto_tree_add_uint(pdu_tree, hf_acn_sdt_vector, tvb, vector_offset, 1, vector);
1471 /* Add Vector item to tree*/
1472 ptr = match_strval(vector, acn_sdt_vector_vals);
1473 proto_item_append_text(ti, ": ");
1474 proto_item_append_text(ti, ptr);
1476 /* NO HEADER DATA ON THESE* (at least so far) */
1479 if (pdu_flags & ACN_PDU_FLAG_D) {
1480 /* use new values */
1481 data_offset = offset;
1482 data_length = pdu_length - pdu_flvh_length;
1483 last_pdu_offsets->data = offset;
1484 last_pdu_offsets->data_length = data_length;
1486 /* use last values */
1487 data_offset = last_pdu_offsets->data;
1488 data_length = last_pdu_offsets->data_length;
1490 end_offset = data_offset + data_length;
1493 case ACN_SDT_VECTOR_ACK:
1494 proto_tree_add_item(pdu_tree, hf_acn_reliable_sequence_number, tvb, data_offset, 4, FALSE);
1497 case ACN_SDT_VECTOR_CHANNEL_PARAMS:
1498 data_offset = acn_add_channel_parameter(tvb, pinfo, pdu_tree, data_offset);
1499 data_offset = acn_add_address(tvb, pinfo, pdu_tree, data_offset, "Ad-hoc Address:");
1500 data_offset = acn_add_expiry(tvb, pinfo, pdu_tree, data_offset, "Ad-hoc Expiry:");
1502 case ACN_SDT_VECTOR_LEAVE:
1505 case ACN_SDT_VECTOR_CONNECT:
1506 /* Protocol ID item */
1507 proto_tree_add_item(pdu_tree, hf_acn_protocol_id, tvb, data_offset, 4, FALSE);
1510 case ACN_SDT_VECTOR_CONNECT_ACCEPT:
1511 /* Protocol ID item */
1512 proto_tree_add_item(pdu_tree, hf_acn_protocol_id, tvb, data_offset, 4, FALSE);
1515 case ACN_SDT_VECTOR_CONNECT_REFUSE:
1516 /* Protocol ID item */
1517 proto_tree_add_item(pdu_tree, hf_acn_protocol_id, tvb, data_offset, 4, FALSE);
1519 proto_tree_add_item(pdu_tree, hf_acn_refuse_code, tvb, data_offset, 1, FALSE);
1522 case ACN_SDT_VECTOR_DISCONNECT:
1523 /* Protocol ID item */
1524 proto_tree_add_item(pdu_tree, hf_acn_protocol_id, tvb, data_offset, 4, FALSE);
1527 case ACN_SDT_VECTOR_DISCONNECTING:
1528 /* Protocol ID item */
1529 proto_tree_add_item(pdu_tree, hf_acn_protocol_id, tvb, data_offset, 4, FALSE);
1531 proto_tree_add_item(pdu_tree, hf_acn_reason_code, tvb, data_offset, 1, FALSE);
1537 return pdu_start + pdu_length;
1541 /******************************************************************************/
1542 /* Dissect SDT Client PDU */
1544 dissect_acn_sdt_client_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, acn_pdu_offsets *last_pdu_offsets)
1546 /* common to all pdu */
1550 guint32 pdu_flvh_length; /* flags, length, vector, header */
1551 acn_pdu_offsets pdu_offsets = {0,0,0,0,0};
1556 guint32 vector_offset;
1557 guint32 header_offset;
1558 guint32 data_offset;
1559 guint32 data_length;
1563 proto_item *ti, *pi;
1564 proto_tree *pdu_tree = NULL;
1565 proto_tree *flag_tree = NULL;
1570 guint32 protocol_id;
1571 guint16 association;
1573 /* save start of pdu block */
1575 pdu_offsets.start = pdu_start;
1577 /* get PDU flags and length flag first */
1578 octet = tvb_get_guint8(tvb, offset++);
1579 pdu_flags = octet & 0xf0;
1580 length1 = octet & 0x0f; /* bottom 4 bits only */
1581 length2 = tvb_get_guint8(tvb, offset++);
1583 /* if length flag is set, then we have a 20 bit length else we have a 12 bit */
1584 /* flvh = flags, length, vector, header */
1585 if (pdu_flags & ACN_PDU_FLAG_L) {
1586 length3 = tvb_get_guint8(tvb, offset);
1588 pdu_length = length3 | (length2 << 8) | (length1 << 16);
1589 pdu_flvh_length = 3;
1591 pdu_length = length2 | (length1 << 8);
1592 pdu_flvh_length = 2;
1594 /* offset should now be pointing to vector (if one exists) */
1596 /* Add pdu item and tree */
1597 ti = proto_tree_add_item(tree, hf_acn_pdu, tvb, pdu_start, pdu_length, FALSE);
1598 pdu_tree = proto_item_add_subtree(ti, ett_acn_sdt_client_pdu);
1600 /* Add flag item and tree */
1601 pi = proto_tree_add_uint(pdu_tree, hf_acn_pdu_flags, tvb, pdu_start, 1, pdu_flags);
1602 flag_tree = proto_item_add_subtree(pi, ett_acn_pdu_flags);
1603 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_l, tvb, pdu_start, 1, FALSE);
1604 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_v, tvb, pdu_start, 1, FALSE);
1605 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_h, tvb, pdu_start, 1, FALSE);
1606 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_d, tvb, pdu_start, 1, FALSE);
1608 /* Add PDU Length item */
1609 proto_tree_add_uint(pdu_tree, hf_acn_pdu_length, tvb, pdu_start, pdu_flvh_length, pdu_length);
1611 /* Set vector offset */
1612 if (pdu_flags & ACN_PDU_FLAG_V) {
1613 /* use new values */
1614 vector_offset = offset;
1615 last_pdu_offsets->vector = offset;
1617 pdu_flvh_length += 2;
1619 /* use last values */
1620 vector_offset = last_pdu_offsets->vector;
1622 /* offset should now be pointing to header (if one exists) */
1624 /* add Member ID item */
1625 member_id = tvb_get_ntohs(tvb, vector_offset);
1626 proto_tree_add_uint(pdu_tree, hf_acn_member_id, tvb, vector_offset, 2, member_id);
1628 /* Set header offset */
1629 if (pdu_flags & ACN_PDU_FLAG_H) {
1630 /* use new values */
1631 header_offset = offset;
1632 last_pdu_offsets->header = offset;
1634 pdu_flvh_length += 6;
1636 /* use last values */
1637 header_offset = last_pdu_offsets->header;
1639 /* offset should now be pointing to data (if one exists) */
1641 /* add Protocol ID item (Header)*/
1642 protocol_id = tvb_get_ntohl(tvb, header_offset);
1643 proto_tree_add_uint(pdu_tree, hf_acn_protocol_id, tvb, header_offset, 4, protocol_id);
1646 /* Add protocol to tree*/
1647 ptr = match_strval(protocol_id, acn_protocol_id_vals);
1648 proto_item_append_text(ti, ": ");
1649 proto_item_append_text(ti, ptr);
1651 /* add association item */
1652 association = tvb_get_ntohs(tvb, header_offset);
1653 proto_tree_add_uint(pdu_tree, hf_acn_association, tvb, header_offset, 2, association);
1657 if (pdu_flags & ACN_PDU_FLAG_D) {
1658 /* use new values */
1659 data_offset = offset;
1660 data_length = pdu_length - pdu_flvh_length;
1661 last_pdu_offsets->data = offset;
1662 last_pdu_offsets->data_length = data_length;
1664 /* use last values */
1665 data_offset = last_pdu_offsets->data;
1666 data_length = last_pdu_offsets->data_length;
1668 end_offset = data_offset + data_length;
1670 switch (protocol_id) {
1671 case ACN_PROTOCOL_ID_SDT:
1672 while (data_offset < end_offset) {
1673 old_offset = data_offset;
1674 data_offset = dissect_acn_sdt_wrapped_pdu(tvb, pinfo, pdu_tree, data_offset, &pdu_offsets);
1675 if (old_offset == data_offset) break;
1678 case ACN_PROTOCOL_ID_DMP:
1679 while (data_offset < end_offset) {
1680 old_offset = data_offset;
1681 data_offset = dissect_acn_dmp_pdu(tvb, pinfo, pdu_tree, data_offset, &pdu_offsets);
1682 if (data_offset == old_offset) break;
1686 return pdu_start + pdu_length;
1690 /******************************************************************************/
1691 /* reverses the characters in a string */
1697 for (i=0, j=strlen(s)-1; i < j; i++, j--) {
1705 /******************************************************************************/
1706 /* level to string (ascii) */
1707 /* level : 8 bit value */
1708 /* string : pointer to buffer to fill */
1709 /* leading_char: character to buffer left of digits */
1710 /* min_char : mininum number of characters (for filling, not including space)*/
1711 /* show_zero: show zeros or dots */
1712 /* also adds a space to right end */
1714 /* returns end of string */
1715 /* faster than printf() */
1717 ltos(guint8 level, gchar *string, guint8 base, gchar leading_char, guint8 min_chars, gboolean show_zero)
1721 if (base < 2 || base > 16) {
1725 /* deal with zeros */
1726 if ((level == 0) && (!show_zero)) {
1727 for (i=0;i<min_chars;i++) {
1736 /* do our convert, comes out backwords! */
1738 string[i++] = "0123456789ABCDEF"[level % base];
1739 } while ((level /= base) > 0);
1741 /* expand to needed character */
1742 for (;i<min_chars;i++) {
1743 string[i] = leading_char;
1748 /* now reverse (and correct) the order */
1751 /* add a space at the end (ok its at the start but it will be at the end)*/
1758 /******************************************************************************/
1759 /* Dissect DMX data PDU */
1761 dissect_acn_dmx_data_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, acn_pdu_offsets *last_pdu_offsets)
1763 /* common to all pdu */
1767 guint32 pdu_flvh_length; /* flags, length, vector, header */
1768 acn_pdu_offsets pdu_offsets = {0,0,0,0,0};
1773 guint32 vector_offset;
1774 guint32 data_offset;
1777 guint32 data_length;
1778 guint32 header_offset;
1783 proto_item *ti, *pi;
1784 proto_tree *pdu_tree = NULL;
1785 proto_tree *flag_tree = NULL;
1786 /* proto_tree *addr_tree = NULL; */
1789 acn_dmp_adt_type adt = {0,0,0,0,0,0};
1801 /* save start of pdu block */
1803 pdu_offsets.start = pdu_start;
1805 /* get PDU flags and length flag first */
1806 octet = tvb_get_guint8(tvb, offset++);
1807 pdu_flags = octet & 0xf0;
1808 length1 = octet & 0x0f; /* bottom 4 bits only */
1809 length2 = tvb_get_guint8(tvb, offset++);
1811 /* if length flag is set, then we have a 20 bit length else we have a 12 bit */
1812 /* flvh = flags, length, vector, header */
1813 if (pdu_flags & ACN_PDU_FLAG_L) {
1814 length3 = tvb_get_guint8(tvb, offset);
1816 pdu_length = length3 | (length2 << 8) | (length1 << 16);
1817 pdu_flvh_length = 3;
1819 pdu_length = length2 | (length1 << 8);
1820 pdu_flvh_length = 2;
1822 /* offset should now be pointing to vector (if one exists) */
1824 /* Add pdu item and tree */
1825 ti = proto_tree_add_item(tree, hf_acn_pdu, tvb, pdu_start, pdu_length, FALSE);
1826 pdu_tree = proto_item_add_subtree(ti, ett_acn_dmx_data_pdu);
1828 /* Add flag item and tree */
1829 pi = proto_tree_add_uint(pdu_tree, hf_acn_pdu_flags, tvb, pdu_start, 1, pdu_flags);
1830 flag_tree = proto_item_add_subtree(pi, ett_acn_pdu_flags);
1831 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_l, tvb, pdu_start, 1, FALSE);
1832 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_v, tvb, pdu_start, 1, FALSE);
1833 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_h, tvb, pdu_start, 1, FALSE);
1834 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_d, tvb, pdu_start, 1, FALSE);
1836 /* Add PDU Length item */
1837 proto_tree_add_uint(pdu_tree, hf_acn_pdu_length, tvb, pdu_start, pdu_flvh_length, pdu_length);
1839 /* Set vector offset */
1840 if (pdu_flags & ACN_PDU_FLAG_V) {
1841 /* use new values */
1842 vector_offset = offset;
1843 last_pdu_offsets->vector = offset;
1845 pdu_flvh_length += 1;
1847 /* use last values */
1848 vector_offset = last_pdu_offsets->vector;
1850 /* offset should now be pointing to header (if one exists) */
1852 /* Add Vector item */
1853 vector = tvb_get_guint8(tvb, vector_offset);
1854 proto_tree_add_uint(pdu_tree, hf_acn_dmp_vector, tvb, vector_offset, 1, vector);
1856 /* Add Vector item to tree*/
1857 ptr = match_strval(vector, acn_dmp_vector_vals);
1858 proto_item_append_text(ti, ": ");
1859 proto_item_append_text(ti, ptr);
1861 /* Set header offset */
1862 if (pdu_flags & ACN_PDU_FLAG_H) {
1863 /* use new values */
1864 header_offset = offset;
1865 last_pdu_offsets->header = offset;
1869 /* use last values */
1870 header_offset = last_pdu_offsets->header;
1872 /* offset should now be pointing to data (if one exists) */
1874 /* process based on vector */
1875 acn_add_dmp_address_type(tvb, pinfo, pdu_tree, header_offset, &adt);
1878 if (pdu_flags & ACN_PDU_FLAG_D) {
1879 /* use new values */
1880 data_offset = offset;
1881 data_length = pdu_length - pdu_flvh_length;
1882 last_pdu_offsets->data = offset;
1883 last_pdu_offsets->data_length = data_length;
1885 /* use last values */
1886 data_offset = last_pdu_offsets->data;
1887 data_length = last_pdu_offsets->data_length;
1889 end_offset = data_offset + data_length;
1892 case ACN_DMP_VECTOR_SET_PROPERTY:
1893 old_offset = data_offset;
1894 data_offset = acn_add_dmp_address(tvb, pinfo, pdu_tree, data_offset, &adt);
1895 if (data_offset == old_offset) break;
1897 #define BUFFER_SIZE 128
1899 buffer = ep_alloc(BUFFER_SIZE);
1903 /* values base on display mode */
1904 switch ((guint)global_acn_dmx_display_view) {
1905 case ACN_PREF_DMX_DISPLAY_HEX:
1909 /* case ACN_PREF_DMX_DISPLAY_PER: */
1915 /* do we display leading zeros */
1916 if (global_acn_dmx_display_leading_zeros) {
1922 /* add a header line */
1923 memset(buffer, ' ', 10);
1925 for (x=1;x<=20;x++) {
1926 buf_ptr = ltos((guint8)x, buf_ptr, 10, ' ', min_char, FALSE);
1933 proto_tree_add_text(pdu_tree, tvb, data_offset, 0, buffer);
1935 /* start our line */
1936 g_snprintf(buffer, BUFFER_SIZE, "001-020: ");
1937 buf_ptr = buffer + 9;
1941 for (x=data_offset; x < end_offset; x++) {
1942 level = tvb_get_guint8(tvb, x);
1943 if (global_acn_dmx_display_view==ACN_PREF_DMX_DISPLAY_PER) {
1944 if ((level > 0) && (level < 3)) {
1947 level = level * 100 / 255;
1950 buf_ptr = ltos(level, buf_ptr, base, leading_char, min_char, global_acn_dmx_display_zeros);
1954 if (item_cnt == 20 || x == (end_offset-1)) {
1956 proto_tree_add_text(pdu_tree, tvb, data_offset, item_cnt, buffer);
1958 g_snprintf(buffer, BUFFER_SIZE, "%03d-%03d: ",total_cnt, total_cnt+20);
1959 buf_ptr = buffer + 9;
1962 /* add separater character */
1963 if (item_cnt == 10) {
1971 address data type (fixed at 0xA2)
1972 start code - 1 byte, reserved (should be 0)
1973 - 1 byte, start code (0x255)
1974 - 2 bytes, packet offset (should be 0000)
1975 address increment - 4 bytes (ignore)
1976 number of dmx values - 4 bytes (0-512)
1977 dmx values 0-512 bytes (data)
1982 return pdu_start + pdu_length;
1987 /******************************************************************************/
1988 /* Dissect DMX Base PDU */
1990 dissect_acn_dmx_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, acn_pdu_offsets *last_pdu_offsets)
1992 /* common to all pdu */
1996 guint32 pdu_flvh_length; /* flags, length, vector, header */
1997 acn_pdu_offsets pdu_offsets = {0,0,0,0,0};
2002 guint32 vector_offset;
2003 guint32 data_offset;
2005 guint32 data_length;
2007 proto_item *ti, *pi;
2008 proto_tree *pdu_tree = NULL;
2009 proto_tree *flag_tree = NULL;
2017 /* save start of pdu block */
2019 pdu_offsets.start = pdu_start;
2021 /* get PDU flags and length flag first */
2022 octet = tvb_get_guint8(tvb, offset++);
2023 pdu_flags = octet & 0xf0;
2024 length1 = octet & 0x0f; /* bottom 4 bits only */
2025 length2 = tvb_get_guint8(tvb, offset++);
2027 /* if length flag is set, then we have a 20 bit length else we have a 12 bit */
2028 /* flvh = flags, length, vector, header */
2029 if (pdu_flags & ACN_PDU_FLAG_L) {
2030 length3 = tvb_get_guint8(tvb, offset);
2032 pdu_length = length3 | (length2 << 8) | (length1 << 16);
2033 pdu_flvh_length = 3;
2035 pdu_length = length2 | (length1 << 8);
2036 pdu_flvh_length = 2;
2039 /* offset should now be pointing to vector (if one exists) */
2041 /* Add pdu item and tree */
2042 ti = proto_tree_add_item(tree, hf_acn_pdu, tvb, pdu_start, pdu_length, FALSE);
2043 pdu_tree = proto_item_add_subtree(ti, ett_acn_dmx_pdu);
2045 /* Add flag item and tree */
2046 pi = proto_tree_add_uint(pdu_tree, hf_acn_pdu_flags, tvb, pdu_start, 1, pdu_flags);
2047 flag_tree = proto_item_add_subtree(pi, ett_acn_pdu_flags);
2048 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_l, tvb, pdu_start, 1, FALSE);
2049 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_v, tvb, pdu_start, 1, FALSE);
2050 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_h, tvb, pdu_start, 1, FALSE);
2051 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_d, tvb, pdu_start, 1, FALSE);
2053 /* Add PDU Length item */
2054 proto_tree_add_uint(pdu_tree, hf_acn_pdu_length, tvb, pdu_start, pdu_flvh_length, pdu_length);
2056 /* Set vector offset */
2057 if (pdu_flags & ACN_PDU_FLAG_V) {
2058 /* use new values */
2059 vector_offset = offset;
2060 last_pdu_offsets->vector = offset;
2062 pdu_flvh_length += 4;
2064 /* use last values */
2065 vector_offset = last_pdu_offsets->vector;
2067 /* offset should now be pointing to header (if one exists) */
2069 /* Add Vector item */
2070 vector = tvb_get_ntohl(tvb, vector_offset);
2071 proto_tree_add_item(pdu_tree, hf_acn_dmx_vector, tvb, vector_offset, 4, FALSE);
2072 /* vector_offset +=4; */
2074 /* Add Vector item to tree*/
2075 proto_item_append_text(ti, ": %s", match_strval(vector, acn_dmx_vector_vals));
2077 /* NO HEADER DATA ON THESE* (at least so far) */
2080 if (pdu_flags & ACN_PDU_FLAG_D) {
2081 /* use new values */
2082 data_offset = offset;
2083 data_length = pdu_length - pdu_flvh_length;
2084 last_pdu_offsets->data = offset;
2085 last_pdu_offsets->data_length = data_length;
2087 /* use last values */
2088 data_offset = last_pdu_offsets->data;
2089 data_length = last_pdu_offsets->data_length;
2091 end_offset = data_offset + data_length;
2093 /* process based on vector */
2096 proto_tree_add_item(pdu_tree, hf_acn_dmx_source_name, tvb, data_offset, 32, FALSE);
2099 priority = tvb_get_guint8(tvb, data_offset);
2100 proto_tree_add_item(pdu_tree, hf_acn_dmx_priority, tvb, data_offset, 1, FALSE);
2103 proto_tree_add_item(pdu_tree, hf_acn_dmx_sequence_number, tvb, data_offset, 1, FALSE);
2106 universe = tvb_get_ntohs(tvb, data_offset);
2107 proto_tree_add_item(pdu_tree, hf_acn_dmx_universe , tvb, data_offset, 2, FALSE);
2110 proto_item_append_text(ti, ", Universe: %d, Priority: %d", universe, priority);
2112 data_offset = dissect_acn_dmx_data_pdu(tvb, pinfo, pdu_tree, data_offset, &pdu_offsets);
2116 return pdu_start + pdu_length;
2119 /******************************************************************************/
2120 /* Dissect SDT Base PDU */
2122 dissect_acn_sdt_base_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, acn_pdu_offsets *last_pdu_offsets)
2124 /* common to all pdu */
2128 guint32 pdu_flvh_length; /* flags, length, vector, header */
2129 acn_pdu_offsets pdu_offsets = {0,0,0,0,0};
2134 guint32 vector_offset;
2135 guint32 data_offset;
2138 guint32 data_length;
2140 proto_item *ti, *pi;
2141 proto_tree *pdu_tree = NULL;
2142 proto_tree *flag_tree = NULL;
2149 /* save start of pdu block */
2151 pdu_offsets.start = pdu_start;
2153 /* get PDU flags and length flag first */
2154 octet = tvb_get_guint8(tvb, offset++);
2155 pdu_flags = octet & 0xf0;
2156 length1 = octet & 0x0f; /* bottom 4 bits only */
2157 length2 = tvb_get_guint8(tvb, offset++);
2159 /* if length flag is set, then we have a 20 bit length else we have a 12 bit */
2160 /* flvh = flags, length, vector, header */
2161 if (pdu_flags & ACN_PDU_FLAG_L) {
2162 length3 = tvb_get_guint8(tvb, offset);
2164 pdu_length = length3 | (length2 << 8) | (length1 << 16);
2165 pdu_flvh_length = 3;
2167 pdu_length = length2 | (length1 << 8);
2168 pdu_flvh_length = 2;
2170 /* offset should now be pointing to vector (if one exists) */
2172 /* Add pdu item and tree */
2173 ti = proto_tree_add_item(tree, hf_acn_pdu, tvb, pdu_start, pdu_length, FALSE);
2174 pdu_tree = proto_item_add_subtree(ti, ett_acn_sdt_base_pdu);
2176 /* Add flag item and tree */
2177 pi = proto_tree_add_uint(pdu_tree, hf_acn_pdu_flags, tvb, pdu_start, 1, pdu_flags);
2178 flag_tree = proto_item_add_subtree(pi, ett_acn_pdu_flags);
2179 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_l, tvb, pdu_start, 1, FALSE);
2180 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_v, tvb, pdu_start, 1, FALSE);
2181 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_h, tvb, pdu_start, 1, FALSE);
2182 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_d, tvb, pdu_start, 1, FALSE);
2184 /* Add PDU Length item */
2185 proto_tree_add_uint(pdu_tree, hf_acn_pdu_length, tvb, pdu_start, pdu_flvh_length, pdu_length);
2187 /* Set vector offset */
2188 if (pdu_flags & ACN_PDU_FLAG_V) {
2189 /* use new values */
2190 vector_offset = offset;
2191 last_pdu_offsets->vector = offset;
2195 /* use last values */
2196 vector_offset = last_pdu_offsets->vector;
2198 /* offset should now be pointing to header (if one exists) */
2200 /* Add Vector item */
2201 vector = tvb_get_guint8(tvb, vector_offset);
2202 proto_tree_add_uint(pdu_tree, hf_acn_sdt_vector, tvb, vector_offset, 1, vector);
2204 /* Add Vector item to tree*/
2205 ptr = match_strval(vector, acn_sdt_vector_vals);
2206 proto_item_append_text(ti, ": ");
2207 proto_item_append_text(ti, ptr);
2209 /* NO HEADER DATA ON THESE* (at least so far) */
2212 if (pdu_flags & ACN_PDU_FLAG_D) {
2213 /* use new values */
2214 data_offset = offset;
2215 data_length = pdu_length - pdu_flvh_length;
2216 last_pdu_offsets->data = offset;
2217 last_pdu_offsets->data_length = data_length;
2219 /* use last values */
2220 data_offset = last_pdu_offsets->data;
2221 data_length = last_pdu_offsets->data_length;
2223 end_offset = data_offset + data_length;
2225 /* process based on vector */
2227 case ACN_SDT_VECTOR_UNKNOWN:
2229 case ACN_SDT_VECTOR_REL_WRAP:
2230 case ACN_SDT_VECTOR_UNREL_WRAP:
2231 proto_tree_add_item(pdu_tree, hf_acn_channel_number, tvb, data_offset, 2, FALSE);
2233 proto_tree_add_item(pdu_tree, hf_acn_total_sequence_number, tvb, data_offset, 4, FALSE);
2235 proto_tree_add_item(pdu_tree, hf_acn_reliable_sequence_number, tvb, data_offset, 4, FALSE);
2237 proto_tree_add_item(pdu_tree, hf_acn_oldest_available_wrapper, tvb, data_offset, 4, FALSE);
2239 proto_tree_add_item(pdu_tree, hf_acn_first_memeber_to_ack, tvb, data_offset, 2, FALSE);
2241 proto_tree_add_item(pdu_tree, hf_acn_last_memeber_to_ack, tvb, data_offset, 2, FALSE);
2243 proto_tree_add_item(pdu_tree, hf_acn_mak_threshold, tvb, data_offset, 2, FALSE);
2246 while (data_offset < end_offset) {
2247 old_offset = data_offset;
2248 data_offset = dissect_acn_sdt_client_pdu(tvb, pinfo, pdu_tree, data_offset, &pdu_offsets);
2249 if (data_offset == old_offset) break;
2252 case ACN_SDT_VECTOR_CHANNEL_PARAMS:
2254 case ACN_SDT_VECTOR_JOIN:
2255 proto_tree_add_item(pdu_tree, hf_acn_cid, tvb, data_offset, 16, FALSE);
2257 proto_tree_add_item(pdu_tree, hf_acn_member_id, tvb, data_offset, 2, FALSE);
2259 proto_tree_add_item(pdu_tree, hf_acn_channel_number, tvb, data_offset, 2, FALSE);
2261 proto_tree_add_item(pdu_tree, hf_acn_reciprocal_channel, tvb, data_offset, 2, FALSE);
2263 proto_tree_add_item(pdu_tree, hf_acn_total_sequence_number, tvb, data_offset, 4, FALSE);
2265 proto_tree_add_item(pdu_tree, hf_acn_reliable_sequence_number, tvb, data_offset, 4, FALSE);
2267 data_offset = acn_add_address(tvb, pinfo, pdu_tree, data_offset, "Destination Address:");
2268 data_offset = acn_add_channel_parameter(tvb, pinfo, pdu_tree, data_offset);
2269 data_offset = acn_add_expiry(tvb, pinfo, pdu_tree, data_offset, "Ad-hoc Expiry:");
2271 case ACN_SDT_VECTOR_JOIN_REFUSE:
2272 pi = proto_tree_add_item(pdu_tree, hf_acn_cid, tvb, data_offset, 16, FALSE);
2274 proto_item_append_text(pi, "(Leader)");
2275 proto_tree_add_item(pdu_tree, hf_acn_channel_number, tvb, data_offset, 2, FALSE);
2277 proto_tree_add_item(pdu_tree, hf_acn_member_id, tvb, data_offset, 2, FALSE);
2279 proto_tree_add_item(pdu_tree, hf_acn_reliable_sequence_number, tvb, data_offset, 4, FALSE);
2281 proto_tree_add_item(pdu_tree, hf_acn_refuse_code, tvb, data_offset, 1, FALSE);
2284 case ACN_SDT_VECTOR_JOIN_ACCEPT:
2285 pi = proto_tree_add_item(pdu_tree, hf_acn_cid, tvb, data_offset, 16, FALSE);
2287 proto_item_append_text(pi, "(Leader)");
2288 proto_tree_add_item(pdu_tree, hf_acn_channel_number, tvb, data_offset, 2, FALSE);
2290 proto_tree_add_item(pdu_tree, hf_acn_member_id, tvb, data_offset, 2, FALSE);
2292 proto_tree_add_item(pdu_tree, hf_acn_reliable_sequence_number, tvb, data_offset, 4, FALSE);
2294 proto_tree_add_item(pdu_tree, hf_acn_reciprocal_channel, tvb, data_offset, 2, FALSE);
2297 case ACN_SDT_VECTOR_LEAVE:
2299 case ACN_SDT_VECTOR_LEAVING:
2300 pi = proto_tree_add_item(pdu_tree, hf_acn_cid, tvb, data_offset, 16, FALSE);
2302 proto_item_append_text(pi, "(Leader)");
2303 proto_tree_add_item(pdu_tree, hf_acn_channel_number, tvb, data_offset, 2, FALSE);
2305 proto_tree_add_item(pdu_tree, hf_acn_member_id, tvb, data_offset, 2, FALSE);
2307 proto_tree_add_item(pdu_tree, hf_acn_reliable_sequence_number, tvb, data_offset, 4, FALSE);
2309 proto_tree_add_item(pdu_tree, hf_acn_reason_code, tvb, data_offset, 1, FALSE);
2312 case ACN_SDT_VECTOR_CONNECT:
2314 case ACN_SDT_VECTOR_CONNECT_ACCEPT:
2316 case ACN_SDT_VECTOR_CONNECT_REFUSE:
2318 case ACN_SDT_VECTOR_DISCONNECT:
2320 case ACN_SDT_VECTOR_DISCONNECTING:
2322 case ACN_SDT_VECTOR_ACK:
2324 case ACN_SDT_VECTOR_NAK:
2325 pi = proto_tree_add_item(pdu_tree, hf_acn_cid, tvb, data_offset, 16, FALSE);
2327 proto_item_append_text(pi, "(Leader)");
2328 proto_tree_add_item(pdu_tree, hf_acn_channel_number, tvb, data_offset, 2, FALSE);
2330 proto_tree_add_item(pdu_tree, hf_acn_member_id, tvb, data_offset, 2, FALSE);
2332 proto_tree_add_item(pdu_tree, hf_acn_reliable_sequence_number, tvb, data_offset, 4, FALSE);
2334 proto_tree_add_item(pdu_tree, hf_acn_first_missed_sequence, tvb, data_offset, 4, FALSE);
2336 proto_tree_add_item(pdu_tree, hf_acn_last_missed_sequence, tvb, data_offset, 4, FALSE);
2339 case ACN_SDT_VECTOR_GET_SESSION:
2340 proto_tree_add_item(pdu_tree, hf_acn_cid, tvb, data_offset, 16, FALSE);
2343 case ACN_SDT_VECTOR_SESSIONS:
2344 member_id = tvb_get_ntohs(tvb, data_offset);
2345 switch (member_id) {
2347 data_offset = acn_add_channel_owner_info_block(tvb, pinfo, pdu_tree, data_offset);
2350 data_offset = acn_add_channel_member_info_block(tvb, pinfo, pdu_tree, data_offset);
2356 return pdu_start + pdu_length;
2359 /******************************************************************************/
2360 /* Dissect Root PDU */
2362 dissect_acn_root_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, acn_pdu_offsets *last_pdu_offsets)
2364 /* common to all pdu */
2368 guint32 pdu_flvh_length; /* flags, length, vector, header */
2369 acn_pdu_offsets pdu_offsets = {0,0,0,0,0};
2374 guint32 vector_offset;
2375 guint32 header_offset;
2376 guint32 data_offset;
2379 guint32 data_length;
2381 proto_item *ti, *pi;
2382 proto_tree *pdu_tree = NULL;
2383 proto_tree *flag_tree = NULL;
2386 guint32 protocol_id;
2389 /* save start of pdu block */
2391 pdu_offsets.start = pdu_start;
2393 /* get PDU flags and length flag first */
2394 octet = tvb_get_guint8(tvb, offset++);
2395 pdu_flags = octet & 0xf0;
2396 length1 = octet & 0x0f; /* bottom 4 bits only */
2397 length2 = tvb_get_guint8(tvb, offset++);
2399 /* if length flag is set, then we have a 20 bit length else we have a 12 bit */
2400 /* flvh = flags, length, vector, header */
2401 if (pdu_flags & ACN_PDU_FLAG_L) {
2402 length3 = tvb_get_guint8(tvb, offset);
2404 pdu_length = length3 | (length2 << 8) | (length1 << 16);
2405 pdu_flvh_length = 3;
2407 pdu_length = length2 | (length1 << 8);
2408 pdu_flvh_length = 2;
2410 /* offset should now be pointing to vector (if one exists) */
2412 /* Add pdu item and tree */
2413 ti = proto_tree_add_item(tree, hf_acn_pdu, tvb, pdu_start, pdu_length, FALSE);
2414 pdu_tree = proto_item_add_subtree(ti, ett_acn_root_pdu);
2416 /* Add flag item and tree */
2417 pi = proto_tree_add_uint(pdu_tree, hf_acn_pdu_flags, tvb, pdu_start, 1, pdu_flags);
2418 flag_tree = proto_item_add_subtree(pi, ett_acn_pdu_flags);
2419 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_l, tvb, pdu_start, 1, FALSE);
2420 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_v, tvb, pdu_start, 1, FALSE);
2421 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_h, tvb, pdu_start, 1, FALSE);
2422 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_d, tvb, pdu_start, 1, FALSE);
2424 /* Add PDU Length item */
2425 proto_tree_add_uint(pdu_tree, hf_acn_pdu_length, tvb, pdu_start, pdu_flvh_length, pdu_length);
2427 /* Set vector offset */
2428 if (pdu_flags & ACN_PDU_FLAG_V) {
2429 /* use new values */
2430 vector_offset = offset;
2431 last_pdu_offsets->vector = offset;
2433 pdu_flvh_length += 4;
2435 /* use last values */
2436 vector_offset = last_pdu_offsets->vector;
2438 /* offset should now be pointing to header (if one exists) */
2442 /* Get Protocol ID (vector) */
2443 protocol_id = tvb_get_ntohl(tvb, vector_offset);
2444 proto_tree_add_uint(pdu_tree, hf_acn_protocol_id, tvb, vector_offset, 4, protocol_id);
2446 /* process based on protocol_id */
2447 switch (protocol_id) {
2448 case ACN_PROTOCOL_ID_DMX:
2449 if (global_acn_dmx_enable) {
2450 proto_item_append_text(ti,": Root DMX");
2452 /* Set header offset */
2453 if (pdu_flags & ACN_PDU_FLAG_H) {
2454 /* use new values */
2455 header_offset = offset;
2456 last_pdu_offsets->header = offset;
2458 pdu_flvh_length += 16;
2460 /* use last values */
2461 header_offset = last_pdu_offsets->header;
2463 /* offset should now be pointing to data (if one exists) */
2465 /* get Header (CID) 16 bytes */
2466 tvb_get_guid(tvb, header_offset, &guid, FALSE);
2467 proto_item_append_text(ti, ", Src: %s", guid_to_str(&guid));
2469 proto_tree_add_item(pdu_tree, hf_acn_cid, tvb, header_offset, 16, FALSE);
2470 header_offset += 16;
2473 if (pdu_flags & ACN_PDU_FLAG_D) {
2474 /* use new values */
2475 data_offset = offset;
2476 data_length = pdu_length - pdu_flvh_length;
2477 last_pdu_offsets->data = offset;
2478 last_pdu_offsets->data_length = data_length;
2480 /* use last values */
2481 data_offset = last_pdu_offsets->data;
2482 data_length = last_pdu_offsets->data_length;
2484 end_offset = data_offset + data_length;
2486 /* adjust for what we used */
2487 while (data_offset < end_offset) {
2488 old_offset = data_offset;
2489 data_offset = dissect_acn_dmx_pdu(tvb, pinfo, pdu_tree, data_offset, &pdu_offsets);
2490 if (data_offset == old_offset) break;
2494 case ACN_PROTOCOL_ID_SDT:
2496 proto_item_append_text(ti,": Root SDT");
2498 /* Set header offset */
2499 if (pdu_flags & ACN_PDU_FLAG_H) {
2500 /* use new values */
2501 header_offset = offset;
2502 last_pdu_offsets->header = offset;
2504 pdu_flvh_length += 16;
2506 /* use last values */
2507 header_offset = last_pdu_offsets->header;
2509 /* offset should now be pointing to data (if one exists) */
2511 /* get Header (CID) 16 bytes */
2512 tvb_get_guid(tvb, header_offset, &guid, FALSE);
2513 proto_item_append_text(ti, ", Src: %s", guid_to_str(&guid));
2515 proto_tree_add_item(pdu_tree, hf_acn_cid, tvb, header_offset, 16, FALSE);
2516 header_offset += 16;
2519 if (pdu_flags & ACN_PDU_FLAG_D) {
2520 /* use new values */
2521 data_offset = offset;
2522 data_length = pdu_length - pdu_flvh_length;
2523 last_pdu_offsets->data = offset;
2524 last_pdu_offsets->data_length = data_length;
2526 /* use last values */
2527 data_offset = last_pdu_offsets->data;
2528 data_length = last_pdu_offsets->data_length;
2530 end_offset = data_offset + data_length;
2532 /* adjust for what we used */
2533 while (data_offset < end_offset) {
2534 old_offset = data_offset;
2535 data_offset = dissect_acn_sdt_base_pdu(tvb, pinfo, pdu_tree, data_offset, &pdu_offsets);
2536 if (data_offset == old_offset) break;
2541 return pdu_start + pdu_length;
2544 /******************************************************************************/
2547 dissect_acn(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
2549 proto_item *ti = NULL;
2550 proto_tree *acn_tree = NULL;
2551 guint32 data_offset = 0;
2554 acn_pdu_offsets pdu_offsets = {0,0,0,0,0};
2556 /* if (!is_acn(tvb)) { */
2560 /* Set the protocol column */
2561 if (check_col(pinfo->cinfo, COL_PROTOCOL)) {
2562 col_set_str(pinfo->cinfo, COL_PROTOCOL, "ACN");
2565 /* Clear out stuff in the info column */
2566 if(check_col(pinfo->cinfo,COL_INFO)){
2567 /* col_clear(pinfo->cinfo,COL_INFO); */
2568 col_add_fstr(pinfo->cinfo,COL_INFO, "ACN [Src Port: %d, Dst Port: %d]", pinfo->srcport, pinfo->destport );
2571 if (tree) { /* we are being asked for details */
2572 ti = proto_tree_add_item(tree, proto_acn, tvb, 0, -1, FALSE);
2573 acn_tree = proto_item_add_subtree(ti, ett_acn);
2575 pdu_offsets.start = data_offset;
2577 /* add preamble, postamble and ACN Packet ID */
2578 proto_tree_add_item(acn_tree, hf_acn_preamble_size, tvb, data_offset, 2, FALSE);
2580 proto_tree_add_item(acn_tree, hf_acn_postamble_size, tvb, data_offset, 2, FALSE);
2582 proto_tree_add_item(acn_tree, hf_acn_packet_identifier, tvb, data_offset, 12, FALSE);
2585 /* one past the last byte */
2586 end_offset = data_offset + tvb_reported_length_remaining(tvb, data_offset);
2587 while (data_offset < end_offset) {
2588 old_offset = data_offset;
2589 data_offset = dissect_acn_root_pdu(tvb, pinfo, acn_tree, data_offset, &pdu_offsets);
2590 if (data_offset == old_offset) break;
2593 return tvb_length(tvb);
2596 /******************************************************************************/
2597 /* Register protocol */
2598 void proto_register_acn(void)
2600 static hf_register_info hf[] = {
2601 /**************************************************************************/
2602 /* In alphabetical order */
2605 { &hf_acn_ip_address_type,
2606 { "Type", "acn.ip_address_type",
2607 FT_UINT8, BASE_DEC, VALS(acn_ip_address_type_vals), 0x0,
2611 { &hf_acn_association,
2612 { "Association", "acn.association",
2613 FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
2614 "Association", HFILL }
2616 /* Channel Number */
2617 { &hf_acn_channel_number,
2618 { "Channel Number", "acn.channel_number",
2619 FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
2620 "Channel Number", HFILL }
2625 FT_GUID, BASE_NONE, NULL, 0x0,
2628 /* Client Protocol ID */
2629 { &hf_acn_client_protocol_id,
2630 { "Client Protocol ID", "acn.client_protocol_id",
2631 FT_UINT32, BASE_DEC, VALS(acn_protocol_id_vals), 0x0,
2632 "ClientProtocol ID", HFILL }
2636 { "Data", "acn.dmp_data",
2637 FT_BYTES, BASE_HEX, NULL, 0x0,
2641 { "Addr", "acn.dmp_data8",
2642 FT_INT8, BASE_DEC_HEX, NULL, 0x0,
2646 { "Addr", "acn.dmp_data16",
2647 FT_INT16, BASE_DEC_HEX, NULL, 0x0,
2651 { "Addr", "acn.dmp_data24",
2652 FT_INT24, BASE_DEC_HEX, NULL, 0x0,
2656 { "Addr", "acn.dmp_data32",
2657 FT_INT32, BASE_DEC_HEX, NULL, 0x0,
2661 { &hf_acn_dmp_address_data_pairs,
2662 { "Address-Data Pairs", "acn.dmp_address_data_pairs",
2663 FT_BYTES, BASE_DEC, NULL, 0x0,
2664 "More address-data pairs", HFILL }
2668 { &hf_acn_dmp_address1,
2669 { "Address", "acn.dmp_address",
2670 FT_UINT8, BASE_DEC_HEX, NULL, 0x0,
2673 { &hf_acn_dmp_address2,
2674 { "Address", "acn.dmp_address",
2675 FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
2678 { &hf_acn_dmp_address4,
2679 { "Address", "acn.dmp_address",
2680 FT_UINT32, BASE_DEC_HEX, NULL, 0x0,
2684 /* DMP Address type*/
2686 { "Address and Data Type", "acn.dmp_adt",
2687 FT_UINT8, BASE_DEC_HEX, NULL, 0x0,
2688 "Address and Data Type", HFILL }
2690 { &hf_acn_dmp_adt_a,
2691 { "Size", "acn.dmp_adt_a",
2692 FT_UINT8, BASE_DEC, VALS(acn_dmp_adt_a_vals), 0x03,
2695 { &hf_acn_dmp_adt_d,
2696 { "Data Type", "acn.dmp_adt_d",
2697 FT_UINT8, BASE_DEC, VALS(acn_dmp_adt_d_vals), 0x30,
2698 "Data Type", HFILL }
2700 { &hf_acn_dmp_adt_r,
2701 { "Relative", "acn.dmp_adt_r",
2702 FT_UINT8, BASE_DEC, VALS(acn_dmp_adt_r_vals), 0x40,
2705 { &hf_acn_dmp_adt_v,
2706 { "Virtual", "acn.dmp_adt_v",
2707 FT_UINT8, BASE_DEC, VALS(acn_dmp_adt_v_vals), 0x80,
2710 { &hf_acn_dmp_adt_x,
2711 { "Reserved", "acn.dmp_adt_x",
2712 FT_UINT8, BASE_DEC, NULL, 0x0c,
2716 /* DMP Reason Code */
2717 { &hf_acn_dmp_reason_code,
2718 { "Reason Code", "acn.dmp_reason_code",
2719 FT_UINT8, BASE_DEC, VALS(acn_dmp_reason_code_vals), 0x0,
2720 "Reason Code", HFILL }
2724 { &hf_acn_dmp_vector,
2725 { "DMP Vector", "acn.dmp_vector",
2726 FT_UINT8, BASE_DEC, VALS(acn_dmp_vector_vals), 0x0,
2727 "DMP Vector", HFILL }
2731 { "Expiry", "acn.expiry",
2732 FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
2735 /* First Member to ACK */
2736 { &hf_acn_first_memeber_to_ack,
2737 { "First Member to ACK", "acn.first_member_to_ack",
2738 FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
2739 "First Member to ACK", HFILL }
2741 /* First Missed Sequence */
2742 { &hf_acn_first_missed_sequence,
2743 { "First Missed Sequence", "acn.first_missed_sequence",
2744 FT_UINT32, BASE_DEC_HEX, NULL, 0x0,
2745 "First Missed Sequence", HFILL }
2749 { "IPV4", "acn.ipv4",
2750 FT_IPv4, BASE_NONE, NULL, 0x0,
2755 { "IPV6", "acn.ipv6",
2756 FT_IPv6, BASE_NONE, NULL, 0x0,
2759 /* Last Member to ACK */
2760 { &hf_acn_last_memeber_to_ack,
2761 { "Last Member to ACK", "acn.last_member_to_ack",
2762 FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
2763 "Last Member to ACK", HFILL }
2765 /* Last Missed Sequence */
2766 { &hf_acn_last_missed_sequence,
2767 { "Last Missed Sequence", "acn.last_missed_sequence",
2768 FT_UINT32, BASE_DEC_HEX, NULL, 0x0,
2769 "Last Missed Sequence", HFILL }
2772 { &hf_acn_mak_threshold,
2773 { "MAK Threshold", "acn.mak_threshold",
2774 FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
2775 "MAK Threshold", HFILL }
2778 { &hf_acn_member_id,
2779 { "Member ID", "acn.member_id",
2780 FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
2781 "Member ID", HFILL }
2784 { &hf_acn_nak_holdoff,
2785 { "NAK holdoff (ms)", "acn.nak_holdoff",
2786 FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
2787 "NAK holdoff", HFILL }
2790 { &hf_acn_nak_max_wait,
2791 { "NAK Max Wait (ms)", "acn.nak_max_wait",
2792 FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
2793 "NAK Max Wait", HFILL }
2796 { &hf_acn_nak_modulus,
2797 { "NAK Modulus", "acn.nak_modulus",
2798 FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
2799 "NAK Modulus", HFILL }
2801 /* NAK Outbound Flag */
2802 { &hf_acn_nak_outbound_flag,
2803 { "NAK Outbound Flag", "acn.nak_outbound_flag",
2804 FT_BOOLEAN, 8, NULL, 0x80,
2805 "NAK Outbound Flag", HFILL }
2807 /* Oldest Available Wrapper */
2808 { &hf_acn_oldest_available_wrapper,
2809 { "Oldest Available Wrapper", "acn.oldest_available_wrapper",
2810 FT_UINT32, BASE_DEC_HEX, NULL, 0x0,
2811 "Oldest Available Wrapper", HFILL }
2813 /* Preamble Sizet */
2814 { &hf_acn_preamble_size,
2815 { "Size of preamble", "acn.preamble_size",
2816 FT_UINT16, BASE_DEC, NULL, 0x0,
2817 "Preamble size in bytes", HFILL }
2819 /* Packet Identifier */
2820 { &hf_acn_packet_identifier,
2821 { "Packet Identifier", "acn.packet_identifier",
2822 FT_STRING, BASE_NONE, NULL, 0x0,
2823 "Packet Identififer", HFILL }
2828 FT_NONE, BASE_NONE, NULL, 0x0,
2832 { &hf_acn_pdu_flags,
2833 { "Flags", "acn.pdu.flags",
2834 FT_UINT8, BASE_HEX, NULL, 0x0,
2835 "PDU Flags", HFILL }
2837 { &hf_acn_pdu_flag_d,
2838 { "Data", "acn.pdu.flag_d",
2839 FT_BOOLEAN, 8, NULL, ACN_PDU_FLAG_D,
2840 "Data flag", HFILL }
2842 { &hf_acn_pdu_flag_h,
2843 { "Header", "acn.pdu.flag_h",
2844 FT_BOOLEAN, 8, NULL, ACN_PDU_FLAG_H,
2845 "Header flag", HFILL }
2847 { &hf_acn_pdu_flag_l,
2848 { "Length", "acn.pdu.flag_l",
2849 FT_BOOLEAN, 8, NULL, ACN_PDU_FLAG_L,
2850 "Length flag", HFILL }
2852 { &hf_acn_pdu_flag_v,
2853 { "Vector", "acn.pdu.flag_v",
2854 FT_BOOLEAN, 8, NULL, ACN_PDU_FLAG_V,
2855 "Vector flag", HFILL }
2858 { &hf_acn_pdu_length,
2859 { "Length", "acn.pdu.flag_d",
2860 FT_UINT32, BASE_DEC, NULL, 0x0,
2861 "PDU Length", HFILL }
2865 { "Port", "acn.port",
2866 FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
2869 /* Postamble Size */
2870 { &hf_acn_postamble_size,
2871 { "Size of postamble", "acn.postamble_size",
2872 FT_UINT16, BASE_DEC, NULL, 0x0,
2873 "Postamble size in bytes", HFILL }
2876 { &hf_acn_protocol_id,
2877 { "Protocol ID", "acn.protocol_id",
2878 FT_UINT32, BASE_DEC, VALS(acn_protocol_id_vals), 0x0,
2879 "Protocol ID", HFILL }
2882 { &hf_acn_reason_code,
2883 { "Reason Code", "acn.reason_code",
2884 FT_UINT8, BASE_DEC, VALS(acn_reason_code_vals), 0x0,
2885 "Reason Code", HFILL }
2887 /* Reciprocal Channel */
2888 { &hf_acn_reciprocal_channel,
2889 { "Reciprocal Sequence Number", "acn.acn_reciprocal_channel",
2890 FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
2891 "Reciprocal Channel", HFILL }
2894 { &hf_acn_refuse_code,
2895 { "Refuse Code", "acn.acn_refuse_code",
2896 FT_UINT8, BASE_DEC, VALS(acn_refuse_code_vals), 0x0,
2897 "Refuse Code", HFILL }
2899 /* Reliable Sequence Number */
2900 { &hf_acn_reliable_sequence_number,
2901 { "Reliable Sequence Number", "acn.reliable_sequence_number",
2902 FT_UINT32, BASE_DEC_HEX, NULL, 0x0,
2903 "Reliable Sequence Number", HFILL }
2906 { &hf_acn_sdt_vector,
2907 { "STD Vector", "acn.sdt_vector",
2908 FT_UINT8, BASE_DEC, VALS(acn_sdt_vector_vals), 0x0,
2909 "STD Vector", HFILL }
2913 { &hf_acn_dmx_vector,
2914 { "Vector", "acn.dmx_vector",
2915 FT_UINT32, BASE_DEC, VALS(acn_dmx_vector_vals), 0x0,
2916 "DMX Vector", HFILL }
2918 /* DMX Source Name */
2919 { &hf_acn_dmx_source_name,
2920 { "Source", "acn.dmx.source_name",
2921 FT_STRING, BASE_NONE, NULL, 0x0,
2922 "DMX Source Name", HFILL }
2926 { &hf_acn_dmx_priority,
2927 { "Priority", "acn.dmx.priority",
2928 FT_UINT8, BASE_DEC, NULL, 0x0,
2929 "DMX Priority", HFILL }
2931 /* DMX Sequence number */
2932 { &hf_acn_dmx_sequence_number,
2933 { "Seq No", "acn.dmx.seq_number",
2934 FT_UINT8, BASE_DEC, NULL, 0x0,
2935 "DMX Sequence Number", HFILL }
2938 { &hf_acn_dmx_universe,
2939 { "Universe", "acn.dmx.universe",
2940 FT_UINT16, BASE_DEC, NULL, 0x0,
2941 "DMX Universe", HFILL }
2944 { &hf_acn_session_count,
2945 { "Session Count", "acn.session_count",
2946 FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
2947 "Session Count", HFILL }
2949 /* Total Sequence Number */
2950 { &hf_acn_total_sequence_number,
2951 { "Total Sequence Number", "acn.total_sequence_number",
2952 FT_UINT32, BASE_DEC_HEX, NULL, 0x0,
2953 "Total Sequence Number", HFILL }
2957 /* Setup protocol subtree array */
2958 static gint *ett[] = {
2960 &ett_acn_channel_owner_info_block,
2961 &ett_acn_channel_member_info_block,
2962 &ett_acn_channel_parameter,
2964 &ett_acn_address_type,
2968 &ett_acn_sdt_client_pdu,
2969 &ett_acn_sdt_base_pdu,
2971 &ett_acn_dmx_address,
2972 &ett_acn_dmx_data_pdu,
2976 module_t *acn_module;
2977 if (proto_acn == -1) {
2978 proto_acn = proto_register_protocol (
2979 "Architecture for Control Networks", /* name */
2980 "ACN", /* short name */
2985 acn_module = prefs_register_protocol(proto_acn, proto_reg_handoff_acn);
2986 proto_register_field_array(proto_acn, hf, array_length(hf));
2987 proto_register_subtree_array(ett, array_length(ett));
2988 prefs_register_bool_preference(acn_module, "heuristic_acn",
2990 "Enable Architecture for Control Networks dissector (ANSI BSR E1.17)",
2993 prefs_register_bool_preference(acn_module, "dmx_enable",
2995 "Enable Streaming DMX extension dissector (ANSI BSR E1.31)",
2996 &global_acn_dmx_enable);
2998 prefs_register_enum_preference(acn_module, "dmx_display_view",
2999 "DMX, display format",
3001 &global_acn_dmx_display_view,
3005 prefs_register_bool_preference(acn_module, "dmx_display_zeros",
3006 "DMX, display zeros",
3007 "Display zeros instead of dots",
3008 &global_acn_dmx_display_zeros);
3010 prefs_register_bool_preference(acn_module, "dmx_display_leading_zeros",
3011 "DMX, display leading zeros",
3012 "Display leading zeros on levels",
3013 &global_acn_dmx_display_leading_zeros);
3017 /******************************************************************************/
3018 /* Register handoff */
3020 proto_reg_handoff_acn(void)
3022 static guint initialized = FALSE;
3023 /* static dissector_handle_t acn_handle; */
3026 /* acn_handle = new_create_dissector_handle(dissect_acn, proto_acn); */
3027 /* dissector_add("udp.port", 0, acn_handle); */
3028 heur_dissector_add("udp", dissect_acn_heur, proto_acn);