1590 lines
50 KiB
C
1590 lines
50 KiB
C
/* packet-bvlc.c
|
|
* Routines for BACnet/IP (BVLL, BVLC) dissection
|
|
* Copyright 2001, Hartmut Mueller <hartmut@abmlinux.org>, FH Dortmund
|
|
*
|
|
* Wireshark - Network traffic analyzer
|
|
* By Gerald Combs <gerald@wireshark.org>
|
|
* Copyright 1998 Gerald Combs
|
|
*
|
|
* Copied from README.developer,v 1.23
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include <epan/packet.h>
|
|
#include "packet-bacnet.h"
|
|
|
|
void proto_register_bvlc(void);
|
|
void proto_reg_handoff_bvlc(void);
|
|
|
|
#define BVLC_UDP_PORT 0xBAC0
|
|
|
|
/* Network Layer Wrapper Control Information */
|
|
#define BAC_WRAPPER_CONTROL_NET 0x80
|
|
#define BAC_WRAPPER_MSG_ENCRYPED 0x40
|
|
#define BAC_WRAPPER_RESERVED 0x20
|
|
#define BAC_WRAPPER_AUTHD_PRESENT 0x10
|
|
#define BAC_WRAPPER_DO_NOT_UNWRAP 0x08
|
|
#define BAC_WRAPPER_DO_NOT_DECRPT 0x04
|
|
#define BAC_WRAPPER_NO_TRUST_SRC 0x02
|
|
#define BAC_WRAPPER_SECURE_BY_RTR 0x01
|
|
|
|
static int proto_bvlc = -1;
|
|
static int proto_bscvlc = -1;
|
|
static int hf_bvlc_type = -1;
|
|
static int hf_bvlc_function = -1;
|
|
static int hf_bvlc_ipv6_function = -1;
|
|
static int hf_bvlc_length = -1;
|
|
static int hf_bvlc_result_ip4 = -1;
|
|
static int hf_bvlc_result_ip6 = -1;
|
|
static int hf_bvlc_bdt_ip = -1;
|
|
static int hf_bvlc_bdt_mask = -1;
|
|
static int hf_bvlc_bdt_port = -1;
|
|
static int hf_bvlc_reg_ttl = -1;
|
|
static int hf_bvlc_fdt_ip = -1;
|
|
static int hf_bvlc_fdt_ipv6 = -1;
|
|
static int hf_bvlc_fdt_port = -1;
|
|
static int hf_bvlc_fdt_ttl = -1;
|
|
static int hf_bvlc_fdt_timeout = -1;
|
|
static int hf_bvlc_fwd_ip = -1;
|
|
static int hf_bvlc_fwd_port = -1;
|
|
static int hf_bvlc_virt_source = -1;
|
|
static int hf_bvlc_virt_dest = -1;
|
|
static int hf_bvlc_orig_source_addr = -1;
|
|
static int hf_bvlc_orig_source_port = -1;
|
|
static int hf_bscvlc_control = -1;
|
|
static int hf_bscvlc_control_data_option = -1;
|
|
static int hf_bscvlc_control_destination_option = -1;
|
|
static int hf_bscvlc_control_destination_address = -1;
|
|
static int hf_bscvlc_control_origin_address = -1;
|
|
static int hf_bscvlc_control_reserved = -1;
|
|
static int hf_bscvlc_header = -1;
|
|
static int hf_bscvlc_header_marker = -1;
|
|
static int hf_bscvlc_header_length = -1;
|
|
static int hf_bscvlc_header_data = -1;
|
|
static int hf_bscvlc_header_opt_type = -1;
|
|
static int hf_bscvlc_header_opt_data = -1;
|
|
static int hf_bscvlc_header_opt_must_understand = -1;
|
|
static int hf_bscvlc_header_opt_more = -1;
|
|
static int hf_bscvlc_vendor_id = -1;
|
|
static int hf_bscvlc_proprietary_opt_type = -1;
|
|
static int hf_bscvlc_proprietary_data = -1;
|
|
static int hf_bscvlc_hub_conn_state = -1;
|
|
static int hf_bscvlc_accept_conns = -1;
|
|
static int hf_bscvlc_max_bvlc_length = -1;
|
|
static int hf_bscvlc_max_npdu_length = -1;
|
|
static int hf_bscvlc_function = -1;
|
|
static int hf_bscvlc_result = -1;
|
|
static int hf_bscvlc_error_class = -1;
|
|
static int hf_bscvlc_error_code = -1;
|
|
static int hf_bscvlc_result_data = -1;
|
|
static int hf_bscvlc_uris = -1;
|
|
static int hf_bscvlc_msg_id = -1;
|
|
static int hf_bscvlc_orig_vmac = -1;
|
|
static int hf_bscvlc_dest_vmac = -1;
|
|
static int hf_bscvlc_connect_vmac = -1;
|
|
static int hf_bscvlc_connect_uuid = -1;
|
|
|
|
static dissector_table_t bvlc_dissector_table;
|
|
static dissector_table_t bscvlc_dissector_table;
|
|
static dissector_table_t bvlc_ipv6_dissector_table;
|
|
static dissector_handle_t bvlc_handle = NULL;
|
|
static dissector_handle_t bscvlc_handle = NULL;
|
|
|
|
static const value_string bvlc_function_names[] = {
|
|
{ 0x00, "BVLC-Result" },
|
|
{ 0x01, "Write-Broadcast-Distribution-Table" },
|
|
{ 0x02, "Read-Broadcast-Distribution-Table" },
|
|
{ 0x03, "Read-Broadcast-Distribution-Table-Ack" },
|
|
{ 0x04, "Forwarded-NPDU" },
|
|
{ 0x05, "Register-Foreign-Device" },
|
|
{ 0x06, "Read-Foreign-Device-Table" },
|
|
{ 0x07, "Read-Foreign-Device-Table-Ack" },
|
|
{ 0x08, "Delete-Foreign-Device-Table-Entry" },
|
|
{ 0x09, "Distribute-Broadcast-To-Network" },
|
|
{ 0x0a, "Original-Unicast-NPDU" },
|
|
{ 0x0b, "Original-Broadcast-NPDU" },
|
|
{ 0x0c, "Secured-BVLL" },
|
|
{ 0, NULL }
|
|
};
|
|
|
|
static const value_string bscvlc_function_names[] = {
|
|
{ 0x00, "BVLC-Result" },
|
|
{ 0x01, "Encapsulated-NPDU" },
|
|
{ 0x02, "Address-Resolution" },
|
|
{ 0x03, "Address-Resolution-ACK" },
|
|
{ 0x04, "Advertisement" },
|
|
{ 0x05, "Advertisement-Solicitation" },
|
|
{ 0x06, "Connect-Request" },
|
|
{ 0x07, "Connect-Accept" },
|
|
{ 0x08, "Disconnect-Request" },
|
|
{ 0x09, "Disconnect-ACK" },
|
|
{ 0x0A, "Heartbeat-Request" },
|
|
{ 0x0B, "Heartbeat-ACK" },
|
|
{ 0x0C, "Proprietary-Message" },
|
|
{ 0, NULL }
|
|
};
|
|
|
|
static const value_string bvlc_result_names[] = {
|
|
{ 0x00, "Successful completion" },
|
|
{ 0x10, "Write-Broadcast-Distribution-Table NAK" },
|
|
{ 0x20, "Read-Broadcast-Distribution-Table NAK" },
|
|
{ 0x30, "Register-Foreign-Device NAK" },
|
|
{ 0x40, "Read-Foreign-Device-Table NAK" },
|
|
{ 0x50, "Delete-Foreign-Device-Table-Entry NAK" },
|
|
{ 0x60, "Distribute-Broadcast-To-Network NAK" },
|
|
{ 0, NULL }
|
|
};
|
|
|
|
static const value_string bscvlc_result_names[] = {
|
|
{ 0x00, "Successful completion (ACK)" },
|
|
{ 0x01, "Completion failed (NAK)" },
|
|
{ 0, NULL }
|
|
};
|
|
|
|
static const value_string bvlc_ipv6_function_names[] = {
|
|
{ 0x00, "BVLC-Result", },
|
|
{ 0x01, "Original-Unicast-NPDU", },
|
|
{ 0x02, "Original-Broadcast-NPDU", },
|
|
{ 0x03, "Address-Resolution", },
|
|
{ 0x04, "Forwarded-Address-Resolution", },
|
|
{ 0x05, "Address-Resolution-ACK", },
|
|
{ 0x06, "Virtual-Address-Resolution", },
|
|
{ 0x07, "Virtual-Address-Resolution-ACK", },
|
|
{ 0x08, "Forwarded-NPDU", },
|
|
{ 0x09, "Register-Foreign-Device", },
|
|
{ 0x0A, "Delete-Foreign-Device-Table-Entry", },
|
|
{ 0x0B, "Secure-BVLL", },
|
|
{ 0x0C, "Distribute-Broadcast-To-Network", },
|
|
{ 0, NULL }
|
|
};
|
|
|
|
static const value_string bvlc_ipv6_result_names[] = {
|
|
{ 0x00, "Successful completion" },
|
|
{ 0x30, "Address-Resolution NAK" },
|
|
{ 0x60, "Virtual-Address-Resolution NAK" },
|
|
{ 0x90, "Register-Foreign-Device NAK" },
|
|
{ 0xA0, "Delete-Foreign-Device-Table-Entry NAK" },
|
|
{ 0xC0, "Distribute-Broadcast-To-Network NAK" },
|
|
{ 0, NULL }
|
|
};
|
|
|
|
static const value_string bscvlc_header_type_names[] = {
|
|
{ 0x01, "Secure Path" },
|
|
{ 0x1F, "Proprietary Header Option" },
|
|
{ 0, NULL }
|
|
};
|
|
|
|
static const value_string bscvlc_hub_conn_state_names[] = {
|
|
{ 0x00, "No hub connection" },
|
|
{ 0x01, "Connected to primary hub" },
|
|
{ 0x02, "Connected to failover hub" },
|
|
{ 0, NULL }
|
|
};
|
|
|
|
static const value_string bscvlc_hub_accept_conns_names[] = {
|
|
{ 0x00, "The node does not support accepting direct connections" },
|
|
{ 0x01, "The node supports accepting direct connections" },
|
|
{ 0, NULL }
|
|
};
|
|
|
|
static gint ett_bvlc = -1;
|
|
static gint ett_bscvlc = -1;
|
|
static gint ett_bscvlc_ctrl = -1;
|
|
static gint ett_bscvlc_hdr = -1;
|
|
static gint ett_bdt = -1;
|
|
static gint ett_fdt = -1;
|
|
|
|
#define BACNET_IP_ANNEX_J 0x81
|
|
#define BACNET_IPV6_ANNEX_U 0x82
|
|
|
|
static const value_string bvlc_types[] = {
|
|
{ BACNET_IP_ANNEX_J, "BACnet/IP (Annex J)" },
|
|
{ BACNET_IPV6_ANNEX_U, "BACnet/IPV6 (Annex U)" },
|
|
{ 0, NULL }
|
|
};
|
|
|
|
#define BSCVLC_CONTROL_DATA_OPTION 0x01
|
|
#define BSCVLC_CONTROL_DEST_OPTION 0x02
|
|
#define BSCVLC_CONTROL_DEST_ADDRESS 0x04
|
|
#define BSCVLC_CONTROL_ORIG_ADDRESS 0x08
|
|
#define BSCVLC_CONTROL_RESERVED 0xF0
|
|
|
|
static const true_false_string control_data_option_set_high = {
|
|
"Data Options field is present.",
|
|
"Data Options field is absent."
|
|
};
|
|
|
|
static const true_false_string control_destination_option_set_high = {
|
|
"Destination Options field is present.",
|
|
"Destination Options field is absent."
|
|
};
|
|
|
|
static const true_false_string control_destination_address_set_high = {
|
|
"Destination Virtual Address is present.",
|
|
"Destination Virtual Address is absent."
|
|
};
|
|
|
|
static const true_false_string control_orig_address_set_high = {
|
|
"Originating Virtual Address is present.",
|
|
"Originating Virtual Address is absent."
|
|
};
|
|
|
|
static const true_false_string control_reserved_set_high = {
|
|
"Shall be zero, but is not.",
|
|
"Shall be zero and is zero."
|
|
};
|
|
|
|
#define BSCVLC_HEADER_OPTION_TYPE 0x1F
|
|
#define BSCVLC_HEADER_OPTION_DATA 0x20
|
|
#define BSCVLC_HEADER_OPTION_MUST_UNDERSTAND 0x40
|
|
#define BSCVLC_HEADER_OPTION_MORE_OPTIONS 0x80
|
|
|
|
#define BSCVLC_HEADER_TYPE_SECURE_PATH 0x01
|
|
#define BSCVLC_HEADER_TYPE_PROPRIETARY 0x1F
|
|
|
|
|
|
static const true_false_string header_opt_data_set_high = {
|
|
"The 'Header Length' and 'Header Data' fields are present.",
|
|
"The 'Header Length' and 'Header Data' fields are absent."
|
|
};
|
|
|
|
static const true_false_string header_opt_must_understand_set_high = {
|
|
"This header option must be understood for consuming the message.",
|
|
"This header option can be ignored if not understood."
|
|
};
|
|
|
|
static const true_false_string header_opt_more_set_high = {
|
|
"Another header option follows in the current header option list.",
|
|
"This is the last header option in the current header option list."
|
|
};
|
|
|
|
static const value_string
|
|
BACnetErrorClass [] = {
|
|
{ 0, "device" },
|
|
{ 1, "object" },
|
|
{ 2, "property" },
|
|
{ 3, "resources" },
|
|
{ 4, "security" },
|
|
{ 5, "services" },
|
|
{ 6, "vt" },
|
|
{ 7, "communication" },
|
|
{ 0, NULL }
|
|
/* Enumerated values 0-63 are reserved for definition by ASHRAE.
|
|
Enumerated values64-65535 may be used by others subject to
|
|
the procedures and constraints described in Clause 23. */
|
|
};
|
|
|
|
static const value_string
|
|
BACnetErrorCode[] = {
|
|
{ 0, "other"},
|
|
{ 1, "authentication-failed"},
|
|
{ 2, "configuration-in-progress"},
|
|
{ 3, "device-busy"},
|
|
{ 4, "dynamic-creation-not-supported"},
|
|
{ 5, "file-access-denied"},
|
|
{ 6, "incompatible-security-levels"},
|
|
{ 7, "inconsistent-parameters"},
|
|
{ 8, "inconsistent-selection-criterion"},
|
|
{ 9, "invalid-data-type"},
|
|
{ 10, "invalid-file-access-method"},
|
|
{ 11, "invalid-file-start-position"},
|
|
{ 12, "invalid-operator-name"},
|
|
{ 13, "invalid-parameter-data-type"},
|
|
{ 14, "invalid-time-stamp"},
|
|
{ 15, "key-generation-error"},
|
|
{ 16, "missing-required-parameter"},
|
|
{ 17, "no-objects-of-specified-type"},
|
|
{ 18, "no-space-for-object"},
|
|
{ 19, "no-space-to-add-list-element"},
|
|
{ 20, "no-space-to-write-property"},
|
|
{ 21, "no-vt-sessions-available"},
|
|
{ 22, "property-is-not-a-list"},
|
|
{ 23, "object-deletion-not-permitted"},
|
|
{ 24, "object-identifier-already-exists"},
|
|
{ 25, "operational-problem"},
|
|
{ 26, "password-failure"},
|
|
{ 27, "read-access-denied"},
|
|
{ 28, "security-not-supported"},
|
|
{ 29, "service-request-denied"},
|
|
{ 30, "timeout"},
|
|
{ 31, "unknown-object"},
|
|
{ 32, "unknown-property"},
|
|
{ 33, "removed enumeration"},
|
|
{ 34, "unknown-vt-class"},
|
|
{ 35, "unknown-vt-session"},
|
|
{ 36, "unsupported-object-type"},
|
|
{ 37, "value-out-of-range"},
|
|
{ 38, "vt-session-already-closed"},
|
|
{ 39, "vt-session-termination-failure"},
|
|
{ 40, "write-access-denied"},
|
|
{ 41, "character-set-not-supported"},
|
|
{ 42, "invalid-array-index"},
|
|
{ 43, "cov-subscription-failed"},
|
|
{ 44, "not-cov-property"},
|
|
{ 45, "optional-functionality-not-supported"},
|
|
{ 46, "invalid-configuration-data"},
|
|
{ 47, "datatype-not-supported"},
|
|
{ 48, "duplicate-name"},
|
|
{ 49, "duplicate-object-id"},
|
|
{ 50, "property-is-not-an-array"},
|
|
{ 51, "abort - buffer - overflow" },
|
|
{ 52, "abort - invalid - apdu - in - this - state" },
|
|
{ 53, "abort - preempted - by - higher - priority - task" },
|
|
{ 54, "abort - segmentation - not - supported" },
|
|
{ 55, "abort - proprietary" },
|
|
{ 56, "abort - other" },
|
|
{ 57, "reject - invalid - tag" },
|
|
{ 58, "reject - network - down" },
|
|
{ 59, "reject - buffer - overflow" },
|
|
{ 60, "reject - inconsistent - parameters" },
|
|
{ 61, "reject - invalid - parameter - data - type" },
|
|
{ 62, "reject - invalid - tag" },
|
|
{ 63, "reject - missing - required - parameter" },
|
|
{ 64, "reject - parameter - out - of - range" },
|
|
{ 65, "reject - too - many - arguments" },
|
|
{ 66, "reject - undefined - enumeration" },
|
|
{ 67, "reject - unrecognized - service" },
|
|
{ 68, "reject - proprietary" },
|
|
{ 69, "reject - other" },
|
|
{ 70, "unknown - device" },
|
|
{ 71, "unknown - route" },
|
|
{ 72, "value - not - initialized" },
|
|
{ 73, "invalid-event-state"},
|
|
{ 74, "no-alarm-configured"},
|
|
{ 75, "log-buffer-full"},
|
|
{ 76, "logged-value-purged"},
|
|
{ 77, "no-property-specified"},
|
|
{ 78, "not-configured-for-triggered-logging"},
|
|
{ 79, "unknown-subscription"},
|
|
{ 80, "parameter-out-of-range"},
|
|
{ 81, "list-element-not-found"},
|
|
{ 82, "busy"},
|
|
{ 83, "communication-disabled"},
|
|
{ 84, "success"},
|
|
{ 85, "access-denied"},
|
|
{ 86, "bad-destination-address"},
|
|
{ 87, "bad-destination-device-id"},
|
|
{ 88, "bad-signature"},
|
|
{ 89, "bad-source-address"},
|
|
{ 90, "bad-timestamp"},
|
|
{ 91, "cannot-use-key"},
|
|
{ 92, "cannot-verify-message-id"},
|
|
{ 93, "correct-key-revision"},
|
|
{ 94, "destination-device-id-required"},
|
|
{ 95, "duplicate-message"},
|
|
{ 96, "encryption-not-configured"},
|
|
{ 97, "encryption-required"},
|
|
{ 98, "incorrect-key"},
|
|
{ 99, "invalid-key-data"},
|
|
{ 100, "key-update-in-progress"},
|
|
{ 101, "malformed-message"},
|
|
{ 102, "not-key-server"},
|
|
{ 103, "security-not-configured"},
|
|
{ 104, "source-security-required"},
|
|
{ 105, "too-many-keys"},
|
|
{ 106, "unknown-authentication-type"},
|
|
{ 107, "unknown-key"},
|
|
{ 108, "unknown-key-revision"},
|
|
{ 109, "unknown-source-message"},
|
|
{ 110, "not-router-to-dnet"},
|
|
{ 111, "router-busy"},
|
|
{ 112, "unknown-network-message"},
|
|
{ 113, "message-too-long"},
|
|
{ 114, "security-error"},
|
|
{ 115, "addressing-error"},
|
|
{ 116, "write-bdt-failed"},
|
|
{ 117, "read-bdt-failed"},
|
|
{ 118, "register-foreign-device-failed"},
|
|
{ 119, "read-fdt-failed"},
|
|
{ 120, "delete-fdt-entry-failed"},
|
|
{ 121, "distribute-broadcast-failed"},
|
|
{ 122, "unknown-file-size"},
|
|
{ 123, "abort-apdu-too-long"},
|
|
{ 124, "abort-application-exceeded-reply-time"},
|
|
{ 125, "abort-out-of-resources"},
|
|
{ 126, "abort-tsm-timeout"},
|
|
{ 127, "abort-window-size-out-of-range"},
|
|
{ 128, "file-full"},
|
|
{ 129, "inconsistent-configuration"},
|
|
{ 130, "inconsistent-object-type"},
|
|
{ 131, "internal-error"},
|
|
{ 132, "not-configured"},
|
|
{ 133, "out-of-memory"},
|
|
{ 134, "value-too-long"},
|
|
{ 135, "abort-insufficient-security"},
|
|
{ 136, "abort-security-error"},
|
|
{ 137, "duplicate-entry"},
|
|
{ 138, "invalid-value-in-this-state"},
|
|
{ 139, "invalid-operation-in-this-state"},
|
|
{ 140, "list-item-not-numbered"},
|
|
{ 141, "list-item-not-timestamped"},
|
|
{ 142, "invalid-data-encoding"},
|
|
{ 143, "bvlc-function-unknown"},
|
|
{ 144, "bvlc-proprietary-function-unknown"},
|
|
{ 145, "header-encoding-error"},
|
|
{ 146, "header-not-understood"},
|
|
{ 147, "message-incomplete"},
|
|
{ 148, "not-a-bacnet-sc-hub"},
|
|
{ 149, "payload-expected"},
|
|
{ 150, "unexpected-data"},
|
|
{ 151, "node-duplicate-vmac"},
|
|
{ 152, "http-unexpected-response-code"},
|
|
{ 153, "http-no-upgrade"},
|
|
{ 154, "http-resource-not-local"},
|
|
{ 155, "http-proxy-authentication-failed"},
|
|
{ 156, "http-response-timeout"},
|
|
{ 157, "http-response-syntax-error"},
|
|
{ 158, "http-response-value-error"},
|
|
{ 159, "http-response-missing-header"},
|
|
{ 160, "http-websocket-header-error"},
|
|
{ 161, "http-upgrade-required"},
|
|
{ 162, "http-upgrade-error"},
|
|
{ 163, "http-temporary-unavailable"},
|
|
{ 164, "http-not-a-server"},
|
|
{ 165, "http-error"},
|
|
{ 166, "websocket-scheme-not-supported"},
|
|
{ 167, "websocket-unknown-control-message"},
|
|
{ 168, "websocket-close-error"},
|
|
{ 169, "websocket-closed-by-peer"},
|
|
{ 170, "websocket-endpoint-leaves"},
|
|
{ 171, "websocket-protocol-error"},
|
|
{ 172, "websocket-data-not-accepted"},
|
|
{ 173, "websocket-closed-abnormally"},
|
|
{ 174, "websocket-data-inconsistent"},
|
|
{ 175, "websocket-data-against-policy"},
|
|
{ 176, "websocket-frame-too-long"},
|
|
{ 177, "websocket-extension-missing"},
|
|
{ 178, "websocket-request-unavailable"},
|
|
{ 179, "websocket-error"},
|
|
{ 180, "tls-client-certificate-error"},
|
|
{ 181, "tls-server-certificate-error"},
|
|
{ 182, "tls-client-authentication-failed"},
|
|
{ 183, "tls-server-authentication-failed"},
|
|
{ 184, "tls-client-certificate-expired"},
|
|
{ 185, "tls-server-certificate-expired"},
|
|
{ 186, "tls-client-certificate-revoked"},
|
|
{ 187, "tls-server-certificate-revoked"},
|
|
{ 188, "tls-error"},
|
|
{ 189, "dns-unavailable"},
|
|
{ 190, "dns-name-resolution-failed"},
|
|
{ 191, "dns-resolver-failure"},
|
|
{ 192, "dns-error"},
|
|
{ 193, "tcp-connect-timeout"},
|
|
{ 194, "tcp-connection-refused"},
|
|
{ 195, "tcp-closed-by-local"},
|
|
{ 196, "tcp-closed-other"},
|
|
{ 197, "tcp-error"},
|
|
{ 198, "ip-address-not-reachable"},
|
|
{ 199, "ip-error"},
|
|
{ 0, NULL}
|
|
/* Enumerated values 0-255 are reserved for definition by ASHRAE.
|
|
Enumerated values 256-65535 may be used by others subject to the
|
|
procedures and constraints described in Clause 23. */
|
|
};
|
|
|
|
static int * const bscvlc_control_flags[] = {
|
|
&hf_bscvlc_control_data_option,
|
|
&hf_bscvlc_control_destination_option,
|
|
&hf_bscvlc_control_destination_address,
|
|
&hf_bscvlc_control_origin_address,
|
|
&hf_bscvlc_control_reserved,
|
|
NULL
|
|
};
|
|
|
|
static int * const bscvlc_header_flags[] = {
|
|
&hf_bscvlc_header_opt_type,
|
|
&hf_bscvlc_header_opt_data,
|
|
&hf_bscvlc_header_opt_must_understand,
|
|
&hf_bscvlc_header_opt_more,
|
|
NULL
|
|
};
|
|
|
|
static int
|
|
dissect_ipv4_bvlc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
|
|
{
|
|
|
|
proto_item *ti;
|
|
proto_item *ti_bdt;
|
|
proto_item *ti_fdt;
|
|
proto_tree *bvlc_tree;
|
|
proto_tree *bdt_tree; /* Broadcast Distribution Table */
|
|
proto_tree *fdt_tree; /* Foreign Device Table */
|
|
|
|
gint offset;
|
|
guint8 bvlc_type;
|
|
guint8 bvlc_function;
|
|
guint16 bvlc_length;
|
|
guint16 packet_length;
|
|
guint npdu_length;
|
|
guint length_remaining;
|
|
tvbuff_t *next_tvb;
|
|
|
|
offset = 0;
|
|
|
|
bvlc_type = tvb_get_guint8(tvb, offset);
|
|
bvlc_function = tvb_get_guint8(tvb, offset + 1);
|
|
packet_length = tvb_get_ntohs(tvb, offset + 2);
|
|
length_remaining = tvb_reported_length_remaining(tvb, offset);
|
|
|
|
if (bvlc_function > 0x08) {
|
|
/* We have a constant header length of BVLC of 4 in every
|
|
* BVLC-packet forewarding an NPDU. Beware: Changes in the
|
|
* BACnet-IP-standard may break this.
|
|
*/
|
|
bvlc_length = 4;
|
|
} else if (bvlc_function == 0x04) {
|
|
/* 4 Bytes + 6 Bytes for B/IP Address of Originating Device */
|
|
bvlc_length = 10;
|
|
} else {
|
|
/* BVLC-packets with function below 0x09 contain
|
|
* routing-level data (e.g. Broadcast Distribution)
|
|
* but no NPDU for BACnet, so bvlc_length goes up to the end
|
|
* of the captured frame.
|
|
*/
|
|
bvlc_length = packet_length;
|
|
}
|
|
|
|
if (bvlc_length < 4 || bvlc_length > packet_length) {
|
|
return 0; /* reject */
|
|
}
|
|
|
|
/* Put the BVLC Type in the info column */
|
|
col_append_fstr(pinfo->cinfo, COL_INFO, " BVLC Function %s ",
|
|
val_to_str_const(bvlc_function, bvlc_function_names, "unknown"));
|
|
|
|
ti = proto_tree_add_item(tree, proto_bvlc, tvb, 0, bvlc_length, ENC_NA);
|
|
bvlc_tree = proto_item_add_subtree(ti, ett_bvlc);
|
|
proto_tree_add_uint(bvlc_tree, hf_bvlc_type, tvb, offset, 1,
|
|
bvlc_type);
|
|
offset++;
|
|
proto_tree_add_uint(bvlc_tree, hf_bvlc_function, tvb,
|
|
offset, 1, bvlc_function);
|
|
offset++;
|
|
if (length_remaining != packet_length)
|
|
proto_tree_add_uint_format_value(bvlc_tree, hf_bvlc_length, tvb, offset,
|
|
2, bvlc_length,
|
|
"%d of %d bytes (invalid length - expected %d bytes)",
|
|
bvlc_length, packet_length, length_remaining);
|
|
else
|
|
proto_tree_add_uint_format_value(bvlc_tree, hf_bvlc_length, tvb, offset,
|
|
2, bvlc_length, "%d of %d bytes BACnet packet length",
|
|
bvlc_length, packet_length);
|
|
offset += 2;
|
|
switch (bvlc_function) {
|
|
case 0x00: /* BVLC-Result */
|
|
/* I don't know why the result code is encoded in 4 nibbles,
|
|
* but only using one: 0x00r0. Shifting left 4 bits.
|
|
*/
|
|
/* We should bitmask the result correctly when we have a
|
|
* packet to dissect, see README.developer, 1.6.2, FID */
|
|
proto_tree_add_item(bvlc_tree, hf_bvlc_result_ip4, tvb,
|
|
offset, 2, ENC_BIG_ENDIAN);
|
|
/*offset += 2;*/
|
|
break;
|
|
case 0x01: /* Write-Broadcast-Distribution-Table */
|
|
case 0x03: /* Read-Broadcast-Distribution-Table-Ack */
|
|
/* List of BDT Entries: N*10-octet */
|
|
ti_bdt = proto_tree_add_item(bvlc_tree, proto_bvlc, tvb,
|
|
offset, bvlc_length-4, ENC_NA);
|
|
bdt_tree = proto_item_add_subtree(ti_bdt, ett_bdt);
|
|
/* List of BDT Entries: N*10-octet */
|
|
while ((bvlc_length - offset) > 9) {
|
|
proto_tree_add_item(bdt_tree, hf_bvlc_bdt_ip,
|
|
tvb, offset, 4, ENC_BIG_ENDIAN);
|
|
offset += 4;
|
|
proto_tree_add_item(bdt_tree, hf_bvlc_bdt_port,
|
|
tvb, offset, 2, ENC_BIG_ENDIAN);
|
|
offset += 2;
|
|
proto_tree_add_item(bdt_tree,
|
|
hf_bvlc_bdt_mask, tvb, offset, 4,
|
|
ENC_NA);
|
|
offset += 4;
|
|
}
|
|
/* We check this if we get a BDT-packet somewhere */
|
|
break;
|
|
case 0x02: /* Read-Broadcast-Distribution-Table */
|
|
/* nothing to do here */
|
|
break;
|
|
case 0x05: /* Register-Foreign-Device */
|
|
/* Time-to-Live 2-octets T, Time-to-Live T, in seconds */
|
|
proto_tree_add_item(bvlc_tree, hf_bvlc_reg_ttl,
|
|
tvb, offset, 2, ENC_BIG_ENDIAN);
|
|
/*offset += 2;*/
|
|
break;
|
|
case 0x06: /* Read-Foreign-Device-Table */
|
|
/* nothing to do here */
|
|
break;
|
|
case 0x07: /* Read-Foreign-Device-Table-Ack */
|
|
/* List of FDT Entries: N*10-octet */
|
|
/* N indicates the number of entries in the FDT whose
|
|
* contents are being returned. Each returned entry
|
|
* consists of the 6-octet B/IP address of the registrant;
|
|
* the 2-octet Time-to-Live value supplied at the time of
|
|
* registration; and a 2-octet value representing the
|
|
* number of seconds remaining before the BBMD will purge
|
|
* the registrant's FDT entry if no re-registration occurs.
|
|
*/
|
|
ti_fdt = proto_tree_add_item(bvlc_tree, proto_bvlc, tvb,
|
|
offset, bvlc_length -4, ENC_NA);
|
|
fdt_tree = proto_item_add_subtree(ti_fdt, ett_fdt);
|
|
/* List of FDT Entries: N*10-octet */
|
|
while ((bvlc_length - offset) > 9) {
|
|
proto_tree_add_item(fdt_tree, hf_bvlc_fdt_ip,
|
|
tvb, offset, 4, ENC_BIG_ENDIAN);
|
|
offset += 4;
|
|
proto_tree_add_item(fdt_tree, hf_bvlc_fdt_port,
|
|
tvb, offset, 2, ENC_BIG_ENDIAN);
|
|
offset += 2;
|
|
proto_tree_add_item(fdt_tree,
|
|
hf_bvlc_fdt_ttl, tvb, offset, 2,
|
|
ENC_BIG_ENDIAN);
|
|
offset += 2;
|
|
proto_tree_add_item(fdt_tree,
|
|
hf_bvlc_fdt_timeout, tvb, offset, 2,
|
|
ENC_BIG_ENDIAN);
|
|
offset += 2;
|
|
}
|
|
/* We check this if we get a FDT-packet somewhere */
|
|
break;
|
|
case 0x08: /* Delete-Foreign-Device-Table-Entry */
|
|
/* FDT Entry: 6-octets */
|
|
proto_tree_add_item(bvlc_tree, hf_bvlc_fdt_ip,
|
|
tvb, offset, 4, ENC_BIG_ENDIAN);
|
|
offset += 4;
|
|
proto_tree_add_item(bvlc_tree, hf_bvlc_fdt_port,
|
|
tvb, offset, 2, ENC_BIG_ENDIAN);
|
|
/*offset += 2;*/
|
|
break;
|
|
case 0x0C: /* Secure-BVLL */
|
|
offset = bacnet_dissect_sec_wrapper(tvb, pinfo, tree, offset, NULL);
|
|
if (offset < 0) {
|
|
call_data_dissector(tvb, pinfo, tree);
|
|
return tvb_captured_length(tvb);
|
|
}
|
|
dissect_ipv4_bvlc(tvb, pinfo, tree, data);
|
|
break;
|
|
/* We check this if we get a FDT-packet somewhere */
|
|
case 0x04: /* Forwarded-NPDU
|
|
* Why is this 0x04? It would have been a better
|
|
* idea to append all forewarded NPDUs at the
|
|
* end of the function table in the B/IP-standard!
|
|
*/
|
|
/* proto_tree_add_bytes_format(); */
|
|
proto_tree_add_item(bvlc_tree, hf_bvlc_fwd_ip,
|
|
tvb, offset, 4, ENC_BIG_ENDIAN);
|
|
offset += 4;
|
|
proto_tree_add_item(bvlc_tree, hf_bvlc_fwd_port,
|
|
tvb, offset, 2, ENC_BIG_ENDIAN);
|
|
/*offset += 2;*/
|
|
break;
|
|
default:
|
|
/* Distribute-Broadcast-To-Network
|
|
* Original-Unicast-NPDU
|
|
* Original-Broadcast-NPDU
|
|
* Going to the next dissector...
|
|
*/
|
|
break;
|
|
}
|
|
|
|
/* Ok, no routing information BVLC packet. Dissect as
|
|
* BACnet NPDU
|
|
*/
|
|
npdu_length = packet_length - bvlc_length;
|
|
next_tvb = tvb_new_subset_length_caplen(tvb, bvlc_length, -1, npdu_length);
|
|
/* Code from Guy Harris */
|
|
if (!dissector_try_uint(bvlc_dissector_table,
|
|
bvlc_function, next_tvb, pinfo, tree)) {
|
|
/* Unknown function - dissect the paylod as data */
|
|
call_data_dissector(next_tvb, pinfo, tree);
|
|
}
|
|
return tvb_reported_length(tvb);
|
|
}
|
|
|
|
static int
|
|
dissect_ipv6_bvlc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
|
|
{
|
|
proto_item *ti;
|
|
proto_tree *bvlc_tree;
|
|
|
|
gint offset;
|
|
guint8 bvlc_type;
|
|
guint8 bvlc_function;
|
|
guint16 bvlc_length = 0;
|
|
guint16 packet_length;
|
|
guint npdu_length;
|
|
guint length_remaining;
|
|
tvbuff_t *next_tvb;
|
|
|
|
offset = 0;
|
|
|
|
bvlc_type = tvb_get_guint8(tvb, offset);
|
|
bvlc_function = tvb_get_guint8(tvb, offset + 1);
|
|
packet_length = tvb_get_ntohs(tvb, offset + 2);
|
|
length_remaining = tvb_reported_length_remaining(tvb, offset);
|
|
|
|
switch (bvlc_function) {
|
|
case 0x00:
|
|
case 0x09:
|
|
bvlc_length = 9;
|
|
break;
|
|
case 0x01:
|
|
bvlc_length = 10;
|
|
break;
|
|
case 0x02:
|
|
case 0x06:
|
|
case 0x0C:
|
|
bvlc_length = 7;
|
|
break;
|
|
case 0x03:
|
|
case 0x05:
|
|
case 0x07:
|
|
bvlc_length = 10;
|
|
break;
|
|
case 0x04:
|
|
bvlc_length = 28;
|
|
break;
|
|
case 0x08:
|
|
case 0x0A:
|
|
bvlc_length = 25;
|
|
break;
|
|
case 0x0B:
|
|
bvlc_length = 4;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (bvlc_length > packet_length) {
|
|
return 0; /* reject */
|
|
}
|
|
|
|
/* Put the BVLC Type in the info column */
|
|
col_append_fstr(pinfo->cinfo, COL_INFO, " BVLC Function %s ",
|
|
val_to_str_const(bvlc_function, bvlc_function_names, "unknown"));
|
|
|
|
ti = proto_tree_add_item(tree, proto_bvlc, tvb, 0,
|
|
bvlc_length, ENC_NA);
|
|
bvlc_tree = proto_item_add_subtree(ti, ett_bvlc);
|
|
/* add the BVLC type */
|
|
proto_tree_add_uint(bvlc_tree, hf_bvlc_type, tvb, offset, 1,
|
|
bvlc_type);
|
|
offset++;
|
|
/* add the BVLC function */
|
|
proto_tree_add_uint(bvlc_tree, hf_bvlc_ipv6_function, tvb,
|
|
offset, 1, bvlc_function);
|
|
offset++;
|
|
/* add the length information */
|
|
if (length_remaining != packet_length)
|
|
proto_tree_add_uint_format_value(bvlc_tree, hf_bvlc_length, tvb, offset,
|
|
2, bvlc_length,
|
|
"%d of %d bytes (invalid length - expected %d bytes)",
|
|
bvlc_length, packet_length, length_remaining);
|
|
else
|
|
proto_tree_add_uint_format_value(bvlc_tree, hf_bvlc_length, tvb, offset,
|
|
2, bvlc_length,
|
|
"%d of %d bytes BACnet packet length",
|
|
bvlc_length, packet_length);
|
|
offset += 2;
|
|
|
|
/* add the optional present virtual source address */
|
|
if (bvlc_function != 0x0B) {
|
|
proto_tree_add_item(bvlc_tree, hf_bvlc_virt_source, tvb, offset,
|
|
3, ENC_BIG_ENDIAN);
|
|
offset += 3;
|
|
}
|
|
|
|
/* handle additional function parameters */
|
|
switch (bvlc_function) {
|
|
case 0x00: /* BVLC-Result */
|
|
proto_tree_add_item(bvlc_tree, hf_bvlc_result_ip6, tvb,
|
|
offset, 2, ENC_BIG_ENDIAN);
|
|
offset += 2;
|
|
break;
|
|
case 0x01: /* Original-Unicast-NPDU */
|
|
case 0x03: /* Address-Resolution */
|
|
case 0x05: /* Address-Resolution-ACK */
|
|
case 0x07: /* Virtual-Address-Resolution-ACK */
|
|
proto_tree_add_item(bvlc_tree, hf_bvlc_virt_dest, tvb, offset,
|
|
3, ENC_BIG_ENDIAN);
|
|
offset += 3;
|
|
break;
|
|
case 0x04: /* Forwarded-Address-Resolution */
|
|
proto_tree_add_item(bvlc_tree, hf_bvlc_virt_dest, tvb, offset,
|
|
3, ENC_BIG_ENDIAN);
|
|
offset += 3;
|
|
proto_tree_add_item(bvlc_tree, hf_bvlc_orig_source_addr,
|
|
tvb, offset, 16, ENC_NA);
|
|
offset += 16;
|
|
proto_tree_add_item(bvlc_tree, hf_bvlc_orig_source_port,
|
|
tvb, offset, 2, ENC_BIG_ENDIAN);
|
|
offset += 2;
|
|
break;
|
|
case 0x08: /* Forwarded-NPDU */
|
|
proto_tree_add_item(bvlc_tree, hf_bvlc_orig_source_addr,
|
|
tvb, offset, 16, ENC_NA);
|
|
offset += 16;
|
|
proto_tree_add_item(bvlc_tree, hf_bvlc_orig_source_port,
|
|
tvb, offset, 2, ENC_BIG_ENDIAN);
|
|
offset += 2;
|
|
break;
|
|
case 0x06: /* Virtual-Address-Resolution */
|
|
break;
|
|
case 0x09: /* Register-Foreign-Device */
|
|
proto_tree_add_item(bvlc_tree, hf_bvlc_reg_ttl,
|
|
tvb, offset, 2, ENC_BIG_ENDIAN);
|
|
offset += 2;
|
|
break;
|
|
case 0x0A: /* Delete-Foreign-Device-Table-Entry */
|
|
proto_tree_add_item(bvlc_tree, hf_bvlc_fdt_ipv6,
|
|
tvb, offset, 16, ENC_NA);
|
|
offset += 16;
|
|
proto_tree_add_item(bvlc_tree, hf_bvlc_fdt_port,
|
|
tvb, offset, 2, ENC_BIG_ENDIAN);
|
|
offset += 2;
|
|
break;
|
|
case 0x0B: /* Secure-BVLL */
|
|
offset = bacnet_dissect_sec_wrapper(tvb, pinfo, tree, offset, NULL);
|
|
if (offset < 0) {
|
|
call_data_dissector(tvb, pinfo, tree);
|
|
return tvb_captured_length(tvb);
|
|
}
|
|
dissect_ipv6_bvlc(tvb, pinfo, tree, data);
|
|
break;
|
|
case 0x02: /* Original-Broadcast-NPDU */
|
|
case 0x0c: /* Distribute-Broadcast-To-Network */
|
|
default:
|
|
/*
|
|
* Going to the next dissector...
|
|
*/
|
|
break;
|
|
}
|
|
|
|
/* Ok, no routing information BVLC packet. Dissect as
|
|
* BACnet NPDU
|
|
*/
|
|
npdu_length = packet_length - offset;
|
|
next_tvb = tvb_new_subset_length_caplen(tvb, offset, -1, npdu_length);
|
|
/* Code from Guy Harris */
|
|
if ( ! dissector_try_uint(bvlc_ipv6_dissector_table,
|
|
bvlc_function, next_tvb, pinfo, tree)) {
|
|
/* Unknown function - dissect the paylod as data */
|
|
call_data_dissector(next_tvb, pinfo, tree);
|
|
}
|
|
|
|
return tvb_reported_length(tvb);
|
|
}
|
|
|
|
static int
|
|
dissect_bvlc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
|
|
{
|
|
guint8 bvlc_type;
|
|
guint ret = 0;
|
|
|
|
bvlc_type = tvb_get_guint8(tvb, 0);
|
|
|
|
/*
|
|
* Simple sanity check - make sure the type is one we know about.
|
|
*/
|
|
if (try_val_to_str(bvlc_type, bvlc_types) == NULL)
|
|
return 0;
|
|
|
|
col_set_str(pinfo->cinfo, COL_PROTOCOL, "BVLC");
|
|
col_set_str(pinfo->cinfo, COL_INFO, "BACnet Virtual Link Control");
|
|
|
|
switch (bvlc_type)
|
|
{
|
|
case BACNET_IP_ANNEX_J:
|
|
ret = dissect_ipv4_bvlc(tvb, pinfo, tree, data);
|
|
break;
|
|
case BACNET_IPV6_ANNEX_U:
|
|
ret = dissect_ipv6_bvlc(tvb, pinfo, tree, data);
|
|
break;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int
|
|
dissect_bscvlc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
|
|
{
|
|
proto_item *ti;
|
|
proto_tree *bvlc_tree;
|
|
tvbuff_t *next_tvb;
|
|
gint offset;
|
|
gint start;
|
|
gint bvlc_length;
|
|
gint packet_length;
|
|
gint npdu_length;
|
|
guint8 bvlc_function;
|
|
guint8 bvlc_control;
|
|
guint8 bvlc_result;
|
|
guint8 hdr_byte;
|
|
gint8 mac_buffer[16];
|
|
guint bvlc_message_id;
|
|
guint idx;
|
|
gboolean bMoreFlag;
|
|
gboolean bDataFlag;
|
|
proto_tree *subtree;
|
|
|
|
/* Calculate length of BSCVLC block to get remaining payload length */
|
|
offset = 0;
|
|
|
|
packet_length = tvb_reported_length_remaining(tvb, offset);
|
|
if(packet_length < 4)
|
|
return 0; /* reject */
|
|
|
|
/* Fix part of the header first */
|
|
bvlc_function = tvb_get_guint8(tvb, offset++);
|
|
bvlc_control = tvb_get_guint8(tvb, offset++);
|
|
bvlc_message_id = tvb_get_guint16(tvb, offset, ENC_BIG_ENDIAN);
|
|
offset += 2;
|
|
|
|
/* Variable part of the header next */
|
|
bvlc_length = offset;
|
|
|
|
if ((bvlc_control & BSCVLC_CONTROL_ORIG_ADDRESS) != 0)
|
|
bvlc_length += 6;
|
|
|
|
if ((bvlc_control & BSCVLC_CONTROL_DEST_ADDRESS) != 0)
|
|
bvlc_length += 6;
|
|
|
|
if ((bvlc_control & BSCVLC_CONTROL_DEST_OPTION) != 0)
|
|
{
|
|
bMoreFlag = TRUE;
|
|
|
|
while(tvb_reported_length_remaining(tvb, bvlc_length) > 0 &&
|
|
(hdr_byte = tvb_get_guint8(tvb, bvlc_length)) != 0 && bMoreFlag)
|
|
{
|
|
/* get flags and type... */
|
|
bMoreFlag= (hdr_byte & BSCVLC_HEADER_OPTION_MORE_OPTIONS);
|
|
bDataFlag= (hdr_byte & BSCVLC_HEADER_OPTION_DATA);
|
|
bvlc_length++;
|
|
|
|
if(bDataFlag)
|
|
{
|
|
npdu_length = (gint)(tvb_get_guint8(tvb, bvlc_length++) << 8);
|
|
npdu_length += (gint)tvb_get_guint8(tvb, bvlc_length++);
|
|
bvlc_length += npdu_length;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((bvlc_control & BSCVLC_CONTROL_DATA_OPTION) != 0)
|
|
{
|
|
bMoreFlag = TRUE;
|
|
|
|
while(tvb_reported_length_remaining(tvb, bvlc_length) > 0 &&
|
|
(hdr_byte = tvb_get_guint8(tvb, bvlc_length)) != 0 && bMoreFlag)
|
|
{
|
|
/* get flags and type... */
|
|
bMoreFlag= (hdr_byte & BSCVLC_HEADER_OPTION_MORE_OPTIONS);
|
|
bDataFlag= (hdr_byte & BSCVLC_HEADER_OPTION_DATA);
|
|
bvlc_length++;
|
|
|
|
if(bDataFlag)
|
|
{
|
|
npdu_length = (gint)(tvb_get_guint8(tvb, bvlc_length++) << 8);
|
|
npdu_length += (gint)tvb_get_guint8(tvb, bvlc_length++);
|
|
bvlc_length += npdu_length;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Now add the BSCVLC payload size for specified function */
|
|
switch (bvlc_function)
|
|
{
|
|
case 0x00: /* BVLC-Result */
|
|
case 0x03: /* Address-Resolution-ACK */
|
|
case 0x0C: /* Proprietary-Message */
|
|
/* complete packet length because of optional present variable length error data
|
|
but no length encoded for it in the structure of this frame */
|
|
bvlc_length = packet_length;
|
|
break;
|
|
case 0x02: /* Address-Resolution */
|
|
case 0x05: /* Advertisement-Solicitation */
|
|
case 0x08: /* Disconnect-Request */
|
|
case 0x09: /* Disconnect-ACK */
|
|
case 0x0A: /* Heartbeat-Request */
|
|
case 0x0B: /* Heartbeat-ACK */
|
|
/* No additional payload here */
|
|
break;
|
|
case 0x04: /* Advertisement */
|
|
bvlc_length += 6;
|
|
break;
|
|
case 0x06: /* Connect-Request */
|
|
case 0x07: /* Connect-Accept */
|
|
bvlc_length += 26;
|
|
break;
|
|
case 0x01: /* Encapsulated-NPDU */
|
|
default:
|
|
/* The additional payload will be decoded elsewhere */
|
|
break;
|
|
}
|
|
|
|
col_set_str(pinfo->cinfo, COL_PROTOCOL, "BSCVLC");
|
|
col_set_str(pinfo->cinfo, COL_INFO, "BACnet Secure Connect Virtual Link Control");
|
|
|
|
/* Put the BSCVLC Type and Message ID in the info column */
|
|
col_append_fstr(pinfo->cinfo, COL_INFO, " BSCVLC Function %s Message-ID %u",
|
|
val_to_str_const(bvlc_function, bscvlc_function_names, "unknown"), bvlc_message_id);
|
|
|
|
/* Fill the tree... */
|
|
offset = 0;
|
|
ti = proto_tree_add_item(tree, proto_bscvlc, tvb, 0, bvlc_length, ENC_NA);
|
|
bvlc_tree = proto_item_add_subtree(ti, ett_bvlc);
|
|
|
|
proto_tree_add_uint(bvlc_tree, hf_bscvlc_function, tvb,
|
|
offset, 1, bvlc_function);
|
|
offset++;
|
|
proto_tree_add_bitmask(bvlc_tree, tvb, offset, hf_bscvlc_control,
|
|
ett_bscvlc_ctrl, bscvlc_control_flags, ENC_NA);
|
|
offset ++;
|
|
proto_tree_add_uint(bvlc_tree, hf_bscvlc_msg_id, tvb,
|
|
offset, 2, bvlc_message_id);
|
|
offset += 2;
|
|
|
|
if ((bvlc_control & BSCVLC_CONTROL_ORIG_ADDRESS) != 0)
|
|
{
|
|
for(idx = 0; idx < 6; idx++)
|
|
snprintf(&mac_buffer[idx * 2], sizeof(mac_buffer) - (idx * 2), "%02X", tvb_get_guint8(tvb, offset + idx));
|
|
col_append_fstr(pinfo->cinfo, COL_INFO, " SMAC %s", mac_buffer);
|
|
|
|
proto_tree_add_item(bvlc_tree, hf_bscvlc_orig_vmac, tvb, offset, 6, ENC_NA);
|
|
offset += 6;
|
|
}
|
|
|
|
if ((bvlc_control & BSCVLC_CONTROL_DEST_ADDRESS) != 0)
|
|
{
|
|
for(idx = 0; idx < 6; idx++)
|
|
snprintf(&mac_buffer[idx * 2], sizeof(mac_buffer) - (idx * 2), "%02X", tvb_get_guint8(tvb, offset + idx));
|
|
col_append_fstr(pinfo->cinfo, COL_INFO, " DMAC %s", mac_buffer);
|
|
|
|
proto_tree_add_item(bvlc_tree, hf_bscvlc_dest_vmac, tvb, offset, 6, ENC_NA);
|
|
offset += 6;
|
|
}
|
|
|
|
if ((bvlc_control & BSCVLC_CONTROL_DEST_OPTION) != 0)
|
|
{
|
|
bMoreFlag = TRUE;
|
|
|
|
while(tvb_reported_length_remaining(tvb, offset) > 0 &&
|
|
(hdr_byte = tvb_get_guint8(tvb, offset)) != 0 && bMoreFlag)
|
|
{
|
|
/* get flags and type... */
|
|
bMoreFlag= (hdr_byte & BSCVLC_HEADER_OPTION_MORE_OPTIONS);
|
|
bDataFlag= (hdr_byte & BSCVLC_HEADER_OPTION_DATA);
|
|
start = offset;
|
|
|
|
offset++;
|
|
|
|
if(bDataFlag)
|
|
{
|
|
npdu_length = (gint)(tvb_get_guint8(tvb, offset++) << 8);
|
|
npdu_length += (gint)tvb_get_guint8(tvb, offset++);
|
|
offset += npdu_length;
|
|
}
|
|
|
|
subtree = proto_tree_add_subtree_format(bvlc_tree, tvb, start, offset - start,
|
|
ett_bscvlc_hdr, NULL, "%s", "Destination Options");
|
|
proto_tree_add_bitmask_value(subtree, tvb, start, hf_bscvlc_header,
|
|
ett_bscvlc_hdr, bscvlc_header_flags, hdr_byte);
|
|
|
|
if(bDataFlag)
|
|
{
|
|
proto_tree_add_item(subtree, hf_bscvlc_header_length, tvb, start + 1, 2, ENC_NA);
|
|
proto_tree_add_item(subtree, hf_bscvlc_header_data, tvb, start + 3, npdu_length, ENC_NA);
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((bvlc_control & BSCVLC_CONTROL_DATA_OPTION) != 0)
|
|
{
|
|
bMoreFlag = TRUE;
|
|
|
|
while(tvb_reported_length_remaining(tvb, offset) > 0 &&
|
|
(hdr_byte = tvb_get_guint8(tvb, offset)) != 0 && bMoreFlag)
|
|
{
|
|
/* get flags and type... */
|
|
bMoreFlag= (hdr_byte & BSCVLC_HEADER_OPTION_MORE_OPTIONS);
|
|
bDataFlag= (hdr_byte & BSCVLC_HEADER_OPTION_DATA);
|
|
start = offset;
|
|
|
|
offset++;
|
|
|
|
if(bDataFlag)
|
|
{
|
|
npdu_length = (gint)(tvb_get_guint8(tvb, offset++) << 8);
|
|
npdu_length += (gint)tvb_get_guint8(tvb, offset++);
|
|
offset += npdu_length;
|
|
}
|
|
|
|
subtree = proto_tree_add_subtree_format(bvlc_tree, tvb, start, offset - start,
|
|
ett_bscvlc_hdr, NULL, "%s", "Data Options");
|
|
proto_tree_add_bitmask_value(subtree, tvb, start, hf_bscvlc_header,
|
|
ett_bscvlc_hdr, bscvlc_header_flags, hdr_byte);
|
|
|
|
if(bDataFlag)
|
|
{
|
|
proto_tree_add_item(subtree, hf_bscvlc_header_length, tvb, start + 1, 2, ENC_NA);
|
|
proto_tree_add_item(subtree, hf_bscvlc_header_data, tvb, start + 3, npdu_length, ENC_NA);
|
|
}
|
|
}
|
|
}
|
|
|
|
switch (bvlc_function)
|
|
{
|
|
case 0x02: /* Address-Resolution */
|
|
case 0x05: /* Advertisement-Solicitation */
|
|
case 0x08: /* Disconnect-Request */
|
|
case 0x09: /* Disconnect-ACK */
|
|
case 0x0A: /* Heartbeat-Request */
|
|
case 0x0B: /* Heartbeat-ACK */
|
|
break;
|
|
case 0x00: /* BVLC-Result */
|
|
subtree = proto_tree_add_subtree_format(bvlc_tree, tvb, offset, packet_length - offset,
|
|
ett_bscvlc_hdr, NULL, "%s", "BVLC-Result");
|
|
proto_tree_add_item(subtree, hf_bscvlc_function, tvb,
|
|
offset, 1, ENC_NA);
|
|
offset++;
|
|
proto_tree_add_item(subtree, hf_bscvlc_result, tvb,
|
|
offset, 1, ENC_NA);
|
|
bvlc_result = tvb_get_guint8(tvb, offset);
|
|
offset++;
|
|
|
|
col_append_fstr(pinfo->cinfo, COL_INFO, " %s",
|
|
val_to_str_const(bvlc_result, bscvlc_result_names, "unknown"));
|
|
|
|
if(bvlc_result)
|
|
{
|
|
proto_tree_add_item(subtree, hf_bscvlc_header_marker, tvb,
|
|
offset, 1, ENC_NA);
|
|
offset++;
|
|
proto_tree_add_item(subtree, hf_bscvlc_error_class, tvb,
|
|
offset, 2, ENC_NA);
|
|
offset += 2;
|
|
proto_tree_add_item(subtree, hf_bscvlc_error_code, tvb,
|
|
offset, 2, ENC_NA);
|
|
offset += 2;
|
|
proto_tree_add_item(subtree, hf_bscvlc_result_data, tvb,
|
|
offset, packet_length - offset, ENC_NA);
|
|
}
|
|
/* Force and of packet */
|
|
offset = packet_length;
|
|
break;
|
|
case 0x03: /* Address-Resolution-ACK */
|
|
subtree = proto_tree_add_subtree_format(bvlc_tree, tvb, offset, packet_length - offset,
|
|
ett_bscvlc_hdr, NULL, "%s", "Address-Resolution-ACK");
|
|
proto_tree_add_item(subtree, hf_bscvlc_uris, tvb,
|
|
offset, packet_length - offset, ENC_NA);
|
|
/* Force and of packet */
|
|
offset = packet_length;
|
|
break;
|
|
case 0x04: /* Advertisement */
|
|
subtree = proto_tree_add_subtree_format(bvlc_tree, tvb, offset, packet_length - offset,
|
|
ett_bscvlc_hdr, NULL, "%s", "Advertisement");
|
|
proto_tree_add_item(subtree, hf_bscvlc_hub_conn_state, tvb,
|
|
offset, 1, ENC_NA);
|
|
offset++;
|
|
proto_tree_add_item(subtree, hf_bscvlc_accept_conns, tvb,
|
|
offset, 1, ENC_NA);
|
|
offset++;
|
|
proto_tree_add_item(subtree, hf_bscvlc_max_bvlc_length, tvb,
|
|
offset, 2, ENC_NA);
|
|
offset += 2;
|
|
proto_tree_add_item(subtree, hf_bscvlc_max_npdu_length, tvb,
|
|
offset, 2, ENC_NA);
|
|
offset += 2;
|
|
break;
|
|
case 0x06: /* Connect-Request */
|
|
subtree = proto_tree_add_subtree_format(bvlc_tree, tvb, offset, packet_length - offset,
|
|
ett_bscvlc_hdr, NULL, "%s", "Connect-Request");
|
|
proto_tree_add_item(subtree, hf_bscvlc_connect_vmac, tvb,
|
|
offset, 6, ENC_NA);
|
|
offset += 6;
|
|
proto_tree_add_item(subtree, hf_bscvlc_connect_uuid, tvb,
|
|
offset, 16, ENC_NA);
|
|
offset += 16;
|
|
proto_tree_add_item(subtree, hf_bscvlc_max_bvlc_length, tvb,
|
|
offset, 2, ENC_NA);
|
|
offset += 2;
|
|
proto_tree_add_item(subtree, hf_bscvlc_max_npdu_length, tvb,
|
|
offset, 2, ENC_NA);
|
|
offset += 2;
|
|
break;
|
|
case 0x07: /* Connect-Accept */
|
|
subtree = proto_tree_add_subtree_format(bvlc_tree, tvb, offset, packet_length - offset,
|
|
ett_bscvlc_hdr, NULL, "%s", "Connect-Accept");
|
|
proto_tree_add_item(subtree, hf_bscvlc_connect_vmac, tvb,
|
|
offset, 6, ENC_NA);
|
|
offset += 6;
|
|
proto_tree_add_item(subtree, hf_bscvlc_connect_uuid, tvb,
|
|
offset, 16, ENC_NA);
|
|
offset += 16;
|
|
proto_tree_add_item(subtree, hf_bscvlc_max_bvlc_length, tvb,
|
|
offset, 2, ENC_NA);
|
|
offset += 2;
|
|
proto_tree_add_item(subtree, hf_bscvlc_max_npdu_length, tvb,
|
|
offset, 2, ENC_NA);
|
|
offset += 2;
|
|
break;
|
|
case 0x0C: /* Proprietary-Message */
|
|
subtree = proto_tree_add_subtree_format(bvlc_tree, tvb, offset, packet_length - offset,
|
|
ett_bscvlc_hdr, NULL, "%s", "Proprietary-Message");
|
|
proto_tree_add_item(subtree, hf_bscvlc_vendor_id, tvb,
|
|
offset, 2, ENC_NA);
|
|
offset += 2;
|
|
proto_tree_add_item(subtree, hf_bscvlc_proprietary_opt_type, tvb,
|
|
offset, 1, ENC_NA);
|
|
offset++;
|
|
proto_tree_add_item(subtree, hf_bscvlc_proprietary_data, tvb,
|
|
offset, packet_length - offset, ENC_NA);
|
|
/* Force and of packet */
|
|
offset = packet_length;
|
|
break;
|
|
case 0x01: /* Encapsulated-NPDU */
|
|
default:
|
|
/* Here we assume additional payload belongs to upper layers and will be decoded later */
|
|
break;
|
|
}
|
|
|
|
/* Let the remaining frame to be decoded elsewhere */
|
|
npdu_length = packet_length - offset;
|
|
next_tvb = tvb_new_subset_length_caplen(tvb, offset, -1, npdu_length);
|
|
/* Code from Guy Harris */
|
|
if (!dissector_try_uint(bscvlc_dissector_table,
|
|
bvlc_function, next_tvb, pinfo, tree)) {
|
|
/* Unknown function - dissect the paylod as data */
|
|
call_data_dissector(next_tvb, pinfo, tree);
|
|
}
|
|
|
|
return tvb_reported_length(tvb);
|
|
}
|
|
|
|
void
|
|
proto_register_bvlc(void)
|
|
{
|
|
static hf_register_info hf[] = {
|
|
{ &hf_bvlc_type,
|
|
{ "Type", "bvlc.type",
|
|
FT_UINT8, BASE_HEX, VALS(bvlc_types), 0,
|
|
NULL, HFILL }
|
|
},
|
|
{ &hf_bvlc_function,
|
|
{ "Function", "bvlc.function",
|
|
FT_UINT8, BASE_HEX, VALS(bvlc_function_names), 0,
|
|
"BVLC Function", HFILL }
|
|
},
|
|
{ &hf_bvlc_ipv6_function,
|
|
{ "Function", "bvlc.function_ipv6",
|
|
FT_UINT8, BASE_HEX, VALS(bvlc_ipv6_function_names), 0,
|
|
"BVLC Function IPV6", HFILL }
|
|
},
|
|
{ &hf_bvlc_length,
|
|
{ "BVLC-Length", "bvlc.length",
|
|
FT_UINT16, BASE_DEC, NULL, 0,
|
|
"Length of BVLC", HFILL }
|
|
},
|
|
{ &hf_bvlc_virt_source,
|
|
{ "BVLC-Virtual-Source", "bvlc.virtual_source",
|
|
FT_UINT24, BASE_DEC_HEX, NULL, 0,
|
|
"Virtual source address of BVLC", HFILL }
|
|
},
|
|
{ &hf_bvlc_virt_dest,
|
|
{ "BVLC-Virtual-Destination", "bvlc.virtual_dest",
|
|
FT_UINT24, BASE_DEC_HEX, NULL, 0,
|
|
"Virtual destination address of BVLC", HFILL }
|
|
},
|
|
{ &hf_bvlc_result_ip4,
|
|
{ "Result", "bvlc.result",
|
|
FT_UINT16, BASE_HEX, VALS(bvlc_result_names), 0,
|
|
"Result Code", HFILL }
|
|
},
|
|
{ &hf_bvlc_result_ip6,
|
|
{ "Result", "bvlc.result",
|
|
FT_UINT16, BASE_HEX, VALS(bvlc_ipv6_result_names), 0,
|
|
"Result Code", HFILL }
|
|
},
|
|
{ &hf_bvlc_bdt_ip,
|
|
{ "IP", "bvlc.bdt_ip",
|
|
FT_IPv4, BASE_NONE, NULL, 0,
|
|
"BDT IP", HFILL }
|
|
},
|
|
{ &hf_bvlc_bdt_port,
|
|
{ "Port", "bvlc.bdt_port",
|
|
FT_UINT16, BASE_DEC, NULL, 0,
|
|
"BDT Port", HFILL }
|
|
},
|
|
{ &hf_bvlc_bdt_mask,
|
|
{ "Mask", "bvlc.bdt_mask",
|
|
FT_BYTES, BASE_NONE, NULL, 0,
|
|
"BDT Broadcast Distribution Mask", HFILL }
|
|
},
|
|
{ &hf_bvlc_reg_ttl,
|
|
{ "TTL", "bvlc.reg_ttl",
|
|
FT_UINT16, BASE_DEC, NULL, 0,
|
|
"Foreign Device Time To Live", HFILL }
|
|
},
|
|
{ &hf_bvlc_fdt_ip,
|
|
{ "IP", "bvlc.fdt_ip",
|
|
FT_IPv4, BASE_NONE, NULL, 0,
|
|
"FDT IP", HFILL }
|
|
},
|
|
{ &hf_bvlc_fdt_ipv6,
|
|
{ "IP", "bvlc.fdt_ipv6",
|
|
FT_IPv6, BASE_NONE, NULL, 0,
|
|
"FDT IP", HFILL }
|
|
},
|
|
{ &hf_bvlc_fdt_port,
|
|
{ "Port", "bvlc.fdt_port",
|
|
FT_UINT16, BASE_DEC, NULL, 0,
|
|
"FDT Port", HFILL }
|
|
},
|
|
{ &hf_bvlc_fdt_ttl,
|
|
{ "TTL", "bvlc.fdt_ttl",
|
|
FT_UINT16, BASE_DEC, NULL, 0,
|
|
"Foreign Device Time To Live", HFILL }
|
|
},
|
|
{ &hf_bvlc_fdt_timeout,
|
|
{ "Timeout", "bvlc.fdt_timeout",
|
|
FT_UINT16, BASE_DEC, NULL, 0,
|
|
"Foreign Device Timeout (seconds)", HFILL }
|
|
},
|
|
{ &hf_bvlc_fwd_ip,
|
|
{ "IP", "bvlc.fwd_ip",
|
|
FT_IPv4, BASE_NONE, NULL, 0,
|
|
"FWD IP", HFILL }
|
|
},
|
|
{ &hf_bvlc_fwd_port,
|
|
{ "Port", "bvlc.fwd_port",
|
|
FT_UINT16, BASE_DEC, NULL, 0,
|
|
"FWD Port", HFILL }
|
|
},
|
|
{ &hf_bvlc_orig_source_addr,
|
|
{ "IP", "bvlc.orig_source_addr",
|
|
FT_IPv6, BASE_NONE, NULL, 0,
|
|
"ORIG IP", HFILL }
|
|
},
|
|
{ &hf_bvlc_orig_source_port,
|
|
{ "Port", "bvlc.orig_source_port",
|
|
FT_UINT16, BASE_DEC, NULL, 0,
|
|
"ORIG Port", HFILL }
|
|
},
|
|
};
|
|
|
|
static gint *ett[] = {
|
|
&ett_bvlc,
|
|
&ett_bdt,
|
|
&ett_fdt,
|
|
};
|
|
|
|
static hf_register_info bsc_hf[] = {
|
|
{ &hf_bscvlc_control,
|
|
{ "Control", "bscvlc.control",
|
|
FT_UINT8, BASE_HEX, NULL, 0,
|
|
"BSCVLC Control", HFILL }
|
|
},
|
|
{ &hf_bscvlc_control_data_option,
|
|
{ "Data Option", "bscvlc.control_data_option",
|
|
FT_BOOLEAN, 8, TFS(&control_data_option_set_high),
|
|
BSCVLC_CONTROL_DATA_OPTION, "BSCVLC Control", HFILL }
|
|
},
|
|
{ &hf_bscvlc_control_destination_option,
|
|
{ "Destination Option", "bscvlc.control_dest_option",
|
|
FT_BOOLEAN, 8, TFS(&control_destination_option_set_high),
|
|
BSCVLC_CONTROL_DEST_OPTION, "BSCVLC Control", HFILL }
|
|
},
|
|
{ &hf_bscvlc_control_destination_address,
|
|
{ "Destination Address","bscvlc.control_dest_address",
|
|
FT_BOOLEAN, 8, TFS(&control_destination_address_set_high),
|
|
BSCVLC_CONTROL_DEST_ADDRESS, "BSCVLC Control", HFILL }
|
|
},
|
|
{ &hf_bscvlc_control_origin_address,
|
|
{ "Origin Address", "bscvlc.control_orig_address",
|
|
FT_BOOLEAN, 8, TFS(&control_orig_address_set_high),
|
|
BSCVLC_CONTROL_ORIG_ADDRESS, "BSCVLC Control", HFILL }
|
|
},
|
|
{ &hf_bscvlc_control_reserved,
|
|
{ "Reserved", "bscvlc.control_reserved",
|
|
FT_BOOLEAN, 8, TFS(&control_reserved_set_high),
|
|
BSCVLC_CONTROL_RESERVED, "BSCVLC Control", HFILL }
|
|
},
|
|
{ &hf_bscvlc_header,
|
|
{ "Header Data Length", "bscvlc.header",
|
|
FT_UINT8, BASE_HEX, NULL, 0,
|
|
"BSCVLC Header Control Data", HFILL }
|
|
},
|
|
{ &hf_bscvlc_header_marker,
|
|
{ "Header Error Marker","bscvlc.header_error_marker",
|
|
FT_UINT8, BASE_HEX, NULL, 0,
|
|
"BSCVLC Header Error Marker", HFILL }
|
|
},
|
|
{ &hf_bscvlc_header_length,
|
|
{ "Header Data Length", "bscvlc.header_length",
|
|
FT_UINT16, BASE_DEC, NULL, 0,
|
|
"BSCVLC Header Data Length", HFILL }
|
|
},
|
|
{ &hf_bscvlc_header_data,
|
|
{ "Header Data", "bscvlc.header_data",
|
|
FT_BYTES, BASE_NONE, NULL, 0,
|
|
"BSCVLC Header Option", HFILL }
|
|
},
|
|
{ &hf_bscvlc_header_opt_type,
|
|
{ "Header Type", "bscvlc.header_type",
|
|
FT_UINT8, BASE_HEX, VALS(bscvlc_header_type_names),
|
|
BSCVLC_HEADER_OPTION_TYPE, "BSCVLC Header Option", HFILL }
|
|
},
|
|
{ &hf_bscvlc_header_opt_data,
|
|
{ "Header Data", "bscvlc.header_data_present",
|
|
FT_BOOLEAN, 8, TFS(&header_opt_data_set_high),
|
|
BSCVLC_HEADER_OPTION_DATA, "BSCVLC Header Option", HFILL }
|
|
},
|
|
{ &hf_bscvlc_header_opt_must_understand,
|
|
{ "Header Must Understand","bscvlc.header_understand",
|
|
FT_BOOLEAN, 8, TFS(&header_opt_must_understand_set_high),
|
|
BSCVLC_HEADER_OPTION_MUST_UNDERSTAND, "BSCVLC Header Option", HFILL }
|
|
},
|
|
{ &hf_bscvlc_header_opt_more,
|
|
{ "Header More", "bscvlc.header_more",
|
|
FT_BOOLEAN, 8, TFS(&header_opt_more_set_high),
|
|
BSCVLC_HEADER_OPTION_MORE_OPTIONS, "BSCVLC Header Option", HFILL }
|
|
},
|
|
{ &hf_bscvlc_vendor_id,
|
|
{ "Vendor ID", "bscvlc.vendor_id",
|
|
FT_UINT16, BASE_HEX, NULL, 0,
|
|
"BSCVLC Vendor ID", HFILL }
|
|
},
|
|
{ &hf_bscvlc_proprietary_opt_type,
|
|
{ "Proprietary Type", "bscvlc.proprietary_type",
|
|
FT_UINT8, BASE_HEX, NULL, 0,
|
|
"BSCVLC Proprietary Type", HFILL }
|
|
},
|
|
{ &hf_bscvlc_proprietary_data,
|
|
{ "Proprietary Data", "bscvlc.proprietary_data",
|
|
FT_BYTES, BASE_NONE, NULL, 0,
|
|
"BSCVLC Proprietary Data", HFILL }
|
|
},
|
|
{ &hf_bscvlc_hub_conn_state,
|
|
{ "Hub Connection Status","bscvlc.hub_conn_state",
|
|
FT_UINT8, BASE_HEX, VALS(bscvlc_hub_conn_state_names), 0,
|
|
"BSCVLC Hub Connection Status", HFILL }
|
|
},
|
|
{ &hf_bscvlc_accept_conns,
|
|
{ "Hub Accepts Connections","bscvlc.accept_conns",
|
|
FT_UINT8, BASE_HEX, VALS(bscvlc_hub_accept_conns_names), 0,
|
|
"BSCVLC Accepts Connections", HFILL }
|
|
},
|
|
{ &hf_bscvlc_max_bvlc_length,
|
|
{ "Max. BVLC Length", "bscvlc.max_bvlc_length",
|
|
FT_UINT16, BASE_DEC, NULL, 0,
|
|
"Max Supported BVLC Length", HFILL }
|
|
},
|
|
{ &hf_bscvlc_max_npdu_length,
|
|
{ "Max. NPDU Length", "bscvlc.max_npdu_length",
|
|
FT_UINT16, BASE_DEC, NULL, 0,
|
|
"Max Supported NPDU Length", HFILL }
|
|
},
|
|
{ &hf_bscvlc_function,
|
|
{ "Function", "bscvlc.function",
|
|
FT_UINT8, BASE_HEX, VALS(bscvlc_function_names), 0,
|
|
"BSCVLC Function", HFILL }
|
|
},
|
|
{ &hf_bscvlc_result,
|
|
{ "Result", "bscvlc.result",
|
|
FT_UINT8, BASE_HEX, VALS(bscvlc_result_names), 0,
|
|
"Result Code", HFILL }
|
|
},
|
|
{ &hf_bscvlc_error_class,
|
|
{ "Error Class", "bscvlc.error_class",
|
|
FT_UINT32, BASE_DEC, VALS(BACnetErrorClass), 0, NULL, HFILL }
|
|
},
|
|
{ &hf_bscvlc_error_code,
|
|
{ "Error Code", "bscvlc.error_code",
|
|
FT_UINT32, BASE_DEC, VALS(BACnetErrorCode), 0, NULL, HFILL }
|
|
},
|
|
{ &hf_bscvlc_result_data,
|
|
{ "Result Data", "bscvlc.result_data",
|
|
FT_BYTES, BASE_NONE, NULL, 0,
|
|
"BSCVLC Result Data", HFILL }
|
|
},
|
|
{ &hf_bscvlc_uris,
|
|
{ "URI's", "bscvlc.uris",
|
|
FT_BYTES, BASE_NONE, NULL, 0,
|
|
"BSCVLC Address URI's", HFILL }
|
|
},
|
|
{ &hf_bscvlc_msg_id,
|
|
{ "Message ID", "bscvlc.msgid",
|
|
FT_UINT16, BASE_DEC, NULL, 0,
|
|
"BSCVLC Message ID", HFILL }
|
|
},
|
|
{ &hf_bscvlc_orig_vmac,
|
|
{ "SVMAC", "bscvlc.orig_virtual_address",
|
|
FT_BYTES, BASE_NONE, NULL, 0,
|
|
"ORIG VMAC", HFILL }
|
|
},
|
|
{ &hf_bscvlc_dest_vmac,
|
|
{ "DVMAC", "bscvlc.dest_virtual_address",
|
|
FT_BYTES, BASE_NONE, NULL, 0,
|
|
"DEST VMAC", HFILL }
|
|
},
|
|
{ &hf_bscvlc_connect_vmac,
|
|
{ "Connecting VMAC", "bscvlc.connect_virtual_address",
|
|
FT_BYTES, BASE_NONE, NULL, 0,
|
|
"BSCVLC Connecting VMAC", HFILL }
|
|
},
|
|
{ &hf_bscvlc_connect_uuid,
|
|
{ "Connecting UUID", "bscvlc.connect_uuid",
|
|
FT_BYTES, BASE_NONE, NULL, 0,
|
|
"BSCVLC Connecting UUID", HFILL }
|
|
},
|
|
};
|
|
|
|
static gint *bsc_ett[] = {
|
|
&ett_bscvlc,
|
|
&ett_bscvlc_ctrl,
|
|
&ett_bscvlc_hdr
|
|
};
|
|
|
|
proto_bvlc = proto_register_protocol("BACnet Virtual Link Control", "BVLC", "bvlc");
|
|
|
|
proto_register_field_array(proto_bvlc, hf, array_length(hf));
|
|
proto_register_subtree_array(ett, array_length(ett));
|
|
|
|
bvlc_handle = register_dissector("bvlc", dissect_bvlc, proto_bvlc);
|
|
|
|
bvlc_dissector_table = register_dissector_table("bvlc.function", "BVLC Function", proto_bvlc, FT_UINT8, BASE_HEX);
|
|
bvlc_ipv6_dissector_table = register_dissector_table("bvlc.function_ipv6", "BVLC Function IPV6", proto_bvlc, FT_UINT8, BASE_HEX);
|
|
|
|
proto_bscvlc = proto_register_protocol("BACnet Secure Connect Virtual Link Control", "BSCVLC", "bscvlc");
|
|
|
|
proto_register_field_array(proto_bscvlc, bsc_hf, array_length(bsc_hf));
|
|
proto_register_subtree_array(bsc_ett, array_length(bsc_ett));
|
|
|
|
bscvlc_handle = register_dissector("bscvlc", dissect_bscvlc, proto_bscvlc);
|
|
|
|
bscvlc_dissector_table = register_dissector_table("bscvlc.function", "BSCVLC Function", proto_bscvlc, FT_UINT8, BASE_HEX);
|
|
}
|
|
|
|
void
|
|
proto_reg_handoff_bvlc(void)
|
|
{
|
|
dissector_add_uint_with_preference("udp.port", BVLC_UDP_PORT, bvlc_handle);
|
|
dissector_add_string("ws.protocol", "hub.bsc.bacnet.org", bscvlc_handle);
|
|
dissector_add_string("ws.protocol", "dc.bsc.bacnet.org", bscvlc_handle);
|
|
}
|
|
|
|
/*
|
|
* Editor modelines - https://www.wireshark.org/tools/modelines.html
|
|
*
|
|
* Local variables:
|
|
* c-basic-offset: 8
|
|
* tab-width: 8
|
|
* indent-tabs-mode: t
|
|
* End:
|
|
*
|
|
* vi: set shiftwidth=8 tabstop=8 noexpandtab:
|
|
* :indentSize=8:tabSize=8:noTabs=false:
|
|
*/
|