2 * Routines for BACnet/IP (BVLL, BVLC) dissection
3 * Copyright 2001, Hartmut Mueller <hartmut@abmlinux.org>, FH Dortmund
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
9 * Copied from README.developer,v 1.23
11 * SPDX-License-Identifier: GPL-2.0-or-later
16 #include <epan/packet.h>
19 #include "packet-bacnet.h"
21 void proto_register_bvlc(void);
22 void proto_reg_handoff_bvlc(void);
24 #define BVLC_UDP_PORT 0xBAC0
26 /* Network Layer Wrapper Control Information */
27 #define BAC_WRAPPER_CONTROL_NET 0x80
28 #define BAC_WRAPPER_MSG_ENCRYPED 0x40
29 #define BAC_WRAPPER_RESERVED 0x20
30 #define BAC_WRAPPER_AUTHD_PRESENT 0x10
31 #define BAC_WRAPPER_DO_NOT_UNWRAP 0x08
32 #define BAC_WRAPPER_DO_NOT_DECRPT 0x04
33 #define BAC_WRAPPER_NO_TRUST_SRC 0x02
34 #define BAC_WRAPPER_SECURE_BY_RTR 0x01
36 static int proto_bvlc
;
37 static int proto_bscvlc
;
38 static int hf_bvlc_type
;
39 static int hf_bvlc_function
;
40 static int hf_bvlc_ipv6_function
;
41 static int hf_bvlc_length
;
42 static int hf_bvlc_result_ip4
;
43 static int hf_bvlc_result_ip6
;
44 static int hf_bvlc_bdt_ip
;
45 static int hf_bvlc_bdt_mask
;
46 static int hf_bvlc_bdt_port
;
47 static int hf_bvlc_reg_ttl
;
48 static int hf_bvlc_fdt_ip
;
49 static int hf_bvlc_fdt_ipv6
;
50 static int hf_bvlc_fdt_port
;
51 static int hf_bvlc_fdt_ttl
;
52 static int hf_bvlc_fdt_timeout
;
53 static int hf_bvlc_fwd_ip
;
54 static int hf_bvlc_fwd_port
;
55 static int hf_bvlc_virt_source
;
56 static int hf_bvlc_virt_dest
;
57 static int hf_bvlc_orig_source_addr
;
58 static int hf_bvlc_orig_source_port
;
59 static int hf_bscvlc_control
;
60 static int hf_bscvlc_control_data_option
;
61 static int hf_bscvlc_control_destination_option
;
62 static int hf_bscvlc_control_destination_address
;
63 static int hf_bscvlc_control_origin_address
;
64 static int hf_bscvlc_control_reserved
;
65 static int hf_bscvlc_header
;
66 static int hf_bscvlc_header_marker
;
67 static int hf_bscvlc_header_length
;
68 static int hf_bscvlc_header_data
;
69 static int hf_bscvlc_header_opt_type
;
70 static int hf_bscvlc_header_opt_data
;
71 static int hf_bscvlc_header_opt_must_understand
;
72 static int hf_bscvlc_header_opt_more
;
73 static int hf_bscvlc_vendor_id
;
74 static int hf_bscvlc_proprietary_opt_type
;
75 static int hf_bscvlc_proprietary_data
;
76 static int hf_bscvlc_hub_conn_state
;
77 static int hf_bscvlc_accept_conns
;
78 static int hf_bscvlc_max_bvlc_length
;
79 static int hf_bscvlc_max_npdu_length
;
80 static int hf_bscvlc_function
;
81 static int hf_bscvlc_result
;
82 static int hf_bscvlc_error_class
;
83 static int hf_bscvlc_error_code
;
84 static int hf_bscvlc_result_data
;
85 static int hf_bscvlc_uris
;
86 static int hf_bscvlc_msg_id
;
87 static int hf_bscvlc_orig_vmac
;
88 static int hf_bscvlc_dest_vmac
;
89 static int hf_bscvlc_connect_vmac
;
90 static int hf_bscvlc_connect_uuid
;
92 static dissector_table_t bvlc_dissector_table
;
93 static dissector_table_t bscvlc_dissector_table
;
94 static dissector_table_t bvlc_ipv6_dissector_table
;
95 static dissector_handle_t bvlc_handle
;
96 static dissector_handle_t bscvlc_handle
;
98 static const value_string bvlc_function_names
[] = {
99 { 0x00, "BVLC-Result" },
100 { 0x01, "Write-Broadcast-Distribution-Table" },
101 { 0x02, "Read-Broadcast-Distribution-Table" },
102 { 0x03, "Read-Broadcast-Distribution-Table-Ack" },
103 { 0x04, "Forwarded-NPDU" },
104 { 0x05, "Register-Foreign-Device" },
105 { 0x06, "Read-Foreign-Device-Table" },
106 { 0x07, "Read-Foreign-Device-Table-Ack" },
107 { 0x08, "Delete-Foreign-Device-Table-Entry" },
108 { 0x09, "Distribute-Broadcast-To-Network" },
109 { 0x0a, "Original-Unicast-NPDU" },
110 { 0x0b, "Original-Broadcast-NPDU" },
111 { 0x0c, "Secured-BVLL" },
115 static const value_string bscvlc_function_names
[] = {
116 { 0x00, "BVLC-Result" },
117 { 0x01, "Encapsulated-NPDU" },
118 { 0x02, "Address-Resolution" },
119 { 0x03, "Address-Resolution-ACK" },
120 { 0x04, "Advertisement" },
121 { 0x05, "Advertisement-Solicitation" },
122 { 0x06, "Connect-Request" },
123 { 0x07, "Connect-Accept" },
124 { 0x08, "Disconnect-Request" },
125 { 0x09, "Disconnect-ACK" },
126 { 0x0A, "Heartbeat-Request" },
127 { 0x0B, "Heartbeat-ACK" },
128 { 0x0C, "Proprietary-Message" },
132 static const value_string bvlc_result_names
[] = {
133 { 0x00, "Successful completion" },
134 { 0x10, "Write-Broadcast-Distribution-Table NAK" },
135 { 0x20, "Read-Broadcast-Distribution-Table NAK" },
136 { 0x30, "Register-Foreign-Device NAK" },
137 { 0x40, "Read-Foreign-Device-Table NAK" },
138 { 0x50, "Delete-Foreign-Device-Table-Entry NAK" },
139 { 0x60, "Distribute-Broadcast-To-Network NAK" },
143 static const value_string bscvlc_result_names
[] = {
144 { 0x00, "Successful completion (ACK)" },
145 { 0x01, "Completion failed (NAK)" },
149 static const value_string bvlc_ipv6_function_names
[] = {
150 { 0x00, "BVLC-Result", },
151 { 0x01, "Original-Unicast-NPDU", },
152 { 0x02, "Original-Broadcast-NPDU", },
153 { 0x03, "Address-Resolution", },
154 { 0x04, "Forwarded-Address-Resolution", },
155 { 0x05, "Address-Resolution-ACK", },
156 { 0x06, "Virtual-Address-Resolution", },
157 { 0x07, "Virtual-Address-Resolution-ACK", },
158 { 0x08, "Forwarded-NPDU", },
159 { 0x09, "Register-Foreign-Device", },
160 { 0x0A, "Delete-Foreign-Device-Table-Entry", },
161 { 0x0B, "Secure-BVLL", },
162 { 0x0C, "Distribute-Broadcast-To-Network", },
166 static const value_string bvlc_ipv6_result_names
[] = {
167 { 0x00, "Successful completion" },
168 { 0x30, "Address-Resolution NAK" },
169 { 0x60, "Virtual-Address-Resolution NAK" },
170 { 0x90, "Register-Foreign-Device NAK" },
171 { 0xA0, "Delete-Foreign-Device-Table-Entry NAK" },
172 { 0xC0, "Distribute-Broadcast-To-Network NAK" },
176 static const value_string bscvlc_header_type_names
[] = {
177 { 0x01, "Secure Path" },
178 { 0x1F, "Proprietary Header Option" },
182 static const value_string bscvlc_hub_conn_state_names
[] = {
183 { 0x00, "No hub connection" },
184 { 0x01, "Connected to primary hub" },
185 { 0x02, "Connected to failover hub" },
189 static const value_string bscvlc_hub_accept_conns_names
[] = {
190 { 0x00, "The node does not support accepting direct connections" },
191 { 0x01, "The node supports accepting direct connections" },
196 static int ett_bscvlc
;
197 static int ett_bscvlc_ctrl
;
198 static int ett_bscvlc_hdr
;
202 #define BACNET_IP_ANNEX_J 0x81
203 #define BACNET_IPV6_ANNEX_U 0x82
205 static const value_string bvlc_types
[] = {
206 { BACNET_IP_ANNEX_J
, "BACnet/IP (Annex J)" },
207 { BACNET_IPV6_ANNEX_U
, "BACnet/IPV6 (Annex U)" },
211 #define BSCVLC_CONTROL_DATA_OPTION 0x01
212 #define BSCVLC_CONTROL_DEST_OPTION 0x02
213 #define BSCVLC_CONTROL_DEST_ADDRESS 0x04
214 #define BSCVLC_CONTROL_ORIG_ADDRESS 0x08
215 #define BSCVLC_CONTROL_RESERVED 0xF0
217 static const true_false_string control_data_option_set_high
= {
218 "Data Options field is present.",
219 "Data Options field is absent."
222 static const true_false_string control_destination_option_set_high
= {
223 "Destination Options field is present.",
224 "Destination Options field is absent."
227 static const true_false_string control_destination_address_set_high
= {
228 "Destination Virtual Address is present.",
229 "Destination Virtual Address is absent."
232 static const true_false_string control_orig_address_set_high
= {
233 "Originating Virtual Address is present.",
234 "Originating Virtual Address is absent."
237 static const true_false_string control_reserved_set_high
= {
238 "Shall be zero, but is not.",
239 "Shall be zero and is zero."
242 #define BSCVLC_HEADER_OPTION_TYPE 0x1F
243 #define BSCVLC_HEADER_OPTION_DATA 0x20
244 #define BSCVLC_HEADER_OPTION_MUST_UNDERSTAND 0x40
245 #define BSCVLC_HEADER_OPTION_MORE_OPTIONS 0x80
247 #define BSCVLC_HEADER_TYPE_SECURE_PATH 0x01
248 #define BSCVLC_HEADER_TYPE_PROPRIETARY 0x1F
251 static const true_false_string header_opt_data_set_high
= {
252 "The 'Header Length' and 'Header Data' fields are present.",
253 "The 'Header Length' and 'Header Data' fields are absent."
256 static const true_false_string header_opt_must_understand_set_high
= {
257 "This header option must be understood for consuming the message.",
258 "This header option can be ignored if not understood."
261 static const true_false_string header_opt_more_set_high
= {
262 "Another header option follows in the current header option list.",
263 "This is the last header option in the current header option list."
266 static const value_string
267 BACnetErrorClass
[] = {
275 { 7, "communication" },
277 /* Enumerated values 0-63 are reserved for definition by ASHRAE.
278 Enumerated values64-65535 may be used by others subject to
279 the procedures and constraints described in Clause 23. */
282 static const value_string
283 BACnetErrorCode
[] = {
285 { 1, "authentication-failed"},
286 { 2, "configuration-in-progress"},
288 { 4, "dynamic-creation-not-supported"},
289 { 5, "file-access-denied"},
290 { 6, "incompatible-security-levels"},
291 { 7, "inconsistent-parameters"},
292 { 8, "inconsistent-selection-criterion"},
293 { 9, "invalid-data-type"},
294 { 10, "invalid-file-access-method"},
295 { 11, "invalid-file-start-position"},
296 { 12, "invalid-operator-name"},
297 { 13, "invalid-parameter-data-type"},
298 { 14, "invalid-time-stamp"},
299 { 15, "key-generation-error"},
300 { 16, "missing-required-parameter"},
301 { 17, "no-objects-of-specified-type"},
302 { 18, "no-space-for-object"},
303 { 19, "no-space-to-add-list-element"},
304 { 20, "no-space-to-write-property"},
305 { 21, "no-vt-sessions-available"},
306 { 22, "property-is-not-a-list"},
307 { 23, "object-deletion-not-permitted"},
308 { 24, "object-identifier-already-exists"},
309 { 25, "operational-problem"},
310 { 26, "password-failure"},
311 { 27, "read-access-denied"},
312 { 28, "security-not-supported"},
313 { 29, "service-request-denied"},
315 { 31, "unknown-object"},
316 { 32, "unknown-property"},
317 { 33, "removed enumeration"},
318 { 34, "unknown-vt-class"},
319 { 35, "unknown-vt-session"},
320 { 36, "unsupported-object-type"},
321 { 37, "value-out-of-range"},
322 { 38, "vt-session-already-closed"},
323 { 39, "vt-session-termination-failure"},
324 { 40, "write-access-denied"},
325 { 41, "character-set-not-supported"},
326 { 42, "invalid-array-index"},
327 { 43, "cov-subscription-failed"},
328 { 44, "not-cov-property"},
329 { 45, "optional-functionality-not-supported"},
330 { 46, "invalid-configuration-data"},
331 { 47, "datatype-not-supported"},
332 { 48, "duplicate-name"},
333 { 49, "duplicate-object-id"},
334 { 50, "property-is-not-an-array"},
335 { 51, "abort - buffer - overflow" },
336 { 52, "abort - invalid - apdu - in - this - state" },
337 { 53, "abort - preempted - by - higher - priority - task" },
338 { 54, "abort - segmentation - not - supported" },
339 { 55, "abort - proprietary" },
340 { 56, "abort - other" },
341 { 57, "reject - invalid - tag" },
342 { 58, "reject - network - down" },
343 { 59, "reject - buffer - overflow" },
344 { 60, "reject - inconsistent - parameters" },
345 { 61, "reject - invalid - parameter - data - type" },
346 { 62, "reject - invalid - tag" },
347 { 63, "reject - missing - required - parameter" },
348 { 64, "reject - parameter - out - of - range" },
349 { 65, "reject - too - many - arguments" },
350 { 66, "reject - undefined - enumeration" },
351 { 67, "reject - unrecognized - service" },
352 { 68, "reject - proprietary" },
353 { 69, "reject - other" },
354 { 70, "unknown - device" },
355 { 71, "unknown - route" },
356 { 72, "value - not - initialized" },
357 { 73, "invalid-event-state"},
358 { 74, "no-alarm-configured"},
359 { 75, "log-buffer-full"},
360 { 76, "logged-value-purged"},
361 { 77, "no-property-specified"},
362 { 78, "not-configured-for-triggered-logging"},
363 { 79, "unknown-subscription"},
364 { 80, "parameter-out-of-range"},
365 { 81, "list-element-not-found"},
367 { 83, "communication-disabled"},
369 { 85, "access-denied"},
370 { 86, "bad-destination-address"},
371 { 87, "bad-destination-device-id"},
372 { 88, "bad-signature"},
373 { 89, "bad-source-address"},
374 { 90, "bad-timestamp"},
375 { 91, "cannot-use-key"},
376 { 92, "cannot-verify-message-id"},
377 { 93, "correct-key-revision"},
378 { 94, "destination-device-id-required"},
379 { 95, "duplicate-message"},
380 { 96, "encryption-not-configured"},
381 { 97, "encryption-required"},
382 { 98, "incorrect-key"},
383 { 99, "invalid-key-data"},
384 { 100, "key-update-in-progress"},
385 { 101, "malformed-message"},
386 { 102, "not-key-server"},
387 { 103, "security-not-configured"},
388 { 104, "source-security-required"},
389 { 105, "too-many-keys"},
390 { 106, "unknown-authentication-type"},
391 { 107, "unknown-key"},
392 { 108, "unknown-key-revision"},
393 { 109, "unknown-source-message"},
394 { 110, "not-router-to-dnet"},
395 { 111, "router-busy"},
396 { 112, "unknown-network-message"},
397 { 113, "message-too-long"},
398 { 114, "security-error"},
399 { 115, "addressing-error"},
400 { 116, "write-bdt-failed"},
401 { 117, "read-bdt-failed"},
402 { 118, "register-foreign-device-failed"},
403 { 119, "read-fdt-failed"},
404 { 120, "delete-fdt-entry-failed"},
405 { 121, "distribute-broadcast-failed"},
406 { 122, "unknown-file-size"},
407 { 123, "abort-apdu-too-long"},
408 { 124, "abort-application-exceeded-reply-time"},
409 { 125, "abort-out-of-resources"},
410 { 126, "abort-tsm-timeout"},
411 { 127, "abort-window-size-out-of-range"},
413 { 129, "inconsistent-configuration"},
414 { 130, "inconsistent-object-type"},
415 { 131, "internal-error"},
416 { 132, "not-configured"},
417 { 133, "out-of-memory"},
418 { 134, "value-too-long"},
419 { 135, "abort-insufficient-security"},
420 { 136, "abort-security-error"},
421 { 137, "duplicate-entry"},
422 { 138, "invalid-value-in-this-state"},
423 { 139, "invalid-operation-in-this-state"},
424 { 140, "list-item-not-numbered"},
425 { 141, "list-item-not-timestamped"},
426 { 142, "invalid-data-encoding"},
427 { 143, "bvlc-function-unknown"},
428 { 144, "bvlc-proprietary-function-unknown"},
429 { 145, "header-encoding-error"},
430 { 146, "header-not-understood"},
431 { 147, "message-incomplete"},
432 { 148, "not-a-bacnet-sc-hub"},
433 { 149, "payload-expected"},
434 { 150, "unexpected-data"},
435 { 151, "node-duplicate-vmac"},
436 { 152, "http-unexpected-response-code"},
437 { 153, "http-no-upgrade"},
438 { 154, "http-resource-not-local"},
439 { 155, "http-proxy-authentication-failed"},
440 { 156, "http-response-timeout"},
441 { 157, "http-response-syntax-error"},
442 { 158, "http-response-value-error"},
443 { 159, "http-response-missing-header"},
444 { 160, "http-websocket-header-error"},
445 { 161, "http-upgrade-required"},
446 { 162, "http-upgrade-error"},
447 { 163, "http-temporary-unavailable"},
448 { 164, "http-not-a-server"},
449 { 165, "http-error"},
450 { 166, "websocket-scheme-not-supported"},
451 { 167, "websocket-unknown-control-message"},
452 { 168, "websocket-close-error"},
453 { 169, "websocket-closed-by-peer"},
454 { 170, "websocket-endpoint-leaves"},
455 { 171, "websocket-protocol-error"},
456 { 172, "websocket-data-not-accepted"},
457 { 173, "websocket-closed-abnormally"},
458 { 174, "websocket-data-inconsistent"},
459 { 175, "websocket-data-against-policy"},
460 { 176, "websocket-frame-too-long"},
461 { 177, "websocket-extension-missing"},
462 { 178, "websocket-request-unavailable"},
463 { 179, "websocket-error"},
464 { 180, "tls-client-certificate-error"},
465 { 181, "tls-server-certificate-error"},
466 { 182, "tls-client-authentication-failed"},
467 { 183, "tls-server-authentication-failed"},
468 { 184, "tls-client-certificate-expired"},
469 { 185, "tls-server-certificate-expired"},
470 { 186, "tls-client-certificate-revoked"},
471 { 187, "tls-server-certificate-revoked"},
473 { 189, "dns-unavailable"},
474 { 190, "dns-name-resolution-failed"},
475 { 191, "dns-resolver-failure"},
477 { 193, "tcp-connect-timeout"},
478 { 194, "tcp-connection-refused"},
479 { 195, "tcp-closed-by-local"},
480 { 196, "tcp-closed-other"},
482 { 198, "ip-address-not-reachable"},
485 /* Enumerated values 0-255 are reserved for definition by ASHRAE.
486 Enumerated values 256-65535 may be used by others subject to the
487 procedures and constraints described in Clause 23. */
490 static int * const bscvlc_control_flags
[] = {
491 &hf_bscvlc_control_data_option
,
492 &hf_bscvlc_control_destination_option
,
493 &hf_bscvlc_control_destination_address
,
494 &hf_bscvlc_control_origin_address
,
495 &hf_bscvlc_control_reserved
,
499 static int * const bscvlc_header_flags
[] = {
500 &hf_bscvlc_header_opt_type
,
501 &hf_bscvlc_header_opt_data
,
502 &hf_bscvlc_header_opt_must_understand
,
503 &hf_bscvlc_header_opt_more
,
508 // NOLINTNEXTLINE(misc-no-recursion)
509 dissect_ipv4_bvlc(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
515 proto_tree
*bvlc_tree
;
516 proto_tree
*bdt_tree
; /* Broadcast Distribution Table */
517 proto_tree
*fdt_tree
; /* Foreign Device Table */
521 uint8_t bvlc_function
;
522 uint16_t bvlc_length
;
523 uint16_t packet_length
;
524 unsigned npdu_length
;
525 unsigned length_remaining
;
530 bvlc_type
= tvb_get_uint8(tvb
, offset
);
531 bvlc_function
= tvb_get_uint8(tvb
, offset
+ 1);
532 packet_length
= tvb_get_ntohs(tvb
, offset
+ 2);
533 length_remaining
= tvb_reported_length_remaining(tvb
, offset
);
535 if (bvlc_function
> 0x08) {
536 /* We have a constant header length of BVLC of 4 in every
537 * BVLC-packet forewarding an NPDU. Beware: Changes in the
538 * BACnet-IP-standard may break this.
541 } else if (bvlc_function
== 0x04) {
542 /* 4 Bytes + 6 Bytes for B/IP Address of Originating Device */
545 /* BVLC-packets with function below 0x09 contain
546 * routing-level data (e.g. Broadcast Distribution)
547 * but no NPDU for BACnet, so bvlc_length goes up to the end
548 * of the captured frame.
550 bvlc_length
= packet_length
;
553 if (bvlc_length
< 4 || bvlc_length
> packet_length
) {
554 return 0; /* reject */
557 /* Put the BVLC Type in the info column */
558 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " BVLC Function %s ",
559 val_to_str_const(bvlc_function
, bvlc_function_names
, "unknown"));
561 ti
= proto_tree_add_item(tree
, proto_bvlc
, tvb
, 0, bvlc_length
, ENC_NA
);
562 bvlc_tree
= proto_item_add_subtree(ti
, ett_bvlc
);
563 proto_tree_add_uint(bvlc_tree
, hf_bvlc_type
, tvb
, offset
, 1,
566 proto_tree_add_uint(bvlc_tree
, hf_bvlc_function
, tvb
,
567 offset
, 1, bvlc_function
);
569 if (length_remaining
!= packet_length
)
570 proto_tree_add_uint_format_value(bvlc_tree
, hf_bvlc_length
, tvb
, offset
,
572 "%d of %d bytes (invalid length - expected %d bytes)",
573 bvlc_length
, packet_length
, length_remaining
);
575 proto_tree_add_uint_format_value(bvlc_tree
, hf_bvlc_length
, tvb
, offset
,
576 2, bvlc_length
, "%d of %d bytes BACnet packet length",
577 bvlc_length
, packet_length
);
579 switch (bvlc_function
) {
580 case 0x00: /* BVLC-Result */
581 /* I don't know why the result code is encoded in 4 nibbles,
582 * but only using one: 0x00r0. Shifting left 4 bits.
584 /* We should bitmask the result correctly when we have a
585 * packet to dissect, see README.developer, 1.6.2, FID */
586 proto_tree_add_item(bvlc_tree
, hf_bvlc_result_ip4
, tvb
,
587 offset
, 2, ENC_BIG_ENDIAN
);
590 case 0x01: /* Write-Broadcast-Distribution-Table */
591 case 0x03: /* Read-Broadcast-Distribution-Table-Ack */
592 /* List of BDT Entries: N*10-octet */
593 ti_bdt
= proto_tree_add_item(bvlc_tree
, proto_bvlc
, tvb
,
594 offset
, bvlc_length
-4, ENC_NA
);
595 bdt_tree
= proto_item_add_subtree(ti_bdt
, ett_bdt
);
596 /* List of BDT Entries: N*10-octet */
597 while ((bvlc_length
- offset
) > 9) {
598 proto_tree_add_item(bdt_tree
, hf_bvlc_bdt_ip
,
599 tvb
, offset
, 4, ENC_BIG_ENDIAN
);
601 proto_tree_add_item(bdt_tree
, hf_bvlc_bdt_port
,
602 tvb
, offset
, 2, ENC_BIG_ENDIAN
);
604 proto_tree_add_item(bdt_tree
,
605 hf_bvlc_bdt_mask
, tvb
, offset
, 4,
609 /* We check this if we get a BDT-packet somewhere */
611 case 0x02: /* Read-Broadcast-Distribution-Table */
612 /* nothing to do here */
614 case 0x05: /* Register-Foreign-Device */
615 /* Time-to-Live 2-octets T, Time-to-Live T, in seconds */
616 proto_tree_add_item(bvlc_tree
, hf_bvlc_reg_ttl
,
617 tvb
, offset
, 2, ENC_BIG_ENDIAN
);
620 case 0x06: /* Read-Foreign-Device-Table */
621 /* nothing to do here */
623 case 0x07: /* Read-Foreign-Device-Table-Ack */
624 /* List of FDT Entries: N*10-octet */
625 /* N indicates the number of entries in the FDT whose
626 * contents are being returned. Each returned entry
627 * consists of the 6-octet B/IP address of the registrant;
628 * the 2-octet Time-to-Live value supplied at the time of
629 * registration; and a 2-octet value representing the
630 * number of seconds remaining before the BBMD will purge
631 * the registrant's FDT entry if no re-registration occurs.
633 ti_fdt
= proto_tree_add_item(bvlc_tree
, proto_bvlc
, tvb
,
634 offset
, bvlc_length
-4, ENC_NA
);
635 fdt_tree
= proto_item_add_subtree(ti_fdt
, ett_fdt
);
636 /* List of FDT Entries: N*10-octet */
637 while ((bvlc_length
- offset
) > 9) {
638 proto_tree_add_item(fdt_tree
, hf_bvlc_fdt_ip
,
639 tvb
, offset
, 4, ENC_BIG_ENDIAN
);
641 proto_tree_add_item(fdt_tree
, hf_bvlc_fdt_port
,
642 tvb
, offset
, 2, ENC_BIG_ENDIAN
);
644 proto_tree_add_item(fdt_tree
,
645 hf_bvlc_fdt_ttl
, tvb
, offset
, 2,
648 proto_tree_add_item(fdt_tree
,
649 hf_bvlc_fdt_timeout
, tvb
, offset
, 2,
653 /* We check this if we get a FDT-packet somewhere */
655 case 0x08: /* Delete-Foreign-Device-Table-Entry */
656 /* FDT Entry: 6-octets */
657 proto_tree_add_item(bvlc_tree
, hf_bvlc_fdt_ip
,
658 tvb
, offset
, 4, ENC_BIG_ENDIAN
);
660 proto_tree_add_item(bvlc_tree
, hf_bvlc_fdt_port
,
661 tvb
, offset
, 2, ENC_BIG_ENDIAN
);
664 case 0x0C: /* Secure-BVLL */
665 offset
= bacnet_dissect_sec_wrapper(tvb
, pinfo
, tree
, offset
, NULL
);
667 call_data_dissector(tvb
, pinfo
, tree
);
668 return tvb_captured_length(tvb
);
670 increment_dissection_depth(pinfo
);
671 dissect_ipv4_bvlc(tvb
, pinfo
, tree
, data
);
672 decrement_dissection_depth(pinfo
);
674 /* We check this if we get a FDT-packet somewhere */
675 case 0x04: /* Forwarded-NPDU
676 * Why is this 0x04? It would have been a better
677 * idea to append all forewarded NPDUs at the
678 * end of the function table in the B/IP-standard!
680 /* proto_tree_add_bytes_format(); */
681 proto_tree_add_item(bvlc_tree
, hf_bvlc_fwd_ip
,
682 tvb
, offset
, 4, ENC_BIG_ENDIAN
);
684 proto_tree_add_item(bvlc_tree
, hf_bvlc_fwd_port
,
685 tvb
, offset
, 2, ENC_BIG_ENDIAN
);
689 /* Distribute-Broadcast-To-Network
690 * Original-Unicast-NPDU
691 * Original-Broadcast-NPDU
692 * Going to the next dissector...
697 /* Ok, no routing information BVLC packet. Dissect as
700 npdu_length
= packet_length
- bvlc_length
;
701 next_tvb
= tvb_new_subset_length(tvb
, bvlc_length
, npdu_length
);
702 /* Code from Guy Harris */
703 if (!dissector_try_uint(bvlc_dissector_table
,
704 bvlc_function
, next_tvb
, pinfo
, tree
)) {
705 /* Unknown function - dissect the payload as data */
706 call_data_dissector(next_tvb
, pinfo
, tree
);
708 return tvb_reported_length(tvb
);
712 // NOLINTNEXTLINE(misc-no-recursion)
713 dissect_ipv6_bvlc(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
716 proto_tree
*bvlc_tree
;
720 uint8_t bvlc_function
;
721 uint16_t bvlc_length
= 0;
722 uint16_t packet_length
;
723 unsigned npdu_length
;
724 unsigned length_remaining
;
729 bvlc_type
= tvb_get_uint8(tvb
, offset
);
730 bvlc_function
= tvb_get_uint8(tvb
, offset
+ 1);
731 packet_length
= tvb_get_ntohs(tvb
, offset
+ 2);
732 length_remaining
= tvb_reported_length_remaining(tvb
, offset
);
734 switch (bvlc_function
) {
766 if (bvlc_length
> packet_length
) {
767 return 0; /* reject */
770 /* Put the BVLC Type in the info column */
771 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " BVLC Function %s ",
772 val_to_str_const(bvlc_function
, bvlc_ipv6_function_names
, "unknown"));
774 ti
= proto_tree_add_item(tree
, proto_bvlc
, tvb
, 0,
775 bvlc_length
, ENC_NA
);
776 bvlc_tree
= proto_item_add_subtree(ti
, ett_bvlc
);
777 /* add the BVLC type */
778 proto_tree_add_uint(bvlc_tree
, hf_bvlc_type
, tvb
, offset
, 1,
781 /* add the BVLC function */
782 proto_tree_add_uint(bvlc_tree
, hf_bvlc_ipv6_function
, tvb
,
783 offset
, 1, bvlc_function
);
785 /* add the length information */
786 if (length_remaining
!= packet_length
)
787 proto_tree_add_uint_format_value(bvlc_tree
, hf_bvlc_length
, tvb
, offset
,
789 "%d of %d bytes (invalid length - expected %d bytes)",
790 bvlc_length
, packet_length
, length_remaining
);
792 proto_tree_add_uint_format_value(bvlc_tree
, hf_bvlc_length
, tvb
, offset
,
794 "%d of %d bytes BACnet packet length",
795 bvlc_length
, packet_length
);
798 /* add the optional present virtual source address */
799 if (bvlc_function
!= 0x0B) {
800 proto_tree_add_item(bvlc_tree
, hf_bvlc_virt_source
, tvb
, offset
,
805 /* handle additional function parameters */
806 switch (bvlc_function
) {
807 case 0x00: /* BVLC-Result */
808 proto_tree_add_item(bvlc_tree
, hf_bvlc_result_ip6
, tvb
,
809 offset
, 2, ENC_BIG_ENDIAN
);
812 case 0x01: /* Original-Unicast-NPDU */
813 case 0x03: /* Address-Resolution */
814 case 0x05: /* Address-Resolution-ACK */
815 case 0x07: /* Virtual-Address-Resolution-ACK */
816 proto_tree_add_item(bvlc_tree
, hf_bvlc_virt_dest
, tvb
, offset
,
820 case 0x04: /* Forwarded-Address-Resolution */
821 proto_tree_add_item(bvlc_tree
, hf_bvlc_virt_dest
, tvb
, offset
,
824 proto_tree_add_item(bvlc_tree
, hf_bvlc_orig_source_addr
,
825 tvb
, offset
, 16, ENC_NA
);
827 proto_tree_add_item(bvlc_tree
, hf_bvlc_orig_source_port
,
828 tvb
, offset
, 2, ENC_BIG_ENDIAN
);
831 case 0x08: /* Forwarded-NPDU */
832 proto_tree_add_item(bvlc_tree
, hf_bvlc_orig_source_addr
,
833 tvb
, offset
, 16, ENC_NA
);
835 proto_tree_add_item(bvlc_tree
, hf_bvlc_orig_source_port
,
836 tvb
, offset
, 2, ENC_BIG_ENDIAN
);
839 case 0x06: /* Virtual-Address-Resolution */
841 case 0x09: /* Register-Foreign-Device */
842 proto_tree_add_item(bvlc_tree
, hf_bvlc_reg_ttl
,
843 tvb
, offset
, 2, ENC_BIG_ENDIAN
);
846 case 0x0A: /* Delete-Foreign-Device-Table-Entry */
847 proto_tree_add_item(bvlc_tree
, hf_bvlc_fdt_ipv6
,
848 tvb
, offset
, 16, ENC_NA
);
850 proto_tree_add_item(bvlc_tree
, hf_bvlc_fdt_port
,
851 tvb
, offset
, 2, ENC_BIG_ENDIAN
);
854 case 0x0B: /* Secure-BVLL */
855 offset
= bacnet_dissect_sec_wrapper(tvb
, pinfo
, tree
, offset
, NULL
);
857 call_data_dissector(tvb
, pinfo
, tree
);
858 return tvb_captured_length(tvb
);
860 increment_dissection_depth(pinfo
);
861 dissect_ipv6_bvlc(tvb
, pinfo
, tree
, data
);
862 decrement_dissection_depth(pinfo
);
864 case 0x02: /* Original-Broadcast-NPDU */
865 case 0x0c: /* Distribute-Broadcast-To-Network */
868 * Going to the next dissector...
873 /* Ok, no routing information BVLC packet. Dissect as
876 npdu_length
= packet_length
- offset
;
877 next_tvb
= tvb_new_subset_length(tvb
, offset
, npdu_length
);
878 /* Code from Guy Harris */
879 if ( ! dissector_try_uint(bvlc_ipv6_dissector_table
,
880 bvlc_function
, next_tvb
, pinfo
, tree
)) {
881 /* Unknown function - dissect the payload as data */
882 call_data_dissector(next_tvb
, pinfo
, tree
);
885 return tvb_reported_length(tvb
);
889 dissect_bvlc(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
894 bvlc_type
= tvb_get_uint8(tvb
, 0);
897 * Simple sanity check - make sure the type is one we know about.
899 if (try_val_to_str(bvlc_type
, bvlc_types
) == NULL
)
902 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "BVLC");
903 col_set_str(pinfo
->cinfo
, COL_INFO
, "BACnet Virtual Link Control");
907 case BACNET_IP_ANNEX_J
:
908 ret
= dissect_ipv4_bvlc(tvb
, pinfo
, tree
, data
);
910 case BACNET_IPV6_ANNEX_U
:
911 ret
= dissect_ipv6_bvlc(tvb
, pinfo
, tree
, data
);
919 dissect_bscvlc(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
922 proto_tree
*bvlc_tree
;
929 uint8_t bvlc_function
;
930 uint8_t bvlc_control
;
933 int8_t mac_buffer
[16];
934 unsigned bvlc_message_id
;
940 /* Calculate length of BSCVLC block to get remaining payload length */
943 packet_length
= tvb_reported_length_remaining(tvb
, offset
);
944 if(packet_length
< 4)
945 return 0; /* reject */
947 /* Fix part of the header first */
948 bvlc_function
= tvb_get_uint8(tvb
, offset
++);
949 bvlc_control
= tvb_get_uint8(tvb
, offset
++);
950 bvlc_message_id
= tvb_get_uint16(tvb
, offset
, ENC_BIG_ENDIAN
);
953 /* Variable part of the header next */
954 bvlc_length
= offset
;
956 if ((bvlc_control
& BSCVLC_CONTROL_ORIG_ADDRESS
) != 0)
959 if ((bvlc_control
& BSCVLC_CONTROL_DEST_ADDRESS
) != 0)
962 if ((bvlc_control
& BSCVLC_CONTROL_DEST_OPTION
) != 0)
966 while(tvb_reported_length_remaining(tvb
, bvlc_length
) > 0 &&
967 (hdr_byte
= tvb_get_uint8(tvb
, bvlc_length
)) != 0 && bMoreFlag
)
969 /* get flags and type... */
970 bMoreFlag
= (hdr_byte
& BSCVLC_HEADER_OPTION_MORE_OPTIONS
);
971 bDataFlag
= (hdr_byte
& BSCVLC_HEADER_OPTION_DATA
);
976 npdu_length
= (int)(tvb_get_uint8(tvb
, bvlc_length
++) << 8);
977 npdu_length
+= (int)tvb_get_uint8(tvb
, bvlc_length
++);
978 bvlc_length
+= npdu_length
;
983 if ((bvlc_control
& BSCVLC_CONTROL_DATA_OPTION
) != 0)
987 while(tvb_reported_length_remaining(tvb
, bvlc_length
) > 0 &&
988 (hdr_byte
= tvb_get_uint8(tvb
, bvlc_length
)) != 0 && bMoreFlag
)
990 /* get flags and type... */
991 bMoreFlag
= (hdr_byte
& BSCVLC_HEADER_OPTION_MORE_OPTIONS
);
992 bDataFlag
= (hdr_byte
& BSCVLC_HEADER_OPTION_DATA
);
997 npdu_length
= (int)(tvb_get_uint8(tvb
, bvlc_length
++) << 8);
998 npdu_length
+= (int)tvb_get_uint8(tvb
, bvlc_length
++);
999 bvlc_length
+= npdu_length
;
1004 /* Now add the BSCVLC payload size for specified function */
1005 switch (bvlc_function
)
1007 case 0x00: /* BVLC-Result */
1008 case 0x03: /* Address-Resolution-ACK */
1009 case 0x0C: /* Proprietary-Message */
1010 /* complete packet length because of optional present variable length error data
1011 but no length encoded for it in the structure of this frame */
1012 bvlc_length
= packet_length
;
1014 case 0x02: /* Address-Resolution */
1015 case 0x05: /* Advertisement-Solicitation */
1016 case 0x08: /* Disconnect-Request */
1017 case 0x09: /* Disconnect-ACK */
1018 case 0x0A: /* Heartbeat-Request */
1019 case 0x0B: /* Heartbeat-ACK */
1020 /* No additional payload here */
1022 case 0x04: /* Advertisement */
1025 case 0x06: /* Connect-Request */
1026 case 0x07: /* Connect-Accept */
1029 case 0x01: /* Encapsulated-NPDU */
1031 /* The additional payload will be decoded elsewhere */
1035 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "BSCVLC");
1036 col_set_str(pinfo
->cinfo
, COL_INFO
, "BACnet Secure Connect Virtual Link Control");
1038 /* Put the BSCVLC Type and Message ID in the info column */
1039 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " BSCVLC Function %s Message-ID %u",
1040 val_to_str_const(bvlc_function
, bscvlc_function_names
, "unknown"), bvlc_message_id
);
1042 /* Fill the tree... */
1044 ti
= proto_tree_add_item(tree
, proto_bscvlc
, tvb
, 0, bvlc_length
, ENC_NA
);
1045 bvlc_tree
= proto_item_add_subtree(ti
, ett_bvlc
);
1047 proto_tree_add_uint(bvlc_tree
, hf_bscvlc_function
, tvb
,
1048 offset
, 1, bvlc_function
);
1050 proto_tree_add_bitmask(bvlc_tree
, tvb
, offset
, hf_bscvlc_control
,
1051 ett_bscvlc_ctrl
, bscvlc_control_flags
, ENC_NA
);
1053 proto_tree_add_uint(bvlc_tree
, hf_bscvlc_msg_id
, tvb
,
1054 offset
, 2, bvlc_message_id
);
1057 if ((bvlc_control
& BSCVLC_CONTROL_ORIG_ADDRESS
) != 0)
1059 for(idx
= 0; idx
< 6; idx
++)
1060 snprintf(&mac_buffer
[idx
* 2], sizeof(mac_buffer
) - (idx
* 2), "%02X", tvb_get_uint8(tvb
, offset
+ idx
));
1061 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " SMAC %s", mac_buffer
);
1063 proto_tree_add_item(bvlc_tree
, hf_bscvlc_orig_vmac
, tvb
, offset
, 6, ENC_NA
);
1067 if ((bvlc_control
& BSCVLC_CONTROL_DEST_ADDRESS
) != 0)
1069 for(idx
= 0; idx
< 6; idx
++)
1070 snprintf(&mac_buffer
[idx
* 2], sizeof(mac_buffer
) - (idx
* 2), "%02X", tvb_get_uint8(tvb
, offset
+ idx
));
1071 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " DMAC %s", mac_buffer
);
1073 proto_tree_add_item(bvlc_tree
, hf_bscvlc_dest_vmac
, tvb
, offset
, 6, ENC_NA
);
1077 if ((bvlc_control
& BSCVLC_CONTROL_DEST_OPTION
) != 0)
1081 while(tvb_reported_length_remaining(tvb
, offset
) > 0 &&
1082 (hdr_byte
= tvb_get_uint8(tvb
, offset
)) != 0 && bMoreFlag
)
1084 /* get flags and type... */
1085 bMoreFlag
= (hdr_byte
& BSCVLC_HEADER_OPTION_MORE_OPTIONS
);
1086 bDataFlag
= (hdr_byte
& BSCVLC_HEADER_OPTION_DATA
);
1093 npdu_length
= (int)(tvb_get_uint8(tvb
, offset
++) << 8);
1094 npdu_length
+= (int)tvb_get_uint8(tvb
, offset
++);
1095 offset
+= npdu_length
;
1098 subtree
= proto_tree_add_subtree_format(bvlc_tree
, tvb
, start
, offset
- start
,
1099 ett_bscvlc_hdr
, NULL
, "%s", "Destination Options");
1100 proto_tree_add_bitmask_value(subtree
, tvb
, start
, hf_bscvlc_header
,
1101 ett_bscvlc_hdr
, bscvlc_header_flags
, hdr_byte
);
1105 proto_tree_add_item(subtree
, hf_bscvlc_header_length
, tvb
, start
+ 1, 2, ENC_NA
);
1106 proto_tree_add_item(subtree
, hf_bscvlc_header_data
, tvb
, start
+ 3, npdu_length
, ENC_NA
);
1111 if ((bvlc_control
& BSCVLC_CONTROL_DATA_OPTION
) != 0)
1115 while(tvb_reported_length_remaining(tvb
, offset
) > 0 &&
1116 (hdr_byte
= tvb_get_uint8(tvb
, offset
)) != 0 && bMoreFlag
)
1118 /* get flags and type... */
1119 bMoreFlag
= (hdr_byte
& BSCVLC_HEADER_OPTION_MORE_OPTIONS
);
1120 bDataFlag
= (hdr_byte
& BSCVLC_HEADER_OPTION_DATA
);
1127 npdu_length
= (int)(tvb_get_uint8(tvb
, offset
++) << 8);
1128 npdu_length
+= (int)tvb_get_uint8(tvb
, offset
++);
1129 offset
+= npdu_length
;
1132 subtree
= proto_tree_add_subtree_format(bvlc_tree
, tvb
, start
, offset
- start
,
1133 ett_bscvlc_hdr
, NULL
, "%s", "Data Options");
1134 proto_tree_add_bitmask_value(subtree
, tvb
, start
, hf_bscvlc_header
,
1135 ett_bscvlc_hdr
, bscvlc_header_flags
, hdr_byte
);
1139 proto_tree_add_item(subtree
, hf_bscvlc_header_length
, tvb
, start
+ 1, 2, ENC_NA
);
1140 proto_tree_add_item(subtree
, hf_bscvlc_header_data
, tvb
, start
+ 3, npdu_length
, ENC_NA
);
1145 switch (bvlc_function
)
1147 case 0x02: /* Address-Resolution */
1148 case 0x05: /* Advertisement-Solicitation */
1149 case 0x08: /* Disconnect-Request */
1150 case 0x09: /* Disconnect-ACK */
1151 case 0x0A: /* Heartbeat-Request */
1152 case 0x0B: /* Heartbeat-ACK */
1154 case 0x00: /* BVLC-Result */
1155 subtree
= proto_tree_add_subtree_format(bvlc_tree
, tvb
, offset
, packet_length
- offset
,
1156 ett_bscvlc_hdr
, NULL
, "%s", "BVLC-Result");
1157 proto_tree_add_item(subtree
, hf_bscvlc_function
, tvb
,
1160 proto_tree_add_item(subtree
, hf_bscvlc_result
, tvb
,
1162 bvlc_result
= tvb_get_uint8(tvb
, offset
);
1165 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " %s",
1166 val_to_str_const(bvlc_result
, bscvlc_result_names
, "unknown"));
1170 proto_tree_add_item(subtree
, hf_bscvlc_header_marker
, tvb
,
1173 proto_tree_add_item(subtree
, hf_bscvlc_error_class
, tvb
,
1176 proto_tree_add_item(subtree
, hf_bscvlc_error_code
, tvb
,
1179 proto_tree_add_item(subtree
, hf_bscvlc_result_data
, tvb
,
1180 offset
, packet_length
- offset
, ENC_NA
);
1182 /* Force and of packet */
1183 offset
= packet_length
;
1185 case 0x03: /* Address-Resolution-ACK */
1186 subtree
= proto_tree_add_subtree_format(bvlc_tree
, tvb
, offset
, packet_length
- offset
,
1187 ett_bscvlc_hdr
, NULL
, "%s", "Address-Resolution-ACK");
1188 proto_tree_add_item(subtree
, hf_bscvlc_uris
, tvb
,
1189 offset
, packet_length
- offset
, ENC_NA
);
1190 /* Force and of packet */
1191 offset
= packet_length
;
1193 case 0x04: /* Advertisement */
1194 subtree
= proto_tree_add_subtree_format(bvlc_tree
, tvb
, offset
, packet_length
- offset
,
1195 ett_bscvlc_hdr
, NULL
, "%s", "Advertisement");
1196 proto_tree_add_item(subtree
, hf_bscvlc_hub_conn_state
, tvb
,
1199 proto_tree_add_item(subtree
, hf_bscvlc_accept_conns
, tvb
,
1202 proto_tree_add_item(subtree
, hf_bscvlc_max_bvlc_length
, tvb
,
1205 proto_tree_add_item(subtree
, hf_bscvlc_max_npdu_length
, tvb
,
1209 case 0x06: /* Connect-Request */
1210 subtree
= proto_tree_add_subtree_format(bvlc_tree
, tvb
, offset
, packet_length
- offset
,
1211 ett_bscvlc_hdr
, NULL
, "%s", "Connect-Request");
1212 proto_tree_add_item(subtree
, hf_bscvlc_connect_vmac
, tvb
,
1215 proto_tree_add_item(subtree
, hf_bscvlc_connect_uuid
, tvb
,
1216 offset
, 16, ENC_NA
);
1218 proto_tree_add_item(subtree
, hf_bscvlc_max_bvlc_length
, tvb
,
1221 proto_tree_add_item(subtree
, hf_bscvlc_max_npdu_length
, tvb
,
1225 case 0x07: /* Connect-Accept */
1226 subtree
= proto_tree_add_subtree_format(bvlc_tree
, tvb
, offset
, packet_length
- offset
,
1227 ett_bscvlc_hdr
, NULL
, "%s", "Connect-Accept");
1228 proto_tree_add_item(subtree
, hf_bscvlc_connect_vmac
, tvb
,
1231 proto_tree_add_item(subtree
, hf_bscvlc_connect_uuid
, tvb
,
1232 offset
, 16, ENC_NA
);
1234 proto_tree_add_item(subtree
, hf_bscvlc_max_bvlc_length
, tvb
,
1237 proto_tree_add_item(subtree
, hf_bscvlc_max_npdu_length
, tvb
,
1241 case 0x0C: /* Proprietary-Message */
1242 subtree
= proto_tree_add_subtree_format(bvlc_tree
, tvb
, offset
, packet_length
- offset
,
1243 ett_bscvlc_hdr
, NULL
, "%s", "Proprietary-Message");
1244 proto_tree_add_item(subtree
, hf_bscvlc_vendor_id
, tvb
,
1247 proto_tree_add_item(subtree
, hf_bscvlc_proprietary_opt_type
, tvb
,
1250 proto_tree_add_item(subtree
, hf_bscvlc_proprietary_data
, tvb
,
1251 offset
, packet_length
- offset
, ENC_NA
);
1252 /* Force and of packet */
1253 offset
= packet_length
;
1255 case 0x01: /* Encapsulated-NPDU */
1257 /* Here we assume additional payload belongs to upper layers and will be decoded later */
1261 /* Let the remaining frame to be decoded elsewhere */
1262 npdu_length
= packet_length
- offset
;
1263 next_tvb
= tvb_new_subset_length(tvb
, offset
, npdu_length
);
1264 /* Code from Guy Harris */
1265 if (!dissector_try_uint(bscvlc_dissector_table
,
1266 bvlc_function
, next_tvb
, pinfo
, tree
)) {
1267 /* Unknown function - dissect the payload as data */
1268 call_data_dissector(next_tvb
, pinfo
, tree
);
1271 return tvb_reported_length(tvb
);
1275 proto_register_bvlc(void)
1277 static hf_register_info hf
[] = {
1279 { "Type", "bvlc.type",
1280 FT_UINT8
, BASE_HEX
, VALS(bvlc_types
), 0,
1283 { &hf_bvlc_function
,
1284 { "Function", "bvlc.function",
1285 FT_UINT8
, BASE_HEX
, VALS(bvlc_function_names
), 0,
1286 "BVLC Function", HFILL
}
1288 { &hf_bvlc_ipv6_function
,
1289 { "Function", "bvlc.function_ipv6",
1290 FT_UINT8
, BASE_HEX
, VALS(bvlc_ipv6_function_names
), 0,
1291 "BVLC Function IPV6", HFILL
}
1294 { "BVLC-Length", "bvlc.length",
1295 FT_UINT16
, BASE_DEC
, NULL
, 0,
1296 "Length of BVLC", HFILL
}
1298 { &hf_bvlc_virt_source
,
1299 { "BVLC-Virtual-Source", "bvlc.virtual_source",
1300 FT_UINT24
, BASE_DEC_HEX
, NULL
, 0,
1301 "Virtual source address of BVLC", HFILL
}
1303 { &hf_bvlc_virt_dest
,
1304 { "BVLC-Virtual-Destination", "bvlc.virtual_dest",
1305 FT_UINT24
, BASE_DEC_HEX
, NULL
, 0,
1306 "Virtual destination address of BVLC", HFILL
}
1308 { &hf_bvlc_result_ip4
,
1309 { "Result", "bvlc.result",
1310 FT_UINT16
, BASE_HEX
, VALS(bvlc_result_names
), 0,
1311 "Result Code", HFILL
}
1313 { &hf_bvlc_result_ip6
,
1314 { "Result", "bvlc.result",
1315 FT_UINT16
, BASE_HEX
, VALS(bvlc_ipv6_result_names
), 0,
1316 "Result Code", HFILL
}
1319 { "IP", "bvlc.bdt_ip",
1320 FT_IPv4
, BASE_NONE
, NULL
, 0,
1323 { &hf_bvlc_bdt_port
,
1324 { "Port", "bvlc.bdt_port",
1325 FT_UINT16
, BASE_DEC
, NULL
, 0,
1328 { &hf_bvlc_bdt_mask
,
1329 { "Mask", "bvlc.bdt_mask",
1330 FT_BYTES
, BASE_NONE
, NULL
, 0,
1331 "BDT Broadcast Distribution Mask", HFILL
}
1334 { "TTL", "bvlc.reg_ttl",
1335 FT_UINT16
, BASE_DEC
, NULL
, 0,
1336 "Foreign Device Time To Live", HFILL
}
1339 { "IP", "bvlc.fdt_ip",
1340 FT_IPv4
, BASE_NONE
, NULL
, 0,
1343 { &hf_bvlc_fdt_ipv6
,
1344 { "IP", "bvlc.fdt_ipv6",
1345 FT_IPv6
, BASE_NONE
, NULL
, 0,
1348 { &hf_bvlc_fdt_port
,
1349 { "Port", "bvlc.fdt_port",
1350 FT_UINT16
, BASE_DEC
, NULL
, 0,
1354 { "TTL", "bvlc.fdt_ttl",
1355 FT_UINT16
, BASE_DEC
, NULL
, 0,
1356 "Foreign Device Time To Live", HFILL
}
1358 { &hf_bvlc_fdt_timeout
,
1359 { "Timeout", "bvlc.fdt_timeout",
1360 FT_UINT16
, BASE_DEC
, NULL
, 0,
1361 "Foreign Device Timeout (seconds)", HFILL
}
1364 { "IP", "bvlc.fwd_ip",
1365 FT_IPv4
, BASE_NONE
, NULL
, 0,
1368 { &hf_bvlc_fwd_port
,
1369 { "Port", "bvlc.fwd_port",
1370 FT_UINT16
, BASE_DEC
, NULL
, 0,
1373 { &hf_bvlc_orig_source_addr
,
1374 { "IP", "bvlc.orig_source_addr",
1375 FT_IPv6
, BASE_NONE
, NULL
, 0,
1378 { &hf_bvlc_orig_source_port
,
1379 { "Port", "bvlc.orig_source_port",
1380 FT_UINT16
, BASE_DEC
, NULL
, 0,
1381 "ORIG Port", HFILL
}
1385 static int *ett
[] = {
1391 static hf_register_info bsc_hf
[] = {
1392 { &hf_bscvlc_control
,
1393 { "Control", "bscvlc.control",
1394 FT_UINT8
, BASE_HEX
, NULL
, 0,
1395 "BSCVLC Control", HFILL
}
1397 { &hf_bscvlc_control_data_option
,
1398 { "Data Option", "bscvlc.control_data_option",
1399 FT_BOOLEAN
, 8, TFS(&control_data_option_set_high
),
1400 BSCVLC_CONTROL_DATA_OPTION
, "BSCVLC Control", HFILL
}
1402 { &hf_bscvlc_control_destination_option
,
1403 { "Destination Option", "bscvlc.control_dest_option",
1404 FT_BOOLEAN
, 8, TFS(&control_destination_option_set_high
),
1405 BSCVLC_CONTROL_DEST_OPTION
, "BSCVLC Control", HFILL
}
1407 { &hf_bscvlc_control_destination_address
,
1408 { "Destination Address","bscvlc.control_dest_address",
1409 FT_BOOLEAN
, 8, TFS(&control_destination_address_set_high
),
1410 BSCVLC_CONTROL_DEST_ADDRESS
, "BSCVLC Control", HFILL
}
1412 { &hf_bscvlc_control_origin_address
,
1413 { "Origin Address", "bscvlc.control_orig_address",
1414 FT_BOOLEAN
, 8, TFS(&control_orig_address_set_high
),
1415 BSCVLC_CONTROL_ORIG_ADDRESS
, "BSCVLC Control", HFILL
}
1417 { &hf_bscvlc_control_reserved
,
1418 { "Reserved", "bscvlc.control_reserved",
1419 FT_BOOLEAN
, 8, TFS(&control_reserved_set_high
),
1420 BSCVLC_CONTROL_RESERVED
, "BSCVLC Control", HFILL
}
1422 { &hf_bscvlc_header
,
1423 { "Header Data Length", "bscvlc.header",
1424 FT_UINT8
, BASE_HEX
, NULL
, 0,
1425 "BSCVLC Header Control Data", HFILL
}
1427 { &hf_bscvlc_header_marker
,
1428 { "Header Error Marker","bscvlc.header_error_marker",
1429 FT_UINT8
, BASE_HEX
, NULL
, 0,
1430 "BSCVLC Header Error Marker", HFILL
}
1432 { &hf_bscvlc_header_length
,
1433 { "Header Data Length", "bscvlc.header_length",
1434 FT_UINT16
, BASE_DEC
, NULL
, 0,
1435 "BSCVLC Header Data Length", HFILL
}
1437 { &hf_bscvlc_header_data
,
1438 { "Header Data", "bscvlc.header_data",
1439 FT_BYTES
, BASE_NONE
, NULL
, 0,
1440 "BSCVLC Header Option", HFILL
}
1442 { &hf_bscvlc_header_opt_type
,
1443 { "Header Type", "bscvlc.header_type",
1444 FT_UINT8
, BASE_HEX
, VALS(bscvlc_header_type_names
),
1445 BSCVLC_HEADER_OPTION_TYPE
, "BSCVLC Header Option", HFILL
}
1447 { &hf_bscvlc_header_opt_data
,
1448 { "Header Data", "bscvlc.header_data_present",
1449 FT_BOOLEAN
, 8, TFS(&header_opt_data_set_high
),
1450 BSCVLC_HEADER_OPTION_DATA
, "BSCVLC Header Option", HFILL
}
1452 { &hf_bscvlc_header_opt_must_understand
,
1453 { "Header Must Understand","bscvlc.header_understand",
1454 FT_BOOLEAN
, 8, TFS(&header_opt_must_understand_set_high
),
1455 BSCVLC_HEADER_OPTION_MUST_UNDERSTAND
, "BSCVLC Header Option", HFILL
}
1457 { &hf_bscvlc_header_opt_more
,
1458 { "Header More", "bscvlc.header_more",
1459 FT_BOOLEAN
, 8, TFS(&header_opt_more_set_high
),
1460 BSCVLC_HEADER_OPTION_MORE_OPTIONS
, "BSCVLC Header Option", HFILL
}
1462 { &hf_bscvlc_vendor_id
,
1463 { "Vendor ID", "bscvlc.vendor_id",
1464 FT_UINT16
, BASE_HEX
, NULL
, 0,
1465 "BSCVLC Vendor ID", HFILL
}
1467 { &hf_bscvlc_proprietary_opt_type
,
1468 { "Proprietary Type", "bscvlc.proprietary_type",
1469 FT_UINT8
, BASE_HEX
, NULL
, 0,
1470 "BSCVLC Proprietary Type", HFILL
}
1472 { &hf_bscvlc_proprietary_data
,
1473 { "Proprietary Data", "bscvlc.proprietary_data",
1474 FT_BYTES
, BASE_NONE
, NULL
, 0,
1475 "BSCVLC Proprietary Data", HFILL
}
1477 { &hf_bscvlc_hub_conn_state
,
1478 { "Hub Connection Status","bscvlc.hub_conn_state",
1479 FT_UINT8
, BASE_HEX
, VALS(bscvlc_hub_conn_state_names
), 0,
1480 "BSCVLC Hub Connection Status", HFILL
}
1482 { &hf_bscvlc_accept_conns
,
1483 { "Hub Accepts Connections","bscvlc.accept_conns",
1484 FT_UINT8
, BASE_HEX
, VALS(bscvlc_hub_accept_conns_names
), 0,
1485 "BSCVLC Accepts Connections", HFILL
}
1487 { &hf_bscvlc_max_bvlc_length
,
1488 { "Max. BVLC Length", "bscvlc.max_bvlc_length",
1489 FT_UINT16
, BASE_DEC
, NULL
, 0,
1490 "Max Supported BVLC Length", HFILL
}
1492 { &hf_bscvlc_max_npdu_length
,
1493 { "Max. NPDU Length", "bscvlc.max_npdu_length",
1494 FT_UINT16
, BASE_DEC
, NULL
, 0,
1495 "Max Supported NPDU Length", HFILL
}
1497 { &hf_bscvlc_function
,
1498 { "Function", "bscvlc.function",
1499 FT_UINT8
, BASE_HEX
, VALS(bscvlc_function_names
), 0,
1500 "BSCVLC Function", HFILL
}
1502 { &hf_bscvlc_result
,
1503 { "Result", "bscvlc.result",
1504 FT_UINT8
, BASE_HEX
, VALS(bscvlc_result_names
), 0,
1505 "Result Code", HFILL
}
1507 { &hf_bscvlc_error_class
,
1508 { "Error Class", "bscvlc.error_class",
1509 FT_UINT32
, BASE_DEC
, VALS(BACnetErrorClass
), 0, NULL
, HFILL
}
1511 { &hf_bscvlc_error_code
,
1512 { "Error Code", "bscvlc.error_code",
1513 FT_UINT32
, BASE_DEC
, VALS(BACnetErrorCode
), 0, NULL
, HFILL
}
1515 { &hf_bscvlc_result_data
,
1516 { "Result Data", "bscvlc.result_data",
1517 FT_BYTES
, BASE_NONE
, NULL
, 0,
1518 "BSCVLC Result Data", HFILL
}
1521 { "URI's", "bscvlc.uris",
1522 FT_BYTES
, BASE_NONE
, NULL
, 0,
1523 "BSCVLC Address URI's", HFILL
}
1525 { &hf_bscvlc_msg_id
,
1526 { "Message ID", "bscvlc.msgid",
1527 FT_UINT16
, BASE_DEC
, NULL
, 0,
1528 "BSCVLC Message ID", HFILL
}
1530 { &hf_bscvlc_orig_vmac
,
1531 { "SVMAC", "bscvlc.orig_virtual_address",
1532 FT_BYTES
, BASE_NONE
, NULL
, 0,
1533 "ORIG VMAC", HFILL
}
1535 { &hf_bscvlc_dest_vmac
,
1536 { "DVMAC", "bscvlc.dest_virtual_address",
1537 FT_BYTES
, BASE_NONE
, NULL
, 0,
1538 "DEST VMAC", HFILL
}
1540 { &hf_bscvlc_connect_vmac
,
1541 { "Connecting VMAC", "bscvlc.connect_virtual_address",
1542 FT_BYTES
, BASE_NONE
, NULL
, 0,
1543 "BSCVLC Connecting VMAC", HFILL
}
1545 { &hf_bscvlc_connect_uuid
,
1546 { "Connecting UUID", "bscvlc.connect_uuid",
1547 FT_BYTES
, BASE_NONE
, NULL
, 0,
1548 "BSCVLC Connecting UUID", HFILL
}
1552 static int *bsc_ett
[] = {
1558 proto_bvlc
= proto_register_protocol("BACnet Virtual Link Control", "BVLC", "bvlc");
1560 proto_register_field_array(proto_bvlc
, hf
, array_length(hf
));
1561 proto_register_subtree_array(ett
, array_length(ett
));
1563 bvlc_handle
= register_dissector("bvlc", dissect_bvlc
, proto_bvlc
);
1565 bvlc_dissector_table
= register_dissector_table("bvlc.function", "BVLC Function", proto_bvlc
, FT_UINT8
, BASE_HEX
);
1566 bvlc_ipv6_dissector_table
= register_dissector_table("bvlc.function_ipv6", "BVLC Function IPV6", proto_bvlc
, FT_UINT8
, BASE_HEX
);
1568 proto_bscvlc
= proto_register_protocol("BACnet Secure Connect Virtual Link Control", "BSCVLC", "bscvlc");
1570 proto_register_field_array(proto_bscvlc
, bsc_hf
, array_length(bsc_hf
));
1571 proto_register_subtree_array(bsc_ett
, array_length(bsc_ett
));
1573 bscvlc_handle
= register_dissector("bscvlc", dissect_bscvlc
, proto_bscvlc
);
1575 bscvlc_dissector_table
= register_dissector_table("bscvlc.function", "BSCVLC Function", proto_bscvlc
, FT_UINT8
, BASE_HEX
);
1579 proto_reg_handoff_bvlc(void)
1581 dissector_add_uint_with_preference("udp.port", BVLC_UDP_PORT
, bvlc_handle
);
1582 dissector_add_string("ws.protocol", "hub.bsc.bacnet.org", bscvlc_handle
);
1583 dissector_add_string("ws.protocol", "dc.bsc.bacnet.org", bscvlc_handle
);
1587 * Editor modelines - https://www.wireshark.org/tools/modelines.html
1592 * indent-tabs-mode: t
1595 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
1596 * :indentSize=8:tabSize=8:noTabs=false: