Coverage Report

Created: 2025-08-04 07:15

/src/wireshark/epan/dissectors/packet-bvlc.c
Line
Count
Source (jump to first uncovered line)
1
/* packet-bvlc.c
2
 * Routines for BACnet/IP (BVLL, BVLC) dissection
3
 * Copyright 2001, Hartmut Mueller <hartmut@abmlinux.org>, FH Dortmund
4
 *
5
 * Wireshark - Network traffic analyzer
6
 * By Gerald Combs <gerald@wireshark.org>
7
 * Copyright 1998 Gerald Combs
8
 *
9
 * Copied from README.developer,v 1.23
10
 *
11
 * SPDX-License-Identifier: GPL-2.0-or-later
12
 */
13
14
#include "config.h"
15
16
#include <epan/packet.h>
17
#include <epan/tfs.h>
18
19
#include "packet-bacnet.h"
20
#include "packet-bacapp.h"
21
22
void proto_register_bvlc(void);
23
void proto_reg_handoff_bvlc(void);
24
25
14
#define BVLC_UDP_PORT 0xBAC0
26
27
/* Network Layer Wrapper Control Information */
28
#define BAC_WRAPPER_CONTROL_NET   0x80
29
#define BAC_WRAPPER_MSG_ENCRYPED  0x40
30
#define BAC_WRAPPER_RESERVED    0x20
31
#define BAC_WRAPPER_AUTHD_PRESENT 0x10
32
#define BAC_WRAPPER_DO_NOT_UNWRAP 0x08
33
#define BAC_WRAPPER_DO_NOT_DECRPT 0x04
34
#define BAC_WRAPPER_NO_TRUST_SRC  0x02
35
#define BAC_WRAPPER_SECURE_BY_RTR 0x01
36
37
static int proto_bvlc;
38
static int proto_bscvlc;
39
static int hf_bvlc_type;
40
static int hf_bvlc_function;
41
static int hf_bvlc_ipv6_function;
42
static int hf_bvlc_length;
43
static int hf_bvlc_result_ip4;
44
static int hf_bvlc_result_ip6;
45
static int hf_bvlc_bdt_ip;
46
static int hf_bvlc_bdt_mask;
47
static int hf_bvlc_bdt_port;
48
static int hf_bvlc_reg_ttl;
49
static int hf_bvlc_fdt_ip;
50
static int hf_bvlc_fdt_ipv6;
51
static int hf_bvlc_fdt_port;
52
static int hf_bvlc_fdt_ttl;
53
static int hf_bvlc_fdt_timeout;
54
static int hf_bvlc_fwd_ip;
55
static int hf_bvlc_fwd_port;
56
static int hf_bvlc_virt_source;
57
static int hf_bvlc_virt_dest;
58
static int hf_bvlc_orig_source_addr;
59
static int hf_bvlc_orig_source_port;
60
static int hf_bscvlc_control;
61
static int hf_bscvlc_control_data_option;
62
static int hf_bscvlc_control_destination_option;
63
static int hf_bscvlc_control_destination_address;
64
static int hf_bscvlc_control_origin_address;
65
static int hf_bscvlc_control_reserved;
66
static int hf_bscvlc_header;
67
static int hf_bscvlc_header_marker;
68
static int hf_bscvlc_header_length;
69
static int hf_bscvlc_header_data;
70
static int hf_bscvlc_header_opt_type;
71
static int hf_bscvlc_header_opt_data;
72
static int hf_bscvlc_header_opt_must_understand;
73
static int hf_bscvlc_header_opt_more;
74
static int hf_bscvlc_vendor_id;
75
static int hf_bscvlc_proprietary_opt_type;
76
static int hf_bscvlc_proprietary_data;
77
static int hf_bscvlc_hub_conn_state;
78
static int hf_bscvlc_accept_conns;
79
static int hf_bscvlc_max_bvlc_length;
80
static int hf_bscvlc_max_npdu_length;
81
static int hf_bscvlc_function;
82
static int hf_bscvlc_result;
83
static int hf_bscvlc_error_class;
84
static int hf_bscvlc_error_code;
85
static int hf_bscvlc_result_data;
86
static int hf_bscvlc_uris;
87
static int hf_bscvlc_msg_id;
88
static int hf_bscvlc_orig_vmac;
89
static int hf_bscvlc_dest_vmac;
90
static int hf_bscvlc_connect_vmac;
91
static int hf_bscvlc_connect_uuid;
92
static int hf_bscvlc_identity_device_id;
93
static int hf_bscvlc_hello_opt;
94
static int hf_bscvlc_hello_opt_identity_relay;
95
96
static dissector_table_t bvlc_dissector_table;
97
static dissector_table_t bscvlc_dissector_table;
98
static dissector_table_t bvlc_ipv6_dissector_table;
99
static dissector_handle_t bvlc_handle;
100
static dissector_handle_t bscvlc_handle;
101
102
static const value_string bvlc_function_names[] = {
103
  { 0x00, "BVLC-Result" },
104
  { 0x01, "Write-Broadcast-Distribution-Table" },
105
  { 0x02, "Read-Broadcast-Distribution-Table" },
106
  { 0x03, "Read-Broadcast-Distribution-Table-Ack" },
107
  { 0x04, "Forwarded-NPDU" },
108
  { 0x05, "Register-Foreign-Device" },
109
  { 0x06, "Read-Foreign-Device-Table" },
110
  { 0x07, "Read-Foreign-Device-Table-Ack" },
111
  { 0x08, "Delete-Foreign-Device-Table-Entry" },
112
  { 0x09, "Distribute-Broadcast-To-Network" },
113
  { 0x0a, "Original-Unicast-NPDU" },
114
  { 0x0b, "Original-Broadcast-NPDU" },
115
  { 0x0c, "Secured-BVLL" },
116
  { 0, NULL }
117
};
118
119
static const value_string bscvlc_function_names[] = {
120
  { 0x00, "BVLC-Result" },
121
  { 0x01, "Encapsulated-NPDU" },
122
  { 0x02, "Address-Resolution" },
123
  { 0x03, "Address-Resolution-ACK" },
124
  { 0x04, "Advertisement" },
125
  { 0x05, "Advertisement-Solicitation" },
126
  { 0x06, "Connect-Request" },
127
  { 0x07, "Connect-Accept" },
128
  { 0x08, "Disconnect-Request" },
129
  { 0x09, "Disconnect-ACK" },
130
  { 0x0A, "Heartbeat-Request" },
131
  { 0x0B, "Heartbeat-ACK" },
132
  { 0x0C, "Proprietary-Message" },
133
  { 0, NULL }
134
};
135
136
static const value_string bvlc_result_names[] = {
137
  { 0x00, "Successful completion" },
138
  { 0x10, "Write-Broadcast-Distribution-Table NAK" },
139
  { 0x20, "Read-Broadcast-Distribution-Table NAK" },
140
  { 0x30, "Register-Foreign-Device NAK" },
141
  { 0x40, "Read-Foreign-Device-Table NAK" },
142
  { 0x50, "Delete-Foreign-Device-Table-Entry NAK" },
143
  { 0x60, "Distribute-Broadcast-To-Network NAK" },
144
  { 0,    NULL }
145
};
146
147
static const value_string bscvlc_result_names[] = {
148
  { 0x00, "Successful completion (ACK)" },
149
  { 0x01, "Completion failed (NAK)" },
150
  { 0,    NULL }
151
};
152
153
static const value_string bvlc_ipv6_function_names[] = {
154
  { 0x00, "BVLC-Result", },
155
  { 0x01, "Original-Unicast-NPDU", },
156
  { 0x02, "Original-Broadcast-NPDU", },
157
  { 0x03, "Address-Resolution", },
158
  { 0x04, "Forwarded-Address-Resolution", },
159
  { 0x05, "Address-Resolution-ACK", },
160
  { 0x06, "Virtual-Address-Resolution", },
161
  { 0x07, "Virtual-Address-Resolution-ACK", },
162
  { 0x08, "Forwarded-NPDU", },
163
  { 0x09, "Register-Foreign-Device", },
164
  { 0x0A, "Delete-Foreign-Device-Table-Entry", },
165
  { 0x0B, "Secure-BVLL", },
166
  { 0x0C, "Distribute-Broadcast-To-Network", },
167
  { 0, NULL }
168
};
169
170
static const value_string bvlc_ipv6_result_names[] = {
171
  { 0x00, "Successful completion" },
172
  { 0x30, "Address-Resolution NAK" },
173
  { 0x60, "Virtual-Address-Resolution NAK" },
174
  { 0x90, "Register-Foreign-Device NAK" },
175
  { 0xA0, "Delete-Foreign-Device-Table-Entry NAK" },
176
  { 0xC0, "Distribute-Broadcast-To-Network NAK" },
177
  { 0, NULL }
178
};
179
180
static const value_string bscvlc_header_type_names[] = {
181
  { 0x01, "Secure Path" },
182
  { 0x02, "Hello" },
183
  { 0x03, "Identity" },
184
  { 0x04, "Hint" },
185
  { 0x05, "Token" },
186
  { 0x1F, "Proprietary Header Option" },
187
  { 0,    NULL }
188
};
189
190
static const value_string bscvlc_hub_conn_state_names[] = {
191
  { 0x00, "No hub connection" },
192
  { 0x01, "Connected to primary hub" },
193
  { 0x02, "Connected to failover hub" },
194
  { 0,    NULL }
195
};
196
197
static const value_string bscvlc_hub_accept_conns_names[] = {
198
  { 0x00, "The node does not support accepting direct connections" },
199
  { 0x01, "The node supports accepting direct connections" },
200
  { 0,    NULL }
201
};
202
203
static int ett_bvlc;
204
static int ett_bscvlc;
205
static int ett_bscvlc_ctrl;
206
static int ett_bscvlc_hdr;
207
static int ett_bdt;
208
static int ett_fdt;
209
210
0
#define BACNET_IP_ANNEX_J   0x81
211
6
#define BACNET_IPV6_ANNEX_U   0x82
212
213
static const value_string bvlc_types[] = {
214
  { BACNET_IP_ANNEX_J,  "BACnet/IP (Annex J)" },
215
  { BACNET_IPV6_ANNEX_U,  "BACnet/IPV6 (Annex U)" },
216
  { 0, NULL }
217
};
218
219
14
#define BSCVLC_CONTROL_DATA_OPTION    0x01
220
14
#define BSCVLC_CONTROL_DEST_OPTION    0x02
221
14
#define BSCVLC_CONTROL_DEST_ADDRESS   0x04
222
14
#define BSCVLC_CONTROL_ORIG_ADDRESS   0x08
223
14
#define BSCVLC_CONTROL_RESERVED     0xF0
224
225
static const true_false_string control_data_option_set_high = {
226
  "Data Options field is present.",
227
  "Data Options field is absent."
228
};
229
230
static const true_false_string control_destination_option_set_high = {
231
  "Destination Options field is present.",
232
  "Destination Options field is absent."
233
};
234
235
static const true_false_string control_destination_address_set_high = {
236
  "Destination Virtual Address is present.",
237
  "Destination Virtual Address is absent."
238
};
239
240
static const true_false_string control_orig_address_set_high = {
241
  "Originating Virtual Address is present.",
242
  "Originating Virtual Address is absent."
243
};
244
245
static const true_false_string control_reserved_set_high = {
246
  "Shall be zero, but is not.",
247
  "Shall be zero and is zero."
248
};
249
250
/* BSCVLC Header option bits */
251
14
#define BSCVLC_HDR_MORE_OPTIONS_FOLLOW            0x80
252
14
#define BSCVLC_HDR_MUST_UNDERSTAND                0x40
253
0
#define BSCVLC_HDR_EVERY_SEGMENT                  0x40
254
14
#define BSCVLC_HDR_DATA_PRESENT                   0x20
255
14
#define BSCVLC_HDR_OPTION_TYPE_MASK               0x1F
256
257
/* BSCVLC Header options and their bits */
258
0
#define BSCVLC_HDR_OPT_SECURE_PATH                0x01  /* only data option */
259
0
#define BSCVLC_HDR_OPT_HELLO                      0x02  /* only destination option */
260
#define BSCVLC_HDR_OPT_HELLO_BIT_IDENT_RELAY      0x01  /* only with the connect request */
261
0
#define BSCVLC_HDR_OPT_IDENTITY                   0x03  /* only data option */
262
0
#define BSCVLC_HDR_OPT_HINT                       0x04  /* only data option */
263
0
#define BSCVLC_HDR_OPT_TOKEN                      0x05  /* only data option */
264
0
#define BSCVLC_HDR_OPT_PROPRIETARY                0x1F  /* data or destination option */
265
266
267
static const true_false_string header_opt_data_set_high = {
268
  "The 'Header Length' and 'Header Data' fields are present.",
269
  "The 'Header Length' and 'Header Data' fields are absent."
270
};
271
272
static const true_false_string header_opt_must_understand_set_high = {
273
  "This header option must be understood for consuming the message.",
274
  "This header option can be ignored if not understood."
275
};
276
277
static const true_false_string header_opt_more_set_high = {
278
  "Another header option follows in the current header option list.",
279
  "This is the last header option in the current header option list."
280
};
281
282
14
#define BSCVLC_HELLO_IDENTITY_RELAY   0x01
283
284
static const true_false_string hello_opt_identity_relay_set_high = {
285
  "Identity relay is allowed.",
286
  "Identity relay is forbidden."
287
};
288
289
static int * const bscvlc_hello1_opt_flags[] = {
290
  &hf_bscvlc_hello_opt_identity_relay,
291
  NULL
292
};
293
294
static const value_string
295
BACnetErrorClass [] = {
296
    { 0, "device" },
297
    { 1, "object" },
298
    { 2, "property" },
299
    { 3, "resources" },
300
    { 4, "security" },
301
    { 5, "services" },
302
    { 6, "vt" },
303
    { 7, "communication" },
304
    { 0, NULL }
305
/* Enumerated values 0-63 are reserved for definition by ASHRAE.
306
   Enumerated values64-65535 may be used by others subject to
307
   the procedures and constraints described in Clause 23. */
308
};
309
310
static const value_string
311
BACnetErrorCode[] = {
312
    {   0, "other"},
313
    {   1, "authentication-failed"},
314
    {   2, "configuration-in-progress"},
315
    {   3, "device-busy"},
316
    {   4, "dynamic-creation-not-supported"},
317
    {   5, "file-access-denied"},
318
    {   6, "incompatible-security-levels"},
319
    {   7, "inconsistent-parameters"},
320
    {   8, "inconsistent-selection-criterion"},
321
    {   9, "invalid-data-type"},
322
    {  10, "invalid-file-access-method"},
323
    {  11, "invalid-file-start-position"},
324
    {  12, "invalid-operator-name"},
325
    {  13, "invalid-parameter-data-type"},
326
    {  14, "invalid-time-stamp"},
327
    {  15, "key-generation-error"},
328
    {  16, "missing-required-parameter"},
329
    {  17, "no-objects-of-specified-type"},
330
    {  18, "no-space-for-object"},
331
    {  19, "no-space-to-add-list-element"},
332
    {  20, "no-space-to-write-property"},
333
    {  21, "no-vt-sessions-available"},
334
    {  22, "property-is-not-a-list"},
335
    {  23, "object-deletion-not-permitted"},
336
    {  24, "object-identifier-already-exists"},
337
    {  25, "operational-problem"},
338
    {  26, "password-failure"},
339
    {  27, "read-access-denied"},
340
    {  28, "security-not-supported"},
341
    {  29, "service-request-denied"},
342
    {  30, "timeout"},
343
    {  31, "unknown-object"},
344
    {  32, "unknown-property"},
345
    {  33, "removed enumeration"},
346
    {  34, "unknown-vt-class"},
347
    {  35, "unknown-vt-session"},
348
    {  36, "unsupported-object-type"},
349
    {  37, "value-out-of-range"},
350
    {  38, "vt-session-already-closed"},
351
    {  39, "vt-session-termination-failure"},
352
    {  40, "write-access-denied"},
353
    {  41, "character-set-not-supported"},
354
    {  42, "invalid-array-index"},
355
    {  43, "cov-subscription-failed"},
356
    {  44, "not-cov-property"},
357
    {  45, "optional-functionality-not-supported"},
358
    {  46, "invalid-configuration-data"},
359
    {  47, "datatype-not-supported"},
360
    {  48, "duplicate-name"},
361
    {  49, "duplicate-object-id"},
362
    {  50, "property-is-not-an-array"},
363
    {  51, "abort - buffer - overflow" },
364
    {  52, "abort - invalid - apdu - in - this - state" },
365
    {  53, "abort - preempted - by - higher - priority - task" },
366
    {  54, "abort - segmentation - not - supported" },
367
    {  55, "abort - proprietary" },
368
    {  56, "abort - other" },
369
    {  57, "reject - invalid - tag" },
370
    {  58, "reject - network - down" },
371
    {  59, "reject - buffer - overflow" },
372
    {  60, "reject - inconsistent - parameters" },
373
    {  61, "reject - invalid - parameter - data - type" },
374
    {  62, "reject - invalid - tag" },
375
    {  63, "reject - missing - required - parameter" },
376
    {  64, "reject - parameter - out - of - range" },
377
    {  65, "reject - too - many - arguments" },
378
    {  66, "reject - undefined - enumeration" },
379
    {  67, "reject - unrecognized - service" },
380
    {  68, "reject - proprietary" },
381
    {  69, "reject - other" },
382
    {  70, "unknown - device" },
383
    {  71, "unknown - route" },
384
    {  72, "value - not - initialized" },
385
    {  73, "invalid-event-state"},
386
    {  74, "no-alarm-configured"},
387
    {  75, "log-buffer-full"},
388
    {  76, "logged-value-purged"},
389
    {  77, "no-property-specified"},
390
    {  78, "not-configured-for-triggered-logging"},
391
    {  79, "unknown-subscription"},
392
    {  80, "parameter-out-of-range"},
393
    {  81, "list-element-not-found"},
394
    {  82, "busy"},
395
    {  83, "communication-disabled"},
396
    {  84, "success"},
397
    {  85, "access-denied"},
398
    {  86, "bad-destination-address"},
399
    {  87, "bad-destination-device-id"},
400
    {  88, "bad-signature"},
401
    {  89, "bad-source-address"},
402
    {  90, "bad-timestamp"},
403
    {  91, "cannot-use-key"},
404
    {  92, "cannot-verify-message-id"},
405
    {  93, "correct-key-revision"},
406
    {  94, "destination-device-id-required"},
407
    {  95, "duplicate-message"},
408
    {  96, "encryption-not-configured"},
409
    {  97, "encryption-required"},
410
    {  98, "incorrect-key"},
411
    {  99, "invalid-key-data"},
412
    { 100, "key-update-in-progress"},
413
    { 101, "malformed-message"},
414
    { 102, "not-key-server"},
415
    { 103, "security-not-configured"},
416
    { 104, "source-security-required"},
417
    { 105, "too-many-keys"},
418
    { 106, "unknown-authentication-type"},
419
    { 107, "unknown-key"},
420
    { 108, "unknown-key-revision"},
421
    { 109, "unknown-source-message"},
422
    { 110, "not-router-to-dnet"},
423
    { 111, "router-busy"},
424
    { 112, "unknown-network-message"},
425
    { 113, "message-too-long"},
426
    { 114, "security-error"},
427
    { 115, "addressing-error"},
428
    { 116, "write-bdt-failed"},
429
    { 117, "read-bdt-failed"},
430
    { 118, "register-foreign-device-failed"},
431
    { 119, "read-fdt-failed"},
432
    { 120, "delete-fdt-entry-failed"},
433
    { 121, "distribute-broadcast-failed"},
434
    { 122, "unknown-file-size"},
435
    { 123, "abort-apdu-too-long"},
436
    { 124, "abort-application-exceeded-reply-time"},
437
    { 125, "abort-out-of-resources"},
438
    { 126, "abort-tsm-timeout"},
439
    { 127, "abort-window-size-out-of-range"},
440
    { 128, "file-full"},
441
    { 129, "inconsistent-configuration"},
442
    { 130, "inconsistent-object-type"},
443
    { 131, "internal-error"},
444
    { 132, "not-configured"},
445
    { 133, "out-of-memory"},
446
    { 134, "value-too-long"},
447
    { 135, "abort-insufficient-security"},
448
    { 136, "abort-security-error"},
449
    { 137, "duplicate-entry"},
450
    { 138, "invalid-value-in-this-state"},
451
    { 139, "invalid-operation-in-this-state"},
452
    { 140, "list-item-not-numbered"},
453
    { 141, "list-item-not-timestamped"},
454
    { 142, "invalid-data-encoding"},
455
    { 143, "bvlc-function-unknown"},
456
    { 144, "bvlc-proprietary-function-unknown"},
457
    { 145, "header-encoding-error"},
458
    { 146, "header-not-understood"},
459
    { 147, "message-incomplete"},
460
    { 148, "not-a-bacnet-sc-hub"},
461
    { 149, "payload-expected"},
462
    { 150, "unexpected-data"},
463
    { 151, "node-duplicate-vmac"},
464
    { 152, "http-unexpected-response-code"},
465
    { 153, "http-no-upgrade"},
466
    { 154, "http-resource-not-local"},
467
    { 155, "http-proxy-authentication-failed"},
468
    { 156, "http-response-timeout"},
469
    { 157, "http-response-syntax-error"},
470
    { 158, "http-response-value-error"},
471
    { 159, "http-response-missing-header"},
472
    { 160, "http-websocket-header-error"},
473
    { 161, "http-upgrade-required"},
474
    { 162, "http-upgrade-error"},
475
    { 163, "http-temporary-unavailable"},
476
    { 164, "http-not-a-server"},
477
    { 165, "http-error"},
478
    { 166, "websocket-scheme-not-supported"},
479
    { 167, "websocket-unknown-control-message"},
480
    { 168, "websocket-close-error"},
481
    { 169, "websocket-closed-by-peer"},
482
    { 170, "websocket-endpoint-leaves"},
483
    { 171, "websocket-protocol-error"},
484
    { 172, "websocket-data-not-accepted"},
485
    { 173, "websocket-closed-abnormally"},
486
    { 174, "websocket-data-inconsistent"},
487
    { 175, "websocket-data-against-policy"},
488
    { 176, "websocket-frame-too-long"},
489
    { 177, "websocket-extension-missing"},
490
    { 178, "websocket-request-unavailable"},
491
    { 179, "websocket-error"},
492
    { 180, "tls-client-certificate-error"},
493
    { 181, "tls-server-certificate-error"},
494
    { 182, "tls-client-authentication-failed"},
495
    { 183, "tls-server-authentication-failed"},
496
    { 184, "tls-client-certificate-expired"},
497
    { 185, "tls-server-certificate-expired"},
498
    { 186, "tls-client-certificate-revoked"},
499
    { 187, "tls-server-certificate-revoked"},
500
    { 188, "tls-error"},
501
    { 189, "dns-unavailable"},
502
    { 190, "dns-name-resolution-failed"},
503
    { 191, "dns-resolver-failure"},
504
    { 192, "dns-error"},
505
    { 193, "tcp-connect-timeout"},
506
    { 194, "tcp-connection-refused"},
507
    { 195, "tcp-closed-by-local"},
508
    { 196, "tcp-closed-other"},
509
    { 197, "tcp-error"},
510
    { 198, "ip-address-not-reachable"},
511
    { 199, "ip-error"},
512
    { 200, "certificate-expired"},
513
    { 201, "certificate-invalid"},
514
    { 202, "certificate-malformed"},
515
    { 203, "certificate-revoked"},
516
    { 204, "unknown-key"},
517
    { 205, "referenced-port-in-error"},
518
    { 206, "not-enabled"},
519
    { 207, "adjust-scope-required"},
520
    { 208, "auth-scope-required"},
521
    { 209, "bind-scope-required"},
522
    { 210, "config-scope-required"},
523
    { 211, "control-scope-required"},
524
    { 212, "extended-scope-required"},
525
    { 213, "incorrect-client"},
526
    { 214, "install-scope-required"},
527
    { 215, "insufficient-scope"},
528
    { 216, "no-default-scope"},
529
    { 217, "no-policy"},
530
    { 218, "revoked-token"},
531
    { 219, "override-scope-required"},
532
    { 220, "inactive-token"},
533
    { 221, "unknown-audience"},
534
    { 222, "unknown-client"},
535
    { 223, "unknown-scope"},
536
    { 224, "view-scope-required"},
537
    { 225, "incorrect-audience"},
538
    { 226, "incorrect-client-origin"},
539
    { 227, "invalid-array-size"},
540
    { 228, "incorrect-issuer"},
541
    { 229, "invalid-token"},
542
    { 0,   NULL}
543
/* Enumerated values 0-255 are reserved for definition by ASHRAE.
544
   Enumerated values 256-65535 may be used by others subject to the
545
   procedures and constraints described in Clause 23. */
546
};
547
548
static int * const bscvlc_control_flags[] = {
549
  &hf_bscvlc_control_data_option,
550
  &hf_bscvlc_control_destination_option,
551
  &hf_bscvlc_control_destination_address,
552
  &hf_bscvlc_control_origin_address,
553
  &hf_bscvlc_control_reserved,
554
  NULL
555
};
556
557
static int * const bscvlc_header_flags[] = {
558
  &hf_bscvlc_header_opt_type,
559
  &hf_bscvlc_header_opt_data,
560
  &hf_bscvlc_header_opt_must_understand,
561
  &hf_bscvlc_header_opt_more,
562
  NULL
563
};
564
565
static int
566
// NOLINTNEXTLINE(misc-no-recursion)
567
dissect_ipv4_bvlc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
568
0
{
569
570
0
  proto_item *ti;
571
0
  proto_item *ti_bdt;
572
0
  proto_item *ti_fdt;
573
0
  proto_tree *bvlc_tree;
574
0
  proto_tree *bdt_tree; /* Broadcast Distribution Table */
575
0
  proto_tree *fdt_tree; /* Foreign Device Table */
576
577
0
  int offset;
578
0
  uint8_t bvlc_type;
579
0
  uint8_t bvlc_function;
580
0
  uint16_t bvlc_length;
581
0
  uint16_t packet_length;
582
0
  unsigned npdu_length;
583
0
  unsigned length_remaining;
584
0
  tvbuff_t *next_tvb;
585
586
0
  offset = 0;
587
588
0
  bvlc_type = tvb_get_uint8(tvb, offset);
589
0
  bvlc_function = tvb_get_uint8(tvb, offset + 1);
590
0
  packet_length = tvb_get_ntohs(tvb, offset + 2);
591
0
  length_remaining = tvb_reported_length_remaining(tvb, offset);
592
593
0
  if (bvlc_function > 0x08) {
594
    /*  We have a constant header length of BVLC of 4 in every
595
     *  BVLC-packet forewarding an NPDU. Beware: Changes in the
596
     *  BACnet-IP-standard may break this.
597
     */
598
0
    bvlc_length = 4;
599
0
  } else if (bvlc_function == 0x04) {
600
    /* 4 Bytes + 6 Bytes for B/IP Address of Originating Device */
601
0
    bvlc_length = 10;
602
0
  } else {
603
    /*  BVLC-packets with function below 0x09 contain
604
     *  routing-level data (e.g. Broadcast Distribution)
605
     *  but no NPDU for BACnet, so bvlc_length goes up to the end
606
     *  of the captured frame.
607
     */
608
0
    bvlc_length = packet_length;
609
0
  }
610
611
0
  if (bvlc_length < 4 || bvlc_length > packet_length) {
612
0
    return 0; /* reject */
613
0
  }
614
615
  /* Put the BVLC Type in the info column */
616
0
  col_append_fstr(pinfo->cinfo, COL_INFO, " BVLC Function %s ",
617
0
      val_to_str_const(bvlc_function, bvlc_function_names, "unknown"));
618
619
0
  ti = proto_tree_add_item(tree, proto_bvlc, tvb, 0, bvlc_length, ENC_NA);
620
0
  bvlc_tree = proto_item_add_subtree(ti, ett_bvlc);
621
0
  proto_tree_add_uint(bvlc_tree, hf_bvlc_type, tvb, offset, 1,
622
0
    bvlc_type);
623
0
  offset++;
624
0
  proto_tree_add_uint(bvlc_tree, hf_bvlc_function, tvb,
625
0
    offset, 1, bvlc_function);
626
0
  offset++;
627
0
  if (length_remaining != packet_length)
628
0
    proto_tree_add_uint_format_value(bvlc_tree, hf_bvlc_length, tvb, offset,
629
0
      2, bvlc_length,
630
0
      "%d of %d bytes (invalid length - expected %d bytes)",
631
0
      bvlc_length, packet_length, length_remaining);
632
0
  else
633
0
    proto_tree_add_uint_format_value(bvlc_tree, hf_bvlc_length, tvb, offset,
634
0
      2, bvlc_length, "%d of %d bytes BACnet packet length",
635
0
      bvlc_length, packet_length);
636
0
  offset += 2;
637
0
  switch (bvlc_function) {
638
0
  case 0x00: /* BVLC-Result */
639
    /* I don't know why the result code is encoded in 4 nibbles,
640
     * but only using one: 0x00r0. Shifting left 4 bits.
641
     */
642
    /* We should bitmask the result correctly when we have a
643
     * packet to dissect, see README.developer, 1.6.2, FID */
644
0
    proto_tree_add_item(bvlc_tree, hf_bvlc_result_ip4, tvb,
645
0
      offset, 2, ENC_BIG_ENDIAN);
646
    /*offset += 2;*/
647
0
    break;
648
0
  case 0x01: /* Write-Broadcast-Distribution-Table */
649
0
  case 0x03: /* Read-Broadcast-Distribution-Table-Ack */
650
    /* List of BDT Entries: N*10-octet */
651
0
    ti_bdt = proto_tree_add_item(bvlc_tree, proto_bvlc, tvb,
652
0
      offset, bvlc_length-4, ENC_NA);
653
0
    bdt_tree = proto_item_add_subtree(ti_bdt, ett_bdt);
654
    /* List of BDT Entries: N*10-octet */
655
0
    while ((bvlc_length - offset) > 9) {
656
0
      proto_tree_add_item(bdt_tree, hf_bvlc_bdt_ip,
657
0
        tvb, offset, 4, ENC_BIG_ENDIAN);
658
0
      offset += 4;
659
0
      proto_tree_add_item(bdt_tree, hf_bvlc_bdt_port,
660
0
        tvb, offset, 2, ENC_BIG_ENDIAN);
661
0
      offset += 2;
662
0
      proto_tree_add_item(bdt_tree,
663
0
        hf_bvlc_bdt_mask, tvb, offset, 4,
664
0
        ENC_NA);
665
0
      offset += 4;
666
0
    }
667
    /* We check this if we get a BDT-packet somewhere */
668
0
    break;
669
0
  case 0x02: /* Read-Broadcast-Distribution-Table */
670
    /* nothing to do here */
671
0
    break;
672
0
  case 0x05: /* Register-Foreign-Device */
673
    /* Time-to-Live 2-octets T, Time-to-Live T, in seconds */
674
0
    proto_tree_add_item(bvlc_tree, hf_bvlc_reg_ttl,
675
0
      tvb, offset, 2, ENC_BIG_ENDIAN);
676
    /*offset += 2;*/
677
0
    break;
678
0
  case 0x06: /* Read-Foreign-Device-Table */
679
    /* nothing to do here */
680
0
    break;
681
0
  case 0x07: /* Read-Foreign-Device-Table-Ack */
682
    /* List of FDT Entries: N*10-octet */
683
    /* N indicates the number of entries in the FDT whose
684
     * contents are being returned. Each returned entry
685
     * consists of the 6-octet B/IP address of the registrant;
686
     * the 2-octet Time-to-Live value supplied at the time of
687
     * registration; and a 2-octet value representing the
688
     * number of seconds remaining before the BBMD will purge
689
     * the registrant's FDT entry if no re-registration occurs.
690
     */
691
0
    ti_fdt = proto_tree_add_item(bvlc_tree, proto_bvlc, tvb,
692
0
      offset, bvlc_length -4, ENC_NA);
693
0
    fdt_tree = proto_item_add_subtree(ti_fdt, ett_fdt);
694
    /* List of FDT Entries: N*10-octet */
695
0
    while ((bvlc_length - offset) > 9) {
696
0
      proto_tree_add_item(fdt_tree, hf_bvlc_fdt_ip,
697
0
        tvb, offset, 4, ENC_BIG_ENDIAN);
698
0
      offset += 4;
699
0
      proto_tree_add_item(fdt_tree, hf_bvlc_fdt_port,
700
0
        tvb, offset, 2, ENC_BIG_ENDIAN);
701
0
      offset += 2;
702
0
      proto_tree_add_item(fdt_tree,
703
0
        hf_bvlc_fdt_ttl, tvb, offset, 2,
704
0
        ENC_BIG_ENDIAN);
705
0
      offset += 2;
706
0
      proto_tree_add_item(fdt_tree,
707
0
        hf_bvlc_fdt_timeout, tvb, offset, 2,
708
0
        ENC_BIG_ENDIAN);
709
0
      offset += 2;
710
0
    }
711
    /* We check this if we get a FDT-packet somewhere */
712
0
    break;
713
0
  case 0x08: /* Delete-Foreign-Device-Table-Entry */
714
    /* FDT Entry: 6-octets */
715
0
    proto_tree_add_item(bvlc_tree, hf_bvlc_fdt_ip,
716
0
      tvb, offset, 4, ENC_BIG_ENDIAN);
717
0
    offset += 4;
718
0
    proto_tree_add_item(bvlc_tree, hf_bvlc_fdt_port,
719
0
      tvb, offset, 2, ENC_BIG_ENDIAN);
720
    /*offset += 2;*/
721
0
    break;
722
0
  case 0x0C: /* Secure-BVLL */
723
0
    offset = bacnet_dissect_sec_wrapper(tvb, pinfo, tree, offset, NULL);
724
0
    if (offset < 0) {
725
0
      call_data_dissector(tvb, pinfo, tree);
726
0
      return tvb_captured_length(tvb);
727
0
    }
728
0
    increment_dissection_depth(pinfo);
729
0
    dissect_ipv4_bvlc(tvb, pinfo, tree, data);
730
0
    decrement_dissection_depth(pinfo);
731
0
    break;
732
    /* We check this if we get a FDT-packet somewhere */
733
0
  case 0x04:  /* Forwarded-NPDU
734
       * Why is this 0x04? It would have been a better
735
       * idea to append all forewarded NPDUs at the
736
       * end of the function table in the B/IP-standard!
737
       */
738
    /* proto_tree_add_bytes_format(); */
739
0
    proto_tree_add_item(bvlc_tree, hf_bvlc_fwd_ip,
740
0
      tvb, offset, 4, ENC_BIG_ENDIAN);
741
0
    offset += 4;
742
0
    proto_tree_add_item(bvlc_tree, hf_bvlc_fwd_port,
743
0
      tvb, offset, 2, ENC_BIG_ENDIAN);
744
    /*offset += 2;*/
745
0
    break;
746
0
  default:
747
    /* Distribute-Broadcast-To-Network
748
     * Original-Unicast-NPDU
749
     * Original-Broadcast-NPDU
750
     * Going to the next dissector...
751
     */
752
0
    break;
753
0
  }
754
755
  /* Ok, no routing information BVLC packet. Dissect as
756
   * BACnet NPDU
757
   */
758
0
  npdu_length = packet_length - bvlc_length;
759
0
  next_tvb = tvb_new_subset_length(tvb, bvlc_length, npdu_length);
760
  /* Code from Guy Harris */
761
0
  if (!dissector_try_uint(bvlc_dissector_table,
762
0
    bvlc_function, next_tvb, pinfo, tree)) {
763
    /* Unknown function - dissect the payload as data */
764
0
    call_data_dissector(next_tvb, pinfo, tree);
765
0
  }
766
0
  return tvb_reported_length(tvb);
767
0
}
768
769
static int
770
// NOLINTNEXTLINE(misc-no-recursion)
771
dissect_ipv6_bvlc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
772
59
{
773
59
  proto_item *ti;
774
59
  proto_tree *bvlc_tree;
775
776
59
  int offset;
777
59
  uint8_t bvlc_type;
778
59
  uint8_t bvlc_function;
779
59
  uint16_t bvlc_length = 0;
780
59
  uint16_t packet_length;
781
59
  unsigned npdu_length;
782
59
  unsigned length_remaining;
783
59
  tvbuff_t *next_tvb;
784
785
59
  offset = 0;
786
787
59
  bvlc_type = tvb_get_uint8(tvb, offset);
788
59
  bvlc_function = tvb_get_uint8(tvb, offset + 1);
789
59
  packet_length = tvb_get_ntohs(tvb, offset + 2);
790
59
  length_remaining = tvb_reported_length_remaining(tvb, offset);
791
792
59
  switch (bvlc_function) {
793
0
  case 0x00:
794
0
  case 0x09:
795
0
    bvlc_length = 9;
796
0
    break;
797
0
  case 0x01:
798
0
    bvlc_length = 10;
799
0
    break;
800
0
  case 0x02:
801
0
  case 0x06:
802
0
  case 0x0C:
803
0
    bvlc_length = 7;
804
0
    break;
805
0
  case 0x03:
806
0
  case 0x05:
807
0
  case 0x07:
808
0
    bvlc_length = 10;
809
0
    break;
810
0
  case 0x04:
811
0
    bvlc_length = 28;
812
0
    break;
813
0
  case 0x08:
814
0
  case 0x0A:
815
0
    bvlc_length = 25;
816
0
    break;
817
58
  case 0x0B:
818
58
    bvlc_length = 4;
819
58
    break;
820
1
  default:
821
1
    break;
822
59
  }
823
824
59
  if (bvlc_length > packet_length) {
825
0
    return 0; /* reject */
826
0
  }
827
828
  /* Put the BVLC Type in the info column */
829
59
  col_append_fstr(pinfo->cinfo, COL_INFO, " BVLC Function %s ",
830
59
      val_to_str_const(bvlc_function, bvlc_ipv6_function_names, "unknown"));
831
832
59
  ti = proto_tree_add_item(tree, proto_bvlc, tvb, 0,
833
59
    bvlc_length, ENC_NA);
834
59
  bvlc_tree = proto_item_add_subtree(ti, ett_bvlc);
835
  /* add the BVLC type */
836
59
  proto_tree_add_uint(bvlc_tree, hf_bvlc_type, tvb, offset, 1,
837
59
    bvlc_type);
838
59
  offset++;
839
  /* add the BVLC function */
840
59
  proto_tree_add_uint(bvlc_tree, hf_bvlc_ipv6_function, tvb,
841
59
    offset, 1, bvlc_function);
842
59
  offset++;
843
  /* add the length information */
844
59
  if (length_remaining != packet_length)
845
59
    proto_tree_add_uint_format_value(bvlc_tree, hf_bvlc_length, tvb, offset,
846
59
      2, bvlc_length,
847
59
      "%d of %d bytes (invalid length - expected %d bytes)",
848
59
      bvlc_length, packet_length, length_remaining);
849
0
  else
850
0
    proto_tree_add_uint_format_value(bvlc_tree, hf_bvlc_length, tvb, offset,
851
0
      2, bvlc_length,
852
0
      "%d of %d bytes BACnet packet length",
853
0
      bvlc_length, packet_length);
854
59
  offset += 2;
855
856
  /* add the optional present virtual source address */
857
59
  if (bvlc_function != 0x0B) {
858
1
    proto_tree_add_item(bvlc_tree, hf_bvlc_virt_source, tvb, offset,
859
1
      3, ENC_BIG_ENDIAN);
860
1
    offset += 3;
861
1
  }
862
863
  /* handle additional function parameters */
864
59
  switch (bvlc_function) {
865
0
  case 0x00: /* BVLC-Result */
866
0
    proto_tree_add_item(bvlc_tree, hf_bvlc_result_ip6, tvb,
867
0
      offset, 2, ENC_BIG_ENDIAN);
868
0
    offset += 2;
869
0
    break;
870
0
  case 0x01: /* Original-Unicast-NPDU */
871
0
  case 0x03: /* Address-Resolution */
872
0
  case 0x05: /* Address-Resolution-ACK */
873
0
  case 0x07: /* Virtual-Address-Resolution-ACK */
874
0
    proto_tree_add_item(bvlc_tree, hf_bvlc_virt_dest, tvb, offset,
875
0
      3, ENC_BIG_ENDIAN);
876
0
    offset += 3;
877
0
    break;
878
0
  case 0x04: /* Forwarded-Address-Resolution */
879
0
    proto_tree_add_item(bvlc_tree, hf_bvlc_virt_dest, tvb, offset,
880
0
      3, ENC_BIG_ENDIAN);
881
0
    offset += 3;
882
0
    proto_tree_add_item(bvlc_tree, hf_bvlc_orig_source_addr,
883
0
      tvb, offset, 16, ENC_NA);
884
0
    offset += 16;
885
0
    proto_tree_add_item(bvlc_tree, hf_bvlc_orig_source_port,
886
0
      tvb, offset, 2, ENC_BIG_ENDIAN);
887
0
    offset += 2;
888
0
    break;
889
0
  case 0x08: /* Forwarded-NPDU */
890
0
    proto_tree_add_item(bvlc_tree, hf_bvlc_orig_source_addr,
891
0
      tvb, offset, 16, ENC_NA);
892
0
    offset += 16;
893
0
    proto_tree_add_item(bvlc_tree, hf_bvlc_orig_source_port,
894
0
      tvb, offset, 2, ENC_BIG_ENDIAN);
895
0
    offset += 2;
896
0
    break;
897
0
  case 0x06: /* Virtual-Address-Resolution */
898
0
    break;
899
0
  case 0x09: /* Register-Foreign-Device */
900
0
    proto_tree_add_item(bvlc_tree, hf_bvlc_reg_ttl,
901
0
      tvb, offset, 2, ENC_BIG_ENDIAN);
902
0
    offset += 2;
903
0
    break;
904
0
  case 0x0A: /* Delete-Foreign-Device-Table-Entry */
905
0
    proto_tree_add_item(bvlc_tree, hf_bvlc_fdt_ipv6,
906
0
      tvb, offset, 16, ENC_NA);
907
0
    offset += 16;
908
0
    proto_tree_add_item(bvlc_tree, hf_bvlc_fdt_port,
909
0
      tvb, offset, 2, ENC_BIG_ENDIAN);
910
0
    offset += 2;
911
0
    break;
912
58
  case 0x0B: /* Secure-BVLL */
913
58
    offset = bacnet_dissect_sec_wrapper(tvb, pinfo, tree, offset, NULL);
914
58
    if (offset < 0) {
915
0
      call_data_dissector(tvb, pinfo, tree);
916
0
      return tvb_captured_length(tvb);
917
0
    }
918
58
    increment_dissection_depth(pinfo);
919
58
    dissect_ipv6_bvlc(tvb, pinfo, tree, data);
920
58
    decrement_dissection_depth(pinfo);
921
58
    break;
922
0
  case 0x02: /* Original-Broadcast-NPDU */
923
0
  case 0x0c: /* Distribute-Broadcast-To-Network */
924
1
  default:
925
    /*
926
     * Going to the next dissector...
927
     */
928
1
    break;
929
59
  }
930
931
  /* Ok, no routing information BVLC packet. Dissect as
932
   * BACnet NPDU
933
   */
934
1
  npdu_length = packet_length - offset;
935
1
  next_tvb = tvb_new_subset_length(tvb, offset, npdu_length);
936
  /* Code from Guy Harris */
937
1
  if ( ! dissector_try_uint(bvlc_ipv6_dissector_table,
938
1
    bvlc_function, next_tvb, pinfo, tree)) {
939
    /* Unknown function - dissect the payload as data */
940
1
    call_data_dissector(next_tvb, pinfo, tree);
941
1
  }
942
943
1
  return tvb_reported_length(tvb);
944
59
}
945
946
static int
947
dissect_bvlc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
948
7
{
949
7
  uint8_t bvlc_type;
950
7
  unsigned ret = 0;
951
952
7
  bvlc_type = tvb_get_uint8(tvb, 0);
953
954
  /*
955
   * Simple sanity check - make sure the type is one we know about.
956
   */
957
7
  if (try_val_to_str(bvlc_type, bvlc_types) == NULL)
958
1
    return 0;
959
960
6
  col_set_str(pinfo->cinfo, COL_PROTOCOL, "BVLC");
961
6
  col_set_str(pinfo->cinfo, COL_INFO, "BACnet Virtual Link Control");
962
963
6
  switch (bvlc_type)
964
6
  {
965
0
  case BACNET_IP_ANNEX_J:
966
0
    ret = dissect_ipv4_bvlc(tvb, pinfo, tree, data);
967
0
    break;
968
6
  case BACNET_IPV6_ANNEX_U:
969
6
    ret = dissect_ipv6_bvlc(tvb, pinfo, tree, data);
970
6
    break;
971
6
  }
972
973
1
  return ret;
974
6
}
975
976
static int
977
dissect_bscvlc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
978
0
{
979
0
  proto_item *ti;
980
0
  proto_tree *bvlc_tree;
981
0
  tvbuff_t *next_tvb;
982
0
  int offset;
983
0
  int start;
984
0
  int bvlc_length;
985
0
  int packet_length;
986
0
  int npdu_length = 0;
987
0
  uint8_t bvlc_function;
988
0
  uint8_t bvlc_control;
989
0
  uint8_t bvlc_result;
990
0
  uint8_t hdr_byte;
991
0
  uint8_t option;
992
0
  int8_t mac_buffer[16];
993
0
  unsigned bvlc_message_id;
994
0
  unsigned idx;
995
0
  bool bMustSegment;
996
0
  bool bMoreFlag;
997
0
  bool bDataFlag;
998
0
  const char *pszUnderstand;
999
0
  const char *pszOption;
1000
0
  proto_tree *subtree;
1001
1002
  /* Calculate length of BSCVLC block to get remaining payload length */
1003
0
  offset = 0;
1004
1005
0
  packet_length = tvb_reported_length_remaining(tvb, offset);
1006
0
  if(packet_length < 4)
1007
0
    return 0; /* reject */
1008
1009
  /* Fix part of the header first */
1010
0
  bvlc_function = tvb_get_uint8(tvb, offset++);
1011
0
  bvlc_control = tvb_get_uint8(tvb, offset++);
1012
0
  bvlc_message_id = tvb_get_uint16(tvb, offset, ENC_BIG_ENDIAN);
1013
0
  offset += 2;
1014
1015
  /* Variable part of the header next */
1016
0
  bvlc_length = offset;
1017
1018
0
  if ((bvlc_control & BSCVLC_CONTROL_ORIG_ADDRESS) != 0)
1019
0
    bvlc_length += 6;
1020
1021
0
  if ((bvlc_control & BSCVLC_CONTROL_DEST_ADDRESS) != 0)
1022
0
    bvlc_length += 6;
1023
1024
0
  if ((bvlc_control & BSCVLC_CONTROL_DEST_OPTION) != 0)
1025
0
  {
1026
0
    bMoreFlag = true;
1027
1028
0
    while(tvb_reported_length_remaining(tvb, bvlc_length) > 0 &&
1029
0
          (hdr_byte = tvb_get_uint8(tvb, bvlc_length)) != 0 && bMoreFlag)
1030
0
    {
1031
      /* get flags and type... */
1032
0
      bMoreFlag = (hdr_byte & BSCVLC_HDR_MORE_OPTIONS_FOLLOW);
1033
0
      bDataFlag = (hdr_byte & BSCVLC_HDR_DATA_PRESENT);
1034
0
      bvlc_length++;
1035
1036
0
      if(bDataFlag)
1037
0
      {
1038
0
        npdu_length = (int)(tvb_get_uint8(tvb, bvlc_length++) << 8);
1039
0
        npdu_length += (int)tvb_get_uint8(tvb, bvlc_length++);
1040
0
        bvlc_length += npdu_length;
1041
0
      }
1042
0
    }
1043
0
  }
1044
1045
0
  if ((bvlc_control & BSCVLC_CONTROL_DATA_OPTION) != 0)
1046
0
  {
1047
0
    bMoreFlag = true;
1048
1049
0
    while(tvb_reported_length_remaining(tvb, bvlc_length) > 0 &&
1050
0
          (hdr_byte = tvb_get_uint8(tvb, bvlc_length)) != 0 && bMoreFlag)
1051
0
    {
1052
      /* get flags and type... */
1053
0
      bMoreFlag= (hdr_byte & BSCVLC_HDR_MORE_OPTIONS_FOLLOW);
1054
0
      bDataFlag= (hdr_byte & BSCVLC_HDR_DATA_PRESENT);
1055
0
      bvlc_length++;
1056
1057
0
      if(bDataFlag)
1058
0
      {
1059
0
        npdu_length = (int)(tvb_get_uint8(tvb, bvlc_length++) << 8);
1060
0
        npdu_length += (int)tvb_get_uint8(tvb, bvlc_length++);
1061
0
        bvlc_length += npdu_length;
1062
0
      }
1063
0
    }
1064
0
  }
1065
1066
  /* Now add the BSCVLC payload size for specified function */
1067
0
  switch (bvlc_function)
1068
0
  {
1069
0
  case 0x00: /* BVLC-Result */
1070
0
  case 0x03: /* Address-Resolution-ACK */
1071
0
  case 0x0C: /* Proprietary-Message */
1072
    /* complete packet length because of optional present variable length error data
1073
       but no length encoded for it in the structure of this frame */
1074
0
    bvlc_length = packet_length;
1075
0
    break;
1076
0
  case 0x02: /* Address-Resolution */
1077
0
  case 0x05: /* Advertisement-Solicitation */
1078
0
  case 0x08: /* Disconnect-Request */
1079
0
  case 0x09: /* Disconnect-ACK */
1080
0
  case 0x0A: /* Heartbeat-Request */
1081
0
  case 0x0B: /* Heartbeat-ACK */
1082
    /* No additional payload here */
1083
0
    break;
1084
0
  case 0x04: /* Advertisement */
1085
0
    bvlc_length += 6;
1086
0
    break;
1087
0
  case 0x06: /* Connect-Request */
1088
0
  case 0x07: /* Connect-Accept */
1089
0
    bvlc_length += 26;
1090
0
    break;
1091
0
  case 0x01: /* Encapsulated-NPDU */
1092
0
  default:
1093
    /* The additional payload will be decoded elsewhere */
1094
0
    break;
1095
0
  }
1096
1097
0
  col_set_str(pinfo->cinfo, COL_PROTOCOL, "BSCVLC");
1098
0
  col_set_str(pinfo->cinfo, COL_INFO, "BACnet Secure Connect Virtual Link Control");
1099
1100
  /* Put the BSCVLC Type and Message ID in the info column */
1101
0
  col_append_fstr(pinfo->cinfo, COL_INFO, " BSCVLC Function %s Message-ID %u",
1102
0
      val_to_str_const(bvlc_function, bscvlc_function_names, "unknown"), bvlc_message_id);
1103
1104
  /* Fill the tree... */
1105
0
  offset = 0;
1106
0
  ti = proto_tree_add_item(tree, proto_bscvlc, tvb, 0, bvlc_length, ENC_NA);
1107
0
  bvlc_tree = proto_item_add_subtree(ti, ett_bvlc);
1108
1109
0
  proto_tree_add_uint(bvlc_tree, hf_bscvlc_function, tvb,
1110
0
    offset, 1, bvlc_function);
1111
0
  offset++;
1112
0
  proto_tree_add_bitmask(bvlc_tree, tvb, offset, hf_bscvlc_control,
1113
0
        ett_bscvlc_ctrl, bscvlc_control_flags, ENC_NA);
1114
0
  offset ++;
1115
0
  proto_tree_add_uint(bvlc_tree, hf_bscvlc_msg_id, tvb,
1116
0
    offset, 2, bvlc_message_id);
1117
0
  offset += 2;
1118
1119
0
  if ((bvlc_control & BSCVLC_CONTROL_ORIG_ADDRESS) != 0)
1120
0
  {
1121
0
    for(idx = 0; idx < 6; idx++)
1122
0
      snprintf(&mac_buffer[idx * 2], sizeof(mac_buffer) - (idx * 2), "%02X", tvb_get_uint8(tvb, offset + idx));
1123
0
    col_append_fstr(pinfo->cinfo, COL_INFO, " SMAC %s", mac_buffer);
1124
1125
0
    proto_tree_add_item(bvlc_tree, hf_bscvlc_orig_vmac, tvb, offset, 6, ENC_NA);
1126
0
    offset += 6;
1127
0
  }
1128
1129
0
  if ((bvlc_control & BSCVLC_CONTROL_DEST_ADDRESS) != 0)
1130
0
  {
1131
0
    for(idx = 0; idx < 6; idx++)
1132
0
      snprintf(&mac_buffer[idx * 2],  sizeof(mac_buffer) - (idx * 2), "%02X", tvb_get_uint8(tvb, offset + idx));
1133
0
    col_append_fstr(pinfo->cinfo, COL_INFO, " DMAC %s", mac_buffer);
1134
1135
0
    proto_tree_add_item(bvlc_tree, hf_bscvlc_dest_vmac, tvb, offset, 6, ENC_NA);
1136
0
    offset += 6;
1137
0
  }
1138
1139
0
  if ((bvlc_control & BSCVLC_CONTROL_DEST_OPTION) != 0)
1140
0
  {
1141
0
    bMoreFlag = true;
1142
1143
0
    while(tvb_reported_length_remaining(tvb, offset) > 0 &&
1144
0
          (hdr_byte = tvb_get_uint8(tvb, offset)) != 0 && bMoreFlag)
1145
0
    {
1146
      /* get flags and type... */
1147
0
      option = (hdr_byte & BSCVLC_HDR_OPTION_TYPE_MASK);
1148
0
      bMustSegment = (hdr_byte & BSCVLC_HDR_MUST_UNDERSTAND);
1149
0
      bMoreFlag = (hdr_byte & BSCVLC_HDR_MORE_OPTIONS_FOLLOW);
1150
0
      bDataFlag = (hdr_byte & BSCVLC_HDR_DATA_PRESENT);
1151
0
      start = offset;
1152
1153
0
      offset++;
1154
1155
0
      if(bDataFlag)
1156
0
      {
1157
0
        npdu_length = (int)(tvb_get_uint8(tvb, offset++) << 8);
1158
0
        npdu_length += (int)tvb_get_uint8(tvb, offset++);
1159
0
        offset += npdu_length;
1160
0
      }
1161
1162
0
      if(bMustSegment)
1163
0
        pszUnderstand = "must understand";
1164
0
      else
1165
0
        pszUnderstand = "optional";
1166
1167
0
      switch(option)
1168
0
      {
1169
0
      case BSCVLC_HDR_OPT_SECURE_PATH:
1170
0
        pszOption = "secure path";
1171
0
        break;
1172
0
      case BSCVLC_HDR_OPT_HELLO:
1173
0
        pszOption = "hello";
1174
0
        break;
1175
0
      case BSCVLC_HDR_OPT_IDENTITY:
1176
0
        pszOption = "identity";
1177
0
        break;
1178
0
      case BSCVLC_HDR_OPT_HINT:
1179
0
        pszOption = "hint";
1180
0
        break;
1181
0
      case BSCVLC_HDR_OPT_TOKEN:
1182
0
        pszOption = "token";
1183
0
        break;
1184
0
      case BSCVLC_HDR_OPT_PROPRIETARY:
1185
0
        pszOption = "proprietary";
1186
0
        break;
1187
0
      default:
1188
0
        pszOption = "reserved by ASHREA";
1189
0
        break;
1190
0
      }
1191
1192
0
      subtree = proto_tree_add_subtree_format(bvlc_tree, tvb, start, offset - start,
1193
0
          ett_bscvlc_hdr, NULL, "Destination %s option %s", pszUnderstand, pszOption);
1194
0
      proto_tree_add_bitmask_value(subtree, tvb, start, hf_bscvlc_header,
1195
0
        ett_bscvlc_hdr, bscvlc_header_flags, hdr_byte);
1196
1197
0
      if(bDataFlag)
1198
0
      {
1199
0
        proto_tree_add_item(subtree, hf_bscvlc_header_length, tvb, start + 1, 2, ENC_BIG_ENDIAN);
1200
0
        switch(option)
1201
0
        {
1202
0
        case BSCVLC_HDR_OPT_HELLO:
1203
0
          proto_tree_add_bitmask_value(subtree, tvb, start + 3, hf_bscvlc_hello_opt,
1204
0
            ett_bscvlc_hdr, bscvlc_hello1_opt_flags, tvb_get_uint8(tvb, start + 3));
1205
0
          break;
1206
0
        case BSCVLC_HDR_OPT_IDENTITY:
1207
0
          proto_tree_add_item(subtree, hf_bscvlc_identity_device_id, tvb, start + 3, 3, ENC_BIG_ENDIAN);
1208
0
          break;
1209
0
        case BSCVLC_HDR_OPT_HINT:
1210
0
          bacnet_dissect_scope(tvb_new_subset_length(tvb, start, npdu_length + 3), pinfo, subtree, 3, "scope: ");
1211
0
          break;
1212
0
        case BSCVLC_HDR_OPT_TOKEN:
1213
0
          bacnet_dissect_token(tvb_new_subset_length(tvb, start, npdu_length + 3), pinfo, subtree, 3, "token: ");
1214
0
          break;
1215
0
        default:
1216
0
          proto_tree_add_item(subtree, hf_bscvlc_header_data, tvb, start + 3, npdu_length, ENC_NA);
1217
0
          break;
1218
0
        }
1219
0
      }
1220
0
    }
1221
0
  }
1222
1223
0
  if ((bvlc_control & BSCVLC_CONTROL_DATA_OPTION) != 0)
1224
0
  {
1225
0
    bMoreFlag = true;
1226
1227
0
    while(tvb_reported_length_remaining(tvb, offset) > 0 &&
1228
0
          (hdr_byte = tvb_get_uint8(tvb, offset)) != 0 && bMoreFlag)
1229
0
    {
1230
      /* get flags and type... */
1231
0
      option = (hdr_byte & BSCVLC_HDR_OPTION_TYPE_MASK);
1232
0
      bMustSegment = (hdr_byte & BSCVLC_HDR_EVERY_SEGMENT);
1233
0
      bMoreFlag = (hdr_byte & BSCVLC_HDR_MORE_OPTIONS_FOLLOW);
1234
0
      bDataFlag = (hdr_byte & BSCVLC_HDR_DATA_PRESENT);
1235
0
      start = offset;
1236
1237
0
      offset++;
1238
1239
0
      if(bDataFlag)
1240
0
      {
1241
0
        npdu_length = (int)(tvb_get_uint8(tvb, offset++) << 8);
1242
0
        npdu_length += (int)tvb_get_uint8(tvb, offset++);
1243
0
        offset += npdu_length;
1244
0
      }
1245
1246
0
      if(bMustSegment)
1247
0
        pszUnderstand = "must understand";
1248
0
      else
1249
0
        pszUnderstand = "optional";
1250
1251
0
      switch(option)
1252
0
      {
1253
0
      case BSCVLC_HDR_OPT_SECURE_PATH:
1254
0
        pszOption = "secure path";
1255
0
        break;
1256
0
      case BSCVLC_HDR_OPT_HELLO:
1257
0
        pszOption = "hello";
1258
0
        break;
1259
0
      case BSCVLC_HDR_OPT_IDENTITY:
1260
0
        pszOption = "identity";
1261
0
        break;
1262
0
      case BSCVLC_HDR_OPT_HINT:
1263
0
        pszOption = "hint";
1264
0
        break;
1265
0
      case BSCVLC_HDR_OPT_TOKEN:
1266
0
        pszOption = "token";
1267
0
        break;
1268
0
      case BSCVLC_HDR_OPT_PROPRIETARY:
1269
0
        pszOption = "proprietary";
1270
0
        break;
1271
0
      default:
1272
0
        pszOption = "reserved by ASHREA";
1273
0
        break;
1274
0
      }
1275
1276
0
      subtree = proto_tree_add_subtree_format(bvlc_tree, tvb, start, offset - start,
1277
0
          ett_bscvlc_hdr, NULL, "Data %s option %s", pszUnderstand, pszOption);
1278
0
      proto_tree_add_bitmask_value(subtree, tvb, start, hf_bscvlc_header,
1279
0
        ett_bscvlc_hdr, bscvlc_header_flags, hdr_byte);
1280
1281
0
      if(bDataFlag)
1282
0
      {
1283
0
        proto_tree_add_item(subtree, hf_bscvlc_header_length, tvb, start + 1, 2, ENC_BIG_ENDIAN);
1284
0
        switch(option)
1285
0
        {
1286
0
        case BSCVLC_HDR_OPT_HELLO:
1287
0
          proto_tree_add_bitmask_value(subtree, tvb, start + 3, hf_bscvlc_hello_opt,
1288
0
            ett_bscvlc_hdr, bscvlc_hello1_opt_flags, tvb_get_uint8(tvb, start + 3));
1289
0
          break;
1290
0
        case BSCVLC_HDR_OPT_IDENTITY:
1291
0
          proto_tree_add_item(subtree, hf_bscvlc_identity_device_id, tvb, start + 3, 3, ENC_BIG_ENDIAN);
1292
0
          break;
1293
0
        case BSCVLC_HDR_OPT_HINT:
1294
0
          bacnet_dissect_scope(tvb_new_subset_length(tvb, start, npdu_length + 3), pinfo, subtree, 3, "scope: ");
1295
0
          break;
1296
0
        case BSCVLC_HDR_OPT_TOKEN:
1297
0
          bacnet_dissect_token(tvb_new_subset_length(tvb, start, npdu_length + 3), pinfo, subtree, 3, "token: ");
1298
0
          break;
1299
0
        default:
1300
0
          proto_tree_add_item(subtree, hf_bscvlc_header_data, tvb, start + 3, npdu_length, ENC_NA);
1301
0
          break;
1302
0
        }
1303
0
      }
1304
0
    }
1305
0
  }
1306
1307
0
  switch (bvlc_function)
1308
0
  {
1309
0
  case 0x02: /* Address-Resolution */
1310
0
  case 0x05: /* Advertisement-Solicitation */
1311
0
  case 0x08: /* Disconnect-Request */
1312
0
  case 0x09: /* Disconnect-ACK */
1313
0
  case 0x0A: /* Heartbeat-Request */
1314
0
  case 0x0B: /* Heartbeat-ACK */
1315
0
    break;
1316
0
  case 0x00: /* BVLC-Result */
1317
0
    subtree = proto_tree_add_subtree_format(bvlc_tree, tvb, offset, packet_length - offset,
1318
0
        ett_bscvlc_hdr, NULL, "%s", "BVLC-Result");
1319
0
    proto_tree_add_item(subtree, hf_bscvlc_function, tvb,
1320
0
        offset, 1, ENC_NA);
1321
0
    offset++;
1322
0
    proto_tree_add_item(subtree, hf_bscvlc_result, tvb,
1323
0
        offset, 1, ENC_NA);
1324
0
    bvlc_result = tvb_get_uint8(tvb, offset);
1325
0
    offset++;
1326
1327
0
    col_append_fstr(pinfo->cinfo, COL_INFO, " %s",
1328
0
        val_to_str_const(bvlc_result, bscvlc_result_names, "unknown"));
1329
1330
0
    if(bvlc_result)
1331
0
    {
1332
0
      proto_tree_add_item(subtree, hf_bscvlc_header_marker, tvb,
1333
0
          offset, 1, ENC_NA);
1334
0
      offset++;
1335
0
      proto_tree_add_item(subtree, hf_bscvlc_error_class, tvb,
1336
0
          offset, 2, ENC_BIG_ENDIAN);
1337
0
      offset += 2;
1338
0
      proto_tree_add_item(subtree, hf_bscvlc_error_code, tvb,
1339
0
          offset, 2, ENC_BIG_ENDIAN);
1340
0
      offset += 2;
1341
0
      proto_tree_add_item(subtree, hf_bscvlc_result_data, tvb,
1342
0
          offset, packet_length - offset, ENC_NA);
1343
0
    }
1344
    /* Force and of packet */
1345
0
    offset = packet_length;
1346
0
    break;
1347
0
  case 0x03: /* Address-Resolution-ACK */
1348
0
    subtree = proto_tree_add_subtree_format(bvlc_tree, tvb, offset, packet_length - offset,
1349
0
        ett_bscvlc_hdr, NULL, "%s", "Address-Resolution-ACK");
1350
0
    proto_tree_add_item(subtree, hf_bscvlc_uris, tvb,
1351
0
        offset, packet_length - offset, ENC_NA);
1352
    /* Force and of packet */
1353
0
    offset = packet_length;
1354
0
    break;
1355
0
  case 0x04: /* Advertisement */
1356
0
    subtree = proto_tree_add_subtree_format(bvlc_tree, tvb, offset, packet_length - offset,
1357
0
        ett_bscvlc_hdr, NULL, "%s", "Advertisement");
1358
0
    proto_tree_add_item(subtree, hf_bscvlc_hub_conn_state, tvb,
1359
0
        offset, 1, ENC_NA);
1360
0
    offset++;
1361
0
    proto_tree_add_item(subtree, hf_bscvlc_accept_conns, tvb,
1362
0
        offset, 1, ENC_NA);
1363
0
    offset++;
1364
0
    proto_tree_add_item(subtree, hf_bscvlc_max_bvlc_length, tvb,
1365
0
        offset, 2, ENC_BIG_ENDIAN);
1366
0
    offset += 2;
1367
0
    proto_tree_add_item(subtree, hf_bscvlc_max_npdu_length, tvb,
1368
0
        offset, 2, ENC_BIG_ENDIAN);
1369
0
    offset += 2;
1370
0
    break;
1371
0
  case 0x06: /* Connect-Request */
1372
0
    subtree = proto_tree_add_subtree_format(bvlc_tree, tvb, offset, packet_length - offset,
1373
0
        ett_bscvlc_hdr, NULL, "%s", "Connect-Request");
1374
0
    proto_tree_add_item(subtree, hf_bscvlc_connect_vmac, tvb,
1375
0
        offset, 6, ENC_NA);
1376
0
    offset += 6;
1377
0
    proto_tree_add_item(subtree, hf_bscvlc_connect_uuid, tvb,
1378
0
        offset, 16, ENC_NA);
1379
0
    offset += 16;
1380
0
    proto_tree_add_item(subtree, hf_bscvlc_max_bvlc_length, tvb,
1381
0
        offset, 2, ENC_BIG_ENDIAN);
1382
0
    offset += 2;
1383
0
    proto_tree_add_item(subtree, hf_bscvlc_max_npdu_length, tvb,
1384
0
        offset, 2, ENC_BIG_ENDIAN);
1385
0
    offset += 2;
1386
0
    break;
1387
0
  case 0x07: /* Connect-Accept */
1388
0
    subtree = proto_tree_add_subtree_format(bvlc_tree, tvb, offset, packet_length - offset,
1389
0
        ett_bscvlc_hdr, NULL, "%s", "Connect-Accept");
1390
0
    proto_tree_add_item(subtree, hf_bscvlc_connect_vmac, tvb,
1391
0
        offset, 6, ENC_NA);
1392
0
    offset += 6;
1393
0
    proto_tree_add_item(subtree, hf_bscvlc_connect_uuid, tvb,
1394
0
        offset, 16, ENC_NA);
1395
0
    offset += 16;
1396
0
    proto_tree_add_item(subtree, hf_bscvlc_max_bvlc_length, tvb,
1397
0
        offset, 2, ENC_BIG_ENDIAN);
1398
0
    offset += 2;
1399
0
    proto_tree_add_item(subtree, hf_bscvlc_max_npdu_length, tvb,
1400
0
        offset, 2, ENC_BIG_ENDIAN);
1401
0
    offset += 2;
1402
0
    break;
1403
0
  case 0x0C: /* Proprietary-Message */
1404
0
    subtree = proto_tree_add_subtree_format(bvlc_tree, tvb, offset, packet_length - offset,
1405
0
        ett_bscvlc_hdr, NULL, "%s", "Proprietary-Message");
1406
0
    proto_tree_add_item(subtree, hf_bscvlc_vendor_id, tvb,
1407
0
        offset, 2, ENC_BIG_ENDIAN);
1408
0
    offset += 2;
1409
0
    proto_tree_add_item(subtree, hf_bscvlc_proprietary_opt_type, tvb,
1410
0
        offset, 1, ENC_NA);
1411
0
    offset++;
1412
0
    proto_tree_add_item(subtree, hf_bscvlc_proprietary_data, tvb,
1413
0
        offset, packet_length - offset, ENC_NA);
1414
    /* Force and of packet */
1415
0
    offset = packet_length;
1416
0
    break;
1417
0
  case 0x01: /* Encapsulated-NPDU */
1418
0
  default:
1419
    /* Here we assume additional payload belongs to upper layers and will be decoded later */
1420
0
    break;
1421
0
  }
1422
1423
  /* Let the remaining frame to be decoded elsewhere */
1424
0
  npdu_length = packet_length - offset;
1425
0
  next_tvb = tvb_new_subset_length(tvb, offset, npdu_length);
1426
  /* Code from Guy Harris */
1427
0
  if (!dissector_try_uint(bscvlc_dissector_table,
1428
0
    bvlc_function, next_tvb, pinfo, tree)) {
1429
    /* Unknown function - dissect the payload as data */
1430
0
    call_data_dissector(next_tvb, pinfo, tree);
1431
0
  }
1432
1433
0
  return tvb_reported_length(tvb);
1434
0
}
1435
1436
void
1437
proto_register_bvlc(void)
1438
14
{
1439
14
  static hf_register_info hf[] = {
1440
14
    { &hf_bvlc_type,
1441
14
      { "Type",           "bvlc.type",
1442
14
      FT_UINT8, BASE_HEX, VALS(bvlc_types), 0,
1443
14
      NULL, HFILL }
1444
14
    },
1445
14
    { &hf_bvlc_function,
1446
14
      { "Function",           "bvlc.function",
1447
14
      FT_UINT8, BASE_HEX, VALS(bvlc_function_names), 0,
1448
14
      "BVLC Function", HFILL }
1449
14
    },
1450
14
    { &hf_bvlc_ipv6_function,
1451
14
      { "Function",           "bvlc.function_ipv6",
1452
14
      FT_UINT8, BASE_HEX, VALS(bvlc_ipv6_function_names), 0,
1453
14
      "BVLC Function IPV6", HFILL }
1454
14
    },
1455
14
    { &hf_bvlc_length,
1456
14
      { "BVLC-Length",        "bvlc.length",
1457
14
      FT_UINT16, BASE_DEC, NULL, 0,
1458
14
      "Length of BVLC", HFILL }
1459
14
    },
1460
14
    { &hf_bvlc_virt_source,
1461
14
      { "BVLC-Virtual-Source", "bvlc.virtual_source",
1462
14
      FT_UINT24, BASE_DEC_HEX, NULL, 0,
1463
14
      "Virtual source address of BVLC", HFILL }
1464
14
    },
1465
14
    { &hf_bvlc_virt_dest,
1466
14
      { "BVLC-Virtual-Destination", "bvlc.virtual_dest",
1467
14
      FT_UINT24, BASE_DEC_HEX, NULL, 0,
1468
14
      "Virtual destination address of BVLC", HFILL }
1469
14
    },
1470
14
    { &hf_bvlc_result_ip4,
1471
14
      { "Result",           "bvlc.result",
1472
14
      FT_UINT16, BASE_HEX, VALS(bvlc_result_names), 0,
1473
14
      "Result Code", HFILL }
1474
14
    },
1475
14
    { &hf_bvlc_result_ip6,
1476
14
      { "Result",           "bvlc.result",
1477
14
      FT_UINT16, BASE_HEX, VALS(bvlc_ipv6_result_names), 0,
1478
14
      "Result Code", HFILL }
1479
14
    },
1480
14
    { &hf_bvlc_bdt_ip,
1481
14
      { "IP",           "bvlc.bdt_ip",
1482
14
      FT_IPv4, BASE_NONE, NULL, 0,
1483
14
      "BDT IP", HFILL }
1484
14
    },
1485
14
    { &hf_bvlc_bdt_port,
1486
14
      { "Port",           "bvlc.bdt_port",
1487
14
      FT_UINT16, BASE_DEC, NULL, 0,
1488
14
      "BDT Port", HFILL }
1489
14
    },
1490
14
    { &hf_bvlc_bdt_mask,
1491
14
      { "Mask",           "bvlc.bdt_mask",
1492
14
      FT_BYTES, BASE_NONE, NULL, 0,
1493
14
      "BDT Broadcast Distribution Mask", HFILL }
1494
14
    },
1495
14
    { &hf_bvlc_reg_ttl,
1496
14
      { "TTL",           "bvlc.reg_ttl",
1497
14
      FT_UINT16, BASE_DEC, NULL, 0,
1498
14
      "Foreign Device Time To Live", HFILL }
1499
14
    },
1500
14
    { &hf_bvlc_fdt_ip,
1501
14
      { "IP",           "bvlc.fdt_ip",
1502
14
      FT_IPv4, BASE_NONE, NULL, 0,
1503
14
      "FDT IP", HFILL }
1504
14
    },
1505
14
    { &hf_bvlc_fdt_ipv6,
1506
14
      { "IP",           "bvlc.fdt_ipv6",
1507
14
      FT_IPv6, BASE_NONE, NULL, 0,
1508
14
      "FDT IP", HFILL }
1509
14
    },
1510
14
    { &hf_bvlc_fdt_port,
1511
14
      { "Port",           "bvlc.fdt_port",
1512
14
      FT_UINT16, BASE_DEC, NULL, 0,
1513
14
      "FDT Port", HFILL }
1514
14
    },
1515
14
    { &hf_bvlc_fdt_ttl,
1516
14
      { "TTL",           "bvlc.fdt_ttl",
1517
14
      FT_UINT16, BASE_DEC, NULL, 0,
1518
14
      "Foreign Device Time To Live", HFILL }
1519
14
    },
1520
14
    { &hf_bvlc_fdt_timeout,
1521
14
      { "Timeout",           "bvlc.fdt_timeout",
1522
14
      FT_UINT16, BASE_DEC, NULL, 0,
1523
14
      "Foreign Device Timeout (seconds)", HFILL }
1524
14
    },
1525
14
    { &hf_bvlc_fwd_ip,
1526
14
      { "IP",           "bvlc.fwd_ip",
1527
14
      FT_IPv4, BASE_NONE, NULL, 0,
1528
14
      "FWD IP", HFILL }
1529
14
    },
1530
14
    { &hf_bvlc_fwd_port,
1531
14
      { "Port",           "bvlc.fwd_port",
1532
14
      FT_UINT16, BASE_DEC, NULL, 0,
1533
14
      "FWD Port", HFILL }
1534
14
    },
1535
14
    { &hf_bvlc_orig_source_addr,
1536
14
      { "IP",             "bvlc.orig_source_addr",
1537
14
      FT_IPv6, BASE_NONE, NULL, 0,
1538
14
      "ORIG IP", HFILL }
1539
14
    },
1540
14
    { &hf_bvlc_orig_source_port,
1541
14
      { "Port",           "bvlc.orig_source_port",
1542
14
      FT_UINT16, BASE_DEC, NULL, 0,
1543
14
      "ORIG Port", HFILL }
1544
14
    },
1545
14
  };
1546
1547
14
  static int *ett[] = {
1548
14
    &ett_bvlc,
1549
14
    &ett_bdt,
1550
14
    &ett_fdt,
1551
14
  };
1552
1553
14
  static hf_register_info bsc_hf[] = {
1554
14
    { &hf_bscvlc_control,
1555
14
      { "Control",    "bscvlc.control",
1556
14
      FT_UINT8, BASE_HEX, NULL, 0,
1557
14
      "BSCVLC Control", HFILL }
1558
14
    },
1559
14
    { &hf_bscvlc_control_data_option,
1560
14
      { "Data Option",  "bscvlc.control_data_option",
1561
14
      FT_BOOLEAN, 8, TFS(&control_data_option_set_high),
1562
14
      BSCVLC_CONTROL_DATA_OPTION, "BSCVLC Control", HFILL }
1563
14
    },
1564
14
    { &hf_bscvlc_control_destination_option,
1565
14
      { "Destination Option", "bscvlc.control_dest_option",
1566
14
      FT_BOOLEAN, 8, TFS(&control_destination_option_set_high),
1567
14
      BSCVLC_CONTROL_DEST_OPTION, "BSCVLC Control", HFILL }
1568
14
    },
1569
14
    { &hf_bscvlc_control_destination_address,
1570
14
      { "Destination Address","bscvlc.control_dest_address",
1571
14
      FT_BOOLEAN, 8, TFS(&control_destination_address_set_high),
1572
14
      BSCVLC_CONTROL_DEST_ADDRESS, "BSCVLC Control", HFILL }
1573
14
    },
1574
14
    { &hf_bscvlc_control_origin_address,
1575
14
      { "Origin Address", "bscvlc.control_orig_address",
1576
14
      FT_BOOLEAN, 8, TFS(&control_orig_address_set_high),
1577
14
      BSCVLC_CONTROL_ORIG_ADDRESS, "BSCVLC Control", HFILL }
1578
14
    },
1579
14
    { &hf_bscvlc_control_reserved,
1580
14
      { "Reserved", "bscvlc.control_reserved",
1581
14
      FT_BOOLEAN, 8, TFS(&control_reserved_set_high),
1582
14
      BSCVLC_CONTROL_RESERVED, "BSCVLC Control", HFILL }
1583
14
    },
1584
14
    { &hf_bscvlc_header,
1585
14
      { "Header Data Length", "bscvlc.header",
1586
14
      FT_UINT8, BASE_HEX, NULL, 0,
1587
14
      "BSCVLC Header Control Data", HFILL }
1588
14
    },
1589
14
    { &hf_bscvlc_header_marker,
1590
14
      { "Header Error Marker","bscvlc.header_error_marker",
1591
14
      FT_UINT8, BASE_HEX, NULL, 0,
1592
14
      "BSCVLC Header Error Marker", HFILL }
1593
14
    },
1594
14
    { &hf_bscvlc_header_length,
1595
14
      { "Header Data Length", "bscvlc.header_length",
1596
14
      FT_UINT16, BASE_DEC, NULL, 0,
1597
14
      "BSCVLC Header Data Length", HFILL }
1598
14
    },
1599
14
    { &hf_bscvlc_header_data,
1600
14
      { "Header Data",  "bscvlc.header_data",
1601
14
      FT_BYTES, BASE_NONE, NULL, 0,
1602
14
      "BSCVLC Header Option", HFILL }
1603
14
    },
1604
14
    { &hf_bscvlc_header_opt_type,
1605
14
      { "Header Type",  "bscvlc.header_type",
1606
14
      FT_UINT8, BASE_HEX, VALS(bscvlc_header_type_names),
1607
14
      BSCVLC_HDR_OPTION_TYPE_MASK, "BSCVLC Header Option", HFILL }
1608
14
    },
1609
14
    { &hf_bscvlc_header_opt_data,
1610
14
      { "Header Data",  "bscvlc.header_data_present",
1611
14
      FT_BOOLEAN, 8, TFS(&header_opt_data_set_high),
1612
14
      BSCVLC_HDR_DATA_PRESENT, "BSCVLC Header Option", HFILL }
1613
14
    },
1614
14
    { &hf_bscvlc_header_opt_must_understand,
1615
14
      { "Header Must Understand","bscvlc.header_understand",
1616
14
      FT_BOOLEAN, 8, TFS(&header_opt_must_understand_set_high),
1617
14
      BSCVLC_HDR_MUST_UNDERSTAND, "BSCVLC Header Option", HFILL }
1618
14
    },
1619
14
    { &hf_bscvlc_header_opt_more,
1620
14
      { "Header More",  "bscvlc.header_more",
1621
14
      FT_BOOLEAN, 8, TFS(&header_opt_more_set_high),
1622
14
      BSCVLC_HDR_MORE_OPTIONS_FOLLOW, "BSCVLC Header Option", HFILL }
1623
14
    },
1624
14
    { &hf_bscvlc_vendor_id,
1625
14
      { "Vendor ID",          "bscvlc.vendor_id",
1626
14
      FT_UINT16, BASE_HEX, NULL, 0,
1627
14
      "BSCVLC Vendor ID", HFILL }
1628
14
    },
1629
14
    { &hf_bscvlc_proprietary_opt_type,
1630
14
      { "Proprietary Type", "bscvlc.proprietary_type",
1631
14
      FT_UINT8, BASE_HEX, NULL, 0,
1632
14
      "BSCVLC Proprietary Type", HFILL }
1633
14
    },
1634
14
    { &hf_bscvlc_proprietary_data,
1635
14
      { "Proprietary Data", "bscvlc.proprietary_data",
1636
14
      FT_BYTES, BASE_NONE, NULL, 0,
1637
14
      "BSCVLC Proprietary Data", HFILL }
1638
14
    },
1639
14
    { &hf_bscvlc_hub_conn_state,
1640
14
      { "Hub Connection Status","bscvlc.hub_conn_state",
1641
14
      FT_UINT8, BASE_HEX, VALS(bscvlc_hub_conn_state_names), 0,
1642
14
      "BSCVLC Hub Connection Status", HFILL }
1643
14
    },
1644
14
    { &hf_bscvlc_accept_conns,
1645
14
      { "Hub Accepts Connections","bscvlc.accept_conns",
1646
14
      FT_UINT8, BASE_HEX, VALS(bscvlc_hub_accept_conns_names), 0,
1647
14
      "BSCVLC Accepts Connections", HFILL }
1648
14
    },
1649
14
    { &hf_bscvlc_max_bvlc_length,
1650
14
      { "Max. BVLC Length", "bscvlc.max_bvlc_length",
1651
14
      FT_UINT16, BASE_DEC, NULL, 0,
1652
14
      "Max Supported BVLC Length", HFILL }
1653
14
    },
1654
14
    { &hf_bscvlc_max_npdu_length,
1655
14
      { "Max. NPDU Length", "bscvlc.max_npdu_length",
1656
14
      FT_UINT16, BASE_DEC, NULL, 0,
1657
14
      "Max Supported NPDU Length", HFILL }
1658
14
    },
1659
14
    { &hf_bscvlc_function,
1660
14
      { "Function",           "bscvlc.function",
1661
14
      FT_UINT8, BASE_HEX, VALS(bscvlc_function_names), 0,
1662
14
      "BSCVLC Function", HFILL }
1663
14
    },
1664
14
    { &hf_bscvlc_result,
1665
14
      { "Result",             "bscvlc.result",
1666
14
      FT_UINT8, BASE_HEX, VALS(bscvlc_result_names), 0,
1667
14
      "Result Code", HFILL }
1668
14
    },
1669
14
    { &hf_bscvlc_error_class,
1670
14
      { "Error Class",  "bscvlc.error_class",
1671
14
      FT_UINT32, BASE_DEC, VALS(BACnetErrorClass), 0, NULL, HFILL }
1672
14
    },
1673
14
    { &hf_bscvlc_error_code,
1674
14
      { "Error Code",   "bscvlc.error_code",
1675
14
      FT_UINT32, BASE_DEC, VALS(BACnetErrorCode), 0, NULL, HFILL }
1676
14
    },
1677
14
    { &hf_bscvlc_result_data,
1678
14
      { "Result Data",  "bscvlc.result_data",
1679
14
      FT_BYTES, BASE_NONE, NULL, 0,
1680
14
      "BSCVLC Result Data", HFILL }
1681
14
    },
1682
14
    { &hf_bscvlc_uris,
1683
14
      { "URI's",    "bscvlc.uris",
1684
14
      FT_BYTES, BASE_NONE, NULL, 0,
1685
14
      "BSCVLC Address URI's", HFILL }
1686
14
    },
1687
14
    { &hf_bscvlc_msg_id,
1688
14
      { "Message ID",         "bscvlc.msgid",
1689
14
      FT_UINT16, BASE_DEC, NULL, 0,
1690
14
      "BSCVLC Message ID", HFILL }
1691
14
    },
1692
14
    { &hf_bscvlc_orig_vmac,
1693
14
      { "SVMAC",              "bscvlc.orig_virtual_address",
1694
14
      FT_BYTES, BASE_NONE, NULL, 0,
1695
14
      "ORIG VMAC", HFILL }
1696
14
    },
1697
14
    { &hf_bscvlc_dest_vmac,
1698
14
      { "DVMAC",              "bscvlc.dest_virtual_address",
1699
14
      FT_BYTES, BASE_NONE, NULL, 0,
1700
14
      "DEST VMAC", HFILL }
1701
14
    },
1702
14
    { &hf_bscvlc_connect_vmac,
1703
14
      { "Connecting VMAC",  "bscvlc.connect_virtual_address",
1704
14
      FT_BYTES, BASE_NONE, NULL, 0,
1705
14
      "BSCVLC Connecting VMAC", HFILL }
1706
14
    },
1707
14
    { &hf_bscvlc_connect_uuid,
1708
14
      { "Connecting UUID",  "bscvlc.connect_uuid",
1709
14
      FT_BYTES, BASE_NONE, NULL, 0,
1710
14
      "BSCVLC Connecting UUID", HFILL }
1711
14
    },
1712
14
    { &hf_bscvlc_identity_device_id,
1713
14
      { "Identity Device ID", "bscvlc.identity_device_id",
1714
14
      FT_UINT24, BASE_DEC, NULL, 0,
1715
14
      "BSCVLC Identity Device ID", HFILL }
1716
14
    },
1717
14
    { &hf_bscvlc_hello_opt,
1718
14
      { "Hello option",   "bscvlc.hello_opt",
1719
14
      FT_UINT8, BASE_HEX, NULL, 0,
1720
14
      "BSCVLC Hello option", HFILL }
1721
14
    },
1722
14
    { &hf_bscvlc_hello_opt_identity_relay,
1723
14
      { "Hello Identity Relay","bscvlc.hello_opt_identity_relay",
1724
14
      FT_BOOLEAN, 8, TFS(&hello_opt_identity_relay_set_high),
1725
14
      BSCVLC_HELLO_IDENTITY_RELAY, "BSCVLC Hello Option", HFILL }
1726
14
    },
1727
14
  };
1728
1729
14
  static int *bsc_ett[] = {
1730
14
    &ett_bscvlc,
1731
14
    &ett_bscvlc_ctrl,
1732
14
    &ett_bscvlc_hdr
1733
14
  };
1734
1735
14
  proto_bvlc = proto_register_protocol("BACnet Virtual Link Control", "BVLC", "bvlc");
1736
1737
14
  proto_register_field_array(proto_bvlc, hf, array_length(hf));
1738
14
  proto_register_subtree_array(ett, array_length(ett));
1739
1740
14
  bvlc_handle = register_dissector("bvlc", dissect_bvlc, proto_bvlc);
1741
1742
14
  bvlc_dissector_table = register_dissector_table("bvlc.function", "BVLC Function", proto_bvlc, FT_UINT8, BASE_HEX);
1743
14
  bvlc_ipv6_dissector_table = register_dissector_table("bvlc.function_ipv6", "BVLC Function IPV6", proto_bvlc, FT_UINT8, BASE_HEX);
1744
1745
14
  proto_bscvlc = proto_register_protocol("BACnet Secure Connect Virtual Link Control", "BSCVLC", "bscvlc");
1746
1747
14
  proto_register_field_array(proto_bscvlc, bsc_hf, array_length(bsc_hf));
1748
14
  proto_register_subtree_array(bsc_ett, array_length(bsc_ett));
1749
1750
14
  bscvlc_handle = register_dissector("bscvlc", dissect_bscvlc, proto_bscvlc);
1751
1752
14
  bscvlc_dissector_table = register_dissector_table("bscvlc.function", "BSCVLC Function", proto_bscvlc, FT_UINT8, BASE_HEX);
1753
14
}
1754
1755
void
1756
proto_reg_handoff_bvlc(void)
1757
14
{
1758
14
  dissector_add_uint_with_preference("udp.port", BVLC_UDP_PORT, bvlc_handle);
1759
14
  dissector_add_string("ws.protocol", "hub.bsc.bacnet.org", bscvlc_handle);
1760
14
  dissector_add_string("ws.protocol", "dc.bsc.bacnet.org", bscvlc_handle);
1761
14
}
1762
1763
/*
1764
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
1765
 *
1766
 * Local variables:
1767
 * c-basic-offset: 8
1768
 * tab-width: 8
1769
 * indent-tabs-mode: t
1770
 * End:
1771
 *
1772
 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
1773
 * :indentSize=8:tabSize=8:noTabs=false:
1774
 */