Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-bvlc.c
blob253b9d6555216051c036cc3fa739c62b06909de8
1 /* packet-bvlc.c
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
14 #include "config.h"
16 #include <epan/packet.h>
17 #include <epan/tfs.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" },
112 { 0, NULL }
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" },
129 { 0, NULL }
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" },
140 { 0, NULL }
143 static const value_string bscvlc_result_names[] = {
144 { 0x00, "Successful completion (ACK)" },
145 { 0x01, "Completion failed (NAK)" },
146 { 0, NULL }
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", },
163 { 0, NULL }
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" },
173 { 0, NULL }
176 static const value_string bscvlc_header_type_names[] = {
177 { 0x01, "Secure Path" },
178 { 0x1F, "Proprietary Header Option" },
179 { 0, NULL }
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" },
186 { 0, NULL }
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" },
192 { 0, NULL }
195 static int ett_bvlc;
196 static int ett_bscvlc;
197 static int ett_bscvlc_ctrl;
198 static int ett_bscvlc_hdr;
199 static int ett_bdt;
200 static int ett_fdt;
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)" },
208 { 0, NULL }
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 [] = {
268 { 0, "device" },
269 { 1, "object" },
270 { 2, "property" },
271 { 3, "resources" },
272 { 4, "security" },
273 { 5, "services" },
274 { 6, "vt" },
275 { 7, "communication" },
276 { 0, NULL }
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[] = {
284 { 0, "other"},
285 { 1, "authentication-failed"},
286 { 2, "configuration-in-progress"},
287 { 3, "device-busy"},
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"},
314 { 30, "timeout"},
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"},
366 { 82, "busy"},
367 { 83, "communication-disabled"},
368 { 84, "success"},
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"},
412 { 128, "file-full"},
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"},
472 { 188, "tls-error"},
473 { 189, "dns-unavailable"},
474 { 190, "dns-name-resolution-failed"},
475 { 191, "dns-resolver-failure"},
476 { 192, "dns-error"},
477 { 193, "tcp-connect-timeout"},
478 { 194, "tcp-connection-refused"},
479 { 195, "tcp-closed-by-local"},
480 { 196, "tcp-closed-other"},
481 { 197, "tcp-error"},
482 { 198, "ip-address-not-reachable"},
483 { 199, "ip-error"},
484 { 0, NULL}
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,
496 NULL
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,
504 NULL
507 static int
508 // NOLINTNEXTLINE(misc-no-recursion)
509 dissect_ipv4_bvlc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
512 proto_item *ti;
513 proto_item *ti_bdt;
514 proto_item *ti_fdt;
515 proto_tree *bvlc_tree;
516 proto_tree *bdt_tree; /* Broadcast Distribution Table */
517 proto_tree *fdt_tree; /* Foreign Device Table */
519 int offset;
520 uint8_t bvlc_type;
521 uint8_t bvlc_function;
522 uint16_t bvlc_length;
523 uint16_t packet_length;
524 unsigned npdu_length;
525 unsigned length_remaining;
526 tvbuff_t *next_tvb;
528 offset = 0;
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.
540 bvlc_length = 4;
541 } else if (bvlc_function == 0x04) {
542 /* 4 Bytes + 6 Bytes for B/IP Address of Originating Device */
543 bvlc_length = 10;
544 } else {
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,
564 bvlc_type);
565 offset++;
566 proto_tree_add_uint(bvlc_tree, hf_bvlc_function, tvb,
567 offset, 1, bvlc_function);
568 offset++;
569 if (length_remaining != packet_length)
570 proto_tree_add_uint_format_value(bvlc_tree, hf_bvlc_length, tvb, offset,
571 2, bvlc_length,
572 "%d of %d bytes (invalid length - expected %d bytes)",
573 bvlc_length, packet_length, length_remaining);
574 else
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);
578 offset += 2;
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);
588 /*offset += 2;*/
589 break;
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);
600 offset += 4;
601 proto_tree_add_item(bdt_tree, hf_bvlc_bdt_port,
602 tvb, offset, 2, ENC_BIG_ENDIAN);
603 offset += 2;
604 proto_tree_add_item(bdt_tree,
605 hf_bvlc_bdt_mask, tvb, offset, 4,
606 ENC_NA);
607 offset += 4;
609 /* We check this if we get a BDT-packet somewhere */
610 break;
611 case 0x02: /* Read-Broadcast-Distribution-Table */
612 /* nothing to do here */
613 break;
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);
618 /*offset += 2;*/
619 break;
620 case 0x06: /* Read-Foreign-Device-Table */
621 /* nothing to do here */
622 break;
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);
640 offset += 4;
641 proto_tree_add_item(fdt_tree, hf_bvlc_fdt_port,
642 tvb, offset, 2, ENC_BIG_ENDIAN);
643 offset += 2;
644 proto_tree_add_item(fdt_tree,
645 hf_bvlc_fdt_ttl, tvb, offset, 2,
646 ENC_BIG_ENDIAN);
647 offset += 2;
648 proto_tree_add_item(fdt_tree,
649 hf_bvlc_fdt_timeout, tvb, offset, 2,
650 ENC_BIG_ENDIAN);
651 offset += 2;
653 /* We check this if we get a FDT-packet somewhere */
654 break;
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);
659 offset += 4;
660 proto_tree_add_item(bvlc_tree, hf_bvlc_fdt_port,
661 tvb, offset, 2, ENC_BIG_ENDIAN);
662 /*offset += 2;*/
663 break;
664 case 0x0C: /* Secure-BVLL */
665 offset = bacnet_dissect_sec_wrapper(tvb, pinfo, tree, offset, NULL);
666 if (offset < 0) {
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);
673 break;
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);
683 offset += 4;
684 proto_tree_add_item(bvlc_tree, hf_bvlc_fwd_port,
685 tvb, offset, 2, ENC_BIG_ENDIAN);
686 /*offset += 2;*/
687 break;
688 default:
689 /* Distribute-Broadcast-To-Network
690 * Original-Unicast-NPDU
691 * Original-Broadcast-NPDU
692 * Going to the next dissector...
694 break;
697 /* Ok, no routing information BVLC packet. Dissect as
698 * BACnet NPDU
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);
711 static int
712 // NOLINTNEXTLINE(misc-no-recursion)
713 dissect_ipv6_bvlc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
715 proto_item *ti;
716 proto_tree *bvlc_tree;
718 int offset;
719 uint8_t bvlc_type;
720 uint8_t bvlc_function;
721 uint16_t bvlc_length = 0;
722 uint16_t packet_length;
723 unsigned npdu_length;
724 unsigned length_remaining;
725 tvbuff_t *next_tvb;
727 offset = 0;
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) {
735 case 0x00:
736 case 0x09:
737 bvlc_length = 9;
738 break;
739 case 0x01:
740 bvlc_length = 10;
741 break;
742 case 0x02:
743 case 0x06:
744 case 0x0C:
745 bvlc_length = 7;
746 break;
747 case 0x03:
748 case 0x05:
749 case 0x07:
750 bvlc_length = 10;
751 break;
752 case 0x04:
753 bvlc_length = 28;
754 break;
755 case 0x08:
756 case 0x0A:
757 bvlc_length = 25;
758 break;
759 case 0x0B:
760 bvlc_length = 4;
761 break;
762 default:
763 break;
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,
779 bvlc_type);
780 offset++;
781 /* add the BVLC function */
782 proto_tree_add_uint(bvlc_tree, hf_bvlc_ipv6_function, tvb,
783 offset, 1, bvlc_function);
784 offset++;
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,
788 2, bvlc_length,
789 "%d of %d bytes (invalid length - expected %d bytes)",
790 bvlc_length, packet_length, length_remaining);
791 else
792 proto_tree_add_uint_format_value(bvlc_tree, hf_bvlc_length, tvb, offset,
793 2, bvlc_length,
794 "%d of %d bytes BACnet packet length",
795 bvlc_length, packet_length);
796 offset += 2;
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,
801 3, ENC_BIG_ENDIAN);
802 offset += 3;
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);
810 offset += 2;
811 break;
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,
817 3, ENC_BIG_ENDIAN);
818 offset += 3;
819 break;
820 case 0x04: /* Forwarded-Address-Resolution */
821 proto_tree_add_item(bvlc_tree, hf_bvlc_virt_dest, tvb, offset,
822 3, ENC_BIG_ENDIAN);
823 offset += 3;
824 proto_tree_add_item(bvlc_tree, hf_bvlc_orig_source_addr,
825 tvb, offset, 16, ENC_NA);
826 offset += 16;
827 proto_tree_add_item(bvlc_tree, hf_bvlc_orig_source_port,
828 tvb, offset, 2, ENC_BIG_ENDIAN);
829 offset += 2;
830 break;
831 case 0x08: /* Forwarded-NPDU */
832 proto_tree_add_item(bvlc_tree, hf_bvlc_orig_source_addr,
833 tvb, offset, 16, ENC_NA);
834 offset += 16;
835 proto_tree_add_item(bvlc_tree, hf_bvlc_orig_source_port,
836 tvb, offset, 2, ENC_BIG_ENDIAN);
837 offset += 2;
838 break;
839 case 0x06: /* Virtual-Address-Resolution */
840 break;
841 case 0x09: /* Register-Foreign-Device */
842 proto_tree_add_item(bvlc_tree, hf_bvlc_reg_ttl,
843 tvb, offset, 2, ENC_BIG_ENDIAN);
844 offset += 2;
845 break;
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);
849 offset += 16;
850 proto_tree_add_item(bvlc_tree, hf_bvlc_fdt_port,
851 tvb, offset, 2, ENC_BIG_ENDIAN);
852 offset += 2;
853 break;
854 case 0x0B: /* Secure-BVLL */
855 offset = bacnet_dissect_sec_wrapper(tvb, pinfo, tree, offset, NULL);
856 if (offset < 0) {
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);
863 break;
864 case 0x02: /* Original-Broadcast-NPDU */
865 case 0x0c: /* Distribute-Broadcast-To-Network */
866 default:
868 * Going to the next dissector...
870 break;
873 /* Ok, no routing information BVLC packet. Dissect as
874 * BACnet NPDU
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);
888 static int
889 dissect_bvlc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
891 uint8_t bvlc_type;
892 unsigned ret = 0;
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)
900 return 0;
902 col_set_str(pinfo->cinfo, COL_PROTOCOL, "BVLC");
903 col_set_str(pinfo->cinfo, COL_INFO, "BACnet Virtual Link Control");
905 switch (bvlc_type)
907 case BACNET_IP_ANNEX_J:
908 ret = dissect_ipv4_bvlc(tvb, pinfo, tree, data);
909 break;
910 case BACNET_IPV6_ANNEX_U:
911 ret = dissect_ipv6_bvlc(tvb, pinfo, tree, data);
912 break;
915 return ret;
918 static int
919 dissect_bscvlc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
921 proto_item *ti;
922 proto_tree *bvlc_tree;
923 tvbuff_t *next_tvb;
924 int offset;
925 int start;
926 int bvlc_length;
927 int packet_length;
928 int npdu_length;
929 uint8_t bvlc_function;
930 uint8_t bvlc_control;
931 uint8_t bvlc_result;
932 uint8_t hdr_byte;
933 int8_t mac_buffer[16];
934 unsigned bvlc_message_id;
935 unsigned idx;
936 bool bMoreFlag;
937 bool bDataFlag;
938 proto_tree *subtree;
940 /* Calculate length of BSCVLC block to get remaining payload length */
941 offset = 0;
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);
951 offset += 2;
953 /* Variable part of the header next */
954 bvlc_length = offset;
956 if ((bvlc_control & BSCVLC_CONTROL_ORIG_ADDRESS) != 0)
957 bvlc_length += 6;
959 if ((bvlc_control & BSCVLC_CONTROL_DEST_ADDRESS) != 0)
960 bvlc_length += 6;
962 if ((bvlc_control & BSCVLC_CONTROL_DEST_OPTION) != 0)
964 bMoreFlag = true;
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);
972 bvlc_length++;
974 if(bDataFlag)
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)
985 bMoreFlag = true;
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);
993 bvlc_length++;
995 if(bDataFlag)
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;
1013 break;
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 */
1021 break;
1022 case 0x04: /* Advertisement */
1023 bvlc_length += 6;
1024 break;
1025 case 0x06: /* Connect-Request */
1026 case 0x07: /* Connect-Accept */
1027 bvlc_length += 26;
1028 break;
1029 case 0x01: /* Encapsulated-NPDU */
1030 default:
1031 /* The additional payload will be decoded elsewhere */
1032 break;
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... */
1043 offset = 0;
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);
1049 offset++;
1050 proto_tree_add_bitmask(bvlc_tree, tvb, offset, hf_bscvlc_control,
1051 ett_bscvlc_ctrl, bscvlc_control_flags, ENC_NA);
1052 offset ++;
1053 proto_tree_add_uint(bvlc_tree, hf_bscvlc_msg_id, tvb,
1054 offset, 2, bvlc_message_id);
1055 offset += 2;
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);
1064 offset += 6;
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);
1074 offset += 6;
1077 if ((bvlc_control & BSCVLC_CONTROL_DEST_OPTION) != 0)
1079 bMoreFlag = true;
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);
1087 start = offset;
1089 offset++;
1091 if(bDataFlag)
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);
1103 if(bDataFlag)
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)
1113 bMoreFlag = true;
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);
1121 start = offset;
1123 offset++;
1125 if(bDataFlag)
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);
1137 if(bDataFlag)
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 */
1153 break;
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,
1158 offset, 1, ENC_NA);
1159 offset++;
1160 proto_tree_add_item(subtree, hf_bscvlc_result, tvb,
1161 offset, 1, ENC_NA);
1162 bvlc_result = tvb_get_uint8(tvb, offset);
1163 offset++;
1165 col_append_fstr(pinfo->cinfo, COL_INFO, " %s",
1166 val_to_str_const(bvlc_result, bscvlc_result_names, "unknown"));
1168 if(bvlc_result)
1170 proto_tree_add_item(subtree, hf_bscvlc_header_marker, tvb,
1171 offset, 1, ENC_NA);
1172 offset++;
1173 proto_tree_add_item(subtree, hf_bscvlc_error_class, tvb,
1174 offset, 2, ENC_NA);
1175 offset += 2;
1176 proto_tree_add_item(subtree, hf_bscvlc_error_code, tvb,
1177 offset, 2, ENC_NA);
1178 offset += 2;
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;
1184 break;
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;
1192 break;
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,
1197 offset, 1, ENC_NA);
1198 offset++;
1199 proto_tree_add_item(subtree, hf_bscvlc_accept_conns, tvb,
1200 offset, 1, ENC_NA);
1201 offset++;
1202 proto_tree_add_item(subtree, hf_bscvlc_max_bvlc_length, tvb,
1203 offset, 2, ENC_NA);
1204 offset += 2;
1205 proto_tree_add_item(subtree, hf_bscvlc_max_npdu_length, tvb,
1206 offset, 2, ENC_NA);
1207 offset += 2;
1208 break;
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,
1213 offset, 6, ENC_NA);
1214 offset += 6;
1215 proto_tree_add_item(subtree, hf_bscvlc_connect_uuid, tvb,
1216 offset, 16, ENC_NA);
1217 offset += 16;
1218 proto_tree_add_item(subtree, hf_bscvlc_max_bvlc_length, tvb,
1219 offset, 2, ENC_NA);
1220 offset += 2;
1221 proto_tree_add_item(subtree, hf_bscvlc_max_npdu_length, tvb,
1222 offset, 2, ENC_NA);
1223 offset += 2;
1224 break;
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,
1229 offset, 6, ENC_NA);
1230 offset += 6;
1231 proto_tree_add_item(subtree, hf_bscvlc_connect_uuid, tvb,
1232 offset, 16, ENC_NA);
1233 offset += 16;
1234 proto_tree_add_item(subtree, hf_bscvlc_max_bvlc_length, tvb,
1235 offset, 2, ENC_NA);
1236 offset += 2;
1237 proto_tree_add_item(subtree, hf_bscvlc_max_npdu_length, tvb,
1238 offset, 2, ENC_NA);
1239 offset += 2;
1240 break;
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,
1245 offset, 2, ENC_NA);
1246 offset += 2;
1247 proto_tree_add_item(subtree, hf_bscvlc_proprietary_opt_type, tvb,
1248 offset, 1, ENC_NA);
1249 offset++;
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;
1254 break;
1255 case 0x01: /* Encapsulated-NPDU */
1256 default:
1257 /* Here we assume additional payload belongs to upper layers and will be decoded later */
1258 break;
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);
1274 void
1275 proto_register_bvlc(void)
1277 static hf_register_info hf[] = {
1278 { &hf_bvlc_type,
1279 { "Type", "bvlc.type",
1280 FT_UINT8, BASE_HEX, VALS(bvlc_types), 0,
1281 NULL, HFILL }
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 }
1293 { &hf_bvlc_length,
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 }
1318 { &hf_bvlc_bdt_ip,
1319 { "IP", "bvlc.bdt_ip",
1320 FT_IPv4, BASE_NONE, NULL, 0,
1321 "BDT IP", HFILL }
1323 { &hf_bvlc_bdt_port,
1324 { "Port", "bvlc.bdt_port",
1325 FT_UINT16, BASE_DEC, NULL, 0,
1326 "BDT Port", HFILL }
1328 { &hf_bvlc_bdt_mask,
1329 { "Mask", "bvlc.bdt_mask",
1330 FT_BYTES, BASE_NONE, NULL, 0,
1331 "BDT Broadcast Distribution Mask", HFILL }
1333 { &hf_bvlc_reg_ttl,
1334 { "TTL", "bvlc.reg_ttl",
1335 FT_UINT16, BASE_DEC, NULL, 0,
1336 "Foreign Device Time To Live", HFILL }
1338 { &hf_bvlc_fdt_ip,
1339 { "IP", "bvlc.fdt_ip",
1340 FT_IPv4, BASE_NONE, NULL, 0,
1341 "FDT IP", HFILL }
1343 { &hf_bvlc_fdt_ipv6,
1344 { "IP", "bvlc.fdt_ipv6",
1345 FT_IPv6, BASE_NONE, NULL, 0,
1346 "FDT IP", HFILL }
1348 { &hf_bvlc_fdt_port,
1349 { "Port", "bvlc.fdt_port",
1350 FT_UINT16, BASE_DEC, NULL, 0,
1351 "FDT Port", HFILL }
1353 { &hf_bvlc_fdt_ttl,
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 }
1363 { &hf_bvlc_fwd_ip,
1364 { "IP", "bvlc.fwd_ip",
1365 FT_IPv4, BASE_NONE, NULL, 0,
1366 "FWD IP", HFILL }
1368 { &hf_bvlc_fwd_port,
1369 { "Port", "bvlc.fwd_port",
1370 FT_UINT16, BASE_DEC, NULL, 0,
1371 "FWD Port", HFILL }
1373 { &hf_bvlc_orig_source_addr,
1374 { "IP", "bvlc.orig_source_addr",
1375 FT_IPv6, BASE_NONE, NULL, 0,
1376 "ORIG IP", HFILL }
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[] = {
1386 &ett_bvlc,
1387 &ett_bdt,
1388 &ett_fdt,
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 }
1520 { &hf_bscvlc_uris,
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[] = {
1553 &ett_bscvlc,
1554 &ett_bscvlc_ctrl,
1555 &ett_bscvlc_hdr
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);
1578 void
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
1589 * Local variables:
1590 * c-basic-offset: 8
1591 * tab-width: 8
1592 * indent-tabs-mode: t
1593 * End:
1595 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
1596 * :indentSize=8:tabSize=8:noTabs=false: