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;
167 static int hf_acn_dmx_start_code = -1;
168 static int hf_acn_dmx_increment = -1;
169 static int hf_acn_dmx_count = -1;
171 /* static int hf_acn_dmx_dmp_vector = -1; */
173 /* Try heuristic ACN decode */
174 static gboolean global_acn_heur = FALSE;
175 static gboolean global_acn_dmx_enable = FALSE;
176 static gint global_acn_dmx_display_view = 0;
177 static gint global_acn_dmx_display_line_format = 0;
178 static gboolean global_acn_dmx_display_zeros = FALSE;
179 static gboolean global_acn_dmx_display_leading_zeros = FALSE;
182 static const value_string acn_protocol_id_vals[] = {
183 { ACN_PROTOCOL_ID_SDT, "SDT Protocol" },
184 { ACN_PROTOCOL_ID_DMP, "DMP Protocol" },
185 { ACN_PROTOCOL_ID_DMX, "DMX Protocol" },
189 static const value_string acn_dmp_adt_r_vals[] = {
195 static const value_string acn_dmp_adt_v_vals[] = {
201 static const value_string acn_dmp_adt_d_vals[] = {
202 { ACN_DMP_ADT_D_NS, "Non-range, single data item" },
203 { ACN_DMP_ADT_D_RS, "Range, single data item" },
204 { ACN_DMP_ADT_D_RE, "Range, array of equal size data items" },
205 { ACN_DMP_ADT_D_RM, "Range, series of mixed size data items" },
209 static const value_string acn_dmp_adt_a_vals[] = {
210 { ACN_DMP_ADT_A_1, "1 octet" },
211 { ACN_DMP_ADT_A_2, "2 octets" },
212 { ACN_DMP_ADT_A_4, "4 octets" },
213 { ACN_DMP_ADT_A_R, "reserved" },
218 static const value_string acn_sdt_vector_vals[] = {
219 {ACN_SDT_VECTOR_UNKNOWN, "Unknown"},
220 {ACN_SDT_VECTOR_REL_WRAP, "Reliable Wrapper"},
221 {ACN_SDT_VECTOR_UNREL_WRAP, "Unreliable Wrapper"},
222 {ACN_SDT_VECTOR_CHANNEL_PARAMS, "Channel Parameters"},
223 {ACN_SDT_VECTOR_JOIN, "Join"},
224 {ACN_SDT_VECTOR_JOIN_REFUSE, "Join Refuse"},
225 {ACN_SDT_VECTOR_JOIN_ACCEPT, "Join Accept"},
226 {ACN_SDT_VECTOR_LEAVE, "Leave"},
227 {ACN_SDT_VECTOR_LEAVING, "Leaving"},
228 {ACN_SDT_VECTOR_CONNECT, "Connect"},
229 {ACN_SDT_VECTOR_CONNECT_ACCEPT, "Connect Accept"},
230 {ACN_SDT_VECTOR_CONNECT_REFUSE, "Connect Refuse"},
231 {ACN_SDT_VECTOR_DISCONNECT, "Disconnect"},
232 {ACN_SDT_VECTOR_DISCONNECTING, "Disconnecting"},
233 {ACN_SDT_VECTOR_ACK, "Ack"},
234 {ACN_SDT_VECTOR_NAK, "Nak"},
235 {ACN_SDT_VECTOR_GET_SESSION, "Get Session"},
236 {ACN_SDT_VECTOR_SESSIONS, "Sessions"},
240 static const value_string acn_dmx_vector_vals[] = {
241 {ACN_DMX_VECTOR, "Streaming DMX"},
245 static const value_string acn_dmp_vector_vals[] = {
246 {ACN_DMP_VECTOR_UNKNOWN, "Unknown"},
247 {ACN_DMP_VECTOR_GET_PROPERTY, "Get Property"},
248 {ACN_DMP_VECTOR_SET_PROPERTY, "Set Property"},
249 {ACN_DMP_VECTOR_GET_PROPERTY_REPLY, "Get property reply"},
250 {ACN_DMP_VECTOR_EVENT, "Event"},
251 {ACN_DMP_VECTOR_MAP_PROPERTY, "Map Property"},
252 {ACN_DMP_VECTOR_UNMAP_PROPERTY, "Unmap Property"},
253 {ACN_DMP_VECTOR_SUBSCRIBE, "Subscribe"},
254 {ACN_DMP_VECTOR_UNSUBSCRIBE, "Unsubscribe"},
255 {ACN_DMP_VECTOR_GET_PROPERTY_FAIL, "Get Property Fail"},
256 {ACN_DMP_VECTOR_SET_PROPERTY_FAIL, "Set Property Fail"},
257 {ACN_DMP_VECTOR_MAP_PROPERTY_FAIL, "Map Property Fail"},
258 {ACN_DMP_VECTOR_SUBSCRIBE_ACCEPT, "Subscribe Accept"},
259 {ACN_DMP_VECTOR_SUBSCRIBE_REJECT, "Subscribe Reject"},
260 {ACN_DMP_VECTOR_ALLOCATE_MAP, "Allocate Map"},
261 {ACN_DMP_VECTOR_ALLOCATE_MAP_REPLY, "Allocate Map Reply"},
262 {ACN_DMP_VECTOR_DEALLOCATE_MAP, "Deallocate Map"},
266 static const value_string acn_ip_address_type_vals[] = {
267 { ACN_ADDR_NULL, "Null"},
268 { ACN_ADDR_IPV4, "IPv4"},
269 { ACN_ADDR_IPV6, "IPv6"},
270 { ACN_ADDR_IPPORT, "Port"},
274 static const value_string acn_refuse_code_vals[] = {
275 { ACN_REFUSE_CODE_NONSPECIFIC, "Nonspecific" },
276 { ACN_REFUSE_CODE_ILLEGAL_PARAMS, "Illegal Parameters" },
277 { ACN_REFUSE_CODE_LOW_RESOURCES, "Low Resources" },
278 { ACN_REFUSE_CODE_ALREADY_MEMBER, "Already Member" },
279 { ACN_REFUSE_CODE_BAD_ADDR_TYPE, "Bad Address Type" },
280 { ACN_REFUSE_CODE_NO_RECIP_CHAN, "No Reciprocal Channel" },
284 static const value_string acn_reason_code_vals[] = {
285 { ACN_REASON_CODE_NONSPECIFIC, "Nonspecific" },
286 { ACN_REASON_CODE_NO_RECIP_CHAN, "No Reciprocal Channel" },
287 { ACN_REASON_CODE_CHANNEL_EXPIRED, "Channel Expired" },
288 { ACN_REASON_CODE_LOST_SEQUENCE, "Lost Sequence" },
289 { ACN_REASON_CODE_SATURATED, "Saturated" },
290 { ACN_REASON_CODE_TRANS_ADDR_CHANGING, "Transport Address Changing" },
291 { ACN_REASON_CODE_ASKED_TO_LEAVE, "Asked to Leave" },
292 { ACN_REASON_CODE_NO_RECIPIENT, "No Recipient"},
296 static const value_string acn_dmp_reason_code_vals[] = {
297 { ACN_DMP_REASON_CODE_NONSPECIFIC, "Nonspecific" },
298 { ACN_DMP_REASON_CODE_NOT_A_PROPERTY, "Not a Property" },
299 { ACN_DMP_REASON_CODE_WRITE_ONLY, "Write Only" },
300 { ACN_DMP_REASON_CODE_NOT_WRITABLE, "Not Writable" },
301 { ACN_DMP_REASON_CODE_DATA_ERROR, "Data Error" },
302 { ACN_DMP_REASON_CODE_MAPS_NOT_SUPPORTED, "Maps not Supported" },
303 { ACN_DMP_REASON_CODE_SPACE_NOT_AVAILABLE, "Space not Available" },
304 { ACN_DMP_REASON_CODE_PROP_NOT_MAPABLE, "Property not Mapable"},
305 { ACN_DMP_REASON_CODE_MAP_NOT_ALLOCATED, "Map not Allocated"},
306 { ACN_DMP_REASON_CODE_SUBSCRIPTION_NOT_SUPPORTED, "Subscription not Supported"},
307 { ACN_DMP_REASON_CODE_NO_SUBSCRIPTIONS_SUPPORTED, "No Subscriptions Supported"},
311 static const enum_val_t dmx_display_view[] = {
312 { "hex" , "Hex ", ACN_PREF_DMX_DISPLAY_HEX },
313 { "decimal", "Decimal", ACN_PREF_DMX_DISPLAY_DEC },
314 { "percent", "Percent", ACN_PREF_DMX_DISPLAY_PER },
318 static const enum_val_t dmx_display_line_format[] = {
319 { "20 per line", "20 per line", ACN_PREF_DMX_DISPLAY_20PL },
320 { "16 per line", "16 per line", ACN_PREF_DMX_DISPLAY_16PL },
324 /******************************************************************************/
325 /* Test to see if it is an ACN Packet */
326 static gboolean is_acn(tvbuff_t *tvb)
328 static char acn_packet_id[] = "ASC-E1.17\0\0\0"; /* must be 12 bytes */
331 /* Get the fields in octets 2 - 12 octet */
332 packet_id = tvb_get_ephemeral_string(tvb, 4, 12);
333 if (memcmp(packet_id, &acn_packet_id, 12) == 0) {
340 /******************************************************************************/
341 /* Heuristic dissector */
343 dissect_acn_heur( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree )
345 /* This is a heuristic dissector, which means we get all the UDP
346 * traffic not sent to a known dissector and not claimed by
347 * a heuristic dissector called before us!
350 /* abort if not enabled! */
351 if (!global_acn_heur) return FALSE;
353 /* abort if it is NOT an ACN packet */
354 if (!is_acn(tvb)) return FALSE;
356 /* else, dissect it */
357 dissect_acn(tvb, pinfo, tree);
361 /******************************************************************************/
362 /* Adds tree branch for channel owner info block */
364 acn_add_channel_owner_info_block(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree _U_, int offset)
367 proto_tree *this_tree = NULL;
368 guint32 session_count;
371 pi = proto_tree_add_text(this_tree, tvb, offset, 8, "Channel Owner Info Block");
372 this_tree = proto_item_add_subtree(pi, ett_acn_channel_owner_info_block);
374 proto_tree_add_item(this_tree, hf_acn_member_id, tvb, offset, 2, FALSE);
376 proto_tree_add_item(this_tree, hf_acn_channel_number, tvb, offset, 2, FALSE);
378 offset += acn_add_address(tvb, pinfo, this_tree, offset, "Destination Address:");
379 offset += acn_add_address(tvb, pinfo, this_tree, offset, "Source Address:");
381 session_count = tvb_get_ntohs(tvb, offset);
382 for (x=0; x<session_count; x++) {
383 pi = proto_tree_add_item(this_tree, hf_acn_protocol_id, tvb, offset, 4, FALSE);
384 proto_item_append_text(pi, " #%d", x+1);
390 /******************************************************************************/
391 /* Adds tree branch for channel member info block */
393 acn_add_channel_member_info_block(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree _U_, int offset)
396 proto_tree *this_tree = NULL;
397 guint32 session_count;
400 pi = proto_tree_add_text(this_tree, tvb, offset, 8, "Channel Member Info Block");
401 this_tree = proto_item_add_subtree(pi, ett_acn_channel_member_info_block);
403 proto_tree_add_item(this_tree, hf_acn_member_id, tvb, offset, 2, FALSE);
405 proto_tree_add_item(this_tree, hf_acn_cid, tvb, offset, 16, FALSE);
407 proto_tree_add_item(this_tree, hf_acn_channel_number, tvb, offset, 2, FALSE);
409 offset += acn_add_address(tvb, pinfo, this_tree, offset, "Destination Address:");
410 offset += acn_add_address(tvb, pinfo, this_tree, offset, "Source Address:");
411 proto_tree_add_item(this_tree, hf_acn_reciprocal_channel, tvb, offset, 2, FALSE);
414 session_count = tvb_get_ntohs(tvb, offset);
415 for (x=0; x<session_count; x++) {
416 pi = proto_tree_add_item(this_tree, hf_acn_protocol_id, tvb, offset, 4, FALSE);
417 proto_item_append_text(pi, " #%d", x+1);
424 /******************************************************************************/
425 /* Add labeled expiry */
427 acn_add_expiry(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, const char *label)
429 proto_tree_add_text(tree, tvb, offset, 2, "%s %d", label, tvb_get_guint8(tvb, offset));
435 /******************************************************************************/
436 /* Adds tree branch for channel parameters */
438 acn_add_channel_parameter(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset)
441 proto_tree *param_tree = NULL;
443 pi = proto_tree_add_text(tree, tvb, offset, 8, "Channel Parameter Block");
444 param_tree = proto_item_add_subtree(pi, ett_acn_channel_parameter);
445 proto_tree_add_item(param_tree, hf_acn_expiry, tvb, offset, 1, FALSE);
447 proto_tree_add_item(param_tree, hf_acn_nak_outbound_flag, tvb, offset, 1, FALSE);
449 proto_tree_add_item(param_tree, hf_acn_nak_holdoff, tvb, offset, 2, FALSE);
451 proto_tree_add_item(param_tree, hf_acn_nak_modulus, tvb, offset, 2, FALSE);
453 proto_tree_add_item(param_tree, hf_acn_nak_max_wait, tvb, offset, 2, FALSE);
455 return offset; /* bytes used */
459 /******************************************************************************/
460 /* Add an address tree */
462 acn_add_address(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, const char *label)
465 proto_tree *addr_tree = NULL;
466 guint8 ip_address_type;
471 struct e_in6_addr IPv6;
475 ip_address_type = tvb_get_guint8(tvb, offset);
477 switch (ip_address_type) {
479 proto_tree_add_item(tree, hf_acn_ip_address_type, tvb, offset, 1, FALSE);
483 /* Build tree and add type*/
484 pi = proto_tree_add_text(tree, tvb, offset, 7, label);
485 addr_tree = proto_item_add_subtree(pi, ett_acn_address);
486 proto_tree_add_item(addr_tree, hf_acn_ip_address_type, tvb, offset, 1, FALSE);
489 port = tvb_get_ntohs(tvb, offset);
490 proto_tree_add_item(addr_tree, hf_acn_port, tvb, offset, 2, FALSE);
493 proto_tree_add_item(addr_tree, hf_acn_ipv4, tvb, offset, 4, FALSE);
494 /* Append port and address to tree item */
495 IPv4 = tvb_get_ipv4(tvb, offset);
496 SET_ADDRESS(&addr, AT_IPv4, sizeof(IPv4), &IPv4);
497 proto_item_append_text(pi, " %s, Port %d", address_to_str(&addr), port);
501 /* Build tree and add type*/
502 pi = proto_tree_add_text(tree, tvb, offset, 19, label);
503 addr_tree = proto_item_add_subtree(pi, ett_acn_address);
504 proto_tree_add_item(addr_tree, hf_acn_ip_address_type, tvb, offset, 1, FALSE);
507 port = tvb_get_ntohs(tvb, offset);
508 proto_tree_add_item(addr_tree, hf_acn_port, tvb, offset, 2, FALSE);
511 proto_tree_add_item(addr_tree, hf_acn_ipv6, tvb, offset, 16, FALSE);
512 /* Append port and address to tree item */
513 tvb_get_ipv6(tvb, offset, &IPv6);
514 SET_ADDRESS(&addr, AT_IPv6, sizeof(struct e_in6_addr), &IPv6);
515 proto_item_append_text(pi, " %s, Port %d", address_to_str(&addr), port);
518 case ACN_ADDR_IPPORT:
519 /* Build tree and add type*/
520 pi = proto_tree_add_text(tree, tvb, offset, 3, label);
521 addr_tree = proto_item_add_subtree(pi, ett_acn_address);
522 proto_tree_add_item(addr_tree, hf_acn_ip_address_type, tvb, offset, 1, FALSE);
525 port = tvb_get_ntohs(tvb, offset);
526 proto_tree_add_item(addr_tree, hf_acn_port, tvb, offset, 2, FALSE);
527 /* Append port to tree item */
528 proto_item_append_text(pi, " %s Port %d", address_to_str(&addr), port);
535 /******************************************************************************/
536 /* Adds tree branch for address type */
538 acn_add_dmp_address_type(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, acn_dmp_adt_type *adt)
541 proto_tree *this_tree = NULL;
545 /* header contains address and data type */
546 adt->flags = tvb_get_guint8(tvb, offset);
548 D = ACN_DMP_ADT_EXTRACT_D(adt->flags);
549 name = val_to_str(D, acn_dmp_adt_d_vals, "not valid (%d)");
550 pi = proto_tree_add_text(tree, tvb, offset, 1, "Address and Data Type: %s", name);
552 this_tree = proto_item_add_subtree(pi, ett_acn_address_type);
553 proto_tree_add_uint(this_tree, hf_acn_dmp_adt_v, tvb, offset, 1, adt->flags);
554 proto_tree_add_uint(this_tree, hf_acn_dmp_adt_r, tvb, offset, 1, adt->flags);
555 proto_tree_add_uint(this_tree, hf_acn_dmp_adt_d, tvb, offset, 1, adt->flags);
556 proto_tree_add_uint(this_tree, hf_acn_dmp_adt_x, tvb, offset, 1, adt->flags);
557 proto_tree_add_uint(this_tree, hf_acn_dmp_adt_a, tvb, offset, 1, adt->flags);
560 return offset; /* bytes used */
563 /******************************************************************************/
564 /* Add an dmp address */
566 acn_add_dmp_address(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, acn_dmp_adt_type *adt)
568 guint32 start_offset;
572 start_offset = offset;
574 D = ACN_DMP_ADT_EXTRACT_D(adt->flags);
575 A = ACN_DMP_ADT_EXTRACT_A(adt->flags);
577 case ACN_DMP_ADT_D_NS: /* Non-range address, Single data item */
580 switch (A) { /* address */
581 case ACN_DMP_ADT_A_1: /* One octet address, (range: one octet address, increment, and count). */
582 adt->address = tvb_get_guint8(tvb, offset);
586 case ACN_DMP_ADT_A_2: /* Two octet address, (range: two octet address, increment, and count). */
587 adt->address = tvb_get_ntohs(tvb, offset);
591 case ACN_DMP_ADT_A_4: /* Four octet address, (range: one octet address, increment, and count). */
592 adt->address = tvb_get_ntohl(tvb, offset);
596 default: /* and ACN_DMP_ADT_A_R (Four octet address, (range: four octet address, increment, and count)*/
598 } /* of switch (A) */
600 if (adt->flags & ACN_DMP_ADT_FLAG_V) {
601 proto_tree_add_text(tree, tvb, start_offset, bytes_used, "Virtual Address: 0x%X", adt->address);
603 proto_tree_add_text(tree, tvb, start_offset, bytes_used, "Actual Address: 0x%X", adt->address);
607 case ACN_DMP_ADT_D_RS: /* Range address, Single data item */
609 case ACN_DMP_ADT_A_1: /* One octet address, (range: one octet address, increment, and count). */
610 adt->address = tvb_get_guint8(tvb, offset);
612 adt->increment = tvb_get_guint8(tvb, offset);
614 adt->count = tvb_get_guint8(tvb, offset);
618 case ACN_DMP_ADT_A_2: /* Two octet address, (range: two octet address, increment, and count). */
619 adt->address = tvb_get_ntohs(tvb, offset);
621 adt->increment = tvb_get_ntohs(tvb, offset);
623 adt->count = tvb_get_ntohs(tvb, offset);
627 case ACN_DMP_ADT_A_4: /* Four octet address, (range: four octet address, increment, and count). */
628 adt->address = tvb_get_ntohl(tvb, offset);
630 adt->increment = tvb_get_ntohl(tvb, offset);
632 adt->count = tvb_get_ntohl(tvb, offset);
636 default: /* and ACN_DMP_ADT_A_R, this reserved....so it has no meaning yet */
638 } /* of switch (A) */
640 if (adt->flags & ACN_DMP_ADT_FLAG_V) {
641 proto_tree_add_text(tree, tvb, start_offset, bytes_used, "Virtual Address first: 0x%X, inc: %d, count: %d", adt->address, adt->increment, adt->count);
643 proto_tree_add_text(tree, tvb, start_offset, bytes_used, "Actual Address first: 0x%X, inc: %d, count: %d", adt->address, adt->increment, adt->count);
647 case ACN_DMP_ADT_D_RE: /* Range address, Array of equal size data items */
649 case ACN_DMP_ADT_A_1: /* One octet address, (range: one octet address, increment, and count). */
650 adt->address = tvb_get_guint8(tvb, offset);
652 adt->increment = tvb_get_guint8(tvb, offset);
654 adt->count = tvb_get_guint8(tvb, offset);
658 case ACN_DMP_ADT_A_2: /* Two octet address, (range: two octet address, increment, and count). */
659 adt->address = tvb_get_ntohs(tvb, offset);
661 adt->increment = tvb_get_ntohs(tvb, offset);
663 adt->count = tvb_get_ntohs(tvb, offset);
667 case ACN_DMP_ADT_A_4: /* Four octet address, (range: four octet address, increment, and count). */
668 adt->address = tvb_get_ntohl(tvb, offset);
670 adt->increment = tvb_get_ntohl(tvb, offset);
672 adt->count = tvb_get_ntohl(tvb, offset);
676 default: /* and ACN_DMP_ADT_A_R, this reserved....so it has no meaning yet */
678 } /* of switch (A) */
680 if (adt->flags & ACN_DMP_ADT_FLAG_V) {
681 proto_tree_add_text(tree, tvb, start_offset, bytes_used, "Virtual Address first: 0x%X, inc: %d, count: %d", adt->address, adt->increment, adt->count);
683 proto_tree_add_text(tree, tvb, start_offset, bytes_used, "Actual Address first: 0x%X, inc: %d, count: %d", adt->address, adt->increment, adt->count);
687 case ACN_DMP_ADT_D_RM: /* Range address, Series of mixed size data items */
689 case ACN_DMP_ADT_A_1: /* One octet address, (range: one octet address, increment, and count). */
690 adt->address = tvb_get_guint8(tvb, offset);
692 adt->increment = tvb_get_guint8(tvb, offset);
694 adt->count = tvb_get_guint8(tvb, offset);
698 case ACN_DMP_ADT_A_2: /* Two octet address, (range: two octet address, increment, and count). */
699 adt->address = tvb_get_ntohs(tvb, offset);
701 adt->increment = tvb_get_ntohs(tvb, offset);
703 adt->count = tvb_get_ntohs(tvb, offset);
707 case ACN_DMP_ADT_A_4: /* Four octet address, (range: four octet address, increment, and count). */
708 adt->address = tvb_get_ntohl(tvb, offset);
710 adt->increment = tvb_get_ntohl(tvb, offset);
712 adt->count = tvb_get_ntohl(tvb, offset);
716 default: /* and ACN_DMP_ADT_A_R, this reserved....so it has no meaning yet */
718 } /* of switch (A) */
720 if (adt->flags & ACN_DMP_ADT_FLAG_V) {
721 proto_tree_add_text(tree, tvb, start_offset, bytes_used, "Virtual Address first: 0x%X, inc: %d, count: %d", adt->address, adt->increment, adt->count);
723 proto_tree_add_text(tree, tvb, start_offset, bytes_used, "Actual Address first: 0x%X, inc: %d, count: %d", adt->address, adt->increment, adt->count);
726 } /* of switch (D) */
732 /*******************************************************************************/
733 /* Display DMP Data */
734 #define BUFFER_SIZE 128
736 acn_add_dmp_data(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, acn_dmp_adt_type *adt)
739 guint32 start_offset;
742 guint32 data_address;
744 gchar buffer[BUFFER_SIZE];
746 guint32 ok_to_process = FALSE;
748 start_offset = offset;
751 /* We would like to rip through Property Address-Data pairs */
752 /* but since we don't now how many there are nor how big the data size is, */
753 /* it not possible. So, we just show the whole thing as a block of date! */
755 /* There are a few exceptions however */
756 /* 1) if the address type is ACN_DMP_ADT_D_NS or ACN_DMP_ADT_D_RS and */
757 /* or ACN_DMP_ADT_D_RE */
758 /* then number of bytes is <= count + 4. Each value is at least one byte */
759 /* and another address/data pair is at least 4 bytes so if the remaining */
760 /* bytes is less than the count plus 4 then the remaining data */
761 /* must be all data */
763 /* 2) if the address type is ACN_DMP_ADT_D_RE and the number of bytes */
764 /* equals the number of bytes in remaining in the pdu then there is */
765 /* a 1 to one match */
767 D = ACN_DMP_ADT_EXTRACT_D(adt->flags);
769 case ACN_DMP_ADT_D_NS:
770 case ACN_DMP_ADT_D_RS:
771 if (adt->data_length <= adt->count + 4) {
772 ok_to_process = TRUE;
775 case ACN_DMP_ADT_D_RE:
776 if (adt->data_length == adt->count) {
777 ok_to_process = TRUE;
779 if (adt->data_length <= adt->count + 4) {
780 ok_to_process = TRUE;
785 if (!ok_to_process) {
786 data_size = adt->data_length;
787 ti = proto_tree_add_item(tree, hf_acn_data, tvb, offset, data_size, FALSE);
789 proto_item_set_text(ti, "Data and more Address-Data Pairs (further dissection not possible)");
793 A = ACN_DMP_ADT_EXTRACT_A(adt->flags);
795 case ACN_DMP_ADT_D_NS: /* Non-range address, Single data item */
796 /* calculate data size */
797 data_size = adt->data_length;
798 data_address = adt->address;
801 case ACN_DMP_ADT_A_1: /* One octet address, (range: one octet address, increment, and count). */
802 g_snprintf(buffer, BUFFER_SIZE, "Addr 0x%2.2X ->", data_address);
804 case ACN_DMP_ADT_A_2: /* Two octet address, (range: two octet address, increment, and count). */
805 g_snprintf(buffer, BUFFER_SIZE, "Addr 0x%4.4X ->", data_address);
807 case ACN_DMP_ADT_A_4: /* Four octet address, (range: four octet address, increment, and count). */
808 g_snprintf(buffer, BUFFER_SIZE, "Addr 0x%8.8X ->", data_address);
810 default: /* and ACN_DMP_ADT_A_R, this reserved....so it has no meaning yet */
816 data_value = tvb_get_guint8(tvb, offset);
817 proto_tree_add_int_format(tree, hf_acn_data8, tvb, offset, 1, data_value, "%s %2.2X", buffer, data_value);
820 data_value = tvb_get_ntohs(tvb, offset);
821 proto_tree_add_int_format(tree, hf_acn_data16, tvb, offset, 2, data_value, "%s %4.4X", buffer, data_value);
824 data_value = tvb_get_ntoh24(tvb, offset);
825 proto_tree_add_int_format(tree, hf_acn_data24, tvb, offset, 3, data_value, "%s %6.6X", buffer, data_value);
828 data_value = tvb_get_ntohl(tvb, offset);
829 proto_tree_add_int_format(tree, hf_acn_data32, tvb, offset, 4, data_value, "%s %8.8X", buffer, data_value);
832 /* build string of values */
833 for (y=0;y<20 && y<data_size;y++) {
834 data_value = tvb_get_guint8(tvb, offset+y);
835 g_snprintf(buffer, BUFFER_SIZE, "%s %2.2X", buffer, data_value);
838 ti = proto_tree_add_item(tree, hf_acn_data, tvb, offset, data_size, FALSE);
840 /* change the text */
841 proto_item_set_text(ti, "%s", buffer);
843 } /* of switch (data_size) */
847 case ACN_DMP_ADT_D_RS: /* Range address, Single data item */
848 /* calculate data size */
849 data_size = adt->data_length;
850 data_address = adt->address;
852 for (x=0;x<adt->count;x++) {
854 case ACN_DMP_ADT_A_1: /* One octet address, (range: one octet address, increment, and count). */
855 g_snprintf(buffer, BUFFER_SIZE, "Addr 0x%2.2X ->", data_address);
857 case ACN_DMP_ADT_A_2: /* Two octet address, (range: two octet address, increment, and count). */
858 g_snprintf(buffer, BUFFER_SIZE, "Addr 0x%4.4X ->", data_address);
860 case ACN_DMP_ADT_A_4: /* Four octet address, (range: four octet address, increment, and count). */
861 g_snprintf(buffer, BUFFER_SIZE, "Addr 0x%8.8X ->", data_address);
863 default: /* and ACN_DMP_ADT_A_R, this reserved....so it has no meaning yet */
869 data_value = tvb_get_guint8(tvb, offset);
870 proto_tree_add_int_format(tree, hf_acn_data8, tvb, offset, 1, data_value, "%s %2.2X", buffer, data_value);
873 data_value = tvb_get_ntohs(tvb, offset);
874 proto_tree_add_int_format(tree, hf_acn_data8, tvb, offset, 2, data_value, "%s %4.4X", buffer, data_value);
877 data_value = tvb_get_ntoh24(tvb, offset);
878 proto_tree_add_int_format(tree, hf_acn_data8, tvb, offset, 3, data_value, "%s %6.6X", buffer, data_value);
881 data_value = tvb_get_ntohl(tvb, offset);
882 proto_tree_add_int_format(tree, hf_acn_data8, tvb, offset, 4, data_value, "%s %8.8X", buffer, data_value);
885 /* build string of values */
886 for (y=0;y<20 && y<data_size;y++) {
887 data_value = tvb_get_guint8(tvb, offset+y);
888 g_snprintf(buffer, BUFFER_SIZE, "%s %2.2X", buffer, data_value);
891 ti = proto_tree_add_item(tree, hf_acn_data, tvb, offset, data_size, FALSE);
892 /* change the text */
893 proto_item_set_text(ti, "%s", buffer);
895 } /* of switch (data_size) */
896 data_address += adt->increment;
897 } /* of (x=0;x<adt->count;x++) */
901 case ACN_DMP_ADT_D_RE: /* Range address, Array of equal size data items */
902 /* calculate data size */
903 data_size = adt->data_length / adt->count;
904 data_address = adt->address;
906 for (x=0;x<adt->count;x++) {
908 case ACN_DMP_ADT_A_1: /* One octet address, (range: one octet address, increment, and count). */
909 g_snprintf(buffer, BUFFER_SIZE, "Addr 0x%2.2X ->", data_address);
911 case ACN_DMP_ADT_A_2: /* Two octet address, (range: two octet address, increment, and count). */
912 g_snprintf(buffer, BUFFER_SIZE, "Addr 0x%4.4X ->", data_address);
914 case ACN_DMP_ADT_A_4: /* Four octet address, (range: four octet address, increment, and count). */
915 g_snprintf(buffer, BUFFER_SIZE, "Addr 0x%8.8X ->", data_address);
917 default: /* and ACN_DMP_ADT_A_R, this reserved....so it has no meaning yet */
923 data_value = tvb_get_guint8(tvb, offset);
924 proto_tree_add_int_format(tree, hf_acn_data8, tvb, offset, 1, data_value, "%s %2.2X", buffer, data_value);
927 data_value = tvb_get_ntohs(tvb, offset);
928 proto_tree_add_int_format(tree, hf_acn_data8, tvb, offset, 2, data_value, "%s %4.4X", buffer, data_value);
931 data_value = tvb_get_ntoh24(tvb, offset);
932 proto_tree_add_int_format(tree, hf_acn_data8, tvb, offset, 3, data_value, "%s %6.6X", buffer, data_value);
935 data_value = tvb_get_ntohl(tvb, offset);
936 proto_tree_add_int_format(tree, hf_acn_data8, tvb, offset, 4, data_value, "%s %8.8X", buffer, data_value);
939 /* build string of values */
940 for (y=0;y<20 && y<data_size;y++) {
941 data_value = tvb_get_guint8(tvb, offset+y);
942 g_snprintf(buffer, BUFFER_SIZE, "%s %2.2X", buffer, data_value);
945 ti = proto_tree_add_item(tree, hf_acn_data, tvb, offset, data_size, FALSE);
946 /* change the text */
947 proto_item_set_text(ti, "%s", buffer);
949 } /* of switch (data_size) */
952 data_address += adt->increment;
953 } /* of (x=0;x<adt->count;x++) */
956 case ACN_DMP_ADT_D_RM: /* Range address, Series of mixed size data items */
957 data_size = adt->data_length;
958 ti = proto_tree_add_item(tree, hf_acn_data, tvb, offset, data_size, FALSE);
960 /* change the text */
961 proto_item_set_text(ti, "Mixed size data items");
963 } /* of switch (D) */
968 /*******************************************************************************/
969 /* Display DMP Reason codes */
970 #define BUFFER_SIZE 128
972 acn_add_dmp_reason_codes(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, acn_dmp_adt_type *adt)
975 guint32 start_offset;
977 guint32 data_address;
980 gchar buffer[BUFFER_SIZE];
983 start_offset = offset;
986 D = ACN_DMP_ADT_EXTRACT_D(adt->flags);
987 A = ACN_DMP_ADT_EXTRACT_A(adt->flags);
989 case ACN_DMP_ADT_D_NS: /* Non-range address, Single data item */
990 data_address = adt->address;
992 case ACN_DMP_ADT_A_1: /* One octet address, (range: one octet address, increment, and count). */
993 g_snprintf(buffer, BUFFER_SIZE, "Addr 0x%2.2X ->", data_address);
995 case ACN_DMP_ADT_A_2: /* Two octet address, (range: two octet address, increment, and count). */
996 g_snprintf(buffer, BUFFER_SIZE, "Addr 0x%4.4X ->", data_address);
998 case ACN_DMP_ADT_A_4: /* Four octet address, (range: four octet address, increment, and count). */
999 g_snprintf(buffer, BUFFER_SIZE, "Addr 0x%8.8X ->", data_address);
1001 default: /* and ACN_DMP_ADT_A_R, this reserved....so it has no meaning yet */
1006 data_value = tvb_get_guint8(tvb, offset);
1007 /* convert to string */
1008 name = val_to_str(data_value, acn_dmp_reason_code_vals, "reason not valid (%d)");
1010 proto_tree_add_int_format(tree, hf_acn_data8, tvb, offset, 1, data_value, "%s %s", buffer, name);
1014 case ACN_DMP_ADT_D_RS: /* Range address, Single data item */
1015 data_address = adt->address;
1016 for (x=0;x<adt->count;x++) {
1018 case ACN_DMP_ADT_A_1: /* One octet address, (range: one octet address, increment, and count). */
1019 g_snprintf(buffer, BUFFER_SIZE, "Addr 0x%2.2X ->", data_address);
1021 case ACN_DMP_ADT_A_2: /* Two octet address, (range: two octet address, increment, and count). */
1022 g_snprintf(buffer, BUFFER_SIZE, "Addr 0x%4.4X ->", data_address);
1024 case ACN_DMP_ADT_A_4: /* Four octet address, (range: four octet address, increment, and count). */
1025 g_snprintf(buffer, BUFFER_SIZE, "Addr 0x%8.8X ->", data_address);
1027 default: /* and ACN_DMP_ADT_A_R, this reserved....so it has no meaning yet */
1032 data_value = tvb_get_guint8(tvb, offset);
1033 /* convert to string */
1034 name = val_to_str(data_value, acn_dmp_reason_code_vals, "reason not valid (%d)");
1036 proto_tree_add_int_format(tree, hf_acn_data8, tvb, offset, 1, data_value, "%s %s", buffer, name);
1038 data_address += adt->increment;
1039 } /* of (x=0;x<adt->count;x++) */
1043 case ACN_DMP_ADT_D_RE: /* Range address, Array of equal size data items */
1044 case ACN_DMP_ADT_D_RM: /* Range address, Series of mixed size data items */
1045 data_address = adt->address;
1046 for (x=0;x<adt->count;x++) {
1048 case ACN_DMP_ADT_A_1: /* One octet address, (range: one octet address, increment, and count). */
1049 g_snprintf(buffer, BUFFER_SIZE, "Addr 0x%2.2X ->", data_address);
1051 case ACN_DMP_ADT_A_2: /* Two octet address, (range: two octet address, increment, and count). */
1052 g_snprintf(buffer, BUFFER_SIZE, "Addr 0x%4.4X ->", data_address);
1054 case ACN_DMP_ADT_A_4: /* Four octet address, (range: four octet address, increment, and count). */
1055 g_snprintf(buffer, BUFFER_SIZE, "Addr 0x%8.8X ->", data_address);
1057 default: /* and ACN_DMP_ADT_A_R, this reserved....so it has no meaning yet */
1061 data_value = tvb_get_guint8(tvb, offset);
1062 /* convert to string */
1063 name = val_to_str(data_value, acn_dmp_reason_code_vals, "reason not valid (%d)");
1065 proto_tree_add_int_format(tree, hf_acn_data8, tvb, offset, 1, data_value, "%s %s", buffer, name);
1066 data_address += adt->increment;
1068 } /* of (x=0;x<adt->count;x++) */
1070 } /* of switch (D) */
1075 /******************************************************************************/
1076 /* Dissect wrapped SDT PDU */
1078 dissect_acn_dmp_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, acn_pdu_offsets *last_pdu_offsets)
1080 /* common to all pdu */
1084 guint32 pdu_flvh_length; /* flags, length, vector, header */
1085 acn_pdu_offsets pdu_offsets = {0,0,0,0,0};
1091 guint32 vector_offset;
1092 guint32 header_offset;
1093 guint32 data_offset;
1096 guint32 data_length;
1097 guint32 address_count;
1099 proto_item *ti, *pi;
1100 proto_tree *pdu_tree = NULL;
1101 proto_tree *flag_tree = NULL;
1105 acn_dmp_adt_type adt = {0,0,0,0,0,0};
1106 acn_dmp_adt_type adt2 = {0,0,0,0,0,0};
1109 /* save start of pdu block */
1111 pdu_offsets.start = pdu_start;
1113 /* get PDU flags and length flag first */
1114 octet = tvb_get_guint8(tvb, offset++);
1115 pdu_flags = octet & 0xf0;
1116 length1 = octet & 0x0f; /* bottom 4 bits only */
1117 length2 = tvb_get_guint8(tvb, offset++);
1119 /* if length flag is set, then we have a 20 bit length else we have a 12 bit */
1120 /* flvh = flags, length, vector, header */
1121 if (pdu_flags & ACN_PDU_FLAG_L) {
1122 length3 = tvb_get_guint8(tvb, offset);
1124 pdu_length = length3 | (length2 << 8) | (length1 << 16);
1125 pdu_flvh_length = 3;
1127 pdu_length = length2 | (length1 << 8);
1128 pdu_flvh_length = 2;
1130 /* offset should now be pointing to vector (if one exists) */
1132 /* Add pdu item and tree */
1133 ti = proto_tree_add_item(tree, hf_acn_pdu, tvb, pdu_start, pdu_length, FALSE);
1134 pdu_tree = proto_item_add_subtree(ti, ett_acn_dmp_pdu);
1136 /* Add flag item and tree */
1137 pi = proto_tree_add_uint(pdu_tree, hf_acn_pdu_flags, tvb, pdu_start, 1, pdu_flags);
1138 flag_tree = proto_item_add_subtree(pi, ett_acn_pdu_flags);
1139 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_l, tvb, pdu_start, 1, FALSE);
1140 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_v, tvb, pdu_start, 1, FALSE);
1141 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_h, tvb, pdu_start, 1, FALSE);
1142 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_d, tvb, pdu_start, 1, FALSE);
1144 /* Add PDU Length item */
1145 proto_tree_add_uint(pdu_tree, hf_acn_pdu_length, tvb, pdu_start, pdu_flvh_length, pdu_length);
1147 /* Set vector offset */
1148 if (pdu_flags & ACN_PDU_FLAG_V) {
1149 /* use new values */
1150 vector_offset = offset;
1151 last_pdu_offsets->vector = offset;
1155 /* use last values */
1156 vector_offset = last_pdu_offsets->vector;
1158 /* offset should now be pointing to header (if one exists) */
1160 /* Add Vector item */
1161 vector = tvb_get_guint8(tvb, vector_offset);
1162 proto_tree_add_uint(pdu_tree, hf_acn_dmp_vector, tvb, vector_offset, 1, vector);
1164 /* Add Vector item to tree*/
1165 name = val_to_str(vector, acn_dmp_vector_vals, "not valid (%d)");
1166 proto_item_append_text(ti, ": ");
1167 proto_item_append_text(ti, name);
1169 /* Set header offset */
1170 if (pdu_flags & ACN_PDU_FLAG_H) {
1171 /* use new values */
1172 header_offset = offset;
1173 last_pdu_offsets->header = offset;
1177 /* use last values */
1178 header_offset = last_pdu_offsets->header;
1180 /* offset should now be pointing to data (if one exists) */
1182 /* header contains address and data type */
1183 acn_add_dmp_address_type(tvb, pinfo, pdu_tree, header_offset, &adt);
1186 if (pdu_flags & ACN_PDU_FLAG_D) {
1187 /* use new values */
1188 data_offset = offset;
1189 data_length = pdu_length - pdu_flvh_length;
1190 last_pdu_offsets->data = offset;
1191 last_pdu_offsets->data_length = data_length;
1193 /* use last values */
1194 data_offset = last_pdu_offsets->data;
1195 data_length = last_pdu_offsets->data_length;
1197 end_offset = data_offset + data_length;
1200 case ACN_DMP_VECTOR_UNKNOWN:
1202 case ACN_DMP_VECTOR_GET_PROPERTY:
1203 /* Rip trough property address */
1204 while (data_offset < end_offset) {
1205 old_offset = data_offset;
1206 data_offset = acn_add_dmp_address(tvb, pinfo, pdu_tree, data_offset, &adt);
1207 if (old_offset == data_offset) break;
1210 case ACN_DMP_VECTOR_SET_PROPERTY:
1211 /* Rip through Property Address-Data pairs */
1212 /* But, in reality, this generally won't work as we have know way of */
1213 /* calculating the next Address-Data pair */
1214 while (data_offset < end_offset) {
1215 old_offset = data_offset;
1216 data_offset = acn_add_dmp_address(tvb, pinfo, pdu_tree, data_offset, &adt);
1217 if (old_offset == data_offset) break;
1219 adt.data_length = data_length - (data_offset - old_offset);
1220 old_offset = data_offset;
1221 data_offset = acn_add_dmp_data(tvb, pinfo, pdu_tree, data_offset, &adt);
1222 if (old_offset == data_offset) break;
1225 case ACN_DMP_VECTOR_GET_PROPERTY_REPLY:
1226 /* Rip through Property Address-Data pairs */
1227 /* But, in reality, this generally won't work as we have know way of */
1228 /* calculating the next Address-Data pair */
1229 while (data_offset < end_offset) {
1230 old_offset = data_offset;
1231 data_offset = acn_add_dmp_address(tvb, pinfo, pdu_tree, data_offset, &adt);
1232 if (old_offset == data_offset) break;
1234 adt.data_length = data_length - (data_offset - old_offset);
1235 old_offset = data_offset;
1236 data_offset = acn_add_dmp_data(tvb, pinfo, pdu_tree, data_offset, &adt);
1237 if (old_offset == data_offset) break;
1240 case ACN_DMP_VECTOR_EVENT:
1241 /* Rip through Property Address-Data pairs */
1242 /* But, in reality, this generally won't work as we have know way of */
1243 /* calculating the next Address-Data pair */
1244 while (data_offset < end_offset) {
1245 old_offset = data_offset;
1246 data_offset = acn_add_dmp_address(tvb, pinfo, pdu_tree, data_offset, &adt);
1247 if (old_offset == data_offset) break;
1249 adt.data_length = data_length - (data_offset - old_offset);
1250 old_offset = data_offset;
1251 data_offset = acn_add_dmp_data(tvb, pinfo, pdu_tree, data_offset, &adt);
1252 if (old_offset == data_offset) break;
1255 case ACN_DMP_VECTOR_MAP_PROPERTY:
1256 /* Virtual Address type */
1257 data_offset = acn_add_dmp_address_type(tvb, pinfo, pdu_tree, data_offset, &adt2);
1258 /* Rip through Actual-Virtual Address Pairs */
1259 while (data_offset < end_offset) {
1261 old_offset = data_offset;
1262 data_offset = acn_add_dmp_address(tvb, pinfo, pdu_tree, data_offset, &adt);
1263 if (old_offset == data_offset) break;
1264 D = ACN_DMP_ADT_EXTRACT_D(adt.flags);
1266 case ACN_DMP_ADT_D_NS:
1269 case ACN_DMP_ADT_D_RS:
1272 case ACN_DMP_ADT_D_RE:
1273 address_count = adt.count;
1275 /*case ACN_DMP_ADT_D_RM: */
1278 return pdu_start + pdu_length;
1283 while (address_count > 0) {
1284 data_offset = acn_add_dmp_address(tvb, pinfo, pdu_tree, data_offset, &adt2);
1289 case ACN_DMP_VECTOR_UNMAP_PROPERTY:
1290 /* Rip trough Actaul Proptery Address */
1291 while (data_offset < end_offset) {
1292 old_offset = data_offset;
1293 data_offset = acn_add_dmp_address(tvb, pinfo, pdu_tree, data_offset, &adt);
1294 if (old_offset == data_offset) break;
1297 case ACN_DMP_VECTOR_SUBSCRIBE:
1298 /* Rip trough Proptery Address */
1299 while (data_offset < end_offset) {
1300 old_offset = data_offset;
1301 data_offset = acn_add_dmp_address(tvb, pinfo, pdu_tree, data_offset, &adt);
1302 if (old_offset == data_offset) break;
1305 case ACN_DMP_VECTOR_UNSUBSCRIBE:
1306 /* Rip trough Proptery Address */
1307 while (data_offset < end_offset) {
1308 old_offset = data_offset;
1309 data_offset = acn_add_dmp_address(tvb, pinfo, pdu_tree, data_offset, &adt);
1310 if (old_offset == data_offset) break;
1313 case ACN_DMP_VECTOR_GET_PROPERTY_FAIL:
1314 /* Rip trough Address-Reason Code Pairs */
1315 while (data_offset < end_offset) {
1316 old_offset = data_offset;
1317 data_offset = acn_add_dmp_address(tvb, pinfo, pdu_tree, data_offset, &adt);
1318 if (old_offset == data_offset) break;
1320 adt.data_length = data_length - (data_offset - old_offset);
1321 old_offset = data_offset;
1322 data_offset = acn_add_dmp_reason_codes(tvb, pinfo, pdu_tree, data_offset, &adt);
1323 if (old_offset == data_offset) break;
1326 case ACN_DMP_VECTOR_SET_PROPERTY_FAIL:
1327 /* Rip trough Address-Reason Code Pairs */
1328 while (data_offset < end_offset) {
1329 old_offset = data_offset;
1330 data_offset = acn_add_dmp_address(tvb, pinfo, pdu_tree, data_offset, &adt);
1331 if (old_offset == data_offset) break;
1333 adt.data_length = data_length - (data_offset - old_offset);
1334 old_offset = data_offset;
1335 data_offset = acn_add_dmp_reason_codes(tvb, pinfo, pdu_tree, data_offset, &adt);
1336 if (old_offset == data_offset) break;
1339 case ACN_DMP_VECTOR_MAP_PROPERTY_FAIL:
1340 /* Rip trough Address-Reason Code Pairs */
1341 while (data_offset < end_offset) {
1342 old_offset = data_offset;
1343 data_offset = acn_add_dmp_address(tvb, pinfo, pdu_tree, data_offset, &adt);
1344 if (old_offset == data_offset) break;
1346 adt.data_length = data_length - (data_offset - old_offset);
1347 old_offset = data_offset;
1348 data_offset = acn_add_dmp_reason_codes(tvb, pinfo, pdu_tree, data_offset, &adt);
1349 if (old_offset == data_offset) break;
1352 case ACN_DMP_VECTOR_SUBSCRIBE_ACCEPT:
1353 /* Rip through Property Addrsses */
1354 while (data_offset < end_offset) {
1355 old_offset = data_offset;
1356 data_offset = acn_add_dmp_address(tvb, pinfo, pdu_tree, data_offset, &adt);
1357 if (old_offset == data_offset) break;
1360 case ACN_DMP_VECTOR_SUBSCRIBE_REJECT:
1361 /* Rip trough Address-Reason Code Pairs */
1362 while (data_offset < end_offset) {
1363 old_offset = data_offset;
1364 data_offset = acn_add_dmp_address(tvb, pinfo, pdu_tree, data_offset, &adt);
1365 if (old_offset == data_offset) break;
1367 adt.data_length = data_length - (data_offset - old_offset);
1368 old_offset = data_offset;
1369 data_offset = acn_add_dmp_reason_codes(tvb, pinfo, pdu_tree, data_offset, &adt);
1370 if (old_offset == data_offset) break;
1373 case ACN_DMP_VECTOR_ALLOCATE_MAP:
1374 /* No data for this */
1376 case ACN_DMP_VECTOR_ALLOCATE_MAP_REPLY:
1377 /* Single reason code */
1378 proto_tree_add_item(pdu_tree, hf_acn_dmp_reason_code, tvb, data_offset, 1, FALSE);
1380 case ACN_DMP_VECTOR_DEALLOCATE_MAP:
1381 /* No data for this */
1385 return pdu_start + pdu_length;
1389 /******************************************************************************/
1390 /* Dissect wrapped SDT PDU */
1392 dissect_acn_sdt_wrapped_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree _U_, int offset, acn_pdu_offsets *last_pdu_offsets)
1394 /* common to all pdu */
1398 guint32 pdu_flvh_length; /* flags, length, vector, header */
1399 acn_pdu_offsets pdu_offsets = {0,0,0,0,0};
1404 guint32 vector_offset;
1405 guint32 data_offset;
1407 guint32 data_length;
1409 proto_item *ti, *pi;
1410 proto_tree *pdu_tree = NULL;
1411 proto_tree *flag_tree = NULL;
1417 /* save start of pdu block */
1419 pdu_offsets.start = pdu_start;
1421 /* get PDU flags and length flag first */
1422 octet = tvb_get_guint8(tvb, offset++);
1423 pdu_flags = octet & 0xf0;
1424 length1 = octet & 0x0f; /* bottom 4 bits only */
1425 length2 = tvb_get_guint8(tvb, offset++);
1427 /* if length flag is set, then we have a 20 bit length else we have a 12 bit */
1428 /* flvh = flags, length, vector, header */
1429 if (pdu_flags & ACN_PDU_FLAG_L) {
1430 length3 = tvb_get_guint8(tvb, offset);
1432 pdu_length = length3 | (length2 << 8) | (length1 << 16);
1433 pdu_flvh_length = 3;
1435 pdu_length = length2 | (length1 << 8);
1436 pdu_flvh_length = 2;
1438 /* offset should now be pointing to vector (if one exists) */
1440 /* Add pdu item and tree */
1441 ti = proto_tree_add_item(tree, hf_acn_pdu, tvb, pdu_start, pdu_length, FALSE);
1442 pdu_tree = proto_item_add_subtree(ti, ett_acn_sdt_pdu);
1444 /* Add flag item and tree */
1445 pi = proto_tree_add_uint(pdu_tree, hf_acn_pdu_flags, tvb, pdu_start, 1, pdu_flags);
1446 flag_tree = proto_item_add_subtree(pi, ett_acn_pdu_flags);
1447 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_l, tvb, pdu_start, 1, FALSE);
1448 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_v, tvb, pdu_start, 1, FALSE);
1449 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_h, tvb, pdu_start, 1, FALSE);
1450 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_d, tvb, pdu_start, 1, FALSE);
1452 /* Add PDU Length item */
1453 proto_tree_add_uint(pdu_tree, hf_acn_pdu_length, tvb, pdu_start, pdu_flvh_length, pdu_length);
1455 /* Set vector offset */
1456 if (pdu_flags & ACN_PDU_FLAG_V) {
1457 /* use new values */
1458 vector_offset = offset;
1459 last_pdu_offsets->vector = offset;
1463 /* use last values */
1464 vector_offset = last_pdu_offsets->vector;
1466 /* offset should now be pointing to header (if one exists) */
1468 /* Add Vector item */
1469 vector = tvb_get_guint8(tvb, vector_offset);
1470 proto_tree_add_uint(pdu_tree, hf_acn_sdt_vector, tvb, vector_offset, 1, vector);
1472 /* Add Vector item to tree*/
1473 name = val_to_str(vector, acn_sdt_vector_vals, "not valid (%d)");
1474 proto_item_append_text(ti, ": ");
1475 proto_item_append_text(ti, name);
1477 /* NO HEADER DATA ON THESE* (at least so far) */
1480 if (pdu_flags & ACN_PDU_FLAG_D) {
1481 /* use new values */
1482 data_offset = offset;
1483 data_length = pdu_length - pdu_flvh_length;
1484 last_pdu_offsets->data = offset;
1485 last_pdu_offsets->data_length = data_length;
1487 /* use last values */
1488 data_offset = last_pdu_offsets->data;
1489 data_length = last_pdu_offsets->data_length;
1491 end_offset = data_offset + data_length;
1494 case ACN_SDT_VECTOR_ACK:
1495 proto_tree_add_item(pdu_tree, hf_acn_reliable_sequence_number, tvb, data_offset, 4, FALSE);
1498 case ACN_SDT_VECTOR_CHANNEL_PARAMS:
1499 data_offset = acn_add_channel_parameter(tvb, pinfo, pdu_tree, data_offset);
1500 data_offset = acn_add_address(tvb, pinfo, pdu_tree, data_offset, "Ad-hoc Address:");
1501 data_offset = acn_add_expiry(tvb, pinfo, pdu_tree, data_offset, "Ad-hoc Expiry:");
1503 case ACN_SDT_VECTOR_LEAVE:
1506 case ACN_SDT_VECTOR_CONNECT:
1507 /* Protocol ID item */
1508 proto_tree_add_item(pdu_tree, hf_acn_protocol_id, tvb, data_offset, 4, FALSE);
1511 case ACN_SDT_VECTOR_CONNECT_ACCEPT:
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_REFUSE:
1517 /* Protocol ID item */
1518 proto_tree_add_item(pdu_tree, hf_acn_protocol_id, tvb, data_offset, 4, FALSE);
1520 proto_tree_add_item(pdu_tree, hf_acn_refuse_code, tvb, data_offset, 1, FALSE);
1523 case ACN_SDT_VECTOR_DISCONNECT:
1524 /* Protocol ID item */
1525 proto_tree_add_item(pdu_tree, hf_acn_protocol_id, tvb, data_offset, 4, FALSE);
1528 case ACN_SDT_VECTOR_DISCONNECTING:
1529 /* Protocol ID item */
1530 proto_tree_add_item(pdu_tree, hf_acn_protocol_id, tvb, data_offset, 4, FALSE);
1532 proto_tree_add_item(pdu_tree, hf_acn_reason_code, tvb, data_offset, 1, FALSE);
1538 return pdu_start + pdu_length;
1542 /******************************************************************************/
1543 /* Dissect SDT Client PDU */
1545 dissect_acn_sdt_client_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, acn_pdu_offsets *last_pdu_offsets)
1547 /* common to all pdu */
1551 guint32 pdu_flvh_length; /* flags, length, vector, header */
1552 acn_pdu_offsets pdu_offsets = {0,0,0,0,0};
1557 guint32 vector_offset;
1558 guint32 header_offset;
1559 guint32 data_offset;
1560 guint32 data_length;
1564 proto_item *ti, *pi;
1565 proto_tree *pdu_tree = NULL;
1566 proto_tree *flag_tree = NULL;
1571 guint32 protocol_id;
1572 guint16 association;
1574 /* save start of pdu block */
1576 pdu_offsets.start = pdu_start;
1578 /* get PDU flags and length flag first */
1579 octet = tvb_get_guint8(tvb, offset++);
1580 pdu_flags = octet & 0xf0;
1581 length1 = octet & 0x0f; /* bottom 4 bits only */
1582 length2 = tvb_get_guint8(tvb, offset++);
1584 /* if length flag is set, then we have a 20 bit length else we have a 12 bit */
1585 /* flvh = flags, length, vector, header */
1586 if (pdu_flags & ACN_PDU_FLAG_L) {
1587 length3 = tvb_get_guint8(tvb, offset);
1589 pdu_length = length3 | (length2 << 8) | (length1 << 16);
1590 pdu_flvh_length = 3;
1592 pdu_length = length2 | (length1 << 8);
1593 pdu_flvh_length = 2;
1595 /* offset should now be pointing to vector (if one exists) */
1597 /* Add pdu item and tree */
1598 ti = proto_tree_add_item(tree, hf_acn_pdu, tvb, pdu_start, pdu_length, FALSE);
1599 pdu_tree = proto_item_add_subtree(ti, ett_acn_sdt_client_pdu);
1601 /* Add flag item and tree */
1602 pi = proto_tree_add_uint(pdu_tree, hf_acn_pdu_flags, tvb, pdu_start, 1, pdu_flags);
1603 flag_tree = proto_item_add_subtree(pi, ett_acn_pdu_flags);
1604 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_l, tvb, pdu_start, 1, FALSE);
1605 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_v, tvb, pdu_start, 1, FALSE);
1606 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_h, tvb, pdu_start, 1, FALSE);
1607 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_d, tvb, pdu_start, 1, FALSE);
1609 /* Add PDU Length item */
1610 proto_tree_add_uint(pdu_tree, hf_acn_pdu_length, tvb, pdu_start, pdu_flvh_length, pdu_length);
1612 /* Set vector offset */
1613 if (pdu_flags & ACN_PDU_FLAG_V) {
1614 /* use new values */
1615 vector_offset = offset;
1616 last_pdu_offsets->vector = offset;
1618 pdu_flvh_length += 2;
1620 /* use last values */
1621 vector_offset = last_pdu_offsets->vector;
1623 /* offset should now be pointing to header (if one exists) */
1625 /* add Member ID item */
1626 member_id = tvb_get_ntohs(tvb, vector_offset);
1627 proto_tree_add_uint(pdu_tree, hf_acn_member_id, tvb, vector_offset, 2, member_id);
1629 /* Set header offset */
1630 if (pdu_flags & ACN_PDU_FLAG_H) {
1631 /* use new values */
1632 header_offset = offset;
1633 last_pdu_offsets->header = offset;
1635 pdu_flvh_length += 6;
1637 /* use last values */
1638 header_offset = last_pdu_offsets->header;
1640 /* offset should now be pointing to data (if one exists) */
1642 /* add Protocol ID item (Header)*/
1643 protocol_id = tvb_get_ntohl(tvb, header_offset);
1644 proto_tree_add_uint(pdu_tree, hf_acn_protocol_id, tvb, header_offset, 4, protocol_id);
1647 /* Add protocol to tree*/
1648 name = val_to_str(protocol_id, acn_protocol_id_vals, "id not valid (%d)");
1649 proto_item_append_text(ti, ": ");
1650 proto_item_append_text(ti, name);
1652 /* add association item */
1653 association = tvb_get_ntohs(tvb, header_offset);
1654 proto_tree_add_uint(pdu_tree, hf_acn_association, tvb, header_offset, 2, association);
1658 if (pdu_flags & ACN_PDU_FLAG_D) {
1659 /* use new values */
1660 data_offset = offset;
1661 data_length = pdu_length - pdu_flvh_length;
1662 last_pdu_offsets->data = offset;
1663 last_pdu_offsets->data_length = data_length;
1665 /* use last values */
1666 data_offset = last_pdu_offsets->data;
1667 data_length = last_pdu_offsets->data_length;
1669 end_offset = data_offset + data_length;
1671 switch (protocol_id) {
1672 case ACN_PROTOCOL_ID_SDT:
1673 while (data_offset < end_offset) {
1674 old_offset = data_offset;
1675 data_offset = dissect_acn_sdt_wrapped_pdu(tvb, pinfo, pdu_tree, data_offset, &pdu_offsets);
1676 if (old_offset == data_offset) break;
1679 case ACN_PROTOCOL_ID_DMP:
1680 while (data_offset < end_offset) {
1681 old_offset = data_offset;
1682 data_offset = dissect_acn_dmp_pdu(tvb, pinfo, pdu_tree, data_offset, &pdu_offsets);
1683 if (data_offset == old_offset) break;
1687 return pdu_start + pdu_length;
1691 /******************************************************************************/
1692 /* reverses the characters in a string */
1698 for (i=0, j=strlen(s)-1; i < j; i++, j--) {
1706 /******************************************************************************/
1707 /* level to string (ascii) */
1708 /* level : 8 bit value */
1709 /* string : pointer to buffer to fill */
1710 /* leading_char: character to buffer left of digits */
1711 /* min_char : mininum number of characters (for filling, not including space)*/
1712 /* show_zero: show zeros or dots */
1713 /* also adds a space to right end */
1715 /* returns end of string */
1716 /* faster than printf() */
1718 ltos(guint8 level, gchar *string, guint8 base, gchar leading_char, guint8 min_chars, gboolean show_zero)
1722 if (base < 2 || base > 16) {
1726 /* deal with zeros */
1727 if ((level == 0) && (!show_zero)) {
1728 for (i=0;i<min_chars;i++) {
1737 /* do our convert, comes out backwords! */
1739 string[i++] = "0123456789ABCDEF"[level % base];
1740 } while ((level /= base) > 0);
1742 /* expand to needed character */
1743 for (;i<min_chars;i++) {
1744 string[i] = leading_char;
1749 /* now reverse (and correct) the order */
1752 /* add a space at the end (ok its at the start but it will be at the end)*/
1759 /******************************************************************************/
1760 /* Dissect DMX data PDU */
1761 #define BUFFER_SIZE 128
1763 dissect_acn_dmx_data_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, acn_pdu_offsets *last_pdu_offsets)
1765 /* common to all pdu */
1769 guint32 pdu_flvh_length; /* flags, length, vector, header */
1770 acn_pdu_offsets pdu_offsets = {0,0,0,0,0};
1775 guint32 vector_offset;
1776 guint32 data_offset;
1778 guint32 data_length;
1779 guint32 header_offset;
1784 proto_item *ti, *pi;
1785 proto_tree *pdu_tree = NULL;
1786 proto_tree *flag_tree = NULL;
1787 /* proto_tree *addr_tree = NULL; */
1790 acn_dmp_adt_type adt = {0,0,0,0,0,0};
1793 gchar buffer[BUFFER_SIZE];
1803 guint16 dmx_start_code;
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 name = val_to_str(vector, acn_dmp_vector_vals, "not valid (%d)");
1864 proto_item_append_text(ti, ": ");
1865 proto_item_append_text(ti, name);
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 dmx_start_code = tvb_get_ntohs(tvb, data_offset);
1900 proto_tree_add_item(pdu_tree, hf_acn_dmx_start_code, tvb, data_offset, 2, FALSE);
1902 proto_tree_add_item(pdu_tree, hf_acn_dmx_increment, tvb, data_offset, 2, FALSE);
1904 dmx_count = tvb_get_ntohs(tvb, data_offset);
1905 proto_tree_add_item(pdu_tree, hf_acn_dmx_count, tvb, data_offset, 2, FALSE);
1910 switch (global_acn_dmx_display_line_format) {
1911 case ACN_PREF_DMX_DISPLAY_16PL:
1920 /* values base on display mode */
1921 switch ((guint)global_acn_dmx_display_view) {
1922 case ACN_PREF_DMX_DISPLAY_HEX:
1926 /* case ACN_PREF_DMX_DISPLAY_PER: */
1932 /* do we display leading zeros */
1933 if (global_acn_dmx_display_leading_zeros) {
1939 /* add a snippet to info (this may be slow) */
1940 if(check_col(pinfo->cinfo,COL_INFO)){
1941 col_append_fstr(pinfo->cinfo,COL_INFO, ", Sc %02x, [%02x %02x %02x %02x %02x %02x...]",
1943 tvb_get_guint8(tvb, data_offset),
1944 tvb_get_guint8(tvb, data_offset+1),
1945 tvb_get_guint8(tvb, data_offset+2),
1946 tvb_get_guint8(tvb, data_offset+3),
1947 tvb_get_guint8(tvb, data_offset+4),
1948 tvb_get_guint8(tvb, data_offset+5));
1951 /* add a header line */
1952 g_snprintf(buffer, BUFFER_SIZE, "%-10s: ", "Data...");
1955 for (x=1;x<=perline;x++) {
1956 buf_ptr = ltos((guint8)x, buf_ptr, 10, ' ', min_char, FALSE);
1963 proto_tree_add_text(pdu_tree, tvb, data_offset, dmx_count, buffer);
1965 /* start our line */
1966 g_snprintf(buffer, BUFFER_SIZE, "001-%03d: ", perline);
1967 buf_ptr = buffer + 9;
1971 for (x=data_offset; x < end_offset; x++) {
1972 level = tvb_get_guint8(tvb, x);
1973 if (global_acn_dmx_display_view==ACN_PREF_DMX_DISPLAY_PER) {
1974 if ((level > 0) && (level < 3)) {
1977 level = level * 100 / 255;
1980 buf_ptr = ltos(level, buf_ptr, base, leading_char, min_char, global_acn_dmx_display_zeros);
1984 if (item_cnt == perline || x == (end_offset-1)) {
1986 proto_tree_add_text(pdu_tree, tvb, data_offset, item_cnt, buffer);
1987 data_offset += perline;
1988 g_snprintf(buffer, BUFFER_SIZE, "%03d-%03d: ",total_cnt, total_cnt+perline);
1989 buf_ptr = buffer + 9;
1992 /* add separater character */
1993 if (item_cnt == halfline) {
2001 address data type (fixed at 0xA2)
2002 start code - 1 byte, reserved (should be 0)
2003 - 1 byte, start code (0x255)
2004 - 2 bytes, packet offset (should be 0000)
2005 address increment - 4 bytes (ignore)
2006 number of dmx values - 4 bytes (0-512)
2007 dmx values 0-512 bytes (data)
2012 return pdu_start + pdu_length;
2017 /******************************************************************************/
2018 /* Dissect DMX Base PDU */
2020 dissect_acn_dmx_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, acn_pdu_offsets *last_pdu_offsets)
2022 /* common to all pdu */
2026 guint32 pdu_flvh_length; /* flags, length, vector, header */
2027 acn_pdu_offsets pdu_offsets = {0,0,0,0,0};
2032 guint32 vector_offset;
2033 guint32 data_offset;
2035 guint32 data_length;
2037 proto_item *ti, *pi;
2038 proto_tree *pdu_tree = NULL;
2039 proto_tree *flag_tree = NULL;
2050 /* save start of pdu block */
2052 pdu_offsets.start = pdu_start;
2054 /* get PDU flags and length flag first */
2055 octet = tvb_get_guint8(tvb, offset++);
2056 pdu_flags = octet & 0xf0;
2057 length1 = octet & 0x0f; /* bottom 4 bits only */
2058 length2 = tvb_get_guint8(tvb, offset++);
2060 /* if length flag is set, then we have a 20 bit length else we have a 12 bit */
2061 /* flvh = flags, length, vector, header */
2062 if (pdu_flags & ACN_PDU_FLAG_L) {
2063 length3 = tvb_get_guint8(tvb, offset);
2065 pdu_length = length3 | (length2 << 8) | (length1 << 16);
2066 pdu_flvh_length = 3;
2068 pdu_length = length2 | (length1 << 8);
2069 pdu_flvh_length = 2;
2072 /* offset should now be pointing to vector (if one exists) */
2074 /* Add pdu item and tree */
2075 ti = proto_tree_add_item(tree, hf_acn_pdu, tvb, pdu_start, pdu_length, FALSE);
2076 pdu_tree = proto_item_add_subtree(ti, ett_acn_dmx_pdu);
2078 /* Add flag item and tree */
2079 pi = proto_tree_add_uint(pdu_tree, hf_acn_pdu_flags, tvb, pdu_start, 1, pdu_flags);
2080 flag_tree = proto_item_add_subtree(pi, ett_acn_pdu_flags);
2081 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_l, tvb, pdu_start, 1, FALSE);
2082 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_v, tvb, pdu_start, 1, FALSE);
2083 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_h, tvb, pdu_start, 1, FALSE);
2084 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_d, tvb, pdu_start, 1, FALSE);
2086 /* Add PDU Length item */
2087 proto_tree_add_uint(pdu_tree, hf_acn_pdu_length, tvb, pdu_start, pdu_flvh_length, pdu_length);
2089 /* Set vector offset */
2090 if (pdu_flags & ACN_PDU_FLAG_V) {
2091 /* use new values */
2092 vector_offset = offset;
2093 last_pdu_offsets->vector = offset;
2095 pdu_flvh_length += 4;
2097 /* use last values */
2098 vector_offset = last_pdu_offsets->vector;
2100 /* offset should now be pointing to header (if one exists) */
2102 /* Add Vector item */
2103 vector = tvb_get_ntohl(tvb, vector_offset);
2104 proto_tree_add_item(pdu_tree, hf_acn_dmx_vector, tvb, vector_offset, 4, FALSE);
2105 /* vector_offset +=4; */
2107 /* Add Vector item to tree*/
2108 name = val_to_str(vector, acn_dmx_vector_vals, "not valid (%d)");
2109 proto_item_append_text(ti, ": %s", name);
2111 /* NO HEADER DATA ON THESE* (at least so far) */
2114 if (pdu_flags & ACN_PDU_FLAG_D) {
2115 /* use new values */
2116 data_offset = offset;
2117 data_length = pdu_length - pdu_flvh_length;
2118 last_pdu_offsets->data = offset;
2119 last_pdu_offsets->data_length = data_length;
2121 /* use last values */
2122 data_offset = last_pdu_offsets->data;
2123 data_length = last_pdu_offsets->data_length;
2125 end_offset = data_offset + data_length;
2127 /* process based on vector */
2130 proto_tree_add_item(pdu_tree, hf_acn_dmx_source_name, tvb, data_offset, 32, FALSE);
2133 priority = tvb_get_guint8(tvb, data_offset);
2134 proto_tree_add_item(pdu_tree, hf_acn_dmx_priority, tvb, data_offset, 1, FALSE);
2137 sequence = tvb_get_guint8(tvb, data_offset);
2138 proto_tree_add_item(pdu_tree, hf_acn_dmx_sequence_number, tvb, data_offset, 1, FALSE);
2141 universe = tvb_get_ntohs(tvb, data_offset);
2142 proto_tree_add_item(pdu_tree, hf_acn_dmx_universe , tvb, data_offset, 2, FALSE);
2145 /* add universe to info */
2146 if(check_col(pinfo->cinfo,COL_INFO)){
2147 col_append_fstr(pinfo->cinfo,COL_INFO, ", Universe %d, Seq %3d", universe, sequence );
2150 proto_item_append_text(ti, ", Universe: %d, Priority: %d", universe, priority);
2152 data_offset = dissect_acn_dmx_data_pdu(tvb, pinfo, pdu_tree, data_offset, &pdu_offsets);
2156 return pdu_start + pdu_length;
2159 /******************************************************************************/
2160 /* Dissect SDT Base PDU */
2162 dissect_acn_sdt_base_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, acn_pdu_offsets *last_pdu_offsets)
2164 /* common to all pdu */
2168 guint32 pdu_flvh_length; /* flags, length, vector, header */
2169 acn_pdu_offsets pdu_offsets = {0,0,0,0,0};
2174 guint32 vector_offset;
2175 guint32 data_offset;
2178 guint32 data_length;
2180 proto_item *ti, *pi;
2181 proto_tree *pdu_tree = NULL;
2182 proto_tree *flag_tree = NULL;
2189 /* save start of pdu block */
2191 pdu_offsets.start = pdu_start;
2193 /* get PDU flags and length flag first */
2194 octet = tvb_get_guint8(tvb, offset++);
2195 pdu_flags = octet & 0xf0;
2196 length1 = octet & 0x0f; /* bottom 4 bits only */
2197 length2 = tvb_get_guint8(tvb, offset++);
2199 /* if length flag is set, then we have a 20 bit length else we have a 12 bit */
2200 /* flvh = flags, length, vector, header */
2201 if (pdu_flags & ACN_PDU_FLAG_L) {
2202 length3 = tvb_get_guint8(tvb, offset);
2204 pdu_length = length3 | (length2 << 8) | (length1 << 16);
2205 pdu_flvh_length = 3;
2207 pdu_length = length2 | (length1 << 8);
2208 pdu_flvh_length = 2;
2210 /* offset should now be pointing to vector (if one exists) */
2212 /* Add pdu item and tree */
2213 ti = proto_tree_add_item(tree, hf_acn_pdu, tvb, pdu_start, pdu_length, FALSE);
2214 pdu_tree = proto_item_add_subtree(ti, ett_acn_sdt_base_pdu);
2216 /* Add flag item and tree */
2217 pi = proto_tree_add_uint(pdu_tree, hf_acn_pdu_flags, tvb, pdu_start, 1, pdu_flags);
2218 flag_tree = proto_item_add_subtree(pi, ett_acn_pdu_flags);
2219 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_l, tvb, pdu_start, 1, FALSE);
2220 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_v, tvb, pdu_start, 1, FALSE);
2221 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_h, tvb, pdu_start, 1, FALSE);
2222 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_d, tvb, pdu_start, 1, FALSE);
2224 /* Add PDU Length item */
2225 proto_tree_add_uint(pdu_tree, hf_acn_pdu_length, tvb, pdu_start, pdu_flvh_length, pdu_length);
2227 /* Set vector offset */
2228 if (pdu_flags & ACN_PDU_FLAG_V) {
2229 /* use new values */
2230 vector_offset = offset;
2231 last_pdu_offsets->vector = offset;
2235 /* use last values */
2236 vector_offset = last_pdu_offsets->vector;
2238 /* offset should now be pointing to header (if one exists) */
2240 /* Add Vector item */
2241 vector = tvb_get_guint8(tvb, vector_offset);
2242 proto_tree_add_uint(pdu_tree, hf_acn_sdt_vector, tvb, vector_offset, 1, vector);
2244 /* Add Vector item to tree*/
2245 name = val_to_str(vector, acn_sdt_vector_vals, "not valid (%d)");
2246 proto_item_append_text(ti, ": ");
2247 proto_item_append_text(ti, name);
2249 /* NO HEADER DATA ON THESE* (at least so far) */
2252 if (pdu_flags & ACN_PDU_FLAG_D) {
2253 /* use new values */
2254 data_offset = offset;
2255 data_length = pdu_length - pdu_flvh_length;
2256 last_pdu_offsets->data = offset;
2257 last_pdu_offsets->data_length = data_length;
2259 /* use last values */
2260 data_offset = last_pdu_offsets->data;
2261 data_length = last_pdu_offsets->data_length;
2263 end_offset = data_offset + data_length;
2265 /* process based on vector */
2267 case ACN_SDT_VECTOR_UNKNOWN:
2269 case ACN_SDT_VECTOR_REL_WRAP:
2270 case ACN_SDT_VECTOR_UNREL_WRAP:
2271 proto_tree_add_item(pdu_tree, hf_acn_channel_number, tvb, data_offset, 2, FALSE);
2273 proto_tree_add_item(pdu_tree, hf_acn_total_sequence_number, tvb, data_offset, 4, FALSE);
2275 proto_tree_add_item(pdu_tree, hf_acn_reliable_sequence_number, tvb, data_offset, 4, FALSE);
2277 proto_tree_add_item(pdu_tree, hf_acn_oldest_available_wrapper, tvb, data_offset, 4, FALSE);
2279 proto_tree_add_item(pdu_tree, hf_acn_first_memeber_to_ack, tvb, data_offset, 2, FALSE);
2281 proto_tree_add_item(pdu_tree, hf_acn_last_memeber_to_ack, tvb, data_offset, 2, FALSE);
2283 proto_tree_add_item(pdu_tree, hf_acn_mak_threshold, tvb, data_offset, 2, FALSE);
2286 while (data_offset < end_offset) {
2287 old_offset = data_offset;
2288 data_offset = dissect_acn_sdt_client_pdu(tvb, pinfo, pdu_tree, data_offset, &pdu_offsets);
2289 if (data_offset == old_offset) break;
2292 case ACN_SDT_VECTOR_CHANNEL_PARAMS:
2294 case ACN_SDT_VECTOR_JOIN:
2295 proto_tree_add_item(pdu_tree, hf_acn_cid, tvb, data_offset, 16, FALSE);
2297 proto_tree_add_item(pdu_tree, hf_acn_member_id, tvb, data_offset, 2, FALSE);
2299 proto_tree_add_item(pdu_tree, hf_acn_channel_number, tvb, data_offset, 2, FALSE);
2301 proto_tree_add_item(pdu_tree, hf_acn_reciprocal_channel, tvb, data_offset, 2, FALSE);
2303 proto_tree_add_item(pdu_tree, hf_acn_total_sequence_number, tvb, data_offset, 4, FALSE);
2305 proto_tree_add_item(pdu_tree, hf_acn_reliable_sequence_number, tvb, data_offset, 4, FALSE);
2307 data_offset = acn_add_address(tvb, pinfo, pdu_tree, data_offset, "Destination Address:");
2308 data_offset = acn_add_channel_parameter(tvb, pinfo, pdu_tree, data_offset);
2309 data_offset = acn_add_expiry(tvb, pinfo, pdu_tree, data_offset, "Ad-hoc Expiry:");
2311 case ACN_SDT_VECTOR_JOIN_REFUSE:
2312 pi = proto_tree_add_item(pdu_tree, hf_acn_cid, tvb, data_offset, 16, FALSE);
2314 proto_item_append_text(pi, "(Leader)");
2315 proto_tree_add_item(pdu_tree, hf_acn_channel_number, tvb, data_offset, 2, FALSE);
2317 proto_tree_add_item(pdu_tree, hf_acn_member_id, tvb, data_offset, 2, FALSE);
2319 proto_tree_add_item(pdu_tree, hf_acn_reliable_sequence_number, tvb, data_offset, 4, FALSE);
2321 proto_tree_add_item(pdu_tree, hf_acn_refuse_code, tvb, data_offset, 1, FALSE);
2324 case ACN_SDT_VECTOR_JOIN_ACCEPT:
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_reciprocal_channel, tvb, data_offset, 2, FALSE);
2337 case ACN_SDT_VECTOR_LEAVE:
2339 case ACN_SDT_VECTOR_LEAVING:
2340 pi = proto_tree_add_item(pdu_tree, hf_acn_cid, tvb, data_offset, 16, FALSE);
2342 proto_item_append_text(pi, "(Leader)");
2343 proto_tree_add_item(pdu_tree, hf_acn_channel_number, tvb, data_offset, 2, FALSE);
2345 proto_tree_add_item(pdu_tree, hf_acn_member_id, tvb, data_offset, 2, FALSE);
2347 proto_tree_add_item(pdu_tree, hf_acn_reliable_sequence_number, tvb, data_offset, 4, FALSE);
2349 proto_tree_add_item(pdu_tree, hf_acn_reason_code, tvb, data_offset, 1, FALSE);
2352 case ACN_SDT_VECTOR_CONNECT:
2354 case ACN_SDT_VECTOR_CONNECT_ACCEPT:
2356 case ACN_SDT_VECTOR_CONNECT_REFUSE:
2358 case ACN_SDT_VECTOR_DISCONNECT:
2360 case ACN_SDT_VECTOR_DISCONNECTING:
2362 case ACN_SDT_VECTOR_ACK:
2364 case ACN_SDT_VECTOR_NAK:
2365 pi = proto_tree_add_item(pdu_tree, hf_acn_cid, tvb, data_offset, 16, FALSE);
2367 proto_item_append_text(pi, "(Leader)");
2368 proto_tree_add_item(pdu_tree, hf_acn_channel_number, tvb, data_offset, 2, FALSE);
2370 proto_tree_add_item(pdu_tree, hf_acn_member_id, tvb, data_offset, 2, FALSE);
2372 proto_tree_add_item(pdu_tree, hf_acn_reliable_sequence_number, tvb, data_offset, 4, FALSE);
2374 proto_tree_add_item(pdu_tree, hf_acn_first_missed_sequence, tvb, data_offset, 4, FALSE);
2376 proto_tree_add_item(pdu_tree, hf_acn_last_missed_sequence, tvb, data_offset, 4, FALSE);
2379 case ACN_SDT_VECTOR_GET_SESSION:
2380 proto_tree_add_item(pdu_tree, hf_acn_cid, tvb, data_offset, 16, FALSE);
2383 case ACN_SDT_VECTOR_SESSIONS:
2384 member_id = tvb_get_ntohs(tvb, data_offset);
2385 switch (member_id) {
2387 data_offset = acn_add_channel_owner_info_block(tvb, pinfo, pdu_tree, data_offset);
2390 data_offset = acn_add_channel_member_info_block(tvb, pinfo, pdu_tree, data_offset);
2396 return pdu_start + pdu_length;
2399 /******************************************************************************/
2400 /* Dissect Root PDU */
2402 dissect_acn_root_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, acn_pdu_offsets *last_pdu_offsets)
2404 /* common to all pdu */
2408 guint32 pdu_flvh_length; /* flags, length, vector, header */
2409 acn_pdu_offsets pdu_offsets = {0,0,0,0,0};
2414 guint32 vector_offset;
2415 guint32 header_offset;
2416 guint32 data_offset;
2419 guint32 data_length;
2421 proto_item *ti, *pi;
2422 proto_tree *pdu_tree = NULL;
2423 proto_tree *flag_tree = NULL;
2426 guint32 protocol_id;
2429 /* save start of pdu block */
2431 pdu_offsets.start = pdu_start;
2433 /* get PDU flags and length flag first */
2434 octet = tvb_get_guint8(tvb, offset++);
2435 pdu_flags = octet & 0xf0;
2436 length1 = octet & 0x0f; /* bottom 4 bits only */
2437 length2 = tvb_get_guint8(tvb, offset++);
2439 /* if length flag is set, then we have a 20 bit length else we have a 12 bit */
2440 /* flvh = flags, length, vector, header */
2441 if (pdu_flags & ACN_PDU_FLAG_L) {
2442 length3 = tvb_get_guint8(tvb, offset);
2444 pdu_length = length3 | (length2 << 8) | (length1 << 16);
2445 pdu_flvh_length = 3;
2447 pdu_length = length2 | (length1 << 8);
2448 pdu_flvh_length = 2;
2450 /* offset should now be pointing to vector (if one exists) */
2452 /* Add pdu item and tree */
2453 ti = proto_tree_add_item(tree, hf_acn_pdu, tvb, pdu_start, pdu_length, FALSE);
2454 pdu_tree = proto_item_add_subtree(ti, ett_acn_root_pdu);
2456 /* Add flag item and tree */
2457 pi = proto_tree_add_uint(pdu_tree, hf_acn_pdu_flags, tvb, pdu_start, 1, pdu_flags);
2458 flag_tree = proto_item_add_subtree(pi, ett_acn_pdu_flags);
2459 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_l, tvb, pdu_start, 1, FALSE);
2460 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_v, tvb, pdu_start, 1, FALSE);
2461 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_h, tvb, pdu_start, 1, FALSE);
2462 proto_tree_add_item(flag_tree, hf_acn_pdu_flag_d, tvb, pdu_start, 1, FALSE);
2464 /* Add PDU Length item */
2465 proto_tree_add_uint(pdu_tree, hf_acn_pdu_length, tvb, pdu_start, pdu_flvh_length, pdu_length);
2467 /* Set vector offset */
2468 if (pdu_flags & ACN_PDU_FLAG_V) {
2469 /* use new values */
2470 vector_offset = offset;
2471 last_pdu_offsets->vector = offset;
2473 pdu_flvh_length += 4;
2475 /* use last values */
2476 vector_offset = last_pdu_offsets->vector;
2478 /* offset should now be pointing to header (if one exists) */
2482 /* Get Protocol ID (vector) */
2483 protocol_id = tvb_get_ntohl(tvb, vector_offset);
2484 proto_tree_add_uint(pdu_tree, hf_acn_protocol_id, tvb, vector_offset, 4, protocol_id);
2486 /* process based on protocol_id */
2487 switch (protocol_id) {
2488 case ACN_PROTOCOL_ID_DMX:
2489 if (global_acn_dmx_enable) {
2490 proto_item_append_text(ti,": Root DMX");
2492 /* Set header offset */
2493 if (pdu_flags & ACN_PDU_FLAG_H) {
2494 /* use new values */
2495 header_offset = offset;
2496 last_pdu_offsets->header = offset;
2498 pdu_flvh_length += 16;
2500 /* use last values */
2501 header_offset = last_pdu_offsets->header;
2503 /* offset should now be pointing to data (if one exists) */
2505 /* get Header (CID) 16 bytes */
2506 tvb_get_guid(tvb, header_offset, &guid, FALSE);
2507 proto_item_append_text(ti, ", Src: %s", guid_to_str(&guid));
2509 /* add cid to info */
2510 if(check_col(pinfo->cinfo,COL_INFO)){
2511 col_clear(pinfo->cinfo,COL_INFO);
2512 col_add_fstr(pinfo->cinfo,COL_INFO, "CID %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_dmx_pdu(tvb, pinfo, pdu_tree, data_offset, &pdu_offsets);
2536 if (data_offset == old_offset) break;
2540 case ACN_PROTOCOL_ID_SDT:
2542 proto_item_append_text(ti,": Root SDT");
2544 /* Set header offset */
2545 if (pdu_flags & ACN_PDU_FLAG_H) {
2546 /* use new values */
2547 header_offset = offset;
2548 last_pdu_offsets->header = offset;
2550 pdu_flvh_length += 16;
2552 /* use last values */
2553 header_offset = last_pdu_offsets->header;
2555 /* offset should now be pointing to data (if one exists) */
2557 /* get Header (CID) 16 bytes */
2558 tvb_get_guid(tvb, header_offset, &guid, FALSE);
2559 proto_item_append_text(ti, ", Src: %s", guid_to_str(&guid));
2561 proto_tree_add_item(pdu_tree, hf_acn_cid, tvb, header_offset, 16, FALSE);
2562 header_offset += 16;
2565 if (pdu_flags & ACN_PDU_FLAG_D) {
2566 /* use new values */
2567 data_offset = offset;
2568 data_length = pdu_length - pdu_flvh_length;
2569 last_pdu_offsets->data = offset;
2570 last_pdu_offsets->data_length = data_length;
2572 /* use last values */
2573 data_offset = last_pdu_offsets->data;
2574 data_length = last_pdu_offsets->data_length;
2576 end_offset = data_offset + data_length;
2578 /* adjust for what we used */
2579 while (data_offset < end_offset) {
2580 old_offset = data_offset;
2581 data_offset = dissect_acn_sdt_base_pdu(tvb, pinfo, pdu_tree, data_offset, &pdu_offsets);
2582 if (data_offset == old_offset) break;
2587 return pdu_start + pdu_length;
2590 /******************************************************************************/
2593 dissect_acn(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
2595 proto_item *ti = NULL;
2596 proto_tree *acn_tree = NULL;
2597 guint32 data_offset = 0;
2600 acn_pdu_offsets pdu_offsets = {0,0,0,0,0};
2602 /* if (!is_acn(tvb)) { */
2606 /* Set the protocol column */
2607 if (check_col(pinfo->cinfo, COL_PROTOCOL)) {
2608 col_set_str(pinfo->cinfo, COL_PROTOCOL, "ACN");
2611 /* Clear out stuff in the info column */
2612 if(check_col(pinfo->cinfo,COL_INFO)){
2613 /* col_clear(pinfo->cinfo,COL_INFO); */
2614 col_add_fstr(pinfo->cinfo,COL_INFO, "ACN [Src Port: %d, Dst Port: %d]", pinfo->srcport, pinfo->destport );
2617 if (tree) { /* we are being asked for details */
2618 ti = proto_tree_add_item(tree, proto_acn, tvb, 0, -1, FALSE);
2619 acn_tree = proto_item_add_subtree(ti, ett_acn);
2621 pdu_offsets.start = data_offset;
2623 /* add preamble, postamble and ACN Packet ID */
2624 proto_tree_add_item(acn_tree, hf_acn_preamble_size, tvb, data_offset, 2, FALSE);
2626 proto_tree_add_item(acn_tree, hf_acn_postamble_size, tvb, data_offset, 2, FALSE);
2628 proto_tree_add_item(acn_tree, hf_acn_packet_identifier, tvb, data_offset, 12, FALSE);
2631 /* one past the last byte */
2632 end_offset = data_offset + tvb_reported_length_remaining(tvb, data_offset);
2633 while (data_offset < end_offset) {
2634 old_offset = data_offset;
2635 data_offset = dissect_acn_root_pdu(tvb, pinfo, acn_tree, data_offset, &pdu_offsets);
2636 if (data_offset == old_offset) break;
2639 return tvb_length(tvb);
2642 /******************************************************************************/
2643 /* Register protocol */
2644 void proto_register_acn(void)
2646 static hf_register_info hf[] = {
2647 /**************************************************************************/
2648 /* In alphabetical order */
2651 { &hf_acn_ip_address_type,
2652 { "Addr Type", "acn.ip_address_type",
2653 FT_UINT8, BASE_DEC, VALS(acn_ip_address_type_vals), 0x0,
2657 { &hf_acn_association,
2658 { "Association", "acn.association",
2659 FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
2662 /* Channel Number */
2663 { &hf_acn_channel_number,
2664 { "Channel Number", "acn.channel_number",
2665 FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
2671 FT_GUID, BASE_NONE, NULL, 0x0,
2674 /* Client Protocol ID */
2675 { &hf_acn_client_protocol_id,
2676 { "Client Protocol ID", "acn.client_protocol_id",
2677 FT_UINT32, BASE_DEC, VALS(acn_protocol_id_vals), 0x0,
2682 { "Data", "acn.dmp_data",
2683 FT_BYTES, BASE_HEX, NULL, 0x0,
2687 { "Addr", "acn.dmp_data8",
2688 FT_UINT8, BASE_DEC_HEX, NULL, 0x0,
2692 { "Addr", "acn.dmp_data16",
2693 FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
2697 { "Addr", "acn.dmp_data24",
2698 FT_UINT24, BASE_DEC_HEX, NULL, 0x0,
2702 { "Addr", "acn.dmp_data32",
2703 FT_UINT32, BASE_DEC_HEX, NULL, 0x0,
2707 { &hf_acn_dmp_address_data_pairs,
2708 { "Address-Data Pairs", "acn.dmp_address_data_pairs",
2709 FT_BYTES, BASE_DEC, NULL, 0x0,
2710 "More address-data pairs", HFILL }
2714 { &hf_acn_dmp_address1,
2715 { "Address", "acn.dmp_address",
2716 FT_UINT8, BASE_DEC_HEX, NULL, 0x0,
2719 { &hf_acn_dmp_address2,
2720 { "Address", "acn.dmp_address",
2721 FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
2724 { &hf_acn_dmp_address4,
2725 { "Address", "acn.dmp_address",
2726 FT_UINT32, BASE_DEC_HEX, NULL, 0x0,
2730 /* DMP Address type*/
2732 { "Address and Data Type", "acn.dmp_adt",
2733 FT_UINT8, BASE_DEC_HEX, NULL, 0x0,
2736 { &hf_acn_dmp_adt_a,
2737 { "Size", "acn.dmp_adt_a",
2738 FT_UINT8, BASE_DEC, VALS(acn_dmp_adt_a_vals), 0x03,
2741 { &hf_acn_dmp_adt_d,
2742 { "Data Type", "acn.dmp_adt_d",
2743 FT_UINT8, BASE_DEC, VALS(acn_dmp_adt_d_vals), 0x30,
2746 { &hf_acn_dmp_adt_r,
2747 { "Relative", "acn.dmp_adt_r",
2748 FT_UINT8, BASE_DEC, VALS(acn_dmp_adt_r_vals), 0x40,
2751 { &hf_acn_dmp_adt_v,
2752 { "Virtual", "acn.dmp_adt_v",
2753 FT_UINT8, BASE_DEC, VALS(acn_dmp_adt_v_vals), 0x80,
2756 { &hf_acn_dmp_adt_x,
2757 { "Reserved", "acn.dmp_adt_x",
2758 FT_UINT8, BASE_DEC, NULL, 0x0c,
2762 /* DMP Reason Code */
2763 { &hf_acn_dmp_reason_code,
2764 { "Reason Code", "acn.dmp_reason_code",
2765 FT_UINT8, BASE_DEC, VALS(acn_dmp_reason_code_vals), 0x0,
2770 { &hf_acn_dmp_vector,
2771 { "DMP Vector", "acn.dmp_vector",
2772 FT_UINT8, BASE_DEC, VALS(acn_dmp_vector_vals), 0x0,
2777 { "Expiry", "acn.expiry",
2778 FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
2781 /* First Member to ACK */
2782 { &hf_acn_first_memeber_to_ack,
2783 { "First Member to ACK", "acn.first_member_to_ack",
2784 FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
2787 /* First Missed Sequence */
2788 { &hf_acn_first_missed_sequence,
2789 { "First Missed Sequence", "acn.first_missed_sequence",
2790 FT_UINT32, BASE_DEC_HEX, NULL, 0x0,
2795 { "IPV4", "acn.ipv4",
2796 FT_IPv4, BASE_NONE, NULL, 0x0,
2801 { "IPV6", "acn.ipv6",
2802 FT_IPv6, BASE_NONE, NULL, 0x0,
2805 /* Last Member to ACK */
2806 { &hf_acn_last_memeber_to_ack,
2807 { "Last Member to ACK", "acn.last_member_to_ack",
2808 FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
2811 /* Last Missed Sequence */
2812 { &hf_acn_last_missed_sequence,
2813 { "Last Missed Sequence", "acn.last_missed_sequence",
2814 FT_UINT32, BASE_DEC_HEX, NULL, 0x0,
2818 { &hf_acn_mak_threshold,
2819 { "MAK Threshold", "acn.mak_threshold",
2820 FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
2824 { &hf_acn_member_id,
2825 { "Member ID", "acn.member_id",
2826 FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
2830 { &hf_acn_nak_holdoff,
2831 { "NAK holdoff (ms)", "acn.nak_holdoff",
2832 FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
2836 { &hf_acn_nak_max_wait,
2837 { "NAK Max Wait (ms)", "acn.nak_max_wait",
2838 FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
2842 { &hf_acn_nak_modulus,
2843 { "NAK Modulus", "acn.nak_modulus",
2844 FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
2847 /* NAK Outbound Flag */
2848 { &hf_acn_nak_outbound_flag,
2849 { "NAK Outbound Flag", "acn.nak_outbound_flag",
2850 FT_BOOLEAN, 8, NULL, 0x80,
2853 /* Oldest Available Wrapper */
2854 { &hf_acn_oldest_available_wrapper,
2855 { "Oldest Available Wrapper", "acn.oldest_available_wrapper",
2856 FT_UINT32, BASE_DEC_HEX, NULL, 0x0,
2859 /* Preamble Sizet */
2860 { &hf_acn_preamble_size,
2861 { "Size of preamble", "acn.preamble_size",
2862 FT_UINT16, BASE_DEC, NULL, 0x0,
2863 "Preamble size in bytes", HFILL }
2865 /* Packet Identifier */
2866 { &hf_acn_packet_identifier,
2867 { "Packet Identifier", "acn.packet_identifier",
2868 FT_STRING, BASE_NONE, NULL, 0x0,
2874 FT_NONE, BASE_NONE, NULL, 0x0,
2878 { &hf_acn_pdu_flags,
2879 { "Flags", "acn.pdu.flags",
2880 FT_UINT8, BASE_HEX, NULL, 0x0,
2881 "PDU Flags", HFILL }
2883 { &hf_acn_pdu_flag_d,
2884 { "Data", "acn.pdu.flag_d",
2885 FT_BOOLEAN, 8, NULL, ACN_PDU_FLAG_D,
2886 "Data flag", HFILL }
2888 { &hf_acn_pdu_flag_h,
2889 { "Header", "acn.pdu.flag_h",
2890 FT_BOOLEAN, 8, NULL, ACN_PDU_FLAG_H,
2891 "Header flag", HFILL }
2893 { &hf_acn_pdu_flag_l,
2894 { "Length", "acn.pdu.flag_l",
2895 FT_BOOLEAN, 8, NULL, ACN_PDU_FLAG_L,
2896 "Length flag", HFILL }
2898 { &hf_acn_pdu_flag_v,
2899 { "Vector", "acn.pdu.flag_v",
2900 FT_BOOLEAN, 8, NULL, ACN_PDU_FLAG_V,
2901 "Vector flag", HFILL }
2904 { &hf_acn_pdu_length,
2905 { "Length", "acn.pdu.flag_d",
2906 FT_UINT32, BASE_DEC, NULL, 0x0,
2907 "PDU Length", HFILL }
2911 { "Port", "acn.port",
2912 FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
2915 /* Postamble Size */
2916 { &hf_acn_postamble_size,
2917 { "Size of postamble", "acn.postamble_size",
2918 FT_UINT16, BASE_DEC, NULL, 0x0,
2919 "Postamble size in bytes", HFILL }
2922 { &hf_acn_protocol_id,
2923 { "Protocol ID", "acn.protocol_id",
2924 FT_UINT32, BASE_DEC, VALS(acn_protocol_id_vals), 0x0,
2928 { &hf_acn_reason_code,
2929 { "Reason Code", "acn.reason_code",
2930 FT_UINT8, BASE_DEC, VALS(acn_reason_code_vals), 0x0,
2933 /* Reciprocal Channel */
2934 { &hf_acn_reciprocal_channel,
2935 { "Reciprocal Channel Number", "acn.acn_reciprocal_channel",
2936 FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
2937 "Reciprocal Channel", HFILL }
2940 { &hf_acn_refuse_code,
2941 { "Refuse Code", "acn.acn_refuse_code",
2942 FT_UINT8, BASE_DEC, VALS(acn_refuse_code_vals), 0x0,
2945 /* Reliable Sequence Number */
2946 { &hf_acn_reliable_sequence_number,
2947 { "Reliable Sequence Number", "acn.reliable_sequence_number",
2948 FT_UINT32, BASE_DEC_HEX, NULL, 0x0,
2952 { &hf_acn_sdt_vector,
2953 { "STD Vector", "acn.sdt_vector",
2954 FT_UINT8, BASE_DEC, VALS(acn_sdt_vector_vals), 0x0,
2959 { &hf_acn_dmx_vector,
2960 { "Vector", "acn.dmx_vector",
2961 FT_UINT32, BASE_DEC, VALS(acn_dmx_vector_vals), 0x0,
2962 "DMX Vector", HFILL }
2964 /* DMX Source Name */
2965 { &hf_acn_dmx_source_name,
2966 { "Source", "acn.dmx.source_name",
2967 FT_STRING, BASE_NONE, NULL, 0x0,
2968 "DMX Source Name", HFILL }
2972 { &hf_acn_dmx_priority,
2973 { "Priority", "acn.dmx.priority",
2974 FT_UINT8, BASE_DEC, NULL, 0x0,
2975 "DMX Priority", HFILL }
2977 /* DMX Sequence number */
2978 { &hf_acn_dmx_sequence_number,
2979 { "Seq No", "acn.dmx.seq_number",
2980 FT_UINT8, BASE_DEC, NULL, 0x0,
2981 "DMX Sequence Number", HFILL }
2984 { &hf_acn_dmx_universe,
2985 { "Universe", "acn.dmx.universe",
2986 FT_UINT16, BASE_DEC, NULL, 0x0,
2987 "DMX Universe", HFILL }
2990 /* DMX Start Code */
2991 { &hf_acn_dmx_start_code,
2992 { "Start Code", "acn.dmx.start_code",
2993 FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
2994 "DMX Start Code", HFILL }
2997 /* DMX Address Increment */
2998 { &hf_acn_dmx_increment,
2999 { "Increment", "acn.dmx.increment",
3000 FT_UINT16, BASE_DEC, NULL, 0x0,
3001 "DMX Increment", HFILL }
3004 /* DMX Packet Count */
3005 { &hf_acn_dmx_count,
3006 { "Count", "acn.dmx.count",
3007 FT_UINT16, BASE_DEC, NULL, 0x0,
3008 "DMX Count", HFILL }
3012 { &hf_acn_session_count,
3013 { "Session Count", "acn.session_count",
3014 FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
3017 /* Total Sequence Number */
3018 { &hf_acn_total_sequence_number,
3019 { "Total Sequence Number", "acn.total_sequence_number",
3020 FT_UINT32, BASE_DEC_HEX, NULL, 0x0,
3025 /* Setup protocol subtree array */
3026 static gint *ett[] = {
3028 &ett_acn_channel_owner_info_block,
3029 &ett_acn_channel_member_info_block,
3030 &ett_acn_channel_parameter,
3032 &ett_acn_address_type,
3036 &ett_acn_sdt_client_pdu,
3037 &ett_acn_sdt_base_pdu,
3039 &ett_acn_dmx_address,
3040 &ett_acn_dmx_data_pdu,
3044 module_t *acn_module;
3045 if (proto_acn == -1) {
3046 proto_acn = proto_register_protocol (
3047 "Architecture for Control Networks", /* name */
3048 "ACN", /* short name */
3053 acn_module = prefs_register_protocol(proto_acn, proto_reg_handoff_acn);
3054 proto_register_field_array(proto_acn, hf, array_length(hf));
3055 proto_register_subtree_array(ett, array_length(ett));
3056 prefs_register_bool_preference(acn_module, "heuristic_acn",
3058 "Enable Architecture for Control Networks dissector (ANSI BSR E1.17)",
3061 prefs_register_bool_preference(acn_module, "dmx_enable",
3063 "Enable Streaming DMX extension dissector (ANSI BSR E1.31)",
3064 &global_acn_dmx_enable);
3066 prefs_register_enum_preference(acn_module, "dmx_display_view",
3067 "DMX, display format",
3069 &global_acn_dmx_display_view,
3073 prefs_register_bool_preference(acn_module, "dmx_display_zeros",
3074 "DMX, display zeros",
3075 "Display zeros instead of dots",
3076 &global_acn_dmx_display_zeros);
3078 prefs_register_bool_preference(acn_module, "dmx_display_leading_zeros",
3079 "DMX, display leading zeros",
3080 "Display leading zeros on levels",
3081 &global_acn_dmx_display_leading_zeros);
3083 prefs_register_enum_preference(acn_module, "dmx_display_line_format",
3084 "DMX, display line format",
3085 "Display line format",
3086 &global_acn_dmx_display_line_format,
3087 dmx_display_line_format,
3092 /******************************************************************************/
3093 /* Register handoff */
3095 proto_reg_handoff_acn(void)
3097 static guint initialized = FALSE;
3098 /* static dissector_handle_t acn_handle; */
3101 /* acn_handle = new_create_dissector_handle(dissect_acn, proto_acn); */
3102 /* dissector_add("udp.port", 0, acn_handle); */
3103 heur_dissector_add("udp", dissect_acn_heur, proto_acn);